Mercurial > SDL_sound_CoreAudio
comparison decoders/timidity/playmidi.c @ 199:2d887640d300
Initial add.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Fri, 04 Jan 2002 06:49:49 +0000 |
parents | |
children | 498240aa76f1 |
comparison
equal
deleted
inserted
replaced
198:f9a752f41ab6 | 199:2d887640d300 |
---|---|
1 /* | |
2 | |
3 TiMidity -- Experimental MIDI to WAVE converter | |
4 Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi> | |
5 | |
6 This program is free software; you can redistribute it and/or modify | |
7 it under the terms of the GNU General Public License as published by | |
8 the Free Software Foundation; either version 2 of the License, or | |
9 (at your option) any later version. | |
10 | |
11 This program is distributed in the hope that it will be useful, | |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 GNU General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with this program; if not, write to the Free Software | |
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
19 | |
20 playmidi.c -- random stuff in need of rearrangement | |
21 | |
22 */ | |
23 | |
24 #if HAVE_CONFIG_H | |
25 # include <config.h> | |
26 #endif | |
27 | |
28 #include <stdio.h> | |
29 #include <stdlib.h> | |
30 #include <string.h> | |
31 | |
32 #include "SDL_sound.h" | |
33 | |
34 #define __SDL_SOUND_INTERNAL__ | |
35 #include "SDL_sound_internal.h" | |
36 | |
37 #include "timidity.h" | |
38 #include "options.h" | |
39 #include "instrum.h" | |
40 #include "playmidi.h" | |
41 #include "output.h" | |
42 #include "mix.h" | |
43 #include "tables.h" | |
44 | |
45 static void adjust_amplification(MidiSong *song) | |
46 { | |
47 song->master_volume = (float)(song->amplification) / (float)100.0; | |
48 } | |
49 | |
50 static void reset_voices(MidiSong *song) | |
51 { | |
52 int i; | |
53 for (i=0; i<MAX_VOICES; i++) | |
54 song->voice[i].status=VOICE_FREE; | |
55 } | |
56 | |
57 /* Process the Reset All Controllers event */ | |
58 static void reset_controllers(MidiSong *song, int c) | |
59 { | |
60 song->channel[c].volume=90; /* Some standard says, although the SCC docs say 0. */ | |
61 song->channel[c].expression=127; /* SCC-1 does this. */ | |
62 song->channel[c].sustain=0; | |
63 song->channel[c].pitchbend=0x2000; | |
64 song->channel[c].pitchfactor=0; /* to be computed */ | |
65 } | |
66 | |
67 static void reset_midi(MidiSong *song) | |
68 { | |
69 int i; | |
70 for (i=0; i<16; i++) | |
71 { | |
72 reset_controllers(song, i); | |
73 /* The rest of these are unaffected by the Reset All Controllers event */ | |
74 song->channel[i].program=song->default_program; | |
75 song->channel[i].panning=NO_PANNING; | |
76 song->channel[i].pitchsens=2; | |
77 song->channel[i].bank=0; /* tone bank or drum set */ | |
78 } | |
79 reset_voices(song); | |
80 } | |
81 | |
82 static void select_sample(MidiSong *song, int v, Instrument *ip) | |
83 { | |
84 Sint32 f, cdiff, diff; | |
85 int s,i; | |
86 Sample *sp, *closest; | |
87 | |
88 s=ip->samples; | |
89 sp=ip->sample; | |
90 | |
91 if (s==1) | |
92 { | |
93 song->voice[v].sample=sp; | |
94 return; | |
95 } | |
96 | |
97 f=song->voice[v].orig_frequency; | |
98 for (i=0; i<s; i++) | |
99 { | |
100 if (sp->low_freq <= f && sp->high_freq >= f) | |
101 { | |
102 song->voice[v].sample=sp; | |
103 return; | |
104 } | |
105 sp++; | |
106 } | |
107 | |
108 /* | |
109 No suitable sample found! We'll select the sample whose root | |
110 frequency is closest to the one we want. (Actually we should | |
111 probably convert the low, high, and root frequencies to MIDI note | |
112 values and compare those.) */ | |
113 | |
114 cdiff=0x7FFFFFFF; | |
115 closest=sp=ip->sample; | |
116 for(i=0; i<s; i++) | |
117 { | |
118 diff=sp->root_freq - f; | |
119 if (diff<0) diff=-diff; | |
120 if (diff<cdiff) | |
121 { | |
122 cdiff=diff; | |
123 closest=sp; | |
124 } | |
125 sp++; | |
126 } | |
127 song->voice[v].sample=closest; | |
128 return; | |
129 } | |
130 | |
131 static void recompute_freq(MidiSong *song, int v) | |
132 { | |
133 int | |
134 sign=(song->voice[v].sample_increment < 0), /* for bidirectional loops */ | |
135 pb=song->channel[song->voice[v].channel].pitchbend; | |
136 double a; | |
137 | |
138 if (!song->voice[v].sample->sample_rate) | |
139 return; | |
140 | |
141 if (song->voice[v].vibrato_control_ratio) | |
142 { | |
143 /* This instrument has vibrato. Invalidate any precomputed | |
144 sample_increments. */ | |
145 | |
146 int i=VIBRATO_SAMPLE_INCREMENTS; | |
147 while (i--) | |
148 song->voice[v].vibrato_sample_increment[i]=0; | |
149 } | |
150 | |
151 if (pb==0x2000 || pb<0 || pb>0x3FFF) | |
152 song->voice[v].frequency = song->voice[v].orig_frequency; | |
153 else | |
154 { | |
155 pb-=0x2000; | |
156 if (!(song->channel[song->voice[v].channel].pitchfactor)) | |
157 { | |
158 /* Damn. Somebody bent the pitch. */ | |
159 Sint32 i=pb*song->channel[song->voice[v].channel].pitchsens; | |
160 if (pb<0) | |
161 i=-i; | |
162 song->channel[song->voice[v].channel].pitchfactor= | |
163 (float)(bend_fine[(i>>5) & 0xFF] * bend_coarse[i>>13]); | |
164 } | |
165 if (pb>0) | |
166 song->voice[v].frequency= | |
167 (Sint32)(song->channel[song->voice[v].channel].pitchfactor * | |
168 (double)(song->voice[v].orig_frequency)); | |
169 else | |
170 song->voice[v].frequency= | |
171 (Sint32)((double)(song->voice[v].orig_frequency) / | |
172 song->channel[song->voice[v].channel].pitchfactor); | |
173 } | |
174 | |
175 a = FSCALE(((double)(song->voice[v].sample->sample_rate) * | |
176 (double)(song->voice[v].frequency)) / | |
177 ((double)(song->voice[v].sample->root_freq) * | |
178 (double)(song->rate)), | |
179 FRACTION_BITS); | |
180 | |
181 if (sign) | |
182 a = -a; /* need to preserve the loop direction */ | |
183 | |
184 song->voice[v].sample_increment = (Sint32)(a); | |
185 } | |
186 | |
187 static void recompute_amp(MidiSong *song, int v) | |
188 { | |
189 Sint32 tempamp; | |
190 | |
191 /* TODO: use fscale */ | |
192 | |
193 tempamp= (song->voice[v].velocity * | |
194 song->channel[song->voice[v].channel].volume * | |
195 song->channel[song->voice[v].channel].expression); /* 21 bits */ | |
196 | |
197 if (!(song->encoding & PE_MONO)) | |
198 { | |
199 if (song->voice[v].panning > 60 && song->voice[v].panning < 68) | |
200 { | |
201 song->voice[v].panned=PANNED_CENTER; | |
202 | |
203 song->voice[v].left_amp= | |
204 FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume, | |
205 21); | |
206 } | |
207 else if (song->voice[v].panning<5) | |
208 { | |
209 song->voice[v].panned = PANNED_LEFT; | |
210 | |
211 song->voice[v].left_amp= | |
212 FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume, | |
213 20); | |
214 } | |
215 else if (song->voice[v].panning>123) | |
216 { | |
217 song->voice[v].panned = PANNED_RIGHT; | |
218 | |
219 song->voice[v].left_amp= /* left_amp will be used */ | |
220 FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume, | |
221 20); | |
222 } | |
223 else | |
224 { | |
225 song->voice[v].panned = PANNED_MYSTERY; | |
226 | |
227 song->voice[v].left_amp= | |
228 FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume, | |
229 27); | |
230 song->voice[v].right_amp = song->voice[v].left_amp * (song->voice[v].panning); | |
231 song->voice[v].left_amp *= (float)(127 - song->voice[v].panning); | |
232 } | |
233 } | |
234 else | |
235 { | |
236 song->voice[v].panned = PANNED_CENTER; | |
237 | |
238 song->voice[v].left_amp= | |
239 FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume, | |
240 21); | |
241 } | |
242 } | |
243 | |
244 static void start_note(MidiSong *song, MidiEvent *e, int i) | |
245 { | |
246 Instrument *ip; | |
247 int j; | |
248 | |
249 if (ISDRUMCHANNEL(song, e->channel)) | |
250 { | |
251 if (!(ip=song->drumset[song->channel[e->channel].bank]->instrument[e->a])) | |
252 { | |
253 if (!(ip=song->drumset[0]->instrument[e->a])) | |
254 return; /* No instrument? Then we can't play. */ | |
255 } | |
256 if (ip->samples != 1) | |
257 { | |
258 SNDDBG(("Strange: percussion instrument with %d samples!", | |
259 ip->samples)); | |
260 } | |
261 | |
262 if (ip->sample->note_to_use) /* Do we have a fixed pitch? */ | |
263 song->voice[i].orig_frequency = freq_table[(int)(ip->sample->note_to_use)]; | |
264 else | |
265 song->voice[i].orig_frequency = freq_table[e->a & 0x7F]; | |
266 | |
267 /* drums are supposed to have only one sample */ | |
268 song->voice[i].sample = ip->sample; | |
269 } | |
270 else | |
271 { | |
272 if (song->channel[e->channel].program == SPECIAL_PROGRAM) | |
273 ip=song->default_instrument; | |
274 else if (!(ip=song->tonebank[song->channel[e->channel].bank]-> | |
275 instrument[song->channel[e->channel].program])) | |
276 { | |
277 if (!(ip=song->tonebank[0]->instrument[song->channel[e->channel].program])) | |
278 return; /* No instrument? Then we can't play. */ | |
279 } | |
280 | |
281 if (ip->sample->note_to_use) /* Fixed-pitch instrument? */ | |
282 song->voice[i].orig_frequency = freq_table[(int)(ip->sample->note_to_use)]; | |
283 else | |
284 song->voice[i].orig_frequency = freq_table[e->a & 0x7F]; | |
285 select_sample(song, i, ip); | |
286 } | |
287 | |
288 song->voice[i].status = VOICE_ON; | |
289 song->voice[i].channel = e->channel; | |
290 song->voice[i].note = e->a; | |
291 song->voice[i].velocity = e->b; | |
292 song->voice[i].sample_offset = 0; | |
293 song->voice[i].sample_increment = 0; /* make sure it isn't negative */ | |
294 | |
295 song->voice[i].tremolo_phase = 0; | |
296 song->voice[i].tremolo_phase_increment = song->voice[i].sample->tremolo_phase_increment; | |
297 song->voice[i].tremolo_sweep = song->voice[i].sample->tremolo_sweep_increment; | |
298 song->voice[i].tremolo_sweep_position = 0; | |
299 | |
300 song->voice[i].vibrato_sweep = song->voice[i].sample->vibrato_sweep_increment; | |
301 song->voice[i].vibrato_sweep_position = 0; | |
302 song->voice[i].vibrato_control_ratio = song->voice[i].sample->vibrato_control_ratio; | |
303 song->voice[i].vibrato_control_counter = song->voice[i].vibrato_phase = 0; | |
304 for (j=0; j<VIBRATO_SAMPLE_INCREMENTS; j++) | |
305 song->voice[i].vibrato_sample_increment[j] = 0; | |
306 | |
307 if (song->channel[e->channel].panning != NO_PANNING) | |
308 song->voice[i].panning = song->channel[e->channel].panning; | |
309 else | |
310 song->voice[i].panning = song->voice[i].sample->panning; | |
311 | |
312 recompute_freq(song, i); | |
313 recompute_amp(song, i); | |
314 if (song->voice[i].sample->modes & MODES_ENVELOPE) | |
315 { | |
316 /* Ramp up from 0 */ | |
317 song->voice[i].envelope_stage = 0; | |
318 song->voice[i].envelope_volume = 0; | |
319 song->voice[i].control_counter = 0; | |
320 recompute_envelope(song, i); | |
321 apply_envelope_to_amp(song, i); | |
322 } | |
323 else | |
324 { | |
325 song->voice[i].envelope_increment = 0; | |
326 apply_envelope_to_amp(song, i); | |
327 } | |
328 } | |
329 | |
330 static void kill_note(MidiSong *song, int i) | |
331 { | |
332 song->voice[i].status = VOICE_DIE; | |
333 } | |
334 | |
335 /* Only one instance of a note can be playing on a single channel. */ | |
336 static void note_on(MidiSong *song) | |
337 { | |
338 int i = song->voices, lowest=-1; | |
339 Sint32 lv=0x7FFFFFFF, v; | |
340 MidiEvent *e = song->current_event; | |
341 | |
342 while (i--) | |
343 { | |
344 if (song->voice[i].status == VOICE_FREE) | |
345 lowest=i; /* Can't get a lower volume than silence */ | |
346 else if (song->voice[i].channel==e->channel && | |
347 (song->voice[i].note==e->a || song->channel[song->voice[i].channel].mono)) | |
348 kill_note(song, i); | |
349 } | |
350 | |
351 if (lowest != -1) | |
352 { | |
353 /* Found a free voice. */ | |
354 start_note(song,e,lowest); | |
355 return; | |
356 } | |
357 | |
358 /* Look for the decaying note with the lowest volume */ | |
359 i = song->voices; | |
360 while (i--) | |
361 { | |
362 if ((song->voice[i].status != VOICE_ON) && | |
363 (song->voice[i].status != VOICE_DIE)) | |
364 { | |
365 v = song->voice[i].left_mix; | |
366 if ((song->voice[i].panned == PANNED_MYSTERY) | |
367 && (song->voice[i].right_mix > v)) | |
368 v = song->voice[i].right_mix; | |
369 if (v<lv) | |
370 { | |
371 lv=v; | |
372 lowest=i; | |
373 } | |
374 } | |
375 } | |
376 | |
377 if (lowest != -1) | |
378 { | |
379 /* This can still cause a click, but if we had a free voice to | |
380 spare for ramping down this note, we wouldn't need to kill it | |
381 in the first place... Still, this needs to be fixed. Perhaps | |
382 we could use a reserve of voices to play dying notes only. */ | |
383 | |
384 song->cut_notes++; | |
385 song->voice[lowest].status=VOICE_FREE; | |
386 start_note(song,e,lowest); | |
387 } | |
388 else | |
389 song->lost_notes++; | |
390 } | |
391 | |
392 static void finish_note(MidiSong *song, int i) | |
393 { | |
394 if (song->voice[i].sample->modes & MODES_ENVELOPE) | |
395 { | |
396 /* We need to get the envelope out of Sustain stage */ | |
397 song->voice[i].envelope_stage = 3; | |
398 song->voice[i].status = VOICE_OFF; | |
399 recompute_envelope(song, i); | |
400 apply_envelope_to_amp(song, i); | |
401 } | |
402 else | |
403 { | |
404 /* Set status to OFF so resample_voice() will let this voice out | |
405 of its loop, if any. In any case, this voice dies when it | |
406 hits the end of its data (ofs>=data_length). */ | |
407 song->voice[i].status = VOICE_OFF; | |
408 } | |
409 } | |
410 | |
411 static void note_off(MidiSong *song) | |
412 { | |
413 int i = song->voices; | |
414 MidiEvent *e = song->current_event; | |
415 | |
416 while (i--) | |
417 if (song->voice[i].status == VOICE_ON && | |
418 song->voice[i].channel == e->channel && | |
419 song->voice[i].note == e->a) | |
420 { | |
421 if (song->channel[e->channel].sustain) | |
422 { | |
423 song->voice[i].status = VOICE_SUSTAINED; | |
424 } | |
425 else | |
426 finish_note(song, i); | |
427 return; | |
428 } | |
429 } | |
430 | |
431 /* Process the All Notes Off event */ | |
432 static void all_notes_off(MidiSong *song) | |
433 { | |
434 int i = song->voices; | |
435 int c = song->current_event->channel; | |
436 | |
437 SNDDBG(("All notes off on channel %d", c)); | |
438 while (i--) | |
439 if (song->voice[i].status == VOICE_ON && | |
440 song->voice[i].channel == c) | |
441 { | |
442 if (song->channel[c].sustain) | |
443 song->voice[i].status = VOICE_SUSTAINED; | |
444 else | |
445 finish_note(song, i); | |
446 } | |
447 } | |
448 | |
449 /* Process the All Sounds Off event */ | |
450 static void all_sounds_off(MidiSong *song) | |
451 { | |
452 int i = song->voices; | |
453 int c = song->current_event->channel; | |
454 | |
455 while (i--) | |
456 if (song->voice[i].channel == c && | |
457 song->voice[i].status != VOICE_FREE && | |
458 song->voice[i].status != VOICE_DIE) | |
459 { | |
460 kill_note(song, i); | |
461 } | |
462 } | |
463 | |
464 static void adjust_pressure(MidiSong *song) | |
465 { | |
466 MidiEvent *e = song->current_event; | |
467 int i = song->voices; | |
468 | |
469 while (i--) | |
470 if (song->voice[i].status == VOICE_ON && | |
471 song->voice[i].channel == e->channel && | |
472 song->voice[i].note == e->a) | |
473 { | |
474 song->voice[i].velocity = e->b; | |
475 recompute_amp(song, i); | |
476 apply_envelope_to_amp(song, i); | |
477 return; | |
478 } | |
479 } | |
480 | |
481 static void drop_sustain(MidiSong *song) | |
482 { | |
483 int i = song->voices; | |
484 int c = song->current_event->channel; | |
485 | |
486 while (i--) | |
487 if (song->voice[i].status == VOICE_SUSTAINED && song->voice[i].channel == c) | |
488 finish_note(song, i); | |
489 } | |
490 | |
491 static void adjust_pitchbend(MidiSong *song) | |
492 { | |
493 int c = song->current_event->channel; | |
494 int i = song->voices; | |
495 | |
496 while (i--) | |
497 if (song->voice[i].status != VOICE_FREE && song->voice[i].channel == c) | |
498 { | |
499 recompute_freq(song, i); | |
500 } | |
501 } | |
502 | |
503 static void adjust_volume(MidiSong *song) | |
504 { | |
505 int c = song->current_event->channel; | |
506 int i = song->voices; | |
507 | |
508 while (i--) | |
509 if (song->voice[i].channel == c && | |
510 (song->voice[i].status==VOICE_ON || song->voice[i].status==VOICE_SUSTAINED)) | |
511 { | |
512 recompute_amp(song, i); | |
513 apply_envelope_to_amp(song, i); | |
514 } | |
515 } | |
516 | |
517 static void seek_forward(MidiSong *song, Sint32 until_time) | |
518 { | |
519 reset_voices(song); | |
520 while (song->current_event->time < until_time) | |
521 { | |
522 switch(song->current_event->type) | |
523 { | |
524 /* All notes stay off. Just handle the parameter changes. */ | |
525 | |
526 case ME_PITCH_SENS: | |
527 song->channel[song->current_event->channel].pitchsens = | |
528 song->current_event->a; | |
529 song->channel[song->current_event->channel].pitchfactor = 0; | |
530 break; | |
531 | |
532 case ME_PITCHWHEEL: | |
533 song->channel[song->current_event->channel].pitchbend = | |
534 song->current_event->a + song->current_event->b * 128; | |
535 song->channel[song->current_event->channel].pitchfactor = 0; | |
536 break; | |
537 | |
538 case ME_MAINVOLUME: | |
539 song->channel[song->current_event->channel].volume = | |
540 song->current_event->a; | |
541 break; | |
542 | |
543 case ME_PAN: | |
544 song->channel[song->current_event->channel].panning = | |
545 song->current_event->a; | |
546 break; | |
547 | |
548 case ME_EXPRESSION: | |
549 song->channel[song->current_event->channel].expression = | |
550 song->current_event->a; | |
551 break; | |
552 | |
553 case ME_PROGRAM: | |
554 if (ISDRUMCHANNEL(song, song->current_event->channel)) | |
555 /* Change drum set */ | |
556 song->channel[song->current_event->channel].bank = | |
557 song->current_event->a; | |
558 else | |
559 song->channel[song->current_event->channel].program = | |
560 song->current_event->a; | |
561 break; | |
562 | |
563 case ME_SUSTAIN: | |
564 song->channel[song->current_event->channel].sustain = | |
565 song->current_event->a; | |
566 break; | |
567 | |
568 case ME_RESET_CONTROLLERS: | |
569 reset_controllers(song, song->current_event->channel); | |
570 break; | |
571 | |
572 case ME_TONE_BANK: | |
573 song->channel[song->current_event->channel].bank = | |
574 song->current_event->a; | |
575 break; | |
576 | |
577 case ME_EOT: | |
578 song->current_sample = song->current_event->time; | |
579 return; | |
580 } | |
581 song->current_event++; | |
582 } | |
583 /*song->current_sample=song->current_event->time;*/ | |
584 if (song->current_event != song->events) | |
585 song->current_event--; | |
586 song->current_sample=until_time; | |
587 } | |
588 | |
589 static void skip_to(MidiSong *song, Sint32 until_time) | |
590 { | |
591 if (song->current_sample > until_time) | |
592 song->current_sample = 0; | |
593 | |
594 reset_midi(song); | |
595 song->buffered_count = 0; | |
596 song->buffer_pointer = song->common_buffer; | |
597 song->current_event = song->events; | |
598 | |
599 if (until_time) | |
600 seek_forward(song, until_time); | |
601 } | |
602 | |
603 static void do_compute_data(MidiSong *song, Sint32 count) | |
604 { | |
605 int i; | |
606 memset(song->buffer_pointer, 0, | |
607 (song->encoding & PE_MONO) ? (count * 4) : (count * 8)); | |
608 for (i = 0; i < song->voices; i++) | |
609 { | |
610 if(song->voice[i].status != VOICE_FREE) | |
611 mix_voice(song, song->buffer_pointer, i, count); | |
612 } | |
613 song->current_sample += count; | |
614 } | |
615 | |
616 /* count=0 means flush remaining buffered data to output device, then | |
617 flush the device itself */ | |
618 static void compute_data(MidiSong *song, void *stream, Sint32 count) | |
619 { | |
620 int channels; | |
621 | |
622 if ( song->encoding & PE_MONO ) | |
623 channels = 1; | |
624 else | |
625 channels = 2; | |
626 | |
627 if (!count) | |
628 { | |
629 if (song->buffered_count) | |
630 song->write(stream, song->common_buffer, channels * song->buffered_count); | |
631 song->buffer_pointer = song->common_buffer; | |
632 song->buffered_count = 0; | |
633 return; | |
634 } | |
635 | |
636 while ((count + song->buffered_count) >= song->buffer_size) | |
637 { | |
638 do_compute_data(song, song->buffer_size - song->buffered_count); | |
639 count -= song->buffer_size - song->buffered_count; | |
640 song->write(stream, song->common_buffer, channels * song->buffer_size); | |
641 song->buffer_pointer = song->common_buffer; | |
642 song->buffered_count = 0; | |
643 } | |
644 if (count>0) | |
645 { | |
646 do_compute_data(song, count); | |
647 song->buffered_count += count; | |
648 song->buffer_pointer += (song->encoding & PE_MONO) ? count : count*2; | |
649 } | |
650 } | |
651 | |
652 void Timidity_Start(MidiSong *song) | |
653 { | |
654 song->playing = 1; | |
655 adjust_amplification(song); | |
656 skip_to(song, 0); | |
657 } | |
658 | |
659 int Timidity_PlaySome(MidiSong *song, void *stream, Sint32 len) | |
660 { | |
661 Sint32 start_sample, end_sample, samples; | |
662 int bytes_per_sample; | |
663 | |
664 if (!song->playing) | |
665 return 0; | |
666 | |
667 bytes_per_sample = | |
668 ((song->encoding & PE_MONO) ? 1 : 2) | |
669 * ((song->encoding & PE_16BIT) ? 2 : 1); | |
670 samples = len / bytes_per_sample; | |
671 | |
672 start_sample = song->current_sample; | |
673 end_sample = song->current_sample+samples; | |
674 while ( song->current_sample < end_sample ) { | |
675 /* Handle all events that should happen at this time */ | |
676 while (song->current_event->time <= song->current_sample) { | |
677 switch(song->current_event->type) { | |
678 | |
679 /* Effects affecting a single note */ | |
680 | |
681 case ME_NOTEON: | |
682 if (!(song->current_event->b)) /* Velocity 0? */ | |
683 note_off(song); | |
684 else | |
685 note_on(song); | |
686 break; | |
687 | |
688 case ME_NOTEOFF: | |
689 note_off(song); | |
690 break; | |
691 | |
692 case ME_KEYPRESSURE: | |
693 adjust_pressure(song); | |
694 break; | |
695 | |
696 /* Effects affecting a single channel */ | |
697 | |
698 case ME_PITCH_SENS: | |
699 song->channel[song->current_event->channel].pitchsens = | |
700 song->current_event->a; | |
701 song->channel[song->current_event->channel].pitchfactor = 0; | |
702 break; | |
703 | |
704 case ME_PITCHWHEEL: | |
705 song->channel[song->current_event->channel].pitchbend = | |
706 song->current_event->a + song->current_event->b * 128; | |
707 song->channel[song->current_event->channel].pitchfactor = 0; | |
708 /* Adjust pitch for notes already playing */ | |
709 adjust_pitchbend(song); | |
710 break; | |
711 | |
712 case ME_MAINVOLUME: | |
713 song->channel[song->current_event->channel].volume = | |
714 song->current_event->a; | |
715 adjust_volume(song); | |
716 break; | |
717 | |
718 case ME_PAN: | |
719 song->channel[song->current_event->channel].panning = | |
720 song->current_event->a; | |
721 break; | |
722 | |
723 case ME_EXPRESSION: | |
724 song->channel[song->current_event->channel].expression = | |
725 song->current_event->a; | |
726 adjust_volume(song); | |
727 break; | |
728 | |
729 case ME_PROGRAM: | |
730 if (ISDRUMCHANNEL(song, song->current_event->channel)) { | |
731 /* Change drum set */ | |
732 song->channel[song->current_event->channel].bank = | |
733 song->current_event->a; | |
734 } | |
735 else | |
736 song->channel[song->current_event->channel].program = | |
737 song->current_event->a; | |
738 break; | |
739 | |
740 case ME_SUSTAIN: | |
741 song->channel[song->current_event->channel].sustain = | |
742 song->current_event->a; | |
743 if (!song->current_event->a) | |
744 drop_sustain(song); | |
745 break; | |
746 | |
747 case ME_RESET_CONTROLLERS: | |
748 reset_controllers(song, song->current_event->channel); | |
749 break; | |
750 | |
751 case ME_ALL_NOTES_OFF: | |
752 all_notes_off(song); | |
753 break; | |
754 | |
755 case ME_ALL_SOUNDS_OFF: | |
756 all_sounds_off(song); | |
757 break; | |
758 | |
759 case ME_TONE_BANK: | |
760 song->channel[song->current_event->channel].bank = | |
761 song->current_event->a; | |
762 break; | |
763 | |
764 case ME_EOT: | |
765 /* Give the last notes a couple of seconds to decay */ | |
766 SNDDBG(("Playing time: ~%d seconds\n", | |
767 song->current_sample/song->rate+2)); | |
768 SNDDBG(("Notes cut: %d\n", song->cut_notes)); | |
769 SNDDBG(("Notes lost totally: %d\n", song->lost_notes)); | |
770 song->playing = 0; | |
771 return (song->current_sample - start_sample) * bytes_per_sample; | |
772 } | |
773 song->current_event++; | |
774 } | |
775 if (song->current_event->time > end_sample) | |
776 compute_data(song, stream, end_sample-song->current_sample); | |
777 else | |
778 compute_data(song, stream, song->current_event->time-song->current_sample); | |
779 } | |
780 return samples * bytes_per_sample; | |
781 } | |
782 | |
783 void Timidity_SetVolume(MidiSong *song, int volume) | |
784 { | |
785 int i; | |
786 if (volume > MAX_AMPLIFICATION) | |
787 song->amplification = MAX_AMPLIFICATION; | |
788 else | |
789 if (volume < 0) | |
790 song->amplification = 0; | |
791 else | |
792 song->amplification = volume; | |
793 adjust_amplification(song); | |
794 for (i = 0; i < song->voices; i++) | |
795 if (song->voice[i].status != VOICE_FREE) | |
796 { | |
797 recompute_amp(song, i); | |
798 apply_envelope_to_amp(song, i); | |
799 } | |
800 } |