From 3bc47baa1daa7da8287e7b2c12a41f8f07824cb1 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Sun, 19 Jun 2016 22:08:32 -1000 Subject: [PATCH] N64 SNG fixes --- include/amuse/SongState.hpp | 16 ++++---- include/amuse/Voice.hpp | 8 +--- lib/Sequencer.cpp | 6 +-- lib/SongState.cpp | 80 +++++++++++++++++-------------------- lib/SoundMacroState.cpp | 15 ++++--- lib/Voice.cpp | 20 +++++----- 6 files changed, 68 insertions(+), 77 deletions(-) diff --git a/include/amuse/SongState.hpp b/include/amuse/SongState.hpp index 99a40cd..10c263f 100644 --- a/include/amuse/SongState.hpp +++ b/include/amuse/SongState.hpp @@ -41,9 +41,9 @@ class SongState uint32_t m_startTick; uint16_t m_unk1; uint16_t m_unk2; - uint16_t m_regionIndex; - int16_t m_initialPitch; - void swapBig(); + int16_t m_regionIndex; + int16_t m_unk3; + bool indexValid() const; }; /** Tempo change entry */ @@ -56,8 +56,8 @@ class SongState const unsigned char* m_songData = nullptr; /**< Base pointer to active song */ - /** State of a single channel within arrangement */ - struct Channel + /** State of a single track within arrangement */ + struct Track { struct Header { @@ -79,17 +79,17 @@ class SongState int32_t m_lastPitchVal = 0; /**< Last value of pitch */ uint32_t m_lastModTick = 0; /**< Last position of mod wheel change */ int32_t m_lastModVal = 0; /**< Last value of mod */ - std::array m_remNoteLengths = {}; /**< Remaining ticks per note */ + std::array m_remNoteLengths; /**< Remaining ticks per note */ int32_t m_eventWaitCountdown = 0; /**< Current wait in ticks */ int32_t m_lastN64EventTick = 0; /**< Last command time on this channel (for computing delta times from absolute times in N64 songs) */ - Channel(SongState& parent, uint8_t midiChan, const TrackRegion* regions); + Track(SongState& parent, uint8_t midiChan, const TrackRegion* regions); void setRegion(Sequencer& seq, const TrackRegion* region); void advanceRegion(Sequencer& seq); bool advance(Sequencer& seq, int32_t ticks); }; - std::array, 64> m_channels; + std::array, 64> m_tracks; const uint32_t* m_regionIdx; /**< Table of offsets to song-region data */ /** Current pointer to tempo control, iterated over playback */ diff --git a/include/amuse/Voice.hpp b/include/amuse/Voice.hpp index c2a4406..600aa47 100644 --- a/include/amuse/Voice.hpp +++ b/include/amuse/Voice.hpp @@ -308,12 +308,6 @@ public: _notifyCtrlChange(ctrl, val); } - /** Get ModWheel value on voice */ - int8_t getModWheel() const - { - return m_state.m_modWheelSel ? m_state.m_modWheelSel.evaluate(*this, m_state) : getCtrlValue(1); - } - /** 'install' external MIDI controller storage */ void installCtrlValues(int8_t* cvs) { @@ -322,7 +316,7 @@ public: } /** Get MIDI pitch wheel value on voice */ - int8_t getPitchWheel() const {return m_curPitchWheel * 127 / 2 + 64;} + float getPitchWheel() const {return m_curPitchWheel;} /** Get MIDI aftertouch value on voice */ int8_t getAftertouch() const {return m_curAftertouch;} diff --git a/lib/Sequencer.cpp b/lib/Sequencer.cpp index 674db8e..b084f1b 100644 --- a/lib/Sequencer.cpp +++ b/lib/Sequencer.cpp @@ -72,15 +72,15 @@ Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId, m_midiSetup = it->second->data(); m_submix = m_engine.addSubmix(smx); - m_submix->makeReverbHi(0.2f, 0.65f, 1.f, 0.5f, 0.f, 0.f); + m_submix->makeReverbHi(0.2f, 0.3f, 1.f, 0.5f, 0.f, 0.f); } Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId, const SFXGroupIndex* sfxGroup, Submix* smx) : Entity(engine, group, groupId), m_sfxGroup(sfxGroup) { - m_submix = m_engine.addSubmix(smx); - m_submix->makeReverbHi(0.2f, 0.65f, 1.f, 0.5f, 0.f, 0.f); + //m_submix = m_engine.addSubmix(smx); + //m_submix->makeReverbHi(0.2f, 0.3f, 1.f, 0.5f, 0.f, 0.f); std::map sortSFX; for (const auto& sfx : sfxGroup->m_sfxEntries) diff --git a/lib/SongState.cpp b/lib/SongState.cpp index a06477d..b9f5284 100644 --- a/lib/SongState.cpp +++ b/lib/SongState.cpp @@ -76,13 +76,9 @@ void SongState::Header::swapBig() m_unkOff = SBig(m_unkOff); } -void SongState::TrackRegion::swapBig() +bool SongState::TrackRegion::indexValid() const { - m_startTick = SBig(m_startTick); - m_unk1 = SBig(m_unk1); - m_unk2 = SBig(m_unk2); - m_regionIndex = SBig(m_regionIndex); - m_initialPitch = SBig(m_initialPitch); + return SBig(m_regionIndex) >= 0; } void SongState::TempoChange::swapBig() @@ -91,20 +87,22 @@ void SongState::TempoChange::swapBig() m_tempo = SBig(m_tempo); } -void SongState::Channel::Header::swapBig() +void SongState::Track::Header::swapBig() { m_type = SBig(m_type); m_pitchOff = SBig(m_pitchOff); m_modOff = SBig(m_modOff); } -SongState::Channel::Channel(SongState& parent, uint8_t midiChan, const TrackRegion* regions) +SongState::Track::Track(SongState& parent, uint8_t midiChan, const TrackRegion* regions) : m_parent(parent), m_midiChan(midiChan), m_curRegion(nullptr), m_nextRegion(regions) -{} - -void SongState::Channel::setRegion(Sequencer& seq, const TrackRegion* region) { - assert(region->m_regionIndex != 0xffff); + for (int i=0 ; i<128 ; ++i) + m_remNoteLengths[i] = INT_MIN; +} + +void SongState::Track::setRegion(Sequencer& seq, const TrackRegion* region) +{ m_curRegion = region; uint32_t regionIdx = SBig(m_curRegion->m_regionIndex); m_nextRegion = &m_curRegion[1]; @@ -113,7 +111,6 @@ void SongState::Channel::setRegion(Sequencer& seq, const TrackRegion* region) Header header = *reinterpret_cast(m_data); header.swapBig(); - assert(header.m_type == 8); m_data += 12; if (header.m_pitchOff) @@ -123,7 +120,6 @@ void SongState::Channel::setRegion(Sequencer& seq, const TrackRegion* region) m_eventWaitCountdown = 0; m_lastPitchTick = m_parent.m_curTick; - //m_lastPitchVal = SBig(m_curRegion->m_initialPitch); m_lastPitchVal = 0; seq.setPitchWheel(m_midiChan, clamp(-1.f, m_lastPitchVal / 32768.f, 1.f)); m_lastModTick = m_parent.m_curTick; @@ -140,7 +136,7 @@ void SongState::Channel::setRegion(Sequencer& seq, const TrackRegion* region) } } -void SongState::Channel::advanceRegion(Sequencer& seq) +void SongState::Track::advanceRegion(Sequencer& seq) { setRegion(seq, m_nextRegion); } @@ -154,16 +150,16 @@ void SongState::initialize(const unsigned char* ptr) m_regionIdx = reinterpret_cast(ptr + m_header.m_regionIdxOff); const uint8_t* chanMap = reinterpret_cast(ptr + m_header.m_chanMapOff); - /* Initialize all channels */ + /* Initialize all tracks */ for (int i=0 ; i<64 ; ++i) { if (trackIdx[i]) { const TrackRegion* region = reinterpret_cast(ptr + SBig(trackIdx[i])); - m_channels[i].emplace(*this, chanMap[i], region); + m_tracks[i].emplace(*this, chanMap[i], region); } else - m_channels[i] = std::experimental::nullopt; + m_tracks[i] = std::experimental::nullopt; } /* Initialize tempo */ @@ -177,12 +173,12 @@ void SongState::initialize(const unsigned char* ptr) m_songState = SongPlayState::Playing; } -bool SongState::Channel::advance(Sequencer& seq, int32_t ticks) +bool SongState::Track::advance(Sequencer& seq, int32_t ticks) { int32_t endTick = m_parent.m_curTick + ticks; /* Advance region if needed */ - while (m_nextRegion->m_regionIndex != 0xffff) + while (m_nextRegion->indexValid()) { uint32_t nextRegTick = SBig(m_nextRegion->m_startTick); if (endTick > nextRegTick) @@ -191,8 +187,22 @@ bool SongState::Channel::advance(Sequencer& seq, int32_t ticks) break; } + /* Stop finished notes */ + for (int i=0 ; i<128 ; ++i) + { + if (m_remNoteLengths[i] != INT_MIN) + { + m_remNoteLengths[i] -= ticks; + if (m_remNoteLengths[i] <= 0) + { + seq.keyOff(m_midiChan, i, 0); + m_remNoteLengths[i] = INT_MIN; + } + } + } + if (!m_data) - return m_nextRegion->m_regionIndex == 0xffff; + return !m_nextRegion->indexValid(); /* Update continuous pitch data */ if (m_pitchWheelData) @@ -260,21 +270,6 @@ bool SongState::Channel::advance(Sequencer& seq, int32_t ticks) } } - /* Stop finished notes */ - for (int i=0 ; i<128 ; ++i) - { - if (m_remNoteLengths[i]) - { - if (m_remNoteLengths[i] <= ticks) - { - seq.keyOff(m_midiChan, i, 0); - m_remNoteLengths[i] = 0; - } - else - m_remNoteLengths[i] -= ticks; - } - } - /* Loop through as many commands as we can for this time period */ if (m_parent.m_header.m_trackIdxOff == 0x18 || m_parent.m_header.m_trackIdxOff == 0x58) { @@ -295,7 +290,7 @@ bool SongState::Channel::advance(Sequencer& seq, int32_t ticks) { /* End of channel */ m_data = nullptr; - return m_nextRegion->m_regionIndex == 0xffff; + return !m_nextRegion->indexValid(); } else if (m_data[0] & 0x80) { @@ -339,7 +334,7 @@ bool SongState::Channel::advance(Sequencer& seq, int32_t ticks) { /* End of channel */ m_data = nullptr; - return m_nextRegion->m_regionIndex == 0xffff; + return !m_nextRegion->indexValid(); } else if (m_data[0] & 0x80) { @@ -365,7 +360,6 @@ bool SongState::Channel::advance(Sequencer& seq, int32_t ticks) /* Set next delta-time */ int32_t absTick = SBig(*reinterpret_cast(m_data)); - assert(absTick >= m_lastN64EventTick); m_eventWaitCountdown += absTick - m_lastN64EventTick; m_lastN64EventTick = absTick; m_data += 4; @@ -412,10 +406,10 @@ bool SongState::advance(Sequencer& seq, double dt) } } - /* Advance all channels */ - for (std::experimental::optional& chan : m_channels) - if (chan) - done &= chan->advance(seq, remTicks); + /* Advance all tracks */ + for (std::experimental::optional& trk : m_tracks) + if (trk) + done &= trk->advance(seq, remTicks); m_curTick += remTicks; diff --git a/lib/SoundMacroState.cpp b/lib/SoundMacroState.cpp index 39720a3..3d4517c 100644 --- a/lib/SoundMacroState.cpp +++ b/lib/SoundMacroState.cpp @@ -52,21 +52,21 @@ float SoundMacroState::Evaluator::evaluate(const Voice& vox, const SoundMacroSta break; case 129: /* Aftertouch */ - thisValue = vox.getAftertouch(); + thisValue = vox.getAftertouch() * (2.f / 127.f); break; case 130: /* LFO1 */ if (vox.m_lfoPeriods[0]) - thisValue = (std::sin(vox.m_voiceTime / vox.m_lfoPeriods[0] * 2.f * M_PIF) / 2.f + 0.5f) * 127.f; + thisValue = std::sin(vox.m_voiceTime / vox.m_lfoPeriods[0] * 2.f * M_PIF); break; case 131: /* LFO2 */ if (vox.m_lfoPeriods[1]) - thisValue = (std::sin(vox.m_voiceTime / vox.m_lfoPeriods[1] * 2.f * M_PIF) / 2.f + 0.5f) * 127.f; + thisValue = std::sin(vox.m_voiceTime / vox.m_lfoPeriods[1] * 2.f * M_PIF); break; case 132: /* Surround panning */ - thisValue = vox.m_curSpan * 64.f + 64.f; + thisValue = vox.m_curSpan; break; case 133: /* Macro-starting key */ @@ -78,10 +78,13 @@ float SoundMacroState::Evaluator::evaluate(const Voice& vox, const SoundMacroSta break; case 135: /* Time since macro-start (ms) */ - thisValue = st.m_execTime * 1000.f; + thisValue = clamp(0.f, float(st.m_execTime * 1000.f), 16383.f); break; default: - thisValue = vox.getCtrlValue(comp.m_midiCtrl); + if (comp.m_midiCtrl == 10) /* Centered pan computation */ + thisValue = vox.getCtrlValue(comp.m_midiCtrl) * (2.f / 127.f) - 1.f; + else + thisValue = vox.getCtrlValue(comp.m_midiCtrl) * (2.f / 127.f); break; } } diff --git a/lib/Voice.cpp b/lib/Voice.cpp index 01accf7..491806f 100644 --- a/lib/Voice.cpp +++ b/lib/Voice.cpp @@ -253,12 +253,12 @@ bool Voice::_advanceSample(int16_t& samp, int32_t& newPitch) } /* Dynamically evaluate per-sample SoundMacro parameters */ - float evalVol = m_state.m_volumeSel ? ((m_state.m_volumeSel.evaluate(*this, m_state) / 127.f) * m_curVol) : m_curVol; + float evalVol = m_state.m_volumeSel ? (m_state.m_volumeSel.evaluate(*this, m_state) / 2.f * m_curVol) : m_curVol; bool panDirty = false; if (m_state.m_panSel) { - float evalPan = (m_state.m_panSel.evaluate(*this, m_state) - 64.f) / 64.f; + float evalPan = m_state.m_panSel.evaluate(*this, m_state); if (evalPan != m_curPan) { m_curPan = evalPan; @@ -267,7 +267,7 @@ bool Voice::_advanceSample(int16_t& samp, int32_t& newPitch) } if (m_state.m_spanSel) { - float evalSpan = (m_state.m_spanSel.evaluate(*this, m_state) - 64.f) / 64.f; + float evalSpan = m_state.m_spanSel.evaluate(*this, m_state); if (evalSpan != m_curSpan) { m_curSpan = evalSpan; @@ -276,7 +276,7 @@ bool Voice::_advanceSample(int16_t& samp, int32_t& newPitch) } if (m_state.m_reverbSel) { - float evalRev = m_state.m_reverbSel.evaluate(*this, m_state) / 127.f; + float evalRev = m_state.m_reverbSel.evaluate(*this, m_state) / 2.f; if (evalRev != m_curReverbVol) { m_curReverbVol = evalRev; @@ -287,7 +287,7 @@ bool Voice::_advanceSample(int16_t& samp, int32_t& newPitch) _setPan(m_curPan); if (m_state.m_pitchWheelSel) - _setPitchWheel((m_state.m_pitchWheelSel.evaluate(*this, m_state) - 64.f) / 64.f); + _setPitchWheel(m_state.m_pitchWheelSel.evaluate(*this, m_state)); /* Process user volume slew */ if (m_engine.m_ampMode == AmplitudeMode::PerSample) @@ -326,11 +326,11 @@ bool Voice::_advanceSample(int16_t& samp, int32_t& newPitch) /* Apply tremolo */ if (m_state.m_tremoloSel && (m_tremoloScale || m_tremoloModScale)) { - float t = m_state.m_tremoloSel.evaluate(*this, m_state); + float t = m_state.m_tremoloSel.evaluate(*this, m_state) / 2.f; if (m_tremoloScale && m_tremoloModScale) { float fac = (1.0f - t) + (m_tremoloScale * t); - float modT = getModWheel() / 127.f; + float modT = m_state.m_modWheelSel ? (m_state.m_modWheelSel.evaluate(*this, m_state) / 2.f) : (getCtrlValue(1) / 127.f); float modFac = (1.0f - modT) + (m_tremoloModScale * modT); m_nextLevel *= fac * modFac; } @@ -341,7 +341,7 @@ bool Voice::_advanceSample(int16_t& samp, int32_t& newPitch) } else if (m_tremoloModScale) { - float modT = getModWheel() / 127.f; + float modT = m_state.m_modWheelSel ? (m_state.m_modWheelSel.evaluate(*this, m_state) / 2.f) : (getCtrlValue(1) / 127.f); float modFac = (1.0f - modT) + (m_tremoloModScale * modT); m_nextLevel *= modFac; } @@ -451,7 +451,7 @@ size_t Voice::supplyAudio(size_t samples, int16_t* data) /* Process per-block evaluators here */ if (m_state.m_pedalSel) { - bool pedal = m_state.m_pedalSel.evaluate(*this, m_state) >= 64; + bool pedal = m_state.m_pedalSel.evaluate(*this, m_state) >= 1.f; if (pedal != m_sustained) setPedal(pedal); } @@ -1110,7 +1110,7 @@ bool Voice::doPortamento(uint8_t newNote) pState = true; break; case 2: - pState = (m_state.m_portamentoSel ? m_state.m_portamentoSel.evaluate(*this, m_state) : getCtrlValue(65)) >= 64; + pState = m_state.m_portamentoSel ? (m_state.m_portamentoSel.evaluate(*this, m_state) >= 1.f) : (getCtrlValue(65) >= 64); break; }