home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / sound / sbutil / source.exe / ADLIB.PAS next >
Encoding:
Pascal/Delphi Source File  |  1991-04-25  |  20.7 KB  |  724 lines

  1. {**************************************************************************
  2.  
  3.                                 ADLIB
  4.                        FM AdLib Sound Utilitys
  5.  
  6.                             Date: 4/4/91
  7.                              Version: 1
  8.  
  9. ***************************************************************************
  10.  
  11.                    Copyright (c) 1991, Zackzon Labs.
  12.  
  13.                        Author: Anthony Rumble
  14.  
  15. ==========
  16. Addresses:
  17. ==========
  18. InterNet: c9106510@cc.newcastle.edu
  19. SIGNet: 28:2200/108
  20.  
  21. Snail Mail:
  22.  32 Woolwich Rd.
  23.  Hunters Hill, NSW, 2110
  24.  Australia
  25.  
  26. =========================================================================
  27.                               NOTE!
  28. =========================================================================
  29.  
  30. Many of these functions are incomplete, due to lack of information.
  31. Especially the ROL player. If you can fill the gaps, please get into
  32. contact with me about it. Thankyou.
  33.  
  34. -------------------------------------------------------------------------
  35.                               HISTORY
  36. -------------------------------------------------------------------------
  37. 1.0 - ROL Player still dosent work. Direct playing seems to work.
  38. *************************************************************************}
  39. unit adlib;
  40.  
  41. interface
  42.  
  43. uses dos, misc, bnktb;
  44.  
  45. type
  46.  Signature_Block = record
  47.   Version:word;
  48.   Block:array[0..18] of char;
  49.   Tst1:byte;
  50.   Tst2:byte;
  51.   Tst3:byte;
  52.  end;
  53.  
  54.  rol_header = record
  55.   Maj_Vers:word;
  56.   Min_Vers:word;
  57.   filler1:array[1..40] of char;
  58.   TickBeats:word;
  59.   BeatMeasure:word;
  60.   yscale:word;
  61.   xscale:word;
  62.   filler2:byte;
  63.   mode:byte;
  64.   filler3:array[1..90] of char;
  65.   filler4:array[1..38] of char;
  66.   filler5:array[1..15] of char;
  67.  end;
  68.  
  69.  Instrument = bnktb.Instrument;
  70.  
  71.  addr_type = array[0..1] of word;
  72.  
  73. const
  74.  
  75.    TestString = 'SOUND-DRIVER-AD-LIB';
  76.  
  77.       ALLDONE = $00;
  78.  STILLPLAYING = $01;
  79.  
  80.      DISABLED = $00;
  81.       ENABLED = $01;
  82.  
  83.       MELODIC = $00;
  84.    PERCUSSIVE = $01;
  85.  
  86.        VOICE1 = $00;
  87.        VOICE2 = $01;
  88.        VOICE3 = $02;
  89.        VOICE4 = $03;
  90.        VOICE5 = $04;
  91.        VOICE6 = $05;
  92.        VOICE7 = $06;
  93.        VOICE8 = $07;
  94.        VOICE9 = $08;
  95.  
  96.        LibInt = $65;
  97.  
  98.           Init = $00;
  99.   RelTimeStart = $02;
  100.       SetState = $03;
  101.       GetState = $04;
  102.          Flush = $05;
  103.        SetMode = $06;
  104.        GetMode = $07;
  105.   SetRelVolume = $08;
  106.       SetTempo = $09;
  107.   SetTranspose = $0A;
  108.   GetTranspose = $0B;
  109.    SetActVoice = $0C;
  110.    GetActVoice = $0D;
  111.    PlayNoteDel = $0E;
  112.       PlayNote = $0F;
  113.      SetTimbre = $10;
  114.       SetPitch = $11;
  115.    SetTickBeat = $12;
  116.         NoteOn = $13;
  117.        NoteOff = $14;
  118.        _Timbre = $15;
  119.   SetPitchBend = $16;
  120.       WaveForm = $17;
  121.  
  122. Var
  123.       Regs : Registers;
  124.       intp : pointer;
  125.          p : ^signature_block;
  126.   SigBlock : Signature_Block;
  127.  GActVoice : word; {Active Voice}
  128.         GT : array[0..10] of Instrument; {use global variable to keep array valid}
  129.  
  130. function initialize:boolean;
  131. procedure rel_timestart(TimeNum, TimeDen : integer);
  132. procedure set_state(state:word);
  133. function get_state:byte;
  134. procedure flush_buffer;
  135. procedure set_mode(mde:byte);
  136. function get_mode:byte;
  137. function Set_RelVolume(VolNum,VolDen,TimeNum,TimeDen :integer) :boolean;
  138. function Set_Tempo(Tempo,TimeNum,TimeDen :integer) :boolean;
  139. procedure set_transpose;
  140. procedure get_transpose;
  141. procedure set_active_voice(vse:byte);
  142. function get_active_voice:byte;
  143. function Play_NoteDel(Pitch :integer; LengthNum,LengthDen,DelayNum,DelayDen :word) :boolean;
  144. function Play_Note(Pitch :integer; LengthNum,LengthDen :word) :boolean;
  145. function Set_Timbre(TimeNum,TimeDen :word) :boolean;
  146. function Set_Pitch(DeltaOctave,DeltaNum,DeltaDen :integer; TimeNum,TimeDen :word) :boolean;
  147. procedure Set_TickBeat(TickBeat :integer);
  148. procedure Note_On(Voice :word; Pitch :integer);
  149. procedure Note_Off(Voice :word);
  150. procedure timbre;
  151. procedure set_pitchbend;
  152. procedure wave_form;
  153. procedure Load_Instrument(FileSpec :string);
  154. function Load_Song(FileSpec :string) :boolean;
  155.  
  156. implementation
  157.  
  158. {****************************************************************************
  159.                                INITIALIZE
  160. ----------------------------------------------------------------------------
  161.    Checks for the driver. If present will initialise it, and return TRUE
  162.                         else will return FALSE
  163. ****************************************************************************}
  164. function initialize:boolean;
  165. var
  166.  Signature:string[19];
  167.  x:word;
  168. begin
  169.  
  170.  getintvec($65,intp);
  171.  
  172.  p := ptr(seg(intp^), ofs(intp^) - sizeof(Signature_block));
  173.  
  174.  SigBlock := p^;
  175.  for x:= 1 to 19 do
  176.  begin
  177.   Signature[x] := SigBlock.block[x-1];
  178.  end;
  179.  Signature[0] := #19;
  180.  if Signature = TestString then
  181.  begin
  182.   regs.SI := Init;
  183.   Intr(LibInt, Regs);
  184.   initialize := TRUE;
  185.  end
  186.  else initialize := FALSE;
  187. end;
  188. {****************************************************************************
  189.                                REL_TIMESTART
  190. ----------------------------------------------------------------------------
  191. ????
  192. ****************************************************************************}
  193. procedure rel_timestart(TimeNum, TimeDen : integer);
  194. var
  195.  TD,TN :integer;
  196. begin
  197.  TD:=TimeDen;
  198.  TN:=TimeNum;
  199.  Regs.SI := RelTimeStart;
  200.  Regs.ES:=Seg(TN);
  201.  Regs.BX:=Ofs(TN);
  202.  Intr(LibInt, Regs);
  203. end;
  204. {****************************************************************************
  205.                                SET_STATE
  206. ----------------------------------------------------------------------------
  207. Starts or stops a song..
  208. Either
  209.  DISABLED or
  210.  ENABLED
  211. ****************************************************************************}
  212. procedure set_state(state:word);
  213. var
  214.  st:word;
  215. begin
  216.  st := state;
  217.  Regs.SI := SetState;
  218.  Regs.ES := seg(st);
  219.  Regs.BX := ofs(st);
  220.  Intr(LibInt, Regs);
  221. end;
  222. {****************************************************************************
  223.                                GET_STATE
  224. ----------------------------------------------------------------------------
  225. Returns either
  226.  ALLDONE  or
  227.  STILLPLAYING
  228. ****************************************************************************}
  229. function get_state:byte;
  230. begin
  231.  Regs.SI := GetState;
  232.  Intr(LibInt, Regs);
  233.  if (regs.ax = $00) then get_state := ALLDONE
  234.  else get_state := STILLPLAYING;
  235. end;
  236. {****************************************************************************
  237.                                 FLUSH
  238. ----------------------------------------------------------------------------
  239.                        Flushes the Song Buffer
  240. ****************************************************************************}
  241. procedure flush_buffer;
  242. begin
  243.  Regs.SI := Flush;
  244.  Intr(LibInt, Regs);
  245. end;
  246. {****************************************************************************
  247.                                SET_MODE
  248. ----------------------------------------------------------------------------
  249. Either
  250.  MELODIC  or
  251.  PERCUSSIVE
  252. ****************************************************************************}
  253. procedure set_mode(mde:byte);
  254. var
  255.  mode:integer;
  256. begin
  257.  mode := mde;
  258.  Regs.SI := SetMode;
  259.  Regs.ES := seg(mode);
  260.  Regs.BX := ofs(mode);
  261.  Intr(LibInt, Regs);
  262. end;
  263. {****************************************************************************
  264.                                GET_MODE
  265. ----------------------------------------------------------------------------
  266. Returns either
  267.  MELODIC or
  268.  PERCUSSIVE
  269. ****************************************************************************}
  270. function get_mode:byte;
  271. begin
  272.  Regs.SI := GetMode;
  273.  Intr(LibInt, Regs);
  274.  get_mode := Regs.AX;
  275. end;
  276. {****************************************************************************
  277.                                SET_RELVOLUME
  278. ----------------------------------------------------------------------------
  279. VolNum: ?
  280. VolDen: ?
  281. TimeNum: ?
  282. TimeDen: ?
  283. ****************************************************************************}
  284. function Set_RelVolume(VolNum,VolDen,TimeNum,TimeDen :integer) :boolean;
  285. var
  286.  TD,TN,VD,VN :word; {To put variables values in proper order in memory}
  287. begin
  288.  TD:=TimeDen;
  289.  TN:=TimeNum;
  290.  VD:=VolDen;
  291.  VN:=VolNum;
  292.  Regs.SI := SetRelVolume;
  293.  Regs.ES:=Seg(VN);
  294.  Regs.BX:=Ofs(VN);
  295.  Intr(LibInt, Regs);
  296.  Set_RelVolume:=(Regs.BP=1);
  297. end;
  298. {****************************************************************************
  299.                                SET_TEMPO
  300. ----------------------------------------------------------------------------
  301. Tempo: Tempo
  302. TimeNum: ?
  303. TimeDen: ?
  304. ****************************************************************************}
  305. function Set_Tempo(Tempo,TimeNum,TimeDen :integer) :boolean;
  306. var
  307.  TD,TN,TP :integer; {To put variables values in proper order in memory}
  308. begin
  309.  TD:=TimeDen;
  310.  TN:=TimeNum;
  311.  TP:=Tempo;
  312.  Regs.SI := SetTempo;
  313.  Regs.ES := seg(TP);
  314.  Regs.BX := ofs(TP);
  315.  Intr(LibInt, Regs);
  316.  Set_Tempo:=(Regs.BP=1);
  317. end;
  318. {****************************************************************************
  319.                                SET_TRANSPOSE
  320. ----------------------------------------------------------------------------
  321.               Unknown how to program this function. Dont use
  322. ****************************************************************************}
  323. procedure set_transpose;
  324. begin
  325.  Regs.SI := SetTranspose;
  326.  Intr(LibInt, Regs);
  327. end;
  328. {****************************************************************************
  329.                                GET_TRANSPOSE
  330. ----------------------------------------------------------------------------
  331.                Unknown how to program this funvtion. Dont use.
  332. ****************************************************************************}
  333. procedure get_transpose;
  334. begin
  335.  Regs.SI := GetTranspose;
  336.  Intr(LibInt, Regs);
  337. end;
  338. {****************************************************************************
  339.                             SET_ACTIVE_VOICE
  340. -----------------------------------------------------------------------------
  341. Vse can either be a byte between 0 -> 8
  342.  
  343. Or you can use the constants VOICEx
  344. ie/ VOICE6
  345. ****************************************************************************}
  346. procedure set_active_voice(vse:byte);
  347. var
  348.  voice:word;
  349. begin
  350.  GActVoice:=vse;
  351.  voice := vse;
  352.  Regs.SI := SetActVoice;
  353.  Regs.ES := seg(voice);
  354.  Regs.BX := ofs(voice);
  355.  Intr(LibInt, Regs);
  356. end;
  357. {****************************************************************************
  358.                                GET_ACTIVE_VOICE
  359. ----------------------------------------------------------------------------
  360. Returns the active voice no. Between 0 -> 8
  361. ****************************************************************************}
  362. function get_active_voice:byte;
  363. begin
  364.  Regs.SI := GetActVoice;
  365.  Intr(LibInt, Regs);
  366.  get_active_voice := Regs.AX;
  367. end;
  368. {****************************************************************************
  369.                              PLAY_NOTEDEL
  370. -----------------------------------------------------------------------------
  371. Pitch: Pitch Number
  372. LengthNum: Decay length
  373. LengthDen: Attach Length
  374. DelayNum: Decay Delay?
  375. DelayDen: Attack Delay?
  376. ****************************************************************************}
  377. function Play_NoteDel(Pitch :integer; LengthNum,LengthDen,DelayNum,DelayDen :word) :boolean;
  378. var
  379.  DD,DN,LD,LN :word;
  380.  P           :integer;
  381. begin
  382.  P:=Pitch;
  383.  LD:=LengthDen;
  384.  LN:=LengthNum;
  385.  DN:=DelayNum;
  386.  DD:=DelayDen;
  387.  Regs.SI := PlayNoteDel;
  388.  Regs.ES:=Seg(P);
  389.  Regs.BX:=Ofs(P);
  390.  Intr(LibInt, Regs);
  391.  Play_NoteDel:=(Regs.BP=1);
  392. end;
  393. {****************************************************************************
  394.                                PLAY_NOTE
  395. ----------------------------------------------------------------------------
  396. Pitch: Pitch Number
  397. LengthNum: Decay length
  398. LengthDen: Attach Length
  399. ****************************************************************************}
  400. function Play_Note(Pitch :integer; LengthNum,LengthDen :word) :boolean;
  401. var
  402.  LD,LN :word;
  403.  P     :integer;
  404. begin
  405.  P:=Pitch;
  406.  LD:=LengthDen;
  407.  LN:=LengthNum;
  408.  Regs.ES := seg(P);
  409.  Regs.BX := ofs(P);
  410.  Regs.SI := PlayNote;
  411.  Intr(LibInt, Regs);
  412.  Play_Note:=(Regs.BP=1);
  413. end;
  414. {****************************************************************************
  415.                                SET_TIMBRE
  416. -----------------------------------------------------------------------------
  417. GT[GActVoice] contains the Instrument
  418. TimeNum: ?
  419. TimeDen: ?
  420. ****************************************************************************}
  421. function Set_Timbre(TimeNum,TimeDen :word) :boolean;
  422. var
  423.  TD,TN :word;
  424.  T     :^integer;
  425.  c1,c2 :byte;
  426. begin
  427.  T:=Addr(GT[GActVoice]);
  428.  TN:=TimeNum;
  429.  TD:=TimeDen;
  430.  Regs.SI := SetTimbre;
  431.  Regs.ES:=Seg(T);
  432.  Regs.BX:=Ofs(T);
  433.  Intr(LibInt, Regs);
  434.  Set_Timbre:=(Regs.BP=1);
  435. end;
  436. {****************************************************************************
  437.                                 SET_PITCH
  438. ----------------------------------------------------------------------------
  439.        Unknown how to program this function as yet. Do not use.
  440. ****************************************************************************}
  441. function Set_Pitch(DeltaOctave,DeltaNum,DeltaDen :integer; TimeNum,TimeDen :word) :boolean;
  442. var
  443.  TD,TN   :word;
  444.  DD,DN,D :integer;
  445.  c1,c2   :byte;
  446. begin
  447.  D:=DeltaOctave;
  448.  DN:=DeltaNum;
  449.  DD:=DeltaDen;
  450.  TN:=TimeNum;
  451.  TD:=TimeDen;
  452.  Regs.SI := SetPitch;
  453.  Regs.ES:=Seg(D);
  454.  Regs.BX:=Ofs(D);
  455.  Intr(LibInt, Regs);
  456.  Set_Pitch:=(Regs.BP=1);
  457. end;
  458. {****************************************************************************
  459.                               SET_TICKBEAT
  460. ----------------------------------------------------------------------------
  461.        Unknown how to program this function as yet. Do not use.
  462. ****************************************************************************}
  463. procedure Set_TickBeat(TickBeat :integer);
  464. begin
  465.  Regs.ES:=Seg(TickBeat);
  466.  Regs.BX:=Ofs(TickBeat);
  467.  Regs.SI := SetTickBeat;
  468.  Intr(LibInt, Regs);
  469. end;
  470. {****************************************************************************
  471.                               NOTE_ON
  472. -----------------------------------------------------------------------------
  473. Direct Note On
  474. ****************************************************************************}
  475. procedure Note_On(Voice :word; Pitch :integer);
  476. var
  477.  P :integer;
  478.  V :word;
  479. begin
  480.  P:=Pitch;
  481.  V:=Voice;
  482.  Regs.SI := NoteOn;
  483.  Regs.ES:=Seg(V);
  484.  Regs.BX:=Ofs(V);
  485.  Intr(LibInt, Regs);
  486. end;
  487. {****************************************************************************
  488.                               NOTE_OFF
  489. -----------------------------------------------------------------------------
  490. Direct Note Off
  491. ****************************************************************************}
  492. procedure Note_Off(Voice :word);
  493. begin
  494.  Regs.SI := NoteOff;
  495.  Regs.ES:=Seg(Voice);
  496.  Regs.BX:=Ofs(Voice);
  497.  Intr(LibInt, Regs);
  498. end;
  499. {****************************************************************************
  500.                                 TIMBRE
  501. -----------------------------------------------------------------------------
  502. Direct Timbre
  503. ****************************************************************************}
  504. procedure timbre;
  505. var
  506.  T:^integer;
  507.  V:word;
  508. begin
  509.  V:=GActVoice;
  510.  T:=Addr(GT[V]);
  511.  Regs.ES:=Seg(V);
  512.  Regs.BX:=Ofs(V);
  513.  Regs.SI := _Timbre;
  514.  Intr(LibInt, Regs);
  515. end;
  516. {****************************************************************************
  517.                               SET_PITCHBEND
  518. -----------------------------------------------------------------------------
  519.        Unknown how to program this function as yet. Do not use
  520. ****************************************************************************}
  521. procedure set_pitchbend;
  522. begin
  523.  Regs.SI := SetPitchBend;
  524.  Intr(LibInt, Regs);
  525. end;
  526. {****************************************************************************
  527.                                 WAVE_FORM
  528. -----------------------------------------------------------------------------
  529.        Unknown how to program this function as yet. Do not use
  530. ****************************************************************************}
  531. procedure wave_form;
  532. begin
  533.  Regs.SI := Waveform;
  534.  Intr(LibInt, Regs);
  535. end;
  536. {****************************************************************************
  537.                            LOAD_INSTRUMENT
  538. -----------------------------------------------------------------------------
  539. Load an Instument from Disk and Place in Array
  540. ****************************************************************************}
  541. procedure Load_Instrument(FileSpec :string);
  542. var
  543.  c1 :byte;
  544.  n  :integer;
  545.  f  :file of integer;
  546. begin
  547.  writeln('Loading Ins from Bnk:',FileSpec);
  548.  if not load_bnk(filespec, GT[GActVoice]) then
  549.  begin
  550.   writeln('Loading Ins from .INS:',FileSpec);
  551.   filespec:=filespec+'.ins';
  552.   if not(Exist(FileSpec)) then
  553.   begin
  554.    writeln('Cant find Instriment file');
  555.    halt(1);
  556.   end;
  557.   Assign(f,FileSpec);
  558.   Reset(f);
  559.   Read(f,n);
  560.   for c1:=1 to 26 do
  561.    Read(f,GT[GActVoice,c1]);
  562.   Close(f);
  563.  end;
  564. end;
  565. {****************************************************************************
  566.                                LOAD_SONG
  567. -----------------------------------------------------------------------------
  568.               Read a .ROL file and place song in Buffer
  569. ****************************************************************************}
  570. function Load_Song(FileSpec :string) :boolean;
  571. var
  572.  nb :byte;
  573.  ns :string[255];
  574.  ni,ni2,ni3,ni4,BPM,tempi :integer;
  575.  c1,c2  :word;
  576.  nr,nr2,tempr :real;
  577.  fl :boolean;
  578.  f  :file;
  579.  templi:longint;
  580. {---------------------------------------------------------------------------
  581.                                 STRINGREAD
  582. ---------------------------------------------------------------------------
  583. uses f,ns
  584. ---------------------------------------------------------------------------}
  585. procedure StringRead(len :word); 
  586. var
  587.  nc :char;
  588.  c1 :word;
  589. begin
  590.  ns:='';
  591.  for c1:=1 to len do
  592.  begin
  593.   BlockRead(f,nc,1);
  594.   ns:=ConCat(ns,nc);
  595.  end;
  596. end;
  597. {---------------------------------------------------------------------------
  598.                                 TEMPOREAD
  599. ---------------------------------------------------------------------------
  600. uses f,nb
  601. ---------------------------------------------------------------------------}
  602. procedure TempoRead;
  603. var
  604.  b1,b2,b3,b4 :byte;
  605. begin
  606.  BlockRead(f,b1,1);
  607.  BlockRead(f,b2,1);
  608.  BlockRead(f,b3,1);
  609.  BlockRead(f,b4,1);
  610. { nb:=51+Round(b3/2.5); }
  611.  nb:=trunc(b4);
  612. end;
  613. {---------------------------------------------------------------------------
  614.                                 VOLUMEREAD
  615. ---------------------------------------------------------------------------}
  616. procedure VolumeRead;
  617. var
  618.  b1,b2,b3,b4 :byte;
  619. begin
  620.  BlockRead(f,b1,1);
  621.  BlockRead(f,b2,1);
  622.  BlockRead(f,b3,1);
  623.  BlockRead(f,b4,1);
  624.  nb:=51+Round(b3/2.5);
  625. end;
  626.  
  627. begin
  628.  Load_Song:=true;
  629.  if not(Exist(FileSpec)) then
  630.  begin
  631.   Load_Song:=false;
  632.   Exit;
  633.  end;
  634.  if not initialize then
  635.  begin
  636.   writeln(#7,'Error. SOUND.COM or equilivant not loaded');
  637.   halt(1);
  638.  end;
  639.  Rel_TimeStart(0,1);
  640.  
  641.  {Open ROL File}
  642.  
  643.  Assign(f,FileSpec);
  644.  Reset(f,1);
  645.  {Read in Header}
  646.  StringRead(44);
  647.  {Read in Ticks per Beat}
  648.  BlockRead(f,ni,2);
  649.  Set_TickBeat(ni); {Ticks per Beat}
  650.  {Read in Beats per Measure}
  651.  BlockRead(f,ni,2);
  652.  BPM:=ni; {Beats per Measure}
  653.  
  654.  StringRead(5);
  655.  {Read in Mode}
  656.  BlockRead(f,nb,1);
  657.  Set_Mode(nb);  {Mode}
  658.  
  659.  StringRead(143);
  660.  {Read in General Tempo}
  661.  TempoRead;
  662.  fl:=Set_Tempo(nb,0,1); {Tempo}
  663.  {Read in Specific Tempos}
  664.  BlockRead(f,ni,2);
  665.  for c1:=1 to ni do
  666.  begin
  667.   BlockRead(f,ni2,2);
  668.   TempoRead;
  669.   fl:=Set_Tempo(nb,ni2,1); {Tempo}
  670.  end;
  671.  {Read in each music pattern}
  672.  for c1:=0 to 10 do {11 Voices}
  673.  begin
  674.   Set_Active_Voice(c1);
  675.   StringRead(15);
  676.   BlockRead(f,ni2,2); {Time in ticks of last Note}
  677.   c2:=0;
  678.   while (c2<ni2) do
  679.   begin
  680.    BlockRead(f,ni3,2); {Note Pitch}
  681.    BlockRead(f,ni4,2); {Note Duration}
  682.    fl:=Play_Note(ni3-60,ni4,BPM); {Note}
  683.    c2:=c2+ni4; {Summation of Durations}
  684.   end;
  685.   StringRead(15);
  686.   BlockRead(f,ni2,2);
  687.   for c2:=1 to ni2 do {Instuments}
  688.   begin
  689.    BlockRead(f,ni3,2);
  690.    StringRead(9);
  691.    nb:=Pos(#0,ns);
  692.    Delete(ns,nb,Length(ns));
  693.    Load_Instrument(ns);
  694.    fl:=Set_Timbre(ni3,1);
  695.    StringRead(1);
  696.    BlockRead(f,ni4,2);
  697.   end;
  698.   StringRead(15);
  699.   BlockRead(f,ni2,2);
  700.   nb:=1;
  701.   for c2:=1 to ni2 do {Volume}
  702.   begin
  703.    BlockRead(f,ni3,2);
  704.    fl:=Set_RelVolume(100,nb,ni3,1);  {Use inverse to disable Relative}
  705.    VolumeRead;
  706.    fl:=Set_RelVolume(nb,100,ni3,1);
  707.   end;
  708.   StringRead(15);
  709.   BlockRead(f,ni2,2);
  710.   for c2:=1 to ni2 do {Pitch -disabled}
  711.   begin
  712.    BlockRead(f,ni3,2);
  713.    BlockRead(f,nr,4);
  714.    if (nr=0) then nr2:=1 else nr2:=nr;
  715. {   tempr:=nr*100.0;
  716.    templi:=trunc(tempr);
  717.    tempi:=abs(templi);
  718.    fl:=Set_Pitch(0,tempi,Trunc((nr/nr2)*100),ni3,1); }
  719.   end;
  720.  end;
  721.  Close(f);
  722. end;
  723.  
  724. end.