author | llornkcor <llornkcor> | 2002-07-20 22:07:31 (UTC) |
---|---|---|
committer | llornkcor <llornkcor> | 2002-07-20 22:07:31 (UTC) |
commit | 2342d48be31847e7ead9d1cc682452e8f0122351 (patch) (unidiff) | |
tree | 8329bb94e9d429c905a0ef6b881cf1c0f775bf14 /core/multimedia/opieplayer/modplug/sndmix.cpp | |
parent | 0f24c1fb86d3bb58d8696358b824c0e01752b10d (diff) | |
download | opie-2342d48be31847e7ead9d1cc682452e8f0122351.zip opie-2342d48be31847e7ead9d1cc682452e8f0122351.tar.gz opie-2342d48be31847e7ead9d1cc682452e8f0122351.tar.bz2 |
initial commit of modplugin
Diffstat (limited to 'core/multimedia/opieplayer/modplug/sndmix.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | core/multimedia/opieplayer/modplug/sndmix.cpp | 1248 |
1 files changed, 1248 insertions, 0 deletions
diff --git a/core/multimedia/opieplayer/modplug/sndmix.cpp b/core/multimedia/opieplayer/modplug/sndmix.cpp new file mode 100644 index 0000000..bfc5f4a --- a/dev/null +++ b/core/multimedia/opieplayer/modplug/sndmix.cpp | |||
@@ -0,0 +1,1248 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and modify it | ||
3 | * under the terms of the GNU General Public License as published by the | ||
4 | * Free Software Foundation; either version 2 of the license or (at your | ||
5 | * option) any later version. | ||
6 | * | ||
7 | * Authors: Olivier Lapicque <olivierl@jps.net> | ||
8 | */ | ||
9 | |||
10 | #include "stdafx.h" | ||
11 | #include "sndfile.h" | ||
12 | |||
13 | #ifdef MODPLUG_TRACKER | ||
14 | #define ENABLE_STEREOVU | ||
15 | #endif | ||
16 | |||
17 | // Volume ramp length, in 1/10 ms | ||
18 | #define VOLUMERAMPLEN 146// 1.46ms = 64 samples at 44.1kHz | ||
19 | |||
20 | // VU-Meter | ||
21 | #define VUMETER_DECAY 4 | ||
22 | |||
23 | // SNDMIX: These are global flags for playback control | ||
24 | UINT CSoundFile::m_nStereoSeparation = 128; | ||
25 | LONG CSoundFile::m_nStreamVolume = 0x8000; | ||
26 | UINT CSoundFile::m_nMaxMixChannels = 32; | ||
27 | // Mixing Configuration (SetWaveConfig) | ||
28 | DWORD CSoundFile::gdwSysInfo = 0; | ||
29 | DWORD CSoundFile::gnChannels = 1; | ||
30 | DWORD CSoundFile::gdwSoundSetup = 0; | ||
31 | DWORD CSoundFile::gdwMixingFreq = 44100; | ||
32 | DWORD CSoundFile::gnBitsPerSample = 16; | ||
33 | // Mixing data initialized in | ||
34 | UINT CSoundFile::gnAGC = AGC_UNITY; | ||
35 | UINT CSoundFile::gnVolumeRampSamples = 64; | ||
36 | UINT CSoundFile::gnVUMeter = 0; | ||
37 | UINT CSoundFile::gnCPUUsage = 0; | ||
38 | LPSNDMIXHOOKPROC CSoundFile::gpSndMixHook = NULL; | ||
39 | PMIXPLUGINCREATEPROC CSoundFile::gpMixPluginCreateProc = NULL; | ||
40 | LONG gnDryROfsVol = 0; | ||
41 | LONG gnDryLOfsVol = 0; | ||
42 | LONG gnRvbROfsVol = 0; | ||
43 | LONG gnRvbLOfsVol = 0; | ||
44 | int gbInitPlugins = 0; | ||
45 | |||
46 | typedef DWORD (MPPASMCALL * LPCONVERTPROC)(LPVOID, int *, DWORD, LPLONG, LPLONG); | ||
47 | |||
48 | extern DWORD MPPASMCALL X86_Convert32To8(LPVOID lpBuffer, int *, DWORD nSamples, LPLONG, LPLONG); | ||
49 | extern DWORD MPPASMCALL X86_Convert32To16(LPVOID lpBuffer, int *, DWORD nSamples, LPLONG, LPLONG); | ||
50 | extern DWORD MPPASMCALL X86_Convert32To24(LPVOID lpBuffer, int *, DWORD nSamples, LPLONG, LPLONG); | ||
51 | extern DWORD MPPASMCALL X86_Convert32To32(LPVOID lpBuffer, int *, DWORD nSamples, LPLONG, LPLONG); | ||
52 | extern UINT MPPASMCALL X86_AGC(int *pBuffer, UINT nSamples, UINT nAGC); | ||
53 | extern VOID MPPASMCALL X86_Dither(int *pBuffer, UINT nSamples, UINT nBits); | ||
54 | extern VOID MPPASMCALL X86_InterleaveFrontRear(int *pFrontBuf, int *pRearBuf, DWORD nSamples); | ||
55 | extern VOID MPPASMCALL X86_StereoFill(int *pBuffer, UINT nSamples, LPLONG lpROfs, LPLONG lpLOfs); | ||
56 | extern VOID MPPASMCALL X86_MonoFromStereo(int *pMixBuf, UINT nSamples); | ||
57 | |||
58 | extern const short int ModSinusTable[64]; | ||
59 | extern const short int ModRampDownTable[64]; | ||
60 | extern const short int ModSquareTable[64]; | ||
61 | extern const short int ModRandomTable[64]; | ||
62 | extern const DWORD LinearSlideUpTable[256]; | ||
63 | extern const DWORD LinearSlideDownTable[256]; | ||
64 | extern const DWORD FineLinearSlideUpTable[16]; | ||
65 | extern const DWORD FineLinearSlideDownTable[16]; | ||
66 | extern const signed char ft2VibratoTable[256];// -64 .. +64 | ||
67 | extern int MixSoundBuffer[MIXBUFFERSIZE*4]; | ||
68 | extern int MixRearBuffer[MIXBUFFERSIZE*2]; | ||
69 | UINT gnReverbSend; | ||
70 | |||
71 | |||
72 | // Log tables for pre-amp | ||
73 | // We don't want the tracker to get too loud | ||
74 | const UINT PreAmpTable[16] = | ||
75 | { | ||
76 | 0x60, 0x60, 0x60, 0x70,// 0-7 | ||
77 | 0x80, 0x88, 0x90, 0x98,// 8-15 | ||
78 | 0xA0, 0xA4, 0xA8, 0xB0,// 16-23 | ||
79 | 0xB4, 0xB8, 0xBC, 0xC0,// 24-31 | ||
80 | }; | ||
81 | |||
82 | const UINT PreAmpAGCTable[16] = | ||
83 | { | ||
84 | 0x60, 0x60, 0x60, 0x60, | ||
85 | 0x68, 0x70, 0x78, 0x80, | ||
86 | 0x84, 0x88, 0x8C, 0x90, | ||
87 | 0x94, 0x98, 0x9C, 0xA0, | ||
88 | }; | ||
89 | |||
90 | |||
91 | // Return (a*b)/c - no divide error | ||
92 | int _muldiv(long a, long b, long c) | ||
93 | { | ||
94 | #ifdef WIN32 | ||
95 | int sign, result; | ||
96 | _asm { | ||
97 | mov eax, a | ||
98 | mov ebx, b | ||
99 | or eax, eax | ||
100 | mov edx, eax | ||
101 | jge aneg | ||
102 | neg eax | ||
103 | aneg: | ||
104 | xor edx, ebx | ||
105 | or ebx, ebx | ||
106 | mov ecx, c | ||
107 | jge bneg | ||
108 | neg ebx | ||
109 | bneg: | ||
110 | xor edx, ecx | ||
111 | or ecx, ecx | ||
112 | mov sign, edx | ||
113 | jge cneg | ||
114 | neg ecx | ||
115 | cneg: | ||
116 | mul ebx | ||
117 | cmp edx, ecx | ||
118 | jae diverr | ||
119 | div ecx | ||
120 | jmp ok | ||
121 | diverr: | ||
122 | mov eax, 0x7fffffff | ||
123 | ok: | ||
124 | mov edx, sign | ||
125 | or edx, edx | ||
126 | jge rneg | ||
127 | neg eax | ||
128 | rneg: | ||
129 | mov result, eax | ||
130 | } | ||
131 | return result; | ||
132 | #else | ||
133 | return ((unsigned long long) a * (unsigned long long) b ) / c; | ||
134 | #endif | ||
135 | } | ||
136 | |||
137 | |||
138 | // Return (a*b+c/2)/c - no divide error | ||
139 | int _muldivr(long a, long b, long c) | ||
140 | { | ||
141 | #ifdef WIN32 | ||
142 | int sign, result; | ||
143 | _asm { | ||
144 | mov eax, a | ||
145 | mov ebx, b | ||
146 | or eax, eax | ||
147 | mov edx, eax | ||
148 | jge aneg | ||
149 | neg eax | ||
150 | aneg: | ||
151 | xor edx, ebx | ||
152 | or ebx, ebx | ||
153 | mov ecx, c | ||
154 | jge bneg | ||
155 | neg ebx | ||
156 | bneg: | ||
157 | xor edx, ecx | ||
158 | or ecx, ecx | ||
159 | mov sign, edx | ||
160 | jge cneg | ||
161 | neg ecx | ||
162 | cneg: | ||
163 | mul ebx | ||
164 | mov ebx, ecx | ||
165 | shr ebx, 1 | ||
166 | add eax, ebx | ||
167 | adc edx, 0 | ||
168 | cmp edx, ecx | ||
169 | jae diverr | ||
170 | div ecx | ||
171 | jmp ok | ||
172 | diverr: | ||
173 | mov eax, 0x7fffffff | ||
174 | ok: | ||
175 | mov edx, sign | ||
176 | or edx, edx | ||
177 | jge rneg | ||
178 | neg eax | ||
179 | rneg: | ||
180 | mov result, eax | ||
181 | } | ||
182 | return result; | ||
183 | #else | ||
184 | return ((unsigned long long) a * (unsigned long long) b + (c >> 1)) / c; | ||
185 | #endif | ||
186 | } | ||
187 | |||
188 | |||
189 | BOOL CSoundFile::InitPlayer(BOOL bReset) | ||
190 | //-------------------------------------- | ||
191 | { | ||
192 | if (m_nMaxMixChannels > MAX_CHANNELS) m_nMaxMixChannels = MAX_CHANNELS; | ||
193 | if (gdwMixingFreq < 4000) gdwMixingFreq = 4000; | ||
194 | if (gdwMixingFreq > MAX_SAMPLE_RATE) gdwMixingFreq = MAX_SAMPLE_RATE; | ||
195 | gnVolumeRampSamples = (gdwMixingFreq * VOLUMERAMPLEN) / 100000; | ||
196 | if (gnVolumeRampSamples < 8) gnVolumeRampSamples = 8; | ||
197 | gnDryROfsVol = gnDryLOfsVol = 0; | ||
198 | gnRvbROfsVol = gnRvbLOfsVol = 0; | ||
199 | if (bReset) | ||
200 | { | ||
201 | gnVUMeter = 0; | ||
202 | gnCPUUsage = 0; | ||
203 | } | ||
204 | gbInitPlugins = (bReset) ? 3 : 1; | ||
205 | InitializeDSP(bReset); | ||
206 | return TRUE; | ||
207 | } | ||
208 | |||
209 | |||
210 | BOOL CSoundFile::FadeSong(UINT msec) | ||
211 | //---------------------------------- | ||
212 | { | ||
213 | LONG nsamples = _muldiv(msec, gdwMixingFreq, 1000); | ||
214 | if (nsamples <= 0) return FALSE; | ||
215 | if (nsamples > 0x100000) nsamples = 0x100000; | ||
216 | m_nBufferCount = nsamples; | ||
217 | LONG nRampLength = m_nBufferCount; | ||
218 | // Ramp everything down | ||
219 | for (UINT noff=0; noff < m_nMixChannels; noff++) | ||
220 | { | ||
221 | MODCHANNEL *pramp = &Chn[ChnMix[noff]]; | ||
222 | if (!pramp) continue; | ||
223 | pramp->nNewLeftVol = pramp->nNewRightVol = 0; | ||
224 | pramp->nRightRamp = (-pramp->nRightVol << VOLUMERAMPPRECISION) / nRampLength; | ||
225 | pramp->nLeftRamp = (-pramp->nLeftVol << VOLUMERAMPPRECISION) / nRampLength; | ||
226 | pramp->nRampRightVol = pramp->nRightVol << VOLUMERAMPPRECISION; | ||
227 | pramp->nRampLeftVol = pramp->nLeftVol << VOLUMERAMPPRECISION; | ||
228 | pramp->nRampLength = nRampLength; | ||
229 | pramp->dwFlags |= CHN_VOLUMERAMP; | ||
230 | } | ||
231 | m_dwSongFlags |= SONG_FADINGSONG; | ||
232 | return TRUE; | ||
233 | } | ||
234 | |||
235 | |||
236 | BOOL CSoundFile::GlobalFadeSong(UINT msec) | ||
237 | //---------------------------------------- | ||
238 | { | ||
239 | if (m_dwSongFlags & SONG_GLOBALFADE) return FALSE; | ||
240 | m_nGlobalFadeMaxSamples = _muldiv(msec, gdwMixingFreq, 1000); | ||
241 | m_nGlobalFadeSamples = m_nGlobalFadeMaxSamples; | ||
242 | m_dwSongFlags |= SONG_GLOBALFADE; | ||
243 | return TRUE; | ||
244 | } | ||
245 | |||
246 | |||
247 | UINT CSoundFile::Read(LPVOID lpDestBuffer, UINT cbBuffer) | ||
248 | //------------------------------------------------------- | ||
249 | { | ||
250 | LPBYTE lpBuffer = (LPBYTE)lpDestBuffer; | ||
251 | LPCONVERTPROC pCvt = X86_Convert32To8; | ||
252 | UINT lRead, lMax, lSampleSize, lCount, lSampleCount, nStat=0; | ||
253 | LONG nVUMeterMin = 0x7FFFFFFF, nVUMeterMax = -0x7FFFFFFF; | ||
254 | UINT nMaxPlugins; | ||
255 | |||
256 | { | ||
257 | nMaxPlugins = MAX_MIXPLUGINS; | ||
258 | while ((nMaxPlugins > 0) && (!m_MixPlugins[nMaxPlugins-1].pMixPlugin)) nMaxPlugins--; | ||
259 | } | ||
260 | m_nMixStat = 0; | ||
261 | lSampleSize = gnChannels; | ||
262 | if (gnBitsPerSample == 16) { lSampleSize *= 2; pCvt = X86_Convert32To16; } | ||
263 | #ifndef FASTSOUNDLIB | ||
264 | else if (gnBitsPerSample == 24) { lSampleSize *= 3; pCvt = X86_Convert32To24; } | ||
265 | else if (gnBitsPerSample == 32) { lSampleSize *= 4; pCvt = X86_Convert32To32; } | ||
266 | #endif | ||
267 | lMax = cbBuffer / lSampleSize; | ||
268 | if ((!lMax) || (!lpBuffer) || (!m_nChannels)) return 0; | ||
269 | lRead = lMax; | ||
270 | if (m_dwSongFlags & SONG_ENDREACHED) goto MixDone; | ||
271 | while (lRead > 0) | ||
272 | { | ||
273 | // Update Channel Data | ||
274 | if (!m_nBufferCount) | ||
275 | { | ||
276 | #ifndef FASTSOUNDLIB | ||
277 | if (m_dwSongFlags & SONG_FADINGSONG) | ||
278 | { | ||
279 | m_dwSongFlags |= SONG_ENDREACHED; | ||
280 | m_nBufferCount = lRead; | ||
281 | } else | ||
282 | #endif | ||
283 | if (!ReadNote()) | ||
284 | { | ||
285 | #ifndef FASTSOUNDLIB | ||
286 | if (!FadeSong(FADESONGDELAY)) | ||
287 | #endif | ||
288 | { | ||
289 | m_dwSongFlags |= SONG_ENDREACHED; | ||
290 | if (lRead == lMax) goto MixDone; | ||
291 | m_nBufferCount = lRead; | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | lCount = m_nBufferCount; | ||
296 | if (lCount > MIXBUFFERSIZE) lCount = MIXBUFFERSIZE; | ||
297 | if (lCount > lRead) lCount = lRead; | ||
298 | if (!lCount) break; | ||
299 | lSampleCount = lCount; | ||
300 | #ifndef NO_REVERB | ||
301 | gnReverbSend = 0; | ||
302 | #endif | ||
303 | // Resetting sound buffer | ||
304 | X86_StereoFill(MixSoundBuffer, lSampleCount, &gnDryROfsVol, &gnDryLOfsVol); | ||
305 | if (gnChannels >= 2) | ||
306 | { | ||
307 | lSampleCount *= 2; | ||
308 | m_nMixStat += CreateStereoMix(lCount); | ||
309 | ProcessStereoDSP(lCount); | ||
310 | } else | ||
311 | { | ||
312 | m_nMixStat += CreateStereoMix(lCount); | ||
313 | if (nMaxPlugins) ProcessPlugins(lCount); | ||
314 | ProcessStereoDSP(lCount); | ||
315 | X86_MonoFromStereo(MixSoundBuffer, lCount); | ||
316 | } | ||
317 | nStat++; | ||
318 | #ifndef NO_AGC | ||
319 | // Automatic Gain Control | ||
320 | if (gdwSoundSetup & SNDMIX_AGC) ProcessAGC(lSampleCount); | ||
321 | #endif | ||
322 | UINT lTotalSampleCount = lSampleCount; | ||
323 | #ifndef FASTSOUNDLIB | ||
324 | // Multichannel | ||
325 | if (gnChannels > 2) | ||
326 | { | ||
327 | X86_InterleaveFrontRear(MixSoundBuffer, MixRearBuffer, lSampleCount); | ||
328 | lTotalSampleCount *= 2; | ||
329 | } | ||
330 | // Hook Function | ||
331 | if (gpSndMixHook) | ||
332 | { | ||
333 | gpSndMixHook(MixSoundBuffer, lTotalSampleCount, gnChannels); | ||
334 | } | ||
335 | #endif | ||
336 | // Perform clipping + VU-Meter | ||
337 | lpBuffer += pCvt(lpBuffer, MixSoundBuffer, lTotalSampleCount, &nVUMeterMin, &nVUMeterMax); | ||
338 | // Buffer ready | ||
339 | lRead -= lCount; | ||
340 | m_nBufferCount -= lCount; | ||
341 | } | ||
342 | MixDone: | ||
343 | if (lRead) memset(lpBuffer, (gnBitsPerSample == 8) ? 0x80 : 0, lRead * lSampleSize); | ||
344 | // VU-Meter | ||
345 | nVUMeterMin >>= (24-MIXING_ATTENUATION); | ||
346 | nVUMeterMax >>= (24-MIXING_ATTENUATION); | ||
347 | if (nVUMeterMax < nVUMeterMin) nVUMeterMax = nVUMeterMin; | ||
348 | if ((gnVUMeter = (UINT)(nVUMeterMax - nVUMeterMin)) > 0xFF) gnVUMeter = 0xFF; | ||
349 | if (nStat) { m_nMixStat += nStat-1; m_nMixStat /= nStat; } | ||
350 | return lMax - lRead; | ||
351 | } | ||
352 | |||
353 | |||
354 | |||
355 | ///////////////////////////////////////////////////////////////////////////// | ||
356 | // Handles navigation/effects | ||
357 | |||
358 | BOOL CSoundFile::ProcessRow() | ||
359 | //--------------------------- | ||
360 | { | ||
361 | if (++m_nTickCount >= m_nMusicSpeed * (m_nPatternDelay+1) + m_nFrameDelay) | ||
362 | { | ||
363 | m_nPatternDelay = 0; | ||
364 | m_nFrameDelay = 0; | ||
365 | m_nTickCount = 0; | ||
366 | m_nRow = m_nNextRow; | ||
367 | // Reset Pattern Loop Effect | ||
368 | if (m_nCurrentPattern != m_nNextPattern) m_nCurrentPattern = m_nNextPattern; | ||
369 | // Check if pattern is valid | ||
370 | if (!(m_dwSongFlags & SONG_PATTERNLOOP)) | ||
371 | { | ||
372 | m_nPattern = (m_nCurrentPattern < MAX_ORDERS) ? Order[m_nCurrentPattern] : 0xFF; | ||
373 | if ((m_nPattern < MAX_PATTERNS) && (!Patterns[m_nPattern])) m_nPattern = 0xFE; | ||
374 | while (m_nPattern >= MAX_PATTERNS) | ||
375 | { | ||
376 | // End of song ? | ||
377 | if ((m_nPattern == 0xFF) || (m_nCurrentPattern >= MAX_ORDERS)) | ||
378 | { | ||
379 | //if (!m_nRepeatCount) | ||
380 | return FALSE; //never repeat entire song | ||
381 | if (!m_nRestartPos) | ||
382 | { | ||
383 | m_nMusicSpeed = m_nDefaultSpeed; | ||
384 | m_nMusicTempo = m_nDefaultTempo; | ||
385 | m_nGlobalVolume = m_nDefaultGlobalVolume; | ||
386 | for (UINT i=0; i<MAX_CHANNELS; i++) | ||
387 | { | ||
388 | Chn[i].dwFlags |= CHN_NOTEFADE | CHN_KEYOFF; | ||
389 | Chn[i].nFadeOutVol = 0; | ||
390 | if (i < m_nChannels) | ||
391 | { | ||
392 | Chn[i].nGlobalVol = ChnSettings[i].nVolume; | ||
393 | Chn[i].nVolume = ChnSettings[i].nVolume; | ||
394 | Chn[i].nPan = ChnSettings[i].nPan; | ||
395 | Chn[i].nPanSwing = Chn[i].nVolSwing = 0; | ||
396 | Chn[i].nOldVolParam = 0; | ||
397 | Chn[i].nOldOffset = 0; | ||
398 | Chn[i].nOldHiOffset = 0; | ||
399 | Chn[i].nPortamentoDest = 0; | ||
400 | if (!Chn[i].nLength) | ||
401 | { | ||
402 | Chn[i].dwFlags = ChnSettings[i].dwFlags; | ||
403 | Chn[i].nLoopStart = 0; | ||
404 | Chn[i].nLoopEnd = 0; | ||
405 | Chn[i].pHeader = NULL; | ||
406 | Chn[i].pSample = NULL; | ||
407 | Chn[i].pInstrument = NULL; | ||
408 | } | ||
409 | } | ||
410 | } | ||
411 | } | ||
412 | // if (m_nRepeatCount > 0) m_nRepeatCount--; | ||
413 | m_nCurrentPattern = m_nRestartPos; | ||
414 | m_nRow = 0; | ||
415 | if ((Order[m_nCurrentPattern] >= MAX_PATTERNS) || (!Patterns[Order[m_nCurrentPattern]])) return FALSE; | ||
416 | } else | ||
417 | { | ||
418 | m_nCurrentPattern++; | ||
419 | } | ||
420 | m_nPattern = (m_nCurrentPattern < MAX_ORDERS) ? Order[m_nCurrentPattern] : 0xFF; | ||
421 | if ((m_nPattern < MAX_PATTERNS) && (!Patterns[m_nPattern])) m_nPattern = 0xFE; | ||
422 | } | ||
423 | m_nNextPattern = m_nCurrentPattern; | ||
424 | } | ||
425 | // Weird stuff? | ||
426 | if ((m_nPattern >= MAX_PATTERNS) || (!Patterns[m_nPattern])) return FALSE; | ||
427 | // Should never happen | ||
428 | if (m_nRow >= PatternSize[m_nPattern]) m_nRow = 0; | ||
429 | m_nNextRow = m_nRow + 1; | ||
430 | if (m_nNextRow >= PatternSize[m_nPattern]) | ||
431 | { | ||
432 | if (!(m_dwSongFlags & SONG_PATTERNLOOP)) m_nNextPattern = m_nCurrentPattern + 1; | ||
433 | m_nNextRow = 0; | ||
434 | } | ||
435 | // Reset channel values | ||
436 | MODCHANNEL *pChn = Chn; | ||
437 | MODCOMMAND *m = Patterns[m_nPattern] + m_nRow * m_nChannels; | ||
438 | for (UINT nChn=0; nChn<m_nChannels; pChn++, nChn++, m++) | ||
439 | { | ||
440 | pChn->nRowNote = m->note; | ||
441 | pChn->nRowInstr = m->instr; | ||
442 | pChn->nRowVolCmd = m->volcmd; | ||
443 | pChn->nRowVolume = m->vol; | ||
444 | pChn->nRowCommand = m->command; | ||
445 | pChn->nRowParam = m->param; | ||
446 | |||
447 | pChn->nLeftVol = pChn->nNewLeftVol; | ||
448 | pChn->nRightVol = pChn->nNewRightVol; | ||
449 | pChn->dwFlags &= ~(CHN_PORTAMENTO | CHN_VIBRATO | CHN_TREMOLO | CHN_PANBRELLO); | ||
450 | pChn->nCommand = 0; | ||
451 | } | ||
452 | } | ||
453 | // Should we process tick0 effects? | ||
454 | if (!m_nMusicSpeed) m_nMusicSpeed = 1; | ||
455 | m_dwSongFlags |= SONG_FIRSTTICK; | ||
456 | if (m_nTickCount) | ||
457 | { | ||
458 | m_dwSongFlags &= ~SONG_FIRSTTICK; | ||
459 | if ((!(m_nType & MOD_TYPE_XM)) && (m_nTickCount < m_nMusicSpeed * (1 + m_nPatternDelay))) | ||
460 | { | ||
461 | if (!(m_nTickCount % m_nMusicSpeed)) m_dwSongFlags |= SONG_FIRSTTICK; | ||
462 | } | ||
463 | |||
464 | } | ||
465 | // Update Effects | ||
466 | return ProcessEffects(); | ||
467 | } | ||
468 | |||
469 | |||
470 | //////////////////////////////////////////////////////////////////////////////////////////// | ||
471 | // Handles envelopes & mixer setup | ||
472 | |||
473 | BOOL CSoundFile::ReadNote() | ||
474 | //------------------------- | ||
475 | { | ||
476 | if (!ProcessRow()) return FALSE; | ||
477 | //////////////////////////////////////////////////////////////////////////////////// | ||
478 | m_nTotalCount++; | ||
479 | if (!m_nMusicTempo) return FALSE; | ||
480 | m_nBufferCount = (gdwMixingFreq * 5 * m_nTempoFactor) / (m_nMusicTempo << 8); | ||
481 | // Master Volume + Pre-Amplification / Attenuation setup | ||
482 | DWORD nMasterVol; | ||
483 | { | ||
484 | int nchn32 = (m_nChannels < 32) ? m_nChannels : 31; | ||
485 | if ((m_nType & MOD_TYPE_IT) && (m_nInstruments) && (nchn32 < 6)) nchn32 = 6; | ||
486 | int realmastervol = m_nMasterVolume; | ||
487 | if (realmastervol > 0x80) | ||
488 | { | ||
489 | realmastervol = 0x80 + ((realmastervol - 0x80) * (nchn32+4)) / 16; | ||
490 | } | ||
491 | UINT attenuation = (gdwSoundSetup & SNDMIX_AGC) ? PreAmpAGCTable[nchn32>>1] : PreAmpTable[nchn32>>1]; | ||
492 | DWORD mastervol = (realmastervol * (m_nSongPreAmp + 0x10)) >> 6; | ||
493 | if (mastervol > 0x200) mastervol = 0x200; | ||
494 | if ((m_dwSongFlags & SONG_GLOBALFADE) && (m_nGlobalFadeMaxSamples)) | ||
495 | { | ||
496 | mastervol = _muldiv(mastervol, m_nGlobalFadeSamples, m_nGlobalFadeMaxSamples); | ||
497 | } | ||
498 | nMasterVol = (mastervol << 7) / attenuation; | ||
499 | if (nMasterVol > 0x180) nMasterVol = 0x180; | ||
500 | } | ||
501 | //////////////////////////////////////////////////////////////////////////////////// | ||
502 | // Update channels data | ||
503 | m_nMixChannels = 0; | ||
504 | MODCHANNEL *pChn = Chn; | ||
505 | for (UINT nChn=0; nChn<MAX_CHANNELS; nChn++,pChn++) | ||
506 | { | ||
507 | if ((pChn->dwFlags & CHN_NOTEFADE) && (!(pChn->nFadeOutVol|pChn->nRightVol|pChn->nLeftVol))) | ||
508 | { | ||
509 | pChn->nLength = 0; | ||
510 | pChn->nROfs = pChn->nLOfs = 0; | ||
511 | } | ||
512 | // Check for unused channel | ||
513 | if ((pChn->dwFlags & CHN_MUTE) || ((nChn >= m_nChannels) && (!pChn->nLength))) | ||
514 | { | ||
515 | pChn->nVUMeter = 0; | ||
516 | #ifdef ENABLE_STEREOVU | ||
517 | pChn->nLeftVU = pChn->nRightVU = 0; | ||
518 | #endif | ||
519 | continue; | ||
520 | } | ||
521 | // Reset channel data | ||
522 | pChn->nInc = 0; | ||
523 | pChn->nRealVolume = 0; | ||
524 | pChn->nRealPan = pChn->nPan + pChn->nPanSwing; | ||
525 | if (pChn->nRealPan < 0) pChn->nRealPan = 0; | ||
526 | if (pChn->nRealPan > 256) pChn->nRealPan = 256; | ||
527 | pChn->nRampLength = 0; | ||
528 | // Calc Frequency | ||
529 | if ((pChn->nPeriod)&& (pChn->nLength)) | ||
530 | { | ||
531 | int vol = pChn->nVolume + pChn->nVolSwing; | ||
532 | |||
533 | if (vol < 0) vol = 0; | ||
534 | if (vol > 256) vol = 256; | ||
535 | // Tremolo | ||
536 | if (pChn->dwFlags & CHN_TREMOLO) | ||
537 | { | ||
538 | UINT trempos = pChn->nTremoloPos & 0x3F; | ||
539 | if (vol > 0) | ||
540 | { | ||
541 | int tremattn = (m_nType & MOD_TYPE_XM) ? 5 : 6; | ||
542 | switch (pChn->nTremoloType & 0x03) | ||
543 | { | ||
544 | case 1: | ||
545 | vol += (ModRampDownTable[trempos] * (int)pChn->nTremoloDepth) >> tremattn; | ||
546 | break; | ||
547 | case 2: | ||
548 | vol += (ModSquareTable[trempos] * (int)pChn->nTremoloDepth) >> tremattn; | ||
549 | break; | ||
550 | case 3: | ||
551 | vol += (ModRandomTable[trempos] * (int)pChn->nTremoloDepth) >> tremattn; | ||
552 | break; | ||
553 | default: | ||
554 | vol += (ModSinusTable[trempos] * (int)pChn->nTremoloDepth) >> tremattn; | ||
555 | } | ||
556 | } | ||
557 | if ((m_nTickCount) || ((m_nType & (MOD_TYPE_STM|MOD_TYPE_S3M|MOD_TYPE_IT)) && (!(m_dwSongFlags & SONG_ITOLDEFFECTS)))) | ||
558 | { | ||
559 | pChn->nTremoloPos = (trempos + pChn->nTremoloSpeed) & 0x3F; | ||
560 | } | ||
561 | } | ||
562 | // Tremor | ||
563 | if (pChn->nCommand == CMD_TREMOR) | ||
564 | { | ||
565 | UINT n = (pChn->nTremorParam >> 4) + (pChn->nTremorParam & 0x0F); | ||
566 | UINT ontime = pChn->nTremorParam >> 4; | ||
567 | if ((!(m_nType & MOD_TYPE_IT)) || (m_dwSongFlags & SONG_ITOLDEFFECTS)) { n += 2; ontime++; } | ||
568 | UINT tremcount = (UINT)pChn->nTremorCount; | ||
569 | if (tremcount >= n) tremcount = 0; | ||
570 | if ((m_nTickCount) || (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))) | ||
571 | { | ||
572 | if (tremcount >= ontime) vol = 0; | ||
573 | pChn->nTremorCount = (BYTE)(tremcount + 1); | ||
574 | } | ||
575 | pChn->dwFlags |= CHN_FASTVOLRAMP; | ||
576 | } | ||
577 | // Clip volume | ||
578 | if (vol < 0) vol = 0; | ||
579 | if (vol > 0x100) vol = 0x100; | ||
580 | vol <<= 6; | ||
581 | // Process Envelopes | ||
582 | if (pChn->pHeader) | ||
583 | { | ||
584 | INSTRUMENTHEADER *penv = pChn->pHeader; | ||
585 | // Volume Envelope | ||
586 | if ((pChn->dwFlags & CHN_VOLENV) && (penv->nVolEnv)) | ||
587 | { | ||
588 | int envpos = pChn->nVolEnvPosition; | ||
589 | UINT pt = penv->nVolEnv - 1; | ||
590 | for (UINT i=0; i<(UINT)(penv->nVolEnv-1); i++) | ||
591 | { | ||
592 | if (envpos <= penv->VolPoints[i]) | ||
593 | { | ||
594 | pt = i; | ||
595 | break; | ||
596 | } | ||
597 | } | ||
598 | int x2 = penv->VolPoints[pt]; | ||
599 | int x1, envvol; | ||
600 | if (envpos >= x2) | ||
601 | { | ||
602 | envvol = penv->VolEnv[pt] << 2; | ||
603 | x1 = x2; | ||
604 | } else | ||
605 | if (pt) | ||
606 | { | ||
607 | envvol = penv->VolEnv[pt-1] << 2; | ||
608 | x1 = penv->VolPoints[pt-1]; | ||
609 | } else | ||
610 | { | ||
611 | envvol = 0; | ||
612 | x1 = 0; | ||
613 | } | ||
614 | if (envpos > x2) envpos = x2; | ||
615 | if ((x2 > x1) && (envpos > x1)) | ||
616 | { | ||
617 | envvol += ((envpos - x1) * (((int)penv->VolEnv[pt]<<2) - envvol)) / (x2 - x1); | ||
618 | } | ||
619 | if (envvol < 0) envvol = 0; | ||
620 | if (envvol > 256) envvol = 256; | ||
621 | vol = (vol * envvol) >> 8; | ||
622 | } | ||
623 | // Panning Envelope | ||
624 | if ((pChn->dwFlags & CHN_PANENV) && (penv->nPanEnv)) | ||
625 | { | ||
626 | int envpos = pChn->nPanEnvPosition; | ||
627 | UINT pt = penv->nPanEnv - 1; | ||
628 | for (UINT i=0; i<(UINT)(penv->nPanEnv-1); i++) | ||
629 | { | ||
630 | if (envpos <= penv->PanPoints[i]) | ||
631 | { | ||
632 | pt = i; | ||
633 | break; | ||
634 | } | ||
635 | } | ||
636 | int x2 = penv->PanPoints[pt], y2 = penv->PanEnv[pt]; | ||
637 | int x1, envpan; | ||
638 | if (envpos >= x2) | ||
639 | { | ||
640 | envpan = y2; | ||
641 | x1 = x2; | ||
642 | } else | ||
643 | if (pt) | ||
644 | { | ||
645 | envpan = penv->PanEnv[pt-1]; | ||
646 | x1 = penv->PanPoints[pt-1]; | ||
647 | } else | ||
648 | { | ||
649 | envpan = 128; | ||
650 | x1 = 0; | ||
651 | } | ||
652 | if ((x2 > x1) && (envpos > x1)) | ||
653 | { | ||
654 | envpan += ((envpos - x1) * (y2 - envpan)) / (x2 - x1); | ||
655 | } | ||
656 | if (envpan < 0) envpan = 0; | ||
657 | if (envpan > 64) envpan = 64; | ||
658 | int pan = pChn->nPan; | ||
659 | if (pan >= 128) | ||
660 | { | ||
661 | pan += ((envpan - 32) * (256 - pan)) / 32; | ||
662 | } else | ||
663 | { | ||
664 | pan += ((envpan - 32) * (pan)) / 32; | ||
665 | } | ||
666 | if (pan < 0) pan = 0; | ||
667 | if (pan > 256) pan = 256; | ||
668 | pChn->nRealPan = pan; | ||
669 | } | ||
670 | // FadeOut volume | ||
671 | if (pChn->dwFlags & CHN_NOTEFADE) | ||
672 | { | ||
673 | UINT fadeout = penv->nFadeOut; | ||
674 | if (fadeout) | ||
675 | { | ||
676 | pChn->nFadeOutVol -= fadeout << 1; | ||
677 | if (pChn->nFadeOutVol <= 0) pChn->nFadeOutVol = 0; | ||
678 | vol = (vol * pChn->nFadeOutVol) >> 16; | ||
679 | } else | ||
680 | if (!pChn->nFadeOutVol) | ||
681 | { | ||
682 | vol = 0; | ||
683 | } | ||
684 | } | ||
685 | // Pitch/Pan separation | ||
686 | if ((penv->nPPS) && (pChn->nRealPan) && (pChn->nNote)) | ||
687 | { | ||
688 | int pandelta = (int)pChn->nRealPan + (int)((int)(pChn->nNote - penv->nPPC - 1) * (int)penv->nPPS) / (int)8; | ||
689 | if (pandelta < 0) pandelta = 0; | ||
690 | if (pandelta > 256) pandelta = 256; | ||
691 | pChn->nRealPan = pandelta; | ||
692 | } | ||
693 | } else | ||
694 | { | ||
695 | // No Envelope: key off => note cut | ||
696 | if (pChn->dwFlags & CHN_NOTEFADE) // 1.41-: CHN_KEYOFF|CHN_NOTEFADE | ||
697 | { | ||
698 | pChn->nFadeOutVol = 0; | ||
699 | vol = 0; | ||
700 | } | ||
701 | } | ||
702 | // vol is 14-bits | ||
703 | if (vol) | ||
704 | { | ||
705 | // IMPORTANT: pChn->nRealVolume is 14 bits !!! | ||
706 | // -> _muldiv( 14+8, 6+6, 18); => RealVolume: 14-bit result (22+12-20) | ||
707 | pChn->nRealVolume = _muldiv(vol * m_nGlobalVolume, pChn->nGlobalVol * pChn->nInsVol, 1 << 20); | ||
708 | } | ||
709 | if (pChn->nPeriod < m_nMinPeriod) pChn->nPeriod = m_nMinPeriod; | ||
710 | int period = pChn->nPeriod; | ||
711 | if ((pChn->dwFlags & (CHN_GLISSANDO|CHN_PORTAMENTO)) ==(CHN_GLISSANDO|CHN_PORTAMENTO)) | ||
712 | { | ||
713 | period = GetPeriodFromNote(GetNoteFromPeriod(period), pChn->nFineTune, pChn->nC4Speed); | ||
714 | } | ||
715 | |||
716 | // Arpeggio ? | ||
717 | if (pChn->nCommand == CMD_ARPEGGIO) | ||
718 | { | ||
719 | switch(m_nTickCount % 3) | ||
720 | { | ||
721 | case 1:period = GetPeriodFromNote(pChn->nNote + (pChn->nArpeggio >> 4), pChn->nFineTune, pChn->nC4Speed); break; | ||
722 | case 2:period = GetPeriodFromNote(pChn->nNote + (pChn->nArpeggio & 0x0F), pChn->nFineTune, pChn->nC4Speed); break; | ||
723 | } | ||
724 | } | ||
725 | |||
726 | if (m_dwSongFlags & SONG_AMIGALIMITS) | ||
727 | { | ||
728 | if (period < 113*4) period = 113*4; | ||
729 | if (period > 856*4) period = 856*4; | ||
730 | } | ||
731 | |||
732 | // Pitch/Filter Envelope | ||
733 | if ((pChn->pHeader) && (pChn->dwFlags & CHN_PITCHENV) && (pChn->pHeader->nPitchEnv)) | ||
734 | { | ||
735 | INSTRUMENTHEADER *penv = pChn->pHeader; | ||
736 | int envpos = pChn->nPitchEnvPosition; | ||
737 | UINT pt = penv->nPitchEnv - 1; | ||
738 | for (UINT i=0; i<(UINT)(penv->nPitchEnv-1); i++) | ||
739 | { | ||
740 | if (envpos <= penv->PitchPoints[i]) | ||
741 | { | ||
742 | pt = i; | ||
743 | break; | ||
744 | } | ||
745 | } | ||
746 | int x2 = penv->PitchPoints[pt]; | ||
747 | int x1, envpitch; | ||
748 | if (envpos >= x2) | ||
749 | { | ||
750 | envpitch = (((int)penv->PitchEnv[pt]) - 32) * 8; | ||
751 | x1 = x2; | ||
752 | } else | ||
753 | if (pt) | ||
754 | { | ||
755 | envpitch = (((int)penv->PitchEnv[pt-1]) - 32) * 8; | ||
756 | x1 = penv->PitchPoints[pt-1]; | ||
757 | } else | ||
758 | { | ||
759 | envpitch = 0; | ||
760 | x1 = 0; | ||
761 | } | ||
762 | if (envpos > x2) envpos = x2; | ||
763 | if ((x2 > x1) && (envpos > x1)) | ||
764 | { | ||
765 | int envpitchdest = (((int)penv->PitchEnv[pt]) - 32) * 8; | ||
766 | envpitch += ((envpos - x1) * (envpitchdest - envpitch)) / (x2 - x1); | ||
767 | } | ||
768 | if (envpitch < -256) envpitch = -256; | ||
769 | if (envpitch > 256) envpitch = 256; | ||
770 | // Filter Envelope: controls cutoff frequency | ||
771 | if (penv->dwFlags & ENV_FILTER) | ||
772 | { | ||
773 | #ifndef NO_FILTER | ||
774 | SetupChannelFilter(pChn, (pChn->dwFlags & CHN_FILTER) ? FALSE : TRUE, envpitch); | ||
775 | #endif // NO_FILTER | ||
776 | } else | ||
777 | // Pitch Envelope | ||
778 | { | ||
779 | int l = envpitch; | ||
780 | if (l < 0) | ||
781 | { | ||
782 | l = -l; | ||
783 | if (l > 255) l = 255; | ||
784 | period = _muldiv(period, LinearSlideUpTable[l], 0x10000); | ||
785 | } else | ||
786 | { | ||
787 | if (l > 255) l = 255; | ||
788 | period = _muldiv(period, LinearSlideDownTable[l], 0x10000); | ||
789 | } | ||
790 | } | ||
791 | } | ||
792 | |||
793 | // Vibrato | ||
794 | if (pChn->dwFlags & CHN_VIBRATO) | ||
795 | { | ||
796 | UINT vibpos = pChn->nVibratoPos; | ||
797 | LONG vdelta; | ||
798 | switch (pChn->nVibratoType & 0x03) | ||
799 | { | ||
800 | case 1: | ||
801 | vdelta = ModRampDownTable[vibpos]; | ||
802 | break; | ||
803 | case 2: | ||
804 | vdelta = ModSquareTable[vibpos]; | ||
805 | break; | ||
806 | case 3: | ||
807 | vdelta = ModRandomTable[vibpos]; | ||
808 | break; | ||
809 | default: | ||
810 | vdelta = ModSinusTable[vibpos]; | ||
811 | } | ||
812 | UINT vdepth = ((m_nType != MOD_TYPE_IT) || (m_dwSongFlags & SONG_ITOLDEFFECTS)) ? 6 : 7; | ||
813 | vdelta = (vdelta * (int)pChn->nVibratoDepth) >> vdepth; | ||
814 | if ((m_dwSongFlags & SONG_LINEARSLIDES) && (m_nType & MOD_TYPE_IT)) | ||
815 | { | ||
816 | LONG l = vdelta; | ||
817 | if (l < 0) | ||
818 | { | ||
819 | l = -l; | ||
820 | vdelta = _muldiv(period, LinearSlideDownTable[l >> 2], 0x10000) - period; | ||
821 | if (l & 0x03) vdelta += _muldiv(period, FineLinearSlideDownTable[l & 0x03], 0x10000) - period; | ||
822 | |||
823 | } else | ||
824 | { | ||
825 | vdelta = _muldiv(period, LinearSlideUpTable[l >> 2], 0x10000) - period; | ||
826 | if (l & 0x03) vdelta += _muldiv(period, FineLinearSlideUpTable[l & 0x03], 0x10000) - period; | ||
827 | |||
828 | } | ||
829 | } | ||
830 | period += vdelta; | ||
831 | if ((m_nTickCount) || ((m_nType & MOD_TYPE_IT) && (!(m_dwSongFlags & SONG_ITOLDEFFECTS)))) | ||
832 | { | ||
833 | pChn->nVibratoPos = (vibpos + pChn->nVibratoSpeed) & 0x3F; | ||
834 | } | ||
835 | } | ||
836 | // Panbrello | ||
837 | if (pChn->dwFlags & CHN_PANBRELLO) | ||
838 | { | ||
839 | UINT panpos = ((pChn->nPanbrelloPos+0x10) >> 2) & 0x3F; | ||
840 | LONG pdelta; | ||
841 | switch (pChn->nPanbrelloType & 0x03) | ||
842 | { | ||
843 | case 1: | ||
844 | pdelta = ModRampDownTable[panpos]; | ||
845 | break; | ||
846 | case 2: | ||
847 | pdelta = ModSquareTable[panpos]; | ||
848 | break; | ||
849 | case 3: | ||
850 | pdelta = ModRandomTable[panpos]; | ||
851 | break; | ||
852 | default: | ||
853 | pdelta = ModSinusTable[panpos]; | ||
854 | } | ||
855 | pChn->nPanbrelloPos += pChn->nPanbrelloSpeed; | ||
856 | pdelta = ((pdelta * (int)pChn->nPanbrelloDepth) + 2) >> 3; | ||
857 | pdelta += pChn->nRealPan; | ||
858 | if (pdelta < 0) pdelta = 0; | ||
859 | if (pdelta > 256) pdelta = 256; | ||
860 | pChn->nRealPan = pdelta; | ||
861 | } | ||
862 | int nPeriodFrac = 0; | ||
863 | // Instrument Auto-Vibrato | ||
864 | if ((pChn->pInstrument) && (pChn->pInstrument->nVibDepth)) | ||
865 | { | ||
866 | MODINSTRUMENT *pins = pChn->pInstrument; | ||
867 | if (pins->nVibSweep == 0) | ||
868 | { | ||
869 | pChn->nAutoVibDepth = pins->nVibDepth << 8; | ||
870 | } else | ||
871 | { | ||
872 | if (m_nType & MOD_TYPE_IT) | ||
873 | { | ||
874 | pChn->nAutoVibDepth += pins->nVibSweep << 3; | ||
875 | } else | ||
876 | if (!(pChn->dwFlags & CHN_KEYOFF)) | ||
877 | { | ||
878 | pChn->nAutoVibDepth += (pins->nVibDepth << 8) /pins->nVibSweep; | ||
879 | } | ||
880 | if ((pChn->nAutoVibDepth >> 8) > pins->nVibDepth) | ||
881 | pChn->nAutoVibDepth = pins->nVibDepth << 8; | ||
882 | } | ||
883 | pChn->nAutoVibPos += pins->nVibRate; | ||
884 | int val; | ||
885 | switch(pins->nVibType) | ||
886 | { | ||
887 | case 4:// Random | ||
888 | val = ModRandomTable[pChn->nAutoVibPos & 0x3F]; | ||
889 | pChn->nAutoVibPos++; | ||
890 | break; | ||
891 | case 3:// Ramp Down | ||
892 | val = ((0x40 - (pChn->nAutoVibPos >> 1)) & 0x7F) - 0x40; | ||
893 | break; | ||
894 | case 2:// Ramp Up | ||
895 | val = ((0x40 + (pChn->nAutoVibPos >> 1)) & 0x7f) - 0x40; | ||
896 | break; | ||
897 | case 1:// Square | ||
898 | val = (pChn->nAutoVibPos & 128) ? +64 : -64; | ||
899 | break; | ||
900 | default:// Sine | ||
901 | val = ft2VibratoTable[pChn->nAutoVibPos & 255]; | ||
902 | } | ||
903 | int n =((val * pChn->nAutoVibDepth) >> 8); | ||
904 | if (m_nType & MOD_TYPE_IT) | ||
905 | { | ||
906 | int df1, df2; | ||
907 | if (n < 0) | ||
908 | { | ||
909 | n = -n; | ||
910 | UINT n1 = n >> 8; | ||
911 | df1 = LinearSlideUpTable[n1]; | ||
912 | df2 = LinearSlideUpTable[n1+1]; | ||
913 | } else | ||
914 | { | ||
915 | UINT n1 = n >> 8; | ||
916 | df1 = LinearSlideDownTable[n1]; | ||
917 | df2 = LinearSlideDownTable[n1+1]; | ||
918 | } | ||
919 | n >>= 2; | ||
920 | period = _muldiv(period, df1 + ((df2-df1)*(n&0x3F)>>6), 256); | ||
921 | nPeriodFrac = period & 0xFF; | ||
922 | period >>= 8; | ||
923 | } else | ||
924 | { | ||
925 | period += (n >> 6); | ||
926 | } | ||
927 | } | ||
928 | // Final Period | ||
929 | if (period <= m_nMinPeriod) | ||
930 | { | ||
931 | if (m_nType & MOD_TYPE_S3M) pChn->nLength = 0; | ||
932 | period = m_nMinPeriod; | ||
933 | } | ||
934 | if (period > m_nMaxPeriod) | ||
935 | { | ||
936 | if ((m_nType & MOD_TYPE_IT) || (period >= 0x100000)) | ||
937 | { | ||
938 | pChn->nFadeOutVol = 0; | ||
939 | pChn->dwFlags |= CHN_NOTEFADE; | ||
940 | pChn->nRealVolume = 0; | ||
941 | } | ||
942 | period = m_nMaxPeriod; | ||
943 | nPeriodFrac = 0; | ||
944 | } | ||
945 | UINT freq = GetFreqFromPeriod(period, pChn->nC4Speed, nPeriodFrac); | ||
946 | if ((m_nType & MOD_TYPE_IT) && (freq < 256)) | ||
947 | { | ||
948 | pChn->nFadeOutVol = 0; | ||
949 | pChn->dwFlags |= CHN_NOTEFADE; | ||
950 | pChn->nRealVolume = 0; | ||
951 | } | ||
952 | UINT ninc = _muldiv(freq, 0x10000, gdwMixingFreq); | ||
953 | if ((ninc >= 0xFFB0) && (ninc <= 0x10090)) ninc = 0x10000; | ||
954 | if (m_nFreqFactor != 128) ninc = (ninc * m_nFreqFactor) >> 7; | ||
955 | if (ninc > 0xFF0000) ninc = 0xFF0000; | ||
956 | pChn->nInc = (ninc+1) & ~3; | ||
957 | } | ||
958 | |||
959 | // Increment envelope position | ||
960 | if (pChn->pHeader) | ||
961 | { | ||
962 | INSTRUMENTHEADER *penv = pChn->pHeader; | ||
963 | // Volume Envelope | ||
964 | if (pChn->dwFlags & CHN_VOLENV) | ||
965 | { | ||
966 | // Increase position | ||
967 | pChn->nVolEnvPosition++; | ||
968 | // Volume Loop ? | ||
969 | if (penv->dwFlags & ENV_VOLLOOP) | ||
970 | { | ||
971 | UINT volloopend = penv->VolPoints[penv->nVolLoopEnd]; | ||
972 | if (m_nType != MOD_TYPE_XM) volloopend++; | ||
973 | if (pChn->nVolEnvPosition == volloopend) | ||
974 | { | ||
975 | pChn->nVolEnvPosition = penv->VolPoints[penv->nVolLoopStart]; | ||
976 | if ((penv->nVolLoopEnd == penv->nVolLoopStart) && (!penv->VolEnv[penv->nVolLoopStart]) | ||
977 | && ((!(m_nType & MOD_TYPE_XM)) || (penv->nVolLoopEnd+1 == penv->nVolEnv))) | ||
978 | { | ||
979 | pChn->dwFlags |= CHN_NOTEFADE; | ||
980 | pChn->nFadeOutVol = 0; | ||
981 | } | ||
982 | } | ||
983 | } | ||
984 | // Volume Sustain ? | ||
985 | if ((penv->dwFlags & ENV_VOLSUSTAIN) && (!(pChn->dwFlags & CHN_KEYOFF))) | ||
986 | { | ||
987 | if (pChn->nVolEnvPosition == (UINT)penv->VolPoints[penv->nVolSustainEnd]+1) | ||
988 | pChn->nVolEnvPosition = penv->VolPoints[penv->nVolSustainBegin]; | ||
989 | } else | ||
990 | // End of Envelope ? | ||
991 | if (pChn->nVolEnvPosition > penv->VolPoints[penv->nVolEnv - 1]) | ||
992 | { | ||
993 | if ((m_nType & MOD_TYPE_IT) || (pChn->dwFlags & CHN_KEYOFF)) pChn->dwFlags |= CHN_NOTEFADE; | ||
994 | pChn->nVolEnvPosition = penv->VolPoints[penv->nVolEnv - 1]; | ||
995 | if ((!penv->VolEnv[penv->nVolEnv-1]) && ((nChn >= m_nChannels) || (m_nType & MOD_TYPE_IT))) | ||
996 | { | ||
997 | pChn->dwFlags |= CHN_NOTEFADE; | ||
998 | pChn->nFadeOutVol = 0; | ||
999 | |||
1000 | pChn->nRealVolume = 0; | ||
1001 | } | ||
1002 | } | ||
1003 | } | ||
1004 | // Panning Envelope | ||
1005 | if (pChn->dwFlags & CHN_PANENV) | ||
1006 | { | ||
1007 | pChn->nPanEnvPosition++; | ||
1008 | if (penv->dwFlags & ENV_PANLOOP) | ||
1009 | { | ||
1010 | UINT panloopend = penv->PanPoints[penv->nPanLoopEnd]; | ||
1011 | if (m_nType != MOD_TYPE_XM) panloopend++; | ||
1012 | if (pChn->nPanEnvPosition == panloopend) | ||
1013 | pChn->nPanEnvPosition = penv->PanPoints[penv->nPanLoopStart]; | ||
1014 | } | ||
1015 | // Panning Sustain ? | ||
1016 | if ((penv->dwFlags & ENV_PANSUSTAIN) && (pChn->nPanEnvPosition == (UINT)penv->PanPoints[penv->nPanSustainEnd]+1) | ||
1017 | && (!(pChn->dwFlags & CHN_KEYOFF))) | ||
1018 | { | ||
1019 | // Panning sustained | ||
1020 | pChn->nPanEnvPosition = penv->PanPoints[penv->nPanSustainBegin]; | ||
1021 | } else | ||
1022 | { | ||
1023 | if (pChn->nPanEnvPosition > penv->PanPoints[penv->nPanEnv - 1]) | ||
1024 | pChn->nPanEnvPosition = penv->PanPoints[penv->nPanEnv - 1]; | ||
1025 | } | ||
1026 | } | ||
1027 | // Pitch Envelope | ||
1028 | if (pChn->dwFlags & CHN_PITCHENV) | ||
1029 | { | ||
1030 | // Increase position | ||
1031 | pChn->nPitchEnvPosition++; | ||
1032 | // Pitch Loop ? | ||
1033 | if (penv->dwFlags & ENV_PITCHLOOP) | ||
1034 | { | ||
1035 | if (pChn->nPitchEnvPosition >= penv->PitchPoints[penv->nPitchLoopEnd]) | ||
1036 | pChn->nPitchEnvPosition = penv->PitchPoints[penv->nPitchLoopStart]; | ||
1037 | } | ||
1038 | // Pitch Sustain ? | ||
1039 | if ((penv->dwFlags & ENV_PITCHSUSTAIN) && (!(pChn->dwFlags & CHN_KEYOFF))) | ||
1040 | { | ||
1041 | if (pChn->nPitchEnvPosition == (UINT)penv->PitchPoints[penv->nPitchSustainEnd]+1) | ||
1042 | pChn->nPitchEnvPosition = penv->PitchPoints[penv->nPitchSustainBegin]; | ||
1043 | } else | ||
1044 | { | ||
1045 | if (pChn->nPitchEnvPosition > penv->PitchPoints[penv->nPitchEnv - 1]) | ||
1046 | pChn->nPitchEnvPosition = penv->PitchPoints[penv->nPitchEnv - 1]; | ||
1047 | } | ||
1048 | } | ||
1049 | } | ||
1050 | #ifdef MODPLUG_PLAYER | ||
1051 | // Limit CPU -> > 80% -> don't ramp | ||
1052 | if ((gnCPUUsage >= 80) && (!pChn->nRealVolume)) | ||
1053 | { | ||
1054 | pChn->nLeftVol = pChn->nRightVol = 0; | ||
1055 | } | ||
1056 | #endif // MODPLUG_PLAYER | ||
1057 | // Volume ramping | ||
1058 | pChn->dwFlags &= ~CHN_VOLUMERAMP; | ||
1059 | if ((pChn->nRealVolume) || (pChn->nLeftVol) || (pChn->nRightVol)) | ||
1060 | pChn->dwFlags |= CHN_VOLUMERAMP; | ||
1061 | #ifdef MODPLUG_PLAYER | ||
1062 | // Decrease VU-Meter | ||
1063 | if (pChn->nVUMeter > VUMETER_DECAY)pChn->nVUMeter -= VUMETER_DECAY; else pChn->nVUMeter = 0; | ||
1064 | #endif // MODPLUG_PLAYER | ||
1065 | #ifdef ENABLE_STEREOVU | ||
1066 | if (pChn->nLeftVU > VUMETER_DECAY) pChn->nLeftVU -= VUMETER_DECAY; else pChn->nLeftVU = 0; | ||
1067 | if (pChn->nRightVU > VUMETER_DECAY) pChn->nRightVU -= VUMETER_DECAY; else pChn->nRightVU = 0; | ||
1068 | #endif | ||
1069 | // Check for too big nInc | ||
1070 | if (((pChn->nInc >> 16) + 1) >= (LONG)(pChn->nLoopEnd - pChn->nLoopStart)) pChn->dwFlags &= ~CHN_LOOP; | ||
1071 | pChn->nNewRightVol = pChn->nNewLeftVol = 0; | ||
1072 | pChn->pCurrentSample = ((pChn->pSample) && (pChn->nLength) && (pChn->nInc)) ? pChn->pSample : NULL; | ||
1073 | if (pChn->pCurrentSample) | ||
1074 | { | ||
1075 | // Update VU-Meter (nRealVolume is 14-bit) | ||
1076 | #ifdef MODPLUG_PLAYER | ||
1077 | UINT vutmp = pChn->nRealVolume >> (14 - 8); | ||
1078 | if (vutmp > 0xFF) vutmp = 0xFF; | ||
1079 | if (pChn->nVUMeter >= 0x100) pChn->nVUMeter = vutmp; | ||
1080 | vutmp >>= 1; | ||
1081 | if (pChn->nVUMeter < vutmp)pChn->nVUMeter = vutmp; | ||
1082 | #endif // MODPLUG_PLAYER | ||
1083 | #ifdef ENABLE_STEREOVU | ||
1084 | UINT vul = (pChn->nRealVolume * pChn->nRealPan) >> 14; | ||
1085 | if (vul > 127) vul = 127; | ||
1086 | if (pChn->nLeftVU > 127) pChn->nLeftVU = (BYTE)vul; | ||
1087 | vul >>= 1; | ||
1088 | if (pChn->nLeftVU < vul) pChn->nLeftVU = (BYTE)vul; | ||
1089 | UINT vur = (pChn->nRealVolume * (256-pChn->nRealPan)) >> 14; | ||
1090 | if (vur > 127) vur = 127; | ||
1091 | if (pChn->nRightVU > 127) pChn->nRightVU = (BYTE)vur; | ||
1092 | vur >>= 1; | ||
1093 | if (pChn->nRightVU < vur) pChn->nRightVU = (BYTE)vur; | ||
1094 | #endif | ||
1095 | #ifdef MODPLUG_TRACKER | ||
1096 | UINT kChnMasterVol = (pChn->dwFlags & CHN_EXTRALOUD) ? 0x100 : nMasterVol; | ||
1097 | #else | ||
1098 | #define kChnMasterVolnMasterVol | ||
1099 | #endif // MODPLUG_TRACKER | ||
1100 | // Adjusting volumes | ||
1101 | if (gnChannels >= 2) | ||
1102 | { | ||
1103 | int pan = ((int)pChn->nRealPan) - 128; | ||
1104 | pan *= (int)m_nStereoSeparation; | ||
1105 | pan /= 128; | ||
1106 | pan += 128; | ||
1107 | |||
1108 | if (pan < 0) pan = 0; | ||
1109 | if (pan > 256) pan = 256; | ||
1110 | #ifndef FASTSOUNDLIB | ||
1111 | if (gdwSoundSetup & SNDMIX_REVERSESTEREO) pan = 256 - pan; | ||
1112 | #endif | ||
1113 | LONG realvol = (pChn->nRealVolume * kChnMasterVol) >> (8-1); | ||
1114 | if (gdwSoundSetup & SNDMIX_SOFTPANNING) | ||
1115 | { | ||
1116 | if (pan < 128) | ||
1117 | { | ||
1118 | pChn->nNewLeftVol = (realvol * pan) >> 8; | ||
1119 | pChn->nNewRightVol = (realvol * 128) >> 8; | ||
1120 | } else | ||
1121 | { | ||
1122 | pChn->nNewLeftVol = (realvol * 128) >> 8; | ||
1123 | pChn->nNewRightVol = (realvol * (256 - pan)) >> 8; | ||
1124 | } | ||
1125 | } else | ||
1126 | { | ||
1127 | pChn->nNewLeftVol = (realvol * pan) >> 8; | ||
1128 | pChn->nNewRightVol = (realvol * (256 - pan)) >> 8; | ||
1129 | } | ||
1130 | } else | ||
1131 | { | ||
1132 | pChn->nNewRightVol = (pChn->nRealVolume * kChnMasterVol) >> 8; | ||
1133 | pChn->nNewLeftVol = pChn->nNewRightVol; | ||
1134 | } | ||
1135 | // Clipping volumes | ||
1136 | if (pChn->nNewRightVol > 0xFFFF) pChn->nNewRightVol = 0xFFFF; | ||
1137 | if (pChn->nNewLeftVol > 0xFFFF) pChn->nNewLeftVol = 0xFFFF; | ||
1138 | // Check IDO | ||
1139 | if (gdwSoundSetup & SNDMIX_NORESAMPLING) | ||
1140 | { | ||
1141 | pChn->dwFlags |= CHN_NOIDO; | ||
1142 | } else | ||
1143 | { | ||
1144 | pChn->dwFlags &= ~(CHN_NOIDO|CHN_HQSRC); | ||
1145 | if( pChn->nInc == 0x10000 ) | ||
1146 | {pChn->dwFlags |= CHN_NOIDO; | ||
1147 | } | ||
1148 | else | ||
1149 | {if( ((gdwSoundSetup & SNDMIX_HQRESAMPLER) == 0) && ((gdwSoundSetup & SNDMIX_ULTRAHQSRCMODE) == 0) ) | ||
1150 | {if (pChn->nInc >= 0xFF00) pChn->dwFlags |= CHN_NOIDO; | ||
1151 | } | ||
1152 | } | ||
1153 | } | ||
1154 | pChn->nNewRightVol >>= MIXING_ATTENUATION; | ||
1155 | pChn->nNewLeftVol >>= MIXING_ATTENUATION; | ||
1156 | pChn->nRightRamp = pChn->nLeftRamp = 0; | ||
1157 | // Dolby Pro-Logic Surround | ||
1158 | if ((pChn->dwFlags & CHN_SURROUND) && (gnChannels <= 2)) pChn->nNewLeftVol = - pChn->nNewLeftVol; | ||
1159 | // Checking Ping-Pong Loops | ||
1160 | if (pChn->dwFlags & CHN_PINGPONGFLAG) pChn->nInc = -pChn->nInc; | ||
1161 | // Setting up volume ramp | ||
1162 | if ((pChn->dwFlags & CHN_VOLUMERAMP) | ||
1163 | && ((pChn->nRightVol != pChn->nNewRightVol) | ||
1164 | || (pChn->nLeftVol != pChn->nNewLeftVol))) | ||
1165 | { | ||
1166 | LONG nRampLength = gnVolumeRampSamples; | ||
1167 | LONG nRightDelta = ((pChn->nNewRightVol - pChn->nRightVol) << VOLUMERAMPPRECISION); | ||
1168 | LONG nLeftDelta = ((pChn->nNewLeftVol - pChn->nLeftVol) << VOLUMERAMPPRECISION); | ||
1169 | #ifndef FASTSOUNDLIB | ||
1170 | if ((gdwSoundSetup & SNDMIX_DIRECTTODISK) | ||
1171 | || ((gdwSysInfo & (SYSMIX_ENABLEMMX|SYSMIX_FASTCPU)) | ||
1172 | && (gdwSoundSetup & SNDMIX_HQRESAMPLER) && (gnCPUUsage <= 20))) | ||
1173 | { | ||
1174 | if ((pChn->nRightVol|pChn->nLeftVol) && (pChn->nNewRightVol|pChn->nNewLeftVol) && (!(pChn->dwFlags & CHN_FASTVOLRAMP))) | ||
1175 | { | ||
1176 | nRampLength = m_nBufferCount; | ||
1177 | if (nRampLength > (1 << (VOLUMERAMPPRECISION-1))) nRampLength = (1 << (VOLUMERAMPPRECISION-1)); | ||
1178 | if (nRampLength < (LONG)gnVolumeRampSamples) nRampLength = gnVolumeRampSamples; | ||
1179 | } | ||
1180 | } | ||
1181 | #endif | ||
1182 | pChn->nRightRamp = nRightDelta / nRampLength; | ||
1183 | pChn->nLeftRamp = nLeftDelta / nRampLength; | ||
1184 | pChn->nRightVol = pChn->nNewRightVol - ((pChn->nRightRamp * nRampLength) >> VOLUMERAMPPRECISION); | ||
1185 | pChn->nLeftVol = pChn->nNewLeftVol - ((pChn->nLeftRamp * nRampLength) >> VOLUMERAMPPRECISION); | ||
1186 | if (pChn->nRightRamp|pChn->nLeftRamp) | ||
1187 | { | ||
1188 | pChn->nRampLength = nRampLength; | ||
1189 | } else | ||
1190 | { | ||
1191 | pChn->dwFlags &= ~CHN_VOLUMERAMP; | ||
1192 | pChn->nRightVol = pChn->nNewRightVol; | ||
1193 | pChn->nLeftVol = pChn->nNewLeftVol; | ||
1194 | } | ||
1195 | } else | ||
1196 | { | ||
1197 | pChn->dwFlags &= ~CHN_VOLUMERAMP; | ||
1198 | pChn->nRightVol = pChn->nNewRightVol; | ||
1199 | pChn->nLeftVol = pChn->nNewLeftVol; | ||
1200 | } | ||
1201 | pChn->nRampRightVol = pChn->nRightVol << VOLUMERAMPPRECISION; | ||
1202 | pChn->nRampLeftVol = pChn->nLeftVol << VOLUMERAMPPRECISION; | ||
1203 | // Adding the channel in the channel list | ||
1204 | ChnMix[m_nMixChannels++] = nChn; | ||
1205 | if (m_nMixChannels >= MAX_CHANNELS) break; | ||
1206 | } else | ||
1207 | { | ||
1208 | #ifdef ENABLE_STEREOVU | ||
1209 | // Note change but no sample | ||
1210 | if (pChn->nLeftVU > 128) pChn->nLeftVU = 0; | ||
1211 | if (pChn->nRightVU > 128) pChn->nRightVU = 0; | ||
1212 | #endif | ||
1213 | if (pChn->nVUMeter > 0xFF) pChn->nVUMeter = 0; | ||
1214 | pChn->nLeftVol = pChn->nRightVol = 0; | ||
1215 | pChn->nLength = 0; | ||
1216 | } | ||
1217 | } | ||
1218 | // Checking Max Mix Channels reached: ordering by volume | ||
1219 | if ((m_nMixChannels >= m_nMaxMixChannels) && (!(gdwSoundSetup & SNDMIX_DIRECTTODISK))) | ||
1220 | { | ||
1221 | for (UINT i=0; i<m_nMixChannels; i++) | ||
1222 | { | ||
1223 | UINT j=i; | ||
1224 | while ((j+1<m_nMixChannels) && (Chn[ChnMix[j]].nRealVolume < Chn[ChnMix[j+1]].nRealVolume)) | ||
1225 | { | ||
1226 | UINT n = ChnMix[j]; | ||
1227 | ChnMix[j] = ChnMix[j+1]; | ||
1228 | ChnMix[j+1] = n; | ||
1229 | j++; | ||
1230 | } | ||
1231 | } | ||
1232 | } | ||
1233 | if (m_dwSongFlags & SONG_GLOBALFADE) | ||
1234 | { | ||
1235 | if (!m_nGlobalFadeSamples) | ||
1236 | { | ||
1237 | m_dwSongFlags |= SONG_ENDREACHED; | ||
1238 | return FALSE; | ||
1239 | } | ||
1240 | if (m_nGlobalFadeSamples > m_nBufferCount) | ||
1241 | m_nGlobalFadeSamples -= m_nBufferCount; | ||
1242 | else | ||
1243 | m_nGlobalFadeSamples = 0; | ||
1244 | } | ||
1245 | return TRUE; | ||
1246 | } | ||
1247 | |||
1248 | |||