I have a small tip question about quality of conversions, my folowing code
it's in Delphi 7. My app record in PCM format and real time, I need to
convert buffers in MS ADPCM or GSM 6.10 ( I need true PCM samples in
application so I can't record directlly in GSM ) in order to save compressed
audio on disk (for logging).
But for compressed audio I have spikes on audio, like audio blocks not
aligned perfectlly (small gaps) - take a look on a picture of converted tone
here :
http://www.hcv.ro/adpcm.gif
I initialise ACM like that :
//------------------------------------------------------------------------------------
// ACM Stream Open
x := acmStreamOpen(hndl_acm,nil, formatin.format, formatout.format, nil,
0, 0, 0);
log.Lines.Add('ACM Open Code : '+inttostr(x));
// ACM Stream Size
x := acmStreamSize(hndl_acm, WAVE_BUFFER_SIZE, ACM_OUT_BUFFER_SIZE,
ACM_STREAMSIZEF_SOURCE);
log.Lines.Add('ACM Stream Size Code : '+inttostr(x)+', Suggested Size :
'+inttostr(ACM_OUT_BUFFER_SIZE));
// Get required memory...
GetMem(ACM_Buff_In,WAVE_BUFFER_SIZE);
ZeroMemory(ACM_Buff_In,WAVE_BUFFER_SIZE);
GetMem(ACM_Buff_Out,ACM_OUT_BUFFER_SIZE);
ZeroMemory(ACM_Buff_Out,ACM_OUT_BUFFER_SIZE);
// Prepare header
with AcmHeader do begin
cbStruct := SizeOf(TACMStreamHeader);
fdwStatus := 0;
dwUser := 0;
pbSrc := ACM_Buff_In;
cbSrcLength := WAVE_BUFFER_SIZE;
cbSrcLengthUsed := 0;
dwSrcUser := 0;
pbDst := ACM_Buff_Out;
cbDstLength := ACM_OUT_BUFFER_SIZE;
cbDstLengthUsed := 0;
dwDstUser := 0;
end;
x := acmStreamPrepareHeader(hndl_acm, AcmHeader, 0);
log.Lines.Add('ACM Prepare Headers Code : '+inttostr(x));
//------------------------------------------------------------------------------
Eveything is OK (I omit for clarity other stuff there), return codes are 0.
Now, I instruct my audio input driver to get PCM samples and get them in
calback mechanism (waveinopen... etc)
I use several switched buffers (circular buffer) to get audio blocks in PCM,
each buffer has let's say 2048 bytes.
For test, I collect back real time all those buffers, put back in RIFF
format and write to file. For PCM audio sounds great, no spikes, no gaps,
perfect.
For ADPCM or GSM my audio sounds like I have some gaps, the audio blocks are
not aligned right. The processing time is right ( fenomenon persist even with
32768 bytes buffer ) and I suspect ACM_STREAMCONVERTF_BLOCKALIGN flags or
some.
My conversion working code :
//---------------------------------------------------------------------------------------------
// make a copy from circular buffer to ACM buffer
move(hdata^,ACM_Buff_In^,hsize);
// convert
acmStreamConvert(hndl_acm,ACMHeader,ACM_STREAMCONVERTF_BLOCKALIGN)
// make clean
acmStreamReset(hndl_acm,0);
// get size of just converted block
NewSize := ACMHeader.cbDstLengthUsed;
//----------------------------------------------------------------------------------
So I put in some memory stream all converted blocks as they arrive but
sounds like missing small parts of audio (check picture), the same problem
for ADPCM codec and GSM codec but windows sound recorder can convert
perfectlly.
Thanks very much in advance,
Alex,
http://www.hcv.ro/adpcm_triangle.gif
and looks like previouse buffer is done but next one give me a small piece
of audio from previouse in front of new audio data. Strange ? How to correct
this ?
Thanks again,
You have made the output buffer the best estimate for the input buffer
by using acmStreamSize(). but in order to be fully aligned your input
buffer must be an integer multiple of your output block alignment.
Otherwise you must find out what input bytes have not been used and
transfer those to the beginning of the input buffer before filling the
input buffer. And if your chosen output format block align is not
constant, that you _have_ to do. But that's not so in PCM > GSM
The easiest way to fully align input & output buffers is to call ...
y := acmStreamSize(hndl_acm, ACM_OUT_BUFFER_SIZE, WAVE_BUFFER_SIZE,
ACM_STREAMSIZEF_DESTINATION);
... to get the input equivalent of the output buffer size. Otherwise
work it out for yourself if you know the (constant) output block size.
With your 2048 byte PCM buffer at (for example) 16 bits/ sample mono,
that is 1024 PCM samples. GSM is 320 samples/block so that is 3.2
blocks of GSM for 1024 PCM blocks. The 0.2 left over is where your
output spike is coming from, by 7% of PCM being chopped out.
Assuming 3 GSM blocks your input buffer should be
320 (GSM samples/block) * 3 * (16bits/8 PCM bytes/block) == 1920 bytes
for the input buffer.
But acmStreamSize() does these calculations for you if you use it both
ways..
If you cannot use a consistent buffer length for the output buffer (or
are doing some fancy comnversion - suppose you are converting from
8000 samples/sec GSM to 11025 samples/ sec GSM and so must do 8000GSM
> 8000PCM > 11025PCM > 11025GSM) then you _have_ to get into buffer-
shuffling the left-overs, and that's tedious <g>.
Alan Lloyd