Sidechain - sharing data between plugins

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

Hi all,

I'm working on a plugin in which I'd like to implement sidechain functionality. The easiest way to do this would be to add one additional input to the plugin, but that's not good idea since most hosts can't handle vst effects with more than 2 inputs. So now I'm thinking about creating a separate plugin which would only fill some shared buffer with audio data. This shared audio buffer would then be taken as sidechain input in the main processing plugin. The problem is my coding skills are pretty lame, and I don't know how to create this kind of shared buffer. I've found this: http://support.microsoft.com/default.as ... -US;100634 , but for some reason that doesn't work for me. When I do something like this:

Code: Select all

#pragma data_seg(".MYSEC")
struct SharedData
{
  int plugID;
  bool mutex;
  bool isNew;
  unsigned long blockSize;
  float buffer[32768];
} sidechainBusA;

#pragma data_seg()
#pragma comment(linker, "/SECTION:.MYSEC,RWS")
I always get linker warning saying :

Code: Select all

section '.MYSEC' specified with /SECTION option does not exist
,and no data is shared between plugin instances.
Does anyone have an idea how to do this properly?
Thanks in advance!

cheers,
Bart

Post

I thought most host DID support more than 2 inputs on effects. Which hosts do you mean? :)

Post

Code: Select all

#pragma data_seg(".MYSEC")
You only need shared data segs if you want to
share data accross applications,
if you want to stay in the same host, using static members in your DLL will do the job.
David Viens, Plogue Art et Technologie Inc. Montreal.
https://bsky.app/profile/plgdavid.bsky.social
https://plogue.com

Post

stefancrs wrote:I thought most host DID support more than 2 inputs on effects. Which hosts do you mean? :)
Well maybe I should use "many" instead of "most" :D
The hosts I know that can't make any use of additional inputs are Logic,Audition and freeware Kristal. Also, last time when I tried FL Studio (4.5.x IIRC) and WaveLab (veeery old 3.0 version), they didn't have that ability. I'm sure that this list is not complete.

cheers,
Bart

Post

FEV wrote:
stefancrs wrote:I thought most host DID support more than 2 inputs on effects. Which hosts do you mean? :)
Well maybe I should use "many" instead of "most" :D
The hosts I know that can't make any use of additional inputs are Logic,Audition and freeware Kristal. Also, last time when I tried FL Studio (4.5.x IIRC) and WaveLab (veeery old 3.0 version), they didn't have that ability. I'm sure that this list is not complete.

cheers,
Bart
Ok. So far not many hosts then :) And one can always load up a host-vsti inside a host I guess.

Apart from that, how will you solve the problem really? If sharing data, how will you handle the latency? You never know if the host will try to process the sidechain or the other channel before the other etc.

Post

davidv@plogue wrote: You only need shared data segs if you want to
share data accross applications,
if you want to stay in the same host, using static members in your DLL will do the job.
Hmmm. I did very simple plug where I do something like this:

Code: Select all

in the header:
static float sidSample;

Code: Select all

in the process:
out = 0.f;

if (mode)   // mode = true - throw shared sample to plugin output
 {
   out = sidSample;
 }
else   // mode = false - throw input value to shared sample variable
 {
   sidSample = in;
 };
mode variable is controlled with one of the plugin parameters

Then I instantiated this plugin two times (one with mode=true the other one with mode=false) and expected to get _something_ in the output of receiving plugin, but I only get silence :( Am I doing something stupid (or maybe I'm not doing something important)?
:help:

cheers,
Bart

Post

stefancrs wrote: Ok. So far not many hosts then :) And one can always load up a host-vsti inside a host I guess.
Like I said, these are only the one I'm aware of, and I haven't tested even 5% percent of hosts that are listed in the kvr's "Quick Host links". For me the most important fact is that Logic 5 (which I mostly use) doesn't support such plugins. The rest is not so important :D
Apart from that, how will you solve the problem really? If sharing data, how will you handle the latency? You never know if the host will try to process the sidechain or the other channel before the other etc.
Well first I have to make that data sharing to work, then I will worry about that :D
I know this is possible since I saw this kind of functionality in couple of plugins (for example ModuLR Senderella, Tobybear MixBox, TC Works Compressor DeEsser).

cheers,
Bart

Post

It is possible, yes. But it won't ever work as good as having two inputs.

Hosts that support more than one input:
Podium, energyXT, cubase, bidule, (tracktion with rack filters?). etc :)
I'd prefer supporting modern technology than old and cumbersome technology... :)

