File:  [UNIX Amiga Emulator] / uae / src / os.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:38:55 2018 UTC (8 years, 3 months ago) by root
Branches: MAIN, BSchmidt
CVS tags: uae068, HEAD
uae-0.6.8

 /* 
  * UAE - The Un*x Amiga Emulator
  * 
  * OS specific functions
  * 
  * (c) 1995 Bernd Schmidt
  * (c) 1996 Marcus Sundberg
  */

#include "sysconfig.h"
#include "sysdeps.h"

#include "config.h"
#include "options.h"
#include "memory.h"
#include "custom.h"
#include "os.h"
#include "events.h"

#ifndef DONT_WANT_SOUND
static void sample_ulaw_handler(void);
#endif

int joystickpresent = 0;

#ifdef HAVE_LINUX_JOYSTICK_H

static int js0;

struct JS_DATA_TYPE jscal;

void read_joystick(UWORD *dir, int *button)
{
    static int minx = MAXINT, maxx = MININT,
               miny = MAXINT, maxy = MININT;
    int left = 0, right = 0, top = 0, bot = 0;
    struct JS_DATA_TYPE buffer;
    int len;
    
    *dir = 0;
    *button = 0;
    if (!joystickpresent)
    	return;
    
    len = read(js0, &buffer, sizeof(buffer));
    if (len != sizeof(buffer)) 
    	return;
    
    if (buffer.x < minx) minx = buffer.x;
    if (buffer.y < miny) miny = buffer.y;
    if (buffer.x > maxx) maxx = buffer.x;
    if (buffer.y > maxy) maxy = buffer.y;
    
    if (buffer.x < (minx + (maxx-minx)/3))
    	left = 1;
    else if (buffer.x > (minx + 2*(maxx-minx)/3))
    	right = 1;

    if (buffer.y < (miny + (maxy-miny)/3))
    	top = 1;
    else if (buffer.y > (miny + 2*(maxy-miny)/3))
    	bot = 1;
    	
    if (left) top = !top;
    if (right) bot = !bot;
    *dir = bot | (right << 1) | (top << 8) | (left << 9);
    *button = (buffer.buttons & 3) != 0;
}

void init_joystick(void)
{
    js0 = open("/dev/js0", O_RDONLY);
    if (js0 < 0)
    	return;
    joystickpresent = 1;
}

void close_joystick(void)
{
    if (joystickpresent)
	close(js0);
}

#elif defined(__DOS__)

void read_joystick(UWORD *dir, int *button)
{
    static int minx = MAXINT, maxx = MININT,
	       miny = MAXINT, maxy = MININT;
    int left = 0, right = 0, top = 0, bot = 0;
    char JoyPort;
    int laps, JoyX, JoyY;

    *dir = 0;
    *button = 0;
    if (!joystickpresent)
	return;

    JoyX = 0;
    JoyY = 0;
    laps = 0;
    __asm__ __volatile__("cli");
    outportb(0x201, 0xff);
    do {
	JoyPort = inportb(0x201);
	JoyX = JoyX + (JoyPort & 1);
	JoyY = JoyY + ((JoyPort & 2) >> 1);
	laps++;
    } while(((JoyPort & 3) != 0) && (laps != 65535));
    __asm__ __volatile__("sti");

    if (JoyX < minx) minx = JoyX;
    if (JoyY < miny) miny = JoyY;
    if (JoyX > maxx) maxx = JoyX;
    if (JoyY > maxy) maxy = JoyY;

    if (JoyX < (minx + (maxx-minx)/3))
	left = 1;
    else if (JoyX > (minx + 2*(maxx-minx)/3))
	right = 1;

    if (JoyY < (miny + (maxy-miny)/3))
	top = 1;
    else if (JoyY > (miny + 2*(maxy-miny)/3))
	bot = 1;

    if (left) top = !top;
    if (right) bot = !bot;
    *dir = bot | (right << 1) | (top << 8) | (left << 9);
    *button = ((~JoyPort) & 48) != 0;
}

void init_joystick(void)
{
    int laps = 0;
    char JoyPort;
    __asm__ __volatile__("cli");
    outportb(0x201, 0xff);
    do {
	JoyPort = inportb(0x201);
	laps++;
    } while(((JoyPort & 3) != 0) && (laps != 65535));
    __asm__ __volatile__("sti");
    if (laps != 65535)
	joystickpresent = 1;
}

