1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-04 17:49:45 +02:00
2010-01-24 09:19:39 +00:00

323 lines
9.6 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* timebase.c -- management of calls, time bases and heaps for moxc */
/*****************************************************************************
* Change Log
* Date | Change
*-----------+-----------------------------------------------------------------
* 2-Apr-91 | JDW : further changes
* 21-Mar-92 | GWL : abort recovery
* 28-Apr-03 | DM : true->TRUE
*****************************************************************************/
#include "stdio.h"
#include "cext.h"
#include "userio.h"
#include "midifns.h"
#include "timebase.h"
#include "moxc.h"
timebase_type timebase_queue = NULL; /* waiting to run timebase queue */
call_type callfree = NULL; /* free list */
private void fatal();
/****************************************************************************
* timebase_create
* Inputs:
* maxsize is the initial size of the heap
* Outputs:
* returns an initialized timebase_type
****************************************************************************/
timebase_type timebase_create(maxsize)
int maxsize;
{
static char *error_msg = "Out of memory in timebase_create()";
timebase_type base = (timebase_type) memget(sizeof(timebase_node));
if (!base) fatal(error_msg);
base->next = NULL;
base->next_time = MAXTIME;
base->virt_base = 0L;
base->real_base = 0L;
base->rate = 256L;
base->heap_size = 0;
base->heap_max = maxsize;
base->heap = (call_type *) memget(sizeof(call_type) * maxsize);
if (!base->heap) fatal(error_msg);
return base;
}
/****************************************************************************
* callinsert
* Inputs:
* timebase_type base: the time base and heap
* call_type call: the call to insert in heap
* Outputs:
none
* Implementation:
* linear insertion; to be changed to heap
****************************************************************************/
void callinsert(base, call)
timebase_type base;
call_type call;
{
int i;
register call_type *heap = base->heap;
/* handle overflow -- this should never be executed if the user
* gives the right initial heap size
*/
base->heap_size++;
if (base->heap_size >= base->heap_max) {
call_type *new_heap = (call_type *)
memget((base->heap_max << 1) * sizeof(call_type));
int i;
call_type *oldptr;
call_type *newptr;
if (!new_heap) {
gprintf(TRANS, "Out of space, can't allocate new heap\n");
EXIT(1);
}
oldptr = base->heap;
newptr = new_heap;
for (i = base->heap_max; i > 0; i--) *newptr++ = *oldptr++;
memfree((char *) heap, base->heap_max * sizeof(call_type));
base->heap = heap = new_heap;
base->heap_max = (base->heap_max << 1);
}
/* now do the heap insert */
i = base->heap_size;
while (i > 1) {
int parent = i >> 1;
if (heap[parent]->u.e.time < call->u.e.time ||
(heap[parent]->u.e.time == call->u.e.time &&
heap[parent]->u.e.priority <= call->u.e.priority)) break;
heap[i] = heap[parent];
i = parent;
}
heap[i] = call;
/* if next_time might change, reinsert base into queue */
if (heap[1] == call) {
remove_base(base);
insert_base(base);
}
}
/****************************************************************************
* callshow
* Inputs:
* calltype call: the call to show
* Effect:
* prints a description of call
* Assumes:
* call is not null
****************************************************************************/
void callshow(call)
call_type call;
{
int i;
gprintf(TRANS,"address: %lx\n", (ulong)call);
gprintf(TRANS,"time: %ld\n", call->u.e.time);
gprintf(TRANS,"routine: %lx\n", (ulong)call->u.e.routine);
gprintf(TRANS,"parameters:");
for (i = 0; i < MAX_CALL_ARGS; i++) {
gprintf(TRANS, " %d", call->u.e.p.arg[i]);
}
gprintf(TRANS, "\n");
}
/***************************************************************
* fatal
*
* Input : msg: a message to be displayed
* Effect: print message and exit program
***************************************************************/
private void fatal(msg)
char *msg;
{
gprintf(FATAL, msg);
EXIT(1);
}
/***************************************************************
* timebase_free
*
* Input : a time base
* Effect: deallocate the time base
***************************************************************/
void timebase_free(timebase)
timebase_type timebase;
{
remove_base(timebase);
if (timebase->heap) {
memfree((char *) timebase->heap,
(timebase->heap_max * sizeof(call_type)));
}
memfree((char *) timebase, sizeof(timebase_node));
}
/***************************************************************
* insert_base
*
* Input : a time base not in the list
* Effect: insert timebase at the appropriate spot in the list
* computes the next_time field from the top of the heap
***************************************************************/
void insert_base(timebase)
timebase_type timebase;
{
register timebase_type *ptr = &timebase_queue;
register time_type next_time = MAXTIME;
/* compute next_time */
if (timebase->heap_size != 0) {
register call_type call = timebase->heap[1];
/* virt to real calculation */
next_time = (virt_to_real_256(timebase, call->u.e.time) &
0xFFFFFF00) + call->u.e.priority;
/* gprintf(TRANS,
"insert next_time is %ld, vt %ld, rb %ld, vb %ld rt %ld\n",
next_time, timebase->heap[1]->u.e.time,
timebase->real_base, timebase->virt_base, timebase->rate);
*/
}
timebase->next_time = next_time;
if (next_time != MAXTIME) {
/* insert into the list */
while (TRUE) {
if (! *ptr) {
*ptr = timebase;
timebase->next = NULL;
return;
} else if ((*ptr)->next_time >= next_time) {
timebase->next = *ptr;
*ptr = timebase;
return;
} else ptr = &((*ptr)->next);
}
}
}
/***************************************************************
* remove_base
*
* Input : timebase
* Effect: if timebase is in the queue, remove it
***************************************************************/
void remove_base(timebase)
timebase_type timebase;
{
timebase_type *ptr = &timebase_queue;
while (*ptr) {
if (*ptr == timebase) {
*ptr = timebase->next;
return;
} else ptr = &((*ptr)->next);
}
}
/***************************************************************
* remove_call
*
* Input : a timebase -- passed as a global
* Assumes: a_timebase->heap_size > 0
* Returns: the earliest call in the queue
* Effect: removes the earliest call in the queue
***************************************************************/
call_type remove_call(timebase_type a_timebase)
{
register call_type *heap = a_timebase->heap;
call_type result = heap[1];
register call_type large;
int i = 1;
int child = i << 1;;
large = heap[a_timebase->heap_size--];
while (child <= a_timebase->heap_size) {
if (child + 1 <= a_timebase->heap_size) {
if (heap[child + 1]->u.e.time < heap[child]->u.e.time ||
(heap[child + 1]->u.e.time == heap[child]->u.e.time &&
heap[child + 1]->u.e.priority < heap[child]->u.e.priority))
child++;
}
/* child is now the index of the least child */
if (large->u.e.time < heap[child]->u.e.time ||
(large->u.e.time == heap[child]->u.e.time &&
large->u.e.priority <= heap[child]->u.e.priority)) break;
/* swap */
heap[i] = heap[child];
i = child;
child = i << 1;
}
heap[i] = large;
return result;
}
/***************************************************************
* set_rate
*
* Input : timebase and new rate
* Effect: makes the current rate of timebase be rate
***************************************************************/
void set_rate(base, rate)
timebase_type base;
time_type rate;
{
if (base == timebase) base->virt_base = virttime;
else base->virt_base = real_to_virt(base, eventtime);
base->real_base = eventtime;
base->rate = rate;
/* gprintf(TRANS, "new real_base %ld virt_base %ld\n",
base->real_base, base->virt_base);
*/
remove_base(base);
insert_base(base);
}
/***************************************************************
* set_virttime
*
* Input : virtual time
* Effect: makes the current virtual time of timebase be vtime
***************************************************************/
void set_virttime(base, vtime)
timebase_type base;
time_type vtime;
{
base->real_base = eventtime;
base->virt_base = vtime;
if (base == timebase) virttime = vtime;
remove_base(base);
insert_base(base);
}
/***************************************************************
* timebase_use
*
* Input : a timebase to use for scheduling
* Effect: sets up globals: timebase, virttime
***************************************************************/
void timebase_use(base)
register timebase_type base;
{
if (timebase != base) {
timebase = base;
virttime = real_to_virt(base, eventtime);
}
}