test-resample.cpp revision bd72d22097f78f5bd668b223bc8c94e351311e31
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}] [-i input-sample-rate] " 37 "[-o output-sample-rate] [<input-file>] <output-file>\n", name); 38 fprintf(stderr," -p enable profiling\n"); 39 fprintf(stderr," -h create wav file\n"); 40 fprintf(stderr," -v verbose : log buffer provider calls\n"); 41 fprintf(stderr," -s stereo (ignored if input file is specified)\n"); 42 fprintf(stderr," -q resampler quality\n"); 43 fprintf(stderr," dq : default quality\n"); 44 fprintf(stderr," lq : low quality\n"); 45 fprintf(stderr," mq : medium quality\n"); 46 fprintf(stderr," hq : high quality\n"); 47 fprintf(stderr," vhq : very high quality\n"); 48 fprintf(stderr," -i input file sample rate (ignored if input file is specified)\n"); 49 fprintf(stderr," -o output file sample rate\n"); 50 return -1; 51} 52 53int main(int argc, char* argv[]) { 54 55 const char* const progname = argv[0]; 56 bool profiling = false; 57 bool writeHeader = false; 58 int channels = 1; 59 int input_freq = 0; 60 int output_freq = 0; 61 AudioResampler::src_quality quality = AudioResampler::DEFAULT_QUALITY; 62 63 int ch; 64 while ((ch = getopt(argc, argv, "phvsq:i:o:")) != -1) { 65 switch (ch) { 66 case 'p': 67 profiling = true; 68 break; 69 case 'h': 70 writeHeader = true; 71 break; 72 case 'v': 73 gVerbose = true; 74 break; 75 case 's': 76 channels = 2; 77 break; 78 case 'q': 79 if (!strcmp(optarg, "dq")) 80 quality = AudioResampler::DEFAULT_QUALITY; 81 else if (!strcmp(optarg, "lq")) 82 quality = AudioResampler::LOW_QUALITY; 83 else if (!strcmp(optarg, "mq")) 84 quality = AudioResampler::MED_QUALITY; 85 else if (!strcmp(optarg, "hq")) 86 quality = AudioResampler::HIGH_QUALITY; 87 else if (!strcmp(optarg, "vhq")) 88 quality = AudioResampler::VERY_HIGH_QUALITY; 89 else { 90 usage(progname); 91 return -1; 92 } 93 break; 94 case 'i': 95 input_freq = atoi(optarg); 96 break; 97 case 'o': 98 output_freq = atoi(optarg); 99 break; 100 case '?': 101 default: 102 usage(progname); 103 return -1; 104 } 105 } 106 argc -= optind; 107 argv += optind; 108 109 const char* file_in = NULL; 110 const char* file_out = NULL; 111 if (argc == 1) { 112 file_out = argv[0]; 113 } else if (argc == 2) { 114 file_in = argv[0]; 115 file_out = argv[1]; 116 } else { 117 usage(progname); 118 return -1; 119 } 120 121 // ---------------------------------------------------------- 122 123 size_t input_size; 124 void* input_vaddr; 125 if (argc == 2) { 126 SF_INFO info; 127 info.format = 0; 128 SNDFILE *sf = sf_open(file_in, SFM_READ, &info); 129 if (sf == NULL) { 130 perror(file_in); 131 return EXIT_FAILURE; 132 } 133 input_size = info.frames * info.channels * sizeof(short); 134 input_vaddr = malloc(input_size); 135 (void) sf_readf_short(sf, (short *) input_vaddr, info.frames); 136 sf_close(sf); 137 channels = info.channels; 138 input_freq = info.samplerate; 139 } else { 140 double k = 1000; // Hz / s 141 double time = (input_freq / 2) / k; 142 size_t input_frames = size_t(input_freq * time); 143 input_size = channels * sizeof(int16_t) * input_frames; 144 input_vaddr = malloc(input_size); 145 int16_t* in = (int16_t*)input_vaddr; 146 for (size_t i=0 ; i<input_frames ; i++) { 147 double t = double(i) / input_freq; 148 double y = sin(M_PI * k * t * t); 149 int16_t yi = floor(y * 32767.0 + 0.5); 150 for (size_t j=0 ; j<(size_t)channels ; j++) { 151 in[i*channels + j] = yi / (1+j); 152 } 153 } 154 } 155 156 // ---------------------------------------------------------- 157 158 class Provider: public AudioBufferProvider { 159 int16_t* const mAddr; // base address 160 const size_t mNumFrames; // total frames 161 const int mChannels; 162 size_t mNextFrame; // index of next frame to provide 163 size_t mUnrel; // number of frames not yet released 164 public: 165 Provider(const void* addr, size_t size, int channels) 166 : mAddr((int16_t*) addr), 167 mNumFrames(size / (channels*sizeof(int16_t))), 168 mChannels(channels), 169 mNextFrame(0), mUnrel(0) { 170 } 171 virtual status_t getNextBuffer(Buffer* buffer, 172 int64_t pts = kInvalidPTS) { 173 size_t requestedFrames = buffer->frameCount; 174 if (requestedFrames > mNumFrames - mNextFrame) { 175 buffer->frameCount = mNumFrames - mNextFrame; 176 } 177 if (gVerbose) { 178 printf("getNextBuffer() requested %u frames out of %u frames available," 179 " and returned %u frames\n", 180 requestedFrames, mNumFrames - mNextFrame, buffer->frameCount); 181 } 182 mUnrel = buffer->frameCount; 183 if (buffer->frameCount > 0) { 184 buffer->i16 = &mAddr[mChannels * mNextFrame]; 185 return NO_ERROR; 186 } else { 187 buffer->i16 = NULL; 188 return NOT_ENOUGH_DATA; 189 } 190 } 191 virtual void releaseBuffer(Buffer* buffer) { 192 if (buffer->frameCount > mUnrel) { 193 fprintf(stderr, "ERROR releaseBuffer() released %u frames but only %u available " 194 "to release\n", buffer->frameCount, mUnrel); 195 mNextFrame += mUnrel; 196 mUnrel = 0; 197 } else { 198 if (gVerbose) { 199 printf("releaseBuffer() released %u frames out of %u frames available " 200 "to release\n", buffer->frameCount, mUnrel); 201 } 202 mNextFrame += buffer->frameCount; 203 mUnrel -= buffer->frameCount; 204 } 205 } 206 } provider(input_vaddr, input_size, channels); 207 208 size_t input_frames = input_size / (channels * sizeof(int16_t)); 209 if (gVerbose) { 210 printf("%u input frames\n", input_frames); 211 } 212 size_t output_size = 2 * 4 * ((int64_t) input_frames * output_freq) / input_freq; 213 output_size &= ~7; // always stereo, 32-bits 214 215 void* output_vaddr = malloc(output_size); 216 217 if (profiling) { 218 AudioResampler* resampler = AudioResampler::create(16, channels, 219 output_freq, quality); 220 221 size_t out_frames = output_size/8; 222 resampler->setSampleRate(input_freq); 223 resampler->setVolume(0x1000, 0x1000); 224 225 memset(output_vaddr, 0, output_size); 226 timespec start, end; 227 clock_gettime(CLOCK_MONOTONIC, &start); 228 resampler->resample((int*) output_vaddr, out_frames, &provider); 229 resampler->resample((int*) output_vaddr, out_frames, &provider); 230 resampler->resample((int*) output_vaddr, out_frames, &provider); 231 resampler->resample((int*) output_vaddr, out_frames, &provider); 232 clock_gettime(CLOCK_MONOTONIC, &end); 233 int64_t start_ns = start.tv_sec * 1000000000LL + start.tv_nsec; 234 int64_t end_ns = end.tv_sec * 1000000000LL + end.tv_nsec; 235 int64_t time = (end_ns - start_ns)/4; 236 printf("%f Mspl/s\n", out_frames/(time/1e9)/1e6); 237 238 delete resampler; 239 } 240 241 AudioResampler* resampler = AudioResampler::create(16, channels, 242 output_freq, quality); 243 size_t out_frames = output_size/8; 244 resampler->setSampleRate(input_freq); 245 resampler->setVolume(0x1000, 0x1000); 246 247 memset(output_vaddr, 0, output_size); 248 if (gVerbose) { 249 printf("resample() %u output frames\n", out_frames); 250 } 251 resampler->resample((int*) output_vaddr, out_frames, &provider); 252 if (gVerbose) { 253 printf("resample() complete\n"); 254 } 255 resampler->reset(); 256 if (gVerbose) { 257 printf("reset() complete\n"); 258 } 259 260 // down-mix (we just truncate and keep the left channel) 261 int32_t* out = (int32_t*) output_vaddr; 262 int16_t* convert = (int16_t*) malloc(out_frames * channels * sizeof(int16_t)); 263 for (size_t i = 0; i < out_frames; i++) { 264 for (int j=0 ; j<channels ; j++) { 265 int32_t s = out[i * 2 + j] >> 12; 266 if (s > 32767) s = 32767; 267 else if (s < -32768) s = -32768; 268 convert[i * channels + j] = int16_t(s); 269 } 270 } 271 272 // write output to disk 273 if (writeHeader) { 274 SF_INFO info; 275 info.frames = 0; 276 info.samplerate = output_freq; 277 info.channels = channels; 278 info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; 279 SNDFILE *sf = sf_open(file_out, SFM_WRITE, &info); 280 if (sf == NULL) { 281 perror(file_out); 282 return EXIT_FAILURE; 283 } 284 (void) sf_writef_short(sf, convert, out_frames); 285 sf_close(sf); 286 } else { 287 int output_fd = open(file_out, O_WRONLY | O_CREAT | O_TRUNC, 288 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 289 if (output_fd < 0) { 290 perror(file_out); 291 return EXIT_FAILURE; 292 } 293 write(output_fd, convert, out_frames * channels * sizeof(int16_t)); 294 close(output_fd); 295 } 296 297 return EXIT_SUCCESS; 298} 299