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
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;
48 /* note frequencies */
49 double ss_middle_A_freq
= 440.0;
50 static double note_frequency
[128];
57 * ss_note_frequency - MIDI note to frequency converter
58 * @note: the MIDI note
60 * Accepts a MIDI note number (range 0 to 127) and
61 * returns its frequency in Hz.
63 double ss_note_frequency(int note
)
67 if(note
< 0 || note
> 127)
70 /* builds the table if empty */
71 if(note_frequency
[0] == 0.0)
73 for(n
= 0;n
< 128;n
++)
74 note_frequency
[n
] = (ss_middle_A_freq
/ 32.0) *
75 pow(2.0, (((double)n
- 9.0) / 12.0));
78 return(note_frequency
[note
]);
82 struct ss_wave
* ss_alloc_wave(int size
, int n_channels
, int s_rate
)
86 if((w
= (struct ss_wave
*)malloc(sizeof(struct ss_wave
))) != NULL
)
90 memset(w
, '\0', sizeof(struct ss_wave
));
92 w
->size
= (double) size
;
93 w
->n_channels
= n_channels
;
96 /* alloc space for the pointers to the waves */
97 w
->wave
= (sample_t
**)malloc(n_channels
* sizeof(sample_t
*));
99 /* alloc space for the waves themselves */
100 for(n
= 0;n
< n_channels
;n
++)
101 w
->wave
[n
] = (sample_t
*)malloc(size
* sizeof(sample_t
));
109 * ss_get_sample - Reads a sample from a wave buffer.
110 * @wave: the wave PCM data
111 * @size: size of the wave in samples
112 * @offset: sample number to be returned
114 * Returns the sample number @offset from the @wave buffer
115 * of @size size, doing interpolation if @offset
118 sample_t
ss_get_sample(sample_t
* wave
, double size
, double offset
)
120 sample_t d
, s1
, s2
, r
= 0.0;
123 /* take care of wrappings */
124 if(offset
< 0) offset
+= size
;
128 switch(ss_interpolation
)
131 /* no interpolation */
136 /* linear interpolation */
137 if(offset
> size
- 2)
141 d
= (sample_t
)(offset
- floor(offset
));
143 s2
= (wave
[o
+ 1] - s1
) * d
;
151 /* cubic spline (borrowed from timidity) */
152 if(offset
< 1 || offset
> size
- 3)
165 d
= (sample_t
)(offset
- floor(offset
));
168 ((5.0 * s3
- 11.0 * s2
+ 7.0 * s1
- s0
) / 4.0) *
169 (d
+ 1.0) * (d
- 1.0)) * d
;
172 ((5.0 * s0
- 11.0 * s1
+ 7.0 * t
- s3
) / 4.0) *
173 d
* (d
- 2.0)) * (1.0 - d
) + s2
) / 6.0;
181 /* lagrange (borrowed from timidity) */
182 if(offset
< 1 || offset
> size
- 3)
193 d
= (sample_t
)(offset
- floor(offset
));
195 s3
+= -3.0 * s2
+ 3.0 * s1
- s0
;
196 s3
*= (d
- 2.0) / 6.0;
197 s3
+= s2
- 2.0 * s1
+ s0
;
198 s3
*= (d
- 1.0) / 2.0;
214 * ss_tempo_from_wave - Calculates a tempo from a wave
216 * @note: note to calculate the tempo from
217 * @len: whole notes the tempo should match
219 * Calculates the optimal tempo for the @w wave, playing the @note,
220 * to last @len whole notes.
222 double ss_tempo_from_wave(struct ss_wave
* w
, int note
, double len
)
226 d
= ss_note_frequency(note
) / w
->base_freq
;
228 /* get the length of a whole, in seconds */
229 d
*= w
->s_rate
/ w
->size
;
231 /* convert to minutes */
243 * ss_pitch_from_tempo - Calculates a pitch from a tempo
245 * @tempo: current tempo
246 * @len: desired length in whole notes
248 * Calculates the optimal frequency (pitch) for the @w wave, at @tempo,
249 * to last @len whole notes.
251 double ss_pitch_from_tempo(struct ss_wave
* w
, double tempo
, double len
)
255 /* calculate number of seconds the wave lasts */
256 d
= w
->size
/ (double) w
->s_rate
;
258 /* convert to minutes, then to wpms */
262 return(w
->base_freq
* d
* len
);