src/codecs/timidity/playmidi.c
author Ozkan Sezer
Mon, 16 Dec 2019 10:33:55 +0300
changeset 1083 7a3b49dbf90f
parent 999 1a87fe70802d
permissions -rw-r--r--
timidity: minor warning fixes

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