• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Wrapping VSTGUI for Dummies
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Wrapping VSTGUI for Dummies


  • Subject: Wrapping VSTGUI for Dummies
  • From: Art Gillespie <email@hidden>
  • Date: Thu, 2 Oct 2003 16:54:44 -0400

Peoples,

After spending the better part of the day doing some pro-bono work trying to help out yet another dev with their Emagic VST->AU wrapper woes, I came to the following conclusion:

The Emagic VST->AU wrapper is useless.

Below is a modified copy of VST2AUView.cpp with my comments and changes (generally preceded with AG:). I tried to simply comment out the original stuff that I changed, so you can compare and contrast. I also tried to edit my original comments for content and political sensitivity, but may have missed a few. :)

Hope this helps somebody out.

Best,

Art
>>0xBA



#include "VST2AUView.h"
#include "AEffEditor.hpp"
#ifndef __AudioEffect__
#include "AudioEffect.hpp"
#endif


// ------------------------------------------------------------------------ -----
// Class CVST2AUView
// ------------------------------------------------------------------------ -----

// Component entry point -------------------------------------------------------
COMPONENT_ENTRY(CVST2AUView);

// -> V1.1: Mechanism for CodeWarrior symbol export
#ifdef __MWERKS__
#pragma export list CVST2AUViewEntry
#endif
// <- V1.1


// ------------------------------------------------------------------------ -----
CVST2AUView::CVST2AUView(AudioUnitCarbonView tView):
AUCarbonViewBase(tView),
m_pcVSTGUI(NULL),
m_u32Left(0),
m_u32Top(0),
m_u32Bottom(0),
m_u32Right(0),
theBundle(NULL) //AG: since we need the bundleRef so often, let's keep it around!!!
{}

//--------------------------
// Special IdleProc o handle idle events of VSTGUI etc
pascal void IdleProc(EventLoopTimerRef tTimer, void *pUser)
{
if(pUser){
CVST2AUView *pcThis = (CVST2AUView *)(pUser);

GrafPtr tPort;
EventRecord sEvent;

GetPort(&tPort);
SetPortWindowPort(pcThis->m_tWindow);
sEvent.what = nullEvent;
//AG: SetOrigin is totally gay
//SetOrigin(pcThis->m_u32Left, -pcThis->m_u32Top);
pcThis->pcFX->dispatcher(effEditIdle, 0, 0, 0, 0.0f);
//AG: ibid
//SetOrigin(0, 0);
SetPort(tPort);
}
}


// ------------------------------------------------------------------------ -----
CVST2AUView::~CVST2AUView(void)
{
//idle proc and timer remove
if(m_tTimer)
RemoveEventLoopTimer(m_tTimer);
if(m_uppIdleProc)
DisposeEventLoopTimerUPP(m_uppIdleProc);
m_tTimer = NULL;
m_uppIdleProc = NULL;

//rest of all
//AG: use dispatcher instead of direct instance
//if (m_pcVSTGUI) m_pcVSTGUI->close();
pcFX->dispatcher(effEditClose, 0, 0, 0, 0.0f);
//delete m_pcVSTGUI;
//m_pcVSTGUI = NULL;
//pcFX->setEditor(NULL);
//AG: Since we kept our bundleref around, let's dispose of it
if (theBundle)
{
CFRelease(theBundle);
theBundle = NULL;
}
}




