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 }