Make Analyzer UI require instance-access
[calf.git] / src / synth.cpp
bloba1f47d68efa532995d27ae5f519aed7e64de1246
1 /* Calf DSP Library
2 * Generic polyphonic synthesizer framework.
4 * Copyright (C) 2007 Krzysztof Foltman
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
21 #include <calf/synth.h>
23 using namespace dsp;
24 using namespace std;
26 void basic_synth::init_voices(int count)
28 allocated_voices.init(count);
29 active_voices.init(count);
30 unused_voices.init(count);
31 for (int i = 0; i < count; i++)
33 dsp::voice *v = alloc_voice();
34 allocated_voices.add(v);
35 unused_voices.add(v);
39 void basic_synth::kill_note(int note, int vel, bool just_one)
41 for_all_voices(it) {
42 // preserve sostenuto notes
43 if ((*it)->get_current_note() == note && !(sostenuto && (*it)->sostenuto)) {
44 (*it)->note_off(vel);
45 if (just_one)
46 return;
51 dsp::voice *basic_synth::give_voice()
53 if (active_voices.size() >= polyphony_limit)
54 steal_voice();
55 if (unused_voices.empty())
56 return NULL;
57 else {
58 dsp::voice *v = unused_voices.pop();
59 v->reset();
60 return v;
64 void basic_synth::steal_voice()
66 dsp::voice *found = NULL;
67 float priority = 10000;
68 //int idx = 0;
69 for_all_voices(i)
71 //printf("Voice %d priority %f at %p\n", idx++, (*i)->get_priority(), *i);
72 if ((*i)->get_priority() < priority)
74 priority = (*i)->get_priority();
75 found = *i;
78 //printf("Found: %p\n\n", *found);
79 if (!found)
80 return;
82 found->steal();
85 void basic_synth::trim_voices()
87 // count stealable voices
88 unsigned int count = 0;
89 for_all_voices(i)
91 if ((*i)->get_priority() < 10000)
92 count++;
94 // printf("Count=%d limit=%d\n", count, polyphony_limit);
95 // steal any voices above polyphony limit
96 if (count > polyphony_limit) {
97 for (unsigned int i = 0; i < count - polyphony_limit; i++)
98 steal_voice();
102 void basic_synth::note_on(int note, int vel)
104 if (!vel) {
105 note_off(note, 0);
106 return;
108 bool perc = check_percussion();
109 dsp::voice *v = give_voice();
110 if (!v)
111 return;
112 v->setup(sample_rate);
113 v->released = false;
114 v->sostenuto = false;
115 gate.set(note);
116 v->note_on(note, vel);
117 active_voices.add(v);
118 if (perc) {
119 percussion_note_on(note, vel);
123 void basic_synth::note_off(int note, int vel)
125 gate.reset(note);
126 if (!hold)
127 kill_note(note, vel, false);
130 void basic_synth::on_pedal_release()
132 for_all_voices(i)
134 int note = (*i)->get_current_note();
135 if (note < 0 || note > 127)
136 continue;
137 bool still_held = gate[note];
138 // sostenuto pedal released
139 if ((*i)->sostenuto && !sostenuto)
141 // mark note as non-sostenuto
142 (*i)->sostenuto = false;
143 // if key still pressed or hold pedal used, hold the note (as non-sostenuto so it can be released later by releasing the key or pedal)
144 // if key has been released and hold pedal is not depressed, release the note
145 if (!still_held && !hold)
146 (*i)->note_off(127);
148 else if (!hold && !still_held && !(*i)->released)
150 (*i)->released = true;
151 (*i)->note_off(127);
156 void basic_synth::control_change(int ctl, int val)
158 if (ctl == 64) { // HOLD controller
159 bool prev = hold;
160 hold = (val >= 64);
161 if (!hold && prev && !sostenuto) {
162 on_pedal_release();
165 if (ctl == 66) { // SOSTENUTO controller
166 bool prev = sostenuto;
167 sostenuto = (val >= 64);
168 if (sostenuto && !prev) {
169 // SOSTENUTO was pressed - move all notes onto sustain stack
170 for_all_voices(i) {
171 (*i)->sostenuto = true;
174 if (!sostenuto && prev) {
175 // SOSTENUTO was released - release all keys which were previously held
176 on_pedal_release();
179 if (ctl == 123 || ctl == 120) { // all notes off, all sounds off
180 if (ctl == 120) { // for "all sounds off", automatically release hold and sostenuto pedal
181 control_change(66, 0);
182 control_change(64, 0);
184 for_all_voices(i)
186 if (ctl == 123)
187 (*i)->note_off(127);
188 else
189 (*i)->steal();
192 if (ctl == 121) {
193 control_change(1, 0);
194 control_change(7, 100);
195 control_change(10, 64);
196 control_change(11, 127);
197 // release hold..hold2
198 for (int i = 64; i <= 69; i++)
199 control_change(i, 0);
203 void basic_synth::render_to(float (*output)[2], int nsamples)
205 // render voices, eliminate ones that aren't sounding anymore
206 for (dsp::voice **i = active_voices.begin(); i != active_voices.end(); ) {
207 dsp::voice *v = *i;
208 v->render_to(output, nsamples);
209 if (!v->get_active()) {
210 i = active_voices.erase(i);
211 unused_voices.add(v);
212 continue;
214 i++;
218 basic_synth::~basic_synth()
220 for (voice_array::iterator i = allocated_voices.begin(); i != allocated_voices.end(); ++i)
221 delete *i;