Wavetable: add pitchbend support, key follow mod source and pitch mod destination
[calf.git] / src / calf / synth.h
blobfbd90a5098a03323114490e38025170ffacd5d65
1 /* Calf DSP Library
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.
22 #ifndef CALF_SYNTH_H
23 #define CALF_SYNTH_H
25 #include <assert.h>
26 #include <math.h>
27 #include <memory.h>
28 #include <stdint.h>
29 #include <bitset>
30 #include <list>
31 #include <stack>
33 namespace dsp {
35 /**
36 * A kind of set with fast non-ordered iteration, used for storing lists of pressed keys.
38 class keystack {
39 private:
40 int dcount;
41 uint8_t active[128];
42 uint8_t states[128];
43 public:
44 keystack() {
45 memset(states, 0xFF, sizeof(states));
46 dcount = 0;
48 void clear() {
49 for (int i=0; i<dcount; i++)
50 states[active[i]] = 0xFF;
51 dcount = 0;
53 bool push(int key) {
54 assert(key >= 0 && key <= 127);
55 if (states[key] != 0xFF) {
56 return true;
58 states[key] = dcount;
59 active[dcount++] = key;
60 return false;
62 bool pop(int key) {
63 if (states[key] == 0xFF)
64 return false;
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];
69 active[pos] = last;
70 // mark that position's new place on stack
71 states[last] = pos;
73 states[key] = 0xFF;
74 dcount--;
75 return true;
77 inline bool has(int key) {
78 return states[key] != 0xFF;
80 inline int count() {
81 return dcount;
83 inline bool empty() {
84 return (dcount == 0);
86 inline int nth(int n) {
87 return active[n];
91 /**
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
105 class voice {
106 public:
107 int sample_rate;
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
130 virtual ~voice() {}
133 template<class Base>
134 class block_allvoices_base
136 public:
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)
142 int s = 0;
143 make_snapshot(s++);
144 while(sample_ctr + nsamples >= Base::BlockSize)
146 make_snapshot(s++);
147 nsamples -= (Base::BlockSize - sample_ctr);
148 sample_ctr = 0;
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).
160 template<class Base>
161 class block_voice: public Base {
162 public:
163 // derived from 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;
174 block_voice()
176 read_ptr = BlockSize;
178 virtual void reset()
180 Base::reset();
181 read_ptr = BlockSize;
183 virtual void render_to(float (*buf)[2], int nsamples)
185 int p = 0;
186 int current_snapshot = 0;
187 while(p < nsamples)
189 if (read_ptr == BlockSize)
191 render_block(current_snapshot);
192 current_snapshot++;
193 read_ptr = 0;
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];
199 p += ncopy;
200 read_ptr += ncopy;
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
208 template<class T>
209 struct basic_pool {
210 typedef T *iterator;
211 typedef const T *const_iterator;
212 T *items;
213 int count;
214 int alloc_size;
216 basic_pool()
217 : items()
218 , count()
219 , alloc_size()
222 void init(int max_count)
224 assert(!items);
225 assert(!count);
226 assert(!alloc_size);
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; }
238 bool add(T v)
240 if (count >= alloc_size)
241 return false;
242 items[count++] = v;
243 return true;
246 iterator erase(iterator iter)
248 erase(iter - begin());
249 return iter;
251 void erase(int pos)
253 assert(pos >= 0 && pos < count);
254 if (pos != count - 1)
255 std::swap(items[count - 1], items[pos]);
256 count--;
257 items[count] = T();
260 T pop() {
261 if (count)
262 return items[--count];
263 else
264 return NULL;
267 ~basic_pool()
269 delete []items;
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
276 /// be horrible.
277 /// @todo it would make sense to support all notes off controller too
278 struct basic_synth {
279 protected:
280 typedef basic_pool<dsp::voice *> voice_array;
281 /// Current sample rate
282 int sample_rate;
283 /// Hold pedal state
284 bool hold;
285 /// Sostenuto pedal state
286 bool sostenuto;
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;
301 public:
302 virtual void setup(int sr) {
303 sample_rate = sr;
304 hold = false;
305 sostenuto = false;
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();
325 #endif