📄 moxc.c
字号:
/* MOXC -- a C version of Collinge's MOXIE language *//* Copyright 1989 Carnegie Mellon University *//****************************************************************************** Change Log* Date | Change*-----------+-----------------------------------------------------------------* 31-Dec-85 | Modified for use with midi* 5-Feb-86 | Added m_rest and m_restuntil allowing rests at top level* 28-May-86 | Added command line parsing* 4-Jun-86 | changed keyevent to separate calls for each event type* 10-Jul-86 | put loop in mainscore with prompt to play and replay* 03-Jun-88 | modified for portability (AMIGA) -JCD* 07-Jul-89 | time bases -RBD* 31-Jan-90 | GWL : cleaned up for LATTICE* 30-Jun-90 | RBD : further changes* 2-Apr-91 | JDW : further changes* 4-Mar-91 | GWL : DOS allows odd inst addrs* 10-Oct-94 | nix : posicionador tridimensionale interface* 28-Apr-03 | DM : true->TRUE, false->FALSE*****************************************************************************/#include "switches.h"#ifdef AMIGA#ifdef AZTEC#include "functions.h"#else#include "amiga.h"#endif#include "exec/exec.h"#include "cmtcmd.h"extern long event_mask; /* imported from midifns.c */#endifextern int abort_flag; /*DMH: taken out of ifdef AMIGA for moxcrun*/#include "stdio.h"#include "cext.h"#include "userio.h"#include "midifns.h"#include "cmdline.h"#include "midicode.h"#include "timebase.h"#include "moxc.h"#ifdef AMIGA /*DMH: only AMIGA cares about AMIGA's "proportional controllers"*/#include "prop1.h"#endif#ifdef POSICIONADOR_3D#include "pos3d.h"#include "pos3dbuf.h"#endif /* POSICIONADOR_3D */extern char *app_syntax;/***************************************************************************** IMPORTS:* asciievent(k) user-defined action for terminal input* bendchange(ch, val) user-defined pitch bend handler* ctrlchange(ch, c, val) user-defined control change handler* keydown(ch, p, v) user-defined MIDI note on handler* keyup(ch, p) user-defined MIDI note off handler* mainscore() user-defined first action(s)* musicfns lots of time and io functions* peddown(ch) user-defined pedal down handler* pedup(ch) user-defined pedal up handler* touchchange(ch, val) user-defined aftertouch handler* app_syntax string defining extra command line options** EXPORTS:* * cause(delay, routine, p1, p2, ..., p8)* moxcdone -- set to TRUE to quit* eventtime -- ideallized current time******************************************************************************/#define SAFEMOXC TRUE#define BREAKKEY 0x03int moxcdone; /* flag to halt execution */time_type eventtime; /* time of current call -- used to avoid */ /* timing errors due to finite execution speed */time_type virttime; /* virtual time of current call */timebase_type timebase; /* time base of current call */int mididecode = TRUE; /* whether to decode messages or just call midievent */int debug = FALSE;int moxcdebug = FALSE;time_type next_wakeup;timebase_type default_base;#ifdef AMIGAint pub_port_signal;struct MsgPort pub_port;#endif/****************************************************************************** Routines local to this module*****************************************************************************/private void callrun();private void decode();private void moxcterm();/***************************************************************************** callallcancel* Inputs:* timebase_queue* Effect: * return all calls to free list* Implementation:* If timebase_queue is not empty, there's a pending call. Remove the call* (not necessarily the timebase) and repeat.****************************************************************************/void callallcancel(){ if (moxcdebug) gprintf(GDEBUG, "cancel all calls\n"); while (timebase_queue) { timebase = timebase_queue; timebase_queue = timebase->next; while (timebase->heap_size > 0) { call_free(remove_call(timebase)); } insert_base(timebase); }}/* catchup -- bring current timebase up to date by running its calls *//**/void catchup(){ register call_type call; /* Remember where we're going in virtual time because setting the * rate will also modify timebase->virt_base. We don't want catchup * to stop short: */ time_type target_time = timebase->virt_base; /* remember timebase here because it's possible that a call will do * a timebase_use() and change it: */ register timebase_type my_base = timebase; while (my_base->heap_size != 0 && (my_base->heap[1]->u.e.time < target_time)) { /* eventtime is the real time at which something was scheduled */ eventtime = (my_base->next_time) >> 8; call = remove_call(my_base); virttime = call->u.e.time; (*(call->u.e.routine))(CALLARGS(call)); call_free(call); } /* now that we've possibly pulled events out of the timebase, adjust * the position in the timebase queue (and possibly remove it). */ remove_base(my_base); insert_base(my_base);}/***************************************************************************** cause* Inputs:* delay_type (long) delay: time before this call should occur* int (*routine)(): routine that implements the call* int p1 through p8: parameters to pass to routine* Effect: * builds a call and puts it in pending queue for later scheduling****************************************************************************/#ifndef DOTS_FOR_ARGSvoid cause(delay, routine, p) delay_type delay; int (*routine)(); call_args_node p;#else#include <stdarg.h>void cause(delay_type delay, ...)/* note: the routine parameter is not checked because any routine type can be passed as a parameter, but in the call struct it's an int (*)() */#endif{ register call_type call = call_alloc();#ifdef DOTS_FOR_ARGS va_list xp;#endif if (!call) { gprintf(ERROR, "cause: out of memory\n"); EXIT(1); }#ifdef DOTS_FOR_ARGS call->u.e.time = virttime + delay; call->u.e.priority = 128; /* default priority */ va_start(xp, delay); call->u.e.routine = (int (*)()) va_arg(xp, long *); call->u.e.p = va_arg(xp, call_args_node); va_end(xp);#else call->u.e.time = virttime + delay; call->u.e.priority = 128; /* default priority */ call->u.e.routine = routine; call->u.e.p = p;#endif#ifdef SAFEMOXC if (call->u.e.routine == 0) { gprintf(ERROR,"cause called with NULL routine\n"); EXIT(1);#ifndef DOS /* IBM allows odd addresses */ } else if (((long) call->u.e.routine) & 1) { gprintf(ERROR, "cause called with bad routine address: 0x%lx\n", call->u.e.routine); EXIT(1);#endif }#endif /* put call in default queue */ callinsert(timebase, call); if (moxcdebug) { gprintf(GDEBUG,"(cause) call is pending on timebase 0x%x:\n", timebase); callshow(call); }}/***************************************************************************** causepri* Inputs:* int delay: time before this call should occur* int pri: priority, lowest priority goes first* int (*routine)(): routine that implements the call* int p1 through p8: parameters to pass to routine* Effect: * builds a call and puts it in pending queue for later scheduling****************************************************************************/#ifndef DOTS_FOR_ARGSvoid causepri(delay, pri, routine, p) delay_type delay; int pri; int (*routine)(); call_args_node p;#else/* already included stdarg.h */void causepri(delay_type delay, int pri, ...)#endif{ register call_type call = call_alloc();#ifdef DOTS_FOR_ARGS va_list xp;#endif if (!call) { gprintf(ERROR, "cause: out of memory\n"); EXIT(1); }#ifdef DOTS_FOR_ARGS call->u.e.time = virttime + delay; call->u.e.priority = pri; /* default priority */ va_start(xp, pri); call->u.e.routine = (int (*)()) va_arg(xp, long *); call->u.e.p = va_arg(xp, call_args_node); va_end(xp);#else call->u.e.time = virttime + delay; call->u.e.priority = pri; /* default priority */ call->u.e.routine = routine; call->u.e.p = p;#endif#ifdef SAFEMOXC if (call->u.e.routine == 0) { gprintf(ERROR,"cause called with NULL routine\n"); EXIT(1);#ifndef DOS /* IBM allows odd addresses */ } else if (((long) call->u.e.routine) & 1) { gprintf(ERROR, "causepri called with bad routine address: 0x%lx\n", call->u.e.routine); EXIT(1);#endif }#endif /* put call in default queue */ callinsert(timebase, call); if (moxcdebug) { gprintf(GDEBUG,"(cause) call is pending:"); callshow(call); }}/***************************************************************************** callrun* Inputs:* call_type call: the call to execute* Effect: * executes the previously scheduled call call and deallocates it****************************************************************************/private void callrun(){ call_type call; if (moxcdebug) { gprintf(GDEBUG,"(callrun) running a call: \n"); } /* remove from head of queue */ while (!timebase_queue) gprintf(TRANS, "callrun fatal error\n"); timebase = timebase_queue; timebase_queue = timebase->next; if (debug) gprintf(TRANS, "callrun time %ld\n", timebase->next_time); eventtime = (timebase->next_time) >> 8; /* real time of the call */ /* remove first call from timebase */ call = remove_call(timebase); if (debug) gprintf(TRANS, "callrun call %lx\n", (ulong)call); insert_base(timebase); virttime = call->u.e.time; /* virtual time of the call */ if (moxcdebug) callshow(call); (*(call->u.e.routine))(CALLARGS(call)); call_free(call);}/****************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -