00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "stdafx.h"
00011 #include "sndfile.h"
00012
00013 #ifdef WIN32
00014 #pragma warning(disable:4244)
00015 #endif
00016
00017
00018 extern const BYTE ImpulseTrackerPortaVolCmd[16];
00019 extern const WORD S3MFineTuneTable[16];
00020 extern const WORD ProTrackerPeriodTable[6*12];
00021 extern const WORD ProTrackerTunedPeriods[15*12];
00022 extern const WORD FreqS3MTable[];
00023 extern const WORD XMPeriodTable[96+8];
00024 extern const UINT XMLinearTable[768];
00025 extern const DWORD FineLinearSlideUpTable[16];
00026 extern const DWORD FineLinearSlideDownTable[16];
00027 extern const DWORD LinearSlideUpTable[256];
00028 extern const DWORD LinearSlideDownTable[256];
00029 extern const signed char retrigTable1[16];
00030 extern const signed char retrigTable2[16];
00031 extern const short int ModRandomTable[64];
00032
00033
00035
00036
00037 DWORD CSoundFile::GetLength(BOOL bAdjust, BOOL bTotal)
00038
00039 {
00040 UINT dwElapsedTime=0, nRow=0, nCurrentPattern=0, nNextPattern=0, nPattern=Order[0];
00041 UINT nMusicSpeed=m_nDefaultSpeed, nMusicTempo=m_nDefaultTempo, nNextRow=0;
00042 UINT nMaxRow = 0, nMaxPattern = 0;
00043 LONG nGlbVol = m_nDefaultGlobalVolume, nOldGlbVolSlide = 0;
00044 BYTE samples[MAX_CHANNELS];
00045 BYTE instr[MAX_CHANNELS];
00046 BYTE notes[MAX_CHANNELS];
00047 BYTE vols[MAX_CHANNELS];
00048 BYTE oldparam[MAX_CHANNELS];
00049 BYTE chnvols[MAX_CHANNELS];
00050 DWORD patloop[MAX_CHANNELS];
00051
00052 memset(instr, 0, sizeof(instr));
00053 memset(notes, 0, sizeof(notes));
00054 memset(vols, 0xFF, sizeof(vols));
00055 memset(patloop, 0, sizeof(patloop));
00056 memset(oldparam, 0, sizeof(oldparam));
00057 memset(chnvols, 64, sizeof(chnvols));
00058 memset(samples, 0, sizeof(samples));
00059 for (UINT icv=0; icv<m_nChannels; icv++) chnvols[icv] = ChnSettings[icv].nVolume;
00060 nMaxRow = m_nNextRow;
00061 nMaxPattern = m_nNextPattern;
00062 nCurrentPattern = nNextPattern = 0;
00063 nPattern = Order[0];
00064 nRow = nNextRow = 0;
00065 for (;;)
00066 {
00067 UINT nSpeedCount = 0;
00068 nRow = nNextRow;
00069 nCurrentPattern = nNextPattern;
00070
00071 nPattern = Order[nCurrentPattern];
00072 while (nPattern >= MAX_PATTERNS)
00073 {
00074
00075 if ((nPattern == 0xFF) || (nCurrentPattern >= MAX_ORDERS))
00076 {
00077 goto EndMod;
00078 } else
00079 {
00080 nCurrentPattern++;
00081 nPattern = (nCurrentPattern < MAX_ORDERS) ? Order[nCurrentPattern] : 0xFF;
00082 }
00083 nNextPattern = nCurrentPattern;
00084 }
00085
00086 if ((nPattern >= MAX_PATTERNS) || (!Patterns[nPattern])) break;
00087
00088 if (nRow >= PatternSize[nPattern]) nRow = 0;
00089
00090 nNextRow = nRow + 1;
00091 if (nNextRow >= PatternSize[nPattern])
00092 {
00093 nNextPattern = nCurrentPattern + 1;
00094 nNextRow = 0;
00095 }
00096 if (!nRow)
00097 {
00098 for (UINT ipck=0; ipck<m_nChannels; ipck++) patloop[ipck] = dwElapsedTime;
00099 }
00100 if (!bTotal)
00101 {
00102 if ((nCurrentPattern > nMaxPattern) || ((nCurrentPattern == nMaxPattern) && (nRow >= nMaxRow)))
00103 {
00104 if (bAdjust)
00105 {
00106 m_nMusicSpeed = nMusicSpeed;
00107 m_nMusicTempo = nMusicTempo;
00108 }
00109 break;
00110 }
00111 }
00112 MODCHANNEL *pChn = Chn;
00113 MODCOMMAND *p = Patterns[nPattern] + nRow * m_nChannels;
00114 for (UINT nChn=0; nChn<m_nChannels; p++,pChn++, nChn++) if (*((DWORD *)p))
00115 {
00116 UINT command = p->command;
00117 UINT param = p->param;
00118 UINT note = p->note;
00119 if (p->instr) { instr[nChn] = p->instr; notes[nChn] = 0; vols[nChn] = 0xFF; }
00120 if ((note) && (note <= 120)) notes[nChn] = note;
00121 if (p->volcmd == VOLCMD_VOLUME) { vols[nChn] = p->vol; }
00122 if (command) switch (command)
00123 {
00124
00125 case CMD_POSITIONJUMP:
00126 if (param <= nCurrentPattern) goto EndMod;
00127 nNextPattern = param;
00128 nNextRow = 0;
00129 if (bAdjust)
00130 {
00131 pChn->nPatternLoopCount = 0;
00132 pChn->nPatternLoop = 0;
00133 }
00134 break;
00135
00136 case CMD_PATTERNBREAK:
00137 nNextRow = param;
00138 nNextPattern = nCurrentPattern + 1;
00139 if (bAdjust)
00140 {
00141 pChn->nPatternLoopCount = 0;
00142 pChn->nPatternLoop = 0;
00143 }
00144 break;
00145
00146 case CMD_SPEED:
00147 if (!param) break;
00148 if ((param <= 0x20) || (m_nType != MOD_TYPE_MOD))
00149 {
00150 if (param < 128) nMusicSpeed = param;
00151 }
00152 break;
00153
00154 case CMD_TEMPO:
00155 if ((bAdjust) && (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT)))
00156 {
00157 if (param) pChn->nOldTempo = param; else param = pChn->nOldTempo;
00158 }
00159 if (param >= 0x20) nMusicTempo = param; else
00160
00161 if ((param & 0xF0) == 0x10)
00162 {
00163 nMusicTempo += param & 0x0F;
00164 if (nMusicTempo > 255) nMusicTempo = 255;
00165 } else
00166 {
00167 nMusicTempo -= param & 0x0F;
00168 if (nMusicTempo < 32) nMusicTempo = 32;
00169 }
00170 break;
00171
00172 case CMD_S3MCMDEX:
00173 if ((param & 0xF0) == 0x60) { nSpeedCount = param & 0x0F; break; } else
00174 if ((param & 0xF0) == 0xB0) { param &= 0x0F; param |= 0x60; }
00175 case CMD_MODCMDEX:
00176 if ((param & 0xF0) == 0xE0) nSpeedCount = (param & 0x0F) * nMusicSpeed; else
00177 if ((param & 0xF0) == 0x60)
00178 {
00179 if (param & 0x0F) dwElapsedTime += (dwElapsedTime - patloop[nChn]) * (param & 0x0F);
00180 else patloop[nChn] = dwElapsedTime;
00181 }
00182 break;
00183 }
00184 if (!bAdjust) continue;
00185 switch(command)
00186 {
00187
00188 case CMD_PORTAMENTOUP:
00189 case CMD_PORTAMENTODOWN:
00190 if (param) pChn->nOldPortaUpDown = param;
00191 break;
00192
00193 case CMD_TONEPORTAMENTO:
00194 if (param) pChn->nPortamentoSlide = param << 2;
00195 break;
00196
00197 case CMD_OFFSET:
00198 if (param) pChn->nOldOffset = param;
00199 break;
00200
00201 case CMD_VOLUMESLIDE:
00202 case CMD_TONEPORTAVOL:
00203 case CMD_VIBRATOVOL:
00204 if (param) pChn->nOldVolumeSlide = param;
00205 break;
00206
00207 case CMD_VOLUME:
00208 vols[nChn] = param;
00209 break;
00210
00211 case CMD_GLOBALVOLUME:
00212 if (m_nType != MOD_TYPE_IT) param <<= 1;
00213 if (param > 128) param = 128;
00214 nGlbVol = param << 1;
00215 break;
00216
00217 case CMD_GLOBALVOLSLIDE:
00218 if (param) nOldGlbVolSlide = param; else param = nOldGlbVolSlide;
00219 if (((param & 0x0F) == 0x0F) && (param & 0xF0))
00220 {
00221 param >>= 4;
00222 if (m_nType != MOD_TYPE_IT) param <<= 1;
00223 nGlbVol += param << 1;
00224 } else
00225 if (((param & 0xF0) == 0xF0) && (param & 0x0F))
00226 {
00227 param = (param & 0x0F) << 1;
00228 if (m_nType != MOD_TYPE_IT) param <<= 1;
00229 nGlbVol -= param;
00230 } else
00231 if (param & 0xF0)
00232 {
00233 param >>= 4;
00234 param <<= 1;
00235 if (m_nType != MOD_TYPE_IT) param <<= 1;
00236 nGlbVol += param * nMusicSpeed;
00237 } else
00238 {
00239 param = (param & 0x0F) << 1;
00240 if (m_nType != MOD_TYPE_IT) param <<= 1;
00241 nGlbVol -= param * nMusicSpeed;
00242 }
00243 if (nGlbVol < 0) nGlbVol = 0;
00244 if (nGlbVol > 256) nGlbVol = 256;
00245 break;
00246 case CMD_CHANNELVOLUME:
00247 if (param <= 64) chnvols[nChn] = param;
00248 break;
00249 case CMD_CHANNELVOLSLIDE:
00250 if (param) oldparam[nChn] = param; else param = oldparam[nChn];
00251 pChn->nOldChnVolSlide = param;
00252 if (((param & 0x0F) == 0x0F) && (param & 0xF0))
00253 {
00254 param = (param >> 4) + chnvols[nChn];
00255 } else
00256 if (((param & 0xF0) == 0xF0) && (param & 0x0F))
00257 {
00258 if (chnvols[nChn] > (int)(param & 0x0F)) param = chnvols[nChn] - (param & 0x0F);
00259 else param = 0;
00260 } else
00261 if (param & 0x0F)
00262 {
00263 param = (param & 0x0F) * nMusicSpeed;
00264 param = (chnvols[nChn] > param) ? chnvols[nChn] - param : 0;
00265 } else param = ((param & 0xF0) >> 4) * nMusicSpeed + chnvols[nChn];
00266 if (param > 64) param = 64;
00267 chnvols[nChn] = param;
00268 break;
00269 }
00270 }
00271 nSpeedCount += nMusicSpeed;
00272 dwElapsedTime += (2500 * nSpeedCount) / nMusicTempo;
00273 }
00274 EndMod:
00275 if ((bAdjust) && (!bTotal))
00276 {
00277 m_nGlobalVolume = nGlbVol;
00278 m_nOldGlbVolSlide = nOldGlbVolSlide;
00279 for (UINT n=0; n<m_nChannels; n++)
00280 {
00281 Chn[n].nGlobalVol = chnvols[n];
00282 if (notes[n]) Chn[n].nNewNote = notes[n];
00283 if (instr[n]) Chn[n].nNewIns = instr[n];
00284 if (vols[n] != 0xFF)
00285 {
00286 if (vols[n] > 64) vols[n] = 64;
00287 Chn[n].nVolume = vols[n] << 2;
00288 }
00289 }
00290 }
00291 return (dwElapsedTime+500) / 1000;
00292 }
00293
00294
00296
00297
00298 void CSoundFile::InstrumentChange(MODCHANNEL *pChn, UINT instr, BOOL bPorta, BOOL bUpdVol, BOOL bResetEnv)
00299
00300 {
00301 BOOL bInstrumentChanged = FALSE;
00302
00303 if (instr >= MAX_INSTRUMENTS) return;
00304 INSTRUMENTHEADER *penv = Headers[instr];
00305 MODINSTRUMENT *psmp = &Ins[instr];
00306 UINT note = pChn->nNewNote;
00307 if ((penv) && (note) && (note <= 128))
00308 {
00309 if (penv->NoteMap[note-1] >= 0xFE) return;
00310 UINT n = penv->Keyboard[note-1];
00311 psmp = ((n) && (n < MAX_SAMPLES)) ? &Ins[n] : NULL;
00312 } else
00313 if (m_nInstruments)
00314 {
00315 if (note >= 0xFE) return;
00316 psmp = NULL;
00317 }
00318
00319 if (bUpdVol) pChn->nVolume = (psmp) ? psmp->nVolume : 0;
00320
00321 if (penv != pChn->pHeader)
00322 {
00323 bInstrumentChanged = TRUE;
00324 pChn->pHeader = penv;
00325 } else
00326
00327 if ((bPorta) && (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) && (penv)
00328 && (pChn->pInstrument) && (psmp != pChn->pInstrument))
00329 {
00330
00331
00332 return;
00333 }
00334
00335 pChn->nNewIns = 0;
00336 if (psmp)
00337 {
00338 if (penv)
00339 {
00340 pChn->nInsVol = (psmp->nGlobalVol * penv->nGlobalVol) >> 6;
00341 if (penv->dwFlags & ENV_SETPANNING) pChn->nPan = penv->nPan;
00342 pChn->nNNA = penv->nNNA;
00343 } else
00344 {
00345 pChn->nInsVol = psmp->nGlobalVol;
00346 }
00347 if (psmp->uFlags & CHN_PANNING) pChn->nPan = psmp->nPan;
00348 }
00349
00350 if (bResetEnv)
00351 {
00352 if ((!bPorta) || (!(m_nType & MOD_TYPE_IT)) || (m_dwSongFlags & SONG_ITCOMPATMODE)
00353 || (!pChn->nLength) || ((pChn->dwFlags & CHN_NOTEFADE) && (!pChn->nFadeOutVol)))
00354 {
00355 pChn->dwFlags |= CHN_FASTVOLRAMP;
00356 if ((m_nType & MOD_TYPE_IT) && (!bInstrumentChanged) && (penv) && (!(pChn->dwFlags & (CHN_KEYOFF|CHN_NOTEFADE))))
00357 {
00358 if (!(penv->dwFlags & ENV_VOLCARRY)) pChn->nVolEnvPosition = 0;
00359 if (!(penv->dwFlags & ENV_PANCARRY)) pChn->nPanEnvPosition = 0;
00360 if (!(penv->dwFlags & ENV_PITCHCARRY)) pChn->nPitchEnvPosition = 0;
00361 } else
00362 {
00363 pChn->nVolEnvPosition = 0;
00364 pChn->nPanEnvPosition = 0;
00365 pChn->nPitchEnvPosition = 0;
00366 }
00367 pChn->nAutoVibDepth = 0;
00368 pChn->nAutoVibPos = 0;
00369 } else
00370 if ((penv) && (!(penv->dwFlags & ENV_VOLUME)))
00371 {
00372 pChn->nVolEnvPosition = 0;
00373 pChn->nAutoVibDepth = 0;
00374 pChn->nAutoVibPos = 0;
00375 }
00376 }
00377
00378 if (!psmp)
00379 {
00380 pChn->pInstrument = NULL;
00381 pChn->nInsVol = 0;
00382 return;
00383 }
00384
00385 if ((bPorta) && (psmp == pChn->pInstrument))
00386 {
00387 if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT)) return;
00388 pChn->dwFlags &= ~(CHN_KEYOFF|CHN_NOTEFADE);
00389 pChn->dwFlags = (pChn->dwFlags & (0xFFFFFF00 | CHN_PINGPONGFLAG)) | (psmp->uFlags);
00390 } else
00391 {
00392 pChn->dwFlags &= ~(CHN_KEYOFF|CHN_NOTEFADE|CHN_VOLENV|CHN_PANENV|CHN_PITCHENV);
00393 pChn->dwFlags = (pChn->dwFlags & 0xFFFFFF00) | (psmp->uFlags);
00394 if (penv)
00395 {
00396 if (penv->dwFlags & ENV_VOLUME) pChn->dwFlags |= CHN_VOLENV;
00397 if (penv->dwFlags & ENV_PANNING) pChn->dwFlags |= CHN_PANENV;
00398 if (penv->dwFlags & ENV_PITCH) pChn->dwFlags |= CHN_PITCHENV;
00399 if ((penv->dwFlags & ENV_PITCH) && (penv->dwFlags & ENV_FILTER))
00400 {
00401 if (!pChn->nCutOff) pChn->nCutOff = 0x7F;
00402 }
00403 if (penv->nIFC & 0x80) pChn->nCutOff = penv->nIFC & 0x7F;
00404 if (penv->nIFR & 0x80) pChn->nResonance = penv->nIFR & 0x7F;
00405 }
00406 pChn->nVolSwing = pChn->nPanSwing = 0;
00407 }
00408 pChn->pInstrument = psmp;
00409 pChn->nLength = psmp->nLength;
00410 pChn->nLoopStart = psmp->nLoopStart;
00411 pChn->nLoopEnd = psmp->nLoopEnd;
00412 pChn->nC4Speed = psmp->nC4Speed;
00413 pChn->pSample = psmp->pSample;
00414 pChn->nTranspose = psmp->RelativeTone;
00415 pChn->nFineTune = psmp->nFineTune;
00416 if (pChn->dwFlags & CHN_SUSTAINLOOP)
00417 {
00418 pChn->nLoopStart = psmp->nSustainStart;
00419 pChn->nLoopEnd = psmp->nSustainEnd;
00420 pChn->dwFlags |= CHN_LOOP;
00421 if (pChn->dwFlags & CHN_PINGPONGSUSTAIN) pChn->dwFlags |= CHN_PINGPONGLOOP;
00422 }
00423 if ((pChn->dwFlags & CHN_LOOP) && (pChn->nLoopEnd < pChn->nLength)) pChn->nLength = pChn->nLoopEnd;
00424 }
00425
00426
00427 void CSoundFile::NoteChange(UINT nChn, int note, BOOL bPorta, BOOL bResetEnv)
00428
00429 {
00430 if (note < 1) return;
00431 MODCHANNEL * const pChn = &Chn[nChn];
00432 MODINSTRUMENT *pins = pChn->pInstrument;
00433 INSTRUMENTHEADER *penv = pChn->pHeader;
00434 if ((penv) && (note <= 0x80))
00435 {
00436 UINT n = penv->Keyboard[note - 1];
00437 if ((n) && (n < MAX_SAMPLES)) pins = &Ins[n];
00438 note = penv->NoteMap[note-1];
00439 }
00440
00441 if (note >= 0x80)
00442 {
00443
00444 KeyOff(nChn);
00445
00446 if (note == 0xFE)
00447 {
00448 pChn->dwFlags |= (CHN_NOTEFADE|CHN_FASTVOLRAMP);
00449 if ((!(m_nType & MOD_TYPE_IT)) || (m_nInstruments)) pChn->nVolume = 0;
00450 pChn->nFadeOutVol = 0;
00451 }
00452 return;
00453 }
00454 if (!pins) return;
00455 if ((!bPorta) && (m_nType & (MOD_TYPE_XM|MOD_TYPE_MED|MOD_TYPE_MT2)))
00456 {
00457 pChn->nTranspose = pins->RelativeTone;
00458 pChn->nFineTune = pins->nFineTune;
00459 }
00460 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2|MOD_TYPE_MED)) note += pChn->nTranspose;
00461 if (note < 1) note = 1;
00462 if (note > 132) note = 132;
00463 pChn->nNote = note;
00464 if ((!bPorta) || (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))) pChn->nNewIns = 0;
00465 UINT period = GetPeriodFromNote(note, pChn->nFineTune, pChn->nC4Speed);
00466 if (period)
00467 {
00468 if ((!bPorta) || (!pChn->nPeriod)) pChn->nPeriod = period;
00469 pChn->nPortamentoDest = period;
00470 if ((!bPorta) || ((!pChn->nLength) && (!(m_nType & MOD_TYPE_S3M))))
00471 {
00472 pChn->pInstrument = pins;
00473 pChn->pSample = pins->pSample;
00474 pChn->nLength = pins->nLength;
00475 pChn->nLoopEnd = pins->nLength;
00476 pChn->nLoopStart = 0;
00477 pChn->dwFlags = (pChn->dwFlags & 0xFFFFFF00) | (pins->uFlags);
00478 if (pChn->dwFlags & CHN_SUSTAINLOOP)
00479 {
00480 pChn->nLoopStart = pins->nSustainStart;
00481 pChn->nLoopEnd = pins->nSustainEnd;
00482 pChn->dwFlags &= ~CHN_PINGPONGLOOP;
00483 pChn->dwFlags |= CHN_LOOP;
00484 if (pChn->dwFlags & CHN_PINGPONGSUSTAIN) pChn->dwFlags |= CHN_PINGPONGLOOP;
00485 if (pChn->nLength > pChn->nLoopEnd) pChn->nLength = pChn->nLoopEnd;
00486 } else
00487 if (pChn->dwFlags & CHN_LOOP)
00488 {
00489 pChn->nLoopStart = pins->nLoopStart;
00490 pChn->nLoopEnd = pins->nLoopEnd;
00491 if (pChn->nLength > pChn->nLoopEnd) pChn->nLength = pChn->nLoopEnd;
00492 }
00493 pChn->nPos = 0;
00494 pChn->nPosLo = 0;
00495 if (pChn->nVibratoType < 4) pChn->nVibratoPos = ((m_nType & MOD_TYPE_IT) && (!(m_dwSongFlags & SONG_ITOLDEFFECTS))) ? 0x10 : 0;
00496 if (pChn->nTremoloType < 4) pChn->nTremoloPos = 0;
00497 }
00498 if (pChn->nPos >= pChn->nLength) pChn->nPos = pChn->nLoopStart;
00499 } else bPorta = FALSE;
00500 if ((!bPorta) || (!(m_nType & MOD_TYPE_IT))
00501 || ((pChn->dwFlags & CHN_NOTEFADE) && (!pChn->nFadeOutVol))
00502 || ((m_dwSongFlags & SONG_ITCOMPATMODE) && (pChn->nRowInstr)))
00503 {
00504 if ((m_nType & MOD_TYPE_IT) && (pChn->dwFlags & CHN_NOTEFADE) && (!pChn->nFadeOutVol))
00505 {
00506 pChn->nVolEnvPosition = 0;
00507 pChn->nPanEnvPosition = 0;
00508 pChn->nPitchEnvPosition = 0;
00509 pChn->nAutoVibDepth = 0;
00510 pChn->nAutoVibPos = 0;
00511 pChn->dwFlags &= ~CHN_NOTEFADE;
00512 pChn->nFadeOutVol = 65536;
00513 }
00514 if ((!bPorta) || (!(m_dwSongFlags & SONG_ITCOMPATMODE)) || (pChn->nRowInstr))
00515 {
00516 if ((!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) || (pChn->nRowInstr))
00517 {
00518 pChn->dwFlags &= ~CHN_NOTEFADE;
00519 pChn->nFadeOutVol = 65536;
00520 }
00521 }
00522 }
00523 pChn->dwFlags &= ~(CHN_EXTRALOUD|CHN_KEYOFF);
00524
00525 if (!bPorta)
00526 {
00527 pChn->nVUMeter = 0x100;
00528 pChn->nLeftVU = pChn->nRightVU = 0xFF;
00529 pChn->dwFlags &= ~CHN_FILTER;
00530 pChn->dwFlags |= CHN_FASTVOLRAMP;
00531 pChn->nRetrigCount = 0;
00532 pChn->nTremorCount = 0;
00533 if (bResetEnv)
00534 {
00535 pChn->nVolSwing = pChn->nPanSwing = 0;
00536 if (penv)
00537 {
00538 if (!(penv->dwFlags & ENV_VOLCARRY)) pChn->nVolEnvPosition = 0;
00539 if (!(penv->dwFlags & ENV_PANCARRY)) pChn->nPanEnvPosition = 0;
00540 if (!(penv->dwFlags & ENV_PITCHCARRY)) pChn->nPitchEnvPosition = 0;
00541 if (m_nType & MOD_TYPE_IT)
00542 {
00543
00544 if (penv->nVolSwing)
00545 {
00546 int d = ((LONG)penv->nVolSwing*(LONG)((rand() & 0xFF) - 0x7F)) / 128;
00547 pChn->nVolSwing = (signed short)((d * pChn->nVolume + 1)/128);
00548 }
00549
00550 if (penv->nPanSwing)
00551 {
00552 int d = ((LONG)penv->nPanSwing*(LONG)((rand() & 0xFF) - 0x7F)) / 128;
00553 pChn->nPanSwing = (signed short)d;
00554 }
00555 }
00556 }
00557 pChn->nAutoVibDepth = 0;
00558 pChn->nAutoVibPos = 0;
00559 }
00560 pChn->nLeftVol = pChn->nRightVol = 0;
00561 BOOL bFlt = (m_dwSongFlags & SONG_MPTFILTERMODE) ? FALSE : TRUE;
00562
00563 if (penv)
00564 {
00565 if (penv->nIFR & 0x80) { pChn->nResonance = penv->nIFR & 0x7F; bFlt = TRUE; }
00566 if (penv->nIFC & 0x80) { pChn->nCutOff = penv->nIFC & 0x7F; bFlt = TRUE; }
00567 } else
00568 {
00569 pChn->nVolSwing = pChn->nPanSwing = 0;
00570 }
00571 #ifndef NO_FILTER
00572 if ((pChn->nCutOff < 0x7F) && (bFlt)) SetupChannelFilter(pChn, TRUE);
00573 #endif // NO_FILTER
00574 }
00575 }
00576
00577
00578 UINT CSoundFile::GetNNAChannel(UINT nChn) const
00579
00580 {
00581 const MODCHANNEL *pChn = &Chn[nChn];
00582
00583 const MODCHANNEL *pi = &Chn[m_nChannels];
00584 for (UINT i=m_nChannels; i<MAX_CHANNELS; i++, pi++) if (!pi->nLength) return i;
00585 if (!pChn->nFadeOutVol) return 0;
00586
00587 UINT result = 0;
00588 DWORD vol = 64*65536;
00589 DWORD envpos = 0xFFFFFF;
00590 const MODCHANNEL *pj = &Chn[m_nChannels];
00591 for (UINT j=m_nChannels; j<MAX_CHANNELS; j++, pj++)
00592 {
00593 if (!pj->nFadeOutVol) return j;
00594 DWORD v = pj->nVolume;
00595 if (pj->dwFlags & CHN_NOTEFADE)
00596 v = v * pj->nFadeOutVol;
00597 else
00598 v <<= 16;
00599 if (pj->dwFlags & CHN_LOOP) v >>= 1;
00600 if ((v < vol) || ((v == vol) && (pj->nVolEnvPosition > envpos)))
00601 {
00602 envpos = pj->nVolEnvPosition;
00603 vol = v;
00604 result = j;
00605 }
00606 }
00607 return result;
00608 }
00609
00610
00611 void CSoundFile::CheckNNA(UINT nChn, UINT instr, int note, BOOL bForceCut)
00612
00613 {
00614 MODCHANNEL *pChn = &Chn[nChn];
00615 INSTRUMENTHEADER *penv = pChn->pHeader, *pHeader;
00616 signed char *pSample;
00617 if (note > 0x80) note = 0;
00618 if (note < 1) return;
00619
00620 if ((!(m_nType & (MOD_TYPE_IT|MOD_TYPE_MT2))) || (!m_nInstruments) || (bForceCut))
00621 {
00622 if ((m_dwSongFlags & SONG_CPUVERYHIGH)
00623 || (!pChn->nLength) || (pChn->dwFlags & CHN_MUTE)
00624 || ((!pChn->nLeftVol) && (!pChn->nRightVol))) return;
00625 UINT n = GetNNAChannel(nChn);
00626 if (!n) return;
00627 MODCHANNEL *p = &Chn[n];
00628
00629 *p = *pChn;
00630 p->dwFlags &= ~(CHN_VIBRATO|CHN_TREMOLO|CHN_PANBRELLO|CHN_MUTE|CHN_PORTAMENTO);
00631 p->nMasterChn = nChn+1;
00632 p->nCommand = 0;
00633
00634 p->nFadeOutVol = 0;
00635 p->dwFlags |= (CHN_NOTEFADE|CHN_FASTVOLRAMP);
00636
00637 pChn->nLength = pChn->nPos = pChn->nPosLo = 0;
00638 pChn->nROfs = pChn->nLOfs = 0;
00639 pChn->nLeftVol = pChn->nRightVol = 0;
00640 return;
00641 }
00642 if (instr >= MAX_INSTRUMENTS) instr = 0;
00643 pSample = pChn->pSample;
00644 pHeader = pChn->pHeader;
00645 if ((instr) && (note))
00646 {
00647 pHeader = Headers[instr];
00648 if (pHeader)
00649 {
00650 UINT n = 0;
00651 if (note <= 0x80)
00652 {
00653 n = pHeader->Keyboard[note-1];
00654 note = pHeader->NoteMap[note-1];
00655 if ((n) && (n < MAX_SAMPLES)) pSample = Ins[n].pSample;
00656 }
00657 } else pSample = NULL;
00658 }
00659 if (!penv) return;
00660 MODCHANNEL *p = pChn;
00661 for (UINT i=nChn; i<MAX_CHANNELS; p++, i++)
00662 if ((i >= m_nChannels) || (p == pChn))
00663 {
00664 if (((p->nMasterChn == nChn+1) || (p == pChn)) && (p->pHeader))
00665 {
00666 BOOL bOk = FALSE;
00667
00668 switch(p->pHeader->nDCT)
00669 {
00670
00671 case DCT_NOTE:
00672 if ((note) && (p->nNote == note) && (pHeader == p->pHeader)) bOk = TRUE;
00673 break;
00674
00675 case DCT_SAMPLE:
00676 if ((pSample) && (pSample == p->pSample)) bOk = TRUE;
00677 break;
00678
00679 case DCT_INSTRUMENT:
00680 if (pHeader == p->pHeader) bOk = TRUE;
00681 break;
00682 }
00683
00684 if (bOk)
00685 {
00686 switch(p->pHeader->nDNA)
00687 {
00688
00689 case DNA_NOTECUT:
00690 KeyOff(i);
00691 p->nVolume = 0;
00692 break;
00693
00694 case DNA_NOTEOFF:
00695 KeyOff(i);
00696 break;
00697
00698 case DNA_NOTEFADE:
00699 p->dwFlags |= CHN_NOTEFADE;
00700 break;
00701 }
00702 if (!p->nVolume)
00703 {
00704 p->nFadeOutVol = 0;
00705 p->dwFlags |= (CHN_NOTEFADE|CHN_FASTVOLRAMP);
00706 }
00707 }
00708 }
00709 }
00710 if (pChn->dwFlags & CHN_MUTE) return;
00711
00712 if ((pChn->nVolume) && (pChn->nLength))
00713 {
00714 UINT n = GetNNAChannel(nChn);
00715 if (n)
00716 {
00717 MODCHANNEL *p = &Chn[n];
00718
00719 *p = *pChn;
00720 p->dwFlags &= ~(CHN_VIBRATO|CHN_TREMOLO|CHN_PANBRELLO|CHN_MUTE|CHN_PORTAMENTO);
00721 p->nMasterChn = nChn+1;
00722 p->nCommand = 0;
00723
00724 switch(pChn->nNNA)
00725 {
00726 case NNA_NOTEOFF: KeyOff(n); break;
00727 case NNA_NOTECUT:
00728 p->nFadeOutVol = 0;
00729 case NNA_NOTEFADE: p->dwFlags |= CHN_NOTEFADE; break;
00730 }
00731 if (!p->nVolume)
00732 {
00733 p->nFadeOutVol = 0;
00734 p->dwFlags |= (CHN_NOTEFADE|CHN_FASTVOLRAMP);
00735 }
00736
00737 pChn->nLength = pChn->nPos = pChn->nPosLo = 0;
00738 pChn->nROfs = pChn->nLOfs = 0;
00739 }
00740 }
00741 }
00742
00743
00744 BOOL CSoundFile::ProcessEffects()
00745
00746 {
00747 int nBreakRow = -1, nPosJump = -1, nPatLoopRow = -1;
00748 MODCHANNEL *pChn = Chn;
00749 for (UINT nChn=0; nChn<m_nChannels; nChn++, pChn++)
00750 {
00751 UINT instr = pChn->nRowInstr;
00752 UINT volcmd = pChn->nRowVolCmd;
00753 UINT vol = pChn->nRowVolume;
00754 UINT cmd = pChn->nRowCommand;
00755 UINT param = pChn->nRowParam;
00756 BOOL bPorta = ((cmd != CMD_TONEPORTAMENTO) && (cmd != CMD_TONEPORTAVOL) && (volcmd != VOLCMD_TONEPORTAMENTO)) ? FALSE : TRUE;
00757 UINT nStartTick = 0;
00758
00759 pChn->dwFlags &= ~CHN_FASTVOLRAMP;
00760
00761 if ((cmd == CMD_MODCMDEX) || (cmd == CMD_S3MCMDEX))
00762 {
00763 if ((!param) && (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))) param = pChn->nOldCmdEx; else pChn->nOldCmdEx = param;
00764
00765 if ((param & 0xF0) == 0xD0)
00766 {
00767 nStartTick = param & 0x0F;
00768 } else
00769 if (!m_nTickCount)
00770 {
00771
00772 if ((((param & 0xF0) == 0x60) && (cmd == CMD_MODCMDEX))
00773 || (((param & 0xF0) == 0xB0) && (cmd == CMD_S3MCMDEX)))
00774 {
00775 int nloop = PatternLoop(pChn, param & 0x0F);
00776 if (nloop >= 0) nPatLoopRow = nloop;
00777 } else
00778
00779 if ((param & 0xF0) == 0xE0)
00780 {
00781 m_nPatternDelay = param & 0x0F;
00782 }
00783 }
00784 }
00785
00786
00787 if (m_nTickCount == nStartTick)
00788 {
00789 UINT note = pChn->nRowNote;
00790 if (instr) pChn->nNewIns = instr;
00791
00792 if (m_nType & (MOD_TYPE_MOD|MOD_TYPE_XM|MOD_TYPE_MT2))
00793 {
00794 if ((note == 0xFF) && ((!pChn->pHeader) || (!(pChn->pHeader->dwFlags & ENV_VOLUME))))
00795 {
00796 pChn->dwFlags |= CHN_FASTVOLRAMP;
00797 pChn->nVolume = 0;
00798 note = instr = 0;
00799 }
00800 }
00801 if ((!note) && (instr))
00802 {
00803 if (m_nInstruments)
00804 {
00805 if (pChn->pInstrument) pChn->nVolume = pChn->pInstrument->nVolume;
00806 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
00807 {
00808 pChn->dwFlags |= CHN_FASTVOLRAMP;
00809 pChn->nVolEnvPosition = 0;
00810 pChn->nPanEnvPosition = 0;
00811 pChn->nPitchEnvPosition = 0;
00812 pChn->nAutoVibDepth = 0;
00813 pChn->nAutoVibPos = 0;
00814 pChn->dwFlags &= ~CHN_NOTEFADE;
00815 pChn->nFadeOutVol = 65536;
00816 }
00817 } else
00818 {
00819 if (instr < MAX_SAMPLES) pChn->nVolume = Ins[instr].nVolume;
00820 }
00821 if (!(m_nType & MOD_TYPE_IT)) instr = 0;
00822 }
00823
00824 if (instr >= MAX_INSTRUMENTS) instr = 0;
00825
00826 if (note >= 0xFE) instr = 0;
00827 if ((note) && (note <= 128)) pChn->nNewNote = note;
00828
00829 if ((note) && (note <= 128) && (!bPorta))
00830 {
00831 CheckNNA(nChn, instr, note, FALSE);
00832 }
00833
00834 if (instr)
00835 {
00836 MODINSTRUMENT *psmp = pChn->pInstrument;
00837 InstrumentChange(pChn, instr, bPorta, TRUE);
00838 pChn->nNewIns = 0;
00839
00840 if ((m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))
00841 && (psmp != pChn->pInstrument) && (note) && (note < 0x80))
00842 {
00843 bPorta = FALSE;
00844 }
00845 }
00846
00847 if (note)
00848 {
00849 if ((!instr) && (pChn->nNewIns) && (note < 0x80))
00850 {
00851 InstrumentChange(pChn, pChn->nNewIns, bPorta, FALSE, (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) ? FALSE : TRUE);
00852 pChn->nNewIns = 0;
00853 }
00854 NoteChange(nChn, note, bPorta, (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) ? FALSE : TRUE);
00855 if ((bPorta) && (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) && (instr))
00856 {
00857 pChn->dwFlags |= CHN_FASTVOLRAMP;
00858 pChn->nVolEnvPosition = 0;
00859 pChn->nPanEnvPosition = 0;
00860 pChn->nPitchEnvPosition = 0;
00861 pChn->nAutoVibDepth = 0;
00862 pChn->nAutoVibPos = 0;
00863 }
00864 }
00865
00866 if (volcmd == VOLCMD_VOLUME)
00867 {
00868 if (vol > 64) vol = 64;
00869 pChn->nVolume = vol << 2;
00870 pChn->dwFlags |= CHN_FASTVOLRAMP;
00871 } else
00872 if (volcmd == VOLCMD_PANNING)
00873 {
00874 if (vol > 64) vol = 64;
00875 pChn->nPan = vol << 2;
00876 pChn->dwFlags |= CHN_FASTVOLRAMP;
00877 }
00878 }
00879
00880
00881 if ((volcmd > VOLCMD_PANNING) && (m_nTickCount >= nStartTick))
00882 {
00883 if (volcmd == VOLCMD_TONEPORTAMENTO)
00884 {
00885 if (m_nType & MOD_TYPE_IT)
00886 TonePortamento(pChn, ImpulseTrackerPortaVolCmd[vol & 0x0F]);
00887 else
00888 TonePortamento(pChn, vol * 16);
00889 } else
00890 {
00891 if (vol) pChn->nOldVolParam = vol; else vol = pChn->nOldVolParam;
00892 switch(volcmd)
00893 {
00894 case VOLCMD_VOLSLIDEUP:
00895 VolumeSlide(pChn, vol << 4);
00896 break;
00897
00898 case VOLCMD_VOLSLIDEDOWN:
00899 VolumeSlide(pChn, vol);
00900 break;
00901
00902 case VOLCMD_FINEVOLUP:
00903 if (m_nType & MOD_TYPE_IT)
00904 {
00905 if (m_nTickCount == nStartTick) VolumeSlide(pChn, (vol << 4) | 0x0F);
00906 } else
00907 FineVolumeUp(pChn, vol);
00908 break;
00909
00910 case VOLCMD_FINEVOLDOWN:
00911 if (m_nType & MOD_TYPE_IT)
00912 {
00913 if (m_nTickCount == nStartTick) VolumeSlide(pChn, 0xF0 | vol);
00914 } else
00915 FineVolumeDown(pChn, vol);
00916 break;
00917
00918 case VOLCMD_VIBRATOSPEED:
00919 Vibrato(pChn, vol << 4);
00920 break;
00921
00922 case VOLCMD_VIBRATO:
00923 Vibrato(pChn, vol);
00924 break;
00925
00926 case VOLCMD_PANSLIDELEFT:
00927 PanningSlide(pChn, vol);
00928 break;
00929
00930 case VOLCMD_PANSLIDERIGHT:
00931 PanningSlide(pChn, vol << 4);
00932 break;
00933
00934 case VOLCMD_PORTAUP:
00935 PortamentoUp(pChn, vol << 2);
00936 break;
00937
00938 case VOLCMD_PORTADOWN:
00939 PortamentoDown(pChn, vol << 2);
00940 break;
00941 }
00942 }
00943 }
00944
00945
00946 if (cmd) switch (cmd)
00947 {
00948
00949 case CMD_VOLUME:
00950 if (!m_nTickCount)
00951 {
00952 pChn->nVolume = (param < 64) ? param*4 : 256;
00953 pChn->dwFlags |= CHN_FASTVOLRAMP;
00954 }
00955 break;
00956
00957
00958 case CMD_PORTAMENTOUP:
00959 if ((!param) && (m_nType & MOD_TYPE_MOD)) break;
00960 PortamentoUp(pChn, param);
00961 break;
00962
00963
00964 case CMD_PORTAMENTODOWN:
00965 if ((!param) && (m_nType & MOD_TYPE_MOD)) break;
00966 PortamentoDown(pChn, param);
00967 break;
00968
00969
00970 case CMD_VOLUMESLIDE:
00971 if ((param) || (m_nType != MOD_TYPE_MOD)) VolumeSlide(pChn, param);
00972 break;
00973
00974
00975 case CMD_TONEPORTAMENTO:
00976 TonePortamento(pChn, param);
00977 break;
00978
00979
00980 case CMD_TONEPORTAVOL:
00981 if ((param) || (m_nType != MOD_TYPE_MOD)) VolumeSlide(pChn, param);
00982 TonePortamento(pChn, 0);
00983 break;
00984
00985
00986 case CMD_VIBRATO:
00987 Vibrato(pChn, param);
00988 break;
00989
00990
00991 case CMD_VIBRATOVOL:
00992 if ((param) || (m_nType != MOD_TYPE_MOD)) VolumeSlide(pChn, param);
00993 Vibrato(pChn, 0);
00994 break;
00995
00996
00997 case CMD_SPEED:
00998 if (!m_nTickCount) SetSpeed(param);
00999 break;
01000
01001
01002 case CMD_TEMPO:
01003 if (!m_nTickCount)
01004 {
01005 if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))
01006 {
01007 if (param) pChn->nOldTempo = param; else param = pChn->nOldTempo;
01008 }
01009 SetTempo(param);
01010 }
01011 break;
01012
01013
01014 case CMD_OFFSET:
01015 if (m_nTickCount) break;
01016 if (param) pChn->nOldOffset = param; else param = pChn->nOldOffset;
01017 param <<= 8;
01018 param |= (UINT)(pChn->nOldHiOffset) << 16;
01019 if ((pChn->nRowNote) && (pChn->nRowNote < 0x80))
01020 {
01021 if (bPorta)
01022 pChn->nPos = param;
01023 else
01024 pChn->nPos += param;
01025 if (pChn->nPos >= pChn->nLength)
01026 {
01027 if (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)))
01028 {
01029 pChn->nPos = pChn->nLoopStart;
01030 if ((m_dwSongFlags & SONG_ITOLDEFFECTS) && (pChn->nLength > 4))
01031 {
01032 pChn->nPos = pChn->nLength - 2;
01033 }
01034 }
01035 }
01036 } else
01037 if ((param < pChn->nLength) && (m_nType & (MOD_TYPE_MTM|MOD_TYPE_DMF)))
01038 {
01039 pChn->nPos = param;
01040 }
01041 break;
01042
01043
01044 case CMD_ARPEGGIO:
01045 if ((m_nTickCount) || (!pChn->nPeriod) || (!pChn->nNote)) break;
01046 if ((!param) && (!(m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT)))) break;
01047 pChn->nCommand = CMD_ARPEGGIO;
01048 if (param) pChn->nArpeggio = param;
01049 break;
01050
01051
01052 case CMD_RETRIG:
01053 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
01054 {
01055 if (!(param & 0xF0)) param |= pChn->nRetrigParam & 0xF0;
01056 if (!(param & 0x0F)) param |= pChn->nRetrigParam & 0x0F;
01057 param |= 0x100;
01058 }
01059 if (param) pChn->nRetrigParam = (BYTE)(param & 0xFF); else param = pChn->nRetrigParam;
01060 RetrigNote(nChn, param);
01061 break;
01062
01063
01064 case CMD_TREMOR:
01065 if (m_nTickCount) break;
01066 pChn->nCommand = CMD_TREMOR;
01067 if (param) pChn->nTremorParam = param;
01068 break;
01069
01070
01071 case CMD_GLOBALVOLUME:
01072 if (m_nTickCount) break;
01073 if (m_nType != MOD_TYPE_IT) param <<= 1;
01074 if (param > 128) param = 128;
01075 m_nGlobalVolume = param << 1;
01076 break;
01077
01078
01079 case CMD_GLOBALVOLSLIDE:
01080 GlobalVolSlide(param);
01081 break;
01082
01083
01084 case CMD_PANNING8:
01085 if (m_nTickCount) break;
01086 if (!(m_dwSongFlags & SONG_SURROUNDPAN)) pChn->dwFlags &= ~CHN_SURROUND;
01087 if (m_nType & (MOD_TYPE_IT|MOD_TYPE_XM|MOD_TYPE_MT2))
01088 {
01089 pChn->nPan = param;
01090 } else
01091 if (param <= 0x80)
01092 {
01093 pChn->nPan = param << 1;
01094 } else
01095 if (param == 0xA4)
01096 {
01097 pChn->dwFlags |= CHN_SURROUND;
01098 pChn->nPan = 0x80;
01099 }
01100 pChn->dwFlags |= CHN_FASTVOLRAMP;
01101 break;
01102
01103
01104 case CMD_PANNINGSLIDE:
01105 PanningSlide(pChn, param);
01106 break;
01107
01108
01109 case CMD_TREMOLO:
01110 Tremolo(pChn, param);
01111 break;
01112
01113
01114 case CMD_FINEVIBRATO:
01115 FineVibrato(pChn, param);
01116 break;
01117
01118
01119 case CMD_MODCMDEX:
01120 ExtendedMODCommands(nChn, param);
01121 break;
01122
01123
01124 case CMD_S3MCMDEX:
01125 ExtendedS3MCommands(nChn, param);
01126 break;
01127
01128
01129 case CMD_KEYOFF:
01130 if (!m_nTickCount) KeyOff(nChn);
01131 break;
01132
01133
01134 case CMD_XFINEPORTAUPDOWN:
01135 switch(param & 0xF0)
01136 {
01137 case 0x10: ExtraFinePortamentoUp(pChn, param & 0x0F); break;
01138 case 0x20: ExtraFinePortamentoDown(pChn, param & 0x0F); break;
01139
01140 case 0x50:
01141 case 0x60:
01142 case 0x70:
01143 case 0x90:
01144 case 0xA0: ExtendedS3MCommands(nChn, param); break;
01145 }
01146 break;
01147
01148
01149 case CMD_CHANNELVOLUME:
01150 if (m_nTickCount) break;
01151 if (param <= 64)
01152 {
01153 pChn->nGlobalVol = param;
01154 pChn->dwFlags |= CHN_FASTVOLRAMP;
01155 }
01156 break;
01157
01158
01159 case CMD_CHANNELVOLSLIDE:
01160 ChannelVolSlide(pChn, param);
01161 break;
01162
01163
01164 case CMD_PANBRELLO:
01165 Panbrello(pChn, param);
01166 break;
01167
01168
01169 case CMD_SETENVPOSITION:
01170 if (!m_nTickCount)
01171 {
01172 pChn->nVolEnvPosition = param;
01173 pChn->nPanEnvPosition = param;
01174 pChn->nPitchEnvPosition = param;
01175 if (pChn->pHeader)
01176 {
01177 INSTRUMENTHEADER *penv = pChn->pHeader;
01178 if ((pChn->dwFlags & CHN_PANENV) && (penv->nPanEnv) && (param > penv->PanPoints[penv->nPanEnv-1]))
01179 {
01180 pChn->dwFlags &= ~CHN_PANENV;
01181 }
01182 }
01183 }
01184 break;
01185
01186
01187 case CMD_POSITIONJUMP:
01188 nPosJump = param;
01189 break;
01190
01191
01192 case CMD_PATTERNBREAK:
01193 nBreakRow = param;
01194 break;
01195
01196
01197 case CMD_MIDI:
01198 if (m_nTickCount) break;
01199 if (param < 0x80)
01200 {
01201 ProcessMidiMacro(nChn, &m_MidiCfg.szMidiSFXExt[pChn->nActiveMacro << 5], param);
01202 } else
01203 {
01204 ProcessMidiMacro(nChn, &m_MidiCfg.szMidiZXXExt[(param & 0x7F) << 5], 0);
01205 }
01206 break;
01207 }
01208 }
01209
01210
01211 if (!m_nTickCount)
01212 {
01213
01214 if (nPatLoopRow >= 0)
01215 {
01216 m_nNextPattern = m_nCurrentPattern;
01217 m_nNextRow = nPatLoopRow;
01218 if (m_nPatternDelay) m_nNextRow++;
01219 } else
01220
01221 if ((nBreakRow >= 0) || (nPosJump >= 0))
01222 {
01223 BOOL bNoLoop = FALSE;
01224 if (nPosJump < 0) nPosJump = m_nCurrentPattern+1;
01225 if (nBreakRow < 0) nBreakRow = 0;
01226
01227 #ifndef FASTSOUNDLIB
01228 if ((nPosJump < (int)m_nCurrentPattern)
01229 || ((nPosJump == (int)m_nCurrentPattern) && (nBreakRow <= (int)m_nRow)))
01230 {
01231 if (!IsValidBackwardJump(m_nCurrentPattern, m_nRow, nPosJump, nBreakRow))
01232 {
01233 if (m_nRepeatCount)
01234 {
01235 if (m_nRepeatCount > 0) m_nRepeatCount--;
01236 } else
01237 {
01238 #ifdef MODPLUG_TRACKER
01239 if (gdwSoundSetup & SNDMIX_NOBACKWARDJUMPS)
01240 #endif
01241
01242 bNoLoop = TRUE;
01243
01244
01245 m_nRepeatCount = m_nInitialRepeatCount;
01246 }
01247 }
01248 }
01249 #endif // FASTSOUNDLIB
01250 if (((!bNoLoop) && (nPosJump < MAX_ORDERS))
01251 && ((nPosJump != (int)m_nCurrentPattern) || (nBreakRow != (int)m_nRow)))
01252 {
01253 if (nPosJump != (int)m_nCurrentPattern)
01254 {
01255 for (UINT i=0; i<m_nChannels; i++) Chn[i].nPatternLoopCount = 0;
01256 }
01257 m_nNextPattern = nPosJump;
01258 m_nNextRow = (UINT)nBreakRow;
01259 }
01260 }
01261 }
01262 return TRUE;
01263 }
01264
01265
01267
01268
01269 void CSoundFile::PortamentoUp(MODCHANNEL *pChn, UINT param)
01270
01271 {
01272 if (param) pChn->nOldPortaUpDown = param; else param = pChn->nOldPortaUpDown;
01273 if ((m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM)) && ((param & 0xF0) >= 0xE0))
01274 {
01275 if (param & 0x0F)
01276 {
01277 if ((param & 0xF0) == 0xF0)
01278 {
01279 FinePortamentoUp(pChn, param & 0x0F);
01280 } else
01281 if ((param & 0xF0) == 0xE0)
01282 {
01283 ExtraFinePortamentoUp(pChn, param & 0x0F);
01284 }
01285 }
01286 return;
01287 }
01288
01289 if (!(m_dwSongFlags & SONG_FIRSTTICK))
01290 {
01291 DoFreqSlide(pChn, -(int)(param * 4));
01292 }
01293 }
01294
01295
01296 void CSoundFile::PortamentoDown(MODCHANNEL *pChn, UINT param)
01297
01298 {
01299 if (param) pChn->nOldPortaUpDown = param; else param = pChn->nOldPortaUpDown;
01300 if ((m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM)) && ((param & 0xF0) >= 0xE0))
01301 {
01302 if (param & 0x0F)
01303 {
01304 if ((param & 0xF0) == 0xF0)
01305 {
01306 FinePortamentoDown(pChn, param & 0x0F);
01307 } else
01308 if ((param & 0xF0) == 0xE0)
01309 {
01310 ExtraFinePortamentoDown(pChn, param & 0x0F);
01311 }
01312 }
01313 return;
01314 }
01315 if (!(m_dwSongFlags & SONG_FIRSTTICK)) DoFreqSlide(pChn, (int)(param << 2));
01316 }
01317
01318
01319 void CSoundFile::FinePortamentoUp(MODCHANNEL *pChn, UINT param)
01320
01321 {
01322 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
01323 {
01324 if (param) pChn->nOldFinePortaUpDown = param; else param = pChn->nOldFinePortaUpDown;
01325 }
01326 if (m_dwSongFlags & SONG_FIRSTTICK)
01327 {
01328 if ((pChn->nPeriod) && (param))
01329 {
01330 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))))
01331 {
01332 pChn->nPeriod = _muldivr(pChn->nPeriod, LinearSlideDownTable[param & 0x0F], 65536);
01333 } else
01334 {
01335 pChn->nPeriod -= (int)(param * 4);
01336 }
01337 if (pChn->nPeriod < 1) pChn->nPeriod = 1;
01338 }
01339 }
01340 }
01341
01342
01343 void CSoundFile::FinePortamentoDown(MODCHANNEL *pChn, UINT param)
01344
01345 {
01346 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
01347 {
01348 if (param) pChn->nOldFinePortaUpDown = param; else param = pChn->nOldFinePortaUpDown;
01349 }
01350 if (m_dwSongFlags & SONG_FIRSTTICK)
01351 {
01352 if ((pChn->nPeriod) && (param))
01353 {
01354 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))))
01355 {
01356 pChn->nPeriod = _muldivr(pChn->nPeriod, LinearSlideUpTable[param & 0x0F], 65536);
01357 } else
01358 {
01359 pChn->nPeriod += (int)(param * 4);
01360 }
01361 if (pChn->nPeriod > 0xFFFF) pChn->nPeriod = 0xFFFF;
01362 }
01363 }
01364 }
01365
01366
01367 void CSoundFile::ExtraFinePortamentoUp(MODCHANNEL *pChn, UINT param)
01368
01369 {
01370 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
01371 {
01372 if (param) pChn->nOldFinePortaUpDown = param; else param = pChn->nOldFinePortaUpDown;
01373 }
01374 if (m_dwSongFlags & SONG_FIRSTTICK)
01375 {
01376 if ((pChn->nPeriod) && (param))
01377 {
01378 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))))
01379 {
01380 pChn->nPeriod = _muldivr(pChn->nPeriod, FineLinearSlideDownTable[param & 0x0F], 65536);
01381 } else
01382 {
01383 pChn->nPeriod -= (int)(param);
01384 }
01385 if (pChn->nPeriod < 1) pChn->nPeriod = 1;
01386 }
01387 }
01388 }
01389
01390
01391 void CSoundFile::ExtraFinePortamentoDown(MODCHANNEL *pChn, UINT param)
01392
01393 {
01394 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
01395 {
01396 if (param) pChn->nOldFinePortaUpDown = param; else param = pChn->nOldFinePortaUpDown;
01397 }
01398 if (m_dwSongFlags & SONG_FIRSTTICK)
01399 {
01400 if ((pChn->nPeriod) && (param))
01401 {
01402 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))))
01403 {
01404 pChn->nPeriod = _muldivr(pChn->nPeriod, FineLinearSlideUpTable[param & 0x0F], 65536);
01405 } else
01406 {
01407 pChn->nPeriod += (int)(param);
01408 }
01409 if (pChn->nPeriod > 0xFFFF) pChn->nPeriod = 0xFFFF;
01410 }
01411 }
01412 }
01413
01414
01415
01416 void CSoundFile::TonePortamento(MODCHANNEL *pChn, UINT param)
01417
01418 {
01419 if (param) pChn->nPortamentoSlide = param * 4;
01420 pChn->dwFlags |= CHN_PORTAMENTO;
01421 if ((pChn->nPeriod) && (pChn->nPortamentoDest) && (!(m_dwSongFlags & SONG_FIRSTTICK)))
01422 {
01423 if (pChn->nPeriod < pChn->nPortamentoDest)
01424 {
01425 LONG delta = (int)pChn->nPortamentoSlide;
01426 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))))
01427 {
01428 UINT n = pChn->nPortamentoSlide >> 2;
01429 if (n > 255) n = 255;
01430 delta = _muldivr(pChn->nPeriod, LinearSlideUpTable[n], 65536) - pChn->nPeriod;
01431 if (delta < 1) delta = 1;
01432 }
01433 pChn->nPeriod += delta;
01434 if (pChn->nPeriod > pChn->nPortamentoDest) pChn->nPeriod = pChn->nPortamentoDest;
01435 } else
01436 if (pChn->nPeriod > pChn->nPortamentoDest)
01437 {
01438 LONG delta = - (int)pChn->nPortamentoSlide;
01439 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))))
01440 {
01441 UINT n = pChn->nPortamentoSlide >> 2;
01442 if (n > 255) n = 255;
01443 delta = _muldivr(pChn->nPeriod, LinearSlideDownTable[n], 65536) - pChn->nPeriod;
01444 if (delta > -1) delta = -1;
01445 }
01446 pChn->nPeriod += delta;
01447 if (pChn->nPeriod < pChn->nPortamentoDest) pChn->nPeriod = pChn->nPortamentoDest;
01448 }
01449 }
01450 }
01451
01452
01453 void CSoundFile::Vibrato(MODCHANNEL *p, UINT param)
01454
01455 {
01456 if (param & 0x0F) p->nVibratoDepth = (param & 0x0F) * 4;
01457 if (param & 0xF0) p->nVibratoSpeed = (param >> 4) & 0x0F;
01458 p->dwFlags |= CHN_VIBRATO;
01459 }
01460
01461
01462 void CSoundFile::FineVibrato(MODCHANNEL *p, UINT param)
01463
01464 {
01465 if (param & 0x0F) p->nVibratoDepth = param & 0x0F;
01466 if (param & 0xF0) p->nVibratoSpeed = (param >> 4) & 0x0F;
01467 p->dwFlags |= CHN_VIBRATO;
01468 }
01469
01470
01471 void CSoundFile::Panbrello(MODCHANNEL *p, UINT param)
01472
01473 {
01474 if (param & 0x0F) p->nPanbrelloDepth = param & 0x0F;
01475 if (param & 0xF0) p->nPanbrelloSpeed = (param >> 4) & 0x0F;
01476 p->dwFlags |= CHN_PANBRELLO;
01477 }
01478
01479
01480 void CSoundFile::VolumeSlide(MODCHANNEL *pChn, UINT param)
01481
01482 {
01483 if (param) pChn->nOldVolumeSlide = param; else param = pChn->nOldVolumeSlide;
01484 LONG newvolume = pChn->nVolume;
01485 if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM|MOD_TYPE_AMF))
01486 {
01487 if ((param & 0x0F) == 0x0F)
01488 {
01489 if (param & 0xF0)
01490 {
01491 FineVolumeUp(pChn, (param >> 4));
01492 return;
01493 } else
01494 {
01495 if ((m_dwSongFlags & SONG_FIRSTTICK) && (!(m_dwSongFlags & SONG_FASTVOLSLIDES)))
01496 {
01497 newvolume -= 0x0F * 4;
01498 }
01499 }
01500 } else
01501 if ((param & 0xF0) == 0xF0)
01502 {
01503 if (param & 0x0F)
01504 {
01505 FineVolumeDown(pChn, (param & 0x0F));
01506 return;
01507 } else
01508 {
01509 if ((m_dwSongFlags & SONG_FIRSTTICK) && (!(m_dwSongFlags & SONG_FASTVOLSLIDES)))
01510 {
01511 newvolume += 0x0F * 4;
01512 }
01513 }
01514 }
01515 }
01516 if ((!(m_dwSongFlags & SONG_FIRSTTICK)) || (m_dwSongFlags & SONG_FASTVOLSLIDES))
01517 {
01518 if (param & 0x0F) newvolume -= (int)((param & 0x0F) * 4);
01519 else newvolume += (int)((param & 0xF0) >> 2);
01520 if (m_nType & MOD_TYPE_MOD) pChn->dwFlags |= CHN_FASTVOLRAMP;
01521 }
01522 if (newvolume < 0) newvolume = 0;
01523 if (newvolume > 256) newvolume = 256;
01524 pChn->nVolume = newvolume;
01525 }
01526
01527
01528 void CSoundFile::PanningSlide(MODCHANNEL *pChn, UINT param)
01529
01530 {
01531 LONG nPanSlide = 0;
01532 if (param) pChn->nOldPanSlide = param; else param = pChn->nOldPanSlide;
01533 if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM))
01534 {
01535 if (((param & 0x0F) == 0x0F) && (param & 0xF0))
01536 {
01537 if (m_dwSongFlags & SONG_FIRSTTICK)
01538 {
01539 param = (param & 0xF0) >> 2;
01540 nPanSlide = - (int)param;
01541 }
01542 } else
01543 if (((param & 0xF0) == 0xF0) && (param & 0x0F))
01544 {
01545 if (m_dwSongFlags & SONG_FIRSTTICK)
01546 {
01547 nPanSlide = (param & 0x0F) << 2;
01548 }
01549 } else
01550 {
01551 if (!(m_dwSongFlags & SONG_FIRSTTICK))
01552 {
01553 if (param & 0x0F) nPanSlide = (int)((param & 0x0F) << 2);
01554 else nPanSlide = -(int)((param & 0xF0) >> 2);
01555 }
01556 }
01557 } else
01558 {
01559 if (!(m_dwSongFlags & SONG_FIRSTTICK))
01560 {
01561 if (param & 0x0F) nPanSlide = -(int)((param & 0x0F) << 2);
01562 else nPanSlide = (int)((param & 0xF0) >> 2);
01563 }
01564 }
01565 if (nPanSlide)
01566 {
01567 nPanSlide += pChn->nPan;
01568 if (nPanSlide < 0) nPanSlide = 0;
01569 if (nPanSlide > 256) nPanSlide = 256;
01570 pChn->nPan = nPanSlide;
01571 }
01572 }
01573
01574
01575 void CSoundFile::FineVolumeUp(MODCHANNEL *pChn, UINT param)
01576
01577 {
01578 if (param) pChn->nOldFineVolUpDown = param; else param = pChn->nOldFineVolUpDown;
01579 if (m_dwSongFlags & SONG_FIRSTTICK)
01580 {
01581 pChn->nVolume += param * 4;
01582 if (pChn->nVolume > 256) pChn->nVolume = 256;
01583 if (m_nType & MOD_TYPE_MOD) pChn->dwFlags |= CHN_FASTVOLRAMP;
01584 }
01585 }
01586
01587
01588 void CSoundFile::FineVolumeDown(MODCHANNEL *pChn, UINT param)
01589
01590 {
01591 if (param) pChn->nOldFineVolUpDown = param; else param = pChn->nOldFineVolUpDown;
01592 if (m_dwSongFlags & SONG_FIRSTTICK)
01593 {
01594 pChn->nVolume -= param * 4;
01595 if (pChn->nVolume < 0) pChn->nVolume = 0;
01596 if (m_nType & MOD_TYPE_MOD) pChn->dwFlags |= CHN_FASTVOLRAMP;
01597 }
01598 }
01599
01600
01601 void CSoundFile::Tremolo(MODCHANNEL *p, UINT param)
01602
01603 {
01604 if (param & 0x0F) p->nTremoloDepth = (param & 0x0F) << 2;
01605 if (param & 0xF0) p->nTremoloSpeed = (param >> 4) & 0x0F;
01606 p->dwFlags |= CHN_TREMOLO;
01607 }
01608
01609
01610 void CSoundFile::ChannelVolSlide(MODCHANNEL *pChn, UINT param)
01611
01612 {
01613 LONG nChnSlide = 0;
01614 if (param) pChn->nOldChnVolSlide = param; else param = pChn->nOldChnVolSlide;
01615 if (((param & 0x0F) == 0x0F) && (param & 0xF0))
01616 {
01617 if (m_dwSongFlags & SONG_FIRSTTICK) nChnSlide = param >> 4;
01618 } else
01619 if (((param & 0xF0) == 0xF0) && (param & 0x0F))
01620 {
01621 if (m_dwSongFlags & SONG_FIRSTTICK) nChnSlide = - (int)(param & 0x0F);
01622 } else
01623 {
01624 if (!(m_dwSongFlags & SONG_FIRSTTICK))
01625 {
01626 if (param & 0x0F) nChnSlide = -(int)(param & 0x0F);
01627 else nChnSlide = (int)((param & 0xF0) >> 4);
01628 }
01629 }
01630 if (nChnSlide)
01631 {
01632 nChnSlide += pChn->nGlobalVol;
01633 if (nChnSlide < 0) nChnSlide = 0;
01634 if (nChnSlide > 64) nChnSlide = 64;
01635 pChn->nGlobalVol = nChnSlide;
01636 }
01637 }
01638
01639
01640 void CSoundFile::ExtendedMODCommands(UINT nChn, UINT param)
01641
01642 {
01643 MODCHANNEL *pChn = &Chn[nChn];
01644 UINT command = param & 0xF0;
01645 param &= 0x0F;
01646 switch(command)
01647 {
01648
01649
01650 case 0x10: if ((param) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) FinePortamentoUp(pChn, param); break;
01651
01652 case 0x20: if ((param) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) FinePortamentoDown(pChn, param); break;
01653
01654 case 0x30: pChn->dwFlags &= ~CHN_GLISSANDO; if (param) pChn->dwFlags |= CHN_GLISSANDO; break;
01655
01656 case 0x40: pChn->nVibratoType = param & 0x07; break;
01657
01658 case 0x50: if (m_nTickCount) break;
01659 pChn->nC4Speed = S3MFineTuneTable[param];
01660 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
01661 pChn->nFineTune = param*2;
01662 else
01663 pChn->nFineTune = MOD2XMFineTune(param);
01664 if (pChn->nPeriod) pChn->nPeriod = GetPeriodFromNote(pChn->nNote, pChn->nFineTune, pChn->nC4Speed);
01665 break;
01666
01667
01668 case 0x70: pChn->nTremoloType = param & 0x07; break;
01669
01670 case 0x80: if (!m_nTickCount) { pChn->nPan = (param << 4) + 8; pChn->dwFlags |= CHN_FASTVOLRAMP; } break;
01671
01672 case 0x90: RetrigNote(nChn, param); break;
01673
01674 case 0xA0: if ((param) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) FineVolumeUp(pChn, param); break;
01675
01676 case 0xB0: if ((param) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) FineVolumeDown(pChn, param); break;
01677
01678 case 0xC0: NoteCut(nChn, param); break;
01679
01680
01681
01682 case 0xF0: pChn->nActiveMacro = param; break;
01683 }
01684 }
01685
01686
01687 void CSoundFile::ExtendedS3MCommands(UINT nChn, UINT param)
01688
01689 {
01690 MODCHANNEL *pChn = &Chn[nChn];
01691 UINT command = param & 0xF0;
01692 param &= 0x0F;
01693 switch(command)
01694 {
01695
01696
01697 case 0x10: pChn->dwFlags &= ~CHN_GLISSANDO; if (param) pChn->dwFlags |= CHN_GLISSANDO; break;
01698
01699 case 0x20: if (m_nTickCount) break;
01700 pChn->nC4Speed = S3MFineTuneTable[param & 0x0F];
01701 pChn->nFineTune = MOD2XMFineTune(param);
01702 if (pChn->nPeriod) pChn->nPeriod = GetPeriodFromNote(pChn->nNote, pChn->nFineTune, pChn->nC4Speed);
01703 break;
01704
01705 case 0x30: pChn->nVibratoType = param & 0x07; break;
01706
01707 case 0x40: pChn->nTremoloType = param & 0x07; break;
01708
01709 case 0x50: pChn->nPanbrelloType = param & 0x07; break;
01710
01711 case 0x60: m_nFrameDelay = param; break;
01712
01713 case 0x70: if (m_nTickCount) break;
01714 switch(param)
01715 {
01716 case 0:
01717 case 1:
01718 case 2:
01719 {
01720 MODCHANNEL *bkp = &Chn[m_nChannels];
01721 for (UINT i=m_nChannels; i<MAX_CHANNELS; i++, bkp++)
01722 {
01723 if (bkp->nMasterChn == nChn+1)
01724 {
01725 if (param == 1) KeyOff(i); else
01726 if (param == 2) bkp->dwFlags |= CHN_NOTEFADE; else
01727 { bkp->dwFlags |= CHN_NOTEFADE; bkp->nFadeOutVol = 0; }
01728 }
01729 }
01730 }
01731 break;
01732 case 3: pChn->nNNA = NNA_NOTECUT; break;
01733 case 4: pChn->nNNA = NNA_CONTINUE; break;
01734 case 5: pChn->nNNA = NNA_NOTEOFF; break;
01735 case 6: pChn->nNNA = NNA_NOTEFADE; break;
01736 case 7: pChn->dwFlags &= ~CHN_VOLENV; break;
01737 case 8: pChn->dwFlags |= CHN_VOLENV; break;
01738 case 9: pChn->dwFlags &= ~CHN_PANENV; break;
01739 case 10: pChn->dwFlags |= CHN_PANENV; break;
01740 case 11: pChn->dwFlags &= ~CHN_PITCHENV; break;
01741 case 12: pChn->dwFlags |= CHN_PITCHENV; break;
01742 }
01743 break;
01744
01745 case 0x80: if (!m_nTickCount) { pChn->nPan = (param << 4) + 8; pChn->dwFlags |= CHN_FASTVOLRAMP; } break;
01746
01747 case 0x90: ExtendedChannelEffect(pChn, param & 0x0F); break;
01748
01749 case 0xA0: if (!m_nTickCount)
01750 {
01751 pChn->nOldHiOffset = param;
01752 if ((pChn->nRowNote) && (pChn->nRowNote < 0x80))
01753 {
01754 DWORD pos = param << 16;
01755 if (pos < pChn->nLength) pChn->nPos = pos;
01756 }
01757 }
01758 break;
01759
01760
01761 case 0xC0: NoteCut(nChn, param); break;
01762
01763
01764
01765
01766 case 0xF0: pChn->nActiveMacro = param; break;
01767 }
01768 }
01769
01770
01771 void CSoundFile::ExtendedChannelEffect(MODCHANNEL *pChn, UINT param)
01772
01773 {
01774
01775 if (m_nTickCount) return;
01776 switch(param & 0x0F)
01777 {
01778
01779 case 0x00: pChn->dwFlags &= ~CHN_SURROUND; break;
01780
01781 case 0x01: pChn->dwFlags |= CHN_SURROUND; pChn->nPan = 128; break;
01783
01784
01785 case 0x08:
01786 pChn->dwFlags &= ~CHN_REVERB;
01787 pChn->dwFlags |= CHN_NOREVERB;
01788 break;
01789
01790 case 0x09:
01791 pChn->dwFlags &= ~CHN_NOREVERB;
01792 pChn->dwFlags |= CHN_REVERB;
01793 break;
01794
01795 case 0x0A:
01796 m_dwSongFlags &= ~SONG_SURROUNDPAN;
01797 break;
01798
01799 case 0x0B:
01800 m_dwSongFlags |= SONG_SURROUNDPAN;
01801 break;
01802
01803 case 0x0C:
01804 m_dwSongFlags &= ~SONG_MPTFILTERMODE;
01805 break;
01806
01807 case 0x0D:
01808 m_dwSongFlags |= SONG_MPTFILTERMODE;
01809 break;
01810
01811 case 0x0E:
01812 pChn->dwFlags &= ~(CHN_PINGPONGFLAG);
01813 break;
01814
01815 case 0x0F:
01816 if ((!(pChn->dwFlags & CHN_LOOP)) && (!pChn->nPos) && (pChn->nLength))
01817 {
01818 pChn->nPos = pChn->nLength - 1;
01819 pChn->nPosLo = 0xFFFF;
01820 }
01821 pChn->dwFlags |= CHN_PINGPONGFLAG;
01822 break;
01823 }
01824 }
01825
01826
01827 void CSoundFile::ProcessMidiMacro(UINT nChn, LPCSTR pszMidiMacro, UINT param)
01828
01829 {
01830 MODCHANNEL *pChn = &Chn[nChn];
01831 DWORD dwMacro = (*((LPDWORD)pszMidiMacro)) & 0x7F5F7F5F;
01832
01833 if (dwMacro != 0x30463046)
01834 {
01835 UINT pos = 0, nNib = 0, nBytes = 0;
01836 DWORD dwMidiCode = 0, dwByteCode = 0;
01837 while (pos+6 <= 32)
01838 {
01839 CHAR cData = pszMidiMacro[pos++];
01840 if (!cData) break;
01841 if ((cData >= '0') && (cData <= '9')) { dwByteCode = (dwByteCode<<4) | (cData-'0'); nNib++; } else
01842 if ((cData >= 'A') && (cData <= 'F')) { dwByteCode = (dwByteCode<<4) | (cData-'A'+10); nNib++; } else
01843 if ((cData >= 'a') && (cData <= 'f')) { dwByteCode = (dwByteCode<<4) | (cData-'a'+10); nNib++; } else
01844 if ((cData == 'z') || (cData == 'Z')) { dwByteCode = param & 0x7f; nNib = 2; } else
01845 if ((cData == 'x') || (cData == 'X')) { dwByteCode = param & 0x70; nNib = 2; } else
01846 if ((cData == 'y') || (cData == 'Y')) { dwByteCode = (param & 0x0f)<<3; nNib = 2; } else
01847 if (nNib >= 2)
01848 {
01849 nNib = 0;
01850 dwMidiCode |= dwByteCode << (nBytes*8);
01851 dwByteCode = 0;
01852 nBytes++;
01853 if (nBytes >= 3)
01854 {
01855 UINT nMasterCh = (nChn < m_nChannels) ? nChn+1 : pChn->nMasterChn;
01856 if ((nMasterCh) && (nMasterCh <= m_nChannels))
01857 {
01858 UINT nPlug = ChnSettings[nMasterCh-1].nMixPlugin;
01859 if ((nPlug) && (nPlug <= MAX_MIXPLUGINS))
01860 {
01861 IMixPlugin *pPlugin = m_MixPlugins[nPlug-1].pMixPlugin;
01862 if ((pPlugin) && (m_MixPlugins[nPlug-1].pMixState))
01863 {
01864 pPlugin->MidiSend(dwMidiCode);
01865 }
01866 }
01867 }
01868 nBytes = 0;
01869 dwMidiCode = 0;
01870 }
01871 }
01872
01873 }
01874 return;
01875 }
01876
01877 pszMidiMacro += 4;
01878
01879 if (pszMidiMacro[0] == '0')
01880 {
01881 CHAR cData1 = pszMidiMacro[2];
01882 DWORD dwParam = 0;
01883 if ((cData1 == 'z') || (cData1 == 'Z'))
01884 {
01885 dwParam = param;
01886 } else
01887 {
01888 CHAR cData2 = pszMidiMacro[3];
01889 if ((cData1 >= '0') && (cData1 <= '9')) dwParam += (cData1 - '0') << 4; else
01890 if ((cData1 >= 'A') && (cData1 <= 'F')) dwParam += (cData1 - 'A' + 0x0A) << 4;
01891 if ((cData2 >= '0') && (cData2 <= '9')) dwParam += (cData2 - '0'); else
01892 if ((cData2 >= 'A') && (cData2 <= 'F')) dwParam += (cData2 - 'A' + 0x0A);
01893 }
01894 switch(pszMidiMacro[1])
01895 {
01896
01897 case '0':
01898 {
01899 int oldcutoff = pChn->nCutOff;
01900 if (dwParam < 0x80) pChn->nCutOff = dwParam;
01901 #ifndef NO_FILTER
01902 oldcutoff -= pChn->nCutOff;
01903
01904 if (oldcutoff < 0) oldcutoff = -oldcutoff;
01905 if ((pChn->nVolume > 0) || (oldcutoff < 0x10)
01906 || (!(pChn->dwFlags & CHN_FILTER)) || (!(pChn->nLeftVol|pChn->nRightVol)))
01907 SetupChannelFilter(pChn, (pChn->dwFlags & CHN_FILTER) ? FALSE : TRUE);
01908 #endif
01909 }
01910 break;
01911
01912
01913 case '1':
01914 if (dwParam < 0x80) pChn->nResonance = dwParam;
01915 #ifndef NO_FILTER
01916 SetupChannelFilter(pChn, (pChn->dwFlags & CHN_FILTER) ? FALSE : TRUE);
01917 #endif
01918
01919 break;
01920 }
01921
01922 }
01923 }
01924
01925
01926 void CSoundFile::RetrigNote(UINT nChn, UINT param)
01927
01928 {
01929
01930 MODCHANNEL *pChn = &Chn[nChn];
01931 UINT nRetrigSpeed = param & 0x0F;
01932 UINT nRetrigCount = pChn->nRetrigCount;
01933 BOOL bDoRetrig = FALSE;
01934
01935 if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))
01936 {
01937 if (!nRetrigSpeed) nRetrigSpeed = 1;
01938 if ((nRetrigCount) && (!(nRetrigCount % nRetrigSpeed))) bDoRetrig = TRUE;
01939 nRetrigCount++;
01940 } else
01941 {
01942 UINT realspeed = nRetrigSpeed;
01943 if ((param & 0x100) && (pChn->nRowVolCmd == VOLCMD_VOLUME) && (pChn->nRowParam & 0xF0)) realspeed++;
01944 if ((m_nTickCount) || (param & 0x100))
01945 {
01946 if (!realspeed) realspeed = 1;
01947 if ((!(param & 0x100)) && (m_nMusicSpeed) && (!(m_nTickCount % realspeed))) bDoRetrig = TRUE;
01948 nRetrigCount++;
01949 } else if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) nRetrigCount = 0;
01950 if (nRetrigCount >= realspeed)
01951 {
01952 if ((m_nTickCount) || ((param & 0x100) && (!pChn->nRowNote))) bDoRetrig = TRUE;
01953 }
01954 }
01955 if (bDoRetrig)
01956 {
01957 UINT dv = (param >> 4) & 0x0F;
01958 if (dv)
01959 {
01960 int vol = pChn->nVolume;
01961 if (retrigTable1[dv])
01962 vol = (vol * retrigTable1[dv]) >> 4;
01963 else
01964 vol += ((int)retrigTable2[dv]) << 2;
01965 if (vol < 0) vol = 0;
01966 if (vol > 256) vol = 256;
01967 pChn->nVolume = vol;
01968 pChn->dwFlags |= CHN_FASTVOLRAMP;
01969 }
01970 UINT nNote = pChn->nNewNote;
01971 LONG nOldPeriod = pChn->nPeriod;
01972 if ((nNote) && (nNote <= 120) && (pChn->nLength)) CheckNNA(nChn, 0, nNote, TRUE);
01973 BOOL bResetEnv = FALSE;
01974 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
01975 {
01976 if ((pChn->nRowInstr) && (param < 0x100)) { InstrumentChange(pChn, pChn->nRowInstr, FALSE, FALSE); bResetEnv = TRUE; }
01977 if (param < 0x100) bResetEnv = TRUE;
01978 }
01979 NoteChange(nChn, nNote, FALSE, bResetEnv);
01980 if ((m_nType & MOD_TYPE_IT) && (!pChn->nRowNote) && (nOldPeriod)) pChn->nPeriod = nOldPeriod;
01981 if (!(m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))) nRetrigCount = 0;
01982 }
01983 pChn->nRetrigCount = (BYTE)nRetrigCount;
01984 }
01985
01986
01987 void CSoundFile::DoFreqSlide(MODCHANNEL *pChn, LONG nFreqSlide)
01988
01989 {
01990
01991 if (!pChn->nPeriod) return;
01992 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))))
01993 {
01994 if (nFreqSlide < 0)
01995 {
01996 UINT n = (- nFreqSlide) >> 2;
01997 if (n > 255) n = 255;
01998 pChn->nPeriod = _muldivr(pChn->nPeriod, LinearSlideDownTable[n], 65536);
01999 } else
02000 {
02001 UINT n = (nFreqSlide) >> 2;
02002
02003 if (n > 255) n = 255;
02004 pChn->nPeriod = _muldivr(pChn->nPeriod, LinearSlideUpTable[n], 65536);
02005 }
02006 } else
02007 {
02008 pChn->nPeriod += nFreqSlide;
02009 }
02010 if (pChn->nPeriod < 1)
02011 {
02012 pChn->nPeriod = 1;
02013 if (m_nType & MOD_TYPE_IT)
02014 {
02015 pChn->dwFlags |= CHN_NOTEFADE;
02016 pChn->nFadeOutVol = 0;
02017 }
02018 }
02019 }
02020
02021
02022 void CSoundFile::NoteCut(UINT nChn, UINT nTick)
02023
02024 {
02025 if (m_nTickCount == nTick)
02026 {
02027 MODCHANNEL *pChn = &Chn[nChn];
02028
02029 pChn->nVolume = 0;
02030 pChn->dwFlags |= CHN_FASTVOLRAMP;
02031 }
02032 }
02033
02034
02035 void CSoundFile::KeyOff(UINT nChn)
02036
02037 {
02038 MODCHANNEL *pChn = &Chn[nChn];
02039 BOOL bKeyOn = (pChn->dwFlags & CHN_KEYOFF) ? FALSE : TRUE;
02040 pChn->dwFlags |= CHN_KEYOFF;
02041
02042 if ((pChn->pHeader) && (!(pChn->dwFlags & CHN_VOLENV)))
02043 {
02044 pChn->dwFlags |= CHN_NOTEFADE;
02045 }
02046 if (!pChn->nLength) return;
02047 if ((pChn->dwFlags & CHN_SUSTAINLOOP) && (pChn->pInstrument) && (bKeyOn))
02048 {
02049 MODINSTRUMENT *psmp = pChn->pInstrument;
02050 if (psmp->uFlags & CHN_LOOP)
02051 {
02052 if (psmp->uFlags & CHN_PINGPONGLOOP)
02053 pChn->dwFlags |= CHN_PINGPONGLOOP;
02054 else
02055 pChn->dwFlags &= ~(CHN_PINGPONGLOOP|CHN_PINGPONGFLAG);
02056 pChn->dwFlags |= CHN_LOOP;
02057 pChn->nLength = psmp->nLength;
02058 pChn->nLoopStart = psmp->nLoopStart;
02059 pChn->nLoopEnd = psmp->nLoopEnd;
02060 if (pChn->nLength > pChn->nLoopEnd) pChn->nLength = pChn->nLoopEnd;
02061 } else
02062 {
02063 pChn->dwFlags &= ~(CHN_LOOP|CHN_PINGPONGLOOP|CHN_PINGPONGFLAG);
02064 pChn->nLength = psmp->nLength;
02065 }
02066 }
02067 if (pChn->pHeader)
02068 {
02069 INSTRUMENTHEADER *penv = pChn->pHeader;
02070 if (((penv->dwFlags & ENV_VOLLOOP) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) && (penv->nFadeOut))
02071 pChn->dwFlags |= CHN_NOTEFADE;
02072 }
02073 }
02074
02075
02077
02078
02079
02080 void CSoundFile::SetSpeed(UINT param)
02081
02082 {
02083 UINT max = (m_nType == MOD_TYPE_IT) ? 256 : 128;
02084
02085 #ifndef MODPLUG_TRACKER
02086 #ifndef FASTSOUNDLIB
02087
02088 if ((!param) || (param >= 0x80) || ((m_nType & (MOD_TYPE_MOD|MOD_TYPE_XM|MOD_TYPE_MT2)) && (param >= 0x1E)))
02089 {
02090 if (IsSongFinished(m_nCurrentPattern, m_nRow+1))
02091 {
02092 GlobalFadeSong(1000);
02093 }
02094 }
02095 #endif // FASTSOUNDLIB
02096 #endif // MODPLUG_TRACKER
02097 if ((m_nType & MOD_TYPE_S3M) && (param > 0x80)) param -= 0x80;
02098 if ((param) && (param <= max)) m_nMusicSpeed = param;
02099 }
02100
02101
02102 void CSoundFile::SetTempo(UINT param)
02103
02104 {
02105 if (param < 0x20)
02106 {
02107
02108 if ((param & 0xF0) == 0x10)
02109 {
02110 m_nMusicTempo += (param & 0x0F) * 2;
02111 if (m_nMusicTempo > 255) m_nMusicTempo = 255;
02112 } else
02113 {
02114 m_nMusicTempo -= (param & 0x0F) * 2;
02115 if ((LONG)m_nMusicTempo < 32) m_nMusicTempo = 32;
02116 }
02117 } else
02118 {
02119 m_nMusicTempo = param;
02120 }
02121 }
02122
02123
02124 int CSoundFile::PatternLoop(MODCHANNEL *pChn, UINT param)
02125
02126 {
02127 if (param)
02128 {
02129 if (pChn->nPatternLoopCount)
02130 {
02131 pChn->nPatternLoopCount--;
02132 if (!pChn->nPatternLoopCount) return -1;
02133 } else
02134 {
02135 MODCHANNEL *p = Chn;
02136 for (UINT i=0; i<m_nChannels; i++, p++) if (p != pChn)
02137 {
02138
02139 if (p->nPatternLoopCount) return -1;
02140 }
02141 pChn->nPatternLoopCount = param;
02142 }
02143 return pChn->nPatternLoop;
02144 } else
02145 {
02146 pChn->nPatternLoop = m_nRow;
02147 }
02148 return -1;
02149 }
02150
02151
02152 void CSoundFile::GlobalVolSlide(UINT param)
02153
02154 {
02155 LONG nGlbSlide = 0;
02156 if (param) m_nOldGlbVolSlide = param; else param = m_nOldGlbVolSlide;
02157 if (((param & 0x0F) == 0x0F) && (param & 0xF0))
02158 {
02159 if (m_dwSongFlags & SONG_FIRSTTICK) nGlbSlide = (param >> 4) * 2;
02160 } else
02161 if (((param & 0xF0) == 0xF0) && (param & 0x0F))
02162 {
02163 if (m_dwSongFlags & SONG_FIRSTTICK) nGlbSlide = - (int)((param & 0x0F) * 2);
02164 } else
02165 {
02166 if (!(m_dwSongFlags & SONG_FIRSTTICK))
02167 {
02168 if (param & 0xF0) nGlbSlide = (int)((param & 0xF0) >> 4) * 2;
02169 else nGlbSlide = -(int)((param & 0x0F) * 2);
02170 }
02171 }
02172 if (nGlbSlide)
02173 {
02174 if (m_nType != MOD_TYPE_IT) nGlbSlide *= 2;
02175 nGlbSlide += m_nGlobalVolume;
02176 if (nGlbSlide < 0) nGlbSlide = 0;
02177 if (nGlbSlide > 256) nGlbSlide = 256;
02178 m_nGlobalVolume = nGlbSlide;
02179 }
02180 }
02181
02182
02183 DWORD CSoundFile::IsSongFinished(UINT nStartOrder, UINT nStartRow) const
02184
02185 {
02186 UINT nOrd;
02187
02188 for (nOrd=nStartOrder; nOrd<MAX_ORDERS; nOrd++)
02189 {
02190 UINT nPat = Order[nOrd];
02191 if (nPat != 0xFE)
02192 {
02193 MODCOMMAND *p;
02194
02195 if (nPat >= MAX_PATTERNS) break;
02196 p = Patterns[nPat];
02197 if (p)
02198 {
02199 UINT len = PatternSize[nPat] * m_nChannels;
02200 UINT pos = (nOrd == nStartOrder) ? nStartRow : 0;
02201 pos *= m_nChannels;
02202 while (pos < len)
02203 {
02204 UINT cmd;
02205 if ((p[pos].note) || (p[pos].volcmd)) return 0;
02206 cmd = p[pos].command;
02207 if (cmd == CMD_MODCMDEX)
02208 {
02209 UINT cmdex = p[pos].param & 0xF0;
02210 if ((!cmdex) || (cmdex == 0x60) || (cmdex == 0xE0) || (cmdex == 0xF0)) cmd = 0;
02211 }
02212 if ((cmd) && (cmd != CMD_SPEED) && (cmd != CMD_TEMPO)) return 0;
02213 pos++;
02214 }
02215 }
02216 }
02217 }
02218 return (nOrd < MAX_ORDERS) ? nOrd : MAX_ORDERS-1;
02219 }
02220
02221
02222 BOOL CSoundFile::IsValidBackwardJump(UINT nStartOrder, UINT nStartRow, UINT nJumpOrder, UINT nJumpRow) const
02223
02224 {
02225 while ((nJumpOrder < MAX_PATTERNS) && (Order[nJumpOrder] == 0xFE)) nJumpOrder++;
02226 if ((nStartOrder >= MAX_PATTERNS) || (nJumpOrder >= MAX_PATTERNS)) return FALSE;
02227
02228 if (nJumpOrder > nStartOrder) return TRUE;
02229 if ((nJumpOrder < nStartOrder) || (nJumpRow >= PatternSize[nStartOrder])
02230 || (!Patterns[nStartOrder]) || (nStartRow >= 256) || (nJumpRow >= 256)) return FALSE;
02231
02232 BYTE row_hist[256];
02233 memset(row_hist, 0, sizeof(row_hist));
02234 UINT nRows = PatternSize[nStartOrder], row = nJumpRow;
02235 if (nRows > 256) nRows = 256;
02236 row_hist[nStartRow] = TRUE;
02237 while ((row < 256) && (!row_hist[row]))
02238 {
02239 if (row >= nRows) return TRUE;
02240 row_hist[row] = TRUE;
02241 MODCOMMAND *p = Patterns[nStartOrder] + row * m_nChannels;
02242 row++;
02243 int breakrow = -1, posjump = 0;
02244 for (UINT i=0; i<m_nChannels; i++, p++)
02245 {
02246 if (p->command == CMD_POSITIONJUMP)
02247 {
02248 if (p->param < nStartOrder) return FALSE;
02249 if (p->param > nStartOrder) return TRUE;
02250 posjump = TRUE;
02251 } else
02252 if (p->command == CMD_PATTERNBREAK)
02253 {
02254 breakrow = p->param;
02255 }
02256 }
02257 if (breakrow >= 0)
02258 {
02259 if (!posjump) return TRUE;
02260 row = breakrow;
02261 }
02262 if (row >= nRows) return TRUE;
02263 }
02264 return FALSE;
02265 }
02266
02267
02269
02270
02271 UINT CSoundFile::GetNoteFromPeriod(UINT period) const
02272
02273 {
02274 if (!period) return 0;
02275 if (m_nType & (MOD_TYPE_MED|MOD_TYPE_MOD|MOD_TYPE_MTM|MOD_TYPE_669|MOD_TYPE_OKT|MOD_TYPE_AMF0))
02276 {
02277 period >>= 2;
02278 for (UINT i=0; i<6*12; i++)
02279 {
02280 if (period >= ProTrackerPeriodTable[i])
02281 {
02282 if ((period != ProTrackerPeriodTable[i]) && (i))
02283 {
02284 UINT p1 = ProTrackerPeriodTable[i-1];
02285 UINT p2 = ProTrackerPeriodTable[i];
02286 if (p1 - period < (period - p2)) return i+36;
02287 }
02288 return i+1+36;
02289 }
02290 }
02291 return 6*12+36;
02292 } else
02293 {
02294 for (UINT i=1; i<120; i++)
02295 {
02296 LONG n = GetPeriodFromNote(i, 0, 0);
02297 if ((n > 0) && (n <= (LONG)period)) return i;
02298 }
02299 return 120;
02300 }
02301 }
02302
02303
02304
02305 UINT CSoundFile::GetPeriodFromNote(UINT note, int nFineTune, UINT nC4Speed) const
02306
02307 {
02308 if ((!note) || (note > 0xF0)) return 0;
02309 if (m_nType & (MOD_TYPE_IT|MOD_TYPE_S3M|MOD_TYPE_STM|MOD_TYPE_MDL|MOD_TYPE_ULT|MOD_TYPE_WAV
02310 |MOD_TYPE_FAR|MOD_TYPE_DMF|MOD_TYPE_PTM|MOD_TYPE_AMS|MOD_TYPE_DBM|MOD_TYPE_AMF|MOD_TYPE_PSM))
02311 {
02312 note--;
02313 if (m_dwSongFlags & SONG_LINEARSLIDES)
02314 {
02315 return (FreqS3MTable[note % 12] << 5) >> (note / 12);
02316 } else
02317 {
02318 if (!nC4Speed) nC4Speed = 8363;
02319 return _muldiv(8363, (FreqS3MTable[note % 12] << 5), nC4Speed << (note / 12));
02320 }
02321 } else
02322 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
02323 {
02324 if (note < 13) note = 13;
02325 note -= 13;
02326 if (m_dwSongFlags & SONG_LINEARSLIDES)
02327 {
02328 LONG l = ((120 - note) << 6) - (nFineTune / 2);
02329 if (l < 1) l = 1;
02330 return (UINT)l;
02331 } else
02332 {
02333 int finetune = nFineTune;
02334 UINT rnote = (note % 12) << 3;
02335 UINT roct = note / 12;
02336 int rfine = finetune / 16;
02337 int i = rnote + rfine + 8;
02338 if (i < 0) i = 0;
02339 if (i >= 104) i = 103;
02340 UINT per1 = XMPeriodTable[i];
02341 if ( finetune < 0 )
02342 {
02343 rfine--;
02344 finetune = -finetune;
02345 } else rfine++;
02346 i = rnote+rfine+8;
02347 if (i < 0) i = 0;
02348 if (i >= 104) i = 103;
02349 UINT per2 = XMPeriodTable[i];
02350 rfine = finetune & 0x0F;
02351 per1 *= 16-rfine;
02352 per2 *= rfine;
02353 return ((per1 + per2) << 1) >> roct;
02354 }
02355 } else
02356 {
02357 note--;
02358 nFineTune = XM2MODFineTune(nFineTune);
02359 if ((nFineTune) || (note < 36) || (note >= 36+6*12))
02360 return (ProTrackerTunedPeriods[nFineTune*12 + note % 12] << 5) >> (note / 12);
02361 else
02362 return (ProTrackerPeriodTable[note-36] << 2);
02363 }
02364 }
02365
02366
02367 UINT CSoundFile::GetFreqFromPeriod(UINT period, UINT nC4Speed, int nPeriodFrac) const
02368
02369 {
02370 if (!period) return 0;
02371 if (m_nType & (MOD_TYPE_MED|MOD_TYPE_MOD|MOD_TYPE_MTM|MOD_TYPE_669|MOD_TYPE_OKT|MOD_TYPE_AMF0))
02372 {
02373 return (3546895L*4) / period;
02374 } else
02375 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
02376 {
02377 if (m_dwSongFlags & SONG_LINEARSLIDES)
02378 return XMLinearTable[period % 768] >> (period / 768);
02379 else
02380 return 8363 * 1712L / period;
02381 } else
02382 {
02383 if (m_dwSongFlags & SONG_LINEARSLIDES)
02384 {
02385 if (!nC4Speed) nC4Speed = 8363;
02386 return _muldiv(nC4Speed, 1712L << 8, (period << 8)+nPeriodFrac);
02387 } else
02388 {
02389 return _muldiv(8363, 1712L << 8, (period << 8)+nPeriodFrac);
02390 }
02391 }
02392 }
02393
02394