[Delphi] converting the dialogic Vox file to a wave file

Source: Internet
Author: User

I was so happy to read the materials. The conversion class supports Vox conversion in 8/16-bit, 6000/8000 sampling rate, ADPCM, mulaw, and alaw formats.

It is strange that the sound formats recorded by the Huawei ICD platform are slightly different. The speech of a platform can be converted using our program, however, after the recordings on another platform are converted, the waveforms above the 0 axis are lost, but the sound is basically the same. It is estimated that the two platforms use different recording cards. However, cooledit can normally display two speech waveforms, without knowing the tiny differences in the algorithms. We used cooledit to save the sound that we could not normally display the waveform as the dialogic Vox format for comparison, and found that the two sounds were indeed different. We then convert the sound stored in cooledit, and the result shows that the waveform is normal.

The final result shows that the waveform has been adjusted because it is necessary to initialize ADPCM once after 48 binary samples of 1000 or 0000 have been accumulated, the noise after conversion is slightly larger than the source file, but it is acceptable.

The original initialization text is as follows. I always feel that my translation is not accurate.

"Initial Conditions
When the ADPCM Algorithm is reset, The step size SS (n) is set to the minimum value (16) and
Estimated waveform value x is set to zero (half scale). Playback of 48 samples (24 bytes) of plus
And minus zero (10002 and 00002) will reset the algorithm. Twenty-four bytes of 08 hex or 80
Hex will satisfy this requirement. It is necessary to alternate positive and negative zero values
Because the encoding formula always adds 1/8 of the quantization size. If all values were positive
Or negative, a DC component wocould be added that wocould create a false reference level ."

Call example

ProcedureTform1.btnbrowseclick (Sender: tobject );
VaR
Vox: tvox;
Begin
If(Opendialog1.execute)Then
Begin

// The default value is the 6 K sampling rate, which is 8 bits and the ADPCM format.
Vox: = tvox. Create (opendialog1.filename );
If (VOX. Convert = 0) then
Showmessage ('convert success! The OUTFILE be saved as '+ vox. outfilename );
Vox. Free;
End;
End;

Class of convert Vox to wave

Unit uvoxtowave;

Interface
Uses
Sysutils;
Type
Tvoxformat = (vf_adpcm = 1, vf_mulaw = 2, vf_alaw = 3 );
Tvoxrate = (vr_6k = 6000, vr_8k = 8000 );
Tvoxbitspersample = (vb_8 = 1, vb_16 = 2 );
Twavehead = packed record
Chead: array [0 .. 3] of char; {'riff '}
Nlength: longint;
Cwavetag: array [0 .. 7] of char; {'wavefmt '}
Nheaderlength: longint; {16}
Wformattag: word; {format type 01 00}
Nchannels: word; {number of channels (I. e. Mono, stereo, etc.) 01}
Nsample spersec: longint; {sample rate 8000}
Navgbytespersec: longint; {for buffer estimation 8000}
Nblockalign: word; {1}
Wbitspersample: word; {8}
End;
Tdatahead = packed record
Cdatatag: array [0 .. 3] of char; {'data '}
Ndatalen: longint;
End;
Pwavehead = ^ twavehead;
Tvox = Class
Private
Finfilename, foutfilename: string;
Fvoxformat: tvoxformat;
Fvoxrate: tvoxrate;
Fvoxbitspersample: tvoxbitspersample;
Rate, bit_rate: integer;
Sample: byte; // sample read from input file
Buffer: array [0 .. 9999] of byte; // a block of input data

