This is the home of the Destroy FX Audio Unit utilities library


Introduction

Hello. Here you will find information about a library of helpful functions for dealing with Audio Units in Mac OS X, written by Sophia Poirier of Destroy FX. Currently, the library contains code that is useful for these things:


License

This library binary and source code are released under the terms of a modified BSD License. It allows you to still use the library even if your project is not open source, although we still strongly encourage open source music software development. The documentation (what you are looking at right now) is released under the terms of the GNU Free Documentation License, with the exception of the example code snippets (in sections labeled "programming example"), which, like the other source code, are released under the terms of the same modified BSD License.


How to get it

You can download the packaged up distribution. It contains documentation, header files, a pre-built Mach-O library, resource files, and source files. Since I might not always keep that perfectly up to date, you can always find the latest sources in the Destroy FX Subversion repository at SourceForge. To checkout the latest stuff from our Destroy FX Library, you can run this command in a shell:

svn checkout https://destroyfx.svn.sourceforge.net/svnroot/destroyfx/dfx-library dfx-library

Or you can browse the files via the ViewVC web interface, if you prefer. Please note that there are a lot of files in the repository, most of which are not a part of this library. The files that comprise this library are the ones that start with dfx-au-utilities in their names and the ones in the {language-code}.lproj bundles (those are localized resource files, where {language-code} is an ISO 639 language code).


How to use it

First, you are going to want to read the documentation for any part of the library that you are planning to utilize. This section, however, contains some general info about how to incorporate the library into your project.

The simplest way to use the library is to #include "dfx-au-utilities.h" and link against the pre-built static library lib-dfx-au-utilities.a. If you are using any of the AU preset file stuff in the library, you will also need to include the resource files that are in the localized {language-code}.lproj bundles (where {language-code} is an ISO 639 language code). Those bundles contain Interface Builder *.nib files and localized string *.strings files. I have named them in such a way that they should hopefully not clash with the names of anyone else's existing resource files. Note that, if you rename these resource files, the library will not work, unless you also modify the source code to reference the new file names. HELP WANTED: Currently, the only languages included are English, Dutch (thanks to Koen Tanghe), and French (thanks to Airy André). If you make translations for any other languages, please share! I'd love to include them in the distribution. You can edit any nib stuff in Interface Builder and the source code files can be processed with Apple's genstrings tool.

If you don't want to use the pre-built library, or if you want to make modifications to the source code, then instead of linking against the pre-built library, you will want to compile and link all of the *.c source files. There is also a header file named dfx-au-utilities-private.h that contains an interface for the functions that are used by the functions defined in the primary interface. If you're interested, you may want to check that stuff out, and perhaps you'll find something useful for your projects, in which case you can also #include "dfx-au-utilities-private.h" in your source code to be able to access and use those functions. I am not going to really document that stuff, though, since I don't consider it to be the important stuff, and I'd prefer to keep things simple and clean.

This library relies on some code in the AudioUnit.framework and AudioToolbox.framework system frameworks, so if your project does not already link against those, then you will need to add them to your project.

This library presents a C API. However, whenever possible (and sensible), transactions are done with CoreFoundation types. This means that Objective C developers can easily utilize the code, since CF types are interchangeable between Carbon and Cocoa.


Contact the author

There is a contact form at the bottom of destroyfx.org which you can use to contact Sophia. If you experience any problems with the library or make any interesting modifications, please let me know! If you have a question about any of this stuff, please feel free to ask me; that way I know what is lacking or unclear in the documentation.






Documentation

Finding, loading, and saving AU preset files

CFArray callbacks for Factory Presets arrays

CFArray callbacks for AU Migrate arrays

Getting an un-opened Component's version from its resource file

Getting an AU's plugin name and manufacturer name

Comparing ComponentDescriptions

System availability / host support

Posting parameter change notifications






Finding, loading, and saving AU preset files


Why this matters

In Mac OS X, there are standardized locations for Audio Unit preset files:

	~/Library/Audio/Presets/{manufacturer-name}/{plugin-name}
	/Library/Audio/Presets/{manufacturer-name}/{plugin-name}
	/Network/Library/Audio/Presets/{manufacturer-name}/{plugin-name}

(where {manufacturer-name} is the first part of the name from the Component name string and {plugin-name} is the second part of that string)

In order to best take advantage of the benefits that users get from centralized and standardized plugin settings locations, every AU host should should make it brain-dead easy for users to save to those locations and to access the preset files that are stored in those locations. The user should not have to think about this issue; things should just work smoothly. Otherwise, you can be sure that virtually no users will be going to the trouble of navigating to the proper standard folder, and then they will lose out.

