title
Products            Buy            Support Forum            Professional            About            Codec Central
 

Music Converter DSP Architecture

Collapse
This topic is closed.
X
This is a sticky topic.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Spoon
    Administrator
    • Apr 2002
    • 44505

    Music Converter DSP Architecture

    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
    Spoon
    www.dbpoweramp.com
Working...

]]>