mirror of https://github.com/AxioDL/amuse.git
374 lines
10 KiB
C++
374 lines
10 KiB
C++
#include "amuse/SoundMacroState.hpp"
|
|
#include "amuse/Voice.hpp"
|
|
#include "amuse/Engine.hpp"
|
|
#include "amuse/Common.hpp"
|
|
#include <string.h>
|
|
|
|
namespace amuse
|
|
{
|
|
|
|
void SoundMacroState::Header::swapBig()
|
|
{
|
|
m_size = SBig(m_size);
|
|
m_macroId = SBig(m_macroId);
|
|
}
|
|
|
|
void SoundMacroState::Command::swapBig()
|
|
{
|
|
uint32_t* words = reinterpret_cast<uint32_t*>(this);
|
|
words[0] = SBig(words[0]);
|
|
words[1] = SBig(words[1]);
|
|
}
|
|
|
|
void SoundMacroState::initialize(const unsigned char* ptr)
|
|
{
|
|
m_ptr = ptr;
|
|
m_ticksPerSec = 1000.f;
|
|
m_midiKey = 0;
|
|
m_midiVel = 0;
|
|
m_midiMod = 0;
|
|
m_random.seed();
|
|
m_pc.clear();
|
|
m_pc.push_back(-1);
|
|
m_execTime = 0.f;
|
|
m_keyoff = false;
|
|
m_sampleEnd = false;
|
|
m_loopCountdown = -1;
|
|
m_lastPlayMacroVid = -1;
|
|
memcpy(&m_header, ptr, sizeof(Header));
|
|
m_header.swapBig();
|
|
}
|
|
|
|
void SoundMacroState::initialize(const unsigned char* ptr, float ticksPerSec,
|
|
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod)
|
|
{
|
|
m_ptr = ptr;
|
|
m_ticksPerSec = ticksPerSec;
|
|
m_midiKey = midiKey;
|
|
m_midiVel = midiVel;
|
|
m_midiMod = midiMod;
|
|
m_random.seed();
|
|
m_pc.clear();
|
|
m_pc.push_back(-1);
|
|
m_execTime = 0.f;
|
|
m_keyoff = false;
|
|
m_sampleEnd = false;
|
|
m_loopCountdown = -1;
|
|
m_lastPlayMacroVid = -1;
|
|
memcpy(&m_header, ptr, sizeof(Header));
|
|
m_header.swapBig();
|
|
}
|
|
|
|
bool SoundMacroState::advance(Voice& vox, float dt)
|
|
{
|
|
/* Nothing if uninitialized or finished */
|
|
if (m_pc.back() == -1)
|
|
return true;
|
|
|
|
/* Loop through as many commands as we can for this time period */
|
|
while (true)
|
|
{
|
|
/* Advance wait timer if active, returning if waiting */
|
|
if (m_inWait)
|
|
{
|
|
m_waitCountdown -= dt;
|
|
if (m_waitCountdown < 0.f)
|
|
m_inWait = false;
|
|
else
|
|
{
|
|
m_execTime += dt;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* Load next command based on counter */
|
|
const Command* commands = reinterpret_cast<const Command*>(m_ptr + sizeof(Header));
|
|
Command cmd = commands[m_pc.back()++];
|
|
cmd.swapBig();
|
|
|
|
/* Perform function of command */
|
|
switch (cmd.m_op)
|
|
{
|
|
case Op::End:
|
|
case Op::Stop:
|
|
m_pc.back() = -1;
|
|
return true;
|
|
case Op::SplitKey:
|
|
{
|
|
uint8_t keyNumber = cmd.m_data[0];
|
|
int16_t macroId = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
|
int16_t macroStep = *reinterpret_cast<int16_t*>(&cmd.m_data[3]);
|
|
|
|
if (m_midiKey >= keyNumber)
|
|
{
|
|
/* Do Branch */
|
|
if (macroId == m_header.m_macroId)
|
|
m_pc.back() = macroStep;
|
|
else
|
|
vox.loadSoundMacro(macroId, macroStep);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case Op::SplitVel:
|
|
{
|
|
uint8_t velocity = cmd.m_data[0];
|
|
int16_t macroId = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
|
int16_t macroStep = *reinterpret_cast<int16_t*>(&cmd.m_data[3]);
|
|
|
|
if (m_midiVel >= velocity)
|
|
{
|
|
/* Do Branch */
|
|
if (macroId == m_header.m_macroId)
|
|
m_pc.back() = macroStep;
|
|
else
|
|
vox.loadSoundMacro(macroId, macroStep);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case Op::WaitTicks:
|
|
{
|
|
bool keyRelease = cmd.m_data[0];
|
|
bool random = cmd.m_data[1];
|
|
bool sampleEnd = cmd.m_data[2];
|
|
bool absolute = cmd.m_data[3];
|
|
bool ms = cmd.m_data[4];
|
|
int16_t time = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
|
|
|
|
/* Set wait state */
|
|
float q = ms ? 1000.f : m_ticksPerSec;
|
|
float secTime = time / q;
|
|
if (absolute)
|
|
{
|
|
if (secTime <= m_execTime)
|
|
break;
|
|
m_waitCountdown = secTime - m_execTime;
|
|
}
|
|
else
|
|
m_waitCountdown = secTime;
|
|
|
|
/* Randomize at the proper resolution */
|
|
if (random)
|
|
secTime = std::fmod(m_random() / q, secTime);
|
|
|
|
m_inWait = true;
|
|
m_keyoffWait = keyRelease;
|
|
m_sampleEndWait = sampleEnd;
|
|
break;
|
|
}
|
|
case Op::Loop:
|
|
{
|
|
bool keyRelease = cmd.m_data[0];
|
|
bool random = cmd.m_data[1];
|
|
bool sampleEnd = cmd.m_data[2];
|
|
int16_t step = *reinterpret_cast<int16_t*>(&cmd.m_data[3]);
|
|
int16_t times = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
|
|
|
|
if ((keyRelease && m_keyoff) || (sampleEnd && m_sampleEnd))
|
|
{
|
|
/* Break out of loop */
|
|
m_loopCountdown = -1;
|
|
break;
|
|
}
|
|
|
|
if (random)
|
|
times = m_random() % times;
|
|
|
|
if (m_loopCountdown == -1 && times != -1)
|
|
m_loopCountdown = times;
|
|
|
|
if (m_loopCountdown > 0)
|
|
{
|
|
/* Loop back to step */
|
|
--m_loopCountdown;
|
|
m_pc.back() = step;
|
|
}
|
|
else /* Break out of loop */
|
|
m_loopCountdown = -1;
|
|
|
|
break;
|
|
}
|
|
case Op::Goto:
|
|
{
|
|
int16_t macroId = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
|
int16_t macroStep = *reinterpret_cast<int16_t*>(&cmd.m_data[3]);
|
|
|
|
/* Do Branch */
|
|
if (macroId == m_header.m_macroId)
|
|
m_pc.back() = macroStep;
|
|
else
|
|
vox.loadSoundMacro(macroId, macroStep);
|
|
|
|
break;
|
|
}
|
|
case Op::WaitMs:
|
|
{
|
|
bool keyRelease = cmd.m_data[0];
|
|
bool random = cmd.m_data[1];
|
|
bool sampleEnd = cmd.m_data[2];
|
|
bool absolute = cmd.m_data[3];
|
|
int16_t time = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
|
|
|
|
/* Set wait state */
|
|
float secTime = time / 1000.f;
|
|
if (absolute)
|
|
{
|
|
if (secTime <= m_execTime)
|
|
break;
|
|
m_waitCountdown = secTime - m_execTime;
|
|
}
|
|
else
|
|
m_waitCountdown = secTime;
|
|
|
|
/* Randomize at the proper resolution */
|
|
if (random)
|
|
secTime = std::fmod(m_random() / 1000.f, secTime);
|
|
|
|
m_inWait = true;
|
|
m_keyoffWait = keyRelease;
|
|
m_sampleEndWait = sampleEnd;
|
|
break;
|
|
}
|
|
case Op::PlayMacro:
|
|
{
|
|
int8_t addNote = cmd.m_data[0];
|
|
int16_t macroId = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
|
int16_t macroStep = *reinterpret_cast<int16_t*>(&cmd.m_data[3]);
|
|
int8_t priority = cmd.m_data[5];
|
|
int8_t maxVoices = cmd.m_data[6];
|
|
|
|
Voice* sibVox = vox.startSiblingMacro(addNote, macroId, macroStep);
|
|
if (sibVox)
|
|
m_lastPlayMacroVid = sibVox->vid();
|
|
|
|
break;
|
|
}
|
|
case Op::SendKeyOff:
|
|
{
|
|
uint8_t vid = cmd.m_data[0];
|
|
bool lastStarted = cmd.m_data[1];
|
|
|
|
if (lastStarted)
|
|
{
|
|
if (m_lastPlayMacroVid != -1)
|
|
{
|
|
Voice* otherVox = vox.getEngine().findVoice(m_lastPlayMacroVid);
|
|
otherVox->keyOff();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Voice* otherVox = vox.getEngine().findVoice(m_variables[vid]);
|
|
otherVox->keyOff();
|
|
}
|
|
|
|
break;
|
|
}
|
|
case Op::SplitMod:
|
|
{
|
|
uint8_t mod = cmd.m_data[0];
|
|
int16_t macroId = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
|
int16_t macroStep = *reinterpret_cast<int16_t*>(&cmd.m_data[3]);
|
|
|
|
if (m_midiMod >= mod)
|
|
{
|
|
/* Do Branch */
|
|
if (macroId == m_header.m_macroId)
|
|
m_pc.back() = macroStep;
|
|
else
|
|
vox.loadSoundMacro(macroId, macroStep);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case Op::PianoPan:
|
|
case Op::SetAdsr:
|
|
case Op::ScaleVolume:
|
|
case Op::Panning:
|
|
case Op::Envelope:
|
|
case Op::StartSample:
|
|
case Op::StopSample:
|
|
case Op::KeyOff:
|
|
case Op::SplitRnd:
|
|
case Op::FadeIn:
|
|
case Op::Spanning:
|
|
case Op::SetAdsrCtrl:
|
|
case Op::RndNote:
|
|
case Op::AddNote:
|
|
case Op::SetNote:
|
|
case Op::LastNote:
|
|
case Op::Portamento:
|
|
case Op::Vibrato:
|
|
case Op::PitchSweep1:
|
|
case Op::PitchSweep2:
|
|
case Op::SetPitch:
|
|
case Op::SetPitchAdsr:
|
|
case Op::ScaleVolumeDLS:
|
|
case Op::Mod2Vibrange:
|
|
case Op::SetupTremolo:
|
|
case Op::Return:
|
|
case Op::GoSub:
|
|
case Op::TrapEvent:
|
|
case Op::SendMessage:
|
|
case Op::GetMessage:
|
|
case Op::GetVid:
|
|
case Op::AddAgeCount:
|
|
case Op::SetAgeCount:
|
|
case Op::SendFlag:
|
|
case Op::PitchWheelR:
|
|
case Op::SetPriority:
|
|
case Op::AddPriority:
|
|
case Op::AgeCntSpeed:
|
|
case Op::AgeCntVel:
|
|
case Op::VolSelect:
|
|
case Op::PanSelect:
|
|
case Op::PitchWheelSelect:
|
|
case Op::ModWheelSelect:
|
|
case Op::PedalSelect:
|
|
case Op::PortaSelect:
|
|
case Op::ReverbSelect:
|
|
case Op::SpanSelect:
|
|
case Op::DopplerSelect:
|
|
case Op::TremoloSelect:
|
|
case Op::PreASelect:
|
|
case Op::PreBSelect:
|
|
case Op::PostBSelect:
|
|
case Op::AuxAFXSelect:
|
|
case Op::AuxBFXSelect:
|
|
case Op::SetupLFO:
|
|
case Op::ModeSelect:
|
|
case Op::SetKeygroup:
|
|
case Op::SRCmodeSelect:
|
|
case Op::AddVars:
|
|
case Op::SubVars:
|
|
case Op::MulVars:
|
|
case Op::DivVars:
|
|
case Op::AddIVars:
|
|
case Op::IfEqual:
|
|
case Op::IfLess:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_execTime += dt;
|
|
return false;
|
|
}
|
|
|
|
void SoundMacroState::keyoff()
|
|
{
|
|
m_keyoff = true;
|
|
if (m_inWait && m_keyoffWait)
|
|
m_inWait = false;
|
|
}
|
|
|
|
void SoundMacroState::sampleEnd()
|
|
{
|
|
m_sampleEnd = true;
|
|
if (m_inWait && m_sampleEndWait)
|
|
m_inWait = false;
|
|
}
|
|
|
|
}
|