// ------------------------------------------------------------------------ -----
OSStatus CVST2AUView::CreateUI(Float32 rX, Float32 rY)
{
// -> V1.1: Put the unique bundle identifier here
// Get the bundle reference with the bundle ID
theBundle=CFBundleGetBundleWithIdentifier(CFSTR("com.pspaudioware.plugin s.springverb"));
// <- V1.1
if (!theBundle)
{
//AG Why the fuck doesn't emagic check return values?
fprintf(stderr, "CFBundleGetBundleWithIdentifier Failed\n");
return kAudioUnitErr_FailedInitialization;
}
//AG We want to keep the BundleRef around
CFRetain(theBundle);
// Open the resources
const SInt16 s16OldRes=CurResFile();
const SInt16 s16Res=CFBundleOpenBundleResourceMap(theBundle);
UseResFile(s16Res);

// Get the calling Audio Unit
const AudioUnit tAU=GetEditAudioUnit();

// Get the this-ptr. This is very dirty!
AudioEffect* ptrEffect=NULL;
UInt32 u32Size=sizeof(AudioEffect*);
AudioUnitGetProperty(tAU, kVST2AudioUnitProperty_AudioEffectPtr, kAudioUnitScope_Global, 0, (void*)(&ptrEffect), &u32Size);
pcFX = ptrEffect;
if (pcFX == NULL) //AG: check for errors!
return kAudioUnitErr_FailedInitialization;
// Create the VST GUI
//AG: The VST is supposed to manage it's own interface instance
// ... this wrapper *should* be using dispatcher opcodes to do all this
// if we create a new instance of the GUI and call SetEditor, with most VSTs this will
// cause a memory leak as the plug-ins self-created UI pointer is dereferenced.
// Broken. (see AEffect::setEditor)
//

//m_pcVSTGUI=new VST2AU_GUI_CLASS(pcFX);
//pcFX->setEditor(m_pcVSTGUI);

/**
* AG: The best-kept secret about VST's gui handling (or so it would seem).
* The proper way to inform a VST UI (including VSTGUI) of offsets is by getting
* a pointer to the editor's bounds rect and setting it. (Yes, this is very, very
* bad OO). So here we use the dispatcher interface to get the rect and offset it
* using the x, y offsets passed to CreateUI.
*
* It's up to the VST's UI to handle offsets, so all of the calls to SetOrigin are
* unnecessary. VST's that use VSTGUI get this behavior automatically. Unfortunately,
* it seems that many VSTGUI-based plugins don't pass the AEffEditor's rect member as
* the first argument to CFrame's constructor (look at the source for CFrame in vstgui.cpp
* and you'll see under the #elif MAC section that it sets up x, y offsets for the drawing
* context).
*
* If you use this code and you're using VSTGUI and you find you're still drawing without the
* appropriate offset, check to see that your passing the right
* rect to CFrame's constructor in your open() method.
*/
ERect* psRect=NULL;
pcFX->dispatcher(effEditGetRect, 0, 0, (void*)&psRect, 0.0f);
//m_pcVSTGUI->getRect(&psRect);
psRect->left+=UInt32(rX);
psRect->top+=UInt32(rY);
psRect->right+=UInt32(rX);
psRect->bottom+=UInt32(rY);
m_u32Left=psRect->left;
m_u32Top=psRect->top;
m_u32Bottom=psRect->bottom;
m_u32Right=psRect->right;

//AG: NO, NO, NO, NO... why do we need to do this? The dispatcher interface doesn't
//provide for it, so why do we need it?
// See long-winded explanation of offsets for VST above
//m_pcVSTGUI->originX = m_u32Left;
//m_pcVSTGUI->originY = -m_u32Top;

//AG: SetOrigin is the devil
//SetOrigin(m_u32Left, -m_u32Top);
//AG: Use opcodes/dispatcher interface instead
//m_pcVSTGUI->open(WindowPtr(mCarbonWindow));

pcFX->dispatcher(effEditOpen, 0, 0, WindowPtr(mCarbonWindow), 0.0f);

mBottomRight.v=psRect->bottom;
mBottomRight.h=psRect->right;

GrafPtr tPort;
GetPort(&tPort);
SetPortWindowPort(mCarbonWindow);

//AG: NO
//SetOrigin(m_pcVSTGUI->originX, m_pcVSTGUI->originY);//m_u32Left, -m_u32Top);


//AG: Huh? Why would we draw here? Most hosts won't even have resized the window
//until we return from CreateUI

//ERect sRect;
//sRect.top=0;
//sRect.left=0;
//sRect.bottom=mBottomRight.v;
//sRect.right=mBottomRight.h;
//m_pcVSTGUI->draw(&sRect);

//
SetPort(tPort);

// Set the old resource file
UseResFile(s16OldRes);
/**
* AG: THE SMART WAY TO DO THIS IS TO USE CONTROL EVENTS ON THE CARBON PANE
* I've commented out Emagic's original handler installer and put in what
* I use. Emagic's version won't work consistently in hosts other than logic (and not even
* then), causing
* mad mouse and draw bugs.
*
* // Add some events to the handler
* EventTypeSpec asWindowEvents[] =
* {
* { kEventClassMouse, kEventMouseDown },
* { kEventClassMouse, kEventMouseDragged },
*
* { kEventClassWindow, kEventWindowDrawContent },
* { kEventClassWindow, kEventWindowResizeCompleted },
* { kEventClassWindow, kEventWindowDragCompleted },
* { kEventClassWindow, kEventWindowUpdate }//,
*
* };
*
* WantEventTypes(GetWindowEventTarget(mCarbonWindow),
* GetEventTypeCount(asWindowEvents),
* asWindowEvents);
*/

/** AG: My Event handling scheme (ControlEvents work with hosts other than Logic) **/

/* Register for control events on the Carbon Pane */
EventTypeSpec eventTypes[5];
eventTypes[0].eventClass = kEventClassControl;
eventTypes[0].eventKind = kEventControlDraw;
eventTypes[1].eventClass = kEventClassControl;
eventTypes[1].eventKind = kEventControlHit;
eventTypes[2].eventClass = kEventClassControl;
eventTypes[2].eventKind = kEventControlHitTest;
eventTypes[3].eventClass = kEventClassControl;
eventTypes[3].eventKind = kEventControlClick;
eventTypes[4].eventClass = kEventClassControl;
eventTypes[4].eventKind = kEventControlTrack;
WantEventTypes(GetControlEventTarget(mCarbonPane),
GetEventTypeCount(eventTypes),
eventTypes);


TXNInitTextension ( NULL, 0, 0 );

//Try to start event loop timer for idle() calls
m_tWindow = mCarbonWindow;
m_uppIdleProc = NewEventLoopTimerUPP(IdleProc);
OSStatus tErr = InstallEventLoopTimer(GetMainEventLoop(),
100. * kEventDurationMillisecond, 60 * kEventDurationMillisecond,
m_uppIdleProc,
this, &m_tTimer);
//AG: Should have been calling this
CFBundleCloseBundleResourceMap(theBundle, s16Res);
return noErr;
}

