/* TiMidity++ -- MIDI to WAVE converter and player Copyright (C) 1999-2004 Masanao Izumo Copyright (C) 1995 Tuukka Toivonen 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 */ #include #include #ifndef NO_STRING_H #include #else #include #endif #ifdef HAVE_UNISTD_H #include #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" #include "memb.h" #include "zip.h" #include "arc.h" #include "mod.h" #include "wrd.h" #include "tables.h" #include "reverb.h" #include /* rcp.c */ 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; static MidiEventList *evlist, *current_midi_point; static int32 event_count; static MBlockList mempool; static StringTable string_event_strtab; 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(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; } 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_read_track == 1 && current_file_info->format == 1 && strncmp(si, "@KMIDI", 6) == 0) 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; } } int convert_midi_control_change(int chn, int type, int val, MidiEvent *ev_ret) { switch(type) { case 0: type = ME_TONE_BANK_MSB; break; case 1: type = ME_MODULATION_WHEEL; break; case 2: type = ME_BREATH; break; case 4: type = ME_FOOT; break; case 5: type = ME_PORTAMENTO_TIME_MSB; break; case 6: type = ME_DATA_ENTRY_MSB; break; case 7: type = ME_MAINVOLUME; break; case 8: type = ME_BALANCE; break; case 10: type = ME_PAN; break; case 11: type = ME_EXPRESSION; break; case 32: type = ME_TONE_BANK_LSB; break; case 37: type = ME_PORTAMENTO_TIME_LSB; break; case 38: type = ME_DATA_ENTRY_LSB; break; case 64: type = ME_SUSTAIN; break; case 65: type = ME_PORTAMENTO; break; case 66: type = ME_SOSTENUTO; break; case 67: type = ME_SOFT_PEDAL; break; case 68: type = ME_LEGATO_FOOTSWITCH; break; case 69: type = ME_HOLD2; break; case 71: type = ME_HARMONIC_CONTENT; break; case 72: type = ME_RELEASE_TIME; break; case 73: type = ME_ATTACK_TIME; break; case 74: type = ME_BRIGHTNESS; break; case 84: type = ME_PORTAMENTO_CONTROL; break; case 91: type = ME_REVERB_EFFECT; break; case 92: type = ME_TREMOLO_EFFECT; break; case 93: type = ME_CHORUS_EFFECT; break; case 94: type = ME_CELESTE_EFFECT; break; case 95: type = ME_PHASER_EFFECT; break; case 96: type = ME_RPN_INC; break; case 97: type = ME_RPN_DEC; break; case 98: type = ME_NRPN_LSB; break; case 99: type = ME_NRPN_MSB; break; case 100: type = ME_RPN_LSB; break; case 101: type = ME_RPN_MSB; break; case 120: type = ME_ALL_SOUNDS_OFF; break; case 121: type = ME_RESET_CONTROLLERS; break; case 123: type = ME_ALL_NOTES_OFF; break; case 126: type = ME_MONO; break; case 127: type = ME_POLY; break; default: type = -1; break; } 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; } 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 */ 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;icmsg(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 < MAX_CHANNELS; 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> 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 == 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; } if(len >= 8 && val[0] == 0x43 && val[1] == 0x10 && val[2] == 0x4C && val[3] == 0x00 && val[4] == 0x00 && val[5] == 0x7E) { /* XG SYSTEM ON */ SETMIDIEVENT(*ev, 0, ME_RESET, 0, XG_SYSTEM_MODE, SYSEX_TAG); 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<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; 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) { 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 */ 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: 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_TONE_MAP : SC_55_DRUM_MAP); break; case 2: ctl->cmsg(CMSG_INFO, VERB_DEBUG, "(GS ch=%d SC-88 MAP)", ch); mapID[ch] = (!ISDRUMCHANNEL(ch) ? SC_88_TONE_MAP : SC_88_DRUM_MAP); break; case 3: ctl->cmsg(CMSG_INFO, VERB_DEBUG, "(GS ch=%d SC-88Pro MAP)", ch); mapID[ch] = (!ISDRUMCHANNEL(ch) ? SC_88PRO_TONE_MAP : SC_88PRO_DRUM_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_TONE_MAP : SC_8850_DRUM_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: ctl->cmsg(CMSG_INFO, VERB_DEBUG, "(GM2 ch=%d)", ch); mapID[ch] = (!ISDRUMCHANNEL(ch) ? GM2_TONE_MAP : GM2_DRUM_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(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; /* 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; } 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; } 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, "@KMIDI", 6) == 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) fwrite(buff, 1, n, ofp); 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_c = p->time_center * play_mode->rate / 1000.0f; p->sample_l = p->sample_c * p->time_ratio_left; p->sample_r = p->sample_c * p->time_ratio_right; p->level_ratio_c = (double)p->level * (double)p->level_center / (127.0f * 127.0f); p->level_ratio_l = (double)p->level * (double)p->level_left / (127.0f * 127.0f); p->level_ratio_r = (double)p->level * (double)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; 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); } /*! 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. */ void recompute_userdrum(int bank, int prog) { UserDrumset *p; p = get_userdrum(bank, prog); free_tone_bank_element(&drumset[bank]->tone[prog]); if(drumset[p->source_prog]) { if(drumset[p->source_prog]->tone[p->source_note].name) { copy_tone_bank_element(&drumset[bank]->tone[prog], &drumset[p->source_prog]->tone[p->source_note]); 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); } } } /*! 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); }