Welcome, guest | Sign In | My Account | Store | Cart
# 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)

History