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