WDL-OL/IPlug project for gen~ code export
I've made an IPlug project that can be used to quickly compile a gen~ patch to VST2/VST3/AU/RTAS/AAX/APP/IOS* and to add a gui etc.
It's an early version, but it might be handy for someone. Please read the IPlugExamples.rtf in detail before asking about how to compile it.
*note: ProTools formats require Avid developer account and IOS project is out-dated (only works with IOS4 sdk on Xcode3)
www.olilarkin.co.uk
Thank you very much OLI!
PS: It would be very useful a sample IPlugGen project, implementing a basic gui and some control.
have a look at the IPlug example projects, which feature lots of different kinds of control
Greatness!
Wow! great stuff Oli! many thanks!
this looks like a great idea!
I have a naive question, I'm looking at developing a VST (that talks to a hardware device, and outputs midi). I was previously assuming Id build it in Juce...
but having looked at IPlug, it seems to offer much the same facilities.
Ive looked around, and cannot find any real comparison about why to choose IPlug/Wdl over Juce, or vice versa ... is there some comparison somewhere, or a guide about which to choose.
the only reason Ive found so far, is due to commercial licensing of Juce - something I don't think is applicable for me... though of course avoiding is a good thing generally :)
(just to be clear, I'm not after X is better than Y, I'm sure both are great... but wonder how to make an informed choice)
A few thoughts (I use both)
JUCE:
has good documentation
has consistent and high quality code
has a big user base
very good vector graphics capabilities
has a rather nice project generator (the introjucer)
much more than just plugins
doesn't impose particular thread safety technique
WDL-OL/IPlug:
Easier for C++ beginners
Concise plugin implementation
Many helpful scripts
IDE projects setup for debugging in lots of common hosts
Free
Possible to fork it and "own" your version
Perhaps less of a moving target
Uses rather brutal mutex locks for thread safety
I think JUCE is well worth the money, but i like the simplicity of implementing plugins in IPlug.
I'm actually working on a new version of IPlug that is based on VST3 and is lock-free. Also the graphics can be done using whatever framework you like (IGraphics, JUCE, VSTGUI etc)
Sure, I understand nothing, but how Gen passing parameters in the cpp code is enumerating and including them in an array of kVstParameter or something. For those who do not know anything, an example would be good, just like the ones you make reference, but using some specific parameter in a dial control and background image.
Anyway I appreciate your contribution and I will continue looking.
Thank you!
Thanks Oli, that is exactly what I was after :o)
from a quick look, it looks like WDL, is maintained by Cockos (of Reaper fame),
does this means its pretty well maintained?
it looks to have pretty good coverage for guis in the virtual window system...
Im not a beginner in C++, but I do have an aversion to frameworks which enforces there way of working to much, it usually makes then difficult to integrate with other software/frameworks...
(code generators like introjucer I've also sometimes find as much of a hinderance as help, though I've not played with introducer so this may not be the case)
Im also not keen on the juce licensing, I don't want to make commercial software, but that doesn't necessarily mean I want to (or can, due to other frameworks) make my source code open source.
so I guess looks like WDL/IPlug might be a good option for me :)
Hi Oli
I just tried this and i've found that it compiles your default Flanger plugin fine however as soon as any changes are made to the gen patch and the code is exported again xcode says that the calls in IPLugGen.cpp to: create, destroy, num_inputs, reset and setparameter are ambiguous.
On exporting the code from the edited gen patch it also removes the: #include "gen_export.h" and the namespace gen_export{} lines from the code. I corrected this but it didn't have any effect on the previous problem.
....on a side note as well the duplicate python script also doesn't seem to work properly for the IPLugGen-master folder; it duplicates the folder and changes the name but doesn't alter the names of anything inside. I've used it for duplicating the IplugEffect folder for normal projects and it works in that instance.
Thanks for creating all this though in general, its been great for learning how to build plugins.
Regards
Ollie
Issue Resolved - I was on Max 6.1.
Updated Max and it works perfectly now.
Great Work again!
This is brilliant!
Thanks!
Thanks very much for this Oli. Truly fantastic resource.
Hi.
I would like to be able to get multiple channels of audio into a Gen patch but I am stuck.
I have adapted Oli's example patch 'IPlugGen' to have a very simple 2 in 2 out patch with a mix object to control the 2 sources. Currently there is no second source. and ATM, I am just trying to silence one input using inputs[1] = NULL;
in ProcessDoubleReplacing
. I assumed this would make in2 silent and in1 pass into Gen unchanged but it actually results in total silence.
My question is this: What code should I place in ProcessDoubleReplacing
to route audio to in1 OR in2? For example, the following is from the IPlugResampler ProcessDoubleReplacing
. How could I send this output to in1 or in2?
double* out1 = outputs[0];
double* out2 = outputs[1];
WDL_ResampleSample *resampledAudio=NULL;
int numSamples = mResampler.ResamplePrepare(nFrames,1,&resampledAudio);
for (int s = 0; s < numSamples; s++)
{
if (mSampleIndx >= 44100) mSampleIndx = 0;
resampledAudio[s] = mAudioToResample[mSampleIndx++] * mGain;
}
if (mResampler.ResampleOut(out1, numSamples, nFrames, 1) != nFrames)
{
//failed somehow
memset(out1, 0 , nFrames * sizeof(double));
}
memcpy(out2, out1, nFrames * sizeof(double));
Any help would be great. I've attached the Max Patch since I was not allowed to upload the Xcode Project. If you can take the time to look at this, you'd need to export the code using this patch instead of the example in IPlugGen.
Thanks
Dave
not sure i quite understand what stage you're at, but if you want to silence the right channel of the incoming sample buffer in IPlug's ProcessDoubleReplacing, you could do so with
void IPlugGen::ProcessDoubleReplacing(double** inputs, double** outputs, int nFrames)
{
// Mutex is already locked for us.
double* in0 = inputs[0]; //pointer to the first sample in the left channel
double* in1 = inputs[1]; //pointer to the first sample in the right channel
memset(in1, 0, nFrames * sizeof(double)); // set (nFrames * sizeof(double)) bytes to 0
perform(gen, inputs, num_inputs(), outputs, num_outputs(), nFrames);
}
Hi Oli,
Thanks for a speedy reply.
That does indeed silence the right channel and then the one GUI slider controls the blend of left to right. Here's the code that worked:
void IPlugGenTwoInputs::ProcessDoubleReplacing(double** inputs, double** outputs, int nFrames)
{
// Mutex is already locked for us.
double* in0 = inputs[0]; //pointer to the first sample in the left channel
double* in1 = inputs[1]; //pointer to the first sample in the right channel
memset(in1, 0, nFrames * sizeof(double)); // set (nFrames * sizeof(double)) bytes to 0
perform(gen, inputs, num_inputs(), outputs, num_outputs(), nFrames);
}
I tried your 'IPlugResampler' project and got it working with an array I filled with a one second sample of a wav. It loops and works great. My final goal is to have two such arrays going into Gen so that in my Gen patch I can do x with in1
and do y with in2
etc. Right now the slider would mix between in1 and in2.
So, the next step for me is to get my adaptation of your 'IPlugResampler' project to send it's audio into either in 1
or in 2
:

My adaptation of your 'IPlugResampler' project is basically the same except I replace some code in your constructor:
//Fill the mAudioToResample array with 100 cycles of a 441hz sine wave
double recip = 1. / 44100.;
double phase = 0.;
for (int i = 0; i< 44100; i++)
{
mAudioToResample[i] = sin( phase * 6.283185307179586);
phase += recip * 441.;
if (phase > 1.) phase -= 1.;
}
With:
const double test[] = {0.862, 0.855957, 0.858887, 0.855316, 0.856354, 0.854279, 0.854156, 0.852905, 0.852234, 0.851349, 0.850403, 0.849701, 0.848724, 0.847931, 0.846893, 0.846436, 0.845734, 0.839447, 0.766388, 0.228851, …….etc etc….
for (int i = 0; i< 44100; i++)
{
mAudioToResample[i] = test[i];
}
As I said, that works. No problems.
When trying to get the array into Gen I tired this but it failed:
void IPlugGenTwoInputs::ProcessDoubleReplacing(double** inputs, double** outputs, int nFrames)
{
// Mutex is already locked for us.
double* in0 = inputs[0]; //pointer to the first sample in the left channel
double* in1 = inputs[1]; //pointer to the first sample in the right channel
WDL_ResampleSample *resampledAudio=NULL;
int numSamples = mResampler.ResamplePrepare(nFrames,1,&resampledAudio);
for (int s = 0; s < numSamples; s++)
{
if (mSampleIndx >= 44100) mSampleIndx = 0;
resampledAudio[s] = mAudioToResample[mSampleIndx++] * mGain;
}
if (mResampler.ResampleOut(in1, numSamples, nFrames, 1) != nFrames)
{
//failed somehow
memset(in1, 0 , nFrames * sizeof(double));
}
memcpy(in1, in0, nFrames * sizeof(double));
//end Resampler example
perform(gen, inputs, num_inputs(), outputs, num_outputs(), nFrames);
}
I thought the above would play the array through the Gen patch but I just get silence.
My question: How can I send one array of sample data (a loop) to one Gen input and a second array of different sample data (another loop) to the second Gen input? Is this possible? Any help would be great.
If you have the time, I uploaded the project here:
Cheers
Dave
bit busy to look at this... i do consultancy via skype if you are still stuck
Sure. I am still stuck. What's your Skype name Oli?
I'm cambridgekoala (based in Estonia) --> Vladimir Putin cuddling a Koala is my profile picture!
well i'm feeling generous... since the C++ looks absolutely horrific on this forum, i've made a gist:
not tested but should show you roughly how to get two separate resampled audio sources into the left and right inputs of your gen process
Thanks very much Oli, I'll check that out tomorrow.
btw, nice work on Virtual CZ. Picked one up from Plugin Boutique last weekend. Not had much of a chance to play but it's sounding good.
Add me to Skype please. I'm sure I'll need your consultancy soon anyway
Dave
Hello Oli,
I noticed that inside the Reset() method of IPlugGen you wrote :
gen->sr = GetSampleRate();
reset(gen);
Is it safe to include also (after the gen->sr assign):
gen->vs = GetBlockSize(); //to assign the "buffer size" to "gen vector size"
You did't add it for a specific reason (stability ?), or you simply forgot to add it?
Is it safe to add that assignment at reset() ?
...Otherwise "gen vector size" will be always fixed to " DEFAULT_BLOCK_SIZE " (assigned in constructor)
Thank you in advance for any hint !