diff options
author | James Cowgill <jcowgill@debian.org> | 2019-07-15 23:43:22 +0100 |
---|---|---|
committer | James Cowgill <jcowgill@debian.org> | 2019-07-15 23:43:22 +0100 |
commit | 1eb7116a256029ed6f5ce8d0ffac280adcbe8c35 (patch) | |
tree | b8867e88955ad6c7195e6998c261c4e69664d054 /soundlib | |
parent | 2690ce9c090be73f3ba565e624bece14ced24878 (diff) | |
parent | dc825bfd49ccba2594b05f2926234839182ed70b (diff) |
Update upstream source from tag 'upstream/0.4.5'
Update to upstream version '0.4.5'
with Debian dir dd5e0f3a68c5a79fc4c224020a9b8cedcbd36e32
Diffstat (limited to 'soundlib')
-rw-r--r-- | soundlib/AudioReadTarget.h | 4 | ||||
-rw-r--r-- | soundlib/InstrumentExtensions.cpp | 35 | ||||
-rw-r--r-- | soundlib/Load_mod.cpp | 66 | ||||
-rw-r--r-- | soundlib/Load_mt2.cpp | 4 | ||||
-rw-r--r-- | soundlib/Load_mtm.cpp | 22 | ||||
-rw-r--r-- | soundlib/ModChannel.h | 6 | ||||
-rw-r--r-- | soundlib/ModInstrument.cpp | 6 | ||||
-rw-r--r-- | soundlib/ModInstrument.h | 80 | ||||
-rw-r--r-- | soundlib/ModSample.cpp | 5 | ||||
-rw-r--r-- | soundlib/ModSequence.cpp | 23 | ||||
-rw-r--r-- | soundlib/SampleFormatFLAC.cpp | 4 | ||||
-rw-r--r-- | soundlib/SampleIO.cpp | 5 | ||||
-rw-r--r-- | soundlib/Snd_defs.h | 5 | ||||
-rw-r--r-- | soundlib/Snd_fx.cpp | 30 | ||||
-rw-r--r-- | soundlib/Sndfile.cpp | 3 | ||||
-rw-r--r-- | soundlib/Sndmix.cpp | 33 | ||||
-rw-r--r-- | soundlib/UpgradeModule.cpp | 12 |
17 files changed, 202 insertions, 141 deletions
diff --git a/soundlib/AudioReadTarget.h b/soundlib/AudioReadTarget.h index e5da84a..3bb6f5d 100644 --- a/soundlib/AudioReadTarget.h +++ b/soundlib/AudioReadTarget.h @@ -40,7 +40,7 @@ public: , outputBuffer(buffer) , outputBuffers(buffers) { - MPT_ASSERT(SampleFormat(SampleFormatTraits<Tsample>::sampleFormat).IsValid()); + MPT_ASSERT(SampleFormat(SampleFormatTraits<Tsample>::sampleFormat()).IsValid()); } std::size_t GetRenderedCount() const { return countRendered; } public: @@ -48,7 +48,7 @@ public: { // Convert to output sample format and optionally perform dithering and clipping if needed - const SampleFormat sampleFormat = SampleFormatTraits<Tsample>::sampleFormat; + const SampleFormat sampleFormat = SampleFormatTraits<Tsample>::sampleFormat(); if(sampleFormat.IsInt()) { diff --git a/soundlib/InstrumentExtensions.cpp b/soundlib/InstrumentExtensions.cpp index 10127bd..87bb171 100644 --- a/soundlib/InstrumentExtensions.cpp +++ b/soundlib/InstrumentExtensions.cpp @@ -120,9 +120,9 @@ PSB. PanEnv.nSustainStart; PSE. PanEnv.nSustainEnd; PTTL pitchToTempoLock; PTTF pitchToTempoLock (fractional part); -PVEH nPluginVelocityHandling; -PVOH nPluginVolumeHandling; -R... nResampling; +PVEH pluginVelocityHandling; +PVOH pluginVolumeHandling; +R... resampling; RP.. [EXT] nRestartPos; RPB. [EXT] nRowsPerBeat; RPM. [EXT] nRowsPerMeasure; @@ -314,12 +314,12 @@ if(!writeAll) WRITE_MPTHEADER_envelope_member( ENV_PITCH , value , uint8 , MagicBE("PiE[") ) WRITE_MPTHEADER_sized_member( nMixPlug , uint8 , MagicBE("MiP.") ) WRITE_MPTHEADER_sized_member( nVolRampUp , uint16 , MagicBE("VR..") ) - WRITE_MPTHEADER_trunc_member( nResampling , uint16 , MagicBE("R...") ) + WRITE_MPTHEADER_sized_member( resampling , uint8 , MagicBE("R...") ) WRITE_MPTHEADER_sized_member( nCutSwing , uint8 , MagicBE("CS..") ) WRITE_MPTHEADER_sized_member( nResSwing , uint8 , MagicBE("RS..") ) WRITE_MPTHEADER_sized_member( nFilterMode , uint8 , MagicBE("FM..") ) - WRITE_MPTHEADER_sized_member( nPluginVelocityHandling , uint8 , MagicBE("PVEH") ) - WRITE_MPTHEADER_sized_member( nPluginVolumeHandling , uint8 , MagicBE("PVOH") ) + WRITE_MPTHEADER_sized_member( pluginVelocityHandling , uint8 , MagicBE("PVEH") ) + WRITE_MPTHEADER_sized_member( pluginVolumeHandling , uint8 , MagicBE("PVOH") ) WRITE_MPTHEADER_trunc_member( pitchToTempoLock.GetInt() , uint16 , MagicBE("PTTL") ) WRITE_MPTHEADER_trunc_member( pitchToTempoLock.GetFract() , uint16 , MagicLE("PTTF") ) WRITE_MPTHEADER_sized_member( PitchEnv.nReleaseNode , uint8 , MagicBE("PERN") ) @@ -373,9 +373,9 @@ void CSoundFile::SaveExtendedInstrumentProperties(INSTRUMENTINDEX numInstruments WritePropertyIfNeeded(*this, &ModInstrument::nMidiChannel, MagicBE("MC.."), sizeof(ModInstrument::nMidiChannel), f, numInstruments); WritePropertyIfNeeded(*this, &ModInstrument::nMidiProgram, MagicBE("MP.."), sizeof(ModInstrument::nMidiProgram), f, numInstruments); WritePropertyIfNeeded(*this, &ModInstrument::wMidiBank, MagicBE("MB.."), sizeof(ModInstrument::wMidiBank), f, numInstruments); - WritePropertyIfNeeded(*this, &ModInstrument::nResampling, MagicBE("R..."), sizeof(ModInstrument::nResampling), f, numInstruments); - WritePropertyIfNeeded(*this, &ModInstrument::nPluginVelocityHandling, MagicBE("PVEH"), sizeof(ModInstrument::nPluginVelocityHandling), f, numInstruments); - WritePropertyIfNeeded(*this, &ModInstrument::nPluginVolumeHandling, MagicBE("PVOH"), sizeof(ModInstrument::nPluginVolumeHandling), f, numInstruments); + WritePropertyIfNeeded(*this, &ModInstrument::resampling, MagicBE("R..."), sizeof(ModInstrument::resampling), f, numInstruments); + WritePropertyIfNeeded(*this, &ModInstrument::pluginVelocityHandling, MagicBE("PVEH"), sizeof(ModInstrument::pluginVelocityHandling), f, numInstruments); + WritePropertyIfNeeded(*this, &ModInstrument::pluginVolumeHandling, MagicBE("PVOH"), sizeof(ModInstrument::pluginVolumeHandling), f, numInstruments); if(!(GetType() & MOD_TYPE_XM)) { @@ -575,16 +575,15 @@ bool ReadInstrumentHeaderField(ModInstrument *input, uint32 fcode, uint16 fsize, GET_MPTHEADER_envelope_member(ENV_PITCH , value , uint8 , MagicBE("PiE[") ) GET_MPTHEADER_array_member( NoteMap , uint8 , MagicBE("NM[.") ) GET_MPTHEADER_array_member( Keyboard , uint16 , MagicBE("K[..") ) - GET_MPTHEADER_chararray_member( name , char , MagicBE("n[..") ) - GET_MPTHEADER_chararray_member( filename , char , MagicBE("fn[.") ) + GET_MPTHEADER_chararray_member( name , char , MagicBE("n[..") ) + GET_MPTHEADER_chararray_member( filename , char , MagicBE("fn[.") ) GET_MPTHEADER_sized_member( nMixPlug , uint8 , MagicBE("MiP.") ) GET_MPTHEADER_sized_member( nVolRampUp , uint16 , MagicBE("VR..") ) - GET_MPTHEADER_sized_member( nResampling , uint32 , MagicBE("R...") ) GET_MPTHEADER_sized_member( nCutSwing , uint8 , MagicBE("CS..") ) GET_MPTHEADER_sized_member( nResSwing , uint8 , MagicBE("RS..") ) GET_MPTHEADER_sized_member( nFilterMode , uint8 , MagicBE("FM..") ) - GET_MPTHEADER_sized_member( nPluginVelocityHandling , uint8 , MagicBE("PVEH") ) - GET_MPTHEADER_sized_member( nPluginVolumeHandling , uint8 , MagicBE("PVOH") ) + GET_MPTHEADER_sized_member( pluginVelocityHandling , uint8 , MagicBE("PVEH") ) + GET_MPTHEADER_sized_member( pluginVolumeHandling , uint8 , MagicBE("PVOH") ) GET_MPTHEADER_sized_member( PitchEnv.nReleaseNode , uint8 , MagicBE("PERN") ) GET_MPTHEADER_sized_member( PanEnv.nReleaseNode , uint8 , MagicBE("AERN") ) GET_MPTHEADER_sized_member( VolEnv.nReleaseNode , uint8 , MagicBE("VERN") ) @@ -592,6 +591,14 @@ bool ReadInstrumentHeaderField(ModInstrument *input, uint32 fcode, uint16 fsize, GET_MPTHEADER_sized_member( PanEnv.dwFlags , uint8 , MagicBE("AFLG") ) GET_MPTHEADER_sized_member( VolEnv.dwFlags , uint8 , MagicBE("VFLG") ) GET_MPTHEADER_sized_member( midiPWD , int8 , MagicBE("MPWD") ) + case MagicBE("R..."): + { + // Resampling has been written as various sizes including uint16 and uint32 in the past + uint32 tmp = file.ReadTruncatedIntLE<uint32>(fsize); + if(Resampling::IsKnownMode(tmp)) + input->resampling = static_cast<ResamplingMode>(tmp); + result = true; + } break; case MagicBE("PTTL"): { // Integer part of pitch/tempo lock diff --git a/soundlib/Load_mod.cpp b/soundlib/Load_mod.cpp index 47567da..073fd7b 100644 --- a/soundlib/Load_mod.cpp +++ b/soundlib/Load_mod.cpp @@ -345,23 +345,23 @@ MPT_BINARY_STRUCT(MODSampleHeader, 30) // Synthesized StarTrekker instruments struct AMInstrument { - char am[2]; // "AM" + char am[2]; // "AM" char zero[4]; - uint16be startLevel; // Start level - uint16be attack1Level; // Attack 1 level - uint16be attack1Speed; // Attack 1 speed - uint16be attack2Level; // Attack 2 level - uint16be attack2Speed; // Attack 2 speed - uint16be sustainLevel; // Sustain level - uint16be decaySpeed; // Decay speed - uint16be sustainTime; // Sustain time - uint16be nt; // ? - uint16be releaseSpeed; // Release speed - uint16be waveform; // Waveform - int16be pitchFall; // Pitch fall - uint16be vibAmp; // Vibrato amplitude - uint16be vibSpeed; // Vibrato speed - uint16be octave; // Base frequency + uint16be startLevel; // Start level + uint16be attack1Level; // Attack 1 level + uint16be attack1Speed; // Attack 1 speed + uint16be attack2Level; // Attack 2 level + uint16be attack2Speed; // Attack 2 speed + uint16be sustainLevel; // Sustain level + uint16be decaySpeed; // Decay speed + uint16be sustainTime; // Sustain time + uint16be nt; // ? + uint16be releaseSpeed; // Release speed + uint16be waveform; // Waveform + int16be pitchFall; // Pitch fall + uint16be vibAmp; // Vibrato amplitude + uint16be vibSpeed; // Vibrato speed + uint16be octave; // Base frequency void ConvertToMPT(ModSample &sample, ModInstrument &ins, mpt::fast_prng &rng) const { @@ -376,15 +376,16 @@ struct AMInstrument sample.RelativeTone = static_cast<int8>(-12 * octave); if(sample.AllocateSample()) { + int8 *p = sample.sample8(); for(SmpLength i = 0; i < sample.nLength; i++) { switch(waveform) { default: - case 0: sample.sample8()[i] = ModSinusTable[i * 2]; break; // Sine - case 1: sample.sample8()[i] = static_cast<int8>(-128 + i * 8); break; // Saw - case 2: sample.sample8()[i] = i < 16 ? -128 : 127; break; // Square - case 3: sample.sample8()[i] = mpt::random<int8>(rng); break; // Noise + case 0: p[i] = ModSinusTable[i * 2]; break; // Sine + case 1: p[i] = static_cast<int8>(-128 + i * 8); break; // Saw + case 2: p[i] = i < 16 ? -128 : 127; break; // Square + case 3: p[i] = mpt::random<int8>(rng); break; // Noise } } } @@ -492,7 +493,7 @@ MPT_BINARY_STRUCT(PT36InfoChunk, 64) // Check if header magic equals a given string. -static bool IsMagic(const char *magic1, const char *magic2) +static bool IsMagic(const char *magic1, const char (&magic2)[5]) { return std::memcmp(magic1, magic2, 4) == 0; } @@ -1023,11 +1024,15 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags) if(m.command || m.param) { - // No support for Startrekker assembly macros if(isStartrekker && m.command == 0x0E) { + // No support for Startrekker assembly macros m.command = CMD_NONE; m.param = 0; + } else if(isStartrekker && m.command == 0x0F && m.param > 0x1F) + { + // Startrekker caps speed at 31 ticks per row + m.param = 0x1F; } ConvertModCommand(m); } @@ -1281,13 +1286,13 @@ static uint32 CountInvalidChars(const char (&name)[N]) // Thanks for Fraggie for this information! (https://www.un4seen.com/forum/?topic=14471.msg100829#msg100829) enum STVersions { - UST1_00, // Ultimate Soundtracker 1.0-1.21 (K. Obarski) - UST1_80, // Ultimate Soundtracker 1.8-2.0 (K. Obarski) - ST2_00_Exterminator, // SoundTracker 2.0 (The Exterminator), D.O.C. Sountracker II (Unknown/D.O.C.) - ST_III, // Defjam Soundtracker III (Il Scuro/Defjam), Alpha Flight SoundTracker IV (Alpha Flight), D.O.C. SoundTracker IV (Unknown/D.O.C.), D.O.C. SoundTracker VI (Unknown/D.O.C.) - ST_IX, // D.O.C. SoundTracker IX (Unknown/D.O.C.) - MST1_00, // Master Soundtracker 1.0 (Tip/The New Masters) - ST2_00, // SoundTracker 2.0, 2.1, 2.2 (Unknown/D.O.C.) + UST1_00, // Ultimate Soundtracker 1.0-1.21 (K. Obarski) + UST1_80, // Ultimate Soundtracker 1.8-2.0 (K. Obarski) + ST2_00_Exterminator, // SoundTracker 2.0 (The Exterminator), D.O.C. Sountracker II (Unknown/D.O.C.) + ST_III, // Defjam Soundtracker III (Il Scuro/Defjam), Alpha Flight SoundTracker IV (Alpha Flight), D.O.C. SoundTracker IV (Unknown/D.O.C.), D.O.C. SoundTracker VI (Unknown/D.O.C.) + ST_IX, // D.O.C. SoundTracker IX (Unknown/D.O.C.) + MST1_00, // Master Soundtracker 1.0 (Tip/The New Masters) + ST2_00, // SoundTracker 2.0, 2.1, 2.2 (Unknown/D.O.C.) }; @@ -1521,8 +1526,7 @@ bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags) if(fileHeader.restartPos != 0x78) { // Convert to CIA timing - //m_nDefaultTempo = TEMPO(((709378.92 / 50.0) * 125.0) / ((240 - fileHeader.restartPos) * 122.0)); - m_nDefaultTempo.Set((709379 / ((240 - fileHeader.restartPos) * 122)) * 125 / 50); + m_nDefaultTempo = TEMPO((709379.0 * 125.0 / 50.0) / ((240 - fileHeader.restartPos) * 122.0)); if(minVersion > UST1_80) { // D.O.C. SoundTracker IX re-introduced the variable tempo after some other versions dropped it. diff --git a/soundlib/Load_mt2.cpp b/soundlib/Load_mt2.cpp index 2a98b24..e256cb1 100644 --- a/soundlib/Load_mt2.cpp +++ b/soundlib/Load_mt2.cpp @@ -1060,7 +1060,7 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags) { if(drumSample[drum] == i && Instruments[drumMap[drum]] != nullptr) { - Instruments[drumMap[drum]]->nResampling = SRCMODE_NEAREST; + Instruments[drumMap[drum]]->resampling = SRCMODE_NEAREST; } } } @@ -1105,7 +1105,7 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags) mptSmp.nFineTune = group.pitch; if(sampleNoInterpolation[sample - 1]) { - mptIns->nResampling = SRCMODE_NEAREST; + mptIns->resampling = SRCMODE_NEAREST; } if(sampleSynchronized[sample - 1]) { diff --git a/soundlib/Load_mtm.cpp b/soundlib/Load_mtm.cpp index 10140ba..3819602 100644 --- a/soundlib/Load_mtm.cpp +++ b/soundlib/Load_mtm.cpp @@ -58,8 +58,8 @@ struct MTMSampleHeader LimitMax(mptSmp.nLoopEnd, mptSmp.nLength); if(mptSmp.nLoopStart + 4 >= mptSmp.nLoopEnd) mptSmp.nLoopStart = mptSmp.nLoopEnd = 0; if(mptSmp.nLoopEnd) mptSmp.uFlags.set(CHN_LOOP); - mptSmp.nFineTune = MOD2XMFineTune(finetune); - mptSmp.nC5Speed = ModSample::TransposeToFrequency(0, mptSmp.nFineTune); + mptSmp.nFineTune = finetune; // Uses MOD units but allows the full int8 range rather than just -8...+7 so we keep the value as-is and convert it during playback + mptSmp.nC5Speed = ModSample::TransposeToFrequency(0, finetune * 16); if(attribute & 0x01) { @@ -204,11 +204,25 @@ bool CSoundFile::ReadMTM(FileReader &file, ModLoadingFlags loadFlags) { // No 8xx panning in MultiTracker, only E8x cmd = param = 0; + } else if(cmd == 0x0E) + { + // MultiTracker does not support these commands + switch(param & 0xF0) + { + case 0x00: + case 0x30: + case 0x40: + case 0x60: + case 0x70: + case 0xF0: + cmd = param = 0; + break; + } } - m->command = cmd; - m->param = param; if(cmd != 0 || param != 0) { + m->command = cmd; + m->param = param; ConvertModCommand(*m); #ifdef MODPLUG_TRACKER m->Convert(MOD_TYPE_MTM, MOD_TYPE_S3M, *this); diff --git a/soundlib/ModChannel.h b/soundlib/ModChannel.h index 88c6df5..4cc1f7f 100644 --- a/soundlib/ModChannel.h +++ b/soundlib/ModChannel.h @@ -28,8 +28,8 @@ struct ModChannel struct EnvInfo { FlagSet<EnvelopeFlags> flags; - uint32 nEnvPosition; - int32 nEnvValueAtReleaseJump; + uint32 nEnvPosition = 0; + int32 nEnvValueAtReleaseJump = NOT_YET_RELEASED; void Reset() { @@ -87,7 +87,7 @@ struct ModChannel CHANNELINDEX nMasterChn; ModCommand rowCommand; // 8-bit members - uint8 resamplingMode; + ResamplingMode resamplingMode; uint8 nRestoreResonanceOnNewNote; // See nRestorePanOnNewNote uint8 nRestoreCutoffOnNewNote; // ditto uint8 nNote; diff --git a/soundlib/ModInstrument.cpp b/soundlib/ModInstrument.cpp index d5eb6e6..604e4ea 100644 --- a/soundlib/ModInstrument.cpp +++ b/soundlib/ModInstrument.cpp @@ -163,13 +163,13 @@ ModInstrument::ModInstrument(SAMPLEINDEX sample) nMixPlug = 0; nVolRampUp = 0; - nResampling = SRCMODE_DEFAULT; + resampling = SRCMODE_DEFAULT; nCutSwing = 0; nResSwing = 0; nFilterMode = FLTMODE_UNCHANGED; pitchToTempoLock.Set(0); - nPluginVelocityHandling = PLUGIN_VELOCITYHANDLING_CHANNEL; - nPluginVolumeHandling = PLUGIN_VOLUMEHANDLING_IGNORE; + pluginVelocityHandling = PLUGIN_VELOCITYHANDLING_CHANNEL; + pluginVolumeHandling = PLUGIN_VOLUMEHANDLING_IGNORE; pTuning = CSoundFile::GetDefaultTuning(); diff --git a/soundlib/ModInstrument.h b/soundlib/ModInstrument.h index 8fc1bae..41c4b51 100644 --- a/soundlib/ModInstrument.h +++ b/soundlib/ModInstrument.h @@ -64,46 +64,46 @@ struct InstrumentEnvelope : public std::vector<EnvelopeNode> // Instrument Struct struct ModInstrument { - uint32 nFadeOut; // Instrument fadeout speed - uint32 nGlobalVol; // Global volume (0...64, all sample volumes are multiplied with this - TODO: This is 0...128 in Impulse Tracker) - uint32 nPan; // Default pan (0...256), if the appropriate flag is set. Sample panning overrides instrument panning. - - uint16 nVolRampUp; // Default sample ramping up, 0 = use global default - - uint16 wMidiBank; // MIDI Bank (1...16384). 0 = Don't send. - uint8 nMidiProgram; // MIDI Program (1...128). 0 = Don't send. - uint8 nMidiChannel; // MIDI Channel (1...16). 0 = Don't send. 17 = Mapped (Send to tracker channel modulo 16). - uint8 nMidiDrumKey; // Drum set note mapping (currently only used by the .MID loader) - int8 midiPWD; // MIDI Pitch Wheel Depth in semitones - - FlagSet<InstrumentFlags> dwFlags; // Instrument flags - NewNoteAction nNNA; // New note action - DuplicateCheckType nDCT; // Duplicate check type (i.e. which condition will trigger the duplicate note action) - DuplicateNoteAction nDNA; // Duplicate note action - uint8 nPanSwing; // Random panning factor (0...64) - uint8 nVolSwing; // Random volume factor (0...100) - uint8 nIFC; // Default filter cutoff (0...127). Used if the high bit is set - uint8 nIFR; // Default filter resonance (0...127). Used if the high bit is set - - int8 nPPS; // Pitch/Pan separation (i.e. how wide the panning spreads, -32...32) - uint8 nPPC; // Pitch/Pan centre (zero-based, default is NOTE_MIDDLE_C - 1) - - PLUGINDEX nMixPlug; // Plugin assigned to this instrument (0 = no plugin, 1 = first plugin) - uint8 nCutSwing; // Random cutoff factor (0...64) - uint8 nResSwing; // Random resonance factor (0...64) - InstrFilterMode nFilterMode; // Default filter mode - uint8 nPluginVelocityHandling; // How to deal with plugin velocity (PLUGIN_VELOCITYHANDLING_* constants) - uint8 nPluginVolumeHandling; // How to deal with plugin volume (PLUGIN_VOLUMEHANDLING_* constants) - TEMPO pitchToTempoLock; // BPM at which the samples assigned to this instrument loop correctly (0 = unset) - uint32 nResampling; // Resampling mode (SRCMODE_* constants) - CTuning *pTuning; // sample tuning assigned to this instrument - - InstrumentEnvelope VolEnv; // Volume envelope data - InstrumentEnvelope PanEnv; // Panning envelope data - InstrumentEnvelope PitchEnv; // Pitch / filter envelope data - - uint8 NoteMap[128]; // Note mapping, e.g. C-5 => D-5. - SAMPLEINDEX Keyboard[128]; // Sample mapping, e.g. C-5 => Sample 1 + uint32 nFadeOut; // Instrument fadeout speed + uint32 nGlobalVol; // Global volume (0...64, all sample volumes are multiplied with this - TODO: This is 0...128 in Impulse Tracker) + uint32 nPan; // Default pan (0...256), if the appropriate flag is set. Sample panning overrides instrument panning. + + uint16 nVolRampUp; // Default sample ramping up, 0 = use global default + + uint16 wMidiBank; // MIDI Bank (1...16384). 0 = Don't send. + uint8 nMidiProgram; // MIDI Program (1...128). 0 = Don't send. + uint8 nMidiChannel; // MIDI Channel (1...16). 0 = Don't send. 17 = Mapped (Send to tracker channel modulo 16). + uint8 nMidiDrumKey; // Drum set note mapping (currently only used by the .MID loader) + int8 midiPWD; // MIDI Pitch Wheel Depth in semitones + + FlagSet<InstrumentFlags> dwFlags; // Instrument flags + NewNoteAction nNNA; // New note action + DuplicateCheckType nDCT; // Duplicate check type (i.e. which condition will trigger the duplicate note action) + DuplicateNoteAction nDNA; // Duplicate note action + uint8 nPanSwing; // Random panning factor (0...64) + uint8 nVolSwing; // Random volume factor (0...100) + uint8 nIFC; // Default filter cutoff (0...127). Used if the high bit is set + uint8 nIFR; // Default filter resonance (0...127). Used if the high bit is set + + int8 nPPS; // Pitch/Pan separation (i.e. how wide the panning spreads, -32...32) + uint8 nPPC; // Pitch/Pan centre (zero-based, default is NOTE_MIDDLE_C - 1) + + PLUGINDEX nMixPlug; // Plugin assigned to this instrument (0 = no plugin, 1 = first plugin) + uint8 nCutSwing; // Random cutoff factor (0...64) + uint8 nResSwing; // Random resonance factor (0...64) + InstrFilterMode nFilterMode; // Default filter mode + PlugVelocityHandling pluginVelocityHandling; // How to deal with plugin velocity + PlugVolumeHandling pluginVolumeHandling; // How to deal with plugin volume + ResamplingMode resampling; // Resampling mode + TEMPO pitchToTempoLock; // BPM at which the samples assigned to this instrument loop correctly (0 = unset) + CTuning *pTuning; // sample tuning assigned to this instrument + + InstrumentEnvelope VolEnv; // Volume envelope data + InstrumentEnvelope PanEnv; // Panning envelope data + InstrumentEnvelope PitchEnv; // Pitch / filter envelope data + + uint8 NoteMap[128]; // Note mapping, e.g. C-5 => D-5. + SAMPLEINDEX Keyboard[128]; // Sample mapping, e.g. C-5 => Sample 1 char name[MAX_INSTRUMENTNAME]; char filename[MAX_INSTRUMENTFILENAME]; diff --git a/soundlib/ModSample.cpp b/soundlib/ModSample.cpp index 73a54ae..05a0117 100644 --- a/soundlib/ModSample.cpp +++ b/soundlib/ModSample.cpp @@ -113,6 +113,11 @@ void ModSample::Convert(MODTYPE fromType, MODTYPE toType) if(!CSoundFile::SupportsOPL(toType) && uFlags[CHN_ADLIB]) { SetAdlib(false); + } else if(toType == MOD_TYPE_S3M && uFlags[CHN_ADLIB]) + { + // No support for OPL3 waveforms in S3M + adlib[8] &= 0x03; + adlib[9] &= 0x03; } } diff --git a/soundlib/ModSequence.cpp b/soundlib/ModSequence.cpp index 5036913..15c3945 100644 --- a/soundlib/ModSequence.cpp +++ b/soundlib/ModSequence.cpp @@ -342,27 +342,31 @@ bool ModSequenceSet::ConvertSubsongsToMultipleSequences() Reporting::Confirm("The order list contains separator items.\nThe new format supports multiple sequences, do you want to convert those separate tracks into multiple song sequences?", "Order list conversion", false, true) == cnfYes) { - ORDERINDEX length = m_Sequences[0].GetLengthTailTrimmed(); + ORDERINDEX length = m_Sequences[0].GetLength(); for(ORDERINDEX ord = 0; ord < length; ord++) { // End of subsong? if(!m_Sequences[0].IsValidPat(ord) && m_Sequences[0][ord] != GetIgnoreIndex()) { - // remove all separator patterns between current and next subsong first - while(ord < length && !m_sndFile.Patterns.IsValidIndex(m_Sequences[0][ord])) + // Remove all separator patterns between current and next subsong first + while(ord < length && !m_sndFile.Patterns.IsValidPat(m_Sequences[0][ord])) { m_Sequences[0][ord] = GetInvalidPatIndex(); ord++; modified = true; } - if(ord >= length) break; - ORDERINDEX startOrd = ord; - modified = true; + if(ord >= length) + break; + + const SEQUENCEINDEX newSeq = AddSequence(false); + if(newSeq == SEQUENCEINDEX_INVALID) + break; - SEQUENCEINDEX newSeq = AddSequence(false); + const ORDERINDEX startOrd = ord; m_Sequences[newSeq].reserve(length - startOrd); + modified = true; - // now, move all following orders to the new sequence + // Now, move all following orders to the new sequence while(ord < length && m_Sequences[0][ord] != GetInvalidPatIndex()) { PATTERNINDEX copyPat = m_Sequences[0][ord]; @@ -370,7 +374,7 @@ bool ModSequenceSet::ConvertSubsongsToMultipleSequences() m_Sequences[0][ord] = GetInvalidPatIndex(); ord++; - // is this a valid pattern? adjust pattern jump commands, if necessary. + // Is this a valid pattern? adjust pattern jump commands, if necessary. if(m_sndFile.Patterns.IsValidPat(copyPat)) { for(auto &m : m_sndFile.Patterns[copyPat]) @@ -382,6 +386,7 @@ bool ModSequenceSet::ConvertSubsongsToMultipleSequences() } } } + ord--; } } SetSequence(0); diff --git a/soundlib/SampleFormatFLAC.cpp b/soundlib/SampleFormatFLAC.cpp index 09aed0a..63de71c 100644 --- a/soundlib/SampleFormatFLAC.cpp +++ b/soundlib/SampleFormatFLAC.cpp @@ -196,8 +196,8 @@ struct FLACDecoder if(length > 6 && !mpt::CompareNoCaseAscii(tag, "TITLE=", 6)) { mpt::ustring sampleName; - mpt::String::Read<mpt::String::maybeNullTerminated>(sampleName, client.sndFile.GetCharsetInternal(), tag + 6, length - 6); - mpt::String::Copy(client.sndFile.m_szNames[client.sample], mpt::ToCharset(mpt::CharsetUTF8, sampleName)); + mpt::String::Read<mpt::String::maybeNullTerminated>(sampleName, mpt::CharsetUTF8, tag + 6, length - 6); + mpt::String::Copy(client.sndFile.m_szNames[client.sample], mpt::ToCharset(client.sndFile.GetCharsetInternal(), sampleName)); } else if(length > 11 && !mpt::CompareNoCaseAscii(tag, "SAMPLERATE=", 11)) { uint32 sampleRate = ConvertStrTo<uint32>(tag + 11); diff --git a/soundlib/SampleIO.cpp b/soundlib/SampleIO.cpp index bb371b2..f7cf942 100644 --- a/soundlib/SampleIO.cpp +++ b/soundlib/SampleIO.cpp @@ -1018,8 +1018,7 @@ size_t SampleIO::WriteSample(std::ostream &f, const ModSample &sample, SmpLength MPT_ASSERT(len == numSamples); if(sample.uFlags[CHN_16BIT]) { - const int16 *const pSample16 = sample.sample16(); - const int16 *p = pSample16; + const int16 *p = sample.sample16(); int s_old = 0; const int s_ofs = (GetEncoding() == unsignedPCM) ? 0x80 : 0; for(SmpLength j = 0; j < numSamples; j++) @@ -1028,7 +1027,7 @@ size_t SampleIO::WriteSample(std::ostream &f, const ModSample &sample, SmpLength p++; if(sample.uFlags[CHN_STEREO]) { - s_new = (s_new + (static_cast<int>(*p)) + 1) / 2; + s_new = (s_new + mpt::rshift_signed(*p, 8) + 1) / 2; p++; } if(GetEncoding() == deltaPCM) diff --git a/soundlib/Snd_defs.h b/soundlib/Snd_defs.h index 7522582..02f21d0 100644 --- a/soundlib/Snd_defs.h +++ b/soundlib/Snd_defs.h @@ -366,14 +366,14 @@ enum PluginMutePriority }; // Plugin velocity handling options -enum PLUGVELOCITYHANDLING +enum PlugVelocityHandling : uint8 { PLUGIN_VELOCITYHANDLING_CHANNEL = 0, PLUGIN_VELOCITYHANDLING_VOLUME }; // Plugin volumecommand handling options -enum PLUGVOLUMEHANDLING +enum PlugVolumeHandling : uint8 { PLUGIN_VOLUMEHANDLING_MIDI = 0, PLUGIN_VOLUMEHANDLING_DRYWET, @@ -514,6 +514,7 @@ enum PlayBehaviour kFT2NoteDelayWithoutInstr, // Sometime between OpenMPT 1.18.03.00 and 1.19.01.00, delayed instrument-less notes in XM started recalling the default sample volume and panning kOPLFlexibleNoteOff, // Full control after note-off over OPL voices, ^^^ sends note cut instead of just note-off kITInstrWithNoteOffOldEffects, // Instrument number with note-off recalls default volume - special cases with Old Effects enabled + kMIDIVolumeOnNoteOffBug, // Update MIDI channel volume on note-off (legacy bug emulation) // Add new play behaviours here. diff --git a/soundlib/Snd_fx.cpp b/soundlib/Snd_fx.cpp index a2b0b87..2da930a 100644 --- a/soundlib/Snd_fx.cpp +++ b/soundlib/Snd_fx.cpp @@ -1025,7 +1025,8 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod if(m.note == NOTE_KEYOFF || m.note == NOTE_NOTECUT || (m.note == NOTE_FADE && GetNumInstruments()) || ((m.command == CMD_MODCMDEX || m.command == CMD_S3MCMDEX) && (m.param & 0xF0) == 0xC0 && paramLo < numTicks) - || (m.command == CMD_DELAYCUT && paramLo != 0 && startTick + paramLo < numTicks)) + || (m.command == CMD_DELAYCUT && paramLo != 0 && startTick + paramLo < numTicks) + || m.command == CMD_KEYOFF) { stopNote = true; } @@ -1452,7 +1453,6 @@ void CSoundFile::InstrumentChange(ModChannel &chn, uint32 instr, bool bPorta, bo if(returnAfterVolumeAdjust) return; - // Instrument adjust chn.nNewIns = 0; @@ -4487,6 +4487,15 @@ void CSoundFile::ExtendedMODCommands(CHANNELINDEX nChn, ModCommand::PARAM param) { chn.nFineTune = MOD2XMFineTune(param); if(chn.nPeriod && chn.rowCommand.IsNote()) chn.nPeriod = GetPeriodFromNote(chn.nNote, chn.nFineTune, chn.nC5Speed); + } else if(GetType() == MOD_TYPE_MTM) + { + if(chn.rowCommand.IsNote() && chn.pModSample != nullptr) + { + // Effect is permanent in MultiTracker + const_cast<ModSample *>(chn.pModSample)->nFineTune = param; + chn.nFineTune = param; + if(chn.nPeriod) chn.nPeriod = GetPeriodFromNote(chn.nNote, chn.nFineTune, chn.nC5Speed); + } } else if(chn.rowCommand.IsNote()) { chn.nFineTune = MOD2XMFineTune(param - 8); @@ -5578,7 +5587,7 @@ void CSoundFile::KeyOff(ModChannel &chn) const if(chn.position.GetUInt() > chn.nLength) { // Test case: SusAfterLoop.it - chn.position.Set(chn.position.GetInt() - chn.nLength + chn.nLoopStart); + chn.position.Set(chn.nLoopStart + ((chn.position.GetInt() - chn.nLoopStart) % (chn.nLoopEnd - chn.nLoopStart))); } } else { @@ -5657,7 +5666,7 @@ void CSoundFile::SetTempo(TEMPO param, bool setFromUI) // ProTracker sets the tempo after the first tick. // Note: The case of one tick per row is handled in ProcessRow() instead. // Test case: TempoChange.mod -#if MPT_MSVC_AT_LEAST(2017,8) +#if MPT_MSVC_AT_LEAST(2017,8) && MPT_MSVC_BEFORE(2019,0) // Work-around MSVC getting confused about deduced const input type in noexcept operator inside noexcept condition. m_PlayState.m_nMusicTempo.SetRaw(std::min(param.GetRaw(), specs.GetTempoMax().GetRaw())); #else @@ -5837,15 +5846,18 @@ uint32 CSoundFile::GetPeriodFromNote(uint32 note, int32 nFineTune, uint32 nC5Spe return Util::muldiv_unsigned(8363, (FreqS3MTable[note % 12u] << 5), nC5Speed << (note / 12u)); //8363 * freq[note%12] / nC5Speed * 2^(5-note/12) } - } else if (GetType() == MOD_TYPE_XM) + } else if (GetType() & (MOD_TYPE_XM | MOD_TYPE_MTM)) { if (note < 12) note = 12; note -= 12; - // FT2 Compatibility: The lower three bits of the finetune are truncated. - // Test case: Finetune-Precision.xm - if(m_playBehaviour[kFT2FinetunePrecision]) + if(GetType() == MOD_TYPE_MTM) + { + nFineTune *= 16; + } else if(m_playBehaviour[kFT2FinetunePrecision]) { + // FT2 Compatibility: The lower three bits of the finetune are truncated. + // Test case: Finetune-Precision.xm nFineTune &= ~7; } @@ -5892,7 +5904,7 @@ uint32 CSoundFile::GetPeriodFromNote(uint32 note, int32 nFineTune, uint32 nC5Spe uint32 CSoundFile::GetFreqFromPeriod(uint32 period, uint32 c5speed, int32 nPeriodFrac) const { if (!period) return 0; - if (GetType() == MOD_TYPE_XM) + if (GetType() & (MOD_TYPE_XM | MOD_TYPE_MTM)) { if(m_playBehaviour[kFT2Periods]) { diff --git a/soundlib/Sndfile.cpp b/soundlib/Sndfile.cpp index 2481b17..45e0ed6 100644 --- a/soundlib/Sndfile.cpp +++ b/soundlib/Sndfile.cpp @@ -711,7 +711,7 @@ void CSoundFile::SetDspEffects(uint32 DSPMask) { #ifdef ENABLE_ASM #ifndef NO_REVERB - if(!(GetProcSupport() & PROCSUPPORT_MMX)) DSPMask &= ~SNDDSP_REVERB; + if(!(GetRealProcSupport() & PROCSUPPORT_MMX)) DSPMask &= ~SNDDSP_REVERB; #endif #endif m_MixerSettings.DSPMask = DSPMask; @@ -1163,7 +1163,6 @@ PlayBehaviourSet CSoundFile::GetDefaultPlaybackBehaviour(MODTYPE type) break; case MOD_TYPE_MOD: - playBehaviour.set(kMODSampleSwap); playBehaviour.set(kRowDelayWithNoteDelay); break; diff --git a/soundlib/Sndmix.cpp b/soundlib/Sndmix.cpp index 566441e..7f51ccf 100644 --- a/soundlib/Sndmix.cpp +++ b/soundlib/Sndmix.cpp @@ -1036,7 +1036,8 @@ void CSoundFile::ProcessVolumeEnvelope(ModChannel &chn, int &vol) const // if we are in the release portion of the envelope, // rescale envelope factor so that it is proportional to the release point // and release envelope beginning. - if(chn.VolEnv.nEnvValueAtReleaseJump != NOT_YET_RELEASED) + if(pIns->VolEnv.nReleaseNode != ENV_RELEASE_NODE_UNSET + && chn.VolEnv.nEnvValueAtReleaseJump != NOT_YET_RELEASED) { int envValueAtReleaseJump = chn.VolEnv.nEnvValueAtReleaseJump; int envValueAtReleaseNode = pIns->VolEnv[pIns->VolEnv.nReleaseNode].value * 4; @@ -2315,12 +2316,12 @@ bool CSoundFile::ReadNote() if (chn.pCurrentSample || (chn.HasMIDIOutput() && !chn.dwFlags[CHN_KEYOFF | CHN_NOTEFADE])) { // Update VU-Meter (nRealVolume is 14-bit) - uint32 vul = (chn.nRealVolume * chn.nRealPan) / (1 << 14); + uint32 vul = (chn.nRealVolume * (256-chn.nRealPan)) / (1 << 14); if (vul > 127) vul = 127; if (chn.nLeftVU > 127) chn.nLeftVU = (uint8)vul; vul /= 2; if (chn.nLeftVU < vul) chn.nLeftVU = (uint8)vul; - uint32 vur = (chn.nRealVolume * (256-chn.nRealPan)) / (1 << 14); + uint32 vur = (chn.nRealVolume * chn.nRealPan) / (1 << 14); if (vur > 127) vur = 127; if (chn.nRightVU > 127) chn.nRightVU = (uint8)vur; vur /= 2; @@ -2394,13 +2395,13 @@ bool CSoundFile::ReadNote() //if (chn.nNewRightVol > 0xFFFF) chn.nNewRightVol = 0xFFFF; //if (chn.nNewLeftVol > 0xFFFF) chn.nNewLeftVol = 0xFFFF; - if(chn.pModInstrument && Resampling::IsKnownMode(chn.pModInstrument->nResampling)) + if(chn.pModInstrument && Resampling::IsKnownMode(chn.pModInstrument->resampling)) { // For defined resampling modes, use per-instrument resampling mode if set - chn.resamplingMode = static_cast<uint8>(chn.pModInstrument->nResampling); + chn.resamplingMode = chn.pModInstrument->resampling; } else if(Resampling::IsKnownMode(m_nResampling)) { - chn.resamplingMode = static_cast<uint8>(m_nResampling); + chn.resamplingMode = m_nResampling; } else if(m_SongFlags[SONG_ISAMIGA] && m_Resampler.m_Settings.emulateAmiga) { // Enforce Amiga resampler for Amiga modules @@ -2408,7 +2409,7 @@ bool CSoundFile::ReadNote() } else { // Default to global mixer settings - chn.resamplingMode = static_cast<uint8>(m_Resampler.m_Settings.SrcMode); + chn.resamplingMode = m_Resampler.m_Settings.SrcMode; } if(chn.increment.IsUnity() && !(chn.dwFlags[CHN_VIBRATO] || chn.nAutoVibDepth || chn.resamplingMode == SRCMODE_AMIGA)) @@ -2540,11 +2541,13 @@ void CSoundFile::ProcessMidiOut(CHANNELINDEX nChn) if(note != NOTE_NONE) { int32 velocity = static_cast<int32>(4 * defaultVolume); - switch(pIns->nPluginVelocityHandling) + switch(pIns->pluginVelocityHandling) { case PLUGIN_VELOCITYHANDLING_CHANNEL: velocity = chn.nVolume; - break; + break; + default: + break; } int32 swing = chn.nVolSwing; @@ -2560,23 +2563,23 @@ void CSoundFile::ProcessMidiOut(CHANNELINDEX nChn) SendMIDINote(nChn, realNote, static_cast<uint16>(velocity)); } + const bool processVolumeAlsoOnNote = (pIns->pluginVelocityHandling == PLUGIN_VELOCITYHANDLING_VOLUME); + const bool hasNote = m_playBehaviour[kMIDIVolumeOnNoteOffBug] ? (note != NOTE_NONE) : ModCommand::IsNote(note); - const bool processVolumeAlsoOnNote = (pIns->nPluginVelocityHandling == PLUGIN_VELOCITYHANDLING_VOLUME); - - if((hasVolCommand && !note) || (note && processVolumeAlsoOnNote)) + if((hasVolCommand && !hasNote) || (hasNote && processVolumeAlsoOnNote)) { - switch(pIns->nPluginVolumeHandling) + switch(pIns->pluginVolumeHandling) { case PLUGIN_VOLUMEHANDLING_DRYWET: if(hasVolCommand) pPlugin->SetDryRatio(2 * vol); else pPlugin->SetDryRatio(2 * defaultVolume); break; - case PLUGIN_VOLUMEHANDLING_MIDI: if(hasVolCommand) pPlugin->MidiCC(MIDIEvents::MIDICC_Volume_Coarse, std::min<uint8>(127u, 2u * vol), nChn); else pPlugin->MidiCC(MIDIEvents::MIDICC_Volume_Coarse, static_cast<uint8>(std::min<uint32>(127u, 2u * defaultVolume)), nChn); break; - + default: + break; } } } diff --git a/soundlib/UpgradeModule.cpp b/soundlib/UpgradeModule.cpp index 33e70af..c614d58 100644 --- a/soundlib/UpgradeModule.cpp +++ b/soundlib/UpgradeModule.cpp @@ -413,6 +413,18 @@ void CSoundFile::UpgradeModule() } } + if(m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 28, 03, 04)) + { + for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) if (Instruments[i] != nullptr) + { + if(Instruments[i]->pluginVolumeHandling == PLUGIN_VOLUMEHANDLING_MIDI || Instruments[i]->pluginVolumeHandling == PLUGIN_VOLUMEHANDLING_DRYWET) + { + m_playBehaviour.set(kMIDIVolumeOnNoteOffBug); + break; + } + } + } + Patterns.ForEachModCommand(UpgradePatternData(*this)); // Convert compatibility flags |