There now follows the specification for the DSP Architecture:

Code:
//===============================================================================
// Create a DSP object, is a pointer to anything, in this case a c++ class
//===============================================================================

extern "C" __declspec( dllexport ) void *DSP_Create(STNStdReport &_StdErrors)
{
	return(new clDSP(_StdErrors));
}

//===============================================================================
// Destroy previously created DSP object
//===============================================================================
extern "C" __declspec( dllexport ) int DSP_Destroy(void *DSP)
{
	if (DSP)
		delete ((clDSP *)DSP);
	return(1);
}

//===============================================================================
// Shows the DSP configuration page, Encode Settings contains the DSP settings (could be --setting1="xyz"  --setting2="123"  (you decide what on the remove page call) 
//===============================================================================
extern "C" __declspec( dllexport ) HWND DSP_ShowConfigBit(void *DSP, HWND OnForm, int XOffset, int YOffset, wchar_t *EncodeSettings)
{
	clDSP *pDSP = (clDSP *)DSP;
	if (pDSP)
		return(pDSP->ShowConfigBit(OnForm, XOffset, YOffset, EncodeSettings));
	return(NULL);
}

//===============================================================================
// Removes the DSP settings page, use this opportunity to return the settings  *** returned string must persist, whilst the *DSP object exists
//===============================================================================
extern "C" __declspec( dllexport ) wchar_t *DSP_RemoveConfigBit(void *DSP, HWND OnForm)
{
	clDSP *pDSP = (clDSP *)DSP;
	if (pDSP)
		return(pDSP->RemoveConfigBit(OnForm));
	return(NULL);
}

//===============================================================================
// Begin a DSP effect
//===============================================================================
extern "C" __declspec( dllexport ) int DSP_BeginConversion(void *DSP, STdBEncoderFluid &EncoderFluid, wchar_t *DSPSettings)
{
	clDSP *pDSP = (clDSP *)DSP;
	if (pDSP)
		return(pDSP->BeginConversion(EncoderFluid, DSPSettings));
	return(0);
}

//===============================================================================
// Final DSP call as encoded file is about to close
//===============================================================================
extern "C" __declspec( dllexport ) int DSP_EndConversion(void *DSP, STdBEncoderFluid &EncoderFluid)
{
	clDSP *pDSP = (clDSP *)DSP;
	if (pDSP)
		return(pDSP->EndConversion(EncoderFluid));
	return(0);
}

//===============================================================================
// After the ID tags are written, another call to DSP
//===============================================================================
extern "C" __declspec( dllexport ) int DSP_AfterConversion(void *DSP, STdBEncoderFluid &EncoderFluid)
{
	clDSP *pDSP = (clDSP *)DSP;
	if (pDSP)
		return(pDSP->AfterConversion(EncoderFluid));
	return(0);
}

//===============================================================================
// Called if Non-live DSP conversion
//===============================================================================
extern "C" __declspec( dllexport ) int DSP_PassNonLive(void *DSP, wchar_t *TmpWavFile, WAVEFORMATEXTENSIBLE *wfxex, wchar_t *DSPSettings, wchar_t *EvtNameQuit)
{
	clDSP *pDSP = (clDSP *)DSP;
	if (pDSP)
		return(pDSP->PassNonLive(TmpWavFile, wfxex, DSPSettings, EvtNameQuit));
	return(0);	
}

//===============================================================================
// A live DSP call, each audio block is passed for processing
//===============================================================================
extern "C" __declspec( dllexport ) int DSP_PassAudioBlock(void *DSP, STdBAudioBlock &AudioBlock)
{
	clDSP *pDSP = (clDSP *)DSP;
	if (pDSP)
		return(pDSP->PassAudioBlock(AudioBlock));
	return(0);
}

//===============================================================================
// Gets DSP information before conversion
//===============================================================================
extern "C" __declspec( dllexport ) int DSP_Get(void *DSP, wchar_t *Getting, STdBCodecGetSet &Pass)
{
	if (DSP)
		return(((clDSP *)DSP)->Get(Getting, Pass));
	return(0);
}

//===============================================================================
// Sets DSP values before conversion
//===============================================================================
extern "C" __declspec( dllexport ) int DSP_Set(void *DSP, wchar_t *Setting, STdBCodecGetSet &Pass)
{
	if (DSP)
		return(((clDSP *)DSP)->Set(Setting, Pass));
	return(0);
}

