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 23abc91186SMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24abc91186SMilanka Ringwald * RINGWALD 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 40abc91186SMilanka Ringwald #include <stdint.h> 41abc91186SMilanka Ringwald #include <stdio.h> 42abc91186SMilanka Ringwald #include <stdlib.h> 43abc91186SMilanka Ringwald #include <string.h> 44abc91186SMilanka Ringwald #include <fcntl.h> 45abc91186SMilanka Ringwald #include <unistd.h> 46abc91186SMilanka Ringwald 47abc91186SMilanka Ringwald #include "wav_util.h" 48abc91186SMilanka Ringwald #include "btstack_util.h" 496f91db60SMilanka Ringwald #include "btstack_debug.h" 50abc91186SMilanka Ringwald 51abc91186SMilanka Ringwald static int wav_reader_fd; 52abc91186SMilanka Ringwald static int bytes_per_sample = 2; 53abc91186SMilanka Ringwald 54abc91186SMilanka Ringwald /* Write wav file utils */ 55abc91186SMilanka Ringwald typedef struct wav_writer_state { 56abc91186SMilanka Ringwald FILE * wav_file; 57abc91186SMilanka Ringwald int total_num_samples; 58abc91186SMilanka Ringwald int num_channels; 59abc91186SMilanka Ringwald int sampling_frequency; 60abc91186SMilanka Ringwald int frame_count; 61abc91186SMilanka Ringwald } wav_writer_state_t; 62abc91186SMilanka Ringwald 63abc91186SMilanka Ringwald wav_writer_state_t wav_writer_state; 64abc91186SMilanka Ringwald 65abc91186SMilanka Ringwald 66abc91186SMilanka Ringwald static void little_endian_fstore_16(FILE *wav_file, uint16_t value){ 67abc91186SMilanka Ringwald uint8_t buf[2]; 68abc91186SMilanka Ringwald little_endian_store_16(buf, 0, value); 69abc91186SMilanka Ringwald fwrite(&buf, 1, 2, wav_file); 70abc91186SMilanka Ringwald } 71abc91186SMilanka Ringwald 72abc91186SMilanka Ringwald static void little_endian_fstore_32(FILE *wav_file, uint32_t value){ 73abc91186SMilanka Ringwald uint8_t buf[4]; 74abc91186SMilanka Ringwald little_endian_store_32(buf, 0, value); 75abc91186SMilanka Ringwald fwrite(&buf, 1, 4, wav_file); 76abc91186SMilanka Ringwald } 77abc91186SMilanka Ringwald 78abc91186SMilanka Ringwald static ssize_t __read(int fd, void *buf, size_t count){ 79abc91186SMilanka Ringwald ssize_t len, pos = 0; 80abc91186SMilanka Ringwald 81abc91186SMilanka Ringwald while (count > 0) { 82abc91186SMilanka Ringwald len = read(fd, (int8_t * )buf + pos, count); 83abc91186SMilanka Ringwald if (len <= 0) 84abc91186SMilanka Ringwald return pos; 85abc91186SMilanka Ringwald 86abc91186SMilanka Ringwald count -= len; 87abc91186SMilanka Ringwald pos += len; 88abc91186SMilanka Ringwald } 89abc91186SMilanka Ringwald return pos; 90abc91186SMilanka Ringwald } 91abc91186SMilanka Ringwald 92abc91186SMilanka Ringwald static void write_wav_header(FILE * wav_file, int total_num_samples, int num_channels, int sample_rate){ 93fbc7c9f2SMilanka Ringwald unsigned int write_with_bytes_per_sample = 2; 94abc91186SMilanka Ringwald /* write RIFF header */ 95abc91186SMilanka Ringwald fwrite("RIFF", 1, 4, wav_file); 96abc91186SMilanka Ringwald // num_samples = blocks * subbands 97fbc7c9f2SMilanka Ringwald uint32_t data_bytes = (uint32_t) (write_with_bytes_per_sample * total_num_samples * num_channels); 98abc91186SMilanka Ringwald little_endian_fstore_32(wav_file, data_bytes + 36); 99abc91186SMilanka Ringwald fwrite("WAVE", 1, 4, wav_file); 100abc91186SMilanka Ringwald 101fbc7c9f2SMilanka Ringwald int byte_rate = sample_rate * num_channels * write_with_bytes_per_sample; 102fbc7c9f2SMilanka Ringwald int bits_per_sample = 8 * write_with_bytes_per_sample; 103abc91186SMilanka Ringwald int block_align = num_channels * bits_per_sample; 104abc91186SMilanka Ringwald int fmt_length = 16; 105abc91186SMilanka Ringwald int fmt_format_tag = 1; // PCM 106abc91186SMilanka Ringwald 107abc91186SMilanka Ringwald /* write fmt chunk */ 108abc91186SMilanka Ringwald fwrite("fmt ", 1, 4, wav_file); 109abc91186SMilanka Ringwald little_endian_fstore_32(wav_file, fmt_length); 110abc91186SMilanka Ringwald little_endian_fstore_16(wav_file, fmt_format_tag); 111abc91186SMilanka Ringwald little_endian_fstore_16(wav_file, num_channels); 112abc91186SMilanka Ringwald little_endian_fstore_32(wav_file, sample_rate); 113abc91186SMilanka Ringwald little_endian_fstore_32(wav_file, byte_rate); 114abc91186SMilanka Ringwald little_endian_fstore_16(wav_file, block_align); 115abc91186SMilanka Ringwald little_endian_fstore_16(wav_file, bits_per_sample); 116abc91186SMilanka Ringwald 117abc91186SMilanka Ringwald /* write data chunk */ 118abc91186SMilanka Ringwald fwrite("data", 1, 4, wav_file); 119abc91186SMilanka Ringwald little_endian_fstore_32(wav_file, data_bytes); 120abc91186SMilanka Ringwald } 121abc91186SMilanka Ringwald 122abc91186SMilanka Ringwald int wav_writer_open(const char * filepath, int num_channels, int sampling_frequency){ 123abc91186SMilanka Ringwald FILE * wav_file = fopen(filepath, "wb"); 124abc91186SMilanka Ringwald if (!wav_file) return 1; 125abc91186SMilanka Ringwald 126abc91186SMilanka Ringwald wav_writer_state.wav_file = wav_file; 127abc91186SMilanka Ringwald wav_writer_state.frame_count = 0; 128abc91186SMilanka Ringwald wav_writer_state.total_num_samples = 0; 129abc91186SMilanka Ringwald wav_writer_state.num_channels = num_channels; 130abc91186SMilanka Ringwald wav_writer_state.sampling_frequency = sampling_frequency; 131abc91186SMilanka Ringwald write_wav_header(wav_writer_state.wav_file, 0, num_channels, sampling_frequency); 132abc91186SMilanka Ringwald return 0; 133abc91186SMilanka Ringwald } 134abc91186SMilanka Ringwald 135abc91186SMilanka Ringwald int wav_writer_close(void){ 136*90af00b8SMatthias Ringwald if (wav_writer_state.wav_file == NULL) return 0; 137abc91186SMilanka Ringwald rewind(wav_writer_state.wav_file); 138abc91186SMilanka Ringwald write_wav_header(wav_writer_state.wav_file, wav_writer_state.total_num_samples, 139abc91186SMilanka Ringwald wav_writer_state.num_channels, wav_writer_state.sampling_frequency); 140abc91186SMilanka Ringwald fclose(wav_writer_state.wav_file); 141*90af00b8SMatthias Ringwald wav_writer_state.wav_file = NULL; 142abc91186SMilanka Ringwald return 0; 143abc91186SMilanka Ringwald } 144abc91186SMilanka Ringwald 145abc91186SMilanka Ringwald int wav_writer_write_int8(int num_samples, int8_t * data){ 146abc91186SMilanka Ringwald if (data == NULL) return 1; 147abc91186SMilanka Ringwald int i = 0; 148abc91186SMilanka Ringwald int8_t zero_byte = 0; 149abc91186SMilanka Ringwald for (i=0; i<num_samples; i++){ 150abc91186SMilanka Ringwald fwrite(&zero_byte, 1, 1, wav_writer_state.wav_file); 151abc91186SMilanka Ringwald uint8_t byte_value = (uint8_t)data[i]; 152abc91186SMilanka Ringwald fwrite(&byte_value, 1, 1, wav_writer_state.wav_file); 153abc91186SMilanka Ringwald } 154abc91186SMilanka Ringwald 155abc91186SMilanka Ringwald wav_writer_state.total_num_samples+=num_samples; 156abc91186SMilanka Ringwald wav_writer_state.frame_count++; 157abc91186SMilanka Ringwald return 0; 158abc91186SMilanka Ringwald } 159abc91186SMilanka Ringwald 16092abe7b9SMatthias Ringwald int wav_writer_write_le_int16(int num_samples, int16_t * data){ 161fbc7c9f2SMilanka Ringwald if (data == NULL) return 1; 162fbc7c9f2SMilanka Ringwald fwrite(data, num_samples, 2, wav_writer_state.wav_file); 163fbc7c9f2SMilanka Ringwald 164fbc7c9f2SMilanka Ringwald wav_writer_state.total_num_samples+=num_samples; 165fbc7c9f2SMilanka Ringwald wav_writer_state.frame_count++; 166fbc7c9f2SMilanka Ringwald return 0; 167fbc7c9f2SMilanka Ringwald } 168fbc7c9f2SMilanka Ringwald 16992abe7b9SMatthias Ringwald int wav_writer_write_int16(int num_samples, int16_t * data){ 17092abe7b9SMatthias Ringwald if (btstack_is_little_endian()){ 17192abe7b9SMatthias Ringwald return wav_writer_write_le_int16(num_samples, data); 17292abe7b9SMatthias Ringwald } 17392abe7b9SMatthias Ringwald if (data == NULL) return 1; 17492abe7b9SMatthias Ringwald 17592abe7b9SMatthias Ringwald int i; 17692abe7b9SMatthias Ringwald for (i=0;i<num_samples;i++){ 17792abe7b9SMatthias Ringwald uint16_t sample = btstack_flip_16(data[i]); 17892abe7b9SMatthias Ringwald fwrite(&sample, 1, 2, wav_writer_state.wav_file); 17992abe7b9SMatthias Ringwald } 18092abe7b9SMatthias Ringwald 18192abe7b9SMatthias Ringwald wav_writer_state.total_num_samples+=num_samples; 18292abe7b9SMatthias Ringwald wav_writer_state.frame_count++; 18392abe7b9SMatthias Ringwald return 0; 18492abe7b9SMatthias Ringwald } 18592abe7b9SMatthias Ringwald 186abc91186SMilanka Ringwald int wav_reader_open(const char * filepath){ 187abc91186SMilanka Ringwald wav_reader_fd = open(filepath, O_RDONLY); 188abc91186SMilanka Ringwald if (!wav_reader_fd) { 1896f91db60SMilanka Ringwald log_error("Can't open file %s", filepath); 190abc91186SMilanka Ringwald return 1; 191abc91186SMilanka Ringwald } 192abc91186SMilanka Ringwald 193abc91186SMilanka Ringwald uint8_t buf[40]; 194abc91186SMilanka Ringwald __read(wav_reader_fd, buf, sizeof(buf)); 195abc91186SMilanka Ringwald 196abc91186SMilanka Ringwald int num_channels = little_endian_read_16(buf, 22); 197abc91186SMilanka Ringwald int block_align = little_endian_read_16(buf, 32); 1986f91db60SMilanka Ringwald if (num_channels != 1 && num_channels != 2) { 1996f91db60SMilanka Ringwald log_error("Unexpected num channels %d", num_channels); 2006f91db60SMilanka Ringwald return 1; 2016f91db60SMilanka Ringwald } 202abc91186SMilanka Ringwald bytes_per_sample = block_align/num_channels; 203abc91186SMilanka Ringwald if (bytes_per_sample > 2){ 204abc91186SMilanka Ringwald bytes_per_sample = bytes_per_sample/8; 205abc91186SMilanka Ringwald } 206abc91186SMilanka Ringwald return 0; 207abc91186SMilanka Ringwald } 208abc91186SMilanka Ringwald 209abc91186SMilanka Ringwald int wav_reader_close(void){ 210abc91186SMilanka Ringwald close(wav_reader_fd); 211abc91186SMilanka Ringwald return 0; 212abc91186SMilanka Ringwald } 213abc91186SMilanka Ringwald 214abc91186SMilanka Ringwald // Wav data: 8bit is uint8_t; 16bit is int16 215abc91186SMilanka Ringwald int wav_reader_read_int8(int num_samples, int8_t * data){ 216abc91186SMilanka Ringwald if (!wav_reader_fd) return 1; 217abc91186SMilanka Ringwald int i; 218abc91186SMilanka Ringwald int bytes_read = 0; 219abc91186SMilanka Ringwald 220abc91186SMilanka Ringwald for (i=0; i<num_samples; i++){ 221abc91186SMilanka Ringwald if (bytes_per_sample == 2){ 222abc91186SMilanka Ringwald uint8_t buf[2]; 223abc91186SMilanka Ringwald bytes_read +=__read(wav_reader_fd, &buf, 2); 224abc91186SMilanka Ringwald data[i] = buf[1]; 225abc91186SMilanka Ringwald } else { 226abc91186SMilanka Ringwald uint8_t buf[1]; 227abc91186SMilanka Ringwald bytes_read +=__read(wav_reader_fd, &buf, 1); 228abc91186SMilanka Ringwald data[i] = buf[0] + 128; 229abc91186SMilanka Ringwald } 230abc91186SMilanka Ringwald } 231747ec646SMilanka Ringwald if (bytes_read == num_samples*bytes_per_sample) { 232747ec646SMilanka Ringwald return 0; 233747ec646SMilanka Ringwald } else { 234747ec646SMilanka Ringwald return 1; 235747ec646SMilanka Ringwald } 236abc91186SMilanka Ringwald } 237abc91186SMilanka Ringwald 238fbc7c9f2SMilanka Ringwald int wav_reader_read_int16(int num_samples, int16_t * data){ 239fbc7c9f2SMilanka Ringwald if (!wav_reader_fd) return 1; 240fbc7c9f2SMilanka Ringwald int i; 241fbc7c9f2SMilanka Ringwald int bytes_read = 0; 242fbc7c9f2SMilanka Ringwald for (i=0; i<num_samples; i++){ 243fbc7c9f2SMilanka Ringwald uint8_t buf[2]; 244fbc7c9f2SMilanka Ringwald bytes_read +=__read(wav_reader_fd, &buf, 2); 245fbc7c9f2SMilanka Ringwald data[i] = little_endian_read_16(buf, 0); 246fbc7c9f2SMilanka Ringwald } 247747ec646SMilanka Ringwald if (bytes_read == num_samples*bytes_per_sample) { 248747ec646SMilanka Ringwald return 0; 249747ec646SMilanka Ringwald } else { 250747ec646SMilanka Ringwald return 1; 251747ec646SMilanka Ringwald } 252fbc7c9f2SMilanka Ringwald } 253fbc7c9f2SMilanka Ringwald 254abc91186SMilanka Ringwald 255