diff --git a/src/sound_ahi.c b/src/sound_ahi.c index 59bbede..e15fd32 100644 --- a/src/sound_ahi.c +++ b/src/sound_ahi.c @@ -1,59 +1,128 @@ /* Amiga AHI driver for Extended Module Player - * Copyright (C) 2007 Lorence Lombardo + * Based on a MikMod driver written by Szilard Biro, which was loosely + * based on an old AmigaOS4 version by Fredrik Wikstrom. * * This file is part of the Extended Module Player and is distributed * under the terms of the GNU General Public License. See the COPYING * file for more information. */ +#ifdef __amigaos4__ +#define __USE_INLINE__ +#endif + #include -#include -#include -#include -#include #include #include "sound.h" -static int fd; +#include +#include +#include -static int init(struct options *options) -{ - char **parm = options->driver_parm; - char outfile[256]; - int nch = options->format & XMP_FORMAT_MONO ? 1 : 2; - int res = options->format & XMP_FORMAT_8BIT ? 8 : 16; - int bsize = options->rate * nch * res / 4; - - parm_init(parm); - chkparm1("buffer", bsize = strtoul(token, NULL, 0)); - parm_end(); - - sprintf(outfile, "AUDIO:B/%d/F/%d/C/%d/BUFFER/%d", - res, options->rate, nch, bsize); - - fd = open(outfile, O_WRONLY); - if (fd < 0) - return -1; - - return 0; +#define BUFFERSIZE (4 << 10) + +static struct MsgPort *AHImp = NULL; +static struct AHIRequest *AHIReq[2] = { NULL, NULL }; +static int active = 0; +static signed char *AHIBuf[2] = { NULL, NULL }; + +static void closeLibs(void) { + if (AHIReq[1]) { + AHIReq[0]->ahir_Link = NULL; /* in case we are linked to req[0] */ + if (!CheckIO((struct IORequest *) AHIReq[1])) { + AbortIO((struct IORequest *) AHIReq[1]); + WaitIO((struct IORequest *) AHIReq[1]); + } + FreeVec(AHIReq[1]); + AHIReq[1] = NULL; + } + if (AHIReq[0]) { + if (!CheckIO((struct IORequest *) AHIReq[0])) { + AbortIO((struct IORequest *) AHIReq[0]); + WaitIO((struct IORequest *) AHIReq[0]); + } + if (AHIReq[0]->ahir_Std.io_Device) { + CloseDevice((struct IORequest *) AHIReq[0]); + AHIReq[0]->ahir_Std.io_Device = NULL; + } + DeleteIORequest((struct IORequest *) AHIReq[0]); + AHIReq[0] = NULL; + } + if (AHImp) { + DeleteMsgPort(AHImp); + AHImp = NULL; + } + if (AHIBuf[0]) { + FreeVec(AHIBuf[0]); + AHIBuf[0] = NULL; + } + if (AHIBuf[1]) { + FreeVec(AHIBuf[1]); + AHIBuf[1] = NULL; + } } -static void play(void *b, int i) -{ - int j; - - while (i) { - if ((j = write(fd, b, i)) > 0) { - i -= j; - b = (char *)b + j; - } else - break; - } +static int init(struct options *options) { + AHImp = CreateMsgPort(); + if (AHImp) { + AHIReq[0] = (struct AHIRequest *)CreateIORequest(AHImp, sizeof(struct AHIRequest)); + if (AHIReq[0]) { + AHIReq[0]->ahir_Version = 4; + AHIReq[1] = AllocVec(sizeof(struct AHIRequest), MEMF_PUBLIC); + if (AHIReq[1]) { + if (!OpenDevice(AHINAME, AHI_DEFAULT_UNIT, (struct IORequest *)AHIReq[0], 0)) { + AHIReq[0]->ahir_Std.io_Command = CMD_WRITE; + AHIReq[0]->ahir_Std.io_Data = NULL; + AHIReq[0]->ahir_Std.io_Offset = 0; + AHIReq[0]->ahir_Frequency = options->rate; + AHIReq[0]->ahir_Type = (options->format & XMP_FORMAT_8BIT)? + ((options->format & XMP_FORMAT_MONO)? AHIST_M8S : AHIST_S8S ) : + ((options->format & XMP_FORMAT_MONO)? AHIST_M16S : AHIST_S16S); + AHIReq[0]->ahir_Volume = 0x10000; + AHIReq[0]->ahir_Position = 0x8000; + + CopyMem(AHIReq[0], AHIReq[1], sizeof(struct AHIRequest)); + + AHIBuf[0] = AllocVec(BUFFERSIZE, MEMF_PUBLIC | MEMF_CLEAR); + if (AHIBuf[0]) { + AHIBuf[1] = AllocVec(BUFFERSIZE, MEMF_PUBLIC | MEMF_CLEAR); + if (AHIBuf[1]) { + /* driver is initialized before calling libxmp, so this is OK : */ + options->format &= ~XMP_FORMAT_UNSIGNED;/* no unsigned with AHI */ + return 0; + } + } + } + } + } + } + + closeLibs(); + return -1; } -static void deinit(void) -{ - close(fd); +static void deinit(void) { + closeLibs(); +} + +static void play(void *b, int len) { + signed char *in = (signed char *)b; + int chunk; + while (len > 0) { + if (AHIReq[active]->ahir_Std.io_Data) { + WaitIO((struct IORequest *) AHIReq[active]); + } + chunk = (len < BUFFERSIZE)? len : BUFFERSIZE; + memcpy(AHIBuf[active], in, chunk); + len -= chunk; + in += chunk; + + AHIReq[active]->ahir_Std.io_Data = AHIBuf[active]; + AHIReq[active]->ahir_Std.io_Length = chunk; + AHIReq[active]->ahir_Link = !CheckIO((struct IORequest *) AHIReq[active ^ 1]) ? AHIReq[active ^ 1] : NULL; + SendIO((struct IORequest *)AHIReq[active]); + active ^= 1; + } } static void flush(void) @@ -68,15 +137,10 @@ static void onresume(void) { } -static const char *const help[] = { - "buffer=val", "Audio buffer size", - NULL -}; - struct sound_driver sound_ahi = { "ahi", "Amiga AHI audio", - help, + NULL, init, deinit, play,