Browse Source

* created more helper functions for vorbis, mad and a52 decoders
* updated madopenal sample to use this helpers

git-svn-id: trunk@4690 -

ivost 19 years ago
parent
commit
afb39dc4b3

+ 103 - 75
packages/extra/a52/a52.pas

@@ -405,46 +405,45 @@ procedure a52_free(state: pa52_state_t); cdecl; external {$IFDEF DYNLINK}a52lib{
 }
 
 type
-  read_func  = function(ptr: pointer; size, nmemb: culong; datasource: pointer): culong; cdecl;
-  seek_func  = function(datasource: pointer; offset: cint64; whence: cint): cint; cdecl;
-  close_func = function(datasource: pointer): cint; cdecl;
-  tell_func  = function(datasource: pointer): clong; cdecl;
+  a52_read_func  = function(ptr: pointer; size, nmemb: culong; datasource: pointer): culong; cdecl;
+  a52_seek_func  = function(datasource: pointer; offset: cint64; whence: cint): cint; cdecl;
+  a52_close_func = function(datasource: pointer): cint; cdecl;
+  a52_tell_func  = function(datasource: pointer): clong; cdecl;
 
   pa52_decoder = ^a52_decoder;
   a52_decoder = record
-  // buffer
     inbuf       : array[0..4095] of cuint8;
     inbuf_ptr   : pcuint8;
     frame_size  : cint;
     flags       : cint;
     channels    : cint;
     state       : pa52_state_t;
-    samples     : psample_t;
-
-  // callbacks
+    samples     : array[0..1,0..1535] of cint16;
+    samplecnt   : cint;
+    sampleofs   : cint;
     datasource  : pointer;
-    read        : read_func;
-    seek        : seek_func;
-    close       : close_func;
-    tell        : tell_func;
+    read        : a52_read_func;
+    seek        : a52_seek_func;
+    close       : a52_close_func;
+    tell        : a52_tell_func;
 
-  // codec info
+  // Userinfo
     sample_rate : cint;
     bit_rate    : cint;
   end;
 
-function a52_decoder_init(mm_accel: cuint32; datasource: pointer; read: read_func; seek: seek_func; close: close_func; tell: tell_func): pa52_decoder;
+function a52_decoder_init(mm_accel: cuint32; datasource: pointer; read: a52_read_func; seek: a52_seek_func; close: a52_close_func; tell: a52_tell_func): pa52_decoder;
 function a52_decoder_read(decoder: pa52_decoder; buffer: pointer; length: cint): cint;
 procedure a52_decoder_free(decoder: pa52_decoder);
 
 implementation
 
-function a52_decoder_init(mm_accel: cuint32; datasource: pointer; read: read_func; seek: seek_func; close: close_func; tell: tell_func): pa52_decoder;
+function a52_decoder_init(mm_accel: cuint32; datasource: pointer; read: a52_read_func; seek: a52_seek_func; close: a52_close_func; tell: a52_tell_func): pa52_decoder;
 begin
   GetMem(Result, Sizeof(a52_decoder));
   FillChar(Result^, Sizeof(a52_decoder), 0);
   Result^.state := a52_init(mm_accel);
-  Result^.samples := a52_samples(Result^.state);
+  //Result^.samples := a52_samples(Result^.state);
   Result^.inbuf_ptr := @Result^.inbuf;
   Result^.datasource := datasource;
   Result^.read := read;
@@ -462,7 +461,7 @@ begin
   FreeMem(decoder);
 end;
 
-procedure float_to_int(f: psample_t; s16: pcint16; nchannels: cint);
+{procedure float_to_int(f: psample_t; s16: pcint16; nchannels: cint);
 var
   i, c: cint;
 begin
@@ -477,7 +476,7 @@ begin
       Inc(s16);
     end;
   end;
-end;
+end;}
 
 function a52_decoder_read(decoder: pa52_decoder; buffer: pointer; length: cint): cint;
 const
