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>
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
);
39 void basic_synth::kill_note(int note
, int vel
, bool just_one
)
42 // preserve sostenuto notes
43 if ((*it
)->get_current_note() == note
&& !(sostenuto
&& (*it
)->sostenuto
)) {
51 dsp::voice
*basic_synth::give_voice()
53 if (active_voices
.size() >= polyphony_limit
)
55 if (unused_voices
.empty())
58 dsp::voice
*v
= unused_voices
.pop();
64 void basic_synth::steal_voice()
66 dsp::voice
*found
= NULL
;
67 float priority
= 10000;
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();
78 //printf("Found: %p\n\n", *found);
85 void basic_synth::trim_voices()
87 // count stealable voices
88 unsigned int count
= 0;
91 if ((*i
)->get_priority() < 10000)
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
++)
102 void basic_synth::note_on(int note
, int vel
)
108 bool perc
= check_percussion();
109 dsp::voice
*v
= give_voice();
112 v
->setup(sample_rate
);
114 v
->sostenuto
= false;
116 v
->note_on(note
, vel
);
117 active_voices
.add(v
);
119 percussion_note_on(note
, vel
);
123 void basic_synth::note_off(int note
, int vel
)
127 kill_note(note
, vel
, false);
130 void basic_synth::on_pedal_release()
134 int note
= (*i
)->get_current_note();
135 if (note
< 0 || note
> 127)
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
)
148 else if (!hold
&& !still_held
&& !(*i
)->released
)
150 (*i
)->released
= true;
156 void basic_synth::control_change(int ctl
, int val
)
158 if (ctl
== 64) { // HOLD controller
161 if (!hold
&& prev
&& !sostenuto
) {
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
171 (*i
)->sostenuto
= true;
174 if (!sostenuto
&& prev
) {
175 // SOSTENUTO was released - release all keys which were previously held
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);
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(); ) {
208 v
->render_to(output
, nsamples
);
209 if (!v
->get_active()) {
210 i
= active_voices
.erase(i
);
211 unused_voices
.add(v
);
218 basic_synth::~basic_synth()
220 for (voice_array::iterator i
= allocated_voices
.begin(); i
!= allocated_voices
.end(); ++i
)