void close_joystick(void)
{
}

#elif defined(AMIGA)

#define EXEC_TYPES_H /* exec/types.h has trouble as LONG, ULONG, etc. */
typedef void *APTR;  /* are already defined. This avoid the trouble.  */
typedef char *STRPTR;
typedef float *FLOAT;
typedef int BOOL;
#define VOID void

#include <hardware/custom.h>
#include <hardware/cia.h>

#define CIAAPRA 0xBFE001 
#define CUSTOM  0xDFF000

static struct Custom *custom= (struct Custom*) CUSTOM;
static struct CIA *cia = (struct CIA *) CIAAPRA;

void read_joystick(UWORD *dir, int *button)
{
    int bot, right, top, left, joy,fire;
    
    joy   = custom->joy1dat;
    fire  = !( cia->ciapra & 0x0080 ) ? 1 : 0;

    right = (joy & 0x0002) ? 1 : 0;
    left  = (joy & 0x0200) ? 1 : 0;
    bot   = (joy & 0x0001) ? 1 : 0;
    top   = (joy & 0x0100) ? 1 : 0;
    
    *button = fire;
    *dir = bot | (right << 1) | (top << 8) | (left << 9);
}

void init_joystick(void)
{
}

void close_joystick(void)
{
}

#elif !defined(__BEOS__)

void read_joystick(UWORD *dir, int *button)
{
    *dir = 0;
    *button = 0;
}

void init_joystick(void)
{
}

void close_joystick(void)
{
}

#endif

int sound_available = 0;

struct audio_channel_data audio_channel[4];

#ifdef __BEOS__
UWORD *sndbuffer;
#elif !defined(AMIGA)
/* The buffer is too large... */
static UWORD sndbuffer[44100];
#endif
UWORD *sndbufpt;

static ULONG data;

int sound_table[256][64];
static int dspbits = 16;
int sndbufsize;

void init_sound_table16(void)
{
    int i,j;
    
    for (i = 0; i < 256; i++)
	for (j = 0; j < 64; j++)
	    sound_table[i][j] = j * (BYTE)i;
}

void init_sound_table8 (void)
{
    int i,j;
    
    for (i = 0; i < 256; i++)
	for (j = 0; j < 64; j++)
	    sound_table[i][j] = (j * (BYTE)i) / 256;
}

static int exact_log2(int v)
{
    int l = 0;
    while ((v >>= 1) != 0)
	l++;
    return l;
}

#ifdef LINUX_SOUND

#include <sys/ioctl.h>
#include <sys/soundcard.h>

static int sfd;
static int have_sound;

void close_sound(void)
{
    if (have_sound)
	close(sfd);
}

int init_sound (void)
{
    int tmp;
    int rate;
    
    unsigned long formats;
    
    sfd = open ("/dev/dsp", O_WRONLY);
    have_sound = !(sfd < 0);
    if (!have_sound) {
	return 0;
    }
    
    ioctl (sfd, SNDCTL_DSP_GETFMTS, &formats);

    if (sound_desired_bsiz < 128 || sound_desired_bsiz > 16384) {
	fprintf(stderr, "Sound buffer size %d out of range.\n", sound_desired_bsiz);
	sound_desired_bsiz = 8192;
    }
    
    tmp = 0x00040000 + exact_log2(sound_desired_bsiz);
    ioctl (sfd, SNDCTL_DSP_SETFRAGMENT, &tmp);
    ioctl (sfd, SNDCTL_DSP_GETBLKSIZE, &sndbufsize);

    dspbits = sound_desired_bits;
    ioctl(sfd, SNDCTL_DSP_SAMPLESIZE, &dspbits);
    ioctl(sfd, SOUND_PCM_READ_BITS, &dspbits);
    if (dspbits != sound_desired_bits) {
	fprintf(stderr, "Can't use sound with %d bits\n", sound_desired_bits);
	return 0;
    }

    tmp = 0;
    ioctl(sfd, SNDCTL_DSP_STEREO, &tmp);
    
    rate = sound_desired_freq;
    ioctl(sfd, SNDCTL_DSP_SPEED, &rate);
    ioctl(sfd, SOUND_PCM_READ_RATE, &rate);
    /* Some soundcards have a bit of tolerance here. */
    if (rate < sound_desired_freq * 90 / 100 || rate > sound_desired_freq * 110 / 100) {
	fprintf(stderr, "Can't use sound with desired frequency %d\n", sound_desired_freq);
	return 0;
    }

    eventtab[ev_sample].evtime = (long)maxhpos * maxvpos * 50 / rate;

    if (dspbits == 16) {
	/* Will this break horribly on Linux/Alpha? Possible... */
	if (!(formats & AFMT_S16_LE))
	    return 0;
	init_sound_table16 ();
	eventtab[ev_sample].handler = sample16_handler;
    } else {
	if (!(formats & AFMT_U8))
	    return 0;
	init_sound_table8 ();
	eventtab[ev_sample].handler = sample8_handler;
    }
    sound_available = 1;
    printf ("Sound driver found and configured for %d bits at %d Hz, buffer is %d bytes\n",
	    dspbits, rate, sndbufsize);
    sndbufpt = sndbuffer;
    return 1;
}

