OpenWareLaboratory
PolyphonicProcessor.h
Go to the documentation of this file.
1 #ifndef __PolyphonicProcessor_h__
2 #define __PolyphonicProcessor_h__
3 
4 #include "MidiProcessor.h"
5 #include "SignalGenerator.h"
6 #include "VoiceAllocator.h"
7 
11 template<class SynthVoice, int VOICES>
12 class PolyphonicProcessor : public VoiceAllocator<SynthVoice, VOICES> {
14 protected:
15  static const uint16_t TAKEN = 0xffff;
16  uint8_t notes[VOICES];
17  uint16_t allocation[VOICES];
18  uint16_t allocated;
19 protected:
20  void take(uint8_t ch, MidiMessage msg){
21  release(ch);
22  notes[ch] = msg.getNote();
23  allocation[ch] = TAKEN;
24  Allocator::voice[ch]->noteOn(msg);
25  }
26  void release(uint8_t ch){
27  allocation[ch] = ++allocated;
29  Allocator::voice[ch]->gate(false);
30  }
31 public:
33  virtual ~PolyphonicProcessor(){};
35  size_t active = 0;
36  for(int i=0; i<VOICES; ++i){
37  if(allocation[i] == TAKEN)
38  active++;
39  }
40  return active;
41  }
42  void noteOn(MidiMessage msg){
43  uint8_t note = msg.getNote();
44  uint16_t minval = USHRT_MAX;
45  uint8_t minidx = 0;
46  // take oldest free voice, to allow voices to ring out
47  for(int i=0; i<VOICES; ++i){
48  if(notes[i] == note){
49  minidx = i;
50  break;
51  }
52  if(allocation[i] < minval){
53  minidx = i;
54  minval = allocation[i];
55  }
56  }
57  // take oldest voice
58  take(minidx, msg);
59  }
60  void noteOff(MidiMessage msg){
61  uint8_t note = msg.getNote();
62  for(int i=0; i<VOICES; ++i)
63  // if(notes[i] == note && allocation[i] == TAKEN)
64  if(notes[i] == note)
65  release(i);
66  }
68  for(int i=0; i<VOICES; ++i)
69  Allocator::voice[i]->pitchbend(msg);
70  }
71  void modulate(MidiMessage msg){
72  for(int i=0; i<VOICES; ++i)
73  Allocator::voice[i]->modulate(msg);
74  }
76  // route channel pressure to all voices
77  for(int i=0; i<VOICES; ++i)
78  Allocator::voice[i]->setPressure(msg.getChannelPressure()/128.0f);
79  }
81  // route poly key pressure to the right voice
82  uint8_t note = msg.getNote();
83  for(int i=0; i<VOICES; ++i)
84  if(notes[i] == note)
85  Allocator::voice[i]->setPressure(msg.getPolyKeyPressure()/128.0f);
86  }
87  void sustainOff(){
88  // gate off any sustained (but not active) voices
89  for(int i=0; i<VOICES; ++i){
90  if(allocation[i] != TAKEN)
91  Allocator::voice[i]->gate(false);
92  }
93  }
94 };
95 
96 #endif /* __PolyphonicProcessor_h__ */
uint8_t getPolyKeyPressure()
Definition: MidiMessage.h:75
uint8_t getChannelPressure()
Definition: MidiMessage.h:72
uint8_t getNote()
Definition: MidiMessage.h:60
Supports both Polyphonic Key Pressure and Channel Pressure Aftertouch.
void noteOff(MidiMessage msg)
void take(uint8_t ch, MidiMessage msg)
void modulate(MidiMessage msg)
void pitchbend(MidiMessage msg)
void polyKeyPressure(MidiMessage msg)
static const uint16_t TAKEN
void release(uint8_t ch)
uint16_t allocation[VOICES]
void noteOn(MidiMessage msg)
void channelPressure(MidiMessage msg)
SynthVoice * voice[VOICES]
Definition: VoiceAllocator.h:7