diff options
| author | Pepper <pepper@scannerjammer.com> | 2015-01-16 15:38:48 -0500 |
|---|---|---|
| committer | Pepper <pepper@scannerjammer.com> | 2015-01-16 15:38:48 -0500 |
| commit | 131832f418372c0654aa4169c4283f863cb96226 (patch) | |
| tree | c86492441c3de3d13ebe2c2e2d9bc5dcf04aeaf0 /src/readmidi.c | |
first commit
Diffstat (limited to 'src/readmidi.c')
| -rw-r--r-- | src/readmidi.c | 6294 |
1 files changed, 6294 insertions, 0 deletions
diff --git a/src/readmidi.c b/src/readmidi.c new file mode 100644 index 0000000..125d80d --- /dev/null +++ b/src/readmidi.c @@ -0,0 +1,6294 @@ +/* + TiMidity++ -- MIDI to WAVE converter and player + Copyright (C) 1999-2009 Masanao Izumo <iz@onicos.co.jp> + Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ +#ifdef __POCC__ +#include <sys/types.h> +#endif //for off_t +#include <stdio.h> +#include <stdlib.h> +#ifndef NO_STRING_H +#include <string.h> +#else +#include <strings.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ +//#include "timidity.h" +#include "common.h" +//#include "instrum.h" +//#include "playmidi.h" +#include "readmidi.h" +#include "output.h" +//#include "controls.h" +#include "strtab.h"//string table +#include "memb.h" //utils +//#include "mod.h" +//#include "wrd.h" +#include "tables.h" +//#include "reverb.h" +#include <math.h> + +/* rcp.c */ +//any idea what rcp might stand for? not sure, might be some other lib man...I don't know whether this is going to be +//possible, there are so many linked files here well need to dig this thourgh +//well in meantime i checked fluidsynth and half way made it to compiling it, so it compiles but doesn't link yet because depend on log functions, which can be probably replaced with something else ok I guess we should use that +int read_rcp_file(struct timidity_file *tf, char *magic0, char *fn); + +/* mld.c */ +extern int read_mfi_file(struct timidity_file *tf); +extern char *get_mfi_file_title(struct timidity_file *tf); + +#define MAX_MIDI_EVENT ((MAX_SAFE_MALLOC_SIZE / sizeof(MidiEvent)) - 1) +#define MARKER_START_CHAR '(' +#define MARKER_END_CHAR ')' + +static uint8 rhythm_part[2]; /* for GS */ +static uint8 drum_setup_xg[16] = { 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9 }; /* for XG */ + +enum +{ + CHORUS_ST_NOT_OK = 0, + CHORUS_ST_OK +}; + +#ifdef ALWAYS_TRACE_TEXT_META_EVENT +int opt_trace_text_meta_event = 1; +#else +int opt_trace_text_meta_event = 0; +#endif /* ALWAYS_TRACE_TEXT_META_EVENT */ + +int opt_default_mid = 0; +int opt_system_mid = 0; +int ignore_midi_error = 1; +ChannelBitMask quietchannels; +struct midi_file_info *current_file_info = NULL; +int readmidi_error_flag = 0; +int readmidi_wrd_mode = 0; +int play_system_mode = DEFAULT_SYSTEM_MODE; + +/* Mingw gcc3 and Borland C hack */ +/* If these are not NULL initialized cause Hang up */ +/* why ? I dont know. (Keishi Suenaga) */ +static MidiEventList *evlist=NULL, *current_midi_point=NULL; +static int32 event_count; +static MBlockList mempool; +static StringTable string_event_strtab = { 0 }; +static int current_read_track; +static int karaoke_format, karaoke_title_flag; +static struct midi_file_info *midi_file_info = NULL; +static char **string_event_table = NULL; +static int string_event_table_size = 0; +int default_channel_program[256]; +static MidiEvent timesig[256]; + +void init_delay_status_gs(void); +void init_chorus_status_gs(void); +void init_reverb_status_gs(void); +void init_eq_status_gs(void); +void init_insertion_effect_gs(void); +void init_multi_eq_xg(void); +static void init_all_effect_xg(void); + +/* MIDI ports will be merged in several channels in the future. */ +int midi_port_number; + +/* 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*/ + +#define SETMIDIEVENT(e, at, t, ch, pa, pb) \ + { (e).time = (at); (e).type = (t); \ + (e).channel = (uint8)(ch); (e).a = (uint8)(pa); (e).b = (uint8)(pb); } + +#define MIDIEVENT(at, t, ch, pa, pb) \ + { MidiEvent event; SETMIDIEVENT(event, at, t, ch, pa, pb); \ + readmidi_add_event(&event); } + +#if MAX_CHANNELS <= 16 +#define MERGE_CHANNEL_PORT(ch) ((int)(ch)) +#define MERGE_CHANNEL_PORT2(ch, port) ((int)(ch)) +#else +#define MERGE_CHANNEL_PORT(ch) ((int)(ch) | (midi_port_number << 4)) +#define MERGE_CHANNEL_PORT2(ch, port) ((int)(ch) | ((int)port << 4)) +#endif + +#define alloc_midi_event() \ + (MidiEventList *)new_segment(&mempool, sizeof(MidiEventList)) + +typedef struct _UserDrumset { + int8 bank; + int8 prog; + int8 play_note; + int8 level; + int8 assign_group; + int8 pan; + int8 reverb_send_level; + int8 chorus_send_level; + int8 rx_note_off; + int8 rx_note_on; + int8 delay_send_level; + int8 source_map; + int8 source_prog; + int8 source_note; + struct _UserDrumset *next; +} UserDrumset; + +UserDrumset *userdrum_first = (UserDrumset *)NULL; +UserDrumset *userdrum_last = (UserDrumset *)NULL; + +void init_userdrum(); +UserDrumset *get_userdrum(int bank, int prog); +void recompute_userdrum_altassign(int bank,int group); + +typedef struct _UserInstrument { + int8 bank; + int8 prog; + int8 source_map; + int8 source_bank; + int8 source_prog; + int8 vibrato_rate; + int8 vibrato_depth; + int8 cutoff_freq; + int8 resonance; + int8 env_attack; + int8 env_decay; + int8 env_release; + int8 vibrato_delay; + struct _UserInstrument *next; +} UserInstrument; + +UserInstrument *userinst_first = (UserInstrument *)NULL; +UserInstrument *userinst_last = (UserInstrument *)NULL; + +void init_userinst(); +UserInstrument *get_userinst(int bank, int prog); +void recompute_userinst(int bank, int prog); +void recompute_userinst_altassign(int bank,int group); + +int32 readmidi_set_track(int trackno, int rewindp) +{ + current_read_track = trackno; + memset(&chorus_status_gs.text, 0, sizeof(struct chorus_text_gs_t)); + if(karaoke_format == 1 && current_read_track == 2) + karaoke_format = 2; /* Start karaoke lyric */ + else if(karaoke_format == 2 && current_read_track == 3) + karaoke_format = 3; /* End karaoke lyric */ + midi_port_number = 0; + + if(evlist == NULL) + return 0; + if(rewindp) + current_midi_point = evlist; + else + { + /* find the last event in the list */ + while(current_midi_point->next != NULL) + current_midi_point = current_midi_point->next; + } + return current_midi_point->event.time; +} + +void readmidi_add_event(MidiEvent *a_event) +{ + MidiEventList *newev; + int32 at; + + if(event_count == MAX_MIDI_EVENT) + { + if(!readmidi_error_flag) + { + readmidi_error_flag = 1; + ctl->cmsg(CMSG_ERROR, VERB_NORMAL, + "Maxmum number of events is exceeded"); + } + return; + } + event_count++; + + at = a_event->time; + newev = alloc_midi_event(); + newev->event = *a_event; /* assign by value!!! */ + if(at < 0) /* for safety */ + at = newev->event.time = 0; + + if(at >= current_midi_point->event.time) + { + /* Forward scan */ + MidiEventList *next = current_midi_point->next; + while (next && (next->event.time <= at)) + { + current_midi_point = next; + next = current_midi_point->next; + } + newev->prev = current_midi_point; + newev->next = next; + current_midi_point->next = newev; + if (next) + next->prev = newev; + } + else + { + /* Backward scan -- symmetrical to the one above */ + MidiEventList *prev = current_midi_point->prev; + while (prev && (prev->event.time > at)) { + current_midi_point = prev; + prev = current_midi_point->prev; + } + newev->prev = prev; + newev->next = current_midi_point; + current_midi_point->prev = newev; + if (prev) + prev->next = newev; + } + current_midi_point = newev; +} + +void readmidi_add_ctl_event(int32 at, int ch, int a, int b) +{ + MidiEvent ev; + + if(convert_midi_control_change(ch, a, b, &ev)) + { + ev.time = at; + readmidi_add_event(&ev); + } + else + ctl->cmsg(CMSG_INFO, VERB_DEBUG, "(Control ch=%d %d: %d)", ch, a, b); +} + +char *readmidi_make_string_event(int type, char *string, MidiEvent *ev, + int cnv) +{ + char *text; + int len; + StringTableNode *st; + int a, b; + + if(string_event_strtab.nstring == 0) + put_string_table(&string_event_strtab, "", 0); + else if(string_event_strtab.nstring == 0x7FFE) + { + SETMIDIEVENT(*ev, 0, type, 0, 0, 0); + return NULL; /* Over flow */ + } + a = (string_event_strtab.nstring & 0xff); + b = ((string_event_strtab.nstring >> 8) & 0xff); + + len = strlen(string); + if(cnv) + { + text = (char *)new_segment(&tmpbuffer, SAFE_CONVERT_LENGTH(len) + 1); + code_convert(string, text + 1, SAFE_CONVERT_LENGTH(len), NULL, NULL); + } + else + { + text = (char *)new_segment(&tmpbuffer, len + 1); + memcpy(text + 1, string, len); + text[len + 1] = '\0'; + } + + st = put_string_table(&string_event_strtab, text, strlen(text + 1) + 1); + reuse_mblock(&tmpbuffer); + + text = st->string; + *text = type; + SETMIDIEVENT(*ev, 0, type, 0, a, b); + return text; +} + +static char *readmidi_make_lcd_event(int type, const uint8 *data, MidiEvent *ev) +{ + char *text; + int len; + StringTableNode *st; + int a, b, i; + + if(string_event_strtab.nstring == 0) + put_string_table(&string_event_strtab, "", 0); + else if(string_event_strtab.nstring == 0x7FFE) + { + SETMIDIEVENT(*ev, 0, type, 0, 0, 0); + return NULL; /* Over flow */ + } + a = (string_event_strtab.nstring & 0xff); + b = ((string_event_strtab.nstring >> 8) & 0xff); + + len = 128; + + text = (char *)new_segment(&tmpbuffer, len + 2); + + for( i=0; i<64; i++){ + const char tbl[]= "0123456789ABCDEF"; + text[1+i*2 ]=tbl[data[i]>>4]; + text[1+i*2+1]=tbl[data[i]&0xF]; + } + text[len + 1] = '\0'; + + + st = put_string_table(&string_event_strtab, text, strlen(text + 1) + 1); + reuse_mblock(&tmpbuffer); + + text = st->string; + *text = type; + SETMIDIEVENT(*ev, 0, type, 0, a, b); + return text; +} + +/* Computes how many (fractional) samples one MIDI delta-time unit contains */ +static void compute_sample_increment(int32 tempo, int32 divisions) +{ + double a; + a = (double) (tempo) * (double) (play_mode->rate) * (65536.0/1000000.0) / + (double)(divisions); + + sample_correction = (int32)(a) & 0xFFFF; + sample_increment = (int32)(a) >> 16; + + ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Samples per delta-t: %d (correction %d)", + sample_increment, sample_correction); +} + +/* Read variable-length number (7 bits per byte, MSB first) */ +static int32 getvl(struct timidity_file *tf) +{ + int32 l; + int c; + + errno = 0; + l = 0; + + /* 1 */ + if((c = tf_getc(tf)) == EOF) + goto eof; + if(!(c & 0x80)) return l | c; + l = (l | (c & 0x7f)) << 7; + + /* 2 */ + if((c = tf_getc(tf)) == EOF) + goto eof; + if(!(c & 0x80)) return l | c; + l = (l | (c & 0x7f)) << 7; + + /* 3 */ + if((c = tf_getc(tf)) == EOF) + goto eof; + if(!(c & 0x80)) return l | c; + l = (l | (c & 0x7f)) << 7; + + /* 4 */ + if((c = tf_getc(tf)) == EOF) + goto eof; + if(!(c & 0x80)) return l | c; + + /* Error */ + ctl->cmsg(CMSG_ERROR, VERB_NORMAL, + "%s: Illigal Variable-length quantity format.", + current_filename); + return -2; + + eof: + if(errno) + ctl->cmsg(CMSG_ERROR, VERB_NORMAL, + "%s: read_midi_event: %s", + current_filename, strerror(errno)); + else + ctl->cmsg(CMSG_ERROR, VERB_NORMAL, + "Warning: %s: Too shorten midi file.", + current_filename); + return -1; +} + +static char *add_karaoke_title(char *s1, char *s2) +{ + char *ks; + int k1, k2; + + if(s1 == NULL) + return safe_strdup(s2); + + k1 = strlen(s1); + k2 = strlen(s2); + if(k2 == 0) + return s1; + ks = (char *)safe_malloc(k1 + k2 + 2); + memcpy(ks, s1, k1); + ks[k1++] = ' '; + memcpy(ks + k1, s2, k2 + 1); + free(s1); + s1 = NULL; + + return ks; +} + + +/* Print a string from the file, followed by a newline. Any non-ASCII + or unprintable characters will be converted to periods. */ +static char *dumpstring(int type, int32 len, char *label, int allocp, + struct timidity_file *tf) +{ + char *si, *so; + int s_maxlen = SAFE_CONVERT_LENGTH(len); + int llen, solen; + + if(len <= 0) + { + ctl->cmsg(CMSG_TEXT, VERB_VERBOSE, "%s", label); + return NULL; + } + + si = (char *)new_segment(&tmpbuffer, len + 1); + so = (char *)new_segment(&tmpbuffer, s_maxlen); + + if(len != tf_read(si, 1, len, tf)) + { + reuse_mblock(&tmpbuffer); + return NULL; + } + si[len]='\0'; + + if(type == 1 && + current_file_info->format == 1 && + (strncmp(si, "@K", 2) == 0)) +/* Karaoke string should be "@KMIDI KARAOKE FILE" */ + karaoke_format = 1; + + code_convert(si, so, s_maxlen, NULL, NULL); + + llen = strlen(label); + solen = strlen(so); + if(llen + solen >= MIN_MBLOCK_SIZE) + so[MIN_MBLOCK_SIZE - llen - 1] = '\0'; + + ctl->cmsg(CMSG_TEXT, VERB_VERBOSE, "%s%s", label, so); + + if(allocp) + { + so = safe_strdup(so); + reuse_mblock(&tmpbuffer); + return so; + } + reuse_mblock(&tmpbuffer); + return NULL; +} + +static uint16 gs_convert_master_vol(int vol) +{ + double v; + + if(vol >= 0x7f) + return 0xffff; + v = (double)vol * (0xffff/127.0); + if(v >= 0xffff) + return 0xffff; + return (uint16)v; +} + +static uint16 gm_convert_master_vol(uint16 v1, uint16 v2) +{ + return (((v1 & 0x7f) | ((v2 & 0x7f) << 7)) << 2) | 3; +} + +static void check_chorus_text_start(void) +{ + struct chorus_text_gs_t *p = &(chorus_status_gs.text); + if(p->status != CHORUS_ST_OK && p->voice_reserve[17] && + p->macro[2] && p->pre_lpf[2] && p->level[2] && + p->feed_back[2] && p->delay[2] && p->rate[2] && + p->depth[2] && p->send_level[2]) + { + ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Chorus text start"); + p->status = CHORUS_ST_OK; + } +} + +struct ctl_chg_types { + unsigned char mtype; + int ttype; +} ctl_chg_list[] = { + { 0, ME_TONE_BANK_MSB }, + { 1, ME_MODULATION_WHEEL }, + { 2, ME_BREATH }, + { 4, ME_FOOT }, + { 5, ME_PORTAMENTO_TIME_MSB }, + { 6, ME_DATA_ENTRY_MSB }, + { 7, ME_MAINVOLUME }, + { 8, ME_BALANCE }, + { 10, ME_PAN }, + { 11, ME_EXPRESSION }, + { 32, ME_TONE_BANK_LSB }, + { 37, ME_PORTAMENTO_TIME_LSB }, + { 38, ME_DATA_ENTRY_LSB }, + { 64, ME_SUSTAIN }, + { 65, ME_PORTAMENTO }, + { 66, ME_SOSTENUTO }, + { 67, ME_SOFT_PEDAL }, + { 68, ME_LEGATO_FOOTSWITCH }, + { 69, ME_HOLD2 }, + { 71, ME_HARMONIC_CONTENT }, + { 72, ME_RELEASE_TIME }, + { 73, ME_ATTACK_TIME }, + { 74, ME_BRIGHTNESS }, + { 84, ME_PORTAMENTO_CONTROL }, + { 91, ME_REVERB_EFFECT }, + { 92, ME_TREMOLO_EFFECT }, + { 93, ME_CHORUS_EFFECT }, + { 94, ME_CELESTE_EFFECT }, + { 95, ME_PHASER_EFFECT }, + { 96, ME_RPN_INC }, + { 97, ME_RPN_DEC }, + { 98, ME_NRPN_LSB }, + { 99, ME_NRPN_MSB }, + { 100, ME_RPN_LSB }, + { 101, ME_RPN_MSB }, + { 120, ME_ALL_SOUNDS_OFF }, + { 121, ME_RESET_CONTROLLERS }, + { 123, ME_ALL_NOTES_OFF }, + { 126, ME_MONO }, + { 127, ME_POLY }, +}; + +int convert_midi_control_change(int chn, int type, int val, MidiEvent *ev_ret) +{ + int i; + for (i = 0; i < ARRAY_SIZE(ctl_chg_list); i++) { + if (ctl_chg_list[i].mtype == type) { + type = ctl_chg_list[i].ttype; + break; + } + } + if (i >= ARRAY_SIZE(ctl_chg_list)) + type = -1; + + if(type != -1) + { + if(val > 127) + val = 127; + ev_ret->type = type; + ev_ret->channel = chn; + ev_ret->a = val; + ev_ret->b = 0; + return 1; + } + return 0; +} + +int unconvert_midi_control_change(MidiEvent *ev) +{ + int i; + for (i = 0; i < ARRAY_SIZE(ctl_chg_list); i++) { + if (ctl_chg_list[i].ttype == ev->type) + break; + } + if (i >= ARRAY_SIZE(ctl_chg_list)) + return -1; + + return ctl_chg_list[i].mtype; +} + +static int block_to_part(int block, int port) +{ + int p; + p = block & 0x0F; + if(p == 0) {p = 9;} + else if(p <= 9) {p--;} + return MERGE_CHANNEL_PORT2(p, port); +} + +/* Map XG types onto GS types. XG should eventually have its own tables */ +static int set_xg_reverb_type(int msb, int lsb) +{ + int type = 4; + + if ((msb == 0x00) || + (msb >= 0x05 && msb <= 0x0F) || + (msb >= 0x14)) /* NO EFFECT */ + { + ctl->cmsg(CMSG_INFO,VERB_NOISY,"XG Set Reverb Type (NO EFFECT %d %d)", msb, lsb); + return -1; + } + + switch(msb) + { + case 0x01: + type = 3; /* Hall 1 */ + break; + case 0x02: + type = 0; /* Room 1 */ + break; + case 0x03: + type = 3; /* Stage 1 -> Hall 1 */ + break; + case 0x04: + type = 5; /* Plate */ + break; + default: + type = 4; /* unsupported -> Hall 2 */ + break; + } + if (lsb == 0x01) + { + switch(msb) + { + case 0x01: + type = 4; /* Hall 2 */ + break; + case 0x02: + type = 1; /* Room 2 */ + break; + case 0x03: + type = 4; /* Stage 2 -> Hall 2 */ + break; + default: + break; + } + } + if (lsb == 0x02 && msb == 0x02) + type = 2; /* Room 3 */ + + ctl->cmsg(CMSG_INFO,VERB_NOISY,"XG Set Reverb Type (%d)", type); + return type; +} + +/* Map XG types onto GS types. XG should eventually have its own tables */ +static int set_xg_chorus_type(int msb, int lsb) +{ + int type = 2; + + if ((msb >= 0x00 && msb <= 0x40) || + (msb >= 0x45 && msb <= 0x47) || + (msb >= 0x49)) /* NO EFFECT */ + { + ctl->cmsg(CMSG_INFO,VERB_NOISY,"XG Set Chorus Type (NO EFFECT %d %d)", msb, lsb); + return -1; + } + + switch(msb) + { + case 0x41: + type = 0; /* Chorus 1 */ + break; + case 0x42: + type = 0; /* Celeste 1 -> Chorus 1 */ + break; + case 0x43: + type = 5; + break; + default: + type = 2; /* unsupported -> Chorus 3 */ + break; + } + if (lsb == 0x01) + { + switch(msb) + { + case 0x41: + type = 1; /* Chorus 2 */ + break; + case 0x42: + type = 1; /* Celeste 2 -> Chorus 2 */ + break; + default: + break; + } + } + else if (lsb == 0x02) + { + switch(msb) + { + case 0x41: + type = 2; /* Chorus 3 */ + break; + case 0x42: + type = 2; /* Celeste 3 -> Chorus 3 */ + break; + default: + break; + } + } + else if (lsb == 0x08) + { + switch(msb) + { + case 0x41: + type = 3; /* Chorus 4 */ + break; + case 0x42: + type = 3; /* Celeste 4 -> Chorus 4 */ + break; + default: + break; + } + } + + ctl->cmsg(CMSG_INFO,VERB_NOISY,"XG Set Chorus Type (%d)", type); + return type; +} + +/* XG SysEx parsing function by Eric A. Welsh + * Also handles GS patch+bank changes + * + * This function provides basic support for XG Bulk Dump and Parameter + * Change SysEx events + */ +int parse_sysex_event_multi(uint8 *val, int32 len, MidiEvent *evm) +{ + int num_events = 0; /* Number of events added */ + uint32 channel_tt; + int i, j; + static uint8 xg_reverb_type_msb = 0x01, xg_reverb_type_lsb = 0x00; + static uint8 xg_chorus_type_msb = 0x41, xg_chorus_type_lsb = 0x00; + + if(current_file_info->mid == 0 || current_file_info->mid >= 0x7e) + current_file_info->mid = val[0]; + + /* Effect 1 or Multi EQ */ + if(len >= 8 && + val[0] == 0x43 && /* Yamaha ID */ + val[2] == 0x4C && /* XG Model ID */ + ((val[1] < 0x10 && val[5] == 0x02) || /* Bulk Dump*/ + (val[1] >= 0x10 && val[3] == 0x02))) /* Parameter Change */ + { + uint8 addhigh, addmid, addlow; /* Addresses */ + uint8 *body; /* SysEx body */ + int ent, v; /* Entry # of sub-event */ + uint8 *body_end; /* End of SysEx body */ + + if (val[1] < 0x10) /* Bulk Dump */ + { + addhigh = val[5]; + addmid = val[6]; + addlow = val[7]; + body = val + 8; + body_end = val + len - 3; + } + else /* Parameter Change */ + { + addhigh = val[3]; + addmid = val[4]; + addlow = val[5]; + body = val + 6; + body_end = val + len - 2; + } + + /* set the SYSEX_XG_MSB info */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_MSB, 0, addhigh, addmid); + num_events++; + + for (ent = addlow; body <= body_end; body++, ent++) { + if(addmid == 0x01) { /* Effect 1 */ + switch(ent) { + case 0x00: /* Reverb Type MSB */ + xg_reverb_type_msb = *body; +#if 0 /* XG specific reverb is not supported yet, use GS instead */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; +#endif + break; + + case 0x01: /* Reverb Type LSB */ + xg_reverb_type_lsb = *body; +#if 0 /* XG specific reverb is not supported yet, use GS instead */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; +#else + v = set_xg_reverb_type(xg_reverb_type_msb, xg_reverb_type_lsb); + if (v >= 0) { + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_GS_LSB, 0, v, 0x05); + num_events++; + } +#endif + break; + + case 0x0C: /* Reverb Return */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; + break; + + case 0x20: /* Chorus Type MSB */ + xg_chorus_type_msb = *body; +#if 0 /* XG specific chorus is not supported yet, use GS instead */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; +#endif + break; + + case 0x21: /* Chorus Type LSB */ + xg_chorus_type_lsb = *body; +#if 0 /* XG specific chorus is not supported yet, use GS instead */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; +#else + v = set_xg_chorus_type(xg_chorus_type_msb, xg_chorus_type_lsb); + if (v >= 0) { + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_GS_LSB, 0, v, 0x0D); + num_events++; + } +#endif + break; + + case 0x2C: /* Chorus Return */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; + break; + + default: + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; + break; + } + } + else if(addmid == 0x40) { /* Multi EQ */ + switch(ent) { + case 0x00: /* EQ type */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; + break; + + case 0x01: /* EQ gain1 */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; + break; + + case 0x02: /* EQ frequency1 */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; + break; + + case 0x03: /* EQ Q1 */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; + break; + + case 0x04: /* EQ shape1 */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; + break; + + case 0x05: /* EQ gain2 */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; + break; + + case 0x06: /* EQ frequency2 */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; + break; + + case 0x07: /* EQ Q2 */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; + break; + + case 0x09: /* EQ gain3 */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; + break; + + case 0x0A: /* EQ frequency3 */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; + break; + + case 0x0B: /* EQ Q3 */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; + break; + + case 0x0D: /* EQ gain4 */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; + break; + + case 0x0E: /* EQ frequency4 */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; + break; + + case 0x0F: /* EQ Q4 */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; + break; + + case 0x11: /* EQ gain5 */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; + break; + + case 0x12: /* EQ frequency5 */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; + break; + + case 0x13: /* EQ Q5 */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; + break; + + case 0x14: /* EQ shape5 */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; + break; + + default: + break; + } + } + } + } + + /* Effect 2 (Insertion Effects) */ + else if(len >= 8 && + val[0] == 0x43 && /* Yamaha ID */ + val[2] == 0x4C && /* XG Model ID */ + ((val[1] < 0x10 && val[5] == 0x03) || /* Bulk Dump*/ + (val[1] >= 0x10 && val[3] == 0x03))) /* Parameter Change */ + { + uint8 addhigh, addmid, addlow; /* Addresses */ + uint8 *body; /* SysEx body */ + int ent; /* Entry # of sub-event */ + uint8 *body_end; /* End of SysEx body */ + + if (val[1] < 0x10) /* Bulk Dump */ + { + addhigh = val[5]; + addmid = val[6]; + addlow = val[7]; + body = val + 8; + body_end = val + len - 3; + } + else /* Parameter Change */ + { + addhigh = val[3]; + addmid = val[4]; + addlow = val[5]; + body = val + 6; + body_end = val + len - 2; + } + + /* set the SYSEX_XG_MSB info */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_MSB, 0, addhigh, addmid); + num_events++; + + for (ent = addlow; body <= body_end; body++, ent++) { + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); + num_events++; + } + } + + /* XG Multi Part Data parameter change */ + else if(len >= 10 && + val[0] == 0x43 && /* Yamaha ID */ + val[2] == 0x4C && /* XG Model ID */ + ((val[1] < 0x10 && val[5] == 0x08 && /* Bulk Dump */ + (val[4] == 0x29 || val[4] == 0x3F)) || /* Blocks 1 or 2 */ + (val[1] >= 0x10 && val[3] == 0x08))) /* Parameter Change */ + { + uint8 addhigh, addmid, addlow; /* Addresses */ + uint8 *body; /* SysEx body */ + uint8 p; /* Channel part number [0..15] */ + int ent; /* Entry # of sub-event */ + uint8 *body_end; /* End of SysEx body */ + + if (val[1] < 0x10) /* Bulk Dump */ + { + addhigh = val[5]; + addmid = val[6]; + addlow = val[7]; + body = val + 8; + p = addmid; + body_end = val + len - 3; + } + else /* Parameter Change */ + { + addhigh = val[3]; + addmid = val[4]; + addlow = val[5]; + body = val + 6; + p = addmid; + body_end = val + len - 2; + } + + /* set the SYSEX_XG_MSB info */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_MSB, p, addhigh, addmid); + num_events++; + + for (ent = addlow; body <= body_end; body++, ent++) { + switch(ent) { + case 0x00: /* Element Reserve */ +/* ctl->cmsg(CMSG_INFO, VERB_NOISY, "Element Reserve is not supported. (CH:%d VAL:%d)", p, *body); */ + break; + + case 0x01: /* bank select MSB */ + SETMIDIEVENT(evm[num_events], 0, ME_TONE_BANK_MSB, p, *body, SYSEX_TAG); + num_events++; + break; + + case 0x02: /* bank select LSB */ + SETMIDIEVENT(evm[num_events], 0, ME_TONE_BANK_LSB, p, *body, SYSEX_TAG); + num_events++; + break; + + case 0x03: /* program number */ + SETMIDIEVENT(evm[num_events], 0, ME_PROGRAM, p, *body, SYSEX_TAG); + num_events++; + break; + + case 0x04: /* Rcv CHANNEL */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, p, *body, 0x99); + num_events++; + break; + + case 0x05: /* mono/poly mode */ + if(*body == 0) {SETMIDIEVENT(evm[num_events], 0, ME_MONO, p, 0, SYSEX_TAG);} + else {SETMIDIEVENT(evm[num_events], 0, ME_POLY, p, 0, SYSEX_TAG);} + num_events++; + break; + + case 0x06: /* Same Note Number Key On Assign */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, p, *body, ent); + num_events++; + break; + + case 0x07: /* Part Mode */ + drum_setup_xg[*body] = p; + SETMIDIEVENT(evm[num_events], 0, ME_DRUMPART, p, *body, SYSEX_TAG); + num_events++; + break; + + case 0x08: /* note shift */ + SETMIDIEVENT(evm[num_events], 0, ME_KEYSHIFT, p, *body, SYSEX_TAG); + num_events++; + break; + + case 0x09: /* Detune 1st bit */ + ctl->cmsg(CMSG_INFO, VERB_NOISY, "Detune 1st bit is not supported. (CH:%d VAL:%d)", p, *body); + break; + + case 0x0A: /* Detune 2nd bit */ + ctl->cmsg(CMSG_INFO, VERB_NOISY, "Detune 2nd bit is not supported. (CH:%d VAL:%d)", p, *body); + break; + + case 0x0B: /* volume */ + SETMIDIEVENT(evm[num_events], 0, ME_MAINVOLUME, p, *body, SYSEX_TAG); + num_events++; + break; + + case 0x0C: /* Velocity Sense Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_GS_LSB, p, *body, 0x21); + num_events++; + break; + + case 0x0D: /* Velocity Sense Offset */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_GS_LSB, p, *body, 0x22); + num_events++; + break; + + case 0x0E: /* pan */ + if(*body == 0) { + SETMIDIEVENT(evm[num_events], 0, ME_RANDOM_PAN, p, 0, SYSEX_TAG); + } + else { + SETMIDIEVENT(evm[num_events], 0, ME_PAN, p, *body, SYSEX_TAG); + } + num_events++; + break; + + case 0x0F: /* Note Limit Low */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x42); + num_events++; + break; + + case 0x10: /* Note Limit High */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x43); + num_events++; + break; + + case 0x11: /* Dry Level */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, p, *body, ent); + num_events++; + break; + + case 0x12: /* chorus send */ + SETMIDIEVENT(evm[num_events], 0, ME_CHORUS_EFFECT, p, *body, SYSEX_TAG); + num_events++; + break; + + case 0x13: /* reverb send */ + SETMIDIEVENT(evm[num_events], 0, ME_REVERB_EFFECT, p, *body, SYSEX_TAG); + num_events++; + break; + + case 0x14: /* Variation Send */ + SETMIDIEVENT(evm[num_events], 0, ME_CELESTE_EFFECT, p, *body, SYSEX_TAG); + num_events++; + break; + + case 0x15: /* Vibrato Rate */ + SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, p, 0x08, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); + num_events += 3; + break; + + case 0x16: /* Vibrato Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, p, 0x09, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); + num_events += 3; + break; + + case 0x17: /* Vibrato Delay */ + SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, p, 0x0A, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); + num_events += 3; + break; + + case 0x18: /* Filter Cutoff Frequency */ + SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, p, 0x20, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); + num_events += 3; + break; + + case 0x19: /* Filter Resonance */ + SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, p, 0x21, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); + num_events += 3; + break; + + case 0x1A: /* EG Attack Time */ + SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, p, 0x63, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); + num_events += 3; + break; + + case 0x1B: /* EG Decay Time */ + SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, p, 0x64, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); + num_events += 3; + break; + + case 0x1C: /* EG Release Time */ + SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, p, 0x66, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); + num_events += 3; + break; + + case 0x1D: /* MW Pitch Control */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x16); + num_events++; + break; + + case 0x1E: /* MW Filter Control */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x17); + num_events++; + break; + + case 0x1F: /* MW Amplitude Control */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x18); + num_events++; + break; + + case 0x20: /* MW LFO PMod Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x1A); + num_events++; + break; + + case 0x21: /* MW LFO FMod Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x1B); + num_events++; + break; + + case 0x22: /* MW LFO AMod Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x1C); + num_events++; + break; + + case 0x23: /* bend pitch control */ + SETMIDIEVENT(evm[num_events], 0, ME_RPN_MSB, p, 0, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_RPN_LSB, p, 0, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, p, (*body - 0x40) & 0x7F, SYSEX_TAG); + num_events += 3; + break; + + case 0x24: /* Bend Filter Control */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x22); + num_events++; + break; + + case 0x25: /* Bend Amplitude Control */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x23); + num_events++; + break; + + case 0x26: /* Bend LFO PMod Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x25); + num_events++; + break; + + case 0x27: /* Bend LFO FMod Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x26); + num_events++; + break; + + case 0x28: /* Bend LFO AMod Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x27); + num_events++; + break; + + case 0x30: /* Rcv Pitch Bend */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x48); + num_events++; + break; + + case 0x31: /* Rcv Channel Pressure */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x49); + num_events++; + break; + + case 0x32: /* Rcv Program Change */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x4A); + num_events++; + break; + + case 0x33: /* Rcv Control Change */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x4B); + num_events++; + break; + + case 0x34: /* Rcv Poly Pressure */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x4C); + num_events++; + break; + + case 0x35: /* Rcv Note Message */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x4D); + num_events++; + break; + + case 0x36: /* Rcv RPN */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x4E); + num_events++; + break; + + case 0x37: /* Rcv NRPN */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x4F); + num_events++; + break; + + case 0x38: /* Rcv Modulation */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x50); + num_events++; + break; + + case 0x39: /* Rcv Volume */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x51); + num_events++; + break; + + case 0x3A: /* Rcv Pan */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x52); + num_events++; + break; + + case 0x3B: /* Rcv Expression */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x53); + num_events++; + break; + + case 0x3C: /* Rcv Hold1 */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x54); + num_events++; + break; + + case 0x3D: /* Rcv Portamento */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x55); + num_events++; + break; + + case 0x3E: /* Rcv Sostenuto */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x56); + num_events++; + break; + + case 0x3F: /* Rcv Soft */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x57); + num_events++; + break; + + case 0x40: /* Rcv Bank Select */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x58); + num_events++; + break; + + case 0x41: /* scale tuning */ + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + case 0x4c: + SETMIDIEVENT(evm[num_events], 0, ME_SCALE_TUNING, p, ent - 0x41, *body - 64); + num_events++; + ctl->cmsg(CMSG_INFO, VERB_NOISY, "Scale Tuning %s (CH:%d %d cent)", + note_name[ent - 0x41], p, *body - 64); + break; + + case 0x4D: /* CAT Pitch Control */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x00); + num_events++; + break; + + case 0x4E: /* CAT Filter Control */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x01); + num_events++; + break; + + case 0x4F: /* CAT Amplitude Control */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x02); + num_events++; + break; + + case 0x50: /* CAT LFO PMod Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x04); + num_events++; + break; + + case 0x51: /* CAT LFO FMod Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x05); + num_events++; + break; + + case 0x52: /* CAT LFO AMod Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x06); + num_events++; + break; + + case 0x53: /* PAT Pitch Control */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x0B); + num_events++; + break; + + case 0x54: /* PAT Filter Control */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x0C); + num_events++; + break; + + case 0x55: /* PAT Amplitude Control */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x0D); + num_events++; + break; + + case 0x56: /* PAT LFO PMod Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x0F); + num_events++; + break; + + case 0x57: /* PAT LFO FMod Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x10); + num_events++; + break; + + case 0x58: /* PAT LFO AMod Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x11); + num_events++; + break; + + case 0x59: /* AC1 Controller Number */ + ctl->cmsg(CMSG_INFO, VERB_NOISY, "AC1 Controller Number is not supported. (CH:%d VAL:%d)", p, *body); + break; + + case 0x5A: /* AC1 Pitch Control */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x2C); + num_events++; + break; + + case 0x5B: /* AC1 Filter Control */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x2D); + num_events++; + break; + + case 0x5C: /* AC1 Amplitude Control */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x2E); + num_events++; + break; + + case 0x5D: /* AC1 LFO PMod Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x30); + num_events++; + break; + + case 0x5E: /* AC1 LFO FMod Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x31); + num_events++; + break; + + case 0x5F: /* AC1 LFO AMod Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x32); + num_events++; + break; + + case 0x60: /* AC2 Controller Number */ + ctl->cmsg(CMSG_INFO, VERB_NOISY, "AC2 Controller Number is not supported. (CH:%d VAL:%d)", p, *body); + break; + + case 0x61: /* AC2 Pitch Control */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x37); + num_events++; + break; + + case 0x62: /* AC2 Filter Control */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x38); + num_events++; + break; + + case 0x63: /* AC2 Amplitude Control */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x39); + num_events++; + break; + + case 0x64: /* AC2 LFO PMod Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x3B); + num_events++; + break; + + case 0x65: /* AC2 LFO FMod Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x3C); + num_events++; + break; + + case 0x66: /* AC2 LFO AMod Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x3D); + num_events++; + break; + + case 0x67: /* Portamento Switch */ + SETMIDIEVENT(evm[num_events], 0, ME_PORTAMENTO, p, *body, SYSEX_TAG); + num_events++; + + case 0x68: /* Portamento Time */ + SETMIDIEVENT(evm[num_events], 0, ME_PORTAMENTO_TIME_MSB, p, *body, SYSEX_TAG); + num_events++; + + case 0x69: /* Pitch EG Initial Level */ + ctl->cmsg(CMSG_INFO, VERB_NOISY, "Pitch EG Initial Level is not supported. (CH:%d VAL:%d)", p, *body); + break; + + case 0x6A: /* Pitch EG Attack Time */ + ctl->cmsg(CMSG_INFO, VERB_NOISY, "Pitch EG Attack Time is not supported. (CH:%d VAL:%d)", p, *body); + break; + + case 0x6B: /* Pitch EG Release Level */ + ctl->cmsg(CMSG_INFO, VERB_NOISY, "Pitch EG Release Level is not supported. (CH:%d VAL:%d)", p, *body); + break; + + case 0x6C: /* Pitch EG Release Time */ + ctl->cmsg(CMSG_INFO, VERB_NOISY, "Pitch EG Release Time is not supported. (CH:%d VAL:%d)", p, *body); + break; + + case 0x6D: /* Velocity Limit Low */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x44); + num_events++; + break; + + case 0x6E: /* Velocity Limit High */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x45); + num_events++; + break; + + case 0x70: /* Bend Pitch Low Control */ + ctl->cmsg(CMSG_INFO, VERB_NOISY, "Bend Pitch Low Control is not supported. (CH:%d VAL:%d)", p, *body); + break; + + case 0x71: /* Filter EG Depth */ + ctl->cmsg(CMSG_INFO, VERB_NOISY, "Filter EG Depth is not supported. (CH:%d VAL:%d)", p, *body); + break; + + case 0x72: /* EQ BASS */ + SETMIDIEVENT(evm[num_events], 0,ME_NRPN_MSB, p, 0x01, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0,ME_NRPN_LSB, p, 0x30, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0,ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); + num_events += 3; + break; + + case 0x73: /* EQ TREBLE */ + SETMIDIEVENT(evm[num_events], 0,ME_NRPN_MSB, p, 0x01, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0,ME_NRPN_LSB, p, 0x31, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0,ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); + num_events += 3; + break; + + case 0x76: /* EQ BASS frequency */ + SETMIDIEVENT(evm[num_events], 0,ME_NRPN_MSB, p, 0x01, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0,ME_NRPN_LSB, p, 0x34, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0,ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); + num_events += 3; + break; + + case 0x77: /* EQ TREBLE frequency */ + SETMIDIEVENT(evm[num_events], 0,ME_NRPN_MSB, p, 0x01, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0,ME_NRPN_LSB, p, 0x35, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0,ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); + num_events += 3; + break; + + default: + ctl->cmsg(CMSG_INFO,VERB_NOISY,"Unsupported XG Bulk Dump SysEx. (ADDR:%02X %02X %02X VAL:%02X)",addhigh,addlow,ent,*body); + continue; + break; + } + } + } + + /* XG Drum Setup */ + else if(len >= 10 && + val[0] == 0x43 && /* Yamaha ID */ + val[2] == 0x4C && /* XG Model ID */ + ((val[1] < 0x10 && (val[5] & 0xF0) == 0x30) || /* Bulk Dump*/ + (val[1] >= 0x10 && (val[3] & 0xF0) == 0x30))) /* Parameter Change */ + { + uint8 addhigh, addmid, addlow; /* Addresses */ + uint8 *body; /* SysEx body */ + uint8 dp, note; /* Channel part number [0..15] */ + int ent; /* Entry # of sub-event */ + uint8 *body_end; /* End of SysEx body */ + + if (val[1] < 0x10) /* Bulk Dump */ + { + addhigh = val[5]; + addmid = val[6]; + addlow = val[7]; + body = val + 8; + body_end = val + len - 3; + } + else /* Parameter Change */ + { + addhigh = val[3]; + addmid = val[4]; + addlow = val[5]; + body = val + 6; + body_end = val + len - 2; + } + + dp = drum_setup_xg[(addhigh & 0x0F) + 1]; + note = addmid; + + /* set the SYSEX_XG_MSB info */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_MSB, dp, addhigh, addmid); + num_events++; + + for (ent = addlow; body <= body_end; body++, ent++) { + switch(ent) { + case 0x00: /* Pitch Coarse */ + SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x18, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); + num_events += 3; + break; + case 0x01: /* Pitch Fine */ + SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x19, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); + num_events += 3; + break; + case 0x02: /* Level */ + SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x1A, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); + num_events += 3; + break; + case 0x03: /* Alternate Group */ + ctl->cmsg(CMSG_INFO, VERB_NOISY, "Alternate Group is not supported. (CH:%d NOTE:%d VAL:%d)", dp, note, *body); + break; + case 0x04: /* Pan */ + SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x1C, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); + num_events += 3; + break; + case 0x05: /* Reverb Send */ + SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x1D, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); + num_events += 3; + break; + case 0x06: /* Chorus Send */ + SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x1E, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); + num_events += 3; + break; + case 0x07: /* Variation Send */ + SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x1F, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); + num_events += 3; + break; + case 0x08: /* Key Assign */ + ctl->cmsg(CMSG_INFO, VERB_NOISY, "Key Assign is not supported. (CH:%d NOTE:%d VAL:%d)", dp, note, *body); + break; + case 0x09: /* Rcv Note Off */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_MSB, dp, note, 0); + SETMIDIEVENT(evm[num_events + 1], 0, ME_SYSEX_LSB, dp, *body, 0x46); + num_events += 2; + break; + case 0x0A: /* Rcv Note On */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_MSB, dp, note, 0); + SETMIDIEVENT(evm[num_events + 1], 0, ME_SYSEX_LSB, dp, *body, 0x47); + num_events += 2; + break; + case 0x0B: /* Filter Cutoff Frequency */ + SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x14, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); + num_events += 3; + break; + case 0x0C: /* Filter Resonance */ + SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x15, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); + num_events += 3; + break; + case 0x0D: /* EG Attack */ + SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x16, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); + num_events += 3; + break; + case 0x0E: /* EG Decay1 */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, dp, *body, ent); + num_events++; + break; + case 0x0F: /* EG Decay2 */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, dp, *body, ent); + num_events++; + break; + case 0x20: /* EQ BASS */ + SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x30, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); + num_events += 3; + break; + case 0x21: /* EQ TREBLE */ + SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x31, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); + num_events += 3; + break; + case 0x24: /* EQ BASS frequency */ + SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x34, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); + num_events += 3; + break; + case 0x25: /* EQ TREBLE frequency */ + SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x35, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); + SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); + num_events += 3; + break; + case 0x50: /* High Pass Filter Cutoff Frequency */ + ctl->cmsg(CMSG_INFO, VERB_NOISY, "High Pass Filter Cutoff Frequency is not supported. (CH:%d NOTE:%d VAL:%d)", dp, note, *body); + break; + case 0x60: /* Velocity Pitch Sense */ + ctl->cmsg(CMSG_INFO, VERB_NOISY, "Velocity Pitch Sense is not supported. (CH:%d NOTE:%d VAL:%d)", dp, note, *body); + break; + case 0x61: /* Velocity LPF Cutoff Sense */ + ctl->cmsg(CMSG_INFO, VERB_NOISY, "Velocity LPF Cutoff Sense is not supported. (CH:%d NOTE:%d VAL:%d)", dp, note, *body); + break; + default: + ctl->cmsg(CMSG_INFO,VERB_NOISY,"Unsupported XG Bulk Dump SysEx. (ADDR:%02X %02X %02X VAL:%02X)",addhigh,addmid,ent,*body); + break; + } + } + } + + /* parsing GS System Exclusive Message... + * + * val[4] == Parameter Address(High) + * val[5] == Parameter Address(Middle) + * val[6] == Parameter Address(Low) + * val[7]... == Data... + * val[last] == Checksum(== 128 - (sum of addresses&data bytes % 128)) + */ + else if(len >= 9 && + val[0] == 0x41 && /* Roland ID */ + val[1] == 0x10 && /* Device ID */ + val[2] == 0x42 && /* GS Model ID */ + val[3] == 0x12) /* Data Set Command */ + { + uint8 p, dp, udn, gslen, port = 0; + int i, addr, addr_h, addr_m, addr_l, checksum; + p = block_to_part(val[5], midi_port_number); + + /* calculate checksum */ + checksum = 0; + for(gslen = 9; gslen < len; gslen++) + if(val[gslen] == 0xF7) + break; + for(i=4;i<gslen-1;i++) { + checksum += val[i]; + } + if(((128 - (checksum & 0x7F)) & 0x7F) != val[gslen-1]) { + ctl->cmsg(CMSG_INFO,VERB_NOISY,"GS SysEx: Checksum Error."); + return num_events; + } + + /* drum channel */ + dp = rhythm_part[(val[5] & 0xF0) >> 4]; + + /* calculate user drumset number */ + udn = (val[5] & 0xF0) >> 4; + + addr_h = val[4]; + addr_m = val[5]; + addr_l = val[6]; + if(addr_h == 0x50) { /* for double module mode */ + port = 1; + p = block_to_part(val[5], port); + addr_h = 0x40; + } else if(addr_h == 0x51) { + port = 1; + p = block_to_part(val[5], port); + addr_h = 0x41; + } + addr = (((int32)addr_h)<<16 | ((int32)addr_m)<<8 | (int32)addr_l); + + switch(addr_h) { + case 0x40: + if((addr & 0xFFF000) == 0x401000) { + switch(addr & 0xFF) { + case 0x00: /* Tone Number */ + SETMIDIEVENT(evm[0], 0, ME_TONE_BANK_MSB, p,val[7], SYSEX_TAG); + SETMIDIEVENT(evm[1], 0, ME_PROGRAM, p, val[8], SYSEX_TAG); + num_events += 2; + break; + case 0x02: /* Rx. Channel */ + if (val[7] == 0x10) { + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, + block_to_part(val[5], + midi_port_number ^ port), 0x80, 0x45); + } else { + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, + block_to_part(val[5], + midi_port_number ^ port), + MERGE_CHANNEL_PORT2(val[7], + midi_port_number ^ port), 0x45); + } + num_events++; + break; + case 0x03: /* Rx. Pitch Bend */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x48); + num_events++; + break; + case 0x04: /* Rx. Channel Pressure */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x49); + num_events++; + break; + case 0x05: /* Rx. Program Change */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x4A); + num_events++; + break; + case 0x06: /* Rx. Control Change */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x4B); + num_events++; + break; + case 0x07: /* Rx. Poly Pressure */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x4C); + num_events++; + break; + case 0x08: /* Rx. Note Message */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x4D); + num_events++; + break; + case 0x09: /* Rx. RPN */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x4E); + num_events++; + break; + case 0x0A: /* Rx. NRPN */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x4F); + num_events++; + break; + case 0x0B: /* Rx. Modulation */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x50); + num_events++; + break; + case 0x0C: /* Rx. Volume */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x51); + num_events++; + break; + case 0x0D: /* Rx. Panpot */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x52); + num_events++; + break; + case 0x0E: /* Rx. Expression */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x53); + num_events++; + break; + case 0x0F: /* Rx. Hold1 */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x54); + num_events++; + break; + case 0x10: /* Rx. Portamento */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x55); + num_events++; + break; + case 0x11: /* Rx. Sostenuto */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x56); + num_events++; + break; + case 0x12: /* Rx. Soft */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x57); + num_events++; + break; + case 0x13: /* MONO/POLY Mode */ + if(val[7] == 0) {SETMIDIEVENT(evm[0], 0, ME_MONO, p, val[7], SYSEX_TAG);} + else {SETMIDIEVENT(evm[0], 0, ME_POLY, p, val[7], SYSEX_TAG);} + num_events++; + break; + case 0x14: /* Assign Mode */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x24); + num_events++; + break; + case 0x15: /* Use for Rhythm Part */ + if(val[7]) { + rhythm_part[val[7] - 1] = p; + } + break; + case 0x16: /* Pitch Key Shift (dummy. see parse_sysex_event()) */ + break; + case 0x17: /* Pitch Offset Fine */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x26); + num_events++; + break; + case 0x19: /* Part Level */ + SETMIDIEVENT(evm[0], 0, ME_MAINVOLUME, p, val[7], SYSEX_TAG); + num_events++; + break; + case 0x1A: /* Velocity Sense Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x21); + num_events++; + break; + case 0x1B: /* Velocity Sense Offset */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x22); + num_events++; + break; + case 0x1C: /* Part Panpot */ + if (val[7] == 0) { + SETMIDIEVENT(evm[0], 0, ME_RANDOM_PAN, p, 0, SYSEX_TAG); + } else { + SETMIDIEVENT(evm[0], 0, ME_PAN, p, val[7], SYSEX_TAG); + } + num_events++; + break; + case 0x1D: /* Keyboard Range Low */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x42); + num_events++; + break; + case 0x1E: /* Keyboard Range High */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x43); + num_events++; + break; + case 0x1F: /* CC1 Controller Number */ + ctl->cmsg(CMSG_INFO, VERB_NOISY, "CC1 Controller Number is not supported. (CH:%d VAL:%d)", p, val[7]); + break; + case 0x20: /* CC2 Controller Number */ + ctl->cmsg(CMSG_INFO, VERB_NOISY, "CC2 Controller Number is not supported. (CH:%d VAL:%d)", p, val[7]); + break; + case 0x21: /* Chorus Send Level */ + SETMIDIEVENT(evm[0], 0, ME_CHORUS_EFFECT, p, val[7], SYSEX_TAG); + num_events++; + break; + case 0x22: /* Reverb Send Level */ + SETMIDIEVENT(evm[0], 0, ME_REVERB_EFFECT, p, val[7], SYSEX_TAG); + num_events++; + break; + case 0x23: /* Rx. Bank Select */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x58); + num_events++; + break; + case 0x24: /* Rx. Bank Select LSB */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x59); + num_events++; + break; + case 0x2C: /* Delay Send Level */ + SETMIDIEVENT(evm[0], 0, ME_CELESTE_EFFECT, p, val[7], SYSEX_TAG); + num_events++; + break; + case 0x2A: /* Pitch Fine Tune */ + SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, p, 0x00, SYSEX_TAG); + SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, p, 0x01, SYSEX_TAG); + SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, p, val[7], SYSEX_TAG); + SETMIDIEVENT(evm[3], 0, ME_DATA_ENTRY_LSB, p, val[8], SYSEX_TAG); + num_events += 4; + break; + case 0x30: /* TONE MODIFY1: Vibrato Rate */ + SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); + SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, p, 0x08, SYSEX_TAG); + SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, p, val[7], SYSEX_TAG); + num_events += 3; + break; + case 0x31: /* TONE MODIFY2: Vibrato Depth */ + SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); + SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, p, 0x09, SYSEX_TAG); + SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, p, val[7], SYSEX_TAG); + num_events += 3; + break; + case 0x32: /* TONE MODIFY3: TVF Cutoff Freq */ + SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); + SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, p, 0x20, SYSEX_TAG); + SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, p, val[7], SYSEX_TAG); + num_events += 3; + break; + case 0x33: /* TONE MODIFY4: TVF Resonance */ + SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); + SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, p, 0x21, SYSEX_TAG); + SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, p, val[7], SYSEX_TAG); + num_events += 3; + break; + case 0x34: /* TONE MODIFY5: TVF&TVA Env.attack */ + SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); + SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, p, 0x63, SYSEX_TAG); + SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, p, val[7], SYSEX_TAG); + num_events += 3; + break; + case 0x35: /* TONE MODIFY6: TVF&TVA Env.decay */ + SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); + SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, p, 0x64, SYSEX_TAG); + SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, p, val[7], SYSEX_TAG); + num_events += 3; + break; + case 0x36: /* TONE MODIFY7: TVF&TVA Env.release */ + SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); + SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, p, 0x66, SYSEX_TAG); + SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, p, val[7], SYSEX_TAG); + num_events += 3; + break; + case 0x37: /* TONE MODIFY8: Vibrato Delay */ + SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); + SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, p, 0x0A, SYSEX_TAG); + SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, p, val[7], SYSEX_TAG); + num_events += 3; + break; + case 0x40: /* Scale Tuning */ + for (i = 0; i < 12; i++) { + SETMIDIEVENT(evm[i], + 0, ME_SCALE_TUNING, p, i, val[i + 7] - 64); + ctl->cmsg(CMSG_INFO, VERB_NOISY, + "Scale Tuning %s (CH:%d %d cent)", + note_name[i], p, val[i + 7] - 64); + } + num_events += 12; + break; + default: + ctl->cmsg(CMSG_INFO,VERB_NOISY,"Unsupported GS SysEx. (ADDR:%02X %02X %02X VAL:%02X %02X)",addr_h,addr_m,addr_l,val[7],val[8]); + break; + } + } else if((addr & 0xFFF000) == 0x402000) { + switch(addr & 0xFF) { + case 0x00: /* MOD Pitch Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x16); + num_events++; + break; + case 0x01: /* MOD TVF Cutoff Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x17); + num_events++; + break; + case 0x02: /* MOD Amplitude Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x18); + num_events++; + break; + case 0x03: /* MOD LFO1 Rate Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x19); + num_events++; + break; + case 0x04: /* MOD LFO1 Pitch Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x1A); + num_events++; + break; + case 0x05: /* MOD LFO1 TVF Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x1B); + num_events++; + break; + case 0x06: /* MOD LFO1 TVA Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x1C); + num_events++; + break; + case 0x07: /* MOD LFO2 Rate Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x1D); + num_events++; + break; + case 0x08: /* MOD LFO2 Pitch Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x1E); + num_events++; + break; + case 0x09: /* MOD LFO2 TVF Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x1F); + num_events++; + break; + case 0x0A: /* MOD LFO2 TVA Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x20); + num_events++; + break; + case 0x10: /* !!!FIXME!!! Bend Pitch Control */ + SETMIDIEVENT(evm[0], 0, ME_RPN_MSB, p, 0, SYSEX_TAG); + SETMIDIEVENT(evm[1], 0, ME_RPN_LSB, p, 0, SYSEX_TAG); + SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, p, (val[7] - 0x40) & 0x7F, SYSEX_TAG); + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x21); + num_events += 4; + break; + case 0x11: /* Bend TVF Cutoff Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x22); + num_events++; + break; + case 0x12: /* Bend Amplitude Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x23); + num_events++; + break; + case 0x13: /* Bend LFO1 Rate Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x24); + num_events++; + break; + case 0x14: /* Bend LFO1 Pitch Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x25); + num_events++; + break; + case 0x15: /* Bend LFO1 TVF Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x26); + num_events++; + break; + case 0x16: /* Bend LFO1 TVA Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x27); + num_events++; + break; + case 0x17: /* Bend LFO2 Rate Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x28); + num_events++; + break; + case 0x18: /* Bend LFO2 Pitch Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x29); + num_events++; + break; + case 0x19: /* Bend LFO2 TVF Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x2A); + num_events++; + break; + case 0x1A: /* Bend LFO2 TVA Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x2B); + num_events++; + break; + case 0x20: /* CAf Pitch Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x00); + num_events++; + break; + case 0x21: /* CAf TVF Cutoff Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x01); + num_events++; + break; + case 0x22: /* CAf Amplitude Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x02); + num_events++; + break; + case 0x23: /* CAf LFO1 Rate Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x03); + num_events++; + break; + case 0x24: /* CAf LFO1 Pitch Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x04); + num_events++; + break; + case 0x25: /* CAf LFO1 TVF Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x05); + num_events++; + break; + case 0x26: /* CAf LFO1 TVA Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x06); + num_events++; + break; + case 0x27: /* CAf LFO2 Rate Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x07); + num_events++; + break; + case 0x28: /* CAf LFO2 Pitch Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x08); + num_events++; + break; + case 0x29: /* CAf LFO2 TVF Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x09); + num_events++; + break; + case 0x2A: /* CAf LFO2 TVA Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x0A); + num_events++; + break; + case 0x30: /* PAf Pitch Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x0B); + num_events++; + break; + case 0x31: /* PAf TVF Cutoff Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x0C); + num_events++; + break; + case 0x32: /* PAf Amplitude Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x0D); + num_events++; + break; + case 0x33: /* PAf LFO1 Rate Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x0E); + num_events++; + break; + case 0x34: /* PAf LFO1 Pitch Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x0F); + num_events++; + break; + case 0x35: /* PAf LFO1 TVF Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x10); + num_events++; + break; + case 0x36: /* PAf LFO1 TVA Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x11); + num_events++; + break; + case 0x37: /* PAf LFO2 Rate Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x12); + num_events++; + break; + case 0x38: /* PAf LFO2 Pitch Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x13); + num_events++; + break; + case 0x39: /* PAf LFO2 TVF Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x14); + num_events++; + break; + case 0x3A: /* PAf LFO2 TVA Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x15); + num_events++; + break; + case 0x40: /* CC1 Pitch Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x2C); + num_events++; + break; + case 0x41: /* CC1 TVF Cutoff Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x2D); + num_events++; + break; + case 0x42: /* CC1 Amplitude Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x2E); + num_events++; + break; + case 0x43: /* CC1 LFO1 Rate Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x2F); + num_events++; + break; + case 0x44: /* CC1 LFO1 Pitch Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x30); + num_events++; + break; + case 0x45: /* CC1 LFO1 TVF Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x31); + num_events++; + break; + case 0x46: /* CC1 LFO1 TVA Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x32); + num_events++; + break; + case 0x47: /* CC1 LFO2 Rate Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x33); + num_events++; + break; + case 0x48: /* CC1 LFO2 Pitch Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x34); + num_events++; + break; + case 0x49: /* CC1 LFO2 TVF Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x35); + num_events++; + break; + case 0x4A: /* CC1 LFO2 TVA Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x36); + num_events++; + break; + case 0x50: /* CC2 Pitch Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x37); + num_events++; + break; + case 0x51: /* CC2 TVF Cutoff Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x38); + num_events++; + break; + case 0x52: /* CC2 Amplitude Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x39); + num_events++; + break; + case 0x53: /* CC2 LFO1 Rate Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x3A); + num_events++; + break; + case 0x54: /* CC2 LFO1 Pitch Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x3B); + num_events++; + break; + case 0x55: /* CC2 LFO1 TVF Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x3C); + num_events++; + break; + case 0x56: /* CC2 LFO1 TVA Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x3D); + num_events++; + break; + case 0x57: /* CC2 LFO2 Rate Control */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x3E); + num_events++; + break; + case 0x58: /* CC2 LFO2 Pitch Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x3F); + num_events++; + break; + case 0x59: /* CC2 LFO2 TVF Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x40); + num_events++; + break; + case 0x5A: /* CC2 LFO2 TVA Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x41); + num_events++; + break; + default: + ctl->cmsg(CMSG_INFO,VERB_NOISY,"Unsupported GS SysEx. (ADDR:%02X %02X %02X VAL:%02X %02X)",addr_h,addr_m,addr_l,val[7],val[8]); + break; + } + } else if((addr & 0xFFFF00) == 0x400100) { + switch(addr & 0xFF) { + case 0x30: /* Reverb Macro */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x05); + num_events++; + break; + case 0x31: /* Reverb Character */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x06); + num_events++; + break; + case 0x32: /* Reverb Pre-LPF */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x07); + num_events++; + break; + case 0x33: /* Reverb Level */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x08); + num_events++; + break; + case 0x34: /* Reverb Time */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x09); + num_events++; + break; + case 0x35: /* Reverb Delay Feedback */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x0A); + num_events++; + break; + case 0x36: /* Unknown Reverb Parameter */ + break; + case 0x37: /* Reverb Predelay Time */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x0C); + num_events++; + break; + case 0x38: /* Chorus Macro */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x0D); + num_events++; + break; + case 0x39: /* Chorus Pre-LPF */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x0E); + num_events++; + break; + case 0x3A: /* Chorus Level */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x0F); + num_events++; + break; + case 0x3B: /* Chorus Feedback */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x10); + num_events++; + break; + case 0x3C: /* Chorus Delay */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x11); + num_events++; + break; + case 0x3D: /* Chorus Rate */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x12); + num_events++; + break; + case 0x3E: /* Chorus Depth */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x13); + num_events++; + break; + case 0x3F: /* Chorus Send Level to Reverb */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x14); + num_events++; + break; + case 0x40: /* Chorus Send Level to Delay */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x15); + num_events++; + break; + case 0x50: /* Delay Macro */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x16); + num_events++; + break; + case 0x51: /* Delay Pre-LPF */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x17); + num_events++; + break; + case 0x52: /* Delay Time Center */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x18); + num_events++; + break; + case 0x53: /* Delay Time Ratio Left */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x19); + num_events++; + break; + case 0x54: /* Delay Time Ratio Right */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x1A); + num_events++; + break; + case 0x55: /* Delay Level Center */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x1B); + num_events++; + break; + case 0x56: /* Delay Level Left */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x1C); + num_events++; + break; + case 0x57: /* Delay Level Right */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x1D); + num_events++; + break; + case 0x58: /* Delay Level */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x1E); + num_events++; + break; + case 0x59: /* Delay Feedback */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x1F); + num_events++; + break; + case 0x5A: /* Delay Send Level to Reverb */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x20); + num_events++; + break; + default: + ctl->cmsg(CMSG_INFO,VERB_NOISY,"Unsupported GS SysEx. (ADDR:%02X %02X %02X VAL:%02X %02X)",addr_h,addr_m,addr_l,val[7],val[8]); + break; + } + } else if((addr & 0xFFFF00) == 0x400200) { + switch(addr & 0xFF) { /* EQ Parameter */ + case 0x00: /* EQ LOW FREQ */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x01); + num_events++; + break; + case 0x01: /* EQ LOW GAIN */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x02); + num_events++; + break; + case 0x02: /* EQ HIGH FREQ */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x03); + num_events++; + break; + case 0x03: /* EQ HIGH GAIN */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x04); + num_events++; + break; + default: + ctl->cmsg(CMSG_INFO,VERB_NOISY,"Unsupported GS SysEx. (ADDR:%02X %02X %02X VAL:%02X %02X)",addr_h,addr_m,addr_l,val[7],val[8]); + break; + } + } else if((addr & 0xFFFF00) == 0x400300) { + switch(addr & 0xFF) { /* Insertion Effect Parameter */ + case 0x00: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x27); + SETMIDIEVENT(evm[1], 0, ME_SYSEX_GS_LSB, p, val[8], 0x28); + num_events += 2; + break; + case 0x03: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x29); + num_events++; + break; + case 0x04: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x2A); + num_events++; + break; + case 0x05: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x2B); + num_events++; + break; + case 0x06: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x2C); + num_events++; + break; + case 0x07: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x2D); + num_events++; + break; + case 0x08: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x2E); + num_events++; + break; + case 0x09: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x2F); + num_events++; + break; + case 0x0A: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x30); + num_events++; + break; + case 0x0B: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x31); + num_events++; + break; + case 0x0C: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x32); + num_events++; + break; + case 0x0D: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x33); + num_events++; + break; + case 0x0E: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x34); + num_events++; + break; + case 0x0F: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x35); + num_events++; + break; + case 0x10: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x36); + num_events++; + break; + case 0x11: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x37); + num_events++; + break; + case 0x12: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x38); + num_events++; + break; + case 0x13: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x39); + num_events++; + break; + case 0x14: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x3A); + num_events++; + break; + case 0x15: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x3B); + num_events++; + break; + case 0x16: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x3C); + num_events++; + break; + case 0x17: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x3D); + num_events++; + break; + case 0x18: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x3E); + num_events++; + break; + case 0x19: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x3F); + num_events++; + break; + case 0x1B: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x40); + num_events++; + break; + case 0x1C: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x41); + num_events++; + break; + case 0x1D: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x42); + num_events++; + break; + case 0x1E: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x43); + num_events++; + break; + case 0x1F: + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x44); + num_events++; + break; + default: + ctl->cmsg(CMSG_INFO,VERB_NOISY,"Unsupported GS SysEx. (ADDR:%02X %02X %02X VAL:%02X %02X)",addr_h,addr_m,addr_l,val[7],val[8]); + break; + } + } else if((addr & 0xFFF000) == 0x404000) { + switch(addr & 0xFF) { + case 0x00: /* TONE MAP NUMBER */ + SETMIDIEVENT(evm[0], 0, ME_TONE_BANK_LSB, p, val[7], SYSEX_TAG); + num_events++; + break; + case 0x01: /* TONE MAP-0 NUMBER */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x25); + num_events++; + break; + case 0x20: /* EQ ON/OFF */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x00); + num_events++; + break; + case 0x22: /* EFX ON/OFF */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x23); + num_events++; + break; + default: + ctl->cmsg(CMSG_INFO,VERB_NOISY,"Unsupported GS SysEx. (ADDR:%02X %02X %02X VAL:%02X %02X)",addr_h,addr_m,addr_l,val[7],val[8]); + break; + } + } + break; + case 0x41: + switch(addr & 0xF00) { + case 0x100: /* Play Note Number */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_MSB, dp, val[6], 0); + SETMIDIEVENT(evm[1], 0, ME_SYSEX_GS_LSB, dp, val[7], 0x47); + num_events += 2; + break; + case 0x200: + SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, dp, 0x1A, SYSEX_TAG); + SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, dp, val[6], SYSEX_TAG); + SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, dp, val[7], SYSEX_TAG); + num_events += 3; + break; + case 0x400: + SETMIDIEVENT(evm[0], 0,ME_NRPN_MSB, dp, 0x1C, SYSEX_TAG); + SETMIDIEVENT(evm[1], 0,ME_NRPN_LSB, dp, val[6], SYSEX_TAG); + SETMIDIEVENT(evm[2], 0,ME_DATA_ENTRY_MSB, dp, val[7], SYSEX_TAG); + num_events += 3; + break; + case 0x500: + SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, dp, 0x1D, SYSEX_TAG); + SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, dp, val[6], SYSEX_TAG); + SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, dp, val[7], SYSEX_TAG); + num_events += 3; + break; + case 0x600: + SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, dp, 0x1E, SYSEX_TAG); + SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, dp, val[6], SYSEX_TAG); + SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, dp, val[7], SYSEX_TAG); + num_events += 3; + break; + case 0x700: /* Rx. Note Off */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_MSB, dp, val[6], 0); + SETMIDIEVENT(evm[1], 0, ME_SYSEX_LSB, dp, val[7], 0x46); + num_events += 2; + break; + case 0x800: /* Rx. Note On */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_MSB, dp, val[6], 0); + SETMIDIEVENT(evm[1], 0, ME_SYSEX_LSB, dp, val[7], 0x47); + num_events += 2; + break; + case 0x900: + SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, dp, 0x1F, SYSEX_TAG); + SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, dp, val[6], SYSEX_TAG); + SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, dp, val[7], SYSEX_TAG); + num_events += 3; + break; + default: + ctl->cmsg(CMSG_INFO,VERB_NOISY,"Unsupported GS SysEx. (ADDR:%02X %02X %02X VAL:%02X %02X)",addr_h,addr_m,addr_l,val[7],val[8]); + break; + } + break; +#if 0 + case 0x20: /* User Instrument */ + switch(addr & 0xF00) { + case 0x000: /* Source Map */ + get_userinst(64 + udn, val[6])->source_map = val[7]; + break; + case 0x100: /* Source Bank */ + get_userinst(64 + udn, val[6])->source_bank = val[7]; + break; +#if !defined(TIMIDITY_TOOLS) + case 0x200: /* Source Prog */ + get_userinst(64 + udn, val[6])->source_prog = val[7]; + break; +#endif + default: + ctl->cmsg(CMSG_INFO,VERB_NOISY,"Unsupported GS SysEx. (ADDR:%02X %02X %02X VAL:%02X %02X)",addr_h,addr_m,addr_l,val[7],val[8]); + break; + } + break; +#endif + case 0x21: /* User Drumset */ + switch(addr & 0xF00) { + case 0x100: /* Play Note */ + get_userdrum(64 + udn, val[6])->play_note = val[7]; + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_MSB, dp, val[6], 0); + SETMIDIEVENT(evm[1], 0, ME_SYSEX_GS_LSB, dp, val[7], 0x47); + num_events += 2; + break; + case 0x200: /* Level */ + get_userdrum(64 + udn, val[6])->level = val[7]; + SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, dp, 0x1A, SYSEX_TAG); + SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, dp, val[6], SYSEX_TAG); + SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, dp, val[7], SYSEX_TAG); + num_events += 3; + break; + case 0x300: /* Assign Group */ + get_userdrum(64 + udn, val[6])->assign_group = val[7]; + if(val[7] != 0) {recompute_userdrum_altassign(udn + 64, val[7]);} + break; + case 0x400: /* Panpot */ + get_userdrum(64 + udn, val[6])->pan = val[7]; + SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, dp, 0x1C, SYSEX_TAG); + SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, dp, val[6], SYSEX_TAG); + SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, dp, val[7], SYSEX_TAG); + num_events += 3; + break; + case 0x500: /* Reverb Send Level */ + get_userdrum(64 + udn, val[6])->reverb_send_level = val[7]; + SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, dp, 0x1D, SYSEX_TAG); + SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, dp, val[6], SYSEX_TAG); + SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, dp, val[7], SYSEX_TAG); + num_events += 3; + break; + case 0x600: /* Chorus Send Level */ + get_userdrum(64 + udn, val[6])->chorus_send_level = val[7]; + SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, dp, 0x1E, SYSEX_TAG); + SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, dp, val[6], SYSEX_TAG); + SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, dp, val[7], SYSEX_TAG); + num_events += 3; + break; + case 0x700: /* Rx. Note Off */ + get_userdrum(64 + udn, val[6])->rx_note_off = val[7]; + SETMIDIEVENT(evm[0], 0, ME_SYSEX_MSB, dp, val[6], 0); + SETMIDIEVENT(evm[1], 0, ME_SYSEX_LSB, dp, val[7], 0x46); + num_events += 2; + break; + case 0x800: /* Rx. Note On */ + get_userdrum(64 + udn, val[6])->rx_note_on = val[7]; + SETMIDIEVENT(evm[0], 0, ME_SYSEX_MSB, dp, val[6], 0); + SETMIDIEVENT(evm[1], 0, ME_SYSEX_LSB, dp, val[7], 0x47); + num_events += 2; + break; + case 0x900: /* Delay Send Level */ + get_userdrum(64 + udn, val[6])->delay_send_level = val[7]; + SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, dp, 0x1F, SYSEX_TAG); + SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, dp, val[6], SYSEX_TAG); + SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, dp, val[7], SYSEX_TAG); + num_events += 3; + break; + case 0xA00: /* Source Map */ + get_userdrum(64 + udn, val[6])->source_map = val[7]; + break; + case 0xB00: /* Source Prog */ + get_userdrum(64 + udn, val[6])->source_prog = val[7]; + break; +#if !defined(TIMIDITY_TOOLS) + case 0xC00: /* Source Note */ + get_userdrum(64 + udn, val[6])->source_note = val[7]; + break; +#endif + default: + ctl->cmsg(CMSG_INFO,VERB_NOISY,"Unsupported GS SysEx. (ADDR:%02X %02X %02X VAL:%02X %02X)",addr_h,addr_m,addr_l,val[7],val[8]); + break; + } + break; + case 0x00: /* System */ + switch (addr & 0xfff0) { + case 0x0100: /* Channel Msg Rx Port (A) */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, + block_to_part(addr & 0xf, 0), val[7], 0x46); + num_events++; + break; + case 0x0110: /* Channel Msg Rx Port (B) */ + SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, + block_to_part(addr & 0xf, 1), val[7], 0x46); + num_events++; + break; + default: + /* ctl->cmsg(CMSG_INFO,VERB_NOISY, "Unsupported GS SysEx. " + "(ADDR:%02X %02X %02X VAL:%02X %02X)", + addr_h, addr_m, addr_l, val[7], val[8]);*/ + break; + } + break; + } + } + + /* Non-RealTime / RealTime Universal SysEx messages + * 0 0x7e(Non-RealTime) / 0x7f(RealTime) + * 1 SysEx device ID. Could be from 0x00 to 0x7f. + * 0x7f means disregard device. + * 2 Sub ID + * ... + * E 0xf7 + */ + else if (len > 4 && val[0] >= 0x7e) + switch (val[2]) { + case 0x01: /* Sample Dump header */ + case 0x02: /* Sample Dump packet */ + case 0x03: /* Dump Request */ + case 0x04: /* Device Control */ + if (val[3] == 0x05) { /* Global Parameter Control */ + if (val[7] == 0x01 && val[8] == 0x01) { /* Reverb */ + for (i = 9; i < len && val[i] != 0xf7; i+= 2) { + switch(val[i]) { + case 0x00: /* Reverb Type */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, 0, val[i + 1], 0x60); + num_events++; + break; + case 0x01: /* Reverb Time */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_GS_LSB, 0, val[i + 1], 0x09); + num_events++; + break; + } + } + } else if (val[7] == 0x01 && val[8] == 0x02) { /* Chorus */ + for (i = 9; i < len && val[i] != 0xf7; i+= 2) { + switch(val[i]) { + case 0x00: /* Chorus Type */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, 0, val[i + 1], 0x61); + num_events++; + break; + case 0x01: /* Modulation Rate */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_GS_LSB, 0, val[i + 1], 0x12); + num_events++; + break; + case 0x02: /* Modulation Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_GS_LSB, 0, val[i + 1], 0x13); + num_events++; + break; + case 0x03: /* Feedback */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_GS_LSB, 0, val[i + 1], 0x10); + num_events++; + break; + case 0x04: /* Send To Reverb */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_GS_LSB, 0, val[i + 1], 0x14); + num_events++; + break; + } + } + } + } + break; + case 0x05: /* Sample Dump extensions */ + case 0x06: /* Inquiry Message */ + case 0x07: /* File Dump */ + break; + case 0x08: /* MIDI Tuning Standard */ + switch (val[3]) { + case 0x01: + SETMIDIEVENT(evm[0], 0, ME_BULK_TUNING_DUMP, 0, val[4], 0); + for (i = 0; i < 128; i++) { + SETMIDIEVENT(evm[i * 2 + 1], 0, ME_BULK_TUNING_DUMP, + 1, i, val[i * 3 + 21]); + SETMIDIEVENT(evm[i * 2 + 2], 0, ME_BULK_TUNING_DUMP, + 2, val[i * 3 + 22], val[i * 3 + 23]); + } + num_events += 257; + break; + case 0x02: + SETMIDIEVENT(evm[0], 0, ME_SINGLE_NOTE_TUNING, + 0, val[4], 0); + for (i = 0; i < val[5]; i++) { + SETMIDIEVENT(evm[i * 2 + 1], 0, ME_SINGLE_NOTE_TUNING, + 1, val[i * 4 + 6], val[i * 4 + 7]); + SETMIDIEVENT(evm[i * 2 + 2], 0, ME_SINGLE_NOTE_TUNING, + 2, val[i * 4 + 8], val[i * 4 + 9]); + } + num_events += val[5] * 2 + 1; + break; + case 0x0b: + channel_tt = ((val[4] & 0x03) << 14 | val[5] << 7 | val[6]) + << ((val[4] >> 2) * 16); + if (val[1] == 0x7f) { + SETMIDIEVENT(evm[0], 0, ME_MASTER_TEMPER_TYPE, + 0, val[7], (val[0] == 0x7f)); + num_events++; + } else { + for (i = j = 0; i < 32; i++) + if (channel_tt & 1 << i) { + SETMIDIEVENT(evm[j], 0, ME_TEMPER_TYPE, + MERGE_CHANNEL_PORT(i), + val[7], (val[0] == 0x7f)); + j++; + } + num_events += j; + } + break; + case 0x0c: + SETMIDIEVENT(evm[0], 0, ME_USER_TEMPER_ENTRY, + 0, val[4], val[21]); + for (i = 0; i < val[21]; i++) { + SETMIDIEVENT(evm[i * 5 + 1], 0, ME_USER_TEMPER_ENTRY, + 1, val[i * 10 + 22], val[i * 10 + 23]); + SETMIDIEVENT(evm[i * 5 + 2], 0, ME_USER_TEMPER_ENTRY, + 2, val[i * 10 + 24], val[i * 10 + 25]); + SETMIDIEVENT(evm[i * 5 + 3], 0, ME_USER_TEMPER_ENTRY, + 3, val[i * 10 + 26], val[i * 10 + 27]); + SETMIDIEVENT(evm[i * 5 + 4], 0, ME_USER_TEMPER_ENTRY, + 4, val[i * 10 + 28], val[i * 10 + 29]); + SETMIDIEVENT(evm[i * 5 + 5], 0, ME_USER_TEMPER_ENTRY, + 5, val[i * 10 + 30], val[i * 10 + 31]); + } + num_events += val[21] * 5 + 1; + break; + } + break; + case 0x09: /* General MIDI Message */ + switch(val[3]) { + case 0x01: /* Channel Pressure */ + for (i = 5; i < len && val[i] != 0xf7; i+= 2) { + switch(val[i]) { + case 0x00: /* Pitch Control */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, val[4], val[i + 1], 0x00); + num_events++; + break; + case 0x01: /* Filter Cutoff Control */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, val[4], val[i + 1], 0x01); + num_events++; + break; + case 0x02: /* Amplitude Control */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, val[4], val[i + 1], 0x02); + num_events++; + break; + case 0x03: /* LFO Pitch Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, val[4], val[i + 1], 0x04); + num_events++; + break; + case 0x04: /* LFO Filter Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, val[4], val[i + 1], 0x05); + num_events++; + break; + case 0x05: /* LFO Amplitude Depth */ + SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, val[4], val[i + 1], 0x06); + num_events++; + break; + } + } + break; + } + break; + case 0x7b: /* End of File */ + case 0x7c: /* Handshaking Message: Wait */ + case 0x7d: /* Handshaking Message: Cancel */ + case 0x7e: /* Handshaking Message: NAK */ + case 0x7f: /* Handshaking Message: ACK */ + break; + } + + return(num_events); +} + +int parse_sysex_event(uint8 *val, int32 len, MidiEvent *ev) +{ + uint16 vol; + + if(current_file_info->mid == 0 || current_file_info->mid >= 0x7e) + current_file_info->mid = val[0]; + + if(len >= 10 && + val[0] == 0x41 && /* Roland ID */ + val[1] == 0x10 && /* Device ID */ + val[2] == 0x42 && /* GS Model ID */ + val[3] == 0x12) /* Data Set Command */ + { + /* Roland GS-Based Synthesizers. + * val[4..6] is address, val[7..len-2] is body. + * + * GS Channel part number + * 0 10 + * 1-9 1-9 + * 10-15 11-16 + */ + + int32 addr,checksum,i; /* SysEx address */ + uint8 *body; /* SysEx body */ + uint8 p,gslen; /* Channel part number [0..15] */ + + /* check Checksum */ + checksum = 0; + for(gslen = 9; gslen < len; gslen++) + if(val[gslen] == 0xF7) + break; + for(i=4;i<gslen-1;i++) { + checksum += val[i]; + } + if(((128 - (checksum & 0x7F)) & 0x7F) != val[gslen-1]) { + return 0; + } + + addr = (((int32)val[4])<<16 | + ((int32)val[5])<<8 | + (int32)val[6]); + body = val + 7; + p = (uint8)((addr >> 8) & 0xF); + if(p == 0) + p = 9; + else if(p <= 9) + p--; + p = MERGE_CHANNEL_PORT(p); + + if(val[4] == 0x50) { /* for double module mode */ + p += 16; + addr = (((int32)0x40)<<16 | + ((int32)val[5])<<8 | + (int32)val[6]); + } else { /* single module mode */ + addr = (((int32)val[4])<<16 | + ((int32)val[5])<<8 | + (int32)val[6]); + } + + if((addr & 0xFFF0FF) == 0x401015) /* Rhythm Parts */ + { +#ifdef GS_DRUMPART +/* GS drum part check from Masaaki Koyanagi's patch (GS_Drum_Part_Check()) */ +/* Modified by Masanao Izumo */ + SETMIDIEVENT(*ev, 0, ME_DRUMPART, p, *body, SYSEX_TAG); + return 1; +#else + return 0; +#endif /* GS_DRUMPART */ + } + + if((addr & 0xFFF0FF) == 0x401016) /* Key Shift */ + { + SETMIDIEVENT(*ev, 0, ME_KEYSHIFT, p, *body, SYSEX_TAG); + return 1; + } + + if(addr == 0x400000) /* Master Tune, not for SMF */ + { + uint16 tune = ((body[1] & 0xF) << 8) | ((body[2] & 0xF) << 4) | (body[3] & 0xF); + + if (tune < 0x18) + tune = 0x18; + else if (tune > 0x7E8) + tune = 0x7E8; + SETMIDIEVENT(*ev, 0, ME_MASTER_TUNING, 0, tune & 0xFF, (tune >> 8) & 0x7F); + return 1; + } + + if(addr == 0x400004) /* Master Volume */ + { + vol = gs_convert_master_vol(*body); + SETMIDIEVENT(*ev, 0, ME_MASTER_VOLUME, + 0, vol & 0xFF, (vol >> 8) & 0xFF); + return 1; + } + + if((addr & 0xFFF0FF) == 0x401019) /* Volume on/off */ + { +#if 0 + SETMIDIEVENT(*ev, 0, ME_VOLUME_ONOFF, p, *body >= 64, SYSEX_TAG); +#endif + return 0; + } + + if((addr & 0xFFF0FF) == 0x401002) /* Receive channel on/off */ + { +#if 0 + SETMIDIEVENT(*ev, 0, ME_RECEIVE_CHANNEL, (uint8)p, *body >= 64, SYSEX_TAG); +#endif + return 0; + } + + if(0x402000 <= addr && addr <= 0x402F5A) /* Controller Routing */ + return 0; + + if((addr & 0xFFF0FF) == 0x401040) /* Alternate Scale Tunings */ + return 0; + + if((addr & 0xFFFFF0) == 0x400130) /* Changing Effects */ + { + struct chorus_text_gs_t *chorus_text = &(chorus_status_gs.text); + switch(addr & 0xF) + { + case 0x8: /* macro */ + memcpy(chorus_text->macro, body, 3); + break; + case 0x9: /* PRE-LPF */ + memcpy(chorus_text->pre_lpf, body, 3); + break; + case 0xa: /* level */ + memcpy(chorus_text->level, body, 3); + break; + case 0xb: /* feed back */ + memcpy(chorus_text->feed_back, body, 3); + break; + case 0xc: /* delay */ + memcpy(chorus_text->delay, body, 3); + break; + case 0xd: /* rate */ + memcpy(chorus_text->rate, body, 3); + break; + case 0xe: /* depth */ + memcpy(chorus_text->depth, body, 3); + break; + case 0xf: /* send level */ + memcpy(chorus_text->send_level, body, 3); + break; + default: break; + } + + check_chorus_text_start(); + return 0; + } + + if((addr & 0xFFF0FF) == 0x401003) /* Rx Pitch-Bend */ + return 0; + + if(addr == 0x400110) /* Voice Reserve */ + { + if(len >= 25) + memcpy(chorus_status_gs.text.voice_reserve, body, 18); + check_chorus_text_start(); + return 0; + } + + if(addr == 0x40007F || /* GS Reset */ + addr == 0x00007F) /* SC-88 Single Module */ + { + SETMIDIEVENT(*ev, 0, ME_RESET, 0, GS_SYSTEM_MODE, SYSEX_TAG); + return 1; + } + return 0; + } + + if(len > 9 && + val[0] == 0x41 && /* Roland ID */ + val[1] == 0x10 && /* Device ID */ + val[2] == 0x45 && + val[3] == 0x12 && + val[4] == 0x10 && + val[5] == 0x00 && + val[6] == 0x00) + { + /* Text Insert for SC */ + uint8 save; + + len -= 2; + save = val[len]; + val[len] = '\0'; + if(readmidi_make_string_event(ME_INSERT_TEXT, (char *)val + 7, ev, 1)) + { + val[len] = save; + return 1; + } + val[len] = save; + return 0; + } + + if(len > 9 && /* GS lcd event. by T.Nogami*/ + val[0] == 0x41 && /* Roland ID */ + val[1] == 0x10 && /* Device ID */ + val[2] == 0x45 && + val[3] == 0x12 && + val[4] == 0x10 && + val[5] == 0x01 && + val[6] == 0x00) + { + /* Text Insert for SC */ + uint8 save; + + len -= 2; + save = val[len]; + val[len] = '\0'; + if(readmidi_make_lcd_event(ME_GSLCD, (uint8 *)val + 7, ev)) + { + val[len] = save; + return 1; + } + val[len] = save; + return 0; + } + + /* val[1] can have values other than 0x10 for the XG ON event, which + * work on real XG hardware. I have several midi that use 0x1f instead + * of 0x10. playmidi.h lists 0x10 - 0x13 as MU50/80/90/100. I don't + * know what real world Device Number 0x1f would correspond to, but the + * XG spec says the entire 0x1n range is valid, and 0x1f works on real + * hardware, so I have modified the check below to accept the entire + * 0x1n range. + * + * I think there are/were some hacks somewhere in playmidi.c (?) to work + * around non- 0x10 values, but this fixes the root of the problem, which + * allows the server mode to handle XG initialization properly as well. + */ + if(len >= 8 && + val[0] == 0x43 && + (val[1] >= 0x10 && val[1] <= 0x1f) && + val[2] == 0x4C) + { + int addr = (val[3] << 16) | (val[4] << 8) | val[5]; + + if (addr == 0x00007E) /* XG SYSTEM ON */ + { + SETMIDIEVENT(*ev, 0, ME_RESET, 0, XG_SYSTEM_MODE, SYSEX_TAG); + return 1; + } + else if (addr == 0x000000 && len >= 12) /* XG Master Tune */ + { + uint16 tune = ((val[7] & 0xF) << 8) | ((val[8] & 0xF) << 4) | (val[9] & 0xF); + + if (tune > 0x7FF) + tune = 0x7FF; + SETMIDIEVENT(*ev, 0, ME_MASTER_TUNING, 0, tune & 0xFF, (tune >> 8) & 0x7F); + return 1; + } + } + + if (len >= 7 && val[0] == 0x7F && val[1] == 0x7F) + { + if (val[2] == 0x04 && val[3] == 0x03) /* GM2 Master Fine Tune */ + { + uint16 tune = (val[4] & 0x7F) | (val[5] << 7) | 0x4000; + + SETMIDIEVENT(*ev, 0, ME_MASTER_TUNING, 0, tune & 0xFF, (tune >> 8) & 0x7F); + return 1; + } + if (val[2] == 0x04 && val[3] == 0x04) /* GM2 Master Coarse Tune */ + { + uint8 tune = val[5]; + + if (tune < 0x28) + tune = 0x28; + else if (tune > 0x58) + tune = 0x58; + SETMIDIEVENT(*ev, 0, ME_MASTER_TUNING, 0, tune, 0x80); + return 1; + } + } + + /* Non-RealTime / RealTime Universal SysEx messages + * 0 0x7e(Non-RealTime) / 0x7f(RealTime) + * 1 SysEx device ID. Could be from 0x00 to 0x7f. + * 0x7f means disregard device. + * 2 Sub ID + * ... + * E 0xf7 + */ + if (len > 4 && val[0] >= 0x7e) + switch (val[2]) { + case 0x01: /* Sample Dump header */ + case 0x02: /* Sample Dump packet */ + case 0x03: /* Dump Request */ + break; + case 0x04: /* MIDI Time Code Setup/Device Control */ + switch (val[3]) { + case 0x01: /* Master Volume */ + vol = gm_convert_master_vol(val[4], val[5]); + if (val[1] == 0x7f) { + SETMIDIEVENT(*ev, 0, ME_MASTER_VOLUME, 0, + vol & 0xff, vol >> 8 & 0xff); + } else { + SETMIDIEVENT(*ev, 0, ME_MAINVOLUME, + MERGE_CHANNEL_PORT(val[1]), + vol >> 8 & 0xff, 0); + } + return 1; + } + break; + case 0x05: /* Sample Dump extensions */ + case 0x06: /* Inquiry Message */ + case 0x07: /* File Dump */ + break; + case 0x08: /* MIDI Tuning Standard */ + switch (val[3]) { + case 0x0a: + SETMIDIEVENT(*ev, 0, ME_TEMPER_KEYSIG, 0, + val[4] - 0x40 + val[5] * 16, (val[0] == 0x7f)); + return 1; + } + break; + case 0x09: /* General MIDI Message */ + /* GM System Enable/Disable */ + if(val[3] == 1) { + ctl->cmsg(CMSG_INFO, VERB_DEBUG, "SysEx: GM System On"); + SETMIDIEVENT(*ev, 0, ME_RESET, 0, GM_SYSTEM_MODE, 0); + } else if(val[3] == 3) { + ctl->cmsg(CMSG_INFO, VERB_DEBUG, "SysEx: GM2 System On"); + SETMIDIEVENT(*ev, 0, ME_RESET, 0, GM2_SYSTEM_MODE, 0); + } else { + ctl->cmsg(CMSG_INFO, VERB_DEBUG, "SysEx: GM System Off"); + SETMIDIEVENT(*ev, 0, ME_RESET, 0, DEFAULT_SYSTEM_MODE, 0); + } + return 1; + case 0x7b: /* End of File */ + case 0x7c: /* Handshaking Message: Wait */ + case 0x7d: /* Handshaking Message: Cancel */ + case 0x7e: /* Handshaking Message: NAK */ + case 0x7f: /* Handshaking Message: ACK */ + break; + } + + return 0; +} + +static int read_sysex_event(int32 at, int me, int32 len, + struct timidity_file *tf) +{ + uint8 *val; + MidiEvent ev, evm[260]; /* maximum number of XG bulk dump events */ + int ne, i; + + if(len == 0) + return 0; + if(me != 0xF0) + { + skip(tf, len); + return 0; + } + + val = (uint8 *)new_segment(&tmpbuffer, len); + if(tf_read(val, 1, len, tf) != len) + { + reuse_mblock(&tmpbuffer); + return -1; + } + if(parse_sysex_event(val, len, &ev)) + { + ev.time = at; + readmidi_add_event(&ev); + } + if ((ne = parse_sysex_event_multi(val, len, evm))) + { + for (i = 0; i < ne; i++) { + evm[i].time = at; + readmidi_add_event(&evm[i]); + } + } + + reuse_mblock(&tmpbuffer); + + return 0; +} + +static char *fix_string(char *s) +{ + int i, j, w; + char c; + + if(s == NULL) + return NULL; + while(*s == ' ' || *s == '\t' || *s == '\r' || *s == '\n') + s++; + + /* s =~ tr/ \t\r\n/ /s; */ + w = 0; + for(i = j = 0; (c = s[i]) != '\0'; i++) + { + if(c == '\t' || c == '\r' || c == '\n') + c = ' '; + if(w) + w = (c == ' '); + if(!w) + { + s[j++] = c; + w = (c == ' '); + } + } + + /* s =~ s/ $//; */ + if(j > 0 && s[j - 1] == ' ') + j--; + + s[j] = '\0'; + return s; +} + +static void smf_time_signature(int32 at, struct timidity_file *tf, int len) +{ + int n, d, c, b; + + /* Time Signature (nn dd cc bb) + * [0]: numerator + * [1]: denominator + * [2]: number of MIDI clocks in a metronome click + * [3]: number of notated 32nd-notes in a MIDI + * quarter-note (24 MIDI Clocks). + */ + + if(len != 4) + { + ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, "Invalid time signature"); + skip(tf, len); + return; + } + + n = tf_getc(tf); + d = (1<<tf_getc(tf)); + c = tf_getc(tf); + b = tf_getc(tf); + + if(n == 0 || d == 0) + { + ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, "Invalid time signature"); + return; + } + + MIDIEVENT(at, ME_TIMESIG, 0, n, d); + MIDIEVENT(at, ME_TIMESIG, 1, c, b); + ctl->cmsg(CMSG_INFO, VERB_NOISY, + "Time signature: %d/%d %d clock %d q.n.", n, d, c, b); + if(current_file_info->time_sig_n == -1) + { + current_file_info->time_sig_n = n; + current_file_info->time_sig_d = d; + current_file_info->time_sig_c = c; + current_file_info->time_sig_b = b; + } +} + +static void smf_key_signature(int32 at, struct timidity_file *tf, int len) +{ + int8 sf, mi; + /* Key Signature (sf mi) + * sf = -7: 7 flats + * sf = -1: 1 flat + * sf = 0: key of C + * sf = 1: 1 sharp + * sf = 7: 7 sharps + * mi = 0: major key + * mi = 1: minor key + */ + + if (len != 2) { + ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, "Invalid key signature"); + skip(tf, len); + return; + } + sf = tf_getc(tf); + mi = tf_getc(tf); + if (sf < -7 || sf > 7) { + ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, "Invalid key signature"); + return; + } + if (mi != 0 && mi != 1) { + ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, "Invalid key signature"); + return; + } + MIDIEVENT(at, ME_KEYSIG, 0, sf, mi); + ctl->cmsg(CMSG_INFO, VERB_NOISY, + "Key signature: %d %s %s", abs(sf), + (sf < 0) ? "flat(s)" : "sharp(s)", (mi) ? "minor" : "major"); +} + +/* Used for WRD reader */ +int dump_current_timesig(MidiEvent *codes, int maxlen) +{ + int i, n; + MidiEventList *e; + + if(maxlen <= 0 || evlist == NULL) + return 0; + n = 0; + for(i = 0, e = evlist; i < event_count; i++, e = e->next) + if(e->event.type == ME_TIMESIG && e->event.channel == 0) + { + if(n == 0 && e->event.time > 0) + { + /* 4/4 is default */ + SETMIDIEVENT(codes[0], 0, ME_TIMESIG, 0, 4, 4); + n++; + if(maxlen == 1) + return 1; + } + + if(n > 0) + { + if(e->event.a == codes[n - 1].a && + e->event.b == codes[n - 1].b) + continue; /* Unchanged */ + if(e->event.time == codes[n - 1].time) + n--; /* overwrite previous code */ + } + codes[n++] = e->event; + if(n == maxlen) + return n; + } + return n; +} + +/* Read a SMF track */ +static int read_smf_track(struct timidity_file *tf, int trackno, int rewindp) +{ + int32 len, next_pos, pos; + char tmp[4]; + int lastchan, laststatus; + int me, type, a, b, c; + int i; + int32 smf_at_time; + int note_seen = (! opt_preserve_silence); + + smf_at_time = readmidi_set_track(trackno, rewindp); + + /* Check the formalities */ + if((tf_read(tmp, 1, 4, tf) != 4) || (tf_read(&len, 4, 1, tf) != 1)) + { + ctl->cmsg(CMSG_ERROR, VERB_NORMAL, + "%s: Can't read track header.", current_filename); + return -1; + } + len = BE_LONG(len); + next_pos = tf_tell(tf) + len; + if(strncmp(tmp, "MTrk", 4)) + { + ctl->cmsg(CMSG_ERROR, VERB_NORMAL, + "%s: Corrupt MIDI file.", current_filename); + return -2; + } + + lastchan = laststatus = 0; + + for(;;) + { + if(readmidi_error_flag) + return -1; + if((len = getvl(tf)) < 0) + return -1; + smf_at_time += len; + errno = 0; + if((i = tf_getc(tf)) == EOF) + { + if(errno) + ctl->cmsg(CMSG_ERROR, VERB_NORMAL, + "%s: read_midi_event: %s", + current_filename, strerror(errno)); + else + ctl->cmsg(CMSG_ERROR, VERB_NORMAL, + "Warning: %s: Too shorten midi file.", + current_filename); + return -1; + } + + me = (uint8)i; + if(me == 0xF0 || me == 0xF7) /* SysEx event */ + { + if((len = getvl(tf)) < 0) + return -1; + if((i = read_sysex_event(smf_at_time, me, len, tf)) != 0) + return i; + } + else if(me == 0xFF) /* Meta event */ + { + type = tf_getc(tf); + if((len = getvl(tf)) < 0) + return -1; + if(type > 0 && type < 16) + { + static char *label[] = + { + "Text event: ", "Text: ", "Copyright: ", "Track name: ", + "Instrument: ", "Lyric: ", "Marker: ", "Cue point: " + }; + + if(type == 5 || /* Lyric */ + (type == 1 && (opt_trace_text_meta_event || + karaoke_format == 2 || + chorus_status_gs.text.status == CHORUS_ST_OK)) || + (type == 6 && (current_file_info->format == 0 || + (current_file_info->format == 1 && + current_read_track == 0)))) + { + char *str, *text; + MidiEvent ev; + + str = (char *)new_segment(&tmpbuffer, len + 3); + if(type != 6) + { + i = tf_read(str, 1, len, tf); + str[len] = '\0'; + } + else + { + i = tf_read(str + 1, 1, len, tf); + str[0] = MARKER_START_CHAR; + str[len + 1] = MARKER_END_CHAR; + str[len + 2] = '\0'; + } + + if(i != len) + { + ctl->cmsg(CMSG_ERROR, VERB_NORMAL, + "Warning: %s: Too shorten midi file.", + current_filename); + reuse_mblock(&tmpbuffer); + return -1; + } + + if((text = readmidi_make_string_event(1, str, &ev, 1)) + == NULL) + { + reuse_mblock(&tmpbuffer); + continue; + } + ev.time = smf_at_time; + + if(type == 6) + { + if(strlen(fix_string(text + 1)) == 2) + { + reuse_mblock(&tmpbuffer); + continue; /* Empty Marker */ + } + } + + switch(type) + { + case 1: + if(karaoke_format == 2) + { + *text = ME_KARAOKE_LYRIC; + if(karaoke_title_flag == 0 && + strncmp(str, "@T", 2) == 0) + current_file_info->karaoke_title = + add_karaoke_title(current_file_info-> + karaoke_title, str + 2); + ev.type = ME_KARAOKE_LYRIC; + readmidi_add_event(&ev); + continue; + } + if(chorus_status_gs.text.status == CHORUS_ST_OK) + { + *text = ME_CHORUS_TEXT; + ev.type = ME_CHORUS_TEXT; + readmidi_add_event(&ev); + continue; + } + *text = ME_TEXT; + ev.type = ME_TEXT; + readmidi_add_event(&ev); + continue; + case 5: + *text = ME_LYRIC; + ev.type = ME_LYRIC; + readmidi_add_event(&ev); + continue; + case 6: + *text = ME_MARKER; + ev.type = ME_MARKER; + readmidi_add_event(&ev); + continue; + } + } + + if(type == 3 && /* Sequence or Track Name */ + (current_file_info->format == 0 || + (current_file_info->format == 1 && + current_read_track == 0))) + { + if(current_file_info->seq_name == NULL) { + char *name = dumpstring(3, len, "Sequence: ", 1, tf); + current_file_info->seq_name = safe_strdup(fix_string(name)); + free(name); + } + else + dumpstring(3, len, "Sequence: ", 0, tf); + } + else if(type == 1 && + current_file_info->first_text == NULL && + (current_file_info->format == 0 || + (current_file_info->format == 1 && + current_read_track == 0))) { + char *name = dumpstring(1, len, "Text: ", 1, tf); + current_file_info->first_text = safe_strdup(fix_string(name)); + free(name); + } + else + dumpstring(type, len, label[(type>7) ? 0 : type], 0, tf); + } + else + { + switch(type) + { + case 0x00: + if(len == 2) + { + a = tf_getc(tf); + b = tf_getc(tf); + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(Sequence Number %02x %02x)", a, b); + } + else + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(Sequence Number len=%d)", len); + break; + + case 0x2F: /* End of Track */ + pos = tf_tell(tf); + if(pos < next_pos) + tf_seek(tf, next_pos - pos, SEEK_CUR); + return 0; + + case 0x51: /* Tempo */ + a = tf_getc(tf); + b = tf_getc(tf); + c = tf_getc(tf); + MIDIEVENT(smf_at_time, ME_TEMPO, c, a, b); + break; + + case 0x54: + /* SMPTE Offset (hr mn se fr ff) + * hr: hours&type + * 0 1 2 3 4 5 6 7 bits + * 0 |<--type -->|<---- hours [0..23]---->| + * type: 00: 24 frames/second + * 01: 25 frames/second + * 10: 30 frames/second (drop frame) + * 11: 30 frames/second (non-drop frame) + * mn: minis [0..59] + * se: seconds [0..59] + * fr: frames [0..29] + * ff: fractional frames [0..99] + */ + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(SMPTE Offset meta event)"); + skip(tf, len); + break; + + case 0x58: /* Time Signature */ + smf_time_signature(smf_at_time, tf, len); + break; + + case 0x59: /* Key Signature */ + smf_key_signature(smf_at_time, tf, len); + break; + + case 0x7f: /* Sequencer-Specific Meta-Event */ + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(Sequencer-Specific meta event, length %ld)", + len); + skip(tf, len); + break; + + case 0x20: /* MIDI channel prefix (SMF v1.0) */ + if(len == 1) + { + int midi_channel_prefix = tf_getc(tf); + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(MIDI channel prefix %d)", + midi_channel_prefix); + } + else + skip(tf, len); + break; + + case 0x21: /* MIDI port number */ + if(len == 1) + { + if((midi_port_number = tf_getc(tf)) + == EOF) + { + ctl->cmsg(CMSG_ERROR, VERB_NORMAL, + "Warning: %s: Too shorten midi file.", + current_filename); + return -1; + } + midi_port_number &= 0xF; + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(MIDI port number %d)", midi_port_number); + } + else + skip(tf, len); + break; + + default: + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(Meta event type 0x%02x, length %ld)", + type, len); + skip(tf, len); + break; + } + } + } + else /* MIDI event */ + { + a = me; + if(a & 0x80) /* status byte */ + { + lastchan = MERGE_CHANNEL_PORT(a & 0x0F); + laststatus = (a >> 4) & 0x07; + if(laststatus != 7) + a = tf_getc(tf) & 0x7F; + } + switch(laststatus) + { + case 0: /* Note off */ + b = tf_getc(tf) & 0x7F; + MIDIEVENT(smf_at_time, ME_NOTEOFF, lastchan, a,b); + break; + + case 1: /* Note on */ + b = tf_getc(tf) & 0x7F; + if(b) + { + if (! note_seen && smf_at_time > 0) + { + MIDIEVENT(0, ME_NOTEON, lastchan, a, 0); + MIDIEVENT(0, ME_NOTEOFF, lastchan, a, 0); + note_seen = 1; + } + MIDIEVENT(smf_at_time, ME_NOTEON, lastchan, a,b); + } + else /* b == 0 means Note Off */ + { + MIDIEVENT(smf_at_time, ME_NOTEOFF, lastchan, a, 0); + } + break; + + case 2: /* Key Pressure */ + b = tf_getc(tf) & 0x7F; + MIDIEVENT(smf_at_time, ME_KEYPRESSURE, lastchan, a, b); + break; + + case 3: /* Control change */ + b = tf_getc(tf); + readmidi_add_ctl_event(smf_at_time, lastchan, a, b); + break; + + case 4: /* Program change */ + MIDIEVENT(smf_at_time, ME_PROGRAM, lastchan, a, 0); + break; + + case 5: /* Channel pressure */ + MIDIEVENT(smf_at_time, ME_CHANNEL_PRESSURE, lastchan, a, 0); + break; + + case 6: /* Pitch wheel */ + b = tf_getc(tf) & 0x7F; + MIDIEVENT(smf_at_time, ME_PITCHWHEEL, lastchan, a, b); + break; + + default: /* case 7: */ + /* Ignore this event */ + switch(lastchan & 0xF) + { + case 2: /* Sys Com Song Position Pntr */ + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(Sys Com Song Position Pntr)"); + tf_getc(tf); + tf_getc(tf); + break; + + case 3: /* Sys Com Song Select(Song #) */ + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(Sys Com Song Select(Song #))"); + tf_getc(tf); + break; + + case 6: /* Sys Com tune request */ + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(Sys Com tune request)"); + break; + case 8: /* Sys real time timing clock */ + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(Sys real time timing clock)"); + break; + case 10: /* Sys real time start */ + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(Sys real time start)"); + break; + case 11: /* Sys real time continue */ + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(Sys real time continue)"); + break; + case 12: /* Sys real time stop */ + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(Sys real time stop)"); + break; + case 14: /* Sys real time active sensing */ + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(Sys real time active sensing)"); + break; +#if 0 + case 15: /* Meta */ + case 0: /* SysEx */ + case 7: /* SysEx */ +#endif + default: /* 1, 4, 5, 9, 13 */ + ctl->cmsg(CMSG_ERROR, VERB_NORMAL, + "*** Can't happen: status 0x%02X channel 0x%02X", + laststatus, lastchan & 0xF); + break; + } + } + } + } + /*NOTREACHED*/ +} + +/* Free the linked event list from memory. */ +static void free_midi_list(void) +{ + if(evlist != NULL) + { + reuse_mblock(&mempool); + evlist = NULL; + } +} + +static void move_channels(int *chidx) +{ + int i, ch, maxch, newch; + MidiEventList *e; + + for (i = 0; i < 256; i++) + chidx[i] = -1; + /* check channels */ + for (i = maxch = 0, e = evlist; i < event_count; i++, e = e->next) + if (! GLOBAL_CHANNEL_EVENT_TYPE(e->event.type)) { + if ((ch = e->event.channel) < REDUCE_CHANNELS) + chidx[ch] = ch; + if (maxch < ch) + maxch = ch; + } + if (maxch >= REDUCE_CHANNELS) + /* Move channel if enable */ + for (i = maxch = 0, e = evlist; i < event_count; i++, e = e->next) + if (! GLOBAL_CHANNEL_EVENT_TYPE(e->event.type)) { + if (chidx[ch = e->event.channel] != -1) + ch = e->event.channel = chidx[ch]; + else { /* -1 */ + if (ch >= MAX_CHANNELS) { + newch = ch % REDUCE_CHANNELS; + while (newch < ch && newch < MAX_CHANNELS) { + if (chidx[newch] == -1) { + ctl->cmsg(CMSG_INFO, VERB_VERBOSE, + "channel %d => %d", ch, newch); + ch = e->event.channel = chidx[ch] = newch; + break; + } + newch += REDUCE_CHANNELS; + } + } + if (chidx[ch] == -1) { + if (ch < MAX_CHANNELS) + chidx[ch] = ch; + else { + newch = ch % MAX_CHANNELS; + ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, + "channel %d => %d (mixed)", ch, newch); + ch = e->event.channel = chidx[ch] = newch; + } + } + } + if (maxch < ch) + maxch = ch; + } + for (i = 0, e = evlist; i < event_count; i++, e = e->next) + if (e->event.type == ME_SYSEX_GS_LSB) { + if (e->event.b == 0x45 || e->event.b == 0x46) + if (maxch < e->event.channel) + maxch = e->event.channel; + } else if (e->event.type == ME_SYSEX_XG_LSB) { + if (e->event.b == 0x99) + if (maxch < e->event.channel) + maxch = e->event.channel; + } + current_file_info->max_channel = maxch; +} + +void change_system_mode(int mode) +{ + int mid; + + if(opt_system_mid) + { + mid = opt_system_mid; + mode = -1; /* Always use opt_system_mid */ + } + else + mid = current_file_info->mid; + pan_table = sc_pan_table; + switch(mode) + { + case GM_SYSTEM_MODE: + if(play_system_mode == DEFAULT_SYSTEM_MODE) + { + play_system_mode = GM_SYSTEM_MODE; + vol_table = def_vol_table; + } + break; + case GM2_SYSTEM_MODE: + play_system_mode = GM2_SYSTEM_MODE; + vol_table = def_vol_table; + pan_table = gm2_pan_table; + break; + case GS_SYSTEM_MODE: + play_system_mode = GS_SYSTEM_MODE; + vol_table = gs_vol_table; + break; + case XG_SYSTEM_MODE: + if (play_system_mode != XG_SYSTEM_MODE) {init_all_effect_xg();} + play_system_mode = XG_SYSTEM_MODE; + vol_table = xg_vol_table; + break; + default: + /* --module option */ + if (is_gs_module()) { + play_system_mode = GS_SYSTEM_MODE; + break; + } else if (is_xg_module()) { + if (play_system_mode != XG_SYSTEM_MODE) {init_all_effect_xg();} + play_system_mode = XG_SYSTEM_MODE; + break; + } + switch(mid) + { + case 0x41: + play_system_mode = GS_SYSTEM_MODE; + vol_table = gs_vol_table; + break; + case 0x43: + if (play_system_mode != XG_SYSTEM_MODE) {init_all_effect_xg();} + play_system_mode = XG_SYSTEM_MODE; + vol_table = xg_vol_table; + break; + case 0x7e: + play_system_mode = GM_SYSTEM_MODE; + vol_table = def_vol_table; + break; + default: + play_system_mode = DEFAULT_SYSTEM_MODE; + vol_table = def_vol_table; + break; + } + break; + } +} + +int get_default_mapID(int ch) +{ + if(play_system_mode == XG_SYSTEM_MODE) + return ISDRUMCHANNEL(ch) ? XG_DRUM_MAP : XG_NORMAL_MAP; + return INST_NO_MAP; +} + +/* 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) +{ + MidiEvent *groomed_list, *lp; + MidiEventList *meep; + int32 i, j, our_event_count, tempo, skip_this_event; + int32 sample_cum, samples_to_do, at, st, dt, counting_time; + int ch, gch; + uint8 current_set[MAX_CHANNELS], + warn_tonebank[128 + MAP_BANK_COUNT], warn_drumset[128 + MAP_BANK_COUNT]; + int8 bank_lsb[MAX_CHANNELS], bank_msb[MAX_CHANNELS], mapID[MAX_CHANNELS]; + int current_program[MAX_CHANNELS]; + int wrd_args[WRD_MAXPARAM]; + int wrd_argc; + int chidx[256]; + int newbank, newprog; + + move_channels(chidx); + + COPY_CHANNELMASK(drumchannels, current_file_info->drumchannels); + COPY_CHANNELMASK(drumchannel_mask, current_file_info->drumchannel_mask); + + /* Move drumchannels */ + for(ch = REDUCE_CHANNELS; ch < MAX_CHANNELS; ch++) + { + i = chidx[ch]; + if(i != -1 && i != ch && !IS_SET_CHANNELMASK(drumchannel_mask, i)) + { + if(IS_SET_CHANNELMASK(drumchannels, ch)) + SET_CHANNELMASK(drumchannels, i); + else + UNSET_CHANNELMASK(drumchannels, i); + } + } + + memset(warn_tonebank, 0, sizeof(warn_tonebank)); + if (special_tonebank >= 0) + newbank = special_tonebank; + else + newbank = default_tonebank; + for(j = 0; j < MAX_CHANNELS; j++) + { + if(ISDRUMCHANNEL(j)) + current_set[j] = 0; + else + { + if (tonebank[newbank] == NULL) + { + if (warn_tonebank[newbank] == 0) + { + ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, + "Tone bank %d is undefined", newbank); + warn_tonebank[newbank] = 1; + } + newbank = 0; + } + current_set[j] = newbank; + } + bank_lsb[j] = bank_msb[j] = 0; + if(play_system_mode == XG_SYSTEM_MODE && j % 16 == 9) + bank_msb[j] = 127; /* Use MSB=127 for XG */ + current_program[j] = default_program[j]; + } + + memset(warn_drumset, 0, sizeof(warn_drumset)); + tempo = 500000; + compute_sample_increment(tempo, divisions); + + /* This may allocate a bit more than we need */ + groomed_list = lp = + (MidiEvent *)safe_malloc(sizeof(MidiEvent) * (event_count + 1)); + meep = evlist; + + our_event_count = 0; + st = at = sample_cum = 0; + counting_time = 2; /* We strip any silence before the first NOTE ON. */ + wrd_argc = 0; + change_system_mode(DEFAULT_SYSTEM_MODE); + + for(j = 0; j < MAX_CHANNELS; j++) + mapID[j] = get_default_mapID(j); + + for(i = 0; i < event_count; i++) + { + skip_this_event = 0; + ch = meep->event.channel; + gch = GLOBAL_CHANNEL_EVENT_TYPE(meep->event.type); + if(!gch && ch >= MAX_CHANNELS) /* For safety */ + meep->event.channel = ch = ch % MAX_CHANNELS; + + if(!gch && IS_SET_CHANNELMASK(quietchannels, ch)) + skip_this_event = 1; + else switch(meep->event.type) + { + case ME_NONE: + skip_this_event = 1; + break; + case ME_RESET: + change_system_mode(meep->event.a); + ctl->cmsg(CMSG_INFO, VERB_NOISY, "MIDI reset at %d sec", + (int)((double)st / play_mode->rate + 0.5)); + for(j = 0; j < MAX_CHANNELS; j++) + { + if(play_system_mode == XG_SYSTEM_MODE && j % 16 == 9) + mapID[j] = XG_DRUM_MAP; + else + mapID[j] = get_default_mapID(j); + if(ISDRUMCHANNEL(j)) + current_set[j] = 0; + else + { + if(special_tonebank >= 0) + current_set[j] = special_tonebank; + else + current_set[j] = default_tonebank; + if(tonebank[current_set[j]] == NULL) + current_set[j] = 0; + } + bank_lsb[j] = bank_msb[j] = 0; + if(play_system_mode == XG_SYSTEM_MODE && j % 16 == 9) + bank_msb[j] = 127; /* Use MSB=127 for XG */ + current_program[j] = default_program[j]; + } + break; + + case ME_PROGRAM: + if (ISDRUMCHANNEL(ch)) + newbank = current_program[ch]; + else + newbank = current_set[ch]; + newprog = meep->event.a; + switch (play_system_mode) { + case GS_SYSTEM_MODE: /* GS */ + switch (bank_lsb[ch]) { + case 0: /* No change */ + break; + case 1: + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(GS ch=%d SC-55 MAP)", ch); + mapID[ch] = (ISDRUMCHANNEL(ch)) ? SC_55_DRUM_MAP + : SC_55_TONE_MAP; + break; + case 2: + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(GS ch=%d SC-88 MAP)", ch); + mapID[ch] = (ISDRUMCHANNEL(ch)) ? SC_88_DRUM_MAP + : SC_88_TONE_MAP; + break; + case 3: + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(GS ch=%d SC-88Pro MAP)", ch); + mapID[ch] = (ISDRUMCHANNEL(ch)) ? SC_88PRO_DRUM_MAP + : SC_88PRO_TONE_MAP; + break; + case 4: + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(GS ch=%d SC-8820/SC-8850 MAP)", ch); + mapID[ch] = (ISDRUMCHANNEL(ch)) ? SC_8850_DRUM_MAP + : SC_8850_TONE_MAP; + break; + default: + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(GS: ch=%d Strange bank LSB %d)", + ch, bank_lsb[ch]); + break; + } + newbank = bank_msb[ch]; + break; + case XG_SYSTEM_MODE: /* XG */ + switch (bank_msb[ch]) { + case 0: /* Normal */ + if (ch == 9 && bank_lsb[ch] == 127 + && mapID[ch] == XG_DRUM_MAP) + /* FIXME: Why this part is drum? Is this correct? */ + ctl->cmsg(CMSG_WARNING, VERB_NORMAL, + "Warning: XG bank 0/127 is found. " + "It may be not correctly played."); + else { + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(XG ch=%d Normal voice)", ch); + midi_drumpart_change(ch, 0); + mapID[ch] = XG_NORMAL_MAP; + } + break; + case 64: /* SFX voice */ + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(XG ch=%d SFX voice)", ch); + midi_drumpart_change(ch, 0); + mapID[ch] = XG_SFX64_MAP; + break; + case 126: /* SFX kit */ + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(XG ch=%d SFX kit)", ch); + midi_drumpart_change(ch, 1); + mapID[ch] = XG_SFX126_MAP; + break; + case 127: /* Drum kit */ + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(XG ch=%d Drum kit)", ch); + midi_drumpart_change(ch, 1); + mapID[ch] = XG_DRUM_MAP; + break; + default: + ctl->cmsg(CMSG_INFO, VERB_DEBUG, + "(XG: ch=%d Strange bank MSB %d)", + ch, bank_msb[ch]); + break; + } + newbank = bank_lsb[ch]; + break; + case GM2_SYSTEM_MODE: /* GM2 */ + ctl->cmsg(CMSG_INFO, VERB_DEBUG, "(GM2 ch=%d)", ch); + if ((bank_msb[ch] & 0xfe) == 0x78) /* 0x78/0x79 */ + midi_drumpart_change(ch, bank_msb[ch] == 0x78); + mapID[ch] = (ISDRUMCHANNEL(ch)) ? GM2_DRUM_MAP + : GM2_TONE_MAP; + newbank = bank_lsb[ch]; + break; + default: + newbank = bank_msb[ch]; + break; + } + if (ISDRUMCHANNEL(ch)) + current_set[ch] = newprog; + else { + if (special_tonebank >= 0) + newbank = special_tonebank; + if (current_program[ch] == SPECIAL_PROGRAM) + skip_this_event = 1; + current_set[ch] = newbank; + } + current_program[ch] = newprog; + break; + + case ME_NOTEON: + if(counting_time) + counting_time = 1; + if(ISDRUMCHANNEL(ch)) + { + newbank = current_set[ch]; + newprog = meep->event.a; + instrument_map(mapID[ch], &newbank, &newprog); + + if(!drumset[newbank]) /* Is this a defined drumset? */ + { + if(warn_drumset[newbank] == 0) + { + ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, + "Drum set %d is undefined", newbank); + warn_drumset[newbank] = 1; + } + newbank = 0; + } + + /* Mark this instrument to be loaded */ + if(!(drumset[newbank]->tone[newprog].instrument)) + drumset[newbank]->tone[newprog].instrument = + MAGIC_LOAD_INSTRUMENT; + } + else + { + if(current_program[ch] == SPECIAL_PROGRAM) + break; + newbank = current_set[ch]; + newprog = current_program[ch]; + instrument_map(mapID[ch], &newbank, &newprog); + if(tonebank[newbank] == NULL) + { + if(warn_tonebank[newbank] == 0) + { + ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, + "Tone bank %d is undefined", newbank); + warn_tonebank[newbank] = 1; + } + newbank = 0; + } + + /* Mark this instrument to be loaded */ + if(!(tonebank[newbank]->tone[newprog].instrument)) + tonebank[newbank]->tone[newprog].instrument = + MAGIC_LOAD_INSTRUMENT; + } + break; + + case ME_TONE_BANK_MSB: + bank_msb[ch] = meep->event.a; + break; + + case ME_TONE_BANK_LSB: + bank_lsb[ch] = meep->event.a; + break; + + case ME_CHORUS_TEXT: + case ME_LYRIC: + case ME_MARKER: + case ME_INSERT_TEXT: + case ME_TEXT: + case ME_KARAOKE_LYRIC: + if((meep->event.a | meep->event.b) == 0) + skip_this_event = 1; + else if(counting_time && ctl->trace_playing) + counting_time = 1; + break; + + case ME_GSLCD: + if (counting_time && ctl->trace_playing) + counting_time = 1; + skip_this_event = !ctl->trace_playing; + break; + + case ME_DRUMPART: + midi_drumpart_change(ch, meep->event.a); + break; + + case ME_WRD: + if(readmidi_wrd_mode == WRD_TRACE_MIMPI) + { + wrd_args[wrd_argc++] = meep->event.a | 256 * meep->event.b; + if(ch != WRD_ARG) + { + if(ch == WRD_MAG) { + wrdt->apply(WRD_MAGPRELOAD, wrd_argc, wrd_args); + } + else if(ch == WRD_PLOAD) + wrdt->apply(WRD_PHOPRELOAD, wrd_argc, wrd_args); + else if(ch == WRD_PATH) + wrdt->apply(WRD_PATH, wrd_argc, wrd_args); + wrd_argc = 0; + } + } + if(counting_time == 2 && readmidi_wrd_mode != WRD_TRACE_NOTHING) + counting_time = 1; + break; + + case ME_SHERRY: + if(counting_time == 2) + counting_time = 1; + break; + + case ME_NOTE_STEP: + if(counting_time == 2) + skip_this_event = 1; + break; + } + + /* Recompute time in samples*/ + if((dt = meep->event.time - at) && !counting_time) + { + samples_to_do = sample_increment * dt; + sample_cum += sample_correction * dt; + if(sample_cum & 0xFFFF0000) + { + samples_to_do += ((sample_cum >> 16) & 0xFFFF); + sample_cum &= 0x0000FFFF; + } + st += samples_to_do; + if(st < 0) + { + ctl->cmsg(CMSG_ERROR, VERB_NORMAL, + "Overflow the sample counter"); + free(groomed_list); + return NULL; + } + } + else if(counting_time == 1) + counting_time = 0; + + if(meep->event.type == ME_TEMPO) + { + tempo = ch + meep->event.b * 256 + meep->event.a * 65536; + compute_sample_increment(tempo, divisions); + } + + if(!skip_this_event) + { + /* Add the event to the list */ + *lp = meep->event; + lp->time = st; + lp++; + our_event_count++; + } + at = meep->event.time; + meep = meep->next; + } + /* Add an End-of-Track event */ + lp->time = st; + lp->type = ME_EOT; + our_event_count++; + free_midi_list(); + + *eventsp = our_event_count; + *samplesp = st; + return groomed_list; +} + +static int read_smf_file(struct timidity_file *tf) +{ + int32 len, divisions; + int16 format, tracks, divisions_tmp; + int i; + + if(current_file_info->file_type == IS_OTHER_FILE) + current_file_info->file_type = IS_SMF_FILE; + + if(current_file_info->karaoke_title == NULL) + karaoke_title_flag = 0; + else + karaoke_title_flag = 1; + + errno = 0; + if(tf_read(&len, 4, 1, tf) != 1) + { + if(errno) + ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s", current_filename, + strerror(errno)); + else + ctl->cmsg(CMSG_WARNING, VERB_NORMAL, + "%s: Not a MIDI file!", current_filename); + return 1; + } + len = BE_LONG(len); + + tf_read(&format, 2, 1, tf); + tf_read(&tracks, 2, 1, tf); + tf_read(&divisions_tmp, 2, 1, tf); + format = BE_SHORT(format); + tracks = BE_SHORT(tracks); + divisions_tmp = BE_SHORT(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); + } + else + divisions = (int32)divisions_tmp; + + if(play_mode->flag & PF_MIDI_EVENT) + play_mode->acntl(PM_REQ_DIVISIONS, &divisions); + + if(len > 6) + { + ctl->cmsg(CMSG_WARNING, VERB_NORMAL, + "%s: MIDI file header size %ld bytes", + current_filename, len); + skip(tf, len - 6); /* skip the excess */ + } + if(format < 0 || format > 2) + { + ctl->cmsg(CMSG_ERROR, VERB_NORMAL, + "%s: Unknown MIDI file format %d", current_filename, format); + return 1; + } + ctl->cmsg(CMSG_INFO, VERB_VERBOSE, "Format: %d Tracks: %d Divisions: %d", + format, tracks, divisions); + + current_file_info->format = format; + current_file_info->tracks = tracks; + current_file_info->divisions = divisions; + if(tf->url->url_tell != NULL) + current_file_info->hdrsiz = (int16)tf_tell(tf); + else + current_file_info->hdrsiz = -1; + + switch(format) + { + case 0: + if(read_smf_track(tf, 0, 1)) + { + if(ignore_midi_error) + break; + return 1; + } + break; + + case 1: + for(i = 0; i < tracks; i++) + { + if(read_smf_track(tf, i, 1)) + { + if(ignore_midi_error) + break; + return 1; + } + } + break; + + case 2: /* We simply play the tracks sequentially */ + for(i = 0; i < tracks; i++) + { + if(read_smf_track(tf, i, 0)) + { + if(ignore_midi_error) + break; + return 1; + } + } + break; + } + return 0; +} + +void readmidi_read_init(void) +{ + int i; + static int first = 1; + + /* initialize effect status */ + for (i = 0; i < MAX_CHANNELS; i++) + init_channel_layer(i); + free_effect_buffers(); + init_reverb_status_gs(); + init_delay_status_gs(); + init_chorus_status_gs(); + init_eq_status_gs(); + init_insertion_effect_gs(); + init_multi_eq_xg(); + if (play_system_mode == XG_SYSTEM_MODE) {init_all_effect_xg();} + init_userdrum(); + init_userinst(); + rhythm_part[0] = rhythm_part[1] = 9; + for(i = 0; i < 6; i++) {drum_setup_xg[i] = 9;} + + /* Put a do-nothing event first in the list for easier processing */ + evlist = current_midi_point = alloc_midi_event(); + evlist->event.time = 0; + evlist->event.type = ME_NONE; + evlist->event.channel = 0; + evlist->event.a = 0; + evlist->event.b = 0; + evlist->prev = NULL; + evlist->next = NULL; + readmidi_error_flag = 0; + event_count = 1; + + if(string_event_table != NULL) + { + free(string_event_table[0]); + free(string_event_table); + string_event_table = NULL; + string_event_table_size = 0; + } + if (first != 1) + if (string_event_strtab.nstring > 0) + delete_string_table(&string_event_strtab); + init_string_table(&string_event_strtab); + karaoke_format = 0; + + for(i = 0; i < 256; i++) + default_channel_program[i] = -1; + readmidi_wrd_mode = WRD_TRACE_NOTHING; + first = 0; +} + +static void insert_note_steps(void) +{ + MidiEventList *e; + int32 i, n, at, lasttime, meas, beat; + uint8 num = 0, denom = 1, a, b; + + e = evlist; + for (i = n = 0; i < event_count - 1 && n < 256 - 1; i++, e = e->next) + if (e->event.type == ME_TIMESIG && e->event.channel == 0) { + if (n == 0 && e->event.time > 0) { /* 4/4 is default */ + SETMIDIEVENT(timesig[n], 0, ME_TIMESIG, 0, 4, 4); + n++; + } + if (n > 0 && e->event.a == timesig[n - 1].a + && e->event.b == timesig[n - 1].b) + continue; /* unchanged */ + if (n > 0 && e->event.time == timesig[n - 1].time) + n--; /* overwrite previous timesig */ + timesig[n++] = e->event; + } + if (n == 0) { + SETMIDIEVENT(timesig[n], 0, ME_TIMESIG, 0, 4, 4); + n++; + } + timesig[n] = timesig[n - 1]; + timesig[n].time = 0x7fffffff; /* stopper */ + lasttime = e->event.time; + readmidi_set_track(0, 1); + at = n = meas = beat = 0; + while (at < lasttime && ! readmidi_error_flag) { + if (at >= timesig[n].time) { + if (beat != 0) + meas++, beat = 0; + num = timesig[n].a, denom = timesig[n].b, n++; + } + a = (meas + 1) & 0xff; + b = (((meas + 1) >> 8) & 0x0f) + ((beat + 1) << 4); + MIDIEVENT(at, ME_NOTE_STEP, 0, a, b); + if (++beat == num) + meas++, beat = 0; + at += current_file_info->divisions * 4 / denom; + } +} + +MidiEvent *read_midi_file(struct timidity_file *tf, int32 *count, int32 *sp, + char *fn) +{ + char magic[4]; + MidiEvent *ev; + int err, macbin_check, mtype, i; + + macbin_check = 1; + current_file_info = get_midi_file_info(current_filename, 1); + COPY_CHANNELMASK(drumchannels, current_file_info->drumchannels); + COPY_CHANNELMASK(drumchannel_mask, current_file_info->drumchannel_mask); + + errno = 0; + + if((mtype = get_module_type(fn)) > 0) + { + readmidi_read_init(); + if(!IS_URL_SEEK_SAFE(tf->url)) + tf->url = url_cache_open(tf->url, 1); + err = load_module_file(tf, mtype); + if(!err) + { + current_file_info->format = 0; + memset(&drumchannels, 0, sizeof(drumchannels)); + goto grooming; + } + free_midi_list(); + + if(err == 2) + return NULL; + url_rewind(tf->url); + url_cache_disable(tf->url); + } + +#if MAX_CHANNELS > 16 + for(i = 16; i < MAX_CHANNELS; i++) + { + if(!IS_SET_CHANNELMASK(drumchannel_mask, i)) + { + if(IS_SET_CHANNELMASK(drumchannels, i & 0xF)) + SET_CHANNELMASK(drumchannels, i); + else + UNSET_CHANNELMASK(drumchannels, i); + } + } +#endif + + if(opt_default_mid && + (current_file_info->mid == 0 || current_file_info->mid >= 0x7e)) + current_file_info->mid = opt_default_mid; + + retry_read: + if(tf_read(magic, 1, 4, tf) != 4) + { + if(errno) + ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s", current_filename, + strerror(errno)); + else + ctl->cmsg(CMSG_WARNING, VERB_NORMAL, + "%s: Not a MIDI file!", current_filename); + return NULL; + } + + if(memcmp(magic, "MThd", 4) == 0) + { + readmidi_read_init(); + err = read_smf_file(tf); + } + else if(memcmp(magic, "RCM-", 4) == 0 || memcmp(magic, "COME", 4) == 0) + { + readmidi_read_init(); + err = read_rcp_file(tf, magic, fn); + } + else if (strncmp(magic, "RIFF", 4) == 0) { + if (tf_read(magic, 1, 4, tf) == 4 && + tf_read(magic, 1, 4, tf) == 4 && + strncmp(magic, "RMID", 4) == 0 && + tf_read(magic, 1, 4, tf) == 4 && + strncmp(magic, "data", 4) == 0 && + tf_read(magic, 1, 4, tf) == 4) { + goto retry_read; + } else { + err = 1; + ctl->cmsg(CMSG_WARNING, VERB_NORMAL, + "%s: Not a MIDI file!", current_filename); + } + } + else if(memcmp(magic, "melo", 4) == 0) + { + readmidi_read_init(); + err = read_mfi_file(tf); + } + else + { + if(macbin_check && magic[0] == 0) + { + /* Mac Binary */ + macbin_check = 0; + skip(tf, 128 - 4); + goto retry_read; + } + else if(memcmp(magic, "RIFF", 4) == 0) + { + /* RIFF MIDI file */ + skip(tf, 20 - 4); + goto retry_read; + } + err = 1; + ctl->cmsg(CMSG_WARNING, VERB_NORMAL, + "%s: Not a MIDI file!", current_filename); + } + + if(err) + { + free_midi_list(); + if(string_event_strtab.nstring > 0) + delete_string_table(&string_event_strtab); + return NULL; + } + + /* Read WRD file */ + if(!(play_mode->flag&PF_CAN_TRACE)) + { + if(wrdt->start != NULL) + wrdt->start(WRD_TRACE_NOTHING); + readmidi_wrd_mode = WRD_TRACE_NOTHING; + } + else if(wrdt->id != '-' && wrdt->opened) + { + readmidi_wrd_mode = import_wrd_file(fn); + if(wrdt->start != NULL) + if(wrdt->start(readmidi_wrd_mode) == -1) + { + /* strip all WRD events */ + MidiEventList *e; + int32 i; + for(i = 0, e = evlist; i < event_count; i++, e = e->next) + if (e->event.type == ME_WRD || e->event.type == ME_SHERRY) + e->event.type = ME_NONE; + } + } + else + readmidi_wrd_mode = WRD_TRACE_NOTHING; + + /* make lyric table */ + if(string_event_strtab.nstring > 0) + { + string_event_table_size = string_event_strtab.nstring; + string_event_table = make_string_array(&string_event_strtab); + if(string_event_table == NULL) + { + delete_string_table(&string_event_strtab); + string_event_table_size = 0; + } + } + + grooming: + insert_note_steps(); + ev = groom_list(current_file_info->divisions, count, sp); + if(ev == NULL) + { + free_midi_list(); + if(string_event_strtab.nstring > 0) + delete_string_table(&string_event_strtab); + return NULL; + } + current_file_info->samples = *sp; + if(current_file_info->first_text == NULL) + current_file_info->first_text = safe_strdup(""); + current_file_info->readflag = 1; + return ev; +} + + +struct midi_file_info *new_midi_file_info(const char *filename) +{ + struct midi_file_info *p; + p = (struct midi_file_info *)safe_malloc(sizeof(struct midi_file_info)); + + /* Initialize default members */ + memset(p, 0, sizeof(struct midi_file_info)); + p->hdrsiz = -1; + p->format = -1; + p->tracks = -1; + p->divisions = -1; + p->time_sig_n = p->time_sig_d = -1; + p->samples = -1; + p->max_channel = -1; + p->file_type = IS_OTHER_FILE; + if(filename != NULL) + p->filename = safe_strdup(filename); + COPY_CHANNELMASK(p->drumchannels, default_drumchannels); + COPY_CHANNELMASK(p->drumchannel_mask, default_drumchannel_mask); + + /* Append to midi_file_info */ + p->next = midi_file_info; + midi_file_info = p; + + return p; +} + +void free_all_midi_file_info(void) +{ + struct midi_file_info *info, *next; + + info = midi_file_info; + while (info) { + next = info->next; + free(info->filename); + if (info->seq_name) + free(info->seq_name); + if (info->karaoke_title != NULL && info->karaoke_title == info->first_text) + free(info->karaoke_title); + else { + if (info->karaoke_title) + free(info->karaoke_title); + if (info->first_text) + free(info->first_text); + if (info->midi_data) + free(info->midi_data); + if (info->pcm_filename) + free(info->pcm_filename); /* Note: this memory is freed in playmidi.c*/ + } + free(info); + info = next; + } + midi_file_info = NULL; + current_file_info = NULL; +} + +struct midi_file_info *get_midi_file_info(char *filename, int newp) +{ + struct midi_file_info *p; + + filename = url_expand_home_dir(filename); + /* Linear search */ + for(p = midi_file_info; p; p = p->next) + if(!strcmp(filename, p->filename)) + return p; + if(newp) + return new_midi_file_info(filename); + return NULL; +} + +struct timidity_file *open_midi_file(char *fn, + int decompress, int noise_mode) +{ + struct midi_file_info *infop; + struct timidity_file *tf; +#if defined(SMFCONV) && defined(__W32__) + extern int opt_rcpcv_dll; +#endif + + infop = get_midi_file_info(fn, 0); + if(infop == NULL || infop->midi_data == NULL) + tf = open_file(fn, decompress, noise_mode); + else + { + tf = open_with_mem(infop->midi_data, infop->midi_data_size, + noise_mode); + if(infop->compressed) + { + if((tf->url = url_inflate_open(tf->url, infop->midi_data_size, 1)) + == NULL) + { + close_file(tf); + return NULL; + } + } + } + +#if defined(SMFCONV) && defined(__W32__) + /* smf convert */ + if(tf != NULL && opt_rcpcv_dll) + { + if(smfconv_w32(tf, fn)) + { + close_file(tf); + return NULL; + } + } +#endif + + return tf; +} + +#ifndef NO_MIDI_CACHE +static long deflate_url_reader(char *buf, long size, void *user_val) +{ + return url_nread((URL)user_val, buf, size); +} + +/* + * URL data into deflated buffer. + */ +static void url_make_file_data(URL url, struct midi_file_info *infop) +{ + char buff[BUFSIZ]; + MemBuffer b; + long n; + DeflateHandler compressor; + + init_memb(&b); + + /* url => b */ + if((compressor = open_deflate_handler(deflate_url_reader, url, + ARC_DEFLATE_LEVEL)) == NULL) + return; + while((n = zip_deflate(compressor, buff, sizeof(buff))) > 0) + push_memb(&b, buff, n); + close_deflate_handler(compressor); + infop->compressed = 1; + + /* b => mem */ + infop->midi_data_size = b.total_size; + rewind_memb(&b); + infop->midi_data = (void *)safe_malloc(infop->midi_data_size); + read_memb(&b, infop->midi_data, infop->midi_data_size); + delete_memb(&b); +} + +static int check_need_cache(URL url, char *filename) +{ + int t1, t2; + t1 = url_check_type(filename); + t2 = url->type; + return (t1 == URL_http_t || t1 == URL_ftp_t || t1 == URL_news_t) + && t2 != URL_arc_t; +} +#else +/*ARGSUSED*/ +static void url_make_file_data(URL url, struct midi_file_info *infop) +{ +} +/*ARGSUSED*/ +static int check_need_cache(URL url, char *filename) +{ + return 0; +} +#endif /* NO_MIDI_CACHE */ + +int check_midi_file(char *filename) +{ + struct midi_file_info *p; + struct timidity_file *tf; + char tmp[4]; + int32 len; + int16 format; + int check_cache; + + if(filename == NULL) + { + if(current_file_info == NULL) + return -1; + filename = current_file_info->filename; + } + + p = get_midi_file_info(filename, 0); + if(p != NULL) + return p->format; + p = get_midi_file_info(filename, 1); + + if(get_module_type(filename) > 0) + { + p->format = 0; + return 0; + } + + tf = open_file(filename, 1, OF_SILENT); + if(tf == NULL) + return -1; + + check_cache = check_need_cache(tf->url, filename); + if(check_cache) + { + if(!IS_URL_SEEK_SAFE(tf->url)) + { + if((tf->url = url_cache_open(tf->url, 1)) == NULL) + { + close_file(tf); + return -1; + } + } + } + + /* Parse MIDI header */ + if(tf_read(tmp, 1, 4, tf) != 4) + { + close_file(tf); + return -1; + } + + if(tmp[0] == 0) + { + skip(tf, 128 - 4); + if(tf_read(tmp, 1, 4, tf) != 4) + { + close_file(tf); + return -1; + } + } + + if(strncmp(tmp, "RCM-", 4) == 0 || + strncmp(tmp, "COME", 4) == 0 || + strncmp(tmp, "RIFF", 4) == 0 || + strncmp(tmp, "melo", 4) == 0 || + strncmp(tmp, "M1", 2) == 0) + { + p->format = format = 1; + goto end_of_header; + } + + if(strncmp(tmp, "MThd", 4) != 0) + { + close_file(tf); + return -1; + } + + if(tf_read(&len, 4, 1, tf) != 1) + { + close_file(tf); + return -1; + } + len = BE_LONG(len); + + tf_read(&format, 2, 1, tf); + format = BE_SHORT(format); + if(format < 0 || format > 2) + { + close_file(tf); + return -1; + } + skip(tf, len - 2); + + p->format = format; + p->hdrsiz = (int16)tf_tell(tf); + + end_of_header: + if(check_cache) + { + url_rewind(tf->url); + url_cache_disable(tf->url); + url_make_file_data(tf->url, p); + } + close_file(tf); + return format; +} + +static char *get_midi_title1(struct midi_file_info *p) +{ + char *s; + + if(p->format != 0 && p->format != 1) + return NULL; + + if((s = p->seq_name) == NULL) + if((s = p->karaoke_title) == NULL) + s = p->first_text; + if(s != NULL) + { + int all_space, i; + + all_space = 1; + for(i = 0; s[i]; i++) + if(s[i] != ' ') + { + all_space = 0; + break; + } + if(all_space) + s = NULL; + } + return s; +} + +char *get_midi_title(char *filename) +{ + struct midi_file_info *p; + struct timidity_file *tf; + char tmp[4]; + int32 len; + int16 format, tracks, trk; + int laststatus, check_cache; + int mtype; + + if(filename == NULL) + { + if(current_file_info == NULL) + return NULL; + filename = current_file_info->filename; + } + + p = get_midi_file_info(filename, 0); + if(p == NULL) + p = get_midi_file_info(filename, 1); + else + { + if(p->seq_name != NULL || p->first_text != NULL || p->format < 0) + return get_midi_title1(p); + } + + tf = open_file(filename, 1, OF_SILENT); + if(tf == NULL) + return NULL; + + mtype = get_module_type(filename); + check_cache = check_need_cache(tf->url, filename); + if(check_cache || mtype > 0) + { + if(!IS_URL_SEEK_SAFE(tf->url)) + { + if((tf->url = url_cache_open(tf->url, 1)) == NULL) + { + close_file(tf); + return NULL; + } + } + } + + if(mtype > 0) + { + char *title, *str; + + title = get_module_title(tf, mtype); + if(title == NULL) + { + /* No title */ + p->seq_name = NULL; + p->format = 0; + goto end_of_parse; + } + + len = (int32)strlen(title); + len = SAFE_CONVERT_LENGTH(len); + str = (char *)new_segment(&tmpbuffer, len); + code_convert(title, str, len, NULL, NULL); + p->seq_name = (char *)safe_strdup(str); + reuse_mblock(&tmpbuffer); + p->format = 0; + free (title); + goto end_of_parse; + } + + /* Parse MIDI header */ + if(tf_read(tmp, 1, 4, tf) != 4) + { + close_file(tf); + return NULL; + } + + if(tmp[0] == 0) + { + skip(tf, 128 - 4); + if(tf_read(tmp, 1, 4, tf) != 4) + { + close_file(tf); + return NULL; + } + } + + if(memcmp(tmp, "RCM-", 4) == 0 || memcmp(tmp, "COME", 4) == 0) + { + int i; + char local[0x40 + 1]; + char *str; + + p->format = 1; + skip(tf, 0x20 - 4); + tf_read(local, 1, 0x40, tf); + local[0x40]='\0'; + + for(i = 0x40 - 1; i >= 0; i--) + { + if(local[i] == 0x20) + local[i] = '\0'; + else if(local[i] != '\0') + break; + } + + i = SAFE_CONVERT_LENGTH(i + 1); + str = (char *)new_segment(&tmpbuffer, i); + code_convert(local, str, i, NULL, NULL); + p->seq_name = (char *)safe_strdup(str); + reuse_mblock(&tmpbuffer); + p->format = 1; + goto end_of_parse; + } + if(memcmp(tmp, "melo", 4) == 0) + { + int i; + char *master, *converted; + + master = get_mfi_file_title(tf); + if (master != NULL) + { + i = SAFE_CONVERT_LENGTH(strlen(master) + 1); + converted = (char *)new_segment(&tmpbuffer, i); + code_convert(master, converted, i, NULL, NULL); + p->seq_name = (char *)safe_strdup(converted); + reuse_mblock(&tmpbuffer); + } + else + { + p->seq_name = (char *)safe_malloc(1); + p->seq_name[0] = '\0'; + } + p->format = 0; + goto end_of_parse; + } + + if(strncmp(tmp, "M1", 2) == 0) + { + /* I don't know MPC file format */ + p->format = 1; + goto end_of_parse; + } + + if(strncmp(tmp, "RIFF", 4) == 0) + { + /* RIFF MIDI file */ + skip(tf, 20 - 4); + if(tf_read(tmp, 1, 4, tf) != 4) + { + close_file(tf); + return NULL; + } + } + + if(strncmp(tmp, "MThd", 4) != 0) + { + close_file(tf); + return NULL; + } + + if(tf_read(&len, 4, 1, tf) != 1) + { + close_file(tf); + return NULL; + } + + len = BE_LONG(len); + + tf_read(&format, 2, 1, tf); + tf_read(&tracks, 2, 1, tf); + format = BE_SHORT(format); + tracks = BE_SHORT(tracks); + p->format = format; + p->tracks = tracks; + if(format < 0 || format > 2) + { + p->format = -1; + close_file(tf); + return NULL; + } + + skip(tf, len - 4); + p->hdrsiz = (int16)tf_tell(tf); + + if(format == 2) + goto end_of_parse; + + if(tracks >= 3) + { + tracks = 3; + karaoke_format = 0; + } + else + { + tracks = 1; + karaoke_format = -1; + } + + for(trk = 0; trk < tracks; trk++) + { + int32 next_pos, pos; + + if(trk >= 1 && karaoke_format == -1) + break; + + if((tf_read(tmp,1,4,tf) != 4) || (tf_read(&len,4,1,tf) != 1)) + break; + + if(memcmp(tmp, "MTrk", 4)) + break; + + next_pos = tf_tell(tf) + len; + laststatus = -1; + for(;;) + { + int i, me, type; + + /* skip Variable-length quantity */ + do + { + if((i = tf_getc(tf)) == EOF) + goto end_of_parse; + } while (i & 0x80); + + if((me = tf_getc(tf)) == EOF) + goto end_of_parse; + + if(me == 0xF0 || me == 0xF7) /* SysEx */ + { + if((len = getvl(tf)) < 0) + goto end_of_parse; + if((p->mid == 0 || p->mid >= 0x7e) && len > 0 && me == 0xF0) + { + p->mid = tf_getc(tf); + len--; + } + skip(tf, len); + } + else if(me == 0xFF) /* Meta */ + { + type = tf_getc(tf); + if((len = getvl(tf)) < 0) + goto end_of_parse; + if((type == 1 || type == 3) && len > 0 && + (trk == 0 || karaoke_format != -1)) + { + char *si, *so; + int s_maxlen = SAFE_CONVERT_LENGTH(len); + + si = (char *)new_segment(&tmpbuffer, len + 1); + so = (char *)new_segment(&tmpbuffer, s_maxlen); + + if(len != tf_read(si, 1, len, tf)) + { + reuse_mblock(&tmpbuffer); + goto end_of_parse; + } + + si[len]='\0'; + code_convert(si, so, s_maxlen, NULL, NULL); + if(trk == 0 && type == 3) + { + if(p->seq_name == NULL) { + char *name = safe_strdup(so); + p->seq_name = safe_strdup(fix_string(name)); + free(name); + } + reuse_mblock(&tmpbuffer); + if(karaoke_format == -1) + goto end_of_parse; + } + if(p->first_text == NULL) { + char *name; + name = safe_strdup(so); + p->first_text = safe_strdup(fix_string(name)); + free(name); + } + if(karaoke_format != -1) + { + if(trk == 1 && strncmp(si, "@K", 2) == 0) + karaoke_format = 1; + else if(karaoke_format == 1 && trk == 2) + karaoke_format = 2; + } + if(type == 1 && karaoke_format == 2) + { + if(strncmp(si, "@T", 2) == 0) + p->karaoke_title = + add_karaoke_title(p->karaoke_title, si + 2); + else if(si[0] == '\\') + goto end_of_parse; + } + reuse_mblock(&tmpbuffer); + } + else if(type == 0x2F) + { + pos = tf_tell(tf); + if(pos < next_pos) + tf_seek(tf, next_pos - pos, SEEK_CUR); + break; /* End of track */ + } + else + skip(tf, len); + } + else /* MIDI event */ + { + /* skip MIDI event */ + karaoke_format = -1; + if(trk != 0) + goto end_of_parse; + + if(me & 0x80) /* status byte */ + { + laststatus = (me >> 4) & 0x07; + if(laststatus != 7) + tf_getc(tf); + } + + switch(laststatus) + { + case 0: case 1: case 2: case 3: case 6: + tf_getc(tf); + break; + case 7: + if(!(me & 0x80)) + break; + switch(me & 0x0F) + { + case 2: + tf_getc(tf); + tf_getc(tf); + break; + case 3: + tf_getc(tf); + break; + } + break; + } + } + } + } + + end_of_parse: + if(check_cache) + { + url_rewind(tf->url); + url_cache_disable(tf->url); + url_make_file_data(tf->url, p); + } + close_file(tf); + if(p->first_text == NULL) + p->first_text = safe_strdup(""); + return get_midi_title1(p); +} + +int midi_file_save_as(char *in_name, char *out_name) +{ + struct timidity_file *tf; + FILE* ofp; + char buff[BUFSIZ]; + long n; + + if(in_name == NULL) + { + if(current_file_info == NULL) + return 0; + in_name = current_file_info->filename; + } + out_name = (char *)url_expand_home_dir(out_name); + + ctl->cmsg(CMSG_INFO, VERB_NORMAL, "Save as %s...", out_name); + + errno = 0; + if((tf = open_midi_file(in_name, 1, 0)) == NULL) + { + ctl->cmsg(CMSG_ERROR, VERB_NORMAL, + "%s: %s", out_name, + errno ? strerror(errno) : "Can't save file"); + return -1; + } + + errno = 0; + if((ofp = fopen(out_name, "wb")) == NULL) + { + ctl->cmsg(CMSG_ERROR, VERB_NORMAL, + "%s: %s", out_name, + errno ? strerror(errno) : "Can't save file"); + close_file(tf); + return -1; + } + + while((n = tf_read(buff, 1, sizeof(buff), tf)) > 0) { + size_t dummy = fwrite(buff, 1, n, ofp); ++dummy; + } + ctl->cmsg(CMSG_INFO, VERB_NORMAL, "Save as %s...Done", out_name); + + fclose(ofp); + close_file(tf); + return 0; +} + +char *event2string(int id) +{ + if(id == 0) + return ""; +#ifdef ABORT_AT_FATAL + if(id >= string_event_table_size) + abort(); +#endif /* ABORT_AT_FATAL */ + if(string_event_table == NULL || id < 0 || id >= string_event_table_size) + return NULL; + return string_event_table[id]; +} + +/*! initialize Delay Effect (GS) */ +void init_delay_status_gs(void) +{ + struct delay_status_gs_t *p = &delay_status_gs; + p->type = 0; + p->level = 0x40; + p->level_center = 0x7F; + p->level_left = 0; + p->level_right = 0; + p->time_c = 0x61; + p->time_l = 0x01; + p->time_r = 0x01; + p->feedback = 0x50; + p->pre_lpf = 0; + recompute_delay_status_gs(); +} + +/*! recompute Delay Effect (GS) */ +void recompute_delay_status_gs(void) +{ + struct delay_status_gs_t *p = &delay_status_gs; + p->time_center = delay_time_center_table[p->time_c > 0x73 ? 0x73 : p->time_c]; + p->time_ratio_left = (double)p->time_l / 24; + p->time_ratio_right = (double)p->time_r / 24; + p->sample[0] = p->time_center * play_mode->rate / 1000.0f; + p->sample[1] = p->sample[0] * p->time_ratio_left; + p->sample[2] = p->sample[0] * p->time_ratio_right; + p->level_ratio[0] = p->level * p->level_center / (127.0f * 127.0f); + p->level_ratio[1] = p->level * p->level_left / (127.0f * 127.0f); + p->level_ratio[2] = p->level * p->level_right / (127.0f * 127.0f); + p->feedback_ratio = (double)(p->feedback - 64) * (0.763f * 2.0f / 100.0f); + p->send_reverb_ratio = (double)p->send_reverb * (0.787f / 100.0f); + + if(p->level_left != 0 || (p->level_right != 0 && p->type == 0)) { + p->type = 1; /* it needs 3-tap delay effect. */ + } + + if(p->pre_lpf) { + p->lpf.a = 2.0 * ((double)(7 - p->pre_lpf) / 7.0f * 16000.0f + 200.0f) / play_mode->rate; + init_filter_lowpass1(&(p->lpf)); + } +} + +/*! Delay Macro (GS) */ +void set_delay_macro_gs(int macro) +{ + struct delay_status_gs_t *p = &delay_status_gs; + if(macro >= 4) {p->type = 2;} /* cross delay */ + macro *= 10; + p->time_center = delay_time_center_table[delay_macro_presets[macro + 1]]; + p->time_ratio_left = (double)delay_macro_presets[macro + 2] / 24; + p->time_ratio_right = (double)delay_macro_presets[macro + 3] / 24; + p->level_center = delay_macro_presets[macro + 4]; + p->level_left = delay_macro_presets[macro + 5]; + p->level_right = delay_macro_presets[macro + 6]; + p->level = delay_macro_presets[macro + 7]; + p->feedback = delay_macro_presets[macro + 8]; +} + +/*! initialize Reverb Effect (GS) */ +void init_reverb_status_gs(void) +{ + struct reverb_status_gs_t *p = &reverb_status_gs; + p->character = 0x04; + p->pre_lpf = 0; + p->level = 0x40; + p->time = 0x40; + p->delay_feedback = 0; + p->pre_delay_time = 0; + recompute_reverb_status_gs(); + init_reverb(); +} + +/*! recompute Reverb Effect (GS) */ +void recompute_reverb_status_gs(void) +{ + struct reverb_status_gs_t *p = &reverb_status_gs; + + if(p->pre_lpf) { + p->lpf.a = 2.0 * ((double)(7 - p->pre_lpf) / 7.0f * 16000.0f + 200.0f) / play_mode->rate; + init_filter_lowpass1(&(p->lpf)); + } +} + +/*! Reverb Type (GM2) */ +void set_reverb_macro_gm2(int macro) +{ + struct reverb_status_gs_t *p = &reverb_status_gs; + int type = macro; + if (macro == 8) {macro = 5;} + macro *= 6; + p->character = reverb_macro_presets[macro]; + p->pre_lpf = reverb_macro_presets[macro + 1]; + p->level = reverb_macro_presets[macro + 2]; + p->time = reverb_macro_presets[macro + 3]; + p->delay_feedback = reverb_macro_presets[macro + 4]; + p->pre_delay_time = reverb_macro_presets[macro + 5]; + + switch(type) { /* override GS macro's parameter */ + case 0: /* Small Room */ + p->time = 44; + break; + case 1: /* Medium Room */ + case 8: /* Plate */ + p->time = 50; + break; + case 2: /* Large Room */ + p->time = 56; + break; + case 3: /* Medium Hall */ + case 4: /* Large Hall */ + p->time = 64; + break; + } +} + +/*! Reverb Macro (GS) */ +void set_reverb_macro_gs(int macro) +{ + struct reverb_status_gs_t *p = &reverb_status_gs; + macro *= 6; + p->character = reverb_macro_presets[macro]; + p->pre_lpf = reverb_macro_presets[macro + 1]; + p->level = reverb_macro_presets[macro + 2]; + p->time = reverb_macro_presets[macro + 3]; + p->delay_feedback = reverb_macro_presets[macro + 4]; + p->pre_delay_time = reverb_macro_presets[macro + 5]; +} + +/*! initialize Chorus Effect (GS) */ +void init_chorus_status_gs(void) +{ + struct chorus_status_gs_t *p = &chorus_status_gs; + p->macro = 0; + p->pre_lpf = 0; + p->level = 0x40; + p->feedback = 0x08; + p->delay = 0x50; + p->rate = 0x03; + p->depth = 0x13; + p->send_reverb = 0; + p->send_delay = 0; + recompute_chorus_status_gs(); +} + +/*! recompute Chorus Effect (GS) */ +void recompute_chorus_status_gs() +{ + struct chorus_status_gs_t *p = &chorus_status_gs; + + if(p->pre_lpf) { + p->lpf.a = 2.0 * ((double)(7 - p->pre_lpf) / 7.0f * 16000.0f + 200.0f) / play_mode->rate; + init_filter_lowpass1(&(p->lpf)); + } +} + +/*! Chorus Macro (GS), Chorus Type (GM2) */ +void set_chorus_macro_gs(int macro) +{ + struct chorus_status_gs_t *p = &chorus_status_gs; + macro *= 8; + p->pre_lpf = chorus_macro_presets[macro]; + p->level = chorus_macro_presets[macro + 1]; + p->feedback = chorus_macro_presets[macro + 2]; + p->delay = chorus_macro_presets[macro + 3]; + p->rate = chorus_macro_presets[macro + 4]; + p->depth = chorus_macro_presets[macro + 5]; + p->send_reverb = chorus_macro_presets[macro + 6]; + p->send_delay = chorus_macro_presets[macro + 7]; +} + +/*! initialize EQ (GS) */ +void init_eq_status_gs(void) +{ + struct eq_status_gs_t *p = &eq_status_gs; + p->low_freq = 0; + p->low_gain = 0x40; + p->high_freq = 0; + p->high_gain = 0x40; + recompute_eq_status_gs(); +} + +/*! recompute EQ (GS) */ +void recompute_eq_status_gs(void) +{ + double freq, dbGain; + struct eq_status_gs_t *p = &eq_status_gs; + + /* Lowpass Shelving Filter */ + if(p->low_freq == 0) {freq = 200;} + else {freq = 400;} + dbGain = p->low_gain - 0x40; + if(freq < play_mode->rate / 2) { + p->lsf.q = 0; + p->lsf.freq = freq; + p->lsf.gain = dbGain; + calc_filter_shelving_low(&(p->lsf)); + } + + /* Highpass Shelving Filter */ + if(p->high_freq == 0) {freq = 3000;} + else {freq = 6000;} + dbGain = p->high_gain - 0x40; + if(freq < play_mode->rate / 2) { + p->hsf.q = 0; + p->hsf.freq = freq; + p->hsf.gain = dbGain; + calc_filter_shelving_high(&(p->hsf)); + } +} + +/*! initialize Multi EQ (XG) */ +void init_multi_eq_xg(void) +{ + multi_eq_xg.valid = 0; + set_multi_eq_type_xg(0); + recompute_multi_eq_xg(); +} + +/*! set Multi EQ type (XG) */ +void set_multi_eq_type_xg(int type) +{ + struct multi_eq_xg_t *p = &multi_eq_xg; + type *= 20; + p->gain1 = multi_eq_block_table_xg[type]; + p->freq1 = multi_eq_block_table_xg[type + 1]; + p->q1 = multi_eq_block_table_xg[type + 2]; + p->shape1 = multi_eq_block_table_xg[type + 3]; + p->gain2 = multi_eq_block_table_xg[type + 4]; + p->freq2 = multi_eq_block_table_xg[type + 5]; + p->q2 = multi_eq_block_table_xg[type + 6]; + p->gain3 = multi_eq_block_table_xg[type + 8]; + p->freq3 = multi_eq_block_table_xg[type + 9]; + p->q3 = multi_eq_block_table_xg[type + 10]; + p->gain4 = multi_eq_block_table_xg[type + 12]; + p->freq4 = multi_eq_block_table_xg[type + 13]; + p->q4 = multi_eq_block_table_xg[type + 14]; + p->gain5 = multi_eq_block_table_xg[type + 16]; + p->freq5 = multi_eq_block_table_xg[type + 17]; + p->q5 = multi_eq_block_table_xg[type + 18]; + p->shape5 = multi_eq_block_table_xg[type + 19]; +} + +/*! recompute Multi EQ (XG) */ +void recompute_multi_eq_xg(void) +{ + struct multi_eq_xg_t *p = &multi_eq_xg; + + if(p->freq1 != 0 && p->freq1 < 60 && p->gain1 != 0x40) { + p->valid1 = 1; + if(p->shape1) { /* peaking */ + p->eq1p.q = (double)p->q1 / 10.0; + p->eq1p.freq = eq_freq_table_xg[p->freq1]; + p->eq1p.gain = p->gain1 - 0x40; + calc_filter_peaking(&(p->eq1p)); + } else { /* shelving */ + p->eq1s.q = (double)p->q1 / 10.0; + p->eq1s.freq = eq_freq_table_xg[p->freq1]; + p->eq1s.gain = p->gain1 - 0x40; + calc_filter_shelving_low(&(p->eq1s)); + } + } else {p->valid1 = 0;} + if(p->freq2 != 0 && p->freq2 < 60 && p->gain2 != 0x40) { + p->valid2 = 1; + p->eq2p.q = (double)p->q2 / 10.0; + p->eq2p.freq = eq_freq_table_xg[p->freq2]; + p->eq2p.gain = p->gain2 - 0x40; + calc_filter_peaking(&(p->eq2p)); + } else {p->valid2 = 0;} + if(p->freq3 != 0 && p->freq3 < 60 && p->gain3 != 0x40) { + p->valid3 = 1; + p->eq3p.q = (double)p->q3 / 10.0; + p->eq4p.freq = eq_freq_table_xg[p->freq3]; + p->eq4p.gain = p->gain3 - 0x40; + calc_filter_peaking(&(p->eq3p)); + } else {p->valid3 = 0;} + if(p->freq4 != 0 && p->freq4 < 60 && p->gain4 != 0x40) { + p->valid4 = 1; + p->eq4p.q = (double)p->q4 / 10.0; + p->eq4p.freq = eq_freq_table_xg[p->freq4]; + p->eq4p.gain = p->gain4 - 0x40; + calc_filter_peaking(&(p->eq4p)); + } else {p->valid4 = 0;} + if(p->freq5 != 0 && p->freq5 < 60 && p->gain5 != 0x40) { + p->valid5 = 1; + if(p->shape5) { /* peaking */ + p->eq5p.q = (double)p->q5 / 10.0; + p->eq5p.freq = eq_freq_table_xg[p->freq5]; + p->eq5p.gain = p->gain5 - 0x40; + calc_filter_peaking(&(p->eq5p)); + } else { /* shelving */ + p->eq5s.q = (double)p->q5 / 10.0; + p->eq5s.freq = eq_freq_table_xg[p->freq5]; + p->eq5s.gain = p->gain5 - 0x40; + calc_filter_shelving_high(&(p->eq5s)); + } + } else {p->valid5 = 0;} + p->valid = p->valid1 || p->valid2 || p->valid3 || p->valid4 || p->valid5; +} + +/*! convert GS user drumset assign groups to internal "alternate assign". */ +void recompute_userdrum_altassign(int bank, int group) +{ + int number = 0, i; + char *params[131], param[10]; + ToneBank *bk; + UserDrumset *p; + + for(p = userdrum_first; p != NULL; p = p->next) { + if(p->assign_group == group) { + sprintf(param, "%d", p->prog); + params[number] = safe_strdup(param); + number++; + } + } + params[number] = NULL; + + alloc_instrument_bank(1, bank); + bk = drumset[bank]; + bk->alt = add_altassign_string(bk->alt, params, number); + for (i = number - 1; i >= 0; i--) + free(params[i]); +} + +/*! initialize GS user drumset. */ +void init_userdrum() +{ + int i; + AlternateAssign *alt; + + free_userdrum(); + + for(i=0;i<2;i++) { /* allocate alternative assign */ + alt = (AlternateAssign *)safe_malloc(sizeof(AlternateAssign)); + memset(alt, 0, sizeof(AlternateAssign)); + alloc_instrument_bank(1, 64 + i); + drumset[64 + i]->alt = alt; + } +} + +/*! recompute GS user drumset. */ +Instrument *recompute_userdrum(int bank, int prog) +{ + UserDrumset *p; + Instrument *ip = NULL; + + p = get_userdrum(bank, prog); + + free_tone_bank_element(&drumset[bank]->tone[prog]); + if(drumset[p->source_prog]) { + ToneBankElement *source_tone = &drumset[p->source_prog]->tone[p->source_note]; + + if(source_tone->name == NULL /* NULL if "soundfont" directive is used */ + && source_tone->instrument == NULL) { + if((ip = load_instrument(1, p->source_prog, p->source_note)) == NULL) { + ip = MAGIC_ERROR_INSTRUMENT; + } + source_tone->instrument = ip; + } + if(source_tone->name) { + copy_tone_bank_element(&drumset[bank]->tone[prog], source_tone); + ctl->cmsg(CMSG_INFO,VERB_NOISY,"User Drumset (%d %d -> %d %d)", p->source_prog, p->source_note, bank, prog); + } else if(drumset[0]->tone[p->source_note].name) { + copy_tone_bank_element(&drumset[bank]->tone[prog], &drumset[0]->tone[p->source_note]); + ctl->cmsg(CMSG_INFO,VERB_NOISY,"User Drumset (%d %d -> %d %d)", 0, p->source_note, bank, prog); + } else { + ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "Referring user drum set %d, note %d not found - this instrument will not be heard as expected", bank, prog); + } + } + return ip; +} + +/*! get pointer to requested GS user drumset. + if it's not found, allocate a new item first. */ +UserDrumset *get_userdrum(int bank, int prog) +{ + UserDrumset *p; + + for(p = userdrum_first; p != NULL; p = p->next) { + if(p->bank == bank && p->prog == prog) {return p;} + } + + p = (UserDrumset *)safe_malloc(sizeof(UserDrumset)); + memset(p, 0, sizeof(UserDrumset)); + p->next = NULL; + if(userdrum_first == NULL) { + userdrum_first = p; + userdrum_last = p; + } else { + userdrum_last->next = p; + userdrum_last = p; + } + p->bank = bank; + p->prog = prog; + + return p; +} + +/*! free GS user drumset. */ +void free_userdrum() +{ + UserDrumset *p, *next; + + for(p = userdrum_first; p != NULL; p = next){ + next = p->next; + free(p); + } + userdrum_first = userdrum_last = NULL; +} + +/*! initialize GS user instrument. */ +void init_userinst() +{ + free_userinst(); +} + +/*! recompute GS user instrument. */ +void recompute_userinst(int bank, int prog) +{ + UserInstrument *p; + + p = get_userinst(bank, prog); + + free_tone_bank_element(&tonebank[bank]->tone[prog]); + if(tonebank[p->source_bank]) { + if(tonebank[p->source_bank]->tone[p->source_prog].name) { + copy_tone_bank_element(&tonebank[bank]->tone[prog], &tonebank[p->source_bank]->tone[p->source_prog]); + ctl->cmsg(CMSG_INFO,VERB_NOISY,"User Instrument (%d %d -> %d %d)", p->source_bank, p->source_prog, bank, prog); + } else if(tonebank[0]->tone[p->source_prog].name) { + copy_tone_bank_element(&tonebank[bank]->tone[prog], &tonebank[0]->tone[p->source_prog]); + ctl->cmsg(CMSG_INFO,VERB_NOISY,"User Instrument (%d %d -> %d %d)", 0, p->source_prog, bank, prog); + } + } +} + +/*! get pointer to requested GS user instrument. + if it's not found, allocate a new item first. */ +UserInstrument *get_userinst(int bank, int prog) +{ + UserInstrument *p; + + for(p = userinst_first; p != NULL; p = p->next) { + if(p->bank == bank && p->prog == prog) {return p;} + } + + p = (UserInstrument *)safe_malloc(sizeof(UserInstrument)); + memset(p, 0, sizeof(UserInstrument)); + p->next = NULL; + if(userinst_first == NULL) { + userinst_first = p; + userinst_last = p; + } else { + userinst_last->next = p; + userinst_last = p; + } + p->bank = bank; + p->prog = prog; + + return p; +} + +/*! free GS user instrument. */ +void free_userinst() +{ + UserInstrument *p, *next; + + for(p = userinst_first; p != NULL; p = next){ + next = p->next; + free(p); + } + userinst_first = userinst_last = NULL; +} + +static void set_effect_param_xg(struct effect_xg_t *st, int type_msb, int type_lsb) +{ + int i, j; + for (i = 0; effect_parameter_xg[i].type_msb != -1 + && effect_parameter_xg[i].type_lsb != -1; i++) { + if (type_msb == effect_parameter_xg[i].type_msb + && type_lsb == effect_parameter_xg[i].type_lsb) { + for (j = 0; j < 16; j++) { + st->param_lsb[j] = effect_parameter_xg[i].param_lsb[j]; + } + for (j = 0; j < 10; j++) { + st->param_msb[j] = effect_parameter_xg[i].param_msb[j]; + } + ctl->cmsg(CMSG_INFO, VERB_NOISY, "XG EFX: %s", effect_parameter_xg[i].name); + return; + } + } + if (type_msb != 0) { + for (i = 0; effect_parameter_xg[i].type_msb != -1 + && effect_parameter_xg[i].type_lsb != -1; i++) { + if (type_lsb == effect_parameter_xg[i].type_lsb) { + for (j = 0; j < 16; j++) { + st->param_lsb[j] = effect_parameter_xg[i].param_lsb[j]; + } + for (j = 0; j < 10; j++) { + st->param_msb[j] = effect_parameter_xg[i].param_msb[j]; + } + ctl->cmsg(CMSG_INFO, VERB_NOISY, "XG EFX: %s", effect_parameter_xg[i].name); + return; + } + } + } +} + +/*! recompute XG effect parameters. */ +void recompute_effect_xg(struct effect_xg_t *st) +{ + EffectList *efc = st->ef; + + if (efc == NULL) {return;} + while (efc != NULL && efc->info != NULL) + { + (*efc->engine->conv_xg)(st, efc); + (*efc->engine->do_effect)(NULL, MAGIC_INIT_EFFECT_INFO, efc); + efc = efc->next_ef; + } +} + +void realloc_effect_xg(struct effect_xg_t *st) +{ + int type_msb = st->type_msb, type_lsb = st->type_lsb; + + free_effect_list(st->ef); + st->ef = NULL; + st->use_msb = 0; + + switch(type_msb) { + case 0x05: + st->use_msb = 1; + st->ef = push_effect(st->ef, EFFECT_DELAY_LCR); + st->ef = push_effect(st->ef, EFFECT_DELAY_EQ2); + break; + case 0x06: + st->use_msb = 1; + st->ef = push_effect(st->ef, EFFECT_DELAY_LR); + st->ef = push_effect(st->ef, EFFECT_DELAY_EQ2); + break; + case 0x07: + st->use_msb = 1; + st->ef = push_effect(st->ef, EFFECT_ECHO); + st->ef = push_effect(st->ef, EFFECT_DELAY_EQ2); + break; + case 0x08: + st->use_msb = 1; + st->ef = push_effect(st->ef, EFFECT_CROSS_DELAY); + st->ef = push_effect(st->ef, EFFECT_DELAY_EQ2); + break; + case 0x41: + case 0x42: + st->ef = push_effect(st->ef, EFFECT_CHORUS); + st->ef = push_effect(st->ef, EFFECT_CHORUS_EQ3); + break; + case 0x43: + st->ef = push_effect(st->ef, EFFECT_FLANGER); + st->ef = push_effect(st->ef, EFFECT_CHORUS_EQ3); + break; + case 0x44: + st->ef = push_effect(st->ef, EFFECT_SYMPHONIC); + st->ef = push_effect(st->ef, EFFECT_CHORUS_EQ3); + break; + case 0x49: + st->ef = push_effect(st->ef, EFFECT_STEREO_DISTORTION); + st->ef = push_effect(st->ef, EFFECT_OD_EQ3); + break; + case 0x4A: + st->ef = push_effect(st->ef, EFFECT_STEREO_OVERDRIVE); + st->ef = push_effect(st->ef, EFFECT_OD_EQ3); + break; + case 0x4B: + st->ef = push_effect(st->ef, EFFECT_STEREO_AMP_SIMULATOR); + break; + case 0x4C: + st->ef = push_effect(st->ef, EFFECT_EQ3); + break; + case 0x4D: + st->ef = push_effect(st->ef, EFFECT_EQ2); + break; + case 0x4E: + if (type_lsb == 0x01 || type_lsb == 0x02) { + st->ef = push_effect(st->ef, EFFECT_XG_AUTO_WAH); + st->ef = push_effect(st->ef, EFFECT_XG_AUTO_WAH_EQ2); + st->ef = push_effect(st->ef, EFFECT_XG_AUTO_WAH_OD); + st->ef = push_effect(st->ef, EFFECT_XG_AUTO_WAH_OD_EQ3); + } else { + st->ef = push_effect(st->ef, EFFECT_XG_AUTO_WAH); + st->ef = push_effect(st->ef, EFFECT_XG_AUTO_WAH_EQ2); + } + break; + case 0x5E: + st->ef = push_effect(st->ef, EFFECT_LOFI); + break; + default: /* Not Supported */ + type_msb = type_lsb = 0; + break; + } + set_effect_param_xg(st, type_msb, type_lsb); + recompute_effect_xg(st); +} + +static void init_effect_xg(struct effect_xg_t *st) +{ + int i; + + free_effect_list(st->ef); + st->ef = NULL; + + st->use_msb = 0; + st->type_msb = st->type_lsb = st->connection = + st->send_reverb = st->send_chorus = 0; + st->part = 0x7f; + st->ret = st->pan = st->mw_depth = st->bend_depth = st->cat_depth = + st->ac1_depth = st->ac2_depth = st->cbc1_depth = st->cbc2_depth = 0x40; + for (i = 0; i < 16; i++) {st->param_lsb[i] = 0;} + for (i = 0; i < 10; i++) {st->param_msb[i] = 0;} +} + +/*! initialize XG effect parameters */ +static void init_all_effect_xg(void) +{ + int i; + init_effect_xg(&reverb_status_xg); + reverb_status_xg.type_msb = 0x01; + reverb_status_xg.connection = XG_CONN_SYSTEM_REVERB; + realloc_effect_xg(&reverb_status_xg); + init_effect_xg(&chorus_status_xg); + chorus_status_xg.type_msb = 0x41; + chorus_status_xg.connection = XG_CONN_SYSTEM_CHORUS; + realloc_effect_xg(&chorus_status_xg); + for (i = 0; i < XG_VARIATION_EFFECT_NUM; i++) { + init_effect_xg(&variation_effect_xg[i]); + variation_effect_xg[i].type_msb = 0x05; + realloc_effect_xg(&variation_effect_xg[i]); + } + for (i = 0; i < XG_INSERTION_EFFECT_NUM; i++) { + init_effect_xg(&insertion_effect_xg[i]); + insertion_effect_xg[i].type_msb = 0x49; + realloc_effect_xg(&insertion_effect_xg[i]); + } + init_ch_effect_xg(); +} + +/*! initialize GS insertion effect parameters */ +void init_insertion_effect_gs(void) +{ + int i; + struct insertion_effect_gs_t *st = &insertion_effect_gs; + + free_effect_list(st->ef); + st->ef = NULL; + + for(i = 0; i < 20; i++) {st->parameter[i] = 0;} + + st->type = 0; + st->type_lsb = 0; + st->type_msb = 0; + st->send_reverb = 0x28; + st->send_chorus = 0; + st->send_delay = 0; + st->control_source1 = 0; + st->control_depth1 = 0x40; + st->control_source2 = 0; + st->control_depth2 = 0x40; + st->send_eq_switch = 0x01; +} + +static void set_effect_param_gs(struct insertion_effect_gs_t *st, int msb, int lsb) +{ + int i, j; + for (i = 0; effect_parameter_gs[i].type_msb != -1 + && effect_parameter_gs[i].type_lsb != -1; i++) { + if (msb == effect_parameter_gs[i].type_msb + && lsb == effect_parameter_gs[i].type_lsb) { + for (j = 0; j < 20; j++) { + st->parameter[j] = effect_parameter_gs[i].param[j]; + } + ctl->cmsg(CMSG_INFO, VERB_NOISY, "GS EFX: %s", effect_parameter_gs[i].name); + break; + } + } +} + +/*! recompute GS insertion effect parameters. */ +void recompute_insertion_effect_gs(void) +{ + struct insertion_effect_gs_t *st = &insertion_effect_gs; + EffectList *efc = st->ef; + + if (st->ef == NULL) {return;} + while(efc != NULL && efc->info != NULL) + { + (*efc->engine->conv_gs)(st, efc); + (*efc->engine->do_effect)(NULL, MAGIC_INIT_EFFECT_INFO, efc); + efc = efc->next_ef; + } +} + +/*! re-allocate GS insertion effect parameters. */ +void realloc_insertion_effect_gs(void) +{ + struct insertion_effect_gs_t *st = &insertion_effect_gs; + int type_msb = st->type_msb, type_lsb = st->type_lsb; + + free_effect_list(st->ef); + st->ef = NULL; + + switch(type_msb) { + case 0x01: + switch(type_lsb) { + case 0x00: /* Stereo-EQ */ + st->ef = push_effect(st->ef, EFFECT_STEREO_EQ); + break; + case 0x10: /* Overdrive */ + st->ef = push_effect(st->ef, EFFECT_EQ2); + st->ef = push_effect(st->ef, EFFECT_OVERDRIVE1); + break; + case 0x11: /* Distortion */ + st->ef = push_effect(st->ef, EFFECT_EQ2); + st->ef = push_effect(st->ef, EFFECT_DISTORTION1); + break; + case 0x40: /* Hexa Chorus */ + st->ef = push_effect(st->ef, EFFECT_EQ2); + st->ef = push_effect(st->ef, EFFECT_HEXA_CHORUS); + break; + case 0x72: /* Lo-Fi 1 */ + st->ef = push_effect(st->ef, EFFECT_EQ2); + st->ef = push_effect(st->ef, EFFECT_LOFI1); + break; + case 0x73: /* Lo-Fi 2 */ + st->ef = push_effect(st->ef, EFFECT_EQ2); + st->ef = push_effect(st->ef, EFFECT_LOFI2); + break; + default: break; + } + break; + case 0x11: + switch(type_lsb) { + case 0x03: /* OD1 / OD2 */ + st->ef = push_effect(st->ef, EFFECT_OD1OD2); + break; + default: break; + } + break; + default: break; + } + + set_effect_param_gs(st, type_msb, type_lsb); + + recompute_insertion_effect_gs(); +} + +/*! initialize channel layers. */ +void init_channel_layer(int ch) +{ + if (ch >= MAX_CHANNELS) + return; + CLEAR_CHANNELMASK(channel[ch].channel_layer); + SET_CHANNELMASK(channel[ch].channel_layer, ch); + channel[ch].port_select = ch >> 4; +} + +/*! add a new layer. */ +void add_channel_layer(int to_ch, int from_ch) +{ + if (to_ch >= MAX_CHANNELS || from_ch >= MAX_CHANNELS) + return; + /* add a channel layer */ + UNSET_CHANNELMASK(channel[to_ch].channel_layer, to_ch); + SET_CHANNELMASK(channel[to_ch].channel_layer, from_ch); + ctl->cmsg(CMSG_INFO, VERB_NOISY, + "Channel Layer (CH:%d -> CH:%d)", from_ch, to_ch); +} + +/*! remove all layers for this channel. */ +void remove_channel_layer(int ch) +{ + int i, offset; + + if (ch >= MAX_CHANNELS) + return; + /* remove channel layers */ + offset = ch & ~0xf; + for (i = offset; i < offset + REDUCE_CHANNELS; i++) + UNSET_CHANNELMASK(channel[i].channel_layer, ch); + SET_CHANNELMASK(channel[ch].channel_layer, ch); +} + +void free_readmidi(void) +{ + reuse_mblock(&mempool); + free_all_midi_file_info(); + free_userdrum(); + free_userinst(); + if (string_event_strtab.nstring > 0) + delete_string_table(&string_event_strtab); + if (string_event_table != NULL) { + free(string_event_table[0]); + free(string_event_table); + string_event_table = NULL; + string_event_table_size = 0; + } +} + +int main(){ + return 0; //well obviously this won't compile because of all the libs it asks for, should we just copy those to this directory too? well need to figure out which to compy, overwise we will end up with whole timidity here. +} |
