Log in

View Full Version : Using the Aud-X SDK library in Delphi


TFM_TheMask
22nd May 2006, 19:28
I'm trying to translate the Aud-X SDK Library to Delphi but I don't get it to work. Is there anyone with knowledge of C++ and Delphi that can help me.

Here is my translation of the header file:

unit AUDXLIB1;

interface
uses
{$IFDEF WIN32}
Windows;
{$ELSE}
Wintypes, WinProcs;
{$ENDIF}


{$IFNDEF AUDXLIB_H}
{$DEFINE AUDXLIB_H}

{$IFDEF __cplusplus }
{$ENDIF}


{///============================================================================ }
{///:::::::::::::::::::::::::::::::ENCODER:::::::::::::::::::::::::::::::::::::: }

{+//* }
{-* Initializes audx encoding }
{-* Input: }
{-* quality - values: 0 (STRQ 80 kbps), 1 (STDQ 128 kbps), 2 (HGHQ 192 kbps) or 3 (SPBQ 192 kbps) }
{-* Returns: }
{-* 0 - couldn't start new encoding process, }
{-* nonzero - handler of the newly initialized encoding process }
{= }
var
initEncoding: function(quality: Integer): LongInt cdecl {$IFDEF WIN32} stdcall {$ENDIF};

{+//* }
{-* Encodes audx frame. }
{-* Input: }
{-* henc - handler of an encoding process, }
{-* pcm_block - input buffer containing pcm data to be encoded (must be nonNULL) with 6912 samples (1152 per each channel), }
{-* the interlaced channel order MUST be: [0: FL] [1: FR] [2: C] [3: LFE] [4: SL] [5: SR]. }
{-* Output: }
{-* audx_frame - output buffer filled with audx stream data }
{-* }
{-* Returns: }
{-* -1 - handler of an uninitialized encoding process, invalid input data or error in processing, }
{-* 0 - input data and processing correct - needs more input, }
{-* frameLength - frame length (in bytes) - the data int audx_frame can be consumed. }
{= }
var
encodeAudXframe: function(henc: LongInt;
var pcm_block: SmallInt;
var audx_frame: Byte): Integer cdecl {$IFDEF WIN32} stdcall {$ENDIF};

{+//* }
{-* Flushing internal buffers. Should be called after all PCM input samples have been consumed. }
{-* Output: }
{-* henc - handler of an encoding process, }
{-* audx_frame - output buffer filled with audx stream data. }
{-* }
{-* Returns: }
{-* -1 - flushing finished - all internal buffers are empty and encoding process is reset }
{-* (henc is no longer a handler of the process), }
{-* or uninitialized encoding process, }
{-* 0 - flushing should be called once again - no output data produced, }
{-* frameLength - frame length (in bytes) - the data in audx_frame can be consumed. }
{= }
var
flushEncoder: function(henc: LongInt;
var audx_frame: Byte): Integer cdecl {$IFDEF WIN32} stdcall {$ENDIF};
{///============================================================================ }


{///============================================================================ }
{///:::::::::::::::::::::::::::::::DECODER:::::::::::::::::::::::::::::::::::::: }
{+//* }
{-* Initializes audx decoding }
{-* Input: }
{-* quality - values: 0 (STRQ 80 kbps), 1 (STDQ 128 kbps), 2 (HGHQ 192 kbps) or 3 (SPBQ 192 kbps) }
{-* Returns: }
{-* 0 - couldn't initilize ne decoding process }
{-* nonzero - handler of the newly initialized decoding process }
{= }
var
initDecoding: function: LongInt cdecl {$IFDEF WIN32} stdcall {$ENDIF};

{+//* }
{-* Decodes audx/mp3 frame. }
{-* Input: }
{-* hdec - handler of a decoding process, }
{-* audx_frame - input buffer containing data to be decoded (must be nonNULL), }
{-* audx_frame_size - size of the input buffer in bytes (must be > 0) }
{-* }
{-* Output: }
{-* dec_pcm_block - output buffer filled with 16bits PCM samples (must be nonNULL) }
{-* dec_pcm_block_size - size of the output buffer in bytes (must be nonNULL) }
{-* is_audx - indicates whether input data contained an audx frame or regular mp3 (must be nonNULL) }
{-* }
{-* Returns: }
{-* -1 - handler of an uninitialized decoding process, invalid input data or error in processing, }
{-* 0 - input data and processing correct, input data was not consumed (should be supplied once again) }
{-* 1 - input data and processing correct, input data was consumed (new input portion can be supplied) }
{= }
var
decodeAudXframe: function(hdec: LongInt;
var audx_frame: array of char;
audx_frame_size: LongInt;
var dec_pcm_block: SmallInt;
var dec_pcm_block_size: LongInt;
var is_audx: Integer): Integer cdecl {$IFDEF WIN32} stdcall {$ENDIF};

{+//* }
{-* Resets an initialized decoding process }
{-* (puts the process in a uninitialized state, hdec is no longer a handler of the process), }
{-* or does nothing if a decoding process is uninitialized }
{-* Input: }
{-* hdec - handler to a decoding process }
{= }
var
resetDecoder: procedure(hdec: LongInt) cdecl {$IFDEF WIN32} stdcall {$ENDIF};
{///============================================================================ }

{$IFDEF __cplusplus}
{$ENDIF}

{$ENDIF}

var
DLLLoaded: Boolean { is DLL (dynamically) loaded already? }
{$IFDEF WIN32} = False; {$ENDIF}

implementation

var
SaveExit: pointer;
DLLHandle: THandle;
{$IFNDEF MSDOS}
ErrorMode: Integer;
{$ENDIF}

procedure NewExit; far;
begin
ExitProc := SaveExit;
FreeLibrary(DLLHandle)
end {NewExit};

procedure LoadDLL;
begin
if DLLLoaded then Exit;
{$IFNDEF MSDOS}
ErrorMode := SetErrorMode($8000{SEM_NoOpenFileErrorBox});
{$ENDIF}
DLLHandle := LoadLibrary('AUDXLIB.DLL');
if DLLHandle >= 32 then
begin
DLLLoaded := True;
SaveExit := ExitProc;
ExitProc := @NewExit;
@initEncoding := GetProcAddress(DLLHandle,'initEncoding');
{$IFDEF WIN32}
Assert(@initEncoding <> nil);
{$ENDIF}
@encodeAudXframe := GetProcAddress(DLLHandle,'encodeAudXframe');
{$IFDEF WIN32}
Assert(@encodeAudXframe <> nil);
{$ENDIF}
@flushEncoder := GetProcAddress(DLLHandle,'flushEncoder');
{$IFDEF WIN32}
Assert(@flushEncoder <> nil);
{$ENDIF}
@initDecoding := GetProcAddress(DLLHandle,'initDecoding');
{$IFDEF WIN32}
Assert(@initDecoding <> nil);
{$ENDIF}
@decodeAudXframe := GetProcAddress(DLLHandle,'decodeAudXframe');
{$IFDEF WIN32}
Assert(@decodeAudXframe <> nil);
{$ENDIF}
@resetDecoder := GetProcAddress(DLLHandle,'resetDecoder');
{$IFDEF WIN32}
Assert(@resetDecoder <> nil);
{$ENDIF}
end
else
begin
DLLLoaded := False;
{ Error: AUDXLIB.DLL could not be loaded !! }
end;
{$IFNDEF MSDOS}
SetErrorMode(ErrorMode)
{$ENDIF}
end {LoadDLL};

begin
LoadDLL;
end.


And here is the sample program to get it to work. I am specially interested in de decoder functionality and the way to tell if the mp3 is Aud-X:

program TestAudX;

uses
AUDXLIB1 in 'AUDXLIB1.PAS',
Classes, SysUtils, dialogs;

var
Handle : THandle;
stream : TFileStream;
size : Longint;
Buffer: array [1..2048] of char;
IsAudX : integer;
mp3fill : longint;
pcm : smallint;
res : integer;
begin
IsAudX := 0;
mp3fill := 102400;
pcm := sizeof(mp3fill);
Handle := InitDecoding;
stream := TFileStream.Create('d:\audx.mp3', fmOpenReadWrite or fmShareDenyWrite);
Fillchar(Buffer, sizeof(Buffer), #0);
size := stream.Read(Buffer, sizeof(buffer));
res := decodeAudXframe(handle, buffer, size , pcm, mp3fill, IsAudX);
if (IsAudX = 1) then
showmessage('AudX');
Fillchar(Buffer, sizeof(Buffer), #0);
size := stream.Read(Buffer, sizeof(buffer));
ResetDecoder(handle);
end.

Myrsloik
22nd May 2006, 21:27
A link to/copy of the original header file would make this much easier.

TFM_TheMask
22nd May 2006, 21:37
Sorry, here you go:

#ifndef AUDXLIB_H
#define AUDXLIB_H

#if defined( __cplusplus )
extern "C"
{
#endif


//============================================================================
//:::::::::::::::::::::::::::::::ENCODER::::::::::::::::::::::::::::::::::::::

/**
* Initializes audx encoding
* Input:
* quality - values: 0 (STRQ 80 kbps), 1 (STDQ 128 kbps), 2 (HGHQ 192 kbps) or 3 (SPBQ 192 kbps)
* Returns:
* 0 - couldn't start new encoding process,
* nonzero - handler of the newly initialized encoding process
*/
long __cdecl initEncoding ( int quality );

/**
* Encodes audx frame.
* Input:
* henc - handler of an encoding process,
* pcm_block - input buffer containing pcm data to be encoded (must be nonNULL) with 6912 samples (1152 per each channel),
* the interlaced channel order MUST be: [0: FL] [1: FR] [2: C] [3: LFE] [4: SL] [5: SR].
* Output:
* audx_frame - output buffer filled with audx stream data
*
* Returns:
* -1 - handler of an uninitialized encoding process, invalid input data or error in processing,
* 0 - input data and processing correct - needs more input,
* frameLength - frame length (in bytes) - the data int audx_frame can be consumed.
*/
int __cdecl encodeAudXframe ( long henc, short* pcm_block, unsigned char* audx_frame );

/**
* Flushing internal buffers. Should be called after all PCM input samples have been consumed.
* Output:
* henc - handler of an encoding process,
* audx_frame - output buffer filled with audx stream data.
*
* Returns:
* -1 - flushing finished - all internal buffers are empty and encoding process is reset
* (henc is no longer a handler of the process),
* or uninitialized encoding process,
* 0 - flushing should be called once again - no output data produced,
* frameLength - frame length (in bytes) - the data in audx_frame can be consumed.
*/
int __cdecl flushEncoder ( long henc, unsigned char* audx_frame );
//============================================================================


//============================================================================
//:::::::::::::::::::::::::::::::DECODER::::::::::::::::::::::::::::::::::::::
/**
* Initializes audx decoding
* Input:
* quality - values: 0 (STRQ 80 kbps), 1 (STDQ 128 kbps), 2 (HGHQ 192 kbps) or 3 (SPBQ 192 kbps)
* Returns:
* 0 - couldn't initilize ne decoding process
* nonzero - handler of the newly initialized decoding process
*/
long __cdecl initDecoding ( void );

/**
* Decodes audx/mp3 frame.
* Input:
* hdec - handler of a decoding process,
* audx_frame - input buffer containing data to be decoded (must be nonNULL),
* audx_frame_size - size of the input buffer in bytes (must be > 0)
*
* Output:
* dec_pcm_block - output buffer filled with 16bits PCM samples (must be nonNULL)
* dec_pcm_block_size - size of the output buffer in bytes (must be nonNULL)
* is_audx - indicates whether input data contained an audx frame or regular mp3 (must be nonNULL)
*
* Returns:
* -1 - handler of an uninitialized decoding process, invalid input data or error in processing,
* 0 - input data and processing correct, input data was not consumed (should be supplied once again)
* 1 - input data and processing correct, input data was consumed (new input portion can be supplied)
*/
int __cdecl decodeAudXframe ( long hdec, unsigned char* audx_frame, long audx_frame_size, short* dec_pcm_block, long* dec_pcm_block_size, int* is_audx );

/**
* Resets an initialized decoding process
* (puts the process in a uninitialized state, hdec is no longer a handler of the process),
* or does nothing if a decoding process is uninitialized
* Input:
* hdec - handler to a decoding process
*/
void __cdecl resetDecoder ( long hdec );
//============================================================================

#if defined(__cplusplus)
}
#endif

#endif

Myrsloik
22nd May 2006, 22:05
With your ifdefs the calling convention used in delphi will be stdcall (WIN32 is always defined in delphi) while the functions in the header are all declared as cdecl (unless there's some really evil preprocessor usage going on).

That you use the far modifier for one function also looks odd and most likely does nothing here.

After looking at it some more you're saying that your output buffer is 102400 bytes but in reality it's only 2 bytes in decodeAudXframe.

TFM_TheMask
23rd May 2006, 05:31
So what must I change?

Myrsloik
24th May 2006, 00:36
After actually trying to get it to work and not just looking for apparent conversion errors I noticed that the sdk never mentions how big the output buffer has to be. All samples which use it have the allocation of it removed because it's not interesting or at least that's how it seems. Either I'm completely wrong or the only way you'll get this stuff to work reliably is to ask the original developer.

TFM_TheMask
24th May 2006, 05:55
I tried that but he doesn't know anything about Delphi. He only knows C++.

TFM_TheMask
24th May 2006, 18:28
I found this in the ffdshow audio decoder filter, maybe this will help sorting out the size of the buffer that I need:

/*
* Copyright (c) 2006 Milan Cutka
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "stdafx.h"
#include "TaudioCodecAudX.h"
#include "mp3header.h"
#include "Tconfig.h"
#include "IffdshowBase.h"
#include "IffdshowDec.h"
#include "IffdshowDecAudio.h"
#include "dsutil.h"
#include "Tdll.h"

const char_t* TaudioCodecAudX::dllname=_l("audxlib.dll");

TaudioCodecAudX::TaudioCodecAudX(IffdshowBase *deci,IdecAudioSink *Isink):
Tcodec(deci),
TaudioCodec(deci,Isink)
{
layer=0;oldmode=-1;ctx=-1;
dll=NULL;
}
bool TaudioCodecAudX::init(const CMediaType &mt)
{
dll=new Tdll(dllname,config);
dll->loadFunction(initDecoding,"initDecoding");
dll->loadFunction(decodeAudXframe,"decodeAudXframe");
dll->loadFunction(resetDecoder,"resetDecoder");
if (!dll->ok)
return false;

hdrlayer=0;
Textradata extradata(mt);
if (extradata.size==sizeof(MPEG1WAVEFORMAT)-sizeof(WAVEFORMATEX))
{
const MPEG1WAVEFORMAT *m1wf=(const MPEG1WAVEFORMAT*)(extradata.data-sizeof(WAVEFORMATEX));
switch (m1wf->fwHeadLayer)
{
case ACM_MPEG_LAYER1:hdrlayer=layer=mp3header::MAD_LAYER_I;break;
case ACM_MPEG_LAYER2:hdrlayer=layer=mp3header::MAD_LAYER_II;break;
case ACM_MPEG_LAYER3:hdrlayer=layer=mp3header::MAD_LAYER_III;break;
}
}
ctx=initDecoding();
fmt.sf=TsampleFormat::SF_PCM16;
fmt.freq=mp3header::findNearestFreq(fmt.freq);
return true;
}
TaudioCodecAudX::~TaudioCodecAudX()
{
if (ctx) resetDecoder(ctx);
if (dll) delete dll;
}
void TaudioCodecAudX::getInputDescr1(char_t *buf,size_t buflen) const
{
if (layer)
tsnprintf(buf,buflen,_l("mp%i"),layer);
else
tsnprintf(buf,buflen,_l("mp1/2/3"));
buf[buflen-1]='\0';
}
HRESULT TaudioCodecAudX::decode(TbyteBuffer &src0)
{
TbyteBuffer::iterator src=src0.begin();
int srcLength=(int)src0.size();
for (;srcLength>4;)
{
mp3header hdr(&*src,srcLength);
if (!hdr.ok || (hdrlayer!=mp3header::MAD_LAYER_I && hdr.layer==mp3header::MAD_LAYER_I) || (layer!=0 && hdr.layer!=layer) || hdr.samplerate!=fmt.freq/* || (oldmode!=-1 && hdr.mode!=oldmode)*/)
{
src++;
srcLength--;
continue;
}
bpssum+=(lastbps=hdr.bitrate/1000);numframes++;
layer=hdr.layer;oldmode=hdr.mode;
int framelen=hdr.calc_frame_len();
if (srcLength<framelen)
break;
int used_bytes=0;
long dstsize;
short *dst=(short*)getDst(dstsize=102400);
int isAudX=0;
int decoded=decodeAudXframe(ctx,&*src,framelen,dst,&dstsize,&isAudX);
if (isAudX)
fmt.setChannels(6);
if (decoded<0)
break;
else if (decoded>0)
{
used_bytes=framelen;
if (dstsize)
{
HRESULT hr=sinkA->deliverDecodedSample(dst,dstsize/fmt.blockAlign(),fmt,1);
if (hr!=S_OK)
return hr;
}
}
src+=used_bytes;srcLength-=used_bytes;
}
if (src!=src0.begin())
src0.erase(src0.begin(),src);
return S_OK;
}
bool TaudioCodecAudX::onSeek(REFERENCE_TIME segmentStart)
{
if (ctx)
{
return true;
}
else
return false;
}

bool TaudioCodecAudX::getVersion(const Tconfig *config,ffstring &vers,ffstring &license)
{
if (Tdll::check(dllname,config))
{
vers=_l("present");
return true;
}
else
{
vers=_l("not found");
return false;
}
}