@@ -485,86 +484,115 @@ const
   ac3_channels: array[0..7] of cint = (2,1,2,3,3,4,4,5);
 var
   num, ofs: cint;
-  flags, len, i: cint;
+  flags, len, i, j: cint;
   sample_rate, bit_rate: cint;
   level: cfloat;
 begin
+  // check blocksize here!
+
   ofs := 0;
   num := length;
 
   while num > 0 do
   begin
-    len := PtrInt(decoder^.inbuf_ptr) - PtrInt(@decoder^.inbuf);
-
-    if (len < HEADER_SIZE) or (len < decoder^.frame_size) then
+    if decoder^.samplecnt = 0 then
     begin
-      (* inbuf too small : enlarge *)
-      len := Sizeof(a52_decoder.inbuf) - len;
-      if decoder^.read(decoder^.inbuf_ptr, 1, len, decoder^.datasource) <> len then
-        Exit(ofs);
-      Inc(decoder^.inbuf_ptr, len);
-    end;
+      len := PtrInt(decoder^.inbuf_ptr) - PtrInt(@decoder^.inbuf);
 
-    if decoder^.frame_size = 0 then
-    begin
-      (* no header seen : find one. We need at least 7 bytes to parse it *)
-      //WriteLn('no header seen (', len, ')');
-
-      len := a52_syncinfo(@decoder^.inbuf, decoder^.flags, sample_rate, bit_rate);
-      if len = 0 then
+      if (len < HEADER_SIZE) or (len < decoder^.frame_size) then
       begin
-        (* no sync found : move by one byte (inefficient, but simple!) *)
-        Move(decoder^.inbuf[1], decoder^.inbuf[0], PtrInt(decoder^.inbuf_ptr) - PtrInt(@decoder^.inbuf) - 1);
-        Dec(decoder^.inbuf_ptr, 1);
-      end else begin
-        decoder^.frame_size := len;
-
-        (* update codec info *)
-        decoder^.sample_rate := sample_rate;
-        decoder^.bit_rate := bit_rate;
-        decoder^.channels := ac3_channels[decoder^.flags and $7];
-        if decoder^.flags and A52_LFE <> 0 then
-          Inc(decoder^.channels);
-
-       {WriteLn('  frame_size  : ', decoder^.frame_size);
-        WriteLn('  sample_rate : ', sample_rate);
-        WriteLn('  bit_rate    : ', bit_rate);
-        WriteLn('  channels    : ', decoder^.channels);}
-      end;
+        (* inbuf too small : enlarge *)
+        len := Sizeof(a52_decoder.inbuf) - len;
+        len := decoder^.read(decoder^.inbuf_ptr, 1, len, decoder^.datasource);
+        if len <= 0 then
+          Exit(ofs);
 
-      Continue;
-    end;
+        Inc(decoder^.inbuf_ptr, len);
+      end;
 
-    (* decode the frame *)
-    flags := A52_STEREO;//decoder^.flags;
-    level := High(Smallint)-30;
+      if decoder^.frame_size = 0 then
+      begin
+        (* no header seen : find one. We need at least 7 bytes to parse it *)
+        //WriteLn('no header seen (', len, ')');
+
+        len := a52_syncinfo(@decoder^.inbuf, decoder^.flags, sample_rate, bit_rate);
+        if len = 0 then
+        begin
+          (* no sync found : move by one byte (inefficient, but simple!) *)
+          Move(decoder^.inbuf[1], decoder^.inbuf[0], PtrInt(decoder^.inbuf_ptr) - PtrInt(@decoder^.inbuf) - 1);
+          Dec(decoder^.inbuf_ptr, 1);
+        end else begin
+          decoder^.frame_size := len;
+
+          (* update codec info *)
+          decoder^.sample_rate := sample_rate;
+          decoder^.bit_rate := bit_rate;
+          decoder^.channels := ac3_channels[decoder^.flags and $7];
+          if decoder^.flags and A52_LFE <> 0 then
+            Inc(decoder^.channels);
+
+         {WriteLn('  frame_size  : ', decoder^.frame_size);
+          WriteLn('  sample_rate : ', sample_rate);
+          WriteLn('  bit_rate    : ', bit_rate);
+          WriteLn('  channels    : ', decoder^.channels);}
+        end;
+
+        Continue;
+      end;
 
