You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

183 lines
3.7 KiB

/* 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);
}