Post

stefancrs wrote:It is possible, yes. But it won't ever work as good as having two inputs.

Hosts that support more than one input:
Podium, energyXT, cubase, bidule, (tracktion with rack filters?). etc :)
I'd prefer supporting modern technology than old and cumbersome technology... :)
I can always do it both ways :wink: - one version with with 3-4 inputs and the other with shared buffer.

cheers,
Bart

Post

FEV wrote: I've found this: http://support.microsoft.com/default.as ... -US;100634 , but for some reason that doesn't work for me.
I'm never tried to use shared data segments, but that article says that, besides setting up the named section, "'you must inform the linker of the correct sharing attributes for this new named data section using either the .def file or a linker switch." Did you do this?

I'm not sure you need any fancy data segment tricks anyway. Anything you define in your effect's class as a member variable should be separate from instance to instance, and anything defined global or static should be shared between instances. All that's left to worry about is synchronization - look up mutexes and critical sections. Whoops, sorry - didn't realize you were talking about two different plugins, not two instances of the same plugin. My bad.

If you can accept some latency, you might also consider using a network socket to pass around the sidechain signal, since doing it that way automatically opens up the possiblity of cross-machine sidechaining. Though this is probably a better bet using control-rate signals rather than audio-rate.
Image
Don't do it my way.

Post

this is how I handled it in Senderella...

Code: Select all

#pragma data_seg("SHARED")

	struct BufferRec
	{
		int   id;
		int   mode;
		float left[MAX_BUFFER_SIZE];
		float right[MAX_BUFFER_SIZE];
		int  processCounter;

	};

	BufferRec buffer[MAX_CHANNELS][MAX_INSTANCES];
	
	int       numSendsOnThisCh[MAX_INSTANCES];
	int       numRecvsOnThisCh[MAX_INSTANCES];
	int       instanceSlot[MAX_INSTANCES-1];
	int       randomCheck;

#pragma data_seg()

#pragma comment(linker, "/section:SHARED,RWS")
It seems to work in most hosts I've tried. FL forces a certain order.. like you can't send backwards.. but everything else I tried worked wonderfully.. no latency issues either. :wink:
Last edited by ModuLR on Fri Mar 04, 2005 5:53 pm, edited 1 time in total.
ModuLR / Radio

Post

BTW, I get that warning as well.. "section 'SHARED' specified with /SECTION option does not exist" but it didn't matter... it still works.
ModuLR / Radio

Post

As matter of fact.. here is the entire Senderella Source... maybe you can get something out of that (and for the code Guru's, please don't give me crap about my coding style.. I know it shit already) :lol: ... but if you can get something out of it, go for it!

Code: Select all

/*
  ==============================================================================
  SEnDerELLa v1.03 - written by Sean Person (ModuLR) / 12.02.04
  ==============================================================================
*/


#include "audioeffectx.h"

#include <cstdlib>
#include <windows.h>
#include <time.h>
#include <math.h>


//-----------------------------

static int numInstances = 0;


//===============================================================================
// Setup your baisc filter parameters here
//===============================================================================
const char VENDOR_NAME[64]  = "ModuLR";
const char FILTER_NAME[64]  = "SenDeReLLA";
const long FILTER_ID        = 'SEND';
const long NUM_INPUTS       = 2;
const long NUM_OUTPUTS      = 2;
const long NUM_PARAMS       = 2;
const long NUM_PROGRAMS     = 0;
const long LATENCY          = 0;
const bool IS_A_SYNTH       = false;
const bool HAS_MIDI_IN      = false;
const bool HAS_MIDI_OUT     = false;
const bool SYNC_TO_HOST     = false;


//===============================================================================
// Label your parameter index as constants here (will be used for the index)
//===============================================================================
const int MAX_CHANNELS  = 1;
const int MAX_INSTANCES = 64;
const int MAX_LATENCY   = 4096;
const int MAX_EVENTS    = 250;

const int MODE          = 0;
const int VOLUME        = 1;
const int SEND          = 0;
const int RECEIVE       = 1;
const int PASS_THRU     = 0;
const int REDIRECT      = 1;



//==============================================================================
// Create a shared data segment in dll (these vars become global to all instances)
// and I don't give a shiz if it's technically "wrong" cos it works with NO LATENCY!
//==============================================================================
#pragma data_seg("SHARED")

	struct BufferRec
	{
		int   id;
		int   mode;
		float left[MAX_LATENCY];
		float right[MAX_LATENCY];
		int  processCounter;

	};

	BufferRec buffer[MAX_CHANNELS][MAX_INSTANCES];
	
	int       numSendsOnThisCh[MAX_INSTANCES];
	int       numRecvsOnThisCh[MAX_INSTANCES];
	int       instanceSlot[MAX_INSTANCES-1];
	int       randomCheck;

#pragma data_seg()

#pragma comment(linker, "/section:SHARED,RWS")




//==============================================================================
//    This wraps MyVST as an AudioEffectX...
//==============================================================================
class MyVST: public AudioEffectX
{

private:

	double                   sampleRate;
	int                      bufferSize;

	bool                     updateFilter;

	int                      currentProgram;
	float                    param[NUM_PARAMS];

	bool                     switched,initializing,clearBuffer;
	int                      localInstanceNum;
    int                      randomNum;

