Minor cleanings to ss_song_render().
[ahxm.git] / ss_core.c
blob4747e0d7d84f302a6dbcd469965bf664ddc098f1
1 /*
3 Ann Hell Ex Machina - Music Software
4 Copyright (C) 2003/2005 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 "annhell.h"
35 /*******************
36 Data
37 ********************/
39 /* main output frequency */
40 int ss_frequency=44100;
42 /* interpolation type: 0, none; 1, linear; 2, cubic spline; 3, lagrange */
43 int ss_interpolation=3;
45 /* output channels */
46 int ss_nchannels=2;
48 /* note frequencies */
49 double ss_middle_A_freq=440.0;
50 static double note_frequency[128];
52 /* debug level */
53 int ss_debug=1;
55 /*******************
56 Code
57 ********************/
59 /**
60 * ss_note_frequency - MIDI note to frequency converter
61 * @note: the MIDI note
63 * Accepts a MIDI note number (range 0 to 127) and
64 * returns its frequency in Hz.
66 double ss_note_frequency(int note)
68 int n;
70 if(note < 0 || note > 127)
71 return(0);
73 /* builds the table if empty */
74 if(note_frequency[0] == 0.0)
76 for(n=0;n < 128;n++)
77 note_frequency[n]=(ss_middle_A_freq / 32.0) *
78 pow(2.0, (((double)n - 9.0) / 12.0));
81 return(note_frequency[note]);
85 struct ss_wave * ss_alloc_wave(int size, int n_channels, int s_rate)
87 struct ss_wave * w;
89 if((w=(struct ss_wave *)malloc(sizeof(struct ss_wave))) != NULL)
91 int n;
93 memset(w, '\0', sizeof(struct ss_wave));
95 w->size=(double) size;
96 w->n_channels=n_channels;
97 w->s_rate=s_rate;
99 /* alloc space for the pointers to the waves */
100 w->wave=(float **)malloc(n_channels * sizeof(float *));
102 /* alloc space for the waves themselves */
103 for(n=0;n < n_channels;n++)
104 w->wave[n]=(float *)malloc(size * sizeof(float));
107 return(w);
112 * ss_get_sample - Reads a sample from a wave buffer.
113 * @wave: the wave PCM data
114 * @size: size of the wave in samples
115 * @offset: sample number to be returned
117 * Returns the sample number @offset from the @wave buffer
118 * of @size size, doing interpolation if @offset
119 * is not an integer.
121 float ss_get_sample(float * wave, double size, double offset)
123 float d, s1, s2, r=0.0;
124 int o;
126 /* take care of wrappings */
127 if(offset < 0) offset += size;
129 o=(int) offset;
131 switch(ss_interpolation)
133 case 0:
134 /* no interpolation */
135 r=wave[o];
136 break;
138 case 1:
139 /* linear interpolation */
140 if(offset > size - 2)
141 r=wave[o];
142 else
144 d=(float)(offset - floor(offset));
145 s1=wave[o];
146 s2=(wave[o + 1] - s1) * d;
148 r=s1 + s2;
151 break;
153 case 2:
154 /* cubic spline (borrowed from timidity) */
155 if(offset < 1 || offset > size - 3)
156 r=wave[o];
157 else
159 float s0, s3, t;
161 s0=wave[o - 1];
162 s1=wave[o];
163 s2=wave[o + 1];
164 s3=wave[o + 2];
166 t=s2;
168 d=(float)(offset - floor(offset));
170 s2=(6.0 * s2 +
171 ((5.0 * s3 - 11.0 * s2 + 7.0 * s1 - s0) / 4.0) *
172 (d + 1.0) * (d - 1.0)) * d;
174 s1=((6.0 * s1 +
175 ((5.0 * s0 - 11.0 * s1 + 7.0 * t - s3) / 4.0) *
176 d * (d - 2.0)) * (1.0 - d) + s2) / 6.0;
178 r=s1;
181 break;
183 case 3:
184 /* lagrange (borrowed from timidity) */
185 if(offset < 1 || offset > size - 3)
186 r=wave[o];
187 else
189 float s0, s3;
191 s0=wave[o - 1];
192 s1=wave[o];
193 s2=wave[o + 1];
194 s3=wave[o + 2];
196 d=(float)(offset - floor(offset));
198 s3 += -3.0 * s2 + 3.0 * s1 - s0;
199 s3 *= (d - 2.0) / 6.0;
200 s3 += s2 - 2.0 * s1 + s0;
201 s3 *= (d - 1.0) / 2.0;
202 s3 += s1 - s0;
203 s3 *= d;
204 s3 += s0;
206 r=s3;
209 break;
212 return(r);
217 * ss_tempo_from_wave - Calculates a tempo from a wave
218 * @w: the wave
219 * @note: note to calculate the tempo from
220 * @len: whole notes the tempo should match
222 * Calculates the optimal tempo for the @w wave, playing the @note,
223 * to last @len whole notes.
225 double ss_tempo_from_wave(struct ss_wave * w, int note, double len)
227 double d;
229 d=ss_note_frequency(note) / w->base_freq;
231 /* get the length of a whole, in seconds */
232 d *= w->s_rate / w->size;
234 /* convert to minutes */
235 d *= 60.0;
237 /* then to bpm,s */
238 d *= 4.0;
239 d *= len;
241 return(d);
246 * ss_pitch_from_tempo - Calculates a pitch from a tempo
247 * @w: the wave
248 * @tempo: current tempo
249 * @len: desired length in whole notes
251 * Calculates the optimal frequency (pitch) for the @w wave, at @tempo,
252 * to last @len whole notes.
254 double ss_pitch_from_tempo(struct ss_wave * w, double tempo, double len)
256 double d;
258 /* calculate number of seconds the wave lasts */
259 d=w->size / (double) w->s_rate;
261 /* convert to minutes, then to wpms */
262 d /= 60.0;
263 d *= (tempo / 4.0);
265 return(w->base_freq * d * len);