PDA

View Full Version : Music Converter DSP Architecture



Spoon
11-26-2010, 03:11 PM
There now follows the specification for the DSP Architecture:



//================================================== =============================
// 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):




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
};





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)





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>



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