5 Commits

Author SHA1 Message Date
9f9fae2822 now working only with symbols 2024-04-21 10:29:49 -03:00
bea578104f seems working 2024-04-21 07:55:18 -03:00
af7afaf8b2 set getchunk setchunk 2024-04-21 05:51:58 -03:00
9f67aa682a add test files 2024-04-17 06:29:13 -03:00
dd4847399c readme 2022-10-04 07:19:13 -03:00
10 changed files with 357 additions and 2 deletions

156
README.md Normal file
View File

@@ -0,0 +1,156 @@
# Pdvst-0.52
Based on https://github.com/jyg/pure-data/tree/master/pdvst but updated to load with Pd-0.52
or higher.
# How does it work ?
PdVst consists of two main parts :
* a vst-plugin (pdvst-template32.dll, pdvst-template64.dll) to place in your favorite vst folder.
* a custom external scheduler (vstschedlib.dll) to copy in the pure-data /bin folder
When a PdVst plugin is opened by the host application, a setup file (*.pdv) is read to determine
information about the plugin, such as the Pd patch file to use, the number of parameters, etc...
An instance of Pd.exe is started and opens the Pd patch file whose name was found in the setup file.
# Installation
This new version doesn't need a custom version of pure-data. You can use your current pure-data
installation (>= Pd-0.52) with your favorite externals).
1) According to your pd version (32 or 64 bits), go to the folder pd-scheduler32 or pd-scheduler64.
Copy `vstschedlib.dll` to `\bin` directory of your current pure-data installation
2) Copy your plugin `.dll` file (e.g. `Pd_Gain.dll`) to the vst plugins directory
for the application (e.g. `c:/Program Files (x86)/Steinberg/Cubase VST/VstPlugins/`)
3) New way : in the vst plugin directory, create a subdir with the name of your plugin
(e.g. `c:/Program Files (x86)/Steinberg/Cubase VST/VstPlugins/Pd_Gain/`).
This folder will contain the `.pdv` and `.pd` files associated to your plugin.
NOTE (advanced) : if you choose the new way, you can also include an standalone version of
puredata in the vst directory, simply paste it in the subfolder `.pd/`
(e.g. `c:/Program Files (x86)/Steinberg/Cubase VST/VstPlugins/.pd/`)
3bis) Old way : create a pdvst folder in the directory that contains the
application (e.g. `Reaper.exe`) that you want to use PdVst with.
(e.g. `c:/Program Files/REAPER/pdvst/`). This folder will contain the `.pdv` and `.pd` files, and
optionnally a copy of pure-data application (inside `c:/Program Files/REAPER/pdvst/pd/`).
# Creating VST Plugins from Pd Patches
* Create a new `.pdv` setup file (see the `.pdv` Setup File section). The file
must be named the same as the plugin (e.g. for a plugin named Pd_Gain you
would create a file named `Pd_Gain.pdv`). Place this file and all dependant
files (`.pd` files, external Pd library `.dll` files, etc.) as specified above (section
"Installation").
* Make a copy of the `pdvst-template32.dll` / `pdvst-template64.dll` file and
rename the same as the plugin and `.pdv` file (e.g. for a plugin named
Pd_Gain you would copy `pdvst-template32.dll` to a new file named `Pd_Gain.dll`).
Move your new plugin `.dll` file to the vst plugins folder of the application.
# The .pdv Setup File-
This file contains all of the information about your plugin. The format is ASCII
text with keys and values separated by an '=' character and each key and value
pair separated by a carriage return. Comments are demarked with a '#' character.
For an example, see Pd_Gain.pdv.
-Keys-
CHANNELS = <integer>
Number of audio input and output channels. Tested with 2 and 4.
Should work with larger values.
PDPATH = <string>
Path to the installation directory of pure-data program.
(example : PDPATH = C:/Program Files (x86)/pd-0.47-1/ )
If this line is not specified, for compatibility with older version, the program will first
look for pd.exe in <host_exec_dir>/pdvst/pd/bin.
If there is not an existing pd installation in <host_exec_dir>/pdvst/, the program will then
look for pd.exe in <VST_FOLDER>/.pd/
MAIN = <string>
The .pd file for Pd to open when the plugin is opened.
ID = <string[4]>
The 4-character unique ID for the VST plugin. This is required by VST and
just needs to be a unique string of four characters.
SYNTH = <TRUE/FALSE>
Boolean value stating whether this plugin is an instrument (VSTi) or an effect.
Both types of plugins can send/receive midi events.
CUSTOMGUI = <TRUE/FALSE>
Boolean value stating whether the Pd patch uses a custom GUI (e.g. GrIPD).
DEBUG = <TRUE/FALSE>
Boolean value stating whether to display the Pd GUI when the plugin is opened.
PARAMETERS = <integer>
Number of parameters the plugin uses (up to 128).
NAMEPARAMETER<integer> = <string>
Display name for parameters. Used when CUSTOMGUI is false or the VST host doesn't
support custom editors.
PROGRAM = <string>
Declares a new VST program and sets the name (up to 128 programs can be declared)
PARAMETER<integer> = <float>
Defines the parameter values for the last declared program. <float> must be
between 0 and 1 inclusive.
# Pd/VST audio/midi Communication
When the plugin is opened, the .pd patch file declared in the .pdv setup file's MAIN key
will be opened.
The Pd patch will receive its incoming audio stream from the adc~ object,
and incoming MIDI data from the Pd objects notein, ctlin, and pgmin.
Pd patches should output their audio stream to the dac~ object,
and their midi stream to the noteout, ctlout, pgmout objects.
REMARKS :
* The midi out feature is still experimental and not fully tested. It should work when host uses ASIO driver, more erratic with mmio. Midi out note on/off have been tested, other midi messages untested but should work.
* Inside puredata plugin, don't use "media/ASIO" or "media/standard" audio menu, you may crash pd & host.
* You can continue to use "media/midi settings" menu to select input and output midi devices independently from host.
# Pd/VST - further communications
For purposes such as GUI interaction and VST automation, your patch may need to communicate
further with the VST host. Special Pd send/receive symbols can be used in your Pd patch.
For an example, see the pd-gain.pd file.
* rvstparameter<integer> : Use this symbol to receive parameter values from the VST host. Values will be floats between 0 and 1 inclusive.
* svstparameter<integer> : Use this symbol to send parameter values to the VST host. Values should be floats between 0 and 1 inclusive.
* rvstopengui : Use this symbol to receive notification that the patch's GUI should be opened or closed. The value will be either 1 or 0.
* rvstplugname : Use this symbol to receive plug & instance name from host
* vstTimeInfo (play head information support) :
vstTimeInfo.ppqPos, vstTimeInfo.tempo, vstTimeInfo.timeSigNumerator, vstTimeInfo.timeSigDenominator, vstTimeInfo.flags are experimental receivers for getting time infos from host. Names should change in the future.
* EXPERIMENTAL
guiName : use this symbol to send and signal to the host the name of the gui-extra window to embed (see Pd_Gain(gui) example).
Note: for most VST hosts, parameters for VST instruments are recorded as sysex data, so be
sure to disable any MIDI message filtering in the VST host.
#CURRENT FEATURES
* Windows x32 and x64 only
* Support for embedding external gui window into host
* multichannel audio in/out support
* integrated vst midi-in, experimental midi-out
* added play head information support (see examples)
#TODO
* optimize plugin loading
* use of chunks for preset saving

