From b88fd4ff9c6ae7af26c81b6fee069dc90ef2707d Mon Sep 17 00:00:00 2001 From: Taylor Holberton Date: Sat, 1 Oct 2016 12:33:46 -0400 Subject: put programs into utils dir --- utils/tinyplay.c | 303 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 utils/tinyplay.c (limited to 'utils/tinyplay.c') diff --git a/utils/tinyplay.c b/utils/tinyplay.c new file mode 100644 index 0000000..920b0e8 --- /dev/null +++ b/utils/tinyplay.c @@ -0,0 +1,303 @@ +/* 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 +#include +#include + +#define ID_RIFF 0x46464952 +#define ID_WAVE 0x45564157 +#define ID_FMT 0x20746d66 +#define ID_DATA 0x61746164 + +struct riff_wave_header { + uint32_t riff_id; + uint32_t riff_sz; + uint32_t wave_id; +}; + +struct chunk_header { + uint32_t id; + uint32_t sz; +}; + +struct chunk_fmt { + 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; +}; + +static int close = 0; + +void play_sample(FILE *file, unsigned int card, unsigned int device, unsigned int channels, + unsigned int rate, unsigned int bits, unsigned int period_size, + unsigned int period_count); + +void stream_close(int sig) +{ + /* allow the stream to be closed gracefully */ + signal(sig, SIG_IGN); + close = 1; +} + +int main(int argc, char **argv) +{ + FILE *file; + struct riff_wave_header riff_wave_header; + struct chunk_header chunk_header; + struct chunk_fmt chunk_fmt; + unsigned int device = 0; + unsigned int card = 0; + unsigned int period_size = 1024; + unsigned int period_count = 4; + unsigned int channels = 2; + unsigned int rate = 48000; + unsigned int bits = 16; + unsigned int is_raw = 0; /* Default wav file */ + char *filename; + int more_chunks = 1; + + if (argc < 2) { + fprintf(stderr, "Usage1: %s file.wav [-D card] [-d device] [-p period_size]" + " [-n n_periods] \n", argv[0]); + fprintf(stderr, "Usage2: %s file.raw [-D card] [-d device] [-p period_size] " + "[-n n_periods] [-c channels] [-r rate] [-b bits] -i raw \n", argv[0]); + return 1; + } + + filename = argv[1]; + file = fopen(filename, "rb"); + if (!file) { + fprintf(stderr, "Unable to open file '%s'\n", filename); + return 1; + } + + /* parse command line arguments */ + argv += 2; + while (*argv) { + if (strcmp(*argv, "-d") == 0) { + argv++; + if (*argv) + device = atoi(*argv); + } + if (strcmp(*argv, "-p") == 0) { + argv++; + if (*argv) + period_size = atoi(*argv); + } + if (strcmp(*argv, "-n") == 0) { + argv++; + if (*argv) + period_count = atoi(*argv); + } + if (strcmp(*argv, "-D") == 0) { + argv++; + if (*argv) + card = atoi(*argv); + } + if (strcmp(*argv, "-c") == 0) { + argv++; + if (*argv) + channels = atoi(*argv); + } + if (strcmp(*argv, "-r") == 0) { + argv++; + if (*argv) + rate = atoi(*argv); + } + if (strcmp(*argv, "-b") == 0) { + argv++; + if (*argv) + bits = atoi(*argv); + } + if (strcmp(*argv, "-i") == 0) { + argv++; + if (*argv) { + if (strcasecmp(*argv, "raw") == 0) { + is_raw = 1; + } + } + } + if (*argv) + argv++; + } + + if ( !is_raw ) { + fread(&riff_wave_header, sizeof(riff_wave_header), 1, file); + if ((riff_wave_header.riff_id != ID_RIFF) || + (riff_wave_header.wave_id != ID_WAVE)) { + fprintf(stderr, "Error: '%s' is not a riff/wave file\n", filename); + fclose(file); + return 1; + } + do { + fread(&chunk_header, sizeof(chunk_header), 1, file); + switch (chunk_header.id) { + case ID_FMT: + fread(&chunk_fmt, sizeof(chunk_fmt), 1, file); + /* If the format header is larger, skip the rest */ + if (chunk_header.sz > sizeof(chunk_fmt)) + fseek(file, chunk_header.sz - sizeof(chunk_fmt), SEEK_CUR); + break; + case ID_DATA: + /* Stop looking for chunks */ + more_chunks = 0; + break; + default: + /* Unknown chunk, skip bytes */ + fseek(file, chunk_header.sz, SEEK_CUR); + } + } while (more_chunks); + channels = chunk_fmt.num_channels; + rate = chunk_fmt.sample_rate; + bits = chunk_fmt.bits_per_sample; + } + + play_sample(file, card, device, channels, rate, bits, period_size, period_count); + + fclose(file); + + return 0; +} + +int check_param(struct pcm_params *params, unsigned int param, unsigned int value, + char *param_name, char *param_unit) +{ + unsigned int min; + unsigned int max; + int is_within_bounds = 1; + + min = pcm_params_get_min(params, param); + if (value < min) { + fprintf(stderr, "%s is %u%s, device only supports >= %u%s\n", param_name, value, + param_unit, min, param_unit); + is_within_bounds = 0; + } + + max = pcm_params_get_max(params, param); + if (value > max) { + fprintf(stderr, "%s is %u%s, device only supports <= %u%s\n", param_name, value, + param_unit, max, param_unit); + is_within_bounds = 0; + } + + return is_within_bounds; +} + +int sample_is_playable(unsigned int card, unsigned int device, unsigned int channels, + unsigned int rate, unsigned int bits, unsigned int period_size, + unsigned int period_count) +{ + struct pcm_params *params; + int can_play; + + params = pcm_params_get(card, device, PCM_OUT); + if (params == NULL) { + fprintf(stderr, "Unable to open PCM device %u.\n", device); + return 0; + } + + can_play = check_param(params, PCM_PARAM_RATE, rate, "Sample rate", "Hz"); + can_play &= check_param(params, PCM_PARAM_CHANNELS, channels, "Sample", " channels"); + can_play &= check_param(params, PCM_PARAM_SAMPLE_BITS, bits, "Bitrate", " bits"); + can_play &= check_param(params, PCM_PARAM_PERIOD_SIZE, period_size, "Period size", "Hz"); + can_play &= check_param(params, PCM_PARAM_PERIODS, period_count, "Period count", "Hz"); + + pcm_params_free(params); + + return can_play; +} + +void play_sample(FILE *file, unsigned int card, unsigned int device, unsigned int channels, + unsigned int rate, unsigned int bits, unsigned int period_size, + unsigned int period_count) +{ + struct pcm_config config; + struct pcm *pcm; + char *buffer; + int size; + int num_read; + + memset(&config, 0, sizeof(config)); + config.channels = channels; + config.rate = rate; + config.period_size = period_size; + config.period_count = period_count; + if (bits == 32) + config.format = PCM_FORMAT_S32_LE; + else if (bits == 16) + config.format = PCM_FORMAT_S16_LE; + config.start_threshold = 0; + config.stop_threshold = 0; + config.silence_threshold = 0; + + if (!sample_is_playable(card, device, channels, rate, bits, period_size, period_count)) { + return; + } + + pcm = pcm_open(card, device, PCM_OUT, &config); + if (!pcm || !pcm_is_ready(pcm)) { + fprintf(stderr, "Unable to open PCM device %u (%s)\n", + device, pcm_get_error(pcm)); + return; + } + + size = pcm_frames_to_bytes(pcm, 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); + + /* catch ctrl-c to shutdown cleanly */ + signal(SIGINT, stream_close); + + 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 (!close && num_read > 0); + + free(buffer); + pcm_close(pcm); +} + -- cgit v1.2.3