Skip to content

ASCII Bell support and Fruit Jam example #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 33 additions & 2 deletions adafruit_color_terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
`adafruit_color_terminal`
================================================================================

Extension of supports ANSI color escapes for subsets of text
Extension of supports ANSI color escapes for subsets of text and optionally the
ASCII bell escape code.


* Author(s): Tim Cocks
Expand All @@ -28,6 +29,7 @@
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Color_Terminal.git"

from audiocore import WaveFile
from displayio import Palette, TileGrid
from terminalio import Terminal
from tilepalettemapper import TilePaletteMapper
Expand Down Expand Up @@ -63,9 +65,20 @@ class ColorTerminal:
:param height: The height of the terminal in characters.
:param custom_palette: A custom palette of colors to use instead of the default ones.
Must contain at least 9 colors.
:param audio_interface: The audio interface to use for playing ASCII bell escape codes.
:param bell_audio_file: The wave audio file to use for the ASCII bell escape codes.
Defaults to beep.wav
"""

def __init__(self, font, width, height, custom_palette=None):
def __init__(
self,
font,
width,
height,
custom_palette=None,
audio_interface=None,
bell_audio_file="/beep.wav",
):
if custom_palette is None:
self.terminal_palette = Palette(9)
self.terminal_palette[0] = 0x000000
Expand Down Expand Up @@ -99,6 +112,11 @@ def __init__(self, font, width, height, custom_palette=None):

self.cur_color_mapping = [0, 1]

self.audio_interface = audio_interface
if audio_interface is not None:
beep_wave_file = open(bell_audio_file, "rb")
self.beep_wave = WaveFile(beep_wave_file)

@staticmethod
def parse_ansi_colors(text):
"""
Expand Down Expand Up @@ -195,6 +213,13 @@ def write(self, s):

if not color_map:
self.terminal.write(s)
if (
"\x07" in s
and self.audio_interface is not None
and not self.audio_interface.playing
):
print("playing beep")
self.audio_interface.play(self.beep_wave)
return

idx = 0
Expand Down Expand Up @@ -222,6 +247,12 @@ def write(self, s):

self.apply_color(cur_slice)
self.terminal.write(cur_slice)
if (
"\x07" in cur_slice
and self.audio_interface is not None
and not self.audio_interface.playing
):
self.audio_interface.play(self.beep_wave)

# index after last can be in the color map if color code is last thing in string
if idx in color_map:
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
# Uncomment the below if you use native CircuitPython modules such as
# digitalio, micropython and busio. List the modules you use. Without it, the
# autodoc module docs will fail to generate with a warning.
autodoc_mock_imports = ["terminalio", "tilepalettemapper", "displayio"]
autodoc_mock_imports = ["terminalio", "tilepalettemapper", "displayio", "audiocore"]

autodoc_preserve_defaults = True

Expand Down
Binary file added examples/beep.wav
Binary file not shown.
3 changes: 3 additions & 0 deletions examples/beep.wav.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
71 changes: 71 additions & 0 deletions examples/color_terminal_fruit_jam_belltest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import time

import supervisor
from adafruit_fruitjam import peripherals
from displayio import Group
from terminalio import FONT

from adafruit_color_terminal import ColorTerminal

main_group = Group()

display = supervisor.runtime.display
if display is None or peripherals.get_display_config()[2] < 4:
print(
"To use ColorTerminal there must be an initialized display with a color depth at least 4."
)
print(
"Initializing display to default size 640x480 with color depth 8, ",
"if you do not want this configuration then initialize the display ",
"before running this example.",
)
peripherals.request_display_config(640, 480, 8)

fruitjam_peripherals = peripherals.Peripherals()

fruitjam_peripherals.dac.headphone_output = True
fruitjam_peripherals.dac.configure_clocks(sample_rate=16000, bit_depth=16)

font_bb = FONT.get_bounding_box()
screen_size = (display.width // font_bb[0], display.height // font_bb[1])

terminal = ColorTerminal(
FONT, screen_size[0], screen_size[1], audio_interface=fruitjam_peripherals.audio
)
main_group.append(terminal.tilegrid)

black = chr(27) + "[30m"
red = chr(27) + "[31m"
green = chr(27) + "[32m"
yellow = chr(27) + "[33m"
blue = chr(27) + "[34m"
magenta = chr(27) + "[35m"
cyan = chr(27) + "[36m"
white = chr(27) + "[37m"
reset = chr(27) + "[0m"


message = f"Hello {green}World{reset} {yellow}ANSI\n"
terminal.write(message)
print(message, end="")

message = f"{magenta}Terminal {red}Colors{reset}"
terminal.write(message)
print(message)

display.root_group = main_group

print(terminal.cursor_x, terminal.cursor_y)

move_cursor = chr(27) + "[10;10H"
terminal.write(f" Something {move_cursor}{cyan} Else{reset}")

time.sleep(2)

terminal.write(" beep\x07")

while True:
pass
59 changes: 59 additions & 0 deletions examples/color_terminal_fruit_jam_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries
#
# SPDX-License-Identifier: MIT

import supervisor
from adafruit_fruitjam import peripherals
from displayio import Group
from terminalio import FONT

from adafruit_color_terminal import ColorTerminal

main_group = Group()

display = supervisor.runtime.display
if display is None or peripherals.get_display_config()[2] < 4:
print(
"To use ColorTerminal there must be an initialized display with a color depth at least 4."
)
print(
"Initializing display to default size 640x480 with color depth 8, ",
"if you do not want this configuration then initialize the display ",
"before running this example.",
)
peripherals.request_display_config(640, 480, 8)

font_bb = FONT.get_bounding_box()
screen_size = (display.width // font_bb[0], display.height // font_bb[1])

terminal = ColorTerminal(FONT, screen_size[0], screen_size[1])
main_group.append(terminal.tilegrid)

black = chr(27) + "[30m"
red = chr(27) + "[31m"
green = chr(27) + "[32m"
yellow = chr(27) + "[33m"
blue = chr(27) + "[34m"
magenta = chr(27) + "[35m"
cyan = chr(27) + "[36m"
white = chr(27) + "[37m"
reset = chr(27) + "[0m"


message = f"Hello {green}World{reset} {yellow}ANSI\n"
terminal.write(message)
print(message, end="")

message = f"{magenta}Terminal {red}Colors{reset}"
terminal.write(message)
print(message)

display.root_group = main_group

print(terminal.cursor_x, terminal.cursor_y)

move_cursor = chr(27) + "[10;10H"
terminal.write(f" Something {move_cursor}{cyan} Else{reset}")

while True:
pass
2 changes: 2 additions & 0 deletions ruff.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ ignore = [
"PLR2004", # magic-value-comparison
"UP030", # format literals
"PLW1514", # unspecified-encoding
"PLR0913", # too many args
"PLR0917", # too many positional args

]

Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy