Skip to content

Commit

Permalink
Final touchups to examples and supporting code
Browse files Browse the repository at this point in the history
  • Loading branch information
ZodiusInfuser committed Aug 1, 2024
1 parent 5945cfc commit 6da8438
Show file tree
Hide file tree
Showing 29 changed files with 230 additions and 107 deletions.
17 changes: 13 additions & 4 deletions boards/PIMORONI_TINYFX/visible_libs/tiny_fx.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from machine import ADC, Pin
from pimoroni_i2c import PimoroniI2C
from picofx import PWMLED, RGBLED
from audio import WavPlayer


class TinyFX:
Expand All @@ -14,9 +15,9 @@ class TinyFX:
I2C_SDA_PIN = 16
I2C_SCL_PIN = 17

I2S_DATA = 18
I2S_BCLK = 19
I2S_LRCLK = 20
I2S_DATA_PIN = 18
I2S_BCLK_PIN = 19
I2S_LRCLK_PIN = 20
AMP_EN_PIN = 21

USER_SW_PIN = 22
Expand All @@ -29,7 +30,7 @@ class TinyFX:
OUTPUT_GAMMA = 2.8
RGB_GAMMA = 2.2

def __init__(self, init_i2c=True):
def __init__(self, init_i2c=True, init_wav=True, wav_root="/"):
# Set up the mono and RGB LED outputs
self.outputs = [PWMLED(out, gamma=self.OUTPUT_GAMMA) for out in self.OUT_PINS]
self.rgb = RGBLED(*self.RGB_PINS, invert=False, gamma=self.RGB_GAMMA)
Expand All @@ -44,6 +45,10 @@ def __init__(self, init_i2c=True):
# Set up the internal voltage sensor
self.__v_sense = ADC(Pin(self.V_SENSE_PIN))

# Set up the wav (and tone) player, if the user wants
if init_wav:
self.wav = WavPlayer(0, self.I2S_BCLK_PIN, self.I2S_LRCLK_PIN, self.I2S_DATA_PIN, self.AMP_EN_PIN, root=wav_root)

def boot_pressed(self):
return self.__switch.value() == 0

Expand Down Expand Up @@ -84,3 +89,7 @@ def clear(self):
out.off()

self.rgb.set_rgb(0, 0, 0)

