Make the layout more appropriate for a library-only package, move front-ends and other things not library-related out of src/ and into players/. Signed-off-by: Claudio Matsuoka <cmatsuoka@gmail.com>master
commit
3e1d8617b4
35 changed files with 6237 additions and 0 deletions
@ -0,0 +1,26 @@ |
||||
|
||||
#MAIN_OBJS = getopt.o getopt1.o options.o drivers.o main.o
|
||||
MAIN_OBJS = sound_alsa.o terminal.o info.o options.o main.o
|
||||
MAIN_DFILES = Makefile $(MAIN_OBJS:.o=.c)
|
||||
MAIN_PATH = players/xmp
|
||||
|
||||
dist-main: |
||||
mkdir -p $(DIST)/$(MAIN_PATH)
|
||||
cp -RPp $(addprefix $(MAIN_PATH)/,$(MAIN_DFILES)) $(DIST)/$(MAIN_PATH)
|
||||
|
||||
$(MAIN_PATH)/options.o: Makefile |
||||
|
||||
M_OBJS = $(addprefix $(MAIN_PATH)/,$(MAIN_OBJS))
|
||||
|
||||
$(MAIN_PATH)/xmp: $(M_OBJS) $(LIB) |
||||
@CMD='$(LD) -o $@ $(LDFLAGS) $(M_OBJS) -Llib -lxmp -lm -lasound'; \
|
||||
if [ "$(V)" -gt 0 ]; then echo $$CMD; else echo LD $@ ; fi; \
|
||||
eval $$CMD
|
||||
|
||||
$(M_OBJS): $(LIB) |
||||
|
||||
install-xmp: $(MAIN_PATH)/xmp |
||||
@echo Installing xmp in $(DESTDIR)$(BINDIR)
|
||||
@[ -d $(DESTDIR)$(BINDIR) ] || mkdir -p $(DESTDIR)$(BINDIR)
|
||||
@$(INSTALL_PROGRAM) $+ $(DESTDIR)$(BINDIR)
|
||||
|
||||
@ -0,0 +1,19 @@ |
||||
|
||||
struct options { |
||||
int start; /* start order */ |
||||
int amplify; /* amplification factor */ |
||||
int freq; /* sampling rate */ |
||||
int format; /* sample format */ |
||||
int time; /* max. replay time */ |
||||
int mix; /* channel separation */ |
||||
int loop; /* loop module */ |
||||
int random; /* play in random order */ |
||||
int load_only; /* load module and exit */ |
||||
char *out_file; /* output file name */ |
||||
char *ins_path; /* instrument path */ |
||||
char mute[XMP_MAX_CHANNELS]; |
||||
}; |
||||
|
||||
int set_tty(void); |
||||
int reset_tty(void); |
||||
|
||||
@ -0,0 +1,106 @@ |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include "xmp.h" |
||||
|
||||
extern struct xmp_drv_info drv_file; |
||||
extern struct xmp_drv_info drv_wav; |
||||
extern struct xmp_drv_info drv_osx; |
||||
extern struct xmp_drv_info drv_solaris; |
||||
extern struct xmp_drv_info drv_hpux; |
||||
extern struct xmp_drv_info drv_bsd; |
||||
extern struct xmp_drv_info drv_netbsd; |
||||
extern struct xmp_drv_info drv_openbsd; |
||||
extern struct xmp_drv_info drv_sndio; |
||||
extern struct xmp_drv_info drv_sgi; |
||||
extern struct xmp_drv_info drv_aix; |
||||
extern struct xmp_drv_info drv_oss_seq; |
||||
extern struct xmp_drv_info drv_oss; |
||||
extern struct xmp_drv_info drv_alsa; |
||||
extern struct xmp_drv_info drv_alsa05; |
||||
extern struct xmp_drv_info drv_net; |
||||
extern struct xmp_drv_info drv_esd; |
||||
extern struct xmp_drv_info drv_arts; |
||||
extern struct xmp_drv_info drv_nas; |
||||
extern struct xmp_drv_info drv_pulseaudio; |
||||
extern struct xmp_drv_info drv_os2dart; |
||||
extern struct xmp_drv_info drv_qnx; |
||||
extern struct xmp_drv_info drv_beos; |
||||
extern struct xmp_drv_info drv_amiga; |
||||
extern struct xmp_drv_info drv_win32; |
||||
|
||||
|
||||
void init_drivers() |
||||
{ |
||||
#ifdef DRIVER_OSX |
||||
xmp_drv_register(&drv_osx); |
||||
#endif |
||||
#ifdef DRIVER_WIN32 |
||||
xmp_drv_register(&drv_win32); |
||||
#endif |
||||
#ifdef DRIVER_SOLARIS |
||||
xmp_drv_register(&drv_solaris); |
||||
#endif |
||||
#ifdef DRIVER_HPUX |
||||
xmp_drv_register(&drv_hpux); |
||||
#endif |
||||
#ifdef DRIVER_BSD |
||||
xmp_drv_register(&drv_bsd); |
||||
#endif |
||||
#ifdef DRIVER_NETBSD |
||||
xmp_drv_register(&drv_netbsd); |
||||
#endif |
||||
#ifdef DRIVER_SNDIO |
||||
xmp_drv_register(&drv_sndio); |
||||
#endif |
||||
#ifdef DRIVER_OPENBSD |
||||
xmp_drv_register(&drv_openbsd); |
||||
#endif |
||||
#ifdef DRIVER_SGI |
||||
xmp_drv_register(&drv_sgi); |
||||
#endif |
||||
#ifdef DRIVER_OSS_SEQ |
||||
xmp_drv_register(&drv_oss_seq); |
||||
#endif |
||||
#ifdef DRIVER_OSS |
||||
xmp_drv_register(&drv_oss); |
||||
#endif |
||||
#ifdef DRIVER_ALSA |
||||
xmp_drv_register(&drv_alsa); |
||||
#endif |
||||
#ifdef DRIVER_ALSA05 |
||||
xmp_drv_register(&drv_alsa05); |
||||
#endif |
||||
#ifdef DRIVER_QNX |
||||
xmp_drv_register(&drv_qnx); |
||||
#endif |
||||
#ifdef DRIVER_BEOS |
||||
xmp_drv_register(&drv_beos); |
||||
#endif |
||||
#ifdef DRIVER_AMIGA |
||||
xmp_drv_register(&drv_amiga); |
||||
#endif |
||||
#ifdef DRIVER_NET |
||||
xmp_drv_register(&drv_net); |
||||
#endif |
||||
#ifdef DRIVER_OS2DART |
||||
xmp_drv_register(&drv_os2dart); |
||||
#endif |
||||
#ifdef DRIVER_PULSEAUDIO |
||||
xmp_drv_register(&drv_pulseaudio); |
||||
#endif |
||||
#ifdef DRIVER_ARTS |
||||
xmp_drv_register(&drv_arts); |
||||
#endif |
||||
#ifdef DRIVER_ESD |
||||
xmp_drv_register(&drv_esd); |
||||
#endif |
||||
#ifdef DRIVER_NAS |
||||
xmp_drv_register(&drv_nas); |
||||
#endif |
||||
xmp_drv_register(&drv_file); |
||||
xmp_drv_register(&drv_wav); |
||||
} |
||||
|
||||
@ -0,0 +1,26 @@ |
||||
|
||||
DRV = file.c oss.c hpux.c bsd.c solaris.c alsa.c alsa05.c \
|
||||
sgi.c os2_dart.c netbsd.c openbsd.c aix.c qnx.c \
|
||||
win32.c smix.c wav.c osx.c beos.c pulseaudio.c amiga.c sndio.c
|
||||
|
||||
DRIVERS_OBJS = file.o wav.o
|
||||
DRIVERS_LOBJS = smix.lo
|
||||
DRIVERS_DFILES = Makefile $(DRV) debug.c
|
||||
DRIVERS_PATH = src/drivers
|
||||
|
||||
# Don't include platform-specific drivers in DRIVERS_OBJS so we can generate
|
||||
# foreign makefiles from it (such as MSVC .dsp files, etc)
|
||||
|
||||
D_OBJS = $(addprefix $(DRIVERS_PATH)/,$(DRIVERS_OBJS) $(DRIVERS))
|
||||
D_LOBJS = $(addprefix $(DRIVERS_PATH)/,$(DRIVERS_LOBJS))
|
||||
|
||||
dist-drivers: |
||||
mkdir -p $(DIST)/$(DRIVERS_PATH)
|
||||
cp -RPp $(addprefix $(DRIVERS_PATH)/,$(DRIVERS_DFILES)) $(DIST)/$(DRIVERS_PATH)
|
||||
|
||||
$(DRIVERS_PATH)/beos.o: src/drivers/beos.c |
||||
g++ -c $(XCFLAGS) -o $@ $+
|
||||
|
||||
$(DRIVERS_PATH)/arts.o: src/drivers/arts.c |
||||
$(CC) $(CFLAGS) $(XCFLAGS) `artsc-config --cflags` -o $@ $+
|
||||
|
||||
@ -0,0 +1,153 @@ |
||||
/* 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. |
||||
*/ |
||||
|
||||
/*
|
||||
* Based on the AIX XMMS output plugin by Peter Alm, Thomas Nilsson |
||||
* and Olle Hallnas. |
||||
*/ |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include <sys/types.h> |
||||
#include <sys/param.h> |
||||
#include <sys/audio.h> |
||||
#include <sys/ioctl.h> |
||||
#include <sys/stat.h> |
||||
|
||||
#include <fcntl.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <unistd.h> |
||||
|
||||
#include "common.h" |
||||
#include "driver.h" |
||||
#include "mixer.h" |
||||
|
||||
static int audio_fd; |
||||
static audio_control control; |
||||
static audio_change change; |
||||
|
||||
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)", |
||||
/* "buffer=val", "Audio buffer size (default is 32768)", */ |
||||
NULL |
||||
}; |
||||
|
||||
struct xmp_drv_info drv_bsd = { |
||||
"aix", /* driver ID */ |
||||
"AIX PCM audio", /* driver description */ |
||||
help, /* help */ |
||||
init, /* init */ |
||||
shutdown, /* shutdown */ |
||||
dummy, /* starttimer */ |
||||
dummy, /* stoptimer */ |
||||
bufdump, /* bufdump */ |
||||
NULL |
||||
}; |
||||
|
||||
#define AUDIO_MIN_GAIN 0 |
||||
#define AUDIO_MAX_GAIN 100 |
||||
|
||||
static int setaudio(struct xmp_options *o) |
||||
{ |
||||
audio_init ainit; |
||||
int gain = 128; |
||||
int bsize = 32 * 1024; |
||||
char *token, **parm; |
||||
|
||||
parm_init(); |
||||
chkparm1("gain", gain = strtoul(token, NULL, 0)); |
||||
/* chkparm1 ("buffer", bsize = strtoul(token, NULL, 0)); */ |
||||
parm_end(); |
||||
|
||||
if (gain < AUDIO_MIN_GAIN) |
||||
gain = AUDIO_MIN_GAIN; |
||||
if (gain > AUDIO_MAX_GAIN) |
||||
gain = AUDIO_MAX_GAIN; |
||||
|
||||
init.mode = PCM; /* audio format */ |
||||
init.srate = o->freq; /* sample rate */ |
||||
init.operation = PLAY; /* PLAY or RECORD */ |
||||
init.channels = o->outfmt & XMP_FORMAT_MONO ? 1 : 2; |
||||
init.bits_per_sample = o->resol; /* bits per sample */ |
||||
init.flags = BIG_ENDIAN | TWOS_COMPLEMENT; |
||||
|
||||
if (ioctl(audio_fd, AUDIO_INIT, &init) < 0) { |
||||
close(audio_fd); |
||||
return XMP_ERR_DINIT; |
||||
} |
||||
|
||||
/* full blast; range: 0-0x7fffffff */ |
||||
change.volume = 0x7fffffff * (1.0 * gain / 200.0); |
||||
change.monitor = AUDIO_IGNORE; /* monitor what's recorded ? */ |
||||
change.input = AUDIO_IGNORE; /* input to record from */ |
||||
change.output = OUTPUT_1; /* line-out */ |
||||
change.balance = 0x3FFFFFFF; |
||||
|
||||
control.ioctl_request = AUDIO_CHANGE; |
||||
control.request_info = (char *)&change; |
||||
if (ioctl(audio_fd, AUDIO_CONTROL, &control) < 0) { |
||||
close(audio_fd); |
||||
return XMP_ERR_DINIT; |
||||
} |
||||
|
||||
/* start playback - won't actually start until write() calls occur */ |
||||
control.ioctl_request = AUDIO_START; |
||||
control.position = 0; |
||||
if (ioctl(audio_fd, AUDIO_CONTROL, &control) < 0) { |
||||
close(audio_fd); |
||||
return XMP_ERR_DINIT; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int init(struct context_data *ctx) |
||||
{ |
||||
if ((audio_fd = open("/dev/paud0/1", O_WRONLY)) == -1) |
||||
return XMP_ERR_DINIT; |
||||
|
||||
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. |
||||
*/ |
||||
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; |
||||
(char *)b += j; |
||||
} else |
||||
break; |
||||
}; |
||||
} |
||||
|
||||
static void shutdown(struct context_data *ctx) |
||||
{ |
||||
control.ioctl_request = AUDIO_STOP; |
||||
ioctl(audio_fd, AUDIO_CONTROL, &control); |
||||
close(audio_fd); |
||||
} |
||||
@ -0,0 +1,175 @@ |
||||
/* ALSA driver for xmp
|
||||
* Copyright (C) 2005-2007 Claudio Matsuoka and Hipolito Carraro Jr |
||||
* Based on the 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. |
||||
*/ |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <sys/time.h> |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#include <fcntl.h> |
||||
#include <unistd.h> |
||||
#include <sys/ioctl.h> |
||||
#include <alsa/asoundlib.h> |
||||
#include <alsa/pcm.h> |
||||
|
||||
#include "driver.h" |
||||
|
||||
static int init (struct context_data *); |
||||
static int prepare_driver (void); |
||||
static void dshutdown (struct context_data *); |
||||
static int to_fmt (struct xmp_options *); |
||||
static void bufdump (struct context_data *, void *, int); |
||||
static void flush (void); |
||||
|
||||
static void dummy () { } |
||||
|
||||
static char *help[] = { |
||||
"buffer=num", "Set the ALSA buffer time in milliseconds", |
||||
"period=num", "Set the ALSA period time in milliseconds", |
||||
"card <name>", "Select sound card to use", |
||||
NULL |
||||
}; |
||||
|
||||
struct xmp_drv_info drv_alsa = { |
||||
"alsa", /* driver ID */ |
||||
"ALSA PCM audio", /* driver description */ |
||||
help, /* help */ |
||||
init, /* init */ |
||||
dshutdown, /* shutdown */ |
||||
dummy, /* starttimer */ |
||||
flush, /* stoptimer */ |
||||
bufdump, /* bufdump */ |
||||
}; |
||||
|
||||
static snd_pcm_t *pcm_handle; |
||||
|
||||
|
||||
static int init(struct context_data *ctx) |
||||
{ |
||||
snd_pcm_hw_params_t *hwparams; |
||||
int ret; |
||||
char *token, **parm; |
||||
unsigned int channels, rate; |
||||
unsigned int btime = 250000; /* 250ms */ |
||||
unsigned int ptime = 50000; /* 50ms */ |
||||
char *card_name = "default"; |
||||
struct xmp_options *o = &ctx->o; |
||||
|
||||
parm_init();
|
||||
chkparm1("buffer", btime = 1000 * strtoul(token, NULL, 0)); |
||||
chkparm1("period", btime = 1000 * strtoul(token, NULL, 0)); |
||||
chkparm1("card", card_name = token); |
||||
parm_end(); |
||||
|
||||
if ((ret = snd_pcm_open(&pcm_handle, card_name, |
||||
SND_PCM_STREAM_PLAYBACK, 0)) < 0) { |
||||
fprintf(stderr, "Unable to initialize ALSA pcm device: %s\n", |
||||
snd_strerror(ret)); |
||||
return XMP_ERR_DINIT; |
||||
} |
||||
|
||||
channels = (o->outfmt & XMP_FORMAT_MONO) ? 1 : 2; |
||||
rate = o->freq; |
||||
|
||||
snd_pcm_hw_params_alloca(&hwparams); |
||||
snd_pcm_hw_params_any(pcm_handle, hwparams); |
||||
snd_pcm_hw_params_set_access(pcm_handle, hwparams, |
||||
SND_PCM_ACCESS_RW_INTERLEAVED); |
||||
snd_pcm_hw_params_set_format(pcm_handle, hwparams, to_fmt(o)); |
||||
snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &rate, 0); |
||||
snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &channels); |
||||
snd_pcm_hw_params_set_buffer_time_near(pcm_handle, hwparams, &btime, 0); |
||||
snd_pcm_hw_params_set_period_time_near(pcm_handle, hwparams, &ptime, 0); |
||||
snd_pcm_nonblock(pcm_handle, 0); |
||||
|
||||
if ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) { |
||||
fprintf(stderr, "Unable to set ALSA output parameters: %s\n", |
||||
snd_strerror(ret)); |
||||
return XMP_ERR_DINIT; |
||||
} |
||||
|
||||
if (prepare_driver() < 0) |
||||
return XMP_ERR_DINIT; |
||||
|
||||
o->freq = rate; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int prepare_driver() |
||||
{ |
||||
int ret; |
||||
|
||||
if ((ret = snd_pcm_prepare(pcm_handle)) < 0 ) { |
||||
fprintf(stderr, "Unable to prepare ALSA: %s\n", |
||||
snd_strerror(ret)); |
||||
return ret; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int to_fmt(struct xmp_options *o) |
||||
{ |
||||
int fmt; |
||||
|
||||
switch (o->resol) { |
||||
case 0: |
||||
return SND_PCM_FORMAT_MU_LAW; |
||||
case 8: |
||||
fmt = SND_PCM_FORMAT_U8 | SND_PCM_FORMAT_S8; |
||||
break; |
||||
default: |
||||
if (o->big_endian) { |
||||
fmt = SND_PCM_FORMAT_S16_BE | SND_PCM_FORMAT_U16_BE; |
||||
} else { |
||||
fmt = SND_PCM_FORMAT_S16_LE | SND_PCM_FORMAT_U16_LE; |
||||
} |
||||
} |
||||
|
||||
if (o->outfmt & XMP_FMT_UNS) { |
||||
fmt &= SND_PCM_FORMAT_U8 | SND_PCM_FORMAT_U16_LE | |
||||
SND_PCM_FORMAT_U16_BE; |
||||
} else { |
||||
fmt &= SND_PCM_FORMAT_S8 | SND_PCM_FORMAT_S16_LE | |
||||
SND_PCM_FORMAT_S16_BE; |
||||
} |
||||
|
||||
return fmt; |
||||
} |
||||
|
||||
/* 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 frames; |
||||
|
||||
frames = snd_pcm_bytes_to_frames(pcm_handle, i); |
||||
if (snd_pcm_writei(pcm_handle, b, frames) < 0) { |
||||
snd_pcm_prepare(pcm_handle); |
||||
} |
||||
} |
||||
|
||||
static void dshutdown(struct context_data *ctx) |
||||
{ |
||||
snd_pcm_close(pcm_handle); |
||||
} |
||||
|
||||
static void flush() |
||||
{ |
||||
snd_pcm_drain(pcm_handle); |
||||
prepare_driver(); |
||||
} |
||||
@ -0,0 +1,234 @@ |
||||
/* 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) |
||||
*/ |
||||
|
||||
/* preliminary alsa 0.5 support, Tijs van Bakel, 02-03-2000.
|
||||
* only default values are supported and music sounds chunky |
||||
*/ |
||||
|
||||
/* Better ALSA 0.5 support, Rob Adamson, 16 Mar 2000.
|
||||
* Again, hard-wired fragment size & number and sample rate, |
||||
* but it plays smoothly now. |
||||
*/ |
||||
|
||||
/* 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> |
||||
#include <sys/time.h> |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#include <fcntl.h> |
||||
#include <unistd.h> |
||||
#include <sys/ioctl.h> |
||||
#include <sys/asoundlib.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 xmp_drv_info drv_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; |
||||
static char *mybuffer_nextfree = NULL; |
||||
static char *card_name; |
||||
|
||||
|
||||
static int prepare_driver(void) |
||||
{ |
||||
int rc; |
||||
|
||||
rc = snd_pcm_plugin_prepare(pcm_handle, SND_PCM_CHANNEL_PLAYBACK); |
||||
if (rc < 0) { |
||||
printf("Unable to prepare plugin: %s\n", snd_strerror(rc)); |
||||
return rc; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int to_fmt(struct xmp_options *o) |
||||
{ |
||||
int fmt; |
||||
|
||||
if (o->resol == 0) |
||||
return SND_PCM_SFMT_MU_LAW; |
||||
|
||||
if (o->resol == 8) { |
||||
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) { |
||||
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) { |
||||
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; |
||||
} |
||||
|
||||
return fmt; |
||||
} |
||||
|
||||
static int init(struct context_data *ctx) |
||||
{ |
||||
struct xmp_options *o = &ctx->o; |
||||
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(); |
||||
chkparm2("frag", "%d,%d", &frag_num, &frag_size); |
||||
if (frag_num > 8) |
||||
frag_num = 8; |
||||
if (frag_num < 4) |
||||
frag_num = 4; |
||||
if (frag_size > 65536) |
||||
frag_size = 65536; |
||||
if (frag_size < 16) |
||||
frag_size = 16; |
||||
chkparm1("card", card_name = token); |
||||
// card = snd_card_name(card_name); /* ? */
|
||||
// dev = snd_defaults_pcm_device(); /* ? */
|
||||
parm_end(); |
||||
|
||||
mybuffer = malloc(frag_size); |
||||
if (mybuffer) { |
||||
mybuffer_nextfree = mybuffer; |
||||
} else { |
||||
printf("Unable to allocate memory for mixer buffer\n"); |
||||
return XMP_ERR_DINIT; |
||||
} |
||||
|
||||
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; |
||||
} |
||||
|
||||
memset(¶ms, 0, sizeof(snd_pcm_channel_params_t)); |
||||
|
||||
params.mode = SND_PCM_MODE_BLOCK; |
||||
params.buf.block.frag_size = frag_size; |
||||
params.buf.block.frags_min = 1; |
||||
params.buf.block.frags_max = frag_num; |
||||
|
||||
//params.mode = SND_PCM_MODE_STREAM;
|
||||
//params.buf.stream.queue_size = 16384;
|
||||
//params.buf.stream.fill = SND_PCM_FILL_NONE;
|
||||
//params.buf.stream.max_fill = 0;
|
||||
|
||||
params.channel = SND_PCM_CHANNEL_PLAYBACK; |
||||
params.start_mode = SND_PCM_START_FULL; |
||||
params.stop_mode = SND_PCM_STOP_ROLLOVER; |
||||
|
||||
params.format.interleave = 1; |
||||
params.format.format = to_fmt(o); |
||||
params.format.rate = o->freq; |
||||
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; |
||||
} |
||||
|
||||
if (prepare_driver() < 0) |
||||
return XMP_ERR_DINIT; |
||||
|
||||
memset(&setup, 0, sizeof(setup)); |
||||
setup.mode = SND_PCM_MODE_STREAM; |
||||
setup.channel = SND_PCM_CHANNEL_PLAYBACK; |
||||
|
||||
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 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) |
||||
{ |
||||
/* Note this assumes a fragment size of (frag_size) */ |
||||
while (i > 0) { |
||||
size_t f = (frag_size) - (mybuffer_nextfree - mybuffer); |
||||
size_t to_copy = (f < i) ? f : i; |
||||
|
||||
memcpy(mybuffer_nextfree, b, to_copy); |
||||
b += to_copy; |
||||
mybuffer_nextfree += to_copy; |
||||
f -= to_copy; |
||||
i -= to_copy; |
||||
if (f == 0) { |
||||
snd_pcm_plugin_write(pcm_handle, mybuffer, frag_size); |
||||
mybuffer_nextfree = mybuffer; |
||||
} |
||||
} |
||||
} |
||||
|
||||
static void dshutdown(struct context_data *ctx) |
||||
{ |
||||
snd_pcm_close(pcm_handle); |
||||
free(mybuffer); |
||||
} |
||||
|
||||
static void flush() |
||||
{ |
||||
snd_pcm_plugin_flush(pcm_handle, SND_PCM_CHANNEL_PLAYBACK); |
||||
prepare_driver(); |
||||
} |
||||
@ -0,0 +1,90 @@ |
||||
/* Amiga AHI driver for Extended Module Player
|
||||
* Copyright (C) 2007 Lorence Lombardo |
||||
* |
||||
* 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 <stdlib.h> |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#include <fcntl.h> |
||||
#include <unistd.h> |
||||
#include <string.h> |
||||
|
||||
#include "common.h" |
||||
#include "driver.h" |
||||
#include "mixer.h" |
||||
#include "convert.h" |
||||
|
||||
static int fd; |
||||
|
||||
static int init(struct context_data *); |
||||
static void bufdump(struct context_data *, void *, int); |
||||
static void shutdown(struct context_data *); |
||||
|
||||
static void dummy() |
||||
{ |
||||
} |
||||
|
||||
static char *help[] = { |
||||
"buffer=val", "Audio buffer size", |
||||
NULL |
||||
}; |
||||
|
||||
struct xmp_drv_info drv_amiga = { |
||||
"ahi", /* driver ID */ |
||||
"Amiga AHI audio", /* driver description */ |
||||
help, /* help */ |
||||
init, /* init */ |
||||
shutdown, /* shutdown */ |
||||
dummy, /* starttimer */ |
||||
dummy, /* stoptimer */ |
||||
dummy, /* resetvoices */ |
||||
bufdump, /* bufdump */ |
||||
NULL |
||||
}; |
||||
|
||||
static int init(struct context_data *ctx) |
||||
{ |
||||
struct xmp_options *o = &ctx->o; |
||||
char outfile[256]; |
||||
int nch = o->outfmt & XMP_FORMAT_MONO ? 1 : 2; |
||||
int bsize = o->freq * nch * o->resol / 4; |
||||
char *token, **parm; |
||||
|
||||
parm_init(); |
||||
chkparm1("buffer", bsize = strtoul(token, NULL, 0)); |
||||
parm_end(); |
||||
|
||||
sprintf(outfile, "AUDIO:B/%d/F/%d/C/%d/BUFFER/%d", |
||||
o->resol, o->freq, nch, bsize); |
||||
|
||||
fd = open(outfile, O_WRONLY); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static void bufdump(struct context_data *ctx, void *b, int i) |
||||
{ |
||||
int j; |
||||
|
||||
while (i) { |
||||
if ((j = write(fd, b, i)) > 0) { |
||||
i -= j; |
||||
b = (char *)b + j; |
||||
} else |
||||
break; |
||||
} |
||||
} |
||||
|
||||
static void shutdown(struct context_data *ctx) |
||||
{ |
||||
if (fd) |
||||
close(fd); |
||||
} |
||||
@ -0,0 +1,230 @@ |
||||
/* 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 <Application.h> |
||||
#include <SoundPlayer.h> |
||||
|
||||
#define B_AUDIO_CHAR 1 |
||||
#define B_AUDIO_SHORT 2 |
||||
|
||||
extern "C" { |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
|
||||
#include "xmp.h" |
||||
|
||||
/* g++ doesn't like typedef xmp_context and struct context_data */ |
||||
#define xmp_context _xmp_context |
||||
#include "common.h" |
||||
|
||||
#include "driver.h" |
||||
#include "mixer.h" |
||||
} |
||||
|
||||
static int init (struct context_data *ctx); |
||||
static void bufdump (struct context_data *, void *, int); |
||||
static void myshutdown (struct context_data *); |
||||
|
||||
static void dummy() |
||||
{ |
||||
} |
||||
|
||||
static char *help[] = { |
||||
"buffer=num,size", "set the number and size of buffer fragments", |
||||
NULL |
||||
}; |
||||
|
||||
struct xmp_drv_info drv_beos = { |
||||
"beos", /* driver ID */ |
||||
"BeOS PCM audio", /* driver description */ |
||||
NULL, /* help */ |
||||
(int (*)())init, /* init */ |
||||
(void (*)())myshutdown, /* shutdown */ |
||||
dummy, /* starttimer */ |
||||
dummy, /* flush */ |
||||
(void (*)())bufdump, /* bufdump */ |
||||
}; |
||||
|
||||
static media_raw_audio_format fmt; |
||||
static BSoundPlayer *player; |
||||
|
||||
|
||||
/*
|
||||
* CoreAudio helpers from mplayer/libao |
||||
* The player fills a ring buffer, BSP retrieves data from the buffer |
||||
*/ |
||||
|
||||
static int paused; |
||||
static uint8 *buffer; |
||||
static int buffer_len; |
||||
static int buf_write_pos; |
||||
static int buf_read_pos; |
||||
static int chunk_size; |
||||
static int chunk_num; |
||||
static int packet_size; |
||||
|
||||
|
||||
/* return minimum number of free bytes in buffer, value may change between
|
||||
* two immediately following calls, and the real number of free bytes |
||||
* might actually be larger! */ |
||||
static int buf_free() |
||||
{ |
||||
int free = buf_read_pos - buf_write_pos - chunk_size; |
||||
if (free < 0) |
||||
free += buffer_len; |
||||
return free; |
||||
} |
||||
|
||||
/* return minimum number of buffered bytes, value may change between
|
||||
* two immediately following calls, and the real number of buffered bytes |
||||
* might actually be larger! */ |
||||
static int buf_used() |
||||
{ |
||||
int used = buf_write_pos - buf_read_pos; |
||||
if (used < 0) |
||||
used += buffer_len; |
||||
return used; |
||||
} |
||||
|
||||
/* add data to ringbuffer */ |
||||
static int write_buffer(unsigned char *data, int len) |
||||
{ |
||||
int first_len = buffer_len - buf_write_pos; |
||||
int free = buf_free(); |
||||
|
||||
if (len > free) |
||||
len = free; |
||||
if (first_len > len) |
||||
first_len = len; |
||||
|
||||
/* till end of buffer */ |
||||
memcpy(buffer + buf_write_pos, data, first_len); |
||||
if (len > first_len) { /* we have to wrap around */ |
||||
/* remaining part from beginning of buffer */ |
||||
memcpy(buffer, data + first_len, len - first_len); |
||||
} |
||||
buf_write_pos = (buf_write_pos + len) % buffer_len; |
||||
|
||||
return len; |
||||
} |
||||
|
||||
/* remove data from ringbuffer */ |
||||
static int read_buffer(unsigned char *data, int len) |
||||
{ |
||||
int first_len = buffer_len - buf_read_pos; |
||||
int buffered = buf_used(); |
||||
|
||||
if (len > buffered) |
||||
len = buffered; |
||||
if (first_len > len) |
||||
first_len = len; |
||||
|
||||
/* till end of buffer */ |
||||
memcpy(data, buffer + buf_read_pos, first_len); |
||||
if (len > first_len) { /* we have to wrap around */ |
||||
/* remaining part from beginning of buffer */ |
||||
memcpy(data + first_len, buffer, len - first_len); |
||||
} |
||||
buf_read_pos = (buf_read_pos + len) % buffer_len; |
||||
|
||||
return len; |
||||
} |
||||
|
||||
/*
|
||||
* end of CoreAudio helpers |
||||
*/ |
||||
|
||||
|
||||
void render_proc(void *theCookie, void *buffer, size_t req,
|
||||
const media_raw_audio_format &format) |
||||
{
|
||||
int amt; |
||||
|
||||
while ((amt = buf_used()) < req) |
||||
snooze(100000); |
||||
|
||||
read_buffer((unsigned char *)buffer, req); |
||||
} |
||||
|
||||
|
||||
static int init(struct context_data *ctx) |
||||
{ |
||||
struct xmp_options *o = &ctx->o; |
||||
char *dev; |
||||
char *token, **parm; |
||||
static char desc[80]; |
||||
|
||||
be_app = new BApplication("application/x-vnd.cm-xmp"); |
||||
|
||||
chunk_size = 4096; |
||||
chunk_num = 20; |
||||
|
||||
parm_init(); |
||||
chkparm2("buffer", "%d,%d", &chunk_num, &chunk_size); |
||||
parm_end(); |
||||
|
||||
snprintf(desc, 80, "%s [%d fragments of %d bytes]", |
||||
drv_beos.description, chunk_num, chunk_size); |
||||
drv_beos.description = desc; |
||||
|
||||
fmt.frame_rate = o->freq; |
||||
fmt.channel_count = o->outfmt & XMP_FORMAT_MONO ? 1 : 2; |
||||
fmt.format = o->resol > 8 ? B_AUDIO_SHORT : B_AUDIO_CHAR; |
||||
fmt.byte_order = B_HOST_IS_LENDIAN ? |
||||
B_MEDIA_LITTLE_ENDIAN : B_MEDIA_BIG_ENDIAN; |
||||
fmt.buffer_size = chunk_size * chunk_num; |
||||
|
||||
buffer_len = chunk_size * chunk_num; |
||||
buffer = (uint8 *)calloc(1, buffer_len); |
||||
buf_read_pos = 0; |
||||
buf_write_pos = 0; |
||||
paused = 1; |
||||
|
||||
player = new BSoundPlayer(&fmt, "xmp output", render_proc); |
||||
|
||||
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 = 0; |
||||
|
||||
/* block until we have enough free space in the buffer */ |
||||
while (buf_free() < i) |
||||
snooze(100000); |
||||
|
||||
while (i) { |
||||
if ((j = write_buffer((uint8 *)b, i)) > 0) { |
||||
i -= j; |
||||
b += j; |
||||
} else |
||||
break; |
||||
} |
||||
|
||||
if (paused) { |
||||
player->Start();
|
||||
player->SetHasData(true); |
||||
paused = 0; |
||||
} |
||||
} |
||||
|
||||
static void myshutdown(struct context_data *ctx) |
||||
{ |
||||
player->Stop();
|
||||
be_app->Lock(); |
||||
be_app->Quit(); |
||||
} |
||||
|
||||
@ -0,0 +1,123 @@ |
||||
/* 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 <sys/types.h> |
||||
#include <sys/param.h> |
||||
#include <sys/audioio.h> |
||||
#include <sys/ioctl.h> |
||||
#include <sys/stat.h> |
||||
|
||||
#include <fcntl.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <unistd.h> |
||||
|
||||
#include "common.h" |
||||
#include "driver.h" |
||||
#include "mixer.h" |
||||
|
||||
static int audio_fd; |
||||
|
||||
static int init(struct context_data *); |
||||
static int setaudio(struct xmp_option *); |
||||
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)", |
||||
"buffer=val", "Audio buffer size (default is 32768)", |
||||
NULL |
||||
}; |
||||
|
||||
struct xmp_drv_info drv_bsd = { |
||||
"bsd", /* driver ID */ |
||||
"BSD 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; |
||||
int gain = 128; |
||||
int bsize = 32 * 1024; |
||||
char *token, **parm; |
||||
|
||||
parm_init(); |
||||
chkparm1("gain", gain = strtoul(token, NULL, 0)); |
||||
chkparm1("buffer", bsize = strtoul(token, NULL, 0)); |
||||
parm_end(); |
||||
|
||||
if (gain < AUDIO_MIN_GAIN) |
||||
gain = AUDIO_MIN_GAIN; |
||||
if (gain > AUDIO_MAX_GAIN) |
||||
gain = AUDIO_MAX_GAIN; |
||||
|
||||
AUDIO_INITINFO(&ainfo); |
||||
|
||||
ainfo.play.sample_rate = o->freq; |
||||
ainfo.play.channels = o->outfmt & XMP_FORMAT_MONO ? 1 : 2; |
||||
ainfo.play.precision = o->resol; |
||||
ainfo.play.encoding = o->resol > 8 ? |
||||
AUDIO_ENCODING_SLINEAR : AUDIO_ENCODING_ULINEAR; |
||||
ainfo.play.gain = gain; |
||||
ainfo.play.buffer_size = bsize; |
||||
|
||||
if (ioctl(audio_fd, AUDIO_SETINFO, &ainfo) == -1) { |
||||
close(audio_fd); |
||||
return XMP_ERR_DINIT; |
||||
} |
||||
|
||||
drv_bsd.description = "BSD PCM audio"; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int init(struct context_data *ctx) |
||||
{ |
||||
if ((audio_fd = open("/dev/sound", 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; |
||||
(char *)b += j; |
||||
} else |
||||
break; |
||||
}; |
||||
} |
||||
|
||||
static void shutdown(struct context_data *ctx) |
||||
{ |
||||
close(audio_fd); |
||||
} |
||||
@ -0,0 +1,57 @@ |
||||
/* 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 <string.h> |
||||
#include <stdlib.h> |
||||
#include "common.h" |
||||
#include "driver.h" |
||||
|
||||
static void starttimer(void); |
||||
static void stoptimer(void); |
||||
static void bufdump(void); |
||||
static int init(struct context_data *ctx); |
||||
static void shutdown(struct context_data *); |
||||
|
||||
struct xmp_drv_info drv_debug = { |
||||
"debug", /* driver ID */ |
||||
"Driver debugger", /* driver description */ |
||||
NULL, /* help */ |
||||
init, /* init */ |
||||
shutdown, /* shutdown */ |
||||
starttimer, /* settimer */ |
||||
stoptimer, /* stoptimer */ |
||||
bufdump, /* bufdump */ |
||||
}; |
||||
|
||||
static void starttimer() |
||||
{ |
||||
printf("** starttimer\n"); |
||||
} |
||||
|
||||
static void stoptimer() |
||||
{ |
||||
printf("** stoptimer\n"); |
||||
} |
||||
|
||||
static void bufdump() |
||||
{ |
||||
} |
||||
|
||||
static int init(struct context_data *ctx) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
static void shutdown(struct context_data *ctx) |
||||
{ |
||||
printf("** shutdown\n"); |
||||
} |
||||
@ -0,0 +1,127 @@ |
||||
/* 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 <stdlib.h> |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#include <fcntl.h> |
||||
#include <string.h> |
||||
#include <unistd.h> |
||||
#include "common.h" |
||||
#include "driver.h" |
||||
#include "convert.h" |
||||
|
||||
#ifndef O_BINARY |
||||
#define O_BINARY 0 |
||||
#endif |
||||
|
||||
#define DATA(x) (((struct data *)drv_file.data)->x) |
||||
|
||||
struct data { |
||||
int fd; |
||||
int endian; |
||||
}; |
||||
|
||||
static int init(struct context_data *); |
||||
static void bufdump(struct context_data *, void *, int); |
||||
static void shutdown(struct context_data *); |
||||
|
||||
static void dummy() |
||||
{ |
||||
} |
||||
|
||||
static char *help[] = { |
||||
"big-endian", "Generate big-endian 16-bit samples", |
||||
"little-endian", "Generate little-endian 16-bit samples", |
||||
NULL |
||||
}; |
||||
|
||||
struct xmp_drv_info drv_file = { |
||||
"file", /* driver ID */ |
||||
"file", /* driver description */ |
||||
help, /* help */ |
||||
init, /* init */ |
||||
shutdown, /* shutdown */ |
||||
dummy, /* starttimer */ |
||||
dummy, /* stoptimer */ |
||||
bufdump, /* bufdump */ |
||||
}; |
||||
|
||||
static int init(struct context_data *ctx) |
||||
{ |
||||
struct xmp_options *o = &ctx->o; |
||||
char *buf; |
||||
int bsize; |
||||
char *token, **parm; |
||||
|
||||
drv_file.data = malloc(sizeof (struct data)); |
||||
if (drv_file.data == NULL) |
||||
return -1; |
||||
|
||||
DATA(endian) = 0; |
||||
parm_init(); |
||||
chkparm0("big-endian", DATA(endian) = 1); |
||||
chkparm0("little-endian", DATA(endian) = -1); |
||||
parm_end(); |
||||
|
||||
if (!o->outfile) |
||||
o->outfile = "xmp.out"; |
||||
|
||||
if (strcmp(o->outfile, "-")) { |
||||
DATA(fd) = open(o->outfile, O_WRONLY | O_CREAT | O_TRUNC |
||||
| O_BINARY, 0644); |
||||
if (DATA(fd) < 0) |
||||
return -1; |
||||
} else { |
||||
DATA(fd) = 1; |
||||
} |
||||
|
||||
if (strcmp(o->outfile, "-")) { |
||||
bsize = strlen(drv_file.description) + strlen(o->outfile) + 8; |
||||
buf = malloc(bsize); |
||||
snprintf(buf, bsize, "%s: %s", drv_file.description, |
||||
o->outfile); |
||||
drv_file.description = buf; |
||||
} else { |
||||
drv_file.description = strdup("Output to stdout"); |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static void bufdump(struct context_data *ctx, void *b, int i) |
||||
{ |
||||
struct xmp_options *o = &ctx->o; |
||||
int j; |
||||
|
||||
if ((o->big_endian && DATA(endian) == -1) || |
||||
(!o->big_endian && DATA(endian) == 1)) { |
||||
xmp_cvt_sex(i, b); |
||||
} |
||||
|
||||
while (i) { |
||||
if ((j = write(DATA(fd), b, i)) > 0) { |
||||
i -= j; |
||||
b = (char *)b + j; |
||||
} else |
||||
break; |
||||
} |
||||
} |
||||
|
||||
static void shutdown(struct context_data *ctx) |
||||
{ |
||||
if (DATA(fd) > 0) |
||||
close(DATA(fd)); |
||||
|
||||
free(drv_file.description); |
||||
free(drv_file.data); |
||||
} |
||||
@ -0,0 +1,164 @@ |
||||
/* 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. |
||||
*/ |
||||
|
||||
/* This code was tested on a 9000/710 running HP-UX 9.05 with 8 kHz,
|
||||
* 16 bit mono output. |
||||
*/ |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include <unistd.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <sys/ioctl.h> |
||||
#include <sys/audio.h> |
||||
#include <fcntl.h> |
||||
|
||||
#include "common.h" |
||||
#include "driver.h" |
||||
#include "mixer.h" |
||||
|
||||
static int audio_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() |
||||
{ |
||||
} |
||||
|
||||
/* Standard sampling rates */ |
||||
static int srate[] = { |
||||
44100, 32000, 22050, 16000, 11025, 8000, 0 |
||||
}; |
||||
|
||||
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", |
||||
NULL |
||||
}; |
||||
|
||||
struct xmp_drv_info drv_hpux = { |
||||
"hpux", /* driver ID */ |
||||
"HP-UX PCM audio", /* driver description */ |
||||
help, /* help */ |
||||
init, /* init */ |
||||
shutdown, /* shutdown */ |
||||
dummy, /* starttimer */ |
||||
dummy, /* flush */ |
||||
bufdump, /* bufdump */ |
||||
}; |
||||
|
||||
static int setaudio(struct xmp_options *o) |
||||
{ |
||||
int flags; |
||||
int gain = 128; |
||||
int bsize = 32 * 1024; |
||||
int port = AUDIO_OUT_SPEAKER; |
||||
struct audio_gains agains; |
||||
struct audio_describe adescribe; |
||||
char *token, **parm; |
||||
int i; |
||||
|
||||
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_OUT_HEADPHONE; |
||||
break; |
||||
case 'l': |
||||
port = AUDIO_OUT_LINE; |
||||
break; |
||||
default: |
||||
port = AUDIO_OUT_SPEAKER; |
||||
} |
||||
|
||||
if ((flags = fcntl(audio_fd, F_GETFL, 0)) < 0) |
||||
return XMP_ERR_DINIT; |
||||
|
||||
flags |= O_NDELAY; |
||||
if ((flags = fcntl(audio_fd, F_SETFL, flags)) < 0) |
||||
return XMP_ERR_DINIT; |
||||
|
||||
if (ioctl(audio_fd, AUDIO_SET_DATA_FORMAT, AUDIO_FORMAT_LINEAR16BIT) == |
||||
-1) |
||||
return XMP_ERR_DINIT; |
||||
|
||||
if (ioctl(audio_fd, AUDIO_SET_CHANNELS, |
||||
o->outfmt & XMP_FORMAT_MONO ? 1 : 2) == -1) { |
||||
o->outfmt ^= XMP_FORMAT_MONO; |
||||
|
||||
if (ioctl(audio_fd, AUDIO_SET_CHANNELS, |
||||
o->outfmt & XMP_FORMAT_MONO ? 1 : 2) == -1) |
||||
return XMP_ERR_DINIT; |
||||
} |
||||
|
||||
ioctl(audio_fd, AUDIO_SET_OUTPUT, port); |
||||
|
||||
for (i = 0; ioctl(audio_fd, AUDIO_SET_SAMPLE_RATE, o->freq) == -1; i++) |
||||
if ((o->freq = srate[i]) == 0) |
||||
return XMP_ERR_DINIT; |
||||
|
||||
if (ioctl(audio_fd, AUDIO_DESCRIBE, &adescribe) == -1) |
||||
return XMP_ERR_DINIT; |
||||
|
||||
if (ioctl(audio_fd, AUDIO_GET_GAINS, &agains) == -1) |
||||
return XMP_ERR_DINIT; |
||||
|
||||
agains.transmit_gain = adescribe.min_transmit_gain + |
||||
(adescribe.max_transmit_gain - adescribe.min_transmit_gain) * |
||||
gain / 256; |
||||
|
||||
if (ioctl(audio_fd, AUDIO_SET_GAINS, &agains) == -1) |
||||
return XMP_ERR_DINIT; |
||||
|
||||
ioctl(audio_fd, AUDIO_SET_TXBUFSIZE, bsize); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int init(struct context_data *ctx) |
||||
{ |
||||
if ((audio_fd = open("/dev/audio", O_WRONLY)) == -1) |
||||
return XMP_ERR_DINIT; |
||||
|
||||
if (setaudio(ctl) != 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; |
||||
(char *)b += j; |
||||
} else |
||||
break; |
||||
} |
||||
} |
||||
|
||||
static void shutdown(struct context_data *ctx) |
||||
{ |
||||
close(audio_fd); |
||||
} |
||||
@ -0,0 +1,168 @@ |
||||
/* 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. |
||||
*/ |
||||
|
||||
/* Based on bsd.c and solaris.c */ |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include <sys/types.h> |
||||
#include <sys/param.h> |
||||
#include <sys/audioio.h> |
||||
#include <sys/mman.h> |
||||
#include <sys/ioctl.h> |
||||
#include <sys/stat.h> |
||||
|
||||
#include <fcntl.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <unistd.h> |
||||
|
||||
#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)", |
||||
/* XXX "port={s|h|l}", "Audio port (s[peaker], h[eadphones], l[ineout])", XXX */ |
||||
"buffer=val", "Audio buffer size (default is 32768)", |
||||
NULL |
||||
}; |
||||
|
||||
struct xmp_drv_info drv_netbsd = { |
||||
"netbsd", /* driver ID */ |
||||
"NetBSD 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; |
||||
int gain = 128; |
||||
int bsize = 32 * 1024; |
||||
char *token, **parm; |
||||
|
||||
/* try to open audioctldevice */ |
||||
if ((audioctl_fd = open("/dev/audioctl", O_RDWR)) < 0) { |
||||
fprintf(stderr, "couldn't open audioctldevice\n"); |
||||
close(audio_fd); |
||||
return -1; |
||||
} |
||||
|
||||
/* empty buffers before change config */ |
||||
ioctl(audio_fd, AUDIO_DRAIN, 0); /* drain everything out */ |
||||
ioctl(audio_fd, AUDIO_FLUSH); /* flush audio */ |
||||
ioctl(audioctl_fd, AUDIO_FLUSH); /* flush audioctl */ |
||||
|
||||
/* 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); |
||||
|
||||
parm_init(); |
||||
chkparm1("gain", gain = strtoul(token, NULL, 0)); |
||||
chkparm1("buffer", bsize = strtoul(token, NULL, 0)); |
||||
/* chkparm1 ("port", port = (int)*token) */ |
||||
parm_end(); |
||||
|
||||
#if 0 |
||||
switch (port) { |
||||
case 'h': |
||||
port = AUDIO_HEADPHONE; |
||||
break; |
||||
case 'l': |
||||
port = AUDIO_LINE_OUT; |
||||
break; |
||||
case 's': |
||||
port = AUDIO_SPEAKER; |
||||
} |
||||
#endif |
||||
if (gain < AUDIO_MIN_GAIN) |
||||
gain = AUDIO_MIN_GAIN; |
||||
if (gain > AUDIO_MAX_GAIN) |
||||
gain = AUDIO_MAX_GAIN; |
||||
|
||||
AUDIO_INITINFO(&ainfo); |
||||
|
||||
ainfo.play.sample_rate = o->freq; |
||||
ainfo.play.channels = o->outfmt & XMP_FORMAT_MONO ? 1 : 2; |
||||
ainfo.play.precision = o->resol; |
||||
/* ainfo.play.precision = AUDIO_ENCODING_ULINEAR; */ |
||||
ainfo.play.encoding = o->resol > 8 ? |
||||
AUDIO_ENCODING_SLINEAR : AUDIO_ENCODING_ULINEAR; |
||||
ainfo.play.gain = gain; |
||||
/* ainfo.play.port = port; */ |
||||
ainfo.play.buffer_size = bsize; |
||||
|
||||
if (ioctl(audio_fd, AUDIO_SETINFO, &ainfo) == -1) { |
||||
close(audio_fd); |
||||
return XMP_ERR_DINIT; |
||||
} |
||||
|
||||
/* o->resol = 0; */ |
||||
/* o->freq = 8000; */ |
||||
/* o->outfmt |=XMP_FORMAT_MONO; */ |
||||
o->freq = 44000; |
||||
drv_netbsd.description = "NetBSD PCM audio"; |
||||
return 0; |
||||
} |
||||
|
||||
static int init(struct context_data *ctx) |
||||
{ |
||||
if ((audio_fd = open("/dev/sound", O_WRONLY)) == -1) |
||||
return XMP_ERR_DINIT; |
||||
|
||||
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. |
||||
*/ |
||||
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; |
||||
(char *)b += j; |
||||
} else |
||||
break; |
||||
} |
||||
} |
||||
|
||||
static void shutdown(struct context_data *ctx) |
||||
{ |
||||
close(audio_fd); |
||||
} |
||||
@ -0,0 +1,125 @@ |
||||
/* 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. |
||||
*/ |
||||
|
||||
/* This should work for OpenBSD */ |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include <sys/types.h> |
||||
#include <sys/param.h> |
||||
#include <sys/audioio.h> |
||||
#include <sys/ioctl.h> |
||||
#include <sys/stat.h> |
||||
|
||||
#include <fcntl.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <unistd.h> |
||||
|
||||
#include "common.h" |
||||
#include "driver.h" |
||||
#include "mixer.h" |
||||
|
||||
static int audio_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)", |
||||
"buffer=val", "Audio buffer size (default is 32768)", |
||||
NULL |
||||
}; |
||||
|
||||
struct xmp_drv_info drv_openbsd = { |
||||
"openbsd", /* driver ID */ |
||||
"OpenBSD 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; |
||||
int gain = 128; |
||||
int bsize = 32 * 1024; |
||||
char *token, **parm; |
||||
|
||||
parm_init(); |
||||
chkparm1("gain", gain = strtoul(token, NULL, 0)); |
||||
chkparm1("buffer", bsize = strtoul(token, NULL, 0)); |
||||
parm_end(); |
||||
|
||||
if (gain < AUDIO_MIN_GAIN) |
||||
gain = AUDIO_MIN_GAIN; |
||||
if (gain > AUDIO_MAX_GAIN) |
||||
gain = AUDIO_MAX_GAIN; |
||||
|
||||
AUDIO_INITINFO(&ainfo); |
||||
|
||||
ainfo.play.sample_rate = o->freq; |
||||
ainfo.play.channels = o->outfmt & XMP_FORMAT_MONO ? 1 : 2; |
||||
ainfo.play.precision = o->resol; |
||||
ainfo.play.encoding = o->resol > 8 ? |
||||
AUDIO_ENCODING_SLINEAR : AUDIO_ENCODING_ULINEAR; |
||||
ainfo.play.gain = gain; |
||||
ainfo.play.buffer_size = bsize; |
||||
|
||||
if (ioctl(audio_fd, AUDIO_SETINFO, &ainfo) == -1) { |
||||
close(audio_fd); |
||||
return XMP_ERR_DINIT; |
||||
} |
||||
|
||||
drv_openbsd.description = "OpenBSD PCM audio"; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int init(struct context_data *ctx) |
||||
{ |
||||
if ((audio_fd = open("/dev/sound", O_WRONLY)) == -1) |
||||
return XMP_ERR_DINIT; |
||||
|
||||
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. |
||||
*/ |
||||
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); |
||||
} |
||||
@ -0,0 +1,261 @@ |
||||
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
|
||||
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
|
||||
/*
|
||||
This should work for OS/2 Dart
|
||||
|
||||
History:
|
||||
1.0 - By Kevin Langman |
||||
|
||||
*/ |
||||
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
|
||||
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
|
||||
|
||||
#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> |
||||
|
||||
#define INCL_DOS |
||||
#include <os2.h> |
||||
#include <mcios2.h> |
||||
#include <meerror.h> |
||||
#include <os2medef.h> |
||||
|
||||
#include "common.h" |
||||
#include "driver.h" |
||||
#include "mixer.h" |
||||
|
||||
#define BUFFERCOUNT 4 |
||||
#define BUF_MIN 8 |
||||
#define BUF_MAX 32 |
||||
|
||||
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 MCI_MIX_BUFFER MixBuffers[BUFFERCOUNT]; |
||||
static MCI_MIXSETUP_PARMS MixSetupParms; |
||||
static MCI_BUFFER_PARMS BufferParms; |
||||
static MCI_GENERIC_PARMS GenericParms; |
||||
|
||||
static ULONG DeviceID = 0; |
||||
static int bsize = 16; |
||||
static short next = 2; |
||||
static short ready = 1; |
||||
|
||||
static HMTX mutex; |
||||
|
||||
static void dummy() |
||||
{ |
||||
} |
||||
|
||||
static char *help[] = { |
||||
"sharing={Y,N}", "Device Sharing (default is N)", |
||||
"device=val", "OS/2 Audio Device (default is 0 auto-detect)", |
||||
"buffer=val", "Audio buffer size (default is 16)", |
||||
NULL |
||||
}; |
||||
|
||||
struct xmp_drv_info drv_os2dart = { |
||||
"dart", /* driver ID */ |
||||
"OS/2 Direct Audio Realtime", /* driver description */ |
||||
help, /* help */ |
||||
init, /* init */ |
||||
shutdown, /* shutdown */ |
||||
dummy, /* starttimer */ |
||||
dummy, /* flush */ |
||||
bufdump, /* bufdump */ |
||||
}; |
||||
|
||||
// Buffer update thread (created and called by DART)
|
||||
static LONG APIENTRY OS2_Dart_UpdateBuffers |
||||
(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags) { |
||||
|
||||
if ((ulFlags == MIX_WRITE_COMPLETE) || |
||||
((ulFlags == (MIX_WRITE_COMPLETE | MIX_STREAM_ERROR)) && |
||||
(ulStatus == ERROR_DEVICE_UNDERRUN))) { |
||||
DosRequestMutexSem(mutex, SEM_INDEFINITE_WAIT); |
||||
ready++; |
||||
DosReleaseMutexSem(mutex); |
||||
} |
||||
|
||||
return (TRUE); |
||||
} |
||||
|
||||
static int setaudio(struct xmp_options *o) |
||||
{ |
||||
char sharing = 0; |
||||
int device = 0; |
||||
int flags; |
||||
int i; |
||||
MCI_AMP_OPEN_PARMS AmpOpenParms; |
||||
char *token, **parm; |
||||
|
||||
//printf( "In SetAudio...\n" );
|
||||
|
||||
parm_init(); |
||||
chkparm1("sharing", sharing = *token); |
||||
chkparm1("device", device = atoi(token)); |
||||
chkparm1("buffer", bsize = strtoul(token, NULL, 0)); |
||||
parm_end(); |
||||
|
||||
if ((bsize < BUF_MIN || bsize > BUF_MAX) && bsize != 0) { |
||||
bsize = 16 * 1024; |
||||
} else { |
||||
bsize *= 1024; |
||||
} |
||||
|
||||
//if( sharing < 1 || sharing > 0 ){
|
||||
// sharing = 0;
|
||||
//}
|
||||
|
||||
MixBuffers[0].pBuffer = NULL; /* marker */ |
||||
memset(&GenericParms, 0, sizeof(MCI_GENERIC_PARMS)); |
||||
|
||||
/* open AMP device */ |
||||
memset(&AmpOpenParms, 0, sizeof(MCI_AMP_OPEN_PARMS)); |
||||
AmpOpenParms.usDeviceID = 0; |
||||
|
||||
AmpOpenParms.pszDeviceType = |
||||
(PSZ) MAKEULONG(MCI_DEVTYPE_AUDIO_AMPMIX, (USHORT) device); |
||||
|
||||
flags = MCI_WAIT | MCI_OPEN_TYPE_ID; |
||||
if (sharing == 'Y' || sharing == 'y') { |
||||
flags = flags | MCI_OPEN_SHAREABLE; |
||||
} |
||||
|
||||
if (mciSendCommand(0, MCI_OPEN, flags, |
||||
(PVOID) & AmpOpenParms, 0) != MCIERR_SUCCESS) { |
||||
return -1; |
||||
} |
||||
|
||||
DeviceID = AmpOpenParms.usDeviceID; |
||||
|
||||
/* setup playback parameters */ |
||||
memset(&MixSetupParms, 0, sizeof(MCI_MIXSETUP_PARMS)); |
||||
|
||||
MixSetupParms.ulBitsPerSample = o->resol; |
||||
MixSetupParms.ulFormatTag = MCI_WAVE_FORMAT_PCM; |
||||
MixSetupParms.ulSamplesPerSec = o->freq; |
||||
MixSetupParms.ulChannels = o->outfmt & XMP_FORMAT_MONO ? 1 : 2; |
||||
MixSetupParms.ulFormatMode = MCI_PLAY; |
||||
MixSetupParms.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO; |
||||
MixSetupParms.pmixEvent = OS2_Dart_UpdateBuffers; |
||||
|
||||
if (mciSendCommand(DeviceID, MCI_MIXSETUP, |
||||
MCI_WAIT | MCI_MIXSETUP_INIT, |
||||
(PVOID) & MixSetupParms, 0) != MCIERR_SUCCESS) { |
||||
|
||||
mciSendCommand(DeviceID, MCI_CLOSE, MCI_WAIT, |
||||
(PVOID) & GenericParms, 0); |
||||
return -1; |
||||
} |
||||
|
||||
/* take in account the DART suggested buffer size... */ |
||||
if (bsize == 0) { |
||||
bsize = MixSetupParms.ulBufferSize; |
||||
} |
||||
//printf( "Dart Buffer Size = %d\n", bsize );
|
||||
|
||||
BufferParms.ulNumBuffers = BUFFERCOUNT; |
||||
BufferParms.ulBufferSize = bsize; |
||||
BufferParms.pBufList = MixBuffers; |
||||
|
||||
if (mciSendCommand(DeviceID, MCI_BUFFER, |
||||
MCI_WAIT | MCI_ALLOCATE_MEMORY, |
||||
(PVOID) & BufferParms, 0) != MCIERR_SUCCESS) { |
||||
mciSendCommand(DeviceID, MCI_CLOSE, MCI_WAIT, |
||||
(PVOID) & GenericParms, 0); |
||||
return -1; |
||||
} |
||||
|
||||
for (i = 0; i < BUFFERCOUNT; i++) { |
||||
MixBuffers[i].ulBufferLength = bsize; |
||||
} |
||||
|
||||
//MixBuffers[0].ulBufferLength = bsize;
|
||||
//MixBuffers[1].ulBufferLength = bsize;
|
||||
//MixBuffers[2].ulBufferLength = bsize;
|
||||
//MixBuffers[3].ulBufferLength = bsize;
|
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int init(struct context_data *ctx) |
||||
{ |
||||
//printf( "In Init...\n" );
|
||||
|
||||
if (setaudio(ctl) != 0) |
||||
return XMP_ERR_DINIT; |
||||
|
||||
/* Start Playback */ |
||||
//printf("Starting Playback!!\n");
|
||||
memset(MixBuffers[0].pBuffer, /*32767 */ 0, bsize); |
||||
memset(MixBuffers[1].pBuffer, /*32767 */ 0, bsize); |
||||
MixSetupParms.pmixWrite(MixSetupParms.ulMixHandle, MixBuffers, 2); |
||||
|
||||
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 int index = 0; |
||||
|
||||
//printf( "In BufDump...\n" );
|
||||
|
||||
if (index + i > bsize) { |
||||
|
||||
//printf("Next = %d, ready = %d\n", next, ready);
|
||||
|
||||
do { |
||||
DosRequestMutexSem(mutex, SEM_INDEFINITE_WAIT); |
||||
if (ready != 0) { |
||||
DosReleaseMutexSem(mutex); |
||||
break; |
||||
} |
||||
DosReleaseMutexSem(mutex); |
||||
DosSleep(20); |
||||
} while (TRUE); |
||||
|
||||
MixBuffers[next].ulBufferLength = index; |
||||
MixSetupParms.pmixWrite(MixSetupParms.ulMixHandle, |
||||
&(MixBuffers[next]), 1); |
||||
ready--; |
||||
next++; |
||||
index = 0; |
||||
if (next == BUFFERCOUNT) { |
||||
next = 0; |
||||
} |
||||
} |
||||
memcpy(&((char *)MixBuffers[next].pBuffer)[index], b, i); |
||||
index += i; |
||||
|
||||
} |
||||
|
||||
static void shutdown(struct context_data *ctx) |
||||
{ |
||||
//printf( "In ShutDown...\n" );
|
||||
|
||||
if (MixBuffers[0].pBuffer) { |
||||
mciSendCommand(DeviceID, MCI_BUFFER, |
||||
MCI_WAIT | MCI_DEALLOCATE_MEMORY, &BufferParms, |
||||
0); |
||||
MixBuffers[0].pBuffer = NULL; |
||||
} |
||||
if (DeviceID) { |
||||
mciSendCommand(DeviceID, MCI_CLOSE, MCI_WAIT, |
||||
(PVOID) & GenericParms, 0); |
||||
DeviceID = 0; |
||||
} |
||||
} |
||||
@ -0,0 +1,217 @@ |
||||
/* 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. |
||||
*/ |
||||
|
||||
/*
|
||||
* devfs /dev/sound/dsp support by Dirk Jagdmann |
||||
* resume/onpause by Test Rat <ttsestt@gmail.com> |
||||
*/ |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include <sys/time.h> |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#include <fcntl.h> |
||||
#include <unistd.h> |
||||
#include <sys/ioctl.h> |
||||
|
||||
#if defined(HAVE_SYS_SOUNDCARD_H) |
||||
#include <sys/soundcard.h> |
||||
#elif defined(HAVE_MACHINE_SOUNDCARD_H) |
||||
#include <machine/soundcard.h> |
||||
#endif |
||||
|
||||
#include "driver.h" |
||||
|
||||
static int audio_fd; |
||||
|
||||
static void from_fmt(struct xmp_options *, int); |
||||
static int to_fmt(struct xmp_options *); |
||||
static void setaudio(struct xmp_options *); |
||||
static int init(struct context_data *); |
||||
static void shutdown(struct context_data *); |
||||
static void bufdump(struct context_data *, void *, int); |
||||
static void resume(void); |
||||
static void onpause(void); |
||||
|
||||
static char *help[] = { |
||||
"frag=num,size", "Set the number and size of fragments", |
||||
"dev=<device_name>", "Audio device to use (default /dev/dsp)", |
||||
"nosync", "Don't flush OSS buffers between modules", |
||||
NULL |
||||
}; |
||||
|
||||
struct xmp_drv_info drv_oss = { |
||||
"oss", /* driver ID */ |
||||
"OSS PCM audio", /* driver description */ |
||||
help, /* help */ |
||||
init, /* init */ |
||||
shutdown, /* shutdown */ |
||||
resume, /* starttimer */ |
||||
onpause, /* stoptimer */ |
||||
bufdump, /* bufdump */ |
||||
}; |
||||
|
||||
static int fragnum, fragsize; |
||||
static int do_sync = 1; |
||||
|
||||
static int to_fmt(struct xmp_options *o) |
||||
{ |
||||
int fmt; |
||||
|
||||
if (!o->resol) |
||||
return AFMT_MU_LAW; |
||||
|
||||
if (o->resol == 8) |
||||
fmt = AFMT_U8 | AFMT_S8; |
||||
else { |
||||
fmt = o->big_endian ? AFMT_S16_BE | AFMT_U16_BE : |
||||
AFMT_S16_LE | AFMT_U16_LE; |
||||
} |
||||
|
||||
if (o->outfmt & XMP_FMT_UNS) |
||||
fmt &= AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE; |
||||
else |
||||
fmt &= AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE; |
||||
|
||||
return fmt; |
||||
} |
||||
|
||||
static void from_fmt(struct xmp_options *o, int outfmt) |
||||
{ |
||||
if (outfmt & AFMT_MU_LAW) { |
||||
o->resol = 0; |
||||
return; |
||||
} |
||||
|
||||
if (outfmt & (AFMT_S16_LE | AFMT_S16_BE | AFMT_U16_LE | AFMT_U16_BE)) |
||||
o->resol = 16; |
||||
else |
||||
o->resol = 8; |
||||
|
||||
if (outfmt & (AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE)) |
||||
o->outfmt |= XMP_FMT_UNS; |
||||
else |
||||
o->outfmt &= ~XMP_FMT_UNS; |
||||
} |
||||
|
||||
static void setaudio(struct xmp_options *o) |
||||
{ |
||||
static int fragset = 0; |
||||
int frag = 0; |
||||
int fmt; |
||||
|
||||
frag = (fragnum << 16) + fragsize; |
||||
|
||||
fmt = to_fmt(o); |
||||
ioctl(audio_fd, SNDCTL_DSP_SETFMT, &fmt); |
||||
from_fmt(o, fmt); |
||||
|
||||
fmt = !(o->outfmt & XMP_FORMAT_MONO); |
||||
ioctl(audio_fd, SNDCTL_DSP_STEREO, &fmt); |
||||
if (fmt) |
||||
o->outfmt &= ~XMP_FORMAT_MONO; |
||||
else |
||||
o->outfmt |= XMP_FORMAT_MONO; |
||||
|
||||
ioctl(audio_fd, SNDCTL_DSP_SPEED, &o->freq); |
||||
|
||||
/* Set the fragments only once */ |
||||
if (!fragset) { |
||||
if (fragnum && fragsize) |
||||
ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag); |
||||
fragset++; |
||||
} |
||||
} |
||||
|
||||
static int init(struct context_data *ctx) |
||||
{ |
||||
char *dev_audio[] = { "/dev/dsp", "/dev/sound/dsp" }; |
||||
struct xmp_options *o = &ctx->o; |
||||
audio_buf_info info; |
||||
static char buf[80]; |
||||
char *token, **parm; |
||||
int i; |
||||
|
||||
fragnum = 16; /* default number of fragments */ |
||||
i = 1024; /* default size of fragment */ |
||||
|
||||
parm_init(); |
||||
chkparm2("frag", "%d,%d", &fragnum, &i); |
||||
chkparm1("dev", dev_audio[0] = token); |
||||
chkparm0("nosync", do_sync = 0); |
||||
parm_end(); |
||||
|
||||
for (fragsize = 0; i >>= 1; fragsize++) ; |
||||
if (fragsize < 4) |
||||
fragsize = 4; |
||||
|
||||
for (i = 0; i < sizeof(dev_audio) / sizeof(dev_audio[0]); i++) |
||||
if ((audio_fd = open(dev_audio[i], O_WRONLY)) >= 0) |
||||
break; |
||||
if (audio_fd < 0) |
||||
return XMP_ERR_DINIT; |
||||
|
||||
setaudio(o); |
||||
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info) == 0) { |
||||
snprintf(buf, 80, "%s [%d fragments of %d bytes]", |
||||
drv_oss.description, info.fragstotal, |
||||
info.fragsize); |
||||
drv_oss.description = buf; |
||||
} |
||||
|
||||
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) |
||||
{ |
||||
ioctl(audio_fd, SNDCTL_DSP_RESET, NULL); |
||||
close(audio_fd); |
||||
} |
||||
|
||||
static void resume() |
||||
{ |
||||
#ifdef SNDCTL_DSP_SETTRIGGER |
||||
int trig = PCM_ENABLE_OUTPUT; |
||||
ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &trig); |
||||
#endif |
||||
} |
||||
|
||||
static void onpause() |
||||
{ |
||||
#ifdef SNDCTL_DSP_SETTRIGGER |
||||
int trig = 0; |
||||
ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &trig); |
||||
#else |
||||
ioctl(audio_fd, SNDCTL_DSP_RESET, NULL); |
||||
#endif |
||||
|
||||
if (do_sync) |
||||
ioctl(audio_fd, SNDCTL_DSP_SYNC, NULL); |
||||
} |
||||
@ -0,0 +1,279 @@ |
||||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2012 Claudio Matsuoka and Hipolito Carraro Jr |
||||
* CoreAudio helpers (C) 2000 Timothy J. Wood |
||||
* |
||||
* 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 <CoreAudio/CoreAudio.h> |
||||
#include <AudioUnit/AudioUnit.h> |
||||
#include <AudioToolbox/AudioToolbox.h> |
||||
#include <CoreServices/CoreServices.h> |
||||
#include <unistd.h> |
||||
|
||||
#include "common.h" |
||||
#include "driver.h" |
||||
#include "mixer.h" |
||||
|
||||
|
||||
static int init (struct context_data *ctx); |
||||
static void bufdump (struct context_data *, void *, int); |
||||
static void shutdown (struct context_data *); |
||||
|
||||
static void dummy () { } |
||||
|
||||
struct xmp_drv_info drv_osx = { |
||||
"osx", /* driver ID */ |
||||
"OSX CoreAudio", /* driver description */ |
||||
NULL, /* help */ |
||||
init, /* init */ |
||||
shutdown, /* shutdown */ |
||||
dummy, /* starttimer */ |
||||
dummy, /* flush */ |
||||
bufdump, /* bufdump */ |
||||
}; |
||||
|
||||
static AudioUnit au; |
||||
|
||||
|
||||
/*
|
||||
* CoreAudio helpers from mplayer/libao |
||||
* The player fills a ring buffer, OSX retrieves data from the buffer |
||||
*/ |
||||
|
||||
static int paused; |
||||
static uint8 *buffer; |
||||
static int buffer_len; |
||||
static int buf_write_pos; |
||||
static int buf_read_pos; |
||||
static int num_chunks; |
||||
static int chunk_size; |
||||
static int packet_size; |
||||
|
||||
|
||||
/* return minimum number of free bytes in buffer, value may change between
|
||||
* two immediately following calls, and the real number of free bytes |
||||
* might actually be larger! */ |
||||
static int buf_free() |
||||
{ |
||||
int free = buf_read_pos - buf_write_pos - chunk_size; |
||||
if (free < 0) |
||||
free += buffer_len; |
||||
return free; |
||||
} |
||||
|
||||
/* return minimum number of buffered bytes, value may change between
|
||||
* two immediately following calls, and the real number of buffered bytes |
||||
* might actually be larger! */ |
||||
static int buf_used() |
||||
{ |
||||
int used = buf_write_pos - buf_read_pos; |
||||
if (used < 0) |
||||
used += buffer_len; |
||||
return used; |
||||
} |
||||
|
||||
/* add data to ringbuffer */ |
||||
static int write_buffer(unsigned char *data, int len) |
||||
{ |
||||
int first_len = buffer_len - buf_write_pos; |
||||
int free = buf_free(); |
||||
|
||||
if (len > free) |
||||
len = free; |
||||
if (first_len > len) |
||||
first_len = len; |
||||
|
||||
/* till end of buffer */ |
||||
memcpy(buffer + buf_write_pos, data, first_len); |
||||
if (len > first_len) { /* we have to wrap around */ |
||||
/* remaining part from beginning of buffer */ |
||||
memcpy(buffer, data + first_len, len - first_len); |
||||
} |
||||
buf_write_pos = (buf_write_pos + len) % buffer_len; |
||||
|
||||
return len; |
||||
} |
||||
|
||||
/* remove data from ringbuffer */ |
||||
static int read_buffer(unsigned char *data, int len) |
||||
{ |
||||
int first_len = buffer_len - buf_read_pos; |
||||
int buffered = buf_used(); |
||||
|
||||
if (len > buffered) |
||||
len = buffered; |
||||
if (first_len > len) |
||||
first_len = len; |
||||
|
||||
/* till end of buffer */ |
||||
memcpy(data, buffer + buf_read_pos, first_len); |
||||
if (len > first_len) { /* we have to wrap around */ |
||||
/* remaining part from beginning of buffer */ |
||||
memcpy(data + first_len, buffer, len - first_len); |
||||
} |
||||
buf_read_pos = (buf_read_pos + len) % buffer_len; |
||||
|
||||
return len; |
||||
} |
||||
|
||||
OSStatus render_proc(void *inRefCon, |
||||
AudioUnitRenderActionFlags *inActionFlags, |
||||
const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, |
||||
UInt32 inNumFrames, AudioBufferList *ioData) |
||||
{ |
||||
int amt = buf_used(); |
||||
int req = inNumFrames * packet_size; |
||||
|
||||
if (amt > req) |
||||
amt = req; |
||||
|
||||
read_buffer((unsigned char *)ioData->mBuffers[0].mData, amt); |
||||
ioData->mBuffers[0].mDataByteSize = amt; |
||||
|
||||
return noErr; |
||||
} |
||||
|
||||
/*
|
||||
* end of CoreAudio helpers |
||||
*/ |
||||
|
||||
|
||||
static int init(struct context_data *ctx) |
||||
{ |
||||
struct xmp_options *o = &ctx->o; |
||||
AudioStreamBasicDescription ad; |
||||
Component comp; |
||||
ComponentDescription cd; |
||||
AURenderCallbackStruct rc; |
||||
//char *token, **parm;
|
||||
OSStatus err; |
||||
UInt32 size, max_frames; |
||||
|
||||
//parm_init();
|
||||
//parm_end();
|
||||
|
||||
ad.mSampleRate = o->freq; |
||||
ad.mFormatID = kAudioFormatLinearPCM; |
||||
ad.mFormatFlags = kAudioFormatFlagIsPacked | |
||||
kAudioFormatFlagIsSignedInteger; |
||||
if (o->big_endian) |
||||
ad.mFormatFlags |= kAudioFormatFlagIsBigEndian; |
||||
else |
||||
ad.mFormatFlags &= ~kAudioFormatFlagIsBigEndian; |
||||
|
||||
ad.mChannelsPerFrame = o->outfmt & XMP_FORMAT_MONO ? 1 : 2; |
||||
ad.mBitsPerChannel = o->resol; |
||||
|
||||
ad.mBytesPerFrame = o->resol / 8 * ad.mChannelsPerFrame; |
||||
ad.mBytesPerPacket = ad.mBytesPerFrame; |
||||
ad.mFramesPerPacket = 1; |
||||
|
||||
packet_size = ad.mFramesPerPacket * ad.mChannelsPerFrame * |
||||
(ad.mBitsPerChannel / 8); |
||||
|
||||
cd.componentType = kAudioUnitType_Output; |
||||
cd.componentSubType = kAudioUnitSubType_DefaultOutput; |
||||
cd.componentManufacturer = kAudioUnitManufacturer_Apple; |
||||
cd.componentFlags = 0; |
||||
cd.componentFlagsMask = 0; |
||||
|
||||
if ((comp = FindNextComponent(NULL, &cd)) == NULL) { |
||||
fprintf(stderr, "error: FindNextComponent\n"); |
||||
return XMP_ERR_DINIT; |
||||
} |
||||
|
||||
if ((err = OpenAComponent(comp, &au))) { |
||||
fprintf(stderr, "error: OpenAComponent (%d)\n", (int)err); |
||||
return XMP_ERR_DINIT; |
||||
} |
||||
|
||||
if ((err = AudioUnitInitialize(au))) { |
||||
fprintf(stderr, "error: AudioUnitInitialize (%d)\n", (int)err); |
||||
return XMP_ERR_DINIT; |
||||
} |
||||
|
||||
if ((err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, |
||||
kAudioUnitScope_Input, 0, &ad, sizeof(ad)))) { |
||||
fprintf(stderr, "error: AudioUnitSetProperty: StreamFormat (%d)\n", (int)err); |
||||
fprintf(stderr, "mSampleRate = %lf\n", ad.mSampleRate); |
||||
fprintf(stderr, "mFormatID = 0x%x\n", (unsigned)ad.mFormatID); |
||||
fprintf(stderr, "mFormatFlags = 0x%x\n", (unsigned)ad.mFormatFlags); |
||||
fprintf(stderr, "mChannelsPerFrame = %d\n", (int)ad.mChannelsPerFrame); |
||||
fprintf(stderr, "mBitsPerChannel = %d\n", (int)ad.mBitsPerChannel); |
||||
fprintf(stderr, "mBytesPerFrame = %d\n", (int)ad.mBytesPerFrame); |
||||
fprintf(stderr, "mBytesPerPacket = %d\n", (int)ad.mBytesPerPacket); |
||||
fprintf(stderr, "mFramesPerPacket = %d\n", (int)ad.mFramesPerPacket); |
||||
|
||||
return XMP_ERR_DINIT; |
||||
} |
||||
|
||||
size = sizeof(UInt32); |
||||
if ((err = AudioUnitGetProperty(au, kAudioDevicePropertyBufferSize, |
||||
kAudioUnitScope_Input, 0, &max_frames, &size))) { |
||||
fprintf(stderr, "error: AudioUnitGetProperty: BufferSize (%d)\n", (int)err); |
||||
return XMP_ERR_DINIT; |
||||
} |
||||
|
||||
chunk_size = max_frames; |
||||
num_chunks = (o->freq * ad.mBytesPerFrame + chunk_size - 1) / |
||||
chunk_size; |
||||
buffer_len = (num_chunks + 1) * chunk_size; |
||||
buffer = calloc(num_chunks + 1, chunk_size); |
||||
|
||||
rc.inputProc = render_proc; |
||||
rc.inputProcRefCon = 0; |
||||
|
||||
buf_read_pos = 0; |
||||
buf_write_pos = 0; |
||||
paused = 1; |
||||
|
||||
if ((err = AudioUnitSetProperty(au, kAudioUnitProperty_SetRenderCallback, |
||||
kAudioUnitScope_Input, 0, &rc, sizeof(rc)))) { |
||||
fprintf(stderr, "error: AudioUnitSetProperty: SetRenderCallback (%d)\n", (int)err); |
||||
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 = 0; |
||||
|
||||
/* block until we have enough free space in the buffer */ |
||||
while (buf_free() < i) |
||||
usleep(100000); |
||||
|
||||
while (i) { |
||||
if ((j = write_buffer(b, i)) > 0) { |
||||
i -= j; |
||||
b += j; |
||||
} else |
||||
break; |
||||
} |
||||
|
||||
if (paused) { |
||||
AudioOutputUnitStart(au); |
||||
paused = 0; |
||||
} |
||||
} |
||||
|
||||
|
||||
static void shutdown(struct context_data *ctx) |
||||
{ |
||||
AudioOutputUnitStop(au); |
||||
AudioUnitUninitialize(au); |
||||
CloseComponent(au); |
||||
free(buffer); |
||||
} |
||||
@ -0,0 +1,101 @@ |
||||
/* 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 <pulse/simple.h> |
||||
#include <pulse/error.h> |
||||
|
||||
#include "common.h" |
||||
#include "driver.h" |
||||
#include "mixer.h" |
||||
|
||||
static pa_simple *s; |
||||
|
||||
static int init(struct context_data *); |
||||
static void bufdump(struct context_data *, void *, int); |
||||
static void myshutdown(struct context_data *); |
||||
static void flush(); |
||||
|
||||
static void dummy() |
||||
{ |
||||
} |
||||
|
||||
struct xmp_drv_info drv_pulseaudio = { |
||||
"pulseaudio", /* driver ID */ |
||||
"PulseAudio", /* driver description */ |
||||
NULL, /* help */ |
||||
init, /* init */ |
||||
myshutdown, /* shutdown */ |
||||
dummy, /* starttimer */ |
||||
flush, /* flush */ |
||||
bufdump, /* bufdump */ |
||||
}; |
||||
|
||||
static int init(struct context_data *ctx) |
||||
{ |
||||
struct xmp_options *o = &ctx->o; |
||||
pa_sample_spec ss; |
||||
int error; |
||||
|
||||
ss.format = PA_SAMPLE_S16NE; |
||||
ss.channels = o->outfmt & XMP_FORMAT_MONO ? 1 : 2; |
||||
ss.rate = o->freq; |
||||
|
||||
s = pa_simple_new(NULL, /* Use the default server */ |
||||
"xmp", /* Our application's name */ |
||||
PA_STREAM_PLAYBACK, |
||||
NULL, /* Use the default device */ |
||||
"Music", /* Description of our stream */ |
||||
&ss, /* Our sample format */ |
||||
NULL, /* Use default channel map */ |
||||
NULL, /* Use default buffering attributes */ |
||||
&error); /* Ignore error code */ |
||||
|
||||
if (s == 0) { |
||||
fprintf(stderr, "pulseaudio error: %s\n", pa_strerror(error)); |
||||
return XMP_ERR_DINIT; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static void flush() |
||||
{ |
||||
int error; |
||||
|
||||
if (pa_simple_drain(s, &error) < 0) { |
||||
fprintf(stderr, "pulseaudio error: %s\n", pa_strerror(error)); |
||||
} |
||||
} |
||||
|
||||
static void bufdump(struct context_data *ctx, void *b, int i) |
||||
{ |
||||
int j, error; |
||||
|
||||
do { |
||||
if ((j = pa_simple_write(s, b, i, &error)) > 0) { |
||||
i -= j; |
||||
b += j; |
||||
} else |
||||
break; |
||||
} while (i); |
||||
|
||||
if (j < 0) { |
||||
fprintf(stderr, "pulseaudio error: %s\n", pa_strerror(error)); |
||||
} |
||||
} |
||||
|
||||
static void myshutdown(struct context_data *ctx) |
||||
{ |
||||
if (s) |
||||
pa_simple_free(s); |
||||
} |
||||
@ -0,0 +1,130 @@ |
||||
/* 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. |
||||
*/ |
||||
|
||||
/*
|
||||
* Based on the QNX4 port of nspmod by Mike Gorchak <malva@selena.kherson.ua> |
||||
*/ |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include <sys/audio.h> |
||||
#include <sys/ioctl.h> |
||||
#include "common.h" |
||||
#include "driver.h" |
||||
#include "mixer.h" |
||||
|
||||
static int fd_audio; |
||||
|
||||
static int init(struct context_data *); |
||||
static void bufdump(struct context_data *, void *, int); |
||||
static void myshutdown(struct context_data *); |
||||
static void mysync(); |
||||
|
||||
static void dummy() |
||||
{ |
||||
} |
||||
|
||||
static char *help[] = { |
||||
"dev=<device_name>", "Audio device name (default is /dev/dsp)", |
||||
"buffer=val", "Audio buffer size (default is 32768)", |
||||
NULL |
||||
}; |
||||
|
||||
struct xmp_drv_info drv_qnx = { |
||||
"QNX", /* driver ID */ |
||||
"QNX PCM audio", /* driver description */ |
||||
NULL, /* help */ |
||||
init, /* init */ |
||||
myshutdown, /* shutdown */ |
||||
dummy, /* starttimer */ |
||||
dummy, /* flush */ |
||||
bufdump, /* bufdump */ |
||||
}; |
||||
|
||||
static int init(struct context_data *ctx) |
||||
{ |
||||
struct xmp_options *o = &ctx->o; |
||||
int rc, rate, bits, stereo, bsize; |
||||
char *dev; |
||||
char *token, **parm; |
||||
|
||||
parm_init(); |
||||
chkparm1("dev", dev = token); |
||||
chkparm1("buffer", bsize = strtoul(token, NULL, 0)); |
||||
parm_end(); |
||||
|
||||
rate = o->freq; |
||||
bits = o->resol; |
||||
stereo = 1; |
||||
bufsize = 32 * 1024; |
||||
|
||||
fd_audio = open(dev, O_WRONLY); |
||||
if (fd_audio < 0) { |
||||
fprintf(stderr, "can't open audio device\n"); |
||||
return XMP_ERR_DINIT; |
||||
} |
||||
|
||||
if (o->outfmt & XMP_FORMAT_MONO) |
||||
stereo = 0; |
||||
|
||||
if (ioctl(fd_audio, SOUND_PCM_WRITE_BITS, &bits) < 0) { |
||||
perror("can't set resolution"); |
||||
goto error; |
||||
} |
||||
|
||||
if (ioctl(fd, SNDCTL_DSP_STEREO, &stereo) < 0) { |
||||
perror("can't set channels"); |
||||
goto error; |
||||
} |
||||
|
||||
if (ioctl(fd, SNDCTL_DSP_SPEED, &rate) < 0) { |
||||
perror("can't set rate"); |
||||
goto error; |
||||
} |
||||
|
||||
if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &buf.size) < 0) { |
||||
perror("can't set rate"); |
||||
goto error; |
||||
} |
||||
|
||||
if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &bufsize) < 0) { |
||||
perror("can't set buffer"); |
||||
goto error; |
||||
} |
||||
|
||||
return 0; |
||||
|
||||
error: |
||||
close(fd_audio); |
||||
return XMP_ERR_DINIT; |
||||
} |
||||
|
||||
static void bufdump(struct context_data *ctx, void *b, int i) |
||||
{ |
||||
int j; |
||||
|
||||
do { |
||||
if ((j = write(fd_audio, b, i)) > 0) { |
||||
i -= j; |
||||
b += j; |
||||
} else |
||||
break; |
||||
} while (i); |
||||
} |
||||
|
||||
static void myshutdown(struct context_data *ctx) |
||||
{ |
||||
close(fd_audio); |
||||
} |
||||
|
||||
static void mysync() |
||||
{ |
||||
ioctl(fd, SNDCTL_DSP_SYNC, NULL); |
||||
} |
||||
@ -0,0 +1,221 @@ |
||||
/* 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); |
||||
} |
||||
@ -0,0 +1,42 @@ |
||||
/* 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 "common.h" |
||||
#include "driver.h" |
||||
#include "mixer.h" |
||||
|
||||
static int init(struct context_data *); |
||||
static void shutdown(struct context_data *); |
||||
|
||||
static void dummy() |
||||
{ |
||||
} |
||||
|
||||
struct xmp_drv_info drv_smix = { |
||||
"smix", /* driver ID */ |
||||
"nil softmixer", /* driver description */ |
||||
NULL, /* help */ |
||||
init, /* init */ |
||||
shutdown, /* shutdown */ |
||||
dummy, /* starttimer */ |
||||
dummy, /* stoptimer */ |
||||
dummy, /* bufdump */ |
||||
NULL |
||||
}; |
||||
|
||||
static int init(struct context_data *ctx) |
||||
{ |
||||
} |
||||
|
||||
static void shutdown(struct context_data *ctx) |
||||
{ |
||||
} |
||||
@ -0,0 +1,110 @@ |
||||
/*
|
||||
* Copyright (c) 2009 Thomas Pfaff <tpfaff@tp76.info> |
||||
* |
||||
* Permission to use, copy, modify, and distribute this software for any |
||||
* purpose with or without fee is hereby granted, provided that the above |
||||
* copyright notice and this permission notice appear in all copies. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
*/ |
||||
|
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
|
||||
#include <sndio.h> |
||||
|
||||
#include "driver.h" |
||||
#include "mixer.h" |
||||
#include "common.h" |
||||
|
||||
static struct sio_hdl *hdl; |
||||
|
||||
static int init (struct context_data *); |
||||
static void bufdump (struct context_data *, void *, int); |
||||
static void shutdown (struct context_data *); |
||||
static void dummy (void); |
||||
|
||||
struct xmp_drv_info drv_sndio = { |
||||
"sndio", /* driver ID */ |
||||
"OpenBSD sndio", /* driver description */ |
||||
NULL, /* help */ |
||||
init, /* init */ |
||||
shutdown, /* shutdown */ |
||||
dummy, /* starttimer */ |
||||
dummy, /* stoptimer */ |
||||
bufdump, /* bufdump */ |
||||
}; |
||||
|
||||
static void |
||||
dummy (void) |
||||
{ |
||||
} |
||||
|
||||
static int |
||||
init (struct context_data *ctx) |
||||
{ |
||||
struct sio_par par, askpar; |
||||
struct xmp_options *opt = &ctx->o; |
||||
|
||||
hdl = sio_open (NULL, SIO_PLAY, 0); |
||||
if (hdl == NULL) { |
||||
fprintf (stderr, "%s: failed to open audio device\n", |
||||
__func__); |
||||
return XMP_ERR_DINIT; |
||||
} |
||||
|
||||
sio_initpar (&par); |
||||
par.pchan = opt->outfmt & XMP_FORMAT_MONO ? 1 : 2; |
||||
par.rate = opt->freq; |
||||
par.bits = opt->resol; |
||||
par.sig = opt->resol > 8 ? 1 : 0; |
||||
par.le = SIO_LE_NATIVE; |
||||
par.appbufsz = par.rate / 4; |
||||
|
||||
askpar = par; |
||||
if (!sio_setpar (hdl, &par) || !sio_getpar (hdl, &par)) { |
||||
fprintf (stderr, "%s: failed to set parameters\n", __func__); |
||||
goto error; |
||||
} |
||||
|
||||
if ((par.bits == 16 && par.le != askpar.le) || |
||||
par.bits != askpar.bits || |
||||
par.sig != askpar.sig || |
||||
par.pchan != askpar.pchan || |
||||
((par.rate * 1000 < askpar.rate * 995) || |
||||
(par.rate * 1000 > askpar.rate * 1005))) { |
||||
fprintf (stderr, "%s: parameters not supported\n", __func__); |
||||
goto error; |
||||
} |
||||
|
||||
if (!sio_start (hdl)) { |
||||
fprintf (stderr, "%s: failed to start audio device\n", |
||||
__func__); |
||||
goto error; |
||||
} |
||||
return 0; |
||||
|
||||
error: |
||||
sio_close (hdl); |
||||
return XMP_ERR_DINIT; |
||||
} |
||||
|
||||
static void |
||||
bufdump (struct context_data *ctx, void *b, int len) |
||||
{ |
||||
if (b != NULL) |
||||
sio_write (hdl, buf, len); |
||||
} |
||||
|
||||
static void |
||||
shutdown (struct context_data *ctx) |
||||
{ |
||||
sio_close (hdl); |
||||
hdl = NULL; |
||||
} |
||||
@ -0,0 +1,206 @@ |
||||
/* 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); |
||||
} |
||||
@ -0,0 +1,183 @@ |
||||
/* 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 <stdlib.h> |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#include <fcntl.h> |
||||
#include <string.h> |
||||
#include <unistd.h> |
||||
#include <limits.h> |
||||
#include "common.h" |
||||
#include "driver.h" |
||||
#include "convert.h" |
||||
|
||||
#ifndef O_BINARY |
||||
#define O_BINARY 0 |
||||
#endif |
||||
|
||||
#define DATA(x) (((struct data *)drv_wav.data)->x) |
||||
|
||||
struct data { |
||||
int fd; |
||||
uint32 size; |
||||
}; |
||||
|
||||
static int init(struct context_data *); |
||||
static void bufdump(struct context_data *, void *, int); |
||||
static void shutdown(struct context_data *); |
||||
|
||||
static void dummy() |
||||
{ |
||||
} |
||||
|
||||
struct xmp_drv_info drv_wav = { |
||||
"wav", /* driver ID */ |
||||
"WAV writer", /* driver description */ |
||||
NULL, /* help */ |
||||
init, /* init */ |
||||
shutdown, /* shutdown */ |
||||
dummy, /* starttimer */ |
||||
dummy, /* stoptimer */ |
||||
bufdump, /* bufdump */ |
||||
}; |
||||
|
||||
static void writeval_16l(int fd, uint16 v) |
||||
{ |
||||
uint8 x; |
||||
|
||||
x = v & 0xff; |
||||
write(DATA(fd), &x, 1); |
||||
|
||||
x = v >> 8; |
||||
write(DATA(fd), &x, 1); |
||||
} |
||||
|
||||
static void writeval_32l(int fd, uint32 v) |
||||
{ |
||||
uint8 x; |
||||
|
||||
x = v & 0xff; |
||||
write(DATA(fd), &x, 1); |
||||
|
||||
x = (v >> 8) & 0xff; |
||||
write(DATA(fd), &x, 1); |
||||
|
||||
x = (v >> 16) & 0xff; |
||||
write(DATA(fd), &x, 1); |
||||
|
||||
x = (v >> 24) & 0xff; |
||||
write(DATA(fd), &x, 1); |
||||
} |
||||
|
||||
static int init(struct context_data *ctx) |
||||
{ |
||||
char *buf; |
||||
uint32 len = 0; |
||||
uint16 chan; |
||||
uint32 sampling_rate, bytes_per_second; |
||||
uint16 bytes_per_frame, bits_per_sample; |
||||
char *f, filename[PATH_MAX]; |
||||
struct xmp_options *o = &ctx->o; |
||||
|
||||
drv_wav.data = malloc(sizeof (struct data)); |
||||
if (drv_wav.data == NULL) |
||||
return -1; |
||||
|
||||
if (!o->outfile) { |
||||
if (global_filename) { |
||||
if ((f = strrchr(global_filename, '/')) != NULL) |
||||
strncpy(filename, f + 1, PATH_MAX); |
||||
else |
||||
strncpy(filename, global_filename, PATH_MAX); |
||||
} else { |
||||
strcpy(filename, "xmp"); |
||||
} |
||||
|
||||
strncat(filename, ".wav", PATH_MAX); |
||||
|
||||
o->outfile = filename; |
||||
} |
||||
|
||||
if (strcmp(o->outfile, "-")) { |
||||
DATA(fd) = open(o->outfile, O_WRONLY | O_CREAT | O_TRUNC |
||||
| O_BINARY, 0644); |
||||
if (DATA(fd) < 0) |
||||
return -1; |
||||
} else { |
||||
DATA(fd) = 1; |
||||
} |
||||
|
||||
if (strcmp(o->outfile, "-")) { |
||||
int len = strlen(drv_wav.description) + strlen(o->outfile) + 8; |
||||
if ((buf = malloc(len)) == NULL) |
||||
return -1; |
||||
snprintf(buf, len, "%s: %s", drv_wav.description, o->outfile); |
||||
drv_wav.description = buf; |
||||
} else { |
||||
drv_wav.description = strdup("WAV writer: stdout"); |
||||
len = -1; |
||||
} |
||||
|
||||
write(DATA(fd), "RIFF", 4); |
||||
writeval_32l(DATA(fd), len); |
||||
write(DATA(fd), "WAVE", 4); |
||||
|
||||
chan = o->outfmt & XMP_FORMAT_MONO ? 1 : 2; |
||||
sampling_rate = o->freq; |
||||
bits_per_sample = o->resol; |
||||
if (bits_per_sample == 8) |
||||
o->outfmt |= XMP_FMT_UNS; |
||||
bytes_per_frame = chan * bits_per_sample / 8; |
||||
bytes_per_second = sampling_rate * bytes_per_frame; |
||||
|
||||
write(DATA(fd), "fmt ", 4); |
||||
writeval_32l(DATA(fd), 16); |
||||
writeval_16l(DATA(fd), 1); |
||||
writeval_16l(DATA(fd), chan); |
||||
writeval_32l(DATA(fd), sampling_rate); |
||||
writeval_32l(DATA(fd), bytes_per_second); |
||||
writeval_16l(DATA(fd), bytes_per_frame); |
||||
writeval_16l(DATA(fd), bits_per_sample); |
||||
|
||||
write(DATA(fd), "data", 4); |
||||
writeval_32l(DATA(fd), len); |
||||
|
||||
DATA(size) = 0; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static void bufdump(struct context_data *ctx, void *b, int i) |
||||
{ |
||||
struct xmp_options *o = &ctx->o; |
||||
|
||||
if (o->big_endian) |
||||
xmp_cvt_sex(i, b); |
||||
write(DATA(fd), b, i); |
||||
DATA(size) += i; |
||||
} |
||||
|
||||
static void shutdown(struct context_data *ctx) |
||||
{ |
||||
lseek(DATA(fd), 40, SEEK_SET); |
||||
writeval_32l(DATA(fd), DATA(size)); |
||||
|
||||
lseek(DATA(fd), 4, SEEK_SET); |
||||
writeval_32l(DATA(fd), DATA(size) + 40); |
||||
|
||||
if (DATA(fd) > 0) |
||||
close(DATA(fd)); |
||||
|
||||
free(drv_wav.description); |
||||
free(drv_wav.data); |
||||
} |
||||
@ -0,0 +1,177 @@ |
||||
/* 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. |
||||
*/ |
||||
|
||||
/*
|
||||
* Based on Bjornar Henden's driver for Mikmod |
||||
*/ |
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include <windows.h> |
||||
#include "common.h" |
||||
#include "driver.h" |
||||
#include "mixer.h" |
||||
|
||||
#define MAXBUFFERS 32 /* max number of buffers */ |
||||
#define BUFFERSIZE 120 /* buffer size in ms */ |
||||
|
||||
static HWAVEOUT hwaveout; |
||||
static WAVEHDR header[MAXBUFFERS]; |
||||
static LPSTR buffer[MAXBUFFERS]; /* pointers to buffers */ |
||||
static WORD freebuffer; /* */ |
||||
static WORD nextbuffer; /* next buffer to be mixed */ |
||||
static int num_buffers; |
||||
|
||||
static int init(struct context_data *); |
||||
static void bufdump(struct context_data *, void *, int); |
||||
static void deinit(struct context_data *); |
||||
|
||||
static void dummy() |
||||
{ |
||||
} |
||||
|
||||
static char *help[] = { |
||||
"buffers=val", "Number of buffers (default 10)", |
||||
NULL |
||||
}; |
||||
|
||||
struct xmp_drv_info drv_win32 = { |
||||
"win32", /* driver ID */ |
||||
"Windows WinMM driver", /* driver description */ |
||||
help, /* help */ |
||||
init, /* init */ |
||||
deinit, /* shutdown */ |
||||
dummy, /* starttimer */ |
||||
dummy, /* flush */ |
||||
bufdump, /* bufdump */ |
||||
}; |
||||
|
||||
static void show_error(int res) |
||||
{ |
||||
char *msg; |
||||
|
||||
switch (res) { |
||||
case MMSYSERR_ALLOCATED: |
||||
msg = "Device is already open"; |
||||
break; |
||||
case MMSYSERR_BADDEVICEID: |
||||
msg = "Device is out of range"; |
||||
break; |
||||
case MMSYSERR_NODRIVER: |
||||
msg = "No audio driver in this system"; |
||||
break; |
||||
case MMSYSERR_NOMEM: |
||||
msg = "Unable to allocate sound memory"; |
||||
break; |
||||
case WAVERR_BADFORMAT: |
||||
msg = "Audio format not supported"; |
||||
break; |
||||
case WAVERR_SYNC: |
||||
msg = "The device is synchronous"; |
||||
break; |
||||
default: |
||||
msg = "Unknown media error"; |
||||
} |
||||
|
||||
fprintf(stderr, "Error: %s", msg); |
||||
} |
||||
|
||||
static void CALLBACK wave_callback(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, |
||||
DWORD dwParam1, DWORD dwParam2) |
||||
{ |
||||
if (uMsg == WOM_DONE) { |
||||
freebuffer++; |
||||
freebuffer %= num_buffers; |
||||
} |
||||
} |
||||
|
||||
static int init(struct context_data *ctx) |
||||
{ |
||||
struct xmp_options *o = &ctx->o; |
||||
MMRESULT res; |
||||
WAVEFORMATEX wfe; |
||||
int i; |
||||
char *token, **parm; |
||||
|
||||
num_buffers = 10; |
||||
|
||||
parm_init(); |
||||
chkparm1("buffers", num_buffers = strtoul(token, NULL, 0)); |
||||
parm_end(); |
||||
|
||||
if (num_buffers > MAXBUFFERS) |
||||
num_buffers = MAXBUFFERS; |
||||
|
||||
if (!waveOutGetNumDevs()) |
||||
return XMP_ERR_DINIT; |
||||
|
||||
wfe.wFormatTag = WAVE_FORMAT_PCM; |
||||
wfe.wBitsPerSample = o->resol; |
||||
wfe.nChannels = o->flags & XMP_FORMAT_MONO ? 1 : 2; |
||||
wfe.nSamplesPerSec = o->freq; |
||||
wfe.nAvgBytesPerSec = wfe.nSamplesPerSec * wfe.nChannels * |
||||
wfe.wBitsPerSample / 8; |
||||
wfe.nBlockAlign = wfe.nChannels * wfe.wBitsPerSample / 8; |
||||
|
||||
res = waveOutOpen(&hwaveout, WAVE_MAPPER, &wfe, (DWORD) wave_callback, |
||||
0, CALLBACK_FUNCTION); |
||||
|
||||
if (res != MMSYSERR_NOERROR) { |
||||
show_error(res); |
||||
return XMP_ERR_DINIT; |
||||
} |
||||
|
||||
waveOutReset(hwaveout); |
||||
|
||||
for (i = 0; i < num_buffers; i++) { |
||||
buffer[i] = malloc(OUT_MAXLEN); |
||||
header[i].lpData = buffer[i]; |
||||
|
||||
if (!buffer[i] || res != MMSYSERR_NOERROR) { |
||||
show_error(res); |
||||
return XMP_ERR_DINIT; |
||||
} |
||||
} |
||||
|
||||
freebuffer = nextbuffer = 0; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static void bufdump(struct context_data *ctx, void *b, int len) |
||||
{ |
||||
memcpy(buffer[nextbuffer], b, len); |
||||
|
||||
while ((nextbuffer + 1) % num_buffers == freebuffer) |
||||
Sleep(10); |
||||
|
||||
header[nextbuffer].dwBufferLength = len; |
||||
waveOutPrepareHeader(hwaveout, &header[nextbuffer], sizeof(WAVEHDR)); |
||||
waveOutWrite(hwaveout, &header[nextbuffer], sizeof(WAVEHDR)); |
||||
|
||||
nextbuffer++; |
||||
nextbuffer %= num_buffers; |
||||
} |
||||
|
||||
static void deinit(struct context_data *ctx) |
||||
{ |
||||
int i; |
||||
|
||||
if (hwaveout) { |
||||
for (i = 0; i < num_buffers; i++) { |
||||
if (header[i].dwFlags & WHDR_PREPARED) |
||||
waveOutUnprepareHeader(hwaveout, &header[i], |
||||
sizeof(WAVEHDR)); |
||||
free(buffer[i]); |
||||
} |
||||
while (waveOutClose(hwaveout) == WAVERR_STILLPLAYING) |
||||
Sleep(10); |
||||
hwaveout = NULL; |
||||
} |
||||
} |
||||
@ -0,0 +1,63 @@ |
||||
#include <stdio.h> |
||||
#include <xmp.h> |
||||
|
||||
void info_mod(struct xmp_module_info *mi) |
||||
{ |
||||
int i; |
||||
|
||||
printf("Module name : %s\n", mi->mod->name); |
||||
printf("Module type : %s\n", mi->mod->type); |
||||
printf("Module length : %d patterns\n", mi->mod->len); |
||||
printf("Stored patterns: %d\n", mi->mod->pat); |
||||
printf("Instruments : %d\n", mi->mod->ins); |
||||
printf("Samples : %d\n", mi->mod->smp); |
||||
printf("Channels : %d [ ", mi->mod->chn); |
||||
|
||||
for (i = 0; i < mi->mod->chn; i++) { |
||||
printf("%x ", mi->mod->xxc[i].pan >> 4); |
||||
} |
||||
printf("]\n"); |
||||
|
||||
printf("Estimated time : %dmin%ds\n", (mi->total_time + 500) / 60000, |
||||
((mi->total_time + 500) / 1000) % 60); |
||||
} |
||||
|
||||
|
||||
void info_frame(struct xmp_module_info *mi, int reset) |
||||
{ |
||||
static int ord = -1, tpo = -1, bpm = -1; |
||||
static int max_channels = -1; |
||||
int time; |
||||
|
||||
if (reset) { |
||||
ord = -1; |
||||
max_channels = -1; |
||||
} |
||||
|
||||
if (mi->virt_used > max_channels) |
||||
max_channels = mi->virt_used; |
||||
|
||||
if (mi->frame != 0) |
||||
return; |
||||
|
||||
time = mi->current_time / 100; |
||||
|
||||
if (mi->order != ord || mi->bpm != bpm || mi->tempo != tpo) { |
||||
printf("\rTempo[%02X] BPM[%02X] Pos[%02X/%02X] " |
||||
"Pat[%02X/%02X] Row[ / ] Chn[ / ] 0:00:00.0", |
||||
mi->tempo, mi->bpm, |
||||
mi->order, mi->mod->len - 1, |
||||
mi->pattern, mi->mod->pat - 1); |
||||
ord = mi->order; |
||||
bpm = mi->bpm; |
||||
tpo = mi->tempo; |
||||
} |
||||
|
||||
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" |
||||
"%02X/%02X] Chn[%02X/%02X] %3d:%02d:%02d.%d", |
||||
mi->row, mi->num_rows - 1, mi->virt_used, max_channels, |
||||
(int)(time / (60 * 600)), (int)((time / 600) % 60), |
||||
(int)((time / 10) % 60), (int)(time % 10)); |
||||
|
||||
fflush(stdout); |
||||
} |
||||
@ -0,0 +1,637 @@ |
||||
/* 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. |
||||
*/ |
||||
|
||||
/*
|
||||
* Fri, 05 Jun 1998 16:46:13 -0700 "Mark R. Boyns" <boyns@sdsu.edu> |
||||
* I needed to use xmp as a filter and was able to use /dev/fd/0 as an |
||||
* input source but ran into problems with xmp trying to read interactive |
||||
* commands. So, I added a few lines of code to disable command reading |
||||
* with the --nocmd option. |
||||
*/ |
||||
|
||||
/*
|
||||
* Wed, 10 Jun 1998 15:42:25 -0500 Douglas Carmichael <dcarmich@dcarmichael.net> |
||||
* Support for real-time priority in FreeBSD. |
||||
*/ |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <time.h> |
||||
#include <sys/time.h> |
||||
#include <sys/types.h> |
||||
#ifdef __CYGWIN__ |
||||
#include <sys/select.h> |
||||
#endif |
||||
#ifdef HAVE_SIGNAL_H |
||||
#include <signal.h> |
||||
#endif |
||||
#include <unistd.h> |
||||
|
||||
#ifdef __AROS__ |
||||
#define __AMIGA__ |
||||
#endif |
||||
|
||||
#ifdef __AMIGA__ |
||||
#undef HAVE_TERMIOS_H |
||||
#define __USE_INLINE__ |
||||
#include <proto/dos.h> |
||||
#endif |
||||
|
||||
#ifdef HAVE_TERMIOS_H |
||||
#include <termios.h> |
||||
#endif |
||||
|
||||
#ifdef HAVE_SYS_RTPRIO_H |
||||
#include <sys/resource.h> |
||||
#include <sys/rtprio.h> |
||||
#endif |
||||
|
||||
#ifdef __EMX__ |
||||
#define INCL_BASE |
||||
#include <os2.h> |
||||
#endif |
||||
|
||||
#ifdef WIN32 |
||||
#include <windows.h> |
||||
#include "conio.h" |
||||
#endif |
||||
|
||||
#include "xmp.h" |
||||
|
||||
extern int optind; |
||||
|
||||
/* Options not belonging to libxmp */ |
||||
int probeonly = 0; |
||||
int randomize = 0; |
||||
int loadonly = 0; |
||||
int nocmd = 0; |
||||
int showtime = 0; |
||||
#ifdef HAVE_SYS_RTPRIO_H |
||||
int rt = 0; |
||||
#endif |
||||
|
||||
static struct xmp_options *opt; |
||||
|
||||
static int verbosity; |
||||
#ifdef HAVE_TERMIOS_H |
||||
static struct termios term; |
||||
#endif |
||||
static int background = 0; |
||||
#ifdef SIGTSTP |
||||
static int stopped = 0; |
||||
#endif |
||||
static int refresh_status = 0; |
||||
static int max_nch = 0; |
||||
static double rows, tot_nch; |
||||
int skip = 0; |
||||
|
||||
#ifdef HAVE_SIGNAL_H |
||||
static int sigusr = 0; |
||||
#endif |
||||
|
||||
void get_options (int, char **, struct xmp_options *, xmp_context); |
||||
void init_drivers (void); |
||||
|
||||
static xmp_context ctx; |
||||
static int paused; |
||||
|
||||
|
||||
static int set_tty() |
||||
{ |
||||
#ifdef HAVE_TERMIOS_H |
||||
struct termios t; |
||||
|
||||
if (background) |
||||
return -1; |
||||
|
||||
if (tcgetattr (0, &term) < 0) |
||||
return -1; |
||||
|
||||
t = term; |
||||
t.c_lflag &= ~(ECHO | ICANON | TOSTOP); |
||||
t.c_cc[VMIN] = t.c_cc[VTIME] = 0; |
||||
|
||||
if (tcsetattr (0, TCSAFLUSH, &t) < 0) |
||||
return -1; |
||||
#endif |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
static int reset_tty() |
||||
{ |
||||
#ifdef HAVE_TERMIOS_H |
||||
if (background) |
||||
return -1; |
||||
|
||||
if (tcsetattr(0, TCSAFLUSH, &term) < 0) { |
||||
fprintf(stderr, "can't reset terminal!\n"); |
||||
return -1; |
||||
} |
||||
#endif |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
#ifdef HAVE_SIGNAL_H |
||||
|
||||
#ifdef SIGTSTP |
||||
static void sigtstp_handler(int n) |
||||
{ |
||||
if (!stopped) { |
||||
if (showtime) |
||||
fprintf(stderr, "\n"); |
||||
else if (verbosity) |
||||
fprintf(stderr, "] - STOPPED\n"); |
||||
xmp_timer_stop(ctx); |
||||
stopped = 1; |
||||
} |
||||
|
||||
signal (SIGTSTP, SIG_DFL); |
||||
kill (getpid (), SIGTSTP); |
||||
} |
||||
|
||||
|
||||
static void sigcont_handler(int n) |
||||
{ |
||||
#ifndef __AMIGA__ |
||||
background = (tcgetpgrp(0) == getppid()); |
||||
#endif |
||||
|
||||
if (background) |
||||
reset_tty(); |
||||
else |
||||
set_tty(); |
||||
|
||||
if (stopped) |
||||
xmp_timer_restart(ctx); |
||||
|
||||
stopped = 0; |
||||
refresh_status = 1; |
||||
|
||||
/* Unlike BSD systems, signals under Linux are reset to their
|
||||
* default behavior when raised. |
||||
*/ |
||||
signal(SIGCONT, sigcont_handler); |
||||
signal(SIGTSTP, sigtstp_handler); |
||||
} |
||||
#endif |
||||
|
||||
static void sigusr_handler(int n) |
||||
{ |
||||
signal(sigusr = n, sigusr_handler); |
||||
} |
||||
|
||||
|
||||
static void cleanup(int s) |
||||
{ |
||||
signal(SIGTERM, SIG_DFL); |
||||
signal(SIGINT, SIG_DFL); |
||||
#ifdef SIGQUIT |
||||
signal(SIGQUIT, SIG_DFL); |
||||
#endif |
||||
signal(SIGFPE, SIG_DFL); |
||||
signal(SIGSEGV, SIG_DFL); |
||||
|
||||
fprintf(stderr, "\n*** Interrupted: signal %d caught\n", s); |
||||
xmp_stop_module(ctx); |
||||
xmp_close_audio(ctx); |
||||
|
||||
reset_tty (); |
||||
|
||||
exit (-2); |
||||
} |
||||
|
||||
#endif /* HAVE_SIGNAL_H */ |
||||
|
||||
#ifdef __CYGWIN__ |
||||
/*
|
||||
* from daniel åkerud <daniel.akerud@gmail.com> |
||||
* date Tue, Jul 28, 2009 at 9:59 AM |
||||
* |
||||
* Under Cygwin, the read() in process_echoback blocks because VTIME = 0 |
||||
* is not handled correctly. To fix this you can either: |
||||
* |
||||
* 1. Enable "tty emulation" in Cygwin using an environment variable. |
||||
* http://www.mail-archive.com/cygwin@cygwin.com/msg99417.html
|
||||
* For me this is _very_ slow and I can see the characters as they are |
||||
* typed out when running xmp. I have not investigated why this is |
||||
* happening, but there is of course a reason why this mode is not |
||||
* enabled by default. |
||||
*
|
||||
* 2. Do a select() before read()ing if the platform is Cygwin. |
||||
* This makes Cygwin builds work out of the box with no fiddling around, |
||||
* but does impose a neglectible cpu overhead (for Cygwin builds only). |
||||
*/ |
||||
static int stdin_ready_for_reading() |
||||
{ |
||||
fd_set fds; |
||||
struct timeval tv; |
||||
int ret; |
||||
|
||||
tv.tv_sec = 0; |
||||
tv.tv_usec = 0; |
||||
|
||||
FD_ZERO(&fds); |
||||
FD_SET(STDIN_FILENO, &fds); |
||||
|
||||
ret = select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv); |
||||
|
||||
if (ret > 0 && FD_ISSET(STDIN_FILENO, &fds)) |
||||
return 1; |
||||
|
||||
return 0; |
||||
} |
||||
#endif |
||||
|
||||
void read_keyboard() |
||||
{ |
||||
unsigned char cmd; |
||||
int k; |
||||
|
||||
/* Interactive commands */ |
||||
|
||||
if (nocmd || background) |
||||
return; |
||||
|
||||
#if defined HAVE_TERMIOS_H && !defined WIN32 |
||||
#ifdef __CYGWIN__ |
||||
k = 0; |
||||
if (stdin_ready_for_reading()) |
||||
#endif |
||||
k = read(0, &cmd, 1); |
||||
#elif defined WIN32 |
||||
k = cmd = kbhit() ? getch() : 0; |
||||
#elif defined __AMIGA__ |
||||
/* Amiga CLI */ |
||||
{ |
||||
BPTR in = Input(); |
||||
k = cmd = 0; |
||||
if (WaitForChar(in, 1)) { |
||||
char c; |
||||
Read(in, &c, 1); |
||||
cmd = k = c; |
||||
} |
||||
} |
||||
#else |
||||
k = cmd = 0; |
||||
#endif |
||||
|
||||
if (k > 0) { |
||||
switch (cmd) { |
||||
case 'q': /* quit */ |
||||
skip = -2; |
||||
xmp_mod_stop(ctx); |
||||
paused = 0; |
||||
break; |
||||
case 'f': /* jump to next order */ |
||||
xmp_ord_next(ctx); |
||||
paused = 0; |
||||
break; |
||||
case 'b': /* jump to previous order */ |
||||
xmp_ord_prev(ctx); |
||||
paused = 0; |
||||
break; |
||||
case 'n': /* skip to next module */ |
||||
skip = 1; |
||||
xmp_mod_stop(ctx); |
||||
paused = 0; |
||||
break; |
||||
case 'p': /* skip to previous module */ |
||||
skip = -1; |
||||
xmp_mod_stop(ctx); |
||||
paused = 0; |
||||
break; |
||||
case 'l': |
||||
if (xmp_test_flag(ctx, XMP_CTL_LOOP)) |
||||
xmp_reset_flag(ctx, XMP_CTL_LOOP); |
||||
else |
||||
xmp_set_flag(ctx, XMP_CTL_LOOP); |
||||
break; |
||||
case ' ': /* paused module */ |
||||
paused ^= 1; |
||||
|
||||
if (verbosity) { |
||||
fprintf (stderr, "%s", paused ? |
||||
"] - PAUSED\b\b\b\b\b\b\b\b\b\b" : |
||||
"] \b\b\b\b\b\b\b\b\b\b"); |
||||
} |
||||
|
||||
if (paused) |
||||
xmp_timer_stop(ctx); |
||||
else |
||||
xmp_timer_restart(ctx); |
||||
|
||||
break; |
||||
case '1': |
||||
case '2': |
||||
case '3': |
||||
case '4': |
||||
case '5': |
||||
case '6': |
||||
case '7': |
||||
case '8': |
||||
case '9': |
||||
xmp_channel_mute(ctx, cmd - '1', 1, -1); |
||||
break; |
||||
case '0': |
||||
xmp_channel_mute(ctx, 9, 1, -1); |
||||
break; |
||||
case '!': |
||||
xmp_channel_mute(ctx, 0, 8, 0); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
static void shuffle (int argc, char **argv) |
||||
{ |
||||
int i, j; |
||||
char *x; |
||||
|
||||
for (i = 1; i < argc; i++) { |
||||
j = 1 + rand () % (argc - 1); |
||||
x = argv[i]; |
||||
argv[i] = argv[j]; |
||||
argv[j] = x; |
||||
} |
||||
} |
||||
|
||||
|
||||
int main(int argc, char **argv) |
||||
{ |
||||
int i, t, lf_flag, first, num_mod; |
||||
time_t t0, t1, t2, t3; |
||||
#ifndef WIN32 |
||||
struct timeval tv; |
||||
struct timezone tz; |
||||
#endif |
||||
#ifdef HAVE_SYS_RTPRIO_H |
||||
struct rtprio rtp; |
||||
#endif |
||||
int getprevious = 0, skipprev = 0; |
||||
#ifdef __EMX__ |
||||
long rc; |
||||
#endif |
||||
struct xmp_module_info mi; |
||||
|
||||
init_drivers(); |
||||
|
||||
ctx = xmp_create_context(); |
||||
|
||||
xmp_init(ctx, argc, argv); |
||||
opt = xmp_get_options(ctx); |
||||
|
||||
//opt->verbosity = 1;
|
||||
get_options(argc, argv, opt, ctx); |
||||
//verbosity = opt->verbosity;
|
||||
|
||||
if (!(probeonly || argv[optind])) { |
||||
fprintf (stderr, "%s: no modules to play\n" |
||||
"Use `%s --help' for more information.\n", argv[0], argv[0]); |
||||
exit (-1); |
||||
} |
||||
|
||||
#ifndef WIN32 |
||||
gettimeofday(&tv, &tz); |
||||
srand(tv.tv_usec); |
||||
#else |
||||
srand(GetTickCount()); |
||||
#endif |
||||
|
||||
if (randomize) |
||||
shuffle(argc - optind + 1, &argv[optind - 1]); |
||||
|
||||
if (opt->outfile && (!opt->drv_id || strcmp(opt->drv_id, "wav"))) |
||||
opt->drv_id = "file"; |
||||
|
||||
global_filename = argv[optind]; |
||||
|
||||
#ifdef HAVE_TERMIOS_H |
||||
if ((background = (tcgetpgrp (0) == getppid ()))) { |
||||
//verb = opt->verbosity;
|
||||
//opt->verbosity = 0;
|
||||
i = xmp_open_audio(ctx); |
||||
//xmp_verbosity_level(ctx, opt->verbosity = verb);
|
||||
} else |
||||
#endif |
||||
{ |
||||
i = xmp_open_audio(ctx); |
||||
} |
||||
|
||||
if (i < 0) { |
||||
fprintf (stderr, "%s: ", argv[0]); |
||||
switch (i) { |
||||
case XMP_ERR_DINIT: |
||||
fprintf (stderr, "can't initialize driver\n"); |
||||
return -1; |
||||
case XMP_ERR_NODRV: |
||||
fprintf (stderr, "driver does not exist\n"); |
||||
return -2; |
||||
case XMP_ERR_DSPEC: |
||||
fprintf (stderr, "driver not specified\n"); |
||||
return -3; |
||||
default: |
||||
fprintf (stderr, "unknown error\n"); |
||||
return -128; |
||||
} |
||||
} |
||||
|
||||
fprintf(stderr, "Extended Module Player " VERSION "\n" |
||||
"Copyright (C) 1996-2012 Claudio Matsuoka and Hipolito Carraro Jr\n"); |
||||
|
||||
if (1) { |
||||
int srate, res, chn, itpt; |
||||
|
||||
xmp_get_driver_cfg(ctx, &srate, &res, &chn, &itpt); |
||||
fprintf(stderr, "Using %s\n", (char*)xmp_get_driver_description(ctx)); |
||||
if (srate) { |
||||
fprintf(stderr, "Mixer set to %dbit, %d Hz, %s%s\n", res, srate, |
||||
itpt ? "interpolated " : "", chn > 1 ? "stereo" : "mono"); |
||||
} |
||||
} |
||||
|
||||
if (probeonly) |
||||
exit(0); |
||||
|
||||
/*
|
||||
* Support for real-time priority by Douglas Carmichael <dcarmich@mcs.com> |
||||
*/ |
||||
#ifdef HAVE_SYS_RTPRIO_H |
||||
if (rt) { |
||||
rtp.type = RTP_PRIO_REALTIME; |
||||
rtp.prio = 0; |
||||
if (rtprio (RTP_SET, 0, &rtp) == -1) { |
||||
fprintf (stderr, "%s: Can't get realtime priority.\n", argv[0]); |
||||
exit(1); |
||||
} |
||||
} |
||||
#endif |
||||
|
||||
#ifdef __EMX__ |
||||
rc = DosSetPriority (PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MINIMUM, 0); |
||||
if (rc != 0) { |
||||
printf ("Error setting Priority. Priority defaulting to the System Default.\n" ); |
||||
} |
||||
#endif |
||||
|
||||
#ifdef HAVE_SIGNAL_H |
||||
signal(SIGTERM, cleanup); |
||||
signal(SIGINT, cleanup); |
||||
signal(SIGFPE, cleanup); |
||||
signal(SIGSEGV, cleanup); |
||||
#ifdef SIGQUIT |
||||
signal(SIGQUIT, cleanup); |
||||
#endif |
||||
#ifdef SIGTSTP |
||||
signal(SIGTSTP, sigtstp_handler); |
||||
#endif |
||||
#ifdef SIGCONT |
||||
signal(SIGCONT, sigcont_handler); |
||||
#endif |
||||
#ifdef SIGUSR1 |
||||
signal(SIGUSR1, sigusr_handler); |
||||
signal(SIGUSR2, sigusr_handler); |
||||
#endif |
||||
#endif |
||||
|
||||
set_tty (); |
||||
|
||||
paused = 0; |
||||
time (&t0); |
||||
|
||||
num_mod = lf_flag = 0; |
||||
for (first = optind; optind < argc; optind++) { |
||||
if (getprevious) { |
||||
optind -= 2; |
||||
if (optind < first) { |
||||
optind += 2; |
||||
} |
||||
} |
||||
|
||||
if (!background) { |
||||
if (lf_flag) |
||||
fprintf (stderr, "\n"); |
||||
lf_flag = fprintf (stderr, "Loading %s... (%d of %d)\n", |
||||
argv[optind], optind - first + 1, argc - first); |
||||
} |
||||
|
||||
if (background) { |
||||
//verb = xmp_verbosity_level(ctx, 0);
|
||||
t = xmp_load_module(ctx, argv[optind]); |
||||
//xmp_verbosity_level(ctx, verb);
|
||||
} else { |
||||
t = xmp_load_module(ctx, argv[optind]); |
||||
} |
||||
|
||||
if (t < 0) { |
||||
switch (t) { |
||||
case -1: |
||||
fprintf (stderr, "%s: %s: unrecognized file format\n", |
||||
argv[0], argv[optind]); |
||||
getprevious = skipprev; |
||||
continue; |
||||
case -2: |
||||
fprintf (stderr, "%s: %s: possibly corrupted file\n", |
||||
argv[0], argv[optind]); |
||||
getprevious = skipprev; |
||||
continue; |
||||
case -3: { |
||||
char line[1024]; |
||||
snprintf(line, 1024, "%s: %s", *argv, argv[optind]); |
||||
perror(line); |
||||
getprevious = skipprev; |
||||
continue; } |
||||
} |
||||
} |
||||
|
||||
rows = tot_nch = max_nch = getprevious = skipprev = 0; |
||||
num_mod++; |
||||
|
||||
//xmp_get_module_info(ctx, &mi);
|
||||
|
||||
if (loadonly) |
||||
goto skip_play; |
||||
|
||||
/* Play the module */ |
||||
time(&t2); |
||||
xmp_player_start(ctx); |
||||
for (;;) { |
||||
read_keyboard(); |
||||
|
||||
if (paused) { |
||||
usleep(100000); |
||||
} else { |
||||
if (xmp_player_frame(ctx) != 0) |
||||
break; |
||||
xmp_play_buffer(ctx); |
||||
xmp_player_get_info(ctx, &mi); |
||||
printf("%2d %2d %2d\r", mi.order, mi.pattern, mi.row); |
||||
fflush(stdout); |
||||
} |
||||
} |
||||
xmp_player_end(ctx); |
||||
time(&t3); |
||||
t = difftime(t3, t2); |
||||
|
||||
xmp_release_module(ctx); |
||||
|
||||
if (showtime) { |
||||
fprintf(stderr, "\r \r"); |
||||
} |
||||
if (!background) { |
||||
fprintf (stderr, |
||||
"\rElapsed time : %dmin%02ds %s \n", |
||||
t / 60, t % 60, skip ? "(SKIPPED)" : " "); |
||||
|
||||
#if 0 |
||||
fprintf (stderr, "Channels used : %d/%d", max_nch, mi.chn); |
||||
if (max_nch) |
||||
fprintf (stderr, ", avg %.2f (%.1f%%)\n", |
||||
tot_nch / rows, 100.0 * tot_nch / rows / mi.chn); |
||||
else |
||||
fprintf (stderr, "\n"); |
||||
#endif |
||||
} |
||||
|
||||
skip_play: |
||||
|
||||
if (skip == -1) { |
||||
optind -= optind > first ? 2 : 1; |
||||
skipprev = 1; |
||||
} |
||||
|
||||
if (skip == -2) |
||||
break; |
||||
|
||||
skip = 0; |
||||
} |
||||
|
||||
time (&t1); |
||||
|
||||
if (!loadonly && !background && num_mod > 1) { |
||||
t = difftime (t1, t0); |
||||
fprintf (stderr, "\n\t%d modules played, total time %dh%02dmin%02ds\n", |
||||
num_mod, t / 3600, (t % 3600) / 60, t % 60);
|
||||
} |
||||
|
||||
xmp_close_audio(ctx); |
||||
xmp_deinit(ctx); |
||||
xmp_free_context(ctx); |
||||
reset_tty(); |
||||
|
||||
return 0; |
||||
} |
||||
@ -0,0 +1,141 @@ |
||||
/* A simple frontend for xmp */ |
||||
|
||||
#define HAVE_TERMIOS_H |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <signal.h> |
||||
#include <sys/time.h> |
||||
#include <xmp.h> |
||||
//#include "sound.h"
|
||||
#include "common.h" |
||||
|
||||
extern int optind; |
||||
|
||||
static void cleanup() |
||||
{ |
||||
signal(SIGTERM, SIG_DFL); |
||||
signal(SIGINT, SIG_DFL); |
||||
signal(SIGQUIT, SIG_DFL); |
||||
signal(SIGFPE, SIG_DFL); |
||||
signal(SIGSEGV, SIG_DFL); |
||||
|
||||
sound_deinit(); |
||||
reset_tty(); |
||||
printf("\n"); |
||||
exit(EXIT_FAILURE); |
||||
} |
||||
|
||||
|
||||
static void shuffle(int argc, char **argv) |
||||
{ |
||||
int i, j; |
||||
char *x; |
||||
|
||||
for (i = 1; i < argc; i++) { |
||||
j = 1 + rand() % (argc - 1); |
||||
x = argv[i]; |
||||
argv[i] = argv[j]; |
||||
argv[j] = x; |
||||
} |
||||
} |
||||
|
||||
int main(int argc, char **argv) |
||||
{ |
||||
xmp_context ctx; |
||||
struct xmp_module_info mi; |
||||
struct options options; |
||||
int i; |
||||
int silent = 0; |
||||
int first; |
||||
#ifndef WIN32 |
||||
struct timeval tv; |
||||
struct timezone tz; |
||||
|
||||
gettimeofday(&tv, &tz); |
||||
srand(tv.tv_usec); |
||||
#else |
||||
srand(GetTickCount()); |
||||
#endif |
||||
|
||||
memset(&options, 0, sizeof (struct options)); |
||||
get_options(argc, argv, &options); |
||||
|
||||
if (options.random) { |
||||
shuffle(argc - optind + 1, &argv[optind - 1]); |
||||
} |
||||
|
||||
if (!silent && sound_init(44100, 2) < 0) { |
||||
fprintf(stderr, "%s: can't initialize sound\n", argv[0]); |
||||
exit(EXIT_FAILURE); |
||||
} |
||||
|
||||
signal(SIGTERM, cleanup); |
||||
signal(SIGINT, cleanup); |
||||
signal(SIGFPE, cleanup); |
||||
signal(SIGSEGV, cleanup); |
||||
signal(SIGQUIT, cleanup); |
||||
|
||||
set_tty(); |
||||
|
||||
ctx = xmp_create_context(); |
||||
|
||||
for (first = optind; optind < argc; optind++) { |
||||
printf("\nLoading %s... (%d of %d)\n", |
||||
argv[optind], optind - first + 1, argc - first); |
||||
|
||||
if (xmp_load_module(ctx, argv[optind]) < 0) { |
||||
fprintf(stderr, "%s: error loading %s\n", argv[0], |
||||
argv[i]); |
||||
continue; |
||||
} |
||||
|
||||
if (xmp_player_start(ctx, options.start, 44100, 0) == 0) { |
||||
int new_mod = 1; |
||||
|
||||
/* Mute channels */ |
||||
|
||||
for (i = 0; i < XMP_MAX_CHANNELS; i++) { |
||||
xmp_channel_mute(ctx, i, options.mute[i]); |
||||
} |
||||
|
||||
/* Show module data */ |
||||
|
||||
xmp_player_get_info(ctx, &mi); |
||||
|
||||
info_mod(&mi); |
||||
|
||||
/* Play module */ |
||||
|
||||
while (xmp_player_frame(ctx) == 0) { |
||||
|
||||
xmp_player_get_info(ctx, &mi); |
||||
if (mi.loop_count > 0) |
||||
break; |
||||
|
||||
info_frame(&mi, new_mod); |
||||
if (!silent) { |
||||
sound_play(mi.buffer, mi.buffer_size); |
||||
} |
||||
|
||||
new_mod = 0; |
||||
options.start = 0; |
||||
|
||||
} |
||||
xmp_player_end(ctx); |
||||
} |
||||
|
||||
xmp_release_module(ctx); |
||||
printf("\n"); |
||||
} |
||||
xmp_free_context(ctx); |
||||
|
||||
reset_tty(); |
||||
|
||||
if (!silent) { |
||||
sound_deinit(); |
||||
} |
||||
|
||||
exit(EXIT_SUCCESS); |
||||
} |
||||
@ -0,0 +1,325 @@ |
||||
/* 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. |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <ctype.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include <unistd.h> |
||||
#include <getopt.h> |
||||
#include <xmp.h> |
||||
|
||||
#include "common.h" |
||||
|
||||
extern char *optarg; |
||||
static int o, i; |
||||
static char *token; |
||||
|
||||
extern int probeonly; |
||||
extern int loadonly; |
||||
extern int randomize; |
||||
extern int nocmd; |
||||
#ifdef HAVE_SYS_RTPRIO_H |
||||
extern int rt; |
||||
#endif |
||||
|
||||
#define OPT_LOADONLY 0x103 |
||||
#define OPT_FX9BUG 0x105 |
||||
#define OPT_PROBEONLY 0x106 |
||||
#define OPT_STDOUT 0x109 |
||||
#define OPT_STEREO 0x10a |
||||
#define OPT_NOCMD 0x10b |
||||
#define OPT_REALTIME 0x10c |
||||
#define OPT_FIXLOOP 0x10d |
||||
#define OPT_CRUNCH 0x10e |
||||
#define OPT_NOFILTER 0x10f |
||||
#define OPT_VBLANK 0x110 |
||||
#define OPT_SHOWTIME 0x111 |
||||
#define OPT_DUMP 0x112 |
||||
|
||||
static void exclude_formats(char *list) |
||||
{ |
||||
char *tok; |
||||
|
||||
tok = strtok(list, ", "); |
||||
while (tok) { |
||||
xmp_enable_format(tok, 0); |
||||
tok = strtok(NULL, ", "); |
||||
} |
||||
} |
||||
|
||||
static void list_wrap(char *s, int l, int r, int v) |
||||
{ |
||||
int i; |
||||
static int c = 0; |
||||
static int m = 0; |
||||
char *t; |
||||
|
||||
if (s == NULL) { |
||||
for (i = 0; i < l; i++) |
||||
printf(" "); |
||||
c = l; |
||||
m = r; |
||||
return; |
||||
} else if (c > l) { |
||||
c++; |
||||
printf(v ? "," : " "); |
||||
} |
||||
|
||||
t = strtok(s, " "); |
||||
|
||||
while (t) { |
||||
if ((c + strlen(t) + 1) > m) { |
||||
c = l; |
||||
printf("\n"); |
||||
for (i = 0; i < l; i++) { |
||||
printf(" "); |
||||
} |
||||
} else if (c > l) { |
||||
printf(" "); |
||||
} |
||||
c += strlen(t) + 1; |
||||
printf("%s", t); |
||||
t = strtok(NULL, " "); |
||||
} |
||||
} |
||||
|
||||
static void usage(char *s) |
||||
{ |
||||
struct xmp_fmt_info *f, *fmt; |
||||
struct xmp_drv_info *d, *drv; |
||||
char **hlp, buf[80]; |
||||
int i; |
||||
|
||||
printf("Usage: %s [options] [modules]\n", s); |
||||
|
||||
#if 0 |
||||
printf("\nRegistered module loaders:\n"); |
||||
xmp_get_fmt_info(&fmt); |
||||
list_wrap(NULL, 3, 78, 1); |
||||
|
||||
for (i = 0, f = fmt; f; i++, f = f->next) { |
||||
snprintf(buf, 80, "%s (%s)", f->id, f->tracker); |
||||
list_wrap(buf, 3, 0, 1); |
||||
} |
||||
|
||||
snprintf(buf, 80, "[%d registered loaders]", i); |
||||
list_wrap(buf, 3, 0, 0); |
||||
printf("\n"); |
||||
|
||||
printf("\nAvailable drivers:\n"); |
||||
|
||||
xmp_get_drv_info(&drv); |
||||
list_wrap(NULL, 3, 78, 1); |
||||
for (d = drv; d; d = d->next) { |
||||
snprintf(buf, 80, "%s (%s)", d->id, d->description); |
||||
list_wrap(buf, 3, 0, 1); |
||||
} |
||||
|
||||
printf("\n"); |
||||
|
||||
for (d = drv; d; d = d->next) { |
||||
if (d->help) |
||||
printf("\n%s options:\n", d->description); |
||||
for (hlp = d->help; hlp && *hlp; hlp += 2) |
||||
printf(" -D%-20.20s %s\n", hlp[0], hlp[1]); |
||||
} |
||||
#endif |
||||
|
||||
printf("\nPlayer control options:\n" |
||||
" -D parameter[=val] Pass configuration parameter to the output driver\n" |
||||
" -d --driver name Force output to the specified device\n" |
||||
" --fix-sample-loops Use sample loop start /2 in MOD/UNIC/NP3\n" |
||||
" --offset-bug-emulation Emulate Protracker 2.x bug in effect 9\n" |
||||
" -l --loop Enable module looping\n" |
||||
" -M --mute ch-list Mute the specified channels\n" |
||||
" --nocmd Disable interactive commands\n" |
||||
" --norc Don't read configuration files\n" |
||||
" -R --random Random order playing\n" |
||||
#ifdef HAVE_SYS_RTPRIO_H |
||||
" --realtime Run in real-time priority\n" |
||||
#endif |
||||
" -S --solo ch-list Set channels to solo mode\n" |
||||
" -s --start num Start from the specified order\n" |
||||
" -T --tempo num Initial tempo (default 6)\n" |
||||
" -t --time num Maximum playing time in seconds\n" |
||||
" --vblank Force vblank timing in Amiga modules (no CIA)\n" |
||||
"\nPlayer sound options:\n" |
||||
" -8 --8bit Convert 16 bit samples to 8 bit\n" |
||||
" -m --mono Mono output\n" |
||||
" -P --pan pan Percentual pan amplitude\n" |
||||
" -r --reverse Reverse left/right stereo channels\n" |
||||
" --stereo Stereo output\n" |
||||
"\nSoftware mixer options:\n" |
||||
" -a --amplify {0|1|2|3} Amplification factor: 0=Normal, 1=x2, 2=x4, 3=x8\n" |
||||
" -b --bits {8|16} Software mixer resolution (8 or 16 bits)\n" |
||||
" -c --stdout Mix the module to stdout\n" |
||||
" -F --click-filter Apply low pass filter to reduce clicks\n" |
||||
" -f --frequency rate Sampling rate in hertz (default 44100)\n" |
||||
" -n --nearest Use nearest neighbor interpolation\n" |
||||
" -o --output-file name Mix the module to file ('-' for stdout)\n" |
||||
" -u --unsigned Set the mixer to use unsigned samples\n" |
||||
"\nEnvironment options:\n" |
||||
" -I --instrument-path Set pathname to external samples\n" |
||||
"\nInformation options:\n" |
||||
" -h --help Print a summary of the command line options\n" |
||||
" --load-only Load module and exit\n" |
||||
" --probe-only Probe audio device and exit\n" |
||||
" -q --quiet Quiet mode (verbosity level = 0)\n" |
||||
" --show-time Display elapsed and remaining time\n" |
||||
" -V --version Print version information\n" |
||||
" -v --verbose Verbose mode (incremental)\n"); |
||||
} |
||||
|
||||
void get_options(int argc, char **argv, struct options *options) |
||||
{ |
||||
int optidx = 0; |
||||
#define OPTIONS "a:b:cD:d:f:hI:lM:mo:qRS:s:T:t:uVv" |
||||
static struct option lopt[] = { |
||||
{"amplify", 1, 0, 'a'}, |
||||
{"bits", 1, 0, 'b'}, |
||||
{"driver", 1, 0, 'd'}, |
||||
{"frequency", 1, 0, 'f'}, |
||||
{"offset-bug-emulation", 0, 0, OPT_FX9BUG}, |
||||
{"help", 0, 0, 'h'}, |
||||
{"instrument-path", 1, 0, 'I'}, |
||||
{"load-only", 0, 0, OPT_LOADONLY}, |
||||
{"loop", 0, 0, 'l'}, |
||||
{"mono", 0, 0, 'm'}, |
||||
{"mute", 1, 0, 'M'}, |
||||
{"nocmd", 0, 0, OPT_NOCMD}, |
||||
{"output-file", 1, 0, 'o'}, |
||||
{"pan", 1, 0, 'P'}, |
||||
{"quiet", 0, 0, 'q'}, |
||||
{"random", 0, 0, 'R'}, |
||||
{"solo", 1, 0, 'S'}, |
||||
{"start", 1, 0, 's'}, |
||||
{"stdout", 0, 0, 'c'}, |
||||
{"tempo", 1, 0, 'T'}, |
||||
{"time", 1, 0, 't'}, |
||||
{"unsigned", 0, 0, 'u'}, |
||||
{"version", 0, 0, 'V'}, |
||||
{"verbose", 0, 0, 'v'}, |
||||
{NULL, 0, 0, 0} |
||||
}; |
||||
|
||||
i = 0; |
||||
while ((o = getopt_long(argc, argv, OPTIONS, lopt, &optidx)) != -1) { |
||||
switch (o) { |
||||
case 'a': |
||||
options->amplify = atoi(optarg); |
||||
break; |
||||
case 'b': |
||||
if (atoi(optarg) == 8) { |
||||
options->format |= XMP_FORMAT_8BIT; |
||||
} |
||||
break; |
||||
case 'c': |
||||
options->out_file = "-"; |
||||
break; |
||||
#if 0 |
||||
case 'D': |
||||
xmp_set_driver_parameter(opt, optarg); |
||||
break; |
||||
case 'd': |
||||
options->drv_id = optarg; |
||||
break; |
||||
case OPT_FX9BUG: |
||||
options->quirk |= XMP_QRK_FX9BUG; |
||||
break; |
||||
#endif |
||||
case 'f': |
||||
options->freq = strtoul(optarg, NULL, 0); |
||||
break; |
||||
case 'I': |
||||
options->ins_path = optarg; |
||||
break; |
||||
case 'l': |
||||
options->loop = 1; |
||||
break; |
||||
case OPT_LOADONLY: |
||||
options->load_only = 1; |
||||
break; |
||||
case 'm': |
||||
options->format |= XMP_FORMAT_MONO; |
||||
break; |
||||
case 'o': |
||||
options->out_file = optarg; |
||||
if (strlen(optarg) >= 4 && |
||||
!strcasecmp(optarg + strlen(optarg) - 4, ".wav")) { |
||||
//options->drv_id = "wav";
|
||||
} |
||||
break; |
||||
case 'P': |
||||
options->mix = strtoul(optarg, NULL, 0); |
||||
if (options->mix < 0) |
||||
options->mix = 0; |
||||
if (options->mix > 100) |
||||
options->mix = 100; |
||||
break; |
||||
case 'q': |
||||
//options->verbosity = 0;
|
||||
break; |
||||
case 'R': |
||||
options->random = 1; |
||||
break; |
||||
case 'M': |
||||
case 'S': |
||||
if (o == 'S') { |
||||
memset(options->mute, 1, XMP_MAX_CHANNELS); |
||||
} |
||||
token = strtok(optarg, ","); |
||||
while (token) { |
||||
int a, b; |
||||
char buf[40]; |
||||
memset(buf, 0, 40); |
||||
if (strchr(token, '-')) { |
||||
b = strcspn(token, "-"); |
||||
strncpy(buf, token, b); |
||||
a = atoi(buf); |
||||
strncpy(buf, token + b + 1, |
||||
strlen(token) - b - 1); |
||||
b = atoi(buf); |
||||
} else { |
||||
a = b = atoi(token); |
||||
} |
||||
for (; b >= a; b--) { |
||||
if (b < XMP_MAX_CHANNELS) |
||||
options->mute[b] = (o == 'M'); |
||||
} |
||||
token = strtok(NULL, ","); |
||||
} |
||||
break; |
||||
case 's': |
||||
options->start = strtoul(optarg, NULL, 0); |
||||
break; |
||||
case 't': |
||||
options->time = strtoul(optarg, NULL, 0); |
||||
break; |
||||
case 'u': |
||||
options->format |= XMP_FORMAT_UNSIGNED; |
||||
break; |
||||
case 'V': |
||||
puts("Extended Module Player " VERSION); |
||||
exit(0); |
||||
case 'v': |
||||
//options->verbosity++;
|
||||
break; |
||||
case 'h': |
||||
usage(argv[0]); |
||||
default: |
||||
exit(-1); |
||||
} |
||||
} |
||||
|
||||
/* Set limits */ |
||||
if (options->freq < 1000) |
||||
options->freq = 1000; /* Min. rate 1 kHz */ |
||||
if (options->freq > 48000) |
||||
options->freq = 48000; /* Max. rate 48 kHz */ |
||||
} |
||||
@ -0,0 +1,11 @@ |
||||
|
||||
struct sound_driver { |
||||
char *id; |
||||
char *description; |
||||
char **help; |
||||
int (*init) (); |
||||
void (*deinit) (); |
||||
void (*pause) (); |
||||
void (*resume) (); |
||||
struct list_head *next; |
||||
}; |
||||
@ -0,0 +1,70 @@ |
||||
|
||||
#include <alsa/asoundlib.h> |
||||
#include <alsa/pcm.h> |
||||
#include "sound.h" |
||||
|
||||
static snd_pcm_t *pcm_handle; |
||||
|
||||
|
||||
int sound_init(int sampling_rate, int channels) |
||||
{ |
||||
snd_pcm_hw_params_t *hwparams; |
||||
int ret; |
||||
unsigned int chan, rate; |
||||
unsigned int btime = 250000; /* 250ms */ |
||||
unsigned int ptime = 50000; /* 50ms */ |
||||
char *card_name = "default"; |
||||
|
||||
if ((ret = snd_pcm_open(&pcm_handle, card_name, |
||||
SND_PCM_STREAM_PLAYBACK, 0)) < 0) { |
||||
fprintf(stderr, "Unable to initialize ALSA pcm device: %s\n", |
||||
snd_strerror(ret)); |
||||
return -1; |
||||
} |
||||
|
||||
chan = channels; |
||||
rate = sampling_rate; |
||||
|
||||
snd_pcm_hw_params_alloca(&hwparams); |
||||
snd_pcm_hw_params_any(pcm_handle, hwparams); |
||||
snd_pcm_hw_params_set_access(pcm_handle, hwparams, |
||||
SND_PCM_ACCESS_RW_INTERLEAVED); |
||||
snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16); |
||||
snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &rate, 0); |
||||
snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &chan); |
||||
snd_pcm_hw_params_set_buffer_time_near(pcm_handle, hwparams, &btime, 0); |
||||
snd_pcm_hw_params_set_period_time_near(pcm_handle, hwparams, &ptime, 0); |
||||
snd_pcm_nonblock(pcm_handle, 0); |
||||
|
||||
if ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) { |
||||
fprintf(stderr, "Unable to set ALSA output parameters: %s\n", |
||||
snd_strerror(ret)); |
||||
return -1; |
||||
} |
||||
|
||||
if ((ret = snd_pcm_prepare(pcm_handle)) < 0) { |
||||
fprintf(stderr, "Unable to prepare ALSA: %s\n", |
||||
snd_strerror(ret)); |
||||
return -1; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
void sound_play(void *b, int i) |
||||
{ |
||||
int frames; |
||||
|
||||
frames = snd_pcm_bytes_to_frames(pcm_handle, i); |
||||
if (snd_pcm_writei(pcm_handle, b, frames) < 0) { |
||||
snd_pcm_prepare(pcm_handle); |
||||
} |
||||
} |
||||
|
||||
void sound_deinit() |
||||
{ |
||||
/* snd_pcm_drain(pcm_handle); */ |
||||
snd_pcm_close(pcm_handle); |
||||
} |
||||
|
||||
|
||||
@ -0,0 +1,41 @@ |
||||
#include <stdio.h> |
||||
#include <termios.h> |
||||
#include <xmp.h> |
||||
#include "common.h" |
||||
|
||||
static int background = 0; |
||||
static struct termios term; |
||||
|
||||
int set_tty() |
||||
{ |
||||
struct termios t; |
||||
|
||||
if (background) |
||||
return -1; |
||||
|
||||
if (tcgetattr(0, &term) < 0) |
||||
return -1; |
||||
|
||||
t = term; |
||||
t.c_lflag &= ~(ECHO | ICANON | TOSTOP); |
||||
t.c_cc[VMIN] = t.c_cc[VTIME] = 0; |
||||
|
||||
if (tcsetattr(0, TCSAFLUSH, &t) < 0) |
||||
return -1; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int reset_tty() |
||||
{ |
||||
if (background) |
||||
return -1; |
||||
|
||||
if (tcsetattr(0, TCSAFLUSH, &term) < 0) { |
||||
fprintf(stderr, "can't reset terminal!\n"); |
||||
return -1; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
Loading…
Reference in new issue