15 #include <dispatch/dispatch.h>
17 #include <AudioToolbox/AudioToolbox.h>
29 "title" :
"VuoAudioFile",
38 "VuoList_VuoAudioSamples",
39 "AudioToolbox.framework",
40 "CoreFoundation.framework"
75 float *buffer = (
float*)malloc(bufferSize);
76 bzero(buffer, bufferSize);
79 VuoInteger framesRemaining = VuoAudioSamples_bufferSize;
80 float *subBuffer = buffer;
82 while (framesRemaining)
84 AudioBufferList bufferList;
85 bufferList.mNumberBuffers = 1;
86 bufferList.mBuffers[0].mNumberChannels = afi->outputFormat.mChannelsPerFrame;
87 bufferList.mBuffers[0].mDataByteSize = sizeof(float) * afi->outputFormat.mChannelsPerFrame * framesRemaining;
88 bufferList.mBuffers[0].mData = (void *)subBuffer;
90 UInt32 numFrames = framesRemaining;
91 OSStatus err = ExtAudioFileRead(afi->audioFile, &numFrames, &bufferList);
95 char *errStr = VuoOsStatus_getText(err);
96 VUserLog(
"Error reading samples: %s", errStr);
99 if (afi->finishedPlayback)
100 afi->finishedPlayback();
110 framesRemaining -= numFrames;
111 subBuffer += numFrames * afi->outputFormat.mChannelsPerFrame;
125 case VuoLoopType_Loop:
127 const SInt64 targetFrame = 0;
129 OSStatus err = ExtAudioFileSeek(afi->audioFile, targetFrame + afi->headerFrames);
133 char *errStr = VuoOsStatus_getText(err);
134 VUserLog(
"Error seeking to sample: %s", errStr);
136 afi->playing = false;
152 for (
VuoInteger channel = 0; channel < afi->outputFormat.mChannelsPerFrame; ++channel)
158 samples.
samples[sample] = buffer[sample*afi->outputFormat.mChannelsPerFrame + channel];
164 dispatch_sync(afi->audioFileQueue, ^{
165 if (afi->decodedChannels)
166 afi->decodedChannels(channels);
170 VuoRelease(channels);
215 afi->
loop = VuoLoopType_None;
222 CFStringRef urlCFS = CFStringCreateWithCString(NULL, normalizedURL, kCFStringEncodingUTF8);
223 CFURLRef url = CFURLCreateWithString(NULL, urlCFS, NULL);
226 VUserLog(
"Couldn't open '%s': Invalid URL.", normalizedURL);
235 OSStatus err = ExtAudioFileOpenURL(url, &afi->
audioFile);
241 VUserLog(
"Couldn't open '%s': %s", normalizedURL, errStr);
251 OSStatus err = ExtAudioFileGetProperty(afi->
audioFile, kExtAudioFileProperty_FileDataFormat, &size, &afi->
inputFormat);
255 VUserLog(
"Error getting file format for '%s': %s", url, errStr);
263 OSStatus err = ExtAudioFileGetProperty(afi->
audioFile, kExtAudioFileProperty_FileLengthFrames, &size, &afi->
totalFrameCount);
267 VUserLog(
"Error getting frame count for '%s': %s", url, errStr);
277 afi->
outputFormat.mFormatFlags = kAudioFormatFlagIsFloat;
283 OSStatus err = ExtAudioFileSetProperty(afi->
audioFile, kExtAudioFileProperty_ClientDataFormat, size, &afi->
outputFormat);
287 VUserLog(
"Error setting output format for '%s': %s", url, errStr);
294 AudioConverterRef ac;
295 UInt32 size =
sizeof(AudioConverterRef);
297 OSStatus err = ExtAudioFileGetProperty(afi->
audioFile, kExtAudioFileProperty_AudioConverter, &size, &ac);
301 VUserLog(
"Error getting audio converter info for '%s': %s", url, errStr);
306 AudioConverterPrimeInfo pi;
307 UInt32 size =
sizeof(AudioConverterPrimeInfo);
309 OSStatus err = AudioConverterGetProperty(ac, kAudioConverterPrimeInfo, &size, &pi);
312 if (err != kAudioFormatUnsupportedPropertyError)
315 VUserLog(
"Error getting header info for '%s': %s", url, errStr);
325 dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
326 afi->
playbackTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, DISPATCH_TIMER_STRICT, q);
330 dispatch_source_set_timer(afi->
playbackTimer, dispatch_time(DISPATCH_TIME_NOW, nanoseconds), nanoseconds, 0);
332 VuoAudioFile_decodeChannels(afi);
335 dispatch_semaphore_signal(afi->playbackTimerCanceled);
341 dispatch_resume(afi->playbackTimer);
364 *channelCount = afi->
inputFormat.mChannelsPerFrame;
383 afi->decodedChannels = decodedChannels;
384 afi->finishedPlayback = finishedPlayback;
399 afi->decodedChannels = NULL;
400 afi->finishedPlayback = NULL;
424 SInt64 targetFrame = time * afi->inputFormat.mSampleRate;
426 OSStatus err = ExtAudioFileSeek(afi->audioFile, targetFrame + afi->headerFrames);
429 char *errStr = VuoOsStatus_getText(err);
430 VUserLog(
"Error seeking to sample: %s", errStr);