{
   CTDEMO.PAS, by Markus Saukkonen 1991. T„t„ l„hdekoodia saa levitt„„
   vapaasti, mutta vain CT_VOICE.PAS:n mukana.
   CTDEMO on yksinkertainen esimerkki CT_VOICE-unitin k„yt”st„ Sound
   Blasterin ohjaamiseen. Ohjelma lukee .VOC-tiedostoja ja soittaa ne.
   Latausosa on hieman monimutkainen, koska .VOC-tiedostossa voi olla
   rajoittamaton m„„r„ erimittaisia datablokkeja (CTDEMO ei ymm„rr„ eri
   blokkityyppej„, se vain soittaa ne kertaalleen l„pi). Tiedot luetaan
   levylt„ vuorotellen kahteen puskuriin, tyylin„ "toiseen ladataan -
   toista soitetaan".
}

uses
   crt,ct_voice;

const
   BUFSIZE=32000; {Puskurin maksimikoko, <=64K, muistia varataan 2*BUFSIZE}

var
   f:file;
   file_h:record {.VOC-tiedoston headeri}
      message:array[0..$13] of char;
      offset:word; {osoittaa ensimm„iseen datablokkiin}
      version:word; {hi=major, lo=minor}
      identify:word; {version komplementti + 1234h}
   end;
   header_l:byte; {headerin pituus tavuissa}
   header:record {headeri}
      blocktype:byte;
      size1:word;
      size2:byte;
      speed:byte;
      compress:byte;
   end;
   blklen:longint; {blokin pituus (kootaan header.sizeist„)}
   bufree:word; {paljonko nykyisess„ puskurissa vapaata tilaa}
   status:word; {statusword, johon ct-driver asettaa tietoa soitosta}
   p,p_save:array[0..1] of pointer; {osoittimet kahdelle puskurille}
   p_addr:array[0..1] of longint absolute p; {...samat my”s longinteiksi,
                                              koska TP ei tajua osoittimien
                                              laskutoimituksia             }
   loppu:boolean;
   i,j,k,apukoko,playlen:word;


begin
   writeln('CTDEMO, demonstrates CT_VOICE.TPU. By Markus Saukkonen 1991.'#10);
   if paramcount<1 then begin
      writeln('Usage:'#13#10'   CTDEMO file.VOC');
      halt;
   end;
   if memavail<2*(BUFSIZE+sizeof(header)+1) then begin
      writeln('Not enough memory.');
      halt(1);
   end;

   assign(f,paramstr(1));
   reset(f,1);
   blockread(f,file_h,sizeof(file_h)); {luetaan tiedoston headeri}
   if (file_h.version xor $ffff)+$1234<>file_h.identify then begin
      writeln('File ',paramstr(1),' is not a Creative Voice File.');
      halt;
   end;
   getmem(p[0],BUFSIZE+sizeof(header)+1); {varataan tilaa}
   getmem(p[1],BUFSIZE+sizeof(header)+1);
   writeln('Playing file '+paramstr(1)+'...');

   status:=0;
   if initializedriver>0 then begin
      writeln('Couldn''t initialize Sound Blaster.');
      halt(2);
   end;
   setstatusaddress(@status);
   speaker(SPEAKER_ON);

   i:=0; blklen:=0;
   repeat
      bufree:=BUFSIZE;
      p_save[i and 1]:=p[i and 1];
      inc(p_addr[i and 1],sizeof(header));
      repeat
         if blklen=0 then begin {headeri luetaan vain jos ollaan blokin alussa}
            {$I-}
            blockread(f,header,sizeof(header)); {luetaan seuraava headeri}
            {$I+}
            if IOresult<>0 then begin {oltiin tiedoston lopussa, lopetetaan}
               close(f);
               while status<>0 do {odotellaan viimeisen blokin soittoa...}
                  if keypressed then
                     write(readkey);
               speaker(SPEAKER_OFF);
               uninstalldriver;
               p[0]:=p_save[0];
               p[1]:=p_save[1];
               freemem(p[0],BUFSIZE+sizeof(header)+1);
               freemem(p[1],BUFSIZE+sizeof(header)+1);
               halt;
            end;
            blklen:=header.size1+(longint(header.size2) shl 16);
            dec(blklen,2); {blklen=„„nidatan pituus}
         end;
         if (bufree>blklen) then {montako tavua luetaan kerralla?}
            apukoko:=blklen
         else
            apukoko:=bufree;
         blockread(f,p[i and 1]^,apukoko,j);
         inc(p_addr[i and 1],j); {Osoitinta eteenp„in...}
         dec(bufree,apukoko);
         dec(blklen,apukoko);
         loppu:=(filepos(f)=filesize(f)-1);
      until (bufree=0) or (loppu);
      if loppu then
         playlen:=BUFSIZE-bufree
      else
         playlen:=BUFSIZE;
      p[i and 1]:=p_save[i and 1]; {osoitin headerin paikalle}
      header.size1:=playlen+2; {headeriin oikeat tiedot}
      header.size2:=0;
      header.blocktype:=1; {new voice block}
      move(header,p[i and 1]^,sizeof(header)); {headeri paikalleen}
      mem[seg(p[i and 1]^) : ofs(p[i and 1]^)+BUFSIZE+sizeof(header)] := 0;
      {laitettiin puskurin loppuun blokki 0 (=lopetusblokki)}

      {odotellaan kunnes edellinen blokki on soinut loppuun:}
      while status<>0 do
         if keypressed then {odotellessa voidaan tehd„ mit„ vain}
            write(readkey);
      playsample(p[i and 1]); {ja seuraava p„tk„ soimaan}
      inc(i);
   until false;
end.