From 2ab3d99967d68c79351fe2a3df22c445447e3010 Mon Sep 17 00:00:00 2001 From: Michał Cichoń Date: Tue, 15 Nov 2011 22:28:48 +0100 Subject: Initial import. --- libao/src/src/ao_au.c | 250 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 libao/src/src/ao_au.c (limited to 'libao/src/src/ao_au.c') diff --git a/libao/src/src/ao_au.c b/libao/src/src/ao_au.c new file mode 100644 index 0000000..f6aad2d --- /dev/null +++ b/libao/src/src/ao_au.c @@ -0,0 +1,250 @@ +/* + * + * ao_au.c + * + * Copyright (C) Wil Mahan - May 2001 + * + * This file is part of libao, a cross-platform audio output library. See + * README for a history of this source code. + * + * libao is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * libao is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + ******************************************************************** + + last mod: $Id: ao_au.c 17718 2010-12-06 20:09:29Z xiphmont $ + + ********************************************************************/ + +#include +#include +#include +#include +#include +#include +#ifndef _MSC_VER +# include +#endif +#include +#include + +#define AUDIO_FILE_MAGIC ((uint_32)0x2e736e64) /* ".snd" */ + +#define AUDIO_UNKNOWN_SIZE (~0) /* (unsigned) -1 */ + +/* Format codes (not comprehensive) */ +#define AUDIO_FILE_ENCODING_LINEAR_8 (2) /* 8-bit linear PCM */ +#define AUDIO_FILE_ENCODING_LINEAR_16 (3) /* 16-bit linear PCM */ + +#define AU_HEADER_LEN (28) + +#define DEFAULT_SWAP_BUFFER_SIZE 2048 + +/* Write a uint_32 in big-endian order. */ +#define WRITE_U32(buf, x) \ + *(buf) = (unsigned char)(((x)>>24)&0xff);\ + *((buf)+1) = (unsigned char)(((x)>>16)&0xff);\ + *((buf)+2) = (unsigned char)(((x)>>8)&0xff);\ + *((buf)+3) = (unsigned char)((x)&0xff); + +typedef struct Audio_filehdr { + uint_32 magic; /* magic number */ + uint_32 hdr_size; /* offset of the data */ + uint_32 data_size; /* length of data (optional) */ + uint_32 encoding; /* data format code */ + uint_32 sample_rate; /* samples per second */ + uint_32 channels; /* number of interleaved channels */ + char info[4]; /* optional text information */ +} Audio_filehdr; + +static char *ao_au_options[] = {"matrix","verbose","quiet","debug"}; +static ao_info ao_au_info = +{ + AO_TYPE_FILE, + "AU file output", + "au", + "Wil Mahan ", + "Sends output to a .au file", + AO_FMT_BIG, + 0, + ao_au_options, + sizeof(ao_au_options)/sizeof(*ao_au_options) +}; + +typedef struct ao_au_internal +{ + Audio_filehdr au; +} ao_au_internal; + + +static int ao_au_test(void) +{ + return 1; /* File driver always works */ +} + + +static ao_info *ao_au_driver_info(void) +{ + return &ao_au_info; +} + + +static int ao_au_device_init(ao_device *device) +{ + ao_au_internal *internal; + + internal = (ao_au_internal *) malloc(sizeof(ao_au_internal)); + + if (internal == NULL) + return 0; /* Could not initialize device memory */ + + memset(&(internal->au), 0, sizeof(internal->au)); + + device->internal = internal; + device->output_matrix_order = AO_OUTPUT_MATRIX_FIXED; + + return 1; /* Memory alloc successful */ +} + + +static int ao_au_set_option(ao_device *device, const char *key, + const char *value) +{ + return 1; /* No options! */ +} + + +static int ao_au_open(ao_device *device, ao_sample_format *format) +{ + ao_au_internal *internal = (ao_au_internal *) device->internal; + unsigned char buf[AU_HEADER_LEN]; + + /* The AU format is big-endian */ + device->driver_byte_format = AO_FMT_BIG; + + /* Fill out the header */ + internal->au.magic = AUDIO_FILE_MAGIC; + internal->au.channels = device->output_channels; + if (format->bits == 8) + internal->au.encoding = AUDIO_FILE_ENCODING_LINEAR_8; + else if (format->bits == 16) + internal->au.encoding = AUDIO_FILE_ENCODING_LINEAR_16; + else { + /* Only 8 and 16 bits are supported at present. */ + return 0; + } + internal->au.sample_rate = format->rate; + internal->au.hdr_size = AU_HEADER_LEN; + + /* From the AU specification: "When audio files are passed + * through pipes, the 'data_size' field may not be known in + * advance. In such cases, the 'data_size' should be set + * to AUDIO_UNKNOWN_SIZE." + */ + internal->au.data_size = AUDIO_UNKNOWN_SIZE; + /* strncpy(state->au.info, "OGG ", 4); */ + + /* Write the header in big-endian order */ + WRITE_U32(buf, internal->au.magic); + WRITE_U32(buf + 4, internal->au.hdr_size); + WRITE_U32(buf + 8, internal->au.data_size); + WRITE_U32(buf + 12, internal->au.encoding); + WRITE_U32(buf + 16, internal->au.sample_rate); + WRITE_U32(buf + 20, internal->au.channels); + strncpy (buf + 24, internal->au.info, 4); + + if (fwrite(buf, sizeof(char), AU_HEADER_LEN, device->file) + != AU_HEADER_LEN) { + return 0; /* Error writing header */ + } + + if(!device->inter_matrix){ + /* set up matrix such that users are warned about > stereo playback */ + if(device->output_channels<=2) + device->inter_matrix=strdup("L,R"); + //else no matrix, which results in a warning + } + + + return 1; +} + + +/* + * play the sample to the already opened file descriptor + */ +static int ao_au_play(ao_device *device, const char *output_samples, + uint_32 num_bytes) +{ + if (fwrite(output_samples, sizeof(char), num_bytes, + device->file) < num_bytes) + return 0; + else + return 1; +} + +static int ao_au_close(ao_device *device) +{ + ao_au_internal *internal = (ao_au_internal *) device->internal; + + off_t size; + unsigned char buf[4]; + + /* Try to find the total file length, including header */ + size = ftell(device->file); + + /* It's not a problem if the lseek() fails; the AU + * format does not require a file length. This is + * useful for writing to non-seekable files (e.g. + * pipes). + */ + if (size > 0) { + internal->au.data_size = size - AU_HEADER_LEN; + + /* Rewind the file */ + if (fseek(device->file, 8 /* offset of data_size */, + SEEK_SET) < 0) + { + return 1; /* Seek failed; that's okay */ + } + + /* Fill in the file length */ + WRITE_U32 (buf, internal->au.data_size); + if (fwrite(buf, sizeof(char), 4, device->file) < 4) { + return 1; /* Header write failed; that's okay */ + } + } + + return 1; +} + + +static void ao_au_device_clear(ao_device *device) +{ + ao_au_internal *internal = (ao_au_internal *) device->internal; + + free(internal); + device->internal=NULL; +} + +ao_functions ao_au = { + ao_au_test, + ao_au_driver_info, + ao_au_device_init, + ao_au_set_option, + ao_au_open, + ao_au_play, + ao_au_close, + ao_au_device_clear +}; -- cgit v1.2.3