SIGSEGV crashes seem fixed (Closes: #1145).
[ahxm.git] / ss_gen.c
blob3f57eeca9f0dcf37212655d89967a84e2930ceb6
1 /*
3 Ann Hell Ex Machina - Music Software
4 Copyright (C) 2003/2007 Angel Ortega <angel@triptico.com>
6 ss_gen.c - Software syntesizer's sound generators
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 http://www.triptico.com
26 #include "config.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <math.h>
33 #include "ahxm.h"
35 /*******************
36 Data
37 ********************/
39 /* maximum number of generators */
40 int ss_gen_num = SS_MAX_GENERATORS;
42 /* generator pool */
43 static struct ss_gen *ss_gen_pool = NULL;
45 /* free generator queue */
46 static struct ss_gen *ss_gen_free_queue = NULL;
49 /*******************
50 Code
51 ********************/
53 static void ss_gen_enqueue(struct ss_gen **q, struct ss_gen *g)
54 /* Enqueues a generator in a generator queue */
56 g->prev = NULL;
57 g->next = *q;
59 if (*q != NULL)
60 (*q)->prev = g;
62 *q = g;
66 void ss_gen_init(void)
67 /* inits the generator pool */
69 int n;
71 ss_gen_pool = (struct ss_gen *) realloc(ss_gen_pool, ss_gen_num *
72 sizeof(struct ss_gen));
74 memset(ss_gen_pool, '\0', ss_gen_num * sizeof(struct ss_gen));
76 /* enqueue all into the free generator queue */
77 for (n = 0; n < ss_gen_num; n++)
78 ss_gen_enqueue(&ss_gen_free_queue, &ss_gen_pool[n]);
82 static struct ss_gen *ss_gen_dequeue(struct ss_gen **q, struct ss_gen *g)
83 /* Dequeues a generator from a generator queue */
85 if (g->prev != NULL)
86 g->prev->next = g->next;
87 else
88 *q = g->next;
90 if (g->next != NULL)
91 g->next->prev = g->prev;
93 return g;
97 static struct ss_gen *ss_gen_pop(struct ss_gen **q)
98 /* gets the first enqueued generator from q */
100 struct ss_gen *g = NULL;
102 if (*q != NULL)
103 g = ss_gen_dequeue(q, *q);
105 return g;
110 * ss_gen_alloc - Allocs and enqueues a generator
111 * @q: queue where the generator will be enqueued
113 * Allocs and enqueues a generator into the @q queue.
115 * The new generator is returned, or NULL if the
116 * generator pool is empty.
118 struct ss_gen *ss_gen_alloc(struct ss_gen **q)
120 struct ss_gen *g;
122 if ((g = ss_gen_pop(&ss_gen_free_queue)) != NULL)
123 ss_gen_enqueue(q, g);
125 return g;
130 * ss_gen_free - Dequeues a generator and frees it
131 * @q: the queue holding the generator
132 * @g: the generator
134 * Dequeues a generator and sends it back to the generator pool.
136 void ss_gen_free(struct ss_gen **q, struct ss_gen *g)
138 ss_gen_enqueue(&ss_gen_free_queue, ss_gen_dequeue(q, g));
143 * ss_gen_sustain - Sets sustain for a generator
144 * @g: the generator
145 * @sustain: sustain time in msecs
147 * Sets sustain for a generator, where @sustain is expressed
148 * in milliseconds.
150 void ss_gen_sustain(struct ss_gen *g, double sustain)
152 g->sustain = MS2F(sustain);
157 * ss_gen_attack - Sets attack for a generator
158 * @g: the generator
159 * @attack: attack time in msecs
161 * Sets attack for a generator, where @attack is expressed
162 * in milliseconds.
164 void ss_gen_attack(struct ss_gen *g, double attack)
166 if ((g->attack = MS2F(attack)) > 0) {
167 /* calculates the delta volume */
168 g->davol = g->vol / (sample_t) g->attack;
170 g->vol = 0.0;
176 * ss_gen_vibrato - Sets vibrato for a generator
177 * @g: the generator
178 * @depth: vibrato depth in msecs
179 * @freq: vibrato frequency
181 * Sets vibrato for a generator, with a @depth expressed in
182 * milliseconds and a frequency @freq expressed in hzs.
184 void ss_gen_vibrato(struct ss_gen *g, double depth, double freq)
186 /* good freq: 6 Hz (0.001) */
187 /* good depth: 1/6 semitone (20, 30 frames) */
189 g->vib_depth = MS2F(depth);
190 g->vib_inc = (6.28 * freq) / (double) ss_frequency;
191 g->vibrato = 0.0;
196 * ss_gen_portamento - Sets portamento for a generator
197 * @g: the generator
198 * @portamento: portamento value
200 * Sets portamento for a generator, where @portamento is an
201 * increment to the internal cursor of the wave. This value must
202 * be very small. Negative values will make the frequency slide
203 * down and positive slide up.
205 void ss_gen_portamento(struct ss_gen *g, double portamento)
207 g->portamento = portamento;
212 * ss_gen_play - Activates a generator.
213 * @g: generator
214 * @freq: frequency of the sound to be generated
215 * @vol: volume
216 * @note_id: note id
217 * @w: the wave
219 * Activates a generator, usually as a response for a 'note on'
220 * message from an upper level. The wave @w holds all the sample
221 * data (PCM data, base frequency, etc.), @freq is the desired
222 * frequency, @vol the volume and @note_id a positive, unique
223 * identifier for the note.
225 void ss_gen_play(struct ss_gen *g, double freq, sample_t vol, int note_id, struct ss_wave *w)
227 /* store data */
228 g->note_id = note_id;
229 g->vol = vol;
230 g->w = w;
232 /* start from the beginning */
233 g->cursor = 0;
235 /* calculate increment */
236 g->inc = freq / w->base_freq;
237 g->inc *= (double) w->s_rate / (double) ss_frequency;
239 /* default sustain, vibrato and portamento */
240 ss_gen_sustain(g, 50.0);
241 ss_gen_attack(g, 0.0);
242 ss_gen_vibrato(g, 0.0, 0.0);
243 ss_gen_portamento(g, 0.0);
248 * ss_gen_release - Releases a generator.
249 * @g: the generator
251 * Releases a generator, usually as a response for a 'note off'
252 * message from an upper level. The generator enters SS_GEN_RELEASED
253 * mode, which starts generating sustain data until it's over.
255 void ss_gen_release(struct ss_gen *g)
257 /* note needs not be tracked anymore */
258 g->note_id = -1;
260 /* calculates the delta volume */
261 g->dsvol = g->vol / (sample_t) g->sustain;
266 * ss_gen_frame - Generates a frame of samples.
267 * @g: the generator
268 * @n_channels: the desired number of channels
269 * @frame: array where the output samples will be stored
271 * Generates a frame of samples from the @g generator, that will be stored
272 * in the @frame array. If @n_channels is greater than the number
273 * of channels the generator has, they are sequentially spread.
275 * Returns non-zero if the generator is stopped and should be freed.
277 int ss_gen_frame(struct ss_gen *g, int n_channels, sample_t frame[])
279 int n, m;
280 int to_free = 0;
281 double v;
282 sample_t l_frame[SS_MAX_CHANNELS];
283 struct ss_wave *w;
285 v = g->cursor;
286 w = g->w;
288 /* process attack */
289 if (g->attack) {
290 g->vol += g->davol;
291 g->attack--;
294 /* process vibrato */
295 if (g->vib_inc) {
296 g->vibrato += g->vib_inc;
297 v += sin(g->vibrato) * g->vib_depth;
300 /* add samples to frame */
301 for (n = 0; n < w->n_channels; n++)
302 l_frame[n] = ss_get_sample(w, n, v) * g->vol;
304 /* spread the frame into n_channels */
305 for (n = w->first_channel, m = 0; n < n_channels; n++, m++) {
306 frame[n] += l_frame[m % w->n_channels];
308 n += w->skip_channels;
311 /* increment pointer */
312 g->cursor += g->inc;
314 /* test loop boundaries */
315 if (g->cursor > w->loop_end) {
316 /* loop mode? */
317 if (w->loop_start < 0)
318 to_free = 1;
319 else
320 g->cursor = w->loop_start;
323 /* process sustain */
324 if (g->note_id == -1) {
325 g->vol -= g->dsvol;
327 if (--g->sustain <= 0)
328 to_free = 1;
331 /* process portamento */
332 g->inc += g->portamento;
334 return to_free;