static void flush_sound_buffer(void)
{
    write(sfd, sndbuffer, sndbufsize);
    sndbufpt = sndbuffer;
}

#elif defined(AF_SOUND)

#include <AF/AFlib.h>

static AFAudioConn  *aud;
static AC            ac;
static long          aftime;
static int           rate;

static int have_sound;

void close_sound(void)
{
}

int init_sound (void)
{
    AFSetACAttributes   attributes;
    AFDeviceDescriptor *aDev;
    int                 device;
    
    aud = AFOpenAudioConn(NULL);
    have_sound = !(aud == NULL);
    if (!have_sound) {
	return 0;
    }
    
    for(device = 0; device < ANumberOfAudioDevices(aud); device++) {
	aDev = AAudioDeviceDescriptor(aud, device);
	rate = aDev->playSampleFreq;
	sndbufsize = (rate / 8) * 4;
	if(aDev->inputsFromPhone == 0
	   && aDev->outputsToPhone == 0
	   && aDev->playNchannels == 1)
	    break;
    }
    if (device == ANumberOfAudioDevices(aud)) {
	return 0;
    }
    
    dspbits = 16;
    attributes.type = LIN16;
    ac = AFCreateAC(aud, device, ACEncodingType, &attributes);
    aftime = AFGetTime(ac);

    init_sound_table16 ();
    eventtab[ev_sample].handler = sample16_handler;
    eventtab[ev_sample].evtime = (long)maxhpos * maxvpos * 50 / rate;
    
    sndbufpt = sndbuffer;
    sound_available = 1;
    printf ("Sound driver found and configured for %d bits at %d Hz, buffer is %d bytes\n", dspbits, rate, sndbufsize);
    return 1;
}

static void flush_sound_buffer(void)
{
    long size = (char *)sndbufpt - (char *)sndbuffer;
    if (AFGetTime(ac) > aftime)
	aftime = AFGetTime(ac);
    AFPlaySamples(ac, aftime, size, (unsigned char*) sndbuffer);
    aftime += size / 2;
    sndbufpt = sndbuffer;
}

#elif defined(__mac__)

#include <Sound.h>

static SndChannelPtr newChannel;
static ExtSoundHeader theSndBuffer;
static SndCommand theCmd;

/* The buffer is too large... */
static UWORD buffer0[44100], buffer1[44100], *sndbufpt;

static int have_sound;
static int nextbuf=0;
static Boolean sFlag=true;

void close_sound(void)
{
}

int init_sound (void)
{	
    if (SndNewChannel(&newChannel, sampledSynth, initMono, NULL)) 
	return 0;
    sndbufsize = 44100;
    init_sound_table8 ();

    sndbufpt = buffer0;
    sound_available = 1;
    return 1;
}

static void flush_sound_buffer(void)
{
    sndbufpt = buffer0;
    
    theSndBuffer.samplePtr = (Ptr)buffer0;
    theSndBuffer.numChannels = 1;
    theSndBuffer.sampleRate = 0xac440000;
    theSndBuffer.encode = extSH;
    theSndBuffer.numFrames = sndbufsize;
    theSndBuffer.sampleSize = 8;
    theCmd.param1 = 0;
    theCmd.param2 = (long)&theSndBuffer;
    theCmd.cmd = bufferCmd;
    SndDoCommand(newChannel, &theCmd, false);    
}

#elif defined(__DOS__)

#include "sound/sb.h"
#include "sound/gus.h"

