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

sndmix.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 MODPLUG_TRACKER
00014 #define ENABLE_STEREOVU
00015 #endif
00016 
00017 // Volume ramp length, in 1/10 ms
00018 #define VOLUMERAMPLEN   146     // 1.46ms = 64 samples at 44.1kHz
00019 
00020 // VU-Meter
00021 #define VUMETER_DECAY           4
00022 
00023 // SNDMIX: These are global flags for playback control
00024 UINT CSoundFile::m_nStereoSeparation = 128;
00025 LONG CSoundFile::m_nStreamVolume = 0x8000;
00026 UINT CSoundFile::m_nMaxMixChannels = 32;
00027 // Mixing Configuration (SetWaveConfig)
00028 DWORD CSoundFile::gdwSysInfo = 0;
00029 DWORD CSoundFile::gnChannels = 1;
00030 DWORD CSoundFile::gdwSoundSetup = 0;
00031 DWORD CSoundFile::gdwMixingFreq = 44100;
00032 DWORD CSoundFile::gnBitsPerSample = 16;
00033 // Mixing data initialized in
00034 UINT CSoundFile::gnAGC = AGC_UNITY;
00035 UINT CSoundFile::gnVolumeRampSamples = 64;
00036 UINT CSoundFile::gnVUMeter = 0;
00037 UINT CSoundFile::gnCPUUsage = 0;
00038 LPSNDMIXHOOKPROC CSoundFile::gpSndMixHook = NULL;
00039 PMIXPLUGINCREATEPROC CSoundFile::gpMixPluginCreateProc = NULL;
00040 LONG gnDryROfsVol = 0;
00041 LONG gnDryLOfsVol = 0;
00042 LONG gnRvbROfsVol = 0;
00043 LONG gnRvbLOfsVol = 0;
00044 int gbInitPlugins = 0;
00045 
00046 typedef DWORD (MPPASMCALL * LPCONVERTPROC)(LPVOID, int *, DWORD, LPLONG, LPLONG);
00047 
00048 extern DWORD MPPASMCALL X86_Convert32To8(LPVOID lpBuffer, int *, DWORD nSamples, LPLONG, LPLONG);
00049 extern DWORD MPPASMCALL X86_Convert32To16(LPVOID lpBuffer, int *, DWORD nSamples, LPLONG, LPLONG);
00050 extern DWORD MPPASMCALL X86_Convert32To24(LPVOID lpBuffer, int *, DWORD nSamples, LPLONG, LPLONG);
00051 extern DWORD MPPASMCALL X86_Convert32To32(LPVOID lpBuffer, int *, DWORD nSamples, LPLONG, LPLONG);
00052 extern UINT MPPASMCALL X86_AGC(int *pBuffer, UINT nSamples, UINT nAGC);
00053 extern VOID MPPASMCALL X86_Dither(int *pBuffer, UINT nSamples, UINT nBits);
00054 extern VOID MPPASMCALL X86_InterleaveFrontRear(int *pFrontBuf, int *pRearBuf, DWORD nSamples);
00055 extern VOID MPPASMCALL X86_StereoFill(int *pBuffer, UINT nSamples, LPLONG lpROfs, LPLONG lpLOfs);
00056 extern VOID MPPASMCALL X86_MonoFromStereo(int *pMixBuf, UINT nSamples);
00057 
00058 extern const short int ModSinusTable[64];
00059 extern const short int ModRampDownTable[64];
00060 extern const short int ModSquareTable[64];
00061 extern const short int ModRandomTable[64];
00062 extern const DWORD LinearSlideUpTable[256];
00063 extern const DWORD LinearSlideDownTable[256];
00064 extern const DWORD FineLinearSlideUpTable[16];
00065 extern const DWORD FineLinearSlideDownTable[16];
00066 extern const signed char ft2VibratoTable[256];  // -64 .. +64
00067 extern int MixSoundBuffer[MIXBUFFERSIZE*4];
00068 extern int MixRearBuffer[MIXBUFFERSIZE*2];
00069 UINT gnReverbSend;
00070 
00071 
00072 // Log tables for pre-amp
00073 // We don't want the tracker to get too loud
00074 const UINT PreAmpTable[16] =
00075 {
00076         0x60, 0x60, 0x60, 0x70, // 0-7
00077         0x80, 0x88, 0x90, 0x98, // 8-15
00078         0xA0, 0xA4, 0xA8, 0xB0, // 16-23
00079         0xB4, 0xB8, 0xBC, 0xC0, // 24-31
00080 };
00081 
00082 const UINT PreAmpAGCTable[16] =
00083 {
00084         0x60, 0x60, 0x60, 0x60,
00085         0x68, 0x70, 0x78, 0x80,
00086         0x84, 0x88, 0x8C, 0x90,
00087         0x94, 0x98, 0x9C, 0xA0,
00088 };
00089 
00090 
00091 // Return (a*b)/c - no divide error
00092 int _muldiv(long a, long b, long c)
00093 {
00094 #ifdef WIN32
00095         int sign, result;
00096         _asm {
00097         mov eax, a
00098         mov ebx, b
00099         or eax, eax
00100         mov edx, eax
00101         jge aneg
00102         neg eax
00103 aneg:
00104         xor edx, ebx
00105         or ebx, ebx
00106         mov ecx, c
00107         jge bneg
00108         neg ebx
00109 bneg:
00110         xor edx, ecx
00111         or ecx, ecx
00112         mov sign, edx
00113         jge cneg
00114         neg ecx
00115 cneg:
00116         mul ebx
00117         cmp edx, ecx
00118         jae diverr
00119         div ecx
00120         jmp ok
00121 diverr:
00122         mov eax, 0x7fffffff
00123 ok:
00124         mov edx, sign
00125         or edx, edx
00126         jge rneg
00127         neg eax
00128 rneg:
00129         mov result, eax
00130         }
00131         return result;
00132 #else
00133         return ((unsigned long long) a * (unsigned long long) b ) / c;
00134 #endif
00135 }
00136 
00137 
00138 // Return (a*b+c/2)/c - no divide error
00139 int _muldivr(long a, long b, long c)
00140 {
00141 #ifdef WIN32
00142         int sign, result;
00143         _asm {
00144         mov eax, a
00145         mov ebx, b
00146         or eax, eax
00147         mov edx, eax
00148         jge aneg
00149         neg eax
00150 aneg:
00151         xor edx, ebx
00152         or ebx, ebx
00153         mov ecx, c
00154         jge bneg
00155         neg ebx
00156 bneg:
00157         xor edx, ecx
00158         or ecx, ecx
00159         mov sign, edx
00160         jge cneg
00161         neg ecx
00162 cneg:
00163         mul ebx
00164         mov ebx, ecx
00165         shr ebx, 1
00166         add eax, ebx
00167         adc edx, 0
00168         cmp edx, ecx
00169         jae diverr
00170         div ecx
00171         jmp ok
00172 diverr:
00173         mov eax, 0x7fffffff
00174 ok:
00175         mov edx, sign
00176         or edx, edx
00177         jge rneg
00178         neg eax
00179 rneg:
00180         mov result, eax
00181         }
00182         return result;
00183 #else
00184         return ((unsigned long long) a * (unsigned long long) b + (c >> 1)) / c;
00185 #endif
00186 }
00187 
00188 
00189 BOOL CSoundFile::InitPlayer(BOOL bReset)
00190 //--------------------------------------
00191 {
00192         if (m_nMaxMixChannels > MAX_CHANNELS) m_nMaxMixChannels = MAX_CHANNELS;
00193         if (gdwMixingFreq < 4000) gdwMixingFreq = 4000;
00194         if (gdwMixingFreq > MAX_SAMPLE_RATE) gdwMixingFreq = MAX_SAMPLE_RATE;
00195         gnVolumeRampSamples = (gdwMixingFreq * VOLUMERAMPLEN) / 100000;
00196         if (gnVolumeRampSamples < 8) gnVolumeRampSamples = 8;
00197         gnDryROfsVol = gnDryLOfsVol = 0;
00198         gnRvbROfsVol = gnRvbLOfsVol = 0;
00199         if (bReset)
00200         {
00201                 gnVUMeter = 0;
00202                 gnCPUUsage = 0;
00203         }
00204         gbInitPlugins = (bReset) ? 3 : 1;
00205         InitializeDSP(bReset);
00206         return TRUE;
00207 }
00208 
00209 
00210 BOOL CSoundFile::FadeSong(UINT msec)
00211 //----------------------------------
00212 {
00213         LONG nsamples = _muldiv(msec, gdwMixingFreq, 1000);
00214         if (nsamples <= 0) return FALSE;
00215         if (nsamples > 0x100000) nsamples = 0x100000;
00216         m_nBufferCount = nsamples;
00217         LONG nRampLength = m_nBufferCount;
00218         // Ramp everything down
00219         for (UINT noff=0; noff < m_nMixChannels; noff++)
00220         {
00221                 MODCHANNEL *pramp = &Chn[ChnMix[noff]];
00222                 if (!pramp) continue;
00223                 pramp->nNewLeftVol = pramp->nNewRightVol = 0;
00224                 pramp->nRightRamp = (-pramp->nRightVol << VOLUMERAMPPRECISION) / nRampLength;
00225                 pramp->nLeftRamp = (-pramp->nLeftVol << VOLUMERAMPPRECISION) / nRampLength;
00226                 pramp->nRampRightVol = pramp->nRightVol << VOLUMERAMPPRECISION;
00227                 pramp->nRampLeftVol = pramp->nLeftVol << VOLUMERAMPPRECISION;
00228                 pramp->nRampLength = nRampLength;
00229                 pramp->dwFlags |= CHN_VOLUMERAMP;
00230         }
00231         m_dwSongFlags |= SONG_FADINGSONG;
00232         return TRUE;
00233 }
00234 
00235 
00236 BOOL CSoundFile::GlobalFadeSong(UINT msec)
00237 //----------------------------------------
00238 {
00239         if (m_dwSongFlags & SONG_GLOBALFADE) return FALSE;
00240         m_nGlobalFadeMaxSamples = _muldiv(msec, gdwMixingFreq, 1000);
00241         m_nGlobalFadeSamples = m_nGlobalFadeMaxSamples;
00242         m_dwSongFlags |= SONG_GLOBALFADE;
00243         return TRUE;
00244 }
00245 
00246 
00247 UINT CSoundFile::Read(LPVOID lpDestBuffer, UINT cbBuffer)
00248 //-------------------------------------------------------
00249 {
00250         LPBYTE lpBuffer = (LPBYTE)lpDestBuffer;
00251         LPCONVERTPROC pCvt = X86_Convert32To8;
00252         UINT lRead, lMax, lSampleSize, lCount, lSampleCount, nStat=0;
00253         LONG nVUMeterMin = 0x7FFFFFFF, nVUMeterMax = -0x7FFFFFFF;
00254         UINT nMaxPlugins;
00255                 
00256         {
00257                 nMaxPlugins = MAX_MIXPLUGINS;
00258                 while ((nMaxPlugins > 0) && (!m_MixPlugins[nMaxPlugins-1].pMixPlugin)) nMaxPlugins--;
00259         }
00260         m_nMixStat = 0;
00261         lSampleSize = gnChannels;
00262         if (gnBitsPerSample == 16) { lSampleSize *= 2; pCvt = X86_Convert32To16; }
00263 #ifndef FASTSOUNDLIB
00264         else if (gnBitsPerSample == 24) { lSampleSize *= 3; pCvt = X86_Convert32To24; } 
00265         else if (gnBitsPerSample == 32) { lSampleSize *= 4; pCvt = X86_Convert32To32; } 
00266 #endif
00267         lMax = cbBuffer / lSampleSize;
00268         if ((!lMax) || (!lpBuffer) || (!m_nChannels)) return 0;
00269         lRead = lMax;
00270         if (m_dwSongFlags & SONG_ENDREACHED) goto MixDone;
00271         while (lRead > 0)
00272         {
00273                 // Update Channel Data
00274                 if (!m_nBufferCount)
00275                 {
00276 #ifndef FASTSOUNDLIB
00277                         if (m_dwSongFlags & SONG_FADINGSONG)
00278                         {
00279                                 m_dwSongFlags |= SONG_ENDREACHED;
00280                                 m_nBufferCount = lRead;
00281                         } else
00282 #endif
00283                         if (!ReadNote())
00284                         {
00285 #ifndef FASTSOUNDLIB
00286                                 if (!FadeSong(FADESONGDELAY))
00287 #endif
00288                                 {
00289                                         m_dwSongFlags |= SONG_ENDREACHED;
00290                                         if (lRead == lMax) goto MixDone;
00291                                         m_nBufferCount = lRead;
00292                                 }
00293                         }
00294                 }
00295                 lCount = m_nBufferCount;
00296                 if (lCount > MIXBUFFERSIZE) lCount = MIXBUFFERSIZE;
00297                 if (lCount > lRead) lCount = lRead;
00298                 if (!lCount) break;
00299                 lSampleCount = lCount;
00300 #ifndef NO_REVERB
00301                 gnReverbSend = 0;
00302 #endif
00303                 // Resetting sound buffer
00304                 X86_StereoFill(MixSoundBuffer, lSampleCount, &gnDryROfsVol, &gnDryLOfsVol);
00305                 if (gnChannels >= 2)
00306                 {
00307                         lSampleCount *= 2;
00308                         m_nMixStat += CreateStereoMix(lCount);
00309                         ProcessStereoDSP(lCount);
00310                 } else
00311                 {
00312                         m_nMixStat += CreateStereoMix(lCount);
00313                         if (nMaxPlugins) ProcessPlugins(lCount);
00314                         ProcessStereoDSP(lCount);
00315                         X86_MonoFromStereo(MixSoundBuffer, lCount);
00316                 }
00317                 nStat++;
00318 #ifndef NO_AGC
00319                 // Automatic Gain Control
00320                 if (gdwSoundSetup & SNDMIX_AGC) ProcessAGC(lSampleCount);
00321 #endif
00322                 UINT lTotalSampleCount = lSampleCount;
00323 #ifndef FASTSOUNDLIB
00324                 // Multichannel
00325                 if (gnChannels > 2)
00326                 {
00327                         X86_InterleaveFrontRear(MixSoundBuffer, MixRearBuffer, lSampleCount);
00328                         lTotalSampleCount *= 2;
00329                 }
00330                 // Hook Function
00331                 if (gpSndMixHook)
00332                 {
00333                         gpSndMixHook(MixSoundBuffer, lTotalSampleCount, gnChannels);
00334                 }
00335 #endif
00336                 // Perform clipping + VU-Meter
00337                 lpBuffer += pCvt(lpBuffer, MixSoundBuffer, lTotalSampleCount, &nVUMeterMin, &nVUMeterMax);
00338                 // Buffer ready
00339                 lRead -= lCount;
00340                 m_nBufferCount -= lCount;
00341         }
00342 MixDone:
00343         if (lRead) memset(lpBuffer, (gnBitsPerSample == 8) ? 0x80 : 0, lRead * lSampleSize);
00344         // VU-Meter
00345         nVUMeterMin >>= (24-MIXING_ATTENUATION);
00346         nVUMeterMax >>= (24-MIXING_ATTENUATION);
00347         if (nVUMeterMax < nVUMeterMin) nVUMeterMax = nVUMeterMin;
00348         if ((gnVUMeter = (UINT)(nVUMeterMax - nVUMeterMin)) > 0xFF) gnVUMeter = 0xFF;
00349         if (nStat) { m_nMixStat += nStat-1; m_nMixStat /= nStat; }
00350         return lMax - lRead;
00351 }
00352 
00353 
00354 
00356 // Handles navigation/effects
00357 
00358 BOOL CSoundFile::ProcessRow()
00359 //---------------------------
00360 {
00361         if (++m_nTickCount >= m_nMusicSpeed * (m_nPatternDelay+1) + m_nFrameDelay)
00362         {
00363                 m_nPatternDelay = 0;
00364                 m_nFrameDelay = 0;
00365                 m_nTickCount = 0;
00366                 m_nRow = m_nNextRow;
00367                 // Reset Pattern Loop Effect
00368                 if (m_nCurrentPattern != m_nNextPattern) m_nCurrentPattern = m_nNextPattern;
00369                 // Check if pattern is valid
00370                 if (!(m_dwSongFlags & SONG_PATTERNLOOP))
00371                 {
00372                         m_nPattern = (m_nCurrentPattern < MAX_ORDERS) ? Order[m_nCurrentPattern] : 0xFF;
00373                         if ((m_nPattern < MAX_PATTERNS) && (!Patterns[m_nPattern])) m_nPattern = 0xFE;
00374                         while (m_nPattern >= MAX_PATTERNS)
00375                         {
00376                                 // End of song ?
00377                                 if ((m_nPattern == 0xFF) || (m_nCurrentPattern >= MAX_ORDERS))
00378                                 {
00379                                         //if (!m_nRepeatCount)
00380                                                 return FALSE;     //never repeat entire song
00381                                         if (!m_nRestartPos)
00382                                         {
00383                                                 m_nMusicSpeed = m_nDefaultSpeed;
00384                                                 m_nMusicTempo = m_nDefaultTempo;
00385                                                 m_nGlobalVolume = m_nDefaultGlobalVolume;
00386                                                 for (UINT i=0; i<MAX_CHANNELS; i++)
00387                                                 {
00388                                                         Chn[i].dwFlags |= CHN_NOTEFADE | CHN_KEYOFF;
00389                                                         Chn[i].nFadeOutVol = 0;
00390                                                         if (i < m_nChannels)
00391                                                         {
00392                                                                 Chn[i].nGlobalVol = ChnSettings[i].nVolume;
00393                                                                 Chn[i].nVolume = ChnSettings[i].nVolume;
00394                                                                 Chn[i].nPan = ChnSettings[i].nPan;
00395                                                                 Chn[i].nPanSwing = Chn[i].nVolSwing = 0;
00396                                                                 Chn[i].nOldVolParam = 0;
00397                                                                 Chn[i].nOldOffset = 0;
00398                                                                 Chn[i].nOldHiOffset = 0;
00399                                                                 Chn[i].nPortamentoDest = 0;
00400                                                                 if (!Chn[i].nLength)
00401                                                                 {
00402                                                                         Chn[i].dwFlags = ChnSettings[i].dwFlags;
00403                                                                         Chn[i].nLoopStart = 0;
00404                                                                         Chn[i].nLoopEnd = 0;
00405                                                                         Chn[i].pHeader = NULL;
00406                                                                         Chn[i].pSample = NULL;
00407                                                                         Chn[i].pInstrument = NULL;
00408                                                                 }
00409                                                         }
00410                                                 }
00411                                         }
00412 //                                      if (m_nRepeatCount > 0) m_nRepeatCount--;
00413                                         m_nCurrentPattern = m_nRestartPos;
00414                                         m_nRow = 0;
00415                                         if ((Order[m_nCurrentPattern] >= MAX_PATTERNS) || (!Patterns[Order[m_nCurrentPattern]])) return FALSE;
00416                                 } else
00417                                 {
00418                                         m_nCurrentPattern++;
00419                                 }
00420                                 m_nPattern = (m_nCurrentPattern < MAX_ORDERS) ? Order[m_nCurrentPattern] : 0xFF;
00421                                 if ((m_nPattern < MAX_PATTERNS) && (!Patterns[m_nPattern])) m_nPattern = 0xFE;
00422                         }
00423                         m_nNextPattern = m_nCurrentPattern;
00424                 }
00425                 // Weird stuff?
00426                 if ((m_nPattern >= MAX_PATTERNS) || (!Patterns[m_nPattern])) return FALSE;
00427                 // Should never happen
00428                 if (m_nRow >= PatternSize[m_nPattern]) m_nRow = 0;
00429                 m_nNextRow = m_nRow + 1;
00430                 if (m_nNextRow >= PatternSize[m_nPattern])
00431                 {
00432                         if (!(m_dwSongFlags & SONG_PATTERNLOOP)) m_nNextPattern = m_nCurrentPattern + 1;
00433                         m_nNextRow = 0;
00434                 }
00435                 // Reset channel values
00436                 MODCHANNEL *pChn = Chn;
00437                 MODCOMMAND *m = Patterns[m_nPattern] + m_nRow * m_nChannels;
00438                 for (UINT nChn=0; nChn<m_nChannels; pChn++, nChn++, m++)
00439                 {
00440                         pChn->nRowNote = m->note;
00441                         pChn->nRowInstr = m->instr;
00442                         pChn->nRowVolCmd = m->volcmd;
00443                         pChn->nRowVolume = m->vol;
00444                         pChn->nRowCommand = m->command;
00445                         pChn->nRowParam = m->param;
00446 
00447                         pChn->nLeftVol = pChn->nNewLeftVol;
00448                         pChn->nRightVol = pChn->nNewRightVol;
00449                         pChn->dwFlags &= ~(CHN_PORTAMENTO | CHN_VIBRATO | CHN_TREMOLO | CHN_PANBRELLO);
00450                         pChn->nCommand = 0;
00451                 }
00452         }
00453         // Should we process tick0 effects?
00454         if (!m_nMusicSpeed) m_nMusicSpeed = 1;
00455         m_dwSongFlags |= SONG_FIRSTTICK;
00456         if (m_nTickCount)
00457         {
00458                 m_dwSongFlags &= ~SONG_FIRSTTICK;
00459                 if ((!(m_nType & MOD_TYPE_XM)) && (m_nTickCount < m_nMusicSpeed * (1 + m_nPatternDelay)))
00460                 {
00461                         if (!(m_nTickCount % m_nMusicSpeed)) m_dwSongFlags |= SONG_FIRSTTICK;
00462                 }
00463 
00464         }
00465         // Update Effects
00466         return ProcessEffects();
00467 }
00468 
00469 
00471 // Handles envelopes & mixer setup
00472 
00473 BOOL CSoundFile::ReadNote()
00474 //-------------------------
00475 {
00476         if (!ProcessRow()) return FALSE;
00478         m_nTotalCount++;
00479         if (!m_nMusicTempo) return FALSE;
00480         m_nBufferCount = (gdwMixingFreq * 5 * m_nTempoFactor) / (m_nMusicTempo << 8);
00481         // Master Volume + Pre-Amplification / Attenuation setup
00482         DWORD nMasterVol;
00483         {
00484                 int nchn32 = (m_nChannels < 32) ? m_nChannels : 31;
00485                 if ((m_nType & MOD_TYPE_IT) && (m_nInstruments) && (nchn32 < 6)) nchn32 = 6;
00486                 int realmastervol = m_nMasterVolume;
00487                 if (realmastervol > 0x80)
00488                 {
00489                         realmastervol = 0x80 + ((realmastervol - 0x80) * (nchn32+4)) / 16;
00490                 }
00491                 UINT attenuation = (gdwSoundSetup & SNDMIX_AGC) ? PreAmpAGCTable[nchn32>>1] : PreAmpTable[nchn32>>1];
00492                 DWORD mastervol = (realmastervol * (m_nSongPreAmp + 0x10)) >> 6;
00493                 if (mastervol > 0x200) mastervol = 0x200;
00494                 if ((m_dwSongFlags & SONG_GLOBALFADE) && (m_nGlobalFadeMaxSamples))
00495                 {
00496                         mastervol = _muldiv(mastervol, m_nGlobalFadeSamples, m_nGlobalFadeMaxSamples);
00497                 }
00498                 nMasterVol = (mastervol << 7) / attenuation;
00499                 if (nMasterVol > 0x180) nMasterVol = 0x180;
00500         }
00502         // Update channels data
00503         m_nMixChannels = 0;
00504         MODCHANNEL *pChn = Chn;
00505         for (UINT nChn=0; nChn<MAX_CHANNELS; nChn++,pChn++)
00506         {
00507                 if ((pChn->dwFlags & CHN_NOTEFADE) && (!(pChn->nFadeOutVol|pChn->nRightVol|pChn->nLeftVol)))
00508                 {
00509                         pChn->nLength = 0;
00510                         pChn->nROfs = pChn->nLOfs = 0;
00511                 }
00512                 // Check for unused channel
00513                 if ((pChn->dwFlags & CHN_MUTE) || ((nChn >= m_nChannels) && (!pChn->nLength)))
00514                 {
00515                         pChn->nVUMeter = 0;
00516 #ifdef ENABLE_STEREOVU
00517                         pChn->nLeftVU = pChn->nRightVU = 0;
00518 #endif
00519                         continue;
00520                 }
00521                 // Reset channel data
00522                 pChn->nInc = 0;
00523                 pChn->nRealVolume = 0;
00524                 pChn->nRealPan = pChn->nPan + pChn->nPanSwing;
00525                 if (pChn->nRealPan < 0) pChn->nRealPan = 0;
00526                 if (pChn->nRealPan > 256) pChn->nRealPan = 256;
00527                 pChn->nRampLength = 0;
00528                 // Calc Frequency
00529                 if ((pChn->nPeriod)     && (pChn->nLength))
00530                 {
00531                         int vol = pChn->nVolume + pChn->nVolSwing;
00532                         
00533                         if (vol < 0) vol = 0;
00534                         if (vol > 256) vol = 256;
00535                         // Tremolo
00536                         if (pChn->dwFlags & CHN_TREMOLO)
00537                         {
00538                                 UINT trempos = pChn->nTremoloPos & 0x3F;
00539                                 if (vol > 0)
00540                                 {
00541                                         int tremattn = (m_nType & MOD_TYPE_XM) ? 5 : 6;
00542                                         switch (pChn->nTremoloType & 0x03)
00543                                         {
00544                                         case 1:
00545                                                 vol += (ModRampDownTable[trempos] * (int)pChn->nTremoloDepth) >> tremattn;
00546                                                 break;
00547                                         case 2:
00548                                                 vol += (ModSquareTable[trempos] * (int)pChn->nTremoloDepth) >> tremattn;
00549                                                 break;
00550                                         case 3:
00551                                                 vol += (ModRandomTable[trempos] * (int)pChn->nTremoloDepth) >> tremattn;
00552                                                 break;
00553                                         default:
00554                                                 vol += (ModSinusTable[trempos] * (int)pChn->nTremoloDepth) >> tremattn;
00555                                         }
00556                                 }
00557                                 if ((m_nTickCount) || ((m_nType & (MOD_TYPE_STM|MOD_TYPE_S3M|MOD_TYPE_IT)) && (!(m_dwSongFlags & SONG_ITOLDEFFECTS))))
00558                                 {
00559                                         pChn->nTremoloPos = (trempos + pChn->nTremoloSpeed) & 0x3F;
00560                                 }
00561                         }
00562                         // Tremor
00563                         if (pChn->nCommand == CMD_TREMOR)
00564                         {
00565                                 UINT n = (pChn->nTremorParam >> 4) + (pChn->nTremorParam & 0x0F);
00566                                 UINT ontime = pChn->nTremorParam >> 4;
00567                                 if ((!(m_nType & MOD_TYPE_IT)) || (m_dwSongFlags & SONG_ITOLDEFFECTS)) { n += 2; ontime++; }
00568                                 UINT tremcount = (UINT)pChn->nTremorCount;
00569                                 if (tremcount >= n) tremcount = 0;
00570                                 if ((m_nTickCount) || (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT)))
00571                                 {
00572                                         if (tremcount >= ontime) vol = 0;
00573                                         pChn->nTremorCount = (BYTE)(tremcount + 1);
00574                                 }
00575                                 pChn->dwFlags |= CHN_FASTVOLRAMP;
00576                         }
00577                         // Clip volume
00578                         if (vol < 0) vol = 0;
00579                         if (vol > 0x100) vol = 0x100;
00580                         vol <<= 6;
00581                         // Process Envelopes
00582                         if (pChn->pHeader)
00583                         {
00584                                 INSTRUMENTHEADER *penv = pChn->pHeader;
00585                                 // Volume Envelope
00586                                 if ((pChn->dwFlags & CHN_VOLENV) && (penv->nVolEnv))
00587                                 {
00588                                         int envpos = pChn->nVolEnvPosition;
00589                                         UINT pt = penv->nVolEnv - 1;
00590                                         for (UINT i=0; i<(UINT)(penv->nVolEnv-1); i++)
00591                                         {
00592                                                 if (envpos <= penv->VolPoints[i])
00593                                                 {
00594                                                         pt = i;
00595                                                         break;
00596                                                 }
00597                                         }
00598                                         int x2 = penv->VolPoints[pt];
00599                                         int x1, envvol;
00600                                         if (envpos >= x2)
00601                                         {
00602                                                 envvol = penv->VolEnv[pt] << 2;
00603                                                 x1 = x2;
00604                                         } else
00605                                         if (pt)
00606                                         {
00607                                                 envvol = penv->VolEnv[pt-1] << 2;
00608                                                 x1 = penv->VolPoints[pt-1];
00609                                         } else
00610                                         {
00611                                                 envvol = 0;
00612                                                 x1 = 0;
00613                                         }
00614                                         if (envpos > x2) envpos = x2;
00615                                         if ((x2 > x1) && (envpos > x1))
00616                                         {
00617                                                 envvol += ((envpos - x1) * (((int)penv->VolEnv[pt]<<2) - envvol)) / (x2 - x1);
00618                                         }
00619                                         if (envvol < 0) envvol = 0;
00620                                         if (envvol > 256) envvol = 256;
00621                                         vol = (vol * envvol) >> 8;
00622                                 }
00623                                 // Panning Envelope
00624                                 if ((pChn->dwFlags & CHN_PANENV) && (penv->nPanEnv))
00625                                 {
00626                                         int envpos = pChn->nPanEnvPosition;
00627                                         UINT pt = penv->nPanEnv - 1;
00628                                         for (UINT i=0; i<(UINT)(penv->nPanEnv-1); i++)
00629                                         {
00630                                                 if (envpos <= penv->PanPoints[i])
00631                                                 {
00632                                                         pt = i;
00633                                                         break;
00634                                                 }
00635                                         }
00636                                         int x2 = penv->PanPoints[pt], y2 = penv->PanEnv[pt];
00637                                         int x1, envpan;
00638                                         if (envpos >= x2)
00639                                         {
00640                                                 envpan = y2;
00641                                                 x1 = x2;
00642                                         } else
00643                                         if (pt)
00644                                         {
00645                                                 envpan = penv->PanEnv[pt-1];
00646                                                 x1 = penv->PanPoints[pt-1];
00647                                         } else
00648                                         {
00649                                                 envpan = 128;
00650                                                 x1 = 0;
00651                                         }
00652                                         if ((x2 > x1) && (envpos > x1))
00653                                         {
00654                                                 envpan += ((envpos - x1) * (y2 - envpan)) / (x2 - x1);
00655                                         }
00656                                         if (envpan < 0) envpan = 0;
00657                                         if (envpan > 64) envpan = 64;
00658                                         int pan = pChn->nPan;
00659                                         if (pan >= 128)
00660                                         {
00661                                                 pan += ((envpan - 32) * (256 - pan)) / 32;
00662                                         } else
00663                                         {
00664                                                 pan += ((envpan - 32) * (pan)) / 32;
00665                                         }
00666                                         if (pan < 0) pan = 0;
00667                                         if (pan > 256) pan = 256;
00668                                         pChn->nRealPan = pan;
00669                                 }
00670                                 // FadeOut volume
00671                                 if (pChn->dwFlags & CHN_NOTEFADE)
00672                                 {
00673                                         UINT fadeout = penv->nFadeOut;
00674                                         if (fadeout)
00675                                         {
00676                                                 pChn->nFadeOutVol -= fadeout << 1;
00677                                                 if (pChn->nFadeOutVol <= 0) pChn->nFadeOutVol = 0;
00678                                                 vol = (vol * pChn->nFadeOutVol) >> 16;
00679                                         } else
00680                                         if (!pChn->nFadeOutVol)
00681                                         {
00682                                                 vol = 0;
00683                                         }
00684                                 }
00685                                 // Pitch/Pan separation
00686                                 if ((penv->nPPS) && (pChn->nRealPan) && (pChn->nNote))
00687                                 {
00688                                         int pandelta = (int)pChn->nRealPan + (int)((int)(pChn->nNote - penv->nPPC - 1) * (int)penv->nPPS) / (int)8;
00689                                         if (pandelta < 0) pandelta = 0;
00690                                         if (pandelta > 256) pandelta = 256;
00691                                         pChn->nRealPan = pandelta;
00692                                 }
00693                         } else
00694                         {
00695                                 // No Envelope: key off => note cut
00696                                 if (pChn->dwFlags & CHN_NOTEFADE) // 1.41-: CHN_KEYOFF|CHN_NOTEFADE
00697                                 {
00698                                         pChn->nFadeOutVol = 0;
00699                                         vol = 0;
00700                                 }
00701                         }
00702                         // vol is 14-bits
00703                         if (vol)
00704                         {
00705                                 // IMPORTANT: pChn->nRealVolume is 14 bits !!!
00706                                 // -> _muldiv( 14+8, 6+6, 18); => RealVolume: 14-bit result (22+12-20)
00707                                 pChn->nRealVolume = _muldiv(vol * m_nGlobalVolume, pChn->nGlobalVol * pChn->nInsVol, 1 << 20);
00708                         }
00709                         if (pChn->nPeriod < m_nMinPeriod) pChn->nPeriod = m_nMinPeriod;
00710                         int period = pChn->nPeriod;
00711                         if ((pChn->dwFlags & (CHN_GLISSANDO|CHN_PORTAMENTO)) == (CHN_GLISSANDO|CHN_PORTAMENTO))
00712                         {
00713                                 period = GetPeriodFromNote(GetNoteFromPeriod(period), pChn->nFineTune, pChn->nC4Speed);
00714                         }
00715 
00716                         // Arpeggio ?
00717                         if (pChn->nCommand == CMD_ARPEGGIO)
00718                         {
00719                                 switch(m_nTickCount % 3)
00720                                 {
00721                                 case 1: period = GetPeriodFromNote(pChn->nNote + (pChn->nArpeggio >> 4), pChn->nFineTune, pChn->nC4Speed); break;
00722                                 case 2: period = GetPeriodFromNote(pChn->nNote + (pChn->nArpeggio & 0x0F), pChn->nFineTune, pChn->nC4Speed); break;
00723                                 }
00724                         }
00725 
00726                         if (m_dwSongFlags & SONG_AMIGALIMITS)
00727                         {
00728                                 if (period < 113*4) period = 113*4;
00729                                 if (period > 856*4) period = 856*4;
00730                         }
00731 
00732                         // Pitch/Filter Envelope
00733                         if ((pChn->pHeader) && (pChn->dwFlags & CHN_PITCHENV) && (pChn->pHeader->nPitchEnv))
00734                         {
00735                                 INSTRUMENTHEADER *penv = pChn->pHeader;
00736                                 int envpos = pChn->nPitchEnvPosition;
00737                                 UINT pt = penv->nPitchEnv - 1;
00738                                 for (UINT i=0; i<(UINT)(penv->nPitchEnv-1); i++)
00739                                 {
00740                                         if (envpos <= penv->PitchPoints[i])
00741                                         {
00742                                                 pt = i;
00743                                                 break;
00744                                         }
00745                                 }
00746                                 int x2 = penv->PitchPoints[pt];
00747                                 int x1, envpitch;
00748                                 if (envpos >= x2)
00749                                 {
00750                                         envpitch = (((int)penv->PitchEnv[pt]) - 32) * 8;
00751                                         x1 = x2;
00752                                 } else
00753                                 if (pt)
00754                                 {
00755                                         envpitch = (((int)penv->PitchEnv[pt-1]) - 32) * 8;
00756                                         x1 = penv->PitchPoints[pt-1];
00757                                 } else
00758                                 {
00759                                         envpitch = 0;
00760                                         x1 = 0;
00761                                 }
00762                                 if (envpos > x2) envpos = x2;
00763                                 if ((x2 > x1) && (envpos > x1))
00764                                 {
00765                                         int envpitchdest = (((int)penv->PitchEnv[pt]) - 32) * 8;
00766                                         envpitch += ((envpos - x1) * (envpitchdest - envpitch)) / (x2 - x1);
00767                                 }
00768                                 if (envpitch < -256) envpitch = -256;
00769                                 if (envpitch > 256) envpitch = 256;
00770                                 // Filter Envelope: controls cutoff frequency
00771                                 if (penv->dwFlags & ENV_FILTER)
00772                                 {
00773 #ifndef NO_FILTER
00774                                         SetupChannelFilter(pChn, (pChn->dwFlags & CHN_FILTER) ? FALSE : TRUE, envpitch);
00775 #endif // NO_FILTER
00776                                 } else
00777                                 // Pitch Envelope
00778                                 {
00779                                         int l = envpitch;
00780                                         if (l < 0)
00781                                         {
00782                                                 l = -l;
00783                                                 if (l > 255) l = 255;
00784                                                 period = _muldiv(period, LinearSlideUpTable[l], 0x10000);
00785                                         } else
00786                                         {
00787                                                 if (l > 255) l = 255;
00788                                                 period = _muldiv(period, LinearSlideDownTable[l], 0x10000);
00789                                         }
00790                                 }
00791                         }
00792                         
00793                         // Vibrato
00794                         if (pChn->dwFlags & CHN_VIBRATO)
00795                         {
00796                                 UINT vibpos = pChn->nVibratoPos;
00797                                 LONG vdelta;
00798                                 switch (pChn->nVibratoType & 0x03)
00799                                 {
00800                                 case 1:
00801                                         vdelta = ModRampDownTable[vibpos];
00802                                         break;
00803                                 case 2:
00804                                         vdelta = ModSquareTable[vibpos];
00805                                         break;
00806                                 case 3:
00807                                         vdelta = ModRandomTable[vibpos];
00808                                         break;
00809                                 default:
00810                                         vdelta = ModSinusTable[vibpos];
00811                                 }
00812                                 UINT vdepth = ((m_nType != MOD_TYPE_IT) || (m_dwSongFlags & SONG_ITOLDEFFECTS)) ? 6 : 7;
00813                                 vdelta = (vdelta * (int)pChn->nVibratoDepth) >> vdepth;
00814                                 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (m_nType & MOD_TYPE_IT))
00815                                 {
00816                                         LONG l = vdelta;
00817                                         if (l < 0)
00818                                         {
00819                                                 l = -l;
00820                                                 vdelta = _muldiv(period, LinearSlideDownTable[l >> 2], 0x10000) - period;
00821                                                 if (l & 0x03) vdelta += _muldiv(period, FineLinearSlideDownTable[l & 0x03], 0x10000) - period;
00822 
00823                                         } else
00824                                         {
00825                                                 vdelta = _muldiv(period, LinearSlideUpTable[l >> 2], 0x10000) - period;
00826                                                 if (l & 0x03) vdelta += _muldiv(period, FineLinearSlideUpTable[l & 0x03], 0x10000) - period;
00827 
00828                                         }
00829                                 }
00830                                 period += vdelta;
00831                                 if ((m_nTickCount) || ((m_nType & MOD_TYPE_IT) && (!(m_dwSongFlags & SONG_ITOLDEFFECTS))))
00832                                 {
00833                                         pChn->nVibratoPos = (vibpos + pChn->nVibratoSpeed) & 0x3F;
00834                                 }
00835                         }
00836                         // Panbrello
00837                         if (pChn->dwFlags & CHN_PANBRELLO)
00838                         {
00839                                 UINT panpos = ((pChn->nPanbrelloPos+0x10) >> 2) & 0x3F;
00840                                 LONG pdelta;
00841                                 switch (pChn->nPanbrelloType & 0x03)
00842                                 {
00843                                 case 1:
00844                                         pdelta = ModRampDownTable[panpos];
00845                                         break;
00846                                 case 2:
00847                                         pdelta = ModSquareTable[panpos];
00848                                         break;
00849                                 case 3:
00850                                         pdelta = ModRandomTable[panpos];
00851                                         break;
00852                                 default:
00853                                         pdelta = ModSinusTable[panpos];
00854                                 }
00855                                 pChn->nPanbrelloPos += pChn->nPanbrelloSpeed;
00856                                 pdelta = ((pdelta * (int)pChn->nPanbrelloDepth) + 2) >> 3;
00857                                 pdelta += pChn->nRealPan;
00858                                 if (pdelta < 0) pdelta = 0;
00859                                 if (pdelta > 256) pdelta = 256;
00860                                 pChn->nRealPan = pdelta;
00861                         }
00862                         int nPeriodFrac = 0;
00863                         // Instrument Auto-Vibrato
00864                         if ((pChn->pInstrument) && (pChn->pInstrument->nVibDepth))
00865                         {
00866                                 MODINSTRUMENT *pins = pChn->pInstrument;
00867                                 if (pins->nVibSweep == 0)
00868                                 {
00869                                         pChn->nAutoVibDepth = pins->nVibDepth << 8;
00870                                 } else
00871                                 {
00872                                         if (m_nType & MOD_TYPE_IT)
00873                                         {
00874                                                 pChn->nAutoVibDepth += pins->nVibSweep << 3;
00875                                         } else
00876                                         if (!(pChn->dwFlags & CHN_KEYOFF))
00877                                         {
00878                                                 pChn->nAutoVibDepth += (pins->nVibDepth << 8) / pins->nVibSweep;
00879                                         }
00880                                         if ((pChn->nAutoVibDepth >> 8) > pins->nVibDepth)
00881                                                 pChn->nAutoVibDepth = pins->nVibDepth << 8;
00882                                 }
00883                                 pChn->nAutoVibPos += pins->nVibRate;
00884                                 int val;
00885                                 switch(pins->nVibType)
00886                                 {
00887                                 case 4: // Random
00888                                         val = ModRandomTable[pChn->nAutoVibPos & 0x3F];
00889                                         pChn->nAutoVibPos++;
00890                                         break;
00891                                 case 3: // Ramp Down
00892                                         val = ((0x40 - (pChn->nAutoVibPos >> 1)) & 0x7F) - 0x40;
00893                                         break;
00894                                 case 2: // Ramp Up
00895                                         val = ((0x40 + (pChn->nAutoVibPos >> 1)) & 0x7f) - 0x40;
00896                                         break;
00897                                 case 1: // Square
00898                                         val = (pChn->nAutoVibPos & 128) ? +64 : -64;
00899                                         break;
00900                                 default:        // Sine
00901                                         val = ft2VibratoTable[pChn->nAutoVibPos & 255];
00902                                 }
00903                                 int n = ((val * pChn->nAutoVibDepth) >> 8);
00904                                 if (m_nType & MOD_TYPE_IT)
00905                                 {
00906                                         int df1, df2;
00907                                         if (n < 0)
00908                                         {
00909                                                 n = -n;
00910                                                 UINT n1 = n >> 8;
00911                                                 df1 = LinearSlideUpTable[n1];
00912                                                 df2 = LinearSlideUpTable[n1+1];
00913                                         } else
00914                                         {
00915                                                 UINT n1 = n >> 8;
00916                                                 df1 = LinearSlideDownTable[n1];
00917                                                 df2 = LinearSlideDownTable[n1+1];
00918                                         }
00919                                         n >>= 2;
00920                                         period = _muldiv(period, df1 + ((df2-df1)*(n&0x3F)>>6), 256);
00921                                         nPeriodFrac = period & 0xFF;
00922                                         period >>= 8;
00923                                 } else
00924                                 {
00925                                         period += (n >> 6);
00926                                 }
00927                         }
00928                         // Final Period
00929                         if (period <= m_nMinPeriod)
00930                         {
00931                                 if (m_nType & MOD_TYPE_S3M) pChn->nLength = 0;
00932                                 period = m_nMinPeriod;
00933                         }
00934                         if (period > m_nMaxPeriod)
00935                         {
00936                                 if ((m_nType & MOD_TYPE_IT) || (period >= 0x100000))
00937                                 {
00938                                         pChn->nFadeOutVol = 0;
00939                                         pChn->dwFlags |= CHN_NOTEFADE;
00940                                         pChn->nRealVolume = 0;
00941                                 }
00942                                 period = m_nMaxPeriod;
00943                                 nPeriodFrac = 0;
00944                         }
00945                         UINT freq = GetFreqFromPeriod(period, pChn->nC4Speed, nPeriodFrac);
00946                         if ((m_nType & MOD_TYPE_IT) && (freq < 256))
00947                         {
00948                                 pChn->nFadeOutVol = 0;
00949                                 pChn->dwFlags |= CHN_NOTEFADE;
00950                                 pChn->nRealVolume = 0;
00951                         }
00952                         UINT ninc = _muldiv(freq, 0x10000, gdwMixingFreq);
00953                         if ((ninc >= 0xFFB0) && (ninc <= 0x10090)) ninc = 0x10000;
00954                         if (m_nFreqFactor != 128) ninc = (ninc * m_nFreqFactor) >> 7;
00955                         if (ninc > 0xFF0000) ninc = 0xFF0000;
00956                         pChn->nInc = (ninc+1) & ~3;
00957                 }
00958                 
00959                 // Increment envelope position
00960                 if (pChn->pHeader)
00961                 {
00962                         INSTRUMENTHEADER *penv = pChn->pHeader;
00963                         // Volume Envelope
00964                         if (pChn->dwFlags & CHN_VOLENV)
00965                         {
00966                                 // Increase position
00967                                 pChn->nVolEnvPosition++;
00968                                 // Volume Loop ?
00969                                 if (penv->dwFlags & ENV_VOLLOOP)
00970                                 {
00971                                         UINT volloopend = penv->VolPoints[penv->nVolLoopEnd];
00972                                         if (m_nType != MOD_TYPE_XM) volloopend++;
00973                                         if (pChn->nVolEnvPosition == volloopend)
00974                                         {
00975                                                 pChn->nVolEnvPosition = penv->VolPoints[penv->nVolLoopStart];
00976                                                 if ((penv->nVolLoopEnd == penv->nVolLoopStart) && (!penv->VolEnv[penv->nVolLoopStart])
00977                                                  && ((!(m_nType & MOD_TYPE_XM)) || (penv->nVolLoopEnd+1 == penv->nVolEnv)))
00978                                                 {
00979                                                         pChn->dwFlags |= CHN_NOTEFADE;
00980                                                         pChn->nFadeOutVol = 0;
00981                                                 }
00982                                         }
00983                                 }
00984                                 // Volume Sustain ?
00985                                 if ((penv->dwFlags & ENV_VOLSUSTAIN) && (!(pChn->dwFlags & CHN_KEYOFF)))
00986                                 {
00987                                         if (pChn->nVolEnvPosition == (UINT)penv->VolPoints[penv->nVolSustainEnd]+1)
00988                                                 pChn->nVolEnvPosition = penv->VolPoints[penv->nVolSustainBegin];
00989                                 } else
00990                                 // End of Envelope ?
00991                                 if (pChn->nVolEnvPosition > penv->VolPoints[penv->nVolEnv - 1])
00992                                 {
00993                                         if ((m_nType & MOD_TYPE_IT) || (pChn->dwFlags & CHN_KEYOFF)) pChn->dwFlags |= CHN_NOTEFADE;
00994                                         pChn->nVolEnvPosition = penv->VolPoints[penv->nVolEnv - 1];
00995                                         if ((!penv->VolEnv[penv->nVolEnv-1]) && ((nChn >= m_nChannels) || (m_nType & MOD_TYPE_IT)))
00996                                         {
00997                                                 pChn->dwFlags |= CHN_NOTEFADE;
00998                                                 pChn->nFadeOutVol = 0;
00999 
01000                                                 pChn->nRealVolume = 0;
01001                                         }
01002                                 }
01003                         }
01004                         // Panning Envelope
01005                         if (pChn->dwFlags & CHN_PANENV)
01006                         {
01007                                 pChn->nPanEnvPosition++;
01008                                 if (penv->dwFlags & ENV_PANLOOP)
01009                                 {
01010                                         UINT panloopend = penv->PanPoints[penv->nPanLoopEnd];
01011                                         if (m_nType != MOD_TYPE_XM) panloopend++;
01012                                         if (pChn->nPanEnvPosition == panloopend)
01013                                                 pChn->nPanEnvPosition = penv->PanPoints[penv->nPanLoopStart];
01014                                 }
01015                                 // Panning Sustain ?
01016                                 if ((penv->dwFlags & ENV_PANSUSTAIN) && (pChn->nPanEnvPosition == (UINT)penv->PanPoints[penv->nPanSustainEnd]+1)
01017                                  && (!(pChn->dwFlags & CHN_KEYOFF)))
01018                                 {
01019                                         // Panning sustained
01020                                         pChn->nPanEnvPosition = penv->PanPoints[penv->nPanSustainBegin];
01021                                 } else
01022                                 {
01023                                         if (pChn->nPanEnvPosition > penv->PanPoints[penv->nPanEnv - 1])
01024                                                 pChn->nPanEnvPosition = penv->PanPoints[penv->nPanEnv - 1];
01025                                 }
01026                         }
01027                         // Pitch Envelope
01028                         if (pChn->dwFlags & CHN_PITCHENV)
01029                         {
01030                                 // Increase position
01031                                 pChn->nPitchEnvPosition++;
01032                                 // Pitch Loop ?
01033                                 if (penv->dwFlags & ENV_PITCHLOOP)
01034                                 {
01035                                         if (pChn->nPitchEnvPosition >= penv->PitchPoints[penv->nPitchLoopEnd])
01036                                                 pChn->nPitchEnvPosition = penv->PitchPoints[penv->nPitchLoopStart];
01037                                 }
01038                                 // Pitch Sustain ?
01039                                 if ((penv->dwFlags & ENV_PITCHSUSTAIN) && (!(pChn->dwFlags & CHN_KEYOFF)))
01040                                 {
01041                                         if (pChn->nPitchEnvPosition == (UINT)penv->PitchPoints[penv->nPitchSustainEnd]+1)
01042                                                 pChn->nPitchEnvPosition = penv->PitchPoints[penv->nPitchSustainBegin];
01043                                 } else
01044                                 {
01045                                         if (pChn->nPitchEnvPosition > penv->PitchPoints[penv->nPitchEnv - 1])
01046                                                 pChn->nPitchEnvPosition = penv->PitchPoints[penv->nPitchEnv - 1];
01047                                 }
01048                         }
01049                 }
01050 #ifdef MODPLUG_PLAYER
01051                 // Limit CPU -> > 80% -> don't ramp
01052                 if ((gnCPUUsage >= 80) && (!pChn->nRealVolume))
01053                 {
01054                         pChn->nLeftVol = pChn->nRightVol = 0;
01055                 }
01056 #endif // MODPLUG_PLAYER
01057                 // Volume ramping
01058                 pChn->dwFlags &= ~CHN_VOLUMERAMP;
01059                 if ((pChn->nRealVolume) || (pChn->nLeftVol) || (pChn->nRightVol))
01060                         pChn->dwFlags |= CHN_VOLUMERAMP;
01061 #ifdef MODPLUG_PLAYER
01062                 // Decrease VU-Meter
01063                 if (pChn->nVUMeter > VUMETER_DECAY)     pChn->nVUMeter -= VUMETER_DECAY; else pChn->nVUMeter = 0;
01064 #endif // MODPLUG_PLAYER
01065 #ifdef ENABLE_STEREOVU
01066                 if (pChn->nLeftVU > VUMETER_DECAY) pChn->nLeftVU -= VUMETER_DECAY; else pChn->nLeftVU = 0;
01067                 if (pChn->nRightVU > VUMETER_DECAY) pChn->nRightVU -= VUMETER_DECAY; else pChn->nRightVU = 0;
01068 #endif
01069                 // Check for too big nInc
01070                 if (((pChn->nInc >> 16) + 1) >= (LONG)(pChn->nLoopEnd - pChn->nLoopStart)) pChn->dwFlags &= ~CHN_LOOP;
01071                 pChn->nNewRightVol = pChn->nNewLeftVol = 0;
01072                 pChn->pCurrentSample = ((pChn->pSample) && (pChn->nLength) && (pChn->nInc)) ? pChn->pSample : NULL;
01073                 if (pChn->pCurrentSample)
01074                 {
01075                         // Update VU-Meter (nRealVolume is 14-bit)
01076 #ifdef MODPLUG_PLAYER
01077                         UINT vutmp = pChn->nRealVolume >> (14 - 8);
01078                         if (vutmp > 0xFF) vutmp = 0xFF;
01079                         if (pChn->nVUMeter >= 0x100) pChn->nVUMeter = vutmp;
01080                         vutmp >>= 1;
01081                         if (pChn->nVUMeter < vutmp)     pChn->nVUMeter = vutmp;
01082 #endif // MODPLUG_PLAYER
01083 #ifdef ENABLE_STEREOVU
01084                         UINT vul = (pChn->nRealVolume * pChn->nRealPan) >> 14;
01085                         if (vul > 127) vul = 127;
01086                         if (pChn->nLeftVU > 127) pChn->nLeftVU = (BYTE)vul;
01087                         vul >>= 1;
01088                         if (pChn->nLeftVU < vul) pChn->nLeftVU = (BYTE)vul;
01089                         UINT vur = (pChn->nRealVolume * (256-pChn->nRealPan)) >> 14;
01090                         if (vur > 127) vur = 127;
01091                         if (pChn->nRightVU > 127) pChn->nRightVU = (BYTE)vur;
01092                         vur >>= 1;
01093                         if (pChn->nRightVU < vur) pChn->nRightVU = (BYTE)vur;
01094 #endif
01095 #ifdef MODPLUG_TRACKER
01096                         UINT kChnMasterVol = (pChn->dwFlags & CHN_EXTRALOUD) ? 0x100 : nMasterVol;
01097 #else
01098 #define         kChnMasterVol   nMasterVol
01099 #endif // MODPLUG_TRACKER
01100                         // Adjusting volumes
01101                         if (gnChannels >= 2)
01102                         {
01103                                 int pan = ((int)pChn->nRealPan) - 128;
01104                                 pan *= (int)m_nStereoSeparation;
01105                                 pan /= 128;
01106                                 pan += 128;
01107 
01108                                 if (pan < 0) pan = 0;
01109                                 if (pan > 256) pan = 256;
01110 #ifndef FASTSOUNDLIB
01111                                 if (gdwSoundSetup & SNDMIX_REVERSESTEREO) pan = 256 - pan;
01112 #endif
01113                                 LONG realvol = (pChn->nRealVolume * kChnMasterVol) >> (8-1);
01114                                 if (gdwSoundSetup & SNDMIX_SOFTPANNING)
01115                                 {
01116                                         if (pan < 128)
01117                                         {
01118                                                 pChn->nNewLeftVol = (realvol * pan) >> 8;
01119                                                 pChn->nNewRightVol = (realvol * 128) >> 8;
01120                                         } else
01121                                         {
01122                                                 pChn->nNewLeftVol = (realvol * 128) >> 8;
01123                                                 pChn->nNewRightVol = (realvol * (256 - pan)) >> 8;
01124                                         }
01125                                 } else
01126                                 {
01127                                         pChn->nNewLeftVol = (realvol * pan) >> 8;
01128                                         pChn->nNewRightVol = (realvol * (256 - pan)) >> 8;
01129                                 }
01130                         } else
01131                         {
01132                                 pChn->nNewRightVol = (pChn->nRealVolume * kChnMasterVol) >> 8;
01133                                 pChn->nNewLeftVol = pChn->nNewRightVol;
01134                         }
01135                         // Clipping volumes
01136                         if (pChn->nNewRightVol > 0xFFFF) pChn->nNewRightVol = 0xFFFF;
01137                         if (pChn->nNewLeftVol > 0xFFFF) pChn->nNewLeftVol = 0xFFFF;
01138                         // Check IDO
01139                         if (gdwSoundSetup & SNDMIX_NORESAMPLING)
01140                         {
01141                                 pChn->dwFlags |= CHN_NOIDO;
01142                         } else
01143                         {
01144                                 pChn->dwFlags &= ~(CHN_NOIDO|CHN_HQSRC);
01145                                 if( pChn->nInc == 0x10000 )
01146                                 {       pChn->dwFlags |= CHN_NOIDO;
01147                                 }
01148                                 else
01149                                 {       if( ((gdwSoundSetup & SNDMIX_HQRESAMPLER) == 0) && ((gdwSoundSetup & SNDMIX_ULTRAHQSRCMODE) == 0) )
01150                                         {       if (pChn->nInc >= 0xFF00) pChn->dwFlags |= CHN_NOIDO;
01151                                         }
01152                                 }
01153                         }
01154                         pChn->nNewRightVol >>= MIXING_ATTENUATION;
01155                         pChn->nNewLeftVol >>= MIXING_ATTENUATION;
01156                         pChn->nRightRamp = pChn->nLeftRamp = 0;
01157                         // Dolby Pro-Logic Surround
01158                         if ((pChn->dwFlags & CHN_SURROUND) && (gnChannels <= 2)) pChn->nNewLeftVol = - pChn->nNewLeftVol;
01159                         // Checking Ping-Pong Loops
01160                         if (pChn->dwFlags & CHN_PINGPONGFLAG) pChn->nInc = -pChn->nInc;
01161                         // Setting up volume ramp
01162                         if ((pChn->dwFlags & CHN_VOLUMERAMP)
01163                          && ((pChn->nRightVol != pChn->nNewRightVol)
01164                           || (pChn->nLeftVol != pChn->nNewLeftVol)))
01165                         {
01166                                 LONG nRampLength = gnVolumeRampSamples;
01167                                 LONG nRightDelta = ((pChn->nNewRightVol - pChn->nRightVol) << VOLUMERAMPPRECISION);
01168                                 LONG nLeftDelta = ((pChn->nNewLeftVol - pChn->nLeftVol) << VOLUMERAMPPRECISION);
01169 #ifndef FASTSOUNDLIB
01170                                 if ((gdwSoundSetup & SNDMIX_DIRECTTODISK)
01171                                  || ((gdwSysInfo & (SYSMIX_ENABLEMMX|SYSMIX_FASTCPU))
01172                                   && (gdwSoundSetup & SNDMIX_HQRESAMPLER) && (gnCPUUsage <= 20)))
01173                                 {
01174                                         if ((pChn->nRightVol|pChn->nLeftVol) && (pChn->nNewRightVol|pChn->nNewLeftVol) && (!(pChn->dwFlags & CHN_FASTVOLRAMP)))
01175                                         {
01176                                                 nRampLength = m_nBufferCount;
01177                                                 if (nRampLength > (1 << (VOLUMERAMPPRECISION-1))) nRampLength = (1 << (VOLUMERAMPPRECISION-1));
01178                                                 if (nRampLength < (LONG)gnVolumeRampSamples) nRampLength = gnVolumeRampSamples;
01179                                         }
01180                                 }
01181 #endif
01182                                 pChn->nRightRamp = nRightDelta / nRampLength;
01183                                 pChn->nLeftRamp = nLeftDelta / nRampLength;
01184                                 pChn->nRightVol = pChn->nNewRightVol - ((pChn->nRightRamp * nRampLength) >> VOLUMERAMPPRECISION);
01185                                 pChn->nLeftVol = pChn->nNewLeftVol - ((pChn->nLeftRamp * nRampLength) >> VOLUMERAMPPRECISION);
01186                                 if (pChn->nRightRamp|pChn->nLeftRamp)
01187                                 {
01188                                         pChn->nRampLength = nRampLength;
01189                                 } else
01190                                 {
01191                                         pChn->dwFlags &= ~CHN_VOLUMERAMP;
01192                                         pChn->nRightVol = pChn->nNewRightVol;
01193                                         pChn->nLeftVol = pChn->nNewLeftVol;
01194                                 }
01195                         } else
01196                         {
01197                                 pChn->dwFlags &= ~CHN_VOLUMERAMP;
01198                                 pChn->nRightVol = pChn->nNewRightVol;
01199                                 pChn->nLeftVol = pChn->nNewLeftVol;
01200                         }
01201                         pChn->nRampRightVol = pChn->nRightVol << VOLUMERAMPPRECISION;
01202                         pChn->nRampLeftVol = pChn->nLeftVol << VOLUMERAMPPRECISION;
01203                         // Adding the channel in the channel list
01204                         ChnMix[m_nMixChannels++] = nChn;
01205                         if (m_nMixChannels >= MAX_CHANNELS) break;
01206                 } else
01207                 {
01208 #ifdef ENABLE_STEREOVU
01209                         // Note change but no sample
01210                         if (pChn->nLeftVU > 128) pChn->nLeftVU = 0;
01211                         if (pChn->nRightVU > 128) pChn->nRightVU = 0;
01212 #endif
01213                         if (pChn->nVUMeter > 0xFF) pChn->nVUMeter = 0;
01214                         pChn->nLeftVol = pChn->nRightVol = 0;
01215                         pChn->nLength = 0;
01216                 }
01217         }
01218         // Checking Max Mix Channels reached: ordering by volume
01219         if ((m_nMixChannels >= m_nMaxMixChannels) && (!(gdwSoundSetup & SNDMIX_DIRECTTODISK)))
01220         {
01221                 for (UINT i=0; i<m_nMixChannels; i++)
01222                 {
01223                         UINT j=i;
01224                         while ((j+1<m_nMixChannels) && (Chn[ChnMix[j]].nRealVolume < Chn[ChnMix[j+1]].nRealVolume))
01225                         {
01226                                 UINT n = ChnMix[j];
01227                                 ChnMix[j] = ChnMix[j+1];
01228                                 ChnMix[j+1] = n;
01229                                 j++;
01230                         }
01231                 }
01232         }
01233         if (m_dwSongFlags & SONG_GLOBALFADE)
01234         {
01235                 if (!m_nGlobalFadeSamples)
01236                 {
01237                         m_dwSongFlags |= SONG_ENDREACHED;
01238                         return FALSE;
01239                 }
01240                 if (m_nGlobalFadeSamples > m_nBufferCount)
01241                         m_nGlobalFadeSamples -= m_nBufferCount;
01242                 else
01243                         m_nGlobalFadeSamples = 0;
01244         }
01245         return TRUE;
01246 }
01247 
01248 

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