/**
AG: Commented out Emagic's HandleEvent.

// ------------------------------------------------------------------------ -----
bool CVST2AUView::HandleEvent(EventRef tEvent)
{

const UInt32 kTitleSize=16;

UInt32 iClass=GetEventClass(tEvent);
UInt32 iKind=GetEventKind(tEvent);

if (iClass==kEventClassWindow)
{
if (iKind==kEventWindowUpdate || iKind==kEventWindowDrawContent
|| iKind==kEventWindowResizeCompleted || iKind==kEventWindowDragCompleted)
{
// -> V1.1: Put the unique bundle identifier here
// Get the bundle reference with the bundle ID
CFBundleRef tRef=CFBundleGetBundleWithIdentifier(CFSTR("com.pspaudioware.plugins.spr ingverb"));
// <- V1.1
//AG: CHECK FOR FUCKING ERROR CODES!!!!
if (!tRef)
{
fprintf(stderr, "CFBundleGetBundleWithIdentifier Failed in HandleEvent\n");
return false;
}
// Open the resources
const SInt16 s16OldRes=CurResFile();
const SInt16 s16Res=CFBundleOpenBundleResourceMap(tRef);
UseResFile(s16Res);

GrafPtr tPort;
GetPort(&tPort);
SetPortWindowPort(mCarbonWindow);
SetOrigin(m_u32Left, -m_u32Top);

ERect sRect;
sRect.top=0;
sRect.left=0;
sRect.bottom=mBottomRight.v;
sRect.right=mBottomRight.h;
m_pcVSTGUI->draw(&sRect);

// SetOrigin(0, 0);
SetPort(tPort);

// Set the old resource file
UseResFile(s16OldRes);

return true;
}
}

else if (iClass==kEventClassMouse)
{
if (iKind==kEventMouseDown || iKind==kEventMouseDragged)
{
fprintf(stderr, "Mouse Down\n");
HIPoint tPnt;
UInt32 u32Modifiers=0;
GetEventParameter(tEvent, kEventParamWindowMouseLocation, typeHIPoint, NULL, sizeof(HIPoint), NULL, &tPnt);
GetEventParameter(tEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &u32Modifiers);
tPnt.y-=kTitleSize;

if (tPnt.x>=m_u32Left && tPnt.x<m_u32Right && tPnt.y>=m_u32Top && tPnt.y<m_u32Bottom)
{
tPnt.y-=m_u32Top;
GrafPtr tPort;
GetPort(&tPort);
SetPortWindowPort(mCarbonWindow);
SetOrigin(m_u32Left, -m_u32Top);

m_pcVSTGUI->mouse(tPnt.x, tPnt.y);

// SetOrigin(0, 0);
SetPort(tPort);

return true;
}
}
}

return false;
}

*/

