-- $Id: wc-streams-codec.adb,v 1.2 2005/02/11 02:59:38 ken Exp $
--
-- (c) Warren W. Gay VE3WWG ve3wwg@home.com, ve3wwg@yahoo.com
--
-- Protected under the GNU GPL License

with Ada.Streams, Ada.IO_Exceptions;
use Ada.Streams, Ada.IO_Exceptions;

with WC.Streams.Endian;
with WC.CInts;

use WC.Streams.Endian;
use WC.CInts;

package body WC.Streams.Codec is

   CVSID: constant String := "$Header: /home/cvsroot/bush/src/ADAVOX-0.51/wc/wc-streams-codec.adb,v 1.2 2005/02/11 02:59:38 ken Exp $";
    
   pragma Optimize(Time);

   --------------------------------------------------
   -- IMPORTANT NOTE : The MPEG 1 Layer 3 (MP3)
   -- support is planned for, but not complete here.
   -- I repeat: MP3 support is NOT YET SUPPORTED.
   --------------------------------------------------
   -- MPEG 1 Layer 3 :
   --------------------------------------------------
   -- This CODEC is an Ada95 Adaptation of the mpg123 library code by :
   --      Michael Hipp (email: hippm@informatik.uni-tuebingen.de)
   --      Oliver Fromme <oliver.fromme@heim3.tu-clausthal.de>
   -- Which used code or ideas from:
   --      MPEG Software Simulation Group: reference decoder package
   --      Tobias Bading: idea for DCT64 in subband synthesis from maplay package
   --      Jeff Tsay and Mikko Tommila: MDCT36 from maplay package
   --      Philipp Knirsch <phil@mpik-tueb.mpg.de>: DCT36/manual unroll idea
   --      Thomas Woerner <..> (SGI Audio)
   --      Damien Clermonte <..> (HP-UX audio fixes)
   --      Niclas Lindstrom <nil@wineasy.se>: OS2 port
   --      Stefan Bieschewski <stb@acm.org>: Pentium optimizations, decode_i586.s
   --      Martin Denn <mdenn@unix-ag.uni-kl.de>: NAS port
   --      Niklas Beisert <nbeisert@physik.tu-muenchen.de> MPEG 2.5 tables
   --      <mycroft@NetBSD.ORG> and <augustss@cs.chalmers.se>: NetBSD
   --      Kevin Brintnall <kbrint@visi.com> BSD patch
   --      Tony Million: win32 port
   --      Steven Tiger Lang: advanced shuffle
   --      Henrik P Johnson: HTTP auth patch
   --      Eric B. Mitchell: esd port
   --      Ryan R. Prosser <prosser@geocities.com> esd port for Solaris
   --      Daniel Kobras <daniel.kobras@student.uni-tuebingen.de>: lot of (DK)-bugfixes
   --      and more ....
   --------------------------------------------------
   procedure Pump_MPEG1L3(In_Str, Out_Str : Audio_Stream)
   is
      type Real is new float digits 6;
      type Real_Array is array(Integer range <>) of Real;
      type Integer_Array is array(Integer range <>) of Integer;

      -- These tables are derived from the tabinit.c code :
      Cos_64 : constant Real_Array(0..15) := (
         +5.00602998235196295208435796064705414E-01, +5.05470959897543639031524537186257362E-01, +5.15447309922624556720142929844286073E-01, 
         +5.31042591089784158753066278801924227E-01, +5.53103896034444523772781454606928264E-01, +5.82934968206133840922748140522813287E-01, 
         +6.22504123035664790541347107799552418E-01, +6.74808341455005732643923632707583238E-01, +7.44536271002298527998865956822882595E-01, 
         +8.39349645415526863351761421849772660E-01, +9.72568237861960817271147344831305759E-01, +1.16943993343288467725345908254652727E+00, 
         +1.48416461631416627536816932320107298E+00, +2.05778100995341077148435837695927830E+00, +3.40760841846871887221744057416827900E+00, 
         +1.01900081235480336134049950125302075E+01
      );
      Cos_32 : constant Real_Array(0..7) := (
         +5.02419286188155684051356852926062402E-01, +5.22498614939688902757825017530990408E-01, +5.66944034816357690946455466507458709E-01, 
         +6.46821783359990102322319843741738055E-01, +7.88154623451250237675062143560822392E-01, +1.06067768599034711126012642257165908E+00, 
         +1.72244709823833414485353549006063645E+00, +5.10114861868915510628025300476906523E+00
      );
      Cos_16 : constant Real_Array(0..3) := (
         +5.09795579104159178574461053212729666E-01, +6.01344886935045281565331842799082551E-01, +8.99976223136415601070500075442382126E-01, 
         +2.56291544774150534453417693558918700E+00
      );
      Cos_8 : constant Real_Array(0..1) := (
         +5.41196100146196994759399678809330680E-01, +1.30656296487637630396403537469396383E+00
      );
      Cos_4 : constant Real                        :=  +7.07106781186547476080687252286693933E-01;
      Dec_Win : constant Real_Array(0..543) := (
         -0.00000000000000000000000000000000000E+00, +1.44995574951171875000000000000000000E+01, -1.06496749877929687500000000000000000E+02,  -- 2
         +2.29492996215820312500000000000000000E+02, -1.01846891784667968750000000000000000E+03, +2.57642137145996093750000000000000000E+03,  -- 5
         -3.28689968872070312500000000000000000E+03, +1.87439279632568359375000000000000000E+04, -3.75178550109863281250000000000000000E+04,  -- 8
         -1.87439279632568359375000000000000000E+04, -3.28689968872070312500000000000000000E+03, -2.57642137145996093750000000000000000E+03,  -- 11
         -1.01846891784667968750000000000000000E+03, -2.29492996215820312500000000000000000E+02, -1.06496749877929687500000000000000000E+02,  -- 14
         -1.44995574951171875000000000000000000E+01, -0.00000000000000000000000000000000000E+00, +1.44995574951171875000000000000000000E+01,  -- 17
         -1.06496749877929687500000000000000000E+02, +2.29492996215820312500000000000000000E+02, -1.01846891784667968750000000000000000E+03,  -- 20
         +2.57642137145996093750000000000000000E+03, -3.28689968872070312500000000000000000E+03, +1.87439279632568359375000000000000000E+04,  -- 23
         -3.75178550109863281250000000000000000E+04, -1.87439279632568359375000000000000000E+04, -3.28689968872070312500000000000000000E+03,  -- 26
         -2.57642137145996093750000000000000000E+03, -1.01846891784667968750000000000000000E+03, -2.29492996215820312500000000000000000E+02,  -- 29
         -1.06496749877929687500000000000000000E+02, -1.44995574951171875000000000000000000E+01, +4.99984741210937500000000000000000000E-01,  -- 32
         +1.54995269775390625000000000000000000E+01, -1.08996673583984375000000000000000000E+02, +2.59492080688476562500000000000000000E+02,  -- 35
         -9.99969482421875000000000000000000000E+02, +2.75841581726074218750000000000000000E+03, -2.97940907287597656250000000000000000E+03,  -- 38
         +1.96673997802734375000000000000000000E+04, -3.74948557128906250000000000000000000E+04, -1.78194561767578125000000000000000000E+04,  -- 41
         -3.56689114379882812500000000000000000E+03, -2.39392694091796875000000000000000000E+03, -1.03146852111816406250000000000000000E+03,  -- 44
         -2.00493881225585937500000000000000000E+02, -1.03996826171875000000000000000000000E+02, -1.29996032714843750000000000000000000E+01,  -- 47
         +4.99984741210937500000000000000000000E-01, +1.54995269775390625000000000000000000E+01, -1.08996673583984375000000000000000000E+02,  -- 50
         +2.59492080688476562500000000000000000E+02, -9.99969482421875000000000000000000000E+02, +2.75841581726074218750000000000000000E+03,  -- 53
         -2.97940907287597656250000000000000000E+03, +1.96673997802734375000000000000000000E+04, -3.74948557128906250000000000000000000E+04,  -- 56
         -1.78194561767578125000000000000000000E+04, -3.56689114379882812500000000000000000E+03, -2.39392694091796875000000000000000000E+03,  -- 59
         -1.03146852111816406250000000000000000E+03, -2.00493881225585937500000000000000000E+02, -1.03996826171875000000000000000000000E+02,  -- 62
         -1.29996032714843750000000000000000000E+01, +4.99984741210937500000000000000000000E-01, +1.74994659423828125000000000000000000E+01,  -- 65
         -1.10996612548828125000000000000000000E+02, +2.90491134643554687500000000000000000E+02, -9.75970214843750000000000000000000000E+02,  -- 68
         +2.93941029357910156250000000000000000E+03, -2.64391931152343750000000000000000000E+03, +2.05873717041015625000000000000000000E+04,  -- 71
         -3.74268577880859375000000000000000000E+04, -1.68949843902587890625000000000000000E+04, -3.81988342285156250000000000000000000E+03,  -- 74
         -2.21243247985839843750000000000000000E+03, -1.03996826171875000000000000000000000E+03, -1.73494705200195312500000000000000000E+02,  -- 77
         -1.00996917724609375000000000000000000E+02, -1.19996337890625000000000000000000000E+01, +4.99984741210937500000000000000000000E-01,  -- 80
         +1.74994659423828125000000000000000000E+01, -1.10996612548828125000000000000000000E+02, +2.90491134643554687500000000000000000E+02,  -- 83
         -9.75970214843750000000000000000000000E+02, +2.93941029357910156250000000000000000E+03, -2.64391931152343750000000000000000000E+03,  -- 86
         +2.05873717041015625000000000000000000E+04, -3.74268577880859375000000000000000000E+04, -1.68949843902587890625000000000000000E+04,  -- 89
         -3.81988342285156250000000000000000000E+03, -2.21243247985839843750000000000000000E+03, -1.03996826171875000000000000000000000E+03,  -- 92
         -1.73494705200195312500000000000000000E+02, -1.00996917724609375000000000000000000E+02, -1.19996337890625000000000000000000000E+01,  -- 95
         +4.99984741210937500000000000000000000E-01, +1.89994201660156250000000000000000000E+01, -1.12496566772460937500000000000000000E+02,  -- 98
         +3.22490158081054687500000000000000000E+02, -9.46471115112304687500000000000000000E+02, +3.11840483093261718750000000000000000E+03,  -- 101
         -2.28043040466308593750000000000000000E+03, +2.15023437805175781250000000000000000E+04, -3.73138612365722656250000000000000000E+04,  -- 104
         -1.59730125274658203125000000000000000E+04, -4.04587652587890625000000000000000000E+03, -2.03143800354003906250000000000000000E+03,  -- 107
         -1.04346815490722656250000000000000000E+03, -1.46995513916015625000000000000000000E+02, -9.79970092773437500000000000000000000E+01,  -- 110
         -1.04996795654296875000000000000000000E+01, +4.99984741210937500000000000000000000E-01, +1.89994201660156250000000000000000000E+01,  -- 113
         -1.12496566772460937500000000000000000E+02, +3.22490158081054687500000000000000000E+02, -9.46471115112304687500000000000000000E+02,  -- 116
         +3.11840483093261718750000000000000000E+03, -2.28043040466308593750000000000000000E+03, +2.15023437805175781250000000000000000E+04,  -- 119
         -3.73138612365722656250000000000000000E+04, -1.59730125274658203125000000000000000E+04, -4.04587652587890625000000000000000000E+03,  -- 122
         -2.03143800354003906250000000000000000E+03, -1.04346815490722656250000000000000000E+03, -1.46995513916015625000000000000000000E+02,  -- 125
         -9.79970092773437500000000000000000000E+01, -1.04996795654296875000000000000000000E+01, +4.99984741210937500000000000000000000E-01,  -- 128
         +2.04993743896484375000000000000000000E+01, -1.13496536254882812500000000000000000E+02, +3.55489151000976562500000000000000000E+02,  -- 131
         -9.10972198486328125000000000000000000E+02, +3.29439945983886718750000000000000000E+03, -1.88794238281250000000000000000000000E+03,  -- 134
         +2.24098160858154296875000000000000000E+04, -3.71553660736083984375000000000000000E+04, -1.50555405273437500000000000000000000E+04,  -- 137
         -4.24587042236328125000000000000000000E+03, -1.85244346618652343750000000000000000E+03, -1.04246818542480468750000000000000000E+03,  -- 140
         -1.21996276855468750000000000000000000E+02, -9.49971008300781250000000000000000000E+01, -9.49971008300781250000000000000000000E+00,  -- 143
         +4.99984741210937500000000000000000000E-01, +2.04993743896484375000000000000000000E+01, -1.13496536254882812500000000000000000E+02,  -- 146
         +3.55489151000976562500000000000000000E+02, -9.10972198486328125000000000000000000E+02, +3.29439945983886718750000000000000000E+03,  -- 149
         -1.88794238281250000000000000000000000E+03, +2.24098160858154296875000000000000000E+04, -3.71553660736083984375000000000000000E+04,  -- 152
         -1.50555405273437500000000000000000000E+04, -4.24587042236328125000000000000000000E+03, -1.85244346618652343750000000000000000E+03,  -- 155
         -1.04246818542480468750000000000000000E+03, -1.21996276855468750000000000000000000E+02, -9.49971008300781250000000000000000000E+01,  -- 158
         -9.49971008300781250000000000000000000E+00, +4.99984741210937500000000000000000000E-01, +2.24993133544921875000000000000000000E+01,  -- 161
         -1.13996520996093750000000000000000000E+02, +3.89488113403320312500000000000000000E+02, -8.69473464965820312500000000000000000E+02,  -- 164
         +3.46739418029785156250000000000000000E+03, -1.46745521545410156250000000000000000E+03, +2.33077886810302734375000000000000000E+04,  -- 167
         -3.69528722534179687500000000000000000E+04, -1.41440683441162109375000000000000000E+04, -4.41986511230468750000000000000000000E+03,  -- 170
         -1.67544886779785156250000000000000000E+03, -1.03746833801269531250000000000000000E+03, -9.84969940185546875000000000000000000E+01,  -- 173
         -9.14972076416015625000000000000000000E+01, -8.49974060058593750000000000000000000E+00, +4.99984741210937500000000000000000000E-01,  -- 176
         +2.24993133544921875000000000000000000E+01, -1.13996520996093750000000000000000000E+02, +3.89488113403320312500000000000000000E+02,  -- 179
         -8.69473464965820312500000000000000000E+02, +3.46739418029785156250000000000000000E+03, -1.46745521545410156250000000000000000E+03,  -- 182
         +2.33077886810302734375000000000000000E+04, -3.69528722534179687500000000000000000E+04, -1.41440683441162109375000000000000000E+04,  -- 185
         -4.41986511230468750000000000000000000E+03, -1.67544886779785156250000000000000000E+03, -1.03746833801269531250000000000000000E+03,  -- 188
         -9.84969940185546875000000000000000000E+01, -9.14972076416015625000000000000000000E+01, -8.49974060058593750000000000000000000E+00,  -- 191
         +4.99984741210937500000000000000000000E-01, +2.44992523193359375000000000000000000E+01, -1.13996520996093750000000000000000000E+02,  -- 194
         +4.23987060546875000000000000000000000E+02, -8.21974914550781250000000000000000000E+02, +3.63538905334472656250000000000000000E+03,  -- 197
         -1.01846891784667968750000000000000000E+03, +2.41942616271972656250000000000000000E+04, -3.67063797760009765625000000000000000E+04,  -- 200
         -1.32405959167480468750000000000000000E+04, -4.56936054992675781250000000000000000E+03, -1.50195416259765625000000000000000000E+03,  -- 203
         -1.02846861267089843750000000000000000E+03, -7.64976654052734375000000000000000000E+01, -8.79973144531250000000000000000000000E+01,  -- 206
         -7.99975585937500000000000000000000000E+00, +4.99984741210937500000000000000000000E-01, +2.44992523193359375000000000000000000E+01,  -- 209
         -1.13996520996093750000000000000000000E+02, +4.23987060546875000000000000000000000E+02, -8.21974914550781250000000000000000000E+02,  -- 212
         +3.63538905334472656250000000000000000E+03, -1.01846891784667968750000000000000000E+03, +2.41942616271972656250000000000000000E+04,  -- 215
         -3.67063797760009765625000000000000000E+04, -1.32405959167480468750000000000000000E+04, -4.56936054992675781250000000000000000E+03,  -- 218
         -1.50195416259765625000000000000000000E+03, -1.02846861267089843750000000000000000E+03, -7.64976654052734375000000000000000000E+01,  -- 221
         -8.79973144531250000000000000000000000E+01, -7.99975585937500000000000000000000000E+00, +9.99969482421875000000000000000000000E-01,  -- 224
         +2.64991912841796875000000000000000000E+01, -1.13496536254882812500000000000000000E+02, +4.59485977172851562500000000000000000E+02,  -- 227
         -7.67476577758789062500000000000000000E+02, +3.79838407897949218750000000000000000E+03, -5.40983489990234375000000000000000000E+02,  -- 230
         +2.50677349700927734375000000000000000E+04, -3.64163886260986328125000000000000000E+04, -1.23466231994628906250000000000000000E+04,  -- 233
         -4.69435673522949218750000000000000000E+03, -1.33145936584472656250000000000000000E+03, -1.01596899414062500000000000000000000E+03,  -- 236
         -5.54983062744140625000000000000000000E+01, -8.44974212646484375000000000000000000E+01, -6.99978637695312500000000000000000000E+00,  -- 239
         +9.99969482421875000000000000000000000E-01, +2.64991912841796875000000000000000000E+01, -1.13496536254882812500000000000000000E+02,  -- 242
         +4.59485977172851562500000000000000000E+02, -7.67476577758789062500000000000000000E+02, +3.79838407897949218750000000000000000E+03,  -- 245
         -5.40983489990234375000000000000000000E+02, +2.50677349700927734375000000000000000E+04, -3.64163886260986328125000000000000000E+04,  -- 248
         -1.23466231994628906250000000000000000E+04, -4.69435673522949218750000000000000000E+03, -1.33145936584472656250000000000000000E+03,  -- 251
         -1.01596899414062500000000000000000000E+03, -5.54983062744140625000000000000000000E+01, -8.44974212646484375000000000000000000E+01,  -- 254
         -6.99978637695312500000000000000000000E+00, +9.99969482421875000000000000000000000E-01, +2.89991149902343750000000000000000000E+01,  -- 257
         -1.11996582031250000000000000000000000E+02, +4.95484878540039062500000000000000000E+02, -7.06978424072265625000000000000000000E+02,  -- 260
         +3.95487930297851562500000000000000000E+03, -3.49989318847656250000000000000000000E+01, +2.59257087860107421875000000000000000E+04,  -- 263
         -3.60833987884521484375000000000000000E+04, -1.14641501312255859375000000000000000E+04, -4.79585363769531250000000000000000000E+03,  -- 266
         -1.16496444702148437500000000000000000E+03, -1.00046946716308593750000000000000000E+03, -3.59989013671875000000000000000000000E+01,  -- 269
         -8.04975433349609375000000000000000000E+01, -6.49980163574218750000000000000000000E+00, +9.99969482421875000000000000000000000E-01,  -- 272
         +2.89991149902343750000000000000000000E+01, -1.11996582031250000000000000000000000E+02, +4.95484878540039062500000000000000000E+02,  -- 275
         -7.06978424072265625000000000000000000E+02, +3.95487930297851562500000000000000000E+03, -3.49989318847656250000000000000000000E+01,  -- 278
         +2.59257087860107421875000000000000000E+04, -3.60833987884521484375000000000000000E+04, -1.14641501312255859375000000000000000E+04,  -- 281
         -4.79585363769531250000000000000000000E+03, -1.16496444702148437500000000000000000E+03, -1.00046946716308593750000000000000000E+03,  -- 284
         -3.59989013671875000000000000000000000E+01, -8.04975433349609375000000000000000000E+01, -6.49980163574218750000000000000000000E+00,  -- 287
         +9.99969482421875000000000000000000000E-01, +3.14990386962890625000000000000000000E+01, -1.10496627807617187500000000000000000E+02,  -- 290
         +5.31983764648437500000000000000000000E+02, -6.39980468750000000000000000000000000E+02, +4.10437474060058593750000000000000000E+03,  -- 293
         +4.98984771728515625000000000000000000E+02, +2.67661831359863281250000000000000000E+04, -3.57089102172851562500000000000000000E+04,  -- 296
         -1.05941766815185546875000000000000000E+04, -4.87485122680664062500000000000000000E+03, -1.00296939086914062500000000000000000E+03,  -- 299
         -9.80970062255859375000000000000000000E+02, -1.79994506835937500000000000000000000E+01, -7.69976501464843750000000000000000000E+01,  -- 302
         -5.49983215332031250000000000000000000E+00, +9.99969482421875000000000000000000000E-01, +3.14990386962890625000000000000000000E+01,  -- 305
         -1.10496627807617187500000000000000000E+02, +5.31983764648437500000000000000000000E+02, -6.39980468750000000000000000000000000E+02,  -- 308
         +4.10437474060058593750000000000000000E+03, +4.98984771728515625000000000000000000E+02, +2.67661831359863281250000000000000000E+04,  -- 311
         -3.57089102172851562500000000000000000E+04, -1.05941766815185546875000000000000000E+04, -4.87485122680664062500000000000000000E+03,  -- 314
         -1.00296939086914062500000000000000000E+03, -9.80970062255859375000000000000000000E+02, -1.79994506835937500000000000000000000E+01,  -- 317
         -7.69976501464843750000000000000000000E+01, -5.49983215332031250000000000000000000E+00, +9.99969482421875000000000000000000000E-01,  -- 320
         +3.39989624023437500000000000000000000E+01, -1.07496719360351562500000000000000000E+02, +5.68482650756835937500000000000000000E+02,  -- 323
         -5.65482742309570312500000000000000000E+02, +4.24537043762207031250000000000000000E+03, +1.06096762084960937500000000000000000E+03,  -- 326
         +2.75881580505371093750000000000000000E+04, -3.52939228820800781250000000000000000E+04, -9.73870278930664062500000000000000000E+03,  -- 329
         -4.93134950256347656250000000000000000E+03, -8.45974182128906250000000000000000000E+02, -9.59470718383789062500000000000000000E+02,  -- 332
         -9.99969482421875000000000000000000000E-01, -7.34977569580078125000000000000000000E+01, -4.99984741210937500000000000000000000E+00,  -- 335
         +9.99969482421875000000000000000000000E-01, +3.39989624023437500000000000000000000E+01, -1.07496719360351562500000000000000000E+02,  -- 338
         +5.68482650756835937500000000000000000E+02, -5.65482742309570312500000000000000000E+02, +4.24537043762207031250000000000000000E+03,  -- 341
         +1.06096762084960937500000000000000000E+03, +2.75881580505371093750000000000000000E+04, -3.52939228820800781250000000000000000E+04,  -- 344
         -9.73870278930664062500000000000000000E+03, -4.93134950256347656250000000000000000E+03, -8.45974182128906250000000000000000000E+02,  -- 347
         -9.59470718383789062500000000000000000E+02, -9.99969482421875000000000000000000000E-01, -7.34977569580078125000000000000000000E+01,  -- 350
         -4.99984741210937500000000000000000000E+00, +1.49995422363281250000000000000000000E+00, +3.64988861083984375000000000000000000E+01,  -- 353
         -1.03996826171875000000000000000000000E+02, +6.04981536865234375000000000000000000E+02, -4.84985198974609375000000000000000000E+02,  -- 356
         +4.37736640930175781250000000000000000E+03, +1.64994964599609375000000000000000000E+03, +2.83881336364746093750000000000000000E+04,  -- 359
         -3.48384367828369140625000000000000000E+04, -8.89922840881347656250000000000000000E+03, -4.96734840393066406250000000000000000E+03,  -- 362
         -6.93978820800781250000000000000000000E+02, -9.34971466064453125000000000000000000E+02, +1.44995574951171875000000000000000000E+01,  -- 365
         -6.94978790283203125000000000000000000E+01, -4.49986267089843750000000000000000000E+00, +1.49995422363281250000000000000000000E+00,  -- 368
         +3.64988861083984375000000000000000000E+01, -1.03996826171875000000000000000000000E+02, +6.04981536865234375000000000000000000E+02,  -- 371
         -4.84985198974609375000000000000000000E+02, +4.37736640930175781250000000000000000E+03, +1.64994964599609375000000000000000000E+03,  -- 374
         +2.83881336364746093750000000000000000E+04, -3.48384367828369140625000000000000000E+04, -8.89922840881347656250000000000000000E+03,  -- 377
         -4.96734840393066406250000000000000000E+03, -6.93978820800781250000000000000000000E+02, -9.34971466064453125000000000000000000E+02,  -- 380
         +1.44995574951171875000000000000000000E+01, -6.94978790283203125000000000000000000E+01, -4.49986267089843750000000000000000000E+00,  -- 383
         +1.49995422363281250000000000000000000E+00, +3.94987945556640625000000000000000000E+01, -9.99969482421875000000000000000000000E+01,  -- 386
         +6.41480422973632812500000000000000000E+02, -3.96987884521484375000000000000000000E+02, +4.49886270141601562500000000000000000E+03,  -- 389
         +2.26643083190917968750000000000000000E+03, +2.91656099090576171875000000000000000E+04, -3.43449518432617187500000000000000000E+04,  -- 392
         -8.07725349426269531250000000000000000E+03, -4.98284793090820312500000000000000000E+03, -5.47483291625976562500000000000000000E+02,  -- 395
         -9.08472274780273437500000000000000000E+02, +2.84991302490234375000000000000000000E+01, -6.59979858398437500000000000000000000E+01,  -- 398
         -3.99987792968750000000000000000000000E+00, +1.49995422363281250000000000000000000E+00, +3.94987945556640625000000000000000000E+01,  -- 401
         -9.99969482421875000000000000000000000E+01, +6.41480422973632812500000000000000000E+02, -3.96987884521484375000000000000000000E+02,  -- 404
         +4.49886270141601562500000000000000000E+03, +2.26643083190917968750000000000000000E+03, +2.91656099090576171875000000000000000E+04,  -- 407
         -3.43449518432617187500000000000000000E+04, -8.07725349426269531250000000000000000E+03, -4.98284793090820312500000000000000000E+03,  -- 410
         -5.47483291625976562500000000000000000E+02, -9.08472274780273437500000000000000000E+02, +2.84991302490234375000000000000000000E+01,  -- 413
         -6.59979858398437500000000000000000000E+01, -3.99987792968750000000000000000000000E+00, +1.99993896484375000000000000000000000E+00,  -- 416
         +4.24987030029296875000000000000000000E+01, -9.44971160888671875000000000000000000E+01, +6.77979309082031250000000000000000000E+02,  -- 419
         -3.02490768432617187500000000000000000E+02, +4.60935932922363281250000000000000000E+03, +2.90891122436523437500000000000000000E+03,  -- 422
         +2.99180869445800781250000000000000000E+04, -3.38134680633544921875000000000000000E+04, -7.27377801513671875000000000000000000E+03,  -- 425
         -4.97934803771972656250000000000000000E+03, -4.06987579345703125000000000000000000E+02, -8.79473159790039062500000000000000000E+02,  -- 428
         +4.14987335205078125000000000000000000E+01, -6.24980926513671875000000000000000000E+01, -3.49989318847656250000000000000000000E+00,  -- 431
         +1.99993896484375000000000000000000000E+00, +4.24987030029296875000000000000000000E+01, -9.44971160888671875000000000000000000E+01,  -- 434
         +6.77979309082031250000000000000000000E+02, -3.02490768432617187500000000000000000E+02, +4.60935932922363281250000000000000000E+03,  -- 437
         +2.90891122436523437500000000000000000E+03, +2.99180869445800781250000000000000000E+04, -3.38134680633544921875000000000000000E+04,  -- 440
         -7.27377801513671875000000000000000000E+03, -4.97934803771972656250000000000000000E+03, -4.06987579345703125000000000000000000E+02,  -- 443
         -8.79473159790039062500000000000000000E+02, +4.14987335205078125000000000000000000E+01, -6.24980926513671875000000000000000000E+01,  -- 446
         -3.49989318847656250000000000000000000E+00, +1.99993896484375000000000000000000000E+00, +4.54986114501953125000000000000000000E+01,  -- 449
         -8.84972991943359375000000000000000000E+01, +7.13978210449218750000000000000000000E+02, -2.00993865966796875000000000000000000E+02,  -- 452
         +4.70785632324218750000000000000000000E+03, +3.57689083862304687500000000000000000E+03, +3.06435648040771484375000000000000000E+04,  -- 455
         -3.32459853820800781250000000000000000E+04, -6.48980194091796875000000000000000000E+03, -4.95784869384765625000000000000000000E+03,  -- 458
         -2.72491683959960937500000000000000000E+02, -8.48974090576171875000000000000000000E+02, +5.29983825683593750000000000000000000E+01,  -- 461
         -5.84982147216796875000000000000000000E+01, -3.49989318847656250000000000000000000E+00, +1.99993896484375000000000000000000000E+00,  -- 464
         +4.54986114501953125000000000000000000E+01, -8.84972991943359375000000000000000000E+01, +7.13978210449218750000000000000000000E+02,  -- 467
         -2.00993865966796875000000000000000000E+02, +4.70785632324218750000000000000000000E+03, +3.57689083862304687500000000000000000E+03,  -- 470
         +3.06435648040771484375000000000000000E+04, -3.32459853820800781250000000000000000E+04, -6.48980194091796875000000000000000000E+03,  -- 473
         -4.95784869384765625000000000000000000E+03, -2.72491683959960937500000000000000000E+02, -8.48974090576171875000000000000000000E+02,  -- 476
         +5.29983825683593750000000000000000000E+01, -5.84982147216796875000000000000000000E+01, -3.49989318847656250000000000000000000E+00,  -- 479
         +2.49992370605468750000000000000000000E+00, +4.84985198974609375000000000000000000E+01, -8.14975128173828125000000000000000000E+01,  -- 482
         +7.48977142333984375000000000000000000E+02, -9.24971771240234375000000000000000000E+01, +4.79235374450683593750000000000000000E+03,  -- 485
         +4.26986968994140625000000000000000000E+03, +3.13410435180664062500000000000000000E+04, -3.26440037536621093750000000000000000E+04,  -- 488
         -5.72732521057128906250000000000000000E+03, -4.91884988403320312500000000000000000E+03, -1.43995605468750000000000000000000000E+02,  -- 491
         -8.16975067138671875000000000000000000E+02, +6.34980621337890625000000000000000000E+01, -5.54983062744140625000000000000000000E+01,  -- 494
         -2.99990844726562500000000000000000000E+00, +2.49992370605468750000000000000000000E+00, +4.84985198974609375000000000000000000E+01,  -- 497
         -8.14975128173828125000000000000000000E+01, +7.48977142333984375000000000000000000E+02, -9.24971771240234375000000000000000000E+01,  -- 500
         +4.79235374450683593750000000000000000E+03, +4.26986968994140625000000000000000000E+03, +3.13410435180664062500000000000000000E+04,  -- 503
         -3.26440037536621093750000000000000000E+04, -5.72732521057128906250000000000000000E+03, -4.91884988403320312500000000000000000E+03,  -- 506
         -1.43995605468750000000000000000000000E+02, -8.16975067138671875000000000000000000E+02, +6.34980621337890625000000000000000000E+01,  -- 509
         -5.54983062744140625000000000000000000E+01, -2.99990844726562500000000000000000000E+00, +2.49992370605468750000000000000000000E+00,  -- 512
         +5.19984130859375000000000000000000000E+01, -7.29977722167968750000000000000000000E+01, +7.83476089477539062500000000000000000E+02,  -- 515
         +2.24993133544921875000000000000000000E+01, +4.86335157775878906250000000000000000E+03, +4.98734779357910156250000000000000000E+03,  -- 518
         +3.20085231475830078125000000000000000E+04, -3.20085231475830078125000000000000000E+04, -4.98734779357910156250000000000000000E+03,  -- 521
         -4.86335157775878906250000000000000000E+03, -2.24993133544921875000000000000000000E+01, -7.83476089477539062500000000000000000E+02,  -- 524
         +7.29977722167968750000000000000000000E+01, -5.19984130859375000000000000000000000E+01, -2.49992370605468750000000000000000000E+00,  -- 527
         +2.49992370605468750000000000000000000E+00, +5.19984130859375000000000000000000000E+01, -7.29977722167968750000000000000000000E+01,  -- 530
         +7.83476089477539062500000000000000000E+02, +2.24993133544921875000000000000000000E+01, +4.86335157775878906250000000000000000E+03,  -- 533
         +4.98734779357910156250000000000000000E+03, +3.20085231475830078125000000000000000E+04, -3.20085231475830078125000000000000000E+04,  -- 536
         -4.98734779357910156250000000000000000E+03, -4.86335157775878906250000000000000000E+03, -2.24993133544921875000000000000000000E+01,  -- 539
         -7.83476089477539062500000000000000000E+02, +7.29977722167968750000000000000000000E+01, -5.19984130859375000000000000000000000E+01,  -- 542
         -2.49992370605468750000000000000000000E+00
      );
      Int_Win_Base : constant Integer_Array(0..256) := (
             0,    -1,    -1,    -1,    -1,    -1,    -1,    -2,    -2,    -2,    -2,    -3,    -3,    -4,    -4,    -5,    -5,    -6,  -- 17
            -7,    -7,    -8,    -9,   -10,   -11,   -13,   -14,   -16,   -17,   -19,   -21,   -24,   -26,   -29,   -31,   -35,   -38,  -- 35
           -41,   -45,   -49,   -53,   -58,   -63,   -68,   -73,   -79,   -85,   -91,   -97,  -104,  -111,  -117,  -125,  -132,  -139,  -- 53
          -147,  -154,  -161,  -169,  -176,  -183,  -190,  -196,  -202,  -208,  -213,  -218,  -222,  -225,  -227,  -228,  -228,  -227,  -- 71
          -224,  -221,  -215,  -208,  -200,  -189,  -177,  -163,  -146,  -127,  -106,   -83,   -57,   -29,     2,    36,    72,   111,  -- 89
           153,   197,   244,   294,   347,   401,   459,   519,   581,   645,   711,   779,   848,   919,   991,  1064,  1137,  1210,  -- 107
          1283,  1356,  1428,  1498,  1567,  1634,  1698,  1759,  1817,  1870,  1919,  1962,  2001,  2032,  2057,  2075,  2085,  2087,  -- 125
          2080,  2063,  2037,  2000,  1952,  1893,  1822,  1739,  1644,  1535,  1414,  1280,  1131,   970,   794,   605,   402,   185,  -- 143
           -45,  -288,  -545,  -814, -1095, -1388, -1692, -2006, -2330, -2663, -3004, -3351, -3705, -4063, -4425, -4788, -5153, -5517,  -- 161
         -5879, -6237, -6589, -6935, -7271, -7597, -7910, -8209, -8491, -8755, -8998, -9219, -9416, -9585, -9727, -9838, -9916, -9959,  -- 179
         -9966, -9935, -9863, -9750, -9592, -9389, -9139, -8840, -8492, -8092, -7640, -7134, -6574, -5959, -5288, -4561, -3776, -2935,  -- 197
         -2037, -1082,   -70,   998,  2122,  3300,  4533,  5818,  7154,  8540,  9975, 11455, 12980, 14548, 16155, 17799, 19478, 21189,  -- 215
         22929, 24694, 26482, 28289, 30112, 31947, 33791, 35640, 37489, 39336, 41176, 43006, 44821, 46617, 48390, 50137, 51853, 53534,  -- 233
         55178, 56778, 58333, 59838, 61289, 62684, 64019, 65290, 66494, 67629, 68692, 69679, 70590, 71420, 72169, 72835, 73415, 73908,  -- 251
         74313, 74630, 74856, 74992, 75038
      );
   begin

      raise Unsupported_Format;

   end Pump_MPEG1L3;


   --------------------------------------------------
   -- IMA/DVI ADPCM Algorithm :
   --------------------------------------------------
   -- NOTE :
   --  This CODEC has been tested to work with
   --  monophonic 2,3,4 and 5 bit compressed files,
   --  produced with CoolEdit-2000. However, when
   --  sterio files are produced by CoolEdit-2000,
   --  only the 4-bit sample files play correctly
   --  here. While CoolEdit-2000 is able to play its
   --  own sterio files, I strongly suspect that the
   --  created files are incorrect. It is suspected
   --  that CoolEdit incorrectly interleaves the
   --  2,3 and 5-bit samples for non-monophonic files.
   --------------------------------------------------
   procedure Pump_IMA_ADPCM(In_Str, Out_Str : Audio_Stream)
   is
      type Audio_Byte_Array is array(Audio_U16 range <>) of Audio_Byte;
      type Audio_I16_Array is array(Audio_U16 range <>) of Audio_I16;
      type Samples_Out_Array is array(Audio_U16 range <>,Audio_U16 range <>) of Audio_I16;

      Bits_Per_Sample :       Audio_U16;      -- Bits per IMA ADPCM Sample
      Block_Size :            Audio_U16;      -- Size of the samples block
      Samples_Per_Block :     Audio_U16;      -- Max # of samples per block
      
      N_Chan :                Audio_U16 := Audio_U16( Channels(In_Str.all) );

      type Hdr_Recd is
         record
            Samp_0 :          Audio_I16;
            Step_Tbl_Index :  Audio_Byte;
            Reserved :        Audio_Byte;
         end record;

      type Hdr_Recd_Array is array(1..N_Chan) of Hdr_Recd;

      type IMA_Recd(Bytes : Audio_U16) is
         record
            Header :          Hdr_Recd_Array;
            Samples :         Audio_Byte_Array(1..Bytes);
         end record;

      Step_Table : constant array(0..Audio_I16(88)) of Audio_U16 := (
         7, 8, 9, 10, 11, 12, 13, 14, 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, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
         2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
         5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
         15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 );
   
      function Step_Index(X : Audio_I16) return Audio_I16 is
      begin

         if X < Step_Table'First then
            return Step_Table'First;
         elsif X > Step_Table'Last then
            return Step_Table'Last;
         else
            return X;
         end if;

      end Step_Index;

      -- Index Tables :

      Idx_Tab2 : constant Audio_I16_Array(0..Audio_U16(3))  := ( -1,  2, -1,  2);
      Idx_Tab3 : constant Audio_I16_Array(0..Audio_U16(7))  := ( -1, -1,  1,  2, -1, -1,  1, 2 );
      Idx_Tab4 : constant Audio_I16_Array(0..Audio_U16(15)) := ( -1, -1, -1, -1,  2,  4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8 );
      Idx_Tab5 : constant Audio_I16_Array(0..Audio_U16(31)) := (-1,-1,-1,-1,-1,-1,-1,-1,1,2,4,6,8,10,13,16,-1,-1,-1,-1,-1,-1,-1,-1,1,2,4,6,8,10,13,16);
    
      -- Bit size specific values :

      Index_Tab : constant array(2..Audio_U16(5)) of Audio_U16   := (  3,  7, 15, 31 ); -- Upper bounds for idx_tab()
      Samps_Tab : constant array(2..Audio_U16(5)) of Audio_U16   := ( 32, 32,  8, 32 ); -- Samples per "data word"
      Bytes_Tab : constant array(2..Audio_U16(5)) of Audio_U16   := (  8, 12,  4, 20 ); -- Bytes per "data word"
      Masks_Tab : constant array(2..Audio_U16(5)) of Audio_U16   := (  3,  7, 15, 31 ); -- Bit mask for each bit size
      Signs_Tab : constant array(2..Audio_U16(5)) of Audio_Byte  := (  2,  4,  8, 16 ); -- Sign mask for each bit size

   begin

      Audio_U16'Read(In_Str,Block_Size);                                      -- Determine the block size
      Audio_U16'Read(In_Str,Bits_Per_Sample);                                 -- Determine bits / sample
      Audio_U16'Read(In_Str,Samples_Per_Block);                               -- Max # of samples per block
      
      declare
         Chan_Wd_Bytes :  Audio_U16 := Bytes_Tab(Bits_Per_Sample) * N_Chan;   -- # of bytes needed to satisfy all channels for 1 "data word"
         N_Samps :        Audio_U16 := 0;                                     -- # of samples in the current block
         Sign :           Audio_Byte := Signs_Tab(Bits_Per_Sample);           -- Sign bit mask
         Step_X :         Audio_I16_Array(1..N_Chan);                         -- Step table index
         Idx_Tab :        Audio_I16_Array(0..Index_Tab(Bits_Per_Sample));     -- index table
         Bytes_Avail :    Audio_U16 := 0;                                     -- Bytes available to read
         Sample_Bytes :   Audio_U16 := 0;                                     -- Bytes available for samples
         X :              Audio_I16;                                          -- Current Index value
         Samp_0 :         Audio_I16;                                          -- Prior sample
         A_Bits :         Audio_U16 := 0;                                     -- Bits held in Acc
         Mask :           Audio_U16 := Masks_Tab(Bits_Per_Sample);            -- Bit mask for sample delta
         Acc :            Audio_U16 := 0;                                     -- Bit accumulator
         Wd_Samps :       Audio_U16 := Samps_Tab(Bits_Per_Sample);            -- Samples / "data word"
         Samp_Delta :     Audio_Byte := 0;                                    -- Sample Delta
         Step :           Audio_U16;                                          -- Current step value
         Diff :           Audio_I32 := 0;                                     -- Computed difference
         Samp_X :         Audio_I32 := 0;                                     -- New Sample X
      begin

         case Bits_Per_Sample is
            when 2 =>
               Idx_Tab := Idx_Tab2;       -- 2 bit table
            when 3 =>
               Idx_Tab := Idx_Tab3;       -- 3 bit table
            when 4 =>
               Idx_Tab := Idx_Tab4;       -- 4 bit table
            when 5 =>
               Idx_Tab := Idx_Tab5;       -- 5 bit table
            when others =>
               raise Program_Error;
         end case;

         loop
            Bytes_Avail := Audio_U16(In_Items(In_Str.all,1));
            if Bytes_Avail > Block_Size then
               Bytes_Avail := Block_Size;
            end if;

            exit when Bytes_Avail <= 4 * N_Chan;         -- Exit if we don't have enough for a header

            Sample_Bytes := Bytes_Avail - 4 * N_Chan;    -- Compute the bytes available for samples

            exit when Sample_Bytes < 4;                  -- Exit when no sample bytes exist

            N_Samps := ((Bytes_Avail - (4 * N_Chan)) * 8) / ( Bits_Per_Sample * N_Chan ) + 1;

            if N_Samps > Samples_Per_Block then
               N_Samps := Samples_Per_Block;
            end if;

            declare
               BX :     Audio_U16 := 1;                  -- Index into Block.Samples(BX)
               SX :     Audio_U16 := 2;                  -- Sample Index (1st sample comes from header)
               Block :  IMA_Recd(Sample_Bytes);          -- IMA ADPCM Block
               Emit :   Samples_Out_Array(1..N_Samps,1..N_Chan);
            begin

               IMA_Recd'Read(In_Str,Block);              -- Read in the block

               -- Force bad data to not exceed array bounds 

               for X in Block.Header'Range loop
                  Emit(1,X) := Block.Header(X).Samp_0;   -- First sample for channel X
                  Step_X(X) := Step_Index( Audio_I16(Block.Header(X).Step_Tbl_Index) );
               end loop;

               -- The remaining bytes is the data portion :

               loop
                  exit when SX + 1 > N_Samps;            -- Exit when all samples have been processed

                  -- Check if this is a short "last block" :

                  if Sample_Bytes + 1 - BX < Chan_Wd_Bytes then
                     for FX in SX..Emit'Last(1) loop     -- Fill all remaining samples..
                        for Chx in Emit'Range(2) loop    -- for all channels..
                           Emit(FX,Chx) := Block.Header(Chx).Samp_0; -- with the last generated sample
                        end loop;
                     end loop;
                     exit;
                  end if;

                  for Chx in 1..N_Chan loop              -- For all channels

                     X := Step_X(Chx);                   -- Get Step_Table index for this channel
                     Samp_0 := Block.Header(Chx).Samp_0; -- Previous sample
                     A_Bits := 0;                        -- No sample bits in acc yet

                     for PX in 1..Wd_Samps loop          -- for all samples in a "data word"
                        if A_Bits < Bits_Per_Sample then
                           if A_Bits = 0 then
                              Acc := Audio_U16( Block.Samples(BX) );
                           else
                              Acc := Acc or Shift_Left( Audio_U16( Block.Samples(BX) ), Natural(A_Bits) );
                           end if;
                           A_Bits := A_Bits + 8;
                           BX := BX + 1;
                        end if;
                        
                        Samp_Delta := Audio_Byte( Acc and Mask );           -- Extract a delta (n-bits)
                        Acc := Shift_Right(Acc,Natural(Bits_Per_Sample));   -- Shift out used up delta bits
                        A_Bits := A_Bits - Bits_Per_Sample;                 -- Now have fewer bits in Acc

                        Step := Step_Table(X);                              -- Get current step value
                        Diff := Audio_I32( Shift_Right(Step,Natural(Bits_Per_Sample-1)) );

                        for Z in 1..Bits_Per_Sample loop
                           if ( Samp_Delta and Shift_Right(Audio_U8(Sign),Natural(Z)) ) /= 0 then
                              Diff := Diff + Audio_I32( Shift_Right(Step,Natural(Z-1)) );
                           end if;
                        end loop;
                        
                        if ( Samp_Delta and Sign ) /= 0 then   -- Test delta sign
                           Diff := -Diff;                      -- Make the delta negative
                        end if;

                        -- Compute the next sample based upon the difference

                        Samp_X := Audio_I32(Samp_0) + Diff;    -- prior + delta

                        if Samp_X > 32767 then                 -- Range clamping..
                           Samp_X := 32767;
                        elsif Samp_X < -32768 then
                           Samp_X := -32768;
                        end if;

                        Emit(SX+PX-1,Chx) := Audio_I16( Samp_X );    -- Save for later write to Out_Str

                        X := Step_Index( X + Idx_Tab(Audio_U16(Samp_Delta)) );
                        Samp_0 := Audio_I16(Samp_X);                 -- Current sample becomes previous sample
                     end loop; -- End "data word"

                     Step_X(Chx) := X;                               -- Save index
                     Block.Header(Chx).Samp_0 := Samp_0;             -- Save previous sample
                  end loop; -- for all channels
                        
                  SX := SX + Wd_Samps;                               -- # of samples created in inner loop from a "data word"

               end loop; -- for all samples to be decompressed

               Samples_Out_Array'Write(Out_Str,Emit);                -- Write all decompressed samples to out stream
            end; -- for samples within the current IMA ADPCM block
         end loop; -- for all available bytes of data            
      end;

   end Pump_IMA_ADPCM;

   --------------------------------------------------
   -- Microsoft ADPCM :
   --------------------------------------------------
   procedure Pump_MS_ADPCM(In_Str, Out_Str : Audio_Stream)
   is
      Chans :                  Audio_U16 := Audio_U16(Channels(In_Str.all)); -- # of Audio Channels

      type Samples_Out_Array is array(Audio_U16 range <>,Audio_U16 range <>) of Audio_I16;
      type Audio_Byte_Array is array(Audio_U16 range <>) of Audio_Byte;
      type Audio_I16_Array is array(Audio_U16 range <>) of Audio_I16;

      type Coef_Set is 
         record 
            Coef1 :        Audio_I16;  -- ADPCM coefficient 1
            Coef2 :        Audio_I16;  -- ADPCM coefficient 2
         end record; 

      type Coef_Set_Array is array (Audio_U16 range <>) of Coef_Set;

      type Block_Hdr(Chans : Audio_U16) is
         record
            Predictor :    Audio_Byte_Array(1..Chans);
            Init_Delta :   Audio_I16_Array(1..Chans);
            Sample_1 :     Audio_I16_Array(1..Chans);
            Sample_2 :     Audio_I16_Array(1..Chans);
         end record;

      type ADPCM_Block(Chans, Sample_Bytes : Audio_U16) is
         record
            Header :       Block_Hdr(Chans);
            Samples :      Audio_Byte_Array(1..Sample_Bytes);
         end record;

      type Chan_Info_Type is
         record
            Predictor :    Audio_U16;      -- From Block_Hdr
            Init_Delta :   Audio_I32;
            Sample_1 :     Audio_I16;
            Sample_2 :     Audio_I16;
            Coef1 :        Audio_I16;      -- Coefficients..
            Coef2 :        Audio_I16;
         end record;

      type Chan_Info_Array is array(1..Chans) of Chan_Info_Type;

      ------------------------------------------------------------
      function Sample_Bytes(Block_Bytes : Audio_U16) return Audio_U16 is
      begin
         if Block_Bytes < 7 * Chans then
            return 0;           -- No samples in this block
         end if;
         return Block_Bytes - 7 * Chans;     -- This does not include the initial 2 samples!
      end Sample_Bytes;
      ------------------------------------------------------------

      Fixed_Point_Coef_Base :      constant Audio_I32 := 256;
      Fixed_Point_Adaption_Base :  constant Audio_I32 := 256;
      Min_Delta :                  constant Audio_I32 :=  16;

      Adaption_Table : constant array(-8..Audio_I32(7)) of Audio_I32 := (
         768, 614, 512, 409, 307, 230, 230, 230,         -- Adaption Table constants
         230, 230, 230, 230, 307, 409, 512, 614
      );

      Block_Size :         Audio_U16;              -- ADPCM Block size
      Bits_Per_ADPCM :     Audio_U16;              -- Often provided as zero, but should be 4
      Samples_Per_Block :  Audio_U16;              -- # of samples per ADPCM block
      Sample_Length :      Audio_U32;              -- # of samples in this file
      Num_Coef :           Audio_U16;              -- # of Coefficients

    begin

      Audio_U16'Read(In_Str,Block_Size);           -- Fetch the block size
      Audio_U16'Read(In_Str,Bits_Per_ADPCM);       -- Often given as zero, but should be 4
      Audio_U16'Read(In_Str,Samples_Per_Block);    -- # of samples per block
      Audio_U32'Read(In_Str,Sample_Length);        -- Sample length of this "play"
      Audio_U16'Read(In_Str,Num_Coef);             -- Read the number of coefficients

      if Num_Coef > 256 then
         raise Program_Error;
      end if;

      declare
         Byte_Count :   Audio_U16 := 0;            -- Bytes available to read
         Samp_Bytes :   Audio_U16 := 0;            -- Bytes available as sample data within the block
         Coef :         Coef_Set_Array(1..Num_Coef); -- Coefficient set
         Pred_Samp :    Audio_I32;                 -- Predicted Sample
         Edelta :       Audio_I32;                 -- Input ADPCM error delta
         New_Delta :    Audio_I32;                 -- New iDelta
         New_Sampl :    Audio_I32;                 -- New generated 16-bit PCM sample
      begin

         Coef_Set_Array'Read(In_Str,Coef);         -- Read in the Coefficients

         loop
            --------------------------------------------------
            -- Determine if the next ADPCM Block is a partial
            --------------------------------------------------
            Byte_Count := Audio_U16(In_Items(In_Str.all,1)); -- How many incoming bytes are available?
            if Byte_Count > Block_Size then
               Byte_Count := Block_Size;           -- Use regular block size
            end if;
            Samp_Bytes := Sample_Bytes(Byte_Count); -- How many bytes after the block header?

            exit when Samp_Bytes < 1;              -- Exit when there is no more data to process

            --------------------------------------------------
            -- Allow For The Last Partial ADPCM Block :
            --------------------------------------------------
            declare
               Fetch :      Boolean := True;       -- Nibble fetching state
               Byte :       Audio_U8;              -- Current byte
               Nibble :     Audio_U8;              -- Current nibble

               Info :       Chan_Info_Array;       -- Extra Channel state info
               N_Samps :    Audio_U16 := ( Samp_Bytes * 8 ) / ( 4 * Chans ) + 2; -- Includes the initial 2 samples
               Smpc :       Audio_U16 := 2;                                      -- Sample count including the initial 2
               Out_Samps :  Samples_Out_Array(1..N_Samps,1..Chans);              -- Buffer for output samples
               Block :      ADPCM_Block(Chans,Samp_Bytes);                       -- Precisely sized block
               SX :         Audio_U16 := Block.Samples'First;                    -- Sample Index into Block.Samples() array
            begin

               ADPCM_Block'Read(In_Str,Block);     -- Read the ADPCM Block

               --------------------------------------------------
               -- Initialize predictors, coefficients etc. :
               --------------------------------------------------
               for X in Block.Header.Predictor'range loop
                  Info(X).Predictor := Audio_U16(Block.Header.Predictor(X)) + Coef'First;

                  Info(X).Init_Delta := Audio_I32( Block.Header.Init_Delta(X) );
                  Info(X).Sample_1 := Block.Header.Sample_1(X);
                  Info(X).Sample_2 := Block.Header.Sample_2(X);

                  Info(X).Coef1 := Coef(Info(X).Predictor).Coef1;
                  Info(X).Coef2 := Coef(Info(X).Predictor).Coef2;

                  Out_Samps(1,X) := Block.Header.Sample_2(X);
                  Out_Samps(2,X) := Block.Header.Sample_1(X);
               end loop;

               --------------------------------------------------
               -- Decompress all samples in this block :
               --------------------------------------------------
               loop
                  exit when Smpc >= N_Samps;

                  for X in Info'Range loop         -- For all channels

                     -- Predict the next sample :
                     Pred_Samp := ( Audio_I32( Info(X).Sample_1 ) * Audio_I32( Info(X).Coef1 )
                        + Audio_I32( Info(X).Sample_2 ) * Audio_I32( Info(X).Coef2 ) ) / Fixed_Point_Coef_Base;

                     if Fetch then                 -- Fetch the error delta out of the Block.Samples array
                        Byte := Block.Samples(SX); -- Current byte
                        Nibble := Shift_Right(Byte,4); -- Current nibble
                     else
                        Nibble := Byte and 16#0F#; -- Least significant nibble
                        SX := SX + 1;
                     end if;

                     Fetch := Fetch xor True;      -- Two nibbles to every byte

                     if ( Nibble and 16#08# ) = 0 then
                        Edelta := Audio_I32( Nibble );
                     else
                        Edelta := -Audio_I32( 8 - (Nibble and 7) );
                     end if;

                     New_Sampl := Pred_Samp + Info(X).Init_Delta * Edelta;

                     if New_Sampl > 32767 then
                        New_Sampl := 32767;        -- Fix overly positive sample value
                     elsif New_Sampl < -32768 then
                        New_Sampl := -32768;       -- Fix overly negative sample value
                     end if;
                     
                     Out_Samps(Smpc+1,X) := Audio_I16( New_Sampl );

                     New_Delta := ( Info(X).Init_Delta * Adaption_Table(Edelta) ) / Fixed_Point_Adaption_Base;

                     if New_Delta < Min_Delta then
                        Info(X).Init_Delta := Min_Delta; -- Fix overly negative delta
                     else
                        Info(X).Init_Delta := New_Delta; -- Else save OK delta
                     end if;

                     Info(X).Sample_2 := Info(X).Sample_1;        -- N-1 sample becomes N-2 sample
                     Info(X).Sample_1 := Audio_I16( New_Sampl );  -- New sample becomes N-1 sample
                  end loop; -- for all channels

                  Smpc := Smpc + 1;

               end loop; -- for all samples in the block

               Samples_Out_Array'Write(Out_Str,Out_Samps);        -- Write expanded samples to output stream

            end; -- end of the current ADPCM block
         end loop; -- end of all samples to play
      end;

   end Pump_MS_ADPCM;

   --------------------------------------------------
   -- Process CODEC_Mulaw :
   --------------------------------------------------
   procedure Pump_Mulaw(In_Str, Out_Str : Audio_Stream)
   is
      type Audio_Byte_Array is array(Positive range <>) of Audio_Byte;
      type Audio_I16_Array is array(Positive range <>) of Audio_I16;

      Sign_Bit :   constant Audio_Byte     := 16#80#;    -- Sign bit for a A-law byte
      Quant_Mask : constant Audio_Byte     := 16#0F#;    -- Quantization field mask
      Nsegs :      constant Unsigned_16    := 8;         -- Number of A-law segments
      Seg_Mask :   constant Audio_Byte     := 16#70#;    -- Segment field mask.
      Seg_Shift :  constant Natural        := 4;         -- Left shift for segment number
      Bias :       constant Audio_I16      := 16#0084#;  -- Bias for linear code
    
      Sample_Count : Positive;
      U_Val :      Audio_Byte;      -- Byte from input stream
      T :          Unsigned_16;     -- Temp
      Shft :       Unsigned_8;      -- Shift count

   begin

      loop
         Sample_Count := In_Items(In_Str.all,1);
         declare
            In_Samples :   Audio_Byte_Array(1..Sample_Count);
            Out_Samples :  Audio_I16_Array(In_Samples'Range);
         begin

            Audio_Byte_Array'Read(In_Str,In_Samples);

            for X in In_Samples'Range loop
               U_Val := not In_Samples(X);
               T := Shift_Left(Unsigned_16(U_Val and Quant_Mask),3) + Unsigned_16(Bias);

               Shft := Shift_Right(Unsigned_8(U_Val and Seg_Mask),Seg_Shift);
               if Shft > 0 then
                  T := Shift_Left(T,Natural(Shft));
               end if;

               if ( U_Val and Sign_Bit ) = Sign_Bit then
                  Out_Samples(X) := Bias - Audio_I16(T);
               else
                  Out_Samples(X) := Audio_I16(T) - Bias;
               end if;
            end loop;

            Audio_I16_Array'Write(Out_Str,Out_Samples);

         exception
            when Ada.IO_Exceptions.End_Error =>
               exit;
         end;
      end loop;

   end Pump_Mulaw;

   --------------------------------------------------
   -- Pump Alaw 8-Bit Samples :
   --------------------------------------------------
   procedure Pump_Alaw_8(In_Str, Out_Str : Audio_Stream)
   is
      type Audio_Byte_Array is array(Positive range <>) of Audio_Byte;
      type Audio_I16_Array is array(Positive range <>) of Audio_I16;

      Sign_Bit :     constant Audio_Byte  := 16#80#;     -- Sign bit for a A-law byte
      Quant_Mask :   constant Audio_Byte  := 16#000F#;   -- Quantization field mask
      Nsegs :        constant Unsigned_16 := 8;          -- Number of A-law segments
      Seg_Mask :     constant Audio_byte  := 16#70#;     -- Segment field mask.
      Seg_Shift :    constant Natural     := 4;          -- Left shift for segment number (t >> 4) in C

      Sample_Count : Positive;
      A_Val :        Audio_Byte;          -- A value
      T :            Unsigned_16;         -- temp
      Seg :          Natural;             -- segment

   begin

      loop
         Sample_Count := In_Items(In_Str.all,1);
         declare
            In_Samples :   Audio_Byte_Array(1..Sample_Count);
            Out_Samples :  Audio_I16_Array(In_Samples'Range);
         begin

            Audio_Byte_Array'Read(In_Str,In_Samples);

            for X in In_Samples'Range loop
               A_Val := In_Samples(X) xor Audio_Byte(16#55#);
               T := Shift_Left(Unsigned_16(A_Val and Quant_Mask),4);
               Seg := Natural(Shift_Right(Unsigned_16(A_Val and Seg_Mask),Seg_Shift));

               case Seg is
                  when 0 =>
                     T := T + 8;
                  when 1 =>
                     T := T + 16#0108#;
                  when others =>
                     T := T + 16#0108#;
                     if Seg > 1 then
                        T := Shift_Left(T,Seg-1);
                     end if;
               end case;
            
               if ( A_Val and Sign_Bit ) /= 0 then
                  Out_Samples(X) := -Audio_I16(T);
               else
                  Out_Samples(X) := Audio_I16(T);
               end if;
            end loop;

            Audio_I16_Array'Write(Out_Str,Out_Samples);
         exception
            when Ada.IO_Exceptions.End_Error =>
               exit;
         end;
      end loop;

   end Pump_Alaw_8;

   --------------------------------------------------
   -- Pump Signed 8-bit Samples to Output :
   --------------------------------------------------
   procedure Pump_PCM_8(In_Str, Out_Str : Audio_Stream)
   is
      type Audio_Signed_Array is array(Positive range <>) of Audio_Signed;
      type Audio_Byte_Array is array(Positive range <>) of Audio_Byte;

      Sample_Count :   Positive;       -- Sample Count
   begin

      loop
         Sample_Count := In_Items(In_Str.all,1);

         declare
            In_Samples :  Audio_Signed_Array(1..Sample_Count);
            Out_Samples : Audio_Byte_Array(In_Samples'Range);
         begin
            Audio_Signed_Array'Read(In_Str,In_Samples);
      
            for X in In_Samples'Range loop
               Out_Samples(X) := Audio_Byte( 128 + Integer_16( In_Samples(X) ) );
            end loop;
      
            Audio_Byte_Array'Write(Out_Str,Out_Samples);
         exception
            when Ada.IO_Exceptions.End_Error =>
               exit;
         end;
      end loop;

   end Pump_PCM_8;

   --------------------------------------------------
   -- Pump Unsigned 8-bit Samples to Output :
   --------------------------------------------------
   procedure Pump_PCM_U8(In_Str, Out_Str : Audio_Stream)
   is
      type Audio_Signed_Array is array(Positive range <>) of Audio_Signed;
      type Audio_Byte_Array is array(Positive range <>) of Audio_Byte;

      Sample_Count :       Positive;       -- Sample count
   begin

      loop    -- Process groups of samples
         Sample_Count := In_Items(In_Str.all,1);

         declare
            Samples :  Audio_Byte_Array(1..Sample_Count);
         begin
            Audio_Byte_Array'Read(In_Str,Samples);
            Audio_Byte_Array'Write(Out_Str,Samples);
         exception
            when Ada.IO_Exceptions.End_Error =>
               exit;
         end;
      end loop;

   end Pump_PCM_U8;

   --------------------------------------------------
   -- Pump Signed 16-bit Samples to Output :
   --------------------------------------------------
   procedure Pump_PCM_16(In_Str, Out_Str : Audio_Stream)
   is
      type Audio_I16_Array is array(Positive range <>) of Audio_I16;

      Sample_Count :   Positive;
   begin

      loop
         Sample_Count := In_Items(In_Str.all,2);

         declare
            Samples :  Audio_I16_Array(1..Sample_Count);
         begin
            Audio_I16_Array'Read(In_Str,Samples);
            Audio_I16_Array'Write(Out_Str,Samples);
         exception
            when Ada.IO_Exceptions.End_Error =>
               exit;
         end;
      end loop;

   end Pump_PCM_16;

   --------------------------------------------------
   -- Pump Signed 24-bit Samples to Output :
   --------------------------------------------------
   procedure Pump_PCM_24(In_Str, Out_Str : Audio_Stream)
   is
      Sample :  Audio_I24;
   begin

      loop
         begin
            Audio_I24'Read(In_Str,Sample);
         exception
            when Ada.IO_Exceptions.End_Error =>
               exit;
         end;

         Audio_I24'Write(Out_Str,Sample);
      end loop;

   end Pump_PCM_24;

   --------------------------------------------------
   -- Pump Signed 32-bit Samples to Output :
   --------------------------------------------------
   procedure Pump_PCM_32(In_Str, Out_Str : Audio_Stream)
   is
      Sample :     Audio_I32;
   begin

      loop
         begin
            Audio_I32'Read(In_Str,Sample);
         exception
            when Ada.IO_Exceptions.End_Error =>
               exit;
         end;
         Audio_I32'Write(Out_Str,Sample);
      end loop;

   end Pump_PCM_32;

   --------------------------------------------------
   -- Pump the Input Stream to the Output Stream :
   --------------------------------------------------
   procedure Pump(In_Str, Out_Str : Audio_Stream)
   is
      Chans :        Audio_Channels;      -- # of audio channels
      Samp_Rate :    Audio_Sample_Rate;   -- Sample rate in samples / second
      Samp_Size :    Audio_Sample_Size;   -- Sample size in bits
      Samp_Type :    Audio_Sample_Type;   -- Sample Data Format
   begin

      -- Determine the input sample parameters :

      Chans     := Channels(In_Str.all);
      Samp_Rate := Sample_Rate(In_Str.all);
      Samp_Size := Sample_Size(In_Str.all);
      Samp_Type := Sample_Type(In_Str.all);

      -- Configure the output device parameters :

      Set_Channels(Out_Str.all,Chans);
      Set_Sample_Rate(Out_Str.all,Samp_Rate);

      -- Choose the CODEC for the input Sample Format :

      case Samp_Type is
         when CODEC_Linear_U8 =>
            Set_Sample_Size(Out_Str.all,Samp_Size);
            Pump_PCM_U8(In_Str,Out_Str);
         when CODEC_Linear_8 =>  -- Linear 8-bit samples
            Set_Sample_Size(Out_Str.all,Samp_Size);
            Pump_PCM_8(In_Str,Out_Str);
         when CODEC_Linear_16 =>     -- Linear 16-bit samples
            Set_Sample_Size(Out_Str.all,Samp_Size);
            Pump_PCM_16(In_Str,Out_Str);
         when CODEC_Linear_24 =>
            Set_Sample_Size(Out_Str.all,Samp_Size);
            Pump_PCM_24(In_Str,Out_Str);
         when CODEC_Linear_32 =>
            Set_Sample_Size(Out_Str.all,Samp_Size);
            Pump_PCM_32(In_str,Out_Str);
         when CODEC_Mulaw =>
            Set_Sample_Size(Out_Str.all,16);
            Pump_Mulaw(In_Str,Out_Str);
         when CODEC_Alaw_8 =>
            Set_Sample_Size(Out_Str.all,16);
            Pump_Alaw_8(In_Str,Out_Str);
         when CODEC_MS_ADPCM =>
            Set_Sample_Size(Out_Str.all,16);
            Pump_MS_ADPCM(In_Str,Out_Str);
         when CODEC_IMA_ADPCM =>
            Set_Sample_Size(Out_Str.all,16);
            Pump_IMA_ADPCM(In_Str,Out_Str);
         when others =>
            raise Unsupported_Format;
      end case;

   end Pump;

end WC.Streams.Codec;
