support scripts for c2sim
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Fri, 20 Aug 2010 08:29:14 +0000 (08:29 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Fri, 20 Aug 2010 08:29:14 +0000 (08:29 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@179 01035d8c-6547-0410-b346-abe4f91aad63

codec2/src/Makefile
codec2/src/c2sim.c [new file with mode: 0644]
codec2/src/interp.c
codec2/src/listen.sh [changed mode: 0755->0644]
codec2/src/listensim.sh [new file with mode: 0755]
codec2/src/sim.sh [new file with mode: 0755]

index f037794bdb5f8d0b64920869b8ae4db7162ddb41..d59afe93219917a26e7683fde35bec3af93c8875 100644 (file)
@@ -1,17 +1,13 @@
 CC=gcc
 CFLAGS=-g -Wall -I. -I../src -Wall -g -DFLOATING_POINT -DVAR_ARRAYS
 
-SINENC_OBJ  = sine.o four1.o sinenc.o dump.o
-SINEDEC_OBJ = sine.o four1.o dump.o quantise.o lpc.o lsp.o phase.o \
-              postfilter.o interp.o sinedec.o 
+C2SIM_OBJ = sine.o nlp.o four1.o dump.o quantise.o lpc.o lsp.o phase.o \
+            postfilter.o interp.o c2sim.o 
 
-all: sinenc sinedec
+all: c2sim
 
-sinenc: $(SINENC_OBJ)
-       $(CC) $(CFLAGS) $(SINENC_OBJ) -o sinenc -lm
-
-sinedec: $(SINEDEC_OBJ)
-       $(CC) $(CFLAGS) $(SINEDEC_OBJ) -o sinedec -lm
+c2sim: $(C2SIM_OBJ)
+       $(CC) $(CFLAGS) $(C2SIM_OBJ) -o c2sim -lm
 
 %.o : %.c
        $(CC) -c $(CFLAGS) $< -o $@
diff --git a/codec2/src/c2sim.c b/codec2/src/c2sim.c
new file mode 100644 (file)
index 0000000..04407bd
--- /dev/null
@@ -0,0 +1,372 @@
+/*---------------------------------------------------------------------------*\
+
+  FILE........: c2sim.c
+  AUTHOR......: David Rowe
+  DATE CREATED: 20/8/2010
+
+  Codec2 simulation.  Combines encoder and decoder and allows switching in 
+  out various algorithms and quantisation steps. 
+
+\*---------------------------------------------------------------------------*/
+
+/*
+  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 General Public License version 2, 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 General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "defines.h"
+#include "sine.h"
+#include "nlp.h"
+#include "dump.h"
+#include "lpc.h"
+#include "quantise.h"
+#include "phase.h"
+#include "postfilter.h"
+#include "interp.h"
+
+/*---------------------------------------------------------------------------*\
+                                                                             
+ switch_present()                                                            
+                                                                             
+ Searches the command line arguments for a "switch".  If the switch is       
+ found, returns the command line argument where it ws found, else returns    
+ NULL.                                                                       
+                                                                             
+\*---------------------------------------------------------------------------*/
+
+int switch_present(sw,argc,argv)
+register char sw[];     /* switch in string form */
+register int argc;      /* number of command line arguments */
+register char *argv[];  /* array of command line arguments in string form */
+{
+  register int i;       /* loop variable */
+
+  for(i=1; i<argc; i++)
+    if (!strcmp(sw,argv[i]))
+      return(i);
+
+  return 0;
+}
+
+/*---------------------------------------------------------------------------*\
+                                                                          
+                               MAIN                                        
+                                                                         
+\*---------------------------------------------------------------------------*/
+
+int main(int argc, char *argv[])
+{
+  FILE *fout;          /* output speech file                    */
+  FILE *fin;           /* input speech file                     */
+  short buf[N];                /* input/output buffer                   */
+  float Sn[M];         /* float input speech samples            */
+  COMP  Sw[FFT_ENC];   /* DFT of w[]                            */
+  float w[M];          /* time domain hamming window            */
+  COMP  W[FFT_ENC];    /* DFT of w[]                            */
+  MODEL model;
+  float Pn[2*N];       /* trapezoidal synthesis window          */
+  float Sn_[2*N];      /* synthesised speech */
+  int   i;             /* loop variable                         */
+  int   frames;
+  float prev_Wo;
+  float pitch;
+
+  char  out_file[MAX_STR];
+  int   arg;
+  float snr;
+  float sum_snr;
+
+  int lpc_model, order;
+  int lsp, lsp_quantiser;
+  float ak[LPC_MAX+1];
+  
+  int dump;
+  
+  int phase0;
+  float ex_phase[MAX_AMP+1];
+  int voiced, voiced_1, voiced_2;
+
+  int   postfilt;
+  float bg_est;
+
+  int   hand_snr;
+  FILE *fsnr;
+
+  MODEL model_1, model_2, model_3, model_synth, model_a, model_b;
+  int transition, decimate;
+
+  for(i=0; i<M; i++)
+      Sn[i] = 1.0;
+  for(i=0; i<2*N; i++)
+      Sn_[i] = 0;
+
+  prev_Wo = TWO_PI/P_MAX;
+
+  voiced_1 = voiced_2 = 0;
+  model_1.Wo = TWO_PI/P_MIN;
+  model_1.L = floor(PI/model_1.Wo);
+  for(i=1; i<=model_1.L; i++) {
+      model_1.A[i] = 0.0;
+      model_1.phi[i] = 0.0;
+  }
+  for(i=1; i<=MAX_AMP; i++) {
+      ex_phase[i] = 0.0;
+  }
+  model_synth = model_3 = model_2 = model_1;
+
+  if (argc < 2) {
+      printf("\nCodec2 - 2400 bit/s speech codec - Simulation Program\n");
+      printf("            http://rowetel.com/codec2.html\n\n");
+      printf("usage: %s InputFile [-o OutputFile]\n", argv[0]);
+      printf("        [-o lpc Order]\n");
+      printf("        [--lsp]\n");
+      printf("        [--phase0]\n");
+      printf("        [--postfilter]\n");
+      printf("        [--hand_snr]\n");
+      printf("        [--dec]\n");
+      printf("        [--dump DumpFilePrefix]\n");
+    exit(0);
+  }
+
+  /* Interpret command line arguments -------------------------------------*/
+
+  /* Input file */
+
+  if ((fin = fopen(argv[1],"rb")) == NULL) {
+    printf("Error opening input speech file: %s\n",argv[1]);
+    exit(1);
+  }
+
+  /* Output file */
+
+  if ((arg = switch_present("-o",argc,argv))) {
+    if ((fout = fopen(argv[arg+1],"wb")) == NULL) {
+      printf("Error opening output speech file: %s\n",argv[arg+1]);
+      exit(1);
+    }
+    strcpy(out_file,argv[arg+1]);
+  }
+  else
+    fout = NULL;
+
+  lpc_model = 0;
+  if ((arg = switch_present("--lpc",argc,argv))) {
+      lpc_model = 1;
+      order = atoi(argv[arg+1]);
+      if ((order < 4) || (order > 20)) {
+        printf("Error in lpc order: %d\n", order);
+        exit(1);
+      }          
+  }
+
+  dump = switch_present("--dump",argc,argv);
+  if (dump) 
+      dump_on(argv[dump+1]);
+
+  lsp = switch_present("--lsp",argc,argv);
+  lsp_quantiser = 0;
+
+  phase0 = switch_present("--phase0",argc,argv);
+  if (phase0) {
+      ex_phase[0] = 0;
+  }
+
+  hand_snr = switch_present("--hand_snr",argc,argv);
+  if (hand_snr) {
+      fsnr = fopen(argv[hand_snr+1],"rt");
+      assert(fsnr != NULL);
+  }
+
+  bg_est = 0.0;
+  postfilt = switch_present("--postfilter",argc,argv);
+
+  decimate = switch_present("--dec",argc,argv);
+  transition = 0;
+
+  /* Initialise ------------------------------------------------------------*/
+
+  make_analysis_window(w,W);
+  make_synthesis_window(Pn);
+  quantise_init();
+
+  /* Main loop ------------------------------------------------------------*/
+
+  frames = 0;
+  sum_snr = 0;
+  while(fread(buf,sizeof(short),N,fin)) {
+    frames++;
+    
+    /* Read input speech */
+
+    for(i=0; i<M-N; i++)
+      Sn[i] = Sn[i+N];
+    for(i=0; i<N; i++)
+      Sn[i+M-N] = buf[i];
+    dump_Sn(Sn);
+    dft_speech(Sw, Sn, w); dump_Sw(Sw);   
+
+    /* Estimate pitch */
+
+    nlp(Sn,N,M,P_MIN,P_MAX,&pitch,Sw,&prev_Wo);
+    prev_Wo = TWO_PI/pitch;
+    model.Wo = TWO_PI/pitch;
+
+    /* estimate model parameters */
+
+    dft_speech(Sw, Sn, w); 
+    two_stage_pitch_refinement(&model, Sw);
+    estimate_amplitudes(&model, Sw, W);
+    dump_Sn(Sn); dump_Sw(Sw); dump_model(&model);
+
+    /* optional zero-phase modelling */
+
+    if (phase0) {
+       float Wn[M];                    /* windowed speech samples */
+       float ak_phase[PHASE_LPC+1];    /* autocorrelation coeffs  */
+       float Rk[PHASE_LPC+1];          /* autocorrelation coeffs  */
+       COMP  Sw_[FFT_ENC];
+       
+       dump_phase(&model.phi[0], model.L);
+
+       /* Determine LPCs for phase modelling.  Note that we may also
+          find the LPCs as part of the {Am} modelling, this can
+          probably be combined in the final codec.  However during
+          development some subtle bugs were found when combining LPC
+          and phase models so for the purpose of development it's
+          easier to find LPCs indepenently for phase modelling
+          here. */
+
+       for(i=0; i<M; i++)
+           Wn[i] = Sn[i]*w[i];
+       autocorrelate(Wn,Rk,M,PHASE_LPC);
+       levinson_durbin(Rk,ak_phase,PHASE_LPC);
+
+       if (lpc_model)
+           assert(order == PHASE_LPC);
+
+       dump_ak(ak_phase, PHASE_LPC);
+       
+       /* determine voicing */
+
+       snr = est_voicing_mbe(&model, Sw, W, (FS/TWO_PI)*model.Wo, Sw_, &voiced);
+       dump_Sw_(Sw_);
+       dump_snr(snr);
+
+       /* just to make sure we are not cheating - kill all phases */
+
+       for(i=0; i<MAX_AMP; i++)
+           model.phi[i] = 0;
+       if (hand_snr) {
+           fscanf(fsnr,"%f\n",&snr);
+           voiced = snr > 2.0;
+       }
+       phase_synth_zero_order(&model, ak_phase, voiced, ex_phase);
+       
+       if (postfilt)
+           postfilter(&model, voiced, &bg_est);
+    }
+    /* optional LPC model amplitudes */
+
+    if (lpc_model) {
+       snr = lpc_model_amplitudes(Sn, w, &model, order, lsp, ak);
+       sum_snr += snr;
+        dump_quantised_model(&model);
+    }
+
+    /* option decimation to 20ms rate, which enables interpolation
+       routine to synthesise in between frame */
+
+    if (decimate) {
+       if (frames%2) {
+
+           /* odd frames use the original model parameters */
+
+           model_synth = model_2;
+           transition = 0;
+       }
+       else {
+           interp(&model_3, &model_1, &model_synth, &model_a, &model_b, 
+                  &transition);
+
+           /* phase need to be supplied outside of this routine, e.g. via
+              a phase model */
+              
+           for(i=1; i<=model_synth.L; i++)
+               model_synth.phi[i] = model_2.phi[i];
+       }
+
+       model_3 = model_2;
+       model_2 = model_1;
+       model_1 = model;
+       model = model_synth;
+    }
+
+    /* 
+       Simulate Wo quantisation noise
+       model.Wo += 2.0*(PI/8000)*(1.0 - 2.0*(float)rand()/RAND_MAX);
+       if (model.Wo > TWO_PI/20.0) model.Wo = TWO_PI/20.0;
+       if (model.Wo < TWO_PI/160.0) model.Wo = TWO_PI/160.0;
+       model.L = floor(PI/model.Wo);   
+    */
+
+    /* Synthesise speech */
+
+    if (fout != NULL) {
+
+       if (transition) {
+           synthesise(Sn_,&model_a,Pn,1);
+           synthesise(Sn_,&model_b,Pn,0);
+       }
+       else {
+           synthesise(Sn_,&model,Pn,1);
+       }
+
+       /* Save output speech to disk */
+
+       for(i=0; i<N; i++) {
+           if (Sn_[i] > 32767.0)
+               buf[i] = 32767;
+           else if (Sn_[i] < -32767.0)
+               buf[i] = -32767;
+           else
+               buf[i] = Sn_[i];
+       }
+       fwrite(buf,sizeof(short),N,fout);
+    }    
+  }
+
+  if (fout != NULL)
+    fclose(fout);
+
+  if (lpc_model)
+      printf("SNR av = %5.2f dB\n", sum_snr/frames);
+
+  if (dump)
+      dump_off();
+
+  if (hand_snr)
+    fclose(fsnr);
+
+  return 0;
+}
+
index 70ed274fe6079e04aa1b5d07e692b164ca41b0d2..21112b57d0990f996008a54db6d7916eea46b30a 100644 (file)
@@ -37,8 +37,7 @@
   interp()
         
   Given two frames decribed by model parameters 20ms apart, determines the
-  model parameters of the 10ms frame between them.  Note that phases are
-  not interpolated, they must be set external to this function.
+  model parameters of the 10ms frame between them.
 
 \*---------------------------------------------------------------------------*/
 
old mode 100755 (executable)
new mode 100644 (file)
index 14c0a4f..bebd106
@@ -1,13 +1,9 @@
 #!/bin/sh
-# listen.sh
+# listensim.sh
 # David Rowe 10 Sep 2009
 #
-# Run menu with common sample file options
+# Listen to files processed with sim.sh
 
-# listen to various modelling and quantisation steps
-../script/menu.sh ../raw/$1.raw $1_uq.raw $1_phase0.raw $1_lpc10.raw $1_lsp.raw $1_phase0_lpc10.raw $1_phase0_lsp.raw ../raw/$1_g729a.raw $2 $3
+../script/menu.sh ../raw/$1.raw $1_uq.raw $1_phase0.raw $1_lpc10.raw $1_lsp.raw $1_phase0_lpc10.raw $1_phase0_lsp.raw $1_phase0_lsp.raw $2 $3
 
-# compare to other codecs
-
-#../script/menu.sh ../raw/$1.raw $1_phase0_lsp.raw $1_phase0_lsp_20.raw $1_phase0_lsp_20_EWo.raw ../raw/$1_g729a.raw ../raw/$1_gsm13k.raw ../raw/$1_speex_8k.raw $2 $3
 
diff --git a/codec2/src/listensim.sh b/codec2/src/listensim.sh
new file mode 100755 (executable)
index 0000000..64f7455
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+# listensim.sh
+# David Rowe 10 Sep 2009
+#
+# Listen to files processed with sim.sh
+
+../script/menu.sh ../raw/$1.raw $1_uq.raw $1_phase0.raw $1_lpc10.raw $1_lsp.raw $1_phase0_lpc10.raw $1_phase0_lsp.raw $1_phase0_lsp_dec.raw $2 $3
+
+
diff --git a/codec2/src/sim.sh b/codec2/src/sim.sh
new file mode 100755 (executable)
index 0000000..ed298e3
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/sh
+# sim.sh
+# David Rowe 10 Sep 2009
+
+# Process a source file using the codec 2 simulation.  An output
+# speech file is generated for each major processing step, from the
+# unquantised siusoidal model to fully quantised.  This way we can
+# listen to the effect of each processing step.  Use listensim.sh to
+# test the output files.
+
+../src/c2sim ../raw/$1.raw -o $1_uq.raw
+../src/c2sim ../raw/$1.raw --phase0 -o $1_phase0.raw --postfilter
+../src/c2sim ../raw/$1.raw --lpc 10 -o $1_lpc10.raw
+../src/c2sim ../raw/$1.raw --lpc 10 --lsp -o $1_lsp.raw
+../src/c2sim ../raw/$1.raw --phase0 --lpc 10 -o $1_phase0_lpc10.raw --postfilter
+../src/c2sim ../raw/$1.raw --phase0 --lpc 10 --lsp -o $1_phase0_lsp.raw --postfilter
+../src/c2sim ../raw/$1.raw --phase0 --lpc 10 --lsp -o $1_phase0_lsp_dec.raw --postfilter --dec
+