View File

@@ -0,0 +1,43 @@
#N canvas 0 265 818 358 12;
#X obj 78 87 adc~, f 6;
#X obj 73 241 loadbang;
#X msg 73 271 \; pd dsp 1 \;;
#X obj 77 162 dac~, f 6;
#X msg 142 52 \$1 30;
#X obj 142 87 line~;
#X obj 122 127 *~;
#X obj 78 127 *~;
#X obj 142 11 r gain;
#X obj 242 8 r rvstparameter0;
#X obj 242 235 * 100;
#X obj 242 263 dbtorms;
#X obj 242 290 s gain;
#X obj 300 225 s svstparameter0;
#X obj 277 75 vsl 50 128 0 1 0 0 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000 0 1;
#X msg 277 42 set \$1;
#X text 355 117 range is 0..1;
#X obj 498 10 r rvstplugname;
#X symbolatom 498 48 17 0 0 0 - - - 0;
#X obj 516 102 r rvstdata;
#X symbolatom 516 136 17 0 0 0 - - - 0;
#X obj 516 265 s svstdata;
#X msg 547 216 symbol hello\ world\ 2;
#X connect 0 0 7 0;
#X connect 0 1 6 0;
#X connect 1 0 2 0;
#X connect 4 0 5 0;
#X connect 5 0 6 1;
#X connect 5 0 7 1;
#X connect 6 0 3 1;
#X connect 7 0 3 0;
#X connect 8 0 4 0;
#X connect 9 0 10 0;
#X connect 9 0 15 0;
#X connect 10 0 11 0;
#X connect 11 0 12 0;
#X connect 14 0 13 0;
#X connect 14 0 10 0;
#X connect 15 0 14 0;
#X connect 17 0 18 0;
#X connect 19 0 20 0;
#X connect 22 0 21 0;

