There now follows the specification for the DSP Architecture:
Where the object DSP_Create can be a class pointer and used later on as a class.
Structures (1 byte alignment packing):
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