; PCTUNE
;
; Program for Proteus
;
; (C) 2003-2004 Simone Zanella Productions
;
; This program plays a melody in RTTTL format through PC speaker.
; Limitations: volume is not supported.
#!proteus -z
IF LT(ARGC, 5)
CONSOLELN "Syntax: " ARGV(1) " " ARGV(2) " [rtttl_melody]"
CONSOLELN ""
CONSOLELN "This program plays a melody in RTTTL format through PC speaker."
CONSOLELN ""
CONSOLELN "Limitations:"
CONSOLELN "- volume is not supported.\n"
; Default melody
S = "ColonelBogeyf:d=4,o=5,b=140:8g,8e,p,8p,8e,8f,8g,e6,e6,2c6,8g,8e,p,8p,8e,8f,8e,g,g,2f,8f,8d,p,8p,8d,8e,8f,8g,8e,p,8p,8e,8f#,8e,8d,8g,8p,8e,8f#,8d,8p,8a,8g.,16f#,8g,8a,8g,8f#,8e,8d,8g,8e,p,8p,8e,8f,8g,e6,e6,2c6,8g,8e,p,8p,8e,8f,8e,g,g,2f,8f,8d,p,8p,8a,8b,8a,8c6,8g,p,8p,8g,8f,8e,8d,8a,8p,8c,8b4,8g,8p,8b4,2c.,p"
ELSE
S = ARGV(5)
FI
Note = VECCREATE(2, 3, 5, 7, 8, 10)
P = STRSTR(S, ":")
Title = LEFT(S, DEC(P))
S = RESTFROM(S, INC(P))
P = STRSTR(S, ":")
Defaults = LEFT(S, DEC(P))
S = RESTFROM(S, INC(P))
CONSOLELN "// RTTTL: " Title
DefDuration = 4
DefScale = "5"
DefBeatSpm = 63
; Not implemented
DefVolume = 7
; Implemented by slightly decreasing note duration
DefStyle = 1
; Volume
; 5 = scale
; 63 = beats-per-minute
; 7 = volume
; 1 = style
T2 = TOKNEW(Defaults, ",")
FOR X = 1 TO TOKNUM(T2)
SWITCH LEFT(TOKGET(T2, X), 1) STRIEQ
ON "D"
; Default duration
DefDuration = RESTFROM(TOKGET(T2, X), 3)
ON "O"
; Default octave
DefScale = RESTFROM(TOKGET(T2, X), 3)
ON "B"
; Number of notes per minute
DefBeatSpm = RESTFROM(TOKGET(T2, X), 3)
ON "V"
; Default volume
DefVolume = RESTFROM(TOKGET(T2, X), 3)
ON "S"
; Default style
DefStyle = RESTFROM(TOKGET(T2, X), 3)
OFF
NEXT
; Beat duration (milliseconds)
beat = FDIV(60000, DefBeatSpm)
CONSOLELN "// DefDuration = " DefDuration
CONSOLELN "// DefScale = " DefScale
CONSOLELN "// DefBeatSpm = " DefBeatSpm
CONSOLELN "// DefVolume = " DefVolume
CONSOLELN "// DefStyle = " DefStyle
TOKFREE(T2)
T2 = TOKNEW(S, ",")
C = 1
FOR X = 1 TO TOKNUM(T2)
WhichNote = TOKGET(T2, X)
Duration = ""
Y = 0
WHILE ISDIGIT(SUBSTR(WhichNote, INC(Y), 1))
INC(@Y)
LOOP
IF Y
Duration = LEFT(WhichNote, Y)
ELSE
Duration = DefDuration
FI
WhichNote = RESTFROM(WhichNote, INC(Y))
PWhichNote = LEFT(WhichNote, 1)
IF STREQ(SUBSTR(WhichNote, 2, 1), "#")
PWhichNote = PWhichNote "#"
WhichNote = RESTFROM(WhichNote, 3)
ELSE
WhichNote = RESTFROM(WhichNote, 2)
FI
PWhichNote = UPPER(PWhichNote)
IF ISNOTEMPTY(WhichNote)
C1 = LEFT(WhichNote, 1)
C2 = SUBSTR(WhichNote, 2, 1)
IF AND(ISNOTEMPTY(C1), ISDIGIT(C1))
Scale = C1
Special = C2
ELSE
IF AND(ISNOTEMPTY(C2), ISDIGIT(C2))
Scale = C2
Special = C1
ELSE
Special = WhichNote
Scale = DefScale
FI
FI
ELSE
Scale = DefScale
Special = ""
FI
PlayNote(PWhichNote, Duration, Scale, Special, beat, C)
INC(@C)
NEXT
TOKFREE(T2)
ABORT 0
FUNCTION PlayNote(whichnote, duration, scale, special, beat, c)
d = FDIV(1, duration)
SWITCH special STREQ
ON "."
d = ADD(d, FDIV(d, 2))
ON ","
d = ADD(d, FDIV(d, 2), FDIV(d, 4))
ON "&"
d = FDIV(MUL(d, 2), 3)
OFF
SWITCH _DefStyle EQ
ON 1
; Normal = 90%
d = FDIV(MUL(d, 100), 90)
ON 2
; Continuous = 100%
ON 3
; Staccato = 70%
d = FDIV(MUL(d, 100), 70)
OFF
d = INT(MUL(beat, d))
IF STRNEQ(LEFT(whichnote, 1), "P")
; Note: A-G
; A4 = 440
; A5 = 880
; A6 = 1760
; A7 = 3520
IF IN(LEFT(whichnote, 1), "AB")
INC(@scale)
FI
SWITCH scale EQ
ON 4
basefreq = 440
ON 5
basefreq = 880
ON 6
basefreq = 1760
ON 7
basefreq = 3520
OFF
C3 = SUB(ASC(LEFT(whichnote, 1)), ASC("A"))
IF C3
basefreq = MUL(basefreq, POW(2, FDIV(VECGET(_Note, C3), 12)))
FI
IF STREQ(RIGHT(whichnote, 1), "#")
basefreq = MUL(basefreq, POW(2, FDIV(1, 12)))
FI
basefreq = INT(basefreq)
BEEP(basefreq, d)
SLEEP(FDIV(d, 1000))
FI
RETURN
!bdoc
Here it is, in theory, for modern tunings:
A above Middle C is 440 Hz
to get the note 1 halfstep above, multiply by 2 ^ 1/12 (that's
2 to the 1/12 power, also known as the "twelfth
root of two)
So A# would be 440 * 1.059463094 or about
466.153 Hz.
Octaves are easy, they're just double the frequency,
so the A the octave above A440 would be 880.
(This is the same as multiplying by 2 ^ 12/12).
I'll leave it as an exercise for you to do the math and come
up with all your frequencies.
An interesting aside: Pianos are tuned slightly off! Depending
on how short your piano is, the higher notes are tuned slightly
sharp and the lower notes are tuned slightly flat. This will make
it sound more in tune--because of physical characteristics of the
string and the harmonics it generates, than it would if it were
in perfect tune.
!edoc