From 5157decd47710b3ed8e4e62e79e07aa1967bd532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juha=20Vehvil=C3=A4inen?= Date: Wed, 19 Jun 2002 15:00:09 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r14, which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/vst/; revision=15 --- EditorThread.cpp | 59 ++++++ EditorThread.h | 57 ++++++ PopupWindow.cpp | 116 +++++++++++ PopupWindow.h | 55 +++++ ReadMe.txt | 57 ++++++ Resource.h | 16 ++ StdAfx.cpp | 8 + StdAfx.h | 42 ++++ Vst/AEffEditor.h | 44 ++++ Vst/AEffect.h | 172 ++++++++++++++++ Vst/AEffectx.h | 534 +++++++++++++++++++++++++++++++++++++++++++++++ Vst/AudioEffect.hpp | 109 ++++++++++ Vst/audioeffectx.h | 185 +++++++++++++++++ VstHost.cpp | 581 ++++++++++++++++++++++++++++++++++++++++++++++++++++ VstHost.h | 145 +++++++++++++ crazy.pd | 16 ++ export.h | 9 + neontest.pd | 14 ++ res/vst.rc2 | 13 ++ vst.aps | Bin 0 -> 17844 bytes vst.clw | 37 ++++ vst.cpp | 111 ++++++++++ vst.def | 7 + vst.dsp | 176 ++++++++++++++++ vst.dsw | 29 +++ vst.h | 46 +++++ vst.ncb | Bin 0 -> 199680 bytes vst.opt | Bin 0 -> 54784 bytes vst.plg | 53 +++++ vst.rc | 124 +++++++++++ vst.sln | 21 ++ vst.suo | Bin 0 -> 12288 bytes vst.vcproj | 224 ++++++++++++++++++++ vsttest.pd | 32 +++ vst~.cpp | 579 +++++++++++++++++++++++++++++++++++++++++++++++++++ vst~.h | 63 ++++++ vst~.pdf | Bin 0 -> 192748 bytes 37 files changed, 3734 insertions(+) create mode 100644 EditorThread.cpp create mode 100644 EditorThread.h create mode 100644 PopupWindow.cpp create mode 100644 PopupWindow.h create mode 100644 ReadMe.txt create mode 100644 Resource.h create mode 100644 StdAfx.cpp create mode 100644 StdAfx.h create mode 100644 Vst/AEffEditor.h create mode 100644 Vst/AEffect.h create mode 100644 Vst/AEffectx.h create mode 100644 Vst/AudioEffect.hpp create mode 100644 Vst/audioeffectx.h create mode 100644 VstHost.cpp create mode 100644 VstHost.h create mode 100644 crazy.pd create mode 100644 export.h create mode 100644 neontest.pd create mode 100644 res/vst.rc2 create mode 100644 vst.aps create mode 100644 vst.clw create mode 100644 vst.cpp create mode 100644 vst.def create mode 100644 vst.dsp create mode 100644 vst.dsw create mode 100644 vst.h create mode 100644 vst.ncb create mode 100644 vst.opt create mode 100644 vst.plg create mode 100644 vst.rc create mode 100644 vst.sln create mode 100644 vst.suo create mode 100644 vst.vcproj create mode 100644 vsttest.pd create mode 100644 vst~.cpp create mode 100644 vst~.h create mode 100644 vst~.pdf diff --git a/EditorThread.cpp b/EditorThread.cpp new file mode 100644 index 0000000..5030f5a --- /dev/null +++ b/EditorThread.cpp @@ -0,0 +1,59 @@ +// EditorThread.cpp : implementation file +// + +#include "stdafx.h" +#include "vst.h" +#include "EditorThread.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CEditorThread + +IMPLEMENT_DYNCREATE(CEditorThread, CWinThread) + +CEditorThread::CEditorThread() +{ + pop = NULL; +} + +CEditorThread::~CEditorThread() +{ +} + +BOOL CEditorThread::InitInstance() +{ + pop = new CPopupWindow(); + m_pMainWnd = pop; + pop->CreateEx( WS_EX_DLGMODALFRAME , AfxRegisterWndClass( CS_DBLCLKS) ," VST window" , WS_CAPTION | WS_THICKFRAME | WS_POPUP | WS_SYSMENU , 10 , 10 , 300 , 300 , NULL , NULL , NULL); + pop->SetPlugin( plug ); + pop->DoInit(); + pop->ShowWindow( SW_SHOW ); + pop->BringWindowToTop(); + pop->SetFocus(); + return TRUE; +} + +int CEditorThread::ExitInstance() +{ + // TODO: perform any per-thread cleanup here + return CWinThread::ExitInstance(); +} + +BEGIN_MESSAGE_MAP(CEditorThread, CWinThread) + //{{AFX_MSG_MAP(CEditorThread) + // NOTE - the ClassWizard will add and remove mapping macros here. + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CEditorThread message handlers + +void CEditorThread::SetPlugin(VSTPlugin *p) +{ + plug = p; +} diff --git a/EditorThread.h b/EditorThread.h new file mode 100644 index 0000000..5c2c182 --- /dev/null +++ b/EditorThread.h @@ -0,0 +1,57 @@ +#if !defined(AFX_EDITORTHREAD_H__9F3ACE98_7522_400D_9404_DFD67E3D721B__INCLUDED_) +#define AFX_EDITORTHREAD_H__9F3ACE98_7522_400D_9404_DFD67E3D721B__INCLUDED_ + +#include "PopupWindow.h" // Added by ClassView +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// EditorThread.h : header file +// + +class VSTPLugin; + +///////////////////////////////////////////////////////////////////////////// +// CEditorThread thread + +class CEditorThread : public CWinThread +{ + DECLARE_DYNCREATE(CEditorThread) +protected: + + +// Attributes +public: + CEditorThread(); // protected constructor used by dynamic creation + +// Operations +public: + VSTPlugin* plug; + void SetPlugin( VSTPlugin *); + CPopupWindow *pop; + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CEditorThread) + public: + virtual BOOL InitInstance(); + virtual int ExitInstance(); + //}}AFX_VIRTUAL + +// Implementation +protected: + virtual ~CEditorThread(); + + // Generated message map functions + //{{AFX_MSG(CEditorThread) + // NOTE - the ClassWizard will add and remove member functions here. + //}}AFX_MSG + + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_EDITORTHREAD_H__9F3ACE98_7522_400D_9404_DFD67E3D721B__INCLUDED_) diff --git a/PopupWindow.cpp b/PopupWindow.cpp new file mode 100644 index 0000000..5a96bdc --- /dev/null +++ b/PopupWindow.cpp @@ -0,0 +1,116 @@ +// PopupWindow.cpp : implementation file +// + +#include "stdafx.h" +#include "m_pd.h" +#include "vst.h" +#include "PopupWindow.h" +#include "EditorThread.h" +#include "VstHost.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +extern CVstApp theApp; + +///////////////////////////////////////////////////////////////////////////// +// CPopupWindow + +IMPLEMENT_DYNCREATE(CPopupWindow, CFrameWnd) + +CPopupWindow::CPopupWindow() +{ + plug = NULL; +} + +CPopupWindow::~CPopupWindow() +{ + plug->OnEditorCLose(); + plug = NULL; +} + + +BEGIN_MESSAGE_MAP(CPopupWindow, CFrameWnd) + //{{AFX_MSG_MAP(CPopupWindow) + ON_WM_ENTERIDLE() + ON_WM_TIMER() + ON_WM_MOVE() + ON_WM_CLOSE() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CPopupWindow message handlers + +void CPopupWindow::OnEnterIdle(UINT nWhy, CWnd* pWho) +{ + CFrameWnd::OnEnterIdle(nWhy, pWho); + + // TODO: Add your message handler code here + if (plug != NULL ) + { + plug->EditorIdle(); + } +} + +void CPopupWindow::SetPlugin(VSTPlugin *p) +{ + plug = p; + plug->Dispatch(effEditOpen , 0 , 0 , m_hWnd , 0.0f ); + RECT r = plug->GetEditorRect(); + CString str = theApp.GetProfileString( "VSTPos" , plug->GetName() , "10,10"); + int idx = str.Find(","); + CString x = str.Left( idx ); + CString y = str.Right( idx ); + printf(" index is %d left is %s and right is %s" , idx , x , y); + SetWindowPos( &wndTopMost , atoi( x ) , atoi( y ) , (r.right - r.left) + 10 , r.bottom - r.top + 30 , SWP_SHOWWINDOW ); +} + +BOOL CPopupWindow::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) +{ + // TODO: Add your specialized code here and/or call the base class + + return CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext); +} + +void CPopupWindow::DoInit() +{ + printf("DoInit\n"); + plug->Dispatch(effEditTop,0,0, 0,0.0f); + printf("Dispatched to the top\n"); + SetTimer(0,25,NULL); +} + +void CPopupWindow::OnTimer(UINT nIDEvent) +{ + plug->Dispatch(effEditIdle, 0, 0, NULL, 0.0f); + CFrameWnd::OnTimer(nIDEvent); +} + +void CPopupWindow::OnMove(int x, int y) +{ + CFrameWnd::OnMove(x, y); + if ( plug != NULL ) + { + char buf[100]; + sprintf( buf , "%d,%d" , x , y ); + theApp.WriteProfileString( "VSTPos" , plug->GetName() , buf ); + } +} + + +void CPopupWindow::OnFinalRelease() +{ + // + CFrameWnd::OnFinalRelease(); +} + +void CPopupWindow::OnClose() +{ + // TODO: Add your message handler code here and/or call default + plug->StopEditing(); + CFrameWnd::OnClose(); +} diff --git a/PopupWindow.h b/PopupWindow.h new file mode 100644 index 0000000..32d9ea5 --- /dev/null +++ b/PopupWindow.h @@ -0,0 +1,55 @@ +#if !defined(AFX_POPUPWINDOW_H__7B1E2281_5085_4F60_8002_5F79B2CAFFE3__INCLUDED_) +#define AFX_POPUPWINDOW_H__7B1E2281_5085_4F60_8002_5F79B2CAFFE3__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// PopupWindow.h : header file +// + +class VSTPlugin; + +///////////////////////////////////////////////////////////////////////////// +// CPopupWindow frame + +class CPopupWindow : public CFrameWnd +{ + DECLARE_DYNCREATE(CPopupWindow) +// Attributes +public: + CPopupWindow(); + virtual ~CPopupWindow(); +// Operations +public: + void DoInit(); + void SetPlugin( VSTPlugin *p); + VSTPlugin * plug; + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CPopupWindow) + public: + virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL); + virtual void OnFinalRelease(); + //}}AFX_VIRTUAL + +// Implementation +protected: + + + // Generated message map functions + //{{AFX_MSG(CPopupWindow) + afx_msg void OnEnterIdle(UINT nWhy, CWnd* pWho); + afx_msg void OnTimer(UINT nIDEvent); + afx_msg void OnMove(int x, int y); + afx_msg void OnClose(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_POPUPWINDOW_H__7B1E2281_5085_4F60_8002_5F79B2CAFFE3__INCLUDED_) diff --git a/ReadMe.txt b/ReadMe.txt new file mode 100644 index 0000000..e144350 --- /dev/null +++ b/ReadMe.txt @@ -0,0 +1,57 @@ +VST~ + +reference: http://iem.kug.ac.at/~jams/ +this plugin uses a tiny amount of code from the plugin~ +object mentioned above. It also tries to replicate the +syntax + +setup + +Set environment var to locate your plugins: + +set VST_PATH=C:\Program Files\Steinberg\Vstplugins\Plugins archive;C:\Program Files\Steinberg\Vstplugins\VSTPlugs;C:\audio\Cubase5\Vstplugins\VstPlugins;C:\Program Files\Steinberg\Vstplugins + +add the following line to your PD startup (editing the path to +suit) + +-lib \VST\Debug\vst + +There are three example patches - using Waldorf D-pole, Pro-52 +(helpfully called neontest) and Crazy Diamond http://rumpelrausch.de.vu/ + +notes: + +In order to support plugins with spaces in the name it takes all +the parameters it is given and assumes they are parts of the +name with spaces in between. Thus + + vst~ waldorf d-pole + +loads the d-pole plugin because it looks for "waldorf d-pole". The +VST_PATH environment variable is use just like for "Plugin~". +The two right most inputs are for midi note and velocity and +work just like the "noteout" object. + +There is not currently any support for: + + programs + other midi messages + help file + + I am in the process of adding all of these. The editor does +actually work but the window it is in breaks PD so it is disabled +at present. There are no plans for a graphical interface for +plugins with no supplied editor - what do you think PD is for ;-) + +I have discovered that not all VST plugins behave properly +- for example I found one called VST_Chopper that crashes +PD if you print its parameters. + +New Stuff: + +There are a number of "plugins" that come with Cubase (truetape, double delay etc). +Despite being in a folder called VSTPLugins these are NOT VST plugins but +Cubase extentsions. Steinberg themselves told me this. + +There is now support for the built in editor. Send an Edit message to the +plugin to see the graphical editor. diff --git a/Resource.h b/Resource.h new file mode 100644 index 0000000..7fe29ce --- /dev/null +++ b/Resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by VST.RC +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS + +#define _APS_NEXT_RESOURCE_VALUE 4000 +#define _APS_NEXT_CONTROL_VALUE 4000 +#define _APS_NEXT_SYMED_VALUE 4000 +#define _APS_NEXT_COMMAND_VALUE 32771 +#endif +#endif diff --git a/StdAfx.cpp b/StdAfx.cpp new file mode 100644 index 0000000..5a3a91f --- /dev/null +++ b/StdAfx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// vst.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + + diff --git a/StdAfx.h b/StdAfx.h new file mode 100644 index 0000000..ec2d51f --- /dev/null +++ b/StdAfx.h @@ -0,0 +1,42 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__694C13F1_369D_446F_992D_3F454A0993C6__INCLUDED_) +#define AFX_STDAFX_H__694C13F1_369D_446F_992D_3F454A0993C6__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions + +#ifndef _AFX_NO_OLE_SUPPORT +#include // MFC OLE classes +#include // MFC OLE dialog classes +#include // MFC Automation classes +#endif // _AFX_NO_OLE_SUPPORT + + +#ifndef _AFX_NO_DB_SUPPORT +#include // MFC ODBC database classes +#endif // _AFX_NO_DB_SUPPORT + +#ifndef _AFX_NO_DAO_SUPPORT +#include // MFC DAO database classes +#endif // _AFX_NO_DAO_SUPPORT + +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__694C13F1_369D_446F_992D_3F454A0993C6__INCLUDED_) diff --git a/Vst/AEffEditor.h b/Vst/AEffEditor.h new file mode 100644 index 0000000..16d5fa1 --- /dev/null +++ b/Vst/AEffEditor.h @@ -0,0 +1,44 @@ +#ifndef __AEffEditor__ +#define __AEffEditor__ + +class AudioEffect; + +struct ERect +{ + short top; + short left; + short bottom; + short right; +}; + +class AEffEditor +{ +public: + AEffEditor (AudioEffect *effect) {this->effect = effect; updateFlag = 0; } + virtual ~AEffEditor() {} + + virtual long getRect(ERect **rect) {*rect = 0; return 0;} + virtual long open(void *ptr) {systemWindow = ptr; return 0;} + virtual void close() {} + virtual void idle() { if(updateFlag) {updateFlag = 0; update();} } + +#if MAC + virtual void draw(ERect *rect) {rect = rect;} + virtual long mouse(long x, long y) {x = x; y = y; return 0;} + virtual long key(long keyCode) {keyCode = keyCode; return 0;} + virtual void top() {} + virtual void sleep() {} +#endif + virtual void update() {} + virtual void postUpdate() {updateFlag = 1;} + +protected: + AEffEditor () {}; + + AudioEffect *effect; + void *systemWindow; + long updateFlag; +}; + +#endif + diff --git a/Vst/AEffect.h b/Vst/AEffect.h new file mode 100644 index 0000000..c6c9557 --- /dev/null +++ b/Vst/AEffect.h @@ -0,0 +1,172 @@ +#ifndef __AEffect__ +#define __AEffect__ + +/* + to create an Audio Effect for power pc's, create a + code resource + file type: 'aPcs' + resource type: 'aEff' + ppc header: none (raw pef) + + for windows, it's a .dll + + the only symbol searched for is: + AEffect *main(float (*audioMaster)(AEffect *effect, long opcode, long index, + long value, void *ptr, float opt)); +*/ + +#if PRAGMA_ALIGN_SUPPORTED || __MWERKS__ + #pragma options align=mac68k +#elif defined CBUILDER + #pragma -a8 +#elif defined(WIN32) || defined(__FLAT__) + #pragma pack(push) + #pragma pack(8) +#endif + +#if defined(WIN32) || defined(__FLAT__) || defined CBUILDER + #define VSTCALLBACK __cdecl +#else + #define VSTCALLBACK +#endif + +//--------------------------------------------------------------------------------------------- +// misc def's +//--------------------------------------------------------------------------------------------- + +typedef struct AEffect AEffect; +typedef long (VSTCALLBACK *audioMasterCallback)(AEffect *effect, long opcode, long index, + long value, void *ptr, float opt); + +// prototype for plug-in main +// AEffect *main(audioMasterCallback audioMaster); + +#ifdef CBUILDER + #define kEffectMagic 'PtsV' +#else + #define kEffectMagic 'VstP' +#endif + +//--------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------- + +struct AEffect +{ + long magic; // must be kEffectMagic ('VstP') + long (VSTCALLBACK *dispatcher)(AEffect *effect, long opCode, long index, long value, + void *ptr, float opt); + void (VSTCALLBACK *process)(AEffect *effect, float **inputs, float **outputs, long sampleframes); + void (VSTCALLBACK *setParameter)(AEffect *effect, long index, float parameter); + float (VSTCALLBACK *getParameter)(AEffect *effect, long index); + + long numPrograms; + long numParams; // all programs are assumed to have numParams parameters + long numInputs; // + long numOutputs; // + long flags; // see constants + long resvd1; // reserved, must be 0 + long resvd2; // reserved, must be 0 + long initialDelay; // for algorithms which need input in the first place + long realQualities; // number of realtime qualities (0: realtime) + long offQualities; // number of offline qualities (0: realtime only) + float ioRatio; // input samplerate to output samplerate ratio, not used yet + void *object; // for class access (see AudioEffect.hpp), MUST be 0 else! + void *user; // user access + long uniqueID; // pls choose 4 character as unique as possible. + // this is used to identify an effect for save+load + long version; // + void (VSTCALLBACK *processReplacing)(AEffect *effect, float **inputs, float **outputs, long sampleframes); + char future[60]; // pls zero +}; + + +//--------------------------------------------------------------------------------------------- +// flags bits +//--------------------------------------------------------------------------------------------- + +#define effFlagsHasEditor 1 // if set, is expected to react to editor messages +#define effFlagsHasClip 2 // return > 1. in getVu() if clipped +#define effFlagsHasVu 4 // return vu value in getVu(); > 1. means clipped +#define effFlagsCanMono 8 // if numInputs == 2, makes sense to be used for mono in +#define effFlagsCanReplacing 16 // supports in place output (processReplacing() exsists) +#define effFlagsProgramChunks 32 // program data are handled in formatless chunks + +//--------------------------------------------------------------------------------------------- +// dispatcher opCodes +//--------------------------------------------------------------------------------------------- + +enum +{ + effOpen = 0, // initialise + effClose, // exit, release all memory and other resources! + + effSetProgram, // program no in + effGetProgram, // return current program no. + effSetProgramName, // user changed program name (max 24 char + 0) to as passed in string + effGetProgramName, // stuff program name (max 24 char + 0) into string + + effGetParamLabel, // stuff parameter label (max 8 char + 0) into string + // (examples: sec, dB, type) + effGetParamDisplay, // stuff parameter textual representation into string + // (examples: 0.5, -3, PLATE) + effGetParamName, // stuff parameter label (max 8 char + 0) into string + // (examples: Time, Gain, RoomType) + effGetVu, // called if (flags & (effFlagsHasClip | effFlagsHasVu)) + + // system + + effSetSampleRate, // in opt (float) + effSetBlockSize, // in value + effMainsChanged, // the user has switched the 'power on' button to + // value (0 off, else on). This only switches audio + // processing; you should flush delay buffers etc. + // editor + + effEditGetRect, // stuff rect (top, left, bottom, right) into ptr + effEditOpen, // system dependant Window pointer in ptr + effEditClose, // no arguments + effEditDraw, // draw method, ptr points to rect + effEditMouse, // index: x, value: y + effEditKey, // system keycode in value + effEditIdle, // no arguments. Be gentle! + effEditTop, // window has topped, no arguments + effEditSleep, // window goes to background + + // new + + effIdentify, // returns 'NvEf' + effGetChunk, // host requests pointer to chunk into (void**)ptr, byteSize returned + effSetChunk, // plug-in receives saved chunk, byteSize passed + + effNumOpcodes +}; + +//--------------------------------------------------------------------------------------------- +// audioMaster opCodes +//--------------------------------------------------------------------------------------------- + +enum +{ + audioMasterAutomate = 0, // index, value, returns 0 + audioMasterVersion, // vst version, currently 2 (0 for older) + audioMasterCurrentId, // returns the unique id of a plug that's currently + // loading + audioMasterIdle, // call application idle routine (this will + // call effEditIdle for all open editors too) + audioMasterPinConnected // inquire if an input or output is beeing connected; + // index enumerates input or output counting from zero, + // value is 0 for input and != 0 otherwise. note: the + // return value is 0 for such that older versions + // will always return true. + +}; + +#if PRAGMA_ALIGN_SUPPORTED || __MWERKS__ + #pragma options align=reset +#elif defined(WIN32) || defined(__FLAT__) + #pragma pack(pop) +#elif defined CBUILDER + #pragma -a- +#endif + +#endif // __AEffect__ diff --git a/Vst/AEffectx.h b/Vst/AEffectx.h new file mode 100644 index 0000000..7dfefbd --- /dev/null +++ b/Vst/AEffectx.h @@ -0,0 +1,534 @@ +#ifndef __aeffectx__ +#define __aeffectx__ + +#ifndef __AEffect__ +#include "AEffect.h" +#endif + +//------------------------------------------------------------------------------------------------------- +// VST Plug-Ins SDK +// version 2.0 extension +// (c)1999 Steinberg Soft+Hardware GmbH +//------------------------------------------------------------------------------------------------------- + +//------------------------------------------------------------------------------------------------------- +// VstEvent +//------------------------------------------------------------------------------------------------------- + +typedef struct VstEvent VstEvent; +typedef struct VstMidiEvent VstMidiEvent; +typedef struct VstEvents VstEvents; + +struct VstEvent // a generic timestamped event +{ + long type; // see enum below + long byteSize; // of this event, excl. type and byteSize + long deltaFrames; // sample frames related to the current block start sample position + long flags; // generic flags, none defined yet (0) + + char data[16]; // size may vary but is usually 16 +}; + +enum // VstEvent types +{ + kVstMidiType = 1, // midi event, can be cast as VstMidiEvent (see below) + kVstAudioType, // audio + kVstVideoType, // video + kVstParameterType, // parameter + kVstTriggerType // trigger + // ...etc +}; + +struct VstMidiEvent // to be casted from a VstEvent +{ + long type; // kVstMidiType + long byteSize; // 24 + long deltaFrames; // sample frames related to the current block start sample position + long flags; // none defined yet + + long noteLength; // (in sample frames) of entire note, if available, else 0 + long noteOffset; // offset into note from note start if available, else 0 + + char midiData[4]; // 1 thru 3 midi bytes; midiData[3] is reserved (zero) + char detune; // -64 to +63 cents; for scales other than 'well-tempered' ('microtuning') + char noteOffVelocity; + char reserved1; // zero + char reserved2; // zero +}; + +struct VstEvents // a block of events for the current audio block +{ + long numEvents; + long reserved; // zero + VstEvent* events[2]; // variable +}; + +//------------------------------------------------------------------------------------------------------- +// VstTimeInfo +//------------------------------------------------------------------------------------------------------- + +typedef struct VstTimeInfo VstTimeInfo; + +// VstTimeInfo as requested via audioMasterGetTime (getTimeInfo()) +// refers to the current time slice. note the new slice is +// already started when processEvents() is called + +struct VstTimeInfo +{ + double samplePos; // current location + double sampleRate; + double nanoSeconds; // system time + double ppqPos; // 1 ppq + double tempo; // in bpm + double barStartPos; // last bar start, in 1 ppq + double cycleStartPos; // 1 ppq + double cycleEndPos; // 1 ppq + long timeSigNumerator; // time signature + long timeSigDenominator; + long smpteOffset; + long smpteFrameRate; // 0:24, 1:25, 2:29.97, 3:30, 4:29.97 df, 5:30 df + long samplesToNextClock; // midi clock resolution (24 ppq), can be negative + long flags; // see below +}; + +enum +{ + kVstTransportChanged = 1, + kVstTransportPlaying = 1 << 1, + kVstTransportCycleActive = 1 << 2, + + kVstAutomationWriting = 1 << 6, + kVstAutomationReading = 1 << 7, + + // flags which indicate which of the fields in this VstTimeInfo + // are valid; samplePos and sampleRate are always valid + kVstNanosValid = 1 << 8, + kVstPpqPosValid = 1 << 9, + kVstTempoValid = 1 << 10, + kVstBarsValid = 1 << 11, + kVstCyclePosValid = 1 << 12, // start and end + kVstTimeSigValid = 1 << 13, + kVstSmpteValid = 1 << 14, + kVstClockValid = 1 << 15 +}; + +//------------------------------------------------------------------------------------------------------- +// VarIo +//------------------------------------------------------------------------------------------------------- + +typedef struct VstVariableIo VstVariableIo; + +struct VstVariableIo +{ + float **inputs; + float **outputs; + long numSamplesInput; + long numSamplesOutput; + long *numSamplesInputProcessed; + long *numSamplesOutputProcessed; +}; + +//--------------------------------------------------------------------------------------------- +// new audioMaster opCodes +//--------------------------------------------------------------------------------------------- + +enum +{ + // VstEvents + VstTimeInfo + audioMasterWantMidi = audioMasterPinConnected + 2, // is a filter which is currently ignored + audioMasterGetTime, // returns const VstTimeInfo* (or 0 if not supported) + // should contain a mask indicating which fields are required + // (see valid masks above), as some items may require extensive + // conversions + audioMasterProcessEvents, // VstEvents* in + audioMasterSetTime, // VstTimenfo* in , filter in , not supported + audioMasterTempoAt, // returns tempo (in bpm * 10000) at sample frame location passed in + + // parameters + audioMasterGetNumAutomatableParameters, + audioMasterGetParameterQuantization, // returns the integer value for +1.0 representation, + // or 1 if full single float precision is maintained + // in automation. parameter index in (-1: all, any) + // connections, configuration + audioMasterIOChanged, // numInputs and/or numOutputs has changed + audioMasterNeedIdle, // plug needs idle calls (outside its editor window) + audioMasterSizeWindow, // index: width, value: height + audioMasterGetSampleRate, + audioMasterGetBlockSize, + audioMasterGetInputLatency, + audioMasterGetOutputLatency, + audioMasterGetPreviousPlug, // input pin in (-1: first to come), returns cEffect* + audioMasterGetNextPlug, // output pin in (-1: first to come), returns cEffect* + + // realtime info + audioMasterWillReplaceOrAccumulate, // returns: 0: not supported, 1: replace, 2: accumulate + audioMasterGetCurrentProcessLevel, // returns: 0: not supported, + // 1: currently in user thread (gui) + // 2: currently in audio thread (where process is called) + // 3: currently in 'sequencer' thread (midi, timer etc) + // 4: currently offline processing and thus in user thread + // other: not defined, but probably pre-empting user thread. + audioMasterGetAutomationState, // returns 0: not supported, 1: off, 2:read, 3:write, 4:read/write + + // offline + audioMasterOfflineStart, + audioMasterOfflineRead, // ptr points to offline structure, see below. return 0: error, 1 ok + audioMasterOfflineWrite, // same as read + audioMasterOfflineGetCurrentPass, + audioMasterOfflineGetCurrentMetaPass, + + // other + audioMasterSetOutputSampleRate, // for variable i/o, sample rate in + audioMasterGetSpeakerArrangement, // (long)input in , output in + audioMasterGetVendorString, // fills with a string identifying the vendor (max 64 char) + audioMasterGetProductString, // fills with a string with product name (max 64 char) + audioMasterGetVendorVersion, // returns vendor-specific version + audioMasterVendorSpecific, // no definition, vendor specific handling + audioMasterSetIcon, // void* in , format not defined yet + audioMasterCanDo, // string in ptr, see below + audioMasterGetLanguage, // see enum + audioMasterOpenWindow, // returns platform specific ptr + audioMasterCloseWindow, // close window, platform specific handle in + audioMasterGetDirectory, // get plug directory, FSSpec on MAC, else char* + audioMasterUpdateDisplay // something has changed, update 'multi-fx' display +}; + +enum VstHostLanguage +{ + kVstLangEnglish = 1, + kVstLangGerman, + kVstLangFrench, + kVstLangItalian, + kVstLangSpanish, + kVstLangJapanese +}; + +//--------------------------------------------------------------------------------------------- +// dispatcher opCodes +//--------------------------------------------------------------------------------------------- + +enum +{ + // VstEvents + effProcessEvents = effSetChunk + 1, // VstEvents* in + + // parameters and programs + effCanBeAutomated, // parameter index in + effString2Parameter, // parameter index in , string in + effGetNumProgramCategories, // no arguments. this is for dividing programs into groups (like GM) + effGetProgramNameIndexed, // get program name of category , program into . + // category (that is, ) may be -1, in which case program indices + // are enumerated linearily (as usual); otherwise, each category starts + // over with index 0. + effCopyProgram, // copy current program to destination + // note: implies setParameter + // connections, configuration + effConnectInput, // input at has been (dis-)connected; + // == 0: disconnected, else connected + effConnectOutput, // same as input + effGetInputProperties, // , VstPinProperties* in ptr, return != 0 => true + effGetOutputProperties, // dto + effGetPlugCategory, // no parameter, return value is category + + // realtime + effGetCurrentPosition, // for external dsp, see flag bits below + effGetDestinationBuffer, // for external dsp, see flag bits below. returns float* + + // offline + effOfflineNotify, // ptr = VstAudioFile array, value = count, index = start flag + effOfflinePrepare, // ptr = VstOfflineTask array, value = count + effOfflineRun, // dto + + // other + effProcessVarIo, // VstVariableIo* in + effSetSpeakerArrangement, // VstSpeakerArrangement* pluginInput in + // VstSpeakerArrangement* pluginOutput in + effSetBlockSizeAndSampleRate, // block size in , sampleRate in + effSetBypass, // onOff in (0 = off) + effGetEffectName, // char* name (max 32 bytes) in + effGetErrorText, // char* text (max 256 bytes) in + effGetVendorString, // fills with a string identifying the vendor (max 64 char) + effGetProductString, // fills with a string with product name (max 64 char) + effGetVendorVersion, // returns vendor-specific version + effVendorSpecific, // no definition, vendor specific handling + effCanDo, // + effGetTailSize, // returns tail size; 0 is default (return 1 for 'no tail') + effIdle, // idle call in response to audioMasterneedIdle. must + // return 1 to keep idle calls beeing issued + + // gui + effGetIcon, // void* in , not yet defined + effSetViewPosition, // set view position (in window) to x y + + // and... + effGetParameterProperties, // of param , VstParameterProperties* in + effKeysRequired, // returns 0: needs keys (default for 1.0 plugs), 1: don't need + effGetVstVersion, // returns 2; older versions return 0 + + effNumV2Opcodes + // note that effNumOpcodes doesn't apply anymore +}; + +typedef struct VstParameterProperties VstParameterProperties; +typedef struct VstPinProperties VstPinProperties; + +struct VstParameterProperties +{ + float stepFloat; + float smallStepFloat; + float largeStepFloat; + char label[64]; + long flags; + long minInteger; + long maxInteger; + long stepInteger; + long largeStepInteger; + char shortLabel[8]; // recommended: 6 + delimiter + char future[48]; +}; + +// parameter properties flags +enum +{ + kVstParameterIsSwitch = 1 << 0, + kVstParameterUsesIntegerMinMax = 1 << 1, + kVstParameterUsesFloatStep = 1 << 2, + kVstParameterUsesIntStep = 1 << 3 +}; + +struct VstPinProperties +{ + char label[64]; + long flags; + long reserved; + char shortLabel[8]; // recommended: 6 + delimiter + char future[48]; +}; + +// pin properties flags +enum +{ + kVstPinIsActive = 1 << 0, + kVstPinIsStereo = 1 << 1 +}; + +// category +enum VstPlugCategory +{ + kPlugCategUnknown = 0, + kPlugCategEffect, + kPlugCategSynth, + kPlugCategAnalysis, + kPlugCategMastering, + kPlugCategSpacializer, // 'panners' + kPlugCategRoomFx, // delays and reverbs + kPlugSurroundFx // dedicated surround processor +}; + +//--------------------------------------------------------------------------------------------- +// flags bits +//--------------------------------------------------------------------------------------------- + +enum +{ + effFlagsIsSynth = 1 << 8, // host may assign mixer channels for its outputs + effFlagsNoSoundInStop = 1 << 9, // does not produce sound when input is all silence + effFlagsExtIsAsync = 1 << 10, // for external dsp; plug returns immedeately from process() + // host polls plug position (current block) via effGetCurrentPosition + effFlagsExtHasBuffer = 1 << 11 // external dsp, may have their own output buffe (32 bit float) + // host then requests this via effGetDestinationBuffer +}; + +//--------------------------------------------------------------------------------------------- +// surround setup +//--------------------------------------------------------------------------------------------- + +typedef struct VstSpeakerProperties VstSpeakerProperties; +typedef struct VstSpeakerArrangement VstSpeakerArrangement; + +struct VstSpeakerProperties +{ // units: range: except: + float azimuth; // rad -PI...PI 10.f for LFE channel + float elevation; // rad -PI/2...PI/2 10.f for LFE channel + float radius; // meter 0.f for LFE channel + float reserved; // 0. + char name[64]; // for new setups, new names should be given (L/R/C... won't do) + char future[32]; +}; + +// note: the origin for azimuth is right (as by math conventions dealing with radians); +// the elevation origin is also right, visualizing a rotation of a circle across the +// -pi/pi axis of the horizontal circle. thus, an elevation of -pi/2 corresponds +// to bottom, and a speaker standing on the left, and 'beaming' upwards would have +// an azimuth of -pi, and an elevation of pi/2. +// for user interface representation, grads are more likely to be used, and the +// origins will obviously 'shift' accordingly. + +struct VstSpeakerArrangement +{ + float lfeGain; // LFE channel gain is adjusted [dB] higher than other channels + long numChannels; // number of channels in this speaker arrangement + VstSpeakerProperties speakers[8]; // variable +}; + +//--------------------------------------------------------------------------------------------- +// offline +//--------------------------------------------------------------------------------------------- + +typedef struct VstOfflineTask VstOfflineTask; +typedef struct VstAudioFile VstAudioFile; +typedef struct VstAudioFileMarker VstAudioFileMarker; + +struct VstOfflineTask +{ + char processName[96]; // set by plug + + // audio access + double readPosition; // set by plug/host + double writePosition; // set by plug/host + long readCount; // set by plug/host + long writeCount; // set by plug + long sizeInputBuffer; // set by host + long sizeOutputBuffer; // set by host + void* inputBuffer; // set by host + void* outputBuffer; // set by host + double positionToProcessFrom; // set by host + double numFramesToProcess; // set by host + double maxFramesToWrite; // set by plug + + // other data access + void* extraBuffer; // set by plug + long value; // set by host or plug + long index; // set by host or plug + + // file attributes + double numFramesInSourceFile; // set by host + double sourceSampleRate; // set by host or plug + double destinationSampleRate; // set by host or plug + long numSourceChannels; // set by host or plug + long numDestinationChannels; // set by host or plug + long sourceFormat; // set by host + long destinationFormat; // set by plug + char outputText[512]; // set by plug or host + + // progress notification + double progress; // set by plug + long progressMode; // reserved for future + char progressText[100]; // set by plug + + long flags; // set by host and plug; see VstOfflineTaskFlags + long returnValue; // reserved for future + void* hostOwned; // set by host + void* plugOwned; // set by plug + + char future[1024]; +}; + +enum VstOfflineTaskFlags +{ + // set by host + kVstOfflineUnvalidParameter = 1 << 0, + kVstOfflineNewFile = 1 << 1, + + // set by plug + kVstOfflinePlugError = 1 << 10, + kVstOfflineInterleavedAudio = 1 << 11, + kVstOfflineTempOutputFile = 1 << 12, + kVstOfflineFloatOutputFile = 1 << 13, + kVstOfflineRandomWrite = 1 << 14, + kVstOfflineStretch = 1 << 15, + kVstOfflineNoThread = 1 << 16 +}; + +// option passed to offlineRead/offlineWrite + +enum VstOfflineOption +{ + kVstOfflineAudio, // reading/writing audio samples + kVstOfflinePeaks, // reading graphic representation + kVstOfflineParameter, // reading/writing parameters + kVstOfflineMarker, // reading/writing marker + kVstOfflineCursor, // reading/moving edit cursor + kVstOfflineSelection, // reading/changing selection + kVstOfflineQueryFiles // to request the host to call asynchronously offlineNotify +}; + +// structure passed to offlineNotify and offlineStart + +struct VstAudioFile +{ + long flags; // see enum VstAudioFileFlags + void* hostOwned; // any data private to host + void* plugOwned; // any data private to plugin + char name[100]; // file title + long uniqueId; // uniquely identify a file during a session + double sampleRate; // file sample rate + long numChannels; // number of channels (1 for mono, 2 for stereo...) + double numFrames; // number of frames in the audio file + long format; // reserved for future + double editCursorPosition; // -1 if no such cursor + double selectionStart; // frame index of first selected frame, or -1 + double selectionSize; // number of frames in selection, or 0 + long selectedChannelsMask; // 1 bit per channel + long numMarkers; // number of markers in the file + long timeRulerUnit; // see doc for possible values + double timeRulerOffset; // offset in time ruler (positive or negative) + double tempo; // as bpm + long timeSigNumerator; // time signature numerator + long timeSigDenominator; // time signature denominator + long ticksPerBlackNote; // resolution + long smpteFrameRate; // smpte rate (set as in VstTimeInfo) + + char future[64]; +}; + +enum VstAudioFileFlags +{ + // set by host (in call offlineNotify) + kVstOfflineReadOnly = 1 << 0, + kVstOfflineNoRateConversion = 1 << 1, + kVstOfflineNoChannelChange = 1 << 2, + + // Set by plug (in function offlineStart) + kVstOfflineCanProcessSelection = 1 << 10, + kVstOfflineNoCrossfade = 1 << 11, + kVstOfflineWantRead = 1 << 12, + kVstOfflineWantWrite = 1 << 13, + kVstOfflineWantWriteMarker = 1 << 14, + kVstOfflineWantMoveCursor = 1 << 15, + kVstOfflineWantSelect = 1 << 16 +}; + +struct VstAudioFileMarker +{ + double position; + char name[32]; + long type; + long id; + long reserved; +}; + +//--------------------------------------------------------------------------------------------- +// others +//--------------------------------------------------------------------------------------------- + +// structure passed to openWindow and closeWindow + +struct VstWindow +{ + char title[128]; // title + short xPos; // position and size + short yPos; + short width; + short height; + long style; // 0: with title, 1: without title + + void *parent; // parent of this window + void *userHandle; // reserved + void *winHandle; // reserved + + char future[104]; +}; + +#endif + diff --git a/Vst/AudioEffect.hpp b/Vst/AudioEffect.hpp new file mode 100644 index 0000000..08eb6d1 --- /dev/null +++ b/Vst/AudioEffect.hpp @@ -0,0 +1,109 @@ +#ifndef __AudioEffect__ +#define __AudioEffect__ + +#include "AEffect.h" // "c" interface +#include + +class AEffEditor; +class AudioEffect; + +// Needs to be defined by the audio effect and is +// called to create the audio effect object instance. +AudioEffect* createEffectInstance (audioMasterCallback audioMaster); + +long dispatchEffectClass(AEffect *e, + long opCode, long index, long value, void *ptr, float opt); +float getParameterClass(long index); +void setParameterClass(long index, float value); +void processClass(AEffect *e, float **inputs, float **outputs, long sampleFrames); +void processClassReplacing(AEffect *e, float **inputs, float **outputs, long sampleFrames); + +class AudioEffect +{ +friend class AEffEditor; +friend long dispatchEffectClass(AEffect *e, long opCode, long index, long value, void *ptr, float opt); +friend float getParameterClass(AEffect *e, long index); +friend void setParameterClass(AEffect *e, long index, float value); +friend void processClass(AEffect *e, float **inputs, float **outputs, long sampleFrames); +friend void processClassReplacing(AEffect *e, float **inputs, float **outputs, long sampleFrames); + +public: + AudioEffect(audioMasterCallback audioMaster, long numPrograms, long numParams); + virtual ~AudioEffect(); + + virtual void setParameter(long index, float value) {index = index; value = value;} + virtual float getParameter(long index) {index = index; return 0;} + virtual void setParameterAutomated(long index, float value); + + AEffect *getAeffect() {return &cEffect;} + void setEditor(AEffEditor *editor) + { this->editor = editor; + if(editor) cEffect.flags |= effFlagsHasEditor; + else cEffect.flags &= ~effFlagsHasEditor;} + + // called from audio master + virtual void process(float **inputs, float **outputs, long sampleFrames) = 0; + virtual void processReplacing(float **inputs, float **outputs, long sampleFrames) + {inputs = inputs; outputs = outputs; sampleFrames = sampleFrames;} + virtual long dispatcher(long opCode, long index, long value, void *ptr, float opt); + virtual void open() {} + virtual void close() {} + virtual long getProgram() {return curProgram;} + virtual void setProgram(long program) {curProgram = program;} // don't forget to set curProgram + virtual void setProgramName(char *name) {*name = 0;} // all following refer to curProgram + virtual void getProgramName(char *name) {*name = 0;} + virtual void getParameterLabel(long index, char *label) {index = index; *label = 0;} + virtual void getParameterDisplay(long index, char *text) {index = index; *text = 0;} + virtual void getParameterName(long index, char *text) {index = index; *text = 0;} + virtual float getVu() {return 0;} + virtual long getChunk(void** data, bool isPreset = false) {return 0;} // returns byteSize + virtual long setChunk(void* data, long byteSize, bool isPreset = false) {return 0;} + virtual void setSampleRate(float sampleRate) {this->sampleRate = sampleRate;} + virtual void setBlockSize(long blockSize) {this->blockSize = blockSize;} + virtual void suspend() {} + virtual void resume() {} + + // setup + virtual void setUniqueID(long iD) {cEffect.uniqueID = iD;} // must call this! + virtual void setNumInputs(long inputs) {cEffect.numInputs = inputs;} + virtual void setNumOutputs(long outputs) {cEffect.numOutputs = outputs;} + virtual void hasVu(bool state = true); + virtual void hasClip(bool state = true); + virtual void canMono(bool state = true); + virtual void canProcessReplacing(bool state = true); + virtual void programsAreChunks(bool state = true); + virtual void setRealtimeQualities(long qualities); + virtual void setOfflineQualities(long qualities); + virtual void setInitialDelay(long delay); + + // inquiry + virtual float getSampleRate() {return sampleRate;} + virtual long getBlockSize() {return blockSize;} + + // host communication + virtual long getMasterVersion(); + virtual long getCurrentUniqueId(); + virtual void masterIdle(); + virtual bool isInputConnected(long input); + virtual bool isOutputConnected(long output); + + // tools + virtual void dB2string(float value, char *text); + virtual void Hz2string(float samples, char *text); + virtual void ms2string(float samples, char *text); + virtual void float2string(float value, char *string); + virtual void long2string(long value, char *text); + +protected: + // members + float sampleRate; + AEffEditor *editor; + audioMasterCallback audioMaster; + long numPrograms; + long numParams; + long curProgram; + long blockSize; + AEffect cEffect; +}; + +#endif diff --git a/Vst/audioeffectx.h b/Vst/audioeffectx.h new file mode 100644 index 0000000..435a63e --- /dev/null +++ b/Vst/audioeffectx.h @@ -0,0 +1,185 @@ +#ifndef __audioeffectx__ +#define __audioeffectx__ + +//---------------------------------------------------------------------------------------------------------------------------- +// VST Plug-Ins SDK +// version 2.0 extension +// (c)1999 Steinberg Soft+Hardware GmbH +//---------------------------------------------------------------------------------------------------------------------------- + +#ifndef __AudioEffect__ +#include "AudioEffect.hpp" // version 1.0 base class AudioEffect +#endif + +#ifndef __aeffectx__ +#include "aeffectx.h" // version 2.0 'C' extensions and structures +#endif + +//---------------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------------- +// AudioEffectX extends AudioEffect with the new features. so you should derive +// your plug from AudioEffectX +//---------------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------------- + +class AudioEffectX : public AudioEffect +{ +public: + AudioEffectX (audioMasterCallback audioMaster, long numPrograms, long numParams); + virtual ~AudioEffectX (); + + virtual long dispatcher (long opCode, long index, long value, void *ptr, float opt); + + // 'host' are methods which go from plug to host, and are usually not overridden + // 'plug' are methods which you may override to implement the according functionality (to host) + +//---------------------------------------------------------------------------------------------------------------------------- +// events + time +//---------------------------------------------------------------------------------------------------------------------------- + + // host + virtual void wantEvents (long filter = 1); // filter is currently ignored, midi channel data only (default) + virtual VstTimeInfo* getTimeInfo (long filter); + // returns const VstTimeInfo* (or 0 if not supported) + // filter should contain a mask indicating which fields are requested + // (see valid masks in aeffectx.h), as some items may require extensive + // conversions + virtual long tempoAt (long pos); // returns tempo (in bpm * 10000) at sample frame location + bool sendVstEventsToHost (VstEvents* events); // true:success + + // plug + virtual long processEvents (VstEvents* events) {return 0;} // wants no more...else return 1! + // VstEvents and VstMidiEvents are declared in aeffectx.h + +//---------------------------------------------------------------------------------------------------------------------------- +// parameters and programs +//---------------------------------------------------------------------------------------------------------------------------- + + // host + virtual long getNumAutomatableParameters (); + virtual long getParameterQuantization (); // returns the integer value for +1.0 representation, + // or 1 if full single float precision is maintained + // in automation. parameter index in (-1: all, any) + // plug + virtual bool canParameterBeAutomated (long index) { return true; } + virtual bool string2parameter (long index, char* text) {return false;} // note: implies setParameter. text==0 is to be + // expected to check the capability (returns true). + virtual float getChannelParameter (long channel, long index) {return 0;} + virtual long getNumCategories () {return 1L;} + virtual bool getProgramNameIndexed (long category, long index, char* text) {return false;} + virtual bool copyProgram (long destination) {return false;} + +//---------------------------------------------------------------------------------------------------------------------------- +// connections, configuration +//---------------------------------------------------------------------------------------------------------------------------- + + // host + virtual bool ioChanged (); // tell host numInputs and/or numOutputs and/or numParameters has changed + virtual bool needIdle (); // plug needs idle calls (outside its editor window) + virtual bool sizeWindow (long width, long height); + virtual double updateSampleRate (); // gets and returns sample rate from host (may issue setSampleRate() ) + virtual long updateBlockSize (); // same for block size + virtual long getInputLatency (); + virtual long getOutputLatency (); + virtual AEffect* getPreviousPlug (long input); // input can be -1 in which case the first found is returned + virtual AEffect* getNextPlug (long output); // output can be -1 in which case the first found is returned + + // plug + virtual void inputConnected (long index, bool state) {} // input at has been (dis-)connected, + virtual void outputConnected (long index, bool state) {} // same as input; state == true: connected + virtual bool getInputProperties (long index, VstPinProperties* properties) {return false;} + virtual bool getOutputProperties (long index, VstPinProperties* properties) {return false;} + virtual VstPlugCategory getPlugCategory() + { if (cEffect.flags & effFlagsIsSynth) return kPlugCategSynth; return kPlugCategUnknown; } + +//---------------------------------------------------------------------------------------------------------------------------- +// realtime +//---------------------------------------------------------------------------------------------------------------------------- + + // host + virtual long willProcessReplacing (); // returns 0: not implemented, 1: replacing, 2: accumulating + virtual long getCurrentProcessLevel (); // returns: 0: not supported, + // 1: currently in user thread (gui) + // 2: currently in audio thread or irq (where process is called) + // 3: currently in 'sequencer' thread or irq (midi, timer etc) + // 4: currently offline processing and thus in user thread + // other: not defined, but probably pre-empting user thread. + virtual long getAutomationState (); // returns 0: not supported, 1: off, 2:read, 3:write, 4:read/write + virtual void wantAsyncOperation (bool state = true); // notify host that we want to operate asynchronously. + // process() will return immedeately; host will poll getCurrentPosition + // to see if data are available in time. + virtual void hasExternalBuffer (bool state = true); // external dsp, may have their own output buffe (32 bit float) + // host then requests this via effGetDestinationBuffer + + // plug + virtual long reportCurrentPosition () {return 0;} // for external dsp, see wantAsyncOperation () + virtual float* reportDestinationBuffer () {return 0;} // for external dsp (dma option) + +//---------------------------------------------------------------------------------------------------------------------------- +// offline +//---------------------------------------------------------------------------------------------------------------------------- + + // host + virtual bool offlineRead (VstOfflineTask* offline, VstOfflineOption option, bool readSource = true); + virtual bool offlineWrite (VstOfflineTask* offline, VstOfflineOption option); + virtual bool offlineStart (VstAudioFile* ptr, long numAudioFiles, long numNewAudioFiles); + virtual long offlineGetCurrentPass (); + virtual long offlineGetCurrentMetaPass (); + + // plug + virtual bool offlineNotify (VstAudioFile* ptr, long numAudioFiles, bool start) { return false; } + virtual bool offlinePrepare (VstOfflineTask* offline, long count) {return false;} + virtual bool offlineRun (VstOfflineTask* offline, long count) {return false;} + + virtual long offlineGetNumPasses () {return 0;} + virtual long offlineGetNumMetaPasses () {return 0;} + +//---------------------------------------------------------------------------------------------------------------------------- +// other +//---------------------------------------------------------------------------------------------------------------------------- + + // host + virtual void setOutputSamplerate (float samplerate); + virtual bool getSpeakerArrangement (VstSpeakerArrangement* pluginInput, VstSpeakerArrangement* pluginOutput); + virtual bool getHostVendorString (char* text); // fills with a string identifying the vendor (max 64 char) + virtual bool getHostProductString (char* text); // fills with a string with product name (max 64 char) + virtual long getHostVendorVersion (); // returns vendor-specific version + virtual long hostVendorSpecific (long lArg1, long lArg2, void* ptrArg, float floatArg); // no definition + virtual long canHostDo (char* text); // see 'hostCanDos' in audioeffectx.cpp + // returns 0: don't know (default), 1: yes, -1: no + virtual void isSynth (bool state = true); // will call wantEvents if true + virtual void noTail (bool state = true); // true: tells host we produce no output when silence comes in + // enables host to omit process() when no data are present + // on any one input. + virtual long getHostLanguage (); // returns VstHostLanguage + virtual void* openWindow (VstWindow*); // create new window + virtual bool closeWindow (VstWindow*); // close a newly created window + virtual void* getDirectory (); // get the plug's directory, FSSpec on mac, else char* + virtual bool updateDisplay(); // something has changed, update 'multi-fx' display + // returns true if supported + + // plug + virtual bool processVariableIo (VstVariableIo* varIo) {return false;} + virtual bool setSpeakerArrangement (VstSpeakerArrangement* pluginInput, VstSpeakerArrangement* pluginOutput) {return false;} + virtual void setBlockSizeAndSampleRate (long blockSize, float sampleRate) + {this->blockSize = blockSize; this->sampleRate = sampleRate;} + virtual bool setBypass(bool onOff) {return false;} // for 'soft-bypass; process() still called + virtual bool getEffectName (char* name) {return false;} // name max 32 char + virtual bool getErrorText (char* text) {return false;} // max 256 char + virtual bool getVendorString (char* text) {return false;} // fill text with a string identifying the vendor (max 64 char) + virtual bool getProductString (char* text) {return false;} // fill text with a string identifying the product name (max 64 char) // fills with a string with product name (max 64 char) + virtual long getVendorVersion () {return 0;} // return vendor-specific version + virtual long vendorSpecific (long lArg, long lArg2, void* ptrArg, float floatArg) {return 0;} + // no definition, vendor specific handling + virtual long canDo (char* text) {return 0;} // see 'plugCanDos' in audioeffectx.cpp. return values: + // 0: don't know (default), 1: yes, -1: no + virtual void* getIcon () {return 0;} // not yet defined + virtual bool setViewPosition (long x, long y) {return false;} + virtual long getGetTailSize () {return 0; } + virtual long fxIdle () {return 0;} + virtual bool getParameterProperties (long index, VstParameterProperties* p) {return false;} + virtual bool keysRequired () {return false;} // version 1 plugs will return true + virtual long getVstVersion () {return 2;} +}; + +#endif diff --git a/VstHost.cpp b/VstHost.cpp new file mode 100644 index 0000000..d93f7f9 --- /dev/null +++ b/VstHost.cpp @@ -0,0 +1,581 @@ +#include "stdafx.h" +#include "m_pd.h" +#include "EditorThread.h" +#include "VstHost.h" +#include "PopupWindow.h" +#include "vst\aeffeditor.h" +#include "vst\aeffectx.h" + + +VstTimeInfo VSTPlugin::_timeInfo; + +float VSTPlugin::sample_rate = 44100; + + +//////////////////// +// +///////////////////// +VSTPlugin::VSTPlugin() +{ + queue_size=0; + _sDllName = NULL; + h_dll=NULL; + instantiated=false; // Constructin' with no instance + overwrite = false; + w = GetForegroundWindow(); + show_params = false; + _midichannel = 0; + edited = false; +} + +VSTPlugin::~VSTPlugin() +{ + Free(); // Call free + delete _sDllName; // if _sDllName = NULL , the operation does nothing -> it's safe. +} + +int VSTPlugin::Instance( const char *dllname) +{ + h_dll=LoadLibrary(dllname); + + if(h_dll==NULL) + { + return VSTINSTANCE_ERR_NO_VALID_FILE; + } + post("Loaded library %s" , dllname); + PVSTMAIN main = (PVSTMAIN)GetProcAddress(h_dll,"main"); + if(!main) + { + FreeLibrary(h_dll); + _pEffect=NULL; + instantiated=false; + return VSTINSTANCE_ERR_NO_VST_PLUGIN; + } + //post("Found main function - about to call it"); + //This calls the "main" function and receives the pointer to the AEffect structure. + _pEffect = main((audioMasterCallback)&(this->Master)); + + if(!_pEffect) + { + post("VST plugin : unable to create effect"); + FreeLibrary(h_dll); + _pEffect=NULL; + instantiated=false; + return VSTINSTANCE_ERR_REJECTED; + } + + if( _pEffect->magic!=kEffectMagic) + { + post("VST plugin : Instance query rejected by 0x%.8X\n",(int)_pEffect); + FreeLibrary(h_dll); + _pEffect=NULL; + instantiated=false; + return VSTINSTANCE_ERR_REJECTED; + } + + //post("VST plugin : Instanced at (Effect*): %.8X\n",(int)_pEffect); + + //init plugin + _pEffect->user = this; + Dispatch( effOpen , 0, 0, NULL, 0.0f); + Dispatch( effSetProgram , 0, 0, NULL, 0.0f); +// Dispatch( effMainsChanged, 0, 1, NULL, 0.0f); + + //************************************set samplerate and stream size here + // we get it when we init our DSP + +// Dispatch( effSetSampleRate, 0, 0, NULL, (float)Global::pConfig->_pOutputDriver->_samplesPerSec); +// Dispatch( effSetBlockSize, 0, STREAM_SIZE, NULL, 0.0f); + + + if (!Dispatch( effGetProductString, 0, 0, &_sProductName, 0.0f)) + { + CString str1(dllname); + CString str2 = str1.Mid(str1.ReverseFind('\\')+1); + int snip = str2.Find('.'); + if ( snip != -1 ) + { + str1 = str2.Left( snip ); + } + else + { + str1 = str2; + } + strcpy(_sProductName,str1); + + } + + if (!_pEffect->dispatcher(_pEffect, effGetVendorString, 0, 0, &_sVendorName, 0.0f)) + { + strcpy(_sVendorName, "Unknown vendor"); + } + _version = _pEffect->version; + _isSynth = (_pEffect->flags & effFlagsIsSynth)?true:false; + overwrite = (_pEffect->flags & effFlagsCanReplacing)?true:false; + editor = (_pEffect->flags & effFlagsHasEditor)?true:false; + + if ( _sDllName != NULL ) delete _sDllName; + _sDllName = new char[strlen(dllname)+1]; + sprintf(_sDllName,dllname); + + + + + //keep plugin name + instantiated=true; + + return VSTINSTANCE_NO_ERROR; +} + +int VSTPlugin::getNumInputs( void ) +{ + return _pEffect->numInputs; +} + +int VSTPlugin::getNumOutputs( void ) +{ + return _pEffect->numOutputs; +} + + +void VSTPlugin::Create(VSTPlugin *plug) +{ + h_dll=plug->h_dll; + _pEffect=plug->_pEffect; + _pEffect->user=this; + Dispatch( effMainsChanged, 0, 1, NULL, 0.0f); +// strcpy(_editName,plug->_editName); On current implementation, this replaces the right one. + strcpy(_sProductName,plug->_sProductName); + strcpy(_sVendorName,plug->_sVendorName); + + _sDllName = new char[strlen(plug->_sDllName)+1]; + strcpy(_sDllName,plug->_sDllName); + + _isSynth=plug->_isSynth; + _version=plug->_version; + + plug->instantiated=false; // We are "stoling" the plugin from the "plug" object so this + // is just a "trick" so that when destructing the "plug", it + // doesn't unload the Dll. + instantiated=true; +} + +void VSTPlugin::Free() // Called also in destruction +{ + if(instantiated) + { + instantiated=false; + post("VST plugin : Free query 0x%.8X\n",(int)_pEffect); + _pEffect->user = NULL; + Dispatch( effMainsChanged, 0, 0, NULL, 0.0f); + Dispatch( effClose, 0, 0, NULL, 0.0f); +// delete _pEffect; // <- Should check for the necessity of this command. + _pEffect=NULL; + FreeLibrary(h_dll); + } +} + +void VSTPlugin::Init( float samplerate , float blocksize ) +{ + sample_rate = samplerate; + Dispatch(effOpen , 0, 0, NULL, 0.f); + Dispatch(effMainsChanged, 0, 1, NULL, 0.f); + Dispatch(effSetSampleRate, 0, 0, 0, (float) sample_rate ); + Dispatch(effSetBlockSize, 0, blocksize, NULL, 0.f ); +} + + +bool VSTPlugin::DescribeValue(int p,char* psTxt) +{ + int parameter = p; + if(instantiated) + { + if(parameter<_pEffect->numParams) + { +// char par_name[64]; + char par_display[64]; + char par_label[64]; + +// Dispatch(effGetParamName,parameter,0,par_name,0.0f); + Dispatch(effGetParamDisplay,parameter,0,par_display,0.0f); + Dispatch(effGetParamLabel,parameter,0,par_label,0.0f); +// sprintf(psTxt,"%s:%s%s",par_name,par_display,par_label); + sprintf(psTxt,"%s%s",par_display,par_label); + return true; + } + else sprintf(psTxt,"NumParams Exeeded"); + } + else sprintf(psTxt,"Not loaded"); + + return false; +} + +bool VSTPlugin::SetParameter(int parameter, float value) +{ + if(instantiated) + { + if (( parameter >= 0 ) && (parameter<=_pEffect->numParams)) + { + _pEffect->setParameter(_pEffect,parameter,value); + return true; + } + } + + return false; +} + +bool VSTPlugin::SetParameter(int parameter, int value) +{ + return SetParameter(parameter,value/65535.0f); +} + +int VSTPlugin::GetCurrentProgram() +{ + if(instantiated) + return Dispatch(effGetProgram,0,0,NULL,0.0f); + else + return 0; +} + +void VSTPlugin::SetCurrentProgram(int prg) +{ + if(instantiated) + Dispatch(effSetProgram,0,prg,NULL,0.0f); +} + +bool VSTPlugin::AddMIDI(unsigned char data0,unsigned char data1,unsigned char data2) +{ + if (instantiated) + { + VstMidiEvent* pevent=&midievent[queue_size]; + + pevent->type = kVstMidiType; + pevent->byteSize = 24; + pevent->deltaFrames = 0; + pevent->flags = 0; + pevent->detune = 0; + pevent->noteLength = 0; + pevent->noteOffset = 0; + pevent->reserved1 = 0; + pevent->reserved2 = 0; + pevent->noteOffVelocity = 0; + pevent->midiData[0] = data0; + pevent->midiData[1] = data1; + pevent->midiData[2] = data2; + pevent->midiData[3] = 0; + + if ( queue_size < MAX_EVENTS ) queue_size++; + SendMidi(); + return true; + } + else return false; +} + + +void VSTPlugin::SendMidi() +{ + if(/*instantiated &&*/ queue_size>0) + { + // Prepare MIDI events and free queue dispatching all events + events.numEvents = queue_size; + events.reserved = 0; + for(int q=0;qprocessReplacing( _pEffect , inputs , outputs , sampleframes ); + +} + +void VSTPlugin::process( float **inputs, float **outputs, long sampleframes ) +{ + _pEffect->process( _pEffect , inputs , outputs , sampleframes ); +} + + +// Host callback dispatcher +long VSTPlugin::Master(AEffect *effect, long opcode, long index, long value, void *ptr, float opt) +{ + //post("VST plugin call to host dispatcher: Eff: 0x%.8X, Opcode = %d, Index = %d, Value = %d, PTR = %.8X, OPT = %.3f\n",(int)effect, opcode,index,value,(int)ptr,opt); + //st( "audioMasterWantMidi %d " , audioMasterWantMidi); + + // Support opcodes + switch(opcode) + { + case audioMasterAutomate: + return 0; // index, value, returns 0 + + case audioMasterVersion: + return 9; // vst version, currently 7 (0 for older) + + case audioMasterCurrentId: + return 'AASH'; // returns the unique id of a plug that's currently loading + + case audioMasterIdle: + effect->dispatcher(effect, effEditIdle, 0, 0, NULL, 0.0f); + return 0; // call application idle routine (this will call effEditIdle for all open editors too) + + case audioMasterPinConnected: + return false; // inquire if an input or output is beeing connected; + + case audioMasterWantMidi: + return 0; + + case audioMasterProcessEvents: + return 0; // Support of vst events to host is not available + + case audioMasterGetTime: + memset(&_timeInfo, 0, sizeof(_timeInfo)); + _timeInfo.samplePos = 0; + _timeInfo.sampleRate = sample_rate; + return (long)&_timeInfo; + + + case audioMasterTempoAt: + return 0; + + case audioMasterNeedIdle: + effect->dispatcher(effect, effIdle, 0, 0, NULL, 0.0f); + return 1; + + case audioMasterGetSampleRate: + return sample_rate; + + case audioMasterGetVendorString: // Just fooling version string + strcpy((char*)ptr,"Steinberg"); + return 0; + + case audioMasterGetVendorVersion: + return 5000; // HOST version 5000 + + case audioMasterGetProductString: // Just fooling product string + strcpy((char*)ptr,"Cubase 5.0"); + return 0; + + case audioMasterVendorSpecific: + { + return 0; + } + + + case audioMasterGetLanguage: + return kVstLangEnglish; + + case audioMasterUpdateDisplay: + post("audioMasterUpdateDisplay"); + effect->dispatcher(effect, effEditIdle, 0, 0, NULL, 0.0f); + return 0; + + + case audioMasterSetTime: post("VST master dispatcher: Set Time");break; + case audioMasterGetNumAutomatableParameters: post("VST master dispatcher: GetNumAutPar");break; + case audioMasterGetParameterQuantization: post("VST master dispatcher: ParamQuant");break; + case audioMasterIOChanged: post("VST master dispatcher: IOchanged");break; + case audioMasterSizeWindow: post("VST master dispatcher: Size Window");break; + case audioMasterGetBlockSize: post("VST master dispatcher: GetBlockSize");break; + case audioMasterGetInputLatency: post("VST master dispatcher: GetInLatency");break; + case audioMasterGetOutputLatency: post("VST master dispatcher: GetOutLatency");break; + case audioMasterGetPreviousPlug: post("VST master dispatcher: PrevPlug");break; + case audioMasterGetNextPlug: post("VST master dispatcher: NextPlug");break; + case audioMasterWillReplaceOrAccumulate: post("VST master dispatcher: WillReplace"); break; + case audioMasterGetCurrentProcessLevel: return 0; break; + case audioMasterGetAutomationState: post("VST master dispatcher: GetAutState");break; + case audioMasterOfflineStart: post("VST master dispatcher: Offlinestart");break; + case audioMasterOfflineRead: post("VST master dispatcher: Offlineread");break; + case audioMasterOfflineWrite: post("VST master dispatcher: Offlinewrite");break; + case audioMasterOfflineGetCurrentPass: post("VST master dispatcher: OfflineGetcurrentpass");break; + case audioMasterOfflineGetCurrentMetaPass: post("VST master dispatcher: GetGetCurrentMetapass");break; + case audioMasterSetOutputSampleRate: post("VST master dispatcher: Setsamplerate");break; + case audioMasterGetSpeakerArrangement: post("VST master dispatcher: Getspeaker");break; + case audioMasterSetIcon: post("VST master dispatcher: seticon");break; + case audioMasterCanDo: post("VST master dispatcher: Can Do");break; + case audioMasterOpenWindow: post("VST master dispatcher: OpenWindow");break; + case audioMasterCloseWindow: post("VST master dispatcher: CloseWindow");break; + case audioMasterGetDirectory: post("VST master dispatcher: GetDirectory");break; +// case audioMasterUpdateDisplay: post("VST master dispatcher: audioMasterUpdateDisplay");break; + + default: post("VST master dispatcher: undefed: %d , %d",opcode , effKeysRequired ) ;break; + } + + + return 0; +} + +bool VSTPlugin::AddNoteOn( unsigned char note,unsigned char speed,unsigned char midichannel) +{ + if(instantiated) + { + VstMidiEvent* pevent=&midievent[queue_size]; + + pevent->type = kVstMidiType; + pevent->byteSize = 24; + pevent->deltaFrames = 0; + pevent->flags = 0; + pevent->detune = 0; + pevent->noteLength = 0; + pevent->noteOffset = 0; + pevent->reserved1 = 0; + pevent->reserved2 = 0; + pevent->noteOffVelocity = 0; + pevent->midiData[0] = (char)MIDI_NOTEON | midichannel; // Midi On + pevent->midiData[1] = note; + pevent->midiData[2] = speed; + pevent->midiData[3] = 0; + + if ( queue_size < MAX_EVENTS ) queue_size++; + SendMidi(); + return true; + } + else return false; + + +} + +bool VSTPlugin::AddNoteOff( unsigned char note,unsigned char midichannel) +{ + if (instantiated) + { + + VstMidiEvent* pevent=&midievent[queue_size]; + + pevent->type = kVstMidiType; + pevent->byteSize = 24; + pevent->deltaFrames = 0; + pevent->flags = 0; + pevent->detune = 0; + pevent->noteLength = 0; + pevent->noteOffset = 0; + pevent->reserved1 = 0; + pevent->reserved2 = 0; + pevent->noteOffVelocity = 0; + pevent->midiData[0] = (char)MIDI_NOTEOFF | midichannel; // Midi Off + pevent->midiData[1] = note; + pevent->midiData[2] = 0; + pevent->midiData[3] = 0; + + if ( queue_size < MAX_EVENTS ) queue_size++; + + SendMidi(); + return true; + + } + else return false; +} + + +bool VSTPlugin::replace() +{ + return overwrite; +} + + +void VSTPlugin::edit() +{ + if(instantiated) + { + if ( ( editor ) && (!edited)) + { + edited = true; + //b = (CEditorThread*) AfxBeginThread(RUNTIME_CLASS( CEditorThread ) ); + b = new CEditorThread(); + b->SetPlugin( this ); + b->CreateThread(); + } + } +} + +void VSTPlugin::EditorIdle() +{ + Dispatch(effEditIdle,0,0, w,0.0f); +} + +RECT VSTPlugin::GetEditorRect() +{ + RECT ret; + ERect *r; + Dispatch(effEditGetRect,0,0, &r,0.0f); + ret.top = r->top; + ret.bottom = r->bottom; + ret.left = r->left; + ret.right = r->right; + return ret; +} + +void VSTPlugin::SetEditWindow(HWND h) +{ + w = h; + Dispatch(effEditOpen,0,0, w,0.0f); +} + +void VSTPlugin::OnEditorCLose() +{ + Dispatch(effEditClose,0,0, w,0.0f); +} + +void VSTPlugin::SetShowParameters(bool s) +{ + show_params = s; +} + +bool VSTPlugin::ShowParams() +{ + return show_params; +} + +void VSTPlugin::AddAftertouch(int value) +{ + if (value < 0) value = 0; else if (value > 127) value = 127; + AddMIDI( (char)MIDI_NOTEOFF | _midichannel , value ); +} + +void VSTPlugin::AddPitchBend(int value) +{ + AddMIDI( MIDI_PITCHBEND + (_midichannel & 0xf) , ((value>>7) & 127), (value & 127)); +} + +void VSTPlugin::AddProgramChange(int value) +{ + if (value < 0) value = 0; else if (value > 127) value = 127; + AddMIDI( MIDI_PROGRAMCHANGE + (_midichannel & 0xf), value, 0); +} + +void VSTPlugin::AddControlChange(int control, int value) +{ + if (control < 0) control = 0; else if (control > 127) control = 127; + if (value < 0) value = 0; else if (value > 127) value = 127; + AddMIDI( MIDI_CONTROLCHANGE + (_midichannel & 0xf), control, value); +} + + +bool VSTPlugin::GetProgramName( int cat , int p, char *buf) +{ + int parameter = p; + if(instantiated) + { + if(parameter +#define MAX_EVENTS 64 +#define MAX_INOUTS 8 + +#define VSTINSTANCE_ERR_NO_VALID_FILE -1 +#define VSTINSTANCE_ERR_NO_VST_PLUGIN -2 +#define VSTINSTANCE_ERR_REJECTED -3 +#define VSTINSTANCE_NO_ERROR 0 + +#define MIDI_NOTEON 144 +#define MIDI_NOTEOFF 128 +#define MIDI_POLYAFTERTOUCH 160 +#define MIDI_CONTROLCHANGE 176 +#define MIDI_PROGRAMCHANGE 192 +#define MIDI_AFTERTOUCH 208 +#define MIDI_PITCHBEND 224 + +typedef AEffect* (*PVSTMAIN)(audioMasterCallback audioMaster); +typedef HWND (*POPWIN)(void); +typedef HWND (*GETWIN)(void); + +class VSTPlugin +{ +public: + void StopEditing(); + int GetNumCategories(); + bool GetProgramName( int cat, int p , char* buf); + void AddControlChange( int control , int value ); + void AddProgramChange( int value ); + void AddPitchBend( int value ); + void AddAftertouch( int value ); + bool editor; + bool ShowParams(); + void SetShowParameters( bool s); + void OnEditorCLose(); + void SetEditWindow( HWND h ); + CEditorThread* b; + RECT GetEditorRect(); + void EditorIdle(); + void edit(void); + bool replace( ); + VSTPlugin(); + ~VSTPlugin(); + + void Free(); + int Instance( const char *dllname); + void Create(VSTPlugin *plug); + void Init( float samplerate , float blocksize ); + + virtual int GetNumParams(void) { return _pEffect->numParams; } + virtual void GetParamName(int numparam,char* name) + { + if ( numparam < _pEffect->numParams ) Dispatch(effGetParamName,numparam,0,name,0.0f); + else strcpy(name,"Out of Range"); + + } + virtual void GetParamValue(int numparam,char* parval) + { + if ( numparam < _pEffect->numParams ) DescribeValue(numparam,parval); + else strcpy(parval,"Out of Range"); + } + virtual float GetParamValue(int numparam) + { + if ( numparam < _pEffect->numParams ) return (_pEffect->getParameter(_pEffect, numparam)); + else return -1.0; + } + + int getNumInputs( void ); + int getNumOutputs( void ); + + virtual char* GetName(void) { return _sProductName; } + unsigned long GetVersion() { return _version; } + char* GetVendorName(void) { return _sVendorName; } + char* GetDllName(void) { return _sDllName; } + + long NumParameters(void) { return _pEffect->numParams; } + float GetParameter(long parameter) { return _pEffect->getParameter(_pEffect, parameter); } + bool DescribeValue(int parameter,char* psTxt); + bool SetParameter(int parameter, float value); + bool SetParameter(int parameter, int value); + void SetCurrentProgram(int prg); + int GetCurrentProgram(); + int NumPrograms() { return _pEffect->numPrograms; } + bool IsSynth() { return _isSynth; } + + bool AddMIDI(unsigned char data0,unsigned char data1=0,unsigned char data2=0); + void SendMidi(); + + + void processReplacing( float **inputs, float **outputs, long sampleframes ); + void process( float **inputs, float **outputs, long sampleframes ); + + AEffect *_pEffect; + long Dispatch(long opCode, long index, long value, void *ptr, float opt) + { + return _pEffect->dispatcher(_pEffect, opCode, index, value, ptr, opt); + } + + static long Master(AEffect *effect, long opcode, long index, long value, void *ptr, float opt); + + bool AddNoteOn( unsigned char note,unsigned char speed,unsigned char midichannel=0); + bool AddNoteOff( unsigned char note,unsigned char midichannel=0); + + + char _midichannel; + bool instantiated; + int _instance; // Remove when Changing the FileFormat. + + HWND w; + +protected: + + HMODULE h_dll; + HMODULE h_winddll; + + char _sProductName[64]; + char _sVendorName[64]; + char *_sDllName; // Contains dll name + ULONG _version; + bool _isSynth; + + float * inputs[MAX_INOUTS]; + float * outputs[MAX_INOUTS]; + float junk[256]; + + static VstTimeInfo _timeInfo; + VstMidiEvent midievent[MAX_EVENTS]; + VstEvents events; + int queue_size; + bool overwrite; + + + +private: + bool edited; + bool show_params; + static float sample_rate; +}; + + +#endif // _VSTPLUGIN_HOST \ No newline at end of file diff --git a/crazy.pd b/crazy.pd new file mode 100644 index 0000000..370149f --- /dev/null +++ b/crazy.pd @@ -0,0 +1,16 @@ +#N canvas 297 500 460 310 12; +#X msg 152 115 print; +#X floatatom 236 37 5 0 0; +#X obj 243 129 makenote 100 1000; +#X obj 211 260 dac~; +#X obj 190 198 vst~ craxzy diamonds; +#X floatatom 363 29 5 0 0; +#X msg 96 140 edit; +#X connect 0 0 4 0; +#X connect 1 0 2 0; +#X connect 2 0 4 1; +#X connect 2 1 4 2; +#X connect 4 1 3 0; +#X connect 4 2 3 1; +#X connect 5 0 2 2; +#X connect 6 0 4 0; diff --git a/export.h b/export.h new file mode 100644 index 0000000..404bec1 --- /dev/null +++ b/export.h @@ -0,0 +1,9 @@ +#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus) +extern "C" { +#endif + + __declspec(dllexport) void vst_setup( void ); + +#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus) +} +#endif diff --git a/neontest.pd b/neontest.pd new file mode 100644 index 0000000..c1e0544 --- /dev/null +++ b/neontest.pd @@ -0,0 +1,14 @@ +#N canvas 297 500 458 308 12; +#X msg 152 115 print; +#X floatatom 235 37 5 0 0; +#X obj 189 196 vst~ pro-52; +#X obj 243 129 makenote 100 1000; +#X obj 211 260 dac~; +#X msg 89 138 edit; +#X connect 0 0 2 0; +#X connect 1 0 3 0; +#X connect 2 1 4 0; +#X connect 2 2 4 1; +#X connect 3 0 2 1; +#X connect 3 1 2 2; +#X connect 5 0 2 0; diff --git a/res/vst.rc2 b/res/vst.rc2 new file mode 100644 index 0000000..a87ea63 --- /dev/null +++ b/res/vst.rc2 @@ -0,0 +1,13 @@ +// +// VST.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/vst.aps b/vst.aps new file mode 100644 index 0000000..4b2a9e2 Binary files /dev/null and b/vst.aps differ diff --git a/vst.clw b/vst.clw new file mode 100644 index 0000000..5e1b73f --- /dev/null +++ b/vst.clw @@ -0,0 +1,37 @@ +; CLW file contains information for the MFC ClassWizard + +[General Info] +Version=1 +ClassCount=3 +Class1=CVstApp +LastClass=CPopupWindow +NewFileInclude2=#include "vst.h" +ResourceCount=0 +NewFileInclude1=#include "stdafx.h" +Class2=CEditorThread +LastTemplate=CFrameWnd +Class3=CPopupWindow + +[CLS:CVstApp] +Type=0 +HeaderFile=vst.h +ImplementationFile=vst.cpp +Filter=N + +[CLS:CEditorThread] +Type=0 +HeaderFile=EditorThread.h +ImplementationFile=EditorThread.cpp +BaseClass=CWinThread +Filter=N +LastObject=CEditorThread + +[CLS:CPopupWindow] +Type=0 +HeaderFile=PopupWindow.h +ImplementationFile=PopupWindow.cpp +BaseClass=CFrameWnd +Filter=T +VirtualFilter=fWC +LastObject=CPopupWindow + diff --git a/vst.cpp b/vst.cpp new file mode 100644 index 0000000..e5bda65 --- /dev/null +++ b/vst.cpp @@ -0,0 +1,111 @@ +// vst.cpp : Defines the initialization routines for the DLL. +// + +#include "stdafx.h" +#include "vst.h" +#include "m_pd.h" +#include "EditorThread.h" +#include "VstHost.h" +#include "Popupwindow.h" +#include "vst~.h" +#include "export.h" +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +// +// Note! +// +// If this DLL is dynamically linked against the MFC +// DLLs, any functions exported from this DLL which +// call into MFC must have the AFX_MANAGE_STATE macro +// added at the very beginning of the function. +// +// For example: +// +// extern "C" BOOL PASCAL EXPORT ExportedFunction() +// { +// AFX_MANAGE_STATE(AfxGetStaticModuleState()); +// // normal function body here +// } +// +// It is very important that this macro appear in each +// function, prior to any calls into MFC. This means that +// it must appear as the first statement within the +// function, even before any object variable declarations +// as their constructors may generate calls into the MFC +// DLL. +// +// Please see MFC Technical Notes 33 and 58 for additional +// details. +// + +///////////////////////////////////////////////////////////////////////////// +// CVstApp + +BEGIN_MESSAGE_MAP(CVstApp, CWinApp) + //{{AFX_MSG_MAP(CVstApp) + // NOTE - the ClassWizard will add and remove mapping macros here. + // DO NOT EDIT what you see in these blocks of generated code! + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CVstApp construction + +CVstApp::CVstApp() +{ + // TODO: add construction code here, + // Place all significant initialization in InitInstance + +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only CVstApp object + +CVstApp theApp; + + +#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus) +extern "C" { +#endif + +typedef struct _vstlib +{ + t_object x_obj; +} t_vstLib; + +static t_class* vstLib_class; + +static void* vstLib_new(t_symbol* s) { + t_vstLib *x = (t_vstLib *)pd_new( vstLib_class); + return (x); +} + + void vst_setup(void) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + vstLib_class = class_new(gensym("vstLib"), (t_newmethod)vstLib_new, 0, + sizeof(t_vstLib), 0, (t_atomtype)0); + + AfxOleInit( ); + + + // call setups here + + vst_tilde_setup(); + + post("VST host by mark williamson"); + post("contains source code from the Psycle tracker"); + + post("Contact: mark@junklight.com . website: http://www.junklight.com"); + post("VSTLib: version: 0.1 "); + post("VSTLib: compiled: "__DATE__); + post(""); +} + +#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus) +} +#endif \ No newline at end of file diff --git a/vst.def b/vst.def new file mode 100644 index 0000000..86f8503 --- /dev/null +++ b/vst.def @@ -0,0 +1,7 @@ +; vst.def : Declares the module parameters for the DLL. + +LIBRARY "vst" +DESCRIPTION 'vst Windows Dynamic Link Library' + +EXPORTS + vst_setup diff --git a/vst.dsp b/vst.dsp new file mode 100644 index 0000000..32f71e4 --- /dev/null +++ b/vst.dsp @@ -0,0 +1,176 @@ +# Microsoft Developer Studio Project File - Name="vst" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=vst - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "vst.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "vst.mak" CFG="vst - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "vst - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "vst - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "vst - Win32 Release" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 5 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\src" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PD" /D "NT" /D "__GNUC__" /D "_WINDLL" /FR /Yu"stdafx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 ..\bin\pd.lib /nologo /subsystem:windows /dll /machine:I386 + +!ELSEIF "$(CFG)" == "vst - Win32 Debug" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 5 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\src" /D "_DEBUG" /D "PD" /D "NT" /D "__GNUC__" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_WINDLL" /Yu"stdafx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 ..\bin\pd.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "vst - Win32 Release" +# Name "vst - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\EditorThread.cpp +# End Source File +# Begin Source File + +SOURCE=.\PopupWindow.cpp +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\vst.cpp +# End Source File +# Begin Source File + +SOURCE=.\vst.def +# End Source File +# Begin Source File + +SOURCE=.\vst.rc +# End Source File +# Begin Source File + +SOURCE=.\VstHost.cpp +# End Source File +# Begin Source File + +SOURCE=.\vst~.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\EditorThread.h +# End Source File +# Begin Source File + +SOURCE=.\export.h +# End Source File +# Begin Source File + +SOURCE=.\PopupWindow.h +# End Source File +# Begin Source File + +SOURCE=.\Resource.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# Begin Source File + +SOURCE=.\vst.h +# End Source File +# Begin Source File + +SOURCE=.\VstHost.h +# End Source File +# Begin Source File + +SOURCE=.\vst~.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\res\vst.rc2 +# End Source File +# End Group +# Begin Source File + +SOURCE=.\ReadMe.txt +# End Source File +# End Target +# End Project diff --git a/vst.dsw b/vst.dsw new file mode 100644 index 0000000..a620ccd --- /dev/null +++ b/vst.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "vst"=.\vst.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/vst.h b/vst.h new file mode 100644 index 0000000..098fc67 --- /dev/null +++ b/vst.h @@ -0,0 +1,46 @@ +// vst.h : main header file for the VST DLL +// + +#if !defined(AFX_VST_H__013CDC75_CDE8_40AD_AE29_D952471B07F5__INCLUDED_) +#define AFX_VST_H__013CDC75_CDE8_40AD_AE29_D952471B07F5__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CVstApp +// See vst.cpp for the implementation of this class +// + +class CVstApp : public CWinApp +{ +public: + CVstApp(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CVstApp) + //}}AFX_VIRTUAL + + //{{AFX_MSG(CVstApp) + // NOTE - the ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_VST_H__013CDC75_CDE8_40AD_AE29_D952471B07F5__INCLUDED_) + diff --git a/vst.ncb b/vst.ncb new file mode 100644 index 0000000..40caa31 Binary files /dev/null and b/vst.ncb differ diff --git a/vst.opt b/vst.opt new file mode 100644 index 0000000..8453f26 Binary files /dev/null and b/vst.opt differ diff --git a/vst.plg b/vst.plg new file mode 100644 index 0000000..4d13ceb --- /dev/null +++ b/vst.plg @@ -0,0 +1,53 @@ + + +
+

