Today I made a few performance tests with one of my plug-ins to check which compiler on Mac OS X gave me the fastest output. I used the following freely available compilers:
- LLVM-GCC 4.2 (Included in Xcode 3.2.2)
- GCC 4.2 (Included in Xcode 3.2.2)
- LLVM-Clang 1.5 (trunk 102427 - 27.April 2010)
I made 5 executables of my plug-in with the following compiler settings.
The optimization setting was always set to -O3 (fastest)
- LLVM-GCC 4.2 - LTO enabled
- LLVM-GCC 4.2 - LTO disabled
- GCC 4.2 - Auto vectorization enabled
- GCC 4.2 - Auto vectorization disabled
- LLVM-Clang 1.5 - LTO disabled
Then I added measuring code to VSTKit and timed the audio process call of all versions 20 times for one second, removed the slowest run and here are the results (lower bars are better):
As you can see the LLVM-GCC4.2 combo is performing best in this scenario. I wondered a little bit about the result for GCC4.2 with auto vectorization enabled, as I already vectorized the code by hand and the few locations the compiler did vectorize for me (can be seen by the compiler switch -ftree-vectorizer-verbose=2) aren’t hot spots in Shark.
A note on Clang: I build clang today from source with the newest code from their repository. I check clang once in a while to see if it can compile my code. The trunk version is now capable of compiling my code, this wasn’t the case a few weeks ago. I needed to turn of Link Time Optimization (LTO) as the linker did not understand the compiler output files generated with this option.
But anyway the numbers for clang are promising for such a young compiler which can compile c++ code for not longer than a half year.
Cubase 5 is now completely Cocoa based (and with support for Carbon plug-ins). So, what does it mean to port a cross-platform C++ application to Cocoa.
At the time Apple removed the 64 bit HIToolbox API from Mac OS X, we needed to redesign our native platform implementation of our base framework. Before we had more or less a simple macro based differentiation between our supported platforms like this:
void myFunction ()
{
#if MAC
// call some Mac API
#elif WINDOWS
// call some Windows API
#elif BEOS
// call some BeOS API
#endif
}
This doesn’t really work good as we needed to support a different language than C, or C++ namely Objective-C. So we sat down and thought about alternatives. As we already use some kind of COM like interfaces to connect to plug-ins we thought we could adapt this for our platform layer and we did.
We re-factored all our UI platform code so that we use interfaces for windows, views, menus and so on.
It works like this, if we took the pseudo code from above:
class SimpleInterface : public Unknown
{
public:
static SimpleInterface* createSimpleInterface ();
virtual void doMyFunction () = 0;
};
void myFunction ()
{
interface->doMyFunction ();
}
This way we can now build up different implementations for Windows, Mac Carbon, Mac Cocoa and so on.
The Mac Cocoa code would look like this:
class CocoaSimpleInterface : public SimpleInterface
{
public:
void doMyFunction ();
};
void CocoaSimpleInterface::doMyFunction ()
{
// some objective-c code here
}
SimpleInterface* SimpleInterface::createSimpleInterface ()
{
return new CocoaSimpleInterface;
}
We even did implement nearly all interfaces for Carbon too. We needed to as nearly all plug-ins today uses Carbon for their user interfaces. So instead of working with window groups to layer Carbon and Cocoa windows together, we just can create windows based on the plug-ins use of Carbon or Cocoa. This does give us better user experience than other Cocoa hosts which have a hard time to support Carbon based plug-ins.
So this design decision gave us many benefits we could not solved before. Even supporting new platforms will be much easier now.
Now to some things that worked not that easy. And that’s mainly AppKit.
Apple told developers some years now to switch to Cocoa from Carbon, but boy is Cocoa buggy and less customizable than Carbon. To build up simple applications or Mac only applications with Cocoa is straight forward and maybe one of the best native solutions I saw yet, but complex cross-platform applications ?
No. One really amusing example is the menu bar. As you can imagine, we build up the menu bar in code, abstract so that we only need to write code once for all platforms. But do you think you can build a menu bar in Cocoa from code ? No, you cannot, if you try to you get so much weird behavior like double Help menus, non working menu items, etc. So we just have to create a more or less empty menu bar in Interface Builder. And we need to do this for every language we support, not like Carbon where Carbon nicely translates it’s own items.
Another big problem for us, or mainly for our plug-in developers will be that Objective-C does not have the two-level namespace feature known from C++. This basically means that class name clashes can occur. It will be interesting to see what solutions the plug-in developers will come up with, especially those coming from Windows without much knowledge of the Mac API.
So now that Cubase 5 is Cocoa based, what’s next ? Yeah, let’s start to build a 64 bit version. We are now at the same point we were 2 years ago before Apple dropped 64 bit HIToolbox. So nothing really won from a users point of view. Internally it was a good thing to re-factor our UI code and gave us the opportunity to fix some bugs and streamline our native implementations.
I’m very proud to announce the first release of VSTKit, the cocoa framework for hosting VST3 plug-ins.
This is the first third party implementation for hosting VST3 plug-ins. Completely written in Cocoa and ready to use in every host application on Mac OS X. Also included is a test application which can be used to test VST3 plug-ins in another implementation than Cubase/Nuendo.
Go to the VSTKit page and download it.
To add a sidechain audio input to the again VST3 plug-in is actually very simple.
You need to add the input in the initialize(…) method of the AGain class:
addAudioInput (USTRING ("Sidechain Mono In"), SpeakerArr::kMono, kAux);
-
addAudioInput (USTRING ("Sidechain Mono In"), SpeakerArr::kMono, kAux);
After that you can check in the process function if the sidechain is active :
BusList* busList = getBusList (kAudio, kInput);
Bus* bus = busList ? (Bus*)busList->at (1) : 0;
if (bus && bus->isActive ())
{
// sidechain is active !!!
float* sidechainIn = data.inputs[1].channelBuffers32[0];
// do some processing with the input samples ...
}
-
BusList* busList = getBusList (kAudio, kInput);
-
Bus* bus = busList ? (Bus*)busList->at (1) : 0;
-
if (bus && bus->isActive ())
-
{
-
// sidechain is active !!!
-
float* sidechainIn = data.inputs[1].channelBuffers32[0];
-
// do some processing with the input samples …
-
}
To get this all working with AGain there are some more change to be done in AGain::setBusArrangements(…):
tresult PLUGIN_API AGain::setBusArrangements (SpeakerArrangement* inputs, int32 numIns, SpeakerArrangement* outputs, int32 numOuts)
{
if (numIns == 2 && numOuts == 1) // Sidechain chain, was: numIns == 1
{
if (inputs[0] == SpeakerArr::kMono && outputs[0] == SpeakerArr::kMono)
{
AudioBus* bus = (AudioBus*)(audioInputs.at (0));
if (bus)
{
if (bus->getArrangement () != SpeakerArr::kMono)
{
removeAudioBusses ();
addAudioInput (USTRING ("Mono In"), SpeakerArr::kMono);
addAudioOutput (USTRING ("Mono Out"), SpeakerArr::kMono);
addAudioInput (USTRING ("Sidechain Mono In"), SpeakerArr::kMono, kAux); // add sidechain, always mono
}
return kResultOk;
}
}
else
{
AudioBus* bus = (AudioBus*)(audioInputs.at (0));
if (bus)
{
if (bus->getArrangement () != SpeakerArr::kStereo)
{
removeAudioBusses ();
addAudioInput (USTRING ("Stereo In"), SpeakerArr::kStereo);
addAudioOutput (USTRING ("Stereo Out"), SpeakerArr::kStereo);
addAudioInput (USTRING ("Sidechain Mono In"), SpeakerArr::kMono, kAux); // add sidechain, always mono
}
return kResultOk;
}
}
}
return kResultFalse;
}
-
tresult PLUGIN_API AGain::setBusArrangements (SpeakerArrangement* inputs, int32 numIns, SpeakerArrangement* outputs, int32 numOuts)
-
{
-
if (numIns == 2 && numOuts == 1) // Sidechain chain, was: numIns == 1
-
{
-
if (inputs[0] == SpeakerArr::kMono && outputs[0] == SpeakerArr::kMono)
-
{
-
AudioBus* bus = (AudioBus*)(audioInputs.at (0));
-
if (bus)
-
{
-
if (bus->getArrangement () != SpeakerArr::kMono)
-
{
-
removeAudioBusses ();
-
addAudioInput (USTRING ("Mono In"), SpeakerArr::kMono);
-
addAudioOutput (USTRING ("Mono Out"), SpeakerArr::kMono);
-
addAudioInput (USTRING ("Sidechain Mono In"), SpeakerArr::kMono, kAux); // add sidechain, always mono
-
}
-
return kResultOk;
-
}
-
}
-
else
-
{
-
AudioBus* bus = (AudioBus*)(audioInputs.at (0));
-
if (bus)
-
{
-
if (bus->getArrangement () != SpeakerArr::kStereo)
-
{
-
removeAudioBusses ();
-
addAudioInput (USTRING ("Stereo In"), SpeakerArr::kStereo);
-
addAudioOutput (USTRING ("Stereo Out"), SpeakerArr::kStereo);
-
addAudioInput (USTRING ("Sidechain Mono In"), SpeakerArr::kMono, kAux); // add sidechain, always mono
-
}
-
return kResultOk;
-
}
-
}
-
}
-
return kResultFalse;
-
}
After I’ve fixed the nameserver entry for arne.knup.de so that my current page is again accessible I have added two more songs to my music page.
One was an entry in Steinbergs internal remix contest for the Cubase 4 demo song. All Steinberg employees could vote for them and my entry was 3rd place. But only the winner got a price. So enjoy it.
Today it’s time to talk about debugging with Xcode 2.4. And be warned, debugging can be a pain with Xcode. But first things first.
You choose the VST host in Xcode with “New Custom Executable”. You can add as many as you like, not like Visual Studio where you can only set one.
With Xcode 2.4 a new debug information format called DWARF was added to the existing stabs format. With this change it’s actually possible to debug C++ code. But the default format is still stabs, so go into the target build settings and change stabs to DWARF.
So when you now hit “Build and Restart” your preferred VST host should start.
Now to the caveats. GDB or Xcode has a bug that when your vst was once loaded and then unloaded and loaded again all your breakpoints wouldn’t break. This is a problem in hosts like Cubase which scans all modified or new plug-ins on startup. So if you need to use Cubase as host, start it first without debugger let the scanning happen and then quit Cubase. Now you can hit Debug to actually debug your plug-in.
If you have objects like the VstTimeInfo and you want to see a summary of its values in the debugger Xcode has some nice method: double click into the summary field for the variable (in this case the VstTimeInfo variable) and enter Tempo: {$VAR.tempo} bpmNow you see “Tempo: 120 bpm” whenever a VstTimeInfo struct is in the current scope (and the tempo is 120). Because of some bugs in Xcode or gdb this does not work everytime.
You can even call methods of that object (if it has methods, VstTimeInfo does not have any method). Just take your effect class (AudioEffect) and enter Sample Rate: {$VAR->getSampleRate()}into the summary field and you will see the current sample rate whenever your effect class is in scope.
So, after Apple switched the processors for the macintosh it looks like more windows only developers are thinking to port their plug-ins to the mac. I will try to give some short tips for new VST mac developers.
How to start a new fresh project in Xcode:
- Use the “Carbon Bundle” template when creating a new project.
- Open the target settings and change the build setting “Wrapper Extension” from ‘bundle’ to ‘vst’. (Don’t forget to change the configuration to ‘All Configurations’ before)
- Add a “Header Search Path” to the root of the VST 2.4 sdk.
- Add the sdk sources and headers to the project.
You should be able to build the target now with only one linker error :
Undefined symbols:
“createEffectInstance(int (*)(AEffect*, int, int, int, void*, float))”, referenced from: _VSTPluginMain in vstplugmain.o
As an experienced vst developer, you know that this is actually the entry function which will be called by the host to instantiate the vst plug-in. So add your own source files to the project and try to build it.
Next tip will be coming next week.
There’s a lot of talk about the incompatibility of VST 2.3 plug-ins in Cubase 4 on MacIntel.
I will try to give an overview about this issue from my viewpoint.
First get back to the announcement of Apple that they will switch from PowerPC processors to Intel processors. It was some kind of shock to say at least, because for us developers it was the next big transition after the two before namely from m68k to powerpc and then from classic Mac OS to Mac OS X.
At the same time Steinberg development was going to define and implement VST 3 and an update for VST 2.
VST 2.4 had 3 main goals :
- 64 bit system compatibility (not processing)
- MacIntel compatibility
- SDK clean up (with an eye on VST 3) so that we don’t need to make a VST 2.5 update
So we deprecated most stuff which was not used and stuff which won’t work on 64 bit systems.
At that time the only 64 bit operating system available was Windows XP 64 bit (besides all the unix/linux OS we don’t support at the moment). But we knew that Apple is working on a 64 bit OS as well. So we tried to get some information of how it would look like to write an SDK which we don’t need to update when Apple is shipping a 64 bit OS. One thing what was very clear is that Quickdraw won’t be ported by Apple and that there won’t be any support for non composited windows. Because of NDA we could not talk about this aspect in the public, but some Apple developers talked about it on some official mailing-lists in the past month, so I think this should be OK to post now.
So it was clear that the way the UI is handled in VST won’t be supported with Mac OS X 64 bit.
Looking at VST SDK 2.3 we saw that there were special treatment for the Mac UI: effEditDraw, effEditMouse, effEditTop, effEditSleep, effEditKey.
Part of the clean up was to remove special platform opcodes if possible. As we looked at what Mac OS API we could use in the future, we saw that we don’t need these opcodes anymore with HIViews. So we deprecated them and defined that with VST SDK 2.4 all windows must be composited (something previously wasn’t defined at all) and we clearly defined how to embed a plug-in editor into the host window (which was also not defined in previous SDK’s). So for the first time with VST on the Macintosh, we clearly described the editor part and we took care of future compatibility with Mac OS X 64 bit in mind.
One other aspect of switching to HIViews is that we may see more stability, because of some obscure bugs in Quickdraw we saw. (remember the “exception occurred in Module QD” crash ?)
Now comes backwards compatibility, the most discussed thing about VST 2.4.
As MacIntel was only officially supported with VST 2.4 and at that time no shipping Mac had an Intel processor, we saw the opportunity to get out of this special macintosh treatments in the SDK with only supporting VST 2.4 on MacIntel. We made it clear with the announcement of 2.4 that we won’t support 2.3 plug-ins on MacIntel and Windows 64 bit. We released 2.4 before Apple shipped any Intel Mac.
But there was and there are plug-ins which are compiled for MacIntel with VST 2.3. So what ?
There are two possibilities:
- these plug-ins are ported to 2.4
- VST hosts should support 2.3 and 2.4
Porting plug-ins to 2.4 may costs time for the plug-in developers to rewrite their UI code.
Supporting 2.3 for hosts (at least for the ones who support it on mac ppc) must be completely retested.
Even if you think that enabling 2.3 support in Cubase would be just a developer switch, I must admit that this is not the case. We never tested non compositing windows on MacIntel, all the code for support 2.3 on ppc is not compiled into Cubase 4 for MacIntel. This would mean Cubase 4 MacIntel must be completely tested again only for plug-ins where the developers know early on that their plug-in won’t work if they release it without 2.4 support.
I’ve mixed feelings about this, on the one hand I understand plug-in developers who don’t want to waste time supporting MacIntel.
On the other hand I think it’s their mistake to release a UB VST version of their plug-ins compiled with 2.3 as they should have known better.
And I think plug-in developers should take the opportunity for an easier transition to 64 bit on Mac OS. If they get their editors working without Quickdraw with VST 2.4 the chances are very high that they are getting a 64 bit version of their plug-in much earlier running than the others.
And even for those who don’t care at the moment for 64 bit, I think I gave any possible help on the VST mailing-list to get the editors working without much afford on their side.
Just as a reminder, here’s the source code I posted how to get an old plug-in working with HIViews:
// Start of Header
#include "aeffeditor.h"
class MacEditorWrapper
{
public:
MacEditorWrapper (AEffEditor* editor);
~MacEditorWrapper ();
bool attach (WindowRef window);
bool remove ();
virtual void draw (ERect* rect);
virtual bool mouse (VstInt32 x, VstInt32 y);
virtual bool wheel (float distance);
virtual void warpOrigin ();
virtual void resetOrigin ();
virtual void offsetChanged (int x, int y) { offsetX= x; offsetY = y; }
protected:
static pascal OSStatus carbonEventHandler (EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData);
AEffEditor* editor;
HIViewRef userPane;
HIViewRef contentView;
WindowRef window;
int offsetX;
int offsetY;
};
// End of Header
// Start of Source
#include "maceditorwrapper.h"
MacEditorWrapper::MacEditorWrapper (AEffEditor* editor)
: editor (editor)
, userPane (0)
, contentView (0)
, window (0)
, offsetX (0)
, offsetY (0)
{
}
MacEditorWrapper::~MacEditorWrapper ()
{
}
void MacEditorWrapper::draw (ERect* rect)
{
if (userPane)
editor->draw (rect);
}
bool MacEditorWrapper::mouse (VstInt32 x, VstInt32 y)
{
if (userPane)
return editor->mouse (x, y);
return false;
}
bool MacEditorWrapper::wheel (float distance)
{
if (userPane)
return editor->onWheel (distance);
return false;
}
void MacEditorWrapper::warpOrigin ()
{
if (userPane)
SetOrigin (-offsetX, -offsetY);
}
void MacEditorWrapper::resetOrigin ()
{
if (userPane)
SetOrigin (0, 0);
}
bool MacEditorWrapper::attach (WindowRef window)
{
WindowAttributes attr;
if (GetWindowAttributes (window, &attr) == noErr)
{
if (attr & kWindowCompositingAttribute)
{
if (HIViewFindByID (HIViewGetRoot (window), kHIViewWindowContentID, &contentView) == noErr)
{
ERect* r;
editor->getRect (&r);
if (CreateUserPaneControl (NULL, (Rect*)r, 0, &userPane) == noErr)
{
OSStatus err = HIViewAddSubview (contentView, userPane);
assert (err == noErr);
const EventTypeSpec eventTypes[] = { {kEventClassControl, kEventControlDraw},
{kEventClassControl, kEventControlHitTest},
{kEventClassControl, kEventControlClick},
{kEventClassControl, kEventControlBoundsChanged},
{kEventClassMouse, kEventMouseWheelMoved},
};
err = InstallControlEventHandler (userPane, MacEditorWrapper::carbonEventHandler, GetEventTypeCount (eventTypes), eventTypes, this, NULL);
assert (err == noErr);
this->window = window;
return true;
}
}
}
}
return false;
}
bool MacEditorWrapper::remove ()
{
if (userPane)
{
HIViewRemoveFromSuperview (userPane);
userPane = 0;
window = 0;
return true;
}
return false;
}
pascal OSStatus MacEditorWrapper::carbonEventHandler (EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData)
{
MacEditorWrapper* wrapper = (MacEditorWrapper*)inUserData;
OSStatus result = eventNotHandledErr;
CGrafPtr savedPort;
Boolean portChanged = QDSwapPort (GetWindowPort (wrapper->window), &savedPort);
SetOrigin (-wrapper->offsetX, -wrapper->offsetY);
switch (GetEventClass (inEvent))
{
case kEventClassMouse:
{
if (GetEventKind (inEvent) == kEventMouseWheelMoved)
{
SInt32 wheelDelta;
GetEventParameter (inEvent, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof (SInt32), NULL, &wheelDelta);
if (wrapper->wheel ((float)wheelDelta))
result = noErr;
}
break;
}
case kEventClassControl:
{
switch (GetEventKind (inEvent))
{
case kEventControlDraw:
{
ERect* r;
wrapper->editor->getRect (&r);
wrapper->draw (r);
result = noErr;
break;
}
case kEventControlHitTest:
{
result = noErr;
break;
}
case kEventControlClick:
{
HIPoint hipoint;
GetEventParameter (inEvent, kEventParamWindowMouseLocation, typeHIPoint, NULL, sizeof (HIPoint), NULL, &hipoint);
HIPointConvert (&hipoint, kHICoordSpaceWindow, wrapper->window, kHICoordSpaceView, wrapper->userPane);
if (wrapper->mouse ((VstInt32)hipoint.x, (VstInt32)hipoint.y) == 1)
result = noErr;
break;
}
case kEventControlBoundsChanged:
{
UInt32 flags;
GetEventParameter (inEvent, kEventParamAttributes, typeUInt32, NULL, sizeof (UInt32), NULL, &flags);
if (flags & kControlBoundsChangePositionChanged)
{
HIPoint hipoint = {0, 0 };
HIPointConvert (&hipoint, kHICoordSpaceView, wrapper->userPane, kHICoordSpaceView, wrapper->contentView);
wrapper->offsetChanged (hipoint.x, hipoint.y);
}
break;
}
}
break;
}
}
SetOrigin (0, 0);
if (portChanged)
QDSwapPort (savedPort, NULL);
return result;
}
// End of Source
-
// Start of Header
-
#include "aeffeditor.h"
-
-
class MacEditorWrapper
-
{
-
public:
-
MacEditorWrapper (AEffEditor* editor);
-
~MacEditorWrapper ();
-
-
bool attach (WindowRef window);
-
bool remove ();
-
-
virtual void draw (ERect* rect);
-
virtual bool mouse (VstInt32 x, VstInt32 y);
-
virtual bool wheel (float distance);
-
-
virtual void warpOrigin ();
-
virtual void resetOrigin ();
-
-
virtual void offsetChanged (int x, int y) { offsetX= x; offsetY = y; }
-
-
protected:
-
static pascal OSStatus carbonEventHandler (EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData);
-
-
AEffEditor* editor;
-
HIViewRef userPane;
-
HIViewRef contentView;
-
WindowRef window;
-
int offsetX;
-
int offsetY;
-
};
-
// End of Header
-
-
// Start of Source
-
#include "maceditorwrapper.h"
-
-
MacEditorWrapper::MacEditorWrapper (AEffEditor* editor)
-
: editor (editor)
-
, userPane (0)
-
, contentView (0)
-
, window (0)
-
, offsetX (0)
-
, offsetY (0)
-
{
-
}
-
-
MacEditorWrapper::~MacEditorWrapper ()
-
{
-
}
-
-
void MacEditorWrapper::draw (ERect* rect)
-
{
-
if (userPane)
-
editor->draw (rect);
-
}
-
-
bool MacEditorWrapper::mouse (VstInt32 x, VstInt32 y)
-
{
-
if (userPane)
-
return editor->mouse (x, y);
-
return false;
-
}
-
-
bool MacEditorWrapper::wheel (float distance)
-
{
-
if (userPane)
-
return editor->onWheel (distance);
-
return false;
-
}
-
-
void MacEditorWrapper::warpOrigin ()
-
{
-
if (userPane)
-
SetOrigin (-offsetX, -offsetY);
-
}
-
-
void MacEditorWrapper::resetOrigin ()
-
{
-
if (userPane)
-
SetOrigin (0, 0);
-
}
-
-
bool MacEditorWrapper::attach (WindowRef window)
-
{
-
WindowAttributes attr;
-
if (GetWindowAttributes (window, &attr) == noErr)
-
{
-
if (attr & kWindowCompositingAttribute)
-
{
-
if (HIViewFindByID (HIViewGetRoot (window), kHIViewWindowContentID, &contentView) == noErr)
-
{
-
ERect* r;
-
editor->getRect (&r);
-
if (CreateUserPaneControl (NULL, (Rect*)r, 0, &userPane) == noErr)
-
{
-
OSStatus err = HIViewAddSubview (contentView, userPane);
-
assert (err == noErr);
-
const EventTypeSpec eventTypes[] = { {kEventClassControl, kEventControlDraw},
-
{kEventClassControl, kEventControlHitTest},
-
{kEventClassControl, kEventControlClick},
-
{kEventClassControl, kEventControlBoundsChanged},
-
{kEventClassMouse, kEventMouseWheelMoved},
-
};
-
err = InstallControlEventHandler (userPane, MacEditorWrapper::carbonEventHandler, GetEventTypeCount (eventTypes), eventTypes, this, NULL);
-
assert (err == noErr);
-
this->window = window;
-
return true;
-
}
-
}
-
}
-
}
-
return false;
-
}
-
-
bool MacEditorWrapper::remove ()
-
{
-
if (userPane)
-
{
-
HIViewRemoveFromSuperview (userPane);
-
userPane = 0;
-
window = 0;
-
return true;
-
}
-
return false;
-
}
-
-
pascal OSStatus MacEditorWrapper::carbonEventHandler (EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData)
-
{
-
MacEditorWrapper* wrapper = (MacEditorWrapper*)inUserData;
-
OSStatus result = eventNotHandledErr;
-
-
CGrafPtr savedPort;
-
Boolean portChanged = QDSwapPort (GetWindowPort (wrapper->window), &savedPort);
-
SetOrigin (-wrapper->offsetX, -wrapper->offsetY);
-
-
switch (GetEventClass (inEvent))
-
{
-
case kEventClassMouse:
-
{
-
if (GetEventKind (inEvent) == kEventMouseWheelMoved)
-
{
-
SInt32 wheelDelta;
-
GetEventParameter (inEvent, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof (SInt32), NULL, &wheelDelta);
-
if (wrapper->wheel ((float)wheelDelta))
-
result = noErr;
-
}
-
break;
-
}
-
case kEventClassControl:
-
{
-
switch (GetEventKind (inEvent))
-
{
-
case kEventControlDraw:
-
{
-
ERect* r;
-
wrapper->editor->getRect (&r);
-
wrapper->draw (r);
-
result = noErr;
-
break;
-
}
-
case kEventControlHitTest:
-
{
-
result = noErr;
-
break;
-
}
-
case kEventControlClick:
-
{
-
HIPoint hipoint;
-
GetEventParameter (inEvent, kEventParamWindowMouseLocation, typeHIPoint, NULL, sizeof (HIPoint), NULL, &hipoint);
-
HIPointConvert (&hipoint, kHICoordSpaceWindow, wrapper->window, kHICoordSpaceView, wrapper->userPane);
-
if (wrapper->mouse ((VstInt32)hipoint.x, (VstInt32)hipoint.y) == 1)
-
result = noErr;
-
break;
-
}
-
case kEventControlBoundsChanged:
-
{
-
UInt32 flags;
-
GetEventParameter (inEvent, kEventParamAttributes, typeUInt32, NULL, sizeof (UInt32), NULL, &flags);
-
if (flags & kControlBoundsChangePositionChanged)
-
{
-
HIPoint hipoint = {0, 0 };
-
HIPointConvert (&hipoint, kHICoordSpaceView, wrapper->userPane, kHICoordSpaceView, wrapper->contentView);
-
wrapper->offsetChanged (hipoint.x, hipoint.y);
-
}
-
break;
-
}
-
}
-
break;
-
}
-
}
-
-
SetOrigin (0, 0);
-
if (portChanged)
-
QDSwapPort (savedPort, NULL);
-
-
return result;
-
}
-
// End of Source
With this code you only need to do this in your editor open (void* ptr) method:
#if MAC
guiWrapper = new MacEditorWrapper (this);
guiWrapper->attach ((WindowRef)ptr);
#endif
-
#if MAC
-
guiWrapper = new MacEditorWrapper (this);
-
guiWrapper->attach ((WindowRef)ptr);
-
#endif
And this on close :
#if MAC
guiWrapper->remove ();
delete guiWrapper;
guiWrapper = 0;
#endif
-
#if MAC
-
guiWrapper->remove ();
-
delete guiWrapper;
-
guiWrapper = 0;
-
#endif
And of course guiWrapper should be a member of your editor class.
As knup is now hosted on a new machine I changed my blog software. Now I’m using WordPress. It will take some time until all stuff from my old site will be available.
So stay tuned.
One nice thing about this change is, that I can write my posts now in TextMate. That’s a lot nicer than in these clunky embedded web browser editors.
It just made me thick to edit large files in Xcode that I completly switched to BBEdit now.
The one thing I missed most was to quickly find the selected text in the Apple headers. So I have written an apple script for this which uses Spotlight and BBEdit’s multi search I like to share with you :
set MacOSSDK to "/Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/"
tell application "BBEdit"
set fdoc to name of front text document
set searchString to (selection of text of front text document) as text
end tell
set command to "mdfind "kMDItemTextContent == '" & searchString & "'" -onlyin " & MacOSSDK
set mdResult to every paragraph of (do shell script command)
if (not mdResult = "") then
set fileList to {}
set fileListRef to a reference to fileList
repeat with posixFile in mdResult
copy POSIX file posixFile to the end of fileListRef
end repeat
tell application "BBEdit"
set search_opts to {starting at top:true, case sensitive:true, match words:true}
set searchResult to find (searchString as text) searching in fileList options search_opts
activate
end tell
end if
-
set MacOSSDK to "/Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/"
-
tell application "BBEdit"
-
set fdoc to name of front text document
-
set searchString to (selection of text of front text document) as text
-
end tell
-
set command to "mdfind "kMDItemTextContent == ‘" & searchString & "’" -onlyin " & MacOSSDK
-
set mdResult to every paragraph of (do shell script command)
-
if (not mdResult = "") then
-
set fileList to {}
-
set fileListRef to a reference to fileList
-
repeat with posixFile in mdResult
-
copy POSIX file posixFile to the end of fileListRef
-
end repeat
-
tell application "BBEdit"
-
set search_opts to {starting at top:true, case sensitive:true, match words:true}
-
set searchResult to find (searchString as text) searching in fileList options search_opts
-
activate
-
end tell
-
end if
—
Next Page »