#pragma once #include #include #include #ifdef WITH_BOOST #include #include using boost::container::pmr::polymorphic_allocator; template , class Pred = std::equal_to> using unordered_map = std::unordered_map>>; template , class Pred = std::equal_to> using unordered_multimap = std::unordered_multimap>>; #else using std::pmr::unordered_map; using std::pmr::unordered_multimap; #endif #include #include "nodelib/basics.h" #include "data/node.h" #include "util/mem.h" namespace Xybrid::Data { class CommandPort; class AudioPort; } namespace Xybrid::NodeLib { class ParamReader; /*! * \class InstrumentCore * * Helper class to form the core of an instrument node. * * Not mandatory by any means, but handles all the "standard" commands for you. */ class InstrumentCore { public: class Note { friend class InstrumentCore; InstrumentCore* core = nullptr; void* intern = nullptr; public: uint16_t id; double note = 64.0; // floating point to allow smooth pitch bends double noteAdd = 0.0; double time = 0.0; double volume = 1.0; double pan = 0.0; ADSR adsr; double adsrTime = 0; uint8_t adsrPhase = 0; union { std::array scratch {0.0}; std::array ptr; }; template inline T& scratchAs() { return *(reinterpret_cast(reinterpret_cast(&scratch))); } Note() = default; Note(InstrumentCore*, uint16_t id); double effectiveNote() const; double ampMult() const; }; friend class Note; class Tween { friend class InstrumentCore; public: uint16_t noteId; int16_t ticksLeft = -1; uint8_t flags = 0; double timeStart = 0.0; double timeEnd = 0.0; double valStart = 0.0; double valEnd = 0.0; double* op; Tween(Note&, double*, double val, double time, int16_t ticks = -1); void startTick(Note&, double tickTime); void process(Note&, double smpTime); }; private: // double time; double smpTime; public: double volume = 1.0; double pan = 0.0; unordered_map activeNotes = {16, Util::ralloc}; unordered_multimap activeTweens = {16, Util::ralloc}; std::function paramFilter; std::unordered_map> globalParam; std::unordered_map> localParam; std::function processNote; std::function onNoteOn; std::function onNoteLegato; std::function onNoteOff; std::function onDeleteNote; InstrumentCore() = default; ~InstrumentCore(); inline double globalTime() const { return time; } inline double sampleTime() const { return smpTime; } void release(); void reset(); void process(Data::Node*); void process(Data::CommandPort*, Data::AudioPort* = nullptr); void advanceNote(Note&); void deleteNote(Note&); /// Removes tween matching the specified note and target. void removeTween(Note&, double*); /// Removes all tweens matching the specified note. void removeTweens(Note&); Tween* findTween(Note&, double*); Tween& startTween(Note&, double*, double val, double time, int16_t ticks = -1); }; }