-    if a52_frame(decoder^.state, @decoder^.inbuf, flags, level, 0) <> 0 then
-    begin
-      decoder^.inbuf_ptr := @decoder^.inbuf;
-      decoder^.frame_size := 0;
-      Continue;
-    end;
+      (* decode the frame *)
+      flags := A52_STEREO;//decoder^.flags;
+      level := High(Smallint)-30;
 
-    for i := 0 to 5 do
-    begin
-      if a52_block(decoder^.state) <> 0 then
+      if a52_frame(decoder^.state, @decoder^.inbuf, flags, level, 0) <> 0 then
       begin
         decoder^.inbuf_ptr := @decoder^.inbuf;
         decoder^.frame_size := 0;
-        Exit(-1);
+        Continue;
+      end;
+
+      for i := 0 to 5 do
+      begin
+        if a52_block(decoder^.state) <> 0 then
+        begin
+          decoder^.inbuf_ptr := @decoder^.inbuf;
+          decoder^.frame_size := 0;
+          Exit(-1);
+        end;
+
+        for j := 0 to 255 do
+        begin
+          decoder^.samples[0, i*256+j] := Round(decoder^.state^.samples[j + 000]);
+          decoder^.samples[1, i*256+j] := Round(decoder^.state^.samples[j + 256]);
+        end;
       end;
 
-      float_to_int(decoder^.samples, pointer(PtrInt(buffer) + ofs + 2{channels}*i*256*2{sample_size}), 2{channels});
+      (* skip decoded frame *)
+      Move(decoder^.inbuf[decoder^.frame_size], decoder^.inbuf[0], PtrInt(decoder^.inbuf_ptr) - PtrInt(@decoder^.inbuf) - decoder^.frame_size);
+      Dec(decoder^.inbuf_ptr, decoder^.frame_size);
+      decoder^.frame_size := 0;
+
+      decoder^.sampleofs := 0;
+      decoder^.samplecnt := 6*256;
     end;
 
-    (* skip decoded frame *)
-    Move(decoder^.inbuf[decoder^.frame_size], decoder^.inbuf[0], PtrInt(decoder^.inbuf_ptr) - PtrInt(@decoder^.inbuf) - decoder^.frame_size);
-    Dec(decoder^.inbuf_ptr, decoder^.frame_size);
-    decoder^.frame_size := 0;
+    len := num div 4;
+    if len > decoder^.samplecnt then
+      len := decoder^.samplecnt;
+
+    for i := 0 to len - 1 do
+    begin
+      pcint16(ptrint(buffer) + ofs + 0)^ := decoder^.samples[0][decoder^.sampleofs];
+      pcint16(ptrint(buffer) + ofs + 2)^ := decoder^.samples[1][decoder^.sampleofs];
+
+      Inc(decoder^.sampleofs);
+      Dec(decoder^.samplecnt);
+      ofs := ofs + 4;
+      num := num - 4;
+    end;
 
-    ofs := ofs + 2{channels}*(6*256){samples}*2{sample_size};
-    num := num - 2{channels}*(6*256){samples}*2{sample_size};
+    //ofs := ofs + 2{channels}*(6*256){samples}*2{sample_size};
+    //num := num - 2{channels}*(6*256){samples}*2{sample_size};
   end;
 
   Result := ofs;

+ 178 - 16
packages/extra/mad/mad.pas

@@ -437,12 +437,12 @@ type
     synth       : mad_synth;
   end;
 
