From 587b9600946b6a5ad60e7104594ca70d7cf63389 Mon Sep 17 00:00:00 2001 From: Claudio Matsuoka Date: Sat, 22 Nov 2014 22:09:50 -0200 Subject: [PATCH] Add AIFF file output driver Signed-off-by: Claudio Matsuoka --- CREDITS | 1 + Changelog | 1 + src/Makefile.am | 2 +- src/options.c | 3 + src/sound.c | 2 + src/sound_aiff.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 src/sound_aiff.c diff --git a/CREDITS b/CREDITS index 680bc89..f93beb1 100644 --- a/CREDITS +++ b/CREDITS @@ -41,6 +41,7 @@ The Authors - Lorence Lombardo * Amiga AHI driver + * AIFF file writer - Kevin Langman * OS/2 port and OS/2 DART drivers diff --git a/Changelog b/Changelog index 96cb675..f51a0d6 100644 --- a/Changelog +++ b/Changelog @@ -2,6 +2,7 @@ Stable versions --------------- 4.0.10 (): + - Add AIFF file output driver (by Lorence Lombardo) - Adjust CoreAudio driver latency 4.0.9 (20140926): diff --git a/src/Makefile.am b/src/Makefile.am index e7f4716..98f7c7a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,7 +9,7 @@ bin_PROGRAMS = xmp xmp_SOURCES = \ commands.c common.h getopt.h list.h getopt.c getopt1.c info.c main.c \ options.c read_config.c sound.c sound.h sound_file.c sound_null.c \ - sound_wav.c terminal.c + sound_wav.c sound_aiff.c terminal.c xmp_LDADD = ${libxmp_LIBS} xmp_LDFLAGS = ${XMP_DARWIN_LDFLAGS} diff --git a/src/options.c b/src/options.c index 9e3f01a..5bbf895 100644 --- a/src/options.c +++ b/src/options.c @@ -238,6 +238,9 @@ void get_options(int argc, char **argv, struct options *options) if (strlen(optarg) >= 4 && !strcasecmp(optarg + strlen(optarg) - 4, ".wav")) { options->driver_id = "wav"; + } else if (strlen(optarg) >= 5 && + !strcasecmp(optarg + strlen(optarg) - 5, ".aiff")) { + options->driver_id = "aiff"; } else { options->driver_id = "file"; } diff --git a/src/sound.c b/src/sound.c index 67a1eaa..1d711c8 100644 --- a/src/sound.c +++ b/src/sound.c @@ -12,6 +12,7 @@ extern struct sound_driver sound_null; extern struct sound_driver sound_wav; +extern struct sound_driver sound_aiff; extern struct sound_driver sound_file; extern struct sound_driver sound_qnx; extern struct sound_driver sound_alsa05; @@ -88,6 +89,7 @@ void init_sound_drivers(void) register_sound_driver(&sound_qnx); #endif register_sound_driver(&sound_wav); + register_sound_driver(&sound_aiff); register_sound_driver(&sound_file); register_sound_driver(&sound_null); } diff --git a/src/sound_aiff.c b/src/sound_aiff.c new file mode 100644 index 0000000..5c921ba --- /dev/null +++ b/src/sound_aiff.c @@ -0,0 +1,166 @@ +/* Amiga AIFF driver for Extended Module Player + * Copyright (C) 2014 Lorence Lombardo + * + * This file is part of the Extended Module Player and is distributed + * under the terms of the GNU General Public License. See the COPYING + * file for more information. + */ + +#include +#include +#include +#include +#include +#include +#include "sound.h" + +typedef struct { + /* Exponent, bit #15 is sign bit for mantissa */ + unsigned short exponent; + + /* 64 bit mantissa */ + unsigned long mantissa[2]; +} extended; + + +static int fd; +static int channels; +static int bits; +static int swap_endian; +static long size; + + +static void ulong2extended(unsigned long in, extended *ex) +{ + int exponent = 31 + 16383; + + while (!(in & 0x80000000)) { + exponent--; + in <<= 1; + } + + ex->exponent = exponent; + ex->mantissa[0] = in; + ex->mantissa[1] = 0; +} + +static inline void write8(int fd, unsigned char c) +{ + write(fd, &c, 1); +} + +static void write32b(int fd, unsigned long w) +{ + write8(fd, (w & 0xff000000) >> 24); + write8(fd, (w & 0x00ff0000) >> 16); + write8(fd, (w & 0x0000ff00) >> 8); + write8(fd, w & 0x000000ff); +} + +static int init(struct options *options) +{ + char hed[54] = { + 'F', 'O', 'R', 'M', 0, 0, 0, 0, + 'A', 'I', 'F', 'F', + + /* COMM chunk */ + 'C', 'O', 'M', 'M', 0, 0, 0, 18, + 0, 0, /* channels */ + 0, 0, 0, 0, /* frames */ + 0, 0, /* bits */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* rate (extended format) */ + + /* SSND chunk */ + 'S', 'S', 'N', 'D', 0, 0, 0, 0, + 0, 0, 0, 0, /* offset */ + 0, 0, 0, 0 /* block size */ + }; + extended ex; + + swap_endian = !is_big_endian(); + channels = options->format & XMP_FORMAT_MONO ? 1 : 2; + bits = options->format & XMP_FORMAT_8BIT ? 8 : 16; + size = 0; + + ulong2extended(options->rate, &ex); + hed[21] = channels; + hed[27] = bits; + hed[28] = (ex.exponent & 0xff00) >> 8; + hed[29] = ex.exponent & 0x00ff; + hed[30] = (ex.mantissa[0] & 0xff000000) >> 24; + hed[31] = (ex.mantissa[0] & 0x00ff0000) >> 16; + hed[32] = (ex.mantissa[0] & 0x0000ff00) >> 8; + hed[33] = ex.mantissa[0] & 0x000000ff; + + if (options->out_file == NULL) { + options->out_file = "out.aiff"; + } + + if (strcmp(options->out_file, "-")) { + fd = open(options->out_file, O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (fd < 0) + return -1; + } else { + fd = 1; + } + + write(fd, hed, 54); + + return 0; +} + +static void play(void *b, int len) +{ + if (swap_endian && bits == 16) { + convert_endian(b, len); + } + write(fd, b, len); + size += len; +} + +static void deinit(void) +{ + unsigned long tmp; + + if (size > 54) { + lseek(fd, 4, SEEK_SET); /* FORM chunk size */ + tmp = size - 8; + write32b(fd, tmp); + + lseek(fd, 22, SEEK_SET); /* COMM frames */ + tmp = (size - 54) / (bits / 8) / channels; + write32b(fd, tmp); + + lseek(fd, 42, SEEK_SET); /* SSND chunk size */ + tmp = size - 48; /* minus header + 8 */ + write32b(fd, tmp); + } + + if (fd > 0) { + close(fd); + } +} + +static void flush(void) +{ +} + +static void onpause(void) +{ +} + +static void onresume(void) +{ +} + +struct sound_driver sound_aiff = { + "aiff", + "AIFF writer", + NULL, + init, + deinit, + play, + flush, + onpause, + onresume +};