SS: word; // current step size for ADPCM
Ssindex: word; // current index into step size table
SN: smallint; // current 12-bit linear sample value
Out_val: byte; //. wav output value
Out_int: smallint; // Linear Output Value
Function decode (sample: byte; SN: smallint; var SS: word; var ssindex: Word): smallint;
Procedure convertadpcm (infile, OUTFILE: integer );
Procedure convertmulaw (infile, OUTFILE: integer );
Procedure convertalaw (infile, OUTFILE: integer );
Published
Property infilename: String read finfilename;
Property outfilename: String read foutfilename;
Public
Constructor create (infilename: string; outfilename: String = ''; voxformat: tvoxformat = vf_adpcm; voxrate: tvoxrate = vr_6k; voxbitspersample: tvoxbitspersample = vb_8 );
Function convert: integer;
End;
Const
Seek_set = 0;
Seek_end = 2;
Resetvalue = 48;
Formats: array [0 .. 2] of string = ('adpcm ', 'mu-Law', 'a-Law ');
Mulaw: array [0 .. 255] of smallint = (
-32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
-23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
-15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
-11900,-11388,-10876,-10364,-9852,-9340,-8828,-8316,
-7932,-7676,-7420,-7164,-6908,-6652,-6396,-6140,
-5884,-5628,-5372,-5116,-4860,-4604,-4348,-4092,
-3900,-3772,-3644,-3516,-3388,-3260,-3132,-3004,
-2876,-2748,-2620,-2492,-2364,-2236,-2108,-1980,
-1884,-1820,-1756,-1692,-1628,-1564,-1500,-1436,
-1372,-1308,-1244,-1180,-1116,-1052,-988,-924,
-876,-844,-812,-780,-748,-716,-684,-652,
-620,-588,-556,-524,-492,-460,-428,-396,
-372,-356,-340,-324,-308,-292,-276,-260,
-244,-228,-212,-196,-180,-164,-148,-132,
-120,-112,-104,-96,-88,-80,-72,-64,
-56,-48,-40,-32,-24,-16,-8, 0,
32124,311 00, 30076,290 52, 28028,270 04, 25980,249 56,
23932,229 08, 21884,208 60, 19836,188 12, 17788,167 64,
15996,154 84, 14972,144 60, 13948,134 36, 12924,124 12,
11900,113 88, 10876,103 64, 9852,934 0, 8828,831 6,
7932,767 6, 7420,716 4, 6908,665 2, 6396,614 0,
5884,562 8, 5372,511 6, 4860,460 4, 4348,409 2,
3900,377 2, 3644,351 6, 3388,326 0, 3132,300 4,
2876,274 8, 2620,249 2, 2364,223 6, 2108,198 0,
1884,182 0, 1756,169 2, 1628,156 4, 1500,143 6,
1372,130 8, 1244,118 0, 1116,105 2, 988,924,
876,844,812,780,748,716,684,652,
620,588,556,524,492,460,428,396,
372,356,340,324,308,292,276,260,
244,228,212,196,180,164,148,132,
120,112,104, 96, 88, 80, 72, 64,
56, 48, 40, 32, 24, 16, 8, 0
);
Alaw: array [0 .. 255] of smallint = (
-5504,-5248,-6016,-5760,-4480,-4224,-4992,-4736,
-7552,-7296,-8064,-7808,-6528,-6272,-7040,-6784,
-2752,-2624,-3008,-2880,-2240,-2112,-2496,-2368,
-3776,-3648,-4032,-3904,-3264,-3136,-3520,-3392,
-22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
-30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
-11008,-10496,-12032,-11520,-8960,-8448,-9984,-9472,
-15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
-344,-328,-376,-360,-280,-264,-312,-296,
-472,-456,-504,-488,-408,-392,-440,-424,
-88,-72,-120,-104,-24,-8,-56,-40,
-216,-200,-248,-232,-152,-136,-184,-168,
-1376,-1312,-1504,-1440,-1120,-1056,-1248,-1184,
-1888,-1824,-2016,-1952,-1632,-1568,-1760,-1696,
-688,-656,-752,-720,-560,-528,-624,-592,
-944,-912,-1008,-976,-816,-784,-880,-848,
5504,524 8, 6016,576 0, 4480,422 4, 4992,473 6,
7552,729 6, 8064,780 8, 6528,627 2, 7040,678 4,
2752,262 4, 3008,288 0, 2240,211 2, 2496,236 8,
3776,364 8, 4032,390 4, 3264,313 6, 3520,339 2,
22016,209 92, 24064,230 40, 17920,168 96, 19968,189 44,
30208,291 84, 32256,312 32, 26112,250 88, 28160,271 36,
11008,104 96, 12032,115 20, 8960,844 8, 9984,947 2,
15104,145 92, 16128,156 16, 13056,125 44, 14080,135 68,
344,328,376,360,280,264,312,296,
472,456,504,488,408,392,440,424,
88, 72,120,104, 24, 8, 56, 40,
216,200,248,232,152,136,184,168,
1376,131 2, 1504,144 0, 1120,105 6, 1248,118 4,
1888,182 4, 2016,195 2, 1632,156 8, 1760,169 6,
688,656,752,720,560,528,624,592,
944,912,100 8, 976,816,784,880,848
);

