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.
|