Where the object DSP_Create can be a class pointer and used later on as a class.

Structures (1 byte alignment packing):

Code:
struct STdBCodecGetSet {
	int Index;
	int Item1;
	__int64 Item2;
	__int64 Item3;
	wchar_t *Item4;
	wchar_t *Item5;
	wchar_t *Item6;
	void *Item7;
};

//------used to describe an audio format--------
struct STdBAudioInfo {		// NB by default dB sets all items to 0/NULL
	WAVEFORMATEXTENSIBLE WFXEx;		// ONLY uncompressed audio allowed here
	int bps;				// Average bitrate (in bits per second) ie 192000
	__int64 Lengthmsec;		// Time length in mili seconds (length of audio block, or entire file Decoder::Open)
	__int64 FileSize;		// only used by Decoder::Open, size in bytes of compressed data
	int Blank0;				// not used
	int Blank1;			// not used
};

struct STNStdReport {	
	HANDLE hFileError;			// <in> file handle for errors, can be NULL - if write should write 'Line describing problem\r\n', no filenames
	HANDLE hFileInfo;			// <in>	file handle for Information pass back to main prog, can be NULL - as above
	HANDLE hFileDebug;			// <in> file handle for Debugging, can be NULL - as above
};

struct STdBEncoderFluid {	// fluid items (ie can be changed by DSP / Compressor / Input)
							// IMPORTANT: Encoder Fluid is passed to begin and end BUT the one passed to END will have final settings (ie wfx, etc)
							// ** if changing say ID Tags then duplicate and pass new pointer (ie data owned by changer)
	wchar_t *InFileName;	// decoding filename (with extension, CANNOT CHANGE)  Might be '-' for stdin from CD Input to CoreConverter
	wchar_t *OutFileName;	// encoding filename (with extension, is .IGNORE if utility codec)
							//	** Special case memory encode CAN be: [memory]    (nb returned data should as written to file, ie with headers)
							// if memory encode and change WFX then update in pAudioInfo
	wchar_t *EncodingStr;	// Codec encoding Settings
	STdBAudioInfo *pAudioInfo;	// items such as FileSize / Lengthmsec might be 0 (ie Aux Input) (CAN ONLY CHANGE BEFORE Encoder::BeginConversion)
	void *IDTags;			
	DWORD IDTagByteSize;	
	void *AudioProps;		
	DWORD AudioPropsByteSize;
	int ConversionError;	// <read only> set to true if there was an error
};

//--------An Audio Block, from Decode::DecodeBlock and sent to Encoder---------
struct STdBAudioBlock		// NB by default dB sets all items to 0/NULL
{
	void *pData;			// <out decoder><in encoder> can be NULL, data block is owned by decoder and is valid until next call or class destroy
	DWORD DataBytes;		// <out decoder><in encoder> Datasize as pointed to by pData
	STdBAudioInfo AudioInfo;// <out decoder><in encoder> Describes audio data
	__int64	PositionMiliSec;// <out decoder><in encoder> Start position of block in Mili Seconds
	int IsLast;				// <out decoder><in encoder> when !=0 is last data block
	int Blank0;				// not used
	int Blank1;				// not used
	wchar_t *PassOutAction;	// <out - both> an action: both encoder + dsp + decoder (set to NULL to use last action, "" to kill last action)
	void *Blank3;			// not used

	// Decoder: ** Special if file was opened with DECODE_WANT_DECODEPACKETS:
	//		pData points to compressed data and DataBytes is the size
	//		IsLast is set when last data block
	//		return uncompressed data when can, and a valid WFX when able to

	// Encoder: ** Special case, if OutFileName is [memory] then return compressed
	// data (with headers) in pData + DataBytes  ** if encoder changes the WFX put new in AudioInfo
};
Code:
Common DSP 'Get' items, all other items in STdBCodecGetSet = 0 (both in + out)

	'Communicate'			called at various times to give this component the change to Get / Set other (Encoder / DSP / Decoder)
		<see decoder Communicate, is same>

	'IsLive'	
		Item4: <in> wide str DSP Settings String (DO NOT STORE THIS)
		return 1 = yes live effect (otherwise rendered to tmp wave)

	'SendOverReplayGainTags'		(R13.1 required)
		return:  1=Yes, default=no (they are dropped)
