diff options
Diffstat (limited to 'externals/grill/vst')
-rw-r--r-- | externals/grill/vst/license.txt | 4 | ||||
-rw-r--r-- | externals/grill/vst/package.txt | 2 | ||||
-rw-r--r-- | externals/grill/vst/pd/help-vst~.pd | 199 | ||||
-rw-r--r-- | externals/grill/vst/readme.txt | 3 | ||||
-rw-r--r-- | externals/grill/vst/src/editorwin.hpp | 20 | ||||
-rw-r--r-- | externals/grill/vst/src/main.cpp | 489 | ||||
-rw-r--r-- | externals/grill/vst/src/main.h | 12 | ||||
-rw-r--r-- | externals/grill/vst/src/vst.rc | 2 | ||||
-rw-r--r-- | externals/grill/vst/src/vstedit.cpp | 76 | ||||
-rw-r--r-- | externals/grill/vst/src/vsthost.cpp | 938 | ||||
-rw-r--r-- | externals/grill/vst/src/vsthost.h | 293 | ||||
-rw-r--r-- | externals/grill/vst/src/vstmaster.cpp | 288 | ||||
-rw-r--r-- | externals/grill/vst/src/vstmidi.cpp | 52 | ||||
-rw-r--r-- | externals/grill/vst/src/vstparam.cpp | 105 | ||||
-rw-r--r-- | externals/grill/vst/vst.vcproj | 17 |
15 files changed, 1404 insertions, 1096 deletions
diff --git a/externals/grill/vst/license.txt b/externals/grill/vst/license.txt index 05faa5c3..4535110c 100644 --- a/externals/grill/vst/license.txt +++ b/externals/grill/vst/license.txt @@ -1,6 +1,6 @@ vst~ - VST plugin object for PD based on the work of Jarno Seppänen and Mark Williamson -Copyright (C) 2003 Thomas Grill +Copyright (C) 2003-2005 Thomas Grill This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -52,7 +52,7 @@ syntax --- flext ---------------------------------------------- flext - C++ layer for Max/MSP and pd (pure data) externals -Copyright (C) 2001-2003 Thomas Grill +Copyright (C) 2001-2005 Thomas Grill This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/externals/grill/vst/package.txt b/externals/grill/vst/package.txt index 97f909f0..59e4c4c6 100644 --- a/externals/grill/vst/package.txt +++ b/externals/grill/vst/package.txt @@ -5,6 +5,6 @@ BUILDTYPE=multi BUILDDIR=build
SRCDIR=src
-SRCS=main.cpp vsthost.cpp editor.cpp
+SRCS=main.cpp vsthost.cpp vstmaster.cpp vstedit.cpp vstparam.cpp vstmidi.cpp editor.cpp
HDRS=main.h vsthost.h editor.h editorwin.hpp editormac.hpp
diff --git a/externals/grill/vst/pd/help-vst~.pd b/externals/grill/vst/pd/help-vst~.pd index dcf48343..a43cdb2e 100644 --- a/externals/grill/vst/pd/help-vst~.pd +++ b/externals/grill/vst/pd/help-vst~.pd @@ -1,8 +1,8 @@ -#N canvas 146 124 833 559 12;
+#N canvas 125 128 853 560 12;
#X obj 26 190 dac~;
#X obj 26 94 noise~;
-#X obj 140 192 print A;
-#X obj 443 431 tgl 15 0 empty empty empty 0 -6 0 8 -225271 -1 -1 1
+#X obj 93 189 print A;
+#X obj 443 431 tgl 15 0 empty empty empty 0 -6 0 8 -225271 -1 -1 0
1;
#X msg 442 453 vis \$1;
#X obj 231 430 tgl 15 0 empty empty empty 0 -6 0 8 -225271 -1 -1 1
@@ -10,32 +10,34 @@ #X msg 230 452 edit \$1;
#X msg 298 452 getedit;
#X msg 505 453 getvis;
-#N canvas 367 122 558 434 info 0;
-#X msg 94 130 getversion;
-#X msg 94 75 getname;
-#X msg 95 153 getvendor;
-#X msg 94 188 getsynth;
-#X msg 94 218 getins;
-#X msg 155 220 getouts;
-#X msg 95 104 getdll;
-#X obj 26 260 s \$0-vst;
-#X msg 100 293 print;
-#X msg 101 340 echo \$1;
-#X obj 100 323 tgl 15 0 empty empty empty 0 -6 0 8 -225271 -1 -1 0
-1;
-#X msg 173 339 getecho;
-#X text 250 321 old stuff;
-#X text 171 190 is synth?;
-#X text 179 153 get vendor string;
-#X text 181 131 get version;
-#X text 154 104 get shared lib name;
-#X text 159 79 get internal (official) plug name;
-#X text 219 221 number of plug inlets and outlets;
+#N canvas 367 122 562 438 info 0;
+#X msg 92 160 getversion;
+#X msg 92 105 getname;
+#X msg 93 183 getvendor;
+#X msg 92 218 getsynth;
+#X msg 92 248 getins;
+#X msg 153 250 getouts;
+#X msg 93 134 getdll;
+#X obj 24 290 s \$0-vst;
+#X msg 98 323 print;
+#X msg 99 370 echo \$1;
+#X obj 98 353 tgl 15 0 empty empty empty 0 -6 0 8 -225271 -1 -1 0 1
+;
+#X msg 171 369 getecho;
+#X text 248 351 old stuff;
+#X text 169 220 is synth?;
+#X text 177 183 get vendor string;
+#X text 179 161 get version;
+#X text 152 134 get shared lib name;
+#X text 157 109 get internal (official) plug name;
+#X text 217 251 number of plug inlets and outlets;
#X msg 93 41 getattributes;
-#X text 213 38 get all attributes;
-#X msg 268 189 geteditor;
-#X text 348 189 has editor?;
+#X msg 266 219 geteditor;
+#X text 346 219 has editor?;
#X msg 22 41 help;
+#X text 213 38 list all attributes;
+#X msg 93 64 getmethods;
+#X text 213 65 list all methods;
#X connect 0 0 7 0;
#X connect 1 0 7 0;
#X connect 2 0 7 0;
@@ -48,8 +50,9 @@ #X connect 10 0 9 0;
#X connect 11 0 7 0;
#X connect 19 0 7 0;
-#X connect 21 0 7 0;
-#X connect 23 0 7 0;
+#X connect 20 0 7 0;
+#X connect 22 0 7 0;
+#X connect 24 0 7 0;
#X restore 445 110 pd info;
#X obj 96 96 r \$0-vst;
#X obj 229 479 s \$0-vst;
@@ -60,11 +63,11 @@ #X obj 26 323 s \$0-vst;
#X text 65 249 set/get plugin;
#X text 511 110 further information;
-#X obj 23 15 cnv 15 750 58 empty empty vst~ 10 32 0 24 -260818 -1 0
+#X obj 23 15 cnv 15 800 58 empty empty vst~ 10 32 0 24 -260818 -1 0
;
-#X text 137 173 attribute outlet;
+#X text 90 170 attribute outlet;
#X text 103 137 inlets outlets [plugname];
-#N canvas 367 122 513 321 win 0;
+#N canvas 367 122 521 329 win 0;
#X obj 11 287 s \$0-vst;
#X msg 28 84 getx;
#X text 135 77 get window coordinates;
@@ -103,7 +106,7 @@ #X obj 27 240 bng 25 250 50 0 empty empty empty 0 -6 0 8 -225271 -1
-1;
#X obj 27 271 openpanel;
-#N canvas 461 281 498 343 midi 0;
+#N canvas 461 281 502 347 midi 0;
#X obj 20 279 s \$0-vst;
#X msg 238 147 ctlchg 3 123;
#X text 116 28 note on;
@@ -156,7 +159,7 @@ #X text 256 239 mute output;
#X msg 230 262 mute \$1;
#X msg 312 262 getmute;
-#N canvas 200 110 473 372 parameters 0;
+#N canvas 200 110 477 376 parameters 0;
#X obj 84 118 hsl 128 15 0 1 0 0 empty empty empty -2 -6 0 8 -225271
-1 -1 0 1;
#X msg 81 135 param 2 \$1;
@@ -189,7 +192,7 @@ #X connect 14 0 2 0;
#X connect 15 0 2 0;
#X restore 444 143 pd parameters;
-#N canvas 0 0 458 308 programs 0;
+#N canvas 0 0 462 312 programs 0;
#X obj 39 245 s \$0-vst;
#X msg 162 106 getprogram;
#X text 134 34 get number of programs;
@@ -224,24 +227,118 @@ #X text 562 175 VST programs;
#X text 134 53 http://grrrr.org;
#X text 513 209 midi messages for VST synths;
-#X text 448 314 Attention: this vst~ version will crash when a plugin
-is unloaded with the editor window open!;
-#X text 133 14 VST plugins for PD \, (C)2003-05 Thomas Grill;
-#X msg 27 429 subplug AudioTrack;
-#X obj 27 479 s \$0-vst;
-#X msg 39 452 getsubplug;
+#X msg 47 413 subplug AudioTrack;
+#X obj 32 498 s \$0-vst;
+#X msg 54 468 getsubplug;
#X obj 26 140 vst~ 2 2 @pnames 100;
-#X text 27 387 subplugin name for plugin shells;
#X text 229 501 you can also alt-click on the vst~ object;
-#X connect 1 0 52 0;
-#X connect 1 0 52 1;
+#X msg 32 382 getpluglist;
+#X msg 52 440 subplug C4;
+#N canvas 105 36 474 631 time 0;
+#X obj 17 225 s \$0-vst;
+#X msg 112 78 samplepos \$1;
+#X obj 111 60 nbx 5 14 0 1e+037 0 0 empty empty empty 0 -6 0 10 -225271
+-1 -1 5 256;
+#X msg 224 77 getsamplepos;
+#X obj 111 108 nbx 5 14 0 1e+037 0 0 empty empty empty 0 -6 0 10 -225271
+-1 -1 11 256;
+#X msg 112 126 ppqpos \$1;
+#X msg 199 127 getppqpos;
+#X obj 111 153 nbx 5 14 5 400 0 1 empty empty empty 0 -6 0 10 -225271
+-1 -1 120 256;
+#X msg 112 171 tempo \$1;
+#X msg 199 172 gettempo;
+#X msg 113 28 playing \$1;
+#X msg 203 28 getplaying;
+#X obj 112 -1 tgl 25 0 empty empty empty 0 -6 0 8 -225271 -1 -1 1 1
+;
+#X obj 109 218 tgl 25 0 empty empty empty 0 -6 0 8 -225271 -1 -1 1
+1;
+#X msg 110 247 looping \$1;
+#X msg 200 247 getlooping;
+#X obj 111 275 nbx 5 14 0 1e+037 0 0 empty empty empty 0 -6 0 10 -225271
+-1 -1 5 256;
+#X msg 112 293 loopstart \$1;
+#X msg 222 293 getloopstart;
+#X obj 111 319 nbx 5 14 0 1e+037 0 0 empty empty empty 0 -6 0 10 -225271
+-1 -1 35 256;
+#X msg 112 337 loopend \$1;
+#X msg 222 337 getloopend;
+#X obj 111 363 nbx 5 14 0 1e+037 0 0 empty empty empty 0 -6 0 10 -225271
+-1 -1 0 256;
+#X msg 112 379 looplength \$1;
+#X msg 227 379 getlooplength;
+#X obj 112 512 nbx 5 14 0 1e+037 0 0 empty empty empty 0 -6 0 10 -225271
+-1 -1 0 256;
+#X msg 113 528 smpteoffset \$1;
+#X msg 235 528 getsmpteoffset;
+#X msg 113 570 smpterate \$1;
+#X msg 227 570 getsmpterate;
+#X obj 113 553 hradio 15 1 0 6 empty empty empty 0 -6 0 8 -225271 -1
+-1 0;
+#X text 227 552 24/25/24/30/29.97df/30df;
+#X obj 112 415 nbx 5 14 1 128 0 1 empty empty empty 0 -6 0 10 -225271
+-1 -1 4 256;
+#X msg 113 433 timenom \$1;
+#X msg 205 434 gettimenom;
+#X obj 113 455 nbx 5 14 1 128 0 1 empty empty empty 0 -6 0 10 -225271
+-1 -1 4 256;
+#X msg 114 473 timeden \$1;
+#X msg 206 474 gettimeden;
+#X text 300 423 time signature;
+#X text 302 438 nominator;
+#X text 302 476 denominator;
+#X text 284 161 tempo in quarters per minute;
+#X connect 1 0 0 0;
+#X connect 2 0 1 0;
+#X connect 3 0 0 0;
+#X connect 4 0 5 0;
+#X connect 5 0 0 0;
+#X connect 6 0 0 0;
+#X connect 7 0 8 0;
+#X connect 8 0 0 0;
+#X connect 9 0 0 0;
+#X connect 10 0 0 0;
+#X connect 11 0 0 0;
+#X connect 12 0 10 0;
+#X connect 13 0 14 0;
+#X connect 14 0 0 0;
+#X connect 15 0 0 0;
+#X connect 16 0 17 0;
+#X connect 17 0 0 0;
+#X connect 18 0 0 0;
+#X connect 19 0 20 0;
+#X connect 20 0 0 0;
+#X connect 21 0 0 0;
+#X connect 22 0 23 0;
+#X connect 23 0 0 0;
+#X connect 24 0 0 0;
+#X connect 25 0 26 0;
+#X connect 26 0 0 0;
+#X connect 27 0 0 0;
+#X connect 28 0 0 0;
+#X connect 29 0 0 0;
+#X connect 30 0 28 0;
+#X connect 32 0 33 0;
+#X connect 33 0 0 0;
+#X connect 34 0 0 0;
+#X connect 35 0 36 0;
+#X connect 36 0 0 0;
+#X connect 37 0 0 0;
+#X restore 446 280 pd time;
+#X text 513 278 sequencer stuff;
+#X text 133 14 VST plugins for PD \, (C)2003-2005 Thomas Grill;
+#X text 443 319 Attention: this vst~ version will crash when a plugin
+is unloaded with the editor window open!;
+#X connect 1 0 50 0;
+#X connect 1 0 50 1;
#X connect 3 0 4 0;
#X connect 4 0 12 0;
#X connect 5 0 6 0;
#X connect 6 0 11 0;
#X connect 7 0 11 0;
#X connect 8 0 12 0;
-#X connect 10 0 52 0;
+#X connect 10 0 50 0;
#X connect 15 0 16 0;
#X connect 24 0 16 0;
#X connect 25 0 26 0;
@@ -253,8 +350,10 @@ is unloaded with the editor window open!; #X connect 36 0 39 0;
#X connect 39 0 37 0;
#X connect 40 0 37 0;
-#X connect 49 0 50 0;
-#X connect 51 0 50 0;
-#X connect 52 0 0 0;
-#X connect 52 1 0 1;
-#X connect 52 2 2 0;
+#X connect 47 0 48 0;
+#X connect 49 0 48 0;
+#X connect 50 0 0 0;
+#X connect 50 1 0 1;
+#X connect 50 2 2 0;
+#X connect 52 0 48 0;
+#X connect 53 0 48 0;
diff --git a/externals/grill/vst/readme.txt b/externals/grill/vst/readme.txt index 5c52e97f..fc55be79 100644 --- a/externals/grill/vst/readme.txt +++ b/externals/grill/vst/readme.txt @@ -55,6 +55,9 @@ Version history: - pre14: allow window titles with spaces and update it on window startup - pre18: open plug interface on Alt-Click - pre18: experimental plug shell support +- pre19: better shell support +- pre19: restructured code and added time info +- pre19: support for event processing (like MIDI in) 0.0.0: - version of mark@junklight.com diff --git a/externals/grill/vst/src/editorwin.hpp b/externals/grill/vst/src/editorwin.hpp index f29313d4..29e63db6 100644 --- a/externals/grill/vst/src/editorwin.hpp +++ b/externals/grill/vst/src/editorwin.hpp @@ -38,7 +38,7 @@ static LRESULT CALLBACK wndproc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp) plug->StartEditing(hwnd); break; case WM_CLOSE: -#ifdef FLEXT_DEBUG +#ifdef FLEXT_LOGGING flext::post("WM_CLOSE"); #endif // plug could already have been unloaded... @@ -46,7 +46,7 @@ static LRESULT CALLBACK wndproc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp) DestroyWindow(hwnd); break; case WM_DESTROY: -#ifdef FLEXT_DEBUG +#ifdef FLEXT_LOGGING flext::post("WM_DESTROY"); #endif // stop editor thread @@ -66,7 +66,7 @@ static LRESULT CALLBACK wndproc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp) short x = reinterpret_cast<short &>(wx),y = reinterpret_cast<short &>(wy); // x and y are the coordinates of the client rect (= actual VST interface) plug->SetPos(x,y,false); -#ifdef FLEXT_DEBUG +#ifdef FLEXT_LOGGING flext::post("WM_MOVE x/y=%i/%i",x,y); #endif break; @@ -87,7 +87,7 @@ static LRESULT CALLBACK wndproc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp) } #endif -#if 0 //def FLEXT_DEBUG +#if 0 //def FLEXT_LOGGING case WM_SIZE: { WORD wx = LOWORD(lp),wy = HIWORD(lp); short x = reinterpret_cast<short &>(wx),y = reinterpret_cast<short &>(wy); @@ -98,7 +98,7 @@ static LRESULT CALLBACK wndproc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp) #endif default: - #ifdef FLEXT_DEBUG + #ifdef FLEXT_LOGGING flext::post("WND MSG %i, WP=%i, lp=%i",msg,wp,lp); #endif @@ -169,7 +169,7 @@ static void threadfun(flext::thr_params *p) ERect r; plug->GetEditorRect(r); windowsize(wnd,plug->GetX(),plug->GetY(),r.right-r.left,r.bottom-r.top,plug->GetCaption(),SWP_SHOWWINDOW); -#ifdef FLEXT_DEBUG +#ifdef FLEXT_LOGGING flext::post("Editor rect left/top=%i/%i, right/bottom=%i/%i",r.left,r.top,r.right,r.bottom); #endif @@ -220,23 +220,23 @@ void SetupEditor() void StartEditor(VSTPlugin *p) { -#ifdef FLEXT_DEBUG +#ifdef FLEXT_LOGGING flext::post("Start editor 1"); #endif flext::LaunchThread(threadfun,reinterpret_cast<flext::thr_params *>(p)); -#ifdef FLEXT_DEBUG +#ifdef FLEXT_LOGGING flext::post("Start editor 2"); #endif } void StopEditor(VSTPlugin *p) { -#ifdef FLEXT_DEBUG +#ifdef FLEXT_LOGGING flext::post("Stop editor 1"); #endif PostMessage(p->EditorHandle(),WM_CLOSE,0,0); flext::StopThread(threadfun,reinterpret_cast<flext::thr_params *>(p)); -#ifdef FLEXT_DEBUG +#ifdef FLEXT_LOGGING flext::post("Stop editor 2"); #endif } diff --git a/externals/grill/vst/src/main.cpp b/externals/grill/vst/src/main.cpp index 75b5feda..1292a746 100644 --- a/externals/grill/vst/src/main.cpp +++ b/externals/grill/vst/src/main.cpp @@ -26,109 +26,142 @@ WARRANTIES, see the file, "license.txt," in this distribution. #endif -#define VST_VERSION "0.1.0pre18" +#define VST_VERSION "0.1.0pre19" -class vst: - public flext_dsp +class vst + : public flext_dsp + , public Responder { FLEXT_HEADER_S(vst,flext_dsp,Setup) public: - vst(I argc,const A *argv); + vst(int argc,const t_atom *argv); ~vst(); protected: - virtual V m_dsp(I n,t_signalvec const *insigs,t_signalvec const *outsigs); - virtual V m_signal(I n,R *const *insigs,R *const *outsigs); + virtual void m_dsp(int n,t_signalvec const *insigs,t_signalvec const *outsigs); + virtual void m_signal(int n,t_sample *const *insigs,t_sample *const *outsigs); virtual void m_click() { ms_edit(true); } - BL ms_plug(I argc,const A *argv); - BL ms_plug(const AtomList &args) { return ms_plug(args.Count(),args.Atoms()); } - V mg_plug(AtomList &sym) const { sym(1); SetString(sym[0],plugname.c_str()); } + bool ms_plug(int argc,const t_atom *argv); + bool ms_plug(const AtomList &args) { return ms_plug(args.Count(),args.Atoms()); } + void mg_plug(AtomList &sym) const { sym(1); SetString(sym[0],plugname.c_str()); } - void ms_subplug(I argc,const A *argv); + void ms_subplug(int argc,const t_atom *argv); void ms_subplug(const AtomList &args) { ms_subplug(args.Count(),args.Atoms()); } void mg_subplug(AtomList &sym) const { sym(1); SetString(sym[0],subplug.c_str()); } - V mg_editor(BL &ed) { ed = plug && plug->HasEditor(); } - - V ms_edit(BL on) { if(plug) plug->Edit(on); } - V mg_edit(BL &ed) { ed = plug && plug->IsEdited(); } - V ms_vis(BL vis) { if(plug) plug->Visible(vis); } - V mg_vis(BL &vis) { vis = plug && plug->IsVisible(); } - - V mg_winx(I &x) const { x = plug?plug->GetX():0; } - V mg_winy(I &y) const { y = plug?plug->GetY():0; } - V ms_winx(I x) { if(plug) plug->SetX(x); } - V ms_winy(I y) { if(plug) plug->SetY(y); } - V ms_wincaption(bool c) { if(plug) plug->SetCaption(c); } - V mg_wincaption(bool &c) const { c = plug && plug->GetCaption(); } - V ms_wintitle(const AtomList &t); - V mg_wintitle(AtomList &t) const { if(plug) { t(1); SetString(t[0],plug->GetTitle()); } } - - V mg_chnsin(I &c) const { c = plug?plug->GetNumInputs():0; } - V mg_chnsout(I &c) const { c = plug?plug->GetNumOutputs():0; } - V mg_params(I &p) const { p = plug?plug->GetNumParams():0; } - V mg_programs(I &p) const { p = plug?plug->GetNumPrograms():0; } - V mg_progcats(I &p) const { p = plug?plug->GetNumCategories():0; } - V mg_plugname(const S *&s) const { s = plug?MakeSymbol(plug->GetName()):sym__; } - V mg_plugvendor(const S *&s) const { s = plug?MakeSymbol(plug->GetVendorName()):sym__; } - V mg_plugdll(const S *&s) const { s = plug?MakeSymbol(plug->GetDllName()):sym__; } - V mg_plugversion(I &v) const { v = plug?plug->GetVersion():0; } - V mg_issynth(BL &s) const { s = plug && plug->IsSynth(); } - - V m_print(I ac,const A *av); - - V ms_program(I p); - V mg_program(I &p) const { p = plug?plug->GetCurrentProgram():0; } - V mg_progname(int argc,const t_atom *argv) const; + void m_pluglist() { if(plug) plug->ListPlugs(sym_pluglist); } + + void mg_editor(bool &ed) { ed = plug && plug->HasEditor(); } + + void ms_edit(bool on) { if(plug) plug->Edit(on); } + void mg_edit(bool &ed) { ed = plug && plug->IsEdited(); } + void ms_vis(bool vis) { if(plug) plug->Visible(vis); } + void mg_vis(bool &vis) { vis = plug && plug->IsVisible(); } + + void mg_winx(int &x) const { x = plug?plug->GetX():0; } + void mg_winy(int &y) const { y = plug?plug->GetY():0; } + void ms_winx(int x) { if(plug) plug->SetX(x); } + void ms_winy(int y) { if(plug) plug->SetY(y); } + void ms_wincaption(bool c) { if(plug) plug->SetCaption(c); } + void mg_wincaption(bool &c) const { c = plug && plug->GetCaption(); } + void ms_wintitle(const AtomList &t); + void mg_wintitle(AtomList &t) const { if(plug) { t(1); SetString(t[0],plug->GetTitle()); } } + + void mg_chnsin(int &c) const { c = plug?plug->GetNumInputs():0; } + void mg_chnsout(int &c) const { c = plug?plug->GetNumOutputs():0; } + void mg_params(int &p) const { p = plug?plug->GetNumParams():0; } + void mg_programs(int &p) const { p = plug?plug->GetNumPrograms():0; } + void mg_progcats(int &p) const { p = plug?plug->GetNumCategories():0; } + void mg_plugname(const t_symbol *&s) const { s = plug?MakeSymbol(plug->GetName()):sym__; } + void mg_plugvendor(const t_symbol *&s) const { s = plug?MakeSymbol(plug->GetVendorName()):sym__; } + void mg_plugdll(const t_symbol *&s) const { s = plug?MakeSymbol(plug->GetDllName()):sym__; } + void mg_plugversion(int &v) const { v = plug?plug->GetVersion():0; } + void mg_issynth(bool &s) const { s = plug && plug->IsSynth(); } + + void m_print(int ac,const t_atom *av); + + void ms_program(int p) { if(plug && p >= 0) plug->SetCurrentProgram(p); } + void mg_program(int &p) const { p = plug?plug->GetCurrentProgram():0; } + void mg_progname(int argc,const t_atom *argv) const; - V m_pname(I pnum); - V ms_paramnames(int cnt) { paramnames = cnt; if(plug) plug->ScanParams(cnt); } - - V ms_param(I pnum,F val); - V ms_params(int argc,const t_atom *argv); - V mg_param(I pnum); - V mg_params(int argc,const t_atom *argv); - V m_ptext(I pnum); - V m_ptexts(int argc,const t_atom *argv); - -// V m_control(const S *ctrl_name,I ctrl_value); - V m_pitchbend(I ctrl_value); - V m_programchange(I ctrl_value); - V m_aftertouch(I ctrl_value); - V m_ctrlchange(I control,I ctrl_value); - V m_note(I note,I vel); - inline V m_noteoff(I note) { m_note(note,0); } + void m_pname(int pnum); + void ms_paramnames(int cnt) { paramnames = cnt; if(plug) plug->ScanParams(cnt); } + + void ms_param(int pnum,float val); + void ms_params(int argc,const t_atom *argv); + void mg_param(int pnum); + void mg_params(int argc,const t_atom *argv); + void m_ptext(int pnum); + void m_ptexts(int argc,const t_atom *argv); + +// void m_control(const t_symbol *ctrl_name,int ctrl_value); + void m_pitchbend(int ctrl_value) { if(plug) plug->AddPitchBend(ctrl_value ); } + void m_programchange(int ctrl_value) { if(plug) plug->AddProgramChange(ctrl_value ); } + void m_aftertouch(int ctrl_value) { if(plug) plug->AddAftertouch(ctrl_value ); } + void m_ctrlchange(int control,int ctrl_value) { if(plug) plug->AddControlChange(control,ctrl_value ); } + void m_note(int note,int vel); + void m_noteoff(int note) { m_note(note,0); } + + void mg_playing(bool &p) { p = plug && plug->GetPlaying(); } + void ms_playing(bool p) { if(plug) plug->SetPlaying(p); } + void mg_looping(bool &p) { p = plug && plug->GetLooping(); } + void ms_looping(bool p) { if(plug) plug->SetLooping(p); } + void mg_samplepos(float &p) { p = plug?(float)plug->GetSamplePos():0; } + void ms_samplepos(float p) { if(plug) plug->SetSamplePos(p); } + void mg_ppqpos(float &p) { p = plug?(float)plug->GetPPQPos():0; } + void ms_ppqpos(float p) { if(plug) plug->SetPPQPos(p); } + void mg_tempo(float &p) { p = plug?(float)plug->GetTempo():0; } + void ms_tempo(float p) { if(plug) plug->SetTempo(p); } + void mg_barstart(float &p) { p = plug?(float)plug->GetBarStart():0; } + void ms_barstart(float p) { if(plug) plug->SetBarStart(p); } + void mg_cyclestart(float &p) { p = plug?(float)plug->GetCycleStart():0; } + void ms_cyclestart(float p) { if(plug) plug->SetCycleStart(p); } + void mg_cycleend(float &p) { p = plug?(float)plug->GetCycleEnd():0; } + void ms_cycleend(float p) { if(plug) plug->SetCycleEnd(p); } + void mg_cyclelength(float &p) { p = plug?(float)(plug->GetCycleEnd()-plug->GetCycleStart()):0; } + void ms_cyclelength(float p) { if(p) plug->SetCycleEnd(plug->GetCycleStart()+p); } + void mg_timesignom(int &p) { p = plug?plug->GetTimesigNom():0; } + void ms_timesignom(int p) { if(plug) plug->SetTimesigNom(p); } + void mg_timesigden(int &p) { p = plug?plug->GetTimesigDen():0; } + void ms_timesigden(int p) { if(plug) plug->SetTimesigDen(p); } + void mg_smpteoffset(int &p) { p = plug?plug->GetSmpteOffset():0; } + void ms_smpteoffset(int p) { if(plug) plug->SetSmpteOffset(p); } + void mg_smpterate(int &p) { p = plug?plug->GetSmpteRate():0; } + void ms_smpterate(int p) { if(plug) plug->SetSmpteRate(p); } private: - V display_parameter(I param,BL showparams); + void display_parameter(int param,bool showparams); VSTPlugin *plug; std::string plugname,subplug; bool echoparam,visible,bypass,mute; int paramnames; - I blsz; - V (VSTPlugin::*vstfun)(R **insigs,R **outsigs,L n); - BL sigmatch; - R **vstin,**vstout,**tmpin,**tmpout; + int blsz; + void (VSTPlugin::*vstfun)(t_sample **insigs,t_sample **outsigs,long n); + bool sigmatch; + t_sample **vstin,**vstout,**tmpin,**tmpout; - V InitPlug(); - V ClearPlug(); - V InitPlugDSP(); - V InitBuf(); - V ClearBuf(); + void InitPlug(); + void ClearPlug(); + bool LoadPlug(); + void InitPlugDSP(); + void InitBuf(); + void ClearBuf(); - static V Setup(t_classid); + static void Setup(t_classid); + virtual void Respond(const t_symbol *sym,int argc = 0,const t_atom *argv = NULL); FLEXT_CALLBACK_V(m_print) FLEXT_CALLVAR_V(mg_plug,ms_plug) FLEXT_CALLVAR_V(mg_subplug,ms_subplug) + FLEXT_CALLBACK(m_pluglist) FLEXT_CALLVAR_B(mg_edit,ms_edit) FLEXT_CALLGET_B(mg_editor) @@ -175,15 +208,29 @@ private: FLEXT_CALLGET_I(mg_plugversion) FLEXT_CALLGET_B(mg_issynth) - static const t_symbol *sym_progname,*sym_pname,*sym_param,*sym_ptext; + FLEXT_CALLVAR_B(mg_playing,ms_playing) + FLEXT_CALLVAR_B(mg_looping,ms_looping) + FLEXT_CALLVAR_F(mg_samplepos,ms_samplepos) + FLEXT_CALLVAR_F(mg_ppqpos,ms_ppqpos) + FLEXT_CALLVAR_F(mg_tempo,ms_tempo) + FLEXT_CALLVAR_F(mg_barstart,ms_barstart) + FLEXT_CALLVAR_F(mg_cyclestart,ms_cyclestart) + FLEXT_CALLVAR_F(mg_cycleend,ms_cycleend) + FLEXT_CALLVAR_F(mg_cyclelength,ms_cyclelength) + FLEXT_CALLVAR_I(mg_timesignom,ms_timesignom) + FLEXT_CALLVAR_I(mg_timesigden,ms_timesigden) + FLEXT_CALLVAR_I(mg_smpteoffset,ms_smpteoffset) + FLEXT_CALLVAR_I(mg_smpterate,ms_smpterate) + + static const t_symbol *sym_progname,*sym_pname,*sym_param,*sym_ptext,*sym_pluglist; }; FLEXT_NEW_DSP_V("vst~",vst); -const t_symbol *vst::sym_progname,*vst::sym_pname,*vst::sym_param,*vst::sym_ptext; +const t_symbol *vst::sym_progname,*vst::sym_pname,*vst::sym_param,*vst::sym_ptext,*vst::sym_pluglist; -V vst::Setup(t_classid c) +void vst::Setup(t_classid c) { post(""); post("vst~ %s - VST plugin object, (C)2003-05 Thomas Grill",VST_VERSION); @@ -192,6 +239,7 @@ V vst::Setup(t_classid c) FLEXT_CADDATTR_VAR(c,"plug",mg_plug,ms_plug); FLEXT_CADDATTR_VAR(c,"subplug",mg_subplug,ms_subplug); + FLEXT_CADDMETHOD_(c,0,"getpluglist",m_pluglist); FLEXT_CADDATTR_VAR(c,"edit",mg_edit,ms_edit); FLEXT_CADDATTR_GET(c,"editor",mg_editor); FLEXT_CADDATTR_VAR(c,"vis",mg_vis,ms_vis); @@ -236,34 +284,50 @@ V vst::Setup(t_classid c) FLEXT_CADDATTR_GET(c,"version",mg_plugversion); FLEXT_CADDATTR_GET(c,"synth",mg_issynth); + FLEXT_CADDATTR_VAR(c,"playing",mg_playing,ms_playing); + FLEXT_CADDATTR_VAR(c,"looping",mg_looping,ms_looping); + FLEXT_CADDATTR_VAR(c,"samplepos",mg_samplepos,ms_samplepos); + FLEXT_CADDATTR_VAR(c,"ppqpos",mg_ppqpos,ms_ppqpos); + FLEXT_CADDATTR_VAR(c,"tempo",mg_tempo,ms_tempo); + FLEXT_CADDATTR_VAR(c,"barstart",mg_barstart,ms_barstart); + FLEXT_CADDATTR_VAR(c,"loopstart",mg_cyclestart,ms_cyclestart); + FLEXT_CADDATTR_VAR(c,"loopend",mg_cycleend,ms_cycleend); + FLEXT_CADDATTR_VAR(c,"looplength",mg_cyclelength,ms_cyclelength); + FLEXT_CADDATTR_VAR(c,"timenom",mg_timesignom,ms_timesignom); + FLEXT_CADDATTR_VAR(c,"timeden",mg_timesigden,ms_timesigden); + FLEXT_CADDATTR_VAR(c,"smpteoffset",mg_smpteoffset,ms_smpteoffset); + FLEXT_CADDATTR_VAR(c,"smpterate",mg_smpterate,ms_smpterate); + sym_progname = MakeSymbol("progname"); sym_pname = MakeSymbol("pname"); sym_param = MakeSymbol("param"); sym_ptext = MakeSymbol("ptext"); + sym_pluglist = MakeSymbol("pluglist"); + VSTPlugin::Setup(); SetupEditor(); } -vst::vst(I argc,const A *argv): +vst::vst(int argc,const t_atom *argv): plug(NULL),visible(false), blsz(0), vstfun(NULL),vstin(NULL),vstout(NULL),tmpin(NULL),tmpout(NULL), echoparam(false),bypass(false),mute(false),paramnames(0) { - if(argc >= 2 && CanbeInt(argv[0]) && CanbeInt(argv[1])) { - AddInSignal(GetAInt(argv[0])); - AddOutSignal(GetAInt(argv[1])); - - if(argc >= 3 && !ms_plug(argc-2,argv+2)) InitProblem(); - } - else - throw "syntax: vst~ inputs outputs [plug]"; - #if FLEXT_OS == FLEXT_OS_WIN // this is necessary for Waveshell CoInitializeEx(NULL,COINIT_MULTITHREADED+COINIT_SPEED_OVER_MEMORY); #endif + + int ins = 1,outs = 1; + if(argc >= 1 && CanbeInt(argv[0])) { ins = GetAInt(argv[0]); argc--,argv++; } + if(argc >= 1 && CanbeInt(argv[0])) { outs = GetAInt(argv[0]); argc--,argv++; } + + AddInSignal(ins); + AddOutSignal(outs); + + if(argc >= 1 && !ms_plug(argc,argv)) InitProblem(); } vst::~vst() @@ -274,7 +338,7 @@ vst::~vst() #endif } -V vst::ClearPlug() +void vst::ClearPlug() { if(plug) { plug->Edit(false); @@ -283,7 +347,7 @@ V vst::ClearPlug() } } -V vst::InitPlug() +void vst::InitPlug() { FLEXT_ASSERT(plug); @@ -296,7 +360,7 @@ V vst::InitPlug() plug->ScanParams(paramnames); } -V vst::InitPlugDSP() +void vst::InitPlugDSP() { FLEXT_ASSERT(plug); // this might be invalid if DSP is switched off, @@ -304,36 +368,36 @@ V vst::InitPlugDSP() plug->DspInit(Samplerate(),Blocksize()); } -V vst::ClearBuf() +void vst::ClearBuf() { if(!plug) return; if(vstin) { - for(I i = 0; i < plug->GetNumInputs(); ++i) FreeAligned(vstin[i]); + for(int i = 0; i < plug->GetNumInputs(); ++i) FreeAligned(vstin[i]); delete[] vstin; vstin = NULL; delete[] tmpin; tmpin = NULL; } if(vstout) { - for(I i = 0; i < plug->GetNumOutputs(); ++i) FreeAligned(vstout[i]); + for(int i = 0; i < plug->GetNumOutputs(); ++i) FreeAligned(vstout[i]); delete[] vstout; vstout = NULL; delete[] tmpout; tmpout = NULL; } } -V vst::InitBuf() +void vst::InitBuf() { FLEXT_ASSERT(!vstin && !tmpin && !vstout && !tmpout); const int inputs = plug->GetNumInputs(),outputs = plug->GetNumOutputs(); - I i; + int i; - vstin = new R *[inputs]; - tmpin = new R *[inputs]; - for(i = 0; i < inputs; ++i) vstin[i] = (R *)NewAligned(Blocksize()*sizeof(R)); + vstin = new t_sample *[inputs]; + tmpin = new t_sample *[inputs]; + for(i = 0; i < inputs; ++i) vstin[i] = (t_sample *)NewAligned(Blocksize()*sizeof(t_sample)); - vstout = new R *[outputs]; - tmpout = new R *[outputs]; - for(i = 0; i < outputs; ++i) vstout[i] = (R *)NewAligned(Blocksize()*sizeof(R)); + vstout = new t_sample *[outputs]; + tmpout = new t_sample *[outputs]; + for(i = 0; i < outputs; ++i) vstout[i] = (t_sample *)NewAligned(Blocksize()*sizeof(t_sample)); } static std::string findFilePath(const std::string &path,const std::string &dllname) @@ -372,52 +436,21 @@ static std::string findFilePath(const std::string &path,const std::string &dllna } -BL vst::ms_plug(I argc,const A *argv) +bool vst::LoadPlug() { - ClearPlug(); - - plugname.clear(); - C buf[255]; - for(I i = 0; i < argc; i++) { - if(i > 0) plugname += ' '; - GetAString(argv[i],buf,sizeof buf); -#if FLEXT_OS == FLEXT_OS_WIN - strlwr(buf); -#endif - -#if FLEXT_SYS == FLEXT_SYS_PD - // strip char escapes (only in newer/devel PD version) - char *cs = buf,*cd = cs; - while(*cs) { - if(*cs != '\\') *(cd++) = *cs; - ++cs; - } - *cd = 0; -#endif - - plugname += buf; - } - - if(!plugname.length()) return false; + if(plug) ClearPlug(); - plug = new VSTPlugin; - - // now try to load plugin - - // to help deal with spaces we assume ALL of the args make - // up the filename - bool lf = false; - int loaderr = VSTINSTANCE_NO_ERROR; + plug = new VSTPlugin(this); // try loading the dll from the raw filename - if ((loaderr = plug->Instance(plugname.c_str(),subplug.c_str())) == VSTINSTANCE_NO_ERROR) { - FLEXT_LOG("raw filename loaded fine"); - lf = true; - } - - if(!lf) { // try finding it on the PD path - C *name,dir[1024]; - I fd = open_via_path("",plugname.c_str(),".dll",dir,&name,sizeof(dir)-1,0); + bool ok = plug->Instance(plugname.c_str(),subplug.c_str()); + if(ok) + FLEXT_LOG("raw filename loaded fine"); + else { +#if FLEXT_SYS == FLEXT_SYS_PD + // try finding it on the PD path + char *name,dir[1024]; + int fd = open_via_path("",plugname.c_str(),".dll",dir,&name,sizeof(dir)-1,0); if(fd > 0) close(fd); else name = NULL; @@ -430,35 +463,38 @@ BL vst::ms_plug(I argc,const A *argv) dllname += "\\"; dllname += name; - lf = (loaderr = plug->Instance(dllname.c_str())) == VSTINSTANCE_NO_ERROR; + ok = plug->Instance(dllname.c_str()); } +#endif } - if(!lf) { // try finding it on the VST path - C *vst_path = getenv("VST_PATH"); + if(!ok) { + // try finding it on the VST path + char *vst_path = getenv("VST_PATH"); std::string dllname(plugname); if(dllname.find(".dll") == -1) dllname += ".dll"; if(vst_path) { FLEXT_LOG("found VST_PATH env variable"); - char* tok_path = new C[strlen( vst_path)+1]; + char* tok_path = new char[strlen( vst_path)+1]; strcpy( tok_path , vst_path); char *tok = strtok( tok_path , ";" ); while( tok != NULL ) { std::string abpath( tok ); if( abpath[abpath.length()-1] != '\\' ) abpath += "\\"; - FLEXT_LOG1("trying VST_PATH %s",(const C *)abpath.c_str()); + FLEXT_LOG1("trying VST_PATH %s",(const char *)abpath.c_str()); std::string realpath = findFilePath( abpath , dllname ); //post( "findFilePath( %s , %s ) = %s\n" , abpath , dllname , realpath ); if ( realpath.length() ) { realpath += plugname; - FLEXT_LOG1("trying %s",(const C *)realpath.c_str()); - if((loaderr = plug->Instance( realpath.c_str() )) == VSTINSTANCE_NO_ERROR ) { + FLEXT_LOG1("trying %s",(const char *)realpath.c_str()); + + ok = plug->Instance(realpath.c_str()); + if(ok) { FLEXT_LOG("plugin loaded via VST_PATH"); - lf = true; break; } } @@ -471,39 +507,65 @@ BL vst::ms_plug(I argc,const A *argv) } } - if(!lf) { // failed - don't make any ins or outs - post("%s - unable to load plugin '%s', load error %i",thisName(),plugname.c_str(),loaderr); + if(!ok) { + post("%s - unable to load plugin '%s'",thisName(),plugname.c_str()); ClearPlug(); - } + } + else + InitPlug(); + + return ok; +} + +static char *stripesc(char *buf) +{ +#if FLEXT_SYS == FLEXT_SYS_PD + // strip char escapes (only in newer/devel PD version) + char *cs = buf,*cd = cs; + while(*cs) { + if(*cs != '\\') *(cd++) = *cs; + ++cs; + } + *cd = 0; +#endif + return buf; +} - // re-init dsp stuff - if(plug) InitPlug(); +bool vst::ms_plug(int argc,const t_atom *argv) +{ + ClearPlug(); - return lf; + plugname.clear(); + char buf[255]; + for(int i = 0; i < argc; i++) { + if(i > 0) plugname += ' '; + GetAString(argv[i],buf,sizeof buf); +#if FLEXT_OS == FLEXT_OS_WIN + strlwr(buf); +#endif + plugname += stripesc(buf); + } + + if(!plugname.length()) + return false; + else + return LoadPlug(); } -void vst::ms_subplug(I argc,const A *argv) +void vst::ms_subplug(int argc,const t_atom *argv) { subplug.clear(); - C buf[255]; - for(I i = 0; i < argc; i++) { + char buf[255]; + for(int i = 0; i < argc; i++) { if(i > 0) subplug += ' '; GetAString(argv[i],buf,sizeof buf); - -#if FLEXT_SYS == FLEXT_SYS_PD - // strip char escapes (only in newer/devel PD version) - char *cs = buf,*cd = cs; - while(*cs) { - if(*cs != '\\') *(cd++) = *cs; - ++cs; - } - *cd = 0; -#endif - subplug += buf; + subplug += stripesc(buf); } + + LoadPlug(); } -V vst::m_dsp(I n,t_signalvec const *,t_signalvec const *) +void vst::m_dsp(int n,t_signalvec const *,t_signalvec const *) { if(plug) { FLEXT_ASSERT(vstfun); @@ -518,7 +580,7 @@ V vst::m_dsp(I n,t_signalvec const *,t_signalvec const *) } } -V vst::m_signal(I n,R *const *insigs,R *const *outsigs) +void vst::m_signal(int n,t_sample *const *insigs,t_sample *const *outsigs) { if(mute) flext_dsp::m_signal(n,insigs,outsigs); @@ -532,10 +594,10 @@ V vst::m_signal(I n,R *const *insigs,R *const *outsigs) i = 1; } else if(mx == 2) { - R *o1 = outsigs[0],*o2 = outsigs[1]; - const R *i1 = insigs[0],*i2 = insigs[1]; + t_sample *o1 = outsigs[0],*o2 = outsigs[1]; + const t_sample *i1 = insigs[0],*i2 = insigs[1]; for(int s = 0; s < n; ++s) { - const R f = *(i1++); + const t_sample f = *(i1++); *(o2++) = *(i2++); *(o1++) = f; } @@ -555,16 +617,16 @@ V vst::m_signal(I n,R *const *insigs,R *const *outsigs) const int inputs = plug->GetNumInputs(),outputs = plug->GetNumOutputs(); if(sigmatch) - (plug->*vstfun)(const_cast<R **>(insigs),const_cast<R **>(outsigs),n); + (plug->*vstfun)(const_cast<t_sample **>(insigs),const_cast<t_sample **>(outsigs),n); else { const int cntin = CntInSig(),cntout = CntOutSig(); - R **inv,**outv; + t_sample **inv,**outv; if(inputs <= cntin) - inv = const_cast<R **>(insigs); + inv = const_cast<t_sample **>(insigs); else { // more plug inputs than inlets - I i; - for(i = 0; i < cntin; ++i) tmpin[i] = const_cast<R *>(insigs[i]); + int i; + for(i = 0; i < cntin; ++i) tmpin[i] = const_cast<t_sample *>(insigs[i]); // set dangling inputs to zero // according to mode... (e.g. set zero) @@ -573,11 +635,11 @@ V vst::m_signal(I n,R *const *insigs,R *const *outsigs) inv = tmpin; } - const BL more = outputs <= cntout; + const bool more = outputs <= cntout; if(more) // more outlets than plug outputs - outv = const_cast<R **>(outsigs); + outv = const_cast<t_sample **>(outsigs); else { - I i; + int i; for(i = 0; i < cntout; ++i) tmpout[i] = outsigs[i]; for(; i < outputs; ++i) tmpout[i] = vstout[i]; @@ -603,11 +665,11 @@ V vst::m_signal(I n,R *const *insigs,R *const *outsigs) #if 0 -V vst::m_control(const S *ctrl_name,I ctrl_value) +void vst::m_control(const t_symbol *ctrl_name,int ctrl_value) { if(!plug) return; - I parm_num = 0; + int parm_num = 0; if (!*GetString(ctrl_name) || !strlen(GetString(ctrl_name))) { error ("plugin~: control messages must have a name and a value"); @@ -626,26 +688,6 @@ V vst::m_control(const S *ctrl_name,I ctrl_value) #endif -V vst::m_pitchbend(I ctrl_value) -{ - if(plug) plug->AddPitchBend(ctrl_value ); -} - -V vst::m_aftertouch(I ctrl_value) -{ - if(plug) plug->AddAftertouch(ctrl_value ); -} - -V vst::m_programchange(I ctrl_value) -{ - if(plug) plug->AddProgramChange(ctrl_value ); -} - -V vst::ms_program(I p) -{ - if(plug && p >= 0) plug->SetCurrentProgram(p); -} - void vst::mg_progname(int argc,const t_atom *argv) const { if(plug) { @@ -662,7 +704,7 @@ void vst::mg_progname(int argc,const t_atom *argv) const char str[256]; plug->GetProgramName(cat,pnum,str); - A at[3]; + t_atom at[3]; SetInt(at[0],cat); SetInt(at[1],pnum); SetString(at[2],str); @@ -673,12 +715,7 @@ void vst::mg_progname(int argc,const t_atom *argv) const } } -V vst::m_ctrlchange(I control,I ctrl_value) -{ - if(plug) plug->AddControlChange(control,ctrl_value ); -} - -V vst::ms_wintitle(const AtomList &t) +void vst::ms_wintitle(const AtomList &t) { if(plug) { char txt[256]; @@ -692,7 +729,7 @@ V vst::ms_wintitle(const AtomList &t) * may be of use */ -V vst::m_print(I ac,const A *av) +void vst::m_print(int ac,const t_atom *av) { if(!plug) return; @@ -705,7 +742,7 @@ V vst::m_print(I ac,const A *av) if( ac > 0 ) { for( i = 0 ; i < ac ; i++) { if(IsString(av[i])) { - const C *buf = GetString(av[i]); + const char *buf = GetString(av[i]); if ( strcmp( buf , "-params" ) == 0 ) { params = true; } @@ -773,7 +810,7 @@ V vst::m_print(I ac,const A *av) } -V vst::display_parameter(I param,BL showparams) +void vst::display_parameter(int param,bool showparams) { int j = param; /* the Steinberg(tm) way... */ @@ -801,25 +838,25 @@ V vst::display_parameter(I param,BL showparams) } } -V vst::m_pname(I pnum) +void vst::m_pname(int pnum) { if(!plug || pnum < 0 || pnum >= plug->GetNumParams()) return; char name[256]; // how many chars needed? plug->GetParamName(pnum,name); - A at[2]; + t_atom at[2]; SetInt(at[0],pnum); SetString(at[1],name); ToOutAnything(GetOutAttr(),sym_pname,2,at); } // set the value of a parameter -V vst::ms_param(I pnum,F val) +void vst::ms_param(int pnum,float val) { if(!plug || pnum < 0 || pnum >= plug->GetNumParams()) return; - F xval = plug->GetParamValue( pnum ); + float xval = plug->GetParamValue( pnum ); // if(xval <= 1.0f) // What's that???? if(true) { @@ -849,17 +886,17 @@ void vst::ms_params(int argc,const t_atom *argv) } } -V vst::mg_param(I pnum) +void vst::mg_param(int pnum) { if(!plug || pnum < 0 || pnum >= plug->GetNumParams()) return; - A at[2]; + t_atom at[2]; SetInt(at[0],pnum); SetFloat(at[1],plug->GetParamValue(pnum)); ToOutAnything(GetOutAttr(),sym_param,2,at); } -V vst::mg_params(int argc,const t_atom *argv) +void vst::mg_params(int argc,const t_atom *argv) { if(plug) { char str[255]; @@ -877,7 +914,7 @@ V vst::mg_params(int argc,const t_atom *argv) } } -V vst::m_ptext(I pnum) +void vst::m_ptext(int pnum) { if(!plug || pnum < 0 || pnum >= plug->GetNumParams()) return; @@ -885,13 +922,13 @@ V vst::m_ptext(I pnum) memset(display,0,sizeof(display)); plug->GetParamValue(pnum,display); - A at[2]; + t_atom at[2]; SetInt(at[0],pnum); SetString(at[1],display); ToOutAnything(GetOutAttr(),sym_ptext,2,at); } -V vst::m_ptexts(int argc,const t_atom *argv) +void vst::m_ptexts(int argc,const t_atom *argv) { if(plug) { char str[255]; @@ -909,7 +946,7 @@ V vst::m_ptexts(int argc,const t_atom *argv) } } -V vst::m_note(I note,I velocity) +void vst::m_note(int note,int velocity) { if(!plug) return; @@ -918,3 +955,9 @@ V vst::m_note(I note,I velocity) else plug->AddNoteOff(note); } + +void vst::Respond(const t_symbol *sym,int argc,const t_atom *argv) +{ + FLEXT_ASSERT(sym); + ToOutAnything(GetOutAttr(),sym,argc,argv); +} diff --git a/externals/grill/vst/src/main.h b/externals/grill/vst/src/main.h index fab6b622..ffd138ec 100644 --- a/externals/grill/vst/src/main.h +++ b/externals/grill/vst/src/main.h @@ -24,17 +24,5 @@ WARRANTIES, see the file, "license.txt," in this distribution. #error Platform not supported! #endif -typedef void V; -typedef int I; -typedef long L; -typedef unsigned long UL; -typedef float F; -typedef t_sample R; -typedef char C; -typedef bool BL; -typedef t_atom A; -typedef t_symbol S; - - #endif diff --git a/externals/grill/vst/src/vst.rc b/externals/grill/vst/src/vst.rc index bc1a1b94..8f8e368b 100644 --- a/externals/grill/vst/src/vst.rc +++ b/externals/grill/vst/src/vst.rc @@ -46,7 +46,7 @@ BEGIN VALUE "FileDescription", "vst~ external" VALUE "FileVersion", "0,1, 0, 8" VALUE "InternalName", "vst~" - VALUE "LegalCopyright", "Copyright (C) 2003-2004 Thomas Grill" + VALUE "LegalCopyright", "Copyright (C) 2003-2005 Thomas Grill" VALUE "OriginalFilename", "vst~.DLL" VALUE "ProductName", "VST plugin object" VALUE "ProductVersion", "0, 1, 0, 8" diff --git a/externals/grill/vst/src/vstedit.cpp b/externals/grill/vst/src/vstedit.cpp new file mode 100644 index 00000000..804e83ca --- /dev/null +++ b/externals/grill/vst/src/vstedit.cpp @@ -0,0 +1,76 @@ +/*
+vst~ - VST plugin object for PD
+based on the work of Jarno Seppänen and Mark Williamson
+
+Copyright (c)2003-2005 Thomas Grill (gr@grrrr.org)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+*/
+
+#include "vsthost.h"
+#include "editor.h"
+
+
+void VSTPlugin::Edit(bool open)
+{
+ if(Is()) {
+ if(open) {
+ if(HasEditor() && !IsEdited())
+ StartEditor(this);
+ }
+ else if(IsEdited())
+ StopEditor(this);
+ }
+}
+
+void VSTPlugin::StartEditing(WHandle h)
+{
+ FLEXT_ASSERT(h != NULL);
+ Dispatch(effEditOpen,0,0,hwnd = h);
+// Dispatch(effEditTop);
+
+ TitleEditor(this,title.c_str());
+}
+
+void VSTPlugin::StopEditing()
+{
+ if(Is()) {
+ Dispatch(effEditClose);
+ hwnd = NULL;
+ }
+}
+
+void VSTPlugin::Visible(bool vis)
+{
+ if(Is() && IsEdited()) ShowEditor(this,vis);
+}
+
+bool VSTPlugin::IsVisible() const
+{
+ return Is() && IsEdited() && IsEditorShown(this);
+}
+
+
+void VSTPlugin::SetPos(int x,int y,bool upd)
+{
+ if(Is()) {
+ posx = x; posy = y;
+ if(upd && IsEdited()) MoveEditor(this,posx,posy);
+ }
+}
+
+void VSTPlugin::SetCaption(bool c)
+{
+ if(Is()) {
+ caption = c;
+ if(IsEdited()) CaptionEditor(this,c);
+ }
+}
+
+void VSTPlugin::SetTitle(const char *t)
+{
+ if(Is()) {
+ title = t;
+ if(IsEdited()) TitleEditor(this,t);
+ }
+}
diff --git a/externals/grill/vst/src/vsthost.cpp b/externals/grill/vst/src/vsthost.cpp index 0d883cd9..2c4f0643 100644 --- a/externals/grill/vst/src/vsthost.cpp +++ b/externals/grill/vst/src/vsthost.cpp @@ -2,94 +2,113 @@ vst~ - VST plugin object for PD based on the work of Jarno Seppänen and Mark Williamson -Copyright (c)2003-2004 Thomas Grill (xovo@gmx.net) +Copyright (c)2003-2005 Thomas Grill (gr@grrrr.org) For information on usage and redistribution, and for a DISCLAIMER OF ALL WARRANTIES, see the file, "license.txt," in this distribution. */ -#include "editor.h" #include "vsthost.h" -#include "AEffectx.h" -#include <ctype.h> -typedef AEffect *(VSTCALLBACK *PVSTMAIN)(audioMasterCallback audioMaster); - - - -VSTPlugin::VSTPlugin(): - h_dll(NULL),hwnd(NULL),_pEffect(NULL), - posx(0),posy(0),caption(true), - _midichannel(0),queue_size(0), - paramnamecnt(0) +const t_symbol + *VSTPlugin::sym_event, + *VSTPlugin::sym_evmidi, + *VSTPlugin::sym_evaudio, + *VSTPlugin::sym_evvideo, + *VSTPlugin::sym_evparam, + *VSTPlugin::sym_evtrigger, + *VSTPlugin::sym_evsysex, + *VSTPlugin::sym_ev_, + *VSTPlugin::sym_midi[8]; + +void VSTPlugin::Setup() +{ + sym_event = flext::MakeSymbol("event"); + sym_evmidi = flext::MakeSymbol("midi"); + sym_evaudio = flext::MakeSymbol("audio"); + sym_evvideo = flext::MakeSymbol("video"); + sym_evparam = flext::MakeSymbol("param"); + sym_evtrigger = flext::MakeSymbol("trigger"); + sym_evsysex = flext::MakeSymbol("sysex"); + sym_ev_ = flext::MakeSymbol("???"); + + sym_midi[0] = flext::MakeSymbol("noteon"); + sym_midi[1] = flext::MakeSymbol("noteoff"); + sym_midi[2] = flext::MakeSymbol("polyafter"); + sym_midi[3] = flext::MakeSymbol("cntl"); + sym_midi[4] = flext::MakeSymbol("progchg"); + sym_midi[5] = flext::MakeSymbol("chnafter"); + sym_midi[6] = flext::MakeSymbol("pitchbend"); + sym_midi[7] = sym__; +} + +VSTPlugin::VSTPlugin(Responder *resp) + : hdll(NULL),hwnd(NULL) + , effect(NULL),pluginmain(NULL),audiomaster(NULL) + , responder(resp) + , posx(0),posy(0),caption(true) + , midichannel(0),eventqusz(0) + , paramnamecnt(0) + , transchg(true) + , playing(false),looping(false) + , samplerate(0) + , samplepos(0),ppqpos(0) + , tempo(120) + , timesignom(4),timesigden(4) + , barstartpos(0) + , cyclestartpos(0),cycleendpos(0) + , smpteoffset(0),smpterate(0) {} VSTPlugin::~VSTPlugin() { - Free(); // Call free + Free(); } - -void VSTPlugin::FreeVST(MHandle handle) -{ -#if FLEXT_OS == FLEXT_OS_WIN - FreeLibrary(handle); -#elif FLEXT_OS == FLEXT_OS_MAC -#else -#error Platform not supported -#endif -} + #if FLEXT_OS == FLEXT_OS_MAC -OSStatus FSPathMakeFSSpec( - const UInt8 *path, - FSSpec *spec, - Boolean *isDirectory) /* can be NULL */ +OSStatus FSPathMakeFSSpec(const UInt8 *path,FSSpec *spec,Boolean *isDirectory) /* can be NULL */ { - OSStatus result; - FSRef ref; - - /* check parameters */ - require_action(NULL != spec, BadParameter, result = paramErr); - - /* convert the POSIX path to an FSRef */ - result = FSPathMakeRef(path, &ref, isDirectory); - require_noerr(result, FSPathMakeRef); - - /* and then convert the FSRef to an FSSpec */ - result = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL); - require_noerr(result, FSGetCatalogInfo); + OSStatus result; + FSRef ref; + + /* check parameters */ + require_action(NULL != spec, BadParameter, result = paramErr); + + /* convert the POSIX path to an FSRef */ + result = FSPathMakeRef(path, &ref, isDirectory); + require_noerr(result, FSPathMakeRef); + + /* and then convert the FSRef to an FSSpec */ + result = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL); + require_noerr(result, FSGetCatalogInfo); FSGetCatalogInfo: FSPathMakeRef: BadParameter: - - return ( result ); + return result; } #endif -static long uniqueid = 0; - -int VSTPlugin::Instance(const char *dllname,const char *subname) +// hdll, pluginmain and audiomaster are set here +// must be NULL beforehand! +bool VSTPlugin::NewPlugin(const char *plugname) { -#ifdef FLEXT_DEBUG - flext::post("New Plugin 1 - %x",this); -#endif + FLEXT_ASSERT(!hdll && !pluginmain && !audiomaster); + + dllname = plugname; - PVSTMAIN pluginmain; #if FLEXT_OS == FLEXT_OS_WIN - h_dll = LoadLibrary(dllname); - if(!h_dll) - return VSTINSTANCE_ERR_NO_VALID_FILE; + hdll = LoadLibrary(dllname.c_str()); + if(hdll) pluginmain = (PVSTMAIN)GetProcAddress(hdll,"main"); + audiomaster = Master; - pluginmain = (PVSTMAIN)GetProcAddress(h_dll,"main"); - void *audioMasterFPtr = Master; - #elif FLEXT_OS == FLEXT_OS_MAC short resFileID; FSSpec spec; OSErr err; - err = FSPathMakeFSSpec(dllname,&spec,NULL); + err = FSPathMakeFSSpec(dllname.c_str(),&spec,NULL); resFileID = FSpOpenResFile(&spec, fsRdPerm); short cResCB = Count1Resources('aEff'); @@ -104,7 +123,7 @@ int VSTPlugin::Instance(const char *dllname,const char *subname) OSType resType; codeH = Get1IndResource('aEff', short(i+1)); - if (!codeH) continue; + if(!codeH) continue; GetResInfo(codeH, &resID, &resType, fragName); DetachResource(codeH); @@ -116,7 +135,7 @@ int VSTPlugin::Instance(const char *dllname,const char *subname) kPrivateCFragCopy, &connID, (Ptr *) & mainAddr, errName); - if (!err) { + if(!err) { #ifdef __CFM__ pluginmain = (PVSTMAIN)NewMachOFromCFM(mainAddr); #else @@ -124,10 +143,9 @@ int VSTPlugin::Instance(const char *dllname,const char *subname) #endif } } - CloseResFile(resFileID); - void *audioMasterFPtr = + audiomaster = #ifdef __CFM__ NewCFMFromMachO(Master); #else @@ -138,702 +156,190 @@ int VSTPlugin::Instance(const char *dllname,const char *subname) #error Platform not supported #endif - if(!pluginmain) { - FreeVST(h_dll); - _pEffect = NULL; - return VSTINSTANCE_ERR_NO_VST_PLUGIN; - } - - - uniqueid = 0; - - //This calls the "main" function and receives the pointer to the AEffect structure. - _pEffect = pluginmain((audioMasterCallback)audioMasterFPtr); - if(!_pEffect || _pEffect->magic != kEffectMagic) { - post("VST plugin : Unable to create effect"); - - _pEffect = NULL; - FreeVST(h_dll); - h_dll = NULL; - return VSTINSTANCE_ERR_REJECTED; - } - - if(subname && *subname && Dispatch(effGetPlugCategory) == kPlugCategShell) { - // scan shell for subplugins - char tempName[64]; - char idname[5]; idname[4] = 0; - while((uniqueid = Dispatch(effShellGetNextPlugin,0,0,tempName))) { - // subplug needs a name - *(long *)idname = uniqueid; - post("plug %s - %s",idname,tempName); - if(!strcmp(subname,tempName) || !strcmp(subname,idname)) break; - } - } - - if(uniqueid) { - // re-init with uniqueID set - _pEffect = pluginmain((audioMasterCallback)audioMasterFPtr); - if(!_pEffect || _pEffect->magic != kEffectMagic) { - post("VST plugin : Unable to create effect"); - - _pEffect = NULL; - FreeVST(h_dll); - h_dll = NULL; - return VSTINSTANCE_ERR_REJECTED; - } + if(hdll && pluginmain && audiomaster) + return true; + else { + FreePlugin(); + return false; } +} +void VSTPlugin::FreePlugin() +{ +#if FLEXT_OS == FLEXT_OS_WIN + if(hdll) FreeLibrary(hdll); +#elif FLEXT_OS == FLEXT_OS_MAC + #ifdef __MACOSX__ #ifdef __CFM__ - DisposeCFMFromMachO(audioMasterFPtr); - DisposeMachOFromCFM(pluginmain); -#endif + if(audiomaster) DisposeCFMFromMachO(audiomaster); + if(pluginmain) DisposeMachOFromCFM(pluginmain); #endif - - - //init plugin - _pEffect->user = this; - - long ret = Dispatch( effOpen ); - FLEXT_ASSERT(!ret); - - ret = Dispatch( effIdentify); - FLEXT_ASSERT(ret == 'NvEf'); - - *_sProductName = 0; - ret = Dispatch( effGetProductString, 0, 0, _sProductName, 0.0f); - if(!*_sProductName) { - // no product name given by plugin -> extract it from the filename - - std::string str1(dllname); - std::string::size_type slpos = str1.rfind('\\'); - if(slpos == std::string::npos) { - slpos = str1.rfind('/'); - if(slpos == std::string::npos) - slpos = 0; - else - ++slpos; - } - else - ++slpos; - std::string str2 = str1.substr(slpos); - int snip = str2.find('.'); - if( snip != std::string::npos ) - str1 = str2.substr(0,snip); - else - str1 = str2; - strcpy(_sProductName,str1.c_str()); - } - - if(*_sProductName) { - char tmp[512]; - sprintf(tmp,"vst~ - %s",_sProductName); - title = tmp; - } - else - title = "vst~"; - - *_sVendorName = 0; - Dispatch( effGetVendorString, 0, 0,_sVendorName, 0.0f); - - _sDllName = dllname; - -#ifdef FLEXT_DEBUG - flext::post("New Plugin 2 - %x",this); #endif - return VSTINSTANCE_NO_ERROR; -} +#else +#error Platform not supported +#endif + effect = NULL; + audiomaster = NULL; + pluginmain = NULL; + hdll = NULL; +} /* -void VSTPlugin::Create(VSTPlugin *plug) -{ - h_dll = plug->h_dll; - _pEffect = plug->_pEffect; - _pEffect->user = this; - - Dispatch( effMainsChanged, 0, 1); -// 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; -} +This is static to be able to communicate between the plugin methods +and the static Audiomaster function +the this (plugin->user) pointer has not been initialized at the point it is needed +static should not be a problem, as we are single-threaded and it is immediately +queried in a called function */ +long VSTPlugin::uniqueid = 0; -void VSTPlugin::Free() // Called also in destruction -{ - if(Is()) { - if(IsEdited()) StopEditor(this); - - // shut down plugin - Dispatch(effMainsChanged, 0, 0); - Dispatch(effClose); - -#ifdef FLEXT_DEBUG - flext::post("Free Plugin 1 - %x",this); -#endif - - _pEffect = NULL; - - // \TODO - // Here, we really have to wait until the editor thread has terminated - // otherwise WM_DESTROY etc. messages may still be pending - // in other words: this is a design flaw - // There should be a data stub accessible from the plugin object and the thread - // holding the necessary data, so that both can operate independently - - if(h_dll) { - FreeVST(h_dll); - h_dll = NULL; - } - -#ifdef FLEXT_DEBUG - flext::post("Free Plugin 2 - %x",this); -#endif - } -} - -void VSTPlugin::DspInit(float samplerate,int blocksize) -{ - // sample rate and block size must _first_ be set - Dispatch(effSetSampleRate, 0, 0,NULL,samplerate); - Dispatch(effSetBlockSize, 0, blocksize); - // than signal that mains have changed! - Dispatch(effMainsChanged, 0, 1); -} +std::string VSTPlugin::dllloading; -static void striptrail(char *txt) +bool VSTPlugin::InstPlugin(long plugid) { - // strip trailing whitespace - for(int i = strlen(txt)-1; i >= 0; --i) - // cast to unsigned char since isspace functions don't want characters like 0x80 = -128 - if(isspace(((unsigned char *)txt)[i])) txt[i] = 0; -} + uniqueid = plugid; + dllloading = dllname; -void VSTPlugin::GetParamName(int numparam,char *name) const -{ - if(numparam < GetNumParams()) { - name[0] = 0; - Dispatch(effGetParamName,numparam,0,name,0.0f); - striptrail(name); - } - else - name[0] = 0; -} + FLEXT_ASSERT(pluginmain && audiomaster); -bool VSTPlugin::SetParamFloat(int parameter,float value) -{ - if(Is() && parameter >= 0 && parameter < GetNumParams()) { - _pEffect->setParameter(_pEffect,parameter,value); - return true; - } - else + //This calls the "main" function and receives the pointer to the AEffect structure. + effect = pluginmain(audiomaster); + if(!effect || effect->magic != kEffectMagic) { + post("VST plugin : Unable to create effect"); + effect = NULL; return false; -} - -void VSTPlugin::GetParamValue(int numparam,char *parval) const -{ - if(Is()) { - if(numparam < GetNumParams()) { - // how many chars needed? - char par_display[64]; par_display[0] = 0; - Dispatch(effGetParamDisplay,numparam,0,par_display,0.0f); -// if(par_display[7]) par_display[8] = 0; // set trailing zero - - // how many chars needed? - char par_label[64]; par_label[0] = 0; - Dispatch(effGetParamLabel,numparam,0,par_label,0.0f); - striptrail(par_label); -// if(par_label[7]) par_label[8] = 0; // set trailing zero - - sprintf(parval,"%s%s",par_display,par_label); - } - else - strcpy(parval,"Index out of range"); } - else - strcpy(parval,"Plugin not loaded"); -} - -float VSTPlugin::GetParamValue(int numparam) const -{ - if(Is() && numparam < GetNumParams()) - return _pEffect->getParameter(_pEffect, numparam); - else - return -1.0; + return true; } -void VSTPlugin::ScanParams(int cnt) +bool VSTPlugin::Instance(const char *name,const char *subname) { - if(cnt < 0) cnt = GetNumParams(); - if(paramnamecnt >= cnt) return; - if(cnt >= GetNumParams()) cnt = GetNumParams(); - - char name[64]; - for(int i = paramnamecnt; i < cnt; ++i) { - GetParamName(i,name); - if(*name) paramnames[std::string(name)] = i; + bool ok = effect != NULL; + + if(!ok && dllname != name) { + FreePlugin(); + // freshly load plugin + ok = NewPlugin(name) && InstPlugin(); } - paramnamecnt = cnt; -} - -int VSTPlugin::GetParamIx(const char *p) const -{ - NameMap::const_iterator it = paramnames.find(std::string(p)); - return it == paramnames.end()?-1:it->second; -} -void VSTPlugin::Edit(bool open) -{ - if(Is()) { - if(open) { - if(HasEditor() && !IsEdited()) - StartEditor(this); - } - else if(IsEdited()) - StopEditor(this); - } -} + if(ok && subname && *subname && Dispatch(effGetPlugCategory) == kPlugCategShell) { + // sub plugin-name given -> scan plugs -void VSTPlugin::StartEditing(WHandle h) -{ - FLEXT_ASSERT(h != NULL); - Dispatch(effEditOpen,0,0,hwnd = h); -// Dispatch(effEditTop); - - TitleEditor(this,title.c_str()); -} + long plugid; + char tmp[64]; + // scan shell for subplugins + while((plugid = Dispatch(effShellGetNextPlugin,0,0,tmp))) { + // subplug needs a name + FLEXT_LOG1("subplug %s",tmp); + if(!strcmp(subname,tmp)) + // found + break; + } -void VSTPlugin::StopEditing() -{ - if(Is()) { - Dispatch(effEditClose); - hwnd = NULL; + // re-init with plugid set + if(plugid) ok = InstPlugin(plugid); } -} - -void VSTPlugin::Visible(bool vis) -{ - if(Is() && IsEdited()) ShowEditor(this,vis); -} - -bool VSTPlugin::IsVisible() const -{ - return Is() && IsEdited() && IsEditorShown(this); -} - -bool VSTPlugin::AddMIDI(unsigned char data0,unsigned char data1,unsigned char data2) -{ - if(Is()) { - 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(Is() && queue_size > 0) { - // Prepare MIDI events and free queue dispatching all events - events.numEvents = queue_size; - events.reserved = 0; - for(int q = 0; q < queue_size; q++) - events.events[q] = (VstEvent*)&midievent[q]; - - Dispatch(effProcessEvents, 0, 0, &events, 0.0f); - queue_size = 0; - } -} - -static int range(int value,int mn = 0,int mx = 127) -{ - return value < mn?mn:(value > mx?mx:value); -} - -bool VSTPlugin::AddNoteOn( unsigned char note,unsigned char speed,unsigned char midichannel) -{ - return AddMIDI((char)MIDI_NOTEON | midichannel,note,speed); -} - -bool VSTPlugin::AddNoteOff( unsigned char note,unsigned char midichannel) -{ - return AddMIDI((char)MIDI_NOTEOFF | midichannel,note,0); -} -void VSTPlugin::AddAftertouch(int value) -{ - AddMIDI( (char)MIDI_NOTEOFF | _midichannel , range(value) ); -} - -void VSTPlugin::AddPitchBend(int value) -{ - AddMIDI( MIDI_PITCHBEND + (_midichannel & 0xf) , ((value>>7) & 127), (value & 127)); -} - -void VSTPlugin::AddProgramChange(int value) -{ - AddMIDI( MIDI_PROGRAMCHANGE + (_midichannel & 0xf), range(value), 0); -} - -void VSTPlugin::AddControlChange(int control, int value) -{ - AddMIDI( MIDI_CONTROLCHANGE + (_midichannel & 0xf), range(control), range(value)); -} - - -bool VSTPlugin::GetProgramName( int cat , int p, char *buf) const -{ - buf[0] = 0; - int parameter = p; - if(parameter < GetNumPrograms() && cat < GetNumCategories()) { - Dispatch(effGetProgramNameIndexed,parameter,cat,buf,0.0f); - striptrail(buf); - return true; - } - else - return false; -} - -void VSTPlugin::SetPos(int x,int y,bool upd) -{ - if(Is()) { - posx = x; posy = y; - if(upd && IsEdited()) MoveEditor(this,posx,posy); + if(ok) { + //init plugin + effect->user = this; + ok = Dispatch(effOpen) == 0; } -} -void VSTPlugin::SetCaption(bool c) -{ - if(Is()) { - caption = c; - if(IsEdited()) CaptionEditor(this,c); + if(ok) { + ok = Dispatch(effIdentify) == 'NvEf'; } -} -void VSTPlugin::SetTitle(const char *t) -{ - if(Is()) { - title = t; - if(IsEdited()) TitleEditor(this,t); - } -} + if(ok) { + *productname = 0; + long ret = Dispatch(effGetProductString,0,0,productname); + + if(!*productname) { + // no product name given by plugin -> extract it from the filename + + std::string str1(dllname); + std::string::size_type slpos = str1.rfind('\\'); + if(slpos == std::string::npos) { + slpos = str1.rfind('/'); + if(slpos == std::string::npos) + slpos = 0; + else + ++slpos; + } + else + ++slpos; + std::string str2 = str1.substr(slpos); + int snip = str2.find('.'); + if( snip != std::string::npos ) + str1 = str2.substr(0,snip); + else + str1 = str2; + strcpy(productname,str1.c_str()); + } + + if(*productname) { + char tmp[512]; + sprintf(tmp,"vst~ - %s",productname); + title = tmp; + } + else + title = "vst~"; -void VSTPlugin::processReplacing( float **inputs, float **outputs, long sampleframes ) -{ - _pEffect->processReplacing( _pEffect , inputs , outputs , sampleframes ); -} + *vendorname = 0; + Dispatch(effGetVendorString,0,0,vendorname); + } -void VSTPlugin::process( float **inputs, float **outputs, long sampleframes ) -{ - _pEffect->process( _pEffect , inputs , outputs , sampleframes ); + if(!ok) Free(); + return ok; } -#if 1 - -// Host callback dispatcher -long VSTPlugin::Master(AEffect *effect, long opcode, long index, long value, void *ptr, float opt) +void VSTPlugin::Free() // Called also in destruction { -#if 0 - audioMasterEnum op = (audioMasterEnum)opcode; - audioMasterEnumx opx = (audioMasterEnumx)opcode; -#endif - -#ifdef FLEXT_DEBUG - post("VST -> host: Eff = 0x%.8X, Opcode = %d, Index = %d, Value = %d, PTR = %.8X, OPT = %.3f\n",(int)effect, opcode,index,value,(int)ptr,opt); -#endif - -// VSTPlugin *th = effect?(VSTPlugin *)effect->user:NULL; + if(effect) { + Edit(false); - switch (opcode) { - case audioMasterAutomate: // 0 -#ifdef FLEXT_DEBUG - post("Automate index=%li value=%li opt=%f",index,value,opt); -#endif - // index, value given - //! \todo set effect parameter - return 0; - case audioMasterVersion: // 1 - // support VST 2.3 - return 2300; -// return 2; - case audioMasterCurrentId: { // 2 - return uniqueid; + // shut down plugin + Dispatch(effMainsChanged, 0, 0); + Dispatch(effClose); } - case audioMasterIdle: // 3 - effect->dispatcher(effect, effEditIdle, 0, 0, NULL, 0.0f); - return 0; - case audioMasterPinConnected: // 4 - //! \todo set connection state correctly (if possible..) - // index=pin, value=0..input, else..output -#ifdef FLEXT_DEBUG - post("Pin connected pin=%li conn=%li",index,value); -#endif - return 0; // 0 means connected - case audioMasterWantMidi: // 6 -#ifdef FLEXT_DEBUG - post("Want MIDI = %li",value); -#endif - return 0; // VST header says: "currently ignored" - case audioMasterGetTime: // 7 - return 0; // not supported - case audioMasterProcessEvents: { // 8 - // VST event data from plugin - VstEvent *ev = static_cast<VstEvent *>(ptr); - if(ev->type == kVstMidiType) { - VstMidiEvent *mev = static_cast<VstMidiEvent *>(ptr); -#ifdef FLEXT_DEBUG - if(mev->byteSize == 24) - post("MIDI event delta=%li len=%li offs=%li detune=%i offvel=%i",mev->deltaFrames,mev->noteLength,mev->noteOffset,(int)mev->detune,(int)mev->noteOffVelocity); - else - // has incorrect size - post("MIDI event"); -#endif - } - else { -#ifdef FLEXT_DEBUG - post("VST event type=%li",ev->type); -#endif - } - return 1; - } - case audioMasterSetTime: { // 9 - VstTimeInfo *tminfo = static_cast<VstTimeInfo *>(ptr); -#ifdef FLEXT_DEBUG - post("TimeInfo pos=%lf rate=%lf filter=%li",tminfo->samplePos,tminfo->sampleRate,value); -#endif - return 0; // not supported - } - case audioMasterTempoAt: // 10 - return 0; // not supported - case audioMasterGetNumAutomatableParameters: // 11 - return 0; // not supported - case audioMasterSizeWindow: // 15 - return 0; -// case audioMasterGetSampleRate: // 16 -// case audioMasterGetBlockSize: // 17 - case audioMasterGetCurrentProcessLevel: // 23 - // return thread state - return flext::GetThreadId() == flext::GetSysThreadId()?2:1; - case audioMasterGetVendorString: // 32 - strcpy((char*)ptr,"grrrr.org"); - return 0; - case audioMasterGetProductString: // 33 - strcpy((char *)ptr,"vst~ host external"); - return 0; - case audioMasterGetVendorVersion: // 34 - return 100; - case audioMasterCanDo: // 37 -#ifdef FLEXT_DEBUG - post("\taudioMasterCanDo PTR = %s",ptr); -#endif - if(!strcmp((char *)ptr,"sendVstEvents")) - return 1; - else if(!strcmp((char *)ptr,"sendVstMidiEvent")) - return 1; - else if(!strcmp((char *)ptr,"sendVstTimeInfo")) - return 1; // NOT YET - else if(!strcmp((char *)ptr,"receiveVstEvents")) - return 1; - else if(!strcmp((char *)ptr,"receiveVstMidiEvent")) - return 1; - else if(!strcmp((char *)ptr,"receiveVstTimeInfo")) - return 1; // NOT YET - else if(!strcmp((char *)ptr,"reportConnectionChanges")) - return 0; // \TODO PD has hard times supporting that... - else if(!strcmp((char *)ptr,"acceptIOChanges")) - return 0; // \TODO what does this means exactly? - else if(!strcmp((char *)ptr,"supplyIdle")) - return 1; - else if(!strcmp((char *)ptr,"sizeWindow")) - return 1; - else if(!strcmp((char *)ptr,"supportShell")) - return 0; // deprecated - new one is shellCategory - else if(!strcmp((char *)ptr,"offline")) - return 0; // not supported - else if(!strcmp((char *)ptr,"asyncProcessing")) - return 0; // not supported - else if(!strcmp((char *)ptr,"shellCategory")) - return 1; // supported! - - return 0; // not supported - case audioMasterGetLanguage: // 38 - return kVstLangEnglish; - case audioMasterGetDirectory: // 41 - // return full path of plugin - return 0; // not supported - case audioMasterUpdateDisplay: // 42 -#ifdef FLEXT_DEBUG - post("UPDATE DISPLAY"); -#endif - return 0; - default: -#ifdef FLEXT_DEBUG - post("Unknown opcode %li",opcode); -#endif - return 0; - } -} + // \TODO + // Here, we really have to wait until the editor thread has terminated + // otherwise WM_DESTROY etc. messages may still be pending + // in other words: this is a design flaw + // There should be a data stub accessible from the plugin object and the thread + // holding the necessary data, so that both can operate independently -#else + FreePlugin(); +} -// Host callback dispatcher -long VSTPlugin::Master(AEffect *effect, long opcode, long index, long value, void *ptr, float opt) +void VSTPlugin::DspInit(float sr,int blsz) { - VSTPlugin *th = effect?(VSTPlugin *)effect->user:NULL; - if(!th) FLEXT_LOG("No this"); - -#ifdef FLEXT_DEBUG - if(opcode != audioMasterGetTime) - 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); -#endif - - // Support opcodes - switch(opcode) - { - case audioMasterAutomate: - return 0; // index, value, returns 0 - - case audioMasterVersion: - return 2; // vst version, currently 7 (0 for older) - - case audioMasterCurrentId: - return subplugid; - - 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: - if(value == 0) - return index < 2?0:1; //input - else - return index < 2?0:1; //output - -/* - 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 = th?th->sample_rate:0; - return (long)&_timeInfo; - - - case audioMasterTempoAt: - return 0; - - case audioMasterNeedIdle: -// effect->dispatcher(effect, effIdle, 0, 0, NULL, 0.0f); - return 1; - - case audioMasterGetSampleRate: - return th?(long)th->sample_rate:0; - - 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; + // sample rate and block size must _first_ be set + Dispatch(effSetSampleRate,0,0,NULL,samplerate = sr); + Dispatch(effSetBlockSize, 0,blsz); + // then signal that mains have changed! + Dispatch(effMainsChanged,0,1); +} + +void VSTPlugin::ListPlugs(const t_symbol *sym) const +{ + if(responder) { + if(Is() && Dispatch(effGetPlugCategory) == kPlugCategShell) { + t_atom at; + // sub plugin-name given -> scan plugs + char tmp[64]; + // scan shell for subplugins + while(Dispatch(effShellGetNextPlugin,0,0,tmp)) { + SetString(at,tmp); + responder->Respond(sym,1,&at); + } + } - case audioMasterGetLanguage: - return kVstLangEnglish; - - case audioMasterUpdateDisplay: - FLEXT_LOG("audioMasterUpdateDisplay"); - effect->dispatcher(effect, effEditIdle, 0, 0, NULL, 0.0f); - return 0; - - case audioMasterCanDo: - if (!strcmp((char *)ptr,"sendVstEvents")) return 1; - else if (!strcmp((char *)ptr,"sendVstMidiEvent")) return 1; - else if (!strcmp((char *)ptr,"sendVstTimeInfo")) return 1; -// "receiveVstEvents", -// "receiveVstMidiEvent", -// "receiveVstTimeInfo", - -// "reportConnectionChanges", -// "acceptIOChanges", -// else if (!strcmp((char*)ptr,"sizeWindow")) return 1; - else if (!strcmp((char*)ptr,"supplyIdle")) return 1; - return -1; - - case audioMasterSetTime: FLEXT_LOG("VST master dispatcher: Set Time");break; - case audioMasterGetNumAutomatableParameters: FLEXT_LOG("VST master dispatcher: GetNumAutPar");break; - case audioMasterGetParameterQuantization: FLEXT_LOG("VST master dispatcher: ParamQuant");break; - case audioMasterIOChanged: FLEXT_LOG("VST master dispatcher: IOchanged");break; - case audioMasterSizeWindow: FLEXT_LOG("VST master dispatcher: Size Window");break; - case audioMasterGetBlockSize: FLEXT_LOG("VST master dispatcher: GetBlockSize");break; - case audioMasterGetInputLatency: FLEXT_LOG("VST master dispatcher: GetInLatency");break; - case audioMasterGetOutputLatency: FLEXT_LOG("VST master dispatcher: GetOutLatency");break; - case audioMasterGetPreviousPlug: FLEXT_LOG("VST master dispatcher: PrevPlug");break; - case audioMasterGetNextPlug: FLEXT_LOG("VST master dispatcher: NextPlug");break; - case audioMasterWillReplaceOrAccumulate: FLEXT_LOG("VST master dispatcher: WillReplace"); break; - case audioMasterGetCurrentProcessLevel: return 0; break; - case audioMasterGetAutomationState: FLEXT_LOG("VST master dispatcher: GetAutState");break; - case audioMasterOfflineStart: FLEXT_LOG("VST master dispatcher: Offlinestart");break; - case audioMasterOfflineRead: FLEXT_LOG("VST master dispatcher: Offlineread");break; - case audioMasterOfflineWrite: FLEXT_LOG("VST master dispatcher: Offlinewrite");break; - case audioMasterOfflineGetCurrentPass: FLEXT_LOG("VST master dispatcher: OfflineGetcurrentpass");break; - case audioMasterOfflineGetCurrentMetaPass: FLEXT_LOG("VST master dispatcher: GetGetCurrentMetapass");break; - case audioMasterSetOutputSampleRate: FLEXT_LOG("VST master dispatcher: Setsamplerate");break; - case audioMasterGetSpeakerArrangement: FLEXT_LOG("VST master dispatcher: Getspeaker");break; - case audioMasterSetIcon: FLEXT_LOG("VST master dispatcher: seticon");break; - case audioMasterOpenWindow: FLEXT_LOG("VST master dispatcher: OpenWindow");break; - case audioMasterCloseWindow: FLEXT_LOG("VST master dispatcher: CloseWindow");break; - case audioMasterGetDirectory: FLEXT_LOG("VST master dispatcher: GetDirectory");break; -// case audioMasterUpdateDisplay: post("VST master dispatcher: audioMasterUpdateDisplay");break; - -#ifdef FLEXT_DEBUG - default: - post("VST master dispatcher: undefed: %d , %d",opcode , effKeysRequired ); -#endif - } - - return 0; + // bang + responder->Respond(sym); + } } - -#endif diff --git a/externals/grill/vst/src/vsthost.h b/externals/grill/vst/src/vsthost.h index 185a7113..8dc20394 100644 --- a/externals/grill/vst/src/vsthost.h +++ b/externals/grill/vst/src/vsthost.h @@ -2,7 +2,7 @@ vst~ - VST plugin object for PD based on the work of Jarno Seppänen and Mark Williamson -Copyright (c)2003-2004 Thomas Grill (xovo@gmx.net) +Copyright (c)2003-2005 Thomas Grill (gr@grrrr.org) For information on usage and redistribution, and for a DISCLAIMER OF ALL WARRANTIES, see the file, "license.txt," in this distribution. */ @@ -11,9 +11,13 @@ WARRANTIES, see the file, "license.txt," in this distribution. #define __VSTHOST_H #include <flext.h> +#include <string> +#include <map> +#include <math.h> + #include "AEffectx.h" #include "AEffEditor.hpp" -#include <string> + #if FLEXT_OS == FLEXT_OS_WIN #include <windows.h> @@ -28,51 +32,57 @@ typedef void *MHandle; #endif -#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 +#define MIDI_MAX_EVENTS 64 +class Responder +{ +public: + virtual void Respond(const t_symbol *sym,int argc = 0,const t_atom *argv = NULL) = 0; +}; class VSTPlugin: public flext { public: - VSTPlugin(); + static void Setup(); + + VSTPlugin(Responder *resp); ~VSTPlugin(); - int Instance(const char *dllname,const char *subplug = NULL); + bool Instance(const char *plug,const char *subplug = NULL); void Free(); void DspInit(float samplerate,int blocksize); - bool Is() const { return _pEffect != NULL; } + ////////////////////////////////////////////////////////////////////////////// + +public: + bool Is() const { return effect != NULL; } - long GetVersion() const { return _pEffect?_pEffect->version:0; } + long GetVersion() const { return effect?effect->version:0; } bool IsSynth() const { return HasFlags(effFlagsIsSynth); } bool IsReplacing() const { return HasFlags(effFlagsCanReplacing); } bool HasEditor() const { return HasFlags(effFlagsHasEditor); } - const char *GetName() const { return _sProductName; } - const char *GetVendorName() const { return _sVendorName; } - const char *GetDllName() const { return _sDllName.c_str(); } + const char *GetName() const { return productname; } + const char *GetVendorName() const { return vendorname; } + const char *GetDllName() const { return dllname.c_str(); } - int GetNumInputs() const { return _pEffect?_pEffect->numInputs:0; } - int GetNumOutputs() const { return _pEffect?_pEffect->numOutputs:0; } + int GetNumInputs() const { return effect?effect->numInputs:0; } + int GetNumOutputs() const { return effect?effect->numOutputs:0; } - int GetNumParams() const { return _pEffect?_pEffect->numParams:0; } + void ListPlugs(const t_symbol *sym) const; + +private: + char productname[300]; + char vendorname[300]; + std::string dllname; // Contains dll name + + ////////////////////////////////////////////////////////////////////////////// + +public: + int GetNumParams() const { return effect?effect->numParams:0; } void GetParamName(int numparam,char *name) const; void GetParamValue(int numparam,char *parval) const; float GetParamValue(int numparam) const; @@ -89,21 +99,35 @@ public: void SetCurrentProgram(int prg) { Dispatch(effSetProgram,0,prg); } int GetCurrentProgram() const { return Dispatch(effGetProgram); } - int GetNumPrograms() const { return _pEffect->numPrograms; } + int GetNumPrograms() const { return effect->numPrograms; } int GetNumCategories() const { return Dispatch(effGetNumProgramCategories); } - bool GetProgramName( int cat, int p , char* buf) const; + bool GetProgramName(int cat,int p,char* buf) const; + +private: + struct NameCmp: + std::less<std::string> + { + bool operator()(const std::string &a,const std::string &b) const { return a.compare(b) < 0; } + }; + + typedef std::map<std::string,int,NameCmp> NameMap; + int paramnamecnt; + NameMap paramnames; + ////////////////////////////////////////////////////////////////////////////// - bool AddMIDI(unsigned char data0,unsigned char data1=0,unsigned char data2=0); +public: + void SetPos(int x,int y,bool upd = true); + void SetX(int x,bool upd = true) { SetPos(x,posy,upd); } + void SetY(int y,bool upd = true) { SetPos(posx,y,upd); } + int GetX() const { return posx; } + int GetY() const { return posy; } + void SetCaption(bool b); + bool GetCaption() const { return caption; } + void SetTitle(const char *t); + const char *GetTitle() const { return title.c_str(); } - bool AddNoteOn( unsigned char note,unsigned char speed,unsigned char midichannel=0); - bool AddNoteOff( unsigned char note,unsigned char midichannel=0); - - void AddControlChange( int control , int value ); - void AddProgramChange( int value ); - void AddPitchBend( int value ); - void AddAftertouch( int value ); void Edit(bool open); @@ -120,64 +144,173 @@ public: void Paint(ERect &r) const { Dispatch(effEditDraw,0,0,&r); } - void processReplacing( float **inputs, float **outputs, long sampleframes ); - void process( float **inputs, float **outputs, long sampleframes ); +private: + int posx,posy; // Window position + bool caption; // Window border + std::string title; // Window title - long Dispatch(long opCode, long index = 0, long value = 0, void *ptr = NULL, float opt = 0) const - { - return Is()?_pEffect->dispatcher(_pEffect, opCode, index, value, ptr, opt):0; - } + ////////////////////////////////////////////////////////////////////////////// - static long VSTCALLBACK Master(AEffect *effect, long opcode, long index, long value, void *ptr, float opt); +public: + enum { + MIDI_NOTEON = 144, + MIDI_NOTEOFF = 128, + MIDI_POLYAFTERTOUCH = 160, + MIDI_CONTROLCHANGE = 176, + MIDI_PROGRAMCHANGE = 192, + MIDI_AFTERTOUCH = 208, + MIDI_PITCHBEND = 224 + }; + + bool AddMIDI(unsigned char data0,unsigned char data1 = 0,unsigned char data2 = 0); - void SetPos(int x,int y,bool upd = true); - void SetX(int x,bool upd = true) { SetPos(x,posy,upd); } - void SetY(int y,bool upd = true) { SetPos(posx,y,upd); } - int GetX() const { return posx; } - int GetY() const { return posy; } - void SetCaption(bool b); - bool GetCaption() const { return caption; } - void SetTitle(const char *t); - const char *GetTitle() const { return title.c_str(); } + static int range(int value,int mn = 0,int mx = 127) { return value < mn?mn:(value > mx?mx:value); } -protected: + bool AddNoteOn(unsigned char note,unsigned char speed,unsigned char midichannel = 0) + { + return AddMIDI((char)MIDI_NOTEON|midichannel,note,speed); + } - MHandle h_dll; - WHandle hwnd; + bool AddNoteOff(unsigned char note,unsigned char midichannel = 0) + { + return AddMIDI((char)MIDI_NOTEOFF|midichannel,note,0); + } + + void AddControlChange(int control,int value) + { + AddMIDI(MIDI_CONTROLCHANGE+(midichannel&0xf),range(control),range(value)); + } + + void AddProgramChange(int value) + { + AddMIDI(MIDI_PROGRAMCHANGE+(midichannel&0xf),range(value),0); + } - AEffect *_pEffect; + void AddPitchBend(int value) + { + AddMIDI(MIDI_PITCHBEND+(midichannel&0xf),((value>>7)&127),(value&127)); + } - static void FreeVST(MHandle handle); + void AddAftertouch(int value) + { + AddMIDI((char)MIDI_AFTERTOUCH|midichannel,range(value)); + } - inline long GetFlags() const { return _pEffect?_pEffect->flags:0; } - inline bool HasFlags(long msk) const { return _pEffect && (_pEffect->flags&msk); } +private: + void SendMidi(); - char _sProductName[300]; - char _sVendorName[300]; - std::string _sDllName; // Contains dll name + // static VstTimeInfo _timeInfo; + VstMidiEvent midievent[MIDI_MAX_EVENTS]; + VstEvents events; + int eventqusz; - struct NameCmp: - std::less<std::string> + char midichannel; + + ////////////////////////////////////////////////////////////////////////////// + +public: + + void SetPlaying(bool p) { if(playing != p) transchg = true,playing = p; } + bool GetPlaying() const { return playing; } + void SetLooping(bool p) { if(looping != p) transchg = true,looping = p; } + bool GetLooping() const { return looping; } + + void SetSamplePos(double p) { if(samplepos != p) transchg = true,samplepos = p; } + double GetSamplePos() const { return samplepos; } + void SetTempo(double p) { if(tempo != p) transchg = true,tempo = p; } + double GetTempo() const { return tempo; } + void SetPPQPos(double p) { if(ppqpos != p) transchg = true,ppqpos = p; } + double GetPPQPos() const { return ppqpos; } + + void SetTimesigNom(int p) { if(timesignom != p) transchg = true,timesignom = p; } + int GetTimesigNom() const { return timesignom; } + void SetTimesigDen(int p) { if(timesigden != p) transchg = true,timesigden = p; } + int GetTimesigDen() const { return timesigden; } + void SetBarStart(double p) { if(barstartpos != p) transchg = true,barstartpos = p; } + double GetBarStart() const { return barstartpos; } + void SetCycleStart(double p) { if(cyclestartpos != p) transchg = true,cyclestartpos = p; } + double GetCycleStart() const { return cyclestartpos; } + void SetCycleEnd(double p) { if(cycleendpos != p) transchg = true,cycleendpos = p; } + double GetCycleEnd() const { return cycleendpos; } + + void SetSmpteOffset(int p) { if(smpteoffset != p) transchg = true,smpteoffset = p; } + int GetSmpteOffset() const { return smpteoffset; } + void SetSmpteRate(int p) { if(smpterate != p) transchg = true,smpterate = p; } + int GetSmpteRate() const { return smpterate; } + +private: + + bool playing,looping; + float samplerate; + bool transchg; + + double samplepos,tempo; + double ppqpos; + + int timesignom,timesigden; + double barstartpos; + double cyclestartpos,cycleendpos; + int smpteoffset,smpterate; + + ////////////////////////////////////////////////////////////////////////////// + +public: + void processReplacing(float **inputs,float **outputs,long sampleframes ) { - bool operator()(const std::string &a,const std::string &b) const { return a.compare(b) < 0; } - }; + FLEXT_ASSERT(effect); + effect->processReplacing(effect,inputs,outputs,sampleframes); + if(playing) updatepos(sampleframes); + } - typedef std::map<std::string,int,NameCmp> NameMap; - int paramnamecnt; - NameMap paramnames; - + void process(float **inputs,float **outputs,long sampleframes ) + { + FLEXT_ASSERT(effect); + effect->process(effect,inputs,outputs,sampleframes); + if(playing) updatepos(sampleframes); + } -// static VstTimeInfo _timeInfo; - VstMidiEvent midievent[MAX_EVENTS]; - VstEvents events; - int queue_size; +private: + void updatepos(long frames); - void SendMidi(); - char _midichannel; + ////////////////////////////////////////////////////////////////////////////// - int posx,posy; // Window position - bool caption; // Window border - std::string title; // Window title +private: + Responder *responder; + + bool NewPlugin(const char *plugname); + void FreePlugin(); + bool InstPlugin(long plugid = 0); + + static long uniqueid; + static std::string dllloading; + + inline long GetFlags() const { return effect?effect->flags:0; } + inline bool HasFlags(long msk) const { return effect && (effect->flags&msk); } + + + // the handle to the shared library + MHandle hdll; + // the handle to the plugin editor window + WHandle hwnd; + // the VST plugin instance + AEffect *effect; + + typedef AEffect *(VSTCALLBACK *PVSTMAIN)(audioMasterCallback audioMaster); + PVSTMAIN pluginmain; + audioMasterCallback audiomaster; + + long Dispatch(long opCode,long index = 0,long value = 0,void *ptr = NULL,float opt = 0) const + { + FLEXT_ASSERT(effect); + return effect->dispatcher(effect,opCode,index,value,ptr,opt); + } + + static long VSTCALLBACK Master(AEffect *effect, long opcode, long index, long value, void *ptr, float opt); + + static const t_symbol *sym_event,*sym_evmidi,*sym_evaudio,*sym_evvideo,*sym_evparam,*sym_evtrigger,*sym_evsysex,*sym_ev_; + static const t_symbol *sym_midi[8]; + + void ProcessEvent(const VstEvent &ev); }; #endif diff --git a/externals/grill/vst/src/vstmaster.cpp b/externals/grill/vst/src/vstmaster.cpp new file mode 100644 index 00000000..0395fb65 --- /dev/null +++ b/externals/grill/vst/src/vstmaster.cpp @@ -0,0 +1,288 @@ +/*
+vst~ - VST plugin object for PD
+based on the work of Jarno Seppänen and Mark Williamson
+
+Copyright (c)2003-2005 Thomas Grill (gr@grrrr.org)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+*/
+
+#include "vsthost.h"
+
+static const int VST_VERSION = 100;
+static const char *vendor = "grrrr.org";
+static const char *product = "vst~";
+
+
+void VSTPlugin::ProcessEvent(const VstEvent &ev)
+{
+ if(!responder) return;
+
+ if(ev.type == kVstMidiType) {
+ const VstMidiEvent &mev = (const VstMidiEvent &)ev;
+ t_atom lst[10];
+ SetSymbol(lst[0],sym_evmidi);
+ int midi = ((unsigned char)mev.midiData[0]>>4)-8;
+ FLEXT_ASSERT(midi >= 0 && midi < 8);
+ SetSymbol(lst[1],sym_midi[midi]);
+ SetInt(lst[2],(unsigned char)mev.midiData[0]&0x0f);
+ SetInt(lst[3],(unsigned char)mev.midiData[1]);
+ SetInt(lst[4],(unsigned char)mev.midiData[2]);
+ // what about running status? (obviously not possible)
+ SetInt(lst[5],mev.deltaFrames);
+ SetInt(lst[6],mev.noteLength);
+ SetInt(lst[7],mev.noteOffset);
+ SetInt(lst[8],(int)mev.detune);
+ SetInt(lst[9],(int)mev.noteOffVelocity);
+ responder->Respond(sym_event,9,lst);
+ }
+ else {
+ const t_symbol *sym;
+ if(ev.type == kVstAudioType)
+ sym = sym_evaudio;
+ else if(ev.type == kVstVideoType)
+ sym = sym_evvideo;
+ else if(ev.type == kVstParameterType)
+ sym = sym_evparam;
+ else if(ev.type == kVstTriggerType)
+ sym = sym_evtrigger;
+ else if(ev.type == kVstSysExType)
+ sym = sym_evsysex;
+ else
+ sym = sym_ev_;
+
+ int data = ev.byteSize-sizeof(ev.deltaFrames)-sizeof(ev.flags);
+ const int stsize = 16;
+ t_atom stlst[stsize];
+ t_atom *lst = data+3 > stsize?new t_atom[data+3]:stlst;
+
+ SetSymbol(lst[0],sym);
+ SetInt(lst[1],ev.deltaFrames);
+ SetInt(lst[2],ev.flags);
+ for(int i = 0; i < data; ++i) SetInt(lst[3],(unsigned char)ev.data[i]);
+
+ responder->Respond(sym_event,data+3,lst);
+
+ if(lst != stlst) delete[] lst;
+ }
+}
+
+// Host callback dispatcher
+long VSTPlugin::Master(AEffect *effect, long opcode, long index, long value, void *ptr, float opt)
+{
+#ifdef FLEXT_LOGGING
+ post("VST -> host: Eff = 0x%.8X, Opcode = %d, Index = %d, Value = %d, PTR = %.8X, OPT = %.3f\n",(int)effect, opcode,index,value,(int)ptr,opt);
+#endif
+
+ VSTPlugin *th = effect?(VSTPlugin *)effect->user:NULL;
+
+ switch (opcode) {
+ case audioMasterAutomate: // 0
+#ifdef FLEXT_LOGGING
+ post("Automate index=%li value=%li opt=%f",index,value,opt);
+#endif
+ // index, value given
+ //! \todo set effect parameter
+ return 0;
+
+ case audioMasterVersion: // 1
+ // support VST 2.3
+ return 2300;
+
+ case audioMasterCurrentId: // 2
+ // set to subplugin id (default 0)
+ return uniqueid;
+
+ case audioMasterIdle: // 3
+ effect->dispatcher(effect, effEditIdle, 0, 0, NULL, 0.0f);
+ return 0;
+
+ case audioMasterPinConnected: // 4
+ //! \todo set connection state correctly (if possible..)
+ // index=pin, value=0..input, else..output
+#ifdef FLEXT_LOGGING
+ post("Pin connected pin=%li conn=%li",index,value);
+#endif
+ return 0; // 0 means connected
+
+ case audioMasterWantMidi: // 6
+#ifdef FLEXT_LOGGING
+ post("Want MIDI = %li",value);
+#endif
+ return 0; // VST header says: "currently ignored"
+
+ case audioMasterGetTime: { // 7
+ if(!th) return 0;
+
+ static VstTimeInfo time;
+ memset(&time,0,sizeof(time));
+
+ // flags
+ time.flags = kVstTempoValid|kVstBarsValid|kVstCyclePosValid|kVstPpqPosValid|kVstSmpteValid|kVstTimeSigValid;
+
+ if(th->transchg) { time.flags |= kVstTransportChanged; th->transchg = false; }
+ if(th->playing) time.flags |= kVstTransportPlaying;
+ if(th->looping) time.flags |= kVstTransportCycleActive;
+
+ time.sampleRate = th->samplerate;
+ time.samplePos = th->samplepos;
+ time.ppqPos = th->ppqpos;
+
+ time.tempo = th->tempo;
+ time.barStartPos = th->barstartpos;
+ time.cycleStartPos = th->cyclestartpos;
+ time.cycleEndPos = th->cycleendpos;
+
+ time.timeSigNumerator = th->timesignom;
+ time.timeSigDenominator = th->timesigden;
+
+ // SMPTE data
+ time.smpteOffset = th->smpteoffset;
+ time.smpteFrameRate = th->smpterate;
+
+// time.samplesToNextClock = 0;
+
+ if(value&kVstNanosValid) {
+ time.nanoSeconds = flext::GetOSTime()*1.e9;
+ time.flags |= kVstNanosValid;
+ }
+
+ return (long)&time;
+ }
+
+ case audioMasterProcessEvents: { // 8
+ // VST event data from plugin
+ VstEvents *evs = static_cast<VstEvents *>(ptr);
+ if(th) {
+ for(int i = 0; i < evs->numEvents; ++i)
+ th->ProcessEvent(*evs->events[i]);
+ return 1;
+ }
+ else
+ return 0;
+ }
+
+ case audioMasterSetTime: { // 9
+ VstTimeInfo *tminfo = static_cast<VstTimeInfo *>(ptr);
+#ifdef FLEXT_DEBUG
+ post("TimeInfo pos=%lf rate=%lf filter=%li",tminfo->samplePos,tminfo->sampleRate,value);
+#endif
+ return 0; // not supported
+ }
+
+ case audioMasterTempoAt: // 10
+ return 0; // not supported
+
+ case audioMasterGetNumAutomatableParameters: // 11
+ return 0; // not supported
+
+ case audioMasterSizeWindow: // 15
+ return 0;
+
+ case audioMasterGetSampleRate: // 16
+ return 0; // not supported
+ case audioMasterGetBlockSize: // 17
+ return 0; // not supported
+
+ case audioMasterGetCurrentProcessLevel: // 23
+ // return thread state
+ return flext::GetThreadId() == flext::GetSysThreadId()?2:1;
+
+ case audioMasterGetVendorString: // 32
+ strcpy((char*)ptr,vendor);
+ return 0;
+
+ case audioMasterGetProductString: // 33
+ strcpy((char *)ptr,product);
+ return 0;
+
+ case audioMasterGetVendorVersion: // 34
+ return VST_VERSION;
+
+ case audioMasterCanDo: // 37
+#ifdef FLEXT_LOGGING
+ post("\taudioMasterCanDo PTR = %s",ptr);
+#endif
+ if(!strcmp((char *)ptr,"sendVstEvents"))
+ return 1;
+ else if(!strcmp((char *)ptr,"sendVstMidiEvent"))
+ return 1;
+ else if(!strcmp((char *)ptr,"sendVstTimeInfo"))
+ return 1; // NOT YET
+ else if(!strcmp((char *)ptr,"receiveVstEvents"))
+ return 1;
+ else if(!strcmp((char *)ptr,"receiveVstMidiEvent"))
+ return 1;
+ else if(!strcmp((char *)ptr,"receiveVstTimeInfo"))
+ return 1; // NOT YET
+ else if(!strcmp((char *)ptr,"reportConnectionChanges"))
+ return 0; // \TODO PD has hard times supporting that...
+ else if(!strcmp((char *)ptr,"acceptIOChanges"))
+ return 0; // \TODO what does this means exactly?
+ else if(!strcmp((char *)ptr,"supplyIdle"))
+ return 1;
+ else if(!strcmp((char *)ptr,"sizeWindow"))
+ return 1;
+ else if(!strcmp((char *)ptr,"supportShell"))
+ return 0; // deprecated - new one is shellCategory
+ else if(!strcmp((char *)ptr,"offline"))
+ return 0; // not supported
+ else if(!strcmp((char *)ptr,"asyncProcessing"))
+ return 0; // not supported
+ else if(!strcmp((char *)ptr,"shellCategory"))
+ return 1; // supported!
+ else if(!strcmp((char *)ptr,"editFile"))
+ return 0; // not supported
+ else if(!strcmp((char *)ptr,"openFileSelector"))
+ return 0; // not supported
+ else if(!strcmp((char *)ptr,"closeFileSelector"))
+ return 0; // not supported
+ else if(!strcmp((char *)ptr,"startStopProcess"))
+ return 0; // not supported
+#ifdef FLEXT_DEBUG
+ else
+ post("Unknown audioMasterCanDo PTR = %s",ptr);
+#endif
+
+ return 0; // not supported
+
+ case audioMasterGetLanguage: // 38
+ return kVstLangEnglish;
+
+ case audioMasterGetDirectory: // 41
+ return (long)(th?th->dllname.c_str():dllloading.c_str());
+
+ case audioMasterUpdateDisplay: // 42
+#ifdef FLEXT_LOGGING
+ post("UPDATE DISPLAY");
+#endif
+ return 0;
+
+ default:
+#ifdef FLEXT_DEBUG
+ post("Unknown opcode %li",opcode);
+#endif
+ return 0;
+ }
+}
+
+void VSTPlugin::updatepos(long frames)
+{
+ bool inloop = ppqpos < cycleendpos;
+
+ // \todo should the sample position also jump back when cycling?
+ // and if, how?
+ samplepos += frames;
+
+ ppqpos += frames*tempo/(samplerate*60);
+
+ if(looping) {
+ double cyclelen = cycleendpos-cyclestartpos;
+ if(cyclelen > 0) {
+ if(inloop && ppqpos >= cycleendpos)
+ ppqpos = cyclestartpos+fmod(ppqpos-cyclestartpos,cyclelen);
+ }
+ else
+ ppqpos = cyclestartpos;
+ }
+}
diff --git a/externals/grill/vst/src/vstmidi.cpp b/externals/grill/vst/src/vstmidi.cpp new file mode 100644 index 00000000..8bddba98 --- /dev/null +++ b/externals/grill/vst/src/vstmidi.cpp @@ -0,0 +1,52 @@ +/*
+vst~ - VST plugin object for PD
+based on the work of Jarno Seppänen and Mark Williamson
+
+Copyright (c)2003-2005 Thomas Grill (gr@grrrr.org)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+*/
+
+#include "vsthost.h"
+
+bool VSTPlugin::AddMIDI(unsigned char data0,unsigned char data1,unsigned char data2)
+{
+ if(Is()) {
+ VstMidiEvent *pevent = &midievent[eventqusz];
+
+ 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(eventqusz < MIDI_MAX_EVENTS) ++eventqusz;
+ SendMidi();
+ return true;
+ }
+ else return false;
+}
+
+
+void VSTPlugin::SendMidi()
+{
+ if(Is() && eventqusz > 0) {
+ // Prepare MIDI events and free queue dispatching all events
+ events.numEvents = eventqusz;
+ events.reserved = 0;
+ for(int q = 0; q < eventqusz; q++)
+ events.events[q] = (VstEvent*)&midievent[q];
+
+ Dispatch(effProcessEvents, 0, 0, &events, 0.0f);
+ eventqusz = 0;
+ }
+}
diff --git a/externals/grill/vst/src/vstparam.cpp b/externals/grill/vst/src/vstparam.cpp new file mode 100644 index 00000000..30515b23 --- /dev/null +++ b/externals/grill/vst/src/vstparam.cpp @@ -0,0 +1,105 @@ +/*
+vst~ - VST plugin object for PD
+based on the work of Jarno Seppänen and Mark Williamson
+
+Copyright (c)2003-2005 Thomas Grill (gr@grrrr.org)
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the file, "license.txt," in this distribution.
+*/
+
+#include "vsthost.h"
+#include <ctype.h>
+
+static void striptrail(char *txt)
+{
+ // strip trailing whitespace
+ for(int i = strlen(txt)-1; i >= 0; --i)
+ // cast to unsigned char since isspace functions don't want characters like 0x80 = -128
+ if(isspace(((unsigned char *)txt)[i])) txt[i] = 0;
+}
+
+void VSTPlugin::GetParamName(int numparam,char *name) const
+{
+ if(numparam < GetNumParams()) {
+ name[0] = 0;
+ Dispatch(effGetParamName,numparam,0,name);
+ striptrail(name);
+ }
+ else
+ name[0] = 0;
+}
+
+bool VSTPlugin::SetParamFloat(int parameter,float value)
+{
+ if(Is() && parameter >= 0 && parameter < GetNumParams()) {
+ effect->setParameter(effect,parameter,value);
+ return true;
+ }
+ else
+ return false;
+}
+
+void VSTPlugin::GetParamValue(int numparam,char *parval) const
+{
+ if(Is()) {
+ if(numparam < GetNumParams()) {
+ // how many chars needed?
+ char par_display[64]; par_display[0] = 0;
+ Dispatch(effGetParamDisplay,numparam,0,par_display);
+// if(par_display[7]) par_display[8] = 0; // set trailing zero
+
+ // how many chars needed?
+ char par_label[64]; par_label[0] = 0;
+ Dispatch(effGetParamLabel,numparam,0,par_label);
+ striptrail(par_label);
+// if(par_label[7]) par_label[8] = 0; // set trailing zero
+
+ sprintf(parval,"%s%s",par_display,par_label);
+ }
+ else
+ strcpy(parval,"Index out of range");
+ }
+ else
+ strcpy(parval,"Plugin not loaded");
+}
+
+float VSTPlugin::GetParamValue(int numparam) const
+{
+ if(Is() && numparam < GetNumParams())
+ return effect->getParameter(effect,numparam);
+ else
+ return -1.0;
+}
+
+void VSTPlugin::ScanParams(int cnt)
+{
+ if(cnt < 0) cnt = GetNumParams();
+ if(paramnamecnt >= cnt) return;
+ if(cnt >= GetNumParams()) cnt = GetNumParams();
+
+ char name[64];
+ for(int i = paramnamecnt; i < cnt; ++i) {
+ GetParamName(i,name);
+ if(*name) paramnames[std::string(name)] = i;
+ }
+ paramnamecnt = cnt;
+}
+
+int VSTPlugin::GetParamIx(const char *p) const
+{
+ NameMap::const_iterator it = paramnames.find(std::string(p));
+ return it == paramnames.end()?-1:it->second;
+}
+
+bool VSTPlugin::GetProgramName(int cat,int p,char *buf) const
+{
+ buf[0] = 0;
+ int parameter = p;
+ if(parameter < GetNumPrograms() && cat < GetNumCategories()) {
+ Dispatch(effGetProgramNameIndexed,parameter,cat,buf);
+ striptrail(buf);
+ return true;
+ }
+ else
+ return false;
+}
diff --git a/externals/grill/vst/vst.vcproj b/externals/grill/vst/vst.vcproj index 4541b83d..7121d85e 100644 --- a/externals/grill/vst/vst.vcproj +++ b/externals/grill/vst/vst.vcproj @@ -87,7 +87,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=""c:\data\prog\pd\pd-cvs\src";..\flext\source;c:\data\prog\audio\vstsdk2.3\source\common" - PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_WIN32_WINNT=0x0501,WINVER=0x0501;_USRDLL;FLEXT_SYS=2;FLEXT_THREADS;FLEXT_LOGGING" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_WIN32_WINNT=0x0501;WINVER=0x0501;_USRDLL;FLEXT_SYS=2;FLEXT_THREADS;xFLEXT_LOGGING" BasicRuntimeChecks="3" RuntimeLibrary="1" UsePrecompiledHeader="2" @@ -275,11 +275,23 @@ </FileConfiguration> </File> <File + RelativePath=".\src\vstedit.cpp"> + </File> + <File RelativePath=".\src\vsthost.cpp"> </File> <File RelativePath=".\src\vsthost.h"> </File> + <File + RelativePath=".\src\vstmaster.cpp"> + </File> + <File + RelativePath=".\src\vstmidi.cpp"> + </File> + <File + RelativePath=".\src\vstparam.cpp"> + </File> </Filter> <Filter Name="doc" @@ -326,6 +338,9 @@ <File RelativePath="src\main.h"> </File> + <File + RelativePath=".\src\resource.h"> + </File> </Files> <Globals> </Globals> |