Rather than simply proposing a solution and leaving it up to everyone to implement in their own way, I decided to just provide one that everyone can use. Using this library, you can do things The Right Way™ without hardly having to think about it. There is a save file dialog that gives the user an extremely simple and fool-proof interface for saving their AU preset files. It has a text edit field for the preset name. That's all that there is, and that's all that there needs to be. The file then is saved in the user domain, where user-authored files should go. But just in case the user wants to save in a weird location, there is a "Choose custom location..." button that will bring up a Navigation Services save file dialog. For finding and opening AU preset files, there is a function that you can call that will return a CFTree of all of the preset files for a given AU in a given file system domain. You can use this to generate a menu of preset files, or whatever other sort of interface works for your particular application. (This side of things isn't as ready-made as the saving side of things, but that is because I don't want to pretend that I know how everyone's interface could best present a collection of preset file names to the user.) There is also a function for reading an AU preset file's data and applying it as the new state data for an AU instance.

I really think that it would be a big improvement if every host had behavior like this. Users want an easy way to have their plugin settings accessible in all of their plugin host apps. This gives them that, and makes it fool-proof. Users don't want to always worry about where their files are being saved and always be asked to choose a location. This gives them that. It gives a clean, simple system with advantages of great interoperability, which is what plugins are supposed to be all about.


Functions

SaveAUStateToPresetFile
SaveAUStateToPresetFile_Bundle

CFTreeCreateFromAUPresetFilesInDomain
GetCFURLFromFileURLsTreeNode
CopyAUPresetNameFromCFURL
RestoreAUStateFromPresetFile
CustomRestoreAUPresetFile
GetAUComponentDescriptionFromStateData
GetAUComponentDescriptionFromPresetFile

To give you a better understanding of the purposes of these functions, here's what I think the ideal host behavior might be, using these functions:

For each instanciated AU, the host offers a menu for preset file stuff. The first item in the menu says "Save Preset File..." When the user chooses that menu item, the host calls SaveAUStateToPresetFile.

The host calls CFTreeCreateFromAUPresetFilesInDomain for each relevant file system domain: kUserDomain, kLocalDomain, and kNetworkDomain. For each one that returns a valid CFTree, the host creates a sub-menu item accordingly: "User presets", "Local presets", and "Network presets". The host populates those sub-menus by walking through the respective trees. For each node in the tree, the host uses GetCFURLFromFileURLsTreeNode to get the CFURL for that tree node. For each file CFURL in the tree, the host uses CopyAUPresetNameFromCFURL to get a CFString to use as the text for that menu item. For each sub-directory CFURL in the tree, the host uses CFURLCopyLastPathComponent to get a CFString to use as the text for that menu item, and makes that menu item another sub-menu for all of the children of that tree node. Now the sub-menus are complete. When the user chooses any one of the preset files from these sub-menus, the host uses RestoreAUStateFromPresetFile to load that file in the AU.

Finally, there is one more item in this menu: "Load Preset File..." When the user chooses that item, the host calls CustomRestoreAUPresetFile.



SaveAUStateToPresetFile

ComponentResult SaveAUStateToPresetFile(AudioUnit inAUComponentInstance, CFStringRef inDefaultAUPresetName, CFURLRef * outSavedAUPresetFileURL)

inAUComponentInstance
The AudioUnit instance whose state data (ClassInfo AU property) you want to write out to a preset file.

inDefaultAUPresetName
The default AU preset name that you would like to appear as the initial text in the file name field of the Save dialog. Can be NULL.

outSavedAUPresetFileURL
Upon successful return, this may point to a CFURLRef that references the file to which the data was saved. Can be NULL.

result
A result code: noErr if the operation was successful, otherwise some appropriate error code. If the user changed her mind and canceled the Save dialog, then the error code will be userCanceledErr. If the AU's state data could not be retrieved, then the error code will be whatever the AU itself or the Component Manager returned. If there was an error writing the data to disk, then the error code will be whatever CFURL error was returned when attempting the operation. If there was a problem finding the standard location for the AU for saving the file, then an appropriate error code will be returned. If there was an error finding or opening the nib resource file or the dialog window information contained in it, then the error code encountered when attempting those operations will be returned. If any necessary CoreFoundation objects could not be created, then coreFoundationUnknownErr is returned. If the user chose "Choose custom location...", then any errors encountered when creating and running the Navigation Services PutFile dialog will be returned.


explanation

This is the function that you use when the user wants to export a preset file for an AU to disk. It's very simple to use and does pretty much all of the work for you.

The user does not need to type the preset name with the .aupreset file name extension appended. It will be automatically appended for the output file name. But if the user did type the name with .aupreset appended, that will be noted and nothing extra will be appended.

If the file name is too long, it will be truncated (before appending the .aupreset extension, so the extension is always complete).

If the caller has some reason to suggest a default name for the new AU preset file (like maybe the host interface provides a means for the user to name the current AU state before exporting it), then that name can be passed in as the inDefaultAUPresetName argument. If you are not interested in providing a default name, then pass in NULL for inDefaultAUPresetName.

You should not provide inDefaultAUPresetName with the .aupreset file name extension appended to it. That will be done automatically.

The caller is responsible for releasing inDefaultAUPresetName when done with it. SaveAUStateToPresetFile does not consume a reference to inDefaultAUPresetName, nor is it retained.

This function sets the value of the kAUPresetNameKey in the saved preset dictionary to name that the user enters as the file name. This is the expected behavior when saving AU preset files.

If you are interested in knowing to which file the AU state data was saved, you can provide a valid pointer to a CFURLRef for the outSavedAUPresetFileURL argument. If you are not interested, pass in NULL for outSavedAUPresetFileURL. But please note that it might be the case that no valid reference is available before this function returns. Therefore, if you do pass in a valid reference to a CFURLRef for the outSavedAUPresetFileURL argument, the you should first NULL the CFURLRef. If the function returns successfully, you still must check to see if your CFURLRef is still null in order to determine if the CFURL was able to be provided. If the CFURL is not null, then you own a reference to it and are responsible for releasing it when done with it.

Note that, because of Navigation Services modality, if the user chooses to save to a non-standard location using the Nav Services PutFile dialog, you might not see the error code result from that save operation. If the dialog fails to run, you will get an error code for that, but not necessarily an error code indicating whether or not the write operation succeeded. If the dialog runs modally, you will get the final result, but if it is modeless, you will not. I might try to address this shortcoming in the future.

Similarly, it may not be possible to get the CFURL of the saved file. Again, if the caller passes a reference to a CFURLRef for the outSavedAUPresetFileURL argument, the caller should first NULL the CFURLRef, since it might be the case that no valid reference is available before this function returns.

The Nav Services PutFile dialog defaults to starting the off in the User domain standard preset location for the AU. If that directory or any of its parent directories do not already exist, they will be (if possible) created. If they could not be created, then no particular default starting location is set.

When you call this function, all of the resources for the dialogs and message alerts are searched for in the main application bundle. If you are hosting an Audio Unit but are not the running application, you need to call the SaveAUStateToPresetFile_Bundle function instead so that you can specify the bundle where the resources can be found.

legacy note: (The following only applies if you are using a pre-2008 version of the library nib files which included a domain-choice radio control.) If the error was a write permissions error and the user's chosen save-to file system domain was not the user domain, then a pre-made error message will be shown informing the user that there was an access privileges error and that the user should try saving in the user domain, and then the dialog will automatically change the domain selection to User. The dialog will remain open and you (the caller) will not see this error return. Any other errors will be returned, though, and you should do what you need to do to inform the user of the error that occurred.



SaveAUStateToPresetFile_Bundle

ComponentResult SaveAUStateToPresetFile_Bundle(AudioUnit inAUComponentInstance, CFStringRef inDefaultAUPresetName, CFURLRef * outSavedAUPresetFileURL, CFBundleRef inBundle)

inAUComponentInstance
The AudioUnit instance whose state data (ClassInfo AU property) you want to write out to a preset file.

inDefaultAUPresetName
The default AU preset name that you would like to appear as the initial text in the file name field of the Save dialog. Can be NULL.

outSavedAUPresetFileURL
Upon successful return, this may point to a CFURLRef that references the file to which the data was saved. Can be NULL.

inBundle
A reference to the bundle where the dialog and message resources can be found. If NULL, then the main application bundle is used.

result
A result code, the same as with SaveAUStateToPresetFile.


explanation

This is a variant of SaveAUStateToPresetFile that allows you to specify the bundle where the dialog and message resources are located. You should use this function if you are calling from some plugin or framework or anything other than the running application.


programming example

Here's an example of how an AUCarbonView might use this function to load a preset file for its associated Audio Unit:

CFBundleRef pluginBundle = CFBundleGetBundleWithIdentifier(CFSTR("org.destroyfx.MegaEffect"));
if (pluginBundle != NULL)
{
	CFURLRef savedFileUrl = NULL;
	ComponentResult result = SaveAUStateToPresetFile_Bundle(GetEditAudioUnit(), NULL, &savedFileUrl, pluginBundle);
	if ( (result == noErr) && (savedFileUrl != NULL) )
	{
		CFShow(savedFileUrl);	/* print info about the saved file's URL to stderr */
		CFRelease(savedFileUrl);
	}
}



CFTreeCreateFromAUPresetFilesInDomain

CFTreeRef CFTreeCreateFromAUPresetFilesInDomain(Component inAUComponent, short inFileSystemDomain)

inAUComponent
The AU Component whose preset files you want to find. Note: you can cast a ComponentInstance or AudioUnit to Component for this.

inFileSystemDomain
The file system domain FindFolder constant for the domain that you want to search in for preset files. Valid values are kUserDomain, kLocalDomain, and kNetworkDomain.

result
A CFTree with the complete hierarchy of preset files and sub-directories for the given AU and domain. The root tree is for the root directory containing the preset files. If no preset files are found or if an error occurs, the result will be NULL. The info field of each tree node's CFTreeContext is a CFURLRef for the preset file or sub-directory.


explanation

This is the function that you use when you want to find out what AU preset files exist on the user's system. In order to find everything in the user's presets collection, you will want to do this for each possible file system domain: kUserDomain, kLocalDomain, and kNetworkDomain.

The caller owns a reference to the CFTree. You should CFRelease it when you are done. When you do that, all child trees and contained CFURLs will be released. The CFURLRef in each tree node is valid for the lifespan of the returned CFTree object. If you are going to release the tree, you should first retain any CFURLs that you still want to be able to access.

If you want an easy way to fetch the CFURL for a given tree node, you can use GetCFURLFromFileURLsTreeNode.

If any sub-directory contains no preset files, then it gets pruned from the tree before this function returns, so you don't need to check for empty branches.

If you want to know whether a given tree node is a reference to a preset file or a sub-directory of preset files, simply check to see if it has any children with CFTreeGetChildCount. If the return count value is greater than 0, then that means that the tree node references a sub-directory; otherwise, it references a file.

If you want to get a nicely displayable name string for a given preset file CFURL (like for the text in a menu entry, without its parent directory path prefixed and without the .aupreset file name extension), you can use CopyAUPresetNameFromCFURL. If you want to do the same thing for a sub-directory CFURL, simply use the CFURLCopyLastPathComponent function (which is part of the regular CoreFoundation API).

This function checks each file found to determine if it is an AU preset type file, based on its file name extension (.aupreset). It also examines the data in the file to determine whether it is valid AU state data for the specified AU (i.e. the identifying values must match the AU's ComponentDescription, which is determined by using ComponentAndDescriptionMatch_Loosely). Any files that don't pass either of these examinations are excluded from the tree. There should not ever be preset files for the wrong AU in the standard locations, but just in case there are, they will be excluded.


programming example

Here's an example recursive function that walks through the CFTree hierarchy, looks at each node and determines if it's a file or sub-directory, gets the CFURLRef for each node, and uses CFShow to print a description of the CFURL to stderr:

void showtree(CFTreeRef inTree)
{
	if (inTree == NULL)
		fprintf(stderr, "tree is null!\n");
	else
	{
		if (CFTreeGetChildCount(inTree) > 0)
			fprintf(stderr, "this tree node represents a sub-directory of preset files\n");
		else
			fprintf(stderr, "this tree node represents a preset file\n");
		CFURLRef treeItemURL = GetCFURLFromFileURLsTreeNode(inTree);
		CFShow(treeItemURL);
		CFTreeRef child = CFTreeGetFirstChild(inTree);
		if (child != NULL)
			showtree(child);
		CFTreeRef next = CFTreeGetNextSibling(inTree);
		if (next != NULL)
			showtree(next);
	}
}

And here's an example of using the above function to find all of the AU preset files in each valid file system domain, for a given AU Component:

CFTreeRef aupresetsTree;

fprintf(stderr, "\n\tlooking in the user domain for preset files...\n");
aupresetsTree = CFTreeCreateFromAUPresetFilesInDomain(someAUComponent, kUserDomain);
showtree(aupresetsTree);
if (aupresetsTree != NULL)
	CFRelease(aupresetsTree);

fprintf(stderr, "\n\tlooking in the local domain for preset files...\n");
aupresetsTree = CFTreeCreateFromAUPresetFilesInDomain(someAUComponent, kLocalDomain);
showtree(aupresetsTree);
if (aupresetsTree != NULL)
	CFRelease(aupresetsTree);

fprintf(stderr, "\n\tlooking in the network domain for preset files...\n");
aupresetsTree = CFTreeCreateFromAUPresetFilesInDomain(someAUComponent, kNetworkDomain);
showtree(aupresetsTree);
if (aupresetsTree != NULL)
	CFRelease(aupresetsTree);



GetCFURLFromFileURLsTreeNode

CFURLRef GetCFURLFromFileURLsTreeNode(CFTreeRef inTree)

inTree
A CFTreeRef that holds a CFURLRef in the info field of its CFTreeContext.

result
The CFURLRef that is contained in the input tree, or NULL if something goes wrong.


explanation

You use this function when you want to access one of the files or sub-directories in the tree that is returned by CFTreeCreateFromAUPresetFilesInDomain. The file or sub-directory CFURL reference is contained in the info field of each tree node's CFTreeContext structure. Since there's no very quick and convenient way to access that tree data pointer, I wrote this function to make it easy.

This function simply returns the pointer value without retaining the CFURL. The tree owns a reference to the CFURL. If you need to keep a reference to the CFURL beyond the life of its owner tree, then you are responsible for retaining it and then releasing it when you are done.


programming example

See RestoreAUStateFromPresetFile for a usage example.



CopyAUPresetNameFromCFURL

CFStringRef CopyAUPresetNameFromCFURL(CFURLRef inAUPresetFileURL)

inAUPresetFileURL
A CFURLRef representing an AU preset file.

result
A CFStringRef that has the name of the file represented by the input file without the .aupreset file name extension. If anything goes wrong, the result is NULL. If the input CFURL does not represent a file with an extension, then I'm not sure what happens, whatever happens when you do that with CFURLCreateCopyDeletingPathExtension.


explanation

This is a convenience function for getting a more user-friendly display text of an AU preset file from a CFURL reference to the file. It removes the parent directory path and the .aupreset file name extension, returning only the name of the file without file name extension. You will probably want to use this function when generating a user interface to the preset files in the user's collection.

The caller owns a reference to the returned CFString and is responsible for releasing it when done.


programming example

Here's an example that iterates through every sibling in one level of a preset files tree and uses the readable name from CopyAUPresetNameFromCFURL to set the text of each item in a menu:

CFIndex numChildren = CFTreeGetChildCount(parentTree);
SetControlMaximum(yourMenuControl, numChildren);
CFTreeRef presetFileTreeNode = CFTreeGetFirstChild(parentTree);
for (CFIndex i=0; i < numChildren; i++)
{
	CFURLRef theFile = GetCFURLFromFileURLsTreeNode(presetFileTreeNode);
	CFStringRef itemName = NULL;
	/* it's a sub-directory of preset files */
	if (CFTreeGetChildCount(presetFileTreeNode) > 0)
		itemName = CFURLCopyLastPathComponent(theFile);
	/* it's a preset file */
	else
		itemName = CopyAUPresetNameFromCFURL(theFile);
	if (itemName != NULL)
	{
		SetMenuItemTextWithCFString(yourMenu, i+1, itemName);
		CFRelease(itemName);
	}
	presetFileTreeNode = CFTreeGetNextSibling(presetFileTreeNode);
}



RestoreAUStateFromPresetFile

ComponentResult RestoreAUStateFromPresetFile(AudioUnit inAUComponentInstance, CFURLRef inAUPresetFileURL)

inAUComponentInstance
The AudioUnit instance whose state data (ClassInfo AU property) you want to restore from a preset file on disk.

inAUPresetFileURL
A CFURLRef that references the AU preset file that contains the AU state data that you would like to restore.

result
A result code: noErr if the operation was successful, otherwise some appropriate error code. If the AU's state data could not be restored, then the error code will be whatever the AU itself or the Component Manager returned. If there was an error reading the data from disk, then the error code will be whatever CFURL error was returned when attempting the operation. If the file's data was not valid XML data that could be translated into a CFPropertyList, then coreFoundationUnknownErr or whatever error code was encountered during that operation is returned.


explanation

This is the function that you would use to get the data from an AU preset file and set that as the current state of an Audio Unit. For example, you might call this after you have used CFTreeCreateFromAUPresetFilesInDomain to get a tree of the user's preset files collection, presented that collection to the user, and then the user indicated that she wanted to load one of those presets.

The caller is responsible for releasing inAUPresetFileURL when done with it. RestoreAUStateFromPresetFile does not consume a reference to inAUPresetFileURL, nor is it retained.


programming example

CFTreeRef aupresetsTree = CFTreeCreateFromAUPresetFilesInDomain((Component)someAUInstance, kUserDomain);
/* ...do something here to present the tree to the user... */
/* ...the user chooses a file... */
/* ...get the tree node corresponding to that file... */
CFURLRef theFile = GetCFURLFromFileURLsTreeNode(presetTreeNode);
ComponentResult result = RestoreAUStateFromPresetFile(someAUInstance, theFile);



CustomRestoreAUPresetFile

ComponentResult CustomRestoreAUPresetFile(AudioUnit inAUComponentInstance)

inAUComponentInstance
The AudioUnit instance whose state data (ClassInfo AU property) you want to restore from a preset file on disk.

result
A result code: noErr if the operation was successful, otherwise some appropriate error code. If any error is encountered when creating and running the Navigation Services GetFile dialog, then that will be returned.


explanation

This function will bring up a Navigation Services GetFile dialog that will allow the user to locate a preset file anywhere. If a file is chosen, the data will be read from disk and, if that is successful, an attempt will be made to restore the data as the new state for the AU.

Note that, because of Navigation Services modality, you might not see the error code result from the GetFile dialog response, file reading operations, or AU state restoring operations. If the dialog fails to run, you will get an error code for that, but not necessarily any error codes indicating whether or not the file reading or AU state data restoring operations succeeded. If the dialog runs modally, you will get the final result, but if it is modeless, you will not. I might try to address this shortcoming in the future.

The GetFile dialog will filter out any files that are not AU preset type files, as determined by the file name extension (.aupreset). It will also examine AU preset files to see if their contents have AU state data with identifying values that match for the specified AU (which is determined by using ComponentAndDescriptionMatch_Loosely), and filter out any files that do not pass this examination.



GetAUComponentDescriptionFromStateData

OSStatus GetAUComponentDescriptionFromStateData(CFPropertyListRef inAUStateData, ComponentDescription * outComponentDescription)

inAUStateData
A CFPropertyListRef containing an AU state data dictionary.

outComponentDescription
Upon successful return, this structure's type, sub-type, and manufacturer ID values will be set to those found in the AU preset file's data (and the other values in the structure will be set to zero).

result
A result code: noErr if the operation was successful, otherwise some appropriate error code. Possible error code is kAudioUnitErr_InvalidPropertyValue if the dictionary is not in the expected format or is missing any of the required keys, or if the dictionary's value for kAUPresetVersionKey is unrecognized.


explanation

AU state data is stored in the form of a CFDictionary. The dictionary is expected to contain values for the type, sub-type, and manufacturer IDs of the specific AU that created the data. This is in order to specify which AU is able read the data. This function collects those identifying values from an AU state data dictionary into a ComponentDescription, providing a simple way to identify the data's creator.

This function is used internally by GetAUComponentDescriptionFromPresetFile to process the data contained in an AU preset file. Since it may also be useful in other contexts, I made it one of the public functions of this library.



GetAUComponentDescriptionFromPresetFile

OSStatus GetAUComponentDescriptionFromPresetFile(CFURLRef inAUPresetFileURL, ComponentDescription * outComponentDescription)

inAUPresetFileURL
A CFURLRef representing an AU preset file.

outComponentDescription
Upon successful return, this structure's type, sub-type, and manufacturer ID values will be set to those found in the AU preset file's data (and the other values in the structure will be set to zero).

result
A result code: noErr if the operation was successful, otherwise some appropriate error code. Possible error codes are those returned by CreatePropertyListFromXMLFile or GetAUComponentDescriptionFromStateData.


explanation

This is a variant of GetAUComponentDescriptionFromStateData that allows you to start with a file reference to an AU preset file and then retrieve the identifying values of the contained AU state data's creator. It is a convenience function that takes care of reading the XML data from the AU preset file, and then from there does the same thing as GetAUComponentDescriptionFromStateData.

This function is used internally by CFTreeCreateFromAUPresetFilesInDomain and CustomRestoreAUPresetFile when they validate an AU preset file's data to see if its identifying values match those of the specified AU. Since it may also be useful in other contexts, I made it one of the public functions of this library.






CFArray callbacks for Factory Presets arrays


Why this matters

CFArrays use a set of callbacks that define what happens to their contained data items when you retain the array, release the array, ask to compare 2 items in the array, or ask for a description of an item in the array. When the data items that an array holds are all CF types, there are standard CF ways to handle all of these situations and a convenient pre-made global CFArray callbacks structure that gives you that behavior (kCFTypeArrayCallBacks). In the AU API, though, you need to make CFArrays of non-CF type data when you support the kAudioUnitProperty_FactoryPresets property. So for those arrays, you need to define custom callbacks that will properly handle pointers to AUPreset structures as their data items. The lifespan of the array may be greater than the lifespan of the plugin and any of its AUPreset data, so you must insure proper memory management of the AUPreset data items when the CFArray is retained and released. That's what my callbacks do, which can be used via the kCFAUPresetArrayCallBacks constant.

Using these callbacks also requires the use of an object that can encompass an AUPreset structure but also hold the necessary extra data to mimic CFType behavior. That is the purpose of the CFAUPresetRef type. It is an opaque type and so there are functions for handling it correctly. You must only use this data type with the Factory Preset array callbacks in this library.


Types

CFAUPresetRef


Functions

CFAUPresetCreate
CFAUPresetRetain
CFAUPresetRelease


Constants

kCFAUPresetArrayCallBacks



CFAUPresetRef

typedef const struct CFAUPreset * CFAUPresetRef


explanation

CFAUPreset is an opaque type that contains an AUPreset structure. It is a wrapper-type object designed to be able to mimic CoreFoundation object behavior for the AUPreset structure.

Please note that CFAUPreset is not a CFType, and therefore CFAUPresetRef is not compatible with any common CoreFoundation functions (like CFRetain, CFRelease, etc.). The functions contained in this library are the only ones that you can use with a CFAUPresetRef.

A CFAUPresetRef can be cast to AUPreset*, but the same is not true for the reverse.



CFAUPresetCreate

CFAUPresetRef CFAUPresetCreate(CFAllocatorRef inAllocator, SInt32 inPresetNumber, CFStringRef inPresetName)

inAllocator
The allocator to use to allocate the memory via CFAllocatorAllocate.

inPresetNumber
The value that you want set as the presetNumber value in the AUPreset.

inPresetName
The string that you want used as the presetName value in the AUPreset.

result
A reference to a newly allocated CFAUPreset object containing an AUPreset with its fields set to the values as passed into this function.


explanation

This function will allocate an instance of a CFAUPreset object and initialize the value fields of its contained AUPreset structure according to the corresponding arguments of the function.

The caller owns a reference to the returned CFAUPresetRef and is responsible for releasing it when done.


programming example

Here's an example implementation of an AUBase-derived AU's GetPresets() method:

ComponentResult MegaEffect::GetPresets(CFArrayRef * outData) const
{
	if (outData == NULL)
		return noErr;

	CFMutableArrayRef newArray = CFArrayCreateMutable(kCFAllocatorDefault, 2, &kCFAUPresetArrayCallBacks);
	if (newArray == NULL)
		return coreFoundationUnknownErr;

	CFAUPresetRef newPreset = CFAUPresetCreate(kCFAllocatorDefault, 1, CFSTR("a preset"));
	if (newPreset != NULL)
	{
		CFArrayAppendValue(newArray, newPreset);
		CFAUPresetRelease(newPreset);
	}

	newPreset = CFAUPresetCreate(kCFAllocatorDefault, 2, CFSTR("another preset"));
	if (newPreset != NULL)
	{
		CFArrayAppendValue(newArray, newPreset);
		CFAUPresetRelease(newPreset);
	}

	*outData = (CFArrayRef)newArray;
	return noErr;
}



CFAUPresetRetain

CFAUPresetRef CFAUPresetRetain(CFAUPresetRef inPreset)

inPreset
A reference to a CFAUPreset object to be retained.

result
A reference to the CFAUPreset object that was retained.


explanation

This function mimics the behavior of CFRetain, but specifically for the CFAUPresetRef type and not any CFTypeRef.



CFAUPresetRelease

void CFAUPresetRelease(CFAUPresetRef inPreset)

inPreset
A reference to a CFAUPreset object to be released.


explanation

This function mimics the behavior of CFRelease, but specifically for the CFAUPresetRef type and not any CFTypeRef.


programming example

See CFAUPresetCreate for a relevant example.



kCFAUPresetArrayCallBacks

const CFArrayCallBacks kCFAUPresetArrayCallBacks


explanation

This CFArrayCallbacks structure is initialized (when your code is loaded) to contain pointers to callbacks that will correctly handle retaining, releasing, comparing, and describing CFArrays that contain CFAUPresetRef instances as their data items. You can pass this for the CFArrayCallbacks* argument when creating arrays with CFArrayCreate or CFArrayCreateMutable.


programming example

See CFAUPresetCreate for a relevant example.






CFArray callbacks for AU Migrate arrays


Why this matters

CFArrays use a set of callbacks that define what happens to their contained data items when you retain the array, release the array, ask to compare 2 items in the array, or ask for a description of an item in the array. When the data items that an array holds are all CF types, there are standard CF ways to handle all of these situations and a convenient pre-made global CFArray callbacks structure that gives you that behavior (kCFTypeArrayCallBacks). In the AU API, though, you need to make CFArrays of non-CF type data when you support the kAudioUnitMigrateProperty_FromPlugin property. So for those arrays, you need to define custom callbacks that will properly handle pointers to AudioUnitOtherPluginDesc structures as their data items. The lifespan of the array may be greater than the lifespan of the plugin and any of its AudioUnitOtherPluginDesc data, so you must insure proper memory management of the AudioUnitOtherPluginDesc data items when the CFArray is retained and released. That's what my callbacks do, which can be used via the kCFAUOtherPluginDescArrayCallBacks constant.

Using these callbacks also requires the use of an object that can encompass an AudioUnitOtherPluginDesc structure but also hold the necessary extra data to mimic CFType behavior. That is the purpose of the CFAUOtherPluginDescRef type. It is an opaque type and so there are functions for handling it correctly. You must only use this data type with the AU Migrate array callbacks in this library.


Types

CFAUOtherPluginDescRef


Functions

CFAUOtherPluginDescCreate
CFAUOtherPluginDescCreateVST
CFAUOtherPluginDescCreateMAS
CFAUOtherPluginDescRetain
CFAUOtherPluginDescRelease


Constants

kCFAUOtherPluginDescArrayCallBacks



CFAUOtherPluginDescRef

typedef const struct CFAUOtherPluginDesc * CFAUOtherPluginDescRef


explanation

CFAUOtherPluginDesc is an opaque type that contains an AudioUnitOtherPluginDesc structure. It is a wrapper-type object designed to be able to mimic CoreFoundation object behavior for the AudioUnitOtherPluginDesc structure.

Please note that CFAUOtherPluginDesc is not a CFType, and therefore CFAUOtherPluginDescRef is not compatible with any common CoreFoundation functions (like CFRetain, CFRelease, etc.). The functions contained in this library are the only ones that you can use with a CFAUOtherPluginDescRef.

A CFAUOtherPluginDescRef can be cast to AudioUnitOtherPluginDesc*, but the same is not true for the reverse.



CFAUOtherPluginDescCreate

CFAUOtherPluginDescRef CFAUOtherPluginDescCreate(CFAllocatorRef inAllocator, UInt32 inFormat, OSType inTypeID, OSType inSubTypeID, OSType inManufacturerID)

inAllocator
The allocator to use to allocate the memory via CFAllocatorAllocate.

inFormat
The value that you want set as the format value in the AudioUnitOtherPluginDesc.

inTypeID
The value that you want set as the mType value in the AudioUnitOtherPluginDesc.

inSubTypeID
The value that you want set as the mSubType value in the AudioUnitOtherPluginDesc.

inManufacturerID
The value that you want set as the mManufacturer value in the AudioUnitOtherPluginDesc.

result
A reference to a newly allocated CFAUOtherPluginDesc object containing an AudioUnitOtherPluginDesc with its fields set to the values as passed into this function.


explanation

This function will allocate an instance of a CFAUOtherPluginDesc object and initialize the value fields of its contained AudioUnitOtherPluginDesc structure according to the corresponding arguments of the function.

The caller owns a reference to the returned CFAUOtherPluginDescRef and is responsible for releasing it when done.


programming example

See CFAUOtherPluginDescCreateVST for a closely related example.



CFAUOtherPluginDescCreateVST

CFAUOtherPluginDescRef CFAUOtherPluginDescCreateVST(CFAllocatorRef inAllocator, OSType inUniqueID)

inAllocator
The allocator to use to allocate the memory via CFAllocatorAllocate.

inUniqueID
The compatible VST plugin's "unique ID" value.

result
A reference to a newly allocated CFAUOtherPluginDesc object containing an AudioUnitOtherPluginDesc with its fields set correctly for specifying a VST plugin with the identifying value as passed into this function.


explanation

This function will allocate an instance of a CFAUOtherPluginDesc object and initialize the value fields of its contained AudioUnitOtherPluginDesc structure according to specifying a VST plugin the corresponding argument of the function.

The caller owns a reference to the returned CFAUOtherPluginDescRef and is responsible for releasing it when done.

This function is a convenience wrapper for CFAUOtherPluginDescCreate.


programming example

Here's an example implementation the GetProperty method, specifically overridden for the kAudioUnitMigrateProperty_FromPlugin property, for an AUEffectBase-derived AU that has VST and MAS counterpart versions with importable settings:

ComponentResult MegaEffect::GetProperty(AudioUnitPropertyID inPropertyID, 
					AudioUnitScope inScope, AudioUnitElement inElement, 
					void * outData)
{
	if (inPropertyID == kAudioUnitMigrateProperty_FromPlugin)
	{
		CFMutableArrayRef descsArray = CFArrayCreateMutable(kCFAllocatorDefault, 2, &kCFAUOtherPluginDescArrayCallBacks);
		if (descsArray == NULL)
			return coreFoundationUnknownErr;

		CFAUOtherPluginDescRef otherPluginMigrateDesc = CFAUOtherPluginDescCreateVST(kCFAllocatorDefault, 'Plug');
		if (otherPluginMigrateDesc != NULL)
		{
			CFArrayAppendValue(descsArray, otherPluginMigrateDesc);
			CFAUOtherPluginDescRelease(otherPluginMigrateDesc);
		}

		otherPluginMigrateDesc = CFAUOtherPluginDescCreateMAS(kCFAllocatorDefault, 'Plug', 3, 'Acme');
		if (otherPluginMigrateDesc != NULL)
		{
			CFArrayAppendValue(descsArray, otherPluginMigrateDesc);
			CFAUOtherPluginDescRelease(otherPluginMigrateDesc);
		}

		*((CFArrayRef*)outData) = descsArray;
		return noErr;
	}

	return AUEffectBase::GetProperty(inPropertyID, inScope, inElement, outData);
}



CFAUOtherPluginDescCreateMAS

CFAUOtherPluginDescRef CFAUOtherPluginDescCreateMAS(CFAllocatorRef inAllocator, OSType inEffectID, OSType inVariantID, OSType inManufacturerID)

inAllocator
The allocator to use to allocate the memory via CFAllocatorAllocate.

inEffectID
The compatible MAS plugin's masEffectID value.

inVariantID
The compatible MAS plugin's masVariantID value.

inManufacturerID
The compatible MAS plugin's masManufacturer value.

result
A reference to a newly allocated CFAUOtherPluginDesc object containing an AudioUnitOtherPluginDesc with its fields set correctly for specifying a MAS plugin with the identifying values as passed into this function.


explanation

This function will allocate an instance of a CFAUOtherPluginDesc object and initialize the value fields of its contained AudioUnitOtherPluginDesc structure according to specifying a MAS plugin the corresponding arguments of the function.

The caller owns a reference to the returned CFAUOtherPluginDescRef and is responsible for releasing it when done.

This function is a convenience wrapper for CFAUOtherPluginDescCreate.


programming example

See CFAUOtherPluginDescCreateVST for a relevant example.



CFAUOtherPluginDescRetain

CFAUOtherPluginDescRef CFAUOtherPluginDescRetain(CFAUOtherPluginDescRef inDesc)

inPreset
A reference to a CFAUOtherPluginDesc object to be retained.

result
A reference to the CFAUOtherPluginDesc object that was retained.


explanation

This function mimics the behavior of CFRetain, but specifically for the CFAUOtherPluginDescRef type and not any CFTypeRef.



CFAUOtherPluginDescRelease

void CFAUOtherPluginDescRelease(CFAUOtherPluginDescRef inDesc)

inPreset
A reference to a CFAUOtherPluginDesc object to be released.


explanation

This function mimics the behavior of CFRelease, but specifically for the CFAUOtherPluginDescRef type and not any CFTypeRef.


programming example

See CFAUOtherPluginDescCreateVST for a relevant example.



kCFAUOtherPluginDescArrayCallBacks

const CFArrayCallBacks kCFAUOtherPluginDescArrayCallBacks


explanation

This CFArrayCallbacks structure is initialized (when your code is loaded) to contain pointers to callbacks that will correctly handle retaining, releasing, comparing, and describing CFArrays that contain CFAUOtherPluginDescRef instances as their data items. You can pass this for the CFArrayCallbacks* argument when creating arrays with CFArrayCreate or CFArrayCreateMutable.


programming example

See CFAUOtherPluginDescCreateVST for a relevant example.






Getting an un-opened Component's version from its resource file


Why this matters

My code is more reliable and many, many, many times faster than using GetComponentVersion. I got thoroughly sick of waiting ages for certain AU host apps to finish launching, so I wrote this function for them to use.

Some Audio Unit host apps like to scan through all of the available Audio Units during launch time in order to query information from each AU. For example, it's common for multi-track audio apps that have mixer-style interfaces to query the SupportedNumChannels property for each plugin in order to determine whether a given plugin should be made available on a mono track, stereo track, etc. Querying properties from Unitialized AUs typically is not very expensive, but when the user's AU collection is very large, the time spent opening, querying properties, and closing every AU can really add up and delay the host app's launch time considerably.

I think that the best way for the host to avoid this inefficiency is to query the required info only upon the first time that it encounters a given AU, and then to cache that info for future reference. However, if an AU's version changes, then you can expect that some of its properties may also have changed, and the cache data will then be incorrect. Because of this, the host should also cache the version value for the AU whenever it caches other data for that AU. Then, during launch time, the host can check the version of each already-known AU, compare it to the value in the cache data, and then, if version values differ, the host knows that it should re-query that info and update the cached data. For this reason, getting an AU's version value quickly and accurately is important.

The problem with the standard way of getting Component version values is that it is neither quick nor accurate, in the case of most AUs. The standard way is to use GetComponentVersion or CallComponentVersion from the official Component API. Both functions do the same thing, which is to use the kComponentVersionSelect selector to query the Component's version value. This is not quick because it requires that you OpenAComponent instance first. It is not accurate because, in my own surveying, I've found that the vast majority of AUs do not properly support the Version selector. However, all of the AUs that I looked at do have proper version values in their 'thng' resources. Since it's easy to not support the selector, but impossible to make an AU without the 'thng' resource, it's a lot easier for a developer to forget about the Version selector, or let it get out of sync with the version in the 'thng' resource. For this reason, it's more reliable to use the version from resource. Plus, you don't need to open a component instance to get that value, you only need a Component record (what you get from FindNextComponent), so performance-wise it is extremely inexpensive, many orders of magnitude faster than using the Version selector. In a test that I performed on my 800 MHz G4 with 300 AUs, using GetComponentVersion took a total of 7.8 seconds, whereas using GetComponentVersionFromResource took only 0.66 seconds.


Functions

GetComponentVersionFromResource



GetComponentVersionFromResource

OSErr GetComponentVersionFromResource(Component inComponent, SInt32 * outVersion)

inComponent
The Component whose version value you want. Note: you can cast a ComponentInstance or AudioUnit to Component for this.

outVersion
A pointer to a SInt32 which, on successful return, will be set to the value of the Component's version.

result
A result code: noErr if the operation was successful, otherwise some appropriate error code. If there was a problem locating the Component, then the error code will be the one that the Component Manager returned. If there were any problems handling the Component's resource, then the error will be the one that the Resource Manager returned. If no version 2 or higher 'thng' resource could be found, then resNotFound is returned.


explanation

You can call this function to get the version of a Component from its resource file, without having to load the Component.

This function works with any type of Component, not just Audio Units, as long as the component has a version 2 or higher 'thng' resource (version 2 was the first version of the 'thng' resource format that contained the version value). All Audio Units use version 2 'thng' resources.






Getting an AU's plugin name and manufacturer name


Why this matters

Audio Unit Component names are formatted in this certain way: "Manufacturer Name: Plugin Name". Very often, AU hosts want to parse out just the plugin name or just the manufacturer name to display to the user. So that's what these functions do. It's a common thing to need to do, and a pretty simple thing, but still I see no reason why every host author should need to write their own parsing code redundantly, so I'm sharing mine. Plus I needed to write this code for the AU preset file handling stuff anyway.

Please note that the "manufacturer: plugin" name format is only an Audio Unit thing, so these functions are not useful for other types of Components.


Functions

CopyAUNameAndManufacturerStrings
GetAUNameAndManufacturerCStrings



CopyAUNameAndManufacturerStrings

OSStatus CopyAUNameAndManufacturerStrings(Component inAUComponent, CFStringRef * outNameString, CFStringRef * outManufacturerString)

inAUComponent
The AU Component whose plugin name and/or manufacturer name you want. Note: you can cast a ComponentInstance or AudioUnit to Component for this.

outNameString
Upon successful return, the CFStringRef will reference a CFString representation of the Audio Unit's specific plugin name. Can be NULL.

outManufacturerString
Upon successful return, the CFStringRef will reference a CFString representation of the Audio Unit's manufacturer name. Can be NULL.

result
A result code: noErr if the operation was successful, otherwise some appropriate error code. If there was any problem creating the CFStrings, coreFoundationUnknownErr is returned. Other possible error codes are the same as the ones described for GetAUNameAndManufacturerCStrings.


explanation

If you only want the plugin name or only want the manufacturer name, you can send a valid pointer to a CFStringRef for the one that you want and NULL for the other one. You cannot, however, send NULL for both. Doing that will result in a paramErr return value, and duh, why would you want to do that anyway?

The caller owns a reference to each output CFString and is responsible for releasing them when done.

This function is a convenience wrapper for GetAUNameAndManufacturerCStrings. Since often you want the strings as CFStrings, this is a handy function. But the actual stored strings for AUs are Pascal strings, so the first step is get them char-style.

Currently, if the caller requests both name strings and only one could be retrieved, an error code will be returned, but the string that was retrieved will be valid on return. I'm not sure what to do about that situation. In practice, it really shouldn't ever happen, but if it does, currently that's the behavior, and it means that you'll get a somewhat misleading result code and potentially leak memory with the CFString that was successfully created.


programming example

Here's an example of getting the name strings for an AU and outputting them to stderr:

CFStringRef nameString, manufacturerString;
OSStatus error = CopyAUNameAndManufacturerStrings(someAUComponent, &nameString, &manufacturerString);
if (error == noErr)
{
	fprintf(stderr, "the name of this plugin is:  ");
	CFShow(nameString);

	fprintf(stderr, "the name of this plugin's manufacturer is:  ");
	CFShow(manufacturerString);

	CFRelease(nameString);
	CFRelease(manufacturerString);
}



GetAUNameAndManufacturerCStrings

OSStatus GetAUNameAndManufacturerCStrings(Component inAUComponent, char * outNameString, char * outManufacturerString)

inAUComponent
The AU Component whose plugin name and/or manufacturer name you want. Note: you can cast a ComponentInstance or AudioUnit to Component for this.

outNameString
Upon successful return, the buffer is filled with a null-terminated C string representation of the Audio Unit's specific plugin name. Can be NULL.

outManufacturerString
Upon successful return, the buffer is filled with a null-terminated C string representation of the Audio Unit's manufacturer name. Can be NULL.

result
A result code: noErr if the operation was successful, otherwise some appropriate error code. If there was any problem creating or getting the handle for the resource name data, nilHandleErr is returned. If getting the Component name info fails, the error code is the one returned by GetComponentInfo. If the Component name string is not in the proper AU colon-delimited format, internalComponentErr is returned.


explanation

If you only want the plugin name or only want the manufacturer name, you can send a valid char pointer for the one that you want and NULL for the other one. You cannot, however, send NULL for both. Doing that will result in a paramErr return value, and duh, why would you want to do that anyway?

Both outNameString and outManufacturerString, if non-null, must be valid char buffers capable of storing as much as 256 bytes each.


programming example

Here's an example of just getting the plugin name C string for an AU and viewing it in stderr:

char nameCString[256];
OSStatus error = GetAUNameAndManufacturerCStrings(someAUComponent, nameCString, NULL);
if (error == noErr)
{
	fprintf(stderr, "the name of this plugin is:  %s\n", nameCString);
}






Comparing ComponentDescriptions


Why this matters

A ComponentDescription is a struct that contains values that together uniquely identify a Component (an Audio Unit is a type of Component). It is what you use to programatically describe a specific Component. The struct contains 5 values, but only 3 of them are actually used for the purposes of uniquely identifying the AU. Occasionally it is useful to compare ComponentDescriptions to see if they match, so these are just some convenience functions that make that simple, comparing on the basis of the 3 identifying values: the type, sub-type, and manufacturer IDs. For example, both CFTreeCreateFromAUPresetFilesInDomain and CustomRestoreAUPresetFile use these functions to compare the ComponentDescription that GetAUComponentDescriptionFromPresetFile supplies to that of a particular AU Component.

These functions also come in "loosely" varieties which match only the sub-type and manufacturer codes (ignoring the type code). The reason for this is that Apple changed the expectations of settings data compatibility in August 2005 (with the release of the CoreAudio SDK version 1.4.2) to allow for compatibility between settings that don't match the type code of a given AU. This allows for you to make different varieties of AUs that are essentially the same plugin in most senses, but different in their type categories (e.g. you may have an offline version and a realtime effect version of some effect). These would share the same sub-type and manufacturer codes and would be expected to be able to read each other's settings data interchangeably.


Functions

ComponentDescriptionsMatch
ComponentDescriptionsMatch_Loosely
ComponentAndDescriptionMatch
ComponentAndDescriptionMatch_Loosely



ComponentDescriptionsMatch

Boolean ComponentDescriptionsMatch(const ComponentDescription * inComponentDescription1, const ComponentDescription * inComponentDescription2)

inComponentDescription1
A pointer to one of the ComponentDescriptions that you want to compare.

inComponentDescription2
A pointer to the ComponentDescription that you want to compare to inComponentDescription1.

result
The result is TRUE if both ComponentDescriptions match, and FALSE otherwise.


explanation

This function compares 2 ComponentDescriptions to see if they match based on their identifying values.



ComponentDescriptionsMatch_Loosely

Boolean ComponentDescriptionsMatch_Loosely(const ComponentDescription * inComponentDescription1, const ComponentDescription * inComponentDescription2)

inComponentDescription1
A pointer to one of the ComponentDescriptions that you want to compare.

inComponentDescription2
A pointer to the ComponentDescription that you want to compare to inComponentDescription1.

result
The result is TRUE if the sub-type and manufacturer codes of both ComponentDescriptions match, and FALSE otherwise.


explanation

This function is the same as ComponentDescriptionsMatch except that it ignores the type codes when comparing.



ComponentAndDescriptionMatch

Boolean ComponentAndDescriptionMatch(Component inComponent, const ComponentDescription * inComponentDescription)

inComponent
A Component whose ComponentDescription you want to compare to another ComponentDescription.

inComponentDescription
The ComponentDescription that you want to compare to inComponent's ComponentDescription.

result
The result is TRUE if inComponent's ComponentDescription matches inComponentDescription, and FALSE otherwise.


explanation

If you are starting with a Component that you want to compare to some ComponentDescription, then this function will do the work of querying the Component's ComponentDescription and then comparing those 2 ComponentDescriptions to see if they match. If querying the ComponentDescription of inComponent's fails, then the function will return FALSE.

This function is a convenience wrapper for ComponentDescriptionsMatch.



ComponentAndDescriptionMatch_Loosely

Boolean ComponentAndDescriptionMatch_Loosely(Component inComponent, const ComponentDescription * inComponentDescription)

inComponent
A Component whose ComponentDescription you want to compare to another ComponentDescription.

inComponentDescription
The ComponentDescription that you want to compare to inComponent's ComponentDescription.

result
The result is TRUE if inComponent's sub-type and manufacturer codes match inComponentDescription's, and FALSE otherwise.


explanation

This function is the same as ComponentAndDescriptionMatch except that it ignores the type codes when comparing.






System availability / host support


Why this matters

Sometimes certain versions of core system software or AU host applications are missing important features or have significant bugs, and it is useful to be able to check on the state of such things in the environment in which your AU is running.


Functions

IsAvailable_AU2rev1
IsTransportStateProcSafe



IsAvailable_AU2rev1

Boolean IsAvailable_AU2rev1()

result
The result is TRUE if the system frameworks implement the AU API version 2 revision 1 or higher, and FALSE otherwise.


explanation

There were some new APIs introduce in AU v2 rev1, such as the AUEventListener stuff. This function lets you check to see if this is available on the system. It's really only useful for Mac OS X 10.2. Systems with Mac OS X 10.3 or higher always have this available, but systems with Mac OS X 10.2 will only have it available if QuickTime 6.4 or higher (with AudioToolbox.framework 1.3 or higher) is installed.



IsTransportStateProcSafe

Boolean IsTransportStateProcSafe()

result
The result is FALSE if you will definitely cause a crash by calling HostCallbackInfo.transportStateProc(), and TRUE otherwise.


explanation

There was a rather heinous bug in versions of Logic lower than 6.4.2 and versions of GarageBand lower than 1.1.0 that requires special attention if you make an AU that utilizes the transportStateProc() HostCallback. Basically, you can't call that callback if your AU is being hosted by one of the bad versions of those applications, because doing so will cause the application to crash.

The reason is because of a bug in the AudioUnitSetProperty() calling of those applications. They would first call AudioUnitGetPropertyInfo() for the kAudioUnitProperty_HostCallbacks property, and then call AudioUnitSetProperty() passing the data size that they got from AudioUnitGetPropertyInfo() rather than the size of the actual data buffer that they were setting on the AU. This problem was caught at the time when the transportStateProc() was added to the HostCallbackInfo structure, because in that period of transition, the hosts were not yet built aware of the larger size of that structure, but some AUs were. Note that, if a host is not going to support a given HostCallback, it is supposed to set that callback function pointer to NULL when setting the property data on the AU. In these cases, however, the callback function pointer was being set to random memory, because the host applications were telling AUs that the data buffer was larger than it actually was, and so the value of the transportStateProc() function pointer would just be set to whatever bytes came after the host's data buffer in memory, rather than being set to NULL. So before calling the transportStateProc() callback, you want to use this function to make sure that you can call it safely.


programming example

Here's an example of calling the transportStateProc safely from an AUEffectBase-derived AU's ProcessBufferLists() method:

/* the result of IsTransportStateProcSafe() will never change during the process' life span, 
   so there's no need to call this more than once */
static const bool gTransportStateProcIsSafe = IsTransportStateProcSafe();

OSStatus MegaEffect::ProcessBufferLists(AudioUnitRenderActionFlags & ioActionFlags, 
                     const AudioBufferList & inBuffer, AudioBufferList & outBuffer, 
                     UInt32 inFramesToProcess)
{
	if (gTransportStateProcIsSafe)
	{
		Boolean isPlaying = true;
		Boolean transportStateChanged = false;
		Float64 currentSampleInTimeLine = 0.0;
		Boolean isCycling = false;
		Float64 cycleStartBeat = 0.0, cycleEndBeat = 0.0;
		OSStatus status = CallHostTransportState(&isPlaying, &transportStateChanged, 
		                                         &currentSampleInTimeLine, 
		                                         &isCycling, &cycleStartBeat, &cycleEndBeat);
		if (status == noErr)
		{
			/* ...do what you gotta do... */
		}
	}
}






Posting parameter change notifications


Why this matters

Sometimes a change occurs to an Audio Unit's parameter that other interested parties might not be aware of. For example, an AU might do something in a certain context that changes a parameter value internally (like mapping a MIDI CC event to a parameter change), and maybe the GUI or some other interface might want to be notified so that it can update itself to reflect that change. These functions provide easy ways to do that. AU has a nice system for sending parameter change notifications to any arbitrary number of parameter listeners, and these functions are just a wrappers for that part of the AU API. I found myself writing the same little 6 line function over and over again in every AU that I worked on, so I figured I'd just make one reusable function for them all. So these functions are just for convenience, they don't provide any extra functionality.


Functions

AUParameterChange_TellListeners_ScopeElement
AUParameterChange_TellListeners



AUParameterChange_TellListeners_ScopeElement

void AUParameterChange_TellListeners_ScopeElement(AudioUnit inAUComponentInstance, AudioUnitParameterID inParameterID, AudioUnitScope inScope, AudioUnitElement inElement)

inAUComponentInstance
The AudioUnit instance whose parameter value has changed.

inParameterID
The ID of the changed parameter.

inScope
The scope of the changed parameter.

inElement
The element of the changed parameter.


explanation

This function is a convenience wrapper of AUParameterListenerNotify, which is part of the regular Audio Unit API. When you use AUParameterListenerNotify, you need to have an AudioUnitParameter structure, initialize all of its values, and then call AUParameterListenerNotify. This function just lets you do that in 1 line rather than 6.


programming example

See AUParameterChange_TellListeners for a relevant example.



AUParameterChange_TellListeners

void AUParameterChange_TellListeners(AudioUnit inAUComponentInstance, AudioUnitParameterID inParameterID)

inAUComponentInstance
The AudioUnit instance whose parameter value has changed.

inParameterID
The ID of the changed parameter.


explanation

This function is a convenience wrapper of a convenience wrapper. It simply calls AUParameterChange_TellListeners_ScopeElement passing kAudioUnitScope_Global for the scope value and 0 for the element value. Since I find that, most of the time, my AUs' parameters are in the global scope and element 0, I rarely ever need specify other scopes or elements, so I made this simplified function.


programming example

Here's an example of sending change notifications for every parameter right after a factory preset has been loaded:

OSStatus MegaEffect::NewFactoryPresetSet(const AUPreset & inNewFactoryPreset)
{
	/* ...do something to change load the factory preset settings... */

	for (UInt32 i=0; i < yourNumParameters; i++)
		AUParameterChange_TellListeners(GetComponentInstance(), yourParameterList[i]);

	return noErr;
}






Change log

May 8th 2008:

August 18th 2006:

September 9th 2005:

August 12th 2005:

March 6th 2005:

June 14th 2004:

September 23rd 2003:

September 18th 2003: