📄 rcp.c
字号:
/* TiMidity++ -- MIDI to WAVE converter and player Copyright (C) 1999-2002 Masanao Izumo <mo@goice.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 *//* rcp.c - written by Masanao Izumo <mo@goice.co.jp> */#include <stdio.h>#ifndef NO_STRING_H#include <string.h>#else#include <strings.h>#endif#include "timidity.h"#include "common.h"#include "instrum.h"#include "playmidi.h"#include "readmidi.h"#include "controls.h"#define RCP_MAXCHANNELS 32/* #define RCP_LOOP_CONT_LIMIT 16 */#define RCP_LOOP_TIME_LIMIT 600struct NoteList{ int32 gate; /* Note length */ int ch; /* channel */ int note; /* Note number */ struct NoteList *next; /* next note */};struct RCPNoteTracer{ int gfmt; /*! RCP format (1 if G36 or G18) */ int32 at; /*! current time */ int32 tempo; /*! current tempo (sync with current_tempo) */ int32 tempo_to; /*! tempo gradate to */ int tempo_grade; /*! tempo gradation slope */ int tempo_step; /*! tempo gradation step */ struct NoteList *notes; /*! note list */ MBlockList pool; /*! memory pool for notes */ struct NoteList *freelist; /*! free note list */};#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); }static int read_rcp_track(struct timidity_file *tf, int trackno, int gfmt);static int preprocess_sysex(uint8* ex, int ch, int gt, int vel);/* Note Tracer */static void ntr_init(struct RCPNoteTracer *ntr, int gfmt, int32 at);static void ntr_end(struct RCPNoteTracer *ntr);static void ntr_incr(struct RCPNoteTracer *ntr, int step);static void ntr_note_on(struct RCPNoteTracer *ntr, int ch, int note, int velo, int gate);static void ntr_wait_all_off(struct RCPNoteTracer *ntr);#define ntr_at(ntr) ((ntr).at)#define USER_EXCLUSIVE_LENGTH 24#define MAX_EXCLUSIVE_LENGTH 1024static uint8 user_exclusive_data[8][USER_EXCLUSIVE_LENGTH];static int32 init_tempo;static int32 init_keysig;static int play_bias;#define TEMPO_GRADATION_SKIP 2#define TEMPO_GRADATION_GRADE 600int read_rcp_file(struct timidity_file *tf, char *magic0, char *fn){ char buff[361], *p; int ntrack, timebase1, timebase2, i, len, gfmt; strncpy(buff, magic0, 4); if(tf_read(buff + 4, 1, 32-4, tf) != 32-4) return 1; len = strlen(fn); if(strncmp(buff, "RCM-PC98V2.0(C)COME ON MUSIC", 28) == 0) { /* RCP or R36 */ gfmt = 0; if(check_file_extension(fn, ".r36", 1)) current_file_info->file_type = IS_R36_FILE; else current_file_info->file_type = IS_RCP_FILE; } else if(strncmp(buff, "COME ON MUSIC RECOMPOSER RCP3.0", 31) == 0) { /* G36 or G18 */ gfmt = 1; if(check_file_extension(fn, ".g18", 1)) current_file_info->file_type = IS_G18_FILE; else current_file_info->file_type = IS_G36_FILE; } else return 1; /* title */ if(tf_read(buff, 1, 64, tf) != 64) return 1; if(current_file_info->seq_name == NULL) { buff[64] = '\0'; for(len = 63; len >= 0; len--) { if(buff[len] == ' ') buff[len] = '\0'; else if(buff[len] != '\0') break; } len = SAFE_CONVERT_LENGTH(len + 1); p = (char *)new_segment(&tmpbuffer, len); code_convert(buff, p, len, NULL, NULL); current_file_info->seq_name = (char *)safe_strdup(p); reuse_mblock(&tmpbuffer); } current_file_info->format = 1; if(!gfmt) /* RCP or R36 */ { if(tf_read(buff, 1, 336, tf) != 336) return 1;#ifndef __BORLANDC__ buff[336] = '\0'; for(len = 335; len >= 0; len--) { if(buff[len] == ' ') buff[len] = '\0'; else if(buff[len] != '\0') break; } len = SAFE_CONVERT_LENGTH(len + 1); p = (char *)new_segment(&tmpbuffer, len); code_convert(buff, p, len, NULL, NULL); ctl->cmsg(CMSG_INFO, VERB_VERBOSE, "Memo: %s", p); reuse_mblock(&tmpbuffer);#else buff[336] = '\0'; { char tmp[30]; int i; for(i=0;i<336;i+=28) { strncpy(tmp,buff+i,28); tmp[28] = '\0'; for(len=28; len>=0; len--) { if(tmp[len] == ' ') tmp[len] = '\0'; else if(tmp[len] != '\0') break; } if(tmp[0]=='\0') continue; len = SAFE_CONVERT_LENGTH(len + 1); p = (char *)new_segment(&tmpbuffer, len); code_convert(tmp, p, len, NULL, NULL); ctl->cmsg(CMSG_INFO, VERB_VERBOSE, "Memo: %s", p); reuse_mblock(&tmpbuffer); } }#endif skip(tf, 16); /* 0x40 */ timebase1 = tf_getc(tf); init_tempo = tf_getc(tf); /* tempo */ ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Tempo %d", init_tempo); if(init_tempo < 8 || init_tempo > 250) init_tempo = 120; /* Time Signature: numerator, denominator, Key Signature */ current_file_info->time_sig_n = tf_getc(tf); ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Time signature(n) %d", current_file_info->time_sig_n); current_file_info->time_sig_d = tf_getc(tf); ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Time signature(d) %d", current_file_info->time_sig_d); init_keysig = tf_getc(tf); ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Key signature %d", init_keysig); if (init_keysig < 0 || init_keysig >= 32) init_keysig = 0; play_bias = (int)(signed char)tf_getc(tf); ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Play bias %d", play_bias); if(play_bias < -36 || play_bias > 36) play_bias = 0; skip(tf, 12); /* cm6 */ skip(tf, 4); /* reserved */ skip(tf, 12); /* gsd */ skip(tf, 4); /* reserved */ if((ntrack = tf_getc(tf)) == EOF) return 1; ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Number of tracks %d", ntrack); if(ntrack != 18 && ntrack != 36) ntrack = 18; timebase2 = tf_getc(tf); skip(tf, 14); /* reserved */ skip(tf, 16); /* */ skip(tf, 32 * (14 + 2)); /* rhythm definition */ } else /* G36 or G18 */ { skip(tf, 64); /* reserved */ /* memo */ if(tf_read(buff, 1, 360, tf) != 360) return 1; buff[360] = '\0'; for(len = 359; len >= 0; len--) { if(buff[len] == ' ') buff[len] = '\0'; else if(buff[len] != '\0') break; } len = SAFE_CONVERT_LENGTH(len + 1); p = (char *)new_segment(&tmpbuffer, len); code_convert(buff, p, len, NULL, NULL); ctl->cmsg(CMSG_INFO, VERB_VERBOSE, "Memo: %s", p); reuse_mblock(&tmpbuffer); /* Number of tracks */ ntrack = tf_getc(tf); ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Number of tracks %d", ntrack); if(ntrack != 18 && ntrack != 36) ntrack = 18; skip(tf, 1); timebase1 = tf_getc(tf); timebase2 = tf_getc(tf); init_tempo = tf_getc(tf); /* tempo */ ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Tempo %d", init_tempo); if(init_tempo < 8 || init_tempo > 250) init_tempo = 120; skip(tf, 1); /* ?? */ /* Time Signature: numerator, denominator, Key Signature */ current_file_info->time_sig_n = tf_getc(tf); ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Time signature(n) %d", current_file_info->time_sig_n); current_file_info->time_sig_d = tf_getc(tf); ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Time signature(n) %d", current_file_info->time_sig_d); init_keysig = tf_getc(tf); ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Key signature %d", init_keysig); if (init_keysig < 0 || init_keysig >= 32) init_keysig = 0; play_bias = (int)(signed char)tf_getc(tf); ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Play bias %d", play_bias); if(play_bias < -36 || play_bias > 36) play_bias = 0; skip(tf, 6 + 16 + 112); /* reserved */ skip(tf, 12); /* gsd */ skip(tf, 4); skip(tf, 12); /* gsd */ skip(tf, 4); skip(tf, 12); /* cm6 */ skip(tf, 4); skip(tf, 80); /* reserved */ skip(tf, 128 * (14 + 2)); /* rhythm definition */ } /* SysEx data */ for(i = 0; i < 8; i++) { int mid; skip(tf, 24); /* memo */ if(tf_read(user_exclusive_data[i], 1, USER_EXCLUSIVE_LENGTH, tf) != USER_EXCLUSIVE_LENGTH) return 1; mid = user_exclusive_data[i][0]; if(mid > 0 && mid < 0x7e && (current_file_info->mid == 0 || current_file_info->mid >= 0x7e)) current_file_info->mid = mid; } current_file_info->divisions = (timebase1 | (timebase2 << 8)); ctl->cmsg(CMSG_INFO, VERB_DEBUG, "divisions %d", current_file_info->divisions); current_file_info->format = 1; current_file_info->tracks = ntrack; if(!IS_URL_SEEK_SAFE(tf->url)) if((tf->url = url_cache_open(tf->url, 1)) == NULL) return 1; for(i = 0; i < ntrack; i++) if(read_rcp_track(tf, i, gfmt)) { if(ignore_midi_error) return 0; return 1; } return 0;}static void rcp_tempo_set(int32 at, int32 tempo){ int lo, mid, hi; lo = (tempo & 0xff); mid = ((tempo >> 8) & 0xff); hi = ((tempo >> 16) & 0xff); MIDIEVENT(at, ME_TEMPO, lo, hi, mid);}static int32 rcp_tempo_change(struct RCPNoteTracer *ntr, int a, int b){ int32 tempo; tempo = (int32)((uint32)60000000 * 64 / (init_tempo * a)); /* 6*10^7 / (ini*a/64) */ ntr->tempo_grade = b; if (b != 0) { ntr->tempo_to = tempo; ntr->tempo_step = 0; ntr->tempo_grade *= TEMPO_GRADATION_GRADE * TEMPO_GRADATION_SKIP; tempo = ntr->tempo; /* unchanged */ } else { ntr->tempo = tempo; rcp_tempo_set(ntr_at(*ntr), tempo); } return tempo;}static void rcp_timesig_change(int32 at){ int n, d; n = current_file_info->time_sig_n; d = current_file_info->time_sig_d; MIDIEVENT(at, ME_TIMESIG, 0, n, d);}static void rcp_keysig_change(int32 at, int32 key){ int8 sf, mi; if (key < 8) sf = key, mi = 0; else if (key < 16) sf = 8 - key, mi = 0; else if (key < 24) sf = key - 16, mi = 1; else sf = 24 - key, mi = 1; MIDIEVENT(at, ME_KEYSIG, 0, sf, mi);}static char *rcp_cmd_name(int cmd){ if(cmd < 0x80) { static char name[16]; sprintf(name, "NoteOn %d", cmd); return name; } switch(cmd) { case 0x90: return "UserExclusive0"; case 0x91: return "UserExclusive1"; case 0x92: return "UserExclusive2"; case 0x93: return "UserExclusive3"; case 0x94: return "UserExclusive4"; case 0x95: return "UserExclusive5"; case 0x96: return "UserExclusive6"; case 0x97: return "UserExclusive7"; case 0x98: return "ChannelExclusive"; case 0xc0: return "DX7 function"; case 0xc1: return "DX parameter"; case 0xc2: return "DX RERF"; case 0xc3: return "TX function"; case 0xc5: return "FB-01 P parameter"; case 0xc6: return "FB-01 S System"; case 0xc7: return "TX81Z V VCED"; case 0xc8: return "TX81Z A ACED"; case 0xc9: return "TX81Z P PCED"; case 0xca: return "TX81Z S System"; case 0xcb: return "TX81Z E EFFECT"; case 0xcc: return "DX7-2 R REMOTE SW"; case 0xcd: return "DX7-2 A ACED"; case 0xce: return "DX7-2 P PCED"; case 0xcf: return "TX802 P PCED"; case 0xd0: return "YamahaBase"; case 0xd1: return "YamahaPara"; case 0xd2: return "YamahaDevice"; case 0xd3: return "XGPara"; case 0xdc: return "MKS-7"; case 0xdd: return "RolandBase"; case 0xde: return "RolandPara"; case 0xdf: return "RolandDevice"; case 0xe1: return "BnkLPrg"; case 0xe2: return "Bank&ProgCng"; case 0xe5: return "KeyScan"; case 0xe6: return "ChChange"; case 0xe7: return "TempoChange"; case 0xea: return "ChannelAfterTouch"; case 0xeb: return "ControlChange"; case 0xec: return "ProgChange"; case 0xed: return "AfterTouch"; case 0xee: return "PitchBend"; case 0xf5: return "KeyChange"; case 0xf6: return "Comment"; case 0xf7: return "2ndEvent"; case 0xf8: return "LoopEnd"; case 0xf9: return "LoopStart"; case 0xfc: return "SameMeasure"; case 0xfd: return "MeasureEnd"; case 0xfe: return "EndOfTrack"; } return "Unknown";}static int rcp_parse_sysex_event(int32 at, uint8 *val, int32 len){ MidiEvent ev, evm[260]; int ne, i; if(len == 0) {return 0;} if(parse_sysex_event(val, len, &ev)) { ev.time = at; readmidi_add_event(&ev); } if ((ne = parse_sysex_event_multi(val, len, evm)) > 0) for (i = 0; i < ne; i++) { evm[i].time = at; readmidi_add_event(&evm[i]); } return 0;}#define MAX_STACK_DEPTH 16static int read_rcp_track(struct timidity_file *tf, int trackno, int gfmt){ int32 current_tempo; int size; int ch; long last_point, cmdlen; int key_offset; struct RCPNoteTracer ntr; struct { long start_at; /* loop start time */ long loop_start; /* loop start seek point */ int count; /* loop count */ } stack[MAX_STACK_DEPTH]; int sp; int i, len; uint8 sysex[MAX_EXCLUSIVE_LENGTH]; int roland_base_init = 0; int roland_dev_init = 0; int roland_base_addr0 = 0; int roland_base_addr1 = 0; int roland_device_id = 0x10; int roland_model_id = 0x16; int yamaha_base_init = 0; int yamaha_dev_init = 0; int yamaha_base_addr0 = 0; int yamaha_base_addr1 = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -