test-resample.cpp revision 86eae0e5931103e040ac2cdd023ef5db252e09f6
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "AudioResampler.h" 18#include <media/AudioBufferProvider.h> 19#include <unistd.h> 20#include <stdio.h> 21#include <stdlib.h> 22#include <fcntl.h> 23#include <string.h> 24#include <sys/mman.h> 25#include <sys/stat.h> 26#include <errno.h> 27#include <time.h> 28#include <math.h> 29#include <audio_utils/sndfile.h> 30 31using namespace android; 32 33bool gVerbose = false; 34 35static int usage(const char* name) { 36 fprintf(stderr,"Usage: %s [-p] [-h] [-v] [-s] [-q {dq|lq|mq|hq|vhq|dlq|dmq|dhq}]" 37 " [-i input-sample-rate] [-o output-sample-rate] [<input-file>]" 38 " <output-file>\n", name); 39 fprintf(stderr," -p enable profiling\n"); 40 fprintf(stderr," -h create wav file\n"); 41 fprintf(stderr," -v verbose : log buffer provider calls\n"); 42 fprintf(stderr," -s stereo (ignored if input file is specified)\n"); 43 fprintf(stderr," -q resampler quality\n"); 44 fprintf(stderr," dq : default quality\n"); 45 fprintf(stderr," lq : low quality\n"); 46 fprintf(stderr," mq : medium quality\n"); 47 fprintf(stderr," hq : high quality\n"); 48 fprintf(stderr," vhq : very high quality\n"); 49 fprintf(stderr," dlq : dynamic low quality\n"); 50 fprintf(stderr," dmq : dynamic medium quality\n"); 51 fprintf(stderr," dhq : dynamic high quality\n"); 52 fprintf(stderr," -i input file sample rate (ignored if input file is specified)\n"); 53 fprintf(stderr," -o output file sample rate\n"); 54 return -1; 55} 56 57int main(int argc, char* argv[]) { 58 59 const char* const progname = argv[0]; 60 bool profiling = false; 61 bool writeHeader = false; 62 int channels = 1; 63 int input_freq = 0; 64 int output_freq = 0; 65 AudioResampler::src_quality quality = AudioResampler::DEFAULT_QUALITY; 66 67 int ch; 68 while ((ch = getopt(argc, argv, "phvsq:i:o:")) != -1) { 69 switch (ch) { 70 case 'p': 71 profiling = true; 72 break; 73 case 'h': 74 writeHeader = true; 75 break; 76 case 'v': 77 gVerbose = true; 78 break; 79 case 's': 80 channels = 2; 81 break; 82 case 'q': 83 if (!strcmp(optarg, "dq")) 84 quality = AudioResampler::DEFAULT_QUALITY; 85 else if (!strcmp(optarg, "lq")) 86 quality = AudioResampler::LOW_QUALITY; 87 else if (!strcmp(optarg, "mq")) 88 quality = AudioResampler::MED_QUALITY; 89 else if (!strcmp(optarg, "hq")) 90 quality = AudioResampler::HIGH_QUALITY; 91 else if (!strcmp(optarg, "vhq")) 92 quality = AudioResampler::VERY_HIGH_QUALITY; 93 else if (!strcmp(optarg, "dlq")) 94 quality = AudioResampler::DYN_LOW_QUALITY; 95 else if (!strcmp(optarg, "dmq")) 96 quality = AudioResampler::DYN_MED_QUALITY; 97 else if (!strcmp(optarg, "dhq")) 98 quality = AudioResampler::DYN_HIGH_QUALITY; 99 else { 100 usage(progname); 101 return -1; 102 } 103 break; 104 case 'i': 105 input_freq = atoi(optarg); 106 break; 107 case 'o': 108 output_freq = atoi(optarg); 109 break; 110 case '?': 111 default: 112 usage(progname); 113 return -1; 114 } 115 } 116 argc -= optind; 117 argv += optind; 118 119 const char* file_in = NULL; 120 const char* file_out = NULL; 121 if (argc == 1) { 122 file_out = argv[0]; 123 } else if (argc == 2) { 124 file_in = argv[0]; 125 file_out = argv[1]; 126 } else { 127 usage(progname); 128 return -1; 129 } 130 131 // ---------------------------------------------------------- 132 133 size_t input_size; 134 void* input_vaddr; 135 if (argc == 2) { 136 SF_INFO info; 137 info.format = 0; 138 SNDFILE *sf = sf_open(file_in, SFM_READ, &info); 139 if (sf == NULL) { 140 perror(file_in); 141 return EXIT_FAILURE; 142 } 143 input_size = info.frames * info.channels * sizeof(short); 144 input_vaddr = malloc(input_size); 145 (void) sf_readf_short(sf, (short *) input_vaddr, info.frames); 146 sf_close(sf); 147 channels = info.channels; 148 input_freq = info.samplerate; 149 } else { 150 // data for testing is exactly (input sampling rate/1000)/2 seconds 151 // so 44.1khz input is 22.05 seconds 152 double k = 1000; // Hz / s 153 double time = (input_freq / 2) / k; 154 size_t input_frames = size_t(input_freq * time); 155 input_size = channels * sizeof(int16_t) * input_frames; 156 input_vaddr = malloc(input_size); 157 int16_t* in = (int16_t*)input_vaddr; 158 for (size_t i=0 ; i<input_frames ; i++) { 159 double t = double(i) / input_freq; 160 double y = sin(M_PI * k * t * t); 161 int16_t yi = floor(y * 32767.0 + 0.5); 162 for (size_t j=0 ; j<(size_t)channels ; j++) { 163 in[i*channels + j] = yi / (1+j); // right ch. 1/2 left ch. 164 } 165 } 166 } 167 168 // ---------------------------------------------------------- 169 170 class Provider: public AudioBufferProvider { 171 int16_t* const mAddr; // base address 172 const size_t mNumFrames; // total frames 173 const int mChannels; 174 size_t mNextFrame; // index of next frame to provide 175 size_t mUnrel; // number of frames not yet released 176 public: 177 Provider(const void* addr, size_t size, int channels) 178 : mAddr((int16_t*) addr), 179 mNumFrames(size / (channels*sizeof(int16_t))), 180 mChannels(channels), 181 mNextFrame(0), mUnrel(0) { 182 } 183 virtual status_t getNextBuffer(Buffer* buffer, 184 int64_t pts = kInvalidPTS) { 185 (void)pts; // suppress warning 186 size_t requestedFrames = buffer->frameCount; 187 if (requestedFrames > mNumFrames - mNextFrame) { 188 buffer->frameCount = mNumFrames - mNextFrame; 189 } 190 if (gVerbose) { 191 printf("getNextBuffer() requested %u frames out of %u frames available," 192 " and returned %u frames\n", 193 requestedFrames, mNumFrames - mNextFrame, buffer->frameCount); 194 } 195 mUnrel = buffer->frameCount; 196 if (buffer->frameCount > 0) { 197 buffer->i16 = &mAddr[mChannels * mNextFrame]; 198 return NO_ERROR; 199 } else { 200 buffer->i16 = NULL; 201 return NOT_ENOUGH_DATA; 202 } 203 } 204 virtual void releaseBuffer(Buffer* buffer) { 205 if (buffer->frameCount > mUnrel) { 206 fprintf(stderr, "ERROR releaseBuffer() released %u frames but only %u available " 207 "to release\n", buffer->frameCount, mUnrel); 208 mNextFrame += mUnrel; 209 mUnrel = 0; 210 } else { 211 if (gVerbose) { 212 printf("releaseBuffer() released %u frames out of %u frames available " 213 "to release\n", buffer->frameCount, mUnrel); 214 } 215 mNextFrame += buffer->frameCount; 216 mUnrel -= buffer->frameCount; 217 } 218 buffer->frameCount = 0; 219 buffer->i16 = NULL; 220 } 221 void reset() { 222 mNextFrame = 0; 223 } 224 } provider(input_vaddr, input_size, channels); 225 226 size_t input_frames = input_size / (channels * sizeof(int16_t)); 227 if (gVerbose) { 228 printf("%u input frames\n", input_frames); 229 } 230 size_t output_size = 2 * 4 * ((int64_t) input_frames * output_freq) / input_freq; 231 output_size &= ~7; // always stereo, 32-bits 232 233 void* output_vaddr = malloc(output_size); 234 AudioResampler* resampler = AudioResampler::create(16, channels, 235 output_freq, quality); 236 size_t out_frames = output_size/8; 237 resampler->setSampleRate(input_freq); 238 resampler->setVolume(0x1000, 0x1000); 239 240 if (profiling) { 241 const int looplimit = 100; 242 timespec start, end; 243 clock_gettime(CLOCK_MONOTONIC, &start); 244 for (int i = 0; i < looplimit; ++i) { 245 resampler->resample((int*) output_vaddr, out_frames, &provider); 246 provider.reset(); // reset only provider as benchmarking 247 } 248 clock_gettime(CLOCK_MONOTONIC, &end); 249 int64_t start_ns = start.tv_sec * 1000000000LL + start.tv_nsec; 250 int64_t end_ns = end.tv_sec * 1000000000LL + end.tv_nsec; 251 int64_t time = end_ns - start_ns; 252 printf("time(ns):%lld channels:%d quality:%d\n", time, channels, quality); 253 printf("%f Mspl/s\n", out_frames * looplimit / (time / 1e9) / 1e6); 254 resampler->reset(); 255 } 256 257 memset(output_vaddr, 0, output_size); 258 if (gVerbose) { 259 printf("resample() %u output frames\n", out_frames); 260 } 261 resampler->resample((int*) output_vaddr, out_frames, &provider); 262 if (gVerbose) { 263 printf("resample() complete\n"); 264 } 265 resampler->reset(); 266 if (gVerbose) { 267 printf("reset() complete\n"); 268 } 269 270 // mono takes left channel only 271 // stereo right channel is half amplitude of stereo left channel (due to input creation) 272 int32_t* out = (int32_t*) output_vaddr; 273 int16_t* convert = (int16_t*) malloc(out_frames * channels * sizeof(int16_t)); 274 275 for (size_t i = 0; i < out_frames; i++) { 276 for (int j = 0; j < channels; j++) { 277 int32_t s = out[i * 2 + j] >> 12; 278 if (s > 32767) 279 s = 32767; 280 else if (s < -32768) 281 s = -32768; 282 convert[i * channels + j] = int16_t(s); 283 } 284 } 285 286 // write output to disk 287 if (writeHeader) { 288 SF_INFO info; 289 info.frames = 0; 290 info.samplerate = output_freq; 291 info.channels = channels; 292 info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; 293 SNDFILE *sf = sf_open(file_out, SFM_WRITE, &info); 294 if (sf == NULL) { 295 perror(file_out); 296 return EXIT_FAILURE; 297 } 298 (void) sf_writef_short(sf, convert, out_frames); 299 sf_close(sf); 300 } else { 301 int output_fd = open(file_out, O_WRONLY | O_CREAT | O_TRUNC, 302 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 303 if (output_fd < 0) { 304 perror(file_out); 305 return EXIT_FAILURE; 306 } 307 write(output_fd, convert, out_frames * channels * sizeof(int16_t)); 308 close(output_fd); 309 } 310 311 return EXIT_SUCCESS; 312} 313