Skip to content

Commit 7172849

Browse files
authored
Merge pull request #3190 from adafruit/duplo_boombox
adding code and mp3 files for duplo color boombox
2 parents 047e5ec + 3ed0272 commit 7172849

16 files changed

Lines changed: 171 additions & 0 deletions

File tree

Duplo_Color_Boombox/code.py

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
# SPDX-FileCopyrightText: 2026 Liz Clark for Adafruit Industries
2+
# SPDX-License-Identifier: MIT
3+
4+
"""Duplo Color Boombox"""
5+
6+
import board
7+
import sdcardio
8+
import storage
9+
import audiobusio
10+
import audiomixer
11+
import audiomp3
12+
from digitalio import DigitalInOut, Direction
13+
from adafruit_as7341 import AS7341
14+
from adafruit_seesaw import digitalio, neopixel, rotaryio, seesaw
15+
16+
#Power Setup
17+
external_power = DigitalInOut(board.EXTERNAL_POWER)
18+
external_power.direction = Direction.OUTPUT
19+
external_power.value = True
20+
21+
#SD Card setup
22+
23+
spi = board.SPI()
24+
cs = board.D10
25+
sdcard = sdcardio.SDCard(spi, cs)
26+
vfs = storage.VfsFat(sdcard)
27+
storage.mount(vfs, "/sd", readonly=True)
28+
29+
#Audio
30+
mp3 = audiomp3.MP3Decoder(open("/sd/blue.mp3", "rb"))
31+
32+
i2s = audiobusio.I2SOut(board.I2S_BIT_CLOCK, board.I2S_WORD_SELECT, board.I2S_DATA)
33+
mixer = audiomixer.Mixer(voice_count=1, sample_rate=mp3.sample_rate, channel_count=1,
34+
bits_per_sample=mp3.bits_per_sample)
35+
i2s.play(mixer)
36+
mixer.voice[0].level = 0.5
37+
38+
#Color Sensor
39+
i2c = board.STEMMA_I2C()
40+
sensor = AS7341(i2c)
41+
sensor.led_current = 4 # increments in units of 4
42+
sensor.led = False
43+
44+
brick_dictionary = [
45+
{'song': "/sd/blue.mp3", 'value': (1619, 13852, 19215, 18562, 12912, 8818, 9512, 5440),
46+
'color': ((0, 255, 255))},
47+
{'song': "/sd/orange.mp3", 'value': (2517, 3983, 5661, 6864, 16857, 39049, 55151, 35696),
48+
'color': ((255, 60, 0))},
49+
{'song': "/sd/coral.mp3", 'value': (3004, 6712, 7499, 7160, 13858, 46007, 65535, 39278),
50+
'color': ((250, 50, 50))},
51+
{'song': "/sd/purple.mp3", 'value': (2562, 20704, 19222, 15806, 16624, 18399, 27316, 22525),
52+
'color': ((125, 0, 255))},
53+
{'song': "/sd/red.mp3", 'value': (1453, 2629, 4050, 4656, 5527, 13403, 31096, 21368),
54+
'color': ((255, 0, 0))},
55+
{'song': "/sd/yellow.mp3", 'value': (3051, 4446, 8633, 17412, 37450, 48224, 56249, 34726),
56+
'color': ((255, 150, 0))},
57+
{'song': "/sd/butter.mp3", 'value': (4102, 8631, 13692, 29000, 58147, 63230, 65535, 43143),
58+
'color': ((255, 255, 0))},
59+
{'song': "/sd/green.mp3", 'value': (1383, 2767, 5850, 12964, 22118, 16304, 12669, 7008),
60+
'color': ((120, 255, 0))},
61+
{'song': "/sd/lime.mp3", 'value': (3017, 8109, 17948, 36761, 48754, 38009, 31671, 19457),
62+
'color': ((150, 255, 0))},
63+
{'song': "/sd/lightblue.mp3", 'value': (4188, 29507, 42326, 53214, 54067, 37512, 34129, 23544),
64+
'color':((100, 250, 255))},
65+
{'song': "/sd/white.mp3", 'value': (5246, 27506, 33883, 44702, 62766, 64254, 65535, 48334),
66+
'color':((255, 255, 255))},
67+
]
68+
69+
def find_closest_brick(reading, dictionary, max_distance=50000):
70+
"""
71+
Find the brick with the closest matching sensor values.
72+
73+
Args:
74+
new_reading: Tuple of 8 sensor values
75+
brick_dictionary: List of brick dictionaries
76+
max_distance: Maximum distance to consider a valid match
77+
78+
Returns:
79+
Tuple of (matched_brick, distance) or (None, distance) if no good match
80+
"""
81+
best_match = None
82+
best_distance = float('inf')
83+
84+
for brick in dictionary:
85+
# Calculate total distance (sum of absolute differences)
86+
distance = sum(abs(v1 - v2) for v1, v2 in zip(reading, brick['value']))
87+
88+
if distance < best_distance:
89+
best_distance = distance
90+
best_match = brick
91+
92+
# Only return a match if it's close enough
93+
if best_distance > max_distance:
94+
return None
95+
96+
return best_match
97+
98+
#Rotary STEMMA I2C
99+
seesaw = seesaw.Seesaw(i2c, 0x36)
100+
encoder = rotaryio.IncrementalEncoder(seesaw)
101+
seesaw.pin_mode(24, seesaw.INPUT_PULLUP)
102+
switch = digitalio.DigitalIO(seesaw, 24)
103+
switch_state = False
104+
105+
pixel = neopixel.NeoPixel(seesaw, 6, 1)
106+
pixel.brightness = 1
107+
pixel.fill((0, 0, 0))
108+
109+
last_position = -1
110+
volume = 0.5 # volume
111+
play = False
112+
play_state = False
113+
114+
mp3 = audiomp3.MP3Decoder(open("/sd/boot.mp3", "rb"))
115+
mixer.voice[0].play(mp3, loop=False)
116+
117+
while True:
118+
119+
# make clockwise rotation positive
120+
position = -encoder.position
121+
122+
if position != last_position:
123+
if position > last_position:
124+
#decrease volume
125+
volume = volume - 0.05
126+
volume = max(volume, 0)
127+
else:
128+
#increase volume
129+
volume = volume + 0.05
130+
volume = min(volume, 1)
131+
# set the audio volume
132+
mixer.voice[0].level = volume
133+
print(volume)
134+
last_position = position
135+
136+
if not switch.value and not switch_state:
137+
print("Button pressed")
138+
switch_state = True
139+
if not play:
140+
sensor.led = True
141+
sensor_color = sensor.all_channels
142+
matched_brick = find_closest_brick(sensor_color, brick_dictionary)
143+
print(sensor_color)
144+
if matched_brick is not None:
145+
print(matched_brick['song'])
146+
mp3 = audiomp3.MP3Decoder(open(matched_brick['song'], "rb"))
147+
pixel.fill(matched_brick['color'])
148+
play = True
149+
mixer.voice[0].play(mp3, loop=False)
150+
play_state = True
151+
else:
152+
print("insert brick")
153+
mp3 = audiomp3.MP3Decoder(open("/sd/uhoh.mp3", "rb"))
154+
mixer.voice[0].play(mp3, loop=False)
155+
else:
156+
if play_state:
157+
i2s.pause()
158+
play_state = False
159+
else:
160+
i2s.resume()
161+
play_state = True
162+
163+
if switch.value and switch_state:
164+
sensor.led = False
165+
switch_state = False
166+
print("Button released")
167+
168+
if not mixer.playing:
169+
play_state = False
170+
play = False
171+
pixel.fill((0,0,0))

Duplo_Color_Boombox/sd/blue.mp3

12 KB
Binary file not shown.

Duplo_Color_Boombox/sd/boot.mp3

14 KB
Binary file not shown.

Duplo_Color_Boombox/sd/brown.mp3

444 KB
Binary file not shown.

Duplo_Color_Boombox/sd/butter.mp3

818 KB
Binary file not shown.

Duplo_Color_Boombox/sd/coral.mp3

623 KB
Binary file not shown.

Duplo_Color_Boombox/sd/green.mp3

13.4 KB
Binary file not shown.

Duplo_Color_Boombox/sd/grey.mp3

433 KB
Binary file not shown.
724 KB
Binary file not shown.

Duplo_Color_Boombox/sd/lime.mp3

643 KB
Binary file not shown.

0 commit comments

Comments
 (0)