View File

@@ -0,0 +1,49 @@
# Number of audio input and output channels
CHANNELS = 2
# installation directory of puredata (optional)
# If non specified, will search in <host_exec_dir>\pdvst\pd\
# then in <vst_dir>\.pd\
#PDPATH = D:\Programs\pd-0.48-1-test\
# Main Pd patch of the plugin
MAIN = Pd_Chunks-test.pd
# Unique four character VST plugin ID
ID = pdch
# Whether this is a VSTi
SYNTH = FALSE
# Whether there is a custom GUI (e.g. GrIPD)
CUSTOMGUI = FALSE
# Display Pd GUI or not
DEBUG = TRUE
# External libraries (comma delimited list, relative to pdvst/)
# ***OBSOLETE, use [declare] inside patch instead***
#LIB =
# Number of VST parameters (up to 128)
PARAMETERS = 1
# Name of first VST parameter
# used when CUSTOMGUI is false or VST host doesn't support custom editors
NAMEPARAMETER0 = Level
# Define a program (up to 128)
PROGRAM = Full Blast
# Set first parameter value for this program
PARAMETER0 = 1.0
#another program
PROGRAM = Muted
PARAMETER0 = 0.0
#another program
PROGRAM = -6dB
PARAMETER0 = 0.94

Binary file not shown.

View File

@@ -17,5 +17,5 @@ ALL: vstschedlib.c
gcc -Wall -I$(PDDIR)src -I../vst-template vstschedlib.c -static-libgcc \ gcc -Wall -I$(PDDIR)src -I../vst-template vstschedlib.c -static-libgcc \
-shared -L$(PDDIR)bin -l:pd.dll -o vstschedlib.dll -shared -L$(PDDIR)bin -l:pd.dll -o vstschedlib.dll
strip vstschedlib.dll strip vstschedlib.dll
cp vstschedlib.dll ../build/pd-scheduler$(arch)/vstschedlib.dll #cp vstschedlib.dll ../build/pd-scheduler$(arch)/vstschedlib.dll
#cp vstschedlib.dll ../build/Release$(arch)/.pd/bin/vstschedlib.dll cp vstschedlib.dll ../build/Release$(arch)/.pd/bin/vstschedlib.dll

View File

