1c72fcc34Sopenharmony_ci/* 2c72fcc34Sopenharmony_ci * Copyright (C) 2013-2015 Intel Corporation 3c72fcc34Sopenharmony_ci * 4c72fcc34Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 5c72fcc34Sopenharmony_ci * it under the terms of the GNU General Public License as published by 6c72fcc34Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 7c72fcc34Sopenharmony_ci * (at your option) any later version. 8c72fcc34Sopenharmony_ci * 9c72fcc34Sopenharmony_ci * This program is distributed in the hope that it will be useful, 10c72fcc34Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 11c72fcc34Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12c72fcc34Sopenharmony_ci * GNU General Public License for more details. 13c72fcc34Sopenharmony_ci * 14c72fcc34Sopenharmony_ci */ 15c72fcc34Sopenharmony_ci 16c72fcc34Sopenharmony_ci#include "aconfig.h" 17c72fcc34Sopenharmony_ci 18c72fcc34Sopenharmony_ci#include <stdio.h> 19c72fcc34Sopenharmony_ci#include <stddef.h> 20c72fcc34Sopenharmony_ci#include <stdlib.h> 21c72fcc34Sopenharmony_ci#include <stdbool.h> 22c72fcc34Sopenharmony_ci#include <errno.h> 23c72fcc34Sopenharmony_ci 24c72fcc34Sopenharmony_ci#include "gettext.h" 25c72fcc34Sopenharmony_ci 26c72fcc34Sopenharmony_ci#include "common.h" 27c72fcc34Sopenharmony_ci#include "alsa.h" 28c72fcc34Sopenharmony_ci#include "bat-signal.h" 29c72fcc34Sopenharmony_ci 30c72fcc34Sopenharmony_ciint retval_play; 31c72fcc34Sopenharmony_ciint retval_record; 32c72fcc34Sopenharmony_ci 33c72fcc34Sopenharmony_ci/* update chunk_fmt data to bat */ 34c72fcc34Sopenharmony_cistatic int update_fmt_to_bat(struct bat *bat, struct chunk_fmt *fmt) 35c72fcc34Sopenharmony_ci{ 36c72fcc34Sopenharmony_ci bat->channels = fmt->channels; 37c72fcc34Sopenharmony_ci bat->rate = fmt->sample_rate; 38c72fcc34Sopenharmony_ci bat->sample_size = fmt->sample_length / 8; 39c72fcc34Sopenharmony_ci if (bat->sample_size > 4) { 40c72fcc34Sopenharmony_ci fprintf(bat->err, _("Invalid format: sample size=%d\n"), 41c72fcc34Sopenharmony_ci bat->sample_size); 42c72fcc34Sopenharmony_ci return -EINVAL; 43c72fcc34Sopenharmony_ci } 44c72fcc34Sopenharmony_ci bat->frame_size = fmt->blocks_align; 45c72fcc34Sopenharmony_ci 46c72fcc34Sopenharmony_ci return 0; 47c72fcc34Sopenharmony_ci} 48c72fcc34Sopenharmony_ci 49c72fcc34Sopenharmony_ci/* calculate frames and update to bat */ 50c72fcc34Sopenharmony_cistatic int update_frames_to_bat(struct bat *bat, struct wav_chunk_header *header, 51c72fcc34Sopenharmony_ci FILE *file ATTRIBUTE_UNUSED) 52c72fcc34Sopenharmony_ci{ 53c72fcc34Sopenharmony_ci /* The number of analyzed captured frames is arbitrarily set to half of 54c72fcc34Sopenharmony_ci the number of frames of the wav file or the number of frames of the 55c72fcc34Sopenharmony_ci wav file when doing direct analysis (--local) */ 56c72fcc34Sopenharmony_ci bat->frames = header->length / bat->frame_size; 57c72fcc34Sopenharmony_ci if (!bat->local) 58c72fcc34Sopenharmony_ci bat->frames /= 2; 59c72fcc34Sopenharmony_ci 60c72fcc34Sopenharmony_ci return 0; 61c72fcc34Sopenharmony_ci} 62c72fcc34Sopenharmony_ci 63c72fcc34Sopenharmony_cistatic int read_chunk_fmt(struct bat *bat, char *file, FILE *fp, bool skip, 64c72fcc34Sopenharmony_ci struct wav_chunk_header *header) 65c72fcc34Sopenharmony_ci{ 66c72fcc34Sopenharmony_ci size_t err; 67c72fcc34Sopenharmony_ci int ret, header_skip; 68c72fcc34Sopenharmony_ci struct chunk_fmt chunk_fmt; 69c72fcc34Sopenharmony_ci 70c72fcc34Sopenharmony_ci err = fread(&chunk_fmt, sizeof(chunk_fmt), 1, fp); 71c72fcc34Sopenharmony_ci if (err != 1) { 72c72fcc34Sopenharmony_ci fprintf(bat->err, _("Read chunk fmt error: %s:%zd\n"), 73c72fcc34Sopenharmony_ci file, err); 74c72fcc34Sopenharmony_ci return -EIO; 75c72fcc34Sopenharmony_ci } 76c72fcc34Sopenharmony_ci /* If the format header is larger, skip the rest */ 77c72fcc34Sopenharmony_ci header_skip = header->length - sizeof(chunk_fmt); 78c72fcc34Sopenharmony_ci if (header_skip > 0) { 79c72fcc34Sopenharmony_ci ret = fseek(fp, header_skip, SEEK_CUR); 80c72fcc34Sopenharmony_ci if (ret == -1) { 81c72fcc34Sopenharmony_ci fprintf(bat->err, _("Seek fmt header error: %s:%d\n"), 82c72fcc34Sopenharmony_ci file, ret); 83c72fcc34Sopenharmony_ci return -EINVAL; 84c72fcc34Sopenharmony_ci } 85c72fcc34Sopenharmony_ci } 86c72fcc34Sopenharmony_ci /* If the file is opened for playback, update BAT data; 87c72fcc34Sopenharmony_ci If the file is opened for analysis, no update */ 88c72fcc34Sopenharmony_ci if (skip == false) { 89c72fcc34Sopenharmony_ci err = update_fmt_to_bat(bat, &chunk_fmt); 90c72fcc34Sopenharmony_ci if (err != 0) 91c72fcc34Sopenharmony_ci return err; 92c72fcc34Sopenharmony_ci } 93c72fcc34Sopenharmony_ci 94c72fcc34Sopenharmony_ci return 0; 95c72fcc34Sopenharmony_ci} 96c72fcc34Sopenharmony_ci 97c72fcc34Sopenharmony_ciint read_wav_header(struct bat *bat, char *file, FILE *fp, bool skip) 98c72fcc34Sopenharmony_ci{ 99c72fcc34Sopenharmony_ci struct wav_header riff_wave_header; 100c72fcc34Sopenharmony_ci struct wav_chunk_header chunk_header; 101c72fcc34Sopenharmony_ci int more_chunks = 1; 102c72fcc34Sopenharmony_ci size_t err; 103c72fcc34Sopenharmony_ci int ret; 104c72fcc34Sopenharmony_ci 105c72fcc34Sopenharmony_ci /* Read header of RIFF wav file */ 106c72fcc34Sopenharmony_ci err = fread(&riff_wave_header, sizeof(riff_wave_header), 1, fp); 107c72fcc34Sopenharmony_ci if (err != 1) { 108c72fcc34Sopenharmony_ci fprintf(bat->err, _("Read header error: %s:%zd\n"), file, err); 109c72fcc34Sopenharmony_ci return -EIO; 110c72fcc34Sopenharmony_ci } 111c72fcc34Sopenharmony_ci if ((riff_wave_header.magic != WAV_RIFF) 112c72fcc34Sopenharmony_ci || (riff_wave_header.type != WAV_WAVE)) { 113c72fcc34Sopenharmony_ci fprintf(bat->err, _("%s is not a riff/wave file\n"), file); 114c72fcc34Sopenharmony_ci return -EINVAL; 115c72fcc34Sopenharmony_ci } 116c72fcc34Sopenharmony_ci 117c72fcc34Sopenharmony_ci /* Read chunks in RIFF wav file */ 118c72fcc34Sopenharmony_ci do { 119c72fcc34Sopenharmony_ci err = fread(&chunk_header, sizeof(chunk_header), 1, fp); 120c72fcc34Sopenharmony_ci if (err != 1) { 121c72fcc34Sopenharmony_ci fprintf(bat->err, _("Read chunk header error: ")); 122c72fcc34Sopenharmony_ci fprintf(bat->err, _("%s:%zd\n"), file, err); 123c72fcc34Sopenharmony_ci return -EIO; 124c72fcc34Sopenharmony_ci } 125c72fcc34Sopenharmony_ci 126c72fcc34Sopenharmony_ci switch (chunk_header.type) { 127c72fcc34Sopenharmony_ci case WAV_FMT: 128c72fcc34Sopenharmony_ci /* WAV_FMT chunk, read and analyze */ 129c72fcc34Sopenharmony_ci err = read_chunk_fmt(bat, file, fp, skip, 130c72fcc34Sopenharmony_ci &chunk_header); 131c72fcc34Sopenharmony_ci if (err != 0) 132c72fcc34Sopenharmony_ci return err; 133c72fcc34Sopenharmony_ci break; 134c72fcc34Sopenharmony_ci case WAV_DATA: 135c72fcc34Sopenharmony_ci /* WAV_DATA chunk, break looping */ 136c72fcc34Sopenharmony_ci /* If the file is opened for playback, update BAT data; 137c72fcc34Sopenharmony_ci If the file is opened for analysis, no update */ 138c72fcc34Sopenharmony_ci if (skip == false) { 139c72fcc34Sopenharmony_ci err = update_frames_to_bat(bat, &chunk_header, 140c72fcc34Sopenharmony_ci fp); 141c72fcc34Sopenharmony_ci if (err != 0) 142c72fcc34Sopenharmony_ci return err; 143c72fcc34Sopenharmony_ci } 144c72fcc34Sopenharmony_ci /* Stop looking for chunks */ 145c72fcc34Sopenharmony_ci more_chunks = 0; 146c72fcc34Sopenharmony_ci break; 147c72fcc34Sopenharmony_ci default: 148c72fcc34Sopenharmony_ci /* Unknown chunk, skip bytes */ 149c72fcc34Sopenharmony_ci ret = fseek(fp, chunk_header.length, SEEK_CUR); 150c72fcc34Sopenharmony_ci if (ret == -1) { 151c72fcc34Sopenharmony_ci fprintf(bat->err, _("Fail to skip unknown")); 152c72fcc34Sopenharmony_ci fprintf(bat->err, _(" chunk of %s:%d\n"), 153c72fcc34Sopenharmony_ci file, ret); 154c72fcc34Sopenharmony_ci return -EINVAL; 155c72fcc34Sopenharmony_ci } 156c72fcc34Sopenharmony_ci } 157c72fcc34Sopenharmony_ci } while (more_chunks); 158c72fcc34Sopenharmony_ci 159c72fcc34Sopenharmony_ci return 0; 160c72fcc34Sopenharmony_ci} 161c72fcc34Sopenharmony_ci 162c72fcc34Sopenharmony_civoid prepare_wav_info(struct wav_container *wav, struct bat *bat) 163c72fcc34Sopenharmony_ci{ 164c72fcc34Sopenharmony_ci wav->header.magic = WAV_RIFF; 165c72fcc34Sopenharmony_ci wav->header.type = WAV_WAVE; 166c72fcc34Sopenharmony_ci wav->format.magic = WAV_FMT; 167c72fcc34Sopenharmony_ci wav->format.fmt_size = 16; 168c72fcc34Sopenharmony_ci wav->format.format = WAV_FORMAT_PCM; 169c72fcc34Sopenharmony_ci wav->format.channels = bat->channels; 170c72fcc34Sopenharmony_ci wav->format.sample_rate = bat->rate; 171c72fcc34Sopenharmony_ci wav->format.sample_length = bat->sample_size * 8; 172c72fcc34Sopenharmony_ci wav->format.blocks_align = bat->channels * bat->sample_size; 173c72fcc34Sopenharmony_ci wav->format.bytes_p_second = wav->format.blocks_align * bat->rate; 174c72fcc34Sopenharmony_ci wav->chunk.length = bat->frames * bat->frame_size; 175c72fcc34Sopenharmony_ci wav->chunk.type = WAV_DATA; 176c72fcc34Sopenharmony_ci wav->header.length = (wav->chunk.length) + sizeof(wav->chunk) 177c72fcc34Sopenharmony_ci + sizeof(wav->format) + sizeof(wav->header) - 8; 178c72fcc34Sopenharmony_ci} 179c72fcc34Sopenharmony_ci 180c72fcc34Sopenharmony_ciint write_wav_header(FILE *fp, struct wav_container *wav, struct bat *bat) 181c72fcc34Sopenharmony_ci{ 182c72fcc34Sopenharmony_ci int err = 0; 183c72fcc34Sopenharmony_ci 184c72fcc34Sopenharmony_ci err = fwrite(&wav->header, 1, sizeof(wav->header), fp); 185c72fcc34Sopenharmony_ci if (err != sizeof(wav->header)) { 186c72fcc34Sopenharmony_ci fprintf(bat->err, _("Write file error: header %d\n"), err); 187c72fcc34Sopenharmony_ci return -EIO; 188c72fcc34Sopenharmony_ci } 189c72fcc34Sopenharmony_ci err = fwrite(&wav->format, 1, sizeof(wav->format), fp); 190c72fcc34Sopenharmony_ci if (err != sizeof(wav->format)) { 191c72fcc34Sopenharmony_ci fprintf(bat->err, _("Write file error: format %d\n"), err); 192c72fcc34Sopenharmony_ci return -EIO; 193c72fcc34Sopenharmony_ci } 194c72fcc34Sopenharmony_ci err = fwrite(&wav->chunk, 1, sizeof(wav->chunk), fp); 195c72fcc34Sopenharmony_ci if (err != sizeof(wav->chunk)) { 196c72fcc34Sopenharmony_ci fprintf(bat->err, _("Write file error: chunk %d\n"), err); 197c72fcc34Sopenharmony_ci return -EIO; 198c72fcc34Sopenharmony_ci } 199c72fcc34Sopenharmony_ci 200c72fcc34Sopenharmony_ci return 0; 201c72fcc34Sopenharmony_ci} 202c72fcc34Sopenharmony_ci 203c72fcc34Sopenharmony_ci/* update wav header when data size changed */ 204c72fcc34Sopenharmony_ciint update_wav_header(struct bat *bat, FILE *fp, int bytes) 205c72fcc34Sopenharmony_ci{ 206c72fcc34Sopenharmony_ci int err = 0; 207c72fcc34Sopenharmony_ci struct wav_container wav; 208c72fcc34Sopenharmony_ci 209c72fcc34Sopenharmony_ci prepare_wav_info(&wav, bat); 210c72fcc34Sopenharmony_ci wav.chunk.length = bytes; 211c72fcc34Sopenharmony_ci wav.header.length = (wav.chunk.length) + sizeof(wav.chunk) 212c72fcc34Sopenharmony_ci + sizeof(wav.format) + sizeof(wav.header) - 8; 213c72fcc34Sopenharmony_ci rewind(fp); 214c72fcc34Sopenharmony_ci err = write_wav_header(fp, &wav, bat); 215c72fcc34Sopenharmony_ci 216c72fcc34Sopenharmony_ci return err; 217c72fcc34Sopenharmony_ci} 218c72fcc34Sopenharmony_ci 219c72fcc34Sopenharmony_ci/* 220c72fcc34Sopenharmony_ci * Generate buffer to be played either from input file or from generated data 221c72fcc34Sopenharmony_ci * Return value 222c72fcc34Sopenharmony_ci * <0 error 223c72fcc34Sopenharmony_ci * 0 ok 224c72fcc34Sopenharmony_ci * >0 break 225c72fcc34Sopenharmony_ci */ 226c72fcc34Sopenharmony_ciint generate_input_data(struct bat *bat, void *buffer, int bytes, int frames) 227c72fcc34Sopenharmony_ci{ 228c72fcc34Sopenharmony_ci int err; 229c72fcc34Sopenharmony_ci static int load; 230c72fcc34Sopenharmony_ci 231c72fcc34Sopenharmony_ci if (bat->playback.file != NULL) { 232c72fcc34Sopenharmony_ci /* From input file */ 233c72fcc34Sopenharmony_ci load = 0; 234c72fcc34Sopenharmony_ci 235c72fcc34Sopenharmony_ci while (1) { 236c72fcc34Sopenharmony_ci err = fread((char *)buffer + load, 1, bytes - load, bat->fp); 237c72fcc34Sopenharmony_ci if (0 == err) { 238c72fcc34Sopenharmony_ci if (feof(bat->fp)) { 239c72fcc34Sopenharmony_ci fprintf(bat->log, 240c72fcc34Sopenharmony_ci _("End of playing.\n")); 241c72fcc34Sopenharmony_ci return 1; 242c72fcc34Sopenharmony_ci } 243c72fcc34Sopenharmony_ci } else if (err < bytes - load) { 244c72fcc34Sopenharmony_ci if (ferror(bat->fp)) { 245c72fcc34Sopenharmony_ci fprintf(bat->err, _("Read file error")); 246c72fcc34Sopenharmony_ci fprintf(bat->err, _(": %d\n"), err); 247c72fcc34Sopenharmony_ci return -EIO; 248c72fcc34Sopenharmony_ci } 249c72fcc34Sopenharmony_ci load += err; 250c72fcc34Sopenharmony_ci } else { 251c72fcc34Sopenharmony_ci break; 252c72fcc34Sopenharmony_ci } 253c72fcc34Sopenharmony_ci } 254c72fcc34Sopenharmony_ci } else { 255c72fcc34Sopenharmony_ci /* Generate sine wave */ 256c72fcc34Sopenharmony_ci if ((bat->sinus_duration) && (load > bat->sinus_duration)) 257c72fcc34Sopenharmony_ci return 1; 258c72fcc34Sopenharmony_ci 259c72fcc34Sopenharmony_ci err = generate_sine_wave(bat, frames, buffer); 260c72fcc34Sopenharmony_ci if (err != 0) 261c72fcc34Sopenharmony_ci return err; 262c72fcc34Sopenharmony_ci 263c72fcc34Sopenharmony_ci load += frames; 264c72fcc34Sopenharmony_ci } 265c72fcc34Sopenharmony_ci 266c72fcc34Sopenharmony_ci return 0; 267c72fcc34Sopenharmony_ci} 268