1 /* 2 * Copyright (c) 2009, The MilkyTracker Team. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * - Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * - Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * - Neither the name of the <ORGANIZATION> nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * PlayerIT.h 32 * MilyPlay core 33 * 34 * Created by Peter Barth on Tue Oct 19 2004. 35 * 36 */ 37 #ifndef __PLAYERIT_H__ 38 #define __PLAYERIT_H__ 39 40 #include "PlayerBase.h" 41 #include "XModule.h" 42 43 class PlayerIT : public PlayerBase 44 { 45 private: 46 enum EXMMinPeriod 47 { 48 XM_MINPERIOD = 50 49 }; 50 51 struct TPrEnv 52 { 53 TEnvelope *envstruc; 54 bool enabled; 55 mp_sint32 a,b,step; 56 mp_uint32 bpmCounter, bpmAdder; 57 58 private: reachedEndTPrEnv59 bool reachedEnd(bool keyon) 60 { 61 bool reachedEnd = ((step >= envstruc->env[b][0]) && (b >= envstruc->num - 1)); 62 63 if (!reachedEnd) 64 return false; 65 66 bool ITBreakLoop = (envstruc->type & 16); 67 if (ITBreakLoop && keyon) 68 return false; 69 70 bool AMSBreakLoop = (envstruc->type & (4+8)) == (4+8); 71 bool XMBreakLoop = ((envstruc->type & (2+4)) == (2+4)) && (envstruc->sustain == envstruc->loope); 72 73 bool brokeLoop = !keyon && (AMSBreakLoop || XMBreakLoop); 74 75 //bool res = ((envstruc->type & 4) && brokeLoop) || (!(envstruc->type & 4)); 76 return ((envstruc->type & 4) && brokeLoop) || (!(envstruc->type & 4)); 77 } 78 79 public: 80 finishedTPrEnv81 bool finished(bool keyon) 82 { 83 if (envstruc == NULL || 84 !enabled) 85 return false; 86 87 return reachedEnd(keyon); 88 } 89 cuttedTPrEnv90 bool cutted(bool keyon) 91 { 92 return (envstruc && 93 reachedEnd(keyon) && 94 envstruc->env[b][1] == 0); 95 } 96 setEnabledTPrEnv97 void setEnabled(bool enabled) { this->enabled = enabled; } isEnabledTPrEnv98 bool isEnabled() { return enabled && envstruc != NULL; } 99 }; 100 101 struct TLastOperands 102 { 103 mp_ubyte portaup; 104 mp_ubyte portadown; 105 mp_ubyte portanote; 106 mp_ubyte fineportaup; 107 mp_ubyte fineportadown; 108 mp_ubyte xfineportaup; 109 mp_ubyte xfineportadown; 110 mp_ubyte volslide; 111 mp_ubyte finevolslide; 112 mp_ubyte gvolslide; 113 mp_ubyte chnvolslide; 114 mp_ubyte panslide; 115 mp_ubyte arpeg; 116 mp_ubyte retrig; 117 mp_ubyte tremor; 118 mp_ubyte smpoffset; 119 mp_ubyte temposlide; 120 }; 121 122 #define DEFINE_STATINTERFACE \ 123 mp_sint32 getNote() { return chnstat().note; } \ 124 mp_sint32 getIns() { return chnstat().ins; } \ 125 mp_uword getInsflags() { return chnstat().insflags; } \ 126 mp_sint32 getSmp() { return chnstat().smp; } \ 127 \ 128 void setNote(mp_sint32 note) { chnstat().note = note; } \ 129 void setIns(mp_sint32 ins) { chnstat().ins = ins; } \ 130 void setInsflags(mp_uword insflags) { chnstat().insflags = insflags; } \ 131 void setSmp(mp_sint32 smp) { chnstat().smp = smp; } \ 132 \ 133 mp_sint32 getFlags() { return chnstat().flags; } \ 134 void setFlags(mp_uint32 flags) { chnstat().flags = flags; } \ 135 void setFlag(mp_uint32 flag) { chnstat().flags |= flag; } \ 136 void resetFlag(mp_uint32 flag) { chnstat().flags &= ~flag; } \ 137 bool isFlagSet(mp_uint32 flag) { return (chnstat().flags & flag); } \ 138 \ 139 void setVol(mp_sint32 vol) { chnstat().vol = vol; } \ 140 void incVol(mp_sint32 offs) { chnstat().vol+=offs; if (chnstat().vol>255) chnstat().vol=255; } \ 141 void decVol(mp_sint32 offs) { chnstat().vol-=offs; if (chnstat().vol<0) chnstat().vol=0; } \ 142 void adjustTremoloTremorVol() { chnstat().tremorVol = chnstat().tremoloVol = chnstat().vol; chnstat().hasTremolo = false; chnstat().finalTremoloVol = 0; } \ 143 void adjustTremoloVol() { chnstat().tremoloVol = chnstat().vol; chnstat().hasTremolo = false; chnstat().finalTremoloVol = 0; } \ 144 void setFinalTremVol(mp_sint32 vol) { chnstat().finalTremoloVol = vol; chnstat().hasTremolo = true; } \ 145 \ 146 void setPan(mp_sint32 pan) { chnstat().pan = pan; } \ 147 void incPan(mp_sint32 offs) { chnstat().pan+=offs; if (chnstat().pan>255) chnstat().pan=255; } \ 148 void decPan(mp_sint32 offs) { chnstat().pan-=offs; if (chnstat().pan<0) chnstat().pan=0; } \ 149 \ 150 void setPer(mp_sint32 per) { chnstat().per = per; } \ 151 void decPer(mp_sint32 offs) { chnstat().per-=offs; } \ 152 void incPer(mp_sint32 offs) { chnstat().per+=offs; } \ 153 void adjustVibratoPer() { chnstat().hasVibrato = false; chnstat().finalVibratoPer = 0; } \ 154 void setFinalVibratoPer(mp_sint32 per) { chnstat().finalVibratoPer = per; chnstat().hasVibrato = true; } \ 155 \ 156 void clampPerMax(mp_sint32 max) { if (chnstat().per > max) chnstat().per = max; } \ 157 void clampPerMin(mp_sint32 min) { if (chnstat().per < min) chnstat().per = min; } \ 158 \ 159 void setMasterVol(mp_sint32 vol) { chnstat().masterVol = vol; } \ 160 void incMasterVol(mp_sint32 offs) { chnstat().masterVol+=offs; if (chnstat().masterVol>255) chnstat().masterVol=255; } \ 161 void decMasterVol(mp_sint32 offs) { chnstat().masterVol-=offs; if (chnstat().masterVol<0) chnstat().masterVol=0; } \ 162 void setInsMasterVol(mp_sint32 vol) { chnstat().insMasterVol = vol; } \ 163 void setSmpMasterVol(mp_sint32 vol) { chnstat().smpMasterVol = vol; } \ 164 void setFreqadjust(mp_sword freqadjust) { chnstat().freqadjust = freqadjust; } \ 165 void setRelnote(mp_sint32 relnote) { chnstat().relnote = relnote; } \ 166 void setFinetune(mp_sint32 finetune) { chnstat().finetune = finetune; } \ 167 \ 168 mp_sint32 getVol() { return chnstat().vol; } \ 169 mp_sint32 getTremoloVol() { return chnstat().tremoloVol; } \ 170 mp_sint32 getTremorVol() { return chnstat().tremorVol; } \ 171 mp_sint32 getVolume() { return chnstat().getVolumeInternal(); } \ 172 \ 173 mp_sint32 getPan() { return chnstat().pan; } \ 174 mp_sint32 getPer() { return chnstat().per; } \ 175 mp_sint32 getPeriod() { return chnstat().getPeriodInternal(); } \ 176 \ 177 mp_sint32 getMasterVol() { return chnstat().masterVol; } \ 178 mp_sint32 getInsMasterVol() { return chnstat().insMasterVol; } \ 179 mp_sint32 getSmpMasterVol() { return chnstat().smpMasterVol; } \ 180 mp_sword getFreqadjust() { return chnstat().freqadjust; } \ 181 mp_sint32 getRelnote() { return chnstat().relnote; } \ 182 mp_sint32 getFinetune() { return chnstat().finetune; } \ 183 \ 184 bool getKeyon() { return chnstat().keyon; } \ 185 \ 186 TPrEnv& getVenv() { return chnstat().venv; } \ 187 TPrEnv& getPenv() { return chnstat().penv; } \ 188 TPrEnv& getFenv() { return chnstat().fenv; } \ 189 TPrEnv& getVibenv() { return chnstat().vibenv; } \ 190 TPrEnv& getPitchenv() { return chnstat().pitchenv; } \ 191 \ 192 mp_ubyte getAvibused() { return chnstat().avibused; } \ 193 mp_ubyte getAvibspd() { return chnstat().avibspd; } \ 194 mp_ubyte getAvibdepth() { return chnstat().avibdepth; } \ 195 mp_ubyte getAvibcnt() { return chnstat().avibcnt; } \ 196 mp_ubyte getAvibsweep() { return chnstat().avibsweep; } \ 197 mp_sint32 getAvibswcnt() { return chnstat().avibswcnt; } \ 198 \ 199 void setKeyon(bool keyon) { chnstat().keyon = keyon; } \ 200 void setAvibused(mp_ubyte avibused) { chnstat().avibused = avibused; } \ 201 void setAvibspd(mp_ubyte avibspd) { chnstat().avibspd = avibspd; } \ 202 void setAvibdepth(mp_ubyte avibdepth) { chnstat().avibdepth = avibdepth; } \ 203 void setAvibcnt(mp_ubyte avibcnt) { chnstat().avibcnt = avibcnt; } \ 204 void setAvibsweep(mp_ubyte avibsweep) { chnstat().avibsweep = avibsweep; } \ 205 void setAvibswcnt(mp_sint32 avibswcnt) { chnstat().avibswcnt = avibswcnt; } \ 206 \ 207 void avibAdvance() \ 208 { \ 209 chnstat().avibcnt+=chnstat().avibspd; \ 210 /* IT style auto vibrato */ \ 211 if (chnstat().avibused & 128) \ 212 { \ 213 if (chnstat().avibswcnt < ((mp_sint32)chnstat().avibdepth << 8) && chnstat().avibsweep) \ 214 /* Our vibrato depth is two times finer than the one from IT, increment by sweep*2 */ \ 215 chnstat().avibswcnt+=(mp_sint32)chnstat().avibsweep<<1; \ 216 } \ 217 /* XM style auto vibrato */ \ 218 else \ 219 { \ 220 if (chnstat().avibswcnt < chnstat().avibsweep) \ 221 chnstat().avibswcnt = (chnstat().avibswcnt+1) & 0xFF; \ 222 } \ 223 } \ 224 \ 225 void setFadevolstart(mp_sint32 fadevolstart) { chnstat().fadevolstart = fadevolstart; } \ 226 mp_sint32 getFadevolstart() { return chnstat().fadevolstart; } \ 227 \ 228 void setFadevolstep(mp_sint32 fadevolstep) { chnstat().fadevolstep = fadevolstep; } \ 229 mp_sint32 getFadevolstep() { return chnstat().fadevolstep; } \ 230 \ 231 void decFadevolstart() { chnstat().fadevolstart-=chnstat().fadevolstep; if (chnstat().fadevolstart<0) chnstat().fadevolstart=0; } \ 232 \ 233 void setFadeout(bool fadeout) { chnstat().fadeout = fadeout; } \ 234 bool getFadeout() { return chnstat().fadeout; } \ 235 \ 236 void setCutoff(mp_ubyte cutoff) { chnstat().cutoff = cutoff; } \ 237 mp_ubyte getCutoff() { return chnstat().cutoff; } \ 238 \ 239 void setResonance(mp_ubyte resonance) { chnstat().resonance = resonance; } \ 240 mp_ubyte getResonance() { return chnstat().resonance; } 241 242 public: 243 struct TChnState 244 { chnstatTChnState245 TChnState& chnstat() { return *this; } 246 247 mp_uint32 flags; 248 249 mp_sint32 note; 250 mp_sint32 ins; 251 mp_uword insflags; 252 mp_sint32 smp; 253 254 mp_sint32 vol; 255 mp_sint32 tremoloVol; 256 mp_sint32 finalTremoloVol; 257 mp_sint32 tremorVol; 258 bool hasTremolo; 259 260 mp_sint32 pan; 261 262 mp_sint32 per; 263 mp_sint32 finalVibratoPer; 264 bool hasVibrato; 265 266 mp_sint32 insMasterVol; 267 mp_sint32 smpMasterVol; 268 mp_sint32 masterVol; 269 270 mp_sint32 relnote; 271 mp_sint32 finetune; 272 mp_sword freqadjust; 273 274 bool keyon; 275 bool fadeout; 276 277 TPrEnv venv; 278 TPrEnv penv; 279 TPrEnv fenv; 280 TPrEnv vibenv; 281 TPrEnv pitchenv; 282 283 mp_ubyte avibused; 284 mp_ubyte avibspd; 285 mp_ubyte avibdepth; 286 mp_ubyte avibcnt; 287 mp_ubyte avibsweep; 288 mp_sint32 avibswcnt; 289 290 mp_sint32 fadevolstart; 291 mp_sint32 fadevolstep; 292 getVolumeInternalTChnState293 mp_sint32 getVolumeInternal() { return hasTremolo ? finalTremoloVol : vol; } getPeriodInternalTChnState294 mp_sint32 getPeriodInternal() { return hasVibrato ? finalVibratoPer : per; } 295 296 mp_ubyte cutoff; 297 mp_ubyte resonance; 298 299 DEFINE_STATINTERFACE 300 }; 301 302 private: 303 struct TModuleChannel; 304 305 struct TVirtualChannel 306 { 307 private: 308 bool active; 309 310 mp_sint32 channelIndex; 311 312 TChnState state; 313 314 TModuleChannel* host; 315 TModuleChannel* oldHost; 316 317 public: 318 // if we're in background we work on our own state 319 // if not, we're just going to work on the host state 320 TChnState& chnstat(); 321 getRealStateTVirtualChannel322 TChnState& getRealState() { return state; } 323 updateStateTVirtualChannel324 void updateState(const TChnState& src) 325 { 326 state = src; 327 state.flags = 0; 328 } 329 setActiveTVirtualChannel330 void setActive(bool active) { this->active = active; } getActiveTVirtualChannel331 bool getActive() { return active; } 332 setHostTVirtualChannel333 void setHost(TModuleChannel* host) { this->host = host; } getHostTVirtualChannel334 TModuleChannel* getHost() { return host; } getBackgroundTVirtualChannel335 bool getBackground() { return host == NULL; } 336 setOldHostTVirtualChannel337 void setOldHost(TModuleChannel* host) { this->oldHost = host; } getOldHostTVirtualChannel338 TModuleChannel* getOldHost() { return oldHost; } 339 setChannelIndexTVirtualChannel340 void setChannelIndex(mp_sint32 channelIndex) { this->channelIndex = channelIndex; } getChannelIndexTVirtualChannel341 mp_sint32 getChannelIndex() { return channelIndex; } 342 343 DEFINE_STATINTERFACE 344 getResultingVolumeTVirtualChannel345 mp_sint32 getResultingVolume() 346 { 347 mp_sint32 vol = (getVolume()*getFadevolstart())>>16; 348 vol = (vol*getMasterVol()*getInsMasterVol())>>16; 349 vol = (vol*getSmpMasterVol())>>8; 350 return vol; 351 } 352 clearTVirtualChannel353 void clear() 354 { 355 mp_sint32 cIndex = channelIndex; 356 memset(this, 0, sizeof(TVirtualChannel)); 357 channelIndex = cIndex; 358 } 359 360 friend struct TModuleChannel; 361 }; 362 363 struct TModuleChannel 364 { 365 private: 366 TChnState state; 367 368 TVirtualChannel* vchn; 369 370 public: 371 // if we're having a virtual channel, we need to work on the state of the virtual channel 372 // if not, we're just going to work on our own state chnstatTModuleChannel373 TChnState& chnstat() { return vchn ? vchn->chnstat() : state; } 374 getRealStateTModuleChannel375 TChnState& getRealState() { return state; } 376 hasVchnTModuleChannel377 bool hasVchn() { return vchn != NULL; } getVchnTModuleChannel378 TVirtualChannel* getVchn() { return vchn; } linkVchnTModuleChannel379 void linkVchn(TVirtualChannel* vchn) 380 { 381 vchn->clear(); 382 vchn->setActive(true); 383 this->vchn = vchn; 384 vchn->setHost(this); 385 } 386 unlinkVchnTModuleChannel387 TVirtualChannel* unlinkVchn() 388 { 389 vchn->setHost(NULL); 390 vchn->setOldHost(this); 391 vchn->updateState(getRealState()); 392 TVirtualChannel* result = vchn; 393 vchn = NULL; 394 return result; 395 } 396 getPlaybackChannelIndexTModuleChannel397 mp_sint32 getPlaybackChannelIndex() { return ((vchn == NULL) ? -1 : vchn->getChannelIndex()); } 398 399 DEFINE_STATINTERFACE 400 slideToPerTModuleChannel401 void slideToPer(mp_sint32 op) 402 { 403 if (destper>chnstat().per) { 404 chnstat().per+=op; 405 if (chnstat().per>destper) chnstat().per=destper; 406 } 407 else if (destper<chnstat().per) { 408 chnstat().per-=op; 409 if (chnstat().per<destper) chnstat().per=destper; 410 } 411 } 412 413 mp_sint32 channelIndex; 414 415 bool hasSetVolume; 416 mp_sint32 destper; 417 418 //mp_sint32 c4spd; 419 mp_sint32 currentnote; 420 mp_sint32 destnote; 421 bool validnote; 422 mp_sint32 lastnoportanote; 423 424 mp_uint32 smpoffs; 425 mp_uint32 smpoffshigh; 426 427 mp_ubyte eff[MP_NUMEFFECTS]; 428 mp_ubyte eop[MP_NUMEFFECTS]; 429 TLastOperands old[MP_NUMEFFECTS]; 430 431 mp_sint32 loopstart; 432 mp_sint32 execloop; 433 mp_sint32 loopcounter; 434 bool isLooping; 435 mp_sint32 loopingValidPosition; 436 437 mp_ubyte vibdepth[MP_NUMEFFECTS]; 438 mp_ubyte vibspeed[MP_NUMEFFECTS]; 439 mp_ubyte vibpos[MP_NUMEFFECTS]; 440 mp_ubyte trmdepth[MP_NUMEFFECTS]; 441 mp_ubyte trmspeed[MP_NUMEFFECTS]; 442 mp_ubyte trmpos[MP_NUMEFFECTS]; 443 mp_ubyte panbrellodepth[MP_NUMEFFECTS]; 444 mp_ubyte panbrellospeed[MP_NUMEFFECTS]; 445 mp_ubyte panbrellopos[MP_NUMEFFECTS]; 446 mp_ubyte tremorcnt[MP_NUMEFFECTS]; 447 mp_sint32 retrigcounterE9x[MP_NUMEFFECTS]; 448 mp_ubyte retrigmaxE9x[MP_NUMEFFECTS]; 449 mp_sint32 retrigcounterRxx[MP_NUMEFFECTS]; 450 mp_ubyte retrigmaxRxx[MP_NUMEFFECTS]; 451 452 friend struct TVirtualChannel; 453 }; 454 455 #undef DEFINE_STATINTERFACE 456 457 private: 458 459 static const mp_sint32 vibtab[32]; 460 static const mp_sint32 finesintab[256]; 461 static const mp_uword lintab[769]; 462 static const mp_uint32 logtab[]; 463 static const mp_uint32 powtab[]; 464 465 TModuleChannel *chninfo; // our channel information 466 TVirtualChannel *vchninfo; // our virtual channels 467 468 mp_ubyte *attick; 469 470 mp_sint32 patternIndex; // holds current pattern index 471 mp_sint32 numModuleChannels; // max number of "host" channels (from module header) 472 mp_sint32 numMaxVirChannels; // max number of virtual channels in total 473 mp_sint32 numVirtualChannels; // max number of virtual channels (dynamic) 474 mp_sint32 numEffects; // current number of effects 475 mp_sint32 numChannels; // current number of channels 476 mp_sint32 curMaxVirChannels; 477 478 mp_ubyte pbreak; 479 mp_ubyte pbreakpos; 480 mp_sint32 pbreakPriority; 481 mp_ubyte pjump; 482 mp_ubyte pjumppos,pjumprow; 483 mp_sint32 pjumpPriority; 484 bool patDelay; 485 bool haltFlag; 486 mp_sint32 startNextRow; 487 488 mp_sint32 patDelayCount; 489 490 // keep track of what positions we already visited (bitmap) 491 mp_ubyte rowHits[256*256/8]; 492 bool isLooping; 493 494 /////////////////////////////////////////////////////////////////////////////////////////////////// 495 // this information is updated while the song plays 496 /////////////////////////////////////////////////////////////////////////////////////////////////// 497 bool newInsPTFlag; // New instrument PT like 498 bool newInsST3Flag; // New instrument ST3 like 499 bool oldPTInsChangeFlag; // sample without note flag (old PT style) 500 bool playModePT; 501 bool playModePTPitchLimit; 502 bool playModeFT2; 503 bool playModeChopSampleOffset; 504 isRowVisited(mp_sint32 row)505 bool isRowVisited(mp_sint32 row) 506 { 507 return (rowHits[row>>3]>>(row&7))&1; 508 } 509 visitRow(mp_sint32 row)510 void visitRow(mp_sint32 row) 511 { 512 rowHits[row>>3] |= (1<<(row&7)); 513 } 514 515 TVirtualChannel* allocateVirtualChannel(); releaseVirtualChannel(TVirtualChannel * vchn)516 void releaseVirtualChannel(TVirtualChannel* vchn) 517 { 518 vchn->setActive(false); 519 if (vchn->getChannelIndex() == curMaxVirChannels-1) 520 curMaxVirChannels--; 521 } 522 523 struct TNNATriggerInfo 524 { 525 mp_sint32 note; 526 mp_sint32 ins; 527 mp_sint32 smp; 528 }; 529 530 void handleNoteOFF(TChnState& state); 531 void handlePastNoteAction(TModuleChannel* chnInf, mp_ubyte pastNoteActionType); 532 bool handleDCT(TModuleChannel* chnInf, const TNNATriggerInfo& triggerInfo, mp_ubyte DCT, mp_ubyte DCA); 533 bool handleNNAs(TModuleChannel* chnInf, const TNNATriggerInfo& triggerInfo); 534 void adjustVirtualChannels(); 535 536 static void prenvelope(TPrEnv* env, bool keyon, bool timingIT); // process envelopes 537 538 static mp_sint32 getenvval(TPrEnv* env, mp_sint32 n); // get envelope value 539 540 static mp_sint32 interpolate(mp_sint32 eax,mp_sint32 ebx,mp_sint32 ecx,mp_sint32 edi,mp_sint32 esi); 541 542 // This takes the period *with* 8 bit fractional part 543 static mp_sint32 getlinfreq(mp_sint32 per); 544 // This takes the period *with* 8 bit fractional part 545 static mp_sint32 getlogfreq(mp_sint32 per); 546 // this returns a period *without* the 8 bit fractional part 547 mp_sint32 getlinperiod(mp_sint32 note, mp_sint32 relnote, mp_sint32 finetune); 548 // this returns a period *without* the 8 bit fractional part 549 mp_sint32 getlogperiod(mp_sint32 note, mp_sint32 relnote, mp_sint32 finetune); 550 getbpmrate(mp_uint32 bpm)551 mp_uint32 getbpmrate(mp_uint32 bpm) 552 { 553 // digibooster "real BPM" setting 554 mp_uint32 realCiaTempo = (bpm * (baseBpm << 8) / 125) >> 8; 555 556 if (!realCiaTempo) realCiaTempo++; 557 558 mp_int64 t = ((mp_int64)realCiaTempo)<<(32+2); 559 560 const mp_uint32 timerBase = (mp_uint32)(5.0f*500.0f*(MP_BEATLENGTH*MP_TIMERFREQ / (float)MP_BASEFREQ)); 561 562 return (mp_uint32)(t/timerBase); 563 } 564 getperiod(mp_sint32 note,mp_sint32 relnote,mp_sint32 finetune)565 mp_sint32 getperiod(mp_sint32 note, mp_sint32 relnote, mp_sint32 finetune) 566 { 567 /*mp_sint32 logper = getlogperiod(note,relnote,finetune); 568 mp_sint32 linper = getlinperiod(note,relnote,finetune); 569 570 mp_sint32 logfreq = getlogfreq(logper<<8); 571 mp_sint32 linfreq = getlinfreq(linper<<8); 572 573 return (module->header.freqtab&1) ? linper : logper;*/ 574 575 if (playModeFT2) 576 { 577 // FT2 doesn't support lower 3 bits 578 if (finetune > 0) 579 finetune &= ~3; 580 else if (finetune < 0) 581 { 582 finetune = -((-finetune + 7) & ~3); 583 if (finetune < -128) 584 finetune = -128; 585 } 586 } 587 588 return (module->header.freqtab&1) ? getlinperiod(note,relnote,finetune) : getlogperiod(note,relnote,finetune); 589 } 590 getFinalVolume(TChnState & state,mp_sint32 nv,mp_sint32 mainVolume)591 mp_sint32 getFinalVolume(TChnState& state, mp_sint32 nv, mp_sint32 mainVolume) 592 { 593 mp_sint32 vol = (nv*getenvval(&state.venv,256))>>7; 594 vol = (vol*state.fadevolstart)>>16; 595 vol = (vol*state.masterVol*state.insMasterVol)>>16; 596 vol = (vol*state.smpMasterVol*mainVolume)>>16; 597 return vol; 598 } 599 getFinalCutoff(TChnState & state,mp_sint32 nc)600 mp_sint32 getFinalCutoff(TChnState& state, mp_sint32 nc) 601 { 602 if (state.pitchenv.envstruc != NULL && 603 state.pitchenv.envstruc->type & 128) 604 return (nc != MP_INVALID_VALUE) ? nc*getenvval(&state.pitchenv, 256) : 127*getenvval(&state.pitchenv, 256); 605 else 606 return (nc != MP_INVALID_VALUE) ? (nc << 8) : nc; 607 } 608 getFinalPanning(TChnState & state,mp_sint32 np)609 mp_sint32 getFinalPanning(TChnState& state, mp_sint32 np) 610 { 611 mp_sint32 envpan = getenvval(&state.penv,128); 612 //if (envpan!=256) cprintf("%i\r\n",envpan); 613 mp_sint32 finalpan = np+(envpan-128)*(128-abs(np-128))/128; 614 if (finalpan<0) finalpan=0; 615 if (finalpan>255) finalpan=255; 616 return finalpan; 617 } 618 getFinalFreq(TChnState & state,mp_sint32 per)619 mp_sint32 getFinalFreq(TChnState& state, mp_sint32 per) 620 { 621 if (per<1) return 0; 622 623 // valid envelope and pitch envelope is not configured as filter envelope 624 if (state.pitchenv.envstruc != NULL && !(state.pitchenv.envstruc->type & 128) && (state.pitchenv.envstruc->type & 1)) 625 { 626 // scale the envelope point that 256 units match one semitone 627 mp_sint32 pitch = (getenvval(&state.pitchenv, 128) - 128) * 32; 628 // add that semitone to the current note 629 mp_sint32 note = state.getNote() + (pitch>>8); 630 // the tone between two semitones 631 mp_sint32 subnote = pitch & 255; 632 // that would be the actual period we have 633 mp_sint32 baseperiod = getperiod(state.getNote(), state.getRelnote(), state.getFinetune()); 634 635 mp_sint32 period1 = getperiod(note, state.getRelnote(), state.getFinetune()); 636 mp_sint32 period2 = getperiod(note+1, state.getRelnote(), state.getFinetune()); 637 mp_sint32 finalperiod = (period1 * (256-subnote) + period2 * subnote); 638 639 mp_sint32 diff = finalperiod - (baseperiod << 8); 640 per+=diff; 641 if (per < XM_MINPERIOD) 642 per = XM_MINPERIOD; 643 } 644 mp_sint32 eval = getenvval(&state.fenv,128)-128; 645 mp_uint32 freq = (module->header.freqtab&1) ? getlinfreq(per) : getlogfreq(per); 646 647 mp_sint32 finalFreq = (freq+(eval*63))+(mp_sint32)state.freqadjust; 648 if (finalFreq < 0) finalFreq = 0; 649 650 return finalFreq; 651 } 652 653 mp_sint32 getFinalPeriod(TChnState& state, mp_sint32 p); 654 655 void playInstrument(TModuleChannel* chnInf, bool bNoRestart = false); 656 657 void triggerEnvelope(TPrEnv& dstEnv, TEnvelope& srcEnv); 658 void triggerEnvelopes(TModuleChannel* chnInf); 659 void triggerAutovibrato(TModuleChannel* chnInf); 660 void triggerInstrumentFX(TModuleChannel* chnInf, bool triggerEnv = true); 661 662 void updatePlayModeFlags(); 663 handlePeriodOverflow(TModuleChannel * chnInf)664 void handlePeriodOverflow(TModuleChannel* chnInf) 665 { 666 // PTK/FT1 playmode 667 if (playModePTPitchLimit && options[PlayModeOptionForcePTPitchLimit]) 668 { 669 chnInf->clampPerMax(856*4); 670 } 671 // FT2 playmode (does nothing right now) 672 else 673 { 674 //if (chnInf->per > 14150) 675 // chnInf->per %= 14150; 676 } 677 } 678 handlePeriodUnderflow(TModuleChannel * chnInf)679 void handlePeriodUnderflow(TModuleChannel* chnInf) 680 { 681 // PTK/FT1 playmode 682 if (playModePTPitchLimit && options[PlayModeOptionForcePTPitchLimit]) 683 { 684 chnInf->clampPerMin(113*4); 685 } 686 // FT2 playmode (clamp on low value, not what FT2 does btw.) 687 else 688 { 689 chnInf->clampPerMin(XM_MINPERIOD); 690 //chninfo[channel].per &= 0x3FFF; 691 } 692 } 693 694 mp_sint32 calcVibrato(TModuleChannel* chnInf, mp_sint32 effcnt, mp_sint32 depthShift = 5); 695 void doTickVolslidePT(TModuleChannel* chnInf, mp_sint32 effcnt); 696 void doTickVolslideST(TModuleChannel* chnInf, mp_sint32 effcnt); 697 void doTickEffect(TModuleChannel* chnInf, mp_sint32 effcnt); 698 699 void doVolslidePT(TModuleChannel* chnInf, mp_sint32 effcnt, mp_ubyte eop); 700 void doVolslideST(TModuleChannel* chnInf, mp_sint32 effcnt, mp_ubyte eop); 701 void doEffect(TModuleChannel* chnInf, mp_sint32 effcnt); 702 703 void doTickeffects(); 704 void progressRow(); 705 void update(); 706 void updateBPMIndependent(); 707 708 void setNewPosition(mp_sint32 poscnt); 709 710 void tickhandler(); 711 712 mp_sint32 allocateStructures(); 713 void freeMemory(); 714 715 // stop song by setting flag and setting speed to zero 716 void halt(); 717 718 protected: 719 virtual void clearEffectMemory(); 720 721 public: 722 PlayerIT(mp_uint32 frequency); 723 724 virtual ~PlayerIT(); 725 getType()726 virtual PlayerTypes getType() const { return PlayerType_IT; } 727 setNumMaxVirChannels(mp_sint32 max)728 void setNumMaxVirChannels(mp_sint32 max) { numMaxVirChannels = max; } getNumMaxVirChannels()729 mp_sint32 getNumMaxVirChannels() const { return numMaxVirChannels; } 730 731 // virtual from mixer class, perform playing here 732 virtual void timerHandler(mp_sint32 currentBeatPacket); 733 734 // override base class method 735 virtual mp_sint32 startPlaying(XModule* module, 736 bool repeat = false, 737 mp_uint32 startPosition = 0, 738 mp_uint32 startRow = 0, 739 mp_sint32 numChannels = -1, 740 const mp_ubyte* customPanningTable = NULL, 741 bool idle = false, 742 mp_sint32 patternIndex = -1, 743 bool playOneRowOnly = false); 744 745 virtual void restart(mp_uint32 startPosition = 0, mp_uint32 startRow = 0, bool resetMixer = true, const mp_ubyte* customPanningTable = NULL, bool playOneRowOnly = false); 746 747 virtual void reset(); 748 749 virtual void resetAllSpeed(); 750 751 virtual bool grabChannelInfo(mp_sint32 chn, TPlayerChannelInfo& channelInfo) const; 752 getCurMaxVirChannels()753 mp_sint32 getCurMaxVirChannels() const { return curMaxVirChannels; } 754 }; 755 756 #endif 757