author | llornkcor <llornkcor> | 2002-07-20 22:07:31 (UTC) |
---|---|---|
committer | llornkcor <llornkcor> | 2002-07-20 22:07:31 (UTC) |
commit | 2342d48be31847e7ead9d1cc682452e8f0122351 (patch) (unidiff) | |
tree | 8329bb94e9d429c905a0ef6b881cf1c0f775bf14 /core/multimedia/opieplayer/modplug/snd_fx.cpp | |
parent | 0f24c1fb86d3bb58d8696358b824c0e01752b10d (diff) | |
download | opie-2342d48be31847e7ead9d1cc682452e8f0122351.zip opie-2342d48be31847e7ead9d1cc682452e8f0122351.tar.gz opie-2342d48be31847e7ead9d1cc682452e8f0122351.tar.bz2 |
initial commit of modplugin
Diffstat (limited to 'core/multimedia/opieplayer/modplug/snd_fx.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | core/multimedia/opieplayer/modplug/snd_fx.cpp | 2394 |
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 | ||
18 | extern const BYTE ImpulseTrackerPortaVolCmd[16]; | ||
19 | extern const WORD S3MFineTuneTable[16]; | ||
20 | extern const WORD ProTrackerPeriodTable[6*12]; | ||
21 | extern const WORD ProTrackerTunedPeriods[15*12]; | ||
22 | extern const WORD FreqS3MTable[]; | ||
23 | extern const WORD XMPeriodTable[96+8]; | ||
24 | extern const UINT XMLinearTable[768]; | ||
25 | extern const DWORD FineLinearSlideUpTable[16]; | ||
26 | extern const DWORD FineLinearSlideDownTable[16]; | ||
27 | extern const DWORD LinearSlideUpTable[256]; | ||
28 | extern const DWORD LinearSlideDownTable[256]; | ||
29 | extern const signed char retrigTable1[16]; | ||
30 | extern const signed char retrigTable2[16]; | ||
31 | extern const short int ModRandomTable[64]; | ||
32 | |||
33 | |||
34 | //////////////////////////////////////////////////////////// | ||
35 | // Length | ||
36 | |||
37 | DWORD 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 | } | ||
274 | EndMod: | ||
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 | |||
298 | void 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 | |||
427 | void 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 | |||
578 | UINT 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 | |||
611 | void 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 | |||
744 | BOOL 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 | |||
1269 | void 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 | |||
1296 | void 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 | |||
1319 | void 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 | |||
1343 | void 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 | |||
1367 | void 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 | |||
1391 | void 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 | ||
1416 | void 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 | |||
1453 | void 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 | |||
1462 | void 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 | |||
1471 | void 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 | |||
1480 | void 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 | |||
1528 | void 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 | |||
1575 | void 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 | |||
1588 | void 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 | |||
1601 | void 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 | |||
1610 | void 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 | |||
1640 | void 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 | |||
1687 | void 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 | |||
1771 | void 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 | |||
1827 | void 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 | |||
1926 | void 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 | |||
1987 | void 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 | |||
2022 | void 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 | |||
2035 | void 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 | |||
2080 | void 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 | |||
2102 | void 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 | |||
2124 | int 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 | |||
2152 | void 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 | |||
2183 | DWORD 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 | |||
2222 | BOOL 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 | |||
2271 | UINT 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 | |||
2305 | UINT 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 | |||
2367 | UINT 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 | |||