playbq.c revision c323fec2a2639c0cf7463016d592d0eb0539657c
10a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten/* 20a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * Copyright (C) 2010 The Android Open Source Project 30a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * 40a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * Licensed under the Apache License, Version 2.0 (the "License"); 50a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * you may not use this file except in compliance with the License. 60a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * You may obtain a copy of the License at 70a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * 80a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * http://www.apache.org/licenses/LICENSE-2.0 90a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * 100a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * Unless required by applicable law or agreed to in writing, software 110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * distributed under the License is distributed on an "AS IS" BASIS, 120a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * See the License for the specific language governing permissions and 140a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten * limitations under the License. 150a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten */ 160a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 170a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten// Play an audio file using buffer queue 180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <assert.h> 200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <math.h> 21ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten#include <pthread.h> 220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <stdio.h> 230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <stdlib.h> 240a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <string.h> 25701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten#include <time.h> 260a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <unistd.h> 270a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 28c6853892c94800e72c0bd676d5d2136d48cea76eGlenn Kasten#include <SLES/OpenSLES.h> 290a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#ifdef ANDROID 3056847632bc2fd39a8fff68fa1e883f06310c876aGlenn Kasten#include <audio_utils/sndfile.h> 310a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#else 320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#include <sndfile.h> 330a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten#endif 340a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 35ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten#include <media/nbaio/MonoPipe.h> 36ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten#include <media/nbaio/MonoPipeReader.h> 37ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 38701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten#define max(a, b) ((a) > (b) ? (a) : (b)) 39701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten#define min(a, b) ((a) < (b) ? (a) : (b)) 40701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 410a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenunsigned numBuffers = 2; 420a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenint framesPerBuffer = 512; 430a058cc3d720cdf3f0f8222472a862258482f34fGlenn KastenSNDFILE *sndfile; 440a058cc3d720cdf3f0f8222472a862258482f34fGlenn KastenSF_INFO sfinfo; 450a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenunsigned which; // which buffer to use next 460a058cc3d720cdf3f0f8222472a862258482f34fGlenn KastenSLboolean eof; // whether we have hit EOF on input yet 47c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hungvoid *buffers; 48ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn KastenSLuint32 byteOrder; // desired to use for PCM buffers 49ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn KastenSLuint32 nativeByteOrder; // of platform 50c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hungaudio_format_t transferFormat = AUDIO_FORMAT_PCM_16_BIT; 51c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hungsize_t sfframesize = 0; 52ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten 53ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten// swap adjacent bytes; this would normally be in <unistd.h> but is missing here 54ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kastenstatic void swab(const void *from, void *to, ssize_t n) 55ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten{ 56ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten // from and to as char pointers 57ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten const char *from_ch = (const char *) from; 58ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten char *to_ch = (char *) to; 59ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten // note that we don't swap the last odd byte 60ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten while (n >= 2) { 61ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten to_ch[0] = from_ch[1]; 62ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten to_ch[1] = from_ch[0]; 63ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten to_ch += 2; 64ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten from_ch += 2; 65ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten n -= 2; 66ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 67ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten} 68ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten 69ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten// squeeze 16-bit signed PCM samples down to 8-bit unsigned PCM samples by truncation; no dithering 70ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kastenstatic void squeeze(const short *from, unsigned char *to, ssize_t n) 71ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten{ 72ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten // note that we don't squeeze the last odd byte 73ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten while (n >= 2) { 74ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten *to++ = (*from++ + 32768) >> 8; 75ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten n -= 2; 76ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 77ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten} 780a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 79c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung// squeeze 32-bit signed PCM samples down to 24-bit unsigned PCM samples by truncation 80c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hungstatic void squeeze24(const unsigned char *from, unsigned char *to, ssize_t n) 81c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung{ 82c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung // note that we don't squeeze the last odd bytes 83c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung while (n >= 3) { 84c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung ++from; 85c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung *to++ = *from++; 86c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung *to++ = *from++; 87c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung *to++ = *from++; 88c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung n -= 4; 89c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung } 90c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung} 91c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung 92ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kastenstatic android::MonoPipeReader *pipeReader; 93ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kastenstatic android::MonoPipe *pipeWriter; 94ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kastenstatic unsigned underruns = 0; 95ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten// This callback is called each time a buffer finishes playing 970a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 980a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenstatic void callback(SLBufferQueueItf bufq, void *param) 990a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten{ 1009a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten assert(NULL == param); 1010a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (!eof) { 102c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung void *buffer = (char *)buffers + framesPerBuffer * sfframesize * which; 103ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten ssize_t count = pipeReader->read(buffer, framesPerBuffer, (int64_t) -1); 104ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten // on underrun from pipe, substitute silence 1050a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (0 >= count) { 106c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung memset(buffer, 0, framesPerBuffer * sfframesize); 107ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten count = framesPerBuffer; 108ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten ++underruns; 109ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten } 110ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten if (count > 0) { 111c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung SLuint32 nbytes = count * sfframesize; 112ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten if (byteOrder != nativeByteOrder) { 113ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten swab(buffer, buffer, nbytes); 114ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 115c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung if (transferFormat == AUDIO_FORMAT_PCM_8_BIT) { 116c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung squeeze((short *) buffer, (unsigned char *) buffer, nbytes); 117ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten nbytes /= 2; 118c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung } else if (transferFormat == AUDIO_FORMAT_PCM_24_BIT_PACKED) { 119c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung squeeze24((unsigned char *) buffer, (unsigned char *) buffer, nbytes); 120c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung nbytes = nbytes * 3 / 4; 121ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 122ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten SLresult result = (*bufq)->Enqueue(bufq, buffer, nbytes); 1230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 1240a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (++which >= numBuffers) 1250a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten which = 0; 1260a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 1270a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 1280a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten} 1290a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 130ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten// This thread reads from a (slow) filesystem with unpredictable latency and writes to pipe 131ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 132c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hungstatic void *file_reader_loop(void *arg __unused) 133ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten{ 134ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten#define READ_FRAMES 256 135c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung void *temp = malloc(READ_FRAMES * sfframesize); 136ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten sf_count_t total = 0; 137c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung sf_count_t count; 138ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten for (;;) { 139c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung switch (transferFormat) { 140c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_FLOAT: 141c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung count = sf_readf_float(sndfile, (float *) temp, READ_FRAMES); 142c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 143c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_32_BIT: 144c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_24_BIT_PACKED: 145c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung count = sf_readf_int(sndfile, (int *) temp, READ_FRAMES); 146c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 147c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_16_BIT: 148c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_8_BIT: 149c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung count = sf_readf_short(sndfile, (short *) temp, READ_FRAMES); 150c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 151c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung default: 152c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung count = 0; 153c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 154c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung } 155ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten if (0 >= count) { 156ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten eof = SL_BOOLEAN_TRUE; 157ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten break; 158ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten } 159c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung const unsigned char *ptr = (unsigned char *) temp; 160ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten while (count > 0) { 161ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten ssize_t actual = pipeWriter->write(ptr, (size_t) count); 162ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten if (actual < 0) { 163ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten break; 164ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten } 165ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten if ((sf_count_t) actual < count) { 166ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten usleep(10000); 167ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten } 168c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung ptr += actual * sfframesize; 169ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten count -= actual; 170ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten total += actual; 171ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten } 172ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten // simulate occasional filesystem latency 173ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten if ((total & 0xFF00) == 0xFF00) { 174ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten usleep(100000); 175ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten } 176ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten } 177ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten free(temp); 178ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten return NULL; 179ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten} 180ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 181ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten// Main program 182ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 1830a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kastenint main(int argc, char **argv) 1840a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten{ 185ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten // Determine the native byte order (SL_BYTEORDER_NATIVE not available until 1.1) 186ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten union { 187ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten short s; 188ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten char c[2]; 189ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } u; 190ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten u.s = 0x1234; 191ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten if (u.c[0] == 0x34) { 192ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten nativeByteOrder = SL_BYTEORDER_LITTLEENDIAN; 193ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } else if (u.c[0] == 0x12) { 194ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten nativeByteOrder = SL_BYTEORDER_BIGENDIAN; 195ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } else { 196ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten fprintf(stderr, "Unable to determine native byte order\n"); 197ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten return EXIT_FAILURE; 198ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 199ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten byteOrder = nativeByteOrder; 200ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten 2010a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLboolean enableReverb = SL_BOOLEAN_FALSE; 202f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten SLboolean enablePlaybackRate = SL_BOOLEAN_FALSE; 203701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten SLpermille initialRate = 0; 204701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten SLpermille finalRate = 0; 205701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten SLpermille deltaRate = 1; 206701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten SLmillisecond deltaRateMs = 0; 2070a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2080a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // process command-line options 2090a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten int i; 2100a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten for (i = 1; i < argc; ++i) { 2110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten char *arg = argv[i]; 212701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten if (arg[0] != '-') { 2130a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 214701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 215ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten if (!strcmp(arg, "-b")) { 216ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten byteOrder = SL_BYTEORDER_BIGENDIAN; 217ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } else if (!strcmp(arg, "-l")) { 218ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten byteOrder = SL_BYTEORDER_LITTLEENDIAN; 219ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } else if (!strcmp(arg, "-8")) { 220c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung transferFormat = AUDIO_FORMAT_PCM_8_BIT; 221c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung } else if (!strcmp(arg, "-24")) { 222c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung transferFormat = AUDIO_FORMAT_PCM_24_BIT_PACKED; 223c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung } else if (!strcmp(arg, "-32")) { 224c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung transferFormat = AUDIO_FORMAT_PCM_32_BIT; 225ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } else if (!strncmp(arg, "-f", 2)) { 2260a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten framesPerBuffer = atoi(&arg[2]); 2270a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } else if (!strncmp(arg, "-n", 2)) { 2280a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten numBuffers = atoi(&arg[2]); 2299a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten } else if (!strncmp(arg, "-p", 2)) { 230701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten initialRate = atoi(&arg[2]); 231f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten enablePlaybackRate = SL_BOOLEAN_TRUE; 232701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } else if (!strncmp(arg, "-P", 2)) { 233701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten finalRate = atoi(&arg[2]); 234f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten enablePlaybackRate = SL_BOOLEAN_TRUE; 235701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } else if (!strncmp(arg, "-q", 2)) { 236701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten deltaRate = atoi(&arg[2]); 237701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten // deltaRate is a magnitude, so take absolute value 238701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten if (deltaRate < 0) { 239701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten deltaRate = -deltaRate; 240701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 241f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten enablePlaybackRate = SL_BOOLEAN_TRUE; 242701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } else if (!strncmp(arg, "-Q", 2)) { 243701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten deltaRateMs = atoi(&arg[2]); 244f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten enablePlaybackRate = SL_BOOLEAN_TRUE; 2450a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } else if (!strcmp(arg, "-r")) { 2460a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten enableReverb = SL_BOOLEAN_TRUE; 2470a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } else { 2480a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten fprintf(stderr, "option %s ignored\n", arg); 2490a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 2500a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 2510a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2520a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (argc - i != 1) { 253c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung fprintf(stderr, "usage: [-b/l] [-8 | -24 | -32] [-f#] [-n#] [-p#] [-r]" 254c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung " %s filename\n", argv[0]); 255701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -b force big-endian byte order (default is native byte order)\n"); 256701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -l force little-endian byte order (default is native byte order)\n"); 257701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -8 output 8-bits per sample (default is 16-bits per sample)\n"); 258c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung fprintf(stderr, " -24 output 24-bits per sample\n"); 259c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung fprintf(stderr, " -32 output 32-bits per sample\n"); 260701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -f# frames per buffer (default 512)\n"); 261701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -n# number of buffers (default 2)\n"); 262701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -p# initial playback rate in per mille (default 1000)\n"); 263701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -P# final playback rate in per mille (default same as -p#)\n"); 264701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -q# magnitude of playback rate changes in per mille (default 1)\n"); 265701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -Q# period between playback rate changes in ms (default 50)\n"); 266701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, " -r enable reverb (default disabled)\n"); 2670a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten return EXIT_FAILURE; 2680a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 2690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten const char *filename = argv[i]; 2710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten //memset(&sfinfo, 0, sizeof(SF_INFO)); 2720a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten sfinfo.format = 0; 2730a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten sndfile = sf_open(filename, SFM_READ, &sfinfo); 2740a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (NULL == sndfile) { 2750a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten perror(filename); 2760a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten return EXIT_FAILURE; 2770a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 2780a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 2790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // verify the file format 2800a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten switch (sfinfo.channels) { 2810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 1: 2820a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 2: 2830a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 2840a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten default: 2850a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten fprintf(stderr, "unsupported channel count %d\n", sfinfo.channels); 286701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten goto close_sndfile; 2870a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 288701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 2890a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten switch (sfinfo.samplerate) { 2900a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 8000: 2910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 11025: 2920a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 12000: 2930a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 16000: 2940a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 22050: 2950a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 24000: 2960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 32000: 2970a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 44100: 2980a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case 48000: 2990a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 3000a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten default: 3010a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten fprintf(stderr, "unsupported sample rate %d\n", sfinfo.samplerate); 302701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten goto close_sndfile; 3030a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 304701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 3050a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten switch (sfinfo.format & SF_FORMAT_TYPEMASK) { 3060a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case SF_FORMAT_WAV: 3070a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 3080a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten default: 3090a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten fprintf(stderr, "unsupported format type 0x%x\n", sfinfo.format & SF_FORMAT_TYPEMASK); 310701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten goto close_sndfile; 3110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 312701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 3130a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten switch (sfinfo.format & SF_FORMAT_SUBMASK) { 314c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case SF_FORMAT_FLOAT: 315c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case SF_FORMAT_PCM_32: 3160a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case SF_FORMAT_PCM_16: 3170a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten case SF_FORMAT_PCM_U8: 3180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 3190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten default: 3200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten fprintf(stderr, "unsupported sub-format 0x%x\n", sfinfo.format & SF_FORMAT_SUBMASK); 321701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten goto close_sndfile; 3220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 3230a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 324c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung SLuint32 bitsPerSample; 325c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung switch (transferFormat) { 326c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_FLOAT: 327c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung bitsPerSample = 32; 328c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung sfframesize = sfinfo.channels * sizeof(float); 329c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 330c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_32_BIT: 331c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung bitsPerSample = 32; 332c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung sfframesize = sfinfo.channels * sizeof(int); 333c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 334c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_24_BIT_PACKED: 335c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung bitsPerSample = 24; 336c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung sfframesize = sfinfo.channels * sizeof(int); // use int size 337c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 338c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_16_BIT: 339c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung bitsPerSample = 16; 340c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung sfframesize = sfinfo.channels * sizeof(short); 341c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 342c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_8_BIT: 343c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung bitsPerSample = 8; 344c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung sfframesize = sfinfo.channels * sizeof(short); // use short size 345c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 346c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung default: 347c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung fprintf(stderr, "unsupported transfer format %#x\n", transferFormat); 348c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung goto close_sndfile; 349c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung } 350ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 351c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung { 352c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung buffers = malloc(framesPerBuffer * sfframesize * numBuffers); 3530a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3540a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // create engine 3550a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLresult result; 3560a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLObjectItf engineObject; 3570a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); 3580a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3590a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLEngineItf engineEngine; 3600a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); 3610a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3620a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); 3630a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3640a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3650a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // create output mix 3660a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLObjectItf outputMixObject; 3670a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB}; 3680a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLboolean req[1] = {SL_BOOLEAN_TRUE}; 3690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, enableReverb ? 1 : 0, 3700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten ids, req); 3710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3720a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); 3730a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3740a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3750a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // configure environmental reverb on output mix 3760a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLEnvironmentalReverbItf mixEnvironmentalReverb = NULL; 3770a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (enableReverb) { 3780a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB, 3790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten &mixEnvironmentalReverb); 3800a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLEnvironmentalReverbSettings settings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR; 3820a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*mixEnvironmentalReverb)->SetEnvironmentalReverbProperties(mixEnvironmentalReverb, 3830a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten &settings); 3840a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 3850a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 3860a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 3870a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // configure audio source 3880a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLDataLocator_BufferQueue loc_bufq; 3890a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten loc_bufq.locatorType = SL_DATALOCATOR_BUFFERQUEUE; 3900a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten loc_bufq.numBuffers = numBuffers; 3910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLDataFormat_PCM format_pcm; 3920a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten format_pcm.formatType = SL_DATAFORMAT_PCM; 3930a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten format_pcm.numChannels = sfinfo.channels; 3940a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten format_pcm.samplesPerSec = sfinfo.samplerate * 1000; 395ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten format_pcm.bitsPerSample = bitsPerSample; 3960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten format_pcm.containerSize = format_pcm.bitsPerSample; 3970a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten format_pcm.channelMask = 1 == format_pcm.numChannels ? SL_SPEAKER_FRONT_CENTER : 3980a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; 399ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten format_pcm.endianness = byteOrder; 4000a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLDataSource audioSrc; 4010a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten audioSrc.pLocator = &loc_bufq; 4020a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten audioSrc.pFormat = &format_pcm; 4030a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 4040a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // configure audio sink 4050a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLDataLocator_OutputMix loc_outmix; 4060a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; 4070a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten loc_outmix.outputMix = outputMixObject; 4080a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLDataSink audioSnk; 4090a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten audioSnk.pLocator = &loc_outmix; 4100a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten audioSnk.pFormat = NULL; 4110a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 4120a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // create audio player 4139a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten SLInterfaceID ids2[3] = {SL_IID_BUFFERQUEUE, SL_IID_PLAYBACKRATE, SL_IID_EFFECTSEND}; 4149a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten SLboolean req2[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; 4150a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLObjectItf playerObject; 4160a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audioSrc, 417f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten &audioSnk, enableReverb ? 3 : (enablePlaybackRate ? 2 : 1), ids2, req2); 418701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten if (SL_RESULT_SUCCESS != result) { 419701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, "can't create audio player\n"); 420701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten goto no_player; 421701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 4220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 423ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten { 424ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 4250a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // realize the player 4260a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE); 4270a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 4280a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 4290a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // get the effect send interface and enable effect send reverb for this player 4300a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (enableReverb) { 4310a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLEffectSendItf playerEffectSend; 4320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerObject)->GetInterface(playerObject, SL_IID_EFFECTSEND, &playerEffectSend); 4330a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 4340a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerEffectSend)->EnableEffectSend(playerEffectSend, mixEnvironmentalReverb, 4350a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SL_BOOLEAN_TRUE, (SLmillibel) 0); 4360a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 4370a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 4380a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 4399a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten // get the playback rate interface and configure the rate 4409a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten SLPlaybackRateItf playerPlaybackRate; 4413eaa329775fc522d8ea4acd4edc379eabf9ac332Glenn Kasten SLpermille currentRate = 0; 442f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten if (enablePlaybackRate) { 443f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAYBACKRATE, 444f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten &playerPlaybackRate); 445f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten assert(SL_RESULT_SUCCESS == result); 446f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten SLpermille defaultRate; 447f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten result = (*playerPlaybackRate)->GetRate(playerPlaybackRate, &defaultRate); 448f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten assert(SL_RESULT_SUCCESS == result); 449f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten SLuint32 defaultProperties; 450f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten result = (*playerPlaybackRate)->GetProperties(playerPlaybackRate, &defaultProperties); 451f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten assert(SL_RESULT_SUCCESS == result); 452f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten printf("default playback rate %d per mille, properties 0x%x\n", defaultRate, 453f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten defaultProperties); 454f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten if (initialRate <= 0) { 455f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten initialRate = defaultRate; 456f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten } 457f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten if (finalRate <= 0) { 458f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten finalRate = initialRate; 459f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten } 460f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten currentRate = defaultRate; 461f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten if (finalRate == initialRate) { 462701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten deltaRate = 0; 463f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten } else if (finalRate < initialRate) { 464f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten deltaRate = -deltaRate; 465f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten } 466f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten if (initialRate != defaultRate) { 467f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, initialRate); 468f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten if (SL_RESULT_FEATURE_UNSUPPORTED == result) { 469f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten fprintf(stderr, "initial playback rate %d is unsupported\n", initialRate); 470f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten deltaRate = 0; 471f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten } else if (SL_RESULT_PARAMETER_INVALID == result) { 472f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten fprintf(stderr, "initial playback rate %d is invalid\n", initialRate); 473f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten deltaRate = 0; 474f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten } else { 475f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten assert(SL_RESULT_SUCCESS == result); 476f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten currentRate = initialRate; 477f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten } 4789a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten } 4799a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten } 4809a6c9db763121c3b11765c6c8cf935983c0385bfGlenn Kasten 4810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // get the play interface 4820a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLPlayItf playerPlay; 4830a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay); 4840a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 4850a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 4860a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // get the buffer queue interface 4870a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLBufferQueueItf playerBufferQueue; 4880a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE, 4890a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten &playerBufferQueue); 4900a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 4910a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 4920a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // loop until EOF or no more buffers 4930a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten for (which = 0; which < numBuffers; ++which) { 494c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung void *buffer = (char *)buffers + framesPerBuffer * sfframesize * which; 4950a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten sf_count_t frames = framesPerBuffer; 4960a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten sf_count_t count; 497c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung switch (transferFormat) { 498c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_FLOAT: 499c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung count = sf_readf_float(sndfile, (float *) buffer, frames); 500c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 501c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_32_BIT: 502c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung count = sf_readf_int(sndfile, (int *) buffer, frames); 503c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 504c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_24_BIT_PACKED: 505c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung count = sf_readf_int(sndfile, (int *) buffer, frames); 506c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 507c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_16_BIT: 508c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung case AUDIO_FORMAT_PCM_8_BIT: 509c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung count = sf_readf_short(sndfile, (short *) buffer, frames); 510c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 511c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung default: 512c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung count = 0; 513c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung break; 514c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung } 5150a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (0 >= count) { 5160a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten eof = SL_BOOLEAN_TRUE; 5170a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 5180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 5190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 5200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // enqueue a buffer 521c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung SLuint32 nbytes = count * sfframesize; 522ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten if (byteOrder != nativeByteOrder) { 523ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten swab(buffer, buffer, nbytes); 524ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 525c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung if (transferFormat == AUDIO_FORMAT_PCM_8_BIT) { 526c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung squeeze((short *) buffer, (unsigned char *) buffer, nbytes); 527ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten nbytes /= 2; 528c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung } else if (transferFormat == AUDIO_FORMAT_PCM_24_BIT_PACKED) { 529c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung squeeze24((unsigned char *) buffer, (unsigned char *) buffer, nbytes); 530c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung nbytes = nbytes * 3 / 4; 531ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten } 532ebca1a420c4ada9eff2e82f0100abaea95b48f24Glenn Kasten result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, nbytes); 5330a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 5340a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 535701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten if (which >= numBuffers) { 5360a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten which = 0; 537701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 5380a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 5390a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // register a callback on the buffer queue 5400a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, callback, NULL); 5410a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 5420a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 543c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung // Create a NBAIO pipe for asynchronous data handling. In this case, 544c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung // sample rate doesn't matter and audio_format just sets the transfer frame size. 545c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung const android::NBAIO_Format nbaio_format = android::Format_from_SR_C( 546c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung sfinfo.samplerate, sfinfo.channels, 547c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung transferFormat == AUDIO_FORMAT_PCM_8_BIT ? AUDIO_FORMAT_PCM_16_BIT : 548c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung transferFormat == AUDIO_FORMAT_PCM_24_BIT_PACKED ? 549c323fec2a2639c0cf7463016d592d0eb0539657cAndy Hung AUDIO_FORMAT_PCM_32_BIT : transferFormat); 550ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten pipeWriter = new android::MonoPipe(16384, nbaio_format, false /*writeCanBlock*/); 551ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten android::NBAIO_Format offer = nbaio_format; 552ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten size_t numCounterOffers = 0; 553ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten ssize_t neg = pipeWriter->negotiate(&offer, 1, NULL, numCounterOffers); 554ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten assert(0 == neg); 555ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten pipeReader = new android::MonoPipeReader(pipeWriter); 556ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten numCounterOffers = 0; 557ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten neg = pipeReader->negotiate(&offer, 1, NULL, numCounterOffers); 558ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten assert(0 == neg); 559ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 560ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten // create thread to read from file 561ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten pthread_t thread; 562ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten int ok = pthread_create(&thread, (const pthread_attr_t *) NULL, file_reader_loop, NULL); 563ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten assert(0 == ok); 564ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 565ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten // give thread a head start so that the pipe is initially filled 566ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten sleep(1); 567ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 5680a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // set the player's state to playing 5690a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING); 5700a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 5710a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 572701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten // get the initial time 573701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten struct timespec prevTs; 574701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten clock_gettime(CLOCK_MONOTONIC, &prevTs); 575701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten long elapsedNs = 0; 576701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten long deltaRateNs = deltaRateMs * 1000000; 577701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 5780a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // wait until the buffer queue is empty 5790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten SLBufferQueueState bufqstate; 5800a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten for (;;) { 5810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten result = (*playerBufferQueue)->GetState(playerBufferQueue, &bufqstate); 5820a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten assert(SL_RESULT_SUCCESS == result); 5830a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten if (0 >= bufqstate.count) { 5840a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten break; 5850a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 586f8d147df8f6dba1bb5bb0ea4c09795ee827569caGlenn Kasten if (!enablePlaybackRate || deltaRate == 0) { 587701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten sleep(1); 588701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } else { 589701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten struct timespec curTs; 590701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten clock_gettime(CLOCK_MONOTONIC, &curTs); 591701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten elapsedNs += (curTs.tv_sec - prevTs.tv_sec) * 1000000000 + 592701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten // this term can be negative 593701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten (curTs.tv_nsec - prevTs.tv_nsec); 594701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten prevTs = curTs; 595701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten if (elapsedNs < deltaRateNs) { 596701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten usleep((deltaRateNs - elapsedNs) / 1000); 597701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten continue; 598701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 599701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten elapsedNs -= deltaRateNs; 600701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten SLpermille nextRate = currentRate + deltaRate; 601701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten result = (*playerPlaybackRate)->SetRate(playerPlaybackRate, nextRate); 602701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten if (SL_RESULT_SUCCESS != result) { 603701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, "next playback rate %d is unsupported\n", nextRate); 604701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } else if (SL_RESULT_PARAMETER_INVALID == result) { 605701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten fprintf(stderr, "next playback rate %d is invalid\n", nextRate); 606701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } else { 607701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten assert(SL_RESULT_SUCCESS == result); 608701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 609701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten currentRate = nextRate; 610701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten if (currentRate >= max(initialRate, finalRate)) { 611701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten currentRate = max(initialRate, finalRate); 612701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten deltaRate = -abs(deltaRate); 613701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } else if (currentRate <= min(initialRate, finalRate)) { 614701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten currentRate = min(initialRate, finalRate); 615701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten deltaRate = abs(deltaRate); 616701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 617701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten } 6180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten } 6190a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 6200a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // destroy audio player 6210a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten (*playerObject)->Destroy(playerObject); 6220a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 623ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten } 624ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 625701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kastenno_player: 626701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 6270a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // destroy output mix 6280a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten (*outputMixObject)->Destroy(outputMixObject); 6290a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 6300a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten // destroy engine 6310a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten (*engineObject)->Destroy(engineObject); 6320a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten 633ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten } 634ad6c970f500cf99dd1eb23b9f5b2360948db90e7Glenn Kasten 635701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kastenclose_sndfile: 636701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 637701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten (void) sf_close(sndfile); 638701cf2a089c87ec5b8e5a953f637b250aee4a58aGlenn Kasten 6390a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten return EXIT_SUCCESS; 6400a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten} 641