📄 seqmread.c
字号:
/* * seqmread.c * * Convert a MIDI file to a seq. *//* Copyright 1989 Carnegie Mellon University *//****************************************************************************** Change Log* Date | who : Change*-----------+-----------------------------------------------------------------* 17-Feb-92 | GWL : only one stdio.h* : fix to satisfy compiler: void returns, time_type giotime(), int filegetc()*****************************************************************************/#include "switches.h"#include "stdio.h"#include "cext.h"#include "cmdline.h"#include "midifns.h" /* to get time_type */#include "timebase.h"#include "moxc.h" /* to get debug declared */#include "seq.h"#include "seqread.h" /* to get scale */#include "seqmread.h"#include "userio.h"#include "ctype.h"#include "midifile.h"#include "tempomap.h"int filegetc();void initfuncs();void prtime();void snding_free();typedef struct snding_struct { struct snding_struct *next; event_type event_ptr; int pitch; int channel;} snding_node, *snding_type;#define snding_alloc() (snding_type) memget(sizeof(snding_node))#define snding_free(s) memfree(s, sizeof(snding_node))snding_type snding_list = NULL;tempomap_type the_tempomap;event_type initial_clock; /* remember the first clock event */long prev_ticksize; /* remember the previous ticksize */int sysex_id = 0;void smf_noteoff();void smf_error();void smf_header();void smf_trackstart();void smf_trackend();void smf_noteon();void smf_pressure();void smf_parameter();void smf_pitchbend();void smf_program();void smf_chanpressure();void smf_sysex();void smf_metamisc();void smf_metaseq();void smf_metaeot();void smf_timesig();void smf_smpte();void smf_tempo();void smf_keysig();void smf_metaspecial();void smf_metatext();void smf_arbitrary();private seq_type the_score;static FILE *F;int filegetc(){/* int temp = getc(F); printf(" %x ", temp);*/ return(int)(getc(F));}void seq_read_smf(seq, fp) seq_type seq; FILE *fp;{ F = fp; initfuncs(); sysex_id = 0; /* sysex in seq has to correspond to a symbol */ the_score = seq; /* current sequence is a global within this module */ if (!seq) return; the_tempomap = tempomap_create(); /* insert an initial clock to correspond to the default midifile tempo (tempomap_create creates a corresponding initial entry in the tempomap) (see smf_tempo for explanation of the scale() call) */ initial_clock = insert_clock(the_score, 0L, 0, 500L << 16); /* scale(24 * 500000, 1 << 16, 24000) */ if (!the_tempomap) return; Mf_getc = filegetc; midifile(); /* fmac_close(F); -- do not close the file because the caller might try to * close it (in fact XLISP insists on closing it as a side effect of * garbage collection. */ gprintf(TRANS, "\nLoaded Midi file with %ld note(s), %ld ctrl(s).\n\n", seq_notecount(seq), seq_ctrlcount(seq)); seq_reset(seq); while (snding_list) { snding_type snding = snding_list; snding_list = snding_list->next; gprintf(TRANS, "Note-on (key %d, chan %d) has no matching noteoff\n", snding->pitch, snding->channel + 1); snding_free(snding); } tempomap_free(the_tempomap);}/* gio_time -- get the time in millisec for Adagio *//* * Since Adagio times are (in their precise form) 1/256 ms, we want * a similar time for midifiles, whose natural unit would be microseconds. * We'll shift the microsecond time by 2 to get 1/250 ms = 4 us units * and convert using the scale function when necessary. * Real time is the time of the last tempo change (last_tempo_time) * which is in 4us units + elapsed time. * Elapsed time is the elapsed beats times the beat duration. * Elapsed beats is Mf_currtime - last_tempo_beat. * Beat duration is the specified tempo / division, where specified tempo * is in microseconds, and division is parts per quarternote. */unsigned long divisions = 24L;time_type gio_time(){ return (tempomap_lookup(the_tempomap, Mf_currtime) + 125L) / 250L;}void smf_header(format,ntrks,division){/* gprintf(TRANS, "Header format=%d ntrks=%d division=%d\n", format,ntrks,division); */ if (format > 1) gprintf(TRANS, "Warning: format %d midi file may not work.\n", format); divisions = division; /* adjust the initial tempochange */ the_tempomap->entries->tempo = 500000L / division;}void smf_trackstart(){/* gprintf(TRANS, "Track start\n"); */}void smf_trackend(){/* gprintf(TRANS, "Track end\n"); */}void smf_noteon(chan,pitch,vol){ snding_type snding; if (vol == 0) { /* convert to a noteoff */ smf_noteoff(chan, pitch, 0); return; }/* prtime(); gprintf(TRANS, "Note on, chan=%d pitch=%d vol=%d\n",chan+1,pitch,vol);*/ /* get ready to remember the sounding note */ snding = snding_alloc(); snding->next = snding_list; snding_list = snding; /* enter an event into score and remember it */ snding->event_ptr = insert_note(the_score, gio_time(), 0, chan + 1, pitch, 0L, vol); snding->pitch = pitch; snding->channel = chan;}void smf_noteoff(chan,pitch,vol){ snding_type *snding_ptr; register snding_type snding;/* prtime(); gprintf(TRANS, "Note off, chan=%d pitch=%d vol=%d\n",chan+1,pitch,vol);*/ /* search for the snding record */ for (snding_ptr = &snding_list; (snding = *snding_ptr) && ((snding->pitch != pitch) || (snding->channel != chan)); snding_ptr = &(snding->next)) /* printf("* search *\n") */; if (!snding) { gprintf(TRANS, "Note off %d, channel %d ignored: no note on\n", pitch, chan + 1); } else { event_type event = snding->event_ptr; event->u.note.ndur += (gio_time() - event->ntime) << 8; /* free the snding record */ *snding_ptr = snding->next; snding_free(snding); }}void smf_pressure(chan,pitch,press){ prtime(); gprintf(TRANS, "Pressure, chan=%d pitch=%d press=%d (IGNORED)\n", chan + 1, pitch, press);}void smf_parameter(chan,control,value){ int ctrl = 0;/* prtime(); gprintf(TRANS, "Parameter, chan=%d c1=%d c2=%d\n",chan+1,control,value); */ /* see if the control is one of the standard Adagio controls that can be encoded in a special way. If not, ctrl remains at zero. */ switch (control) { case PORTASWITCH: ctrl = PSWITCH_CTRL; break; case MODWHEEL: ctrl = MODWHEEL_CTRL; break; case VOLUME: ctrl = VOLUME_CTRL; break; } if (ctrl) /* then do special ctrl insert and save storage */ insert_ctrl(the_score, gio_time(), 0, ctrl, chan + 1, value); else insert_macctrl(the_score, gio_time(), 0, control, chan + 1, value);} /* smf_pitchbend -- handle a pitch bend event *//* * NOTE: the midifile code from Tim Thompson has the msb and lsb bytes swapped. * Thus the parameter msb is really the low order byte and lsb is high order. */void smf_pitchbend(chan,msb,lsb){/* prtime(); gprintf(TRANS, "Pitchbend, chan=%d msb=%d lsb=%d\n",chan+1,msb,lsb); */ insert_ctrl(the_score, gio_time(), 0, BEND_CTRL, chan + 1, ((lsb << 7) + msb) >> 6);}void smf_program(chan,program){/* prtime(); gprintf(TRANS, "Program, chan=%d program=%d\n",chan+1,program); */ insert_ctrl(the_score, gio_time(), 0, PROGRAM_CTRL, chan + 1, program);}void smf_chanpressure(chan,press){/* prtime(); gprintf(TRANS, "Channel pressure, chan=%d pressure=%d\n",chan+1,press); */ insert_ctrl(the_score, gio_time(), 0, TOUCH_CTRL, chan + 1, press);}void smf_sysex(leng,mess)int leng;char *mess;{ char symb[10]; def_type defn; int i; sprintf(symb, "X%d", sysex_id++); if (leng > 255) { gprintf(TRANS, "sysex too long (%d bytes), ignored\n", leng - 2); return; } /* need to end up with a prefix of [0][length], so add 2 to length; note that this will copy past the end of the message -- this is slightly dangerous and definitely crufty: */ defn = insert_def(the_score, symb, (unsigned char *) mess, leng + 2); /* now fix up the definition by inserting the prefix bytes: */ for (i = leng + 1; i > 1; i--) defn->definition[i] = defn->definition[i - 2]; defn->definition[0] = 0; defn->definition[1] = leng; insert_macro(the_score, gio_time(), 0, defn, 1, 0, NULL);/* prtime(); gprintf(TRANS, "Sysex, leng=%d (IGNORED)\n",leng); */}void smf_metamisc(type,leng,mess)char *mess;{ prtime(); gprintf(TRANS, "Meta event, unrecognized, type=0x%02x leng=%d (IGNORED)\n", type, leng);}void smf_metaspecial(type,leng,mess)char *mess;{ prtime(); gprintf(TRANS, "Meta event, sequencer-specific, type=0x%02x leng=%d (IGNORED)\n", type, leng);}void smf_metatext(type,leng,mess)char *mess;{ static char *ttype[] = { NULL, "Text Event", /* type=0x01 */ "Copyright Notice", /* type=0x02 */ "Sequence/Track Name", "Instrument Name", /* ... */ "Lyric", "Marker", "Cue Point", /* type=0x07 */ "Unrecognized" }; int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1; if ( type < 1 || type > unrecognized ) type = unrecognized;}void smf_metaseq(num){ prtime(); gprintf(TRANS, "Meta event, sequence number = %d (IGNORED)\n",num);}void smf_metaeot(){/* prtime(); gprintf(TRANS, "Meta event, end of track\n"); */}void smf_keysig(sf,mi){/* prtime(); gprintf(TRANS, "Key signature, sharp/flats=%d minor=%d\n",sf,mi); */}/* smf_tempo -- handle a midifile tempo change *//* * NOTE: if divisions is positive, it gives time units per quarter, and * tempo is microsec per division. The product is microsec per quarter. * To convert to ticksize (parameter to insert_clock), we divide by 24*1000 * to get units of millisec and 24ths of quarter notes. insert_clock * expects this to have a 16 bit fractional part. */void smf_tempo(tempo)long tempo;{ time_type ctime = gio_time(); long ticksize = scale(tempo, 1024L, 375L);/* (tempo / 24000) << 16; microsec/clock converted to ms/quarter, shifted 16*//* prtime(); gprintf(TRANS, "Tempo, microseconds-per-MIDI-quarter-note = %ld\n",tempo);*/ tempomap_insert(the_tempomap, Mf_currtime, tempo / divisions); if (ctime == 0) { /* we already have a clock event at t=0 -> fix it */ initial_clock->u.clock.ticksize = ticksize; } else { /* we need a new one */ /* NOTE: after the first clock, insert clock events 1/2 tick early to make sure ticksize is set before clock_tick() wakes up and reads it. */ insert_clock(the_score, ctime - (prev_ticksize >> 17), 0, ticksize); prev_ticksize = ticksize; }}void smf_timesig(nn,dd,cc,bb){/* int denom = 1; while ( dd-- > 0 ) denom *= 2; prtime(); gprintf(TRANS, "Time signature=%d/%d MIDI-clocks/click=%d 32nd-notes/24-MIDI-clocks=%d\n", nn,denom,cc,bb); */}void smf_smpte(hr,mn,se,fr,ff){ prtime(); gprintf(TRANS, "SMPTE, hour=%d minute=%d second=%d frame=%d fract-frame=%d (IGNORED)\n", hr, mn, se, fr, ff);}void smf_arbitrary(leng,mess)char *mess;{ prtime(); gprintf(TRANS, "Arbitrary bytes, leng=%d (IGNORED)\n",leng);}void smf_error(msg) char *msg;{ gprintf(ERROR, msg);}void prtime(){ gprintf(TRANS, "Time=%ld/%ld ",Mf_currtime, gio_time());}void initfuncs(){ Mf_error = smf_error; Mf_header = smf_header; Mf_starttrack = smf_trackstart; Mf_endtrack = smf_trackend; Mf_on = smf_noteon; Mf_off = smf_noteoff; Mf_pressure = smf_pressure; Mf_controller = smf_parameter; Mf_pitchbend = smf_pitchbend; Mf_program = smf_program; Mf_chanpressure = smf_chanpressure; Mf_sysex = smf_sysex; Mf_metamisc = smf_metamisc; Mf_seqnum = smf_metaseq; Mf_eot = smf_metaeot; Mf_timesig = smf_timesig; Mf_smpte = smf_smpte; Mf_tempo = smf_tempo; Mf_keysig = smf_keysig; Mf_sqspecific = smf_metaspecial; Mf_text = smf_metatext; Mf_arbitrary = smf_arbitrary;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -