diff options
Diffstat (limited to 'src/c2sim.c')
| -rw-r--r-- | src/c2sim.c | 1168 |
1 files changed, 1168 insertions, 0 deletions
diff --git a/src/c2sim.c b/src/c2sim.c new file mode 100644 index 0000000..01ebba1 --- /dev/null +++ b/src/c2sim.c @@ -0,0 +1,1168 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: c2sim.c + AUTHOR......: David Rowe + DATE CREATED: 20/8/2010 + + Codec2 simulation. Combines encoder and decoder and allows + switching in and out various algorithms and quantisation steps. Used + for algorithm development. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2009 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <math.h> +#include <unistd.h> +#include <getopt.h> + +#include "defines.h" +#include "sine.h" +#include "nlp.h" +#include "dump.h" +#include "lpc.h" +#include "lsp.h" +#include "quantise.h" +#include "phase.h" +#include "postfilter.h" +#include "interp.h" +#include "bpf.h" +#include "bpfb.h" +#include "newamp1.h" +#include "lpcnet_freq.h" +#include "sd.h" + +void synth_one_frame(int n_samp, codec2_fftr_cfg fftr_inv_cfg, short buf[], MODEL *model, float Sn_[], float Pn[], int prede, float *de_mem, float gain); +void print_help(const struct option *long_options, int num_opts, char* argv[]); + +#define N_SAMP n_samp /* quick fix for run time sample rate selection */ + +/*---------------------------------------------------------------------------*\ + + MAIN + +\*---------------------------------------------------------------------------*/ + +int main(int argc, char *argv[]) +{ + + int Fs = 8000; + int set_fs; + + int lpc_model = 0, order = LPC_ORD; + int lsp = 0, lspd = 0, lspvq = 0; + int lspjmv = 0; + int prede = 0; + int postfilt; + int hand_voicing = 0, hi = 0, simlpcpf = 0, modelin=0, modelout=0; + int lpcpf = 0; + FILE *fvoicing = 0; + int dec; + int decimate = 1; + int amread, Woread, pahw; + int awread; + int hmread; + int phase0 = 0; + int scalar_quant_Wo_e = 0; + int scalar_quant_Wo_e_low = 0; + int vector_quant_Wo_e = 0; + int dump_pitch_e = 0; + float gain = 1.0; + int bpf_en = 0; + int bpfb_en = 0; + FILE *fam = NULL, *fWo = NULL; + FILE *faw = NULL; + FILE *fhm = NULL; + FILE *fjmv = NULL; + FILE *flspEWov = NULL; + FILE *ften_ms_centre = NULL; + FILE *fmodelout = NULL; + FILE *fmodelin = NULL; + #ifdef DUMP + int dump; + #endif + char out_file[MAX_STR]; + FILE *fout = NULL; /* output speech file */ + int rateK = 0, newamp1vq = 0, rate_K_dec = 0, perframe=0; + int bands = 0, bands_lower_en; + float bands_lower = -1E32; + int K = 20; + float framelength_s = N_S; + int lspEWov = 0, rateKWov = 0, first = 0; + FILE *frateKWov = NULL; + int ten_ms_centre = 0; + FILE *fphasenn = NULL; + FILE *frateK = NULL; + FILE *frateKin = NULL; + int rateKout, rateKin; + FILE *fbands = NULL; + int bands_resample = 0; + + char* opt_string = "ho:"; + struct option long_options[] = { + { "Fs", required_argument, &set_fs, 1 }, + { "rateK", no_argument, &rateK, 1 }, + { "perframe", no_argument, &perframe, 1 }, + { "newamp1vq", no_argument, &newamp1vq, 1 }, + { "rateKdec", required_argument, &rate_K_dec, 1 }, + { "rateKout", required_argument, &rateKout, 1 }, + { "rateKin", required_argument, &rateKin, 1 }, + { "bands",required_argument, &bands, 1 }, + { "bands_lower",required_argument, &bands_lower_en, 1 }, + { "bands_resample", no_argument, &bands_resample, 1 }, + { "lpc", required_argument, &lpc_model, 1 }, + { "lsp", no_argument, &lsp, 1 }, + { "lspd", no_argument, &lspd, 1 }, + { "lspvq", no_argument, &lspvq, 1 }, + { "lspjmv", no_argument, &lspjmv, 1 }, + { "phase0", no_argument, &phase0, 1 }, + { "postfilter", no_argument, &postfilt, 1 }, + { "hand_voicing", required_argument, &hand_voicing, 1 }, + { "dec", required_argument, &dec, 1 }, + { "hi", no_argument, &hi, 1 }, + { "simlpcpf", no_argument, &simlpcpf, 1 }, + { "lpcpf", no_argument, &lpcpf, 1 }, + { "prede", no_argument, &prede, 1 }, + { "dump_pitch_e", required_argument, &dump_pitch_e, 1 }, + { "sq_pitch_e", no_argument, &scalar_quant_Wo_e, 1 }, + { "sq_pitch_e_low", no_argument, &scalar_quant_Wo_e_low, 1 }, + { "vq_pitch_e", no_argument, &vector_quant_Wo_e, 1 }, + { "rate", required_argument, NULL, 0 }, + { "gain", required_argument, NULL, 0 }, + { "bpf", no_argument, &bpf_en, 1 }, + { "bpfb", no_argument, &bpfb_en, 1 }, + { "amread", required_argument, &amread, 1 }, + { "hmread", required_argument, &hmread, 1 }, + { "awread", required_argument, &awread, 1 }, + { "Woread", required_argument, &Woread, 1 }, + { "pahw", required_argument, &pahw, 1 }, + { "lspEWov", required_argument, &lspEWov, 1 }, + { "rateKWov", required_argument, &rateKWov, 1 }, + { "first", no_argument, &first, 1 }, + { "ten_ms_centre", required_argument, &ten_ms_centre, 1 }, + { "framelength_s", required_argument, NULL, 0 }, + { "modelout", required_argument, &modelout, 1 }, + { "modelin", required_argument, &modelin, 1 }, + #ifdef DUMP + { "dump", required_argument, &dump, 1 }, + #endif + { "help", no_argument, NULL, 'h' }, + { NULL, no_argument, NULL, 0 } + }; + int num_opts=sizeof(long_options)/sizeof(struct option); + + /*----------------------------------------------------------------*\ + + Interpret Command Line Arguments + + \*----------------------------------------------------------------*/ + + if (argc < 2) { + print_help(long_options, num_opts, argv); + } + + while(1) { + int option_index = 0; + int opt = getopt_long(argc, argv, opt_string, + long_options, &option_index); + if (opt == -1) + break; + switch (opt) { + case 0: + if(strcmp(long_options[option_index].name, "Fs") == 0) { + Fs= atoi(optarg); + if((Fs != 8000) && (Fs != 16000)) { + fprintf(stderr, "Error Fs must be 8000 or 16000\n"); + exit(1); + } + } else if(strcmp(long_options[option_index].name, "lpc") == 0) { + order = atoi(optarg); + #ifdef DUMP + } else if(strcmp(long_options[option_index].name, "dump") == 0) { + if (dump) + dump_on(optarg); + #endif + } else if(strcmp(long_options[option_index].name, "lsp") == 0 + || strcmp(long_options[option_index].name, "lspd") == 0 + || strcmp(long_options[option_index].name, "lspvq") == 0) { + assert(order == LPC_ORD); + } else if(strcmp(long_options[option_index].name, "rateKdec") == 0) { + rate_K_dec = atoi(optarg); + fprintf(stderr, "rate_K_dec: %d\n", rate_K_dec); + } else if(strcmp(long_options[option_index].name, "rateKout") == 0) { + /* read model records from file or stdin */ + if ((frateK = fopen(optarg,"wb")) == NULL) { + fprintf(stderr, "Error opening output rateK file: %s: %s\n", + optarg, strerror(errno)); + exit(1); + } + fprintf(stderr, "each record is %d bytes\n", (int)(K*sizeof(float))); + } else if(strcmp(long_options[option_index].name, "rateKin") == 0) { + /* read model records from file or stdin */ + if ((frateKin = fopen(optarg,"rb")) == NULL) { + fprintf(stderr, "Error opening input rateK file: %s: %s\n", + optarg, strerror(errno)); + exit(1); + } + fprintf(stderr, "each record is %d bytes\n", (int)(K*sizeof(float))); + } else if(strcmp(long_options[option_index].name, "bands") == 0) { + /* write mel spaced band energies to file or stdout */ + if ((fbands = fopen(optarg,"wb")) == NULL) { + fprintf(stderr, "Error opening bands file: %s: %s\n", + optarg, strerror(errno)); + exit(1); + } + } else if(strcmp(long_options[option_index].name, "bands_lower") == 0) { + bands_lower = atof(optarg); + fprintf(stderr, "bands_lower: %f\n", bands_lower); + } else if(strcmp(long_options[option_index].name, "dec") == 0) { + + decimate = atoi(optarg); + if ((decimate != 2) && (decimate != 3) && (decimate != 4)) { + fprintf(stderr, "Error in --dec, must be 2, 3, or 4\n"); + exit(1); + } + + if (!phase0) { + fprintf(stderr, "needs --phase0 to resample phase when using --dec\n"); + exit(1); + } + if (!lpc_model) { + fprintf(stderr, "needs --lpc [order] to resample amplitudes when using --dec\n"); + exit(1); + } + + } else if(strcmp(long_options[option_index].name, "hand_voicing") == 0) { + if ((fvoicing = fopen(optarg,"rt")) == NULL) { + fprintf(stderr, "Error opening voicing file: %s: %s.\n", + optarg, strerror(errno)); + exit(1); + } + } else if(strcmp(long_options[option_index].name, "Woread") == 0) { + if ((fWo = fopen(optarg,"rb")) == NULL) { + fprintf(stderr, "Error opening float Wo file: %s: %s.\n", + optarg, strerror(errno)); + exit(1); + } + } else if(strcmp(long_options[option_index].name, "amread") == 0) { + if ((fam = fopen(optarg,"rb")) == NULL) { + fprintf(stderr, "Error opening float Am file: %s: %s.\n", + optarg, strerror(errno)); + exit(1); + } + } else if(strcmp(long_options[option_index].name, "hmread") == 0) { + if ((fhm = fopen(optarg,"rb")) == NULL) { + fprintf(stderr, "Error opening float Hm file: %s: %s.\n", + optarg, strerror(errno)); + exit(1); + } + } else if(strcmp(long_options[option_index].name, "awread") == 0) { + if ((faw = fopen(optarg,"rb")) == NULL) { + fprintf(stderr, "Error opening float Aw file: %s: %s.\n", + optarg, strerror(errno)); + exit(1); + } + } else if(strcmp(long_options[option_index].name, "dump_pitch_e") == 0) { + if ((fjmv = fopen(optarg,"wt")) == NULL) { + fprintf(stderr, "Error opening pitch & energy dump file: %s: %s.\n", + optarg, strerror(errno)); + exit(1); + } + } else if(strcmp(long_options[option_index].name, "gain") == 0) { + gain = atof(optarg); + } else if(strcmp(long_options[option_index].name, "framelength_s") == 0) { + framelength_s = atof(optarg); + } else if(strcmp(long_options[option_index].name, "pahw") == 0) { + + /* set up a bunch of arguments instead of having to enter them on cmd line every time */ + + phase0 = postfilt = amread = hmread = Woread = 1; + char file_name[MAX_STR]; + sprintf(file_name, "%s_am.out", optarg); + fprintf(stderr, "reading %s", file_name); + if ((fam = fopen(file_name,"rb")) == NULL) { + fprintf(stderr, "Error opening float Am file: %s: %s.\n", + file_name, strerror(errno)); + exit(1); + } + sprintf(file_name, "%s_hm.out", optarg); + fprintf(stderr, " %s", file_name); + if ((fhm = fopen(file_name,"rb")) == NULL) { + fprintf(stderr, "Error opening float Hm file: %s: %s.\n", + file_name, strerror(errno)); + exit(1); + } + sprintf(file_name, "%s_Wo.out", optarg); + fprintf(stderr, " %s\n", file_name); + if ((fWo = fopen(file_name,"rb")) == NULL) { + fprintf(stderr, "Error opening float Wo file: %s: %s.\n", + file_name, strerror(errno)); + exit(1); + } + } else if(strcmp(long_options[option_index].name, "lspEWov") == 0) { + /* feature file for deep learning experiments */ + lpc_model = 1; phase0 = 1; + if ((flspEWov = fopen(optarg,"wb")) == NULL) { + fprintf(stderr, "Error opening lspEWov float file: %s: %s\n", + optarg, strerror(errno)); + exit(1); + } + } else if(strcmp(long_options[option_index].name, "rateKWov") == 0) { + /* feature file for deep learning experiments */ + rateK = 1; newamp1vq = 1; + if ((frateKWov = fopen(optarg,"wb")) == NULL) { + fprintf(stderr, "Error opening rateKWov float file: %s: %s\n", + optarg, strerror(errno)); + exit(1); + } + } else if(strcmp(long_options[option_index].name, "ten_ms_centre") == 0) { + /* dump 10ms of audio centred on analysis frame to check time alignment with + 16 kHz source audio */ + ten_ms_centre = 1; + if ((ften_ms_centre = fopen(optarg,"wb")) == NULL) { + fprintf(stderr, "Error opening ten_ms_centre short file: %s: %s\n", + optarg, strerror(errno)); + exit(1); + } + } else if(strcmp(long_options[option_index].name, "modelout") == 0) { + /* write model records to file or stdout */ + modelout = 1; + if (strcmp(optarg, "-") == 0) fmodelout = stdout; + else if ((fmodelout = fopen(optarg,"wb")) == NULL) { + fprintf(stderr, "Error opening modelout file: %s: %s\n", + optarg, strerror(errno)); + exit(1); + } + fprintf(stderr, "each model record is %d bytes\n", (int)sizeof(MODEL)); + } else if(strcmp(long_options[option_index].name, "modelin") == 0) { + /* read model records from file or stdin */ + modelin = 1; + if (strcmp(optarg, "-") == 0) fmodelin = stdin; + else if ((fmodelin = fopen(optarg,"rb")) == NULL) { + fprintf(stderr, "Error opening modelin file: %s: %s\n", + optarg, strerror(errno)); + exit(1); + } + fprintf(stderr, "each model record is %d bytes\n", (int)sizeof(MODEL)); + } else if(strcmp(long_options[option_index].name, "rate") == 0) { + if(strcmp(optarg,"3200") == 0) { + lpc_model = 1; + scalar_quant_Wo_e = 1; + lspd = 1; + phase0 = 1; + postfilt = 1; + decimate = 1; + lpcpf = 1; + } else if(strcmp(optarg,"2400") == 0) { + lpc_model = 1; + vector_quant_Wo_e = 1; + lsp = 1; + phase0 = 1; + postfilt = 1; + decimate = 2; + lpcpf = 1; + } else if(strcmp(optarg,"1400") == 0) { + lpc_model = 1; + vector_quant_Wo_e = 1; + lsp = 1; + phase0 = 1; + postfilt = 1; + decimate = 4; + lpcpf = 1; + } else if(strcmp(optarg,"1300") == 0) { + lpc_model = 1; + scalar_quant_Wo_e = 1; + lsp = 1; + phase0 = 1; + postfilt = 1; + decimate = 4; + lpcpf = 1; + } else if(strcmp(optarg,"1200") == 0) { + lpc_model = 1; + scalar_quant_Wo_e = 1; + lspjmv = 1; + phase0 = 1; + postfilt = 1; + decimate = 4; + lpcpf = 1; + } else { + fprintf(stderr, "Error: invalid output rate (3200|2400|1400|1200) %s\n", optarg); + exit(1); + } + } + break; + + case 'h': + print_help(long_options, num_opts, argv); + break; + + case 'o': + if (strcmp(optarg, "-") == 0) fout = stdout; + else if ((fout = fopen(optarg,"wb")) == NULL) { + fprintf(stderr, "Error opening output speech file: %s: %s.\n", + optarg, strerror(errno)); + exit(1); + } + strcpy(out_file,optarg); + break; + + default: + /* This will never be reached */ + break; + } + } + + /* Input file */ + + FILE *fin; /* input speech file */ + if (strcmp(argv[optind], "-") == 0) fin = stdin; + else if ((fin = fopen(argv[optind],"rb")) == NULL) { + fprintf(stderr, "Error opening input speech file: %s: %s.\n", + argv[optind], strerror(errno)); + exit(1); + } + + C2CONST c2const = c2const_create(Fs, framelength_s); + int n_samp = c2const.n_samp; + int m_pitch = c2const.m_pitch; + + short buf[N_SAMP]; /* input/output buffer */ + float buf_float[N_SAMP]; + float Sn[m_pitch]; /* float input speech samples */ + float Sn_pre[m_pitch]; /* pre-emphasised input speech samples */ + COMP Sw[FFT_ENC]; /* DFT of Sn[] */ + codec2_fft_cfg fft_fwd_cfg; + codec2_fftr_cfg fftr_fwd_cfg; + codec2_fftr_cfg fftr_inv_cfg; + float w[m_pitch]; /* time domain hamming window */ + float W[FFT_ENC]; /* DFT of w[] */ + MODEL model; + float Pn[2*N_SAMP]; /* trapezoidal synthesis window */ + float Sn_[2*N_SAMP]; /* synthesised speech */ + int i,m; /* loop variable */ + int frames; + float prev_f0; + float pitch; + float snr; + float sum_snr; + + float pre_mem = 0.0, de_mem = 0.0; + float ak[1+order]; + // COMP Sw_[FFT_ENC]; + // COMP Ew[FFT_ENC]; + + float ex_phase[MAX_AMP+1]; + + float bg_est = 0.0; + + + MODEL prev_model; + float lsps[order]; + float e, prev_e; + int lsp_indexes[order]; + float lsps_[order]; + float Woe_[2]; + + float lsps_dec[4][order], e_dec[4], weight, weight_inc, ak_dec[4][order]; + MODEL model_dec[4], prev_model_dec; + float prev_lsps_dec[order], prev_e_dec; + + void *nlp_states; + float hpf_states[2]; + #if 0 + struct PEXP *pexp = NULL; + struct AEXP *aexp = NULL; + #endif + float bpf_buf[BPF_N+N_SAMP]; + + COMP Aw[FFT_ENC]; + COMP H[MAX_AMP]; + + float sd_sum = 0.0; int sd_frames = 0; + + for(i=0; i<m_pitch; i++) { + Sn[i] = 1.0; + Sn_pre[i] = 1.0; + } + for(i=0; i<2*N_SAMP; i++) + Sn_[i] = 0; + + prev_f0 = 1/P_MAX_S; + + prev_model.Wo = c2const.Wo_max; + prev_model.L = floor(PI/prev_model.Wo); + for(i=1; i<=prev_model.L; i++) { + prev_model.A[i] = 0.0; + prev_model.phi[i] = 0.0; + } + for(i=1; i<=MAX_AMP; i++) { + //ex_phase[i] = (PI/3)*(float)rand()/RAND_MAX; + ex_phase[i] = 0.0; + } + e = prev_e = 1; + hpf_states[0] = hpf_states[1] = 0.0; + + nlp_states = nlp_create(&c2const); + + ex_phase[0] = 0; + Woe_[0] = Woe_[1] = 1.0; + + /* Initialise ------------------------------------------------------------*/ + + fft_fwd_cfg = codec2_fft_alloc(FFT_ENC, 0, NULL, NULL); /* fwd FFT,used in several places */ + fftr_fwd_cfg = codec2_fftr_alloc(FFT_ENC, 0, NULL, NULL); /* fwd FFT,used in several places */ + fftr_inv_cfg = codec2_fftr_alloc(FFT_DEC, 1, NULL, NULL); /* inverse FFT, used just for synth */ + codec2_fft_cfg phase_fft_fwd_cfg = codec2_fft_alloc(NEWAMP1_PHASE_NFFT, 0, NULL, NULL); + codec2_fft_cfg phase_fft_inv_cfg = codec2_fft_alloc(NEWAMP1_PHASE_NFFT, 1, NULL, NULL); + + make_analysis_window(&c2const, fft_fwd_cfg, w, W); + make_synthesis_window(&c2const, Pn); + + if (bpfb_en) + bpf_en = 1; + if (bpf_en) { + for(i=0; i<BPF_N; i++) + bpf_buf[i] = 0.0; + } + + for(i=0; i<LPC_ORD; i++) { + prev_lsps_dec[i] = i*PI/(LPC_ORD+1); + } + prev_e_dec = 1; + for(m=1; m<=MAX_AMP; m++) + prev_model_dec.A[m] = 0.0; + prev_model_dec.Wo = c2const.Wo_min; + prev_model_dec.L = PI/prev_model_dec.Wo; + prev_model_dec.voiced = 0; + + /* mel resampling experiments */ + + float rate_K_sample_freqs_kHz[K]; float se = 0.0; int nse = 0; + if (rateK) { + mel_sample_freqs_kHz(rate_K_sample_freqs_kHz, NEWAMP1_K, ftomel(200.0), ftomel(3700.0) ); + } + float rate_K_vec_delay[rate_K_dec+1][K]; + float rate_K_vec_delay_[rate_K_dec+1][K]; + MODEL rate_K_model_delay[rate_K_dec+1]; + for (int d=0; d<=rate_K_dec; d++) { + for(int k=0; k<K; k++) { + rate_K_vec_delay[d][k] = 0; + rate_K_vec_delay_[d][k] = 0; + } + for(m=1; m<=MAX_AMP; m++) + rate_K_model_delay[d].A[m] = 0.0; + rate_K_model_delay[d].Wo = c2const.Wo_min; + rate_K_model_delay[d].L = M_PI/prev_model_dec.Wo; + rate_K_model_delay[d].voiced = 0; + } + float eq[K]; + for(int k=0; k<K; k++) eq[k] = 0; + + /*----------------------------------------------------------------* \ + + Main Loop + + \*----------------------------------------------------------------*/ + + frames = 0; + sum_snr = 0; + while(fread(buf,sizeof(short),N_SAMP,fin)) { + frames++; + + for(i=0; i<N_SAMP; i++) + buf_float[i] = buf[i]; + + /* optionally filter input speech */ + + if (prede) { + pre_emp(Sn_pre, buf_float, &pre_mem, N_SAMP); + for(i=0; i<N_SAMP; i++) + buf_float[i] = Sn_pre[i]; + } + + if (bpf_en) { + /* filter input speech to create buf_float_bpf[], this is fed to the + LPC modelling. Unfiltered speech in in buf_float[], which is + delayed to match that of the BPF */ + + /* BPF speech */ + + for(i=0; i<BPF_N; i++) + bpf_buf[i] = bpf_buf[N_SAMP+i]; + for(i=0; i<N_SAMP; i++) + bpf_buf[BPF_N+i] = buf_float[i]; + if (bpfb_en) + inverse_filter(&bpf_buf[BPF_N], bpfb, N_SAMP, buf_float, BPF_N); + else + inverse_filter(&bpf_buf[BPF_N], bpf, N_SAMP, buf_float, BPF_N); + } + + /* shift buffer of input samples, and insert new samples */ + + for(i=0; i<m_pitch-N_SAMP; i++) { + Sn[i] = Sn[i+N_SAMP]; + } + for(i=0; i<N_SAMP; i++) { + Sn[i+m_pitch-N_SAMP] = buf_float[i]; + } + + /*------------------------------------------------------------*\ + + Estimate Sinusoidal Model Parameters + + \*------------------------------------------------------------*/ + + nlp(nlp_states, Sn, N_SAMP, &pitch, Sw, W, &prev_f0); + model.Wo = TWO_PI/pitch; + + dft_speech(&c2const, fft_fwd_cfg, Sw, Sn, w); + two_stage_pitch_refinement(&c2const, &model, Sw); + estimate_amplitudes(&model, Sw, W, 1); + + #ifdef DUMP + dump_Sn(m_pitch, Sn); dump_Sw(Sw); dump_model(&model); + #endif + + /* speech centred on analysis frame for Deep Learning work */ + + if (ten_ms_centre) { + int n_10_ms = Fs*0.01; + int n_5_ms = Fs*0.005; + short buf[n_10_ms]; + for(i=0; i<n_10_ms; i++) { + buf[i] = Sn[m_pitch/2-n_5_ms+i]; + } + fwrite(buf, n_10_ms, sizeof(short), ften_ms_centre); + } + + if (hi) { + int m; + for(m=1; m<model.L/2; m++) + model.A[m] = 0.0; + for(m=3*model.L/4; m<=model.L; m++) + model.A[m] = 0.0; + } + + /*------------------------------------------------------------*\ + + Zero-phase modelling + + \*------------------------------------------------------------*/ + + /* estimate voicing - do this all the time so model.voicing + * is set, useful for machine learning work */ + snr = est_voicing_mbe(&c2const, &model, Sw, W); + + if (phase0) { + #ifdef DUMP + dump_phase(&model.phi[0], model.L); + #endif + + if (dump_pitch_e) + fprintf(fjmv, "%f %f %d ", model.Wo, snr, model.voiced); + + #ifdef DUMP + dump_snr(snr); + #endif + + /* just to make sure we are not cheating - kill all phases */ + + for(i=0; i<=MAX_AMP; i++) + model.phi[i] = 0; + + if (hand_voicing) { + int ret = fscanf(fvoicing,"%d\n",&model.voiced); + assert(ret == 1); + } + } + + /*------------------------------------------------------------*\ + + LPC model amplitudes and LSP quantisation + + \*------------------------------------------------------------*/ + + if (lpc_model) { + float ak_[LPC_ORD+1]; + + e = speech_to_uq_lsps(lsps, ak, Sn, w, m_pitch, order); + for(i=0; i<order; i++) + lsps_[i] = lsps[i]; + + #ifdef DUMP + dump_ak(ak, order); + dump_E(e); + #endif + + if (dump_pitch_e) + fprintf(fjmv, "%f\n", e); + + #ifdef DUMP + dump_lsp(lsps); + #endif + + /* various LSP quantisation schemes */ + + if (lsp) { + encode_lsps_scalar(lsp_indexes, lsps, LPC_ORD); + decode_lsps_scalar(lsps_, lsp_indexes, LPC_ORD); + bw_expand_lsps(lsps_, LPC_ORD, 50.0, 100.0); + lsp_to_lpc(lsps_, ak_, LPC_ORD); + } + + if (lspd) { + encode_lspds_scalar(lsp_indexes, lsps, LPC_ORD); + decode_lspds_scalar(lsps_, lsp_indexes, LPC_ORD); + lsp_to_lpc(lsps_, ak_, LPC_ORD); + } + + if (lspjmv) { + /* Jean-Marc's multi-stage, split VQ */ + lspjmv_quantise(lsps, lsps_, LPC_ORD); + { + float lsps_bw[LPC_ORD]; + memcpy(lsps_bw, lsps_, sizeof(float)*order); + bw_expand_lsps(lsps_bw, LPC_ORD, 50.0, 100.0); + lsp_to_lpc(lsps_bw, ak_, LPC_ORD); + } + } + + if (lsp || lspd || lspjmv) { + sd_sum += spectral_dist(ak, ak_, LPC_ORD, fft_fwd_cfg, FFT_ENC); + sd_frames ++; + } + + memcpy(ak, ak_, (LPC_ORD+1)*sizeof(float)); + + if (scalar_quant_Wo_e) { + e = decode_energy(encode_energy(e, E_BITS), E_BITS); + model.Wo = decode_Wo(&c2const, encode_Wo(&c2const, model.Wo, WO_BITS), WO_BITS); + model.L = PI/model.Wo; /* if we quantise Wo re-compute L */ + } + + if (scalar_quant_Wo_e_low) { + int ind; + e = decode_energy(ind = encode_energy(e, 3), 3); + model.Wo = decode_log_Wo(&c2const, encode_log_Wo(&c2const, model.Wo, 5), 5); + model.L = PI/model.Wo; /* if we quantise Wo re-compute L */ + } + + if (vector_quant_Wo_e) { + /* JVM's experimental joint Wo & LPC energy quantiser */ + quantise_WoE(&c2const, &model, &e, Woe_); + } + + } + + if (amread) { + int ret = fread(model.A, sizeof(float), MAX_AMP, fam); + assert(ret == MAX_AMP); + } + + if (Woread) { + int ret = fread(&model.Wo, sizeof(float), 1, fWo); + model.L = floor(PI/model.Wo); + assert(ret == 1); + } + + /* dump features for Deep learning, placed here so we can get quantised features */ + + if (lspEWov) { + /* order LSPs - energy - Wo - voicing flag - order LPCs */ + if (lsp) + fwrite(lsps_, order, sizeof(float), flspEWov); + else + fwrite(lsps, order, sizeof(float), flspEWov); + + fwrite(&e, 1, sizeof(float), flspEWov); + fwrite(&model.Wo, 1, sizeof(float), flspEWov); + float voiced_float = model.voiced; + fwrite(&voiced_float, 1, sizeof(float), flspEWov); + fwrite(&ak[1], order, sizeof(float), flspEWov); + } + + /* LPCNet type mel spaced band ML data */ + float bands_mean = 0.0; + if (fbands) { + float bandE[LPCNET_FREQ_MAX_BANDS]; + float freqkHz[LPCNET_FREQ_MAX_BANDS]; + int nbands = lpcnet_compute_band_energy(bandE, freqkHz, Sw, Fs, FFT_ENC); + for(int i=0; i<nbands; i++) + bands_mean += bandE[i]; + bands_mean /= nbands; + //fprintf(stderr, "bands_mean: %f bands_lower %f\n", bands_mean, bands_lower); + if (bands_mean > bands_lower) + assert(fwrite(bandE, sizeof(float), nbands, fbands) == nbands); + // optionally reconstruct [Am} by linear interpolation of band energies, + // this doesn't sound very Good + if (bands_resample) + resample_rate_L(&c2const, &model, &bandE[1], &freqkHz[1], nbands-2); + } + + /*------------------------------------------------------------*\ + + Optional newamp1 simulation, as used in 700C + + \*------------------------------------------------------------*/ + + if (rateK) { + float rate_K_vec[K]; + resample_const_rate_f(&c2const, &model, rate_K_vec, rate_K_sample_freqs_kHz, K); + + if (frateK != NULL) + assert(fwrite(rate_K_vec, sizeof(float), K, frateK) == K); + + if (frateKin != NULL) { + assert(fread(rate_K_vec, sizeof(float), K, frateKin) == K); + /* apply newamp1 postfilter - this helped male samples with VQVAE work */ + float sum = 0.0; + for(int k=0; k<K; k++) + sum += rate_K_vec[k]; + float mean = sum/K; + float rate_K_vec_no_mean[K]; + for(int k=0; k<K; k++) + rate_K_vec_no_mean[k] = rate_K_vec[k] - mean; + post_filter_newamp1(rate_K_vec_no_mean, rate_K_sample_freqs_kHz, K, 1.5); + for(int k=0; k<K; k++) + rate_K_vec[k] = rate_K_vec_no_mean[k] + mean; + } + + float rate_K_vec_[K]; + if (newamp1vq) { + /* remove mean */ + float sum = 0.0; + for(int k=0; k<K; k++) + sum += rate_K_vec[k]; + float mean = sum/K; + float rate_K_vec_no_mean[K]; + for(int k=0; k<K; k++) + rate_K_vec_no_mean[k] = rate_K_vec[k] - mean; + + newamp1_eq(rate_K_vec_no_mean, eq, K, 1); + + /* two stage VQ */ + float rate_K_vec_no_mean_[K]; int indexes[2]; + rate_K_mbest_encode(indexes, rate_K_vec_no_mean, rate_K_vec_no_mean_, K, NEWAMP1_VQ_MBEST_DEPTH); + for(int k=0; k<K; k++) + rate_K_vec_[k] = rate_K_vec_no_mean_[k] + mean; + + /* running sum of squared error for variance calculation */ + for(int k=0; k<K; k++) + se += pow(rate_K_vec_no_mean[k]-rate_K_vec_no_mean_[k],2.0); + nse += K; + } + else { + for(int k=0; k<K; k++) + rate_K_vec_[k] = rate_K_vec[k]; + } + + if (frateKWov != NULL) { + /* We use standard nb_features=55 feature records for compatibility with train_lpcnet.py */ + float features[55] = {0}; + /* just using 18/20 for compatibility with LPCNet, coarse scaling for NN input */ + for(int i=0; i<18; i++) + features[i] = (rate_K_vec_[i]-30)/40; + // keep in range of 40 ... 255 for pitch embedding + int pitch_index = 21 + 2.0*M_PI/model.Wo; + features[36] = 0.02*(pitch_index-100); + //features[36] = (model.Wo - c2const.Wo_min)/(c2const.Wo_max - c2const.Wo_min) - 0.5; + features[37] = model.voiced; + if (first) + features[18] = -0.9; + if (lpc_model) { + MODEL model_; + model_.Wo = model.Wo; + model_.L = model.L; + model_.voiced = model.voiced; + float Rk[order+1], ak[order+1]; + resample_rate_L(&c2const, &model_, rate_K_vec_, rate_K_sample_freqs_kHz, K); + determine_autoc(&c2const, Rk, order, &model_, NEWAMP1_PHASE_NFFT, phase_fft_fwd_cfg, phase_fft_inv_cfg); + /* -40 dB noise floor and Lag windowing from LPCNet/freq.c - helps reduce large spikes in spectrum when LPC + analysis loses it. */ + Rk[0] += Rk[0]*1e-4 + 320/12/38.; + for (i=1;i<order+1;i++) Rk[i] *= (1 - 6e-5*i*i); + levinson_durbin(Rk, ak, order); + + for(int i=0; i<order; i++) + features[18+i] = ak[i+1]; + } + fwrite(features, 55, sizeof(float), frateKWov); + } + + if (rate_K_dec) { + // update delay lines + for(int d=0; d<rate_K_dec; d++) { + rate_K_model_delay[d] = rate_K_model_delay[d+1]; + memcpy(&rate_K_vec_delay[d][0], &rate_K_vec_delay[d+1][0], sizeof(float)*K); + } + rate_K_model_delay[rate_K_dec] = model; + memcpy(&rate_K_vec_delay[rate_K_dec][0], rate_K_vec_, sizeof(float)*K); + + if ((frames % rate_K_dec) == 0) { + // every rate_K_dec frames, calculate interpolated output values + if (perframe) { + // calculate interpolation coeff c for each frame + float *A = &rate_K_vec_delay[0][0]; + float *B = &rate_K_vec_delay[rate_K_dec][0]; + for(int d=0; d<=rate_K_dec; d++) { + float *T = &rate_K_vec_delay[d][0]; + float num = 0.0, den = 0.0; + for(int k=0; k<K; k++) { + num += (B[k]-T[k])*(A[k]-B[k]); + den += (A[k]-B[k])*(A[k]-B[k]); + } + float c = -num/den; + for(int k=0; k<K; k++) + rate_K_vec_delay_[d][k] = c*A[k] + (1.0-c)*B[k]; + } + } + else { + // use linear interpolation + float c=0.0, inc = 1.0/rate_K_dec; + for(int d=0; d<=rate_K_dec; d++) { + for(int k=0; k<K; k++) + rate_K_vec_delay_[d][k] = (1.0-c)*rate_K_vec_delay[0][k] + c*rate_K_vec_delay[rate_K_dec][k]; + c += inc; + } + } + } else { + // otherwise just shift out frames we have already interpolated + for(int d=0; d<rate_K_dec; d++) { + memcpy(&rate_K_vec_delay_[d][0], &rate_K_vec_delay_[d+1][0], sizeof(float)*K); + } + } + + // output from delay line + model = rate_K_model_delay[0]; + for(int k=0; k<K; k++) + rate_K_vec_[k] = rate_K_vec_delay_[0][k]; + } + + resample_rate_L(&c2const, &model, rate_K_vec_, rate_K_sample_freqs_kHz, K); + } + + /*------------------------------------------------------------*\ + + Synthesise and optional decimation to 20 or 40ms frame rate + + \*------------------------------------------------------------*/ + + /* + if decimate == 2, we interpolate frame n from frame n-1 and n+1 + if decimate == 4, we interpolate frames n, n+1, n+2, from frames n-1 and n+3 + + This is meant to give identical results to the implementations of various modes + in codec2.c + */ + + /* delay line to keep frame by frame voicing decisions */ + + for(i=0; i<decimate-1; i++) + model_dec[i] = model_dec[i+1]; + model_dec[decimate-1] = model; + + if ((frames % decimate) == 0) { + for(i=0; i<order; i++) + lsps_dec[decimate-1][i] = lsps_[i]; + e_dec[decimate-1] = e; + model_dec[decimate-1] = model; + + /* interpolate the model parameters */ + + weight_inc = 1.0/decimate; + for(i=0, weight=weight_inc; i<decimate-1; i++, weight += weight_inc) { + //model_dec[i].voiced = model_dec[decimate-1].voiced; + interpolate_lsp_ver2(&lsps_dec[i][0], prev_lsps_dec, &lsps_dec[decimate-1][0], weight, order); + interp_Wo2(&model_dec[i], &prev_model_dec, &model_dec[decimate-1], weight, c2const.Wo_min); + e_dec[i] = interp_energy2(prev_e_dec, e_dec[decimate-1],weight); + } + + /* then recover spectral amplitudes and synthesise */ + + for(i=0; i<decimate; i++) { + if (lpc_model) { + lsp_to_lpc(&lsps_dec[i][0], &ak_dec[i][0], order); + aks_to_M2(fftr_fwd_cfg, &ak_dec[i][0], order, &model_dec[i], e_dec[i], + &snr, 0, simlpcpf, lpcpf, 1, LPCPF_BETA, LPCPF_GAMMA, Aw); + apply_lpc_correction(&model_dec[i]); + sum_snr += snr; + #ifdef DUMP + dump_lsp_(&lsps_dec[i][0]); + dump_ak_(&ak_dec[i][0], order); + dump_quantised_model(&model_dec[i]); + #endif + } + + if (modelin) { + int nrec; + nrec = fread(&model_dec[i],sizeof(MODEL),1,fmodelin); + if (nrec != 1) { + fprintf(stderr, "Warning - error reading model in record in frame %d - do you have enough records in file?\n", frames); + } + } + + if (phase0) { + /* optionally read in Aw, replacing values generated using LPC */ + + if (awread) { + int ret = fread(Aw, sizeof(COMP), FFT_ENC, faw); + assert(ret == FFT_ENC); + } + + /* optionally read in Hm directly, bypassing sampling of Aw[] */ + + if (hmread) { + int ret = fread(H, sizeof(COMP), MAX_AMP, fhm); + assert(ret == MAX_AMP); + } else { + determine_phase(&c2const, H, &model_dec[i], NEWAMP1_PHASE_NFFT, phase_fft_fwd_cfg, phase_fft_inv_cfg); + } + phase_synth_zero_order(n_samp, &model_dec[i], ex_phase, H); + } + + if (postfilt) + postfilter(&model_dec[i], &bg_est); + synth_one_frame(n_samp, fftr_inv_cfg, buf, &model_dec[i], Sn_, Pn, prede, &de_mem, gain); + if (fout != NULL) + fwrite(buf,sizeof(short),N_SAMP,fout); + if (modelout) { + /* optionally don't write to filter out low energy frames */ + if (bands) { + if (bands_mean > bands_lower) + fwrite(&model_dec[i],sizeof(MODEL),1,fmodelout); + } + else + fwrite(&model_dec[i],sizeof(MODEL),1,fmodelout); + } + } + + /* update memories for next frame ----------------------------*/ + + prev_model_dec = model_dec[decimate-1]; + prev_e_dec = e_dec[decimate-1]; + for(i=0; i<LPC_ORD; i++) + prev_lsps_dec[i] = lsps_dec[decimate-1][i]; + } + + } + + /*----------------------------------------------------------------*\ + + End Main Loop + + \*----------------------------------------------------------------*/ + + fclose(fin); + + if (fout != NULL) + fclose(fout); + + if (lpc_model) { + fprintf(stderr, "LPC->{Am} SNR av: %5.2f dB over %d frames\n", sum_snr/frames, frames); + if (lsp || lspd || lspjmv) + fprintf(stderr, "LSP quantiser SD: %5.2f dB*dB over %d frames\n", sd_sum/sd_frames, sd_frames); + } + if (newamp1vq) { + fprintf(stderr, "var: %3.2f dB*dB\n", se/nse); + } + #ifdef DUMP + if (dump) + dump_off(); + #endif + + if (hand_voicing) + fclose(fvoicing); + + nlp_destroy(nlp_states); + + if (fam != NULL) fclose(fam); + if (fWo != NULL) fclose(fWo); + if (faw != NULL) fclose(faw); + if (fhm != NULL) fclose(fhm); + if (fjmv != NULL) fclose(fjmv); + if (flspEWov != NULL) fclose(flspEWov); + if (fphasenn != NULL) fclose(fphasenn); + if (frateK != NULL) fclose(frateK); + if (frateKin != NULL) fclose(frateKin); + if (ften_ms_centre != NULL) fclose(ften_ms_centre); + if (fmodelout != NULL) fclose(fmodelout); + if (fbands != NULL) fclose(fbands); + if (frateKWov != NULL) fclose(frateKWov); + + return 0; +} + +void synth_one_frame(int n_samp, codec2_fftr_cfg fftr_inv_cfg, short buf[], MODEL *model, float Sn_[], + float Pn[], int prede, float *de_mem, float gain) +{ + int i; + + synthesise(n_samp, fftr_inv_cfg, Sn_, model, Pn, 1); + if (prede) + de_emp(Sn_, Sn_, de_mem, n_samp); + + for(i=0; i<n_samp; i++) { + Sn_[i] *= gain; + if (Sn_[i] > 32767.0) + buf[i] = 32767; + else if (Sn_[i] < -32767.0) + buf[i] = -32767; + else + buf[i] = Sn_[i]; + } + +} + +void print_help(const struct option* long_options, int num_opts, char* argv[]) +{ + int i; + char *option_parameters; + + fprintf(stderr, "\nCodec2 - low bit rate speech codec - Simulation Program\n" + "\thttp://rowetel.com/codec2.html\n\n" + "usage: %s [OPTIONS] <InputFile>\n\n" + "Options:\n" + "\t-o <OutputFile>\n", argv[0]); + for(i=0; i<num_opts-1; i++) { + if(long_options[i].has_arg == no_argument) { + option_parameters=""; + } else if (strcmp("lpc", long_options[i].name) == 0) { + option_parameters = " <Order>"; + } else if (strcmp("dec", long_options[i].name) == 0) { + option_parameters = " <2|4>"; + } else if (strcmp("hand_voicing", long_options[i].name) == 0) { + option_parameters = " <VoicingFile>"; + } else if (strcmp("dump_pitch_e", long_options[i].name) == 0) { + option_parameters = " <Dump File>"; + } else if (strcmp("rate", long_options[i].name) == 0) { + option_parameters = " <3200|2400|1400|1300|1200>"; + } else if (strcmp("dump", long_options[i].name) == 0) { + option_parameters = " <DumpFilePrefix>"; + } else { + option_parameters = " <UNDOCUMENTED parameter>"; + } + fprintf(stderr, "\t--%s%s\n", long_options[i].name, option_parameters); + } + + exit(1); +} |