void (*SND_Write)(void *buf, unsigned long size);  // Pointer to function that plays data on card

void close_sound(void)
{
}

int init_sound (void)
{
    int rate;

    dspbits = sound_desired_bits;
    rate = sound_desired_freq;
    if ((rate != 22050) && (rate != 44100)) {
	fprintf(stderr, "Can't use sample rate %d!\n", rate);
	return 0;
    }
	
    if (GUS_Init(&dspbits, &rate, &sndbufsize));
    else if (SB_DetectInitSound(&dspbits, &rate, &sndbufsize));
    else if (0/*OTHER_CARD_DETECT_ROUTINE*/);
    else
	return 0;
    
    eventtab[ev_sample].evtime = (long)maxhpos * maxvpos * 50 / rate;

    if (dspbits == 16) {
	init_sound_table16 ();
	eventtab[ev_sample].handler = sample16_handler;
    } else {
	init_sound_table8 ();
	eventtab[ev_sample].handler = sample8_handler;
    }
    sound_available = 1;
    fprintf(stderr, "Sound driver found and configured for %d bits at %d Hz, buffer is %d bytes\n",
	    dspbits, rate, sndbufsize);
    sndbufpt = sndbuffer;
    return 1;
}

static void flush_sound_buffer(void)
{
    SND_Write(sndbuffer, sndbufsize);
    sndbufpt = sndbuffer;
}

#elif defined(SOLARIS_SOUND)

#include <sys/audioio.h>

static int sfd;
static int have_sound;

void close_sound(void)
{
    if (have_sound)
	close(sfd);
}

int init_sound (void)
{
    int rate;

    struct audio_info sfd_info;

    sfd = open("/dev/audio", O_WRONLY);
    have_sound = !(sfd <0);
    if (!have_sound) {
        return 0;
    }
    
    if (sound_desired_bsiz < 128 || sound_desired_bsiz > 44100) {
	fprintf(stderr, "Sound buffer size %d out of range.\n", sound_desired_bsiz);
	sound_desired_bsiz = 8192;
    }

    rate = sound_desired_freq;
    dspbits = sound_desired_bits;
    AUDIO_INITINFO(&sfd_info);
    sfd_info.play.sample_rate = rate;
    sfd_info.play.channels = 1;
    sfd_info.play.precision = dspbits;
    sfd_info.play.encoding = (dspbits == 8 ) ? AUDIO_ENCODING_ULAW : AUDIO_ENCODING_LINEAR;
    if (ioctl(sfd, AUDIO_SETINFO, &sfd_info)) {
	fprintf(stderr, "Can't use sample rate %d with %d bits, %s!\n", rate, dspbits, (dspbits ==8) ? "ulaw" : "linear");
	return 0;
    }
    eventtab[ev_sample].evtime = (long)maxhpos * maxvpos * 50 / rate;

    init_sound_table16 ();

    if (dspbits == 8) {
	eventtab[ev_sample].handler = sample_ulaw_handler;
    } else {
	eventtab[ev_sample].handler = sample16_handler;
    }

    sndbufpt = sndbuffer;
    smplcnt = 0;
    sound_available = 1;
    sndbufsize = sound_desired_bsiz;
    printf ("Sound driver found and configured for %d bits, %s at %d Hz, buffer is %d bytes\n", dspbits, (dspbits ==8) ? "ulaw" : "linear", rate, sndbufsize);
    return 1;
}

static void flush_sound_buffer(void)
{
    write(sfd, sndbuffer, sndbufsize);
    sndbufpt = sndbuffer;
}


#elif defined(AMIGA) && !defined(DONT_WANT_SOUND)
/*
 * Compared to Linux, AF_SOUND, and mac above, the AMIGA sound processing
 * with OS routines is awfull. (sam)
 */
#define DEVICES_TIMER_H /* as there is a conflict on timeval */
#include <proto/exec.h>
#include <proto/alib.h>
#include <proto/dos.h>

#include <exec/memory.h>
#include <exec/devices.h>
#include <exec/io.h>

#include <graphics/gfxbase.h>
#include <devices/timer.h>
#include <devices/audio.h>

static char whichchannel[]={1,2,4,8};
static struct IOAudio *AudioIO;
static struct MsgPort *AudioMP;
static struct Message *AudioMSG;

