Adafruit_Learning_System_Gu.../PyPortal_BusySimulator/code.py
2022-01-03 16:03:50 -06:00

231 lines
6.6 KiB
Python

# SPDX-FileCopyrightText: 2020 Tim C, written for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
"""
PyPortal implementation of Busy Simulator notification sound looper.
"""
import time
import board
import displayio
import adafruit_touchscreen
from adafruit_displayio_layout.layouts.grid_layout import GridLayout
from adafruit_displayio_layout.widgets.icon_widget import IconWidget
from audiocore import WaveFile
from audioio import AudioOut
# How many seconds to wait between playing samples
# Lower time means it will play faster
WAIT_TIME = 3.0
# List that will hold indexes of notification samples to play
LOOP = []
# last time that we played a sample
LAST_PLAY_TIME = 0
CUR_LOOP_INDEX = 0
# touch events must have at least this long between them
COOLDOWN_TIME = 0.25 # seconds
# last time that the display was touched
# used for debouncing and cooldown enforcement
LAST_PRESS_TIME = -1
# Was any icon touched last iteration.
# Used for debouncing.
WAS_TOUCHED = False
def next_index():
"""
return the next index in the LOOP that should get played
"""
if CUR_LOOP_INDEX + 1 >= len(LOOP):
return 0
return CUR_LOOP_INDEX + 1
# list of icons to show
# each entry is a tuple containing:
# (Icon Label, Icon BMP image file, Notification sample wav file
_icons = [
("Outlook", "icons/outlook.bmp", "sounds/outlook.wav"),
("Phone", "icons/phone.bmp", "sounds/phone.wav"),
("Skype", "icons/skype.bmp", "sounds/skype.wav"),
("Teams", "icons/teams.bmp", "sounds/teams.wav"),
("Discord", "icons/discord.bmp", "sounds/discord.wav"),
("Apple Mail", "icons/applemail.bmp", "sounds/applemail.wav"),
("iMessage", "icons/imessage.bmp", "sounds/imessage.wav"),
("Slack", "icons/slack.bmp", "sounds/slack.wav"),
("G Calendar", "icons/gcal.bmp", "sounds/RE.wav"),
("G Chat", "icons/gchat.bmp", "sounds/gchat.wav"),
("Stop", "icons/stop.bmp", ""),
]
# Make the display context.
display = board.DISPLAY
main_group = displayio.Group()
display.show(main_group)
# Touchscreen initialization
ts = adafruit_touchscreen.Touchscreen(
board.TOUCH_XL,
board.TOUCH_XR,
board.TOUCH_YD,
board.TOUCH_YU,
calibration=((5200, 59000), (5800, 57000)),
size=(display.width, display.height),
)
# Setup the file as the bitmap data source
bg_bitmap = displayio.OnDiskBitmap("busysim_background.bmp")
# Create a TileGrid to hold the bitmap
bg_tile_grid = displayio.TileGrid(
bg_bitmap,
pixel_shader=getattr(bg_bitmap, "pixel_shader", displayio.ColorConverter()),
)
# add it to the group that is showing
main_group.append(bg_tile_grid)
# grid to hold the icons
layout = GridLayout(
x=0,
y=0,
width=320,
height=240,
grid_size=(4, 3),
cell_padding=20,
)
# initialize the icons in the grid
for i, icon in enumerate(_icons):
icon_widget = IconWidget(
icon[0],
icon[1],
x=0,
y=0,
on_disk=True,
transparent_index=0,
label_background=0x888888,
)
layout.add_content(icon_widget, grid_position=(i % 4, i // 4), cell_size=(1, 1))
# add the grid to the group showing on the display
main_group.append(layout)
def check_for_touch(_now):
"""
Check the touchscreen and do any actions necessary if an
icon has been touched. Applies debouncing and cool down
enforcement to filter out unneeded touch events.
:param int _now: The current time in seconds. Used for cool down enforcement
"""
# pylint: disable=global-statement, too-many-nested-blocks, consider-using-enumerate
global CUR_LOOP_INDEX
global LOOP
global LAST_PRESS_TIME
global WAS_TOUCHED
# read the touch data
touch_point = ts.touch_point
# if anything is touched
if touch_point:
# if the touch just began. We ignore further events until
# after the touch has been lifted
if not WAS_TOUCHED:
# set the variable so we know to ignore future events until
# touch is released
WAS_TOUCHED = True
# if it has been long enough time since previous touch event
if _now - LAST_PRESS_TIME > COOLDOWN_TIME:
LAST_PRESS_TIME = time.monotonic()
# loop over the icons
for _ in range(len(_icons)):
# lookup current icon in the grid layout
cur_icon = layout.get_cell((_ % 4, _ // 4))
# check if it's being touched
if cur_icon.contains(touch_point):
print("icon {} touched".format(_))
# if it's the stop icon
if _icons[_][0] == "Stop":
# empty out the loop
LOOP = []
# set current index back to 0
CUR_LOOP_INDEX = 0
else: # any other icon
# insert the touched icons sample index into the loop
LOOP.insert(CUR_LOOP_INDEX, _)
# print(LOOP)
# break out of the for loop.
# if current icon is being touched then no others can be
break
# nothing is touched
else:
# set variable back to false for debouncing
WAS_TOUCHED = False
# main loop
while True:
# store current time in variable for cool down enforcement
_now = time.monotonic()
# check for and process touch events
check_for_touch(_now)
# if it's time to play a sample
if LAST_PLAY_TIME + WAIT_TIME <= _now:
# print("time to play")
# if there are any samples in the loop
if len(LOOP) > 0:
# open the sample wav file
with open(_icons[LOOP[CUR_LOOP_INDEX]][2], "rb") as wave_file:
print("playing: {}".format(_icons[LOOP[CUR_LOOP_INDEX]][2]))
# initialize audio output pin
audio = AudioOut(board.AUDIO_OUT)
# initialize WaveFile object
wave = WaveFile(wave_file)
# play it
audio.play(wave)
# while it's still playing
while audio.playing:
# update time variable
_now = time.monotonic()
# check for and process touch events
check_for_touch(_now)
# after done playing. deinit audio output
audio.deinit()
# increment index counter
CUR_LOOP_INDEX = next_index()
# update variable for last time we attempted to play sample
LAST_PLAY_TIME = _now