More reformatting.
[ahxm.git] / ss_core.c
blobf3f79ec0426ab04ede063f8a75cf04f91a0ace37
1 /*
3 Ann Hell Ex Machina - Music Software
4 Copyright (C) 2003/2008 Angel Ortega <angel@triptico.com>
6 ss_core.c - Softsynth core functions
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"
36 /** data **/
38 /* main output frequency */
39 int ss_frequency = 44100;
41 /* interpolation type: 0, none; 1, linear; 2, cubic spline; 3, lagrange */
42 int ss_interpolation = 3;
44 /* output channels */
45 int ss_nchannels = -1;
47 /* note frequencies */
48 double ss_middle_A_freq = 440.0;
49 static double note_frequency[128];
52 /** code **/
54 /**
55 * ss_note_frequency - MIDI note to frequency converter
56 * @note: the MIDI note
58 * Accepts a MIDI note number (range 0 to 127) and
59 * returns its frequency in Hz.
61 double ss_note_frequency(int note)
63 int n;
65 if (note < 0 || note > 127)
66 return 0;
68 /* builds the table if empty */
69 if (note_frequency[0] == 0.0) {
70 for (n = 0; n < 128; n++)
71 note_frequency[n] = (ss_middle_A_freq / 32.0) *
72 pow(2.0, (((double) n - 9.0) / 12.0));
75 return note_frequency[note];
79 /**
80 * ss_alloc_wave - Allocates a wave structure.
81 * @size: size in frames
82 * @n_channels: number of channels
83 * @s_rate: sampling rate
84 * @p_size: size of the sound page
86 * Allocates a wave structure. If @p_size is -1, it's assumed to be the
87 * same as @size (so the sound will live entirely in memory).
89 struct ss_wave *ss_alloc_wave(int size, int n_channels, int s_rate,
90 int p_size)
92 struct ss_wave *w = NULL;
94 if (p_size == -1)
95 p_size = size;
97 if ((w = (struct ss_wave *) malloc(sizeof(struct ss_wave))) != NULL) {
98 memset(w, '\0', sizeof(struct ss_wave));
100 w->size = (double) size;
101 w->p_size = p_size;
102 w->n_channels = n_channels;
103 w->s_rate = s_rate;
105 /* alloc space for the pointers to the waves */
106 w->wave = (sample_t **) malloc(n_channels * sizeof(sample_t *));
107 memset(w->wave, '\0', n_channels * sizeof(sample_t *));
110 return w;
115 * ss_free_wave - Frees a wave structure.
116 * @w: the wave structure
118 * Frees a struct ss_wave allocated by ss_alloc_wave().
120 void ss_free_wave(struct ss_wave *w)
122 if (w->wave != NULL) {
123 int n;
125 /* frees the buffers */
126 for (n = 0; n < w->n_channels; n++)
127 if (w->wave[n] != NULL)
128 free(w->wave[n]);
130 /* frees the space for the pointers to the waves */
131 free(w->wave);
133 /* if it has a filename, also free it */
134 if (w->filename != NULL)
135 free((char *) w->filename);
138 /* frees the wave itself */
139 free(w);
143 void ss_prepare_wave(struct ss_wave *w)
144 /* prepares a wave file for usage (creates the page buffers) */
146 int n;
148 /* alloc space for the waves themselves */
149 for (n = 0; n < w->n_channels; n++) {
150 w->wave[n] =
151 (sample_t *) realloc(w->wave[n], w->p_size * sizeof(sample_t));
153 memset(w->wave[n], '\0', w->p_size * sizeof(sample_t));
158 static void ss_load_page(struct ss_wave *w, int offset)
159 /* loads a page from a wave file into memory */
161 FILE *f;
162 int s;
164 /* set the offset to some samples behind the
165 wanted offset (to avoid possible page bounces) */
166 if ((w->p_offset = offset - 441) < 0)
167 w->p_offset = 0;
169 /* too much page faults for this wave? */
170 if (w->page_faults >= 8) {
171 /* increase space */
172 if ((w->p_size *= 2) > (int) w->size) {
173 /* if this resize is too much, just
174 set it to load the full wave */
175 w->p_size = (int) w->size;
176 w->p_offset = 0;
179 /* trigger a page resizing and restart statistics */
180 w->page_faults = 0;
183 if (w->page_faults == 0)
184 ss_prepare_wave(w);
186 if ((f = fopen(w->filename, "rb")) == NULL) {
187 fprintf(stderr, "Can't open '%s'\n", w->filename);
188 return;
191 if (verbose >= 3)
192 printf("load_page [%s,%d,%d,%d]\n", w->filename,
193 w->p_offset, w->p_size, w->page_faults);
195 /* calculate the frame size */
196 s = w->p_offset * (w->bits / 8) * w->n_channels;
198 /* move there */
199 fseek(f, w->f_pos + s, SEEK_SET);
201 /* fill the page */
202 load_pcm_wave(f, w);
204 fclose(f);
206 w->page_faults++;
210 static sample_t ss_pick_sample(struct ss_wave *w, int channel,
211 double offset)
212 /* picks a sample from a ss_wave, forcing a call to ss_load_page() if
213 the wanted sample is not in memory */
215 int o;
216 sample_t *wave;
218 o = (int) offset;
220 /* is the wanted sample not in memory? */
221 if (o < w->p_offset || o > w->p_offset + w->p_size) {
223 if (verbose >= 3)
224 printf
225 ("ss_pick_sample: offset: %lf, p_offset: %d, p_size: %d, size: %lf, loop_end: %lf\n",
226 offset, w->p_offset, w->p_size, w->size, w->loop_end);
228 ss_load_page(w, o);
231 wave = w->wave[channel];
232 return wave[o - w->p_offset];
237 * ss_get_sample - Reads a sample from a wave.
238 * @wave: the wave
239 * @channel: the channel
240 * @offset: sample number to be returned
242 * Returns the sample number @offset from the @channel of the @wave. @Offset
243 * can be a non-integer value.
245 sample_t ss_get_sample(struct ss_wave * w, int channel, double offset)
247 sample_t d, t, r = 0.0;
248 sample_t s0, s1, s2, s3;
250 /* take care of wrappings */
251 if (offset < 0)
252 offset += w->size;
254 /* pick sample at offset */
255 s1 = ss_pick_sample(w, channel, offset);
257 switch (ss_interpolation) {
258 case 0:
259 /* no interpolation */
260 r = s1;
261 break;
263 case 1:
264 /* linear interpolation */
265 if (offset > w->size - 2)
266 r = s1;
267 else {
268 d = (sample_t) (offset - floor(offset));
269 s2 = (ss_pick_sample(w, channel, offset + 1) - s1) * d;
271 r = s1 + s2;
274 break;
276 case 2:
277 /* cubic spline (borrowed from timidity) */
278 if (offset < 1 || offset > w->size - 3)
279 r = s1;
280 else {
281 s0 = ss_pick_sample(w, channel, offset - 1);
282 s2 = ss_pick_sample(w, channel, offset + 1);
283 s3 = ss_pick_sample(w, channel, offset + 2);
285 t = s2;
287 d = (sample_t) (offset - floor(offset));
289 s2 = (6.0 * s2 +
290 ((5.0 * s3 - 11.0 * s2 + 7.0 * s1 - s0) / 4.0) *
291 (d + 1.0) * (d - 1.0)) * d;
293 s1 = ((6.0 * s1 +
294 ((5.0 * s0 - 11.0 * s1 + 7.0 * t - s3) / 4.0) *
295 d * (d - 2.0)) * (1.0 - d) + s2) / 6.0;
297 r = s1;
300 break;
302 case 3:
303 /* lagrange (borrowed from timidity) */
304 if (offset < 1 || offset > w->size - 3)
305 r = s1;
306 else {
307 s0 = ss_pick_sample(w, channel, offset - 1);
308 s2 = ss_pick_sample(w, channel, offset + 1);
309 s3 = ss_pick_sample(w, channel, offset + 2);
311 d = (sample_t) (offset - floor(offset));
313 s3 += -3.0 * s2 + 3.0 * s1 - s0;
314 s3 *= (d - 2.0) / 6.0;
315 s3 += s2 - 2.0 * s1 + s0;
316 s3 *= (d - 1.0) / 2.0;
317 s3 += s1 - s0;
318 s3 *= d;
319 s3 += s0;
321 r = s3;
324 break;
327 return r;
332 * ss_tempo_from_wave - Calculates a tempo from a wave
333 * @w: the wave
334 * @note: note to calculate the tempo from
335 * @len: whole notes the tempo should match
337 * Calculates the optimal tempo for the @w wave, playing the @note,
338 * to last @len whole notes.
340 double ss_tempo_from_wave(const struct ss_wave *w, int note, double len)
342 double d;
344 d = ss_note_frequency(note) / w->base_freq;
346 /* get the length of a whole, in seconds */
347 d *= w->s_rate / w->size;
349 /* convert to minutes */
350 d *= 60.0;
352 /* then to bpm,s */
353 d *= 4.0;
354 d *= len;
356 return d;
361 * ss_pitch_from_tempo - Calculates a pitch from a tempo
362 * @w: the wave
363 * @tempo: current tempo
364 * @len: desired length in whole notes
366 * Calculates the optimal frequency (pitch) for the @w wave, at @tempo,
367 * to last @len whole notes.
369 double ss_pitch_from_tempo(const struct ss_wave *w, double tempo,
370 double len)
372 double d;
374 /* calculate number of seconds the wave lasts */
375 d = w->size / (double) w->s_rate;
377 /* convert to minutes, then to wpms */
378 d /= 60.0;
379 d *= (tempo / 4.0);
381 return w->base_freq * d * len;