Got rid of SS_GEN_ZOMBIE (untested).
[ahxm.git] / ss_gen.c
blob42bf83827af71821cad5c854774f66c41b8864f6
1 /*
3 Ann Hell Ex Machina - Music Software
4 Copyright (C) 2003 Angel Ortega <angel@triptico.com>
6 generator.c - Software syntesizer's sound generator
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>
32 #include "core.h"
33 #include "generator.h"
35 /*******************
36 Data
37 ********************/
39 /* number of generators */
40 int _ss_gen_num=SS_GEN_NUM;
42 /* generator poll */
43 struct ss_gen * _ss_gen_poll=NULL;
46 /*******************
47 Code
48 ********************/
50 struct ss_gen * _ss_gen_get_free(void)
52 int n;
54 /* first time allocation */
55 if(_ss_gen_poll == NULL)
57 _ss_gen_poll=(struct ss_gen *) malloc(_ss_gen_num *
58 sizeof(struct ss_gen));
60 memset(_ss_gen_poll, '\0', _ss_gen_num * sizeof(struct ss_gen));
63 /* find one in SS_GEN_FREE mode */
64 for(n=0;n < _ss_gen_num;n++)
66 if(_ss_gen_poll[n].mode == SS_GEN_FREE)
67 return(&_ss_gen_poll[n]);
70 return(NULL);
74 /**
75 * generator_play - Activates a generator.
76 * @g: the generator
77 * @wave: wave samples for each channel
78 * @vol: volume for each channel
79 * @size: size of each wave in samples
80 * @inc: cursor increment (frequency)
81 * @loop_start: sample number of the start of the loop (-1, no loop)
82 * @loop_end: sample number of the end of the loop
83 * @sustain: number of samples the sound will fade out after release
85 * Activates a generator, usually as a response for a 'note on'
86 * message from an upper level. @g must be in GEN_MODE_FREE mode.
87 * @wave sould contain pointers to PCM wave data.
88 * @inc is the cursor increment, and should be the result of the
89 * original wave's sample rate divided by the desired frequency.
90 * @loop_start and @loop_end should mark the start and end of
91 * a loop in the sound. If @loop_start is -1 and the sound cursor
92 * reaches the end of the sample, the generator moves to
93 * GEN_MODE_ZOMBIE mode and stops generating sound; if a loop is
94 * defined, the generator produces sound indefinitely until a call
95 * to generator_release() is done.
97 * This function returns -1 if the generator is not free, and
98 * 0 if everything is OK and the generator moved to
99 * GEN_MODE_PLAYING mode.
101 int ss_gen_play(int note_id, int instrk, float * wave[], float vol[],
102 double size, double inc, double loop_start, double loop_end,
103 int sustain)
105 struct ss_gen * g;
106 int n;
108 /* find a free generator or fail */
109 if((g=_ss_gen_get_free()) == NULL)
110 return(-1);
112 g->mode=SS_GEN_PLAYING;
113 g->note_id=note_id;
114 g->instrk=instrk;
116 /* transfers waves and volumes */
117 for(n=0;n < CHANNELS;n++)
119 g->wave[n]=wave[n];
120 g->vol[n]=vol[n];
123 g->size=size;
124 g->inc=inc;
126 g->loop_start=loop_start;
127 g->loop_end=loop_end;
129 g->sustain=sustain;
131 /* no portamento by default */
132 g->portamento=0;
134 /* start from the beginning */
135 g->cursor=0;
137 return(0);
142 * generator_release - Releases a generator.
143 * @g: the generator
145 * Releases a generator, usually as a response for a 'note off'
146 * message from an upper level. If the generator is in
147 * GEN_MODE_ZOMBIE mode (as a result of a non-looped sound
148 * reaching the end of the sample) or if it has no sustain, the
149 * generator is immediately freed and ready for a new
150 * activation; if the sound has sustain, the generator
151 * moves to GEN_MODE_RELEASED mode and keeps generating
152 * fading-out sound for the sustain time.
154 * Returns -1 if the generator is free or already released,
155 * 0 if entered GEN_MODE_RELEASED mode or 1 if it was
156 * immediately freed and entered GEN_MODE_FREE mode.
158 int ss_gen_release(int note_id)
160 struct ss_gen * g;
161 int n;
163 for(n=0;n < _ss_gen_num;n++)
165 g=&_ss_gen_poll[n];
167 if(g->note_id != note_id)
168 continue;
170 /* note needs not be tracked anymore */
171 g->note_id=0;
173 /* generator is released */
174 g->mode=SS_GEN_RELEASED;
176 /* calculates delta volume values */
177 for(n=0;n < CHANNELS;n++)
179 if(g->wave[n])
180 g->dvol[n]=g->vol[n] / (float) g->sustain;
181 else
182 g->dvol[n]=0.0;
186 return(1);
191 * generator - Generates a frame of samples.
192 * @g: the generator
193 * @sample: array where the output samples will be stored
195 * Generates a frame of samples, that will be stored
196 * in the @sample array. If the generator is in
197 * GEN_MODE_RELEASED mode, the sound should keep fading-out
198 * until the sustain time is exhausted and then moved to
199 * GEN_MODE_FREE mode; if the generator is playing and
200 * a non-looped sound reaches the end, it's moved to
201 * GEN_MODE_ZOMBIE mode. It also processes portamento.
203 * Returns 0 if generator is in GEN_MODE_FREE or
204 * GEN_MODE_ZOMBIE mode, or 1 if sound were generated and
205 * stored in @sample.
207 int _ss_gen_frame(struct ss_gen * g, float frame[])
209 float s;
210 int n;
211 int to_free=0;
213 /* return if generator is not active */
214 if(g->mode == SS_GEN_FREE)
215 return(0);
217 /* get samples */
218 for(n=0;n < CHANNELS;n++)
220 if(g->wave[n] != NULL)
222 s=get_sample(g->wave[n],
223 g->loop_end, g->cursor) * g->vol[n];
225 frame[n] += s;
229 /* increment pointer */
230 g->cursor += g->inc;
232 /* test loop boundaries */
233 if(g->cursor > g->loop_end)
235 /* loop mode? */
236 if(g->loop_start == -1)
237 to_free=1;
238 else
239 g->cursor=g->loop_start;
242 /* process sustain */
243 if(g->mode == SS_GEN_RELEASED)
245 for(n=0;n < CHANNELS;n++)
246 g->vol[n] -= g->dvol[n];
248 if(--g->sustain <= 0)
249 to_free=1;
252 /* process portamento */
253 if(g->portamento)
255 if(--g->portamento <= 0)
256 g->inc=g->dest_inc;
257 else
258 g->inc += g->dinc;
261 if(to_free)
262 g->mode=SS_GEN_FREE;
264 return(1);
268 void ss_gen_frame(int instrk, float frame[])
270 struct ss_gen * g;
271 int n;
273 for(n=0;n < _ss_gen_num;n++)
275 g=&_ss_gen_poll[n];
277 if(g->instrk == instrk)
278 _ss_gen_frame(g, frame);
284 * generator_portamento - Sets portamento for a generator.
285 * @g: the generator
286 * @portamento: portamento time
287 * @dest_inc: destination inc (frequency)
289 * Sets the portamento for a generator. @portamento is the
290 * number of frames the generator should move from its current
291 * cursor increment to @dest_inc. See generator_play() for an
292 * explanation of the value contained in @dest_inc.
294 * Returns -1 if the generator is not in GEN_MODE_PLAYING
295 * mode, or 0 if the portamento was accepted.
297 * FIXME: The API for portamento will probably change.
299 int ss_gen_portamento(struct ss_gen * g, int portamento, double dest_inc)
301 /* generator must be playing */
302 if(g->mode != SS_GEN_PLAYING)
303 return(-1);
305 g->portamento=portamento;
306 g->dest_inc=dest_inc;
307 g->dinc=((dest_inc - g->inc) / (double) portamento);
309 return(0);