MCUME/MCUME_teensy41/teensyuae/audio.c

313 wiersze
7.1 KiB
C

/*
* UAE - The Un*x Amiga Emulator
*
* OS specific functions
*
* Copyright 1995, 1996, 1997 Bernd Schmidt
* Copyright 1996 Marcus Sundberg
* Copyright 1996 Manfred Thole
*/
#include "shared.h"
#include "memory.h"
#include "custom.h"
#include "gensound.h"
#include "sounddep/sound.h"
#include "events.h"
#include "audio.h"
int sound_available = 0;
struct audio_channel_data audio_channel[4];
#ifdef HAS_TABLE
static short sound_table[256][64];
#endif
unsigned long int sample_evtime;
void init_sound_table16(void)
{
#ifdef HAS_TABLE
int i,j;
for (i = 0; i < 256; i++)
for (j = 0; j < 64; j++)
sound_table[i][j] = j * (uae_s8)i;
#endif
}
void AUDxDAT(int nr, uae_u16 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
}
void AUDxLCH(int nr, uae_u16 v) { audio_channel[nr].lc = (audio_channel[nr].lc & 0xffff) | ((uae_u32)v << 16); }
void AUDxLCL(int nr, uae_u16 v) { audio_channel[nr].lc = (audio_channel[nr].lc & ~0xffff) | (v & 0xFFFE); }
void AUDxPER(int nr, uae_u16 v)
{
if (v <= 0) {
#if 0 /* v == 0 is rather common, and harmless, and the value isn't signed anyway */
static int warned = 0;
if (!warned)
write_log ("Broken program accessing the sound hardware\n"), warned++;
#endif
v = 65535;
}
if (v < maxhpos/2 && currprefs.produce_sound < 3)
v = maxhpos/2;
audio_channel[nr].per = v;
}
void AUDxVOL(int nr, uae_u16 v) { audio_channel[nr].vol = v & 64 ? 63 : v & 63; }
void AUDxLEN(int nr, uae_u16 v) { audio_channel[nr].len = v; }
/* Templates! I want templates! */
void sample16_handler(void)
{
#ifndef DONT_WANT_SOUND
int nr, adk;
uae_u32 data = SOUND16_BASE_VAL;
eventtab[ev_sample].evtime = cycles + sample_evtime;
eventtab[ev_sample].oldcycles = cycles;
adk = adkcon;
#ifdef HAS_TABLE
if (!(adk & 0x11))
data += sound_table[audio_channel[0].current_sample][audio_channel[0].vol];
if (!(adk & 0x22))
data += sound_table[audio_channel[1].current_sample][audio_channel[1].vol];
if (!(adk & 0x44))
data += sound_table[audio_channel[2].current_sample][audio_channel[2].vol];
if (!(adk & 0x88))
data += sound_table[audio_channel[3].current_sample][audio_channel[3].vol];
#else
if (!(adk & 0x11))
data += (uae_s8)audio_channel[0].current_sample*audio_channel[0].vol;
if (!(adk & 0x22))
data += (uae_s8)audio_channel[1].current_sample*audio_channel[1].vol;
if (!(adk & 0x44))
data += (uae_s8)audio_channel[2].current_sample*audio_channel[2].vol;
if (!(adk & 0x88))
data += (uae_s8)audio_channel[3].current_sample*audio_channel[3].vol;
#endif
PUT_SOUND_WORD (data);
check_sound_buffers ();
#endif
}
#ifdef HAS_ULAW
static uae_u8 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 (uae_u8)(mask & ch);
}
void sample_ulaw_handler(void)
{
#ifndef DONT_WANT_SOUND
int nr;
uae_u32 data = 0;
char *bp = (char *)sndbufpt;
eventtab[ev_sample].evtime += cycles - eventtab[ev_sample].oldcycles;
eventtab[ev_sample].oldcycles = cycles;
for (nr = 0; nr < 4; nr++) {
#ifdef HAS_TABLE
if (!(adkcon & (0x11 << nr)))
data += sound_table[audio_channel[nr].current_sample][audio_channel[nr].vol];
#endif
}
PUT_SOUND_BYTE (int2ulaw (data));
check_sound_buffers ();
#endif
}
#endif
#ifndef DONT_WANT_SOUND
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 (currprefs.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 = (uae_u8)(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 (currprefs.produce_sound == 0)
cdp->per = 65535;
cdp->current_sample = (uae_u8)(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 && currprefs.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 (currprefs.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 = (uae_u8)(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