From a0ef465b3140a827b149146cd51c9489859db33d Mon Sep 17 00:00:00 2001 From: Simon Wilson Date: Thu, 2 Jun 2011 23:40:00 -0700 Subject: Add tinyplay utility to play PCM riff/wave files --- Makefile | 5 ++- tinyplay.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 tinyplay.c diff --git a/Makefile b/Makefile index 589ff4c..aa1310b 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,9 @@ INC = include OBJECTS = mixer.o pcm.o LIB = libtinyalsa.so +tinyplay: $(LIB) tinyplay.o + gcc tinyplay.o -L. -ltinyalsa -o tinyplay + libtinyalsa.so: $(OBJECTS) gcc -shared $(OBJECTS) -o $(LIB) @@ -10,4 +13,4 @@ libtinyalsa.so: $(OBJECTS) gcc $(CFLAGS) $< -I$(INC) clean: - rm $(LIB) $(OBJECTS) + rm $(LIB) $(OBJECTS) tinyplay.o tinyplay diff --git a/tinyplay.c b/tinyplay.c new file mode 100644 index 0000000..63ced5b --- /dev/null +++ b/tinyplay.c @@ -0,0 +1,146 @@ +/* tinyplay.c +** +** Copyright 2011, The Android Open Source Project +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** * Neither the name of The Android Open Source Project nor the names of +** its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +** DAMAGE. +*/ + +#include +#include +#include +#include + +#define ID_RIFF 0x46464952 +#define ID_WAVE 0x45564157 +#define ID_FMT 0x20746d66 +#define ID_DATA 0x61746164 + +#define FORMAT_PCM 1 + +struct wav_header { + uint32_t riff_id; + uint32_t riff_sz; + uint32_t riff_fmt; + uint32_t fmt_id; + uint32_t fmt_sz; + uint16_t audio_format; + uint16_t num_channels; + uint32_t sample_rate; + uint32_t byte_rate; + uint16_t block_align; + uint16_t bits_per_sample; + uint32_t data_id; + uint32_t data_sz; +}; + +void play_sample(FILE *file, unsigned int channels, unsigned int rate, + unsigned int bits); + +int main(int argc, char **argv) +{ + FILE *file; + struct wav_header header; + + file = fopen(argv[1], "rb"); + if (!file) { + fprintf(stderr, "Unable to open file '%s'\n", argv[1]); + return 1; + } + + fread(&header, sizeof(struct wav_header), 1, file); + + if ((header.riff_id != ID_RIFF) || + (header.riff_fmt != ID_WAVE) || + (header.fmt_id != ID_FMT) || + (header.audio_format != FORMAT_PCM) || + (header.fmt_sz != 16)) { + fprintf(stderr, "Error: '%s' is not a PCM riff/wave file\n", argv[1]); + fclose(file); + return 1; + } + + play_sample(file, header.num_channels, header.sample_rate, + header.bits_per_sample); + + fclose(file); + + return 0; +} + +void play_sample(FILE *file, unsigned int channels, unsigned int rate, + unsigned int bits) +{ + struct pcm_config config; + struct pcm *pcm; + char *buffer; + int size; + int num_read; + + config.channels = channels; + config.rate = rate; + config.period_size = 1024; + config.period_count = 4; + if (bits == 32) + config.format = PCM_FORMAT_S32_LE; + else if (bits == 16) + config.format = PCM_FORMAT_S16_LE; + + pcm = pcm_open(0, 0, PCM_OUT, &config); + if (!pcm || !pcm_is_ready(pcm)) { + fprintf(stderr, "%s\n", pcm_get_error(pcm)); + return; + } + + size = pcm_get_buffer_size(pcm); + buffer = malloc(size); + if (!buffer) { + fprintf(stderr, "Unable to allocate %d bytes\n", size); + free(buffer); + pcm_close(pcm); + return; + } + + printf("Playing sample: %u ch, %u hz, %u bit\n", channels, rate, bits); + + while (fread(buffer, 1, size, file) == size) { + if (pcm_write(pcm, buffer, size)) { + fprintf(stderr, "Error playing sample\n"); + break; + } + } + + do { + num_read = fread(buffer, 1, size, file); + if (num_read > 0) { + if (pcm_write(pcm, buffer, num_read)) { + fprintf(stderr, "Error playing sample\n"); + break; + } + } + } while (num_read > 0); + + free(buffer); + pcm_close(pcm); +} + -- cgit v1.2.3