OpenWareLaboratory
VoiceAllocator.h
Go to the documentation of this file.
1 #ifndef __VoiceAllocator_h__
2 #define __VoiceAllocator_h__
3 
4 template<class SynthVoice, int VOICES>
5 class VoiceAllocator : public MidiProcessor {
6 protected:
7  SynthVoice* voice[VOICES];
8  float pb_range = 2/8192.0f;
9  float mod_range = 0.5/127.0f;
10  bool dosustain = false;
11  uint16_t rpn_id = 0;
12  uint8_t rpn_msb = 0;
13  uint8_t tuning_semitones = 69;
14  static float noteToFrequency(float note){
15  return 440 * exp2f((note - 69) / 12);
16  }
17  static float frequencyToNote(float freq){
18  return 12 * log2f(freq / 440) + 69;
19  }
20 public:
22  return voice[0]->getPitchBendRange();
23  }
28  void setPitchBendRange(float range){
29  for(int i=0; i<VOICES; ++i)
30  voice[i]->setPitchBendRange(range);
31  }
35  void setModulationDepthRange(float range){
36  for(int i=0; i<VOICES; ++i)
37  voice[i]->setModulationDepthRange(range);
38  }
42  void setDynamicRange(float range){
43  for(int i=0; i<VOICES; ++i)
44  voice[i]->setDynamicRange(range);
45  }
46  float getTuning(){
47  return voice[0]->getTuning();
48  }
49  void setTuning(float frequency){
50  for(int i=0; i<VOICES; ++i)
51  voice[i]->setTuning(frequency);
52  }
53  void allNotesOff() {
54  for(int i=0; i<VOICES; ++i)
55  voice[i]->gate(false);
56  }
57  // todo: unison note on/off
58  void allNotesOn() {
59  for(int i=0; i<VOICES; ++i)
60  voice[i]->gate(true);
61  }
62  void setVoice(size_t index, SynthVoice* obj){
63  if(index < VOICES)
64  voice[index] = obj;
65  }
66  SynthVoice* getVoice(size_t index){
67  if(index < VOICES)
68  return voice[index];
69  return NULL;
70  }
71  void setParameter(uint8_t parameter_id, float value){
72  for(int i=0; i<VOICES; ++i)
73  voice[i]->setParameter(parameter_id, value);
74  }
75  void sustain(MidiMessage msg){
76  setSustain(msg.getControllerValue() > 63);
77  }
78  bool getSustain(){
79  return dosustain;
80  }
81  void setSustain(bool value){
82  if(value != dosustain && !value)
83  sustainOff();
84  dosustain = value;
85  }
86  virtual void sustainOff(){}
87  void rpn(uint16_t id, uint8_t msb, uint8_t lsb, MidiMessage msg){
88  switch(id){
90  float semitones = msb + lsb/100.0f; // semitones and cents
91  setPitchBendRange(semitones);
92  break;
93  }
94  case MIDI_RPN_FINE_TUNING: {
95  // The MSB and LSB together form a 14-bit value that sets the tuning in semitones,
96  // with a +/- 1 semitone range, where 0x2000 is A440 tuning
97  // MIDI note 69 is Middle A, 440Hz concert pitch
98  float semitones = tuning_semitones + (((msb << 7) | lsb) - 8192) / 8192.0f;
99  setTuning(noteToFrequency(semitones));
100  break;
101  }
102  case MIDI_RPN_COARSE_TUNING: {
103  // Setting the coarse tuning adjusts the tuning in semitones, where 0x40 is A440 tuning.
104  // Setting coarse tuning resets fine tuning.
105  // Only the coarse data entry / MSB is used.
106  tuning_semitones = 69 + msb - 0x40;
108  break;
109  }
111  setModulationDepthRange(((msb << 7) | lsb) / 16384.0f);
112  break;
113  }
114  }
115  }
117  switch(msg.getControllerNumber()){
118  case MIDI_CC_MODULATION:
119  modulate(msg);
120  break;
121  case MIDI_CC_SUSTAIN:
122  sustain(msg);
123  break;
124  case MIDI_ALL_NOTES_OFF:
125  allNotesOff();
126  break;
127  // case MIDI_CC_DATA_INCR: // Data Button Increment
128  // case MIDI_CC_DATA_DECR: // Data Button Decrement
129  case MIDI_CC_RPN_LSB: // RPN LSB comes first
130  rpn_id = msg.getControllerValue();
131  break;
132  case MIDI_CC_RPN_MSB: // Then comes RPN MSB
133  rpn_id |= msg.getControllerValue() << 7;
134  if(rpn_id == MIDI_RPN_RESET){ // RPN reset
135  rpn_id = 0;
136  rpn_msb = 0;
137  }
138  break;
139  case MIDI_CC_DATAENTRY_MSB: // Data Entry MSB
140  rpn_msb = msg.getControllerValue();
141  rpn(rpn_id, rpn_msb, 0, msg); // call rpn callback with zero LSB
142  break;
143  case MIDI_CC_DATAENTRY_LSB: // Data Entry LSB
144  rpn(rpn_id, rpn_msb, msg.getControllerValue(), msg);
145  break;
146  }
147  }
148 };
149 
150 template<class Allocator, class SynthVoice, int VOICES>
151 class VoiceAllocatorSignalGenerator : public Allocator, public SignalGenerator {
152  static_assert(std::is_base_of<VoiceAllocator<SynthVoice, VOICES>, Allocator>::value, "Allocator must derive from VoiceAllocator");
154 protected:
156 public:
157  template <typename... Args>
159  Allocator(std::forward<Args>(args)...), buffer(buffer) {}
161  float generate(){
162  float sample = this->voice[0]->generate();
163  for(int i=1; i<VOICES; ++i)
164  sample += this->voice[i]->generate();
165  return sample;
166  }
167  void generate(FloatArray output){
168  this->voice[0]->generate(output);
169  for(int i=1; i<VOICES; ++i){
170  this->voice[i]->generate(buffer);
171  output.add(buffer);
172  }
173  }
174  static MyClass* create(size_t blocksize){
175  FloatArray buffer = FloatArray::create(blocksize);
176  return new MyClass(buffer);
177  }
178  static void destroy(MyClass* obj){
180  delete obj;
181  }
182 };
183 
184 template<class Allocator, class SynthVoice, int VOICES>
185 class VoiceAllocatorSignalProcessor : public Allocator, public SignalProcessor {
186  static_assert(std::is_base_of<VoiceAllocator<SynthVoice, VOICES>, Allocator>::value, "Allocator must derive from VoiceAllocator");
188 protected:
190 public:
191  template <typename... Args>
193  Allocator(std::forward<Args>(args)...), buffer(buffer) {}
196  float process(float input){
197  float sample = 0;
198  for(int i=0; i<VOICES; ++i)
199  sample += this->voice[i]->process(input);
200  return sample;
201  }
202  void process(FloatArray input, FloatArray output){
203  for(int i=0; i<VOICES; ++i){
204  this->voice[i]->process(input, buffer);
205  output.add(buffer);
206  }
207  }
208  static MyClass* create(size_t blocksize){
209  FloatArray buffer = FloatArray::create(blocksize);
210  return new MyClass(buffer);
211  }
212  static void destroy(MyClass* obj){
214  delete obj;
215  }
216 };
217 
218 template<class Allocator, class SynthVoice, int VOICES>
220  static_assert(std::is_base_of<VoiceAllocator<SynthVoice, VOICES>, Allocator>::value, "Allocator must derive from VoiceAllocator");
222 protected:
224 public:
225  template <typename... Args>
227  Allocator(std::forward<Args>(args)...), buffer(buffer) {}
229  void generate(AudioBuffer& output){
230  this->voice[0]->generate(output);
231  for(int i=1; i<VOICES; ++i){
232  this->voice[i]->generate(*buffer);
233  output.add(*buffer);
234  }
235  }
236  static MyClass* create(size_t channels, size_t blocksize){
237  AudioBuffer* buffer = AudioBuffer::create(channels, blocksize);
238  return new MyClass(buffer);
239  }
240  static void destroy(MyClass* obj){
242  delete obj;
243  }
244 };
245 
246 template<class Allocator, class SynthVoice, int VOICES>
248  static_assert(std::is_base_of<VoiceAllocator<SynthVoice, VOICES>, Allocator>::value, "Allocator must derive from VoiceAllocator");
250 protected:
252 public:
253  template <typename... Args>
255  Allocator(std::forward<Args>(args)...), buffer(buffer) {}
258  void process(AudioBuffer& input, AudioBuffer& output){
259  for(int i=0; i<VOICES; ++i){
260  this->voice[i]->process(input, *buffer);
261  output.add(*buffer);
262  }
263  }
264  static MyClass* create(size_t channels, size_t blocksize){
265  AudioBuffer* buffer = AudioBuffer::create(channels, blocksize);
266  return new MyClass(buffer);
267  }
268  static void destroy(MyClass* obj){
270  delete obj;
271  }
272 };
273 
274 
275 #endif /* __VoiceAllocator_h__ */
@ MIDI_RPN_PITCH_BEND_RANGE
Definition: MidiStatus.h:93
@ MIDI_RPN_COARSE_TUNING
Definition: MidiStatus.h:95
@ MIDI_RPN_MODULATION_DEPTH_RANGE
Definition: MidiStatus.h:96
@ MIDI_RPN_FINE_TUNING
Definition: MidiStatus.h:94
@ MIDI_RPN_RESET
Definition: MidiStatus.h:98
@ MIDI_ALL_NOTES_OFF
Definition: MidiStatus.h:57
@ MIDI_CC_SUSTAIN
Definition: MidiStatus.h:46
@ MIDI_CC_DATAENTRY_LSB
Definition: MidiStatus.h:45
@ MIDI_CC_MODULATION
Definition: MidiStatus.h:36
@ MIDI_CC_DATAENTRY_MSB
Definition: MidiStatus.h:38
@ MIDI_CC_RPN_LSB
Definition: MidiStatus.h:52
@ MIDI_CC_RPN_MSB
Definition: MidiStatus.h:53
static AudioBuffer * create(int channels, int samples)
void add(float scalar)
Definition: AudioBuffer.h:17
static void destroy(AudioBuffer *buffer)
This class contains useful methods for manipulating arrays of floats.
Definition: FloatArray.h:12
void add(FloatArray operand2, FloatArray destination)
Element-wise sum between arrays.
Definition: FloatArray.cpp:231
static void destroy(FloatArray array)
Destroys a FloatArray created with the create() method.
Definition: FloatArray.cpp:472
static FloatArray create(int size)
Creates a new FloatArray.
Definition: FloatArray.cpp:466
uint8_t getControllerValue()
Definition: MidiMessage.h:69
uint8_t getControllerNumber()
Definition: MidiMessage.h:66
Base class for MIDI processors such as AbstractSynth.
Definition: MidiProcessor.h:11
virtual void modulate(MidiMessage msg)
Definition: MidiProcessor.h:17
virtual void process(MidiMessage msg)
Definition: MidiProcessor.h:22
Base class for signal generators such as Oscillators.
Base class for signal processors such as Filters.
static void destroy(MyClass *obj)
static MyClass * create(size_t channels, size_t blocksize)
void generate(AudioBuffer &output)
VoiceAllocatorMultiSignalGenerator(AudioBuffer *buffer, Args &&... args)
static MyClass * create(size_t channels, size_t blocksize)
VoiceAllocatorMultiSignalProcessor(AudioBuffer *buffer, Args &&... args)
static void destroy(MyClass *obj)
void process(AudioBuffer &input, AudioBuffer &output)
VoiceAllocatorSignalGenerator(FloatArray buffer, Args &&... args)
static void destroy(MyClass *obj)
float generate()
Produce the next consecutive sample.
void generate(FloatArray output)
Produce a block of samples.
static MyClass * create(size_t blocksize)
static void destroy(MyClass *obj)
virtual void process(MidiMessage msg)
Definition: MidiProcessor.h:22
VoiceAllocatorSignalProcessor(FloatArray buffer, Args &&... args)
static MyClass * create(size_t blocksize)
void process(FloatArray input, FloatArray output)
void setSustain(bool value)
SynthVoice * voice[VOICES]
Definition: VoiceAllocator.h:7
void sustain(MidiMessage msg)
uint8_t tuning_semitones
SynthVoice * getVoice(size_t index)
virtual void sustainOff()
void setPitchBendRange(float range)
Set pitch bend range in semitones.
float getPitchBendRange()
void setVoice(size_t index, SynthVoice *obj)
void controlChange(MidiMessage msg)
void setDynamicRange(float range)
Set the MIDI velocity dynamic range in dB, default 72dB.
void setModulationDepthRange(float range)
Set modulation depth range, from 0 to 1.0.
static float frequencyToNote(float freq)
void rpn(uint16_t id, uint8_t msb, uint8_t lsb, MidiMessage msg)
void setTuning(float frequency)
static float noteToFrequency(float note)
void setParameter(uint8_t parameter_id, float value)