home *** CD-ROM | disk | FTP | other *** search
- PROGRAM MusicalScale;
- CONST
- Off = 0; {By: Merlin Hanson Genie:M.L.HANSON}
- On = 1;
- Down = 0;
- Up = 1;
- VAR
- Period : integer ;
- C4 : real;
- Volume : 1..15;
- Key : char;
- OldWord : long_integer;
- PeriodArr : ARRAY [1..13] OF integer;
- Index : 1..13;
-
- {$P-} {Pointer range checking off.}
- PROCEDURE KeyClicker(OnOff : integer);
- TYPE
- Pointer = ^long_integer;
- VAR
- Funny : RECORD
- CASE boolean OF
- TRUE : (A : long_integer);
- FALSE : (P : Pointer);
- END {record};
- SSP : long_integer;
-
- FUNCTION Super
- (StackPointer : long_integer)
- : long_integer;
- GEMDOS($20);
-
- FUNCTION Peek( address: long_integer ): long_integer;
- BEGIN
- Funny.A := Address;
- Peek := Funny.P^;
- END;
-
- PROCEDURE Poke( address, value: long_integer );
- BEGIN
- Funny.A := Address;
- Funny.P^ := Value;
- END;
-
- BEGIN {keyclicker}
- SSP := Super(0);
- CASE OnOff OF
- OFF : BEGIN
- OldWord := Peek($484);
- Poke($484,OldWord & $FEFFFFFF);
- END;
- ON : Poke($484,OldWord);
- END {case};
- SSP := Super(SSP);
- END {keyclicker};
- {$P=}
-
- {------------------ Following from CURSOR.PAS ------------------}
- PROCEDURE out_char( c: integer );
- CONST
- screen = 2;
-
- PROCEDURE bconout( device, c: integer );
- BIOS(3);
-
- BEGIN {out_char}
- bconout( screen, c );
- END; {out_char}
-
- { Put a two-character escape sequence to the console device (an escape
- followed by a single character) }
- PROCEDURE out_escape( c: char );
- CONST
- escape = 27;
- BEGIN
- out_char( escape );
- out_char( ord(c) );
- END;
-
- { Clear the screen and move the cursor to the upper left position }
- PROCEDURE ClrScr;
- BEGIN
- out_escape( 'E' )
- END {clrscr};
-
- { Move to a specific screen coordinate. Home is (1,1). }
- PROCEDURE GotoXY( x, y: integer );
- BEGIN
- out_escape( 'Y' ); out_char( 31+x ); out_char( 31+y );
- END {gotoxy};
-
- {----------------------- End of CURSOR.PAS ------------------}
-
- PROCEDURE FillPeriodArray;
- CONST
- Ratio = 0.943874313; { 1 / (2 ^ [1/12] ) from a calculator. }
- {For frequency, the ratio for adjacent semitones is
- 2 ^ (1/12) but the sound chip is based on period, rather than
- frequency, so the reciprocal is used. }
- VAR
- PeriodReal : real;
- i : integer;
-
- BEGIN {fillperiodarray}
- PeriodReal := C4; {Change this slightly to tune.}
- PeriodArr[1] := ROUND(PeriodReal);
- FOR i := 2 TO 13 DO
- BEGIN
- PeriodReal := PeriodReal * Ratio;
- PeriodArr[i] := ROUND(PeriodReal);
- END
- END {fillperiodarray};
-
- PROCEDURE DisplayText;
- BEGIN
- ClrScr;
- GOTOXY(9,37);
- WriteLn('TUNING');
- GOTOXY(11,25);
- WriteLn('The current period for C4 is: 478' );
- WriteLn;
- WriteLn('The nominal period is: 478' :57);
- END {displayText};
-
- PROCEDURE Tune(UpDown : integer);
- BEGIN
- CASE UpDown OF
- {Up means higher frequency, so lower period.}
- Up : C4 := C4 - 1;
- Down : C4 := C4 + 1;
- END {case};
- FillPeriodArray;
- {Remember the number printed is a *period*, so a larger
- number is actually a *lower* frequency. Its not very
- appealing to the intuition.}
- GOTOXY(11,55);
- WriteLn(ROUND(C4));
- END {tune};
-
- FUNCTION gia_read
- (data : integer;
- register : integer)
- : integer ;
- XBIOS( 28 ) ;
-
- PROCEDURE gia_write
- (data : integer;
- register : integer) ;
- XBIOS( 28 ) ;
-
- PROCEDURE EnableChannelA;
- CONST
- Reg7 = 7; {The 'master control' register.}
- VAR
- dummy : integer;
- OldReg : integer;
- BEGIN {enablechannelA}
- OldReg := gia_read(dummy,Reg7);
- Gia_Write(OldReg & ($FE), {Preserve PortA,PortB status.}
- Reg7 + 128);
- END {enablechannelA};
-
- PROCEDURE Sound
- (Period : integer;
- Volume : integer);
- CONST
- Reg0 = 0; {8 low-order bits of period.}
- Reg1 = 1; {4 high-order bits of period.}
- Reg8 = 8; {Volume for channel A. }
- BEGIN {sound}
- gia_write(Volume , Reg8 + 128);
- gia_write(Period & $FF, Reg0 + 128);
- Gia_Write(SHR(Period,8),Reg1 + 128);
- END {sound};
-
- FUNCTION ConsoleInputNoEcho : char;
- {Get one character from the console.
- Don't print it on the monitor.}
- GEMDOS ($07);
-
- PROCEDURE Silence;
- {A brief moment of silence to take care of the case
- where two adjacent notes are the same.}
- VAR
- k : integer;
- junk : real;
- BEGIN
- Sound(0,0);
- junk := 0; {Avoid possible overflow.}
- FOR k := 1 TO 500 Do
- junk := junk * junk;
- END{silence};
-
- PROCEDURE CleanUp;
- CONST
- Reg7 = 7; {The 'master control' register.}
- VAR
- dummy : integer;
- OldReg : integer;
- BEGIN
- {Turn the volume down.}
- Sound(0,0);
- {Return ports to original state.}
- OldReg := gia_read(dummy,Reg7);
- {Force 6 low order bits to 1, sound off on all channels.}
- gia_write(OldReg | $3F, Reg7 + 128);
- KeyClicker(On);
- END {cleanup};
-
- BEGIN {main}
- DisplayText;
- KeyClicker(Off);
- C4 := 478;
- FillPeriodArray;
- EnableChannelA;
- Volume := 10;
- LOOP
- Key := ConsoleInputNoEcho;
- EXIT IF Key IN ['q','Q'];
- CASE Key OF
- '+' : Tune(Up);
- '-' : Tune(Down);
- 'c' : Index := 1;
- 'd' : Index := 3;
- 'e' : Index := 5;
- 'f' : Index := 6;
- 'g' : Index := 8;
- 'a' : Index := 10;
- 'b' : Index := 12;
- 'C' : Index := 13;
- {sharps and flats only provided for tuning.}
- '1' : Index := 2; { C# }
- '2' : Index := 4; { D# }
-
- '3' : Index := 7; { F# }
- '4' : Index := 9; { G# }
- '5' : Index := 11; { A# }
- END {case};
- Silence;
- Period := PeriodArr[Index];
- Sound(Period,Volume);
- END {loop};
- CleanUp;
- END. {program}
-