You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
206 lines
4.9 KiB
206 lines
4.9 KiB
/* Extended Module Player |
|
* Copyright (C) 1996-2012 Claudio Matsuoka and Hipolito Carraro Jr |
|
* |
|
* This file is part of the Extended Module Player and is distributed |
|
* under the terms of the GNU General Public License. See doc/COPYING |
|
* for more information. |
|
*/ |
|
|
|
/* CS4231 code tested on Sparc 20 and Ultra 1 running Solaris 2.5.1 |
|
* with mono/stereo, 16 bit, 22.05 kHz and 44.1 kHz using the internal |
|
* speaker and headphones. |
|
* |
|
* AMD 7930 code tested on Axil 240 running Solaris 2.5.1 and an Axil |
|
* 220 running Linux 2.0.33. |
|
*/ |
|
|
|
/* Fixed and improved by Keith Hargrove <Keith.Hargrove@Eng.Sun.COM> |
|
* Wed, 30 Jun 1999 14:23:52 -0700 (PDT) |
|
*/ |
|
|
|
#ifdef HAVE_CONFIG_H |
|
#include "config.h" |
|
#endif |
|
|
|
#include <stdlib.h> |
|
#include <unistd.h> |
|
#include <string.h> |
|
#include <sys/ioctl.h> |
|
#include <sys/types.h> |
|
#include <sys/stat.h> |
|
#include <fcntl.h> |
|
|
|
#if defined(HAVE_SYS_AUDIOIO_H) |
|
#include <sys/audioio.h> |
|
#elif defined(HAVE_SYS_AUDIO_IO_H) |
|
#include <sys/audio.io.h> |
|
#elif defined(HAVE_SUN_AUDIOIO_H) |
|
#include <sun/audioio.h> |
|
#endif |
|
#include <sys/stropts.h> |
|
|
|
/* This is for Linux on Sparc */ |
|
#if defined(HAVE_SBUS_AUDIO_AUDIO_H) |
|
#include <sbus/audio/audio.h> |
|
#endif |
|
|
|
#include "common.h" |
|
#include "driver.h" |
|
#include "mixer.h" |
|
|
|
static int audio_fd; |
|
static int audioctl_fd; |
|
|
|
static int init(struct context_data *); |
|
static int setaudio(struct xmp_options *); |
|
static void bufdump(struct context_data *, void *, int); |
|
static void shutdown(struct context_data *); |
|
|
|
static void dummy() |
|
{ |
|
} |
|
|
|
static char *help[] = { |
|
"gain=val", "Audio output gain (0 to 255)", |
|
"port={s|h|l}", "Audio port (s[peaker], h[eadphones], l[ineout])", |
|
"buffer=val", "Audio buffer size (default is 32768)", |
|
NULL |
|
}; |
|
|
|
struct xmp_drv_info drv_solaris = { |
|
"solaris", /* driver ID */ |
|
"Solaris PCM audio", /* driver description */ |
|
help, /* help */ |
|
init, /* init */ |
|
shutdown, /* shutdown */ |
|
dummy, /* starttimer */ |
|
dummy, /* flush */ |
|
bufdump, /* bufdump */ |
|
}; |
|
|
|
static int setaudio(struct xmp_options *o) |
|
{ |
|
audio_info_t ainfo, ainfo2; |
|
int gain; |
|
int bsize = 32 * 1024; |
|
int port; |
|
char *token, **parm; |
|
AUDIO_INITINFO(&ainfo); |
|
|
|
/* try to open audioctl device */ |
|
if ((audioctl_fd = open("/dev/audioctl", O_RDWR)) < 0) { |
|
fprintf(stderr, "couldn't open audioctl device\n"); |
|
close(audio_fd); |
|
return -1; |
|
} |
|
|
|
/* sleep(2); -- Really needed? */ |
|
|
|
/* empty buffers before change config */ |
|
ioctl(audio_fd, AUDIO_DRAIN, 0); /* drain everything out */ |
|
ioctl(audio_fd, I_FLUSH, FLUSHRW); /* flush everything */ |
|
ioctl(audioctl_fd, I_FLUSH, FLUSHRW); /* flush everything */ |
|
|
|
/* get audio parameters. */ |
|
if (ioctl(audioctl_fd, AUDIO_GETINFO, &ainfo) < 0) { |
|
fprintf(stderr, "AUDIO_GETINFO failed!\n"); |
|
close(audio_fd); |
|
close(audioctl_fd); |
|
return -1; |
|
} |
|
|
|
close(audioctl_fd); |
|
|
|
/* KH: Sun Dbri doesn't support 8bits linear. I dont muck with the gain |
|
* or the port setting. I hate when a program does that. There is |
|
* nothing more frustrating then having a program change your volume |
|
* and change from external speakers to the tiny one |
|
*/ |
|
|
|
gain = ainfo.play.gain; |
|
port = ainfo.play.port; |
|
|
|
parm_init(); |
|
chkparm1("gain", gain = strtoul(token, NULL, 0)); |
|
chkparm1("buffer", bsize = strtoul(token, NULL, 0)); |
|
chkparm1("port", port = (int)*token) |
|
parm_end(); |
|
|
|
switch (port) { |
|
case 'h': |
|
port = AUDIO_HEADPHONE; |
|
break; |
|
case 'l': |
|
port = AUDIO_LINE_OUT; |
|
break; |
|
case 's': |
|
port = AUDIO_SPEAKER; |
|
} |
|
|
|
if (gain < AUDIO_MIN_GAIN) |
|
gain = AUDIO_MIN_GAIN; |
|
if (gain > AUDIO_MAX_GAIN) |
|
gain = AUDIO_MAX_GAIN; |
|
|
|
AUDIO_INITINFO(&ainfo); /* For CS4231 */ |
|
AUDIO_INITINFO(&ainfo2); /* For AMD 7930 if needed */ |
|
|
|
ainfo.play.sample_rate = o->freq; |
|
ainfo.play.channels = o->outfmt & XMP_FORMAT_MONO ? 1 : 2; |
|
ainfo.play.precision = o->resol; |
|
ainfo.play.encoding = AUDIO_ENCODING_LINEAR; |
|
ainfo2.play.gain = ainfo.play.gain = gain; |
|
ainfo2.play.port = ainfo.play.port = port; |
|
ainfo2.play.buffer_size = ainfo.play.buffer_size = bsize; |
|
|
|
if (ioctl(audio_fd, AUDIO_SETINFO, &ainfo) == -1) { |
|
/* CS4231 initialization Failed, perhaps we have an AMD 7930 */ |
|
if (ioctl(audio_fd, AUDIO_SETINFO, &ainfo2) == -1) { |
|
close(audio_fd); |
|
return XMP_ERR_DINIT; |
|
} |
|
|
|
o->resol = 0; |
|
o->freq = 8000; |
|
o->outfmt |= XMP_FORMAT_MONO; |
|
drv_solaris.description = "Solaris AMD7930 PCM audio"; |
|
} else { |
|
drv_solaris.description = "Solaris CS4231 PCM audio"; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static int init(struct context_data *ctx) |
|
{ |
|
struct xmp_options *o = &ctx->o; |
|
|
|
if ((audio_fd = open("/dev/audio", O_WRONLY)) == -1) |
|
return XMP_ERR_DINIT; |
|
|
|
if (setaudio(o) != 0) |
|
return XMP_ERR_DINIT; |
|
|
|
return 0; |
|
} |
|
|
|
/* Build and write one tick (one PAL frame or 1/50 s in standard vblank |
|
* timed mods) of audio data to the output device. |
|
*/ |
|
static void bufdump(struct context_data *ctx, void *b, int i) |
|
{ |
|
int j; |
|
|
|
while (i) { |
|
if ((j = write(audio_fd, b, i)) > 0) { |
|
i -= j; |
|
b = (char *)b + j; |
|
} else |
|
break; |
|
} |
|
} |
|
|
|
static void shutdown(struct context_data *ctx) |
|
{ |
|
close(audio_fd); |
|
}
|
|
|