executor/src/soundfake.c

186 lines
4.6 KiB
C

/* Copyright 1995, 1996 by Abacus Research and
* Development, Inc. All rights reserved.
*/
#if !defined (OMIT_RCSID_STRINGS)
char ROMlib_rcsid_soundfake[] =
"$Id: soundfake.c 63 2004-12-24 18:19:43Z ctm $";
#endif
#include "rsys/common.h"
#include "rsys/sounddriver.h"
#include "rsys/m68kint.h"
#include <TimeMgr.h>
/* This driver "goes through the motions" of playing a sound without
* actually interacting with any sound hardware. The intent is to
* allow systems with and without sound hardware to be indistinguishable
* from the perspective of the program being emulated. For example,
* this driver should cause callbacks to get called at the right times,
* etc.
*/
#define LOGBUFSIZE 11
#define FAKE_BUF_SIZE (1U << LOGBUFSIZE)
#define NUM_FAKE_BUFS 4U
#define MSECS_FOR_BUFFER_TO_PLAY ((FAKE_BUF_SIZE * 1000L) / SND_RATE)
static snd_time t1;
/* # of fake buffers currently enqueued. */
static int num_fake_buffers_enqueued;
static syn68k_addr_t fake_sound_callback;
/* Set to TRUE when we're shutting down, and don't want any new sound
* to creep in.
*/
static boolean_t no_more_sound_p;
static TMTask fake_sound_tm_task;
static boolean_t
sound_fake_works_p (sound_driver_t *s)
{
return !no_more_sound_p;
}
static void
sound_fake_hunger_start (sound_driver_t *s)
{
t1 += FAKE_BUF_SIZE;
}
static struct hunger_info
sound_fake_get_hunger_info (sound_driver_t *s)
{
struct hunger_info info;
info.buf = NULL; /* no buffer at all */
info.bufsize = NUM_FAKE_BUFS * FAKE_BUF_SIZE;
info.t2 = t1 + FAKE_BUF_SIZE;
info.t3 = info.t2 + FAKE_BUF_SIZE;
info.t4 = info.t3;
return info;
}
static void
sound_fake_clear_pending (sound_driver_t *s)
{
fake_sound_tm_task.tmCount = CLC (-1);
num_fake_buffers_enqueued = 0;
}
static void
_note_sound_interrupt (void)
{
if (!no_more_sound_p && num_fake_buffers_enqueued < 2)
sound_callback (0, NULL);
}
/* Installs a time manager task to call back at the requested time. */
static void
set_up_tm_task (void)
{
fake_sound_tm_task.tmAddr = (ProcPtr) CL ((uint32) fake_sound_callback);
InsTime ((QElemPtr) &fake_sound_tm_task);
PrimeTime ((QElemPtr) &fake_sound_tm_task, MSECS_FOR_BUFFER_TO_PLAY);
}
static void
sound_fake_hunger_finish (sound_driver_t *s)
{
++num_fake_buffers_enqueued;
if (num_fake_buffers_enqueued > (int) NUM_FAKE_BUFS)
warning_unexpected ("Too many fake sound buffers got enqueued; this "
"should not be possible.");
/* If we're the only sound enqueued, we need to add a time manager task
* to give us a callback when appropriate.
*/
if (num_fake_buffers_enqueued == 1)
set_up_tm_task ();
_note_sound_interrupt (); /* request even more sound if appropriate. */
}
static syn68k_addr_t
handle_fake_sound_callback (syn68k_addr_t addr, void *junk)
{
if (num_fake_buffers_enqueued > 0)
--num_fake_buffers_enqueued;
if (!no_more_sound_p && num_fake_buffers_enqueued > 0)
{
M68kReg saved_regs[16];
CCRElement saved_ccnz, saved_ccn, saved_ccc, saved_ccv, saved_ccx;
/* Save the 68k registers and cc bits away. */
memcpy (saved_regs, &cpu_state.regs, sizeof saved_regs);
saved_ccnz = cpu_state.ccnz;
saved_ccn = cpu_state.ccn;
saved_ccc = cpu_state.ccc;
saved_ccv = cpu_state.ccv;
saved_ccx = cpu_state.ccx;
set_up_tm_task ();
_note_sound_interrupt ();
memcpy (&cpu_state.regs, saved_regs, sizeof saved_regs);
cpu_state.ccnz = saved_ccnz;
cpu_state.ccn = saved_ccn;
cpu_state.ccc = saved_ccc;
cpu_state.ccv = saved_ccv;
cpu_state.ccx = saved_ccx;
}
return POPADDR ();
}
void
sound_fake_go (sound_driver_t *s)
{
_note_sound_interrupt ();
}
void
sound_fake_stop (sound_driver_t *s)
{
}
static void
sound_fake_shutdown (sound_driver_t *s)
{
no_more_sound_p = TRUE; /* No more callbacks, etc. */
num_fake_buffers_enqueued = 0;
}
static boolean_t
sound_fake_silent_p (sound_driver_t *s)
{
return TRUE;
}
boolean_t
sound_fake_init (sound_driver_t *s)
{
fake_sound_callback = callback_install (handle_fake_sound_callback, NULL);
no_more_sound_p = FALSE;
num_fake_buffers_enqueued = 0;
s->sound_init = sound_fake_init;
s->sound_shutdown = sound_fake_shutdown;
s->sound_works_p = sound_fake_works_p;
s->sound_silent_p = sound_fake_silent_p;
s->sound_hunger_finish = sound_fake_hunger_finish;
s->sound_go = sound_fake_go;
s->sound_stop = sound_fake_stop;
s->sound_hunger_start = sound_fake_hunger_start;
s->sound_get_hunger_info = sound_fake_get_hunger_info;
s->sound_clear_pending = sound_fake_clear_pending;
return TRUE;
}