Merge branch 'master' into dr-mag

pull/8/head^2
drowe67 2019-07-27 11:20:56 +09:30 committed by GitHub
commit 55f1db3113
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 457 additions and 126 deletions

34
.travis.yml 100644
View File

@ -0,0 +1,34 @@
sudo: required
language: generic
dist: xenial
addons:
apt:
packages:
libc6-i386
libspeexdsp-dev
libsamplerate0-dev
sox
git
install:
- export CODEC2DIR=${PWD}/codec2
- export LPCNETDIR=${PWD}
- export BUILDDIR=${PWD}/build_linux
script:
# First build and install vanilla codec2 as we need -lcodec2 to build LPCNet
- git clone https://github.com/drowe67/codec2.git
- cd codec2
- mkdir build_linux && cd build_linux && cmake .. && make VERBOSE=1 codec2
# OK, build and test LPCNet
- cd $LPCNETDIR && mkdir -p $BUILDDIR && cd $BUILDDIR
- cmake -DCODEC2_BUILD_DIR=$CODEC2DIR/build_linux .. && make VERBOSE=1
- cd src && sox ../../wav/wia.wav -t raw -r 16000 - | ./lpcnet_enc -s | ./lpcnet_dec -s > /dev/null
# Re-build codec2 with LPCNet and test FreeDV 2020 support
- cd $CODEC2DIR/build_linux
- make clean
- cmake -DLPCNET_BUILD_DIR=$BUILDDIR ..
- make VERBOSE=1
- cd src
- ./freedv_tx 2020 $LPCNETDIR/wav/wia.wav - | ./freedv_rx 2020 - /dev/null

View File

