alternative new version of the AppleUtility library
[ardour.git] / libs / appleutility / CoreAudio / PublicUtility / CAPersistence.cpp
1 /*
2      File: CAPersistence.cpp
3  Abstract: CAPersistence.h
4   Version: 1.1
5  
6  Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
7  Inc. ("Apple") in consideration of your agreement to the following
8  terms, and your use, installation, modification or redistribution of
9  this Apple software constitutes acceptance of these terms.  If you do
10  not agree with these terms, please do not use, install, modify or
11  redistribute this Apple software.
12  
13  In consideration of your agreement to abide by the following terms, and
14  subject to these terms, Apple grants you a personal, non-exclusive
15  license, under Apple's copyrights in this original Apple software (the
16  "Apple Software"), to use, reproduce, modify and redistribute the Apple
17  Software, with or without modifications, in source and/or binary forms;
18  provided that if you redistribute the Apple Software in its entirety and
19  without modifications, you must retain this notice and the following
20  text and disclaimers in all such redistributions of the Apple Software.
21  Neither the name, trademarks, service marks or logos of Apple Inc. may
22  be used to endorse or promote products derived from the Apple Software
23  without specific prior written permission from Apple.  Except as
24  expressly stated in this notice, no other rights or licenses, express or
25  implied, are granted by Apple herein, including but not limited to any
26  patent rights that may be infringed by your derivative works or by other
27  works in which the Apple Software may be incorporated.
28  
29  The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
30  MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
31  THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
32  FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
33  OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
34  
35  IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
36  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38  INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
39  MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
40  AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
41  STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
42  POSSIBILITY OF SUCH DAMAGE.
43  
44  Copyright (C) 2014 Apple Inc. All Rights Reserved.
45  
46 */
47 #include "CACFArray.h"
48 #include "CACFDictionary.h"
49
50 #include "CAAudioUnit.h"
51 #include "CACFString.h"
52 #include "CAAudioChannelLayout.h"
53 #include "CAAUParameter.h"
54 #include "CAAUMIDIMap.h"
55
56 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
57
58 #pragma mark __CAStreamBasicDescription
59
60 static const CFStringRef kSampleRate = CFSTR("sample rate");
61 static const CFStringRef kFormat = CFSTR("format");
62 static const CFStringRef kFormatFlags = CFSTR("format flags");
63 static const CFStringRef kPacketBytes = CFSTR("packet bytes");
64 static const CFStringRef kFramePackets = CFSTR("frame packets");
65 static const CFStringRef kFrameBytes = CFSTR("frame bytes");
66 static const CFStringRef kFrameChannels = CFSTR("frame channels");
67 static const CFStringRef kChannelBits = CFSTR("channel bits");
68
69                 // This will return a value that should be used as the key for this struct
70                 // and a CFData object that contains the current state of this object
71 OSStatus        CAStreamBasicDescription::Save (CFPropertyListRef *outData) const
72 {
73         CACFDictionary dict(false);
74
75         if (!dict.AddFloat64 (kSampleRate, mSampleRate)) goto error;
76         if (!dict.AddUInt32 (kFormat, mFormatID)) goto error;
77         if (!dict.AddUInt32 (kFormatFlags, mFormatFlags)) goto error;
78         if (!dict.AddUInt32 (kPacketBytes, mBytesPerPacket)) goto error;
79         if (!dict.AddUInt32 (kFramePackets, mFramesPerPacket)) goto error;
80         if (!dict.AddUInt32 (kFrameBytes, mBytesPerFrame)) goto error;
81         if (!dict.AddUInt32 (kFrameChannels, mChannelsPerFrame)) goto error;
82         if (!dict.AddUInt32 (kChannelBits, mBitsPerChannel)) goto error;
83         
84         *outData = dict.GetDict();
85
86         return noErr;
87
88 error:
89         dict.ShouldRelease (true);
90         return paramErr;
91 }
92
93         
94                 // Given a CFData object generated by the save command, this will re-establish
95                 // the CAStreamBasicDescription
96 OSStatus        CAStreamBasicDescription::Restore (CFPropertyListRef& inData)
97 {
98         if (CFGetTypeID (inData) != CFDictionaryGetTypeID()) return paramErr;
99         CACFDictionary dict(static_cast<CFDictionaryRef>(inData), false);
100         
101         if (!dict.GetFloat64 (kSampleRate, mSampleRate)) return paramErr;
102         if (!dict.GetUInt32 (kFormat, mFormatID)) return paramErr;
103         if (!dict.GetUInt32 (kFormatFlags, mFormatFlags)) return paramErr;
104         if (!dict.GetUInt32 (kPacketBytes, mBytesPerPacket)) return paramErr;
105         if (!dict.GetUInt32 (kFramePackets, mFramesPerPacket)) return paramErr;
106         if (!dict.GetUInt32 (kFrameBytes, mBytesPerFrame)) return paramErr;
107         if (!dict.GetUInt32 (kFrameChannels, mChannelsPerFrame)) return paramErr;
108         if (!dict.GetUInt32 (kChannelBits, mBitsPerChannel)) return paramErr;
109
110         return noErr;
111 }
112
113 #pragma mark __CAComponentDescription
114
115 static const CFStringRef kType = CFSTR("type");
116 static const CFStringRef kSubType = CFSTR("subtype");
117 static const CFStringRef kManu = CFSTR("manufacturer");
118
119 OSStatus                CAComponentDescription::Save (CFPropertyListRef *outData) const
120 {
121         CACFDictionary dict(false);
122         if (!dict.AddUInt32 (kType, componentType)) goto error;
123         if (!dict.AddUInt32 (kSubType, componentSubType)) goto error;
124         if (!dict.AddUInt32 (kManu, componentManufacturer)) goto error;
125         
126         *outData = dict.GetDict();
127         
128         return 0;
129 error:
130         dict.ShouldRelease (true);
131         return paramErr;
132 }
133
134 OSStatus                CAComponentDescription::Restore (CFPropertyListRef &inData)
135 {
136         if (CFGetTypeID (inData) != CFDictionaryGetTypeID()) return paramErr;
137         CACFDictionary dict(static_cast<CFDictionaryRef>(inData), false);
138                 
139         if (!dict.GetUInt32 (kType, componentType)) return paramErr;
140         if (!dict.GetUInt32 (kSubType, componentSubType)) return paramErr;
141         if (!dict.GetUInt32 (kManu, componentManufacturer)) return paramErr;
142
143         componentFlags = 0;
144         componentFlagsMask = 0;
145         
146         return 0;
147 }
148
149 #pragma mark __CAComponent
150
151 OSStatus                CAComponent::Save (CFPropertyListRef *outData) const
152 {
153         OSStatus result = mDesc.Save (outData);
154         if (result) return result;
155         
156         //add the name string of the component for a human readable name...
157         // this name string is *not* restored when restoring the component
158         CFStringRef     name = GetCompName ();
159         if (name && *outData)
160                 CFDictionarySetValue ((CFMutableDictionaryRef)(*outData), CFSTR("name"), name);
161         
162         return noErr;
163 }
164
165 OSStatus                CAComponent::Restore (CFPropertyListRef &inData)
166 {
167         if (mDesc.Restore (inData)) return paramErr;
168
169         Clear();
170
171         mComp = AudioComponentFindNext (NULL, &mDesc);
172                 // this will restore the current flags...
173         if (mComp)
174                 AudioComponentGetDescription (Comp(), &mDesc);
175
176         return noErr;
177 }
178
179
180 #pragma mark __CAAudioChannelLayout
181
182 static const CFStringRef kACLTagKey = CFSTR("acl tag");
183 static const CFStringRef kACLBitmapKey = CFSTR("chan bitmap");
184 static const CFStringRef kACLLabelKey = CFSTR("label");
185 static const CFStringRef kACLFlagsKey = CFSTR("flags");
186 static const CFStringRef kACLCoords0Key = CFSTR("coords 0");
187 static const CFStringRef kACLCoords1Key = CFSTR("coords 1");
188 static const CFStringRef kACLCoords2Key = CFSTR("coords 2");
189 static const CFStringRef kACLDescsKey = CFSTR("descriptions");
190         
191 OSStatus        CAAudioChannelLayout::Save (CFPropertyListRef *outData) const 
192 {
193         const AudioChannelLayout& layout = Layout();
194
195         CACFDictionary dict (false);
196         if (!dict.AddUInt32 (kACLTagKey, layout.mChannelLayoutTag))
197                 goto badadd;
198         if (layout.mChannelBitmap && !dict.AddUInt32 (kACLBitmapKey, layout.mChannelBitmap))
199                 goto badadd;
200         
201         if (layout.mNumberChannelDescriptions)
202         {       
203                 CFMutableArrayRef descs = CFArrayCreateMutable (NULL, layout.mNumberChannelDescriptions, &kCFTypeArrayCallBacks);
204                 
205                 const AudioChannelDescription *desc = layout.mChannelDescriptions;
206                 for (unsigned int i = 0; i < layout.mNumberChannelDescriptions; ++i, ++desc) 
207                 {
208                         CACFDictionary descDict (true);
209                         if (!descDict.AddUInt32 (kACLLabelKey, desc->mChannelLabel))
210                                 { CFRelease (descs); goto badadd; }
211                         if (!descDict.AddUInt32 (kACLFlagsKey, desc->mChannelFlags))
212                                 { CFRelease (descs); goto badadd; }
213                         if (!descDict.AddFloat32 (kACLCoords0Key, desc->mCoordinates[0]))
214                                 { CFRelease (descs); goto badadd; }
215                         if (!descDict.AddFloat32 (kACLCoords1Key, desc->mCoordinates[1]))
216                                 { CFRelease (descs); goto badadd; }
217                         if (!descDict.AddFloat32 (kACLCoords2Key, desc->mCoordinates[2]))
218                                 { CFRelease (descs); goto badadd; }
219                         
220                         CFArrayAppendValue (descs, descDict.AsPropertyList());
221                 }
222                 dict.AddArray (kACLDescsKey, descs);
223                 
224                 CFRelease (descs);
225         }
226         
227         *outData = dict.GetDict();      
228         
229         return noErr;
230         
231 badadd:
232         dict.ShouldRelease(true);
233         return paramErr;
234 }
235
236 OSStatus        CAAudioChannelLayout::Restore (CFPropertyListRef &inData) 
237 {
238         if (CFGetTypeID (inData) != CFDictionaryGetTypeID()) return paramErr;
239         CACFDictionary dict(static_cast<CFDictionaryRef>(inData), false);
240
241         RefCountedLayout *temp = NULL;
242         AudioChannelLayout* layout;
243         
244         CFArrayRef descs = NULL;
245         UInt32 numDescs = 0;
246
247         if (dict.GetArray (kACLDescsKey, descs)) {
248                 numDescs = static_cast<OSStatus>(CFArrayGetCount (descs));
249         }
250         
251         temp = RefCountedLayout::CreateWithNumberChannelDescriptions(numDescs);
252         layout = temp->GetLayout();
253                 
254         if (!dict.GetUInt32 (kACLTagKey, layout->mChannelLayoutTag))
255                 goto badget;
256         if (dict.HasKey (kACLBitmapKey)) {
257                 if (!dict.GetUInt32 (kACLBitmapKey, layout->mChannelBitmap))
258                         goto badget;
259         } else
260                 layout->mChannelBitmap = 0;
261                 
262         layout->mNumberChannelDescriptions = numDescs;
263         
264         if (numDescs)
265         {
266                 AudioChannelDescription *desc = layout->mChannelDescriptions;
267                 for (unsigned int i = 0; i < numDescs; ++i, ++desc)
268                 {
269                         CFDictionaryRef descDict = (CFDictionaryRef)CFArrayGetValueAtIndex (descs, i);                  
270                         CACFDictionary theDesc (descDict, false);
271                         
272                         if (!theDesc.GetUInt32 (kACLLabelKey, desc->mChannelLabel))
273                                 goto badget;
274                         if (!theDesc.GetUInt32 (kACLFlagsKey, desc->mChannelFlags))
275                                 goto badget;
276                         if (!theDesc.GetFloat32 (kACLCoords0Key, desc->mCoordinates[0]))
277                                 goto badget;
278                         if (!theDesc.GetFloat32 (kACLCoords1Key, desc->mCoordinates[1]))
279                                 goto badget;
280                         if (!theDesc.GetFloat32 (kACLCoords2Key, desc->mCoordinates[2]))
281                                 goto badget;
282                 }
283         }
284         if (mLayout)
285                 mLayout->release();
286
287         mLayout = temp;
288         
289         return noErr;
290
291 badget:
292         delete temp;
293         return paramErr;
294 }
295
296 #pragma mark __AudioUnitParameter
297
298 static const CFStringRef kAUScopeStr = CFSTR("scope");
299 static const CFStringRef kAUElementIDStr = CFSTR("element ID");
300 static const CFStringRef kAUParameterIDStr = CFSTR("paramID");
301
302 void            CAAUParameter::Save (CFPropertyListRef &outData) const 
303
304         return CAAUParameter::Save (*this, outData); 
305 }
306
307 // static functions to save/restore AudioUnitParameter
308 void            CAAUParameter::Save (const AudioUnitParameter &inParam, CFPropertyListRef &outData)
309 {
310         CACFDictionary dict(false);
311         dict.AddUInt32 (kAUScopeStr, inParam.mScope);
312         dict.AddUInt32 (kAUElementIDStr, inParam.mElement);
313         dict.AddUInt32 (kAUParameterIDStr, inParam.mParameterID);
314
315         outData = dict.AsPropertyList();
316 }
317
318 OSStatus        CAAUParameter::Restore  (const CFPropertyListRef inData, AudioUnitParameter &outParam)
319 {
320         if (CFGetTypeID (inData) != CFDictionaryGetTypeID()) return paramErr;
321         CACFDictionary dict(static_cast<CFDictionaryRef>(inData), false);
322
323         if (!dict.GetUInt32 (kAUScopeStr, outParam.mScope)) return paramErr;
324         if (!dict.GetUInt32 (kAUElementIDStr, outParam.mElement)) return paramErr;
325         if (!dict.GetUInt32 (kAUParameterIDStr, outParam.mParameterID)) return paramErr;
326         return noErr;
327 }
328
329
330 #pragma mark __MIDIMap
331
332 const CFStringRef kParamMIDIStr = CFSTR("param maps");
333
334 const CFStringRef kMIDIFlagsStr = CFSTR("flags");
335 const CFStringRef kMIDISubMinStr = CFSTR("sub min");
336 const CFStringRef kMIDISubMaxStr = CFSTR("sub max");
337 const CFStringRef kMIDIStatusStr = CFSTR("midi status byte");
338 const CFStringRef kMIDIDataByteStr = CFSTR("midi data1 byte");
339 const CFStringRef kAUStr = CFSTR("unit");
340
341 static const CFStringRef kLocalElementIDStr = CFSTR("element ID");
342 static const CFStringRef kLocalScopeStr = CFSTR("scope");
343 static const CFStringRef kLocalParameterIDStr = CFSTR("paramID");
344
345 void CAAUMIDIMap::Save(CFPropertyListRef &outData) const
346 {
347         CACFDictionary paramDict(false);
348
349         paramDict.AddUInt32 (kLocalScopeStr, mScope);
350         paramDict.AddUInt32 (kLocalElementIDStr, mElement);
351         paramDict.AddUInt32 (kLocalParameterIDStr, mParameterID);
352         paramDict.AddUInt32 (kMIDIFlagsStr, mFlags);
353         paramDict.AddFloat32 (kMIDISubMinStr, mSubRangeMin);
354         paramDict.AddFloat32 (kMIDISubMaxStr, mSubRangeMax);
355
356         UInt32 data = mStatus;
357         paramDict.AddUInt32 (kMIDIStatusStr, data);
358
359         data = mData1;
360         paramDict.AddUInt32 (kMIDIDataByteStr, data);
361
362         outData = paramDict.GetCFDictionary();
363 }
364
365 void CAAUMIDIMap::Restore(CFDictionaryRef inData)
366 {       
367         CACFDictionary paramDict (inData, false);
368
369         if (!paramDict.GetUInt32 (kLocalScopeStr, mScope)) return; 
370         if (!paramDict.GetUInt32 (kLocalElementIDStr, mElement)) return; 
371         if (!paramDict.GetUInt32 (kLocalParameterIDStr, mParameterID)) return; 
372         if (!paramDict.GetUInt32 (kMIDIFlagsStr, mFlags)) return;
373         if (!paramDict.GetFloat32 (kMIDISubMinStr, mSubRangeMin)) return; 
374         if (!paramDict.GetFloat32 (kMIDISubMaxStr, mSubRangeMax)) return; 
375         UInt32 data;            
376         if (!paramDict.GetUInt32 (kMIDIStatusStr, data)) return;
377         mStatus = data;
378         if (!paramDict.GetUInt32 (kMIDIDataByteStr, data)) return; 
379         mData1 = data;
380 }
381
382 void            CAAUMIDIMap::SaveAsMapPList (AudioUnit inUnit, const AUParameterMIDIMapping* inMappings, UInt32 inNumMappings, CFPropertyListRef &outData, CFStringRef inName)
383 {
384
385         CACFDictionary mappingDict (false);     
386         CACFArray maps (true);
387         
388         for (UInt32 i = 0; i< inNumMappings; ++i) 
389         {
390                 CFPropertyListRef data;
391                 CAAUMIDIMap paramMap(inMappings[i]);
392                 paramMap.Save (data);
393                 if (data) 
394                 {
395                         maps.AppendCFType (data); 
396                         CFRelease(data); 
397                 }                               
398         }
399
400         if (maps.GetNumberItems()) {
401                 mappingDict.AddCFType (kParamMIDIStr, maps.GetCFArray());
402                 
403                 // Add the AU info here - where this map came from
404                 CAAudioUnit au (inUnit);
405                 CFPropertyListRef data;
406                 au.Comp().Save (&data);
407                 
408                 mappingDict.AddCFType (kAUStr, data);
409                 CFRelease(data);
410                 
411                 if (!inName) inName = CFSTR("Untitled");
412                 mappingDict.AddString (CFSTR("name"), inName);
413                 
414                 mappingDict.AddUInt32 (CFSTR("version"), 1);
415                 
416                 outData = mappingDict.AsPropertyList();
417         } else {
418                 mappingDict.ShouldRelease(true);
419                 outData = NULL;
420         }
421 }
422
423 UInt32          CAAUMIDIMap::NumberOfMaps (const CFDictionaryRef inData)
424 {
425         CACFDictionary dict (inData, false);
426         
427         if (dict.HasKey (kParamMIDIStr)) 
428         {
429                 CFArrayRef cfArray;
430                 dict.GetArray (kParamMIDIStr, cfArray); 
431                 
432                 CACFArray array (cfArray, false);
433                 
434                 return array.GetNumberItems();
435         }
436         return 0;
437 }
438         
439 void            CAAUMIDIMap::RestoreFromMapPList (const CFDictionaryRef inData, AUParameterMIDIMapping* outMappings, UInt32 inNumMappings)
440 {
441
442         CACFDictionary dict (inData, false);
443         
444         if (dict.HasKey (kParamMIDIStr)) 
445         {
446                 CFArrayRef cfArray;
447                 dict.GetArray (kParamMIDIStr, cfArray); 
448                 
449                 CACFArray array (cfArray, false);
450                 
451                 UInt32 count = array.GetNumberItems();
452                 if (count > inNumMappings)
453                         count = inNumMappings;
454                 
455                 for (unsigned int i = 0; i < count; ++i)
456                 {
457                         CFDictionaryRef paramsDictRef;
458                         if (!array.GetDictionary(i, paramsDictRef)) 
459                                 return;
460                         
461                         CAAUMIDIMap parameterMap;
462                         parameterMap.Restore(paramsDictRef);
463                         outMappings[i] = parameterMap;
464                 }
465         }
466 }
467
468