Rev 8752 | Rev 8770 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
8752 | terminx | 1 | /* TinySoundFont - v0.8 - SoundFont2 synthesizer - https://github.com/schellingb/TinySoundFont |
2 | no warranty implied; use at your own risk |
||
3 | Do this: |
||
4 | #define TSF_IMPLEMENTATION |
||
5 | before you include this file in *one* C or C++ file to create the implementation. |
||
6 | // i.e. it should look like this: |
||
7 | #include ... |
||
8 | #include ... |
||
9 | #define TSF_IMPLEMENTATION |
||
10 | #include "tsf.h" |
||
11 | |||
12 | [OPTIONAL] #define TSF_NO_STDIO to remove stdio dependency |
||
13 | [OPTIONAL] #define TSF_MALLOC, TSF_REALLOC, and TSF_FREE to avoid stdlib.h |
||
14 | [OPTIONAL] #define TSF_MEMCPY, TSF_MEMSET to avoid string.h |
||
15 | [OPTIONAL] #define TSF_POW, TSF_POWF, TSF_EXPF, TSF_LOG, TSF_TAN, TSF_LOG10, TSF_SQRT to avoid math.h |
||
16 | |||
17 | NOT YET IMPLEMENTED |
||
18 | - Support for ChorusEffectsSend and ReverbEffectsSend generators |
||
19 | - Better low-pass filter without lowering performance too much |
||
20 | - Support for modulators |
||
21 | |||
22 | LICENSE (MIT) |
||
23 | |||
24 | Copyright (C) 2017, 2018 Bernhard Schelling |
||
25 | Based on SFZero, Copyright (C) 2012 Steve Folta (https://github.com/stevefolta/SFZero) |
||
26 | |||
27 | Permission is hereby granted, free of charge, to any person obtaining a copy of this |
||
28 | software and associated documentation files (the "Software"), to deal in the Software |
||
29 | without restriction, including without limitation the rights to use, copy, modify, merge, |
||
30 | publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons |
||
31 | to whom the Software is furnished to do so, subject to the following conditions: |
||
32 | |||
33 | The above copyright notice and this permission notice shall be included in all |
||
34 | copies or substantial portions of the Software. |
||
35 | |||
36 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, |
||
37 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
||
38 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||
39 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
||
40 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
||
41 | USE OR OTHER DEALINGS IN THE SOFTWARE. |
||
42 | |||
43 | */ |
||
44 | |||
45 | #ifndef TSF_INCLUDE_TSF_INL |
||
46 | #define TSF_INCLUDE_TSF_INL |
||
47 | |||
48 | #ifdef __cplusplus |
||
49 | extern "C" { |
||
50 | # define CPP_DEFAULT0 = 0 |
||
51 | #else |
||
52 | # define CPP_DEFAULT0 |
||
53 | #endif |
||
54 | |||
55 | //define this if you want the API functions to be static |
||
56 | #ifdef TSF_STATIC |
||
57 | #define TSFDEF static |
||
58 | #else |
||
59 | #define TSFDEF extern |
||
60 | #endif |
||
61 | |||
62 | // The load functions will return a pointer to a struct tsf which all functions |
||
63 | // thereafter take as the first parameter. |
||
64 | // On error the tsf_load* functions will return NULL most likely due to invalid |
||
65 | // data (or if the file did not exist in tsf_load_filename). |
||
66 | typedef struct tsf tsf; |
||
67 | |||
68 | #ifndef TSF_NO_STDIO |
||
69 | // Directly load a SoundFont from a .sf2 file path |
||
70 | TSFDEF tsf* tsf_load_filename(const char* filename); |
||
71 | #endif |
||
72 | |||
73 | // Load a SoundFont from a block of memory |
||
74 | TSFDEF tsf* tsf_load_memory(const void* buffer, int size); |
||
75 | |||
76 | // Stream structure for the generic loading |
||
77 | struct tsf_stream |
||
78 | { |
||
79 | // Custom data given to the functions as the first parameter |
||
80 | void* data; |
||
81 | |||
82 | // Function pointer will be called to read 'size' bytes into ptr (returns number of read bytes) |
||
83 | int (*read)(void* data, void* ptr, unsigned int size); |
||
84 | |||
85 | // Function pointer will be called to skip ahead over 'count' bytes (returns 1 on success, 0 on error) |
||
86 | int (*skip)(void* data, unsigned int count); |
||
87 | }; |
||
88 | |||
89 | // Generic SoundFont loading method using the stream structure above |
||
90 | TSFDEF tsf* tsf_load(struct tsf_stream* stream); |
||
91 | |||
92 | // Free the memory related to this tsf instance |
||
93 | TSFDEF void tsf_close(tsf* f); |
||
94 | |||
95 | // Stop all playing notes immediatly and reset all channel parameters |
||
96 | TSFDEF void tsf_reset(tsf* f); |
||
97 | |||
98 | // Returns the preset index from a bank and preset number, or -1 if it does not exist in the loaded SoundFont |
||
99 | TSFDEF int tsf_get_presetindex(const tsf* f, int bank, int preset_number); |
||
100 | |||
101 | // Returns the number of presets in the loaded SoundFont |
||
102 | TSFDEF int tsf_get_presetcount(const tsf* f); |
||
103 | |||
104 | // Returns the name of a preset index >= 0 and < tsf_get_presetcount() |
||
105 | TSFDEF const char* tsf_get_presetname(const tsf* f, int preset_index); |
||
106 | |||
107 | // Returns the name of a preset by bank and preset number |
||
108 | TSFDEF const char* tsf_bank_get_presetname(const tsf* f, int bank, int preset_number); |
||
109 | |||
110 | // Supported output modes by the render methods |
||
111 | enum TSFOutputMode |
||
112 | { |
||
113 | // Two channels with single left/right samples one after another |
||
114 | TSF_STEREO_INTERLEAVED, |
||
115 | // Two channels with all samples for the left channel first then right |
||
116 | TSF_STEREO_UNWEAVED, |
||
117 | // A single channel (stereo instruments are mixed into center) |
||
118 | TSF_MONO, |
||
119 | }; |
||
120 | |||
121 | // Thread safety: |
||
122 | // Your audio output which calls the tsf_render* functions will most likely |
||
123 | // run on a different thread than where the playback tsf_note* functions |
||
124 | // are called. In which case some sort of concurrency control like a |
||
125 | // mutex needs to be used so they are not called at the same time. |
||
126 | |||
127 | // Setup the parameters for the voice render methods |
||
128 | // outputmode: if mono or stereo and how stereo channel data is ordered |
||
129 | // samplerate: the number of samples per second (output frequency) |
||
130 | // global_gain_db: volume gain in decibels (>0 means higher, <0 means lower) |
||
131 | TSFDEF void tsf_set_output(tsf* f, enum TSFOutputMode outputmode, int samplerate, float global_gain_db CPP_DEFAULT0); |
||
132 | |||
133 | // Start playing a note |
||
134 | // preset_index: preset index >= 0 and < tsf_get_presetcount() |
||
135 | // key: note value between 0 and 127 (60 being middle C) |
||
136 | // vel: velocity as a float between 0.0 (equal to note off) and 1.0 (full) |
||
137 | // bank: instrument bank number (alternative to preset_index) |
||
138 | // preset_number: preset number (alternative to preset_index) |
||
139 | // (bank_note_on returns 0 if preset does not exist, otherwise 1) |
||
140 | TSFDEF void tsf_note_on(tsf* f, int preset_index, int key, float vel); |
||
141 | TSFDEF int tsf_bank_note_on(tsf* f, int bank, int preset_number, int key, float vel); |
||
142 | |||
143 | // Stop playing a note |
||
144 | // (bank_note_off returns 0 if preset does not exist, otherwise 1) |
||
145 | TSFDEF void tsf_note_off(tsf* f, int preset_index, int key); |
||
146 | TSFDEF int tsf_bank_note_off(tsf* f, int bank, int preset_number, int key); |
||
147 | |||
148 | // Stop playing all notes (end with sustain and release) |
||
149 | TSFDEF void tsf_note_off_all(tsf* f); |
||
150 | |||
151 | // Returns the number of active voices |
||
152 | TSFDEF int tsf_active_voice_count(tsf* f); |
||
153 | |||
154 | // Render output samples into a buffer |
||
155 | // You can either render as signed 16-bit values (tsf_render_short) or |
||
156 | // as 32-bit float values (tsf_render_float) |
||
157 | // buffer: target buffer of size samples * output_channels * sizeof(type) |
||
158 | // samples: number of samples to render |
||
159 | // flag_mixing: if 0 clear the buffer first, otherwise mix into existing data |
||
160 | TSFDEF void tsf_render_short(tsf* f, short* buffer, int samples, int flag_mixing CPP_DEFAULT0); |
||
161 | TSFDEF void tsf_render_float(tsf* f, float* buffer, int samples, int flag_mixing CPP_DEFAULT0); |
||
162 | |||
163 | // Higher level channel based functions, set up channel parameters |
||
164 | // channel: channel number |
||
165 | // preset_index: preset index >= 0 and < tsf_get_presetcount() |
||
166 | // preset_number: preset number (alternative to preset_index) |
||
167 | // flag_mididrums: 0 for normal channels, otherwise apply MIDI drum channel rules |
||
168 | // bank: instrument bank number (alternative to preset_index) |
||
169 | // pan: stereo panning value from 0.0 (left) to 1.0 (right) (default 0.5 center) |
||
170 | // volume: linear volume scale factor (default 1.0 full) |
||
171 | // pitch_wheel: pitch wheel position 0 to 16383 (default 8192 unpitched) |
||
172 | // pitch_range: range of the pitch wheel in semitones (default 2.0, total +/- 2 semitones) |
||
173 | // tuning: tuning of all playing voices in semitones (default 0.0, standard (A440) tuning) |
||
174 | // (set_preset_number and set_bank_preset return 0 if preset does not exist, otherwise 1) |
||
175 | TSFDEF void tsf_channel_set_presetindex(tsf* f, int channel, int preset_index); |
||
176 | TSFDEF int tsf_channel_set_presetnumber(tsf* f, int channel, int preset_number, int flag_mididrums CPP_DEFAULT0); |
||
177 | TSFDEF void tsf_channel_set_bank(tsf* f, int channel, int bank); |
||
178 | TSFDEF int tsf_channel_set_bank_preset(tsf* f, int channel, int bank, int preset_number); |
||
179 | TSFDEF void tsf_channel_set_pan(tsf* f, int channel, float pan); |
||
180 | TSFDEF void tsf_channel_set_volume(tsf* f, int channel, float volume); |
||
181 | TSFDEF void tsf_channel_set_pitchwheel(tsf* f, int channel, int pitch_wheel); |
||
182 | TSFDEF void tsf_channel_set_pitchrange(tsf* f, int channel, float pitch_range); |
||
183 | TSFDEF void tsf_channel_set_tuning(tsf* f, int channel, float tuning); |
||
184 | |||
185 | // Start or stop playing notes on a channel (needs channel preset to be set) |
||
186 | // channel: channel number |
||
187 | // key: note value between 0 and 127 (60 being middle C) |
||
188 | // vel: velocity as a float between 0.0 (equal to note off) and 1.0 (full) |
||
189 | TSFDEF void tsf_channel_note_on(tsf* f, int channel, int key, float vel); |
||
190 | TSFDEF void tsf_channel_note_off(tsf* f, int channel, int key); |
||
191 | TSFDEF void tsf_channel_note_off_all(tsf* f, int channel); //end with sustain and release |
||
192 | TSFDEF void tsf_channel_sounds_off_all(tsf* f, int channel); //end immediatly |
||
193 | |||
194 | // Apply a MIDI control change to the channel (not all controllers are supported!) |
||
195 | TSFDEF void tsf_channel_midi_control(tsf* f, int channel, int controller, int control_value); |
||
196 | |||
197 | // Get current values set on the channels |
||
198 | TSFDEF int tsf_channel_get_preset_index(tsf* f, int channel); |
||
199 | TSFDEF int tsf_channel_get_preset_bank(tsf* f, int channel); |
||
200 | TSFDEF int tsf_channel_get_preset_number(tsf* f, int channel); |
||
201 | TSFDEF float tsf_channel_get_pan(tsf* f, int channel); |
||
202 | TSFDEF float tsf_channel_get_volume(tsf* f, int channel); |
||
203 | TSFDEF int tsf_channel_get_pitchwheel(tsf* f, int channel); |
||
204 | TSFDEF float tsf_channel_get_pitchrange(tsf* f, int channel); |
||
205 | TSFDEF float tsf_channel_get_tuning(tsf* f, int channel); |
||
206 | |||
207 | #ifdef __cplusplus |
||
208 | # undef CPP_DEFAULT0 |
||
209 | } |
||
210 | #endif |
||
211 | |||
212 | // end header |
||
213 | // --------------------------------------------------------------------------------------------------------- |
||
214 | #endif //TSF_INCLUDE_TSF_INL |
||
215 | |||
216 | #ifdef TSF_IMPLEMENTATION |
||
217 | |||
218 | // The lower this block size is the more accurate the effects are. |
||
219 | // Increasing the value significantly lowers the CPU usage of the voice rendering. |
||
220 | // If LFO affects the low-pass filter it can be hearable even as low as 8. |
||
221 | #ifndef TSF_RENDER_EFFECTSAMPLEBLOCK |
||
222 | #define TSF_RENDER_EFFECTSAMPLEBLOCK 64 |
||
223 | #endif |
||
224 | |||
225 | // Grace release time for quick voice off (avoid clicking noise) |
||
226 | #define TSF_FASTRELEASETIME 0.01f |
||
227 | |||
228 | #if !defined(TSF_MALLOC) || !defined(TSF_FREE) || !defined(TSF_REALLOC) |
||
229 | # include <stdlib.h> |
||
230 | # define TSF_MALLOC malloc |
||
231 | # define TSF_FREE free |
||
232 | # define TSF_REALLOC realloc |
||
233 | #endif |
||
234 | |||
235 | #if !defined(TSF_MEMCPY) || !defined(TSF_MEMSET) |
||
236 | # include <string.h> |
||
237 | # define TSF_MEMCPY memcpy |
||
238 | # define TSF_MEMSET memset |
||
239 | #endif |
||
240 | |||
241 | #if !defined(TSF_POW) || !defined(TSF_POWF) || !defined(TSF_EXPF) || !defined(TSF_LOG) || !defined(TSF_TAN) || !defined(TSF_LOG10) || !defined(TSF_SQRT) |
||
242 | # include <math.h> |
||
243 | # if !defined(__cplusplus) && !defined(NAN) && !defined(powf) && !defined(expf) && !defined(sqrtf) |
||
244 | # define powf (float)pow // deal with old math.h |
||
245 | # define expf (float)exp // files that come without |
||
246 | # define sqrtf (float)sqrt // powf, expf and sqrtf |
||
247 | # endif |
||
248 | # define TSF_POW pow |
||
249 | # define TSF_POWF powf |
||
250 | # define TSF_EXPF expf |
||
251 | # define TSF_LOG log |
||
252 | # define TSF_TAN tan |
||
253 | # define TSF_LOG10 log10 |
||
254 | # define TSF_SQRTF sqrtf |
||
255 | #endif |
||
256 | |||
257 | #ifndef TSF_NO_STDIO |
||
258 | # include <stdio.h> |
||
259 | #endif |
||
260 | |||
261 | #define TSF_TRUE 1 |
||
262 | #define TSF_FALSE 0 |
||
263 | #define TSF_BOOL char |
||
264 | #define TSF_PI 3.14159265358979323846264338327950288 |
||
265 | #define TSF_NULL 0 |
||
266 | |||
267 | #ifdef __cplusplus |
||
268 | extern "C" { |
||
269 | #endif |
||
270 | |||
271 | typedef char tsf_fourcc[4]; |
||
272 | typedef signed char tsf_s8; |
||
273 | typedef unsigned char tsf_u8; |
||
274 | typedef unsigned short tsf_u16; |
||
275 | typedef signed short tsf_s16; |
||
276 | typedef unsigned int tsf_u32; |
||
277 | typedef char tsf_char20[20]; |
||
278 | |||
279 | #define TSF_FourCCEquals(value1, value2) (value1[0] == value2[0] && value1[1] == value2[1] && value1[2] == value2[2] && value1[3] == value2[3]) |
||
280 | |||
281 | struct tsf |
||
282 | { |
||
283 | struct tsf_preset* presets; |
||
284 | float* fontSamples; |
||
285 | struct tsf_voice* voices; |
||
286 | struct tsf_channels* channels; |
||
287 | float* outputSamples; |
||
288 | |||
289 | int presetNum; |
||
290 | int voiceNum; |
||
291 | int outputSampleSize; |
||
292 | unsigned int voicePlayIndex; |
||
293 | |||
294 | enum TSFOutputMode outputmode; |
||
295 | float outSampleRate; |
||
296 | float globalGainDB; |
||
297 | }; |
||
298 | |||
299 | #ifndef TSF_NO_STDIO |
||
300 | static int tsf_stream_stdio_read(FILE* f, void* ptr, unsigned int size) { return (int)fread(ptr, 1, size, f); } |
||
301 | static int tsf_stream_stdio_skip(FILE* f, unsigned int count) { return !fseek(f, count, SEEK_CUR); } |
||
302 | TSFDEF tsf* tsf_load_filename(const char* filename) |
||
303 | { |
||
304 | tsf* res; |
||
305 | struct tsf_stream stream = { TSF_NULL, (int(*)(void*,void*,unsigned int))&tsf_stream_stdio_read, (int(*)(void*,unsigned int))&tsf_stream_stdio_skip }; |
||
306 | #if __STDC_WANT_SECURE_LIB__ |
||
307 | FILE* f = TSF_NULL; fopen_s(&f, filename, "rb"); |
||
308 | #else |
||
309 | FILE* f = fopen(filename, "rb"); |
||
310 | #endif |
||
311 | if (!f) |
||
312 | { |
||
313 | //if (e) *e = TSF_FILENOTFOUND; |
||
314 | return TSF_NULL; |
||
315 | } |
||
316 | stream.data = f; |
||
317 | res = tsf_load(&stream); |
||
318 | fclose(f); |
||
319 | return res; |
||
320 | } |
||
321 | #endif |
||
322 | |||
323 | struct tsf_stream_memory { const char* buffer; unsigned int total, pos; }; |
||
324 | static int tsf_stream_memory_read(struct tsf_stream_memory* m, void* ptr, unsigned int size) { if (size > m->total - m->pos) size = m->total - m->pos; TSF_MEMCPY(ptr, m->buffer+m->pos, size); m->pos += size; return size; } |
||
325 | static int tsf_stream_memory_skip(struct tsf_stream_memory* m, unsigned int count) { if (m->pos + count > m->total) return 0; m->pos += count; return 1; } |
||
326 | TSFDEF tsf* tsf_load_memory(const void* buffer, int size) |
||
327 | { |
||
328 | struct tsf_stream stream = { TSF_NULL, (int(*)(void*,void*,unsigned int))&tsf_stream_memory_read, (int(*)(void*,unsigned int))&tsf_stream_memory_skip }; |
||
329 | struct tsf_stream_memory f = { 0, 0, 0 }; |
||
330 | f.buffer = (const char*)buffer; |
||
331 | f.total = size; |
||
332 | stream.data = &f; |
||
333 | return tsf_load(&stream); |
||
334 | } |
||
335 | |||
336 | enum { TSF_LOOPMODE_NONE, TSF_LOOPMODE_CONTINUOUS, TSF_LOOPMODE_SUSTAIN }; |
||
337 | |||
338 | enum { TSF_SEGMENT_NONE, TSF_SEGMENT_DELAY, TSF_SEGMENT_ATTACK, TSF_SEGMENT_HOLD, TSF_SEGMENT_DECAY, TSF_SEGMENT_SUSTAIN, TSF_SEGMENT_RELEASE, TSF_SEGMENT_DONE }; |
||
339 | |||
340 | struct tsf_hydra |
||
341 | { |
||
342 | struct tsf_hydra_phdr *phdrs; struct tsf_hydra_pbag *pbags; struct tsf_hydra_pmod *pmods; |
||
343 | struct tsf_hydra_pgen *pgens; struct tsf_hydra_inst *insts; struct tsf_hydra_ibag *ibags; |
||
344 | struct tsf_hydra_imod *imods; struct tsf_hydra_igen *igens; struct tsf_hydra_shdr *shdrs; |
||
345 | int phdrNum, pbagNum, pmodNum, pgenNum, instNum, ibagNum, imodNum, igenNum, shdrNum; |
||
346 | }; |
||
347 | |||
348 | union tsf_hydra_genamount { struct { tsf_u8 lo, hi; } range; tsf_s16 shortAmount; tsf_u16 wordAmount; }; |
||
349 | struct tsf_hydra_phdr { tsf_char20 presetName; tsf_u16 preset, bank, presetBagNdx; tsf_u32 library, genre, morphology; }; |
||
350 | struct tsf_hydra_pbag { tsf_u16 genNdx, modNdx; }; |
||
351 | struct tsf_hydra_pmod { tsf_u16 modSrcOper, modDestOper; tsf_s16 modAmount; tsf_u16 modAmtSrcOper, modTransOper; }; |
||
352 | struct tsf_hydra_pgen { tsf_u16 genOper; union tsf_hydra_genamount genAmount; }; |
||
353 | struct tsf_hydra_inst { tsf_char20 instName; tsf_u16 instBagNdx; }; |
||
354 | struct tsf_hydra_ibag { tsf_u16 instGenNdx, instModNdx; }; |
||
355 | struct tsf_hydra_imod { tsf_u16 modSrcOper, modDestOper; tsf_s16 modAmount; tsf_u16 modAmtSrcOper, modTransOper; }; |
||
356 | struct tsf_hydra_igen { tsf_u16 genOper; union tsf_hydra_genamount genAmount; }; |
||
357 | struct tsf_hydra_shdr { tsf_char20 sampleName; tsf_u32 start, end, startLoop, endLoop, sampleRate; tsf_u8 originalPitch; tsf_s8 pitchCorrection; tsf_u16 sampleLink, sampleType; }; |
||
358 | |||
359 | #define TSFR(FIELD) stream->read(stream->data, &i->FIELD, sizeof(i->FIELD)); |
||
360 | static void tsf_hydra_read_phdr(struct tsf_hydra_phdr* i, struct tsf_stream* stream) { TSFR(presetName) TSFR(preset) TSFR(bank) TSFR(presetBagNdx) TSFR(library) TSFR(genre) TSFR(morphology) } |
||
361 | static void tsf_hydra_read_pbag(struct tsf_hydra_pbag* i, struct tsf_stream* stream) { TSFR(genNdx) TSFR(modNdx) } |
||
362 | static void tsf_hydra_read_pmod(struct tsf_hydra_pmod* i, struct tsf_stream* stream) { TSFR(modSrcOper) TSFR(modDestOper) TSFR(modAmount) TSFR(modAmtSrcOper) TSFR(modTransOper) } |
||
363 | static void tsf_hydra_read_pgen(struct tsf_hydra_pgen* i, struct tsf_stream* stream) { TSFR(genOper) TSFR(genAmount) } |
||
364 | static void tsf_hydra_read_inst(struct tsf_hydra_inst* i, struct tsf_stream* stream) { TSFR(instName) TSFR(instBagNdx) } |
||
365 | static void tsf_hydra_read_ibag(struct tsf_hydra_ibag* i, struct tsf_stream* stream) { TSFR(instGenNdx) TSFR(instModNdx) } |
||
366 | static void tsf_hydra_read_imod(struct tsf_hydra_imod* i, struct tsf_stream* stream) { TSFR(modSrcOper) TSFR(modDestOper) TSFR(modAmount) TSFR(modAmtSrcOper) TSFR(modTransOper) } |
||
367 | static void tsf_hydra_read_igen(struct tsf_hydra_igen* i, struct tsf_stream* stream) { TSFR(genOper) TSFR(genAmount) } |
||
368 | static void tsf_hydra_read_shdr(struct tsf_hydra_shdr* i, struct tsf_stream* stream) { TSFR(sampleName) TSFR(start) TSFR(end) TSFR(startLoop) TSFR(endLoop) TSFR(sampleRate) TSFR(originalPitch) TSFR(pitchCorrection) TSFR(sampleLink) TSFR(sampleType) } |
||
369 | #undef TSFR |
||
370 | |||
371 | struct tsf_riffchunk { tsf_fourcc id; tsf_u32 size; }; |
||
372 | struct tsf_envelope { float delay, attack, hold, decay, sustain, release, keynumToHold, keynumToDecay; }; |
||
373 | struct tsf_voice_envelope { float level, slope; int samplesUntilNextSegment; short segment, midiVelocity; struct tsf_envelope parameters; TSF_BOOL segmentIsExponential, isAmpEnv; }; |
||
374 | struct tsf_voice_lowpass { double QInv, a0, a1, b1, b2, z1, z2; TSF_BOOL active; }; |
||
375 | struct tsf_voice_lfo { int samplesUntil; float level, delta; }; |
||
376 | |||
377 | struct tsf_region |
||
378 | { |
||
379 | int loop_mode; |
||
380 | unsigned int sample_rate; |
||
381 | unsigned char lokey, hikey, lovel, hivel; |
||
382 | unsigned int group, offset, end, loop_start, loop_end; |
||
383 | int transpose, tune, pitch_keycenter, pitch_keytrack; |
||
384 | float attenuation, pan; |
||
385 | struct tsf_envelope ampenv, modenv; |
||
386 | int initialFilterQ, initialFilterFc; |
||
387 | int modEnvToPitch, modEnvToFilterFc, modLfoToFilterFc, modLfoToVolume; |
||
388 | float delayModLFO; |
||
389 | int freqModLFO, modLfoToPitch; |
||
390 | float delayVibLFO; |
||
391 | int freqVibLFO, vibLfoToPitch; |
||
392 | }; |
||
393 | |||
394 | struct tsf_preset |
||
395 | { |
||
396 | tsf_char20 presetName; |
||
397 | tsf_u16 preset, bank; |
||
398 | struct tsf_region* regions; |
||
399 | int regionNum; |
||
400 | }; |
||
401 | |||
402 | struct tsf_voice |
||
403 | { |
||
404 | int playingPreset, playingKey, playingChannel; |
||
405 | struct tsf_region* region; |
||
406 | double pitchInputTimecents, pitchOutputFactor; |
||
407 | double sourceSamplePosition; |
||
408 | float noteGainDB, panFactorLeft, panFactorRight; |
||
409 | unsigned int playIndex, loopStart, loopEnd; |
||
410 | struct tsf_voice_envelope ampenv, modenv; |
||
411 | struct tsf_voice_lowpass lowpass; |
||
412 | struct tsf_voice_lfo modlfo, viblfo; |
||
413 | }; |
||
414 | |||
415 | struct tsf_channel |
||
416 | { |
||
417 | unsigned short presetIndex, bank, pitchWheel, midiPan, midiVolume, midiExpression, midiRPN, midiData; |
||
418 | float panOffset, gainDB, pitchRange, tuning; |
||
419 | }; |
||
420 | |||
421 | struct tsf_channels |
||
422 | { |
||
423 | void (*setupVoice)(tsf* f, struct tsf_voice* voice); |
||
424 | struct tsf_channel* channels; |
||
425 | int channelNum, activeChannel; |
||
426 | }; |
||
427 | |||
428 | static double tsf_timecents2Secsd(double timecents) { return TSF_POW(2.0, timecents / 1200.0); } |
||
429 | static float tsf_timecents2Secsf(float timecents) { return TSF_POWF(2.0f, timecents / 1200.0f); } |
||
430 | static float tsf_cents2Hertz(float cents) { return 8.176f * TSF_POWF(2.0f, cents / 1200.0f); } |
||
431 | static float tsf_decibelsToGain(float db) { return (db > -100.f ? TSF_POWF(10.0f, db * 0.05f) : 0); } |
||
432 | static float tsf_gainToDecibels(float gain) { return (gain <= .00001f ? -100.f : (float)(20.0 * TSF_LOG10(gain))); } |
||
433 | |||
434 | static TSF_BOOL tsf_riffchunk_read(struct tsf_riffchunk* parent, struct tsf_riffchunk* chunk, struct tsf_stream* stream) |
||
435 | { |
||
436 | TSF_BOOL IsRiff, IsList; |
||
437 | if (parent && sizeof(tsf_fourcc) + sizeof(tsf_u32) > parent->size) return TSF_FALSE; |
||
438 | if (!stream->read(stream->data, &chunk->id, sizeof(tsf_fourcc)) || *chunk->id <= ' ' || *chunk->id >= 'z') return TSF_FALSE; |
||
439 | if (!stream->read(stream->data, &chunk->size, sizeof(tsf_u32))) return TSF_FALSE; |
||
440 | if (parent && sizeof(tsf_fourcc) + sizeof(tsf_u32) + chunk->size > parent->size) return TSF_FALSE; |
||
441 | if (parent) parent->size -= sizeof(tsf_fourcc) + sizeof(tsf_u32) + chunk->size; |
||
442 | IsRiff = TSF_FourCCEquals(chunk->id, "RIFF"), IsList = TSF_FourCCEquals(chunk->id, "LIST"); |
||
443 | if (IsRiff && parent) return TSF_FALSE; //not allowed |
||
444 | if (!IsRiff && !IsList) return TSF_TRUE; //custom type without sub type |
||
445 | if (!stream->read(stream->data, &chunk->id, sizeof(tsf_fourcc)) || *chunk->id <= ' ' || *chunk->id >= 'z') return TSF_FALSE; |
||
446 | chunk->size -= sizeof(tsf_fourcc); |
||
447 | return TSF_TRUE; |
||
448 | } |
||
449 | |||
450 | static void tsf_region_clear(struct tsf_region* i, TSF_BOOL for_relative) |
||
451 | { |
||
452 | TSF_MEMSET(i, 0, sizeof(struct tsf_region)); |
||
453 | i->hikey = i->hivel = 127; |
||
454 | i->pitch_keycenter = 60; // C4 |
||
455 | if (for_relative) return; |
||
456 | |||
457 | i->pitch_keytrack = 100; |
||
458 | |||
459 | i->pitch_keycenter = -1; |
||
460 | |||
461 | // SF2 defaults in timecents. |
||
462 | i->ampenv.delay = i->ampenv.attack = i->ampenv.hold = i->ampenv.decay = i->ampenv.release = -12000.0f; |
||
463 | i->modenv.delay = i->modenv.attack = i->modenv.hold = i->modenv.decay = i->modenv.release = -12000.0f; |
||
464 | |||
465 | i->initialFilterFc = 13500; |
||
466 | |||
467 | i->delayModLFO = -12000.0f; |
||
468 | i->delayVibLFO = -12000.0f; |
||
469 | } |
||
470 | |||
471 | static void tsf_region_operator(struct tsf_region* region, tsf_u16 genOper, union tsf_hydra_genamount* amount) |
||
472 | { |
||
473 | enum |
||
474 | { |
||
475 | StartAddrsOffset, EndAddrsOffset, StartloopAddrsOffset, EndloopAddrsOffset, StartAddrsCoarseOffset, ModLfoToPitch, VibLfoToPitch, ModEnvToPitch, |
||
476 | InitialFilterFc, InitialFilterQ, ModLfoToFilterFc, ModEnvToFilterFc, EndAddrsCoarseOffset, ModLfoToVolume, Unused1, ChorusEffectsSend, |
||
477 | ReverbEffectsSend, Pan, Unused2, Unused3, Unused4, DelayModLFO, FreqModLFO, DelayVibLFO, FreqVibLFO, DelayModEnv, AttackModEnv, HoldModEnv, |
||
478 | DecayModEnv, SustainModEnv, ReleaseModEnv, KeynumToModEnvHold, KeynumToModEnvDecay, DelayVolEnv, AttackVolEnv, HoldVolEnv, DecayVolEnv, |
||
479 | SustainVolEnv, ReleaseVolEnv, KeynumToVolEnvHold, KeynumToVolEnvDecay, Instrument, Reserved1, KeyRange, VelRange, StartloopAddrsCoarseOffset, |
||
480 | Keynum, Velocity, InitialAttenuation, Reserved2, EndloopAddrsCoarseOffset, CoarseTune, FineTune, SampleID, SampleModes, Reserved3, ScaleTuning, |
||
481 | ExclusiveClass, OverridingRootKey, Unused5, EndOper |
||
482 | }; |
||
483 | switch (genOper) |
||
484 | { |
||
485 | case StartAddrsOffset: region->offset += amount->shortAmount; break; |
||
486 | case EndAddrsOffset: region->end += amount->shortAmount; break; |
||
487 | case StartloopAddrsOffset: region->loop_start += amount->shortAmount; break; |
||
488 | case EndloopAddrsOffset: region->loop_end += amount->shortAmount; break; |
||
489 | case StartAddrsCoarseOffset: region->offset += amount->shortAmount * 32768; break; |
||
490 | case ModLfoToPitch: region->modLfoToPitch = amount->shortAmount; break; |
||
491 | case VibLfoToPitch: region->vibLfoToPitch = amount->shortAmount; break; |
||
492 | case ModEnvToPitch: region->modEnvToPitch = amount->shortAmount; break; |
||
493 | case InitialFilterFc: region->initialFilterFc = amount->shortAmount; break; |
||
494 | case InitialFilterQ: region->initialFilterQ = amount->shortAmount; break; |
||
495 | case ModLfoToFilterFc: region->modLfoToFilterFc = amount->shortAmount; break; |
||
496 | case ModEnvToFilterFc: region->modEnvToFilterFc = amount->shortAmount; break; |
||
497 | case EndAddrsCoarseOffset: region->end += amount->shortAmount * 32768; break; |
||
498 | case ModLfoToVolume: region->modLfoToVolume = amount->shortAmount; break; |
||
499 | case Pan: region->pan = amount->shortAmount / 1000.0f; break; |
||
500 | case DelayModLFO: region->delayModLFO = amount->shortAmount; break; |
||
501 | case FreqModLFO: region->freqModLFO = amount->shortAmount; break; |
||
502 | case DelayVibLFO: region->delayVibLFO = amount->shortAmount; break; |
||
503 | case FreqVibLFO: region->freqVibLFO = amount->shortAmount; break; |
||
504 | case DelayModEnv: region->modenv.delay = amount->shortAmount; break; |
||
505 | case AttackModEnv: region->modenv.attack = amount->shortAmount; break; |
||
506 | case HoldModEnv: region->modenv.hold = amount->shortAmount; break; |
||
507 | case DecayModEnv: region->modenv.decay = amount->shortAmount; break; |
||
508 | case SustainModEnv: region->modenv.sustain = amount->shortAmount; break; |
||
509 | case ReleaseModEnv: region->modenv.release = amount->shortAmount; break; |
||
510 | case KeynumToModEnvHold: region->modenv.keynumToHold = amount->shortAmount; break; |
||
511 | case KeynumToModEnvDecay: region->modenv.keynumToDecay = amount->shortAmount; break; |
||
512 | case DelayVolEnv: region->ampenv.delay = amount->shortAmount; break; |
||
513 | case AttackVolEnv: region->ampenv.attack = amount->shortAmount; break; |
||
514 | case HoldVolEnv: region->ampenv.hold = amount->shortAmount; break; |
||
515 | case DecayVolEnv: region->ampenv.decay = amount->shortAmount; break; |
||
516 | case SustainVolEnv: region->ampenv.sustain = amount->shortAmount; break; |
||
517 | case ReleaseVolEnv: region->ampenv.release = amount->shortAmount; break; |
||
518 | case KeynumToVolEnvHold: region->ampenv.keynumToHold = amount->shortAmount; break; |
||
519 | case KeynumToVolEnvDecay: region->ampenv.keynumToDecay = amount->shortAmount; break; |
||
520 | case KeyRange: region->lokey = amount->range.lo; region->hikey = amount->range.hi; break; |
||
521 | case VelRange: region->lovel = amount->range.lo; region->hivel = amount->range.hi; break; |
||
522 | case StartloopAddrsCoarseOffset: region->loop_start += amount->shortAmount * 32768; break; |
||
523 | case InitialAttenuation: region->attenuation += amount->shortAmount * 0.1f; break; |
||
524 | case EndloopAddrsCoarseOffset: region->loop_end += amount->shortAmount * 32768; break; |
||
525 | case CoarseTune: region->transpose += amount->shortAmount; break; |
||
526 | case FineTune: region->tune += amount->shortAmount; break; |
||
527 | case SampleModes: region->loop_mode = ((amount->wordAmount&3) == 3 ? TSF_LOOPMODE_SUSTAIN : ((amount->wordAmount&3) == 1 ? TSF_LOOPMODE_CONTINUOUS : TSF_LOOPMODE_NONE)); break; |
||
528 | case ScaleTuning: region->pitch_keytrack = amount->shortAmount; break; |
||
529 | case ExclusiveClass: region->group = amount->wordAmount; break; |
||
530 | case OverridingRootKey: region->pitch_keycenter = amount->shortAmount; break; |
||
531 | //case gen_endOper: break; // Ignore. |
||
532 | //default: addUnsupportedOpcode(generator_name); |
||
533 | } |
||
534 | } |
||
535 | |||
536 | static void tsf_region_envtosecs(struct tsf_envelope* p, TSF_BOOL sustainIsGain) |
||
537 | { |
||
538 | // EG times need to be converted from timecents to seconds. |
||
539 | // Pin very short EG segments. Timecents don't get to zero, and our EG is |
||
540 | // happier with zero values. |
||
541 | p->delay = (p->delay < -11950.0f ? 0.0f : tsf_timecents2Secsf(p->delay)); |
||
542 | p->attack = (p->attack < -11950.0f ? 0.0f : tsf_timecents2Secsf(p->attack)); |
||
543 | p->release = (p->release < -11950.0f ? 0.0f : tsf_timecents2Secsf(p->release)); |
||
544 | |||
545 | // If we have dynamic hold or decay times depending on key number we need |
||
546 | // to keep the values in timecents so we can calculate it during startNote |
||
547 | if (!p->keynumToHold) p->hold = (p->hold < -11950.0f ? 0.0f : tsf_timecents2Secsf(p->hold)); |
||
548 | if (!p->keynumToDecay) p->decay = (p->decay < -11950.0f ? 0.0f : tsf_timecents2Secsf(p->decay)); |
||
549 | |||
550 | if (p->sustain < 0.0f) p->sustain = 0.0f; |
||
551 | else if (sustainIsGain) p->sustain = tsf_decibelsToGain(-p->sustain / 10.0f); |
||
552 | else p->sustain = 1.0f - (p->sustain / 1000.0f); |
||
8754 | terminx | 553 | |
554 | p->sustain = clamp(p->sustain, 0, 1.f); |
||
8752 | terminx | 555 | } |
556 | |||
557 | static void tsf_load_presets(tsf* res, struct tsf_hydra *hydra, unsigned int fontSampleCount) |
||
558 | { |
||
559 | enum { GenInstrument = 41, GenKeyRange = 43, GenVelRange = 44, GenSampleID = 53 }; |
||
560 | // Read each preset. |
||
561 | struct tsf_hydra_phdr *pphdr, *pphdrMax; |
||
562 | for (pphdr = hydra->phdrs, pphdrMax = pphdr + hydra->phdrNum - 1; pphdr != pphdrMax; pphdr++) |
||
563 | { |
||
564 | int sortedIndex = 0, region_index = 0; |
||
565 | struct tsf_hydra_phdr *otherphdr; |
||
566 | struct tsf_preset* preset; |
||
567 | struct tsf_hydra_pbag *ppbag, *ppbagEnd; |
||
568 | struct tsf_region globalRegion; |
||
569 | for (otherphdr = hydra->phdrs; otherphdr != pphdrMax; otherphdr++) |
||
570 | { |
||
571 | if (otherphdr == pphdr || otherphdr->bank > pphdr->bank) continue; |
||
572 | else if (otherphdr->bank < pphdr->bank) sortedIndex++; |
||
573 | else if (otherphdr->preset > pphdr->preset) continue; |
||
574 | else if (otherphdr->preset < pphdr->preset) sortedIndex++; |
||
575 | else if (otherphdr < pphdr) sortedIndex++; |
||
576 | } |
||
577 | |||
578 | preset = &res->presets[sortedIndex]; |
||
579 | TSF_MEMCPY(preset->presetName, pphdr->presetName, sizeof(preset->presetName)); |
||
580 | preset->presetName[sizeof(preset->presetName)-1] = '\0'; //should be zero terminated in source file but make sure |
||
581 | preset->bank = pphdr->bank; |
||
582 | preset->preset = pphdr->preset; |
||
583 | preset->regionNum = 0; |
||
584 | |||
585 | //count regions covered by this preset |
||
586 | for (ppbag = hydra->pbags + pphdr->presetBagNdx, ppbagEnd = hydra->pbags + pphdr[1].presetBagNdx; ppbag != ppbagEnd; ppbag++) |
||
587 | { |
||
588 | unsigned char plokey = 0, phikey = 127, plovel = 0, phivel = 127; |
||
589 | struct tsf_hydra_pgen *ppgen, *ppgenEnd; struct tsf_hydra_inst *pinst; struct tsf_hydra_ibag *pibag, *pibagEnd; struct tsf_hydra_igen *pigen, *pigenEnd; |
||
590 | for (ppgen = hydra->pgens + ppbag->genNdx, ppgenEnd = hydra->pgens + ppbag[1].genNdx; ppgen != ppgenEnd; ppgen++) |
||
591 | { |
||
592 | if (ppgen->genOper == GenKeyRange) { plokey = ppgen->genAmount.range.lo; phikey = ppgen->genAmount.range.hi; continue; } |
||
593 | if (ppgen->genOper == GenVelRange) { plovel = ppgen->genAmount.range.lo; phivel = ppgen->genAmount.range.hi; continue; } |
||
594 | if (ppgen->genOper != GenInstrument) continue; |
||
595 | if (ppgen->genAmount.wordAmount >= hydra->instNum) continue; |
||
596 | pinst = hydra->insts + ppgen->genAmount.wordAmount; |
||
597 | for (pibag = hydra->ibags + pinst->instBagNdx, pibagEnd = hydra->ibags + pinst[1].instBagNdx; pibag != pibagEnd; pibag++) |
||
598 | { |
||
599 | unsigned char ilokey = 0, ihikey = 127, ilovel = 0, ihivel = 127; |
||
600 | for (pigen = hydra->igens + pibag->instGenNdx, pigenEnd = hydra->igens + pibag[1].instGenNdx; pigen != pigenEnd; pigen++) |
||
601 | { |
||
602 | if (pigen->genOper == GenKeyRange) { ilokey = pigen->genAmount.range.lo; ihikey = pigen->genAmount.range.hi; continue; } |
||
603 | if (pigen->genOper == GenVelRange) { ilovel = pigen->genAmount.range.lo; ihivel = pigen->genAmount.range.hi; continue; } |
||
604 | if (pigen->genOper == GenSampleID && ihikey >= plokey && ilokey <= phikey && ihivel >= plovel && ilovel <= phivel) preset->regionNum++; |
||
605 | } |
||
606 | } |
||
607 | } |
||
608 | } |
||
609 | |||
610 | preset->regions = (struct tsf_region*)TSF_MALLOC(preset->regionNum * sizeof(struct tsf_region)); |
||
611 | tsf_region_clear(&globalRegion, TSF_TRUE); |
||
612 | |||
613 | // Zones. |
||
614 | for (ppbag = hydra->pbags + pphdr->presetBagNdx, ppbagEnd = hydra->pbags + pphdr[1].presetBagNdx; ppbag != ppbagEnd; ppbag++) |
||
615 | { |
||
616 | struct tsf_hydra_pgen *ppgen, *ppgenEnd; struct tsf_hydra_inst *pinst; struct tsf_hydra_ibag *pibag, *pibagEnd; struct tsf_hydra_igen *pigen, *pigenEnd; |
||
617 | struct tsf_region presetRegion = globalRegion; |
||
618 | int hadGenInstrument = 0; |
||
619 | |||
620 | // Generators. |
||
621 | for (ppgen = hydra->pgens + ppbag->genNdx, ppgenEnd = hydra->pgens + ppbag[1].genNdx; ppgen != ppgenEnd; ppgen++) |
||
622 | { |
||
623 | // Instrument. |
||
624 | if (ppgen->genOper == GenInstrument) |
||
625 | { |
||
626 | struct tsf_region instRegion; |
||
627 | tsf_u16 whichInst = ppgen->genAmount.wordAmount; |
||
628 | if (whichInst >= hydra->instNum) continue; |
||
629 | |||
630 | tsf_region_clear(&instRegion, TSF_FALSE); |
||
631 | pinst = &hydra->insts[whichInst]; |
||
632 | for (pibag = hydra->ibags + pinst->instBagNdx, pibagEnd = hydra->ibags + pinst[1].instBagNdx; pibag != pibagEnd; pibag++) |
||
633 | { |
||
634 | // Generators. |
||
635 | struct tsf_region zoneRegion = instRegion; |
||
636 | int hadSampleID = 0; |
||
637 | for (pigen = hydra->igens + pibag->instGenNdx, pigenEnd = hydra->igens + pibag[1].instGenNdx; pigen != pigenEnd; pigen++) |
||
638 | { |
||
639 | if (pigen->genOper == GenSampleID) |
||
640 | { |
||
641 | struct tsf_hydra_shdr* pshdr; |
||
642 | |||
643 | //preset region key and vel ranges are a filter for the zone regions |
||
644 | if (zoneRegion.hikey < presetRegion.lokey || zoneRegion.lokey > presetRegion.hikey) continue; |
||
645 | if (zoneRegion.hivel < presetRegion.lovel || zoneRegion.lovel > presetRegion.hivel) continue; |
||
646 | if (presetRegion.lokey > zoneRegion.lokey) zoneRegion.lokey = presetRegion.lokey; |
||
647 | if (presetRegion.hikey < zoneRegion.hikey) zoneRegion.hikey = presetRegion.hikey; |
||
648 | if (presetRegion.lovel > zoneRegion.lovel) zoneRegion.lovel = presetRegion.lovel; |
||
649 | if (presetRegion.hivel < zoneRegion.hivel) zoneRegion.hivel = presetRegion.hivel; |
||
650 | |||
651 | //sum regions |
||
652 | zoneRegion.offset += presetRegion.offset; |
||
653 | zoneRegion.end += presetRegion.end; |
||
654 | zoneRegion.loop_start += presetRegion.loop_start; |
||
655 | zoneRegion.loop_end += presetRegion.loop_end; |
||
656 | zoneRegion.transpose += presetRegion.transpose; |
||
657 | zoneRegion.tune += presetRegion.tune; |
||
658 | zoneRegion.pitch_keytrack += presetRegion.pitch_keytrack; |
||
659 | zoneRegion.attenuation += presetRegion.attenuation; |
||
660 | zoneRegion.pan += presetRegion.pan; |
||
661 | zoneRegion.ampenv.delay += presetRegion.ampenv.delay; |
||
662 | zoneRegion.ampenv.attack += presetRegion.ampenv.attack; |
||
663 | zoneRegion.ampenv.hold += presetRegion.ampenv.hold; |
||
664 | zoneRegion.ampenv.decay += presetRegion.ampenv.decay; |
||
665 | zoneRegion.ampenv.sustain += presetRegion.ampenv.sustain; |
||
666 | zoneRegion.ampenv.release += presetRegion.ampenv.release; |
||
667 | zoneRegion.modenv.delay += presetRegion.modenv.delay; |
||
668 | zoneRegion.modenv.attack += presetRegion.modenv.attack; |
||
669 | zoneRegion.modenv.hold += presetRegion.modenv.hold; |
||
670 | zoneRegion.modenv.decay += presetRegion.modenv.decay; |
||
671 | zoneRegion.modenv.sustain += presetRegion.modenv.sustain; |
||
672 | zoneRegion.modenv.release += presetRegion.modenv.release; |
||
673 | zoneRegion.initialFilterQ += presetRegion.initialFilterQ; |
||
674 | zoneRegion.initialFilterFc += presetRegion.initialFilterFc; |
||
675 | zoneRegion.modEnvToPitch += presetRegion.modEnvToPitch; |
||
676 | zoneRegion.modEnvToFilterFc += presetRegion.modEnvToFilterFc; |
||
677 | zoneRegion.delayModLFO += presetRegion.delayModLFO; |
||
678 | zoneRegion.freqModLFO += presetRegion.freqModLFO; |
||
679 | zoneRegion.modLfoToPitch += presetRegion.modLfoToPitch; |
||
680 | zoneRegion.modLfoToFilterFc += presetRegion.modLfoToFilterFc; |
||
681 | zoneRegion.modLfoToVolume += presetRegion.modLfoToVolume; |
||
682 | zoneRegion.delayVibLFO += presetRegion.delayVibLFO; |
||
683 | zoneRegion.freqVibLFO += presetRegion.freqVibLFO; |
||
684 | zoneRegion.vibLfoToPitch += presetRegion.vibLfoToPitch; |
||
685 | |||
686 | // EG times need to be converted from timecents to seconds. |
||
687 | tsf_region_envtosecs(&zoneRegion.ampenv, TSF_TRUE); |
||
688 | tsf_region_envtosecs(&zoneRegion.modenv, TSF_FALSE); |
||
689 | |||
690 | // LFO times need to be converted from timecents to seconds. |
||
691 | zoneRegion.delayModLFO = (zoneRegion.delayModLFO < -11950.0f ? 0.0f : tsf_timecents2Secsf(zoneRegion.delayModLFO)); |
||
692 | zoneRegion.delayVibLFO = (zoneRegion.delayVibLFO < -11950.0f ? 0.0f : tsf_timecents2Secsf(zoneRegion.delayVibLFO)); |
||
693 | |||
694 | // Pin values to their ranges. |
||
695 | if (zoneRegion.pan < -0.5f) zoneRegion.pan = -0.5f; |
||
696 | else if (zoneRegion.pan > 0.5f) zoneRegion.pan = 0.5f; |
||
697 | if (zoneRegion.initialFilterQ < 1500 || zoneRegion.initialFilterQ > 13500) zoneRegion.initialFilterQ = 0; |
||
698 | |||
699 | pshdr = &hydra->shdrs[pigen->genAmount.wordAmount]; |
||
700 | zoneRegion.offset += pshdr->start; |
||
701 | zoneRegion.end += pshdr->end; |
||
702 | zoneRegion.loop_start += pshdr->startLoop; |
||
703 | zoneRegion.loop_end += pshdr->endLoop; |
||
704 | if (pshdr->endLoop > 0) zoneRegion.loop_end -= 1; |
||
705 | if (zoneRegion.pitch_keycenter == -1) zoneRegion.pitch_keycenter = pshdr->originalPitch; |
||
706 | zoneRegion.tune += pshdr->pitchCorrection; |
||
707 | zoneRegion.sample_rate = pshdr->sampleRate; |
||
708 | if (zoneRegion.end && zoneRegion.end < fontSampleCount) zoneRegion.end++; |
||
709 | else zoneRegion.end = fontSampleCount; |
||
710 | |||
711 | preset->regions[region_index] = zoneRegion; |
||
712 | region_index++; |
||
713 | hadSampleID = 1; |
||
714 | } |
||
715 | else tsf_region_operator(&zoneRegion, pigen->genOper, &pigen->genAmount); |
||
716 | } |
||
717 | |||
718 | // Handle instrument's global zone. |
||
719 | if (pibag == hydra->ibags + pinst->instBagNdx && !hadSampleID) |
||
720 | instRegion = zoneRegion; |
||
721 | |||
722 | // Modulators (TODO) |
||
723 | //if (ibag->instModNdx < ibag[1].instModNdx) addUnsupportedOpcode("any modulator"); |
||
724 | } |
||
725 | hadGenInstrument = 1; |
||
726 | } |
||
727 | else tsf_region_operator(&presetRegion, ppgen->genOper, &ppgen->genAmount); |
||
728 | } |
||
729 | |||
730 | // Modulators (TODO) |
||
731 | //if (pbag->modNdx < pbag[1].modNdx) addUnsupportedOpcode("any modulator"); |
||
732 | |||
733 | // Handle preset's global zone. |
||
734 | if (ppbag == hydra->pbags + pphdr->presetBagNdx && !hadGenInstrument) |
||
735 | globalRegion = presetRegion; |
||
736 | } |
||
737 | } |
||
738 | } |
||
739 | |||
740 | static void tsf_load_samples(float** fontSamples, unsigned int* fontSampleCount, struct tsf_riffchunk *chunkSmpl, struct tsf_stream* stream) |
||
741 | { |
||
742 | // Read sample data into float format buffer. |
||
743 | float* out; unsigned int samplesLeft, samplesToRead, samplesToConvert; |
||
744 | samplesLeft = *fontSampleCount = chunkSmpl->size / sizeof(short); |
||
745 | out = *fontSamples = (float*)TSF_MALLOC(samplesLeft * sizeof(float)); |
||
746 | for (; samplesLeft; samplesLeft -= samplesToRead) |
||
747 | { |
||
748 | short sampleBuffer[1024], *in = sampleBuffer;; |
||
749 | samplesToRead = (samplesLeft > 1024 ? 1024 : samplesLeft); |
||
750 | stream->read(stream->data, sampleBuffer, samplesToRead * sizeof(short)); |
||
751 | |||
752 | // Convert from signed 16-bit to float. |
||
753 | for (samplesToConvert = samplesToRead; samplesToConvert > 0; --samplesToConvert) |
||
754 | // If we ever need to compile for big-endian platforms, we'll need to byte-swap here. |
||
755 | *out++ = (float)(*in++ / 32767.0); |
||
756 | } |
||
757 | } |
||
758 | |||
759 | static void tsf_voice_envelope_nextsegment(struct tsf_voice_envelope* e, short active_segment, float outSampleRate) |
||
760 | { |
||
761 | switch (active_segment) |
||
762 | { |
||
763 | case TSF_SEGMENT_NONE: |
||
764 | e->samplesUntilNextSegment = (int)(e->parameters.delay * outSampleRate); |
||
765 | if (e->samplesUntilNextSegment > 0) |
||
766 | { |
||
767 | e->segment = TSF_SEGMENT_DELAY; |
||
768 | e->segmentIsExponential = TSF_FALSE; |
||
769 | e->level = 0.0; |
||
770 | e->slope = 0.0; |
||
771 | return; |
||
772 | } |
||
773 | /* fall through */ |
||
774 | case TSF_SEGMENT_DELAY: |
||
775 | e->samplesUntilNextSegment = (int)(e->parameters.attack * outSampleRate); |
||
776 | if (e->samplesUntilNextSegment > 0) |
||
777 | { |
||
778 | if (!e->isAmpEnv) |
||
779 | { |
||
780 | //mod env attack duration scales with velocity (velocity of 1 is full duration, max velocity is 0.125 times duration) |
||
781 | e->samplesUntilNextSegment = (int)(e->parameters.attack * ((145 - e->midiVelocity) / 144.0f) * outSampleRate); |
||
782 | } |
||
783 | e->segment = TSF_SEGMENT_ATTACK; |
||
784 | e->segmentIsExponential = TSF_FALSE; |
||
785 | e->level = 0.0f; |
||
786 | e->slope = 1.0f / e->samplesUntilNextSegment; |
||
787 | return; |
||
788 | } |
||
789 | /* fall through */ |
||
790 | case TSF_SEGMENT_ATTACK: |
||
791 | e->samplesUntilNextSegment = (int)(e->parameters.hold * outSampleRate); |
||
792 | if (e->samplesUntilNextSegment > 0) |
||
793 | { |
||
794 | e->segment = TSF_SEGMENT_HOLD; |
||
795 | e->segmentIsExponential = TSF_FALSE; |
||
796 | e->level = 1.0f; |
||
797 | e->slope = 0.0f; |
||
798 | return; |
||
799 | } |
||
800 | /* fall through */ |
||
801 | case TSF_SEGMENT_HOLD: |
||
802 | e->samplesUntilNextSegment = (int)(e->parameters.decay * outSampleRate); |
||
803 | if (e->samplesUntilNextSegment > 0) |
||
804 | { |
||
805 | e->segment = TSF_SEGMENT_DECAY; |
||
806 | e->level = 1.0f; |
||
807 | if (e->isAmpEnv) |
||
808 | { |
||
809 | // I don't truly understand this; just following what LinuxSampler does. |
||
810 | float mysterySlope = -9.226f / e->samplesUntilNextSegment; |
||
811 | e->slope = TSF_EXPF(mysterySlope); |
||
812 | e->segmentIsExponential = TSF_TRUE; |
||
813 | if (e->parameters.sustain > 0.0f) |
||
814 | { |
||
815 | // Again, this is following LinuxSampler's example, which is similar to |
||
816 | // SF2-style decay, where "decay" specifies the time it would take to |
||
817 | // get to zero, not to the sustain level. The SFZ spec is not that |
||
818 | // specific about what "decay" means, so perhaps it's really supposed |
||
819 | // to specify the time to reach the sustain level. |
||
820 | e->samplesUntilNextSegment = (int)(TSF_LOG(e->parameters.sustain) / mysterySlope); |
||
821 | } |
||
822 | } |
||
823 | else |
||
824 | { |
||
825 | e->slope = -1.0f / e->samplesUntilNextSegment; |
||
826 | e->samplesUntilNextSegment = (int)(e->parameters.decay * (1.0f - e->parameters.sustain) * outSampleRate); |
||
827 | e->segmentIsExponential = TSF_FALSE; |
||
828 | } |
||
829 | return; |
||
830 | } |
||
831 | /* fall through */ |
||
832 | case TSF_SEGMENT_DECAY: |
||
833 | e->segment = TSF_SEGMENT_SUSTAIN; |
||
834 | e->level = e->parameters.sustain; |
||
835 | e->slope = 0.0f; |
||
836 | e->samplesUntilNextSegment = 0x7FFFFFFF; |
||
837 | e->segmentIsExponential = TSF_FALSE; |
||
838 | return; |
||
839 | case TSF_SEGMENT_SUSTAIN: |
||
840 | e->segment = TSF_SEGMENT_RELEASE; |
||
841 | e->samplesUntilNextSegment = (int)((e->parameters.release <= 0 ? TSF_FASTRELEASETIME : e->parameters.release) * outSampleRate); |
||
842 | if (e->isAmpEnv) |
||
843 | { |
||
844 | // I don't truly understand this; just following what LinuxSampler does. |
||
845 | float mysterySlope = -9.226f / e->samplesUntilNextSegment; |
||
846 | e->slope = TSF_EXPF(mysterySlope); |
||
847 | e->segmentIsExponential = TSF_TRUE; |
||
848 | } |
||
849 | else |
||
850 | { |
||
851 | e->slope = -e->level / e->samplesUntilNextSegment; |
||
852 | e->segmentIsExponential = TSF_FALSE; |
||
853 | } |
||
854 | return; |
||
855 | case TSF_SEGMENT_RELEASE: |
||
856 | default: |
||
857 | e->segment = TSF_SEGMENT_DONE; |
||
858 | e->segmentIsExponential = TSF_FALSE; |
||
859 | e->level = e->slope = 0.0f; |
||
860 | e->samplesUntilNextSegment = 0x7FFFFFF; |
||
861 | } |
||
862 | } |
||
863 | |||
864 | static void tsf_voice_envelope_setup(struct tsf_voice_envelope* e, struct tsf_envelope* new_parameters, int midiNoteNumber, short midiVelocity, TSF_BOOL isAmpEnv, float outSampleRate) |
||
865 | { |
||
866 | e->parameters = *new_parameters; |
||
867 | if (e->parameters.keynumToHold) |
||
868 | { |
||
869 | e->parameters.hold += e->parameters.keynumToHold * (60.0f - midiNoteNumber); |
||
870 | e->parameters.hold = (e->parameters.hold < -10000.0f ? 0.0f : tsf_timecents2Secsf(e->parameters.hold)); |
||
871 | } |
||
872 | if (e->parameters.keynumToDecay) |
||
873 | { |
||
874 | e->parameters.decay += e->parameters.keynumToDecay * (60.0f - midiNoteNumber); |
||
875 | e->parameters.decay = (e->parameters.decay < -10000.0f ? 0.0f : tsf_timecents2Secsf(e->parameters.decay)); |
||
876 | } |
||
877 | e->midiVelocity = midiVelocity; |
||
878 | e->isAmpEnv = isAmpEnv; |
||
879 | tsf_voice_envelope_nextsegment(e, TSF_SEGMENT_NONE, outSampleRate); |
||
880 | } |
||
881 | |||
882 | static void tsf_voice_envelope_process(struct tsf_voice_envelope* e, int numSamples, float outSampleRate) |
||
883 | { |
||
884 | if (e->slope) |
||
885 | { |
||
886 | if (e->segmentIsExponential) e->level *= TSF_POWF(e->slope, (float)numSamples); |
||
887 | else e->level += (e->slope * numSamples); |
||
888 | } |
||
889 | if ((e->samplesUntilNextSegment -= numSamples) <= 0) |
||
890 | tsf_voice_envelope_nextsegment(e, e->segment, outSampleRate); |
||
891 | } |
||
892 | |||
893 | static void tsf_voice_lowpass_setup(struct tsf_voice_lowpass* e, float Fc) |
||
894 | { |
||
895 | // Lowpass filter from http://www.earlevel.com/main/2012/11/26/biquad-c-source-code/ |
||
896 | double K = TSF_TAN(TSF_PI * Fc), KK = K * K; |
||
897 | double norm = 1 / (1 + K * e->QInv + KK); |
||
898 | e->a0 = KK * norm; |
||
899 | e->a1 = 2 * e->a0; |
||
900 | e->b1 = 2 * (KK - 1) * norm; |
||
901 | e->b2 = (1 - K * e->QInv + KK) * norm; |
||
902 | } |
||
903 | |||
904 | static float tsf_voice_lowpass_process(struct tsf_voice_lowpass* e, double In) |
||
905 | { |
||
906 | double Out = In * e->a0 + e->z1; e->z1 = In * e->a1 + e->z2 - e->b1 * Out; e->z2 = In * e->a0 - e->b2 * Out; return (float)Out; |
||
907 | } |
||
908 | |||
909 | static void tsf_voice_lfo_setup(struct tsf_voice_lfo* e, float delay, int freqCents, float outSampleRate) |
||
910 | { |
||
911 | e->samplesUntil = (int)(delay * outSampleRate); |
||
912 | e->delta = (4.0f * tsf_cents2Hertz((float)freqCents) / outSampleRate); |
||
913 | e->level = 0; |
||
914 | } |
||
915 | |||
916 | static void tsf_voice_lfo_process(struct tsf_voice_lfo* e, int blockSamples) |
||
917 | { |
||
918 | if (e->samplesUntil > blockSamples) { e->samplesUntil -= blockSamples; return; } |
||
919 | e->level += e->delta * blockSamples; |
||
920 | if (e->level > 1.0f) { e->delta = -e->delta; e->level = 2.0f - e->level; } |
||
921 | else if (e->level < -1.0f) { e->delta = -e->delta; e->level = -2.0f - e->level; } |
||
922 | } |
||
923 | |||
924 | static void tsf_voice_kill(struct tsf_voice* v) |
||
925 | { |
||
926 | v->playingPreset = -1; |
||
927 | } |
||
928 | |||
929 | static void tsf_voice_end(struct tsf_voice* v, float outSampleRate) |
||
930 | { |
||
931 | tsf_voice_envelope_nextsegment(&v->ampenv, TSF_SEGMENT_SUSTAIN, outSampleRate); |
||
932 | tsf_voice_envelope_nextsegment(&v->modenv, TSF_SEGMENT_SUSTAIN, outSampleRate); |
||
933 | if (v->region->loop_mode == TSF_LOOPMODE_SUSTAIN) |
||
934 | { |
||
935 | // Continue playing, but stop looping. |
||
936 | v->loopEnd = v->loopStart; |
||
937 | } |
||
938 | } |
||
939 | |||
940 | static void tsf_voice_endquick(struct tsf_voice* v, float outSampleRate) |
||
941 | { |
||
942 | v->ampenv.parameters.release = 0.0f; tsf_voice_envelope_nextsegment(&v->ampenv, TSF_SEGMENT_SUSTAIN, outSampleRate); |
||
943 | v->modenv.parameters.release = 0.0f; tsf_voice_envelope_nextsegment(&v->modenv, TSF_SEGMENT_SUSTAIN, outSampleRate); |
||
944 | } |
||
945 | |||
946 | static void tsf_voice_calcpitchratio(struct tsf_voice* v, float pitchShift, float outSampleRate) |
||
947 | { |
||
948 | double note = v->playingKey + v->region->transpose + v->region->tune / 100.0; |
||
949 | double adjustedPitch = v->region->pitch_keycenter + (note - v->region->pitch_keycenter) * (v->region->pitch_keytrack / 100.0); |
||
950 | if (pitchShift) adjustedPitch += pitchShift; |
||
951 | v->pitchInputTimecents = adjustedPitch * 100.0; |
||
952 | v->pitchOutputFactor = v->region->sample_rate / (tsf_timecents2Secsd(v->region->pitch_keycenter * 100.0) * outSampleRate); |
||
953 | } |
||
954 | |||
955 | static void tsf_voice_render(tsf* f, struct tsf_voice* v, float* outputBuffer, int numSamples) |
||
956 | { |
||
957 | struct tsf_region* region = v->region; |
||
958 | float* input = f->fontSamples; |
||
959 | float* outL = outputBuffer; |
||
960 | float* outR = (f->outputmode == TSF_STEREO_UNWEAVED ? outL + numSamples : TSF_NULL); |
||
961 | |||
962 | // Cache some values, to give them at least some chance of ending up in registers. |
||
963 | TSF_BOOL updateModEnv = (region->modEnvToPitch || region->modEnvToFilterFc); |
||
964 | TSF_BOOL updateModLFO = (v->modlfo.delta && (region->modLfoToPitch || region->modLfoToFilterFc || region->modLfoToVolume)); |
||
965 | TSF_BOOL updateVibLFO = (v->viblfo.delta && (region->vibLfoToPitch)); |
||
966 | TSF_BOOL isLooping = (v->loopStart < v->loopEnd); |
||
967 | unsigned int tmpLoopStart = v->loopStart, tmpLoopEnd = v->loopEnd; |
||
968 | double tmpSampleEndDbl = (double)region->end, tmpLoopEndDbl = (double)tmpLoopEnd + 1.0; |
||
969 | double tmpSourceSamplePosition = v->sourceSamplePosition; |
||
970 | struct tsf_voice_lowpass tmpLowpass = v->lowpass; |
||
971 | |||
972 | TSF_BOOL dynamicLowpass = (region->modLfoToFilterFc || region->modEnvToFilterFc); |
||
973 | float tmpSampleRate, tmpInitialFilterFc, tmpModLfoToFilterFc, tmpModEnvToFilterFc; |
||
974 | |||
975 | TSF_BOOL dynamicPitchRatio = (region->modLfoToPitch || region->modEnvToPitch || region->vibLfoToPitch); |
||
976 | double pitchRatio; |
||
977 | float tmpModLfoToPitch, tmpVibLfoToPitch, tmpModEnvToPitch; |
||
978 | |||
979 | TSF_BOOL dynamicGain = (region->modLfoToVolume != 0); |
||
980 | float noteGain = 0, tmpModLfoToVolume; |
||
981 | |||
982 | if (dynamicLowpass) tmpSampleRate = f->outSampleRate, tmpInitialFilterFc = (float)region->initialFilterFc, tmpModLfoToFilterFc = (float)region->modLfoToFilterFc, tmpModEnvToFilterFc = (float)region->modEnvToFilterFc; |
||
983 | else tmpSampleRate = 0, tmpInitialFilterFc = 0, tmpModLfoToFilterFc = 0, tmpModEnvToFilterFc = 0; |
||
984 | |||
985 | if (dynamicPitchRatio) pitchRatio = 0, tmpModLfoToPitch = (float)region->modLfoToPitch, tmpVibLfoToPitch = (float)region->vibLfoToPitch, tmpModEnvToPitch = (float)region->modEnvToPitch; |
||
986 | else pitchRatio = tsf_timecents2Secsd(v->pitchInputTimecents) * v->pitchOutputFactor, tmpModLfoToPitch = 0, tmpVibLfoToPitch = 0, tmpModEnvToPitch = 0; |
||
987 | |||
988 | if (dynamicGain) tmpModLfoToVolume = (float)region->modLfoToVolume * 0.1f; |
||
989 | else noteGain = tsf_decibelsToGain(v->noteGainDB), tmpModLfoToVolume = 0; |
||
990 | |||
991 | while (numSamples) |
||
992 | { |
||
993 | float gainMono, gainLeft, gainRight; |
||
994 | int blockSamples = (numSamples > TSF_RENDER_EFFECTSAMPLEBLOCK ? TSF_RENDER_EFFECTSAMPLEBLOCK : numSamples); |
||
995 | numSamples -= blockSamples; |
||
996 | |||
997 | if (dynamicLowpass) |
||
998 | { |
||
999 | float fres = tmpInitialFilterFc + v->modlfo.level * tmpModLfoToFilterFc + v->modenv.level * tmpModEnvToFilterFc; |
||
1000 | tmpLowpass.active = (fres <= 13500.0f); |
||
1001 | if (tmpLowpass.active) tsf_voice_lowpass_setup(&tmpLowpass, tsf_cents2Hertz(fres) / tmpSampleRate); |
||
1002 | } |
||
1003 | |||
1004 | if (dynamicPitchRatio) |
||
1005 | pitchRatio = tsf_timecents2Secsd(v->pitchInputTimecents + (v->modlfo.level * tmpModLfoToPitch + v->viblfo.level * tmpVibLfoToPitch + v->modenv.level * tmpModEnvToPitch)) * v->pitchOutputFactor; |
||
1006 | |||
1007 | if (dynamicGain) |
||
1008 | noteGain = tsf_decibelsToGain(v->noteGainDB + (v->modlfo.level * tmpModLfoToVolume)); |
||
1009 | |||
1010 | gainMono = noteGain * v->ampenv.level; |
||
1011 | |||
1012 | // Update EG. |
||
1013 | tsf_voice_envelope_process(&v->ampenv, blockSamples, f->outSampleRate); |
||
1014 | if (updateModEnv) tsf_voice_envelope_process(&v->modenv, blockSamples, f->outSampleRate); |
||
1015 | |||
1016 | // Update LFOs. |
||
1017 | if (updateModLFO) tsf_voice_lfo_process(&v->modlfo, blockSamples); |
||
1018 | if (updateVibLFO) tsf_voice_lfo_process(&v->viblfo, blockSamples); |
||
1019 | |||
1020 | switch (f->outputmode) |
||
1021 | { |
||
1022 | case TSF_STEREO_INTERLEAVED: |
||
1023 | gainLeft = gainMono * v->panFactorLeft, gainRight = gainMono * v->panFactorRight; |
||
1024 | while (blockSamples-- && tmpSourceSamplePosition < tmpSampleEndDbl) |
||
1025 | { |
||
1026 | unsigned int pos = (unsigned int)tmpSourceSamplePosition, nextPos = (pos >= tmpLoopEnd && isLooping ? tmpLoopStart : pos + 1); |
||
1027 | |||
1028 | // Simple linear interpolation. |
||
1029 | float alpha = (float)(tmpSourceSamplePosition - pos), val = (input[pos] * (1.0f - alpha) + input[nextPos] * alpha); |
||
1030 | |||
1031 | // Low-pass filter. |
||
1032 | if (tmpLowpass.active) val = tsf_voice_lowpass_process(&tmpLowpass, val); |
||
1033 | |||
1034 | *outL++ += val * gainLeft; |
||
1035 | *outL++ += val * gainRight; |
||
1036 | |||
1037 | // Next sample. |
||
1038 | tmpSourceSamplePosition += pitchRatio; |
||
1039 | if (tmpSourceSamplePosition >= tmpLoopEndDbl && isLooping) tmpSourceSamplePosition -= (tmpLoopEnd - tmpLoopStart + 1.0); |
||
1040 | } |
||
1041 | break; |
||
1042 | |||
1043 | case TSF_STEREO_UNWEAVED: |
||
1044 | gainLeft = gainMono * v->panFactorLeft, gainRight = gainMono * v->panFactorRight; |
||
1045 | while (blockSamples-- && tmpSourceSamplePosition < tmpSampleEndDbl) |
||
1046 | { |
||
1047 | unsigned int pos = (unsigned int)tmpSourceSamplePosition, nextPos = (pos >= tmpLoopEnd && isLooping ? tmpLoopStart : pos + 1); |
||
1048 | |||
1049 | // Simple linear interpolation. |
||
1050 | float alpha = (float)(tmpSourceSamplePosition - pos), val = (input[pos] * (1.0f - alpha) + input[nextPos] * alpha); |
||
1051 | |||
1052 | // Low-pass filter. |
||
1053 | if (tmpLowpass.active) val = tsf_voice_lowpass_process(&tmpLowpass, val); |
||
1054 | |||
1055 | *outL++ += val * gainLeft; |
||
1056 | *outR++ += val * gainRight; |
||
1057 | |||
1058 | // Next sample. |
||
1059 | tmpSourceSamplePosition += pitchRatio; |
||
1060 | if (tmpSourceSamplePosition >= tmpLoopEndDbl && isLooping) tmpSourceSamplePosition -= (tmpLoopEnd - tmpLoopStart + 1.0); |
||
1061 | } |
||
1062 | break; |
||
1063 | |||
1064 | case TSF_MONO: |
||
1065 | while (blockSamples-- && tmpSourceSamplePosition < tmpSampleEndDbl) |
||
1066 | { |
||
1067 | unsigned int pos = (unsigned int)tmpSourceSamplePosition, nextPos = (pos >= tmpLoopEnd && isLooping ? tmpLoopStart : pos + 1); |
||
1068 | |||
1069 | // Simple linear interpolation. |
||
1070 | float alpha = (float)(tmpSourceSamplePosition - pos), val = (input[pos] * (1.0f - alpha) + input[nextPos] * alpha); |
||
1071 | |||
1072 | // Low-pass filter. |
||
1073 | if (tmpLowpass.active) val = tsf_voice_lowpass_process(&tmpLowpass, val); |
||
1074 | |||
1075 | *outL++ += val * gainMono; |
||
1076 | |||
1077 | // Next sample. |
||
1078 | tmpSourceSamplePosition += pitchRatio; |
||
1079 | if (tmpSourceSamplePosition >= tmpLoopEndDbl && isLooping) tmpSourceSamplePosition -= (tmpLoopEnd - tmpLoopStart + 1.0); |
||
1080 | } |
||
1081 | break; |
||
1082 | } |
||
1083 | |||
1084 | if (tmpSourceSamplePosition >= tmpSampleEndDbl || v->ampenv.segment == TSF_SEGMENT_DONE) |
||
1085 | { |
||
1086 | tsf_voice_kill(v); |
||
1087 | return; |
||
1088 | } |
||
1089 | } |
||
1090 | |||
1091 | v->sourceSamplePosition = tmpSourceSamplePosition; |
||
1092 | if (tmpLowpass.active || dynamicLowpass) v->lowpass = tmpLowpass; |
||
1093 | } |
||
1094 | |||
1095 | TSFDEF tsf* tsf_load(struct tsf_stream* stream) |
||
1096 | { |
||
1097 | tsf* res = TSF_NULL; |
||
1098 | struct tsf_riffchunk chunkHead; |
||
1099 | struct tsf_riffchunk chunkList; |
||
1100 | struct tsf_hydra hydra; |
||
1101 | float* fontSamples = TSF_NULL; |
||
1102 | unsigned int fontSampleCount = 0; |
||
1103 | |||
1104 | if (!tsf_riffchunk_read(TSF_NULL, &chunkHead, stream) || !TSF_FourCCEquals(chunkHead.id, "sfbk")) |
||
1105 | { |
||
1106 | //if (e) *e = TSF_INVALID_NOSF2HEADER; |
||
1107 | return res; |
||
1108 | } |
||
1109 | |||
1110 | // Read hydra and locate sample data. |
||
1111 | TSF_MEMSET(&hydra, 0, sizeof(hydra)); |
||
1112 | while (tsf_riffchunk_read(&chunkHead, &chunkList, stream)) |
||
1113 | { |
||
1114 | struct tsf_riffchunk chunk; |
||
1115 | if (TSF_FourCCEquals(chunkList.id, "pdta")) |
||
1116 | { |
||
1117 | while (tsf_riffchunk_read(&chunkList, &chunk, stream)) |
||
1118 | { |
||
1119 | #define HandleChunk(chunkName) (TSF_FourCCEquals(chunk.id, #chunkName) && !(chunk.size % chunkName##SizeInFile)) \ |
||
1120 | { \ |
||
1121 | int num = chunk.size / chunkName##SizeInFile, i; \ |
||
1122 | hydra.chunkName##Num = num; \ |
||
1123 | hydra.chunkName##s = (struct tsf_hydra_##chunkName*)TSF_MALLOC(num * sizeof(struct tsf_hydra_##chunkName)); \ |
||
1124 | for (i = 0; i < num; ++i) tsf_hydra_read_##chunkName(&hydra.chunkName##s[i], stream); \ |
||
1125 | } |
||
1126 | enum |
||
1127 | { |
||
1128 | phdrSizeInFile = 38, pbagSizeInFile = 4, pmodSizeInFile = 10, |
||
1129 | pgenSizeInFile = 4, instSizeInFile = 22, ibagSizeInFile = 4, |
||
1130 | imodSizeInFile = 10, igenSizeInFile = 4, shdrSizeInFile = 46 |
||
1131 | }; |
||
1132 | if HandleChunk(phdr) else if HandleChunk(pbag) else if HandleChunk(pmod) |
||
1133 | else if HandleChunk(pgen) else if HandleChunk(inst) else if HandleChunk(ibag) |
||
1134 | else if HandleChunk(imod) else if HandleChunk(igen) else if HandleChunk(shdr) |
||
1135 | else stream->skip(stream->data, chunk.size); |
||
1136 | #undef HandleChunk |
||
1137 | } |
||
1138 | } |
||
1139 | else if (TSF_FourCCEquals(chunkList.id, "sdta")) |
||
1140 | { |
||
1141 | while (tsf_riffchunk_read(&chunkList, &chunk, stream)) |
||
1142 | { |
||
1143 | if (TSF_FourCCEquals(chunk.id, "smpl")) |
||
1144 | { |
||
1145 | tsf_load_samples(&fontSamples, &fontSampleCount, &chunk, stream); |
||
1146 | } |
||
1147 | else stream->skip(stream->data, chunk.size); |
||
1148 | } |
||
1149 | } |
||
1150 | else stream->skip(stream->data, chunkList.size); |
||
1151 | } |
||
1152 | if (!hydra.phdrs || !hydra.pbags || !hydra.pmods || !hydra.pgens || !hydra.insts || !hydra.ibags || !hydra.imods || !hydra.igens || !hydra.shdrs) |
||
1153 | { |
||
1154 | //if (e) *e = TSF_INVALID_INCOMPLETE; |
||
1155 | } |
||
1156 | else if (fontSamples == TSF_NULL) |
||
1157 | { |
||
1158 | //if (e) *e = TSF_INVALID_NOSAMPLEDATA; |
||
1159 | } |
||
1160 | else |
||
1161 | { |
||
1162 | res = (tsf*)TSF_MALLOC(sizeof(tsf)); |
||
1163 | TSF_MEMSET(res, 0, sizeof(tsf)); |
||
1164 | res->presetNum = hydra.phdrNum - 1; |
||
1165 | res->presets = (struct tsf_preset*)TSF_MALLOC(res->presetNum * sizeof(struct tsf_preset)); |
||
1166 | res->fontSamples = fontSamples; |
||
1167 | res->outSampleRate = 44100.0f; |
||
1168 | fontSamples = TSF_NULL; //don't free below |
||
1169 | tsf_load_presets(res, &hydra, fontSampleCount); |
||
1170 | } |
||
1171 | TSF_FREE(hydra.phdrs); TSF_FREE(hydra.pbags); TSF_FREE(hydra.pmods); |
||
1172 | TSF_FREE(hydra.pgens); TSF_FREE(hydra.insts); TSF_FREE(hydra.ibags); |
||
1173 | TSF_FREE(hydra.imods); TSF_FREE(hydra.igens); TSF_FREE(hydra.shdrs); |
||
1174 | TSF_FREE(fontSamples); |
||
1175 | return res; |
||
1176 | } |
||
1177 | |||
1178 | TSFDEF void tsf_close(tsf* f) |
||
1179 | { |
||
1180 | struct tsf_preset *preset, *presetEnd; |
||
1181 | if (!f) return; |
||
1182 | for (preset = f->presets, presetEnd = preset + f->presetNum; preset != presetEnd; preset++) |
||
1183 | TSF_FREE(preset->regions); |
||
1184 | TSF_FREE(f->presets); |
||
1185 | TSF_FREE(f->fontSamples); |
||
1186 | TSF_FREE(f->voices); |
||
1187 | if (f->channels) { TSF_FREE(f->channels->channels); TSF_FREE(f->channels); } |
||
1188 | TSF_FREE(f->outputSamples); |
||
1189 | TSF_FREE(f); |
||
1190 | } |
||
1191 | |||
1192 | TSFDEF void tsf_reset(tsf* f) |
||
1193 | { |
||
1194 | struct tsf_voice *v = f->voices, *vEnd = v + f->voiceNum; |
||
1195 | for (; v != vEnd; v++) |
||
1196 | if (v->playingPreset != -1 && (v->ampenv.segment < TSF_SEGMENT_RELEASE || v->ampenv.parameters.release)) |
||
1197 | tsf_voice_endquick(v, f->outSampleRate); |
||
1198 | if (f->channels) { TSF_FREE(f->channels->channels); TSF_FREE(f->channels); f->channels = TSF_NULL; } |
||
1199 | } |
||
1200 | |||
1201 | TSFDEF int tsf_get_presetindex(const tsf* f, int bank, int preset_number) |
||
1202 | { |
||
1203 | const struct tsf_preset *presets; |
||
1204 | int i, iMax; |
||
1205 | for (presets = f->presets, i = 0, iMax = f->presetNum; i < iMax; i++) |
||
1206 | if (presets[i].preset == preset_number && presets[i].bank == bank) |
||
1207 | return i; |
||
1208 | return -1; |
||
1209 | } |
||
1210 | |||
1211 | TSFDEF int tsf_get_presetcount(const tsf* f) |
||
1212 | { |
||
1213 | return f->presetNum; |
||
1214 | } |
||
1215 | |||
1216 | TSFDEF const char* tsf_get_presetname(const tsf* f, int preset) |
||
1217 | { |
||
1218 | return (preset < 0 || preset >= f->presetNum ? TSF_NULL : f->presets[preset].presetName); |
||
1219 | } |
||
1220 | |||
1221 | TSFDEF const char* tsf_bank_get_presetname(const tsf* f, int bank, int preset_number) |
||
1222 | { |
||
1223 | return tsf_get_presetname(f, tsf_get_presetindex(f, bank, preset_number)); |
||
1224 | } |
||
1225 | |||
1226 | TSFDEF void tsf_set_output(tsf* f, enum TSFOutputMode outputmode, int samplerate, float global_gain_db) |
||
1227 | { |
||
1228 | f->outputmode = outputmode; |
||
1229 | f->outSampleRate = (float)(samplerate >= 1 ? samplerate : 44100.0f); |
||
1230 | f->globalGainDB = global_gain_db; |
||
1231 | } |
||
1232 | |||
1233 | TSFDEF void tsf_note_on(tsf* f, int preset_index, int key, float vel) |
||
1234 | { |
||
1235 | short midiVelocity = (short)(vel * 127); |
||
1236 | int voicePlayIndex; |
||
1237 | struct tsf_region *region, *regionEnd; |
||
1238 | |||
1239 | if (preset_index < 0 || preset_index >= f->presetNum) return; |
||
1240 | if (vel <= 0.0f) { tsf_note_off(f, preset_index, key); return; } |
||
1241 | |||
1242 | // Play all matching regions. |
||
1243 | voicePlayIndex = f->voicePlayIndex++; |
||
1244 | for (region = f->presets[preset_index].regions, regionEnd = region + f->presets[preset_index].regionNum; region != regionEnd; region++) |
||
1245 | { |
||
1246 | struct tsf_voice *voice, *v, *vEnd; TSF_BOOL doLoop; float filterQDB; |
||
1247 | if (key < region->lokey || key > region->hikey || midiVelocity < region->lovel || midiVelocity > region->hivel) continue; |
||
1248 | |||
1249 | voice = TSF_NULL, v = f->voices, vEnd = v + f->voiceNum; |
||
1250 | if (region->group) |
||
1251 | { |
||
1252 | for (; v != vEnd; v++) |
||
1253 | if (v->playingPreset == preset_index && v->region->group == region->group) tsf_voice_endquick(v, f->outSampleRate); |
||
1254 | else if (v->playingPreset == -1 && !voice) voice = v; |
||
1255 | } |
||
1256 | else for (; v != vEnd; v++) if (v->playingPreset == -1) { voice = v; break; } |
||
1257 | |||
1258 | if (!voice) |
||
1259 | { |
||
1260 | f->voiceNum += 4; |
||
1261 | f->voices = (struct tsf_voice*)TSF_REALLOC(f->voices, f->voiceNum * sizeof(struct tsf_voice)); |
||
1262 | voice = &f->voices[f->voiceNum - 4]; |
||
1263 | voice[1].playingPreset = voice[2].playingPreset = voice[3].playingPreset = -1; |
||
1264 | } |
||
1265 | |||
1266 | voice->region = region; |
||
1267 | voice->playingPreset = preset_index; |
||
1268 | voice->playingKey = key; |
||
1269 | voice->playIndex = voicePlayIndex; |
||
8754 | terminx | 1270 | voice->noteGainDB = f->globalGainDB - clamp(region->attenuation, 0.f, 144.f) - tsf_gainToDecibels(1.0f / vel); |
8752 | terminx | 1271 | |
1272 | if (f->channels) |
||
1273 | { |
||
1274 | f->channels->setupVoice(f, voice); |
||
1275 | } |
||
1276 | else |
||
1277 | { |
||
1278 | tsf_voice_calcpitchratio(voice, 0, f->outSampleRate); |
||
1279 | // The SFZ spec is silent about the pan curve, but a 3dB pan law seems common. This sqrt() curve matches what Dimension LE does; Alchemy Free seems closer to sin(adjustedPan * pi/2). |
||
1280 | voice->panFactorLeft = TSF_SQRTF(0.5f - region->pan); |
||
1281 | voice->panFactorRight = TSF_SQRTF(0.5f + region->pan); |
||
1282 | } |
||
1283 | |||
1284 | // Offset/end. |
||
1285 | voice->sourceSamplePosition = region->offset; |
||
1286 | |||
1287 | // Loop. |
||
1288 | doLoop = (region->loop_mode != TSF_LOOPMODE_NONE && region->loop_start < region->loop_end); |
||
1289 | voice->loopStart = (doLoop ? region->loop_start : 0); |
||
1290 | voice->loopEnd = (doLoop ? region->loop_end : 0); |
||
1291 | |||
1292 | // Setup envelopes. |
||
1293 | tsf_voice_envelope_setup(&voice->ampenv, ®ion->ampenv, key, midiVelocity, TSF_TRUE, f->outSampleRate); |
||
1294 | tsf_voice_envelope_setup(&voice->modenv, ®ion->modenv, key, midiVelocity, TSF_FALSE, f->outSampleRate); |
||
1295 | |||
1296 | // Setup lowpass filter. |
||
1297 | filterQDB = region->initialFilterQ / 10.0f; |
||
1298 | voice->lowpass.QInv = 1.0 / TSF_POW(10.0, (filterQDB / 20.0)); |
||
1299 | voice->lowpass.z1 = voice->lowpass.z2 = 0; |
||
1300 | voice->lowpass.active = (region->initialFilterFc <= 13500); |
||
1301 | if (voice->lowpass.active) tsf_voice_lowpass_setup(&voice->lowpass, tsf_cents2Hertz((float)region->initialFilterFc) / f->outSampleRate); |
||
1302 | |||
1303 | // Setup LFO filters. |
||
1304 | tsf_voice_lfo_setup(&voice->modlfo, region->delayModLFO, region->freqModLFO, f->outSampleRate); |
||
1305 | tsf_voice_lfo_setup(&voice->viblfo, region->delayVibLFO, region->freqVibLFO, f->outSampleRate); |
||
1306 | } |
||
1307 | } |
||
1308 | |||
1309 | TSFDEF int tsf_bank_note_on(tsf* f, int bank, int preset_number, int key, float vel) |
||
1310 | { |
||
1311 | int preset_index = tsf_get_presetindex(f, bank, preset_number); |
||
1312 | if (preset_index == -1) return 0; |
||
1313 | tsf_note_on(f, preset_index, key, vel); |
||
1314 | return 1; |
||
1315 | } |
||
1316 | |||
1317 | TSFDEF void tsf_note_off(tsf* f, int preset_index, int key) |
||
1318 | { |
||
1319 | struct tsf_voice *v = f->voices, *vEnd = v + f->voiceNum, *vMatchFirst = TSF_NULL, *vMatchLast = TSF_NULL; |
||
1320 | for (; v != vEnd; v++) |
||
1321 | { |
||
1322 | //Find the first and last entry in the voices list with matching preset, key and look up the smallest play index |
||
1323 | if (v->playingPreset != preset_index || v->playingKey != key || v->ampenv.segment >= TSF_SEGMENT_RELEASE) continue; |
||
1324 | else if (!vMatchFirst || v->playIndex < vMatchFirst->playIndex) vMatchFirst = vMatchLast = v; |
||
1325 | else if (v->playIndex == vMatchFirst->playIndex) vMatchLast = v; |
||
1326 | } |
||
1327 | if (!vMatchFirst) return; |
||
1328 | for (v = vMatchFirst; v <= vMatchLast; v++) |
||
1329 | { |
||
1330 | //Stop all voices with matching preset, key and the smallest play index which was enumerated above |
||
1331 | if (v != vMatchFirst && v != vMatchLast && |
||
1332 | (v->playIndex != vMatchFirst->playIndex || v->playingPreset != preset_index || v->playingKey != key || v->ampenv.segment >= TSF_SEGMENT_RELEASE)) continue; |
||
1333 | tsf_voice_end(v, f->outSampleRate); |
||
1334 | } |
||
1335 | } |
||
1336 | |||
1337 | TSFDEF int tsf_bank_note_off(tsf* f, int bank, int preset_number, int key) |
||
1338 | { |
||
1339 | int preset_index = tsf_get_presetindex(f, bank, preset_number); |
||
1340 | if (preset_index == -1) return 0; |
||
1341 | tsf_note_off(f, preset_index, key); |
||
1342 | return 1; |
||
1343 | } |
||
1344 | |||
1345 | TSFDEF void tsf_note_off_all(tsf* f) |
||
1346 | { |
||
1347 | struct tsf_voice *v = f->voices, *vEnd = v + f->voiceNum; |
||
1348 | for (; v != vEnd; v++) if (v->playingPreset != -1 && v->ampenv.segment < TSF_SEGMENT_RELEASE) |
||
1349 | tsf_voice_end(v, f->outSampleRate); |
||
1350 | } |
||
1351 | |||
1352 | TSFDEF int tsf_active_voice_count(tsf* f) |
||
1353 | { |
||
1354 | int count = 0; |
||
1355 | struct tsf_voice *v = f->voices, *vEnd = v + f->voiceNum; |
||
1356 | for (; v != vEnd; v++) if (v->playingPreset != -1) count++; |
||
1357 | return count; |
||
1358 | } |
||
1359 | |||
1360 | TSFDEF void tsf_render_short(tsf* f, short* buffer, int samples, int flag_mixing) |
||
1361 | { |
||
1362 | float *floatSamples; |
||
1363 | int channelSamples = (f->outputmode == TSF_MONO ? 1 : 2) * samples, floatBufferSize = channelSamples * sizeof(float); |
||
1364 | short* bufferEnd = buffer + channelSamples; |
||
1365 | if (floatBufferSize > f->outputSampleSize) |
||
1366 | { |
||
1367 | TSF_FREE(f->outputSamples); |
||
1368 | f->outputSamples = (float*)TSF_MALLOC(floatBufferSize); |
||
1369 | f->outputSampleSize = floatBufferSize; |
||
1370 | } |
||
1371 | |||
1372 | tsf_render_float(f, f->outputSamples, samples, TSF_FALSE); |
||
1373 | |||
1374 | floatSamples = f->outputSamples; |
||
1375 | if (flag_mixing) |
||
1376 | while (buffer != bufferEnd) |
||
1377 | { |
||
1378 | float v = *floatSamples++; |
||
1379 | int vi = *buffer + (v < -1.00004566f ? (int)-32768 : (v > 1.00001514f ? (int)32767 : (int)(v * 32767.5f))); |
||
1380 | *buffer++ = (vi < -32768 ? (short)-32768 : (vi > 32767 ? (short)32767 : (short)vi)); |
||
1381 | } |
||
1382 | else |
||
1383 | while (buffer != bufferEnd) |
||
1384 | { |
||
1385 | float v = *floatSamples++; |
||
1386 | *buffer++ = (v < -1.00004566f ? (short)-32768 : (v > 1.00001514f ? (short)32767 : (short)(v * 32767.5f))); |
||
1387 | } |
||
1388 | } |
||
1389 | |||
1390 | TSFDEF void tsf_render_float(tsf* f, float* buffer, int samples, int flag_mixing) |
||
1391 | { |
||
1392 | struct tsf_voice *v = f->voices, *vEnd = v + f->voiceNum; |
||
1393 | if (!flag_mixing) TSF_MEMSET(buffer, 0, (f->outputmode == TSF_MONO ? 1 : 2) * sizeof(float) * samples); |
||
1394 | for (; v != vEnd; v++) |
||
1395 | if (v->playingPreset != -1) |
||
1396 | tsf_voice_render(f, v, buffer, samples); |
||
1397 | } |
||
1398 | |||
1399 | static void tsf_channel_setup_voice(tsf* f, struct tsf_voice* v) |
||
1400 | { |
||
1401 | struct tsf_channel* c = &f->channels->channels[f->channels->activeChannel]; |
||
1402 | float newpan = v->region->pan + c->panOffset; |
||
1403 | v->playingChannel = f->channels->activeChannel; |
||
1404 | v->noteGainDB += c->gainDB; |
||
1405 | tsf_voice_calcpitchratio(v, (c->pitchWheel == 8192 ? c->tuning : ((c->pitchWheel / 16383.0f * c->pitchRange * 2.0f) - c->pitchRange + c->tuning)), f->outSampleRate); |
||
1406 | if (newpan <= -0.5f) { v->panFactorLeft = 1.0f; v->panFactorRight = 0.0f; } |
||
1407 | else if (newpan >= 0.5f) { v->panFactorLeft = 0.0f; v->panFactorRight = 1.0f; } |
||
1408 | else { v->panFactorLeft = TSF_SQRTF(0.5f - newpan); v->panFactorRight = TSF_SQRTF(0.5f + newpan); } |
||
1409 | } |
||
1410 | |||
1411 | static struct tsf_channel* tsf_channel_init(tsf* f, int channel) |
||
1412 | { |
||
1413 | int i; |
||
1414 | if (f->channels && channel < f->channels->channelNum) return &f->channels->channels[channel]; |
||
1415 | if (!f->channels) |
||
1416 | { |
||
1417 | f->channels = (struct tsf_channels*)TSF_MALLOC(sizeof(struct tsf_channels)); |
||
1418 | f->channels->setupVoice = &tsf_channel_setup_voice; |
||
1419 | f->channels->channels = NULL; |
||
1420 | f->channels->channelNum = 0; |
||
1421 | f->channels->activeChannel = 0; |
||
1422 | } |
||
1423 | i = f->channels->channelNum; |
||
1424 | f->channels->channelNum = channel + 1; |
||
1425 | f->channels->channels = (struct tsf_channel*)TSF_REALLOC(f->channels->channels, f->channels->channelNum * sizeof(struct tsf_channel)); |
||
1426 | for (; i <= channel; i++) |
||
1427 | { |
||
1428 | struct tsf_channel* c = &f->channels->channels[i]; |
||
1429 | c->presetIndex = c->bank = 0; |
||
1430 | c->pitchWheel = c->midiPan = 8192; |
||
1431 | c->midiVolume = c->midiExpression = 16383; |
||
1432 | c->midiRPN = 0xFFFF; |
||
1433 | c->midiData = 0; |
||
1434 | c->panOffset = 0.0f; |
||
1435 | c->gainDB = 0.0f; |
||
1436 | c->pitchRange = 2.0f; |
||
1437 | c->tuning = 0.0f; |
||
1438 | } |
||
1439 | return &f->channels->channels[channel]; |
||
1440 | } |
||
1441 | |||
1442 | static void tsf_channel_applypitch(tsf* f, int channel, struct tsf_channel* c) |
||
1443 | { |
||
1444 | struct tsf_voice *v, *vEnd; |
||
1445 | float pitchShift = (c->pitchWheel == 8192 ? c->tuning : ((c->pitchWheel / 16383.0f * c->pitchRange * 2.0f) - c->pitchRange + c->tuning)); |
||
1446 | for (v = f->voices, vEnd = v + f->voiceNum; v != vEnd; v++) |
||
1447 | if (v->playingChannel == channel && v->playingPreset != -1) |
||
1448 | tsf_voice_calcpitchratio(v, pitchShift, f->outSampleRate); |
||
1449 | } |
||
1450 | |||
1451 | TSFDEF void tsf_channel_set_presetindex(tsf* f, int channel, int preset_index) |
||
1452 | { |
||
1453 | tsf_channel_init(f, channel)->presetIndex = (unsigned short)preset_index; |
||
1454 | } |
||
1455 | |||
1456 | TSFDEF int tsf_channel_set_presetnumber(tsf* f, int channel, int preset_number, int flag_mididrums) |
||
1457 | { |
||
1458 | struct tsf_channel *c = tsf_channel_init(f, channel); |
||
1459 | int preset_index; |
||
1460 | if (flag_mididrums) |
||
1461 | { |
||
1462 | preset_index = tsf_get_presetindex(f, 128 | (c->bank & 0x7FFF), preset_number); |
||
1463 | if (preset_index == -1) preset_index = tsf_get_presetindex(f, 128, preset_number); |
||
1464 | if (preset_index == -1) preset_index = tsf_get_presetindex(f, 128, 0); |
||
1465 | if (preset_index == -1) preset_index = tsf_get_presetindex(f, (c->bank & 0x7FFF), preset_number); |
||
1466 | } |
||
1467 | else preset_index = tsf_get_presetindex(f, (c->bank & 0x7FFF), preset_number); |
||
1468 | if (preset_index == -1) preset_index = tsf_get_presetindex(f, 0, preset_number); |
||
1469 | if (preset_index != -1) |
||
1470 | { |
||
1471 | c->presetIndex = (unsigned short)preset_index; |
||
1472 | return 1; |
||
1473 | } |
||
1474 | return 0; |
||
1475 | } |
||
1476 | |||
1477 | TSFDEF void tsf_channel_set_bank(tsf* f, int channel, int bank) |
||
1478 | { |
||
1479 | tsf_channel_init(f, channel)->bank = (unsigned short)bank; |
||
1480 | } |
||
1481 | |||
1482 | TSFDEF int tsf_channel_set_bank_preset(tsf* f, int channel, int bank, int preset_number) |
||
1483 | { |
||
1484 | struct tsf_channel *c = tsf_channel_init(f, channel); |
||
1485 | int preset_index = tsf_get_presetindex(f, bank, preset_number); |
||
1486 | if (preset_index == -1) return 0; |
||
1487 | c->presetIndex = (unsigned short)preset_index; |
||
1488 | c->bank = (unsigned short)bank; |
||
1489 | return 1; |
||
1490 | } |
||
1491 | |||
1492 | TSFDEF void tsf_channel_set_pan(tsf* f, int channel, float pan) |
||
1493 | { |
||
1494 | struct tsf_voice *v, *vEnd; |
||
1495 | for (v = f->voices, vEnd = v + f->voiceNum; v != vEnd; v++) |
||
1496 | if (v->playingChannel == channel && v->playingPreset != -1) |
||
1497 | { |
||
1498 | float newpan = v->region->pan + pan - 0.5f; |
||
1499 | if (newpan <= -0.5f) { v->panFactorLeft = 1.0f; v->panFactorRight = 0.0f; } |
||
1500 | else if (newpan >= 0.5f) { v->panFactorLeft = 0.0f; v->panFactorRight = 1.0f; } |
||
1501 | else { v->panFactorLeft = TSF_SQRTF(0.5f - newpan); v->panFactorRight = TSF_SQRTF(0.5f + newpan); } |
||
1502 | } |
||
1503 | tsf_channel_init(f, channel)->panOffset = pan - 0.5f; |
||
1504 | } |
||
1505 | |||
1506 | TSFDEF void tsf_channel_set_volume(tsf* f, int channel, float volume) |
||
1507 | { |
||
1508 | struct tsf_channel *c = tsf_channel_init(f, channel); |
||
1509 | float gainDB = tsf_gainToDecibels(volume), gainDBChange = gainDB - c->gainDB; |
||
1510 | struct tsf_voice *v, *vEnd; |
||
1511 | if (gainDBChange == 0) return; |
||
1512 | for (v = f->voices, vEnd = v + f->voiceNum; v != vEnd; v++) |
||
1513 | if (v->playingChannel == channel && v->playingPreset != -1) |
||
1514 | v->noteGainDB += gainDBChange; |
||
1515 | c->gainDB = gainDB; |
||
1516 | } |
||
1517 | |||
1518 | TSFDEF void tsf_channel_set_pitchwheel(tsf* f, int channel, int pitch_wheel) |
||
1519 | { |
||
1520 | struct tsf_channel *c = tsf_channel_init(f, channel); |
||
1521 | if (c->pitchWheel == pitch_wheel) return; |
||
1522 | c->pitchWheel = (unsigned short)pitch_wheel; |
||
1523 | tsf_channel_applypitch(f, channel, c); |
||
1524 | } |
||
1525 | |||
1526 | TSFDEF void tsf_channel_set_pitchrange(tsf* f, int channel, float pitch_range) |
||
1527 | { |
||
1528 | struct tsf_channel *c = tsf_channel_init(f, channel); |
||
1529 | if (c->pitchRange == pitch_range) return; |
||
1530 | c->pitchRange = pitch_range; |
||
1531 | if (c->pitchWheel != 8192) tsf_channel_applypitch(f, channel, c); |
||
1532 | } |
||
1533 | |||
1534 | TSFDEF void tsf_channel_set_tuning(tsf* f, int channel, float tuning) |
||
1535 | { |
||
1536 | struct tsf_channel *c = tsf_channel_init(f, channel); |
||
1537 | if (c->tuning == tuning) return; |
||
1538 | c->tuning = tuning; |
||
1539 | tsf_channel_applypitch(f, channel, c); |
||
1540 | } |
||
1541 | |||
1542 | TSFDEF void tsf_channel_note_on(tsf* f, int channel, int key, float vel) |
||
1543 | { |
||
1544 | if (!f->channels || channel >= f->channels->channelNum) return; |
||
1545 | f->channels->activeChannel = channel; |
||
1546 | tsf_note_on(f, f->channels->channels[channel].presetIndex, key, vel); |
||
1547 | } |
||
1548 | |||
1549 | TSFDEF void tsf_channel_note_off(tsf* f, int channel, int key) |
||
1550 | { |
||
1551 | struct tsf_voice *v = f->voices, *vEnd = v + f->voiceNum, *vMatchFirst = TSF_NULL, *vMatchLast = TSF_NULL; |
||
1552 | for (; v != vEnd; v++) |
||
1553 | { |
||
1554 | //Find the first and last entry in the voices list with matching channel, key and look up the smallest play index |
||
1555 | if (v->playingPreset == -1 || v->playingChannel != channel || v->playingKey != key || v->ampenv.segment >= TSF_SEGMENT_RELEASE) continue; |
||
1556 | else if (!vMatchFirst || v->playIndex < vMatchFirst->playIndex) vMatchFirst = vMatchLast = v; |
||
1557 | else if (v->playIndex == vMatchFirst->playIndex) vMatchLast = v; |
||
1558 | } |
||
1559 | if (!vMatchFirst) return; |
||
1560 | for (v = vMatchFirst; v <= vMatchLast; v++) |
||
1561 | { |
||
1562 | //Stop all voices with matching channel, key and the smallest play index which was enumerated above |
||
1563 | if (v != vMatchFirst && v != vMatchLast && |
||
1564 | (v->playIndex != vMatchFirst->playIndex || v->playingPreset == -1 || v->playingChannel != channel || v->playingKey != key || v->ampenv.segment >= TSF_SEGMENT_RELEASE)) continue; |
||
1565 | tsf_voice_end(v, f->outSampleRate); |
||
1566 | } |
||
1567 | } |
||
1568 | |||
1569 | TSFDEF void tsf_channel_note_off_all(tsf* f, int channel) |
||
1570 | { |
||
1571 | struct tsf_voice *v = f->voices, *vEnd = v + f->voiceNum; |
||
1572 | for (; v != vEnd; v++) |
||
1573 | if (v->playingPreset != -1 && v->playingChannel == channel && v->ampenv.segment < TSF_SEGMENT_RELEASE) |
||
1574 | tsf_voice_end(v, f->outSampleRate); |
||
1575 | } |
||
1576 | |||
1577 | TSFDEF void tsf_channel_sounds_off_all(tsf* f, int channel) |
||
1578 | { |
||
1579 | struct tsf_voice *v = f->voices, *vEnd = v + f->voiceNum; |
||
1580 | for (; v != vEnd; v++) |
||
1581 | if (v->playingPreset != -1 && v->playingChannel == channel && (v->ampenv.segment < TSF_SEGMENT_RELEASE || v->ampenv.parameters.release)) |
||
1582 | tsf_voice_endquick(v, f->outSampleRate); |
||
1583 | } |
||
1584 | |||
1585 | TSFDEF void tsf_channel_midi_control(tsf* f, int channel, int controller, int control_value) |
||
1586 | { |
||
1587 | struct tsf_channel* c = tsf_channel_init(f, channel); |
||
1588 | switch (controller) |
||
1589 | { |
||
1590 | case 7 /*VOLUME_MSB*/ : c->midiVolume = (unsigned short)((c->midiVolume & 0x7F ) | (control_value << 7)); goto TCMC_SET_VOLUME; |
||
1591 | case 39 /*VOLUME_LSB*/ : c->midiVolume = (unsigned short)((c->midiVolume & 0x3F80) | control_value); goto TCMC_SET_VOLUME; |
||
1592 | case 11 /*EXPRESSION_MSB*/ : c->midiExpression = (unsigned short)((c->midiExpression & 0x7F ) | (control_value << 7)); goto TCMC_SET_VOLUME; |
||
1593 | case 43 /*EXPRESSION_LSB*/ : c->midiExpression = (unsigned short)((c->midiExpression & 0x3F80) | control_value); goto TCMC_SET_VOLUME; |
||
1594 | case 10 /*PAN_MSB*/ : c->midiPan = (unsigned short)((c->midiPan & 0x7F ) | (control_value << 7)); goto TCMC_SET_PAN; |
||
1595 | case 42 /*PAN_LSB*/ : c->midiPan = (unsigned short)((c->midiPan & 0x3F80) | control_value); goto TCMC_SET_PAN; |
||
1596 | case 6 /*DATA_ENTRY_MSB*/ : c->midiData = (unsigned short)((c->midiData & 0x7F) | (control_value << 7)); goto TCMC_SET_DATA; |
||
1597 | case 38 /*DATA_ENTRY_LSB*/ : c->midiData = (unsigned short)((c->midiData & 0x3F80) | control_value); goto TCMC_SET_DATA; |
||
1598 | case 0 /*BANK_SELECT_MSB*/ : c->bank = (unsigned short)(0x8000 | control_value); return; //bank select MSB alone acts like LSB |
||
1599 | case 32 /*BANK_SELECT_LSB*/ : c->bank = (unsigned short)((c->bank & 0x8000 ? ((c->bank & 0x7F) << 7) : 0) | control_value); return; |
||
1600 | case 101 /*RPN_MSB*/ : c->midiRPN = (unsigned short)(((c->midiRPN == 0xFFFF ? 0 : c->midiRPN) & 0x7F ) | (control_value << 7)); return; |
||
1601 | case 100 /*RPN_LSB*/ : c->midiRPN = (unsigned short)(((c->midiRPN == 0xFFFF ? 0 : c->midiRPN) & 0x3F80) | control_value); return; |
||
1602 | case 98 /*NRPN_LSB*/ : c->midiRPN = 0xFFFF; return; |
||
1603 | case 99 /*NRPN_MSB*/ : c->midiRPN = 0xFFFF; return; |
||
1604 | case 120 /*ALL_SOUND_OFF*/ : tsf_channel_sounds_off_all(f, channel); return; |
||
1605 | case 123 /*ALL_NOTES_OFF*/ : tsf_channel_note_off_all(f, channel); return; |
||
1606 | case 121 /*ALL_CTRL_OFF*/ : |
||
1607 | c->midiVolume = c->midiExpression = 16383; |
||
1608 | c->midiPan = 8192; |
||
1609 | c->bank = 0; |
||
1610 | tsf_channel_set_volume(f, channel, 1.0f); |
||
1611 | tsf_channel_set_pan(f, channel, 0.5f); |
||
1612 | tsf_channel_set_pitchrange(f, channel, 2.0f); |
||
1613 | return; |
||
1614 | } |
||
1615 | return; |
||
1616 | TCMC_SET_VOLUME: |
||
1617 | //Raising to the power of 3 seems to result in a decent sounding volume curve for MIDI |
||
1618 | tsf_channel_set_volume(f, channel, TSF_POWF((c->midiVolume / 16383.0f) * (c->midiExpression / 16383.0f), 3.0f)); |
||
1619 | return; |
||
1620 | TCMC_SET_PAN: |
||
1621 | tsf_channel_set_pan(f, channel, c->midiPan / 16383.0f); |
||
1622 | return; |
||
1623 | TCMC_SET_DATA: |
||
1624 | if (c->midiRPN == 0) tsf_channel_set_pitchrange(f, channel, (c->midiData >> 7) + 0.01f * (c->midiData & 0x7F)); |
||
1625 | else if (c->midiRPN == 1) tsf_channel_set_tuning(f, channel, (int)c->tuning + ((float)c->midiData - 8192.0f) / 8192.0f); //fine tune |
||
1626 | else if (c->midiRPN == 2 && controller == 6) tsf_channel_set_tuning(f, channel, ((float)control_value - 64.0f) + (c->tuning - (int)c->tuning)); //coarse tune |
||
1627 | return; |
||
1628 | } |
||
1629 | |||
1630 | TSFDEF int tsf_channel_get_preset_index(tsf* f, int channel) |
||
1631 | { |
||
1632 | return (f->channels && channel < f->channels->channelNum ? f->channels->channels[channel].presetIndex : 0); |
||
1633 | } |
||
1634 | |||
1635 | TSFDEF int tsf_channel_get_preset_bank(tsf* f, int channel) |
||
1636 | { |
||
1637 | return (f->channels && channel < f->channels->channelNum ? (f->channels->channels[channel].bank & 0x7FFF) : 0); |
||
1638 | } |
||
1639 | |||
1640 | TSFDEF int tsf_channel_get_preset_number(tsf* f, int channel) |
||
1641 | { |
||
1642 | return (f->channels && channel < f->channels->channelNum ? f->presets[f->channels->channels[channel].presetIndex].preset : 0); |
||
1643 | } |
||
1644 | |||
1645 | TSFDEF float tsf_channel_get_pan(tsf* f, int channel) |
||
1646 | { |
||
1647 | return (f->channels && channel < f->channels->channelNum ? f->channels->channels[channel].panOffset - 0.5f : 0.5f); |
||
1648 | } |
||
1649 | |||
1650 | TSFDEF float tsf_channel_get_volume(tsf* f, int channel) |
||
1651 | { |
||
1652 | return (f->channels && channel < f->channels->channelNum ? tsf_decibelsToGain(f->channels->channels[channel].gainDB) : 1.0f); |
||
1653 | } |
||
1654 | |||
1655 | TSFDEF int tsf_channel_get_pitchwheel(tsf* f, int channel) |
||
1656 | { |
||
1657 | return (f->channels && channel < f->channels->channelNum ? f->channels->channels[channel].pitchWheel : 8192); |
||
1658 | } |
||
1659 | |||
1660 | TSFDEF float tsf_channel_get_pitchrange(tsf* f, int channel) |
||
1661 | { |
||
1662 | return (f->channels && channel < f->channels->channelNum ? f->channels->channels[channel].pitchRange : 2.0f); |
||
1663 | } |
||
1664 | |||
1665 | TSFDEF float tsf_channel_get_tuning(tsf* f, int channel) |
||
1666 | { |
||
1667 | return (f->channels && channel < f->channels->channelNum ? f->channels->channels[channel].tuning : 0.0f); |
||
1668 | } |
||
1669 | |||
1670 | #ifdef __cplusplus |
||
1671 | } |
||
1672 | #endif |
||
1673 | |||
1674 | #endif //TSF_IMPLEMENTATION |