Dictionaries allow us to associate a value with a name (generally called a key). It's more general than that, but that's probably the most common use.
A common way to construct a dictionary to use the brace notation:
>>> d = {'one': 1, 'two': 2, 'three': 3}
>>> d
{'one': 1, 'three': 3, 'two': 2}
Notice that dictionaries are not ordered. That's fine, because they don't use numeric indices, they use keys.
As with lists, we can find out how many key-value pairs are in a dictionary using:
>>> len(d) 3
Accessing data in a dictionary is done similarly to lists:
>>> d['three'] 3
as is changing it:
>>> d['three'] = 'not3'
>>> d
{'one': 1, 'three': 'not3', 'two': 2}
Adding a key/value pair to a dictionary is the same as modifying one:
>>> d['four'] = 4
>>> d
{'four': 4, 'one': 1, 'two': 2, 'three': 'not3'}
To remove from a dictionary we use the del function:
>>> del(d['three'])
>>> d
{'four': 4, 'one': 1, 'two': 2}
Finally, we can check if a dictionary contains a specific key:
>>> 'one' in d True >>> 'three' not in d True >>> 'three' in d False
Formats - Songbook
So we have notes represented by tuples that we can put together in a list to make a song. What if we want multiple songs? We could have each in a separate variable. Let's add the additional requirement that we want to connect an I2C OLED display to show a list of songs that we can select from. Having songs in separate variables means that everything has to be hardcoded. That's seldom a good idea. What we'd like is to have things stored in such a way that we just have to add a song and have the menu automatically be updated to reflect it. We can do this by storing them in a dictionary, keyed by name (edited for brevity):
songbook = {'Twinkle Twinkle': [(C4, 0.5), (C4, 0.5), (G4, 0.5), (G4, 0.5), (A4, 0.5), ...],
'ItsyBitsy Spider': [(G4, 0.5), (C4, 0.5), (C4, 0.5), (C4, 0.5), (D4, 0.5), ...],
'Old MacDonald': [(G4, 0.5), (G4, 0.5), (G4, 0.5), (D4, 0.5), (E4, 0.5), ...]
}
With that done, we can get the names of the songs by songbook.keys(). This isn't a list, although it can be used for some list-like things. It can't be indexed, however. We need to convert it to a list in order to be able to do that: list(songbook.keys()). While we're at it, we should go ahead and sort it so that it will display in alphabetical order: sorted(list(songbook.keys())).
Here is the complete code:
# SPDX-FileCopyrightText: 2018 Dave Astels for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import time
import board
from adafruit_debouncer import Debouncer
import busio as io
import digitalio
import pwmio
import adafruit_ssd1306
i2c = io.I2C(board.SCL, board.SDA)
reset_pin = digitalio.DigitalInOut(board.D11)
oled = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c, reset=reset_pin)
select = digitalio.DigitalInOut(board.D7)
select.direction = digitalio.Direction.INPUT
select.pull = digitalio.Pull.UP
button_select = Debouncer(select)
play = digitalio.DigitalInOut(board.D9)
play.direction = digitalio.Direction.INPUT
play.pull = digitalio.Pull.UP
button_play = Debouncer(play)
C4 = 261
C_SH_4 = 277
D4 = 293
D_SH_4 = 311
E4 = 329
F4 = 349
F_SH_4 = 369
G4 = 392
G_SH_4 = 415
A4 = 440
A_SH_4 = 466
B4 = 493
# pylint: disable=line-too-long
songbook = {'Twinkle Twinkle': [(C4, 0.5), (C4, 0.5), (G4, 0.5), (G4, 0.5), (A4, 0.5), (A4, 0.5), (G4, 1.0), (0, 0.5),
(F4, 0.5), (F4, 0.5), (E4, 0.5), (E4, 0.5), (D4, 0.5), (D4, 0.5), (C4, 0.5), (0, 0.5),
(G4, 0.5), (G4, 0.5), (F4, 0.5), (F4, 0.5), (E4, 0.5), (E4, 0.5), (D4, 0.5), (0, 0.5),
(G4, 0.5), (G4, 0.5), (F4, 0.5), (F4, 0.5), (E4, 0.5), (E4, 0.5), (D4, 0.5), (0, 0.5),
(C4, 0.5), (C4, 0.5), (G4, 0.5), (G4, 0.5), (A4, 0.5), (A4, 0.5), (G4, 1.0), (0, 0.5),
(F4, 0.5), (F4, 0.5), (E4, 0.5), (E4, 0.5), (D4, 0.5), (D4, 0.5), (C4, 0.5), (0, 0.5)],
'ItsyBitsy Spider': [(G4, 0.5), (C4, 0.5), (C4, 0.5), (C4, 0.5), (D4, 0.5), (E4, 0.5), (E4, 0.5), (E4, 0.5), (D4, 0.5), (C4, 0.5), (D4, 0.5), (E4, 0.5), (C4, 0.5), (0, 0.5),
(E4, 0.5), (E4, 0.5), (F4, 0.5), (G4, 0.5), (G4, 0.5), (F4, 0.5), (E4, 0.5), (F4, 0.5), (G4, 0.5), (E4, 0.5), (0, 0.5)],
'Old MacDonald': [(G4, 0.5), (G4, 0.5), (G4, 0.5), (D4, 0.5), (E4, 0.5), (E4, 0.5), (D4, 0.5), (0, 0.5),
(B4, 0.5), (B4, 0.5), (A4, 0.5), (A4, 0.5), (G4, 0.5), (0, 0.5),
(D4, 0.5), (G4, 0.5), (G4, 0.5), (G4, 0.5), (D4, 0.5), (E4, 0.5), (E4, 0.5), (D4, 0.5), (0, 0.5),
(B4, 0.5), (B4, 0.5), (A4, 0.5), (A4, 0.5), (G4, 0.5), (0, 0.5),
(D4, 0.5), (D4, 0.5), (G4, 0.5), (G4, 0.5), (G4, 0.5), (D4, 0.5), (D4, 0.5), (G4, 0.5), (G4, 0.5), (G4, 0.5), (0, 0.5),
(G4, 0.5), (G4, 0.5), (G4, 0.5), (G4, 0.5), (G4, 0.5), (G4, 0.5), (0, 0.5),
(G4, 0.5), (G4, 0.5), (G4, 0.5), (G4, 0.5), (G4, 0.5), (G4, 0.5), (0, 0.5),
(G4, 0.5), (G4, 0.5), (G4, 0.5), (D4, 0.5), (E4, 0.5), (E4, 0.5), (D4, 0.5), (0, 0.5),
(B4, 0.5), (B4, 0.5), (A4, 0.5), (A4, 0.5), (G4, 0.5), (0, 0.5)]
}
# pylint: enable=line-too-long
def play_note(note):
if note[0] != 0:
pwm = pwmio.PWMOut(board.D12, duty_cycle = 0, frequency=note[0])
# Hex 7FFF (binary 0111111111111111) is half of the largest value for a 16-bit int,
# i.e. 50%
pwm.duty_cycle = 0x7FFF
time.sleep(note[1])
if note[0] != 0:
pwm.deinit()
def play_song(songname):
for note in songbook[songname]:
play_note(note)
def update(songnames, selected):
oled.fill(0)
line = 0
for songname in songnames:
if line == selected:
oled.text(">", 0, line * 8)
oled.text(songname, 10, line * 8)
line += 1
oled.show()
selected_song = 0
song_names = sorted(list(songbook.keys()))
while True:
button_select.update()
button_play.update()
update(song_names, selected_song)
if button_select.fell:
print("select")
selected_song = (selected_song + 1) % len(songbook)
elif button_play.fell:
print("play")
play_song(song_names[selected_song])
Page last edited January 22, 2025
Text editor powered by tinymce.