diff --git a/mptrack/OPLExport.cpp b/mptrack/OPLExport.cpp index 4ed3278fc4..9ccc8fbd8f 100644 --- a/mptrack/OPLExport.cpp +++ b/mptrack/OPLExport.cpp @@ -336,7 +336,7 @@ class OPLCapture final : public OPL::IRegisterLogger mpt::IO::Write(f, s16le); } - void Port(CHANNELINDEX, uint16 reg, uint8 value) override + void Port(CHANNELINDEX, OPL::Register reg, OPL::Value value) override { if(const auto prevValue = m_prevRegisters.find(reg); prevValue != m_prevRegisters.end() && prevValue->second == value) return; @@ -345,7 +345,7 @@ class OPLCapture final : public OPL::IRegisterLogger } std::vector m_registerDump; - std::map m_prevRegisters, m_registerDumpAtLoopStart; + std::map m_prevRegisters, m_registerDumpAtLoopStart; CSoundFile &m_sndFile; }; diff --git a/soundlib/ModChannel.cpp b/soundlib/ModChannel.cpp index 95f4e4bcb6..f7bd8157e6 100644 --- a/soundlib/ModChannel.cpp +++ b/soundlib/ModChannel.cpp @@ -1,7 +1,8 @@ /* * ModChannel.cpp * -------------- - * Purpose: Module Channel header class and helpers + * Purpose: The ModChannel struct represents the state of one mixer channel. + * ModChannelSettings represents the default settings of one pattern channel. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. @@ -9,8 +10,8 @@ #include "stdafx.h" -#include "Sndfile.h" #include "ModChannel.h" +#include "Sndfile.h" #include "tuning.h" OPENMPT_NAMESPACE_BEGIN @@ -128,7 +129,13 @@ void ModChannel::UpdateInstrumentVolume(const ModSample *smp, const ModInstrumen } -ModCommand::NOTE ModChannel::GetPluginNote(bool ignoreArpeggio) const +uint32 ModChannel::GetVSTVolume() const noexcept +{ + return pModInstrument ? pModInstrument->nGlobalVol * 4 : nVolume; +} + + +ModCommand::NOTE ModChannel::GetPluginNote(bool ignoreArpeggio) const noexcept { if(nArpeggioLastNote != NOTE_NONE && !ignoreArpeggio) { @@ -144,6 +151,24 @@ ModCommand::NOTE ModChannel::GetPluginNote(bool ignoreArpeggio) const } +bool ModChannel::HasMIDIOutput() const noexcept +{ + return pModInstrument != nullptr && pModInstrument->HasValidMIDIChannel(); +} + + +bool ModChannel::HasCustomTuning() const noexcept +{ + return pModInstrument != nullptr && pModInstrument->pTuning != nullptr; +} + + +bool ModChannel::InSustainLoop() const noexcept +{ + return (dwFlags & (CHN_LOOP | CHN_KEYOFF)) == CHN_LOOP && pModSample->uFlags[CHN_SUSTAINLOOP]; +} + + void ModChannel::SetInstrumentPan(int32 pan, const CSoundFile &sndFile) { // IT compatibility: Instrument and sample panning does not override channel panning diff --git a/soundlib/ModChannel.h b/soundlib/ModChannel.h index 242c836c30..52f6b40692 100644 --- a/soundlib/ModChannel.h +++ b/soundlib/ModChannel.h @@ -1,7 +1,8 @@ /* * ModChannel.h * ------------ - * Purpose: Module Channel header class and helpers + * Purpose: The ModChannel struct represents the state of one mixer channel. + * ModChannelSettings represents the default settings of one pattern channel. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. @@ -13,8 +14,6 @@ #include "openmpt/all/BuildSettings.hpp" #include "InstrumentSynth.h" -#include "ModSample.h" -#include "ModInstrument.h" #include "modcommand.h" #include "Paula.h" #include "tuningbase.h" @@ -22,6 +21,8 @@ OPENMPT_NAMESPACE_BEGIN class CSoundFile; +struct ModSample; +struct ModInstrument; // Mix Channel Struct struct ModChannel @@ -187,17 +188,17 @@ struct ModChannel bool IsSamplePlaying() const noexcept { return !increment.IsZero(); } - uint32 GetVSTVolume() const noexcept { return (pModInstrument) ? pModInstrument->nGlobalVol * 4 : nVolume; } + uint32 GetVSTVolume() const noexcept; - ModCommand::NOTE GetPluginNote(bool ignoreArpeggio = false) const; + ModCommand::NOTE GetPluginNote(bool ignoreArpeggio = false) const noexcept; // Check if the channel has a valid MIDI output. A return value of true implies that pModInstrument != nullptr. - bool HasMIDIOutput() const noexcept { return pModInstrument != nullptr && pModInstrument->HasValidMIDIChannel(); } + bool HasMIDIOutput() const noexcept; // Check if the channel uses custom tuning. A return value of true implies that pModInstrument != nullptr. - bool HasCustomTuning() const noexcept { return pModInstrument != nullptr && pModInstrument->pTuning != nullptr; } + bool HasCustomTuning() const noexcept; // Check if currently processed loop is a sustain loop. pModSample is not checked for validity! - bool InSustainLoop() const noexcept { return (dwFlags & (CHN_LOOP | CHN_KEYOFF)) == CHN_LOOP && pModSample->uFlags[CHN_SUSTAINLOOP]; } + bool InSustainLoop() const noexcept; void UpdateInstrumentVolume(const ModSample *smp, const ModInstrument *ins); diff --git a/soundlib/OPL.cpp b/soundlib/OPL.cpp index 6a039c6d92..5c51d2a9b1 100644 --- a/soundlib/OPL.cpp +++ b/soundlib/OPL.cpp @@ -9,8 +9,8 @@ */ #include "stdafx.h" -#include "../common/misc_util.h" #include "OPL.h" +#include "../common/misc_util.h" #include #if MPT_COMPILER_GCC @@ -24,9 +24,9 @@ OPENMPT_NAMESPACE_BEGIN -OPL::OPL(uint32 samplerate) +OPL::OPL(uint32 sampleRate) { - Initialize(samplerate); + Initialize(sampleRate); } @@ -43,12 +43,12 @@ OPL::~OPL() } -void OPL::Initialize(uint32 samplerate) +void OPL::Initialize(uint32 sampleRate) { if(m_opl == nullptr) - m_opl = std::make_unique(samplerate); + m_opl = std::make_unique(sampleRate); else - m_opl->SetSampleRate(samplerate); + m_opl->SetSampleRate(sampleRate); Reset(); } @@ -71,7 +71,7 @@ void OPL::Mix(int32 *target, size_t count, uint32 volumeFactorQ16) } -uint16 OPL::ChannelToRegister(uint8 oplCh) +OPL::Register OPL::ChannelToRegister(uint8 oplCh) { if(oplCh < 9) return oplCh; @@ -81,7 +81,7 @@ uint16 OPL::ChannelToRegister(uint8 oplCh) // Translate a channel's first operator address into a register -uint16 OPL::OperatorToRegister(uint8 oplCh) +OPL::Register OPL::OperatorToRegister(uint8 oplCh) { static constexpr uint8 OPLChannelToOperator[] = { 0, 1, 2, 8, 9, 10, 16, 17, 18 }; if(oplCh < 9) @@ -211,7 +211,7 @@ void OPL::Frequency(CHANNELINDEX c, uint32 milliHertz, bool keyOff, bool beating fnum |= (block << 10); - uint16 channel = ChannelToRegister(oplCh); + OPL::Register channel = ChannelToRegister(oplCh); m_KeyOnBlock[oplCh] = static_cast((keyOff ? 0 : KEYON_BIT) | (fnum >> 8)); // Key on bit + Octave (block) + F-number high 2 bits Port(c, FNUM_LOW | channel, fnum & 0xFFu); // F-Number low 8 bits Port(c, KEYON_BLOCK | channel, m_KeyOnBlock[oplCh]); @@ -237,7 +237,7 @@ void OPL::Volume(CHANNELINDEX c, uint8 vol, bool applyToModulator) return; const auto &patch = m_Patches[oplCh]; - const uint16 modulator = OperatorToRegister(oplCh), carrier = modulator + 3; + const OPL::Register modulator = OperatorToRegister(oplCh), carrier = modulator + 3; if((patch[10] & CONNECTION_BIT) || applyToModulator) { // Set volume of both operators in additive mode @@ -279,7 +279,7 @@ void OPL::Patch(CHANNELINDEX c, const OPLPatch &patch) m_Patches[oplCh] = patch; - const uint16 modulator = OperatorToRegister(oplCh), carrier = modulator + 3; + const OPL::Register modulator = OperatorToRegister(oplCh), carrier = modulator + 3; for(uint8 op = 0; op < 2; op++) { const auto opReg = op ? carrier : modulator; @@ -314,7 +314,7 @@ void OPL::Reset() } -void OPL::Port(CHANNELINDEX c, uint16 reg, uint8 value) +void OPL::Port(CHANNELINDEX c, OPL::Register reg, OPL::Value value) { if(!m_logger) m_opl->Port(reg, value); @@ -323,11 +323,11 @@ void OPL::Port(CHANNELINDEX c, uint16 reg, uint8 value) } -std::vector OPL::AllVoiceRegisters() +std::vector OPL::AllVoiceRegisters() { - static constexpr uint8 opRegisters[] = {OPL::AM_VIB, OPL::KSL_LEVEL, OPL::ATTACK_DECAY, OPL::SUSTAIN_RELEASE, OPL::WAVE_SELECT}; - static constexpr uint8 chnRegisters[] = {OPL::FNUM_LOW, OPL::KEYON_BLOCK, OPL::FEEDBACK_CONNECTION}; - std::vector result; + static constexpr uint8 opRegisters[] = {AM_VIB, KSL_LEVEL, ATTACK_DECAY, SUSTAIN_RELEASE, WAVE_SELECT}; + static constexpr uint8 chnRegisters[] = {FNUM_LOW, KEYON_BLOCK, FEEDBACK_CONNECTION}; + std::vector result; result.reserve(234); for(uint16 chip = 0; chip < 2; chip++) { diff --git a/soundlib/OPL.h b/soundlib/OPL.h index bf1fee002e..6107f75479 100644 --- a/soundlib/OPL.h +++ b/soundlib/OPL.h @@ -23,16 +23,18 @@ class OPL enum OPLRegisters : uint8 { // Operators (combine with result of OperatorToRegister) - AM_VIB = 0x20, // AM / VIB / EG / KSR / Multiple (0x20 to 0x35) - KSL_LEVEL = 0x40, // KSL / Total level (0x40 to 0x55) - ATTACK_DECAY = 0x60, // Attack rate / Decay rate (0x60 to 0x75) - SUSTAIN_RELEASE = 0x80, // Sustain level / Release rate (0x80 to 0x95) - WAVE_SELECT = 0xE0, // Wave select (0xE0 to 0xF5) + AM_VIB = 0x20, // AM / VIB / EG / KSR / Multiple (0x20 to 0x35) + KSL_LEVEL = 0x40, // KSL / Total level (0x40 to 0x55) + ATTACK_DECAY = 0x60, // Attack rate / Decay rate (0x60 to 0x75) + SUSTAIN_RELEASE = 0x80, // Sustain level / Release rate (0x80 to 0x95) + WAVE_SELECT = 0xE0, // Wave select (0xE0 to 0xF5) // Channels (combine with result of ChannelToRegister) - FNUM_LOW = 0xA0, // F-number low bits (0xA0 to 0xA8) - KEYON_BLOCK = 0xB0, // F-number high bits / Key on / Block (octave) (0xB0 to 0xB8) - FEEDBACK_CONNECTION = 0xC0, // Feedback / Connection (0xC0 to 0xC8) + FNUM_LOW = 0xA0, // F-number low bits (0xA0 to 0xA8) + KEYON_BLOCK = 0xB0, // F-number high bits / Key on / Block (octave) (0xB0 to 0xB8) + FEEDBACK_CONNECTION = 0xC0, // Feedback / Connection (0xC0 to 0xC8) + + TREMOLO_VIBRATO_DEPTH = 0xBD, // Tremolo Depth / Vibrato Depth / Percussion Mode / BD/SD/TT/CY/HH Key-On }; enum OPLValues : uint8 @@ -41,12 +43,12 @@ class OPL TREMOLO_ON = 0x80, VIBRATO_ON = 0x40, SUSTAIN_ON = 0x20, - KSR = 0x10, // Key scaling rate - MULTIPLE_MASK = 0x0F, // Frequency multiplier + KSR = 0x10, // Key scaling rate + MULTIPLE_MASK = 0x0F, // Frequency multiplier // KSL_LEVEL - KSL_MASK = 0xC0, // Envelope scaling bits - TOTAL_LEVEL_MASK = 0x3F, // Strength (volume) of OP + KSL_MASK = 0xC0, // Envelope scaling bits + TOTAL_LEVEL_MASK = 0x3F, // Strength (volume) of OP // ATTACK_DECAY ATTACK_MASK = 0xF0, @@ -60,25 +62,28 @@ class OPL KEYON_BIT = 0x20, // FEEDBACK_CONNECTION - FEEDBACK_MASK = 0x0E, // Valid just for first OP of a voice + FEEDBACK_MASK = 0x0E, // Valid just for first OP of a voice CONNECTION_BIT = 0x01, VOICE_TO_LEFT = 0x10, VOICE_TO_RIGHT = 0x20, STEREO_BITS = VOICE_TO_LEFT | VOICE_TO_RIGHT, }; + using Register = uint16; + using Value = uint8; + class IRegisterLogger { public: - virtual void Port(CHANNELINDEX c, uint16 reg, uint8 value) = 0; + virtual void Port(CHANNELINDEX c, Register reg, Value value) = 0; virtual ~IRegisterLogger() {} }; - OPL(uint32 samplerate); - OPL(IRegisterLogger &logger); + explicit OPL(uint32 sampleRate); + explicit OPL(IRegisterLogger &logger); ~OPL(); - void Initialize(uint32 samplerate); + void Initialize(uint32 sampleRate); void Mix(int32 *buffer, size_t count, uint32 volumeFactorQ16); void NoteOff(CHANNELINDEX c); @@ -92,15 +97,15 @@ class OPL void Reset(); // A list of all registers for channels and operators - static std::vector AllVoiceRegisters(); + static std::vector AllVoiceRegisters(); protected: - static uint16 ChannelToRegister(uint8 oplCh); - static uint16 OperatorToRegister(uint8 oplCh); + static Register ChannelToRegister(uint8 oplCh); + static Register OperatorToRegister(uint8 oplCh); static uint8 CalcVolume(uint8 trackerVol, uint8 kslVolume); uint8 GetVoice(CHANNELINDEX c) const; uint8 AllocateVoice(CHANNELINDEX c); - void Port(CHANNELINDEX c, uint16 reg, uint8 value); + void Port(CHANNELINDEX c, Register reg, Value value); enum { diff --git a/soundlib/Sndmix.cpp b/soundlib/Sndmix.cpp index ae8b75023c..26ede66631 100644 --- a/soundlib/Sndmix.cpp +++ b/soundlib/Sndmix.cpp @@ -1156,7 +1156,6 @@ void CSoundFile::ProcessPanningEnvelope(ModChannel &chn) const pan += (envval * (pan)) / 32; } chn.nRealPan = Clamp(pan, 0, 256); - } } @@ -1374,7 +1373,8 @@ void CSoundFile::ProcessInstrumentFade(ModChannel &chn, int &vol) const if (fadeout) { chn.nFadeOutVol -= fadeout * 2; - if (chn.nFadeOutVol <= 0) chn.nFadeOutVol = 0; + if (chn.nFadeOutVol <= 0) + chn.nFadeOutVol = 0; vol = (vol * chn.nFadeOutVol) / 65536; } else if (!chn.nFadeOutVol) {