X-Git-Url: https://git.distorted.org.uk/~mdw/disorder/blobdiff_plain/39492555cd1d64e2f8a3474038f61d28c5c56de5..ce6c36be6c2df99afd01a7a602debb321322e113:/server/decode.c?ds=sidebyside diff --git a/server/decode.c b/server/decode.c index c63ca20..d1be348 100644 --- a/server/decode.c +++ b/server/decode.c @@ -33,10 +33,12 @@ #include #include #include +#include #include "log.h" #include "syscalls.h" #include "defs.h" +#include "wav.h" #include "speaker-protocol.h" /** @brief Encoding lookup table type */ @@ -57,7 +59,7 @@ static FILE *outputfp; static const char *path; /** @brief Input buffer */ -static unsigned char buffer[1048576]; +static char buffer[1048576]; /** @brief Open the input file */ static void open_input(void) { @@ -90,13 +92,14 @@ static inline void output_16(uint16_t n) { static void output_header(int rate, int channels, int bits, - int nbytes) { + int nbytes, + int endian) { struct stream_header header; header.rate = rate; header.bits = bits; header.channels = channels; - header.endian = ENDIAN_BIG; + header.endian = endian; header.nbytes = nbytes; if(fwrite(&header, sizeof header, 1, outputfp) < 1) fatal(errno, "decoding %s: writing format header", path); @@ -183,7 +186,8 @@ static enum mad_flow mp3_output(void attribute((unused)) *data, output_header(header->samplerate, pcm->channels, 16, - 2 * pcm->channels * pcm->length); + 2 * pcm->channels * pcm->length, + ENDIAN_BIG); switch(pcm->channels) { case 1: while(n--) @@ -205,10 +209,10 @@ static enum mad_flow mp3_output(void attribute((unused)) *data, static enum mad_flow mp3_input(void attribute((unused)) *data, struct mad_stream *stream) { const size_t n = fill(); - fprintf(stderr, "n=%zu\n", n); + if(!n) return MAD_FLOW_STOP; - mad_stream_buffer(stream, buffer, n); + mad_stream_buffer(stream, (unsigned char *)buffer, n); return MAD_FLOW_CONTINUE; } @@ -236,10 +240,67 @@ static void decode_mp3(void) { mad_decoder_finish(mad); } +/** @brief OGG decoder */ +static void decode_ogg(void) { + FILE *fp; + OggVorbis_File vf[1]; + int err; + long n; + int bitstream; + vorbis_info *vi; + + if(!(fp = fopen(path, "rb"))) + fatal(errno, "cannot open %s", path); + /* There doesn't seem to be any standard function for mapping the error codes + * to strings l-( */ + if((err = ov_open(fp, vf, 0/*initial*/, 0/*ibytes*/))) + fatal(0, "ov_fopen %s: %d", path, err); + if(!(vi = ov_info(vf, 0/*link*/))) + fatal(0, "ov_info %s: failed", path); + while((n = ov_read(vf, buffer, sizeof buffer, 1/*bigendianp*/, + 2/*bytes/word*/, 1/*signed*/, &bitstream))) { + if(n < 0) + fatal(0, "ov_read %s: %ld", path, n); + if(bitstream > 0) + fatal(0, "only single-bitstream ogg files are supported"); + output_header(vi->rate, vi->channels, 16/*bits*/, n, ENDIAN_BIG); + if(fwrite(buffer, 1, n, outputfp) < (size_t)n) + fatal(errno, "decoding %s: writing sample data", path); + } +} + +/** @brief Sample data callback used by decode_wav() */ +static int wav_write(struct wavfile attribute((unused)) *f, + const char *data, + size_t nbytes, + void attribute((unused)) *u) { + if(fwrite(data, 1, nbytes, outputfp) < nbytes) + fatal(errno, "decoding %s: writing sample data", path); + return 0; +} + +/** @brief WAV file decoder */ +static void decode_wav(void) { + struct wavfile f[1]; + int err; + + if((err = wav_init(f, path))) + fatal(err, "opening %s", path); + if(f->bits % 8) + fatal(err, "%s: unsupported byte size %d", path, f->bits); + output_header(f->rate, f->channels, f->bits, f->datasize, ENDIAN_LITTLE); + if((err = wav_data(f, wav_write, 0))) + fatal(err, "error decoding %s", path); +} + /** @brief Lookup table of decoders */ static const struct decoder decoders[] = { { "*.mp3", decode_mp3 }, { "*.MP3", decode_mp3 }, + { "*.ogg", decode_ogg }, + { "*.OGG", decode_ogg }, + { "*.wav", decode_wav }, + { "*.WAV", decode_wav }, { 0, 0 } };