# writes tab scores for guitar
from winsound import *
from time import *
from Tkinter import *
nScaleFactor = 1.05946309436 # exp(log(2) / 12) # even temper diatonic
aListType = [1,2,3] # for type testing
nBarsPerLine = 4
lBeep = True # If true it will play through the built in speaker.
# otherwise it will search for associated wav files
# One file per note needed
cSoundsFolder = 'Guitar/'
class TabNote:
def __init__(self, nS, nF, nP, cFile):
self.nString = nS
self.nFret = nF
self.nScalePos = nP
self.nTone = int(440 * nScaleFactor ** (nP - 6)) # concert pitch
self.lPause = False
self.cSound = cSoundsFolder + cFile # wav file
def play(self, nI):
if lBeep:
Beep(self.nTone, nI) # milliseconds
else:
nStartTime = time()
PlaySound(self.cSound, SND_FILENAME + SND_ASYNC)
sleep(nI + nStartTime - time()) # seconds
def drawNote(self, canvas, nStart, aLines):
canvas.create_rectangle(nStart - 5, aLines[self.nString - 1] - 5, nStart + 5, aLines[self.nString - 1] + 5, width = 0,fill = 'white')
canvas.create_text(nStart, aLines[self.nString - 1], text = str(self.nFret))
class TabPause:
def __init__(self, nS, nF, nP, cFile):
self.nString = nS
self.nFret = nF
self.nScalePos = nP
self.lPause = True
self.nTone = 37
self.cSound = cSoundsFolder + cFile
def play(self, nI):
if lBeep:
sleep(nI / 1000) # milliseconds
else:
nStartTime = time()
PlaySound(self.cSound, SND_FILENAME + SND_ASYNC)
sleep(nI + nStartTime - time()) # seconds
def drawNote(self, canvas, nStart, aLines):
pass
def PlayNote(aB, nI):
nDelta = 0
if isinstance(aB, type(aListType)):
for i in aB:
nTime = time()
PlayNote(i, nI / len(aB) - nDelta)
nSpent = time() - nTime
nDelta = nSpent - nI / len(aB) # catchup if going too slowly
if nDelta < 0:
nDelta = 0
else:
aB.play(nI)
def PlayTune(aBars):
nDelta = 0
if lBeep:
nDuration = 1300 # beeps are in milliseconds
else:
nDuration = 1.5 # seconds per bar
for aB in aBars:
nTime = time()
PlayNote(aB, nDuration -nDelta)
nSpent = time() - nTime
nDelta = nSpent - nDuration # catchup if going too slowly
if nDelta < 0:
nDelta = 0
def DrawLines(canvas, nUp, nW, nLineH, nLineNo):
nStartX = nW * 0.1
nStopX = nW * 0.9
nLineUp = nLineH * 0.75 / 6 # six strings
nStartY = nUp + nLineUp
nStopY = nUp + 6 * nLineUp
nXStep = (nStopX - nStartX) / nBarsPerLine
aLineBox = []
aBarBox = []
for i in range(6):
canvas.create_line(nStartX, nUp + i * nLineUp + nLineUp, nStopX, nUp + i * nLineUp + nLineUp)
aLineBox.append( nUp + i * nLineUp + nLineUp)
for i in range(nBarsPerLine + 1):
canvas.create_line(nStartX + i * nXStep, nStartY, nStartX + i * nXStep, nStopY)
aBarBox.append([nStartX + i * nXStep, nXStep])
canvas.create_text(nStartX - 20,nUp + 1.5 * nLineUp, text = "T", font = ('Courier', 14,'bold'))
canvas.create_text(nStartX - 20,nUp + 3.5 * nLineUp, text = "A", font = ('Courier', 14,'bold'))
canvas.create_text(nStartX - 20,nUp + 5.5 * nLineUp, text = "B", font = ('Courier', 14,'bold'))
if nLineNo == 0: # time signature
canvas.create_text(nStartX - 10, nUp + 2.5 * nLineUp, text = "2", font = ('Courier', 14,'bold'))
canvas.create_text(nStartX - 10, nUp + 4.5 * nLineUp, text = "4", font = ('Courier', 14,'bold'))
return [aLineBox, aBarBox]
def PlaceNote(canvas, aB, nI, nStart, aLines):
if isinstance(aB, type(aListType)):
for i in aB:
PlaceNote(canvas, i, nI / len(aB), nStart, aLines)
nStart += nI / len(aB)
else:
aB.drawNote(canvas, nStart, aLines)
def PlaceParts(canvas, aPart, aBoxes):
nBarStep = 0
for i in aBoxes:
aLines = i[0]
for j in range(nBarsPerLine):
if len(aPart) <= nBarStep:
return
aB = aPart[nBarStep]
nBarStep = nBarStep + 1
nDuration = i[ 1][ j][ 1] * 0.95
nStart = i[1][ j][ 0] + nDuration * 0.1
for k in aB:
PlaceNote(canvas, k, nDuration/ len(aB), nStart, aLines)
nStart += nDuration/ len(aB)
# EADGBE tuning
dl = 0 # not needed here
dls = 0 # not needed here
p = TabPause(0,0,1,'Pause.wav') # pause
el = TabNote(6,0,1,'Elow.wav') # E low
fl = TabNote(6,1,2,'Flow.wav')
fls = TabNote(6,2,3,'FlowSharp.wav') # F low sharp
gl = TabNote(6,3,4,'Glow.wav')
gls = TabNote(6,4,5,'GlowSharp.wav')
al = TabNote(5,0,6,'Alow.wav')
blf = TabNote(5,1,7,'BlowFlat.wav') # B low flat
bl = TabNote(5,2,8,'Blow.wav')
cl = TabNote(5,3,9,'Clow.wav')
cls = TabNote(5,4,10,'ClowSharp.wav')
dm = TabNote(4,0,11,'Dmid.wav')
dms = TabNote(4,1,12,'DmidSharp.wav')
em = TabNote(4,2,13,'Emid.wav')
fm = TabNote(4,3,14,'Fmid.wav')
fms = TabNote(4,4,15,'FmidSharp.wav')
gm = TabNote(3,0,16,'Gmid.wav')
gms = TabNote(3,1,17,'GmidSharp.wav')
am = TabNote(3,2,18,'Amid.wav')
bmf = TabNote(3,3,19,'BmidFlat.wav')
bm = TabNote(2,0,20,'Bmid.wav')
bmAlt = TabNote(3,4,20,'Bmid.wav') # B middle Alternate fingering
cm = TabNote(2,1,21,'Cmid.wav')
cms = TabNote(2,2,22,'CmidSharp.wav')
d = TabNote(2,3,23,'D.wav')
ds = TabNote(2,4,24,'Dsharp.wav')
e = TabNote(1,0,25,'E.wav')
f = TabNote(1,1,26,'F.wav')
fs = TabNote(1,2,27,'FSharp.wav')
g = TabNote(1,3,28,'G.wav')
gs = TabNote(1,4,29,'GSharp.wav')
a = TabNote(1,5,30,'A.wav')
bf = TabNote(1,6,31,'BFlat.wav')
b = TabNote(1,7,32,'B.wav')
c = TabNote(1,8,33,'C.wav')
cs = TabNote(1,9,34,'CSharp.wav')
dh = TabNote(1,10,35,'Dhigh.wav')
dhs = TabNote(1,11,36,'DhighSharp.wav')
eh = TabNote(1,12,37,'Ehigh.wav') # E high
fh = TabNote(1,13,38,'Fhigh.wav')
fhs = TabNote(1,14,39,'FhighSharp.wav')
gh = TabNote(1,15,40,'Ghigh.wav')
ghs = TabNote(1,16,41,'gHighSharp.wav')
ah = TabNote(1,17,42,'Ahigh.wav')
bhf = TabNote(1,18,43,'BhignFlat.wav')
bh = TabNote(1,19,44,'Bhign.wav')
ch = TabNote(1,20,45,'Chigh.wav')
chs = TabNote(1,21,46,'ChignSharp.wav')
dd = TabNote(1,22,47,'DD.wav')
dds = TabNote(1,23,48,'DDsharp.wav')
aB1 = [[ el , e , el, fs] # First line Bar1 first part
,[ el , gm , el, am]] # second part
aB2 = [[ el , g , el, ds]
,[ el , bmf, el, am]]
aB3 = [[ el , e , el, fs]
,[ el , gm , el, am]]
aB4 = [[ el , g , el, ds]
,[ el , bmf, el, am]]
aB5 = [[ el ,[g,e] ,g , fs] # second line
,[ el ,bl ,el , al]]
aB6 = [[ds ,e ,[d,d], d] # << recursive tree structure
,[fls ,gl ,el , bl]]
aB7 = [[[cms,cms],cms ,[cm,cm], cm]
,[el ,blf ,el , al]]
aB8 = [[[bm,e] ,[cm,e],bm , p]
,[el ,al ,el ,[cl,bl]]]
aB9 = [[p ,[gm,em],gm ,fms]
,[blf ,al ]]
aB10 = [[cm ,bm ,[g,g], g]
,[gl ,em ,bmf , em]]
aB11 = [[[fs,fs] ,fs ,[e,e], e]
,[bl ,fms ,cls , fms]]
aB12 = [[[ds,fs] ,[e,fs] ,ds , p]
,[bl ,cl ,bl , [gl,fls]]]
aB13 = [[el ,[g,e] ,g ,fs]
,[el ,bm ,el ,am]]
aB14 = [[ds ,e ,[d,d] ,d]
,[fms ,gm ,em ,bmAlt]]
aB15 = [[[cms,cms],cms ,[cm,cm],cm]
,[em ,bmf ,em ,am]]
aB16 = [[[bm ,e] ,[cm,e],bm ,p]
,[em ,am ,em ,[em,dm]]]
aB17 = [[p , [e,cms] , e , ds]
,[cls , fms]]
aB18 = [[p , [d ,bm] , d , cms]
,[bl , el]]
aB19 = [[p , [cm,am] , cm , bm]
,[al , dm]]
aB20 = [[p , [dms,bm], em, p]
,[gl , fls , el, p]]
aFirstPart = [aB1[0],aB2[0],aB3[0],aB4[0],aB5[0],aB6[0],aB7[0],aB8[0],aB9[0]
,aB10[0],aB11[0],aB12[0],aB13[0],aB14[0],aB15[0],aB16[0],aB17[0]
,aB18[0],aB19[0],aB20[0]]
aSecondPart = [aB1[1],aB2[1],aB3[1],aB4[1],aB5[1],aB6[1],aB7[1],aB8[1],aB9[1]
,aB10[1],aB11[1],aB12[1],aB13[1],aB14[1],aB15[1],aB16[1],aB17[1]
,aB18[1],aB19[1],aB20[1]]
# Unfortunately I cant work out a way to play both parts together using Beep,
# unless you use two computers.
# However if you are using PlaySound
#,( you will also need the associated sound files)
# You can make a second copy of the program (rename it SugarSecondPart)
# to play the second part alongside the first
# The section of code below will syncronise the two parts.
if not(lBeep):
while (int(time()) % 10 == 0):
sleep(1)
t = int(time()) % 10
while t % 10 <> 0:
t = int(time())
print 'syncronising', t % 10
print 'Playing first part'
PlayTune(aFirstPart)
#sleep(2)
#print 'Playing second part'
#PlayTune(aSecondPart)
nW = 1400
nH = 800
canvas = Canvas( width = nW, height = nH, bg = 'white')
canvas.pack(expand = YES, fill = BOTH)
aBoxes = []
nW = nW * 0.75
nLines = (len(aFirstPart) + 0.0) / nBarsPerLine
if int(nLines) <> nLines:
nLines = int(nLines + 1)
nLineStep = nH * 0.8 / nLines # 5 lines
canvas.create_text( 300, 50, text = 'SugarPlumFairy', font = ('Arial', 20, 'bold'))
for i in range(nLines):
aBoxes.append(DrawLines(canvas, nLineStep * i + 100, nW, nLineStep * 0.75, i))
PlaceParts(canvas, aFirstPart, aBoxes)
PlaceParts(canvas, aSecondPart, aBoxes)