@@ -70,10 +70,20 @@ typedef struct _vstGuiNameReceiver
t_vstGuiNameReceiver *vstGuiNameReceiver; t_vstGuiNameReceiver *vstGuiNameReceiver;
typedef struct _vstChunkReceiver
{
t_object x_obj;
}t_vstChunkReceiver;
t_vstChunkReceiver *vstChunkReceiver;
t_vstParameterReceiver *vstParameterReceivers[MAXPARAMETERS]; t_vstParameterReceiver *vstParameterReceivers[MAXPARAMETERS];
t_class *vstParameterReceiver_class; t_class *vstParameterReceiver_class;
t_class *vstGuiNameReceiver_class; t_class *vstGuiNameReceiver_class;
t_class *vstChunkReceiver_class;
char *pdvstTransferMutexName, char *pdvstTransferMutexName,
*pdvstTransferFileMapName, *pdvstTransferFileMapName,
@@ -195,6 +205,19 @@ int setPdvstPlugName(char* instanceName)
return 0; return 0;
} }
int setPdvstChunk(char* instanceName)
{
t_symbol *tempSym;
tempSym = gensym("rvstdata");
if (tempSym->s_thing)
{
pd_symbol(tempSym->s_thing, gensym(instanceName));
return 1;
}
else
return 0;
}
int setPdvstFloatParameter(int index, float value) int setPdvstFloatParameter(int index, float value)
{ {
@@ -227,6 +250,17 @@ void sendPdVstFloatParameter(t_vstParameterReceiver *x, t_float floatValue)
ReleaseMutex(pdvstTransferMutex); ReleaseMutex(pdvstTransferMutex);
} }
void sendPdVstChunk(t_vstChunkReceiver *x, t_symbol *sym)
{
WaitForSingleObject(pdvstTransferMutex, INFINITE);
pdvstData->datachunk.type = STRING_TYPE;
pdvstData->datachunk.direction = PD_SEND;
pdvstData->datachunk.updated = 1;
strcpy(pdvstData->datachunk.value.stringData,sym->s_name);
ReleaseMutex(pdvstTransferMutex);
}
void sendPdVstGuiName(t_vstGuiNameReceiver *x, t_symbol *symbolValue) void sendPdVstGuiName(t_vstGuiNameReceiver *x, t_symbol *symbolValue)
{ {
WaitForSingleObject(pdvstTransferMutex, INFINITE); WaitForSingleObject(pdvstTransferMutex, INFINITE);
@@ -251,6 +285,7 @@ void makePdvstParameterReceivers()
vstParameterReceivers[i]->x_sym = gensym(string); vstParameterReceivers[i]->x_sym = gensym(string);
pd_bind(&vstParameterReceivers[i]->x_obj.ob_pd, gensym(string)); pd_bind(&vstParameterReceivers[i]->x_obj.ob_pd, gensym(string));
} }
} }
void makePdvstGuiNameReceiver() void makePdvstGuiNameReceiver()
@@ -260,6 +295,15 @@ void makePdvstGuiNameReceiver()
} }
void makevstChunkReceiver()
{
vstChunkReceiver = (t_vstChunkReceiver *)pd_new(vstChunkReceiver_class);
pd_bind(&vstChunkReceiver->x_obj.ob_pd, gensym("svstdata"));
}
void send_dacs(void) void send_dacs(void)
@@ -331,7 +375,20 @@ int scheduler()
class_addfloat(vstParameterReceiver_class, (t_method)sendPdVstFloatParameter); class_addfloat(vstParameterReceiver_class, (t_method)sendPdVstFloatParameter);
makePdvstParameterReceivers(); makePdvstParameterReceivers();
vstChunkReceiver_class = class_new(gensym("vstChunkReceiver"),
0,
0,
sizeof(t_vstChunkReceiver),
0,
0);
class_addsymbol(vstChunkReceiver_class,(t_method)sendPdVstChunk);
makevstChunkReceiver();
vstGuiNameReceiver_class = class_new(gensym("vstGuiNameReceiver"), vstGuiNameReceiver_class = class_new(gensym("vstGuiNameReceiver"),
0, 0,
0, 0,
@@ -390,6 +447,14 @@ int scheduler()
if (setPdvstPlugName((char*)pdvstData->plugName.value.stringData)) if (setPdvstPlugName((char*)pdvstData->plugName.value.stringData))
pdvstData->plugName.updated=0; pdvstData->plugName.updated=0;
} }
// lucarda get data chunk from file
if (pdvstData->datachunk.direction == PD_RECEIVE && \
pdvstData->datachunk.updated)
{
if (setPdvstChunk((char*)pdvstData->datachunk.value.stringData))
pdvstData->datachunk.updated=0;
}
if (pdvstData->hostTimeInfo.updated) if (pdvstData->hostTimeInfo.updated)
{ {

View File

@@ -38,6 +38,7 @@ ALL: $(SOURCES)
cp pdvst-template.dll ../build/Release$(arch)/Pd_Gain-gui.dll cp pdvst-template.dll ../build/Release$(arch)/Pd_Gain-gui.dll
cp pdvst-template.dll ../build/Release$(arch)/Pd_Gain-nogui.dll cp pdvst-template.dll ../build/Release$(arch)/Pd_Gain-nogui.dll
cp pdvst-template.dll ../build/Release$(arch)/Pd_Midi.dll cp pdvst-template.dll ../build/Release$(arch)/Pd_Midi.dll
cp pdvst-template.dll ../build/Release$(arch)/Pd_Chunks-test.dll

View File

@@ -226,6 +226,8 @@ pdvst::pdvst(audioMasterCallback audioMaster)
// {JYG see pdvst::setProgram below for explanation // {JYG see pdvst::setProgram below for explanation
timeFromStartup=GetTickCount(); timeFromStartup=GetTickCount();
// JYG } // JYG }
programsAreChunks(true);
sendPlugName(globalPluginName);
} }
pdvst::~pdvst() pdvst::~pdvst()
@@ -600,6 +602,29 @@ bool pdvst::getOutputProperties(VstInt32 index, VstPinProperties* properties)
return false; return false;
} }
VstInt32 pdvst::getChunk (void** data, bool isPreset)
{
MessageBox(0,"getchunk","debug",MB_OK);
strcpy ((char *)*data, pdvstData->datachunk.value.stringData);
return strlen(pdvstData->datachunk.value.stringData);
}
VstInt32 pdvst::setChunk (void* data, VstInt32 byteSize, bool isPreset)
{
WaitForSingleObject(pdvstTransferMutex, 10);
{
pdvstData->datachunk.direction = PD_RECEIVE;
pdvstData->datachunk.type = STRING_TYPE;
strcpy(pdvstData->datachunk.value.stringData,(char *)data);
pdvstData->datachunk.updated = 1;
ReleaseMutex(pdvstTransferMutex);
}
MessageBox(0,"setchunk","debug",MB_OK);
debugLog("setchunk: %s", data);
return 1;
}
VstInt32 pdvst::canDo(char* text) VstInt32 pdvst::canDo(char* text)
{ {
//if (isASynth) //if (isASynth)
@@ -1088,6 +1113,17 @@ void pdvst::updatePdvstParameters()
}
// to data chunk
if (pdvstData->datachunk.direction == PD_SEND && \
pdvstData->datachunk.updated)
{
if (pdvstData->datachunk.type = STRING_TYPE)
{
pdvstData->datachunk.updated=0;
}
} }
ReleaseMutex(pdvstTransferMutex); ReleaseMutex(pdvstTransferMutex);