	int						 oldProcessCounterValue[MAX_INSTANCES]; 
	int                      loopCounter;



public:
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructor
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	MyVST (audioMasterCallback audioMaster): AudioEffectX (audioMaster,NUM_PROGRAMS,NUM_PARAMS)
	{

		for (int i = 0; i < MAX_CHANNELS; i++)
			
			for (int j = 0; j < MAX_INSTANCES; j++)
			{
				for (int k = 0; k < MAX_LATENCY; k++)
				{
					buffer[i][j].left[k]  = 0;
					buffer[i][j].right[k] = 0;
					buffer[i][j].processCounter = 0;
				}

			}


		initializing = true;
		clearBuffer  = false;

		sampleRate                  = 0;
		bufferSize                  = 0;
		currentProgram			    = 0;
		++numInstances;

		for (int i = 0; i < MAX_INSTANCES; i++)
		  oldProcessCounterValue[i] = 0;
		loopCounter                 = 0;

		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// Basic configuration sent from plugin to host during creation of the effect/instrument
		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        setUniqueID                 (FILTER_ID);
        setNumInputs                (NUM_INPUTS);
        setNumOutputs               (NUM_OUTPUTS);
        setInitialDelay             (LATENCY);
		programsAreChunks           (false);
		wantEvents                  (true);
		canMono                     (true);
		canProcessReplacing         (false);


		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// Initialiaze your default parameters here
		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		setParameter                (MODE   ,0);
		setParameter                (VOLUME ,1);

		initialize();

    }



	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Deconstructor
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	~MyVST()
    {
		int tempCh;
		bool sendCleared;

		sendCleared = false;

		tempCh = 0;
 
		while (!sendCleared)
		{
			// assign shared randomCheck value to randomNum
			randomCheck = randomNum;

			// a a delay to see if any other instances are closing,
			// which will ultimately change the randomCheck value
			Sleep(50);

			//if nothing has changed, then we are ok to clear this send
			if (randomCheck = randomNum)
			{				
				if ( param[MODE] == SEND )
					numSendsOnThisCh[tempCh] -= 1;
			
				if ( param[MODE] == RECEIVE ) 
					numRecvsOnThisCh[tempCh] -= 1;

				buffer[tempCh][localInstanceNum].id=0;
				
				sendCleared = true;
			}
		}


		if (--numInstances == 0)
		{
		}
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// a little mathematic function
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	inline int round(double value)
	{
		return (int)floor(value + 0.5);
	}



	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Initialize a senderella instance
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	void initialize()
	{

		int     tempCh, tempMode;
		bool    foundSlot;

		initializing = true;
		
		//set random seed to time of day
		srand(unsigned(time(NULL)));

		tempCh     = 0;             
		tempMode   = round(param[MODE]);
 

		// when multiple instances of senderella are loaded simultaneously,
		// we must insure we have a proper instance count for a particular
		// channel
		
		while (initializing)
		{
			// generate a random number
			randomNum = rand() % 100000;
			Sleep(50);

			// assign randomCheck to randNum
			randomCheck = randomNum;

			// place a small delay so other instances have a chance to change
			// the randomCheck value
			Sleep(50);

			// if another instance of Senderella has not changed the RandomCheck value
			// then we should increment the number of instances which exist on this channel
			if (randomCheck == randomNum)
			{

				if ( param[MODE] == SEND )
					numSendsOnThisCh[tempCh] += 1;

				// if sender is on receive mode, increment number of recvs on channel
				if ( param[MODE] == RECEIVE )
					numRecvsOnThisCh[tempCh] += 1;

				for (int i = 1; i < MAX_INSTANCES; i++)

					if (buffer[tempCh][i].id == 0)
					{
						// assign this instance it's own local instance number
						localInstanceNum = i;

						foundSlot = true;

						// assign this instance a unique ID
						buffer[tempCh][i].id   = randomNum;

						//buffer[tempCh][i].mode = round(param[MODE]);
						break;
					}
				
				// we are done
				initializing = false;	
			}

		}

	}




	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Send host effect name, vendor info, and if plugin is an effect or instrument
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	bool getEffectName    (char* name) { name=(char*)FILTER_NAME; return true;}
	bool getVendorString  (char* text) { text=(char*)VENDOR_NAME; return true;}
	bool getProductString (char* text) { text=(char*)FILTER_NAME; return true;}
	long getVendorVersion ()	       { return 1000;                         }
	VstPlugCategory getPlugCategory()  { return IS_A_SYNTH ? kPlugCategSynth : kPlugCategEffect; }



	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//Set sample rate and block size
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	void setSampleRate (float newRate) { sampleRate = newRate; }
	void setBlockSize  (long newSize)  { bufferSize = newSize; }



	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//Return CanDo's to host
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	long canDo (char* text)
	{	
		if (text == "receiveVstEvents")                      return 1;
		if (text == "sendVstEvents")                         return 1;
		if ((text == "receiveVstMidiEvents") && HAS_MIDI_IN) return 1;
		if ((text == "sendVstMidiEvent") && HAS_MIDI_OUT)    return 1;
		if ((text == "receiveVstTimeInfo") && SYNC_TO_HOST)  return 1;
		
		return -1;
	}



	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Setup input/output channel labels
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	bool getInputProperties(long index, VstPinProperties* properties)
	{
		if (index < NUM_INPUTS)
		{
			switch (index)
			{
				default : strcpy(properties->label,"Input");
			}
			properties->flags = kVstPinIsActive;
			properties->flags = properties->flags | kVstPinIsStereo;
			return true;
		}
		return false;
	}

	//---------------------------------------------------------------------

	bool getOutputProperties(long index, VstPinProperties* properties)
	{

		if (index < NUM_OUTPUTS)
		{
			switch (index)
			{
				default : strcpy(properties->label,"Output");
			}
			properties->flags = kVstPinIsActive;
			properties->flags = properties->flags | kVstPinIsStereo;
			return true;
		}
		return false;
	}


	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Routines related to parameters
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	float getParameter (long index)
	{
		if (index >= NUM_PARAMS) 
			return 0;
		else 
			return param[index];
	}

	//---------------------------------------------------------------------

	void setParameter (long index, float value)
	{	

	int tempPrevCh,tempCh,tempCurCh;


	tempCh       = 0;
	tempPrevCh   = 0;
	tempCurCh	 = 0;
 
	switch (index)
	{
		case MODE:
		if (!initializing)
		{

			// if the new mode value has changed then adjust numRecvsOnThisCh accordingly.
			if ( round(param[MODE]) != round(value) )
			{
				if ( round(value) == RECEIVE )
				{
					numRecvsOnThisCh[0] += 1;
					numSendsOnThisCh[0] -= 1;
				}
				else
				{
					numRecvsOnThisCh[0] -= 1;
					numSendsOnThisCh[0] += 1;
				}
			}

		}
		break;

	}


	param[index] = value;
	updateFilter = true;

	}

	//---------------------------------------------------------------------

	// adds extra text after the parameter value displayed
	void getParameterLabel (long index, char* label)  
	{ 
		 if (index == VOLUME) strcpy(label,"%");
	}

	//---------------------------------------------------------------------
	
	// set the value displayed by the host's GUI
	void getParameterDisplay (long index, char* text) 
	{ 
		switch (index)
		{


			case  VOLUME  : long2string( round( (param[VOLUME]*100) ),text);
							break;

			case  MODE    : if (round(param[MODE]) == SEND) 
								strcpy(text,"Send");
                            else 
								strcpy(text,"Return"); 
							break;

			default       : strcpy(text,"");
		}
	
		 
	}

	//---------------------------------------------------------------------

	void getParameterName (long index, char* text)    
	{
		switch (index) 
		{
			case VOLUME : strcpy(text,"Amount");         break;
			case MODE   : strcpy(text,"Mode");           break;
			default     : strcpy(text,"---");            break;
		}
	}





	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Routines related to audio processing
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	void process (float** inputs, float** outputs, long num) 
	{
		float* ins[NUM_INPUTS];
		float* outs[NUM_OUTPUTS];
		int	temp_Mode,temp_Ch,k ;
		float temp_Vol;
		bool processing;

		processing = true;


		for (int i=0; i < NUM_INPUTS; i++)   ins[i] = *inputs++;
		for (int i=0; i < NUM_OUTPUTS; i++) outs[i] = *outputs++;


		temp_Mode = round( param[MODE] );
		temp_Ch   = 0;
		temp_Vol  = param[VOLUME];

		if (temp_Mode == SEND) 
		{
			// try to catch is process is not being called by host.
			if (buffer[temp_Ch][localInstanceNum].processCounter == 0)
				buffer[temp_Ch][localInstanceNum].processCounter = 1;
			else
				buffer[temp_Ch][localInstanceNum].processCounter = 0;


			for (int i=0; i < num; i++)
			{
				// write to buffer only if there is a send there
				if (numRecvsOnThisCh[temp_Ch] > 0 )
				{
					buffer[temp_Ch][localInstanceNum].left[i]  = *ins[0] * temp_Vol;
					buffer[temp_Ch][localInstanceNum].right[i] = *ins[1] * temp_Vol;
				}
			
				
				// Pass all audio thru in simplified version
					*outs[0] += *ins[0];
					*outs[1] += *ins[1];


			for (int j=0; j < NUM_INPUTS; j++) ins[j]++;
			for (int j=0; j < NUM_OUTPUTS; j++) outs[j]++;
			}
		}
		else
		if (temp_Mode == RECEIVE)
		{
			
			for (int i=0; i < num; i++)
			{
				for (int j = 1; j <= (numSendsOnThisCh[temp_Ch] + numRecvsOnThisCh[temp_Ch]); j++)				
					if (numSendsOnThisCh[temp_Ch] > 0)
					{
			  	  		k = 0;

						while ( (buffer[temp_Ch][j].id == 0) && ( (j+k) <= (numSendsOnThisCh[temp_Ch] + numRecvsOnThisCh[temp_Ch]) )  )
							k += 1;
						
						//check loop
						//if ( ((int)i % 10) == 0)
						//{
							oldProcessCounterValue[loopCounter] = buffer[temp_Ch][j+k].processCounter;
							loopCounter++;
						//}

						if (loopCounter = 64)
						{
							for (int l=1; l < loopCounter; l++)
								if (oldProcessCounterValue[0] =! oldProcessCounterValue[l])
								{	
									processing = true;
									break;
								}
								else
									processing = false;

							loopCounter = 0;

							if (processing == false)
							{
							    buffer[temp_Ch][j+k].left[i] = 0;
							   	buffer[temp_Ch][j+k].right[i] = 0;
							}
						}
						

						*outs[0] += buffer[temp_Ch][j+k].left[i];
						*outs[1] += buffer[temp_Ch][j+k].right[i];
					}
					else
					{
						*outs[0] = 0;
						*outs[1] = 0;
					}
				  
				


				*outs[0] = (*outs[0] + *ins[0]) * temp_Vol;
				*outs[1] = (*outs[1] + *ins[1]) * temp_Vol;
				
				for (int j=0; j < NUM_INPUTS; j++) ins[j]++;
				for (int j=0; j < NUM_OUTPUTS; j++) outs[j]++;
			}

			clearBuffer = false;
		}

	}
	
	//-------------------------------------------------------------------------

	void resume()
	{
		wantEvents(true);

	}

	//-------------------------------------------------------------------------

    void suspend()
	{
		for (int i = 0; i < MAX_CHANNELS; i++)
			
			for (int j = 0; j < MAX_INSTANCES; j++)
			{
				for (int k = 0; k < MAX_LATENCY; k++)
				{
					buffer[i][j].left[k]  = 0;
					buffer[i][j].right[k] = 0;
				}

			}
		
	}


	private:
};






//==============================================================================
// main()
//==============================================================================


bool oome = false;


//------------------------------------------------------------------------
// Prototype of the export function main
//------------------------------------------------------------------------

__declspec(dllexport) void *main (audioMasterCallback audioMaster);

__declspec(dllexport) void *main (audioMasterCallback audioMaster)
{
	// Get VST Version
	if (!audioMaster (0, audioMasterVersion, 0, 0, 0, 0)) return 0;

	// Create the AudioEffect
	MyVST* effect = new MyVST (audioMaster);
	if (!effect) return 0;

	// Check if no problem in constructor
	if (oome)
	{
		delete effect;
		return 0;
	}
	return effect->getAeffect ();
}




void* hInstance;
BOOL WINAPI DllMain (HINSTANCE hInst, DWORD dwReason, LPVOID lpvReserved)
{
	hInstance = hInst;
	return 1;
}
hopefully something helpful might be lodged in there... :)
ModuLR / Radio

Post

Wow..Thanks for sharing ModuLR :-)
Image

Post

Borogove wrote: I'm never tried to use shared data segments, but that article says that, besides setting up the named section, "'you must inform the linker of the correct sharing attributes for this new named data section using either the .def file or a linker switch." Did you do this?
Yes. That's what this #pragma is for:

Code: Select all

#pragma comment(linker, "/SECTION:.MYSEC,RWS")
This is the same as putting:

Code: Select all

SECTIONS   .MYSEC   READ WRITE SHARED
in .def file.

cheers,
Bart

Post Reply

Return to “DSP and Plugin Development”