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.
 
 
 
 
 
 

221 lines
4.5 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <dmedia/audio.h>
#include <fcntl.h>
#include "common.h"
#include "driver.h"
#include "mixer.h"
static ALport audio_port;
/* Hack to get 16 bit sound working - 19990706 bdowning */
static int al_sample_16;
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()
{
}
/*
* audio port sample rates (these are the only ones supported by the library)
*/
static int srate[] = {
48000,
44100,
32000,
22050,
16000,
11025,
8000,
0
};
static char *help[] = {
"buffer=val", "Audio buffer size",
NULL
};
struct xmp_drv_info drv_sgi = {
"sgi", /* driver ID */
"SGI PCM audio", /* driver description */
help, /* help */
init, /* init */
shutdown, /* shutdown */
dummy, /* starttimer */
dummy, /* flush */
bufdump, /* bufdump */
};
static int setaudio(struct xmp_options *o)
{
int bsize = 32 * 1024;
ALconfig config;
long pvbuffer[2];
char *token, **parm;
int i;
parm_init();
chkparm1("buffer", bsize = strtoul(token, NULL, 0));
parm_end();
if ((config = ALnewconfig()) == 0)
return XMP_ERR_DINIT;
/*
* Set sampling rate
*/
pvbuffer[0] = AL_OUTPUT_RATE;
#if 0 /* DOESN'T WORK */
for (i = 0; srate[i]; i++) {
if (srate[i] <= o->freq)
pvbuffer[1] = o->freq = srate[i];
}
#endif /* DOESN'T WORK */
/*
* This was flawed as far as I can tell - it just progressively lowered
* the sample rate to the lowest possible!
*
* o->freq = 44100
*
* i = 0 / if (48000 <= 44100)
* i = 1 / if (44100 <= 44100)
* then pvbuffer[1] = o->freq = 44100
* i = 2 / if (32000 <= 44100)
* then pvbuffer[1] = o->freq = 32000
* i = 3 / if (22050 <= 32000)
* then pvbuffer[1] = o->freq = 22050
* etc...
*
* Below is my attempt to write a new one. It picks the next highest
* rate available up to the maximum. This seems a lot more reasonable.
*
* - 19990706 bdowning
*/
for (i = 0; srate[i]; i++) ; /* find the end of the array */
while (i-- > 0) {
if (srate[i] >= o->freq) {
pvbuffer[1] = o->freq = srate[i];
break;
}
}
if (i == 0)
pvbuffer[1] = o->freq = srate[0]; /* 48 kHz. Wow! */
if (ALsetparams(AL_DEFAULT_DEVICE, pvbuffer, 2) < 0)
return XMP_ERR_DINIT;
/*
* Set sample format to signed integer
*/
if (ALsetsampfmt(config, AL_SAMPFMT_TWOSCOMP) < 0)
return XMP_ERR_DINIT;
/*
* Set sample width; 24 bit samples are not currently supported by xmp
*/
if (o->resol > 8) {
if (ALsetwidth(config, AL_SAMPLE_16) < 0) {
if (ALsetwidth(config, AL_SAMPLE_8) < 0)
return XMP_ERR_DINIT;
o->resol = 8;
} else
al_sample_16 = 1;
} else {
if (ALsetwidth(config, AL_SAMPLE_8) < 0) {
if (ALsetwidth(config, AL_SAMPLE_16) < 0)
return XMP_ERR_DINIT;
o->resol = 16;
} else
al_sample_16 = 0;
}
/*
* Set number of channels; 4 channel output is not currently supported
*/
if (o->outfmt & XMP_FORMAT_MONO) {
if (ALsetchannels(config, AL_MONO) < 0) {
if (ALsetchannels(config, AL_STEREO) < 0)
return XMP_ERR_DINIT;
o->outfmt &= ~XMP_FORMAT_MONO;
}
} else {
if (ALsetchannels(config, AL_STEREO) < 0) {
if (ALsetchannels(config, AL_MONO) < 0)
return XMP_ERR_DINIT;
o->outfmt |= XMP_FORMAT_MONO;
}
}
/*
* Set buffer size
*/
if (ALsetqueuesize(config, bsize) < 0)
return XMP_ERR_DINIT;
/*
* Open the audio port
*/
if ((audio_port = ALopenport("xmp", "w", config)) == 0)
return XMP_ERR_DINIT;
return 0;
}
static int init(struct context_data *ctx)
{
if (setaudio(&ctx->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.
*
* Apparently ALwritesamps requires the number of samples instead of
* the number of bytes, which is what I assume i is. This was a
* trial-and-error fix, but it appears to work. - 19990706 bdowning
*/
static void bufdump(struct context_data *ctx, void *b, int i)
{
if (al_sample_16)
i /= 2;
ALwritesamps(audio_port, b, i);
}
static void shutdown(struct context_data *ctx)
{
ALcloseport(audio_port);
}