View File

@@ -105,6 +105,9 @@ public:
LPTSTR displayString;//= new TCHAR[MAXSTRINGSIZE]; LPTSTR displayString;//= new TCHAR[MAXSTRINGSIZE];
HWND pdGui; HWND pdGui;
virtual VstInt32 getChunk (void** data, bool isPreset = false);
virtual VstInt32 setChunk (void* data, VstInt32 byteSize, bool isPreset = false);
protected: protected:
static int referenceCount; static int referenceCount;
@@ -170,6 +173,7 @@ protected:
// JYG } // JYG }
//void programsAreChunks (bool) {}
}; };
#endif #endif

View File

@@ -121,6 +121,7 @@ typedef struct _pdvstTransferData
pdvstMidiMessage midiQueue[MAXMIDIQUEUESIZE]; pdvstMidiMessage midiQueue[MAXMIDIQUEUESIZE];
pdvstParameter guiState; pdvstParameter guiState;
pdvstParameter plugName; // transmitted by host pdvstParameter plugName; // transmitted by host
pdvstParameter datachunk; // get/set chunk from .fxp file
pdvstParameter guiName; // transmitted by pd : name of gui window to be embedded pdvstParameter guiName; // transmitted by pd : name of gui window to be embedded
// #ifdef VSTMIDIOUTENABLE // #ifdef VSTMIDIOUTENABLE
int midiOutQueueSize; int midiOutQueueSize;