decoder excitation now in 16-bit precision (was 32), which saves quite a bit
[speexdsp.git] / src / speexdec.c
index 1c1898c..2a3876a 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002-2003 Jean-Marc Valin 
+/* Copyright (C) 2002-2006 Jean-Marc Valin 
    File: speexdec.c
 
    Redistribution and use in source and binary forms, with or without
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
 #include <stdio.h>
 #if !defined WIN32 && !defined _WIN32
 #include <unistd.h>
 #include <getopt.h>
 #endif
+#ifndef HAVE_GETOPT_LONG
+#include "getopt_win.h"
+#endif
 #include <stdlib.h>
 #include <string.h>
 
-#include "speex.h"
-#include "ogg/ogg.h"
+#include <speex/speex.h>
+#include <ogg/ogg.h>
 
 #if defined WIN32 || defined _WIN32
 #include <windows.h>
 #endif
 #include <math.h>
 
+#ifdef __MINGW32__
+#include "wave_out.c"
+#endif
+
 #ifdef HAVE_SYS_SOUNDCARD_H
 #include <sys/soundcard.h>
 #include <sys/types.h>
 
 #include <string.h>
 #include "wav_io.h"
-#include "speex_header.h"
-#include "speex_stereo.h"
-#include "speex_callbacks.h"
-#include "misc.h"
+#include <speex/speex_header.h>
+#include <speex/speex_stereo.h>
+#include <speex/speex_callbacks.h>
+#include "wav_io.h"
 
 #define MAX_FRAME_SIZE 2000
 
@@ -226,11 +237,7 @@ FILE *out_file_open(char *outFile, int rate, int *channels)
       }
       else 
       {
-#if defined WIN32 || defined _WIN32
          fout = fopen(outFile, "wb");
-#else
-         fout = fopen(outFile, "w");
-#endif
          if (!fout)
          {
             perror(outFile);
@@ -282,20 +289,20 @@ void usage()
 
 void version()
 {
-   printf ("speexdec (Speex decoder) version " VERSION " (compiled " __DATE__ ")\n");
-   printf ("Copyright (C) 2002-2003 Jean-Marc Valin\n");
+   printf ("speexdec (Speex decoder) version " SPEEX_VERSION " (compiled " __DATE__ ")\n");
+   printf ("Copyright (C) 2002-2006 Jean-Marc Valin\n");
 }
 
 void version_short()
 {
-   printf ("speexdec version " VERSION "\n");
-   printf ("Copyright (C) 2002-2003 Jean-Marc Valin\n");
+   printf ("speexdec version " SPEEX_VERSION "\n");
+   printf ("Copyright (C) 2002-2006 Jean-Marc Valin\n");
 }
 
-static void *process_header(ogg_packet *op, int enh_enabled, int *frame_size, int *rate, int *nframes, int forceMode, int *channels, SpeexStereoState *stereo, int *extra_headers)
+static void *process_header(ogg_packet *op, int enh_enabled, int *frame_size, int *rate, int *nframes, int forceMode, int *channels, SpeexStereoState *stereo, int *extra_headers, int quiet)
 {
    void *st;
-   SpeexMode *mode;
+   const SpeexMode *mode;
    SpeexHeader *header;
    int modeID;
    SpeexCallback callback;
@@ -306,7 +313,7 @@ static void *process_header(ogg_packet *op, int enh_enabled, int *frame_size, in
       fprintf (stderr, "Cannot read header\n");
       return NULL;
    }
-   if (header->mode >= SPEEX_NB_MODES)
+   if (header->mode >= SPEEX_NB_MODES || header->mode<0)
    {
       fprintf (stderr, "Mode number %d does not (yet/any longer) exist in this version\n", 
                header->mode);
@@ -316,7 +323,8 @@ static void *process_header(ogg_packet *op, int enh_enabled, int *frame_size, in
    modeID = header->mode;
    if (forceMode!=-1)
       modeID = forceMode;
-   mode = speex_mode_list[modeID];
+
+   mode = speex_lib_get_mode (modeID);
    
    if (header->speex_version_id > 1)
    {
@@ -369,20 +377,23 @@ static void *process_header(ogg_packet *op, int enh_enabled, int *frame_size, in
    if (*channels==-1)
       *channels = header->nb_channels;
    
-   fprintf (stderr, "Decoding %d Hz audio using %s mode", 
-            *rate, mode->modeName);
+   if (!quiet)
+   {
+      fprintf (stderr, "Decoding %d Hz audio using %s mode", 
+               *rate, mode->modeName);
 
-   if (*channels==1)
-      fprintf (stderr, " (mono");
-   else
-      fprintf (stderr, " (stereo");
+      if (*channels==1)
+         fprintf (stderr, " (mono");
+      else
+         fprintf (stderr, " (stereo");
       
-   if (header->vbr)
-      fprintf (stderr, ", VBR)\n");
-   else
-      fprintf(stderr, ")\n");
-   /*fprintf (stderr, "Decoding %d Hz audio at %d bps using %s mode\n", 
-    *rate, mode->bitrate, mode->modeName);*/
+      if (header->vbr)
+         fprintf (stderr, ", VBR)\n");
+      else
+         fprintf(stderr, ")\n");
+      /*fprintf (stderr, "Decoding %d Hz audio at %d bps using %s mode\n", 
+       *rate, mode->bitrate, mode->modeName);*/
+   }
 
    *extra_headers = header->extra_headers;
 
