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