@ -5,28 +5,69 @@
cmake_minimum_required(VERSION 3.0)
project(LPCNet C)
set(CMAKE_C_FLAGS "-Wall -W -Wextra -Wno-unused-function -O3 -g -I. -MD ${CMAKE_C_FLAGS}")
option(AVX2 "Enable AVX2 CPU optimizations." OFF)
option(AVX "Enable AVX CPU optimizations." OFF)
option(NEON "Enable NEON CPU optimizations for RPi." OFF)
execute_process(COMMAND grep -c "avx2" /proc/cpuinfo
OUTPUT_VARIABLE AVX2)
execute_process(COMMAND grep -c "avx " /proc/cpuinfo
OUTPUT_VARIABLE AVX)
execute_process(COMMAND grep -c "neon" /proc/cpuinfo
OUTPUT_VARIABLE NEON)
message("AVX2: ${AVX2} AVX: ${AVX} NEON: ${NEON}")
include(GNUInstallDirs)
mark_as_advanced(CLEAR
CMAKE_INSTALL_BINDIR
CMAKE_INSTALL_INCLUDEDIR
CMAKE_INSTALL_LIBDIR
)
if(${AVX2} GREATER 0)
message(STATUS "avx2 processor flags found.")
#
# Prevent in-source builds
# If an in-source build is attempted, you will still need to clean up a few
# files manually.
#
set(CMAKE_DISABLE_SOURCE_CHANGES ON)
set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
message(FATAL_ERROR "In-source builds in ${CMAKE_BINARY_DIR} are not "
"allowed, please remove ./CMakeCache.txt and ./CMakeFiles/, create a "
"separate build directory and run cmake from there.")
endif("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
# Set default flags
set(CMAKE_C_FLAGS "-Wall -W -Wextra -Wno-unused-function -O3 -g -I. -MD ${CMAKE_C_FLAGS} -DENABLE_ASSERTIONS")
# Detection of available CPU optimizations
if(UNIX AND NOT APPLE)
message(STATUS "Looking for available CPU optimizations on Linux/BSD system...")
execute_process(COMMAND grep -c "avx2" /proc/cpuinfo
OUTPUT_VARIABLE AVX2)
execute_process(COMMAND grep -c "avx " /proc/cpuinfo
OUTPUT_VARIABLE AVX)
execute_process(COMMAND grep -c "neon" /proc/cpuinfo
OUTPUT_VARIABLE NEON)
elseif(APPLE)
# Under OSX we need to look through a few sysctl entries to determine what our CPU supports.
message(STATUS "Looking for available CPU optimizations on an OSX system...")
execute_process(COMMAND sysctl -a COMMAND grep machdep.cpu.leaf7_features COMMAND grep -c AVX2
OUTPUT_VARIABLE AVX2)
execute_process(COMMAND sysctl -a COMMAND grep machdep.cpu.features COMMAND grep -c AVX
OUTPUT_VARIABLE AVX)
elseif(WIN32)
message(STATUS "No detection capability on Windows, assuming AVX is available.")
set(AVX TRUE)
else()
message(STATUS "System is not *nix, processor specific optimizations cannot be determined.")
message(" You can try setting them manually, e.g.: -DAVX2=1 or -DAVX=1 or -DNEON=1")
endif()
if(${AVX2} OR ${AVX2} GREATER 0)
message(STATUS "avx2 processor flags found or enabled.")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mavx2 -mfma")
elseif(${AVX} GREATER 0)
elseif(${AVX} OR ${AVX} GREATER 0)
# AVX2 machines will also match on AVX
message(STATUS "avx processor flags found.")
message(STATUS "avx processor flags found or enabled.")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mavx")
endif()
# RPi
if(${NEON} GREATER 0)
message(STATUS "neon processor flags found.")
if(${NEON} OR ${NEON} GREATER 0)
message(STATUS "neon processor flags found or enabled.")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon -march=armv8-a -mtune=cortex-a53")
endif()
@ -57,5 +98,18 @@ else()
endif()
endif()
add_subdirectory(src)
# Find codec2
if(CODEC2_BUILD_DIR)
find_package(codec2 REQUIRED
PATHS ${CODEC2_BUILD_DIR}
NO_DEFAULT_PATH
CONFIGS codec2.cmake
)
if(codec2_FOUND)
message(STATUS "Codec2 library found in build tree.")
endif()
else()
find_package(codec2 REQUIRED)
endif()
add_subdirectory(src)

View File

@ -18,19 +18,45 @@ set(lpcnet_freedv_srcs
${lpcnet_SOURCE_DIR}/nnet_data.c
)
add_library(lpcnetfreedv STATIC ${lpcnet_freedv_srcs})
add_library(lpcnetfreedv SHARED ${lpcnet_freedv_srcs})
target_link_libraries(lpcnetfreedv codec2)
set_target_properties(lpcnetfreedv PROPERTIES
PUBLIC_HEADER lpcnet_freedv.h
)
target_include_directories(lpcnetfreedv INTERFACE
$<INSTALL_INTERFACE:include/lpcnet>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
)
install(TARGETS lpcnetfreedv EXPORT lpcnet-config
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/lpcnet
)
install(EXPORT lpcnet-config
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/lpcnet
)
# Export libfreedv target for import into codec2 from build tree.
export(TARGETS lpcnetfreedv
FILE ${CMAKE_BINARY_DIR}/lpcnetfreedv.cmake
)
add_executable(dump_data dump_data.c)
target_link_libraries(dump_data lpcnetfreedv m codec2)
add_executable(test_lpcnet test_lpcnet.c)
target_link_libraries(test_lpcnet lpcnetfreedv m)
target_link_libraries(test_lpcnet lpcnetfreedv m codec2)
add_executable(test_vec test_vec.c)
target_link_libraries(test_vec m)
if(AVX OR AVX2)
add_executable(test_vec test_vec.c)
target_link_libraries(test_vec m)
else()
message(WARNING "No AVX/AVX2 CPU flags identified, not building test_vec.")
endif()
add_executable(quant_feat quant_feat.c)
target_link_libraries(quant_feat lpcnetfreedv m)
target_link_libraries(quant_feat lpcnetfreedv m codec2)
add_executable(tcodec2_pitch tcodec2_pitch.c codec2_pitch.c)
target_link_libraries(tcodec2_pitch m codec2)
@ -42,7 +68,7 @@ add_executable(tdump tdump.c)
target_link_libraries(tdump lpcnetfreedv m codec2)
add_executable(quant_test quant_test.c)
target_link_libraries(quant_test lpcnetfreedv m)
target_link_libraries(quant_test lpcnetfreedv m codec2)
add_executable(quant2c quant2c.c)
target_link_libraries(quant2c m)
@ -51,10 +77,10 @@ add_executable(diff32 diff32.c)
target_link_libraries(diff32 m)
add_executable(quant_enc quant_enc.c)
target_link_libraries(quant_enc lpcnetfreedv m)
target_link_libraries(quant_enc lpcnetfreedv m codec2)
add_executable(quant_dec quant_dec.c)
target_link_libraries(quant_dec lpcnetfreedv m)
target_link_libraries(quant_dec lpcnetfreedv m codec2)
add_executable(lpcnet_enc lpcnet_enc.c)
target_link_libraries(lpcnet_enc lpcnetfreedv m codec2)
@ -63,4 +89,8 @@ add_executable(lpcnet_dec lpcnet_dec.c)
target_link_libraries(lpcnet_dec lpcnetfreedv m codec2)
add_executable(idct idct.c)
target_link_libraries(idct lpcnetfreedv m)
target_link_libraries(idct lpcnetfreedv m codec2)
install(TARGETS lpcnet_enc lpcnet_dec
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

View File

@ -56,8 +56,8 @@ static RNN_INLINE int lin2ulaw(float x)
}
/** RNNoise wrapper for malloc(). To do your own dynamic allocation, all you need t
o do is replace this function and rnnoise_free */
/** RNNoise wrapper for malloc(). To do your own dynamic allocation,
all you need to do is replace this function and rnnoise_free */
#ifndef OVERRIDE_RNNOISE_ALLOC
static RNN_INLINE void *rnnoise_alloc (size_t size)
{

View File

@ -1,3 +1,6 @@
/* test tool to diffs two .f32 files */
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
@ -5,23 +8,31 @@
#define NB_FEATURES 55
int main(int argc, char *argv[]) {
float f1[NB_FEATURES],f2[NB_FEATURES],fdiff=0.0;
int ret,f=0,i;
float fdiff, fdiff_tot=0.0;
int f=0;
unsigned int ret, i, stride = NB_FEATURES;
FILE *file1 = fopen(argv[1],"rb");
assert(file1 != NULL);
FILE *file2 = fopen(argv[2],"rb");
while(fread(&f1,sizeof(float),NB_FEATURES,file1) == NB_FEATURES) {
ret = fread(&f2,sizeof(float),NB_FEATURES,file2);
if (ret != NB_FEATURES) break;
for(i=0; i<NB_FEATURES; i++) {
fdiff += fabs(f1[i]-f2[i]);
if (isnan(fdiff) || (fdiff > 1E-6)) {
assert(file2 != NULL);
if (argc == 4) {
stride = atoi(argv[3]);
}
float f1[stride],f2[stride];
while(fread(&f1,sizeof(float),stride,file1) == stride) {
ret = fread(&f2,sizeof(float),stride,file2);
if (ret != stride) break;
for(i=0; i<stride; i++) {
fdiff = fabs(f1[i]-f2[i]);
fdiff_tot += fdiff;
if (isnan(fdiff) || (fdiff > 1E-3)) {
printf("f: %d i: %d %f %f %f\n", f, i, f1[i], f2[i], fdiff);
exit(0);
}
}
f++;
}
fprintf(stderr,"f: %d fdiff: %f\n", f, fdiff);
fprintf(stderr,"stride: %d f: %d fdiff_tot: %f\n", stride, f, fdiff_tot);
fclose(file1); fclose(file2);
}

View File

@ -418,7 +418,7 @@ int main(int argc, char **argv) {
if (strcmp(argv[dx], "-") == 0)
f1 = stdin;
else {
f1 = fopen(argv[dx], "r");
f1 = fopen(argv[dx], "rb");
if (f1 == NULL) {
fprintf(stderr,"Error opening input .s16 16kHz speech input file: %s\n", argv[dx]);
exit(1);
@ -427,14 +427,14 @@ int main(int argc, char **argv) {
if (strcmp(argv[dx+1], "-") == 0)
ffeat = stdout;
else {
ffeat = fopen(argv[dx+1], "w");
ffeat = fopen(argv[dx+1], "wb");
if (ffeat == NULL) {
fprintf(stderr,"Error opening output feature file: %s\n", argv[dx+1]);
exit(1);
}
}
if (training) {
fpcm = fopen(argv[dx+2], "w");
fpcm = fopen(argv[dx+2], "wb");
if (fpcm == NULL) {
fprintf(stderr,"Error opening output PCM file: %s\n", argv[dx+2]);
exit(1);
@ -517,6 +517,11 @@ int main(int argc, char **argv) {
c2_Sn[i+c2_Sn_size-c2_frame_size] = x[i];
float f0, voicing, snr; int pitch_index;
pitch_index = codec2_pitch_est(c2pitch, c2_Sn, &f0, &voicing, &snr);
if (pitch_index >= 2*PITCH_MAX_PERIOD) pitch_index = 2*PITCH_MAX_PERIOD-1;
if (pitch_index < 2*PITCH_MIN_PERIOD) pitch_index = 2*PITCH_MIN_PERIOD;
assert(pitch_index < 2*PITCH_MAX_PERIOD);
assert(pitch_index >= 2*PITCH_MIN_PERIOD);
features[2*NB_BANDS] = 0.01*(pitch_index-200);
if (c2voicing_en) features[2*NB_BANDS+1] = voicing;
//int pitch_index_lpcnet = 100*features[2*NB_BANDS] + 200;

View File

@ -28,8 +28,8 @@ float std[] = {
int main(int argc, char *argv[]) {
FILE *fin, *fout;
fin = stdin; fout = stdout;
uint ret;
uint stride = NB_BANDS;
unsigned int ret;
unsigned int stride = NB_BANDS;
int measure = 0;
int scaling = 0;
@ -63,7 +63,7 @@ int main(int argc, char *argv[]) {
float sum[NB_BANDS] = {0.0};
float sumsq[NB_BANDS] = {0.0};
float dctLy[stride], Ly[stride];
uint i; for(i=0; i<stride; i++) Ly[stride] = 0.0;
unsigned int i; for(i=0; i<stride; i++) Ly[stride] = 0.0;
long n = 0;
while(fread(dctLy, sizeof(float), stride, fin) == stride) {
idct(Ly, dctLy);

View File

@ -0,0 +1,93 @@
% linux_v_windows.m
% David Rowe May 2019
%
% Part of system to generate and compare Linux and Windows test files
% that contain LPCNet states. Use to track down issue with Windows version
%
% Run in Octave from LPCNet/src
1;
function [vec1 vec2] = check_vec(fig_num, name, vec1, vec2)
# vector may be supplied as matrix that we need to reshape, e.g. for excitation signal
[rows cols] = size(vec1);
if cols != 1
vec1 = reshape(vec1', 1, rows*cols);
vec2= reshape(vec2', 1, rows*cols);
end
figure(fig_num); clf;
plot(vec1); hold on; plot(vec2); hold off;
title(name);
diff = max(vec1-vec2);
if diff < 1E-3
printf("%s [PASS]\n", name);
else
printf("%s [FAIL]\n", name);
end
endfunction
function check_matrix(fig_num, name, mat1, mat2)
figure(fig_num); clf;
[r c] = size(mat1);
plotr=min(r,100);
plotc=min(c,100);
mesh(mat1(1:plotr,1:plotc)); hold on; mesh(mat2(1:plotr,1:plotc)); hold off;
title(name);
mdiff = mat1-mat2; diff = max(mdiff(:));
if diff < 1E-3
printf("%s [PASS]\n", name);
else
printf("%s [FAIL]\n", name);
% find first row where problem occurs
[rows cols]= size(mat1);
first_error = 1; nerr = 0;
for r=1:rows
e = mat1(r,:) - mat2(r,:);
if max(e) > 1E-3 && nerr < 3
nerr++;
[mx col] = max(e);
printf("max error %f in row: %d col: %d\n", max(e), r, col);
if (first_error)
clf; plot(mat1(r,:),'g'); hold on; plot(mat2(r,:),'b'); plot(mat1(r,:) - mat2(r,:),'r'); hold off;
first_error = 0;
mat1(r,1:10)
mat2(r,1:10)
end
end
end
end
endfunction
n_pitch_embed = 64;
n_pitch = 1;
n_pitch_gain = 1;
n_lpc = 16;
n_condition = 128;
n_gru_a = 1152;
n_last_sig = 160;
n_pred = 160;
n_exc = 160;
n_pcm = 160;
n_cols = n_pitch_embed + n_pitch + n_pitch_gain + n_lpc + n_condition + n_gru_a + n_last_sig + n_pred + n_exc + n_pcm;
linux=load_f32("../build_linux/src/test_lpcnet_statesq.f32", n_cols);
[r c]=size(linux);
printf("linux %d x %d\n", r, c);
windows=load_f32("../build_win/src/test_lpcnet_statesq.f32", n_cols);
[r c]=size(windows);
printf("windows %d x %d\n", r, c);
fig = 1;
st = 1;
en = st + n_pitch_embed-1; check_matrix(fig++, "pitch_embed", linux(:,st:en), windows(:,st:en)); st += n_pitch_embed;
check_vec(fig++, "pitch", linux(:,st), windows(:,st)); st += n_pitch;
check_vec(fig++, "pitch_gain", linux(:,st), windows(:,st)); st += n_pitch_gain;
en = st + n_lpc-1; check_matrix(fig++, "lpc", linux(:,st:en), windows(:,st:en)); st += n_lpc;
en = st + n_condition-1; check_matrix(fig++, "condition", linux(:,st:en), windows(:,st:en)); st += n_condition;
en = st + n_gru_a-1; check_matrix(fig++, "gru a", linux(:,st:en), windows(:,st:en)); st += n_gru_a;
en = st + n_last_sig-1; last_sig = check_vec(fig++, "last_sig", linux(:,st:en), windows(:,st:en)); st += n_last_sig;
en = st + n_pred-1; pred = check_vec(fig++, "pred", linux(:,st:en), windows(:,st:en)); st += n_pred;
en = st + n_exc-1; exc = check_vec(fig++, "exc", linux(:,st:en), windows(:,st:en)); st += n_exc;
en = st + n_pcm-1; pcm = check_vec(fig++, "pcm", linux(:,st:en), windows(:,st:en)); st += n_pcm;

View File

@ -0,0 +1,30 @@
#!/bin/bash
# linux_v_windows.sh
# David Rowe May 2019
#
# Part of system to generate and compare Linux and Windows test files
# that contain LPCNet states. Use to track down issue with Windows version
export WINEPATH=$HOME/freedv-gui/codec2/build_win/src';'$HOME/freedv-gui/build_win/_CPack_Packages/win64/NSIS/FreeDV-1.4.0-devel-win64/bin/
w=all
# start in LPCNet dir
p=$PWD
# Windows
cd build_win/src && make tdump test_lpcnet lpcnet_enc lpcnet_dec
wine lpcnet_enc.exe -s --infile ../../wav/$w.wav --outfile $w.bin
wine lpcnet_dec.exe -s --infile $w.bin --outfile $w'q_out.raw'
#wine tdump.exe ../../wav/$w.wav $w.f32
#wine test_lpcnet.exe $w.f32 $w'_out.raw'
cd $p
# Linux
cd build_linux/src && make test_lpcnet lpcnet_enc lpcnet_dec diff32
./lpcnet_dec -s --infile ../../build_win/src/$w.bin --outfile $w'q_out'.raw
#./test_lpcnet ../../build_win/src/$w.f32 $w'_out.raw'
./diff32 test_lpcnet_statesq.f32 ../../build_win/src/test_lpcnet_statesq.f32 1842
cd $p

View File

@ -54,6 +54,7 @@ struct LPCNetState {
float old_gain[FEATURES_DELAY];
int frame_count;
float deemph_mem;
FILE *ftest; /* used to dump states for automates tests */
};
@ -73,13 +74,14 @@ void run_frame_network(LPCNetState *lpcnet, float *condition, float *gru_a_condi
float conv1_out[FEATURE_CONV1_OUT_SIZE];
float conv2_out[FEATURE_CONV2_OUT_SIZE];
float dense1_out[FEATURE_DENSE1_OUT_SIZE];
net = &lpcnet->nnet;
RNN_COPY(in, features, NB_FEATURES);
compute_embedding(&embed_pitch, &in[NB_FEATURES], pitch);
celt_assert(FRAME_INPUT_SIZE == feature_conv1.nb_inputs);
compute_conv1d(&feature_conv1, conv1_out, net->feature_conv1_state, in);
if (lpcnet->frame_count < FEATURE_CONV1_DELAY) RNN_CLEAR(conv1_out, FEATURE_CONV1_OUT_SIZE);
compute_conv1d(&feature_conv2, conv2_out, net->feature_conv2_state, conv1_out);
celt_assert(FRAME_INPUT_SIZE == FEATURE_CONV2_OUT_SIZE);
if (lpcnet->frame_count < FEATURES_DELAY) RNN_CLEAR(conv2_out, FEATURE_CONV2_OUT_SIZE);
memmove(lpcnet->old_input[1], lpcnet->old_input[0], (FEATURES_DELAY-1)*FRAME_INPUT_SIZE*sizeof(in[0]));
memcpy(lpcnet->old_input[0], in, FRAME_INPUT_SIZE*sizeof(in[0]));
@ -87,6 +89,10 @@ void run_frame_network(LPCNetState *lpcnet, float *condition, float *gru_a_condi
compute_dense(&feature_dense2, condition, dense1_out);
compute_dense(&gru_a_dense_feature, gru_a_condition, condition);
if (lpcnet->frame_count < 1000) lpcnet->frame_count++;
if (lpcnet->ftest) {
fwrite(&in[NB_FEATURES], sizeof(float), EMBED_PITCH_OUT_SIZE, lpcnet->ftest);
}
}
void run_sample_network(NNetState *net, float *pdf, const float *condition, const float *gru_a_condition, int last_exc, int last_sig, int pred)
@ -110,16 +116,27 @@ LPCNetState *lpcnet_create()
LPCNetState *lpcnet;
lpcnet = (LPCNetState *)calloc(sizeof(LPCNetState), 1);
lpcnet->last_exc = 128;
lpcnet->ftest = NULL;
return lpcnet;
}
void lpcnet_destroy(LPCNetState *lpcnet)
{
if (lpcnet->ftest) fclose(lpcnet->ftest);
free(lpcnet);
}
void lpcnet_synthesize(LPCNetState *lpcnet, short *output, const float *features, int N, int logmag)
void lpcnet_open_test_file(LPCNetState *lpcnet, char file_name[]) {
lpcnet->ftest = fopen(file_name, "wb");
if (lpcnet->ftest == NULL) {
fprintf(stderr, "Error opening LPCNet test file: %s\n", file_name);
exit(1);
}
}
void lpcnet_synthesize(LPCNetState *lpcnet, short *output, const float *features, int N)
{
static int count = 0;
int i;
float condition[FEATURE_DENSE2_OUT_SIZE];
float lpc[LPC_ORDER];
@ -128,7 +145,7 @@ void lpcnet_synthesize(LPCNetState *lpcnet, short *output, const float *features
int pitch;
float pitch_gain;
/* FIXME: Remove this -- it's just a temporary hack to match the Python code. */
static int start = LPC_ORDER+1;
static int start = 0; /*(LPC_ORDER+1*/;
/* FIXME: Do proper rounding once the Python code rounds properly. */
pitch = (int)floor(.1 + 50*features[36]+100);
pitch_gain = lpcnet->old_gain[FEATURES_DELAY-1];
@ -137,16 +154,43 @@ void lpcnet_synthesize(LPCNetState *lpcnet, short *output, const float *features
run_frame_network(lpcnet, condition, gru_a_condition, features, pitch);
memcpy(lpc, lpcnet->old_lpc[FEATURES_DELAY-1], LPC_ORDER*sizeof(lpc[0]));
memmove(lpcnet->old_lpc[1], lpcnet->old_lpc[0], (FEATURES_DELAY-1)*LPC_ORDER*sizeof(lpc[0]));
if (logmag) {
float tmp[NB_BANDS];
for (i=0;i<NB_BANDS;i++) tmp[i] = pow(10.f, features[i]);
lpc_from_bands(lpcnet->old_lpc[0], tmp);
float tmp[NB_BANDS];
for (i=0;i<NB_BANDS;i++) tmp[i] = pow(10.f, features[i]);
lpc_from_bands(lpcnet->old_lpc[0], tmp);
}
else
lpc_from_cepstrum(lpcnet->old_lpc[0], features);
lpc_from_cepstrum(lpcnet->old_lpc[0], features);
if (lpcnet->ftest) {
float pitch_f = pitch;
fwrite(&pitch_f, sizeof(float), 1, lpcnet->ftest);
fwrite(&pitch_gain, sizeof(float), 1, lpcnet->ftest);
fwrite(lpc, sizeof(float), LPC_ORDER, lpcnet->ftest);
fwrite(condition, sizeof(float), FEATURE_DENSE2_OUT_SIZE, lpcnet->ftest);
fwrite(gru_a_condition, sizeof(float), 3*GRU_A_STATE_SIZE, lpcnet->ftest);
if (lpcnet->frame_count==1) {
fprintf(stderr, "%d %d %d %d %d %d %d %d %d %d\n", EMBED_PITCH_OUT_SIZE, 1, 1, LPC_ORDER,FEATURE_DENSE2_OUT_SIZE,3*GRU_A_STATE_SIZE,N,N,N,N);
fprintf(stderr, "ftest cols = %d\n", EMBED_PITCH_OUT_SIZE+1+1+LPC_ORDER+FEATURE_DENSE2_OUT_SIZE+3*GRU_A_STATE_SIZE+N+N+N+N);
}
}
if (lpcnet->frame_count <= FEATURES_DELAY)
{
RNN_CLEAR(output, N);
/* zero output when we return early on init */
for(i=0; i<N; i++)
output[i] = 0;
/* pad test file when we return early */
if (lpcnet->ftest) {
float dummy[4]= {0.0};
for(i=0; i<N; i++) {
fwrite(dummy, sizeof(float), 4, lpcnet->ftest);
}
}
return;
}
for (i=start;i<N;i++)
@ -171,11 +215,18 @@ void lpcnet_synthesize(LPCNetState *lpcnet, short *output, const float *features
lpcnet->deemph_mem = pcm;
if (pcm<-32767) pcm = -32767;
if (pcm>32767) pcm = 32767;
if (lpcnet->ftest) {
float exc_f, last_sig_f;
last_sig_f = ulaw2lin(last_sig_ulaw);
fwrite(&last_sig_f, sizeof(float), 1, lpcnet->ftest);
fwrite(&pred, sizeof(float), 1, lpcnet->ftest);
exc_f = ulaw2lin(exc);
fwrite(&exc_f, sizeof(float), 1, lpcnet->ftest);
fwrite(&pcm, sizeof(float), 1, lpcnet->ftest);
count++;
}
output[i] = (int)floor(.5 + pcm);
}
start = 0;
}
#if 1
#endif

View File

@ -41,4 +41,6 @@ typedef struct LPCNetFreeDV LPCNetFreeDV;
int lpcnet_bits_per_frame(LPCNetFreeDV *);
int lpcnet_samples_per_frame(LPCNetFreeDV *);
void lpcnet_open_test_file(LPCNetState *lpcnet, char file_name[]);
#endif

View File

@ -60,9 +60,14 @@ int main(int argc, char **argv) {
int logmag = 0;
int direct_split = 0;
fin = stdin;
fout = stdout;
/* quantiser options */
static struct option long_options[] = {
{"infile", required_argument, 0, 'i'},
{"outfile", required_argument, 0, 'u'},
{"ber", required_argument, 0, 'b'},
{"decimate", required_argument, 0, 'd'},
{"numstages", required_argument, 0, 'n'},
@ -76,8 +81,20 @@ int main(int argc, char **argv) {
int c;
int opt_index = 0;
while ((c = getopt_long (argc, argv, "b:d:n:o:p:sv", long_options, &opt_index)) != -1) {
while ((c = getopt_long (argc, argv, "b:d:n:o:p:svi:u:", long_options, &opt_index)) != -1) {
switch (c) {
case 'i':
if ((fin = fopen(optarg, "rb")) == NULL) {
fprintf(stderr, "Couldn't open input file: %s\n", optarg);
exit(1);
}
break;
case 'u':
if ((fout = fopen(optarg, "wb")) == NULL) {
fprintf(stderr, "Couldn't open output file: %s\n", optarg);
exit(1);
}
break;
case 'b':
ber = atof(optarg);
fprintf(stderr, "BER = %f\n", ber);
@ -118,6 +135,7 @@ int main(int argc, char **argv) {
}
LPCNetFreeDV *lf = lpcnet_freedv_create(direct_split);
lpcnet_open_test_file(lf->net, "test_lpcnet_statesq.f32");
LPCNET_QUANT *q = lf->q;
// this program allows us to tweak params via command line
@ -130,8 +148,6 @@ int main(int argc, char **argv) {
q->dec, q->pred, q->num_stages, q->mbest, q->bits_per_frame, dec*10, (float)q->bits_per_frame/(dec*0.01));
fprintf(stderr, "\n");
fin = stdin;
fout = stdout;
int nbits = 0, nerrs = 0;
char frame[q->bits_per_frame];
int bits_read = 0;

View File

@ -241,8 +241,12 @@ void lpcnet_dump(LPCNET_DUMP *d, float x[], float features[])
c2_Sn[i] = c2_Sn[i+c2_frame_size];
for(i=0; i<c2_frame_size; i++)
c2_Sn[i+c2_Sn_size-c2_frame_size] = x[i];
float f0, voicing, snr; int pitch_index;
pitch_index = codec2_pitch_est(d->c2pitch, c2_Sn, &f0, &voicing, &snr);
pitch_index = codec2_pitch_est(d->c2pitch, c2_Sn, &f0, &voicing), &snr;
if (pitch_index >= 2*PITCH_MAX_PERIOD) pitch_index = 2*PITCH_MAX_PERIOD-1;
if (pitch_index < 2*PITCH_MIN_PERIOD) pitch_index = 2*PITCH_MIN_PERIOD;
features[2*NB_BANDS] = 0.01*(pitch_index-200);
if (d->c2voicing)
features[2*NB_BANDS+1] = voicing;

View File

@ -58,9 +58,14 @@ int main(int argc, char **argv) {
int logmag = 0;
int direct_split = 0;
fin = stdin;
fout = stdout;
/* quantiser options */
static struct option long_options[] = {
{"infile", required_argument, 0, 'i'},
{"outfile", required_argument, 0, 'u'},
{"decimate", required_argument, 0, 'd'},
{"numstages", required_argument, 0, 'n'},
{"pitchquant", required_argument, 0, 'o'},
@ -73,8 +78,20 @@ int main(int argc, char **argv) {
int c;
int opt_index = 0;
while ((c = getopt_long (argc, argv, "d:n:o:p:sv", long_options, &opt_index)) != -1) {
while ((c = getopt_long (argc, argv, "d:n:o:p:svi:u:", long_options, &opt_index)) != -1) {
switch (c) {
case 'i':
if ((fin = fopen(optarg, "rb")) == NULL) {
fprintf(stderr, "Couldn't open input file: %s\n", optarg);
exit(1);
}
break;
case 'u':
if ((fout = fopen(optarg, "wb")) == NULL) {
fprintf(stderr, "Couldn't open output file: %s\n", optarg);
exit(1);
}
break;
case 'd':
dec = atoi(optarg);
fprintf(stderr, "dec = %d\n", dec);
@ -101,6 +118,7 @@ int main(int argc, char **argv) {
break;
default:
fprintf(stderr,"usage: %s [Options]:\n [-d --decimation 1/2/3...]\n", argv[0]);
fprintf(stderr," [-i --infile]\n [-u --outfile]\n");
fprintf(stderr," [-n --numstages]\n [-o --pitchbits nBits]\n");
fprintf(stderr," [-p --pred predCoff] [-s --split]\n");
fprintf(stderr," [-v --verbose]\n");
@ -120,9 +138,6 @@ int main(int argc, char **argv) {
q->dec, q->pred, q->num_stages, q->mbest, q->bits_per_frame, dec*10, (float)q->bits_per_frame/(dec*0.01));
fprintf(stderr, "\n");
fin = stdin;
fout = stdout;
char frame[lpcnet_bits_per_frame(lf)];
int f=0;
int bits_written=0;

View File

@ -28,6 +28,8 @@ int lpcnet_verbose = 0;
#define DEFAULT_PITCH_BITS 6
#define DEFAULT_DEC 3
static int quantise(const float * cb, float vec[], float w[], int k, int m, float *se);
LPCNET_QUANT *lpcnet_quant_create(int direct_split) {
LPCNET_QUANT *q = (LPCNET_QUANT*)malloc(sizeof(LPCNET_QUANT));
if (q == NULL) return NULL;
@ -133,7 +135,7 @@ void quant_pred_mbest(float vec_out[],
float target[k];
for(i=0; i<num_stages; i++) {
mbest_stage[i] = mbest_create(mbest_survivors, num_stages);
mbest_stage[i] = lpcnet_mbest_create(mbest_survivors, num_stages);
index[i] = 0;
}
@ -150,7 +152,7 @@ void quant_pred_mbest(float vec_out[],
/* now quantise err[] using multi-stage mbest search, preserving
mbest_survivors at each stage */
mbest_search(vq, err, w, k, m[0], mbest_stage[0], index);
lpcnet_mbest_search(vq, err, w, k, m[0], mbest_stage[0], index);
if (lpcnet_verbose) MBEST_PRINT("Stage 1:", mbest_stage[0]);
for(s=1; s<num_stages; s++) {
@ -172,7 +174,7 @@ void quant_pred_mbest(float vec_out[],
}
}
pv(" target: ", target);
mbest_search(&vq[s*k*MAX_ENTRIES], target, w, k, m[s], mbest_stage[s], index);
lpcnet_mbest_search(&vq[s*k*MAX_ENTRIES], target, w, k, m[s], mbest_stage[s], index);
}
char str[80]; sprintf(str,"Stage %d:", s+1);
if (lpcnet_verbose) MBEST_PRINT(str, mbest_stage[s]);
@ -195,7 +197,7 @@ void quant_pred_mbest(float vec_out[],
quant_pred_output(vec_out, indexes, err, pred, num_stages, vq, k);
for(i=0; i<num_stages; i++)
mbest_destroy(mbest_stage[i]);
lpcnet_mbest_destroy(mbest_stage[i]);
}
@ -241,7 +243,7 @@ void quant_pred_output(float vec_out[],
\*---------------------------------------------------------------------------*/
int quantise(const float * cb, float vec[], float w[], int k, int m, float *se)
static int quantise(const float * cb, float vec[], float w[], int k, int m, float *se)
/* float cb[][K]; current VQ codebook */
/* float vec[]; vector to quantise */
/* float w[]; weighting vector */
@ -284,7 +286,7 @@ int pitch_encode(float pitch_feature, int pitch_bits) {
// we may not need any special precautions here.
int periods = 0.1 + 50*pitch_feature + 100;
if (periods < PITCH_MIN_PERIOD) periods = PITCH_MIN_PERIOD;
if (periods > PITCH_MAX_PERIOD) periods = PITCH_MAX_PERIOD;
if (periods >= PITCH_MAX_PERIOD) periods = PITCH_MAX_PERIOD-1;
// should probably add rounding here
int q = (periods - PITCH_MIN_PERIOD) >> (8 - pitch_bits);
@ -293,6 +295,9 @@ int pitch_encode(float pitch_feature, int pitch_bits) {
float pitch_decode(int pitch_bits, int q) {
int periods_ = (q << (8 - pitch_bits)) + PITCH_MIN_PERIOD;
/* bit errors can push periods_ to 63*(8-6)+20 = 272 which breaks embedd layer */
if (periods_ < PITCH_MIN_PERIOD) periods_ = PITCH_MIN_PERIOD;
if (periods_ >= PITCH_MAX_PERIOD) periods_ = PITCH_MAX_PERIOD-1;
return ((float)periods_ - 100.0 - 0.1)/50.0;
}

View File

@ -48,8 +48,6 @@ void lpcnet_quant_compute_bits_per_frame(LPCNET_QUANT *q);
extern FILE *lpcnet_fsv;
extern int lpcnet_verbose;
int quantise(const float * cb, float vec[], float w[], int k, int m, float *se);
void quant_pred(float vec_out[], /* prev quant vector, and output */
float vec_in[],
float pred,

View File

@ -5,10 +5,7 @@
DATE CREATED: Jan 2017
Multistage vector quantiser search algorithm that keeps multiple
candidates from each stage.
TODO: A unit test with contrived examples. This is a complex algorithm and
I am afraid I may have missed something subtle.
candidates from each stage - LPCNet version.
\*---------------------------------------------------------------------------*/
@ -38,7 +35,7 @@
#include "mbest.h"
struct MBEST *mbest_create(int entries, int stages) {
struct MBEST *lpcnet_mbest_create(int entries, int stages) {
int i,j;
struct MBEST *mbest;
@ -60,7 +57,7 @@ struct MBEST *mbest_create(int entries, int stages) {
return mbest;
}
void mbest_destroy(struct MBEST *mbest) {
void lpcnet_mbest_destroy(struct MBEST *mbest) {
assert(mbest != NULL);
free(mbest->list);
free(mbest);
@ -77,7 +74,7 @@ void mbest_destroy(struct MBEST *mbest) {
\*---------------------------------------------------------------------------*/
void mbest_insert(struct MBEST *mbest, int index[], float error) {
static void mbest_insert(struct MBEST *mbest, int index[], float error) {
int i, j, found;
struct MBEST_LIST *list = mbest->list;
int entries = mbest->entries;
@ -96,7 +93,7 @@ void mbest_insert(struct MBEST *mbest, int index[], float error) {
}
void mbest_print(char title[], struct MBEST *mbest) {
void lpcnet_mbest_print(char title[], struct MBEST *mbest) {
int i,j;
fprintf(stderr, "%s\n", title);
@ -117,7 +114,7 @@ void mbest_print(char title[], struct MBEST *mbest) {
\*---------------------------------------------------------------------------*/
void mbest_search(
void lpcnet_mbest_search(
const float *cb, /* VQ codebook to search */
float vec[], /* target vector */
float w[], /* weighting vector */
@ -143,33 +140,3 @@ void mbest_search(
}
/*---------------------------------------------------------------------------*\
mbest_search450
Searches vec[] to a codebbook of vectors, and maintains a list of the mbest
closest matches. Only searches the first NewAmp2_K Vectors
\*---------------------------------------------------------------------------*/
void mbest_search450(const float *cb, float vec[], float w[], int k,int shorterK, int m, struct MBEST *mbest, int index[])
{
float e;
int i,j;
float diff;
for(j=0; j<m; j++) {
e = 0.0;
for(i=0; i<k; i++) {
//Only search first NEWAMP2_K Vectors
if(i<shorterK){
diff = cb[j*k+i]-vec[i];
e += powf(diff*w[i],2.0);
}
}
index[0] = j;
mbest_insert(mbest, index, e);
}
}

View File

@ -5,7 +5,7 @@
DATE CREATED: Jan 2017
Multistage vector quantiser search algorithm that keeps multiple
candidates from each stage.
candidates from each stage. LPCNet version.
\*---------------------------------------------------------------------------*/
@ -43,19 +43,17 @@ struct MBEST {
struct MBEST_LIST *list;
};
struct MBEST *mbest_create(int entries, int stages);
void mbest_destroy(struct MBEST *mbest);
void mbest_insert(struct MBEST *mbest, int index[], float error);
void mbest_search(const float *cb, float vec[], float w[], int k, int m, struct MBEST *mbest, int index[]);
void mbest_search450(const float *cb, float vec[], float w[], int k,int shorterK, int m, struct MBEST *mbest, int index[]);
void mbest_print(char title[], struct MBEST *mbest);
struct MBEST *lpcnet_mbest_create(int entries, int stages);
void lpcnet_mbest_destroy(struct MBEST *mbest);
static void mbest_insert(struct MBEST *mbest, int index[], float error);
void lpcnet_mbest_search(const float *cb, float vec[], float w[], int k, int m, struct MBEST *mbest, int index[]);
void lpcnet_mbest_print(char title[], struct MBEST *mbest);
#define MBEST_PRINT_OUT
#ifdef MBEST_PRINT_OUT
#define MBEST_PRINT(a,b) mbest_print((a),(b))
#define MBEST_PRINT(a,b) lpcnet_mbest_print((a),(b))
#else
#define MBEST_PRINT(a,b)
#endif
#endif

View File

@ -358,6 +358,16 @@ void accum_embedding(const EmbeddingLayer *layer, float *output, int input)
}
}
/* needed to replace Windows/gcc rand() with our own rand() function
to get click free synthesised audio - not sure why */
#define NNET_RAND_MAX 32768
static uint32_t next = 1;
uint16_t nnet_rand(void) {
next = next * 1103515245 + 12345;
uint32_t r = (next/65536) % 32768;
return((uint16_t)r);
}
int sample_from_pdf(const float *pdf, int N, float exp_boost, float pdf_floor)
{
int i;
@ -392,10 +402,14 @@ int sample_from_pdf(const float *pdf, int N, float exp_boost, float pdf_floor)
tmp[i] = tmp[i-1] + MAX16(0, norm*tmp[i] - pdf_floor);
}
/* Do the sampling (from the cdf). */
r = tmp[N-1] * ((float)rand()/RAND_MAX);
float annr = (float)nnet_rand();
float arand = (annr/NNET_RAND_MAX);
r = tmp[N-1] * arand;
for (i=0;i<N-1;i++)
{
if (r < tmp[i]) return i;
}
//fprintf(stderr, "DUAL_FC_OUT_SIZE: %d annr: %f arand: %f\n", DUAL_FC_OUT_SIZE, annr, arand);
return N-1;
}

View File

@ -51,7 +51,7 @@ int main(int argc, char **argv) {
if (strcmp(argv[1], "-") == 0)
f1 = stdin;
else {
f1 = fopen(argv[1], "r");
f1 = fopen(argv[1], "rb");
if (f1 == NULL) {
fprintf(stderr,"Error opening input .s16 16kHz speech input file: %s\n", argv[1]);
exit(1);
@ -60,7 +60,7 @@ int main(int argc, char **argv) {
if (strcmp(argv[2], "-") == 0)
ffeat = stdout;
else {
ffeat = fopen(argv[2], "w");
ffeat = fopen(argv[2], "wb");
if (ffeat == NULL) {
fprintf(stderr,"Error opening output feature file: %s\n", argv[2]);
exit(1);
@ -71,10 +71,12 @@ int main(int argc, char **argv) {
float features[LPCNET_NB_FEATURES];
int i;
int f=0;
int nread;
while (1) {
/* note one frame delay */
for (i=0;i<FRAME_SIZE;i++) x[i] = d->tmp[i];
int nread = fread(&d->tmp, sizeof(short), FRAME_SIZE, f1);
nread = fread(&d->tmp, sizeof(short), FRAME_SIZE, f1);
if (nread != FRAME_SIZE) break;
lpcnet_dump(d,x,features);
fwrite(features, sizeof(float), LPCNET_NB_FEATURES, ffeat);

View File

@ -35,15 +35,16 @@
int main(int argc, char **argv) {
FILE *fin, *fout;
LPCNetState *net;
int logmag = 0;
int o = 0;
int opt_idx = 0;
while( o != -1 ) {
static struct option long_opts[] = {
{"mag", no_argument,0, 'i'},
{0, 0, 0, 0}
};
static struct option long_opts[] = {
{"mag", no_argument,0, 'i'},
{0, 0, 0, 0}
};
o = getopt_long(argc,argv,"ih",long_opts,&opt_idx);
@ -59,8 +60,7 @@ int main(int argc, char **argv) {
}
int dx = optind;
if ((argc - dx) < 2)
{
if ((argc - dx) < 2) {
helpmsg:
fprintf(stderr, "usage: test_lpcnet [--mag] <features.f32> <output.pcm>\n");
return 0;
@ -85,6 +85,8 @@ int main(int argc, char **argv) {
}
net = lpcnet_create();
lpcnet_open_test_file(net, "test_lpcnet_states.f32");
while (1) {
float in_features[NB_TOTAL_FEATURES];
float features[NB_FEATURES];