Mercurial > audlegacy-plugins
diff src/modplug/snd_fx.cxx @ 2216:3673c7ec4ea2
Sync with schism's modplug engine. Suggested by G¸«ärkan Seng¸«än.
author | William Pitcock <nenolod@atheme.org> |
---|---|
date | Fri, 07 Dec 2007 12:08:47 -0600 |
parents | 6b5a52635b3b |
children | 6907fc39b53f |
line wrap: on
line diff
--- a/src/modplug/snd_fx.cxx Thu Nov 29 04:17:51 2007 +0300 +++ b/src/modplug/snd_fx.cxx Fri Dec 07 12:08:47 2007 -0600 @@ -64,6 +64,7 @@ UINT nSpeedCount = 0; nRow = nNextRow; nCurrentPattern = nNextPattern; + // Check if pattern is valid nPattern = Order[nCurrentPattern]; while (nPattern >= MAX_PATTERNS) @@ -90,6 +91,20 @@ nNextPattern = nCurrentPattern + 1; nNextRow = 0; } + /* muahahaha */ + if (stop_at_order > -1 && stop_at_row > -1) { + if (stop_at_order <= (signed) nCurrentPattern && stop_at_row <= (signed) nRow) + goto EndMod; + if (stop_at_time > 0) { + /* stupid api decision */ + if (((dwElapsedTime+500) / 1000) >= stop_at_time) { + stop_at_order = nCurrentPattern; + stop_at_row = nRow; + goto EndMod; + } + } + } + if (!nRow) { for (UINT ipck=0; ipck<m_nChannels; ipck++) patloop[ipck] = dwElapsedTime; @@ -155,6 +170,7 @@ } if (param >= 0x20) nMusicTempo = param; else // Tempo Slide + // FIXME: this is totally wrong! if ((param & 0xF0) == 0x10) { nMusicTempo += param & 0x0F; @@ -298,7 +314,7 @@ BOOL bInstrumentChanged = FALSE; if (instr >= MAX_INSTRUMENTS) return; - INSTRUMENTHEADER *penv = Headers[instr]; + INSTRUMENTHEADER *penv = (m_dwSongFlags & SONG_INSTRUMENTMODE) ? Headers[instr] : NULL; MODINSTRUMENT *psmp = &Ins[instr]; UINT note = pChn->nNewNote; if ((penv) && (note) && (note <= 128)) @@ -306,8 +322,9 @@ if (penv->NoteMap[note-1] >= 0xFE) return; UINT n = penv->Keyboard[note-1]; psmp = ((n) && (n < MAX_SAMPLES)) ? &Ins[n] : NULL; + pChn->dwFlags &= ~CHN_SUSTAINLOOP; // turn off sustain } else - if (m_nInstruments) + if (m_dwSongFlags & SONG_INSTRUMENTMODE) { if (note >= 0xFE) return; psmp = NULL; @@ -332,9 +349,11 @@ pChn->nNewIns = 0; if (psmp) { + psmp->played = 1; if (penv) { - pChn->nInsVol = (psmp->nGlobalVol * penv->nGlobalVol) >> 6; + penv->played = 1; + pChn->nInsVol = (psmp->nGlobalVol * penv->nGlobalVol) >> 7; if (penv->dwFlags & ENV_SETPANNING) pChn->nPan = penv->nPan; pChn->nNNA = penv->nNNA; } else @@ -421,29 +440,38 @@ } -void CSoundFile::NoteChange(UINT nChn, int note, BOOL bPorta, BOOL bResetEnv) -//--------------------------------------------------------------------------- +void CSoundFile::NoteChange(UINT nChn, int note, BOOL bPorta, BOOL bResetEnv, BOOL bManual) +//----------------------------------------------------------------------------------------- { if (note < 1) return; MODCHANNEL * const pChn = &Chn[nChn]; MODINSTRUMENT *pins = pChn->pInstrument; - INSTRUMENTHEADER *penv = pChn->pHeader; + INSTRUMENTHEADER *penv = (m_dwSongFlags & SONG_INSTRUMENTMODE) ? pChn->pHeader : NULL; if ((penv) && (note <= 0x80)) { UINT n = penv->Keyboard[note - 1]; if ((n) && (n < MAX_SAMPLES)) pins = &Ins[n]; note = penv->NoteMap[note-1]; + pChn->dwFlags &= ~CHN_SUSTAINLOOP; // turn off sustain } // Key Off if (note >= 0x80) // 0xFE or invalid note => key off { + // technically this is "wrong", as anything besides ^^^, ===, and a valid note + // should cause a note fade... (oh well, it's just a quick hack anyway.) + if (note == 0xFD) { + pChn->dwFlags |= CHN_NOTEFADE; + return; + } + // Key Off KeyOff(nChn); // Note Cut if (note == 0xFE) { pChn->dwFlags |= (CHN_NOTEFADE|CHN_FASTVOLRAMP); - if ((!(m_nType & MOD_TYPE_IT)) || (m_nInstruments)) pChn->nVolume = 0; + if ((!(m_nType & MOD_TYPE_IT)) || (m_dwSongFlags & SONG_INSTRUMENTMODE)) + pChn->nVolume = 0; pChn->nFadeOutVol = 0; } return; @@ -540,8 +568,9 @@ // Volume Swing if (penv->nVolSwing) { - int d = ((LONG)penv->nVolSwing*(LONG)((rand() & 0xFF) - 0x7F)) / 128; - pChn->nVolSwing = (signed short)((d * pChn->nVolume + 1)/128); + /* this was wrong */ + int d = ((LONG)penv->nVolSwing*(LONG)((rand() & 0xFF) - 0x7F)) / 256; + pChn->nVolSwing = (signed short)((d * pChn->nVolume + 1)/256); } // Pan Swing if (penv->nPanSwing) @@ -569,21 +598,42 @@ if ((pChn->nCutOff < 0x7F) && (bFlt)) SetupChannelFilter(pChn, TRUE); #endif // NO_FILTER } + // Special case for MPT + if (bManual) pChn->dwFlags &= ~CHN_MUTE; + if (((pChn->dwFlags & CHN_MUTE) && (gdwSoundSetup & SNDMIX_MUTECHNMODE)) + || ((pChn->pInstrument) && (pChn->pInstrument->uFlags & CHN_MUTE) && (!bManual)) + || ((m_dwSongFlags & SONG_INSTRUMENTMODE) && (pChn->pHeader) + && (pChn->pHeader->dwFlags & ENV_MUTE) && (!bManual))) + { + if (!bManual) pChn->nPeriod = 0; + } } -UINT CSoundFile::GetNNAChannel(UINT nChn) const +UINT CSoundFile::GetNNAChannel(UINT nChn) //--------------------------------------------- { - const MODCHANNEL *pChn = &Chn[nChn]; + MODCHANNEL *pChn = &Chn[nChn]; // Check for empty channel - const MODCHANNEL *pi = &Chn[m_nChannels]; - for (UINT i=m_nChannels; i<MAX_CHANNELS; i++, pi++) if (!pi->nLength) return i; + MODCHANNEL *pi = &Chn[m_nChannels]; + for (UINT i=m_nChannels; i<MAX_CHANNELS; i++, pi++) { + if (!pi->nLength) { + if (pi->dwFlags & CHN_MUTE) { + if (pi->dwFlags & CHN_NNAMUTE) { + pi->dwFlags &= ~(CHN_NNAMUTE|CHN_MUTE); + } else { + /* this channel is muted; skip */ + continue; + } + } + return i; + } + } if (!pChn->nFadeOutVol) return 0; // All channels are used: check for lowest volume UINT result = 0; DWORD vol = 64*65536; // 25% - DWORD envpos = 0xFFFFFF; + int envpos = 0xFFFFFF; const MODCHANNEL *pj = &Chn[m_nChannels]; for (UINT j=m_nChannels; j<MAX_CHANNELS; j++, pj++) { @@ -601,6 +651,10 @@ result = j; } } + if (result) { + /* unmute new nna channel */ + Chn[result].dwFlags &= ~(CHN_MUTE|CHN_NNAMUTE); + } return result; } @@ -608,23 +662,25 @@ void CSoundFile::CheckNNA(UINT nChn, UINT instr, int note, BOOL bForceCut) //------------------------------------------------------------------------ { + MODCHANNEL *p; MODCHANNEL *pChn = &Chn[nChn]; - INSTRUMENTHEADER *penv = pChn->pHeader, *pHeader; + INSTRUMENTHEADER *penv = (m_dwSongFlags & SONG_INSTRUMENTMODE) ? pChn->pHeader : NULL; + INSTRUMENTHEADER *pHeader; signed char *pSample; if (note > 0x80) note = 0; if (note < 1) return; // Always NNA cut - using - if ((!(m_nType & (MOD_TYPE_IT|MOD_TYPE_MT2))) || (!m_nInstruments) || (bForceCut)) + if ((!(m_nType & (MOD_TYPE_IT|MOD_TYPE_MT2))) || (!(m_dwSongFlags & SONG_INSTRUMENTMODE)) || (bForceCut)) { if ((m_dwSongFlags & SONG_CPUVERYHIGH) || (!pChn->nLength) || (pChn->dwFlags & CHN_MUTE) || ((!pChn->nLeftVol) && (!pChn->nRightVol))) return; UINT n = GetNNAChannel(nChn); if (!n) return; - MODCHANNEL *p = &Chn[n]; + p = &Chn[n]; // Copy Channel *p = *pChn; - p->dwFlags &= ~(CHN_VIBRATO|CHN_TREMOLO|CHN_PANBRELLO|CHN_MUTE|CHN_PORTAMENTO); + p->dwFlags &= ~(CHN_VIBRATO|CHN_TREMOLO|CHN_PANBRELLO|CHN_PORTAMENTO); p->nMasterChn = nChn+1; p->nCommand = 0; // Cut the note @@ -641,7 +697,7 @@ pHeader = pChn->pHeader; if ((instr) && (note)) { - pHeader = Headers[instr]; + pHeader = (m_dwSongFlags & SONG_INSTRUMENTMODE) ? Headers[instr] : NULL; if (pHeader) { UINT n = 0; @@ -654,7 +710,7 @@ } else pSample = NULL; } if (!penv) return; - MODCHANNEL *p = pChn; + p = pChn; for (UINT i=nChn; i<MAX_CHANNELS; p++, i++) if ((i >= m_nChannels) || (p == pChn)) { @@ -666,7 +722,7 @@ { // Note case DCT_NOTE: - if ((note) && (p->nNote == note) && (pHeader == p->pHeader)) bOk = TRUE; + if ((note) && ((int)p->nNote == note) && (pHeader == p->pHeader)) bOk = TRUE; break; // Sample case DCT_SAMPLE: @@ -711,10 +767,10 @@ UINT n = GetNNAChannel(nChn); if (n) { - MODCHANNEL *p = &Chn[n]; + p = &Chn[n]; // Copy Channel *p = *pChn; - p->dwFlags &= ~(CHN_VIBRATO|CHN_TREMOLO|CHN_PANBRELLO|CHN_MUTE|CHN_PORTAMENTO); + p->dwFlags &= ~(CHN_VIBRATO|CHN_TREMOLO|CHN_PANBRELLO|CHN_PORTAMENTO); p->nMasterChn = nChn+1; p->nCommand = 0; // Key Off the note @@ -745,17 +801,19 @@ MODCHANNEL *pChn = Chn; for (UINT nChn=0; nChn<m_nChannels; nChn++, pChn++) { + pChn->nCommand=0; + UINT instr = pChn->nRowInstr; UINT volcmd = pChn->nRowVolCmd; UINT vol = pChn->nRowVolume; UINT cmd = pChn->nRowCommand; UINT param = pChn->nRowParam; BOOL bPorta = ((cmd != CMD_TONEPORTAMENTO) && (cmd != CMD_TONEPORTAVOL) && (volcmd != VOLCMD_TONEPORTAMENTO)) ? FALSE : TRUE; - UINT nStartTick = 0; + UINT nStartTick = pChn->nTickStart; pChn->dwFlags &= ~CHN_FASTVOLRAMP; // Process special effects (note delay, pattern delay, pattern loop) - if ((cmd == CMD_MODCMDEX) || (cmd == CMD_S3MCMDEX)) + if (((cmd == CMD_MODCMDEX) || (cmd == CMD_S3MCMDEX))) { if ((!param) && (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))) param = pChn->nOldCmdEx; else pChn->nOldCmdEx = param; // Note Delay ? @@ -797,7 +855,7 @@ } if ((!note) && (instr)) { - if (m_nInstruments) + if (m_dwSongFlags & SONG_INSTRUMENTMODE) { if (pChn->pInstrument) pChn->nVolume = pChn->pInstrument->nVolume; if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) @@ -822,7 +880,7 @@ // Note Cut/Off => ignore instrument if (note >= 0xFE) instr = 0; if ((note) && (note <= 128)) pChn->nNewNote = note; - // New Note Action ? + // New Note Action ? (not when paused!!!) if ((note) && (note <= 128) && (!bPorta)) { CheckNNA(nChn, instr, note, FALSE); @@ -871,6 +929,7 @@ if (vol > 64) vol = 64; pChn->nPan = vol << 2; pChn->dwFlags |= CHN_FASTVOLRAMP; + pChn->dwFlags &= ~CHN_SURROUND; } } @@ -948,6 +1007,14 @@ { pChn->nVolume = (param < 64) ? param*4 : 256; pChn->dwFlags |= CHN_FASTVOLRAMP; + for (UINT i=m_nChannels; i<MAX_CHANNELS; i++) + { + MODCHANNEL *c = &Chn[i]; + if (c->nMasterChn == (nChn+1)) { + c->nVolume = pChn->nVolume; + c->dwFlags |= CHN_FASTVOLRAMP; + } + } } break; @@ -1004,7 +1071,22 @@ if (param) pChn->nOldTempo = param; else param = pChn->nOldTempo; } SetTempo(param); - } + } else { + param = pChn->nOldTempo; // this just got set on tick zero + + switch (param >> 4) { + case 0: + m_nMusicTempo -= param & 0xf; + if (m_nMusicTempo < 32) + m_nMusicTempo = 32; + break; + case 1: + m_nMusicTempo += param & 0xf; + if (m_nMusicTempo > 255) + m_nMusicTempo = 255; + break; + } + } break; // Set Offset @@ -1039,9 +1121,9 @@ // Arpeggio case CMD_ARPEGGIO: + pChn->nCommand = CMD_ARPEGGIO; if ((m_nTickCount) || (!pChn->nPeriod) || (!pChn->nNote)) break; if ((!param) && (!(m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT)))) break; - pChn->nCommand = CMD_ARPEGGIO; if (param) pChn->nArpeggio = param; break; @@ -1053,14 +1135,18 @@ if (!(param & 0x0F)) param |= pChn->nRetrigParam & 0x0F; param |= 0x100; // increment retrig count on first row } + // various bits of retriggery commented out here & below, reverting to old method... + // -Storlek 04aug07 + // if (pChn->nRowNote && !m_nTickCount) pChn->nRetrigCount = 0; if (param) pChn->nRetrigParam = (BYTE)(param & 0xFF); else param = pChn->nRetrigParam; + // pChn->nCommand = CMD_RETRIG; RetrigNote(nChn, param); break; // Tremor case CMD_TREMOR: + pChn->nCommand = CMD_TREMOR; if (m_nTickCount) break; - pChn->nCommand = CMD_TREMOR; if (param) pChn->nTremorParam = param; break; @@ -1149,12 +1235,35 @@ { pChn->nGlobalVol = param; pChn->dwFlags |= CHN_FASTVOLRAMP; + for (UINT i=m_nChannels; i<MAX_CHANNELS; i++) + { + MODCHANNEL *c = &Chn[i]; + if (c->nMasterChn == (nChn+1)) { + c->nGlobalVol = param; + c->dwFlags |= CHN_FASTVOLRAMP; + } + } } break; // Channel volume slide case CMD_CHANNELVOLSLIDE: - ChannelVolSlide(pChn, param); + { + int saw_self = 0; + + for (UINT i=m_nChannels; i<MAX_CHANNELS; i++) + { + MODCHANNEL *c = &Chn[i]; + if (c->nMasterChn == (nChn+1)) { + if (c == pChn) saw_self = 1; + ChannelVolSlide(c, param); + } + } + if (!saw_self) { + ChannelVolSlide(pChn, param); + } + } + break; // Panbrello (IT) @@ -1169,10 +1278,10 @@ pChn->nVolEnvPosition = param; pChn->nPanEnvPosition = param; pChn->nPitchEnvPosition = param; - if (pChn->pHeader) + if ((m_dwSongFlags & SONG_INSTRUMENTMODE) && pChn->pHeader) { INSTRUMENTHEADER *penv = pChn->pHeader; - if ((pChn->dwFlags & CHN_PANENV) && (penv->nPanEnv) && (param > penv->PanPoints[penv->nPanEnv-1])) + if ((pChn->dwFlags & CHN_PANENV) && (penv->PanEnv.nNodes) && ((int)param > penv->PanEnv.Ticks[penv->PanEnv.nNodes-1])) { pChn->dwFlags &= ~CHN_PANENV; } @@ -1267,6 +1376,8 @@ //--------------------------------------------------------- { if (param) pChn->nOldPortaUpDown = param; else param = pChn->nOldPortaUpDown; + if (m_dwSongFlags & SONG_ITCOMPATMODE) pChn->nPortamentoSlide=param*4; + else pChn->nPortamentoDest=0; if ((m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM)) && ((param & 0xF0) >= 0xE0)) { if (param & 0x0F) @@ -1294,6 +1405,8 @@ //----------------------------------------------------------- { if (param) pChn->nOldPortaUpDown = param; else param = pChn->nOldPortaUpDown; + if (m_dwSongFlags & SONG_ITCOMPATMODE) pChn->nPortamentoSlide=param*4; + else pChn->nPortamentoDest=0; if ((m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM)) && ((param & 0xF0) >= 0xE0)) { if (param & 0x0F) @@ -1566,6 +1679,7 @@ if (nPanSlide > 256) nPanSlide = 256; pChn->nPan = nPanSlide; } + pChn->dwFlags &= ~CHN_SURROUND; } @@ -1739,17 +1853,29 @@ } break; // S8x: Set 4-bit Panning - case 0x80: if (!m_nTickCount) { pChn->nPan = (param << 4) + 8; pChn->dwFlags |= CHN_FASTVOLRAMP; } break; + case 0x80: + pChn->dwFlags &= ~CHN_SURROUND; + if (!m_nTickCount) { + pChn->nPan = (param << 4) + 8; + pChn->dwFlags |= CHN_FASTVOLRAMP; + } + break; // S9x: Set Surround case 0x90: ExtendedChannelEffect(pChn, param & 0x0F); break; // SAx: Set 64k Offset case 0xA0: if (!m_nTickCount) { - pChn->nOldHiOffset = param; - if ((pChn->nRowNote) && (pChn->nRowNote < 0x80)) - { - DWORD pos = param << 16; - if (pos < pChn->nLength) pChn->nPos = pos; + if (m_nType & MOD_TYPE_S3M) { + pChn->nPan = ((param ^ 8) << 4) + 8; + pChn->dwFlags &= ~CHN_SURROUND; + pChn->dwFlags |= CHN_FASTVOLRAMP; + } else { + pChn->nOldHiOffset = param; + if ((pChn->nRowNote) && (pChn->nRowNote < 0x80)) + { + DWORD pos = param << 16; + if (pos < pChn->nLength) pChn->nPos = pos; + } } } break; @@ -1772,12 +1898,12 @@ if (m_nTickCount) return; switch(param & 0x0F) { - // S90: Surround Off - case 0x00: pChn->dwFlags &= ~CHN_SURROUND; break; - // S91: Surround On + // S91: Surround On case 0x01: pChn->dwFlags |= CHN_SURROUND; pChn->nPan = 128; break; //////////////////////////////////////////////////////////// // Modplug Extensions + // S90: Surround Off + case 0x00: pChn->dwFlags &= ~CHN_SURROUND; break; // S98: Reverb Off case 0x08: pChn->dwFlags &= ~CHN_REVERB; @@ -1820,102 +1946,176 @@ } } - -void CSoundFile::ProcessMidiMacro(UINT nChn, LPCSTR pszMidiMacro, UINT param) -//--------------------------------------------------------------------------- +// this is all brisby +void CSoundFile::MidiSend(unsigned char *data, unsigned int len, UINT nChn, int fake) { MODCHANNEL *pChn = &Chn[nChn]; - DWORD dwMacro = (*((LPDWORD)pszMidiMacro)) & 0x7F5F7F5F; - // Not Internal Device ? - if (dwMacro != 0x30463046) - { - UINT pos = 0, nNib = 0, nBytes = 0; - DWORD dwMidiCode = 0, dwByteCode = 0; - while (pos+6 <= 32) - { - CHAR cData = pszMidiMacro[pos++]; - if (!cData) break; - if ((cData >= '0') && (cData <= '9')) { dwByteCode = (dwByteCode<<4) | (cData-'0'); nNib++; } else - if ((cData >= 'A') && (cData <= 'F')) { dwByteCode = (dwByteCode<<4) | (cData-'A'+10); nNib++; } else - if ((cData >= 'a') && (cData <= 'f')) { dwByteCode = (dwByteCode<<4) | (cData-'a'+10); nNib++; } else - if ((cData == 'z') || (cData == 'Z')) { dwByteCode = param & 0x7f; nNib = 2; } else - if ((cData == 'x') || (cData == 'X')) { dwByteCode = param & 0x70; nNib = 2; } else - if ((cData == 'y') || (cData == 'Y')) { dwByteCode = (param & 0x0f)<<3; nNib = 2; } else - if (nNib >= 2) - { - nNib = 0; - dwMidiCode |= dwByteCode << (nBytes*8); - dwByteCode = 0; - nBytes++; - if (nBytes >= 3) - { - UINT nMasterCh = (nChn < m_nChannels) ? nChn+1 : pChn->nMasterChn; - if ((nMasterCh) && (nMasterCh <= m_nChannels)) - { - UINT nPlug = ChnSettings[nMasterCh-1].nMixPlugin; - if ((nPlug) && (nPlug <= MAX_MIXPLUGINS)) - { - IMixPlugin *pPlugin = m_MixPlugins[nPlug-1].pMixPlugin; - if ((pPlugin) && (m_MixPlugins[nPlug-1].pMixState)) - { - pPlugin->MidiSend(dwMidiCode); - } - } - } - nBytes = 0; - dwMidiCode = 0; - } - } + int oldcutoff; - } - return; - } - // Internal device - pszMidiMacro += 4; - // Filter ? - if (pszMidiMacro[0] == '0') - { - CHAR cData1 = pszMidiMacro[2]; - DWORD dwParam = 0; - if ((cData1 == 'z') || (cData1 == 'Z')) - { - dwParam = param; - } else - { - CHAR cData2 = pszMidiMacro[3]; - if ((cData1 >= '0') && (cData1 <= '9')) dwParam += (cData1 - '0') << 4; else - if ((cData1 >= 'A') && (cData1 <= 'F')) dwParam += (cData1 - 'A' + 0x0A) << 4; - if ((cData2 >= '0') && (cData2 <= '9')) dwParam += (cData2 - '0'); else - if ((cData2 >= 'A') && (cData2 <= 'F')) dwParam += (cData2 - 'A' + 0x0A); - } - switch(pszMidiMacro[1]) - { - // F0.F0.00.xx: Set CutOff - case '0': - { - int oldcutoff = pChn->nCutOff; - if (dwParam < 0x80) pChn->nCutOff = dwParam; + if (len > 2 && data[0] == 0xF0 && data[1] == 0xF0) { + /* impulse tracker filter control (mfg. 0xF0) */ + if (len == 5) { + switch (data[2]) { + case 0x00: /* set cutoff */ + oldcutoff = pChn->nCutOff; + if (data[3] < 0x80) pChn->nCutOff = data[3]; #ifndef NO_FILTER oldcutoff -= pChn->nCutOff; if (oldcutoff < 0) oldcutoff = -oldcutoff; if ((pChn->nVolume > 0) || (oldcutoff < 0x10) - || (!(pChn->dwFlags & CHN_FILTER)) || (!(pChn->nLeftVol|pChn->nRightVol))) - SetupChannelFilter(pChn, (pChn->dwFlags & CHN_FILTER) ? FALSE : TRUE); + || (!(pChn->dwFlags & CHN_FILTER)) + || (!(pChn->nLeftVol|pChn->nRightVol))) + SetupChannelFilter(pChn, (pChn->dwFlags & CHN_FILTER) + ? FALSE : TRUE); +#endif // NO_FILTER + break; + case 0x01: /* set resonance */ + if (data[3] < 0x80) pChn->nResonance = data[3]; +#ifndef NO_FILTER + SetupChannelFilter(pChn, (pChn->dwFlags & CHN_FILTER) ? FALSE : TRUE); #endif // NO_FILTER - } - break; + break; + }; + } + } + + if (!fake && _midi_out_raw) { + /* okay, this is kind of how it works. + we pass m_nBufferCount as here because while + 1000 * ((8((buffer_size/2) - m_nBufferCount)) / sample_rate) + is the number of msec we need to delay by, libmodplug simply doesn't know + what the buffer size is at this point so m_nBufferCount simply has no + frame of reference. + + fortunately, schism does and can complete this (tags: _schism_midi_out_raw ) + + */ + _midi_out_raw(data, len, m_nBufferCount); + } +} + +static int _was_complete_midi(unsigned char *q, unsigned int len, int nextc) +{ + if (len == 0) return 0; + if (*q == 0xF0) return (q[len-1] == 0xF7 ? 1 : 0); + return ((nextc & 0x80) ? 1 : 0); +} + +void CSoundFile::ProcessMidiMacro(UINT nChn, LPCSTR pszMidiMacro, UINT param, + UINT note, UINT velocity, UINT use_instr) +//--------------------------------------------------------------------------- +{ +/* this was all wrong. -mrsb */ + MODCHANNEL *pChn = &Chn[nChn]; + INSTRUMENTHEADER *penv = (m_dwSongFlags & SONG_INSTRUMENTMODE) + ? Headers[use_instr + ?use_instr + :pChn->nLastInstr] + : NULL; + unsigned char outbuffer[64]; + unsigned char cx; + int mc, fake = 0; + int saw_c; + int i, j, x; + + saw_c = 0; + if (!penv || penv->nMidiChannel == 0) { + /* okay, there _IS_ no real midi channel. forget this for now... */ + mc = 15; + fake = 1; + + } else if (penv->nMidiChannel > 16) { + mc = (nChn-1) % 16; + } else { + mc = (penv->nMidiChannel-1); + } - // F0.F0.01.xx: Set Resonance - case '1': - if (dwParam < 0x80) pChn->nResonance = dwParam; -#ifndef NO_FILTER - SetupChannelFilter(pChn, (pChn->dwFlags & CHN_FILTER) ? FALSE : TRUE); -#endif // NO_FILTER + for (i = j = x = 0, cx =0; i <= 32 && pszMidiMacro[i]; i++) { + int c, cw; + if (pszMidiMacro[i] >= '0' && pszMidiMacro[i] <= '9') { + c = pszMidiMacro[i] - '0'; + cw = 1; + } else if (pszMidiMacro[i] >= 'A' && pszMidiMacro[i] <= 'F') { + c = (pszMidiMacro[i] - 'A') + 10; + cw = 1; + } else if (pszMidiMacro[i] == 'c') { + c = mc; + cw = 1; + saw_c = 1; + } else if (pszMidiMacro[i] == 'n') { + c = (note-1); + cw = 2; + } else if (pszMidiMacro[i] == 'v') { + c = velocity; + cw = 2; + } else if (pszMidiMacro[i] == 'u') { + c = (pChn->nVolume >> 1); + if (c > 127) c = 127; + cw = 2; + } else if (pszMidiMacro[i] == 'x') { + c = pChn->nPan; + if (c > 127) c = 127; + cw = 2; + } else if (pszMidiMacro[i] == 'y') { + c = pChn->nRealPan; + if (c > 127) c = 127; + cw = 2; + } else if (pszMidiMacro[i] == 'a') { + if (!penv) + c = 0; + else + c = (penv->wMidiBank >> 7) & 127; + cw = 2; + } else if (pszMidiMacro[i] == 'b') { + if (!penv) + c = 0; + else + c = penv->wMidiBank & 127; + cw = 2; + } else if (pszMidiMacro[i] == 'z' || pszMidiMacro[i] == 'p') { + c = param & 0x7F; + cw = 2; + } else { + continue; + } + if (j == 0 && cw == 1) { + cx = c; + j = 1; + continue; + } else if (j == 1 && cw == 1) { + cx = (cx << 4) | c; + j = 0; + } else if (j == 0) { + cx = c; + } else if (j == 1) { + outbuffer[x] = cx; + x++; - break; + cx = c; + j = 0; + } + // start of midi message + if (_was_complete_midi(outbuffer,x,cx)) { + MidiSend(outbuffer, x, nChn,saw_c && fake); + x = 0; } - + outbuffer[x] = cx; + x++; + } + if (j == 1) { + outbuffer[x] = cx; + x++; + } + if (x) { + // terminate sysex + if (!_was_complete_midi(outbuffer,x,0xFF)) { + if (*outbuffer == 0xF0) { + outbuffer[x] = 0xF7; + x++; + } + } + MidiSend(outbuffer, x, nChn,saw_c && fake); } } @@ -1932,10 +2132,18 @@ if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT)) { if (!nRetrigSpeed) nRetrigSpeed = 1; - if ((nRetrigCount) && (!(nRetrigCount % nRetrigSpeed))) bDoRetrig = TRUE; - nRetrigCount++; - } else - { + if (m_nMusicSpeed < nRetrigSpeed) { + if (nRetrigCount >= nRetrigSpeed) { + bDoRetrig = TRUE; + nRetrigCount = 0; + } else { + nRetrigCount++; + } + } else { + if ((nRetrigCount) && (!(nRetrigCount % nRetrigSpeed))) bDoRetrig = TRUE; + nRetrigCount++; + } + } else { UINT realspeed = nRetrigSpeed; if ((param & 0x100) && (pChn->nRowVolCmd == VOLCMD_VOLUME) && (pChn->nRowParam & 0xF0)) realspeed++; if ((m_nTickCount) || (param & 0x100)) @@ -2022,9 +2230,10 @@ if (m_nTickCount == nTick) { MODCHANNEL *pChn = &Chn[nChn]; - // if (m_nInstruments) KeyOff(pChn); ? + // if (m_dwSongFlags & SONG_INSTRUMENTMODE) KeyOff(pChn); ? pChn->nVolume = 0; pChn->dwFlags |= CHN_FASTVOLRAMP; + pChn->nLength = 0; } } @@ -2036,7 +2245,7 @@ BOOL bKeyOn = (pChn->dwFlags & CHN_KEYOFF) ? FALSE : TRUE; pChn->dwFlags |= CHN_KEYOFF; //if ((!pChn->pHeader) || (!(pChn->dwFlags & CHN_VOLENV))) - if ((pChn->pHeader) && (!(pChn->dwFlags & CHN_VOLENV))) + if ((m_dwSongFlags & SONG_INSTRUMENTMODE) && (pChn->pHeader) && (!(pChn->dwFlags & CHN_VOLENV))) { pChn->dwFlags |= CHN_NOTEFADE; } @@ -2061,7 +2270,7 @@ pChn->nLength = psmp->nLength; } } - if (pChn->pHeader) + if ((m_dwSongFlags & SONG_INSTRUMENTMODE) && pChn->pHeader) { INSTRUMENTHEADER *penv = pChn->pHeader; if (((penv->dwFlags & ENV_VOLLOOP) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) && (penv->nFadeOut)) @@ -2077,22 +2286,8 @@ void CSoundFile::SetSpeed(UINT param) //----------------------------------- { - UINT max = (m_nType == MOD_TYPE_IT) ? 256 : 128; - // Modplug Tracker and Mod-Plugin don't do this check -#ifndef MODPLUG_TRACKER -#ifndef MODPLUG_FASTSOUNDLIB - // Big Hack!!! - if ((!param) || (param >= 0x80) || ((m_nType & (MOD_TYPE_MOD|MOD_TYPE_XM|MOD_TYPE_MT2)) && (param >= 0x1E))) - { - if (IsSongFinished(m_nCurrentPattern, m_nRow+1)) - { - GlobalFadeSong(1000); - } - } -#endif // MODPLUG_FASTSOUNDLIB -#endif // MODPLUG_TRACKER - if ((m_nType & MOD_TYPE_S3M) && (param > 0x80)) param -= 0x80; - if ((param) && (param <= max)) m_nMusicSpeed = param; + if (param) + m_nMusicSpeed = param; } @@ -2101,6 +2296,7 @@ { if (param < 0x20) { +#if 0 // argh... this is completely wrong // Tempo Slide if ((param & 0xF0) == 0x10) { @@ -2111,6 +2307,7 @@ m_nMusicTempo -= (param & 0x0F) * 2; if ((LONG)m_nMusicTempo < 32) m_nMusicTempo = 32; } +#endif } else { m_nMusicTempo = param; @@ -2126,15 +2323,28 @@ if (pChn->nPatternLoopCount) { pChn->nPatternLoopCount--; - if (!pChn->nPatternLoopCount) return -1; + if (!pChn->nPatternLoopCount) { + // this should get rid of that nasty infinite loop for cases like + // ... .. .. SB0 + // ... .. .. SB1 + // ... .. .. SB1 + // it still doesn't work right in a few strange cases, but oh well :P + pChn->nPatternLoop = m_nRow + 1; + return -1; + } } else { + // hmm. the pattern loop shouldn't care about + // other channels at all... i'm not really + // sure what this code is doing :/ +#if 0 MODCHANNEL *p = Chn; for (UINT i=0; i<m_nChannels; i++, p++) if (p != pChn) { // Loop already done if (p->nPatternLoopCount) return -1; } +#endif pChn->nPatternLoopCount = param; } return pChn->nPatternLoop; @@ -2297,6 +2507,33 @@ } } +// this last param was nC4Speed +UINT CSoundFile::GetLinearPeriodFromNote(UINT note, int nFineTune, UINT) const +{ + if ((!note) || (note > 0xF0)) return 0; + if (m_nType & (MOD_TYPE_IT|MOD_TYPE_S3M|MOD_TYPE_STM|MOD_TYPE_MDL|MOD_TYPE_ULT|MOD_TYPE_WAV + |MOD_TYPE_FAR|MOD_TYPE_DMF|MOD_TYPE_PTM|MOD_TYPE_AMS|MOD_TYPE_DBM|MOD_TYPE_AMF|MOD_TYPE_PSM)) + { + note--; + return (FreqS3MTable[note % 12] << 5) >> (note / 12); + } else + if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) + { + if (note < 13) note = 13; + note -= 13; + LONG l = ((120 - note) << 6) - (nFineTune / 2); + if (l < 1) l = 1; + return (UINT)l; + } else + { + note--; + nFineTune = XM2MODFineTune(nFineTune); + if ((nFineTune) || (note < 36) || (note >= 36+6*12)) + return (ProTrackerTunedPeriods[nFineTune*12 + note % 12] << 5) >> (note / 12); + else + return (ProTrackerPeriodTable[note-36] << 2); + } +} UINT CSoundFile::GetPeriodFromNote(UINT note, int nFineTune, UINT nC4Speed) const