2 * Framework for synthesizer-like plugins. This is based
3 * on my earlier work on Drawbar electric organ emulator.
5 * Copyright (C) 2007 Krzysztof Foltman
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this program; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02111-1307, USA.
36 * A kind of set with fast non-ordered iteration, used for storing lists of pressed keys.
45 memset(states
, 0xFF, sizeof(states
));
49 for (int i
=0; i
<dcount
; i
++)
50 states
[active
[i
]] = 0xFF;
54 assert(key
>= 0 && key
<= 127);
55 if (states
[key
] != 0xFF) {
59 active
[dcount
++] = key
;
63 if (states
[key
] == 0xFF)
65 int pos
= states
[key
];
66 if (pos
!= dcount
-1) {
67 // reuse the popped item's stack position for stack top
68 int last
= active
[dcount
-1];
70 // mark that position's new place on stack
77 inline bool has(int key
) {
78 return states
[key
] != 0xFF;
86 inline int nth(int n
) {
92 * Convert MIDI note number to normalized UINT phase (where 1<<32 is full cycle).
93 * @param MIDI note number
94 * @param cents detune in cents (1/100 of a semitone)
95 * @param sr sample rate
97 inline unsigned int midi_note_to_phase(int note
, double cents
, int sr
) {
98 double incphase
= 440*pow(2.0, (note
-69)/12.0 + cents
/1200.0)/sr
;
99 if (incphase
>= 1.0) incphase
= fmod(incphase
, 1.0);
100 incphase
*= 65536.0*65536.0;
101 return (unsigned int)incphase
;
104 // Base class for all voice objects
108 bool released
, sostenuto
, stolen
;
110 voice() : sample_rate(-1), released(false), sostenuto(false), stolen(false) {}
112 /// reset voice to default state (used when a voice is to be reused)
113 virtual void setup(int sr
) { sample_rate
= sr
; }
114 /// reset voice to default state (used when a voice is to be reused)
115 virtual void reset()=0;
116 /// a note was pressed
117 virtual void note_on(int note
, int vel
)=0;
118 /// a note was released
119 virtual void note_off(int vel
)=0;
120 /// check if voice can be removed from active voice list
121 virtual bool get_active()=0;
122 /// render voice data to buffer
123 virtual void render_to(float (*buf
)[2], int nsamples
)=0;
124 /// very fast note off
125 virtual void steal()=0;
126 /// return the note used by this voice
127 virtual int get_current_note()=0;
128 virtual float get_priority() { return stolen
? 20000 : (released
? 1 : (sostenuto
? 200 : 100)); }
129 /// empty virtual destructor
134 class block_allvoices_base
137 enum { BlockSize
= Base::BlockSize
, MaxSnapshots
= (Base::MaxSampleRun
+ Base::BlockSize
- 1) / Base::BlockSize
+ 1 };
138 unsigned int sample_ctr
;
140 void fill_snapshots(int nsamples
)
144 while(sample_ctr
+ nsamples
>= Base::BlockSize
)
147 nsamples
-= (Base::BlockSize
- sample_ctr
);
150 sample_ctr
+= nsamples
;
152 virtual void make_snapshot(int index
) = 0;
155 /// An "optimized" voice class using fixed-size processing units
156 /// and fixed number of channels. The drawback is that voice
157 /// control is not sample-accurate, and no modulation input
158 /// is possible, but it should be good enough for most cases
159 /// (like Calf Organ).
161 class block_voice
: public Base
{
164 // enum { Channels = 2 };
165 using Base::Channels
;
166 // enum { BlockSize = 16 };
167 using Base::BlockSize
;
168 // float output_buffer[BlockSize][Channels];
169 using Base::output_buffer
;
170 // void render_block();
171 using Base::render_block
;
172 unsigned int read_ptr
;
176 read_ptr
= BlockSize
;
181 read_ptr
= BlockSize
;
183 virtual void render_to(float (*buf
)[2], int nsamples
)
186 int current_snapshot
= 0;
189 if (read_ptr
== BlockSize
)
191 render_block(current_snapshot
);
195 int ncopy
= std::min
<int>(BlockSize
- read_ptr
, nsamples
- p
);
196 for (int i
= 0; i
< ncopy
; i
++)
197 for (int c
= 0; c
< Channels
; c
++)
198 buf
[p
+ i
][c
] += output_buffer
[read_ptr
+ i
][c
];
205 #define for_all_voices(iter) for (dsp::voice **iter = active_voices.begin(); iter != active_voices.end(); iter++)
207 /// A basic preallocated var-array with append and
211 typedef const T
*const_iterator
;
222 void init(int max_count
)
227 items
= new T
[max_count
];
228 alloc_size
= max_count
;
231 T
*begin() { return items
; }
232 T
*end() { return items
+ count
; }
233 const T
*begin() const { return items
; }
234 const T
*end() const { return items
+ count
; }
235 bool empty() const { return count
== 0; }
236 size_t size() const { return count
; }
240 if (count
>= alloc_size
)
246 iterator
erase(iterator iter
)
248 erase(iter
- begin());
253 assert(pos
>= 0 && pos
< count
);
254 if (pos
!= count
- 1)
255 std::swap(items
[count
- 1], items
[pos
]);
262 return items
[--count
];
272 /// Base class for all kinds of polyphonic instruments, provides
273 /// somewhat reasonable voice management, pedal support - and
274 /// little else. It's implemented as a base class with virtual
275 /// functions, so there's some performance loss, but it shouldn't
277 /// @todo it would make sense to support all notes off controller too
280 typedef basic_pool
<dsp::voice
*> voice_array
;
281 /// Current sample rate
285 /// Sostenuto pedal state
287 /// All voices available
288 voice_array allocated_voices
;
289 /// Voices currently playing
290 voice_array active_voices
;
291 /// Voices allocated, but not used
292 voice_array unused_voices
;
293 /// Gate values for all 128 MIDI notes
294 std::bitset
<128> gate
;
295 /// Maximum allocated number of channels
296 unsigned int polyphony_limit
;
298 void init_voices(int count
);
299 void kill_note(int note
, int vel
, bool just_one
);
300 virtual dsp::voice
*alloc_voice() = 0;
302 virtual void setup(int sr
) {
306 polyphony_limit
= (unsigned)-1;
308 virtual void trim_voices();
309 virtual dsp::voice
*give_voice();
310 virtual void steal_voice();
311 virtual void render_to(float (*output
)[2], int nsamples
);
312 virtual void note_on(int note
, int vel
);
313 virtual void percussion_note_on(int note
, int vel
) {}
314 virtual void control_change(int ctl
, int val
);
315 virtual void note_off(int note
, int vel
);
316 /// amt = -8192 to 8191
317 virtual void pitch_bend(int amt
) {}
318 virtual void on_pedal_release();
319 virtual bool check_percussion() { return active_voices
.empty(); }
320 virtual ~basic_synth();