|
|
|
|
@ -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 <stdlib.h> |
|
|
|
|
#include <sys/types.h> |
|
|
|
|
#include <sys/stat.h> |
|
|
|
|
#include <fcntl.h> |
|
|
|
|
#include <unistd.h> |
|
|
|
|
#include <string.h> |
|
|
|
|
#include "sound.h" |
|
|
|
|
|
|
|
|
|
static int fd; |
|
|
|
|
#include <proto/exec.h> |
|
|
|
|
#include <proto/dos.h> |
|
|
|
|
#include <devices/ahi.h> |
|
|
|
|
|
|
|
|
|
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, |
|
|
|
|
|