#pragma once #include #include #include #include "nodelib/basics.h" #include "data/node.h" namespace Xybrid::Data { class CommandPort; class AudioPort; } namespace Xybrid::NodeLib { /*! * \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 { double time; double smpTime; public: class Note { friend class InstrumentCore; void* intern = nullptr; public: uint16_t id; double note; // floating point to allow smooth pitch bends double time = 0; double volume = 1.0; double pan = 0.0; ADSR adsr; double adsrTime = 0; uint8_t adsrPhase = 0; std::array scratch{0.0}; Note() = default; Note(uint16_t id); double ampMult() const; }; 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&); }; std::unordered_map activeNotes; std::unordered_multimap activeTweens; std::function processNote; std::function onNoteOn; std::function onNoteLegato; std::function onNoteOff; std::function onDeleteNote; InstrumentCore() = default; inline double globalTime() const { return time; } inline double sampleTime() const { return smpTime; } void reset(); void process(Data::Node*); void process(Data::CommandPort*, Data::AudioPort* = nullptr); void advanceNote(Note&); void deleteNote(Note&); /// Removes tweens matching the specified note and target. void removeTweens(Note&, double*); /// Removes all tweens matching the specified note. void removeTweens(Note&); Tween& startTween(Note&, double*, double val, double time, int16_t ticks = -1); }; }