timidity/playmidi.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 12 Nov 2018 16:54:24 -0800
changeset 925 5945988b4a41
parent 811 d817ca30412d
permissions -rw-r--r--
Fixed bug 4371 - tvOS Simulator devices not listed

Caleb Cornett

In the Xcode-iOS project, when selecting the libSDL_mixer-tvOS target, no tvOS simulators appear in the available device dropdown.

This is easily fixed with the attached patch.
     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 Perl Artistic License, available in COPYING.
     8 
     9     playmidi.c -- random stuff in need of rearrangement
    10 
    11 */
    12 
    13 #if HAVE_CONFIG_H
    14 #  include <config.h>
    15 #endif
    16 
    17 #include <stdio.h>
    18 #include <stdlib.h>
    19 #include <string.h>
    20 
    21 #include "SDL.h"
    22 
    23 #include "timidity.h"
    24 #include "options.h"
    25 #include "instrum.h"
    26 #include "playmidi.h"
    27 #include "output.h"
    28 #include "mix.h"
    29 #include "tables.h"
    30 
    31 static void adjust_amplification(MidiSong *song)
    32 { 
    33   song->master_volume = (float)(song->amplification) / (float)100.0;
    34 }
    35 
    36 static void reset_voices(MidiSong *song)
    37 {
    38   int i;
    39   for (i=0; i<MAX_VOICES; i++)
    40     song->voice[i].status=VOICE_FREE;
    41 }
    42 
    43 /* Process the Reset All Controllers event */
    44 static void reset_controllers(MidiSong *song, int c)
    45 {
    46   song->channel[c].volume=90; /* Some standard says, although the SCC docs say 0. */
    47   song->channel[c].expression=127; /* SCC-1 does this. */
    48   song->channel[c].sustain=0;
    49   song->channel[c].pitchbend=0x2000;
    50   song->channel[c].pitchfactor=0; /* to be computed */
    51 }
    52 
    53 static void reset_midi(MidiSong *song)
    54 {
    55   int i;
    56   for (i=0; i<MAXCHAN; i++)
    57     {
    58       reset_controllers(song, i);
    59       /* The rest of these are unaffected by the Reset All Controllers event */
    60       song->channel[i].program=song->default_program;
    61       song->channel[i].panning=NO_PANNING;
    62       song->channel[i].pitchsens=2;
    63       song->channel[i].bank=0; /* tone bank or drum set */
    64     }
    65   reset_voices(song);
    66 }
    67 
    68 static void select_sample(MidiSong *song, int v, Instrument *ip, int vel)
    69 {
    70   Sint32 f, cdiff, diff;
    71   int s,i;
    72   Sample *sp, *closest;
    73 
    74   s=ip->samples;
    75   sp=ip->sample;
    76 
    77   if (s==1)
    78     {
    79       song->voice[v].sample=sp;
    80       return;
    81     }
    82 
    83   f=song->voice[v].orig_frequency;
    84   for (i=0; i<s; i++)
    85     {
    86       if (sp->low_freq <= f && sp->high_freq >= f)
    87 	{
    88 	  song->voice[v].sample=sp;
    89 	  return;
    90 	}
    91       sp++;
    92     }
    93 
    94   /* 
    95      No suitable sample found! We'll select the sample whose root
    96      frequency is closest to the one we want. (Actually we should
    97      probably convert the low, high, and root frequencies to MIDI note
    98      values and compare those.) */
    99 
   100   cdiff=0x7FFFFFFF;
   101   closest=sp=ip->sample;
   102   for(i=0; i<s; i++)
   103     {
   104       diff=sp->root_freq - f;
   105       if (diff<0) diff=-diff;
   106       if (diff<cdiff)
   107 	{
   108 	  cdiff=diff;
   109 	  closest=sp;
   110 	}
   111       sp++;
   112     }
   113   song->voice[v].sample=closest;
   114   return;
   115 }
   116 
   117 static void recompute_freq(MidiSong *song, int v)
   118 {
   119   int 
   120     sign=(song->voice[v].sample_increment < 0), /* for bidirectional loops */
   121     pb=song->channel[song->voice[v].channel].pitchbend;
   122   double a;
   123   
   124   if (!song->voice[v].sample->sample_rate)
   125     return;
   126 
   127   if (song->voice[v].vibrato_control_ratio)
   128     {
   129       /* This instrument has vibrato. Invalidate any precomputed
   130          sample_increments. */
   131 
   132       int i=VIBRATO_SAMPLE_INCREMENTS;
   133       while (i--)
   134 	song->voice[v].vibrato_sample_increment[i]=0;
   135     }
   136 
   137   if (pb==0x2000 || pb<0 || pb>0x3FFF)
   138     song->voice[v].frequency = song->voice[v].orig_frequency;
   139   else
   140     {
   141       pb-=0x2000;
   142       if (!(song->channel[song->voice[v].channel].pitchfactor))
   143 	{
   144 	  /* Damn. Somebody bent the pitch. */
   145 	  Sint32 i=pb*song->channel[song->voice[v].channel].pitchsens;
   146 	  if (pb<0)
   147 	    i=-i;
   148 	  song->channel[song->voice[v].channel].pitchfactor=
   149 	    (float)(bend_fine[(i>>5) & 0xFF] * bend_coarse[i>>13]);
   150 	}
   151       if (pb>0)
   152 	song->voice[v].frequency=
   153 	  (Sint32)(song->channel[song->voice[v].channel].pitchfactor *
   154 		  (double)(song->voice[v].orig_frequency));
   155       else
   156 	song->voice[v].frequency=
   157 	  (Sint32)((double)(song->voice[v].orig_frequency) /
   158 		  song->channel[song->voice[v].channel].pitchfactor);
   159     }
   160 
   161   a = FSCALE(((double)(song->voice[v].sample->sample_rate) *
   162 	      (double)(song->voice[v].frequency)) /
   163 	     ((double)(song->voice[v].sample->root_freq) *
   164 	      (double)(song->rate)),
   165 	     FRACTION_BITS);
   166 
   167   if (sign) 
   168     a = -a; /* need to preserve the loop direction */
   169 
   170   song->voice[v].sample_increment = (Sint32)(a);
   171 }
   172 
   173 static void recompute_amp(MidiSong *song, int v)
   174 {
   175   Sint32 tempamp;
   176 
   177   /* TODO: use fscale */
   178 
   179   tempamp= (song->voice[v].velocity *
   180 	    song->channel[song->voice[v].channel].volume * 
   181 	    song->channel[song->voice[v].channel].expression); /* 21 bits */
   182 
   183   if (!(song->encoding & PE_MONO))
   184     {
   185       if (song->voice[v].panning > 60 && song->voice[v].panning < 68)
   186 	{
   187 	  song->voice[v].panned=PANNED_CENTER;
   188 
   189 	  song->voice[v].left_amp=
   190 	    FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
   191 		      21);
   192 	}
   193       else if (song->voice[v].panning<5)
   194 	{
   195 	  song->voice[v].panned = PANNED_LEFT;
   196 
   197 	  song->voice[v].left_amp=
   198 	    FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
   199 		      20);
   200 	}
   201       else if (song->voice[v].panning>123)
   202 	{
   203 	  song->voice[v].panned = PANNED_RIGHT;
   204 
   205 	  song->voice[v].left_amp= /* left_amp will be used */
   206 	    FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
   207 		      20);
   208 	}
   209       else
   210 	{
   211 	  song->voice[v].panned = PANNED_MYSTERY;
   212 
   213 	  song->voice[v].left_amp=
   214 	    FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
   215 		      27);
   216 	  song->voice[v].right_amp = song->voice[v].left_amp * (song->voice[v].panning);
   217 	  song->voice[v].left_amp *= (float)(127 - song->voice[v].panning);
   218 	}
   219     }
   220   else
   221     {
   222       song->voice[v].panned = PANNED_CENTER;
   223 
   224       song->voice[v].left_amp=
   225 	FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
   226 		  21);
   227     }
   228 }
   229 
   230 static void start_note(MidiSong *song, MidiEvent *e, int i)
   231 {
   232   Instrument *ip;
   233   int j;
   234 
   235   if (ISDRUMCHANNEL(song, e->channel))
   236     {
   237       if (!(ip=song->drumset[song->channel[e->channel].bank]->instrument[e->a]))
   238 	{
   239 	  if (!(ip=song->drumset[0]->instrument[e->a]))
   240 	    return; /* No instrument? Then we can't play. */
   241 	}
   242       if (ip->samples != 1)
   243 	{
   244 	  SNDDBG(("Strange: percussion instrument with %d samples!",
   245 		  ip->samples));
   246 	}
   247 
   248       if (ip->sample->note_to_use) /* Do we have a fixed pitch? */
   249 	song->voice[i].orig_frequency = freq_table[(int)(ip->sample->note_to_use)];
   250       else
   251 	song->voice[i].orig_frequency = freq_table[e->a & 0x7F];
   252       
   253       /* drums are supposed to have only one sample */
   254       song->voice[i].sample = ip->sample;
   255     }
   256   else
   257     {
   258       if (song->channel[e->channel].program == SPECIAL_PROGRAM)
   259 	ip=song->default_instrument;
   260       else if (!(ip=song->tonebank[song->channel[e->channel].bank]->
   261 		 instrument[song->channel[e->channel].program]))
   262 	{
   263 	  if (!(ip=song->tonebank[0]->instrument[song->channel[e->channel].program]))
   264 	    return; /* No instrument? Then we can't play. */
   265 	}
   266 
   267       if (ip->sample->note_to_use) /* Fixed-pitch instrument? */
   268 	song->voice[i].orig_frequency = freq_table[(int)(ip->sample->note_to_use)];
   269       else
   270 	song->voice[i].orig_frequency = freq_table[e->a & 0x7F];
   271       select_sample(song, i, ip, e->b);
   272     }
   273 
   274   song->voice[i].status = VOICE_ON;
   275   song->voice[i].channel = e->channel;
   276   song->voice[i].note = e->a;
   277   song->voice[i].velocity = e->b;
   278   song->voice[i].sample_offset = 0;
   279   song->voice[i].sample_increment = 0; /* make sure it isn't negative */
   280 
   281   song->voice[i].tremolo_phase = 0;
   282   song->voice[i].tremolo_phase_increment = song->voice[i].sample->tremolo_phase_increment;
   283   song->voice[i].tremolo_sweep = song->voice[i].sample->tremolo_sweep_increment;
   284   song->voice[i].tremolo_sweep_position = 0;
   285 
   286   song->voice[i].vibrato_sweep = song->voice[i].sample->vibrato_sweep_increment;
   287   song->voice[i].vibrato_sweep_position = 0;
   288   song->voice[i].vibrato_control_ratio = song->voice[i].sample->vibrato_control_ratio;
   289   song->voice[i].vibrato_control_counter = song->voice[i].vibrato_phase = 0;
   290   for (j=0; j<VIBRATO_SAMPLE_INCREMENTS; j++)
   291     song->voice[i].vibrato_sample_increment[j] = 0;
   292 
   293   if (song->channel[e->channel].panning != NO_PANNING)
   294     song->voice[i].panning = song->channel[e->channel].panning;
   295   else
   296     song->voice[i].panning = song->voice[i].sample->panning;
   297 
   298   recompute_freq(song, i);
   299   recompute_amp(song, i);
   300   if (song->voice[i].sample->modes & MODES_ENVELOPE)
   301     {
   302       /* Ramp up from 0 */
   303       song->voice[i].envelope_stage = 0;
   304       song->voice[i].envelope_volume = 0;
   305       song->voice[i].control_counter = 0;
   306       recompute_envelope(song, i);
   307       apply_envelope_to_amp(song, i);
   308     }
   309   else
   310     {
   311       song->voice[i].envelope_increment = 0;
   312       apply_envelope_to_amp(song, i);
   313     }
   314 }
   315 
   316 static void kill_note(MidiSong *song, int i)
   317 {
   318   song->voice[i].status = VOICE_DIE;
   319 }
   320 
   321 /* Only one instance of a note can be playing on a single channel. */
   322 static void note_on(MidiSong *song)
   323 {
   324   int i = song->voices, lowest=-1; 
   325   Sint32 lv=0x7FFFFFFF, v;
   326   MidiEvent *e = song->current_event;
   327 
   328   while (i--)
   329     {
   330       if (song->voice[i].status == VOICE_FREE)
   331 	lowest=i; /* Can't get a lower volume than silence */
   332       else if (song->voice[i].channel==e->channel && 
   333 	       (song->voice[i].note==e->a || song->channel[song->voice[i].channel].mono))
   334 	kill_note(song, i);
   335     }
   336 
   337   if (lowest != -1)
   338     {
   339       /* Found a free voice. */
   340       start_note(song,e,lowest);
   341       return;
   342     }
   343   
   344   /* Look for the decaying note with the lowest volume */
   345   i = song->voices;
   346   while (i--)
   347     {
   348       if ((song->voice[i].status != VOICE_ON) &&
   349 	  (song->voice[i].status != VOICE_DIE))
   350 	{
   351 	  v = song->voice[i].left_mix;
   352 	  if ((song->voice[i].panned == PANNED_MYSTERY)
   353 	      && (song->voice[i].right_mix > v))
   354 	    v = song->voice[i].right_mix;
   355 	  if (v<lv)
   356 	    {
   357 	      lv=v;
   358 	      lowest=i;
   359 	    }
   360 	}
   361     }
   362 
   363   if (lowest != -1)
   364     {
   365       /* This can still cause a click, but if we had a free voice to
   366 	 spare for ramping down this note, we wouldn't need to kill it
   367 	 in the first place... Still, this needs to be fixed. Perhaps
   368 	 we could use a reserve of voices to play dying notes only. */
   369       
   370       song->cut_notes++;
   371       song->voice[lowest].status=VOICE_FREE;
   372       start_note(song,e,lowest);
   373     }
   374   else
   375     song->lost_notes++;
   376 }
   377 
   378 static void finish_note(MidiSong *song, int i)
   379 {
   380   if (song->voice[i].sample->modes & MODES_ENVELOPE)
   381     {
   382       /* We need to get the envelope out of Sustain stage */
   383       song->voice[i].envelope_stage = 3;
   384       song->voice[i].status = VOICE_OFF;
   385       recompute_envelope(song, i);
   386       apply_envelope_to_amp(song, i);
   387     }
   388   else
   389     {
   390       /* Set status to OFF so resample_voice() will let this voice out
   391          of its loop, if any. In any case, this voice dies when it
   392          hits the end of its data (ofs>=data_length). */
   393       song->voice[i].status = VOICE_OFF;
   394     }
   395 }
   396 
   397 static void note_off(MidiSong *song)
   398 {
   399   int i = song->voices;
   400   MidiEvent *e = song->current_event;
   401 
   402   while (i--)
   403     if (song->voice[i].status == VOICE_ON &&
   404 	song->voice[i].channel == e->channel &&
   405 	song->voice[i].note == e->a)
   406       {
   407 	if (song->channel[e->channel].sustain)
   408 	  {
   409 	    song->voice[i].status = VOICE_SUSTAINED;
   410 	  }
   411 	else
   412 	  finish_note(song, i);
   413 	return;
   414       }
   415 }
   416 
   417 /* Process the All Notes Off event */
   418 static void all_notes_off(MidiSong *song)
   419 {
   420   int i = song->voices;
   421   int c = song->current_event->channel;
   422 
   423   SNDDBG(("All notes off on channel %d", c));
   424   while (i--)
   425     if (song->voice[i].status == VOICE_ON &&
   426 	song->voice[i].channel == c)
   427       {
   428 	if (song->channel[c].sustain) 
   429 	  song->voice[i].status = VOICE_SUSTAINED;
   430 	else
   431 	  finish_note(song, i);
   432       }
   433 }
   434 
   435 /* Process the All Sounds Off event */
   436 static void all_sounds_off(MidiSong *song)
   437 {
   438   int i = song->voices;
   439   int c = song->current_event->channel;
   440 
   441   while (i--)
   442     if (song->voice[i].channel == c && 
   443 	song->voice[i].status != VOICE_FREE &&
   444 	song->voice[i].status != VOICE_DIE)
   445       {
   446 	kill_note(song, i);
   447       }
   448 }
   449 
   450 static void adjust_pressure(MidiSong *song)
   451 {
   452   MidiEvent *e = song->current_event;
   453   int i = song->voices;
   454   
   455   while (i--)
   456     if (song->voice[i].status == VOICE_ON &&
   457 	song->voice[i].channel == e->channel &&
   458 	song->voice[i].note == e->a)
   459       {
   460 	song->voice[i].velocity = e->b;
   461 	recompute_amp(song, i);
   462 	apply_envelope_to_amp(song, i);
   463 	return;
   464       }
   465 }
   466 
   467 static void drop_sustain(MidiSong *song)
   468 {
   469   int i = song->voices;
   470   int c = song->current_event->channel;
   471 
   472   while (i--)
   473     if (song->voice[i].status == VOICE_SUSTAINED && song->voice[i].channel == c)
   474       finish_note(song, i);
   475 }
   476 
   477 static void adjust_pitchbend(MidiSong *song)
   478 {
   479   int c = song->current_event->channel;
   480   int i = song->voices;
   481   
   482   while (i--)
   483     if (song->voice[i].status != VOICE_FREE && song->voice[i].channel == c)
   484       {
   485 	recompute_freq(song, i);
   486       }
   487 }
   488 
   489 static void adjust_volume(MidiSong *song)
   490 {
   491   int c = song->current_event->channel;
   492   int i = song->voices;
   493 
   494   while (i--)
   495     if (song->voice[i].channel == c &&
   496 	(song->voice[i].status==VOICE_ON || song->voice[i].status==VOICE_SUSTAINED))
   497       {
   498 	recompute_amp(song, i);
   499 	apply_envelope_to_amp(song, i);
   500       }
   501 }
   502 
   503 static void seek_forward(MidiSong *song, Sint32 until_time)
   504 {
   505   reset_voices(song);
   506   while (song->current_event->time < until_time)
   507     {
   508       switch(song->current_event->type)
   509 	{
   510 	  /* All notes stay off. Just handle the parameter changes. */
   511 
   512 	case ME_PITCH_SENS:
   513 	  song->channel[song->current_event->channel].pitchsens =
   514 	    song->current_event->a;
   515 	  song->channel[song->current_event->channel].pitchfactor = 0;
   516 	  break;
   517 	  
   518 	case ME_PITCHWHEEL:
   519 	  song->channel[song->current_event->channel].pitchbend =
   520 	    song->current_event->a + song->current_event->b * 128;
   521 	  song->channel[song->current_event->channel].pitchfactor = 0;
   522 	  break;
   523 	  
   524 	case ME_MAINVOLUME:
   525 	  song->channel[song->current_event->channel].volume =
   526 	    song->current_event->a;
   527 	  break;
   528 	  
   529 	case ME_PAN:
   530 	  song->channel[song->current_event->channel].panning =
   531 	    song->current_event->a;
   532 	  break;
   533 	      
   534 	case ME_EXPRESSION:
   535 	  song->channel[song->current_event->channel].expression =
   536 	    song->current_event->a;
   537 	  break;
   538 	  
   539 	case ME_PROGRAM:
   540 	  if (ISDRUMCHANNEL(song, song->current_event->channel))
   541 	    /* Change drum set */
   542 	    song->channel[song->current_event->channel].bank =
   543 	      song->current_event->a;
   544 	  else
   545 	    song->channel[song->current_event->channel].program =
   546 	      song->current_event->a;
   547 	  break;
   548 
   549 	case ME_SUSTAIN:
   550 	  song->channel[song->current_event->channel].sustain =
   551 	    song->current_event->a;
   552 	  break;
   553 
   554 	case ME_RESET_CONTROLLERS:
   555 	  reset_controllers(song, song->current_event->channel);
   556 	  break;
   557 	      
   558 	case ME_TONE_BANK:
   559 	  song->channel[song->current_event->channel].bank =
   560 	    song->current_event->a;
   561 	  break;
   562 	  
   563 	case ME_EOT:
   564 	  song->current_sample = song->current_event->time;
   565 	  return;
   566 	}
   567       song->current_event++;
   568     }
   569   /*song->current_sample=song->current_event->time;*/
   570   if (song->current_event != song->events)
   571     song->current_event--;
   572   song->current_sample=until_time;
   573 }
   574 
   575 static void skip_to(MidiSong *song, Sint32 until_time)
   576 {
   577   if (song->current_sample > until_time)
   578     song->current_sample = 0;
   579 
   580   reset_midi(song);
   581   song->buffered_count = 0;
   582   song->buffer_pointer = song->common_buffer;
   583   song->current_event = song->events;
   584   
   585   if (until_time)
   586     seek_forward(song, until_time);
   587 }
   588 
   589 static void do_compute_data(MidiSong *song, Sint32 count)
   590 {
   591   int i;
   592   memset(song->buffer_pointer, 0, 
   593 	 (song->encoding & PE_MONO) ? (count * 4) : (count * 8));
   594   for (i = 0; i < song->voices; i++)
   595     {
   596       if(song->voice[i].status != VOICE_FREE)
   597 	mix_voice(song, song->buffer_pointer, i, count);
   598     }
   599   song->current_sample += count;
   600 }
   601 
   602 /* count=0 means flush remaining buffered data to output device, then
   603    flush the device itself */
   604 static void compute_data(MidiSong *song, void *stream, Sint32 count)
   605 {
   606   int channels;
   607 
   608   if ( song->encoding & PE_MONO )
   609     channels = 1;
   610   else
   611     channels = 2;
   612 
   613   if (!count)
   614     {
   615       if (song->buffered_count)
   616           song->write(stream, song->common_buffer, channels * song->buffered_count);
   617       song->buffer_pointer = song->common_buffer;
   618       song->buffered_count = 0;
   619       return;
   620     }
   621 
   622   while ((count + song->buffered_count) >= song->buffer_size)
   623     {
   624       do_compute_data(song, song->buffer_size - song->buffered_count);
   625       count -= song->buffer_size - song->buffered_count;
   626       song->write(stream, song->common_buffer, channels * song->buffer_size);
   627       song->buffer_pointer = song->common_buffer;
   628       song->buffered_count = 0;
   629     }
   630   if (count>0)
   631     {
   632       do_compute_data(song, count);
   633       song->buffered_count += count;
   634       song->buffer_pointer += (song->encoding & PE_MONO) ? count : count*2;
   635     }
   636 }
   637 
   638 void Timidity_Start(MidiSong *song)
   639 {
   640   song->playing = 1;
   641   adjust_amplification(song);
   642   skip_to(song, 0);
   643 }
   644 
   645 void Timidity_Seek(MidiSong *song, Uint32 ms)
   646 {
   647     skip_to(song, (ms * song->rate) / 1000);
   648 }
   649 
   650 Uint32 Timidity_GetSongLength(MidiSong *song)
   651 {
   652   MidiEvent *last_event = &song->events[song->groomed_event_count - 1];
   653   /* We want last_event->time * 1000 / song->rate */
   654   Uint32 retvalue = (last_event->time / song->rate) * 1000;
   655   retvalue       += (last_event->time % song->rate) * 1000 / song->rate;
   656   return retvalue;
   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 = 1;
   668   bytes_per_sample *= ((song->encoding & PE_32BIT) ? 4 : ((song->encoding & PE_16BIT) ? 2 : 1));
   669   bytes_per_sample *= ((song->encoding & PE_MONO) ? 1 : 2);
   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 }