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
33 #include "generator.h"
39 /* number of generators */
40 int _ss_gen_num
=SS_GEN_NUM
;
43 struct ss_gen
* _ss_gen_poll
=NULL
;
50 struct ss_gen
* _ss_gen_get_free(void)
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
]);
75 * generator_play - Activates a 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
,
108 /* find a free generator or fail */
109 if((g
=_ss_gen_get_free()) == NULL
)
112 g
->mode
=SS_GEN_PLAYING
;
116 /* transfers waves and volumes */
117 for(n
=0;n
< CHANNELS
;n
++)
126 g
->loop_start
=loop_start
;
127 g
->loop_end
=loop_end
;
131 /* no portamento by default */
134 /* start from the beginning */
142 * generator_release - Releases a 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
)
163 for(n
=0;n
< _ss_gen_num
;n
++)
167 if(g
->note_id
!= note_id
)
170 /* note needs not be tracked anymore */
173 /* generator is released */
174 g
->mode
=SS_GEN_RELEASED
;
176 /* calculates delta volume values */
177 for(n
=0;n
< CHANNELS
;n
++)
180 g
->dvol
[n
]=g
->vol
[n
] / (float) g
->sustain
;
191 * generator - Generates a frame of samples.
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
207 int _ss_gen_frame(struct ss_gen
* g
, float frame
[])
213 /* return if generator is not active */
214 if(g
->mode
== SS_GEN_FREE
)
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
];
229 /* increment pointer */
232 /* test loop boundaries */
233 if(g
->cursor
> g
->loop_end
)
236 if(g
->loop_start
== -1)
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)
252 /* process portamento */
255 if(--g
->portamento
<= 0)
268 void ss_gen_frame(int instrk
, float frame
[])
273 for(n
=0;n
< _ss_gen_num
;n
++)
277 if(g
->instrk
== instrk
)
278 _ss_gen_frame(g
, frame
);
284 * generator_portamento - Sets portamento for a 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
)
305 g
->portamento
=portamento
;
306 g
->dest_inc
=dest_inc
;
307 g
->dinc
=((dest_inc
- g
->inc
) / (double) portamento
);