📄 seq.c
字号:
/* seq.c -- implement adagio scores as abstract data type *//****************************************************************************** Change Log* Date | Change*-----------+-----------------------------------------------------------------* 2-Apr-91 | JDW : further changes* 16-Feb-92 | GWL : use reg_timebase in seq_play()* 28-Apr-03 | DM : false->FALSE, true->TRUE, portability changes* 19-May-03 | RBD : no longer assume seq->current remains untouched between * | note inserts*****************************************************************************/#include "stdio.h"#include "cext.h"#include "userio.h"#include "midicode.h"#include "midifns.h"#include "timebase.h"#include "moxc.h"#include "seq.h"#include "string.h"extern int moxcdebug;extern timebase_type default_base;boolean seq_print = FALSE; /* debugging print switch */seq_type sequence; /* this is a global to be accessed by routines called * from the sequence *//* clock state: */time_type clock_ticksize; /* millisec per tick shifted 16 bits */boolean clock_running = FALSE; /* TRUE if clock is running */boolean external_midi_clock = FALSE;boolean suppress_midi_clock = FALSE;private void insert_event();private void process_event();private char *chunk_alloc();private void clock_tick();private void ramp_event(seq_type seq, event_type event, unsigned int value, unsigned int to_value, int increment, time_type step, int n);/*private*/ void send_macro();/* chunk_alloc -- allocate data for a sequence *//* * NOTE: This assumes one chunk is already allocated. * The first chunk holds shared sequence information in * the info struct, and by convention this is always in * the first chunk. */private char *chunk_alloc(seq_type seq, int size){ chunk_type chunk = seq->chunklist->u.info.last_chunk; /* gprintf(TRANS, "chunk_alloc: seq %lx size %d\n", seq, size); */ if (size & 1) size++; /* make it even */ if (chunk->free + size >= CHUNK_SIZE) { chunk_type new_chunk = chunk_create(FALSE); if (!chunk) { gprintf(FATAL, "Out of memory while reading seq\n"); return NULL; } /* add new_chunk to chunk chain */ seq->chunklist->u.info.last_chunk = new_chunk; chunk->next = new_chunk; chunk = new_chunk; } chunk->free += size; return &(chunk->u.data[chunk->free - size]);}/* chunk_create -- create a new chunk for seq data *//* * If this is the first chunk, set first_flag to reserve * space for the info structure. */chunk_type chunk_create(boolean first_flag){ chunk_type result = (chunk_type) memget(sizeof(chunk_node)); if (result) { result->next = NULL; result->u.info.refcount = 1; /* pre-initialize for caller */ result->free = 0; if (first_flag) { result->free = sizeof(struct info_struct); result->u.info.last_chunk = result; result->u.info.dictionary = NULL; result->u.info.eventlist = NULL; result->u.info.ctrlcount = 0; result->u.info.notecount = 0; result->u.info.duration = 0; result->u.info.used_mask = 0; } } /* gprintf(TRANS, "chunk_create: got %lx (size %d)\n", */ /* result, sizeof(chunk_node)); */ return result;}/* clock_tick -- advance the clock and send a tick *//**/private void clock_tick(seq, fraction) seq_type seq; time_type fraction;{ int delay; fraction += clock_ticksize; delay = fraction >> 16; fraction &= 0xFFFF; if (seq->runflag && clock_ticksize && seq->note_enable) { midi_clock(); cause((delay_type)delay, clock_tick, seq, fraction); } else { clock_running = FALSE; midi_stop(); midi_clock(); /* stop takes effect on next clock, so provide one */ }}private void cycle(seq) seq_type seq;{ seq_reset(seq); seq_play(seq);}/***************************************************************************** event_create* Inputs:* seq_type seq: the seq to hold the event* int size: the size of the event in bytes* time_type etime: the time of the event* int eline: the line number of the event* Returns:* event_type: a new event structure or* NULL if there is not enough memory left* Effect:* allocates memory from the chunk, then heap as needed* Implementation:* to reduce the per block storage overhead, we allocate memory in* large chunks and do our own allocation. Allocate from first* chunk first. If full, allocate a new chunk.* WARNING: this implementation assumes that individual events are never freed!!****************************************************************************/private event_type event_create(seq, size, etime, eline) seq_type seq; int size; time_type etime; int eline;{ event_type result = (event_type) chunk_alloc(seq, size); if (result) { result->ntime = etime; result->nline = eline; /* since we know the time, we can insert now: */ insert_event(seq, result); seq_duration(seq) = MAX(seq_duration(seq), etime); } return result;}/* insert_call -- add a call event to the seq *//**/event_type insert_call(seq, ctime, cline, voice, addr, value, n) seq_type seq; time_type ctime; int cline; int voice; int (*addr)(); long value[SEQ_MAX_PARMS]; int n;{ int i; register event_type event = event_create(seq, callsize, ctime, cline); if (seq_print) { gprintf(TRANS, "call(%lx): time %ld, line %d, voice %d, fn %lx,\n\tvalues:", event, ctime, cline, voice, addr); for (i = 0; i < n; i++) gprintf(TRANS, " %ld", value[i]); gprintf(TRANS, "\n"); } if (event) { seq_used_mask(seq) |= 1 << (voice - 1); event->nvoice = ctrl_voice(ESC_CTRL, voice); event->value = CALL_VALUE; event->u.call.routine = addr; /* save the arguments */ for (i = 0; i < n; i++) event->u.call.args.a[i] = value[i]; seq_ctrlcount(seq)++; } return event; } /* insert_clock -- add a clock cmd to the seq *//**/event_type insert_clock(seq, ctime, cline, ticksize) seq_type seq; time_type ctime; int cline; time_type ticksize;{ register event_type event = event_create(seq, clocksize, ctime, cline); if (seq_print) { gprintf(TRANS, "clock(%lx): time %ld, line %d\n", event, ctime, cline); } if (event) { event->nvoice = ctrl_voice(ESC_CTRL, 1); event->value = CLOCK_VALUE; event->u.clock.ticksize = ticksize; seq_ctrlcount(seq)++; } return event;}/* insert_ctrl -- add a control to the seq *//**/event_type insert_ctrl(seq, ctime, cline, ctrl, voice, value) seq_type seq; time_type ctime; int cline; int ctrl; int voice; int value;{ register event_type event = event_create(seq, ctrlsize, ctime, cline); if (seq_print) { gprintf(TRANS, "ctrl(%lx): time %ld, line %d, ctrl %d, voice %d, value %d\n", event, ctime, cline, ctrl, voice, value); } if (event) { seq_used_mask(seq) |= 1 << (voice - 1); event->nvoice = ctrl_voice(ctrl, voice); event->value = value; seq_ctrlcount(seq)++; } return event;}/* insert_ctrlramp -- add a control ramp event to the seq *//**/event_type insert_ctrlramp(seq, rtime, rline, voice, step, dur, ctrl, v1, v2) seq_type seq; time_type rtime; int rline; int voice; time_type step; time_type dur; int ctrl; int v1, v2;{ register event_type event = event_create(seq, ctrlrampsize, rtime, rline); if (seq_print) { gprintf(TRANS, "ctrlramp(%lx): time %ld, line %d, step %ld, dur %ld, ctrl %d, voice %d\n", event, rtime, rline, step, dur, ctrl, voice); gprintf(TRANS, "\tfrom %d to %d\n", v1, v2); } if (event) { seq_used_mask(seq) |= 1 << (voice - 1); event->nvoice = ctrl_voice(ESC_CTRL, voice); event->value = CTRLRAMP_VALUE; if (dur <= 0) dur = 1L; /* don't allow zero duration */ event->u.ramp.dur = dur; event->u.ramp.ctrl = ctrl; if (step <= 0) step = 1; /* don't allow zero step size */ event->u.ramp.step = (short) step; event->u.ramp.u.ctrl.from_value = v1; event->u.ramp.u.ctrl.to_value = v2; seq_ctrlcount(seq)++; seq_duration(seq) = MAX(seq_duration(seq), rtime + dur); } return event;}/* insert_def -- add a definition to the dictionary *//**/def_type insert_def(seq, symbol, definition, deflen) seq_type seq; char *symbol; unsigned char *definition; int deflen;{ int i; def_type defn = (def_type) chunk_alloc(seq, sizeof(def_node)); defn->symbol = chunk_alloc(seq, strlen(symbol) + 1); defn->definition = (unsigned char *) chunk_alloc(seq, deflen); strcpy(defn->symbol, symbol); for (i = 0; i < deflen; i++) { defn->definition[i] = definition[i]; } defn->next = seq_dictionary(seq); seq_dictionary(seq) = defn; if (seq_print) { gprintf(TRANS, "def(%ld): symbol %s defn \n", defn, symbol); for (i = 0; i < deflen; i++) gprintf(TRANS, "%x", definition[i]); gprintf(TRANS, "\n"); } return defn;}/* insert_deframp -- add a def ramp event to the seq *//**/event_type insert_deframp(seq, rtime, rline, voice, step, dur, def, nparms, parms, parm_num, to_value) seq_type seq; time_type rtime; int rline; int voice; time_type step; time_type dur; def_type def; int nparms; /* number of parameters for macro */ short parms[]; /* actual parameter vector */ int parm_num; /* which of the actual parameters to ramp */ int to_value; /* final destination of ramp */{ register event_type event = event_create(seq, deframpsize, rtime, rline); if (seq_print) { int i; gprintf(TRANS, "deframp(%ld): time %ld, line %d, voice %d, step %ld, dur %ld\n", event, rtime, rline, voice, step, dur); gprintf(TRANS, "def %ld, parms"); for (i = 0; i < nparms; i++) gprintf(TRANS, " %d", parms[i]); gprintf(TRANS, "parm_num %d to %d\n", parm_num, to_value); } if (event) { int i; seq_used_mask(seq) |= 1 << (voice - 1); event->nvoice = ctrl_voice(ESC_CTRL, voice); event->value = DEFRAMP_VALUE; if (dur <= 0) dur = 1L; /* don't allow zero duration */ event->u.ramp.dur = dur; event->u.ramp.ctrl = 0; if (step <= 0) step = 1; /* don't allow zero step size */ event->u.ramp.step = (short) step; event->u.ramp.u.def.definition = def->definition; for (i = 0; i < nmacroparms; i++) { event->u.ramp.u.def.parameter[i] = (i < nparms ? parms[i] : 0); } event->u.ramp.u.def.parm_num = parm_num; event->u.ramp.u.def.to_value = to_value; seq_ctrlcount(seq)++; seq_duration(seq) = MAX(seq_duration(seq), rtime + dur); } return event;}/***************************************************************************** insert_event* Inputs:* seq_type seq: where to put the event* event_type event: the event to insert* Effect:* inserts event into the event list* NOTE: it is inserted *after* previously inserted events with the same time* Implementation:* adagio files often contain many independent voices. Although each voice* consists of events in sequence, the voices need not be inter-twined in* the input file. Rather, all the events of voice 1 appear followed by all* the events of voice 2, and so forth. As phase one merges these event* sequences, it must make many passes over an increasingly long list of* events: expensive if we always start from the beginning of the list!* we can exploit the fact that each voice is sequential by starting the* search for the proper point of insertion at the last event inserted.* the variable "last_event" is used to remember this hint. We could* also snapshot "last_event" in "ref_event" when a !tempo or !rate* command occurs as another hint, but we don't.****************************************************************************/private void insert_event(seq, event) seq_type seq; register event_type event;{ event_type *evlptr = &(seq_eventlist(seq)); if ((*evlptr == NULL) || (event->ntime < (*evlptr)->ntime)) { /* insert at the head of the list */ event->next = *evlptr; *evlptr = event; seq->current = event; } else { /* insert somewhere after the head of the list * do not assume: current is not NULL. Although we always leave * it set, the client may access the sequence before the next * insert. */ register event_type previous;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -