+ Framework: factor gridline drawing out of Filter, Filterclavier, Phaser and Flanger...
[calf.git] / src / synth.cpp
blob5b7518b4f5190249b192234d8122abf2169a7c0c
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., 59 Temple Place, Suite 330,
19 * Boston, MA 02111-1307, USA.
21 #include <config.h>
22 #include <assert.h>
23 #include <memory.h>
24 #if USE_JACK
25 #include <jack/jack.h>
26 #endif
27 #include <calf/giface.h>
28 #include <calf/synth.h>
30 using namespace dsp;
31 using namespace std;
33 void basic_synth::kill_note(int note, int vel, bool just_one)
35 for (list<dsp::voice *>::iterator it = active_voices.begin(); it != active_voices.end(); it++) {
36 // preserve sostenuto notes
37 if ((*it)->get_current_note() == note && !(sostenuto && (*it)->sostenuto)) {
38 (*it)->note_off(vel);
39 if (just_one)
40 return;
45 dsp::voice *basic_synth::give_voice()
47 if (active_voices.size() >= polyphony_limit)
49 dsp::voice *stolen = steal_voice();
50 if (stolen)
51 return stolen;
53 if (unused_voices.empty())
54 return alloc_voice();
55 else {
56 dsp::voice *v = unused_voices.top();
57 unused_voices.pop();
58 v->reset();
59 return v;
63 dsp::voice *basic_synth::steal_voice()
65 std::list<dsp::voice *>::iterator found = active_voices.end();
66 float priority = 10000;
67 for(std::list<dsp::voice *>::iterator i = active_voices.begin(); i != active_voices.end(); i++)
69 if ((*i)->get_priority() < priority)
71 priority = (*i)->get_priority();
72 found = i;
75 if (found == active_voices.end())
76 return NULL;
78 (*found)->steal();
79 return NULL;
82 void basic_synth::trim_voices()
84 // count stealable voices
85 unsigned int count = 0;
86 for(std::list<dsp::voice *>::iterator i = active_voices.begin(); i != active_voices.end(); i++)
88 if ((*i)->get_priority() < 10000)
89 count++;
91 // printf("Count=%d limit=%d\n", count, polyphony_limit);
92 // steal any voices above polyphony limit
93 if (count > polyphony_limit) {
94 for (unsigned int i = 0; i < count - polyphony_limit; i++)
95 steal_voice();
99 void basic_synth::note_on(int note, int vel)
101 if (!vel) {
102 note_off(note, 0);
103 return;
105 bool perc = check_percussion();
106 dsp::voice *v = give_voice();
107 v->setup(sample_rate);
108 v->released = false;
109 v->sostenuto = false;
110 gate.set(note);
111 v->note_on(note, vel);
112 active_voices.push_back(v);
113 if (perc) {
114 percussion_note_on(note, vel);
118 void basic_synth::note_off(int note, int vel)
120 gate.reset(note);
121 if (!hold)
122 kill_note(note, vel, false);
125 #define for_all_voices(iter) for (std::list<dsp::voice *>::iterator iter = active_voices.begin(); iter != active_voices.end(); iter++)
127 void basic_synth::on_pedal_release()
129 for_all_voices(i)
131 int note = (*i)->get_current_note();
132 if (note < 0 || note > 127)
133 continue;
134 bool still_held = gate[note];
135 // sostenuto pedal released
136 if ((*i)->sostenuto && !sostenuto)
138 // mark note as non-sostenuto
139 (*i)->sostenuto = false;
140 // 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)
141 // if key has been released and hold pedal is not depressed, release the note
142 if (!still_held && !hold)
143 (*i)->note_off(127);
145 else if (!hold && !still_held && !(*i)->released)
147 (*i)->released = true;
148 (*i)->note_off(127);
153 void basic_synth::control_change(int ctl, int val)
155 if (ctl == 64) { // HOLD controller
156 bool prev = hold;
157 hold = (val >= 64);
158 if (!hold && prev && !sostenuto) {
159 on_pedal_release();
162 if (ctl == 66) { // SOSTENUTO controller
163 bool prev = sostenuto;
164 sostenuto = (val >= 64);
165 if (sostenuto && !prev) {
166 // SOSTENUTO was pressed - move all notes onto sustain stack
167 for_all_voices(i) {
168 (*i)->sostenuto = true;
171 if (!sostenuto && prev) {
172 // SOSTENUTO was released - release all keys which were previously held
173 on_pedal_release();
176 if (ctl == 123 || ctl == 120) { // all notes off, all sounds off
177 vector<int> notes;
178 notes.reserve(128);
179 if (ctl == 120) { // for "all sounds off", automatically release hold and sostenuto pedal
180 control_change(66, 0);
181 control_change(64, 0);
183 for_all_voices(i)
185 if (ctl == 123)
186 (*i)->note_off(127);
187 else
188 (*i)->steal();
191 if (ctl == 121) {
192 control_change(1, 0);
193 control_change(7, 100);
194 control_change(10, 64);
195 control_change(11, 127);
196 // release hold..hold2
197 for (int i = 64; i <= 69; i++)
198 control_change(i, 0);
202 void basic_synth::render_to(float (*output)[2], int nsamples)
204 // render voices, eliminate ones that aren't sounding anymore
205 for (list<dsp::voice *>::iterator i = active_voices.begin(); i != active_voices.end();) {
206 dsp::voice *v = *i;
207 v->render_to(output, nsamples);
208 if (!v->get_active()) {
209 i = active_voices.erase(i);
210 unused_voices.push(v);
211 continue;
213 i++;
217 basic_synth::~basic_synth()
219 while(!unused_voices.empty()) {
220 delete unused_voices.top();
221 unused_voices.pop();
223 for (list<voice *>::iterator i = active_voices.begin(); i != active_voices.end(); i++)
224 delete *i;