From c80b2de38ded12cf6878fe3d299527a4b6eff18b Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 17 Oct 2017 21:54:04 -0700 Subject: [PATCH] Merged over timidity from SDL_sound This has changes to make it safe to load MIDI files as sound chunks and adds the ability to seek in MIDI files Also cherry picked some patches from the original SDL_mixer timidity to fix buffer overruns and so forth. --- mixer.c | 1 - music_timidity.c | 42 +- timidity/CHANGES | 77 ++ timidity/FAQ | 14 +- timidity/README | 3 +- timidity/TODO | 37 + timidity/common.c | 257 ++-- timidity/common.h | 29 +- timidity/config.h | 226 ---- timidity/ctrlmode.c | 26 - timidity/ctrlmode.h | 74 -- timidity/dls1.h | 266 ++++ timidity/dls2.h | 130 ++ timidity/filter.c | 191 --- timidity/filter.h | 23 - timidity/instrum.c | 781 +++--------- timidity/instrum.h | 152 +-- timidity/instrum_dls.c | 1255 +++++++++++++++++++ timidity/{sdl_a.c => instrum_dls.h} | 14 +- timidity/mix.c | 670 +++-------- timidity/mix.h | 12 +- timidity/options.h | 117 ++ timidity/output.c | 90 +- timidity/output.h | 41 +- timidity/playmidi.c | 1741 ++++++--------------------- timidity/playmidi.h | 117 +- timidity/readmidi.c | 810 +++---------- timidity/readmidi.h | 15 +- timidity/resample.c | 374 ++---- timidity/resample.h | 9 +- timidity/sdl_c.c | 133 -- timidity/tables.c | 935 +------------- timidity/tables.h | 35 +- timidity/timidity.c | 804 ++++++++----- timidity/timidity.h | 170 ++- 35 files changed, 3815 insertions(+), 5856 deletions(-) create mode 100644 timidity/CHANGES create mode 100644 timidity/TODO delete mode 100644 timidity/config.h delete mode 100644 timidity/ctrlmode.c delete mode 100644 timidity/ctrlmode.h create mode 100644 timidity/dls1.h create mode 100644 timidity/dls2.h delete mode 100644 timidity/filter.c delete mode 100644 timidity/filter.h create mode 100644 timidity/instrum_dls.c rename timidity/{sdl_a.c => instrum_dls.h} (61%) create mode 100644 timidity/options.h delete mode 100644 timidity/sdl_c.c diff --git a/mixer.c b/mixer.c index b927074d..46a6d9c0 100644 --- a/mixer.c +++ b/mixer.c @@ -568,7 +568,6 @@ static SDL_AudioSpec *Mix_LoadMusic_RW(Mix_MusicType music_type, SDL_RWops *src, /* These music interfaces are not safe to use while music is playing */ if (interface->api == MIX_MUSIC_CMD || interface->api == MIX_MUSIC_MIKMOD || - interface->api == MIX_MUSIC_TIMIDITY || interface->api == MIX_MUSIC_NATIVEMIDI) { continue; } diff --git a/music_timidity.c b/music_timidity.c index f1841518..0e319e7a 100644 --- a/music_timidity.c +++ b/music_timidity.c @@ -28,35 +28,29 @@ #include "timidity/timidity.h" -static int samplesize; - static int TIMIDITY_Open(const SDL_AudioSpec *spec) { - samplesize = spec->size / spec->samples; - if (Timidity_Init(spec->freq, spec->format, spec->channels, spec->samples) != 0) { - Mix_SetError("%s", Timidity_Error()); - return -1; - } - return 0; + return Timidity_Init(); } static void TIMIDITY_Close(void) { - Timidity_Close(); + Timidity_Exit(); } void *TIMIDITY_CreateFromRW(SDL_RWops *src, int freesrc) { - MidiSong *music = Timidity_LoadSong_RW(src, freesrc); - if (!music) { - Mix_SetError("%s", Timidity_Error()); + MidiSong *music = Timidity_LoadSong(src, &music_spec); + if (music && freesrc) { + SDL_RWclose(src); } return music; } static void TIMIDITY_SetVolume(void *context, int volume) { - Timidity_SetVolume(volume); + MidiSong *music = (MidiSong *)context; + Timidity_SetVolume(music, volume); } static int TIMIDITY_Play(void *context) @@ -66,21 +60,21 @@ static int TIMIDITY_Play(void *context) return 0; } -static SDL_bool TIMIDITY_IsPlaying(void *context) -{ - return Timidity_Active() ? SDL_TRUE : SDL_FALSE; -} - static int TIMIDITY_GetAudio(void *context, void *data, int bytes) { - int samples = (bytes / samplesize); - Timidity_PlaySome(data, samples); + MidiSong *music = (MidiSong *)context; + if (!Timidity_PlaySome(music, data, bytes)) { + /* Nothing consumed, everything left */ + return bytes; + } return 0; } -static void TIMIDITY_Stop(void *context) +static int TIMIDITY_Seek(void *context, double position) { - Timidity_Stop(); + MidiSong *music = (MidiSong *)context; + Timidity_Seek(music, (Uint32)(position * 1000)); + return 0; } static void TIMIDITY_Delete(void *context) @@ -103,9 +97,9 @@ Mix_MusicInterface Mix_MusicInterface_TIMIDITY = NULL, /* CreateFromFile */ TIMIDITY_SetVolume, TIMIDITY_Play, - TIMIDITY_IsPlaying, + NULL, /* IsPlaying */ TIMIDITY_GetAudio, - NULL, /* Seek */ + TIMIDITY_Seek, NULL, /* Pause */ NULL, /* Resume */ NULL, /* Stop */ diff --git a/timidity/CHANGES b/timidity/CHANGES new file mode 100644 index 00000000..ab79e993 --- /dev/null +++ b/timidity/CHANGES @@ -0,0 +1,77 @@ +This version of TiMidity should contain all the fixes from the +September 25 2003 SDL_mixer CVS snapshot. In addition, I've made some +changes of my own, e.g.: + +* All file access is done through SDL_RWops. This means the MIDI + stream no longer has to be a file. (The config file and instruments + still have to be though.) + +* Replacing of TiMidity's endian-handling with SDL's. + +* Removal of much unused or unnecessary code, such as + + + The "hooks" for putting a user interface onto TiMidity. + + The antialias filter. It wasn't active, and even at 4 kHz I + couldn't hear any difference when activating it. + + Removed all traces of LOOKUP_HACK and LOOKUP_INTERPOLATION. + According to the code comments they weren't very good anyway. + ("degrades sound quality noticeably"). I also removed the + disclaimer about the "8-bit uLaw to 16-bit PCM and the 13-bit-PCM + to 8-bit uLaw tables" disclaimer, since I believe those were the + tables I removed. + + Removed LOOKUP_SINE since it was already commented out. I think we + can count on our target audience having math co-processors + nowadays. + + Removed USE_LDEXP since it wasn't being used and "it doesn't make + much of a difference either way". + + Removed decompress hack from open_file() since it didn't look very + portable. + + Removed heaps of unnecessary constants. + + Removed unused functions. + + Assume that LINEAR_INTERPOLATION is always used, so remove all + code dealing with it not being so. It's not that I think the + difference in audio quality is that great, but since it wouldn't + compile without code changes I assume no one's used it for quite + some time... + + Assume PRECALC_LOOPS is always defined. Judging by the comments it + may not make much of a difference either way, so why maintain two + versions of the same code? + +* Moving several static globals into the MidiSong struct. This + includes sample rate, formate, etc. which are now all per-song. + +* Moved some typedefs (e.g. MidiSong) to timidity.h for easy inclusion + into the MIDI decoder. + +* Added free_pathlist(). + +* Replaced TiMidity's own 8, 16 and 32-bit types with SDL's. + +* Made TiMidity look for its configuration file in both /etc and + /usr/local/lib/timidity. (Windows version remains unchanged.) + +* Timidity_PlaySome() now takes three arguments. A MidiSong, a decode + buffer and decode buffer size in bytes. (MidiSong is a new argument, + and buffer size used to be in samples.) + + In addition, it will return the number of bytes decoded. + +* Added Timidity_Exit(). + +* Removed Timidity_Stop() and Timidity_Active(). Stopping playback + should be handled by SDL_sound, and Timidity_PlaySome() will return + 0 when the MIDI stream is finished. + +* Modified the ToneBank stuff to allow some data to be shared between + MidiSongs. + +* The following files have been removed: controls.c, controls.h, + filter.c, filter.h, sdl_a.c, sdl_c.c + +* config.h has been renamed as options.h to avoid confusion with the + automatically generated config.h for SDL_sound. + +* Added support for loading DLS format instruments: + Timidity_LoadDLS(), Timidity_FreeDLS(), Timidity_LoadDLSSong() + +* Added Timidity_Init_NoConfig() diff --git a/timidity/FAQ b/timidity/FAQ index f1f8e237..1ee0b77b 100644 --- a/timidity/FAQ +++ b/timidity/FAQ @@ -92,19 +92,7 @@ A: Here are some things to try: - Use a smaller number of simultaneous voices. - - Make sure you compiled with FAST_DECAY and PRECALC_LOOPS enabled - in config.h - - - If you don't have hardware to compute sines, recompile with - LOOKUP_SINE enabled in config.h - - - Recompile with LOOKUP_HACK enabled in config.h. - - - Recompile with LINEAR_INTERPOLATION disabled in config.h. - - - Recompile with DANGEROUS_RENICE enabled in config.h, and make - TiMidity setuid root. This will help only if you frequently play - music while other processes are running. + - Make sure you compiled with FAST_DECAY enabled in options.h - Recompile with an Intel-optimized gcc for a 5-15% performance increase. diff --git a/timidity/README b/timidity/README index e0882f3d..0dd9892c 100644 --- a/timidity/README +++ b/timidity/README @@ -1,4 +1,5 @@ -[This version of timidity has been stripped for simplicity in porting to SDL] +[This version of timidity has been stripped for simplicity in porting to SDL, +and then even further for SDL_sound] ---------------------------------*-text-*--------------------------------- From http://www.cgs.fi/~tt/discontinued.html : diff --git a/timidity/TODO b/timidity/TODO new file mode 100644 index 00000000..69b37ee2 --- /dev/null +++ b/timidity/TODO @@ -0,0 +1,37 @@ +* I don't like the indentation style at all, but for the most part + I've left it alone. + +* Much of the code looks ugly to me. + +* The return value from SDL_RWread() is checked inconsistenly. + +* Group the members of MidiSong into logical units, i.e. structs? + +* The debug messages are probably a bit too noisy. I've removed one + particularly annoying one, but... + + Some of them should be turned into error messages instead. + +* Can the instrument handling be made more efficient? At the moment + different MidiSongs may separately load the same instrument. + + Note that the MidiSong's audio format affects how the instrument is + loaded, so it's not as easy as just letting all MidiSongs share tone + and drum banks. + + At the moment they do share the data that is simply read from the + config file, but that's just a quick hack to avoid having to read + the config file every time a MIDI song is loaded. + +* Check if any of MidiStruct's members can safely be made into static + globals again. + +* TiMidity++ adds a number of undocumented (?) extensions to the + configuration syntax. These are not implemented here. In particular, + the "map" keyword used by the "eawpats". + +* The other decoders generally only read as much of the file as is + necessary. Could we do that in this decoder as well? (Currently it + seems to convert the entire file into MIDI events first.) + +* Can it be optimized? diff --git a/timidity/common.c b/timidity/common.c index 3d6801e2..5835eb9a 100644 --- a/timidity/common.c +++ b/timidity/common.c @@ -1,243 +1,122 @@ /* + TiMidity -- Experimental MIDI to WAVE converter Copyright (C) 1995 Tuukka Toivonen This program is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License, available in COPYING. - */ + + common.c +*/ + +#if HAVE_CONFIG_H +# include +#endif #include #include #include -#include -#include "config.h" -#include "common.h" -#include "output.h" -#include "ctrlmode.h" - -/* I guess "rb" should be right for any libc */ -#define OPEN_MODE "rb" +#include "SDL.h" -char current_filename[PATH_MAX]; +#include "options.h" +#include "common.h" -static PathList *pathlist=NULL; +/* The paths in this list will be tried whenever we're reading a file */ +static PathList *pathlist = NULL; /* This is a linked list */ -/* Try to open a file for reading. If the filename ends in one of the - defined compressor extensions, pipe the file through the decompressor */ -static FILE *try_to_open(const char *name, int decompress, int noise_mode) +/* This is meant to find and open files for reading */ +SDL_RWops *open_file(const char *name) { - FILE *fp; - - fp=fopen(name, OPEN_MODE); /* First just check that the file exists */ - - if (!fp) - return 0; - -#ifdef DECOMPRESSOR_LIST - if (decompress) - { - int l,el; - static char *decompressor_list[] = DECOMPRESSOR_LIST, **dec; - const char *cp; - char tmp[PATH_MAX], tmp2[PATH_MAX], *cp2; - /* Check if it's a compressed file */ - l=strlen(name); - for (dec=decompressor_list; *dec; dec+=2) - { - el=strlen(*dec); - if ((el>=l) || (strcmp(name+l-el, *dec))) - continue; - - /* Yes. Close the file, open a pipe instead. */ - fclose(fp); - - /* Quote some special characters in the file name */ - cp=name; - cp2=tmp2; - while (*cp) - { - switch(*cp) - { - case '\'': - case '\\': - case ' ': - case '`': - case '!': - case '"': - case '&': - case ';': - *cp2++='\\'; - } - *cp2++=*cp++; - } - *cp2=0; - - sprintf(tmp, *(dec+1), tmp2); - fp=popen(tmp, "r"); - break; - } - } -#endif - - return fp; -} - -/* This is meant to find and open files for reading, possibly piping - them through a decompressor. */ -FILE *open_file(const char *name, int decompress, int noise_mode) -{ - FILE *fp; - PathList *plp; - int l; + SDL_RWops *rw; if (!name || !(*name)) { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Attempted to open nameless file."); + SNDDBG(("Attempted to open nameless file.\n")); return 0; } - if (pathlist==NULL) { - /* Generate path list */ -#ifdef DEFAULT_PATH - add_to_pathlist(DEFAULT_PATH); -#endif -#ifdef DEFAULT_PATH1 - add_to_pathlist(DEFAULT_PATH1); -#endif -#ifdef DEFAULT_PATH2 - add_to_pathlist(DEFAULT_PATH2); -#endif -#ifdef DEFAULT_PATH3 - add_to_pathlist(DEFAULT_PATH3); -#endif - } - /* First try the given name */ - strncpy(current_filename, name, PATH_MAX - 1); - current_filename[PATH_MAX - 1]='\0'; - - ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Trying to open %s", current_filename); - if ((fp=try_to_open(current_filename, decompress, noise_mode))) - return fp; - -#ifdef ENOENT - if (noise_mode && (errno != ENOENT)) - { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s", - current_filename, strerror(errno)); - return 0; - } -#endif + SNDDBG(("Trying to open %s\n", name)); + if ((rw = SDL_RWFromFile(name, "rb"))) + return rw; - plp=pathlist; if (name[0] != PATH_SEP) + { + char current_filename[1024]; + PathList *plp = pathlist; + int l; + while (plp) /* Try along the path then */ { - *current_filename=0; - l=(int)strlen(plp->path); + *current_filename = 0; + l = strlen(plp->path); if(l) { strcpy(current_filename, plp->path); - if(current_filename[l-1]!=PATH_SEP) - strcat(current_filename, PATH_STRING); + if(current_filename[l - 1] != PATH_SEP) + { + current_filename[l] = PATH_SEP; + current_filename[l + 1] = '\0'; + } } strcat(current_filename, name); - ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Trying to open %s", current_filename); - if ((fp=try_to_open(current_filename, decompress, noise_mode))) - return fp; -#ifdef ENOENT - if (noise_mode && (errno != ENOENT)) - { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s", - current_filename, strerror(errno)); - return 0; - } -#endif - plp=plp->next; + SNDDBG(("Trying to open %s\n", current_filename)); + if ((rw = SDL_RWFromFile(current_filename, "rb"))) + return rw; + plp = plp->next; } + } /* Nothing could be opened. */ - - *current_filename=0; - - if (noise_mode>=2) - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s", name, strerror(errno)); - + SNDDBG(("Could not open %s\n", name)); return 0; } -/* This closes files opened with open_file */ -void close_file(FILE *fp) -{ -#ifdef DECOMPRESSOR_LIST - if (pclose(fp)) /* Any better ideas? */ -#endif - fclose(fp); - - strncpy(current_filename, "MIDI file", PATH_MAX - 1); -} - -/* This is meant for skipping a few bytes in a file or fifo. */ -void skip(FILE *fp, size_t len) -{ - size_t c; - char tmp[PATH_MAX]; - while (len>0) - { - c=len; - if (c>PATH_MAX) c=PATH_MAX; - len-=c; - if (c!=fread(tmp, 1, c, fp)) - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: skip: %s", - current_filename, strerror(errno)); - } -} - /* This'll allocate memory or die. */ void *safe_malloc(size_t count) { void *p; - if (count > (1<<21)) - { - ctl->cmsg(CMSG_FATAL, VERB_NORMAL, - "Strange, I feel like allocating %d bytes. This must be a bug.", - count); - } - else if ((p=malloc(count))) - return p; - else - ctl->cmsg(CMSG_FATAL, VERB_NORMAL, "Sorry. Couldn't malloc %d bytes.", count); - - ctl->close(); - exit(10); - return(NULL); + + p = malloc(count); + if (p == NULL) + SNDDBG(("Sorry. Couldn't malloc %d bytes.\n", count)); + + return p; } /* This adds a directory to the path list */ void add_to_pathlist(const char *s) { - PathList *plp=safe_malloc(sizeof(PathList)); - strcpy((plp->path=safe_malloc(strlen(s)+1)),s); - plp->next=pathlist; - pathlist=plp; + PathList *plp = safe_malloc(sizeof(PathList)); + + if (plp == NULL) + return; + + plp->path = safe_malloc(strlen(s) + 1); + if (plp->path == NULL) + { + free(plp); + return; + } + + strcpy(plp->path, s); + plp->next = pathlist; + pathlist = plp; } -/* Free memory associated to path list */ void free_pathlist(void) { - PathList *plp, *next_plp; + PathList *plp = pathlist; + PathList *next; - plp = pathlist; - while (plp) { - if (plp->path) { - free(plp->path); - plp->path=NULL; + while (plp) + { + next = plp->next; + free(plp->path); + free(plp); + plp = next; } - next_plp = plp->next; - free(plp); - plp = next_plp; - } - pathlist = NULL; + pathlist = NULL; } diff --git a/timidity/common.h b/timidity/common.h index 8d9c0ec8..cd7ab669 100644 --- a/timidity/common.h +++ b/timidity/common.h @@ -1,39 +1,20 @@ /* + TiMidity -- Experimental MIDI to WAVE converter Copyright (C) 1995 Tuukka Toivonen This program is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License, available in COPYING. - */ - -#include - -#ifndef PATH_MAX /* GNU Hurd doesn't limit path size, thus no PATH_MAX... */ -#define PATH_MAX 1024 /* ...so we'll just impose an arbitrary limit. */ -#endif - -extern char *program_name, current_filename[]; - -extern FILE *msgfp; -extern int num_ochannels; - -#define MULTICHANNEL_OUT -#define MAX_OUT_CHANNELS 6 + common.h +*/ typedef struct { char *path; void *next; } PathList; -/* Noise modes for open_file */ -#define OF_SILENT 0 -#define OF_NORMAL 1 -#define OF_VERBOSE 2 - -extern FILE *open_file(const char *name, int decompress, int noise_mode); +extern SDL_RWops *open_file(const char *name); extern void add_to_pathlist(const char *s); -extern void free_pathlist(void); -extern void close_file(FILE *fp); -extern void skip(FILE *fp, size_t len); extern void *safe_malloc(size_t count); +extern void free_pathlist(void); diff --git a/timidity/config.h b/timidity/config.h deleted file mode 100644 index 255acae5..00000000 --- a/timidity/config.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - TiMidity -- Experimental MIDI to WAVE converter - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the Perl Artistic License, available in COPYING. - */ - -/* This is for use with the SDL library */ -#define SDL -#include "SDL_config.h" -#include "SDL_endian.h" - -#define TIMIDITY_ERROR_SIZE 1024 - -/* When a patch file can't be opened, one of these extensions is - appended to the filename and the open is tried again. - */ -#define PATCH_EXT_LIST { ".pat", 0 } - -/* Acoustic Grand Piano seems to be the usual default instrument. */ -#define DEFAULT_PROGRAM 0 - -/* 9 here is MIDI channel 10, which is the standard percussion channel. - Some files (notably C:\WINDOWS\CANYON.MID) think that 16 is one too. - On the other hand, some files know that 16 is not a drum channel and - try to play music on it. This is now a runtime option, so this isn't - a critical choice anymore. */ -#define DEFAULT_DRUMCHANNELS (1<<9) - -/* A somewhat arbitrary frequency range. The low end of this will - sound terrible as no lowpass filtering is performed on most - instruments before resampling. */ -#define MIN_OUTPUT_RATE 4000 -#define MAX_OUTPUT_RATE 65000 - -/* In percent. */ -/* #define DEFAULT_AMPLIFICATION 70 */ -/* #define DEFAULT_AMPLIFICATION 50 */ -#define DEFAULT_AMPLIFICATION 30 - -/* Default sampling rate, default polyphony, and maximum polyphony. - All but the last can be overridden from the command line. */ -#define DEFAULT_RATE 32000 -/* #define DEFAULT_VOICES 32 */ -/* #define MAX_VOICES 48 */ -#define DEFAULT_VOICES 256 -#define MAX_VOICES 256 -#define MAXCHAN 16 -/* #define MAXCHAN 64 */ -#define MAXNOTE 128 - -/* 1000 here will give a control ratio of 22:1 with 22 kHz output. - Higher CONTROLS_PER_SECOND values allow more accurate rendering - of envelopes and tremolo. The cost is CPU time. */ -#define CONTROLS_PER_SECOND 1000 - -/* Strongly recommended. This option increases CPU usage by half, but - without it sound quality is very poor. */ -#define LINEAR_INTERPOLATION - -/* This is an experimental kludge that needs to be done right, but if - you've got an 8-bit sound card, or cheap multimedia speakers hooked - to your 16-bit output device, you should definitely give it a try. - - Defining LOOKUP_HACK causes table lookups to be used in mixing - instead of multiplication. We convert the sample data to 8 bits at - load time and volumes to logarithmic 7-bit values before looking up - the product, which degrades sound quality noticeably. - - Defining LOOKUP_HACK should save ~20% of CPU on an Intel machine. - LOOKUP_INTERPOLATION might give another ~5% */ -/* #define LOOKUP_HACK - #define LOOKUP_INTERPOLATION */ - -/* Make envelopes twice as fast. Saves ~20% CPU time (notes decay - faster) and sounds more like a GUS. There is now a command line - option to toggle this as well. */ -/* #define FAST_DECAY */ - -/* How many bits to use for the fractional part of sample positions. - This affects tonal accuracy. The entire position counter must fit - in 32 bits, so with FRACTION_BITS equal to 12, the maximum size of - a sample is 1048576 samples (2 megabytes in memory). The GUS gets - by with just 9 bits and a little help from its friends... - "The GUS does not SUCK!!!" -- a happy user :) */ -#define FRACTION_BITS 12 - -#define MAX_SAMPLE_SIZE (1 << (32-FRACTION_BITS)) - -typedef double FLOAT_T; - -/* For some reason the sample volume is always set to maximum in all - patch files. Define this for a crude adjustment that may help - equalize instrument volumes. */ -#define ADJUST_SAMPLE_VOLUMES - -/* The number of samples to use for ramping out a dying note. Affects - click removal. */ -#define MAX_DIE_TIME 20 - -/* On some machines (especially PCs without math coprocessors), - looking up sine values in a table will be significantly faster than - computing them on the fly. Uncomment this to use lookups. */ -/* #define LOOKUP_SINE */ - -/* Shawn McHorse's resampling optimizations. These may not in fact be - faster on your particular machine and compiler. You'll have to run - a benchmark to find out. */ -#define PRECALC_LOOPS - -/* If calling ldexp() is faster than a floating point multiplication - on your machine/compiler/libm, uncomment this. It doesn't make much - difference either way, but hey -- it was on the TODO list, so it - got done. */ -/* #define USE_LDEXP */ - -/**************************************************************************/ -/* Anything below this shouldn't need to be changed unless you're porting - to a new machine with other than 32-bit, big-endian words. */ -/**************************************************************************/ - -/* change FRACTION_BITS above, not these */ -#define INTEGER_BITS (32 - FRACTION_BITS) -#define INTEGER_MASK (0xFFFFFFFF << FRACTION_BITS) -#define FRACTION_MASK (~ INTEGER_MASK) - -/* This is enforced by some computations that must fit in an int */ -#define MAX_CONTROL_RATIO 255 - -typedef unsigned int uint32; -typedef int int32; -typedef unsigned short uint16; -typedef short int16; -typedef unsigned char uint8; -typedef char int8; - -/* Instrument files are little-endian, MIDI files big-endian, so we - need to do some conversions. */ - -#define XCHG_SHORT(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF)) -# define XCHG_LONG(x) ((((x)&0xFF)<<24) | \ - (((x)&0xFF00)<<8) | \ - (((x)&0xFF0000)>>8) | \ - (((x)>>24)&0xFF)) - -#if SDL_BYTEORDER == SDL_LIL_ENDIAN -#define LE_SHORT(x) x -#define LE_LONG(x) x -#define BE_SHORT(x) XCHG_SHORT(x) -#define BE_LONG(x) XCHG_LONG(x) -#else -#define BE_SHORT(x) x -#define BE_LONG(x) x -#define LE_SHORT(x) XCHG_SHORT(x) -#define LE_LONG(x) XCHG_LONG(x) -#endif - -#define MAX_AMPLIFICATION 800 - -/* You could specify a complete path, e.g. "/etc/timidity.cfg", and - then specify the library directory in the configuration file. */ -#define CONFIG_FILE "timidity.cfg" -#define CONFIG_FILE_ETC "/etc/timidity.cfg" -#define CONFIG_FILE_ETC_TIMIDITY_FREEPATS "/etc/timidity/freepats.cfg" - -#if defined(__WIN32__) || defined(__OS2__) -#define DEFAULT_PATH "C:\\TIMIDITY" -#else -#define DEFAULT_PATH "/etc/timidity" -#define DEFAULT_PATH1 "/usr/share/timidity" -#define DEFAULT_PATH2 "/usr/local/share/timidity" -#define DEFAULT_PATH3 "/usr/local/lib/timidity" -#endif - -/* These affect general volume */ -#define GUARD_BITS 3 -#define AMP_BITS (15-GUARD_BITS) - -#ifdef LOOKUP_HACK - typedef int8 sample_t; - typedef uint8 final_volume_t; -# define FINAL_VOLUME(v) (~_l2u[v]) -# define MIXUP_SHIFT 5 -# define MAX_AMP_VALUE 4095 -#else - typedef int16 sample_t; - typedef int32 final_volume_t; -# define FINAL_VOLUME(v) (v) -# define MAX_AMP_VALUE ((1<<(AMP_BITS+1))-1) -#endif - -typedef int16 resample_t; - -#ifdef USE_LDEXP -# define FSCALE(a,b) ldexp((a),(b)) -# define FSCALENEG(a,b) ldexp((a),-(b)) -#else -# define FSCALE(a,b) (float)((a) * (double)(1<<(b))) -# define FSCALENEG(a,b) (float)((a) * (1.0L / (double)(1<<(b)))) -#endif - -/* Vibrato and tremolo Choices of the Day */ -#define SWEEP_TUNING 38 -#define VIBRATO_AMPLITUDE_TUNING 1.0L -#define VIBRATO_RATE_TUNING 38 -#define TREMOLO_AMPLITUDE_TUNING 1.0L -#define TREMOLO_RATE_TUNING 38 - -#define SWEEP_SHIFT 16 -#define RATE_SHIFT 5 - -#define VIBRATO_SAMPLE_INCREMENTS 32 - -#ifndef PI - #define PI 3.14159265358979323846 -#endif - -/* The path separator (D.M.) */ -#if defined(__WIN32__) || defined(__OS2__) -# define PATH_SEP '\\' -# define PATH_STRING "\\" -#else -# define PATH_SEP '/' -# define PATH_STRING "/" -#endif diff --git a/timidity/ctrlmode.c b/timidity/ctrlmode.c deleted file mode 100644 index facaa0b4..00000000 --- a/timidity/ctrlmode.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - TiMidity -- Experimental MIDI to WAVE converter - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the Perl Artistic License, available in COPYING. - */ - -#include "config.h" -#include "ctrlmode.h" - -#ifdef SDL - extern ControlMode sdl_control_mode; -# ifndef DEFAULT_CONTROL_MODE -# define DEFAULT_CONTROL_MODE &sdl_control_mode -# endif -#endif - -ControlMode *ctl_list[]={ -#ifdef SDL - &sdl_control_mode, -#endif - 0 -}; - -ControlMode *ctl=DEFAULT_CONTROL_MODE; diff --git a/timidity/ctrlmode.h b/timidity/ctrlmode.h deleted file mode 100644 index 5a116bc6..00000000 --- a/timidity/ctrlmode.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - TiMidity -- Experimental MIDI to WAVE converter - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the Perl Artistic License, available in COPYING. - */ - -/* Return values for ControlMode.read */ - -#define RC_ERROR -1 -#define RC_NONE 0 -#define RC_QUIT 1 -#define RC_NEXT 2 -#define RC_PREVIOUS 3 /* Restart this song at beginning, or the previous - song if we're less than a second into this one. */ -#define RC_FORWARD 4 -#define RC_BACK 5 -#define RC_JUMP 6 -#define RC_TOGGLE_PAUSE 7 /* Pause/continue */ -#define RC_RESTART 8 /* Restart song at beginning */ - -#define RC_PAUSE 9 /* Really pause playing */ -#define RC_CONTINUE 10 /* Continue if paused */ -#define RC_REALLY_PREVIOUS 11 /* Really go to the previous song */ -#define RC_CHANGE_VOLUME 12 -#define RC_LOAD_FILE 13 /* Load a new midifile */ -#define RC_TUNE_END 14 /* The tune is over, play it again sam? */ - -#define CMSG_INFO 0 -#define CMSG_WARNING 1 -#define CMSG_ERROR 2 -#define CMSG_FATAL 3 -#define CMSG_TRACE 4 -#define CMSG_TIME 5 -#define CMSG_TOTAL 6 -#define CMSG_FILE 7 -#define CMSG_TEXT 8 - -#define VERB_NORMAL 0 -#define VERB_VERBOSE 1 -#define VERB_NOISY 2 -#define VERB_DEBUG 3 -#define VERB_DEBUG_SILLY 4 - -typedef struct { - char *id_name, id_character; - int verbosity, trace_playing, opened; - - int (*open)(int using_stdin, int using_stdout); - void (*pass_playing_list)(int number_of_files, char *list_of_files[]); - void (*close)(void); - int (*read)(int32 *valp); - int (*cmsg)(int type, int verbosity_level, char *fmt, ...); - - void (*refresh)(void); - void (*reset)(void); - void (*file_name)(char *name); - void (*total_time)(int tt); - void (*current_time)(int ct); - - void (*note)(int v); - void (*master_volume)(int mv); - void (*program)(int channel, int val); /* val<0 means drum set -val */ - void (*volume)(int channel, int val); - void (*expression)(int channel, int val); - void (*panning)(int channel, int val); - void (*sustain)(int channel, int val); - void (*pitch_bend)(int channel, int val); - -} ControlMode; - -extern ControlMode *ctl_list[], *ctl; -extern char timidity_error[]; diff --git a/timidity/dls1.h b/timidity/dls1.h new file mode 100644 index 00000000..abc2075a --- /dev/null +++ b/timidity/dls1.h @@ -0,0 +1,266 @@ +/*==========================================================================; +// +// dls1.h +// +// +// Description: +// +// Interface defines and structures for the Instrument Collection Form +// RIFF DLS. +// +// +// Written by Sonic Foundry 1996. Released for public use. +// +//=========================================================================*/ + +#ifndef _INC_DLS1 +#define _INC_DLS1 + +/*////////////////////////////////////////////////////////////////////////// +// +// +// Layout of an instrument collection: +// +// +// RIFF [] 'DLS ' [dlid,colh,INSTLIST,WAVEPOOL,INFOLIST] +// +// INSTLIST +// LIST [] 'lins' +// LIST [] 'ins ' [dlid,insh,RGNLIST,ARTLIST,INFOLIST] +// LIST [] 'ins ' [dlid,insh,RGNLIST,ARTLIST,INFOLIST] +// LIST [] 'ins ' [dlid,insh,RGNLIST,ARTLIST,INFOLIST] +// +// RGNLIST +// LIST [] 'lrgn' +// LIST [] 'rgn ' [rgnh,wsmp,wlnk,ARTLIST] +// LIST [] 'rgn ' [rgnh,wsmp,wlnk,ARTLIST] +// LIST [] 'rgn ' [rgnh,wsmp,wlnk,ARTLIST] +// +// ARTLIST +// LIST [] 'lart' +// 'art1' level 1 Articulation connection graph +// 'art2' level 2 Articulation connection graph +// '3rd1' Possible 3rd party articulation structure 1 +// '3rd2' Possible 3rd party articulation structure 2 .... and so on +// +// WAVEPOOL +// ptbl [] [pool table] +// LIST [] 'wvpl' +// [path], +// [path], +// LIST [] 'wave' [dlid,RIFFWAVE] +// LIST [] 'wave' [dlid,RIFFWAVE] +// LIST [] 'wave' [dlid,RIFFWAVE] +// LIST [] 'wave' [dlid,RIFFWAVE] +// LIST [] 'wave' [dlid,RIFFWAVE] +// +// INFOLIST +// LIST [] 'INFO' +// 'icmt' 'One of those crazy comments.' +// 'icop' 'Copyright (C) 1996 Sonic Foundry' +// +/////////////////////////////////////////////////////////////////////////*/ + + +/*///////////////////////////////////////////////////////////////////////// +// FOURCC's used in the DLS file +/////////////////////////////////////////////////////////////////////////*/ + +#define FOURCC_DLS mmioFOURCC('D','L','S',' ') +#define FOURCC_DLID mmioFOURCC('d','l','i','d') +#define FOURCC_COLH mmioFOURCC('c','o','l','h') +#define FOURCC_WVPL mmioFOURCC('w','v','p','l') +#define FOURCC_PTBL mmioFOURCC('p','t','b','l') +#define FOURCC_PATH mmioFOURCC('p','a','t','h') +#define FOURCC_wave mmioFOURCC('w','a','v','e') +#define FOURCC_LINS mmioFOURCC('l','i','n','s') +#define FOURCC_INS mmioFOURCC('i','n','s',' ') +#define FOURCC_INSH mmioFOURCC('i','n','s','h') +#define FOURCC_LRGN mmioFOURCC('l','r','g','n') +#define FOURCC_RGN mmioFOURCC('r','g','n',' ') +#define FOURCC_RGNH mmioFOURCC('r','g','n','h') +#define FOURCC_LART mmioFOURCC('l','a','r','t') +#define FOURCC_ART1 mmioFOURCC('a','r','t','1') +#define FOURCC_WLNK mmioFOURCC('w','l','n','k') +#define FOURCC_WSMP mmioFOURCC('w','s','m','p') +#define FOURCC_VERS mmioFOURCC('v','e','r','s') + +/*///////////////////////////////////////////////////////////////////////// +// Articulation connection graph definitions +/////////////////////////////////////////////////////////////////////////*/ + +/* Generic Sources */ +#define CONN_SRC_NONE 0x0000 +#define CONN_SRC_LFO 0x0001 +#define CONN_SRC_KEYONVELOCITY 0x0002 +#define CONN_SRC_KEYNUMBER 0x0003 +#define CONN_SRC_EG1 0x0004 +#define CONN_SRC_EG2 0x0005 +#define CONN_SRC_PITCHWHEEL 0x0006 + +/* Midi Controllers 0-127 */ +#define CONN_SRC_CC1 0x0081 +#define CONN_SRC_CC7 0x0087 +#define CONN_SRC_CC10 0x008a +#define CONN_SRC_CC11 0x008b + +/* Generic Destinations */ +#define CONN_DST_NONE 0x0000 +#define CONN_DST_ATTENUATION 0x0001 +#define CONN_DST_PITCH 0x0003 +#define CONN_DST_PAN 0x0004 + +/* LFO Destinations */ +#define CONN_DST_LFO_FREQUENCY 0x0104 +#define CONN_DST_LFO_STARTDELAY 0x0105 + +/* EG1 Destinations */ +#define CONN_DST_EG1_ATTACKTIME 0x0206 +#define CONN_DST_EG1_DECAYTIME 0x0207 +#define CONN_DST_EG1_RELEASETIME 0x0209 +#define CONN_DST_EG1_SUSTAINLEVEL 0x020a + +/* EG2 Destinations */ +#define CONN_DST_EG2_ATTACKTIME 0x030a +#define CONN_DST_EG2_DECAYTIME 0x030b +#define CONN_DST_EG2_RELEASETIME 0x030d +#define CONN_DST_EG2_SUSTAINLEVEL 0x030e + +#define CONN_TRN_NONE 0x0000 +#define CONN_TRN_CONCAVE 0x0001 + +typedef struct _DLSID { + ULONG ulData1; + USHORT usData2; + USHORT usData3; + BYTE abData4[8]; +} DLSID, FAR *LPDLSID; + +typedef struct _DLSVERSION { + DWORD dwVersionMS; + DWORD dwVersionLS; +} DLSVERSION, FAR *LPDLSVERSION; + + +typedef struct _CONNECTION { + USHORT usSource; + USHORT usControl; + USHORT usDestination; + USHORT usTransform; + LONG lScale; +} CONNECTION, FAR *LPCONNECTION; + + +/* Level 1 Articulation Data */ + +typedef struct _CONNECTIONLIST { + ULONG cbSize; /* size of the connection list structure */ + ULONG cConnections; /* count of connections in the list */ +} CONNECTIONLIST, FAR *LPCONNECTIONLIST; + + + +/*///////////////////////////////////////////////////////////////////////// +// Generic type defines for regions and instruments +/////////////////////////////////////////////////////////////////////////*/ + +typedef struct _RGNRANGE { + USHORT usLow; + USHORT usHigh; +} RGNRANGE, FAR * LPRGNRANGE; + +#define F_INSTRUMENT_DRUMS 0x80000000 + +typedef struct _MIDILOCALE { + ULONG ulBank; + ULONG ulInstrument; +} MIDILOCALE, FAR *LPMIDILOCALE; + +/*///////////////////////////////////////////////////////////////////////// +// Header structures found in an DLS file for collection, instruments, and +// regions. +/////////////////////////////////////////////////////////////////////////*/ + +#define F_RGN_OPTION_SELFNONEXCLUSIVE 0x0001 + +typedef struct _RGNHEADER { + RGNRANGE RangeKey; /* Key range */ + RGNRANGE RangeVelocity; /* Velocity Range */ + USHORT fusOptions; /* Synthesis options for this range */ + USHORT usKeyGroup; /* Key grouping for non simultaneous play */ + /* 0 = no group, 1 up is group */ + /* for Level 1 only groups 1-15 are allowed */ +} RGNHEADER, FAR *LPRGNHEADER; + +typedef struct _INSTHEADER { + ULONG cRegions; /* Count of regions in this instrument */ + MIDILOCALE Locale; /* Intended MIDI locale of this instrument */ +} INSTHEADER, FAR *LPINSTHEADER; + +typedef struct _DLSHEADER { + ULONG cInstruments; /* Count of instruments in the collection */ +} DLSHEADER, FAR *LPDLSHEADER; + +/*//////////////////////////////////////////////////////////////////////////// +// definitions for the Wave link structure +////////////////////////////////////////////////////////////////////////////*/ + +/* **** For level 1 only WAVELINK_CHANNEL_MONO is valid **** */ +/* ulChannel allows for up to 32 channels of audio with each bit position */ +/* specifiying a channel of playback */ + +#define WAVELINK_CHANNEL_LEFT 0x0001l +#define WAVELINK_CHANNEL_RIGHT 0x0002l + +#define F_WAVELINK_PHASE_MASTER 0x0001 + +typedef struct _WAVELINK { /* any paths or links are stored right after struct */ + USHORT fusOptions; /* options flags for this wave */ + USHORT usPhaseGroup; /* Phase grouping for locking channels */ + ULONG ulChannel; /* channel placement */ + ULONG ulTableIndex; /* index into the wave pool table, 0 based */ +} WAVELINK, FAR *LPWAVELINK; + +#define POOL_CUE_NULL 0xffffffffl + +typedef struct _POOLCUE { + ULONG ulOffset; /* Offset to the entry in the list */ +} POOLCUE, FAR *LPPOOLCUE; + +typedef struct _POOLTABLE { + ULONG cbSize; /* size of the pool table structure */ + ULONG cCues; /* count of cues in the list */ +} POOLTABLE, FAR *LPPOOLTABLE; + +/*//////////////////////////////////////////////////////////////////////////// +// Structures for the "wsmp" chunk +////////////////////////////////////////////////////////////////////////////*/ + +#define F_WSMP_NO_TRUNCATION 0x0001l +#define F_WSMP_NO_COMPRESSION 0x0002l + + +typedef struct _rwsmp { + ULONG cbSize; + USHORT usUnityNote; /* MIDI Unity Playback Note */ + SHORT sFineTune; /* Fine Tune in log tuning */ + LONG lAttenuation; /* Overall Attenuation to be applied to data */ + ULONG fulOptions; /* Flag options */ + ULONG cSampleLoops; /* Count of Sample loops, 0 loops is one shot */ +} WSMPL, FAR *LPWSMPL; + + +/* This loop type is a normal forward playing loop which is continually */ +/* played until the envelope reaches an off threshold in the release */ +/* portion of the volume envelope */ + +#define WLOOP_TYPE_FORWARD 0 + +typedef struct _rloop { + ULONG cbSize; + ULONG ulType; /* Loop Type */ + ULONG ulStart; /* Start of loop in samples */ + ULONG ulLength; /* Length of loop in samples */ +} WLOOP, FAR *LPWLOOP; + +#endif /*_INC_DLS1 */ diff --git a/timidity/dls2.h b/timidity/dls2.h new file mode 100644 index 00000000..30cec23a --- /dev/null +++ b/timidity/dls2.h @@ -0,0 +1,130 @@ +/* + + dls2.h + + Description: + + Interface defines and structures for the DLS2 extensions of DLS. + + + Written by Microsoft 1998. Released for public use. + +*/ + +#ifndef _INC_DLS2 +#define _INC_DLS2 + +/* + FOURCC's used in the DLS2 file, in addition to DLS1 chunks +*/ + +#define FOURCC_RGN2 mmioFOURCC('r','g','n','2') +#define FOURCC_LAR2 mmioFOURCC('l','a','r','2') +#define FOURCC_ART2 mmioFOURCC('a','r','t','2') +#define FOURCC_CDL mmioFOURCC('c','d','l',' ') +#define FOURCC_DLID mmioFOURCC('d','l','i','d') + +/* + Articulation connection graph definitions. These are in addition to + the definitions in the DLS1 header. +*/ + +/* Generic Sources (in addition to DLS1 sources. */ +#define CONN_SRC_POLYPRESSURE 0x0007 /* Polyphonic Pressure */ +#define CONN_SRC_CHANNELPRESSURE 0x0008 /* Channel Pressure */ +#define CONN_SRC_VIBRATO 0x0009 /* Vibrato LFO */ +#define CONN_SRC_MONOPRESSURE 0x000a /* MIDI Mono pressure */ + + +/* Midi Controllers */ +#define CONN_SRC_CC91 0x00db /* Reverb Send */ +#define CONN_SRC_CC93 0x00dd /* Chorus Send */ + + +/* Generic Destinations */ +#define CONN_DST_GAIN 0x0001 /* Same as CONN_DST_ ATTENUATION, but more appropriate terminology. */ +#define CONN_DST_KEYNUMBER 0x0005 /* Key Number Generator */ + +/* Audio Channel Output Destinations */ +#define CONN_DST_LEFT 0x0010 /* Left Channel Send */ +#define CONN_DST_RIGHT 0x0011 /* Right Channel Send */ +#define CONN_DST_CENTER 0x0012 /* Center Channel Send */ +#define CONN_DST_LEFTREAR 0x0013 /* Left Rear Channel Send */ +#define CONN_DST_RIGHTREAR 0x0014 /* Right Rear Channel Send */ +#define CONN_DST_LFE_CHANNEL 0x0015 /* LFE Channel Send */ +#define CONN_DST_CHORUS 0x0080 /* Chorus Send */ +#define CONN_DST_REVERB 0x0081 /* Reverb Send */ + +/* Vibrato LFO Destinations */ +#define CONN_DST_VIB_FREQUENCY 0x0114 /* Vibrato Frequency */ +#define CONN_DST_VIB_STARTDELAY 0x0115 /* Vibrato Start Delay */ + +/* EG1 Destinations */ +#define CONN_DST_EG1_DELAYTIME 0x020B /* EG1 Delay Time */ +#define CONN_DST_EG1_HOLDTIME 0x020C /* EG1 Hold Time */ +#define CONN_DST_EG1_SHUTDOWNTIME 0x020D /* EG1 Shutdown Time */ + + +/* EG2 Destinations */ +#define CONN_DST_EG2_DELAYTIME 0x030F /* EG2 Delay Time */ +#define CONN_DST_EG2_HOLDTIME 0x0310 /* EG2 Hold Time */ + + +/* Filter Destinations */ +#define CONN_DST_FILTER_CUTOFF 0x0500 /* Filter Cutoff Frequency */ +#define CONN_DST_FILTER_Q 0x0501 /* Filter Resonance */ + + +/* Transforms */ +#define CONN_TRN_CONVEX 0x0002 /* Convex Transform */ +#define CONN_TRN_SWITCH 0x0003 /* Switch Transform */ + + +/* Conditional chunk operators */ + #define DLS_CDL_AND 0x0001 /* X = X & Y */ + #define DLS_CDL_OR 0x0002 /* X = X | Y */ + #define DLS_CDL_XOR 0x0003 /* X = X ^ Y */ + #define DLS_CDL_ADD 0x0004 /* X = X + Y */ + #define DLS_CDL_SUBTRACT 0x0005 /* X = X - Y */ + #define DLS_CDL_MULTIPLY 0x0006 /* X = X * Y */ + #define DLS_CDL_DIVIDE 0x0007 /* X = X / Y */ + #define DLS_CDL_LOGICAL_AND 0x0008 /* X = X && Y */ + #define DLS_CDL_LOGICAL_OR 0x0009 /* X = X || Y */ + #define DLS_CDL_LT 0x000A /* X = (X < Y) */ + #define DLS_CDL_LE 0x000B /* X = (X <= Y) */ + #define DLS_CDL_GT 0x000C /* X = (X > Y) */ + #define DLS_CDL_GE 0x000D /* X = (X >= Y) */ + #define DLS_CDL_EQ 0x000E /* X = (X == Y) */ + #define DLS_CDL_NOT 0x000F /* X = !X */ + #define DLS_CDL_CONST 0x0010 /* 32-bit constant */ + #define DLS_CDL_QUERY 0x0011 /* 32-bit value returned from query */ + #define DLS_CDL_QUERYSUPPORTED 0x0012 /* Test to see if query is supported by synth */ + +/* + Loop and release +*/ + +#define WLOOP_TYPE_RELEASE 1 + +/* + WaveLink chunk +*/ + +#define F_WAVELINK_MULTICHANNEL 0x0002 + + +/* + DLSID queries for +*/ + +DEFINE_GUID(DLSID_GMInHardware, 0x178f2f24, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); +DEFINE_GUID(DLSID_GSInHardware, 0x178f2f25, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); +DEFINE_GUID(DLSID_XGInHardware, 0x178f2f26, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); +DEFINE_GUID(DLSID_SupportsDLS1, 0x178f2f27, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); +DEFINE_GUID(DLSID_SupportsDLS2, 0xf14599e5, 0x4689, 0x11d2, 0xaf, 0xa6, 0x0, 0xaa, 0x0, 0x24, 0xd8, 0xb6); +DEFINE_GUID(DLSID_SampleMemorySize, 0x178f2f28, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); +DEFINE_GUID(DLSID_ManufacturersID, 0xb03e1181, 0x8095, 0x11d2, 0xa1, 0xef, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8); +DEFINE_GUID(DLSID_ProductID, 0xb03e1182, 0x8095, 0x11d2, 0xa1, 0xef, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8); +DEFINE_GUID(DLSID_SamplePlaybackRate, 0x2a91f713, 0xa4bf, 0x11d2, 0xbb, 0xdf, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8); + +#endif /* _INC_DLS2 */ diff --git a/timidity/filter.c b/timidity/filter.c deleted file mode 100644 index a96dbd0d..00000000 --- a/timidity/filter.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - TiMidity -- Experimental MIDI to WAVE converter - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the Perl Artistic License, available in COPYING. - - filter.c: written by Vincent Pagel ( pagel@loria.fr ) - - implements fir antialiasing filter : should help when setting sample - rates as low as 8Khz. - - April 95 - - first draft - - 22/5/95 - - modify "filter" so that it simulate leading and trailing 0 in the buffer - */ - -#include -#include -#include -#include -#include "config.h" -#include "common.h" -#include "ctrlmode.h" -#include "instrum.h" -#include "filter.h" - -/* bessel function */ -static float ino(float x) -{ - float y, de, e, sde; - int i; - - y = x / 2; - e = 1.0; - de = 1.0; - i = 1; - do { - de = de * y / (float) i; - sde = de * de; - e += sde; - } while (!( (e * 1.0e-08 - sde > 0) || (i++ > 25) )); - return(e); -} - -/* Kaiser Window (symetric) */ -static void kaiser(float *w,int n,float beta) -{ - float xind, xi; - int i; - - xind = (float)((2*n - 1) * (2*n - 1)); - for (i =0; i apply the filter given by coef[] to the data buffer - * Note that we simulate leading and trailing 0 at the border of the - * data buffer - */ -static void filter(sample_t *result,sample_t *data, int32 length,float coef[]) -{ - int32 sample,i,sample_window; - int16 peak = 0; - float sum; - - /* Simulate leading 0 at the begining of the buffer */ - for (sample = 0; sample < ORDER2 ; sample++ ) - { - sum = 0.0; - sample_window= sample - ORDER2; - - for (i = 0; i < ORDER ;i++) - sum += (float)(coef[i] * - ((sample_window<0)? 0.0 : data[sample_window++])) ; - - /* Saturation ??? */ - if (sum> 32767.) { sum=32767.; peak++; } - if (sum< -32768.) { sum=-32768; peak++; } - result[sample] = (sample_t) sum; - } - - /* The core of the buffer */ - for (sample = ORDER2; sample < length - ORDER + ORDER2 ; sample++ ) - { - sum = 0.0; - sample_window= sample - ORDER2; - - for (i = 0; i < ORDER ;i++) - sum += data[sample_window++] * coef[i]; - - /* Saturation ??? */ - if (sum> 32767.) { sum=32767.; peak++; } - if (sum< -32768.) { sum=-32768; peak++; } - result[sample] = (sample_t) sum; - } - - /* Simulate 0 at the end of the buffer */ - for (sample = length - ORDER + ORDER2; sample < length ; sample++ ) - { - sum = 0.0; - sample_window= sample - ORDER2; - - for (i = 0; i < ORDER ;i++) - sum += (float)(coef[i] * - ((sample_window>=length)? 0.0 : data[sample_window++])) ; - - /* Saturation ??? */ - if (sum> 32767.) { sum=32767.; peak++; } - if (sum< -32768.) { sum=-32768; peak++; } - result[sample] = (sample_t) sum; - } - - if (peak) - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "Saturation %2.3f %%.", 100.0*peak/ (float) length); -} - -/***********************************************************************/ -/* Prevent aliasing by filtering any freq above the output_rate */ -/* */ -/* I don't worry about looping point -> they will remain soft if they */ -/* were already */ -/***********************************************************************/ -void antialiasing(Sample *sp, int32 output_rate ) -{ - sample_t *temp; - int i; - float fir_symetric[ORDER]; - float fir_coef[ORDER2]; - float freq_cut; /* cutoff frequency [0..1.0] FREQ_CUT/SAMP_FREQ*/ - - - ctl->cmsg(CMSG_INFO, VERB_NOISY, "Antialiasing: Fsample=%iKHz", - sp->sample_rate); - - /* No oversampling */ - if (output_rate>=sp->sample_rate) - return; - - freq_cut= (float) output_rate / (float) sp->sample_rate; - ctl->cmsg(CMSG_INFO, VERB_NOISY, "Antialiasing: cutoff=%f%%", - freq_cut*100.); - - designfir(fir_coef,freq_cut); - - /* Make the filter symetric */ - for (i = 0 ; idata_length); - memcpy(temp,sp->data,sp->data_length); - - filter(sp->data,temp,sp->data_length/sizeof(sample_t),fir_symetric); - - free(temp); -} diff --git a/timidity/filter.h b/timidity/filter.h deleted file mode 100644 index 79133377..00000000 --- a/timidity/filter.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - TiMidity -- Experimental MIDI to WAVE converter - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the Perl Artistic License, available in COPYING. - - filter.h : written by Vincent Pagel ( pagel@loria.fr ) - - implements fir antialiasing filter : should help when setting sample - rates as low as 8Khz. - - */ - -/* Order of the FIR filter = 20 should be enough ! */ -#define ORDER 20 -#define ORDER2 ORDER/2 - -#ifndef PI -#define PI 3.14159265 -#endif - -extern void antialiasing(Sample *sp, int32 output_rate); diff --git a/timidity/instrum.c b/timidity/instrum.c index a549f084..16d5737e 100644 --- a/timidity/instrum.c +++ b/timidity/instrum.c @@ -1,166 +1,82 @@ /* + TiMidity -- Experimental MIDI to WAVE converter Copyright (C) 1995 Tuukka Toivonen This program is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License, available in COPYING. - */ + + instrum.c + + Code to load and unload GUS-compatible instrument patches. + +*/ + +#if HAVE_CONFIG_H +# include +#endif #include #include #include -#include "config.h" +#include "SDL.h" + +#include "timidity.h" +#include "options.h" #include "common.h" #include "instrum.h" -#include "playmidi.h" -#include "output.h" -#include "ctrlmode.h" +#include "instrum_dls.h" #include "resample.h" #include "tables.h" -#include "filter.h" - -/* Some functions get aggravated if not even the standard banks are - available. */ -static ToneBank standard_tonebank, standard_drumset; -ToneBank - *tonebank[MAXBANK]={&standard_tonebank}, - *drumset[MAXBANK]={&standard_drumset}; - -/* This is a special instrument, used for all melodic programs */ -InstrumentLayer *default_instrument=0; - -/* This is only used for tracks that don't specify a program */ -int default_program=DEFAULT_PROGRAM; - -int antialiasing_allowed=0; -#ifdef FAST_DECAY -int fast_decay=1; -#else -int fast_decay=0; -#endif - - -int current_tune_number = 0; -int last_tune_purged = 0; -int current_patch_memory = 0; -int max_patch_memory = 60000000; - -static void purge_as_required(void); static void free_instrument(Instrument *ip) { Sample *sp; int i; if (!ip) return; - - if (!ip->contents) for (i=0; isamples; i++) { sp=&(ip->sample[i]); - if (sp->data) free(sp->data); + free(sp->data); } free(ip->sample); - - if (!ip->contents) - for (i=0; iright_samples; i++) - { - sp=&(ip->right_sample[i]); - if (sp->data) free(sp->data); - } - if (ip->right_sample) - free(ip->right_sample); free(ip); } - -static void free_layer(InstrumentLayer *lp) -{ - InstrumentLayer *next; - - current_patch_memory -= lp->size; - - for (; lp; lp = next) - { - next = lp->next; - free_instrument(lp->instrument); - free(lp); - } -} - -static void free_bank(int dr, int b) +static void free_bank(MidiSong *song, int dr, int b) { int i; - ToneBank *bank=((dr) ? drumset[b] : tonebank[b]); - for (i=0; itone[i].layer) - { - /* Not that this could ever happen, of course */ - if (bank->tone[i].layer != MAGIC_LOAD_INSTRUMENT) - { - free_layer(bank->tone[i].layer); - bank->tone[i].layer=NULL; - bank->tone[i].last_used=-1; - } - } - if (bank->tone[i].name) - { - free(bank->tone[i].name); - bank->tone[i].name = NULL; - } - } -} - - -static void free_old_bank(int dr, int b, int how_old) -{ - int i; - ToneBank *bank=((dr) ? drumset[b] : tonebank[b]); - for (i=0; itone[i].layer && bank->tone[i].last_used < how_old) + ToneBank *bank=((dr) ? song->drumset[b] : song->tonebank[b]); + for (i=0; iinstrument[i]) { - if (bank->tone[i].layer != MAGIC_LOAD_INSTRUMENT) - { - ctl->cmsg(CMSG_INFO, VERB_DEBUG, - "Unloading %s %s[%d,%d] - last used %d.", - (dr)? "drum" : "inst", bank->tone[i].name, - i, b, bank->tone[i].last_used); - free_layer(bank->tone[i].layer); - bank->tone[i].layer=NULL; - bank->tone[i].last_used=-1; - } + /* Not that this could ever happen, of course */ + if (bank->instrument[i] != MAGIC_LOAD_INSTRUMENT) + free_instrument(bank->instrument[i]); + bank->instrument[i]=0; } } - -int32 convert_envelope_rate_attack(uint8 rate, uint8 fastness) +static Sint32 convert_envelope_rate(MidiSong *song, Uint8 rate) { - int32 r; - - r=3-((rate>>6) & 0x3); - r*=3; - r = (int32)(rate & 0x3f) << r; /* 6.9 fixed point */ + Sint32 r; + + r = 3 - ((rate >> 6) & 0x3); + r *= 3; + r = (Sint32) (rate & 0x3f) << r; /* 6.9 fixed point */ /* 15.15 fixed point. */ - return (((r * 44100) / play_mode->rate) * control_ratio) - << 10; -} + r = ((r * 44100) / song->rate) * song->control_ratio; -int32 convert_envelope_rate(uint8 rate) -{ - int32 r; - - r=3-((rate>>6) & 0x3); - r*=3; - r = (int32)(rate & 0x3f) << r; /* 6.9 fixed point */ - - /* 15.15 fixed point. */ - return (((r * 44100) / play_mode->rate) * control_ratio) - << ((fast_decay) ? 10 : 9); +#ifdef FAST_DECAY + return r << 10; +#else + return r << 9; +#endif } -int32 convert_envelope_offset(uint8 offset) +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? */ @@ -169,49 +85,50 @@ int32 convert_envelope_offset(uint8 offset) return offset << (7+15); } -int32 convert_tremolo_sweep(uint8 sweep) +static Sint32 convert_tremolo_sweep(MidiSong *song, Uint8 sweep) { if (!sweep) return 0; return - ((control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) / - (play_mode->rate * sweep); + ((song->control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) / + (song->rate * sweep); } -int32 convert_vibrato_sweep(uint8 sweep, int32 vib_control_ratio) +static Sint32 convert_vibrato_sweep(MidiSong *song, Uint8 sweep, + Sint32 vib_control_ratio) { if (!sweep) return 0; return - (int32) (FSCALE((double) (vib_control_ratio) * SWEEP_TUNING, SWEEP_SHIFT) - / (double)(play_mode->rate * sweep)); + (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) / - (play_mode->rate * sweep); */ + (song->rate * sweep); */ } -int32 convert_tremolo_rate(uint8 rate) +static Sint32 convert_tremolo_rate(MidiSong *song, Uint8 rate) { return - ((SINE_CYCLE_LENGTH * control_ratio * rate) << RATE_SHIFT) / - (TREMOLO_RATE_TUNING * play_mode->rate); + ((SINE_CYCLE_LENGTH * song->control_ratio * rate) << RATE_SHIFT) / + (TREMOLO_RATE_TUNING * song->rate); } -int32 convert_vibrato_rate(uint8 rate) +static Sint32 convert_vibrato_rate(MidiSong *song, Uint8 rate) { /* Return a suitable vibrato_control_ratio value */ return - (VIBRATO_RATE_TUNING * play_mode->rate) / + (VIBRATO_RATE_TUNING * song->rate) / (rate * 2 * VIBRATO_SAMPLE_INCREMENTS); } -static void reverse_data(int16 *sp, int32 ls, int32 le) +static void reverse_data(Sint16 *sp, Sint32 ls, Sint32 le) { - int16 s, *ep=sp+le; + Sint16 s, *ep=sp+le; sp+=ls; le-=ls; le/=2; @@ -233,255 +150,109 @@ static void reverse_data(int16 *sp, int32 ls, int32 le) undefined. TODO: do reverse loops right */ -static InstrumentLayer *load_instrument(const char *name, int font_type, int percussion, - int panning, int amp, int cfg_tuning, int note_to_use, +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, int bank, int gm_num, int sf_ix) + int strip_tail) { - InstrumentLayer *lp, *lastlp, *headlp = 0; Instrument *ip; - FILE *fp; - uint8 tmp[1024]; + Sample *sp; + SDL_RWops *rw; + char tmp[1024]; int i,j,noluck=0; -#ifdef PATCH_EXT_LIST static char *patch_ext[] = PATCH_EXT_LIST; -#endif - int sf2flag = 0; - int right_samples = 0; - int stereo_channels = 1, stereo_layer; - int vlayer_list[19][4], vlayer, vlayer_count = 0; if (!name) return 0; /* Open patch file */ - if ((fp=open_file(name, 1, OF_NORMAL)) == NULL) + if ((rw=open_file(name)) == NULL) { noluck=1; -#ifdef PATCH_EXT_LIST /* Try with various extensions */ for (i=0; patch_ext[i]; i++) { - if (strlen(name)+strlen(patch_ext[i])cmsg(CMSG_ERROR, VERB_NORMAL, - "Instrument `%s' can't be found.", name); + SNDDBG(("Instrument `%s' can't be found.\n", name)); return 0; } - /*ctl->cmsg(CMSG_INFO, VERB_NOISY, "Loading instrument %s", current_filename);*/ + 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 != fread(tmp, 1, 239, fp)) || + 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 */ { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: not an instrument", name); + SNDDBG(("%s: not an instrument\n", name)); return 0; } - -/* patch layout: - * bytes: info: starts at offset: - * 22 id (see above) 0 - * 60 copyright 22 - * 1 instruments 82 - * 1 voices 83 - * 1 channels 84 - * 2 number of waveforms 85 - * 2 master volume 87 - * 4 datasize 89 - * 36 reserved, but now: 93 - * 7 "SF2EXT\0" id 93 - * 1 right samples 100 - * 28 reserved 101 - * 2 instrument number 129 - * 16 instrument name 131 - * 4 instrument size 147 - * 1 number of layers 151 - * 40 reserved 152 - * 1 layer duplicate 192 - * 1 layer number 193 - * 4 layer size 194 - * 1 number of samples 198 - * 40 reserved 199 - * 239 - * THEN, for each sample, see below - */ - - if (!memcmp(tmp + 93, "SF2EXT", 6)) - { - sf2flag = 1; - vlayer_count = tmp[152]; - } - + if (tmp[82] != 1 && tmp[82] != 0) /* instruments. To some patch makers, 0 means 1 */ { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "Can't handle patches with %d instruments", tmp[82]); + 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? */ { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "Can't handle instruments with %d layers", tmp[151]); + SNDDBG(("Can't handle instruments with %d layers\n", tmp[151])); return 0; } - - if (sf2flag && vlayer_count > 0) { - for (i = 0; i < 9; i++) - for (j = 0; j < 4; j++) - vlayer_list[i][j] = tmp[153+i*4+j]; - for (i = 9; i < 19; i++) - for (j = 0; j < 4; j++) - vlayer_list[i][j] = tmp[199+(i-9)*4+j]; - } - else { - for (i = 0; i < 19; i++) - for (j = 0; j < 4; j++) - vlayer_list[i][j] = 0; - vlayer_list[0][0] = 0; - vlayer_list[0][1] = 127; - vlayer_list[0][2] = tmp[198]; - vlayer_list[0][3] = 0; - vlayer_count = 1; - } - - lastlp = 0; - - for (vlayer = 0; vlayer < vlayer_count; vlayer++) { - - lp=(InstrumentLayer *)safe_malloc(sizeof(InstrumentLayer)); - lp->size = sizeof(InstrumentLayer); - lp->lo = vlayer_list[vlayer][0]; - lp->hi = vlayer_list[vlayer][1]; - ip=(Instrument *)safe_malloc(sizeof(Instrument)); - lp->size += sizeof(Instrument); - lp->instrument = ip; - lp->next = 0; - - if (lastlp) lastlp->next = lp; - else headlp = lp; - - lastlp = lp; - - if (sf2flag) ip->type = INST_SF2; - else ip->type = INST_GUS; - ip->samples = vlayer_list[vlayer][2]; - ip->sample = (Sample *)safe_malloc(sizeof(Sample) * ip->samples); - lp->size += sizeof(Sample) * ip->samples; - ip->left_samples = ip->samples; - ip->left_sample = ip->sample; - right_samples = vlayer_list[vlayer][3]; - ip->right_samples = right_samples; - if (right_samples) + ip=safe_malloc(sizeof(Instrument)); + ip->samples = tmp[198]; + ip->sample = safe_malloc(sizeof(Sample) * ip->samples); + for (i=0; isamples; i++) { - ip->right_sample = (Sample *)safe_malloc(sizeof(Sample) * right_samples); - lp->size += sizeof(Sample) * right_samples; - stereo_channels = 2; - } - else ip->right_sample = 0; - ip->contents = 0; - - ctl->cmsg(CMSG_INFO, VERB_NOISY, "%s%s[%d,%d] %s(%d-%d layer %d of %d)", - (percussion)? " ":"", name, - (percussion)? note_to_use : gm_num, bank, - (right_samples)? "(2) " : "", - lp->lo, lp->hi, vlayer+1, vlayer_count); - for (stereo_layer = 0; stereo_layer < stereo_channels; stereo_layer++) - { - int sample_count = 0; - - if (stereo_layer == 0) sample_count = ip->left_samples; - else if (stereo_layer == 1) sample_count = ip->right_samples; - - for (i=0; i < sample_count; i++) - { - uint8 fractions; - int32 tmplong; - uint16 tmpshort; - uint16 sample_volume = 0; - uint8 tmpchar; - Sample *sp = 0; - uint8 sf2delay = 0; + Uint8 fractions; + Sint32 tmplong; + Uint16 tmpshort; + Uint8 tmpchar; #define READ_CHAR(thing) \ - if ((size_t)1 != fread(&tmpchar, 1, 1, fp)) goto fail; \ + if (1 != SDL_RWread(rw, &tmpchar, 1, 1)) goto fail; \ thing = tmpchar; #define READ_SHORT(thing) \ - if ((size_t)1 != fread(&tmpshort, 2, 1, fp)) goto fail; \ - thing = LE_SHORT(tmpshort); + if (1 != SDL_RWread(rw, &tmpshort, 2, 1)) goto fail; \ + thing = SDL_SwapLE16(tmpshort); #define READ_LONG(thing) \ - if ((size_t)1 != fread(&tmplong, 4, 1, fp)) goto fail; \ - thing = LE_LONG(tmplong); + if (1 != SDL_RWread(rw, &tmplong, 4, 1)) goto fail; \ + thing = SDL_SwapLE32(tmplong); -/* - * 7 sample name - * 1 fractions - * 4 length - * 4 loop start - * 4 loop end - * 2 sample rate - * 4 low frequency - * 4 high frequency - * 2 finetune - * 1 panning - * 6 envelope rates | - * 6 envelope offsets | 18 bytes - * 3 tremolo sweep, rate, depth | - * 3 vibrato sweep, rate, depth | - * 1 sample mode - * 2 scale frequency - * 2 scale factor - * 2 sample volume (??) - * 34 reserved - * Now: 1 delay - * 33 reserved - */ - skip(fp, 7); /* Skip the wave name */ - - if (1 != fread(&fractions, 1, 1, fp)) + SDL_RWseek(rw, 7, RW_SEEK_CUR); /* Skip the wave name */ + + if (1 != SDL_RWread(rw, &fractions, 1, 1)) { fail: - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Error reading sample %d", i); - if (stereo_layer == 1) - { - for (j=0; jright_sample[j].data); - free(ip->right_sample); - i = ip->left_samples; - } + SNDDBG(("Error reading sample %d\n", i)); for (j=0; jleft_sample[j].data); - free(ip->left_sample); + free(ip->sample[j].data); + free(ip->sample); free(ip); - free(lp); return 0; } - if (stereo_layer == 0) sp=&(ip->left_sample[i]); - else if (stereo_layer == 1) sp=&(ip->right_sample[i]); - + sp=&(ip->sample[i]); + READ_LONG(sp->data_length); READ_LONG(sp->loop_start); READ_LONG(sp->loop_end); @@ -489,91 +260,64 @@ static InstrumentLayer *load_instrument(const char *name, int font_type, int per READ_LONG(sp->low_freq); READ_LONG(sp->high_freq); READ_LONG(sp->root_freq); - skip(fp, 2); /* Why have a "root frequency" and then "tuning"?? */ + sp->low_vel = 0; + sp->high_vel = 127; + SDL_RWseek(rw, 2, RW_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); - - sp->resonance=0; - sp->cutoff_freq=0; - sp->reverberation=0; - sp->chorusdepth=0; - sp->exclusiveClass=0; - sp->keyToModEnvHold=0; - sp->keyToModEnvDecay=0; - sp->keyToVolEnvHold=0; - sp->keyToVolEnvDecay=0; - - if (cfg_tuning) - { - double tune_factor = (double)(cfg_tuning)/1200.0; - tune_factor = pow(2.0, tune_factor); - sp->root_freq = (uint32)( tune_factor * (double)sp->root_freq ); - } + sp->panning=(Uint8)(panning & 0x7F); /* envelope, tremolo, and vibrato */ - if (18 != fread(tmp, 1, 18, fp)) goto fail; + 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; - ctl->cmsg(CMSG_INFO, VERB_DEBUG, " * no tremolo"); + SNDDBG((" * no tremolo\n")); } else { - sp->tremolo_sweep_increment=convert_tremolo_sweep(tmp[12]); - sp->tremolo_phase_increment=convert_tremolo_rate(tmp[13]); + 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]; - ctl->cmsg(CMSG_INFO, VERB_DEBUG, - " * tremolo: sweep %d, phase %d, depth %d", + SNDDBG((" * tremolo: sweep %d, phase %d, depth %d\n", sp->tremolo_sweep_increment, sp->tremolo_phase_increment, - sp->tremolo_depth); + sp->tremolo_depth)); } if (!tmp[16] || !tmp[17]) { sp->vibrato_sweep_increment= sp->vibrato_control_ratio=sp->vibrato_depth=0; - ctl->cmsg(CMSG_INFO, VERB_DEBUG, " * no vibrato"); + SNDDBG((" * no vibrato\n")); } else { - sp->vibrato_control_ratio=convert_vibrato_rate(tmp[16]); + sp->vibrato_control_ratio=convert_vibrato_rate(song, tmp[16]); sp->vibrato_sweep_increment= - convert_vibrato_sweep(tmp[15], sp->vibrato_control_ratio); + convert_vibrato_sweep(song, tmp[15], sp->vibrato_control_ratio); sp->vibrato_depth=tmp[17]; - ctl->cmsg(CMSG_INFO, VERB_DEBUG, - " * vibrato: sweep %d, ctl %d, depth %d", + SNDDBG((" * vibrato: sweep %d, ctl %d, depth %d\n", sp->vibrato_sweep_increment, sp->vibrato_control_ratio, - sp->vibrato_depth); + sp->vibrato_depth)); } READ_CHAR(sp->modes); - READ_SHORT(tmpshort); - sp->freq_center = (uint8)tmpshort; - READ_SHORT(sp->freq_scale); - - if (sf2flag) - { - READ_SHORT(sample_volume); - READ_CHAR(sf2delay); - READ_CHAR(sp->exclusiveClass); - skip(fp, 32); - } - else - { - skip(fp, 36); - } + + SDL_RWseek(rw, 40, RW_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); + sp->note_to_use=(Uint8)(note_to_use); else sp->note_to_use=0; @@ -590,7 +334,7 @@ static InstrumentLayer *load_instrument(const char *name, int font_type, int per (sp->modes & (MODES_SUSTAIN | MODES_LOOPING | MODES_PINGPONG | MODES_REVERSE))) { - ctl->cmsg(CMSG_INFO, VERB_DEBUG, " - Removing loop and/or sustain"); + SNDDBG((" - Removing loop and/or sustain\n")); sp->modes &=~(MODES_SUSTAIN | MODES_LOOPING | MODES_PINGPONG | MODES_REVERSE); } @@ -598,7 +342,7 @@ static InstrumentLayer *load_instrument(const char *name, int font_type, int per if (strip_envelope==1) { if (sp->modes & MODES_ENVELOPE) - ctl->cmsg(CMSG_INFO, VERB_DEBUG, " - Removing envelope"); + SNDDBG((" - Removing envelope\n")); sp->modes &= ~MODES_ENVELOPE; } else if (strip_envelope != 0) @@ -609,16 +353,14 @@ static InstrumentLayer *load_instrument(const char *name, int font_type, int per /* No loop? Then what's there to sustain? No envelope needed either... */ sp->modes &= ~(MODES_SUSTAIN|MODES_ENVELOPE); - ctl->cmsg(CMSG_INFO, VERB_DEBUG, - " - No loop, removing sustain and 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; - ctl->cmsg(CMSG_INFO, VERB_DEBUG, - " - Weirdness, removing envelope"); + SNDDBG((" - Weirdness, removing envelope\n")); } else if (!(sp->modes & MODES_SUSTAIN)) { @@ -627,65 +369,33 @@ static InstrumentLayer *load_instrument(const char *name, int font_type, int per envelope either... at least the Gravis ones. They're mostly drums. I think. */ sp->modes &= ~MODES_ENVELOPE; - ctl->cmsg(CMSG_INFO, VERB_DEBUG, - " - No sustain, removing envelope"); + SNDDBG((" - No sustain, removing envelope\n")); } } - sp->attenuation = 0; - - for (j=ATTACK; jenvelope_rate[j]= - (j<3)? convert_envelope_rate_attack(tmp[j], 11) : convert_envelope_rate(tmp[j]); + convert_envelope_rate(song, tmp[j]); sp->envelope_offset[j]= convert_envelope_offset(tmp[6+j]); } - if (sf2flag) - { - if (sf2delay > 5) sf2delay = 5; - sp->envelope_rate[DELAY] = (int32)( (sf2delay*play_mode->rate) / 1000 ); - } - else - { - sp->envelope_rate[DELAY]=0; - } - sp->envelope_offset[DELAY]=0; - - for (j=ATTACK; jmodulation_rate[j]=sp->envelope_rate[j]; - sp->modulation_offset[j]=sp->envelope_offset[j]; - } - sp->modulation_rate[DELAY] = sp->modulation_offset[DELAY] = 0; - sp->modEnvToFilterFc=0; - sp->modEnvToPitch=0; - sp->lfo_sweep_increment = 0; - sp->lfo_phase_increment = 0; - sp->modLfoToFilterFc = 0; - sp->vibrato_delay = 0; /* Then read the sample data */ - if (sp->data_length/2 > MAX_SAMPLE_SIZE) - { - goto fail; - } - sp->data = (sample_t *)safe_malloc(sp->data_length + 1); - lp->size += sp->data_length + 1; - - if (1 != fread(sp->data, sp->data_length, 1, fp)) + 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 */ { - int32 i=sp->data_length; - uint8 *cp=(uint8 *)(sp->data); - uint16 *tmp,*newdta; - tmp=newdta=(uint16 *)safe_malloc(sp->data_length*2 + 2); + 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 *)newdta; + *tmp++ = (Uint16)(*cp++) << 8; + cp=(Uint8 *)(sp->data); + sp->data = (sample_t *)new; free(cp); sp->data_length *= 2; sp->loop_start *= 2; @@ -695,11 +405,11 @@ static InstrumentLayer *load_instrument(const char *name, int font_type, int per else /* convert to machine byte order */ { - int32 i=sp->data_length/2; - int16 *tmp=(int16 *)sp->data,s; + Sint32 i=sp->data_length/2; + Sint16 *tmp=(Sint16 *)sp->data,s; while (i--) { - s=LE_SHORT(*tmp); + s=SDL_SwapLE16(*tmp); *tmp++=s; } } @@ -707,8 +417,8 @@ static InstrumentLayer *load_instrument(const char *name, int font_type, int per if (sp->modes & MODES_UNSIGNED) /* convert to signed data */ { - int32 i=sp->data_length/2; - int16 *tmp=(int16 *)sp->data; + Sint32 i=sp->data_length/2; + Sint16 *tmp=(Sint16 *)sp->data; while (i--) *tmp++ ^= 0x8000; } @@ -716,12 +426,12 @@ static InstrumentLayer *load_instrument(const char *name, int font_type, int per /* Reverse reverse loops and pass them off as normal loops */ if (sp->modes & MODES_REVERSE) { - int32 t; + Sint32 t; /* The GUS apparently plays reverse loops by reversing the whole sample. We do the same because the GUS does not SUCK. */ - ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "Reverse loop in %s", name); - reverse_data((int16 *)sp->data, 0, sp->data_length/2); + 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; @@ -731,26 +441,17 @@ static InstrumentLayer *load_instrument(const char *name, int font_type, int per sp->modes |= MODES_LOOPING; /* just in case */ } - /* If necessary do some anti-aliasing filtering */ - - if (antialiasing_allowed) - antialiasing(sp,play_mode->rate); - #ifdef ADJUST_SAMPLE_VOLUMES if (amp!=-1) - sp->volume=(FLOAT_T)((amp) / 100.0); - else if (sf2flag) - sp->volume=(FLOAT_T)((sample_volume) / 255.0); + 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. */ - uint32 i, numsamps=sp->data_length/2; - uint32 higher=0, highcount=0; - int16 maxamp=0,a; - int16 *tmp=(int16 *)sp->data; - i = numsamps; + Sint32 i=sp->data_length/2; + Sint16 maxamp=0,a; + Sint16 *tmp=(Sint16 *)sp->data; while (i--) { a=*tmp++; @@ -758,22 +459,8 @@ static InstrumentLayer *load_instrument(const char *name, int font_type, int per if (a>maxamp) maxamp=a; } - tmp=(int16 *)sp->data; - i = numsamps; - while (i--) - { - a=*tmp++; - if (a<0) a=-a; - if (a > 3*maxamp/4) - { - higher += a; - highcount++; - } - } - if (highcount) higher /= highcount; - else higher = 10000; - sp->volume = (32768.0 * 0.875) / (double)higher ; - ctl->cmsg(CMSG_INFO, VERB_DEBUG, " * volume comp: %f", sp->volume); + sp->volume=(float)(32768.0 / maxamp); + SNDDBG((" * volume comp: %f\n", sp->volume)); } #else if (amp!=-1) @@ -783,28 +470,14 @@ static InstrumentLayer *load_instrument(const char *name, int font_type, int per #endif sp->data_length /= 2; /* These are in bytes. Convert into samples. */ - sp->loop_start /= 2; sp->loop_end /= 2; - sp->data[sp->data_length] = sp->data[sp->data_length-1]; /* Then fractional samples */ sp->data_length <<= FRACTION_BITS; sp->loop_start <<= FRACTION_BITS; sp->loop_end <<= FRACTION_BITS; - /* trim off zero data at end */ - { - int ls = sp->loop_start>>FRACTION_BITS; - int le = sp->loop_end>>FRACTION_BITS; - int se = sp->data_length>>FRACTION_BITS; - while (se > 1 && !sp->data[se-1]) se--; - if (le > se) le = se; - if (ls >= le) sp->modes &= ~MODES_LOOPING; - sp->loop_end = le<data_length = se<loop_start |= @@ -815,196 +488,122 @@ static InstrumentLayer *load_instrument(const char *name, int font_type, int per /* 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(sp); + pre_resample(song, sp); -#ifdef LOOKUP_HACK - /* Squash the 16-bit data into 8 bits. */ - { - uint8 *gulp,*ulp; - int16 *swp; - int l=sp->data_length >> FRACTION_BITS; - gulp=ulp=safe_malloc(l+1); - swp=(int16 *)sp->data; - while(l--) - *ulp++ = (*swp++ >> 8) & 0xFF; - free(sp->data); - sp->data=(sample_t *)gulp; - } -#endif - if (strip_tail==1) { /* Let's not really, just say we did. */ - ctl->cmsg(CMSG_INFO, VERB_DEBUG, " - Stripping tail"); + SNDDBG((" - Stripping tail\n")); sp->data_length = sp->loop_end; } - } /* end of sample loop */ - } /* end of stereo layer loop */ - } /* end of vlayer loop */ - + } - close_file(fp); - return headlp; + SDL_RWclose(rw); + return ip; } -static int fill_bank(int dr, int b) +static int fill_bank(MidiSong *song, int dr, int b) { int i, errors=0; - ToneBank *bank=((dr) ? drumset[b] : tonebank[b]); + ToneBank *bank=((dr) ? song->drumset[b] : song->tonebank[b]); if (!bank) { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "Huh. Tried to load instruments in non-existent %s %d", - (dr) ? "drumset" : "tone bank", b); + SNDDBG(("Huh. Tried to load instruments in non-existent %s %d\n", + (dr) ? "drumset" : "tone bank", b)); return 0; } - for (i=0; itone[i].layer==MAGIC_LOAD_INSTRUMENT) + 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)) { - ctl->cmsg(CMSG_WARNING, (b!=0) ? VERB_VERBOSE : VERB_NORMAL, - "No instrument mapped to %s %d, program %d%s", + 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"); + (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 (!(standard_tonebank.tone[i].layer)) - standard_tonebank.tone[i].layer= + if (!(song->tonebank[0]->instrument[i])) + song->tonebank[0]->instrument[i] = MAGIC_LOAD_INSTRUMENT; } else { - if (!(standard_drumset.tone[i].layer)) - standard_drumset.tone[i].layer= + if (!(song->drumset[0]->instrument[i])) + song->drumset[0]->instrument[i] = MAGIC_LOAD_INSTRUMENT; } } - bank->tone[i].layer=0; + bank->instrument[i] = 0; errors++; } - else if (!(bank->tone[i].layer= - load_instrument(bank->tone[i].name, - bank->tone[i].font_type, + 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].tuning, (bank->tone[i].note!=-1) ? - bank->tone[i].note : - ((dr) ? i : -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, - b, - ((dr) ? i + 128 : i), - bank->tone[i].sf_ix - ))) + bank->tone[i].strip_tail ))) { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "Couldn't load instrument %s (%s %d, program %d)", + SNDDBG(("Couldn't load instrument %s (%s %d, program %d)\n", bank->tone[i].name, - (dr)? "drum set" : "tone bank", b, i); + (dr)? "drum set" : "tone bank", b, i)); errors++; } - else - { /* it's loaded now */ - bank->tone[i].last_used = current_tune_number; - current_patch_memory += bank->tone[i].layer->size; - purge_as_required(); - if (current_patch_memory > max_patch_memory) { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "Not enough memory to load instrument %s (%s %d, program %d)", - bank->tone[i].name, - (dr)? "drum set" : "tone bank", b, i); - errors++; - free_layer(bank->tone[i].layer); - bank->tone[i].layer=0; - bank->tone[i].last_used=-1; - } -#if 0 - if (check_for_rc()) { - free_layer(bank->tone[i].layer); - bank->tone[i].layer=0; - bank->tone[i].last_used=-1; - return 0; - } -#endif - } } } return errors; } -static void free_old_instruments(int how_old) -{ - int i=MAXBANK; - while(i--) - { - if (tonebank[i]) - free_old_bank(0, i, how_old); - if (drumset[i]) - free_old_bank(1, i, how_old); - } -} - -static void purge_as_required(void) -{ - if (!max_patch_memory) return; - - while (last_tune_purged < current_tune_number - && current_patch_memory > max_patch_memory) - { - last_tune_purged++; - free_old_instruments(last_tune_purged); - } -} - - -int load_missing_instruments(void) +int load_missing_instruments(MidiSong *song) { int i=MAXBANK,errors=0; while (i--) { - if (tonebank[i]) - errors+=fill_bank(0,i); - if (drumset[i]) - errors+=fill_bank(1,i); + if (song->tonebank[i]) + errors+=fill_bank(song,0,i); + if (song->drumset[i]) + errors+=fill_bank(song,1,i); } - current_tune_number++; return errors; } -void free_instruments(void) +void free_instruments(MidiSong *song) { - int i=128; + int i=MAXBANK; while(i--) { - if (tonebank[i]) - free_bank(0,i); - if (drumset[i]) - free_bank(1,i); + if (song->tonebank[i]) + free_bank(song, 0, i); + if (song->drumset[i]) + free_bank(song, 1, i); } } -int set_default_instrument(const char *name) +int set_default_instrument(MidiSong *song, char *name) { - InstrumentLayer *lp; -/* if (!(lp=load_instrument(name, 0, -1, -1, -1, 0, 0, 0))) */ - if (!(lp=load_instrument(name, FONT_NORMAL, 0, -1, -1, 0, -1, -1, -1, -1, 0, -1, -1))) + Instrument *ip; + if (!(ip=load_instrument(song, name, 0, -1, -1, -1, 0, 0, 0))) return -1; - if (default_instrument) - free_layer(default_instrument); - default_instrument=lp; - default_program=SPECIAL_PROGRAM; + song->default_instrument = ip; + song->default_program = SPECIAL_PROGRAM; return 0; } diff --git a/timidity/instrum.h b/timidity/instrum.h index 7ba0a99b..3371fcee 100644 --- a/timidity/instrum.h +++ b/timidity/instrum.h @@ -1,44 +1,14 @@ /* + TiMidity -- Experimental MIDI to WAVE converter Copyright (C) 1995 Tuukka Toivonen This program is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License, available in COPYING. - */ + instrum.h -typedef struct { - int32 - loop_start, loop_end, data_length, - sample_rate, low_freq, high_freq, root_freq; - uint8 - root_tune, fine_tune; - int32 - envelope_rate[7], envelope_offset[7], - modulation_rate[7], modulation_offset[7]; - FLOAT_T - volume, resonance, - modEnvToFilterFc, modEnvToPitch, modLfoToFilterFc; - sample_t *data; - int32 - tremolo_sweep_increment, tremolo_phase_increment, - lfo_sweep_increment, lfo_phase_increment, - vibrato_sweep_increment, vibrato_control_ratio, - cutoff_freq; - uint8 - reverberation, chorusdepth, - tremolo_depth, vibrato_depth, - modes; - uint8 - attenuation, freq_center; - int8 - panning, note_to_use, exclusiveClass; - int16 - scale_tuning, keyToModEnvHold, keyToModEnvDecay, - keyToVolEnvHold, keyToVolEnvDecay; - int32 - freq_scale, vibrato_delay; -} Sample; + */ /* Bits in modes: */ #define MODES_16BIT (1<<0) @@ -48,121 +18,13 @@ typedef struct { #define MODES_REVERSE (1<<4) #define MODES_SUSTAIN (1<<5) #define MODES_ENVELOPE (1<<6) -#define MODES_FAST_RELEASE (1<<7) - -#if 0 -typedef struct { - int samples; - Sample *sample; -} Instrument; -#endif - -#define INST_GUS 0 -#define INST_SF2 1 - -typedef struct { - int type; - int samples; - Sample *sample; - int left_samples; - Sample *left_sample; - int right_samples; - Sample *right_sample; - unsigned char *contents; -} Instrument; - - -typedef struct _InstrumentLayer { - uint8 lo, hi; - int size; - Instrument *instrument; - struct _InstrumentLayer *next; -} InstrumentLayer; -struct cfg_type { - int font_code; - int num; - const char *name; -}; - -#define FONT_NORMAL 0 -#define FONT_FFF 1 -#define FONT_SBK 2 -#define FONT_TONESET 3 -#define FONT_DRUMSET 4 -#define FONT_PRESET 5 - - -typedef struct { - char *name; - InstrumentLayer *layer; - int font_type, sf_ix, last_used, tuning; - int note, amp, pan, strip_loop, strip_envelope, strip_tail; -} ToneBankElement; - -#if 0 -typedef struct { - char *name; - Instrument *instrument; - int note, amp, pan, strip_loop, strip_envelope, strip_tail; -} ToneBankElement; -#endif /* A hack to delay instrument loading until after reading the entire MIDI file. */ -#define MAGIC_LOAD_INSTRUMENT ((InstrumentLayer *)(-1)) - -#define MAXPROG 128 -#define MAXBANK 130 -#define SFXBANK (MAXBANK-1) -#define SFXDRUM1 (MAXBANK-2) -#define SFXDRUM2 (MAXBANK-1) -#define XGDRUM 1 - -#if 0 -typedef struct { - ToneBankElement tone[128]; -} ToneBank; -#endif - -typedef struct { - char *name; - ToneBankElement tone[MAXPROG]; -} ToneBank; - - -extern char *sf_file; - -extern ToneBank *tonebank[], *drumset[]; - -#if 0 -extern Instrument *default_instrument; -#endif -extern InstrumentLayer *default_instrument; -extern int default_program; -extern int antialiasing_allowed; -extern int fast_decay; -extern int free_instruments_afterwards; +#define MAGIC_LOAD_INSTRUMENT ((Instrument *) (-1)) #define SPECIAL_PROGRAM -1 -extern int load_missing_instruments(void); -extern void free_instruments(void); -extern void end_soundfont(void); -extern int set_default_instrument(const char *name); - - -extern int32 convert_tremolo_sweep(uint8 sweep); -extern int32 convert_vibrato_sweep(uint8 sweep, int32 vib_control_ratio); -extern int32 convert_tremolo_rate(uint8 rate); -extern int32 convert_vibrato_rate(uint8 rate); - -extern int init_soundfont(char *fname, int oldbank, int newbank, int level); -extern InstrumentLayer *load_sbk_patch(const char *name, int gm_num, int bank, int percussion, - int panning, int amp, int note_to_use, int sf_ix); -extern int current_tune_number; -extern int max_patch_memory; -extern int current_patch_memory; -#define XMAPMAX 800 -extern int xmap[XMAPMAX][5]; -extern void pcmap(int *b, int *v, int *p, int *drums); - +extern int load_missing_instruments(MidiSong *song); +extern void free_instruments(MidiSong *song); +extern int set_default_instrument(MidiSong *song, char *name); diff --git a/timidity/instrum_dls.c b/timidity/instrum_dls.c new file mode 100644 index 00000000..de006068 --- /dev/null +++ b/timidity/instrum_dls.c @@ -0,0 +1,1255 @@ +/* + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + This program is free software; you can redistribute it and/or modify + it under the terms of the Perl Artistic License, available in COPYING. + + instrum.h + + */ + +#include +#include + +#include "SDL.h" +#include "SDL_endian.h" +#include "SDL_rwops.h" + +#include "SDL.h" + +#include "timidity.h" +#include "options.h" +#include "instrum.h" +#include "tables.h" +#include "common.h" + +/*-------------------------------------------------------------------------*/ +/* * * * * * * * * * * * * * * * * load_riff.h * * * * * * * * * * * * * * */ +/*-------------------------------------------------------------------------*/ +typedef struct _RIFF_Chunk { + Uint32 magic; + Uint32 length; + Uint32 subtype; + Uint8 *data; + struct _RIFF_Chunk *child; + struct _RIFF_Chunk *next; +} RIFF_Chunk; + +extern RIFF_Chunk* LoadRIFF(SDL_RWops *src); +extern void FreeRIFF(RIFF_Chunk *chunk); +extern void PrintRIFF(RIFF_Chunk *chunk, int level); +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*-------------------------------------------------------------------------*/ +/* * * * * * * * * * * * * * * * * load_riff.c * * * * * * * * * * * * * * */ +/*-------------------------------------------------------------------------*/ +#define RIFF 0x46464952 /* "RIFF" */ +#define LIST 0x5453494c /* "LIST" */ + +static RIFF_Chunk *AllocRIFFChunk() +{ + RIFF_Chunk *chunk = (RIFF_Chunk *)malloc(sizeof(*chunk)); + if ( !chunk ) { + SDL_Error(SDL_ENOMEM); + return NULL; + } + memset(chunk, 0, sizeof(*chunk)); + return chunk; +} + +static void FreeRIFFChunk(RIFF_Chunk *chunk) +{ + if ( chunk->child ) { + FreeRIFFChunk(chunk->child); + } + if ( chunk->next ) { + FreeRIFFChunk(chunk->next); + } + free(chunk); +} + +static int ChunkHasSubType(Uint32 magic) +{ + static Uint32 chunk_list[] = { + RIFF, LIST + }; + int i; + for ( i = 0; i < SDL_TABLESIZE(chunk_list); ++i ) { + if ( magic == chunk_list[i] ) { + return 1; + } + } + return 0; +} + +static int ChunkHasSubChunks(Uint32 magic) +{ + static Uint32 chunk_list[] = { + RIFF, LIST + }; + int i; + for ( i = 0; i < SDL_TABLESIZE(chunk_list); ++i ) { + if ( magic == chunk_list[i] ) { + return 1; + } + } + return 0; +} + +static void LoadSubChunks(RIFF_Chunk *chunk, Uint8 *data, Uint32 left) +{ + Uint8 *subchunkData; + Uint32 subchunkDataLen; + + while ( left > 8 ) { + RIFF_Chunk *child = AllocRIFFChunk(); + RIFF_Chunk *next, *prev = NULL; + for ( next = chunk->child; next; next = next->next ) { + prev = next; + } + if ( prev ) { + prev->next = child; + } else { + chunk->child = child; + } + + child->magic = (data[0] << 0) | + (data[1] << 8) | + (data[2] << 16) | + (data[3] << 24); + data += 4; + left -= 4; + child->length = (data[0] << 0) | + (data[1] << 8) | + (data[2] << 16) | + (data[3] << 24); + data += 4; + left -= 4; + child->data = data; + + if ( child->length > left ) { + child->length = left; + } + + subchunkData = child->data; + subchunkDataLen = child->length; + if ( ChunkHasSubType(child->magic) && subchunkDataLen >= 4 ) { + child->subtype = (subchunkData[0] << 0) | + (subchunkData[1] << 8) | + (subchunkData[2] << 16) | + (subchunkData[3] << 24); + subchunkData += 4; + subchunkDataLen -= 4; + } + if ( ChunkHasSubChunks(child->magic) ) { + LoadSubChunks(child, subchunkData, subchunkDataLen); + } + + data += child->length; + left -= child->length; + } +} + +RIFF_Chunk *LoadRIFF(SDL_RWops *src) +{ + RIFF_Chunk *chunk; + Uint8 *subchunkData; + Uint32 subchunkDataLen; + + /* Allocate the chunk structure */ + chunk = AllocRIFFChunk(); + + /* Make sure the file is in RIFF format */ + chunk->magic = SDL_ReadLE32(src); + chunk->length = SDL_ReadLE32(src); + if ( chunk->magic != RIFF ) { + SDL_SetError("Not a RIFF file"); + FreeRIFFChunk(chunk); + return NULL; + } + chunk->data = (Uint8 *)malloc(chunk->length); + if ( chunk->data == NULL ) { + SDL_Error(SDL_ENOMEM); + FreeRIFFChunk(chunk); + return NULL; + } + if ( SDL_RWread(src, chunk->data, chunk->length, 1) != 1 ) { + SDL_Error(SDL_EFREAD); + FreeRIFF(chunk); + return NULL; + } + subchunkData = chunk->data; + subchunkDataLen = chunk->length; + if ( ChunkHasSubType(chunk->magic) && subchunkDataLen >= 4 ) { + chunk->subtype = (subchunkData[0] << 0) | + (subchunkData[1] << 8) | + (subchunkData[2] << 16) | + (subchunkData[3] << 24); + subchunkData += 4; + subchunkDataLen -= 4; + } + if ( ChunkHasSubChunks(chunk->magic) ) { + LoadSubChunks(chunk, subchunkData, subchunkDataLen); + } + return chunk; +} + +void FreeRIFF(RIFF_Chunk *chunk) +{ + free(chunk->data); + FreeRIFFChunk(chunk); +} + +void PrintRIFF(RIFF_Chunk *chunk, int level) +{ + static char prefix[128]; + + if ( level == sizeof(prefix)-1 ) { + return; + } + if ( level > 0 ) { + prefix[(level-1)*2] = ' '; + prefix[(level-1)*2+1] = ' '; + } + prefix[level*2] = '\0'; + printf("%sChunk: %c%c%c%c (%d bytes)", prefix, + ((chunk->magic >> 0) & 0xFF), + ((chunk->magic >> 8) & 0xFF), + ((chunk->magic >> 16) & 0xFF), + ((chunk->magic >> 24) & 0xFF), chunk->length); + if ( chunk->subtype ) { + printf(" subtype: %c%c%c%c", + ((chunk->subtype >> 0) & 0xFF), + ((chunk->subtype >> 8) & 0xFF), + ((chunk->subtype >> 16) & 0xFF), + ((chunk->subtype >> 24) & 0xFF)); + } + printf("\n"); + if ( chunk->child ) { + printf("%s{\n", prefix); + PrintRIFF(chunk->child, level + 1); + printf("%s}\n", prefix); + } + if ( chunk->next ) { + PrintRIFF(chunk->next, level); + } + if ( level > 0 ) { + prefix[(level-1)*2] = '\0'; + } +} + +#ifdef TEST_MAIN_RIFF + +main(int argc, char *argv[]) +{ + int i; + for ( i = 1; i < argc; ++i ) { + RIFF_Chunk *chunk; + SDL_RWops *src = SDL_RWFromFile(argv[i], "rb"); + if ( !src ) { + fprintf(stderr, "Couldn't open %s: %s", argv[i], SDL_GetError()); + continue; + } + chunk = LoadRIFF(src); + if ( chunk ) { + PrintRIFF(chunk, 0); + FreeRIFF(chunk); + } else { + fprintf(stderr, "Couldn't load %s: %s\n", argv[i], SDL_GetError()); + } + SDL_RWclose(src); + } +} + +#endif // TEST_MAIN +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*-------------------------------------------------------------------------*/ +/* * * * * * * * * * * * * * * * * load_dls.h * * * * * * * * * * * * * * */ +/*-------------------------------------------------------------------------*/ +/* This code is based on the DLS spec version 1.1, available at: + http://www.midi.org/about-midi/dls/dlsspec.shtml +*/ + +/* Some typedefs so the public dls headers don't need to be modified */ +#define FAR +typedef Uint8 BYTE; +typedef Sint16 SHORT; +typedef Uint16 USHORT; +typedef Uint16 WORD; +typedef Sint32 LONG; +typedef Uint32 ULONG; +typedef Uint32 DWORD; +#define mmioFOURCC(A, B, C, D) \ + (((A) << 0) | ((B) << 8) | ((C) << 16) | ((D) << 24)) +#define DEFINE_GUID(A, B, C, E, F, G, H, I, J, K, L, M) + +#include "dls1.h" +#include "dls2.h" + +typedef struct _WaveFMT { + WORD wFormatTag; + WORD wChannels; + DWORD dwSamplesPerSec; + DWORD dwAvgBytesPerSec; + WORD wBlockAlign; + WORD wBitsPerSample; +} WaveFMT; + +typedef struct _DLS_Wave { + WaveFMT *format; + Uint8 *data; + Uint32 length; + WSMPL *wsmp; + WLOOP *wsmp_loop; +} DLS_Wave; + +typedef struct _DLS_Region { + RGNHEADER *header; + WAVELINK *wlnk; + WSMPL *wsmp; + WLOOP *wsmp_loop; + CONNECTIONLIST *art; + CONNECTION *artList; +} DLS_Region; + +typedef struct _DLS_Instrument { + const char *name; + INSTHEADER *header; + DLS_Region *regions; + CONNECTIONLIST *art; + CONNECTION *artList; +} DLS_Instrument; + +typedef struct _DLS_Data { + struct _RIFF_Chunk *chunk; + + Uint32 cInstruments; + DLS_Instrument *instruments; + + POOLTABLE *ptbl; + POOLCUE *ptblList; + DLS_Wave *waveList; + + const char *name; + const char *artist; + const char *copyright; + const char *comments; +} DLS_Data; + +extern DLS_Data* LoadDLS(SDL_RWops *src); +extern void FreeDLS(DLS_Data *chunk); +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*-------------------------------------------------------------------------*/ +/* * * * * * * * * * * * * * * * * load_dls.c * * * * * * * * * * * * * * */ +/*-------------------------------------------------------------------------*/ + +#define FOURCC_LIST 0x5453494c /* "LIST" */ +#define FOURCC_FMT 0x20746D66 /* "fmt " */ +#define FOURCC_DATA 0x61746164 /* "data" */ +#define FOURCC_INFO mmioFOURCC('I','N','F','O') +#define FOURCC_IARL mmioFOURCC('I','A','R','L') +#define FOURCC_IART mmioFOURCC('I','A','R','T') +#define FOURCC_ICMS mmioFOURCC('I','C','M','S') +#define FOURCC_ICMT mmioFOURCC('I','C','M','T') +#define FOURCC_ICOP mmioFOURCC('I','C','O','P') +#define FOURCC_ICRD mmioFOURCC('I','C','R','D') +#define FOURCC_IENG mmioFOURCC('I','E','N','G') +#define FOURCC_IGNR mmioFOURCC('I','G','N','R') +#define FOURCC_IKEY mmioFOURCC('I','K','E','Y') +#define FOURCC_IMED mmioFOURCC('I','M','E','D') +#define FOURCC_INAM mmioFOURCC('I','N','A','M') +#define FOURCC_IPRD mmioFOURCC('I','P','R','D') +#define FOURCC_ISBJ mmioFOURCC('I','S','B','J') +#define FOURCC_ISFT mmioFOURCC('I','S','F','T') +#define FOURCC_ISRC mmioFOURCC('I','S','R','C') +#define FOURCC_ISRF mmioFOURCC('I','S','R','F') +#define FOURCC_ITCH mmioFOURCC('I','T','C','H') + + +static void FreeRegions(DLS_Instrument *instrument) +{ + if ( instrument->regions ) { + free(instrument->regions); + } +} + +static void AllocRegions(DLS_Instrument *instrument) +{ + int datalen = (instrument->header->cRegions * sizeof(DLS_Region)); + FreeRegions(instrument); + instrument->regions = (DLS_Region *)malloc(datalen); + if ( instrument->regions ) { + memset(instrument->regions, 0, datalen); + } +} + +static void FreeInstruments(DLS_Data *data) +{ + if ( data->instruments ) { + Uint32 i; + for ( i = 0; i < data->cInstruments; ++i ) { + FreeRegions(&data->instruments[i]); + } + free(data->instruments); + } +} + +static void AllocInstruments(DLS_Data *data) +{ + int datalen = (data->cInstruments * sizeof(DLS_Instrument)); + FreeInstruments(data); + data->instruments = (DLS_Instrument *)malloc(datalen); + if ( data->instruments ) { + memset(data->instruments, 0, datalen); + } +} + +static void FreeWaveList(DLS_Data *data) +{ + if ( data->waveList ) { + free(data->waveList); + } +} + +static void AllocWaveList(DLS_Data *data) +{ + int datalen = (data->ptbl->cCues * sizeof(DLS_Wave)); + FreeWaveList(data); + data->waveList = (DLS_Wave *)malloc(datalen); + if ( data->waveList ) { + memset(data->waveList, 0, datalen); + } +} + +static void Parse_colh(DLS_Data *data, RIFF_Chunk *chunk) +{ + data->cInstruments = SDL_SwapLE32(*(Uint32 *)chunk->data); + AllocInstruments(data); +} + +static void Parse_insh(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument) +{ + INSTHEADER *header = (INSTHEADER *)chunk->data; + header->cRegions = SDL_SwapLE32(header->cRegions); + header->Locale.ulBank = SDL_SwapLE32(header->Locale.ulBank); + header->Locale.ulInstrument = SDL_SwapLE32(header->Locale.ulInstrument); + instrument->header = header; + AllocRegions(instrument); +} + +static void Parse_rgnh(DLS_Data *data, RIFF_Chunk *chunk, DLS_Region *region) +{ + RGNHEADER *header = (RGNHEADER *)chunk->data; + header->RangeKey.usLow = SDL_SwapLE16(header->RangeKey.usLow); + header->RangeKey.usHigh = SDL_SwapLE16(header->RangeKey.usHigh); + header->RangeVelocity.usLow = SDL_SwapLE16(header->RangeVelocity.usLow); + header->RangeVelocity.usHigh = SDL_SwapLE16(header->RangeVelocity.usHigh); + header->fusOptions = SDL_SwapLE16(header->fusOptions); + header->usKeyGroup = SDL_SwapLE16(header->usKeyGroup); + region->header = header; +} + +static void Parse_wlnk(DLS_Data *data, RIFF_Chunk *chunk, DLS_Region *region) +{ + WAVELINK *wlnk = (WAVELINK *)chunk->data; + wlnk->fusOptions = SDL_SwapLE16(wlnk->fusOptions); + wlnk->usPhaseGroup = SDL_SwapLE16(wlnk->usPhaseGroup); + wlnk->ulChannel = SDL_SwapLE16(wlnk->ulChannel); + wlnk->ulTableIndex = SDL_SwapLE16(wlnk->ulTableIndex); + region->wlnk = wlnk; +} + +static void Parse_wsmp(DLS_Data *data, RIFF_Chunk *chunk, WSMPL **wsmp_ptr, WLOOP **wsmp_loop_ptr) +{ + Uint32 i; + WSMPL *wsmp = (WSMPL *)chunk->data; + WLOOP *loop; + wsmp->cbSize = SDL_SwapLE32(wsmp->cbSize); + wsmp->usUnityNote = SDL_SwapLE16(wsmp->usUnityNote); + wsmp->sFineTune = SDL_SwapLE16(wsmp->sFineTune); + wsmp->lAttenuation = SDL_SwapLE32(wsmp->lAttenuation); + wsmp->fulOptions = SDL_SwapLE32(wsmp->fulOptions); + wsmp->cSampleLoops = SDL_SwapLE32(wsmp->cSampleLoops); + loop = (WLOOP *)((Uint8 *)chunk->data + wsmp->cbSize); + *wsmp_ptr = wsmp; + *wsmp_loop_ptr = loop; + for ( i = 0; i < wsmp->cSampleLoops; ++i ) { + loop->cbSize = SDL_SwapLE32(loop->cbSize); + loop->ulType = SDL_SwapLE32(loop->ulType); + loop->ulStart = SDL_SwapLE32(loop->ulStart); + loop->ulLength = SDL_SwapLE32(loop->ulLength); + ++loop; + } +} + +static void Parse_art(DLS_Data *data, RIFF_Chunk *chunk, CONNECTIONLIST **art_ptr, CONNECTION **artList_ptr) +{ + Uint32 i; + CONNECTIONLIST *art = (CONNECTIONLIST *)chunk->data; + CONNECTION *artList; + art->cbSize = SDL_SwapLE32(art->cbSize); + art->cConnections = SDL_SwapLE32(art->cConnections); + artList = (CONNECTION *)((Uint8 *)chunk->data + art->cbSize); + *art_ptr = art; + *artList_ptr = artList; + for ( i = 0; i < art->cConnections; ++i ) { + artList->usSource = SDL_SwapLE16(artList->usSource); + artList->usControl = SDL_SwapLE16(artList->usControl); + artList->usDestination = SDL_SwapLE16(artList->usDestination); + artList->usTransform = SDL_SwapLE16(artList->usTransform); + artList->lScale = SDL_SwapLE32(artList->lScale); + ++artList; + } +} + +static void Parse_lart(DLS_Data *data, RIFF_Chunk *chunk, CONNECTIONLIST **conn_ptr, CONNECTION **connList_ptr) +{ + /* FIXME: This only supports one set of connections */ + for ( chunk = chunk->child; chunk; chunk = chunk->next ) { + Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; + switch(magic) { + case FOURCC_ART1: + case FOURCC_ART2: + Parse_art(data, chunk, conn_ptr, connList_ptr); + return; + } + } +} + +static void Parse_rgn(DLS_Data *data, RIFF_Chunk *chunk, DLS_Region *region) +{ + for ( chunk = chunk->child; chunk; chunk = chunk->next ) { + Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; + switch(magic) { + case FOURCC_RGNH: + Parse_rgnh(data, chunk, region); + break; + case FOURCC_WLNK: + Parse_wlnk(data, chunk, region); + break; + case FOURCC_WSMP: + Parse_wsmp(data, chunk, ®ion->wsmp, ®ion->wsmp_loop); + break; + case FOURCC_LART: + case FOURCC_LAR2: + Parse_lart(data, chunk, ®ion->art, ®ion->artList); + break; + } + } +} + +static void Parse_lrgn(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument) +{ + Uint32 region = 0; + for ( chunk = chunk->child; chunk; chunk = chunk->next ) { + Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; + switch(magic) { + case FOURCC_RGN: + case FOURCC_RGN2: + if ( region < instrument->header->cRegions ) { + Parse_rgn(data, chunk, &instrument->regions[region++]); + } + break; + } + } +} + +static void Parse_INFO_INS(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument) +{ + for ( chunk = chunk->child; chunk; chunk = chunk->next ) { + Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; + switch(magic) { + case FOURCC_INAM: /* Name */ + instrument->name = (char *)chunk->data; + break; + } + } +} + +static void Parse_ins(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument) +{ + for ( chunk = chunk->child; chunk; chunk = chunk->next ) { + Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; + switch(magic) { + case FOURCC_INSH: + Parse_insh(data, chunk, instrument); + break; + case FOURCC_LRGN: + Parse_lrgn(data, chunk, instrument); + break; + case FOURCC_LART: + case FOURCC_LAR2: + Parse_lart(data, chunk, &instrument->art, &instrument->artList); + break; + case FOURCC_INFO: + Parse_INFO_INS(data, chunk, instrument); + break; + } + } +} + +static void Parse_lins(DLS_Data *data, RIFF_Chunk *chunk) +{ + Uint32 instrument = 0; + for ( chunk = chunk->child; chunk; chunk = chunk->next ) { + Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; + switch(magic) { + case FOURCC_INS: + if ( instrument < data->cInstruments ) { + Parse_ins(data, chunk, &data->instruments[instrument++]); + } + break; + } + } +} + +static void Parse_ptbl(DLS_Data *data, RIFF_Chunk *chunk) +{ + Uint32 i; + POOLTABLE *ptbl = (POOLTABLE *)chunk->data; + ptbl->cbSize = SDL_SwapLE32(ptbl->cbSize); + ptbl->cCues = SDL_SwapLE32(ptbl->cCues); + data->ptbl = ptbl; + data->ptblList = (POOLCUE *)((Uint8 *)chunk->data + ptbl->cbSize); + for ( i = 0; i < ptbl->cCues; ++i ) { + data->ptblList[i].ulOffset = SDL_SwapLE32(data->ptblList[i].ulOffset); + } + AllocWaveList(data); +} + +static void Parse_fmt(DLS_Data *data, RIFF_Chunk *chunk, DLS_Wave *wave) +{ + WaveFMT *fmt = (WaveFMT *)chunk->data; + fmt->wFormatTag = SDL_SwapLE16(fmt->wFormatTag); + fmt->wChannels = SDL_SwapLE16(fmt->wChannels); + fmt->dwSamplesPerSec = SDL_SwapLE32(fmt->dwSamplesPerSec); + fmt->dwAvgBytesPerSec = SDL_SwapLE32(fmt->dwAvgBytesPerSec); + fmt->wBlockAlign = SDL_SwapLE16(fmt->wBlockAlign); + fmt->wBitsPerSample = SDL_SwapLE16(fmt->wBitsPerSample); + wave->format = fmt; +} + +static void Parse_data(DLS_Data *data, RIFF_Chunk *chunk, DLS_Wave *wave) +{ + wave->data = chunk->data; + wave->length = chunk->length; +} + +static void Parse_wave(DLS_Data *data, RIFF_Chunk *chunk, DLS_Wave *wave) +{ + for ( chunk = chunk->child; chunk; chunk = chunk->next ) { + Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; + switch(magic) { + case FOURCC_FMT: + Parse_fmt(data, chunk, wave); + break; + case FOURCC_DATA: + Parse_data(data, chunk, wave); + break; + case FOURCC_WSMP: + Parse_wsmp(data, chunk, &wave->wsmp, &wave->wsmp_loop); + break; + } + } +} + +static void Parse_wvpl(DLS_Data *data, RIFF_Chunk *chunk) +{ + Uint32 wave = 0; + for ( chunk = chunk->child; chunk; chunk = chunk->next ) { + Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; + switch(magic) { + case FOURCC_wave: + if ( wave < data->ptbl->cCues ) { + Parse_wave(data, chunk, &data->waveList[wave++]); + } + break; + } + } +} + +static void Parse_INFO_DLS(DLS_Data *data, RIFF_Chunk *chunk) +{ + for ( chunk = chunk->child; chunk; chunk = chunk->next ) { + Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; + switch(magic) { + case FOURCC_IARL: /* Archival Location */ + break; + case FOURCC_IART: /* Artist */ + data->artist = (char *)chunk->data; + break; + case FOURCC_ICMS: /* Commisioned */ + break; + case FOURCC_ICMT: /* Comments */ + data->comments = (char *)chunk->data; + break; + case FOURCC_ICOP: /* Copyright */ + data->copyright = (char *)chunk->data; + break; + case FOURCC_ICRD: /* Creation Date */ + break; + case FOURCC_IENG: /* Engineer */ + break; + case FOURCC_IGNR: /* Genre */ + break; + case FOURCC_IKEY: /* Keywords */ + break; + case FOURCC_IMED: /* Medium */ + break; + case FOURCC_INAM: /* Name */ + data->name = (char *)chunk->data; + break; + case FOURCC_IPRD: /* Product */ + break; + case FOURCC_ISBJ: /* Subject */ + break; + case FOURCC_ISFT: /* Software */ + break; + case FOURCC_ISRC: /* Source */ + break; + case FOURCC_ISRF: /* Source Form */ + break; + case FOURCC_ITCH: /* Technician */ + break; + } + } +} + +DLS_Data *LoadDLS(SDL_RWops *src) +{ + RIFF_Chunk *chunk; + DLS_Data *data = (DLS_Data *)malloc(sizeof(*data)); + if ( !data ) { + SDL_Error(SDL_ENOMEM); + return NULL; + } + memset(data, 0, sizeof(*data)); + + data->chunk = LoadRIFF(src); + if ( !data->chunk ) { + FreeDLS(data); + return NULL; + } + + for ( chunk = data->chunk->child; chunk; chunk = chunk->next ) { + Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; + switch(magic) { + case FOURCC_COLH: + Parse_colh(data, chunk); + break; + case FOURCC_LINS: + Parse_lins(data, chunk); + break; + case FOURCC_PTBL: + Parse_ptbl(data, chunk); + break; + case FOURCC_WVPL: + Parse_wvpl(data, chunk); + break; + case FOURCC_INFO: + Parse_INFO_DLS(data, chunk); + break; + } + } + return data; +} + +void FreeDLS(DLS_Data *data) +{ + if ( data->chunk ) { + FreeRIFF(data->chunk); + } + FreeInstruments(data); + FreeWaveList(data); + free(data); +} + +static const char *SourceToString(USHORT usSource) +{ + switch(usSource) { + case CONN_SRC_NONE: + return "NONE"; + case CONN_SRC_LFO: + return "LFO"; + case CONN_SRC_KEYONVELOCITY: + return "KEYONVELOCITY"; + case CONN_SRC_KEYNUMBER: + return "KEYNUMBER"; + case CONN_SRC_EG1: + return "EG1"; + case CONN_SRC_EG2: + return "EG2"; + case CONN_SRC_PITCHWHEEL: + return "PITCHWHEEL"; + case CONN_SRC_CC1: + return "CC1"; + case CONN_SRC_CC7: + return "CC7"; + case CONN_SRC_CC10: + return "CC10"; + case CONN_SRC_CC11: + return "CC11"; + case CONN_SRC_POLYPRESSURE: + return "POLYPRESSURE"; + case CONN_SRC_CHANNELPRESSURE: + return "CHANNELPRESSURE"; + case CONN_SRC_VIBRATO: + return "VIBRATO"; + case CONN_SRC_MONOPRESSURE: + return "MONOPRESSURE"; + case CONN_SRC_CC91: + return "CC91"; + case CONN_SRC_CC93: + return "CC93"; + default: + return "UNKNOWN"; + } +} + +static const char *TransformToString(USHORT usTransform) +{ + switch (usTransform) { + case CONN_TRN_NONE: + return "NONE"; + case CONN_TRN_CONCAVE: + return "CONCAVE"; + case CONN_TRN_CONVEX: + return "CONVEX"; + case CONN_TRN_SWITCH: + return "SWITCH"; + default: + return "UNKNOWN"; + } +} + +static const char *DestinationToString(USHORT usDestination) +{ + switch (usDestination) { + case CONN_DST_NONE: + return "NONE"; + case CONN_DST_ATTENUATION: + return "ATTENUATION"; + case CONN_DST_PITCH: + return "PITCH"; + case CONN_DST_PAN: + return "PAN"; + case CONN_DST_LFO_FREQUENCY: + return "LFO_FREQUENCY"; + case CONN_DST_LFO_STARTDELAY: + return "LFO_STARTDELAY"; + case CONN_DST_EG1_ATTACKTIME: + return "EG1_ATTACKTIME"; + case CONN_DST_EG1_DECAYTIME: + return "EG1_DECAYTIME"; + case CONN_DST_EG1_RELEASETIME: + return "EG1_RELEASETIME"; + case CONN_DST_EG1_SUSTAINLEVEL: + return "EG1_SUSTAINLEVEL"; + case CONN_DST_EG2_ATTACKTIME: + return "EG2_ATTACKTIME"; + case CONN_DST_EG2_DECAYTIME: + return "EG2_DECAYTIME"; + case CONN_DST_EG2_RELEASETIME: + return "EG2_RELEASETIME"; + case CONN_DST_EG2_SUSTAINLEVEL: + return "EG2_SUSTAINLEVEL"; + case CONN_DST_KEYNUMBER: + return "KEYNUMBER"; + case CONN_DST_LEFT: + return "LEFT"; + case CONN_DST_RIGHT: + return "RIGHT"; + case CONN_DST_CENTER: + return "CENTER"; + case CONN_DST_LEFTREAR: + return "LEFTREAR"; + case CONN_DST_RIGHTREAR: + return "RIGHTREAR"; + case CONN_DST_LFE_CHANNEL: + return "LFE_CHANNEL"; + case CONN_DST_CHORUS: + return "CHORUS"; + case CONN_DST_REVERB: + return "REVERB"; + case CONN_DST_VIB_FREQUENCY: + return "VIB_FREQUENCY"; + case CONN_DST_VIB_STARTDELAY: + return "VIB_STARTDELAY"; + case CONN_DST_EG1_DELAYTIME: + return "EG1_DELAYTIME"; + case CONN_DST_EG1_HOLDTIME: + return "EG1_HOLDTIME"; + case CONN_DST_EG1_SHUTDOWNTIME: + return "EG1_SHUTDOWNTIME"; + case CONN_DST_EG2_DELAYTIME: + return "EG2_DELAYTIME"; + case CONN_DST_EG2_HOLDTIME: + return "EG2_HOLDTIME"; + case CONN_DST_FILTER_CUTOFF: + return "FILTER_CUTOFF"; + case CONN_DST_FILTER_Q: + return "FILTER_Q"; + default: + return "UNKOWN"; + } +} + +static void PrintArt(const char *type, CONNECTIONLIST *art, CONNECTION *artList) +{ + Uint32 i; + printf("%s Connections:\n", type); + for ( i = 0; i < art->cConnections; ++i ) { + printf(" Source: %s, Control: %s, Destination: %s, Transform: %s, Scale: %d\n", + SourceToString(artList[i].usSource), + SourceToString(artList[i].usControl), + DestinationToString(artList[i].usDestination), + TransformToString(artList[i].usTransform), + artList[i].lScale); + } +} + +static void PrintWave(DLS_Wave *wave, Uint32 index) +{ + WaveFMT *format = wave->format; + if ( format ) { + printf(" Wave %u: Format: %hu, %hu channels, %u Hz, %hu bits (length = %u)\n", index, format->wFormatTag, format->wChannels, format->dwSamplesPerSec, format->wBitsPerSample, wave->length); + } + if ( wave->wsmp ) { + Uint32 i; + printf(" wsmp->usUnityNote = %hu\n", wave->wsmp->usUnityNote); + printf(" wsmp->sFineTune = %hd\n", wave->wsmp->sFineTune); + printf(" wsmp->lAttenuation = %d\n", wave->wsmp->lAttenuation); + printf(" wsmp->fulOptions = 0x%8.8x\n", wave->wsmp->fulOptions); + printf(" wsmp->cSampleLoops = %u\n", wave->wsmp->cSampleLoops); + for ( i = 0; i < wave->wsmp->cSampleLoops; ++i ) { + WLOOP *loop = &wave->wsmp_loop[i]; + printf(" Loop %u:\n", i); + printf(" ulStart = %u\n", loop->ulStart); + printf(" ulLength = %u\n", loop->ulLength); + } + } +} + +static void PrintRegion(DLS_Region *region, Uint32 index) +{ + printf(" Region %u:\n", index); + if ( region->header ) { + printf(" RangeKey = { %hu - %hu }\n", region->header->RangeKey.usLow, region->header->RangeKey.usHigh); + printf(" RangeVelocity = { %hu - %hu }\n", region->header->RangeVelocity.usLow, region->header->RangeVelocity.usHigh); + printf(" fusOptions = 0x%4.4hx\n", region->header->fusOptions); + printf(" usKeyGroup = %hu\n", region->header->usKeyGroup); + } + if ( region->wlnk ) { + printf(" wlnk->fusOptions = 0x%4.4hx\n", region->wlnk->fusOptions); + printf(" wlnk->usPhaseGroup = %hu\n", region->wlnk->usPhaseGroup); + printf(" wlnk->ulChannel = %u\n", region->wlnk->ulChannel); + printf(" wlnk->ulTableIndex = %u\n", region->wlnk->ulTableIndex); + } + if ( region->wsmp ) { + Uint32 i; + printf(" wsmp->usUnityNote = %hu\n", region->wsmp->usUnityNote); + printf(" wsmp->sFineTune = %hd\n", region->wsmp->sFineTune); + printf(" wsmp->lAttenuation = %d\n", region->wsmp->lAttenuation); + printf(" wsmp->fulOptions = 0x%8.8x\n", region->wsmp->fulOptions); + printf(" wsmp->cSampleLoops = %u\n", region->wsmp->cSampleLoops); + for ( i = 0; i < region->wsmp->cSampleLoops; ++i ) { + WLOOP *loop = ®ion->wsmp_loop[i]; + printf(" Loop %u:\n", i); + printf(" ulStart = %u\n", loop->ulStart); + printf(" ulLength = %u\n", loop->ulLength); + } + } + if ( region->art && region->art->cConnections > 0 ) { + PrintArt("Region", region->art, region->artList); + } +} + +static void PrintInstrument(DLS_Instrument *instrument, Uint32 index) +{ + printf("Instrument %u:\n", index); + if ( instrument->name ) { + printf(" Name: %s\n", instrument->name); + } + if ( instrument->header ) { + Uint32 i; + printf(" ulBank = 0x%8.8x\n", instrument->header->Locale.ulBank); + printf(" ulInstrument = %u\n", instrument->header->Locale.ulInstrument); + printf(" Regions: %u\n", instrument->header->cRegions); + for ( i = 0; i < instrument->header->cRegions; ++i ) { + PrintRegion(&instrument->regions[i], i); + } + } + if ( instrument->art && instrument->art->cConnections > 0 ) { + PrintArt("Instrument", instrument->art, instrument->artList); + } +}; + +void PrintDLS(DLS_Data *data) +{ + printf("DLS Data:\n"); + printf("cInstruments = %u\n", data->cInstruments); + if ( data->instruments ) { + Uint32 i; + for ( i = 0; i < data->cInstruments; ++i ) { + PrintInstrument(&data->instruments[i], i); + } + } + if ( data->ptbl && data->ptbl->cCues > 0 ) { + Uint32 i; + printf("Cues: "); + for ( i = 0; i < data->ptbl->cCues; ++i ) { + if ( i > 0 ) { + printf(", "); + } + printf("%u", data->ptblList[i].ulOffset); + } + printf("\n"); + } + if ( data->waveList ) { + Uint32 i; + printf("Waves:\n"); + for ( i = 0; i < data->ptbl->cCues; ++i ) { + PrintWave(&data->waveList[i], i); + } + } + if ( data->name ) { + printf("Name: %s\n", data->name); + } + if ( data->artist ) { + printf("Artist: %s\n", data->artist); + } + if ( data->copyright ) { + printf("Copyright: %s\n", data->copyright); + } + if ( data->comments ) { + printf("Comments: %s\n", data->comments); + } +} + +#ifdef TEST_MAIN_DLS + +main(int argc, char *argv[]) +{ + int i; + for ( i = 1; i < argc; ++i ) { + DLS_Data *data; + SDL_RWops *src = SDL_RWFromFile(argv[i], "rb"); + if ( !src ) { + fprintf(stderr, "Couldn't open %s: %s", argv[i], SDL_GetError()); + continue; + } + data = LoadDLS(src); + if ( data ) { + PrintRIFF(data->chunk, 0); + PrintDLS(data); + FreeDLS(data); + } else { + fprintf(stderr, "Couldn't load %s: %s\n", argv[i], SDL_GetError()); + } + SDL_RWclose(src); + } +} + +#endif // TEST_MAIN +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*-------------------------------------------------------------------------*/ +/* * * * * * * * * * * * * * * * * instrum_dls.c * * * * * * * * * * * * * */ +/*-------------------------------------------------------------------------*/ + +DLS_Data *Timidity_LoadDLS(SDL_RWops *src) +{ + DLS_Data *patches = LoadDLS(src); + if (!patches) { + SNDDBG(("%s", SDL_GetError())); + } + return patches; +} + +void Timidity_FreeDLS(DLS_Data *patches) +{ + FreeDLS(patches); +} + +/* convert timecents to sec */ +static double to_msec(int timecent) +{ + if (timecent == 0x80000000 || timecent == 0) + return 0.0; + return 1000.0 * pow(2.0, (double)(timecent / 65536) / 1200.0); +} + +/* convert decipercent to {0..1} */ +static double to_normalized_percent(int decipercent) +{ + return ((double)(decipercent / 65536)) / 1000.0; +} + +/* convert from 8bit value to fractional offset (15.15) */ +static Sint32 to_offset(int offset) +{ + return (Sint32)offset << (7+15); +} + +/* calculate ramp rate in fractional unit; + * diff = 8bit, time = msec + */ +static Sint32 calc_rate(MidiSong *song, int diff, int sample_rate, double msec) +{ + double rate; + + if(msec < 6) + msec = 6; + if(diff == 0) + diff = 255; + diff <<= (7+15); + rate = ((double)diff / song->rate) * song->control_ratio * 1000.0 / msec; + return (Sint32)rate; +} + +static int load_connection(ULONG cConnections, CONNECTION *artList, USHORT destination) +{ + ULONG i; + int value = 0; + for (i = 0; i < cConnections; ++i) { + CONNECTION *conn = &artList[i]; + if(conn->usDestination == destination) { + // The formula for the destination is: + // usDestination = usDestination + usTransform(usSource * (usControl * lScale)) + // Since we are only handling source/control of NONE and identity + // transform, this simplifies to: usDestination = usDestination + lScale + if (conn->usSource == CONN_SRC_NONE && + conn->usControl == CONN_SRC_NONE && + conn->usTransform == CONN_TRN_NONE) + value += conn->lScale; + } + } + return value; +} + +static void load_region_dls(MidiSong *song, Sample *sample, DLS_Instrument *ins, Uint32 index) +{ + DLS_Region *rgn = &ins->regions[index]; + DLS_Wave *wave = &song->patches->waveList[rgn->wlnk->ulTableIndex]; + + sample->low_freq = freq_table[rgn->header->RangeKey.usLow]; + sample->high_freq = freq_table[rgn->header->RangeKey.usHigh]; + sample->root_freq = freq_table[rgn->wsmp->usUnityNote]; + sample->low_vel = rgn->header->RangeVelocity.usLow; + sample->high_vel = rgn->header->RangeVelocity.usHigh; + + sample->modes = MODES_16BIT; + sample->sample_rate = wave->format->dwSamplesPerSec; + sample->data_length = wave->length / 2; + sample->data = (sample_t *)safe_malloc(wave->length); + memcpy(sample->data, wave->data, wave->length); + if (rgn->wsmp->cSampleLoops) { + sample->modes |= (MODES_LOOPING|MODES_SUSTAIN); + sample->loop_start = rgn->wsmp_loop->ulStart / 2; + sample->loop_end = sample->loop_start + (rgn->wsmp_loop->ulLength / 2); + } + sample->volume = 1.0f; + + if (sample->modes & MODES_SUSTAIN) { + int value; + double attack, hold, decay, release; int sustain; + CONNECTIONLIST *art = NULL; + CONNECTION *artList = NULL; + + if (ins->art && ins->art->cConnections > 0 && ins->artList) { + art = ins->art; + artList = ins->artList; + } else { + art = rgn->art; + artList = rgn->artList; + } + + value = load_connection(art->cConnections, artList, CONN_DST_EG1_ATTACKTIME); + attack = to_msec(value); + value = load_connection(art->cConnections, artList, CONN_DST_EG1_HOLDTIME); + hold = to_msec(value); + value = load_connection(art->cConnections, artList, CONN_DST_EG1_DECAYTIME); + decay = to_msec(value); + value = load_connection(art->cConnections, artList, CONN_DST_EG1_RELEASETIME); + release = to_msec(value); + value = load_connection(art->cConnections, artList, CONN_DST_EG1_SUSTAINLEVEL); + sustain = (int)((1.0 - to_normalized_percent(value)) * 250.0); + value = load_connection(art->cConnections, artList, CONN_DST_PAN); + sample->panning = (int)((0.5 + to_normalized_percent(value)) * 127.0); + +/* +printf("%d, Rate=%d LV=%d HV=%d Low=%d Hi=%d Root=%d Pan=%d Attack=%f Hold=%f Sustain=%d Decay=%f Release=%f\n", index, sample->sample_rate, rgn->header->RangeVelocity.usLow, rgn->header->RangeVelocity.usHigh, sample->low_freq, sample->high_freq, sample->root_freq, sample->panning, attack, hold, sustain, decay, release); +*/ + + sample->envelope_offset[0] = to_offset(255); + sample->envelope_rate[0] = calc_rate(song, 255, sample->sample_rate, attack); + + sample->envelope_offset[1] = to_offset(250); + sample->envelope_rate[1] = calc_rate(song, 5, sample->sample_rate, hold); + + sample->envelope_offset[2] = to_offset(sustain); + sample->envelope_rate[2] = calc_rate(song, 255 - sustain, sample->sample_rate, decay); + + sample->envelope_offset[3] = to_offset(0); + sample->envelope_rate[3] = calc_rate(song, 5 + sustain, sample->sample_rate, release); + + sample->envelope_offset[4] = to_offset(0); + sample->envelope_rate[4] = to_offset(1); + + sample->envelope_offset[5] = to_offset(0); + sample->envelope_rate[5] = to_offset(1); + + sample->modes |= MODES_ENVELOPE; + } + + sample->data_length <<= FRACTION_BITS; + sample->loop_start <<= FRACTION_BITS; + sample->loop_end <<= FRACTION_BITS; +} + +Instrument *load_instrument_dls(MidiSong *song, int drum, int bank, int instrument) +{ + Instrument *inst; + Uint32 i; + DLS_Instrument *dls_ins; + + if (!song->patches) + return(NULL); + + drum = drum ? 0x80000000 : 0; + for (i = 0; i < song->patches->cInstruments; ++i) { + dls_ins = &song->patches->instruments[i]; + if ((dls_ins->header->Locale.ulBank & 0x80000000) == drum && + ((dls_ins->header->Locale.ulBank >> 8) & 0xFF) == bank && + dls_ins->header->Locale.ulInstrument == instrument) + break; + } + if (i == song->patches->cInstruments && !bank) { + for (i = 0; i < song->patches->cInstruments; ++i) { + dls_ins = &song->patches->instruments[i]; + if ((dls_ins->header->Locale.ulBank & 0x80000000) == drum && + dls_ins->header->Locale.ulInstrument == instrument) + break; + } + } + if (i == song->patches->cInstruments) { + SNDDBG(("Couldn't find %s instrument %d in bank %d\n", drum ? "drum" : "melodic", instrument, bank)); + return(NULL); + } + + inst = (Instrument *)safe_malloc(sizeof(*inst)); + inst->samples = dls_ins->header->cRegions; + inst->sample = (Sample *)safe_malloc(inst->samples * sizeof(*inst->sample)); + memset(inst->sample, 0, inst->samples * sizeof(*inst->sample)); +/* +printf("Found %s instrument %d in bank %d named %s with %d regions\n", drum ? "drum" : "melodic", instrument, bank, dls_ins->name, inst->samples); +*/ + for (i = 0; i < dls_ins->header->cRegions; ++i) { + load_region_dls(song, &inst->sample[i], dls_ins, i); + } + return(inst); +} diff --git a/timidity/sdl_a.c b/timidity/instrum_dls.h similarity index 61% rename from timidity/sdl_a.c rename to timidity/instrum_dls.h index 6ea0f4c0..2fb1fe9c 100644 --- a/timidity/sdl_a.c +++ b/timidity/instrum_dls.h @@ -1,19 +1,13 @@ /* + TiMidity -- Experimental MIDI to WAVE converter Copyright (C) 1995 Tuukka Toivonen This program is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License, available in COPYING. - */ - -#include "config.h" -#include "output.h" -/* export the playback mode */ + instrum.h -#define dpm sdl_play_mode + */ -PlayMode dpm = { - DEFAULT_RATE, PE_16BIT|PE_SIGNED, - "SDL audio" -}; +extern Instrument *load_instrument_dls(MidiSong *song, int drum, int bank, int instrument); diff --git a/timidity/mix.c b/timidity/mix.c index 8871ffbf..f2330236 100644 --- a/timidity/mix.c +++ b/timidity/mix.c @@ -1,177 +1,157 @@ /* + TiMidity -- Experimental MIDI to WAVE converter Copyright (C) 1995 Tuukka Toivonen This program is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License, available in COPYING. - */ + + mix.c */ + +#if HAVE_CONFIG_H +# include +#endif #include #include #include -#include "config.h" -#include "common.h" +#include "SDL.h" + +#include "timidity.h" +#include "options.h" #include "instrum.h" #include "playmidi.h" #include "output.h" -#include "ctrlmode.h" #include "tables.h" #include "resample.h" #include "mix.h" /* Returns 1 if envelope runs out */ -int recompute_envelope(int v) +int recompute_envelope(MidiSong *song, int v) { int stage; - stage = voice[v].envelope_stage; + stage = song->voice[v].envelope_stage; if (stage>5) { /* Envelope ran out. */ - int tmp=(voice[v].status == VOICE_DIE); /* Already displayed as dead */ - voice[v].status = VOICE_FREE; - if(!tmp) - ctl->note(v); + song->voice[v].status = VOICE_FREE; return 1; } - if (voice[v].sample->modes & MODES_ENVELOPE) + if (song->voice[v].sample->modes & MODES_ENVELOPE) { - if (voice[v].status==VOICE_ON || voice[v].status==VOICE_SUSTAINED) + if (song->voice[v].status==VOICE_ON || song->voice[v].status==VOICE_SUSTAINED) { if (stage>2) { /* Freeze envelope until note turns off. Trumpets want this. */ - voice[v].envelope_increment=0; + song->voice[v].envelope_increment=0; return 0; } } } - voice[v].envelope_stage=stage+1; - - if (voice[v].envelope_volume==voice[v].sample->envelope_offset[stage]) - return recompute_envelope(v); - voice[v].envelope_target=voice[v].sample->envelope_offset[stage]; - voice[v].envelope_increment = voice[v].sample->envelope_rate[stage]; - if (voice[v].envelope_targetvoice[v].envelope_stage=stage+1; + + if (song->voice[v].envelope_volume==song->voice[v].sample->envelope_offset[stage]) + return recompute_envelope(song, v); + song->voice[v].envelope_target = song->voice[v].sample->envelope_offset[stage]; + song->voice[v].envelope_increment = song->voice[v].sample->envelope_rate[stage]; + if (song->voice[v].envelope_target < song->voice[v].envelope_volume) + song->voice[v].envelope_increment = -song->voice[v].envelope_increment; return 0; } -void apply_envelope_to_amp(int v) +void apply_envelope_to_amp(MidiSong *song, int v) { - FLOAT_T lamp=voice[v].left_amp, ramp, lramp, rramp, ceamp, lfeamp; - int32 la,ra, lra, rra, cea, lfea; - if (voice[v].panned == PANNED_MYSTERY) + float lamp = song->voice[v].left_amp, ramp; + Sint32 la,ra; + if (song->voice[v].panned == PANNED_MYSTERY) { - lramp=voice[v].lr_amp; - ramp=voice[v].right_amp; - ceamp=voice[v].ce_amp; - rramp=voice[v].rr_amp; - lfeamp=voice[v].lfe_amp; - - if (voice[v].tremolo_phase_increment) + ramp = song->voice[v].right_amp; + if (song->voice[v].tremolo_phase_increment) { - FLOAT_T tv = voice[v].tremolo_volume; - lramp *= tv; - lamp *= tv; - ceamp *= tv; - ramp *= tv; - rramp *= tv; - lfeamp *= tv; + lamp *= song->voice[v].tremolo_volume; + ramp *= song->voice[v].tremolo_volume; } - if (voice[v].sample->modes & MODES_ENVELOPE) + if (song->voice[v].sample->modes & MODES_ENVELOPE) { - FLOAT_T ev = (FLOAT_T)vol_table[voice[v].envelope_volume>>23]; - lramp *= ev; - lamp *= ev; - ceamp *= ev; - ramp *= ev; - rramp *= ev; - lfeamp *= ev; + lamp *= (float)vol_table[song->voice[v].envelope_volume>>23]; + ramp *= (float)vol_table[song->voice[v].envelope_volume>>23]; } - la = (int32)FSCALE(lamp,AMP_BITS); - ra = (int32)FSCALE(ramp,AMP_BITS); - lra = (int32)FSCALE(lramp,AMP_BITS); - rra = (int32)FSCALE(rramp,AMP_BITS); - cea = (int32)FSCALE(ceamp,AMP_BITS); - lfea = (int32)FSCALE(lfeamp,AMP_BITS); + la = (Sint32)FSCALE(lamp,AMP_BITS); + + if (la>MAX_AMP_VALUE) + la=MAX_AMP_VALUE; + + ra = (Sint32)FSCALE(ramp,AMP_BITS); + if (ra>MAX_AMP_VALUE) + ra=MAX_AMP_VALUE; - if (la>MAX_AMP_VALUE) la=MAX_AMP_VALUE; - if (ra>MAX_AMP_VALUE) ra=MAX_AMP_VALUE; - if (lra>MAX_AMP_VALUE) lra=MAX_AMP_VALUE; - if (rra>MAX_AMP_VALUE) rra=MAX_AMP_VALUE; - if (cea>MAX_AMP_VALUE) cea=MAX_AMP_VALUE; - if (lfea>MAX_AMP_VALUE) lfea=MAX_AMP_VALUE; - - voice[v].lr_mix=FINAL_VOLUME(lra); - voice[v].left_mix=FINAL_VOLUME(la); - voice[v].ce_mix=FINAL_VOLUME(cea); - voice[v].right_mix=FINAL_VOLUME(ra); - voice[v].rr_mix=FINAL_VOLUME(rra); - voice[v].lfe_mix=FINAL_VOLUME(lfea); + song->voice[v].left_mix = la; + song->voice[v].right_mix = ra; } else { - if (voice[v].tremolo_phase_increment) - lamp *= voice[v].tremolo_volume; - if (voice[v].sample->modes & MODES_ENVELOPE) - lamp *= (FLOAT_T)vol_table[voice[v].envelope_volume>>23]; + if (song->voice[v].tremolo_phase_increment) + lamp *= song->voice[v].tremolo_volume; + if (song->voice[v].sample->modes & MODES_ENVELOPE) + lamp *= (float)vol_table[song->voice[v].envelope_volume>>23]; - la = (int32)FSCALE(lamp,AMP_BITS); + la = (Sint32)FSCALE(lamp,AMP_BITS); if (la>MAX_AMP_VALUE) la=MAX_AMP_VALUE; - voice[v].left_mix=FINAL_VOLUME(la); + song->voice[v].left_mix = la; } } -static int update_envelope(int v) +static int update_envelope(MidiSong *song, int v) { - voice[v].envelope_volume += voice[v].envelope_increment; + song->voice[v].envelope_volume += song->voice[v].envelope_increment; /* Why is there no ^^ operator?? */ - if (((voice[v].envelope_increment < 0) && - (voice[v].envelope_volume <= voice[v].envelope_target)) || - ((voice[v].envelope_increment > 0) && - (voice[v].envelope_volume >= voice[v].envelope_target))) + if (((song->voice[v].envelope_increment < 0) && + (song->voice[v].envelope_volume <= song->voice[v].envelope_target)) || + ((song->voice[v].envelope_increment > 0) && + (song->voice[v].envelope_volume >= song->voice[v].envelope_target))) { - voice[v].envelope_volume = voice[v].envelope_target; - if (recompute_envelope(v)) + song->voice[v].envelope_volume = song->voice[v].envelope_target; + if (recompute_envelope(song, v)) return 1; } return 0; } -static void update_tremolo(int v) +static void update_tremolo(MidiSong *song, int v) { - int32 depth=voice[v].sample->tremolo_depth<<7; + Sint32 depth = song->voice[v].sample->tremolo_depth << 7; - if (voice[v].tremolo_sweep) + if (song->voice[v].tremolo_sweep) { /* Update sweep position */ - voice[v].tremolo_sweep_position += voice[v].tremolo_sweep; - if (voice[v].tremolo_sweep_position>=(1<voice[v].tremolo_sweep_position += song->voice[v].tremolo_sweep; + if (song->voice[v].tremolo_sweep_position >= (1 << SWEEP_SHIFT)) + song->voice[v].tremolo_sweep=0; /* Swept to max amplitude */ else { /* Need to adjust depth */ - depth *= voice[v].tremolo_sweep_position; + depth *= song->voice[v].tremolo_sweep_position; depth >>= SWEEP_SHIFT; } } - voice[v].tremolo_phase += voice[v].tremolo_phase_increment; + song->voice[v].tremolo_phase += song->voice[v].tremolo_phase_increment; - /* if (voice[v].tremolo_phase >= (SINE_CYCLE_LENGTH<voice[v].tremolo_phase >= (SINE_CYCLE_LENGTH<voice[v].tremolo_phase -= SINE_CYCLE_LENGTH<> RATE_SHIFT) + 1.0) + song->voice[v].tremolo_volume = (float) + (1.0 - FSCALENEG((sine(song->voice[v].tremolo_phase >> RATE_SHIFT) + 1.0) * depth * TREMOLO_AMPLITUDE_TUNING, 17)); @@ -180,54 +160,37 @@ static void update_tremolo(int v) } /* Returns 1 if the note died */ -static int update_signal(int v) +static int update_signal(MidiSong *song, int v) { - if (voice[v].envelope_increment && update_envelope(v)) + if (song->voice[v].envelope_increment && update_envelope(song, v)) return 1; - if (voice[v].tremolo_phase_increment) - update_tremolo(v); + if (song->voice[v].tremolo_phase_increment) + update_tremolo(song, v); - apply_envelope_to_amp(v); + apply_envelope_to_amp(song, v); return 0; } -#ifdef LOOKUP_HACK -# define MIXATION(a) *lp++ += mixup[(a<<8) | (uint8)s]; -#else -# define MIXATION(a) *lp++ += (a)*s; -#endif - -#define MIXSKIP lp++ -#define MIXMAX(a,b) *lp++ += ((a>b)?a:b) * s -#define MIXCENT(a,b) *lp++ += (a/2+b/2) * s -#define MIXHALF(a) *lp++ += (a>>1)*s; +#define MIXATION(a) *lp++ += (a)*s; -static void mix_mystery_signal(resample_t *sp, int32 *lp, int v, int count) +static void mix_mystery_signal(MidiSong *song, sample_t *sp, Sint32 *lp, int v, + int count) { - Voice *vp = voice + v; + Voice *vp = song->voice + v; final_volume_t - left_rear=vp->lr_mix, left=vp->left_mix, - center=vp->ce_mix, - right=vp->right_mix, - right_rear=vp->rr_mix, - lfe=vp->lfe_mix; + right=vp->right_mix; int cc; - resample_t s; + sample_t s; if (!(cc = vp->control_counter)) { - cc = control_ratio; - if (update_signal(v)) + cc = song->control_ratio; + if (update_signal(song, v)) return; /* Envelope ran out */ - - left_rear = vp->lr_mix; - left = vp->left_mix; - center = vp->ce_mix; - right = vp->right_mix; - right_rear = vp->rr_mix; - lfe = vp->lfe_mix; + left = vp->left_mix; + right = vp->right_mix; } while (count) @@ -237,26 +200,14 @@ static void mix_mystery_signal(resample_t *sp, int32 *lp, int v, int count) while (cc--) { s = *sp++; - MIXATION(left); - MIXATION(right); - if (num_ochannels >= 4) { - MIXATION(left_rear); - MIXATION(right_rear); - } - if (num_ochannels == 6) { - MIXATION(center); - MIXATION(lfe); - } + MIXATION(left); + MIXATION(right); } - cc = control_ratio; - if (update_signal(v)) + cc = song->control_ratio; + if (update_signal(song, v)) return; /* Envelope ran out */ - left_rear = vp->lr_mix; left = vp->left_mix; - center = vp->ce_mix; right = vp->right_mix; - right_rear = vp->rr_mix; - lfe = vp->lfe_mix; } else { @@ -264,33 +215,26 @@ static void mix_mystery_signal(resample_t *sp, int32 *lp, int v, int count) while (count--) { s = *sp++; - MIXATION(left); - MIXATION(right); - if (num_ochannels >= 4) { - MIXATION(left_rear); - MIXATION(right_rear); - } - if (num_ochannels == 6) { - MIXATION(center); - MIXATION(lfe); - } + MIXATION(left); + MIXATION(right); } return; } } -static void mix_center_signal(resample_t *sp, int32 *lp, int v, int count) +static void mix_center_signal(MidiSong *song, sample_t *sp, Sint32 *lp, int v, + int count) { - Voice *vp = voice + v; + Voice *vp = song->voice + v; final_volume_t left=vp->left_mix; int cc; - resample_t s; + sample_t s; if (!(cc = vp->control_counter)) { - cc = control_ratio; - if (update_signal(v)) + cc = song->control_ratio; + if (update_signal(song, v)) return; /* Envelope ran out */ left = vp->left_mix; } @@ -302,99 +246,11 @@ static void mix_center_signal(resample_t *sp, int32 *lp, int v, int count) while (cc--) { s = *sp++; - if (num_ochannels == 2) { - MIXATION(left); - MIXATION(left); - } - else if (num_ochannels == 4) { - MIXATION(left); - MIXSKIP; - MIXATION(left); - MIXSKIP; - } - else if (num_ochannels == 6) { - MIXSKIP; - MIXSKIP; - MIXSKIP; - MIXSKIP; - MIXATION(left); - MIXATION(left); - } - } - cc = control_ratio; - if (update_signal(v)) - return; /* Envelope ran out */ - left = vp->left_mix; - } - else - { - vp->control_counter = cc - count; - while (count--) - { - s = *sp++; - if (num_ochannels == 2) { - MIXATION(left); - MIXATION(left); - } - else if (num_ochannels == 4) { - MIXATION(left); - MIXSKIP; - MIXATION(left); - MIXSKIP; - } - else if (num_ochannels == 6) { - MIXSKIP; - MIXSKIP; - MIXSKIP; - MIXSKIP; - MIXATION(left); - MIXATION(left); - } - } - return; - } -} - -static void mix_single_left_signal(resample_t *sp, int32 *lp, int v, int count) -{ - Voice *vp = voice + v; - final_volume_t - left=vp->left_mix; - int cc; - resample_t s; - - if (!(cc = vp->control_counter)) - { - cc = control_ratio; - if (update_signal(v)) - return; /* Envelope ran out */ - left = vp->left_mix; - } - - while (count) - if (cc < count) - { - count -= cc; - while (cc--) - { - s = *sp++; - if (num_ochannels == 2) { - MIXATION(left); - MIXSKIP; - } - if (num_ochannels >= 4) { - MIXHALF(left); - MIXSKIP; - MIXATION(left); - MIXSKIP; - } - if (num_ochannels == 6) { - MIXSKIP; - MIXATION(left); - } + MIXATION(left); + MIXATION(left); } - cc = control_ratio; - if (update_signal(v)) + cc = song->control_ratio; + if (update_signal(song, v)) return; /* Envelope ran out */ left = vp->left_mix; } @@ -404,37 +260,26 @@ static void mix_single_left_signal(resample_t *sp, int32 *lp, int v, int count) while (count--) { s = *sp++; - if (num_ochannels == 2) { - MIXATION(left); - MIXSKIP; - } - if (num_ochannels >= 4) { - MIXHALF(left); - MIXSKIP; - MIXATION(left); - MIXSKIP; - } - if (num_ochannels == 6) { - MIXSKIP; - MIXATION(left); - } + MIXATION(left); + MIXATION(left); } return; } } -static void mix_single_right_signal(resample_t *sp, int32 *lp, int v, int count) +static void mix_single_signal(MidiSong *song, sample_t *sp, Sint32 *lp, int v, + int count) { - Voice *vp = voice + v; + Voice *vp = song->voice + v; final_volume_t left=vp->left_mix; int cc; - resample_t s; + sample_t s; if (!(cc = vp->control_counter)) { - cc = control_ratio; - if (update_signal(v)) + cc = song->control_ratio; + if (update_signal(song, v)) return; /* Envelope ran out */ left = vp->left_mix; } @@ -446,22 +291,11 @@ static void mix_single_right_signal(resample_t *sp, int32 *lp, int v, int count) while (cc--) { s = *sp++; - if (num_ochannels == 2) { - MIXSKIP; - MIXATION(left); - } - if (num_ochannels >= 4) { - MIXSKIP; - MIXHALF(left); - MIXSKIP; - MIXATION(left); - } if (num_ochannels == 6) { - MIXSKIP; - MIXATION(left); - } + MIXATION(left); + lp++; } - cc = control_ratio; - if (update_signal(v)) + cc = song->control_ratio; + if (update_signal(song, v)) return; /* Envelope ran out */ left = vp->left_mix; } @@ -471,36 +305,26 @@ static void mix_single_right_signal(resample_t *sp, int32 *lp, int v, int count) while (count--) { s = *sp++; - if (num_ochannels == 2) { - MIXSKIP; - MIXATION(left); - } - if (num_ochannels >= 4) { - MIXSKIP; - MIXHALF(left); - MIXSKIP; - MIXATION(left); - } if (num_ochannels == 6) { - MIXSKIP; - MIXATION(left); - } + MIXATION(left); + lp++; } return; } } -static void mix_mono_signal(resample_t *sp, int32 *lp, int v, int count) +static void mix_mono_signal(MidiSong *song, sample_t *sp, Sint32 *lp, int v, + int count) { - Voice *vp = voice + v; + Voice *vp = song->voice + v; final_volume_t left=vp->left_mix; int cc; - resample_t s; + sample_t s; if (!(cc = vp->control_counter)) { - cc = control_ratio; - if (update_signal(v)) + cc = song->control_ratio; + if (update_signal(song, v)) return; /* Envelope ran out */ left = vp->left_mix; } @@ -514,8 +338,8 @@ static void mix_mono_signal(resample_t *sp, int32 *lp, int v, int count) s = *sp++; MIXATION(left); } - cc = control_ratio; - if (update_signal(v)) + cc = song->control_ratio; + if (update_signal(song, v)) return; /* Envelope ran out */ left = vp->left_mix; } @@ -531,119 +355,54 @@ static void mix_mono_signal(resample_t *sp, int32 *lp, int v, int count) } } -static void mix_mystery(resample_t *sp, int32 *lp, int v, int count) +static void mix_mystery(MidiSong *song, sample_t *sp, Sint32 *lp, int v, int count) { final_volume_t - left_rear=voice[v].lr_mix, - left=voice[v].left_mix, - center=voice[v].ce_mix, - right=voice[v].right_mix, - right_rear=voice[v].rr_mix, - lfe=voice[v].lfe_mix; - resample_t s; + left = song->voice[v].left_mix, + right = song->voice[v].right_mix; + sample_t s; while (count--) { s = *sp++; - MIXATION(left); - MIXATION(right); - if (num_ochannels >= 4) { - MIXATION(left_rear); - MIXATION(right_rear); - } - if (num_ochannels == 6) { - MIXATION(center); - MIXATION(lfe); - } + MIXATION(left); + MIXATION(right); } } -static void mix_center(resample_t *sp, int32 *lp, int v, int count) +static void mix_center(MidiSong *song, sample_t *sp, Sint32 *lp, int v, int count) { final_volume_t - left=voice[v].left_mix; - resample_t s; + left = song->voice[v].left_mix; + sample_t s; while (count--) { s = *sp++; - if (num_ochannels == 2) { - MIXATION(left); - MIXATION(left); - } - else if (num_ochannels == 4) { - MIXATION(left); - MIXATION(left); - MIXSKIP; - MIXSKIP; - } - else if (num_ochannels == 6) { - MIXSKIP; - MIXSKIP; - MIXSKIP; - MIXSKIP; - MIXATION(left); - MIXATION(left); - } + MIXATION(left); + MIXATION(left); } } -static void mix_single_left(resample_t *sp, int32 *lp, int v, int count) -{ - final_volume_t - left=voice[v].left_mix; - resample_t s; - - while (count--) - { - s = *sp++; - if (num_ochannels == 2) { - MIXATION(left); - MIXSKIP; - } - if (num_ochannels >= 4) { - MIXHALF(left); - MIXSKIP; - MIXATION(left); - MIXSKIP; - } - if (num_ochannels == 6) { - MIXSKIP; - MIXATION(left); - } - } -} -static void mix_single_right(resample_t *sp, int32 *lp, int v, int count) +static void mix_single(MidiSong *song, sample_t *sp, Sint32 *lp, int v, int count) { final_volume_t - left=voice[v].left_mix; - resample_t s; + left = song->voice[v].left_mix; + sample_t s; while (count--) { s = *sp++; - if (num_ochannels == 2) { - MIXSKIP; - MIXATION(left); - } - if (num_ochannels >= 4) { - MIXSKIP; - MIXHALF(left); - MIXSKIP; - MIXATION(left); - } - if (num_ochannels == 6) { - MIXSKIP; - MIXATION(left); - } + MIXATION(left); + lp++; } } -static void mix_mono(resample_t *sp, int32 *lp, int v, int count) +static void mix_mono(MidiSong *song, sample_t *sp, Sint32 *lp, int v, int count) { final_volume_t - left=voice[v].left_mix; - resample_t s; + left = song->voice[v].left_mix; + sample_t s; while (count--) { @@ -653,56 +412,43 @@ static void mix_mono(resample_t *sp, int32 *lp, int v, int count) } /* Ramp a note out in c samples */ -static void ramp_out(resample_t *sp, int32 *lp, int v, int32 c) +static void ramp_out(MidiSong *song, sample_t *sp, Sint32 *lp, int v, Sint32 c) { - /* should be final_volume_t, but uint8 gives trouble. */ - int32 left_rear, left, center, right, right_rear, lfe, li, ri; + /* should be final_volume_t, but Uint8 gives trouble. */ + Sint32 left, right, li, ri; - resample_t s = 0; /* silly warning about uninitialized s */ + sample_t s=0; /* silly warning about uninitialized s */ /* Fix by James Caldwell */ if ( c == 0 ) c = 1; - - left = voice[v].left_mix; - li = -(left/c); - if (!li) li = -1; + + left=song->voice[v].left_mix; + li=-(left/c); + if (!li) li=-1; /* printf("Ramping out: left=%d, c=%d, li=%d\n", left, c, li); */ - if (!(play_mode->encoding & PE_MONO)) + if (!(song->encoding & PE_MONO)) { - if (voice[v].panned==PANNED_MYSTERY) + if (song->voice[v].panned==PANNED_MYSTERY) { - left_rear = voice[v].lr_mix; - center=voice[v].ce_mix; - right=voice[v].right_mix; - right_rear = voice[v].rr_mix; - lfe = voice[v].lfe_mix; - + right=song->voice[v].right_mix; ri=-(right/c); while (c--) { - left_rear += li; if (left_rear<0) left_rear=0; - left += li; if (left<0) left=0; - center += li; if (center<0) center=0; - right += ri; if (right<0) right=0; - right_rear += ri; if (right_rear<0) right_rear=0; - lfe += li; if (lfe<0) lfe=0; + left += li; + if (left<0) + left=0; + right += ri; + if (right<0) + right=0; s=*sp++; - MIXATION(left); - MIXATION(right); - if (num_ochannels >= 4) { - MIXATION(left_rear); - MIXATION(right_rear); - } - if (num_ochannels == 6) { - MIXATION(center); - MIXATION(lfe); - } + MIXATION(left); + MIXATION(right); } } - else if (voice[v].panned==PANNED_CENTER) + else if (song->voice[v].panned==PANNED_CENTER) { while (c--) { @@ -710,27 +456,11 @@ static void ramp_out(resample_t *sp, int32 *lp, int v, int32 c) if (left<0) return; s=*sp++; - if (num_ochannels == 2) { - MIXATION(left); - MIXATION(left); - } - else if (num_ochannels == 4) { - MIXATION(left); - MIXATION(left); - MIXSKIP; - MIXSKIP; - } - else if (num_ochannels == 6) { - MIXSKIP; - MIXSKIP; - MIXSKIP; - MIXSKIP; - MIXATION(left); - MIXATION(left); - } + MIXATION(left); + MIXATION(left); } } - else if (voice[v].panned==PANNED_LEFT) + else if (song->voice[v].panned==PANNED_LEFT) { while (c--) { @@ -739,17 +469,10 @@ static void ramp_out(resample_t *sp, int32 *lp, int v, int32 c) return; s=*sp++; MIXATION(left); - MIXSKIP; - if (num_ochannels >= 4) { - MIXATION(left); - MIXSKIP; - } if (num_ochannels == 6) { - MIXATION(left); - MIXATION(left); - } + lp++; } } - else if (voice[v].panned==PANNED_RIGHT) + else if (song->voice[v].panned==PANNED_RIGHT) { while (c--) { @@ -757,15 +480,8 @@ static void ramp_out(resample_t *sp, int32 *lp, int v, int32 c) if (left<0) return; s=*sp++; - MIXSKIP; + lp++; MIXATION(left); - if (num_ochannels >= 4) { - MIXSKIP; - MIXATION(left); - } if (num_ochannels == 6) { - MIXATION(left); - MIXATION(left); - } } } } @@ -786,65 +502,55 @@ static void ramp_out(resample_t *sp, int32 *lp, int v, int32 c) /**************** interface function ******************/ -void mix_voice(int32 *buf, int v, int32 c) +void mix_voice(MidiSong *song, Sint32 *buf, int v, Sint32 c) { - Voice *vp=voice+v; - int32 count=c; - resample_t *sp; - if (c<0) return; + Voice *vp = song->voice + v; + sample_t *sp; if (vp->status==VOICE_DIE) { - if (count>=MAX_DIE_TIME) - count=MAX_DIE_TIME; - sp=resample_voice(v, &count); - ramp_out(sp, buf, v, count); + if (c>=MAX_DIE_TIME) + c=MAX_DIE_TIME; + sp=resample_voice(song, v, &c); + ramp_out(song, sp, buf, v, c); vp->status=VOICE_FREE; } else { - sp=resample_voice(v, &count); - if (count<0) return; - if (play_mode->encoding & PE_MONO) + sp=resample_voice(song, v, &c); + if (song->encoding & PE_MONO) { /* Mono output. */ if (vp->envelope_increment || vp->tremolo_phase_increment) - mix_mono_signal(sp, buf, v, count); + mix_mono_signal(song, sp, buf, v, c); else - mix_mono(sp, buf, v, count); + mix_mono(song, sp, buf, v, c); } else { if (vp->panned == PANNED_MYSTERY) { if (vp->envelope_increment || vp->tremolo_phase_increment) - mix_mystery_signal(sp, buf, v, count); + mix_mystery_signal(song, sp, buf, v, c); else - mix_mystery(sp, buf, v, count); + mix_mystery(song, sp, buf, v, c); } else if (vp->panned == PANNED_CENTER) { if (vp->envelope_increment || vp->tremolo_phase_increment) - mix_center_signal(sp, buf, v, count); + mix_center_signal(song, sp, buf, v, c); else - mix_center(sp, buf, v, count); + mix_center(song, sp, buf, v, c); } else { /* It's either full left or full right. In either case, every other sample is 0. Just get the offset right: */ + if (vp->panned == PANNED_RIGHT) buf++; if (vp->envelope_increment || vp->tremolo_phase_increment) - { - if (vp->panned == PANNED_RIGHT) - mix_single_right_signal(sp, buf, v, count); - else mix_single_left_signal(sp, buf, v, count); - } + mix_single_signal(song, sp, buf, v, c); else - { - if (vp->panned == PANNED_RIGHT) - mix_single_right(sp, buf, v, count); - else mix_single_left(sp, buf, v, count); - } + mix_single(song, sp, buf, v, c); } } } diff --git a/timidity/mix.h b/timidity/mix.h index 2f582b8a..be2a5f1f 100644 --- a/timidity/mix.h +++ b/timidity/mix.h @@ -1,11 +1,15 @@ /* + TiMidity -- Experimental MIDI to WAVE converter Copyright (C) 1995 Tuukka Toivonen This program is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License, available in COPYING. - */ -extern void mix_voice(int32 *buf, int v, int32 c); -extern int recompute_envelope(int v); -extern void apply_envelope_to_amp(int v); + mix.h + +*/ + +extern void mix_voice(MidiSong *song, Sint32 *buf, int v, Sint32 c); +extern int recompute_envelope(MidiSong *song, int v); +extern void apply_envelope_to_amp(MidiSong *song, int v); diff --git a/timidity/options.h b/timidity/options.h new file mode 100644 index 00000000..75893997 --- /dev/null +++ b/timidity/options.h @@ -0,0 +1,117 @@ +/* + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + This program is free software; you can redistribute it and/or modify + it under the terms of the Perl Artistic License, available in COPYING. +*/ + +/* When a patch file can't be opened, one of these extensions is + appended to the filename and the open is tried again. + */ +#define PATCH_EXT_LIST { ".pat", 0 } + +/* Acoustic Grand Piano seems to be the usual default instrument. */ +#define DEFAULT_PROGRAM 0 + +/* 9 here is MIDI channel 10, which is the standard percussion channel. + Some files (notably C:\WINDOWS\CANYON.MID) think that 16 is one too. + On the other hand, some files know that 16 is not a drum channel and + try to play music on it. This is now a runtime option, so this isn't + a critical choice anymore. */ +#define DEFAULT_DRUMCHANNELS (1<<9) + +/* In percent. */ +#define DEFAULT_AMPLIFICATION 70 + +/* Default polyphony */ +/* #define DEFAULT_VOICES 32 */ +#define DEFAULT_VOICES 256 + +/* 1000 here will give a control ratio of 22:1 with 22 kHz output. + Higher CONTROLS_PER_SECOND values allow more accurate rendering + of envelopes and tremolo. The cost is CPU time. */ +#define CONTROLS_PER_SECOND 1000 + +/* Make envelopes twice as fast. Saves ~20% CPU time (notes decay + faster) and sounds more like a GUS. There is now a command line + option to toggle this as well. */ +#define FAST_DECAY + +/* How many bits to use for the fractional part of sample positions. + This affects tonal accuracy. The entire position counter must fit + in 32 bits, so with FRACTION_BITS equal to 12, the maximum size of + a sample is 1048576 samples (2 megabytes in memory). The GUS gets + by with just 9 bits and a little help from its friends... + "The GUS does not SUCK!!!" -- a happy user :) */ +#define FRACTION_BITS 12 + +/* For some reason the sample volume is always set to maximum in all + patch files. Define this for a crude adjustment that may help + equalize instrument volumes. */ +#define ADJUST_SAMPLE_VOLUMES + +/* The number of samples to use for ramping out a dying note. Affects + click removal. */ +#define MAX_DIE_TIME 20 + +/**************************************************************************/ +/* Anything below this shouldn't need to be changed unless you're porting + to a new machine with other than 32-bit, big-endian words. */ +/**************************************************************************/ + +/* change FRACTION_BITS above, not these */ +#define INTEGER_MASK (0xFFFFFFFF << FRACTION_BITS) +#define FRACTION_MASK (~ INTEGER_MASK) + +/* This is enforced by some computations that must fit in an int */ +#define MAX_CONTROL_RATIO 255 + +#define MAX_AMPLIFICATION 800 + +/* You could specify a complete path, e.g. "/etc/timidity.cfg", and + then specify the library directory in the configuration file. */ +#define CONFIG_FILE "timidity.cfg" +#define CONFIG_FILE_ETC "/etc/timidity.cfg" +#define CONFIG_FILE_ETC_TIMIDITY_FREEPATS "/etc/timidity/freepats.cfg" + +#if defined(__WIN32__) || defined(__OS2__) +#define DEFAULT_PATH "C:\\TIMIDITY" +#else +#define DEFAULT_PATH "/etc/timidity" +#define DEFAULT_PATH1 "/usr/share/timidity" +#define DEFAULT_PATH2 "/usr/local/share/timidity" +#define DEFAULT_PATH3 "/usr/local/lib/timidity" +#endif + +/* These affect general volume */ +#define GUARD_BITS 3 +#define AMP_BITS (15-GUARD_BITS) + +#define MAX_AMP_VALUE ((1<<(AMP_BITS+1))-1) + +#define FSCALE(a,b) (float)((a) * (double)(1<<(b))) +#define FSCALENEG(a,b) (float)((a) * (1.0L / (double)(1<<(b)))) + +/* Vibrato and tremolo Choices of the Day */ +#define SWEEP_TUNING 38 +#define VIBRATO_AMPLITUDE_TUNING 1.0L +#define VIBRATO_RATE_TUNING 38 +#define TREMOLO_AMPLITUDE_TUNING 1.0L +#define TREMOLO_RATE_TUNING 38 + +#define SWEEP_SHIFT 16 +#define RATE_SHIFT 5 + +#ifndef PI + #define PI 3.14159265358979323846 +#endif + +/* The path separator (D.M.) */ +#if defined(__WIN32__) || defined(__OS2__) +# define PATH_SEP '\\' +#else +# define PATH_SEP '/' +#endif + +#define SNDDBG(X) diff --git a/timidity/output.c b/timidity/output.c index 5dab01f2..b62b635c 100644 --- a/timidity/output.c +++ b/timidity/output.c @@ -1,122 +1,102 @@ -/* +/* + TiMidity -- Experimental MIDI to WAVE converter Copyright (C) 1995 Tuukka Toivonen This program is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License, available in COPYING. - */ - -#include "config.h" -#include "output.h" -#include "tables.h" + output.c + + Audio output (to file / device) functions. +*/ -#ifdef SDL -extern PlayMode sdl_play_mode; -#define DEFAULT_PLAY_MODE &sdl_play_mode +#if HAVE_CONFIG_H +# include #endif -PlayMode *play_mode_list[] = { -#ifdef DEFAULT_PLAY_MODE - DEFAULT_PLAY_MODE, -#endif - 0 -}; +#include "SDL.h" -#ifdef DEFAULT_PLAY_MODE - PlayMode *play_mode=DEFAULT_PLAY_MODE; -#endif +#include "options.h" +#include "output.h" /*****************************************************************/ /* Some functions to convert signed 32-bit data to other formats */ -void s32tos8(void *dp, int32 *lp, int32 c) +void s32tos8(void *dp, Sint32 *lp, Sint32 c) { - int8 *cp=(int8 *)(dp); - int32 l; + Sint8 *cp=(Sint8 *)(dp); + Sint32 l; while (c--) { l=(*lp++)>>(32-8-GUARD_BITS); if (l>127) l=127; else if (l<-128) l=-128; - *cp++ = (int8) (l); + *cp++ = (Sint8) (l); } } -void s32tou8(void *dp, int32 *lp, int32 c) +void s32tou8(void *dp, Sint32 *lp, Sint32 c) { - uint8 *cp=(uint8 *)(dp); - int32 l; + Uint8 *cp=(Uint8 *)(dp); + Sint32 l; while (c--) { l=(*lp++)>>(32-8-GUARD_BITS); if (l>127) l=127; else if (l<-128) l=-128; - *cp++ = 0x80 ^ ((uint8) l); + *cp++ = 0x80 ^ ((Uint8) l); } } -void s32tos16(void *dp, int32 *lp, int32 c) +void s32tos16(void *dp, Sint32 *lp, Sint32 c) { - int16 *sp=(int16 *)(dp); - int32 l; + Sint16 *sp=(Sint16 *)(dp); + Sint32 l; while (c--) { l=(*lp++)>>(32-16-GUARD_BITS); if (l > 32767) l=32767; else if (l<-32768) l=-32768; - *sp++ = (int16)(l); + *sp++ = (Sint16)(l); } } -void s32tou16(void *dp, int32 *lp, int32 c) +void s32tou16(void *dp, Sint32 *lp, Sint32 c) { - uint16 *sp=(uint16 *)(dp); - int32 l; + Uint16 *sp=(Uint16 *)(dp); + Sint32 l; while (c--) { l=(*lp++)>>(32-16-GUARD_BITS); if (l > 32767) l=32767; else if (l<-32768) l=-32768; - *sp++ = 0x8000 ^ (uint16)(l); + *sp++ = 0x8000 ^ (Uint16)(l); } } -void s32tos16x(void *dp, int32 *lp, int32 c) +void s32tos16x(void *dp, Sint32 *lp, Sint32 c) { - int16 *sp=(int16 *)(dp); - int32 l; + Sint16 *sp=(Sint16 *)(dp); + Sint32 l; while (c--) { l=(*lp++)>>(32-16-GUARD_BITS); if (l > 32767) l=32767; else if (l<-32768) l=-32768; - *sp++ = XCHG_SHORT((int16)(l)); + *sp++ = SDL_Swap16((Sint16)(l)); } } -void s32tou16x(void *dp, int32 *lp, int32 c) +void s32tou16x(void *dp, Sint32 *lp, Sint32 c) { - uint16 *sp=(uint16 *)(dp); - int32 l; + Uint16 *sp=(Uint16 *)(dp); + Sint32 l; while (c--) { l=(*lp++)>>(32-16-GUARD_BITS); if (l > 32767) l=32767; else if (l<-32768) l=-32768; - *sp++ = XCHG_SHORT(0x8000 ^ (uint16)(l)); - } -} - -void s32toulaw(void *dp, int32 *lp, int32 c) -{ - uint8 *up=(uint8 *)(dp); - int32 l; - while (c--) - { - l=(*lp++)>>(32-13-GUARD_BITS); - if (l > 4095) l=4095; - else if (l<-4096) l=-4096; - *up++ = _l2u[l]; + *sp++ = SDL_Swap16(0x8000 ^ (Uint16)(l)); } } diff --git a/timidity/output.h b/timidity/output.h index 598792dd..e562a437 100644 --- a/timidity/output.h +++ b/timidity/output.h @@ -1,50 +1,35 @@ -/* +/* + TiMidity -- Experimental MIDI to WAVE converter Copyright (C) 1995 Tuukka Toivonen This program is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License, available in COPYING. - */ + + output.h + +*/ /* Data format encoding bits */ #define PE_MONO 0x01 /* versus stereo */ #define PE_SIGNED 0x02 /* versus unsigned */ #define PE_16BIT 0x04 /* versus 8-bit */ -#define PE_ULAW 0x08 /* versus linear */ -#define PE_BYTESWAP 0x10 /* versus the other way */ - -typedef struct { - int32 rate, encoding; - char *id_name; -} PlayMode; -extern PlayMode *play_mode_list[], *play_mode; -extern int init_buffers(int kbytes); - -/* Conversion functions -- These overwrite the int32 data in *lp with +/* Conversion functions -- These overwrite the Sint32 data in *lp with data in another format */ -/* The size of the output buffers */ -extern int AUDIO_BUFFER_SIZE; - -/* Actual copy function */ -extern void (*s32tobuf)(void *dp, int32 *lp, int32 c); - /* 8-bit signed and unsigned*/ -extern void s32tos8(void *dp, int32 *lp, int32 c); -extern void s32tou8(void *dp, int32 *lp, int32 c); +extern void s32tos8(void *dp, Sint32 *lp, Sint32 c); +extern void s32tou8(void *dp, Sint32 *lp, Sint32 c); /* 16-bit */ -extern void s32tos16(void *dp, int32 *lp, int32 c); -extern void s32tou16(void *dp, int32 *lp, int32 c); +extern void s32tos16(void *dp, Sint32 *lp, Sint32 c); +extern void s32tou16(void *dp, Sint32 *lp, Sint32 c); /* byte-exchanged 16-bit */ -extern void s32tos16x(void *dp, int32 *lp, int32 c); -extern void s32tou16x(void *dp, int32 *lp, int32 c); - -/* uLaw (8 bits) */ -extern void s32toulaw(void *dp, int32 *lp, int32 c); +extern void s32tos16x(void *dp, Sint32 *lp, Sint32 c); +extern void s32tou16x(void *dp, Sint32 *lp, Sint32 c); /* little-endian and big-endian specific */ #if SDL_BYTEORDER == SDL_LIL_ENDIAN diff --git a/timidity/playmidi.c b/timidity/playmidi.c index dd128044..d16f34b6 100644 --- a/timidity/playmidi.c +++ b/timidity/playmidi.c @@ -1,142 +1,73 @@ /* + TiMidity -- Experimental MIDI to WAVE converter Copyright (C) 1995 Tuukka Toivonen This program is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License, available in COPYING. - */ + + playmidi.c -- random stuff in need of rearrangement + +*/ + +#if HAVE_CONFIG_H +# include +#endif #include #include #include -#include +#include "SDL.h" -#include "config.h" -#include "common.h" +#include "timidity.h" +#include "options.h" #include "instrum.h" #include "playmidi.h" -#include "readmidi.h" #include "output.h" #include "mix.h" -#include "ctrlmode.h" -#include "timidity.h" - #include "tables.h" - -static int opt_expression_curve = 2; -static int opt_volume_curve = 2; -static int opt_stereo_surround = 0; - - -Channel channel[MAXCHAN]; -Voice voice[MAX_VOICES]; -signed char drumvolume[MAXCHAN][MAXNOTE]; -signed char drumpanpot[MAXCHAN][MAXNOTE]; -signed char drumreverberation[MAXCHAN][MAXNOTE]; -signed char drumchorusdepth[MAXCHAN][MAXNOTE]; - -int - voices=DEFAULT_VOICES; - -int32 - control_ratio=0, - amplification=DEFAULT_AMPLIFICATION; - -FLOAT_T - master_volume; - -int32 drumchannels=DEFAULT_DRUMCHANNELS; -int adjust_panning_immediately=0; - -struct _MidiSong { - int32 samples; - MidiEvent *events; -}; -static int midi_playing = 0; -static int32 lost_notes, cut_notes; -static int32 *buffer_pointer; -static int32 buffered_count; -extern int32 *common_buffer; -extern resample_t *resample_buffer; /* to free it on Timidity_Close */ - -static MidiEvent *event_list, *current_event; -static int32 sample_count, current_sample; - -int GM_System_On=0; -int XG_System_On=0; -int GS_System_On=0; -int XG_System_reverb_type; -int XG_System_chorus_type; -int XG_System_variation_type; - - -static void adjust_amplification(void) +static void adjust_amplification(MidiSong *song) { - master_volume = (FLOAT_T)(amplification) / (FLOAT_T)100.0; - master_volume /= 2; + song->master_volume = (float)(song->amplification) / (float)100.0; } - -static void adjust_master_volume(int32 vol) -{ - master_volume = (double)(vol*amplification) / 1638400.0L; - master_volume /= 2; -} - - -static void reset_voices(void) +static void reset_voices(MidiSong *song) { int i; for (i=0; ivoice[i].status=VOICE_FREE; } /* Process the Reset All Controllers event */ -static void reset_controllers(int c) +static void reset_controllers(MidiSong *song, int c) { - channel[c].volume=90; /* Some standard says, although the SCC docs say 0. */ - channel[c].expression=127; /* SCC-1 does this. */ - channel[c].sustain=0; - channel[c].pitchbend=0x2000; - channel[c].pitchfactor=0; /* to be computed */ - - channel[c].reverberation = 0; - channel[c].chorusdepth = 0; + song->channel[c].volume=90; /* Some standard says, although the SCC docs say 0. */ + song->channel[c].expression=127; /* SCC-1 does this. */ + song->channel[c].sustain=0; + song->channel[c].pitchbend=0x2000; + song->channel[c].pitchfactor=0; /* to be computed */ } -static void redraw_controllers(int c) -{ - ctl->volume(c, channel[c].volume); - ctl->expression(c, channel[c].expression); - ctl->sustain(c, channel[c].sustain); - ctl->pitch_bend(c, channel[c].pitchbend); -} - -static void reset_midi(void) +static void reset_midi(MidiSong *song) { int i; for (i=0; ichannel[i].program=song->default_program; + song->channel[i].panning=NO_PANNING; + song->channel[i].pitchsens=2; + song->channel[i].bank=0; /* tone bank or drum set */ } - reset_voices(); + reset_voices(song); } -static void select_sample(int v, Instrument *ip) +static void select_sample(MidiSong *song, int v, Instrument *ip, int vel) { - int32 f, cdiff, diff, midfreq; + Sint32 f, cdiff, diff; int s,i; Sample *sp, *closest; @@ -145,11 +76,22 @@ static void select_sample(int v, Instrument *ip) if (s==1) { - voice[v].sample=sp; + song->voice[v].sample=sp; return; } - f=voice[v].orig_frequency; + f=song->voice[v].orig_frequency; + for (i=0; ilow_vel <= vel && sp->high_vel >= vel && + sp->low_freq <= f && sp->high_freq >= f) + { + song->voice[v].sample=sp; + return; + } + sp++; + } + /* No suitable sample found! We'll select the sample whose root frequency is closest to the one we want. (Actually we should @@ -158,14 +100,9 @@ static void select_sample(int v, Instrument *ip) cdiff=0x7FFFFFFF; closest=sp=ip->sample; - midfreq = (sp->low_freq + sp->high_freq) / 2; for(i=0; iroot_freq - f; - /* But the root freq. can perfectly well lie outside the keyrange - * frequencies, so let's try: - */ - /* diff=midfreq - f; */ if (diff<0) diff=-diff; if (diffvoice[v].sample=closest; return; } - - -static void select_stereo_samples(int v, InstrumentLayer *lp) -{ - Instrument *ip; - InstrumentLayer *nlp, *bestvel; - int diffvel, midvel, mindiff; - -/* select closest velocity */ - bestvel = lp; - mindiff = 500; - for (nlp = lp; nlp; nlp = nlp->next) { - midvel = (nlp->hi + nlp->lo)/2; - if (!midvel) diffvel = 127; - else if (voice[v].velocity < nlp->lo || voice[v].velocity > nlp->hi) - diffvel = 200; - else diffvel = voice[v].velocity - midvel; - if (diffvel < 0) diffvel = -diffvel; - if (diffvel < mindiff) { - mindiff = diffvel; - bestvel = nlp; - } - } - ip = bestvel->instrument; - - if (ip->right_sample) { - ip->sample = ip->right_sample; - ip->samples = ip->right_samples; - select_sample(v, ip); - voice[v].right_sample = voice[v].sample; - } - else voice[v].right_sample = 0; - ip->sample = ip->left_sample; - ip->samples = ip->left_samples; - select_sample(v, ip); -} - - -static void recompute_freq(int v) +static void recompute_freq(MidiSong *song, int v) { int - sign=(voice[v].sample_increment < 0), /* for bidirectional loops */ - pb=channel[voice[v].channel].pitchbend; + sign=(song->voice[v].sample_increment < 0), /* for bidirectional loops */ + pb=song->channel[song->voice[v].channel].pitchbend; double a; - if (!voice[v].sample->sample_rate) + if (!song->voice[v].sample->sample_rate) return; - if (voice[v].vibrato_control_ratio) + if (song->voice[v].vibrato_control_ratio) { /* This instrument has vibrato. Invalidate any precomputed sample_increments. */ int i=VIBRATO_SAMPLE_INCREMENTS; while (i--) - voice[v].vibrato_sample_increment[i]=0; + song->voice[v].vibrato_sample_increment[i]=0; } if (pb==0x2000 || pb<0 || pb>0x3FFF) - voice[v].frequency=voice[v].orig_frequency; + song->voice[v].frequency = song->voice[v].orig_frequency; else { pb-=0x2000; - if (!(channel[voice[v].channel].pitchfactor)) + if (!(song->channel[song->voice[v].channel].pitchfactor)) { /* Damn. Somebody bent the pitch. */ - int32 i=pb*channel[voice[v].channel].pitchsens; + Sint32 i=pb*song->channel[song->voice[v].channel].pitchsens; if (pb<0) i=-i; - channel[voice[v].channel].pitchfactor= - (FLOAT_T)(bend_fine[(i>>5) & 0xFF] * bend_coarse[i>>13]); + song->channel[song->voice[v].channel].pitchfactor= + (float)(bend_fine[(i>>5) & 0xFF] * bend_coarse[i>>13]); } if (pb>0) - voice[v].frequency= - (int32)(channel[voice[v].channel].pitchfactor * - (double)(voice[v].orig_frequency)); + song->voice[v].frequency= + (Sint32)(song->channel[song->voice[v].channel].pitchfactor * + (double)(song->voice[v].orig_frequency)); else - voice[v].frequency= - (int32)((double)(voice[v].orig_frequency) / - channel[voice[v].channel].pitchfactor); + song->voice[v].frequency= + (Sint32)((double)(song->voice[v].orig_frequency) / + song->channel[song->voice[v].channel].pitchfactor); } - a = FSCALE(((double)(voice[v].sample->sample_rate) * - (double)(voice[v].frequency)) / - ((double)(voice[v].sample->root_freq) * - (double)(play_mode->rate)), + a = FSCALE(((double)(song->voice[v].sample->sample_rate) * + (double)(song->voice[v].frequency)) / + ((double)(song->voice[v].sample->root_freq) * + (double)(song->rate)), FRACTION_BITS); if (sign) a = -a; /* need to preserve the loop direction */ - voice[v].sample_increment = (int32)(a); + song->voice[v].sample_increment = (Sint32)(a); } -static int expr_curve[128] = { - 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 11, - 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 14, 14, 14, 14, 15, 15, - 15, 16, 16, 17, 17, 17, 18, 18, 19, 19, 19, 20, 20, 21, 21, 22, - 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 28, 28, 29, 30, 30, 31, - 32, 32, 33, 34, 35, 35, 36, 37, 38, 39, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 59, 60, 61, 63, - 64, 65, 67, 68, 70, 71, 73, 75, 76, 78, 80, 82, 83, 85, 87, 89, - 91, 93, 95, 97, 99, 102, 104, 106, 109, 111, 113, 116, 118, 121, - 124, 127 -}; - -static int panf(int pan, int speaker, int separation) +static void recompute_amp(MidiSong *song, int v) { - int val; - val = abs(pan - speaker); - val = (val * 127) / separation; - val = 127 - val; - if (val < 0) val = 0; - if (val > 127) val = 127; - return expr_curve[val]; -} - - -static int vcurve[128] = { -0,0,18,29,36,42,47,51,55,58, -60,63,65,67,69,71,73,74,76,77, -79,80,81,82,83,84,85,86,87,88, -89,90,91,92,92,93,94,95,95,96, -97,97,98,99,99,100,100,101,101,102, -103,103,104,104,105,105,106,106,106,107, -107,108,108,109,109,109,110,110,111,111, -111,112,112,112,113,113,114,114,114,115, -115,115,116,116,116,116,117,117,117,118, -118,118,119,119,119,119,120,120,120,120, -121,121,121,122,122,122,122,123,123,123, -123,123,124,124,124,124,125,125,125,125, -126,126,126,126,126,127,127,127 -}; - -static void recompute_amp(int v) -{ - int32 tempamp; - int chan = voice[v].channel; - int panning = voice[v].panning; - int vol = channel[chan].volume; - int expr = channel[chan].expression; - int vel = vcurve[voice[v].velocity]; - FLOAT_T curved_expression, curved_volume; - - if (channel[chan].kit) - { - int note = voice[v].sample->note_to_use; - if (note>0 && drumvolume[chan][note]>=0) vol = drumvolume[chan][note]; - if (note>0 && drumpanpot[chan][note]>=0) panning = drumpanpot[chan][note]; - } - - if (opt_expression_curve == 2) curved_expression = 127.0 * vol_table[expr]; - else if (opt_expression_curve == 1) curved_expression = 127.0 * expr_table[expr]; - else curved_expression = (FLOAT_T)expr; - - if (opt_volume_curve == 2) curved_volume = 127.0 * vol_table[vol]; - else if (opt_volume_curve == 1) curved_volume = 127.0 * expr_table[vol]; - else curved_volume = (FLOAT_T)vol; - - tempamp= (int32)((FLOAT_T)vel * curved_volume * curved_expression); /* 21 bits */ + Sint32 tempamp; /* TODO: use fscale */ - if (num_ochannels > 1) + tempamp= (song->voice[v].velocity * + song->channel[song->voice[v].channel].volume * + song->channel[song->voice[v].channel].expression); /* 21 bits */ + + if (!(song->encoding & PE_MONO)) { - if (panning > 60 && panning < 68) + if (song->voice[v].panning > 60 && song->voice[v].panning < 68) { - voice[v].panned=PANNED_CENTER; - - if (num_ochannels == 6) voice[v].left_amp = - FSCALENEG((double) (tempamp) * voice[v].sample->volume * - master_volume, 20); - else voice[v].left_amp= - FSCALENEG((double)(tempamp) * voice[v].sample->volume * - master_volume, 21); + song->voice[v].panned=PANNED_CENTER; + + song->voice[v].left_amp= + FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume, + 21); } - else if (panning<5) + else if (song->voice[v].panning<5) { - voice[v].panned = PANNED_LEFT; + song->voice[v].panned = PANNED_LEFT; - voice[v].left_amp= - FSCALENEG((double)(tempamp) * voice[v].sample->volume * master_volume, + song->voice[v].left_amp= + FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume, 20); } - else if (panning>123) + else if (song->voice[v].panning>123) { - voice[v].panned = PANNED_RIGHT; + song->voice[v].panned = PANNED_RIGHT; - voice[v].left_amp= /* left_amp will be used */ - FSCALENEG((double)(tempamp) * voice[v].sample->volume * master_volume, + song->voice[v].left_amp= /* left_amp will be used */ + FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume, 20); } else { - FLOAT_T refv = (double)(tempamp) * voice[v].sample->volume * master_volume; - int wide_panning = 64; - - if (num_ochannels == 4) wide_panning = 95; - - voice[v].panned = PANNED_MYSTERY; - voice[v].lfe_amp = FSCALENEG(refv * 64, 27); - - switch (num_ochannels) - { - case 2: - voice[v].lr_amp = 0; - voice[v].left_amp = FSCALENEG(refv * (128-panning), 27); - voice[v].ce_amp = 0; - voice[v].right_amp = FSCALENEG(refv * panning, 27); - voice[v].rr_amp = 0; - break; - case 4: - voice[v].lr_amp = FSCALENEG(refv * panf(panning, 0, wide_panning), 27); - voice[v].left_amp = FSCALENEG(refv * panf(panning, 32, wide_panning), 27); - voice[v].ce_amp = 0; - voice[v].right_amp = FSCALENEG(refv * panf(panning, 95, wide_panning), 27); - voice[v].rr_amp = FSCALENEG(refv * panf(panning, 128, wide_panning), 27); - break; - case 6: - voice[v].lr_amp = FSCALENEG(refv * panf(panning, 0, wide_panning), 27); - voice[v].left_amp = FSCALENEG(refv * panf(panning, 32, wide_panning), 27); - voice[v].ce_amp = FSCALENEG(refv * panf(panning, 64, wide_panning), 27); - voice[v].right_amp = FSCALENEG(refv * panf(panning, 95, wide_panning), 27); - voice[v].rr_amp = FSCALENEG(refv * panf(panning, 128, wide_panning), 27); - break; - } + song->voice[v].panned = PANNED_MYSTERY; + song->voice[v].left_amp= + FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume, + 27); + song->voice[v].right_amp = song->voice[v].left_amp * (song->voice[v].panning); + song->voice[v].left_amp *= (float)(127 - song->voice[v].panning); } } else { - voice[v].panned=PANNED_CENTER; + song->voice[v].panned = PANNED_CENTER; - voice[v].left_amp= - FSCALENEG((double)(tempamp) * voice[v].sample->volume * master_volume, + song->voice[v].left_amp= + FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume, 21); } } - -#define NOT_CLONE 0 -#define STEREO_CLONE 1 -#define REVERB_CLONE 2 -#define CHORUS_CLONE 3 - - -/* just a variant of note_on() */ -static int vc_alloc(int j) -{ - int i=voices; - - while (i--) - { - if (i == j) continue; - if (voice[i].status & VOICE_FREE) { - return i; - } - } - return -1; -} - -static void kill_note(int i); - -static void kill_others(int i) -{ - int j=voices; - - if (!voice[i].sample->exclusiveClass) return; - - while (j--) - { - if (voice[j].status & (VOICE_FREE|VOICE_OFF|VOICE_DIE)) continue; - if (i == j) continue; - if (voice[i].channel != voice[j].channel) continue; - if (voice[j].sample->note_to_use) - { - if (voice[j].sample->exclusiveClass != voice[i].sample->exclusiveClass) continue; - kill_note(j); - } - } -} - - -static void clone_voice(Instrument *ip, int v, MidiEvent *e, int clone_type, int variationbank) -{ - int w, played_note, chorus=0, reverb=0, milli; - int chan = voice[v].channel; - - if (clone_type == STEREO_CLONE) { - if (!voice[v].right_sample && variationbank != 3) return; - if (variationbank == 6) return; - } - - if (channel[chan].kit) { - reverb = drumreverberation[chan][voice[v].note]; - chorus = drumchorusdepth[chan][voice[v].note]; - } - else { - reverb = channel[chan].reverberation; - chorus = channel[chan].chorusdepth; - } - - if (clone_type == REVERB_CLONE) chorus = 0; - else if (clone_type == CHORUS_CLONE) reverb = 0; - else if (clone_type == STEREO_CLONE) reverb = chorus = 0; - - if (reverb > 127) reverb = 127; - if (chorus > 127) chorus = 127; - - if (clone_type == CHORUS_CLONE) { - if (variationbank == 32) chorus = 30; - else if (variationbank == 33) chorus = 60; - else if (variationbank == 34) chorus = 90; - } - - chorus /= 2; /* This is an ad hoc adjustment. */ - - if (!reverb && !chorus && clone_type != STEREO_CLONE) return; - - if ( (w = vc_alloc(v)) < 0 ) return; - - voice[w] = voice[v]; - if (clone_type==STEREO_CLONE) voice[v].clone_voice = w; - voice[w].clone_voice = v; - voice[w].clone_type = clone_type; - - voice[w].sample = voice[v].right_sample; - voice[w].velocity= e->b; - - milli = play_mode->rate/1000; - - if (clone_type == STEREO_CLONE) { - int left, right, leftpan, rightpan; - int panrequest = voice[v].panning; - if (variationbank == 3) { - voice[v].panning = 0; - voice[w].panning = 127; - } - else { - if (voice[v].sample->panning > voice[w].sample->panning) { - left = w; - right = v; - } - else { - left = v; - right = w; - } -#define INSTRUMENT_SEPARATION 12 - leftpan = panrequest - INSTRUMENT_SEPARATION / 2; - rightpan = leftpan + INSTRUMENT_SEPARATION; - if (leftpan < 0) { - leftpan = 0; - rightpan = leftpan + INSTRUMENT_SEPARATION; - } - if (rightpan > 127) { - rightpan = 127; - leftpan = rightpan - INSTRUMENT_SEPARATION; - } - voice[left].panning = leftpan; - voice[right].panning = rightpan; - voice[right].echo_delay = 20 * milli; - } - } - - voice[w].volume = voice[w].sample->volume; - - if (reverb) { - if (opt_stereo_surround) { - if (voice[w].panning > 64) voice[w].panning = 127; - else voice[w].panning = 0; - } - else { - if (voice[v].panning < 64) voice[w].panning = 64 + reverb/2; - else voice[w].panning = 64 - reverb/2; - } - -/* try 98->99 for melodic instruments ? (bit much for percussion) */ - voice[w].volume *= vol_table[(127-reverb)/8 + 98]; - - voice[w].echo_delay += reverb * milli; - voice[w].envelope_rate[DECAY] *= 2; - voice[w].envelope_rate[RELEASE] /= 2; - - if (XG_System_reverb_type >= 0) { - int subtype = XG_System_reverb_type & 0x07; - int rtype = XG_System_reverb_type >>3; - switch (rtype) { - case 0: /* no effect */ - break; - case 1: /* hall */ - if (subtype) voice[w].echo_delay += 100 * milli; - break; - case 2: /* room */ - voice[w].echo_delay /= 2; - break; - case 3: /* stage */ - voice[w].velocity = voice[v].velocity; - break; - case 4: /* plate */ - voice[w].panning = voice[v].panning; - break; - case 16: /* white room */ - voice[w].echo_delay = 0; - break; - case 17: /* tunnel */ - voice[w].echo_delay *= 2; - voice[w].velocity /= 2; - break; - case 18: /* canyon */ - voice[w].echo_delay *= 2; - break; - case 19: /* basement */ - voice[w].velocity /= 2; - break; - default: break; - } - } - } - played_note = voice[w].sample->note_to_use; - if (!played_note) { - played_note = e->a & 0x7f; - if (variationbank == 35) played_note += 12; - else if (variationbank == 36) played_note -= 12; - else if (variationbank == 37) played_note += 7; - else if (variationbank == 36) played_note -= 7; - } -#if 0 - played_note = ( (played_note - voice[w].sample->freq_center) * voice[w].sample->freq_scale ) / 1024 + - voice[w].sample->freq_center; -#endif - voice[w].note = played_note; - voice[w].orig_frequency = freq_table[played_note]; - - if (chorus) { - if (opt_stereo_surround) { - if (voice[v].panning < 64) voice[w].panning = voice[v].panning + 32; - else voice[w].panning = voice[v].panning - 32; - } - - if (!voice[w].vibrato_control_ratio) { - voice[w].vibrato_control_ratio = 100; - voice[w].vibrato_depth = 6; - voice[w].vibrato_sweep = 74; - } - voice[w].volume *= 0.40; - voice[v].volume = voice[w].volume; - recompute_amp(v); - apply_envelope_to_amp(v); - voice[w].vibrato_sweep = chorus/2; - voice[w].vibrato_depth /= 2; - if (!voice[w].vibrato_depth) voice[w].vibrato_depth = 2; - voice[w].vibrato_control_ratio /= 2; - voice[w].echo_delay += 30 * milli; - - if (XG_System_chorus_type >= 0) { - int subtype = XG_System_chorus_type & 0x07; - int chtype = 0x0f & (XG_System_chorus_type >> 3); - switch (chtype) { - case 0: /* no effect */ - break; - case 1: /* chorus */ - chorus /= 3; - if(channel[ voice[w].channel ].pitchbend + chorus < 0x2000) - voice[w].orig_frequency = - (uint32)( (FLOAT_T)voice[w].orig_frequency * bend_fine[chorus] ); - else voice[w].orig_frequency = - (uint32)( (FLOAT_T)voice[w].orig_frequency / bend_fine[chorus] ); - if (subtype) voice[w].vibrato_depth *= 2; - break; - case 2: /* celeste */ - voice[w].orig_frequency += (voice[w].orig_frequency/128) * chorus; - break; - case 3: /* flanger */ - voice[w].vibrato_control_ratio = 10; - voice[w].vibrato_depth = 100; - voice[w].vibrato_sweep = 8; - voice[w].echo_delay += 200 * milli; - break; - case 4: /* symphonic : cf Children of the Night /128 bad, /1024 ok */ - voice[w].orig_frequency += (voice[w].orig_frequency/512) * chorus; - voice[v].orig_frequency -= (voice[v].orig_frequency/512) * chorus; - recompute_freq(v); - break; - case 8: /* phaser */ - break; - default: - break; - } - } - else { - chorus /= 3; - if(channel[ voice[w].channel ].pitchbend + chorus < 0x2000) - voice[w].orig_frequency = - (uint32)( (FLOAT_T)voice[w].orig_frequency * bend_fine[chorus] ); - else voice[w].orig_frequency = - (uint32)( (FLOAT_T)voice[w].orig_frequency / bend_fine[chorus] ); - } - } -#if 0 - voice[w].loop_start = voice[w].sample->loop_start; - voice[w].loop_end = voice[w].sample->loop_end; -#endif - voice[w].echo_delay_count = voice[w].echo_delay; - if (reverb) voice[w].echo_delay *= 2; - - recompute_freq(w); - recompute_amp(w); - if (voice[w].sample->modes & MODES_ENVELOPE) - { - /* Ramp up from 0 */ - voice[w].envelope_stage=ATTACK; - voice[w].modulation_stage=ATTACK; - voice[w].envelope_volume=0; - voice[w].modulation_volume=0; - voice[w].control_counter=0; - voice[w].modulation_counter=0; - recompute_envelope(w); - /*recompute_modulation(w);*/ - } - else - { - voice[w].envelope_increment=0; - voice[w].modulation_increment=0; - } - apply_envelope_to_amp(w); -} - - -static void xremap(int *banknumpt, int *this_notept, int this_kit) { - int i, newmap; - int banknum = *banknumpt; - int this_note = *this_notept; - int newbank, newnote; - - if (!this_kit) { - if (banknum == SFXBANK && tonebank[SFXBANK]) return; - if (banknum == SFXBANK && tonebank[120]) *banknumpt = 120; - return; - } - - if (this_kit != 127 && this_kit != 126) return; - - for (i = 0; i < XMAPMAX; i++) { - newmap = xmap[i][0]; - if (!newmap) return; - if (this_kit == 127 && newmap != XGDRUM) continue; - if (this_kit == 126 && newmap != SFXDRUM1) continue; - if (xmap[i][1] != banknum) continue; - if (xmap[i][3] != this_note) continue; - newbank = xmap[i][2]; - newnote = xmap[i][4]; - if (newbank == banknum && newnote == this_note) return; - if (!drumset[newbank]) return; - if (!drumset[newbank]->tone[newnote].layer) return; - if (drumset[newbank]->tone[newnote].layer == MAGIC_LOAD_INSTRUMENT) return; - *banknumpt = newbank; - *this_notept = newnote; - return; - } -} - - -static void start_note(MidiEvent *e, int i) +static void start_note(MidiSong *song, MidiEvent *e, int i) { - InstrumentLayer *lp; Instrument *ip; - int j, banknum, ch=e->channel; - int played_note, drumpan=NO_PANNING; - int32 rt; - int attacktime, releasetime, decaytime, variationbank; - int brightness = channel[ch].brightness; - int harmoniccontent = channel[ch].harmoniccontent; - int this_note = e->a; - int this_velocity = e->b; - int drumsflag = channel[ch].kit; - int this_prog = channel[ch].program; - - if (channel[ch].sfx) banknum=channel[ch].sfx; - else banknum=channel[ch].bank; - - voice[i].velocity=this_velocity; - - if (XG_System_On) xremap(&banknum, &this_note, drumsflag); - /* if (current_config_pc42b) pcmap(&banknum, &this_note, &this_prog, &drumsflag); */ - - if (drumsflag) + int j; + + if (ISDRUMCHANNEL(song, e->channel)) { - if (!(lp=drumset[banknum]->tone[this_note].layer)) + if (!(ip=song->drumset[song->channel[e->channel].bank]->instrument[e->a])) { - if (!(lp=drumset[0]->tone[this_note].layer)) + if (!(ip=song->drumset[0]->instrument[e->a])) return; /* No instrument? Then we can't play. */ } - ip = lp->instrument; - if (ip->type == INST_GUS && ip->samples != 1) + if (ip->samples != 1) { - ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, - "Strange: percussion instrument with %d samples!", ip->samples); + SNDDBG(("Strange: percussion instrument with %d samples!", + ip->samples)); } if (ip->sample->note_to_use) /* Do we have a fixed pitch? */ - { - voice[i].orig_frequency=freq_table[(int)(ip->sample->note_to_use)]; - drumpan=drumpanpot[ch][(int)ip->sample->note_to_use]; - } + song->voice[i].orig_frequency = freq_table[(int)(ip->sample->note_to_use)]; else - voice[i].orig_frequency=freq_table[this_note & 0x7F]; - + song->voice[i].orig_frequency = freq_table[e->a & 0x7F]; + + /* drums are supposed to have only one sample */ + song->voice[i].sample = ip->sample; } else { - if (channel[ch].program==SPECIAL_PROGRAM) - lp=default_instrument; - else if (!(lp=tonebank[channel[ch].bank]-> - tone[channel[ch].program].layer)) + if (song->channel[e->channel].program == SPECIAL_PROGRAM) + ip=song->default_instrument; + else if (!(ip=song->tonebank[song->channel[e->channel].bank]-> + instrument[song->channel[e->channel].program])) { - if (!(lp=tonebank[0]->tone[this_prog].layer)) + if (!(ip=song->tonebank[0]->instrument[song->channel[e->channel].program])) return; /* No instrument? Then we can't play. */ } - ip = lp->instrument; + if (ip->sample->note_to_use) /* Fixed-pitch instrument? */ - voice[i].orig_frequency=freq_table[(int)(ip->sample->note_to_use)]; + song->voice[i].orig_frequency = freq_table[(int)(ip->sample->note_to_use)]; else - voice[i].orig_frequency=freq_table[this_note & 0x7F]; - } - - select_stereo_samples(i, lp); - - voice[i].starttime = e->time; - played_note = voice[i].sample->note_to_use; - - if (!played_note || !drumsflag) played_note = this_note & 0x7f; -#if 0 - played_note = ( (played_note - voice[i].sample->freq_center) * voice[i].sample->freq_scale ) / 1024 + - voice[i].sample->freq_center; -#endif - voice[i].status=VOICE_ON; - voice[i].channel=ch; - voice[i].note=played_note; - voice[i].velocity=this_velocity; - voice[i].sample_offset=0; - voice[i].sample_increment=0; /* make sure it isn't negative */ - - voice[i].tremolo_phase=0; - voice[i].tremolo_phase_increment=voice[i].sample->tremolo_phase_increment; - voice[i].tremolo_sweep=voice[i].sample->tremolo_sweep_increment; - voice[i].tremolo_sweep_position=0; - - voice[i].vibrato_sweep=voice[i].sample->vibrato_sweep_increment; - voice[i].vibrato_sweep_position=0; - voice[i].vibrato_depth=voice[i].sample->vibrato_depth; - voice[i].vibrato_control_ratio=voice[i].sample->vibrato_control_ratio; - voice[i].vibrato_control_counter=voice[i].vibrato_phase=0; - voice[i].vibrato_delay = voice[i].sample->vibrato_delay; - - kill_others(i); - + song->voice[i].orig_frequency = freq_table[e->a & 0x7F]; + select_sample(song, i, ip, e->b); + } + + song->voice[i].status = VOICE_ON; + song->voice[i].channel = e->channel; + song->voice[i].note = e->a; + song->voice[i].velocity = e->b; + song->voice[i].sample_offset = 0; + song->voice[i].sample_increment = 0; /* make sure it isn't negative */ + + song->voice[i].tremolo_phase = 0; + song->voice[i].tremolo_phase_increment = song->voice[i].sample->tremolo_phase_increment; + song->voice[i].tremolo_sweep = song->voice[i].sample->tremolo_sweep_increment; + song->voice[i].tremolo_sweep_position = 0; + + song->voice[i].vibrato_sweep = song->voice[i].sample->vibrato_sweep_increment; + song->voice[i].vibrato_sweep_position = 0; + song->voice[i].vibrato_control_ratio = song->voice[i].sample->vibrato_control_ratio; + song->voice[i].vibrato_control_counter = song->voice[i].vibrato_phase = 0; for (j=0; jcutoff_freq = 800; - break; - case 25: - voice[i].modEnvToFilterFc=-2.0; - voice[i].sample->cutoff_freq = 800; - break; - case 27: - voice[i].modLfoToFilterFc=2.0; - voice[i].lfo_phase_increment=109; - voice[i].lfo_sweep=122; - voice[i].sample->cutoff_freq = 800; - break; - case 28: - voice[i].modLfoToFilterFc=-2.0; - voice[i].lfo_phase_increment=109; - voice[i].lfo_sweep=122; - voice[i].sample->cutoff_freq = 800; - break; -#endif - default: - break; - } - - - for (j=ATTACK; jenvelope_rate[j]; - voice[i].envelope_offset[j]=voice[i].sample->envelope_offset[j]; - } - - voice[i].echo_delay=voice[i].envelope_rate[DELAY]; - voice[i].echo_delay_count = voice[i].echo_delay; - - if (attacktime!=64) - { - rt = voice[i].envelope_rate[ATTACK]; - rt = rt + ( (64-attacktime)*rt ) / 100; - if (rt > 1000) voice[i].envelope_rate[ATTACK] = rt; - } - if (releasetime!=64) - { - rt = voice[i].envelope_rate[RELEASE]; - rt = rt + ( (64-releasetime)*rt ) / 100; - if (rt > 1000) voice[i].envelope_rate[RELEASE] = rt; - } - if (decaytime!=64) - { - rt = voice[i].envelope_rate[DECAY]; - rt = rt + ( (64-decaytime)*rt ) / 100; - if (rt > 1000) voice[i].envelope_rate[DECAY] = rt; - } + song->voice[i].vibrato_sample_increment[j] = 0; - if (channel[ch].panning != NO_PANNING) - voice[i].panning=channel[ch].panning; + if (song->channel[e->channel].panning != NO_PANNING) + song->voice[i].panning = song->channel[e->channel].panning; else - voice[i].panning=voice[i].sample->panning; - if (drumpan != NO_PANNING) - voice[i].panning=drumpan; - - if (variationbank == 1) { - int pan = voice[i].panning; - int disturb = 0; - /* If they're close up (no reverb) and you are behind the pianist, - * high notes come from the right, so we'll spread piano etc. notes - * out horizontally according to their pitches. - */ - if (this_prog < 21) { - int n = voice[i].velocity - 32; - if (n < 0) n = 0; - if (n > 64) n = 64; - pan = pan/2 + n; - } - /* For other types of instruments, the music sounds more alive if - * notes come from slightly different directions. However, instruments - * do drift around in a sometimes disconcerting way, so the following - * might not be such a good idea. - */ - else disturb = (voice[i].velocity/32 % 8) + - (voice[i].note % 8); /* /16? */ - - if (pan < 64) pan += disturb; - else pan -= disturb; - if (pan < 0) pan = 0; - else if (pan > 127) pan = 127; - voice[i].panning = pan; - } + song->voice[i].panning = song->voice[i].sample->panning; - recompute_freq(i); - recompute_amp(i); - if (voice[i].sample->modes & MODES_ENVELOPE) + recompute_freq(song, i); + recompute_amp(song, i); + if (song->voice[i].sample->modes & MODES_ENVELOPE) { /* Ramp up from 0 */ - voice[i].envelope_stage=ATTACK; - voice[i].envelope_volume=0; - voice[i].control_counter=0; - recompute_envelope(i); + song->voice[i].envelope_stage = 0; + song->voice[i].envelope_volume = 0; + song->voice[i].control_counter = 0; + recompute_envelope(song, i); + apply_envelope_to_amp(song, i); } else { - voice[i].envelope_increment=0; + song->voice[i].envelope_increment = 0; + apply_envelope_to_amp(song, i); } - apply_envelope_to_amp(i); - - voice[i].clone_voice = -1; - voice[i].clone_type = NOT_CLONE; - - clone_voice(ip, i, e, STEREO_CLONE, variationbank); - clone_voice(ip, i, e, CHORUS_CLONE, variationbank); - clone_voice(ip, i, e, REVERB_CLONE, variationbank); - - ctl->note(i); } -static void kill_note(int i) +static void kill_note(MidiSong *song, int i) { - voice[i].status=VOICE_DIE; - if (voice[i].clone_voice >= 0) - voice[ voice[i].clone_voice ].status=VOICE_DIE; - ctl->note(i); + song->voice[i].status = VOICE_DIE; } - /* Only one instance of a note can be playing on a single channel. */ -static void note_on(MidiEvent *e) +static void note_on(MidiSong *song) { - int i=voices, lowest=-1; - int32 lv=0x7FFFFFFF, v; + int i = song->voices, lowest=-1; + Sint32 lv=0x7FFFFFFF, v; + MidiEvent *e = song->current_event; while (i--) { - if (voice[i].status == VOICE_FREE) + if (song->voice[i].status == VOICE_FREE) lowest=i; /* Can't get a lower volume than silence */ - else if (voice[i].channel==e->channel && - (voice[i].note==e->a || channel[voice[i].channel].mono)) - kill_note(i); + else if (song->voice[i].channel==e->channel && + (song->voice[i].note==e->a || song->channel[song->voice[i].channel].mono)) + kill_note(song, i); } if (lowest != -1) { /* Found a free voice. */ - start_note(e,lowest); + start_note(song,e,lowest); return; } -#if 0 /* Look for the decaying note with the lowest volume */ - i=voices; + i = song->voices; while (i--) { - if (voice[i].status & ~(VOICE_ON | VOICE_DIE | VOICE_FREE)) + if ((song->voice[i].status != VOICE_ON) && + (song->voice[i].status != VOICE_DIE)) { - v=voice[i].left_mix; - if ((voice[i].panned==PANNED_MYSTERY) && (voice[i].right_mix>v)) - v=voice[i].right_mix; + v = song->voice[i].left_mix; + if ((song->voice[i].panned == PANNED_MYSTERY) + && (song->voice[i].right_mix > v)) + v = song->voice[i].right_mix; if (vv)) - v=voice[i].right_mix; - if (v= 0) { - if (voice[cl].clone_type==STEREO_CLONE || - (!voice[cl].clone_type && voice[lowest].clone_type==STEREO_CLONE)) - voice[cl].status=VOICE_FREE; - else if (voice[cl].clone_voice==lowest) voice[cl].clone_voice=-1; - } - - cut_notes++; - voice[lowest].status=VOICE_FREE; - ctl->note(lowest); - start_note(e,lowest); + + song->cut_notes++; + song->voice[lowest].status=VOICE_FREE; + start_note(song,e,lowest); } else - lost_notes++; + song->lost_notes++; } -static void finish_note(int i) +static void finish_note(MidiSong *song, int i) { - if (voice[i].sample->modes & MODES_ENVELOPE) + if (song->voice[i].sample->modes & MODES_ENVELOPE) { /* We need to get the envelope out of Sustain stage */ - voice[i].envelope_stage=3; - voice[i].status=VOICE_OFF; - recompute_envelope(i); - apply_envelope_to_amp(i); - ctl->note(i); + song->voice[i].envelope_stage = 3; + song->voice[i].status = VOICE_OFF; + recompute_envelope(song, i); + apply_envelope_to_amp(song, i); } else { /* Set status to OFF so resample_voice() will let this voice out of its loop, if any. In any case, this voice dies when it hits the end of its data (ofs>=data_length). */ - voice[i].status=VOICE_OFF; + song->voice[i].status = VOICE_OFF; } - - { int v; - if ( (v=voice[i].clone_voice) >= 0) - { - voice[i].clone_voice = -1; - finish_note(v); - } - } } -static void note_off(MidiEvent *e) +static void note_off(MidiSong *song) { - int i=voices, v; + int i = song->voices; + MidiEvent *e = song->current_event; + while (i--) - if (voice[i].status==VOICE_ON && - voice[i].channel==e->channel && - voice[i].note==e->a) + if (song->voice[i].status == VOICE_ON && + song->voice[i].channel == e->channel && + song->voice[i].note == e->a) { - if (channel[e->channel].sustain) + if (song->channel[e->channel].sustain) { - voice[i].status=VOICE_SUSTAINED; - - if ( (v=voice[i].clone_voice) >= 0) - { - if (voice[v].status == VOICE_ON) - voice[v].status=VOICE_SUSTAINED; - } - - ctl->note(i); + song->voice[i].status = VOICE_SUSTAINED; } else - finish_note(i); + finish_note(song, i); return; } } /* Process the All Notes Off event */ -static void all_notes_off(int c) +static void all_notes_off(MidiSong *song) { - int i=voices; - ctl->cmsg(CMSG_INFO, VERB_DEBUG, "All notes off on channel %d", c); + int i = song->voices; + int c = song->current_event->channel; + + SNDDBG(("All notes off on channel %d", c)); while (i--) - if (voice[i].status==VOICE_ON && - voice[i].channel==c) + if (song->voice[i].status == VOICE_ON && + song->voice[i].channel == c) { - if (channel[c].sustain) - { - voice[i].status=VOICE_SUSTAINED; - ctl->note(i); - } + if (song->channel[c].sustain) + song->voice[i].status = VOICE_SUSTAINED; else - finish_note(i); + finish_note(song, i); } } /* Process the All Sounds Off event */ -static void all_sounds_off(int c) +static void all_sounds_off(MidiSong *song) { - int i=voices; + int i = song->voices; + int c = song->current_event->channel; + while (i--) - if (voice[i].channel==c && - voice[i].status != VOICE_FREE && - voice[i].status != VOICE_DIE) + if (song->voice[i].channel == c && + song->voice[i].status != VOICE_FREE && + song->voice[i].status != VOICE_DIE) { - kill_note(i); + kill_note(song, i); } } -static void adjust_pressure(MidiEvent *e) +static void adjust_pressure(MidiSong *song) { - int i=voices; + MidiEvent *e = song->current_event; + int i = song->voices; + while (i--) - if (voice[i].status==VOICE_ON && - voice[i].channel==e->channel && - voice[i].note==e->a) + if (song->voice[i].status == VOICE_ON && + song->voice[i].channel == e->channel && + song->voice[i].note == e->a) { - voice[i].velocity=e->b; - recompute_amp(i); - apply_envelope_to_amp(i); + song->voice[i].velocity = e->b; + recompute_amp(song, i); + apply_envelope_to_amp(song, i); return; } } -static void adjust_panning(int c) +static void drop_sustain(MidiSong *song) { - int i=voices; - while (i--) - if ((voice[i].channel==c) && - (voice[i].status==VOICE_ON || voice[i].status==VOICE_SUSTAINED)) - { - if (voice[i].clone_type != NOT_CLONE) continue; - voice[i].panning=channel[c].panning; - recompute_amp(i); - apply_envelope_to_amp(i); - } -} + int i = song->voices; + int c = song->current_event->channel; -static void drop_sustain(int c) -{ - int i=voices; while (i--) - if (voice[i].status==VOICE_SUSTAINED && voice[i].channel==c) - finish_note(i); + if (song->voice[i].status == VOICE_SUSTAINED && song->voice[i].channel == c) + finish_note(song, i); } -static void adjust_pitchbend(int c) +static void adjust_pitchbend(MidiSong *song) { - int i=voices; + int c = song->current_event->channel; + int i = song->voices; + while (i--) - if (voice[i].status!=VOICE_FREE && voice[i].channel==c) + if (song->voice[i].status != VOICE_FREE && song->voice[i].channel == c) { - recompute_freq(i); + recompute_freq(song, i); } } -static void adjust_volume(int c) +static void adjust_volume(MidiSong *song) { - int i=voices; + int c = song->current_event->channel; + int i = song->voices; + while (i--) - if (voice[i].channel==c && - (voice[i].status==VOICE_ON || voice[i].status==VOICE_SUSTAINED)) + if (song->voice[i].channel == c && + (song->voice[i].status==VOICE_ON || song->voice[i].status==VOICE_SUSTAINED)) { - recompute_amp(i); - apply_envelope_to_amp(i); + recompute_amp(song, i); + apply_envelope_to_amp(song, i); } } -static void seek_forward(int32 until_time) +static void seek_forward(MidiSong *song, Sint32 until_time) { - reset_voices(); - while (current_event->time < until_time) + reset_voices(song); + while (song->current_event->time < until_time) { - switch(current_event->type) + switch(song->current_event->type) { /* All notes stay off. Just handle the parameter changes. */ case ME_PITCH_SENS: - channel[current_event->channel].pitchsens= - current_event->a; - channel[current_event->channel].pitchfactor=0; + song->channel[song->current_event->channel].pitchsens = + song->current_event->a; + song->channel[song->current_event->channel].pitchfactor = 0; break; case ME_PITCHWHEEL: - channel[current_event->channel].pitchbend= - current_event->a + current_event->b * 128; - channel[current_event->channel].pitchfactor=0; + song->channel[song->current_event->channel].pitchbend = + song->current_event->a + song->current_event->b * 128; + song->channel[song->current_event->channel].pitchfactor = 0; break; case ME_MAINVOLUME: - channel[current_event->channel].volume=current_event->a; - break; - - case ME_MASTERVOLUME: - adjust_master_volume(current_event->a + (current_event->b <<7)); + song->channel[song->current_event->channel].volume = + song->current_event->a; break; case ME_PAN: - channel[current_event->channel].panning=current_event->a; + song->channel[song->current_event->channel].panning = + song->current_event->a; break; case ME_EXPRESSION: - channel[current_event->channel].expression=current_event->a; + song->channel[song->current_event->channel].expression = + song->current_event->a; break; case ME_PROGRAM: - /* if (ISDRUMCHANNEL(current_event->channel)) */ - if (channel[current_event->channel].kit) + if (ISDRUMCHANNEL(song, song->current_event->channel)) /* Change drum set */ - channel[current_event->channel].bank=current_event->a; + song->channel[song->current_event->channel].bank = + song->current_event->a; else - channel[current_event->channel].program=current_event->a; + song->channel[song->current_event->channel].program = + song->current_event->a; break; case ME_SUSTAIN: - channel[current_event->channel].sustain=current_event->a; - break; - - - case ME_REVERBERATION: - channel[current_event->channel].reverberation=current_event->a; - break; - - case ME_CHORUSDEPTH: - channel[current_event->channel].chorusdepth=current_event->a; - break; - - case ME_HARMONICCONTENT: - channel[current_event->channel].harmoniccontent=current_event->a; - break; - - case ME_RELEASETIME: - channel[current_event->channel].releasetime=current_event->a; - break; - - case ME_ATTACKTIME: - channel[current_event->channel].attacktime=current_event->a; - break; - - case ME_BRIGHTNESS: - channel[current_event->channel].brightness=current_event->a; + song->channel[song->current_event->channel].sustain = + song->current_event->a; break; - case ME_TONE_KIT: - if (current_event->a==SFX_BANKTYPE) - { - channel[current_event->channel].sfx=SFXBANK; - channel[current_event->channel].kit=0; - } - else - { - channel[current_event->channel].sfx=0; - channel[current_event->channel].kit=current_event->a; - } - break; - - case ME_RESET_CONTROLLERS: - reset_controllers(current_event->channel); + reset_controllers(song, song->current_event->channel); break; case ME_TONE_BANK: - channel[current_event->channel].bank=current_event->a; + song->channel[song->current_event->channel].bank = + song->current_event->a; break; case ME_EOT: - current_sample=current_event->time; + song->current_sample = song->current_event->time; return; } - current_event++; + song->current_event++; } - /*current_sample=current_event->time;*/ - if (current_event != event_list) - current_event--; - current_sample=until_time; + /*song->current_sample=song->current_event->time;*/ + if (song->current_event != song->events) + song->current_event--; + song->current_sample=until_time; } -static void skip_to(int32 until_time) +static void skip_to(MidiSong *song, Sint32 until_time) { - if (current_sample > until_time) - current_sample=0; + if (song->current_sample > until_time) + song->current_sample = 0; - reset_midi(); - buffered_count=0; - buffer_pointer=common_buffer; - current_event=event_list; + reset_midi(song); + song->buffered_count = 0; + song->buffer_pointer = song->common_buffer; + song->current_event = song->events; if (until_time) - seek_forward(until_time); - ctl->reset(); + seek_forward(song, until_time); } -static int apply_controls(void) -{ - int rc, i, did_skip=0; - int32 val; - /* ASCII renditions of CD player pictograms indicate approximate effect */ - do - switch(rc=ctl->read(&val)) - { - case RC_QUIT: /* [] */ - case RC_LOAD_FILE: - case RC_NEXT: /* >>| */ - case RC_REALLY_PREVIOUS: /* |<< */ - return rc; - - case RC_CHANGE_VOLUME: - if (val>0 || amplification > -val) - amplification += val; - else - amplification=0; - if (amplification > MAX_AMPLIFICATION) - amplification=MAX_AMPLIFICATION; - adjust_amplification(); - for (i=0; imaster_volume(amplification); - break; - - case RC_PREVIOUS: /* |<< */ - if (current_sample < 2*play_mode->rate) - return RC_REALLY_PREVIOUS; - return RC_RESTART; - - case RC_RESTART: /* |<< */ - skip_to(0); - did_skip=1; - break; - - case RC_JUMP: - if (val >= sample_count) - return RC_NEXT; - skip_to(val); - return rc; - - case RC_FORWARD: /* >> */ - if (val+current_sample >= sample_count) - return RC_NEXT; - skip_to(val+current_sample); - did_skip=1; - break; - - case RC_BACK: /* << */ - if (current_sample > val) - skip_to(current_sample-val); - else - skip_to(0); /* We can't seek to end of previous song. */ - did_skip=1; - break; - } - while (rc!= RC_NONE); - - /* Advertise the skip so that we stop computing the audio buffer */ - if (did_skip) - return RC_JUMP; - else - return rc; -} - -static void do_compute_data(uint32 count) +static void do_compute_data(MidiSong *song, Sint32 count) { int i; - if (!count) return; /* (gl) */ - memset(buffer_pointer, 0, count * num_ochannels * 4); - for (i=0; ibuffer_pointer, 0, + (song->encoding & PE_MONO) ? (count * 4) : (count * 8)); + for (i = 0; i < song->voices; i++) { - if(voice[i].status != VOICE_FREE) - { - if (!voice[i].sample_offset && voice[i].echo_delay_count) - { - if ((uint32)voice[i].echo_delay_count >= count) voice[i].echo_delay_count -= count; - else - { - mix_voice(buffer_pointer+voice[i].echo_delay_count, i, count-voice[i].echo_delay_count); - voice[i].echo_delay_count = 0; - } - } - else mix_voice(buffer_pointer, i, count); - } + if(song->voice[i].status != VOICE_FREE) + mix_voice(song, song->buffer_pointer, i, count); } - current_sample += count; + song->current_sample += count; } - /* count=0 means flush remaining buffered data to output device, then flush the device itself */ -static int compute_data(void *stream, int32 count) +static void compute_data(MidiSong *song, void *stream, Sint32 count) { - int rc, channels; + int channels; - if ( play_mode->encoding & PE_MONO ) + if ( song->encoding & PE_MONO ) channels = 1; else - channels = num_ochannels; + channels = 2; if (!count) { - if (buffered_count) - s32tobuf(stream, common_buffer, channels*buffered_count); - buffer_pointer=common_buffer; - buffered_count=0; - return RC_NONE; + if (song->buffered_count) + song->write(stream, song->common_buffer, channels * song->buffered_count); + song->buffer_pointer = song->common_buffer; + song->buffered_count = 0; + return; } - while ((count+buffered_count) >= AUDIO_BUFFER_SIZE) + while ((count + song->buffered_count) >= song->buffer_size) { - do_compute_data(AUDIO_BUFFER_SIZE-buffered_count); - count -= AUDIO_BUFFER_SIZE-buffered_count; - s32tobuf(stream, common_buffer, channels*AUDIO_BUFFER_SIZE); - buffer_pointer=common_buffer; - buffered_count=0; - - ctl->current_time(current_sample); - if ((rc=apply_controls())!=RC_NONE) - return rc; + do_compute_data(song, song->buffer_size - song->buffered_count); + count -= song->buffer_size - song->buffered_count; + song->write(stream, song->common_buffer, channels * song->buffer_size); + song->buffer_pointer = song->common_buffer; + song->buffered_count = 0; } if (count>0) { - do_compute_data(count); - buffered_count += count; - buffer_pointer += count * channels; + do_compute_data(song, count); + song->buffered_count += count; + song->buffer_pointer += (song->encoding & PE_MONO) ? count : count*2; } - return RC_NONE; } -int Timidity_PlaySome(void *stream, int samples) +void Timidity_Start(MidiSong *song) +{ + song->playing = 1; + adjust_amplification(song); + skip_to(song, 0); +} + +void Timidity_Seek(MidiSong *song, Uint32 ms) { - int rc = RC_NONE; - int32 end_sample; + skip_to(song, (ms * song->rate) / 1000); +} + +Uint32 Timidity_GetSongLength(MidiSong *song) +{ + MidiEvent *last_event = &song->events[song->groomed_event_count - 1]; + /* We want last_event->time * 1000 / song->rate */ + Uint32 retvalue = (last_event->time / song->rate) * 1000; + retvalue += (last_event->time % song->rate) * 1000 / song->rate; + return retvalue; +} + +int Timidity_PlaySome(MidiSong *song, void *stream, Sint32 len) +{ + Sint32 start_sample, end_sample, samples; + int bytes_per_sample; + + if (!song->playing) + return 0; - if ( ! midi_playing ) { - return RC_NONE; - } - end_sample = current_sample+samples; - while ( current_sample < end_sample ) { + bytes_per_sample = + ((song->encoding & PE_MONO) ? 1 : 2) + * ((song->encoding & PE_16BIT) ? 2 : 1); + samples = len / bytes_per_sample; + + start_sample = song->current_sample; + end_sample = song->current_sample+samples; + while ( song->current_sample < end_sample ) { /* Handle all events that should happen at this time */ - while (current_event->time <= current_sample) { - switch(current_event->type) { + while (song->current_event->time <= song->current_sample) { + switch(song->current_event->type) { /* Effects affecting a single note */ case ME_NOTEON: - current_event->a += channel[current_event->channel].transpose; - if (!(current_event->b)) /* Velocity 0? */ - note_off(current_event); + if (!(song->current_event->b)) /* Velocity 0? */ + note_off(song); else - note_on(current_event); + note_on(song); break; case ME_NOTEOFF: - current_event->a += channel[current_event->channel].transpose; - note_off(current_event); + note_off(song); break; case ME_KEYPRESSURE: - adjust_pressure(current_event); + adjust_pressure(song); break; /* Effects affecting a single channel */ case ME_PITCH_SENS: - channel[current_event->channel].pitchsens=current_event->a; - channel[current_event->channel].pitchfactor=0; + song->channel[song->current_event->channel].pitchsens = + song->current_event->a; + song->channel[song->current_event->channel].pitchfactor = 0; break; case ME_PITCHWHEEL: - channel[current_event->channel].pitchbend= - current_event->a + current_event->b * 128; - channel[current_event->channel].pitchfactor=0; + song->channel[song->current_event->channel].pitchbend = + song->current_event->a + song->current_event->b * 128; + song->channel[song->current_event->channel].pitchfactor = 0; /* Adjust pitch for notes already playing */ - adjust_pitchbend(current_event->channel); - ctl->pitch_bend(current_event->channel, - channel[current_event->channel].pitchbend); + adjust_pitchbend(song); break; case ME_MAINVOLUME: - channel[current_event->channel].volume=current_event->a; - adjust_volume(current_event->channel); - ctl->volume(current_event->channel, current_event->a); + song->channel[song->current_event->channel].volume = + song->current_event->a; + adjust_volume(song); break; - - case ME_MASTERVOLUME: - adjust_master_volume(current_event->a + (current_event->b <<7)); - break; - - case ME_REVERBERATION: - channel[current_event->channel].reverberation=current_event->a; - break; - - case ME_CHORUSDEPTH: - channel[current_event->channel].chorusdepth=current_event->a; - break; - + case ME_PAN: - channel[current_event->channel].panning=current_event->a; - if (adjust_panning_immediately) - adjust_panning(current_event->channel); - ctl->panning(current_event->channel, current_event->a); + song->channel[song->current_event->channel].panning = + song->current_event->a; break; case ME_EXPRESSION: - channel[current_event->channel].expression=current_event->a; - adjust_volume(current_event->channel); - ctl->expression(current_event->channel, current_event->a); + song->channel[song->current_event->channel].expression = + song->current_event->a; + adjust_volume(song); break; case ME_PROGRAM: - /* if (ISDRUMCHANNEL(current_event->channel)) { */ - if (channel[current_event->channel].kit) { + if (ISDRUMCHANNEL(song, song->current_event->channel)) { /* Change drum set */ - channel[current_event->channel].bank=current_event->a; + song->channel[song->current_event->channel].bank = + song->current_event->a; } else - { - channel[current_event->channel].program=current_event->a; - } - ctl->program(current_event->channel, current_event->a); + song->channel[song->current_event->channel].program = + song->current_event->a; break; case ME_SUSTAIN: - channel[current_event->channel].sustain=current_event->a; - if (!current_event->a) - drop_sustain(current_event->channel); - ctl->sustain(current_event->channel, current_event->a); + song->channel[song->current_event->channel].sustain = + song->current_event->a; + if (!song->current_event->a) + drop_sustain(song); break; case ME_RESET_CONTROLLERS: - reset_controllers(current_event->channel); - redraw_controllers(current_event->channel); + reset_controllers(song, song->current_event->channel); break; case ME_ALL_NOTES_OFF: - all_notes_off(current_event->channel); + all_notes_off(song); break; case ME_ALL_SOUNDS_OFF: - all_sounds_off(current_event->channel); + all_sounds_off(song); break; - - case ME_HARMONICCONTENT: - channel[current_event->channel].harmoniccontent=current_event->a; - break; - - case ME_RELEASETIME: - channel[current_event->channel].releasetime=current_event->a; - break; - - case ME_ATTACKTIME: - channel[current_event->channel].attacktime=current_event->a; - break; - - case ME_BRIGHTNESS: - channel[current_event->channel].brightness=current_event->a; - break; - + case ME_TONE_BANK: - channel[current_event->channel].bank=current_event->a; + song->channel[song->current_event->channel].bank = + song->current_event->a; break; - - - case ME_TONE_KIT: - if (current_event->a==SFX_BANKTYPE) - { - channel[current_event->channel].sfx=SFXBANK; - channel[current_event->channel].kit=0; - } - else - { - channel[current_event->channel].sfx=0; - channel[current_event->channel].kit=current_event->a; - } - break; - + case ME_EOT: /* Give the last notes a couple of seconds to decay */ - ctl->cmsg(CMSG_INFO, VERB_VERBOSE, - "Playing time: ~%d seconds", current_sample/play_mode->rate+2); - ctl->cmsg(CMSG_INFO, VERB_VERBOSE, - "Notes cut: %d", cut_notes); - ctl->cmsg(CMSG_INFO, VERB_VERBOSE, - "Notes lost totally: %d", lost_notes); - midi_playing = 0; - return RC_TUNE_END; + SNDDBG(("Playing time: ~%d seconds\n", + song->current_sample/song->rate+2)); + SNDDBG(("Notes cut: %d\n", song->cut_notes)); + SNDDBG(("Notes lost totally: %d\n", song->lost_notes)); + song->playing = 0; + return (song->current_sample - start_sample) * bytes_per_sample; } - current_event++; + song->current_event++; } - if (current_event->time > end_sample) - rc=compute_data(stream, end_sample-current_sample); + if (song->current_event->time > end_sample) + compute_data(song, stream, end_sample-song->current_sample); else - rc=compute_data(stream, current_event->time-current_sample); - ctl->refresh(); - if ( (rc!=RC_NONE) && (rc!=RC_JUMP)) - break; + compute_data(song, stream, song->current_event->time-song->current_sample); } - return rc; + return samples * bytes_per_sample; } - -void Timidity_SetVolume(int volume) +void Timidity_SetVolume(MidiSong *song, int volume) { int i; if (volume > MAX_AMPLIFICATION) - amplification=MAX_AMPLIFICATION; + song->amplification = MAX_AMPLIFICATION; else if (volume < 0) - amplification=0; + song->amplification = 0; else - amplification=volume; - adjust_amplification(); - for (i=0; iamplification = volume; + adjust_amplification(song); + for (i = 0; i < song->voices; i++) + if (song->voice[i].status != VOICE_FREE) { - recompute_amp(i); - apply_envelope_to_amp(i); + recompute_amp(song, i); + apply_envelope_to_amp(song, i); } - ctl->master_volume(amplification); -} - -MidiSong *Timidity_LoadSong_RW(SDL_RWops *src, int freesrc) -{ - MidiSong *song; - int32 events; - - /* Allocate memory for the song */ - song = (MidiSong *)safe_malloc(sizeof(*song)); - memset(song, 0, sizeof(*song)); - - strcpy(midi_name, "SDLrwops source"); - - song->events = read_midi_file(src, &events, &song->samples); - if (song->events) { - if (freesrc) { - SDL_RWclose(src); - } - } else { - free(song); - song = NULL; - } - return(song); -} - -void Timidity_Start(MidiSong *song) -{ - load_missing_instruments(); - adjust_amplification(); - sample_count = song->samples; - event_list = song->events; - lost_notes=cut_notes=0; - - skip_to(0); - midi_playing = 1; -} - -int Timidity_Active(void) -{ - return(midi_playing); } - -void Timidity_Stop(void) -{ - midi_playing = 0; -} - -void Timidity_FreeSong(MidiSong *song) -{ - if (free_instruments_afterwards) - free_instruments(); - - free(song->events); - free(song); -} - -void Timidity_Close(void) -{ - if (resample_buffer) { - free(resample_buffer); - resample_buffer=NULL; - } - if (common_buffer) { - free(common_buffer); - common_buffer=NULL; - } - free_instruments(); - free_pathlist(); -} - diff --git a/timidity/playmidi.h b/timidity/playmidi.h index 2a32d7eb..03b287a5 100644 --- a/timidity/playmidi.h +++ b/timidity/playmidi.h @@ -1,15 +1,14 @@ /* + TiMidity -- Experimental MIDI to WAVE converter Copyright (C) 1995 Tuukka Toivonen This program is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License, available in COPYING. - */ -typedef struct { - int32 time; - uint8 channel, type, a, b; -} MidiEvent; + playmidi.h + + */ /* Midi events */ #define ME_NONE 0 @@ -31,84 +30,11 @@ typedef struct { #define ME_TONE_BANK 15 #define ME_LYRIC 16 -#define ME_TONE_KIT 17 -#define ME_MASTERVOLUME 18 -#define ME_CHANNEL_PRESSURE 19 - -#define ME_HARMONICCONTENT 71 -#define ME_RELEASETIME 72 -#define ME_ATTACKTIME 73 -#define ME_BRIGHTNESS 74 - -#define ME_REVERBERATION 91 -#define ME_CHORUSDEPTH 93 #define ME_EOT 99 - -#define SFX_BANKTYPE 64 - -typedef struct { - int - bank, program, volume, sustain, panning, pitchbend, expression, - mono, /* one note only on this channel -- not implemented yet */ - /* new stuff */ - variationbank, reverberation, chorusdepth, harmoniccontent, - releasetime, attacktime, brightness, kit, sfx, - /* end new */ - pitchsens; - FLOAT_T - pitchfactor; /* precomputed pitch bend factor to save some fdiv's */ - char transpose; - char *name; -} Channel; - /* Causes the instrument's default panning to be used. */ #define NO_PANNING -1 -/* envelope points */ -#define MAXPOINT 7 - -typedef struct { - uint8 - status, channel, note, velocity, clone_type; - Sample *sample; - Sample *left_sample; - Sample *right_sample; - int32 clone_voice; - int32 - orig_frequency, frequency, - sample_offset, loop_start, loop_end; - int32 - envelope_volume, modulation_volume; - int32 - envelope_target, modulation_target; - int32 - tremolo_sweep, tremolo_sweep_position, tremolo_phase, - lfo_sweep, lfo_sweep_position, lfo_phase, - vibrato_sweep, vibrato_sweep_position, vibrato_depth, vibrato_delay, - starttime, echo_delay_count; - int32 - echo_delay, - sample_increment, - envelope_increment, - modulation_increment, - tremolo_phase_increment, - lfo_phase_increment; - - final_volume_t left_mix, right_mix, lr_mix, rr_mix, ce_mix, lfe_mix; - - FLOAT_T - left_amp, right_amp, lr_amp, rr_amp, ce_amp, lfe_amp, - volume, tremolo_volume, lfo_volume; - int32 - vibrato_sample_increment[VIBRATO_SAMPLE_INCREMENTS]; - int32 - envelope_rate[MAXPOINT], envelope_offset[MAXPOINT]; - int32 - vibrato_phase, vibrato_control_ratio, vibrato_control_counter, - envelope_stage, modulation_stage, control_counter, - modulation_delay, modulation_counter, panning, panned; -} Voice; /* Voice status options: */ #define VOICE_FREE 0 @@ -124,37 +50,4 @@ typedef struct { #define PANNED_CENTER 3 /* Anything but PANNED_MYSTERY only uses the left volume */ -/* Envelope stages: */ -#define ATTACK 0 -#define HOLD 1 -#define DECAY 2 -#define RELEASE 3 -#define RELEASEB 4 -#define RELEASEC 5 -#define DELAY 6 - -extern Channel channel[16]; -extern Voice voice[MAX_VOICES]; -extern signed char drumvolume[MAXCHAN][MAXNOTE]; -extern signed char drumpanpot[MAXCHAN][MAXNOTE]; -extern signed char drumreverberation[MAXCHAN][MAXNOTE]; -extern signed char drumchorusdepth[MAXCHAN][MAXNOTE]; - -extern int32 control_ratio, amp_with_poly, amplification; -extern int32 drumchannels; -extern int adjust_panning_immediately; -extern int voices; - -#define ISDRUMCHANNEL(c) ((drumchannels & (1<<(c)))) - -extern int GM_System_On; -extern int XG_System_On; -extern int GS_System_On; - -extern int XG_System_reverb_type; -extern int XG_System_chorus_type; -extern int XG_System_variation_type; - -extern int play_midi(MidiEvent *el, int32 events, int32 samples); -extern int play_midi_file(const char *fn); -extern void dumb_pass_playing_list(int number_of_files, char *list_of_files[]); +#define ISDRUMCHANNEL(s, c) (((s)->drumchannels & (1<<(c)))) diff --git a/timidity/readmidi.c b/timidity/readmidi.c index afa79b95..788a1b02 100644 --- a/timidity/readmidi.c +++ b/timidity/readmidi.c @@ -1,254 +1,63 @@ /* + TiMidity -- Experimental MIDI to WAVE converter Copyright (C) 1995 Tuukka Toivonen This program is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License, available in COPYING. - */ +*/ + +#if HAVE_CONFIG_H +# include +#endif #include #include -#include #include -#include +#include "SDL.h" -#include "config.h" +#include "options.h" +#include "timidity.h" #include "common.h" #include "instrum.h" #include "playmidi.h" -#include "readmidi.h" -#include "output.h" -#include "ctrlmode.h" - -int32 quietchannels=0; - -static int midi_port_number; -char midi_name[FILENAME_MAX+1]; - -static int track_info, curr_track, curr_title_track; -static char title[128]; - -#if MAXCHAN <= 16 -#define MERGE_CHANNEL_PORT(ch) ((int)(ch)) -#else -#define MERGE_CHANNEL_PORT(ch) ((int)(ch) | (midi_port_number << 4)) -#endif - -/* to avoid some unnecessary parameter passing */ -static MidiEventList *evlist; -static int32 event_count; -static SDL_RWops *rw; -static int32 at; - -/* These would both fit into 32 bits, but they are often added in - large multiples, so it's simpler to have two roomy ints */ -static int32 sample_increment, sample_correction; /*samples per MIDI delta-t*/ /* Computes how many (fractional) samples one MIDI delta-time unit contains */ -static void compute_sample_increment(int32 tempo, int32 divisions) +static void compute_sample_increment(MidiSong *song, Sint32 tempo, + Sint32 divisions) { double a; - a = (double) (tempo) * (double) (play_mode->rate) * (65536.0/1000000.0) / + a = (double) (tempo) * (double) (song->rate) * (65536.0/1000000.0) / (double)(divisions); - sample_correction = (int32)(a) & 0xFFFF; - sample_increment = (int32)(a) >> 16; + song->sample_correction = (Sint32)(a) & 0xFFFF; + song->sample_increment = (Sint32)(a) >> 16; - ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Samples per delta-t: %d (correction %d)", - sample_increment, sample_correction); + SNDDBG(("Samples per delta-t: %d (correction %d)", + song->sample_increment, song->sample_correction)); } /* Read variable-length number (7 bits per byte, MSB first) */ -static int32 getvl(void) +static Sint32 getvl(SDL_RWops *rw) { - int32 l=0; - uint8 c; + Sint32 l=0; + Uint8 c; for (;;) { - SDL_RWread(rw,&c,1,1); + SDL_RWread(rw, &c, 1, 1); l += (c & 0x7f); if (!(c & 0x80)) return l; l<<=7; } } - -static int sysex(uint32 len, uint8 *syschan, uint8 *sysa, uint8 *sysb, SDL_RWops *rw) -{ - unsigned char *s=(unsigned char *)safe_malloc(len); - int id, model, ch, port, adhi, adlo, cd, dta, dtb, dtc; - if (len != (uint32)SDL_RWread(rw, s, 1, len)) - { - free(s); - return 0; - } - if (len<5) { free(s); return 0; } - if (curr_track == curr_title_track && track_info > 1) title[0] = '\0'; - id=s[0]; port=s[1]; model=s[2]; adhi=s[3]; adlo=s[4]; - if (id==0x7e && port==0x7f && model==0x09 && adhi==0x01) - { - ctl->cmsg(CMSG_TEXT, VERB_VERBOSE, "GM System On", len); - GM_System_On=1; - free(s); - return 0; - } - ch = adlo & 0x0f; - *syschan=(uint8)ch; - if (id==0x7f && len==7 && port==0x7f && model==0x04 && adhi==0x01) - { - ctl->cmsg(CMSG_TEXT, VERB_DEBUG, "Master Volume %d", s[4]+(s[5]<<7)); - *sysa = s[4]; - *sysb = s[5]; - free(s); - return ME_MASTERVOLUME; - /** return s[4]+(s[5]<<7); **/ - } - if (len<8) { free(s); return 0; } - port &=0x0f; - ch = (adlo & 0x0f) | ((port & 0x03) << 4); - *syschan=(uint8)ch; - cd=s[5]; dta=s[6]; - if (len >= 8) dtb=s[7]; - else dtb=-1; - if (len >= 9) dtc=s[8]; - else dtc=-1; - free(s); - if (id==0x43 && model==0x4c) - { - if (!adhi && !adlo && cd==0x7e && !dta) - { - ctl->cmsg(CMSG_TEXT, VERB_VERBOSE, "XG System On", len); - XG_System_On=1; - #ifdef tplus - vol_table = xg_vol_table; - #endif - } - else if (adhi == 2 && adlo == 1) - { - if (dtb==8) dtb=3; - switch (cd) - { - case 0x00: - XG_System_reverb_type=(dta<<3)+dtb; - break; - case 0x20: - XG_System_chorus_type=((dta-64)<<3)+dtb; - break; - case 0x40: - XG_System_variation_type=dta; - break; - case 0x5a: - /* dta==0 Insertion; dta==1 System */ - break; - default: break; - } - } - else if (adhi == 8 && cd <= 40) - { - *sysa = dta & 0x7f; - switch (cd) - { - case 0x01: /* bank select MSB */ - return ME_TONE_KIT; - break; - case 0x02: /* bank select LSB */ - return ME_TONE_BANK; - break; - case 0x03: /* program number */ - /** MIDIEVENT(d->at, ME_PROGRAM, lastchan, a, 0); **/ - return ME_PROGRAM; - break; - case 0x08: /* */ - /* d->channel[adlo&0x0f].transpose = (char)(dta-64); */ - channel[ch].transpose = (char)(dta-64); - ctl->cmsg(CMSG_TEXT, VERB_DEBUG, "transpose channel %d by %d", - (adlo&0x0f)+1, dta-64); - break; - case 0x0b: /* volume */ - return ME_MAINVOLUME; - break; - case 0x0e: /* pan */ - return ME_PAN; - break; - case 0x12: /* chorus send */ - return ME_CHORUSDEPTH; - break; - case 0x13: /* reverb send */ - return ME_REVERBERATION; - break; - case 0x14: /* variation send */ - break; - case 0x18: /* filter cutoff */ - return ME_BRIGHTNESS; - break; - case 0x19: /* filter resonance */ - return ME_HARMONICCONTENT; - break; - default: break; - } - } - return 0; - } - else if (id==0x41 && model==0x42 && adhi==0x12 && adlo==0x40) - { - if (dtc<0) return 0; - if (!cd && dta==0x7f && !dtb && dtc==0x41) - { - ctl->cmsg(CMSG_TEXT, VERB_VERBOSE, "GS System On", len); - GS_System_On=1; - #ifdef tplus - vol_table = gs_vol_table; - #endif - } - else if (dta==0x15 && (cd&0xf0)==0x10) - { - int chan=cd&0x0f; - if (!chan) chan=9; - else if (chan<10) chan--; - chan = MERGE_CHANNEL_PORT(chan); - channel[chan].kit=dtb; - } - else if (cd==0x01) switch(dta) - { - case 0x30: - switch(dtb) - { - case 0: XG_System_reverb_type=16+0; break; - case 1: XG_System_reverb_type=16+1; break; - case 2: XG_System_reverb_type=16+2; break; - case 3: XG_System_reverb_type= 8+0; break; - case 4: XG_System_reverb_type= 8+1; break; - case 5: XG_System_reverb_type=32+0; break; - case 6: XG_System_reverb_type=8*17; break; - case 7: XG_System_reverb_type=8*18; break; - } - break; - case 0x38: - switch(dtb) - { - case 0: XG_System_chorus_type= 8+0; break; - case 1: XG_System_chorus_type= 8+1; break; - case 2: XG_System_chorus_type= 8+2; break; - case 3: XG_System_chorus_type= 8+4; break; - case 4: XG_System_chorus_type= -1; break; - case 5: XG_System_chorus_type= 8*3; break; - case 6: XG_System_chorus_type= -1; break; - case 7: XG_System_chorus_type= -1; break; - } - break; - } - return 0; - } - return 0; -} - /* Print a string from the file, followed by a newline. Any non-ASCII or unprintable characters will be converted to periods. */ -static int dumpstring(int32 len, const char *label) +static int dumpstring(SDL_RWops *rw, Sint32 len, char *label) { signed char *s=safe_malloc(len+1); - if (len != (int32)SDL_RWread(rw, s, 1, len)) + if (len != (Sint32) SDL_RWread(rw, s, 1, len)) { free(s); return -1; @@ -259,7 +68,7 @@ static int dumpstring(int32 len, const char *label) if (s[len]<32) s[len]='.'; } - ctl->cmsg(CMSG_TEXT, VERB_VERBOSE, "%s%s", label, s); + SNDDBG(("%s%s", label, s)); free(s); return 0; } @@ -274,82 +83,54 @@ static int dumpstring(int32 len, const char *label) /* Read a MIDI event, returning a freshly allocated element that can be linked to the event list */ -static MidiEventList *read_midi_event(void) +static MidiEventList *read_midi_event(MidiSong *song) { - static uint8 laststatus, lastchan; - static uint8 nrpn=0, rpn_msb[16], rpn_lsb[16]; /* one per channel */ - uint8 me, type, a,b,c; - int32 len; + static Uint8 laststatus, lastchan; + static Uint8 nrpn=0, rpn_msb[16], rpn_lsb[16]; /* one per channel */ + Uint8 me, type, a,b,c; + Sint32 len; MidiEventList *new; for (;;) { - at+=getvl(); - if (SDL_RWread(rw,&me,1,1)!=1) + song->at += getvl(song->rw); + if (SDL_RWread(song->rw, &me, 1, 1) != 1) { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: read_midi_event: %s", - current_filename, strerror(errno)); + SNDDBG(("read_midi_event: SDL_RWread() failure\n")); return 0; } if(me==0xF0 || me == 0xF7) /* SysEx event */ { - int32 sret; - uint8 sysa=0, sysb=0, syschan=0; - - len=getvl(); - sret=sysex(len, &syschan, &sysa, &sysb, rw); - if (sret) - { - MIDIEVENT(at, sret, syschan, sysa, sysb); - } + len=getvl(song->rw); + SDL_RWseek(song->rw, len, RW_SEEK_CUR); } else if(me==0xFF) /* Meta event */ { - SDL_RWread(rw,&type,1,1); - len=getvl(); + SDL_RWread(song->rw, &type, 1, 1); + len=getvl(song->rw); if (type>0 && type<16) { static char *label[]={ "Text event: ", "Text: ", "Copyright: ", "Track name: ", "Instrument: ", "Lyric: ", "Marker: ", "Cue point: "}; - dumpstring(len, label[(type>7) ? 0 : type]); + dumpstring(song->rw, len, label[(type>7) ? 0 : type]); } else switch(type) { - - case 0x21: /* MIDI port number */ - if(len == 1) - { - SDL_RWread(rw,&midi_port_number,1,1); - if(midi_port_number == EOF) - { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "Warning: \"%s\": Short midi file.", - midi_name); - return 0; - } - midi_port_number &= 0x0f; - if (midi_port_number) - ctl->cmsg(CMSG_INFO, VERB_VERBOSE, - "(MIDI port number %d)", midi_port_number); - midi_port_number &= 0x03; - } - else SDL_RWseek(rw, len, RW_SEEK_CUR); - break; - case 0x2F: /* End of Track */ return MAGIC_EOT; case 0x51: /* Tempo */ - SDL_RWread(rw,&a,1,1); SDL_RWread(rw,&b,1,1); SDL_RWread(rw,&c,1,1); - MIDIEVENT(at, ME_TEMPO, c, a, b); + SDL_RWread(song->rw, &a, 1, 1); + SDL_RWread(song->rw, &b, 1, 1); + SDL_RWread(song->rw, &c, 1, 1); + MIDIEVENT(song->at, ME_TEMPO, c, a, b); default: - ctl->cmsg(CMSG_INFO, VERB_DEBUG, - "(Meta event type 0x%02x, length %ld)", type, len); - SDL_RWseek(rw, len, RW_SEEK_CUR); + SNDDBG(("(Meta event type 0x%02x, length %d)\n", type, len)); + SDL_RWseek(song->rw, len, RW_SEEK_CUR); break; } } @@ -360,30 +141,28 @@ static MidiEventList *read_midi_event(void) { lastchan=a & 0x0F; laststatus=(a>>4) & 0x07; - SDL_RWread(rw,&a, 1,1); + SDL_RWread(song->rw, &a, 1, 1); a &= 0x7F; } switch(laststatus) { case 0: /* Note off */ - SDL_RWread(rw,&b, 1,1); + SDL_RWread(song->rw, &b, 1, 1); b &= 0x7F; - MIDIEVENT(at, ME_NOTEOFF, lastchan, a,b); + MIDIEVENT(song->at, ME_NOTEOFF, lastchan, a,b); case 1: /* Note on */ - SDL_RWread(rw,&b, 1,1); + SDL_RWread(song->rw, &b, 1, 1); b &= 0x7F; - if (curr_track == curr_title_track && track_info > 1) title[0] = '\0'; - MIDIEVENT(at, ME_NOTEON, lastchan, a,b); - + MIDIEVENT(song->at, ME_NOTEON, lastchan, a,b); case 2: /* Key Pressure */ - SDL_RWread(rw,&b, 1,1); + SDL_RWread(song->rw, &b, 1, 1); b &= 0x7F; - MIDIEVENT(at, ME_KEYPRESSURE, lastchan, a, b); + MIDIEVENT(song->at, ME_KEYPRESSURE, lastchan, a, b); case 3: /* Control change */ - SDL_RWread(rw,&b, 1,1); + SDL_RWread(song->rw, &b, 1, 1); b &= 0x7F; { int control=255; @@ -393,14 +172,6 @@ static MidiEventList *read_midi_event(void) case 10: control=ME_PAN; break; case 11: control=ME_EXPRESSION; break; case 64: control=ME_SUSTAIN; break; - - case 71: control=ME_HARMONICCONTENT; break; - case 72: control=ME_RELEASETIME; break; - case 73: control=ME_ATTACKTIME; break; - case 74: control=ME_BRIGHTNESS; break; - case 91: control=ME_REVERBERATION; break; - case 93: control=ME_CHORUSDEPTH; break; - case 120: control=ME_ALL_SOUNDS_OFF; break; case 121: control=ME_RESET_CONTROLLERS; break; case 123: control=ME_ALL_NOTES_OFF; break; @@ -411,9 +182,13 @@ static MidiEventList *read_midi_event(void) Also, some MIDI files use 0 as some sort of continuous controller. This will cause lots of warnings about undefined tone banks. */ - case 0: if (XG_System_On) control = ME_TONE_KIT; else control=ME_TONE_BANK; break; - - case 32: if (XG_System_On) control = ME_TONE_BANK; break; + case 0: control=ME_TONE_BANK; break; + case 32: + if (b!=0) + SNDDBG(("(Strange: tone bank change 0x20%02x)\n", b)); + else + control=ME_TONE_BANK; + break; case 100: nrpn=0; rpn_msb[lastchan]=b; break; case 101: nrpn=0; rpn_lsb[lastchan]=b; break; @@ -423,47 +198,8 @@ static MidiEventList *read_midi_event(void) case 6: if (nrpn) { - if (rpn_msb[lastchan]==1) switch (rpn_lsb[lastchan]) - { -#ifdef tplus - case 0x08: control=ME_VIBRATO_RATE; break; - case 0x09: control=ME_VIBRATO_DEPTH; break; - case 0x0a: control=ME_VIBRATO_DELAY; break; -#endif - case 0x20: control=ME_BRIGHTNESS; break; - case 0x21: control=ME_HARMONICCONTENT; break; - /* - case 0x63: envelope attack rate - case 0x64: envelope decay rate - case 0x66: envelope release rate - */ - } - else switch (rpn_msb[lastchan]) - { - /* - case 0x14: filter cutoff frequency - case 0x15: filter resonance - case 0x16: envelope attack rate - case 0x17: envelope decay rate - case 0x18: pitch coarse - case 0x19: pitch fine - */ - case 0x1a: drumvolume[lastchan][0x7f & rpn_lsb[lastchan]] = b; break; - case 0x1c: - if (!b) b=(int) (127.0*rand()/(RAND_MAX)); - drumpanpot[lastchan][0x7f & rpn_lsb[lastchan]] = b; - break; - case 0x1d: drumreverberation[lastchan][0x7f & rpn_lsb[lastchan]] = b; break; - case 0x1e: drumchorusdepth[lastchan][0x7f & rpn_lsb[lastchan]] = b; break; - /* - case 0x1f: variation send level - */ - } - - ctl->cmsg(CMSG_INFO, VERB_DEBUG, - "(Data entry (MSB) for NRPN %02x,%02x: %ld)", - rpn_msb[lastchan], rpn_lsb[lastchan], - b); + SNDDBG(("(Data entry (MSB) for NRPN %02x,%02x: %d)\n", + rpn_msb[lastchan], rpn_lsb[lastchan], b)); break; } @@ -475,45 +211,41 @@ static MidiEventList *read_midi_event(void) case 0x7F7F: /* RPN reset */ /* reset pitch bend sensitivity to 2 */ - MIDIEVENT(at, ME_PITCH_SENS, lastchan, 2, 0); + MIDIEVENT(song->at, ME_PITCH_SENS, lastchan, 2, 0); default: - ctl->cmsg(CMSG_INFO, VERB_DEBUG, - "(Data entry (MSB) for RPN %02x,%02x: %ld)", - rpn_msb[lastchan], rpn_lsb[lastchan], - b); + SNDDBG(("(Data entry (MSB) for RPN %02x,%02x: %d)\n", + rpn_msb[lastchan], rpn_lsb[lastchan], b)); break; } break; default: - ctl->cmsg(CMSG_INFO, VERB_DEBUG, - "(Control %d: %d)", a, b); + SNDDBG(("(Control %d: %d)\n", a, b)); break; } if (control != 255) { - MIDIEVENT(at, control, lastchan, b, 0); + MIDIEVENT(song->at, control, lastchan, b, 0); } } break; case 4: /* Program change */ a &= 0x7f; - MIDIEVENT(at, ME_PROGRAM, lastchan, a, 0); + MIDIEVENT(song->at, ME_PROGRAM, lastchan, a, 0); case 5: /* Channel pressure - NOT IMPLEMENTED */ break; case 6: /* Pitch wheel */ - SDL_RWread(rw,&b, 1,1); + SDL_RWread(song->rw, &b, 1, 1); b &= 0x7F; - MIDIEVENT(at, ME_PITCHWHEEL, lastchan, a, b); + MIDIEVENT(song->at, ME_PITCHWHEEL, lastchan, a, b); default: - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "*** Can't happen: status 0x%02X, channel 0x%02X", - laststatus, lastchan); + SNDDBG(("*** Can't happen: status 0x%02X, channel 0x%02X\n", + laststatus, lastchan)); break; } } @@ -526,51 +258,50 @@ static MidiEventList *read_midi_event(void) /* Read a midi track into the linked list, either merging with any previous tracks or appending to them. */ -static int read_track(int append) +static int read_track(MidiSong *song, int append) { MidiEventList *meep; MidiEventList *next, *new; - int32 len; + Sint32 len; Sint64 next_pos, pos; char tmp[4]; - meep=evlist; + meep = song->evlist; if (append && meep) { /* find the last event in the list */ for (; meep->next; meep=meep->next) ; - at=meep->event.time; + song->at = meep->event.time; } else - at=0; + song->at=0; /* Check the formalities */ - if ((SDL_RWread(rw,tmp,1,4) != 4) || (SDL_RWread(rw,&len,4,1) != 1)) + + if (SDL_RWread(song->rw, tmp, 1, 4) != 4 || SDL_RWread(song->rw, &len, 4, 1) != 1) { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "%s: Can't read track header.", current_filename); + SNDDBG(("Can't read track header.\n")); return -1; } - len=BE_LONG(len); - next_pos = SDL_RWtell(rw) + len; + len=SDL_SwapBE32(len); + next_pos = SDL_RWtell(song->rw) + len; if (memcmp(tmp, "MTrk", 4)) { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "%s: Corrupt MIDI file.", current_filename); + SNDDBG(("Corrupt MIDI file.\n")); return -2; } for (;;) { - if (!(new=read_midi_event())) /* Some kind of error */ + if (!(new=read_midi_event(song))) /* Some kind of error */ return -2; if (new==MAGIC_EOT) /* End-of-track Hack. */ { - pos = SDL_RWtell(rw); + pos = SDL_RWtell(song->rw); if (pos < next_pos) - SDL_RWseek(rw, next_pos - pos, RW_SEEK_CUR); + SDL_RWseek(song->rw, next_pos - pos, RW_SEEK_CUR); return 0; } @@ -584,147 +315,82 @@ static int read_track(int append) new->next=next; meep->next=new; - event_count++; /* Count the event. (About one?) */ + song->event_count++; /* Count the event. (About one?) */ meep=new; } } /* Free the linked event list from memory. */ -static void free_midi_list(void) +static void free_midi_list(MidiSong *song) { MidiEventList *meep, *next; - if (!(meep=evlist)) return; + if (!(meep = song->evlist)) return; while (meep) { next=meep->next; free(meep); meep=next; } - evlist=0; -} - - -static void xremap_percussion(int *banknumpt, int *this_notept, int this_kit) { - int i, newmap; - int banknum = *banknumpt; - int this_note = *this_notept; - int newbank, newnote; - - if (this_kit != 127 && this_kit != 126) return; - - for (i = 0; i < XMAPMAX; i++) { - newmap = xmap[i][0]; - if (!newmap) return; - if (this_kit == 127 && newmap != XGDRUM) continue; - if (this_kit == 126 && newmap != SFXDRUM1) continue; - if (xmap[i][1] != banknum) continue; - if (xmap[i][3] != this_note) continue; - newbank = xmap[i][2]; - newnote = xmap[i][4]; - if (newbank == banknum && newnote == this_note) return; - if (!drumset[newbank]) return; - *banknumpt = newbank; - *this_notept = newnote; - return; - } + song->evlist=0; } /* Allocate an array of MidiEvents and fill it from the linked list of events, marking used instruments for loading. Convert event times to samples: handle tempo changes. Strip unnecessary events from the list. Free the linked list. */ -static MidiEvent *groom_list(int32 divisions,int32 *eventsp,int32 *samplesp) +static MidiEvent *groom_list(MidiSong *song, Sint32 divisions,Sint32 *eventsp, + Sint32 *samplesp) { MidiEvent *groomed_list, *lp; MidiEventList *meep; - int32 i, our_event_count, tempo, skip_this_event, new_value; - int32 sample_cum, samples_to_do, at, st, dt, counting_time; + Sint32 i, our_event_count, tempo, skip_this_event, new_value; + Sint32 sample_cum, samples_to_do, at, st, dt, counting_time; - int current_bank[MAXCHAN], current_banktype[MAXCHAN], current_set[MAXCHAN], - current_kit[MAXCHAN], current_program[MAXCHAN]; + int current_bank[MAXCHAN], current_set[MAXCHAN], current_program[MAXCHAN]; /* Or should each bank have its own current program? */ - int dset, dnote, drumsflag, mprog; for (i=0; idefault_program; } tempo=500000; - compute_sample_increment(tempo, divisions); + compute_sample_increment(song, tempo, divisions); /* This may allocate a bit more than we need */ - groomed_list=lp=safe_malloc(sizeof(MidiEvent) * (event_count+1)); - meep=evlist; + groomed_list=lp=safe_malloc(sizeof(MidiEvent) * (song->event_count+1)); + meep=song->evlist; our_event_count=0; st=at=sample_cum=0; counting_time=2; /* We strip any silence before the first NOTE ON. */ - for (i=0; ievent_count; i++) { skip_this_event=0; - ctl->cmsg(CMSG_INFO, VERB_DEBUG_SILLY, - "%6d: ch %2d: event %d (%d,%d)", - meep->event.time, meep->event.channel + 1, - meep->event.type, meep->event.a, meep->event.b); if (meep->event.type==ME_TEMPO) { tempo= meep->event.channel + meep->event.b * 256 + meep->event.a * 65536; - compute_sample_increment(tempo, divisions); + compute_sample_increment(song, tempo, divisions); skip_this_event=1; } else if (meep->event.channel >= MAXCHAN) - skip_this_event=1; - else if ((quietchannels & (1<event.channel))) - skip_this_event=1; + skip_this_event=1; else switch (meep->event.type) { case ME_PROGRAM: - - if (current_kit[meep->event.channel]) + if (ISDRUMCHANNEL(song, meep->event.channel)) { - if (current_kit[meep->event.channel]==126) - { - /* note request for 2nd sfx rhythm kit */ - if (meep->event.a && drumset[SFXDRUM2]) - { - current_kit[meep->event.channel]=125; - current_set[meep->event.channel]=SFXDRUM2; - new_value=SFXDRUM2; - } - else if (!meep->event.a && drumset[SFXDRUM1]) - { - current_set[meep->event.channel]=SFXDRUM1; - new_value=SFXDRUM1; - } - else - { - ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, - "XG SFX drum set is undefined"); - skip_this_event=1; - break; - } - } - if (drumset[meep->event.a]) /* Is this a defined drumset? */ + if (song->drumset[meep->event.a]) /* Is this a defined drumset? */ new_value=meep->event.a; else { - ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, - "Drum set %d is undefined", meep->event.a); - if (drumset[0]) - new_value=meep->event.a=0; - else - { - skip_this_event=1; - break; - } + SNDDBG(("Drum set %d is undefined\n", meep->event.a)); + new_value=meep->event.a=0; } if (current_set[meep->event.channel] != new_value) current_set[meep->event.channel]=new_value; @@ -745,169 +411,52 @@ static MidiEvent *groom_list(int32 divisions,int32 *eventsp,int32 *samplesp) case ME_NOTEON: if (counting_time) counting_time=1; - - drumsflag = current_kit[meep->event.channel]; - - if (drumsflag) /* percussion channel? */ + if (ISDRUMCHANNEL(song, meep->event.channel)) { - dset = current_set[meep->event.channel]; - dnote=meep->event.a; - if (XG_System_On) xremap_percussion(&dset, &dnote, drumsflag); - - /*if (current_config_pc42b) pcmap(&dset, &dnote, &mprog, &drumsflag);*/ - - if (drumsflag) - { /* Mark this instrument to be loaded */ - if (!(drumset[dset]->tone[dnote].layer)) - { - drumset[dset]->tone[dnote].layer= - MAGIC_LOAD_INSTRUMENT; - } - else drumset[dset]->tone[dnote].last_used - = current_tune_number; - if (!channel[meep->event.channel].name) channel[meep->event.channel].name= - drumset[dset]->name; - } + if (!(song->drumset[current_set[meep->event.channel]] + ->instrument[meep->event.a])) + song->drumset[current_set[meep->event.channel]] + ->instrument[meep->event.a] = MAGIC_LOAD_INSTRUMENT; } - - if (!drumsflag) /* not percussion */ + else { - int chan=meep->event.channel; - int banknum; - - if (current_banktype[chan]) banknum=SFXBANK; - else banknum=current_bank[chan]; - - mprog = current_program[chan]; - - if (mprog==SPECIAL_PROGRAM) + if (current_program[meep->event.channel]==SPECIAL_PROGRAM) break; - - if (XG_System_On && banknum==SFXBANK && !tonebank[SFXBANK] && tonebank[120]) - banknum = 120; - - /*if (current_config_pc42b) pcmap(&banknum, &dnote, &mprog, &drumsflag);*/ - - if (drumsflag) - { - /* Mark this instrument to be loaded */ - if (!(drumset[dset]->tone[dnote].layer)) - { - drumset[dset]->tone[dnote].layer=MAGIC_LOAD_INSTRUMENT; - } - else drumset[dset]->tone[dnote].last_used = current_tune_number; - if (!channel[meep->event.channel].name) channel[meep->event.channel].name= - drumset[dset]->name; - } - if (!drumsflag) - { /* Mark this instrument to be loaded */ - if (!(tonebank[banknum]->tone[mprog].layer)) - { - tonebank[banknum]->tone[mprog].layer=MAGIC_LOAD_INSTRUMENT; - } - else tonebank[banknum]->tone[mprog].last_used = current_tune_number; - if (!channel[meep->event.channel].name) channel[meep->event.channel].name= - tonebank[banknum]->tone[mprog].name; - } - } - break; - - case ME_TONE_KIT: - if (!meep->event.a || meep->event.a == 127) - { - new_value=meep->event.a; - if (current_kit[meep->event.channel] != new_value) - current_kit[meep->event.channel]=new_value; - else - skip_this_event=1; - break; - } - else if (meep->event.a == 126) - { - if (drumset[SFXDRUM1]) /* Is this a defined tone bank? */ - new_value=meep->event.a; - else - { - ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, - "XG rhythm kit %d is undefined", meep->event.a); - skip_this_event=1; - break; - } - current_set[meep->event.channel]=SFXDRUM1; - current_kit[meep->event.channel]=new_value; - break; - } - else if (meep->event.a != SFX_BANKTYPE) - { - ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, - "XG kit %d is impossible", meep->event.a); - skip_this_event=1; - break; - } - - if (current_kit[meep->event.channel]) - { - skip_this_event=1; - break; - } - if (tonebank[SFXBANK] || tonebank[120]) /* Is this a defined tone bank? */ - new_value=SFX_BANKTYPE; - else - { - ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, - "XG Sfx bank is undefined"); - skip_this_event=1; - break; + if (!(song->tonebank[current_bank[meep->event.channel]] + ->instrument[current_program[meep->event.channel]])) + song->tonebank[current_bank[meep->event.channel]] + ->instrument[current_program[meep->event.channel]] = + MAGIC_LOAD_INSTRUMENT; } - if (current_banktype[meep->event.channel]!=new_value) - current_banktype[meep->event.channel]=new_value; - else - skip_this_event=1; break; case ME_TONE_BANK: - if (current_kit[meep->event.channel]) + if (ISDRUMCHANNEL(song, meep->event.channel)) { skip_this_event=1; break; } - if (XG_System_On && meep->event.a > 0 && meep->event.a < 48) { - channel[meep->event.channel].variationbank=meep->event.a; - ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, - "XG variation bank %d", meep->event.a); - new_value=meep->event.a=0; - } - else if (tonebank[meep->event.a]) /* Is this a defined tone bank? */ + if (song->tonebank[meep->event.a]) /* Is this a defined tone bank? */ new_value=meep->event.a; else { - ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, - "Tone bank %d is undefined", meep->event.a); + SNDDBG(("Tone bank %d is undefined\n", meep->event.a)); new_value=meep->event.a=0; } - if (current_bank[meep->event.channel]!=new_value) current_bank[meep->event.channel]=new_value; else skip_this_event=1; break; - - case ME_HARMONICCONTENT: - channel[meep->event.channel].harmoniccontent=meep->event.a; - break; - case ME_BRIGHTNESS: - channel[meep->event.channel].brightness=meep->event.a; - break; - } /* Recompute time in samples*/ if ((dt=meep->event.time - at) && !counting_time) { - samples_to_do=sample_increment * dt; - sample_cum += sample_correction * dt; + samples_to_do = song->sample_increment * dt; + sample_cum += song->sample_correction * dt; if (sample_cum & 0xFFFF0000) { samples_to_do += ((sample_cum >> 16) & 0xFFFF); @@ -931,143 +480,98 @@ static MidiEvent *groom_list(int32 divisions,int32 *eventsp,int32 *samplesp) lp->time=st; lp->type=ME_EOT; our_event_count++; - free_midi_list(); - + free_midi_list(song); + *eventsp=our_event_count; *samplesp=st; return groomed_list; } -MidiEvent *read_midi_file(SDL_RWops *mrw, int32 *count, int32 *sp) +MidiEvent *read_midi_file(MidiSong *song, Sint32 *count, Sint32 *sp) { - int32 len, divisions; - int16 format, tracks, divisions_tmp; + Sint32 len, divisions; + Sint16 format, tracks, divisions_tmp; int i; char tmp[4]; - rw = mrw; - event_count=0; - at=0; - evlist=0; + song->event_count=0; + song->at=0; + song->evlist=0; - GM_System_On=GS_System_On=XG_System_On=0; - /* vol_table = def_vol_table; */ - XG_System_reverb_type=XG_System_chorus_type=XG_System_variation_type=0; - memset(&drumvolume,-1,sizeof(drumvolume)); - memset(&drumchorusdepth,-1,sizeof(drumchorusdepth)); - memset(&drumreverberation,-1,sizeof(drumreverberation)); - memset(&drumpanpot,NO_PANNING,sizeof(drumpanpot)); - - for (i=0; irw, tmp, 1, 4) != 4 || SDL_RWread(song->rw, &len, 4, 1) != 1) { - /* if (ferror(fp)) - { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s", current_filename, - strerror(errno)); - } - else*/ - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "%s: Not a MIDI file!", current_filename); + SNDDBG(("Not a MIDI file!\n")); return 0; } - len=BE_LONG(len); - - if (!memcmp(tmp, "RIFF", 4)) - { - SDL_RWread(rw,tmp,1,12); - goto past_riff; - } + len=SDL_SwapBE32(len); if (memcmp(tmp, "MThd", 4) || len < 6) { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "%s: Not a MIDI file!", current_filename); + SNDDBG(("Not a MIDI file!\n")); return 0; } - SDL_RWread(rw,&format, 2, 1); - SDL_RWread(rw,&tracks, 2, 1); - SDL_RWread(rw,&divisions_tmp, 2, 1); - format=BE_SHORT(format); - tracks=BE_SHORT(tracks); - track_info = tracks; - curr_track = 0; - curr_title_track = -1; - divisions_tmp=BE_SHORT(divisions_tmp); + SDL_RWread(song->rw, &format, 2, 1); + SDL_RWread(song->rw, &tracks, 2, 1); + SDL_RWread(song->rw, &divisions_tmp, 2, 1); + format=SDL_SwapBE16(format); + tracks=SDL_SwapBE16(tracks); + divisions_tmp=SDL_SwapBE16(divisions_tmp); if (divisions_tmp<0) { /* SMPTE time -- totally untested. Got a MIDI file that uses this? */ divisions= - (int32)(-(divisions_tmp/256)) * (int32)(divisions_tmp & 0xFF); + (Sint32)(-(divisions_tmp/256)) * (Sint32)(divisions_tmp & 0xFF); } - else divisions=(int32)(divisions_tmp); + else divisions=(Sint32)(divisions_tmp); if (len > 6) { - ctl->cmsg(CMSG_WARNING, VERB_NORMAL, - "%s: MIDI file header size %ld bytes", - current_filename, len); - SDL_RWseek(rw, len-6, RW_SEEK_CUR); /* skip the excess */ + SNDDBG(("MIDI file header size %u bytes", len)); + SDL_RWseek(song->rw, len-6, RW_SEEK_CUR); /* skip the excess */ } if (format<0 || format >2) { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "%s: Unknown MIDI file format %d", current_filename, format); + SNDDBG(("Unknown MIDI file format %d\n", format)); return 0; } - ctl->cmsg(CMSG_INFO, VERB_VERBOSE, - "Format: %d Tracks: %d Divisions: %d", format, tracks, divisions); + SNDDBG(("Format: %d Tracks: %d Divisions: %d\n", + format, tracks, divisions)); /* Put a do-nothing event first in the list for easier processing */ - evlist=safe_malloc(sizeof(MidiEventList)); - evlist->event.time=0; - evlist->event.type=ME_NONE; - evlist->next=0; - event_count++; + song->evlist=safe_malloc(sizeof(MidiEventList)); + song->evlist->event.time=0; + song->evlist->event.type=ME_NONE; + song->evlist->next=0; + song->event_count++; switch(format) { case 0: - if (read_track(0)) + if (read_track(song, 0)) { - free_midi_list(); + free_midi_list(song); return 0; } - else curr_track++; break; case 1: for (i=0; i This program is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License, available in COPYING. - */ - -typedef struct { - MidiEvent event; - void *next; -} MidiEventList; - -extern int32 quietchannels; -extern MidiEvent *read_midi_file(SDL_RWops *mrw, int32 *count, int32 *sp); + readmidi.h + + */ -extern char midi_name[FILENAME_MAX+1]; +extern MidiEvent *read_midi_file(MidiSong *song, Sint32 *count, Sint32 *sp); diff --git a/timidity/resample.c b/timidity/resample.c index f8b018c1..71735a21 100644 --- a/timidity/resample.c +++ b/timidity/resample.c @@ -1,71 +1,51 @@ /* + TiMidity -- Experimental MIDI to WAVE converter Copyright (C) 1995 Tuukka Toivonen This program is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License, available in COPYING. - */ + + resample.c +*/ + +#if HAVE_CONFIG_H +# include +#endif #include #include #include -#include "config.h" +#include "SDL.h" + +#include "timidity.h" +#include "options.h" #include "common.h" #include "instrum.h" #include "playmidi.h" -#include "output.h" -#include "ctrlmode.h" #include "tables.h" #include "resample.h" -#ifdef LINEAR_INTERPOLATION -# if defined(LOOKUP_HACK) && defined(LOOKUP_INTERPOLATION) -# define RESAMPLATION \ - v1=src[ofs>>FRACTION_BITS];\ - v2=src[(ofs>>FRACTION_BITS)+1];\ - *dest++ = (resample_t)(v1 + (iplookup[(((v2-v1)<<5) & 0x03FE0) | \ - ((ofs & FRACTION_MASK) >> (FRACTION_BITS-5))])); -# else -# define RESAMPLATION \ - v1=src[ofs>>FRACTION_BITS];\ - v2=src[(ofs>>FRACTION_BITS)+1];\ - *dest++ = (resample_t)(v1 + (((v2-v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS)); -# endif -# define INTERPVARS sample_t v1, v2 -#else -/* Earplugs recommended for maximum listening enjoyment */ -# define RESAMPLATION *dest++ = src[ofs>>FRACTION_BITS]; -# define INTERPVARS -#endif - -#define FINALINTERP if (ofs == le) *dest++=src[ofs>>FRACTION_BITS]; -/* So it isn't interpolation. At least it's final. */ - -extern resample_t *resample_buffer; - /*************** resampling with fixed increment *****************/ -static resample_t *rs_plain(int v, int32 *countptr) +static sample_t *rs_plain(MidiSong *song, int v, Sint32 *countptr) { /* Play sample until end, then free the voice. */ - INTERPVARS; + sample_t v1, v2; Voice - *vp=&voice[v]; - resample_t - *dest=resample_buffer; + *vp=&(song->voice[v]); sample_t + *dest=song->resample_buffer, *src=vp->sample->data; - int32 + Sint32 ofs=vp->sample_offset, incr=vp->sample_increment, le=vp->sample->data_length, count=*countptr; - -#ifdef PRECALC_LOOPS - int32 i, j; + Sint32 i; if (incr<0) incr = -incr; /* In case we're coming out of a bidir loop */ @@ -80,61 +60,42 @@ static resample_t *rs_plain(int v, int32 *countptr) } else count -= i; - for(j = 0; j < i; j++) + while (i--) { - RESAMPLATION; + v1 = src[ofs >> FRACTION_BITS]; + v2 = src[(ofs >> FRACTION_BITS)+1]; + *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS); ofs += incr; } if (ofs >= le) { - FINALINTERP; + if (ofs == le) + *dest++ = src[ofs >> FRACTION_BITS]; vp->status=VOICE_FREE; - ctl->note(v); *countptr-=count+1; } - -#else /* PRECALC_LOOPS */ - while (count--) - { - RESAMPLATION; - ofs += incr; - if (ofs >= le) - { - FINALINTERP; - vp->status=VOICE_FREE; - ctl->note(v); - *countptr-=count+1; - break; - } - } -#endif /* PRECALC_LOOPS */ vp->sample_offset=ofs; /* Update offset */ - return resample_buffer; + return song->resample_buffer; } -static resample_t *rs_loop(Voice *vp, int32 count) +static sample_t *rs_loop(MidiSong *song, Voice *vp, Sint32 count) { /* Play sample until end-of-loop, skip back and continue. */ - INTERPVARS; - int32 + sample_t v1, v2; + Sint32 ofs=vp->sample_offset, incr=vp->sample_increment, le=vp->sample->loop_end, ll=le - vp->sample->loop_start; - resample_t - *dest=resample_buffer; sample_t + *dest=song->resample_buffer, *src=vp->sample->data; - -#ifdef PRECALC_LOOPS - int32 i; - - if (ofs < 0 || le < 0) return resample_buffer; - + Sint32 i; + while (count) { if (ofs >= le) @@ -148,42 +109,31 @@ static resample_t *rs_loop(Voice *vp, int32 count) count = 0; } else count -= i; - if (i > 0) while (i--) { - RESAMPLATION; + v1 = src[ofs >> FRACTION_BITS]; + v2 = src[(ofs >> FRACTION_BITS)+1]; + *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS); ofs += incr; } } -#else - while (count--) - { - RESAMPLATION; - ofs += incr; - if (ofs>=le) - ofs -= ll; /* Hopefully the loop is longer than an increment. */ - } -#endif vp->sample_offset=ofs; /* Update offset */ - return resample_buffer; + return song->resample_buffer; } -static resample_t *rs_bidir(Voice *vp, int32 count) +static sample_t *rs_bidir(MidiSong *song, Voice *vp, Sint32 count) { - INTERPVARS; - int32 + sample_t v1, v2; + Sint32 ofs=vp->sample_offset, incr=vp->sample_increment, le=vp->sample->loop_end, ls=vp->sample->loop_start; - resample_t - *dest=resample_buffer; sample_t + *dest=song->resample_buffer, *src=vp->sample->data; - -#ifdef PRECALC_LOOPS - int32 + Sint32 le2 = le<<1, ls2 = ls<<1, i; @@ -203,7 +153,9 @@ static resample_t *rs_bidir(Voice *vp, int32 count) else count -= i; while (i--) { - RESAMPLATION; + v1 = src[ofs >> FRACTION_BITS]; + v2 = src[(ofs >> FRACTION_BITS)+1]; + *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS); ofs += incr; } } @@ -222,7 +174,9 @@ static resample_t *rs_bidir(Voice *vp, int32 count) else count -= i; while (i--) { - RESAMPLATION; + v1 = src[ofs >> FRACTION_BITS]; + v2 = src[(ofs >> FRACTION_BITS)+1]; + *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS); ofs += incr; } if (ofs>=le) @@ -238,43 +192,9 @@ static resample_t *rs_bidir(Voice *vp, int32 count) } } -#else /* PRECALC_LOOPS */ - /* Play normally until inside the loop region */ - - if (ofs < ls) - { - while (count--) - { - RESAMPLATION; - ofs += incr; - if (ofs>=ls) - break; - } - } - - /* Then do the bidirectional looping */ - - if (count>0) - while (count--) - { - RESAMPLATION; - ofs += incr; - if (ofs>=le) - { - /* fold the overshoot back in */ - ofs = le - (ofs - le); - incr = -incr; - } - else if (ofs <= ls) - { - ofs = ls + (ls - ofs); - incr = -incr; - } - } -#endif /* PRECALC_LOOPS */ vp->sample_increment=incr; vp->sample_offset=ofs; /* Update offset */ - return resample_buffer; + return song->resample_buffer; } /*********************** vibrato versions ***************************/ @@ -290,9 +210,9 @@ static int vib_phase_to_inc_ptr(int phase) return phase-VIBRATO_SAMPLE_INCREMENTS/2; } -static int32 update_vibrato(Voice *vp, int sign) +static Sint32 update_vibrato(MidiSong *song, Voice *vp, int sign) { - int32 depth; + Sint32 depth; int phase, pb; double a; @@ -329,7 +249,7 @@ static int32 update_vibrato(Voice *vp, int sign) a = FSCALE(((double)(vp->sample->sample_rate) * (double)(vp->frequency)) / ((double)(vp->sample->root_freq) * - (double)(play_mode->rate)), + (double)(song->rate)), FRACTION_BITS); pb=(int)((sine(vp->vibrato_phase * @@ -346,26 +266,25 @@ static int32 update_vibrato(Voice *vp, int sign) /* If the sweep's over, we can store the newly computed sample_increment */ if (!vp->vibrato_sweep) - vp->vibrato_sample_increment[phase]=(int32) a; + vp->vibrato_sample_increment[phase]=(Sint32) a; if (sign) a = -a; /* need to preserve the loop direction */ - return (int32) a; + return (Sint32) a; } -static resample_t *rs_vib_plain(int v, int32 *countptr) +static sample_t *rs_vib_plain(MidiSong *song, int v, Sint32 *countptr) { /* Play sample until end, then free the voice. */ - INTERPVARS; - Voice *vp=&voice[v]; - resample_t - *dest=resample_buffer; + sample_t v1, v2; + Voice *vp=&(song->voice[v]); sample_t + *dest=song->resample_buffer, *src=vp->sample->data; - int32 + Sint32 le=vp->sample->data_length, ofs=vp->sample_offset, incr=vp->sample_increment, @@ -382,15 +301,17 @@ static resample_t *rs_vib_plain(int v, int32 *countptr) if (!cc--) { cc=vp->vibrato_control_ratio; - incr=update_vibrato(vp, 0); + incr=update_vibrato(song, vp, 0); } - RESAMPLATION; + v1 = src[ofs >> FRACTION_BITS]; + v2 = src[(ofs >> FRACTION_BITS)+1]; + *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS); ofs += incr; if (ofs >= le) { - FINALINTERP; + if (ofs == le) + *dest++ = src[ofs >> FRACTION_BITS]; vp->status=VOICE_FREE; - ctl->note(v); *countptr-=count+1; break; } @@ -399,29 +320,26 @@ static resample_t *rs_vib_plain(int v, int32 *countptr) vp->vibrato_control_counter=cc; vp->sample_increment=incr; vp->sample_offset=ofs; /* Update offset */ - return resample_buffer; + return song->resample_buffer; } -static resample_t *rs_vib_loop(Voice *vp, int32 count) +static sample_t *rs_vib_loop(MidiSong *song, Voice *vp, Sint32 count) { /* Play sample until end-of-loop, skip back and continue. */ - INTERPVARS; - int32 + sample_t v1, v2; + Sint32 ofs=vp->sample_offset, incr=vp->sample_increment, le=vp->sample->loop_end, ll=le - vp->sample->loop_start; - resample_t - *dest=resample_buffer; sample_t + *dest=song->resample_buffer, *src=vp->sample->data; int cc=vp->vibrato_control_counter; - -#ifdef PRECALC_LOOPS - int32 i; + Sint32 i; int vibflag=0; @@ -443,55 +361,39 @@ static resample_t *rs_vib_loop(Voice *vp, int32 count) count -= i; while(i--) { - RESAMPLATION; + v1 = src[ofs >> FRACTION_BITS]; + v2 = src[(ofs >> FRACTION_BITS)+1]; + *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS); ofs += incr; } if(vibflag) { cc = vp->vibrato_control_ratio; - incr = update_vibrato(vp, 0); + incr = update_vibrato(song, vp, 0); vibflag = 0; } } -#else /* PRECALC_LOOPS */ - while (count--) - { - if (!cc--) - { - cc=vp->vibrato_control_ratio; - incr=update_vibrato(vp, 0); - } - RESAMPLATION; - ofs += incr; - if (ofs>=le) - ofs -= ll; /* Hopefully the loop is longer than an increment. */ - } -#endif /* PRECALC_LOOPS */ - vp->vibrato_control_counter=cc; vp->sample_increment=incr; vp->sample_offset=ofs; /* Update offset */ - return resample_buffer; + return song->resample_buffer; } -static resample_t *rs_vib_bidir(Voice *vp, int32 count) +static sample_t *rs_vib_bidir(MidiSong *song, Voice *vp, Sint32 count) { - INTERPVARS; - int32 + sample_t v1, v2; + Sint32 ofs=vp->sample_offset, incr=vp->sample_increment, le=vp->sample->loop_end, ls=vp->sample->loop_start; - resample_t - *dest=resample_buffer; sample_t + *dest=song->resample_buffer, *src=vp->sample->data; int cc=vp->vibrato_control_counter; - -#ifdef PRECALC_LOOPS - int32 + Sint32 le2=le<<1, ls2=ls<<1, i; @@ -512,13 +414,15 @@ static resample_t *rs_vib_bidir(Voice *vp, int32 count) count -= i; while (i--) { - RESAMPLATION; + v1 = src[ofs >> FRACTION_BITS]; + v2 = src[(ofs >> FRACTION_BITS)+1]; + *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS); ofs += incr; } if (vibflag) { cc = vp->vibrato_control_ratio; - incr = update_vibrato(vp, 0); + incr = update_vibrato(song, vp, 0); vibflag = 0; } } @@ -539,13 +443,15 @@ static resample_t *rs_vib_bidir(Voice *vp, int32 count) count -= i; while (i--) { - RESAMPLATION; + v1 = src[ofs >> FRACTION_BITS]; + v2 = src[(ofs >> FRACTION_BITS)+1]; + *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS); ofs += incr; } if (vibflag) { cc = vp->vibrato_control_ratio; - incr = update_vibrato(vp, (incr < 0)); + incr = update_vibrato(song, vp, (incr < 0)); vibflag = 0; } if (ofs >= le) @@ -561,62 +467,17 @@ static resample_t *rs_vib_bidir(Voice *vp, int32 count) } } -#else /* PRECALC_LOOPS */ - /* Play normally until inside the loop region */ - - if (ofs < ls) - { - while (count--) - { - if (!cc--) - { - cc=vp->vibrato_control_ratio; - incr=update_vibrato(vp, 0); - } - RESAMPLATION; - ofs += incr; - if (ofs>=ls) - break; - } - } - - /* Then do the bidirectional looping */ - - if (count>0) - while (count--) - { - if (!cc--) - { - cc=vp->vibrato_control_ratio; - incr=update_vibrato(vp, (incr < 0)); - } - RESAMPLATION; - ofs += incr; - if (ofs>=le) - { - /* fold the overshoot back in */ - ofs = le - (ofs - le); - incr = -incr; - } - else if (ofs <= ls) - { - ofs = ls + (ls - ofs); - incr = -incr; - } - } -#endif /* PRECALC_LOOPS */ - vp->vibrato_control_counter=cc; vp->sample_increment=incr; vp->sample_offset=ofs; /* Update offset */ - return resample_buffer; + return song->resample_buffer; } -resample_t *resample_voice(int v, int32 *countptr) +sample_t *resample_voice(MidiSong *song, int v, Sint32 *countptr) { - int32 ofs; - uint8 modes; - Voice *vp=&voice[v]; + Sint32 ofs; + Uint8 modes; + Voice *vp=&(song->voice[v]); if (!(vp->sample->sample_rate)) { @@ -628,7 +489,6 @@ resample_t *resample_voice(int v, int32 *countptr) { /* Note finished. Free the voice. */ vp->status = VOICE_FREE; - ctl->note(v); /* Let the caller know how much data we had left */ *countptr = (vp->sample->data_length>>FRACTION_BITS) - ofs; @@ -636,7 +496,7 @@ resample_t *resample_voice(int v, int32 *countptr) else vp->sample_offset += *countptr << FRACTION_BITS; - return (resample_t *)vp->sample->data+ofs; + return vp->sample->data+ofs; } /* Need to resample. Use the proper function. */ @@ -649,12 +509,12 @@ resample_t *resample_voice(int v, int32 *countptr) (vp->status==VOICE_ON || vp->status==VOICE_SUSTAINED))) { if (modes & MODES_PINGPONG) - return rs_vib_bidir(vp, *countptr); + return rs_vib_bidir(song, vp, *countptr); else - return rs_vib_loop(vp, *countptr); + return rs_vib_loop(song, vp, *countptr); } else - return rs_vib_plain(v, countptr); + return rs_vib_plain(song, v, countptr); } else { @@ -663,36 +523,35 @@ resample_t *resample_voice(int v, int32 *countptr) (vp->status==VOICE_ON || vp->status==VOICE_SUSTAINED))) { if (modes & MODES_PINGPONG) - return rs_bidir(vp, *countptr); + return rs_bidir(song, vp, *countptr); else - return rs_loop(vp, *countptr); + return rs_loop(song, vp, *countptr); } else - return rs_plain(v, countptr); + return rs_plain(song, v, countptr); } } -void pre_resample(Sample * sp) +void pre_resample(MidiSong *song, Sample *sp) { double a, xdiff; - int32 incr, ofs, newlen, count; - int16 *src = (int16 *) sp->data; - resample_t *newdata, *dest; - int16 v1, v2, v3, v4, *vptr; + Sint32 incr, ofs, newlen, count; + Sint16 *newdata, *dest, *src = (Sint16 *) sp->data; + Sint16 v1, v2, v3, v4, *vptr; +#ifdef DEBUG_CHATTER static const char note_name[12][3] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" }; - ctl->cmsg(CMSG_INFO, VERB_NOISY, " * pre-resampling for note %d (%s%d)", - sp->note_to_use, - note_name[sp->note_to_use % 12], (sp->note_to_use & 0x7F) / 12); + SNDDBG((" * pre-resampling for note %d (%s%d)\n", + sp->note_to_use, + note_name[sp->note_to_use % 12], (sp->note_to_use & 0x7F) / 12)); +#endif a = ((double) (sp->sample_rate) * freq_table[(int) (sp->note_to_use)]) / - ((double) (sp->root_freq) * play_mode->rate); - if (a <= 0) return; - newlen = (int32)(sp->data_length / a); - if (newlen < 0 || (newlen >> FRACTION_BITS) > MAX_SAMPLE_SIZE) return; + ((double) (sp->root_freq) * song->rate); + newlen = (Sint32)(sp->data_length / a); dest = newdata = safe_malloc(newlen >> (FRACTION_BITS - 1)); count = (newlen >> FRACTION_BITS) - 1; @@ -706,12 +565,17 @@ void pre_resample(Sample * sp) while (--count) { vptr = src + (ofs >> FRACTION_BITS); + /* + * Electric Fence to the rescue: Accessing *(vptr - 1) is not a + * good thing to do when vptr <= src. (TiMidity++ has a similar + * safe-guard here.) + */ v1 = (vptr == src) ? *vptr : *(vptr - 1); v2 = *vptr; v3 = *(vptr + 1); v4 = *(vptr + 2); xdiff = FSCALENEG(ofs & FRACTION_MASK, FRACTION_BITS); - *dest++ = (int16)(v2 + (xdiff / 6.0) * (-2 * v1 - 3 * v2 + 6 * v3 - v4 + + *dest++ = (Sint16)(v2 + (xdiff / 6.0) * (-2 * v1 - 3 * v2 + 6 * v3 - v4 + xdiff * (3 * (v1 - 2 * v2 + v3) + xdiff * (-v1 + 3 * (v2 - v3) + v4)))); ofs += incr; } @@ -720,14 +584,14 @@ void pre_resample(Sample * sp) { v1 = src[ofs >> FRACTION_BITS]; v2 = src[(ofs >> FRACTION_BITS) + 1]; - *dest++ = (resample_t)(v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS)); + *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS); } else *dest++ = src[ofs >> FRACTION_BITS]; sp->data_length = newlen; - sp->loop_start = (int32)(sp->loop_start / a); - sp->loop_end = (int32)(sp->loop_end / a); + sp->loop_start = (Sint32)(sp->loop_start / a); + sp->loop_end = (Sint32)(sp->loop_end / a); free(sp->data); sp->data = (sample_t *) newdata; sp->sample_rate = 0; diff --git a/timidity/resample.h b/timidity/resample.h index ee242893..10081e1c 100644 --- a/timidity/resample.h +++ b/timidity/resample.h @@ -1,10 +1,13 @@ /* + TiMidity -- Experimental MIDI to WAVE converter Copyright (C) 1995 Tuukka Toivonen This program is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License, available in COPYING. - */ -extern resample_t *resample_voice(int v, int32 *countptr); -extern void pre_resample(Sample *sp); + resample.h +*/ + +extern sample_t *resample_voice(MidiSong *song, int v, Sint32 *countptr); +extern void pre_resample(MidiSong *song, Sample *sp); diff --git a/timidity/sdl_c.c b/timidity/sdl_c.c deleted file mode 100644 index 5f1f5e3f..00000000 --- a/timidity/sdl_c.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - TiMidity -- Experimental MIDI to WAVE converter - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the Perl Artistic License, available in COPYING. - */ - -#include -#include -#include - -#include "config.h" -#include "common.h" -#include "output.h" -#include "ctrlmode.h" -#include "instrum.h" -#include "playmidi.h" - -static void ctl_refresh(void); -static void ctl_total_time(int tt); -static void ctl_master_volume(int mv); -static void ctl_file_name(char *name); -static void ctl_current_time(int ct); -static void ctl_note(int v); -static void ctl_program(int ch, int val); -static void ctl_volume(int channel, int val); -static void ctl_expression(int channel, int val); -static void ctl_panning(int channel, int val); -static void ctl_sustain(int channel, int val); -static void ctl_pitch_bend(int channel, int val); -static void ctl_reset(void); -static int ctl_open(int using_stdin, int using_stdout); -static void ctl_close(void); -static int ctl_read(int32 *valp); -static int cmsg(int type, int verbosity_level, char *fmt, ...); - -/**********************************/ -/* export the interface functions */ - -#define ctl sdl_control_mode - -ControlMode ctl= -{ - "SDL interface", 's', - 1,0,0, - ctl_open,NULL, ctl_close, ctl_read, cmsg, - ctl_refresh, ctl_reset, ctl_file_name, ctl_total_time, ctl_current_time, - ctl_note, - ctl_master_volume, ctl_program, ctl_volume, - ctl_expression, ctl_panning, ctl_sustain, ctl_pitch_bend -}; - -static int ctl_open(int using_stdin, int using_stdout) -{ - ctl.opened=1; - return 0; -} - -static void ctl_close(void) -{ - ctl.opened=0; -} - -static int ctl_read(int32 *valp) -{ - return RC_NONE; -} - -static int cmsg(int type, int verbosity_level, char *fmt, ...) -{ -#ifdef GREGS_DEBUG - va_list ap; - int flag_newline = 1; - if ((type==CMSG_TEXT || type==CMSG_INFO || type==CMSG_WARNING) && - ctl.verbosity This program is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License, available in COPYING. - */ +*/ + +#if HAVE_CONFIG_H +# include +#endif #include -#include "config.h" -#include "common.h" + +#include "SDL.h" + #include "tables.h" -#include "instrum.h" -int32 freq_table[128]= +const Sint32 freq_table[128]= { 8176, 8662, 9177, 9723, 10301, 10913, 11562, 12250, @@ -59,7 +64,7 @@ int32 freq_table[128]= }; /* v=2.^((x/127-1) * 6) */ -double vol_table[128] = +const double vol_table[128] = { 0.015625, 0.016145143728351113, 0.016682602624583379, 0.017237953096759438, 0.017811790741104401, 0.01840473098076444, 0.019017409725829021, 0.019650484055324921, @@ -95,44 +100,7 @@ double vol_table[128] = 0.90643012614631979, 0.93660445864574493, 0.96778327049280244, 1 }; - -/* v=2.^((x/127-1) * 4) */ -FLOAT_T expr_table[128] = { -0.062500000000000000, 0.063879466007418617, 0.065289378838287213, 0.066730410498333517, -0.068203247825430205, 0.069708592816961873, 0.071247162964417632, 0.072819691595368496, -0.074426928222992794, 0.076069638903316056, 0.077748606600335793, 0.079464631559205010, -0.081218531687652529, 0.083011142945821639, 0.084843319744713291, 0.086715935353423396, -0.088629882315368322, 0.090586072873697340, 0.092585439406094330, 0.094628934869176312, -0.096717533252700480, 0.098852230043796174, 0.101034042701443255, 0.103264011141422821, -0.105543198231971461, 0.107872690300375454, 0.110253597650746091, 0.112687055093223104, -0.115174222484858521, 0.117716285282438229, 0.120314455107505686, 0.122969970323856051, -0.125684096627776631, 0.128458127651314785, 0.131293385578860888, 0.134191221777339997, -0.137153017440313080, 0.140180184246293943, 0.143274165031597039, 0.146436434478035005, -0.149668499815795553, 0.152971901541831212, 0.156348214154105547, 0.159799046902044661, -0.163326044553552957, 0.166930888178957210, 0.170615295952254331, 0.174381023970043153, -0.178229867088531585, 0.182163659779017467, 0.186184277002251486, 0.190293635102098180, -0.194493692718921724, 0.198786451723130919, 0.203173958169329677, 0.207658303271526207, -0.212241624399866963, 0.216926106099369798, 0.221713981131142046, 0.226607531536579865, -0.231609089725056033, 0.236721039585614190, 0.241945817623200610, 0.247285914119973582, -0.252743874322244710, 0.258322299653617804, 0.264023848954903828, 0.269851239751401739, -0.275807249548151001, 0.281894717153771790, 0.288116544033524102, 0.294475695692230921, -0.300975203087725074, 0.307618164075491973, 0.314407744885198681, 0.321347181629811129, -0.328439781848020751, 0.335688926080714045, 0.343098069482237422, 0.350670743467224599, -0.358410557393772644, 0.366321200283767356, 0.374406442581179333, 0.382670137949167655, -0.391116225106848792, 0.399748729706605410, 0.408571766252830038, 0.417589540063018294, -0.426806349272146446, 0.436226586881288292, 0.445854742851448105, 0.455695406243607215, -0.465753267406005200, 0.476033120209697069, 0.486539864333452310, 0.497278507599085373, -0.508254168358330150, 0.519472077932396359, 0.530937583105370092, 0.542656148672647887, -0.554633360045617918, 0.566874925913830707, 0.579386680965928047, 0.592174588670625557, -0.605244744119077360, 0.618603376929974136, 0.632256854218762432, 0.646211683632397893, -0.660474516451080240, 0.675052150758448599, 0.689951534681746304, 0.705179769703502823, -0.720744114046307338, 0.736651986132290215, 0.752910968118960744, 0.769528809513084777, -0.786513430864326790, 0.803872927540415394, 0.821615573585632974, 0.839749825664467098, -0.858284327092304622, 0.877227911955088646, 0.896589609319902503, 0.916378647538487301, -0.936604458645744820, 0.957276682855321193, 0.978405173154415220, 1.000000000000000000 -}; - -double bend_fine[256] = { +const double bend_fine[256] = { 1, 1.0002256593050698, 1.0004513695322617, 1.0006771306930664, 1.0009029427989777, 1.0011288058614922, 1.0013547198921082, 1.0015806849023274, 1.0018067009036538, 1.002032767907594, 1.0022588859256572, 1.0024850549693551, @@ -199,7 +167,7 @@ double bend_fine[256] = { 1.0585073227945128, 1.0587461848213857, 1.058985100749698, 1.0592240705916123 }; -double bend_coarse[128] = { +const double bend_coarse[128] = { 1, 1.0594630943592953, 1.122462048309373, 1.189207115002721, 1.2599210498948732, 1.3348398541700344, 1.4142135623730951, 1.4983070768766815, 1.5874010519681994, 1.681792830507429, 1.7817974362806785, 1.8877486253633868, @@ -233,880 +201,3 @@ double bend_coarse[128] = { 1024, 1084.8902086239189, 1149.4011374687975, 1217.7480857627863, 1290.1591550923506, 1366.8760106701147, 1448.1546878700494, 1534.2664467217226 }; - -#ifdef LOOKUP_SINE -static double sine_table[257]= -{ - 0, 0.0061358846491544753, 0.012271538285719925, 0.01840672990580482, - 0.024541228522912288, 0.030674803176636626, 0.036807222941358832, 0.04293825693494082, - 0.049067674327418015, 0.055195244349689934, 0.061320736302208578, 0.067443919563664051, - 0.073564563599667426, 0.079682437971430126, 0.085797312344439894, 0.091908956497132724, - 0.098017140329560604, 0.10412163387205459, 0.11022220729388306, 0.11631863091190475, - 0.1224106751992162, 0.12849811079379317, 0.13458070850712617, 0.14065823933284921, - 0.14673047445536175, 0.15279718525844344, 0.15885814333386145, 0.16491312048996989, - 0.17096188876030122, 0.17700422041214875, 0.18303988795514095, 0.18906866414980619, - 0.19509032201612825, 0.2011046348420919, 0.20711137619221856, 0.21311031991609136, - 0.2191012401568698, 0.22508391135979283, 0.23105810828067111, 0.2370236059943672, - 0.24298017990326387, 0.24892760574572015, 0.25486565960451457, 0.26079411791527551, - 0.26671275747489837, 0.27262135544994898, 0.27851968938505306, 0.28440753721127188, - 0.29028467725446233, 0.29615088824362379, 0.30200594931922808, 0.30784964004153487, - 0.31368174039889152, 0.31950203081601569, 0.32531029216226293, 0.33110630575987643, - 0.33688985339222005, 0.34266071731199438, 0.34841868024943456, 0.35416352542049034, - 0.35989503653498811, 0.36561299780477385, 0.37131719395183754, 0.37700741021641826, - 0.38268343236508978, 0.38834504669882625, 0.3939920400610481, 0.39962419984564679, - 0.40524131400498986, 0.41084317105790391, 0.41642956009763715, 0.42200027079979968, - 0.42755509343028208, 0.43309381885315196, 0.43861623853852766, 0.4441221445704292, - 0.44961132965460654, 0.45508358712634384, 0.46053871095824001, 0.46597649576796618, - 0.47139673682599764, 0.47679923006332209, 0.48218377207912272, 0.487550160148436, - 0.49289819222978404, 0.49822766697278187, 0.50353838372571758, 0.50883014254310699, - 0.51410274419322166, 0.51935599016558964, 0.52458968267846895, 0.52980362468629461, - 0.53499761988709715, 0.54017147272989285, 0.54532498842204646, 0.55045797293660481, - 0.55557023301960218, 0.56066157619733603, 0.56573181078361312, 0.57078074588696726, - 0.57580819141784534, 0.58081395809576453, 0.58579785745643886, 0.59075970185887416, - 0.59569930449243336, 0.60061647938386897, 0.60551104140432555, 0.61038280627630948, - 0.61523159058062682, 0.6200572117632891, 0.62485948814238634, 0.62963823891492698, - 0.63439328416364549, 0.63912444486377573, 0.64383154288979139, 0.64851440102211244, - 0.65317284295377676, 0.65780669329707864, 0.66241577759017178, 0.66699992230363747, - 0.67155895484701833, 0.67609270357531592, 0.68060099779545302, 0.68508366777270036, - 0.68954054473706683, 0.693971460889654, 0.69837624940897292, 0.7027547444572253, - 0.70710678118654746, 0.71143219574521643, 0.71573082528381859, 0.72000250796138165, - 0.72424708295146689, 0.7284643904482252, 0.73265427167241282, 0.73681656887736979, - 0.74095112535495911, 0.74505778544146595, 0.74913639452345926, 0.75318679904361241, - 0.75720884650648446, 0.76120238548426178, 0.76516726562245896, 0.76910333764557959, - 0.77301045336273699, 0.77688846567323244, 0.78073722857209438, 0.78455659715557524, - 0.78834642762660623, 0.79210657730021239, 0.79583690460888346, 0.79953726910790501, - 0.80320753148064483, 0.80684755354379922, 0.81045719825259477, 0.8140363297059483, - 0.81758481315158371, 0.82110251499110465, 0.82458930278502529, 0.8280450452577558, - 0.83146961230254524, 0.83486287498638001, 0.83822470555483797, 0.84155497743689833, - 0.84485356524970701, 0.84812034480329712, 0.8513551931052652, 0.85455798836540053, - 0.85772861000027212, 0.86086693863776731, 0.8639728561215867, 0.86704624551569265, - 0.87008699110871135, 0.87309497841829009, 0.8760700941954066, 0.87901222642863341, - 0.88192126434835494, 0.88479709843093779, 0.88763962040285393, 0.89044872324475788, - 0.89322430119551532, 0.89596624975618511, 0.89867446569395382, 0.90134884704602203, - 0.90398929312344334, 0.90659570451491533, 0.90916798309052227, 0.91170603200542988, - 0.91420975570353069, 0.9166790599210427, 0.91911385169005777, 0.9215140393420419, - 0.92387953251128674, 0.92621024213831127, 0.92850608047321548, 0.93076696107898371, - 0.93299279883473885, 0.9351835099389475, 0.93733901191257496, 0.93945922360218992, - 0.94154406518302081, 0.94359345816196039, 0.94560732538052128, 0.94758559101774109, - 0.94952818059303667, 0.95143502096900834, 0.95330604035419375, 0.95514116830577067, - 0.95694033573220894, 0.9587034748958716, 0.96043051941556579, 0.96212140426904158, - 0.96377606579543984, 0.9653944416976894, 0.96697647104485207, 0.96852209427441727, - 0.97003125319454397, 0.97150389098625178, 0.97293995220556007, 0.97433938278557586, - 0.97570213003852857, 0.97702814265775439, 0.97831737071962765, 0.97956976568544052, - 0.98078528040323043, 0.98196386910955524, 0.98310548743121629, 0.98421009238692903, - 0.98527764238894122, 0.98630809724459867, 0.98730141815785843, 0.98825756773074946, - 0.98917650996478101, 0.99005821026229712, 0.99090263542778001, 0.99170975366909953, - 0.99247953459870997, 0.9932119492347945, 0.99390697000235606, 0.99456457073425542, - 0.99518472667219682, 0.99576741446765982, 0.996312612182778, 0.99682029929116567, - 0.99729045667869021, 0.99772306664419164, 0.99811811290014918, 0.99847558057329477, - 0.99879545620517241, 0.99907772775264536, 0.99932238458834954, 0.99952941750109314, - 0.99969881869620425, 0.9998305817958234, 0.9999247018391445, 0.99998117528260111, - 1 -}; - -/* - looks up sin(2 * Pi * x / 1024) -*/ -FLOAT_T sine(int x) -{ - int xx = x & 0xFF; - switch ((x>>8) & 0x03) - { - default: /* just to shut gcc up. */ - case 0: - return sine_table[xx]; - case 1: - return sine_table[0x100 - xx]; - case 2: - return -sine_table[xx]; - case 3: - return -sine_table[0x100 - xx]; - } -} -#endif /* LOOKUP_SINE */ - -#ifdef LOOKUP_HACK -int16 _u2l[] = -{ - -32256, -31228, -30200, -29172, -28143, -27115, -26087, -25059, - -24031, -23002, -21974, -20946, -19918, -18889, -17861, -16833, - -16062, -15548, -15033, -14519, -14005, -13491, -12977, -12463, - -11949, -11435, -10920, -10406, -9892, -9378, -8864, -8350, - -7964, -7707, -7450, -7193, -6936, -6679, -6422, -6165, - -5908, -5651, -5394, -5137, -4880, -4623, -4365, -4108, - -3916, -3787, -3659, -3530, -3402, -3273, -3144, -3016, - -2887, -2759, -2630, -2502, -2373, -2245, -2116, -1988, - -1891, -1827, -1763, -1698, -1634, -1570, -1506, -1441, - -1377, -1313, -1249, -1184, -1120, -1056, -992, -927, - -879, -847, -815, -783, -751, -718, -686, -654, - -622, -590, -558, -526, -494, -461, -429, -397, - -373, -357, -341, -325, -309, -293, -277, -261, - -245, -228, -212, -196, -180, -164, -148, -132, - -120, -112, -104, -96, -88, -80, -72, -64, - -56, -48, -40, -32, -24, -16, -8, 0, - 32256, 31228, 30200, 29172, 28143, 27115, 26087, 25059, - 24031, 23002, 21974, 20946, 19918, 18889, 17861, 16833, - 16062, 15548, 15033, 14519, 14005, 13491, 12977, 12463, - 11949, 11435, 10920, 10406, 9892, 9378, 8864, 8350, - 7964, 7707, 7450, 7193, 6936, 6679, 6422, 6165, - 5908, 5651, 5394, 5137, 4880, 4623, 4365, 4108, - 3916, 3787, 3659, 3530, 3402, 3273, 3144, 3016, - 2887, 2759, 2630, 2502, 2373, 2245, 2116, 1988, - 1891, 1827, 1763, 1698, 1634, 1570, 1506, 1441, - 1377, 1313, 1249, 1184, 1120, 1056, 992, 927, - 879, 847, 815, 783, 751, 718, 686, 654, - 622, 590, 558, 526, 494, 461, 429, 397, - 373, 357, 341, 325, 309, 293, 277, 261, - 245, 228, 212, 196, 180, 164, 148, 132, - 120, 112, 104, 96, 88, 80, 72, 64, - 56, 48, 40, 32, 24, 16, 8, 0 -}; - -int32 *mixup; -#ifdef LOOKUP_INTERPOLATION -int8 *iplookup; -#endif - -#endif - -void init_tables(void) -{ -#ifdef LOOKUP_HACK - int i,j,v; - mixup=safe_malloc(1<<(7+8+2)); /* Give your cache a workout! */ - - for (i=0; i<128; i++) - { - v=_u2l[255-i]; - for (j=-128; j<128; j++) - { - mixup[ ((i & 0x7F)<<8) | (j & 0xFF)] = - (v * j) << MIXUP_SHIFT; - } - } - -#ifdef LOOKUP_INTERPOLATION - iplookup=safe_malloc(1<<(9+5)); - for (i=-256; i<256; i++) - for(j=0; j<32; j++) - iplookup[((i<<5) & 0x3FE0) | j] = (i * j)>>5; - /* I don't know. Quantum bits? Magick? */ -#endif - -#endif -} - -uint8 _l2u_[] = -{ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, - 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, - 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, - 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, - 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, - 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, - 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, - 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, - 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, - 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, - 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, - 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, - 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, - 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, - 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, - 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, - 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, - 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, - 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, - 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, - 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, - 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, - 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, - 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, - 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, - 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, - 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, - 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, - 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, - 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, - 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, - 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, - 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, - 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, - 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, - 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, - 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, - 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D, - 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, - 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, - 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, - 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1E, 0x1E, 0x1E, 0x1E, - 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, - 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, - 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, - 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, - 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, - 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, - 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, - 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2A, 0x2A, - 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, - 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2B, 0x2B, - 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, - 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2C, 0x2C, - 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, - 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2D, 0x2D, - 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, - 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2E, 0x2E, - 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, - 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2F, 0x2F, - 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, - 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3A, - 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3B, - 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3C, - 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3D, - 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, - 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, - 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, - 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, - 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, - 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, - 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, - 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, - 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x52, 0x53, 0x53, 0x53, 0x53, - 0x54, 0x54, 0x54, 0x54, 0x55, 0x55, 0x55, 0x55, 0x56, 0x56, 0x56, 0x56, 0x57, 0x57, 0x57, 0x57, - 0x58, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x59, 0x5A, 0x5A, 0x5A, 0x5A, 0x5B, 0x5B, 0x5B, 0x5B, - 0x5C, 0x5C, 0x5C, 0x5C, 0x5D, 0x5D, 0x5D, 0x5D, 0x5E, 0x5E, 0x5E, 0x5E, 0x5F, 0x5F, 0x5F, 0x5F, - 0x60, 0x60, 0x61, 0x61, 0x62, 0x62, 0x63, 0x63, 0x64, 0x64, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, - 0x68, 0x68, 0x68, 0x69, 0x69, 0x6A, 0x6A, 0x6B, 0x6B, 0x6C, 0x6C, 0x6D, 0x6D, 0x6E, 0x6E, 0x6F, - 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, - 0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8, 0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0, - 0xEF, 0xEF, 0xEE, 0xEE, 0xED, 0xED, 0xEC, 0xEC, 0xEB, 0xEB, 0xEA, 0xEA, 0xE9, 0xE9, 0xE8, 0xE8, - 0xE7, 0xE7, 0xE6, 0xE6, 0xE5, 0xE5, 0xE4, 0xE4, 0xE3, 0xE3, 0xE2, 0xE2, 0xE1, 0xE1, 0xE0, 0xE0, - 0xDF, 0xDF, 0xDF, 0xDF, 0xDE, 0xDE, 0xDE, 0xDE, 0xDD, 0xDD, 0xDD, 0xDD, 0xDC, 0xDC, 0xDC, 0xDC, - 0xDB, 0xDB, 0xDB, 0xDB, 0xDA, 0xDA, 0xDA, 0xDA, 0xD9, 0xD9, 0xD9, 0xD9, 0xD8, 0xD8, 0xD8, 0xD8, - 0xD7, 0xD7, 0xD7, 0xD7, 0xD6, 0xD6, 0xD6, 0xD6, 0xD5, 0xD5, 0xD5, 0xD5, 0xD4, 0xD4, 0xD4, 0xD4, - 0xD3, 0xD3, 0xD3, 0xD3, 0xD2, 0xD2, 0xD2, 0xD2, 0xD1, 0xD1, 0xD1, 0xD1, 0xD0, 0xD0, 0xD0, 0xD0, - 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, - 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, - 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, - 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, - 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, - 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, - 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, - 0xC2, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, - 0xC0, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, - 0xBF, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, - 0xBE, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, - 0xBD, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, - 0xBC, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, - 0xBA, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, - 0xB9, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, - 0xB8, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, - 0xB7, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, - 0xB6, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, - 0xB5, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, - 0xB4, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, - 0xB3, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, - 0xB2, 0xB2, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, - 0xB1, 0xB1, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, - 0xB0, 0xB0, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, - 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, - 0xAF, 0xAF, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, - 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, - 0xAE, 0xAE, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, - 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, - 0xAD, 0xAD, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, - 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, - 0xAC, 0xAC, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, - 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, - 0xAB, 0xAB, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, - 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, - 0xAA, 0xAA, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, - 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, - 0xA9, 0xA9, 0xA9, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, - 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, - 0xA8, 0xA8, 0xA8, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, - 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, - 0xA7, 0xA7, 0xA7, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, - 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, - 0xA6, 0xA6, 0xA6, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, - 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, - 0xA5, 0xA5, 0xA5, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, - 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, - 0xA4, 0xA4, 0xA4, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, - 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, - 0xA3, 0xA3, 0xA3, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, - 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, - 0xA2, 0xA2, 0xA2, 0xA2, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, - 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, - 0xA1, 0xA1, 0xA1, 0xA1, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, - 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, - 0xA0, 0xA0, 0xA0, 0xA0, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, - 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, - 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, - 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, - 0x9F, 0x9F, 0x9F, 0x9F, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, - 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, - 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, - 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, - 0x9E, 0x9E, 0x9E, 0x9E, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, - 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, - 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, - 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, - 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, - 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, - 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, - 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, - 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, - 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, - 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, - 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, - 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, - 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, - 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, - 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, - 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, - 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, - 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, - 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, - 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, - 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, - 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, - 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, - 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, - 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, - 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, - 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, - 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, - 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, - 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, - 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, - 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, - 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, - 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, - 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, - 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, - 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, - 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, - 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, - 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, - 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, - 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, - 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, - 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, - 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, - 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, - 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, - 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, - 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, - 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, - 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, - 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, - 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, - 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, - 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, - 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, - 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, - 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, - 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, - 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, - 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, - 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, - 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, - 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 -}; - -uint8 *_l2u = _l2u_ + 4096; - - -/* $Id$ Greg Lee */ -int xmap[XMAPMAX][5] = { -{ SFXBANK, 0, 0, 120, 0 }, -{ SFXBANK, 0, 1, 120, 1 }, -{ SFXBANK, 0, 2, 120, 2 }, -{ SFXBANK, 0, 3, 120, 3 }, -{ SFXBANK, 0, 4, 120, 4 }, -{ SFXBANK, 0, 5, 120, 5 }, -{ SFXBANK, 0, 16, 120, 16 }, -{ SFXBANK, 0, 32, 120, 32 }, -{ SFXBANK, 0, 33, 120, 33 }, -{ SFXBANK, 0, 34, 120, 34 }, -{ SFXBANK, 0, 35, 120, 35 }, -{ SFXBANK, 0, 36, 120, 36 }, -{ SFXBANK, 0, 48, 120, 48 }, -{ SFXBANK, 0, 49, 120, 49 }, -{ SFXBANK, 0, 50, 120, 50 }, -{ SFXBANK, 0, 51, 120, 51 }, -{ SFXBANK, 0, 52, 120, 52 }, -{ SFXBANK, 0, 54, 120, 54 }, -{ SFXBANK, 0, 55, 120, 55 }, -{ SFXBANK, 0, 64, 120, 64 }, -{ SFXBANK, 0, 65, 120, 65 }, -{ SFXBANK, 0, 66, 120, 66 }, -{ SFXBANK, 0, 67, 120, 67 }, -{ SFXBANK, 0, 68, 120, 68 }, -{ SFXBANK, 0, 69, 120, 69 }, -{ SFXBANK, 0, 70, 120, 70 }, -{ SFXBANK, 0, 80, 120, 80 }, -{ SFXBANK, 0, 81, 120, 81 }, -{ SFXBANK, 0, 82, 120, 82 }, -{ SFXBANK, 0, 83, 120, 83 }, -{ SFXBANK, 0, 84, 120, 84 }, -{ SFXBANK, 0, 85, 120, 85 }, -{ SFXBANK, 0, 86, 120, 86 }, -{ SFXBANK, 0, 87, 120, 87 }, -{ SFXBANK, 0, 88, 120, 88 }, -{ SFXBANK, 0, 89, 120, 89 }, -{ SFXBANK, 0, 90, 120, 90 }, -{ SFXBANK, 0, 96, 120, 96 }, -{ SFXBANK, 0, 97, 120, 97 }, -{ SFXBANK, 0, 98, 120, 98 }, -{ SFXBANK, 0, 99, 120, 99 }, -{ SFXBANK, 0, 100, 120, 100 }, -{ SFXBANK, 0, 101, 120, 101 }, -{ SFXBANK, 0, 112, 120, 112 }, -{ SFXBANK, 0, 113, 120, 113 }, -{ SFXBANK, 0, 114, 120, 114 }, -{ SFXBANK, 0, 115, 120, 115 }, -{ SFXDRUM1, 0, 36, 121, 36 }, -{ SFXDRUM1, 0, 37, 121, 37 }, -{ SFXDRUM1, 0, 38, 121, 38 }, -{ SFXDRUM1, 0, 39, 121, 39 }, -{ SFXDRUM1, 0, 40, 121, 40 }, -{ SFXDRUM1, 0, 41, 121, 41 }, -{ SFXDRUM1, 0, 52, 121, 52 }, -{ SFXDRUM1, 0, 68, 121, 68 }, -{ SFXDRUM1, 0, 69, 121, 69 }, -{ SFXDRUM1, 0, 70, 121, 70 }, -{ SFXDRUM1, 0, 71, 121, 71 }, -{ SFXDRUM1, 0, 72, 121, 72 }, -{ SFXDRUM1, 0, 84, 121, 84 }, -{ SFXDRUM1, 0, 85, 121, 85 }, -{ SFXDRUM1, 0, 86, 121, 86 }, -{ SFXDRUM1, 0, 87, 121, 87 }, -{ SFXDRUM1, 0, 88, 121, 88 }, -{ SFXDRUM1, 0, 90, 121, 90 }, -{ SFXDRUM1, 0, 91, 121, 91 }, -{ SFXDRUM1, 1, 36, 122, 36 }, -{ SFXDRUM1, 1, 37, 122, 37 }, -{ SFXDRUM1, 1, 38, 122, 38 }, -{ SFXDRUM1, 1, 39, 122, 39 }, -{ SFXDRUM1, 1, 40, 122, 40 }, -{ SFXDRUM1, 1, 41, 122, 41 }, -{ SFXDRUM1, 1, 42, 122, 42 }, -{ SFXDRUM1, 1, 52, 122, 52 }, -{ SFXDRUM1, 1, 53, 122, 53 }, -{ SFXDRUM1, 1, 54, 122, 54 }, -{ SFXDRUM1, 1, 55, 122, 55 }, -{ SFXDRUM1, 1, 56, 122, 56 }, -{ SFXDRUM1, 1, 57, 122, 57 }, -{ SFXDRUM1, 1, 58, 122, 58 }, -{ SFXDRUM1, 1, 59, 122, 59 }, -{ SFXDRUM1, 1, 60, 122, 60 }, -{ SFXDRUM1, 1, 61, 122, 61 }, -{ SFXDRUM1, 1, 62, 122, 62 }, -{ SFXDRUM1, 1, 68, 122, 68 }, -{ SFXDRUM1, 1, 69, 122, 69 }, -{ SFXDRUM1, 1, 70, 122, 70 }, -{ SFXDRUM1, 1, 71, 122, 71 }, -{ SFXDRUM1, 1, 72, 122, 72 }, -{ SFXDRUM1, 1, 73, 122, 73 }, -{ SFXDRUM1, 1, 84, 122, 84 }, -{ SFXDRUM1, 1, 85, 122, 85 }, -{ SFXDRUM1, 1, 86, 122, 86 }, -{ SFXDRUM1, 1, 87, 122, 87 }, -{ XGDRUM, 0, 25, 40, 38 }, -{ XGDRUM, 0, 26, 40, 40 }, -{ XGDRUM, 0, 27, 40, 39 }, -{ XGDRUM, 0, 28, 40, 30 }, -{ XGDRUM, 0, 29, 0, 25 }, -{ XGDRUM, 0, 30, 0, 85 }, -{ XGDRUM, 0, 31, 0, 38 }, -{ XGDRUM, 0, 32, 0, 37 }, -{ XGDRUM, 0, 33, 0, 36 }, -{ XGDRUM, 0, 34, 0, 38 }, -{ XGDRUM, 0, 62, 0, 101 }, -{ XGDRUM, 0, 63, 0, 102 }, -{ XGDRUM, 0, 64, 0, 103 }, -{ XGDRUM, 8, 25, 40, 38 }, -{ XGDRUM, 8, 26, 40, 40 }, -{ XGDRUM, 8, 27, 40, 39 }, -{ XGDRUM, 8, 28, 40, 40 }, -{ XGDRUM, 8, 29, 8, 25 }, -{ XGDRUM, 8, 30, 8, 85 }, -{ XGDRUM, 8, 31, 8, 38 }, -{ XGDRUM, 8, 32, 8, 37 }, -{ XGDRUM, 8, 33, 8, 36 }, -{ XGDRUM, 8, 34, 8, 38 }, -{ XGDRUM, 8, 62, 8, 101 }, -{ XGDRUM, 8, 63, 8, 102 }, -{ XGDRUM, 8, 64, 8, 103 }, -{ XGDRUM, 16, 25, 40, 38 }, -{ XGDRUM, 16, 26, 40, 40 }, -{ XGDRUM, 16, 27, 40, 39 }, -{ XGDRUM, 16, 28, 40, 40 }, -{ XGDRUM, 16, 29, 16, 25 }, -{ XGDRUM, 16, 30, 16, 85 }, -{ XGDRUM, 16, 31, 16, 38 }, -{ XGDRUM, 16, 32, 16, 37 }, -{ XGDRUM, 16, 33, 16, 36 }, -{ XGDRUM, 16, 34, 16, 38 }, -{ XGDRUM, 16, 62, 16, 101 }, -{ XGDRUM, 16, 63, 16, 102 }, -{ XGDRUM, 16, 64, 16, 103 }, -{ XGDRUM, 24, 25, 40, 38 }, -{ XGDRUM, 24, 26, 40, 40 }, -{ XGDRUM, 24, 27, 40, 39 }, -{ XGDRUM, 24, 28, 24, 100 }, -{ XGDRUM, 24, 29, 24, 25 }, -{ XGDRUM, 24, 30, 24, 15 }, -{ XGDRUM, 24, 31, 24, 38 }, -{ XGDRUM, 24, 32, 24, 37 }, -{ XGDRUM, 24, 33, 24, 36 }, -{ XGDRUM, 24, 34, 24, 38 }, -{ XGDRUM, 24, 62, 24, 101 }, -{ XGDRUM, 24, 63, 24, 102 }, -{ XGDRUM, 24, 64, 24, 103 }, -{ XGDRUM, 24, 78, 0, 17 }, -{ XGDRUM, 24, 79, 0, 18 }, -{ XGDRUM, 25, 25, 40, 38 }, -{ XGDRUM, 25, 26, 40, 40 }, -{ XGDRUM, 25, 27, 40, 39 }, -{ XGDRUM, 25, 28, 25, 100 }, -{ XGDRUM, 25, 29, 25, 25 }, -{ XGDRUM, 25, 30, 25, 15 }, -{ XGDRUM, 25, 31, 25, 38 }, -{ XGDRUM, 25, 32, 25, 37 }, -{ XGDRUM, 25, 33, 25, 36 }, -{ XGDRUM, 25, 34, 25, 38 }, -{ XGDRUM, 25, 78, 0, 17 }, -{ XGDRUM, 25, 79, 0, 18 }, -{ XGDRUM, 32, 25, 40, 38 }, -{ XGDRUM, 32, 26, 40, 40 }, -{ XGDRUM, 32, 27, 40, 39 }, -{ XGDRUM, 32, 28, 40, 40 }, -{ XGDRUM, 32, 29, 32, 25 }, -{ XGDRUM, 32, 30, 32, 85 }, -{ XGDRUM, 32, 31, 32, 38 }, -{ XGDRUM, 32, 32, 32, 37 }, -{ XGDRUM, 32, 33, 32, 36 }, -{ XGDRUM, 32, 34, 32, 38 }, -{ XGDRUM, 32, 62, 32, 101 }, -{ XGDRUM, 32, 63, 32, 102 }, -{ XGDRUM, 32, 64, 32, 103 }, -{ XGDRUM, 40, 25, 40, 38 }, -{ XGDRUM, 40, 26, 40, 40 }, -{ XGDRUM, 40, 27, 40, 39 }, -{ XGDRUM, 40, 28, 40, 40 }, -{ XGDRUM, 40, 29, 40, 25 }, -{ XGDRUM, 40, 30, 40, 85 }, -{ XGDRUM, 40, 31, 40, 39 }, -{ XGDRUM, 40, 32, 40, 37 }, -{ XGDRUM, 40, 33, 40, 36 }, -{ XGDRUM, 40, 34, 40, 38 }, -{ XGDRUM, 40, 38, 40, 39 }, -{ XGDRUM, 40, 39, 0, 39 }, -{ XGDRUM, 40, 40, 40, 38 }, -{ XGDRUM, 40, 42, 0, 42 }, -{ XGDRUM, 40, 46, 0, 46 }, -{ XGDRUM, 40, 62, 40, 101 }, -{ XGDRUM, 40, 63, 40, 102 }, -{ XGDRUM, 40, 64, 40, 103 }, -{ XGDRUM, 40, 87, 40, 87 } -}; diff --git a/timidity/tables.h b/timidity/tables.h index 95359665..db71ed7b 100644 --- a/timidity/tables.h +++ b/timidity/tables.h @@ -1,36 +1,19 @@ -/* +/* + TiMidity -- Experimental MIDI to WAVE converter Copyright (C) 1995 Tuukka Toivonen This program is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License, available in COPYING. - */ -#ifdef LOOKUP_SINE -extern FLOAT_T sine(int x); -#else + tables.h +*/ + #include #define sine(x) (sin((2*PI/1024.0) * (x))) -#endif #define SINE_CYCLE_LENGTH 1024 -extern int32 freq_table[]; -extern double vol_table[]; -extern double expr_table[]; -extern double bend_fine[]; -extern double bend_coarse[]; -extern uint8 *_l2u; /* 13-bit PCM to 8-bit u-law */ -extern uint8 _l2u_[]; /* used in LOOKUP_HACK */ -#ifdef LOOKUP_HACK -extern int16 _u2l[]; -extern int32 *mixup; -#ifdef LOOKUP_INTERPOLATION -extern int8 *iplookup; -#endif -#endif - -extern void init_tables(void); - -#define XMAPMAX 800 -extern int xmap[XMAPMAX][5]; - +extern const Sint32 freq_table[]; +extern const double vol_table[]; +extern const double bend_fine[]; +extern const double bend_coarse[]; diff --git a/timidity/timidity.c b/timidity/timidity.c index 5b96800a..104e3d62 100644 --- a/timidity/timidity.c +++ b/timidity/timidity.c @@ -1,304 +1,445 @@ /* + TiMidity -- Experimental MIDI to WAVE converter Copyright (C) 1995 Tuukka Toivonen This program is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License, available in COPYING. - */ +*/ + +#if HAVE_CONFIG_H +# include +#endif #include #include #include #include "SDL.h" -#include "config.h" + +#include "timidity.h" + +#include "options.h" #include "common.h" #include "instrum.h" #include "playmidi.h" #include "readmidi.h" #include "output.h" -#include "ctrlmode.h" -#include "timidity.h" #include "tables.h" -void (*s32tobuf)(void *dp, int32 *lp, int32 c); -int free_instruments_afterwards=0; -static char def_instr_name[256]=""; +ToneBank *master_tonebank[MAXBANK], *master_drumset[MAXBANK]; -int AUDIO_BUFFER_SIZE; -resample_t *resample_buffer=NULL; -int32 *common_buffer=NULL; -int num_ochannels; +static char def_instr_name[256] = ""; #define MAXWORDS 10 +/* Quick-and-dirty fgets() replacement. */ + +static char *RWgets(SDL_RWops *rw, char *s, int size) +{ + int num_read = 0; + char *p = s; + + --size;/* so that we nul terminate properly */ + + for (; num_read < size; ++p) + { + if (SDL_RWread(rw, p, 1, 1) != 1) + break; + + num_read++; + + /* Unlike fgets(), don't store newline. Under Windows/DOS we'll + * probably get an extra blank line for every line that's being + * read, but that should be ok. + */ + if (*p == '\n' || *p == '\r') + { + *p = '\0'; + return s; + } + } + + *p = '\0'; + + return (num_read != 0) ? s : NULL; +} + static int read_config_file(const char *name) { - FILE *fp; - char tmp[PATH_MAX], *w[MAXWORDS], *cp; + SDL_RWops *rw; + char tmp[1024], *w[MAXWORDS], *cp; ToneBank *bank=0; int i, j, k, line=0, words; static int rcf_count=0; if (rcf_count>50) - { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "Probable source loop in configuration files"); + { + SNDDBG(("Probable source loop in configuration files\n")); return (-1); - } + } - if (!(fp=open_file(name, 1, OF_VERBOSE))) + if (!(rw=open_file(name))) return -1; - while (fgets(tmp, sizeof(tmp), fp)) + while (RWgets(rw, tmp, sizeof(tmp))) { line++; - w[words=0]=strtok(tmp, " \t\r\n\240"); - if (!w[0] || (*w[0]=='#')) continue; - while (w[words] && (words < (MAXWORDS-1))) - { - w[++words]=strtok(0," \t\r\n\240"); - if (w[words] && w[words][0]=='#') break; - } - if (!strcmp(w[0], "map")) continue; - if (!strcmp(w[0], "dir")) + words=0; + w[0]=strtok(tmp, " \t\240"); + if (!w[0]) continue; + + /* Originally the TiMidity++ extensions were prefixed like this */ + if (strcmp(w[0], "#extension") == 0) + { + w[0]=strtok(0, " \t\240"); + if (!w[0]) continue; + } + + if (*w[0] == '#') + continue; + + while (w[words] && *w[words] != '#' && (words < (MAXWORDS-1))) + w[++words]=strtok(0," \t\240"); + + /* + * TiMidity++ adds a number of extensions to the config file format. + * Many of them are completely irrelevant to SDL_sound, but at least + * we shouldn't choke on them. + * + * Unfortunately the documentation for these extensions is often quite + * vague, gramatically strange or completely absent. + */ + if ( + !strcmp(w[0], "comm") /* "comm" program second */ + || !strcmp(w[0], "HTTPproxy") /* "HTTPproxy" hostname:port */ + || !strcmp(w[0], "FTPproxy") /* "FTPproxy" hostname:port */ + || !strcmp(w[0], "mailaddr") /* "mailaddr" your-mail-address */ + || !strcmp(w[0], "opt") /* "opt" timidity-options */ + ) + { + /* + * + "comm" sets some kind of comment -- the documentation is too + * vague for me to understand at this time. + * + "HTTPproxy", "FTPproxy" and "mailaddr" are for reading data + * over a network, rather than from the file system. + * + "opt" specifies default options for TiMidity++. + * + * These are all quite useless for our version of TiMidity, so + * they can safely remain no-ops. + */ + } else if (!strcmp(w[0], "timeout")) /* "timeout" program second */ + { + /* + * Specifies a timeout value of the program. A number of seconds + * before TiMidity kills the note. This may be useful to implement + * later, but I don't see any urgent need for it. + */ + SNDDBG(("FIXME: Implement \"timeout\" in TiMidity config.\n")); + } else if (!strcmp(w[0], "copydrumset") /* "copydrumset" drumset */ + || !strcmp(w[0], "copybank")) /* "copybank" bank */ + { + /* + * Copies all the settings of the specified drumset or bank to + * the current drumset or bank. May be useful later, but not a + * high priority. + */ + SNDDBG(("FIXME: Implement \"%s\" in TiMidity config.\n", w[0])); + } else if (!strcmp(w[0], "undef")) /* "undef" progno */ + { + /* + * Undefines the tone "progno" of the current tone bank (or + * drum set?). Not a high priority. + */ + SNDDBG(("FIXME: Implement \"undef\" in TiMidity config.\n")); + } else if (!strcmp(w[0], "altassign")) /* "altassign" prog1 prog2 ... */ + { + /* + * Sets the alternate assign for drum set. Whatever that's + * supposed to mean. + */ + SNDDBG(("FIXME: Implement \"altassign\" in TiMidity config.\n")); + } else if (!strcmp(w[0], "soundfont") + || !strcmp(w[0], "font")) + { + /* + * I can't find any documentation for these, but I guess they're + * an alternative way of loading/unloading instruments. + * + * "soundfont" sf_file "remove" + * "soundfont" sf_file ["order=" order] ["cutoff=" cutoff] + * ["reso=" reso] ["amp=" amp] + * "font" "exclude" bank preset keynote + * "font" "order" order bank preset keynote + */ + SNDDBG(("FIXME: Implmement \"%s\" in TiMidity config.\n", w[0])); + } else if (!strcmp(w[0], "progbase")) + { + /* + * The documentation for this makes absolutely no sense to me, but + * apparently it sets some sort of base offset for tone numbers. + * Why anyone would want to do this is beyond me. + */ + SNDDBG(("FIXME: Implement \"progbase\" in TiMidity config.\n")); + } else if (!strcmp(w[0], "map")) /* "map" name set1 elem1 set2 elem2 */ + { + /* + * This extension is the one we will need to implement, as it is + * used by the "eawpats". Unfortunately I cannot find any + * documentation whatsoever for it, but it looks like it's used + * for remapping one instrument to another somehow. + */ + SNDDBG(("FIXME: Implement \"map\" in TiMidity config.\n")); + } + + /* Standard TiMidity config */ + + else if (!strcmp(w[0], "dir")) { if (words < 2) - { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: No directory given\n", name, line); - close_file(fp); - return -2; - } + { + SNDDBG(("%s: line %d: No directory given\n", name, line)); + goto fail; + } for (i=1; icmsg(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: No file name given\n", name, line); - close_file(fp); - return -2; - } - for (i=1; icmsg(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Must specify exactly one patch name\n", - name, line); - close_file(fp); - return -2; + SNDDBG(("%s: line %d: Must specify exactly one patch name\n", + name, line)); + goto fail; } - strncpy(def_instr_name, w[1], 255); - def_instr_name[255]='\0'; - } + strncpy(def_instr_name, w[1], 255); + def_instr_name[255]='\0'; + } else if (!strcmp(w[0], "drumset")) - { - if (words < 2) + { + if (words < 2) { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: No drum set number given\n", - name, line); - close_file(fp); - return -2; + SNDDBG(("%s: line %d: No drum set number given\n", name, line)); + goto fail; } - i=atoi(w[1]); - if (i<0 || i>127) - { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Drum set must be between 0 and 127\n", - name, line); - close_file(fp); - return -2; - } - if (!drumset[i]) - { - drumset[i]=safe_malloc(sizeof(ToneBank)); - memset(drumset[i], 0, sizeof(ToneBank)); - } - bank=drumset[i]; - } - else if (!strcmp(w[0], "bank")) - { - if (words < 2) - { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: No bank number given\n", - name, line); - close_file(fp); - return -2; - } - i=atoi(w[1]); - if (i<0 || i>127) + i=atoi(w[1]); + if (i<0 || i>(MAXBANK-1)) { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Tone bank must be between 0 and 127\n", - name, line); - close_file(fp); - return -2; + SNDDBG(("%s: line %d: Drum set must be between 0 and %d\n", + name, line, MAXBANK-1)); + goto fail; } - if (!tonebank[i]) - { - tonebank[i]=safe_malloc(sizeof(ToneBank)); - memset(tonebank[i], 0, sizeof(ToneBank)); + if (!master_drumset[i]) + { + master_drumset[i] = safe_malloc(sizeof(ToneBank)); + memset(master_drumset[i], 0, sizeof(ToneBank)); + master_drumset[i]->tone = safe_malloc(128 * sizeof(ToneBankElement)); + memset(master_drumset[i]->tone, 0, 128 * sizeof(ToneBankElement)); } - bank=tonebank[i]; - } - else { - if ((words < 2) || (*w[0] < '0' || *w[0] > '9')) - { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: syntax error\n", name, line); - continue; + bank=master_drumset[i]; } - i=atoi(w[0]); - if (i<0 || i>127) - { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Program must be between 0 and 127\n", - name, line); - close_file(fp); - return -2; - } - if (!bank) - { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Must specify tone bank or drum set " - "before assignment\n", - name, line); - close_file(fp); - return -2; - } - if (bank->tone[i].name) - free(bank->tone[i].name); - strcpy((bank->tone[i].name=safe_malloc(strlen(w[1])+1)),w[1]); - bank->tone[i].note=bank->tone[i].amp=bank->tone[i].pan= - bank->tone[i].strip_loop=bank->tone[i].strip_envelope= - bank->tone[i].strip_tail=-1; - - for (j=2; j '9')) + if (words < 2) { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: amplification must be between " - "0 and %d\n", name, line, MAX_AMPLIFICATION); - close_file(fp); - return -2; + SNDDBG(("%s: line %d: No bank number given\n", name, line)); + goto fail; } - bank->tone[i].amp=k; - } - else if (!strcmp(w[j], "note")) - { - k=atoi(cp); - if ((k<0 || k>127) || (*cp < '0' || *cp > '9')) + i=atoi(w[1]); + if (i<0 || i>(MAXBANK-1)) { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: note must be between 0 and 127\n", - name, line); - close_file(fp); - return -2; - } - bank->tone[i].note=k; + SNDDBG(("%s: line %d: Tone bank must be between 0 and %d\n", + name, line, MAXBANK-1)); + goto fail; } - else if (!strcmp(w[j], "pan")) + if (!master_tonebank[i]) { - if (!strcmp(cp, "center")) - k=64; - else if (!strcmp(cp, "left")) - k=0; - else if (!strcmp(cp, "right")) - k=127; - else - k=((atoi(cp)+100) * 100) / 157; - if ((k<0 || k>127) || - (k==0 && *cp!='-' && (*cp < '0' || *cp > '9'))) - { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: panning must be left, right, " - "center, or between -100 and 100\n", - name, line); - close_file(fp); - return -2; + master_tonebank[i] = safe_malloc(sizeof(ToneBank)); + memset(master_tonebank[i], 0, sizeof(ToneBank)); + master_tonebank[i]->tone = safe_malloc(128 * sizeof(ToneBankElement)); + memset(master_tonebank[i]->tone, 0, 128 * sizeof(ToneBankElement)); } - bank->tone[i].pan=k; - } - else if (!strcmp(w[j], "keep")) - { - if (!strcmp(cp, "env")) - bank->tone[i].strip_envelope=0; - else if (!strcmp(cp, "loop")) - bank->tone[i].strip_loop=0; + bank=master_tonebank[i]; + } else + { + if ((words < 2) || (*w[0] < '0' || *w[0] > '9')) { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: keep must be env or loop\n", name, line); - close_file(fp); - return -2; - } + SNDDBG(("%s: line %d: syntax error\n", name, line)); + continue; } - else if (!strcmp(w[j], "strip")) - { - if (!strcmp(cp, "env")) - bank->tone[i].strip_envelope=1; - else if (!strcmp(cp, "loop")) - bank->tone[i].strip_loop=1; - else if (!strcmp(cp, "tail")) - bank->tone[i].strip_tail=1; - else + i=atoi(w[0]); + if (i<0 || i>127) { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: strip must be env, loop, or tail\n", - name, line); - close_file(fp); - return -2; + SNDDBG(("%s: line %d: Program must be between 0 and 127\n", + name, line)); + goto fail; } + if (!bank) + { + SNDDBG(("%s: line %d: Must specify tone bank or drum set before assignment\n", + name, line)); + goto fail; } - else + if (bank->tone[i].name) + free(bank->tone[i].name); + strcpy((bank->tone[i].name=safe_malloc(strlen(w[1])+1)),w[1]); + bank->tone[i].note=bank->tone[i].amp=bank->tone[i].pan= + bank->tone[i].strip_loop=bank->tone[i].strip_envelope= + bank->tone[i].strip_tail=-1; + + for (j=2; jcmsg(CMSG_ERROR, VERB_NORMAL, "%s: line %d: bad patch option %s\n", - name, line, w[j]); - close_file(fp); - return -2; + if (!(cp=strchr(w[j], '='))) + { + SNDDBG(("%s: line %d: bad patch option %s\n", name, line, w[j])); + goto fail; + } + *cp++=0; + if (!strcmp(w[j], "amp")) + { + k=atoi(cp); + if ((k<0 || k>MAX_AMPLIFICATION) || (*cp < '0' || *cp > '9')) + { + SNDDBG(("%s: line %d: amplification must be between 0 and %d\n", + name, line, MAX_AMPLIFICATION)); + goto fail; + } + bank->tone[i].amp=k; + } + else if (!strcmp(w[j], "note")) + { + k=atoi(cp); + if ((k<0 || k>127) || (*cp < '0' || *cp > '9')) + { + SNDDBG(("%s: line %d: note must be between 0 and 127\n", + name, line)); + goto fail; + } + bank->tone[i].note=k; + } + else if (!strcmp(w[j], "pan")) + { + if (!strcmp(cp, "center")) + k=64; + else if (!strcmp(cp, "left")) + k=0; + else if (!strcmp(cp, "right")) + k=127; + else + k=((atoi(cp)+100) * 100) / 157; + if ((k<0 || k>127) || (k==0 && *cp!='-' && (*cp < '0' || *cp > '9'))) + { + SNDDBG(("%s: line %d: panning must be left, right, center, or between -100 and 100\n", + name, line)); + goto fail; + } + bank->tone[i].pan=k; + } + else if (!strcmp(w[j], "keep")) + { + if (!strcmp(cp, "env")) + bank->tone[i].strip_envelope=0; + else if (!strcmp(cp, "loop")) + bank->tone[i].strip_loop=0; + else + { + SNDDBG(("%s: line %d: keep must be env or loop\n", name, line)); + goto fail; + } + } + else if (!strcmp(w[j], "strip")) + { + if (!strcmp(cp, "env")) + bank->tone[i].strip_envelope=1; + else if (!strcmp(cp, "loop")) + bank->tone[i].strip_loop=1; + else if (!strcmp(cp, "tail")) + bank->tone[i].strip_tail=1; + else + { + SNDDBG(("%s: line %d: strip must be env, loop, or tail\n", + name, line)); + goto fail; + } + } + else + { + SNDDBG(("%s: line %d: bad patch option %s\n", name, line, w[j])); + goto fail; + } } } - } - } - if (ferror(fp)) - { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Can't read from %s\n", name); - close_file(fp); - return -2; - } - close_file(fp); + } + SDL_RWclose(rw); return 0; +fail: + SDL_RWclose(rw); + return -2; } -int Timidity_Init(int rate, int format, int channels, int samples) +int Timidity_Init_NoConfig() +{ + /* Allocate memory for the standard tonebank and drumset */ + master_tonebank[0] = safe_malloc(sizeof(ToneBank)); + memset(master_tonebank[0], 0, sizeof(ToneBank)); + master_tonebank[0]->tone = safe_malloc(128 * sizeof(ToneBankElement)); + memset(master_tonebank[0]->tone, 0, 128 * sizeof(ToneBankElement)); + + master_drumset[0] = safe_malloc(sizeof(ToneBank)); + memset(master_drumset[0], 0, sizeof(ToneBank)); + master_drumset[0]->tone = safe_malloc(128 * sizeof(ToneBankElement)); + memset(master_drumset[0]->tone, 0, 128 * sizeof(ToneBankElement)); + + return 0; +} + +int Timidity_Init() { const char *env = getenv("TIMIDITY_CFG"); + + /* !!! FIXME: This may be ugly, but slightly less so than requiring the + * default search path to have only one element. I think. + * + * We only need to include the likely locations for the config + * file itself since that file should contain any other directory + * that needs to be added to the search path. + */ +#ifdef DEFAULT_PATH + add_to_pathlist(DEFAULT_PATH); +#endif +#ifdef DEFAULT_PATH1 + add_to_pathlist(DEFAULT_PATH1); +#endif +#ifdef DEFAULT_PATH2 + add_to_pathlist(DEFAULT_PATH2); +#endif +#ifdef DEFAULT_PATH3 + add_to_pathlist(DEFAULT_PATH3); +#endif + + Timidity_Init_NoConfig(); + if (!env || read_config_file(env)<0) { if (read_config_file(CONFIG_FILE)<0) { if (read_config_file(CONFIG_FILE_ETC)<0) { @@ -308,74 +449,173 @@ int Timidity_Init(int rate, int format, int channels, int samples) } } } + return 0; +} - if (channels < 1 || channels == 3 || channels == 5 || channels > 6) return(-1); +MidiSong *Timidity_LoadDLSSong(SDL_RWops *rw, DLS_Patches *patches, SDL_AudioSpec *audio) +{ + MidiSong *song; + int i; - num_ochannels = channels; + if (rw == NULL) + return NULL; + + /* Allocate memory for the song */ + song = (MidiSong *)safe_malloc(sizeof(*song)); + memset(song, 0, sizeof(*song)); + song->patches = patches; - /* Set play mode parameters */ - play_mode->rate = rate; - play_mode->encoding = 0; - if ( (format&0xFF) == 16 ) { - play_mode->encoding |= PE_16BIT; - } - if ( (format&0x8000) ) { - play_mode->encoding |= PE_SIGNED; - } - if ( channels == 1 ) { - play_mode->encoding |= PE_MONO; - } - switch (format) { - case AUDIO_S8: - s32tobuf = s32tos8; - break; - case AUDIO_U8: - s32tobuf = s32tou8; - break; - case AUDIO_S16LSB: - s32tobuf = s32tos16l; - break; - case AUDIO_S16MSB: - s32tobuf = s32tos16b; - break; - case AUDIO_U16LSB: - s32tobuf = s32tou16l; - break; - case AUDIO_U16MSB: - s32tobuf = s32tou16b; - break; - default: - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Unsupported audio format"); - return(-1); + for (i = 0; i < MAXBANK; i++) + { + if (master_tonebank[i]) + { + song->tonebank[i] = safe_malloc(sizeof(ToneBank)); + memset(song->tonebank[i], 0, sizeof(ToneBank)); + song->tonebank[i]->tone = master_tonebank[i]->tone; + } + if (master_drumset[i]) + { + song->drumset[i] = safe_malloc(sizeof(ToneBank)); + memset(song->drumset[i], 0, sizeof(ToneBank)); + song->drumset[i]->tone = master_drumset[i]->tone; + } } - AUDIO_BUFFER_SIZE = samples; - /* Allocate memory for mixing (WARNING: Memory leak!) */ - resample_buffer = safe_malloc(AUDIO_BUFFER_SIZE*sizeof(resample_t)+100); - common_buffer = safe_malloc(AUDIO_BUFFER_SIZE*num_ochannels*sizeof(int32)); + song->amplification = DEFAULT_AMPLIFICATION; + song->voices = DEFAULT_VOICES; + song->drumchannels = DEFAULT_DRUMCHANNELS; - init_tables(); + song->rw = rw; - if (ctl->open(0, 0)) { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Couldn't open %s\n", ctl->id_name); - return(-1); + song->rate = audio->freq; + song->encoding = 0; + if ((audio->format & 0xFF) == 16) + song->encoding |= PE_16BIT; + if (audio->format & 0x8000) + song->encoding |= PE_SIGNED; + if (audio->channels == 1) + song->encoding |= PE_MONO; + switch (audio->format) { + case AUDIO_S8: + song->write = s32tos8; + break; + case AUDIO_U8: + song->write = s32tou8; + break; + case AUDIO_S16LSB: + song->write = s32tos16l; + break; + case AUDIO_S16MSB: + song->write = s32tos16b; + break; + case AUDIO_U16LSB: + song->write = s32tou16l; + break; + default: + SNDDBG(("Unsupported audio format")); + song->write = s32tou16l; + break; } - if (!control_ratio) { - control_ratio = play_mode->rate / CONTROLS_PER_SECOND; - if(control_ratio<1) - control_ratio=1; - else if (control_ratio > MAX_CONTROL_RATIO) - control_ratio=MAX_CONTROL_RATIO; + song->buffer_size = audio->samples; + song->resample_buffer = safe_malloc(audio->samples * sizeof(sample_t)); + song->common_buffer = safe_malloc(audio->samples * 2 * sizeof(Sint32)); + + song->control_ratio = audio->freq / CONTROLS_PER_SECOND; + if (song->control_ratio < 1) + song->control_ratio = 1; + else if (song->control_ratio > MAX_CONTROL_RATIO) + song->control_ratio = MAX_CONTROL_RATIO; + + song->lost_notes = 0; + song->cut_notes = 0; + + song->events = read_midi_file(song, &(song->groomed_event_count), + &song->samples); + + /* The RWops can safely be closed at this point, but let's make that the + * responsibility of the caller. + */ + + /* Make sure everything is okay */ + if (!song->events) { + free(song); + return(NULL); } + + song->default_instrument = 0; + song->default_program = DEFAULT_PROGRAM; + if (*def_instr_name) - set_default_instrument(def_instr_name); - return(0); + set_default_instrument(song, def_instr_name); + + load_missing_instruments(song); + + return(song); } -char timidity_error[TIMIDITY_ERROR_SIZE] = ""; -const char *Timidity_Error(void) +MidiSong *Timidity_LoadSong(SDL_RWops *rw, SDL_AudioSpec *audio) { - return(timidity_error); + return Timidity_LoadDLSSong(rw, NULL, audio); } +void Timidity_FreeSong(MidiSong *song) +{ + int i; + + free_instruments(song); + + for (i = 0; i < 128; i++) + { + if (song->tonebank[i]) + free(song->tonebank[i]); + if (song->drumset[i]) + free(song->drumset[i]); + } + + free(song->common_buffer); + free(song->resample_buffer); + free(song->events); + free(song); +} + +void Timidity_Exit(void) +{ + int i, j; + + for (i = 0; i < MAXBANK; i++) + { + if (master_tonebank[i]) + { + ToneBankElement *e = master_tonebank[i]->tone; + if (e != NULL) + { + for (j = 0; j < 128; j++) + { + if (e[j].name != NULL) + free(e[j].name); + } + free(e); + } + free(master_tonebank[i]); + master_tonebank[i] = NULL; + } + if (master_drumset[i]) + { + ToneBankElement *e = master_drumset[i]->tone; + if (e != NULL) + { + for (j = 0; j < 128; j++) + { + if (e[j].name != NULL) + free(e[j].name); + } + free(e); + } + free(master_drumset[i]); + master_drumset[i] = NULL; + } + } + + free_pathlist(); +} diff --git a/timidity/timidity.h b/timidity/timidity.h index ec1dbe8b..adb03498 100644 --- a/timidity/timidity.h +++ b/timidity/timidity.h @@ -1,20 +1,170 @@ /* + TiMidity -- Experimental MIDI to WAVE converter Copyright (C) 1995 Tuukka Toivonen This program is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License, available in COPYING. - */ +*/ + +#ifndef TIMIDITY_H +#define TIMIDITY_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef Sint16 sample_t; +typedef Sint32 final_volume_t; + +#define VIBRATO_SAMPLE_INCREMENTS 32 + +/* Maximum polyphony. */ +/* #define MAX_VOICES 48 */ +#define MAX_VOICES 256 +#define MAXCHAN 16 +/* #define MAXCHAN 64 */ +#define MAXBANK 128 + +typedef struct { + Sint32 + loop_start, loop_end, data_length, + sample_rate, low_vel, high_vel, low_freq, high_freq, root_freq; + Sint32 + envelope_rate[6], envelope_offset[6]; + float + volume; + sample_t *data; + Sint32 + tremolo_sweep_increment, tremolo_phase_increment, + vibrato_sweep_increment, vibrato_control_ratio; + Uint8 + tremolo_depth, vibrato_depth, + modes; + Sint8 + panning, note_to_use; +} Sample; + +typedef struct { + int + bank, program, volume, sustain, panning, pitchbend, expression, + mono, /* one note only on this channel -- not implemented yet */ + pitchsens; + /* chorus, reverb... Coming soon to a 300-MHz, eight-way superscalar + processor near you */ + float + pitchfactor; /* precomputed pitch bend factor to save some fdiv's */ +} Channel; + +typedef struct { + Uint8 + status, channel, note, velocity; + Sample *sample; + Sint32 + orig_frequency, frequency, + sample_offset, sample_increment, + envelope_volume, envelope_target, envelope_increment, + tremolo_sweep, tremolo_sweep_position, + tremolo_phase, tremolo_phase_increment, + vibrato_sweep, vibrato_sweep_position; + + final_volume_t left_mix, right_mix; + + float + left_amp, right_amp, tremolo_volume; + Sint32 + vibrato_sample_increment[VIBRATO_SAMPLE_INCREMENTS]; + int + vibrato_phase, vibrato_control_ratio, vibrato_control_counter, + envelope_stage, control_counter, panning, panned; -typedef struct _MidiSong MidiSong; +} Voice; -extern int Timidity_Init(int rate, int format, int channels, int samples); -extern const char *Timidity_Error(void); -extern void Timidity_SetVolume(int volume); -extern int Timidity_PlaySome(void *stream, int samples); -extern MidiSong *Timidity_LoadSong_RW(SDL_RWops *rw, int freerw); +typedef struct { + int samples; + Sample *sample; +} Instrument; + +/* Shared data */ +typedef struct { + char *name; + int note, amp, pan, strip_loop, strip_envelope, strip_tail; +} ToneBankElement; + +typedef struct { + ToneBankElement *tone; + Instrument *instrument[128]; +} ToneBank; + +typedef struct { + Sint32 time; + Uint8 channel, type, a, b; +} MidiEvent; + +typedef struct { + MidiEvent event; + void *next; +} MidiEventList; + +struct _DLS_Data; +typedef struct _DLS_Data DLS_Patches; + +typedef struct { + int playing; + SDL_RWops *rw; + Sint32 rate; + Sint32 encoding; + float master_volume; + Sint32 amplification; + DLS_Patches *patches; + ToneBank *tonebank[MAXBANK]; + ToneBank *drumset[MAXBANK]; + Instrument *default_instrument; + int default_program; + void (*write)(void *dp, Sint32 *lp, Sint32 c); + int buffer_size; + sample_t *resample_buffer; + Sint32 *common_buffer; + Sint32 *buffer_pointer; + /* These would both fit into 32 bits, but they are often added in + large multiples, so it's simpler to have two roomy ints */ + /* samples per MIDI delta-t */ + Sint32 sample_increment; + Sint32 sample_correction; + Channel channel[MAXCHAN]; + Voice voice[MAX_VOICES]; + int voices; + Sint32 drumchannels; + Sint32 buffered_count; + Sint32 control_ratio; + Sint32 lost_notes; + Sint32 cut_notes; + Sint32 samples; + MidiEvent *events; + MidiEvent *current_event; + MidiEventList *evlist; + Sint32 current_sample; + Sint32 event_count; + Sint32 at; + Sint32 groomed_event_count; +} MidiSong; + +/* Some of these are not defined in timidity.c but are here for convenience */ + +extern int Timidity_Init(void); +extern int Timidity_Init_NoConfig(void); +extern void Timidity_SetVolume(MidiSong *song, int volume); +extern int Timidity_PlaySome(MidiSong *song, void *stream, Sint32 len); +extern DLS_Patches *Timidity_LoadDLS(SDL_RWops *rw); +extern void Timidity_FreeDLS(DLS_Patches *patches); +extern MidiSong *Timidity_LoadDLSSong(SDL_RWops *rw, DLS_Patches *patches, SDL_AudioSpec *audio); +extern MidiSong *Timidity_LoadSong(SDL_RWops *rw, SDL_AudioSpec *audio); extern void Timidity_Start(MidiSong *song); -extern int Timidity_Active(void); -extern void Timidity_Stop(void); +extern void Timidity_Seek(MidiSong *song, Uint32 ms); +extern Uint32 Timidity_GetSongLength(MidiSong *song); /* returns millseconds */ extern void Timidity_FreeSong(MidiSong *song); -extern void Timidity_Close(void); +extern void Timidity_Exit(void); + +#ifdef __cplusplus +} +#endif +#endif /* TIMIDITY_H */