Build Log

+

+--------------------Configuration: vst - Win32 Release-------------------- +

+

Command Lines

+Creating temporary file "C:\DOCUME~1\MARKW~1.APP\LOCALS~1\Temp\RSPEA6.tmp" with contents +[ +/nologo /MT /W3 /GX /O2 /I "..\src" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PD" /D "NT" /D "__GNUC__" /D "_WINDLL" /FR"Release/" /Fp"Release/vst.pch" /Yu"stdafx.h" /Fo"Release/" /Fd"Release/" /FD /c +"C:\pd\vst\EditorThread.cpp" +"C:\pd\vst\PopupWindow.cpp" +"C:\pd\vst\vst.cpp" +"C:\pd\vst\VstHost.cpp" +"C:\pd\vst\vst~.cpp" +] +Creating command line "cl.exe @C:\DOCUME~1\MARKW~1.APP\LOCALS~1\Temp\RSPEA6.tmp" +Creating temporary file "C:\DOCUME~1\MARKW~1.APP\LOCALS~1\Temp\RSPEA7.tmp" with contents +[ +..\bin\pd.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"Release/vst.pdb" /machine:I386 /def:".\vst.def" /out:"Release/vst.dll" /implib:"Release/vst.lib" +.\Release\EditorThread.obj +.\Release\PopupWindow.obj +.\Release\StdAfx.obj +.\Release\vst.obj +.\Release\VstHost.obj +.\Release\vst~.obj +.\Release\vst.res +] +Creating command line "link.exe @C:\DOCUME~1\MARKW~1.APP\LOCALS~1\Temp\RSPEA7.tmp" +

Output Window

+Compiling... +EditorThread.cpp +PopupWindow.cpp +vst.cpp +VstHost.cpp +vst~.cpp +Generating Code... +Linking... + Creating library Release/vst.lib and object Release/vst.exp +LINK : warning LNK4089: all references to "OLEAUT32.dll" discarded by /OPT:REF +LINK : warning LNK4089: all references to "comdlg32.dll" discarded by /OPT:REF +Creating command line "bscmake.exe /nologo /o"Release/vst.bsc" .\Release\StdAfx.sbr .\Release\EditorThread.sbr .\Release\PopupWindow.sbr .\Release\vst.sbr .\Release\VstHost.sbr .\Release\vst~.sbr" +Creating browse info file... +

Output Window

+ + + +

Results

+vst.dll - 0 error(s), 2 warning(s) +
+ + diff --git a/vst.rc b/vst.rc new file mode 100644 index 0000000..ecf81fd --- /dev/null +++ b/vst.rc @@ -0,0 +1,124 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif //_WIN32\r\n" + "#include ""res\\vst.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +///////////////////////////////////////////////////////////////////////////// +#endif // APSTUDIO_INVOKED + + + + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "\0" + VALUE "FileDescription", "vst DLL\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "vst\0" + VALUE "LegalCopyright", "Copyright (C) 2002\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename","vst.DLL\0" + VALUE "ProductName", "vst Dynamic Link Library\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif //_WIN32 +#include "res\\vst.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/vst.sln b/vst.sln new file mode 100644 index 0000000..d856c0d --- /dev/null +++ b/vst.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vst", "vst.vcproj", "{20B2DE85-3C09-43DB-A7A9-2F8326B6DB61}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {20B2DE85-3C09-43DB-A7A9-2F8326B6DB61}.Debug.ActiveCfg = Debug|Win32 + {20B2DE85-3C09-43DB-A7A9-2F8326B6DB61}.Debug.Build.0 = Debug|Win32 + {20B2DE85-3C09-43DB-A7A9-2F8326B6DB61}.Release.ActiveCfg = Release|Win32 + {20B2DE85-3C09-43DB-A7A9-2F8326B6DB61}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/vst.suo b/vst.suo new file mode 100644 index 0000000..5249dc0 Binary files /dev/null and b/vst.suo differ diff --git a/vst.vcproj b/vst.vcproj new file mode 100644 index 0000000..4982836 --- /dev/null +++ b/vst.vcproj @@ -0,0 +1,224 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vsttest.pd b/vsttest.pd new file mode 100644 index 0000000..6b11c8d --- /dev/null +++ b/vsttest.pd @@ -0,0 +1,32 @@ +#N canvas 218 503 725 555 12; +#X obj 293 20 osc~ 440; +#X obj 357 96 *~ 0.1; +#X obj 486 21 vsl 15 128 0 1 0 0 empty empty empty 20 8 0 8 -262144 +-1 -1 0 1; +#X obj 302 357 dac~; +#X obj 289 276 vst~ waldorf d-pole; +#X msg 117 221 print; +#X msg 64 236 edit; +#X msg 225 191 param \$1 \$2; +#X obj 191 145 pack \$1 \$2; +#X floatatom 176 69 5 0 0; +#X floatatom 256 84 5 0 1; +#X obj 185 14 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X obj 225 110 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1 +-1; +#X connect 0 0 1 0; +#X connect 1 0 4 1; +#X connect 1 0 4 2; +#X connect 2 0 1 1; +#X connect 4 1 3 0; +#X connect 4 2 3 1; +#X connect 5 0 4 0; +#X connect 6 0 4 0; +#X connect 7 0 4 0; +#X connect 8 0 7 0; +#X connect 9 0 8 0; +#X connect 10 0 8 1; +#X connect 10 0 12 0; +#X connect 11 0 9 0; +#X connect 12 0 8 0; diff --git a/vst~.cpp b/vst~.cpp new file mode 100644 index 0000000..15c26e5 --- /dev/null +++ b/vst~.cpp @@ -0,0 +1,579 @@ +#include "stdafx.h" +#include "m_pd.h" +#include +#include +#include +#include +#include "EditorThread.h" +#include "VstHost.h" + +#include "vst~.h" + +#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus) +extern "C" { +#endif + +static const char * findFilePath( const char * path , const char * dllname ); + +/* ------------------------ vst_tilde~ ----------------------------- */ + +static t_class *vst_tilde_class; + +/** +* the perform routine unpacks its parameters +* looks to see if time is zero (do channel prob +* everytime) if it is to chooses a channel. +* the routine then copies everything in the input +* to the choosen output +*/ + +t_int *vst_tilde_perform_replace(t_int *w) +{ + t_dsp_args *args = (t_dsp_args *)(w[1]); + int n = (t_int)(w[2]); + args->plug->processReplacing( args->inbufs , args->outbufs , args->num_samples ); + return w+3; +} + +t_int *vst_tilde_perform_acc(t_int *w) +{ + t_dsp_args *args = (t_dsp_args *)(w[1]); + int n = (t_int)(w[2]); + args->plug->process( args->inbufs , args->outbufs , args->num_samples ); + return w+3; +} + +/** +* set up our dsp perform routine - it takes parameters +* the input channel, the output channels ( left and right), +* the pin object and the number of samples in the array +*/ + +static void vst_tilde_dsp(t_vst_tilde *x, t_signal **sp) +{ + int i; + if ( x->plug != NULL ) + { + x->d_args = (t_dsp_args *) malloc( sizeof( t_dsp_args )); + x->d_args->num_in = x->num_audio_inputs; + x->d_args->num_out = x->num_audio_outputs; + x->d_args->inbufs = (float**) malloc( x->d_args->num_in * sizeof( float *)); + for( i = 0 ; i< x->d_args->num_in;i++ ) + { + x->d_args->inbufs[i] = sp[ i ]->s_vec; + } + x->d_args->outbufs = (float**) malloc( x->d_args->num_out * sizeof( float *)); + for( i = 0 ; i< x->d_args->num_out;i++ ) + { + x->d_args->outbufs[i] = sp[ i + x->d_args->num_in + 1]->s_vec; + } + x->d_args->num_samples = sp[0]->s_n; + x->d_args->sample_rate = sp[0]->s_sr; + x->d_args->plug = x->plug; + //post("*"); + x->plug->Init( sp[0]->s_sr , sp[0]->s_n ); + //post("*"); + if ( x->plug->replace() ) + { + dsp_add(vst_tilde_perform_replace, 2 , x->d_args , sp[0]->s_n ); + } + else + { + dsp_add(vst_tilde_perform_acc, 2 , x->d_args , sp[0]->s_n ); + } + } + +} + +/** +* free up the tilde object - for now we only need +* to get rid of the clock +*/ + +static void vst_tilde_free(t_vst_tilde *x) +{ + int i; + /* Destroy inlets */ + if (x->audio_inlets != NULL) + { + for (i = 0; i < x->num_audio_inputs; i++) + { + inlet_free (x->audio_inlets[i]); + } + free (x->audio_inlets); + x->audio_inlets = NULL; + } + /* Destroy outlets */ + if (x->control_outlet != NULL) + { + outlet_free (x->control_outlet); + x->control_outlet = NULL; + } + if (x->audio_outlets != NULL) + { + for (i = 0; i < x->num_audio_outputs; i++) + { + outlet_free (x->audio_outlets[i]); + } + free (x->audio_outlets); + x->audio_outlets = NULL; + } + + if( x->d_args != NULL) + { + free( x->d_args->inbufs ); + free( x->d_args->outbufs); + free( x->d_args ); + } + if ( x->plug != NULL ) + { + delete x->plug ; + } +} + +/** +* make a new object - set up out internal variables +* and add our inlets and outlets +*/ + +static void *vst_tilde_new( t_symbol *s, int argc, t_atom *argv) +{ + post("In vst~ new"); + t_vst_tilde *x = (t_vst_tilde *)pd_new(vst_tilde_class); + x->d_args = NULL; + x->plug = new VSTPlugin(); + x->audio_inlets = NULL; + x->audio_outlets = NULL; + x->control_outlet = NULL; + + // to help deal with spaces we assume ALL of the args make + // up the filename + char buf[255]; + CString str; + for( int i = 0 ; i < argc ; i++ ) + { + atom_string( &argv[i] , buf, 255 ); + if ( i == 0 ) + { + str += buf; + } + else + { + str += ' '; + str += buf; + } + } + bool lf = FALSE; + + // try loading the dll from the raw filename + if ( x->plug->Instance( str ) == VSTINSTANCE_NO_ERROR ) + { + //post( "it loaded fine "); + lf = TRUE; + } + else // try finding it on the VST PAth + { + + char* vst_path = getenv ("VST_PATH"); + char* tok_path = (char *) malloc( strlen( vst_path) * sizeof( char )); + + CString dllname; + if ( str.MakeLower().Find( ".dll" ) == -1 ) + { + dllname = str + ".dll"; + } + else + { + dllname = str; + } + strcpy( tok_path , vst_path ); + if ( vst_path != NULL ) + { + char *tok = strtok( tok_path , ";" ); + while( tok != NULL ) + { + CString abpath( tok ); + if( abpath.Right( 1 ) != _T("\\") ) + { + abpath += "\\"; + } + const char * realpath = findFilePath( abpath , dllname ); + //post( "findFilePath( %s , %s ) = %s\n" , abpath , dllname , realpath ); + if ( realpath != NULL ) + { + CString rpath( realpath ); + rpath += _T("\\") + str; + post( "trying %s " , rpath ); + if ( x->plug->Instance( rpath ) == VSTINSTANCE_NO_ERROR ) + { + post( " %s loaded " , x->plug->GetName()); + lf = TRUE; + break; + } + } + tok = strtok( NULL , ";" ); + if ( tok == NULL ) + { + post( "couldn't find dll"); + } + } + } + } + if ( !lf ) // failed - don't make any ins or outs + { + post("Unable to load %s" , str ); + delete x->plug; + x->plug = NULL; + return( x); + } + + // make our inlets and outlets next + + x->num_audio_inputs = x->plug->getNumInputs(); + x->num_audio_outputs = x->plug->getNumOutputs(); + + /* Allocate memory for in- and outlet pointers */ + x->audio_inlets = (t_inlet**)calloc (x->num_audio_inputs, sizeof (t_inlet*)); + x->audio_outlets = (t_outlet**)calloc (x->num_audio_outputs, sizeof (t_outlet*)); + + + /* The first inlet is always there (needn't be created), and is + used for control messages. Now, create the rest of the + inlets for audio signal input. */ + for (i = 0; i < x->num_audio_inputs; i++) + { + x->audio_inlets[i] = inlet_new (&x->x_obj,&x->x_obj.ob_pd,gensym ("signal"),gensym ("signal")); + } + + // set up our inlets for midi notes + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("midinote")); + floatinlet_new(&x->x_obj, &x->x_vel); + + /* We use the first outlet always for VST parameter control messages */ + x->control_outlet = outlet_new (&x->x_obj, gensym ("control")); + + /* The rest of the outlets are used for audio signal output */ + for (i = 0; i < x->num_audio_outputs; i++) + { + x->audio_outlets[i] = outlet_new (&x->x_obj, gensym ("signal")); + } + + return (x); +} + +static const char * findFilePath( const char * path , const char * dllname ) +{ + CFileFind finder; + _chdir( path ); + if ( finder.FindFile( dllname ) == TRUE ) + { + return path; + } + else + { + finder.FindFile(); + while( finder.FindNextFile() ) + { + if ( finder.IsDirectory() ) + { + if ( !finder.IsDots() ) + { + CString *npath = new CString( finder.GetFilePath()); + const char * ret = findFilePath( *npath , dllname ); + if ( ret != NULL) + { + CString *retstr = new CString( ret ); + return *retstr; + } + } + } + } + } + return NULL; +} + + +/** +* setup - add our methods +*/ + + void vst_tilde_setup(void) +{ + srand( (unsigned) time( NULL ) ); + vst_tilde_class = class_new(gensym("vst~"), (t_newmethod) vst_tilde_new, (t_method) vst_tilde_free, + sizeof(t_vst_tilde), 0, A_GIMME , 0); + CLASS_MAINSIGNALIN( vst_tilde_class, t_vst_tilde, x_f); + class_addmethod(vst_tilde_class, (t_method) vst_tilde_dsp, gensym("dsp"), (t_atomtype)0); + class_addmethod (vst_tilde_class,(t_method)vst_tilde_control,gensym ("control"),A_DEFSYM, A_DEFFLOAT, 0); + class_addmethod (vst_tilde_class,(t_method)vst_tilde_pitchbend,gensym ("pitchbend"),A_DEFFLOAT, 0); + class_addmethod (vst_tilde_class,(t_method)vst_tilde_program,gensym ("program"),A_DEFFLOAT, 0); + class_addmethod (vst_tilde_class,(t_method)vst_tilde_programchange,gensym ("programchange"),A_DEFFLOAT, 0); + class_addmethod (vst_tilde_class,(t_method)vst_tilde_ctrlchange,gensym ("ctrlchange"),A_DEFFLOAT ,A_DEFFLOAT, 0); + class_addmethod (vst_tilde_class,(t_method)vst_tilde_print,gensym ("print"),A_GIMME,(t_atomtype) 0); + class_addmethod (vst_tilde_class,(t_method)vst_tilde_edit,gensym ("edit"),(t_atomtype) 0); + class_addmethod (vst_tilde_class,(t_method)vst_tilde_showparams,gensym ("showparams"),(t_atomtype) 0); + class_addmethod (vst_tilde_class,(t_method)vst_tilde_noshowparams,gensym ("noshowparams"),(t_atomtype) 0); + class_addmethod (vst_tilde_class,(t_method)vst_tilde_param,gensym ("param"), A_DEFFLOAT , A_DEFFLOAT , (t_atomtype) 0); + class_addmethod (vst_tilde_class,(t_method)vst_tilde_reset,gensym ("reset"),(t_atomtype) 0); + class_addmethod (vst_tilde_class,(t_method)vst_tilde_midinote,gensym ("midinote"),A_DEFFLOAT,(t_atomtype) 0); + //class_sethelpsymbol(vst_tilde_class, gensym("vst/vsthelp")); +} + + static void vst_tilde_control (t_vst_tilde* x, t_symbol* ctrl_name,t_float ctrl_value) +{ + unsigned parm_num = 0; + + if (ctrl_name->s_name == NULL || strlen (ctrl_name->s_name) == 0) + { + error ("plugin~: control messages must have a name and a value"); + return; + } + //parm_num = vst_tilde_get_parm_number (x, ctrl_name->s_name); + //if (parm_num) + //{ + //vst_tilde_set_control_input_by_index (x, parm_num - 1, ctrl_value); + //} + //else + //{ + //vst_tilde_set_control_input_by_name (x, ctrl_name->s_name, ctrl_value); + //} +} + + static void vst_tilde_pitchbend (t_vst_tilde* x, t_float ctrl_value) +{ + x->plug->AddPitchBend( (int) ctrl_value ); +} + + static void vst_tilde_programchange (t_vst_tilde* x, t_float ctrl_value) +{ + x->plug->AddProgramChange( (int) ctrl_value ); +} + +static void vst_tilde_program (t_vst_tilde* x, t_float ctrl_value) +{ + x->plug->SetCurrentProgram( (int) ctrl_value ); +} + + static void vst_tilde_ctrlchange (t_vst_tilde* x, t_float control , t_float ctrl_value) +{ + x->plug->AddControlChange( (int) control , (int) ctrl_value ); +} + + + /** + * display the parameters names and values and some other bits and pieces that + * may be of use + */ + +static void vst_tilde_print (t_vst_tilde* x, t_symbol *s, int ac, t_atom *av ) +{ + int i; + bool params = false; + bool header = true; + bool programs = false; + bool parameters = true; + int specific = -1; + if ( ac > 0 ) + { + for( i = 0 ; i < ac ; i++) + { + if ( av[i].a_type == A_SYMBOL ) + { + char buf[255]; + atom_string( &av[i] , buf, 255 ); + if ( strcmp( buf , "-params" ) == 0 ) + { + params = true; + } + else if ( strcmp( buf , "-noheader" ) == 0 ) + { + header = false; + } + else if ( strcmp( buf , "-programs" ) == 0 ) + { + programs = true; + parameters = false; + } + else if ( strcmp( buf , "-parameters" ) == 0 ) + { + parameters = false; + } + else if ( strcmp( buf , "-help" ) == 0 ) + { + post("print options:"); + post("-help \t\tprint this"); + post("-params \tshow the parameter display values "); + post("-noheader \tdo not display the header"); + return; + } + } + else if ( av[i].a_type == A_FLOAT ) + { + int p = (int) atom_getfloat( &av[i] ); + if (( p > 0 ) && ( p <= x->plug->GetNumParams())) + { + specific = p - 1; + } + } + } + } + if ( header ) + { + post("VST~ plugin: %s " , x->plug->GetName() ); + post("made by: %s " , x->plug->GetVendorName() ); + post("parameterss %d\naudio: %d in(s)/%d out(s) \nLoaded from library \"%s\".\n", + x->plug->GetNumParams(), + x->num_audio_inputs, + x->num_audio_outputs, + x->plug->GetDllName()); + + post("Flags"); + if ( x->plug->_pEffect->flags & effFlagsHasEditor ) + { + post("Has editor"); + } + if ( x->plug->_pEffect->flags & effFlagsCanReplacing ) + { + post("Can do replacing"); + } + } + if ( parameters ) + { + if ( specific == -1) + { + for (i = 0; i < x->plug->GetNumParams(); i++) + { + display_parameter( x , i , params ); + } + } + else + { + display_parameter( x , specific , params); + } + } + if( programs ) + { + + for( int j = 0; j < x->plug->GetNumCategories() ; j++ ) + { + for( i = 0 ; i < x->plug->GetNumParams() ; i++ ) + { + char buf[64]; + x->plug->GetProgramName( j , i , buf ); + post("Program %d: %s ", i , buf ); + } + } + } +} + +static void display_parameter( t_vst_tilde* x, int param , bool showparams ) +{ + int j = param; + /* the Steinberg(tm) way... */ + char name[109]; + char display[164]; + float val; + if (j == 0) + { + post ("Control input/output(s):"); + } + memset (name, 0, 108); + memset( display, 0 ,163); + x->plug->GetParamName( j , name ); + if ( name[0] != NULL ) + { + if ( showparams ) + { + x->plug->DescribeValue( j , display ); + val = x->plug->GetParamValue( j ); + post ("parameter[#%d], \"%s\" value=%f (%s) ", j + 1, name, val,display); + } + else + { + val = x->plug->GetParamValue( j ); + post ("parameter[#%d], \"%s\" value=%f ", j + 1, name, val); + } + } +} + + +/** +* display an editor - currently not implemented +*/ + + +static void vst_tilde_edit(t_vst_tilde* x) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + if ( x->plug != NULL ) + { + x->plug->edit(); + } + else + { + post("No plugin to edit"); + } +} + +static void vst_tilde_showparams(t_vst_tilde* x) +{ + x->plug->SetShowParameters( true); +} + +static void vst_tilde_noshowparams(t_vst_tilde* x) +{ + x->plug->SetShowParameters( false); +} + + + +/** +* set the value of a parameter +*/ + +static void vst_tilde_param(t_vst_tilde* x , t_float pnum , t_float val) +{ + if ( ( pnum > 0 ) && ( pnum <= x->plug->GetNumParams() )) + { + int i = (int) pnum - 1; + char name[9]; + char display[64]; + float xval; + memset (name, 0, 9); + memset( display, 0 ,64); + x->plug->GetParamName( i , name ); + if ( name[0] != NULL ) + { + xval = x->plug->GetParamValue( i ); + if ( xval <= 1.0f) + { + x->plug->SetParameter( i , val ); + if ( x->plug->ShowParams() ) + { + display_parameter( x , i , true ); + } + } + } + } +} + +static void vst_tilde_reset (t_vst_tilde* x) +{ + +} + +static void vst_tilde_midinote(t_vst_tilde* x , t_float note ) +{ + if ( x->x_vel > 0 ) + { + x->plug->AddNoteOn( note , x->x_vel ); + } + else + { + x->plug->AddNoteOff( note ); + } +} + +#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus) +} +#endif \ No newline at end of file diff --git a/vst~.h b/vst~.h new file mode 100644 index 0000000..90c6c35 --- /dev/null +++ b/vst~.h @@ -0,0 +1,63 @@ +#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus) +extern "C" { +#endif + + +typedef struct _dsp_args +{ + float num_samples; + float sample_rate; + int num_in; + int num_out; + t_float** inbufs; + t_float** outbufs; + VSTPlugin *plug; +} t_dsp_args; + + + +typedef struct _vst_tilde +{ + t_object x_obj; + VSTPlugin *plug; + t_inlet** audio_inlets; + t_outlet** audio_outlets; + int num_audio_inputs; + int num_audio_outputs; + t_outlet* control_outlet; + t_dsp_args *d_args ; + t_float x_vel; + float x_f; +} t_vst_tilde; + +t_int *vst_tilde_perform_replace(t_int *w); +t_int *vst_tilde_perform_acc(t_int *w); +static void vst_tilde_dsp(t_vst_tilde *x, t_signal **sp); +static void vst_tilde_free(t_vst_tilde *x); +static void *vst_tilde_new( t_symbol *s, int argc, t_atom *argv); +static void vst_tilde_float(t_vst_tilde* x, t_float n); + + void vst_tilde_setup(void); + + static void vst_tilde_control (t_vst_tilde* x, t_symbol* ctrl_name,t_float ctrl_value) ; +static void vst_tilde_print (t_vst_tilde* x, t_symbol *s, int ac, t_atom *av ); +static void display_parameter(t_vst_tilde* x, int param, bool showparams ); +static void vst_tilde_edit (t_vst_tilde* x); +static void vst_tilde_showparams(t_vst_tilde* x); +static void vst_tilde_noshowparams(t_vst_tilde* x); +static void vst_tilde_param (t_vst_tilde* x , t_float pnum , t_float val ); +static void vst_tilde_reset (t_vst_tilde* x); +static void vst_tilde_pitchbend (t_vst_tilde* x, t_float ctrl_value); + static void vst_tilde_programchange (t_vst_tilde* x, t_float ctrl_value); +static void vst_tilde_ctrlchange (t_vst_tilde* x, t_float control ,t_float ctrl_value); +static void vst_tilde_program (t_vst_tilde* x, t_float ctrl_value) ; + +static void vst_tilde_midinote(t_vst_tilde* x , t_float note ); + +static void *vstnamecanvas_new(t_symbol *s); + +#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus) +} +#endif + + diff --git a/vst~.pdf b/vst~.pdf new file mode 100644 index 0000000..cb15b2c Binary files /dev/null and b/vst~.pdf differ -- cgit v1.2.1