home *** CD-ROM | disk | FTP | other *** search
- {Sound generation and timing interrupt
-
- Written by:
-
- Nels Anderson
- 92 Bishop Drive
- Framingham, MA 01701
-
- Released to the public domain
- }
-
- unit Sounder;
-
- interface
-
- Uses
- Crt;
-
- procedure StartSound(Notes: POINTER; Repeats: INTEGER; Speed: BYTE);
-
- const
-
- { Notes Values:
-
- Use these constants to get the proper values for notes. The first
- character is the note name, S indicates a sharp, and the final number
- indicates the octave.}
-
- CN3 = 13;
- CS3 = 14;
- DN3 = 15;
- DS3 = 16;
- EN3 = 16;
- FN3 = 17;
- FS3 = 19;
- GN3 = 20;
- GS3 = 21;
- AN3 = 22;
- AS3 = 23;
- BN3 = 25;
- CN4 = 26;
- CS4 = 28;
- DN4 = 29;
- DS4 = 31;
- EF4 = 31;
- EN4 = 33;
- FF4 = 33; {?}
- FN4 = 35;
- FS4 = 37;
- GN4 = 39;
- GS4 = 42;
- AF4 = 42;
- AN4 = 44;
- AS4 = 47;
- BF4 = 47;
- BN4 = 49;
- CN5 = 52;
- CS5 = 55;
- DF5 = 55;
- DN5 = 59;
- DS5 = 62;
- EN5 = 66;
- FN5 = 70;
- FS5 = 74;
- GN5 = 78;
- GS5 = 83;
- AF5 = 83;
- AN5 = 88;
- AS5 = 93;
- BF5 = 93;
- BN5 = 99;
- CN6 = 105;
- CS6 = 111;
- DN6 = 117;
- DS6 = 124;
- EN6 = 133;
- FN6 = 140;
- FS6 = 148;
- GN6 = 157;
- GS6 = 166;
- AN6 = 176;
- AS6 = 186;
- BN6 = 198;
- CN7 = 209;
- CS7 = 222;
- DN7 = 235;
- DS7 = 249;
-
- { Sound Collection:
-
- Each sound is an array of pairs of bytes, where the first byte of each
- pair is the duration in 1/18th second units and the second byte of the
- pair is the note frequency in 10's of Hertz. To use a sound, include
- a command like the following in a program:
-
- StartSound(@PhaserSound,3,1); {do phaser sound 3 times}
-
- Ruddigore: array[1..411] of BYTE = ( {theme song}
- 36,000,
- 3,DN4,1,DN4, 2,DN4,2,DN4,8,FN4,4,DN4,
- 2,DN4,2,DN4,8,AN4,3,AN4,1,AN4,
- 4,DN5,2,AN4,2,AN4,4,AN4,4,BN4, 12,CN5,4,CN4,
- 2,CN4,2,CN4,8,EN4,2,CN4,2,CN4,
- 2,CN4,2,CN4,8,GN4,4,CN4, 4,CN5,2,CN5,2,CN5,2,CN5,2,DF5,4,BF4,
- 12,AF4,3,AF4,1,AF4,
- 4,FF4,4,FF4,6,AF4,2,FF4, 4,EF4,4,EF4,6,AF4,2,AF4,
- 4,FF4,4,FF4,4,AF4,2,AF4,2,AF4, 12,BN4,4,EN4,
- 4,AN4,4,AN4,4,AN4,2,BN4,2,CS5,
- 4,DN5,4,AN4,4,FN4,4,DN4, 4,AN4,4,AN4,4,AN4,2,BN4,2,CS5,
- 6,DN5,2,FN5,4,FN5,4,DN5, 4,DN5,2,DN5,2,DN5,4,CS5,4,CS5,
- 6,DN5,2,FN5,4,FN5,4,DN5, 4,DN5,4,CS5,4,CN5,4,AF4,
- 4,CN5,4,BN4,4,BF4,4,GN4, 4,CS5,4,AN4,4,FS4,4,FN3,
- 8,AN4,8,AN3, 8,DN4,8,000,
-
- 3,DN4,1,DN4, 2,DN4,2,DN4,8,FN4,4,DN4,
- 2,DN4,2,DN4,8,AN4,3,AN4,1,AN4,
- 4,DN5,2,AN4,2,AN4,4,AN4,4,BN4, 12,CN5,4,CN4,
- 2,CN4,2,CN4,8,EN4,2,CN4,2,CN4,
- 2,CN4,2,CN4,8,GN4,4,CN4, 4,CN5,2,CN5,2,CN5,2,CN5,2,DF5,4,BF4,
- 12,AF4,3,AF4,1,AF4,
- 4,FF4,4,FF4,6,AF4,2,FF4, 4,EF4,4,EF4,6,AF4,2,AF4,
- 4,FF4,4,FF4,4,AF4,2,AF4,2,AF4, 12,BN4,4,EN4,
- 4,AN4,4,AN4,4,AN4,2,BN4,2,CS5,
- 4,DN5,4,AN4,4,FN4,4,DN4, 4,AN4,4,AN4,4,AN4,2,BN4,2,CS5,
- 6,DN5,2,FN5,4,FN5,4,DN5, 4,DN5,2,DN5,2,DN5,4,CS5,4,CS5,
- 6,DN5,2,FN5,4,FN5,4,DN5, 4,DN5,4,CS5,4,CN5,4,AF4,
- 4,CN5,4,BN4,4,BF4,4,GN4, 4,CS5,4,AN4,4,FS4,4,FN3,
- 8,AN4,8,AN3,
- 4,DN4,2,000,2,GN3,4,DN4,2,000,2,GN3,
- 4,DN4,2,000,2,GN3,2,DN4,2,GN3,2,DN4,2,GN3,
- 4,DN4,4,000,4,DN4,4,000, 16,DN4,0);
-
- Canon: array[1..639] of BYTE = (
- 36,000,
- 4,000,4,FS5,4,EN5,4,DN5, 4,EN5,4,DN5,4,CS5,8,BN4, {1-2}
- 4,FS5,4,EN5,4,DN5,4,DN5, 4,CS5,4,BN4,4,AN4,4,CS5, {3-4}
- 4,000,4,BN5,4,AN5,4,GN5, 8,AN5,4,BN5,4,CS6, {5-6}
- 8,DN6,8,BN5, 4,FS5,4,EN5,4,FS5,2,AN4,2,GN4, {7-8}
- 4,FS5,4,EN5,4,FS5,4,AN5, 8,FS5,4,FS5,4,EN5, {9-10}
- 4,DN5,2,DN5,2,EN5,4,FS5,4,BN5, 8,BN5,4,000,4,AN5, {11-12}
- 4,GN5,2,FS5,2,EN5,4,DN5,4,EN4, 4,FS4,4,000,4,DN5,4,FS4,
- 4,GN4,4,DN5,4,EN5,4,DN5, 2,CS5,2,BN4,8,AN4,4,000, {15-16}
- 2,FS4,2,AN4,2,FS4,2,AN4,2,FS4,2,AN4,2,FS4,2,AN4, {17}
- 2,EN4,2,AN4,2,EN4,2,AN4,2,EN4,2,AN4,2,EN4,2,AN4, {18}
- 2,FS4,2,BN4,2,FS4,2,BN4,2,FS4,2,BN4,2,FS4,2,AN4, {19}
- 2,AN4,2,CS5,2,FS5,2,GN5,2,FS5,2,DN5,2,AN4,2,CS5, {20}
- 2,AN4,4,DN5,4,GN5,2,DN5,2,CS5,2,BN4, {21}
- 2,DN5,2,CS5,8,DN5,4,DN5, {22}
- 2,DN4,2,BN4,2,CS5,2,BN4,4,DN5,2,EN5,2,DN5, {23}
- 2,CS5,2,BN4,8,AN4,2,EN4,2,AN4, {24}
- 4,FS5,4,DN5,4,FS4,4,FS5, {25}
- 4,EN5,4,AN4,1,EN5,1,FS5,1,EN5,1,FS5,1,EN5,1,FS5,2,EN5,
- 4,DN5,4,BN4,4,FS4,4,DN5, {27}
- 4,CS5,4,AN4,1,CS5,1,DN5,1,CS5,1,DN5,1,CS5,1,BN4,2,CS5,{28}
- 4,BN4,4,DN5,4,BN4,4,GN4, {29}
- 1,FS4,1,AN4,1,DN5,1,FS5,1,AN4,1,DN5,1,FS5,1,AN5, {30}
- 1,DN5,1,FS5,1,AN5,1,BN5,1,AN5,1,GN5,1,FS5,1,EN5,
- 4,DN5,4,BN4,2,GN4,2,BN4,2,CS5,2,DN5, {31}
- 4,CS5,4,EN5,1,AN5,1,BN5,1,AN5,1,BN5,1,AN5,1,BN5,2,GN5,{32}
- 1,FS5,1,EN5,1,DN5,1,AN4,1,FS4,1,EN4,1,BN4,1,AN3, {33}
- 1,DN6,1,GN5,1,FS5,1,DN5,1,AN4,1,GN4,1,FS4,1,DN4,
- 1,EN5,1,DN5,1,CS5,1,BN4,1,CS5,1,GN4,1,FS4,1,EN4, {34}
- 1,GN5,1,FS5,1,EN5,1,DN5,1,CS5,1,BN4,1,AN4,1,GN4,
- 1,DN5,1,CS5,1,BN4,1,FS4,1,DN4,1,CS4,1,BN3,1,FS3, {35}
- 1,BN5,1,EN5,1,DN5,1,CS5,1,BN4,1,AN4,1,GN4,1,FS4,
- 1,CS5,1,BN4,1,AN4,1,GN4,1,AN4,1,EN4,1,DN4,1,CS4, {36}
- 1,AN5,1,GN5,1,FS5,1,EN5,1,DN5,1,CS5,1,BN4,1,AN4,
- 1,BN4,1,AN4,1,GN4,1,FS4,1,FS4,1,DN4,1,CS4,1,BN3, {37}
- 1,GN4,1,BN4,1,CS5,1,DN5,1,GN5,1,AN5,1,BN5,1,DN6,
- 1,FS6,1,EN6,1,DN6,1,AN5,1,FS5,1,EN5,1,DN5,1,AN4, {38}
- 1,DN5,1,EN5,1,FS5,1,GN5,1,AN5,1,BN5,1,CS6,1,DN6,
- 1,GN5,1,FS5,1,EN5,1,DN5,1,CS5,1,BN4,1,AN4,1,GN4, {39}
- 1,BN5,1,AN5,1,GN5,1,FS5,1,EN5,1,DN5,1,CS5,1,BN4,
- 1,CS6,1,BN5,1,AN5,1,GN5,1,FS5,1,EN5,1,DN5,1,CS5, {40}
- 1,AN4,1,GN4,1,FS4,1,EN4,1,DN4,1,CS4,1,BN3,1,AN3,
- 8,DN5,8,AN4, 8,CS5,8,AN4, 8,BF4,8,FN4,
- 8,BF4,4,000,4,BF4, 8,BF4,8,AN4, 16,AN4,16,DN5,0);
-
- PhaserSound: array[1..5] of BYTE = (
- 1,30,1,31,0);
- TorpSound: array[1..13] of BYTE = (
- 1,8,1,9,1,8,1,20,1,21,1,22,0);
- WhistleSound: array[1..5] of BYTE = (
- 4,50,10,100,0);
- Type
- {
- You must modify the number 639 below so that
- it equals the number of cells in the biggest
- array of the Sound Collection constants above.
- }
-
- ByteArray = array[1..639] of BYTE;
- Var
- SoundSpeed: BYTE; {multiplier used to slow down sounds}
- SoundCount: BYTE; {counts how long current sound has been on}
- MySound: ^ByteArray; {points to array of notes and durations}
- New1CInt, {address of new interrupt}
- Int1CSave: POINTER; {saves original $1C interrupt}
- NumRepeats, {number of times to repeat sound}
- MyClock, {general purpose timer}
- SoundOff: INTEGER; {offset into note array}
- SndFlg, {set when sounds allowed}
- MakeSound: BOOLEAN; {set while sound is going}
-
- implementation
-
- procedure StartSound(Notes: POINTER; Repeats: INTEGER; Speed: BYTE);
- { Start generating the sound pointed to by Notes }
- begin
- SoundSpeed := Speed; {set speed}
- SoundOff := 1; {offset into sound array}
- SoundCount := 1; {counter for current note}
- MySound := Notes; {pointer to sound array}
- MakeSound := TRUE; {enable sounds}
- NumRepeats := Repeats; {number times to repeat sound}
- end; {StartSound procedure}
-
- procedure TimerInt;
- interrupt;
- { Clock tick interrupt
-
- BIOS interrupt $1C has been replaced with the following routine. This
- interrupt occurs on each clock tick (18 per second).
-
- The interrupt mainly handles sounds. When the MakeSound flag is true,
- the pointer MySound must be pointing to a byte array containing durations
- and frequencies of sounds to be generated. Sounds will be generated from
- the array until a duration of 0 is found.
-
- A general purpose timer is also incremented each time the interrupt
- occurs.
-
- To use the interrupt, the main program needs to do the following:
-
- Begin
- GetIntVec($1C,Int1CSave); (save original interrupt vector)
- SetIntVec($1C,New1CInt); (install timer interrupt)
- .
- . (body of program)
- .
- StartSound(@PhaserSound,3,1); (phaser sound 3 times, normal speed)
- .
- . (body of program)
- .
- SetIntVec($1C,Int1CSave); (restore original 1C interrupt)
- end.
- }
- begin
- Inc(MyClock); {increment timer}
- if not SndFlg then begin {exit if sounds turned off}
- MakeSound := FALSE;
- Exit;
- end;
- if MakeSound then begin {if making a sound...}
- Dec(SoundCount);
- if SoundCount <= 0 then begin {if current sound done...}
- NoSound;
- SoundCount := SoundSpeed * MySound^[SoundOff];{get duration of next one}
- if SoundCount > 0 then begin {if there is a next one...}
- Inc(SoundOff);
- Sound(10*MySound^[SoundOff]); {start it up}
- Inc(SoundOff);
- end
- else begin {if end of sound array...}
- Dec(NumRepeats); {decrement number of repeats}
- if NumRepeats > 0 then begin {if we must repeat...}
- SoundOff := 3; {reset offset into array}
- SoundCount := MySound^[1]; {get duration of first note}
- Sound(10*MySound^[2]); {start it up}
- end
- else begin {if all repeats now done...}
- NoSound; {stop all sound}
- MakeSound := FALSE; {reset flag}
- end;
- end;
- end; {if SoundCount = 0}
- end; {if making a sound}
- end; {TimerInt interrupt procedure}
-
- begin
-
- SndFlg := TRUE; {sounds are allowed}
- MakeSound := FALSE; {sound initially off}
- MyClock := 0; {reset timer}
- New1CInt := @TimerInt; {get address of interrupt}
-
- end.
-