The question of knob rotation has come up so many times on forums I frequent that I am amazed that I haven’t touched on it already (honestly, it is probably because I thought I already did). But regardless, here it is. The big difference between VST and AU knob handling is that GENERALLY VST2/VSTGUI uses old-school film-strip ‘animation’ for knobs, while AU/Interface-builder uses affine transformation. That is probably a bit simplistic since you can arrange either for one or the other, but that is generally how it plays out if you are not using a 3rd party GUI library. So this post is again aimed at people who are familiar with the VST SDK and VSTGUI but are unfamiliar with OSX interface builder and affine transformations.
The frustration of InterfaceBuilder in regard to the circular slider is that there is no easy way to add custom art, rotation behavior, or most importantly… stops (the circular slider just rotates continuously). So this just solves those issues, while preserving the drag-and-srop WYSIWIG simplicity.
The flow of this post will be from simple to complex. I know how annoying it is to read a whole post full of technical babble and code snippits without a working example (or a working example with no explanation on how to USE it), so I will start with a fully-functional class, follow with how to use it, and end with some technical details and links to even MORE techno-babble.
So first, here is the class: http://solamors.com/MY_Knob_Class.zip
There are 2 versions: regular movement and reversed movement (which I added because flipping the image is easier than flipping the parameter math…).
This was an override of the NSSlider class. It was originally created by Airy André in his take on Urs Heckman’s AU framework. I modified it a bit to be compatible with OBJ-c/ARC (if desired). I like this method because you can use the circular NSSlider element as a WYSIWYG placeholder in the UI NIB, and just change the custom class… very convenient (drag and drop, yaaay).
As with anything in the wild world of AU+ObjC, since the UI is detached from the plugin, make sure to keep members and assets private with unique names or they may find the UI of one of your plugs controlling another plug. The easiest way to to that is to just rename the classes and assets by prefixing them with the name of the project (ie. instead of “My_Knob” class with “myKnobImage” art in your plugin named “Awesomeizer”, rename them “_awe_Knob” and “_aweKnobImage” or whatever).
1) Drag the folder to your project window and make sure to check ‘copy items if needed’ and ‘add to targets:” your cocoa UI bundle:
2) In your view interface, #import the header and add your class as an IBOutlet:
3) In your XIB/NIB, Grab a circular slider element and drag it to your view
4) In the knob element, set the custom class to the name of your class
5) In the Knob Cell element, set the size as usual
6) tie the UI actions, the min/max/default values, drop shadow, etc to the knob as you would any other element and build. The result should look like this:
And there you are! You are good to go. If you want to go a little deeper, read on:
I just whipped up the knob in GIMP with the conic gradient tool, so replace it as needed. The knob is a 2-part image… the background and the position indicator, but you could make it just a single layer, or more layers… say a middle layer with reflections to make the movement look more authentic, etc.
The User-defined params:
The min/max value, images, and min/max angle can all be set in the *.m file if desired. +/-135 degrees is close to the standard physical potentiometer throw, so it is a decent starting point.
I have set up the class for ARC (automatic reference counting), BUT if you don’t use ARC, just delete all the /* */ commented out memory-handling code marked “// for non-arc”.
Other Definable behaviors:
You can control the behavior of the knob on mouse interaction in several ways. I added comments for a few such as: inverted X or Y access tracking, flipping the whole cell, rotation direction, etc. Those are in the “continueTracking” and “drawWithFrame” sections… just look for the comments. Also, you can obviously add other features like unique knob naming, additional mouse behaviors, custom sizing, etc, but I kept the code stripped to just the most useful features.
I won’t re-write the documentation on affine transforms, so here is the link to Apple’s docs: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSAffineTransform_Class/index.html and here is an article at CocoaDev Central with a project that delves deeper into the subject: http://cocoadevcentral.com/articles/000045.php
(Thanks to Urs Heckman and Airy André for their work back in the early 2000’s. Credit to Airy André for the initial class.)