xref: /btstack/platform/posix/wav_util.c (revision bc37f7b0d0a3eaa5763a873c5730bc14b849aaa0)
1 /*
2  * Copyright (C) 2016 BlueKitchen GmbH
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holders nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  * 4. Any redistribution, use, or modification is done solely for
17  *    personal benefit and not for any commercial purpose or for
18  *    monetary gain.
19  *
20  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Please inquire about commercial licensing options at
34  * [email protected]
35  *
36  */
37 
38 #include <stdint.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <fcntl.h>
43 #include <unistd.h>
44 
45 #include "wav_util.h"
46 #include "btstack_util.h"
47 
48 static const uint8_t sine_uint8[] = {
49       0,  15,  31,  46,  61,  74,  86,  97, 107, 114,
50     120, 124, 126, 126, 124, 120, 114, 107,  97,  86,
51      74,  61,  46,  31,  15,   0, 241, 225, 210, 195,
52     182, 170, 159, 149, 142, 136, 132, 130, 130, 132,
53     136, 142, 149, 159, 170, 182, 195, 210, 225, 241,
54 };
55 
56 
57 // input signal: pre-computed sine wave, 160 Hz at 16000 kHz
58 static const int16_t sine_int16[] = {
59      0,    2057,    4107,    6140,    8149,   10126,   12062,   13952,   15786,   17557,
60  19260,   20886,   22431,   23886,   25247,   26509,   27666,   28714,   29648,   30466,
61  31163,   31738,   32187,   32509,   32702,   32767,   32702,   32509,   32187,   31738,
62  31163,   30466,   29648,   28714,   27666,   26509,   25247,   23886,   22431,   20886,
63  19260,   17557,   15786,   13952,   12062,   10126,    8149,    6140,    4107,    2057,
64      0,   -2057,   -4107,   -6140,   -8149,  -10126,  -12062,  -13952,  -15786,  -17557,
65 -19260,  -20886,  -22431,  -23886,  -25247,  -26509,  -27666,  -28714,  -29648,  -30466,
66 -31163,  -31738,  -32187,  -32509,  -32702,  -32767,  -32702,  -32509,  -32187,  -31738,
67 -31163,  -30466,  -29648,  -28714,  -27666,  -26509,  -25247,  -23886,  -22431,  -20886,
68 -19260,  -17557,  -15786,  -13952,  -12062,  -10126,   -8149,   -6140,   -4107,   -2057,
69 };
70 
71 static int phase = 0;
72 
73 static int wav_reader_fd;
74 static int bytes_per_sample = 2;
75 
76 /* Write wav file utils */
77 typedef struct wav_writer_state {
78     FILE * wav_file;
79     int total_num_samples;
80     int num_channels;
81     int sampling_frequency;
82     int frame_count;
83 } wav_writer_state_t;
84 
85 wav_writer_state_t wav_writer_state;
86 
87 
88 static void little_endian_fstore_16(FILE *wav_file, uint16_t value){
89     uint8_t buf[2];
90     little_endian_store_16(buf, 0, value);
91     fwrite(&buf, 1, 2, wav_file);
92 }
93 
94 static void little_endian_fstore_32(FILE *wav_file, uint32_t value){
95     uint8_t buf[4];
96     little_endian_store_32(buf, 0, value);
97     fwrite(&buf, 1, 4, wav_file);
98 }
99 
100 static ssize_t __read(int fd, void *buf, size_t count){
101     ssize_t len, pos = 0;
102 
103     while (count > 0) {
104         len = read(fd, (int8_t * )buf + pos, count);
105         if (len <= 0)
106             return pos;
107 
108         count -= len;
109         pos   += len;
110     }
111     return pos;
112 }
113 
114 static void write_wav_header(FILE * wav_file,  int total_num_samples, int num_channels, int sample_rate){
115     unsigned int write_with_bytes_per_sample = 2;
116     /* write RIFF header */
117     fwrite("RIFF", 1, 4, wav_file);
118     // num_samples = blocks * subbands
119     uint32_t data_bytes = (uint32_t) (write_with_bytes_per_sample * total_num_samples * num_channels);
120     little_endian_fstore_32(wav_file, data_bytes + 36);
121     fwrite("WAVE", 1, 4, wav_file);
122 
123     int byte_rate = sample_rate * num_channels * write_with_bytes_per_sample;
124     int bits_per_sample = 8 * write_with_bytes_per_sample;
125     int block_align = num_channels * bits_per_sample;
126     int fmt_length = 16;
127     int fmt_format_tag = 1; // PCM
128 
129     /* write fmt chunk */
130     fwrite("fmt ", 1, 4, wav_file);
131     little_endian_fstore_32(wav_file, fmt_length);
132     little_endian_fstore_16(wav_file, fmt_format_tag);
133     little_endian_fstore_16(wav_file, num_channels);
134     little_endian_fstore_32(wav_file, sample_rate);
135     little_endian_fstore_32(wav_file, byte_rate);
136     little_endian_fstore_16(wav_file, block_align);
137     little_endian_fstore_16(wav_file, bits_per_sample);
138 
139     /* write data chunk */
140     fwrite("data", 1, 4, wav_file);
141     little_endian_fstore_32(wav_file, data_bytes);
142 }
143 
144 int wav_writer_open(const char * filepath, int num_channels, int sampling_frequency){
145     FILE * wav_file = fopen(filepath, "wb");
146     if (!wav_file) return 1;
147 
148     wav_writer_state.wav_file = wav_file;
149     wav_writer_state.frame_count = 0;
150     wav_writer_state.total_num_samples = 0;
151     wav_writer_state.num_channels = num_channels;
152     wav_writer_state.sampling_frequency = sampling_frequency;
153     write_wav_header(wav_writer_state.wav_file, 0, num_channels, sampling_frequency);
154     return 0;
155 }
156 
157 int wav_writer_close(void){
158     rewind(wav_writer_state.wav_file);
159     write_wav_header(wav_writer_state.wav_file, wav_writer_state.total_num_samples,
160         wav_writer_state.num_channels, wav_writer_state.sampling_frequency);
161     fclose(wav_writer_state.wav_file);
162     return 0;
163 }
164 
165 int wav_writer_write_int8(int num_samples, int8_t * data){
166     if (data == NULL) return 1;
167     int i = 0;
168     int8_t zero_byte = 0;
169     for (i=0; i<num_samples; i++){
170         fwrite(&zero_byte, 1, 1, wav_writer_state.wav_file);
171         uint8_t byte_value = (uint8_t)data[i];
172         fwrite(&byte_value, 1, 1, wav_writer_state.wav_file);
173     }
174 
175     wav_writer_state.total_num_samples+=num_samples;
176     wav_writer_state.frame_count++;
177     return 0;
178 }
179 
180 int wav_writer_write_int16(int num_samples, int16_t * data){
181     if (data == NULL) return 1;
182     fwrite(data, num_samples, 2, wav_writer_state.wav_file);
183 
184     wav_writer_state.total_num_samples+=num_samples;
185     wav_writer_state.frame_count++;
186     return 0;
187 }
188 
189 int wav_reader_open(const char * filepath){
190     wav_reader_fd = open(filepath, O_RDONLY);
191     if (!wav_reader_fd) {
192         printf("Can't open file %s", filepath);
193         return 1;
194     }
195 
196     uint8_t buf[40];
197     __read(wav_reader_fd, buf, sizeof(buf));
198 
199     int num_channels = little_endian_read_16(buf, 22);
200     int block_align = little_endian_read_16(buf, 32);
201     bytes_per_sample = block_align/num_channels;
202     if (bytes_per_sample > 2){
203         bytes_per_sample = bytes_per_sample/8;
204     }
205     return 0;
206 }
207 
208 int wav_reader_close(void){
209     close(wav_reader_fd);
210     return 0;
211 }
212 
213 // Wav data: 8bit is uint8_t; 16bit is int16
214 int wav_reader_read_int8(int num_samples, int8_t * data){
215     if (!wav_reader_fd) return 1;
216     int i;
217     int bytes_read = 0;
218 
219     for (i=0; i<num_samples; i++){
220         if (bytes_per_sample == 2){
221             uint8_t buf[2];
222             bytes_read +=__read(wav_reader_fd, &buf, 2);
223             data[i] = buf[1];
224         } else {
225             uint8_t buf[1];
226             bytes_read +=__read(wav_reader_fd, &buf, 1);
227             data[i] = buf[0] + 128;
228         }
229     }
230     return bytes_read == num_samples*bytes_per_sample;
231 }
232 
233 int wav_reader_read_int16(int num_samples, int16_t * data){
234     if (!wav_reader_fd) return 1;
235     int i;
236     int bytes_read = 0;
237     for (i=0; i<num_samples; i++){
238         uint8_t buf[2];
239         bytes_read +=__read(wav_reader_fd, &buf, 2);
240         data[i] = little_endian_read_16(buf, 0);
241     }
242     return bytes_read == num_samples*bytes_per_sample;
243 }
244 
245 void wav_synthesize_sine_wave_int8(int num_samples, int8_t * data){
246     int i;
247     for (i=0; i<num_samples; i++){
248         data[i] = (int8_t)sine_uint8[phase];
249         phase++;
250         if (phase >= sizeof(sine_uint8)) phase = 0;
251     }
252 }
253 
254 void wav_synthesize_sine_wave_int16(int num_samples, int16_t * data){
255     int i;
256     for (i=0; i < num_samples; i++){
257         data[i] = sine_int16[phase++];
258         if (phase >= (sizeof(sine_int16) / sizeof(int16_t))){
259             phase = 0;
260         }
261     }
262 }
263 
264