xref: /btstack/platform/posix/wav_util.c (revision fbc7c9f2bcce2ae889ba9f9b8e88863825d12925)
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 
38abc91186SMilanka Ringwald #include <stdint.h>
39abc91186SMilanka Ringwald #include <stdio.h>
40abc91186SMilanka Ringwald #include <stdlib.h>
41abc91186SMilanka Ringwald #include <string.h>
42abc91186SMilanka Ringwald #include <fcntl.h>
43abc91186SMilanka Ringwald #include <unistd.h>
44abc91186SMilanka Ringwald 
45abc91186SMilanka Ringwald #include "wav_util.h"
46abc91186SMilanka Ringwald #include "btstack_util.h"
47abc91186SMilanka Ringwald 
48*fbc7c9f2SMilanka Ringwald static const uint8_t sine_uint8[] = {
49abc91186SMilanka Ringwald       0,  15,  31,  46,  61,  74,  86,  97, 107, 114,
50abc91186SMilanka Ringwald     120, 124, 126, 126, 124, 120, 114, 107,  97,  86,
51abc91186SMilanka Ringwald      74,  61,  46,  31,  15,   0, 241, 225, 210, 195,
52abc91186SMilanka Ringwald     182, 170, 159, 149, 142, 136, 132, 130, 130, 132,
53abc91186SMilanka Ringwald     136, 142, 149, 159, 170, 182, 195, 210, 225, 241,
54abc91186SMilanka Ringwald };
55*fbc7c9f2SMilanka Ringwald 
56*fbc7c9f2SMilanka Ringwald 
57*fbc7c9f2SMilanka Ringwald // input signal: pre-computed sine wave, 160 Hz at 16000 kHz
58*fbc7c9f2SMilanka Ringwald static const int16_t sine_int16[] = {
59*fbc7c9f2SMilanka Ringwald      0,    2057,    4107,    6140,    8149,   10126,   12062,   13952,   15786,   17557,
60*fbc7c9f2SMilanka Ringwald  19260,   20886,   22431,   23886,   25247,   26509,   27666,   28714,   29648,   30466,
61*fbc7c9f2SMilanka Ringwald  31163,   31738,   32187,   32509,   32702,   32767,   32702,   32509,   32187,   31738,
62*fbc7c9f2SMilanka Ringwald  31163,   30466,   29648,   28714,   27666,   26509,   25247,   23886,   22431,   20886,
63*fbc7c9f2SMilanka Ringwald  19260,   17557,   15786,   13952,   12062,   10126,    8149,    6140,    4107,    2057,
64*fbc7c9f2SMilanka Ringwald      0,   -2057,   -4107,   -6140,   -8149,  -10126,  -12062,  -13952,  -15786,  -17557,
65*fbc7c9f2SMilanka Ringwald -19260,  -20886,  -22431,  -23886,  -25247,  -26509,  -27666,  -28714,  -29648,  -30466,
66*fbc7c9f2SMilanka Ringwald -31163,  -31738,  -32187,  -32509,  -32702,  -32767,  -32702,  -32509,  -32187,  -31738,
67*fbc7c9f2SMilanka Ringwald -31163,  -30466,  -29648,  -28714,  -27666,  -26509,  -25247,  -23886,  -22431,  -20886,
68*fbc7c9f2SMilanka Ringwald -19260,  -17557,  -15786,  -13952,  -12062,  -10126,   -8149,   -6140,   -4107,   -2057,
69*fbc7c9f2SMilanka Ringwald };
70*fbc7c9f2SMilanka Ringwald 
71abc91186SMilanka Ringwald static int phase = 0;
72abc91186SMilanka Ringwald 
73abc91186SMilanka Ringwald static int wav_reader_fd;
74abc91186SMilanka Ringwald static int bytes_per_sample = 2;
75abc91186SMilanka Ringwald 
76abc91186SMilanka Ringwald /* Write wav file utils */
77abc91186SMilanka Ringwald typedef struct wav_writer_state {
78abc91186SMilanka Ringwald     FILE * wav_file;
79abc91186SMilanka Ringwald     int total_num_samples;
80abc91186SMilanka Ringwald     int num_channels;
81abc91186SMilanka Ringwald     int sampling_frequency;
82abc91186SMilanka Ringwald     int frame_count;
83abc91186SMilanka Ringwald } wav_writer_state_t;
84abc91186SMilanka Ringwald 
85abc91186SMilanka Ringwald wav_writer_state_t wav_writer_state;
86abc91186SMilanka Ringwald 
87abc91186SMilanka Ringwald 
88abc91186SMilanka Ringwald static void little_endian_fstore_16(FILE *wav_file, uint16_t value){
89abc91186SMilanka Ringwald     uint8_t buf[2];
90abc91186SMilanka Ringwald     little_endian_store_16(buf, 0, value);
91abc91186SMilanka Ringwald     fwrite(&buf, 1, 2, wav_file);
92abc91186SMilanka Ringwald }
93abc91186SMilanka Ringwald 
94abc91186SMilanka Ringwald static void little_endian_fstore_32(FILE *wav_file, uint32_t value){
95abc91186SMilanka Ringwald     uint8_t buf[4];
96abc91186SMilanka Ringwald     little_endian_store_32(buf, 0, value);
97abc91186SMilanka Ringwald     fwrite(&buf, 1, 4, wav_file);
98abc91186SMilanka Ringwald }
99abc91186SMilanka Ringwald 
100abc91186SMilanka Ringwald static ssize_t __read(int fd, void *buf, size_t count){
101abc91186SMilanka Ringwald     ssize_t len, pos = 0;
102abc91186SMilanka Ringwald 
103abc91186SMilanka Ringwald     while (count > 0) {
104abc91186SMilanka Ringwald         len = read(fd, (int8_t * )buf + pos, count);
105abc91186SMilanka Ringwald         if (len <= 0)
106abc91186SMilanka Ringwald             return pos;
107abc91186SMilanka Ringwald 
108abc91186SMilanka Ringwald         count -= len;
109abc91186SMilanka Ringwald         pos   += len;
110abc91186SMilanka Ringwald     }
111abc91186SMilanka Ringwald     return pos;
112abc91186SMilanka Ringwald }
113abc91186SMilanka Ringwald 
114abc91186SMilanka Ringwald static void write_wav_header(FILE * wav_file,  int total_num_samples, int num_channels, int sample_rate){
115*fbc7c9f2SMilanka Ringwald     unsigned int write_with_bytes_per_sample = 2;
116abc91186SMilanka Ringwald     /* write RIFF header */
117abc91186SMilanka Ringwald     fwrite("RIFF", 1, 4, wav_file);
118abc91186SMilanka Ringwald     // num_samples = blocks * subbands
119*fbc7c9f2SMilanka Ringwald     uint32_t data_bytes = (uint32_t) (write_with_bytes_per_sample * total_num_samples * num_channels);
120abc91186SMilanka Ringwald     little_endian_fstore_32(wav_file, data_bytes + 36);
121abc91186SMilanka Ringwald     fwrite("WAVE", 1, 4, wav_file);
122abc91186SMilanka Ringwald 
123*fbc7c9f2SMilanka Ringwald     int byte_rate = sample_rate * num_channels * write_with_bytes_per_sample;
124*fbc7c9f2SMilanka Ringwald     int bits_per_sample = 8 * write_with_bytes_per_sample;
125abc91186SMilanka Ringwald     int block_align = num_channels * bits_per_sample;
126abc91186SMilanka Ringwald     int fmt_length = 16;
127abc91186SMilanka Ringwald     int fmt_format_tag = 1; // PCM
128abc91186SMilanka Ringwald 
129abc91186SMilanka Ringwald     /* write fmt chunk */
130abc91186SMilanka Ringwald     fwrite("fmt ", 1, 4, wav_file);
131abc91186SMilanka Ringwald     little_endian_fstore_32(wav_file, fmt_length);
132abc91186SMilanka Ringwald     little_endian_fstore_16(wav_file, fmt_format_tag);
133abc91186SMilanka Ringwald     little_endian_fstore_16(wav_file, num_channels);
134abc91186SMilanka Ringwald     little_endian_fstore_32(wav_file, sample_rate);
135abc91186SMilanka Ringwald     little_endian_fstore_32(wav_file, byte_rate);
136abc91186SMilanka Ringwald     little_endian_fstore_16(wav_file, block_align);
137abc91186SMilanka Ringwald     little_endian_fstore_16(wav_file, bits_per_sample);
138abc91186SMilanka Ringwald 
139abc91186SMilanka Ringwald     /* write data chunk */
140abc91186SMilanka Ringwald     fwrite("data", 1, 4, wav_file);
141abc91186SMilanka Ringwald     little_endian_fstore_32(wav_file, data_bytes);
142abc91186SMilanka Ringwald }
143abc91186SMilanka Ringwald 
144abc91186SMilanka Ringwald int wav_writer_open(const char * filepath, int num_channels, int sampling_frequency){
145abc91186SMilanka Ringwald     FILE * wav_file = fopen(filepath, "wb");
146abc91186SMilanka Ringwald     if (!wav_file) return 1;
147abc91186SMilanka Ringwald 
148abc91186SMilanka Ringwald     wav_writer_state.wav_file = wav_file;
149abc91186SMilanka Ringwald     wav_writer_state.frame_count = 0;
150abc91186SMilanka Ringwald     wav_writer_state.total_num_samples = 0;
151abc91186SMilanka Ringwald     wav_writer_state.num_channels = num_channels;
152abc91186SMilanka Ringwald     wav_writer_state.sampling_frequency = sampling_frequency;
153abc91186SMilanka Ringwald     write_wav_header(wav_writer_state.wav_file, 0, num_channels, sampling_frequency);
154abc91186SMilanka Ringwald     return 0;
155abc91186SMilanka Ringwald }
156abc91186SMilanka Ringwald 
157abc91186SMilanka Ringwald int wav_writer_close(void){
158abc91186SMilanka Ringwald     rewind(wav_writer_state.wav_file);
159abc91186SMilanka Ringwald     write_wav_header(wav_writer_state.wav_file, wav_writer_state.total_num_samples,
160abc91186SMilanka Ringwald         wav_writer_state.num_channels, wav_writer_state.sampling_frequency);
161abc91186SMilanka Ringwald     fclose(wav_writer_state.wav_file);
162abc91186SMilanka Ringwald     return 0;
163abc91186SMilanka Ringwald }
164abc91186SMilanka Ringwald 
165abc91186SMilanka Ringwald int wav_writer_write_int8(int num_samples, int8_t * data){
166abc91186SMilanka Ringwald     if (data == NULL) return 1;
167abc91186SMilanka Ringwald     int i = 0;
168abc91186SMilanka Ringwald     int8_t zero_byte = 0;
169abc91186SMilanka Ringwald     for (i=0; i<num_samples; i++){
170abc91186SMilanka Ringwald         fwrite(&zero_byte, 1, 1, wav_writer_state.wav_file);
171abc91186SMilanka Ringwald         uint8_t byte_value = (uint8_t)data[i];
172abc91186SMilanka Ringwald         fwrite(&byte_value, 1, 1, wav_writer_state.wav_file);
173abc91186SMilanka Ringwald     }
174abc91186SMilanka Ringwald 
175abc91186SMilanka Ringwald     wav_writer_state.total_num_samples+=num_samples;
176abc91186SMilanka Ringwald     wav_writer_state.frame_count++;
177abc91186SMilanka Ringwald     return 0;
178abc91186SMilanka Ringwald }
179abc91186SMilanka Ringwald 
180*fbc7c9f2SMilanka Ringwald int wav_writer_write_int16(int num_samples, int16_t * data){
181*fbc7c9f2SMilanka Ringwald     if (data == NULL) return 1;
182*fbc7c9f2SMilanka Ringwald     fwrite(data, num_samples, 2, wav_writer_state.wav_file);
183*fbc7c9f2SMilanka Ringwald 
184*fbc7c9f2SMilanka Ringwald     wav_writer_state.total_num_samples+=num_samples;
185*fbc7c9f2SMilanka Ringwald     wav_writer_state.frame_count++;
186*fbc7c9f2SMilanka Ringwald     return 0;
187*fbc7c9f2SMilanka Ringwald }
188*fbc7c9f2SMilanka Ringwald 
189abc91186SMilanka Ringwald int wav_reader_open(const char * filepath){
190abc91186SMilanka Ringwald     wav_reader_fd = open(filepath, O_RDONLY);
191abc91186SMilanka Ringwald     if (!wav_reader_fd) {
192abc91186SMilanka Ringwald         printf("Can't open file %s", filepath);
193abc91186SMilanka Ringwald         return 1;
194abc91186SMilanka Ringwald     }
195abc91186SMilanka Ringwald 
196abc91186SMilanka Ringwald     uint8_t buf[40];
197abc91186SMilanka Ringwald     __read(wav_reader_fd, buf, sizeof(buf));
198abc91186SMilanka Ringwald 
199abc91186SMilanka Ringwald     int num_channels = little_endian_read_16(buf, 22);
200abc91186SMilanka Ringwald     int block_align = little_endian_read_16(buf, 32);
201abc91186SMilanka Ringwald     bytes_per_sample = block_align/num_channels;
202abc91186SMilanka Ringwald     if (bytes_per_sample > 2){
203abc91186SMilanka Ringwald         bytes_per_sample = bytes_per_sample/8;
204abc91186SMilanka Ringwald     }
205abc91186SMilanka Ringwald     return 0;
206abc91186SMilanka Ringwald }
207abc91186SMilanka Ringwald 
208abc91186SMilanka Ringwald int wav_reader_close(void){
209abc91186SMilanka Ringwald     close(wav_reader_fd);
210abc91186SMilanka Ringwald     return 0;
211abc91186SMilanka Ringwald }
212abc91186SMilanka Ringwald 
213abc91186SMilanka Ringwald // Wav data: 8bit is uint8_t; 16bit is int16
214abc91186SMilanka Ringwald int wav_reader_read_int8(int num_samples, int8_t * data){
215abc91186SMilanka Ringwald     if (!wav_reader_fd) return 1;
216abc91186SMilanka Ringwald     int i;
217abc91186SMilanka Ringwald     int bytes_read = 0;
218abc91186SMilanka Ringwald 
219abc91186SMilanka Ringwald     for (i=0; i<num_samples; i++){
220abc91186SMilanka Ringwald         if (bytes_per_sample == 2){
221abc91186SMilanka Ringwald             uint8_t buf[2];
222abc91186SMilanka Ringwald             bytes_read +=__read(wav_reader_fd, &buf, 2);
223abc91186SMilanka Ringwald             data[i] = buf[1];
224abc91186SMilanka Ringwald         } else {
225abc91186SMilanka Ringwald             uint8_t buf[1];
226abc91186SMilanka Ringwald             bytes_read +=__read(wav_reader_fd, &buf, 1);
227abc91186SMilanka Ringwald             data[i] = buf[0] + 128;
228abc91186SMilanka Ringwald         }
229abc91186SMilanka Ringwald     }
230abc91186SMilanka Ringwald     return bytes_read == num_samples*bytes_per_sample;
231abc91186SMilanka Ringwald }
232abc91186SMilanka Ringwald 
233*fbc7c9f2SMilanka Ringwald int wav_reader_read_int16(int num_samples, int16_t * data){
234*fbc7c9f2SMilanka Ringwald     if (!wav_reader_fd) return 1;
235*fbc7c9f2SMilanka Ringwald     int i;
236*fbc7c9f2SMilanka Ringwald     int bytes_read = 0;
237*fbc7c9f2SMilanka Ringwald     for (i=0; i<num_samples; i++){
238*fbc7c9f2SMilanka Ringwald         uint8_t buf[2];
239*fbc7c9f2SMilanka Ringwald         bytes_read +=__read(wav_reader_fd, &buf, 2);
240*fbc7c9f2SMilanka Ringwald         data[i] = little_endian_read_16(buf, 0);
241*fbc7c9f2SMilanka Ringwald     }
242*fbc7c9f2SMilanka Ringwald     return bytes_read == num_samples*bytes_per_sample;
243*fbc7c9f2SMilanka Ringwald }
244*fbc7c9f2SMilanka Ringwald 
245abc91186SMilanka Ringwald void wav_synthesize_sine_wave_int8(int num_samples, int8_t * data){
246abc91186SMilanka Ringwald     int i;
247abc91186SMilanka Ringwald     for (i=0; i<num_samples; i++){
248*fbc7c9f2SMilanka Ringwald         data[i] = (int8_t)sine_uint8[phase];
249abc91186SMilanka Ringwald         phase++;
250*fbc7c9f2SMilanka Ringwald         if (phase >= sizeof(sine_uint8)) phase = 0;
251*fbc7c9f2SMilanka Ringwald     }
252*fbc7c9f2SMilanka Ringwald }
253*fbc7c9f2SMilanka Ringwald 
254*fbc7c9f2SMilanka Ringwald void wav_synthesize_sine_wave_int16(int num_samples, int16_t * data){
255*fbc7c9f2SMilanka Ringwald     int i;
256*fbc7c9f2SMilanka Ringwald     for (i=0; i < num_samples; i++){
257*fbc7c9f2SMilanka Ringwald         data[i] = sine_int16[phase++];
258*fbc7c9f2SMilanka Ringwald         if (phase >= (sizeof(sine_int16) / sizeof(int16_t))){
259*fbc7c9f2SMilanka Ringwald             phase = 0;
260*fbc7c9f2SMilanka Ringwald         }
261abc91186SMilanka Ringwald     }
262abc91186SMilanka Ringwald }
263abc91186SMilanka Ringwald 
264