1abc91186SMilanka Ringwald /* 2abc91186SMilanka Ringwald * Copyright (C) 2016 BlueKitchen GmbH 3abc91186SMilanka Ringwald * 4abc91186SMilanka Ringwald * Redistribution and use in source and binary forms, with or without 5abc91186SMilanka Ringwald * modification, are permitted provided that the following conditions 6abc91186SMilanka Ringwald * are met: 7abc91186SMilanka Ringwald * 8abc91186SMilanka Ringwald * 1. Redistributions of source code must retain the above copyright 9abc91186SMilanka Ringwald * notice, this list of conditions and the following disclaimer. 10abc91186SMilanka Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11abc91186SMilanka Ringwald * notice, this list of conditions and the following disclaimer in the 12abc91186SMilanka Ringwald * documentation and/or other materials provided with the distribution. 13abc91186SMilanka Ringwald * 3. Neither the name of the copyright holders nor the names of 14abc91186SMilanka Ringwald * contributors may be used to endorse or promote products derived 15abc91186SMilanka Ringwald * from this software without specific prior written permission. 16abc91186SMilanka Ringwald * 4. Any redistribution, use, or modification is done solely for 17abc91186SMilanka Ringwald * personal benefit and not for any commercial purpose or for 18abc91186SMilanka Ringwald * monetary gain. 19abc91186SMilanka Ringwald * 20abc91186SMilanka Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21abc91186SMilanka Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22abc91186SMilanka Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 242fca4dadSMilanka Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25abc91186SMilanka Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26abc91186SMilanka Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27abc91186SMilanka Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28abc91186SMilanka Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29abc91186SMilanka Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30abc91186SMilanka Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31abc91186SMilanka Ringwald * SUCH DAMAGE. 32abc91186SMilanka Ringwald * 33abc91186SMilanka Ringwald * Please inquire about commercial licensing options at 34abc91186SMilanka Ringwald * [email protected] 35abc91186SMilanka Ringwald * 36abc91186SMilanka Ringwald */ 37abc91186SMilanka Ringwald 38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "wav_util.c" 39ab2c6ae4SMatthias Ringwald 4086d6811aSMatthias Ringwald #include <fcntl.h> 41abc91186SMilanka Ringwald #include <stdio.h> 42abc91186SMilanka Ringwald #include <stdlib.h> 43abc91186SMilanka Ringwald #include <string.h> 44abc91186SMilanka Ringwald 45abc91186SMilanka Ringwald #include "wav_util.h" 46abc91186SMilanka Ringwald #include "btstack_util.h" 476f91db60SMilanka Ringwald #include "btstack_debug.h" 48abc91186SMilanka Ringwald 49e2bf7a9aSMatthias Ringwald /* wav reader state */ 5086d6811aSMatthias Ringwald static FILE * wav_reader_file; 51e2bf7a9aSMatthias Ringwald static int wav_reader_bytes_per_sample = 2; 52e2bf7a9aSMatthias Ringwald static struct { 53e2bf7a9aSMatthias Ringwald uint8_t num_channels; 54e2bf7a9aSMatthias Ringwald uint32_t sampling_rate; 55e2bf7a9aSMatthias Ringwald } wav_reader_state; 56abc91186SMilanka Ringwald 57e2bf7a9aSMatthias Ringwald /* wav writer state */ 58e2bf7a9aSMatthias Ringwald static struct { 59abc91186SMilanka Ringwald FILE * wav_file; 60abc91186SMilanka Ringwald int total_num_samples; 61abc91186SMilanka Ringwald int num_channels; 62abc91186SMilanka Ringwald int sampling_frequency; 63abc91186SMilanka Ringwald int frame_count; 64e2bf7a9aSMatthias Ringwald } wav_writer_state; 65abc91186SMilanka Ringwald 66abc91186SMilanka Ringwald 67abc91186SMilanka Ringwald static void little_endian_fstore_16(FILE *wav_file, uint16_t value){ 68abc91186SMilanka Ringwald uint8_t buf[2]; 69abc91186SMilanka Ringwald little_endian_store_16(buf, 0, value); 70abc91186SMilanka Ringwald fwrite(&buf, 1, 2, wav_file); 71abc91186SMilanka Ringwald } 72abc91186SMilanka Ringwald 73abc91186SMilanka Ringwald static void little_endian_fstore_32(FILE *wav_file, uint32_t value){ 74abc91186SMilanka Ringwald uint8_t buf[4]; 75abc91186SMilanka Ringwald little_endian_store_32(buf, 0, value); 76abc91186SMilanka Ringwald fwrite(&buf, 1, 4, wav_file); 77abc91186SMilanka Ringwald } 78abc91186SMilanka Ringwald 79abc91186SMilanka Ringwald static void write_wav_header(FILE * wav_file, int total_num_samples, int num_channels, int sample_rate){ 80fbc7c9f2SMilanka Ringwald unsigned int write_with_bytes_per_sample = 2; 81abc91186SMilanka Ringwald /* write RIFF header */ 82abc91186SMilanka Ringwald fwrite("RIFF", 1, 4, wav_file); 83abc91186SMilanka Ringwald // num_samples = blocks * subbands 84fbc7c9f2SMilanka Ringwald uint32_t data_bytes = (uint32_t) (write_with_bytes_per_sample * total_num_samples * num_channels); 85abc91186SMilanka Ringwald little_endian_fstore_32(wav_file, data_bytes + 36); 86abc91186SMilanka Ringwald fwrite("WAVE", 1, 4, wav_file); 87abc91186SMilanka Ringwald 88fbc7c9f2SMilanka Ringwald int byte_rate = sample_rate * num_channels * write_with_bytes_per_sample; 89fbc7c9f2SMilanka Ringwald int bits_per_sample = 8 * write_with_bytes_per_sample; 90abc91186SMilanka Ringwald int block_align = num_channels * bits_per_sample; 91abc91186SMilanka Ringwald int fmt_length = 16; 92abc91186SMilanka Ringwald int fmt_format_tag = 1; // PCM 93abc91186SMilanka Ringwald 94abc91186SMilanka Ringwald /* write fmt chunk */ 95abc91186SMilanka Ringwald fwrite("fmt ", 1, 4, wav_file); 96abc91186SMilanka Ringwald little_endian_fstore_32(wav_file, fmt_length); 97abc91186SMilanka Ringwald little_endian_fstore_16(wav_file, fmt_format_tag); 98abc91186SMilanka Ringwald little_endian_fstore_16(wav_file, num_channels); 99abc91186SMilanka Ringwald little_endian_fstore_32(wav_file, sample_rate); 100abc91186SMilanka Ringwald little_endian_fstore_32(wav_file, byte_rate); 101abc91186SMilanka Ringwald little_endian_fstore_16(wav_file, block_align); 102abc91186SMilanka Ringwald little_endian_fstore_16(wav_file, bits_per_sample); 103abc91186SMilanka Ringwald 104abc91186SMilanka Ringwald /* write data chunk */ 105abc91186SMilanka Ringwald fwrite("data", 1, 4, wav_file); 106abc91186SMilanka Ringwald little_endian_fstore_32(wav_file, data_bytes); 107abc91186SMilanka Ringwald } 108abc91186SMilanka Ringwald 109abc91186SMilanka Ringwald int wav_writer_open(const char * filepath, int num_channels, int sampling_frequency){ 110abc91186SMilanka Ringwald FILE * wav_file = fopen(filepath, "wb"); 111abc91186SMilanka Ringwald if (!wav_file) return 1; 112abc91186SMilanka Ringwald 113abc91186SMilanka Ringwald wav_writer_state.wav_file = wav_file; 114abc91186SMilanka Ringwald wav_writer_state.frame_count = 0; 115abc91186SMilanka Ringwald wav_writer_state.total_num_samples = 0; 116abc91186SMilanka Ringwald wav_writer_state.num_channels = num_channels; 117abc91186SMilanka Ringwald wav_writer_state.sampling_frequency = sampling_frequency; 118abc91186SMilanka Ringwald write_wav_header(wav_writer_state.wav_file, 0, num_channels, sampling_frequency); 119abc91186SMilanka Ringwald return 0; 120abc91186SMilanka Ringwald } 121abc91186SMilanka Ringwald 122abc91186SMilanka Ringwald int wav_writer_close(void){ 12390af00b8SMatthias Ringwald if (wav_writer_state.wav_file == NULL) return 0; 124abc91186SMilanka Ringwald rewind(wav_writer_state.wav_file); 125abc91186SMilanka Ringwald write_wav_header(wav_writer_state.wav_file, wav_writer_state.total_num_samples, 126abc91186SMilanka Ringwald wav_writer_state.num_channels, wav_writer_state.sampling_frequency); 127abc91186SMilanka Ringwald fclose(wav_writer_state.wav_file); 12890af00b8SMatthias Ringwald wav_writer_state.wav_file = NULL; 129abc91186SMilanka Ringwald return 0; 130abc91186SMilanka Ringwald } 131abc91186SMilanka Ringwald 132abc91186SMilanka Ringwald int wav_writer_write_int8(int num_samples, int8_t * data){ 133d3c765a3SMatthias Ringwald btstack_assert(data != NULL); 134d3c765a3SMatthias Ringwald if (wav_writer_state.wav_file == NULL) return 1; 135d3c765a3SMatthias Ringwald 136abc91186SMilanka Ringwald int i = 0; 137abc91186SMilanka Ringwald int8_t zero_byte = 0; 138abc91186SMilanka Ringwald for (i=0; i<num_samples; i++){ 139abc91186SMilanka Ringwald fwrite(&zero_byte, 1, 1, wav_writer_state.wav_file); 140abc91186SMilanka Ringwald uint8_t byte_value = (uint8_t)data[i]; 141abc91186SMilanka Ringwald fwrite(&byte_value, 1, 1, wav_writer_state.wav_file); 142abc91186SMilanka Ringwald } 143abc91186SMilanka Ringwald 144abc91186SMilanka Ringwald wav_writer_state.total_num_samples+=num_samples; 145abc91186SMilanka Ringwald wav_writer_state.frame_count++; 146abc91186SMilanka Ringwald return 0; 147abc91186SMilanka Ringwald } 148abc91186SMilanka Ringwald 14992abe7b9SMatthias Ringwald int wav_writer_write_le_int16(int num_samples, int16_t * data){ 150d3c765a3SMatthias Ringwald btstack_assert(data != NULL); 151d3c765a3SMatthias Ringwald if (wav_writer_state.wav_file == NULL) return 1; 152d3c765a3SMatthias Ringwald 153fbc7c9f2SMilanka Ringwald fwrite(data, num_samples, 2, wav_writer_state.wav_file); 154fbc7c9f2SMilanka Ringwald 155fbc7c9f2SMilanka Ringwald wav_writer_state.total_num_samples+=num_samples; 156fbc7c9f2SMilanka Ringwald wav_writer_state.frame_count++; 157fbc7c9f2SMilanka Ringwald return 0; 158fbc7c9f2SMilanka Ringwald } 159fbc7c9f2SMilanka Ringwald 16092abe7b9SMatthias Ringwald int wav_writer_write_int16(int num_samples, int16_t * data){ 161d3c765a3SMatthias Ringwald btstack_assert(data != NULL); 162d3c765a3SMatthias Ringwald if (wav_writer_state.wav_file == NULL) return 1; 163d3c765a3SMatthias Ringwald 16492abe7b9SMatthias Ringwald if (btstack_is_little_endian()){ 16592abe7b9SMatthias Ringwald return wav_writer_write_le_int16(num_samples, data); 16692abe7b9SMatthias Ringwald } 16792abe7b9SMatthias Ringwald 16892abe7b9SMatthias Ringwald int i; 16992abe7b9SMatthias Ringwald for (i=0;i<num_samples;i++){ 17092abe7b9SMatthias Ringwald uint16_t sample = btstack_flip_16(data[i]); 17192abe7b9SMatthias Ringwald fwrite(&sample, 1, 2, wav_writer_state.wav_file); 17292abe7b9SMatthias Ringwald } 17392abe7b9SMatthias Ringwald 17492abe7b9SMatthias Ringwald wav_writer_state.total_num_samples+=num_samples; 17592abe7b9SMatthias Ringwald wav_writer_state.frame_count++; 17692abe7b9SMatthias Ringwald return 0; 17792abe7b9SMatthias Ringwald } 17892abe7b9SMatthias Ringwald 179e2bf7a9aSMatthias Ringwald /** WAV Reader Implementation */ 180e2bf7a9aSMatthias Ringwald 181abc91186SMilanka Ringwald int wav_reader_open(const char * filepath){ 182e2bf7a9aSMatthias Ringwald memset (&wav_reader_state, 0, sizeof(wav_reader_state)); 18386d6811aSMatthias Ringwald wav_reader_file = fopen(filepath, "rb"); 18486d6811aSMatthias Ringwald if (wav_reader_file == NULL) { 1856f91db60SMilanka Ringwald log_error("Can't open file %s", filepath); 186abc91186SMilanka Ringwald return 1; 187abc91186SMilanka Ringwald } 188abc91186SMilanka Ringwald 189abc91186SMilanka Ringwald uint8_t buf[40]; 19086d6811aSMatthias Ringwald fread(buf, 1, sizeof(buf), wav_reader_file); 191abc91186SMilanka Ringwald 192*4016785cSMatthias Ringwald wav_reader_state.num_channels = (uint8_t) little_endian_read_16(buf, 22); 193e2bf7a9aSMatthias Ringwald if ((wav_reader_state.num_channels < 1) || (wav_reader_state.num_channels > 2)) { 194e2bf7a9aSMatthias Ringwald log_error("Unexpected num channels %d", wav_reader_state.num_channels); 1956f91db60SMilanka Ringwald return 1; 1966f91db60SMilanka Ringwald } 197e2bf7a9aSMatthias Ringwald 198e2bf7a9aSMatthias Ringwald wav_reader_state.sampling_rate = little_endian_read_32(buf, 24); 199e2bf7a9aSMatthias Ringwald 200e2bf7a9aSMatthias Ringwald int block_align = little_endian_read_16(buf, 32); 201e2bf7a9aSMatthias Ringwald wav_reader_bytes_per_sample = block_align / wav_reader_state.num_channels; 202e2bf7a9aSMatthias Ringwald if (wav_reader_bytes_per_sample > 2){ 203e2bf7a9aSMatthias Ringwald wav_reader_bytes_per_sample = wav_reader_bytes_per_sample / 8; 204abc91186SMilanka Ringwald } 205e2bf7a9aSMatthias Ringwald 206abc91186SMilanka Ringwald return 0; 207abc91186SMilanka Ringwald } 208abc91186SMilanka Ringwald 209e2bf7a9aSMatthias Ringwald uint8_t wav_reader_get_num_channels(void){ 210e2bf7a9aSMatthias Ringwald return wav_reader_state.num_channels; 211e2bf7a9aSMatthias Ringwald } 212e2bf7a9aSMatthias Ringwald 213e2bf7a9aSMatthias Ringwald uint32_t wav_reader_get_sampling_rate(void){ 214e2bf7a9aSMatthias Ringwald return wav_reader_state.sampling_rate; 215e2bf7a9aSMatthias Ringwald } 216e2bf7a9aSMatthias Ringwald 217abc91186SMilanka Ringwald int wav_reader_close(void){ 21886d6811aSMatthias Ringwald if (wav_reader_file != NULL){ 21986d6811aSMatthias Ringwald fclose(wav_reader_file); 22086d6811aSMatthias Ringwald } 221abc91186SMilanka Ringwald return 0; 222abc91186SMilanka Ringwald } 223abc91186SMilanka Ringwald 224abc91186SMilanka Ringwald // Wav data: 8bit is uint8_t; 16bit is int16 225abc91186SMilanka Ringwald int wav_reader_read_int8(int num_samples, int8_t * data){ 22686d6811aSMatthias Ringwald if (wav_reader_file == NULL) { 22786d6811aSMatthias Ringwald return 1; 22886d6811aSMatthias Ringwald } 229abc91186SMilanka Ringwald int i; 230abc91186SMilanka Ringwald int bytes_read = 0; 231abc91186SMilanka Ringwald 232abc91186SMilanka Ringwald for (i=0; i<num_samples; i++){ 233e2bf7a9aSMatthias Ringwald if (wav_reader_bytes_per_sample == 2){ 234abc91186SMilanka Ringwald uint8_t buf[2]; 235*4016785cSMatthias Ringwald bytes_read += (uint16_t) fread(buf, 1, sizeof(buf), wav_reader_file);; 236abc91186SMilanka Ringwald data[i] = buf[1]; 237abc91186SMilanka Ringwald } else { 238abc91186SMilanka Ringwald uint8_t buf[1]; 239*4016785cSMatthias Ringwald bytes_read += (uint16_t) fread(buf, 1, sizeof(buf), wav_reader_file);; 240abc91186SMilanka Ringwald data[i] = buf[0] + 128; 241abc91186SMilanka Ringwald } 242abc91186SMilanka Ringwald } 243e2bf7a9aSMatthias Ringwald if (bytes_read == num_samples * wav_reader_bytes_per_sample) { 244747ec646SMilanka Ringwald return 0; 245747ec646SMilanka Ringwald } else { 246747ec646SMilanka Ringwald return 1; 247747ec646SMilanka Ringwald } 248abc91186SMilanka Ringwald } 249abc91186SMilanka Ringwald 250fbc7c9f2SMilanka Ringwald int wav_reader_read_int16(int num_samples, int16_t * data){ 25186d6811aSMatthias Ringwald if (wav_reader_file == NULL) { 25286d6811aSMatthias Ringwald return 1; 25386d6811aSMatthias Ringwald } 254fbc7c9f2SMilanka Ringwald int i; 255fbc7c9f2SMilanka Ringwald int bytes_read = 0; 256fbc7c9f2SMilanka Ringwald for (i=0; i<num_samples; i++){ 257fbc7c9f2SMilanka Ringwald uint8_t buf[2]; 258*4016785cSMatthias Ringwald bytes_read += (uint16_t) fread(buf, 1, sizeof(buf), wav_reader_file);; 259fbc7c9f2SMilanka Ringwald data[i] = little_endian_read_16(buf, 0); 260fbc7c9f2SMilanka Ringwald } 261e2bf7a9aSMatthias Ringwald if (bytes_read == num_samples * wav_reader_bytes_per_sample) { 262747ec646SMilanka Ringwald return 0; 263747ec646SMilanka Ringwald } else { 264747ec646SMilanka Ringwald return 1; 265747ec646SMilanka Ringwald } 266fbc7c9f2SMilanka Ringwald } 267fbc7c9f2SMilanka Ringwald 268abc91186SMilanka Ringwald 269