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 ■"
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.π