-  TInputFunc    = function(user: Pointer; var stream: mad_stream): mad_flow; cdecl;
-  THeaderFunc   = function(user: Pointer; var header: mad_header): mad_flow; cdecl;
-  TFilterFunc   = function(user: Pointer; var frame: mad_frame): mad_flow; cdecl;
-  TOutputFunc   = function(user: Pointer; var header: mad_header; var pcm: mad_pcm): mad_flow; cdecl;
-  TErrorFunc    = function(user: Pointer; var stream: mad_stream; var frame: mad_frame): mad_flow; cdecl;
-  TMessageFunc  = function(user, msg: Pointer; var l: cuint): mad_flow; cdecl;
+  mad_input_func    = function(user: Pointer; var stream: mad_stream): mad_flow; cdecl;
+  mad_header_func   = function(user: Pointer; var header: mad_header): mad_flow; cdecl;
+  mad_filter_func   = function(user: Pointer; var frame: mad_frame): mad_flow; cdecl;
+  mad_output_func   = function(user: Pointer; var header: mad_header; var pcm: mad_pcm): mad_flow; cdecl;
+  mad_error_func    = function(user: Pointer; var stream: mad_stream; var frame: mad_frame): mad_flow; cdecl;
+  mad_message_func  = function(user, msg: Pointer; var l: cuint): mad_flow; cdecl;
 
   mad_decoder = record
     mode        : mad_decoder_mode;
@@ -450,18 +450,55 @@ type
     async       : async_struct;
     sync        : ^sync_struct;
     data        : pointer;
-    InputFunc   : TInputFunc;
-    HeaderFunc  : THeaderFunc;
-    FilterFunc  : TFilterFunc;
-    OutputFunc  : TOutputFunc;
-    ErrorFunc   : TErrorFunc;
-    MessageFunc : TMessageFunc;
+    InputFunc   : mad_input_func;
+    HeaderFunc  : mad_header_func;
+    FilterFunc  : mad_filter_func;
+    OutputFunc  : mad_output_func;
+    ErrorFunc   : mad_error_func;
+    MessageFunc : mad_message_func;
   end;
 
-procedure mad_decoder_init(var decoder: mad_decoder; user: pointer; Input: TInputFunc; Header: THeaderFunc; Filter: TFilterFunc; Output: TOutputFunc; Error: TErrorFunc; Message: TMessageFunc); cdecl; external {$IFDEF DYNLINK}madlib{$ENDIF};
-function  mad_decoder_finish(var decoder: mad_decoder): cint; cdecl; external {$IFDEF DYNLINK}madlib{$ENDIF};
-function  mad_decoder_run(var decoder: mad_decoder; mode: mad_decoder_mode): cint; cdecl; external {$IFDEF DYNLINK}madlib{$ENDIF};
-function  mad_decoder_message(var decoder: mad_decoder; msg: Pointer; var l: cuint): cint; cdecl; external {$IFDEF DYNLINK}madlib{$ENDIF};
+procedure mad_decoder_init(var decoder: mad_decoder; user: pointer; Input: mad_input_func; Header: mad_header_func; Filter: mad_filter_func; Output: mad_output_func; Error: mad_error_func; Message: mad_message_func); cdecl; external {$IFDEF DYNLINK}madlib{$ENDIF};
+function mad_decoder_finish(var decoder: mad_decoder): cint; cdecl; external {$IFDEF DYNLINK}madlib{$ENDIF};
+function mad_decoder_run(var decoder: mad_decoder; mode: mad_decoder_mode): cint; cdecl; external {$IFDEF DYNLINK}madlib{$ENDIF};
+function mad_decoder_message(var decoder: mad_decoder; msg: Pointer; var l: cuint): cint; cdecl; external {$IFDEF DYNLINK}madlib{$ENDIF};
+
+
+{
+  Developer of the MAD helpers for FreePascal
+  Copyright (C) 2006 by Ivo Steinmann
+}
+
+const
+  MAD_INPUT_BUFFER_SIZE = 5*8192;
+
+type
+  mad_read_func  = function(ptr: pointer; size, nmemb: culong; datasource: pointer): culong; cdecl;
+  mad_seek_func  = function(datasource: pointer; offset: cint64; whence: cint): cint; cdecl;
+  mad_close_func = function(datasource: pointer): cint; cdecl;
+  mad_tell_func  = function(datasource: pointer): clong; cdecl;
+
+  pmad_decoder2 = ^mad_decoder2;
+  mad_decoder2 = record
+    inbuf       : array[0..MAD_INPUT_BUFFER_SIZE-1] of cuint8;
+    stream      : mad_stream;
+    frame       : mad_frame;
+    synth       : mad_synth;
+    samplecnt   : cint;
+    sampleofs   : cint;
+    datasource  : pointer;
+    read        : mad_read_func;
+    seek        : mad_seek_func;
+    close       : mad_close_func;
+    tell        : mad_tell_func;
+
+  // Userinfo
+    sample_rate : cint;
+  end;
+
+function mad_decoder_init(datasource: pointer; read: mad_read_func; seek: mad_seek_func; close: mad_close_func; tell: mad_tell_func): pmad_decoder2;
+function mad_decoder_read(decoder: pmad_decoder2; buffer: pointer; length: cint): cint;
+procedure mad_decoder_free(decoder: pmad_decoder2);
 
 implementation
 
