test-resample.cpp revision 781366833a12877b8d5ad4aa081114e30f799319
10fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian/* 20fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian * Copyright (C) 2012 The Android Open Source Project 30fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian * 40fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian * Licensed under the Apache License, Version 2.0 (the "License"); 50fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian * you may not use this file except in compliance with the License. 60fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian * You may obtain a copy of the License at 70fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian * 80fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian * http://www.apache.org/licenses/LICENSE-2.0 90fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian * 100fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian * Unless required by applicable law or agreed to in writing, software 110fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian * distributed under the License is distributed on an "AS IS" BASIS, 120fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian * See the License for the specific language governing permissions and 140fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian * limitations under the License. 150fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian */ 160fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 170fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian#include "AudioResampler.h" 180fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian#include <media/AudioBufferProvider.h> 190fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian#include <unistd.h> 200fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian#include <stdio.h> 210fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian#include <stdlib.h> 220fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian#include <fcntl.h> 230fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian#include <string.h> 240fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian#include <sys/mman.h> 250fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian#include <sys/stat.h> 260fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian#include <errno.h> 271e4e4f40b4e2c655ca377adbba53df897545c3aeGlenn Kasten#include <inttypes.h> 280fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian#include <time.h> 293f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian#include <math.h> 30781366833a12877b8d5ad4aa081114e30f799319Andy Hung#include <audio_utils/primitives.h> 31f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten#include <audio_utils/sndfile.h> 32c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten#include <utils/Vector.h> 330fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 340fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopianusing namespace android; 350fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 36781366833a12877b8d5ad4aa081114e30f799319Andy Hungstatic bool gVerbose = false; 37e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten 380fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopianstatic int usage(const char* name) { 39781366833a12877b8d5ad4aa081114e30f799319Andy Hung fprintf(stderr,"Usage: %s [-p] [-f] [-F] [-h] [-v] [-s] [-q {dq|lq|mq|hq|vhq|dlq|dmq|dhq}]" 40781366833a12877b8d5ad4aa081114e30f799319Andy Hung " [-i input-sample-rate] [-o output-sample-rate]" 41781366833a12877b8d5ad4aa081114e30f799319Andy Hung " [-O csv] [-P csv] [<input-file>]" 4286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung " <output-file>\n", name); 433f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian fprintf(stderr," -p enable profiling\n"); 44781366833a12877b8d5ad4aa081114e30f799319Andy Hung fprintf(stderr," -f enable filter profiling\n"); 45781366833a12877b8d5ad4aa081114e30f799319Andy Hung fprintf(stderr," -F enable floating point -q {dlq|dmq|dhq} only"); 463f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian fprintf(stderr," -h create wav file\n"); 47e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten fprintf(stderr," -v verbose : log buffer provider calls\n"); 48bd72d22097f78f5bd668b223bc8c94e351311e31Glenn Kasten fprintf(stderr," -s stereo (ignored if input file is specified)\n"); 493f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian fprintf(stderr," -q resampler quality\n"); 503f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian fprintf(stderr," dq : default quality\n"); 513f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian fprintf(stderr," lq : low quality\n"); 523f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian fprintf(stderr," mq : medium quality\n"); 533f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian fprintf(stderr," hq : high quality\n"); 543f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian fprintf(stderr," vhq : very high quality\n"); 5586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung fprintf(stderr," dlq : dynamic low quality\n"); 5686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung fprintf(stderr," dmq : dynamic medium quality\n"); 5786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung fprintf(stderr," dhq : dynamic high quality\n"); 58bd72d22097f78f5bd668b223bc8c94e351311e31Glenn Kasten fprintf(stderr," -i input file sample rate (ignored if input file is specified)\n"); 593f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian fprintf(stderr," -o output file sample rate\n"); 60c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten fprintf(stderr," -O # frames output per call to resample() in CSV format\n"); 61c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten fprintf(stderr," -P # frames provided per call to resample() in CSV format\n"); 620fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian return -1; 630fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian} 640fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 65c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten// Convert a list of integers in CSV format to a Vector of those values. 66c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten// Returns the number of elements in the list, or -1 on error. 67c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kastenint parseCSV(const char *string, Vector<int>& values) 68c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten{ 69c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten // pass 1: count the number of values and do syntax check 70c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten size_t numValues = 0; 71c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten bool hadDigit = false; 72c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten for (const char *p = string; ; ) { 73c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten switch (*p++) { 74c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten case '0': case '1': case '2': case '3': case '4': 75c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten case '5': case '6': case '7': case '8': case '9': 76c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten hadDigit = true; 77c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten break; 78c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten case '\0': 79c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten if (hadDigit) { 80c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten // pass 2: allocate and initialize vector of values 81c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten values.resize(++numValues); 82c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten values.editItemAt(0) = atoi(p = optarg); 83c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten for (size_t i = 1; i < numValues; ) { 84c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten if (*p++ == ',') { 85c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten values.editItemAt(i++) = atoi(p); 86c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten } 87c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten } 88c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten return numValues; 89c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten } 90c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten // fall through 91c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten case ',': 92c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten if (hadDigit) { 93c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten hadDigit = false; 94c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten numValues++; 95c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten break; 96c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten } 97c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten // fall through 98c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten default: 99c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten return -1; 100c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten } 101c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten } 102c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten} 103c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten 1040fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopianint main(int argc, char* argv[]) { 1050fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 1063f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian const char* const progname = argv[0]; 1076582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung bool profileResample = false; 1086582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung bool profileFilter = false; 1090fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian bool writeHeader = false; 110781366833a12877b8d5ad4aa081114e30f799319Andy Hung bool useFloat = false; 1113f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian int channels = 1; 1120fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian int input_freq = 0; 1130fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian int output_freq = 0; 1140fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian AudioResampler::src_quality quality = AudioResampler::DEFAULT_QUALITY; 115c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten Vector<int> Ovalues; 116c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten Vector<int> Pvalues; 1170fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 1180fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian int ch; 119781366833a12877b8d5ad4aa081114e30f799319Andy Hung while ((ch = getopt(argc, argv, "pfFhvsq:i:o:O:P:")) != -1) { 1200fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian switch (ch) { 1210fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian case 'p': 1226582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung profileResample = true; 1236582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung break; 1246582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung case 'f': 1256582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung profileFilter = true; 1260fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian break; 127781366833a12877b8d5ad4aa081114e30f799319Andy Hung case 'F': 128781366833a12877b8d5ad4aa081114e30f799319Andy Hung useFloat = true; 129781366833a12877b8d5ad4aa081114e30f799319Andy Hung break; 1300fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian case 'h': 1310fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian writeHeader = true; 1320fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian break; 133e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten case 'v': 134e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten gVerbose = true; 135e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten break; 1363f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian case 's': 1373f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian channels = 2; 1383f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian break; 1390fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian case 'q': 1400fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian if (!strcmp(optarg, "dq")) 1410fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian quality = AudioResampler::DEFAULT_QUALITY; 1420fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian else if (!strcmp(optarg, "lq")) 1430fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian quality = AudioResampler::LOW_QUALITY; 1440fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian else if (!strcmp(optarg, "mq")) 1450fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian quality = AudioResampler::MED_QUALITY; 1460fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian else if (!strcmp(optarg, "hq")) 1470fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian quality = AudioResampler::HIGH_QUALITY; 1480fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian else if (!strcmp(optarg, "vhq")) 1490fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian quality = AudioResampler::VERY_HIGH_QUALITY; 15086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung else if (!strcmp(optarg, "dlq")) 15186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung quality = AudioResampler::DYN_LOW_QUALITY; 15286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung else if (!strcmp(optarg, "dmq")) 15386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung quality = AudioResampler::DYN_MED_QUALITY; 15486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung else if (!strcmp(optarg, "dhq")) 15586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung quality = AudioResampler::DYN_HIGH_QUALITY; 1560fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian else { 1573f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian usage(progname); 1580fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian return -1; 1590fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian } 1600fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian break; 1610fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian case 'i': 1620fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian input_freq = atoi(optarg); 1630fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian break; 1640fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian case 'o': 1650fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian output_freq = atoi(optarg); 1660fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian break; 16756df9ff31d583ad3eae4f279a3df550273c58e1eGlenn Kasten case 'O': 168c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten if (parseCSV(optarg, Ovalues) < 0) { 169c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten fprintf(stderr, "incorrect syntax for -O option\n"); 170c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten return -1; 171c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten } 172c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten break; 173c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten case 'P': 174c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten if (parseCSV(optarg, Pvalues) < 0) { 175c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten fprintf(stderr, "incorrect syntax for -P option\n"); 176c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten return -1; 177c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten } 17856df9ff31d583ad3eae4f279a3df550273c58e1eGlenn Kasten break; 1790fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian case '?': 1800fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian default: 1813f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian usage(progname); 1820fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian return -1; 1830fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian } 1840fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian } 185781366833a12877b8d5ad4aa081114e30f799319Andy Hung 186781366833a12877b8d5ad4aa081114e30f799319Andy Hung if (useFloat && quality < AudioResampler::DYN_LOW_QUALITY) { 187781366833a12877b8d5ad4aa081114e30f799319Andy Hung fprintf(stderr, "float processing is only possible for dynamic resamplers\n"); 188781366833a12877b8d5ad4aa081114e30f799319Andy Hung return -1; 189781366833a12877b8d5ad4aa081114e30f799319Andy Hung } 190781366833a12877b8d5ad4aa081114e30f799319Andy Hung 1910fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian argc -= optind; 1923f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian argv += optind; 1930fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 1943f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian const char* file_in = NULL; 1953f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian const char* file_out = NULL; 1963f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian if (argc == 1) { 1973f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian file_out = argv[0]; 1983f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian } else if (argc == 2) { 1993f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian file_in = argv[0]; 2003f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian file_out = argv[1]; 2013f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian } else { 2023f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian usage(progname); 2030fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian return -1; 2040fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian } 2050fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 2060fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian // ---------------------------------------------------------- 2070fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 2083f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian size_t input_size; 2093f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian void* input_vaddr; 2103f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian if (argc == 2) { 211bd72d22097f78f5bd668b223bc8c94e351311e31Glenn Kasten SF_INFO info; 212bd72d22097f78f5bd668b223bc8c94e351311e31Glenn Kasten info.format = 0; 213bd72d22097f78f5bd668b223bc8c94e351311e31Glenn Kasten SNDFILE *sf = sf_open(file_in, SFM_READ, &info); 214bd72d22097f78f5bd668b223bc8c94e351311e31Glenn Kasten if (sf == NULL) { 215bd72d22097f78f5bd668b223bc8c94e351311e31Glenn Kasten perror(file_in); 216bd72d22097f78f5bd668b223bc8c94e351311e31Glenn Kasten return EXIT_FAILURE; 2173f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian } 218bd72d22097f78f5bd668b223bc8c94e351311e31Glenn Kasten input_size = info.frames * info.channels * sizeof(short); 219bd72d22097f78f5bd668b223bc8c94e351311e31Glenn Kasten input_vaddr = malloc(input_size); 220bd72d22097f78f5bd668b223bc8c94e351311e31Glenn Kasten (void) sf_readf_short(sf, (short *) input_vaddr, info.frames); 221bd72d22097f78f5bd668b223bc8c94e351311e31Glenn Kasten sf_close(sf); 222bd72d22097f78f5bd668b223bc8c94e351311e31Glenn Kasten channels = info.channels; 223bd72d22097f78f5bd668b223bc8c94e351311e31Glenn Kasten input_freq = info.samplerate; 2243f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian } else { 22586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung // data for testing is exactly (input sampling rate/1000)/2 seconds 22686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung // so 44.1khz input is 22.05 seconds 2273f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian double k = 1000; // Hz / s 2283f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian double time = (input_freq / 2) / k; 2293f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian size_t input_frames = size_t(input_freq * time); 2303f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian input_size = channels * sizeof(int16_t) * input_frames; 2313f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian input_vaddr = malloc(input_size); 2323f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian int16_t* in = (int16_t*)input_vaddr; 2333f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian for (size_t i=0 ; i<input_frames ; i++) { 2343f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian double t = double(i) / input_freq; 2353f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian double y = sin(M_PI * k * t * t); 2363f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian int16_t yi = floor(y * 32767.0 + 0.5); 237b26e3e9f2ab0334bff21a4fa4851dbf6e57fba5dGlenn Kasten for (size_t j=0 ; j<(size_t)channels ; j++) { 23886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung in[i*channels + j] = yi / (1+j); // right ch. 1/2 left ch. 2393f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian } 2403f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian } 2410fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian } 242781366833a12877b8d5ad4aa081114e30f799319Andy Hung size_t frame_size = channels * sizeof(int16_t); 243781366833a12877b8d5ad4aa081114e30f799319Andy Hung size_t input_frames = input_size / frame_size; 244781366833a12877b8d5ad4aa081114e30f799319Andy Hung 245781366833a12877b8d5ad4aa081114e30f799319Andy Hung // For float processing, convert input int16_t to float array 246781366833a12877b8d5ad4aa081114e30f799319Andy Hung if (useFloat) { 247781366833a12877b8d5ad4aa081114e30f799319Andy Hung void *new_vaddr; 248781366833a12877b8d5ad4aa081114e30f799319Andy Hung 249781366833a12877b8d5ad4aa081114e30f799319Andy Hung frame_size = channels * sizeof(float); 250781366833a12877b8d5ad4aa081114e30f799319Andy Hung input_size = input_frames * frame_size; 251781366833a12877b8d5ad4aa081114e30f799319Andy Hung new_vaddr = malloc(input_size); 252781366833a12877b8d5ad4aa081114e30f799319Andy Hung memcpy_to_float_from_i16(reinterpret_cast<float*>(new_vaddr), 253781366833a12877b8d5ad4aa081114e30f799319Andy Hung reinterpret_cast<int16_t*>(input_vaddr), input_frames * channels); 254781366833a12877b8d5ad4aa081114e30f799319Andy Hung free(input_vaddr); 255781366833a12877b8d5ad4aa081114e30f799319Andy Hung input_vaddr = new_vaddr; 256781366833a12877b8d5ad4aa081114e30f799319Andy Hung } 2570fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 2580fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian // ---------------------------------------------------------- 2590fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 2600fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian class Provider: public AudioBufferProvider { 261781366833a12877b8d5ad4aa081114e30f799319Andy Hung const void* mAddr; // base address 262e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten const size_t mNumFrames; // total frames 263781366833a12877b8d5ad4aa081114e30f799319Andy Hung const size_t mFrameSize; // size of each frame in bytes 264e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten size_t mNextFrame; // index of next frame to provide 265e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten size_t mUnrel; // number of frames not yet released 266c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten const Vector<int> mPvalues; // number of frames provided per call 267c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten size_t mNextPidx; // index of next entry in mPvalues to use 2680fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian public: 269781366833a12877b8d5ad4aa081114e30f799319Andy Hung Provider(const void* addr, size_t frames, size_t frameSize, const Vector<int>& Pvalues) 270781366833a12877b8d5ad4aa081114e30f799319Andy Hung : mAddr(addr), 271781366833a12877b8d5ad4aa081114e30f799319Andy Hung mNumFrames(frames), 272781366833a12877b8d5ad4aa081114e30f799319Andy Hung mFrameSize(frameSize), 273c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten mNextFrame(0), mUnrel(0), mPvalues(Pvalues), mNextPidx(0) { 2740fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian } 2750fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian virtual status_t getNextBuffer(Buffer* buffer, 2760fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian int64_t pts = kInvalidPTS) { 27786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung (void)pts; // suppress warning 278e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten size_t requestedFrames = buffer->frameCount; 279e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten if (requestedFrames > mNumFrames - mNextFrame) { 280e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten buffer->frameCount = mNumFrames - mNextFrame; 281e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten } 282c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten if (!mPvalues.isEmpty()) { 283c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten size_t provided = mPvalues[mNextPidx++]; 2841e4e4f40b4e2c655ca377adbba53df897545c3aeGlenn Kasten printf("mPvalue[%zu]=%zu not %zu\n", mNextPidx-1, provided, buffer->frameCount); 285c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten if (provided < buffer->frameCount) { 286c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten buffer->frameCount = provided; 287c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten } 288c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten if (mNextPidx >= mPvalues.size()) { 289c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten mNextPidx = 0; 290c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten } 291c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten } 292e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten if (gVerbose) { 2931e4e4f40b4e2c655ca377adbba53df897545c3aeGlenn Kasten printf("getNextBuffer() requested %zu frames out of %zu frames available," 2941e4e4f40b4e2c655ca377adbba53df897545c3aeGlenn Kasten " and returned %zu frames\n", 2951e4e4f40b4e2c655ca377adbba53df897545c3aeGlenn Kasten requestedFrames, (size_t) (mNumFrames - mNextFrame), buffer->frameCount); 296e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten } 297e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten mUnrel = buffer->frameCount; 298e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten if (buffer->frameCount > 0) { 299781366833a12877b8d5ad4aa081114e30f799319Andy Hung buffer->raw = (char *)mAddr + mFrameSize * mNextFrame; 300e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten return NO_ERROR; 301e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten } else { 302781366833a12877b8d5ad4aa081114e30f799319Andy Hung buffer->raw = NULL; 303e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten return NOT_ENOUGH_DATA; 304e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten } 3050fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian } 3060fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian virtual void releaseBuffer(Buffer* buffer) { 307e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten if (buffer->frameCount > mUnrel) { 3081e4e4f40b4e2c655ca377adbba53df897545c3aeGlenn Kasten fprintf(stderr, "ERROR releaseBuffer() released %zu frames but only %zu available " 309e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten "to release\n", buffer->frameCount, mUnrel); 310e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten mNextFrame += mUnrel; 311e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten mUnrel = 0; 312e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten } else { 313e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten if (gVerbose) { 3141e4e4f40b4e2c655ca377adbba53df897545c3aeGlenn Kasten printf("releaseBuffer() released %zu frames out of %zu frames available " 315e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten "to release\n", buffer->frameCount, mUnrel); 316e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten } 317e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten mNextFrame += buffer->frameCount; 318e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten mUnrel -= buffer->frameCount; 319e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten } 32047f3f5a119194d4c06815453be9950ba112c8e3eGlenn Kasten buffer->frameCount = 0; 321781366833a12877b8d5ad4aa081114e30f799319Andy Hung buffer->raw = NULL; 3220fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian } 32386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung void reset() { 32486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung mNextFrame = 0; 32586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung } 326781366833a12877b8d5ad4aa081114e30f799319Andy Hung } provider(input_vaddr, input_frames, frame_size, Pvalues); 3270fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 328e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten if (gVerbose) { 3291e4e4f40b4e2c655ca377adbba53df897545c3aeGlenn Kasten printf("%zu input frames\n", input_frames); 330e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten } 331781366833a12877b8d5ad4aa081114e30f799319Andy Hung 332781366833a12877b8d5ad4aa081114e30f799319Andy Hung int bit_depth = useFloat ? 32 : 16; 3333f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian size_t output_size = 2 * 4 * ((int64_t) input_frames * output_freq) / input_freq; 3340fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian output_size &= ~7; // always stereo, 32-bits 3350fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 3366582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung if (profileFilter) { 3376582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung // Check how fast sample rate changes are that require filter changes. 3386582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung // The delta sample rate changes must indicate a downsampling ratio, 3396582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung // and must be larger than 10% changes. 3406582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung // 3416582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung // On fast devices, filters should be generated between 0.1ms - 1ms. 3426582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung // (single threaded). 343781366833a12877b8d5ad4aa081114e30f799319Andy Hung AudioResampler* resampler = AudioResampler::create(bit_depth, channels, 3446582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung 8000, quality); 3456582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung int looplimit = 100; 3460fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian timespec start, end; 347da1a325bc0a1421f4233e62704da4fab8b0acf7bGlenn Kasten clock_gettime(CLOCK_MONOTONIC, &start); 34886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung for (int i = 0; i < looplimit; ++i) { 3496582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung resampler->setSampleRate(9000); 3506582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung resampler->setSampleRate(12000); 3516582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung resampler->setSampleRate(20000); 3526582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung resampler->setSampleRate(30000); 35386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung } 354da1a325bc0a1421f4233e62704da4fab8b0acf7bGlenn Kasten clock_gettime(CLOCK_MONOTONIC, &end); 3550fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian int64_t start_ns = start.tv_sec * 1000000000LL + start.tv_nsec; 3560fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian int64_t end_ns = end.tv_sec * 1000000000LL + end.tv_nsec; 35786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung int64_t time = end_ns - start_ns; 3586582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung printf("%.2f sample rate changes with filter calculation/sec\n", 3596582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung looplimit * 4 / (time / 1e9)); 3606582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung 3616582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung // Check how fast sample rate changes are without filter changes. 3626582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung // This should be very fast, probably 0.1us - 1us per sample rate 3636582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung // change. 3646582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung resampler->setSampleRate(1000); 3656582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung looplimit = 1000; 3666582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung clock_gettime(CLOCK_MONOTONIC, &start); 3676582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung for (int i = 0; i < looplimit; ++i) { 3686582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung resampler->setSampleRate(1000+i); 3696582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung } 3706582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung clock_gettime(CLOCK_MONOTONIC, &end); 3716582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung start_ns = start.tv_sec * 1000000000LL + start.tv_nsec; 3726582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung end_ns = end.tv_sec * 1000000000LL + end.tv_nsec; 3736582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung time = end_ns - start_ns; 3746582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung printf("%.2f sample rate changes without filter calculation/sec\n", 3756582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung looplimit / (time / 1e9)); 3766582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung resampler->reset(); 3776582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung delete resampler; 3786582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung } 3796582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung 3806582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung void* output_vaddr = malloc(output_size); 381781366833a12877b8d5ad4aa081114e30f799319Andy Hung AudioResampler* resampler = AudioResampler::create(bit_depth, channels, 3826582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung output_freq, quality); 3836582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung size_t out_frames = output_size/8; 3846582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung 3856582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung /* set volume precision to 12 bits, so the volume scale is 1<<12. 38684a0c6e87c48f58a0d3be71961432c086a4d24ccAndy Hung * The output int32_t is represented as Q4.27, with 4 bits of guard 38784a0c6e87c48f58a0d3be71961432c086a4d24ccAndy Hung * followed by the int16_t Q.15 portion, and then 12 trailing bits of 38884a0c6e87c48f58a0d3be71961432c086a4d24ccAndy Hung * additional precision. 3896582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * 3906582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * Generally 0 < volumePrecision <= 14 (due to the limits of 3916582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * int16_t values for Volume). volumePrecision cannot be 0 due 3926582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * to rounding and shifts. 3936582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung */ 3946582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung const int volumePrecision = 12; // in bits 3956582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung 3966582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung resampler->setSampleRate(input_freq); 3976582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung resampler->setVolume(1 << volumePrecision, 1 << volumePrecision); 3986582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung 3996582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung if (profileResample) { 4006582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung /* 4016582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * For profiling on mobile devices, upon experimentation 4026582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * it is better to run a few trials with a shorter loop limit, 4036582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * and take the minimum time. 4046582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * 4056582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * Long tests can cause CPU temperature to build up and thermal throttling 4066582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * to reduce CPU frequency. 4076582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * 4086582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * For frequency checks (index=0, or 1, etc.): 4096582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * "cat /sys/devices/system/cpu/cpu${index}/cpufreq/scaling_*_freq" 4106582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * 4116582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * For temperature checks (index=0, or 1, etc.): 4126582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * "cat /sys/class/thermal/thermal_zone${index}/temp" 4136582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * 4146582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * Another way to avoid thermal throttling is to fix the CPU frequency 4156582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * at a lower level which prevents excessive temperatures. 4166582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung */ 4176582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung const int trials = 4; 4186582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung const int looplimit = 4; 4196582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung timespec start, end; 4201e4e4f40b4e2c655ca377adbba53df897545c3aeGlenn Kasten int64_t time = 0; 4216582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung 4226582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung for (int n = 0; n < trials; ++n) { 4236582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung clock_gettime(CLOCK_MONOTONIC, &start); 4246582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung for (int i = 0; i < looplimit; ++i) { 4256582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung resampler->resample((int*) output_vaddr, out_frames, &provider); 4266582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung provider.reset(); // during benchmarking reset only the provider 4276582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung } 4286582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung clock_gettime(CLOCK_MONOTONIC, &end); 4296582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung int64_t start_ns = start.tv_sec * 1000000000LL + start.tv_nsec; 4306582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung int64_t end_ns = end.tv_sec * 1000000000LL + end.tv_nsec; 4316582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung int64_t diff_ns = end_ns - start_ns; 4326582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung if (n == 0 || diff_ns < time) { 4336582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung time = diff_ns; // save the best out of our trials. 4346582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung } 4356582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung } 4366582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung // Mfrms/s is "Millions of output frames per second". 4371e4e4f40b4e2c655ca377adbba53df897545c3aeGlenn Kasten printf("quality: %d channels: %d msec: %" PRId64 " Mfrms/s: %.2lf\n", 4386582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung quality, channels, time/1000000, out_frames * looplimit / (time / 1e9) / 1e6); 43986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung resampler->reset(); 4400fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian } 4410fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 4423f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian memset(output_vaddr, 0, output_size); 443e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten if (gVerbose) { 4441e4e4f40b4e2c655ca377adbba53df897545c3aeGlenn Kasten printf("resample() %zu output frames\n", out_frames); 445e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten } 446c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten if (Ovalues.isEmpty()) { 447c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten Ovalues.push(out_frames); 44856df9ff31d583ad3eae4f279a3df550273c58e1eGlenn Kasten } 449c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten for (size_t i = 0, j = 0; i < out_frames; ) { 450c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten size_t thisFrames = Ovalues[j++]; 451c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten if (j >= Ovalues.size()) { 452c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten j = 0; 453c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten } 454c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten if (thisFrames == 0 || thisFrames > out_frames - i) { 455c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten thisFrames = out_frames - i; 456c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten } 45756df9ff31d583ad3eae4f279a3df550273c58e1eGlenn Kasten resampler->resample((int*) output_vaddr + 2*i, thisFrames, &provider); 45856df9ff31d583ad3eae4f279a3df550273c58e1eGlenn Kasten i += thisFrames; 45956df9ff31d583ad3eae4f279a3df550273c58e1eGlenn Kasten } 460e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten if (gVerbose) { 461e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten printf("resample() complete\n"); 462e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten } 463e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten resampler->reset(); 464e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten if (gVerbose) { 465e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten printf("reset() complete\n"); 466e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten } 4676582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung delete resampler; 4686582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung resampler = NULL; 4693f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian 470781366833a12877b8d5ad4aa081114e30f799319Andy Hung // For float processing, convert output format from float to Q4.27, 471781366833a12877b8d5ad4aa081114e30f799319Andy Hung // which is then converted to int16_t for final storage. 472781366833a12877b8d5ad4aa081114e30f799319Andy Hung if (useFloat) { 473781366833a12877b8d5ad4aa081114e30f799319Andy Hung memcpy_to_q4_27_from_float(reinterpret_cast<int32_t*>(output_vaddr), 474781366833a12877b8d5ad4aa081114e30f799319Andy Hung reinterpret_cast<float*>(output_vaddr), out_frames * 2); // stereo samples 475781366833a12877b8d5ad4aa081114e30f799319Andy Hung } 476781366833a12877b8d5ad4aa081114e30f799319Andy Hung 47786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung // mono takes left channel only 47886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung // stereo right channel is half amplitude of stereo left channel (due to input creation) 4790fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian int32_t* out = (int32_t*) output_vaddr; 4803f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian int16_t* convert = (int16_t*) malloc(out_frames * channels * sizeof(int16_t)); 48186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung 4826582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung // round to half towards zero and saturate at int16 (non-dithered) 4836582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung const int roundVal = (1<<(volumePrecision-1)) - 1; // volumePrecision > 0 4846582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung 4850fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian for (size_t i = 0; i < out_frames; i++) { 48686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung for (int j = 0; j < channels; j++) { 4876582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung int32_t s = out[i * 2 + j] + roundVal; // add offset here 4886582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung if (s < 0) { 4896582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung s = (s + 1) >> volumePrecision; // round to 0 4906582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung if (s < -32768) { 4916582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung s = -32768; 4926582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung } 4936582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung } else { 4946582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung s = s >> volumePrecision; 4956582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung if (s > 32767) { 4966582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung s = 32767; 4976582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung } 4986582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung } 4993f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian convert[i * channels + j] = int16_t(s); 5003f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian } 5010fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian } 5020fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 5030fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian // write output to disk 5040fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian if (writeHeader) { 505f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten SF_INFO info; 506f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten info.frames = 0; 507f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten info.samplerate = output_freq; 508f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten info.channels = channels; 509f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; 510f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten SNDFILE *sf = sf_open(file_out, SFM_WRITE, &info); 511f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten if (sf == NULL) { 512f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten perror(file_out); 513f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten return EXIT_FAILURE; 514f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten } 515f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten (void) sf_writef_short(sf, convert, out_frames); 516f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten sf_close(sf); 517f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten } else { 518f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten int output_fd = open(file_out, O_WRONLY | O_CREAT | O_TRUNC, 519f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 520f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten if (output_fd < 0) { 521f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten perror(file_out); 522f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten return EXIT_FAILURE; 523f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten } 524f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten write(output_fd, convert, out_frames * channels * sizeof(int16_t)); 525f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten close(output_fd); 5260fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian } 5270fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 528f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten return EXIT_SUCCESS; 5290fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian} 530