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