RE: NSSlider correct event handling in Audio Unit with Cocoa GUI
RE: NSSlider correct event handling in Audio Unit with Cocoa GUI
- Subject: RE: NSSlider correct event handling in Audio Unit with Cocoa GUI
- From: Salda Van Mörlingam <email@hidden>
- Date: Sun, 19 Oct 2008 10:18:26 +0000
- Importance: Normal
Michael,
Thanks for getting back right away!.
Yes, it did help. You are right, I was obviously receiving/sending notifications from all instances of the view.
I fixed that and now I'm really close to having my AU behave entirely OK. There's still two more things I'm wondering about:
1. We both agreed I shouldn't need duplicated code to update my graph subview both in the action method and in the event handler, but I'm not able to get this right.
For reference, this is my action method for any of the 8 sliders in my matrix:
-(IBAction) MatrixChanged:(id)sender
{
int parameterNumber = [[sender selectedCell] tag];
Float32 newValue = [[sender selectedCell] floatValue];
parameter[parameterNumber].mAudioUnit = mAU;
NSAssert
(
AUParameterSet(eventListener, self, ¶meter[parameterNumber], newValue, 0) == noErr,
@"setting coefficient parameter in audio unit"
);
[graphView updateParameters: parameterNumber toValue: newValue];
[graphView setNeedsDisplay:TRUE];
if(sender == ParameterSliderMatrix)
[[ParameterBoxMatrix cellWithTag:parameterNumber] setFloatValue:newValue];
else
[[ParameterSliderMatrix cellWithTag:parameterNumber] setFloatValue:newValue];
}
and this is the relevant section in the event handler:
-(void) eventListenerHandler:(void *) inObject event:(const AudioUnitEvent *)inEvent value:(Float32)inValue
{
int parameterID = inEvent->mArgument.mParameter.mParameterID;
switch(inEvent->mEventType)
{
case kAudioUnitEvent_ParameterValueChange:
switch(parameterID)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
[[ParametertBoxMatrix cellWithTag:parameterID] setFloatValue: inValue];
[[ParameterSliderMatrix cellWithTag:parameterID] setFloatValue: inValue];
[graphView updateParameters:parameterID toValue: inValue];
[graphView setNeedsDisplay:YES];
break;
...
}
so, as you can see, I'm duplicating the whole procedure of updating the values in my slider matrix (and textfield matrix: the interface has sliders and textfields above each slider so the user can enter values using either), updating the subview's internal array of parameters and telling it to redraw.
My original reasoning, though, was that whether the change in any of these 8 parameters was effectuated by a host or the user actually moving the sliders, the update of the GUI should result only from the eventual call to the event handler. This,however, appears to only work in the case of the host, but not when the user moves a slider.
In the case of the user moving sliders, my reasoning was:
If the user moves a slider, this should call my action method and this method should merely call AUParameterSet. This, in turn, would also result in a call to my event handler and the handler would update the view.
That way I would only have the graph-updating code in the event handler and not in both the event handler and action method. But it turns out that if the user moves a slider, the event handler doesn't get called, and it makes sense actually, becaue AudioUnitUtilities.h says that passing the listener generating the change to AUEventListenerNotify will cause it not to receive the callback.
So my question is, if the above duplicated code is what you agree shouldn't be duplicated, how should I go about doing it?
And my other doubt:
2. Like you said, in registering the 8 sliders to send notifications I have two options: registering each slider (slider cells actually because they are part of a matrix) or registering the matrix itself and checking what slider was moved inside my gesture handling code.
I actually tried both approaches, but have mixed feelings about one over the other. Specifically, I first thought that checking what specific cell in the matrix was changed in the gesture code, while negligible in this little example, could potentially be seen as an inefficient approach in the case that I have multiple instances of my AU running at the same time. My reasoning for this is that since the check is a single if-statement this likely translates to a conditional jump at the assembly level and, in the case of various AU instances generating gestures at the same time, it's just wasting cycles. I might be blowing it out of proportion, but taking system-level courses at school sort of got me into taking these somewhat subtle implications into consideration.
So, I also tried the other approach and registered every slider cell as opposed to only the matrix. In this case I'm avoiding the jumps, but perhaps at the cost of instantiating 8 notification objects instead of 1. I also noticed another thing with this approach:
I was originally subclassing NSMatrix's mouseDown, in a similar way to NSSlider. That is:
#import "NSMatrixCustom.h"
extern NSString *kBeginGestureNotification;
extern NSString *kEndGestureNotification;
@implementation NSMatrixCustom
-(void) mouseDown:(NSEvent *) theEvent
{
[[NSNotificationCenter defaultCenter] postNotificationName: kBeginGestureNotification object: self];
[super mouseDown:theEvent];
[[NSNotificationCenter defaultCenter] postNotificationName: kEndGestureNotification object: self];
}
@end
Of course, if instead of registering the matrix I register the 8 slidercells, I need to change the way to send the begin and end gesture notifications. My first idea was:
#import "NSMatrixCustom.h"
extern NSString *kBeginGestureNotification;
extern NSString *kEndGestureNotification;
@implementation NSMatrixCustom
-(void) mouseDown:(NSEvent *) theEvent
{
[[NSNotificationCenter defaultCenter] postNotificationName: kBeginGestureNotification object: [self selectedCell]];
[super mouseDown:theEvent];
[[NSNotificationCenter defaultCenter] postNotificationName: kEndGestureNotification object: [self selectedCell]];
}
@end
But the only problem with this is that the first time the user clicks and drags a slider in the matrix the notifications don't show up. By the second time a slider is moved and thereafter, everything works fine.
So my question in this respect is, in terms of efficiency what approach do you think is better? (conditional jumps vs 8 instances of notifications per AU instance). And, in the case of the second approach (individual registered sliders), how should I go about the first-click issue? Perhaps subclassing the cells instead?
Thanks again for your time.
Federico. (I know, the email says Salda, long story...).
>> ----------------------------------------
>>> From: email@hidden
>>> To: email@hidden
>>> Date: Fri, 17 Oct 2008 14:48:31 -0700
>>> CC: email@hidden
>>> Subject: Re: NSSlider correct event handling in Audio Unit with Cocoa GUI
>>>
>>> Salda,
>>>
>>> It just so happens that I am currently working on improvements to the
>>> view templates, so your post is very timely.
>>>
>>> The workaround you have for handling gestures with the slider is
>>> perfectly fine. NSSlider will not call mouseUp, so you can't override
>>> that. The NSSlider does all it's mouseTracking in mouseDown, and does
>>> not return from that method until the mouse is released, so your
>>> override is fine. I cannot think of an easier way to do what you want
>>> to do.
>>>
>>> One thing that I see is incorrect, however, is that you are adding an
>>> observer for the notifications posted by your slider and passing nil
>>> as the last argument. That means that you will get a notification from
>>> other instances of your view. Not just your own slider! I recommend
>>> that you either add a notification for each of your sliders, and pass
>>> the slider as the object, or if you are like me and lazy, check the
>>> object [aNotification object] to make sure that the slider that is
>>> broadcasting the notification is one that is in your instance (and not
>>> some other instance).
>>>
>>> It should not be necessary to duplicate code in your action routine.
>>> All you should need to do is call AUParameterSet() with the correct
>>> parameter id and value, and your listener should get called. Thus you
>>> should be able to handle the user changing the parameter via the
>>> slider and via automation the same exact way with a single piece of
>>> code.
>>>
>>> Hope this helps!
>>>
>>> -michael
>>>
_________________________________________________________________
Connect to the next generation of MSN Messenger
http://imagine-msn.com/messenger/launch80/default.aspx?locale=en-us&source=wlmailtagline _______________________________________________
Do not post admin requests to the list. They will be ignored.
Coreaudio-api mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden