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 <unistd.h> 180fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian#include <stdio.h> 190fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian#include <stdlib.h> 200fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian#include <fcntl.h> 210fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian#include <string.h> 220fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian#include <sys/mman.h> 230fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian#include <sys/stat.h> 240fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian#include <errno.h> 251e4e4f40b4e2c655ca377adbba53df897545c3aeGlenn Kasten#include <inttypes.h> 260fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian#include <time.h> 273f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian#include <math.h> 28781366833a12877b8d5ad4aa081114e30f799319Andy Hung#include <audio_utils/primitives.h> 29f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten#include <audio_utils/sndfile.h> 30c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten#include <utils/Vector.h> 313348e36c51e91e78020bcc6578eda83d97c31becAndy Hung#include <media/AudioBufferProvider.h> 32068561c8e84569d51df2adbbb53b56fdfd09c06bAndy Hung#include <media/AudioResampler.h> 330fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 340fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopianusing namespace android; 350fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 36781366833a12877b8d5ad4aa081114e30f799319Andy Hungstatic bool gVerbose = false; 37e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten 380fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopianstatic int usage(const char* name) { 39df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung fprintf(stderr,"Usage: %s [-p] [-f] [-F] [-v] [-c channels]" 40df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung " [-q {dq|lq|mq|hq|vhq|dlq|dmq|dhq}]" 41781366833a12877b8d5ad4aa081114e30f799319Andy Hung " [-i input-sample-rate] [-o output-sample-rate]" 42781366833a12877b8d5ad4aa081114e30f799319Andy Hung " [-O csv] [-P csv] [<input-file>]" 4386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung " <output-file>\n", name); 443f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian fprintf(stderr," -p enable profiling\n"); 45781366833a12877b8d5ad4aa081114e30f799319Andy Hung fprintf(stderr," -f enable filter profiling\n"); 46781366833a12877b8d5ad4aa081114e30f799319Andy Hung fprintf(stderr," -F enable floating point -q {dlq|dmq|dhq} only"); 47e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten fprintf(stderr," -v verbose : log buffer provider calls\n"); 48df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung fprintf(stderr," -c # channels (1-2 for lq|mq|hq; 1-8 for dlq|dmq|dhq)\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[]) { 1053f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian const char* const progname = argv[0]; 1066582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung bool profileResample = false; 1076582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung bool profileFilter = false; 108781366833a12877b8d5ad4aa081114e30f799319Andy Hung bool useFloat = false; 1093f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian int channels = 1; 1100fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian int input_freq = 0; 1110fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian int output_freq = 0; 1120fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian AudioResampler::src_quality quality = AudioResampler::DEFAULT_QUALITY; 113c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten Vector<int> Ovalues; 114c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten Vector<int> Pvalues; 1150fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 1160fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian int ch; 117df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung while ((ch = getopt(argc, argv, "pfFvc:q:i:o:O:P:")) != -1) { 1180fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian switch (ch) { 1190fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian case 'p': 1206582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung profileResample = true; 1216582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung break; 1226582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung case 'f': 1236582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung profileFilter = true; 1240fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian break; 125781366833a12877b8d5ad4aa081114e30f799319Andy Hung case 'F': 126781366833a12877b8d5ad4aa081114e30f799319Andy Hung useFloat = true; 127781366833a12877b8d5ad4aa081114e30f799319Andy Hung break; 128e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten case 'v': 129e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten gVerbose = true; 130e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten break; 131df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung case 'c': 132df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung channels = atoi(optarg); 1333f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian break; 1340fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian case 'q': 1350fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian if (!strcmp(optarg, "dq")) 1360fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian quality = AudioResampler::DEFAULT_QUALITY; 1370fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian else if (!strcmp(optarg, "lq")) 1380fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian quality = AudioResampler::LOW_QUALITY; 1390fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian else if (!strcmp(optarg, "mq")) 1400fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian quality = AudioResampler::MED_QUALITY; 1410fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian else if (!strcmp(optarg, "hq")) 1420fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian quality = AudioResampler::HIGH_QUALITY; 1430fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian else if (!strcmp(optarg, "vhq")) 1440fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian quality = AudioResampler::VERY_HIGH_QUALITY; 14586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung else if (!strcmp(optarg, "dlq")) 14686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung quality = AudioResampler::DYN_LOW_QUALITY; 14786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung else if (!strcmp(optarg, "dmq")) 14886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung quality = AudioResampler::DYN_MED_QUALITY; 14986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung else if (!strcmp(optarg, "dhq")) 15086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung quality = AudioResampler::DYN_HIGH_QUALITY; 1510fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian else { 1523f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian usage(progname); 1530fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian return -1; 1540fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian } 1550fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian break; 1560fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian case 'i': 1570fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian input_freq = atoi(optarg); 1580fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian break; 1590fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian case 'o': 1600fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian output_freq = atoi(optarg); 1610fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian break; 16256df9ff31d583ad3eae4f279a3df550273c58e1eGlenn Kasten case 'O': 163c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten if (parseCSV(optarg, Ovalues) < 0) { 164c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten fprintf(stderr, "incorrect syntax for -O option\n"); 165c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten return -1; 166c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten } 167c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten break; 168c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten case 'P': 169c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten if (parseCSV(optarg, Pvalues) < 0) { 170c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten fprintf(stderr, "incorrect syntax for -P option\n"); 171c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten return -1; 172c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten } 17356df9ff31d583ad3eae4f279a3df550273c58e1eGlenn Kasten break; 1740fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian case '?': 1750fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian default: 1763f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian usage(progname); 1770fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian return -1; 1780fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian } 1790fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian } 180781366833a12877b8d5ad4aa081114e30f799319Andy Hung 181df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung if (channels < 1 182df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung || channels > (quality < AudioResampler::DYN_LOW_QUALITY ? 2 : 8)) { 183df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung fprintf(stderr, "invalid number of audio channels %d\n", channels); 184df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung return -1; 185df383a5a54582811e5e038efc557172b8ec69dd1Andy 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); 237df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung for (int j = 0; j < channels; j++) { 238df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung in[i*channels + j] = yi / (1 + j); 2393f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian } 2403f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian } 2410fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian } 242df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung size_t input_framesize = channels * sizeof(int16_t); 243df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung size_t input_frames = input_size / input_framesize; 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 249df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung input_framesize = channels * sizeof(float); 250df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung input_size = input_frames * input_framesize; 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 } 275d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten virtual status_t getNextBuffer(Buffer* buffer) { 276e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten size_t requestedFrames = buffer->frameCount; 277e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten if (requestedFrames > mNumFrames - mNextFrame) { 278e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten buffer->frameCount = mNumFrames - mNextFrame; 279e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten } 280c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten if (!mPvalues.isEmpty()) { 281c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten size_t provided = mPvalues[mNextPidx++]; 2821e4e4f40b4e2c655ca377adbba53df897545c3aeGlenn Kasten printf("mPvalue[%zu]=%zu not %zu\n", mNextPidx-1, provided, buffer->frameCount); 283c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten if (provided < buffer->frameCount) { 284c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten buffer->frameCount = provided; 285c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten } 286c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten if (mNextPidx >= mPvalues.size()) { 287c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten mNextPidx = 0; 288c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten } 289c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten } 290e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten if (gVerbose) { 2911e4e4f40b4e2c655ca377adbba53df897545c3aeGlenn Kasten printf("getNextBuffer() requested %zu frames out of %zu frames available," 2921e4e4f40b4e2c655ca377adbba53df897545c3aeGlenn Kasten " and returned %zu frames\n", 2931e4e4f40b4e2c655ca377adbba53df897545c3aeGlenn Kasten requestedFrames, (size_t) (mNumFrames - mNextFrame), buffer->frameCount); 294e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten } 295e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten mUnrel = buffer->frameCount; 296e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten if (buffer->frameCount > 0) { 297781366833a12877b8d5ad4aa081114e30f799319Andy Hung buffer->raw = (char *)mAddr + mFrameSize * mNextFrame; 298e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten return NO_ERROR; 299e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten } else { 300781366833a12877b8d5ad4aa081114e30f799319Andy Hung buffer->raw = NULL; 301e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten return NOT_ENOUGH_DATA; 302e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten } 3030fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian } 3040fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian virtual void releaseBuffer(Buffer* buffer) { 305e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten if (buffer->frameCount > mUnrel) { 3061e4e4f40b4e2c655ca377adbba53df897545c3aeGlenn Kasten fprintf(stderr, "ERROR releaseBuffer() released %zu frames but only %zu available " 307e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten "to release\n", buffer->frameCount, mUnrel); 308e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten mNextFrame += mUnrel; 309e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten mUnrel = 0; 310e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten } else { 311e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten if (gVerbose) { 3121e4e4f40b4e2c655ca377adbba53df897545c3aeGlenn Kasten printf("releaseBuffer() released %zu frames out of %zu frames available " 313e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten "to release\n", buffer->frameCount, mUnrel); 314e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten } 315e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten mNextFrame += buffer->frameCount; 316e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten mUnrel -= buffer->frameCount; 317e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten } 31847f3f5a119194d4c06815453be9950ba112c8e3eGlenn Kasten buffer->frameCount = 0; 319781366833a12877b8d5ad4aa081114e30f799319Andy Hung buffer->raw = NULL; 3200fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian } 32186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung void reset() { 32286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung mNextFrame = 0; 32386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung } 324df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung } provider(input_vaddr, input_frames, input_framesize, Pvalues); 3250fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 326e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten if (gVerbose) { 3271e4e4f40b4e2c655ca377adbba53df897545c3aeGlenn Kasten printf("%zu input frames\n", input_frames); 328e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten } 329781366833a12877b8d5ad4aa081114e30f799319Andy Hung 3303348e36c51e91e78020bcc6578eda83d97c31becAndy Hung audio_format_t format = useFloat ? AUDIO_FORMAT_PCM_FLOAT : AUDIO_FORMAT_PCM_16_BIT; 331df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung int output_channels = channels > 2 ? channels : 2; // output is at least stereo samples 332df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung size_t output_framesize = output_channels * (useFloat ? sizeof(float) : sizeof(int32_t)); 333df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung size_t output_frames = ((int64_t) input_frames * output_freq) / input_freq; 334df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung size_t output_size = output_frames * output_framesize; 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). 3433348e36c51e91e78020bcc6578eda83d97c31becAndy Hung AudioResampler* resampler = AudioResampler::create(format, 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); 3813348e36c51e91e78020bcc6578eda83d97c31becAndy Hung AudioResampler* resampler = AudioResampler::create(format, channels, 3826582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung output_freq, quality); 383df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung 3846582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung resampler->setSampleRate(input_freq); 3855e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung resampler->setVolume(AudioResampler::UNITY_GAIN_FLOAT, AudioResampler::UNITY_GAIN_FLOAT); 3866582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung 3876582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung if (profileResample) { 3886582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung /* 3896582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * For profiling on mobile devices, upon experimentation 3906582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * it is better to run a few trials with a shorter loop limit, 3916582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * and take the minimum time. 3926582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * 3936582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * Long tests can cause CPU temperature to build up and thermal throttling 3946582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * to reduce CPU frequency. 3956582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * 3966582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * For frequency checks (index=0, or 1, etc.): 3976582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * "cat /sys/devices/system/cpu/cpu${index}/cpufreq/scaling_*_freq" 3986582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * 3996582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * For temperature checks (index=0, or 1, etc.): 4006582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * "cat /sys/class/thermal/thermal_zone${index}/temp" 4016582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * 4026582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * Another way to avoid thermal throttling is to fix the CPU frequency 4036582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung * at a lower level which prevents excessive temperatures. 4046582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung */ 4056582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung const int trials = 4; 4066582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung const int looplimit = 4; 4076582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung timespec start, end; 4081e4e4f40b4e2c655ca377adbba53df897545c3aeGlenn Kasten int64_t time = 0; 4096582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung 4106582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung for (int n = 0; n < trials; ++n) { 4116582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung clock_gettime(CLOCK_MONOTONIC, &start); 4126582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung for (int i = 0; i < looplimit; ++i) { 413df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung resampler->resample((int*) output_vaddr, output_frames, &provider); 4146582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung provider.reset(); // during benchmarking reset only the provider 4156582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung } 4166582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung clock_gettime(CLOCK_MONOTONIC, &end); 4176582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung int64_t start_ns = start.tv_sec * 1000000000LL + start.tv_nsec; 4186582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung int64_t end_ns = end.tv_sec * 1000000000LL + end.tv_nsec; 4196582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung int64_t diff_ns = end_ns - start_ns; 4206582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung if (n == 0 || diff_ns < time) { 4216582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung time = diff_ns; // save the best out of our trials. 4226582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung } 4236582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung } 4246582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung // Mfrms/s is "Millions of output frames per second". 4251e4e4f40b4e2c655ca377adbba53df897545c3aeGlenn Kasten printf("quality: %d channels: %d msec: %" PRId64 " Mfrms/s: %.2lf\n", 426df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung quality, channels, time/1000000, output_frames * looplimit / (time / 1e9) / 1e6); 42786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung resampler->reset(); 4286b667dde03a5707285a2ff76ada525075d4c60efAndy Hung 4296b667dde03a5707285a2ff76ada525075d4c60efAndy Hung // TODO fix legacy bug: reset does not clear buffers. 4306b667dde03a5707285a2ff76ada525075d4c60efAndy Hung // delete and recreate resampler here. 4316b667dde03a5707285a2ff76ada525075d4c60efAndy Hung delete resampler; 4326b667dde03a5707285a2ff76ada525075d4c60efAndy Hung resampler = AudioResampler::create(format, channels, 4336b667dde03a5707285a2ff76ada525075d4c60efAndy Hung output_freq, quality); 4346b667dde03a5707285a2ff76ada525075d4c60efAndy Hung resampler->setSampleRate(input_freq); 4356b667dde03a5707285a2ff76ada525075d4c60efAndy Hung resampler->setVolume(AudioResampler::UNITY_GAIN_FLOAT, AudioResampler::UNITY_GAIN_FLOAT); 4360fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian } 4370fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 4383f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian memset(output_vaddr, 0, output_size); 439e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten if (gVerbose) { 440df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung printf("resample() %zu output frames\n", output_frames); 441e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten } 442c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten if (Ovalues.isEmpty()) { 443df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung Ovalues.push(output_frames); 44456df9ff31d583ad3eae4f279a3df550273c58e1eGlenn Kasten } 445df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung for (size_t i = 0, j = 0; i < output_frames; ) { 446c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten size_t thisFrames = Ovalues[j++]; 447c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten if (j >= Ovalues.size()) { 448c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten j = 0; 449c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten } 450df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung if (thisFrames == 0 || thisFrames > output_frames - i) { 451df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung thisFrames = output_frames - i; 452c52b033f0be38ca915d389b672bcf9c46b4c78efGlenn Kasten } 453df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung resampler->resample((int*) output_vaddr + output_channels*i, thisFrames, &provider); 45456df9ff31d583ad3eae4f279a3df550273c58e1eGlenn Kasten i += thisFrames; 45556df9ff31d583ad3eae4f279a3df550273c58e1eGlenn Kasten } 456e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten if (gVerbose) { 457e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten printf("resample() complete\n"); 458e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten } 459e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten resampler->reset(); 460e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten if (gVerbose) { 461e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten printf("reset() complete\n"); 462e00eefe64e3bad166c672db96c9c35992766e819Glenn Kasten } 4636582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung delete resampler; 4646582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung resampler = NULL; 4653f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian 466781366833a12877b8d5ad4aa081114e30f799319Andy Hung // For float processing, convert output format from float to Q4.27, 467781366833a12877b8d5ad4aa081114e30f799319Andy Hung // which is then converted to int16_t for final storage. 468781366833a12877b8d5ad4aa081114e30f799319Andy Hung if (useFloat) { 469781366833a12877b8d5ad4aa081114e30f799319Andy Hung memcpy_to_q4_27_from_float(reinterpret_cast<int32_t*>(output_vaddr), 470df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung reinterpret_cast<float*>(output_vaddr), output_frames * output_channels); 471781366833a12877b8d5ad4aa081114e30f799319Andy Hung } 472781366833a12877b8d5ad4aa081114e30f799319Andy Hung 473df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung // mono takes left channel only (out of stereo output pair) 474df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung // stereo and multichannel preserve all channels. 4750fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian int32_t* out = (int32_t*) output_vaddr; 476df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung int16_t* convert = (int16_t*) malloc(output_frames * channels * sizeof(int16_t)); 47786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung 4785e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung const int volumeShift = 12; // shift requirement for Q4.27 to Q.15 4796582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung // round to half towards zero and saturate at int16 (non-dithered) 4805e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung const int roundVal = (1<<(volumeShift-1)) - 1; // volumePrecision > 0 4816582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung 482df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung for (size_t i = 0; i < output_frames; i++) { 48386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung for (int j = 0; j < channels; j++) { 484df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung int32_t s = out[i * output_channels + j] + roundVal; // add offset here 4856582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung if (s < 0) { 4865e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung s = (s + 1) >> volumeShift; // round to 0 4876582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung if (s < -32768) { 4886582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung s = -32768; 4896582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung } 4906582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung } else { 4915e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung s = s >> volumeShift; 4926582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung if (s > 32767) { 4936582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung s = 32767; 4946582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung } 4956582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung } 4963f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian convert[i * channels + j] = int16_t(s); 4973f71761cab8a08e4ae9e4cf8cb8f1b82643825b2Mathias Agopian } 4980fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian } 4990fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 5000fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian // write output to disk 501df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung SF_INFO info; 502df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung info.frames = 0; 503df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung info.samplerate = output_freq; 504df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung info.channels = channels; 505df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; 506df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung SNDFILE *sf = sf_open(file_out, SFM_WRITE, &info); 507df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung if (sf == NULL) { 508df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung perror(file_out); 509df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung return EXIT_FAILURE; 5100fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian } 511df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung (void) sf_writef_short(sf, convert, output_frames); 512df383a5a54582811e5e038efc557172b8ec69dd1Andy Hung sf_close(sf); 5130fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian 514f5293648b727fb3909cd2300a73377f032f8b050Glenn Kasten return EXIT_SUCCESS; 5150fc2cb59d5f77412f5922540d67fea81f4d1744bMathias Agopian} 516