comparison src/modplug/snd_fx.cxx @ 136:6b5a52635b3b trunk

[svn] - like with so many other things, modplug is now maintained by us.
author nenolod
date Sun, 29 Oct 2006 01:04:52 -0700
parents
children 032053ca08ab 3673c7ec4ea2
comparison
equal deleted inserted replaced
135:33d24bd94ccc 136:6b5a52635b3b
1 /*
2 * This source code is public domain.
3 *
4 * Authors: Olivier Lapicque <olivierl@jps.net>
5 */
6
7 #include "stdafx.h"
8 #include "sndfile.h"
9
10 #ifdef MSC_VER
11 #pragma warning(disable:4244)
12 #endif
13
14 // Tables defined in tables.cpp
15 extern BYTE ImpulseTrackerPortaVolCmd[16];
16 extern WORD S3MFineTuneTable[16];
17 extern WORD ProTrackerPeriodTable[6*12];
18 extern WORD ProTrackerTunedPeriods[15*12];
19 extern WORD FreqS3MTable[];
20 extern WORD XMPeriodTable[96+8];
21 extern UINT XMLinearTable[768];
22 extern DWORD FineLinearSlideUpTable[16];
23 extern DWORD FineLinearSlideDownTable[16];
24 extern DWORD LinearSlideUpTable[256];
25 extern DWORD LinearSlideDownTable[256];
26 extern signed char retrigTable1[16];
27 extern signed char retrigTable2[16];
28 extern short int ModRandomTable[64];
29
30
31 ////////////////////////////////////////////////////////////
32 // Length
33
34 DWORD CSoundFile::GetLength(BOOL bAdjust, BOOL bTotal)
35 //----------------------------------------------------
36 {
37 UINT dwElapsedTime=0, nRow=0, nCurrentPattern=0, nNextPattern=0, nPattern=Order[0];
38 UINT nMusicSpeed=m_nDefaultSpeed, nMusicTempo=m_nDefaultTempo, nNextRow=0;
39 UINT nMaxRow = 0, nMaxPattern = 0;
40 LONG nGlbVol = m_nDefaultGlobalVolume, nOldGlbVolSlide = 0;
41 BYTE samples[MAX_CHANNELS];
42 BYTE instr[MAX_CHANNELS];
43 BYTE notes[MAX_CHANNELS];
44 BYTE vols[MAX_CHANNELS];
45 BYTE oldparam[MAX_CHANNELS];
46 BYTE chnvols[MAX_CHANNELS];
47 DWORD patloop[MAX_CHANNELS];
48
49 memset(instr, 0, sizeof(instr));
50 memset(notes, 0, sizeof(notes));
51 memset(vols, 0xFF, sizeof(vols));
52 memset(patloop, 0, sizeof(patloop));
53 memset(oldparam, 0, sizeof(oldparam));
54 memset(chnvols, 64, sizeof(chnvols));
55 memset(samples, 0, sizeof(samples));
56 for (UINT icv=0; icv<m_nChannels; icv++) chnvols[icv] = ChnSettings[icv].nVolume;
57 nMaxRow = m_nNextRow;
58 nMaxPattern = m_nNextPattern;
59 nCurrentPattern = nNextPattern = 0;
60 nPattern = Order[0];
61 nRow = nNextRow = 0;
62 for (;;)
63 {
64 UINT nSpeedCount = 0;
65 nRow = nNextRow;
66 nCurrentPattern = nNextPattern;
67 // Check if pattern is valid
68 nPattern = Order[nCurrentPattern];
69 while (nPattern >= MAX_PATTERNS)
70 {
71 // End of song ?
72 if ((nPattern == 0xFF) || (nCurrentPattern >= MAX_ORDERS))
73 {
74 goto EndMod;
75 } else
76 {
77 nCurrentPattern++;
78 nPattern = (nCurrentPattern < MAX_ORDERS) ? Order[nCurrentPattern] : 0xFF;
79 }
80 nNextPattern = nCurrentPattern;
81 }
82 // Weird stuff?
83 if ((nPattern >= MAX_PATTERNS) || (!Patterns[nPattern])) break;
84 // Should never happen
85 if (nRow >= PatternSize[nPattern]) nRow = 0;
86 // Update next position
87 nNextRow = nRow + 1;
88 if (nNextRow >= PatternSize[nPattern])
89 {
90 nNextPattern = nCurrentPattern + 1;
91 nNextRow = 0;
92 }
93 if (!nRow)
94 {
95 for (UINT ipck=0; ipck<m_nChannels; ipck++) patloop[ipck] = dwElapsedTime;
96 }
97 if (!bTotal)
98 {
99 if ((nCurrentPattern > nMaxPattern) || ((nCurrentPattern == nMaxPattern) && (nRow >= nMaxRow)))
100 {
101 if (bAdjust)
102 {
103 m_nMusicSpeed = nMusicSpeed;
104 m_nMusicTempo = nMusicTempo;
105 }
106 break;
107 }
108 }
109 MODCHANNEL *pChn = Chn;
110 MODCOMMAND *p = Patterns[nPattern] + nRow * m_nChannels;
111 for (UINT nChn=0; nChn<m_nChannels; p++,pChn++, nChn++) if (*((DWORD *)p))
112 {
113 UINT command = p->command;
114 UINT param = p->param;
115 UINT note = p->note;
116 if (p->instr) { instr[nChn] = p->instr; notes[nChn] = 0; vols[nChn] = 0xFF; }
117 if ((note) && (note <= 120)) notes[nChn] = note;
118 if (p->volcmd == VOLCMD_VOLUME) { vols[nChn] = p->vol; }
119 if (command) switch (command)
120 {
121 // Position Jump
122 case CMD_POSITIONJUMP:
123 if (param <= nCurrentPattern) goto EndMod;
124 nNextPattern = param;
125 nNextRow = 0;
126 if (bAdjust)
127 {
128 pChn->nPatternLoopCount = 0;
129 pChn->nPatternLoop = 0;
130 }
131 break;
132 // Pattern Break
133 case CMD_PATTERNBREAK:
134 nNextRow = param;
135 nNextPattern = nCurrentPattern + 1;
136 if (bAdjust)
137 {
138 pChn->nPatternLoopCount = 0;
139 pChn->nPatternLoop = 0;
140 }
141 break;
142 // Set Speed
143 case CMD_SPEED:
144 if (!param) break;
145 if ((param <= 0x20) || (m_nType != MOD_TYPE_MOD))
146 {
147 if (param < 128) nMusicSpeed = param;
148 }
149 break;
150 // Set Tempo
151 case CMD_TEMPO:
152 if ((bAdjust) && (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT)))
153 {
154 if (param) pChn->nOldTempo = param; else param = pChn->nOldTempo;
155 }
156 if (param >= 0x20) nMusicTempo = param; else
157 // Tempo Slide
158 if ((param & 0xF0) == 0x10)
159 {
160 nMusicTempo += param & 0x0F;
161 if (nMusicTempo > 255) nMusicTempo = 255;
162 } else
163 {
164 nMusicTempo -= param & 0x0F;
165 if (nMusicTempo < 32) nMusicTempo = 32;
166 }
167 break;
168 // Pattern Delay
169 case CMD_S3MCMDEX:
170 if ((param & 0xF0) == 0x60) { nSpeedCount = param & 0x0F; break; } else
171 if ((param & 0xF0) == 0xB0) { param &= 0x0F; param |= 0x60; }
172 case CMD_MODCMDEX:
173 if ((param & 0xF0) == 0xE0) nSpeedCount = (param & 0x0F) * nMusicSpeed; else
174 if ((param & 0xF0) == 0x60)
175 {
176 if (param & 0x0F) dwElapsedTime += (dwElapsedTime - patloop[nChn]) * (param & 0x0F);
177 else patloop[nChn] = dwElapsedTime;
178 }
179 break;
180 }
181 if (!bAdjust) continue;
182 switch(command)
183 {
184 // Portamento Up/Down
185 case CMD_PORTAMENTOUP:
186 case CMD_PORTAMENTODOWN:
187 if (param) pChn->nOldPortaUpDown = param;
188 break;
189 // Tone-Portamento
190 case CMD_TONEPORTAMENTO:
191 if (param) pChn->nPortamentoSlide = param << 2;
192 break;
193 // Offset
194 case CMD_OFFSET:
195 if (param) pChn->nOldOffset = param;
196 break;
197 // Volume Slide
198 case CMD_VOLUMESLIDE:
199 case CMD_TONEPORTAVOL:
200 case CMD_VIBRATOVOL:
201 if (param) pChn->nOldVolumeSlide = param;
202 break;
203 // Set Volume
204 case CMD_VOLUME:
205 vols[nChn] = param;
206 break;
207 // Global Volume
208 case CMD_GLOBALVOLUME:
209 if (m_nType != MOD_TYPE_IT) param <<= 1;
210 if (param > 128) param = 128;
211 nGlbVol = param << 1;
212 break;
213 // Global Volume Slide
214 case CMD_GLOBALVOLSLIDE:
215 if (param) nOldGlbVolSlide = param; else param = nOldGlbVolSlide;
216 if (((param & 0x0F) == 0x0F) && (param & 0xF0))
217 {
218 param >>= 4;
219 if (m_nType != MOD_TYPE_IT) param <<= 1;
220 nGlbVol += param << 1;
221 } else
222 if (((param & 0xF0) == 0xF0) && (param & 0x0F))
223 {
224 param = (param & 0x0F) << 1;
225 if (m_nType != MOD_TYPE_IT) param <<= 1;
226 nGlbVol -= param;
227 } else
228 if (param & 0xF0)
229 {
230 param >>= 4;
231 param <<= 1;
232 if (m_nType != MOD_TYPE_IT) param <<= 1;
233 nGlbVol += param * nMusicSpeed;
234 } else
235 {
236 param = (param & 0x0F) << 1;
237 if (m_nType != MOD_TYPE_IT) param <<= 1;
238 nGlbVol -= param * nMusicSpeed;
239 }
240 if (nGlbVol < 0) nGlbVol = 0;
241 if (nGlbVol > 256) nGlbVol = 256;
242 break;
243 case CMD_CHANNELVOLUME:
244 if (param <= 64) chnvols[nChn] = param;
245 break;
246 case CMD_CHANNELVOLSLIDE:
247 if (param) oldparam[nChn] = param; else param = oldparam[nChn];
248 pChn->nOldChnVolSlide = param;
249 if (((param & 0x0F) == 0x0F) && (param & 0xF0))
250 {
251 param = (param >> 4) + chnvols[nChn];
252 } else
253 if (((param & 0xF0) == 0xF0) && (param & 0x0F))
254 {
255 if (chnvols[nChn] > (int)(param & 0x0F)) param = chnvols[nChn] - (param & 0x0F);
256 else param = 0;
257 } else
258 if (param & 0x0F)
259 {
260 param = (param & 0x0F) * nMusicSpeed;
261 param = (chnvols[nChn] > param) ? chnvols[nChn] - param : 0;
262 } else param = ((param & 0xF0) >> 4) * nMusicSpeed + chnvols[nChn];
263 if (param > 64) param = 64;
264 chnvols[nChn] = param;
265 break;
266 }
267 }
268 nSpeedCount += nMusicSpeed;
269 dwElapsedTime += (2500 * nSpeedCount) / nMusicTempo;
270 }
271 EndMod:
272 if ((bAdjust) && (!bTotal))
273 {
274 m_nGlobalVolume = nGlbVol;
275 m_nOldGlbVolSlide = nOldGlbVolSlide;
276 for (UINT n=0; n<m_nChannels; n++)
277 {
278 Chn[n].nGlobalVol = chnvols[n];
279 if (notes[n]) Chn[n].nNewNote = notes[n];
280 if (instr[n]) Chn[n].nNewIns = instr[n];
281 if (vols[n] != 0xFF)
282 {
283 if (vols[n] > 64) vols[n] = 64;
284 Chn[n].nVolume = vols[n] << 2;
285 }
286 }
287 }
288 return (dwElapsedTime+500) / 1000;
289 }
290
291
292 //////////////////////////////////////////////////////////////////////////////////////////////////
293 // Effects
294
295 void CSoundFile::InstrumentChange(MODCHANNEL *pChn, UINT instr, BOOL bPorta, BOOL bUpdVol, BOOL bResetEnv)
296 //--------------------------------------------------------------------------------------------------------
297 {
298 BOOL bInstrumentChanged = FALSE;
299
300 if (instr >= MAX_INSTRUMENTS) return;
301 INSTRUMENTHEADER *penv = Headers[instr];
302 MODINSTRUMENT *psmp = &Ins[instr];
303 UINT note = pChn->nNewNote;
304 if ((penv) && (note) && (note <= 128))
305 {
306 if (penv->NoteMap[note-1] >= 0xFE) return;
307 UINT n = penv->Keyboard[note-1];
308 psmp = ((n) && (n < MAX_SAMPLES)) ? &Ins[n] : NULL;
309 } else
310 if (m_nInstruments)
311 {
312 if (note >= 0xFE) return;
313 psmp = NULL;
314 }
315 // Update Volume
316 if (bUpdVol) pChn->nVolume = (psmp) ? psmp->nVolume : 0;
317 // bInstrumentChanged is used for IT carry-on env option
318 if (penv != pChn->pHeader)
319 {
320 bInstrumentChanged = TRUE;
321 pChn->pHeader = penv;
322 } else
323 // Special XM hack
324 if ((bPorta) && (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) && (penv)
325 && (pChn->pInstrument) && (psmp != pChn->pInstrument))
326 {
327 // FT2 doesn't change the sample in this case,
328 // but still uses the sample info from the old one (bug?)
329 return;
330 }
331 // Instrument adjust
332 pChn->nNewIns = 0;
333 if (psmp)
334 {
335 if (penv)
336 {
337 pChn->nInsVol = (psmp->nGlobalVol * penv->nGlobalVol) >> 6;
338 if (penv->dwFlags & ENV_SETPANNING) pChn->nPan = penv->nPan;
339 pChn->nNNA = penv->nNNA;
340 } else
341 {
342 pChn->nInsVol = psmp->nGlobalVol;
343 }
344 if (psmp->uFlags & CHN_PANNING) pChn->nPan = psmp->nPan;
345 }
346 // Reset envelopes
347 if (bResetEnv)
348 {
349 if ((!bPorta) || (!(m_nType & MOD_TYPE_IT)) || (m_dwSongFlags & SONG_ITCOMPATMODE)
350 || (!pChn->nLength) || ((pChn->dwFlags & CHN_NOTEFADE) && (!pChn->nFadeOutVol)))
351 {
352 pChn->dwFlags |= CHN_FASTVOLRAMP;
353 if ((m_nType & MOD_TYPE_IT) && (!bInstrumentChanged) && (penv) && (!(pChn->dwFlags & (CHN_KEYOFF|CHN_NOTEFADE))))
354 {
355 if (!(penv->dwFlags & ENV_VOLCARRY)) pChn->nVolEnvPosition = 0;
356 if (!(penv->dwFlags & ENV_PANCARRY)) pChn->nPanEnvPosition = 0;
357 if (!(penv->dwFlags & ENV_PITCHCARRY)) pChn->nPitchEnvPosition = 0;
358 } else
359 {
360 pChn->nVolEnvPosition = 0;
361 pChn->nPanEnvPosition = 0;
362 pChn->nPitchEnvPosition = 0;
363 }
364 pChn->nAutoVibDepth = 0;
365 pChn->nAutoVibPos = 0;
366 } else
367 if ((penv) && (!(penv->dwFlags & ENV_VOLUME)))
368 {
369 pChn->nVolEnvPosition = 0;
370 pChn->nAutoVibDepth = 0;
371 pChn->nAutoVibPos = 0;
372 }
373 }
374 // Invalid sample ?
375 if (!psmp)
376 {
377 pChn->pInstrument = NULL;
378 pChn->nInsVol = 0;
379 return;
380 }
381 // Tone-Portamento doesn't reset the pingpong direction flag
382 if ((bPorta) && (psmp == pChn->pInstrument))
383 {
384 if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT)) return;
385 pChn->dwFlags &= ~(CHN_KEYOFF|CHN_NOTEFADE);
386 pChn->dwFlags = (pChn->dwFlags & (0xFFFFFF00 | CHN_PINGPONGFLAG)) | (psmp->uFlags);
387 } else
388 {
389 pChn->dwFlags &= ~(CHN_KEYOFF|CHN_NOTEFADE|CHN_VOLENV|CHN_PANENV|CHN_PITCHENV);
390 pChn->dwFlags = (pChn->dwFlags & 0xFFFFFF00) | (psmp->uFlags);
391 if (penv)
392 {
393 if (penv->dwFlags & ENV_VOLUME) pChn->dwFlags |= CHN_VOLENV;
394 if (penv->dwFlags & ENV_PANNING) pChn->dwFlags |= CHN_PANENV;
395 if (penv->dwFlags & ENV_PITCH) pChn->dwFlags |= CHN_PITCHENV;
396 if ((penv->dwFlags & ENV_PITCH) && (penv->dwFlags & ENV_FILTER))
397 {
398 if (!pChn->nCutOff) pChn->nCutOff = 0x7F;
399 }
400 if (penv->nIFC & 0x80) pChn->nCutOff = penv->nIFC & 0x7F;
401 if (penv->nIFR & 0x80) pChn->nResonance = penv->nIFR & 0x7F;
402 }
403 pChn->nVolSwing = pChn->nPanSwing = 0;
404 }
405 pChn->pInstrument = psmp;
406 pChn->nLength = psmp->nLength;
407 pChn->nLoopStart = psmp->nLoopStart;
408 pChn->nLoopEnd = psmp->nLoopEnd;
409 pChn->nC4Speed = psmp->nC4Speed;
410 pChn->pSample = psmp->pSample;
411 pChn->nTranspose = psmp->RelativeTone;
412 pChn->nFineTune = psmp->nFineTune;
413 if (pChn->dwFlags & CHN_SUSTAINLOOP)
414 {
415 pChn->nLoopStart = psmp->nSustainStart;
416 pChn->nLoopEnd = psmp->nSustainEnd;
417 pChn->dwFlags |= CHN_LOOP;
418 if (pChn->dwFlags & CHN_PINGPONGSUSTAIN) pChn->dwFlags |= CHN_PINGPONGLOOP;
419 }
420 if ((pChn->dwFlags & CHN_LOOP) && (pChn->nLoopEnd < pChn->nLength)) pChn->nLength = pChn->nLoopEnd;
421 }
422
423
424 void CSoundFile::NoteChange(UINT nChn, int note, BOOL bPorta, BOOL bResetEnv)
425 //---------------------------------------------------------------------------
426 {
427 if (note < 1) return;
428 MODCHANNEL * const pChn = &Chn[nChn];
429 MODINSTRUMENT *pins = pChn->pInstrument;
430 INSTRUMENTHEADER *penv = pChn->pHeader;
431 if ((penv) && (note <= 0x80))
432 {
433 UINT n = penv->Keyboard[note - 1];
434 if ((n) && (n < MAX_SAMPLES)) pins = &Ins[n];
435 note = penv->NoteMap[note-1];
436 }
437 // Key Off
438 if (note >= 0x80) // 0xFE or invalid note => key off
439 {
440 // Key Off
441 KeyOff(nChn);
442 // Note Cut
443 if (note == 0xFE)
444 {
445 pChn->dwFlags |= (CHN_NOTEFADE|CHN_FASTVOLRAMP);
446 if ((!(m_nType & MOD_TYPE_IT)) || (m_nInstruments)) pChn->nVolume = 0;
447 pChn->nFadeOutVol = 0;
448 }
449 return;
450 }
451 if (!pins) return;
452 if ((!bPorta) && (m_nType & (MOD_TYPE_XM|MOD_TYPE_MED|MOD_TYPE_MT2)))
453 {
454 pChn->nTranspose = pins->RelativeTone;
455 pChn->nFineTune = pins->nFineTune;
456 }
457 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2|MOD_TYPE_MED)) note += pChn->nTranspose;
458 if (note < 1) note = 1;
459 if (note > 132) note = 132;
460 pChn->nNote = note;
461 if ((!bPorta) || (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))) pChn->nNewIns = 0;
462 UINT period = GetPeriodFromNote(note, pChn->nFineTune, pChn->nC4Speed);
463 if (period)
464 {
465 if ((!bPorta) || (!pChn->nPeriod)) pChn->nPeriod = period;
466 pChn->nPortamentoDest = period;
467 if ((!bPorta) || ((!pChn->nLength) && (!(m_nType & MOD_TYPE_S3M))))
468 {
469 pChn->pInstrument = pins;
470 pChn->pSample = pins->pSample;
471 pChn->nLength = pins->nLength;
472 pChn->nLoopEnd = pins->nLength;
473 pChn->nLoopStart = 0;
474 pChn->dwFlags = (pChn->dwFlags & 0xFFFFFF00) | (pins->uFlags);
475 if (pChn->dwFlags & CHN_SUSTAINLOOP)
476 {
477 pChn->nLoopStart = pins->nSustainStart;
478 pChn->nLoopEnd = pins->nSustainEnd;
479 pChn->dwFlags &= ~CHN_PINGPONGLOOP;
480 pChn->dwFlags |= CHN_LOOP;
481 if (pChn->dwFlags & CHN_PINGPONGSUSTAIN) pChn->dwFlags |= CHN_PINGPONGLOOP;
482 if (pChn->nLength > pChn->nLoopEnd) pChn->nLength = pChn->nLoopEnd;
483 } else
484 if (pChn->dwFlags & CHN_LOOP)
485 {
486 pChn->nLoopStart = pins->nLoopStart;
487 pChn->nLoopEnd = pins->nLoopEnd;
488 if (pChn->nLength > pChn->nLoopEnd) pChn->nLength = pChn->nLoopEnd;
489 }
490 pChn->nPos = 0;
491 pChn->nPosLo = 0;
492 if (pChn->nVibratoType < 4) pChn->nVibratoPos = ((m_nType & MOD_TYPE_IT) && (!(m_dwSongFlags & SONG_ITOLDEFFECTS))) ? 0x10 : 0;
493 if (pChn->nTremoloType < 4) pChn->nTremoloPos = 0;
494 }
495 if (pChn->nPos >= pChn->nLength) pChn->nPos = pChn->nLoopStart;
496 } else bPorta = FALSE;
497 if ((!bPorta) || (!(m_nType & MOD_TYPE_IT))
498 || ((pChn->dwFlags & CHN_NOTEFADE) && (!pChn->nFadeOutVol))
499 || ((m_dwSongFlags & SONG_ITCOMPATMODE) && (pChn->nRowInstr)))
500 {
501 if ((m_nType & MOD_TYPE_IT) && (pChn->dwFlags & CHN_NOTEFADE) && (!pChn->nFadeOutVol))
502 {
503 pChn->nVolEnvPosition = 0;
504 pChn->nPanEnvPosition = 0;
505 pChn->nPitchEnvPosition = 0;
506 pChn->nAutoVibDepth = 0;
507 pChn->nAutoVibPos = 0;
508 pChn->dwFlags &= ~CHN_NOTEFADE;
509 pChn->nFadeOutVol = 65536;
510 }
511 if ((!bPorta) || (!(m_dwSongFlags & SONG_ITCOMPATMODE)) || (pChn->nRowInstr))
512 {
513 if ((!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) || (pChn->nRowInstr))
514 {
515 pChn->dwFlags &= ~CHN_NOTEFADE;
516 pChn->nFadeOutVol = 65536;
517 }
518 }
519 }
520 pChn->dwFlags &= ~(CHN_EXTRALOUD|CHN_KEYOFF);
521 // Enable Ramping
522 if (!bPorta)
523 {
524 pChn->nVUMeter = 0x100;
525 pChn->nLeftVU = pChn->nRightVU = 0xFF;
526 pChn->dwFlags &= ~CHN_FILTER;
527 pChn->dwFlags |= CHN_FASTVOLRAMP;
528 pChn->nRetrigCount = 0;
529 pChn->nTremorCount = 0;
530 if (bResetEnv)
531 {
532 pChn->nVolSwing = pChn->nPanSwing = 0;
533 if (penv)
534 {
535 if (!(penv->dwFlags & ENV_VOLCARRY)) pChn->nVolEnvPosition = 0;
536 if (!(penv->dwFlags & ENV_PANCARRY)) pChn->nPanEnvPosition = 0;
537 if (!(penv->dwFlags & ENV_PITCHCARRY)) pChn->nPitchEnvPosition = 0;
538 if (m_nType & MOD_TYPE_IT)
539 {
540 // Volume Swing
541 if (penv->nVolSwing)
542 {
543 int d = ((LONG)penv->nVolSwing*(LONG)((rand() & 0xFF) - 0x7F)) / 128;
544 pChn->nVolSwing = (signed short)((d * pChn->nVolume + 1)/128);
545 }
546 // Pan Swing
547 if (penv->nPanSwing)
548 {
549 int d = ((LONG)penv->nPanSwing*(LONG)((rand() & 0xFF) - 0x7F)) / 128;
550 pChn->nPanSwing = (signed short)d;
551 }
552 }
553 }
554 pChn->nAutoVibDepth = 0;
555 pChn->nAutoVibPos = 0;
556 }
557 pChn->nLeftVol = pChn->nRightVol = 0;
558 BOOL bFlt = (m_dwSongFlags & SONG_MPTFILTERMODE) ? FALSE : TRUE;
559 // Setup Initial Filter for this note
560 if (penv)
561 {
562 if (penv->nIFR & 0x80) { pChn->nResonance = penv->nIFR & 0x7F; bFlt = TRUE; }
563 if (penv->nIFC & 0x80) { pChn->nCutOff = penv->nIFC & 0x7F; bFlt = TRUE; }
564 } else
565 {
566 pChn->nVolSwing = pChn->nPanSwing = 0;
567 }
568 #ifndef NO_FILTER
569 if ((pChn->nCutOff < 0x7F) && (bFlt)) SetupChannelFilter(pChn, TRUE);
570 #endif // NO_FILTER
571 }
572 }
573
574
575 UINT CSoundFile::GetNNAChannel(UINT nChn) const
576 //---------------------------------------------
577 {
578 const MODCHANNEL *pChn = &Chn[nChn];
579 // Check for empty channel
580 const MODCHANNEL *pi = &Chn[m_nChannels];
581 for (UINT i=m_nChannels; i<MAX_CHANNELS; i++, pi++) if (!pi->nLength) return i;
582 if (!pChn->nFadeOutVol) return 0;
583 // All channels are used: check for lowest volume
584 UINT result = 0;
585 DWORD vol = 64*65536; // 25%
586 DWORD envpos = 0xFFFFFF;
587 const MODCHANNEL *pj = &Chn[m_nChannels];
588 for (UINT j=m_nChannels; j<MAX_CHANNELS; j++, pj++)
589 {
590 if (!pj->nFadeOutVol) return j;
591 DWORD v = pj->nVolume;
592 if (pj->dwFlags & CHN_NOTEFADE)
593 v = v * pj->nFadeOutVol;
594 else
595 v <<= 16;
596 if (pj->dwFlags & CHN_LOOP) v >>= 1;
597 if ((v < vol) || ((v == vol) && (pj->nVolEnvPosition > envpos)))
598 {
599 envpos = pj->nVolEnvPosition;
600 vol = v;
601 result = j;
602 }
603 }
604 return result;
605 }
606
607
608 void CSoundFile::CheckNNA(UINT nChn, UINT instr, int note, BOOL bForceCut)
609 //------------------------------------------------------------------------
610 {
611 MODCHANNEL *pChn = &Chn[nChn];
612 INSTRUMENTHEADER *penv = pChn->pHeader, *pHeader;
613 signed char *pSample;
614 if (note > 0x80) note = 0;
615 if (note < 1) return;
616 // Always NNA cut - using
617 if ((!(m_nType & (MOD_TYPE_IT|MOD_TYPE_MT2))) || (!m_nInstruments) || (bForceCut))
618 {
619 if ((m_dwSongFlags & SONG_CPUVERYHIGH)
620 || (!pChn->nLength) || (pChn->dwFlags & CHN_MUTE)
621 || ((!pChn->nLeftVol) && (!pChn->nRightVol))) return;
622 UINT n = GetNNAChannel(nChn);
623 if (!n) return;
624 MODCHANNEL *p = &Chn[n];
625 // Copy Channel
626 *p = *pChn;
627 p->dwFlags &= ~(CHN_VIBRATO|CHN_TREMOLO|CHN_PANBRELLO|CHN_MUTE|CHN_PORTAMENTO);
628 p->nMasterChn = nChn+1;
629 p->nCommand = 0;
630 // Cut the note
631 p->nFadeOutVol = 0;
632 p->dwFlags |= (CHN_NOTEFADE|CHN_FASTVOLRAMP);
633 // Stop this channel
634 pChn->nLength = pChn->nPos = pChn->nPosLo = 0;
635 pChn->nROfs = pChn->nLOfs = 0;
636 pChn->nLeftVol = pChn->nRightVol = 0;
637 return;
638 }
639 if (instr >= MAX_INSTRUMENTS) instr = 0;
640 pSample = pChn->pSample;
641 pHeader = pChn->pHeader;
642 if ((instr) && (note))
643 {
644 pHeader = Headers[instr];
645 if (pHeader)
646 {
647 UINT n = 0;
648 if (note <= 0x80)
649 {
650 n = pHeader->Keyboard[note-1];
651 note = pHeader->NoteMap[note-1];
652 if ((n) && (n < MAX_SAMPLES)) pSample = Ins[n].pSample;
653 }
654 } else pSample = NULL;
655 }
656 if (!penv) return;
657 MODCHANNEL *p = pChn;
658 for (UINT i=nChn; i<MAX_CHANNELS; p++, i++)
659 if ((i >= m_nChannels) || (p == pChn))
660 {
661 if (((p->nMasterChn == nChn+1) || (p == pChn)) && (p->pHeader))
662 {
663 BOOL bOk = FALSE;
664 // Duplicate Check Type
665 switch(p->pHeader->nDCT)
666 {
667 // Note
668 case DCT_NOTE:
669 if ((note) && (p->nNote == note) && (pHeader == p->pHeader)) bOk = TRUE;
670 break;
671 // Sample
672 case DCT_SAMPLE:
673 if ((pSample) && (pSample == p->pSample)) bOk = TRUE;
674 break;
675 // Instrument
676 case DCT_INSTRUMENT:
677 if (pHeader == p->pHeader) bOk = TRUE;
678 break;
679 }
680 // Duplicate Note Action
681 if (bOk)
682 {
683 switch(p->pHeader->nDNA)
684 {
685 // Cut
686 case DNA_NOTECUT:
687 KeyOff(i);
688 p->nVolume = 0;
689 break;
690 // Note Off
691 case DNA_NOTEOFF:
692 KeyOff(i);
693 break;
694 // Note Fade
695 case DNA_NOTEFADE:
696 p->dwFlags |= CHN_NOTEFADE;
697 break;
698 }
699 if (!p->nVolume)
700 {
701 p->nFadeOutVol = 0;
702 p->dwFlags |= (CHN_NOTEFADE|CHN_FASTVOLRAMP);
703 }
704 }
705 }
706 }
707 if (pChn->dwFlags & CHN_MUTE) return;
708 // New Note Action
709 if ((pChn->nVolume) && (pChn->nLength))
710 {
711 UINT n = GetNNAChannel(nChn);
712 if (n)
713 {
714 MODCHANNEL *p = &Chn[n];
715 // Copy Channel
716 *p = *pChn;
717 p->dwFlags &= ~(CHN_VIBRATO|CHN_TREMOLO|CHN_PANBRELLO|CHN_MUTE|CHN_PORTAMENTO);
718 p->nMasterChn = nChn+1;
719 p->nCommand = 0;
720 // Key Off the note
721 switch(pChn->nNNA)
722 {
723 case NNA_NOTEOFF: KeyOff(n); break;
724 case NNA_NOTECUT:
725 p->nFadeOutVol = 0;
726 case NNA_NOTEFADE: p->dwFlags |= CHN_NOTEFADE; break;
727 }
728 if (!p->nVolume)
729 {
730 p->nFadeOutVol = 0;
731 p->dwFlags |= (CHN_NOTEFADE|CHN_FASTVOLRAMP);
732 }
733 // Stop this channel
734 pChn->nLength = pChn->nPos = pChn->nPosLo = 0;
735 pChn->nROfs = pChn->nLOfs = 0;
736 }
737 }
738 }
739
740
741 BOOL CSoundFile::ProcessEffects()
742 //-------------------------------
743 {
744 int nBreakRow = -1, nPosJump = -1, nPatLoopRow = -1;
745 MODCHANNEL *pChn = Chn;
746 for (UINT nChn=0; nChn<m_nChannels; nChn++, pChn++)
747 {
748 UINT instr = pChn->nRowInstr;
749 UINT volcmd = pChn->nRowVolCmd;
750 UINT vol = pChn->nRowVolume;
751 UINT cmd = pChn->nRowCommand;
752 UINT param = pChn->nRowParam;
753 BOOL bPorta = ((cmd != CMD_TONEPORTAMENTO) && (cmd != CMD_TONEPORTAVOL) && (volcmd != VOLCMD_TONEPORTAMENTO)) ? FALSE : TRUE;
754 UINT nStartTick = 0;
755
756 pChn->dwFlags &= ~CHN_FASTVOLRAMP;
757 // Process special effects (note delay, pattern delay, pattern loop)
758 if ((cmd == CMD_MODCMDEX) || (cmd == CMD_S3MCMDEX))
759 {
760 if ((!param) && (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))) param = pChn->nOldCmdEx; else pChn->nOldCmdEx = param;
761 // Note Delay ?
762 if ((param & 0xF0) == 0xD0)
763 {
764 nStartTick = param & 0x0F;
765 } else
766 if (!m_nTickCount)
767 {
768 // Pattern Loop ?
769 if ((((param & 0xF0) == 0x60) && (cmd == CMD_MODCMDEX))
770 || (((param & 0xF0) == 0xB0) && (cmd == CMD_S3MCMDEX)))
771 {
772 int nloop = PatternLoop(pChn, param & 0x0F);
773 if (nloop >= 0) nPatLoopRow = nloop;
774 } else
775 // Pattern Delay
776 if ((param & 0xF0) == 0xE0)
777 {
778 m_nPatternDelay = param & 0x0F;
779 }
780 }
781 }
782
783 // Handles note/instrument/volume changes
784 if (m_nTickCount == nStartTick) // can be delayed by a note delay effect
785 {
786 UINT note = pChn->nRowNote;
787 if (instr) pChn->nNewIns = instr;
788 // XM: Key-Off + Sample == Note Cut
789 if (m_nType & (MOD_TYPE_MOD|MOD_TYPE_XM|MOD_TYPE_MT2))
790 {
791 if ((note == 0xFF) && ((!pChn->pHeader) || (!(pChn->pHeader->dwFlags & ENV_VOLUME))))
792 {
793 pChn->dwFlags |= CHN_FASTVOLRAMP;
794 pChn->nVolume = 0;
795 note = instr = 0;
796 }
797 }
798 if ((!note) && (instr))
799 {
800 if (m_nInstruments)
801 {
802 if (pChn->pInstrument) pChn->nVolume = pChn->pInstrument->nVolume;
803 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
804 {
805 pChn->dwFlags |= CHN_FASTVOLRAMP;
806 pChn->nVolEnvPosition = 0;
807 pChn->nPanEnvPosition = 0;
808 pChn->nPitchEnvPosition = 0;
809 pChn->nAutoVibDepth = 0;
810 pChn->nAutoVibPos = 0;
811 pChn->dwFlags &= ~CHN_NOTEFADE;
812 pChn->nFadeOutVol = 65536;
813 }
814 } else
815 {
816 if (instr < MAX_SAMPLES) pChn->nVolume = Ins[instr].nVolume;
817 }
818 if (!(m_nType & MOD_TYPE_IT)) instr = 0;
819 }
820 // Invalid Instrument ?
821 if (instr >= MAX_INSTRUMENTS) instr = 0;
822 // Note Cut/Off => ignore instrument
823 if (note >= 0xFE) instr = 0;
824 if ((note) && (note <= 128)) pChn->nNewNote = note;
825 // New Note Action ?
826 if ((note) && (note <= 128) && (!bPorta))
827 {
828 CheckNNA(nChn, instr, note, FALSE);
829 }
830 // Instrument Change ?
831 if (instr)
832 {
833 MODINSTRUMENT *psmp = pChn->pInstrument;
834 InstrumentChange(pChn, instr, bPorta, TRUE);
835 pChn->nNewIns = 0;
836 // Special IT case: portamento+note causes sample change -> ignore portamento
837 if ((m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))
838 && (psmp != pChn->pInstrument) && (note) && (note < 0x80))
839 {
840 bPorta = FALSE;
841 }
842 }
843 // New Note ?
844 if (note)
845 {
846 if ((!instr) && (pChn->nNewIns) && (note < 0x80))
847 {
848 InstrumentChange(pChn, pChn->nNewIns, bPorta, FALSE, (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) ? FALSE : TRUE);
849 pChn->nNewIns = 0;
850 }
851 NoteChange(nChn, note, bPorta, (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) ? FALSE : TRUE);
852 if ((bPorta) && (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) && (instr))
853 {
854 pChn->dwFlags |= CHN_FASTVOLRAMP;
855 pChn->nVolEnvPosition = 0;
856 pChn->nPanEnvPosition = 0;
857 pChn->nPitchEnvPosition = 0;
858 pChn->nAutoVibDepth = 0;
859 pChn->nAutoVibPos = 0;
860 }
861 }
862 // Tick-0 only volume commands
863 if (volcmd == VOLCMD_VOLUME)
864 {
865 if (vol > 64) vol = 64;
866 pChn->nVolume = vol << 2;
867 pChn->dwFlags |= CHN_FASTVOLRAMP;
868 } else
869 if (volcmd == VOLCMD_PANNING)
870 {
871 if (vol > 64) vol = 64;
872 pChn->nPan = vol << 2;
873 pChn->dwFlags |= CHN_FASTVOLRAMP;
874 }
875 }
876
877 // Volume Column Effect (except volume & panning)
878 if ((volcmd > VOLCMD_PANNING) && (m_nTickCount >= nStartTick))
879 {
880 if (volcmd == VOLCMD_TONEPORTAMENTO)
881 {
882 if (m_nType & MOD_TYPE_IT)
883 TonePortamento(pChn, ImpulseTrackerPortaVolCmd[vol & 0x0F]);
884 else
885 TonePortamento(pChn, vol * 16);
886 } else
887 {
888 if (vol) pChn->nOldVolParam = vol; else vol = pChn->nOldVolParam;
889 switch(volcmd)
890 {
891 case VOLCMD_VOLSLIDEUP:
892 VolumeSlide(pChn, vol << 4);
893 break;
894
895 case VOLCMD_VOLSLIDEDOWN:
896 VolumeSlide(pChn, vol);
897 break;
898
899 case VOLCMD_FINEVOLUP:
900 if (m_nType & MOD_TYPE_IT)
901 {
902 if (m_nTickCount == nStartTick) VolumeSlide(pChn, (vol << 4) | 0x0F);
903 } else
904 FineVolumeUp(pChn, vol);
905 break;
906
907 case VOLCMD_FINEVOLDOWN:
908 if (m_nType & MOD_TYPE_IT)
909 {
910 if (m_nTickCount == nStartTick) VolumeSlide(pChn, 0xF0 | vol);
911 } else
912 FineVolumeDown(pChn, vol);
913 break;
914
915 case VOLCMD_VIBRATOSPEED:
916 Vibrato(pChn, vol << 4);
917 break;
918
919 case VOLCMD_VIBRATO:
920 Vibrato(pChn, vol);
921 break;
922
923 case VOLCMD_PANSLIDELEFT:
924 PanningSlide(pChn, vol);
925 break;
926
927 case VOLCMD_PANSLIDERIGHT:
928 PanningSlide(pChn, vol << 4);
929 break;
930
931 case VOLCMD_PORTAUP:
932 PortamentoUp(pChn, vol << 2);
933 break;
934
935 case VOLCMD_PORTADOWN:
936 PortamentoDown(pChn, vol << 2);
937 break;
938 }
939 }
940 }
941
942 // Effects
943 if (cmd) switch (cmd)
944 {
945 // Set Volume
946 case CMD_VOLUME:
947 if (!m_nTickCount)
948 {
949 pChn->nVolume = (param < 64) ? param*4 : 256;
950 pChn->dwFlags |= CHN_FASTVOLRAMP;
951 }
952 break;
953
954 // Portamento Up
955 case CMD_PORTAMENTOUP:
956 if ((!param) && (m_nType & MOD_TYPE_MOD)) break;
957 PortamentoUp(pChn, param);
958 break;
959
960 // Portamento Down
961 case CMD_PORTAMENTODOWN:
962 if ((!param) && (m_nType & MOD_TYPE_MOD)) break;
963 PortamentoDown(pChn, param);
964 break;
965
966 // Volume Slide
967 case CMD_VOLUMESLIDE:
968 if ((param) || (m_nType != MOD_TYPE_MOD)) VolumeSlide(pChn, param);
969 break;
970
971 // Tone-Portamento
972 case CMD_TONEPORTAMENTO:
973 TonePortamento(pChn, param);
974 break;
975
976 // Tone-Portamento + Volume Slide
977 case CMD_TONEPORTAVOL:
978 if ((param) || (m_nType != MOD_TYPE_MOD)) VolumeSlide(pChn, param);
979 TonePortamento(pChn, 0);
980 break;
981
982 // Vibrato
983 case CMD_VIBRATO:
984 Vibrato(pChn, param);
985 break;
986
987 // Vibrato + Volume Slide
988 case CMD_VIBRATOVOL:
989 if ((param) || (m_nType != MOD_TYPE_MOD)) VolumeSlide(pChn, param);
990 Vibrato(pChn, 0);
991 break;
992
993 // Set Speed
994 case CMD_SPEED:
995 if (!m_nTickCount) SetSpeed(param);
996 break;
997
998 // Set Tempo
999 case CMD_TEMPO:
1000 if (!m_nTickCount)
1001 {
1002 if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))
1003 {
1004 if (param) pChn->nOldTempo = param; else param = pChn->nOldTempo;
1005 }
1006 SetTempo(param);
1007 }
1008 break;
1009
1010 // Set Offset
1011 case CMD_OFFSET:
1012 if (m_nTickCount) break;
1013 if (param) pChn->nOldOffset = param; else param = pChn->nOldOffset;
1014 param <<= 8;
1015 param |= (UINT)(pChn->nOldHiOffset) << 16;
1016 if ((pChn->nRowNote) && (pChn->nRowNote < 0x80))
1017 {
1018 if (bPorta)
1019 pChn->nPos = param;
1020 else
1021 pChn->nPos += param;
1022 if (pChn->nPos >= pChn->nLength)
1023 {
1024 if (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)))
1025 {
1026 pChn->nPos = pChn->nLoopStart;
1027 if ((m_dwSongFlags & SONG_ITOLDEFFECTS) && (pChn->nLength > 4))
1028 {
1029 pChn->nPos = pChn->nLength - 2;
1030 }
1031 }
1032 }
1033 } else
1034 if ((param < pChn->nLength) && (m_nType & (MOD_TYPE_MTM|MOD_TYPE_DMF)))
1035 {
1036 pChn->nPos = param;
1037 }
1038 break;
1039
1040 // Arpeggio
1041 case CMD_ARPEGGIO:
1042 if ((m_nTickCount) || (!pChn->nPeriod) || (!pChn->nNote)) break;
1043 if ((!param) && (!(m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT)))) break;
1044 pChn->nCommand = CMD_ARPEGGIO;
1045 if (param) pChn->nArpeggio = param;
1046 break;
1047
1048 // Retrig
1049 case CMD_RETRIG:
1050 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
1051 {
1052 if (!(param & 0xF0)) param |= pChn->nRetrigParam & 0xF0;
1053 if (!(param & 0x0F)) param |= pChn->nRetrigParam & 0x0F;
1054 param |= 0x100; // increment retrig count on first row
1055 }
1056 if (param) pChn->nRetrigParam = (BYTE)(param & 0xFF); else param = pChn->nRetrigParam;
1057 RetrigNote(nChn, param);
1058 break;
1059
1060 // Tremor
1061 case CMD_TREMOR:
1062 if (m_nTickCount) break;
1063 pChn->nCommand = CMD_TREMOR;
1064 if (param) pChn->nTremorParam = param;
1065 break;
1066
1067 // Set Global Volume
1068 case CMD_GLOBALVOLUME:
1069 if (m_nTickCount) break;
1070 if (m_nType != MOD_TYPE_IT) param <<= 1;
1071 if (param > 128) param = 128;
1072 m_nGlobalVolume = param << 1;
1073 break;
1074
1075 // Global Volume Slide
1076 case CMD_GLOBALVOLSLIDE:
1077 GlobalVolSlide(param);
1078 break;
1079
1080 // Set 8-bit Panning
1081 case CMD_PANNING8:
1082 if (m_nTickCount) break;
1083 if (!(m_dwSongFlags & SONG_SURROUNDPAN)) pChn->dwFlags &= ~CHN_SURROUND;
1084 if (m_nType & (MOD_TYPE_IT|MOD_TYPE_XM|MOD_TYPE_MT2))
1085 {
1086 pChn->nPan = param;
1087 } else
1088 if (param <= 0x80)
1089 {
1090 pChn->nPan = param << 1;
1091 } else
1092 if (param == 0xA4)
1093 {
1094 pChn->dwFlags |= CHN_SURROUND;
1095 pChn->nPan = 0x80;
1096 }
1097 pChn->dwFlags |= CHN_FASTVOLRAMP;
1098 break;
1099
1100 // Panning Slide
1101 case CMD_PANNINGSLIDE:
1102 PanningSlide(pChn, param);
1103 break;
1104
1105 // Tremolo
1106 case CMD_TREMOLO:
1107 Tremolo(pChn, param);
1108 break;
1109
1110 // Fine Vibrato
1111 case CMD_FINEVIBRATO:
1112 FineVibrato(pChn, param);
1113 break;
1114
1115 // MOD/XM Exx Extended Commands
1116 case CMD_MODCMDEX:
1117 ExtendedMODCommands(nChn, param);
1118 break;
1119
1120 // S3M/IT Sxx Extended Commands
1121 case CMD_S3MCMDEX:
1122 ExtendedS3MCommands(nChn, param);
1123 break;
1124
1125 // Key Off
1126 case CMD_KEYOFF:
1127 if (!m_nTickCount) KeyOff(nChn);
1128 break;
1129
1130 // Extra-fine porta up/down
1131 case CMD_XFINEPORTAUPDOWN:
1132 switch(param & 0xF0)
1133 {
1134 case 0x10: ExtraFinePortamentoUp(pChn, param & 0x0F); break;
1135 case 0x20: ExtraFinePortamentoDown(pChn, param & 0x0F); break;
1136 // Modplug XM Extensions
1137 case 0x50:
1138 case 0x60:
1139 case 0x70:
1140 case 0x90:
1141 case 0xA0: ExtendedS3MCommands(nChn, param); break;
1142 }
1143 break;
1144
1145 // Set Channel Global Volume
1146 case CMD_CHANNELVOLUME:
1147 if (m_nTickCount) break;
1148 if (param <= 64)
1149 {
1150 pChn->nGlobalVol = param;
1151 pChn->dwFlags |= CHN_FASTVOLRAMP;
1152 }
1153 break;
1154
1155 // Channel volume slide
1156 case CMD_CHANNELVOLSLIDE:
1157 ChannelVolSlide(pChn, param);
1158 break;
1159
1160 // Panbrello (IT)
1161 case CMD_PANBRELLO:
1162 Panbrello(pChn, param);
1163 break;
1164
1165 // Set Envelope Position
1166 case CMD_SETENVPOSITION:
1167 if (!m_nTickCount)
1168 {
1169 pChn->nVolEnvPosition = param;
1170 pChn->nPanEnvPosition = param;
1171 pChn->nPitchEnvPosition = param;
1172 if (pChn->pHeader)
1173 {
1174 INSTRUMENTHEADER *penv = pChn->pHeader;
1175 if ((pChn->dwFlags & CHN_PANENV) && (penv->nPanEnv) && (param > penv->PanPoints[penv->nPanEnv-1]))
1176 {
1177 pChn->dwFlags &= ~CHN_PANENV;
1178 }
1179 }
1180 }
1181 break;
1182
1183 // Position Jump
1184 case CMD_POSITIONJUMP:
1185 nPosJump = param;
1186 break;
1187
1188 // Pattern Break
1189 case CMD_PATTERNBREAK:
1190 nBreakRow = param;
1191 break;
1192
1193 // Midi Controller
1194 case CMD_MIDI:
1195 if (m_nTickCount) break;
1196 if (param < 0x80)
1197 {
1198 ProcessMidiMacro(nChn, &m_MidiCfg.szMidiSFXExt[pChn->nActiveMacro << 5], param);
1199 } else
1200 {
1201 ProcessMidiMacro(nChn, &m_MidiCfg.szMidiZXXExt[(param & 0x7F) << 5], 0);
1202 }
1203 break;
1204 }
1205 }
1206
1207 // Navigation Effects
1208 if (!m_nTickCount)
1209 {
1210 // Pattern Loop
1211 if (nPatLoopRow >= 0)
1212 {
1213 m_nNextPattern = m_nCurrentPattern;
1214 m_nNextRow = nPatLoopRow;
1215 if (m_nPatternDelay) m_nNextRow++;
1216 } else
1217 // Pattern Break / Position Jump only if no loop running
1218 if ((nBreakRow >= 0) || (nPosJump >= 0))
1219 {
1220 BOOL bNoLoop = FALSE;
1221 if (nPosJump < 0) nPosJump = m_nCurrentPattern+1;
1222 if (nBreakRow < 0) nBreakRow = 0;
1223 // Modplug Tracker & ModPlugin allow backward jumps
1224 #ifndef MODPLUG_FASTSOUNDLIB
1225 if ((nPosJump < (int)m_nCurrentPattern)
1226 || ((nPosJump == (int)m_nCurrentPattern) && (nBreakRow <= (int)m_nRow)))
1227 {
1228 if (!IsValidBackwardJump(m_nCurrentPattern, m_nRow, nPosJump, nBreakRow))
1229 {
1230 if (m_nRepeatCount)
1231 {
1232 if (m_nRepeatCount > 0) m_nRepeatCount--;
1233 } else
1234 {
1235 #ifdef MODPLUG_TRACKER
1236 if (gdwSoundSetup & SNDMIX_NOBACKWARDJUMPS)
1237 #endif
1238 // Backward jump disabled
1239 bNoLoop = TRUE;
1240 //reset repeat count incase there are multiple loops.
1241 //(i.e. Unreal tracks)
1242 m_nRepeatCount = m_nInitialRepeatCount;
1243 }
1244 }
1245 }
1246 #endif // MODPLUG_FASTSOUNDLIB
1247 if (((!bNoLoop) && (nPosJump < MAX_ORDERS))
1248 && ((nPosJump != (int)m_nCurrentPattern) || (nBreakRow != (int)m_nRow)))
1249 {
1250 if (nPosJump != (int)m_nCurrentPattern)
1251 {
1252 for (UINT i=0; i<m_nChannels; i++) Chn[i].nPatternLoopCount = 0;
1253 }
1254 m_nNextPattern = nPosJump;
1255 m_nNextRow = (UINT)nBreakRow;
1256 }
1257 }
1258 }
1259 return TRUE;
1260 }
1261
1262
1263 ////////////////////////////////////////////////////////////
1264 // Channels effects
1265
1266 void CSoundFile::PortamentoUp(MODCHANNEL *pChn, UINT param)
1267 //---------------------------------------------------------
1268 {
1269 if (param) pChn->nOldPortaUpDown = param; else param = pChn->nOldPortaUpDown;
1270 if ((m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM)) && ((param & 0xF0) >= 0xE0))
1271 {
1272 if (param & 0x0F)
1273 {
1274 if ((param & 0xF0) == 0xF0)
1275 {
1276 FinePortamentoUp(pChn, param & 0x0F);
1277 } else
1278 if ((param & 0xF0) == 0xE0)
1279 {
1280 ExtraFinePortamentoUp(pChn, param & 0x0F);
1281 }
1282 }
1283 return;
1284 }
1285 // Regular Slide
1286 if (!(m_dwSongFlags & SONG_FIRSTTICK))
1287 {
1288 DoFreqSlide(pChn, -(int)(param * 4));
1289 }
1290 }
1291
1292
1293 void CSoundFile::PortamentoDown(MODCHANNEL *pChn, UINT param)
1294 //-----------------------------------------------------------
1295 {
1296 if (param) pChn->nOldPortaUpDown = param; else param = pChn->nOldPortaUpDown;
1297 if ((m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM)) && ((param & 0xF0) >= 0xE0))
1298 {
1299 if (param & 0x0F)
1300 {
1301 if ((param & 0xF0) == 0xF0)
1302 {
1303 FinePortamentoDown(pChn, param & 0x0F);
1304 } else
1305 if ((param & 0xF0) == 0xE0)
1306 {
1307 ExtraFinePortamentoDown(pChn, param & 0x0F);
1308 }
1309 }
1310 return;
1311 }
1312 if (!(m_dwSongFlags & SONG_FIRSTTICK)) DoFreqSlide(pChn, (int)(param << 2));
1313 }
1314
1315
1316 void CSoundFile::FinePortamentoUp(MODCHANNEL *pChn, UINT param)
1317 //-------------------------------------------------------------
1318 {
1319 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
1320 {
1321 if (param) pChn->nOldFinePortaUpDown = param; else param = pChn->nOldFinePortaUpDown;
1322 }
1323 if (m_dwSongFlags & SONG_FIRSTTICK)
1324 {
1325 if ((pChn->nPeriod) && (param))
1326 {
1327 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))))
1328 {
1329 pChn->nPeriod = _muldivr(pChn->nPeriod, LinearSlideDownTable[param & 0x0F], 65536);
1330 } else
1331 {
1332 pChn->nPeriod -= (int)(param * 4);
1333 }
1334 if (pChn->nPeriod < 1) pChn->nPeriod = 1;
1335 }
1336 }
1337 }
1338
1339
1340 void CSoundFile::FinePortamentoDown(MODCHANNEL *pChn, UINT param)
1341 //---------------------------------------------------------------
1342 {
1343 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
1344 {
1345 if (param) pChn->nOldFinePortaUpDown = param; else param = pChn->nOldFinePortaUpDown;
1346 }
1347 if (m_dwSongFlags & SONG_FIRSTTICK)
1348 {
1349 if ((pChn->nPeriod) && (param))
1350 {
1351 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))))
1352 {
1353 pChn->nPeriod = _muldivr(pChn->nPeriod, LinearSlideUpTable[param & 0x0F], 65536);
1354 } else
1355 {
1356 pChn->nPeriod += (int)(param * 4);
1357 }
1358 if (pChn->nPeriod > 0xFFFF) pChn->nPeriod = 0xFFFF;
1359 }
1360 }
1361 }
1362
1363
1364 void CSoundFile::ExtraFinePortamentoUp(MODCHANNEL *pChn, UINT param)
1365 //------------------------------------------------------------------
1366 {
1367 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
1368 {
1369 if (param) pChn->nOldFinePortaUpDown = param; else param = pChn->nOldFinePortaUpDown;
1370 }
1371 if (m_dwSongFlags & SONG_FIRSTTICK)
1372 {
1373 if ((pChn->nPeriod) && (param))
1374 {
1375 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))))
1376 {
1377 pChn->nPeriod = _muldivr(pChn->nPeriod, FineLinearSlideDownTable[param & 0x0F], 65536);
1378 } else
1379 {
1380 pChn->nPeriod -= (int)(param);
1381 }
1382 if (pChn->nPeriod < 1) pChn->nPeriod = 1;
1383 }
1384 }
1385 }
1386
1387
1388 void CSoundFile::ExtraFinePortamentoDown(MODCHANNEL *pChn, UINT param)
1389 //--------------------------------------------------------------------
1390 {
1391 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
1392 {
1393 if (param) pChn->nOldFinePortaUpDown = param; else param = pChn->nOldFinePortaUpDown;
1394 }
1395 if (m_dwSongFlags & SONG_FIRSTTICK)
1396 {
1397 if ((pChn->nPeriod) && (param))
1398 {
1399 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))))
1400 {
1401 pChn->nPeriod = _muldivr(pChn->nPeriod, FineLinearSlideUpTable[param & 0x0F], 65536);
1402 } else
1403 {
1404 pChn->nPeriod += (int)(param);
1405 }
1406 if (pChn->nPeriod > 0xFFFF) pChn->nPeriod = 0xFFFF;
1407 }
1408 }
1409 }
1410
1411
1412 // Portamento Slide
1413 void CSoundFile::TonePortamento(MODCHANNEL *pChn, UINT param)
1414 //-----------------------------------------------------------
1415 {
1416 if (param) pChn->nPortamentoSlide = param * 4;
1417 pChn->dwFlags |= CHN_PORTAMENTO;
1418 if ((pChn->nPeriod) && (pChn->nPortamentoDest) && (!(m_dwSongFlags & SONG_FIRSTTICK)))
1419 {
1420 if (pChn->nPeriod < pChn->nPortamentoDest)
1421 {
1422 LONG delta = (int)pChn->nPortamentoSlide;
1423 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))))
1424 {
1425 UINT n = pChn->nPortamentoSlide >> 2;
1426 if (n > 255) n = 255;
1427 delta = _muldivr(pChn->nPeriod, LinearSlideUpTable[n], 65536) - pChn->nPeriod;
1428 if (delta < 1) delta = 1;
1429 }
1430 pChn->nPeriod += delta;
1431 if (pChn->nPeriod > pChn->nPortamentoDest) pChn->nPeriod = pChn->nPortamentoDest;
1432 } else
1433 if (pChn->nPeriod > pChn->nPortamentoDest)
1434 {
1435 LONG delta = - (int)pChn->nPortamentoSlide;
1436 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))))
1437 {
1438 UINT n = pChn->nPortamentoSlide >> 2;
1439 if (n > 255) n = 255;
1440 delta = _muldivr(pChn->nPeriod, LinearSlideDownTable[n], 65536) - pChn->nPeriod;
1441 if (delta > -1) delta = -1;
1442 }
1443 pChn->nPeriod += delta;
1444 if (pChn->nPeriod < pChn->nPortamentoDest) pChn->nPeriod = pChn->nPortamentoDest;
1445 }
1446 }
1447 }
1448
1449
1450 void CSoundFile::Vibrato(MODCHANNEL *p, UINT param)
1451 //-------------------------------------------------
1452 {
1453 if (param & 0x0F) p->nVibratoDepth = (param & 0x0F) * 4;
1454 if (param & 0xF0) p->nVibratoSpeed = (param >> 4) & 0x0F;
1455 p->dwFlags |= CHN_VIBRATO;
1456 }
1457
1458
1459 void CSoundFile::FineVibrato(MODCHANNEL *p, UINT param)
1460 //-----------------------------------------------------
1461 {
1462 if (param & 0x0F) p->nVibratoDepth = param & 0x0F;
1463 if (param & 0xF0) p->nVibratoSpeed = (param >> 4) & 0x0F;
1464 p->dwFlags |= CHN_VIBRATO;
1465 }
1466
1467
1468 void CSoundFile::Panbrello(MODCHANNEL *p, UINT param)
1469 //---------------------------------------------------
1470 {
1471 if (param & 0x0F) p->nPanbrelloDepth = param & 0x0F;
1472 if (param & 0xF0) p->nPanbrelloSpeed = (param >> 4) & 0x0F;
1473 p->dwFlags |= CHN_PANBRELLO;
1474 }
1475
1476
1477 void CSoundFile::VolumeSlide(MODCHANNEL *pChn, UINT param)
1478 //--------------------------------------------------------
1479 {
1480 if (param) pChn->nOldVolumeSlide = param; else param = pChn->nOldVolumeSlide;
1481 LONG newvolume = pChn->nVolume;
1482 if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM|MOD_TYPE_AMF))
1483 {
1484 if ((param & 0x0F) == 0x0F)
1485 {
1486 if (param & 0xF0)
1487 {
1488 FineVolumeUp(pChn, (param >> 4));
1489 return;
1490 } else
1491 {
1492 if ((m_dwSongFlags & SONG_FIRSTTICK) && (!(m_dwSongFlags & SONG_FASTVOLSLIDES)))
1493 {
1494 newvolume -= 0x0F * 4;
1495 }
1496 }
1497 } else
1498 if ((param & 0xF0) == 0xF0)
1499 {
1500 if (param & 0x0F)
1501 {
1502 FineVolumeDown(pChn, (param & 0x0F));
1503 return;
1504 } else
1505 {
1506 if ((m_dwSongFlags & SONG_FIRSTTICK) && (!(m_dwSongFlags & SONG_FASTVOLSLIDES)))
1507 {
1508 newvolume += 0x0F * 4;
1509 }
1510 }
1511 }
1512 }
1513 if ((!(m_dwSongFlags & SONG_FIRSTTICK)) || (m_dwSongFlags & SONG_FASTVOLSLIDES))
1514 {
1515 if (param & 0x0F) newvolume -= (int)((param & 0x0F) * 4);
1516 else newvolume += (int)((param & 0xF0) >> 2);
1517 if (m_nType & MOD_TYPE_MOD) pChn->dwFlags |= CHN_FASTVOLRAMP;
1518 }
1519 if (newvolume < 0) newvolume = 0;
1520 if (newvolume > 256) newvolume = 256;
1521 pChn->nVolume = newvolume;
1522 }
1523
1524
1525 void CSoundFile::PanningSlide(MODCHANNEL *pChn, UINT param)
1526 //---------------------------------------------------------
1527 {
1528 LONG nPanSlide = 0;
1529 if (param) pChn->nOldPanSlide = param; else param = pChn->nOldPanSlide;
1530 if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM))
1531 {
1532 if (((param & 0x0F) == 0x0F) && (param & 0xF0))
1533 {
1534 if (m_dwSongFlags & SONG_FIRSTTICK)
1535 {
1536 param = (param & 0xF0) >> 2;
1537 nPanSlide = - (int)param;
1538 }
1539 } else
1540 if (((param & 0xF0) == 0xF0) && (param & 0x0F))
1541 {
1542 if (m_dwSongFlags & SONG_FIRSTTICK)
1543 {
1544 nPanSlide = (param & 0x0F) << 2;
1545 }
1546 } else
1547 {
1548 if (!(m_dwSongFlags & SONG_FIRSTTICK))
1549 {
1550 if (param & 0x0F) nPanSlide = (int)((param & 0x0F) << 2);
1551 else nPanSlide = -(int)((param & 0xF0) >> 2);
1552 }
1553 }
1554 } else
1555 {
1556 if (!(m_dwSongFlags & SONG_FIRSTTICK))
1557 {
1558 if (param & 0x0F) nPanSlide = -(int)((param & 0x0F) << 2);
1559 else nPanSlide = (int)((param & 0xF0) >> 2);
1560 }
1561 }
1562 if (nPanSlide)
1563 {
1564 nPanSlide += pChn->nPan;
1565 if (nPanSlide < 0) nPanSlide = 0;
1566 if (nPanSlide > 256) nPanSlide = 256;
1567 pChn->nPan = nPanSlide;
1568 }
1569 }
1570
1571
1572 void CSoundFile::FineVolumeUp(MODCHANNEL *pChn, UINT param)
1573 //---------------------------------------------------------
1574 {
1575 if (param) pChn->nOldFineVolUpDown = param; else param = pChn->nOldFineVolUpDown;
1576 if (m_dwSongFlags & SONG_FIRSTTICK)
1577 {
1578 pChn->nVolume += param * 4;
1579 if (pChn->nVolume > 256) pChn->nVolume = 256;
1580 if (m_nType & MOD_TYPE_MOD) pChn->dwFlags |= CHN_FASTVOLRAMP;
1581 }
1582 }
1583
1584
1585 void CSoundFile::FineVolumeDown(MODCHANNEL *pChn, UINT param)
1586 //-----------------------------------------------------------
1587 {
1588 if (param) pChn->nOldFineVolUpDown = param; else param = pChn->nOldFineVolUpDown;
1589 if (m_dwSongFlags & SONG_FIRSTTICK)
1590 {
1591 pChn->nVolume -= param * 4;
1592 if (pChn->nVolume < 0) pChn->nVolume = 0;
1593 if (m_nType & MOD_TYPE_MOD) pChn->dwFlags |= CHN_FASTVOLRAMP;
1594 }
1595 }
1596
1597
1598 void CSoundFile::Tremolo(MODCHANNEL *p, UINT param)
1599 //-------------------------------------------------
1600 {
1601 if (param & 0x0F) p->nTremoloDepth = (param & 0x0F) << 2;
1602 if (param & 0xF0) p->nTremoloSpeed = (param >> 4) & 0x0F;
1603 p->dwFlags |= CHN_TREMOLO;
1604 }
1605
1606
1607 void CSoundFile::ChannelVolSlide(MODCHANNEL *pChn, UINT param)
1608 //------------------------------------------------------------
1609 {
1610 LONG nChnSlide = 0;
1611 if (param) pChn->nOldChnVolSlide = param; else param = pChn->nOldChnVolSlide;
1612 if (((param & 0x0F) == 0x0F) && (param & 0xF0))
1613 {
1614 if (m_dwSongFlags & SONG_FIRSTTICK) nChnSlide = param >> 4;
1615 } else
1616 if (((param & 0xF0) == 0xF0) && (param & 0x0F))
1617 {
1618 if (m_dwSongFlags & SONG_FIRSTTICK) nChnSlide = - (int)(param & 0x0F);
1619 } else
1620 {
1621 if (!(m_dwSongFlags & SONG_FIRSTTICK))
1622 {
1623 if (param & 0x0F) nChnSlide = -(int)(param & 0x0F);
1624 else nChnSlide = (int)((param & 0xF0) >> 4);
1625 }
1626 }
1627 if (nChnSlide)
1628 {
1629 nChnSlide += pChn->nGlobalVol;
1630 if (nChnSlide < 0) nChnSlide = 0;
1631 if (nChnSlide > 64) nChnSlide = 64;
1632 pChn->nGlobalVol = nChnSlide;
1633 }
1634 }
1635
1636
1637 void CSoundFile::ExtendedMODCommands(UINT nChn, UINT param)
1638 //---------------------------------------------------------
1639 {
1640 MODCHANNEL *pChn = &Chn[nChn];
1641 UINT command = param & 0xF0;
1642 param &= 0x0F;
1643 switch(command)
1644 {
1645 // E0x: Set Filter
1646 // E1x: Fine Portamento Up
1647 case 0x10: if ((param) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) FinePortamentoUp(pChn, param); break;
1648 // E2x: Fine Portamento Down
1649 case 0x20: if ((param) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) FinePortamentoDown(pChn, param); break;
1650 // E3x: Set Glissando Control
1651 case 0x30: pChn->dwFlags &= ~CHN_GLISSANDO; if (param) pChn->dwFlags |= CHN_GLISSANDO; break;
1652 // E4x: Set Vibrato WaveForm
1653 case 0x40: pChn->nVibratoType = param & 0x07; break;
1654 // E5x: Set FineTune
1655 case 0x50: if (m_nTickCount) break;
1656 pChn->nC4Speed = S3MFineTuneTable[param];
1657 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
1658 pChn->nFineTune = param*2;
1659 else
1660 pChn->nFineTune = MOD2XMFineTune(param);
1661 if (pChn->nPeriod) pChn->nPeriod = GetPeriodFromNote(pChn->nNote, pChn->nFineTune, pChn->nC4Speed);
1662 break;
1663 // E6x: Pattern Loop
1664 // E7x: Set Tremolo WaveForm
1665 case 0x70: pChn->nTremoloType = param & 0x07; break;
1666 // E8x: Set 4-bit Panning
1667 case 0x80: if (!m_nTickCount) { pChn->nPan = (param << 4) + 8; pChn->dwFlags |= CHN_FASTVOLRAMP; } break;
1668 // E9x: Retrig
1669 case 0x90: RetrigNote(nChn, param); break;
1670 // EAx: Fine Volume Up
1671 case 0xA0: if ((param) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) FineVolumeUp(pChn, param); break;
1672 // EBx: Fine Volume Down
1673 case 0xB0: if ((param) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) FineVolumeDown(pChn, param); break;
1674 // ECx: Note Cut
1675 case 0xC0: NoteCut(nChn, param); break;
1676 // EDx: Note Delay
1677 // EEx: Pattern Delay
1678 // EFx: MOD: Invert Loop, XM: Set Active Midi Macro
1679 case 0xF0: pChn->nActiveMacro = param; break;
1680 }
1681 }
1682
1683
1684 void CSoundFile::ExtendedS3MCommands(UINT nChn, UINT param)
1685 //---------------------------------------------------------
1686 {
1687 MODCHANNEL *pChn = &Chn[nChn];
1688 UINT command = param & 0xF0;
1689 param &= 0x0F;
1690 switch(command)
1691 {
1692 // S0x: Set Filter
1693 // S1x: Set Glissando Control
1694 case 0x10: pChn->dwFlags &= ~CHN_GLISSANDO; if (param) pChn->dwFlags |= CHN_GLISSANDO; break;
1695 // S2x: Set FineTune
1696 case 0x20: if (m_nTickCount) break;
1697 pChn->nC4Speed = S3MFineTuneTable[param & 0x0F];
1698 pChn->nFineTune = MOD2XMFineTune(param);
1699 if (pChn->nPeriod) pChn->nPeriod = GetPeriodFromNote(pChn->nNote, pChn->nFineTune, pChn->nC4Speed);
1700 break;
1701 // S3x: Set Vibrato WaveForm
1702 case 0x30: pChn->nVibratoType = param & 0x07; break;
1703 // S4x: Set Tremolo WaveForm
1704 case 0x40: pChn->nTremoloType = param & 0x07; break;
1705 // S5x: Set Panbrello WaveForm
1706 case 0x50: pChn->nPanbrelloType = param & 0x07; break;
1707 // S6x: Pattern Delay for x frames
1708 case 0x60: m_nFrameDelay = param; break;
1709 // S7x: Envelope Control
1710 case 0x70: if (m_nTickCount) break;
1711 switch(param)
1712 {
1713 case 0:
1714 case 1:
1715 case 2:
1716 {
1717 MODCHANNEL *bkp = &Chn[m_nChannels];
1718 for (UINT i=m_nChannels; i<MAX_CHANNELS; i++, bkp++)
1719 {
1720 if (bkp->nMasterChn == nChn+1)
1721 {
1722 if (param == 1) KeyOff(i); else
1723 if (param == 2) bkp->dwFlags |= CHN_NOTEFADE; else
1724 { bkp->dwFlags |= CHN_NOTEFADE; bkp->nFadeOutVol = 0; }
1725 }
1726 }
1727 }
1728 break;
1729 case 3: pChn->nNNA = NNA_NOTECUT; break;
1730 case 4: pChn->nNNA = NNA_CONTINUE; break;
1731 case 5: pChn->nNNA = NNA_NOTEOFF; break;
1732 case 6: pChn->nNNA = NNA_NOTEFADE; break;
1733 case 7: pChn->dwFlags &= ~CHN_VOLENV; break;
1734 case 8: pChn->dwFlags |= CHN_VOLENV; break;
1735 case 9: pChn->dwFlags &= ~CHN_PANENV; break;
1736 case 10: pChn->dwFlags |= CHN_PANENV; break;
1737 case 11: pChn->dwFlags &= ~CHN_PITCHENV; break;
1738 case 12: pChn->dwFlags |= CHN_PITCHENV; break;
1739 }
1740 break;
1741 // S8x: Set 4-bit Panning
1742 case 0x80: if (!m_nTickCount) { pChn->nPan = (param << 4) + 8; pChn->dwFlags |= CHN_FASTVOLRAMP; } break;
1743 // S9x: Set Surround
1744 case 0x90: ExtendedChannelEffect(pChn, param & 0x0F); break;
1745 // SAx: Set 64k Offset
1746 case 0xA0: if (!m_nTickCount)
1747 {
1748 pChn->nOldHiOffset = param;
1749 if ((pChn->nRowNote) && (pChn->nRowNote < 0x80))
1750 {
1751 DWORD pos = param << 16;
1752 if (pos < pChn->nLength) pChn->nPos = pos;
1753 }
1754 }
1755 break;
1756 // SBx: Pattern Loop
1757 // SCx: Note Cut
1758 case 0xC0: NoteCut(nChn, param); break;
1759 // SDx: Note Delay
1760 // case 0xD0: break;
1761 // SEx: Pattern Delay for x rows
1762 // SFx: S3M: Funk Repeat, IT: Set Active Midi Macro
1763 case 0xF0: pChn->nActiveMacro = param; break;
1764 }
1765 }
1766
1767
1768 void CSoundFile::ExtendedChannelEffect(MODCHANNEL *pChn, UINT param)
1769 //------------------------------------------------------------------
1770 {
1771 // S9x and X9x commands (S3M/XM/IT only)
1772 if (m_nTickCount) return;
1773 switch(param & 0x0F)
1774 {
1775 // S90: Surround Off
1776 case 0x00: pChn->dwFlags &= ~CHN_SURROUND; break;
1777 // S91: Surround On
1778 case 0x01: pChn->dwFlags |= CHN_SURROUND; pChn->nPan = 128; break;
1779 ////////////////////////////////////////////////////////////
1780 // Modplug Extensions
1781 // S98: Reverb Off
1782 case 0x08:
1783 pChn->dwFlags &= ~CHN_REVERB;
1784 pChn->dwFlags |= CHN_NOREVERB;
1785 break;
1786 // S99: Reverb On
1787 case 0x09:
1788 pChn->dwFlags &= ~CHN_NOREVERB;
1789 pChn->dwFlags |= CHN_REVERB;
1790 break;
1791 // S9A: 2-Channels surround mode
1792 case 0x0A:
1793 m_dwSongFlags &= ~SONG_SURROUNDPAN;
1794 break;
1795 // S9B: 4-Channels surround mode
1796 case 0x0B:
1797 m_dwSongFlags |= SONG_SURROUNDPAN;
1798 break;
1799 // S9C: IT Filter Mode
1800 case 0x0C:
1801 m_dwSongFlags &= ~SONG_MPTFILTERMODE;
1802 break;
1803 // S9D: MPT Filter Mode
1804 case 0x0D:
1805 m_dwSongFlags |= SONG_MPTFILTERMODE;
1806 break;
1807 // S9E: Go forward
1808 case 0x0E:
1809 pChn->dwFlags &= ~(CHN_PINGPONGFLAG);
1810 break;
1811 // S9F: Go backward (set position at the end for non-looping samples)
1812 case 0x0F:
1813 if ((!(pChn->dwFlags & CHN_LOOP)) && (!pChn->nPos) && (pChn->nLength))
1814 {
1815 pChn->nPos = pChn->nLength - 1;
1816 pChn->nPosLo = 0xFFFF;
1817 }
1818 pChn->dwFlags |= CHN_PINGPONGFLAG;
1819 break;
1820 }
1821 }
1822
1823
1824 void CSoundFile::ProcessMidiMacro(UINT nChn, LPCSTR pszMidiMacro, UINT param)
1825 //---------------------------------------------------------------------------
1826 {
1827 MODCHANNEL *pChn = &Chn[nChn];
1828 DWORD dwMacro = (*((LPDWORD)pszMidiMacro)) & 0x7F5F7F5F;
1829 // Not Internal Device ?
1830 if (dwMacro != 0x30463046)
1831 {
1832 UINT pos = 0, nNib = 0, nBytes = 0;
1833 DWORD dwMidiCode = 0, dwByteCode = 0;
1834 while (pos+6 <= 32)
1835 {
1836 CHAR cData = pszMidiMacro[pos++];
1837 if (!cData) break;
1838 if ((cData >= '0') && (cData <= '9')) { dwByteCode = (dwByteCode<<4) | (cData-'0'); nNib++; } else
1839 if ((cData >= 'A') && (cData <= 'F')) { dwByteCode = (dwByteCode<<4) | (cData-'A'+10); nNib++; } else
1840 if ((cData >= 'a') && (cData <= 'f')) { dwByteCode = (dwByteCode<<4) | (cData-'a'+10); nNib++; } else
1841 if ((cData == 'z') || (cData == 'Z')) { dwByteCode = param & 0x7f; nNib = 2; } else
1842 if ((cData == 'x') || (cData == 'X')) { dwByteCode = param & 0x70; nNib = 2; } else
1843 if ((cData == 'y') || (cData == 'Y')) { dwByteCode = (param & 0x0f)<<3; nNib = 2; } else
1844 if (nNib >= 2)
1845 {
1846 nNib = 0;
1847 dwMidiCode |= dwByteCode << (nBytes*8);
1848 dwByteCode = 0;
1849 nBytes++;
1850 if (nBytes >= 3)
1851 {
1852 UINT nMasterCh = (nChn < m_nChannels) ? nChn+1 : pChn->nMasterChn;
1853 if ((nMasterCh) && (nMasterCh <= m_nChannels))
1854 {
1855 UINT nPlug = ChnSettings[nMasterCh-1].nMixPlugin;
1856 if ((nPlug) && (nPlug <= MAX_MIXPLUGINS))
1857 {
1858 IMixPlugin *pPlugin = m_MixPlugins[nPlug-1].pMixPlugin;
1859 if ((pPlugin) && (m_MixPlugins[nPlug-1].pMixState))
1860 {
1861 pPlugin->MidiSend(dwMidiCode);
1862 }
1863 }
1864 }
1865 nBytes = 0;
1866 dwMidiCode = 0;
1867 }
1868 }
1869
1870 }
1871 return;
1872 }
1873 // Internal device
1874 pszMidiMacro += 4;
1875 // Filter ?
1876 if (pszMidiMacro[0] == '0')
1877 {
1878 CHAR cData1 = pszMidiMacro[2];
1879 DWORD dwParam = 0;
1880 if ((cData1 == 'z') || (cData1 == 'Z'))
1881 {
1882 dwParam = param;
1883 } else
1884 {
1885 CHAR cData2 = pszMidiMacro[3];
1886 if ((cData1 >= '0') && (cData1 <= '9')) dwParam += (cData1 - '0') << 4; else
1887 if ((cData1 >= 'A') && (cData1 <= 'F')) dwParam += (cData1 - 'A' + 0x0A) << 4;
1888 if ((cData2 >= '0') && (cData2 <= '9')) dwParam += (cData2 - '0'); else
1889 if ((cData2 >= 'A') && (cData2 <= 'F')) dwParam += (cData2 - 'A' + 0x0A);
1890 }
1891 switch(pszMidiMacro[1])
1892 {
1893 // F0.F0.00.xx: Set CutOff
1894 case '0':
1895 {
1896 int oldcutoff = pChn->nCutOff;
1897 if (dwParam < 0x80) pChn->nCutOff = dwParam;
1898 #ifndef NO_FILTER
1899 oldcutoff -= pChn->nCutOff;
1900
1901 if (oldcutoff < 0) oldcutoff = -oldcutoff;
1902 if ((pChn->nVolume > 0) || (oldcutoff < 0x10)
1903 || (!(pChn->dwFlags & CHN_FILTER)) || (!(pChn->nLeftVol|pChn->nRightVol)))
1904 SetupChannelFilter(pChn, (pChn->dwFlags & CHN_FILTER) ? FALSE : TRUE);
1905 #endif // NO_FILTER
1906 }
1907 break;
1908
1909 // F0.F0.01.xx: Set Resonance
1910 case '1':
1911 if (dwParam < 0x80) pChn->nResonance = dwParam;
1912 #ifndef NO_FILTER
1913 SetupChannelFilter(pChn, (pChn->dwFlags & CHN_FILTER) ? FALSE : TRUE);
1914 #endif // NO_FILTER
1915
1916 break;
1917 }
1918
1919 }
1920 }
1921
1922
1923 void CSoundFile::RetrigNote(UINT nChn, UINT param)
1924 //------------------------------------------------
1925 {
1926 // Retrig: bit 8 is set if it's the new XM retrig
1927 MODCHANNEL *pChn = &Chn[nChn];
1928 UINT nRetrigSpeed = param & 0x0F;
1929 UINT nRetrigCount = pChn->nRetrigCount;
1930 BOOL bDoRetrig = FALSE;
1931
1932 if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))
1933 {
1934 if (!nRetrigSpeed) nRetrigSpeed = 1;
1935 if ((nRetrigCount) && (!(nRetrigCount % nRetrigSpeed))) bDoRetrig = TRUE;
1936 nRetrigCount++;
1937 } else
1938 {
1939 UINT realspeed = nRetrigSpeed;
1940 if ((param & 0x100) && (pChn->nRowVolCmd == VOLCMD_VOLUME) && (pChn->nRowParam & 0xF0)) realspeed++;
1941 if ((m_nTickCount) || (param & 0x100))
1942 {
1943 if (!realspeed) realspeed = 1;
1944 if ((!(param & 0x100)) && (m_nMusicSpeed) && (!(m_nTickCount % realspeed))) bDoRetrig = TRUE;
1945 nRetrigCount++;
1946 } else if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) nRetrigCount = 0;
1947 if (nRetrigCount >= realspeed)
1948 {
1949 if ((m_nTickCount) || ((param & 0x100) && (!pChn->nRowNote))) bDoRetrig = TRUE;
1950 }
1951 }
1952 if (bDoRetrig)
1953 {
1954 UINT dv = (param >> 4) & 0x0F;
1955 if (dv)
1956 {
1957 int vol = pChn->nVolume;
1958 if (retrigTable1[dv])
1959 vol = (vol * retrigTable1[dv]) >> 4;
1960 else
1961 vol += ((int)retrigTable2[dv]) << 2;
1962 if (vol < 0) vol = 0;
1963 if (vol > 256) vol = 256;
1964 pChn->nVolume = vol;
1965 pChn->dwFlags |= CHN_FASTVOLRAMP;
1966 }
1967 UINT nNote = pChn->nNewNote;
1968 LONG nOldPeriod = pChn->nPeriod;
1969 if ((nNote) && (nNote <= 120) && (pChn->nLength)) CheckNNA(nChn, 0, nNote, TRUE);
1970 BOOL bResetEnv = FALSE;
1971 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
1972 {
1973 if ((pChn->nRowInstr) && (param < 0x100)) { InstrumentChange(pChn, pChn->nRowInstr, FALSE, FALSE); bResetEnv = TRUE; }
1974 if (param < 0x100) bResetEnv = TRUE;
1975 }
1976 NoteChange(nChn, nNote, FALSE, bResetEnv);
1977 if ((m_nType & MOD_TYPE_IT) && (!pChn->nRowNote) && (nOldPeriod)) pChn->nPeriod = nOldPeriod;
1978 if (!(m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))) nRetrigCount = 0;
1979 }
1980 pChn->nRetrigCount = (BYTE)nRetrigCount;
1981 }
1982
1983
1984 void CSoundFile::DoFreqSlide(MODCHANNEL *pChn, LONG nFreqSlide)
1985 //-------------------------------------------------------------
1986 {
1987 // IT Linear slides
1988 if (!pChn->nPeriod) return;
1989 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))))
1990 {
1991 if (nFreqSlide < 0)
1992 {
1993 UINT n = (- nFreqSlide) >> 2;
1994 if (n > 255) n = 255;
1995 pChn->nPeriod = _muldivr(pChn->nPeriod, LinearSlideDownTable[n], 65536);
1996 } else
1997 {
1998 UINT n = (nFreqSlide) >> 2;
1999
2000 if (n > 255) n = 255;
2001 pChn->nPeriod = _muldivr(pChn->nPeriod, LinearSlideUpTable[n], 65536);
2002 }
2003 } else
2004 {
2005 pChn->nPeriod += nFreqSlide;
2006 }
2007 if (pChn->nPeriod < 1)
2008 {
2009 pChn->nPeriod = 1;
2010 if (m_nType & MOD_TYPE_IT)
2011 {
2012 pChn->dwFlags |= CHN_NOTEFADE;
2013 pChn->nFadeOutVol = 0;
2014 }
2015 }
2016 }
2017
2018
2019 void CSoundFile::NoteCut(UINT nChn, UINT nTick)
2020 //---------------------------------------------
2021 {
2022 if (m_nTickCount == nTick)
2023 {
2024 MODCHANNEL *pChn = &Chn[nChn];
2025 // if (m_nInstruments) KeyOff(pChn); ?
2026 pChn->nVolume = 0;
2027 pChn->dwFlags |= CHN_FASTVOLRAMP;
2028 }
2029 }
2030
2031
2032 void CSoundFile::KeyOff(UINT nChn)
2033 //--------------------------------
2034 {
2035 MODCHANNEL *pChn = &Chn[nChn];
2036 BOOL bKeyOn = (pChn->dwFlags & CHN_KEYOFF) ? FALSE : TRUE;
2037 pChn->dwFlags |= CHN_KEYOFF;
2038 //if ((!pChn->pHeader) || (!(pChn->dwFlags & CHN_VOLENV)))
2039 if ((pChn->pHeader) && (!(pChn->dwFlags & CHN_VOLENV)))
2040 {
2041 pChn->dwFlags |= CHN_NOTEFADE;
2042 }
2043 if (!pChn->nLength) return;
2044 if ((pChn->dwFlags & CHN_SUSTAINLOOP) && (pChn->pInstrument) && (bKeyOn))
2045 {
2046 MODINSTRUMENT *psmp = pChn->pInstrument;
2047 if (psmp->uFlags & CHN_LOOP)
2048 {
2049 if (psmp->uFlags & CHN_PINGPONGLOOP)
2050 pChn->dwFlags |= CHN_PINGPONGLOOP;
2051 else
2052 pChn->dwFlags &= ~(CHN_PINGPONGLOOP|CHN_PINGPONGFLAG);
2053 pChn->dwFlags |= CHN_LOOP;
2054 pChn->nLength = psmp->nLength;
2055 pChn->nLoopStart = psmp->nLoopStart;
2056 pChn->nLoopEnd = psmp->nLoopEnd;
2057 if (pChn->nLength > pChn->nLoopEnd) pChn->nLength = pChn->nLoopEnd;
2058 } else
2059 {
2060 pChn->dwFlags &= ~(CHN_LOOP|CHN_PINGPONGLOOP|CHN_PINGPONGFLAG);
2061 pChn->nLength = psmp->nLength;
2062 }
2063 }
2064 if (pChn->pHeader)
2065 {
2066 INSTRUMENTHEADER *penv = pChn->pHeader;
2067 if (((penv->dwFlags & ENV_VOLLOOP) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) && (penv->nFadeOut))
2068 pChn->dwFlags |= CHN_NOTEFADE;
2069 }
2070 }
2071
2072
2073 //////////////////////////////////////////////////////////
2074 // CSoundFile: Global Effects
2075
2076
2077 void CSoundFile::SetSpeed(UINT param)
2078 //-----------------------------------
2079 {
2080 UINT max = (m_nType == MOD_TYPE_IT) ? 256 : 128;
2081 // Modplug Tracker and Mod-Plugin don't do this check
2082 #ifndef MODPLUG_TRACKER
2083 #ifndef MODPLUG_FASTSOUNDLIB
2084 // Big Hack!!!
2085 if ((!param) || (param >= 0x80) || ((m_nType & (MOD_TYPE_MOD|MOD_TYPE_XM|MOD_TYPE_MT2)) && (param >= 0x1E)))
2086 {
2087 if (IsSongFinished(m_nCurrentPattern, m_nRow+1))
2088 {
2089 GlobalFadeSong(1000);
2090 }
2091 }
2092 #endif // MODPLUG_FASTSOUNDLIB
2093 #endif // MODPLUG_TRACKER
2094 if ((m_nType & MOD_TYPE_S3M) && (param > 0x80)) param -= 0x80;
2095 if ((param) && (param <= max)) m_nMusicSpeed = param;
2096 }
2097
2098
2099 void CSoundFile::SetTempo(UINT param)
2100 //-----------------------------------
2101 {
2102 if (param < 0x20)
2103 {
2104 // Tempo Slide
2105 if ((param & 0xF0) == 0x10)
2106 {
2107 m_nMusicTempo += (param & 0x0F) * 2;
2108 if (m_nMusicTempo > 255) m_nMusicTempo = 255;
2109 } else
2110 {
2111 m_nMusicTempo -= (param & 0x0F) * 2;
2112 if ((LONG)m_nMusicTempo < 32) m_nMusicTempo = 32;
2113 }
2114 } else
2115 {
2116 m_nMusicTempo = param;
2117 }
2118 }
2119
2120
2121 int CSoundFile::PatternLoop(MODCHANNEL *pChn, UINT param)
2122 //-------------------------------------------------------
2123 {
2124 if (param)
2125 {
2126 if (pChn->nPatternLoopCount)
2127 {
2128 pChn->nPatternLoopCount--;
2129 if (!pChn->nPatternLoopCount) return -1;
2130 } else
2131 {
2132 MODCHANNEL *p = Chn;
2133 for (UINT i=0; i<m_nChannels; i++, p++) if (p != pChn)
2134 {
2135 // Loop already done
2136 if (p->nPatternLoopCount) return -1;
2137 }
2138 pChn->nPatternLoopCount = param;
2139 }
2140 return pChn->nPatternLoop;
2141 } else
2142 {
2143 pChn->nPatternLoop = m_nRow;
2144 }
2145 return -1;
2146 }
2147
2148
2149 void CSoundFile::GlobalVolSlide(UINT param)
2150 //-----------------------------------------
2151 {
2152 LONG nGlbSlide = 0;
2153 if (param) m_nOldGlbVolSlide = param; else param = m_nOldGlbVolSlide;
2154 if (((param & 0x0F) == 0x0F) && (param & 0xF0))
2155 {
2156 if (m_dwSongFlags & SONG_FIRSTTICK) nGlbSlide = (param >> 4) * 2;
2157 } else
2158 if (((param & 0xF0) == 0xF0) && (param & 0x0F))
2159 {
2160 if (m_dwSongFlags & SONG_FIRSTTICK) nGlbSlide = - (int)((param & 0x0F) * 2);
2161 } else
2162 {
2163 if (!(m_dwSongFlags & SONG_FIRSTTICK))
2164 {
2165 if (param & 0xF0) nGlbSlide = (int)((param & 0xF0) >> 4) * 2;
2166 else nGlbSlide = -(int)((param & 0x0F) * 2);
2167 }
2168 }
2169 if (nGlbSlide)
2170 {
2171 if (m_nType != MOD_TYPE_IT) nGlbSlide *= 2;
2172 nGlbSlide += m_nGlobalVolume;
2173 if (nGlbSlide < 0) nGlbSlide = 0;
2174 if (nGlbSlide > 256) nGlbSlide = 256;
2175 m_nGlobalVolume = nGlbSlide;
2176 }
2177 }
2178
2179
2180 DWORD CSoundFile::IsSongFinished(UINT nStartOrder, UINT nStartRow) const
2181 //----------------------------------------------------------------------
2182 {
2183 UINT nOrd;
2184
2185 for (nOrd=nStartOrder; nOrd<MAX_ORDERS; nOrd++)
2186 {
2187 UINT nPat = Order[nOrd];
2188 if (nPat != 0xFE)
2189 {
2190 MODCOMMAND *p;
2191
2192 if (nPat >= MAX_PATTERNS) break;
2193 p = Patterns[nPat];
2194 if (p)
2195 {
2196 UINT len = PatternSize[nPat] * m_nChannels;
2197 UINT pos = (nOrd == nStartOrder) ? nStartRow : 0;
2198 pos *= m_nChannels;
2199 while (pos < len)
2200 {
2201 UINT cmd;
2202 if ((p[pos].note) || (p[pos].volcmd)) return 0;
2203 cmd = p[pos].command;
2204 if (cmd == CMD_MODCMDEX)
2205 {
2206 UINT cmdex = p[pos].param & 0xF0;
2207 if ((!cmdex) || (cmdex == 0x60) || (cmdex == 0xE0) || (cmdex == 0xF0)) cmd = 0;
2208 }
2209 if ((cmd) && (cmd != CMD_SPEED) && (cmd != CMD_TEMPO)) return 0;
2210 pos++;
2211 }
2212 }
2213 }
2214 }
2215 return (nOrd < MAX_ORDERS) ? nOrd : MAX_ORDERS-1;
2216 }
2217
2218
2219 BOOL CSoundFile::IsValidBackwardJump(UINT nStartOrder, UINT nStartRow, UINT nJumpOrder, UINT nJumpRow) const
2220 //----------------------------------------------------------------------------------------------------------
2221 {
2222 while ((nJumpOrder < MAX_PATTERNS) && (Order[nJumpOrder] == 0xFE)) nJumpOrder++;
2223 if ((nStartOrder >= MAX_PATTERNS) || (nJumpOrder >= MAX_PATTERNS)) return FALSE;
2224 // Treat only case with jumps in the same pattern
2225 if (nJumpOrder > nStartOrder) return TRUE;
2226 if ((nJumpOrder < nStartOrder) || (nJumpRow >= PatternSize[nStartOrder])
2227 || (!Patterns[nStartOrder]) || (nStartRow >= 256) || (nJumpRow >= 256)) return FALSE;
2228 // See if the pattern is being played backward
2229 BYTE row_hist[256];
2230 memset(row_hist, 0, sizeof(row_hist));
2231 UINT nRows = PatternSize[nStartOrder], row = nJumpRow;
2232 if (nRows > 256) nRows = 256;
2233 row_hist[nStartRow] = TRUE;
2234 while ((row < 256) && (!row_hist[row]))
2235 {
2236 if (row >= nRows) return TRUE;
2237 row_hist[row] = TRUE;
2238 MODCOMMAND *p = Patterns[nStartOrder] + row * m_nChannels;
2239 row++;
2240 int breakrow = -1, posjump = 0;
2241 for (UINT i=0; i<m_nChannels; i++, p++)
2242 {
2243 if (p->command == CMD_POSITIONJUMP)
2244 {
2245 if (p->param < nStartOrder) return FALSE;
2246 if (p->param > nStartOrder) return TRUE;
2247 posjump = TRUE;
2248 } else
2249 if (p->command == CMD_PATTERNBREAK)
2250 {
2251 breakrow = p->param;
2252 }
2253 }
2254 if (breakrow >= 0)
2255 {
2256 if (!posjump) return TRUE;
2257 row = breakrow;
2258 }
2259 if (row >= nRows) return TRUE;
2260 }
2261 return FALSE;
2262 }
2263
2264
2265 //////////////////////////////////////////////////////
2266 // Note/Period/Frequency functions
2267
2268 UINT CSoundFile::GetNoteFromPeriod(UINT period) const
2269 //---------------------------------------------------
2270 {
2271 if (!period) return 0;
2272 if (m_nType & (MOD_TYPE_MED|MOD_TYPE_MOD|MOD_TYPE_MTM|MOD_TYPE_669|MOD_TYPE_OKT|MOD_TYPE_AMF0))
2273 {
2274 period >>= 2;
2275 for (UINT i=0; i<6*12; i++)
2276 {
2277 if (period >= ProTrackerPeriodTable[i])
2278 {
2279 if ((period != ProTrackerPeriodTable[i]) && (i))
2280 {
2281 UINT p1 = ProTrackerPeriodTable[i-1];
2282 UINT p2 = ProTrackerPeriodTable[i];
2283 if (p1 - period < (period - p2)) return i+36;
2284 }
2285 return i+1+36;
2286 }
2287 }
2288 return 6*12+36;
2289 } else
2290 {
2291 for (UINT i=1; i<120; i++)
2292 {
2293 LONG n = GetPeriodFromNote(i, 0, 0);
2294 if ((n > 0) && (n <= (LONG)period)) return i;
2295 }
2296 return 120;
2297 }
2298 }
2299
2300
2301
2302 UINT CSoundFile::GetPeriodFromNote(UINT note, int nFineTune, UINT nC4Speed) const
2303 //-------------------------------------------------------------------------------
2304 {
2305 if ((!note) || (note > 0xF0)) return 0;
2306 if (m_nType & (MOD_TYPE_IT|MOD_TYPE_S3M|MOD_TYPE_STM|MOD_TYPE_MDL|MOD_TYPE_ULT|MOD_TYPE_WAV
2307 |MOD_TYPE_FAR|MOD_TYPE_DMF|MOD_TYPE_PTM|MOD_TYPE_AMS|MOD_TYPE_DBM|MOD_TYPE_AMF|MOD_TYPE_PSM))
2308 {
2309 note--;
2310 if (m_dwSongFlags & SONG_LINEARSLIDES)
2311 {
2312 return (FreqS3MTable[note % 12] << 5) >> (note / 12);
2313 } else
2314 {
2315 if (!nC4Speed) nC4Speed = 8363;
2316 return _muldiv(8363, (FreqS3MTable[note % 12] << 5), nC4Speed << (note / 12));
2317 }
2318 } else
2319 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
2320 {
2321 if (note < 13) note = 13;
2322 note -= 13;
2323 if (m_dwSongFlags & SONG_LINEARSLIDES)
2324 {
2325 LONG l = ((120 - note) << 6) - (nFineTune / 2);
2326 if (l < 1) l = 1;
2327 return (UINT)l;
2328 } else
2329 {
2330 int finetune = nFineTune;
2331 UINT rnote = (note % 12) << 3;
2332 UINT roct = note / 12;
2333 int rfine = finetune / 16;
2334 int i = rnote + rfine + 8;
2335 if (i < 0) i = 0;
2336 if (i >= 104) i = 103;
2337 UINT per1 = XMPeriodTable[i];
2338 if ( finetune < 0 )
2339 {
2340 rfine--;
2341 finetune = -finetune;
2342 } else rfine++;
2343 i = rnote+rfine+8;
2344 if (i < 0) i = 0;
2345 if (i >= 104) i = 103;
2346 UINT per2 = XMPeriodTable[i];
2347 rfine = finetune & 0x0F;
2348 per1 *= 16-rfine;
2349 per2 *= rfine;
2350 return ((per1 + per2) << 1) >> roct;
2351 }
2352 } else
2353 {
2354 note--;
2355 nFineTune = XM2MODFineTune(nFineTune);
2356 if ((nFineTune) || (note < 36) || (note >= 36+6*12))
2357 return (ProTrackerTunedPeriods[nFineTune*12 + note % 12] << 5) >> (note / 12);
2358 else
2359 return (ProTrackerPeriodTable[note-36] << 2);
2360 }
2361 }
2362
2363
2364 UINT CSoundFile::GetFreqFromPeriod(UINT period, UINT nC4Speed, int nPeriodFrac) const
2365 //-----------------------------------------------------------------------------------
2366 {
2367 if (!period) return 0;
2368 if (m_nType & (MOD_TYPE_MED|MOD_TYPE_MOD|MOD_TYPE_MTM|MOD_TYPE_669|MOD_TYPE_OKT|MOD_TYPE_AMF0))
2369 {
2370 return (3546895L*4) / period;
2371 } else
2372 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
2373 {
2374 if (m_dwSongFlags & SONG_LINEARSLIDES)
2375 return XMLinearTable[period % 768] >> (period / 768);
2376 else
2377 return 8363 * 1712L / period;
2378 } else
2379 {
2380 if (m_dwSongFlags & SONG_LINEARSLIDES)
2381 {
2382 if (!nC4Speed) nC4Speed = 8363;
2383 return _muldiv(nC4Speed, 1712L << 8, (period << 8)+nPeriodFrac);
2384 } else
2385 {
2386 return _muldiv(8363, 1712L << 8, (period << 8)+nPeriodFrac);
2387 }
2388 }
2389 }
2390
2391