// Stepsize adjustments per dialogic application note 1366
Ssadjust: array [0 .. 7] of smallint = (-1,-1,-1,-1, 2, 4, 6, 8 );

// Calculated stepsizes per dialogic application note 1366
Sstable: array [0 .. 49] of smallint = (0, 16, 17, 19, 21, 23, 25, 28, 31,
34, 37, 41, 45, 50, 55, 60, 66, 73,
80, 88, 97,107,118,130,143,157,173,
190,209,230,253,279,307,337,371,408,
449,494,544,598,658,724,796,876,963,
1060,116 6, 1282,141 1, 1552 );

Implementation

Constructor tvox. Create (infilename: string; outfilename: String = ''; voxformat: tvoxformat = vf_adpcm; voxrate: tvoxrate = vr_6k; voxbitspersample: bytes = vb_8 );
Begin
Finfilename: = trim (infilename );
Foutfilename: = trim (outfilename );
Fvoxformat: = voxformat;
Fvoxrate: = voxrate;
Fvoxbitspersample: = voxbitspersample;

If (foutfilename = '') then
Foutfilename: = changefileext (finfilename, '.wav ');
Rate: = INTEGER (fvoxrate );
Bit_rate: = INTEGER (fvoxbitspersample );
End;

Function tvox. Decode (sample: byte; SN: smallint; var SS: word; var ssindex: Word): smallint;
VaR
Mn: smallint;
Begin
// The conversion formula is as follows:
// D (n) = (SS (n) * B2) + (SS (N)/2 * B1) + (SS (N)/4 * Bo) + (SS (N)/8)
// If (B3 = 1)
// Then D (n) = D (n) * (-1)
// X (n) = x (n-1) + d (N)

Mn: = 0; // calculate the linear Adjustment
If (sample and $4) <> 0 then Mn: = SS;
If (sample and $2) <> 0 then Mn: = Mn + (ss shr 1); // Div 2
If (sample and $1) <> 0 then Mn: = Mn + (ss shr 2); // Div 4
Mn: = Mn + (ss shr 3); // Div 8
// Obtain the signed bit of the sample, that is, the highest bit.
If (sample and $8) <> 0 then // if the maximum bit is 1, the symbol bit is negative.
SN: = Sn-Mn //... subtract the adjustment
Else // The symbol bit is positive.
SN: = Sn + Mn; //... add the adjustment

If (Sn> 2047) Then // adjust if sample too large...
SN: = 2047;
If (Sn <-2048) Then //... or too small
SN: =-2048;

// Use as index into step size adjustment, adjust Step Size Index
Ssindex: = ssindex + ssadjust [sample and $7];

If (ssindex <1) Then // keep ssindex within bounds...
Ssindex: = 1;
If (ssindex> 49) then
Ssindex: = 49;

SS: = sstable [ssindex]; // get new step size from table

Result: = Sn;
End;
// ----- Dialogc Vox voice format description, in 6 K/8bits example -----------------------------------------------------
// One byte contains two samples, 7-4 digits: sample n, 3-0 digits: sample n + 1
// Each sample is based on ADPCM (adaptive Differential Pulse Code Modulation)
// Encode the sample consisting of every four digits (3rd,). Among them, the bits are 0-positive 1-negative, and the 2-0 bits are different from the previous one.
// IF 1000 or 0000 of the 48 binary values are displayed, You need to reset the initial value of the ADPCM Algorithm.
// Configure //---------------------------------------------------------------------------------------------------

