alternative new version of the AppleUtility library
[ardour.git] / libs / appleutility / CoreAudio / AudioUnits / AUPublic / AUCarbonViewBase / AUCarbonViewControl.cpp
1 /*
2      File: AUCarbonViewControl.cpp
3  Abstract: AUCarbonViewControl.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 "AUCarbonViewControl.h"
48 #include "AUCarbonViewBase.h"
49 #include "AUViewLocalizedStringKeys.h"
50
51 AUCarbonViewControl::AUCarbonViewControl(AUCarbonViewBase *ownerView, AUParameterListenerRef listener, ControlType type, const CAAUParameter &param, ControlRef control) :
52         mOwnerView(ownerView),
53         mListener(listener),
54         mType(type),
55         mParam(param),
56         mControl(control),
57         mInControlInitialization(0)
58 {
59 #if !__LP64__
60         SetControlReference(control, SRefCon(this));
61 #endif
62 }
63
64 AUCarbonViewControl::~AUCarbonViewControl()
65 {
66         AUListenerRemoveParameter(mListener, this, &mParam);
67 }
68
69 AUCarbonViewControl* AUCarbonViewControl::mLastControl = NULL;
70
71 void    AUCarbonViewControl::Bind()
72 {
73 #if !__LP64__
74         mInControlInitialization = 1;   // true
75         AUListenerAddParameter(mListener, this, &mParam);
76                 // will cause an almost-immediate callback
77         
78         EventTypeSpec events[] = {
79                 { kEventClassControl, kEventControlValueFieldChanged }  // N.B. OS X only
80         };
81         
82         WantEventTypes(GetControlEventTarget(mControl), GetEventTypeCount(events), events);
83
84         if (mType == kTypeContinuous || mType == kTypeText || mType == kTypeDiscrete) {
85                 EventTypeSpec events[] = {
86                         { kEventClassControl, kEventControlHit },
87                         { kEventClassControl, kEventControlClick },
88                     { kEventClassControl, kEventControlTrack }
89                 };
90                 WantEventTypes(GetControlEventTarget(mControl), GetEventTypeCount(events), events);
91         } 
92
93         if (mType == kTypeText) {
94                 EventTypeSpec events[] = {
95                         { kEventClassControl, kEventControlSetFocusPart }
96                 };
97                 WantEventTypes(GetControlEventTarget(mControl), GetEventTypeCount(events), events); 
98                 ControlKeyFilterUPP proc = mParam.ValuesHaveStrings() ? StdKeyFilterCallback : NumericKeyFilterCallback;
99                         // this will fail for a static text field
100                 SetControlData(mControl, 0, kControlEditTextKeyFilterTag, sizeof(proc), &proc);
101         }
102         
103         Update(true);
104         mInControlInitialization = 0;   // false
105 #endif
106 }
107
108 void    AUCarbonViewControl::ParameterToControl(Float32 paramValue)
109 {
110 #if !__LP64__
111         ++mInControlInitialization;
112         switch (mType) {
113         case kTypeContinuous:
114                 SetValueFract(AUParameterValueToLinear(paramValue, &mParam));
115                 break;
116         case kTypeDiscrete:
117                 {
118                         long value = long(paramValue);
119                         
120                         // special case [1] -- menu parameters
121                         if (mParam.HasNamedParams()) {
122                                 // if we're dealing with menus they behave differently!
123                                 // becaue setting min and max doesn't work correctly for the control value
124                                 // first menu item always reports a control value of 1
125                                 ControlKind ctrlKind;
126                                 if (GetControlKind(mControl, &ctrlKind) == noErr) {
127                                         if ((ctrlKind.kind == kControlKindPopupArrow) 
128                                                 || (ctrlKind.kind == kControlKindPopupButton))                          
129                                         {
130                                                 value = value - long(mParam.ParamInfo().minValue) + 1;
131                                         }
132                                 }
133                         }
134                         
135                         // special case [2] -- Write-only boolean parameters
136                         AudioUnitParameterInfo AUPI = mParam.ParamInfo();
137                         
138                         bool isWriteOnlyBoolParameter = (       (AUPI.unit == kAudioUnitParameterUnit_Boolean) &&
139                                                                                                 (AUPI.flags & kAudioUnitParameterFlag_IsWritable) &&
140                                                                                                 !(AUPI.flags & kAudioUnitParameterFlag_IsReadable)      );
141                         if (!isWriteOnlyBoolParameter) {
142                                 SetValue (value);
143                         }
144                 }
145                 break;
146         case kTypeText:
147                 {
148                         CFStringRef cfstr = mParam.GetStringFromValueCopy(&paramValue);
149
150                         if ( !(mParam.ParamInfo().flags & kAudioUnitParameterFlag_IsWritable)                   //READ ONLY PARAMS
151                                         && (mParam.ParamInfo().flags & kAudioUnitParameterFlag_IsReadable)) 
152                         {
153                                 if (mParam.GetParamTag()) {
154                                         CFMutableStringRef str = CFStringCreateMutableCopy(NULL, 256, cfstr);
155                                         CFRelease (cfstr);
156                                         CFStringAppend (str, CFSTR(" "));
157                                         CFStringAppend (str, mParam.GetParamTag());
158                                         cfstr = str;
159                                 }
160                         }
161                         SetTextValue(cfstr);
162                         CFRelease (cfstr);
163                 }
164                 break;
165         }
166         --mInControlInitialization;
167 #endif
168 }
169
170 void    AUCarbonViewControl::ControlToParameter()
171 {
172 #if !__LP64__
173         if (mInControlInitialization)
174                 return;
175
176         switch (mType) {
177         case kTypeContinuous:
178                 {
179                         double controlValue = GetValueFract();
180                         Float32 paramValue = AUParameterValueFromLinear(controlValue, &mParam);
181                         mParam.SetValue(mListener, this, paramValue);
182                 }
183                 break;
184         case kTypeDiscrete:
185                 {
186                         long value = GetValue();
187                         
188                         // special case [1] -- Menus
189                         if (mParam.HasNamedParams()) {
190                                 // if we're dealing with menus they behave differently!
191                                 // becaue setting min and max doesn't work correctly for the control value
192                                 // first menu item always reports a control value of 1
193                                 ControlKind ctrlKind;
194                                 if (GetControlKind(mControl, &ctrlKind) == noErr) {
195                                         if ((ctrlKind.kind == kControlKindPopupArrow) 
196                                                 || (ctrlKind.kind == kControlKindPopupButton))                          
197                                         {
198                                                 value = value + long(mParam.ParamInfo().minValue) - 1;
199                                         }
200                                 }
201                         }
202                         
203                         // special case [2] -- Write-only boolean parameters
204                         AudioUnitParameterInfo AUPI = mParam.ParamInfo();
205                         
206                         bool isWriteOnlyBoolParameter = (       (AUPI.unit == kAudioUnitParameterUnit_Boolean) &&
207                                                                                                 (AUPI.flags & kAudioUnitParameterFlag_IsWritable) &&
208                                                                                                 !(AUPI.flags & kAudioUnitParameterFlag_IsReadable)      );
209                         if (isWriteOnlyBoolParameter) {
210                                 value = 1;
211                         }
212                         
213                         mParam.SetValue (mListener, this, value);
214                 }
215                 break;
216         case kTypeText:
217                 {
218                         Float32 val = mParam.GetValueFromString (GetTextValue());
219                         mParam.SetValue(mListener, this, (mParam.IsIndexedParam() ? (int)val : val));
220                         if (mParam.ValuesHaveStrings())
221                                 ParameterToControl(val); //make sure we display the correct text (from the AU)
222                 }
223                 break;
224         }
225 #endif
226 }
227
228 void    AUCarbonViewControl::SetValueFract(double value)
229 {
230 #if !__LP64__
231         SInt32 minimum = GetControl32BitMinimum(mControl);
232         SInt32 maximum = GetControl32BitMaximum(mControl);
233         SInt32 cval = SInt32(value * (maximum - minimum) + minimum + 0.5);
234         SetControl32BitValue(mControl, cval);
235 //      printf("set: value=%lf, min=%ld, max=%ld, ctl value=%ld\n", value, minimum, maximum, cval);
236 #endif
237 }
238
239 double  AUCarbonViewControl::GetValueFract()
240 {
241 #if !__LP64__
242         SInt32 minimum = GetControl32BitMinimum(mControl);
243         SInt32 maximum = GetControl32BitMaximum(mControl);
244         SInt32 cval = GetControl32BitValue(mControl);
245         double result = double(cval - minimum) / double(maximum - minimum);
246 //      printf("get: min=%ld, max=%ld, value=%ld, result=%f\n", minimum, maximum, cval, result);
247         return result;
248 #else
249         return 0;
250 #endif
251 }
252
253 void    AUCarbonViewControl::SetTextValue(CFStringRef cfstr)
254 {
255 #if !__LP64__
256         verify_noerr(SetControlData(mControl, 0, kControlEditTextCFStringTag, sizeof(CFStringRef), &cfstr));
257 #endif
258 }
259
260 CFStringRef     AUCarbonViewControl::GetTextValue()
261 {
262 #if !__LP64__
263         CFStringRef cfstr;
264         verify_noerr(GetControlData(mControl, 0, kControlEditTextCFStringTag, sizeof(CFStringRef), &cfstr, NULL));
265         return cfstr;
266 #else
267         return CFSTR("");
268 #endif
269 }
270
271 void    AUCarbonViewControl::SetValue(long value)
272 {
273 #if !__LP64__
274         SetControl32BitValue(mControl, value);
275 #endif
276 }
277
278 long    AUCarbonViewControl::GetValue()
279 {
280 #if !__LP64__
281         return GetControl32BitValue(mControl);
282 #else
283         return 0;
284 #endif
285 }
286
287 /* Notes on event handling 
288         
289         Button (Click and release on button)
290                 kEventControlClick received
291                 kEventControlTrack received
292                 kEventControlValueFieldChanged received
293                 kEventControlHit received
294         
295         Button (Click and release outside of button bounds)
296                 kEventControlClick received
297                 kEventControlTrack received
298         
299         Slider (Click, drag, and release)
300                 kEventControlClick received
301                 kEventControlTrack received
302                 kEventControlValueFieldChanged received
303                 kEventControlValueFieldChanged received
304                 kEventControlHit received
305                 
306         Slider (Click, release without changing value)
307                 kEventControlClick received
308                 kEventControlTrack received
309 */
310 bool    AUCarbonViewControl::HandleEvent(EventHandlerCallRef inHandlerRef, EventRef event)
311 {
312         UInt32 eclass = GetEventClass(event);
313         UInt32 ekind = GetEventKind(event);
314         ControlRef control;
315         bool            handled = true;
316         
317         switch (eclass) {
318                 case kEventClassControl:
319                 {
320                         AudioUnitParameterInfo AUPI = mParam.ParamInfo();
321                         
322                         bool isWriteOnlyBoolParameter = (       (AUPI.unit == kAudioUnitParameterUnit_Boolean) &&
323                                                                                                 (AUPI.flags & kAudioUnitParameterFlag_IsWritable) &&
324                                                                                                 !(AUPI.flags & kAudioUnitParameterFlag_IsReadable)      );
325                         
326                         switch (ekind) {
327                                 case kEventControlSetFocusPart: // tab
328                                         handled = !handled;             // fall through to next case
329                                         mLastControl = this;
330                                 case kEventControlValueFieldChanged:
331                                         GetEventParameter(event, kEventParamDirectObject, typeControlRef, NULL, sizeof(ControlRef), NULL, &control);
332                                         verify(control == mControl);
333                                         ControlToParameter();
334                                         return handled;                 
335                                 case kEventControlClick:
336                                         if (isWriteOnlyBoolParameter) {
337                                                 GetEventParameter(event, kEventParamDirectObject, typeControlRef, NULL, sizeof(ControlRef), NULL, &control);
338                                                 verify(control == mControl);
339                                                 ControlToParameter();
340                                         } else if (mLastControl != this) {
341                                                 if (mLastControl != NULL) {
342                                                         mLastControl->Update(false);
343                                                 }
344                                                 mLastControl = this;    
345                                         }
346                                         mOwnerView->TellListener(mParam, kAudioUnitCarbonViewEvent_MouseDownInControl, NULL);
347                                         break;  // don't return true, continue normal processing
348                                 case kEventControlHit:
349                                         if (mLastControl != this) {
350                                                 if (mLastControl != NULL)
351                                                         mLastControl->Update(false);
352                                                 mLastControl = this;    
353                                         } 
354                                         mOwnerView->TellListener(mParam, kAudioUnitCarbonViewEvent_MouseUpInControl, NULL);
355                                         break;  // don't return true, continue normal processing
356                                 case kEventControlTrack:                
357                                         if (mLastControl != this) {
358                                                 if (mLastControl != NULL)
359                                                         mLastControl->Update(false);
360                                                 mLastControl = this;    
361                                         }
362                                         
363                                         CallNextEventHandler(inHandlerRef, event);
364                                         ControlToParameter();                                           // new code
365                                         mOwnerView->TellListener(mParam, kAudioUnitCarbonViewEvent_MouseUpInControl, NULL);
366                                         // old code:
367                                         //              break;  // don't return true, continue normal processing
368
369                                         return handled; // don't return true, continue normal processing
370                         }
371                 }
372         }
373         return !handled;
374 }
375
376 pascal void     AUCarbonViewControl::SliderTrackProc(ControlRef theControl, ControlPartCode partCode)
377 {
378         // this doesn't need to actually do anything
379 //      AUCarbonViewControl *This = (AUCarbonViewControl *)GetControlReference(theControl);
380 }
381
382 pascal ControlKeyFilterResult   AUCarbonViewControl::StdKeyFilterCallback(ControlRef theControl, 
383                                                                                                 SInt16 *keyCode, SInt16 *charCode, 
384                                                                                                 EventModifiers *modifiers)
385 {
386 #if !__LP64__
387         SInt16 c = *charCode;
388         if (c >= ' ' || c == '\b' || c == 0x7F || (c >= 0x1c && c <= 0x1f) || c == '\t')
389                 return kControlKeyFilterPassKey;
390         if (c == '\r' || c == 3) {      // return or Enter
391                 AUCarbonViewControl *This = (AUCarbonViewControl *)GetControlReference(theControl);
392                 ControlEditTextSelectionRec sel = { 0, 32767 };
393                 SetControlData(This->mControl, 0, kControlEditTextSelectionTag, sizeof(sel), &sel);
394                 This->ControlToParameter();
395         }
396 #endif
397         return kControlKeyFilterBlockKey;
398 }
399
400 pascal ControlKeyFilterResult   AUCarbonViewControl::NumericKeyFilterCallback(ControlRef theControl, 
401                                                                                                 SInt16 *keyCode, SInt16 *charCode, 
402                                                                                                 EventModifiers *modifiers)
403 {
404 #if !__LP64__
405         SInt16 c = *charCode;
406         if (isdigit(c) || c == '+' || c == '-' || c == '.' || c == '\b' || c == 0x7F || (c >= 0x1c && c <= 0x1f)
407         || c == '\t')
408                 return kControlKeyFilterPassKey;
409         if (c == '\r' || c == 3) {      // return or Enter
410                 AUCarbonViewControl *This = (AUCarbonViewControl *)GetControlReference(theControl);
411                 ControlEditTextSelectionRec sel = { 0, 32767 };
412                 SetControlData(This->mControl, 0, kControlEditTextSelectionTag, sizeof(sel), &sel);
413                 This->ControlToParameter();
414         }
415 #endif
416         return kControlKeyFilterBlockKey;
417 }
418
419 Boolean AUCarbonViewControl::SizeControlToFit(ControlRef inControl, SInt16 *outWidth, SInt16 *outHeight)
420 {
421 #if !__LP64__
422         if (inControl == 0) return false;
423         
424         Boolean bValue = false;
425         // this only works on text controls -- returns an error for other controls, but doesn't do anything,
426         // so the error is irrelevant
427         SetControlData(inControl, kControlEntireControl, 'stim' /* kControlStaticTextIsMultilineTag */, sizeof(Boolean), &bValue);
428         
429         SInt16 baseLineOffset;
430         Rect bestRect;
431         OSErr err = GetBestControlRect(inControl, &bestRect, &baseLineOffset);  
432         if (err != noErr) return false;
433         
434         int width = (bestRect.right - bestRect.left) + 1;
435         int height = (bestRect.bottom - bestRect.top) + 1;
436         
437         Rect boundsRect;
438         GetControlBounds (inControl, &boundsRect);
439         
440         Rect newRect;
441         newRect.top = boundsRect.top;
442         newRect.bottom = newRect.top + height;
443         newRect.left = boundsRect.left;
444         newRect.right = newRect.left + width;
445         
446         SetControlBounds (inControl, &newRect);
447         
448         if (outWidth)
449                 *outWidth = width;
450         
451         if (outHeight)
452                 *outHeight = height;
453 #endif  
454         return true;
455 }
456
457 #pragma mark ___AUPropertyControl
458 bool    AUPropertyControl::HandleEvent(EventHandlerCallRef inHandlerRef, EventRef event)
459 {       
460         UInt32 eclass = GetEventClass(event);
461         UInt32 ekind = GetEventKind(event);
462         switch (eclass) {
463         case kEventClassControl:
464                 switch (ekind) {
465                 case kEventControlValueFieldChanged:
466                         HandleControlChange();
467                         return true;    // handled
468                 }
469         }
470
471         return false;
472 }
473
474 void    AUPropertyControl::RegisterEvents ()
475 {
476 #if !__LP64__
477         EventTypeSpec events[] = {
478                 { kEventClassControl, kEventControlValueFieldChanged }  // N.B. OS X only
479         };
480         
481         WantEventTypes(GetControlEventTarget(mControl), GetEventTypeCount(events), events);
482 #endif
483 }
484
485 void    AUPropertyControl::EmbedControl (ControlRef theControl) 
486
487         mView->EmbedControl (theControl); 
488 }
489
490 WindowRef       AUPropertyControl::GetCarbonWindow()
491 {
492         return mView->GetCarbonWindow();
493 }
494
495 #pragma mark ___AUVPreset
496 #if !__LP64__
497 static CFStringRef kStringFactoryPreset = kAUViewLocalizedStringKey_FactoryPreset;
498 static bool sAUVPresetLocalized = false;
499 #endif
500
501 AUVPresets::AUVPresets (AUCarbonViewBase*               inParentView, 
502                                                 CFArrayRef&                     inPresets,
503                                                 Point                                   inLocation, 
504                                                 int                                     nameWidth, 
505                                                 int                                     controlWidth, 
506                                                 ControlFontStyleRec &   inFontStyle)
507         : AUPropertyControl (inParentView),
508           mPresets (inPresets),
509           mView (inParentView)
510 {
511 #if !__LP64__
512         Rect r;
513         
514         // ok we now have an array of factory presets
515         // get their strings and display them
516
517         r.top = inLocation.v;           r.bottom = r.top;
518         r.left = inLocation.h;          r.right = r.left;
519         
520     // localize as necessary
521     if (!sAUVPresetLocalized) {
522         CFBundleRef mainBundle = CFBundleGetBundleWithIdentifier(kLocalizedStringBundle_AUView);
523         if (mainBundle) {
524             kStringFactoryPreset =      CFCopyLocalizedStringFromTableInBundle(
525                                         kAUViewLocalizedStringKey_FactoryPreset, kLocalizedStringTable_AUView,
526                                         mainBundle, CFSTR("FactoryPreset title string"));
527             sAUVPresetLocalized = true;
528         }
529     }
530     
531     // create localized title string
532     CFMutableStringRef factoryPresetsTitle = CFStringCreateMutable(NULL, 0);
533     CFStringAppend(factoryPresetsTitle, kStringFactoryPreset);
534     CFStringAppend(factoryPresetsTitle, kAUViewUnlocalizedString_TitleSeparator);
535     
536         ControlRef theControl;
537     verify_noerr(CreateStaticTextControl(mView->GetCarbonWindow(), &r, factoryPresetsTitle, &inFontStyle, &theControl));
538         SInt16 width = 0;
539         AUCarbonViewControl::SizeControlToFit(theControl, &width, &mHeight);
540     CFRelease(factoryPresetsTitle);
541         EmbedControl(theControl);
542         
543         r.top -= 2;
544         r.left += width + 10;
545         r.right = r.left;
546         r.bottom = r.top;
547         
548         verify_noerr(CreatePopupButtonControl ( mView->GetCarbonWindow(), &r, NULL, 
549                                                                                         -12345, // DON'T GET MENU FROM RESOURCE mMenuID,!!!
550                                                                                         FALSE,  // variableWidth, 
551                                                                                         0,              // titleWidth, 
552                                                                                         0,              // titleJustification, 
553                                                                                         0,              // titleStyle, 
554                                                                                         &mControl));
555         
556         MenuRef menuRef;
557         verify_noerr(CreateNewMenu(1, 0, &menuRef));
558         
559         int numPresets = CFArrayGetCount(mPresets);
560         
561         for (int i = 0; i < numPresets; ++i)
562         {
563                 AUPreset* preset = (AUPreset*) CFArrayGetValueAtIndex (mPresets, i);
564                 verify_noerr(AppendMenuItemTextWithCFString (menuRef, preset->presetName, 0, 0, 0));
565         }
566         
567         verify_noerr(SetControlData(mControl, 0, kControlPopupButtonMenuRefTag, sizeof(menuRef), &menuRef));
568         verify_noerr (SetControlFontStyle (mControl, &inFontStyle));
569         
570         SetControl32BitMaximum (mControl, numPresets);
571         
572         // size popup
573         SInt16 height = 0;
574         
575         AUCarbonViewControl::SizeControlToFit(mControl, &width, &height);
576         
577         if (height > mHeight) mHeight = height;
578         if (mHeight < 0) mHeight = 0;
579         
580         // find which menu item is the Default preset
581         UInt32 propertySize = sizeof(AUPreset);
582         AUPreset defaultPreset;
583         OSStatus result = AudioUnitGetProperty (mView->GetEditAudioUnit(), 
584                                                                         kAudioUnitProperty_PresentPreset,
585                                                                         kAudioUnitScope_Global, 
586                                                                         0, 
587                                                                         &defaultPreset, 
588                                                                         &propertySize);
589         
590         mPropertyID = kAudioUnitProperty_PresentPreset;
591 #endif  
592 #ifndef __LP64__
593         if (result != noErr) {  // if the PresentPreset property is not implemented, fall back to the CurrentPreset property
594                 OSStatus result = AudioUnitGetProperty (mView->GetEditAudioUnit(), 
595                                                                         kAudioUnitProperty_CurrentPreset,
596                                                                         kAudioUnitScope_Global, 
597                                                                         0, 
598                                                                         &defaultPreset, 
599                                                                         &propertySize);
600                 mPropertyID = kAudioUnitProperty_CurrentPreset;
601                 if (result == noErr)
602                         CFRetain (defaultPreset.presetName);
603         } 
604 #endif
605 #if !__LP64__           
606         EmbedControl (mControl);
607         
608         HandlePropertyChange(defaultPreset);
609         
610         RegisterEvents();
611 #endif
612 }
613
614 void    AUVPresets::AddInterest (AUEventListenerRef             inListener,
615                                                                                         void *          inObject)
616 {
617         AudioUnitEvent e;
618         e.mEventType = kAudioUnitEvent_PropertyChange;
619         e.mArgument.mProperty.mAudioUnit = mView->GetEditAudioUnit();
620         e.mArgument.mProperty.mPropertyID = mPropertyID;
621         e.mArgument.mProperty.mScope = kAudioUnitScope_Global;
622         e.mArgument.mProperty.mElement = 0;
623         
624         AUEventListenerAddEventType(inListener, inObject, &e);
625 }
626
627 void    AUVPresets::RemoveInterest (AUEventListenerRef  inListener,
628                                                                                         void *          inObject)
629 {
630         AudioUnitEvent e;
631         e.mEventType = kAudioUnitEvent_PropertyChange;
632         e.mArgument.mProperty.mAudioUnit = mView->GetEditAudioUnit();
633         e.mArgument.mProperty.mPropertyID = mPropertyID;
634         e.mArgument.mProperty.mScope = kAudioUnitScope_Global;
635         e.mArgument.mProperty.mElement = 0;
636
637         AUEventListenerRemoveEventType(inListener, inObject, &e);
638 }
639
640 void    AUVPresets::HandleControlChange ()
641 {
642 #if !__LP64__
643         SInt32 i = GetControl32BitValue(mControl);
644         if (i > 0)
645         {
646                 AUPreset* preset = (AUPreset*) CFArrayGetValueAtIndex (mPresets, i-1);
647         
648                 verify_noerr(AudioUnitSetProperty (mView->GetEditAudioUnit(), 
649                                                                         mPropertyID,    // either currentPreset or PresentPreset depending on which is supported
650                                                                         kAudioUnitScope_Global, 
651                                                                         0, 
652                                                                         preset, 
653                                                                         sizeof(AUPreset)));
654                                                                         
655                 // when we change a preset we can't expect the AU to update its state
656                 // as it isn't meant to know that its being viewed!
657                 // so we broadcast a notification to all listeners that all parameters on this AU have changed
658                 AudioUnitParameter changedUnit;
659                 changedUnit.mAudioUnit = mView->GetEditAudioUnit();
660                 changedUnit.mParameterID = kAUParameterListener_AnyParameter;
661                 verify_noerr (AUParameterListenerNotify (NULL, NULL, &changedUnit) );
662         }
663 #endif
664 }
665
666 void    AUVPresets::HandlePropertyChange(AUPreset &preset) 
667 {
668 #if !__LP64__
669         // check to see if the preset is in our menu
670         int numPresets = CFArrayGetCount(mPresets);
671         if (preset.presetNumber < 0) {  
672                 SetControl32BitValue (mControl, 0); //controls are one-based
673         } else {
674                 for (SInt32 i = 0; i < numPresets; ++i) {
675                         AUPreset* currPreset = (AUPreset*) CFArrayGetValueAtIndex (mPresets, i);
676                         if (preset.presetNumber == currPreset->presetNumber) {
677                                 SetControl32BitValue (mControl, ++i); //controls are one-based
678                                 break;
679                         }
680                 }
681         }
682         
683         if (preset.presetName)
684                 CFRelease (preset.presetName);
685 #endif
686 }
687
688 bool    AUVPresets::HandlePropertyChange (const AudioUnitProperty &inProp)
689 {
690         if (inProp.mPropertyID == mPropertyID) 
691         {
692                 UInt32 theSize = sizeof(AUPreset);
693                 AUPreset currentPreset;
694                 
695                 OSStatus result = AudioUnitGetProperty(inProp.mAudioUnit, 
696                                                                                                 inProp.mPropertyID, 
697                                                                                                 inProp.mScope, 
698                                                                                                 inProp.mElement, &currentPreset, &theSize);
699                 
700                 if (result == noErr) {
701 #ifndef __LP64__
702                         if (inProp.mPropertyID == kAudioUnitProperty_CurrentPreset && currentPreset.presetName)
703                                 CFRetain (currentPreset.presetName);
704 #endif
705                         HandlePropertyChange(currentPreset);
706                         return true;
707                 }
708         }
709         return false;
710 }