@@ -397,15 +408,19 @@ int main(int argc, char **argv)
    char *inFile, *outFile;
    FILE *fin, *fout=NULL;
    short out[MAX_FRAME_SIZE];
-   float output[MAX_FRAME_SIZE];
+   short output[MAX_FRAME_SIZE];
    int frame_size=0;
    void *st=NULL;
    SpeexBits bits;
    int packet_count=0;
    int stream_init = 0;
+   int quiet = 0;
+   ogg_int64_t page_granule=0, last_granule=0;
+   int skip_samples=0, page_nb_packets;
    struct option long_options[] =
    {
       {"help", no_argument, NULL, 0},
+      {"quiet", no_argument, NULL, 0},
       {"version", no_argument, NULL, 0},
       {"version-short", no_argument, NULL, 0},
       {"enh", no_argument, NULL, 0},
@@ -438,6 +453,7 @@ int main(int argc, char **argv)
    int rate=0;
    int extra_headers;
    int wav_format=0;
+   int lookahead;
 
    enh_enabled = 1;
 
@@ -456,6 +472,9 @@ int main(int argc, char **argv)
          {
             usage();
             exit(0);
+         } else if (strcmp(long_options[option_index].name,"quiet")==0)
+         {
+            quiet = 1;
          } else if (strcmp(long_options[option_index].name,"version")==0)
          {
             version();
@@ -531,7 +550,7 @@ int main(int argc, char **argv)
       outFile = "";
    wav_format = strlen(outFile)>=4 && (
                                        strcmp(outFile+strlen(outFile)-4,".wav")==0
-                                       || strcmp(inFile+strlen(inFile)-4,".WAV")==0);
+                                       || strcmp(outFile+strlen(outFile)-4,".WAV")==0);
    /*Open input file*/
    if (strcmp(inFile, "-")==0)
    {
@@ -542,11 +561,7 @@ int main(int argc, char **argv)
    }
    else 
    {
-#if defined WIN32 || defined _WIN32
       fin = fopen(inFile, "rb");
-#else
-      fin = fopen(inFile, "r");
-#endif
       if (!fin)
       {
          perror(inFile);
@@ -574,19 +589,38 @@ int main(int argc, char **argv)
       /*Loop for all complete pages we got (most likely only one)*/
       while (ogg_sync_pageout(&oy, &og)==1)
       {
+         int packet_no;
          if (stream_init == 0) {
             ogg_stream_init(&os, ogg_page_serialno(&og));
             stream_init = 1;
          }
          /*Add page to the bitstream*/
          ogg_stream_pagein(&os, &og);
+         page_granule = ogg_page_granulepos(&og);
+         page_nb_packets = ogg_page_packets(&og);
+         if (page_granule>0 && frame_size)
+         {
+            /* FIXME: shift the granule values if --force-* is specified */
+            skip_samples = page_nb_packets*frame_size*nframes - (page_granule-last_granule);
+            if (ogg_page_eos(&og))
+               skip_samples = -skip_samples;
+            /*else if (!ogg_page_bos(&og))
+               skip_samples = 0;*/
+         } else
+         {
+            skip_samples = 0;
+         }
+         /*printf ("page granulepos: %d %d %d\n", skip_samples, page_nb_packets, (int)page_granule);*/
+         last_granule = page_granule;
          /*Extract all available packets*/
+         packet_no=0;
          while (!eos && ogg_stream_packetout(&os, &op)==1)
          {
             /*If first packet, process as Speex header*/
             if (packet_count==0)
             {
-               st = process_header(&op, enh_enabled, &frame_size, &rate, &nframes, forceMode, &channels, &stereo, &extra_headers);
+               st = process_header(&op, enh_enabled, &frame_size, &rate, &nframes, forceMode, &channels, &stereo, &extra_headers, quiet);
+               speex_decoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead);
                if (!nframes)
                   nframes=1;
                if (!st)
@@ -595,13 +629,14 @@ int main(int argc, char **argv)
 
             } else if (packet_count==1)
             {
-               print_comments((char*)op.packet, op.bytes);
+               if (!quiet)
+                  print_comments((char*)op.packet, op.bytes);
             } else if (packet_count<=1+extra_headers)
             {
                /* Ignore extra headers */
             } else {
-               
                int lost=0;
+               packet_no++;
                if (loss_percent>0 && 100*((float)rand())/RAND_MAX<loss_percent)
                   lost=1;
 
@@ -616,9 +651,12 @@ int main(int argc, char **argv)
                   int ret;
                   /*Decode frame*/
                   if (!lost)
-                     ret = speex_decode(st, &bits, output);
+                     ret = speex_decode_int(st, &bits, output);
                   else
-                     ret = speex_decode(st, NULL, output);
+                     ret = speex_decode_int(st, NULL, output);
+
+                  /*for (i=0;i<frame_size*channels;i++)
+                    printf ("%d\n", (int)output[i]);*/
 
                   if (ret==-1)
                      break;
@@ -633,7 +671,7 @@ int main(int argc, char **argv)
                      break;
                   }
                   if (channels==2)
-                     speex_decode_stereo(output, frame_size, &stereo);
+                     speex_decode_stereo_int(output, frame_size, &stereo);
 
                   if (print_bitrate) {
                      int tmp;
@@ -642,31 +680,48 @@ int main(int argc, char **argv)
                      fputc (ch, stderr);
                      fprintf (stderr, "Bitrate is use: %d bps     ", tmp);
                   }
-                  /*PCM saturation (just in case)*/
-                  for (i=0;i<frame_size*channels;i++)
-                  {
-                     if (output[i]>32000.0)
-                        output[i]=32000.0;
-                     else if (output[i]<-32000.0)
-                        output[i]=-32000.0;
-                  }
                   /*Convert to short and save to output file*/
                  if (strlen(outFile)!=0)
                   {
                      for (i=0;i<frame_size*channels;i++)
-                        out[i]=(short)le_short((short)floor(.5+output[i]));
+                        out[i]=le_short(output[i]);
                  } else {
                      for (i=0;i<frame_size*channels;i++)
-                        out[i]=(short)floor(.5+output[i]);
+                        out[i]=output[i];
                  }
+                  {
+                     int frame_offset = 0;
+                     int new_frame_size = frame_size;
+                     /*printf ("packet %d %d\n", packet_no, skip_samples);*/
+                     /*fprintf (stderr, "packet %d %d %d\n", packet_no, skip_samples, lookahead);*/
+                     if (packet_no == 1 && j==0 && skip_samples > 0)
+                     {
+                        /*printf ("chopping first packet\n");*/
+                        new_frame_size -= skip_samples+lookahead;
+                        frame_offset = skip_samples+lookahead;
+                     }
+                     if (packet_no == page_nb_packets && skip_samples < 0)
+                     {
+                        int packet_length = nframes*frame_size+skip_samples+lookahead;
+                        new_frame_size = packet_length - j*frame_size;
+                        if (new_frame_size<0)
+                           new_frame_size = 0;
+                        if (new_frame_size>frame_size)
+                           new_frame_size = frame_size;
+                        /*printf ("chopping end: %d %d %d\n", new_frame_size, packet_length, packet_no);*/
+                     }
+                     if (new_frame_size>0)
+                     {  
 #if defined WIN32 || defined _WIN32
-                  if (strlen(outFile)==0)
-                      WIN_Play_Samples (out, sizeof(short) * frame_size*channels);
-                  else
+                        if (strlen(outFile)==0)
+                           WIN_Play_Samples (out+frame_offset*channels, sizeof(short) * new_frame_size*channels);
+                        else
 #endif
-                  fwrite(out, sizeof(short), frame_size*channels, fout);
+                           fwrite(out+frame_offset*channels, sizeof(short), new_frame_size*channels, fout);
                   
-                  audio_size+=sizeof(short)*frame_size*channels;
+                        audio_size+=sizeof(short)*new_frame_size*channels;
+                     }
+                  }
                }
             }
             packet_count++;