parent
638d109dde
commit
587b960094
6 changed files with 174 additions and 1 deletions
@ -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 <stdlib.h> |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#include <fcntl.h> |
||||
#include <unistd.h> |
||||
#include <string.h> |
||||
#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
|
||||
}; |
||||
Loading…
Reference in new issue