def shutdown(self):
self.clear()
self.wav.deinit()
25 changes: 25 additions & 0 deletions examples/tiny_fx/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ These are micropython examples for the Pimoroni [TinyFX](https://shop.pimoroni.c
- [Random](#random)
- [Hue Step](#hue-step)
- [Audio Examples](#audio-examples)
- [Race Start](#race-start)
- [Encounters](#encounters)
- [Photon Sword](#photon-sword)
- [Showcase Examples](#showcase-examples)
- [Rescue Vehicle](#rescue-vehicle)
- [Sensor Wave](#sensor-wave)
Expand Down Expand Up @@ -134,6 +137,28 @@ Play a stepped hue effect on TinyFX's RGB output.

## Audio Examples

### Race Start
[audio/race_start.py](audio/race_start.py)

Plays a simple boop, boop, boop, beeep countdown sound effect when
you press Boot on TinyFx. Great for counting down to a race start.


### Encounters
[audio/fair_use_encounters.py](audio/fair_use_encounters.py)

Play an evocative musical melody with accompanying lights on TinyFX.
Any resemblance to music you might have heard elsewhere is purely coincidental.


### Photon Sword
[audio/photon_sword.py](audio/photon_sword.py)

Play sounds that react to motion with a TinyFX.
Grab yourself an MSA301 and attach it to the Qw/St connector.

This example needs the directory `photon_sword` copied over to your TinyFX.


## Showcase Examples

Expand Down
80 changes: 57 additions & 23 deletions examples/tiny_fx/examples/audio/fair_use_encounters.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,73 @@
import time
from tiny_fx import TinyFX
from audio import WavPlayer
from picofx.colour import RED, YELLOW, GREEN, CYAN, BLUE, BLACK
from machine import Pin
from pimoroni import Analog


"""
An evocative musical melody with accompanying lights.
Play an evocative musical melody with accompanying lights on TinyFX.
Any resemblance to music you might have heard elsewhere is purely coincidental.
Any resemblance to music you might have heard elsewhere is
purely coincidental.
Press "Boot" to exit the program.
"""

tiny = TinyFX()
wav = WavPlayer(0, tiny.I2S_BCLK, tiny.I2S_LRCLK, tiny.I2S_DATA, tiny.AMP_EN_PIN)
# Constants
TONES = (588, 658, 524, 262, 384, 0) # The tones to play in order (0 means silence)
VOLUME = (0.7, 0.5, 0.7, 1.0, 0.9, 0) # The volume of each tone to play (tune to your speaker)
DURATIONS = (0.6, 0.6, 0.6, 0.6, 0.6 * 4, 2.0) # The duration of each tone (in seconds)
OUTPUTS = (2, 3, 1, 6, 4, 0) # Which output to light with each tone
RGBS = (CYAN, BLUE, GREEN, RED, YELLOW, BLACK) # Which R, G, B colours to show for each tone

USE_SENSOR = False # Whether to use an analog sensor to control the speed of the melody
MAX_SPEED = 20 # The maximum speed multipler that the melody will play at
SAMPLES = 5 # The number of measurements to take of the analog sensor, to reduce noise

tones = [588, 658, 524, 262, 384, 0]
durations = [0.6, 0.6, 0.6, 0.6, 0.6 * 4, 2.0]
leds = [2, 3, 1, 6, 4, 0]
# Variables
tiny = TinyFX() # Create a new TinyFX object to interact with the board
index = 0 # The index of the tone to play

n = 0
if USE_SENSOR:
# Create a new Analog object for reading the sensor connector if the sensor is attached
sensor = Analog(Pin(tiny.SENSOR_PIN))

# Wrap the code in a try block, to catch any exceptions (including KeyboardInterrupt)
try:
while not tiny.boot_pressed():
tone = tones[n]
duration = durations[n]
led = leds[n]
tone = TONES[index]
output = OUTPUTS[index]

speed = 1.0
if USE_SENSOR:
# Read the voltage output by the sensor and convert it to a speed
speed = (sensor.read_voltage(SAMPLES) * (MAX_SPEED - 1) / 3.3) + 1

# Print out the speed value to a sensible number of decimal places
print("Speed =", round(speed, 2))

# Play the next tone
if tone:
wav.play_tone(tone, 1.0)
tiny.wav.play_tone(tone, VOLUME[index])

# Turn on just the output for the next tone
tiny.clear()
if led:
tiny.outputs[led - 1].on()
time.sleep(duration)
wav.stop()
time.sleep(0.1)
n += 1
n %= len(tones)
if output:
tiny.outputs[output - 1].on()

# Set the RGB output to a colour for the tone
tiny.rgb.set_rgb(*RGBS[index])

# Wait for the tone's duration before stopping
time.sleep(DURATIONS[index] / speed)
tiny.wav.stop()

# Pause between each tone
time.sleep(0.1 / speed)

# Move on to the next tone and light
index += 1
index %= len(TONES)

# Turn off all the outputs and audio
finally:
tiny.clear()
wav.deinit()
tiny.shutdown()
101 changes: 68 additions & 33 deletions examples/tiny_fx/examples/audio/photon_sword.py
Original file line number Diff line number Diff line change
@@ -1,52 +1,87 @@
import time
from tiny_fx import TinyFX
from audio import WavPlayer
from machine import I2C
from picofx.colour import WHITE
from breakout_msa301 import BreakoutMSA301

"""
Absolutely definitely not a l&%t s&^@*r.
Don't forget to copy the `photon_sword` directory.
Play sounds that react to motion with a TinyFX.
Grab yourself an MSA301 and attach it to the Qw/St connector.
Press boot to power up, swing to make do sounds! SWOOSH SWOOOOSH!!!
"""
This example needs the directory `photon_sword` copied over to your TinyFX.
TRIGGER_DELTA = 1.0
Absolutely definitely not a l&%t s&^@*r.
tiny = TinyFX()
wav = WavPlayer(0, tiny.I2S_BCLK, tiny.I2S_LRCLK, tiny.I2S_DATA, tiny.AMP_EN_PIN, root="/photon_sword")
Press Boot to power up, swing to make do sounds! SWOOSH SWOOOOSH!!! and press Boot to power down
"""

i2c = I2C(0, sda=tiny.I2C_SDA_PIN, scl=tiny.I2C_SCL_PIN)
# Constants
TRIGGER_DELTA = 1.0 # How much movement change is needed to trigger a swinging sound
ANIMATION_SLEEP = 0.05 # The time to sleep between each step of the start and finish animations

msa = BreakoutMSA301(i2c)
# Variables
tiny = TinyFX(wav_root="/photon_sword") # Create a new TinyFX object and tell with where the wav files are located
msa = BreakoutMSA301(tiny.i2c) # Create a new MSA301 object for reading acceleration data
last_axes = None # The last accelerometer values measured

# Set up the MSA301
msa.enable_interrupts(BreakoutMSA301.FREEFALL | BreakoutMSA301.ORIENTATION)

last_axes = None

# Wrap the code in a try block, to catch any exceptions (including KeyboardInterrupt)
try:
while not tiny.boot_pressed():
pass
wav.play_wav("ps-start.wav")
while wav.is_playing():
pass
# Loop forever
while True:
if not wav.is_playing():
wav.play_wav("ps-idle.wav", True)
this_axes = msa.get_x_axis(), msa.get_y_axis(), msa.get_z_axis()
if last_axes is not None:
deltas = [abs(this_axes[n] - last_axes[n]) for n in range(3)]
delta = max(deltas)
if delta > TRIGGER_DELTA:
swing = deltas.index(delta) + 1
file = f"ps-swing{swing}.wav"
wav.play_wav(file)
print(file)
last_axes = this_axes
time.sleep(0.05)
tiny.rgb.set_rgb(*WHITE) # Show that the program is ready

# Wait for the Boot button to be pressed
while not tiny.boot_pressed():
pass
tiny.clear() # Show that the program is running

# Play the start sound and wait for it to finish
tiny.wav.play_wav("ps-start.wav")
while tiny.wav.is_playing():
# Whilst playing animate the outputs
for i in range(len(tiny.outputs)):
tiny.outputs[i].on()
time.sleep(0.05)

# Loop forever, again
while True:

# If nothing is playing, play a looping idle sound
if not tiny.wav.is_playing():
tiny.wav.play_wav("ps-idle.wav", True)

# Read acceleration data from the MSA301
this_axes = msa.get_x_axis(), msa.get_y_axis(), msa.get_z_axis()
if last_axes is not None:
deltas = [abs(this_axes[n] - last_axes[n]) for n in range(3)]
delta = max(deltas)
# If the delta is above the threshold
if delta > TRIGGER_DELTA:
# Select a swing sound to play
swing = deltas.index(delta) + 1
file = f"ps-swing{swing}.wav"
tiny.wav.play_wav(file)
print(file)

# Record the last acceleration, for calculating the next deltas
last_axes = this_axes
time.sleep(0.05)

# Check if the boot button has been pressed
if tiny.boot_pressed():
tiny.wav.play_wav("ps-finish.wav")
while tiny.wav.is_playing():
# Whilst playing animate the outputs
for i in range(len(tiny.outputs)):
tiny.outputs[len(tiny.outputs) - i - 1].off()
time.sleep(0.05)

# Break out of the inner loop
break

# Turn off all the outputs and audio
finally:
wav.deinit()
tiny.shutdown()
Binary file not shown.
49 changes: 30 additions & 19 deletions examples/tiny_fx/examples/audio/race_start.py
Original file line number Diff line number Diff line change
@@ -1,45 +1,56 @@
import time
from tiny_fx import TinyFX
from audio import WavPlayer
from picofx.colour import WHITE

"""
Plays a simple boop, boop, boop, beeep countdown sound effect when
you presss BOOT. Great for counting down to a race start.
you press Boot on TinyFx. Great for counting down to a race start.
Plug a red LED into port 1 and a green LED into port 2.
"""

tiny = TinyFX()
wav = WavPlayer(0, tiny.I2S_BCLK, tiny.I2S_LRCLK, tiny.I2S_DATA, tiny.AMP_EN_PIN)
# Constants
TONES = (440, 440, 440, 880, 0) # The tones to play in order (0 means silence)
DURATIONS = (0.5, 0.5, 0.5, 1.5, 2.0) # The duration of each tone (in seconds)
OUTPUTS = (1, 1, 1, 2, 0) # Which output to light with each tone

tones = [440, 440, 440, 880, 0]
durations = [0.5, 0.5, 0.5, 1.5, 2.0]
leds = [1, 1, 1, 2, 0]

n = 0
# Variables
tiny = TinyFX() # Create a new TinyFX object to interact with the board

# Wrap the code in a try block, to catch any exceptions (including KeyboardInterrupt)
try:
# Loop forever
while True:
tiny.rgb.set_rgb(*WHITE) # Show that the program is ready

# Wait for the Boot button to be pressed
while not tiny.boot_pressed():
pass
tiny.clear() # Show that the program is running

# Loop through all the tones
for i in range(len(TONES)):
tone = TONES[i]
duration = DURATIONS[i]
output = OUTPUTS[i]

for n in range(len(tones)):
tone = tones[n]
duration = durations[n]
led = leds[n]
# Play the next tone
if tone:
wav.play_tone(tone, 1.0, wav.TONE_SQUARE)
tiny.wav.play_tone(tone, 1.0, tiny.wav.TONE_SQUARE)

# Turn on just the output for the next tone
tiny.clear()
if led:
tiny.outputs[led - 1].on()
if output:
tiny.outputs[output - 1].on()

# Wait for the tone's duration before stopping
time.sleep(duration)
wav.stop()
tiny.wav.stop()

# Pause between each tone if not silence
if tone:
time.sleep(0.1)

# Turn off all the outputs and audio
finally:
tiny.clear()
wav.deinit()
tiny.shutdown()
2 changes: 1 addition & 1 deletion examples/tiny_fx/examples/effects/colour/hue_step.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@
# Stop any running effects and turn off all the outputs
finally:
player.stop()
tiny.clear()
tiny.shutdown()
2 changes: 1 addition & 1 deletion examples/tiny_fx/examples/effects/colour/rainbow.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@
# Stop any running effects and turn off all the outputs
finally:
player.stop()
tiny.clear()
tiny.shutdown()
2 changes: 1 addition & 1 deletion examples/tiny_fx/examples/effects/colour/random.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,4 @@
# Stop any running effects and turn off all the outputs
finally:
player.stop()
tiny.clear()
tiny.shutdown()
Loading

0 comments on commit 6da8438

Please sign in to comment.