static unsigned char *buffers[2];
static UWORD *sndbuffer;
static int bufidx, devopen;

static int have_sound, clockval, oldledstate, period;

int init_sound (void) 
{ /* too complex ? No it is only the allocation of a single channel ! */
  /* it would have been far less painfull if AmigaOS provided a */
  /* SOUND: device handler */
    int rate;

    atexit(close_sound);

    if (sound_desired_bsiz < 2 || sound_desired_bsiz > (128*1024)) {
	fprintf(stderr, "Sound buffer size %d out of range.\n", sound_desired_bsiz);
	sound_desired_bsiz = 8192;
    } 
    sndbufsize = (sound_desired_bsiz + 1)&~1;

    /* get the buffers */
    buffers[0] = (void*)AllocMem(sndbufsize,MEMF_CHIP|MEMF_CLEAR);
    buffers[1] = (void*)AllocMem(sndbufsize,MEMF_CHIP|MEMF_CLEAR);
    if(!buffers[0] || !buffers[1]) goto fail;
    bufidx = 0;
    sndbuffer = sndbufpt = (UWORD*)buffers[bufidx];

    /* determine the clock */
    { 
	struct GfxBase *GB;
	GB = (void*)OpenLibrary("graphics.library",0L);
	if(!GB) goto fail;
	if (GB->DisplayFlags & PAL)
	    clockval = 3546895;        /* PAL clock */
	else
	    clockval = 3579545;        /* NTSC clock */
	CloseLibrary((void*)GB);
    }

    if (!sound_desired_freq) sound_desired_freq = 1;
    if (clockval/sound_desired_freq < 124 || clockval/sound_desired_freq > 65535) {
	fprintf(stderr, "Can't use sound with desired frequency %d Hz\n", sound_desired_freq);
        sound_desired_freq = 22000;
    }
    rate   = sound_desired_freq;
    period = (UWORD)(clockval/rate);

    /* setup the stuff */
    AudioMP = CreatePort(0,0);
    if(!AudioMP) goto fail;
    AudioIO = (struct IOAudio *)CreateExtIO(AudioMP, sizeof(struct IOAudio));
    if(!AudioIO) goto fail;

    AudioIO->ioa_Request.io_Message.mn_Node.ln_Pri /*pfew!!*/ = 85;
    AudioIO->ioa_Data = whichchannel;
    AudioIO->ioa_Length = sizeof(whichchannel);
    AudioIO->ioa_AllocKey = 0;
    if(OpenDevice(AUDIONAME, 0, (void*)AudioIO, 0)) goto fail;
    devopen = 1;

    oldledstate = cia->ciapra & (1<<CIAB_LED);
    cia->ciapra |= (1<<CIAB_LED);

    eventtab[ev_sample].evtime = (long)maxhpos * maxvpos * 50 / rate;
    init_sound_table8 ();
    eventtab[ev_sample].handler = sample8_handler;

    printf ("Sound driver found and configured for %d bits at %d Hz, buffer is %d bytes\n",
            8, rate, sndbufsize);

    sound_available = 1;
    return 1;
fail:
    sound_available = 0;
    return 0;
}

void close_sound(void)
{
    if(devopen) {CloseDevice((void*)AudioIO);devopen = 0;}
    if(AudioIO) {DeleteExtIO((void*)AudioIO);AudioIO = NULL;}
    if(AudioMP) {DeletePort((void*)AudioMP);AudioMP = NULL;}
    if(buffers[0]) {FreeMem((APTR)buffers[0],sndbufsize);buffers[0] = 0;}
    if(buffers[1]) {FreeMem((APTR)buffers[1],sndbufsize);buffers[1] = 0;}
    if(sound_available) {
    	cia->ciapra = (cia->ciapra & ~(1<<CIAB_LED)) | oldledstate;
	sound_available = 0;
    }
}

static void flush_sound_buffer(void)
{
    static char IOSent = 0;
    AudioIO->ioa_Request.io_Command = CMD_WRITE;
    AudioIO->ioa_Request.io_Flags   = ADIOF_PERVOL|IOF_QUICK;
    AudioIO->ioa_Data               = (BYTE *)buffers[bufidx];
    AudioIO->ioa_Length             = sndbufsize;
    AudioIO->ioa_Period             = period;
    AudioIO->ioa_Volume             = 64;
    AudioIO->ioa_Cycles             = 1;

    if(IOSent) WaitIO((void*)AudioIO); else IOSent=1;
    BeginIO((void*)AudioIO);

    /* double buffering */
    bufidx = 1 - bufidx;
    sndbuffer = sndbufpt = (UWORD*)buffers[bufidx];
}

#elif !defined(__BEOS__)

int init_sound (void)
{
    produce_sound = 0;
    return 1;
}

void close_sound(void)
{
}

static void flush_sound_buffer(void)
{
}

#endif

void AUDxDAT(int nr, UWORD v) 
{
#ifndef DONT_WANT_SOUND
    struct audio_channel_data *cdp = audio_channel + nr;
    cdp->dat = v;
    if (cdp->state == 0 && !(INTREQR() & (0x80 << nr))) {
	cdp->state = 2;
	INTREQ(0x8000 | (0x80 << nr));
	/* data_written = 2 ???? */
	eventtab[ev_aud0 + nr].evtime = cycles + cdp->per;
	eventtab[ev_aud0 + nr].oldcycles = cycles;
	eventtab[ev_aud0 + nr].active = 1;
	events_schedule();
    }
#endif
}

#ifndef DONT_WANT_SOUND
void sample16_handler(void)
{
    int nr;
    ULONG data = 0;

    eventtab[ev_sample].evtime += cycles - eventtab[ev_sample].oldcycles;
    eventtab[ev_sample].oldcycles = cycles;

    if (produce_sound < 2)
	return;

    for (nr = 0; nr < 4; nr++) {
	if (!(adkcon & (0x11 << nr)))
	    data += sound_table[audio_channel[nr].current_sample][audio_channel[nr].vol];
    }
    *sndbufpt++ = data;
    if ((char *)sndbufpt - (char *)sndbuffer >= sndbufsize) {
	flush_sound_buffer();
    }
}

void sample8_handler(void)
{
    int nr;
    ULONG data = 0;
    unsigned char *bp = (unsigned char *)sndbufpt;
    
    eventtab[ev_sample].evtime += cycles - eventtab[ev_sample].oldcycles;
    eventtab[ev_sample].oldcycles = cycles;
    
    if (produce_sound < 2)
	return;

    for (nr = 0; nr < 4; nr++) {
	if (!(adkcon & (0x11 << nr)))
	    data += sound_table[audio_channel[nr].current_sample][audio_channel[nr].vol];
    }
#ifdef AMIGA
    *bp++ = (unsigned char) data;
#else
    *bp++ = data + 128;
#endif
    sndbufpt = (UWORD *)bp;

    if ((char *)sndbufpt - (char *)sndbuffer >= sndbufsize) {
	flush_sound_buffer();
    }
}

static char int2ulaw(int ch)
{
    int mask;

    if (ch < 0) {
      ch = -ch;
      mask = 0x7f;
    }
    else {
      mask = 0xff;
    }

    if (ch < 32) {
	ch = 0xF0 | ( 15 - (ch/2) );
    } else if (ch < 96) {
        ch = 0xE0 | ( 15 - (ch-32)/4 );
    } else if (ch < 224) {
	ch = 0xD0 | ( 15 - (ch-96)/8 );
    } else if (ch < 480) {
	ch = 0xC0 | ( 15 - (ch-224)/16 );
    } else if (ch < 992 ) {
	ch = 0xB0 | ( 15 - (ch-480)/32 );
    } else if (ch < 2016) {
	ch = 0xA0 | ( 15 - (ch-992)/64 );
    } else if (ch < 4064) {
	ch = 0x90 | ( 15 - (ch-2016)/128 );
    } else if (ch < 8160) {
	ch = 0x80 | ( 15 - (ch-4064)/256 );
    } else {
	ch = 0x80;
    }
    return (char)(mask & ch);
}

static void sample_ulaw_handler(void)
{
    int nr;
    ULONG data = 0;
    char *bp = (char *)sndbufpt;

    eventtab[ev_sample].evtime += cycles - eventtab[ev_sample].oldcycles;
    eventtab[ev_sample].oldcycles = cycles;

    if (produce_sound < 2)
	return;

    for (nr = 0; nr < 4; nr++) {
	if (!(adkcon & (0x11 << nr)))
	    data += sound_table[audio_channel[nr].current_sample][audio_channel[nr].vol];
    }
    *bp++ = int2ulaw(data);
    sndbufpt = (UWORD *)bp;

    if ((char *)sndbufpt - (char *)sndbuffer >= sndbufsize) {
	flush_sound_buffer();
    }
}

