kopia lustrzana https://github.com/Jean-MarcHarvengt/MCUME
313 wiersze
7.1 KiB
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
|
|
|