bool CVST2AUView::HandleEvent(EventRef inEvent)
{
UInt32 eventClass = GetEventClass(inEvent);
UInt32 eventKind = GetEventKind(inEvent);

switch (eventClass)
{
case kEventClassControl:
{
switch (eventKind)
{
case kEventControlDraw:
{

CGrafPtr save;
GetPort(&save);
SetPortWindowPort(mCarbonWindow);
Draw();
SetPort(save);
return true;
}
case kEventControlClick:
case kEventControlTrack:
{
CGrafPtr save;
GetPort(&save);
SetPortWindowPort(mCarbonWindow);
HIPoint mouseLocation_f;
memset(&mouseLocation_f, 0, sizeof(HIPoint));
GetEventParameter(inEvent, kEventParamMouseLocation, typeHIPoint, NULL,
sizeof(HIPoint), NULL, &mouseLocation_f);
long mouseX = (long) mouseLocation_f.x;
long mouseY = (long) mouseLocation_f.y;
MouseDown(mouseX, mouseY);
SetPort(save);
return true;

}
case kEventControlHitTest:
{
//AG: This is a really important event, if we don't return something //sensible, the event manager won't send any more mouse events
int where = 16;
SetEventParameter(inEvent, kEventParamControlPart, typeControlPartCode,
sizeof(typeControlPartCode), &where);
return true;
}
default:
{
return AUCarbonViewBase::HandleEvent(inEvent);
}
}
}
}
return AUCarbonViewBase::HandleEvent(inEvent);

}

void CVST2AUView::MouseDown(long x, long y)
{
Rect controlBounds;
GetControlBounds(mCarbonPane, &controlBounds);
Rect globalBounds;
GetWindowBounds( GetControlOwner(mCarbonPane), kWindowGlobalPortRgn, &globalBounds );
x -= globalBounds.left + controlBounds.left;
y -= globalBounds.top + controlBounds.top;
CGrafPtr port;
GetPort(&port);
SInt16 restmp = CurResFile();
SetPortWindowPort(mCarbonWindow);
SInt16 resNew = CFBundleOpenBundleResourceMap(theBundle);
//AG: robust implementations would chck resNew for validity
pcFX->dispatcher(effEditMouse, x, y, 0, 0.0f);
UseResFile(restmp);
CFBundleCloseBundleResourceMap(theBundle, resNew);
SetPort(port);
}

void CVST2AUView::Draw()
{
SInt16 restmp = CurResFile();
SInt16 resNew = CFBundleOpenBundleResourceMap(theBundle);
//AG: robust implementations would check resNew for validity
ERect* f;
pcFX->dispatcher(effEditGetRect, 0, 0, (void*)&f, 0.0f);
CGrafPtr port;
GetPort(&port);
SetPortWindowPort(mCarbonWindow);
pcFX->dispatcher(effEditDraw, 0, 0, (void*)f, 0.0f);
UseResFile(restmp);
CFBundleCloseBundleResourceMap(theBundle, resNew);
SetPort(port);
}

// ------------------------------------------------------------------------ -----
// End of file.
// ------------------------------------------------------------------------ -----
_______________________________________________
coreaudio-api mailing list | email@hidden
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/coreaudio-api
Do not post admin requests to the list. They will be ignored.
  • Follow-Ups:
    • Re: Wrapping VSTGUI for Dummies
      • From: "Angus F. Hewlett" <email@hidden>
  • Prev by Date: Re: MIDITimeStamp
  • Next by Date: Re: Wrapping VSTGUI for Dummies
  • Previous by thread: Re: [OT] Host Developers! - SheetWindows
  • Next by thread: Re: Wrapping VSTGUI for Dummies
  • Index(es):
    • Date
    • Thread