Procedure tvox. convertadpcm (infile, OUTFILE: integer );
VaR
Index: integer; // index for Misc. Arrays
Bytes: integer; // number of bytes read into a buffer
Outindex: integer; // index for output arrays
Outbytebuffer: array [0 .. 19999] of byte; // output buffer
Outintbuffer: array [0 .. 19999] of smallint; // output buffer
I: integer; // reset count
Highbyte, lowbyte: byte;
Begin
SN: = 0; // initialize the ADPCM Variables
SS: = 16; // initialize the step
Ssindex: = 1;
I: = 0;
// Read a byte of ADPCM Data
Bytes: = fileread (infile, buffer, 10000 );
While (Bytes> 0) Do
Begin
Outindex: = 0;
For index: = 0 to (bytes-1) do
Begin
Sample: = buffer [Index];
Highbyte: = sample SHR 4;
Lowbyte: = sample and $ F;
If (highbyte = 0) or (highbyte = 8) then
INC (I );
// First extract the 4-bit high in one byte...
SN: = decode (Word (sample SHR 4), Sn, SS, ssindex );
If (bit_rate = 1) Then // If 8 bits per sample...
Begin
Out_int: = Sn SHR 4; // rescale output from-128 thru 127
If (out_int> 127) Then // clip if above or below WAV Bounds
Out_int: = 127;
If (out_int <-128) then
Out_int:-128;
Out_val: = byte (out_int-128); // convert to. WAV format
Outbytebuffer [outindex]: = out_val; // write the output byte
INC (outindex );
End
Else
Begin
Out_int: = Sn SHL 4; // rescale to 16 bits
Outintbuffer [outindex]: = out_int; // write the output int
INC (outindex );
End;
If I = resetvalue then // reset ADPCM Variables
Begin
SN: = 0; // initialize the ADPCM Variables
SS: = 16; // initialize the step
I: = 0;
End;
If (lowbyte = 0) or (lowbyte = 8) then
INC (I );
// Now decode the low nibble...
SN: = decode (Word (sample and $ F), Sn, SS, ssindex );
If (bit_rate = 1) Then // If 8 bits per sample...
Begin
Out_int: = Sn SHR 4; // rescale output from-128 thru 127

If (out_int> 127) Then // clip if above or below WAV Bounds
Out_int: = 127;
If (out_int <-128) then
Out_int:-128;

Out_val: = out_int-128; // convert to. WAV format
Outbytebuffer [outindex]: = out_val; // write the output byte
INC (outindex );
End
Else
Begin
Out_int: = Sn SHL 4; // rescale to 16 bits
Outintbuffer [outindex]: = out_int; // write the output int
INC (outindex );
End;
If I = resetvalue then // reset ADPCM Variables
Begin
SN: = 0; // initialize the ADPCM Variables
SS: = 16; // initialize the step
I: = 0;
End;
End;
If (bit_rate = 1) then
Filewrite (OUTFILE, outbytebuffer, bytes * 2)
Else
Filewrite (OUTFILE, outintbuffer, bytes * 4 );
Bytes: = fileread (infile, buffer, 10000 );
End;
End;