static void audio_handler(int nr) 
{
    struct audio_channel_data *cdp = audio_channel + nr;

    switch (cdp->state) {
     case 0:
	fprintf(stderr, "Bug in sound code\n");
	break;

     case 1:
	/* We come here at the first hsync after DMA was turned on. */
	eventtab[ev_aud0 + nr].evtime += maxhpos;
	eventtab[ev_aud0 + nr].oldcycles += maxhpos;
	
	cdp->state = 5;
	INTREQ(0x8000 | (0x80 << nr));
	if (cdp->wlen != 1)
	    cdp->wlen--;
	cdp->nextdat = chipmem_bank.wget(cdp->pt);
	cdp->pt += 2;
	break;

     case 5:
	/* We come here at the second hsync after DMA was turned on. */
	if (produce_sound == 0)
	    cdp->per = 65535;

	eventtab[ev_aud0 + nr].evtime = cycles + cdp->per;
	eventtab[ev_aud0 + nr].oldcycles = cycles;
	cdp->dat = cdp->nextdat;
	cdp->current_sample = (UBYTE)(cdp->dat >> 8);
	cdp->state = 2;
	{
	    int audav = adkcon & (1 << nr);
	    int audap = adkcon & (16 << nr);
	    int napnav = (!audav && !audap) || audav;
	    if (napnav)
		cdp->data_written = 2;
	}
	break;
	
     case 2:
	/* We come here when a 2->3 transition occurs */
	if (produce_sound == 0)
	    cdp->per = 65535;

	cdp->current_sample = (UBYTE)(cdp->dat & 0xFF);
	eventtab[ev_aud0 + nr].evtime = cycles + cdp->per;
	eventtab[ev_aud0 + nr].oldcycles = cycles;

	cdp->state = 3;

	/* Period attachment? */
	if (adkcon & (0x10 << nr)) {
	    if (cdp->intreq2 && cdp->dmaen)
		INTREQ(0x8000 | (0x80 << nr));
	    cdp->intreq2 = 0;

	    cdp->dat = cdp->nextdat;
	    if (cdp->dmaen)
		cdp->data_written = 2;
	    if (nr < 3) {
		if (cdp->dat == 0)
		    (cdp+1)->per = 65535;

		else if (cdp->dat < maxhpos/2 && produce_sound < 3)
		    (cdp+1)->per = maxhpos/2;
		else
		    (cdp+1)->per = cdp->dat;
	    }
	}
	break;
	
     case 3:
	/* We come here when a 3->2 transition occurs */
	if (produce_sound == 0)
	    cdp->per = 65535;

	eventtab[ev_aud0 + nr].evtime = cycles + cdp->per;
	eventtab[ev_aud0 + nr].oldcycles = cycles;
	
	if ((INTREQR() & (0x80 << nr)) && !cdp->dmaen) {
	    cdp->state = 0;
	    cdp->current_sample = 0;
	    eventtab[ev_aud0 + nr].active = 0;
	    break;
	} else {
	    int audav = adkcon & (1 << nr);
	    int audap = adkcon & (16 << nr);
	    int napnav = (!audav && !audap) || audav;
	    cdp->state = 2;
	    
	    if ((cdp->intreq2 && cdp->dmaen && napnav)
		|| (napnav && !cdp->dmaen))
		INTREQ(0x8000 | (0x80 << nr));
	    cdp->intreq2 = 0;
	    
	    cdp->dat = cdp->nextdat;
	    cdp->current_sample = (UBYTE)(cdp->dat >> 8);

	    if (cdp->dmaen && napnav)
		cdp->data_written = 2;
	    
	    /* Volume attachment? */
	    if (audav) {
		if (nr < 3)
		    (cdp+1)->vol = cdp->dat;
	    }
	}
	break;
	    
     default:
	cdp->state = 0;
	eventtab[ev_aud0 + nr].active = 0;
	break;
    }
}

void aud0_handler(void)
{
    audio_handler(0);
}
void aud1_handler(void)
{
    audio_handler(1);
}
void aud2_handler(void)
{
    audio_handler(2);
}
void aud3_handler(void)
{
    audio_handler(3);
}
#endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.