|
|
|
|
@ -1,10 +1,6 @@ |
|
|
|
|
/* ALSA 0.5 driver for xmp
|
|
|
|
|
* Copyright (C) 2000 Tijs van Bakel and Rob Adamson |
|
|
|
|
* |
|
|
|
|
* 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. |
|
|
|
|
* |
|
|
|
|
* Fixed for ALSA 0.5 by Rob Adamson <R.Adamson@fitz.cam.ac.uk> |
|
|
|
|
* Sat, 29 Apr 2000 17:10:46 +0100 (BST) |
|
|
|
|
*/ |
|
|
|
|
@ -20,10 +16,6 @@ |
|
|
|
|
|
|
|
|
|
/* Now uses specified options - Rob Adamson, 20 Mar 2000 */ |
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H |
|
|
|
|
#include "config.h" |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#include <string.h> |
|
|
|
|
#include <stdlib.h> |
|
|
|
|
#include <stdio.h> |
|
|
|
|
@ -34,40 +26,10 @@ |
|
|
|
|
#include <unistd.h> |
|
|
|
|
#include <sys/ioctl.h> |
|
|
|
|
#include <sys/asoundlib.h> |
|
|
|
|
#include "sound.h" |
|
|
|
|
|
|
|
|
|
#include "driver.h" |
|
|
|
|
#include "mixer.h" |
|
|
|
|
|
|
|
|
|
static int init (struct context_data *ctx); |
|
|
|
|
static void dshutdown (struct context_data *); |
|
|
|
|
static void bufdump (struct context_data *, void *, int); |
|
|
|
|
static void bufwipe (void); |
|
|
|
|
static void flush (void); |
|
|
|
|
|
|
|
|
|
static void dummy() |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static char *help[] = { |
|
|
|
|
"frag=num,size", "Set the number and size (bytes) of fragments", |
|
|
|
|
"card <name>", "Select sound card to use", |
|
|
|
|
NULL |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct sound_driver sound_alsa05 = { |
|
|
|
|
"alsa05", /* driver ID */ |
|
|
|
|
"ALSA 0.5 PCM audio", /* driver description */ |
|
|
|
|
help, /* help */ |
|
|
|
|
init, /* init */ |
|
|
|
|
dshutdown, /* shutdown */ |
|
|
|
|
dummy, /* starttimer */ |
|
|
|
|
flush, /* stoptimer */ |
|
|
|
|
bufdump, /* bufdump */ |
|
|
|
|
NULL |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static snd_pcm_t *pcm_handle; |
|
|
|
|
|
|
|
|
|
static int frag_num = 4; |
|
|
|
|
static size_t frag_size = 4096; |
|
|
|
|
static char *mybuffer = NULL; |
|
|
|
|
@ -88,27 +50,24 @@ static int prepare_driver(void) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int to_fmt(struct xmp_options *o) |
|
|
|
|
static int to_fmt(struct options *options) |
|
|
|
|
{ |
|
|
|
|
int fmt; |
|
|
|
|
|
|
|
|
|
if (o->resol == 0) |
|
|
|
|
return SND_PCM_SFMT_MU_LAW; |
|
|
|
|
|
|
|
|
|
if (o->resol == 8) { |
|
|
|
|
if (options->format & XMP_FORMAT_8BIT) { |
|
|
|
|
fmt = SND_PCM_SFMT_U8 | SND_PCM_SFMT_S8; |
|
|
|
|
} else { |
|
|
|
|
fmt = SND_PCM_SFMT_S16_LE | SND_PCM_SFMT_S16_BE | |
|
|
|
|
SND_PCM_SFMT_U16_LE | SND_PCM_SFMT_U16_BE; |
|
|
|
|
|
|
|
|
|
if (o->big_endian) { |
|
|
|
|
if (is_big_endian()) { |
|
|
|
|
fmt &= SND_PCM_SFMT_S16_BE | SND_PCM_SFMT_U16_BE; |
|
|
|
|
} else { |
|
|
|
|
fmt &= SND_PCM_SFMT_S16_LE | SND_PCM_SFMT_U16_LE; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (o->outfmt & XMP_FMT_UNS) { |
|
|
|
|
if (options->format & XMP_FORMAT_UNSIGNED) { |
|
|
|
|
fmt &= SND_PCM_SFMT_U8|SND_PCM_SFMT_U16_LE|SND_PCM_SFMT_U16_BE; |
|
|
|
|
} else { |
|
|
|
|
fmt &= SND_PCM_SFMT_S8|SND_PCM_SFMT_S16_LE|SND_PCM_SFMT_S16_BE; |
|
|
|
|
@ -117,17 +76,16 @@ static int to_fmt(struct xmp_options *o) |
|
|
|
|
return fmt; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int init(struct context_data *ctx) |
|
|
|
|
static int init(struct options *options) |
|
|
|
|
{ |
|
|
|
|
struct xmp_options *o = &ctx->o; |
|
|
|
|
char **parm = options->driver_parm; |
|
|
|
|
snd_pcm_channel_params_t params; |
|
|
|
|
snd_pcm_channel_setup_t setup; |
|
|
|
|
int card = 0; |
|
|
|
|
int dev = 0; |
|
|
|
|
int rc; |
|
|
|
|
char *token, **parm; |
|
|
|
|
|
|
|
|
|
parm_init(); |
|
|
|
|
parm_init(parm); |
|
|
|
|
chkparm2("frag", "%d,%d", &frag_num, &frag_size); |
|
|
|
|
if (frag_num > 8) |
|
|
|
|
frag_num = 8; |
|
|
|
|
@ -147,14 +105,14 @@ static int init(struct context_data *ctx) |
|
|
|
|
mybuffer_nextfree = mybuffer; |
|
|
|
|
} else { |
|
|
|
|
printf("Unable to allocate memory for mixer buffer\n"); |
|
|
|
|
return XMP_ERR_DINIT; |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ((rc = |
|
|
|
|
snd_pcm_open(&pcm_handle, card, dev, SND_PCM_OPEN_PLAYBACK)) < 0) { |
|
|
|
|
printf("Unable to initialize pcm device: %s\n", |
|
|
|
|
snd_strerror(rc)); |
|
|
|
|
return XMP_ERR_DINIT; |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
memset(¶ms, 0, sizeof(snd_pcm_channel_params_t)); |
|
|
|
|
@ -175,13 +133,13 @@ static int init(struct context_data *ctx) |
|
|
|
|
|
|
|
|
|
params.format.interleave = 1; |
|
|
|
|
params.format.format = to_fmt(o); |
|
|
|
|
params.format.rate = o->freq; |
|
|
|
|
params.format.rate = options->rate; |
|
|
|
|
params.format.voices = (o->outfmt & XMP_FORMAT_MONO) ? 1 : 2; |
|
|
|
|
|
|
|
|
|
if ((rc = snd_pcm_plugin_params(pcm_handle, ¶ms)) < 0) { |
|
|
|
|
printf("Unable to set output parameters: %s\n", |
|
|
|
|
snd_strerror(rc)); |
|
|
|
|
return XMP_ERR_DINIT; |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (prepare_driver() < 0) |
|
|
|
|
@ -193,16 +151,13 @@ static int init(struct context_data *ctx) |
|
|
|
|
|
|
|
|
|
if ((rc = snd_pcm_channel_setup(pcm_handle, &setup)) < 0) { |
|
|
|
|
printf("Unable to setup channel: %s\n", snd_strerror(rc)); |
|
|
|
|
return XMP_ERR_DINIT; |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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) |
|
|
|
|
static void play(void *b, int i) |
|
|
|
|
{ |
|
|
|
|
/* Note this assumes a fragment size of (frag_size) */ |
|
|
|
|
while (i > 0) { |
|
|
|
|
@ -221,7 +176,7 @@ static void bufdump(struct context_data *ctx, void *b, int i) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void dshutdown(struct context_data *ctx) |
|
|
|
|
static void deinit() |
|
|
|
|
{ |
|
|
|
|
snd_pcm_close(pcm_handle); |
|
|
|
|
free(mybuffer); |
|
|
|
|
@ -232,3 +187,23 @@ static void flush() |
|
|
|
|
snd_pcm_plugin_flush(pcm_handle, SND_PCM_CHANNEL_PLAYBACK); |
|
|
|
|
prepare_driver(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static char *help[] = { |
|
|
|
|
"frag=num,size", "Set the number and size (bytes) of fragments", |
|
|
|
|
"card <name>", "Select sound card to use", |
|
|
|
|
NULL |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct sound_driver sound_alsa05 = { |
|
|
|
|
"alsa05", /* driver ID */ |
|
|
|
|
"ALSA 0.5 PCM audio", /* driver description */ |
|
|
|
|
help, /* help */ |
|
|
|
|
init, /* init */ |
|
|
|
|
dshutdown, /* shutdown */ |
|
|
|
|
dummy, /* starttimer */ |
|
|
|
|
flush, /* stoptimer */ |
|
|
|
|
bufdump, /* bufdump */ |
|
|
|
|
NULL |
|
|
|
|
}; |
|
|
|
|
|