home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 16 / CD_ASCQ_16_0994.iso / maj / swag / sound.swg < prev    next >
Text File  |  1994-08-29  |  265KB  |  2 lines

  1. SWAGOLX.EXE (c) 1993 GDSOFT  ALL RIGHTS RESERVED 00053         SOUNDBLASTER/ADLIB/SPEAKER ROUTINES                               1      05-28-9313:57ALL                      SWAG SUPPORT TEAM        ALLNOTES.PAS             IMPORT              25     ■"╬ {π> Anyone out there ever bothered to fing out what numbers make which note,π> eg. does any know if Sound(3000) makes an A, a C, D#, or what?  I'd likeπ> to know as many as possible, hopefully With the middle C on a piano asπ> one of them.π}ππConstπ  Notes : Array[1..96] Of Word =π  { C    C#,D-  D    D#,E-  E     F    F#,G-  G    G#,A-  A    A#,B-  B  }π  (0033, 0035, 0037, 0039, 0041, 0044, 0046, 0049, 0052, 0055, 0058, 0062,π   0065, 0069, 0073, 0078, 0082, 0087, 0093, 0098, 0104, 0110, 0117, 0123,π   0131, 0139, 0147, 0156, 0165, 0175, 0185, 0196, 0208, 0220, 0233, 0247,π   0262, 0277, 0294, 0311, 0330, 0349, 0370, 0392, 0415, 0440, 0466, 0494,π   0523, 0554, 0587, 0622, 0659, 0698, 0740, 0784, 0831, 0880, 0932, 0987,π   1047, 1109, 1175, 1245, 1329, 1397, 1480, 1568, 1661, 1760, 1865, 1976,π   2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951,π   4186, 4435, 4699, 4978, 5274, 5588, 5920, 6272, 6645, 7040, 7459, 7902);ππ{πEach line represents one octave, starting With octave 0.  Middle C is 523Hz andπMiddle A is 440 (middle A is what all other note calculations are besed on;πeach note it the 12th root of 2 times the previous one.)  You should be able toπarrange the Array into two dimensions if you want to access it using an octaveπand note #.π}ππ{πHere are the notes..ππ    C0      16.35    C2      65.41    C4     261.63    C6    1046.50π    C#0     17.32    C#2     69.30    C#4    277.18    C#6   1108.73π    D0      18.35    D2      73.42    D4     293.66    D6    1174.66π    D#0     19.45    D#2     77.78    D#4    311.13    D#6   1244.51π    E0      20.60    E2      82.41    E4     329.63    E6    1328.51π    F0      21.83    F2      87.31    F4     349.23    F6    1396.91π    F#0     23.12    F#2     92.50    F#4    369.99    F#6   1479.98π    G0      24.50    G2      98.00    G4     392.00    G6    1567.98π    G#0     25.96    G#2    103.83    G#4    415.30    G#6   1661.22π    A0      27.50    A2     110.00    A4     440.00    A6    1760.00π    A#0     29.14    A#2    116.54    A#4    466.16    A#6   1864.66π    B0      30.87    B2     123.47    B4     493.88    B6    1975.53π    C1      32.70    C3     130.81    C5     523.25    C7    2093.00π    C#1     34.65    C#3    138.59    C#5    554.37    C#7   2217.46π    D1      36.71    D3     146.83    D5     587.33    D7    2349.32π    D#1     38.89    D#3    155.56    D#5    622.25    D#7   2489.02π    E1      41.20    E3     164.81    E5     659.26    E7    2637.02π    F1      43.65    F3     174.61    F5     698.46    F7    2793.83π    F#1     46.25    F#3    185.00    F#5    739.99    F#7   2959.96π    G1      49.00    G3     196.00    G5     783.99    G7    3135.96π    G#1     51.91    G#3    207.65    G#5    830.61    G#7   3322.44π    A1      55.00    A3     220.00    A5     880.00    A7    3520.00π    A#1     58.27    A#3    233.08    A#5    932.33    A#7   3729.31π    B1      61.74    B3     246.94    B5     987.77    B7    3951.07π}                                                       C8    4186.01πππ                             2      05-28-9313:57ALL                      SWAG SUPPORT TEAM        DETCADLB.PAS             IMPORT              13     ■"║ Usesπ  Crt; (* Crt Needed For Delay Routine *)ππFunction AdlibCard : Boolean;π (* Routine to determine if a Adlib compatible card is installed *)πVarπ  Val1,Val2 : Byte;πbeginπ  Port[$388] := 4;      (* Write 60h to register 4 *)π  Delay(3);             (* Which resets timer 1 and 2 *)π  Port[$389] := $60;π  Delay(23);π  Port[$388] := 4;      (* Write 80h to register 4 *)π  Delay(3);             (* Which enables interrupts *)π  Port[$389] := $80;π  Delay(23);π  Val1 := Port[$388];   (* Read status Byte *)π  Port[$388] := 2;      (* Write ffh to register 2 *)π  Delay(3);             (* Which is also Timer 1 *)π  Port[$389] := $FF;π  Delay(23);π  Port[$388] := 4;      (* Write 21h to register 4 *)π  Delay(3);             (* Which will Start Timer 1 *)π  Port[$389] := $21;π  Delay(85);            (* wait 85 microseconds *)π  Val2 := Port[$388];   (* read status Byte *)π  Port[$388] := 4;      (* Repeat the first to steps *)π  Delay(3);             (* Which will reset both Timers *)π  Port[$389] := $60;π  Delay(23);π  Port[$388] := 4;π  Delay(3);π  Port[$389] := $80;    (* Now test the status Bytes saved *)π  If ((Val1 And $e0) = 0) And ((Val2 And $e0) = $c0) Thenπ    AdlibCard := True    (* Card was found *)π  Elseπ    AdlibCard := False;  (* No Card Installed *)πend;ππbeginπ  ClrScr;                       (* Clear the Screen *)π  Write(' Adlib Card ');        (* Prepare Response *)π  If AdlibCard Thenπ    Writeln( 'Found!')           (* There is one *)π  Elseπ    Writeln('Not Found!');       (* Not! *)πend.π     3      05-28-9313:57ALL                      SWAG SUPPORT TEAM        MODMUSIC.PAS             IMPORT              30     ■"V·     MOD File DEMOπππ ST> I do, however, have the MOD File structures in a Text File.π ST> NetMail if you want them.ππ EW> Hey..  Could you post them here if their not too long?π EW> All I have For MOD Files is a Program (so so) that plays themπ EW> through the PCSpeaker, and it's *ALL* in Asm, and I'd loveπ EW> to be able to convert at least the File reading to pascal,ππ The MOD File Format is not overly Complicated in itself, but the musicπ encoded therein is very intricate, since the notes use non-standardπ notations For the frequency, and the effects For each note are veryπ involved.  I can, however, post a good skeleton For the File structure,π but if you want the effects commands, we'll have to go to NetMail,π since it would not be in Pascal.ππType SongNameT = String[20]; {This is the first structure in the File, theπ                              full name of the song in the File}π     SampleT = Record        {This structure is Repeated 31 times, andπ                              describes each instrument}π        Name     : String[22];π        Len      : Word;     {Length of the sample wave pattern, which isπ                              Near the end of the File.  This number isπ                              the number of Words, use MUL 2 For Bytes}π        FineTune : Byte;     {0-7 = 0 to +7, 8-F = -8 to -1 offset fromπ                              normal played notes.  Useful For off-keyπ                              instruments}π        Volume   : Byte;     {0-64 Normal volume of instrument}π        RepeatAt : Word;     {offset in Words of the start of the patternπ                              Repeat For long notes.}π        RepeatLn : Word;     {Length in Words of the Repeated part of theπ                              sample pattern}π        end;ππ     VoiceT = Record  {This structure is not in the MOD File itself, butπ                       should help in organizing all of the voice'sπ                       Charicteristics}π        Sample  : Byte; {0-31    Which instrument sample to play}π        note    : Word; {12 bits Which note. Non-standard strange numbers}π        Effect  : Byte; {0-F     Effect to use on note}π        EffectC : Byte; {00-FF   Control Variable to effect}π        end;ππ     SongDataT = Record {This Record, at offset 950, contains inFormationπ                         about the song music itself}π        SongLength : Byte; {1-128 Number of patterns (not wave) ofπ                            sets of musical notes}π        Fill1      : Byte; {Set to 127}π        Patterns   : Array[0..127] of Byte; {0-63 Outline of song}π                     {Tells which score to play where.  Number ofπ                      patterns is the highest number here}π        Initials   : String[4];             {"M.K.","FLT4", or "FLT8"}π        end;ππ     PatternDataT = Array[1..4] of Byte; {This structure is Repeatedπ                       four times For each note in the score (4 voices,π                       4 Bytes each}ππ     {After this the wave patterns For the samples are placed}ππVar Voice  : Array[1.. 4] of VoiceT;  {Four voices}π    Sample : Array[1..31] of SampleT; {31 samples}ππProcedure ParseData (Patt : PatternDataT, VoiceNum : Byte);π{Stuffs voice With pattern data beFore playing}πbeginπ  Voice[VoiceNum].Sample  := (Patt[1] mod 16) shl 4 + (Patt[3] mod 16);π  Voice[VoiceNum].note    := (Patt[2] shl 4) + (Patt[2] div 16);π  Voice[VoiceNum].Effect  := (Patt[3] div 16;π  Voice[VoiceNum].EffectC := Patt[4];π  end;ππAnyway, this should help explain how to do something With the File.πif you need inFormation on what the numbers For the notes are or howπto interprit the effects, send NetMail.π                                         4      05-28-9313:57ALL                      SWAG SUPPORT TEAM        MUSCNOTE.PAS             IMPORT              21     ■"±┌ {π> Does anyone have a "musical scale" of all the values With the Soundπ> Function? A friend is writing a "happy birthday" Program and wants toπ> get a list of all the notes without actually testing them (G)ππ{ Here's a handy Unit that takes a lot of work out of playing music. }π{ I think it originally came from this echo.                         }ππUnit Music;πInterfaceπUses Crt;πConstπ   e_note = 15;       { Eighth Note      }π   q_note = 30;       { Quarter Note     }π   h_note = 60;       { Half Note        }π   dh_note = 90;      { Dotted Half Note }π   w_note = 120;      { Whole Note       }π   R = 0;             { Rest             }π   C = 1;             { C                }π   Cs = 2;            { C Sharp          }π   Db = 2;            { D Flat           }π   D = 3;             { D                }π   Ds = 4;            { D Sharp          }π   Eb = 4;            { E Flat           }π   E = 5;             { Etc...           }π   F = 6;π   Fs = 7;π   Gb = 7;π   G = 8;π   Gs = 9;π   Ab = 9;π   A = 10;π   As = 11;π   Bb = 11;π   B = 12;ππProcedure PlayTone(Octave : Byte; Note : Byte; Duration : Word);πProcedure ToneOn(Octave   : Byte; Note     : Byte);ππImplementationππVarπ   Oct_Val  : Array [0..8] Of Real;π   Freq_Val : Array [C..B] Of Real;ππProcedure Set_Frequencies;πVar N : Byte;πbeginπ   Freq_Val[1] := 1;π   For N := 2 To 12 Doπ      Freq_Val[N] := Freq_Val[N-1] * 1.0594630944;π   Oct_Val[0] := 32.70319566;π   For N := 1 To 8 Doπ      Oct_Val[N] := Oct_Val[N-1] * 2;πend;ππProcedure PlayTone(Octave : Byte;π                   Note : Byte;π                   Duration : Word);πbeginπ   If Note = R Thenπ      NoSoundπ   Elseπ      Sound(Round(Oct_Val[Octave] * Freq_Val[Note]));π   Delay(Duration*8);π   NoSound;πend;ππProcedure ToneOn(Octave : Byte;π                 Note   : Byte);πbeginπ   If Note = R Then NoSoundπ   Else Sound(Round(Oct_Val[Octave] * Freq_Val[Note]));ππend;ππbeginπSet_Frequencies;πNoSound;πend.πππ{πSomeone else: Here they are:ππConstπ    C     =  2093;π    C#    =  2217;π    D     =  2349;π    D#    =  2489;π    E     =  2637;π    F     =  2794;π    F#    =  2960;π    G     =  3136;π    G#    =  3322;π    A     =  3520;π    A#    =  3729;π    H     =  3951;ππThe next C is 2*2093, the C below is 2093 div 2 etc. pp.π}ππ{ππHere's an octive:π  C = 262;π  CSHARP = 277;π  D = 294;π  DSHARP = 311;π  E = 330;π  F = 349;π  FSHARP = 370;π  G = 392;π  GSHARP = 415;π  A = 440;π  ASHARP = 466;π  B = 494;π  CC = 523;π}                                                                                       5      05-28-9313:57ALL                      JUDY BIRMINGHAM          PIANO.PAS                IMPORT              33     ■"c {πBILL BUCHANANππ> I'm just learning Pascal, and I was 1dering if it's possible 2 playπ> music in Pascal?  if so... how?ππHere's a little Program that allows you to play the "PIANO" on your keyboard.πNo Soundcard needed or anything like that.  This may give you a small ideaπon how to create your own Sounds ...ππ}ππProgram Music;                         {by Judy Birmingham, 9/18/92}πUsesπ  Crt;ππConstπ  {-------------------------------------------------------------------}π  {These values will Vary by the song you choose}π  {I wish I could have made these Variables instead of Constants,π  but I seemed to be locked into using Const, because they defineπ  Array sizes in the Types declared below.}ππ  TotalLinesInSong = 4;             {Number of lines in song}π  MaxNotesInPhrase = 9;             {Max number of notes in any line}π  BeatNote         = 4;             {Bottom number in Time Signature}π                                    {Handles cut time (2/2), 6/8 etc.}π  Tempo            = 160;           {Number of beats per minute}π  {-------------------------------------------------------------------}π  {Note frequencies}π  R = 0;                            {Rest = frequency of 0 : silence}π  C = 260;                          {Frequency of middle c          }π  CC = 277;                         {Double letter indicates a sharp}π  D = 294;π  DD = 311;π  E = 330;π  F = 349;π  FF = 370;π  G = 392;π  GG = 415;π  A = 440;π  AA = 466;π  B = 494;ππ  {Note durations}π  Q  = 1 * (BeatNote/4);                            {Quarter note}π  I  = 0.5 * (BeatNote/4);                          {Eighth note}π  H  = 2 * (BeatNote/4);                            {Half note}π  W  = 4 * (BeatNote/4);                            {Whole note}π  S  = 0.25 * (BeatNote/4);                         {Sixteenth note}π  DQ = 1.5 * (BeatNote/4);                          {Dotted quarter}π  DI = 0.75 * (BeatNote/4);                         {Dotted eighth}π  DH = 3 * (BeatNote/4);                            {Dotted half}π  DS = 0.375 * (BeatNote/4);                        {Dotted sixteenth}ππ  Beat = 60000/Tempo;       {Duration of 1 beat in millisecs}ππTypeπ  IValues = Array [1..MaxNotesInPhrase] of Integer;π  RValues = Array [1..MaxNotesInPhrase] of Real;π  Phrase  = Recordπ    Lyric  :  String;π    Notes  : IValues;   {Array of note frequencies}π    Octave : IValues;   {Array of note octaves}π    Rhythm : RValues;   {Array of note durations}π  end;π  Song = Array [1..TotalLinesInSong] of Phrase;ππ {Sample song}πConstπ  RowRow : Song = (π    (Lyric : 'Row Row Row Your Boat';π    NOTES   :  (C,C,C,D,E,R,0,0,0);π    OCTAVE  :  (1,1,1,1,1,1,0,0,0);π    RHYTHM  :  (DQ,DQ,Q,I,Q,I,R,0,0)π    ),ππ    (Lyric : 'Gently down the stream';π    NOTES   :  (E,D,E,F,G,R,0,0,0);π    OCTAVE  :  (1,1,1,1,1,1,0,0,0);π    RHYTHM  :  (Q,I,Q,I,DQ,DQ,0,0,0)π    ),ππ    (Lyric : 'Merrily merrily merrily merrily';π    NOTES :  (C,C,G,G,E,E,C,C,0  );π    OCTAVE : (2,2,1,1,1,1,1,1,0  );π    RHYTHM : (Q,I,Q,I,Q,I,Q,I,0  )π    ),ππ    (Lyric : 'Life is but a dream.';π    NOTES  : (G,F,E,D,C,R,0,0,0  );π    OCTAVE : (1,1,1,1,1,1,0,0,0  );π    RHYTHM  : (Q,I,Q,I,H,Q,0,0,0  )π    ));ππProcedure LYRICS(THE_WORDS : String);πbeginπ  Writeln(THE_WORDS);πend;ππProcedure PLAYNOTE (NOTE, OCT: Integer; DURATION : Real);πbeginπ  Sound (NOTE * OCT);π  Delay (Round(BEAT * DURATION));π  NoSound;πend;ππProcedure PLAYPHRASE(N : Integer; NOTES, OCTAVE : IValues; RHYTHM : RValues);πVarπ  INDEX : Integer;πbeginπ  For INDEX := 1 to N doπ    PLAYNOTE (NOTES[INDEX], OCTAVE[INDEX], RHYTHM[INDEX]);πend;ππProcedure PLAYSONG (Title : String; Tune : Song);πVarπ  Counter : Integer;πbeginπ  ClrScr;π  GotoXY(11,3);π  Writeln (Title);π  Window (10,5,70,19);π  ClrScr;π  For counter := 1 to TotalLinesInSong doπ  beginπ    LYRICS(Tune[counter].Lyric);π    PLAYPHRASE(MaxNotesInPhrase, Tune[counter].Notes,π               Tune[counter].Octave, Tune[counter].Rhythm);π  end;πend;ππbeginπ  ClrScr;π  PlaySong('"Row Row Row Your Boat "', RowRow);πend.π                                                                                   6      05-28-9313:57ALL                      SWAG SUPPORT TEAM        PLAYMUSC.PAS             IMPORT              16     ■"
  2. x { Here is a Unit that plays music. It came out of this echo recently. }πππUnit Music;ππInterfaceππUsesπ  Crt;πConstπ   e_note = 15;       { Eighth Note      }π   q_note = 30;       { Quarter Note     }π   h_note = 60;       { Half Note        }π   dh_note = 90;      { Dotted Half Note }π   w_note = 120;      { Whole Note       }π   R = 0;             { Rest             }π   C = 1;             { C                }π   Cs = 2;            { C Sharp          }π   Db = 2;            { D Flat           }π   D = 3;             { D                }π   Ds = 4;            { D Sharp          }π   Eb = 4;            { E Flat           }π   E = 5;             { Etc...           }π   F = 6;π   Fs = 7;π   Gb = 7;π   G = 8;π   Gs = 9;π   Ab = 9;π   A = 10;π   As = 11;π   Bb = 11;π   B = 12;ππProcedure PlayTone(Octave : Byte; Note : Byte; Duration : Word);πProcedure ToneOn(Octave   : Byte; Note     : Byte);ππImplementationππVarπ  Oct_Val  : Array [0..8] Of Real;π  Freq_Val : Array [C..B] Of Real;ππProcedure Set_Frequencies;πVarπ  N : Byte;πbeginπ  Freq_Val[1] := 1;π  For N := 2 To 12 Doπ    Freq_Val[N] := Freq_Val[N-1] * 1.0594630944;π  Oct_Val[0] := 32.70319566;π  For N := 1 To 8 Doπ    Oct_Val[N] := Oct_Val[N-1] * 2;πend;ππProcedure PlayTone(Octave : Byte; Note : Byte; Duration : Word);πbeginπ  If Note = R Thenπ    NoSoundπ  Elseπ    Sound(Round(Oct_Val[Octave] * Freq_Val[Note]));π  Delay(Duration*8);π  NoSound;πend;ππProcedure ToneOn(Octave : Byte; Note : Byte);πbeginπ  If Note = R Thenπ    NoSoundπ  Elseπ    Sound(Round(Oct_Val[Octave] * Freq_Val[Note]));πend;ππbeginπ  Set_Frequencies;π  NoSound;πend.ππ{π  This does not include the actual values of the tones, but it is stillπvery helpful (more so than if you had the actual freqencies). If you stillπwant the tones, just substitute the value For the tone into the Proceduresπthat play the tone.π}                                                           7      05-28-9313:57ALL                      SWAG SUPPORT TEAM        SB-VOC.PAS               IMPORT              28     ■"æ▓ { JR> Well, Can you post the sorce code on how to play to the Sound blasterπ JR> Byte by Byte? I could probley find out after that!π JR> JamesππSure thing... this Program will load a File into memory then play it a Byteπat a time... It should be pretty self-explanatory.π}ππProgram rawdemo;ππUses Crt;ππ{$I-}ππConstπ   fname = 'NELLAF.VOC';               { Can be any raw data File }π   resetport  = $226;π   readport   = $22A;π   Writeport  = $22C;π   statusport = $22E;π   dac_Write  = $10;π   adc_read   = $20;π   midi_read  = $30;π   midi_Write = $38;π   speakeron  = $D1;π   speakeroff = $D3;ππFunction reset_dsp : Boolean;πVarπ   count, bdum : Byte;πbeginπ   reset_dsp := False;π   port[resetport] := 1;π   For count := 1 to 6 doπ      bdum := port[statusport];π   port[resetport] := 0;π   For count := 1 to 6 doπ      bdum := port[statusport];π   Repeat Until port[statusport] > $80;π    if port[readport] = $AA thenπ      reset_dsp := True;πend;ππProcedure spk_on;πbeginπ   Repeat Until port[Writeport] < $80;π   port[Writeport] := $D1;πend;ππProcedure spk_off;πbeginπ   Repeat Until port[Writeport] < $80;π   port[Writeport] := $D3;πend;ππProcedure generic(reg,cmd:Integer; data:Byte);πbeginπ   Repeat Until port[Writeport] < $80;π   port[reg] := cmd;π   Repeat Until port[Writeport] < $80;π   port[reg] := data;πend;ππProcedure Write_dsp(data:Byte); Assembler;πAsmπ   mov   dx,$22Cπ   mov   cx,6                          { Change either value of CX For }π@1:π   in    al,dxπ   loop  @1ππ   mov   al,10hπ   out   dx,alπ   mov   cx,36                         { faster or slower playing. }π@2:π   in    al,dxπ   loop  @2ππ   mov   al,dataπ   out   dx,alπend;ππFunction read_dsp : Byte;πbeginπ   Repeat Until port[Writeport] < $80;π     port[Writeport] := $20;π   Repeat Until port[statusport] > $80;π   read_dsp := port[readport];πend;ππProcedure Write_midi(data:Byte);πbeginπ   Repeat Until port[Writeport] < $80;π   port[Writeport] := $38;π   Repeat Until port[Writeport] < $80;π   port[Writeport] := data;πend;ππFunction read_midi : Byte;πbeginπ   Repeat Until port[Writeport] < $80;π   port[Writeport] := $30;π   Repeat Until port[statusport] > $80;π   read_midi := port[readport];πend;ππFunction loadFile(Var buffer:Pointer; Filename:String) : Word;πVarπ   fromf : File;π   size : LongInt;π   errcode : Integer;πbeginπ   assign(fromf,Filename);π   reset(fromf,1);π   errcode := ioresult;π   if errcode = 0 thenπ   beginπ      size := Filesize(fromf);π      Writeln(size);π      getmem(buffer,size);π      blockread(fromf,buffer^,size);π   endπ   else size := 0;π   loadFile := size;π   close(fromf);πend;ππProcedure unload(buffer:Pointer; size:Word);πbeginπ   freemem(buffer,size);πend;ππVarπ   ch : Char;π   buf : Pointer;π   index, fsize : Word;ππbeginπ   ClrScr;π   Writeln;π   Writeln;π   if not reset_dsp thenπ   beginπ      Writeln('Unable to initialize SoundBlaster.');π      halt(1);π   end;π   fsize := loadFile(buf,fname);π   if (fsize <= 0) thenπ   beginπ      Writeln(fname, ' not found.');π      halt(2);π   end;π{   For index := 1 to fsize doπ      dec(mem[seg(buf^):ofs(buf^)+index-1],80);}       { For MOD samples }π   spk_on;π   Writeln('Playing...');π   For index := 1 to fsize doπ      Write_dsp(mem[seg(buf^):ofs(buf^)+index-1]);π   spk_off;π   unload(buf,fsize);π   Writeln('Done.');π   ch := ReadKey;πend.ππ                                                                                                                   8      05-28-9313:57ALL                      AMIT MATHUR              SBDEMO.PAS               IMPORT              5      ■"ñ½ {$M 16384,0,0}ππProgram Demo; { to demonstrate the SBVoice Unit }π              { Copyright 1991 Amit K. Mathur, Windsor, Ontario }ππUses SBVoice;ππbeginπif SBFound then beginπ  if paramcount=1 then beginπ    LoadVoice(ParamStr(1),0,0);π    sb_Output(seg(SoundFile),ofs(SoundFile)+26);π    Repeatπ     Write('Ha');π    Until StatusWord=0;π  end elseπ    Writeln('Usage: DEMO [d:\path\]Filename.voc');π  end elseπ  Writeln('SoundBlaster Init Error.  SoundBlaster v1.00 not Found.');πend.ππ                        9      05-28-9313:57ALL                      AMIT MATHUR              SBVOICE.PAS              IMPORT              78     ■"àe {---------------------------------------------------------------------------π                   Unit SBVoice (v1.10) For Turbo Pascal 6.0π       For interfacing With the SoundBlaster's digitized voice channel.π           Copyright (c) 1991, Amit K. Mathur, Windsor, Ontario.ππ                        By: Amit K. Mathurπ                            3215 St. Patrick's Driveπ                            Windsor, Ontarioπ                            N9E 3H2 CANADAπ                        Ph: (519) 966-6924ππ Networks:  RIME(tm) R/O ->WinDSor, ILink (Shareware), NA-Net (Gaming),π            WWIVNet (#198@5950), or direct on NorthSTAR (519)735-1504.ππ These routines are released to the public domain.  However I will gladlyπ accept contributions towards further development of this and other products.π Please send any changes or improvements my way.  and I'm interested inπ other SoundBlaster utilities and Programming tools.  Thanks in advance.π --------------------------------------------------------------------------}ππ{$O+,F+}π{ Allow this Unit to Be Overlayed (doesn't affect Compilation if you decideπ  not to overlay it), and Force Far calls.                                 }ππUnit SBVoice;ππInterfaceππUses MemAlloc;                                    { Memory Allocation Proc }ππVarπ{$ifNDEF NoSBVoiceArray}                          { to use your own        }π     SoundFile: Array[1..64000] of Byte;          { whatever size you want }π{$endif}π     sgSBDriver, ofSBDriver: Word;                { seg and ofs of Driver  }π     SBDriver: Pointer;                           { Pointer to the driver  }π     StatusWord: Word;                            { stores SB status       }π     SBFound: Boolean;                            { whether Init worked    }ππProcedure loaddriver(fi:String);π{ Loads CT-VOICE.DRV into memory.  'fi' is the path to the driver.         }ππProcedure closedriver;π{ Clean up routine.  not Really necessary if your Program is over.         }ππProcedure loadvoice(f:String;start,size:Word);π{ Load 'f' into memory.  Start is the start of the area withinπ  'f' to load and size is the amount to laod.  if you set size to 0π  then it will load the entire File.                                      }ππFunction sb_getversion:Integer;π{ Get the version number of the CT-VOICE.DRVπ  Returns the Version number                                              }ππFunction sb_init:Integer;π{ Initialize the SoundBlaster.  Call this right after load driver, unlessπ  you have to change the BaseIOAddress or Interrupt number and haven'tπ  changed the CT-VOICE.DRV File itself.π  Returns:  0 - no problemπ            1 - Sound card failiureπ            2 - I/O failiureπ            3 - DMA interrupt failiure                                    }ππProcedure sb_output(sg,os:Word);π{ Output the digitized Sound.  You must load the Sound first!π  sg and os are the segment and offset of either SoundFile or whateverπ  Array you use to store the Sound.  if you use a .VOC File then callπ  With 26 added to the offset.                                            }ππProcedure sb_setstatusWord(sg,os:Word);π{ Sets the location of the status Word.  This is the third thing you shouldπ  do, after loading the driver and initializing it.π  The StatusWord will contain $0FFFF if input/output is in output, andπ  0 when it's done.  It will also hold the values of the markers in voiceπ  Files if any are encounterred, allowing you to coordinate output withπ  your Programs.                                                          }ππProcedure sb_speaker(mode:Word);π{ Set the speaker on/off.  off is mode 0, and On is anything else.  Thisπ  is the fourth thing you should do in your initialization.               }ππProcedure sb_uninstall;π{ Uninstall the driver from memory.   Used by CloseDriver.                }ππProcedure sb_setIOaddress(add:Word);π{ Override the IOaddress found inside the CT-VOICE.DRV File.  Add is theπ  new IO address.                                                         }ππProcedure sb_setinterruptnumber(intno:Word);π{ Allows you to override the Interrupt number in the driver.  IntNo is yourπ  new interrupt number (3, 5, 7 or 9).                                    }ππProcedure sb_stopoutput;π{ Stops the output in progress                                            }ππFunction sb_pauseoutput: Integer;π{ PaUses the output in progress.π  Returns:  0 - successπ            1 - fail                                                      }ππFunction sb_continueoutput: Integer;π{ Continues a paused output.π  Returns:  0 - successπ            1 - fail (nothing to continue)                                }ππFunction sb_breakloop(mode:Word): Integer;π{ Breaks out of the currect output loop.π  Modes:  0 - continue round, stop when doneπ          1 - stop immediatelyπ  Returns:  0 - successπ            1 - not in loop                                               }ππProcedure sb_input(highlength,lowlength,seginputbuff,ofsinputbuff:Word);π{ Input digitized Sound.π  HighLength: The high Byte of the length of the input buffer.π  LowLength:  The low Byte of the length of the input buffer.π  SegInputBuff: The Segment of the start of the input buffer.π  ofsInputBuff: The offset of the start of the input buffer.              }ππProcedure sb_setuserFunction(segaddress,ofsaddress:Word);π{ Sets up a user Function that the SB calls when it encounters a new dataπ  block.  It must perForm a Far ret, preserve DS,DI,SI and flag register.π  Clear Carry flag if you want the driver to process the block, or set itπ  if your routine will.  It must be clear if the block Type is 0, thatπ  is the terminate block.π  SegAddress is the segment of your user Function in memory.π  ofsAddress is the ofset of your user Function in memory.                }ππImplementationππUses Dos;ππProcedure Abort(s:String);πbeginπ  Writeln('The Following Error Has Occurred: ',s);π  Writeln('Remedy and try again.  We apologize For any inconvenience.');π  halt(1);πend;ππProcedure loaddriver(fi:String);πVar f: File;π    k: Integer;π    t: String[8];πbeginπ    assign(f,fi+'CT-VOICE.DRV');π    {$I-} Reset(f,1); {$I+}π    if Ioresult <> 0 thenπ        Abort('Cannot Open '+fi+'CT-VOICE.DRV');π    blockread(f,Mem[sgSBDriver:ofSBDriver],Filesize(f));π    close(f);π    t:='';π    For k:=0 to 7 doπ        t:=t+chr(Mem[sgSBDriver:ofSBDriver+k+3]);π    if t<>'CT-VOICE' thenπ        abort('Invalid CT-VOICE Driver!');πend;ππProcedure closedriver;πbeginπ    sb_uninstall;π    if dalloc(sbdriver)=0 thenπ        abort('Uninstall Error!');πend;ππProcedure loadvoice(f:String;start,size:Word);πVar fi: File;π    k: Word;πbeginπ    assign(fi,f);π    {$I-} Reset(fi,1); {$I+}π    if Ioresult <> 0 thenπ       abort('Cannot Open '+f+'!');π    k:=0;π    seek(fi,start);π    if size=0 then size:=Filesize(fi);π    blockread(fi,Mem[seg(SoundFile):ofs(SoundFile)],size);π    close(fi);πend;ππFunction sb_getversion: Integer; Assembler;πAsmπ   push  bpπ   mov   bx,0π   call  SBDriverπ   pop   bpπend;ππProcedure sb_setIOaddress(add:Word); Assembler;πAsmπ   push  bpπ   mov   bx,1π   mov   ax,addπ   call  SBDriverπ   pop   bpπend;ππProcedure sb_setinterruptnumber(intno:Word); Assembler;πAsmπ   push  bpπ   mov   bx,2π   mov   ax,intnoπ   call  SBDriverπ   pop   bpπend;ππProcedure sb_stopoutput; Assembler;πAsmπ   push  bpπ   mov   bx,8π   call  SBDriverπ   pop   bpπend;ππFunction sb_init: Integer; Assembler;πAsmπ   push  bpπ   mov   bx, 3π   call  SBDriverπ   pop   bpπend;ππFunction sb_pauseoutput: Integer; Assembler;πAsmπ   push  bpπ   mov   bx,10π   call  SBDriverπ   pop   bpπend;ππFunction sb_continueoutput: Integer; Assembler;πAsmπ   push  bpπ   mov   bx,11π   call  SBDriverπ   pop   bpπend;ππFunction sb_breakloop(mode:Word): Integer; Assembler;πAsmπ   push  bpπ   mov   bx,12π   mov   ax,modeπ   call  SBDriverπ   pop   bpπend;ππProcedure sb_output(sg,os:Word); Assembler;πAsmπ    push bpπ    push diπ    mov  bx,6π    mov  di,os             { offset of voice  }π    mov  es,sg             { segment of voice }π    call SBDriverπ    pop  diπ    pop  bpπend;ππProcedure sb_input(highlength,lowlength,seginputbuff,ofsinputbuff:Word);πAssembler;πAsmπ    push bpπ    push diπ    mov  bx,7π    mov  dx,highlengthπ    mov  cx,lowlengthπ    mov  es,seginputbuffπ    mov  di,ofsinputbuffπ    call SBDriverπ    pop  diπ    pop  bpπend;ππProcedure sb_setstatusWord(sg,os:Word); Assembler;πAsmπ    push bpπ    push diπ    mov  bx,5π    mov  di,osπ    mov  es,sgπ    call SBDriverπ    pop  diπ    pop  bpπend;ππProcedure sb_speaker(mode:Word); Assembler;πAsmπ   push  bpπ   mov   bx,4π   mov   ax,modeπ   call  SBDriverπ   pop   bpπend;ππProcedure sb_uninstall; Assembler;πAsmπ   push  bpπ   mov   bx,9π   call  SBDriverπ   pop   bpπend;ππProcedure sb_setuserFunction(segaddress,ofsaddress:Word); Assembler;πAsmπ   push  bpπ   mov   dx,segaddressπ   mov   ax,ofsaddressπ   mov   bx,13π   call  SBDriverπ   pop   bpπend;πππbegin {set up SB}ππ  if DosMemAvail < 5000 then                           { lower the heap   }π      abort('not Enough Memory');                      { With $M to fix   }π  StatusWord:=MAlloc(SBDriver,5000);π  if StatusWord<>0 thenπ      abort('Memory Allocation Error');ππ  sgSBDriver:=MemW[seg(SBDriver):ofs(SBDriver)+2];π  ofSBDriver:=MemW[seg(SBDriver):ofs(SBDriver)];ππ  Loaddriver('');                                      { change at will   }π  if sb_init<>0 then                                   { or stick in your }π      SBFound:=False                                   { own Program init }π  elseπ      SBFound:=True;ππ  if SBFound then beginπ      sb_setstatusWord(seg(statusWord),ofs(statusWord));π      sb_speaker(1);                                   { turn SB on       }π  end;πend.πππ{There's the Unit For .VOC playing.}π                                                                                          10     05-28-9313:57ALL                      JOE DICKSON              SOUNDINF.PAS             IMPORT              96     ■"0 {πJOE DICKSONππ> Hello there.. I was just wondering if anyone had any ideaπ> on how to play a wav/voc File over the pc speaker. I have aπ> Program called PC-VOICE, written by Shin K.H. (Is he here?)π> that will play voc's and wav's (whats the difference?) overπ> the speaker.. I don't know assembly, just pascal, but I'veπ> got a friend that can show me how to link the assembly stuffπ> in With the Pascal, so that shouldn't be a problem..π> Also, I've tried and failed to find the format of a voc/wavπ> File, so if anyone has that, it would be much appriciated.π}ππHeader-- CT-VOICE Header Blockπ-=-πThe header is a data block that identifies the File as a CT-format File.  Thisπmeans that you can use the header to check whether the File is an actualπCT-format File.ππBytes $00 - $13 (0-19)ππThe first 19 Bytes of a VOC File contain the Text "Creative Voice File", asπwell as a Byte With the value $1A.  This identifies the File as a VOC File.ππBytes $14 - $15 (20-21)ππThese Bytes contain the offset address of the sample data as aπlow-Byte/high-Byte value.  At this point, this value is $001A because theπheader is exactly $1A Bytes long.ππHowever, if the length of the header changes later, the Programs that accessπthe VOC data in this File will be able to use the values stored in these twoπBytes to determine the location at which the sample data begins.ππBytes $16 - $17 (22-23)ππThese two Bytes contain the CT-Voice format version number as aπlow-Byte/high-Byte value.  The current version number is still 1.10 (NOTE--Thisπmay have changed, this was published in 92) so Byte $17 contains the mainπversion number ($01) and Byte $16 contains the version subnumber ($0A).  Theπversion number is very important because later CT-Voice format versions may useπan entirely different method For storing the sample data than the currentπversion.ππTo ensure that the data contained in the File will be processed correctly, youπshould always check the File's version number.  if a different version numberπappears, an appropriate warning should be displayed.ππBytes $18 - $19 (24-25)ππThe importance of the version number is obvious in Bytes $18 and $19.  TheseπBytes contain the complement of the version number, added to $1234, as aπlow-Byte/high-Byte value.ππTherefore, With the current version number $010A, Byte $18 contains the valueπ$29, While Byte $19 contains $11.  This results in the Word value $1129.  Ifπyou check this value and succesfully compare it to the version number stored inπthe previos two Bytes, you can be almost certain that you're using a VOC File.ππThis completes the desciprtion of Bytes contained in the header.  Everythingπthat follows these Bytes in the File belongs to the File's data blocks.ππThe Data Blocks--  The eight data blocks of the CT-Voice format have the sameπstructure, except For block 0.  Each block begins With a block identifier,πwhich is a Byte containing a block-Type number between 0 and 7.  This number isπfollowed by three Bytes specifying the length of the block, and then theπspecified number of additional data.ππThe three length Bytes contain increasing values (i.e., the first Byteπrepresents the lowest value and the third Byte represents the highest).  SO theπblock's length can be calculated by using the formula:ππByte1 + Byte2*256 + Byte3*65536ππIn all other cases, the CT-Voice format stores values requiring more than oneπByte in a low Byte followed by  a high-Byte, which corresponds to the Word dataπType.ππBlock 0 - end BlockππThe end block has the lowest block number.  It indicates that there aren't anyπadditional data blocks.  When such a block is reached, the output of VOC dataπduring the playback of digitized Sounds stops.  Therefore, this block should beπlocated only at the end of a VOC File.  The end block is the only block thatπdoesn't have Bytes indicating its block length.ππ+----------------------------+π| STRUCTURE of THE end BLOCK |π|                            |π| Block Type: 1 Byte = 0     |π| Block Length: None         |π| Data Bytes: None           |π+----------------------------+ππBlock 1 - New Voice BlockππThe block Type number 1 is the most frequently used block Type.  It containsπplayable sample data.  The three block length Bytes are followed by a Byteπspecifying the sampling rate (SR) that was used to Record the Sounds.ππCalculatin The Sampling Rate-- Since only 256 different values can be stored inπa singly Byte, the actual sampling rate must be calculated from the value ofπthis Byte.ππUse the following formula to do this:ππ  Actual_sampling_rate = -1000000 div (SR - 256)ππTo convert a sampling rate into the corresponding Byte value, reverse theπequation:ππ  SR = 256 - 1000000 div actual_sampling_rateππThe pack Byte follows the SR Byte.  This value indicates whether and how theπsample data have been packed.ππThe value 0 indicates that the data hasn't been packed; so 8 bits form one dataπvalue.  This is the standard Recording format.  However, your Sound Blasterπcard is also capable of packing data on a hardware level. (good luck trying toπrecreate that)ππA value of 1 in the pack Byte indicates that the original 8 bit values haveπbeen packed to 4 bits.  This results in a pack rate of 2:1.  Although the dataπrequires only half as much memory, this method also reduces the Sound quality.ππThe value 2 indicates a pack rate of 3:1, so the data requires only a third ofπthe memory.  Sound quality reduces significantly.ππA pack Byte value of 3 indicates a pack rate of 4:1, so 8 original bits haveπbeen packed down to 2.  This pack rate results in A LOT of reduction in Soundπquality.ππThe pack Byte is followed by the actual sample data.  The values contained inπthe block length Bytes also indicate the length of the sample data.  Toπdetermine the length of the actual sample data in Bytes, simply subtract the SRπand pack Bytes from the block length.ππ+---------------------------------+π| STRUCTRE of THE NEW VOICE BLOCK |π|                                 |π| Block Type: 1 Byte = 1          |π| Block Length: 3 Bytes           |π| SR Byte: 1 Byte                 |π| Pack Byte: 1 Byte = 0,1,2,3     |π| Data Bytes: X Bytes.            |π+---------------------------------+ππBlock 2 - Subsequent Voice BlockππBlock Type 2 is used to divide sample data into smaller individual blocks. Thisπmethod is used by the Creative Labs Voice Editor when you want to work With aπsample block that's too large to fit into memory in one piece.  This block isπthen simply divided into several smaller blocks.ππSince these blocks contain only three length Bytes and the actual sample data,πblocks of Type 2 must always be preceded by a block of Type 1.  So, theπsampling rate and the pack rate are determined by the preceeding block Type 1.ππ+-----------------------------------------+π| STRUCTURE of THE SUBSEQUENT VOICE BLOCK |π|                                         |π| Block Type: 1 Byte = 2                  |π| Block Length: 3 Bytes                   |π| Data Bytes: X Bytes                     |π+-----------------------------------------+ππBlock 3 - Silence BlockππBlock Type 3 Uses a small number of Bytes to represent a mass of zeros.  Firstπthere are the three familiar block length Bytes.  The length of a silence blockπis always 3, so the lowest Byte contains a three, and then the other two Bytesπcontain zeros.ππThe length Bytes are followed by two other Bytes, which indicate how many zeroπBytes should be replaced by the silence block.ππThis is followed by a Byte that indicates the sampling rate For the silenceπblock.  The SR Byte is encoded in the same way as indicated in block Type 1.ππSilence blocks can be used to insert longer paUses or silences in a sample,πwhich reduces the required data to a few Bytes.  The Voice Editor will insertπthese silence blocks through the Silence Packing Function.ππ+--------------------------------+π| STRUCTURE of THE SILENCE BLOCK |π|                                |π| Block Type: 1 Byte = 3         |π| Block Length: 3 Bytes = 3      |π| Duration: 2 Bytes              |π| Sample Rate: 1 Byte            |π+--------------------------------+ππBlock 4 - Marker BlockππThe marker block is an important element of the CT-Voice format.  It also hasπthree block length Bytes followed by two marker Bytes.  The block length Bytesπalways contain the value 2 in the lowest Byte.ππWhen the playback routine of "CT-VOICE.DRV" encounters a marker block, theπvalue of the marker Byte is copied to a memory location that was specified toπthe driver.  The marker block is often used to determine where exactly inπplayback you are.  This is useful For synchronizing the action of your Programπwith the playback, For a Graphical intro For example.ππUsing the Voice Editor, you can divide large sample data blocks into smallerπones, inserting marker blocks at important locations.  This doesnt affect theπplayback of the sample.  However, you'll be able to determine, from yourπProgram, which point of the sample the playback routine is currently reading.ππ+-------------------------------+π| STRUCTURE of THE MARKER BLOCK |π|                               |π| Block Type : 1 Byte = 4       |π| Block Length: 3 Bytes = 2     |π| Marker: 2 Bytes               |π+-------------------------------+ππBlock 5 - Message BlockππIt's also possible to insert ASCII Texts Within a VOC File.  Use the messageπblock to do this.  if you want to identify a specific seciont of a sample Fileπby adding a title, simply add a block of Type 5, in which you can then storeπthe desired Text.ππThis block also has three block length Bytes.  These Bytes are followed by theπText in ASCII format.  The Text must contain a 0 in the last Byte to indicateπthe end of the Text.  This corresponds to the String convention of the CπProgramming language.  This allows you to pring the Texts in a VOC Fileπdirectly from memory using the printf() Function in ANSI C.ππ+--------------------------------+π| STRUCTURE of THE MESSAGE BLOCK |π|                                |π| Block Type: 1 Byte = 5         |π| Block Length: 3 Bytes          |π| ASCII Data: X Bytes            |π| end Character: 1 Byte = 0      |π+--------------------------------+ππBlock 6 - Repeat BlockππAnother special Characteristic of the CT-Format is that it's possible toπspecify, Within a VOC File, whether specific sample sequences should beπRepeated.  Blocks 6 and 7 are used to do this.ππBlock 6 has three block length Bytes, followed by two Bytes indicating howπoften the following data block should be Repeated.  if the value specified hereπis 4, the next block is played a total of five times (one "normal" playback andπfour Repeats).ππ+-------------------------------+π| STRUCTURE of THE Repeat BLOCK |π|                               |π| Block Type: 1 Byte = 6        |π| Block Length: 3 Bytes = 2     |π| Counter: 2 Bytes              |π+-------------------------------+ππBlock 7 - Repeat end BlockππBlock 7 indicates that all blocks between block 6 and block 7 should beπRepeated.  With this block, several data blocks can be included in a Repeatπloop.  However, nested loops aren't allowed.  The driver is capable of handlingπonly one loop level.ππBlock Type 7 also has three block length Bytes, which actually aren't necessaryπbecause this block doesnt contain any additional data.  Therefore, the blockπlength is always 0.ππ+-------------------------------+π| STRUCUTRE of Repeat end BLOCK |π|                               |π| Block Type: 1 Byte = 7        |π| Block Length: 3 Bytes = 0     |π+-------------------------------+ππWe've now described all the different block Types used in VOC Files.  TheseπFunctions are fully supported by the CT-VOICE.DRV driver software.ππif you'll be writing your own Sound Programs, you should follow this formatπbecause it's easy to use and flexible.  When needed, new block Types are easilyπadded.  Programs that dont recognize block Types should be written so theyπcontinue operating after an unrecognized block.  This is easy to do becauseπeach Function specifies its own block length.ππBiblioGraphy: Stolz, Axel  "The Sound Blaster Book", Abacus Copyright (c)1992,πA Data Decker Book Copyright (c) 1992ππ    11     05-28-9313:57ALL                      STEVEN TALLENT           SOUNDOFF.PAS             IMPORT              10     ■"É╞ {πSTEVEN TALLENTππ> I am look For a piece of code [...] that will turn off the speaker.ππThis is tested code, and should do the trick.  It does its work byπturning off the PC speaker 18.2 times per second.  This should reduceπany Sound to maybe a click or two.  Unfortunately, some games andπmusic software will bypass it (ModPlay, Wolfenstein), but most beepsπand whistles will be gone.  This is a TSR Program, and takes about 3kπmemory (yuk), but you can load it high if you want.  I've found itπespecially useful during late-night BBSing (no alarms at connect/Fileπxfer finish). Hope this does the trick!  Considering its size andπrelative isolation from normal Programs, I didn't see fit to use CLI/STI.π}ππ{$M 1024,0,0}  {BTW, is there any way to make this smaller?!?}π{$N-,S-,G+} { Use g- For 8088 systems, g+ For V20 and above }πProgram NoSpeak;πUsesπ  Dos;ππProcedure ShutOff; INTERRUPT;πbeginπ  Port [97] := Port[97] and 253; {Turn off speaker and disconnect timer}πend;ππbeginπ  SetIntVec( $1C, @ShutOff);π  Keep(0);πend.ππ                                                                                                                       12     05-28-9313:57ALL                      SWAG SUPPORT TEAM        VOC2LPT1.PAS             IMPORT              14     ■"Ç {π    This is a Program to export a VOC or other Raw Sound File to a Parallelπport DAC.. (only For LPT1 now, but i think you can make it work on LPT2 byπchanging the 'PORT[$0378]' to 'PORT[$0388]'...ππ I know, This is a Real mess For figuring it out... I originally had noπintention of posting it, but I believe in free access to info, so here it is!πIf you have any questions about it, just ask... and if you figure out whereπthat bug is (you'll know what I mean, it only plays PART of the VOC) I'dπappreciate input.π}ππ{This Program Assumes you have a DAC on LPT1}π{$M 65520,0,300000}          {only use memory that is needed}πProgram Voc_Play;πUsesπ  Crt;ππProcedure Wait(N : Word);        {Very Crude wait routine}πVarπ  counter : Word;πbeginπ  For Counter:= 1 to N do;πend;ππType Ra = Array[0..0] of Byte;ππVarπ  I2   : ^Ra;π  spd  : Integer;π  res  : Word;π  siz  : LongInt;π  B    : Word;π  s    : String;π  f1   : File of Byte;π  F    : File;ππbeginπ  Write('Enter Voc Filename: ');π  readln(S);π                             {Get Size of File}π  Assign(f1,s);π  Reset(f1);π  spd:=30;                   {this is the play speed}π  siz := FileSize(f1);π  close(f1);π                              {Load up Voc File}π  Assign(f,s);π  Reset(f);π  getmem(I2,siz);               {Allocate Memory For VOC File}π  BlockRead(f,I2^,siz,res);     {Load VOC into Memory)π  Writeln('FileSize = ',siz);   {Testing Point, not needed}ππ  Repeat                      {This is the actual Play routine}      beginπ    For b:=0 to siz doπ    beginπ      Wait(spd);            {Wait a bit}π      Port[$0378]:=I2^[b];  {Put Byte to DAC}π    end;π  end Until KeyPressed;ππend.ππ   13     05-28-9313:57ALL                      SWAG SUPPORT TEAM        VOCINFO.PAS              IMPORT              19     ■"¿ {π I posted beFore about sample converting... the .VOC to the sampleπ Format used by MODS.  You gave me some example code, but the prob is,π VOC Files have a header, how would I do it so that the header wasn'tπ converted?ππHere is the VOC File Format that was posted here a While back.  It worksπwell For me.πππA .VOC File consists of a 26-Byte header Record plus sample data.πThe header Record has the following layout:π}πVoiceHeader  : Recordπ     signature   : Array[1..20] of Char;   { Vendor's name }π     DataStart   : Word;      { Start of data in File }π     Version     : Integer;   { BCD value: min. driver version required }π     ID          : Integer;   { 1-Complement of Version field+$1234 }π   end;                       { used to indentify a .VOC File }ππThe data is divided into 'blocks'.  There are 8 Types of blocks:ππ-  0 : Terminatorπ       1 Byte Record, value 00ππ-  1 : Voice Dataπ       1 Byte, value 01: identifierπ       3 Bytes: length of voice data (len data + 2)π       1 Byte: SR= 256-(1,000,000 / sampling rate)π       1 Byte: pack field, value:π         0 : unpacked, 1 : 4-bit, 2 : 2.6 bit, 3 : 2 bit packedπ       <follows voice data>ππ-  2 : Voice Continuationπ       1 Byte, value 02: identifierπ       3 Bytes: length of voice dataπ       <follows voice data>ππ-  3 : Silenceπ       1 Byte, value 03: identifierπ       3 Bytes: length of silence period (value 3?)π       2 Bytes: silence period in Units of sampling cyclesπ       1 Byte: SR (see above)ππ-  4 : Markerπ       1 Byte, value 04: identifierπ       3 Bytes: length of marker, value 2π       2 Bytes: user defined markerππ-  5 : ASCII Textπ       1 Byte, value 05: identifierπ       3 Bytes, length of String (not counting null Byte)π       <String>π       1 Byte, value 0: String terminatorππ-  6 : Repeat Loopπ       1 Byte, value 06: identifierπ       3 Bytes: length of block, value 2π       2 Bytes: count value+1ππ-  7 : end Repeat Loopπ       1 Byte, value 07: identifierπ       3 Bytes: length of block, value 0ππ{πto my knowledge, the .VOC File Format is proprietary and the dataπherein is only of value For the specific SoundBlaster hardware. I thinkπyou'll have a hard time converting samples to another synthesizer.π}π                                                                           14     05-28-9313:57ALL                      SWAG SUPPORT TEAM        VOCPLAY.PAS              IMPORT              37     ■"4S {π> Does anybody know where to get some good source that plays Vocs?π}ππ{$A+,B-,D+,E-,F+,G-,I-,L-,N-,O+,R-,S-,V-,X-}π{$M   1024,0,0 }πUnit  VOCPlay;ππInterfaceππUsesπ  Dos;ππVarπ  VoiceStatusWord           : Word;π  VocPaused,VOCDrvInstalled : Boolean;ππProcedure AllocateMem(Var P : Pointer;Size : LongInt);πFunction  AllocateMemFunc(Var P : Pointer;Size : LongInt) : Boolean;πFunction  ReAllocateMem(Var P : Pointer;NewSize : LongInt) : Boolean;πProcedure DisAllocateMem(Var P : Pointer);ππProcedure VocOutPut(AdrtoPlay : Pointer);πProcedure VocStop;πProcedure VocPause;πProcedure VocContinue;πProcedure VocSetSpeaker(Onoff : Boolean);πFunction  VocInitDriver : Byte;πFunction  LoadVoctoMem(DateiName : String;Var VocMem : Pointer) : Boolean;ππImplementationπConstπ  VocDriverHeader         = 12;π  VocFileHeaderLen        = $1A;πVarπ  PtrtoDriver,OldExitProc : Pointer;π  Regs                    : Registers;π  SizeIntern              : Word;ππProcedure AllocateMem;πbeginπ  Inc(Size,15);π  SizeIntern := (Size SHR 4);π  Regs.AH    := $48;π  Regs.BX    := SizeIntern;π  MsDos(Regs);π  if Regs.Flags and FCarry <> 0 thenπ    P := NILπ  elseπ    P := Ptr(Regs.AX,0);πend;ππFunction AllocateMemFunc;πbeginπ  AllocateMem(P,Size);π  AllocateMemFunc := P <> NIL;πend;ππFunction ReAllocateMem;πbeginπ  Inc(NewSize,15);π  SizeIntern    := (NewSize SHR 4);π  Regs.AH       := $4A;π  Regs.BX       := SizeIntern;π  Regs.ES       := Seg(P^);π  MsDos(Regs);π  ReAllocateMem := (Regs.BX=SizeIntern);πend;ππProcedure DisAllocateMem;πbeginπ  Regs.AH := $49;π  Regs.ES := Seg(P^);π  MsDos(Regs);πend;ππFunction Exists(FileName : String) : Boolean;πVarπ  S : SearchRec;πbeginπ  FindFirst(FileName,AnyFile,S);π  Exists := (DosError=0);πend;ππFunction VocInitDriver;πConstπ  DriverName = 'CT-VOICE.DRV';πTypeπ  DriverType = Array [0..VocDriverHeader] of Char;πVarπ  Out,S,O    : Word;π  F          : File;πbeginπ  Out := 0;π  if not Exists(DriverName) thenπ beginπ   VocInitDriver := 4;π   Exit;π end;π  Assign(F,DriverName);π  Reset(F,1);π  if not AllocateMemFunc(PtrtoDriver,FileSize(F)) then Out := 5;π  if Out=0 then BlockRead(F,PtrtoDriver^,FileSize(F));π  Close(F);π  if Out<>0 thenπ beginπ   VocInitDriver := Out;π   Exit;π end;π  if (DriverType(PtrtoDriver^)[3]<>'C') orπ     (DriverType(PtrtoDriver^)[4]<>'T') thenπ beginπ   VocInitDriver := 4;π   Exit;π end;π  S := Seg(VoiceStatusWord);π  O := ofs(VoiceStatusWord);π  Asmπ    mov   bx,3π    call  PtrtoDriverπ    mov   Out,axπ    mov   bx,5π    mov   es,Sπ    mov   di,Oπ    call  PtrtoDriverπ  end;π  VocInitDriver := Out;πend;ππProcedure VocUninstallDriver;πbeginπ  if VocDrvInstalled thenπ  Asmπ    mov   bx,9π    call  PtrtoDriverπ  end;πend;ππProcedure VocOutPut;πVarπ  S,O : Word;πbeginπ  VocSetSpeaker(True);π  S := Seg(AdrtoPlay^);π  O := ofs(AdrtoPlay^)+VocFileHeaderLen;π  Asmπ    mov   bx,6π    mov   es,Sπ    mov   di,Oπ    call  PtrtoDriverπ  end;πend;ππProcedure VocStop;πbeginπ  Asmπ    mov   bx,8π    call  PtrtoDriverπ  end;πend;ππProcedure VocPause;πbeginπ  Asmπ    mov   bx,10π    call  PtrtoDriverπ  end;πend;ππProcedure VocContinue;πbeginπ  Asmπ    mov   bx,11π    call  PtrtoDriverπ  end;πend;ππProcedure VocSetSpeaker;πVar B : Byte;πbeginπ  B := ord(Onoff) and $01;π  Asmπ    mov   bx,4π    mov   al,Bπ    call  PtrtoDriverπ  end;πend;ππFunction LoadVoctoMem;πVar F            : File;π    Out          : Boolean;π    Gelesen,Segs : Word;πbeginπ  Out := Exists(DateiName);π  if Out thenπ beginπ   Assign(F,DateiName);Reset(F,1);π   if not AllocateMemFunc(VocMem,FileSize(F)) thenπ  beginπ    Close(F);π    LoadVoctoMem := False;π    Exit;π  end;π   Segs := 0;π   Repeatπ     BlockRead(F,Ptr(Seg(VocMem^)+4096*Segs,ofs(VocMem^))^,$FFFF,Gelesen);π     Inc(Segs);π   Until Gelesen=0;π   Close(F);π end;π  LoadVoctoMem := Out;πend;ππ{$F+}πProcedure VocPlayExitProc;πbeginπ  VocUninstallDriver;π  ExitProc := OldExitProc;πend;π{$F-}ππbeginπ  OldExitProc     := ExitProc;π  ExitProc        := @VocPlayExitProc;π  VoiceStatusWord := 0;π  VocPaused       := False;π  VocDrvInstalled := (VocInitDriver=0);πend.πππ{$A+,B-,D+,E-,F-,G-,I-,L-,N-,O-,R-,S-,V-,X-}π{$M   1024,0,0 }πUses  Crt,VOCPlay;πVar   VocMem   : Pointer;π      FileName : String;π      Ok       : Boolean;πbeginπ  FileName := ParamStr(1);π  Ok       := False;π  if VocDrvInstalled then Ok := LoadVoctoMem(DateiName,VocMem);π  if Ok thenπ beginπ   Write('Playing VOC-File ...');π   VocOutPut(VocMem);π   Repeatπ   Until (VoiceStatusWord=0) or KeyPressed;π   Writeln;π   DisAllocateMem(VocMem);π endπ else Writeln('Hey, there was something wrong.');πend.π                                15     05-28-9313:57ALL                      BILL BUCHANAN            WHISTLE.PAS              IMPORT              5      ■"H { BILL BUCHANAN }ππUsesπ  Crt;ππProcedure OpenWhistle;πVarπ  Frequency : Integer;πbeginπ  For Frequency := 500 to 1000 doπ  beginπ    Delay(1);π    Sound(Frequency)π  end;π  NoSoundπend;ππProcedure CloseWhistle;πVarπ  Frequency: Integer;πbeginπ  For Frequency := 1000 downto 500 doπ  beginπ    Delay(1);π    Sound(Frequency)π  end;π  NoSoundπend;ππbeginπ  OpenWhistle;π  Readln;π  CloseWhistle;πend.                                                                                                                 16     05-28-9313:57ALL                      SWAG SUPPORT TEAM        WINSOUND.PAS             IMPORT              9      ■"oô {πFellow Windows voyeurs,ππA While ago people were asking how to obtain Sound throughπthe PC speaker without using the multimedia DLL (or aπspeaker driver For that matter.)  Below is a basic exampleπof how to do this.π}π  Procedure SoundStart;π  Varπ    Pitch : Integer;π  beginπ  OpenSound;π  For Pitch:= 80 to 84 doπ    beginπ    SetVoicenote (1, Pitch, 100, 1);π    SetVoiceAccent (1, 15, 255, s_Legato, Pitch);π    end;π  StartSound;π  WaitSoundState (S_QueueEmpty);π  StopSound;π  CloseSoundπ  end;ππ{πPlease reference your Windows API reference manual Forπthe SetVoicenote() and SetVoiceAccent() synopsys.ππMicrosoft supports the calls in Windows 3.0, howeverπdocumentation in 3.1 suggests that it will no longerπsupport them.  My interpretation is that For theπfuture these calls will be supported, however will notπbe enhanced or Extended.  Their reasoning is probablyπbased on there drive to sell their multimedia kits.π}π                                                                                             17     06-08-9308:16ALL                      LARRY HADLEY             Play SOUNDS in BackgroundIMPORT              106    ■"é∩ {  SEE XX34 modules at end of document !!!}ππ{$R-,F+}ππ{π  ******************************************************************π  BGSND.PASππ  Background Sound for Turbo Pascalππ  Adapted from BGSND.INC for Turbo Pascal 3.0π  by Michael Quinlanπ  9/17/85ππ  This version for Turbo Pascal 6.0π  by Larry Hadleyπ  3/20/93ππ  The routines are rather primitive, but could easily be extended.ππ  The sample routines included implement something similar to theπ  BASIC PLAY statement.π  ******************************************************************π}πUnit BGSND;ππINTERFACEππUsesπ   DOS;ππCONSTπ   BGSVer = '2.0';               { Unit version number }ππ   BGSPlaying :boolean = FALSE;  { TRUE while music is playing }ππVARπ   _BGSNumItems :integer;ππprocedure BGSPlay(n :integer; VAR items);ππprocedure _BGSStopPlay;ππprocedure PlayMusic(s :string);ππIMPLEMENTATIONππTYPEπ   BGSItem = RECORDπ                cnt :word;     { count to load into the 8253-5 timer;π                                 count = 1,193,180 / frequency }π                tics:integer;  { timer tics to maintain the sound;π                                 18.2 tics per second }π             end;ππ   _BGSItemP = ^BGSItem;ππVARπ   _BGSNextItem :_BGSItemP;π   _BGSOldInt1C :pointer;π   _BGSDuration :integer;π   ExitSave     :pointer;ππprocedure _BGSsaveDS; external;      { saves ds as a CS:CONSTANT for useπ                                        within the int 1C vector }πprocedure _BGSPlayNextItem; external; { used by int 1C vector - selects nextπ                                        note to play }πprocedure _BGSStopPlay; external;ππprocedure _BGSInt1C; external;        { int1C vector - hooks timer }π{$L BGS.OBJ}ππprocedure BGSPlay(n :integer; VAR items);π{π  ***************************************************************************π  You call this procedure to play music in the background. You pass theπ  number of sound segments, and an array with an element for each soundπ  segment. The array elements are two words each; the first word has theπ  count to be loaded into the timer (1,193,180 / frequency). The second wordπ  has the duration of the sound segment, in timer tics (18.2 tics per second).π  ***************************************************************************π}π  VARπ     item_list : array[0..1000] of BGSItem ABSOLUTE items;π  BEGINπ     while BGSPlaying do { wait for previous sounds to finish } ;ππ     if n > 0 thenπ     BEGINπ        _BGSNumItems := n;π        _BGSNextItem := Addr(item_list[0]);π        BGSPlaying   := TRUE;π        _BGSPlayNextItem;π        _BGSsaveDS;π        SetIntVec($1C, @_BGSInt1C);π     END;π  END;ππprocedure BGSErrorExit;π{π **************************************************************************π In case there's an "oopsie" ... make sure that Int $1C is clean, andπ music isn't playing.π **************************************************************************π}π  BEGINπ     ExitProc := ExitSave;π     if BGSPLaying thenπ     BEGINπ        _BGSStopPlay;π        SetIntVec($1C, _BGSOldInt1C);π     END;π  END;ππ{π **************************************************************************ππ    BASIC PLAY Routinesππ **************************************************************************π}ππ{$R+}ππVARπ   MusicArea : array[1..255] of BGSItem; { contains sound segments }ππ{π  frequency table from:π  Peter Norton's Programmer's Guide to the IBM PC, p. 147π}πCONSTπ   Frequency : array[0..83] of real =π{    C        C#       D        D#       E        F        F#       G        G#       A        A#       B }π  (32.70,   34.65,   36.71,   38.89,   41.20,   43.65,   46.25,   49.00,   51.91,   55.00,   58.27,   61.74,π   65.41,   69.30,   73.42,   77.78,   82.41,   87.31,   92.50,   98.00,  103.83,  110.00,  116.54,  123.47,π  130.81,  138.59,  146.83,  155.56,  164.81,  174.61,  185.00,  196.00,  207.65,  220.00,  233.08,  246.94,π  261.63,  277.18,  293.66,  311.13,  329.63,  349.23,  369.99,  392.00,  415.30,  440.00,  466.16,  493.88,π  523.25,  554.37,  587.33,  622.25,  659.26,  698.46,  739.99,  783.99,  830.61,  880.00,  932.33,  987.77,π 1046.50, 1108.73, 1174.66, 1244.51, 1378.51, 1396.91, 1479.98, 1567.98, 1661.22, 1760.00, 1864.66, 1975.53,π 2093.00, 2217.46, 2349.32, 2489.02, 2637.02, 2793.83, 2959.96, 3135.96, 3322.44, 3520.00, 3729.31, 3951.07π  );ππprocedure PlayMusic(s :string);π{π  ***************************************************************************π  Accept a string similar to the BASIC PLAY statement. The following areππ  allowed:π    A to G with optional #ππ    Plays the indicated note in the current octave.π    A # following the letter indicates sharp.π    A number following the letter indicates the length of the noteπ    (4 = quarter note, 16 = sixteenth note, 1 = whole note, etc.).ππ    Onππ    Sets the octave to "n". There are 7 octaves, numbered 0 to 6. Eachπ    octave goes from C to B. Octave 3 starts with middle C.ππ    Lnππ    Sets the default length of following notes. L1 = whole notes, L2 = halfπ    notes, etc. The length can be overridden for a specific note by follow-π    ing the note letter with a number.ππ    Pnππ    Pause. n specifies the length of the pause, just like a note.ππ    Tnππ    Tempo. Number of quarter notes per minute. Default is 120.ππ    Period (.) terminates processing.ππ    Spaces are allowed between items, but not within items.π  ***************************************************************************π}ππ   VARπ      i, n,            { i is the offset in the parameter string;π                         n is the element number in MusicArea }π      NoteLength,π      Tempo,π      CurrentOctave :integer;π      cchar         :char;ππ   function GetNumber:integer;π   {π    **************************************************************************π    get a number from the parameter stringπ    increments i past the end of the numberπ    **************************************************************************π   }π      VARπ         n :integer;π      BEGINπ         n := 0;π         WHILE (i <= length(s)) and (s[i] in ['0'..'9']) doπ         BEGINπ            n := n*10+(Ord(s[i])-Ord('0'));π            i := i+1;π         end;π         GetNumber := n;π      END;ππ   procedure GetNote;π   {π    **************************************************************************π    Input is a note letter. convert it to two sound segments -- one for theπ    sound then a pause following the sound.π    increments i past the current itemπ    **************************************************************************π   }π      VARπ         note,π         len  :integer;π         l    :real;ππ      function CheckSharp(n :integer):integer;π      {π       ************************************************************************π       check for a sharp following the letter. increments i if one foundπ       ************************************************************************π      }π         BEGINπ            if (i < length(s)) and (s[i] = '#') thenπ            BEGINπ               i := i + 1;π               CheckSharp := n + 1π            ENDπ            ELSEπ               CheckSharp := n;π         END;  { CheckSharp }ππ      function FreqToCount(f : real) : integer;π      {π        ***********************************************************************π        convert a frequency to a timer countπ        ***********************************************************************π      }π         BEGINπ            FreqToCount := Round(1193180.0/f);π         END;  { FreqToCount }ππ      BEGIN  { GetNote }π         case cchar ofπ          'A' : note := CheckSharp(9);π          'B' : note := 11;π          'C' : note := CheckSharp(0);π          'D' : note := CheckSharp(2);π          'E' : note := 4;π          'F' : note := CheckSharp(5);π          'G' : note := CheckSharp(7)π         end; { case }ππ         MusicArea[n].cnt := FreqToCount(Frequency[(CurrentOctave*12)+note]);π         if (s[i] in ['0'..'9']) and (i <= length(s)) thenπ            len := GetNumberπ         elseπ            len := NoteLength;π         l := 18.2*60.0*4.0/(Tempo*len);π         MusicArea[n].tics := Round(7.0*l/8.0);ππ         if MusicArea[n].tics = 0 thenπ            MusicArea[n].tics := 1;π         n := n + 1;π         MusicArea[n].cnt := 0;π         MusicArea[n].tics := Round(l/8.0);ππ         if MusicArea[n].tics = 0 thenπ            MusicArea[n].tics := 1;π         n := n + 1;π      END;  { GetNote }ππ      procedure GetPause;π      {π       ************************************************************************π       input is a pause. convert it to a silent sound segment.π       increments i past the current itemπ       ************************************************************************π      }π         VARπ            len  :integer;π            l    :real;ππ         BEGIN  { GetPause }π            MusicArea[n].cnt := 0;π            if (s[i] in ['0'..'9']) and (i <= length(s)) thenπ               len := GetNumberπ            elseπ               len := NoteLength;π            l := 18.2*60.0*4.0/(Tempo*len);π            MusicArea[n].tics := Round(l);π            if MusicArea[n].tics = 0 thenπ               MusicArea[n].tics := 1;π            n := n + 1;π         END;  { GetPause }ππ   BEGIN { PlayMusic }π      NoteLength := 4;π      Tempo := 120;π      CurrentOctave := 3;ππ      n := 1;π      i := 1;π      while (i <= length(s)) and (s[i]<>'.') doπ      BEGINπ         cchar := s[i];π         i := i + 1;π         case cchar ofπ          'A'..'G' : GetNote;π          'O'      : CurrentOctave := GetNumber;π          'L'      : NoteLength    := GetNumber;π          'P'      : GetPause;π          'T'      : Tempo         := Getnumberπ         end; { case }π      END;π      BGSPlay(n-1, MusicArea)π   END; { PlayMusic }ππBEGIN { Unit init code }π  ExitSave := ExitProc;π  ExitProc := @BGSErrorExit;ππ  GetIntVec($1C, _BGSOldInt1C);ππ  Writeln('BGS v'+BGSVer);πEND.ππ(*   DEMO PROGRAM FOR BACKGROUND SOUND *)ππ{$M 1024, 0, 0}πProgram PlayBG;ππUsesπ   DOS,π   CRT,π   BGSND;ππVARπ   F1              :text;π   play_str, buf,π   fname, progname :string;ππProcedure Usage;π   BEGINπ      Writeln('PLAYBG <playfile>');π      Writeln(#10+#13+'Where:');π      Writeln(' <playfile> is the file containing the music you want played in');π      Writeln('            the background');π      Writeln(#10+#13+'The playfile contains a series of notes in ascii format');π      Writeln;π      Halt(1);π   END;ππ{$I-}πFunction Exists(name:string):boolean;π   VARπ      F :file;π   BEGINπ      Assign(f, name);π      Reset(f);π      if IOresult<>0 thenπ         Exists := FALSEπ      ELSEπ      BEGINπ         Exists := TRUE;π         Close(f);π      END;π   END;π{$I+}ππFunction AskYN:boolean;π   VARπ      ch :char;π   BEGINπ      repeatπ         ch := ReadKey;π         if ch = #0 thenπ         BEGINπ            ch := ReadKey;π            ch := #0;π         END;π      until ch in ['y','Y','n','N'];π      Write(ch);π      case ch ofπ        'Y','y' : AskYN := TRUE;π        'N','n' : AskYN := FALSE;π      END;π   END;ππBEGINπ   Writeln('Background Play 1.0');ππ   if ParamCount<1 thenπ      Usage;ππ   fname := ParamStr(1);π   Assign(F1, fname);ππ   if (fname='') or not(Exists(fname)) thenπ   BEGINπ      Writeln('Invalid playfile.');π      Halt(2);π   END;ππ   play_str := '';π   Reset(F1);ππ   repeatπ      ReadLn(F1, buf);π      play_str := play_str+buf;π   until Eof(F1) or (Length(play_str)>=200);ππ   Close(F1);ππ   Writeln(play_str);  {debug}π   PlayMusic(play_str);ππ   Exec(GetEnv('COMSPEC'), '');ππ   if BGSPlaying thenπ   BEGINπ       Writeln('Music still playing - wait for it to finish?');π       if Not(AskYN) thenπ          _BGSStopPlay;π       while BGSPLaying do;π   END;πEND.ππ(*ππXX34 Of OBJ CODE FILES.  Extract to separte files and use XX3401 toπcreate BGS.OBJ and PLAYFIL.ASC.  Here is how to use :ππ1. Copy first block to BGS.XX.π2. run XX3401 : XX3401 D BGS.XX.  This will create BGS.OBJ.π3. Copy second block to PLAYFIL.XX.π4. run XX3401 : XX3401 D PLAYFIL.XXπ5. Write unit code to BGSND.PAS.  Compile.π6. Write demo code to PLAYSND.PAS Compile and run.ππππ*XX3401-000674-210393--68--85-48874---------BGS.OBJ--1-OF--1πU-U+3aIuL4ZWPJlWNrBjRKtYL47bQmt-IooeW0++++-IRL7WPm--QrBZPK7gNL6U63NZπQbBdPqsUAWskAMS65U-+uF6-RFcKNHdQOK7hL47bQqxpPaFQMaRn9Y3HHJ46+k-+uImKπ+U++O6U1+20VZ7M9++F2EJF--2F-J22Xa+Q+G++++UA-2tM9++F1HoF3-2BDF2IVa+Q+π8Bo+-+I-Icl3++lTEYRHHZJBGJF3HJA+13x0FpBCFJVIGJF3HE+ALo75IoxAF2ZCJ131π++lTEYRHF3JGEJF7Hos+0Y75Ip-AEJZ7HYQ+ZN+L+++023x0FpBEH23NHYJMJ2ZIFIp3π+++XY-++++67Lo75IoZCJ131WE++Ad+F+++00Zx0FpBHFJF7HZE6+++tY-A+++6ALo75πIpBIHp-EH23N8E++Pt+F+++00Zx0FpBHEJN3F3A0++-EW+E+E86-YO1T++60+0uA5U++πmpK9v9U++6v+WoM8gEHqsMjsWoM4yei9FUWfysjZLQc4+9UQ+30V+U-EcE++I+vcnzzYπMGHsta54-U+++AhJWymV++-6ck++g9PaEwEy+++aWULaEWO8FE5aEWO9FE8X+++aUno+πR+PYMEk1ta52DU++XII2XA8X++073U6+WyJRmpK9v3-HIJ7KJls4ymuC5U++cE++G8A+π+6Ay++++RGbYMGHsta41DU+++5IMi-k+I820+30V++-E1iV1zwM4++++ukKE1iVozkQTπLptOKJhMWyJRnsmQLU12+pE0l0k4+ED2A+M-+wEz-U23l2Q4+E52GkM-+QFH-U20l4I4π+EH2REM-+gFx-U20l624+E92ZZE0l7Y4+EH2bEM--AGV-U22l8s4+E52i+M-+wGw-U21πlAI4+EJrWU6++5E+π***** END OF XX-BLOCK *****ππ{-------------------------  CUT HERE -------------------------------}ππ*XX3401-000047-210393--68--85-51905-----PLAYFIL.ASC--1-OF--1πJ1Uk62wo62ks62R4FIN5FoQUI1UUFYN4B0-5EY6o62R4FIN5FoQUFoN4FoN31Ec+π***** END OF XX-BLOCK *****ππ*)πππ                                                      18     06-08-9308:27ALL                      MARK LEWIS               Raw Speaker Support      IMPORT              13     ■"àÜ (*π===========================================================================π BBS: Canada Remote SystemsπDate: 05-31-93 (17:52)             Number: 24475πFrom: MARK LEWIS                   Refer#: NONEπ  To: CHARLES LUMIA                 Recvd: NOπSubj: PC SPEAKER AND RAW SO          Conf: (1221) F-PASCALπ---------------------------------------------------------------------------π > Do you know how to send stuff to a PC speaker, I can't even findπ > the port # for it OR how to output any data through it?ππtry this on for size ... these are three TP 6.0 Assembler routines that "mimic"πthe same ones that come in TP's CRT unit. DELAY was given to me by Sean Palmerπ(thanks sean! it works as advertised -=B-) and the other two i hacked outπmyself...ππprocedure delay(ms : word); Assembler;π{ms is the number of milliseconds to delay. 1000ms = 1second}π*)ππasmπ  mov ax,1000π  mul msπ  mov cx,dxπ  mov dx,axπ  mov ah,$86π  int $15πend;ππprocedure sound( hertz : word); Assembler;π{hertz is the sound frequency to send to the speaker port}ππasmπ  MOV    BX,SPπ  MOV    BX,&hertzπ  MOV    AX,34DDhπ  MOV    DX,0012hπ  CMP    DX,BXπ  JNB    @J1π  DIV    BXπ  MOV    BX,AXπ  IN     AL,61hπ  TEST   AL,03hπ  JNZ    @J2π  OR     AL,03hπ  OUT    61h,ALπ  MOV    AL,-4Ahπ  OUT    43h,ALπ@J2:π  MOV    AL,BLπ  OUT    42h,ALπ  MOV    AL,BHπ  OUT    42h,ALπ@J1:πend;ππprocedure nosound; Assembler;π{turns the speaker off}πasmπ  IN     AL,61hπ  AND    AL,0FChπ  OUT    61h,ALπend;ππ                                                             19     06-22-9309:24ALL                      SWAG SUPPORT TEAM        Sonic effects            IMPORT              19     ■"ï UNIT Tones;ππ{ TONES - a set of functions that provide someπ  interesting sonic effects.  Useful for gamesπ  or alerts.                                    }ππINTERFACEππPROCEDURE Tone(CycleLen,NbrCycles: Integer);πPROCEDURE Noise(D: Longint);πPROCEDURE Chirp(F1,F2,Cycles: Integer);πPROCEDURE Sound2(F: Longint);πPROCEDURE NoSound2;ππIMPLEMENTATIONππ{ Tone - output a toneππ  INP:    cyclen - Length (counts) for 1/2 cycleπ         numcyc - number of cycles to make  }ππPROCEDURE Tone(CycleLen,NbrCycles: Integer);ππVARπ    T,I,J : Integer;ππBEGINπ   NbrCycles := NbrCycles SHL 1;  {# half Cycles}π    T := Port[$61];                {Port contents}π    FOR I := 1 TO NbrCycles DOπ        BEGINπ          T := T XOR 2;π          Port[$61] := T;π        FOR J :=1 TO CycleLen DOπ      ENDπEND;πππ{ Noise - make noise for a certain amount ofπ  counts.ππ  INP:   D - the number of kilocounts of Noise}ππPROCEDURE Noise(D: Longint);πVARπ    Count : Longint;π    T,J,I : Integer;πBEGINπ    T := Port[$61];π    Count := 0;π    WHILE Count < D DOπ      BEGINπ         J := (Random(32768) MOD 128) SHL 4;π         FOR I := 1 TO J DO;π         T := T XOR 2;π           Port[$61] := T;π            Inc(Count,J)π      ENDπEND;ππ{ Chirp - create a 'bird Chirp' TYPE Noiseππ  INP:F1 - # OF counts FOR the starting freq.π         F2 - # OF counts FOR the ending freq.π  Cycles - # OF Cycles OF each frequency }ππPROCEDURE Chirp(F1,F2,Cycles: Integer);πVARπ    I,J,K,L : Integer;πBEGINπ    L := Port[$61];π    Cycles := Cycles * 2;π    I := F1;π    WHILE I <> F2 DOπ        BEGINπ            FOR J := 1 TO Cycles DOπ                BEGINπ                    L := L XOR 2;π                    Port[$61] := L;π                    FOR K := 1 TO I DOπ                END;π            IF F1 > F2 THEN Dec(I)π            ELSE Inc(I)π        ENDπEND;ππ{ Sound2 - Generate a continuous tone using theπ  internal timer.ππ  INP:    F - the desired frequeny }ππPROCEDURE Sound2(F: Longint);πVARπ    C : Longint;πBEGINπ    IF F < 19 THEN F := 19;         {Prevent overflow}π    C := 1193180 DIV F;π    Port[$43] := $B6;         {Program new divisor}π    Port[$42] := C MOD 256;   {Rate into the timer}π    Port[$42] := C DIV 256;π    C := Port[$61];         {Enable speaker output}π    Port[$61] := C OR 3     {from the timer       }πEND;πππ{ NoSound2 - turn off the continuous tone           }ππPROCEDURE NoSound2;πVARπ    C : Integer;πBEGINπ    C := Port[$61];             {Mask off speaker}π    Port[$61] := C AND $FC      {output from timer}πEND;ππEND.π                                 20     07-16-9306:01ALL                      MARK SHADARAM            Detect Adlib Sound Card  IMPORT              16     ■"Qc ===========================================================================π BBS: Canada Remote SystemsπDate: 06-25-93 (17:55)             Number: 27742πFrom: T.C. DOYLE                   Refer#: NONEπ  To: ALL                           Recvd: NO  πSubj: Pascal Code How To Detect      Conf: (1221) F-PASCALπ---------------------------------------------------------------------------π I found this in the shareware echo...hmm...wrong place:)π So I decided to forward this message here:ππππ * Originally By: Mark Shadaramπ * Originally To: Allπ * Originally Re: Pascal Code How To Detect Adlib Sound Cardπ * Original Area: <FIDO> Shareware Forumπ * Forwarded by : Blue Wave v2.12ππ{ How to Detect Adlib Sound Card}π{ Coded By Mark Shadaram ( mark.shadaram@oubbs.telecom.uoknor.edu)}πProcedure SetAdlib(Address, Data:Byte);  VAR X,I:Byte;πBEGIN Port[$388]:=Address;π      for I:= 1 to 6 do X:=Port[$388];  {Delay}π      Port[$389]:=Data;π      for I:= 1 to 35 do X:=Port[$388]; {Delay}πEND;πFunction DetectAdlib:Boolean; VAR X,X2:Byte;πBEGIN SetAdlib($4,$60);                  {Step 1}π      SetAdlib($4,$80);                  {Step 2}π      Delay(10);{Just to make sure!}π      X:=Port[$388];                     {Step 3}π      SetAdlib($2,$ff);                  {Step 4}π      SetAdlib($4,$21);                  {Step 5}π      Delay(10);{Just to make sure!}     {Step 6}π      X2:=Port[$388];                    {Step 7}π      SetAdlib($4,$60);                  {Step 8}π      SetAdlib($4,$80);π      X:= X AND $E0;                     {Step 9}π      X2:= X2 AND $E0;π      IF (X =$0) AND (X2 =$C0) THENπ      DetectAdlib:=TRUE ELSE DetectAdlib:=FALSE;πEND;ππ-!- Tag 2.6e + FMail 0.94π ! Origin: NightShift / Wichita Falls, TX (817)855-1526 (1:3805/13)ππ--- GEcho/Telegardπ * Origin: Never mind the bollocks here's TEROX BBS (1:120/324.0)π                                                                                 21     07-16-9306:29ALL                      SWAG SUPPORT TEAM        Play CMF Files on SB     IMPORT              103    ■"DG UNIT CMFTool;π{** Unit - uses SBFMDRV.COM **}πINTERFACEπUSES Dos;πTYPEπ  CMFFileTyp = FILE;π  CMFDataTyp = Pointer;π  CMFHeader = RECORDπ    CMFFileID         : ARRAY[0..3] OF CHAR;π    CMFVersion        : WORD;π    CMFInstrBlockOfs  : WORD;π    CMFMusicBlockOfs  : WORD;π    CMFTickPerBeat    : WORD;π    CMFClockTicksPS   : WORD;π    CMFFileTitleOfs   : WORD;π    CMFComposerOfs    : WORD;π    CMFMusicRemarkOfs : WORD;π    CMFChannelsUsed   : ARRAY[0..15] OF CHAR;π    CMFInstrNumber    : WORD;π    CMFBasicTempo     : WORD;π  END;πCONSTπ   CMFToolVersion       = 'v1.0';πVARπ   CMFStatusByte      : BYTE;π   CMFErrStat         : WORD;π   CMFDriverInstalled : BOOLEAN;π   CMFDriverIRQ       : WORD;π   CMFSongPaused      : BOOLEAN;π   OldExitProc        : Pointer;πPROCEDURE PrintCMFErrMessage;πFUNCTION  CMFGetSongBuffer(VAR CMFBuffer : Pointer; CMFFile : STRING):BOOLEAN;πFUNCTION  CMFFreeSongBuffer (VAR CMFBuffer : Pointer):BOOLEAN;πFUNCTION  CMFInitDriver : BOOLEAN;πFUNCTION  CMFGetVersion : WORD;πPROCEDURE CMFSetStatusByte;πFUNCTION  CMFSetInstruments(VAR CMFBuffer : Pointer):BOOLEAN;πFUNCTION  CMFSetSingleInstruments(VAR CMFInstrument:Pointer; No:WORD):BOOLEAN;πPROCEDURE CMFSetSysClock(Frequency : WORD);πPROCEDURE CMFSetDriverClock(Frequency : WORD);πPROCEDURE CMFSetTransposeOfs (Offset : INTEGER);πFUNCTION  CMFPlaySong(VAR CMFBuffer : Pointer) : BOOLEAN;πFUNCTION  CMFStopSong : BOOLEAN;πFUNCTION  CMFResetDriver:BOOLEAN;πFUNCTION  CMFPauseSong : BOOLEAN;πFUNCTION  CMFContinueSong : BOOLEAN;πIMPLEMENTATIONπTYPEπ   TypeCastTyp = ARRAY [0..6000] of Char;πVARπ   Regs : Registers;π   CMFIntern : ^CMFHeader; { Internal pointer to CMF structure }πPROCEDURE PrintCMFErrMessage;π{ PURPOSE : Displays SB error as text; no change to error status. }πBEGINπ   CASE CMFErrStat OFπ      100 : Write(' SBFMDRV sound driver not found ');π      110 : Write(' Driver reset successful ');π      200 : Write(' CMF file not found ');π      210 : Write(' No memory free for CMF file ');π      220 : Write(' File not in CMF format ');π      300 : Write(' Memory allocation error occurred ');π      400 : Write(' Too many instruments defined ');π      500 : Write(' CMF data could not be played ');π      510 : Write(' CMF data could not be stopped ');π      520 : Write(' CMF data could not be paused ');π      530 : Write(' CMF data could not be continued ');π      END;π   END;πFUNCTION Exists (Filename : STRING):BOOLEAN;π{ PURPOSE : Checks for the existence of a file, and returns a Boolean exp. }πVARπ   F : File;πBEGINπ   Assign(F,Filename);π{$I-}π   Reset(F);π   Close(F);π{$I+}π   Exists := (IoResult = 0) AND (Filename <> '');π   END;πPROCEDURE AllocateMem (VAR Pt : Pointer; Size : LongInt);π{ Reserves as many bytes as Size allows, then sets the pointer in theπ  Pt variable. If not enough memory is available, Pt is set to NIL. }πVARπ   SizeIntern : WORD;πBEGINπ   Inc(Size,15);π   SizeIntern := (Size shr 4);π   Regs.AH := $48;π   Regs.BX := SizeIntern;π   MsDos(Regs);π   IF (Regs.BX <> SizeIntern) THEN Pt := NILπ   ELSE Pt := Ptr(Regs.AX,0);π   END;πFUNCTION  CheckFreeMem (VAR CMFBuffer : Pointer; CMFSize : LongInt):BOOLEAN;π{ Ensures that enough memory has been allocated for CMF file. }πBEGINπ   AllocateMem(CMFBuffer,CMFSize);π   CheckFreeMem := CMFBuffer <> NIL;π   END;πFUNCTION  CMFGetSongBuffer(VAR CMFBuffer : Pointer; CMFFile : STRING):BOOLEAN;π{ Loads file into memory; returns TRUE if load successful, FALSE if not. }πCONSTπ   FileCheck : STRING[4] = 'CTMF';πVARπ   CMFFileSize : LongInt;π   FPresent    : BOOLEAN;π   VFile       : CMFFileTyp;π   Segs        : WORD;π   Read        : WORD;π   Checkcount  : BYTE;πBEGINπ   FPresent := Exists(CMFFile);ππ{ CMF file could not be found }π   IF Not(FPresent) THEN BEGINπ      CMFGetSongBuffer := FALSE;π      CMFErrStat   := 200;π      EXITπ      END;π   Assign(VFile,CMFFile);π   Reset(VFile,1);π   CMFFileSize := Filesize(VFile);π   AllocateMem(CMFBuffer,CMFFileSize);π{ Insufficient memory for CMF file }π   IF (CMFBuffer = NIL) THEN BEGINπ      Close(VFile);π      CMFGetSongBuffer := FALSE;π      CMFErrStat   := 210;π      EXIT;π      END;π   Segs := 0;π   REPEATπ      Blockread(VFile,Ptr(seg(CMFBuffer^)+4096*Segs,Ofs(CMFBuffer^))^,$FFFF,Readπ);π      Inc(Segs);π      UNTIL Read = 0;π   Close(VFile);π{ File not in CMF format }π   CMFIntern := CMFBuffer;π   CheckCount := 1;π   REPEATπ      IF FileCheck[CheckCount] = CMFIntern^.CMFFileID[CheckCount-1]π         THEN Inc(CheckCount)π         ELSE CheckCount := $FF;π      UNTIL CheckCount >= 3;π   IF NOT(CheckCount = 3) THEN BEGINπ      CMFGetSongBuffer := FALSE;π      CMFErrStat   := 220;π      EXIT;π      END;π{ Load was successful }π   CMFGetSongBuffer := TRUE;π   CMFErrStat   := 0;π   END;πFUNCTION CMFFreeSongBuffer (VAR CMFBuffer : Pointer):BOOLEAN;π{ Frees memory allocated for CMF file. }πBEGINπ   Regs.AH := $49;π   Regs.ES := seg(CMFBuffer^);π   MsDos(Regs);π   CMFFreeSongBuffer := TRUE;π   IF (Regs.AX = 7) OR (Regs.AX = 9) THEN BEGINπ      CMFFreeSongBuffer := FALSE;π      CMFErrStat := 300π      END;π   END;πFUNCTION CMFInitDriver : BOOLEAN;π{ Checks for SBFMDRV.COM resident in memory, and resets driver }πCONSTπ   DriverCheck :STRING[5] = 'FMDRV';πVARπ   ScanIRQ,π   CheckCount  : BYTE;π   IRQPtr,π   DummyPtr    : Pointer;ππBEGINπ{ Possible SBFMDRV interrupts lie in range $80 - $BF }π   FOR ScanIRQ := $80 TO $BF DO BEGINπ      GetIntVec(ScanIRQ, IRQPtr);π      DummyPtr := Ptr(Seg(IRQPtr^), $102);π{ Check for string 'FMDRV' in interrupt program. }π      CheckCount := 1;π      REPEATπ         IF DriverCheck[CheckCount] = TypeCastTyp(DummyPtr^)[CheckCount]π            THEN Inc(CheckCount)π            ELSE CheckCount := $FF;π         UNTIL CheckCount >= 5;π      IF (CheckCount = 5) THEN BEGINπ{ String found; reset executed }π         Regs.BX := 08;π         CMFDriverIRQ := ScanIRQ;π         Intr(CMFDriverIRQ, Regs);π         IF Regs.AX = 0 THENπ            CMFInitDriver := TRUEπ         ELSE BEGINπ            CMFInitDriver := FALSE;π            CMFErrStat    := 110;π            END;π         Exit;π         ENDπ      ELSE BEGINπ{ String not found }π         CMFInitDriver := FALSE;π         CMFErrStat := 100;π         END;π      END;π   END;πFUNCTION CMFGetVersion : WORD;π{ Gets version number from SBFMDRV driver. }πBEGINπ   Regs.BX := 0;π   Intr(CMFDriverIRQ,Regs);π   CMFGetVersion := Regs.AX;π   END;πPROCEDURE CMFSetStatusByte;π{ Place driver status byte in CMFStatusByte variable. }πBEGINπ   Regs.BX:= 1;π   Regs.DX:= Seg(CMFStatusByte);π   Regs.AX:= Ofs(CMFStatusByte);π   Intr(CMFDriverIRQ, Regs);π   END;πFUNCTION CMFSetInstruments(VAR CMFBuffer : Pointer):BOOLEAN;π{ Sets SB card FM registers to instrumentation stated in CMF file. }πBEGINπ    CMFIntern := CMFBuffer;π    IF CMFIntern^.CMFInstrNumber > 128 THEN BEGINπ       CMFErrStat := 400;π       CMFSetInstruments := FALSE;π       Exit;π       END;π    Regs.BX := 02;π    Regs.CX := CMFIntern^.CMFInstrNumber;π    Regs.DX := Seg(CMFBuffer^);π    Regs.AX := Ofs(CMFBuffer^)+CMFIntern^.CMFInstrBlockOfs;π    Intr(CMFDriverIRQ, Regs);π    CMFSetInstruments := TRUE;π   END;πFUNCTION CMFSetSingleInstruments(VAR CMFInstrument:Pointer; No:WORD):BOOLEAN;π{ Sets SB FM registers to instrument values corresponding to theπ  data structure following the CMFInstrument pointer. }πBEGINπ    IF No > 128 THEN BEGINπ       CMFErrStat := 400;π       CMFSetSingleInstruments := FALSE;π       Exit;π       END;π    Regs.BX := 02;π    Regs.CX := No;π    Regs.DX := Seg(CMFInstrument^);π    Regs.AX := Ofs(CMFInstrument^);π    Intr(CMFDriverIRQ, Regs);π    CMFSetSingleInstruments := TRUE;π   END;πPROCEDURE CMFSetSysClock(Frequency : WORD);π{ Sets default value of timer 0 to new value. }πBEGINπ   Regs.BX := 03;π   Regs.AX := (1193180 DIV Frequency);π   Intr(CMFDriverIRQ, Regs);π   END;πPROCEDURE CMFSetDriverClock(Frequency : WORD);π{ Sets driver timer frequency to new value. }ππBEGINπ   Regs.BX := 04;π   Regs.AX := (1193180 DIV Frequency);π   Intr(CMFDriverIRQ, Regs);π   END;πPROCEDURE CMFSetTransposeOfs (Offset : INTEGER);π{ Transposes all notes in the CMF file by "Offset." }πBEGINπ   Regs.BX := 05;π   Regs.AX := Offset;π   Intr(CMFDriverIRQ, Regs);π   END;πFUNCTION CMFPlaySong(VAR CMFBuffer : Pointer) : BOOLEAN;π{ Initializes all important parameters and starts song playback. }πVARπ   Check : BOOLEAN;πBEGINπ   CMFIntern := CMFBuffer;π{ Set driver clock frequency }π   CMFSetDriverClock(CMFIntern^.CMFClockTicksPS);π{ Set instruments }π   Check := CMFSetInstruments(CMFBuffer);π   IF Not(Check) THEN Exit;π   Regs.BX := 06;π   Regs.DX := Seg(CMFIntern^);π   Regs.AX := Ofs(CMFIntern^)+CMFIntern^.CMFMusicBlockOfs;π   Intr(CMFDriverIRQ, Regs);π   IF Regs.AX = 0 THEN BEGINπ      CMFPlaySong := TRUE;π      CMFSongPaused := FALSE;π      ENDπ   ELSE BEGINπ      CMFPlaySong := FALSE;π      CMFErrStat := 500;π      END;π   END;πFUNCTION CMFStopSong : BOOLEAN;π{ Attempts to stop song playback. }πBEGINπ   Regs.BX := 07;π   Intr(CMFDriverIRQ, Regs);π   IF Regs.AX = 0 THENπ      CMFStopSong := TRUEπ   ELSE BEGINπ      CMFStopSong := FALSE;π      CMFErrStat  := 510;π      END;π   END;πFUNCTION CMFResetDriver:BOOLEAN;π{ Resets driver to starting status. }πBEGINπ   Regs.BX := 08;π   Intr(CMFDriverIRQ, Regs);π   IF Regs.AX = 0 THENπ      CMFResetDriver := TRUEπ   ELSE BEGINπ      CMFResetDriver := FALSE;π      CMFErrStat    := 110;π      END;π   END;πFUNCTION CMFPauseSong : BOOLEAN;π{ Attempts to pause song playback. If pause is possible, thisπ  function sets the CMFSongPaused variable to TRUE. }πBEGINπ   Regs.BX := 09;π   Intr(CMFDriverIRQ, Regs);π   IF Regs.AX = 0 THEN BEGINπ      CMFPauseSong  := TRUE;π      CMFSongPaused := TRUE;π      ENDπ   ELSE BEGINπ      CMFPauseSong := FALSE;π      CMFErrStat   := 520;π      END;π   END;πFUNCTION CMFContinueSong : BOOLEAN;π{ Attempts to continue playback of a paused song. If continuationπ  is possible, this function sets CMFSongPaused to FALSE. }πBEGINπ   Regs.BX := 10;π   Intr(CMFDriverIRQ, Regs);π   IF Regs.AX = 0 THEN BEGINπ      CMFContinueSong  := TRUE;π      CMFSongPaused    := FALSE;π      ENDπ   ELSE BEGINπ      CMFContinueSong := FALSE;π      CMFErrStat      := 530;ππ      END;π   END;π{$F+}πPROCEDURE CMFToolsExitProc;π{$F-}π{ Resets the status byte address, allowing this program to exit.}πBEGINπ   Regs.BX:= 1;π   Regs.DX:= 0;π   Regs.AX:= 0;π   Intr(CMFDriverIRQ, Regs);π   ExitProc := OldExitProc;π   END;πBEGINπ{ Reset old ExitProc to the Tool unit proc }π   OldExitProc := ExitProc;π   ExitProc := @CMFToolsExitProc;π{ Initialize variables }π   CMFErrStat := 0;π   CMFSongPaused := FALSE;π{ Initialize driver }π   CMFDriverInstalled := CMFInitDriver;π   IF CMFDriverInstalled THEN BEGINπ      CMFStatusByte := 0;π      CMFSetStatusByte;π      END;π   END.ππ{ ---------------------    DEMO PROGRAM  -----------------  }ππProgram CMFDemo;π{* Demo program for CMFTOOL unit *}π{$M 16384,0,65535}πUses CMFTool,Crt;πVARπ   Check      : BOOLEAN;π   SongName   : String;π   SongBuffer : CMFDataTyp;πPROCEDURE TextNumError;π{* INPUT   : None; data comes from CMFErrStat global variableπ * OUTPUT  : Noneπ * PURPOSE : Displays SB error as text, including error number. }πBEGINπ   Write(' Error #',CMFErrStat:3,': ');π   PrintCMFErrMessage;π   WriteLn;π   Halt(CMFErrStat);π   END;πBEGINπ   ClrScr;π{ Displays error if SBFMDRV driver has not been installed }π   IF Not (CMFDriverInstalled) THEN TextNumError;π{ If no song name is included with command line parameters,π  program searches for the default name (here STARFM.CMF). }π   IF ParamCount = 0 THEN SongName := 'STARFM.CMF'π                     ELSE SongName := ParamStr(1);π{ Display driver's version and subversion numbers }π   GotoXY(28,5);π   Write  ('SBFMDRV Version ',Hi(CMFGetVersion):2,'.');π   WriteLn(Lo(CMFGetVersion):2,' loaded');π{ Display interrupt number in use }π   GotoXY(24,10);π   Write  ('System interrupt (IRQ) ');π   WriteLn(CMFDriverIRQ:3,' in use');π   GotoXY(35,15);π   WriteLn('Song Status');π   GotoXY(31,23);π   WriteLn('Song name: ',SongName);π{ Load song file }π   Check := CMFGetSongBuffer(SongBuffer,SongName);π   IF NOT(Check) THEN TextNumError;π{ CMFSetTransposeOfs() controls transposition down or up of the loaded songπ  (positive values transpose up, negative values transpose down). The valueπ  0 plays the loaded song in its original key. }π   CMFSetTransposeOfs(0); { Experiment with this value }π{ Play song }π   Check := CMFPlaySong(SongBuffer);π   IF NOT(Check) THEN TextNumError;π{ During playback, display status byte }π   REPEATπ      GotoXY(41,17);Write(CMFStatusByte:3);π      UNTIL (KeyPressed OR (CMFStatusByte = 0));π{ Stop playback if user presses a key }π   IF KeyPressed THEN BEGINπ      Check := CMFStopSong;π      IF NOT(Check) THEN TextNumError;π      END;π{ Re-initialize driver }π   Check := CMFResetDriver;π   IF NOT(Check) THEN TextNumError;π{ Free song file memory }π   Check := CMFFreeSongBuffer(SongBuffer);π   IF NOT(Check) THEN TextNumError;π   END.π                                                                                        22     07-16-9306:30ALL                      SWAG SUPPORT TEAM        Play VOC files on SB     IMPORT              103    ■"╫e UNIT VOCTOOL;π{* Unit - uses CT-VOICE.DRV. *}πINTERFACEπTYPEπ   VOCFileTyp = File;πCONSTπ   VOCToolVersion  = 'v1.5';π   VOCBreakEnd     = 0;π   VOCBreakNow     = 1;πVARπ   VOCStatusWord        : WORD;π   VOCErrStat           : WORD;π   VOCFileHeader        : STRING;π   VOCFileHeaderLength  : BYTE;π   VOCPaused            : BOOLEAN;π   VOCDriverInstalled   : BOOLEAN;π   VOCDriverVersion     : WORD;π   VOCPtrToDriver       : Pointer;π   OldExitProc          : Pointer;πPROCEDURE PrintVOCErrMessage;πFUNCTION  VOCGetBuffer(VAR VoiceBuff : Pointer; Voicefile : STRING):BOOLEAN;πFUNCTION  VOCFreeBuffer(VAR VoiceBuff : Pointer):BOOLEAN;πFUNCTION  VOCGetVersion:WORD;πPROCEDURE VOCSetPort(PortNumber : WORD);πPROCEDURE VOCSetIRQ(IRQNumber : WORD);πFUNCTION  VOCInitDriver:BOOLEAN;πPROCEDURE VOCDeInstallDriver;πPROCEDURE VOCSetSpeaker(OnOff:BOOLEAN);πPROCEDURE VOCOutput(BufferAddress : Pointer);πPROCEDURE VOCOutputLoop (BufferAddress : Pointer);πPROCEDURE VOCStop;πPROCEDURE VOCPause;πPROCEDURE VOCContinue;πPROCEDURE VOCBreakLoop(BreakMode : WORD);πIMPLEMENTATIONπUSES DOS,Crt;πTYPEπ   TypeCastType = ARRAY [0..6000] of Char;πVARπ   Regs : Registers;πPROCEDURE PrintVOCErrMessage;π{* INPUT   : Noneπ * OUTPUT  : Noneπ * PURPOSE : Displays SB error as text; no change to error status. }πBEGINπ   CASE VOCErrStat OFπ      100 : Write(' Driver file CT-VOICE.DRV not found ');π      110 : Write(' No memory available for driver file ');π      120 : Write(' False driver file ');π      200 : Write(' VOC file not found ');π      210 : Write(' No memory available for driver file ');π      220 : Write(' File not in VOC format ');π      300 : Write(' Memory allocation error occurred ');π      400 : Write(' No sound blaster card found ');π      410 : Write(' False port address used ');π      420 : Write(' False interrupt used ');π      500 : Write(' No loop in process ');π      510 : Write(' No sample for output ');π      520 : Write(' No sample available ');π      END;π   END;ππFUNCTION Exists (Filename : STRING):BOOLEAN;π{* INPUT   : Filename as stringπ * OUTPUT  : TRUE if file is available, FALSE if notπ * PURPOSE : Checks for availability of file then returns Boolean exp. }πVARπ   F : File;πBEGINπ   Assign(F,Filename);π{$I-}π   Reset(F);π   Close(F);π{$I+}π   Exists := (IoResult = 0) AND (Filename <> '');π   END;πPROCEDURE AllocateMem (VAR Pt : Pointer; Size : LongInt);π{* INPUT   : Buffer variable as pointer, buffer size as LongIntπ * OUTPUT  : Pointer to buffer in variable or NILπ * PURPOSE : Reserves as many bytes as Size allows, then moves pointer inπ             the Pt variable. If not enough memory is available, Pt = NIL. }πVARπ   SizeIntern : WORD;πBEGINπ   Inc(Size,15);π   SizeIntern := (Size shr 4);π   Regs.AH := $48;π   Regs.BX := SizeIntern;π   MsDos(Regs);π   IF (Regs.BX <> SizeIntern) THEN Pt := NILπ   ELSE Pt := Ptr(Regs.AX,0);π   END;πFUNCTION  CheckFreeMem (VAR VoiceBuff : Pointer; VoiceSize : LongInt):BOOLEAN;π{* INPUT   : Buffer variable as pointer, size as LongIntπ * OUTPUT  : Pointer to buffer, TRUE/FALSE, after AllocateMemπ * PURPOSE : Checks for sufficient memory to store a VOC file. }πBEGINπ   AllocateMem(VoiceBuff,VoiceSize);π   CheckFreeMem := VoiceBuff <> NIL;π   END;πFUNCTION  VOCGetBuffer (VAR VoiceBuff : Pointer; Voicefile : STRING):BOOLEAN;π{* INPUT   : Buffer variable as pointer, file name as stringπ * OUTPUT  : Pointer to buffer with VOC data, TRUE/FALSEπ * PURPOSE : Loads a file into memory and returns TRUE if file loadedπ             successfully, and FALSE if not. }πVARπ   SampleSize : LongInt;π   FPresent   : BOOLEAN;π   VFile      : VOCFileTyp;π   Segs       : WORD;π   Read       : WORD;πBEGINπ   FPresent := Exists(VoiceFile);π{ VOC file not found }π   IF Not(FPresent) THEN BEGINπ      VOCGetBuffer := FALSE;π      VOCErrStat   := 200;π      EXITπ      END;π   Assign(VFile,Voicefile);π   Reset(VFile,1);π   SampleSize := Filesize(VFile);π   AllocateMem(VoiceBuff,SampleSize);π{ Insufficient memory for the VOC file }π   IF (VoiceBuff = NIL) THEN BEGINπ      Close(VFile);π      VOCGetBuffer := FALSE;π      VOCErrStat   := 210;π      EXIT;π      END;π   Segs := 0;π   REPEATπ      Blockread(VFile,Ptr(seg(VoiceBuff^)+4096*Segs,Ofs(VoiceBuff^))^,$FFFF,Readπ);π      Inc(Segs);π      UNTIL Read = 0;π   Close(VFile);π{ File not in VOC format }π   IF (TypeCastType(VoiceBuff^)[0]<>'C') ORπ      (TypeCastType(VoiceBuff^)[1]<>'r') THEN BEGINπ      VOCGetBuffer := FALSE;π      VOCErrStat := 220;π      EXIT;π      END;π{ Load successful }π   VOCGetBuffer := TRUE;π   VOCErrStat   := 0;π{ Read header length from file }π   VOCFileHeaderLength := Ord(TypeCastType(VoiceBuff^)[20]);π   END;πFUNCTION VOCFreeBuffer (VAR VoiceBuff : Pointer):BOOLEAN;π{* INPUT   : Buffer pointerπ * OUTPUT  : Noneπ * PURPOSE : Frees memory allocated for VOC data. }πBEGINπ   Regs.AH := $49;π   Regs.ES := seg(VoiceBuff^);π   MsDos(Regs);π   VOCFreeBuffer := TRUE;π   IF (Regs.AX = 7) OR (Regs.AX = 9) THEN BEGINπ      VOCFreeBuffer := FALSE;π      VOCErrStat := 300π      END;π   END;πFUNCTION VOCGetVersion:WORD;π{* INPUT   : Noneπ * OUTPUT  : Driver version numberπ * PURPOSE : Returns driver version number. }πVARπ   VDummy : WORD;πBEGINπ   ASMπ      MOV       BX,0π      CALL      VOCPtrToDriverπ      MOV       VDummy, AXπ      END;π   VOCGetVersion := VDummy;π   END;ππPROCEDURE VOCSetPort(PortNumber : WORD);π{* INPUT   : Port address numberπ * OUTPUT  : Noneπ * PURPOSE : Specifies port address before initialization. }πBEGINπ   ASMπ      MOV    BX,1π      MOV    AX,PortNumberπ      CALL   VOCPtrToDriverπ      END;π   END;πPROCEDURE VOCSetIRQ(IRQNumber : WORD);π{* INPUT   : Interrupt numberπ * OUTPUT  : Noneπ * PURPOSE : Specifies interrupt number before initialization.}πBEGINπ   ASMπ      MOV    BX,2π      MOV    AX,IRQNumberπ      CALL   VOCPtrToDriverπ      END;π   END;πFUNCTION  VOCInitDriver: BOOLEAN;π{* INPUT   : Noneπ * OUTPUT  : Error message number, and initialization resultπ * PURPOSE : Initializes driver software. }πVARπ   Out, VSeg, VOfs : WORD;π   F   : File;π   Drivername,π   Pdir        : DirStr;π   Pnam        : NameStr;π   Pext        : ExtStr;πBEGINπ{ Search path for CT-VOICE.DRV driver }π   Pdir := ParamStr(0);π   Fsplit(ParamStr(0),Pdir,Pnam,Pext);π   Drivername := Pdir+'CT-VOICE.DRV';π   VOCInitDriver := TRUE;π{ Driver file not found }π   IF Not Exists(Drivername) THEN BEGINπ      VOCInitDriver := FALSE;π      VOCErrStat    := 100;π      EXIT;π      END;π{ Load driver }π   Assign(F,Drivername);π   Reset(F,1);π   AllocateMem(VOCPtrToDriver,Filesize(F));π{ No memory can be allocated for the driver }π   IF VOCPtrToDriver = NIL THEN BEGINπ      VOCInitDriver := FALSE;π      VOCErrStat    := 110;π      EXIT;π      END;π   Blockread(F,VOCPtrToDriver^,Filesize(F));π   Close(F);π{ Driver file doesn't begin with "CT" - false driver }π   IF (TypeCastType(VOCPtrToDriver^)[3]<>'C') ORπ      (TypeCastType(VOCPtrToDriver^)[4]<>'T') THEN BEGINπ         VOCInitDriver := FALSE;π         VOCErrStat    := 120;π         EXIT;π         END;π{ Get version number and pass to global variable }π   VOCDriverVersion := VOCGetVersion;π{ Start driver }π   Vseg := Seg(VOCStatusWord);π   VOfs := Ofs(VOCStatusWord);π   ASMπ      MOV       BX,3π      CALL      VOCPtrToDriverπ      MOV       Out,AXπ      MOV       BX,5π      MOV       ES,VSegπ      MOV       DI,VOfsπ      CALL      VOCPtrToDriverπ      END;π{ No Sound Blaster card found }π   IF Out = 1 THEN BEGINπ      VOCInitDriver := FALSE;π      VOCErrStat    := 400;π      EXIT;π      END;π{ False port address used }π   IF Out = 2 THEN BEGINπ      VOCInitDriver := FALSE;π      VOCErrStat    := 410;π      EXIT;π      END;π{ False interrupt used }π   IF Out = 3 THEN BEGINπ      VOCInitDriver := FALSE;π      VOCErrStat    := 420;π      EXIT;π      END;π   END;πPROCEDURE VOCDeInstallDriver;π{* INPUT   : Noneπ * OUTPUT  : Noneπ * PURPOSE : Disables driver and releases memory. }πVARπ   Check : BOOLEAN;πBEGINπ   IF VOCDriverInstalled THENπ   ASMπ      MOV       BX,9π      CALL      VOCPtrToDriverπ      END;π   Check := VOCFreeBuffer(VOCPtrToDriver);π   END;πPROCEDURE VOCSetSpeaker(OnOff:BOOLEAN);π{* INPUT   : TRUE=Speaker on, FALSE=Speaker offπ * OUTPUT  : Noneπ * PURPOSE : Sound Blaster output status. }πVARπ   Switch : BYTE;πBEGINπ   Switch := Ord(OnOff) AND $01;π   ASMπ      MOV       BX,4π      MOV       AL,Switchπ      CALL      VOCPtrToDriverπ      END;π   END;πPROCEDURE VOCOutput (BufferAddress : Pointer);π{* INPUT   : Pointer to sample dataπ * OUTPUT  : Noneπ * PURPOSE : Plays sample. }πVARπ   VSeg, VOfs : WORD;πBEGINπ   VOCSetSpeaker(TRUE);π   VSeg := Seg(BufferAddress^);π   VOfs := Ofs(BufferAddress^)+VOCFileHeaderLength;π   ASMπ      MOV       BX,6π      MOV       ES,VSegπ      MOV       DI,VOfsπ      CALL      VOCPtrToDriverπ      END;π   END;πPROCEDURE VOCOutputLoop (BufferAddress : Pointer);π{*    Different from VOCOutput :π *    Speaker does not switch on with every sample output, so aπ *    crackling noise may occur with some Sound Blaster cards. }πVARπ   VSeg, VOfs : WORD;πBEGINπ   VSeg := Seg(BufferAddress^);π   VOfs := Ofs(BufferAddress^)+VOCFileHeaderLength;π   ASMπ      MOV       BX,6π      MOV       ES,VSegπ      MOV       DI,VOfsπ      CALL      VOCPtrToDriverπ      END;π   END;πPROCEDURE VOCStop;π{* INPUT   : Noneπ * OUTPUT  : Noneπ * PURPOSE : Stops a sample. }πBEGINπ   ASMπ      MOV       BX,8π      CALL      VOCPtrToDriverπ      END;π   END;πPROCEDURE VOCPause;π{* INPUT   : Noneπ * OUTPUT  : Noneπ * PURPOSE : Pauses a sample. }πVARπ   Switch : WORD;πBEGINπ   VOCPaused := TRUE;π   ASMπ      MOV       BX,10π      CALL      VOCPtrToDriverπ      MOV       Switch,AXπ      END;π   IF (Switch = 1) THEN BEGINπ      VOCPaused := FALSE;π      VOCErrStat := 510;π      END;π   END;πPROCEDURE VOCContinue;π{* INPUT   : Noneπ * OUTPUT  : Noneπ * PURPOSE : Continues a paused sample. }πVARπ   Switch : WORD;πBEGINπ   ASMπ      MOV       BX,11π      CALL      VOCPtrToDriverπ      MOV       Switch,AXπ      END;π   IF (Switch = 1) THEN BEGINπ      VOCPaused := FALSE;π      VOCErrStat := 520;π      END;π   END;πPROCEDURE VOCBreakLoop(BreakMode : WORD);π{* INPUT   : Break modeπ * OUTPUT  : Noneπ * PURPOSE : Breaks a sample loop. }πBEGINπ   ASMπ      MOV       BX,12π      MOV       AX,BreakModeπ      CALL      VOCPtrToDriverπ      MOV       BreakMode,AXπ      END;π   IF (BreakMode = 1) THEN VOCErrStat := 500;π   END;π{$F+}πPROCEDURE VoiceToolsExitProc;π{$F-}π{* INPUT   : Noneπ * OUTPUT  : Noneπ * PURPOSE : De-installs voice driver. }πBEGINπ   VOCDeInstallDriver;π   ExitProc := OldExitProc;π   END;πBEGINπ{* The following statements execute automatically, as soon as theπ * unit is linked to a program, and the program starts. }π{ Replaces old ExitProc with new one from Tool unit }π   OldExitProc := ExitProc;π   ExitProc := @VoiceToolsExitProc;π{ Initialize values }π   VOCStatusWord := 0;π   VOCErrStat    := 0;π   VOCPaused     := FALSE;π   VOCFileHeaderLength := $1A;π   VOCFileHeader :=π      'Creative Voice File'+#$1A+#$1A+#$00+#$0A+#$01+#$29+#$11+#$01;π{* After installation, VOCDriverInstalled contains either TRUE or FALSE. }π   VOCDriverInstalled := VOCInitDriver;π   END.πππ{    -----------------------    DEMO PROGRAM  --------------------------}ππPROGRAM VToolTest;π{* VTTEST.PAS - uses VOCTOOL.TPU *}ππ{$M 16000,0,50000}πUSES Crt,Voctool;πVARπ   Sound : Pointer;π   Check : BOOLEAN;π   Ch    : CHAR;πPROCEDURE TextNumError;π{* INPUT   : None; data comes from the VOCErrStat global variableπ * OUTPUT  : Noneπ * PURPOSE : Displays SB error on the screen as text, including theπ             error number. Program then ends at the error levelπ             corresponding to the error number. }πBEGINπ   Write(' Error #',VOCErrStat:3,' =');π   PrintVOCErrMessage;π   WriteLn;π   HALT(VOCErrStat);π   END;ππBEGINπ  ClrScr;ππ{ Driver not initialized }π  IF Not(VOCDriverInstalled) THEN TextNumError;π{ Loads DEMO.VOC file into memory }π  Check := VOCGetBuffer(Sound,'\SBPRO\MMPLAY\SBP.VOC');π{ VOC file could not be loaded }π  IF Not(Check) THEN TextNumError;π{ Main loop }π  Write('CT-Voice Driver Version : ');π  WriteLn(Hi(VOCDriverVersion),'.',Lo(VOCDriverVersion));π  WriteLn('(S)ingle play or (M)ultiple play?');π  Write('Press a key : '); Ch := ReadKey;WriteLn;WriteLn;π  CASE UpCase(Ch) OFπ   'S' : BEGINπ            Write('Press a key to stop the sound...');π            VOCOutput(Sound);π            REPEAT UNTIL KeyPressed OR (VOCStatusWord = 0);π            IF KeyPressed THEN VOCStop;π            END;π   'M' : BEGINπ            Ch := #0;π            Write('Press <ESC> to cancel...');π            REPEATπ               VOCOutputLoop(Sound);π               REPEAT UNTIL KeyPressed OR (VOCStatusWord = 0);π               IF KeyPressed THEN Ch := ReadKey;π               UNTIL Ch = #27;π            VOCStop;π            END;π   END;π{ Free VOC file memory }π  Check := VOCFreeBuffer(Sound);π  IF Not(Check) THEN TextNumError;π  END.π                                                                                                             23     08-17-9308:50ALL                      STEVE WIERENGA           Control Speaker          IMPORT              23     ■"Qc ===========================================================================π BBS: Canada Remote SystemsπDate: 07-11-93 (13:22)             Number: 30113πFrom: STEVE WIERENGA               Refer#: NONEπ  To: TRAVIS GRIGGS                 Recvd: NO  πSubj: SPEAKER(OFF)                   Conf: (1221) F-PASCALπ---------------------------------------------------------------------------πHello Travis:ππ >> { untested, but should work }π >> {$M 1024,0,0}π >> {$F+}π >> uses DOS;π >> Varπ >>   Old1C : Procedure;π TG>π >> Procedure SpeakerOff; Interrupt;π >> Beginπ >>     ASM { no sound proc, removes need to use CRT unit in a TSR }π >>       mov dx,061hπ >>       in al,dxπ >>       and al,11111100bπ >>       out dx,alπ >>       pushfπ >>     End;π >>     Old1C;π >> End;π TG>π >> Beginπ >>   GetIntVec ($1C,@Old1C);π >>   SetIntVec ($1C,@SpeakerOff);π >>   Keep(0);π >> End.π TG>π TG> I'm trying to learn to write a TSR.  Could you explain every step andπ TG> why it's there?  Thanks...ππI didn't write that code, actually.  I have never written a TSR and don't planπto in the near future, so I suggest you ask one of the gurus here.ππ >> --- FMail 0.90π TG>π TG> Fmail 0.94 is out.  You should get it.  It's much better...ππI'm still with .90 because I can't afford to register .94 (.90 doesn't have aπregistration) :-(.πTake Care, SteveπShockwave Software Systemsππ--- FMail 0.90π * Origin: The Programmer's Armpit... Home of Monsoon*Qomm! (1:2613/228.2)π===========================================================================π BBS: Canada Remote SystemsπDate: 07-10-93 (11:08)             Number: 30157πFrom: STEVEN TALLENT               Refer#: NONEπ  To: NIELS LANGKILDE               Recvd: NO  πSubj: RE: SPEAKER(OFF)               Conf: (1221) F-PASCALπ---------------------------------------------------------------------------π -=> Quoting Niels Langkilde to Everyone <=-ππ NL> Is it possible to diable/enable the speaker output (alternatvlyπ NL> redirect it) ?? If so, please help !ππThe only thing that can be done is disabling the speaker many timesπa second to do it.  Here's some code that disables it 18 times a second,πbut notably does NOT work with programs that shut down interruptsπduring playback.ππ{$M 1024,0,0}π{$N-,S-,G+} { Use g- for 8088 systems, g+ for V20 and above }πPROGRAM NoSpeak;πUSES Dos;πVAR OLDINT1C : Procedure;ππPROCEDURE ShutOff; INTERRUPT;πBEGINπ  Port [97] := Port[97] and 253; {Turn off speaker}π  OldInt1C;π  end;ππBEGINπ  GetIntVec($1C, @OldInt1C);π  SetIntVec($1C, @ShutOff);π  Keep(0);π  end.ππNote this is a TSR, and I can't guarantee that it'll work right onπanyone's computer.ππ___ Blue Wave/QWK v2.12π--- Renegade v06-25 Betaπ * Origin: Pink's Place  (409)883-8344 735-3712 (1:3811/210)π                                                                            24     08-27-9319:58ALL                      STEVEN TALLEN            8bit raw sounds          IMPORT              49     ■"╬╗ {ππ SoundS.INC  5-27-93  by Steven TallentππThis is a Unit to play 8-bit raw Sound Files on any PC, up to 64kπlarge.  It supports the PC speaker or a DAC (LPT1 or LPT2), althoughπI do plan to upgrade it to support the SoundBlaster and Adlib Soundπcards.  It is Object-oriented in nature, With one instance of aπspeaker defined automatically.  This Unit is public domain, Withπcode and ideas captured from this echo and Dr. Dobbs Journal.ππUsing the code is simple.  Just setup the the Speaker.Kind,πSpeaker.Silent, and Speaker.DisINT to the appropriate values, thenπjust use the methods included.  The SoundBoard Object is veryπflexible For your own code.ππSoundBoard.Play  - Plays 8-bit music in What^ For Size length, Withπ                   Speed milliseconds between each Byte, and SampleRateπ                   as the sample rate (in Hz).  Speed will need to beπ                   changed on different computers (of course).ππSoundBoard.Sound - Plays a Sound at HZ Hertz, Duration in ms, onπ                   VOICE voice.  The code included is useable onπ                   the PC speaker (1 voice) or the Tandy speakerπ                   (3 voices!).ππSoundBoard.Reset - Resets the Sound board.ππSoundBoard.Silent- Convenient Variable that disables all PLAY and Soundπ                   if set to True.ππSoundBoard.DisINT- Disables all interrupts (except during Delays)π                   While using PLAY.ππThis code may be freely distributed, changed, or included in yourπown commercial or shareware code, as long as this isn't all your codeπdoes.  This code may be included in commercial or shareware codeπlibraries only With my permission (I'd like to see someone get someπuse out of it).π}ππUnit Sounds;ππInterfaceππTypeπ  BigArray    = Array[0..0] of Byte;π  PBigArray   = ^BigArray;π  KSoundBoard = (PCspeaker, Tandy, DAC1, DAC2, AdLib, SB, SBpro, SB16);ππ  SoundBoard  = Objectπ    Kind   : KSoundBoard;π    Silent : Boolean;π    DisINT : Boolean;π    Procedure Play(What : PBigArray; Size : Word; Speed : Byte;π                    SampleRate : Word);π    Procedure Sound(Hz, Duration : Word; Voice, Volume : Byte);π    Procedure Reset;π  end;ππVarπ  Speaker : SoundBoard;ππProcedure Delay(ms : Word);ππImplementationππProcedure SoundBoard.Reset;πbeginπ  Case Kind ofπ    PCspeaker, Tandy : Port[97] := Port[97] and $FC;π  end;π  end;ππProcedure SoundBoard.Sound(Hz, Duration : Word; Voice, Volume : Byte);πVarπ  Count   : Word;π  SendByte,π  VoiceID : Byte;πbeginπ  Case Kind ofπ    PCspeaker :π      beginπ        Count := 1193180 div Hz;π        Port[97] := Port[97] or 3;π        Port[67] := 182;π        Port[66] := Lo(Count);π        Port[66] := Hi(Count);π        Delay(Duration);π        Port[97] := Port[97] and $FC;π      end;π    Tandy :π      beginπ        if Voice = 1 thenπ          VoiceId := 0π        elseπ        if Voice = 2 thenπ          VoiceId := 32π        elseπ          VoiceId := 64;π        Count := 111861 div Hz;π        SendByte := 128 + VoiceId + (Count mod 16);π        Port [$61] := $68;π        Port [$C0] := SendByte;π        Port [$C0] := Count div 16;π        if Voice = 1 thenπ          VoiceId := 16π        elseπ        if Voice = 2 thenπ          VoiceId := 48π        elseπ          VoiceId := 96;π        SendByte := 128 + VoiceId + (15 - Volume);π        Port [$61] := $68;π        Port [$C0] := SendByte;π        Delay(Duration);π        SendByte := 128 + VoiceId + 15;π        Port [$61] := $68;π        Port [$C0] := SendByte;π    DAC1:;π    DAC2:;π    AdLib:;π    SB:;π    SBPro:;π    SB16:;π  end;ππProcedure SoundBoard.Play(What : PBigArray; Size : Word;π                          Speed : Byte; SampleRate : Word);πVarπ  Loop,π  Count,π  Data  : Word;πbeginπ  if not Silent thenπ  beginπ    Case Kind ofπ      PCspeaker, Tandy :π        beginπ          Port[97] := Port[97] or 3;π          Count := 1193180 div (SampleRate div 256);π          For Loop := 1 to Size doπ          beginπ            Data := Count div (What^[Loop] + 1);π            Port[67] := 182;π            Port[66] := Lo(Data);π            Port[66] := Hi(Data);π            Delay(Speed);π            if DisINT thenπ            Asmπ              CLIπ            end;π          end;π          Port[97] := Port[97] and $FC;π        end;ππ        DAC1:π          For Loop := 1 to Size doπ          beginπ            Port [$0378] := What^[Loop];π            Delay (Speed);π            if DisINT thenπ            Asmπ              CLIπ            end;π          end;ππ        DAC2:π          For Loop := 1 to Size doπ          beginπ            Port [$0278] := What^[Loop];π            Delay (Speed);π            if DisINT thenπ            Asmπ              CLIπ            end;π          end;ππ        AdLib:;π        SB:;π        SBPro:;π        SB16:;π      end;π      Asmπ        STIπ      end;π  end;πend;ππProcedure Delay(ms : Word); Assembler;πAsmπ  STIπ  MOV AH, $86π  MOV CX, 0π  MOV DX, [ms]π  INT $15πend;ππend.ππ{-----------------------------------------------------------------πHere's a Program that will accept three values from the commandπline, the File, its speed, and the sample rate, and plays itπthrough the PC speaker.  I've tried in on WAV, VOC, SAM, and evenπAmiga sampled Files, With no problems (limited to 64k). I've evenπplayed MOD Files to hear all the sampled instruments!  This Programπdoes not strip header information, but plays it too, but I can'tπhear the difference on WAV and VOC Files.π}πProgram TestSnd;πUsesπ  Sounds;πVarπ  I2   : PBigArray;π  spd  : Integer;π  samp : Word;π  res  : Word;π  siz  : Word;π  s    : String;π  f1   : File of Byte;π  F    : File;πbeginπ  Speaker.Kind   := PCspeaker;π  Speaker.DisINT := True;π  Speaker.Silent := False;π  s := ParamStr(1);π  Assign(f1,s);  {Get size of File}π  Reset(f1);π  Val (ParamStr(2), Spd, Res);π  Val (ParamStr(3), samp, Res);π  siz := FileSize(f1);π  close(f1);π  Assign(f,s);π  Reset(f);π  getmem (I2,siz);  {Allocate Memory For Sound File}π  BlockRead(f,I2^,siz,res);  {Load Sound into Memory}π  Speaker.Play (i2, siz, spd, samp);π  FreeMem (I2, siz);πend.π                                                              25     08-27-9321:36ALL                      DAVID DAHL               Lots of Sound            IMPORT              150    ■"ç± {πI've gotten tired of writing these routines and have gone on to otherπprojects so I don't have time to work on them now.  I figured others may getπsome use out of them though.  They're not totally done yet, but what is thereπdoes work (as far as I can tell).  They support playing digitized Soundπ(signed or unsigned) at sample rates from 18hz to 44.1khz (at least on myπ386sx/25), on the PC Speaker (polled), LPT DACs (1-4) or Adlib FM channels. Iπwas planning on adding Sound Blaster DAC, Gravis UltraSound, and PC Speakerπ(pulse width modulated) support.  I also planned on adding VOC support.  Iπmay add those at a later date, but no promises.  I'll release any new updatesπ(if there are any) through the PDN since these routines are a little longπ(this will be the ONLY post of these routines in this echo).  I haven'tπtested the LPT DAC routines, so could someone who has an LPT DAC please testπthem and let me know if they work?  (They SHOULD work, but you never know.)πThese routines work For me under Turbo Pascal V6.0 on my 386sx/25.π}ππUnit Digital;π(*************************************************************************)π(*                                                                       *)π(*  Programmed by David Dahl                                             *)π(*  This Unit and all routines are PUBLIC DOMAIN.                        *)π(*                                                                       *)π(*  Special thanks to Emil Gilliam For information (and code!) on Adlib  *)π(*  digital output.                                                      *)π(*                                                                       *)π(*  if you use any of these routines in your own Programs, I would       *)π(*  appreciate an acknowledgement in the docs and/or Program... and I'm  *)π(*  sure Mr. Gilliam wouldn't Object to having his name mentioned, too.  *)π(*                                                                       *)π(*************************************************************************)πInterfaceππConstπ  BufSize       = 2048;ππTypeπ  BufferType = Array[1 .. BufSize] of Byte;π  BufPointer = ^BufferType;ππ  DeviceType = (LPT1, LPT2, LPT3, LPT4, PcSpeaker, PCSpeakPW, Adlib,π                SoundBlaster, UltraSound);ππVarπ  DonePlaying : Boolean;ππProcedure SetOutPutDevice(DeviceName : DeviceType; SignedSamples : Boolean);πProcedure SetPlaySpeed(Speed : LongInt);ππProcedure PlayRAWSoundFile(FileName : String; SampleRate : Word);πFunction  LoadBuffer(Var F : File; Var BufP : BufPointer) : Word;πProcedure PlayBuffer(BufPtr : BufPointer; Size : Word);ππProcedure HaltPlaying;πProcedure CleanUp;ππImplementationππUsesπ  Crt;ππConstπ  C8253ModeControl   = $43;π  C8253Channel       : Array [0..2] of Byte = ($40, $41, $42);π  C8253OperatingFreq = 1193180;π  C8259Command       = $20;ππ  TimerInterrupt     = $08;π  AdlibIndex         = $388;π  AdlibReg           = $389;ππTypeπ  ZeroAndOne = 0..1;ππVarπ  DataLength  : Word;π  Buffer      : BufPointer;ππ  LPTAddress  : Word;π  LPTPort     : Array [1 .. 4] of Word Absolute $0040 : $0008;ππ  OldTimerInterrupt : Pointer;π  InterruptVector   : Array [0..255] of Pointer Absolute $0000 : $0000;ππ{=[ Misc Procedures ]=====================================================}ππ{-[ Clear Interrupt Flag (Disable Maskable Interrupts) ]------------------}πProcedure CLI;πInline($FA);ππ{-[ Set Interrupt Flag ]--------------------------------------------------}πProcedure STI;πInline($FB);πππ{=[ Initialize Sound Devices ]============================================}ππ{-[ Initialize Adlib FM For Digital Output ]------------------------------}πProcedure InitializeAdlib;πVarπ  TempInt : Pointer;ππ  Procedure Adlib(Reg, Data : Byte); Assembler;π  Asmπ    mov  dx, AdlibIndex            { Adlib index port }π    mov  al, Regππ    out  dx,al                     { Set the index }ππ    { Wait For hardware to respond }π    in al, dx; in al, dx; in al, dxπ    in al, dx; in al, dx; in al, dxππ    inc  dx                        { Adlib register port }π    mov  al, Dataπ    out  dx, al                    { Set the register value }ππ    dec  dx                        { Adlib index port }ππ    { Wait For hardware to respond }π    in al, dx; in al, dx; in al, dx; in al, dx; in al, dxπ    in al, dx; in al, dx; in al, dx; in al, dx; in al, dxπ    in al, dx; in al, dx; in al, dx; in al, dx; in al, dxπ    in al, dx; in al, dx; in al, dx; in al, dx; in al, dxπ    in al, dx; in al, dx; in al, dx; in al, dx; in al, dxπ    in al, dx; in al, dx; in al, dx; in al, dx; in al, dxπ    in al, dx; in al, dx; in al, dx; in al, dx; in al, dxππ  end;ππbeginπ  Adlib($00, $00);    { Set Adlib test Register }π  Adlib($20, $21);    { Operator 0: MULTI=1, AM=VIB=KSR=0, EG=1 }π  Adlib($60, $F0);    { Attack = 15, Decay = 0 }π  Adlib($80, $F0);    { Sustain = 15, Release = 0 }π  Adlib($C0, $01);    { Feedback = 0, Additive Synthesis = 1 }π  Adlib($E0, $00);    { Waveform = Sine Wave }π  Adlib($43, $3F);    { Operator 4: Total Level = 63, Attenuation = 0 }π  Adlib($B0, $01);    { Fnumber = 399 }π  Adlib($A0, $8F);π  Adlib($B0, $2E);    { FNumber = 143, Key-On }ππ  { Wait For the operator's sine wave to get to top and then stop it thereπ    That way, we have an operator who's wave is stuck at the top, and we canπ    play digitized Sound by changing it's total level (volume) register. }ππ  Asmπ    mov  al, 0                    { Get timer 0 value into DX }π    out  43h, alπ    jmp  @Delay1ππ   @Delay1:π    in   al, 40hπ    mov  dl, alπ    jmp  @Delay2ππ   @Delay2:π    in   al, 40hππ    mov  dh, alπ    sub  dx, 952h                 { Target value }ππ   @wait_loop:π    mov  al, 0                    { Get timer 0 value into BX }π    out  43h, alπ    jmp  @Delay3ππ   @Delay3:π    in   al, 40hπ    mov  bl, alπ    jmp  @Delay4ππ   @Delay4:π    in   al, 40hπ    mov  bh, alπ    cmp  bx, dx                   { Have we waited that much time yet? }π    ja   @wait_loop               { if no, then go back }ππ  end;ππ { Now that the sine wave is at the top, change its frequency to 0 to keepπ   it from moving  }ππ  Adlib($B0, $20);  { F-Number = 0 }π  Adlib($A0, $00);  { Frequency = 0 }ππ  Port[AdlibIndex] := $40;πend;ππ{=[ Sound Device Handlers ]===============================================}πProcedure PlayPCSpeaker; Interrupt;πConstπ  Counter : Word = 1;πbeginπ  if Not(DonePlaying) Thenπ  beginπ    if Counter <= DataLength Thenπ    beginπ      Port[$61] := (Port[$61] and 253) OR ((Buffer^[Counter] and 128) SHR 6);π      Inc(Counter);π    endπ    elseπ    beginπ      DonePlaying := True;π      Counter     := 1;π    end;π  end;ππ  Port[C8259Command] := $20; { Enable Interrupts }πend;ππProcedure PlayPCSpeakerSigned; Interrupt;πConstπ  Counter : Word = 1;πbeginπ  if Not(DonePlaying) Thenπ  beginπ    if Counter <= DataLength Thenπ    beginπ      Port[$61] := (Port[$61] and 253) ORπ                   ((Byte(shortint(Buffer^[Counter]) + 128) AND 128) SHR 6);π      Inc(Counter);π    endπ    elseπ    beginπ      DonePlaying := True;π      Counter     := 1;π    end;π  end;ππ  Port[C8259Command] := $20; { Enable Interrupts }πend;ππProcedure PlayLPT; Interrupt;πConstπ  Counter : Word = 1;πbeginπ  if Not(DonePlaying) Thenπ  beginπ    if Counter <= DataLength Thenπ    beginπ      Port[LPTAddress] := Buffer^[Counter];π      Inc(Counter);π    endπ    elseπ    beginπ      DonePlaying := True;π      Counter     := 1;π    end;π  end;ππ  Port[C8259Command] := $20; { Enable Interupts }πend;ππProcedure PlayLPTSigned; Interrupt;πConstπ  Counter : Word = 1;πbeginπ  if Not(DonePlaying) Thenπ  beginπ    if Counter <= DataLength Thenπ    beginπ      Port[LPTAddress] := Byte(shortint(Buffer^[Counter]) + 128);π      Inc(Counter);π    endπ    elseπ    beginπ      DonePlaying := True;π      Counter     := 1;π    end;π  end;ππ  Port[C8259Command] := $20; { Enable Interupts }πend;ππProcedure PlayAdlib; Interrupt;πConstπ  Counter : Word = 1;πbeginπ  if Not(DonePlaying) Thenπ  beginπ    if Counter <= DataLength Thenπ    beginπ      Port[AdlibReg] := (Buffer^[Counter] SHR 2);π      Inc(Counter);π    endπ    elseπ    beginπ      DonePlaying := True;π      Counter     := 1;π    end;π  end;ππ  Port[C8259Command] := $20; { Enable Interupts }πend;ππProcedure PlayAdlibSigned; Interrupt;πConstπ  Counter : Word = 1;πbeginπ  if Not(DonePlaying) Thenπ  beginπ    if Counter <= DataLength Thenπ    beginπ      Port[AdlibReg] := Byte(shortint(Buffer^[Counter]) + 128) SHR 2;π      Inc(Counter);π    endπ    elseπ    beginπ      DonePlaying := True;π      Counter     := 1;π    end;π  end;ππ  Port[C8259Command] := $20; { Enable Interupts }πend;ππ{=[ 8253 Timer Programming Routines ]=====================================}πProcedure Set8253Channel(ChannelNumber : Byte; ProgramValue : Word);πbeginπ  Port[C8253ModeControl] := 54 or (ChannelNumber SHL 6); { XX110110 }π  Port[C8253Channel[ChannelNumber]] := Lo(ProgramValue);π  Port[C8253Channel[ChannelNumber]] := Hi(ProgramValue);πend;ππ{-[ Set Clock Channel 0 (INT 8, IRQ 0) To Input Speed ]-------------------}πProcedure SetPlaySpeed(Speed : LongInt);πVarπ  ProgramValue : Word;πbeginπ  ProgramValue := C8253OperatingFreq div Speed;π  Set8253Channel(0, ProgramValue);πend;ππ{-[ Set Clock Channel 0 Back To 18.2 Default Value ]----------------------}πProcedure SetDefaultTimerSpeed;πbeginπ  Set8253Channel (0, 0);πend;πππ{=[ File Handling ]=======================================================}ππ{-[ Load Buffer With Data From Raw File ]---------------------------------}πFunction LoadBuffer(Var F : File; Var BufP : BufPointer) : Word;πVarπ  NumRead : Word;πbeginπ  BlockRead(F, BufP^, BufSize, NumRead);π  LoadBuffer := NumRead;πend;πππ{=[ Sound Playing / Setup Routines ]======================================}ππ{-[ Output Sound Data In Buffer ]-----------------------------------------}πProcedure PlayBuffer(BufPtr : BufPointer; Size : Word);πbeginπ  Buffer      := BufPtr;π  DataLength  := Size;π  DonePlaying := False;πend;ππ{-[ Halt Playing ]--------------------------------------------------------}πProcedure HaltPlaying;πbeginπ  DonePlaying := True;πend;ππ{=[ Initialize Data ]=====================================================}πProcedure InitializeData;πConstπ  CalledOnce : Boolean = False;πbeginπ  if Not(CalledOnce) Thenπ  beginπ    DonePlaying       := True;π    OldTimerInterrupt := InterruptVector[TimerInterrupt];π    CalledOnce        := True;π  end;πend;ππ{=[ Set Interrupt Vectors ]===============================================}ππ{-[ Set Timer Interrupt Vector To Our Device ]----------------------------}πProcedure SetOutPutDevice(DeviceName : DeviceType; SignedSamples : Boolean);πbeginπ  CLI;ππ  Case DeviceName ofππ    LPT1..LPT4 :π      beginπ        LPTAddress := LPTPort[Ord(DeviceName)];π        if SignedSamples Thenπ          InterruptVector[TimerInterrupt] := @PlayLPTSignedπ        elseπ          InterruptVector[TimerInterrupt] := @PlayLPT;π      end;ππ    PCSpeaker :π      if SignedSamples Thenπ        InterruptVector[TimerInterrupt] := @PlayPCSpeakerSignedπ      elseπ        InterruptVector[TimerInterrupt] := @PlayPCSpeaker;ππ    Adlib :π      beginπ        InitializeAdlib;π        if SignedSamples Thenπ          InterruptVector[TimerInterrupt] := @PlayAdlibSignedπ        elseπ          InterruptVector[TimerInterrupt] := @PlayAdlib;π      end;ππ    elseπ      beginπ        STI;ππ        Writeln;π        Writeln ('That Sound Device Is Not Supported In This Version.');π        Writeln ('Using PC Speaker In Polled Mode Instead.');ππ        CLI;π        if SignedSamples Thenπ          InterruptVector[TimerInterrupt] := @PlayPCSpeakerSignedπ        elseπ          InterruptVector[TimerInterrupt] := @PlayPCSpeaker;π      end;π  end;π  STI;πend;ππ{-[ Set Timer Interupt Vector To Default Handler ]------------------------}πProcedure SetTimerInterruptVectorDefault;πbeginπ  CLI;π  InterruptVector[TimerInterrupt] := OldTimerInterrupt;π  STI;πend;ππProcedure PlayRAWSoundFile(FileName : String; SampleRate : Word);πVarπ  RawDataFile : File;π  SoundBuffer : Array [ZeroAndOne] of BufPointer;π  BufNum      : ZeroAndOne;π  Size        : Word;πbeginπ  New(SoundBuffer[0]);π  New(SoundBuffer[1]);ππ  SetPlaySpeed(SampleRate);ππ  Assign(RawDataFile, FileName);π  Reset(RawDataFile, 1);ππ  BufNum := 0;π  Size := LoadBuffer(RawDataFile, SoundBuffer[BufNum]);ππ  PlayBuffer(SoundBuffer[BufNum], Size);ππ  While Not(Eof(RawDataFile)) doπ  beginπ    BufNum := (BufNum + 1) and 1;π    Size   := LoadBuffer(RawDataFile, SoundBuffer[BufNum]);ππ    Repeat Until DonePlaying;ππ    PlayBuffer(SoundBuffer[BufNum], Size);π  end;ππ  Close (RawDataFile);ππ  Repeat Until DonePlaying;ππ  SetDefaultTimerSpeed;ππ  Dispose(SoundBuffer[1]);π  Dispose(SoundBuffer[0]);πend;ππ{=[ MUST CALL BEFORE ExitING Program!!! ]=================================}πProcedure CleanUp;πbeginπ  SetDefaultTimerSpeed;π  SetTimerInterruptVectorDefault;πend;ππ{=[ Set Up ]==============================================================}πbeginπ  InitializeData;π  NoSound;πend.ππππππππProgram RAWDigitalOutput;ππ(*************************************************************************)π(*                                                                       *)π(*  Programmed by David Dahl                                             *)π(*  This Program and all routines are PUBLIC DOMAIN.                     *)π(*                                                                       *)π(*  if you use any of these routines in your own Programs, I would       *)π(*  appreciate an acknowledgement in the docs and/or Program.            *)π(*                                                                       *)π(*************************************************************************)ππUsesπ  Crt,π  Digital;ππTypeπ  String4  = String[4];π  String35 = String[35];ππConstπ  MaxDevices = 9;ππ  DeviceCommand  : Array [1..MaxDevices] of String4 =π    ('-L1', '-L2', '-L3', '-L4',π     '-P' , '-PM', '-A' , '-SB', '-GUS' );ππ  DeviceName : Array [1..MaxDevices] of String35 =π    ('LPT DAC on LPT1',π     'LPT DAC on LPT2',π     'LPT DAC on LPT3',π     'LPT DAC on LPT4',π     'PC Speaker (Polled Mode)',π     'PC Speaker (Pulse Width Modulated)',π     'Adlib / SoundBlaster FM',π     'SoundBlaster DAC',π     'Gravis UltraSound');ππ  SignedUnsigned  : Array [False .. True] of String35 =π    ('Unsigned Sample', 'Signed Sample');πππ{-[ Return An All Capaitalized String ]-----------------------------------}πFunction UpString(StringIn : String) : String;πVarπ  TempString : String;π  Counter    : Byte;πbeginπ  TempString := '';π  For Counter := 1 to Length (StringIn) doπ    TempString := TempString + UpCase(StringIn[Counter]);ππ  UpString := TempString;πend;ππ{-[ Check if File Exists ]------------------------------------------------}πFunction FileExists(FileName : String) : Boolean;πVarπ  F : File;πbeginπ  {$I-}π  Assign (F, FileName);π  Reset(F);π  Close(F);π  {$I+}π  FileExists := (IOResult = 0) And (FileName <> '');πend;ππ{=[ Comand Line Parameter Decode ]========================================}πFunction FindOutPutDevice : DeviceType;πVarπ  Counter       : Byte;π  DeviceCounter : Byte;π  Found         : Boolean;π  Device        : DeviceType;πbeginπ  Counter := 1;π  Found   := False;π  Device  := PcSpeaker;ππ  While (Counter <= ParamCount) and Not(Found) doπ  beginπ    For DeviceCounter := 1 To MaxDevices doπ      if UpString(ParamStr(Counter)) = DeviceCommand[DeviceCounter] Thenπ      beginπ        Device := DeviceType(DeviceCounter - 1);π        Found  := True;π      end;ππ    Inc(Counter);π  end;ππ  FindOutPutDevice := Device;πend;ππFunction FindRawFileName : String;πVarπ  FileNameFound : String;π  TempName      : String;π  Found         : Boolean;π  Counter       : Byte;πbeginπ  FileNameFound   := '';π  Counter := 1;π  Found   := False;ππ  While (Counter <= ParamCount) and Not(Found) doπ  beginπ    TempName := UpString(ParamStr(Counter));π    if TempName[1] <> '-' Thenπ    beginπ      FileNameFound := TempName;π      Found         := True;π    end;π    Inc (Counter);π  end;ππ  FindRawFileName := FileNameFound;πend;ππFunction FindPlayBackRate : Word;πVarπ  RateString : String;π  Rate       : Word;π  Found      : Boolean;π  Counter    : Byte;π  ErrorCode  : Integer;πbeginπ  Rate := 22000;π  Counter := 1;π  Found   := False;ππ  While (Counter <= ParamCount) and Not(Found) doπ  beginπ    RateString := UpString(ParamStr(Counter));π    if Copy(RateString,1,2) = '-F' Thenπ    beginπ      RateString := Copy(RateString, 3, Length(RateString) - 2);π      Val(RateString, Rate, ErrorCode);π      if ErrorCode <> 0 Thenπ      beginπ        Rate := 22000;π        Writeln ('Error In Frequency. Using Default');π      end;π      Found := True;π    end;π    Inc (Counter);π  end;ππ  if Rate < 18 Thenπ    Rate := 18π  elseπ  if Rate > 44100 Thenπ    Rate := 44100;ππ  FindPlayBackRate := Rate;πend;ππFunction SignedSample : Boolean;πVarπ  Found   : Boolean;π  Counter : Word;πbeginπ  SignedSample := False;π  Found   := False;π  Counter := 1;ππ  While (Counter <= ParamCount) and Not(Found) doπ  beginπ    if UpString(ParamStr(Counter)) = '-S' Thenπ    beginπ      SignedSample := True;π      Found        := True;π    end;ππ    Inc(Counter);π  end;πend;ππ{=[ Main Program ]========================================================}πVarπ  SampleName : String;π  SampleRate : Word;π  OutDevice  : DeviceType;πbeginπ  Writeln;π  Writeln('RAW Sound File Player V0.07');π  Writeln('Programmed By David Dahl');π  Writeln('Thanks to Emil Gilliam For Adlib digital output information');π  Writeln('This Program is PUBLIC DOMAIN');ππ  if ParamCount <> 0 Thenπ  beginπ    SampleRate := FindPlayBackRate;π    SampleName := FindRawFileName;π    OutDevice  := FindOutPutDevice;π    Writeln;ππ    if SampleName <> '' Thenπ    beginπ      Writeln('Raw File   : ',SampleName);π      Writeln('Format     : ',SignedUnsigned[SignedSample]);π      Writeln('Sample Rate: ',SampleRate);π      Writeln('Device     : ',DeviceName[Ord(OutDevice)+1]);ππ      if FileExists(SampleName) Thenπ      beginπ        SetOutputDevice(OutDevice, SignedSample);π        PlayRAWSoundFile(SampleName, SampleRate);π      endπ      elseπ        Writeln('Sound File Not Found.');π    endπ    elseπ      Writeln('Filename Not Specified.');π  endπ  elseπ  beginπ    Writeln;π    Writeln('USAGE:');π    Writeln(ParamStr(0),' [SWITCHES] <RAW DATA File>');π    Writeln;π    Writeln('SWITCHES:');π    Writeln(' -P      PC Speaker, Polled (Default)');π    Writeln(' -L1     LPT DAC on LPT 1');π    Writeln(' -L2     LPT DAC on LPT 2');π    Writeln(' -L3     LPT DAC on LPT 3');π    Writeln(' -L4     LPT DAC on LPT 4');π    Writeln(' -A      Adlib/Sound Blaster FM');π    Writeln;π    Writeln(' -S      Signed Sample (Unsigned Default)');π    Writeln;π    Writeln(' -FXXXXX Frequency Of Sample. XXXXX can be any Integer ',π             'between 18 to 44100');π    Writeln ('         (22000 Default)');π  end;ππ  CleanUp;πend.πππ                                                                                                     26     08-27-9321:41ALL                      JOERGEN DORCH            Sounds In Pascal         IMPORT              6      ■"[2 {πJOERGEN DORCHππ About Sounds i Pascal - Here's how I do it:π}ππFunction Frequency(Octave, NoteNum : Integer) : Integer;πConstπ  Silence = 32767;πVarπ  Oct : Integer;ππ  Function Power(X, Y : Real) : Real;π  beginπ    Power := Exp(Y * Ln(X));π  end;ππbeginπ  Oct := Octave - 3;π  if NoteNum > 0 thenπ    Frequency := Round(440 * Power(2, Oct + ((NoteNum - 10) / 12)))π  elseπ    Frequency := Silence;πend;ππ{πWhere Octave is in the range [0..6] and NoteNum in the range [1..12],πthat is C = 1, C# = 2, D = 3 etc.π}                                                                                                                             27     08-27-9321:44ALL                      SEAN PALMER              Controling the PC SpeakerIMPORT              13     ■"gO {πSEAN PALMERππ>I have TP 6.0, and I'am looking For a way to address my PC Speaker.  I don'tπ>know what Port it is (like PORT[$30] or something), or how to send raw Soundπ>data to it. Could someone help me?ππTry this, or actually a Variation on it. Doing VOC's and WAV's on a pcπspeaker is not an easy task...ππWhat you're looking For is embedded in the 'click' Procedure below...ππ'click' only works While no tone is being produced. click at differentπrates to get different pitches/effects.ππso I guess the simple answer to your question is that it's controlled byπbit 1 (from 0 to 7) of port $61.π}ππUnit uTone;πInterfaceππProcedure tone(freq : Word);πProcedure noTone;πProcedure click;ππImplementationππConstπ  sCntrl   = $61; { Sound control port }π  SoundOn  = $03; { bit mask to enable speaker }π  SoundOff = $FC; { bit mask to disable speaker }π  C8253    = $43; { port address to control 8253 }π  seTimer  = $B6; { tell 8253 to expect freq data next }π  F8253    = $42; { frequency address on 8253 }ππProcedure tone(freq : Word); Assembler;πAsmπ  mov al, $B6π  out $43, al  {Write timer mode register}π  mov dx, $14π  mov ax, $4F38π  div freq     {1331000/Frequency pulse}π  out $42, alπ  mov al, ahπ  out $42, al  {Write timer a Byte at a time}π  in  al, $61π  or  al, 3π  out $61, al  {port B-switch speaker on}πend;ππProcedure noTone; Assembler;πAsmπ  in  al, $61π  and al, $FCπ  out $61, alπend;ππProcedure click; Assembler;πAsmπ  in  al, $61π  xor al, 2π  out $61, alπend;ππend.π                                           28     08-27-9321:52ALL                      BRIAN PAPE               Play with Soundblaster   IMPORT              28     ■";h {πBRIAN PAPEππOk, here's about 45 minutes of sweating, trying to read some pitifull SBπreference.  This is about as far as I've gotten trying to make the SBπmake some noise that is actually a note, not just a buzz...  If anyoneπcan do ANYTHING at ALL with this, please tell me.ππThis program is not Copyright (c)1993 by Brian Pape.πwritten 4/13/93πIt is 100% my code with nothing taken from anyone else.  If you can use it inπanyway, great.  I should have the actual real version done later this summerπthat is more readable.  The .MOD player is about half done, pending theπfinishing of the code to actually play the notes (decoder is done).πMy fido address is 1:2250/26π}πprogram sb;πusesπ  crt;πconstπ  on     = true;π  off    = false;π  maxreg = $F5;π  maxch  = 10;ππ  note_table : array [0..12] of word =π    ($000,$16b,$181,$198,$1b0,$1ca,$1e5,$202,$220,$241,$263,$287,$2ae);π  key_table  : array [1..12] of char =π    'QWERTYUIOP[]';π  voicekey_table : array [1..11] of char =π    '0123456789';πtypeπ  byteset = set of byte;ππvarπ  ch        : char;π  channel   : byte;π  ch_active : byteset;π  lastnote  : array [0..maxch] of word;πππprocedure writeaddr(b : byte); assembler;πasmπ  mov  al, bπ  mov  dx, 388hπ  out  dx, alπ  mov  cx, 6ππ @wait:π  in   al, dxπ  loop @waitπend;ππprocedure writedata(b : byte); assembler;πasmπ  mov  al, bπ  mov  dx, 389hπ  out  dx, alπ  mov  cx, 35hπ  dec  dxππ @wait:π  in   al, dxπ  loop @waitπend;ππprocedure sb_reset;πvarπ  i : byte;πbeginπ  for i := 1 to maxreg doπ  beginπ    writeaddr(i);π    writedata(0);π  end;πend;ππprocedure sb_off;πbeginπ  writeaddr($b0);π  writedata($11);πend;ππ{ r=register,d=data }πprocedure sb_out(r, d : byte);πbeginπ  writeaddr(r);π  writedata(d);πend;ππprocedure sb_setup;πbeginπ  sb_out($20, $01);π  sb_out($40, $10);π  sb_out($60, $F0);π  sb_out($80, $77);π  sb_out($A0, $98);π  sb_out($23, $01);π  sb_out($43, $00);π  sb_out($63, $F0);π  sb_out($83, $77);π  sb_out($B0, $31);πend;ππprocedure disphelp;πbeginπ  clrscr;π  writeln;π  writeln('Q:C#');π  writeln('W:D');π  writeln('E:D#');π  writeln('R:E');π  writeln('T:F');π  writeln('Y:F#');π  writeln('U:G');π  writeln('I:G#');π  writeln('O:A');π  writeln('P:A#');π  writeln('[:B');π  writeln(']:C');π  writeln('X:Quit');π  writeln;πend;ππprocedure sb_note(channel : byte; note : word; on : boolean);πbeginπ  sb_out($a0 + channel, lo(note));π  sb_out($b0 + channel, ($20 * byte(on)) or $10 or hi(note));πend;ππprocedure updatestatus;πvarπ  i : byte;πbeginπ  gotoxy(1,16);π  for i := 0 to maxch doπ  beginπ    if i in ch_active thenπ      textcolor(14)π    elseπ      textcolor(7);π    write(i : 3);π  end;πend;ππbeginπ  sb_reset;π  sb_out(1, $10);π  sb_setup;π  disphelp;π  channel   := 0;π  ch_active := [0];π  repeatπ    updatestatus;π    ch := upcase(readkey);π    if pos(ch, key_table) <> 0 thenπ    beginπ      lastnote[channel] := note_table[pos(ch, key_table)];π      sb_note(channel, lastnote[channel], on);π    endπ    elseπ    if pos(ch, voicekey_table) <> 0 thenπ    beginπ      channel := pred(pos(ch,voicekey_table));π      if channel in ch_active thenπ        ch_active := ch_active - [channel]π      elseπ        ch_active := ch_active + [channel];π      if not (channel in ch_active) thenπ        sb_note(channel,lastnote[channel],off)π      elseπ        sb_note(channel,lastnote[channel],on);π    end;π  until ch = 'X';π  sb_off;πend.ππ                                                                          29     08-27-9321:53ALL                      NORBERT IGL              Direct output to SB Card IMPORT              22     ■"∞j {πNORBERT IGLππ>> if you already have the DAC Programming, simply Write out eachπ>> Byte to the DAC PORT (Write $10, then the data For Direct Mode)π>> Then Delay after each Byte, depending on the Sampling rate.π>> You'll have to play around With the Delay's.ππ  Just found a piece of source in my Files.... (:-)),π  but i don't know the original author ( RedFox ? )π  and i translated the (orig.) german remarks....π}ππUsesπ  Crt;πConstπ  ResetPort  = $226;π  ReadPort   = $22A;π  WritePort  = $22C;π  StatusPort = $22C;π  DataDaPort = $22E;ππ  { N.I.: Note: Use SB_Port (prev. Msg) to get the correct address.... }ππ  AD_Null       = $80;π  OK            = 0000;π  NichtGefunden = 1000;π  DirectDAC     = $10;π  SpeakerOn     = $D1;π  SpeakerOff    = $D3;ππVarπ  DSPResult   : Word;π  DSPReadWert : Byte;ππ  loop : Word;π  w    : Word;π  m    : Word;πππProcedure WriteToDSP(Command : Byte);πbeginπ  Repeat Until (port[StatusPort] and $80) = 0;π  port[WritePort] := Command;πend;ππProcedure ReadFromDSP;πbeginπ  Repeat Until (port[DataDaPort] and $80) = $80;π  DSPReadWert := port[ReadPort];πend;ππProcedure ResetDSP;πVarπ  MaxVersuch : Byte;πbeginπ  MaxVersuch:=100;π  Repeatπ    port[ResetPort] := 1;π    Delay(10);π    port[ResetPort] := 0;π    ReadFromDSP;π    dec(MaxVersuch);π  Until (DSPReadWert = $AA) or (MaxVersuch = 0);ππ  if MaxVersuch = 0 thenπ    DSPResult := NichtGefundenπ  elseπ    DSPResult := OK;πend;πππbeginπ  ClrScr;ππ  ResetDSP;ππ  if DSPResult <> OK thenπ  beginπ    Writeln(' Soundeblaster not found !');π    Writeln(' Wrong SB-address ?');π  endπ  elseπ  beginπ    Writeln(' Demo : direct output to the SoundblasterCard !');π    Writeln('  ┌──┐  ┌──┐  ┌──┐  ┌──┐  ┌──┐  ┌  creates a square');π    Writeln('  │  │  │  │  │  │  │  │  │  │  │  waveform With an');π    Writeln('──┘  └──┘  └──┘  └──┘  └──┘  └──┘  64`er amplitude ');π    Writeln;π    Writeln(' RedFox (14.11.91) ');ππ    WriteToDSP(SpeakerOn);               { Speaker on }ππ    m := 5000;                           { dynamc Wait (Init) }ππ    For loop := 1 to 600 do              { 600 samples }π    beginπ      dec(m, 10);π      if m < 20 thenπ        m := 500;π      WriteToDSP(DirectDAC);             { command to SB  }π      WriteToDSP(AD_Null + 32);          { now the sample }ππ      { rising edge    }π      For w := 1 to m do begin end;      { dynamc wait    }ππ      WriteToDSP(DirectDAC);             { command to SB  }π      WriteToDSP(AD_Null - 32);          { falling edge   }ππ      For w := 1 to m do begin end;      { wait again     }π    end;π    WriteToDSP(SpeakerOff);              { speaker off }π  end;πend.π                                                                       30     09-26-9309:19ALL                      CATHY NICOLOFF           Adlib/SB Music           IMPORT              43     ■"àÜ (*π===========================================================================π BBS: Canada Remote SystemsπDate: 09-02-93 (00:16)             Number: 36877πFrom: CATHY NICOLOFF               Refer#: NONEπ  To: ALL                           Recvd: NOπSubj: Musical Notes!!!      1/2      Conf: (1221) F-PASCALπ---------------------------------------------------------------------------πHere's some help for all you programmers out there! It's straight fromπmy personal programming library!πππSBNotes : Array[1..12] Of Byte =π      ($AE, $6B, $81, $98, $B0, $CA, $E5, $02, $20, $41, $63, $87);ππ   SBOctaves : Array[1..84] Of Byte =π      ($22, $25, $25, $25, $25, $25, $25, $26, $26, $26, $26, $26,π       $26, $29, $29, $29, $29, $29, $29, $2A, $2A, $2A, $2A, $2A,π       $2A, $2D, $2D, $2D, $2D, $2D, $2D, $2E, $2E, $2E, $2E, $2E,π       $2E, $31, $31, $31, $31, $31, $31, $32, $32, $32, $32, $32,π       $32, $35, $35, $35, $35, $35, $35, $36, $36, $36, $36, $36,π       $36, $39, $39, $39, $39, $39, $39, $3A, $3A, $3A, $3A, $3A,π       $3A, $3D, $3D, $3D, $3D, $3D, $3D, $3E, $3E, $3E, $3E, $3E);ππ    Notes               : Array[1..84] Of Word =π    { C    C#,D-  D    D#,E-  E     F    F#,G-  G    G#,A-  A    A#,B-  B  }π    (0065, 0070, 0073, 0078, 0082, 0087, 0093, 0098, 0104, 0110, 0117, 0123,π     0131, 0139, 0147, 0156, 0165, 0175, 0185, 0196, 0208, 0220, 0233, 0247,π     0262, 0277, 0294, 0311, 0330, 0349, 0370, 0392, 0415, 0440, 0466, 0494,π     0523, 0554, 0587, 0622, 0659, 0698, 0740, 0784, 0831, 0880, 0932, 0987,π     1047, 1109, 1175, 1245, 1329, 1397, 1480, 1568, 1661, 1760, 1865, 1976,π     2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951,π     4186, 4435, 4699, 4978, 5274, 5588, 5920, 6272, 6645, 7040, 7459, 7902);ππExplanation : This is used to emulate single note music (IE-ANSI music).ππThe array NOTES is the frequencies used to do a SOUND/NOSOUND on the PCπspeaker.ππThe SBNOTES and SBOCTAVES arrays are the hex values of the notes, andπtheir octaves for any ADLIB compatible card.ππJust take which note you want, and input the note AND the octaveπinto the Adlib port. Here's some sample code to show you how :π*)ππUnit Music;ππInterfaceππUses Crt;ππCONSTππSBNotes : Array[1..12] Of Byte =π      ($AE, $6B, $81, $98, $B0, $CA, $E5, $02, $20, $41, $63, $87);ππ   SBOctaves : Array[1..84] Of Byte =π      ($22, $25, $25, $25, $25, $25, $25, $26, $26, $26, $26, $26,π       $26, $29, $29, $29, $29, $29, $29, $2A, $2A, $2A, $2A, $2A,π       $2A, $2D, $2D, $2D, $2D, $2D, $2D, $2E, $2E, $2E, $2E, $2E,π       $2E, $31, $31, $31, $31, $31, $31, $32, $32, $32, $32, $32,π       $32, $35, $35, $35, $35, $35, $35, $36, $36, $36, $36, $36,π       $36, $39, $39, $39, $39, $39, $39, $3A, $3A, $3A, $3A, $3A,π       $3A, $3D, $3D, $3D, $3D, $3D, $3D, $3E, $3E, $3E, $3E, $3E);ππ    Notes               : Array[1..84] Of Word =π    { C    C#,D-  D    D#,E-  E     F    F#,G-  G    G#,A-  A    A#,B-  B  }π    (0065, 0070, 0073, 0078, 0082, 0087, 0093, 0098, 0104, 0110, 0117, 0123,π     0131, 0139, 0147, 0156, 0165, 0175, 0185, 0196, 0208, 0220, 0233, 0247,π     0262, 0277, 0294, 0311, 0330, 0349, 0370, 0392, 0415, 0440, 0466, 0494,π     0523, 0554, 0587, 0622, 0659, 0698, 0740, 0784, 0831, 0880, 0932, 0987,π     1047, 1109, 1175, 1245, 1329, 1397, 1480, 1568, 1661, 1760, 1865, 1976,π     2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951,π     4186, 4435, 4699, 4978, 5274, 5588, 5920, 6272, 6645, 7040, 7459, 7902);ππProcedure Play_SB(N, M : Byte);πProcedure Init_SB;πProcedure Reset_SB;πFunction Detect_SB : Boolean;ππImplementationππ(***********************)ππProcedure Play_SB(N, M : Byte);ππVar Loop  : Integer;π    Temp  : Integer;ππBeginπ  Port[$0388] := N;π  For Loop := 1 To 6 Doπ     Temp := Port[$0388];π  Port[$0389] := M;π  For Loop:=1 To 35 Doπ     Temp := Port[$0388];πEnd;ππ(***********************)ππProcedure Init_SB;ππVarπ   A : Integer;ππBeginπ   For A := 1 to 244 Doπ      Play_SB(A,$00);π   Play_SB($01,32);π   Play_SB($B0,$11);π   Play_SB($04,$60);π   Play_SB($04,$80);πEnd;ππ(***********************)ππProcedure Reset_SB;ππBeginπ   Play_SB($20,$41);π   Play_SB($40,$10);π   Play_SB($60,$F0);π   Play_SB($80,$77);π   Play_SB($23,$41);π   Play_SB($43,$00);π   Play_SB($63,$F0);π   Play_SB($83,$77);π   Play_SB($BD,$10);πEnd;ππ(***********************)πππFunction Detect_SB : Boolean;ππVarπ   Dummy1,π   Dummy2  : Byte;ππBeginπ   Play_SB($04,$60);π   Play_SB($04,$80);π   Dummy1 := Port[$388];π   Play_SB($02,$FF);π   Play_SB($04,$21);π   Delay(8);π   Dummy2 := Port[$388];π   Play_SB($04,$60);π   Play_SB($04,$80);π   If ((Dummy1 AND $E0) = $00) And ((Dummy2 AND $E0) = $C0) Thenπ      Detect_SB := Trueπ   Elseπ      Detect_SB := False;πEnd;ππ(***********************)ππEnd.ππThat is my own soundblaster unit I use to output.ππTo play note 'C' at octave 3, do the following :ππPlay_SB($A0, SBNotes[1]);πPlay_SB($B0, SBOctaves[1 + 3 * 12]);ππTo shut off Adlib output, do this :ππPlay_SB($83, $FF);πPlay_SB($B0, $11);ππ{   TEST PROGRAM }ππUses DOS,Crt,Music;ππVAR I : BYTE;ππBEGINπInit_SB;πReset_SB;πFOR I := 1 To 8 DOπ    BEGINπ    Play_SB($A0, SBNotes[i]);π    Play_SB($B0, SBOctaves[i + 3 * 12]);π    DELAY(500);π    END;πInit_SB;πReset_SB;πEND.πππππ                                                                                                                               31     10-28-9311:38ALL                      WIM VAN.VOLLENHOVEN      SOUND Machine            IMPORT              79     ■"ä[ {===========================================================================πDate: 08-31-93 (22:24)πFrom: WIM VAN.VOLLENHOVENπSubj: Sound Moduleπ---------------------------------------------------------------------------πWell.. here is the source code i've found in a pascal toolbox (ECO)πwhich emulates the play function of qbasic :-)ππ{π  call: play(string)ππ        music_string --- the string containing the encoded music to beπ                         played.  the format is the same as that of theπ                         microsoft basic play statement.  the stringπ                         must be <= 254 characters in length.ππ  calls:  soundπ          getint  (internal)ππ  remarks:  the characters accepted by this routine are:ππ            a - g       musical notesπ            # or +      following a - g note, indicates sharpπ            -           following a - g note, indicates flatπ            <           move down one octaveπ            >           move up one octaveπ            .           dot previous note (extend note duration by 3/2)π            mn          normal duration (7/8 of interval between notes)π            ms          staccato durationπ            ml          legato durationπ            ln          length of note (n=1-64; 1=whole note,4=quarter note)π            pn          pause length (same n values as ln above)π            tn          tempo,n=notes/minute (n=32-255,default n=120)π            on          octave number (n=0-6,default n=4)π            nn          play note number n (n=0-84)ππ            the following two commands are ignored by play:ππ            mf          complete note before continuingπ            mb          another process may begin before speaker isπ                        finished playing noteππ  important --- setdefaultnotes must have been called at least once beforeπ                this routine is called.π}ππunit u_play;πinterfaceππusesπ  crtππ  ;ππconstπ  note_octave   : integer = 4;     { current octave for note            }π  note_fraction : real    = 0.875; { fraction of duration given to note }π  note_duration : integer = 0;     { duration of note     ^^semi-legato }π  note_length   : real    = 0.25;  { length of note }π  note_quarter  : real    = 500.0; { moderato pace (principal beat)     }ππππ  procedure quitsound;π  procedure startsound;π  procedure errorbeep;π  procedure warningbeep;π  procedure smallbeep;π  procedure setdefaultnotes;π  procedure play(s: string);π  procedure beep(h, l: word);ππππimplementationπππππ  procedure quitsound;π  var i: word;π  beginπ    for i := 100 downto 1 do begin sound(i*10); delay(2) end;π    for i := 1 to 800 do begin sound(i*10); delay(2) end;π    nosound;π  end;ππ  procedure startsound;π  var i: word;π  beginπ    for i := 100 downto 1 do begin sound(i*15); delay(2) end;π    for i := 1 to 100 do begin sound(i*15); delay(2) end; nosound;π    delay(100); for i := 100 downto 1 do begin sound(i*10); delay(2) end;π    nosound;π  end;πππ  procedure errorbeep;π  beginπ    sound(2000); delay(75); sound(1000); delay(75); nosound;π  end;πππ  procedure warningbeep;π  beginπ    sound(500); delay(500); nosound;π  end;ππ  procedure smallbeep;π  beginπ    sound(300); delay(50); nosound;π  end;ππππππprocedure setdefaultnotes;πbeginπ   note_octave   := 4;             { default octave                      }π   note_fraction := 0.875;         { default sustain is semi-legato      }π   note_length   := 0.25;          { note is quarter note by default     }π   note_quarter  := 500.0;         { moderato pace by default            }πend;ππππprocedure play(s: string);πconstπ                                      { offsets in octave of natural notes }π note_offset   : array[ 'A'..'G' ] of integer = (9,11,0,2,4,5,7);ππ                                      { frequencies for 7 octaves          }π   note_freqs: array[ 0 .. 84 ] of integer =π{π      c    c#     d    d#     e     f    f#     g    g#     a    a#     bπ}π(    0,π     65,  69,  73,  78,  82,  87,  92,  98, 104, 110, 116, 123,π    131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247,π    262, 278, 294, 312, 330, 350, 370, 392, 416, 440, 466, 494,π    524, 556, 588, 624, 660, 700, 740, 784, 832, 880, 932, 988,π   1048,1112,1176,1248,1320,1400,1480,1568,1664,1760,1864,1976,π   2096,2224,2352,2496,2640,2800,2960,3136,3328,3520,3728,3952,π   4192,4448,4704,4992,5280,5600,5920,6272,6656,7040,7456,7904 );ππ   quarter_note = 0.25;            { length of a quarter note }ππ   digits : set of '0'..'9' = ['0'..'9'];ππvarππ   play_freq     : integer;        { frequency of note to be played }π   play_duration : integer;        { duration to sound note }π   rest_duration : integer;        { duration of rest after a note }π   i             : integer;        { offset in music string }π   c             : char;           { current character in music string }π                                   { note frequencies }π   freq          : array[0..6,0..11] of integer absolute note_freqs;π   n             : integer;π   xn            : real;π   k             : integer;ππ  function getint : integer;π  var n: integer;ππ  begin { getint }π    n := 0;π    while(s[i] in digits) do begin n := n*10+ord(s[i])-ord('0'); inc(i) end;π    dec(i); getint := n;π  end   { getint };ππbeginπ  s := s + ' ';                   { append blank to end of music string }π  i := 1;                           { point to first character in music }π  while(i < length(s)) do begin      { begin loop over music string }π    c := upcase(s[i]);        { get next character in music string }π    case c of                 { interpret it                       }π       'A'..'G' : begin { a note }π          n         := note_offset[ c ];π          play_freq := freq[ note_octave ,n ];π          xn := note_quarter * (note_length / quarter_note);π          play_duration := trunc(xn * note_fraction);π          rest_duration := trunc(xn * (1.0 - note_fraction));π                                      { check for sharp/flat }π          if s[i+1] in ['#','+','-' ] thenπ             beginπ                inc(i);π                case s[i] ofπ                   '#',π                   '+' : play_freq :=π                            freq[ note_octave ,succ(n) ];π                   '-' : play_freq :=π                            freq[ note_octave ,pred(n) ];π                   else  ;π                end { case };ππ             end;ππ                   { check for note length }ππ          if (s[i+1] in digits) thenπ             beginππ                inc(i);π                n  := getint;π                xn := (1.0 / n) / quarter_note;ππ                play_duration :=π                    trunc(note_fraction * note_quarter * xn);ππ                rest_duration :=π                   trunc((1.0 - note_fraction) *π                          xn * note_quarter);ππ             end;π                   { check for dotting }ππ             if s[i+1] = '.' thenπ                beginππ                   xn := 1.0;ππ                   while(s[i+1] = '.') doπ                      beginπ                         xn := xn * 1.5;π                         inc(i);π                      end;ππ                   play_duration :=π                       trunc(play_duration * xn);ππ                end;ππ                       { play the note }ππ          sound(play_freq);π          delay(play_duration);π          nosound;π          delay(rest_duration);π        end   { a note };ππ       'M' : begin { 'M' commands }π         inc(i);π         c := s[i];π         case c ofπ           'F' : ;π           'B' : ;π           'N' : note_fraction := 0.875;π           'L' : note_fraction := 1.000;π           'S' : note_fraction := 0.750;π           else ;π         end { case };π       end   { 'M' commands };ππ       'O' : begin { set octave }π         inc(i);π         n := ord(s[i]) - ord('0');π         if (n < 0) or (n > 6) then n := 4;π         note_octave := n;π       end   { set octave };ππ       '<' : begin { drop an octave }π         if note_octave > 0 then dec(note_octave);π       end   { drop an octave };ππ       '>' : begin { ascend an octave }π         if note_octave < 6 then inc(note_octave);π       end   { ascend an octave };ππ       'N' : begin { play note n }π         inc(i); n := getint;π         if (n > 0) and (n <= 84) then beginπ           play_freq     := note_freqs[ n ];π           xn            := note_quarter * (note_length / quarter_note);π           play_duration := trunc(xn * note_fraction);π           rest_duration := trunc(xn * (1.0 - note_fraction));π         end else if (n = 0) then beginπ           play_freq     := 0; play_duration := 0;π           rest_duration := trunc(note_fraction * note_quarter *π                                 (note_length / quarter_note));π         end;π         sound(play_freq); delay(play_duration); nosound;π         delay(rest_duration);π       end   { play note n };π       'L' : begin { set length of notes }π         inc(i); n := getint;π         if n > 0 then note_length := 1.0 / n;π       end   { set length of notes };ππ       'T' : begin { # of quarter notes in a minute }π         inc(i); n := getint;π         note_quarter := (1092.0 / 18.2 / n) * 1000.0;π       end   { # of quarter notes in a minute };ππ       'P' : begin { pause }π         inc(i); n := getint;π         if (n <  1) then n := 1 else if (n > 64) then n := 64;π         play_freq := 0; play_duration := 0;π         rest_duration := trunc(((1.0 / n) / quarter_note) * note_quarter);π         sound(play_freq); delay(play_duration); nosound;π         delay(rest_duration);π       end   { pause };ππ       else  { ignore other stuff };π    end { case };π    inc(i);π  end  { interpret music };π  nosound;                         { make sure sound turned off when through }πend;πππprocedure beep(h, l: word);πbeginπ  sound(h); delay(l); nosound;πend;ππend. { of unit }π                                                                                                         32     11-02-9306:13ALL                      RYNHARDT HAARHOFF        Sampling with Blaster    IMPORT              33     ■"T {πRYNHARDT HAARHOFFππ> Help!!! Does anyone have and source code for sampling through theπ> Sound Blaster??? Its to do with my 'A' Level Project!!!!ππthe following is a small program using "realtime" sampling. If you wouldπrather use the CT-VOICE driver then please tell me so.ππPLEASE NOTE: this was written for a VGA screen, and it uses direct videoπmemory access in 320x200 mode. If you have any problems with the screen, thenπrevert back to the BGI, and replace PutDot with PutPixel. It will be slightlyπslower then :-(πI have an SB PRO, so I can't guarantee it will work on any other SB, orπon any other system. Use at own risk :-)π}ππProgram VoiceScope;ππusesπ  Crt;ππconstπ  ResetPort    = $226;π  CommandPort  = $22C;π  ReadPort     = $22A;π  PollPort     = $22E;π  MaxOldDots   = 50000;  {max size of the array}π  MixerRegPort = $224;   {Volume : Hi nibble = left, Lo Nibble = right}π  MixerDatPort = $225;π  Master       = 35;π  Line         = 46;π  VOC          = 21;π  FM           = 23;     {Hi nibble = FM channel; Lo nibble = volume}π  CD           = 25;π  Mic          = 27;π  ADCChannel   = 29;π  StereoSell   = 31;     {0,1 = mono; 2,3 = stereo}πππvarπ  Scr       : array [0..199, 0..319] of byte absolute $A000:0000;π  Ch        : char;π  XInt,π  XWidth,π  XMax,π  YMax,π  XMid,π  YMid,π  MaxHeight,π  XStart,π  Color,π  ColorBack : integer;π  OldDots   : array [0..MaxOldDots] of byte;     {to store old dots}πππProcedure InitVideo(Mode : byte; Clr : boolean);πbeginπ  if NOT Clr thenπ    Mode := Mode + 128;π  ASMπ    mov AH, 00π    mov AL, Modeπ    int 10hπ  end;πend;ππProcedure PutDot(x, y : word; Color : byte);πbeginπ  Scr[y, x] := Color;πend;ππProcedure SquareFill(x1, y1, x2, y2 : word; Color : byte);πvarπ  y : word;πbeginπ  for y := y1 to y2 doπ    FillChar(Scr[y, x1], x2-x1, Color);πend;ππProcedure SetMixer(PortNum, Vol : byte);  {Set mixer ports}πbeginπ  asmπ    MOV DX, MixerRegPort       {Select register port}π    MOV AL, PortNum            {Select which channel}π    OUT DX, ALπ    MOV DX, MixerDatPort       {Select data port}π    MOV AL, Vol                {Write volume/data}π    OUT DX, ALπ  end;πend;ππFunction ResetSB : boolean;      {resets the SB}πbeginπ  Port[ResetPort] := 1;π  Delay(1);π  Port[ResetPort] := 0;π  Delay(1);π  if Port[PollPort] and 128 = 128 thenπ    ResetSB := Trueπ  elseπ    ResetSB := False;πend;ππProcedure ShowDots(D : integer);   {show the voice data}πvarπ  x, y : word;π  NewX : word;πbeginπ  for x := 1 to XWidth * d doπ  beginπ    port[CommandPort] := $20;                     { these three lines }π    repeat until (port[PollPort] and 128 = 128);  { gets the actual   }π    y := port[ReadPort];                          { data from the SB  }ππ    if y > 128 + MaxHeight thenπ      y := 128 + MaxHeight;π    if y < 128 - MaxHeight thenπ      y := 128 - MaxHeight;ππ    NewX := x div d;π    PutDot(NewX + XStart, OldDots[x] + YMid - 128, ColorBack);π    PutDot(NewX + XStart, y + YMid - 128, y div 2);π    OldDots[x] := y;π  end;π  if keypressed thenπ  begin    {pause}π    Ch := ReadKey;π    if Ch = #32 thenπ      repeat until keypressed;π  end;πend;ππProcedure Init;    {initialize all the variables}πvarπ  N : longint;πbeginπ  InitVideo($13, TRUE);π  Ch        := #0;π  XMax      := 319;π  XMid      := XMax div 2;π  YMax      := 199;π  YMid      := YMax div 2;π  XInt      := 10;π  XWidth    := 280;π  XStart    := XMid - XWidth div 2;π  MaxHeight := 60;π  Color     := 9;π  ColorBack := 0;π  SquareFill(XStart-10, YMid-MaxHeight-1-10, XStart+XWidth+1+10, YMid+MaxHeight+1+10, 10);π  SquareFill(XStart, YMid-MaxHeight-1, XStart+XWidth+1, YMid+MaxHeight+1, ColorBack);π  for N := 0 to MaxOldDots doπ    OldDots[N] := 128;π  if ResetSb then;πend;ππBEGINπ  Init;π  SetMixer(ADCChannel, 1);   {Sets the ADC channel to MIC}ππ  {NOTE: I don't know if the mixer routines will work on any otherπ         SB. If something stalls, then exclude the mixer statementsπ         If you want to use the LINE-IN, then SetMixer(ADCChannel, 6);}ππ  While Ch <> #27 do ShowDots(1);    {This value is a time constant}πEND.π                 33     11-02-9307:50ALL                      EDWARD SCHLUNDER         Format for WAV Files     IMPORT              33     ■"WC {πEDWARD SCHLUNDERππ> Hey everyone.. I am requesting some info on the File format of MODπ> Files  and also WAV Files. I would Really appreciate any help on this topic.ππWell, the MOD File format has been posted over the place many times, so Iπwon't post THAT again. But here comes the WAV File format that you wanted..ππ               WAV File Format. Written by Edward Schlunder.π                        Information from Tony Cookππ Byte(S)        NORMAL CONTENTS               PURPOSE/DESCRIPTIONπ ---------------------------------------------------------------------------ππ 00 - 03        "RIFF"                        Just an identification block.π                                              The quotes are not included.ππ 04 - 07        ???                           This is a long Integer. Itπ                                              tells the number of Bytes longπ                                              the File is, includes header,π                                              not just the Sound data.ππ 08 - 11        "WAVE"                        Just an other I.D. thing.ππ 12 - 15        "fmt "                        Just an other I.D. thing.ππ 16 - 19        16, 0, 0, 0                   Size of header to this point.ππ 20 - 21        1, 0                          Format tag. I'm not sure whatπ                                              'Format tag' means, but Iπ                                              believe it has something toπ                                              do With how the File isπ                                              formated, so that if someoneπ                                              wants to change the Fileπ                                              format to include somethingπ                                              new, they could also changeπ                                              this to show that it's aπ                                              different format.ππ 22 - 23        1, 0                          Channels. Channels is how manyπ                                              Sounds to be played at once.π                                              Sound Blasters have only oneπ                                              channel, and this is probablyπ                                              why this is normally set to 1.π                                              The Amiga has 4 (hence 4π                                              channel MODs) channels. Theπ                                              Gravis Ultra Sound has manyπ                                              more, I believe up to 32.ππ 24 - 27        ???                           Sampling rate, or (in otherπ                                              Words), samples per second.π                                              This is used to determineπ                                              how fast to play the WAV. Itπ                                              is also essentially the sameπ                                              as Bytes 28-31.ππ 28 - 31        ???                           Average Bytes per second.ππ 32 - 33        1, 0                          Block align.ππ 34 - 35        8, 0                          Bits per sample. Ex: Soundπ                                              Blaster can only do 8, Soundπ                                              Blaster 16 can make 16.π                                              Normally, the only valid valuesπ                                              are 8, 12, and 16.ππ 36 - 39        "data"                        Marker that comes just beforeπ                                              the actual sample data.ππ 40 - 43        ???                           The number of Bytes in theπ                                              sample.ππ      There, I hope you like it.. if you ever have any needs For Soundπ   card or just Sound related Programming information, give me a *bang*π   and I'll run... I might be late replying, but I will get back to you.π}π                               34     11-02-9318:38ALL                      LENNERT BAKKER           DETECTS SoundBlaster     IMPORT              22     ■"└± {πFrom: LENNERT BAKKERπSubj: SB AutoDetectπ    Here's how to autodetect a soundblaster and it's baseaddressπ    and some other support-stuff for your convenience: }πππ{ Hey let's check this SB out 8-)}ππConst SBReset     = $6;π      SBRead      = $A;π      SBWrite     = $C;π      SBStatus    = $E;ππVar   SBPort      : Word;π      SBInstalled : Boolean;ππProcedure DetectSoundBlaster;πConst NrTimes           = 10;π      NrTimes2          = 50;πVar   Found             : Boolean;π      Counter1,Counter2 : Word;πBeginπ SBPort:=$210;π Found:=False;π Counter1:=NrTimes;π  While (SBPort<=$260) And Not Found Doπ   Beginπ    Port[SBPort+$6]:=1;π    Port[SBPort+$6]:=0;π    Counter2:=NrTimes2;π     While (Counter2>0) And (Port[SBPort+$E]<128) Doπ      Dec(Counter2);π     If (Counter2=0) Or (Port[SBPort+$A]<>$AA) Thenπ      Beginπ       Dec(Counter1);π        If (Counter1=0) Thenπ         Beginπ          Counter1:=NrTimes;π          SBPort:=SBPort+$10;π         Endπ      End Else Found:=True;π   End;π  If Found then SBInstalled:=Trueπ   Else SBInstalled:=False;πEnd;ππBeginπ DetectSoundBlaster;π  If SBInstalled thenπ   Writeln('SoundBlaster found at port :', SBPort)π  elseπ   Writeln('No soundcard, no boogie!');πEnd.πππ{Here's how to initialize the DSP:}ππProcedure SetupSoundBlaster;πVar I,BDum : Byte;πBeginπ  If SBInstalled thenπ   Beginπ    Port[SBPort+SBReset]:=1; {Reset DSP}π     For I:=1 to 6 doπ      BDum:=Port[SBPort+SBStatus];π    Port[SBPort+SBReset]:=0;π     For I:=1 to 6 doπ      BDum:=Port[SBPort+SBStatus];π     Repeat Until Port[SBPort+SBStatus]>$80;π   End;πEnd;ππ{Respectively turn the speaker on/off}ππProcedure TurnOnSBSpeaker;πBeginπ Repeat Until Port[SBPort+SBWrite]<$80;π Port[SBPort+SBWrite]:=$D1;πEnd;ππProcedure TurnOffSBSpeaker;πBeginπ Repeat Until Port[SBPort+SBWrite]<$80;π Port[SBPort+SBWrite]:=$D3;πEnd;ππ{π  Here's basically how you play a sample, you should reprogramπ  the timer though and have your interrupt routine output bytesπ  to the DSP at regular intervals, say 10000 times/sec or so.π  Rather use machine-language instead, but that shouldn't be tooπ  hard now, should it? 8)π}ππProcedure PlaySample(Sample:Pointer;Length:Word);πVar A : Word;πBeginπ For A:=1 to Length Doπ  Beginπ   Port[SBPort+SBWrite]:=$10;π   Port[SBPort+SBWrite]:=Mem[Seg(Sample^):Ofs(Sample^)+A];π   {Delay some time}π  End;πEnd;ππ{Or sumtin like this (untested) }ππProcedure PlaySampleASM(Sample:Pointer;Length:Word); Assembler;πAsmπ Les Di,[Sample]π Mov Dx,SBPort+SBWriteπ Mov Cx,Lengthπ@LoopIt:π LodsBπ Out Dx,$10π Out Dx,Alππ { Delay Some Time -- What about 1000 NOPs or so ;-) }ππ Loop @LoopItπEnd;ππ                                                             35     01-27-9412:14ALL                      STEVEN TALLENT           Midi                     IMPORT              25     ■"8. {π> Is there anyone here who has a source on how to play MID-files inπ> PAS-programs, they could post here or NetMail to me???ππI can tell you how to access the MIDI port for MPU-401 compatibleπcontrollers.  The MFF (.MID) format is WAY too complex to describe here,πbut I *highly* recommend studying the excellent set of articles by CharlesπPetzold on MIDI and MIDI files in PC Magazine Vol 11, No 7 (Aprilπ14, 1992) to Vol 11, No 19 (November 10, 1992).  The article was mainly forπWindows programmers, but he spent a good portion of the articlesπexplaining MIDI itself in detail (including the MFF (.MID) format).  Allπhis source code and sample programs are availible on ZiffNet.  You canπalso get the MFF format detailed in the 14-page document "Standard MIDI Filesπ1.0" from the International MIDI Association for $7 + $1.50p&h US funds (callπ310-649-6434).ππI wrote a small (buggy, not working yet) unit for MPU-401 access fromπinformation I got here a few months back.  Your MIDI device must beπfully MPU-401 compatible to use this.ππ{ MPU-401 MIDI playback/record routines }π{ Public domain 1993 Steven Tallent     }π{ Plays the proper notes on an MPU-401  }π{ compatible synthesizer. }π{ Reading the Status port (331h) and masking 80h will tell you if}π{ something is waiting to be received from the mpu-401. }ππUnit Midi;ππ{**********************} Interface {**********************}ππType MPU401 = objectπ     Address : Word; {Data port. Status/Comport 1 higher, standard 330h-331h}π     Silent  : Boolean;              {Silence : Software mute }π     Function  Exists : Boolean;     {Does an MPU-401 device exist here?}π     Function  ByteHere: Boolean;    {Is a byte ready to be received?}π     Function  RecByte : Byte;       {Get byte from MIDI device}π     Procedure SendByte (x:Byte);    {Send byte to MIDI device}π     Procedure SendStr (x : String); {Send string of bytes to MIDI device}π     end;ππVAR Synth : MPU401;ππ{********************} Implementation {*******************}ππFunction MPU401.Exists : Boolean;πBeginπ  Exists := True;π  end;ππFunction MPU401.ByteHere : Boolean;πBeginπ  If (port[Address+1] and $80) = 0 then ByteHere := True {wrong?}π                                  else ByteHere := False;π  end;ππFunction MPU401.RecByte : Byte;πBeginπ  RecByte := Port[Address];π  end;ππProcedure MPU401.SendByte (x:Byte);π{Must wait for no data in the buffer}πBeginπ  Repeat until (Port[Address+1] and $80) = $80; {wrong?}π  Port[Address] := x;π  end;ππProcedure MPU401.SendStr (x : String);πVar t : Byte;πBeginπ  For t := 1 to ord(x[0]) do SendByte (ord(x[t]));π  end;ππ{Initialize}πBeginπ  Synth.Address := $300;π  Synth.Silent := False;π  end.ππ{πThis is semi-OOP, so its pretty simple to use.  MIDI uses 1, 2, or 3 byteπcommands to send messages.  For any commands you send to the MIDI device,πuse SendByte for each byte or send them all in SendStr for convenience.πIf you get it working, please respond with the fixed version eitherπhere or Netmail.π}                                                                                        36     01-27-9412:15ALL                      DANIEL CUNNINGHAM        Reading MODs             IMPORT              42     ■"╢╬ {π-> Does anyone know how to read a .MOD file in pascal? Not play a .MODπ-> just read all the pattern and track info. All the notes and stuff andπ-> effects. I dont care about the instrument data and all that.π-> If so, could you please post a source or something?ππI wrote a MOD sample ripper, thought about distributing it, it's ratherπnice.  I wrote it in TP.  I have some doc files on MOD's you might beπinterested in...ππSubject: Amiga modules formaatππ Have you ever wondered how a Protracker 1.1B module is built up?ππ Well, here's the...ππ Protracker 1.1B Song/Module Format:π -----------------------------------ππ Offset  Bytes  Descriptionπ ------  -----  -----------π    0     20    Songname. Remember to put trailing null bytes at theπend...ππ Information for sample 1-31:ππ Offset  Bytes  Descriptionπ ------  -----  -----------π   20     22    Samplename for sample 1. Pad with null bytes.π   42      2    Samplelength for sample 1. Stored as number of words.π                Multiply by two to get real sample length in bytes.π   44      1    Lower four bits are the finetune value, stored as aπsignedπ                four bit number. The upper four bits are not used, andπ                should be set to zero.π                Value:  Finetune:π                  0        0π                  1       +1π                  2       +2π                  3       +3π                  4       +4π                  5       +5π                  6       +6π                  7       +7π                  8       -8π                  9       -7π                  A       -6π                  B       -5π                  C       -4π                  D       -3π                  E       -2π                  F       -1ππ   45      1    Volume for sample 1. Range is $00-$40, or 0-64 decimal.π   46      2    Repeat point for sample 1. Stored as number of wordsπoffsetπ                from start of sample. Multiply by two to get offset inπbytes.π   48      2    Repeat Length for sample 1. Stored as number of words inπ                loop. Multiply by two to get replen in bytes.ππ Information for the next 30 samples starts here. It's just like theπinfo forπ sample 1.ππ Offset  Bytes  Descriptionπ ------  -----  -----------π   50     30    Sample 2...π   80     30    Sample 3...π    .π    .π    .π  890     30    Sample 30...π  920     30    Sample 31...ππ Offset  Bytes  Descriptionπ ------  -----  -----------π  950      1    Songlength. Range is 1-128.π  951      1    Well... this little byte here is set to 127, so that oldπ                trackers will search through all patterns when loading.π                Noisetracker uses this byte for restart, but we don't.π  952    128    Song positions 0-127. Each hold a number from 0-63 thatπ                tells the tracker what pattern to play at that position.π 1080      4    The four letters "M.K." - This is something Mahoney &πKaktusπ                inserted when they increased the number of samples fromπ                15 to 31. If it's not there, the module/song uses 15πsamplesπ                or the text has been removed to make the module harderπtoπ                rip. Startrekker puts "FLT4" or "FLT8" there instead.ππOffset  Bytes  Descriptionπ ------  -----  -----------π 1084    1024   Data for pattern 00.π    .π    .π    .π xxxx  Number of patterns stored is equal to the highest patternnumberπ       in the song position table (at offset 952-1079).ππ Each note is stored as 4 bytes, and all four notes at each position inπ the pattern are stored after each other.ππ 00 -  chan1  chan2  chan3  chan4π 01 -  chan1  chan2  chan3  chan4π 02 -  chan1  chan2  chan3  chan4π etc.ππ Info for each note:ππ  _____byte 1_____   byte2_    _____byte 3_____   byte4_π /                \ /      \  /                \ /      \π 0000          0000-00000000  0000          0000-00000000ππ Upper four    12 bits for    Lower four    Effect command.π bits of sam-  note period.   bits of sam-π ple number.                  ple number.ππ Periodtable for Tuning 0, Normalπ   C-1 to B-1 : 856,808,762,720,678,640,604,570,538,508,480,453π   C-2 to B-2 : 428,404,381,360,339,320,302,285,269,254,240,226π   C-3 to B-3 : 214,202,190,180,170,160,151,143,135,127,120,113ππ To determine what note to show, scan through the table until you findπ the same period as the one stored in byte 1-2. Use the index to lookπ up in a notenames table.ππ This is the data stored in a normal song. A packed song starts with theπ four letters "PACK", but i don't know how the song is packed: You canπ get the source code for the cruncher/decruncher from us if you need it,π but I don't understand it; I've just ripped it from another tracker...ππ In a module, all the samples are stored right after the patterndata.π To determine where a sample starts and stops, you use the sampleinfoπ structures in the beginning of the file (from offset 20). Take a lookπ at the mt_init routine in the playroutine, and you'll see just how itπ is done.ππ Lars "ZAP" Hamre/Amiga Freelancersπππ*** THE END ***ππI believe that file goes under the name of MODFORM.DOC, not sure.  Notπeven sure where I got it.  Anyway, enjoy.π                                                                                                   37     02-15-9408:07ALL                      WILBERT VAN LEIJEN       SB Text to Speech Unit   IMPORT              36     ■"ÿl { SBTS.PAS -- Sound Blaster Text To Speech Interface for Turbo Pascal 6.0 }ππUnit SBTS;ππInterfaceππ{$IFNDEF VER60 }π   ** Needs Version 6.0 of Turbo Pascal to compile **π{$ENDIF }ππ{                                  SBTS.PASππ      This unit provides an interface to the SBTALKER (TM) Text-to-Speechπ      driver.ππ      USAGE NOTES:π       1.  Make sure you have made SBTALKER resident, prior to running yourπ           application.  Call from the DOS command line:π              SBTALKER /DBLASTERππ           SBTALKER.EXE and BLASTER.DRV are found on the diskettes thatπ           came with the Sound Blaster.π       2.  Due to the fact that this unit relies on the built-in assembler,π           you'll need Turbo Pascal, version 6.0 or later to recompile.π       3.  IMPORTANT:  Don't attempt to run an application within theπ           Turbo Pascal Integrated Development Environment.  Do not launchπ           it inside a software-debugger either!  It'll HANG your system.π           RUN it from the DOS command line.ππ       Written by Wilbert van Leijen, Amsterdam 1991.π       Released with source code and all to the Public Domain on anπ       AS-IS basis.  The author assumes NO liability; you use this at yourπ       risk.ππ}πTypeπ  SpeechType   = Record                { SBTALKER configuration record }π                   talk,π                   phoneme     : String;π                   gender,π                   tone,π                   volume,π                   pitch,π                   speed       : Integer;π                 end;πConstπ  TalkerReady  : Boolean = False;      { Flag indicating SBTALKER status }ππVarπ  TalkPtr      : Pointer;              { Pointer to the resident driver }π  SpeechRec    : ^SpeechType;          { Pointer to the configuration record }ππProcedure Say(talk : String);πProcedure Settings(gender, tone, volume, pitch, speed : Integer); Function πUnloadDriver : Boolean;ππImplementationππ{$R-,S- }ππ{ Talk to me }ππProcedure Say(talk : String); Assembler;ππASMπ        CMP    [TalkerReady], Falseπ        JE     @1π        LES    DI, [SpeechRec]π        PUSH   DSπ        LDS    SI, talkπ        CLDπ        LODSBπ        STOSBπ        XOR    CH, CHπ        MOV    CL, ALπ        REP    MOVSBπ        POP    DSπ        MOV    AL, 7π        CALL   [TalkPtr]π@1:πend;  { Say }πππ{ Alter the settings of the SBTALKER driver }ππProcedure Settings(gender, tone, volume, pitch, speed : Integer); Assembler;ππASMπ        CMP    [TalkerReady], Falseπ        JE     @1π        LES    DI, [SpeechRec]π        CLDπ        ADD    DI, SpeechType.genderπ        MOV    AX, genderπ        STOSWπ        MOV    AX, toneπ        STOSWπ        MOV    AX, volumeπ        STOSWπ        MOV    AX, pitchπ        STOSWπ        MOV    AX, speedπ        STOSWπ        MOV    AL, 2π        CALL   [TalkPtr]π@1:πend;  { Settings }ππ{ Unload the SBTALKER driver.  Returns True is successful }ππFunction UnloadDriver : Boolean; Assembler;ππASMπ        MOV    AX, Falseπ        CMP    [TalkerReady], Falseπ        JE     @1π        MOV    AX, 0FBFFhπ        INT    2Fhπ@1:πend;  { UnloadDriver }ππBegin  { SBTS }πASMππ  { Get the vector to multiplex interrupt 2Fh.  Assume it belongs to SBTALKER }ππ        MOV    AX, 352Fhπ        INT    21hπ        MOV    AX, ESπ        OR     AX, AXπ        JZ     @1ππ  { Pass the magic number to the handler }ππ        MOV    AX, 0FBFBhπ        INT    2Fhππ  { Driver responds if the return code is non zero }ππ        OR     AX, AXπ        JNE    @1ππ  { Retrieve the pointers to the SBTALKER driver and its configuration record }ππ        MOV    AX, ES:[BX+4]π        MOV    DX, ES:[BX+6]π        MOV    Word Ptr [TalkPtr], AXπ        MOV    Word Ptr [TalkPtr+2], DXπ        ADD    BX, 20hπ        MOV    Word Ptr [SpeechRec], BXπ        MOV    Word Ptr [SpeechRec+2], DXππ  { Put the default values for gender, tone etc. into this record }ππ        LES    DI, [SpeechRec]π        ADD    DI, SpeechType.genderπ        CLDπ        SUB    AX, AXπ        STOSW                          { gender = male }π        STOSW                          { tone   = bass }π        MOV    AX, 5π        STOSW                          { volume = 5 }π        STOSW                          { pitch  = 5 }π        STOSW                          { speed  = 5 }π        MOV    AL, 2π        CALL   [TalkPtr]π        MOV    [TalkerReady], Trueπ@1:πend;πend.  { SBTS }ππSample call:  Say('hello world!');ππ                                 38     02-15-9408:40ALL                      RICHARD SANDS            Speaker Module in ASM    IMPORT              39     ■"¿╤ UNIT Tone;  {$S-,R-,D-,L-}ππ    (* TONE.PAS - Sound Module for Turbo Pascal 6.0 - Turbo Visionπ     * Written by Richard R. Sandsπ     * Compuserve ID 70274,103π     * January 1991π     *π     * NOTE: Do Not Overlayπ     *)ππINTERFACEππ   Procedure Sound(Hz:Word);π   Procedure NoSound;π   Procedure Delay(MS : Word);ππ   Procedure Beep(Hz, MS:Word);π     { Same asπ               Sound(Hz);π               Delay(MS);π               NoSound;       ...but with more efficient code. }ππ   Procedure BoundsBeep;π     { Used for signalling a boundry or invalid command }ππ   Procedure ErrorBeep;π     { Used for signalling an error condition }ππ   Procedure AttentionBeep;π     { Used for signalling the user }ππIMPLEMENTATIONππ  VARπ    OneMS : Word;ππ{ ------------------------------------------------------------------------- }πProcedure Beep(Hz, MS:Word); assembler;π     { Make the Sound at Frequency Hz for MS milliseconds }π  ASMπ    MOV  BX,Hzπ    MOV  AX,34DDHπ    MOV  DX,0012Hπ    CMP  DX,BXπ    JNC  @Stopπ    DIV  BXπ    MOV  BX,AXπ    IN      AL,61Hπ    TEST AL,3π    JNZ  @99π    OR      AL,3π    OUT  61H,ALπ    MOV  AL,0B6Hπ    OUT  43H,ALπ @99:π    MOV  AL,BLπ    OUT  42H,ALπ    MOV  AL,BHπ    OUT  42H,ALπ @Stop:π {$IFOPT G+}π    PUSH MSπ {$ELSE }π    MOV  AX, MS   { push delay time }π    PUSH AXπ  {$ENDIF }π    CALL Delay    { and wait... }ππ    IN   AL, $61  { Now turn off the speaker }π    AND  AL, $FCπ    OUT  $61, ALπ  end;ππ{ ------------------------------------------------------------------------- }πProcedure BoundsBeep; assembler;π  asmπ  {$IFOPT G+ }π     PUSH 1234      { Pass the Frequency }π     PUSH 10        { Pass the delay time }π  {$ELSE}π     MOV  AX, 1234  { Pass the Frequency }π     PUSH AXπ     MOV  AX, 10    { Pass the delay time }π     PUSH AXπ   {$ENDIF }π     CALL Beepπ  end;ππ{ ------------------------------------------------------------------------- }πProcedure ErrorBeep; assembler;π  asmπ  {$IFOPT G+ }π     PUSH 800   { Pass the Frequency }π     PUSH 75    { Pass the delay time }π  {$ELSE}π     MOV  AX, 800  { Pass the Frequency }π     PUSH AXπ     MOV  AX, 75   { Pass the delay time }π     PUSH AXπ  {$ENDIF }π     CALL Beepπ  end;ππ{ ------------------------------------------------------------------------- }πProcedure AttentionBeep; assembler;π  asmπ  {$IFOPT G+ }π     PUSH 660   { Pass the Frequency }π     PUSH 50    { Pass the delay time }π  {$ELSE}π     MOV  AX, 660  { Pass the Frequency }π     PUSH AXπ     MOV  AX, 50   { Pass the delay time }π     PUSH AXπ  {$ENDIF }π     CALL Beepπ  end;ππ{ ------------------------------------------------------------------------- }πProcedure Sound(Hz:Word); assembler;π   ASMπ      MOV  BX,Hzπ      MOV  AX,34DDHπ      MOV  DX,0012Hπ      CMP  DX,BXπ      JNC  @DONEπ      DIV  BXπ      MOV  BX,AXπ      IN   AL,61Hπ      TEST AL,3π      JNZ  @99π      OR   AL,3π      OUT  61H,ALπ      MOV  AL,0B6Hπ      OUT  43H,ALπ@99:  MOV  AL,BLπ      OUT  42H,ALπ      MOV  AL,BHπ      OUT  42H,ALπ@DONE:π  end;ππ{ ------------------------------------------------------------------------- }πProcedure NoSound; assembler;π  asmπ     IN   AL, $61π     AND  AL, $FCπ     OUT  $61, ALπ  end;ππ{ ------------------------------------------------------------------------- }πprocedure DelayOneMS; assembler;π  asmπ     PUSH CX         { Save CX }π     MOV  CX, OneMS  { Loop count into CX }π  @1:π     LOOP @1         { Wait one millisecond }π     POP  CX         { Restore CX }π  end;ππ{ ------------------------------------------------------------------------- }πProcedure Delay(ms:Word); assembler;π  asmπ     MOV  CX, ms    π     JCXZ @2           π  @1:π     CALL DelayOneMSπ     LOOP @1π  @2:π  end;ππ{ ------------------------------------------------------------------------- }πProcedure Calibrate_Delay; assembler;π  asm   π     MOV  AX,40h         π     MOV  ES,AX          π     MOV  DI,6Ch          { ES:DI is the low word of BIOS timer count }π     MOV  OneMS,55        { Initial value for One MS's time }π     XOR  DX,DX           { DX = 0 }π     MOV  AX,ES:[DI]      { AX = low word of timer }π  @1:π     CMP  AX,ES:[DI]      { Keep looking at low word of timer }π     JE   @1              { until its value changes... }π     MOV  AX,ES:[DI]      { ...then save it }π  @2:π     CAll DelayOneMs      { Delay for a count of OneMS (55) }π     INC  DX              { Increment loop counter }π     CMP  AX,ES:[DI]      { Keep looping until the low word }π     JE   @2              { of the timer count changes again }π     MOV  OneMS, DX       { DX has new OneMS }π  end;ππBEGINπ  Calibrate_DelayπEND.ππ{ ==============================  DEMO ==================================}ππProgram ToneTest;ππUSES Tone;ππbeginπ   ErrorBeep;π   Delay(500);π   AttentionBeep;π   Delay(500);π   BoundsBeep;π   Delay(500);π   Beep(440, 250);πend.π                                     39     05-25-9408:20ALL                      SEAN PALMER              R2D2 Noises              SWAG9405            28     ■"ΦK π{πIf anyone can fill me in on how to output in stereo, I'd be veryπappreciative... I've heard that port $220/$221 is for left channel,π$222/$223 is for the right, but that doesn't make any sense...does it?ππThis code makes R2D2 noises on a SoundBlaster until you press ESC.ππ{adapted from SS4CH.PAS by Frank Hirsch}πUSES Crt;ππconst sampleSize=4096;πvar sampleData:array[0..sampleSize-1]of byte;πconst samplePos:longint=0;πvar sampleSpeed:longint;πvar sampleDelta:longint;ππconst resetPort =$226;πconst readPort  =$22A;πconst writePort =$22C;πconst dataAvailPort=$22E;ππfunction readByte:byte;beginπ repeat until shortInt(port[dataAvailPort])<0;π readByte:=port[readPort];π end;ππprocedure initDSP;beginπ port[resetPort]:=1;π delay(1);π port[resetPort]:=0;π repeat until readByte=$AA;π end;ππvar counter:longint;ππprocedure timerInt;assembler;asmπ  push axπ  push bxπ  push dxπ  push diπ  push dsπ  push esπ  mov ax,seg @DATAπ  mov ds,axππ  mov es,[segB800]π  xor byte ptr es:[0],$21ππ  mov bx,[word ptr samplePos+2]π  mov ah,byte ptr sampleData[bx]π  mov dx,[word ptr sampleSpeed]    {next sample byte}π  add [word ptr samplePos],dxπ  adc bx,[word ptr sampleSpeed+2]π  and bx,[sampleSize-1]π  mov [word ptr samplePos+2],bxπ  mov bx,[word ptr sampleDelta]π  add [word ptr sampleSpeed],bxπ  mov bx,[word ptr sampleDelta+2]π  adc [word ptr sampleSpeed+2],bxπ  mov dx,writePortπ @P2:              {ready for output byte?}π  in al,dxπ  test al,$80π  jnz @P2π  mov al,ahπ  out dx,alππ  mov al,$20       {process interrupt}π  out $20,alπ{  sti}π                   {prep NEXT output}π @P1:              {ready for command?}π  in al,dxπ  test al,$80π  jnz @P1π  mov al,$10       {set up a DAC output}π  out dx,alππ  db $66; inc word ptr [counter]ππ  pop esπ  pop dsπ  pop diπ  pop dxπ  pop bxπ  pop axπ  iretπ  end;ππvarπ  vec08:pointer absolute 0:8*4;π  old08:pointer;ππprocedure setTimerTics(tics:word);beginπ  asm cli; end;π  port[$43]:=$36;π  port[$40]:=lo(tics);π  port[$40]:=hi(tics);π  asm sti end;π  end;ππprocedure setTimerFreq(freq:word);beginπ  setTimerTics(succ(word($1234DC div freq)));π  end;ππprocedure stopTimer;begin setTimerTics(0); end;ππprocedure writeByte(b:byte);beginπ  repeat until shortInt(port[writePort])>=0;π  port[writePort]:=b;π  end;ππprocedure speaker(onOff:boolean);beginπ  if onOff then writeByte($D1)π  else writeByte($D3);π  end;ππvar i,j,n:word;ππconst rate=16384;ππprocedure note(freq,dur,slide:longint);πbeginπ  counter:=0;π  sampleSpeed:=freq*sampleSize*(65536 div rate);π  sampleDelta:=slide;π  dur:=(dur*rate)div 1000;π  repeatπ    if port[$60]=$81 then break;π    until counter>=dur;π  end;πππbeginπ initDSP;π for i:=0 to sampleSize-1 doπ   sampleData[i]:=round(sin(i*pi/(sampleSize shr 1))*127.5+127.5);π old08:=vec08;π speaker(true);π writeByte($10);  {prep sb for data}π asm cli end;π vec08:=@timerInt;π asm sti end;π setTimerFreq(rate);π repeatπ   case random(4) ofπ     0:note(random(1900)+60,(random(2)*80)+40,integer(random(3))-1);π     1:note(random(800)+450,(random(2)*80)+140,integer(random(2049))π                                                              -1024);π     2:note(0,(random(2)+1)*40,0);π     3:note(random(30)+15,(random(2)*80)+40,random(2));π     end;π   until port[$60]=$81;π stopTimer;π asm cli end;π vec08:=old08;π asm sti end;π speaker(false);  {it's probably gonna eat this as data}π speaker(false);π end.π                                                                                  40     05-25-9408:22ALL                      BRIAN GRAINGER           TP AND SOUND BLASTER     SWAG9405            25     ■"\┴ {πCL▒    Come to speak of this...  do you (or anyone) know which ports to zap theπCL▒    data to for the SB to get it to play?  Or better yet, even how to get itπCL▒    to play in DMA transfer mode?ππTry this code.π}π(* A unit to provide basic control over a Sound Blaster or compatible card.*)π(* It works by reading and writing to the standard Sound Blaster ports.    *)π(* Released to the public domain by Brian Grainger, Sparwood, BC.          *)ππUNIT SoundBlaster;ππ(*********************************)INTERFACE(********************************)ππPROCEDURE sbSetAddressDelay(StereoMode : BYTE);πPROCEDURE sbSetDataDelay(StereoMode : BYTE);πPROCEDURE sbSetDataReg(RegNum, Value, StereoMode : BYTE);πFUNCTION  sbGetStatus(StereoMode : BYTE) : BYTE;πPROCEDURE sbResetTimers;πPROCEDURE sbEnableInterrupts;πPROCEDURE sbTurnOff;πFUNCTION  sbIsInstalled : BOOLEAN;ππ(*******************************)IMPLEMENTATION(*****************************)ππCONSTπ  cMono  = 0;π  cLeft  = 1;π  cRight = 2;ππVARπ  vStatus1 : BYTE;π  vStatus2 : BYTE;π  vDelay   : BYTE;π  vI       : BYTE;ππPROCEDURE sbSetAddressDelay(StereoMode : BYTE);π  BEGINπ    FOR vI := 0 TO 5 DOπ      CASE StereoMode OFπ        cMono  : vDelay := Port[$388];π        cLeft  : vDelay := Port[$220];π        cRight : vDelay := Port[$222];π      END;π  END;ππPROCEDURE sbSetDataDelay(StereoMode : BYTE);π  BEGINπ    FOR vI := 0 TO 34 DOπ      CASE StereoMode OFπ        cMono  : vDelay := Port[$388];π        cLeft  : vDelay := Port[$220];π        cRight : vDelay := Port[$222];π      END;π  END;ππPROCEDURE sbSetDataReg(RegNum, Value, StereoMode : BYTE);π  BEGINπ    CASE StereoMode OFπ      cMono  : Port[$388] := RegNum;π      cLeft  : Port[$220] := RegNum;π      cRight : Port[$222] := RegNum;π    END;π    sbSetAddressDelay(StereoMode);π    CASE StereoMode OFπ      cMono  : Port[$389] := Value;π      cLeft  : Port[$221] := Value;π      cRight : Port[$222] := Value;π    END;π    sbSetDataDelay(StereoMode);π  END;ππFUNCTION sbGetStatus(StereoMode : BYTE) : BYTE;π  BEGINπ    sbGetStatus := 0;π    CASE StereoMode OFπ      cMono  : sbGetStatus := Port[$388];π      cLeft  : sbGetStatus := Port[$220];π      cRight : sbGetStatus := Port[$222];π    END;π  END;ππPROCEDURE sbResetTimers;π  BEGINπ    sbSetDataReg($04, $60, cMono);π  END;ππPROCEDURE sbEnableInterrupts;π  BEGINπ    sbSetDataReg($04, $80, cMono);π  END;ππPROCEDURE sbTurnOff;π  BEGINπ    FOR vI := $01 TO $F5 DOπ      sbSetDataReg(vI, $00, cMono);π  END;ππFUNCTION sbIsInstalled : BOOLEAN;π  BEGINπ    sbIsInstalled := FALSE;π    sbResetTimers;π    sbEnableInterrupts;π    vStatus1 := sbGetStatus(cMono);π    sbSetDataReg($02, $FF, cMono);  (* Set timer 1 data register *)π    sbSetDataReg($04, $21, cMono);  (* Start timer 1             *)π    FOR vI := 1 TO 4 DOπ      sbSetDataDelay(cMono);        (* Wait at least 80 uSeconds *)π    vStatus2 := sbGetStatus(cMono);π    sbResetTimers;π    sbEnableInterrupts;π    IF (((vStatus1 AND $E0) = $00) AND ((vStatus2 AND $E0) = $C0)) THENπ      sbIsInstalled := TRUE;π  END;πEND.π                       41     05-25-9408:22ALL                      MIRKO HOLZER             SB Talk Unit             SWAG9405            16     ■"å¼ {π> Hi! I have the following problem:π> I'm trying to get my Sound Blaster card (version 1.0) to speak a string,π> like the SAY.EXE program that comes with SB.ππ(Sorry for the german comments, but I'm to lazy to rewrite them ≡:-|) }ππProgram Talk;π{ by Mirko Holzer; 16.2.1994 }ππUsesπ  Crt,π  Dos,π  Strings;ππConstπ  cSBTalkSig='FB ';ππTypeπ  tTalkEpStruc=recordπ    Signature: array[0..2] of char;  {Signatur: "FB "}π    MajorVers: byte;                 {Hauptversion ??}π    Entry: pointer;                  {Treiber Einsprungadresse}π    Unknown: array[0..23] of byte;   {Weiß nicht was da drin steht...}π    DataLen: byte;                   {Länge des zu sprechenden Strings}π    TalkStr: array[0..255] of char;  {Zu sprechender String}π  end;π  pTalkEpStruc=^tTalkEpStruc;ππVarπ  sbt: pTalkEpStruc;π  eing: string;πππFunction ChkSBT: pointer; assembler;πasmπ  mov ax,$FBFBπ  mov bx,0π  mov es,bxπ  int $2Fπ  mov dx,esπ  mov ax,bxπend;ππProcedure TalkIt(var sb: pTalkEpStruc; what: string);πVarπ  SBCall: pointer;πbeginπ  sb^.DataLen:=Length(what);π  StrPCopy(sb^.TalkStr,what);π  SBCall:=sb^.Entry;π  asmπ    les di,sbπ    mov bx,diπ    mov al,$07π    call [sbcall]π  end;πend;ππππbeginπ  sbt:=ChkSBT;π  ClrScr;π  Writeln('SBTalker - Test');π  Writeln('16.2.94 von Mirko Holzer');π  Writeln;π  If sbt^.Signature<>cSBTalkSig thenπ  beginπ    Writeln('The program sbtalk.exe is not installed.');π    Writeln('Programm beendet.');π    Writeln;π    Halt;π  end;π  TalkIt(sbt,'Hello, here is S B talker speaking... Please enter your string '+π             'or press enter to stop the program.');π  Writeln('Zu sprechenden String eingeben oder <ENTER> drücken für Ende.');π  Repeatπ    eing:='';π    Readln(eing);π    TalkIt(sbt,eing);π  Until eing='';π  TalkIt(sbt,'Look out for Demos from.... Terrible Minds Productions');π  Writeln;πend.πππ                                                                            42     05-25-9408:22ALL                      WILBERT VAN LEIJEN       SBTALKER                 SWAG9405            41     ■"~z {πSasha Case,ππ12-Apr-94 20:07, Sasha Case wrote to Allπ               Subject: SBTALKERπ              Terminate 1.40 REGISTEREDπππ SC> @MSGID: 3:711/929@fidonet 72328398π SC> @REGEED: 1.02u2 00910093π SC> Hi Everyone,π SC> π SC> I've tried once, a coupla months ago, but I'll try again:π SC> π SC> I'm look for anyone with a Sound Blaster SDK or anyone who knows/has π SC> source for π SC> how to access SBTALKER that comes with soundblaster.  Programs like π SC> SBTALKER π SC> and READ do it, and I have seen source for something that did what Iπ SC> needed,π SC> except it used a library I haven't got.  Any help on Units that do thisπ SC> orππHere you go!π}ππUnit SBTS;ππInterfaceππ{     This unit provides an interface to the SBTALKER (TM) Text-to-Speechπ      driver.ππ      USAGE NOTES:π       1.  Make sure you have made SBTALKER resident, prior to running yourπ           application.  Call from the DOS command line:π              SBTALKER /DBLASTERππ           SBTALKER.EXE and BLASTER.DRV are found on the diskettes thatπ           came with the Sound Blaster.π       2.  Due to the fact that this unit relies on the built-in assembler,π           you'll need Turbo Pascal, version 6.0 or later to recompile.π       3.  IMPORTANT:  Don't attempt to run an application within theπ           Turbo Pascal Integrated Development Environment.  Do not launchπ           it inside a software-debugger either!  It'll HANG your system.π           RUN it from the DOS command line.ππ       Written by Wilbert van Leijen, Amsterdam 1991.π       Released with source code and all to the Public Domain on anπ       AS-IS basis.  The author assumes NO liability; you use this at yourπ       risk.ππ       SBTALKER is a registred trade mark of First Byte, Inc. }ππTypeπ  SpeechType   = Record                { SBTALKER configuration record }π                   talk,π                   phoneme     : String;π                   gender,π                   tone,π                   volume,π                   pitch,π                   speed       : Integer;π                 end;πConstπ  TalkerReady  : Boolean = False;      { Flag indicating SBTALKER status }ππVarπ  TalkPtr      : Pointer;              { Pointer to the resident driver }π  SpeechRec    : ^SpeechType;          { Pointer to the configuration record }ππProcedure Say(talk : String);πProcedure Settings(gender, tone, volume, pitch, speed : Integer);πFunction UnloadDriver : Boolean;ππImplementationππ{$R-,S- }ππ{ Talk to me }ππProcedure Say(talk : String); Assembler;ππASMπ        CMP    [TalkerReady], Falseπ        JE     @1π        LES    DI, [SpeechRec]π        PUSH   DSπ        LDS    SI, talkπ        CLDπ        LODSBπ        STOSBπ        XOR    CH, CHπ        MOV    CL, ALπ        REP    MOVSBπ        POP    DSπ        MOV    AL, 7π        CALL   [TalkPtr]π@1:πend;  { Say }ππ{ Alter the settings of the SBTALKER driver.π  Gender: 0 is male, 1 is female;π  Tone:   0 is bass, 1 is treble;π  Volume, pitch and speed must be within the range 0..9.   }ππProcedure Settings(gender, tone, volume, pitch, speed : Integer); Assembler;ππASMπ        CMP    [TalkerReady], Falseπ        JE     @1π        LES    DI, [SpeechRec]π        CLDπ        ADD    DI, SpeechType.genderπ        MOV    AX, genderπ        STOSWπ        MOV    AX, toneπ        STOSWπ        MOV    AX, volumeπ        STOSWπ        MOV    AX, pitchπ        STOSWπ        MOV    AX, speedπ        STOSWπ        MOV    AL, 2π        CALL   [TalkPtr]π@1:πend;  { Settings }ππ{ Unload the SBTALKER driver.  Returns True is successful }ππFunction UnloadDriver : Boolean; Assembler;ππASMπ        MOV    AX, Falseπ        CMP    [TalkerReady], Falseπ        JE     @1π        MOV    AX, 0FBFFhπ        INT    2Fhπ@1:πend;  { UnloadDriver }ππBegin  { SBTS }πASMππ  { Get the vector to multiplex interrupt 2Fh.  Assume it belongs to SBTALKER }ππ        MOV    AX, 352Fhπ        INT    21hπ        MOV    AX, ESπ        OR     AX, AXπ        JZ     @1ππ  { Pass the magic number to the handler }ππ        MOV    AX, 0FBFBhπ        INT    2Fhππ  { Driver responds if the return code is non zero }ππ        OR     AX, AXπ        JNE    @1ππ  { Retrieve the pointers to the SBTALKER driver and its configuration record }ππ        MOV    AX, ES:[BX+4]π        MOV    DX, ES:[BX+6]π        MOV    Word Ptr [TalkPtr], AXπ        MOV    Word Ptr [TalkPtr+2], DXπ        ADD    BX, 20hπ        MOV    Word Ptr [SpeechRec], BXπ        MOV    Word Ptr [SpeechRec+2], DXππ  { Put the default values for gender, tone etc. into this record }ππ        LES    DI, [SpeechRec]π        ADD    DI, SpeechType.genderπ        CLDπ        SUB    AX, AXπ        STOSW                          { gender = male }π        STOSW                          { tone   = bass }π        MOV    AX, 5π        STOSW                          { volume = 5 }π        STOSW                          { pitch  = 5 }π        STOSW                          { speed  = 5 }π        MOV    AL, 2π        CALL   [TalkPtr]π        MOV    [TalkerReady], Trueπ@1:πend;πend.  { SBTS }ππ                                                            43     05-26-9406:37ALL                      MICHAEL W. ARMSTRONG     CDROM Player             IMPORT              178    ■"≡A { Copyright 1993 by Michael W. Armstrong.π                    2800 Skipwith Rdπ                    Richmond, VA 23294ππ  Compuserve ID 72740, 1145π  This program is entered as Shareware.  If you find it useful, a smallπ  donation would be appreciated.  Feel free to incorporate the code intoπ  your own programs.π}ππ{  NOTE : The CD_Vars and CDUNIT_P are at the end of this code }πππ{$X+}πprogram CDPlay;ππ{$IfDef Windows}π{$C PRELOAD}πuses CD_Vars, CDUnit_P, WinCRT, WinProcs;π{$Else}πuses CD_Vars, CDUnit_P, CRT, Drivers;π{$EndIf}ππTypeπ  TotPlayRec = Recordπ     Frames,π     Seconds,π     Minutes,π     Nada     : Byte;π  End;ππVarπ  GoodDisk : Boolean;π  SaveExit   : Pointer;π  OldMode    : Word;π  CurrentTrack,π  StartTrack,π  EndTrack   : Integer;π  TotPlay    : TotPlayRec;π  TrackInfo  : Array[1..99] of PAudioTrackInfo;ππfunction LeadingZero(w: Word): String;πvar s: String;πbeginπ  Str(w:0, s);π  LeadingZero := Copy('00', 1, 2 - Length(s)) + s;πend;πππprocedure DrawScreen;πConst TStr = '%03d:%02d';π      VStr = '%1d.%2d';πVar   FStr : PChar;π      NStr : String;π      Param: Array[1..2] of LongInt;π      Code : Integer;πbeginπ  WriteLn('CD ROM Audio Disk Player');π  WriteLn('Copyright 1992 by M. W. ARMSTRONG');π  Param[1] := MSCDEX_Version.Major;π  Param[2] := MSCDEX_Version.Minor;ππ{$IfDef Windows}π  wvsPrintf(FStr, VStr, Param);π{$Else}π  FormatStr(NStr, VStr, Param);π{$EndIf}ππ  WriteLn('MSCDEX Version ', NStr);π  Str(NumberOfCD, NStr);π  WriteLn('Number of CD ROM Drives is: '+Nstr);π  WriteLn('First CD Drive Letter is  : '+Chr(FirstCD+65));π  WriteLn('There are ' + LeadingZero(EndTrack - StartTrack + 1) + ' Tracks on this disk');π  Code := 1;πend;π{***********************************************************************}ππ{***********************************************************************}πππprocedure Setup;πVarπ  LeadOut,π  StartP,π  TotalPlayTime    : LongInt;π  I     : Integer;π  A,B,C : LongInt;π  Track : Byte;π  EA    : Array[1..4] of Byte;π  SP,EP : LongInt;ππBeginπ  FillChar(AudioDiskInfo, SizeOf(AudioDiskInfo), #0);π  DeviceStatus;π  If Audio THENπ  Beginπ    Audio_Disk_Info;π    TotalPlayTime := 0;π    LeadOut := AudioDiskInfo.LeadOutTrack;ππ    StartTrack := AudioDiskInfo.LowestTrack;π    EndTrack := AudioDiskInfo.HighestTrack;π    CurrentTrack := StartTrack;π    I := StartTrack-1;ππ    Repeat               { Checks if Audio Track or Data Track }π        Inc(I);π        Track := I;π        Audio_Track_Info(StartP, Track);π    Until (Track AND 64 = 0) OR (I = EndTrack);ππ    StartTrack := I;ππ    For I := StartTrack to EndTrack DOπ      Beginπ        Track := I;π        Audio_Track_Info(StartP, Track);π        New(TrackInfo[I]);π        FillChar(TrackInfo[I]^, SizeOf(TrackInfo[I]^), #0);π        TrackInfo[I]^.Track := I;π        TrackInfo[I]^.StartPoint := StartP;π        TrackInfo[I]^.TrackControl := Track;π      End;ππ    For I := StartTrack to EndTrack - 1 DOπ        TrackInfo[I]^.EndPoint := TrackInfo[I+1]^.StartPoint;π    TrackInfo[EndTrack]^.EndPoint := LeadOut;ππ    For I := StartTrack to EndTrack DOπ        Move(TrackInfo[I]^.EndPoint, TrackInfo[I]^.Frames, 4);ππ    TrackInfo[StartTrack]^.PlayMin := TrackInfo[StartTrack]^.Minutes;π    TrackInfo[StartTrack]^.PlaySec := TrackInfo[StartTrack]^.Seconds - 2;ππ    For I := StartTrack + 1 to EndTrack DOπ      Beginπ        EP := (TrackInfo[I]^.Minutes * 60) + TrackInfo[I]^.Seconds;π        SP := (TrackInfo[I-1]^.Minutes * 60) + TrackInfo[I-1]^.Seconds;π        EP := EP - SP;π        TrackInfo[I]^.PlayMin := EP DIV 60;π        TrackInfo[I]^.PlaySec := EP Mod 60;π      End;ππ    TotalPlayTime := AudioDiskInfo.LeadOutTrack - TrackInfo[StartTrack]^.StartPoint;π    Move(TotalPlayTime, TotPlay, 4);π  End;πend;ππ{***********************************************************************}πππBeginπ  Setup;π  If Audio THENπ  If Playing THENπ     StopAudioπ  ELSEπ     Beginπ       StopAudio;π       Play_Audio(TrackInfo[StartTrack]^.StartPoint,π             TrackInfo[EndTrack]^.EndPoint);π       Audio_Status_Info;π       DrawScreen;π     Endπ  ELSEπ      WriteLn('This is not an Audio CD');π  WriteLn('UPC Code is: ', UPC_Code);πend.ππ{ -----------------------------------   CUT HERE --------------------   }ππUnit CD_Vars;ππInterfaceππTypeπ  ListBuf    = Recordπ    UnitCode : Byte;π    UnitSeg,π    UnitOfs  : Word;π  end;π  VTOCArray  = Array[1..2048] of Byte;π  DriveByteArray = Array[1..128] of Byte;ππ  Req_Hdr    = Recordπ     Len     : Byte;π     SubUnit : Byte;π     Command : Byte;π     Status  : Word;π     Reserved: Array[1..8] of Byte;π  End;ππConstπ  Init       = 0;π  IoCtlInput = 3;π  InputFlush = 7;π  IOCtlOutput= 12;π  DevOpen    = 13;π  DevClose   = 14;π  ReadLong   = 128;π  ReadLongP  = 130;π  SeekCmd    = 131;π  PlayCD     = 132;π  StopPlay   = 133;π  ResumePlay = 136;ππTypeππ  Audio_Play = Recordπ    APReq    : Req_Hdr;π    AddrMode : Byte;π    Start    : LongInt;π    NumSecs  : LongInt;π  end;ππ  IOControlBlock = Recordπ    IOReq_Hdr : Req_Hdr;π    MediaDesc : Byte;π    TransAddr : Pointer;π    NumBytes  : Word;π    StartSec  : Word;π    ReqVol    : Pointer;π    TransBlock: Array[1..130] OF Byte;π  End;ππ  ReadControl = Recordπ    IOReq_Hdr : Req_Hdr;π    AddrMode  : Byte;π    TransAddr : Pointer;π    NumSecs   : Word;π    StartSec  : LongInt;π    ReadMode  : Byte;π    IL_Size,π    IL_Skip   : Byte;π  End;ππ  AudioDiskInfoRec = Recordπ    LowestTrack    : Byte;π    HighestTrack   : Byte;π    LeadOutTrack   : LongInt;π  End;ππ  PAudioTrackInfo   = ^AudioTrackInfoRec;π  AudioTrackInfoRec = Recordπ    Track           : Integer;π    StartPoint      : LongInt;π    EndPoint        : LongInt;π    Frames,π    Seconds,π    Minutes,π    PlayMin,π    PlaySec,π    TrackControl    : Byte;π  end;ππ  MSCDEX_Ver_Rec = Recordπ    Major,π    Minor       : Integer;π  End;ππ  DirBufRec    = Recordπ     XAR_Len   : Byte;π     FileStart : LongInt;π     BlockSize : Integer;π     FileLen   : LongInt;π     DT        : Byte;π     Flags     : Byte;π     InterSize : Byte;π     InterSkip : Byte;π     VSSN      : Integer;π     NameLen   : Byte;π     NameArray : Array[1..38] of Char;π     FileVer   : Integer;π     SysUseLen : Byte;π     SysUseData: Array[1..220] of Byte;π     FileName  : String[38];π  end;ππ  Q_Channel_Rec = Recordπ    Control     : Byte;π    Track       : Byte;π    Index       : Byte;π    Minutes     : Byte;π    Seconds     : Byte;π    Frame       : Byte;π    Zero        : Byte;π    AMinutes    : Byte;π    ASeconds    : Byte;π    AFrame      : Byte;π  End;ππVarπ  AudioChannel   : Array[1..9] of Byte;π  RedBook,π  Audio,π  DoorOpen,π  DoorLocked,π  AudioManip,π  DiscInDrive    : Boolean;π  AudioDiskInfo  : AudioDiskInfoRec;π  DriverList     : Array[1..26] of ListBuf;π  NumberOfCD     : Integer;π  FirstCD        : Integer;π  UnitList       : Array[1..26] of Byte;π  MSCDEX_Version : MSCDEX_Ver_Rec;π  QChannelInfo   : Q_Channel_Rec;π  Busy,π  Playing,π  Paused         : Boolean;π  Last_Start,π  Last_End       : LongInt;π  DirBuf         : DirBufRec;ππImplementationππBeginπ  FillChar(DriverList, SizeOf(DriverList), #0);π  FillChar(UnitList, SizeOf(UnitList), #0);π  NumberOfCD  := 0;π  FirstCD  := 0;π  MSCDEX_Version.Major := 0;π  MSCDEX_Version.Minor := 0;πend.ππ{ -----------------------------------   CUT HERE --------------------   }ππ{$X+}ππUnit CDUnit_P;ππInterfaceππ{Include the appropriate units.}ππ{$IfDef Windows}π{$C PRELOAD}πUses Strings, WinCRT, WinDOS, WinProcs, SimRMI, CD_Vars;π{$EndIf}π{$IfDef DPMI}πUses Strings, CRT, DOS, WinAPI, SimRMI, CD_Vars;π{$EndIf}π{$IfDef MSDOS}πUses Strings, CRT, DOS, CD_Vars;π{$EndIf}ππVarπ  Drive   : Integer;  { Must set drive before all operations }π  SubUnit : Integer;ππfunction File_Name(var Code : Integer) : String;ππfunction Read_VTOC(var VTOC : VTOCArray;π                   var Index : Integer) : Boolean;ππprocedure CD_Check(var Code : Integer);ππprocedure Vol_Desc(Var Code : Integer;π                   var ErrCode : Integer);ππprocedure Get_Dir_Entry(PathName : String;π                        var Format, ErrCode : Integer);ππprocedure DeviceStatus;ππprocedure Audio_Channel_Info;ππprocedure Audio_Disk_Info;ππprocedure Audio_Track_Info(Var StartPoint : LongInt;π                           Var TrackControl : Byte);ππprocedure Audio_Status_Info;ππprocedure Q_Channel_Info;ππprocedure Lock(LockDrive : Boolean);ππprocedure Reset;ππprocedure Eject;ππprocedure CloseTray;ππprocedure Resume_Play;ππprocedure Pause_Audio;ππprocedure Play_Audio(StartSec, EndSec : LongInt);ππfunction StopAudio : Boolean;ππfunction Sector_Size(ReadMode : Byte) : Word;ππfunction Volume_Size : LongInt;ππfunction Media_Changed : Boolean;ππfunction Head_Location(AddrMode : Byte) : LongInt;ππprocedure Read_Drive_Bytes(Var ReadBytes : DriveByteArray);ππfunction UPC_Code : String;ππImplementationππConstπ  CarryFlag  = $0001;ππVarπ{$IfDef MSDOS}π  Regs       : Registers;π{$Else}π  Regs       :TRealModeRecord; { from SimRMI Unit }π{$EndIf}π  DOSOffset,π  DOSSegment,π  DOSSelector:Word;π  AllocateLong:Longint;π  IOBlock    : Pointer;πππ{$IfDef MSDOS}π{ standard DOS routines for segments and pointers }πfunction GetIOBlock(var Block : Pointer; Size : Word) : Boolean;πbeginπ  GetMem(Block, Size);π  DOSSegment := Seg(Block^);π  DOSOffset := Ofs(Block^);π  GetIOBlock := TRUE;πend;ππfunction FreeIOBlock(var Block: Pointer) : Boolean;πbeginπ  FreeMem(Block, SizeOf(Block^));π  DOSSegment := 0;π  DOSSelector := 0;π  DOSOffset := 0;π  FreeIOBlock := TRUE;πend;ππ{$ELSE}ππ{ Get a block in DOS and set pointer values.  DOSSelector is usedπ  to access the block under protected mode.  DOSSegment accesses theπ  block in real mode }ππfunction GetIOBlock(var Block : Pointer; Size : Word) : Boolean;πbeginπ  AllocateLong:=GlobalDOSAlloc(Size); { enough extra room for string }π  If AllocateLong<>0 Then  {If allocation was successful...}π  Beginπ     DOSSegment:=AllocateLong SHR 16;     {Get the real mode segment of the memory}π     DOSSelector:=AllocateLong AND $FFFF; {Get the protected mode selector of the memory}π     DOSOffset := 0;π     Block := Ptr(DOSSelector, 0);π     GetIOBlock := TRUE;π  Endπ  ELSEπ     GetIOBlock := FALSE;πend;ππ{ Free the DOS block and dereference the pointer }ππfunction FreeIOBlock(var Block: Pointer) : Boolean;πbeginπ  DOSSelector := GlobalDOSFree(DOSSelector);π  DOSSegment := 0;π  Block := NIL;π  FreeIOBlock := (DOSSelector = 0);πend;ππ{$EndIf}ππprocedure Clear_Regs;πbeginπ  FillChar(Regs, SizeOf(Regs), #0);πend;ππprocedure CD_Intr;πbeginπ  Regs.AH := $15;ππ{$IfDef MSDOS}π  Intr($2F, Regs);  { Call DOS normally }π{$Else}π  If NOT SimRealModeInt($2F,@Regs) Then    {Call DOS through the DPMI}π     Halt(100);π{$EndIf}πend;ππprocedure MSCDEX_Ver;πbeginπ  Clear_Regs;π  Regs.AL := $0C;π  Regs.BX := $0000;π  CD_Intr;π  MSCDEX_Version.Minor := 0;π  If Regs.BX = 0 Thenπ     MSCDEX_Version.Major := 1π  ELSEπ     Beginπ       MSCDEX_Version.Major := Regs.BH;π       MSCDEX_Version.Minor := Regs.BL;π     End;πend;ππprocedure Initialize;πbeginπ  NumberOfCD := 0;π  Clear_Regs;π  Regs.AL := $00;π  Regs.BX := $0000;π  CD_Intr;π  If Regs.BX <> 0 THENπ     Beginπ       NumberOfCD := Regs.BX;π       FirstCD := Regs.CX;π       Clear_Regs;π       FillChar(DriverList, SizeOf(DriverList), #0);π       FillChar(UnitList, SizeOf(UnitList), #0);π       Regs.AL := $01;               { Get List of Driver Header Addresses }π       Regs.ES := Seg(DriverList);π       Regs.BX := Ofs(DriverList);π       CD_Intr;π       Clear_Regs;π       Regs.AL := $0D;               { Get List of CD-ROM Units }π       Regs.ES := Seg(UnitList);π       Regs.BX := Ofs(UnitList);π       CD_Intr;π       MSCDEX_Ver;π     End;πend;πππfunction File_Name(var Code : Integer) : String;πVarπ  FN : Pointer;πbeginπ  Clear_Regs;π  If NOT GetIOBlock(FN, 64) THENπ     Exit;π  FillChar(FN, SizeOf(FN), #0);π  Regs.AL := Code + 1;π{π       Copyright Filename     =  1π       Abstract Filename      =  2π       Bibliographic Filename =  3π}π  Regs.CX := Drive;π  Regs.ES := DOSSegment;π  Regs.BX := DOSOffset;π  CD_Intr;π  Code := Regs.AX;π  If (Regs.Flags AND CarryFlag) = 0 THENπ     File_Name := StrPas(FN)π  ELSEπ     File_Name := '';π  FreeIOBlock(FN);πend;πππfunction Read_VTOC(var VTOC : VTOCArray;π                   var Index : Integer) : Boolean;π{ On entry -π     Index = Vol Desc Number to read from 0 to ?π  On returnπ     Case Index ofπ            1    : Standard Volume Descriptorπ            $FF  : Volume Descriptor Terminatorπ            0    : All othersπ}πvarπ  PVTOC : Pointer;ππbeginπ  Clear_Regs;π  If NOT GetIOBlock(PVTOC, SizeOf(VTOCArray)) THENπ     Exit;π  FillChar(PVTOC^, SizeOf(PVTOC^), #0);π  Regs.AL := $05;π  Regs.CX := Drive;π  Regs.DX := Index;π  Regs.ES := DOSSegment;π  Regs.BX := DOSOffset;π  CD_Intr;π  Index := Regs.AX;π  Move(PVTOC^,VTOC, SizeOf(VTOC));π  If (Regs.Flags AND CarryFlag) = 0 THENπ     Read_VTOC := TRUEπ  ELSEπ     Read_VTOC := FALSE;π  FreeIOBlock(PVTOC);πend;ππprocedure CD_Check(var Code : Integer);πbeginπ  Clear_Regs;π  Regs.AL := $0B;π  Regs.BX := $0000;π  Regs.CX := Drive;π  CD_Intr;π  If Regs.BX <> $ADAD THENπ     Code := 2π  ELSEπ     Beginπ       If Regs.AX <> 0 THENπ          Code := 0π       ELSEπ          Code := 1;π     End;πend;πππprocedure Vol_Desc(Var Code : Integer;π                   var ErrCode : Integer);ππ  function Get_Vol_Desc : Byte;π    beginπ      Clear_Regs;π      Regs.CX := Drive;π      Regs.AL := $0E;π      Regs.BX := $0000;π      CD_Intr;π      Code := Regs.AX;π      If (Regs.Flags AND CarryFlag) <> 0 THENπ         ErrCode := $FF;π      Get_Vol_Desc := Regs.DH;π    end;ππbeginπ  Clear_Regs;π  ErrCode := 0;π  If Code <> 0 THENπ     Beginπ       Regs.DH := Code;π       Regs.DL := 0;π       Regs.BX := $0001;π       Regs.AL := $0E;π       Regs.CX := Drive;π       CD_Intr;π       Code := Regs.AX;π       If (Regs.Flags AND CarryFlag) <> 0 THENπ          ErrCode := $FF;π     End;π  If ErrCode = 0 THENπ     Code := Get_Vol_Desc;πend;ππprocedure Get_Dir_Entry(PathName : String;π                        var Format, ErrCode : Integer);πvarπ  PN : PChar;π  DB : Pointer;πbeginπ  FillChar(DirBuf, SizeOf(DirBuf), #0);π  PathName := PathName + #0;π  If NOT GetIOBlock(DB, SizeOf(DirBufRec) + 256) THENπ     Exit;π  PN := Ptr(DOSSelector, SizeOf(DirBufRec) + 1);π  Clear_Regs;π  Regs.AL := $0F;π  Regs.CL := Drive;π  Regs.CH := 1;π  Regs.ES := DOSSegment;π  Regs.BX := SizeOf(DirBufRec) + 1;π  Regs.SI := DOSSegment;π  Regs.DI := DOSOffset;π  CD_Intr;π  ErrCode := Regs.AX;π  If (Regs.Flags AND CarryFlag) = 0 THENπ  Beginπ    Move(DB^, DirBuf, SizeOf(DirBuf));π    Move(DirBuf.NameArray[1], DirBuf.FileName[1], 38);π    DirBuf.FileName[0] := #12; { File names are only 8.3 }π    Format := Regs.AXπ  Endπ  ELSEπ    Format := $FF;π  FreeIOBlock(DB);πend;ππfunction IO_Control(Command, NumberOfBytes, TransferBytes,π                     ReturnBytes, StartPoint : Byte;π                     var Bytes, TransferBlock): Byte;πvarπ  I : Word;πbeginπ  If NOT GetIOBlock(IOBlock, SizeOf(IOControlBlock)) THENπ     Exit;π  With IOControlBlock(IOBlock^) DOπ  Beginπ    I := Ofs(TransBlock[1]) - Ofs(IOReq_Hdr);π    NumBytes := NumberOfBytes;π    IOReq_Hdr.Len := 26;π    IOReq_Hdr.SubUnit := SubUnit;π    IOReq_Hdr.Status := 0;π    TransAddr := Ptr(DOSSegment, I); { 23 bytes into the IOBlock^ }π    IOReq_Hdr.Command := Command;π    Move(Bytes, TransBlock[1], TransferBytes);π    Clear_Regs;π    Regs.AL := $10;π    Regs.CX := Drive;π    Regs.ES := DOSSegment;π    Regs.BX := DOSOffset;π    CD_Intr;π    Busy := (IOReq_Hdr.Status AND 512) <> 0;π    If ((IOReq_Hdr.Status AND 32768) <> 0) THENπ       I := IOReq_Hdr.Status AND $FFπ    ELSEπ        I := 0;π    If ReturnBytes <> 0 THENπ       Move(TransBlock[StartPoint], TransferBlock, ReturnBytes);π  End;π  IO_Control := I;π  FreeIOBlock(IOBlock);πend;ππprocedure Audio_Channel_Info;πvarπ  Bytes : Byte;πbeginπ  Bytes := 4;π  IO_Control(IOCtlInput, 9, 1, 9, 1, Bytes, AudioChannel);πEnd;ππprocedure DeviceStatus;πvarπ  Bytes : Array[1..2] OF Byte;π  Status: Word;πbeginπ  Bytes[1] := 6;ππ  IO_Control(IOCtlInput, 5, 1, 2, 2, Bytes, Bytes);π  Move(Bytes, Status, 2);ππ  DoorOpen     := Status AND 1 <> 0;π  DoorLocked   := Status AND 2 = 0;π  Audio        := Status AND 16 <> 0;π  AudioManip   := Status AND 256 <> 0;π  DiscInDrive  := Status AND 2048 = 0;π  RedBook      := Status AND 1024 <> 0;πEnd;ππprocedure Audio_Disk_Info;πvar Bytes : Byte;πbeginπ  Bytes := 10;π  IO_Control(IOCtlInput, 7, 1, 6, 2, Bytes, AudioDiskInfo);π  Playing := Busy;πend;ππprocedure Audio_Track_Info(Var StartPoint : LongInt;π                           Var TrackControl : Byte);πvarπ  Bytes : Array[1..5] Of BYTE;πbeginπ  Bytes[1] := 11;π  Bytes[2] := TrackControl;   { Track number }ππ  IO_Control(IOCtlInput, 7, 2, 5, 3, Bytes, Bytes);π  Move(Bytes[1], StartPoint, 4);π  TrackControl := Bytes[5];ππ  Playing := Busy;πend;ππprocedure Q_Channel_Info;πvarπ  Bytes : Byte;πbeginπ  Bytes := 12;π  IO_Control(IOCtlInput, 11, 1, 11, 2, Bytes, QChannelInfo);πend;ππprocedure Audio_Status_Info;πvarπ  Bytes : Array[1..11] Of Byte;πbeginπ  Bytes[1] := 15;π  IO_Control(IOCtlInput, 11, 1, 8, 2, Bytes, Bytes);π  Paused := (Word(Bytes[2]) AND 1) <> 0;π  Move(Bytes[4], Last_Start, 4);π  Move(Bytes[8], Last_End, 4);π  Playing := Busy;πend;ππprocedure Eject;πvarπ  Bytes : Byte;πbeginπ  Bytes := 0;π  IO_Control(IOCtlOutput, 1, 1, 0, 0, Bytes, Bytes);πend;ππprocedure Reset;πvar Bytes : Byte;πbeginπ  Bytes := 2;π  IO_Control(IOCtlOutput, 1, 1, 0, 0, Bytes, Bytes);π  Busy := TRUE;πend;ππprocedure Lock(LockDrive : Boolean);πvarπ  Bytes : Array[1..2] Of Byte;πbeginπ  Bytes[1] := 1;π  If LockDrive THENπ     Bytes[2] := 1π  ELSEπ     Bytes[2] := 0;π  IO_Control(IOCtlOutput, 2, 2, 0, 0, Bytes, Bytes);πend;ππprocedure CloseTray;πvar Bytes : Byte;πbeginπ  Bytes := 5;π  IO_Control(IOCtlOutput, 1, 1, 0, 0, Bytes, Bytes);πend;ππVarπ  AudioPlay : Pointer;πππfunction Play(StartLoc, NumSec : LongInt) : Boolean;πbeginππ  If NOT GetIOBlock(AudioPlay, SizeOf(Audio_Play)) THENπ     Exit;π  With Audio_Play(AudioPlay^) DOπ  Beginπ    APReq.Command := PlayCD;π    APReq.Len := 22;π    APReq.SubUnit := SubUnit;π    Start := StartLoc;π    NumSecs := NumSec;π    AddrMode := 1;π    Regs.AL := $10;π    Regs.CX := Drive;π    Regs.ES := DOSSegment;π    Regs.BX := DOSOffset;π    CD_Intr;π    Play := ((APReq.Status AND 32768) = 0);π  End;π  FreeIOBlock(AudioPlay);πend;ππprocedure Play_Audio(StartSec, EndSec : LongInt);πVarπ  SP,π  EP     : LongInt;π  SArray : Array[1..4] Of Byte;π  EArray : Array[1..4] Of Byte;πbeginπ  Move(StartSec, SArray[1], 4);π  Move(EndSec, EArray[1], 4);π  SP := SArray[3];           { Must use longint or get negative result }π  SP := (SP*75*60) + (SArray[2]*75) + SArray[1];π  EP := EArray[3];π  EP := (EP*75*60) + (EArray[2]*75) + EArray[1];π  EP := EP-SP;ππ  Playing := Play(StartSec, EP);π  Audio_Status_Info;πend;ππprocedure Pause_Audio;πbeginππ  If Playing THENπ     Beginπ       If NOT GetIOBlock(AudioPlay, SizeOf(Audio_Play)) THENπ          Exit;π       With Audio_Play(AudioPlay^) DOπ       Beginπ         APReq.Command := StopPlay;π         APReq.Len := 13;π         APReq.SubUnit := SubUnit;π       End;π       Regs.AL := $10;π       Regs.CX := Drive;π       Regs.ES := DOSSegment;π       Regs.BX := DOSOffset;π       CD_Intr;π       FreeIOBlock(AudioPlay);π     end;π  Audio_Status_Info;π  Playing := FALSE;πend;ππprocedure Resume_Play;πbeginπ  If NOT GetIOBlock(AudioPlay, SizeOf(Audio_Play)) THENπ     Exit;π  With Audio_Play(AudioPlay^) DOπ  Beginπ    APReq.Command := ResumePlay;π    APReq.Len := 13;π    APReq.SubUnit := SubUnit;π  End;π  Regs.AL := $10;π  Regs.CX := Drive;π  Regs.ES := DOSSegment;π  Regs.BX := DOSOffset;π  CD_Intr;π  Audio_Status_Info;π  FreeIOBlock(AudioPlay); { free DOS block anbd dereference pointer }πend;ππfunction StopAudio : Boolean;πbeginππ  If NOT GetIOBlock(AudioPlay, SizeOf(Audio_Play)) THENπ     Exit;π  With Audio_Play(AudioPlay^) DOπ  Beginπ    APReq.Command := StopPlay;π    APReq.Len := 13;π    APReq.SubUnit := SubUnit;π    Regs.AL := $10;π    Regs.CX := Drive;π    Regs.ES := DOSSegment;π    Regs.BX := DOSOffset;π    CD_Intr;π    StopAudio := ((APReq.Status AND 32768) = 0);π  End;π  FreeIOBlock(AudioPlay);πend;ππfunction Sector_Size(ReadMode : Byte) : Word;πVarπ  SecSize : Word;π  Bytes   : Array[1..2] Of Byte;πbeginπ  Bytes[1] := 7;π  Bytes[2] := ReadMode;π  IO_Control(IOCtlInput, 4, 2, 2, 3, Bytes, SecSize);π  Sector_Size := SecSize;πEnd;ππfunction Volume_Size : LongInt;πVarπ  VolSize : LongInt;π  Bytes   : Byte;πbeginπ  Bytes := 8;π  IO_Control(IOCtlInput, 5, 1, 4, 2, Bytes, VolSize);π  Volume_Size := VolSize;πEnd;ππfunction Media_Changed : Boolean;ππ{  1  :  Media not changedπ   0  :  Don't Knowπ  -1  :  Media changedπ}πvarπ  MedChng : Byte;π  Bytes : Byte;πbeginπ  Bytes := 9;π  IO_Control(IOCtlInput, 2, 1, 4, 2, Bytes, MedChng);π  Inc(MedChng);π  If MedChng IN [1,0] THENπ     Media_Changed := Trueπ  ELSEπ     Media_Changed := False;πEnd;ππfunction Head_Location(AddrMode : Byte) : LongInt;πVarπ  HeadLoc : Longint;π  Bytes : Array[1..2] Of Byte;πbeginπ  Bytes[1] := 1;π  Bytes[2] := AddrMode;π  IO_Control(IOCtlInput, 6, 2, 4, 3, Bytes, HeadLoc);π  Head_Location := HeadLoc;πEnd;ππprocedure Read_Drive_Bytes(Var ReadBytes : DriveByteArray);πvarπ  Bytes : Byte;πBeginπ  Bytes := 5;π  IO_Control(IOCtlInput, 130, 1, 128, 3, Bytes, ReadBytes);πEnd;ππfunction UPC_Code : String;πVarπ  I, J, K : Integer;π  TempStr : String;π  Bytes : Array[1..11] Of Byte;πBeginπ  TempStr := '';π  FillChar(Bytes, SizeOf(Bytes), #0);π  Bytes[1] := 14;π  If (IO_Control(IOCtlInput, 11, 1, 11, 1, Bytes, Bytes) <> 0) THENπ     TempStr := 'No UPC Code'π  ELSEπ  Beginπ    For I := 3 to 9 DOπ      Beginπ        J := (Bytes[I] AND $F0) SHR 4;π        K := Bytes[I] AND $0F;π        TempStr := TempStr + Chr(J + 48);π        TempStr := TempStr + Chr(K + 48);π      End;π    If Length(TempStr) > 13 THENπ        TempStr := Copy(TempSTr, 1, 13);π  End;π  UPC_Code := TempStr;πEnd;ππ{************************************************************}π{$IfDef MSDOS}π{$ELSE}π{$F+}πvarπ  ExitRoutine : Pointer;πprocedure MyExit;πbeginπ  ExitProc := ExitRoutine;π  If DOSSelector <> 0 THENπ  Beginπ     GlobalDOSFree(DOSSelector);π     WriteLn('DOS Selector not free');π  Endπ  ELSEπ     WriteLn('DOS Selector free');πend;π{$EndIf}ππBeginπ  NumberOfCD := 0;π  FirstCD := 0;π  FillChar(MSCDEX_Version, SizeOf(MSCDEX_Version), #0);π  Initialize;π  Drive := FirstCD;π  SubUnit := 0;π{$IfDef MSDOS}π{$ELSE}π  ExitRoutine := ExitProc;π  ExitProc := @MyExit;π{$EndIf}πEnd.π                                                                                                               44     08-24-9413:31ALL                      JORDAN RITTER            SoundBlaster Detect      SWAG9408    o¿F    19     ■"   {ππPB> It's me again.  I need code to detect a SB/SB Compat.  card.  I haveπPB> code which will detect the port, but I also need a way of detecting theπPB> SB's IRQ and DMA channel.  Is there any such code available?ππThis code was just posted about 2 weeks ago (I believe)... }πππProgram DetectSoundBlaster;ππUses DOS, CRT;ππFunction hex(a : Word; b : Byte) : String;πConst digit : Array[$0..$F] Of Char = '0123456789ABCDEF';πVar i : Byte;π  xstring : String;πBeginπ  xstring:='';π  For i:=1 To b Doπ  Beginπ    Insert(digit[a And $000F], xstring, 1);π    a:=a ShR 4π  End;π  hex:=xstringπEnd; {hex}ππProcedure SoundPort;πVar xbyte1, xbyte2, xbyte3, xbyte4: Byte;π  xword, xword1, xword2, temp, sbport: Word;π  sbfound, portok: Boolean;ππBeginπ  ClrScr;π  Write('Sound Blaster: ');π  sbfound:=False;π  xbyte1:=1;π  While (xbyte1 < 7) And (Not sbfound) Doπ  Beginπ    sbport:=$200 + ($10 * xbyte1);π    xword1:=0;π    portok:=False;π    While (xword1 < $201) And (Not portok) Doπ    Beginπ      If (Port[sbport + $0C] And $80) = 0 Thenπ        portok:=True;π      Inc(xword1)π    End;π    If portok Thenπ    Beginπ      xbyte3:=Port[sbport + $0C];π      Port[sbport + $0C]:=$D3;π      For xword2:=1 To $1000 Do {nothing};π      xbyte4:=Port[sbport + 6];π      Port[sbport + 6]:=1;π      xbyte2:=Port[sbport + 6];π      xbyte2:=Port[sbport + 6];π      xbyte2:=Port[sbport + 6];π      xbyte2:=Port[sbport + 6];π      Port[sbport + 6]:=0;π      xbyte2:=0;π      Repeatπ        xword1:=0;π        portok:=False;π        While (xword1 < $201) And (Not portok) Doπ        Beginπ          If (Port[sbport + $0E] And $80) = $80 Thenπ            portok:=True;π          Inc(xword1)π        End;π        If portok Thenπ          If Port[sbport + $0A] = $AA Thenπ            sbfound:=True;π        Inc(xbyte2);π      Until (xbyte2 = $10) Or (portok);π      If Not portok Thenπ      Beginπ        Port[sbport + $0C]:=xbyte3;π        Port[sbport + 6]:=xbyte4;π      End;π    End;π    If sbfound Thenπ    Beginπ      Write('Yes');π      Write(' Port: ');π      Write('$', Hex(sbport, 3));π    Endπ    Elseπ      Inc(xbyte1);π  End;π  If Not sbfound Thenπ    Write('No');πEnd;{soundport}ππBeginπ  SoundPort;πEnd.ππ                                                                                                         45     08-24-9413:40ALL                      JASON DYER               Fm-voices                SWAG9408    sm    20     ■"   {πCould somebody tell me how to program the FM-voices of my sound-blaster ?ππHere's a .sbi player for you...π}πprogram SBIread;πuses Crt;πconst SBIREG : array[1..11] of Word =π  ($20,$23,$40,$43,$60,$63,$80,$83,$E0,$E3,$C0);πvarπ  FromF: file;π  I: integer;π  FN: string;π  NumRead, NumWritten: Word;π  buf: array[1..2048] of Char;π  ch: char;π  IsSBI: boolean;π  SBIName: string;πprocedure Bit;πbeginπ  Delay(1); {something fancier was suggested, but this works fine}πend;                                                                           ππfunction CheckSoundCard: boolean;πvar Temp, Temp2: byte;πbeginπ  port[$388]:=$4; repeat until Port[$22E] > 127;π  port[$389]:=$60; repeat until Port[$22E] > 127;π  port[$389]:=$80; repeat until Port[$22E] > 127;π  Temp:=port[$388];π  port[$388]:=$2; repeat until Port[$22E] > 127;π  port[$389]:=$FF; repeat until Port[$22E] > 127;π  port[$388]:=$4; repeat until Port[$22E] > 127;π  port[$389]:=$21; repeat until Port[$22E] > 127;π  Delay(1);π  Temp2:=port[$388];π  port[$388]:=$4; repeat until Port[$22E] > 127;π  port[$389]:=$60; repeat until Port[$22E] > 127;π  port[$389]:=$80; repeat until Port[$22E] > 127;π  If ((temp and $E0)=$00) and ((temp2 and $E0)=$c0) thenπ    CheckSoundCard:=True else CheckSoundCard:=False;πend;πprocedure ClearCard;πvar CP: byte;πbeginπ  For CP:=0 to 255 do beginπ    port[$388]:=CP;π    port[$389]:=0;π  end;πend;πprocedure Sounder(A,B: byte);πbeginπ  port[$388]:=A; Bit;π  port[$389]:=B; Bit;πend;πbeginπ  Writeln('SBI file player');π  if not CheckSoundCard then beginπ    writeln('Soundcard not detected!');π    halt(1);π  end;π  FN:=ParamStr(1);π  If Pos('.',FN)=0 then FN:=FN+'.SBI';π  Assign(FromF, FN);π  Reset(FromF, 1);π  BlockRead(FromF,buf,SizeOf(buf),NumRead);π  Close(FromF);π  If (buf[1]='S') and (buf[2]='B') and (buf[3]='I') and (ord(buf[4])=26)π    then IsSBI:=True else IsSBI:=False;π  If IsSBI=False then Writeln('Not a SBI file!') else beginπ    SBIName:='';π    I:=4;π    repeatπ      i:=i+1;π      if (ord(buf[i])<>0) then SBIName:=SBIName+buf[i];π    until ord(buf[i])=0;π    Writeln('Name of file      : ',FN);π    Writeln('Name of instrument: ',SBIName);π    ClearCard;π    for i:=1 to 11 do Sounder(SBIreg[i],ord(buf[i+36]));π    Sounder($A0,$58);π    Sounder($B0,$31);π    Delay(900);π    ClearCard;π  end;πend.π                                                                                                               46     08-24-9413:46ALL                      CHRISTIAN KULLANDER      Max Volume on SB         SWAG9408    ÷L≈┌    9      ■"   {π KP> HOW CAN I CHANGE THE OVERALL VOLUME OF SOUND BLASTER ? It must be aπ KP> single OUT , or something . . .ππActually I did a small program yesterday that maximizes the master, VOC and FMπvolumes... Here it is:ππ[------------------------------ C u t -----------------------]π}ππprogram MaxVol;ππ  beginπ    Port[$224] := 4;     { register 04h - VOC volume }π    Port[$225] := $FF;π    Port[$224] := $22;   { register 22h - *** Master volume *** }π    Port[$225] := $FF;π    Port[$224] := $26;   { register 26h - FM volume }π    Port[$225] := $FF;π  end.ππ{ππThis works fine on the SB16 I'm using, and it should work as well with all theπother SB models.πThe left volume is in one of the nibbles, and the right in the other (I can'tπremember which one is in which nibble though...;).πThe max volume for L/R is 15/15, and since 15 shl 4 or 15 = 255 (0FFh) that'sπthe value I use. I haven't tried but I guess that you can use the 225h port toπread the register contents as well as write it.ππ // Christian Kullanderπ}π     47     08-24-9413:49ALL                      OSCAR WAHLBERG           Sound/NoSound (BASM)     SWAG9408    ;î╧    6      ■"   πUses CRT;ππ  Procedure Sound (Hertz : Word);Assembler;π  Asmπ    Mov  Bx,SPπ    Mov  Bx,&Hertzπ    Mov  Ax,34DDhπ    Mov  Dx,0012hπ    CMP  Dx,Bxπ    JNB  @J1π    Div  Bxπ    Mov  Bx,Axπ    In   Al,61hπ    Test Al,03hπ    JNZ  @J2π    OR   Al,03hπ    OUT  61h,Alπ    Mov  Al,-4Ahπ    OUT  43h,Alπ   @J2:π    Mov  Al,Blπ    OUT  42h,Alπ    Mov  Al,Bhπ    Out  42h,Alπ   @J1:π  End; {Sound}ππ  Procedure NoSound;Assembler;π  Asmπ    IN  AL,61hπ    AND AL,0FChπ    OUT 61h,ALπ  End;ππBeginππ      SOUND (150);π      DELAY (100);π      SOUND (400);π      DELAY (100);π      NOSOUND;πEND.                                                        48     08-25-9409:08ALL                      RODNEY JOHNSON           FM Synth Code            SWAG9408    b╗∙Y    39     ■"   {π  I got FM-synth code for the PAS (originally for the SB).  Here it is:π}πProgram fmtest;πusesπ  sbfm, crt;πconstπ  instrument: TFMInstrument = (SoundCharacteristic: ($11, $1);π                               Level: ($8A, $40);π                               AttackDecay: ($F0, $F0);π                               SustainRelease: ($FF, $B3);π                               WaveSelect: ($01, $00);π                               FeedBack: $00;π                               Filler: ($06, $00, $00, $00, $00, $00));π  notes: array[0..12] of integer = ($157, $16B, $181, $198, $1B0, $1C1, $1E5,π        $202, $220, $241, $263, $287, $2AE);πbeginπ  SbFMReset;π  SbFMSetVoice(0,@instrument);π  SbFMSetVoice(1,@instrument);π  SbFMSetVoice(11,@instrument);π  SbFMSetVoice(12,@instrument);ππ  SbFMKeyOn(0,notes[0],2);π  delay(250);π  SbFMKeyOn(1,notes[4],3);π  delay(250);π  SbFMKeyOn(1,notes[7],3);π  delay(250);π  SbFMKeyOn(1,notes[12],3);π  delay(1000);ππ  sbFMKeyOff(0);π  sbFMKeyOff(1);π  sbFMKeyOff(11);π  sbFMKeyOff(12);π  sbFMReset;πend.ππUnit SbFM;πinterfaceπtypeπ  PFMInstrument = ^TFMInstrument;π  TFMInstrument = recordπ                    SoundCharacteristic:array[0..1] of byte;π                    Level:              array[0..1] of byte;π                    AttackDecay:        array[0..1] of byte;π                    SustainRelease:     array[0..1] of byte;π                    WaveSelect:         array[0..1] of byte;π                    Feedback:           byte;π                    filler:             array[0..5] of byte;π                  end;πconstπ  SbIOAddr=$220;π  LeftFmAddress=0;π  RightFmAddress=2;π  FMADDRESS=$08;πProcedure WriteFM(chip, addr, data: byte);πProcedure SbFmReset;πProcedure SbFMKeyOff(voice: integer);πProcedure SbFMKeyOn(voice, freq, octave: integer);πProcedure SbFMVoiceVolume(voice, vol: integer);πprocedure sbFMSetVoice(voicenum: integer; Ins: PFMInstrument);πimplementationπProcedure WriteFM(chip, addr, data: byte);πvarπ  ChipAddr:                                integer;π  t:                                        byte;πbeginπ  if chip>0 then chipaddr:=SbIOAddr + RightFMAddress elseπ               chipaddr:=sbIOAddr + LeftFMAddress;π  chipaddr:=SbIOAddr + FMAddress;π  asmπ    push dxπ    push axπ    push cxπ    mov dx,chipaddrπ    mov al,addrπ    out dx,alπ    in al,dxπ    inc dxπ    mov al,dataπ    out dx,alπ    dec dxπ    mov cx,4π@L:π    in al,dxπ    loop @Lπ    pop cxπ    pop axπ    pop dxπ  end;πend;πProcedure SbFmReset;πBeginπ  WriteFM(0, 1, 0);π  WriteFM(1, 1, 0);πend;πProcedure SbFMKeyOff(voice: integer);πvarπ  regnum:                                byte;π  chip:                                        integer;πbeginπ  chip:=voice div 11;π  regnum:=$B0 + (voice mod 11);π  WriteFM(chip, regnum, 0);πend;πProcedure SbFMKeyOn(voice, freq, octave: integer);πvarπ  regnum, t:                                byte;π  chip:                                        integer;πbeginπ  chip:=voice div 11;π  regnum:=$A0 + (voice mod 11);π  WriteFM(chip, regnum, freq and $FF);π  regnum:=$B0 + (voice mod 11);π  t:=(freq shr 8) or (octave shl 2) or $20;π  WriteFM(chip, regnum, t);πend;πProcedure SbFMVoiceVolume(voice, vol: integer);πvarπ  regnum:                                byte;π  chip:                                        integer;πbeginπ  chip:=voice div 11;π  regnum:=$40 + (voice mod 11);π  WriteFM(chip, regnum, vol);πend;πprocedure sbFMSetVoice(voicenum: integer; Ins: PFMInstrument);πvarπ  opcellnum:                                byte;π  celloffset, i, chip:                        integer;πbeginπ  chip:=voicenum div 11;π  voicenum:=voicenum mod 11;π  celloffset:=(voicenum mod 3) + ((voicenum div 3) shr 3);π  opcellnum:=$20 + celloffset;π  WriteFM(chip, opcellnum, ins^.SoundCharacteristic[0]);π  inc(opcellnum, 3);π  WriteFM(chip, opcellnum, ins^.SoundCharacteristic[1]);π  opcellnum:=$40 + celloffset;π  WriteFM(chip, opcellnum, ins^.level[0]);π  inc(opcellnum, 3);π  WriteFM(chip, opcellnum, ins^.Level[1]);π  opcellnum:=$60 + celloffset;π  WriteFM(chip, opcellnum, ins^.AttackDecay[0]);π  inc(opcellnum, 3);π  WriteFM(chip, opcellnum, ins^.AttackDecay[1]);π  opcellnum:=$80 + celloffset;π  WriteFM(chip, opcellnum, ins^.SustainRelease[0]);π  inc(opcellnum, 3);π  WriteFM(chip, opcellnum, ins^.SustainRelease[1]);π  opcellnum:=$E0 + celloffset;π  WriteFM(chip, opcellnum, ins^.WaveSelect[0]);π  inc(opcellnum, 3);π  WriteFM(chip, opcellnum, ins^.WaveSelect[1]);π  opcellnum:=$C0 + voicenum;π  WriteFM(chip, opcellnum, ins^.feedback);πend;πend.ππ{πMessage 1 is FMTEST.PASπMessages 2+3 are SBFM.PASπThat's all.  One thing: if you can make this work with more than twoπvoices at a time, I'd be interested in improved code.  I think that thisπcode uses the AdLib compatibility, which is by no means impressive :-).π}π                                                                         49     08-25-9409:11ALL                      JURI PAKASTE             S3M header               SWAG9408    J8«~    47     ■"   {πFrom: jurip@clinet.fi (Juri Pakaste)ππHopefully someone here has experience reading S3M headers...πI'm trying to read the S3M header. I get the name right, I thinkπI get the number of instruments right, but I can't get the numberπof patterns right. If I understand correctly the file which comesπwith Scream Tracker 3.01 (see below), the number of patternsπshould be located in bytes 35-36 (why on earth two bytes? Whoπwould use over 255 patterns?). The numbers I get have nothing toπdo with numbers DMP and Inertia Player give, though. My little test-πprogram, S3MREAD.EXE, tells me, for example, that a module that hasπ55 (I think) patterns, has in fact 99. Just great. Some of the valuesπit gives manage to get pretty near the ones DMP and IPlay give,πbut... you get the idea.ππHere is there relevant part of S3M technical documentation:ππ------------------------------------8<----------------------------------π π                                Song/Module headerπ          0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   Fπ        -----------------------------------------------------------------π  0000: | Song name, max 28 chars (incl. NUL)                           |π        |---------------------------------------------------------------|π  0010: |                                               |1Ah|Typ| x | x |π        |---------------------------------------------------------------|π  0020: |OrdNum |InsNum |PatNum | Flags | Cwt/v |  Ffv  |'S'|'C'|'R'|'M'|π        |---------------------------------------------------------------|π  0030: |m.v|i.s|i.t|m.m| x | x | x | x | x | x | x | x | x | x | x | x |π        |---------------------------------------------------------------|π  0040: |Channel settings for 32 channels, 255=unused,+128=disabled     |π        |---------------------------------------------------------------|π  0050: |                                                               |π        |---------------------------------------------------------------|π  0060: |Orders; length=OrdNum (must be even)                           |π        |---------------------------------------------------------------|π  xxxx: |Parapointers to instruments; length=InsNum*2                   |π        |---------------------------------------------------------------|π  xxxx: |Parapointers to patterns; length=PatNum*2                      |π        -----------------------------------------------------------------ππ π        Typ     = File type: 16=module,17=songπ        Ordnum  = Number of orders in fileπ        Insnum  = Number of instruments in fileπ        Patnum  = Number of patterns in fileπ        Cwt/v   = Created with tracker / version: &0xfff=version, >>12=trackerπ                        ST30:0x1300π        Ffv     = File format version;π                        1=originalπ                        2=original BUT samples unsignedπ        Parapointers are OFFSET/16 relative to the beginning of the header.π π        PLAYING AFFECTORS / INITIALIZERS:π        Flags   =  +1:st2vibrato π                   +2:st2tempoπ                   +4:amigaslidesπ                   +8:0vol optimizationsπ                   +16:amiga limitsπ                   +32:enable filter/sfxπ        m.v     = master volumeπ        m.m     = master multiplier (&15) + stereo(=+16)π        i.s     = initial speed (command A)π        i.t     = initial tempo (command T)π π        Channel types:π        &128=on, &127=type: (127=unused)π        8  - L-Adlib-Melody 1 (A1)      0  - L-Sample 1 (S1)π        9  - L-Adlib-Melody 2 (A2)      1  - L-Sample 2 (S2)π        10 - L-Adlib-Melody 3 (A3)      2  - L-Sample 3 (S3)π        11 - L-Adlib-Melody 4 (A4)      3  - L-Sample 4 (S4)π        12 - L-Adlib-Melody 5 (A5)      4  - R-Sample 5 (S5)π        13 - L-Adlib-Melody 6 (A6)      5  - R-Sample 6 (S6)π        14 - L-Adlib-Melody 7 (A7)      6  - R-Sample 7 (S7)π        15 - L-Adlib-Melody 8 (A8)      7  - R-Sample 8 (S8)π        16 - L-Adlib-Melody 9 (A9)π                                        26 - L-Adlib-Bassdrum (AB)π        17 - R-Adlib-Melody 1 (B1)      27 - L-Adlib-Snare    (AS)π        18 - R-Adlib-Melody 2 (B2)      28 - L-Adlib-Tom      (AT)π        19 - R-Adlib-Melody 3 (B3)      29 - L-Adlib-Cymbal   (AC)π        20 - R-Adlib-Melody 4 (B4)      30 - L-Adlib-Hihat    (AH)π        21 - R-Adlib-Melody 5 (B5)      31 - R-Adlib-Bassdrum (BB)π        22 - R-Adlib-Melody 6 (B6)      32 - R-Adlib-Snare    (BS)π        23 - R-Adlib-Melody 7 (B7)      33 - R-Adlib-Tom      (BT)π        24 - R-Adlib-Melody 8 (B8)      34 - R-Adlib-Cymbal   (BC)π        25 - R-Adlib-Melody 9 (B9)      35 - R-Adlib-Hihat    (BH)ππSo, shouldn't this piece of code be able to read the name,πnumber of instruments and number of patterns right:ππ}πProgram S3MReader;πVarπ   NameArray       :       Array [1..28] Of Char;π   InstrArray, PatArray : Array [1..2] Of Byte;π   InstrByte, PatByte   :       Byte;π   f : File;π   i       :       Integer;π   j       :       Integer;π   S3MName :       String;ππBeginπ   WriteLn;π   WriteLn;π   If ParamCount = 1 Thenπ   Beginπ      Assign(f,ParamStr(1));π      Reset(f,1);π      BlockRead(f,NameArray,28,i);π      For j := 1 To 28 Do S3MName := S3MName + NameArray[j];π      j := 28;π      While (Ord(S3MName[Length(S3MName)]) = 0) Or (Ord(S3MNameπ   (continues...)[Length(S3MName)]) = 32) Doπ      Beginπ         j := j - 1;π         S3MName[0] := Chr(j);π      End;π      Seek(f,33);π      BlockRead(f,InstrArray,2,i);π      InstrByte := InstrArray[1] + InstrArray[2];π      BlockRead(f,PatArray,2,i);π      PatByte := PatArray[1] + PatArray[2];π      WriteLn('Name: ',S3MName);π      WriteLn('Number of instruments: ',InstrByte);π      WriteLn('Number of patterns: ',PatByte);π      Close(f);π   End;πEnd.ππ                                                                                                                    50     08-25-9409:11ALL                      ADRIAN DENOON            PROGRAMMING SB AND FM    SWAG9408    └┴ë    43     ■"   {πAs I promised, here is the other reply that I am sending you containing theπinformation on Programming the SB via CT-VOICE.DRV.ππBefore I begin, This message may be a little long, so if for any reason, youπloose the end of it or sumthin', let me know, and I'll repost it split upπinto sections, but right now I'll just make one long message.ππO.K. Here we go...πThe information supplied will concern playback and recording of digitalπsamples on the SB's digital channel(s) using the driver supplied byπCreative Labs, CT-VOICE.DRV.ππThere should be a lot of information available on BBS's if you look for itπand want to follow up anything, but for the meaan time, this informationπis taken from a book called "The Sound Blaster Book" by Axel Stolz,πpublished by Abacus ISBN 1-55755-164-2.ππLet me first correct myself about the comment that the driver is executedπas an interrupt... Similar, but not quite... You don't actually make andπinterrupt call (i.e: INT n), but rather make the actual call to the addressπthat the driver was loaded into (i.e: CALL n).ππThe first thing you need to do is load the driver into memory.  Note, theπsegment may be anywhere (you store the pointer as a reference), but theπoffset MUST be zero.  The loading is done as follows...π1.) Allocate memory and get pointer to the block.π2.) Load the driver from disk into the allocated space.πNote: I am not going into much detail regarding error checking, but youπshould do checking on things such as allocation being ok and not NULL, andπsee whether the file exists on the disk, and whether or not it is a validπdriver (this can be done by checking to see that the letters "CT" areπcontained in bytes 3 and 4).ππThe code is as follows (in Pascal):π(Please forgive any minor discrepencies, as I am not a Pascal programmer,π but a C programmer, and I'm only trying to extract those sections that seemπ inportant, so I may not know which functions are Pascal's and which areπ user defined, but you should get the general idea. )π}πVARπ   F : File;π   PtrToDrv : Pointer;ππBEGINπ   Assign( F, 'CT-VOICE.DRV' );π   Reset( F, 1 );π   AllocateMem( PtrToDrv, FileSize(F) );π   Blockread( F, PtrToDrv^, FileSize(F) );π   Close( F );πEND;π{πNOTE: The varible PtrToDrv should be global, as you will be needing it toπreference the memory at a later stage.ππNow that you have the driver loaded, you can start to make function callsπto it.  This is done by setting the register BX to the number of theπfunction that you want to execute, and various other memory registers toπthe parameters, and then calling the address stored in the "PtrToDrv"πvarible.  Return values are usually stored in the register AX.ππEXAMPLE: Function 6: Play a sample:π-------- Input registers:  BX = Function numberπ                           ES:DI = Pointer to sampleπ         Return registers: None.π}πPROCEDURE PlaySample( BufferAddr : Pointer );πVARπ   VSeg, VOfs : WORD;πBEGINπ   VSeg := Seg( BufferAddr^ );π   VOfs := Ofs( BufferAddr^ );π   ASMπ      MOV   BX, 6π      MOV   ES, VSegπ      MOV   Di, VOfsπ      CALL  PtrToDrvπ   END;πEND;ππ{πThe following are a list of all the function available from the CT-VOICE.DRVπdriver.  Note, you will call them by setting BX = function number, settingπthe other registers, and then executing "CALL PtrToDrv":ππ----------------------------------------------------------------------------π#: Description:                  Parameters:π-- -------------------------     -------------------------------------------π0  Determain driver version      AH=Main number (on return)π                                 AL=Sub number (on return)ππ1  Set port address              AX=Port addressππ2  Set interrupt                 AX=Interrupt numberππ3  Initialize driver             AX=0 Successfull (on return)π                                 AX=1 SB not found (on return)π                                 AX=2 Port address error (on return)π                                 AX=3 Interrupt error (on return)ππ4  Loudspeaker on/off            AL=0 offπ                                 AL=1 onππ5  Set "StatusWord" address      ES:DI=Status addressπ                                 (The WORD varible at this address will storeπ                                  the status of the playback so that you canπ                                  monitor the playback of the sample.)ππ6  Sample playback               ES:DI=Sample addressππ7  Record sample                 AX=Sampling rateπ                                 DX:CX=Lengthπ                                 ES:DI=Sample addressππ8  Abort sample                  noneππ9  De-Install driver             noneπ                              π10 Pause Sample                  AX=0 Successfull (on return)π                                 AX=1 Not successfull (on return)ππ11 Continue sample               AX=0 Successfull (on return)π                                 AX=1 Not successfull (on return)ππ12 Interrupt loop                AX=0 At end of loopπ                                 AX=1 Immediatelyπ                                 AX=0 Successfull (on return)π                                 AX=1 No loop being executedππ13 User defined driver function  DX:AX=Function addressπ                                 ES:BX=Address of the current data blockπ}π                                                                                                 51     08-25-9409:11ALL                      GREG VIGNEAULT           SoundBlaster version...  SWAG9408    ∙│ï    17     ■"   {π Someone in an Assembly conference posted a routine to determine theπ version of a Sound Blaster card. I've adapted it for use in TP ...π}ππPROGRAM sb;               { Determine Sound Blaster version.  TP5+  }π                          { Jul.13.94 Greg Vigneault                }πUSES  Dos,                { import GetEnv                           }π      Crt;                { import Delay                            }πVAR Major, Minor : BYTE;  { version has major & minor parts         }ππ(*-----------------------------------------------------------------*)π{ this procedure returns 0.0 if any error condition...              }πPROCEDURE SBver (VAR Maj, Min : BYTE);π  VAR bev : STRING[32];                       { environment string  }π      j,k : WORD;                             { scratch variables   }π  BEGINπ    Maj := 0;  Min := 0;                      { initialize          }π    bev := GetEnv('BLASTER');                 { look in environment }π    IF bev[0] = #0 THEN EXIT;                 { no sign of Blaster  }π    j := Pos('A',bev);                        { search for i/o port }π    IF j = 0 THEN EXIT ELSE INC(j);           { none?               }π    Val( '$'+Copy(bev,j,3), j, k );           { base port number    }π    IF k <> 0 THEN EXIT;                      { if bad port value   }π    INC(j,$C);                                { command port        }π    Port[j] := $E1;                           { command             }π    DEC(j,2);                                 { input port          }π    Delay(20);                                { wait for response   }π    Maj := Port[j];                           { version major part  }π    Delay(20);                                { wait for response   }π    Min := Port[j];                           { version minor part  }π  END {SBver};ππBEGINππ  SBver (Major, Minor);π  WriteLn;π  WriteLn ('Sound Blaster version: ',Major,'.',Minor);π  WriteLn;ππEND.π                                                                                                                      52     08-25-9409:12ALL                      DANIEL SANDS             Wav Player               SWAG9408    ½mPδ    62     ■"   {π>Does anybody know how to load and play a wav in pascal? And I still need toπ>know how to load mods. And I would like to know how to load any other soundπ>files that you know of other than pc speaker beeps. ThanksππI made a WAV player in Pascal, but the source is a few lines long.  <G>ππ Okay.  It will play 4-bit ADPCM wavs, but not well.  Need to get the SBπdeveloper's kit to figure out why.  Oh well.π}ππ{$M 16384,0,655360}ππuses Dos, CRT, objects;ππconst SBase = $220;               {Default port base for Sound Blaster.π                                   Change if necessary}π      SIrq  = 7;                  {Default Irq line for Sound Blaster.π                                   Change if necessary}π      SDMA  = 1;                  {Default DMA channel for Sound Blaster.}ππtypeπ TWAVRec = recordπ             ID: LongInt;π            Len: LongInt;π           end;π PWAVFmt = ^TWAVFmt;π TWAVFmt = recordπ            case word ofπ             1:( FTag: word;π                 NChan: word;π                 SampR: word;π                 AvgSR: word;π                 BLKAl: word;π                 FMTLen: word;π                 FMTDat: array[0..256] of byte);π             2:( Chunk:Pointer);π           end;πvarπ WAVFile: TDosStream;             {WAV file object}π BlkID: TWAVRec;                  {ID for each block in WAV}π BlkFmt: PWAVFmt;                 {Block format}π TotalSz: LongInt;                {Total size of WAV data}π DSPCmd: byte;π NumBits: byte;π SampByte: byte;π BlockSize: word;π EOB: boolean;π DF: String;ππprocedure NewBlock; interrupt;    {Procedure to set up next block or}πvar X:Byte;                       {end playback}πbeginππ X := port[SBase+$e];π port[$20] := $20;π EOB := true;ππend;ππprocedure PrepareSB;πbeginππ SetIntVec(SIrq + 8, @NewBlock);           {Set up service routine}ππ asmπ  in al,$61                                 {Enable timer 2, but}π  and al,$fc                                {do not turn on sound.}π  or al,1π  out $61,alππ  stiππ  mov dx,SBase+6                            {DSP (Digital Sound Processor)π                                             reset port}π  mov al,1                                  {Reset command}π  out dx,alππ  mov bx,4π  call @9                                   {Wait 4 clocks}ππ  mov al,0                                  {Normal mode}π  out dx,alππ @3: mov dx,SBase+$e                        {DSP status port}π @2: in al,dx                               {Read status}π  test al,$80                               {If high bit not set, no data}π  jz @2                                     {ready}ππ  mov dx,Sbase+$a                           {DSP read port}π  in al,dx                                  {Read status}π  cmp al,$aa                                {AA indicates ready}π  jnz @3π  jmp @4π @5:π  in al,dx                                  {Wait for response to last byte}π  test al,$80                               {sent}π  jnz @5π  mov al,ahπ  out dx,al                                 {Send next byte}π  retππ @9:π  push bxπ  mov al,$b6                                {Write count to timer #3}π  out $43,alππ  mov al,0                                  {Low byte of count}π  out $42,alππ  mov al,$10                                {High byte count}π  out $42,alππ  sub bx,$1000π  neg bx                                    {1000h-clocks=desired count}π @10:π  mov al,$80                                {Read count from timer}π  out $43,alππ  in  al,$42                                {Low byte}π  mov ah,alπ  in  al,$42                                {High byte}π  xchg ah,alππ  cmp bx,ax                                 {Pause until count reached}π  jl  @10π  pop bxπ  retπ @4:π  mov dx,SBase+$cππ  mov ah,$40                                {Set time constant}π  call @5ππ  mov ah,SampByte                           {Time divisor}π  call @5ππ end;ππ port[$21] := port[$21] and not (1 shl SIRQ);   {Enable SB interrupt}ππend;ππprocedure ErrorEnd;πbeginπ WAVFile.Done;π Writeln('Error in .WAV');π Halt(1);πend;ππprocedure PlaySound(SndLen: longint);ππvar AbsAddr: LongInt;π    FirstBlk, SecBlk, CurBlk: Pointer;ππbeginππ EOB := False;ππ GetMem(BlkFmt, BlockSize*2);π FirstBlk := BlkFmt;π SecBlk := pointer(longint(FirstBlk) + BlockSize);π CurBlk := FirstBlk;πππ WAVFile.Read(BlkFmt^, BlockSize);π SndLen := SndLen - BlockSize;ππ repeatπ  AbsAddr := Seg(CurBlk^);π  AbsAddr := AbsAddr * 16 +Ofs(CurBlk^);π  SndLen := SndLen - BlockSize;π  asmπ   jmp @4ππ  @5:π   in al,dx                                 {Wait for response to last byte}π   test al,$80                              {sent}π   jnz @5π   mov al,ahπ   out dx,al                                {Send next byte}π   retππ  @4:ππ   mov bx,1π   mov cx,integer(AbsAddr)π   mov dx,SBase+$cππ   mov al,0                                 {Clear byte high/low flip-flop}π   out $c,alππ   mov al,$49                               {Set memory read, single transfer,}π   out $b,al                                {channel 1}ππ   mov al,cl                                {Enter base address}π   out SDMA*2,alπ   mov al,chπ   out SDMA*2,alππ   mov ax,integer(AbsAddr+2)                {High 4 bits goes to DMA page reg}π   mov dx,$83π   mov cl,SDMAπ   sub cl,2π   mov ch,2                                 {Calculate DMA page address}π   shr ch,cl                                {87, 83, 81, 82 channel order}π   xor dl,chπ   out dx,al                                {Send page byte}ππ   mov ax,BlockSize                         {Set byte count}π   out SDMA*2+1,alπ   xchg al,ahπ   out SDMA*2+1,alπ   push axππ   mov al,SDMA                              {Re-enable DMA channel 1}π   out $a,alππ   mov dx,SBase+$c                          {DSP port}ππ   mov ah,DSPCmd                            {DMA 8-bit transfer}π   call @5ππ   pop ax                                   {Get transfer again}π   mov bl,alπ   call @5π   mov ah,blπ   call @5ππ  end;ππ  DSPCmd := DSPCmd and $fe;ππ  if (CurBlk = FirstBlk) then CurBlk := SecBlk else CurBlk := FirstBlk;π  if SndLen > 0 then WAVFile.Read(CurBlk^, BlockSize);ππ  while not EOB doπ   if Keypressed then ErrorEnd;π  EOB := False;ππ until (SndLen<=0);πend;πππbeginππ DF := ParamStr(1);ππ WAVFile.Init(DF, stOpenRead);              {Open WAV file}π WAVFile.Read(BlkID, SizeOf(TWAVRec));      {Read in first block}ππ if BlkID.ID = $46464952 then               {ID of WAV file}π beginπ  TotalSz := BlkID.Len;                     {Get total size}π  repeatπ   WAVFile.Read(BlkID, 4);                  {Read in type chunk}π   TotalSz := TotalSz - 4;                  {and update TS}ππ   if BlkID.ID <> $45564157 then ErrorEnd;  {Must be "WAVE"}π   repeatπ    WAVFile.Read(BlkID, SizeOf(TWAVRec));    {Read in format chunk}π    TotalSz := TotalSz - SizeOf(TWavRec);ππ    if BlkID.ID = $20746d66  then            {"fmt ", set WAV format}π    beginπ     getmem(BlkFmt, BlkID.Len);π     WAVFile.Read(BlkFmt^, BlkID.Len);π     TotalSz := TotalSz - BlkID.Len;π     with BlkFmt^ doπ     beginπ      if FTag = $200 then DSPCmd := $75 else {ADPCM 4-bit compression}π       if FTag = 1 then DSPCmd := $14 else   {Normal}π        ErrorEnd;π      if DSPCmd = $75 then NumBits := 4 else NumBits := 8;π      if NChan = 2 then DSPCmd := DSPCmd + 8; {Stereo}π      SampByte := 256-(1000000 div SampR);   {Sampling rate}π      BlockSize := BlkAl;                    {Size of buffer}π     end;π     freemem(BlkFmt, BlkID.Len);π    end elseππ    if BlkID.ID = $61746164 thenπ    beginπ     PrepareSB;                              {Perform init stuff}π     TotalSz := TotalSz - BlkID.Len;π     PlaySound(BlkID.Len);π    end elseππ     ErrorEnd;π   until TotalSz <= 0;π  until TotalSz <= 0;π end elseπ  ErrorEnd;π WAVFile.Done;π port[$21] := port[$21] or (1 shl SIrq);πend.π                                                                         53     08-26-9408:32ALL                      SWAG SUPPORT TEAM        Call AD-LIB sound driver SWAG9408    8#φv    76     ■"   unit MusicIO;π{Contains procedures and function to call to Ad-Lib sound Driver.π if Sound Driver is not Loaded the system WILL Crash.π Parameters must be passed backwards since the sound driver is madeπ for a C parameter passing sequence.}ππinterfaceππ  usesπ    DOS;ππ  typeπ    Instrument = array[1..26] of integer;ππ  varπ    GActVoice :word; {Active Voice}π    GT        :array[0..10] of Instrument; {use global variable to keep array valid}ππ  procedure InitDriver;π  procedure RelTimeStart(TimeNum,TimeDen :integer);π  procedure SetState(State :integer);π  function GetState :boolean;π  procedure SetMode(PercussionMode :integer);π  function SetVolume(VolNum,VolDen,TimeNum,TimeDen :integer) :boolean;π  function SetTempo(Tempo,TimeNum,TimeDen :integer) :boolean;π  procedure SetActVoice(Voice :word);π  function PlayNote(Pitch :integer; LengthNum,LengthDen :word) :boolean;π  function SetTimbre(TimeNum,TimeDen :word) :boolean;π  procedure SetTickBeat(TickBeat :integer);π  procedure DirectNoteOn(Voice :word; Pitch :integer);π  procedure DirectNoteOff(Voice :word);π  procedure DirectTimbre;π  procedure LoadInstrument(FileSpec :string);π  function LoadSong(FileSpec :string) :boolean;πππimplementationππ  {Returns True if file exists; otherwise, it returns False. Closes the file if it exists.}π  function Exist(fs :string) :boolean;π    varπ      f: file;π    beginπ      {$I-}π      Assign(f,fs);π      Reset(f);π      Close(f);π      {$I+}π      Exist:=(IOResult=0) and (fs<>'');π    end;πππ  procedure InitDriver;π    {Initialize Sound Driver}π    Varπ      r :registers; TmpP:Pointer;π    Beginπ      GetIntVec(101,TmpP);π      If TmpP = Nil Thenπ      Beginπ         WriteLn('Sound Driver Not Installed!');π         Halt(0);π      End;ππ      R.SI:=0;π      Intr(101,r);π    End;ππ  procedure RelTimeStart(TimeNum,TimeDen :integer);π    {Set Relative Time to Start}π    varπ      TD,TN :integer;π      r :registers;π    beginπ      TD:=TimeDen;π      TN:=TimeNum;ππ      r.SI:=2;π      r.ES:=Seg(TN);π      r.BX:=Ofs(TN);ππ      Intr(101,r);π    end;ππ  procedure SetState(State :integer);π    {Start or Stop a Song}π    varπ      r :registers;π    beginπ      r.SI:=3;π      r.ES:=Seg(State);π      r.BX:=Ofs(State);ππ      Intr(101,r);π    end;ππ  function GetState :boolean;π    varπ      r :registers;π    beginπ      r.SI:=4;π      r.ES:=Seg(GetState);π      r.BX:=Ofs(GetState);ππ      Intr(101,r);ππ      GetState:=(r.BP=1);π    end;ππ  procedure SetMode(PercussionMode :integer);π    {Percussion or Melodic Mode}π    varπ      r :registers;π    beginπ      r.SI:=6;π      r.ES:=Seg(PercussionMode);π      r.BX:=Ofs(PercussionMode);ππ      Intr(101,r);π    end;ππ  function SetVolume(VolNum,VolDen,TimeNum,TimeDen :integer) :boolean;π    varπ      TD,TN,VD,VN :word; {To put variables values in proper order in memory}π      r           :registers;π    beginπ      TD:=TimeDen;π      TN:=TimeNum;π      VD:=VolDen;π      VN:=VolNum;ππ      r.SI:=8;π      r.ES:=Seg(VN);π      r.BX:=Ofs(VN);ππ      Intr(101,r);ππ      SetVolume:=(r.BP=1);π    end;ππ  function SetTempo(Tempo,TimeNum,TimeDen :integer) :boolean;π    varπ      TD,TN,TP :integer; {To put variables values in proper order in memory}π      r        :registers;π    beginπ      TD:=TimeDen;π      TN:=TimeNum;π      TP:=Tempo;ππ      r.SI:=9;π      r.ES:=Seg(TP);π      r.BX:=Ofs(TP);ππ      Intr(101,r);ππ      SetTempo:=(r.BP=1);π    end;ππ  procedure SetActVoice(Voice :word);π    varπ      r :registers;π    beginπ      GActVoice:=Voice;ππ      r.SI:=12;π      r.ES:=Seg(Voice);π      r.BX:=Ofs(Voice);ππ      Intr(101,r);π    end;ππ  function PlayNoteDel(Pitch :integer; LengthNum,LengthDen,DelayNum,DelayDen :word) :boolean;π    varπ      DD,DN,LD,LN :word;π      P           :integer;π      r           :registers;π    beginπ      P:=Pitch;π      LD:=LengthDen;π      LN:=LengthNum;π      DN:=DelayNum;π      DD:=DelayDen;ππ      r.SI:=14;π      r.ES:=Seg(P);π      r.BX:=Ofs(P);ππ      Intr(101,r);ππ      PlayNoteDel:=(r.BP=1);π    end;ππ  function PlayNote(Pitch :integer; LengthNum,LengthDen :word) :boolean;π    varπ      LD,LN :word;π      P     :integer;π      r     :registers;π    beginπ      P:=Pitch;π      LD:=LengthDen;π      LN:=LengthNum;ππ      r.SI:=15;π      r.ES:=Seg(P);π      r.BX:=Ofs(P);ππ      Intr(101,r);ππ      PlayNote:=(r.BP=1);π    end;ππ  function SetTimbre(TimeNum,TimeDen :word) :boolean;π    varπ      TD,TN :word;π      T     :^integer;π      c1,c2 :byte;π      r     :registers;π    beginπ      T:=Addr(GT[GActVoice]);π      TN:=TimeNum;π      TD:=TimeDen;ππ      r.SI:=16;π      r.ES:=Seg(T);π      r.BX:=Ofs(T);ππ      Intr(101,r);ππ      SetTimbre:=(r.BP=1);π    end;ππ  function SetPitch(DeltaOctave,DeltaNum,DeltaDen :integer; TimeNum,TimeDen :word) :boolean;π    varπ      TD,TN   :word;π      DD,DN,D :integer;π      c1,c2   :byte;π      r       :registers;π    beginπ      D:=DeltaOctave;π      DN:=DeltaNum;π      DD:=DeltaDen;π      TN:=TimeNum;π      TD:=TimeDen;ππ      r.SI:=16;π      r.ES:=Seg(D);π      r.BX:=Ofs(D);ππ      Intr(101,r);ππ      SetPitch:=(r.BP=1);π    end;ππ  procedure SetTickBeat(TickBeat :integer);π    varπ      r :registers;π    beginπ      r.SI:=18;π      r.ES:=Seg(TickBeat);π      r.BX:=Ofs(TickBeat);ππ      Intr(101,r);π    end;ππ  procedure DirectNoteOn(Voice :word; Pitch :integer);π    varπ      P :integer;π      V :word;π      r :registers;π    beginπ      P:=Pitch;π      V:=Voice;ππ      r.SI:=19;π      r.ES:=Seg(V);π      r.BX:=Ofs(V);ππ      Intr(101,r);π    end;ππ  procedure DirectNoteOff(Voice :word);π    varπ      r :registers;π    beginπ      r.SI:=20;π      r.ES:=Seg(Voice);π      r.BX:=Ofs(Voice);ππ      Intr(101,r);π    end;ππ  procedure DirectTimbre;π    varπ      T     :^integer;π      V     :word;π      r     :registers;π    beginπ      V:=GActVoice;π      T:=Addr(GT[V]);ππ      r.SI:=21;π      r.ES:=Seg(V);π      r.BX:=Ofs(V);ππ      Intr(101,r);π    end;ππ  procedure LoadInstrument(FileSpec :string);π    {Load an Instument from Disk and Place in Array}π    varπ      c1 :byte;π      n  :integer;π      f  :file of integer;π    beginπ      if not(Exist(FileSpec)) then FileSpec:='C:\MUSIC\PIANO1.INS';π      Assign(f,FileSpec);π      Reset(f);π      Read(f,n);π      for c1:=1 to 26 doπ        Read(f,GT[GActVoice,c1]);π      Close(f);π    end;ππ  function LoadSong;π    {Read a .ROL file and place song in Buffer}π    varπ      nb :byte;π      ns :string[255];π      ni,ni2,ni3,ni4,BPM :integer;π      c1,c2  :word;π      nr,nr2 :real;π      fl :boolean;π      f  :file;π    procedure StringRead(len :word); {uses f,ns}π      varπ        nc :char;π        c1 :word;π      beginπ        ns:='';π        for c1:=1 to len doπ          beginπ            BlockRead(f,nc,1);π            ns:=ConCat(ns,nc);π          end;π      end;π    procedure TempoRead; {uses f,nb}π      varπ        b1,b2,b3,b4 :byte;π      beginπ        BlockRead(f,b1,1);π        BlockRead(f,b2,1);π        BlockRead(f,b3,1);π        BlockRead(f,b4,1);π        nb:=(b3{ div 2});π      end;π    procedure VolumeRead;π      varπ        b1,b2,b3,b4 :byte;π      beginπ        BlockRead(f,b1,1);π        BlockRead(f,b2,1);π        BlockRead(f,b3,1);π        BlockRead(f,b4,1);π        nb:=51+Round(b3/2.5);π      end;π    beginπ      LoadSong:=true;π      if not(Exist(FileSpec))π        then beginπ               LoadSong:=false;π               Exit;π             end;ππ      InitDriver;π      RelTimeStart(0,1);π      Assign(f,FileSpec);π      Reset(f,1);π      StringRead(44);π      BlockRead(f,ni,2); SetTickBeat(ni); {Ticks per Beat}π      BlockRead(f,ni,2); BPM:=ni; {Beats per Measure}π      StringRead(5);π      BlockRead(f,nb,1); SetMode(1); {Mode}π      StringRead(143);π      TempoRead; fl:=SetTempo(nb,0,1); {Tempo}π      BlockRead(f,ni,2);π      for c1:=1 to ni doπ        beginπ          BlockRead(f,ni2,2);π          TempoRead; fl:=SetTempo(nb,ni2,1); {Tempo}π        end;π      for c1:=0 to 10 do {11 Voices}π        beginπ          SetActVoice(c1);π          StringRead(15);π          BlockRead(f,ni2,2); {Time in ticks of last Note}π          c2:=0;π          while (c2<ni2) doπ            beginπ              BlockRead(f,ni3,2); {Note Pitch}π              BlockRead(f,ni4,2); {Note Duration}π              fl:=PlayNote(ni3-60,ni4,BPM); {Note}π              c2:=c2+ni4; {Summation of Durations}π            end;π          StringRead(15);π          BlockRead(f,ni2,2);π          for c2:=1 to ni2 do {Instuments}π            beginπ              BlockRead(f,ni3,2);π              StringRead(9);π              nb:=Pos(#0,ns);π              Delete(ns,nb,Length(ns));π              LoadInstrument(ConCat('C:\MUSIC\',ns,'.INS'));π              fl:=SetTimbre(ni3,1);π              StringRead(1);π              BlockRead(f,ni4,2);π            end;π          StringRead(15);π          BlockRead(f,ni2,2);π          nb:=1;π          for c2:=1 to ni2 do {Volume}π            beginπ              BlockRead(f,ni3,2);π              fl:=SetVolume(100,nb,ni3,1); {Use inverse to disable Relative}π              VolumeRead;π              fl:=SetVolume(nb,100,ni3,1);π            end;π          StringRead(15);π          BlockRead(f,ni2,2);π          for c2:=1 to ni2 do {Pitch -disabled}π            beginπ              BlockRead(f,ni3,2);π              BlockRead(f,nr,4);π              if (nr=0) then nr2:=1 else nr2:=nr;π{             fl:=SetPitch(0,Abs(Trunc(nr*100)),Trunc((nr/nr2)*100),ni3,1);}π            end;π        end;π      Close(f);π    end;ππend.π