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., 59 Temple Place, Suite 330,
20 * Boston, MA 02111-1307, USA.
22 #ifndef __CALF_SYNTH_H
23 #define __CALF_SYNTH_H
28 #include "primitives.h"
34 * A kind of set with fast non-ordered iteration, used for storing lists of pressed keys.
43 memset(states
, 0xFF, sizeof(states
));
47 for (int i
=0; i
<dcount
; i
++)
48 states
[active
[i
]] = 0xFF;
52 assert(key
>= 0 && key
<= 127);
53 if (states
[key
] != 0xFF) {
57 active
[dcount
++] = key
;
61 if (states
[key
] == 0xFF)
63 int pos
= states
[key
];
64 if (pos
!= dcount
-1) {
65 // reuse the popped item's stack position for stack top
66 int last
= active
[dcount
-1];
68 // mark that position's new place on stack
75 inline bool has(int key
) {
76 return states
[key
] != 0xFF;
84 inline int nth(int n
) {
90 * Convert MIDI note number to normalized UINT phase (where 1<<32 is full cycle).
91 * @param MIDI note number
92 * @param cents detune in cents (1/100 of a semitone)
93 * @param sr sample rate
95 inline unsigned int midi_note_to_phase(int note
, double cents
, int sr
) {
96 double incphase
= 440*pow(2.0, (note
-69)/12.0 + cents
/1200.0)/sr
;
97 if (incphase
>= 1.0) incphase
= fmod(incphase
, 1.0);
98 incphase
*= 65536.0*65536.0;
99 return (unsigned int)incphase
;
102 // Base class for all voice objects
106 bool released
, sostenuto
, stolen
;
108 voice() : sample_rate(-1), released(false), sostenuto(false), stolen(false) {}
110 /// reset voice to default state (used when a voice is to be reused)
111 virtual void setup(int sr
) { sample_rate
= sr
; }
112 /// reset voice to default state (used when a voice is to be reused)
113 virtual void reset()=0;
114 /// a note was pressed
115 virtual void note_on(int note
, int vel
)=0;
116 /// a note was released
117 virtual void note_off(int vel
)=0;
118 /// check if voice can be removed from active voice list
119 virtual bool get_active()=0;
120 /// render voice data to buffer
121 virtual void render_to(float (*buf
)[2], int nsamples
)=0;
122 /// very fast note off
123 virtual void steal()=0;
124 /// return the note used by this voice
125 virtual int get_current_note()=0;
126 virtual float get_priority() { return stolen
? 20000 : (released
? 1 : (sostenuto
? 200 : 100)); }
127 /// empty virtual destructor
131 /// An "optimized" voice class using fixed-size processing units
132 /// and fixed number of channels. The drawback is that voice
133 /// control is not sample-accurate, and no modulation input
134 /// is possible, but it should be good enough for most cases
135 /// (like Calf Organ).
137 class block_voice
: public Base
{
140 // enum { Channels = 2 };
141 using Base::Channels
;
142 // enum { BlockSize = 16 };
143 using Base::BlockSize
;
144 // float output_buffer[BlockSize][Channels];
145 using Base::output_buffer
;
146 // void render_block();
147 using Base::render_block
;
148 unsigned int read_ptr
;
152 read_ptr
= BlockSize
;
157 read_ptr
= BlockSize
;
159 virtual void render_to(float (*buf
)[2], int nsamples
)
164 if (read_ptr
== BlockSize
)
169 int ncopy
= std::min
<int>(BlockSize
- read_ptr
, nsamples
- p
);
170 for (int i
= 0; i
< ncopy
; i
++)
171 for (int c
= 0; c
< Channels
; c
++)
172 buf
[p
+ i
][c
] += output_buffer
[read_ptr
+ i
][c
];
179 /// Base class for all kinds of polyphonic instruments, provides
180 /// somewhat reasonable voice management, pedal support - and
181 /// little else. It's implemented as a base class with virtual
182 /// functions, so there's some performance loss, but it shouldn't
184 /// @todo it would make sense to support all notes off controller too
187 /// Current sample rate
191 /// Sostenuto pedal state
193 /// Voices currently playing
194 std::list
<dsp::voice
*> active_voices
;
195 /// Voices allocated, but not used
196 std::stack
<dsp::voice
*> unused_voices
;
197 /// Gate values for all 128 MIDI notes
198 std::bitset
<128> gate
;
199 /// Maximum allocated number of channels
200 unsigned int polyphony_limit
;
202 void kill_note(int note
, int vel
, bool just_one
);
204 virtual void setup(int sr
) {
208 polyphony_limit
= (unsigned)-1;
210 virtual void trim_voices();
211 virtual dsp::voice
*give_voice();
212 virtual dsp::voice
*alloc_voice()=0;
213 virtual dsp::voice
*steal_voice();
214 virtual void render_to(float (*output
)[2], int nsamples
);
215 virtual void note_on(int note
, int vel
);
216 virtual void percussion_note_on(int note
, int vel
) {}
217 virtual void control_change(int ctl
, int val
);
218 virtual void note_off(int note
, int vel
);
219 /// amt = -8192 to 8191
220 virtual void pitch_bend(int amt
) {}
221 virtual void on_pedal_release();
222 virtual bool check_percussion() { return active_voices
.empty(); }
223 virtual ~basic_synth();