@@ -544,4 +581,129 @@ begin
   FillChar(synth, sizeof(mad_synth), 0);
 end;
 
+function mad_decoder_init(datasource: pointer; read: mad_read_func; seek: mad_seek_func; close: mad_close_func; tell: mad_tell_func): pmad_decoder2;
+begin
+  GetMem(Result, Sizeof(mad_decoder2));
+  FillChar(Result^, Sizeof(mad_decoder2), 0);
+  mad_stream_init(Result^.stream);
+  mad_frame_init(Result^.frame);
+  mad_synth_init(Result^.synth);
+  Result^.datasource := datasource;
+  Result^.read := read;
+  Result^.seek := seek;
+  Result^.close := close;
+  Result^.tell := tell;
+end;
+
+procedure mad_decoder_free(decoder: pmad_decoder2);
+begin
+  if not Assigned(decoder) then
+    Exit;
+
+  mad_synth_finish(decoder^.synth);
+  mad_frame_finish(decoder^.frame);
+  mad_stream_finish(decoder^.stream);
+  FreeMem(decoder);
+end;
+
+function mad_decoder_read(decoder: pmad_decoder2; buffer: pointer; length: cint): cint;
+var
+  ofs, num, i: cint;
+  inbuf_ptr: pointer;
+  len, remaining: cint;
+begin
+  // check blocksize here!
+
+  ofs := 0;
+  num := length;
+
+  while num > 0 do
+  begin
+    if decoder^.samplecnt = 0 then
+    begin
+      if (decoder^.stream.buffer = nil) or (decoder^.stream.error = MAD_ERROR_BUFLEN) then
+      begin
+        if Assigned(decoder^.stream.next_frame) then
+        begin
+          remaining := ptrint(decoder^.stream.bufend) - ptrint(decoder^.stream.next_frame);
+          inbuf_ptr := pointer(ptrint(@decoder^.inbuf) + remaining);
+          len  := MAD_INPUT_BUFFER_SIZE - remaining;
+          Move(decoder^.stream.next_frame^, decoder^.inbuf, remaining);
+        end else begin
+          remaining := 0;
+          len  := MAD_INPUT_BUFFER_SIZE;
+          inbuf_ptr := @decoder^.inbuf;
+        end;
+
+        len := decoder^.read(inbuf_ptr, 1, len, decoder^.datasource);
+        if len <= 0 then
+          Exit(ofs);
+
+        mad_stream_buffer(decoder^.stream, decoder^.inbuf, len+remaining);
+        decoder^.stream.error := MAD_ERROR_NONE;
+      end;
+
+      if mad_frame_decode(decoder^.frame, decoder^.stream) <> 0 then
+      begin
+        if MAD_RECOVERABLE(decoder^.stream.error) or (decoder^.stream.error = MAD_ERROR_BUFLEN) then
+          Continue;
+
+        Exit(ofs);
+      end;
+
+      mad_synth_frame(decoder^.synth, decoder^.frame);
+
+      with decoder^.synth do
+      if pcm.channels = 2 then
+      begin
+        for i := 0 to pcm.length -1 do
+        begin
+          if pcm.samples[0][i] >= MAD_F_ONE then
+            pcm.samples[0][i] := MAD_F_ONE - 1;
+          if pcm.samples[0][i] < -MAD_F_ONE then
+            pcm.samples[0][i] := -MAD_F_ONE;
+          pcm.samples[0][i] := pcm.samples[0][i] shr (MAD_F_FRACBITS + 1 - 16 + 1);
+
+          if pcm.samples[1][i] >= MAD_F_ONE then
+            pcm.samples[1][i] := MAD_F_ONE - 1;
+          if pcm.samples[1][i] < -MAD_F_ONE then
+            pcm.samples[1][i] := -MAD_F_ONE;
+          pcm.samples[1][i] := pcm.samples[1][i] shr (MAD_F_FRACBITS + 1 - 16 + 1);
+        end;
+      end else begin
+        for i := 0 to pcm.length -1 do
+        begin
+          if pcm.samples[0][i] >= MAD_F_ONE then
+            pcm.samples[0][i] := MAD_F_ONE - 1;
+          if pcm.samples[0][i] < -MAD_F_ONE then
+            pcm.samples[0][i] := -MAD_F_ONE;
+          pcm.samples[0][i] := pcm.samples[0][i] shr (MAD_F_FRACBITS + 1 - 16 + 1);
+          pcm.samples[1][i] := pcm.samples[0][i];
+        end;
+      end;
+
+      decoder^.sampleofs := 0;
+      decoder^.samplecnt := decoder^.synth.pcm.length;
+      decoder^.sample_rate := decoder^.synth.pcm.samplerate;
+    end;
+
+    len := num div 4;
+    if len > decoder^.samplecnt then
+      len := decoder^.samplecnt;
+
+    for i := 0 to len - 1 do
+    begin
+      pcint16(ptrint(buffer) + ofs + 0)^ := decoder^.synth.pcm.samples[0][decoder^.sampleofs];
+      pcint16(ptrint(buffer) + ofs + 2)^ := decoder^.synth.pcm.samples[1][decoder^.sampleofs];
+
+      Inc(decoder^.sampleofs);
+      Dec(decoder^.samplecnt);
+      ofs := ofs + 4;
+      num := num - 4;
+    end;
+  end;
+
+  Result := ofs;
+end;
+
 end.

