mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-02-07 15:39:51 +00:00
test/lc3: add lc3 encoder and decoder tools
This commit is contained in:
parent
85068998a1
commit
3d88d85ad9
1
test/lc3/.gitignore
vendored
Normal file
1
test/lc3/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.wav
|
52
test/lc3/CMakeLists.txt
Normal file
52
test/lc3/CMakeLists.txt
Normal file
@ -0,0 +1,52 @@
|
||||
cmake_minimum_required (VERSION 3.12)
|
||||
project(BTstack-Test-LC3)
|
||||
set (CMAKE_CXX_STANDARD 11)
|
||||
|
||||
# find pkgconfig
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
# portaudio
|
||||
pkg_check_modules(PORTAUDIO portaudio-2.0)
|
||||
if(PORTAUDIO_FOUND)
|
||||
include_directories(${PORTAUDIO_INCLUDE_DIRS})
|
||||
link_directories(${PORTAUDIO_LIBRARY_DIRS})
|
||||
link_libraries(${PORTAUDIO_LIBRARIES})
|
||||
add_compile_definitions(HAVE_PORTAUDIO)
|
||||
endif()
|
||||
|
||||
# local dir for btstack_config.h after build dir to avoid using .h from Makefile
|
||||
include_directories(.)
|
||||
|
||||
include_directories(../../3rd-party/kissfft)
|
||||
include_directories(../../3rd-party/liblc3codec)
|
||||
include_directories(../../3rd-party/tinydir)
|
||||
include_directories(../../src)
|
||||
include_directories(../../platform/posix)
|
||||
|
||||
include_directories(../../3rd-party/liblc3codec/Api)
|
||||
include_directories(../../3rd-party/liblc3codec/Common)
|
||||
include_directories(../../3rd-party/liblc3codec/Common/KissFft)
|
||||
include_directories(../../3rd-party/liblc3codec/Common/Tables)
|
||||
include_directories(../../3rd-party/liblc3codec/TestSupport)
|
||||
|
||||
file(GLOB SOURCES_POSIX "../../platform/posix/*.c")
|
||||
file(GLOB SOURCES_SRC "../../src/*.c" "../../src/*.cpp")
|
||||
file(GLOB LC3_COMMON "../../3rd-party/liblc3codec/Common/*.cpp")
|
||||
file(GLOB LC3_TABLES "../../3rd-party/liblc3codec/Common/Tables/*.cpp")
|
||||
file(GLOB LC3_DECODER "../../3rd-party/liblc3codec/Decoder/*.cpp")
|
||||
file(GLOB LC3_ENCODER "../../3rd-party/liblc3codec/Encoder/*.cpp")
|
||||
|
||||
set (SOURCES_LC3 ${LC3_COMMON} ${LC3_TABLES} ${LC3_DECODER} ${LC3_ENCODER} ${LC3_TESTSUPPORT})
|
||||
|
||||
# Enable ASAN
|
||||
add_compile_options( -g -fsanitize=address)
|
||||
add_link_options( -fsanitize=address)
|
||||
|
||||
# create targets
|
||||
file(GLOB EXAMPLES "lc3_*.c")
|
||||
foreach(EXAMPLE_FILE ${EXAMPLES})
|
||||
get_filename_component(EXAMPLE ${EXAMPLE_FILE} NAME_WE)
|
||||
set (SOURCE_FILES ${SOURCES_POSIX} ${SOURCES_SRC} ${SOURCES_LC3} ${EXAMPLE_FILE})
|
||||
message("Tool: ${EXAMPLE}")
|
||||
add_executable(${EXAMPLE} ${SOURCE_FILES} )
|
||||
endforeach(EXAMPLE_FILE)
|
39
test/lc3/btstack_config.h
Normal file
39
test/lc3/btstack_config.h
Normal file
@ -0,0 +1,39 @@
|
||||
//
|
||||
// btstack_config.h for most tests
|
||||
//
|
||||
|
||||
#ifndef BTSTACK_CONFIG_H
|
||||
#define BTSTACK_CONFIG_H
|
||||
|
||||
// Port related features
|
||||
#define HAVE_BTSTACK_STDIN
|
||||
#define HAVE_MALLOC
|
||||
#define HAVE_POSIX_FILE_IO
|
||||
#define HAVE_POSIX_TIME
|
||||
#define HAVE_LC3_EHIMA
|
||||
|
||||
// BTstack features that can be enabled
|
||||
#define ENABLE_BLE
|
||||
#define ENABLE_CLASSIC
|
||||
#define ENABLE_GATT_CLIENT_PAIRING
|
||||
#define ENABLE_LOG_ERROR
|
||||
#define ENABLE_LOG_INFO
|
||||
#define ENABLE_PRINTF_HEXDUMP
|
||||
#define ENABLE_SDP_DES_DUMP
|
||||
#define ENABLE_SDP_EXTRA_QUERIES
|
||||
|
||||
// #define ENABLE_LE_SECURE_CONNECTIONS
|
||||
#define ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
|
||||
#define ENABLE_LE_CENTRAL
|
||||
#define ENABLE_LE_PERIPHERAL
|
||||
#define ENABLE_LE_SIGNED_WRITE
|
||||
#define ENABLE_SDP_EXTRA_QUERIES
|
||||
#define ENABLE_AVCTP_FRAGMENTATION
|
||||
|
||||
// BTstack configuration. buffers, sizes, ...
|
||||
#define HCI_ACL_PAYLOAD_SIZE 1024
|
||||
#define HCI_INCOMING_PRE_BUFFER_SIZE 6
|
||||
#define NVM_NUM_DEVICE_DB_ENTRIES 4
|
||||
#define NVM_NUM_LINK_KEYS 2
|
||||
|
||||
#endif
|
BIN
test/lc3/dump.lc3
Normal file
BIN
test/lc3/dump.lc3
Normal file
Binary file not shown.
226
test/lc3/lc3_decoder_ehima.c
Normal file
226
test/lc3/lc3_decoder_ehima.c
Normal file
@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright (C) 2022 BlueKitchen GmbH
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* 4. Any redistribution, use, or modification is done solely for
|
||||
* personal benefit and not for any commercial purpose or for
|
||||
* monetary gain.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
|
||||
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* Please inquire about commercial licensing options at
|
||||
* contact@bluekitchen-gmbh.com
|
||||
*
|
||||
*/
|
||||
|
||||
// *****************************************************************************
|
||||
//
|
||||
// LC3 decoder EHIMA
|
||||
//
|
||||
// *****************************************************************************
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "wav_util.h"
|
||||
#include "btstack_util.h"
|
||||
#include "btstack_debug.h"
|
||||
|
||||
#include "lc3.h"
|
||||
#include "lc3_ehima.h"
|
||||
|
||||
#define MAX_NUM_CHANNELS 2
|
||||
#define MAX_SAMPLES_PER_FRAME 480
|
||||
|
||||
static uint8_t read_buffer[200];
|
||||
|
||||
static uint32_t frame_count = 0;
|
||||
|
||||
static void show_usage(const char * path){
|
||||
printf("\n\nUsage: %s input_file.lc3 output_file.wav\n\n", path);
|
||||
}
|
||||
|
||||
static ssize_t __read(int fd, void *buf, size_t count){
|
||||
ssize_t len, pos = 0;
|
||||
while (count > 0) {
|
||||
len = read(fd, (int8_t * )buf + pos, count);
|
||||
if (len <= 0)
|
||||
return pos;
|
||||
|
||||
count -= len;
|
||||
pos += len;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
int main (int argc, const char * argv[]){
|
||||
if (argc < 3){
|
||||
show_usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char * lc3_filename = argv[1];
|
||||
const char * wav_filename = argv[2];
|
||||
|
||||
int fd = open(lc3_filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
printf("Can't open file %s", lc3_filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// read & parse header
|
||||
uint16_t min_header_size = 18;
|
||||
int bytes_read = __read(fd, read_buffer, min_header_size);
|
||||
if (bytes_read != min_header_size) return -10;
|
||||
uint16_t file_id = little_endian_read_16(read_buffer, 0);
|
||||
if (file_id != 0xcc1c) return -10;
|
||||
uint16_t header_size = little_endian_read_16(read_buffer, 2);
|
||||
if (header_size > 100) return -10;
|
||||
uint32_t sample_rate_hz = little_endian_read_16(read_buffer, 4) * 100;
|
||||
uint32_t bitrate = little_endian_read_16(read_buffer, 6) * 100;
|
||||
uint8_t num_channels = little_endian_read_16(read_buffer, 8);
|
||||
uint32_t frame_us = little_endian_read_16(read_buffer, 10) * 10;
|
||||
// offset 12: epmode
|
||||
// offset 14: signal_len
|
||||
// skip addittional fields
|
||||
if (header_size > min_header_size){
|
||||
__read(fd, read_buffer, header_size - min_header_size);
|
||||
}
|
||||
|
||||
if (num_channels > MAX_NUM_CHANNELS) {
|
||||
printf("Too much channels: %u\n", num_channels);
|
||||
return -10;
|
||||
}
|
||||
|
||||
// pick frame duration
|
||||
lc3_frame_duration_t duration2;
|
||||
switch (frame_us) {
|
||||
case 7500:
|
||||
duration2 = LC3_FRAME_DURATION_7500US;
|
||||
break;
|
||||
case 10000:
|
||||
duration2 = LC3_FRAME_DURATION_10000US;
|
||||
break;
|
||||
default:
|
||||
return -10;
|
||||
}
|
||||
|
||||
// init config
|
||||
|
||||
|
||||
// init decoder
|
||||
uint32_t bitrate_per_channel = bitrate / num_channels;
|
||||
uint8_t channel;
|
||||
lc3_decoder_ehima_t decoder_contexts[MAX_NUM_CHANNELS];
|
||||
const lc3_decoder_t * lc3_decoder;
|
||||
for (channel = 0 ; channel < num_channels ; channel++){
|
||||
lc3_decoder_ehima_t * decoder_context = &decoder_contexts[channel];
|
||||
lc3_decoder = lc3_decoder_ehima_init_instance(decoder_context);
|
||||
lc3_decoder->configure(decoder_context, sample_rate_hz, duration2);
|
||||
}
|
||||
uint16_t bytes_per_frame = lc3_decoder->get_number_octets_for_bitrate(&decoder_contexts[0], bitrate_per_channel);
|
||||
uint16_t number_samples_per_frame = lc3_decoder->get_number_samples_per_frame(&decoder_contexts[0]);
|
||||
|
||||
if (number_samples_per_frame > MAX_SAMPLES_PER_FRAME) {
|
||||
printf("number samples per frame %u too large\n", number_samples_per_frame);
|
||||
return -10;
|
||||
}
|
||||
|
||||
// print format
|
||||
printf("LC3 file: %s\n", lc3_filename);
|
||||
printf("WAC file: %s\n", wav_filename);
|
||||
printf("Samplerate: %u Hz\n", sample_rate_hz);
|
||||
printf("Channels: %u\n", num_channels);
|
||||
printf("Bitrate %u bps\n", bitrate);
|
||||
uint16_t frame_ms = frame_us / 1000;
|
||||
printf("Frame: %u.%u ms\n", frame_ms, frame_us - (frame_ms * 1000));
|
||||
|
||||
printf("Bytes per frame: %u\n", bytes_per_frame);
|
||||
printf("Samples per frame: %u\n", number_samples_per_frame);
|
||||
|
||||
// open wav writer
|
||||
wav_writer_open(wav_filename, num_channels, sample_rate_hz);
|
||||
|
||||
while (true){
|
||||
|
||||
bool done = false;
|
||||
int16_t pcm[MAX_NUM_CHANNELS * MAX_SAMPLES_PER_FRAME];
|
||||
|
||||
// get len of lc3 frames
|
||||
int bytes_read = __read(fd, read_buffer, 2);
|
||||
if (2 != bytes_read) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
uint16_t total_frame_len = little_endian_read_16(read_buffer, 0);
|
||||
if (total_frame_len != (bytes_per_frame * num_channels)){
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
for (channel = 0; channel < num_channels; channel++){
|
||||
|
||||
// get next lc3 frame (one channel)
|
||||
int bytes_read = __read(fd, read_buffer, bytes_per_frame);
|
||||
if (bytes_per_frame != bytes_read) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// process frame
|
||||
uint8_t tmp_BEC_detect;
|
||||
uint8_t BFI = 0;
|
||||
|
||||
uint8_t status = lc3_decoder->decode(&decoder_contexts[channel], read_buffer, bytes_per_frame, BFI, &pcm[channel * MAX_SAMPLES_PER_FRAME], number_samples_per_frame, &tmp_BEC_detect);
|
||||
if (status != ERROR_CODE_SUCCESS){
|
||||
printf("Error %u\n", status);
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (done) break;
|
||||
|
||||
uint16_t sample;
|
||||
int16_t wav_frame[MAX_NUM_CHANNELS];
|
||||
for (sample = 0 ; sample < number_samples_per_frame ; sample++){
|
||||
for (channel = 0; channel < num_channels; channel++) {
|
||||
wav_frame[channel] = pcm[channel * MAX_SAMPLES_PER_FRAME + sample];
|
||||
}
|
||||
wav_writer_write_int16(num_channels, wav_frame);
|
||||
}
|
||||
|
||||
frame_count++;
|
||||
}
|
||||
|
||||
wav_writer_close();
|
||||
close(fd);
|
||||
|
||||
printf("Wrote %d frames / %u samples\n\n", frame_count, frame_count * number_samples_per_frame);
|
||||
}
|
192
test/lc3/lc3_encoder_ehima.c
Normal file
192
test/lc3/lc3_encoder_ehima.c
Normal file
@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright (C) 2022 BlueKitchen GmbH
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* 4. Any redistribution, use, or modification is done solely for
|
||||
* personal benefit and not for any commercial purpose or for
|
||||
* monetary gain.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
|
||||
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* Please inquire about commercial licensing options at
|
||||
* contact@bluekitchen-gmbh.com
|
||||
*
|
||||
*/
|
||||
|
||||
// *****************************************************************************
|
||||
//
|
||||
// LC3 decoder EHIMA
|
||||
//
|
||||
// *****************************************************************************
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "wav_util.h"
|
||||
#include "btstack_util.h"
|
||||
#include "btstack_debug.h"
|
||||
|
||||
#include "lc3.h"
|
||||
#include "lc3_ehima.h"
|
||||
|
||||
#define MAX_NUM_CHANNELS 2
|
||||
#define MAX_SAMPLES_PER_FRAME 480
|
||||
|
||||
static uint8_t write_buffer[200];
|
||||
static int16_t samples_buffer[MAX_SAMPLES_PER_FRAME + MAX_NUM_CHANNELS];
|
||||
static int16_t frame_buffer[MAX_SAMPLES_PER_FRAME];
|
||||
|
||||
static uint32_t frame_count = 0;
|
||||
|
||||
static void show_usage(const char * path){
|
||||
printf("Usage: %s input.wav output.lc3 frame_duration_ms octets_per_frame\n", path);
|
||||
printf("- frame_duration_ms: 7.5 or 10\n");
|
||||
printf("- octects_per_frame: 26..155\n");
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
int main (int argc, const char * argv[]){
|
||||
if (argc < 4){
|
||||
show_usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t argv_pos = 1;
|
||||
const char * wav_filename = argv[argv_pos++];
|
||||
const char * lc3_filename = argv[argv_pos++];
|
||||
|
||||
lc3_frame_duration_t frame_duration;
|
||||
if (strcmp(argv[argv_pos], "10") == 0){
|
||||
frame_duration = LC3_FRAME_DURATION_10000US;
|
||||
} else if (strcmp(argv[argv_pos], "7.5") == 0){
|
||||
frame_duration = LC3_FRAME_DURATION_7500US;
|
||||
} else {
|
||||
printf("Invalid frame duration %s, must be either 7.5 or 10\n", argv[2]);
|
||||
return -10;
|
||||
}
|
||||
argv_pos++;
|
||||
|
||||
uint16_t bytes_per_frame = atoi(argv[argv_pos++]);
|
||||
if ((bytes_per_frame < 26) || (bytes_per_frame > 155)){
|
||||
printf("Octets per Frame %u out of range [26..155]\n", bytes_per_frame);
|
||||
return -10;
|
||||
}
|
||||
|
||||
int status = wav_reader_open(wav_filename);
|
||||
if (status != 0){
|
||||
printf("Could not open wav file %s\n", wav_filename);
|
||||
return -10;
|
||||
}
|
||||
|
||||
// get wav config
|
||||
uint32_t sampling_frequency_hz = wav_reader_get_sampling_rate();
|
||||
uint8_t num_channels = wav_reader_get_num_channels();
|
||||
|
||||
// init decoder
|
||||
uint8_t channel;
|
||||
lc3_encoder_ehima_t encoder_contexts[MAX_NUM_CHANNELS];
|
||||
const lc3_encoder_t * lc3_encoder;
|
||||
for (channel = 0 ; channel < num_channels ; channel++){
|
||||
lc3_encoder_ehima_t * encoder_context = &encoder_contexts[channel];
|
||||
lc3_encoder = lc3_encoder_ehima_init_instance(encoder_context);
|
||||
lc3_encoder->configure(encoder_context, sampling_frequency_hz, frame_duration);
|
||||
}
|
||||
uint32_t bitrate_per_channel = lc3_encoder->get_bitrate_for_number_of_octets(&encoder_contexts[0], bytes_per_frame);
|
||||
uint32_t bitrate = bitrate_per_channel * num_channels;
|
||||
uint16_t number_samples_per_frame = lc3_encoder->get_number_samples_per_frame(&encoder_contexts[0]);
|
||||
|
||||
if (number_samples_per_frame > MAX_SAMPLES_PER_FRAME) return -10;
|
||||
|
||||
// create lc3 file and write header for floating point implementation
|
||||
FILE * lc3_file = fopen(lc3_filename, "wb");
|
||||
if (!lc3_file) return 1;
|
||||
|
||||
uint16_t frame_duration_100us = (frame_duration == LC3_FRAME_DURATION_10000US) ? 100 : 75;
|
||||
|
||||
uint8_t header[18];
|
||||
little_endian_store_16(header, 0, 0xcc1c);
|
||||
little_endian_store_16(header, 2, sizeof(header));
|
||||
little_endian_store_16(header, 4, sampling_frequency_hz / 100);
|
||||
little_endian_store_16(header, 6, bitrate / 100);
|
||||
little_endian_store_16(header, 8, num_channels);
|
||||
little_endian_store_16(header, 10, frame_duration_100us * 10);
|
||||
little_endian_store_16(header, 12, 0);
|
||||
little_endian_store_32(header, 14, 0); // num samples need to set later
|
||||
fwrite(header, 1, sizeof(header), lc3_file);
|
||||
|
||||
// print format
|
||||
printf("WAC file: %s\n", wav_filename);
|
||||
printf("LC3 file: %s\n", lc3_filename);
|
||||
printf("Samplerate: %u Hz\n", sampling_frequency_hz);
|
||||
printf("Channels: %u\n", num_channels);
|
||||
printf("Frame duration: %s ms\n", (frame_duration == LC3_FRAME_DURATION_10000US) ? "10" : "7.5");
|
||||
printf("Bitrate: %u\n", bitrate);
|
||||
printf("Samples per Frame: %u\n", number_samples_per_frame);
|
||||
|
||||
while (true){
|
||||
// process file frame by frame
|
||||
memset(samples_buffer, 0, sizeof(samples_buffer));
|
||||
// read samples per frame * num channels
|
||||
status = wav_reader_read_int16(number_samples_per_frame * num_channels, samples_buffer);
|
||||
|
||||
if (status != 0) break;
|
||||
|
||||
// write len of complete frame
|
||||
uint8_t len[2];
|
||||
little_endian_store_16(len, 0, num_channels * bytes_per_frame);
|
||||
fwrite(len, 1, sizeof(len), lc3_file);
|
||||
|
||||
// encode frame by frame
|
||||
for (channel = 0; channel < num_channels ; channel++){
|
||||
uint16_t sample;
|
||||
for (sample = 0 ; sample < number_samples_per_frame ; sample++){
|
||||
frame_buffer[sample] = samples_buffer[ sample * num_channels + channel];
|
||||
}
|
||||
status = lc3_encoder->encode(&encoder_contexts[channel], frame_buffer, write_buffer, bytes_per_frame);
|
||||
if (status != ERROR_CODE_SUCCESS){
|
||||
printf("Error %u\n", status);
|
||||
break;
|
||||
}
|
||||
fwrite(write_buffer, 1, bytes_per_frame, lc3_file);
|
||||
}
|
||||
|
||||
if (status != 0) break;
|
||||
|
||||
frame_count++;
|
||||
}
|
||||
|
||||
uint32_t total_samples = frame_count * number_samples_per_frame;
|
||||
printf("Total samples: %u\n", total_samples);
|
||||
|
||||
// rewind and store num samples
|
||||
little_endian_store_32(header, 14, total_samples); // num samples need to set later
|
||||
rewind(lc3_file);
|
||||
fwrite(header, 1, sizeof(header), lc3_file);
|
||||
fclose(lc3_file);
|
||||
}
|
BIN
test/lc3/sine-mono-8k.lc3
Normal file
BIN
test/lc3/sine-mono-8k.lc3
Normal file
Binary file not shown.
BIN
test/lc3/sine-stereo-8k.lc3
Normal file
BIN
test/lc3/sine-stereo-8k.lc3
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user