Mercurial > audlegacy-plugins
comparison src/Input/timidity/libtimidity/playmidi.c @ 0:13389e613d67 trunk
[svn] - initial import of audacious-plugins tree (lots to do)
| author | nenolod |
|---|---|
| date | Mon, 18 Sep 2006 01:11:49 -0700 |
| parents | |
| children | 088092a52fea |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:13389e613d67 |
|---|---|
| 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 "libaudacious/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 } |
