/*============================================================================= CAPersistence.cpp CAAudioEngine $Log: CAPersistence.cpp,v $ Revision 1.28 2005/05/03 00:39:46 asynth once more Revision 1.27 2005/05/03 00:25:13 asynth must be static Revision 1.26 2005/05/02 23:53:08 asynth define CFStringRefs locally Revision 1.25 2004/11/13 03:44:28 bills save a full "preset" of midi-param maps Revision 1.24 2004/11/12 03:35:06 bills some tweaks to save/restore mappings Revision 1.23 2004/11/12 02:43:56 bills const save method Revision 1.22 2004/11/10 19:04:51 bills fix include Revision 1.21 2004/11/04 23:25:18 cbruyns added MIDIMap save and restore methods Revision 1.20 2004/07/13 00:55:28 bills cleanup up (and Save/Restore for AudioUnitParameter) Revision 1.19 2003/10/18 22:37:06 bills add a human readable name string to the comp dictionary Revision 1.18 2003/10/17 00:27:55 bills tweaks to persistence formats Revision 1.17 2003/10/11 22:28:49 bills tweak save/restore methodology Revision 1.16 2003/10/02 22:30:53 bills remove unused keys Revision 1.15 2003/07/16 00:59:12 bills fix usage of CACFDict Revision 1.14 2003/07/07 21:50:38 dwyatt more refactoring Revision 1.13 2003/07/07 18:36:30 bills CAAU doesn't Save/Restore Revision 1.12 2003/05/25 22:13:39 bills changes to CACFDictionary Revision 1.11 2003/04/03 19:50:45 bills tweaks Revision 1.10 2003/04/02 18:20:02 bills changes to make persistence work Revision 1.9 2003/03/30 23:10:45 bills ChannelMap to ChannelLayout Revision 1.8 2003/03/23 02:53:12 bills some rewrite and add methods Revision 1.7 2003/03/21 06:53:36 bills prelim impl of CA-AU persistence Revision 1.6 2003/03/19 21:16:34 bills changes to how CAAudioUnit manages its internal state Revision 1.5 2003/03/17 03:11:49 bills fix warning Revision 1.4 2003/03/17 02:56:12 bills AU can now keep track of its active busses Revision 1.3 2003/03/12 23:38:21 bills CAAudioUnit::CanDo Revision 1.2 2003/03/12 05:08:57 bills some tweaks Revision 1.1 2003/03/12 05:05:05 bills refactor persistence Created by William Stewart on Mon Mar 10 2003. Copyright (c) 2003 Apple Computer. All rights reserved. =============================================================================*/ #include "CACFArray.h" #include "CACFDictionary.h" #include "CAAudioUnit.h" #include "CACFString.h" #include "CAAudioChannelLayout.h" #include "CAAUParameter.h" #include "CAAUMIDIMap.h" #pragma mark __CAStreamBasicDescription static const CFStringRef kSampleRate = CFSTR("sample rate"); static const CFStringRef kFormat = CFSTR("format"); static const CFStringRef kFormatFlags = CFSTR("format flags"); static const CFStringRef kPacketBytes = CFSTR("packet bytes"); static const CFStringRef kFramePackets = CFSTR("frame packets"); static const CFStringRef kFrameBytes = CFSTR("frame bytes"); static const CFStringRef kFrameChannels = CFSTR("frame channels"); static const CFStringRef kChannelBits = CFSTR("channel bits"); // This will return a value that should be used as the key for this struct // and a CFData object that contains the current state of this object OSStatus CAStreamBasicDescription::Save (CFPropertyListRef *outData) const { CACFDictionary dict(false); if (!dict.AddFloat64 (kSampleRate, mSampleRate)) goto error; if (!dict.AddUInt32 (kFormat, mFormatID)) goto error; if (!dict.AddUInt32 (kFormatFlags, mFormatFlags)) goto error; if (!dict.AddUInt32 (kPacketBytes, mBytesPerPacket)) goto error; if (!dict.AddUInt32 (kFramePackets, mFramesPerPacket)) goto error; if (!dict.AddUInt32 (kFrameBytes, mBytesPerFrame)) goto error; if (!dict.AddUInt32 (kFrameChannels, mChannelsPerFrame)) goto error; if (!dict.AddUInt32 (kChannelBits, mBitsPerChannel)) goto error; *outData = dict.GetDict(); return noErr; error: dict.ShouldRelease (true); return paramErr; } // Given a CFData object generated by the save command, this will re-establish // the CAStreamBasicDescription OSStatus CAStreamBasicDescription::Restore (CFPropertyListRef& inData) { if (CFGetTypeID (inData) != CFDictionaryGetTypeID()) return paramErr; CACFDictionary dict(static_cast(inData), false); if (!dict.GetFloat64 (kSampleRate, mSampleRate)) return paramErr; if (!dict.GetUInt32 (kFormat, mFormatID)) return paramErr; if (!dict.GetUInt32 (kFormatFlags, mFormatFlags)) return paramErr; if (!dict.GetUInt32 (kPacketBytes, mBytesPerPacket)) return paramErr; if (!dict.GetUInt32 (kFramePackets, mFramesPerPacket)) return paramErr; if (!dict.GetUInt32 (kFrameBytes, mBytesPerFrame)) return paramErr; if (!dict.GetUInt32 (kFrameChannels, mChannelsPerFrame)) return paramErr; if (!dict.GetUInt32 (kChannelBits, mBitsPerChannel)) return paramErr; return noErr; } #pragma mark __CAComponentDescription static const CFStringRef kType = CFSTR("type"); static const CFStringRef kSubType = CFSTR("subtype"); static const CFStringRef kManu = CFSTR("manufacturer"); OSStatus CAComponentDescription::Save (CFPropertyListRef *outData) const { CACFDictionary dict(false); if (!dict.AddUInt32 (kType, componentType)) goto error; if (!dict.AddUInt32 (kSubType, componentSubType)) goto error; if (!dict.AddUInt32 (kManu, componentManufacturer)) goto error; *outData = dict.GetDict(); return 0; error: dict.ShouldRelease (true); return paramErr; } OSStatus CAComponentDescription::Restore (CFPropertyListRef &inData) { if (CFGetTypeID (inData) != CFDictionaryGetTypeID()) return paramErr; CACFDictionary dict(static_cast(inData), false); if (!dict.GetUInt32 (kType, componentType)) return paramErr; if (!dict.GetUInt32 (kSubType, componentSubType)) return paramErr; if (!dict.GetUInt32 (kManu, componentManufacturer)) return paramErr; componentFlags = 0; componentFlagsMask = 0; return 0; } #pragma mark __CAComponent OSStatus CAComponent::Save (CFPropertyListRef *outData) const { OSStatus result = mDesc.Save (outData); if (result) return result; //add the name string of the component for a human readable name... // this name string is *not* restored when restoring the component CFStringRef name = GetCompName (); if (name && *outData) CFDictionarySetValue ((CFMutableDictionaryRef)(*outData), CFSTR("name"), name); return noErr; } OSStatus CAComponent::Restore (CFPropertyListRef &inData) { if (mDesc.Restore (inData)) return paramErr; Clear(); mComp = FindNextComponent (NULL, &mDesc); // this will restore the current flags... if (mComp) GetComponentInfo (Comp(), &mDesc, NULL, NULL, NULL); return noErr; } #pragma mark __CAAudioChannelLayout static const CFStringRef kACLTagKey = CFSTR("acl tag"); static const CFStringRef kACLBitmapKey = CFSTR("chan bitmap"); static const CFStringRef kACLLabelKey = CFSTR("label"); static const CFStringRef kACLFlagsKey = CFSTR("flags"); static const CFStringRef kACLCoords0Key = CFSTR("coords 0"); static const CFStringRef kACLCoords1Key = CFSTR("coords 1"); static const CFStringRef kACLCoords2Key = CFSTR("coords 2"); static const CFStringRef kACLDescsKey = CFSTR("descriptions"); OSStatus CAAudioChannelLayout::Save (CFPropertyListRef *outData) const { const AudioChannelLayout& layout = Layout(); CACFDictionary dict (false); if (!dict.AddUInt32 (kACLTagKey, layout.mChannelLayoutTag)) goto badadd; if (layout.mChannelBitmap && !dict.AddUInt32 (kACLBitmapKey, layout.mChannelBitmap)) goto badadd; if (layout.mNumberChannelDescriptions) { CFMutableArrayRef descs = CFArrayCreateMutable (NULL, layout.mNumberChannelDescriptions, &kCFTypeArrayCallBacks); const AudioChannelDescription *desc = layout.mChannelDescriptions; for (unsigned int i = 0; i < layout.mNumberChannelDescriptions; ++i, ++desc) { CACFDictionary descDict (true); if (!descDict.AddUInt32 (kACLLabelKey, desc->mChannelLabel)) { CFRelease (descs); goto badadd; } if (!descDict.AddUInt32 (kACLFlagsKey, desc->mChannelFlags)) { CFRelease (descs); goto badadd; } if (!descDict.AddFloat32 (kACLCoords0Key, desc->mCoordinates[0])) { CFRelease (descs); goto badadd; } if (!descDict.AddFloat32 (kACLCoords1Key, desc->mCoordinates[1])) { CFRelease (descs); goto badadd; } if (!descDict.AddFloat32 (kACLCoords2Key, desc->mCoordinates[2])) { CFRelease (descs); goto badadd; } CFArrayAppendValue (descs, descDict.AsPropertyList()); } dict.AddArray (kACLDescsKey, descs); CFRelease (descs); } *outData = dict.GetDict(); return noErr; badadd: dict.ShouldRelease(true); return paramErr; } OSStatus CAAudioChannelLayout::Restore (CFPropertyListRef &inData) { if (CFGetTypeID (inData) != CFDictionaryGetTypeID()) return paramErr; CACFDictionary dict(static_cast(inData), false); ACLRefCounter *temp = NULL; UInt32 size = 0; AudioChannelLayout* layout; CFArrayRef descs = NULL; UInt32 numDescs = 0; if (dict.GetArray (kACLDescsKey, descs)) { numDescs = CFArrayGetCount (descs); } size = numDescs * sizeof (AudioChannelDescription) + offsetof(AudioChannelLayout, mChannelDescriptions[0]); temp = new ACLRefCounter (size); layout = temp->GetLayout(); if (!dict.GetUInt32 (kACLTagKey, layout->mChannelLayoutTag)) goto badget; if (dict.HasKey (kACLBitmapKey)) { if (!dict.GetUInt32 (kACLBitmapKey, layout->mChannelBitmap)) goto badget; } else layout->mChannelBitmap = 0; layout->mNumberChannelDescriptions = numDescs; if (numDescs) { AudioChannelDescription *desc = layout->mChannelDescriptions; for (unsigned int i = 0; i < numDescs; ++i, ++desc) { CFDictionaryRef descDict = (CFDictionaryRef)CFArrayGetValueAtIndex (descs, i); CACFDictionary theDesc (descDict, false); if (!theDesc.GetUInt32 (kACLLabelKey, desc->mChannelLabel)) goto badget; if (!theDesc.GetUInt32 (kACLFlagsKey, desc->mChannelFlags)) goto badget; if (!theDesc.GetFloat32 (kACLCoords0Key, desc->mCoordinates[0])) goto badget; if (!theDesc.GetFloat32 (kACLCoords1Key, desc->mCoordinates[1])) goto badget; if (!theDesc.GetFloat32 (kACLCoords2Key, desc->mCoordinates[2])) goto badget; } } if (mLayoutHolder) mLayoutHolder->release(); mLayoutHolder = temp; return noErr; badget: delete temp; return paramErr; } #pragma mark __AudioUnitParameter static const CFStringRef kAUScopeStr = CFSTR("scope"); static const CFStringRef kAUElementIDStr = CFSTR("element ID"); static const CFStringRef kAUParameterIDStr = CFSTR("paramID"); void CAAUParameter::Save (CFPropertyListRef &outData) const { return CAAUParameter::Save (*this, outData); } // static functions to save/restore AudioUnitParameter void CAAUParameter::Save (const AudioUnitParameter &inParam, CFPropertyListRef &outData) { CACFDictionary dict(false); dict.AddUInt32 (kAUScopeStr, inParam.mScope); dict.AddUInt32 (kAUElementIDStr, inParam.mElement); dict.AddUInt32 (kAUParameterIDStr, inParam.mParameterID); outData = dict.AsPropertyList(); } OSStatus CAAUParameter::Restore (const CFPropertyListRef inData, AudioUnitParameter &outParam) { if (CFGetTypeID (inData) != CFDictionaryGetTypeID()) return paramErr; CACFDictionary dict(static_cast(inData), false); if (!dict.GetUInt32 (kAUScopeStr, outParam.mScope)) return paramErr; if (!dict.GetUInt32 (kAUElementIDStr, outParam.mElement)) return paramErr; if (!dict.GetUInt32 (kAUParameterIDStr, outParam.mParameterID)) return paramErr; return noErr; } #pragma mark __MIDIMap const CFStringRef kParamMIDIStr = CFSTR("param maps"); const CFStringRef kMIDIFlagsStr = CFSTR("flags"); const CFStringRef kMIDISubMinStr = CFSTR("sub min"); const CFStringRef kMIDISubMaxStr = CFSTR("sub max"); const CFStringRef kMIDIStatusStr = CFSTR("midi status byte"); const CFStringRef kMIDIDataByteStr = CFSTR("midi data1 byte"); const CFStringRef kAUStr = CFSTR("unit"); static const CFStringRef kLocalElementIDStr = CFSTR("element ID"); static const CFStringRef kLocalScopeStr = CFSTR("scope"); static const CFStringRef kLocalParameterIDStr = CFSTR("paramID"); void CAAUMIDIMap::Save(CFPropertyListRef &outData) const { CACFDictionary paramDict(false); paramDict.AddUInt32 (kLocalScopeStr, mScope); paramDict.AddUInt32 (kLocalElementIDStr, mElement); paramDict.AddUInt32 (kLocalParameterIDStr, mParameterID); paramDict.AddUInt32 (kMIDIFlagsStr, mFlags); paramDict.AddFloat32 (kMIDISubMinStr, mSubRangeMin); paramDict.AddFloat32 (kMIDISubMaxStr, mSubRangeMax); UInt32 data = mStatus; paramDict.AddUInt32 (kMIDIStatusStr, data); data = mData1; paramDict.AddUInt32 (kMIDIDataByteStr, data); outData = paramDict.GetCFDictionary(); } void CAAUMIDIMap::Restore(CFDictionaryRef inData) { CACFDictionary paramDict (inData, false); if (!paramDict.GetUInt32 (kLocalScopeStr, mScope)) return; if (!paramDict.GetUInt32 (kLocalElementIDStr, mElement)) return; if (!paramDict.GetUInt32 (kLocalParameterIDStr, mParameterID)) return; if (!paramDict.GetUInt32 (kMIDIFlagsStr, mFlags)) return; if (!paramDict.GetFloat32 (kMIDISubMinStr, mSubRangeMin)) return; if (!paramDict.GetFloat32 (kMIDISubMaxStr, mSubRangeMax)) return; UInt32 data; if (!paramDict.GetUInt32 (kMIDIStatusStr, data)) return; mStatus = data; if (!paramDict.GetUInt32 (kMIDIDataByteStr, data)) return; mData1 = data; } void CAAUMIDIMap::SaveAsMapPList (AudioUnit inUnit, const AUParameterMIDIMapping* inMappings, UInt32 inNumMappings, CFPropertyListRef &outData, CFStringRef inName) { CACFDictionary mappingDict (false); CACFArray maps (true); for (UInt32 i = 0; i< inNumMappings; ++i) { CFPropertyListRef data; CAAUMIDIMap paramMap(inMappings[i]); paramMap.Save (data); if (data) { maps.AppendCFType (data); CFRelease(data); } } if (maps.GetNumberItems()) { mappingDict.AddCFType (kParamMIDIStr, maps.GetCFArray()); // Add the AU info here - where this map came from CAAudioUnit au (inUnit); CFPropertyListRef data; au.Comp().Save (&data); mappingDict.AddCFType (kAUStr, data); CFRelease(data); if (!inName) inName = CFSTR("Untitled"); mappingDict.AddString (CFSTR("name"), inName); mappingDict.AddUInt32 (CFSTR("version"), 1); outData = mappingDict.AsPropertyList(); } else { mappingDict.ShouldRelease(true); outData = NULL; } } UInt32 CAAUMIDIMap::NumberOfMaps (const CFDictionaryRef inData) { CACFDictionary dict (inData, false); if (dict.HasKey (kParamMIDIStr)) { CFArrayRef cfArray; dict.GetArray (kParamMIDIStr, cfArray); CACFArray array (cfArray, false); return array.GetNumberItems(); } return 0; } void CAAUMIDIMap::RestoreFromMapPList (const CFDictionaryRef inData, AUParameterMIDIMapping* outMappings, UInt32 inNumMappings) { CACFDictionary dict (inData, false); if (dict.HasKey (kParamMIDIStr)) { CFArrayRef cfArray; dict.GetArray (kParamMIDIStr, cfArray); CACFArray array (cfArray, false); UInt32 count = array.GetNumberItems(); if (count > inNumMappings) count = inNumMappings; for (unsigned int i = 0; i < count; ++i) { CFDictionaryRef paramsDictRef; if (!array.GetDictionary(i, paramsDictRef)) return; CAAUMIDIMap parameterMap; parameterMap.Restore(paramsDictRef); outMappings[i] = parameterMap; } } }