diff --git a/src/CGBChannel.cpp b/src/CGBChannel.cpp index 257b56e..a06bac0 100644 --- a/src/CGBChannel.cpp +++ b/src/CGBChannel.cpp @@ -13,8 +13,8 @@ * public CGBChannel */ -CGBChannel::CGBChannel(uint8_t owner, ADSR env, Note note, uint8_t vol, int8_t pan) - : env(env), note(note), owner(owner) +CGBChannel::CGBChannel(uint8_t owner, ADSR env, Note note, uint8_t vol, int8_t pan, int8_t instPan) + : env(env), note(note), owner(owner), instPan(instPan) { this->env.att &= 0x7; this->env.dec &= 0x7; @@ -30,11 +30,13 @@ uint8_t CGBChannel::GetOwner() const void CGBChannel::SetVol(uint8_t vol, int8_t pan) { + int combinedPan = std::clamp(pan + instPan, -64, +63); + if (eState < EnvState::REL) { - if (pan < -21) { + if (combinedPan < -21) { // snap left this->pan = Pan::LEFT; - } else if (pan > 20) { + } else if (combinedPan > 20) { // snap right this->pan = Pan::RIGHT; } else { @@ -310,8 +312,8 @@ void CGBChannel::updateVolFade() * public SquareChannel */ -SquareChannel::SquareChannel(uint8_t owner, WaveDuty wd, ADSR env, Note note, uint8_t vol, int8_t pan, int16_t pitch) - : CGBChannel(owner, env, note, vol, pan) +SquareChannel::SquareChannel(uint8_t owner, WaveDuty wd, ADSR env, Note note, uint8_t vol, int8_t pan, int8_t instPan, int16_t pitch) + : CGBChannel(owner, env, note, vol, pan, instPan) { SetPitch(pitch); @@ -392,8 +394,8 @@ uint8_t WaveChannel::volLut[] = { 0, 0, 4, 4, 4, 4, 8, 8, 8, 8, 12, 12, 12, 12, 16, 16 }; -WaveChannel::WaveChannel(uint8_t owner, const uint8_t *wavePtr, ADSR env, Note note, uint8_t vol, int8_t pan, int16_t pitch) - : CGBChannel(owner, env, note, vol, pan) +WaveChannel::WaveChannel(uint8_t owner, const uint8_t *wavePtr, ADSR env, Note note, uint8_t vol, int8_t pan, int8_t instPan, int16_t pitch) + : CGBChannel(owner, env, note, vol, pan, instPan) { SetPitch(pitch); @@ -474,8 +476,8 @@ bool WaveChannel::sampleFetchCallback(std::vector& fetchBuffer, size_t sa * public NoiseChannel */ -NoiseChannel::NoiseChannel(uint8_t owner, NoisePatt np, ADSR env, Note note, uint8_t vol, int8_t pan, int16_t pitch) - : CGBChannel(owner, env, note, vol, pan) +NoiseChannel::NoiseChannel(uint8_t owner, NoisePatt np, ADSR env, Note note, uint8_t vol, int8_t pan, int8_t instPan, int16_t pitch) + : CGBChannel(owner, env, note, vol, pan, instPan) { SetPitch(pitch); this->rs = std::make_unique(); diff --git a/src/CGBChannel.h b/src/CGBChannel.h index c4af37b..9750f57 100644 --- a/src/CGBChannel.h +++ b/src/CGBChannel.h @@ -14,7 +14,7 @@ class CGBChannel { public: - CGBChannel(uint8_t owner, ADSR env, Note note, uint8_t vol, int8_t pan); + CGBChannel(uint8_t owner, ADSR env, Note note, uint8_t vol, int8_t pan, int8_t instPan); CGBChannel(const CGBChannel&) = delete; CGBChannel& operator=(const CGBChannel&) = delete; virtual ~CGBChannel() = default; @@ -46,6 +46,7 @@ class CGBChannel uint8_t envPeak = 0; uint8_t envSustain = 0; uint8_t owner; + const int8_t instPan; // these values are always 1 frame behind in order to provide a smooth transition Pan fromPan = Pan::CENTER; uint8_t fromEnvLevel = 0; @@ -54,7 +55,7 @@ class CGBChannel class SquareChannel : public CGBChannel { public: - SquareChannel(uint8_t owner, WaveDuty wd, ADSR env, Note note, uint8_t vol, int8_t pan, int16_t pitch); + SquareChannel(uint8_t owner, WaveDuty wd, ADSR env, Note note, uint8_t vol, int8_t pan, int8_t instPan, int16_t pitch); void SetPitch(int16_t pitch) override; void Process(sample *buffer, size_t numSamples, MixingArgs& args) override; @@ -67,7 +68,7 @@ class SquareChannel : public CGBChannel class WaveChannel : public CGBChannel { public: - WaveChannel(uint8_t owner, const uint8_t *wavePtr, ADSR env, Note note, uint8_t vol, int8_t pan, int16_t pitch); + WaveChannel(uint8_t owner, const uint8_t *wavePtr, ADSR env, Note note, uint8_t vol, int8_t pan, int8_t instPan, int16_t pitch); void SetPitch(int16_t pitch) override; void Process(sample *buffer, size_t numSamples, MixingArgs& args) override; @@ -80,7 +81,7 @@ class WaveChannel : public CGBChannel class NoiseChannel : public CGBChannel { public: - NoiseChannel(uint8_t owner, NoisePatt np, ADSR env, Note note, uint8_t vol, int8_t pan, int16_t pitch); + NoiseChannel(uint8_t owner, NoisePatt np, ADSR env, Note note, uint8_t vol, int8_t pan, int8_t instPan, int16_t pitch); void SetPitch(int16_t pitch) override; void Process(sample *buffer, size_t numSamples, MixingArgs& args) override; diff --git a/src/SequenceReader.cpp b/src/SequenceReader.cpp index 03905b1..dd5aefd 100644 --- a/src/SequenceReader.cpp +++ b/src/SequenceReader.cpp @@ -442,37 +442,34 @@ void SequenceReader::playNote(Track& trk, Note note, uint8_t owner) uint8_t oldKey = note.midiKey; note.midiKey = ctx.bnk.GetMidiKey(trk.prog, oldKey); + uint8_t pan = ctx.bnk.GetPan(trk.prog, oldKey); + switch (ctx.bnk.GetInstrType(trk.prog, oldKey)) { case InstrType::PCM: - { - uint8_t pan = ctx.bnk.GetPan(trk.prog, oldKey); - ctx.sndChannels.emplace_back( - owner, - ctx.bnk.GetSampInfo(trk.prog, oldKey), - ctx.bnk.GetADSR(trk.prog, oldKey), - note, - trk.GetVol(), - (pan & 0x80) ? int8_t(int(pan) - 0xC0) : trk.GetPan(), - trk.GetPitch(), - false); - } + ctx.sndChannels.emplace_back( + owner, + ctx.bnk.GetSampInfo(trk.prog, oldKey), + ctx.bnk.GetADSR(trk.prog, oldKey), + note, + trk.GetVol(), + trk.GetPan(), + (pan & 0x80) ? int8_t(int(pan) - 0xC0) : 0, + trk.GetPitch(), + false); break; case InstrType::PCM_FIXED: - { - uint8_t pan = ctx.bnk.GetPan(trk.prog, oldKey); - ctx.sndChannels.emplace_back( - owner, - ctx.bnk.GetSampInfo(trk.prog, oldKey), - ctx.bnk.GetADSR(trk.prog, oldKey), - note, - trk.GetVol(), - (pan & 0x80) ? int8_t(int(pan) - 0xC0) : trk.GetPan(), - trk.GetPitch(), - true); - } + ctx.sndChannels.emplace_back( + owner, + ctx.bnk.GetSampInfo(trk.prog, oldKey), + ctx.bnk.GetADSR(trk.prog, oldKey), + note, + trk.GetVol(), + trk.GetPan(), + (pan & 0x80) ? int8_t(int(pan) - 0xC0) : 0, + trk.GetPitch(), + true); break; case InstrType::SQ1: - // TODO Does pan of drum tables really only affect PCM channels? cgbPolyphonySuppressFunc(ctx.sq1Channels); ctx.sq1Channels.emplace_back( owner, @@ -481,6 +478,7 @@ void SequenceReader::playNote(Track& trk, Note note, uint8_t owner) note, trk.GetVol(), trk.GetPan(), + (pan & 0x80) ? int8_t(int(pan) - 0xC0) : 0, trk.GetPitch()); break; case InstrType::SQ2: @@ -492,6 +490,7 @@ void SequenceReader::playNote(Track& trk, Note note, uint8_t owner) note, trk.GetVol(), trk.GetPan(), + (pan & 0x80) ? int8_t(int(pan) - 0xC0) : 0, trk.GetPitch()); break; case InstrType::WAVE: @@ -503,6 +502,7 @@ void SequenceReader::playNote(Track& trk, Note note, uint8_t owner) note, trk.GetVol(), trk.GetPan(), + (pan & 0x80) ? int8_t(int(pan) - 0xC0) : 0, trk.GetPitch()); break; case InstrType::NOISE: @@ -514,6 +514,7 @@ void SequenceReader::playNote(Track& trk, Note note, uint8_t owner) note, trk.GetVol(), trk.GetPan(), + (pan & 0x80) ? int8_t(int(pan) - 0xC0) : 0, trk.GetPitch()); break; case InstrType::INVALID: diff --git a/src/SoundChannel.cpp b/src/SoundChannel.cpp index 04a85e8..fe0a930 100644 --- a/src/SoundChannel.cpp +++ b/src/SoundChannel.cpp @@ -13,8 +13,8 @@ * public SoundChannel */ -SoundChannel::SoundChannel(uint8_t owner, SampleInfo sInfo, ADSR env, Note note, uint8_t vol, int8_t pan, int16_t pitch, bool fixed) - : env(env), note(note), sInfo(sInfo), fixed(fixed), owner(owner) +SoundChannel::SoundChannel(uint8_t owner, SampleInfo sInfo, ADSR env, Note note, uint8_t vol, int8_t pan, int8_t instPan, int16_t pitch, bool fixed) + : env(env), note(note), sInfo(sInfo), fixed(fixed), owner(owner), instPan(instPan) { SetVol(vol, pan); @@ -109,8 +109,9 @@ uint8_t SoundChannel::GetOwner() const void SoundChannel::SetVol(uint8_t vol, int8_t pan) { if (eState < EnvState::REL) { - this->leftVol = uint8_t(note.velocity * vol * (-pan + 64) / 8192); - this->rightVol = uint8_t(note.velocity * vol * (pan + 64) / 8192); + int combinedPan = std::clamp(pan + instPan, -64, +63); + this->leftVol = uint8_t(note.velocity * vol * (-combinedPan + 64) / 8192); + this->rightVol = uint8_t(note.velocity * vol * (combinedPan + 64) / 8192); } } diff --git a/src/SoundChannel.h b/src/SoundChannel.h index d2429f3..8ee7728 100644 --- a/src/SoundChannel.h +++ b/src/SoundChannel.h @@ -19,7 +19,7 @@ class SoundChannel float interStep; }; public: - SoundChannel(uint8_t owner, SampleInfo sInfo, ADSR env, Note note, uint8_t vol, int8_t pan, int16_t pitch, bool fixed); + SoundChannel(uint8_t owner, SampleInfo sInfo, ADSR env, Note note, uint8_t vol, int8_t pan, int8_t instPan, int16_t pitch, bool fixed); SoundChannel(const SoundChannel&) = delete; SoundChannel& operator=(const SoundChannel&) = delete; @@ -58,6 +58,7 @@ class SoundChannel int16_t levelMPTcompressed; uint8_t shiftMPTcompressed; uint8_t owner; + const int8_t instPan; uint8_t envInterStep = 0; uint8_t leftVol; uint8_t rightVol;