iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
VoiceAllocator.h
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the iPlug 2 library. Copyright (C) the iPlug 2 developers.
5
6 See LICENSE.txt for more info.
7
8 ==============================================================================
9 */
10
11#pragma once
12
18#include <array>
19#include <vector>
20#include <stdint.h>
21#include <functional>
22#include <bitset>
23//#include <iostream>
24
25#include "IPlugLogger.h"
26#include "IPlugQueue.h"
27
28#include "SynthVoice.h"
29
30BEGIN_IPLUG_NAMESPACE
31
32using namespace voiceControlNames;
33
35{
36 uint8_t mZone;
37 uint8_t mChannel;
38 uint8_t mKey;
39 uint8_t mFlags;
40};
41
42const uint8_t kAllZones = UCHAR_MAX;
43const uint8_t kAllChannels = UCHAR_MAX;
44const uint8_t kAllKeys = UCHAR_MAX;
45
46// flags
47const uint8_t kVoicesBusy = 1 << 0;
48const uint8_t kVoicesMostRecent = 1 << 1;
49const uint8_t kVoicesAll = 1 << 2;
50
51enum EVoiceAction
52{
53 kNullAction = 0,
54 kNoteOnAction,
55 kNoteOffAction,
56 kPitchBendAction,
57 kPressureAction,
58 kTimbreAction,
59 kSustainAction,
60 kControllerAction,
61 kProgramChangeAction
62};
63
71{
72 VoiceAddress mAddress;
73 EVoiceAction mAction;
74 int mControllerNumber;
75 float mValue;
76 int mSampleOffset;
77};
78
79#pragma mark - VoiceAllocator class
80
81class VoiceAllocator final
82{
83public:
84
85 enum EATMode
86 {
87 kATModeChannel = 0,
88 kATModePoly,
89 kNumATModes
90 };
91
92 enum EPolyMode
93 {
94 kPolyModePoly = 0,
95 kPolyModeMono,
96 kNumPolyModes
97 };
98
99 static constexpr int kVoiceMostRecent = 1 << 7;
100
101 // one voice worth of ramp generators
102 using VoiceControlRamps = ControlRampProcessor::ProcessorArray<kNumVoiceControlRamps>;
103
106
107 VoiceAllocator(const VoiceAllocator&) = delete;
108 VoiceAllocator& operator=(const VoiceAllocator&) = delete;
109
110 void Clear();
111
112 void SetSampleRateAndBlockSize(double sampleRate, int blockSize) { mSampleRate = sampleRate; CalcGlideTimesInSamples(); }
113 void SetNoteGlideTime(double t) { mNoteGlideTime = t; CalcGlideTimesInSamples(); }
114 void SetControlGlideTime(double t) { mControlGlideTime = t; CalcGlideTimesInSamples(); }
115
119 void AddVoice(SynthVoice* pv, uint8_t zone);
120
122 void AddEvent(VoiceInputEvent e) { mInputQueue.Push(e); }
123
125 void ProcessEvents(int samples, int64_t sampleTime);
126
128 void SoftKillAllVoices();
129
131 void HardKillAllVoices();
132
133 void SetKeyToPitchFunction(const std::function<float(int)>& fn) {mKeyToPitchFn = fn;}
134
137
138 void ProcessVoices(sample** inputs, sample** outputs, int nInputs, int nOutputs, int startIndex, int blockSize);
139
140 size_t GetNVoices() const {return mVoicePtrs.size();}
141 SynthVoice* GetVoice(int voiceIndex) const {return mVoicePtrs[voiceIndex];}
142 void SetPitchOffset(float offset) { mPitchOffset = offset; }
143
144private:
145 using VoiceBitsArray = std::bitset<UCHAR_MAX>;
146
147 VoiceBitsArray VoicesMatchingAddress(VoiceAddress va);
148
149 void SendControlToVoiceInputs(VoiceBitsArray v, int ctlIdx, float val, int glideSamples);
150 void SendControlToVoicesDirect(VoiceBitsArray v, int ctlIdx, float val);
151 void SendProgramChangeToVoices(VoiceBitsArray v, int pgm);
152
153 void StartVoice(int voiceIdx, int channel, int key, float pitch, float velocity, int sampleOffset, int64_t sampleTime, bool retrig);
154 void StartVoices(VoiceBitsArray voices, int channel, int key, float pitch, float velocity, int sampleOffset, int64_t sampleTime, bool retrig);
155
156 void StopVoice(int voiceIdx, int sampleOffset);
157 void StopVoices(VoiceBitsArray voices, int sampleOffset);
158
159 void CalcGlideTimesInSamples();
160 void ClearVoiceInputs(SynthVoice* pVoice);
161 int FindFreeVoiceIndex(int startIndex) const;
162 int FindVoiceIndexToSteal(int64_t sampleTime) const;
163
164 void NoteOn(VoiceInputEvent e, int64_t sampleTime);
165 void NoteOff(VoiceInputEvent e, int64_t sampleTime);
166
167 IPlugQueue<VoiceInputEvent> mInputQueue{1024};
168
169 std::vector<SynthVoice*> mVoicePtrs;
170 std::vector<std::unique_ptr<VoiceControlRamps>> mVoiceGlides;
171 std::vector<int> mHeldKeys; // The currently physically held keys on the keyboard
172 std::vector<int> mSustainedNotes; // Any notes that are sustained, including those that are physically held
173
174 std::function<float(int)> mKeyToPitchFn;
175 double mPitchOffset{0.};
176
177 double mNoteGlideTime{0.};
178 double mControlGlideTime{0.01};
179 int mNoteGlideSamples{0}; // glide for note-to-note portamento
180 int mControlGlideSamples{0}; // glide for controls including pitch bend
181 double mSampleRate;
182 int mBlockSize;
183
184 bool mRotateVoices{true};
185 int mVoiceRotateIndex{0};
186 bool mSustainPedalDown{false};
187 float mModWheel{0.f};
188 float mMinHeldVelocity{1.f};
189
190public:
191 EPolyMode mPolyMode {kPolyModePoly};
192 EATMode mATMode {kATModeChannel};
193};
194
195END_IPLUG_NAMESPACE
IPlug logging a.k.a tracing functionality.
A VoiceInputEvent describes a change in input to be applied to one more more voices.
A lock-free SPSC queue used to transfer data between threads based on MLQueue.h by Randy Jones based ...
Definition: IPlugQueue.h:32
bool Push(const T &item)
Definition: IPlugQueue.h:57
void HardKillAllVoices()
Stop all voices from making sound immdiately.
void AddEvent(VoiceInputEvent e)
Add a single event to the input queue for the current processing block.
void SendEventToVoices(VoiceInputEvent event)
Send the event to the voices matching its address.
void SoftKillAllVoices()
Turn all voice gates off, allowing any voice envelopes to finish.
void ProcessEvents(int samples, int64_t sampleTime)
Process all input events and generate voice outputs.
void AddVoice(SynthVoice *pv, uint8_t zone)
Add a synth voice to the allocator.
A generic synthesizer voice to be controlled by a voice allocator.
Definition: SynthVoice.h:35