Mercurial > SDL_sound_CoreAudio
view decoders/timidity/instrum.c @ 566:74405e7be04b
Moved SNDDBG output a little later.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Fri, 30 Jan 2009 19:54:58 -0500 |
parents | cbc2a4ffeeec |
children |
line wrap: on
line source
/* TiMidity -- Experimental MIDI to WAVE converter Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. instrum.c Code to load and unload GUS-compatible instrument patches. */ #if HAVE_CONFIG_H # include <config.h> #endif #include <stdio.h> #include <string.h> #include <stdlib.h> #include "SDL_sound.h" #define __SDL_SOUND_INTERNAL__ #include "SDL_sound_internal.h" #include "timidity.h" #include "options.h" #include "common.h" #include "instrum.h" #include "instrum_dls.h" #include "resample.h" #include "tables.h" static void free_instrument(Instrument *ip) { Sample *sp; int i; if (!ip) return; for (i=0; i<ip->samples; i++) { sp=&(ip->sample[i]); free(sp->data); } free(ip->sample); free(ip); } static void free_bank(MidiSong *song, int dr, int b) { int i; ToneBank *bank=((dr) ? song->drumset[b] : song->tonebank[b]); for (i=0; i<128; i++) if (bank->instrument[i]) { /* Not that this could ever happen, of course */ if (bank->instrument[i] != MAGIC_LOAD_INSTRUMENT) free_instrument(bank->instrument[i]); bank->instrument[i]=0; } } static Sint32 convert_envelope_rate(MidiSong *song, Uint8 rate) { Sint32 r; r = 3 - ((rate >> 6) & 0x3); r *= 3; r = (Sint32) (rate & 0x3f) << r; /* 6.9 fixed point */ /* 15.15 fixed point. */ r = ((r * 44100) / song->rate) * song->control_ratio; #ifdef FAST_DECAY return r << 10; #else return r << 9; #endif } static Sint32 convert_envelope_offset(Uint8 offset) { /* This is not too good... Can anyone tell me what these values mean? Are they GUS-style "exponential" volumes? And what does that mean? */ /* 15.15 fixed point */ return offset << (7+15); } static Sint32 convert_tremolo_sweep(MidiSong *song, Uint8 sweep) { if (!sweep) return 0; return ((song->control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) / (song->rate * sweep); } static Sint32 convert_vibrato_sweep(MidiSong *song, Uint8 sweep, Sint32 vib_control_ratio) { if (!sweep) return 0; return (Sint32) (FSCALE((double) (vib_control_ratio) * SWEEP_TUNING, SWEEP_SHIFT) / (double)(song->rate * sweep)); /* this was overflowing with seashore.pat ((vib_control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) / (song->rate * sweep); */ } static Sint32 convert_tremolo_rate(MidiSong *song, Uint8 rate) { return ((SINE_CYCLE_LENGTH * song->control_ratio * rate) << RATE_SHIFT) / (TREMOLO_RATE_TUNING * song->rate); } static Sint32 convert_vibrato_rate(MidiSong *song, Uint8 rate) { /* Return a suitable vibrato_control_ratio value */ return (VIBRATO_RATE_TUNING * song->rate) / (rate * 2 * VIBRATO_SAMPLE_INCREMENTS); } static void reverse_data(Sint16 *sp, Sint32 ls, Sint32 le) { Sint16 s, *ep=sp+le; sp+=ls; le-=ls; le/=2; while (le--) { s=*sp; *sp++=*ep; *ep--=s; } } /* If panning or note_to_use != -1, it will be used for all samples, instead of the sample-specific values in the instrument file. For note_to_use, any value <0 or >127 will be forced to 0. For other parameters, 1 means yes, 0 means no, other values are undefined. TODO: do reverse loops right */ static Instrument *load_instrument(MidiSong *song, char *name, int percussion, int panning, int amp, int note_to_use, int strip_loop, int strip_envelope, int strip_tail) { Instrument *ip; Sample *sp; SDL_RWops *rw; char tmp[1024]; int i,j,noluck=0; static char *patch_ext[] = PATCH_EXT_LIST; if (!name) return 0; /* Open patch file */ if ((rw=open_file(name)) == NULL) { noluck=1; /* Try with various extensions */ for (i=0; patch_ext[i]; i++) { if (strlen(name)+strlen(patch_ext[i])<1024) { strcpy(tmp, name); strcat(tmp, patch_ext[i]); if ((rw=open_file(tmp)) != NULL) { noluck=0; break; } } } } if (noluck) { SNDDBG(("Instrument `%s' can't be found.\n", name)); return 0; } SNDDBG(("Loading instrument %s\n", tmp)); /* Read some headers and do cursory sanity checks. There are loads of magic offsets. This could be rewritten... */ if ((239 != SDL_RWread(rw, tmp, 1, 239)) || (memcmp(tmp, "GF1PATCH110\0ID#000002", 22) && memcmp(tmp, "GF1PATCH100\0ID#000002", 22))) /* don't know what the differences are */ { SNDDBG(("%s: not an instrument\n", name)); return 0; } if (tmp[82] != 1 && tmp[82] != 0) /* instruments. To some patch makers, 0 means 1 */ { SNDDBG(("Can't handle patches with %d instruments\n", tmp[82])); return 0; } if (tmp[151] != 1 && tmp[151] != 0) /* layers. What's a layer? */ { SNDDBG(("Can't handle instruments with %d layers\n", tmp[151])); return 0; } ip=safe_malloc(sizeof(Instrument)); ip->samples = tmp[198]; ip->sample = safe_malloc(sizeof(Sample) * ip->samples); for (i=0; i<ip->samples; i++) { Uint8 fractions; Sint32 tmplong; Uint16 tmpshort; Uint8 tmpchar; #define READ_CHAR(thing) \ if (1 != SDL_RWread(rw, &tmpchar, 1, 1)) goto fail; \ thing = tmpchar; #define READ_SHORT(thing) \ if (1 != SDL_RWread(rw, &tmpshort, 2, 1)) goto fail; \ thing = SDL_SwapLE16(tmpshort); #define READ_LONG(thing) \ if (1 != SDL_RWread(rw, &tmplong, 4, 1)) goto fail; \ thing = SDL_SwapLE32(tmplong); SDL_RWseek(rw, 7, SEEK_CUR); /* Skip the wave name */ if (1 != SDL_RWread(rw, &fractions, 1, 1)) { fail: SNDDBG(("Error reading sample %d\n", i)); for (j=0; j<i; j++) free(ip->sample[j].data); free(ip->sample); free(ip); return 0; } sp=&(ip->sample[i]); READ_LONG(sp->data_length); READ_LONG(sp->loop_start); READ_LONG(sp->loop_end); READ_SHORT(sp->sample_rate); READ_LONG(sp->low_freq); READ_LONG(sp->high_freq); READ_LONG(sp->root_freq); sp->low_vel = 0; sp->high_vel = 127; SDL_RWseek(rw, 2, SEEK_CUR); /* Why have a "root frequency" and then * "tuning"?? */ READ_CHAR(tmp[0]); if (panning==-1) sp->panning = (tmp[0] * 8 + 4) & 0x7f; else sp->panning=(Uint8)(panning & 0x7F); /* envelope, tremolo, and vibrato */ if (18 != SDL_RWread(rw, tmp, 1, 18)) goto fail; if (!tmp[13] || !tmp[14]) { sp->tremolo_sweep_increment= sp->tremolo_phase_increment=sp->tremolo_depth=0; SNDDBG((" * no tremolo\n")); } else { sp->tremolo_sweep_increment=convert_tremolo_sweep(song, tmp[12]); sp->tremolo_phase_increment=convert_tremolo_rate(song, tmp[13]); sp->tremolo_depth=tmp[14]; SNDDBG((" * tremolo: sweep %d, phase %d, depth %d\n", sp->tremolo_sweep_increment, sp->tremolo_phase_increment, sp->tremolo_depth)); } if (!tmp[16] || !tmp[17]) { sp->vibrato_sweep_increment= sp->vibrato_control_ratio=sp->vibrato_depth=0; SNDDBG((" * no vibrato\n")); } else { sp->vibrato_control_ratio=convert_vibrato_rate(song, tmp[16]); sp->vibrato_sweep_increment= convert_vibrato_sweep(song, tmp[15], sp->vibrato_control_ratio); sp->vibrato_depth=tmp[17]; SNDDBG((" * vibrato: sweep %d, ctl %d, depth %d\n", sp->vibrato_sweep_increment, sp->vibrato_control_ratio, sp->vibrato_depth)); } READ_CHAR(sp->modes); SDL_RWseek(rw, 40, SEEK_CUR); /* skip the useless scale frequency, scale factor (what's it mean?), and reserved space */ /* Mark this as a fixed-pitch instrument if such a deed is desired. */ if (note_to_use!=-1) sp->note_to_use=(Uint8)(note_to_use); else sp->note_to_use=0; /* seashore.pat in the Midia patch set has no Sustain. I don't understand why, and fixing it by adding the Sustain flag to all looped patches probably breaks something else. We do it anyway. */ if (sp->modes & MODES_LOOPING) sp->modes |= MODES_SUSTAIN; /* Strip any loops and envelopes we're permitted to */ if ((strip_loop==1) && (sp->modes & (MODES_SUSTAIN | MODES_LOOPING | MODES_PINGPONG | MODES_REVERSE))) { SNDDBG((" - Removing loop and/or sustain\n")); sp->modes &=~(MODES_SUSTAIN | MODES_LOOPING | MODES_PINGPONG | MODES_REVERSE); } if (strip_envelope==1) { if (sp->modes & MODES_ENVELOPE) SNDDBG((" - Removing envelope\n")); sp->modes &= ~MODES_ENVELOPE; } else if (strip_envelope != 0) { /* Have to make a guess. */ if (!(sp->modes & (MODES_LOOPING | MODES_PINGPONG | MODES_REVERSE))) { /* No loop? Then what's there to sustain? No envelope needed either... */ sp->modes &= ~(MODES_SUSTAIN|MODES_ENVELOPE); SNDDBG((" - No loop, removing sustain and envelope\n")); } else if (!memcmp(tmp, "??????", 6) || tmp[11] >= 100) { /* Envelope rates all maxed out? Envelope end at a high "offset"? That's a weird envelope. Take it out. */ sp->modes &= ~MODES_ENVELOPE; SNDDBG((" - Weirdness, removing envelope\n")); } else if (!(sp->modes & MODES_SUSTAIN)) { /* No sustain? Then no envelope. I don't know if this is justified, but patches without sustain usually don't need the envelope either... at least the Gravis ones. They're mostly drums. I think. */ sp->modes &= ~MODES_ENVELOPE; SNDDBG((" - No sustain, removing envelope\n")); } } for (j=0; j<6; j++) { sp->envelope_rate[j]= convert_envelope_rate(song, tmp[j]); sp->envelope_offset[j]= convert_envelope_offset(tmp[6+j]); } /* Then read the sample data */ sp->data = safe_malloc(sp->data_length); if (1 != SDL_RWread(rw, sp->data, sp->data_length, 1)) goto fail; if (!(sp->modes & MODES_16BIT)) /* convert to 16-bit data */ { Sint32 i=sp->data_length; Uint8 *cp=(Uint8 *)(sp->data); Uint16 *tmp,*new; tmp=new=safe_malloc(sp->data_length*2); while (i--) *tmp++ = (Uint16)(*cp++) << 8; cp=(Uint8 *)(sp->data); sp->data = (sample_t *)new; free(cp); sp->data_length *= 2; sp->loop_start *= 2; sp->loop_end *= 2; } #if SDL_BYTEORDER == SDL_BIG_ENDIAN else /* convert to machine byte order */ { Sint32 i=sp->data_length/2; Sint16 *tmp=(Sint16 *)sp->data,s; while (i--) { s=SDL_SwapLE16(*tmp); *tmp++=s; } } #endif if (sp->modes & MODES_UNSIGNED) /* convert to signed data */ { Sint32 i=sp->data_length/2; Sint16 *tmp=(Sint16 *)sp->data; while (i--) *tmp++ ^= 0x8000; } /* Reverse reverse loops and pass them off as normal loops */ if (sp->modes & MODES_REVERSE) { Sint32 t; /* The GUS apparently plays reverse loops by reversing the whole sample. We do the same because the GUS does not SUCK. */ SNDDBG(("Reverse loop in %s\n", name)); reverse_data((Sint16 *)sp->data, 0, sp->data_length/2); t=sp->loop_start; sp->loop_start=sp->data_length - sp->loop_end; sp->loop_end=sp->data_length - t; sp->modes &= ~MODES_REVERSE; sp->modes |= MODES_LOOPING; /* just in case */ } #ifdef ADJUST_SAMPLE_VOLUMES if (amp!=-1) sp->volume=(float)((amp) / 100.0); else { /* Try to determine a volume scaling factor for the sample. This is a very crude adjustment, but things sound more balanced with it. Still, this should be a runtime option. */ Sint32 i=sp->data_length/2; Sint16 maxamp=0,a; Sint16 *tmp=(Sint16 *)sp->data; while (i--) { a=*tmp++; if (a<0) a=-a; if (a>maxamp) maxamp=a; } sp->volume=(float)(32768.0 / maxamp); SNDDBG((" * volume comp: %f\n", sp->volume)); } #else if (amp!=-1) sp->volume=(double)(amp) / 100.0; else sp->volume=1.0; #endif sp->data_length /= 2; /* These are in bytes. Convert into samples. */ sp->loop_start /= 2; sp->loop_end /= 2; /* Then fractional samples */ sp->data_length <<= FRACTION_BITS; sp->loop_start <<= FRACTION_BITS; sp->loop_end <<= FRACTION_BITS; /* Adjust for fractional loop points. This is a guess. Does anyone know what "fractions" really stands for? */ sp->loop_start |= (fractions & 0x0F) << (FRACTION_BITS-4); sp->loop_end |= ((fractions>>4) & 0x0F) << (FRACTION_BITS-4); /* If this instrument will always be played on the same note, and it's not looped, we can resample it now. */ if (sp->note_to_use && !(sp->modes & MODES_LOOPING)) pre_resample(song, sp); if (strip_tail==1) { /* Let's not really, just say we did. */ SNDDBG((" - Stripping tail\n")); sp->data_length = sp->loop_end; } } SDL_RWclose(rw); return ip; } static int fill_bank(MidiSong *song, int dr, int b) { int i, errors=0; ToneBank *bank=((dr) ? song->drumset[b] : song->tonebank[b]); if (!bank) { SNDDBG(("Huh. Tried to load instruments in non-existent %s %d\n", (dr) ? "drumset" : "tone bank", b)); return 0; } for (i=0; i<128; i++) { if (bank->instrument[i]==MAGIC_LOAD_INSTRUMENT) { bank->instrument[i]=load_instrument_dls(song, dr, b, i); if (bank->instrument[i]) { continue; } if (!(bank->tone[i].name)) { SNDDBG(("No instrument mapped to %s %d, program %d%s\n", (dr)? "drum set" : "tone bank", b, i, (b!=0) ? "" : " - this instrument will not be heard")); if (b!=0) { /* Mark the corresponding instrument in the default bank / drumset for loading (if it isn't already) */ if (!dr) { if (!(song->tonebank[0]->instrument[i])) song->tonebank[0]->instrument[i] = MAGIC_LOAD_INSTRUMENT; } else { if (!(song->drumset[0]->instrument[i])) song->drumset[0]->instrument[i] = MAGIC_LOAD_INSTRUMENT; } } bank->instrument[i] = 0; errors++; } else if (!(bank->instrument[i] = load_instrument(song, bank->tone[i].name, (dr) ? 1 : 0, bank->tone[i].pan, bank->tone[i].amp, (bank->tone[i].note!=-1) ? bank->tone[i].note : ((dr) ? i : -1), (bank->tone[i].strip_loop!=-1) ? bank->tone[i].strip_loop : ((dr) ? 1 : -1), (bank->tone[i].strip_envelope != -1) ? bank->tone[i].strip_envelope : ((dr) ? 1 : -1), bank->tone[i].strip_tail ))) { SNDDBG(("Couldn't load instrument %s (%s %d, program %d)\n", bank->tone[i].name, (dr)? "drum set" : "tone bank", b, i)); errors++; } } } return errors; } int load_missing_instruments(MidiSong *song) { int i=128,errors=0; while (i--) { if (song->tonebank[i]) errors+=fill_bank(song,0,i); if (song->drumset[i]) errors+=fill_bank(song,1,i); } return errors; } void free_instruments(MidiSong *song) { int i=128; while(i--) { if (song->tonebank[i]) free_bank(song, 0, i); if (song->drumset[i]) free_bank(song, 1, i); } } int set_default_instrument(MidiSong *song, char *name) { Instrument *ip; if (!(ip=load_instrument(song, name, 0, -1, -1, -1, 0, 0, 0))) return -1; song->default_instrument = ip; song->default_program = SPECIAL_PROGRAM; return 0; }