mirror of https://github.com/AxioDL/amuse.git
Bug fixes in sequencer and SoundMacro event trapping
This commit is contained in:
parent
2c3c9d3885
commit
44bb7a155b
|
@ -195,8 +195,8 @@ struct AppCallback : boo::IApplicationCallback
|
||||||
if (m_seq)
|
if (m_seq)
|
||||||
voxCount = m_seq->getVoiceCount();
|
voxCount = m_seq->getVoiceCount();
|
||||||
printf("\r "
|
printf("\r "
|
||||||
"\r %" PRISize " Setup %d, Chan %d, VOL: %d%%\r", voxCount,
|
"\r %" PRISize " Setup %d, Chan %d, Octave: %d, Vel: %d, VOL: %d%%\r", voxCount,
|
||||||
m_setupId, m_chanId, int(std::rint(m_volume * 100)));
|
m_setupId, m_chanId, m_octave, m_velocity, int(std::rint(m_volume * 100)));
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,6 +353,32 @@ struct AppCallback : boo::IApplicationCallback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void charKeyDownRepeat(unsigned long charCode)
|
||||||
|
{
|
||||||
|
if (m_seq && m_chanId != -1)
|
||||||
|
{
|
||||||
|
switch (charCode)
|
||||||
|
{
|
||||||
|
case 'z':
|
||||||
|
m_octave = amuse::clamp(-1, m_octave - 1, 8);
|
||||||
|
m_updateDisp = true;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
m_octave = amuse::clamp(-1, m_octave + 1, 8);
|
||||||
|
m_updateDisp = true;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
m_velocity = amuse::clamp(0, m_velocity - 1, 127);
|
||||||
|
m_updateDisp = true;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
m_velocity = amuse::clamp(0, m_velocity + 1, 127);
|
||||||
|
m_updateDisp = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void charKeyDown(unsigned long charCode)
|
void charKeyDown(unsigned long charCode)
|
||||||
{
|
{
|
||||||
charCode = tolower(charCode);
|
charCode = tolower(charCode);
|
||||||
|
@ -381,15 +407,19 @@ struct AppCallback : boo::IApplicationCallback
|
||||||
{
|
{
|
||||||
case 'z':
|
case 'z':
|
||||||
m_octave = amuse::clamp(-1, m_octave - 1, 8);
|
m_octave = amuse::clamp(-1, m_octave - 1, 8);
|
||||||
|
m_updateDisp = true;
|
||||||
break;
|
break;
|
||||||
case 'x':
|
case 'x':
|
||||||
m_octave = amuse::clamp(-1, m_octave + 1, 8);
|
m_octave = amuse::clamp(-1, m_octave + 1, 8);
|
||||||
|
m_updateDisp = true;
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
m_velocity = amuse::clamp(0, m_velocity - 1, 127);
|
m_velocity = amuse::clamp(0, m_velocity - 1, 127);
|
||||||
|
m_updateDisp = true;
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
m_velocity = amuse::clamp(0, m_velocity + 1, 127);
|
m_velocity = amuse::clamp(0, m_velocity + 1, 127);
|
||||||
|
m_updateDisp = true;
|
||||||
break;
|
break;
|
||||||
case '\t':
|
case '\t':
|
||||||
m_seq->setCtrlValue(m_chanId, 64, 127);
|
m_seq->setCtrlValue(m_chanId, 64, 127);
|
||||||
|
@ -637,8 +667,9 @@ struct AppCallback : boo::IApplicationCallback
|
||||||
void EventCallback::charKeyDown(unsigned long charCode, boo::EModifierKey mods, bool isRepeat)
|
void EventCallback::charKeyDown(unsigned long charCode, boo::EModifierKey mods, bool isRepeat)
|
||||||
{
|
{
|
||||||
if (isRepeat)
|
if (isRepeat)
|
||||||
return;
|
m_app.charKeyDownRepeat(charCode);
|
||||||
m_app.charKeyDown(charCode);
|
else
|
||||||
|
m_app.charKeyDown(charCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventCallback::charKeyUp(unsigned long charCode, boo::EModifierKey mods)
|
void EventCallback::charKeyUp(unsigned long charCode, boo::EModifierKey mods)
|
||||||
|
@ -661,6 +692,8 @@ void EventCallback::specialKeyDown(boo::ESpecialKey key, boo::EModifierKey mods,
|
||||||
m_app.m_volume = amuse::clamp(0.f, m_app.m_volume + 0.05f, 1.f);
|
m_app.m_volume = amuse::clamp(0.f, m_app.m_volume + 0.05f, 1.f);
|
||||||
if (m_app.m_vox)
|
if (m_app.m_vox)
|
||||||
m_app.m_vox->setVolume(m_app.m_volume);
|
m_app.m_vox->setVolume(m_app.m_volume);
|
||||||
|
if (m_app.m_seq)
|
||||||
|
m_app.m_seq->setVolume(m_app.m_volume);
|
||||||
m_app.m_updateDisp = true;
|
m_app.m_updateDisp = true;
|
||||||
break;
|
break;
|
||||||
case boo::ESpecialKey::Down:
|
case boo::ESpecialKey::Down:
|
||||||
|
@ -668,6 +701,8 @@ void EventCallback::specialKeyDown(boo::ESpecialKey key, boo::EModifierKey mods,
|
||||||
m_app.m_volume = amuse::clamp(0.f, m_app.m_volume - 0.05f, 1.f);
|
m_app.m_volume = amuse::clamp(0.f, m_app.m_volume - 0.05f, 1.f);
|
||||||
if (m_app.m_vox)
|
if (m_app.m_vox)
|
||||||
m_app.m_vox->setVolume(m_app.m_volume);
|
m_app.m_vox->setVolume(m_app.m_volume);
|
||||||
|
if (m_app.m_seq)
|
||||||
|
m_app.m_seq->setVolume(m_app.m_volume);
|
||||||
m_app.m_updateDisp = true;
|
m_app.m_updateDisp = true;
|
||||||
break;
|
break;
|
||||||
default: break;
|
default: break;
|
||||||
|
|
|
@ -23,7 +23,7 @@ private:
|
||||||
const ADSR* m_curADSR = nullptr; /**< Current timing envelope */
|
const ADSR* m_curADSR = nullptr; /**< Current timing envelope */
|
||||||
double m_sustainFactor; /**< Evaluated sustain percentage as a double */
|
double m_sustainFactor; /**< Evaluated sustain percentage as a double */
|
||||||
double m_releaseStartFactor; /**< Level at whenever release event occurs */
|
double m_releaseStartFactor; /**< Level at whenever release event occurs */
|
||||||
unsigned m_curMs; /**< Current time of envelope stage */
|
double m_curMs; /**< Current time of envelope stage */
|
||||||
public:
|
public:
|
||||||
void reset(const ADSR* adsr);
|
void reset(const ADSR* adsr);
|
||||||
void keyOff();
|
void keyOff();
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "Entity.hpp"
|
#include "Entity.hpp"
|
||||||
#include "AudioGroupProject.hpp"
|
#include "AudioGroupProject.hpp"
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
|
@ -33,6 +34,8 @@ class Sequencer : public Entity
|
||||||
SequencerState m_state = SequencerState::Interactive; /**< Current high-level state of sequencer */
|
SequencerState m_state = SequencerState::Interactive; /**< Current high-level state of sequencer */
|
||||||
bool m_dieOnEnd = false; /**< Sequencer will be killed when current arrangement completes */
|
bool m_dieOnEnd = false; /**< Sequencer will be killed when current arrangement completes */
|
||||||
|
|
||||||
|
float m_curVol = 1.f; /**< Current volume of sequencer */
|
||||||
|
|
||||||
/** State of a single MIDI channel */
|
/** State of a single MIDI channel */
|
||||||
struct ChannelState
|
struct ChannelState
|
||||||
{
|
{
|
||||||
|
@ -45,13 +48,16 @@ class Sequencer : public Entity
|
||||||
|
|
||||||
/** Voices corresponding to currently-pressed keys in channel */
|
/** Voices corresponding to currently-pressed keys in channel */
|
||||||
std::unordered_map<uint8_t, std::shared_ptr<Voice>> m_chanVoxs;
|
std::unordered_map<uint8_t, std::shared_ptr<Voice>> m_chanVoxs;
|
||||||
|
std::unordered_set<std::shared_ptr<Voice>> m_keyoffVoxs;
|
||||||
int8_t m_ctrlVals[128]; /**< MIDI controller values */
|
int8_t m_ctrlVals[128]; /**< MIDI controller values */
|
||||||
|
|
||||||
void _bringOutYourDead();
|
void _bringOutYourDead();
|
||||||
|
size_t getVoiceCount() const;
|
||||||
std::shared_ptr<Voice> keyOn(uint8_t note, uint8_t velocity);
|
std::shared_ptr<Voice> keyOn(uint8_t note, uint8_t velocity);
|
||||||
void keyOff(uint8_t note, uint8_t velocity);
|
void keyOff(uint8_t note, uint8_t velocity);
|
||||||
void setCtrlValue(uint8_t ctrl, int8_t val);
|
void setCtrlValue(uint8_t ctrl, int8_t val);
|
||||||
void setPitchWheel(float pitchWheel);
|
void setPitchWheel(float pitchWheel);
|
||||||
|
void setVolume(float vol);
|
||||||
void allOff();
|
void allOff();
|
||||||
void killKeygroup(uint8_t kg, bool now);
|
void killKeygroup(uint8_t kg, bool now);
|
||||||
std::shared_ptr<Voice> findVoice(int vid);
|
std::shared_ptr<Voice> findVoice(int vid);
|
||||||
|
@ -105,6 +111,9 @@ public:
|
||||||
/** Play MIDI arrangement */
|
/** Play MIDI arrangement */
|
||||||
void playSong(const unsigned char* arrData, bool dieOnEnd=true);
|
void playSong(const unsigned char* arrData, bool dieOnEnd=true);
|
||||||
|
|
||||||
|
/** Set total volume of sequencer */
|
||||||
|
void setVolume(float vol);
|
||||||
|
|
||||||
/** Manually kill sequencer for deferred release from engine */
|
/** Manually kill sequencer for deferred release from engine */
|
||||||
void kill() {m_state = SequencerState::Dead;}
|
void kill() {m_state = SequencerState::Dead;}
|
||||||
};
|
};
|
||||||
|
|
|
@ -123,7 +123,7 @@ class SoundMacroState
|
||||||
uint8_t m_initKey; /**< Key played for this macro invocation */
|
uint8_t m_initKey; /**< Key played for this macro invocation */
|
||||||
uint8_t m_curVel; /**< Current velocity played for this macro invocation */
|
uint8_t m_curVel; /**< Current velocity played for this macro invocation */
|
||||||
uint8_t m_curMod; /**< Current modulation played for this macro invocation */
|
uint8_t m_curMod; /**< Current modulation played for this macro invocation */
|
||||||
uint32_t m_curKey; /**< Current key played for this macro invocation (in cents) */
|
uint32_t m_curPitch; /**< Current key played for this macro invocation (in cents) */
|
||||||
|
|
||||||
double m_execTime; /**< time in seconds of SoundMacro execution (per-update resolution) */
|
double m_execTime; /**< time in seconds of SoundMacro execution (per-update resolution) */
|
||||||
bool m_keyoff; /**< keyoff message has been received */
|
bool m_keyoff; /**< keyoff message has been received */
|
||||||
|
@ -205,18 +205,12 @@ class SoundMacroState
|
||||||
|
|
||||||
int32_t m_variables[256]; /**< 32-bit variables set with relevant commands */
|
int32_t m_variables[256]; /**< 32-bit variables set with relevant commands */
|
||||||
|
|
||||||
/** Messages pending processing for this SoundMacro voice */
|
|
||||||
std::list<int32_t> m_messageQueue;
|
|
||||||
|
|
||||||
/** Event registration data for TRAP_EVENT */
|
/** Event registration data for TRAP_EVENT */
|
||||||
struct EventTrap
|
struct EventTrap
|
||||||
{
|
{
|
||||||
ObjectId macroId = 0xffff;
|
ObjectId macroId = 0xffff;
|
||||||
uint16_t macroStep;
|
uint16_t macroStep;
|
||||||
};
|
};
|
||||||
EventTrap m_keyoffTrap;
|
|
||||||
EventTrap m_sampleEndTrap;
|
|
||||||
EventTrap m_messageTrap;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** initialize state for SoundMacro data at `ptr` */
|
/** initialize state for SoundMacro data at `ptr` */
|
||||||
|
@ -234,9 +228,6 @@ public:
|
||||||
|
|
||||||
/** sample end event */
|
/** sample end event */
|
||||||
void sampleEndNotify(Voice& vox);
|
void sampleEndNotify(Voice& vox);
|
||||||
|
|
||||||
/** SEND_MESSAGE receive event */
|
|
||||||
void messageNotify(Voice& vox, int32_t val);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,10 @@ class Voice : public Entity
|
||||||
|
|
||||||
std::unique_ptr<IBackendVoice> m_backendVoice; /**< Handle to client-implemented backend voice */
|
std::unique_ptr<IBackendVoice> m_backendVoice; /**< Handle to client-implemented backend voice */
|
||||||
SoundMacroState m_state; /**< State container for SoundMacro playback */
|
SoundMacroState m_state; /**< State container for SoundMacro playback */
|
||||||
|
SoundMacroState::EventTrap m_keyoffTrap; /**< Trap for keyoff (SoundMacro overrides default envelope behavior) */
|
||||||
|
SoundMacroState::EventTrap m_sampleEndTrap; /**< Trap for sampleend (SoundMacro overrides voice removal) */
|
||||||
|
SoundMacroState::EventTrap m_messageTrap; /**< Trap for messages sent from other SoundMacros */
|
||||||
|
std::list<int32_t> m_messageQueue; /**< Messages pending processing for SoundMacros in this voice */
|
||||||
std::list<std::shared_ptr<Voice>> m_childVoices; /**< Child voices for PLAYMACRO usage */
|
std::list<std::shared_ptr<Voice>> m_childVoices; /**< Child voices for PLAYMACRO usage */
|
||||||
uint8_t m_keygroup = 0; /**< Keygroup voice is a member of */
|
uint8_t m_keygroup = 0; /**< Keygroup voice is a member of */
|
||||||
|
|
||||||
|
@ -118,6 +122,8 @@ class Voice : public Entity
|
||||||
void _reset();
|
void _reset();
|
||||||
bool _checkSamplePos();
|
bool _checkSamplePos();
|
||||||
void _doKeyOff();
|
void _doKeyOff();
|
||||||
|
void _macroKeyOff();
|
||||||
|
void _macroSampleEnd();
|
||||||
bool _advanceSample(int16_t& samp);
|
bool _advanceSample(int16_t& samp);
|
||||||
void _setTotalPitch(int32_t cents);
|
void _setTotalPitch(int32_t cents);
|
||||||
bool _isRecursivelyDead();
|
bool _isRecursivelyDead();
|
||||||
|
|
|
@ -7,15 +7,18 @@ void Envelope::reset(const ADSR* adsr)
|
||||||
{
|
{
|
||||||
m_phase = State::Attack;
|
m_phase = State::Attack;
|
||||||
m_curADSR = adsr;
|
m_curADSR = adsr;
|
||||||
m_curMs = 0;
|
m_curMs = 0.0;
|
||||||
m_sustainFactor = (adsr->sustainCoarse * 6.25 + adsr->sustainFine * 0.0244) / 100.0;
|
if (m_curADSR->decayCoarse == 128)
|
||||||
|
m_sustainFactor = 1.f;
|
||||||
|
else
|
||||||
|
m_sustainFactor = (adsr->sustainCoarse * 6.25 + adsr->sustainFine * 0.0244) / 100.0;
|
||||||
m_releaseStartFactor = 0.0;
|
m_releaseStartFactor = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Envelope::keyOff()
|
void Envelope::keyOff()
|
||||||
{
|
{
|
||||||
m_phase = State::Release;
|
m_phase = State::Release;
|
||||||
m_curMs = 0;
|
m_curMs = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Envelope::nextSample(double sampleRate)
|
float Envelope::nextSample(double sampleRate)
|
||||||
|
@ -36,15 +39,23 @@ float Envelope::nextSample(double sampleRate)
|
||||||
uint16_t attack = m_curADSR->attackCoarse * 255 + m_curADSR->attackFine;
|
uint16_t attack = m_curADSR->attackCoarse * 255 + m_curADSR->attackFine;
|
||||||
if (attack == 0)
|
if (attack == 0)
|
||||||
{
|
{
|
||||||
m_phase = State::Decay;
|
if (m_curADSR->decayCoarse == 128)
|
||||||
m_curMs = 0;
|
m_phase = State::Sustain;
|
||||||
|
else
|
||||||
|
m_phase = State::Decay;
|
||||||
|
m_curMs = 0.0;
|
||||||
|
m_releaseStartFactor = 1.f;
|
||||||
return 1.f;
|
return 1.f;
|
||||||
}
|
}
|
||||||
double attackFac = m_curMs / double(attack);
|
double attackFac = m_curMs / double(attack);
|
||||||
if (attackFac >= 1.0)
|
if (attackFac >= 1.0)
|
||||||
{
|
{
|
||||||
m_phase = State::Decay;
|
if (m_curADSR->decayCoarse == 128)
|
||||||
m_curMs = 0;
|
m_phase = State::Sustain;
|
||||||
|
else
|
||||||
|
m_phase = State::Decay;
|
||||||
|
m_curMs = 0.0;
|
||||||
|
m_releaseStartFactor = 1.f;
|
||||||
return 1.f;
|
return 1.f;
|
||||||
}
|
}
|
||||||
m_releaseStartFactor = attackFac;
|
m_releaseStartFactor = attackFac;
|
||||||
|
@ -56,7 +67,7 @@ float Envelope::nextSample(double sampleRate)
|
||||||
if (decay == 0)
|
if (decay == 0)
|
||||||
{
|
{
|
||||||
m_phase = State::Sustain;
|
m_phase = State::Sustain;
|
||||||
m_curMs = 0;
|
m_curMs = 0.0;
|
||||||
m_releaseStartFactor = m_sustainFactor;
|
m_releaseStartFactor = m_sustainFactor;
|
||||||
return m_sustainFactor;
|
return m_sustainFactor;
|
||||||
}
|
}
|
||||||
|
@ -64,7 +75,7 @@ float Envelope::nextSample(double sampleRate)
|
||||||
if (decayFac >= 1.0)
|
if (decayFac >= 1.0)
|
||||||
{
|
{
|
||||||
m_phase = State::Sustain;
|
m_phase = State::Sustain;
|
||||||
m_curMs = 0;
|
m_curMs = 0.0;
|
||||||
m_releaseStartFactor = m_sustainFactor;
|
m_releaseStartFactor = m_sustainFactor;
|
||||||
return m_sustainFactor;
|
return m_sustainFactor;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,18 @@ void Sequencer::ChannelState::_bringOutYourDead()
|
||||||
}
|
}
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto it = m_keyoffVoxs.begin() ; it != m_keyoffVoxs.end() ;)
|
||||||
|
{
|
||||||
|
Voice* vox = it->get();
|
||||||
|
vox->_bringOutYourDead();
|
||||||
|
if (vox->_isRecursivelyDead())
|
||||||
|
{
|
||||||
|
it = m_keyoffVoxs.erase(it);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequencer::_bringOutYourDead()
|
void Sequencer::_bringOutYourDead()
|
||||||
|
@ -35,10 +47,6 @@ void Sequencer::_destroy()
|
||||||
Entity::_destroy();
|
Entity::_destroy();
|
||||||
if (m_submix)
|
if (m_submix)
|
||||||
m_submix->m_activeSequencers.erase(this);
|
m_submix->m_activeSequencers.erase(this);
|
||||||
|
|
||||||
for (const auto& chan : m_chanStates)
|
|
||||||
for (const auto& vox : chan.second->m_chanVoxs)
|
|
||||||
vox.second->_destroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Sequencer::~Sequencer() {}
|
Sequencer::~Sequencer() {}
|
||||||
|
@ -83,12 +91,21 @@ Sequencer::ChannelState::ChannelState(Sequencer& parent, uint8_t chanId)
|
||||||
m_submix->makeChorus(15, m_setup.chorus * 5 / 127, 5000);
|
m_submix->makeChorus(15, m_setup.chorus * 5 / 127, 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t Sequencer::ChannelState::getVoiceCount() const
|
||||||
|
{
|
||||||
|
size_t ret = 0;
|
||||||
|
for (const auto& vox : m_chanVoxs)
|
||||||
|
ret += vox.second->getTotalVoices();
|
||||||
|
for (const auto& vox : m_keyoffVoxs)
|
||||||
|
ret += vox->getTotalVoices();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
size_t Sequencer::getVoiceCount() const
|
size_t Sequencer::getVoiceCount() const
|
||||||
{
|
{
|
||||||
size_t ret = 0;
|
size_t ret = 0;
|
||||||
for (const auto& chan : m_chanStates)
|
for (const auto& chan : m_chanStates)
|
||||||
for (const auto& vox : chan.second->m_chanVoxs)
|
ret += chan.second->getVoiceCount();
|
||||||
ret += vox.second->getTotalVoices();
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +124,7 @@ std::shared_ptr<Voice> Sequencer::ChannelState::keyOn(uint8_t note, uint8_t velo
|
||||||
m_parent.m_engine._destroyVoice(ret.get());
|
m_parent.m_engine._destroyVoice(ret.get());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
ret->setVolume(m_setup.volume / 127.f);
|
ret->setVolume(m_parent.m_curVol * m_setup.volume / 127.f);
|
||||||
ret->setPan(m_setup.panning / 64.f - 127.f);
|
ret->setPan(m_setup.panning / 64.f - 127.f);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -131,6 +148,7 @@ void Sequencer::ChannelState::keyOff(uint8_t note, uint8_t velocity)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
keySearch->second->keyOff();
|
keySearch->second->keyOff();
|
||||||
|
m_keyoffVoxs.emplace(std::move(keySearch->second));
|
||||||
m_chanVoxs.erase(keySearch);
|
m_chanVoxs.erase(keySearch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,6 +179,8 @@ void Sequencer::ChannelState::setPitchWheel(float pitchWheel)
|
||||||
{
|
{
|
||||||
for (const auto& vox : m_chanVoxs)
|
for (const auto& vox : m_chanVoxs)
|
||||||
vox.second->setPitchWheel(pitchWheel);
|
vox.second->setPitchWheel(pitchWheel);
|
||||||
|
for (const auto& vox : m_keyoffVoxs)
|
||||||
|
vox->setPitchWheel(pitchWheel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequencer::setPitchWheel(uint8_t chan, float pitchWheel)
|
void Sequencer::setPitchWheel(uint8_t chan, float pitchWheel)
|
||||||
|
@ -209,6 +229,20 @@ void Sequencer::ChannelState::killKeygroup(uint8_t kg, bool now)
|
||||||
}
|
}
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (now)
|
||||||
|
{
|
||||||
|
for (auto it = m_keyoffVoxs.begin() ; it != m_keyoffVoxs.end() ;)
|
||||||
|
{
|
||||||
|
Voice* vox = it->get();
|
||||||
|
if (vox->m_keygroup == kg)
|
||||||
|
{
|
||||||
|
it = m_keyoffVoxs.erase(it);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequencer::killKeygroup(uint8_t kg, bool now)
|
void Sequencer::killKeygroup(uint8_t kg, bool now)
|
||||||
|
@ -222,6 +256,9 @@ std::shared_ptr<Voice> Sequencer::ChannelState::findVoice(int vid)
|
||||||
for (const auto& vox : m_chanVoxs)
|
for (const auto& vox : m_chanVoxs)
|
||||||
if (vox.second->vid() == vid)
|
if (vox.second->vid() == vid)
|
||||||
return vox.second;
|
return vox.second;
|
||||||
|
for (const auto& vox : m_keyoffVoxs)
|
||||||
|
if (vox->vid() == vid)
|
||||||
|
return vox;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,6 +281,12 @@ void Sequencer::ChannelState::sendMacroMessage(ObjectId macroId, int32_t val)
|
||||||
if (vox->getObjectId() == macroId)
|
if (vox->getObjectId() == macroId)
|
||||||
vox->message(val);
|
vox->message(val);
|
||||||
}
|
}
|
||||||
|
for (const auto& v : m_keyoffVoxs)
|
||||||
|
{
|
||||||
|
Voice* vox = v.get();
|
||||||
|
if (vox->getObjectId() == macroId)
|
||||||
|
vox->message(val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequencer::sendMacroMessage(ObjectId macroId, int32_t val)
|
void Sequencer::sendMacroMessage(ObjectId macroId, int32_t val)
|
||||||
|
@ -259,4 +302,26 @@ void Sequencer::playSong(const unsigned char* arrData, bool dieOnEnd)
|
||||||
m_state = SequencerState::Playing;
|
m_state = SequencerState::Playing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Sequencer::ChannelState::setVolume(float vol)
|
||||||
|
{
|
||||||
|
vol = vol * m_setup.volume / 127.f;
|
||||||
|
for (const auto& v : m_chanVoxs)
|
||||||
|
{
|
||||||
|
Voice* vox = v.second.get();
|
||||||
|
vox->setVolume(vol);
|
||||||
|
}
|
||||||
|
for (const auto& v : m_keyoffVoxs)
|
||||||
|
{
|
||||||
|
Voice* vox = v.get();
|
||||||
|
vox->setVolume(vol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sequencer::setVolume(float vol)
|
||||||
|
{
|
||||||
|
m_curVol = vol;
|
||||||
|
for (auto& chan : m_chanStates)
|
||||||
|
chan.second->setVolume(vol);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,11 +123,12 @@ void SoundMacroState::initialize(const unsigned char* ptr, int step, double tick
|
||||||
m_initKey = midiKey;
|
m_initKey = midiKey;
|
||||||
m_initVel = midiVel;
|
m_initVel = midiVel;
|
||||||
m_initMod = midiMod;
|
m_initMod = midiMod;
|
||||||
m_curVel = 0;
|
m_curVel = midiVel;
|
||||||
m_curMod = 0;
|
m_curMod = midiMod;
|
||||||
m_curKey = 0;
|
m_curPitch = midiKey * 100;
|
||||||
m_pc.clear();
|
m_pc.clear();
|
||||||
m_pc.push_back({ptr, step});
|
m_pc.push_back({ptr, step});
|
||||||
|
m_inWait = false;
|
||||||
m_execTime = 0.f;
|
m_execTime = 0.f;
|
||||||
m_keyoff = false;
|
m_keyoff = false;
|
||||||
m_sampleEnd = false;
|
m_sampleEnd = false;
|
||||||
|
@ -135,9 +136,6 @@ void SoundMacroState::initialize(const unsigned char* ptr, int step, double tick
|
||||||
m_lastPlayMacroVid = -1;
|
m_lastPlayMacroVid = -1;
|
||||||
m_useAdsrControllers = false;
|
m_useAdsrControllers = false;
|
||||||
m_portamentoMode = 0;
|
m_portamentoMode = 0;
|
||||||
m_keyoffTrap.macroId = 0xffff;
|
|
||||||
m_sampleEndTrap.macroId = 0xffff;
|
|
||||||
m_messageTrap.macroId = 0xffff;
|
|
||||||
m_header = *reinterpret_cast<const Header*>(ptr);
|
m_header = *reinterpret_cast<const Header*>(ptr);
|
||||||
m_header.swapBig();
|
m_header.swapBig();
|
||||||
}
|
}
|
||||||
|
@ -154,7 +152,11 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
||||||
/* Advance wait timer if active, returning if waiting */
|
/* Advance wait timer if active, returning if waiting */
|
||||||
if (m_inWait)
|
if (m_inWait)
|
||||||
{
|
{
|
||||||
if (!m_indefiniteWait)
|
if (m_keyoffWait && m_keyoff)
|
||||||
|
m_inWait = false;
|
||||||
|
else if (m_sampleEndWait && m_sampleEnd)
|
||||||
|
m_inWait = false;
|
||||||
|
else if (!m_indefiniteWait)
|
||||||
{
|
{
|
||||||
m_waitCountdown -= dt;
|
m_waitCountdown -= dt;
|
||||||
if (m_waitCountdown < 0.f)
|
if (m_waitCountdown < 0.f)
|
||||||
|
@ -178,7 +180,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
||||||
{
|
{
|
||||||
case Op::End:
|
case Op::End:
|
||||||
case Op::Stop:
|
case Op::Stop:
|
||||||
m_pc.clear();
|
m_pc.back().second = -1;
|
||||||
return true;
|
return true;
|
||||||
case Op::SplitKey:
|
case Op::SplitKey:
|
||||||
{
|
{
|
||||||
|
@ -193,7 +195,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
||||||
m_pc.back().second = macroStep;
|
m_pc.back().second = macroStep;
|
||||||
else
|
else
|
||||||
vox.loadSoundObject(macroId, macroStep, m_ticksPerSec,
|
vox.loadSoundObject(macroId, macroStep, m_ticksPerSec,
|
||||||
m_initKey, m_initVel, m_initMod);
|
m_initKey, m_initVel, m_initMod);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -480,6 +482,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
||||||
}
|
}
|
||||||
|
|
||||||
vox.startSample(smpId, offset);
|
vox.startSample(smpId, offset);
|
||||||
|
vox.setPitchKey(m_curPitch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Op::StopSample:
|
case Op::StopSample:
|
||||||
|
@ -489,7 +492,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
||||||
}
|
}
|
||||||
case Op::KeyOff:
|
case Op::KeyOff:
|
||||||
{
|
{
|
||||||
vox.keyOff();
|
vox._macroKeyOff();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Op::SplitRnd:
|
case Op::SplitRnd:
|
||||||
|
@ -568,11 +571,11 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
||||||
noteLo *= 100;
|
noteLo *= 100;
|
||||||
noteHi *= 100;
|
noteHi *= 100;
|
||||||
|
|
||||||
m_curKey = vox.getEngine().nextRandom() % ((noteHi - noteLo) + noteLo);
|
m_curPitch = vox.getEngine().nextRandom() % ((noteHi - noteLo) + noteLo);
|
||||||
if (!free)
|
if (!free)
|
||||||
m_curKey = m_curKey / 100 * 100 + detune;
|
m_curPitch = m_curPitch / 100 * 100 + detune;
|
||||||
|
|
||||||
vox.setPitchKey(m_curKey);
|
vox.setPitchKey(m_curPitch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Op::AddNote:
|
case Op::AddNote:
|
||||||
|
@ -583,7 +586,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
||||||
int8_t ms = cmd.m_data[4];
|
int8_t ms = cmd.m_data[4];
|
||||||
int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
|
int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
|
||||||
|
|
||||||
m_curKey = (orgKey ? m_initKey : m_curKey) + add * 100 + detune;
|
m_curPitch = (orgKey ? (m_initKey * 100) : m_curPitch) + add * 100 + detune;
|
||||||
|
|
||||||
/* Set wait state */
|
/* Set wait state */
|
||||||
if (timeMs)
|
if (timeMs)
|
||||||
|
@ -594,7 +597,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
||||||
m_inWait = true;
|
m_inWait = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
vox.setPitchKey(m_curKey);
|
vox.setPitchKey(m_curPitch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Op::SetNote:
|
case Op::SetNote:
|
||||||
|
@ -604,7 +607,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
||||||
int8_t ms = cmd.m_data[4];
|
int8_t ms = cmd.m_data[4];
|
||||||
int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
|
int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
|
||||||
|
|
||||||
m_curKey = key * 100 + detune;
|
m_curPitch = key * 100 + detune;
|
||||||
|
|
||||||
/* Set wait state */
|
/* Set wait state */
|
||||||
if (timeMs)
|
if (timeMs)
|
||||||
|
@ -615,7 +618,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
||||||
m_inWait = true;
|
m_inWait = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
vox.setPitchKey(m_curKey);
|
vox.setPitchKey(m_curPitch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Op::LastNote:
|
case Op::LastNote:
|
||||||
|
@ -625,7 +628,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
||||||
int8_t ms = cmd.m_data[4];
|
int8_t ms = cmd.m_data[4];
|
||||||
int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
|
int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
|
||||||
|
|
||||||
m_curKey = (add + vox.getLastNote()) * 100 + detune;
|
m_curPitch = (add + vox.getLastNote()) * 100 + detune;
|
||||||
|
|
||||||
/* Set wait state */
|
/* Set wait state */
|
||||||
if (timeMs)
|
if (timeMs)
|
||||||
|
@ -636,7 +639,7 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
||||||
m_inWait = true;
|
m_inWait = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
vox.setPitchKey(m_curKey);
|
vox.setPitchKey(m_curPitch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Op::Portamento:
|
case Op::Portamento:
|
||||||
|
@ -774,16 +777,16 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
||||||
switch (event)
|
switch (event)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
m_keyoffTrap.macroId = macroId;
|
vox.m_keyoffTrap.macroId = macroId;
|
||||||
m_keyoffTrap.macroStep = macroStep;
|
vox.m_keyoffTrap.macroStep = macroStep;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
m_sampleEndTrap.macroId = macroId;
|
vox.m_sampleEndTrap.macroId = macroId;
|
||||||
m_sampleEndTrap.macroStep = macroStep;
|
vox.m_sampleEndTrap.macroStep = macroStep;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
m_messageTrap.macroId = macroId;
|
vox.m_messageTrap.macroId = macroId;
|
||||||
m_messageTrap.macroStep = macroStep;
|
vox.m_messageTrap.macroStep = macroStep;
|
||||||
break;
|
break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
@ -797,16 +800,16 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
||||||
switch (event)
|
switch (event)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
m_keyoffTrap.macroId = 0xffff;
|
vox.m_keyoffTrap.macroId = 0xffff;
|
||||||
m_keyoffTrap.macroStep = -1;
|
vox.m_keyoffTrap.macroStep = -1;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
m_sampleEndTrap.macroId = 0xffff;
|
vox.m_sampleEndTrap.macroId = 0xffff;
|
||||||
m_sampleEndTrap.macroStep = -1;
|
vox.m_sampleEndTrap.macroStep = -1;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
m_messageTrap.macroId = 0xffff;
|
vox.m_messageTrap.macroId = 0xffff;
|
||||||
m_messageTrap.macroStep = -1;
|
vox.m_messageTrap.macroStep = -1;
|
||||||
break;
|
break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
@ -834,10 +837,10 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
||||||
case Op::GetMessage:
|
case Op::GetMessage:
|
||||||
{
|
{
|
||||||
uint8_t vid = cmd.m_data[0];
|
uint8_t vid = cmd.m_data[0];
|
||||||
if (m_messageQueue.size())
|
if (vox.m_messageQueue.size())
|
||||||
{
|
{
|
||||||
m_variables[vid] = m_messageQueue.front();
|
m_variables[vid] = vox.m_messageQueue.front();
|
||||||
m_messageQueue.pop_front();
|
vox.m_messageQueue.pop_front();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_variables[vid] = 0;
|
m_variables[vid] = 0;
|
||||||
|
@ -1221,47 +1224,11 @@ bool SoundMacroState::advance(Voice& vox, double dt)
|
||||||
void SoundMacroState::keyoffNotify(Voice& vox)
|
void SoundMacroState::keyoffNotify(Voice& vox)
|
||||||
{
|
{
|
||||||
m_keyoff = true;
|
m_keyoff = true;
|
||||||
if (m_inWait && m_keyoffWait)
|
|
||||||
m_inWait = false;
|
|
||||||
|
|
||||||
if (m_keyoffTrap.macroId != 0xffff)
|
|
||||||
{
|
|
||||||
if (m_keyoffTrap.macroId == m_header.m_macroId)
|
|
||||||
m_pc.back().second = m_keyoffTrap.macroStep;
|
|
||||||
else
|
|
||||||
vox.loadSoundObject(m_keyoffTrap.macroId, m_keyoffTrap.macroStep,
|
|
||||||
m_ticksPerSec, m_initKey, m_initVel, m_initMod);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundMacroState::sampleEndNotify(Voice& vox)
|
void SoundMacroState::sampleEndNotify(Voice& vox)
|
||||||
{
|
{
|
||||||
m_sampleEnd = true;
|
m_sampleEnd = true;
|
||||||
if (m_inWait && m_sampleEndWait)
|
|
||||||
m_inWait = false;
|
|
||||||
|
|
||||||
if (m_sampleEndTrap.macroId != 0xffff)
|
|
||||||
{
|
|
||||||
if (m_sampleEndTrap.macroId == m_header.m_macroId)
|
|
||||||
m_pc.back().second = m_sampleEndTrap.macroStep;
|
|
||||||
else
|
|
||||||
vox.loadSoundObject(m_sampleEndTrap.macroId, m_sampleEndTrap.macroStep,
|
|
||||||
m_ticksPerSec, m_initKey, m_initVel, m_initMod);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundMacroState::messageNotify(Voice& vox, int32_t val)
|
|
||||||
{
|
|
||||||
m_messageQueue.push_back(val);
|
|
||||||
|
|
||||||
if (m_messageTrap.macroId != 0xffff)
|
|
||||||
{
|
|
||||||
if (m_messageTrap.macroId == m_header.m_macroId)
|
|
||||||
m_pc.back().second = m_messageTrap.macroStep;
|
|
||||||
else
|
|
||||||
vox.loadSoundObject(m_messageTrap.macroId, m_messageTrap.macroStep,
|
|
||||||
m_ticksPerSec, m_initKey, m_initVel, m_initMod);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
233
lib/Voice.cpp
233
lib/Voice.cpp
|
@ -70,6 +70,24 @@ void Voice::_reset()
|
||||||
memset(m_extCtrlVals, 0, 128);
|
memset(m_extCtrlVals, 0, 128);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Voice::_macroSampleEnd()
|
||||||
|
{
|
||||||
|
if (m_sampleEndTrap.macroId != 0xffff)
|
||||||
|
{
|
||||||
|
if (m_sampleEndTrap.macroId == m_state.m_header.m_macroId)
|
||||||
|
{
|
||||||
|
m_state.m_pc.back().second = m_sampleEndTrap.macroStep;
|
||||||
|
m_state.m_inWait = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
loadSoundObject(m_sampleEndTrap.macroId, m_sampleEndTrap.macroStep,
|
||||||
|
m_state.m_ticksPerSec, m_state.m_initKey,
|
||||||
|
m_state.m_initVel, m_state.m_initMod);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_state.sampleEndNotify(*this);
|
||||||
|
}
|
||||||
|
|
||||||
bool Voice::_checkSamplePos()
|
bool Voice::_checkSamplePos()
|
||||||
{
|
{
|
||||||
if (m_curSamplePos >= m_lastSamplePos)
|
if (m_curSamplePos >= m_lastSamplePos)
|
||||||
|
@ -84,7 +102,7 @@ bool Voice::_checkSamplePos()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Notify sample end */
|
/* Notify sample end */
|
||||||
m_state.sampleEndNotify(*this);
|
_macroSampleEnd();
|
||||||
m_curSample = nullptr;
|
m_curSample = nullptr;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -93,7 +111,7 @@ bool Voice::_checkSamplePos()
|
||||||
/* Looped samples issue sample end when ADSR envelope complete */
|
/* Looped samples issue sample end when ADSR envelope complete */
|
||||||
if (m_volAdsr.isComplete())
|
if (m_volAdsr.isComplete())
|
||||||
{
|
{
|
||||||
m_state.sampleEndNotify(*this);
|
_macroSampleEnd();
|
||||||
m_curSample = nullptr;
|
m_curSample = nullptr;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -110,6 +128,7 @@ void Voice::_doKeyOff()
|
||||||
|
|
||||||
void Voice::_setTotalPitch(int32_t cents)
|
void Voice::_setTotalPitch(int32_t cents)
|
||||||
{
|
{
|
||||||
|
fprintf(stderr, "PITCH %d\n", cents);
|
||||||
int32_t interval = cents - m_curSample->first.m_pitch * 100;
|
int32_t interval = cents - m_curSample->first.m_pitch * 100;
|
||||||
double ratio = std::exp2(interval / 1200.0);
|
double ratio = std::exp2(interval / 1200.0);
|
||||||
m_sampleRate = m_curSample->first.m_sampleRate * ratio;
|
m_sampleRate = m_curSample->first.m_sampleRate * ratio;
|
||||||
|
@ -304,7 +323,7 @@ size_t Voice::supplyAudio(size_t samples, int16_t* data)
|
||||||
{
|
{
|
||||||
uint32_t samplesRem = samples;
|
uint32_t samplesRem = samples;
|
||||||
size_t samplesProc = 0;
|
size_t samplesProc = 0;
|
||||||
bool dead = false;
|
bool dead = true;
|
||||||
|
|
||||||
/* Attempt to load stopped sample for immediate decoding */
|
/* Attempt to load stopped sample for immediate decoding */
|
||||||
if (!m_curSample)
|
if (!m_curSample)
|
||||||
|
@ -313,48 +332,91 @@ size_t Voice::supplyAudio(size_t samples, int16_t* data)
|
||||||
if (m_curSample)
|
if (m_curSample)
|
||||||
{
|
{
|
||||||
dead = m_state.advance(*this, samples / m_sampleRate);
|
dead = m_state.advance(*this, samples / m_sampleRate);
|
||||||
if (!dead)
|
uint32_t block = m_curSamplePos / 14;
|
||||||
|
uint32_t rem = m_curSamplePos % 14;
|
||||||
|
|
||||||
|
if (rem)
|
||||||
{
|
{
|
||||||
uint32_t block = m_curSamplePos / 14;
|
uint32_t remCount = std::min(samplesRem, m_lastSamplePos - block * 14);
|
||||||
uint32_t rem = m_curSamplePos % 14;
|
uint32_t decSamples;
|
||||||
|
|
||||||
if (rem)
|
switch (m_curFormat)
|
||||||
{
|
{
|
||||||
uint32_t remCount = std::min(samplesRem, m_lastSamplePos - block * 14);
|
case SampleFormat::DSP:
|
||||||
uint32_t decSamples;
|
{
|
||||||
|
decSamples = DSPDecompressFrameRanged(data, m_curSampleData + 8 * block,
|
||||||
switch (m_curFormat)
|
m_curSample->second.m_coefs,
|
||||||
{
|
&m_prev1, &m_prev2, rem, remCount);
|
||||||
case SampleFormat::DSP:
|
break;
|
||||||
{
|
|
||||||
decSamples = DSPDecompressFrameRanged(data, m_curSampleData + 8 * block,
|
|
||||||
m_curSample->second.m_coefs,
|
|
||||||
&m_prev1, &m_prev2, rem, remCount);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SampleFormat::PCM:
|
|
||||||
{
|
|
||||||
const int16_t* pcm = reinterpret_cast<const int16_t*>(m_curSampleData);
|
|
||||||
for (uint32_t i=0 ; i<remCount ; ++i)
|
|
||||||
data[i] = SBig(pcm[m_curSamplePos+i]);
|
|
||||||
decSamples = remCount;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Per-sample processing */
|
|
||||||
for (int i=0 ; i<decSamples ; ++i)
|
|
||||||
{
|
|
||||||
++samplesProc;
|
|
||||||
++m_curSamplePos;
|
|
||||||
if (_advanceSample(data[i]))
|
|
||||||
return samplesProc;
|
|
||||||
}
|
|
||||||
|
|
||||||
samplesRem -= decSamples;
|
|
||||||
data += decSamples;
|
|
||||||
}
|
}
|
||||||
|
case SampleFormat::PCM:
|
||||||
|
{
|
||||||
|
const int16_t* pcm = reinterpret_cast<const int16_t*>(m_curSampleData);
|
||||||
|
for (uint32_t i=0 ; i<remCount ; ++i)
|
||||||
|
data[i] = SBig(pcm[m_curSamplePos+i]);
|
||||||
|
decSamples = remCount;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Per-sample processing */
|
||||||
|
for (int i=0 ; i<decSamples ; ++i)
|
||||||
|
{
|
||||||
|
++samplesProc;
|
||||||
|
++m_curSamplePos;
|
||||||
|
if (_advanceSample(data[i]))
|
||||||
|
return samplesProc;
|
||||||
|
}
|
||||||
|
|
||||||
|
samplesRem -= decSamples;
|
||||||
|
data += decSamples;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_checkSamplePos())
|
||||||
|
{
|
||||||
|
if (samplesRem)
|
||||||
|
memset(data, 0, sizeof(int16_t) * samplesRem);
|
||||||
|
return samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (samplesRem)
|
||||||
|
{
|
||||||
|
block = m_curSamplePos / 14;
|
||||||
|
uint32_t remCount = std::min(samplesRem, m_lastSamplePos - block * 14);
|
||||||
|
uint32_t decSamples;
|
||||||
|
|
||||||
|
switch (m_curFormat)
|
||||||
|
{
|
||||||
|
case SampleFormat::DSP:
|
||||||
|
{
|
||||||
|
decSamples = DSPDecompressFrame(data, m_curSampleData + 8 * block,
|
||||||
|
m_curSample->second.m_coefs,
|
||||||
|
&m_prev1, &m_prev2, remCount);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SampleFormat::PCM:
|
||||||
|
{
|
||||||
|
const int16_t* pcm = reinterpret_cast<const int16_t*>(m_curSampleData);
|
||||||
|
for (uint32_t i=0 ; i<remCount ; ++i)
|
||||||
|
data[i] = SBig(pcm[m_curSamplePos+i]);
|
||||||
|
decSamples = remCount;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Per-sample processing */
|
||||||
|
for (int i=0 ; i<decSamples ; ++i)
|
||||||
|
{
|
||||||
|
++samplesProc;
|
||||||
|
++m_curSamplePos;
|
||||||
|
if (_advanceSample(data[i]))
|
||||||
|
return samplesProc;
|
||||||
|
}
|
||||||
|
|
||||||
|
samplesRem -= decSamples;
|
||||||
|
data += decSamples;
|
||||||
|
|
||||||
if (_checkSamplePos())
|
if (_checkSamplePos())
|
||||||
{
|
{
|
||||||
|
@ -362,58 +424,15 @@ size_t Voice::supplyAudio(size_t samples, int16_t* data)
|
||||||
memset(data, 0, sizeof(int16_t) * samplesRem);
|
memset(data, 0, sizeof(int16_t) * samplesRem);
|
||||||
return samples;
|
return samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (samplesRem)
|
|
||||||
{
|
|
||||||
block = m_curSamplePos / 14;
|
|
||||||
uint32_t remCount = std::min(samplesRem, m_lastSamplePos - block * 14);
|
|
||||||
uint32_t decSamples;
|
|
||||||
|
|
||||||
switch (m_curFormat)
|
|
||||||
{
|
|
||||||
case SampleFormat::DSP:
|
|
||||||
{
|
|
||||||
decSamples = DSPDecompressFrame(data, m_curSampleData + 8 * block,
|
|
||||||
m_curSample->second.m_coefs,
|
|
||||||
&m_prev1, &m_prev2, remCount);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SampleFormat::PCM:
|
|
||||||
{
|
|
||||||
const int16_t* pcm = reinterpret_cast<const int16_t*>(m_curSampleData);
|
|
||||||
for (uint32_t i=0 ; i<remCount ; ++i)
|
|
||||||
data[i] = SBig(pcm[m_curSamplePos+i]);
|
|
||||||
decSamples = remCount;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Per-sample processing */
|
|
||||||
for (int i=0 ; i<decSamples ; ++i)
|
|
||||||
{
|
|
||||||
++samplesProc;
|
|
||||||
++m_curSamplePos;
|
|
||||||
if (_advanceSample(data[i]))
|
|
||||||
return samplesProc;
|
|
||||||
}
|
|
||||||
|
|
||||||
samplesRem -= decSamples;
|
|
||||||
data += decSamples;
|
|
||||||
|
|
||||||
if (_checkSamplePos())
|
|
||||||
{
|
|
||||||
if (samplesRem)
|
|
||||||
memset(data, 0, sizeof(int16_t) * samplesRem);
|
|
||||||
return samples;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
memset(data, 0, sizeof(int16_t) * samples);
|
memset(data, 0, sizeof(int16_t) * samples);
|
||||||
|
|
||||||
if (dead)
|
if (dead && m_voxState == VoiceState::KeyOff &&
|
||||||
|
m_sampleEndTrap.macroId == 0xffff &&
|
||||||
|
m_messageTrap.macroId == 0xffff &&
|
||||||
|
m_volAdsr.isComplete())
|
||||||
{
|
{
|
||||||
m_voxState = VoiceState::Dead;
|
m_voxState = VoiceState::Dead;
|
||||||
m_backendVoice->stop();
|
m_backendVoice->stop();
|
||||||
|
@ -483,13 +502,13 @@ bool Voice::_loadLayer(const std::vector<const LayerMapping*>& layer, int macroS
|
||||||
{
|
{
|
||||||
if (midiKey >= mapping->keyLo && midiKey <= mapping->keyHi)
|
if (midiKey >= mapping->keyLo && midiKey <= mapping->keyHi)
|
||||||
{
|
{
|
||||||
midiKey += mapping->transpose;
|
uint8_t mappingKey = midiKey + mapping->transpose;
|
||||||
if (m_voxState != VoiceState::Playing)
|
if (m_voxState != VoiceState::Playing)
|
||||||
ret |= loadSoundObject(SBig(mapping->objectId), macroStep, ticksPerSec,
|
ret |= loadSoundObject(SBig(mapping->objectId), macroStep, ticksPerSec,
|
||||||
midiKey, midiVel, midiMod, pushPc);
|
mappingKey, midiVel, midiMod, pushPc);
|
||||||
else
|
else
|
||||||
ret |= _startChildMacro(SBig(mapping->objectId), macroStep, ticksPerSec,
|
ret |= _startChildMacro(SBig(mapping->objectId), macroStep, ticksPerSec,
|
||||||
midiKey, midiVel, midiMod, pushPc).operator bool();
|
mappingKey, midiVel, midiMod, pushPc).operator bool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -514,7 +533,7 @@ bool Voice::loadSoundObject(ObjectId objectId, int macroStep, double ticksPerSec
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Voice::keyOff()
|
void Voice::_macroKeyOff()
|
||||||
{
|
{
|
||||||
if (m_sustained)
|
if (m_sustained)
|
||||||
m_sustainKeyOff = true;
|
m_sustainKeyOff = true;
|
||||||
|
@ -527,8 +546,38 @@ void Voice::keyOff()
|
||||||
m_voxState = VoiceState::KeyOff;
|
m_voxState = VoiceState::KeyOff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Voice::keyOff()
|
||||||
|
{
|
||||||
|
if (m_keyoffTrap.macroId != 0xffff)
|
||||||
|
{
|
||||||
|
if (m_keyoffTrap.macroId == m_state.m_header.m_macroId)
|
||||||
|
{
|
||||||
|
m_state.m_pc.back().second = m_keyoffTrap.macroStep;
|
||||||
|
m_state.m_inWait = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
loadSoundObject(m_keyoffTrap.macroId, m_keyoffTrap.macroStep,
|
||||||
|
m_state.m_ticksPerSec, m_state.m_initKey,
|
||||||
|
m_state.m_initVel, m_state.m_initMod);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_macroKeyOff();
|
||||||
|
}
|
||||||
|
|
||||||
void Voice::message(int32_t val)
|
void Voice::message(int32_t val)
|
||||||
{
|
{
|
||||||
|
m_messageQueue.push_back(val);
|
||||||
|
|
||||||
|
if (m_messageTrap.macroId != 0xffff)
|
||||||
|
{
|
||||||
|
if (m_messageTrap.macroId == m_state.m_header.m_macroId)
|
||||||
|
m_state.m_pc.back().second = m_messageTrap.macroStep;
|
||||||
|
else
|
||||||
|
loadSoundObject(m_messageTrap.macroId, m_messageTrap.macroStep,
|
||||||
|
m_state.m_ticksPerSec, m_state.m_initKey,
|
||||||
|
m_state.m_initVel, m_state.m_initMod);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Voice::startSample(int16_t sampId, int32_t offset)
|
void Voice::startSample(int16_t sampId, int32_t offset)
|
||||||
|
|
Loading…
Reference in New Issue