OK, then I have pointed out the right thing. We should have :
Code: Select all
if (feof(in)) break;
do {
i=fgetc(in); emit_byte(i); /* name */
} while ((i!=0) && (!feof(in)) ;
For documentation, this is my source code in Delphi (Pascal), it is pretty much a translation of Fabrice's C++ code kind into Pascal :
Code: Select all
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, Mask, JvExMask, JvToolEdit, ComCtrls;
type TheadArray=ARRAY[0..43]OF BYTE;
CONST HEADER:TheadArray=(
$52,$49,$46,$46, $00,$00,$00,$00, $57,$41,$56,$45, $66,$6D,$74,$20,
$10,$00,$00,$00, $01,$00,$01,$00, $44,$AC,$00,$00, $88,$58,$01,$00,
$01,$00,$08,$00, $64,$61,$74,$61, $00,$00,$00,$00);
type
THEAD=packed RECORD
case b:boolean of
True:(AsBytes:TheadArray);
false:(Tag1 : ARRAY[1..4]OF CHAR; { 00..03 Constante "RIFF" }
Size0 : LongWord; { 04..07 Filesize-8 }
Tag2 : ARRAY[1..8]OF CHAR; { 08..15 Constante "WAVEfmt..." }
Size1 : Longword; {16..19}
AudioFormat: WORD; {20..21}
NumChannels: WORD; { 22..23 Mono or Stereo }
Freq : LongWord; { 24..27 Frequence (Hz) }
BytePerSec : LongWord; { 28..31 Freq*NbrByte }
NbrByte : WORD; { 32..33 (Format div 8)*Mode }
Format : WORD; { 34..35 8 or 16 bits }
Tag3 : ARRAY[1..4]OF CHAR; { 36..39 Constante "data" }
Size2 : LongWord); { 40..43 Filesize-116 }
end;
TForm1 = class(TForm)
Button1: TButton;
RadioGroup1: TRadioGroup;
JvFilenameEdit1: TJvFilenameEdit;
JvFilenameEdit2: TJvFilenameEdit;
Label1: TLabel;
Label2: TLabel;
ProgressBar1: TProgressBar;
procedure Button1Click(Sender: TObject);
procedure JvFilenameEdit1Change(Sender: TObject);
private
{ Déclarations privées }
fsout,fsin:TFileStream;
file_size,speed:integer;
sample_riff:THEAD;
ccurrent_level:byte;
procedure emit_level(size:integer);
procedure emit_bit(bit:boolean);
procedure emit_byte(val:byte);
procedure emit_gap;
function init:boolean;
public
{ Déclarations publiques }
end;
var
Form1: TForm1;
implementation
uses MMSystem;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var i,size:integer;
b:byte;
hheader:array[0..8] of byte;
begin
speed:=4800;
sample_riff.AsBytes:=header;
sample_riff.Size1:=16;
ccurrent_level:=256-$C0;
if not init then exit;
Cursor:=crHourGlass;
fsin:=TFileStream.Create(JvFilenameEdit1.FileName,fmOpenRead);
ProgressBar1.Max:=fsin.Size;
ProgressBar1.Position:=0;
if FileExists(JvFilenameEdit2.FileName)
then DeleteFile(JvFilenameEdit2.FileName);
fsout:=TFileStream.Create(JvFilenameEdit2.FileName,fmCreate );
fsout.Write(sample_riff.asbytes,44);
fsin.Position:=0;
while (fsin.Position<fsin.size) do
begin
b:=$16;
while (b=$16) do fsin.Read(b,1); // read synchro (0x24 included)
if (fsin.Position>=fsin.size) then break;
ProgressBar1.Position:=fsin.Position; Application.ProcessMessages;
for i:=0 to 255 do emit_byte($16);
emit_byte($24);
//
for i:=0 to 8 do
begin
fsin.Read(b,1);
hheader[i]:=b;
emit_byte(b); //header
end;
ProgressBar1.Position:=fsin.Position; Application.ProcessMessages;
repeat
i:=fsin.Read(b,1);
emit_byte(b); // name
ProgressBar1.Position:=fsin.Position; Application.ProcessMessages;
until ((b=0) or (i=0));
emit_gap;
size:=(hheader[4]*256+hheader[5])-(hheader[6]*256+hheader[7])+1;
for i:=0 to size-1 do begin
fsin.Read(b,1);
emit_byte(b);
ProgressBar1.Position:=fsin.Position; Application.ProcessMessages;
end;
end;
sample_riff.Size2:=fsout.Size;
sample_riff.Size0:=36+sample_riff.Size2;
fsout.Seek(0,soFromBeginning);
fsout.Write(sample_riff.asbytes,44);
fsin.Free;
fsout.Free;
Cursor:=crDefault;
showmessage('Conversion terminée');
end;
procedure TForm1.emit_bit(bit:boolean);
begin
case speed of
4800:begin
emit_level(1);
if bit then emit_level(1)
else emit_level(2);
end;
8000:begin
if bit then begin
emit_level(1);
emit_level(2);
end
else begin
emit_level(2);
emit_level(3);
end;
end;
11025:begin
if bit then begin
emit_level(2);
emit_level(2);
end
else begin
emit_level(3);
emit_level(4);
end;
end;
end;
end;
procedure TForm1.emit_byte(val: byte);
var i:byte;
parity:byte;
begin
parity:=1;
emit_bit(false);
for i:=0 to 7 do
begin
parity:=parity+(val and 1);
emit_bit((val and 1)=1);
val:=val shr 1;
end;
emit_bit((parity and 1)=1);
emit_bit(true);
emit_bit(true);
emit_bit(true);
emit_bit(true); // 4 bits stop au lieu de 3.5 pour être sûr que les routines aient du temps
end;
procedure TForm1.emit_gap;
var i:integer;
begin
//un paquet de bits stop pour laisser le temps d'afficher la ligne de statut
for i:=0 to 99 do emit_bit(true);
end;
procedure TForm1.emit_level(size: integer);
var i:integer;
begin
ccurrent_level:=256-ccurrent_level;
for i:=0 to size-1 do fsout.Write(ccurrent_level,1);
inc(file_size,size);
end;
function TForm1.init:boolean;
begin
case RadioGroup1.ItemIndex of
0:speed:=4800;
1:speed:=8000;
2:speed:=11025;
end;
sample_riff.freq:=speed;
sample_riff.NumChannels:=1;
sample_riff.Format:=8;//8bits
sample_riff.NbrByte:=sample_riff.NumChannels*(sample_riff.Format div 8);
sample_riff.BytePerSec:=(speed*sample_riff.NbrByte);
if not FileExists(JvFilenameEdit1.FileName)
then begin
Result:=false;
exit;
end;
if not DirectoryExists(ExtractFilePath(JvFilenameEdit2.FileName))
then begin
Result:=false;
exit;
end;
Result:=true;
end;
procedure TForm1.JvFilenameEdit1Change(Sender: TObject);
begin
JvFilenameEdit2.FileName:=ChangeFileExt(JvFilenameEdit1.FileName,'.wav')
end;
end.
Edit : source code is updated to V2.0, see below