home *** CD-ROM | disk | FTP | other *** search
/ The Devil's Doorknob BBS Capture (1996-2003) / devilsdoorknobbbscapture1996-2003.iso / Dloads / UTILITIE / VOCSHO.ZIP / VOC_IO.PKG < prev    next >
Text File  |  1991-01-07  |  12KB  |  364 lines

  1. package body VOC_IO is
  2.   use voc_data;
  3.   pragma Optimize(Time);
  4.  
  5.   type One_Byte_Naturals is range 0 .. 255;
  6.    for One_Byte_Naturals'Size use 8;
  7.   type Two_Byte_Naturals is range 0 .. 65535;
  8.    for Two_Byte_Naturals'Size use 16;
  9.  
  10.   type file_type_descriptions is array(0 .. 16#13#) of one_byte_naturals;
  11.  
  12.   type Headers is record
  13.     File_Type_Description : file_type_descriptions;
  14.     Offset_Of_Data_Block  : dos_io.byte_counts;
  15.     version_minor         : one_byte_naturals;
  16.     version_major         : one_byte_naturals;
  17.     id_code_minor         : one_byte_naturals;
  18.     id_code_major         : one_byte_naturals;
  19.   end record;
  20.  
  21.   Headers_Bytes:constant Dos_IO.Byte_Counts
  22.     :=Dos_IO.Byte_Counts(Headers'Size/8);
  23.  
  24.   type block_headers is record
  25.     block_type : block_types;
  26.     blklen     : blklens;
  27.   end record;
  28.  
  29.   block_header_length:constant:=4;
  30.  
  31.   function "-" (Left,
  32.                 Right   : in     Dos_IO.Byte_Counts)
  33.     return Dos_IO.Byte_Counts renames Dos_IO."-";
  34.  
  35.   function "=" (Left,
  36.                 Right   : in     Dos_IO.Byte_Counts)
  37.     return Boolean renames Dos_IO."=";
  38.  
  39.   function ">" (Left,
  40.                 Right   : in     Dos_IO.Byte_Counts)
  41.     return Boolean renames Dos_IO.">";
  42.  
  43.   procedure Open(Name    : in     String;
  44.                  Handle  : in out Handles) is
  45.     Header  : Headers;
  46.   begin
  47.     begin
  48.       Dos_IO.Open(Name, Handle.File_Handle);
  49.     exception
  50.       when dos_io.name_error => raise name_error;
  51.     end;
  52.     handle.is_input:=true;
  53.     if Dos_IO.Read(Handle.File_Handle, Header'Address, Headers_Bytes)
  54.        /= Headers_Bytes then
  55.       Dos_IO.Close(Handle.File_Handle);
  56.       raise Data_Error;
  57.     end if;
  58.     if 16#12#-header.version_major /= header.id_code_major then
  59.       raise data_error;
  60.     end if;
  61.     if 16#33#-header.version_minor /= header.id_code_minor then
  62.       raise data_error;
  63.     end if;
  64.     if header.offset_of_data_block /= headers_bytes then
  65.       Dos_IO.Skip(Handle.File_Handle,
  66.                   headers_bytes-header.offset_of_data_block);
  67.     end if;
  68.     handle.voice_info:=(voice_to_continue=>false);
  69.   end Open;
  70.  
  71.   procedure Read(Handle  : in out Handles;
  72.                  block   :    out VOC_data.blocks) is
  73.     this_type    : VOC_data.block_types;
  74.     block_length : VOC_data.block_lengths;
  75.     sample_rate  : VOC_data.sample_rates;
  76.     null_byte    : one_byte_naturals;
  77.     blklen       : blklens;
  78.     function this_length return blklens is
  79.       blklen:blklens;
  80.     begin
  81.       blklen:=0;  -- zero out 4th allocated byte, assume Intel format
  82.       if dos_io.read(handle.file_handle,blklen'address,3) /= 3 then
  83.         raise Status_Error;
  84.       end if;
  85.       return blklen;
  86.     end this_length;
  87.     function this_rate return voc_data.sample_rates is
  88.       type srs is range 0 .. 255;
  89.        for srs'size use 8;
  90.       sr:srs;
  91.     begin
  92.       if dos_io.read(handle.file_handle,sr'address,1) /= 1 then
  93.         raise Status_Error;
  94.       end if;
  95.       return voc_data.sample_rates(1000000/(256-long_integer(sr)));
  96.     end this_rate;
  97.     function this_pack return voc_data.pack_types is
  98.       type packs is range 0 .. 255;
  99.        for packs'size use 8;
  100.       pack:packs;
  101.     begin
  102.       if dos_io.read(handle.file_handle,pack'address,1) /= 1 then
  103.         raise Status_Error;
  104.       end if;
  105.       return voc_data.pack_types'val(pack);
  106.     end this_pack;
  107.     function this_2 return two_byte_naturals is
  108.       n:two_byte_naturals;
  109.     begin
  110.       if dos_io.read(handle.file_handle,n'address,2) /= 2 then
  111.         raise Status_Error;
  112.       end if;
  113.       return n;
  114.     end this_2;
  115.     procedure get_sound is
  116.       chunk_length:dos_io.byte_counts;
  117.     begin
  118.       if handle.voice_info.remaining_length > blklens(max_sound_length) then
  119.         chunk_length:=dos_io.byte_counts(max_sound_length);
  120.       else
  121.         chunk_length:=dos_io.byte_counts(handle.voice_info.remaining_length);
  122.       end if;
  123.       block:=(voice_data,integer(chunk_length),
  124.               handle.voice_info.sample_rate,
  125.               handle.voice_info.packing,
  126.               data=>(others=>0));
  127.       if dos_io.read(handle.file_handle,block.data(1)'address,
  128.                      chunk_length) /= chunk_length then
  129.         raise data_error;
  130.       end if;
  131.       handle.voice_info.remaining_length
  132.         :=handle.voice_info.remaining_length-blklens(chunk_length);
  133.     end get_sound;
  134.   begin
  135.     if not handle.is_input then
  136.       raise status_error;
  137.     end if;
  138.     if handle.terminated then
  139.       block:=(terminator,0);
  140.       return;
  141.     end if;
  142.     if not Dos_IO.Is_Open(Handle.File_Handle) then
  143.       raise Status_Error;
  144.     end if;
  145.     if handle.voice_info.voice_to_continue and then
  146.        handle.voice_info.remaining_length > 0 then
  147.       get_sound;
  148.       return;
  149.     end if;
  150.     if dos_IO.read(handle.file_handle,this_type'address,1) /= 1 then
  151.       raise data_error;
  152.     end if;
  153.     case this_type is
  154.       when terminator =>
  155.         handle.terminated:=true;
  156.         block:=(terminator,0);
  157.       when voice_data =>
  158.         blklen:=this_length-2;
  159.         sample_rate:=this_rate;
  160.         handle.voice_info:=(voice_to_continue=>true,
  161.                             sample_rate=>sample_rate,
  162.                             packing=>this_pack,
  163.                             remaining_length=>blklen);
  164.         get_sound;
  165.       when voice_continuation =>
  166.         if not handle.voice_info.voice_to_continue then
  167.           raise data_error;
  168.         end if;
  169.         handle.voice_info.remaining_length:=this_length;
  170.         get_sound;
  171.       when silence =>
  172.         if this_length /= 3 then
  173.           raise data_error;
  174.         end if;
  175.         block:=(silence,0,(duration(this_2)+1.0)/this_rate);
  176.       when marker =>
  177.         if this_length /= 2 then
  178.           raise data_error;
  179.         end if;
  180.         block:=(block_type=>marker,block_length=>0,mark=>markers(this_2));
  181.       when text =>
  182.         block_length:=block_lengths(this_length-1);
  183.         block:=(text,block_length,text_string=>(others=>' '));
  184.         if dos_io.read(handle.file_handle,block.text_string(1)'address,
  185.                        dos_io.byte_counts(block_length))
  186.             /= dos_io.byte_counts(block_length) then
  187.           raise data_error;
  188.         end if;
  189.         if dos_io.read(handle.file_handle,null_byte'address,1) /= 1
  190.         or else null_byte /= 0 then
  191.           raise data_error;
  192.         end if;
  193.       when start_repeat =>
  194.         if this_length /= 2 then
  195.           raise data_error;
  196.         end if;
  197.         block:=(start_repeat,0,voc_data.repeat_counts(this_2));
  198.       when end_repeat =>
  199.         if this_length /= 0 then
  200.           raise data_error;
  201.         end if;
  202.         block:=(end_repeat,0);
  203.     end case;
  204.   end Read;
  205.  
  206.   procedure Create(Name   : in     String;
  207.                    Handle : in out Handles) is
  208.     header:headers:=
  209.       (File_Type_Description => (others => 16#1A#),
  210.        Offset_Of_Data_Block  => headers_bytes,
  211.        version_minor         => 10,
  212.        version_major         => 1,
  213.        id_code_minor         => 16#29#,
  214.        id_code_major         => 16#11#
  215.       );
  216.     magic_name:constant string:="Creative Voice File";
  217.   begin
  218.     for i in magic_name'range loop
  219.       header.file_type_description(i-magic_name'first
  220.                                     +header.file_type_description'first)
  221.         :=character'pos(magic_name(i));
  222.     end loop;
  223.     begin
  224.       dos_io.create(name,handle.file_handle);
  225.     exception
  226.       when dos_io.name_error => raise name_error;
  227.     end;
  228.     handle.is_input:=false;
  229.     if Dos_IO.write(Handle.File_Handle, Header'Address, Headers_Bytes)
  230.        /= Headers_Bytes then
  231.       Dos_IO.Close(Handle.File_Handle);
  232.       raise disk_full;
  233.     end if;
  234.   end create;
  235.  
  236.   procedure write_block_header(Handle     : in out Handles;
  237.                                block_type : in     block_types;
  238.                                blklen     : in     blklens) is
  239.     block_header:block_headers:=(block_type,blklen);
  240.   begin
  241.     if Dos_IO.write(Handle.File_Handle,block_header'Address,
  242.                     block_header_length) /= block_header_length then
  243.       raise disk_full;
  244.     end if;
  245.   end write_block_header;
  246.  
  247.   procedure Write_sound(Handle  : in out Handles;
  248.                         block   : in     VOC_data.blocks) is
  249.     type infos is record
  250.       sr     : one_byte_naturals;
  251.       pack   : pack_types;
  252.     end record;
  253.     info:infos:=(one_byte_naturals(256-1000000/long_integer(block.sample_rate)),
  254.                  block.packing);
  255.     sound_length:constant dos_io.byte_counts
  256.       :=dos_io.byte_counts(block.block_length);
  257.   begin
  258.     if handle.is_input then
  259.       raise status_error;
  260.     end if;
  261.     if block.block_type /= voice_data then
  262.       raise data_error;
  263.     end if;
  264.     write_block_header(Handle,voice_data,blklens(block.block_length+2));
  265.     if dos_io.write(Handle.File_Handle,info'address,2) /= 2 then
  266.       raise disk_full;
  267.     end if;
  268.     if dos_io.write(Handle.File_Handle,block.data(1)'address,sound_length)
  269.        /= sound_length then
  270.       raise disk_full;
  271.     end if;
  272.   end write_sound;
  273.  
  274.   procedure Write_silence(Handle      : in out Handles;
  275.                           interval    : in duration;
  276.                           sample_rate : in VOC_data.sample_rates:=8000) is
  277.     type infos is record
  278.       period : two_byte_naturals;
  279.       sr     : one_byte_naturals;
  280.     end record;
  281.     period:two_byte_naturals:=two_byte_naturals(sample_rate*interval);
  282.     info:infos;
  283.     info_length:constant dos_io.byte_counts:=dos_io.byte_counts(info'size/8);
  284.   begin
  285.     if handle.is_input then
  286.       raise status_error;
  287.     end if;
  288.     if period < 1 then return;end if;
  289.     info:=(period-1,
  290.            one_byte_naturals(256-1000000/long_integer(sample_rate)));
  291.     write_block_header(handle,silence,3);
  292.     if Dos_IO.write(Handle.File_Handle,info'Address,info_length)
  293.        /= info_length then
  294.       raise disk_full;
  295.     end if;
  296.   end write_silence;
  297.  
  298.   procedure Write_marker(Handle  : in out Handles;
  299.                          mark    : in     VOC_data.markers) is
  300.     m_length:constant dos_io.byte_counts:=dos_io.byte_counts(markers'size/8);
  301.   begin
  302.     if handle.is_input then
  303.       raise status_error;
  304.     end if;
  305.     write_block_header(handle,marker,2);
  306.     if Dos_IO.write(Handle.File_Handle,mark'Address,m_length) /= m_length then
  307.       raise disk_full;
  308.     end if;
  309.   end write_marker;
  310.  
  311.   procedure Write_text(Handle  : in out Handles;
  312.                        text    : in     string) is
  313.     text_length:constant dos_io.byte_counts:=dos_io.byte_counts(text'length);
  314.     null_byte:one_byte_naturals:=0;
  315.   begin
  316.     if handle.is_input then
  317.       raise status_error;
  318.     end if;
  319.     write_block_header(handle,voc_data.text,text'length+1);
  320.     if Dos_IO.write(Handle.File_Handle,text(text'first)'Address,text_length)
  321.        /= text_length then
  322.       raise disk_full;
  323.     end if;
  324.     if Dos_IO.write(Handle.File_Handle,null_byte'Address,1) /= 1 then
  325.       raise disk_full;
  326.     end if;
  327.   end write_text;
  328.  
  329.   procedure Write_repeat(Handle  : in out Handles;
  330.                          count   : in     VOC_data.repeat_counts) is
  331.     r_length:constant dos_io.byte_counts:=dos_io.byte_counts(repeat_counts'size/8);
  332.   begin
  333.     if handle.is_input then
  334.       raise status_error;
  335.     end if;
  336.     write_block_header(handle,start_repeat,2);
  337.     if Dos_IO.write(Handle.File_Handle,count'Address,r_length) /= r_length then
  338.       raise disk_full;
  339.     end if;
  340.   end write_repeat;
  341.  
  342.   procedure Write_end_repeat(Handle  : in out Handles) is
  343.   begin
  344.     if handle.is_input then
  345.       raise status_error;
  346.     end if;
  347.     write_block_header(handle,end_repeat,0);
  348.   end write_end_repeat;
  349.  
  350.   procedure Close(Handle  : in out Handles) is
  351.     fini:block_types:=terminator;
  352.     fini_length:constant dos_io.byte_counts:=dos_io.byte_counts(fini'size/8);
  353.   begin
  354.     if not handle.is_input then
  355.       if Dos_IO.write(Handle.File_Handle,fini'Address,fini_length)
  356.          /= fini_length then
  357.         raise disk_full;
  358.       end if;
  359.     end if;
  360.     Dos_IO.Close(Handle.File_Handle);
  361.   end Close;
  362.  
  363. end VOC_IO;
  364.