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 49*f89e874bSMatthias Ringwald #ifdef _MSC_VER 50*f89e874bSMatthias Ringwald // ignore deprecated warning for fopen 51*f89e874bSMatthias Ringwald #pragma warning(disable : 4996) 52*f89e874bSMatthias Ringwald #endif 53*f89e874bSMatthias Ringwald 54e2bf7a9aSMatthias Ringwald /* wav reader state */ 5586d6811aSMatthias Ringwald static FILE * wav_reader_file; 56e2bf7a9aSMatthias Ringwald static int wav_reader_bytes_per_sample = 2; 57e2bf7a9aSMatthias Ringwald static struct { 58e2bf7a9aSMatthias Ringwald uint8_t num_channels; 59e2bf7a9aSMatthias Ringwald uint32_t sampling_rate; 60e2bf7a9aSMatthias Ringwald } wav_reader_state; 61abc91186SMilanka Ringwald 62e2bf7a9aSMatthias Ringwald /* wav writer state */ 63e2bf7a9aSMatthias Ringwald static struct { 64abc91186SMilanka Ringwald FILE * wav_file; 65abc91186SMilanka Ringwald int total_num_samples; 66abc91186SMilanka Ringwald int num_channels; 67abc91186SMilanka Ringwald int sampling_frequency; 68abc91186SMilanka Ringwald int frame_count; 69e2bf7a9aSMatthias Ringwald } wav_writer_state; 70abc91186SMilanka Ringwald 71abc91186SMilanka Ringwald 72abc91186SMilanka Ringwald static void little_endian_fstore_16(FILE *wav_file, uint16_t value){ 73abc91186SMilanka Ringwald uint8_t buf[2]; 74abc91186SMilanka Ringwald little_endian_store_16(buf, 0, value); 75abc91186SMilanka Ringwald fwrite(&buf, 1, 2, wav_file); 76abc91186SMilanka Ringwald } 77abc91186SMilanka Ringwald 78abc91186SMilanka Ringwald static void little_endian_fstore_32(FILE *wav_file, uint32_t value){ 79abc91186SMilanka Ringwald uint8_t buf[4]; 80abc91186SMilanka Ringwald little_endian_store_32(buf, 0, value); 81abc91186SMilanka Ringwald fwrite(&buf, 1, 4, wav_file); 82abc91186SMilanka Ringwald } 83abc91186SMilanka Ringwald 84abc91186SMilanka Ringwald static void write_wav_header(FILE * wav_file, int total_num_samples, int num_channels, int sample_rate){ 85fbc7c9f2SMilanka Ringwald unsigned int write_with_bytes_per_sample = 2; 86abc91186SMilanka Ringwald /* write RIFF header */ 87abc91186SMilanka Ringwald fwrite("RIFF", 1, 4, wav_file); 88abc91186SMilanka Ringwald // num_samples = blocks * subbands 89fbc7c9f2SMilanka Ringwald uint32_t data_bytes = (uint32_t) (write_with_bytes_per_sample * total_num_samples * num_channels); 90abc91186SMilanka Ringwald little_endian_fstore_32(wav_file, data_bytes + 36); 91abc91186SMilanka Ringwald fwrite("WAVE", 1, 4, wav_file); 92abc91186SMilanka Ringwald 93fbc7c9f2SMilanka Ringwald int byte_rate = sample_rate * num_channels * write_with_bytes_per_sample; 94fbc7c9f2SMilanka Ringwald int bits_per_sample = 8 * write_with_bytes_per_sample; 95abc91186SMilanka Ringwald int block_align = num_channels * bits_per_sample; 96abc91186SMilanka Ringwald int fmt_length = 16; 97abc91186SMilanka Ringwald int fmt_format_tag = 1; // PCM 98abc91186SMilanka Ringwald 99abc91186SMilanka Ringwald /* write fmt chunk */ 100abc91186SMilanka Ringwald fwrite("fmt ", 1, 4, wav_file); 101abc91186SMilanka Ringwald little_endian_fstore_32(wav_file, fmt_length); 102abc91186SMilanka Ringwald little_endian_fstore_16(wav_file, fmt_format_tag); 103abc91186SMilanka Ringwald little_endian_fstore_16(wav_file, num_channels); 104abc91186SMilanka Ringwald little_endian_fstore_32(wav_file, sample_rate); 105abc91186SMilanka Ringwald little_endian_fstore_32(wav_file, byte_rate); 106abc91186SMilanka Ringwald little_endian_fstore_16(wav_file, block_align); 107abc91186SMilanka Ringwald little_endian_fstore_16(wav_file, bits_per_sample); 108abc91186SMilanka Ringwald 109abc91186SMilanka Ringwald /* write data chunk */ 110abc91186SMilanka Ringwald fwrite("data", 1, 4, wav_file); 111abc91186SMilanka Ringwald little_endian_fstore_32(wav_file, data_bytes); 112abc91186SMilanka Ringwald } 113abc91186SMilanka Ringwald 114abc91186SMilanka Ringwald int wav_writer_open(const char * filepath, int num_channels, int sampling_frequency){ 115abc91186SMilanka Ringwald FILE * wav_file = fopen(filepath, "wb"); 116abc91186SMilanka Ringwald if (!wav_file) return 1; 117abc91186SMilanka Ringwald 118abc91186SMilanka Ringwald wav_writer_state.wav_file = wav_file; 119abc91186SMilanka Ringwald wav_writer_state.frame_count = 0; 120abc91186SMilanka Ringwald wav_writer_state.total_num_samples = 0; 121abc91186SMilanka Ringwald wav_writer_state.num_channels = num_channels; 122abc91186SMilanka Ringwald wav_writer_state.sampling_frequency = sampling_frequency; 123abc91186SMilanka Ringwald write_wav_header(wav_writer_state.wav_file, 0, num_channels, sampling_frequency); 124abc91186SMilanka Ringwald return 0; 125abc91186SMilanka Ringwald } 126abc91186SMilanka Ringwald 127abc91186SMilanka Ringwald int wav_writer_close(void){ 12890af00b8SMatthias Ringwald if (wav_writer_state.wav_file == NULL) return 0; 129abc91186SMilanka Ringwald rewind(wav_writer_state.wav_file); 130abc91186SMilanka Ringwald write_wav_header(wav_writer_state.wav_file, wav_writer_state.total_num_samples, 131abc91186SMilanka Ringwald wav_writer_state.num_channels, wav_writer_state.sampling_frequency); 132abc91186SMilanka Ringwald fclose(wav_writer_state.wav_file); 13390af00b8SMatthias Ringwald wav_writer_state.wav_file = NULL; 134abc91186SMilanka Ringwald return 0; 135abc91186SMilanka Ringwald } 136abc91186SMilanka Ringwald 137abc91186SMilanka Ringwald int wav_writer_write_int8(int num_samples, int8_t * data){ 138d3c765a3SMatthias Ringwald btstack_assert(data != NULL); 139d3c765a3SMatthias Ringwald if (wav_writer_state.wav_file == NULL) return 1; 140d3c765a3SMatthias Ringwald 141abc91186SMilanka Ringwald int i = 0; 142abc91186SMilanka Ringwald int8_t zero_byte = 0; 143abc91186SMilanka Ringwald for (i=0; i<num_samples; i++){ 144abc91186SMilanka Ringwald fwrite(&zero_byte, 1, 1, wav_writer_state.wav_file); 145abc91186SMilanka Ringwald uint8_t byte_value = (uint8_t)data[i]; 146abc91186SMilanka Ringwald fwrite(&byte_value, 1, 1, wav_writer_state.wav_file); 147abc91186SMilanka Ringwald } 148abc91186SMilanka Ringwald 149abc91186SMilanka Ringwald wav_writer_state.total_num_samples+=num_samples; 150abc91186SMilanka Ringwald wav_writer_state.frame_count++; 151abc91186SMilanka Ringwald return 0; 152abc91186SMilanka Ringwald } 153abc91186SMilanka Ringwald 15492abe7b9SMatthias Ringwald int wav_writer_write_le_int16(int num_samples, int16_t * data){ 155d3c765a3SMatthias Ringwald btstack_assert(data != NULL); 156d3c765a3SMatthias Ringwald if (wav_writer_state.wav_file == NULL) return 1; 157d3c765a3SMatthias Ringwald 158fbc7c9f2SMilanka Ringwald fwrite(data, num_samples, 2, wav_writer_state.wav_file); 159fbc7c9f2SMilanka Ringwald 160fbc7c9f2SMilanka Ringwald wav_writer_state.total_num_samples+=num_samples; 161fbc7c9f2SMilanka Ringwald wav_writer_state.frame_count++; 162fbc7c9f2SMilanka Ringwald return 0; 163fbc7c9f2SMilanka Ringwald } 164fbc7c9f2SMilanka Ringwald 16592abe7b9SMatthias Ringwald int wav_writer_write_int16(int num_samples, int16_t * data){ 166d3c765a3SMatthias Ringwald btstack_assert(data != NULL); 167d3c765a3SMatthias Ringwald if (wav_writer_state.wav_file == NULL) return 1; 168d3c765a3SMatthias Ringwald 16992abe7b9SMatthias Ringwald if (btstack_is_little_endian()){ 17092abe7b9SMatthias Ringwald return wav_writer_write_le_int16(num_samples, data); 17192abe7b9SMatthias Ringwald } 17292abe7b9SMatthias Ringwald 17392abe7b9SMatthias Ringwald int i; 17492abe7b9SMatthias Ringwald for (i=0;i<num_samples;i++){ 17592abe7b9SMatthias Ringwald uint16_t sample = btstack_flip_16(data[i]); 17692abe7b9SMatthias Ringwald fwrite(&sample, 1, 2, wav_writer_state.wav_file); 17792abe7b9SMatthias Ringwald } 17892abe7b9SMatthias Ringwald 17992abe7b9SMatthias Ringwald wav_writer_state.total_num_samples+=num_samples; 18092abe7b9SMatthias Ringwald wav_writer_state.frame_count++; 18192abe7b9SMatthias Ringwald return 0; 18292abe7b9SMatthias Ringwald } 18392abe7b9SMatthias Ringwald 184e2bf7a9aSMatthias Ringwald /** WAV Reader Implementation */ 185e2bf7a9aSMatthias Ringwald 186abc91186SMilanka Ringwald int wav_reader_open(const char * filepath){ 187e2bf7a9aSMatthias Ringwald memset (&wav_reader_state, 0, sizeof(wav_reader_state)); 18886d6811aSMatthias Ringwald wav_reader_file = fopen(filepath, "rb"); 18986d6811aSMatthias Ringwald if (wav_reader_file == NULL) { 1906f91db60SMilanka Ringwald log_error("Can't open file %s", filepath); 191abc91186SMilanka Ringwald return 1; 192abc91186SMilanka Ringwald } 193abc91186SMilanka Ringwald 194abc91186SMilanka Ringwald uint8_t buf[40]; 19586d6811aSMatthias Ringwald fread(buf, 1, sizeof(buf), wav_reader_file); 196abc91186SMilanka Ringwald 1974016785cSMatthias Ringwald wav_reader_state.num_channels = (uint8_t) little_endian_read_16(buf, 22); 198e2bf7a9aSMatthias Ringwald if ((wav_reader_state.num_channels < 1) || (wav_reader_state.num_channels > 2)) { 199e2bf7a9aSMatthias Ringwald log_error("Unexpected num channels %d", wav_reader_state.num_channels); 2006f91db60SMilanka Ringwald return 1; 2016f91db60SMilanka Ringwald } 202e2bf7a9aSMatthias Ringwald 203e2bf7a9aSMatthias Ringwald wav_reader_state.sampling_rate = little_endian_read_32(buf, 24); 204e2bf7a9aSMatthias Ringwald 205e2bf7a9aSMatthias Ringwald int block_align = little_endian_read_16(buf, 32); 206e2bf7a9aSMatthias Ringwald wav_reader_bytes_per_sample = block_align / wav_reader_state.num_channels; 207e2bf7a9aSMatthias Ringwald if (wav_reader_bytes_per_sample > 2){ 208e2bf7a9aSMatthias Ringwald wav_reader_bytes_per_sample = wav_reader_bytes_per_sample / 8; 209abc91186SMilanka Ringwald } 210e2bf7a9aSMatthias Ringwald 211abc91186SMilanka Ringwald return 0; 212abc91186SMilanka Ringwald } 213abc91186SMilanka Ringwald 214e2bf7a9aSMatthias Ringwald uint8_t wav_reader_get_num_channels(void){ 215e2bf7a9aSMatthias Ringwald return wav_reader_state.num_channels; 216e2bf7a9aSMatthias Ringwald } 217e2bf7a9aSMatthias Ringwald 218e2bf7a9aSMatthias Ringwald uint32_t wav_reader_get_sampling_rate(void){ 219e2bf7a9aSMatthias Ringwald return wav_reader_state.sampling_rate; 220e2bf7a9aSMatthias Ringwald } 221e2bf7a9aSMatthias Ringwald 222abc91186SMilanka Ringwald int wav_reader_close(void){ 22386d6811aSMatthias Ringwald if (wav_reader_file != NULL){ 22486d6811aSMatthias Ringwald fclose(wav_reader_file); 22586d6811aSMatthias Ringwald } 226abc91186SMilanka Ringwald return 0; 227abc91186SMilanka Ringwald } 228abc91186SMilanka Ringwald 229abc91186SMilanka Ringwald // Wav data: 8bit is uint8_t; 16bit is int16 230abc91186SMilanka Ringwald int wav_reader_read_int8(int num_samples, int8_t * data){ 23186d6811aSMatthias Ringwald if (wav_reader_file == NULL) { 23286d6811aSMatthias Ringwald return 1; 23386d6811aSMatthias Ringwald } 234abc91186SMilanka Ringwald int i; 235abc91186SMilanka Ringwald int bytes_read = 0; 236abc91186SMilanka Ringwald 237abc91186SMilanka Ringwald for (i=0; i<num_samples; i++){ 238e2bf7a9aSMatthias Ringwald if (wav_reader_bytes_per_sample == 2){ 239abc91186SMilanka Ringwald uint8_t buf[2]; 2404016785cSMatthias Ringwald bytes_read += (uint16_t) fread(buf, 1, sizeof(buf), wav_reader_file);; 241abc91186SMilanka Ringwald data[i] = buf[1]; 242abc91186SMilanka Ringwald } else { 243abc91186SMilanka Ringwald uint8_t buf[1]; 2444016785cSMatthias Ringwald bytes_read += (uint16_t) fread(buf, 1, sizeof(buf), wav_reader_file);; 245abc91186SMilanka Ringwald data[i] = buf[0] + 128; 246abc91186SMilanka Ringwald } 247abc91186SMilanka Ringwald } 248e2bf7a9aSMatthias Ringwald if (bytes_read == num_samples * wav_reader_bytes_per_sample) { 249747ec646SMilanka Ringwald return 0; 250747ec646SMilanka Ringwald } else { 251747ec646SMilanka Ringwald return 1; 252747ec646SMilanka Ringwald } 253abc91186SMilanka Ringwald } 254abc91186SMilanka Ringwald 255fbc7c9f2SMilanka Ringwald int wav_reader_read_int16(int num_samples, int16_t * data){ 25686d6811aSMatthias Ringwald if (wav_reader_file == NULL) { 25786d6811aSMatthias Ringwald return 1; 25886d6811aSMatthias Ringwald } 259fbc7c9f2SMilanka Ringwald int i; 260fbc7c9f2SMilanka Ringwald int bytes_read = 0; 261fbc7c9f2SMilanka Ringwald for (i=0; i<num_samples; i++){ 262fbc7c9f2SMilanka Ringwald uint8_t buf[2]; 2634016785cSMatthias Ringwald bytes_read += (uint16_t) fread(buf, 1, sizeof(buf), wav_reader_file);; 264fbc7c9f2SMilanka Ringwald data[i] = little_endian_read_16(buf, 0); 265fbc7c9f2SMilanka Ringwald } 266e2bf7a9aSMatthias Ringwald if (bytes_read == num_samples * wav_reader_bytes_per_sample) { 267747ec646SMilanka Ringwald return 0; 268747ec646SMilanka Ringwald } else { 269747ec646SMilanka Ringwald return 1; 270747ec646SMilanka Ringwald } 271fbc7c9f2SMilanka Ringwald } 272fbc7c9f2SMilanka Ringwald 273abc91186SMilanka Ringwald 274