+ 1 - 0
packages/extra/oggvorbis/vorbis.pas

@@ -430,6 +430,7 @@ var
   Num: cint;
   Res: cint;
 begin
+  // check blocksize here!
   {if length mod 4 <> 0 then
     Exit(0);}
 

+ 43 - 146
packages/extra/openal/examples/madopenal.pas

@@ -13,116 +13,6 @@ var
   codec_rate : Longword;
   codec_chan : Longword;
 
-
-// mad
-const
-  MAD_INPUT_BUFFER_SIZE = 5*8192;
-
-var
-  m_stream  : mad_stream;
-  m_frame   : mad_frame;
-  m_synth   : mad_synth;
-  m_inbuf   : PByte;
-
-{procedure mad_reset;
-begin
-  mad_stream_finish(m_stream);
-  mad_stream_init(m_stream);
-  source.Position := 0;
-end;}
-
-function mad_read(const Buffer: Pointer; const Count: Longword): Longword;
-var
-  X         : Integer;
-  Num       : Longword;
-  Ofs       : Longword;
-  Remaining : Integer;
-  ReadStart : Pointer;
-  ReadSize  : Integer;
-  Output    : PSmallint;
-begin
-  Ofs := 0;
-  Num := Count;
-  while Num > 0 do
-  begin
-    if (m_stream.buffer = nil) or (m_stream.error = MAD_ERROR_BUFLEN) then
-    begin
-      if Assigned(m_stream.next_frame) then
-      begin
-        Remaining := PtrInt(m_stream.bufend) - PtrInt(m_stream.next_frame);
-        Move(m_stream.next_frame^, m_inbuf^, Remaining);
-        ReadStart := Pointer(PtrInt(m_inbuf) + Remaining);
-        ReadSize  := MAD_INPUT_BUFFER_SIZE - Remaining;
-      end else begin
-        ReadSize  := MAD_INPUT_BUFFER_SIZE;
-        ReadStart := m_inbuf;
-        Remaining := 0;
-      end;
-
-      ReadSize := source.Read(ReadStart^, ReadSize);
-      if ReadSize = 0 then
-        Break;
-
-      mad_stream_buffer(m_stream, m_inbuf, ReadSize+Remaining);
-      m_stream.error := MAD_ERROR_NONE;
-    end;
-
-    if mad_frame_decode(m_frame, m_stream) <> 0 then
-    begin
-      if MAD_RECOVERABLE(m_stream.error) or (m_stream.error = MAD_ERROR_BUFLEN) then
-        Continue;
-      Exit(0);
-    end;
-
-    mad_synth_frame(m_synth, m_frame);
-
-    Output := Pointer(PtrUInt(Buffer) + Ofs);
-    with m_synth do
-    if pcm.channels = 2 then
-    begin
-      for X := 0 to pcm.length -1 do
-      begin
-         if pcm.samples[0][X] >= MAD_F_ONE then
-           pcm.samples[0][X] := MAD_F_ONE - 1;
-         if pcm.samples[0][X] < -MAD_F_ONE then
-           pcm.samples[0][X] := -MAD_F_ONE;
-         pcm.samples[0][X] := pcm.samples[0][X] shr (MAD_F_FRACBITS + 1 - 16);
-         Output[X shl 1] := pcm.samples[0][X] div 2;
-
-         if pcm.samples[1][X] >= MAD_F_ONE then
-           pcm.samples[1][X] := MAD_F_ONE - 1;
-         if pcm.samples[1][X] < -MAD_F_ONE then
-           pcm.samples[1][X] := -MAD_F_ONE;
-         pcm.samples[1][X] := pcm.samples[1][X] shr (MAD_F_FRACBITS + 1 - 16);
-         Output[(X shl 1)+1] := pcm.samples[1][X] div 2;
-      end;
-    end else begin
-      for X := 0 to pcm.length -1 do
-      begin
-         if pcm.samples[0][X] >= MAD_F_ONE then
-           pcm.samples[0][X] := MAD_F_ONE - 1;
-         if pcm.samples[0][X] < -MAD_F_ONE then
-           pcm.samples[0][X] := -MAD_F_ONE;
-         pcm.samples[0][X] := pcm.samples[0][X] shr (MAD_F_FRACBITS + 1 - 16);
-
-         Output[X shl 1] := pcm.samples[0][X] div 2;
-         Output[(X shl 1)+1] := pcm.samples[0][X] div 2;
-      end;
-    end;
-
-    Ofs := Ofs + Longword(2{channels}*m_synth.pcm.length*2);
-    Num := Num - Longword(2{channels}*m_synth.pcm.length*2);
-  end;
-
-  Result := Ofs;
-end;
-
-
-// oggvorbis
-var
-  ogg_vorbis    : OggVorbis_File;
-  ogg_callbacks : ov_callbacks;
-
 function ogg_read_func(ptr: pointer; size, nmemb: csize_t; datasource: pointer): csize_t; cdecl;
 begin
   Result := TStream(datasource).Read(ptr^, size*nmemb);
