-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
' The good news iz that I worked out numbers for my notes.
' The bad news iz that I hav not redone the vocals, so they
' are still a-cappella (and kind of breathy).
'
http://ecn.ab.ca/~brewhaha/font/Pavlov_4_Cybersocial_Birds.wmv
' My copyleft on this song iz like this:
'
http://ecn.ab.ca/~brewhaha/finance/CC-BY-SD.wmv
' SD: Some Derivatives.
' That license should go on any disk of my song.
' In a moderated medium (bigger makes it more likely
' they are commercial), like television, that license
' should be played first and about once every seven
' times my video iz played.
' I do not even try to restrict personal performance.
OPTION BASE 1
DIM harmonics(2) AS DOUBLE
' I am hitting more typical ratios than I usually do.
' This maps 540, my tonic, onto a "standard" B,
' letting other notes fall where they may, slightly
' off key, and exactly on the harmonic series:
harmonics(1) = 440 / 2 ^ (1 / 12) ^ 10 / 540
harmonics(2) = harmonics(1)
' Left channel note, right channel, length,
' concert ratio name.
DATA 0, 0, 1, "Jerminal Rest"
DATA 720, 540, 3, "Perfect Fourth"
DATA 0, 0, 1, "Rest"
DATA 672, 432, 8, "Septimal Minor Sixth"
DATA 720, 320, 12, "Major Niinth"
DATA 0, 0, 4, "Rest"
DATA 810, 270, 4, "Tritave"
DATA 900, 540, 4, "Major Sixth"
DATA 810, 648, 8, "Major Third"
DATA 720, 540, 12, "Perfect Fourth"
DATA 0, 0, 4, "Rest"
DATA 640, 320, 4, "Octave"
DATA 540, 540, 12, "Unison"
DATA 360, 480, 12, "Perfect Fourth, crossed"
DATA 0, 0, 4, "Rest"
DATA 720, 540, 8, "Perfect Fourth"
DATA 540, 432, 12, "Major Third"
DATA 0, 0, 8, "Rest"
DATA 640, 480, 3, "Perfect Fourth"
DATA 0, 0, 1, "Rest"
DATA 600, 600, 8, "Unison"
DATA 640, 480, 12, "Perfect Fourth"
DATA 0, 0, 4, "Rest"
DATA 720, 360, 4, "Octave"
DATA 810, 480, 4, "Pythagorean Major Sixth"
DATA 720, 432, 8, "Major Sixth"
DATA 648, 360, 12, "Just Minor Seventh"
DATA 0, 0, 4, "Rest"
DATA 540, 320, 4, "Pythagorean Major Sixth"
DATA 480, 600, 12, "Major Third, crossed"
DATA 320, 540, 12, "Pythagorean Major Sixth, tails in"
DATA 0, 0, 4, "Rest"
DATA 640, 600, 8, "Minor Diatonic Semitone"
DATA 480, 480, 12, "Unison"
DATA 0, 0, 8, "Rest"
DATA 576, 540, 4, "Minor Diatonic Semitone"
DATA 540, 480, 8, "Major Second"
DATA 576, 432, 12, "Perfect Fourth"
DATA 0, 0, 4, "Rest"
DATA 640, 320, 4, "Octave"
DATA 720, 540, 4, "Perfect Fourth"
DATA 640, 640, 6, "Unison"
DATA 0, 0, 2, "Rest"
DATA 576, 540, 8, "Minor Diatonic Semitone"
DATA 480, 320, 12, "Perfect Fifth"
DATA 0, 0, 6, "Rest"
DATA 648, 432, 4, "Perfect Fifth"
DATA 600, 540, 8, "Minor Second"
DATA 640, 640, 12, "Unison"
DATA 0, 0, 4, "Rest"
DATA 720, 432, 4, "Major Sixth"
DATA 810, 540, 4, "Perfect Fifth"
DATA 720, 640, 6, "Major Second"
DATA 0, 0, 2, "Rest"
DATA 810, 540, 8, "Perfect Fifth"
DATA 972, 432, 12, "Major Niinth"
DATA 0, 0, 8, "Rest"
DATA 576, 320, 4, "Just Minor Seventh"
DATA 540, 432, 8, "Major Third"
DATA 576, 540, 12, "Minor Diatonic Semitone"
DATA 0, 0, 4, "Rest"
DATA 640, 320, 4, "Octave"
DATA 720, 540, 4, "Perfect Fourth"
DATA 648, 432, 8, "Perfect Fifth"
DATA 576, 405, 12, "Second Tritone"
DATA 0, 0, 2, "Rest"
DATA 720, 480, 8, "Perfect Fifth"
DATA 648, 432, 12, "Perfect Fifth"
DATA 0, 0, 12, "Rest"
DATA 480, 640, 12, "Perfect Fourth, crossed"
DATA 810, 720, 12, "Major Second"
DATA 0, 0, 6, "Rest"
DATA 480, 540, 6, "Major Second, crossed"
DATA 0, 0, 6, "Rest"
DATA 972, 648, 12, "Perfect Fifth"
DATA 0, 0, 6, "Rest"
DATA 480, 320, 6, "Perfect Fifth"
DATA 648, 432, 12, "Perfect Fifth"
DATA 0, 0, 30, "Terminal Rest"
' F# G G# A A# B C C# D D# E F
' 270 288 320 360 405 432 480
' 540 576 600 640 648 672 720 810 900 960 972
DIM TwoPi AS DOUBLE
DIM pi AS DOUBLE
DIM temp AS DOUBLE
DIM BeatsPerSecond AS DOUBLE
DIM Angle(2) AS DOUBLE
DIM Velocity(2) AS DOUBLE
DIM Acceleration(2) AS DOUBLE
DIM Phase(2) AS DOUBLE
DIM note(2) AS INTEGER
DIM LastNote(2) AS INTEGER
DIM length AS INTEGER
DIM samples AS LONG
DIM t AS LONG
DIM SampleRate AS LONG
DIM k AS INTEGER
DIM g AS INTEGER
DIM amp AS INTEGER
DIM NumHarmonics AS INTEGER
DIM Sign(2) AS INTEGER
DIM glide AS INTEGER
DIM GlideTrim AS LONG
DIM TerminalAngle(2) AS DOUBLE
DIM DropAngle(2) AS DOUBLE
DIM PhaseDir(2) AS DOUBLE
DIM rationame AS STRING
DIM test AS STRING
PRINT
test = "0"
' I frequently flip that.
NumHarmonics = 2
BeatsPerSecond = 15#
pi = 3.141592653589793#
TwoPi = pi * 2
SampleRate = 44100
IF test = "0" THEN
OPEN "\sox\pavlov.raw" FOR OUTPUT AS #4
END IF
' This batch file will compile and view
' if nero waveedit and fbc are in your path.
OPEN "pavlov.bat" FOR OUTPUT AS #1
PRINT #1, "fbc -lang qb c:\basic\pavlov.bas"
PRINT #1, "pavlov.exe"
PRINT #1, "cd \sox"
PRINT #1, "sox -c 2 -r"; SampleRate; " -sw pavlov.raw pavlov.wav stat"
PRINT #1, "waveedit c:\sox\pavlov.wav"
CLOSE #1
OPEN "con" FOR APPEND AS #2
' Change con to your filename to scale numbers.
glide = 30
100
FOR g = 1 TO 79
READ note(1), note(2), length, rationame
PRINT #2, USING "DATA ####-,"; note(1) / 2;
PRINT #2, USING "####-,###"; note(2) / 2; length;
PRINT #2, USING ", &&&"; CHR$(34); rationame; CHR$(34)
' That is for feeding transpositions back into this code, although I
' am using a tuning that maps roughly to 12-TET, so I did not use
' it.
IF g > 0 THEN
' SOUND note(2) * harmonics(2), length
END IF
IF test = "0" THEN
IF note(1) = 0 AND LastNote(1) = 0 THEN
samples = SampleRate * length / BeatsPerSecond
GOSUB 300
GOTO 75
END IF
IF note(1) = 0 AND LastNote(1) <> 0 THEN
GOSUB 250
FOR k = 1 TO NumHarmonics
LastNote(k) = note(k)
NEXT k
samples = SampleRate * length / BeatsPerSecond
GOSUB 300
GOTO 75
END IF
IF LastNote(1) = 0 AND note(1) <> 0 THEN
FOR k = 1 TO NumHarmonics
LastNote(k) = note(k)
NEXT k
samples = SampleRate * length / BeatsPerSecond
GOSUB 275
GOTO 75
END IF
IF note(1) <> 0 AND LastNote(1) <> 0 THEN
samples = SampleRate * length / BeatsPerSecond
samples = samples / glide
GlideTrim = samples
GOSUB 300
samples = SampleRate * length / BeatsPerSecond
samples = samples - GlideTrim
FOR k = 1 TO NumHarmonics
LastNote(k) = note(k)
NEXT k
GOSUB 300
GOTO 75
END IF
END IF
75 NEXT g
CLOSE #4
END
' *Neat* Silencer -- finishes a wave like 275 starts one.
' When it reaches a peak or a trough, then it cuts amplitude in half
' and biases it by half.
250
FOR k = 1 TO NumHarmonics
temp = Angle(k) / TwoPi
Angle(k) = (temp - FIX(temp)) * TwoPi
IF Angle(k) > pi * 3 / 2 THEN
TerminalAngle(k) = pi * 3.5
PhaseDir(k) = 1
DropAngle(k) = pi * 2.5
ELSEIF Angle(k) > pi / 2 THEN
TerminalAngle(k) = pi * 2.5
PhaseDir(k) = 0
DropAngle(k) = pi * 3 / 2
ELSE
TerminalAngle(k) = pi * 3 / 2
PhaseDir(k) = -1
DropAngle(k) = pi / 2
END IF
NEXT k
260
FOR k = 1 TO NumHarmonics
Phase(k) = SIN(Angle(k))
SELECT CASE PhaseDir(k)
CASE 1
IF Angle(k) >= DropAngle(k) THEN
Phase(k) = Phase(k) / 2 + .5
END IF
CASE 0
IF Angle(k) >= DropAngle(k) THEN
Phase(k) = Phase(k) / 2 - .5
END IF
CASE -1
IF Angle(k) >= DropAngle(k) THEN
Phase(k) = Phase(k) / 2 + .5
END IF
END SELECT
IF Angle(k) < TerminalAngle(k) THEN
Angle(k) = Angle(k) + Velocity(k)
ELSE
Angle(k) = TerminalAngle(k)
END IF
NEXT k
GOSUB 400
FOR k = 1 TO NumHarmonics
IF Angle(k) < TerminalAngle(k) THEN GOTO 260
NEXT k
FOR k = 1 TO NumHarmonics
Angle(k) = Angle(k) - Angle(k)
NEXT k
RETURN
275
' This starts a wave from zero, using half the amplitude, a start
' from where sin(angle) = -1, and a bias of half. This cuts
' a leading click that I can hear on some equipment with some tunes.
FOR k = 1 TO NumHarmonics
Velocity(k) = TwoPi * LastNote(k) * harmonics(k) / SampleRate
Acceleration(k) = TwoPi * note(k) * harmonics(k) / SampleRate
Acceleration(k) = (Acceleration(k) - Velocity(k)) / samples
PhaseDir(k) = 1
Angle(k) = 3 / 2 * pi
NEXT k
280
FOR k = 1 TO NumHarmonics
IF PhaseDir(k) = 1 THEN
Phase(k) = SIN(Angle(k)) / 2 + .5
ELSE
Phase(k) = SIN(Angle(k))
END IF
Angle(k) = Angle(k) + Velocity(k)
Velocity(k) = Velocity(k) + Acceleration(k)
NEXT k
samples = samples - 1
GOSUB 400
FOR k = 1 TO NumHarmonics
IF PhaseDir(k) = 1 THEN
Phase(k) = (Phase(k) - .5) * 2
END IF
IF Phase(k) > SIN(Angle(k)) THEN
PhaseDir(k) = -1
END IF
NEXT k
FOR k = 1 TO NumHarmonics
IF PhaseDir(k) = 1 GOTO 280
NEXT k
300
' Calculate constants of change for write loop.
FOR k = 1 TO NumHarmonics
Velocity(k) = TwoPi * LastNote(k) * harmonics(k) / SampleRate
Acceleration(k) = TwoPi * note(k) * harmonics(k) / SampleRate
Acceleration(k) = (Acceleration(k) - Velocity(k)) / samples
NEXT k
' Main write loop. Static Phases problem solved at 250.
FOR t = 1 TO samples
FOR k = 1 TO NumHarmonics
Phase(k) = SIN(Angle(k))
NEXT k
GOSUB 400
FOR k = 1 TO NumHarmonics
Angle(k) = Angle(k) + Velocity(k)
Velocity(k) = Velocity(k) + Acceleration(k)
NEXT k
NEXT t
RETURN
400
' Write a sample.
amp = CINT(Phase(1) * 32000)
PRINT #4, CHR$(amp AND 255);
PRINT #4, CHR$((amp AND 65280) / 256);
amp = CINT(Phase(2) * 32000)
PRINT #4, CHR$(amp AND 255);
PRINT #4, CHR$((amp AND 65280) / 256);
RETURN
'
http://ecn.ab.ca/~brewhaha/Sound/
iJwEAQECAAYFAk8VmGAACgkQHjtqnNd0gPbtBQP9GLjOvYYuXsMJ0qMQ8PPNh0bK
zUZrNJphSO2A4hMmQLiCs2KKrNG3RBKtKJiQIzW8NIZZPdLxOELmvfqPjtf+jb1I
j7bKLMIQuA3x1ymCABZK2t+BEUPnI06h45xDqwMzA0U6BRypGh5efobZ3zicMcPU
TMXS5XWbrX2AoRmnEwk=
=1yK6
-----END PGP SIGNATURE-----