From: <sag...@us...> - 2014-09-29 23:59:28
|
Revision: 4330 http://sourceforge.net/p/modplug/code/4330 Author: saga-games Date: 2014-09-29 23:59:15 +0000 (Mon, 29 Sep 2014) Log Message: ----------- [Fix] Linear frequency slide mode (in all formats except XM) is now implemented using frequencies instead of periods. This fixes some horrible inaccuracies which can add up very quickly when using extra-fine slides in IT. [Fix] MT2: Frequency slides were broken (libopenmpt only) Modified Paths: -------------- trunk/OpenMPT/mptrack/View_smp.cpp trunk/OpenMPT/soundlib/Snd_fx.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/Sndmix.cpp Modified: trunk/OpenMPT/mptrack/View_smp.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_smp.cpp 2014-09-29 23:37:44 UTC (rev 4329) +++ trunk/OpenMPT/mptrack/View_smp.cpp 2014-09-29 23:59:15 UTC (rev 4330) @@ -2399,7 +2399,7 @@ CSoundFile &sndFile = pModDoc->GetrSoundFile(); ModSample &sample = sndFile.GetSample(m_nSample); - uint32 freq = sndFile.GetFreqFromPeriod(sndFile.GetPeriodFromNote(note + (sndFile.GetType() == MOD_TYPE_XM ? sample.RelativeTone : 0), sample.nFineTune, sample.nC5Speed), sample.nC5Speed, 0); + uint32 freq = sndFile.GetFreqFromPeriod(sndFile.GetPeriodFromNote(note + (sndFile.GetType() == MOD_TYPE_XM ? sample.RelativeTone : 0), sample.nFineTune, sample.nC5Speed), 0); const std::string s = mpt::String::Print("%1 (%2.%3 Hz)", sndFile.GetNoteName((ModCommand::NOTE)note), Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp =================================================================== --- trunk/OpenMPT/soundlib/Snd_fx.cpp 2014-09-29 23:37:44 UTC (rev 4329) +++ trunk/OpenMPT/soundlib/Snd_fx.cpp 2014-09-29 23:59:15 UTC (rev 4330) @@ -3141,10 +3141,10 @@ { if ((pChn->nPeriod) && (param)) { - if(m_SongFlags[SONG_LINEARSLIDES] && !(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))) + if(m_SongFlags[SONG_LINEARSLIDES] && GetType() != MOD_TYPE_XM) { int oldPeriod = pChn->nPeriod; - pChn->nPeriod = Util::muldivr(pChn->nPeriod, LinearSlideDownTable[param & 0x0F], 65536); + pChn->nPeriod = Util::muldivr(pChn->nPeriod, LinearSlideUpTable[param & 0x0F], 65536); if(oldPeriod == pChn->nPeriod) { pChn->nPeriod--; @@ -3176,10 +3176,10 @@ { if ((pChn->nPeriod) && (param)) { - if (m_SongFlags[SONG_LINEARSLIDES] && !(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))) + if (m_SongFlags[SONG_LINEARSLIDES] && GetType() != MOD_TYPE_XM) { int oldPeriod = pChn->nPeriod; - pChn->nPeriod = Util::muldivr(pChn->nPeriod, LinearSlideUpTable[param & 0x0F], 65536); + pChn->nPeriod = Util::muldivr(pChn->nPeriod, LinearSlideDownTable[param & 0x0F], 65536); if(oldPeriod == pChn->nPeriod) { pChn->nPeriod++; @@ -3211,10 +3211,10 @@ { if ((pChn->nPeriod) && (param)) { - if(m_SongFlags[SONG_LINEARSLIDES] && !(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))) + if(m_SongFlags[SONG_LINEARSLIDES] && GetType() != MOD_TYPE_XM) { int oldPeriod = pChn->nPeriod; - pChn->nPeriod = Util::muldivr(pChn->nPeriod, FineLinearSlideDownTable[param & 0x0F], 65536); + pChn->nPeriod = Util::muldivr(pChn->nPeriod, FineLinearSlideUpTable[param & 0x0F], 65536); if(oldPeriod == pChn->nPeriod) { pChn->nPeriod--; @@ -3246,10 +3246,10 @@ { if ((pChn->nPeriod) && (param)) { - if(m_SongFlags[SONG_LINEARSLIDES] && !(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))) + if(m_SongFlags[SONG_LINEARSLIDES] && GetType() != MOD_TYPE_XM) { int oldPeriod = pChn->nPeriod; - pChn->nPeriod = Util::muldivr(pChn->nPeriod, FineLinearSlideUpTable[param & 0x0F], 65536); + pChn->nPeriod = Util::muldivr(pChn->nPeriod, FineLinearSlideDownTable[param & 0x0F], 65536); if(oldPeriod == pChn->nPeriod) { pChn->nPeriod++; @@ -3359,9 +3359,9 @@ if (pChn->nPeriod < pChn->nPortamentoDest) { int32 delta = pChn->nPortamentoSlide; - if(m_SongFlags[SONG_LINEARSLIDES] && !(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))) + if(m_SongFlags[SONG_LINEARSLIDES] && GetType() != MOD_TYPE_XM) { - UINT n = pChn->nPortamentoSlide >> 2; + UINT n = pChn->nPortamentoSlide / 4; if (n > 255) n = 255; // Return (a*b+c/2)/c - no divide error // Table is 65536*2(n/192) @@ -3374,9 +3374,9 @@ if (pChn->nPeriod > pChn->nPortamentoDest) { int32 delta = -pChn->nPortamentoSlide; - if(m_SongFlags[SONG_LINEARSLIDES] && !(GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))) + if(m_SongFlags[SONG_LINEARSLIDES] && GetType() != MOD_TYPE_XM) { - UINT n = pChn->nPortamentoSlide >> 2; + UINT n = pChn->nPortamentoSlide / 4; if (n > 255) n = 255; delta = Util::muldivr(pChn->nPeriod, LinearSlideDownTable[n], 65536) - pChn->nPeriod; if (delta > -1) delta = -1; @@ -4640,7 +4640,7 @@ { // IT Linear slides if (!pChn->nPeriod) return; - if(m_SongFlags[SONG_LINEARSLIDES] && !(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))) + if(m_SongFlags[SONG_LINEARSLIDES] && GetType() != MOD_TYPE_XM) { int32 nOldPeriod = pChn->nPeriod; if (nFreqSlide < 0) @@ -4649,7 +4649,7 @@ if (n) { if (n > 255) n = 255; - pChn->nPeriod = Util::muldivr(pChn->nPeriod, LinearSlideDownTable[n], 65536); + pChn->nPeriod = Util::muldivr(pChn->nPeriod, LinearSlideUpTable[n], 65536); if (pChn->nPeriod == nOldPeriod) pChn->nPeriod = nOldPeriod-1; } } else @@ -4658,7 +4658,7 @@ if (n) { if (n > 255) n = 255; - pChn->nPeriod = Util::muldivr(pChn->nPeriod, LinearSlideUpTable[n], 65536); + pChn->nPeriod = Util::muldivr(pChn->nPeriod, LinearSlideDownTable[n], 65536); if (pChn->nPeriod == nOldPeriod) pChn->nPeriod = nOldPeriod+1; } } @@ -4930,11 +4930,12 @@ if (!period) return 0; // This essentially implements std::lower_bound, with the difference that we don't need an iterable container. uint32 minNote = NOTE_MIN, maxNote = NOTE_MAX, count = maxNote - minNote + 1; + const bool periodIsFreq = m_SongFlags[SONG_LINEARSLIDES] && GetType() != MOD_TYPE_XM; while(count > 0) { const uint32 step = count / 2, midNote = minNote + step; uint32 n = GetPeriodFromNote(midNote, nFineTune, nC5Speed); - if(n > period || !n) + if((n > period && !periodIsFreq) || (n < period && periodIsFreq) || !n) { minNote = midNote + 1; count -= step + 1; @@ -4951,13 +4952,14 @@ //------------------------------------------------------------------------------- { if (note == NOTE_NONE || (note >= NOTE_MIN_SPECIAL)) return 0; - if (GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT|MOD_TYPE_MT2|MOD_TYPE_S3M|MOD_TYPE_STM|MOD_TYPE_MDL|MOD_TYPE_ULT|MOD_TYPE_WAV + if (GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT|MOD_TYPE_MT2|MOD_TYPE_S3M|MOD_TYPE_STM|MOD_TYPE_MDL|MOD_TYPE_ULT|MOD_TYPE_WAV|MOD_TYPE_669 |MOD_TYPE_FAR|MOD_TYPE_DMF|MOD_TYPE_PTM|MOD_TYPE_AMS|MOD_TYPE_AMS2|MOD_TYPE_DBM|MOD_TYPE_AMF|MOD_TYPE_PSM|MOD_TYPE_J2B|MOD_TYPE_IMF)) { note -= NOTE_MIN; if(m_SongFlags[SONG_LINEARSLIDES]) { - return (FreqS3MTable[note % 12] << 5) >> (note / 12); + // In IT linear slide mode, periods are equal to frequency. + return Util::muldiv_unsigned(nC5Speed, LinearSlideUpTable[(note % 12) * 16] << (note / 12), 65536 << 5); } else { if (!nC5Speed) nC5Speed = 8363; @@ -5019,8 +5021,8 @@ // Converts period value to sample frequency. Return value is fixed point, with FREQ_FRACBITS fractional bits. -UINT CSoundFile::GetFreqFromPeriod(UINT period, UINT nC5Speed, int nPeriodFrac) const -//----------------------------------------------------------------------------------- +UINT CSoundFile::GetFreqFromPeriod(UINT period, int nPeriodFrac) const +//-------------------------------------------------------------------- { if (!period) return 0; if (GetType() & (MOD_TYPE_MED|MOD_TYPE_MOD|MOD_TYPE_DIGI|MOD_TYPE_MTM|MOD_TYPE_669|MOD_TYPE_AMF0)) @@ -5061,8 +5063,9 @@ { if(m_SongFlags[SONG_LINEARSLIDES]) { - if (!nC5Speed) nC5Speed = 8363; - return Util::muldiv(nC5Speed, (1712L << 8) << FREQ_FRACBITS, (period << 8) + nPeriodFrac); + // IT linear slides already use frequencies instead of periods. + static_assert(FREQ_FRACBITS <= 8, "Check this shift operator"); + return uint32(((uint64(period) << 8) + nPeriodFrac) >> (8 - FREQ_FRACBITS)); } else { return Util::muldiv(8363, (1712L << 8) << FREQ_FRACBITS, (period << 8) + nPeriodFrac); Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2014-09-29 23:37:44 UTC (rev 4329) +++ trunk/OpenMPT/soundlib/Sndfile.h 2014-09-29 23:59:15 UTC (rev 4330) @@ -876,7 +876,7 @@ // Period/Note functions UINT GetNoteFromPeriod(UINT period, int nFineTune = 0, UINT nC5Speed = 0) const; UINT GetPeriodFromNote(UINT note, int nFineTune, UINT nC5Speed) const; - UINT GetFreqFromPeriod(UINT period, UINT nC5Speed, int nPeriodFrac = 0) const; + UINT GetFreqFromPeriod(UINT period, int nPeriodFrac = 0) const; // Misc functions ModSample &GetSample(SAMPLEINDEX sample) { ASSERT(sample <= m_nSamples && sample < CountOf(Samples)); return Samples[sample]; } const ModSample &GetSample(SAMPLEINDEX sample) const { ASSERT(sample <= m_nSamples && sample < CountOf(Samples)); return Samples[sample]; } Modified: trunk/OpenMPT/soundlib/Sndmix.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndmix.cpp 2014-09-29 23:37:44 UTC (rev 4329) +++ trunk/OpenMPT/soundlib/Sndmix.cpp 2014-09-29 23:59:15 UTC (rev 4330) @@ -912,11 +912,11 @@ { l = -l; LimitMax(l, 255); - period = Util::muldiv(period, LinearSlideUpTable[l], 0x10000); + period = Util::muldiv(period, LinearSlideDownTable[l], 65536); } else { LimitMax(l, 255); - period = Util::muldiv(period, LinearSlideDownTable[l], 0x10000); + period = Util::muldiv(period, LinearSlideUpTable[l], 65536); } } //End: Original behavior. } @@ -1341,18 +1341,18 @@ vdelta = (vdelta * (int)chn.nVibratoDepth) >> vdepth; int16 midiDelta = static_cast<int16>(-vdelta); // Periods are upside down - if (m_SongFlags[SONG_LINEARSLIDES] && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))) + if (m_SongFlags[SONG_LINEARSLIDES] && GetType() != MOD_TYPE_XM) { int l = vdelta; if (l < 0) { l = -l; - vdelta = Util::muldiv(period, LinearSlideDownTable[l >> 2], 0x10000) - period; - if (l & 0x03) vdelta += Util::muldiv(period, FineLinearSlideDownTable[l & 0x03], 0x10000) - period; + vdelta = Util::muldiv(period, LinearSlideUpTable[l >> 2], 65536) - period; + if (l & 0x03) vdelta += Util::muldiv(period, FineLinearSlideDownTable[l & 0x03], 65536) - period; } else { - vdelta = Util::muldiv(period, LinearSlideUpTable[l >> 2], 0x10000) - period; - if (l & 0x03) vdelta += Util::muldiv(period, FineLinearSlideUpTable[l & 0x03], 0x10000) - period; + vdelta = Util::muldiv(period, LinearSlideDownTable[l >> 2], 65536) - period; + if (l & 0x03) vdelta += Util::muldiv(period, FineLinearSlideUpTable[l & 0x03], 65536) - period; } } period += vdelta; @@ -1402,6 +1402,13 @@ const ModSample *pSmp = pChn->pModSample; const bool alternativeTuning = pChn->pModInstrument && pChn->pModInstrument->pTuning; + // In IT linear slide mode, we use frequencies, otherwise we use periods, which are upside down. + // In this context, the "up" tables refer to the tables that increase frequency, and the down tables are the ones that decrease frequency. + const uint32 (&upTable)[256] = m_SongFlags[SONG_LINEARSLIDES] ? LinearSlideUpTable : LinearSlideDownTable; + const uint32 (&downTable)[256] = m_SongFlags[SONG_LINEARSLIDES] ? LinearSlideDownTable : LinearSlideUpTable; + const uint32 (&fineUpTable)[16] = m_SongFlags[SONG_LINEARSLIDES] ? FineLinearSlideUpTable : FineLinearSlideDownTable; + const uint32 (&fineDownTable)[16] = m_SongFlags[SONG_LINEARSLIDES] ? FineLinearSlideDownTable : FineLinearSlideUpTable; + // IT compatibility: Autovibrato is so much different in IT that I just put this in a separate code block, to get rid of a dozen IsCompatibilityMode() calls. if(IsCompatibleMode(TRK_IMPULSETRACKER) && !alternativeTuning) { @@ -1449,17 +1456,17 @@ int l = abs(vdelta); if(vdelta < 0) { - vdelta = Util::muldiv(period, LinearSlideDownTable[l >> 2], 0x10000) - period; + vdelta = Util::muldiv(period, upTable[l >> 2], 0x10000) - period; if (l & 0x03) { - vdelta += Util::muldiv(period, FineLinearSlideDownTable[l & 0x03], 0x10000) - period; + vdelta += Util::muldiv(period, fineUpTable[l & 0x03], 0x10000) - period; } } else { - vdelta = Util::muldiv(period, LinearSlideUpTable[l >> 2], 0x10000) - period; + vdelta = Util::muldiv(period, downTable[l >> 2], 0x10000) - period; if (l & 0x03) { - vdelta += Util::muldiv(period, FineLinearSlideUpTable[l & 0x03], 0x10000) - period; + vdelta += Util::muldiv(period, fineDownTable[l & 0x03], 0x10000) - period; } } period -= vdelta; @@ -1527,20 +1534,20 @@ } else //Original behavior { - if (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) + if (GetType() != MOD_TYPE_XM) { int df1, df2; if (n < 0) { n = -n; UINT n1 = n >> 8; - df1 = LinearSlideUpTable[n1]; - df2 = LinearSlideUpTable[n1+1]; + df1 = downTable[n1]; + df2 = downTable[n1+1]; } else { UINT n1 = n >> 8; - df1 = LinearSlideDownTable[n1]; - df2 = LinearSlideDownTable[n1+1]; + df1 = upTable[n1]; + df2 = upTable[n1+1]; } n >>= 2; period = Util::muldiv(period, df1 + ((df2 - df1) * (n & 0x3F) >> 6), 256); @@ -1630,7 +1637,7 @@ const ModInstrument *pIns = pChn->pModInstrument; if(GetType() != MOD_TYPE_MPT || pIns == nullptr || pIns->pTuning == nullptr) { - freq = GetFreqFromPeriod(period, pChn->nC5Speed, periodFrac); + freq = GetFreqFromPeriod(period, periodFrac); } else { freq = pChn->m_Freq; @@ -1834,15 +1841,7 @@ { // Only recompute this whole thing in case the base period has changed. pChn->cachedPeriod = period; - for(uint32 i = NOTE_MIN; i < NOTE_MAX; i++) - { - int32 n = GetPeriodFromNote(i, pChn->nFineTune, pChn->nC5Speed); - if(n > 0 && n <= period) - { - pChn->glissandoPeriod = n; - break; - } - } + pChn->glissandoPeriod = GetPeriodFromNote(GetNoteFromPeriod(period, pChn->nFineTune, pChn->nC5Speed), pChn->nFineTune, pChn->nC5Speed); } period = pChn->glissandoPeriod; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |