From cf67d05bb4b047431b61d25cb4282744e3992e99 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 10 Jun 2002 20:42:53 +0000 Subject: [PATCH] Added Atari audio support (thanks Patrice!) --- README.MiNT | 36 +- configure.in | 29 +- src/audio/Makefile.am | 3 +- src/audio/SDL_audio.c | 9 +- src/audio/SDL_sysaudio.h | 3 + src/audio/mint/.cvsignore | 6 + src/audio/mint/Makefile.am | 14 + src/audio/mint/SDL_mintaudio.c | 628 ++++++++++++++++++++++ src/audio/mint/SDL_mintaudio.h | 15 + src/audio/mint/SDL_mintaudiodma.h | 43 ++ src/audio/mint/SDL_mintaudiogsxb.h | 85 +++ src/audio/mint/SDL_mintaudiointerrupt.S | 183 +++++++ src/audio/mint/SDL_mintaudiointerrupt_s.h | 24 + 13 files changed, 1063 insertions(+), 15 deletions(-) create mode 100644 src/audio/mint/.cvsignore create mode 100644 src/audio/mint/Makefile.am create mode 100644 src/audio/mint/SDL_mintaudio.c create mode 100644 src/audio/mint/SDL_mintaudio.h create mode 100644 src/audio/mint/SDL_mintaudiodma.h create mode 100644 src/audio/mint/SDL_mintaudiogsxb.h create mode 100644 src/audio/mint/SDL_mintaudiointerrupt.S create mode 100644 src/audio/mint/SDL_mintaudiointerrupt_s.h diff --git a/README.MiNT b/README.MiNT index 8854eea11..4a573f2da 100644 --- a/README.MiNT +++ b/README.MiNT @@ -10,9 +10,8 @@ I. Building the Simple DirectMedia Layer libraries: Do the classic configure, with --disable-shared --enable-static and: Tos version (should run everywhere): - --disable-audio --disable-threads - Tos does not support threads, so can not support audio, maybe in a future - version audio support will be added via interrupts. + --disable-threads + Tos does not support threads. MiNT version (maybe Magic, only for multitasking OS): --disable-pthreads --enable-pth @@ -50,11 +49,11 @@ Mouse (XBIOS, GEM, Ikbd) Video (XBIOS (Fullscreen), GEM (Windowed and Fullscreen)) Timer (VBL vector) Joystick and joypad support (Ikbd, Hardware) +Audio support (Hardware, XBIOS, GSXB, /dev/audio if threads enabled) +Threads support (Multitasking OS only via GNU pth library) - What is missing: -Audio support (TOS) CDROM support (Metados, /dev/cdrom) -Threads support (TOS) - Driver combinations: Video Kbd Mouse Timer Jstick Joypads @@ -69,15 +68,20 @@ to report this type event. ============================================================================== V. Environment variables: +SDL_VIDEODRIVER: + Set to 'xbios' to force xbios video driver + Set to 'gem' to force gem video driver + +SDL_AUDIODRIVER: + Set to 'mint' to force Atari audio driver + Set to 'audio' to force Sun /dev/audio audio driver + Set to 'disk' to force disk-writing audio driver + SDL_ATARI_EVENTSDRIVER Set to 'ikbd' to force IKBD 6301 keyboard driver Set to 'gemdos' to force gemdos keyboard driver Set to 'bios' to force bios keyboard driver -SDL_VIDEODRIVER: - Set to 'xbios' to force xbios video driver - Set to 'gem' to force gem video driver - SDL_JOYSTICK_ATARI: Use any of these strings in the environment variable to enable or disable a joystick: @@ -151,7 +155,19 @@ Joypad driver: Available if _MCH cookie is STE or Falcon. VBL timer driver: - Available all machines (I think). + Available on all machines (I think). + +Audio driver: + Cookie _SND is used to detect supported audio capabilities + + STE, Mega STE, TT: + 8 bits DMA (hardware access) + + Falcon, machines with GSXB driver: + Xbios functions + + Other machines: + Not supported -- Patrice Mandin diff --git a/configure.in b/configure.in index fbba8f2f4..e7abdd7dc 100644 --- a/configure.in +++ b/configure.in @@ -435,6 +435,24 @@ CheckDiskAudio() fi } +dnl Set up the Atari Audio driver +CheckAtariAudio() +{ + AC_ARG_ENABLE(mintaudio, +[ --enable-mintaudio support Atari audio driver [default=yes]], + , enable_mintaudio=yes) + if test x$enable_audio = xyes -a x$enable_mintaudio = xyes; then + mintaudio=no + AC_CHECK_HEADER(mint/falcon.h, have_mint_falcon_hdr=yes) + if test x$have_mint_falcon_hdr = xyes; then + mintaudio=yes + CFLAGS="$CFLAGS -DMINTAUDIO_SUPPORT" + AUDIO_SUBDIRS="$AUDIO_SUBDIRS mint" + AUDIO_DRIVERS="$AUDIO_DRIVERS mint/libaudio_mintaudio.la" + fi + fi +} + dnl See if we can use x86 assembly blitters # NASM is available from: http://nasm.octium.net/ CheckNASM() @@ -2380,13 +2398,17 @@ case "$target" in CheckAtariBiosEvent CheckAtariXbiosVideo CheckAtariGemVideo + CheckAtariAudio CheckPTH # Set up files for the main() stub COPY_ARCH_SRC(src/main, linux, SDL_main.c) # Set up files for the audio library - if test x$enable_audio = xyes; then - AUDIO_SUBDIRS="$AUDIO_SUBDIRS sun" - AUDIO_DRIVERS="$AUDIO_DRIVERS sun/libaudio_sun.la" + if test x$enable_threads = xyes -a x$enable_pth = xyes; then + if test x$enable_audio = xyes; then + CFLAGS="$CFLAGS -DSUNAUDIO_SUPPORT" + AUDIO_SUBDIRS="$AUDIO_SUBDIRS sun" + AUDIO_DRIVERS="$AUDIO_DRIVERS sun/libaudio_sun.la" + fi fi # Set up files for the joystick library if test x$enable_joystick = xyes; then @@ -2575,6 +2597,7 @@ src/audio/ums/Makefile src/audio/windib/Makefile src/audio/windx5/Makefile src/audio/disk/Makefile +src/audio/mint/Makefile src/video/Makefile src/video/XFree86/Makefile src/video/XFree86/extensions/Makefile diff --git a/src/audio/Makefile.am b/src/audio/Makefile.am index df23540b1..8330d280a 100644 --- a/src/audio/Makefile.am +++ b/src/audio/Makefile.am @@ -5,7 +5,8 @@ noinst_LTLIBRARIES = libaudio.la # Define which subdirectories need to be built SUBDIRS = @AUDIO_SUBDIRS@ -DIST_SUBDIRS = alsa arts baudio dma dmedia dsp esd macrom nas nto openbsd paudio sun ums windib windx5 disk +DIST_SUBDIRS = alsa arts baudio dma dmedia dsp esd macrom nas nto openbsd \ + paudio sun ums windib windx5 disk mint DRIVERS = @AUDIO_DRIVERS@ diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 3c9d5821c..287fa26bd 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -83,6 +83,9 @@ static AudioBootStrap *bootstrap[] = { #ifdef ENABLE_AHI &AHI_bootstrap, #endif +#ifdef MINTAUDIO_SUPPORT + &MINTAUDIO_bootstrap, +#endif #ifdef DISKAUD_SUPPORT &DISKAUD_bootstrap, #endif @@ -377,6 +380,9 @@ int SDL_OpenAudio(SDL_AudioSpec *desired, SDL_AudioSpec *obtained) #ifdef macintosh /* FIXME: Need to implement PPC interrupt asm for SDL_LockAudio() */ +#else +#if defined(__MINT__) && !defined(ENABLE_THREADS) + /* Uses interrupt driven audio, without thread */ #else /* Create a semaphore for locking the sound buffers */ audio->mixer_lock = SDL_CreateMutex(); @@ -385,7 +391,8 @@ int SDL_OpenAudio(SDL_AudioSpec *desired, SDL_AudioSpec *obtained) SDL_CloseAudio(); return(-1); } -#endif +#endif /* __MINT__ */ +#endif /* macintosh */ /* Calculate the silence and size of the audio specification */ SDL_CalculateAudioSpec(desired); diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h index 7619adbf8..55ad91f05 100644 --- a/src/audio/SDL_sysaudio.h +++ b/src/audio/SDL_sysaudio.h @@ -147,6 +147,9 @@ extern AudioBootStrap SNDMGR_bootstrap; #ifdef ENABLE_AHI extern AudioBootStrap AHI_bootstrap; #endif +#ifdef MINTAUDIO_SUPPORT +extern AudioBootStrap MINTAUDIO_bootstrap; +#endif #ifdef DISKAUD_SUPPORT extern AudioBootStrap DISKAUD_bootstrap; #endif diff --git a/src/audio/mint/.cvsignore b/src/audio/mint/.cvsignore new file mode 100644 index 000000000..899d53557 --- /dev/null +++ b/src/audio/mint/.cvsignore @@ -0,0 +1,6 @@ +Makefile.in +Makefile +.libs +*.o +*.lo +*.la diff --git a/src/audio/mint/Makefile.am b/src/audio/mint/Makefile.am new file mode 100644 index 000000000..57ca3e7f6 --- /dev/null +++ b/src/audio/mint/Makefile.am @@ -0,0 +1,14 @@ + +## Makefile.am for SDL using Xbios/Dma/whatever available audio functions + +noinst_LTLIBRARIES = libaudio_mintaudio.la +libaudio_mintaudio_la_SOURCES = $(SRCS) + +# The SDL audio driver sources +SRCS = SDL_mintaudio.c \ + SDL_mintaudio.h \ + SDL_mintaudiointerrupt.S \ + SDL_mintaudiointerrupt_s.h \ + SDL_mintaudiodma.h \ + SDL_mintaudiogsxb.h + diff --git a/src/audio/mint/SDL_mintaudio.c b/src/audio/mint/SDL_mintaudio.c new file mode 100644 index 000000000..e2d6a9f1c --- /dev/null +++ b/src/audio/mint/SDL_mintaudio.c @@ -0,0 +1,628 @@ +/* + * MiNT audio driver + * + * Patrice Mandin + */ + +#include +#include +#include + +/* Mint includes */ +#include +#include +#include + +#include "SDL_endian.h" +#include "SDL_audio.h" +#include "SDL_audio_c.h" +#include "SDL_audiomem.h" +#include "SDL_sysaudio.h" + +#include "SDL_mintaudio.h" +#include "SDL_mintaudiodma.h" +#include "SDL_mintaudiogsxb.h" +#include "SDL_mintaudiointerrupt_s.h" + +#include "SDL_atarimxalloc_c.h" + +/*--- Defines ---*/ + +#define MINT_AUDIO_DRIVER_NAME "mint" + +/* Master clocks for replay frequencies */ +#define MASTERCLOCK_STE 8010666 /* Not sure of this one */ +#define MASTERCLOCK_TT 16107953 /* Not sure of this one */ +#define MASTERCLOCK_FALCON1 25175000 +#define MASTERCLOCK_FALCON2 32000000 /* Only usable for DSP56K */ +#define MASTERCLOCK_FALCONEXT -1 /* Clock on DSP56K port, unknown */ +#define MASTERCLOCK_MILAN1 22579200 /* Standard clock for 44.1 Khz */ +#define MASTERCLOCK_MILAN2 24576000 /* Standard clock for 48 Khz */ + +/* Master clock predivisors */ +#define MASTERPREDIV_STE 160 +#define MASTERPREDIV_TT 320 +#define MASTERPREDIV_FALCON 256 +#define MASTERPREDIV_MILAN 256 + +/* Values>>16 in _MCH cookie */ +enum { + MCH_ST=0, + MCH_STE, + MCH_TT, + MCH_F30 +}; + +/* MFP 68901 interrupt sources */ +enum { + MFP_PARALLEL=0, + MFP_DCD, + MFP_CTS, + MFP_BITBLT, + MFP_TIMERD, + MFP_BAUDRATE=MFP_TIMERD, + MFP_TIMERC, + MFP_200HZ=MFP_TIMERC, + MFP_ACIA, + MFP_DISK, + MFP_TIMERB, + MFP_HBLANK=MFP_TIMERB, + MFP_TERR, + MFP_TBE, + MFP_RERR, + MFP_RBF, + MFP_TIMERA, + MFP_DMASOUND=MFP_TIMERA, + MFP_RING, + MFP_MONODETECT +}; + +/* Xbtimer() timers */ +enum { + XB_TIMERA=0, + XB_TIMERB, + XB_TIMERC, + XB_TIMERD +}; + +/*--- Static variables ---*/ + +static unsigned long cookie_snd, cookie_mch, cookie_gsxb; +static Uint16 hardfreq[16]; +static Uint16 numfreq; +static SDL_AudioDevice *SDL_MintAudio_device; + +/*--- Audio driver functions ---*/ + +static void Mint_CloseAudio(_THIS); +static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec); +static void Mint_LockAudio(_THIS); +static void Mint_UnlockAudio(_THIS); + +/*--- Audio driver bootstrap functions ---*/ + +static int Audio_Available(void) +{ + const char *envr = getenv("SDL_AUDIODRIVER"); + + /* Check if user asked a different audio driver */ + if ((envr) && (strcmp(envr, MINT_AUDIO_DRIVER_NAME)!=0)) { + return 0; + } + + /* Cookie _SND present ? if not, assume ST machine */ + if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) { + cookie_snd = SND_PSG; + } + + /* Cookie _MCH present ? if not, assume ST machine */ + if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) { + cookie_mch = MCH_ST << 16; + } + + /* Cookie GSXB present ? */ + cookie_gsxb = (Getcookie(C_GSXB, &cookie_gsxb) == C_FOUND); + + /* Check if we have xbios functions (Falcon, clones) */ + if ((cookie_snd & SND_16BIT)!=0) { + /* Check if audio is lockable */ + if (Locksnd()==1) { + Unlocksnd(); + } else { + /* Already in use */ + return(0); + } + + return(1); + } + + /* Check if we have 8 bits DMA audio (STE, TT) */ + if ((cookie_snd & SND_8BIT)!=0) { + return(1); + } + + return(0); +} + +static void Audio_DeleteDevice(SDL_AudioDevice *device) +{ + free(device->hidden); + free(device); +} + +static SDL_AudioDevice *Audio_CreateDevice(int devindex) +{ + SDL_AudioDevice *this; + + /* Initialize all variables that we clean on shutdown */ + this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice)); + if ( this ) { + memset(this, 0, (sizeof *this)); + } + if ( this == NULL ) { + SDL_OutOfMemory(); + if ( this ) { + free(this); + } + return(0); + } + + /* Set the function pointers */ + this->OpenAudio = Mint_OpenAudio; + this->CloseAudio = Mint_CloseAudio; + this->LockAudio = Mint_LockAudio; + this->UnlockAudio = Mint_UnlockAudio; + this->free = Audio_DeleteDevice; + + return this; +} + +AudioBootStrap MINTAUDIO_bootstrap = { + MINT_AUDIO_DRIVER_NAME, "MiNT audio driver", + Audio_Available, Audio_CreateDevice +}; + +static void Mint_LockAudio(_THIS) +{ + void *oldpile; + + /* Stop replay */ + if ((cookie_snd & SND_16BIT)!=0) { + Buffoper(0); + } else if ((cookie_snd & SND_8BIT)!=0) { + oldpile=(void *)Super(0); + DMAAUDIO_IO.control=0; + Super(oldpile); + } +} + +static void Mint_UnlockAudio(_THIS) +{ + void *oldpile; + + /* Restart replay */ + if ((cookie_snd & SND_16BIT)!=0) { + Buffoper(SB_PLA_ENA|SB_PLA_RPT); + } else if ((cookie_snd & SND_8BIT)!=0) { + oldpile=(void *)Super(0); + DMAAUDIO_IO.control=3; + Super(oldpile); + } +} + +/* This is called from the interrupt routine */ +void SDL_MintAudio_Callback(void) +{ + SDL_AudioDevice *audio; + Uint8 *buffer; + + audio = SDL_MintAudio_device; + buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf]; + + if ( ! audio->paused ) { + if ( audio->convert.needed ) { + audio->spec.callback(audio->spec.userdata, + (Uint8 *)audio->convert.buf,audio->convert.len); + SDL_ConvertAudio(&audio->convert); + memcpy(buffer, audio->convert.buf, audio->convert.len_cvt); + } else { + audio->spec.callback(audio->spec.userdata, buffer, audio->spec.size); + } + } +} + +static void Mint_StopAudio_Dma8(void) +{ + void *oldpile; + + oldpile=(void *)Super(0); + DMAAUDIO_IO.control=0; + Super(oldpile); + + Jdisint(MFP_DMASOUND); +} + +static void Mint_StopAudio_Xbios(void) +{ + Buffoper(0); + Jdisint(MFP_DMASOUND); +} + +static void Mint_StopAudio_Gsxb(void) +{ + Buffoper(0); +} + +static void Mint_CloseAudio(_THIS) +{ + if (cookie_gsxb && ((cookie_snd & (SND_GSXB|SND_16BIT))==(SND_GSXB|SND_16BIT)) ) { + Mint_StopAudio_Gsxb(); + } else if ((cookie_snd & SND_16BIT)!=0) { + Mint_StopAudio_Xbios(); + } else if ((cookie_snd & SND_8BIT)!=0) { + Mint_StopAudio_Dma8(); + } + + /* Clear buffers */ + if (SDL_MintAudio_audiobuf[0]) { + Mfree(SDL_MintAudio_audiobuf[0]); + SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL; + } + + /* Unlock sound system */ + if ((cookie_snd & SND_16BIT)!=0) { + Unlocksnd(); + } +} + +static void Mint_CheckAudio_Dma8(SDL_AudioSpec *spec) +{ + int i; + + spec->format = AUDIO_S8; + + switch(cookie_mch>>16) { + case MCH_STE: + /* STE replay frequencies */ + for (i=0;i<4;i++) { + hardfreq[i]=MASTERCLOCK_STE/(MASTERPREDIV_STE*(i+1)); + } + + if (spec->freq>=(hardfreq[0]+hardfreq[1])>>1) { + numfreq=3; /* 50066 */ + } else if (spec->freq>=(hardfreq[1]+hardfreq[2])>>1) { + numfreq=2; /* 25033 */ + } else if (spec->freq>=(hardfreq[2]+hardfreq[3])>>1) { + numfreq=1; /* 12517 */ + } else { + numfreq=0; /* 6258 */ + } + + spec->freq=hardfreq[numfreq]; + break; + case MCH_TT: + /* TT replay frequencies */ + for (i=0;i<4;i++) { + hardfreq[i]=MASTERCLOCK_TT/(MASTERPREDIV_TT*(i+1)); + } + + if (spec->freq>=(hardfreq[0]+hardfreq[1])>>1) { + numfreq=3; /* 50337 */ + } else if (spec->freq>=(hardfreq[1]+hardfreq[2])>>1) { + numfreq=2; /* 25169 */ + } else if (spec->freq>=(hardfreq[2]+hardfreq[3])>>1) { + numfreq=1; /* 12584 */ + } else { + numfreq=0; /* 6292 */ + } + spec->freq=hardfreq[numfreq]; + break; + } +} + +static void Mint_CheckAudio_Xbios(SDL_AudioSpec *spec) +{ + int i; + + /* Check conversions needed */ + switch (spec->format & 0xff) { + case 8: + spec->format = AUDIO_S8; + break; + case 16: + spec->format = AUDIO_S16MSB; + break; + } + + /* Check hardware channels */ + if ((spec->channels==1) && ((spec->format & 0xff)==16)) { + spec->channels=2; + } + + /* Falcon replay frequencies */ + for (i=0;i<16;i++) { + hardfreq[i]=MASTERCLOCK_FALCON1/(MASTERPREDIV_FALCON*(i+1)); + } + + /* The Falcon CODEC only support some frequencies */ + if (spec->freq>=(hardfreq[CLK50K]+hardfreq[CLK33K])>>1) { + numfreq=CLK50K; /* 49170 */ + } else if (spec->freq>=(hardfreq[CLK33K]+hardfreq[CLK25K])>>1) { + numfreq=CLK33K; /* 32780 */ + } else if (spec->freq>=(hardfreq[CLK25K]+hardfreq[CLK20K])>>1) { + numfreq=CLK25K; /* 24585 */ + } else if (spec->freq>=(hardfreq[CLK20K]+hardfreq[CLK16K])>>1) { + numfreq=CLK20K; /* 19668 */ + } else if (spec->freq>=(hardfreq[CLK16K]+hardfreq[CLK12K])>>1) { + numfreq=CLK16K; /* 16390 */ + } else if (spec->freq>=(hardfreq[CLK12K]+hardfreq[CLK10K])>>1) { + numfreq=CLK12K; /* 12292 */ + } else if (spec->freq>=(hardfreq[CLK10K]+hardfreq[CLK8K])>>1) { + numfreq=CLK10K; /* 9834 */ + } else { + numfreq=CLK8K; /* 8195 */ + } + + spec->freq=hardfreq[numfreq]; +} + +static int Mint_CheckAudio_Gsxb(SDL_AudioSpec *spec) +{ + long snd_format; + int i, resolution, format_signed, format_bigendian; + + resolution = spec->format & 0x00ff; + format_signed = ((spec->format & 0x8000)!=0); + format_bigendian = ((spec->format & 0x1000)!=0); + + /* Check formats available */ + snd_format = Sndstatus(SND_QUERYFORMATS); + switch (resolution) { + case 8: + if ((snd_format & SND_FORMAT8)==0) { + SDL_SetError("Mint_CheckAudio: 8 bits samples not supported"); + return -1; + } + snd_format = Sndstatus(SND_QUERY8BIT); + break; + case 16: + if ((snd_format & SND_FORMAT16)==0) { + SDL_SetError("Mint_CheckAudio: 16 bits samples not supported"); + return -1; + } + snd_format = Sndstatus(SND_QUERY16BIT); + break; + default: + SDL_SetError("Mint_CheckAudio: Unsupported sample resolution"); + return -1; + break; + } + + /* Check signed/unsigned format */ + if (format_signed) { + if (snd_format & SND_FORMATSIGNED) { + /* Ok */ + } else if (snd_format & SND_FORMATUNSIGNED) { + /* Give unsigned format */ + spec->format = spec->format & (~0x8000); + } + } else { + if (snd_format & SND_FORMATUNSIGNED) { + /* Ok */ + } else if (snd_format & SND_FORMATSIGNED) { + /* Give signed format */ + spec->format |= 0x8000; + } + } + + if (format_bigendian) { + if (snd_format & SND_FORMATBIGENDIAN) { + /* Ok */ + } else if (snd_format & SND_FORMATLITTLEENDIAN) { + /* Give little endian format */ + spec->format = spec->format & (~0x1000); + } + } else { + if (snd_format & SND_FORMATBIGENDIAN) { + /* Ok */ + } else if (snd_format & SND_FORMATLITTLEENDIAN) { + /* Give big endian format */ + spec->format |= 0x1000; + } + } + + /* Only xbios functions available = clone with PC board */ + for (i=0;i<8;i++) { + hardfreq[i]=MASTERCLOCK_MILAN1/(MASTERPREDIV_MILAN*(i+1)); + } + + if (spec->freq>=(hardfreq[CLK_44K]+hardfreq[CLK_22K])>>1) { + numfreq = CLK_44K; /* 44100 */ + } else if (spec->freq>=(hardfreq[CLK_22K]+hardfreq[CLK_11K])>>1) { + numfreq = CLK_22K; /* 22050 */ + } else { + numfreq = CLK_11K; /* 11025 */ + } + + spec->freq=hardfreq[numfreq]; + + return 0; +} + +static void Mint_InitAudio_Dma8(SDL_AudioSpec *spec) +{ + void *oldpile; + unsigned long buffer; + unsigned char mode; + + oldpile=(void *)Super(0); + + /* Stop currently playing sound */ + DMAAUDIO_IO.control=0; + + /* Set buffer */ + buffer = (unsigned long) SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf]; + DMAAUDIO_IO.start_high = (buffer>>16) & 255; + DMAAUDIO_IO.start_mid = (buffer>>8) & 255; + DMAAUDIO_IO.start_low = buffer & 255; + + buffer += SDL_MintAudio_audiosize; + DMAAUDIO_IO.end_high = (buffer>>16) & 255; + DMAAUDIO_IO.end_mid = (buffer>>8) & 255; + DMAAUDIO_IO.end_low = buffer & 255; + + mode = numfreq; + if (spec->channels==1) { + mode |= 1<<7; + } + DMAAUDIO_IO.mode = mode; + + /* Set interrupt */ + Jdisint(MFP_DMASOUND); + Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_IntDma); + Jenabint(MFP_DMASOUND); + + /* Go */ + DMAAUDIO_IO.control = 3; /* playback + repeat */ + + Super(oldpile); +} + +static void Mint_InitAudio_Xbios(SDL_AudioSpec *spec) +{ + int channels_mode; + void *buffer; + + /* Stop currently playing sound */ + Buffoper(0); + + Settracks(0,0); + Setmontracks(0); + + switch (spec->format & 0xff) { + case 8: + if (spec->channels==2) { + channels_mode=STEREO8; + } else { + channels_mode=MONO8; + } + break; + case 16: + default: + channels_mode=STEREO16; + break; + } + Setmode(channels_mode); + + Devconnect(DMAPLAY, DAC, CLK25M, numfreq, 1); + + /* Set buffer */ + buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf]; + Setbuffer(0, buffer, buffer+SDL_MintAudio_audiosize); + + /* Install interrupt */ + Setinterrupt(SI_TIMERA, SI_PLAY); + + Jdisint(MFP_DMASOUND); + Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_IntXbios); + Jenabint(MFP_DMASOUND); + + /* Go */ + Buffoper(SB_PLA_ENA|SB_PLA_RPT); +} + +static void Mint_InitAudio_Gsxb(SDL_AudioSpec *spec) +{ + int channels_mode; + void *buffer; + + /* Stop currently playing sound */ + Buffoper(0); + + switch (spec->format & 0xff) { + case 8: + if (spec->channels==2) { + channels_mode=STEREO8; + } else { + channels_mode=MONO8; + } + break; + case 16: + if (spec->channels==2) { + channels_mode=STEREO16; + } else { + channels_mode=MONO16; + } + break; + default: + channels_mode=STEREO16; + break; + } + Setmode(channels_mode); + + Devconnect(0, 0, CLKEXT, numfreq, 1); + + /* Set buffer */ + buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf]; + Setbuffer(0, buffer, buffer+SDL_MintAudio_audiosize); + + /* Install interrupt */ + NSetinterrupt(2, SI_PLAY, SDL_MintAudio_IntGsxb); + + /* Go */ + Buffoper(SB_PLA_ENA|SB_PLA_RPT); +} + +static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec) +{ + /* Lock sound system */ + if ((cookie_snd & SND_16BIT)!=0) { + if (Locksnd()!=1) { + SDL_SetError("Mint_OpenAudio: Audio system already in use"); + return(-1); + } + } + + /* Check audio capabilities */ + if (cookie_gsxb && ((cookie_snd & (SND_GSXB|SND_16BIT))==(SND_GSXB|SND_16BIT)) ) { + if (Mint_CheckAudio_Gsxb(spec)==-1) { + return -1; + } + } else if ((cookie_snd & SND_16BIT)!=0) { + Mint_CheckAudio_Xbios(spec); + } else if ((cookie_snd & SND_8BIT)!=0) { + Mint_CheckAudio_Dma8(spec); + } + + SDL_CalculateAudioSpec(spec); + + /* Allocate memory for audio buffers in DMA-able RAM */ + spec->size = spec->samples; + spec->size *= spec->channels; + spec->size *= (spec->format & 0xFF)/8; + + SDL_MintAudio_audiosize = spec->size; + + SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(SDL_MintAudio_audiosize *2, MX_STRAM); + if (SDL_MintAudio_audiobuf[0]==NULL) { + SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer"); + return (-1); + } + SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + SDL_MintAudio_audiosize; + SDL_MintAudio_numbuf=0; + memset(SDL_MintAudio_audiobuf[0], 0, SDL_MintAudio_audiosize * 2); + SDL_MintAudio_mutex = 0; + + SDL_MintAudio_device = this; + + /* Setup audio hardware */ + if (cookie_gsxb && ((cookie_snd & (SND_GSXB|SND_16BIT))==(SND_GSXB|SND_16BIT)) ) { + Mint_InitAudio_Gsxb(spec); + } else if ((cookie_snd & SND_16BIT)!=0) { + Mint_InitAudio_Xbios(spec); + } else if ((cookie_snd & SND_8BIT)!=0) { + Mint_InitAudio_Dma8(spec); + } + + return 1; +} diff --git a/src/audio/mint/SDL_mintaudio.h b/src/audio/mint/SDL_mintaudio.h new file mode 100644 index 000000000..18cf7a447 --- /dev/null +++ b/src/audio/mint/SDL_mintaudio.h @@ -0,0 +1,15 @@ +/* + * MiNT audio driver + * + * Patrice Mandin + */ + +#ifndef _SDL_mintaudio_h +#define _SDL_mintaudio_h + +#include "SDL_sysaudio.h" + +/* Hidden "this" pointer for the audio functions */ +#define _THIS SDL_AudioDevice *this + +#endif /* _SDL_mintaudio_h */ diff --git a/src/audio/mint/SDL_mintaudiodma.h b/src/audio/mint/SDL_mintaudiodma.h new file mode 100644 index 000000000..1c31d4c2d --- /dev/null +++ b/src/audio/mint/SDL_mintaudiodma.h @@ -0,0 +1,43 @@ +/* + * STE/TT 8 bits audio dma registers + * + * Patrice Mandin + */ + +#ifndef _SDL_mintdma_h +#define _SDL_mintdma_h + +#define DMAAUDIO_IO_BASE (0xffff8900) +struct DMAAUDIO_IO_S { + unsigned char int_ctrl; + unsigned char control; + + unsigned char dummy1; + unsigned char start_high; + unsigned char dummy2; + unsigned char start_mid; + unsigned char dummy3; + unsigned char start_low; + + unsigned char dummy4; + unsigned char cur_high; + unsigned char dummy5; + unsigned char cur_mid; + unsigned char dummy6; + unsigned char cur_low; + + unsigned char dummy7; + unsigned char end_high; + unsigned char dummy8; + unsigned char end_mid; + unsigned char dummy9; + unsigned char end_low; + + unsigned char dummy10[12]; + + unsigned char track_select; /* CODEC only */ + unsigned char mode; +}; +#define DMAAUDIO_IO ((*(volatile struct DMAAUDIO_IO_S *)DMAAUDIO_IO_BASE)) + +#endif /* _SDL_mintdma_h */ diff --git a/src/audio/mint/SDL_mintaudiogsxb.h b/src/audio/mint/SDL_mintaudiogsxb.h new file mode 100644 index 000000000..488018577 --- /dev/null +++ b/src/audio/mint/SDL_mintaudiogsxb.h @@ -0,0 +1,85 @@ +/* + * GSXB audio definitions + * + * Patrice Mandin + */ + +#ifndef _SDL_mintgsxb_h +#define _SDL_mintgsxb_h + +#include /* for trap_14_xxx macros */ + +/* GSXB Cookie */ + +#define C_GSXB 0x47535842L + +/* Bit 5 in cookie _SND */ + +#define SND_GSXB (1<<5) + +/* NSoundcmd modes */ + +#define SETRATE 7 /* Set sample rate */ +#define SET8BITFORMAT 8 /* 8 bits format */ +#define SET16BITFORMAT 9 /* 16 bits format */ +#define SET24BITFORMAT 10 /* 24 bits format */ +#define SET32BITFORMAT 11 /* 32 bits format */ +#define LTATTEN_MASTER 12 /* Attenuation */ +#define RTATTEN_MASTER 13 +#define LTATTEN_MICIN 14 +#define RTATTEN_MICIN 15 +#define LTATTEN_FMGEN 16 +#define RTATTEN_FMGEN 17 +#define LTATTEN_LINEIN 18 +#define RTATTEN_LINEIN 19 +#define LTATTEN_CDIN 20 +#define RTATTEN_CDIN 21 +#define LTATTEN_VIDIN 22 +#define RTATTEN_VIDIN 23 +#define LTATTEN_AUXIN 24 +#define RTATTEN_AUXIN 25 + +/* Setmode modes */ + +#define MONO16 3 +#define STEREO24 4 +#define STEREO32 5 +#define MONO24 6 +#define MONO32 7 + +/* Sndstatus modes */ + +#define SND_QUERYFORMATS 2 +#define SND_QUERYMIXERS 3 +#define SND_QUERYSOURCES 4 +#define SND_QUERYDUPLEX 5 +#define SND_QUERY8BIT 8 +#define SND_QUERY16BIT 9 +#define SND_QUERY24BIT 10 +#define SND_QUERY32BIT 11 + +#define SND_FORMAT8 (1<<0) +#define SND_FORMAT16 (1<<1) +#define SND_FORMAT24 (1<<2) +#define SND_FORMAT32 (1<<3) + +#define SND_FORMATSIGNED (1<<0) +#define SND_FORMATUNSIGNED (1<<1) +#define SND_FORMATBIGENDIAN (1<<2) +#define SND_FORMATLITTLEENDIAN (1<<3) + +/* Devconnect prescalers */ + +#define CLK_44K 1 +#define CLK_22K 3 +#define CLK_11K 7 + +/* Extra xbios functions */ + +#define NSoundcmd(mode,data,data2) \ + (long)trap_14_wwl((short)130,(short)(mode),(short)(data),(long)(data2)) +#define NSetinterrupt(src_inter,cause,inth_addr) \ + (long)trap_14_wwwl((short)135,(short)(src_inter),(short)(cause), \ + (long)(inth_addr)) + +#endif /* _SDL_mintgsxb_h */ diff --git a/src/audio/mint/SDL_mintaudiointerrupt.S b/src/audio/mint/SDL_mintaudiointerrupt.S new file mode 100644 index 000000000..f10566af9 --- /dev/null +++ b/src/audio/mint/SDL_mintaudiointerrupt.S @@ -0,0 +1,183 @@ +/* + * Audio interrupt routines + * + * Patrice Mandin + */ + + .text + + .globl _SDL_MintAudio_Callback + + .globl _SDL_MintAudio_IntDma + .globl _SDL_MintAudio_IntXbios + .globl _SDL_MintAudio_IntGsxb + + .globl _SDL_MintAudio_mutex + .globl _SDL_MintAudio_audiobuf + .globl _SDL_MintAudio_numbuf + .globl _SDL_MintAudio_audiosize + +/* + How it works: + - Audio is playing buffer #0 (resp. #1) + - We must calculate a sample in buffer #1 (resp. #0) + so we first call the callback to do it + - Then we swap the buffers +*/ + +/*--- DMA 8 bits interrupt vector ---*/ + + .text +_SDL_MintAudio_IntDma: + + /* Check if we are not already running */ + tstw _SDL_MintAudio_mutex + bnes intdma_end + notw _SDL_MintAudio_mutex + + /* Reenable interrupts */ + movew #0x2300,sr + + /* Swap buffers */ + moveml d0-d1/a0-a1,sp@- + + movel _SDL_MintAudio_numbuf,d0 + movel _SDL_MintAudio_audiobuf,d1 + eorl #1,d0 + beqs intdma_buffer0 + movel _SDL_MintAudio_audiobuf+4,d1 +intdma_buffer0: + movel d0,_SDL_MintAudio_numbuf + + /* Callback */ + movel d1,sp@- + jsr _SDL_MintAudio_Callback + movel sp@+,d1 + + /* Modify DMA addresses */ + lea 0xffff8900:w,a0 + + moveb d1,a0@(0x07) /* Start address */ + rorl #8,d1 + moveb d1,a0@(0x05) + rorl #8,d1 + moveb d1,a0@(0x03) + swap d1 + + addl _SDL_MintAudio_audiosize,d1 + + moveb d1,a0@(0x13) /* End address */ + rorl #8,d1 + moveb d1,a0@(0x11) + rorl #8,d1 + moveb d1,a0@(0x0f) + + moveml sp@+,d0-d1/a0-a1 + + clrw _SDL_MintAudio_mutex +intdma_end: + bclr #5,0xfffffa0f:w + rte + +/*--- Xbios interrupt vector ---*/ + + .text +_SDL_MintAudio_IntXbios: + + /* Check if we are not already running */ + tstw _SDL_MintAudio_mutex + bnes intxbios_end + notw _SDL_MintAudio_mutex + + /* Reenable interrupts */ + movew #0x2300,sr + + /* Swap buffers */ + moveml d0-d2/a0-a2,sp@- + + movel _SDL_MintAudio_numbuf,d0 + movel _SDL_MintAudio_audiobuf,a0 + eorl #1,d0 + beqs intxbios_buffer0 + movel _SDL_MintAudio_audiobuf+4,a0 +intxbios_buffer0: + movel d0,_SDL_MintAudio_numbuf + + /* Callback */ + moveml a0,sp@- + jsr _SDL_MintAudio_Callback + moveml sp@+,a0 + + /* Setbuffer xbios function */ + movel _SDL_MintAudio_audiosize,d1 + lea a0@(0,d1:l),a1 + + movel a1,sp@- + movel a0,sp@- + clrw sp@- + movew #131,sp@- + trap #14 + lea sp@(12),sp + + moveml sp@+,d0-d2/a0-a2 + + clrw _SDL_MintAudio_mutex +intxbios_end: + bclr #5,0xfffffa0f:w + rte + +/*--- GSXB interrupt vector ---*/ + + .text +_SDL_MintAudio_IntGsxb: + + /* Check if we are not already running */ + tstw _SDL_MintAudio_mutex + bnes intgsxb_end + notw _SDL_MintAudio_mutex + + /* Swap buffers */ + moveml d0-d2/a0-a2,sp@- + + movel _SDL_MintAudio_numbuf,d0 + movel _SDL_MintAudio_audiobuf,a0 + eorl #1,d0 + beqs intgsxb_buffer0 + movel _SDL_MintAudio_audiobuf+4,a0 +intgsxb_buffer0: + movel d0,_SDL_MintAudio_numbuf + + /* Callback */ + moveml a0,sp@- + jsr _SDL_MintAudio_Callback + moveml sp@+,a0 + + /* Setbuffer xbios function */ + movel _SDL_MintAudio_audiosize,d1 + lea a0@(0,d1:l),a1 + + movel a1,sp@- + movel a0,sp@- + clrw sp@- + movew #131,sp@- + trap #14 + lea sp@(12),sp + + moveml sp@+,d0-d2/a0-a2 + + clrw _SDL_MintAudio_mutex +intgsxb_end: + rts + +/*--- Common variables ---*/ + + .data + .even + .comm _SDL_MintAudio_mutex,4 + .even + .comm _SDL_MintAudio_audiobuf,8 + .even + .comm _SDL_MintAudio_numbuf,4 + .even + .comm _SDL_MintAudio_audiosize,4 + diff --git a/src/audio/mint/SDL_mintaudiointerrupt_s.h b/src/audio/mint/SDL_mintaudiointerrupt_s.h new file mode 100644 index 000000000..780923ece --- /dev/null +++ b/src/audio/mint/SDL_mintaudiointerrupt_s.h @@ -0,0 +1,24 @@ +/* + * Audio interrupt + * + * Patrice Mandin + */ + +#ifndef _SDL_MINTAUDIOINTERRUPT_S_H_ +#define _SDL_MINTAUDIOINTERRUPT_S_H_ + +#include "SDL_types.h" + +/* Variables */ + +extern void *SDL_MintAudio_audiobuf[2]; /* Pointers to buffers */ +extern long SDL_MintAudio_audiosize; /* Length of audio buffer */ +extern long SDL_MintAudio_numbuf; /* Buffer to play */ +extern long SDL_MintAudio_mutex; + +/* Functions */ +void SDL_MintAudio_IntDma(void); +void SDL_MintAudio_IntXbios(void); +void SDL_MintAudio_IntGsxb(void); + +#endif /* _SDL_MINTAUDIOINTERRUPT_S_H_ */