1 /*
2 * Copyright (C) 2022 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 // *****************************************************************************
39 //
40 // LC3 decoder EHIMA
41 //
42 // *****************************************************************************
43
44 #include <stdint.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <fcntl.h>
49 #include <unistd.h>
50
51 #include "wav_util.h"
52 #include "btstack_util.h"
53 #include "btstack_debug.h"
54
55 #include "btstack_lc3.h"
56 #include "btstack_lc3_google.h"
57
58 #define MAX_NUM_CHANNELS 2
59 #define MAX_SAMPLES_PER_FRAME 480
60
61 static uint8_t write_buffer[200];
62 static int16_t samples_buffer[MAX_SAMPLES_PER_FRAME + MAX_NUM_CHANNELS];
63
64 static uint32_t frame_count = 0;
65
show_usage(const char * path)66 static void show_usage(const char * path){
67 printf("Usage: %s input.wav output.lc3 frame_duration_ms octets_per_frame\n", path);
68 printf("- frame_duration_ms: 7.5 or 10\n");
69 printf("- octects_per_frame: 26..155\n");
70 printf("\n\n");
71 }
72
main(int argc,const char * argv[])73 int main (int argc, const char * argv[]){
74 if (argc < 4){
75 show_usage(argv[0]);
76 return -1;
77 }
78
79 uint8_t argv_pos = 1;
80 const char * wav_filename = argv[argv_pos++];
81 const char * lc3_filename = argv[argv_pos++];
82
83 btstack_lc3_frame_duration_t frame_duration;
84 if (strcmp(argv[argv_pos], "10") == 0){
85 frame_duration = BTSTACK_LC3_FRAME_DURATION_10000US;
86 } else if (strcmp(argv[argv_pos], "7.5") == 0){
87 frame_duration = BTSTACK_LC3_FRAME_DURATION_7500US;
88 } else {
89 printf("Invalid frame duration %s, must be either 7.5 or 10\n", argv[2]);
90 return -10;
91 }
92 argv_pos++;
93
94 uint16_t bytes_per_frame = atoi(argv[argv_pos++]);
95 if ((bytes_per_frame < 26) || (bytes_per_frame > 155)){
96 printf("Octets per Frame %u out of range [26..155]\n", bytes_per_frame);
97 return -10;
98 }
99
100 int status = wav_reader_open(wav_filename);
101 if (status != 0){
102 printf("Could not open wav file %s\n", wav_filename);
103 return -10;
104 }
105
106 // get wav config
107 uint32_t sampling_frequency_hz = wav_reader_get_sampling_rate();
108 uint8_t num_channels = wav_reader_get_num_channels();
109 uint16_t number_samples_per_frame = btstack_lc3_samples_per_frame(sampling_frequency_hz, frame_duration);
110
111 // init decoder
112 uint8_t channel;
113 btstack_lc3_encoder_google_t encoder_contexts[MAX_NUM_CHANNELS];
114 const btstack_lc3_encoder_t * lc3_encoder;
115 for (channel = 0 ; channel < num_channels ; channel++){
116 btstack_lc3_encoder_google_t * encoder_context = &encoder_contexts[channel];
117 lc3_encoder = btstack_lc3_encoder_google_init_instance(encoder_context);
118 lc3_encoder->configure(encoder_context, sampling_frequency_hz, frame_duration, number_samples_per_frame);
119 }
120
121 if (number_samples_per_frame > MAX_SAMPLES_PER_FRAME) return -10;
122
123 // calc bitrate from num octets
124 uint32_t bitrate_per_channel = ((uint32_t) bytes_per_frame * 80000) / (btstack_lc3_frame_duration_in_us(frame_duration) / 100);
125 // fix bitrate for 8_1
126 if ((sampling_frequency_hz == 8000) && (frame_duration == BTSTACK_LC3_FRAME_DURATION_7500US)) {
127 bitrate_per_channel = 27734;
128 }
129 // fix bitrate for 441_1 and 441_2
130 if (sampling_frequency_hz == 44100){
131 switch(frame_duration){
132 case BTSTACK_LC3_FRAME_DURATION_7500US:
133 bitrate_per_channel = 95060;
134 break;
135 case BTSTACK_LC3_FRAME_DURATION_10000US:
136 bitrate_per_channel = 95500;
137 break;
138 default:
139 btstack_unreachable();
140 break;
141 }
142 }
143 uint32_t bitrate = bitrate_per_channel * num_channels;
144
145 // create lc3 file and write header for floating point implementation
146 FILE * lc3_file = fopen(lc3_filename, "wb");
147 if (!lc3_file) return 1;
148
149 uint16_t frame_duration_100us = (frame_duration == BTSTACK_LC3_FRAME_DURATION_10000US) ? 100 : 75;
150
151 uint8_t header[18];
152 little_endian_store_16(header, 0, 0xcc1c);
153 little_endian_store_16(header, 2, sizeof(header));
154 little_endian_store_16(header, 4, sampling_frequency_hz / 100);
155 little_endian_store_16(header, 6, bitrate / 100);
156 little_endian_store_16(header, 8, num_channels);
157 little_endian_store_16(header, 10, frame_duration_100us * 10);
158 little_endian_store_16(header, 12, 0);
159 little_endian_store_32(header, 14, 0); // num samples need to set later
160 fwrite(header, 1, sizeof(header), lc3_file);
161
162 // print format
163 printf("WAC file: %s\n", wav_filename);
164 printf("LC3 file: %s\n", lc3_filename);
165 printf("Samplerate: %u Hz\n", sampling_frequency_hz);
166 printf("Channels: %u\n", num_channels);
167 printf("Frame duration: %s ms\n", (frame_duration == BTSTACK_LC3_FRAME_DURATION_10000US) ? "10" : "7.5");
168 printf("Bitrate: %u\n", bitrate);
169 printf("Samples per Frame: %u\n", number_samples_per_frame);
170
171 while (true){
172 // process file frame by frame
173 memset(samples_buffer, 0, sizeof(samples_buffer));
174 // read samples per frame * num channels
175 status = wav_reader_read_int16(number_samples_per_frame * num_channels, samples_buffer);
176
177 if (status != 0) break;
178
179 // write len of complete frame
180 uint8_t len[2];
181 little_endian_store_16(len, 0, num_channels * bytes_per_frame);
182 fwrite(len, 1, sizeof(len), lc3_file);
183
184 // encode frame by frame
185 for (channel = 0; channel < num_channels ; channel++){
186 status = lc3_encoder->encode_signed_16(&encoder_contexts[channel], &samples_buffer[channel], num_channels, write_buffer);
187 if (status != ERROR_CODE_SUCCESS){
188 printf("Error %u\n", status);
189 break;
190 }
191 fwrite(write_buffer, 1, bytes_per_frame, lc3_file);
192 }
193
194 if (status != 0) break;
195
196 frame_count++;
197 }
198
199 uint32_t total_samples = frame_count * number_samples_per_frame;
200 printf("Total samples: %u\n", total_samples);
201
202 // rewind and store num samples
203 little_endian_store_32(header, 14, total_samples); // num samples need to set later
204 rewind(lc3_file);
205 fwrite(header, 1, sizeof(header), lc3_file);
206 fclose(lc3_file);
207 }
208