19bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten/*
29bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten * Copyright (C) 2012 The Android Open Source Project
39bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten *
49bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
59bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten * you may not use this file except in compliance with the License.
69bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten * You may obtain a copy of the License at
79bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten *
89bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
99bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten *
109bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten * Unless required by applicable law or agreed to in writing, software
119bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
129bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten * See the License for the specific language governing permissions and
149bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten * limitations under the License.
159bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten */
169bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
179bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten#include "AudioResampler.h"
189bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten#include <media/AudioBufferProvider.h>
199bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten#include <unistd.h>
209bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten#include <stdio.h>
219bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten#include <stdlib.h>
229bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten#include <fcntl.h>
239bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten#include <string.h>
249bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten#include <sys/mman.h>
259bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten#include <sys/stat.h>
269bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten#include <errno.h>
279bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten#include <time.h>
289bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten#include <math.h>
299bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
309bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kastenusing namespace android;
319bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
329bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kastenstruct HeaderWav {
339bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    HeaderWav(size_t size, int nc, int sr, int bits) {
349bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        strncpy(RIFF, "RIFF", 4);
359bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        chunkSize = size + sizeof(HeaderWav);
369bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        strncpy(WAVE, "WAVE", 4);
379bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        strncpy(fmt,  "fmt ", 4);
389bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        fmtSize = 16;
399bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        audioFormat = 1;
409bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        numChannels = nc;
419bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        samplesRate = sr;
429bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        byteRate = sr * numChannels * (bits/8);
439bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        align = nc*(bits/8);
449bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        bitsPerSample = bits;
459bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        strncpy(data, "data", 4);
469bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        dataSize = size;
479bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    }
489bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
499bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    char RIFF[4];           // RIFF
509bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    uint32_t chunkSize;     // File size
519bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    char WAVE[4];        // WAVE
529bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    char fmt[4];            // fmt\0
539bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    uint32_t fmtSize;       // fmt size
549bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    uint16_t audioFormat;   // 1=PCM
559bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    uint16_t numChannels;   // num channels
569bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    uint32_t samplesRate;   // sample rate in hz
579bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    uint32_t byteRate;      // Bps
589bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    uint16_t align;         // 2=16-bit mono, 4=16-bit stereo
599bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    uint16_t bitsPerSample; // bits per sample
609bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    char data[4];           // "data"
619bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    uint32_t dataSize;      // size
629bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten};
639bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
649bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kastenstatic int usage(const char* name) {
659bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    fprintf(stderr,"Usage: %s [-p] [-h] [-s] [-q {dq|lq|mq|hq|vhq}] [-i input-sample-rate] "
669bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten                   "[-o output-sample-rate] [<input-file>] <output-file>\n", name);
679bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    fprintf(stderr,"    -p    enable profiling\n");
689bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    fprintf(stderr,"    -h    create wav file\n");
699bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    fprintf(stderr,"    -s    stereo\n");
709bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    fprintf(stderr,"    -q    resampler quality\n");
719bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    fprintf(stderr,"              dq  : default quality\n");
729bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    fprintf(stderr,"              lq  : low quality\n");
739bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    fprintf(stderr,"              mq  : medium quality\n");
749bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    fprintf(stderr,"              hq  : high quality\n");
759bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    fprintf(stderr,"              vhq : very high quality\n");
769bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    fprintf(stderr,"    -i    input file sample rate\n");
779bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    fprintf(stderr,"    -o    output file sample rate\n");
789bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    return -1;
799bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten}
809bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
819bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kastenint main(int argc, char* argv[]) {
829bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
839bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    const char* const progname = argv[0];
849bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    bool profiling = false;
859bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    bool writeHeader = false;
869bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    int channels = 1;
879bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    int input_freq = 0;
889bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    int output_freq = 0;
899bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    AudioResampler::src_quality quality = AudioResampler::DEFAULT_QUALITY;
909bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
919bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    int ch;
929bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    while ((ch = getopt(argc, argv, "phsq:i:o:")) != -1) {
939bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        switch (ch) {
949bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        case 'p':
959bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            profiling = true;
969bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            break;
979bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        case 'h':
989bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            writeHeader = true;
999bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            break;
1009bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        case 's':
1019bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            channels = 2;
1029bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            break;
1039bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        case 'q':
1049bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            if (!strcmp(optarg, "dq"))
1059bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten                quality = AudioResampler::DEFAULT_QUALITY;
1069bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            else if (!strcmp(optarg, "lq"))
1079bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten                quality = AudioResampler::LOW_QUALITY;
1089bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            else if (!strcmp(optarg, "mq"))
1099bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten                quality = AudioResampler::MED_QUALITY;
1109bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            else if (!strcmp(optarg, "hq"))
1119bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten                quality = AudioResampler::HIGH_QUALITY;
1129bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            else if (!strcmp(optarg, "vhq"))
1139bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten                quality = AudioResampler::VERY_HIGH_QUALITY;
1149bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            else {
1159bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten                usage(progname);
1169bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten                return -1;
1179bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            }
1189bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            break;
1199bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        case 'i':
1209bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            input_freq = atoi(optarg);
1219bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            break;
1229bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        case 'o':
1239bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            output_freq = atoi(optarg);
1249bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            break;
1259bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        case '?':
1269bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        default:
1279bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            usage(progname);
1289bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            return -1;
1299bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        }
1309bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    }
1319bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    argc -= optind;
1329bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    argv += optind;
1339bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
1349bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    const char* file_in = NULL;
1359bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    const char* file_out = NULL;
1369bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    if (argc == 1) {
1379bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        file_out = argv[0];
1389bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    } else if (argc == 2) {
1399bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        file_in = argv[0];
1409bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        file_out = argv[1];
1419bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    } else {
1429bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        usage(progname);
1439bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        return -1;
1449bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    }
1459bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
1469bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    // ----------------------------------------------------------
1479bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
1489bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    size_t input_size;
1499bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    void* input_vaddr;
1509bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    if (argc == 2) {
1519bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        struct stat st;
1529bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        if (stat(file_in, &st) < 0) {
1539bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            fprintf(stderr, "stat: %s\n", strerror(errno));
1549bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            return -1;
1559bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        }
1569bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
1579bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        int input_fd = open(file_in, O_RDONLY);
1589bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        if (input_fd < 0) {
1599bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            fprintf(stderr, "open: %s\n", strerror(errno));
1609bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            return -1;
1619bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        }
1629bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
1639bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        input_size = st.st_size;
1649bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        input_vaddr = mmap(0, input_size, PROT_READ, MAP_PRIVATE, input_fd, 0);
1659bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        if (input_vaddr == MAP_FAILED ) {
1669bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            fprintf(stderr, "mmap: %s\n", strerror(errno));
1679bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            return -1;
1689bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        }
1699bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    } else {
1709bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        double k = 1000; // Hz / s
1719bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        double time = (input_freq / 2) / k;
1729bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        size_t input_frames = size_t(input_freq * time);
1739bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        input_size = channels * sizeof(int16_t) * input_frames;
1749bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        input_vaddr = malloc(input_size);
1759bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        int16_t* in = (int16_t*)input_vaddr;
1769bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        for (size_t i=0 ; i<input_frames ; i++) {
1779bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            double t = double(i) / input_freq;
1789bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            double y = sin(M_PI * k * t * t);
1799bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            int16_t yi = floor(y * 32767.0 + 0.5);
1809bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            for (size_t j=0 ; j<(size_t)channels ; j++) {
1819bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten                in[i*channels + j] = yi / (1+j);
1829bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            }
1839bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        }
1849bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    }
1859bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
1869bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    // ----------------------------------------------------------
1879bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
1889bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    class Provider: public AudioBufferProvider {
1899bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        int16_t* mAddr;
1909bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        size_t mNumFrames;
1919bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    public:
1929bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        Provider(const void* addr, size_t size, int channels) {
1939bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            mAddr = (int16_t*) addr;
1949bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            mNumFrames = size / (channels*sizeof(int16_t));
1959bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        }
1969bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        virtual status_t getNextBuffer(Buffer* buffer,
1979bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten                int64_t pts = kInvalidPTS) {
1989bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            buffer->frameCount = mNumFrames;
1999bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            buffer->i16 = mAddr;
2009bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            return NO_ERROR;
2019bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        }
2029bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        virtual void releaseBuffer(Buffer* buffer) {
2039bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        }
2049bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    } provider(input_vaddr, input_size, channels);
2059bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
2069bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    size_t input_frames = input_size / (channels * sizeof(int16_t));
2079bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    size_t output_size = 2 * 4 * ((int64_t) input_frames * output_freq) / input_freq;
2089bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    output_size &= ~7; // always stereo, 32-bits
2099bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
2109bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    void* output_vaddr = malloc(output_size);
2119bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
2129bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    if (profiling) {
2139bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        AudioResampler* resampler = AudioResampler::create(16, channels,
2149bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten                output_freq, quality);
2159bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
2169bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        size_t out_frames = output_size/8;
2179bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        resampler->setSampleRate(input_freq);
2189bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        resampler->setVolume(0x1000, 0x1000);
2199bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
2209bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        memset(output_vaddr, 0, output_size);
2219bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        timespec start, end;
2229bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        clock_gettime(CLOCK_MONOTONIC_HR, &start);
2239bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        resampler->resample((int*) output_vaddr, out_frames, &provider);
2249bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        resampler->resample((int*) output_vaddr, out_frames, &provider);
2259bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        resampler->resample((int*) output_vaddr, out_frames, &provider);
2269bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        resampler->resample((int*) output_vaddr, out_frames, &provider);
2279bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        clock_gettime(CLOCK_MONOTONIC_HR, &end);
2289bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        int64_t start_ns = start.tv_sec * 1000000000LL + start.tv_nsec;
2299bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        int64_t end_ns = end.tv_sec * 1000000000LL + end.tv_nsec;
2309bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        int64_t time = (end_ns - start_ns)/4;
2319bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        printf("%f Mspl/s\n", out_frames/(time/1e9)/1e6);
2329bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
2339bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        delete resampler;
2349bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    }
2359bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
2369bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    AudioResampler* resampler = AudioResampler::create(16, channels,
2379bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            output_freq, quality);
2389bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    size_t out_frames = output_size/8;
2399bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    resampler->setSampleRate(input_freq);
2409bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    resampler->setVolume(0x1000, 0x1000);
2419bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
2429bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    memset(output_vaddr, 0, output_size);
2439bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    resampler->resample((int*) output_vaddr, out_frames, &provider);
2449bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
2459bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    // down-mix (we just truncate and keep the left channel)
2469bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    int32_t* out = (int32_t*) output_vaddr;
2479bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    int16_t* convert = (int16_t*) malloc(out_frames * channels * sizeof(int16_t));
2489bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    for (size_t i = 0; i < out_frames; i++) {
2499bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        for (int j=0 ; j<channels ; j++) {
2509bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            int32_t s = out[i * 2 + j] >> 12;
2519bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            if (s > 32767)       s =  32767;
2529bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            else if (s < -32768) s = -32768;
2539bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            convert[i * channels + j] = int16_t(s);
2549bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        }
2559bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    }
2569bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
2579bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    // write output to disk
2589bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    int output_fd = open(file_out, O_WRONLY | O_CREAT | O_TRUNC,
2599bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten            S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
2609bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    if (output_fd < 0) {
2619bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        fprintf(stderr, "open: %s\n", strerror(errno));
2629bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        return -1;
2639bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    }
2649bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
2659bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    if (writeHeader) {
2669bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        HeaderWav wav(out_frames * channels * sizeof(int16_t), channels, output_freq, 16);
2679bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten        write(output_fd, &wav, sizeof(wav));
2689bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    }
2699bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
2709bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    write(output_fd, convert, out_frames * channels * sizeof(int16_t));
2719bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    close(output_fd);
2729bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten
2739bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten    return 0;
2749bcb476a95a26e62f5706d1f00f4873cf44f9e04Glenn Kasten}
275