Code:
Common DSP 'Set' items, all other items in STdBCodecGetSet = 0 (both in + out)

	'BatchID'
		Item1:	<in> Unique ID			** might not be called, ie coreconverter.exe called from cmd line
		
	'BatchEndConversion'				
		Item1:	<in> Length of Data block (pointed by Item7)
		Item2:  <in> BatchID
		Item4:  <in> DSP CLI String 
		Item5:  <in> wide str Encoder Compression CLI String 
		Item6:  <in> wide str encoder name, ie 'Wave'
		Item7:	<in> Packed IDTag Datablock (can be changed by DSP), Tags as:

							file1_in="filename"			
							file1_out="filename"
							file1_conversionhaderrors			// exists then had error
							...

	'CommunicateResult'		a result from our components 'Communicate' request
		<see decoder CommunicateResult, is same>
Code:
  Order of Encoding:

		Loop For All Files:
			dMC - unqiue batch ID created, write tmp files to TmpFolder\dBxxxxxxxxxx\, do not worry about clean up
				  **** IF BATCH ID is not sent to decoder/encoder/dsp then is not part of batch (CLI) ****

			    Encoders Created, .Get(L"RequiresDSP" which DSP effect is required, then Encoder Freed			  

				--For Each File (CoreConverter)--
				CoreConverter Instance Called
					Decoder Loaded, Object Created (batchid set)
					Encoder Loaded, Object Created (batchid set)

					if enocder SendRawUnCompressed then done here (special routine)
							Decoder.Open (IDTags + Audio Info Read)
							Decoder.Close(EncoderFluid)								(note object still exists)
							Creates 'EncoderFluid' (values which can change)
							Encoder.BeginConversion (Passed EncoderFluid)
							// *** NOTE Encoder.EndConversion is NOT CALLED		
							// *** Encoder is the same object between call to GET("SendRawUnCompressed") and BeginConversion
					else     // Normal conversion

							DSP Loaded, Object Created (batchid set)
							[ == BeforeOpen Communication == ]
							Encoder asked >> NeedHQAudio >> Decoder
							Decoder.Open (IDTags + Audio Info Read + File Ready to decode)
							Creates 'EncoderFluid' (values which can change)				
							NONE LIVE DSPs (decode and render for them, as can change format)
								DSP.PassNonLive
								*** any live DSPs are done here as well in correct order (calling DSP.BeginConversion before) ***
							DSP.BeginConversion (Passed EncoderFluid)   Note: LIVE only
							Encoder.BeginConversion (Passed EncoderFluid)
							[ == BeforeEncoding Communication == ]
							Encode Loop:
								Decoder.DecodeBlock
								DSP.PassAudioBlock						Only Live (not already used in Non-Live)
								Encoder.EncodeBlock
								(MsgTo: DMC:  with the % done, from CoreEncoder.exe to host)
							[ == EndEncoding Communication == ]
							Decoder.Close(EncoderFluid)								(note object still exists)
							DSP.EndConversion(EncoderFluid)					Note: LIVE only		(note object still exists)
							Encoder.EndConversion(EncoderFluid, &ShouldWriteTags)	(note object still exists)
							[ If Temp file: Tmp File Replaces Orig Here, if no error ]
							[ Writes Tags if required ]
							*** CoreConverter will look at EncoderFluid.AudioProps   for FileName1: FileName2:  which is set by Multi-Encoder to tell of multi-filename conversions
							***    if FileName1 is there then EncoderFluid.OutFilename is not used (for AfterConversion, etc)
								(MsgTo: DMC: FileName: xyz   MsgTo: DMC: FileName: xyz2)
							[ == AfterConversion Communication == ]		*** DECODE CLOSE AND ENCODER ENDCONVERSION CALLED BEFORE THIS ***
							DSP.AfterConversion (Passed EncoderFluid)	Note: LIVE + NON-LIVE *** NOW PASSED FINAL FILENAME (can be called 2x if 2 filenames from EncoderFluid.AudioProps) (before would be .tmp.xxx) on error is not passes final filename but still tmp one			
					Encoder Object Deleted / Encoder DLL Freed
					DSP Object Deleted	/ DSP DLL Freed
					Decoder Object Deleted / Input DLL Freed

			    All DSPs created, passed batch ID, given list of files + conversion results in BatchEndConversion, freed
			dMC Shows Errors / Info / Debug