mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-04 17:49:45 +02:00
670 lines
21 KiB
C
670 lines
21 KiB
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 */
|
||
#endif
|
||
extern 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 0x03
|
||
|
||
int 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 AMIGA
|
||
int 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_ARGS
|
||
void 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 */
|
||
#if (__APPLE__ != 1 || __i386__ != 1) /* Intel Mac 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);
|
||
#ifndef GCC_MODEL_CPU
|
||
#define GCC_MODEL_CPU "GCC_MODEL_CPU is undefined for this compilation"
|
||
#endif
|
||
gprintf(ERROR, GCC_MODEL_CPU);
|
||
EXIT(1);
|
||
#endif
|
||
#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_ARGS
|
||
void 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 */
|
||
#if (__APPLE__ != 1 || __i386__ != 1) /* Intel Mac 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
|
||
}
|
||
#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);
|
||
}
|
||
|
||
/****************************************************************************
|
||
* m_restuntil
|
||
* Inputs:
|
||
* int time: call time to rest until
|
||
* Effect:
|
||
* Waits until the specified time has been reached (absolute time).
|
||
* Other "caused" calls will take place during the rest provided
|
||
* this routine is called from "mainscore" (see m_rest description).
|
||
****************************************************************************/
|
||
void m_restuntil(time)
|
||
time_type time;
|
||
{
|
||
time = virt_to_real(timebase, time);
|
||
while(time > gettime()) {
|
||
moxcwait(time);
|
||
}
|
||
}
|
||
|
||
|
||
/****************************************************************************
|
||
* m_rest
|
||
* Inputs:
|
||
* int time: Amount of time to rest
|
||
* Effect:
|
||
* Waits until the amount of time specified has lapsed
|
||
* Assumes:
|
||
* Must not be called from a "caused" routine. Must only be called
|
||
* from "mainscore" or a routine called directly or indirectly from
|
||
* "mainscore" without using "cause".
|
||
****************************************************************************/
|
||
|
||
void m_rest(time)
|
||
time_type time;
|
||
{
|
||
m_restuntil(time + real_to_virt(timebase, gettime()));
|
||
}
|
||
|
||
/****************************************************************************
|
||
* moxcinit
|
||
* Inputs:
|
||
* int argc: number of command line arguments
|
||
* char * argv: command line argument array
|
||
* Effect: initializes moxc system
|
||
****************************************************************************/
|
||
|
||
boolean moxcinit(argc, argv)
|
||
int argc;
|
||
char * argv[];
|
||
{
|
||
meminit();
|
||
io_init();
|
||
#ifdef AMIGA
|
||
pub_port_signal = AllocSignal(-1L);
|
||
pub_port.mp_Node.ln_Type = NT_MSGPORT;
|
||
pub_port.mp_SigBit = pub_port_signal;
|
||
pub_port.mp_SigTask = FindTask(0L);
|
||
pub_port.mp_Flags = PA_SIGNAL;
|
||
pub_port.mp_Node.ln_Name = "CMTcmdport";
|
||
pub_port.mp_MsgList.lh_Head =
|
||
(struct Node *)&pub_port.mp_MsgList.lh_Tail;
|
||
pub_port.mp_MsgList.lh_TailPred =
|
||
(struct Node *)&pub_port.mp_MsgList.lh_Head;
|
||
event_mask |= (1L << pub_port_signal);
|
||
AddPort(&pub_port);
|
||
#endif
|
||
cu_register((cu_fn_type) moxcterm, NULL);
|
||
cl_syntax(midifns_syntax);
|
||
cl_syntax("debug<s>Enable verbose debugging;\
|
||
moxc<s>Enable moxc debug mode;");
|
||
cl_syntax(app_syntax);
|
||
|
||
if (!cl_init(argv, argc)) {
|
||
/* make sure user gets to read the error message(s): */
|
||
gprintf(TRANS, "Type anything to exit...");
|
||
#ifdef DOS
|
||
wait_ascii();
|
||
#else
|
||
ggetchar();
|
||
#endif
|
||
return FALSE;
|
||
}
|
||
debug = cl_switch("debug");
|
||
moxcdebug = cl_switch("moxc");
|
||
timebase = default_base = timebase_create(100);
|
||
default_base->rate = 2560L;
|
||
|
||
eventtime = 0L;
|
||
next_wakeup = MAXTIME;
|
||
musicinit();
|
||
#ifdef POSICIONADOR_3D
|
||
ptInit();
|
||
#endif
|
||
moxcdone = 0;
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
/****************************************************************************
|
||
* moxcwait
|
||
* Input:
|
||
* -1 => wait for next keyboard or midi event or queued event
|
||
* 0 => don't wait
|
||
* T => wait up to T for next keyboard or midi event or queued event
|
||
* (this is used by m_restuntil)
|
||
* Assume: there is work to do (npending > 0 || evqueue) ??
|
||
* Effect: dispatch on user inputs, cause calls
|
||
****************************************************************************/
|
||
|
||
void moxcwait(dateoftimeout)
|
||
time_type dateoftimeout;
|
||
{
|
||
time_type maxtime = dateoftimeout;
|
||
|
||
if (timebase_queue) {
|
||
if ((timebase_queue->next_time >> 8) < maxtime)
|
||
maxtime = (timebase_queue->next_time) >> 8;
|
||
}
|
||
eventwait(maxtime);
|
||
decode();
|
||
}
|
||
|
||
|
||
/****************************************************************************
|
||
* decode
|
||
* Effect: dispatch on user inputs, cause calls
|
||
****************************************************************************/
|
||
|
||
private void decode()
|
||
{
|
||
/* It is important that midi_data is on a word boundary because we
|
||
copy to it by doing a word transfer.
|
||
*/
|
||
byte midi_data[4];
|
||
time_type now;
|
||
byte code;
|
||
char k;
|
||
#ifdef AMIGA
|
||
struct cmd_msg *cmd;
|
||
#endif
|
||
|
||
now = gettime();
|
||
timebase = default_base;
|
||
eventtime = now;
|
||
virttime = 0L;
|
||
|
||
/* gprintf(GDEBUG, "decode at time %ld\n", now); */
|
||
|
||
/**********************************************
|
||
* poll for and decode midi keyboard input
|
||
***********************************************/
|
||
|
||
while (getbuf(FALSE, midi_data)) {
|
||
/* only divide if necessary, divides take 100us on 8MHz 68000: */
|
||
if (virttime == 0)
|
||
virttime = real_to_virt(default_base, now);
|
||
|
||
/* short-circuit midi decoding */
|
||
if (!mididecode) {
|
||
midievent(midi_data);
|
||
continue;
|
||
}
|
||
|
||
code = midi_data[0] & MIDI_CODE_MASK;
|
||
if (code == MIDI_ON_NOTE) {
|
||
if (midi_data[2] == 0) { /* velocity 0 -> note off */
|
||
keyup(1+(midi_data[0] & MIDI_CHN_MASK), midi_data[1]);
|
||
} else {
|
||
keydown((midi_data[0] & MIDI_CHN_MASK)+1,
|
||
midi_data[1], midi_data[2]);
|
||
}
|
||
} else if (code == MIDI_OFF_NOTE) {
|
||
keyup((midi_data[0] & MIDI_CHN_MASK)+1, midi_data[1]);
|
||
} else if (code == MIDI_TOUCH) {
|
||
touchchange((midi_data[0] & MIDI_CHN_MASK)+1,midi_data[1]);
|
||
} else if (code == MIDI_BEND) {
|
||
bendchange((midi_data[0] & MIDI_CHN_MASK)+1,
|
||
midi_data[1] + (midi_data[2] << 7));
|
||
} else if (code == MIDI_CTRL && midi_data[1] == SUSTAIN) {
|
||
if (midi_data[2] == 0) pedup((midi_data[0] & MIDI_CHN_MASK) + 1);
|
||
else peddown((midi_data[0] & MIDI_CHN_MASK) + 1);
|
||
} else if (code == MIDI_CTRL) {
|
||
ctrlchange((midi_data[0] & MIDI_CHN_MASK) + 1,
|
||
midi_data[1], midi_data[2]);
|
||
} else if (code == MIDI_CH_PROGRAM) {
|
||
prgmchange((midi_data[0] & MIDI_CHN_MASK) + 1, midi_data[1] + 1);
|
||
/* think C midi driver doesn't handle sysex the way the Amiga drivers do (yet) */
|
||
#ifndef MACINTOSH
|
||
} else if (code == MIDI_SYSEX) {
|
||
sysex();
|
||
#endif
|
||
}
|
||
}
|
||
|
||
/**********************************************
|
||
* poll for ASCII keyboard input
|
||
***********************************************/
|
||
while (get_ascii(&k)) {
|
||
virttime = real_to_virt(default_base, now);
|
||
asciievent(k);
|
||
/* if user doesn't handle abort char in asciievent,
|
||
we should exit now to avoid an infinite loop */
|
||
if (abort_flag) EXIT(1);
|
||
}
|
||
|
||
#ifdef POSICIONADOR_3D
|
||
/**********************************************
|
||
* poll for posicionador tridimensionale input
|
||
**********************************************/
|
||
{
|
||
pt_value pt_data;
|
||
while (ptGetValue(&pt_data)) {
|
||
/* only divide if necessary, divides take 100us on 8MHz 68000: */
|
||
if (virttime == 0)
|
||
virttime = real_to_virt(default_base, now);
|
||
ptevent(&pt_data);
|
||
}
|
||
}
|
||
#endif /* POSICIONADOR_3D */
|
||
|
||
#ifdef AMIGA
|
||
/**********************************************
|
||
* poll for proportional controller port
|
||
**********************************************/
|
||
if (prop_1_events) {
|
||
int events;
|
||
|
||
Disable();
|
||
events = prop_1_events;
|
||
prop_1_events = 0;
|
||
Enable();
|
||
|
||
if (events & BUTTON_1_RIGHT_CHANGE)
|
||
buttonchange(3, prop_1_right_button);
|
||
if (events & BUTTON_1_LEFT_CHANGE)
|
||
buttonchange(2, prop_1_left_button);
|
||
if (events & PROP_1_LEFT_CHANGE)
|
||
propchange(2, prop_1_left_data);
|
||
if (events & PROP_1_RIGHT_CHANGE)
|
||
propchange(3, prop_1_right_data);
|
||
}
|
||
|
||
/**********************************************
|
||
* poll for input from public command port
|
||
***********************************************/
|
||
|
||
while (cmd = (struct cmd_msg *) GetMsg(&pub_port)) {
|
||
struct symb_descr *desc = &HASHENTRY(lookup(cmd->symbol_name));
|
||
/* gprintf(TRANS, "got %lx (%s) from pub_port\n", cmd, cmd->symbol_name); */
|
||
virttime = real_to_virt(default_base, now);
|
||
if (!desc) {
|
||
gprintf(TRANS, "Error, symbol %s undefined.\n", cmd->symbol_name);
|
||
} else if (desc->symb_type != cmd->symb_type) {
|
||
gprintf(TRANS, "Error, wrong type for symbol %s\n",
|
||
cmd->symbol_name);
|
||
} else if (cmd->symb_type == fn_symb_type) {
|
||
/* gprintf(TRANS, "Calling routine\n"); */
|
||
(*(desc->ptr.routine))(
|
||
(int) cmd->the_args[0], (int) cmd->the_args[1],
|
||
(int) cmd->the_args[2], (int) cmd->the_args[3],
|
||
(int) cmd->the_args[4], (int) cmd->the_args[5],
|
||
(int) cmd->the_args[6], (int) cmd->the_args[7]
|
||
);
|
||
} else if (cmd->symb_type == var_symb_type) {
|
||
*(desc->ptr.intptr) = (int) cmd->the_args[0];
|
||
} else if (cmd->symb_type == vec_symb_type) {
|
||
if (cmd->the_args[0] >= desc->size) {
|
||
gprintf(TRANS, "Error: Vector %s is of size %d\n",
|
||
cmd->symbol_name, desc->size);
|
||
} else {
|
||
(desc->ptr.intptr)[cmd->the_args[0]] = cmd->the_args[1];
|
||
/* gprintf(TRANS, "vec: setting %lx\n",
|
||
&(desc->ptr.intptr)[cmd->the_args[0]]); */
|
||
}
|
||
} else gprintf(TRANS, "Symbol Type Error\n");
|
||
ReplyMsg(&(cmd->msg));
|
||
}
|
||
#endif
|
||
/**********************************************
|
||
* poll for next call in queue
|
||
***********************************************/
|
||
now = (now + 1) << 8; /* shift because next_time is also scaled,
|
||
* add 256 because next_time has added priority */
|
||
if (debug)
|
||
gprintf(TRANS, "now %ld next_time %ld\n",
|
||
now, (timebase_queue ? timebase_queue->next_time : 1234));
|
||
/* give pending events priority, but every 100 events, loop to allow
|
||
input processing (user may want to give a "quit" command) */
|
||
for (k = 0;
|
||
k < 100 && timebase_queue && (now > timebase_queue->next_time);
|
||
k++) {
|
||
callrun();
|
||
}
|
||
/*******************
|
||
* flush text output
|
||
********************/
|
||
#ifdef MACINTOSH_OR_UNIX
|
||
gflush();
|
||
#endif
|
||
}
|
||
|
||
|
||
/****************************************************************************
|
||
* quit
|
||
* Effect: tells moxc to shut down
|
||
****************************************************************************/
|
||
|
||
void quit()
|
||
{
|
||
moxcdone = TRUE;
|
||
}
|
||
|
||
/* moxcrun -- schedule events until done */
|
||
/**/
|
||
void moxcrun()
|
||
{
|
||
moxcdone = FALSE;
|
||
while (!moxcdone && !abort_flag) { /* test for finish */
|
||
if (!timebase_queue) moxcdone = TRUE;
|
||
else moxcwait(MAXTIME); /* do work */
|
||
}
|
||
}
|
||
|
||
/* moxcterm -- clean up after moxcinit */
|
||
/**/
|
||
private void moxcterm()
|
||
{
|
||
#ifdef AMIGA
|
||
FreeSignal((long) pub_port_signal);
|
||
RemPort(&pub_port);
|
||
#endif
|
||
}
|