📄 readmidi.c
字号:
/* TiMidity++ -- MIDI to WAVE converter and player Copyright (C) 1999-2004 Masanao Izumo <iz@onicos.co.jp> Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/#ifdef HAVE_CONFIG_H#include "config.h"#endif /* HAVE_CONFIG_H */#include <stdio.h>#include <stdlib.h>#ifndef NO_STRING_H#include <string.h>#else#include <strings.h>#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif /* HAVE_UNISTD_H */#include "timidity.h"#include "common.h"#include "instrum.h"#include "playmidi.h"#include "readmidi.h"#include "output.h"#include "controls.h"#include "strtab.h"#include "memb.h"#include "zip.h"#include "arc.h"#include "mod.h"#include "wrd.h"#include "tables.h"#include "reverb.h"#include <math.h>/* 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_EVENTint opt_trace_text_meta_event = 1;#elseint 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -