Skip to content

adding code and audio files #1406

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 1 commit into from
Jan 11, 2021
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
238 changes: 238 additions & 0 deletions CircuitPython_Darksaber/code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
"""
Prop-Maker based Darksaber
Adapted from the Prop-Maker based Master Sword code
by Kattni Rembor & Limor Fried
Adafruit invests time and resources providing this open source code.
Please support Adafruit and open source hardware by purchasing
products from Adafruit!
Written by Liz Clark for Adafruit Industries
Copyright (c) 2021 Adafruit Industries
Licensed under the MIT license.
All text above must be included in any redistribution.
"""

import time
import random
import board
from digitalio import DigitalInOut, Direction
import neopixel
import adafruit_lis3dh
from adafruit_led_animation.animation.solid import Solid
from adafruit_led_animation.animation.pulse import Pulse
from adafruit_led_animation.animation.comet import Comet

from adafruit_bluefruit_connect.packet import Packet
from adafruit_bluefruit_connect.color_packet import ColorPacket

from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService

# BLE setup
ble = BLERadio()
uart_service = UARTService()
advertisement = ProvideServicesAdvertisement(uart_service)

# CUSTOMISE SENSITIVITY HERE: smaller numbers = more sensitive to motion
HIT_THRESHOLD = 250
SWING_THRESHOLD = 150

# Set to the length in seconds of the "on.wav" file
POWER_ON_SOUND_DURATION = 1.7

# NeoPixel setup
NUM_PIXELS = 34 # Number of pixels used in project
NEOPIXEL_PIN = board.D5
POWER_PIN = board.D10

enable = DigitalInOut(POWER_PIN)
enable.direction = Direction.OUTPUT
enable.value = False

strip = neopixel.NeoPixel(NEOPIXEL_PIN, NUM_PIXELS, brightness=.5, auto_write=False)
strip.fill(0) # NeoPixels off ASAP on startup
strip.show()

# default NeoPixel color is white
COLOR = (255, 255, 255)

# NeoPixel animations
pulse = Pulse(strip, speed=0.05, color=COLOR, period=3)
solid = Solid(strip, color=COLOR)
comet = Comet(strip, speed=0.05, color=COLOR, tail_length=40)

#audio
try:
from audiocore import WaveFile
except ImportError:
from audioio import WaveFile

try:
from audioio import AudioOut
except ImportError:
try:
from audiopwmio import PWMAudioOut as AudioOut
except ImportError:
pass # not always supported by every board!

audio = AudioOut(board.A0) # Speaker
wave_file = None

# Set up accelerometer on I2C bus, 4G range:
i2c = board.I2C()
accel = adafruit_lis3dh.LIS3DH_I2C(i2c)
accel.range = adafruit_lis3dh.RANGE_4_G

def play_wav(name, loop=False):
"""
Play a WAV file in the 'sounds' directory.
:param name: partial file name string, complete name will be built around
this, e.g. passing 'foo' will play file 'sounds/foo.wav'.
:param loop: if True, sound will repeat indefinitely (until interrupted
by another sound).
"""
global wave_file # pylint: disable=global-statement
print("playing", name)
if wave_file:
wave_file.close()
try:
wave_file = open('sounds/' + name + '.wav', 'rb')
wave = WaveFile(wave_file)
audio.play(wave, loop=loop)
except OSError:
pass # we'll just skip playing then


def power_on(sound, duration):
"""
Animate NeoPixels with accompanying sound effect for power on.
:param sound: sound name (similar format to play_wav() above)
:param duration: estimated duration of sound, in seconds (>0.0)
"""
start_time = time.monotonic() # Save audio start time
play_wav(sound)
while True:
elapsed = time.monotonic() - start_time # Time spent playing sound
if elapsed > duration: # Past sound duration?
break # Stop animating
comet.animate()

# List of swing wav files without the .wav in the name for use with play_wav()
swing_sounds = [
'swing1',
'swing2',
'swing3',
'swing4',
]

# List of hit wav files without the .wav in the name for use with play_wav()
hit_sounds = [
'hit1',
'hit2',
'hit3',
'hit4',
]

mode = 0 # Initial mode = OFF

#RGB LED
red_led = DigitalInOut(board.D11)
green_led = DigitalInOut(board.D12)
blue_led = DigitalInOut(board.D13)

red_led.direction = Direction.OUTPUT
green_led.direction = Direction.OUTPUT
blue_led.direction = Direction.OUTPUT

blue_led.value = True
red_led.value = True
green_led.value = True

# Darksaber start-up before loop
if mode == 0: # If currently off...
enable.value = True
power_on('on', POWER_ON_SOUND_DURATION) # Power up!
play_wav('idle', loop=True) # Play idle sound now
mode = 1 # Idle mode

while True:
# begin advertising BLE
ble.start_advertising(advertisement)
# if no BLE connection...
# allows it to be used without the bluefruit app connection
while not ble.connected:
if mode >= 1: # If not OFF mode...
x, y, z = accel.acceleration # Read accelerometer
accel_total = x * x + z * z
# (Y axis isn't needed, due to the orientation that the Prop-Maker
# Wing is mounted. Also, square root isn't needed, since we're
# comparing thresholds...use squared values instead.)
if accel_total > HIT_THRESHOLD: # Large acceleration = HIT
TRIGGER_TIME = time.monotonic() # Save initial time of hit
play_wav(random.choice(hit_sounds)) # Start playing 'hit' sound
# NeoPixels are solid on with a hit
solid.animate()
mode = 3 # HIT mode
elif mode == 1 and accel_total > SWING_THRESHOLD: # Mild = SWING
TRIGGER_TIME = time.monotonic() # Save initial time of swing
play_wav(random.choice(swing_sounds)) # Randomly choose from available swing sounds
while audio.playing:
pass # wait till we're done
mode = 2 # we'll go back to idle mode
elif mode == 1:
# pulse animation when idling or swinging
pulse.animate()
elif mode > 1: # If in SWING or HIT mode...
if audio.playing: # And sound currently playing...
blend = time.monotonic() - TRIGGER_TIME # Time since triggered
if mode == 2: # If SWING,
blend = abs(0.5 - blend) * 2.0 # ramp up, down
else: # No sound now, but still SWING or HIT modes
play_wav('idle', loop=True) # Resume idle sound
mode = 1 # Return to idle mode
ble.stop_advertising()

# if BLE is connected...
while ble.connected:
# color picker from bluefruit app
if uart_service.in_waiting:
packet = Packet.from_stream(uart_service)
# if a color packet is recieved...
if isinstance(packet, ColorPacket):
print(packet.color)
# color for the different animations are updated
comet.color = packet.color
solid.color = packet.color
pulse.color = packet.color
solid.animate()
# repeat of the above code
if mode >= 1: # If not OFF mode...
x, y, z = accel.acceleration # Read accelerometer
accel_total = x * x + z * z
# (Y axis isn't needed, due to the orientation that the Prop-Maker
# Wing is mounted. Also, square root isn't needed, since we're
# comparing thresholds...use squared values instead.)
if accel_total > HIT_THRESHOLD: # Large acceleration = HIT
TRIGGER_TIME = time.monotonic() # Save initial time of hit
play_wav(random.choice(hit_sounds)) # Start playing 'hit' sound
# NeoPixels are solid on with a hit
solid.animate()
mode = 3 # HIT mode
elif mode == 1 and accel_total > SWING_THRESHOLD: # Mild = SWING
TRIGGER_TIME = time.monotonic() # Save initial time of swing
play_wav(random.choice(swing_sounds)) # Randomly choose from available swing sounds
while audio.playing:
pass # wait till we're done
mode = 2 # we'll go back to idle mode

elif mode == 1:
# pulse animation when idling or swinging
pulse.animate()
elif mode > 1: # If in SWING or HIT mode...
if audio.playing: # And sound currently playing...
blend = time.monotonic() - TRIGGER_TIME # Time since triggered
if mode == 2: # If SWING,
blend = abs(0.5 - blend) * 2.0 # ramp up, down
else: # No sound now, but still SWING or HIT modes
play_wav('idle', loop=True) # Resume idle sound
mode = 1 # Return to idle mode
Binary file added CircuitPython_Darksaber/sounds/hit1.wav
Binary file not shown.
Binary file added CircuitPython_Darksaber/sounds/hit2.wav
Binary file not shown.
Binary file added CircuitPython_Darksaber/sounds/hit3.wav
Binary file not shown.
Binary file added CircuitPython_Darksaber/sounds/hit4.wav
Binary file not shown.
Binary file added CircuitPython_Darksaber/sounds/idle.wav
Binary file not shown.
Binary file added CircuitPython_Darksaber/sounds/on.wav
Binary file not shown.
Binary file added CircuitPython_Darksaber/sounds/swing1.wav
Binary file not shown.
Binary file added CircuitPython_Darksaber/sounds/swing2.wav
Binary file not shown.
Binary file added CircuitPython_Darksaber/sounds/swing3.wav
Binary file not shown.
Binary file added CircuitPython_Darksaber/sounds/swing4.wav
Binary file not shown.