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