diff --git a/configure.ac b/configure.ac index 1c6a5b8..8c4cb1b 100644 --- a/configure.ac +++ b/configure.ac @@ -6,6 +6,7 @@ AC_ARG_WITH(libxmp, [ --with-libxmp= libxmp prefix (optional)], libxmp_path="$withval") AC_PROG_CC +AC_C_BIGENDIAN(AC_DEFINE(ENDIAN_BIG)) if test "$libxmp_path" != ""; then CPPFLAGS="${CPPFLAGS} -I${libxmp_path}/include" diff --git a/src/Makefile b/src/Makefile index 2ba3b33..e7e9b64 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,6 +1,6 @@ SRC_OBJS = sound.o sound_null.o terminal.o info.o commands.o \ - options.o getopt.o getopt1.o main.o + options.o getopt.o getopt1.o main.o sound_wav.o SRC_DFILES = Makefile xmp.1 $(SRC_OBJS:.o=.c) common.h getopt.h \ sound_alsa.c sound_coreaudio.c sound_oss.c sound_sndio.c \ sound_bsd.c sound_solaris.c diff --git a/src/drivers/wav.c b/src/drivers/wav.c deleted file mode 100644 index 15430d1..0000000 --- a/src/drivers/wav.c +++ /dev/null @@ -1,183 +0,0 @@ -/* 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 -#include -#include -#include -#include -#include -#include -#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); -} diff --git a/src/main.c b/src/main.c index ea89ce5..0bfbd5f 100644 --- a/src/main.c +++ b/src/main.c @@ -191,14 +191,6 @@ int main(int argc, char **argv) shuffle(argc - optind + 1, &argv[optind - 1]); } - if (options.out_file) { - f = fopen(options.out_file, "wb"); - if (f == NULL) { - perror(options.out_file); - exit(EXIT_FAILURE); - } - } - #ifdef HAVE_SIGNAL_H signal(SIGTERM, cleanup); signal(SIGINT, cleanup); @@ -303,10 +295,6 @@ int main(int argc, char **argv) sound->play(mi.buffer, mi.buffer_size); - if (options.out_file) { - fwrite(mi.buffer, mi.buffer_size, 1, f); - } - if (!background) { read_command(handle, &control); @@ -351,9 +339,5 @@ int main(int argc, char **argv) sound->deinit(); - if (options.out_file) { - fclose(f); - } - exit(EXIT_SUCCESS); } diff --git a/src/sound.c b/src/sound.c index d4e8b20..9220a58 100644 --- a/src/sound.c +++ b/src/sound.c @@ -2,6 +2,7 @@ #include #include "sound.h" +extern struct sound_driver sound_wav; extern struct sound_driver sound_oss; extern struct sound_driver sound_alsa; extern struct sound_driver sound_win32; @@ -36,6 +37,7 @@ void init_sound_drivers() #ifdef SOUND_ALSA register_sound_driver(&sound_alsa); #endif + register_sound_driver(&sound_wav); } struct sound_driver *select_sound_driver(struct options *options) diff --git a/src/sound_wav.c b/src/sound_wav.c new file mode 100644 index 0000000..23cda1f --- /dev/null +++ b/src/sound_wav.c @@ -0,0 +1,184 @@ +#include +#include +#include +#include +#include +#include +#include +#include "sound.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +static int fd; +static int format_16bit; +static long size; + +struct sound_driver sound_wav; + +#ifdef ENDIAN_BIG +/* Convert little-endian 16 bit samples to big-endian */ +static void convert_endian(int l, unsigned char *p) +{ + unsigned char b; + int i; + + for (i = 0; i < l; i++) { + b = p[0]; + p[0] = p[1]; + p[1] = b; + p += 2; + } +} +#endif + +static void write_16l(int fd, unsigned short v) +{ + unsigned char x; + + x = v & 0xff; + write(fd, &x, 1); + + x = v >> 8; + write(fd, &x, 1); +} + +static void write_32l(int fd, unsigned int v) +{ + unsigned char x; + + x = v & 0xff; + write(fd, &x, 1); + + x = (v >> 8) & 0xff; + write(fd, &x, 1); + + x = (v >> 16) & 0xff; + write(fd, &x, 1); + + x = (v >> 24) & 0xff; + write(fd, &x, 1); +} + +static int init(struct options *options) +{ + char *buf; + unsigned int len = 0; + unsigned short chan; + unsigned int sampling_rate, bytes_per_second; + unsigned short bytes_per_frame, bits_per_sample; + + if (options->out_file == NULL) { + options->out_file = "out.wav"; + } + + if (strcmp(options->out_file, "-")) { + fd = open(options->out_file, O_WRONLY | O_CREAT | O_TRUNC + | O_BINARY, 0644); + if (fd < 0) + return -1; + } else { + fd = 1; + } + + if (strcmp(options->out_file, "-")) { + int len = strlen(sound_wav.description) + + strlen(options->out_file) + 8; + if ((buf = malloc(len)) == NULL) + return -1; + snprintf(buf, len, "%s: %s", sound_wav.description, + options->out_file); + sound_wav.description = buf; + } else { + sound_wav.description = strdup("WAV writer: stdout"); + len = -1; + } + + write(fd, "RIFF", 4); + write_32l(fd, len); + write(fd, "WAVE", 4); + + chan = options->format & XMP_FORMAT_MONO ? 1 : 2; + sampling_rate = options->rate; + + bits_per_sample = options->format & XMP_FORMAT_8BIT ? 8 : 16; + if (bits_per_sample == 8) { + options->format |= XMP_FORMAT_UNSIGNED; + format_16bit = 0; + } else { + options->format &= ~XMP_FORMAT_UNSIGNED; + format_16bit = 1; + } + + bytes_per_frame = chan * bits_per_sample / 8; + bytes_per_second = sampling_rate * bytes_per_frame; + + write(fd, "fmt ", 4); + write_32l(fd, 16); + write_16l(fd, 1); + write_16l(fd, chan); + write_32l(fd, sampling_rate); + write_32l(fd, bytes_per_second); + write_16l(fd, bytes_per_frame); + write_16l(fd, bits_per_sample); + + write(fd, "data", 4); + write_32l(fd, len); + + size = 0; + + return 0; +} + +static void play(void *b, int len) +{ +#ifdef ENDIAN_BIG + if (format_16bit) { + convert_endian(b, len); + } +#endif + write(fd, b, len); + size += len; +} + +static void deinit() +{ + lseek(fd, 40, SEEK_SET); + write_32l(fd, size); + + lseek(fd, 4, SEEK_SET); + write_32l(fd, size + 40); + + if (fd > 0) { + close(fd); + } + + free(sound_wav.description); +} + +static void flush() +{ +} + +static void onpause() +{ +} + +static void onresume() +{ +} + + +struct sound_driver sound_wav = { + "wav", + "WAV writer", + NULL, + init, + deinit, + play, + flush, + onpause, + onresume +}; +