this repo has no description
1/* Copyright: � Copyright 2005 Apple Computer, Inc. All rights reserved.
2
3 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
4 ("Apple") in consideration of your agreement to the following terms, and your
5 use, installation, modification or redistribution of this Apple software
6 constitutes acceptance of these terms. If you do not agree with these terms,
7 please do not use, install, modify or redistribute this Apple software.
8
9 In consideration of your agreement to abide by the following terms, and subject
10 to these terms, Apple grants you a personal, non-exclusive license, under Apple�s
11 copyrights in this original Apple software (the "Apple Software"), to use,
12 reproduce, modify and redistribute the Apple Software, with or without
13 modifications, in source and/or binary forms; provided that if you redistribute
14 the Apple Software in its entirety and without modifications, you must retain
15 this notice and the following text and disclaimers in all such redistributions of
16 the Apple Software. Neither the name, trademarks, service marks or logos of
17 Apple Computer, Inc. may be used to endorse or promote products derived from the
18 Apple Software without specific prior written permission from Apple. Except as
19 expressly stated in this notice, no other rights or licenses, express or implied,
20 are granted by Apple herein, including but not limited to any patent rights that
21 may be infringed by your derivative works or by other works in which the Apple
22 Software may be incorporated.
23
24 The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
25 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
26 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
28 COMBINATION WITH YOUR PRODUCTS.
29
30 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
31 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
32 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
34 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
35 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
36 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37*/
38/*=============================================================================
39 main.cpp
40
41=============================================================================*/
42
43/*
44 auprocess
45 - takes a source audio file, an AU and generates a processed file
46*/
47
48#include "CAAUProcessor.h"
49#include "CAAudioFile.h"
50#include "CAXException.h"
51#include "CAHostTimeBase.h"
52#include "CAFilePathUtils.h"
53#include "CAAudioFileFormats.h"
54
55#if TARGET_OS_MAC
56 #include <pthread.h>
57 #include <mach/mach.h>
58#endif
59
60#define require_noerr ca_require_noerr
61
62#define CA_AU_PROFILE_TIME 1
63
64#if CA_AU_PROFILE_TIME
65 UInt64 sReadTime = 0;
66 UInt64 sRenderTime = 0;
67#endif
68
69#pragma mark __print helpers
70
71void PRINT_MARKS ()
72{
73 printf ("| ");
74 for (int i = 0; i < 48; ++i)
75 printf (" ");
76 printf ("|\n");
77}
78
79void PerfResult(const char *toolname, int group, const char *testname, double value, const char *units, const char *fmt="%.3f")
80{
81 printf("<result tool='%s' group='%d' test='%s' value='", toolname, group, testname);
82 printf(fmt, value);
83 printf("' units='%s' />\n", units);
84}
85
86static int lastProgressPrintDone = -1;
87void PRINT_PROGRESS (Float32 inPercent)
88{
89 int current = int(inPercent / 4.0);
90 for (int i = lastProgressPrintDone; i < current; ++i)
91 printf ("* ");
92 lastProgressPrintDone = current;
93}
94
95#pragma mark __Inpput Callback Definitions
96
97static AURenderCallbackStruct sInputCallback; // we set one of these two callbacks based on AU type
98
99static OSStatus InputCallback (void *inRefCon,
100 AudioUnitRenderActionFlags *ioActionFlags,
101 const AudioTimeStamp *inTimeStamp,
102 UInt32 inBusNumber,
103 UInt32 inNumberFrames,
104 AudioBufferList *ioData)
105{
106 #if CA_AU_PROFILE_TIME
107 UInt64 now = CAHostTimeBase::GetTheCurrentTime();
108 #endif
109
110 CAAudioFile &readFile = *(static_cast<CAAudioFile*>(inRefCon));
111
112#if !CAAF_USE_EXTAUDIOFILE
113 if (SInt64(inTimeStamp->mSampleTime) > readFile.GetNumberPackets()) {
114#else
115 if (SInt64(inTimeStamp->mSampleTime) > readFile.GetNumberFrames()) {
116#endif
117#if DEBUG
118 printf ("reading past end of input\n");
119#endif
120 return -1;
121 }
122
123 readFile.Seek (SInt64(inTimeStamp->mSampleTime));
124 readFile.Read (inNumberFrames, ioData);
125
126 #if CA_AU_PROFILE_TIME
127 sReadTime += (CAHostTimeBase::GetTheCurrentTime() - now);
128 #endif
129
130 return noErr;
131}
132
133static OSStatus FConvInputCallback (void *inRefCon,
134 AudioUnitRenderActionFlags *ioActionFlags,
135 const AudioTimeStamp *inTimeStamp,
136 UInt32 inBusNumber,
137 UInt32 inNumberFrames,
138 AudioBufferList *ioData)
139{
140 #if CA_AU_PROFILE_TIME
141 UInt64 now = CAHostTimeBase::GetTheCurrentTime();
142 #endif
143
144 CAAudioFile &readFile = *(static_cast<CAAudioFile*>(inRefCon));
145
146 // this test is ONLY needed in case of processing with a Format Converter type of AU
147 // in all other cases, the CAAUProcessor class will NEVER call you for input
148 // beyond the end of the file....
149
150#if !CAAF_USE_EXTAUDIOFILE
151 if (SInt64(inTimeStamp->mSampleTime) >= readFile.GetNumberPackets()) {
152#else
153 if (SInt64(inTimeStamp->mSampleTime) >= readFile.GetNumberFrames()) {
154#endif
155 return -1;
156 }
157
158 readFile.Seek (SInt64(inTimeStamp->mSampleTime));
159 UInt32 readPackets = inNumberFrames;
160
161 // also, have to do this for a format converter AU - otherwise we'd just read what we're told
162#if !CAAF_USE_EXTAUDIOFILE
163 if (SInt64(inTimeStamp->mSampleTime + inNumberFrames) > readFile.GetNumberPackets()) {
164#else
165 if (SInt64(inTimeStamp->mSampleTime + inNumberFrames) > readFile.GetNumberFrames()) {
166#endif
167 // first set this to zero as we're only going to read a partial number of frames
168 AudioBuffer *buf = ioData->mBuffers;
169 for (UInt32 i = ioData->mNumberBuffers; i--; ++buf)
170 memset((Byte *)buf->mData, 0, buf->mDataByteSize);
171#if !CAAF_USE_EXTAUDIOFILE
172 readPackets = UInt32 (readFile.GetNumberPackets() - SInt64(inTimeStamp->mSampleTime));
173#else
174 readPackets = UInt32 (readFile.GetNumberFrames() - SInt64(inTimeStamp->mSampleTime));
175#endif
176 }
177
178 readFile.Read (readPackets, ioData);
179
180 #if CA_AU_PROFILE_TIME
181 sReadTime += (CAHostTimeBase::GetTheCurrentTime() - now);
182 #endif
183
184 return noErr;
185}
186
187struct ReadBuffer {
188 AUOutputBL *readData;
189 UInt32 readFrames;
190};
191
192static OSStatus MemoryInputCallback (void *inRefCon,
193 AudioUnitRenderActionFlags *ioActionFlags,
194 const AudioTimeStamp *inTimeStamp,
195 UInt32 inBusNumber,
196 UInt32 inNumberFrames,
197 AudioBufferList *ioData)
198{
199 #if CA_AU_PROFILE_TIME
200 UInt64 now = CAHostTimeBase::GetTheCurrentTime();
201 #endif
202
203 ReadBuffer *readBuffer = (ReadBuffer*)inRefCon;
204
205 if (((readBuffer->readFrames + inNumberFrames) * sizeof(Float32)) > (readBuffer->readData->ABL()->mBuffers[0].mDataByteSize))
206 {
207 // going past read size
208 AudioBuffer *buf = ioData->mBuffers;
209 for (UInt32 i = ioData->mNumberBuffers; i--; ++buf)
210 memset((Byte *)buf->mData, 0, buf->mDataByteSize);
211 }
212 else
213 {
214 AudioBuffer *buf = ioData->mBuffers;
215 AudioBuffer *rBuf = readBuffer->readData->ABL()->mBuffers;
216 for (UInt32 i = ioData->mNumberBuffers; i--; ++buf, ++rBuf) {
217 AudioBuffer readB = *rBuf;
218 readB.mData = static_cast<Float32*>(rBuf->mData) + readBuffer->readFrames;
219 memcpy (buf->mData, readB.mData, buf->mDataByteSize);
220 }
221 readBuffer->readFrames += inNumberFrames;
222 }
223
224 #if CA_AU_PROFILE_TIME
225 sReadTime += (CAHostTimeBase::GetTheCurrentTime() - now);
226 #endif
227
228 return noErr;
229}
230
231#pragma mark __Utility Helpers
232
233CFPropertyListRef ReadPresetFromPresetFile (char* filePath)
234{
235 if (!filePath)
236 return NULL;
237
238 FSRef ref;
239 if (FSPathMakeRef((UInt8 *)filePath, &ref, NULL))
240 return NULL;
241
242 CFDataRef resourceData = NULL;
243 CFPropertyListRef theData = NULL;
244 CFStringRef errString = NULL;
245 CFURLRef fileURL = CFURLCreateFromFSRef (kCFAllocatorDefault, &ref);
246 if (fileURL == NULL) {
247 goto home;
248 }
249
250 SInt32 result;
251
252 // Read the XML file.
253 Boolean status; status = CFURLCreateDataAndPropertiesFromResource (kCFAllocatorDefault, fileURL,
254 &resourceData, // place to put file data
255 NULL, NULL, &result);
256 if (status == false || result) {
257 goto home;
258 }
259
260 theData = CFPropertyListCreateFromXMLData (kCFAllocatorDefault, resourceData,
261 kCFPropertyListImmutable, &errString);
262 if (theData == NULL || errString) {
263 if (theData)
264 CFRelease (theData);
265 theData = NULL;
266 goto home;
267 }
268
269home:
270 if (fileURL)
271 CFRelease (fileURL);
272 if (resourceData)
273 CFRelease (resourceData);
274 if (errString)
275 CFRelease (errString);
276
277 return theData;
278}
279
280#pragma mark __the setup code
281
282#define OFFLINE_AU_CMD "[-au TYPE SUBTYPE MANU] The Audio Unit component description\n\t"
283#define INPUT_FILE "[-i /Path/To/File] The file that is to be processed.\n\t"
284#define OUTPUT_FILE "[-o /Path/To/File/To/Create] This will be in the same format as the input file\n\t"
285#define AU_PRESET_CMD "[-p /Path/To/AUPreset/File] Specify an AU Preset File to establish the state of the AU\n\t"
286#define SHORT_MEM_CMD "[-m] Just reads and processes the first half second of the input file\n\t"
287#define USE_MAX_FRAMES "[-f max_frames] default is 32768 (512 for aufc units)"
288
289static char* usageStr = "Usage: auprocess\n\t"
290 OFFLINE_AU_CMD
291 INPUT_FILE
292 OUTPUT_FILE
293 AU_PRESET_CMD
294 SHORT_MEM_CMD
295 USE_MAX_FRAMES;
296
297int main(int argc, const char * argv[])
298{
299 setbuf (stdout, NULL);
300
301
302#if TARGET_OS_MAC
303 {
304 thread_extended_policy_data_t theFixedPolicy;
305 theFixedPolicy.timeshare = false; // set to true for a non-fixed thread
306 thread_policy_set(pthread_mach_thread_np(pthread_self()),
307 THREAD_EXTENDED_POLICY,
308 (thread_policy_t)&theFixedPolicy,
309 THREAD_EXTENDED_POLICY_COUNT);
310
311 // We keep a reference to the spawning thread's priority around (initialized in the constructor),
312 // and set the importance of the child thread relative to the spawning thread's priority.
313 thread_precedence_policy_data_t thePrecedencePolicy;
314
315 thePrecedencePolicy.importance = 63 - 36;
316 thread_policy_set(pthread_mach_thread_np(pthread_self()),
317 THREAD_PRECEDENCE_POLICY,
318 (thread_policy_t)&thePrecedencePolicy,
319 THREAD_PRECEDENCE_POLICY_COUNT);
320 }
321#endif
322
323
324// These are the variables that are set up from the input parsing
325 char* srcFilePath = NULL;
326 char* destFilePath = NULL;
327 char* auPresetFile = NULL;
328 bool shortMemoryProfile = false;
329 OSType manu, subType, type = 0;
330 int userSetFrames = -1;
331
332 for (int i = 1; i < argc; ++i)
333 {
334 if (strcmp (argv[i], "-au") == 0) {
335 if ( (i + 3) < argc ) {
336 StrToOSType (argv[i + 1], type);
337 StrToOSType (argv[i + 2], subType);
338 StrToOSType (argv[i + 3], manu);
339 i += 3;
340 } else {
341 printf ("Which Audio Unit:\n%s", usageStr);
342 exit(1);
343 }
344 }
345 else if (strcmp (argv[i], "-i") == 0) {
346 srcFilePath = const_cast<char*>(argv[++i]);
347 }
348 else if (strcmp (argv[i], "-o") == 0) {
349 destFilePath = const_cast<char*>(argv[++i]);
350 }
351 else if (strcmp (argv[i], "-p") == 0) {
352 auPresetFile = const_cast<char*>(argv[++i]);
353 }
354 else if (strcmp (argv[i], "-m") == 0) {
355 shortMemoryProfile = true;
356 }
357 else if (strcmp (argv[i], "-f") == 0) {
358 sscanf(argv[++i], "%d", &userSetFrames);
359 }
360 else {
361 printf ("%s\n", usageStr);
362 exit(1);
363 }
364 }
365
366 if (!type || !srcFilePath) {
367 printf ("%s\n", usageStr);
368 exit(1);
369 }
370 if (!destFilePath) {
371 if (!shortMemoryProfile) {
372 printf ("%s\n", usageStr);
373 exit(1);
374 }
375 }
376 // delete pre-existing output file
377 if (!shortMemoryProfile) {
378 FSRef destFSRef;
379 if (FSPathMakeRef((UInt8 *)destFilePath, &destFSRef, NULL) == noErr) {
380 // output file exists - delete it
381 if (FSDeleteObject(&destFSRef)) {
382 printf ("Cannot Delete Output File\n");
383 exit(1);
384 }
385 }
386 }
387
388 CAComponentDescription desc(type, subType, manu);
389
390 CFPropertyListRef presetDict = ReadPresetFromPresetFile(auPresetFile);
391
392 // the num of frames to use when processing the file with the Render call
393 UInt32 maxFramesToUse = shortMemoryProfile ? 512 : 32768;
394
395 // not set from command line
396 if (userSetFrames > 0) {
397 maxFramesToUse = userSetFrames;
398 }
399
400 // in some settings (for instance a delay with 100% feedback) tail time is essentially infinite
401 // so you should safeguard the final OL render stage (post process) which is aimed at pulling the tail through
402 // if you want to bypass this completely, just set this to zero.
403 Float64 maxTailTimeSecs = 10.;
404
405#pragma mark -
406#pragma mark __ The driving code
407#pragma mark -
408
409 try
410 {
411 CAComponent comp(desc);
412
413 // CAAUProcessor's constructor throws... so make sure the component is valid
414 if (comp.IsValid() == false) {
415 printf ("Can't Find Component\n");
416 desc.Print();
417 exit(1);
418 }
419
420 CAAUProcessor processor(comp);
421 processor.AU().Print();
422
423 CAAudioFile srcFile;
424 CAAudioFile destFile;
425
426 srcFile.Open(srcFilePath);
427
428 CAStreamBasicDescription procFormat (srcFile.GetFileDataFormat());
429 procFormat.SetCanonical (srcFile.GetFileDataFormat().NumberChannels(), false);
430
431 printf ("Processing Format:\n\t");
432 procFormat.Print();
433
434
435 if (!shortMemoryProfile) {
436 FSRef parentDir;
437 CFStringRef filename;
438 PosixPathToParentFSRefAndName(destFilePath, parentDir, filename);
439 destFile.CreateNew (parentDir, filename, 'AIFF', srcFile.GetFileDataFormat());
440 destFile.SetClientFormat (procFormat);
441 }
442
443 srcFile.SetClientFormat (procFormat);
444
445 AUOutputBL outputList(procFormat);
446
447 ReadBuffer* readBuf = NULL;
448
449#if !CAAF_USE_EXTAUDIOFILE
450 UInt64 numInputSamples = srcFile.GetNumberPackets();
451#else
452 UInt64 numInputSamples = srcFile.GetNumberFrames();
453#endif
454
455 if (shortMemoryProfile) {
456 readBuf = new ReadBuffer;
457 readBuf->readData = new AUOutputBL(procFormat);
458 readBuf->readFrames = 0;
459 UInt32 numFrames = UInt32(procFormat.mSampleRate / 2);
460 readBuf->readData->Allocate (numFrames); // half a second of audio data
461 readBuf->readData->Prepare(); // half a second of audio data
462
463 // read 1/2 second of audio into this read buffer
464 srcFile.Read (numFrames, readBuf->readData->ABL());
465
466 sInputCallback.inputProc = MemoryInputCallback;
467 sInputCallback.inputProcRefCon = readBuf;
468 numInputSamples = numFrames;
469 }
470 else {
471 if (desc.IsFConv()) {
472 maxFramesToUse = userSetFrames == -1 ? 512 : maxFramesToUse;
473 // some format converter's can call you several times in small granularities
474 // so you can't use a large buffer to render or you won't return all of the input data
475 // this also lessens the final difference between what you should get and what you do
476 // converter units *really* should have a version that are offline AU's to
477 // handle this for you.
478 sInputCallback.inputProc = FConvInputCallback;
479 } else
480 sInputCallback.inputProc = InputCallback;
481
482 sInputCallback.inputProcRefCon = &srcFile;
483 }
484
485 OSStatus result;
486 require_noerr (result = processor.EstablishInputCallback (sInputCallback), home);
487 require_noerr (result = processor.SetMaxFramesPerRender (maxFramesToUse), home);
488 processor.SetMaxTailTime (maxTailTimeSecs);
489 require_noerr (result = processor.Initialize (procFormat, numInputSamples), home);
490 if (presetDict) {
491 require_noerr (result = processor.SetAUPreset (presetDict), home);
492 CFRelease (presetDict);
493 }
494 // this does ALL of the preflighting.. could be specialise for an OfflineAU type
495 // to do this piecemeal and do a progress bar by using the OfflineAUPreflight method
496 require_noerr (result = processor.Preflight (), home);
497
498 bool isDone; isDone = false;
499 bool needsPostProcessing;
500 bool isSilence;
501 UInt32 numFrames; numFrames = processor.MaxFramesPerRender();
502
503#if CA_AU_PROFILE_TIME
504 sReadTime = 0;
505 sRenderTime = 0;
506#endif
507
508PRINT_MARKS();
509 // this is the render loop
510 while (!isDone)
511 {
512 #if CA_AU_PROFILE_TIME
513 UInt64 now = CAHostTimeBase::GetTheCurrentTime();
514 #endif
515 outputList.Prepare(); // have to do this every time...
516 require_noerr (result = processor.Render (outputList.ABL(), numFrames, isSilence, &isDone,
517 &needsPostProcessing), home);
518 #if CA_AU_PROFILE_TIME
519 sRenderTime += (CAHostTimeBase::GetTheCurrentTime() - now);
520 #endif
521
522if (!shortMemoryProfile)
523 PRINT_PROGRESS(processor.GetOLPercentComplete());
524else
525 PRINT_PROGRESS(((processor.SampleTime() / numInputSamples) * 100.));
526
527 if (numFrames && !shortMemoryProfile)
528 destFile.Write (numFrames, outputList.ABL());
529 }
530
531 // this is the postprocessing if needed
532 if (!shortMemoryProfile && needsPostProcessing)
533 {
534 isDone = false;
535 numFrames = processor.MaxFramesPerRender();
536 while (!isDone) {
537 outputList.Prepare(); // have to do this every time...
538 #if CA_AU_PROFILE_TIME
539 UInt64 now = CAHostTimeBase::GetTheCurrentTime();
540 #endif
541 require_noerr (result = processor.PostProcess (outputList.ABL(), numFrames,
542 isSilence, isDone), home);
543 #if CA_AU_PROFILE_TIME
544 sRenderTime += (CAHostTimeBase::GetTheCurrentTime() - now);
545 #endif
546
547PRINT_PROGRESS(processor.GetOLPercentComplete());
548
549 if (numFrames && !shortMemoryProfile)
550 destFile.Write (numFrames, outputList.ABL());
551 }
552 }
553
554printf ("\n");
555
556home:
557 if (result) {
558 printf ("Exit with bad result:%ld\n", result);
559 exit(result);
560 }
561
562 if (readBuf) {
563 delete readBuf->readData;
564 delete readBuf;
565 }
566
567#if CA_AU_PROFILE_TIME
568 if (!shortMemoryProfile) {
569 // this flushes any remaing data to be written to the disk.
570 // the source file is closed in its destructor of course
571 destFile.Close();
572 // open the file again, to get stats about it for profiling
573 destFile.Open(destFilePath);
574 }
575
576 SInt64 numWritten;
577 if (shortMemoryProfile)
578 numWritten = 0;
579 else {
580#if !CAAF_USE_EXTAUDIOFILE
581 numWritten = destFile.GetNumberPackets();
582#else
583 numWritten = destFile.GetNumberFrames();
584#endif
585 }
586
587 printf ("Read File Time:%.2f secs for %lld packets (%.1f secs), wrote %lld packets\n",
588 (CAHostTimeBase::ConvertToNanos (sReadTime) / 1.0e9),
589 numInputSamples,
590 (numInputSamples / procFormat.mSampleRate),
591 numWritten);
592
593 if (!shortMemoryProfile)
594 {
595#if !CAAF_USE_EXTAUDIOFILE
596 UInt64 numOutputSamples = destFile.GetNumberPackets();
597#else
598 UInt64 numOutputSamples = destFile.GetNumberFrames();
599#endif
600
601 if (numOutputSamples == numInputSamples) {
602 printf ("\tWrote the same number of packets as read\n");
603 } else {
604 bool expectationMet = !desc.IsOffline(); // we don't have any expectations for offline AU's
605 if (processor.LatencySampleCount() || processor.TailSampleCount()) {
606 if (numOutputSamples - numInputSamples == processor.TailSampleCount())
607 expectationMet = true;
608 if (expectationMet)
609 printf ("Correctly wrote \'Read Size + Tail\'. ");
610 printf ("AU reports (samples): %ld latency, %ld tail\n",
611 processor.LatencySampleCount(), processor.TailSampleCount());
612 }
613 if (expectationMet == false)
614 {
615 if (numOutputSamples > numInputSamples) {
616 printf ("\tWrote %lld packets (%.2f secs) more than read\n",
617 (numOutputSamples - numInputSamples),
618 ((numOutputSamples - numInputSamples) / procFormat.mSampleRate));
619 } else {
620 printf ("\tRead %lld packets (%.2f secs) more than wrote\n",
621 (numInputSamples - numOutputSamples),
622 ((numInputSamples - numOutputSamples) / procFormat.mSampleRate));
623 }
624 }
625 }
626 }
627
628 Float64 renderTimeSecs = CAHostTimeBase::ConvertToNanos (sRenderTime - sReadTime) / 1.0e9;
629 printf ("Total Render Time:%.2f secs, using render slice size of %ld frames\n",
630 renderTimeSecs, maxFramesToUse);
631
632 Float64 cpuUsage;
633 if (shortMemoryProfile)
634 cpuUsage = (renderTimeSecs / 0.5) * 100.;
635 else
636 cpuUsage = (renderTimeSecs / (numInputSamples / procFormat.mSampleRate)) * 100.;
637 printf ("CPU Usage for Render Time:%.2f%%\n", cpuUsage);
638
639 CFStringRef str = comp.GetCompName();
640 UInt32 compNameLen = CFStringGetLength (str);
641
642 CFStringRef presetName = NULL;
643 if (auPresetFile) {
644 CFPropertyListRef dict;
645 if (processor.AU().GetAUPreset (dict) == noErr) {
646 presetName = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)dict, CFSTR("name"));
647 CFRelease (dict);
648 }
649 }
650
651 UInt32 presetLen = presetName ? CFStringGetLength(presetName) : 0;
652
653 char* cstr = (char*)malloc (compNameLen + presetLen + 2 + 1);
654 CFStringGetCString (str, cstr, (CFStringGetLength (str) + 1), kCFStringEncodingASCII);
655 if (presetName) {
656 cstr[compNameLen] = ':';
657 cstr[compNameLen+1] = ':';
658 CFStringGetCString (presetName, cstr + compNameLen + 2, (CFStringGetLength (presetName) + 1), kCFStringEncodingASCII);
659 }
660 PerfResult("AudioUnitProcess", EndianU32_NtoB(comp.Desc().componentSubType), cstr, cpuUsage, "%realtime");
661 free (cstr);
662#endif
663
664
665 }
666 catch (CAXException &e) {
667 char buf[256];
668 printf("Error: %s (%s)\n", e.mOperation, e.FormatError(buf, sizeof(buf)));
669 exit(1);
670 }
671 catch (...) {
672 printf("An unknown error occurred\n");
673 exit(1);
674 }
675
676 return 0;
677}
678