Procedure tvox. convertmulaw (infile, OUTFILE: integer );
VaR
Index: integer; // index for Misc. Arrays
Bytes: integer; // number of bytes read into a buffer
Outindex: integer; // index for output arrays
Outbytebuffer: array [0 .. 19999] of byte; // output buffer
Outintbuffer: array [0 .. 19999] of smallint; // output buffer
Begin
// Read a block of Mu-law data
Bytes: = fileread (infile, buffer, 10000 );
While (Bytes> 0) Do
Begin
Outindex: = 0;
For index: = 0 to bytes-1 do
Begin
Out_int: = mulaw [buffer [Index]; // convert Mu-law to linear

If (bit_rate = 1) Then // If 8 bits per sample...
Begin
Out_int: = out_int SHR 8; // rescale for 8 bit values
Out_val: = out_int + 128; // convert to. WAV format
Outbytebuffer [outindex]: = out_val; // write the output byte
INC (outindex );
End
Else
Begin
Outintbuffer [outindex]: = out_int; // write the output int
INC (outindex );
End;
End;
If (bit_rate = 1) then
Filewrite (OUTFILE, outbytebuffer, bytes * 2)
Else
Filewrite (OUTFILE, outintbuffer, bytes * 4 );
Bytes: = fileread (infile, buffer, 10000 );
End;
End;

Procedure tvox. convertalaw (infile, OUTFILE: integer );
VaR
Index: integer; // index for Misc. Arrays
Bytes: integer; // number of bytes read into a buffer
Outindex: integer; // index for output arrays
Outbytebuffer: array [0 .. 19999] of byte; // output buffer
Outintbuffer: array [0 .. 19999] of smallint; // output buffer
Begin
// Read a block of A-law data
Bytes: = fileread (infile, buffer, 10000 );
While (Bytes> 0) Do
Begin
Outindex: = 0;
For index: = 0 to bytes-1 do
Begin
Out_int: = alaw [buffer [Index]; // convert a-law to linear

If (bit_rate = 1) Then // If 8 bits per sample...
Begin
Out_int: = out_int SHR 8; // rescale for WAV file
Out_val: = out_int + 128; // convert to. WAV format
Outbytebuffer [outindex]: = out_val; // write the output byte
INC (outindex );
End
Else
Begin
Outintbuffer [outindex]: = out_int; // write the output int
INC (outindex );
End;
End;
If (bit_rate = 1) then
Filewrite (OUTFILE, outbytebuffer, bytes * 2)
Else
Filewrite (OUTFILE, outintbuffer, bytes * 4 );
Bytes: = fileread (infile, buffer, 10000 );
End;
End;

Function tvox. Convert: integer;
VaR
Infile, OUTFILE, filesize: integer;
Wavehead: twavehead;
Datahead: tdatahead;
Begin
Infile: = fileopen (finfilename, $0040 );
If (infile <= 0) Then // if can't create input file...
Begin
Result: =-2;
Exit;
End;
OUTFILE: = filecreate (foutfilename );
If (OUTFILE <= 0) Then // if can't create output file ....
Begin
Fileclose (infile); // close input file
Result: =-3;
Exit;
End;
Filesize: = FileSeek (infile, 0, seek_end); // get size of input file
If (fvoxformat = vf_adpcm) Then // if using ADPCM input format...
Filesize: = filesize * 2; // change from bytes to samples
FileSeek (infile, 0, seek_set); // seek back to beginning of input
// --------- Create wave file head ---------------------------------------------
Strcopy (wavehead. chead, 'riff'); //. wav begins with "riff"
Wavehead. nlength: = (filesize * bit_rate) + sizeof (twavehead); // size of. Wav file (Data + header)
Strcopy (wavehead. cwavetag, 'wavefmt ');
Wavehead. nheaderlength: = 16; // size of. Wav file header
Wavehead. wformattag: = 1; // format tag (01 = Windows PCM)
Wavehead. nchannels: = 1; // channels (1 = mono, 2 = stereo)
Wavehead. nsamplespersec: = rate; // samples per second
Wavehead. navgbytespersec: = Rate * bit_rate; // bytes per second during play
Wavehead. nblockalign: = bit_rate; // bytes per sample
Wavehead. wbitspersample: = 8 * bit_rate; // bits per sample
Strcopy (datahead. cdatatag, 'data'); // specify "data" follows
Datahead. ndatalen: = filesize * bit_rate; // write size of. wav data portion
Filewrite (OUTFILE, wavehead, sizeof (twavehead ));
Filewrite (OUTFILE, datahead, sizeof (tdatahead ));
Case fvoxformat
Vf_adpcm: convertadpcm (infile, OUTFILE );
Vf_mulaw: convertmulaw (infile, OUTFILE );
Vf_alaw: convertalaw (infile, OUTFILE );
End;

Fileclose (infile );
Fileclose (OUTFILE );
Result: = 0;
End;

End.

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.