Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

snd_fx.cpp

Go to the documentation of this file.
00001 /*
00002  * This program is  free software; you can redistribute it  and modify it
00003  * under the terms of the GNU  General Public License as published by the
00004  * Free Software Foundation; either version 2  of the license or (at your
00005  * option) any later version.
00006  *
00007  * Authors: Olivier Lapicque <olivierl@jps.net>
00008 */
00009 
00010 #include "stdafx.h"
00011 #include "sndfile.h"
00012 
00013 #ifdef WIN32
00014 #pragma warning(disable:4244)
00015 #endif
00016 
00017 // Tables defined in tables.cpp
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 // Length
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                 // Check if pattern is valid
00071                 nPattern = Order[nCurrentPattern];
00072                 while (nPattern >= MAX_PATTERNS)
00073                 {
00074                         // End of song ?
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                 // Weird stuff?
00086                 if ((nPattern >= MAX_PATTERNS) || (!Patterns[nPattern])) break;
00087                 // Should never happen
00088                 if (nRow >= PatternSize[nPattern]) nRow = 0;
00089                 // Update next position
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                         // Position Jump
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                         // Pattern Break
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                         // Set Speed
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                         // Set Tempo
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                                 // Tempo Slide
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                         // Pattern Delay
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                         // Portamento Up/Down
00188                         case CMD_PORTAMENTOUP:
00189                         case CMD_PORTAMENTODOWN:
00190                                 if (param) pChn->nOldPortaUpDown = param;
00191                                 break;
00192                         // Tone-Portamento
00193                         case CMD_TONEPORTAMENTO:
00194                                 if (param) pChn->nPortamentoSlide = param << 2;
00195                                 break;
00196                         // Offset
00197                         case CMD_OFFSET:
00198                                 if (param) pChn->nOldOffset = param;
00199                                 break;
00200                         // Volume Slide
00201                         case CMD_VOLUMESLIDE:
00202                         case CMD_TONEPORTAVOL:
00203                         case CMD_VIBRATOVOL:
00204                                 if (param) pChn->nOldVolumeSlide = param;
00205                                 break;
00206                         // Set Volume
00207                         case CMD_VOLUME:
00208                                 vols[nChn] = param;
00209                                 break;
00210                         // Global Volume
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                         // Global Volume Slide
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 // Effects
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         // Update Volume
00319         if (bUpdVol) pChn->nVolume = (psmp) ? psmp->nVolume : 0;
00320         // bInstrumentChanged is used for IT carry-on env option
00321         if (penv != pChn->pHeader)
00322         {
00323                 bInstrumentChanged = TRUE;
00324                 pChn->pHeader = penv;
00325         } else
00326         // Special XM hack
00327         if ((bPorta) && (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) && (penv)
00328          && (pChn->pInstrument) && (psmp != pChn->pInstrument))
00329         {
00330                 // FT2 doesn't change the sample in this case,
00331                 // but still uses the sample info from the old one (bug?)
00332                 return;
00333         }
00334         // Instrument adjust
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         // Reset envelopes
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         // Invalid sample ?
00378         if (!psmp)
00379         {
00380                 pChn->pInstrument = NULL;
00381                 pChn->nInsVol = 0;
00382                 return;
00383         }
00384         // Tone-Portamento doesn't reset the pingpong direction flag
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         // Key Off
00441         if (note >= 0x80)       // 0xFE or invalid note => key off
00442         {
00443                 // Key Off
00444                 KeyOff(nChn);
00445                 // Note Cut
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         // Enable Ramping
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                                         // Volume Swing
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                                         // Pan Swing
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                 // Setup Initial Filter for this note
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         // Check for empty channel
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         // All channels are used: check for lowest volume
00587         UINT result = 0;
00588         DWORD vol = 64*65536;   // 25%
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         // Always NNA cut - using
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                 // Copy Channel
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                 // Cut the note
00634                 p->nFadeOutVol = 0;
00635                 p->dwFlags |= (CHN_NOTEFADE|CHN_FASTVOLRAMP);
00636                 // Stop this channel
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                         // Duplicate Check Type
00668                         switch(p->pHeader->nDCT)
00669                         {
00670                         // Note
00671                         case DCT_NOTE:
00672                                 if ((note) && (p->nNote == note) && (pHeader == p->pHeader)) bOk = TRUE;
00673                                 break;
00674                         // Sample
00675                         case DCT_SAMPLE:
00676                                 if ((pSample) && (pSample == p->pSample)) bOk = TRUE;
00677                                 break;
00678                         // Instrument
00679                         case DCT_INSTRUMENT:
00680                                 if (pHeader == p->pHeader) bOk = TRUE;
00681                                 break;
00682                         }
00683                         // Duplicate Note Action
00684                         if (bOk)
00685                         {
00686                                 switch(p->pHeader->nDNA)
00687                                 {
00688                                 // Cut
00689                                 case DNA_NOTECUT:
00690                                         KeyOff(i);
00691                                         p->nVolume = 0;
00692                                         break;
00693                                 // Note Off
00694                                 case DNA_NOTEOFF:
00695                                         KeyOff(i);
00696                                         break;
00697                                 // Note Fade
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         // New Note Action
00712         if ((pChn->nVolume) && (pChn->nLength))
00713         {
00714                 UINT n = GetNNAChannel(nChn);
00715                 if (n)
00716                 {
00717                         MODCHANNEL *p = &Chn[n];
00718                         // Copy Channel
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                         // Key Off the note
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                         // Stop this channel
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                 // Process special effects (note delay, pattern delay, pattern loop)
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                         // Note Delay ?
00765                         if ((param & 0xF0) == 0xD0)
00766                         {
00767                                 nStartTick = param & 0x0F;
00768                         } else
00769                         if (!m_nTickCount)
00770                         {
00771                                 // Pattern Loop ?
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                                 // Pattern Delay
00779                                 if ((param & 0xF0) == 0xE0)
00780                                 {
00781                                         m_nPatternDelay = param & 0x0F;
00782                                 }
00783                         }
00784                 }
00785                 
00786                 // Handles note/instrument/volume changes
00787                 if (m_nTickCount == nStartTick) // can be delayed by a note delay effect
00788                 {
00789                         UINT note = pChn->nRowNote;
00790                         if (instr) pChn->nNewIns = instr;
00791                         // XM: Key-Off + Sample == Note Cut
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                         // Invalid Instrument ?
00824                         if (instr >= MAX_INSTRUMENTS) instr = 0;
00825                         // Note Cut/Off => ignore instrument
00826                         if (note >= 0xFE) instr = 0;
00827                         if ((note) && (note <= 128)) pChn->nNewNote = note;
00828                         // New Note Action ?
00829                         if ((note) && (note <= 128) && (!bPorta))
00830                         {
00831                                 CheckNNA(nChn, instr, note, FALSE);
00832                         }
00833                         // Instrument Change ?
00834                         if (instr)
00835                         {
00836                                 MODINSTRUMENT *psmp = pChn->pInstrument;
00837                                 InstrumentChange(pChn, instr, bPorta, TRUE);
00838                                 pChn->nNewIns = 0;
00839                                 // Special IT case: portamento+note causes sample change -> ignore portamento
00840                                 if ((m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))
00841                                  && (psmp != pChn->pInstrument) && (note) && (note < 0x80))
00842                                 {
00843                                         bPorta = FALSE;
00844                                 }
00845                         }
00846                         // New Note ?
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                         // Tick-0 only volume commands
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                 // Volume Column Effect (except volume & panning)
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                 // Effects
00946                 if (cmd) switch (cmd)
00947                 {
00948                 // Set Volume
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                 // Portamento Up
00958                 case CMD_PORTAMENTOUP:
00959                         if ((!param) && (m_nType & MOD_TYPE_MOD)) break;
00960                         PortamentoUp(pChn, param);
00961                         break;
00962 
00963                 // Portamento Down
00964                 case CMD_PORTAMENTODOWN:
00965                         if ((!param) && (m_nType & MOD_TYPE_MOD)) break;
00966                         PortamentoDown(pChn, param);
00967                         break;
00968 
00969                 // Volume Slide
00970                 case CMD_VOLUMESLIDE:
00971                         if ((param) || (m_nType != MOD_TYPE_MOD)) VolumeSlide(pChn, param);
00972                         break;
00973 
00974                 // Tone-Portamento
00975                 case CMD_TONEPORTAMENTO:
00976                         TonePortamento(pChn, param);
00977                         break;
00978 
00979                 // Tone-Portamento + Volume Slide
00980                 case CMD_TONEPORTAVOL:
00981                         if ((param) || (m_nType != MOD_TYPE_MOD)) VolumeSlide(pChn, param);
00982                         TonePortamento(pChn, 0);
00983                         break;
00984 
00985                 // Vibrato
00986                 case CMD_VIBRATO:
00987                         Vibrato(pChn, param);
00988                         break;
00989 
00990                 // Vibrato + Volume Slide
00991                 case CMD_VIBRATOVOL:
00992                         if ((param) || (m_nType != MOD_TYPE_MOD)) VolumeSlide(pChn, param);
00993                         Vibrato(pChn, 0);
00994                         break;
00995 
00996                 // Set Speed
00997                 case CMD_SPEED:
00998                         if (!m_nTickCount) SetSpeed(param);
00999                         break;
01000 
01001                 // Set Tempo
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                 // Set Offset
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                 // Arpeggio
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                 // Retrig
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; // increment retrig count on first row
01058                         }
01059                         if (param) pChn->nRetrigParam = (BYTE)(param & 0xFF); else param = pChn->nRetrigParam;
01060                         RetrigNote(nChn, param);
01061                         break;
01062 
01063                 // Tremor
01064                 case CMD_TREMOR:
01065                         if (m_nTickCount) break;
01066                         pChn->nCommand = CMD_TREMOR;
01067                         if (param) pChn->nTremorParam = param;
01068                         break;
01069 
01070                 // Set Global Volume
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                 // Global Volume Slide
01079                 case CMD_GLOBALVOLSLIDE:
01080                         GlobalVolSlide(param);
01081                         break;
01082 
01083                 // Set 8-bit Panning
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                 // Panning Slide
01104                 case CMD_PANNINGSLIDE:
01105                         PanningSlide(pChn, param);
01106                         break;
01107 
01108                 // Tremolo
01109                 case CMD_TREMOLO:
01110                         Tremolo(pChn, param);
01111                         break;
01112 
01113                 // Fine Vibrato
01114                 case CMD_FINEVIBRATO:
01115                         FineVibrato(pChn, param);
01116                         break;
01117 
01118                 // MOD/XM Exx Extended Commands
01119                 case CMD_MODCMDEX:
01120                         ExtendedMODCommands(nChn, param);
01121                         break;
01122 
01123                 // S3M/IT Sxx Extended Commands
01124                 case CMD_S3MCMDEX:
01125                         ExtendedS3MCommands(nChn, param);
01126                         break;
01127 
01128                 // Key Off
01129                 case CMD_KEYOFF:
01130                         if (!m_nTickCount) KeyOff(nChn);
01131                         break;
01132 
01133                 // Extra-fine porta up/down
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                         // Modplug XM Extensions
01140                         case 0x50: 
01141                         case 0x60: 
01142                         case 0x70:
01143                         case 0x90: 
01144                         case 0xA0: ExtendedS3MCommands(nChn, param); break;
01145                         }
01146                         break;
01147 
01148                 // Set Channel Global Volume
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                 // Channel volume slide
01159                 case CMD_CHANNELVOLSLIDE:
01160                         ChannelVolSlide(pChn, param);
01161                         break;
01162 
01163                 // Panbrello (IT)
01164                 case CMD_PANBRELLO:
01165                         Panbrello(pChn, param);
01166                         break;
01167 
01168                 // Set Envelope Position
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                 // Position Jump
01187                 case CMD_POSITIONJUMP:
01188                         nPosJump = param;
01189                         break;
01190 
01191                 // Pattern Break
01192                 case CMD_PATTERNBREAK:
01193                         nBreakRow = param;
01194                         break;
01195 
01196                 // Midi Controller
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         // Navigation Effects
01211         if (!m_nTickCount)
01212         {
01213                 // Pattern Loop
01214                 if (nPatLoopRow >= 0)
01215                 {
01216                         m_nNextPattern = m_nCurrentPattern;
01217                         m_nNextRow = nPatLoopRow;
01218                         if (m_nPatternDelay) m_nNextRow++;
01219                 } else
01220                 // Pattern Break / Position Jump only if no loop running
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                         // Modplug Tracker & ModPlugin allow backward jumps
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                                                 // Backward jump disabled
01242                                                 bNoLoop = TRUE;
01243                                                 //reset repeat count incase there are multiple loops.
01244                                                 //(i.e. Unreal tracks)
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 // Channels effects
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         // Regular Slide
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 // Portamento Slide
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         // E0x: Set Filter
01649         // E1x: Fine Portamento Up
01650         case 0x10:      if ((param) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) FinePortamentoUp(pChn, param); break;
01651         // E2x: Fine Portamento Down
01652         case 0x20:      if ((param) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) FinePortamentoDown(pChn, param); break;
01653         // E3x: Set Glissando Control
01654         case 0x30:      pChn->dwFlags &= ~CHN_GLISSANDO; if (param) pChn->dwFlags |= CHN_GLISSANDO; break;
01655         // E4x: Set Vibrato WaveForm
01656         case 0x40:      pChn->nVibratoType = param & 0x07; break;
01657         // E5x: Set FineTune
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         // E6x: Pattern Loop
01667         // E7x: Set Tremolo WaveForm
01668         case 0x70:      pChn->nTremoloType = param & 0x07; break;
01669         // E8x: Set 4-bit Panning
01670         case 0x80:      if (!m_nTickCount) { pChn->nPan = (param << 4) + 8; pChn->dwFlags |= CHN_FASTVOLRAMP; } break;
01671         // E9x: Retrig
01672         case 0x90:      RetrigNote(nChn, param); break;
01673         // EAx: Fine Volume Up
01674         case 0xA0:      if ((param) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) FineVolumeUp(pChn, param); break;
01675         // EBx: Fine Volume Down
01676         case 0xB0:      if ((param) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) FineVolumeDown(pChn, param); break;
01677         // ECx: Note Cut
01678         case 0xC0:      NoteCut(nChn, param); break;
01679         // EDx: Note Delay
01680         // EEx: Pattern Delay
01681         // EFx: MOD: Invert Loop, XM: Set Active Midi Macro
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         // S0x: Set Filter
01696         // S1x: Set Glissando Control
01697         case 0x10:      pChn->dwFlags &= ~CHN_GLISSANDO; if (param) pChn->dwFlags |= CHN_GLISSANDO; break;
01698         // S2x: Set FineTune
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         // S3x: Set Vibrato WaveForm
01705         case 0x30:      pChn->nVibratoType = param & 0x07; break;
01706         // S4x: Set Tremolo WaveForm
01707         case 0x40:      pChn->nTremoloType = param & 0x07; break;
01708         // S5x: Set Panbrello WaveForm
01709         case 0x50:      pChn->nPanbrelloType = param & 0x07; break;
01710         // S6x: Pattern Delay for x frames
01711         case 0x60:      m_nFrameDelay = param; break;
01712         // S7x: Envelope Control
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         // S8x: Set 4-bit Panning
01745         case 0x80:      if (!m_nTickCount) { pChn->nPan = (param << 4) + 8; pChn->dwFlags |= CHN_FASTVOLRAMP; } break;
01746         // S9x: Set Surround
01747         case 0x90:      ExtendedChannelEffect(pChn, param & 0x0F); break;
01748         // SAx: Set 64k Offset
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         // SBx: Pattern Loop
01760         // SCx: Note Cut
01761         case 0xC0:      NoteCut(nChn, param); break;
01762         // SDx: Note Delay
01763         // case 0xD0:   break;
01764         // SEx: Pattern Delay for x rows
01765         // SFx: S3M: Funk Repeat, IT: Set Active Midi Macro
01766         case 0xF0:      pChn->nActiveMacro = param; break;
01767         }
01768 }
01769 
01770 
01771 void CSoundFile::ExtendedChannelEffect(MODCHANNEL *pChn, UINT param)
01772 //------------------------------------------------------------------
01773 {
01774         // S9x and X9x commands (S3M/XM/IT only)
01775         if (m_nTickCount) return;
01776         switch(param & 0x0F)
01777         {
01778         // S90: Surround Off
01779         case 0x00:      pChn->dwFlags &= ~CHN_SURROUND; break;
01780         // S91: Surround On
01781         case 0x01:      pChn->dwFlags |= CHN_SURROUND; pChn->nPan = 128; break;
01783         // Modplug Extensions
01784         // S98: Reverb Off
01785         case 0x08:
01786                 pChn->dwFlags &= ~CHN_REVERB;
01787                 pChn->dwFlags |= CHN_NOREVERB;
01788                 break;
01789         // S99: Reverb On
01790         case 0x09:
01791                 pChn->dwFlags &= ~CHN_NOREVERB;
01792                 pChn->dwFlags |= CHN_REVERB;
01793                 break;
01794         // S9A: 2-Channels surround mode
01795         case 0x0A:
01796                 m_dwSongFlags &= ~SONG_SURROUNDPAN;
01797                 break;
01798         // S9B: 4-Channels surround mode
01799         case 0x0B:
01800                 m_dwSongFlags |= SONG_SURROUNDPAN;
01801                 break;
01802         // S9C: IT Filter Mode
01803         case 0x0C:
01804                 m_dwSongFlags &= ~SONG_MPTFILTERMODE;
01805                 break;
01806         // S9D: MPT Filter Mode
01807         case 0x0D:
01808                 m_dwSongFlags |= SONG_MPTFILTERMODE;
01809                 break;
01810         // S9E: Go forward
01811         case 0x0E:
01812                 pChn->dwFlags &= ~(CHN_PINGPONGFLAG);
01813                 break;
01814         // S9F: Go backward (set position at the end for non-looping samples)
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         // Not Internal Device ?
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         // Internal device
01877         pszMidiMacro += 4;
01878         // Filter ?
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                 // F0.F0.00.xx: Set CutOff
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 // NO_FILTER
01909                         }
01910                         break;
01911                 
01912                 // F0.F0.01.xx: Set Resonance
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 // NO_FILTER
01918 
01919                         break;
01920                 }
01921                 
01922         }
01923 }
01924 
01925 
01926 void CSoundFile::RetrigNote(UINT nChn, UINT param)
01927 //------------------------------------------------
01928 {
01929         // Retrig: bit 8 is set if it's the new XM retrig
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         // IT Linear slides
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                 // if (m_nInstruments) KeyOff(pChn); ?
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         //if ((!pChn->pHeader) || (!(pChn->dwFlags & CHN_VOLENV)))
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 // CSoundFile: Global Effects
02078 
02079 
02080 void CSoundFile::SetSpeed(UINT param)
02081 //-----------------------------------
02082 {
02083         UINT max = (m_nType == MOD_TYPE_IT) ? 256 : 128;
02084         // Modplug Tracker and Mod-Plugin don't do this check
02085 #ifndef MODPLUG_TRACKER
02086 #ifndef FASTSOUNDLIB
02087         // Big Hack!!!
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                 // Tempo Slide
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                                 // Loop already done
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         // Treat only case with jumps in the same pattern
02228         if (nJumpOrder > nStartOrder) return TRUE;
02229         if ((nJumpOrder < nStartOrder) || (nJumpRow >= PatternSize[nStartOrder])
02230          || (!Patterns[nStartOrder]) || (nStartRow >= 256) || (nJumpRow >= 256)) return FALSE;
02231         // See if the pattern is being played backward
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 // Note/Period/Frequency functions
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 

Generated on Sat Nov 5 16:15:41 2005 for OPIE by  doxygen 1.4.2