#ifndef __AMUSE_SOUNDMACROSTATE_HPP__ #define __AMUSE_SOUNDMACROSTATE_HPP__ #include #include #include #include "Entity.hpp" namespace amuse { class Voice; /** Real-time state of SoundMacro execution */ class SoundMacroState { friend class Voice; /** SoundMacro header */ struct Header { uint32_t m_size; ObjectId 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, UntrapEvent, SendMessage, GetMessage, GetVid, AddAgeCount = 0x30, SetAgeCount, SendFlag, PitchWheelR, SetPriority, AddPriority, AgeCntSpeed, AgeCntVel, VolSelect = 0x40, PanSelect, PitchWheelSelect, ModWheelSelect, PedalSelect, PortamentoSelect, 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(); }; /** 'program counter' stack for the active SoundMacro */ std::vector> m_pc; double m_ticksPerSec; /**< ratio for resolving ticks in commands that use them */ 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_curPitch; /**< Current key played for this macro invocation (in cents) */ double m_execTime; /**< time in seconds of SoundMacro execution (per-update resolution) */ 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_indefiniteWait = false; /**< set when timer wait is indefinite (keyoff/sampleend only) */ bool m_keyoffWait = false; /**< set when active wait is a keyoff wait */ bool m_sampleEndWait = false; /**< set when active wait is a sampleend wait */ double m_waitCountdown; /**< countdown timer for active wait */ 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 */ /** Used to build a multi-component formula for overriding controllers */ struct Evaluator { enum class Combine : uint8_t { Set, Add, Mult }; enum class VarType : uint8_t { Ctrl, Var }; /** Represents one term of the 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 m_comps; /**< Components built up by the macro */ /** Combine additional component(s) to formula */ void addComponent(uint8_t midiCtrl, float scale, Combine combine, VarType varType); /** Calculate value */ float evaluate(const Voice& vox, const SoundMacroState& st) const; /** Determine if able to use */ operator bool() const {return m_comps.size() != 0;} }; Evaluator m_volumeSel; Evaluator m_panSel; Evaluator m_pitchWheelSel; Evaluator m_modWheelSel; Evaluator m_pedalSel; Evaluator m_portamentoSel; Evaluator m_reverbSel; Evaluator m_preAuxASel; Evaluator m_preAuxBSel; Evaluator m_auxAFxSel; Evaluator m_auxBFxSel; Evaluator m_postAuxB; Evaluator m_spanSel; Evaluator m_dopplerSel; Evaluator m_tremoloSel; int32_t m_variables[256]; /**< 32-bit variables set with relevant commands */ /** Event registration data for TRAP_EVENT */ struct EventTrap { ObjectId macroId = 0xffff; uint16_t macroStep; }; public: /** initialize state for SoundMacro data at `ptr` */ void initialize(const unsigned char* ptr, int step); void initialize(const unsigned char* ptr, int step, double 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, double dt); /** keyoff event */ void keyoffNotify(Voice& vox); /** sample end event */ void sampleEndNotify(Voice& vox); }; } #endif // __AMUSE_SOUNDMACROSTATE_HPP__