mirror of https://github.com/AxioDL/amuse.git
Some SoundMacro command implementations
This commit is contained in:
parent
fa8d9038df
commit
338df76711
|
@ -46,7 +46,7 @@ int main(int argc, char* argv[])
|
|||
int sfxId = 0x1337;
|
||||
float vol = 1.0f;
|
||||
float pan = 0.0f;
|
||||
int voiceId = snd.fxStart(sfxId, vol, pan);
|
||||
Voice* voice = snd.fxStart(sfxId, vol, pan);
|
||||
|
||||
/* Play for ~5 sec */
|
||||
int passedFrames = 0;
|
||||
|
@ -57,10 +57,10 @@ int main(int argc, char* argv[])
|
|||
WaitForVSync();
|
||||
}
|
||||
|
||||
/* Stopping a SoundMacro is accomplished by sending the engine a
|
||||
/* Stopping a SoundMacro is accomplished by sending a
|
||||
* MIDI-style 'KeyOff' message for the voice
|
||||
*/
|
||||
snd.fxKeyOff(voiceId);
|
||||
voice.keyOff();
|
||||
|
||||
/* Play for 2 more seconds to allow the macro to gracefully fade-out */
|
||||
passedFrames = 0;
|
||||
|
|
|
@ -35,7 +35,7 @@ public:
|
|||
void swapBig();
|
||||
};
|
||||
private:
|
||||
std::vector<Entry> m_entries;
|
||||
std::vector<std::pair<Entry, ADPCMParms>> m_entries;
|
||||
public:
|
||||
AudioGroupSampleDirectory(const unsigned char* data);
|
||||
};
|
||||
|
|
|
@ -21,10 +21,10 @@ class Engine
|
|||
{
|
||||
IBackendVoiceAllocator& m_backend;
|
||||
std::unordered_map<int, std::unique_ptr<AudioGroup>> m_audioGroups;
|
||||
std::list<std::unique_ptr<Voice>> m_activeVoices;
|
||||
std::list<std::unique_ptr<Emitter>> m_activeEmitters;
|
||||
std::list<std::unique_ptr<Sequencer>> m_activeSequencers;
|
||||
Voice* _allocateVoice(int groupId, double sampleRate, bool dynamicPitch);
|
||||
std::list<Voice> m_activeVoices;
|
||||
std::list<Emitter> m_activeEmitters;
|
||||
std::list<Sequencer> m_activeSequencers;
|
||||
Voice* _allocateVoice(int groupId, double sampleRate, bool dynamicPitch, bool emitter);
|
||||
AudioGroup* _findGroupFromSfxId(int sfxId, const AudioGroupSampleDirectory::Entry*& entOut) const;
|
||||
AudioGroup* _findGroupFromSongId(int songId) const;
|
||||
public:
|
||||
|
@ -48,6 +48,9 @@ public:
|
|||
|
||||
/** Start song playing from loaded audio groups */
|
||||
Sequencer* seqPlay(int songId, const unsigned char* arrData);
|
||||
|
||||
/** Find voice from VoiceId */
|
||||
Voice* findVoice(int vid);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,11 +1,153 @@
|
|||
#ifndef __AMUSE_SOUNDMACROSTATE_HPP__
|
||||
#define __AMUSE_SOUNDMACROSTATE_HPP__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <random>
|
||||
|
||||
namespace amuse
|
||||
{
|
||||
class Voice;
|
||||
|
||||
class SoundMacroState
|
||||
{
|
||||
/** SoundMacro header */
|
||||
struct Header
|
||||
{
|
||||
uint32_t m_size;
|
||||
uint16_t m_macroId;
|
||||
uint8_t m_volume;
|
||||
uint8_t m_pan;
|
||||
void swapBig();
|
||||
} m_header;
|
||||
|
||||
/** SoundMacro command operations */
|
||||
enum class Op : uint8_t
|
||||
{
|
||||
End,
|
||||
Stop,
|
||||
SplitKey,
|
||||
SplitVel,
|
||||
WaitTicks,
|
||||
Loop,
|
||||
Goto,
|
||||
WaitMs,
|
||||
PlayMacro,
|
||||
SendKeyOff,
|
||||
SplitMod,
|
||||
PianoPan,
|
||||
SetAdsr,
|
||||
ScaleVolume,
|
||||
Panning,
|
||||
Envelope,
|
||||
StartSample,
|
||||
StopSample,
|
||||
KeyOff,
|
||||
SplitRnd,
|
||||
FadeIn,
|
||||
Spanning,
|
||||
SetAdsrCtrl,
|
||||
RndNote,
|
||||
AddNote,
|
||||
SetNote,
|
||||
LastNote,
|
||||
Portamento,
|
||||
Vibrato,
|
||||
PitchSweep1,
|
||||
PitchSweep2,
|
||||
SetPitch,
|
||||
SetPitchAdsr,
|
||||
ScaleVolumeDLS,
|
||||
Mod2Vibrange,
|
||||
SetupTremolo,
|
||||
Return,
|
||||
GoSub,
|
||||
TrapEvent = 0x28,
|
||||
SendMessage,
|
||||
GetMessage,
|
||||
GetVid,
|
||||
AddAgeCount = 0x30,
|
||||
SetAgeCount,
|
||||
SendFlag,
|
||||
PitchWheelR,
|
||||
SetPriority,
|
||||
AddPriority,
|
||||
AgeCntSpeed,
|
||||
AgeCntVel,
|
||||
VolSelect = 0x40,
|
||||
PanSelect,
|
||||
PitchWheelSelect,
|
||||
ModWheelSelect,
|
||||
PedalSelect,
|
||||
PortaSelect,
|
||||
ReverbSelect,
|
||||
SpanSelect,
|
||||
DopplerSelect,
|
||||
TremoloSelect,
|
||||
PreASelect,
|
||||
PreBSelect,
|
||||
PostBSelect,
|
||||
AuxAFXSelect,
|
||||
AuxBFXSelect,
|
||||
SetupLFO = 0x50,
|
||||
ModeSelect = 0x58,
|
||||
SetKeygroup,
|
||||
SRCmodeSelect,
|
||||
AddVars = 0x60,
|
||||
SubVars,
|
||||
MulVars,
|
||||
DivVars,
|
||||
AddIVars,
|
||||
IfEqual = 0x70,
|
||||
IfLess,
|
||||
};
|
||||
|
||||
/** SoundMacro command structure */
|
||||
struct Command
|
||||
{
|
||||
Op m_op;
|
||||
char m_data[7];
|
||||
void swapBig();
|
||||
};
|
||||
|
||||
const unsigned char* m_ptr = nullptr; /**< pointer to selected SoundMacro data */
|
||||
std::vector<int> m_pc; /**< 'program counter' stack for the active SoundMacro */
|
||||
|
||||
float m_ticksPerSec; /**< ratio for resolving ticks in commands that use them */
|
||||
uint8_t m_midiKey; /**< Key played for this macro invocation */
|
||||
uint8_t m_midiVel; /**< Velocity played for this macro invocation */
|
||||
uint8_t m_midiMod; /**< Modulation played for this macro invocation */
|
||||
std::linear_congruential_engine<uint32_t, 0x41c64e6d, 0x3039, UINT32_MAX> m_random;
|
||||
|
||||
float m_execTime; /**< time in seconds of SoundMacro execution */
|
||||
bool m_keyoff; /**< keyoff message has been received */
|
||||
bool m_sampleEnd; /**< sample has finished playback */
|
||||
|
||||
bool m_inWait = false; /**< set when timer/keyoff/sampleend wait active */
|
||||
bool m_keyoffWait = false; /**< set when active wait is a keyoff wait */
|
||||
bool m_sampleEndWait = false; /**< set when active wait is a sampleend wait */
|
||||
float m_waitCountdown; /**< countdown timer for active wait */
|
||||
|
||||
int m_loopCountdown = -1; /**< countdown for current loop */
|
||||
int m_lastPlayMacroVid = -1; /**< VoiceId from last PlayMacro command */
|
||||
|
||||
int32_t m_variables[256]; /**< 32-bit variables set with relevant commands */
|
||||
|
||||
public:
|
||||
/** initialize state for SoundMacro data at `ptr` */
|
||||
void initialize(const unsigned char* ptr);
|
||||
void initialize(const unsigned char* ptr, float ticksPerSec,
|
||||
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod);
|
||||
|
||||
/** advances `dt` seconds worth of commands in the SoundMacro
|
||||
* @return `true` if END reached
|
||||
*/
|
||||
bool advance(Voice& vox, float dt);
|
||||
|
||||
/** keyoff event */
|
||||
void keyoff();
|
||||
|
||||
/** sample end event */
|
||||
void sampleEnd();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -23,10 +23,13 @@ enum class VoiceState
|
|||
class Voice : public Entity
|
||||
{
|
||||
friend class Engine;
|
||||
int m_vid;
|
||||
bool m_emitter;
|
||||
std::unique_ptr<IBackendVoice> m_backendVoice;
|
||||
SoundMacroState m_state;
|
||||
Voice* m_sibling = nullptr;
|
||||
public:
|
||||
Voice(Engine& engine, int groupId);
|
||||
Voice(Engine& engine, int groupId, int vid, bool emitter);
|
||||
|
||||
/** Request specified count of audio frames (samples) from voice,
|
||||
* internally advancing the voice stream */
|
||||
|
@ -35,6 +38,15 @@ public:
|
|||
/** Get current state of voice */
|
||||
VoiceState state() const;
|
||||
|
||||
/** Get VoiceId of this voice (unique to all currently-playing voices) */
|
||||
int vid() const {return m_vid;}
|
||||
|
||||
/** Allocate parallel macro and tie to voice for possible emitter influence */
|
||||
Voice* startSiblingMacro(int8_t addNote, int macroId, int macroStep);
|
||||
|
||||
/** Load specified SoundMacro ID of within group into voice */
|
||||
bool loadSoundMacro(int macroId, int macroStep=0);
|
||||
|
||||
/** Signals voice to begin fade-out, eventually reaching silence */
|
||||
void keyOff();
|
||||
|
||||
|
|
|
@ -22,9 +22,9 @@ bool AudioGroup::songInGroup(int songId) const
|
|||
|
||||
const AudioGroupSampleDirectory::Entry* AudioGroup::getSfxEntry(int sfxId) const
|
||||
{
|
||||
for (const AudioGroupSampleDirectory::Entry& ent : m_sdir.m_entries)
|
||||
if (ent.m_sfxId == sfxId)
|
||||
return &ent;
|
||||
for (const auto& ent : m_sdir.m_entries)
|
||||
if (ent.first.m_sfxId == sfxId)
|
||||
return &ent.first;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,13 +13,12 @@ Engine::Engine(IBackendVoiceAllocator& backend)
|
|||
: m_backend(backend)
|
||||
{}
|
||||
|
||||
Voice* Engine::_allocateVoice(int groupId, double sampleRate, bool dynamicPitch)
|
||||
Voice* Engine::_allocateVoice(int groupId, double sampleRate, bool dynamicPitch, bool emitter)
|
||||
{
|
||||
std::unique_ptr<Voice> vox = std::make_unique<Voice>(*this, groupId);
|
||||
vox->m_backendVoice = m_backend.allocateVoice(*vox, sampleRate, dynamicPitch);
|
||||
Voice* ret = vox.get();
|
||||
m_activeVoices.push_back(std::move(vox));
|
||||
return ret;
|
||||
m_activeVoices.emplace_back(*this, groupId, m_activeVoices.size(), emitter);
|
||||
m_activeVoices.back().m_backendVoice =
|
||||
m_backend.allocateVoice(m_activeVoices.back(), sampleRate, dynamicPitch);
|
||||
return &m_activeVoices.back();
|
||||
}
|
||||
|
||||
AudioGroup* Engine::_findGroupFromSfxId(int sfxId, const AudioGroupSampleDirectory::Entry*& entOut) const
|
||||
|
@ -61,7 +60,7 @@ void Engine::removeAudioGroup(int groupId)
|
|||
{
|
||||
for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ;)
|
||||
{
|
||||
if ((*it)->getGroupId() == groupId)
|
||||
if (it->getGroupId() == groupId)
|
||||
{
|
||||
it = m_activeVoices.erase(it);
|
||||
continue;
|
||||
|
@ -71,7 +70,7 @@ void Engine::removeAudioGroup(int groupId)
|
|||
|
||||
for (auto it = m_activeEmitters.begin() ; it != m_activeEmitters.end() ;)
|
||||
{
|
||||
if ((*it)->getGroupId() == groupId)
|
||||
if (it->getGroupId() == groupId)
|
||||
{
|
||||
it = m_activeEmitters.erase(it);
|
||||
continue;
|
||||
|
@ -81,7 +80,7 @@ void Engine::removeAudioGroup(int groupId)
|
|||
|
||||
for (auto it = m_activeSequencers.begin() ; it != m_activeSequencers.end() ;)
|
||||
{
|
||||
if ((*it)->getGroupId() == groupId)
|
||||
if (it->getGroupId() == groupId)
|
||||
{
|
||||
it = m_activeSequencers.erase(it);
|
||||
continue;
|
||||
|
@ -100,7 +99,7 @@ Voice* Engine::fxStart(int sfxId, float vol, float pan)
|
|||
if (!grp)
|
||||
return nullptr;
|
||||
|
||||
Voice* ret = _allocateVoice(grp->groupId(), entry->m_sampleRate, true);
|
||||
Voice* ret = _allocateVoice(grp->groupId(), entry->m_sampleRate, true, false);
|
||||
ret->setVolume(vol);
|
||||
ret->setPanning(pan);
|
||||
return ret;
|
||||
|
@ -115,18 +114,17 @@ Emitter* Engine::addEmitter(const Vector3f& pos, const Vector3f& dir, float maxD
|
|||
if (!grp)
|
||||
return nullptr;
|
||||
|
||||
Voice* vox = _allocateVoice(grp->groupId(), entry->m_sampleRate, true);
|
||||
std::unique_ptr<Emitter> emtr = std::make_unique<Emitter>(*this, grp->groupId(), *vox);
|
||||
Emitter* ret = emtr.get();
|
||||
ret->setPos(pos);
|
||||
ret->setDir(dir);
|
||||
ret->setMaxDist(maxDist);
|
||||
ret->setFalloff(falloff);
|
||||
ret->setMinVol(minVol);
|
||||
ret->setMaxVol(maxVol);
|
||||
Voice* vox = _allocateVoice(grp->groupId(), entry->m_sampleRate, true, true);
|
||||
m_activeEmitters.emplace_back(*this, grp->groupId(), *vox);
|
||||
Emitter& ret = m_activeEmitters.back();
|
||||
ret.setPos(pos);
|
||||
ret.setDir(dir);
|
||||
ret.setMaxDist(maxDist);
|
||||
ret.setFalloff(falloff);
|
||||
ret.setMinVol(minVol);
|
||||
ret.setMaxVol(maxVol);
|
||||
|
||||
m_activeEmitters.push_back(std::move(emtr));
|
||||
return ret;
|
||||
return &ret;
|
||||
}
|
||||
|
||||
/** Start song playing from loaded audio groups */
|
||||
|
@ -134,4 +132,13 @@ Sequencer* Engine::seqPlay(int songId, const unsigned char* arrData)
|
|||
{
|
||||
}
|
||||
|
||||
/** Find voice from VoiceId */
|
||||
Voice* Engine::findVoice(int vid)
|
||||
{
|
||||
for (Voice& vox : m_activeVoices)
|
||||
if (vox.vid() == vid)
|
||||
return &vox;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,373 @@
|
|||
#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;
|
||||
}
|
||||
|
||||
}
|
|
@ -4,8 +4,8 @@
|
|||
namespace amuse
|
||||
{
|
||||
|
||||
Voice::Voice(Engine& engine, int groupId)
|
||||
: Entity(engine, groupId)
|
||||
Voice::Voice(Engine& engine, int groupId, int vid, bool emitter)
|
||||
: Entity(engine, groupId), m_vid(vid), m_emitter(emitter)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -13,4 +13,12 @@ size_t Voice::supplyAudio(size_t frames, int16_t* data)
|
|||
{
|
||||
}
|
||||
|
||||
Voice* Voice::startSiblingMacro(int8_t addNote, int macroId, int macroStep)
|
||||
{
|
||||
}
|
||||
|
||||
bool Voice::loadSoundMacro(int macroId, int macroStep)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue