test-resample.cpp revision f5293648b727fb3909cd2300a73377f032f8b050
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\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\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 struct stat st; 127 if (stat(file_in, &st) < 0) { 128 fprintf(stderr, "stat: %s\n", strerror(errno)); 129 return -1; 130 } 131 132 int input_fd = open(file_in, O_RDONLY); 133 if (input_fd < 0) { 134 fprintf(stderr, "open: %s\n", strerror(errno)); 135 return -1; 136 } 137 138 input_size = st.st_size; 139 input_vaddr = mmap(0, input_size, PROT_READ, MAP_PRIVATE, input_fd, 0); 140 if (input_vaddr == MAP_FAILED ) { 141 fprintf(stderr, "mmap: %s\n", strerror(errno)); 142 return -1; 143 } 144 } else { 145 double k = 1000; // Hz / s 146 double time = (input_freq / 2) / k; 147 size_t input_frames = size_t(input_freq * time); 148 input_size = channels * sizeof(int16_t) * input_frames; 149 input_vaddr = malloc(input_size); 150 int16_t* in = (int16_t*)input_vaddr; 151 for (size_t i=0 ; i<input_frames ; i++) { 152 double t = double(i) / input_freq; 153 double y = sin(M_PI * k * t * t); 154 int16_t yi = floor(y * 32767.0 + 0.5); 155 for (size_t j=0 ; j<(size_t)channels ; j++) { 156 in[i*channels + j] = yi / (1+j); 157 } 158 } 159 } 160 161 // ---------------------------------------------------------- 162 163 class Provider: public AudioBufferProvider { 164 int16_t* const mAddr; // base address 165 const size_t mNumFrames; // total frames 166 const int mChannels; 167 size_t mNextFrame; // index of next frame to provide 168 size_t mUnrel; // number of frames not yet released 169 public: 170 Provider(const void* addr, size_t size, int channels) 171 : mAddr((int16_t*) addr), 172 mNumFrames(size / (channels*sizeof(int16_t))), 173 mChannels(channels), 174 mNextFrame(0), mUnrel(0) { 175 } 176 virtual status_t getNextBuffer(Buffer* buffer, 177 int64_t pts = kInvalidPTS) { 178 size_t requestedFrames = buffer->frameCount; 179 if (requestedFrames > mNumFrames - mNextFrame) { 180 buffer->frameCount = mNumFrames - mNextFrame; 181 } 182 if (gVerbose) { 183 printf("getNextBuffer() requested %u frames out of %u frames available," 184 " and returned %u frames\n", 185 requestedFrames, mNumFrames - mNextFrame, buffer->frameCount); 186 } 187 mUnrel = buffer->frameCount; 188 if (buffer->frameCount > 0) { 189 buffer->i16 = &mAddr[mChannels * mNextFrame]; 190 return NO_ERROR; 191 } else { 192 buffer->i16 = NULL; 193 return NOT_ENOUGH_DATA; 194 } 195 } 196 virtual void releaseBuffer(Buffer* buffer) { 197 if (buffer->frameCount > mUnrel) { 198 fprintf(stderr, "ERROR releaseBuffer() released %u frames but only %u available " 199 "to release\n", buffer->frameCount, mUnrel); 200 mNextFrame += mUnrel; 201 mUnrel = 0; 202 } else { 203 if (gVerbose) { 204 printf("releaseBuffer() released %u frames out of %u frames available " 205 "to release\n", buffer->frameCount, mUnrel); 206 } 207 mNextFrame += buffer->frameCount; 208 mUnrel -= buffer->frameCount; 209 } 210 } 211 } provider(input_vaddr, input_size, channels); 212 213 size_t input_frames = input_size / (channels * sizeof(int16_t)); 214 if (gVerbose) { 215 printf("%u input frames\n", input_frames); 216 } 217 size_t output_size = 2 * 4 * ((int64_t) input_frames * output_freq) / input_freq; 218 output_size &= ~7; // always stereo, 32-bits 219 220 void* output_vaddr = malloc(output_size); 221 222 if (profiling) { 223 AudioResampler* resampler = AudioResampler::create(16, channels, 224 output_freq, quality); 225 226 size_t out_frames = output_size/8; 227 resampler->setSampleRate(input_freq); 228 resampler->setVolume(0x1000, 0x1000); 229 230 memset(output_vaddr, 0, output_size); 231 timespec start, end; 232 clock_gettime(CLOCK_MONOTONIC, &start); 233 resampler->resample((int*) output_vaddr, out_frames, &provider); 234 resampler->resample((int*) output_vaddr, out_frames, &provider); 235 resampler->resample((int*) output_vaddr, out_frames, &provider); 236 resampler->resample((int*) output_vaddr, out_frames, &provider); 237 clock_gettime(CLOCK_MONOTONIC, &end); 238 int64_t start_ns = start.tv_sec * 1000000000LL + start.tv_nsec; 239 int64_t end_ns = end.tv_sec * 1000000000LL + end.tv_nsec; 240 int64_t time = (end_ns - start_ns)/4; 241 printf("%f Mspl/s\n", out_frames/(time/1e9)/1e6); 242 243 delete resampler; 244 } 245 246 AudioResampler* resampler = AudioResampler::create(16, channels, 247 output_freq, quality); 248 size_t out_frames = output_size/8; 249 resampler->setSampleRate(input_freq); 250 resampler->setVolume(0x1000, 0x1000); 251 252 memset(output_vaddr, 0, output_size); 253 if (gVerbose) { 254 printf("resample() %u output frames\n", out_frames); 255 } 256 resampler->resample((int*) output_vaddr, out_frames, &provider); 257 if (gVerbose) { 258 printf("resample() complete\n"); 259 } 260 resampler->reset(); 261 if (gVerbose) { 262 printf("reset() complete\n"); 263 } 264 265 // down-mix (we just truncate and keep the left channel) 266 int32_t* out = (int32_t*) output_vaddr; 267 int16_t* convert = (int16_t*) malloc(out_frames * channels * sizeof(int16_t)); 268 for (size_t i = 0; i < out_frames; i++) { 269 for (int j=0 ; j<channels ; j++) { 270 int32_t s = out[i * 2 + j] >> 12; 271 if (s > 32767) s = 32767; 272 else if (s < -32768) s = -32768; 273 convert[i * channels + j] = int16_t(s); 274 } 275 } 276 277 // write output to disk 278 if (writeHeader) { 279 SF_INFO info; 280 info.frames = 0; 281 info.samplerate = output_freq; 282 info.channels = channels; 283 info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; 284 SNDFILE *sf = sf_open(file_out, SFM_WRITE, &info); 285 if (sf == NULL) { 286 perror(file_out); 287 return EXIT_FAILURE; 288 } 289 (void) sf_writef_short(sf, convert, out_frames); 290 sf_close(sf); 291 } else { 292 int output_fd = open(file_out, O_WRONLY | O_CREAT | O_TRUNC, 293 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 294 if (output_fd < 0) { 295 perror(file_out); 296 return EXIT_FAILURE; 297 } 298 write(output_fd, convert, out_frames * channels * sizeof(int16_t)); 299 close(output_fd); 300 } 301 302 return EXIT_SUCCESS; 303} 304