##### Driver & Library Initilisation ##### [ING] #####
from machine import Pin, PWM, Timer, I2C
from toneLib import allNotes, musicBoxDancer
import utime, os, array, sh1106
##### Configuration Options ##### [ING] #####
songSpeed = 120 #bpm for 4/4
oledPresent = True
##### Blinking LED Initilisation ##### [ING] #####
myLed = Pin("LED",Pin.OUT) # Raspberry Pi Pico W: built-in LED
LEDTimer = Timer()
def blink(LEDTimer):
myLed.value(0)
##### Display Initilisation ##### [ING] #####
if oledPresent:
i2c = machine.I2C(0,sda=machine.Pin(4),scl=machine.Pin(5), freq=2000000) # Around 3MHz is limit.
oled = sh1106.SH1106_I2C(128, 64, i2c, Pin(16), 0x3c, rotate=180)
oled.rotate=180
oled.sleep(False)
startLine = 0
leftMargin = 0
newLine = False
pageOfText = []
##### Routine to feed a line of text (keep to 16 long) ##### [Author: ING] #####
def updateDisplay(displayTimer):
global newLine, pageOfText
if oledPresent:
if newLine:
linePointer = 0
oled.fill(0)
for i in range(startLine,len(pageOfText)):
oled.text(pageOfText[i], leftMargin, linePointer)
linePointer += 10
oled.show()
newLine = False
##### Routine to process text lists so its ready for updateDisplay() ##### [Author: ING] #####
def oPrint(newText):
global pageOfText, newLine
numLines = len(pageOfText)
i=0
if numLines < 6:
pageOfText.append(newText)
else:
for i in range(0,numLines-1):
pageOfText[i] = pageOfText[i+1]
pageOfText[5]=newText
newLine = True
##### Music Initilisation ##### [Author: ING] #####
wholeNoteLength = (60/songSpeed)*4*1000 #for 4/4, in msecs.
noteTimer = Timer()
displayTimer = Timer()
playLength1 = 0
playLength2 = 0
stopNote1 = False
stopNote2 = False
playCounter1 = 100
playCounter2 = 100
getNextNote = True
noteNumber = 0 # start at the first note in array
note = musicBoxDancer[noteNumber]
mainVolume = 32000 # max of 32768 (max duty cycle)
pwm1 = machine.PWM(machine.Pin(18)) # buzzer 1 on pin GP18
pwm2 = machine.PWM(machine.Pin(20)) # buzzer 2 on pin GP20
songLength = len (musicBoxDancer)
print ('songLength =',songLength)
def tickNow(noteTimer):
global noteTicker
noteTicker = True
def play_poly_note(buzzNum, frequency, volume):
global pwm1, pwm2
frequencyHz = int (allNotes[frequency])
if buzzNum == 1:
if frequencyHz > 0:
pwm1.freq(frequencyHz)
pwm1.duty_u16(volume)
else:
pwm1.duty_u16(0) # rest
if buzzNum == 2:
if frequencyHz > 0:
pwm2.freq(frequencyHz)
pwm2.duty_u16(volume)
else:
pwm2.duty_u16(0) # rest
def stopProg():
while 1:
pwm1.deinit()
pwm2.deinit()
#################################
#### Main Start ##### [ING] #####
#################################
print(os.listdir('/'))
print('wholeNoteLength=', wholeNoteLength,'milliseconds')
printNotes = 0 #default is 0. printNotes = 1 for debugging code
LEDTimer.init(freq=5, mode=Timer.PERIODIC, callback=blink)
displayTimer.init(freq=3, mode=Timer.PERIODIC, callback=updateDisplay)
noteTimer.init(freq=100,mode=Timer.PERIODIC, callback=tickNow) # updateBuzzStates serviced every 10msec (100Hz)
noteTicker = False
barCounter = 0
decayVolume1 = 0
decayVolume2 = 0
decayRate = 1024
decayRateSlow = 128
#### Main Loop ##### [ING] #####
while 1:
if getNextNote:
myLed.value(1)
getNextNote = False
if (noteNumber == songLength):
oPrint('song finished')
stopProg()
note = musicBoxDancer[noteNumber]
if note[0] == 2: # buzzer 2
play_poly_note(2, note[1], mainVolume)
decayVolume2 = mainVolume
if printNotes:
print('playing ',noteNumber, note[1], 'on buzzer 2')
playLength2 = note[2]
noteNumber += 1 # advance and also play buzzer 1
note = musicBoxDancer[noteNumber]
if note[0] == 1: # buzzer 1
play_poly_note(1, note[1], mainVolume)
decayVolume1 = mainVolume
if printNotes:
print('playing ',noteNumber, note[1], 'on buzzer 1')
playLength1 = note[2]
if note[0] == 0: # print the line of text
if note[1] == 'Bar':
barCounter += 1
songString = note[1]+" "+str(barCounter)
else:
songString = note[1]
oPrint(songString)
noteNumber += 1
if noteTicker == True:
noteTicker = False
if playLength1 >0:
playCounter1 = wholeNoteLength/(10*playLength1)
if printNotes:
print ('for',playCounter1, 'ticks')
playLength1 = 0
else:
if playCounter1 > 0:
playCounter1 -= 1
#volume decay WIP:
decayVolume1 = pwm1.duty_u16() # get the current duty cycle
if printNotes:
print('Vol 1 is',decayVolume1)
if decayVolume1 < decayRate:
decayVolume1 = 0
else:
decayVolume1 -= decayRate
pwm1.duty_u16(decayVolume1)
else:
stopNote1 = True
if playLength2 >0:
playCounter2 = wholeNoteLength/(10*playLength2)
if printNotes:
print ('for',playCounter2, 'ticks')
playLength2 = 0
else:
if playCounter2 > 0:
playCounter2 -= 1
decayVolume2 = pwm2.duty_u16() # get the current duty cycle
if printNotes:
print('Vol 2 is',decayVolume2)
if decayVolume2 < decayRateSlow:
decayVolume2 = 0
else:
decayVolume2 -= decayRateSlow
pwm2.duty_u16(decayVolume2)
else:
stopNote2 = True
if stopNote1 == True:
stopNote1 = False
pwm1.duty_u16(0)
getNextNote = True
if stopNote2 == True:
stopNote2 = False
pwm2.duty_u16(0)
#### END ##### [ING] #####