144 lines
4.2 KiB
C++
144 lines
4.2 KiB
C++
#pragma once
|
|
|
|
#include <memory>
|
|
#include <functional>
|
|
#include <unordered_map>
|
|
#ifdef WITH_BOOST
|
|
#include <boost/container/pmr/memory_resource.hpp>
|
|
#include <boost/container/pmr/polymorphic_allocator.hpp>
|
|
using boost::container::pmr::polymorphic_allocator;
|
|
template <class Key,
|
|
class T,
|
|
class Hash = std::hash<Key>,
|
|
class Pred = std::equal_to<Key>>
|
|
using unordered_map = std::unordered_map<Key, T, Hash, Pred, polymorphic_allocator<std::pair<const Key,T>>>;
|
|
template <class Key, class T,
|
|
class Hash = std::hash<Key>,
|
|
class Pred = std::equal_to<Key>>
|
|
using unordered_multimap = std::unordered_multimap<Key, T, Hash, Pred, polymorphic_allocator<std::pair<const Key,T>>>;
|
|
#else
|
|
using std::pmr::unordered_map;
|
|
using std::pmr::unordered_multimap;
|
|
#endif
|
|
#include <array>
|
|
#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<double, 5> scratch {0.0};
|
|
std::array<void*, 5> ptr;
|
|
};
|
|
|
|
template<typename T> inline T& scratchAs() { return *(reinterpret_cast<T*>(reinterpret_cast<void*>(&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<uint16_t, Note> activeNotes = {16, Util::ralloc};
|
|
unordered_multimap<uint16_t, Tween> activeTweens = {16, Util::ralloc};
|
|
|
|
std::function<bool(Note*, const ParamReader&)> paramFilter;
|
|
std::unordered_map<uint8_t, std::function<bool(const ParamReader&)>> globalParam;
|
|
std::unordered_map<uint8_t, std::function<bool(Note&, const ParamReader&)>> localParam;
|
|
|
|
std::function<void(Note&, Data::AudioPort*)> processNote;
|
|
std::function<void(Note&)> onNoteOn;
|
|
std::function<void(Note&)> onNoteLegato;
|
|
std::function<void(Note&, bool)> onNoteOff;
|
|
std::function<void(Note&)> 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);
|
|
|
|
};
|
|
}
|