improve resample test

- handle stereo input
- input file can now be ommited, in this case
  a linear chirp will be used automatically
- better usage information

Change-Id: I5d62a6c26a9054a1c1a517a065b4df5a2cdcda22
diff --git a/services/audioflinger/test-resample.cpp b/services/audioflinger/test-resample.cpp
index 151313b..e6d5cbe 100644
--- a/services/audioflinger/test-resample.cpp
+++ b/services/audioflinger/test-resample.cpp
@@ -25,6 +25,7 @@
 #include <sys/stat.h>
 #include <errno.h>
 #include <time.h>
+#include <math.h>
 
 using namespace android;
 
@@ -61,31 +62,34 @@
 };
 
 static int usage(const char* name) {
-    fprintf(stderr,"Usage: %s [-p] [-h] [-q <dq|lq|mq|hq|vhq>] [-i <input-sample-rate>] "
-                   "[-o <output-sample-rate>] <input-file> <output-file>\n", name);
-    fprintf(stderr,"-p              - enable profiling\n");
-    fprintf(stderr,"-h              - create wav file\n");
-    fprintf(stderr,"-q              - resampler quality\n");
-    fprintf(stderr,"                  dq  : default quality\n");
-    fprintf(stderr,"                  lq  : low quality\n");
-    fprintf(stderr,"                  mq  : medium quality\n");
-    fprintf(stderr,"                  hq  : high quality\n");
-    fprintf(stderr,"                  vhq : very high quality\n");
-    fprintf(stderr,"-i              - input file sample rate\n");
-    fprintf(stderr,"-o              - output file sample rate\n");
+    fprintf(stderr,"Usage: %s [-p] [-h] [-s] [-q {dq|lq|mq|hq|vhq}] [-i input-sample-rate] "
+                   "[-o output-sample-rate] [<input-file>] <output-file>\n", name);
+    fprintf(stderr,"    -p    enable profiling\n");
+    fprintf(stderr,"    -h    create wav file\n");
+    fprintf(stderr,"    -s    stereo\n");
+    fprintf(stderr,"    -q    resampler quality\n");
+    fprintf(stderr,"              dq  : default quality\n");
+    fprintf(stderr,"              lq  : low quality\n");
+    fprintf(stderr,"              mq  : medium quality\n");
+    fprintf(stderr,"              hq  : high quality\n");
+    fprintf(stderr,"              vhq : very high quality\n");
+    fprintf(stderr,"    -i    input file sample rate\n");
+    fprintf(stderr,"    -o    output file sample rate\n");
     return -1;
 }
 
 int main(int argc, char* argv[]) {
 
+    const char* const progname = argv[0];
     bool profiling = false;
     bool writeHeader = false;
+    int channels = 1;
     int input_freq = 0;
     int output_freq = 0;
     AudioResampler::src_quality quality = AudioResampler::DEFAULT_QUALITY;
 
     int ch;
-    while ((ch = getopt(argc, argv, "phq:i:o:")) != -1) {
+    while ((ch = getopt(argc, argv, "phsq:i:o:")) != -1) {
         switch (ch) {
         case 'p':
             profiling = true;
@@ -93,6 +97,9 @@
         case 'h':
             writeHeader = true;
             break;
+        case 's':
+            channels = 2;
+            break;
         case 'q':
             if (!strcmp(optarg, "dq"))
                 quality = AudioResampler::DEFAULT_QUALITY;
@@ -105,7 +112,7 @@
             else if (!strcmp(optarg, "vhq"))
                 quality = AudioResampler::VERY_HIGH_QUALITY;
             else {
-                usage(argv[0]);
+                usage(progname);
                 return -1;
             }
             break;
@@ -117,54 +124,74 @@
             break;
         case '?':
         default:
-            usage(argv[0]);
+            usage(progname);
             return -1;
         }
     }
     argc -= optind;
+    argv += optind;
 
-    if (argc != 2) {
-        usage(argv[0]);
+    const char* file_in = NULL;
+    const char* file_out = NULL;
+    if (argc == 1) {
+        file_out = argv[0];
+    } else if (argc == 2) {
+        file_in = argv[0];
+        file_out = argv[1];
+    } else {
+        usage(progname);
         return -1;
     }
 
-    argv += optind;
-
     // ----------------------------------------------------------
 
-    struct stat st;
-    if (stat(argv[0], &st) < 0) {
-        fprintf(stderr, "stat: %s\n", strerror(errno));
-        return -1;
-    }
+    size_t input_size;
+    void* input_vaddr;
+    if (argc == 2) {
+        struct stat st;
+        if (stat(file_in, &st) < 0) {
+            fprintf(stderr, "stat: %s\n", strerror(errno));
+            return -1;
+        }
 
-    int input_fd = open(argv[0], O_RDONLY);
-    if (input_fd < 0) {
-        fprintf(stderr, "open: %s\n", strerror(errno));
-        return -1;
-    }
+        int input_fd = open(file_in, O_RDONLY);
+        if (input_fd < 0) {
+            fprintf(stderr, "open: %s\n", strerror(errno));
+            return -1;
+        }
 
-    size_t input_size = st.st_size;
-    void* input_vaddr = mmap(0, input_size, PROT_READ, MAP_PRIVATE, input_fd,
-            0);
-    if (input_vaddr == MAP_FAILED ) {
-        fprintf(stderr, "mmap: %s\n", strerror(errno));
-        return -1;
+        input_size = st.st_size;
+        input_vaddr = mmap(0, input_size, PROT_READ, MAP_PRIVATE, input_fd, 0);
+        if (input_vaddr == MAP_FAILED ) {
+            fprintf(stderr, "mmap: %s\n", strerror(errno));
+            return -1;
+        }
+    } else {
+        double k = 1000; // Hz / s
+        double time = (input_freq / 2) / k;
+        size_t input_frames = size_t(input_freq * time);
+        input_size = channels * sizeof(int16_t) * input_frames;
+        input_vaddr = malloc(input_size);
+        int16_t* in = (int16_t*)input_vaddr;
+        for (size_t i=0 ; i<input_frames ; i++) {
+            double t = double(i) / input_freq;
+            double y = sin(M_PI * k * t * t);
+            int16_t yi = floor(y * 32767.0 + 0.5);
+            for (size_t j=0 ; j<channels ; j++) {
+                in[i*channels + j] = yi;
+            }
+        }
     }
 
-//    printf("input  sample rate: %d Hz\n", input_freq);
-//    printf("output sample rate: %d Hz\n", output_freq);
-//    printf("input mmap: %p, size=%u\n", input_vaddr, input_size);
-
     // ----------------------------------------------------------
 
     class Provider: public AudioBufferProvider {
         int16_t* mAddr;
         size_t mNumFrames;
     public:
-        Provider(const void* addr, size_t size) {
+        Provider(const void* addr, size_t size, int channels) {
             mAddr = (int16_t*) addr;
-            mNumFrames = size / sizeof(int16_t);
+            mNumFrames = size / (channels*sizeof(int16_t));
         }
         virtual status_t getNextBuffer(Buffer* buffer,
                 int64_t pts = kInvalidPTS) {
@@ -174,47 +201,61 @@
         }
         virtual void releaseBuffer(Buffer* buffer) {
         }
-    } provider(input_vaddr, input_size);
+    } provider(input_vaddr, input_size, channels);
 
-    size_t output_size = 2 * 2 * ((int64_t) input_size * output_freq)
-            / input_freq;
+    size_t input_frames = input_size / (channels * sizeof(int16_t));
+    size_t output_size = 2 * 4 * ((int64_t) input_frames * output_freq) / input_freq;
     output_size &= ~7; // always stereo, 32-bits
 
     void* output_vaddr = malloc(output_size);
-    memset(output_vaddr, 0, output_size);
-
-    AudioResampler* resampler = AudioResampler::create(16, 1, output_freq,
-            quality);
-
-    size_t out_frames = output_size/8;
-    resampler->setSampleRate(input_freq);
-    resampler->setVolume(0x1000, 0x1000);
-    resampler->resample((int*) output_vaddr, out_frames, &provider);
 
     if (profiling) {
+        AudioResampler* resampler = AudioResampler::create(16, channels,
+                output_freq, quality);
+
+        size_t out_frames = output_size/8;
+        resampler->setSampleRate(input_freq);
+        resampler->setVolume(0x1000, 0x1000);
+
         memset(output_vaddr, 0, output_size);
         timespec start, end;
         clock_gettime(CLOCK_MONOTONIC_HR, &start);
         resampler->resample((int*) output_vaddr, out_frames, &provider);
+        resampler->resample((int*) output_vaddr, out_frames, &provider);
+        resampler->resample((int*) output_vaddr, out_frames, &provider);
+        resampler->resample((int*) output_vaddr, out_frames, &provider);
         clock_gettime(CLOCK_MONOTONIC_HR, &end);
         int64_t start_ns = start.tv_sec * 1000000000LL + start.tv_nsec;
         int64_t end_ns = end.tv_sec * 1000000000LL + end.tv_nsec;
-        int64_t time = end_ns - start_ns;
+        int64_t time = (end_ns - start_ns)/4;
         printf("%f Mspl/s\n", out_frames/(time/1e9)/1e6);
+
+        delete resampler;
     }
 
+    AudioResampler* resampler = AudioResampler::create(16, channels,
+            output_freq, quality);
+    size_t out_frames = output_size/8;
+    resampler->setSampleRate(input_freq);
+    resampler->setVolume(0x1000, 0x1000);
+
+    memset(output_vaddr, 0, output_size);
+    resampler->resample((int*) output_vaddr, out_frames, &provider);
+
     // down-mix (we just truncate and keep the left channel)
     int32_t* out = (int32_t*) output_vaddr;
-    int16_t* convert = (int16_t*) malloc(out_frames * sizeof(int16_t));
+    int16_t* convert = (int16_t*) malloc(out_frames * channels * sizeof(int16_t));
     for (size_t i = 0; i < out_frames; i++) {
-        int32_t s = out[i * 2] >> 12;
-        if (s > 32767)       s =  32767;
-        else if (s < -32768) s = -32768;
-        convert[i] = int16_t(s);
+        for (int j=0 ; j<channels ; j++) {
+            int32_t s = out[i * 2 + j] >> 12;
+            if (s > 32767)       s =  32767;
+            else if (s < -32768) s = -32768;
+            convert[i * channels + j] = int16_t(s);
+        }
     }
 
     // write output to disk
-    int output_fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC,
+    int output_fd = open(file_out, O_WRONLY | O_CREAT | O_TRUNC,
             S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
     if (output_fd < 0) {
         fprintf(stderr, "open: %s\n", strerror(errno));
@@ -222,11 +263,11 @@
     }
 
     if (writeHeader) {
-        HeaderWav wav(out_frames*sizeof(int16_t), 1, output_freq, 16);
+        HeaderWav wav(out_frames * channels * sizeof(int16_t), channels, output_freq, 16);
         write(output_fd, &wav, sizeof(wav));
     }
 
-    write(output_fd, convert, out_frames * sizeof(int16_t));
+    write(output_fd, convert, out_frames * channels * sizeof(int16_t));
     close(output_fd);
 
     return 0;