first commit Walkmp3rson code and assets
This commit is contained in:
parent
e426cc1ac9
commit
d1f7f64ebe
6 changed files with 227 additions and 0 deletions
BIN
Walkmp3rson/TAPE1/01_Bartlebeats_Carpeter_.mp3
Executable file
BIN
Walkmp3rson/TAPE1/01_Bartlebeats_Carpeter_.mp3
Executable file
Binary file not shown.
BIN
Walkmp3rson/TAPE1/02_Bartlebeats_Small_Selective_.mp3
Executable file
BIN
Walkmp3rson/TAPE1/02_Bartlebeats_Small_Selective_.mp3
Executable file
Binary file not shown.
BIN
Walkmp3rson/TAPE1/03_Bartlebeats_Daisy_.mp3
Executable file
BIN
Walkmp3rson/TAPE1/03_Bartlebeats_Daisy_.mp3
Executable file
Binary file not shown.
BIN
Walkmp3rson/TAPE1/04_Bartlebeats_Clay Guys_.mp3
Executable file
BIN
Walkmp3rson/TAPE1/04_Bartlebeats_Clay Guys_.mp3
Executable file
Binary file not shown.
227
Walkmp3rson/code.py
Normal file
227
Walkmp3rson/code.py
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
# SPDX-FileCopyrightText: 2022 John Park and Tod Kurt for Adafruit Industries
|
||||
# SPDX-License-Identifier: MIT
|
||||
# Walkmp3rson digital cassette tape player (ok fine it's just SD cards)
|
||||
import time
|
||||
import os
|
||||
import board
|
||||
import busio
|
||||
import sdcardio
|
||||
import storage
|
||||
import audiomixer
|
||||
import audiobusio
|
||||
import audiomp3
|
||||
from adafruit_neokey.neokey1x4 import NeoKey1x4
|
||||
from adafruit_seesaw import seesaw, rotaryio
|
||||
import displayio
|
||||
import terminalio
|
||||
from adafruit_display_text import label
|
||||
from adafruit_st7789 import ST7789
|
||||
from adafruit_progressbar.progressbar import HorizontalProgressBar
|
||||
from adafruit_progressbar.verticalprogressbar import VerticalProgressBar
|
||||
|
||||
|
||||
displayio.release_displays()
|
||||
|
||||
# SPI for TFT display, and SD Card reader on TFT display
|
||||
spi = board.SPI()
|
||||
# display setup
|
||||
tft_cs = board.D6
|
||||
tft_dc = board.D9
|
||||
tft_reset = board.D12
|
||||
display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=tft_reset)
|
||||
display = ST7789(display_bus, width=320, height=240, rotation=90)
|
||||
|
||||
# SD Card setup
|
||||
sd_cs = board.D13
|
||||
sdcard = sdcardio.SDCard(spi, sd_cs)
|
||||
vfs = storage.VfsFat(sdcard)
|
||||
storage.mount(vfs, "/sd")
|
||||
|
||||
# I2C NeoKey setup
|
||||
i2c = busio.I2C(board.SCL, board.SDA)
|
||||
neokey = NeoKey1x4(i2c, addr=0x30)
|
||||
amber = 0x300800
|
||||
red = 0x900000
|
||||
green = 0x009000
|
||||
|
||||
neokey.pixels.fill(amber)
|
||||
keys = [
|
||||
(neokey, 0, green),
|
||||
(neokey, 1, red),
|
||||
(neokey, 2, green),
|
||||
(neokey, 3, green),
|
||||
]
|
||||
# states for key presses
|
||||
key_states = [False, False, False, False]
|
||||
|
||||
# STEMMA QT Rotary encoder setup
|
||||
rotary_seesaw = seesaw.Seesaw(i2c, addr=0x37) # default address is 0x36
|
||||
encoder = rotaryio.IncrementalEncoder(rotary_seesaw)
|
||||
last_encoder_pos = 0
|
||||
|
||||
# file system setup
|
||||
mp3s = []
|
||||
for filename in os.listdir('/sd'):
|
||||
if filename.lower().endswith('.mp3') and not filename.startswith('.'):
|
||||
mp3s.append("/sd/"+filename)
|
||||
|
||||
mp3s.sort() # sort alphanumerically for mixtape order, e.g., "1_King_of_Rock.mp3"
|
||||
for mp3 in mp3s:
|
||||
print(mp3)
|
||||
|
||||
track_number = 0
|
||||
mp3_filename = mp3s[track_number]
|
||||
mp3_bytes = os.stat(mp3_filename)[6] # size in bytes is position 6
|
||||
mp3_file = open(mp3_filename, "rb")
|
||||
mp3stream = audiomp3.MP3Decoder(mp3_file)
|
||||
|
||||
def tracktext(full_path_name, position):
|
||||
return full_path_name.split('_')[position].split('.')[0]
|
||||
|
||||
audio = audiobusio.I2SOut(bit_clock=board.D1, word_select=board.D10, data=board.D11)
|
||||
mixer = audiomixer.Mixer(voice_count=1, sample_rate=22050, channel_count=1,
|
||||
bits_per_sample=16, samples_signed=True)
|
||||
mixer.voice[0].level = 0.15
|
||||
audio.play(mixer)
|
||||
|
||||
# Colors
|
||||
blue_bright = 0x17afcf
|
||||
blue_mid = 0x0d6173
|
||||
blue_dark = 0x041f24
|
||||
|
||||
orange_bright = 0xda8c57
|
||||
orange_mid = 0xa46032
|
||||
orange_dark = 0x472a16
|
||||
|
||||
# display
|
||||
main_display_group = displayio.Group() # everything goes in main group
|
||||
display.show(main_display_group) # show main group (clears screen, too)
|
||||
|
||||
# background bitmap w OnDiskBitmap
|
||||
tape_bitmap = displayio.OnDiskBitmap(open("mp3_tape.bmp", "rb"))
|
||||
tape_tilegrid = displayio.TileGrid(tape_bitmap, pixel_shader=tape_bitmap.pixel_shader)
|
||||
main_display_group.append(tape_tilegrid)
|
||||
|
||||
|
||||
# song name label
|
||||
song_name_text_group = displayio.Group(scale=3, x=90, y=44) # text label goes in this Group
|
||||
song_name_text = tracktext(mp3_filename, 2)
|
||||
song_name_label = label.Label(terminalio.FONT, text=song_name_text, color=orange_bright)
|
||||
song_name_text_group.append(song_name_label) # add the label to the group
|
||||
main_display_group.append(song_name_text_group) # add to the parent group
|
||||
|
||||
# artist name label
|
||||
artist_name_text_group = displayio.Group(scale=2, x=92, y=186)
|
||||
artist_name_text = tracktext(mp3_filename, 1)
|
||||
artist_name_label = label.Label(terminalio.FONT, text=artist_name_text, color=orange_bright)
|
||||
artist_name_text_group.append(artist_name_label)
|
||||
main_display_group.append(artist_name_text_group)
|
||||
|
||||
# song progress bar
|
||||
progress_bar = HorizontalProgressBar(
|
||||
(72, 144),
|
||||
(174, 12),
|
||||
bar_color=blue_bright,
|
||||
outline_color=blue_mid,
|
||||
fill_color=blue_dark,
|
||||
)
|
||||
main_display_group.append(progress_bar)
|
||||
|
||||
# volume level bar
|
||||
volume_bar = VerticalProgressBar(
|
||||
(304, 40),
|
||||
(8, 170),
|
||||
bar_color=orange_bright,
|
||||
outline_color=orange_mid,
|
||||
fill_color=orange_dark,
|
||||
)
|
||||
main_display_group.append(volume_bar)
|
||||
volume_bar.value = mixer.voice[0].level * 100
|
||||
|
||||
def change_track(tracknum):
|
||||
# pylint: disable=global-statement
|
||||
global mp3_filename
|
||||
mp3_filename = mp3s[tracknum]
|
||||
song_name_fc = tracktext(mp3_filename, 2)
|
||||
artist_name_fc = tracktext(mp3_filename, 1)
|
||||
mp3_file_fc = open(mp3_filename, "rb")
|
||||
mp3stream_fc = audiomp3.MP3Decoder(mp3_file_fc)
|
||||
mp3_bytes_fc = os.stat(mp3_filename)[6] # size in bytes is position 6
|
||||
# print(mp3_bytes)
|
||||
# print("Now playing: '{}'".format(mp3_filename))
|
||||
return (mp3_file_fc, mp3stream_fc, song_name_fc, artist_name_fc, mp3_bytes_fc)
|
||||
|
||||
print("Walkmp3rson")
|
||||
play_state = False # so we know if we're auto advancing when mixer finishes a song
|
||||
last_debug_time = 0 # for timing track position
|
||||
reels_anim_frame = 0
|
||||
last_percent_done = 0.01
|
||||
|
||||
while True:
|
||||
encoder_pos = -encoder.position
|
||||
if encoder_pos != last_encoder_pos:
|
||||
encoder_delta = encoder_pos - last_encoder_pos
|
||||
volume_adjust = min(max((mixer.voice[0].level + (encoder_delta*0.005)), 0.0), 1.0)
|
||||
mixer.voice[0].level = volume_adjust
|
||||
|
||||
last_encoder_pos = encoder_pos
|
||||
volume_bar.value = mixer.voice[0].level * 100
|
||||
|
||||
if play_state is True: # if not stopped, auto play next mp3_filename
|
||||
if time.monotonic() - last_debug_time > 0.2: # so we can check track progress
|
||||
last_debug_time = time.monotonic()
|
||||
bytes_played = mp3_file.tell()
|
||||
percent_done = (bytes_played / mp3_bytes)
|
||||
progress_bar.value = min(max(percent_done * 100, 0), 100)
|
||||
|
||||
if not mixer.playing:
|
||||
print("next song")
|
||||
track_number = ((track_number + 1) % len(mp3s))
|
||||
mp3_file, mp3stream, song_name, artist_name, mp3_bytes = change_track(track_number)
|
||||
song_name_label.text = song_name
|
||||
artist_name_label.text = artist_name
|
||||
mixer.voice[0].play(mp3stream, loop=False)
|
||||
|
||||
# Use the NeoKeys as transport controls
|
||||
for k in range(len(keys)):
|
||||
neokey, key_number, color = keys[k]
|
||||
if neokey[key_number] and not key_states[key_number]:
|
||||
key_states[key_number] = True
|
||||
neokey.pixels[key_number] = color
|
||||
|
||||
if key_number == 0: # previous track
|
||||
track_number = ((track_number - 1) % len(mp3s) )
|
||||
mp3_file, mp3stream, song_name, artist_name, mp3_bytes = change_track(track_number)
|
||||
song_name_label.text = song_name
|
||||
artist_name_label.text = artist_name
|
||||
audio.resume()
|
||||
mixer.voice[0].play(mp3stream, loop=False)
|
||||
play_state = True
|
||||
|
||||
if key_number == 1: # Play/pause
|
||||
if play_state:
|
||||
audio.pause()
|
||||
play_state = False
|
||||
else:
|
||||
audio.resume()
|
||||
play_state = True
|
||||
|
||||
if key_number == 2: # Play track from beginning
|
||||
audio.resume()
|
||||
mixer.voice[0].play(mp3stream, loop=False)
|
||||
song_name_label.text = tracktext(mp3_filename, 2)
|
||||
artist_name_label.text = tracktext(mp3_filename, 1)
|
||||
play_state = True
|
||||
|
||||
if key_number == 3: # next track
|
||||
track_number = ((track_number + 1) % len(mp3s))
|
||||
mp3_file, mp3stream, song_name, artist_name, mp3_bytes = change_track(track_number)
|
||||
song_name_label.text = song_name
|
||||
artist_name_label.text = artist_name
|
||||
audio.resume()
|
||||
mixer.voice[0].play(mp3stream, loop=False)
|
||||
play_state = True
|
||||
|
||||
if not neokey[key_number] and key_states[key_number]:
|
||||
neokey.pixels[key_number] = amber
|
||||
key_states[key_number] = False
|
||||
BIN
Walkmp3rson/mp3_tape.bmp
Executable file
BIN
Walkmp3rson/mp3_tape.bmp
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 75 KiB |
Loading…
Reference in a new issue