mirror of https://github.com/AxioDL/amuse.git
Lots of SoundMacro implementations
This commit is contained in:
parent
fa66632b7c
commit
9860e3859c
|
@ -25,6 +25,7 @@ public:
|
|||
bool sfxInGroup(int sfxId) const;
|
||||
bool songInGroup(int songId) const;
|
||||
|
||||
const AudioGroupPool& getPool() const;
|
||||
const AudioGroupSampleDirectory::Entry* getSfxEntry(int sfxId) const;
|
||||
};
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include "Entity.hpp"
|
||||
|
||||
namespace amuse
|
||||
{
|
||||
|
@ -21,9 +22,6 @@ struct ADSR
|
|||
uint8_t releaseCoarse; /* 0-65280ms */
|
||||
};
|
||||
|
||||
/** Curves for mapping velocity to volume and other functional mappings */
|
||||
using Curves = uint8_t[128];
|
||||
|
||||
/** Maps individual MIDI keys to sound-entity as indexed in table
|
||||
* (macro-voice, keymap, layer) */
|
||||
struct Keymap
|
||||
|
@ -51,20 +49,15 @@ struct LayerMapping
|
|||
/** Database of functional objects within Audio Group */
|
||||
class AudioGroupPool
|
||||
{
|
||||
std::unordered_map<int, const unsigned char*> m_soundMacros;
|
||||
std::unordered_map<int, const unsigned char*> m_tables;
|
||||
std::unordered_map<int, const Keymap*> m_keymaps;
|
||||
std::unordered_map<int, std::vector<const LayerMapping*>> m_layers;
|
||||
std::unordered_map<ObjectId, const unsigned char*> m_soundMacros;
|
||||
std::unordered_map<ObjectId, const unsigned char*> m_tables;
|
||||
std::unordered_map<ObjectId, const Keymap*> m_keymaps;
|
||||
std::unordered_map<ObjectId, std::vector<const LayerMapping*>> m_layers;
|
||||
public:
|
||||
AudioGroupPool(const unsigned char* data);
|
||||
const ADSR* tableAsAdsr(int id) const
|
||||
{
|
||||
auto search = m_tables.find(id);
|
||||
if (search == m_tables.cend())
|
||||
return nullptr;
|
||||
return reinterpret_cast<const ADSR*>(search->second);
|
||||
}
|
||||
const Curves* tableAsCurves(int id) const {return reinterpret_cast<const Curves*>(tableAsAdsr(id));}
|
||||
const ADSR* tableAsAdsr(ObjectId id) const;
|
||||
const Curve* tableAsCurves(ObjectId id) const
|
||||
{return reinterpret_cast<const Curve*>(tableAsAdsr(id));}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ class Emitter : public Entity
|
|||
{
|
||||
Voice& m_vox;
|
||||
public:
|
||||
Emitter(Engine& engine, int groupId, Voice& vox);
|
||||
Emitter(Engine& engine, const AudioGroup& group, Voice& vox);
|
||||
|
||||
void setPos(const Vector3f& pos);
|
||||
void setDir(const Vector3f& dir);
|
||||
|
|
|
@ -25,7 +25,7 @@ class Engine
|
|||
std::list<Emitter> m_activeEmitters;
|
||||
std::list<Sequencer> m_activeSequencers;
|
||||
int m_nextVid = 0;
|
||||
Voice* _allocateVoice(int groupId, double sampleRate, bool dynamicPitch, bool emitter);
|
||||
Voice* _allocateVoice(const AudioGroup& group, double sampleRate, bool dynamicPitch, bool emitter);
|
||||
AudioGroup* _findGroupFromSfxId(int sfxId, const AudioGroupSampleDirectory::Entry*& entOut) const;
|
||||
AudioGroup* _findGroupFromSongId(int songId) const;
|
||||
public:
|
||||
|
|
|
@ -1,24 +1,64 @@
|
|||
#ifndef __AMUSE_ENTITY_HPP__
|
||||
#define __AMUSE_ENTITY_HPP__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <functional>
|
||||
|
||||
namespace amuse
|
||||
{
|
||||
class Engine;
|
||||
class AudioGroup;
|
||||
|
||||
enum class ObjectType : uint8_t
|
||||
{
|
||||
Invalid = 0xff,
|
||||
SoundMacro = 0,
|
||||
Table = 1,
|
||||
Kaymap = 4,
|
||||
Layer = 8
|
||||
};
|
||||
|
||||
/** Common ID structure statically tagging
|
||||
* SoundMacros, Tables, Keymaps, Layers */
|
||||
struct ObjectId
|
||||
{
|
||||
ObjectType type = ObjectType::Invalid;
|
||||
uint8_t id = 0xff;
|
||||
bool operator ==(const ObjectId& other) const
|
||||
{return *reinterpret_cast<const uint16_t*>(this) == reinterpret_cast<const uint16_t&>(other);}
|
||||
bool operator !=(const ObjectId& other) const
|
||||
{return *reinterpret_cast<const uint16_t*>(this) != reinterpret_cast<const uint16_t&>(other);}
|
||||
};
|
||||
|
||||
/** Common 'engine child' class */
|
||||
class Entity
|
||||
{
|
||||
protected:
|
||||
Engine& m_engine;
|
||||
int m_groupId;
|
||||
const AudioGroup& m_audioGroup;
|
||||
ObjectId m_objectId; /* if applicable */
|
||||
public:
|
||||
Entity(Engine& engine, int groupId)
|
||||
: m_engine(engine), m_groupId(groupId) {}
|
||||
Entity(Engine& engine, const AudioGroup& group, ObjectId oid=ObjectId())
|
||||
: m_engine(engine), m_audioGroup(group), m_objectId(oid) {}
|
||||
|
||||
Engine& getEngine() {return m_engine;}
|
||||
int getGroupId() {return m_groupId;}
|
||||
const AudioGroup& getAudioGroup() const {return m_audioGroup;}
|
||||
ObjectId getObjectId() const {return m_objectId;}
|
||||
};
|
||||
|
||||
/** Curves for mapping velocity to volume and other functional mappings
|
||||
* (defined here for visibility)*/
|
||||
using Curve = uint8_t[128];
|
||||
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <> struct hash<amuse::ObjectId>
|
||||
{
|
||||
size_t operator()(const amuse::ObjectId& val) const noexcept
|
||||
{return std::hash<uint16_t>()(reinterpret_cast<const uint16_t&>(val));}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // __AMUSE_ENTITY_HPP__
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <random>
|
||||
#include "Entity.hpp"
|
||||
|
||||
namespace amuse
|
||||
{
|
||||
|
@ -14,7 +15,7 @@ class SoundMacroState
|
|||
struct Header
|
||||
{
|
||||
uint32_t m_size;
|
||||
uint16_t m_macroId;
|
||||
ObjectId m_macroId;
|
||||
uint8_t m_volume;
|
||||
uint8_t m_pan;
|
||||
void swapBig();
|
||||
|
@ -78,7 +79,7 @@ class SoundMacroState
|
|||
PitchWheelSelect,
|
||||
ModWheelSelect,
|
||||
PedalSelect,
|
||||
PortaSelect,
|
||||
PortASelect,
|
||||
ReverbSelect,
|
||||
SpanSelect,
|
||||
DopplerSelect,
|
||||
|
@ -112,16 +113,51 @@ class SoundMacroState
|
|||
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_curVol; /**< cumulative (final) volume level sent to voice */
|
||||
bool m_volDirty; /**< set when voice needs updated volume */
|
||||
|
||||
float m_curPan; /**< cumulative (final) volume level sent to voice */
|
||||
bool m_panDirty; /**< set when voice needs updated pan */
|
||||
|
||||
float m_curSpan; /**< cumulative (final) volume level sent to voice */
|
||||
bool m_spanDirty; /**< set when voice needs updated span */
|
||||
|
||||
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 */
|
||||
uint8_t m_initVel; /**< Velocity played for this macro invocation */
|
||||
uint8_t m_initMod; /**< Modulation 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_curMod; /**< Current modulation played for this macro invocation */
|
||||
uint32_t m_curKey; /**< Current key played for this macro invocation (in cents) */
|
||||
uint32_t m_pitchSweep1; /**< Current value of PITCHSWEEP1 controller (in cents) */
|
||||
uint32_t m_pitchSweep2; /**< Current value of PITCHSWEEP2 controller (in cents) */
|
||||
int16_t m_pitchSweep1Add; /**< Value to add to PITCHSWEEP1 controller each cycle */
|
||||
int16_t m_pitchSweep2Add; /**< Value to add to PITCHSWEEP2 controller each cycle */
|
||||
uint8_t m_pitchSweep1Times; /**< Remaining times to advance PITCHSWEEP1 controller */
|
||||
uint8_t m_pitchSweep2Times; /**< Remaining times to advance PITCHSWEEP2 controller */
|
||||
bool m_pitchDirty; /**< set when voice needs latest pitch computation */
|
||||
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 */
|
||||
|
||||
float m_envelopeTime; /**< time since last ENVELOPE command, -1 for no active volume-sweep */
|
||||
float m_envelopeDur; /**< requested duration of last ENVELOPE command */
|
||||
uint8_t m_envelopeStart; /**< initial value for last ENVELOPE command */
|
||||
uint8_t m_envelopeEnd; /**< final value for last ENVELOPE command */
|
||||
const Curve* m_envelopeCurve; /**< curve to use for ENVELOPE command */
|
||||
|
||||
float m_panningTime; /**< time since last PANNING command, -1 for no active pan-sweep */
|
||||
float m_panningDur; /**< requested duration of last PANNING command */
|
||||
uint8_t m_panPos; /**< initial pan value of last PANNING command */
|
||||
uint8_t m_panWidth; /**< delta pan value to target of last PANNING command */
|
||||
|
||||
float m_spanningTime; /**< time since last SPANNING command, -1 for no active span-sweep */
|
||||
float m_spanningDur; /**< requested duration of last SPANNING command */
|
||||
uint8_t m_spanPos; /**< initial pan value of last SPANNING command */
|
||||
uint8_t m_spanWidth; /**< delta pan value to target of last SPANNING command */
|
||||
|
||||
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 */
|
||||
|
@ -130,6 +166,81 @@ class SoundMacroState
|
|||
int m_loopCountdown = -1; /**< countdown for current loop */
|
||||
int m_lastPlayMacroVid = -1; /**< VoiceId from last PlayMacro command */
|
||||
|
||||
bool m_useAdsrControllers; /**< when set, use the following controllers for envelope times */
|
||||
uint8_t m_midiAttack; /**< Attack MIDI controller */
|
||||
uint8_t m_midiDecay; /**< Decay MIDI controller */
|
||||
uint8_t m_midiSustain; /**< Sustain MIDI controller */
|
||||
uint8_t m_midiRelease; /**< Release MIDI controller */
|
||||
|
||||
uint8_t m_portamentoMode; /**< (0: Off, 1: On, 2: MIDI specified) */
|
||||
uint8_t m_portamentoType; /**< (0: New key pressed while old key pressed, 1: Always) */
|
||||
float m_portamentoTime; /**< portamento transition time, 0.f will perform legato */
|
||||
|
||||
int32_t m_vibratoLevel; /**< scale of vibrato effect (in cents) */
|
||||
int32_t m_vibratoModLevel; /**< scale of vibrato mod-wheel influence (in cents) */
|
||||
float m_vibratoPeriod; /**< vibrato wave period-time, 0.f will disable vibrato */
|
||||
bool m_vibratoModWheel; /**< vibrato scaled with mod-wheel if set */
|
||||
|
||||
float m_tremoloScale; /**< minimum volume factor produced via LFO */
|
||||
float m_tremoloModScale; /**< minimum volume factor produced via LFO, scaled via mod wheel */
|
||||
|
||||
float m_lfoPeriods[2]; /**< time-periods for LFO1 and LFO2 */
|
||||
|
||||
/** Used to store LFO-reference parameters for compatible state systems */
|
||||
struct LFOSel
|
||||
{
|
||||
enum class Combine : uint8_t
|
||||
{
|
||||
Set,
|
||||
Add,
|
||||
Mult
|
||||
};
|
||||
enum class VarType : uint8_t
|
||||
{
|
||||
Ctrl,
|
||||
Var
|
||||
};
|
||||
|
||||
/** Represents one term of the LFO formula assembled via *_SELECT commands */
|
||||
struct Component
|
||||
{
|
||||
uint8_t m_midiCtrl;
|
||||
float m_scale;
|
||||
Combine m_combine;
|
||||
VarType m_varType;
|
||||
|
||||
Component(uint8_t midiCtrl, float scale, Combine combine, VarType varType)
|
||||
: m_midiCtrl(midiCtrl), m_scale(scale), m_combine(combine), m_varType(varType) {}
|
||||
};
|
||||
std::vector<Component> m_comps; /**< Components built up by the macro */
|
||||
|
||||
/** Combine additional component(s) to LFO calcuation */
|
||||
void addComponent(uint8_t midiCtrl, float scale,
|
||||
Combine combine, VarType varType);
|
||||
|
||||
/** Calculate current scaled LFO value */
|
||||
float evaluate(Voice& vox, const SoundMacroState& st);
|
||||
|
||||
/** Determine if this LFOSel is valid to use */
|
||||
operator bool() const {return m_comps.size() != 0;}
|
||||
};
|
||||
|
||||
LFOSel m_volumeSel;
|
||||
LFOSel m_panSel;
|
||||
LFOSel m_pitchWheelSel;
|
||||
LFOSel m_modWheelSel;
|
||||
LFOSel m_pedalSel;
|
||||
LFOSel m_portASel;
|
||||
LFOSel m_reverbSel;
|
||||
LFOSel m_preAuxASel;
|
||||
LFOSel m_preAuxBSel;
|
||||
LFOSel m_auxAFxSel;
|
||||
LFOSel m_auxBFxSel;
|
||||
LFOSel m_postAuxB;
|
||||
LFOSel m_spanSel;
|
||||
LFOSel m_dopplerSel;
|
||||
LFOSel m_tremoloSel;
|
||||
|
||||
int32_t m_variables[256]; /**< 32-bit variables set with relevant commands */
|
||||
|
||||
public:
|
||||
|
|
|
@ -28,8 +28,10 @@ class Voice : public Entity
|
|||
std::unique_ptr<IBackendVoice> m_backendVoice;
|
||||
SoundMacroState m_state;
|
||||
Voice* m_sibling = nullptr;
|
||||
uint8_t m_lastNote = 0;
|
||||
public:
|
||||
Voice(Engine& engine, int groupId, int vid, bool emitter);
|
||||
Voice(Engine& engine, const AudioGroup& group, int vid, bool emitter);
|
||||
Voice(Engine& engine, const AudioGroup& group, ObjectId oid, int vid, bool emitter);
|
||||
|
||||
/** Request specified count of audio frames (samples) from voice,
|
||||
* internally advancing the voice stream */
|
||||
|
@ -42,23 +44,33 @@ public:
|
|||
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);
|
||||
Voice* startSiblingMacro(int8_t addNote, ObjectId macroId, int macroStep);
|
||||
|
||||
/** Load specified SoundMacro ID of within group into voice */
|
||||
bool loadSoundMacro(int macroId, int macroStep=0);
|
||||
bool loadSoundMacro(ObjectId macroId, int macroStep=0);
|
||||
|
||||
/** Signals voice to begin fade-out, eventually reaching silence */
|
||||
void keyOff();
|
||||
|
||||
void startSample(int16_t sampId, int32_t offset);
|
||||
void stopSample();
|
||||
void setVolume(float vol);
|
||||
void setPanning(float pan);
|
||||
void setSurroundPanning(float span);
|
||||
void setPitchBend(float pitch);
|
||||
void setPitchKey(int32_t cents);
|
||||
void setModulation(float mod);
|
||||
void setPedal(bool pedal);
|
||||
void setDoppler(float doppler);
|
||||
void setReverbVol(float rvol);
|
||||
void setAdsr(int adsrIdx, uint8_t type);
|
||||
void setAdsr(ObjectId adsrId);
|
||||
void setPitchFrequency(uint32_t hz, uint16_t fine);
|
||||
void setPitchAdsr(ObjectId adsrId, int32_t cents);
|
||||
|
||||
uint8_t getLastNote() const {return m_lastNote;}
|
||||
int8_t getCtrlValue(uint8_t ctrl) const;
|
||||
int8_t getPitchWheel() const;
|
||||
int8_t getModWheel() const;
|
||||
int8_t getAftertouch() const;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "amuse/AudioGroupPool.hpp"
|
||||
#include "amuse/Common.hpp"
|
||||
#include "amuse/Entity.hpp"
|
||||
|
||||
namespace amuse
|
||||
{
|
||||
|
@ -30,7 +31,7 @@ AudioGroupPool::AudioGroupPool(const unsigned char* data)
|
|||
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
|
||||
{
|
||||
uint32_t size = SBig(*reinterpret_cast<const uint32_t*>(cur));
|
||||
uint16_t id = SBig(*reinterpret_cast<const uint16_t*>(cur + 4));
|
||||
ObjectId id = *reinterpret_cast<const ObjectId*>(cur + 4);
|
||||
m_soundMacros[id] = cur + 8;
|
||||
cur += size;
|
||||
}
|
||||
|
@ -42,7 +43,7 @@ AudioGroupPool::AudioGroupPool(const unsigned char* data)
|
|||
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
|
||||
{
|
||||
uint32_t size = SBig(*reinterpret_cast<const uint32_t*>(cur));
|
||||
uint16_t id = SBig(*reinterpret_cast<const uint16_t*>(cur + 4));
|
||||
ObjectId id = *reinterpret_cast<const ObjectId*>(cur + 4);
|
||||
m_tables[id] = cur + 8;
|
||||
cur += size;
|
||||
}
|
||||
|
@ -54,7 +55,7 @@ AudioGroupPool::AudioGroupPool(const unsigned char* data)
|
|||
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
|
||||
{
|
||||
uint32_t size = SBig(*reinterpret_cast<const uint32_t*>(cur));
|
||||
uint16_t id = SBig(*reinterpret_cast<const uint16_t*>(cur + 4));
|
||||
ObjectId id = *reinterpret_cast<const ObjectId*>(cur + 4);
|
||||
m_keymaps[id] = reinterpret_cast<const Keymap*>(cur + 8);
|
||||
cur += size;
|
||||
}
|
||||
|
@ -66,7 +67,7 @@ AudioGroupPool::AudioGroupPool(const unsigned char* data)
|
|||
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
|
||||
{
|
||||
uint32_t size = SBig(*reinterpret_cast<const uint32_t*>(cur));
|
||||
uint16_t id = SBig(*reinterpret_cast<const uint16_t*>(cur + 4));
|
||||
ObjectId id = *reinterpret_cast<const ObjectId*>(cur + 4);
|
||||
std::vector<const LayerMapping*>& mappingsOut = m_layers[id];
|
||||
|
||||
uint32_t count = SBig(*reinterpret_cast<const uint32_t*>(cur+8));
|
||||
|
@ -80,4 +81,12 @@ AudioGroupPool::AudioGroupPool(const unsigned char* data)
|
|||
}
|
||||
}
|
||||
|
||||
const ADSR* AudioGroupPool::tableAsAdsr(ObjectId id) const
|
||||
{
|
||||
auto search = m_tables.find(id);
|
||||
if (search == m_tables.cend())
|
||||
return nullptr;
|
||||
return reinterpret_cast<const ADSR*>(search->second);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
#include "amuse/Emitter.hpp"
|
||||
#include "amuse/Voice.hpp"
|
||||
|
||||
namespace amuse
|
||||
{
|
||||
|
||||
Emitter::Emitter(Engine& engine, int groupId, Voice& vox)
|
||||
: Entity(engine, groupId), m_vox(vox)
|
||||
Emitter::Emitter(Engine& engine, const AudioGroup& group, Voice& vox)
|
||||
: Entity(engine, group, vox.getObjectId()), m_vox(vox)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -13,9 +13,9 @@ Engine::Engine(IBackendVoiceAllocator& backend)
|
|||
: m_backend(backend)
|
||||
{}
|
||||
|
||||
Voice* Engine::_allocateVoice(int groupId, double sampleRate, bool dynamicPitch, bool emitter)
|
||||
Voice* Engine::_allocateVoice(const AudioGroup& group, double sampleRate, bool dynamicPitch, bool emitter)
|
||||
{
|
||||
m_activeVoices.emplace_back(*this, groupId, m_nextVid++, emitter);
|
||||
m_activeVoices.emplace_back(*this, group, m_nextVid++, emitter);
|
||||
m_activeVoices.back().m_backendVoice =
|
||||
m_backend.allocateVoice(m_activeVoices.back(), sampleRate, dynamicPitch);
|
||||
return &m_activeVoices.back();
|
||||
|
@ -66,7 +66,7 @@ void Engine::removeAudioGroup(int groupId)
|
|||
{
|
||||
for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ;)
|
||||
{
|
||||
if (it->getGroupId() == groupId)
|
||||
if (it->getAudioGroup().groupId() == groupId)
|
||||
{
|
||||
it = m_activeVoices.erase(it);
|
||||
continue;
|
||||
|
@ -76,7 +76,7 @@ void Engine::removeAudioGroup(int groupId)
|
|||
|
||||
for (auto it = m_activeEmitters.begin() ; it != m_activeEmitters.end() ;)
|
||||
{
|
||||
if (it->getGroupId() == groupId)
|
||||
if (it->getAudioGroup().groupId() == groupId)
|
||||
{
|
||||
it = m_activeEmitters.erase(it);
|
||||
continue;
|
||||
|
@ -86,7 +86,7 @@ void Engine::removeAudioGroup(int groupId)
|
|||
|
||||
for (auto it = m_activeSequencers.begin() ; it != m_activeSequencers.end() ;)
|
||||
{
|
||||
if (it->getGroupId() == groupId)
|
||||
if (it->getAudioGroup().groupId() == groupId)
|
||||
{
|
||||
it = m_activeSequencers.erase(it);
|
||||
continue;
|
||||
|
@ -105,7 +105,7 @@ Voice* Engine::fxStart(int sfxId, float vol, float pan)
|
|||
if (!grp)
|
||||
return nullptr;
|
||||
|
||||
Voice* ret = _allocateVoice(grp->groupId(), entry->m_sampleRate, true, false);
|
||||
Voice* ret = _allocateVoice(*grp, entry->m_sampleRate, true, false);
|
||||
ret->setVolume(vol);
|
||||
ret->setPanning(pan);
|
||||
return ret;
|
||||
|
@ -120,8 +120,8 @@ Emitter* Engine::addEmitter(const Vector3f& pos, const Vector3f& dir, float maxD
|
|||
if (!grp)
|
||||
return nullptr;
|
||||
|
||||
Voice* vox = _allocateVoice(grp->groupId(), entry->m_sampleRate, true, true);
|
||||
m_activeEmitters.emplace_back(*this, grp->groupId(), *vox);
|
||||
Voice* vox = _allocateVoice(*grp, entry->m_sampleRate, true, true);
|
||||
m_activeEmitters.emplace_back(*this, *grp, *vox);
|
||||
Emitter& ret = m_activeEmitters.back();
|
||||
ret.setPos(pos);
|
||||
ret.setDir(dir);
|
||||
|
|
|
@ -2,15 +2,20 @@
|
|||
#include "amuse/Voice.hpp"
|
||||
#include "amuse/Engine.hpp"
|
||||
#include "amuse/Common.hpp"
|
||||
#include "amuse/AudioGroup.hpp"
|
||||
#include "amuse/AudioGroupPool.hpp"
|
||||
#include <string.h>
|
||||
|
||||
#ifndef M_PIF
|
||||
#define M_PIF 3.14159265358979323846f /* pi */
|
||||
#endif
|
||||
|
||||
namespace amuse
|
||||
{
|
||||
|
||||
void SoundMacroState::Header::swapBig()
|
||||
{
|
||||
m_size = SBig(m_size);
|
||||
m_macroId = SBig(m_macroId);
|
||||
}
|
||||
|
||||
void SoundMacroState::Command::swapBig()
|
||||
|
@ -20,41 +25,139 @@ void SoundMacroState::Command::swapBig()
|
|||
words[1] = SBig(words[1]);
|
||||
}
|
||||
|
||||
void SoundMacroState::LFOSel::addComponent(uint8_t midiCtrl, float scale,
|
||||
Combine combine, VarType varType)
|
||||
{
|
||||
m_comps.push_back({midiCtrl, scale, combine, varType});
|
||||
}
|
||||
|
||||
float SoundMacroState::LFOSel::evaluate(Voice& vox, const SoundMacroState& st)
|
||||
{
|
||||
float value = 0.f;
|
||||
|
||||
/* Iterate each component */
|
||||
for (auto it=m_comps.cbegin() ; it != m_comps.cend() ; ++it)
|
||||
{
|
||||
const Component& comp = *it;
|
||||
float thisValue = 0.f;
|
||||
|
||||
/* Load selected data */
|
||||
if (comp.m_varType == VarType::Ctrl)
|
||||
{
|
||||
switch (comp.m_midiCtrl)
|
||||
{
|
||||
case 128:
|
||||
/* Pitchbend */
|
||||
thisValue = vox.getPitchWheel();
|
||||
break;
|
||||
case 129:
|
||||
/* Aftertouch */
|
||||
thisValue = vox.getAftertouch();
|
||||
break;
|
||||
case 130:
|
||||
/* LFO1 */
|
||||
if (st.m_lfoPeriods[0])
|
||||
thisValue = std::sin(st.m_execTime / st.m_lfoPeriods[0] * 2.f * M_PIF);
|
||||
break;
|
||||
case 131:
|
||||
/* LFO2 */
|
||||
if (st.m_lfoPeriods[1])
|
||||
thisValue = std::sin(st.m_execTime / st.m_lfoPeriods[1] * 2.f * M_PIF);
|
||||
break;
|
||||
case 132:
|
||||
/* Surround panning */
|
||||
thisValue = st.m_curSpan * 64.f + 64.f;
|
||||
break;
|
||||
case 133:
|
||||
/* Macro-starting key */
|
||||
thisValue = st.m_initKey;
|
||||
break;
|
||||
case 134:
|
||||
/* Macro-starting velocity */
|
||||
thisValue = st.m_initVel;
|
||||
break;
|
||||
case 135:
|
||||
/* Time since macro-start (ms) */
|
||||
thisValue = st.m_execTime * 1000.f;
|
||||
break;
|
||||
default:
|
||||
thisValue = vox.getCtrlValue(comp.m_midiCtrl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (comp.m_varType == VarType::Var)
|
||||
thisValue = st.m_variables[std::max(0, std::min(255, int(comp.m_midiCtrl)))];
|
||||
|
||||
/* Apply scale */
|
||||
thisValue *= comp.m_scale;
|
||||
|
||||
/* Combine */
|
||||
if (it != m_comps.cbegin())
|
||||
{
|
||||
switch (comp.m_combine)
|
||||
{
|
||||
case Combine::Add:
|
||||
value += thisValue;
|
||||
break;
|
||||
case Combine::Mult:
|
||||
value *= thisValue;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
else
|
||||
value = thisValue;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
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;
|
||||
m_header = *reinterpret_cast<const Header*>(ptr);
|
||||
m_header.swapBig();
|
||||
initialize(ptr, 1000.f, 0, 0, 0);
|
||||
}
|
||||
|
||||
void SoundMacroState::initialize(const unsigned char* ptr, float ticksPerSec,
|
||||
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod)
|
||||
{
|
||||
m_ptr = ptr;
|
||||
m_curVol = 1.f;
|
||||
m_volDirty = true;
|
||||
m_curPan = 0.f;
|
||||
m_panDirty = true;
|
||||
m_curSpan = 0.f;
|
||||
m_spanDirty = true;
|
||||
m_ticksPerSec = ticksPerSec;
|
||||
m_midiKey = midiKey;
|
||||
m_midiVel = midiVel;
|
||||
m_midiMod = midiMod;
|
||||
m_initKey = 0;
|
||||
m_initVel = 0;
|
||||
m_initMod = 0;
|
||||
m_curVel = 0;
|
||||
m_curMod = 0;
|
||||
m_curKey = 0;
|
||||
m_pitchSweep1 = 0;
|
||||
m_pitchSweep1Times = 0;
|
||||
m_pitchSweep2 = 0;
|
||||
m_pitchSweep2Times = 0;
|
||||
m_pitchDirty = true;
|
||||
m_random.seed();
|
||||
m_pc.clear();
|
||||
m_pc.push_back(-1);
|
||||
m_execTime = 0.f;
|
||||
m_keyoff = false;
|
||||
m_sampleEnd = false;
|
||||
m_envelopeTime = -1.f;
|
||||
m_panningTime = -1.f;
|
||||
m_loopCountdown = -1;
|
||||
m_lastPlayMacroVid = -1;
|
||||
m_useAdsrControllers = false;
|
||||
m_portamentoMode = 0;
|
||||
m_vibratoLevel = 0;
|
||||
m_vibratoModLevel = 0;
|
||||
m_vibratoPeriod = 0.f;
|
||||
m_tremoloScale = 0.f;
|
||||
m_tremoloModScale = 0.f;
|
||||
m_lfoPeriods[0] = 0.f;
|
||||
m_lfoPeriods[1] = 0.f;
|
||||
m_header = *reinterpret_cast<const Header*>(ptr);
|
||||
m_header.swapBig();
|
||||
}
|
||||
|
@ -65,6 +168,107 @@ bool SoundMacroState::advance(Voice& vox, float dt)
|
|||
if (m_pc.back() == -1)
|
||||
return true;
|
||||
|
||||
/* Process active envelope */
|
||||
if (m_envelopeTime >= 0.f)
|
||||
{
|
||||
m_envelopeTime += dt;
|
||||
float start = m_envelopeStart / 127.f;
|
||||
float end = m_envelopeEnd / 127.f;
|
||||
float t = std::max(0.f, std::min(1.f, m_envelopeTime / m_envelopeDur));
|
||||
if (m_envelopeCurve)
|
||||
t = (*m_envelopeCurve)[int(t*127.f)] / 127.f;
|
||||
m_curVol = (start * (1.0f - t)) + (end * t);
|
||||
m_volDirty = true;
|
||||
|
||||
/* Done with envelope */
|
||||
if (m_envelopeTime > m_envelopeDur)
|
||||
m_envelopeTime = -1.f;
|
||||
}
|
||||
|
||||
/* Apply tremolo */
|
||||
float totalVol = m_curVol;
|
||||
if (m_tremoloSel && (m_tremoloScale || m_tremoloModScale))
|
||||
{
|
||||
float t = m_tremoloSel.evaluate(vox, *this);
|
||||
if (m_tremoloScale && m_tremoloModScale)
|
||||
{
|
||||
float fac = (1.0f - t) + (m_tremoloScale * t);
|
||||
float modT = vox.getModWheel() / 127.f;
|
||||
float modFac = (1.0f - modT) + (m_tremoloModScale * modT);
|
||||
totalVol *= fac * modFac;
|
||||
}
|
||||
else if (m_tremoloScale)
|
||||
{
|
||||
float fac = (1.0f - t) + (m_tremoloScale * t);
|
||||
totalVol *= fac;
|
||||
}
|
||||
else if (m_tremoloModScale)
|
||||
{
|
||||
float modT = vox.getModWheel() / 127.f;
|
||||
float modFac = (1.0f - modT) + (m_tremoloModScale * modT);
|
||||
totalVol *= modFac;
|
||||
}
|
||||
m_volDirty = true;
|
||||
}
|
||||
|
||||
/* Apply total volume */
|
||||
if (m_volDirty)
|
||||
{
|
||||
vox.setVolume(totalVol);
|
||||
m_volDirty = false;
|
||||
}
|
||||
|
||||
/* Process active pan-sweep */
|
||||
if (m_panningTime >= 0.f)
|
||||
{
|
||||
m_panningTime += dt;
|
||||
float start = (m_panPos - 64) / 64.f;
|
||||
float end = (m_panPos + m_panWidth - 64) / 64.f;
|
||||
float t = std::max(0.f, std::min(1.f, m_panningTime / m_panningDur));
|
||||
vox.setPanning((start * (1.0f - t)) + (end * t));
|
||||
|
||||
/* Done with panning */
|
||||
if (m_panningTime > m_panningDur)
|
||||
m_panningTime = -1.f;
|
||||
}
|
||||
|
||||
/* Process active span-sweep */
|
||||
if (m_spanningTime >= 0.f)
|
||||
{
|
||||
m_spanningTime += dt;
|
||||
float start = (m_spanPos - 64) / 64.f;
|
||||
float end = (m_spanPos + m_spanWidth - 64) / 64.f;
|
||||
float t = std::max(0.f, std::min(1.f, m_spanningTime / m_spanningDur));
|
||||
vox.setSurroundPanning((start * (1.0f - t)) + (end * t));
|
||||
|
||||
/* Done with spanning */
|
||||
if (m_spanningTime > m_spanningDur)
|
||||
m_spanningTime = -1.f;
|
||||
}
|
||||
|
||||
/* Process pitch sweep 1 */
|
||||
if (m_pitchSweep1Times)
|
||||
{
|
||||
m_pitchSweep1 += m_pitchSweep1Add;
|
||||
--m_pitchSweep1Times;
|
||||
m_pitchDirty = true;
|
||||
}
|
||||
|
||||
/* Process pitch sweep 2 */
|
||||
if (m_pitchSweep2Times)
|
||||
{
|
||||
m_pitchSweep2 += m_pitchSweep2Add;
|
||||
--m_pitchSweep2Times;
|
||||
m_pitchDirty = true;
|
||||
}
|
||||
|
||||
/* Apply total pitch */
|
||||
if (m_pitchDirty)
|
||||
{
|
||||
vox.setPitchKey(m_curKey + m_pitchSweep1 + m_pitchSweep2);
|
||||
m_pitchDirty = false;
|
||||
}
|
||||
|
||||
/* Loop through as many commands as we can for this time period */
|
||||
while (true)
|
||||
{
|
||||
|
@ -96,10 +300,10 @@ bool SoundMacroState::advance(Voice& vox, float dt)
|
|||
case Op::SplitKey:
|
||||
{
|
||||
uint8_t keyNumber = cmd.m_data[0];
|
||||
int16_t macroId = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
ObjectId macroId = *reinterpret_cast<ObjectId*>(&cmd.m_data[1]);
|
||||
int16_t macroStep = *reinterpret_cast<int16_t*>(&cmd.m_data[3]);
|
||||
|
||||
if (m_midiKey >= keyNumber)
|
||||
if (m_initKey >= keyNumber)
|
||||
{
|
||||
/* Do Branch */
|
||||
if (macroId == m_header.m_macroId)
|
||||
|
@ -113,10 +317,10 @@ bool SoundMacroState::advance(Voice& vox, float dt)
|
|||
case Op::SplitVel:
|
||||
{
|
||||
uint8_t velocity = cmd.m_data[0];
|
||||
int16_t macroId = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
ObjectId macroId = *reinterpret_cast<ObjectId*>(&cmd.m_data[1]);
|
||||
int16_t macroStep = *reinterpret_cast<int16_t*>(&cmd.m_data[3]);
|
||||
|
||||
if (m_midiVel >= velocity)
|
||||
if (m_curVel >= velocity)
|
||||
{
|
||||
/* Do Branch */
|
||||
if (macroId == m_header.m_macroId)
|
||||
|
@ -191,7 +395,7 @@ bool SoundMacroState::advance(Voice& vox, float dt)
|
|||
}
|
||||
case Op::Goto:
|
||||
{
|
||||
int16_t macroId = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
ObjectId macroId = *reinterpret_cast<ObjectId*>(&cmd.m_data[1]);
|
||||
int16_t macroStep = *reinterpret_cast<int16_t*>(&cmd.m_data[3]);
|
||||
|
||||
/* Do Branch */
|
||||
|
@ -233,7 +437,7 @@ bool SoundMacroState::advance(Voice& vox, float dt)
|
|||
case Op::PlayMacro:
|
||||
{
|
||||
int8_t addNote = cmd.m_data[0];
|
||||
int16_t macroId = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
ObjectId macroId = *reinterpret_cast<ObjectId*>(&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];
|
||||
|
@ -270,10 +474,10 @@ bool SoundMacroState::advance(Voice& vox, float dt)
|
|||
case Op::SplitMod:
|
||||
{
|
||||
uint8_t mod = cmd.m_data[0];
|
||||
int16_t macroId = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
ObjectId macroId = *reinterpret_cast<ObjectId*>(&cmd.m_data[1]);
|
||||
int16_t macroStep = *reinterpret_cast<int16_t*>(&cmd.m_data[3]);
|
||||
|
||||
if (m_midiMod >= mod)
|
||||
if (m_curMod >= mod)
|
||||
{
|
||||
/* Do Branch */
|
||||
if (macroId == m_header.m_macroId)
|
||||
|
@ -290,49 +494,365 @@ bool SoundMacroState::advance(Voice& vox, float dt)
|
|||
int8_t cenKey = cmd.m_data[1];
|
||||
int8_t cenPan = cmd.m_data[2];
|
||||
|
||||
int32_t pan = int32_t(m_midiKey - cenKey) * scale / 127 + cenPan;
|
||||
int32_t pan = int32_t(m_initKey - cenKey) * scale / 127 + cenPan;
|
||||
pan = std::max(-127, std::min(127, pan));
|
||||
vox.setPanning(pan / 127.f);
|
||||
break;
|
||||
}
|
||||
case Op::SetAdsr:
|
||||
{
|
||||
int16_t tableId = *reinterpret_cast<int16_t*>(&cmd.m_data[0]);
|
||||
uint8_t type = cmd.m_data[2];
|
||||
vox.setAdsr(tableId, type);
|
||||
ObjectId tableId = *reinterpret_cast<ObjectId*>(&cmd.m_data[0]);
|
||||
vox.setAdsr(tableId);
|
||||
break;
|
||||
}
|
||||
case Op::ScaleVolume:
|
||||
{
|
||||
int8_t scale = cmd.m_data[0];
|
||||
int8_t add = cmd.m_data[1];
|
||||
int16_t curve = *reinterpret_cast<int16_t*>(&cmd.m_data[2]);
|
||||
ObjectId curve = *reinterpret_cast<ObjectId*>(&cmd.m_data[2]);
|
||||
bool orgVel = cmd.m_data[4];
|
||||
|
||||
int32_t eval = int32_t(orgVel ? m_initVel : m_curVel) * scale / 127 + add;
|
||||
eval = std::max(0, std::min(127, eval));
|
||||
|
||||
if (curve.id != 0)
|
||||
{
|
||||
const Curve* curveData = vox.getAudioGroup().getPool().tableAsCurves(curve);
|
||||
if (curveData)
|
||||
{
|
||||
m_curVol = (*curveData)[eval] / 127.f;
|
||||
m_volDirty = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_curVol = eval / 127.f;
|
||||
m_volDirty = true;
|
||||
break;
|
||||
}
|
||||
case Op::Panning:
|
||||
{
|
||||
int8_t panPos = cmd.m_data[0];
|
||||
int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
int8_t width = cmd.m_data[3];
|
||||
|
||||
m_panningTime = 0.f;
|
||||
m_panningDur = timeMs / 1000.f;
|
||||
m_panPos = panPos;
|
||||
m_panWidth = width;
|
||||
|
||||
break;
|
||||
}
|
||||
case Op::Envelope:
|
||||
{
|
||||
int8_t scale = cmd.m_data[0];
|
||||
int8_t add = cmd.m_data[1];
|
||||
ObjectId curve = *reinterpret_cast<ObjectId*>(&cmd.m_data[2]);
|
||||
bool ms = cmd.m_data[4];
|
||||
int16_t fadeTime = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
|
||||
|
||||
float q = ms ? 1000.f : m_ticksPerSec;
|
||||
float secTime = fadeTime / q;
|
||||
|
||||
int32_t eval = int32_t(m_curVel) * scale / 127 + add;
|
||||
eval = std::max(0, std::min(127, eval));
|
||||
|
||||
m_envelopeTime = 0.f;
|
||||
m_envelopeDur = secTime;
|
||||
m_envelopeStart = m_curVel;
|
||||
m_envelopeEnd = eval;
|
||||
|
||||
if (curve.id != 0)
|
||||
m_envelopeCurve = vox.getAudioGroup().getPool().tableAsCurves(curve);
|
||||
else
|
||||
m_envelopeCurve = nullptr;
|
||||
|
||||
break;
|
||||
}
|
||||
case Op::StartSample:
|
||||
{
|
||||
int16_t smpId = *reinterpret_cast<int16_t*>(&cmd.m_data[0]);
|
||||
int8_t mode = cmd.m_data[2];
|
||||
int32_t offset = *reinterpret_cast<int32_t*>(&cmd.m_data[3]);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case 1:
|
||||
offset = offset * (127 - m_curVel) / 127;
|
||||
break;
|
||||
case 2:
|
||||
offset = offset * m_curVel / 127;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
vox.startSample(smpId, offset);
|
||||
break;
|
||||
}
|
||||
case Op::StopSample:
|
||||
{
|
||||
vox.stopSample();
|
||||
break;
|
||||
}
|
||||
case Op::KeyOff:
|
||||
{
|
||||
vox.keyOff();
|
||||
break;
|
||||
}
|
||||
case Op::SplitRnd:
|
||||
{
|
||||
uint8_t rndVal = cmd.m_data[0];
|
||||
ObjectId macroId = *reinterpret_cast<ObjectId*>(&cmd.m_data[1]);
|
||||
int16_t macroStep = *reinterpret_cast<int16_t*>(&cmd.m_data[3]);
|
||||
|
||||
if (rndVal <= m_random() % 256)
|
||||
{
|
||||
/* Do branch */
|
||||
if (macroId == m_header.m_macroId)
|
||||
m_pc.back() = macroStep;
|
||||
else
|
||||
vox.loadSoundMacro(macroId, macroStep);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case Op::FadeIn:
|
||||
{
|
||||
int8_t scale = cmd.m_data[0];
|
||||
int8_t add = cmd.m_data[1];
|
||||
ObjectId curve = *reinterpret_cast<ObjectId*>(&cmd.m_data[2]);
|
||||
bool ms = cmd.m_data[4];
|
||||
int16_t fadeTime = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
|
||||
|
||||
float q = ms ? 1000.f : m_ticksPerSec;
|
||||
float secTime = fadeTime / q;
|
||||
|
||||
int32_t eval = int32_t(m_curVel) * scale / 127 + add;
|
||||
eval = std::max(0, std::min(127, eval));
|
||||
|
||||
m_envelopeTime = 0.f;
|
||||
m_envelopeDur = secTime;
|
||||
m_envelopeStart = 0.f;
|
||||
m_envelopeEnd = eval;
|
||||
|
||||
if (curve.id != 0)
|
||||
m_envelopeCurve = vox.getAudioGroup().getPool().tableAsCurves(curve);
|
||||
else
|
||||
m_envelopeCurve = nullptr;
|
||||
|
||||
break;
|
||||
}
|
||||
case Op::Spanning:
|
||||
{
|
||||
int8_t panPos = cmd.m_data[0];
|
||||
int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
int8_t width = cmd.m_data[3];
|
||||
|
||||
m_spanningTime = 0.f;
|
||||
m_spanningDur = timeMs / 1000.f;
|
||||
m_spanPos = panPos;
|
||||
m_spanWidth = width;
|
||||
|
||||
break;
|
||||
}
|
||||
case Op::SetAdsrCtrl:
|
||||
{
|
||||
m_useAdsrControllers = true;
|
||||
m_midiAttack = cmd.m_data[0];
|
||||
m_midiDecay = cmd.m_data[1];
|
||||
m_midiSustain = cmd.m_data[2];
|
||||
m_midiRelease = cmd.m_data[3];
|
||||
break;
|
||||
}
|
||||
case Op::RndNote:
|
||||
{
|
||||
int32_t noteLo = int32_t(cmd.m_data[0]);
|
||||
int8_t detune = cmd.m_data[1];
|
||||
int32_t noteHi = int32_t(cmd.m_data[2]);
|
||||
int8_t free = cmd.m_data[3];
|
||||
int8_t rel = cmd.m_data[4];
|
||||
|
||||
if (rel)
|
||||
{
|
||||
noteLo = m_initKey - noteLo;
|
||||
noteHi = noteLo + noteHi;
|
||||
}
|
||||
|
||||
noteLo *= 100;
|
||||
noteHi *= 100;
|
||||
|
||||
m_curKey = m_random() % (noteHi - noteLo) + noteLo;
|
||||
if (!free)
|
||||
m_curKey = m_curKey / 100 * 100 + detune;
|
||||
|
||||
m_pitchDirty = true;
|
||||
break;
|
||||
}
|
||||
case Op::AddNote:
|
||||
{
|
||||
int32_t add = int32_t(cmd.m_data[0]);
|
||||
int8_t detune = cmd.m_data[1];
|
||||
int8_t orgKey = int32_t(cmd.m_data[2]);
|
||||
int8_t ms = cmd.m_data[4];
|
||||
int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
|
||||
|
||||
m_curKey = (orgKey ? m_initKey : m_curKey) + add * 100 + detune;
|
||||
|
||||
/* Set wait state */
|
||||
if (timeMs)
|
||||
{
|
||||
float q = ms ? 1000.f : m_ticksPerSec;
|
||||
float secTime = timeMs / q;
|
||||
m_waitCountdown = secTime;
|
||||
m_inWait = true;
|
||||
}
|
||||
|
||||
m_pitchDirty = true;
|
||||
break;
|
||||
}
|
||||
case Op::SetNote:
|
||||
{
|
||||
int32_t key = int32_t(cmd.m_data[0]);
|
||||
int8_t detune = cmd.m_data[1];
|
||||
int8_t ms = cmd.m_data[4];
|
||||
int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
|
||||
|
||||
m_curKey = key * 100 + detune;
|
||||
|
||||
/* Set wait state */
|
||||
if (timeMs)
|
||||
{
|
||||
float q = ms ? 1000.f : m_ticksPerSec;
|
||||
float secTime = timeMs / q;
|
||||
m_waitCountdown = secTime;
|
||||
m_inWait = true;
|
||||
}
|
||||
|
||||
m_pitchDirty = true;
|
||||
break;
|
||||
}
|
||||
case Op::LastNote:
|
||||
{
|
||||
int32_t add = int32_t(cmd.m_data[0]);
|
||||
int8_t detune = cmd.m_data[1];
|
||||
int8_t ms = cmd.m_data[4];
|
||||
int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
|
||||
|
||||
m_curKey = (add + vox.getLastNote()) * 100 + detune;
|
||||
|
||||
/* Set wait state */
|
||||
if (timeMs)
|
||||
{
|
||||
float q = ms ? 1000.f : m_ticksPerSec;
|
||||
float secTime = timeMs / q;
|
||||
m_waitCountdown = secTime;
|
||||
m_inWait = true;
|
||||
}
|
||||
|
||||
m_pitchDirty = true;
|
||||
break;
|
||||
}
|
||||
case Op::Portamento:
|
||||
{
|
||||
m_portamentoMode = cmd.m_data[0];
|
||||
m_portamentoType = cmd.m_data[1];
|
||||
int8_t ms = cmd.m_data[4];
|
||||
int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
|
||||
|
||||
float q = ms ? 1000.f : m_ticksPerSec;
|
||||
m_portamentoTime = timeMs / q;
|
||||
break;
|
||||
}
|
||||
case Op::Vibrato:
|
||||
{
|
||||
m_vibratoModLevel = m_vibratoLevel = cmd.m_data[0] * 100 + cmd.m_data[1];
|
||||
m_vibratoModWheel = cmd.m_data[2];
|
||||
int8_t ms = cmd.m_data[4];
|
||||
int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
|
||||
|
||||
float q = ms ? 1000.f : m_ticksPerSec;
|
||||
m_vibratoPeriod = timeMs / q;
|
||||
break;
|
||||
}
|
||||
case Op::PitchSweep1:
|
||||
{
|
||||
m_pitchSweep1 = 0;
|
||||
m_pitchSweep1Times = int32_t(cmd.m_data[0]);
|
||||
m_pitchSweep1Add = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
|
||||
int8_t ms = cmd.m_data[4];
|
||||
int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
|
||||
|
||||
/* Set wait state */
|
||||
if (timeMs)
|
||||
{
|
||||
float q = ms ? 1000.f : m_ticksPerSec;
|
||||
float secTime = timeMs / q;
|
||||
m_waitCountdown = secTime;
|
||||
m_inWait = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case Op::PitchSweep2:
|
||||
{
|
||||
m_pitchSweep2 = 0;
|
||||
m_pitchSweep2Times = int32_t(cmd.m_data[0]);
|
||||
m_pitchSweep2Add = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
|
||||
int8_t ms = cmd.m_data[4];
|
||||
int16_t timeMs = *reinterpret_cast<int16_t*>(&cmd.m_data[5]);
|
||||
|
||||
/* Set wait state */
|
||||
if (timeMs)
|
||||
{
|
||||
float q = ms ? 1000.f : m_ticksPerSec;
|
||||
float secTime = timeMs / q;
|
||||
m_waitCountdown = secTime;
|
||||
m_inWait = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case Op::SetPitch:
|
||||
{
|
||||
uint32_t hz = *reinterpret_cast<uint32_t*>(&cmd.m_data[0]) >> 8;
|
||||
uint16_t fine = *reinterpret_cast<uint16_t*>(&cmd.m_data[3]);
|
||||
vox.setPitchFrequency(hz, fine);
|
||||
break;
|
||||
}
|
||||
case Op::SetPitchAdsr:
|
||||
{
|
||||
ObjectId adsr = *reinterpret_cast<ObjectId*>(&cmd.m_data[0]);
|
||||
int8_t keys = cmd.m_data[3];
|
||||
int8_t cents = cmd.m_data[4];
|
||||
vox.setPitchAdsr(adsr, keys * 100 + cents);
|
||||
break;
|
||||
}
|
||||
case Op::ScaleVolumeDLS:
|
||||
{
|
||||
int16_t scale = *reinterpret_cast<int16_t*>(&cmd.m_data[0]);
|
||||
bool orgVel = cmd.m_data[2];
|
||||
m_curVol = int32_t(orgVel ? m_initVel : m_curVel) * scale / 4096.f / 127.f;
|
||||
m_volDirty = true;
|
||||
break;
|
||||
}
|
||||
case Op::Mod2Vibrange:
|
||||
{
|
||||
int8_t keys = cmd.m_data[0];
|
||||
int8_t cents = cmd.m_data[1];
|
||||
m_vibratoModLevel = keys * 100 + cents;
|
||||
break;
|
||||
}
|
||||
case Op::SetupTremolo:
|
||||
{
|
||||
int16_t scale = *reinterpret_cast<int16_t*>(&cmd.m_data[0]);
|
||||
int16_t modScale = *reinterpret_cast<int16_t*>(&cmd.m_data[3]);
|
||||
m_tremoloScale = scale / 4096.f;
|
||||
m_tremoloModScale = modScale / 4096.f;
|
||||
break;
|
||||
}
|
||||
case Op::Return:
|
||||
case Op::GoSub:
|
||||
case Op::TrapEvent:
|
||||
|
@ -347,22 +867,165 @@ bool SoundMacroState::advance(Voice& vox, float dt)
|
|||
case Op::AddPriority:
|
||||
case Op::AgeCntSpeed:
|
||||
case Op::AgeCntVel:
|
||||
break;
|
||||
case Op::VolSelect:
|
||||
{
|
||||
uint8_t ctrl = cmd.m_data[0];
|
||||
int16_t perc = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
LFOSel::Combine combine = LFOSel::Combine(cmd.m_data[3]);
|
||||
LFOSel::VarType vtype = LFOSel::VarType(cmd.m_data[4]);
|
||||
uint8_t fine = cmd.m_data[5];
|
||||
m_volumeSel.addComponent(ctrl, (perc + fine / 100.f) / 100.f, combine, vtype);
|
||||
break;
|
||||
}
|
||||
case Op::PanSelect:
|
||||
{
|
||||
uint8_t ctrl = cmd.m_data[0];
|
||||
int16_t perc = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
LFOSel::Combine combine = LFOSel::Combine(cmd.m_data[3]);
|
||||
LFOSel::VarType vtype = LFOSel::VarType(cmd.m_data[4]);
|
||||
uint8_t fine = cmd.m_data[5];
|
||||
m_panSel.addComponent(ctrl, (perc + fine / 100.f) / 100.f, combine, vtype);
|
||||
break;
|
||||
}
|
||||
case Op::PitchWheelSelect:
|
||||
{
|
||||
uint8_t ctrl = cmd.m_data[0];
|
||||
int16_t perc = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
LFOSel::Combine combine = LFOSel::Combine(cmd.m_data[3]);
|
||||
LFOSel::VarType vtype = LFOSel::VarType(cmd.m_data[4]);
|
||||
uint8_t fine = cmd.m_data[5];
|
||||
m_pitchWheelSel.addComponent(ctrl, (perc + fine / 100.f) / 100.f, combine, vtype);
|
||||
break;
|
||||
}
|
||||
case Op::ModWheelSelect:
|
||||
{
|
||||
uint8_t ctrl = cmd.m_data[0];
|
||||
int16_t perc = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
LFOSel::Combine combine = LFOSel::Combine(cmd.m_data[3]);
|
||||
LFOSel::VarType vtype = LFOSel::VarType(cmd.m_data[4]);
|
||||
uint8_t fine = cmd.m_data[5];
|
||||
m_modWheelSel.addComponent(ctrl, (perc + fine / 100.f) / 100.f, combine, vtype);
|
||||
break;
|
||||
}
|
||||
case Op::PedalSelect:
|
||||
case Op::PortaSelect:
|
||||
{
|
||||
uint8_t ctrl = cmd.m_data[0];
|
||||
int16_t perc = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
LFOSel::Combine combine = LFOSel::Combine(cmd.m_data[3]);
|
||||
LFOSel::VarType vtype = LFOSel::VarType(cmd.m_data[4]);
|
||||
uint8_t fine = cmd.m_data[5];
|
||||
m_pedalSel.addComponent(ctrl, (perc + fine / 100.f) / 100.f, combine, vtype);
|
||||
break;
|
||||
}
|
||||
case Op::PortASelect:
|
||||
{
|
||||
uint8_t ctrl = cmd.m_data[0];
|
||||
int16_t perc = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
LFOSel::Combine combine = LFOSel::Combine(cmd.m_data[3]);
|
||||
LFOSel::VarType vtype = LFOSel::VarType(cmd.m_data[4]);
|
||||
uint8_t fine = cmd.m_data[5];
|
||||
m_portASel.addComponent(ctrl, (perc + fine / 100.f) / 100.f, combine, vtype);
|
||||
break;
|
||||
}
|
||||
case Op::ReverbSelect:
|
||||
{
|
||||
uint8_t ctrl = cmd.m_data[0];
|
||||
int16_t perc = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
LFOSel::Combine combine = LFOSel::Combine(cmd.m_data[3]);
|
||||
LFOSel::VarType vtype = LFOSel::VarType(cmd.m_data[4]);
|
||||
uint8_t fine = cmd.m_data[5];
|
||||
m_reverbSel.addComponent(ctrl, (perc + fine / 100.f) / 100.f, combine, vtype);
|
||||
break;
|
||||
}
|
||||
case Op::SpanSelect:
|
||||
{
|
||||
uint8_t ctrl = cmd.m_data[0];
|
||||
int16_t perc = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
LFOSel::Combine combine = LFOSel::Combine(cmd.m_data[3]);
|
||||
LFOSel::VarType vtype = LFOSel::VarType(cmd.m_data[4]);
|
||||
uint8_t fine = cmd.m_data[5];
|
||||
m_spanSel.addComponent(ctrl, (perc + fine / 100.f) / 100.f, combine, vtype);
|
||||
break;
|
||||
}
|
||||
case Op::DopplerSelect:
|
||||
{
|
||||
uint8_t ctrl = cmd.m_data[0];
|
||||
int16_t perc = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
LFOSel::Combine combine = LFOSel::Combine(cmd.m_data[3]);
|
||||
LFOSel::VarType vtype = LFOSel::VarType(cmd.m_data[4]);
|
||||
uint8_t fine = cmd.m_data[5];
|
||||
m_dopplerSel.addComponent(ctrl, (perc + fine / 100.f) / 100.f, combine, vtype);
|
||||
break;
|
||||
}
|
||||
case Op::TremoloSelect:
|
||||
{
|
||||
uint8_t ctrl = cmd.m_data[0];
|
||||
int16_t perc = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
LFOSel::Combine combine = LFOSel::Combine(cmd.m_data[3]);
|
||||
LFOSel::VarType vtype = LFOSel::VarType(cmd.m_data[4]);
|
||||
uint8_t fine = cmd.m_data[5];
|
||||
m_tremoloSel.addComponent(ctrl, (perc + fine / 100.f) / 100.f, combine, vtype);
|
||||
break;
|
||||
}
|
||||
case Op::PreASelect:
|
||||
{
|
||||
uint8_t ctrl = cmd.m_data[0];
|
||||
int16_t perc = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
LFOSel::Combine combine = LFOSel::Combine(cmd.m_data[3]);
|
||||
LFOSel::VarType vtype = LFOSel::VarType(cmd.m_data[4]);
|
||||
uint8_t fine = cmd.m_data[5];
|
||||
m_preAuxASel.addComponent(ctrl, (perc + fine / 100.f) / 100.f, combine, vtype);
|
||||
break;
|
||||
}
|
||||
case Op::PreBSelect:
|
||||
{
|
||||
uint8_t ctrl = cmd.m_data[0];
|
||||
int16_t perc = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
LFOSel::Combine combine = LFOSel::Combine(cmd.m_data[3]);
|
||||
LFOSel::VarType vtype = LFOSel::VarType(cmd.m_data[4]);
|
||||
uint8_t fine = cmd.m_data[5];
|
||||
m_preAuxBSel.addComponent(ctrl, (perc + fine / 100.f) / 100.f, combine, vtype);
|
||||
break;
|
||||
}
|
||||
case Op::PostBSelect:
|
||||
{
|
||||
uint8_t ctrl = cmd.m_data[0];
|
||||
int16_t perc = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
LFOSel::Combine combine = LFOSel::Combine(cmd.m_data[3]);
|
||||
LFOSel::VarType vtype = LFOSel::VarType(cmd.m_data[4]);
|
||||
uint8_t fine = cmd.m_data[5];
|
||||
m_postAuxB.addComponent(ctrl, (perc + fine / 100.f) / 100.f, combine, vtype);
|
||||
break;
|
||||
}
|
||||
case Op::AuxAFXSelect:
|
||||
{
|
||||
uint8_t ctrl = cmd.m_data[0];
|
||||
int16_t perc = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
LFOSel::Combine combine = LFOSel::Combine(cmd.m_data[3]);
|
||||
LFOSel::VarType vtype = LFOSel::VarType(cmd.m_data[4]);
|
||||
uint8_t fine = cmd.m_data[5];
|
||||
m_auxAFxSel.addComponent(ctrl, (perc + fine / 100.f) / 100.f, combine, vtype);
|
||||
break;
|
||||
}
|
||||
case Op::AuxBFXSelect:
|
||||
{
|
||||
uint8_t ctrl = cmd.m_data[0];
|
||||
int16_t perc = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
LFOSel::Combine combine = LFOSel::Combine(cmd.m_data[3]);
|
||||
LFOSel::VarType vtype = LFOSel::VarType(cmd.m_data[4]);
|
||||
uint8_t fine = cmd.m_data[5];
|
||||
m_auxBFxSel.addComponent(ctrl, (perc + fine / 100.f) / 100.f, combine, vtype);
|
||||
break;
|
||||
}
|
||||
case Op::SetupLFO:
|
||||
{
|
||||
uint8_t number = cmd.m_data[0];
|
||||
int16_t period = *reinterpret_cast<int16_t*>(&cmd.m_data[1]);
|
||||
if (number <= 1)
|
||||
m_lfoPeriods[number] = period / 1000.f;
|
||||
break;
|
||||
}
|
||||
case Op::ModeSelect:
|
||||
case Op::SetKeygroup:
|
||||
case Op::SRCmodeSelect:
|
||||
|
|
|
@ -4,20 +4,23 @@
|
|||
namespace amuse
|
||||
{
|
||||
|
||||
Voice::Voice(Engine& engine, int groupId, int vid, bool emitter)
|
||||
: Entity(engine, groupId), m_vid(vid), m_emitter(emitter)
|
||||
{
|
||||
}
|
||||
Voice::Voice(Engine& engine, const AudioGroup& group, int vid, bool emitter)
|
||||
: Entity(engine, group), m_vid(vid), m_emitter(emitter)
|
||||
{}
|
||||
|
||||
Voice::Voice(Engine& engine, const AudioGroup& group, ObjectId oid, int vid, bool emitter)
|
||||
: Entity(engine, group, oid), m_vid(vid), m_emitter(emitter)
|
||||
{}
|
||||
|
||||
size_t Voice::supplyAudio(size_t frames, int16_t* data)
|
||||
{
|
||||
}
|
||||
|
||||
Voice* Voice::startSiblingMacro(int8_t addNote, int macroId, int macroStep)
|
||||
Voice* Voice::startSiblingMacro(int8_t addNote, ObjectId macroId, int macroStep)
|
||||
{
|
||||
}
|
||||
|
||||
bool Voice::loadSoundMacro(int macroId, int macroStep)
|
||||
bool Voice::loadSoundMacro(ObjectId macroId, int macroStep)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue