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