from machine import Pin, PWM, Timer
from time import sleep
INTER_TONES_GAP = 80
class Speakerpins:
def __init__(self, pins):
self.pins = pins
self.nextfree = 0
def nextPin(self):
if self.nextfree < len(self.pins):
pin = self.pins[self.nextfree]
self.nextfree += 1
return pin
else:
raise RuntimeError('Fehler: Keine weiteren Pins verfügbar.')
class Stimme:
noteNo = {'c':40, 'd':42, 'e':44, 'f':45, 'g':47, 'a':49, 'h':51, 'b':51,
'C':52, 'D':54, 'E':56, 'F':57, 'G':59, 'A':61, 'H':63, 'B':63, 'p':-22}
def __init__(self, pin, sound):
self.snd = sound
self.__stringPos = 0
self.oktave = 4
self.playing = True
self.noteNoDelta = 0
self.lp = PWM(Pin(pin))
self.lp.duty_u16(8000)
self.plying = True
def tonOff(self, event):
self.lp.deinit()
def setStimme(self, notenstring):
self.notenstring = notenstring
def frequency(self, n):
n += 12*(self.oktave-4)
n += self.noteNoDelta
self.noteNoDelta = 0
return round(440*2**((n-49)/12))
def setEndless(self):
self.endless = True
def wait(self):
self.plying = False
wt = True
while wt:
wt = False
for s in self.snd.stimmen:
if s.plying:
wt = True
self.plying = True
def halt(self):
self.playing = False
def replay(self):
self.playing = True
self.play()
def play(self, event=0):
if self.__stringPos < len(self.notenstring):
z = self.notenstring[self.__stringPos]
if z == '|':
self.wait()
self.__stringPos += 1
z = self.notenstring[self.__stringPos]
while not z in Stimme.noteNo:
if z in 'vV':
self.oktave -= 1
elif z == '^':
self.oktave += 1
elif z in '#+':
self.noteNoDelta = 1
elif z == '-':
self.noteNoDelta = -1
elif z == '@':
self.oktave = 4
elif z == ')':
self.oktave = 2
else:
print('Illegal character in notestring.')
return
self.__stringPos += 1
z = self.notenstring[self.__stringPos]
self.dur = self.snd.defaultLen
if self.__stringPos+1 < len(self.notenstring):
if self.notenstring[self.__stringPos+1] in '12468':
self.__stringPos += 1
self.dur = int(self.notenstring[self.__stringPos])
if self.dur == 6: self.dur = 16
if self.__stringPos+1 < len(self.notenstring):
if self.notenstring[self.__stringPos+1] =='.':
self.dur = 2*self.dur/3
self.__stringPos += 1
elif self.notenstring[self.__stringPos+1] == '.':
self.dur = 2*self.dur/3
self.__stringPos += 1
self.playLen = int(self.snd.lenx*self.snd.taktNenner/self.dur)
f = self.frequency(Stimme.noteNo[z])
if f<8:
self.lp.deinit()
else:
self.lp.freq(f)
Timer(period=self.playLen-INTER_TONES_GAP, mode=Timer.ONE_SHOT, callback=self.tonOff)
if self.playing:
Timer(period=self.playLen, mode=Timer.ONE_SHOT, callback=self.play)
self.__stringPos += 1
else:
if self.snd.endless:
self.__stringPos = 0
Timer(period=2000, mode=Timer.ONE_SHOT, callback=self.play)
class Sound:
btonarten = ['f-dur', 'd-moll', 'b-dur', 'g-moll', 'es-dur', 'c-moll', 'as-dur', 'f-moll',
'des-dur', 'b-moll', 'ges-dur', 'es-moll']
tonarten = ['c-dur', 'a-moll', 'g-dur', 'e-moll', 'd-dur', 'h-moll', 'a-dur', 'fis-moll', 'e-dur',
'cis-moll', 'h-dur', 'gis-moll', 'fis-dur', 'dis-moll', 'cis-dur', 'ais-moll']
def __init__(self, pins, tonart, speedPerTakt, defaultLen=4, taktZähler=4, taktNenner=4):
tonart = tonart.lower()
if not tonart in Sound.tonarten + Sound.btonarten:
print('Tonart unbekannt.')
return
self.pins = pins
self.tonart = tonart
self.speedPerTakt = speedPerTakt
self.defaultLen = defaultLen
self.taktZähler = taktZähler
self.taktNenner = taktNenner
self.lenx = speedPerTakt // taktZähler
self.endless = False
self.stimmen = []
def addStimme(self, notenstring):
pin = self.pins.nextPin()
stimme = Stimme(pin, self)
notenstring = self.clsBlank(notenstring)
notenstring = self.rep(notenstring)
notenstring = self.verschiebeNoten(notenstring)
stimme.setStimme(notenstring)
self.stimmen += [stimme]
def addTakt(self, pin):
self.takt = Takt(pin, self)
@staticmethod
def clsBlank(s):
while ' ' in s:
i = s.index(' ')
s = s[:i] + s[i+1:]
return s
@staticmethod
def quote(s, z, vz='#'):
pos = 0
while z in s[pos:].lower():
i = pos + s[pos:].lower().index(z)
s = s[:i] + vz + s[i:]
pos = i+2
return s
@staticmethod
def rep(s):
while '|:' in s and ':|' in s:
beg = s.index('|:')
end = s.index(':|')
if beg < end:
s = s[:beg] + s[beg+2:end]*2 + s[end+2:]
while ':|' in s:
end = s.index(':|')
s = s[:end]*2 + s[end+2:]
return s
def verschiebeNoten(self, notenstring):
if self.tonart in Sound.tonarten:
no = Sound.tonarten.index(self.tonart) // 2
if no >= 1:
notenstring = self.quote(notenstring, 'f')
if no >= 2:
notenstring = self.quote(notenstring, 'c')
if no >= 3:
notenstring = self.quote(notenstring, 'g')
if no >= 4:
notenstring = self.quote(notenstring, 'd')
if no >= 5:
notenstring = self.quote(notenstring, 'a')
if no >= 6: #sinnvoll?
notenstring = self.quote(notenstring, 'e')
if no >= 7: #sinnvoll?
notenstring = self.quote(notenstring, 'h')
else:
no = Sound.btonarten.index(self.tonart) // 2
notenstring = self.quote(notenstring, 'h', '-')
if no >= 1:
notenstring = self.quote(notenstring, 'e', '-')
if no >= 2:
notenstring = self.quote(notenstring, 'a', '-')
if no >= 3:
notenstring = self.quote(notenstring, 'd', '-')
if no >= 4:
notenstring = self.quote(notenstring, 'g', '-')
if no >= 5: #sinnvoll?
notenstring = self.quote(notenstring, 'c', '-')
return notenstring
def replay(self):
for stimme in self.stimmen:
stimme.replay()
def halt(self):
for stimme in self.stimmen:
stimme.halt()
def setEndless(self, endless=True):
self.endless = endless
def play(self):
for stimme in self.stimmen:
stimme.play()
####### Main
speakerpins = [0, 2, 4]
pins = Speakerpins(speakerpins)
s1 = '@ E4 E4#gCDE6g6Ch e4aCE4DC #g4#gCD4E4 C4a4a4p4'
s2 = '@ h4 E4hCDE6g6a#g a4aCE4DC h4hah4E4 C4a4a4p4'
s3 = ') p4 eEeEeEeE vaAaAaAaA #g#G#g#G#g#G#g#G aAaAaAH^C'
s1 += ' p DFA4GF E4.CE4DC h4 hCD4E4 C4a4a4p4'
s2 += 'vd^faC4ha g4.eg4fe #g4#gah4E4 C4a4a4p4'
s3 += ' d DdDdDdD cCcCcCcC hHhHhHhH aAaAaAaA^'
s1 += '|: E4 hCD4C h a4aCE4DC h4 hCD4E4 C4a4a4p4'
s2 += '|: E4#gCD4a#g e4aCE4DC #g4#gah4E4 C4a4a4p4'
s3 += '|: eEeEeEeE vaAaAaAaA #gG#gG#gG#gG aAaAaAH^C'
s1 += 'pD4FA4GF E4.CE4DC h4hCD4E4 C4a4a4p4 e2c2'
s2 += 'vd^f4aC4ha g4.eg4fe #g4#gah4E4 C4a4a4p4 c2va2'
s3 += ' d DdDdDdD cCcCcCcC eEeEeEeE aAaAaAaA aCaCaCaC'
s1 += 'd2vh2 C2a2 #g2h2 E2C2'
s2 += 'h2#g2 a2e2 e2g2 C2a2'
s3 += '#gE#gE#gE#gE aEaEaEaE #gE#gE#gE#gE aEaEaEaE'
s1 += 'D2h2 C4E4A4A4 #G1^'
s2 += 'h2#g2 a4C4E4E4 vh1^^'
s3 += '#gE#gE#gE#gE aEaAaAaA eEeEeEeE'
s1 += 'E4 hCD4C h a4aCE4DC h4 hCD4E4 C4a4a4p4'
s2 += 'E4#gCD4a#g e4aCE4DC #g4#gah4E4 C4a4a4p4'
s3 += 'eEeEeEeEv aAaAaAaA #gG#gG#gG#gG aAaAaAH^C'
s1 += ' p D4FA4GF E4.CE4DC h4 hCD4E4 C4a4a4p4 :|'
s2 += 'vd^f4aC4ha g4.eg4de #g4#gah4E4 C4a4a4p4 :|'
s3 += ' d DdDdDdD cCcCcCcC eEeEeEeE aAaAaAaA :|'
lied = Sound(pins, 'C-Dur', 1714, defaultLen=8)
lied.addStimme(s1)
lied.addStimme(s2)
lied.addStimme(s3)
lied.play()
#lied.setEndless()
#birth = Sound(pins, 'd-dur', 10000, taktZähler=3)
#birth.addStimme('a8a8 haD C2a8a8 haE D2a8a8 AFD8D8 ChG8G8 FDE D2')
#birth.addStimme('p fff g2p ggg f2p FDh agh8h8 afg f2')
#birth.play()