@@ -149,6 +39,34 @@ begin
   Result := TStream(datasource).Position;
 end;
 
+
+// mad
+var
+  mad_decoder: pmad_decoder2;
+
+{procedure mad_reset;
+begin
+  mad_stream_finish(m_stream);
+  mad_stream_init(m_stream);
+  source.Position := 0;
+end;}
+
+function mad_read(const Buffer: Pointer; const Count: Longword): Longword;
+var
+  Res: cint;
+begin
+  Res := mad_decoder_read(mad_decoder, Buffer, Count);
+  if Res < 0 then
+    Result := 0 else
+    Result := Res;
+end;
+
+
+// oggvorbis
+var
+  ogg_vorbis    : OggVorbis_File;
+  ogg_callbacks : ov_callbacks;
+
 {procedure ogg_reset;
 begin
   ov_pcm_seek(ogg_vorbis, 0);
@@ -160,7 +78,7 @@ var
 begin
   Res := ov_read_ext(ogg_vorbis, Buffer, Count, false, 2, true);
   if Res < 0 then
-    Exit(0) else
+    Result := 0 else
     Result := Res;
 end;
 
@@ -171,27 +89,12 @@ var
 
 function a52_read(const Buffer: Pointer; const Count: Longword): Longword;
 var
-  Ofs: Longword;
-  Num: Longword;
-  Res: Integer;
+  Res: cint;
 begin
-  Ofs := 0;
-  Num := Count;
-
-  while Num > 0 do
-  begin
-    Res := a52_decoder_read(a52_decoder, Pointer(PtrUInt(Buffer) + Ofs), Num);
-    if Res < 0 then
-      Exit(0);
-
-    if Res = 0 then
-      Break;
-
-    Ofs := Ofs + Longword(Res);
-    Num := Num - Longword(Res);
-  end;
-
-  Result := Ofs;
+  Res := a52_decoder_read(a52_decoder, Buffer, Count);
+  if Res < 0 then
+    Result := 0 else
+    Result := Res;
 end;
 
 
@@ -272,15 +175,15 @@ var
   ov: pvorbis_info;
 begin
 // define codec
-  WriteLn('Define codec');
+ { WriteLn('Define codec');
   Writeln('  (1) mp3');
   Writeln('  (2) ogg');
   Writeln('  (3) ac3');
   Write('Enter: '); ReadLn(codec);
-  Write('File: '); ReadLn(Filename);
+  Write('File: '); ReadLn(Filename);}
 
-  {codec := 3;
-  Filename := 'test.ac3';}
+  codec := 3;
+  Filename := 'test.ac3';
 
 
 // load file
@@ -291,14 +194,11 @@ begin
   case codec of
     1: // mad
       begin
-        mad_stream_init(m_stream);
-        mad_frame_init(m_frame);
-        mad_synth_init(m_synth);
-        GetMem(m_inbuf, MAD_INPUT_BUFFER_SIZE);
-        codec_bs   := 2{channels}*1152*2{sample_size};
+        mad_decoder := mad_decoder_init(source, @ogg_read_func, @ogg_seek_func, @ogg_close_func, @ogg_tell_func);
         codec_read := @mad_read;
         codec_rate := 44100;
         codec_chan := 2;
+        codec_bs   := 2*codec_chan;
       end;
 
     2: // oggvorbis
@@ -311,20 +211,20 @@ begin
         if ov_open_callbacks(source, ogg_vorbis, nil, 0, ogg_callbacks) >= 0 then
         begin
           ov := ov_info(ogg_vorbis, -1);
-          codec_bs   := 4;
           codec_read := @ogg_read;
           codec_rate := ov^.rate;
           codec_chan := ov^.channels;
+          codec_bs   := 2*codec_chan;
         end;
       end;
 
     3: // a52
       begin
         a52_decoder := a52_decoder_init(0, source, @ogg_read_func, @ogg_seek_func, @ogg_close_func, @ogg_tell_func);
-        codec_bs   := 2{channels}*1536*2{sample_size};
         codec_read := @a52_read;
         codec_rate := 44100;//48000;
         codec_chan := 2;
+        codec_bs   := 2*codec_chan;
       end;
   end;
 
@@ -371,10 +271,7 @@ begin
   case codec of
     1: // mad
       begin
-        mad_synth_finish(m_synth);
-        mad_frame_finish(m_frame);
-        mad_stream_finish(m_stream);
-        FreeMem(m_inbuf);
+        mad_decoder_free(mad_decoder);
       end;
 
     2: // oggvorbis