Lisa Zhu
Published © MIT

Music Bracelet

Built on pocketbeagle with python, this bracelet can provide combined effects of vibration and LED while playing music.

IntermediateFull instructions providedOver 1 day363
Music Bracelet

Things used in this project

Hardware components

WS2812 Addressable LED Strip
Digilent WS2812 Addressable LED Strip
Cut and Used 10 of the LEDs
×1
Adafruit Level Shifter
Used to output a signal to the LED strip
×1
Adafruit SPI Screen
Screen to display the song list
×1
Resistor 1k ohm
Resistor 1k ohm
A 1k ohm resistor in the tool kit, used to control the button
×1
SparkFun USB Type A Female Breakout
SparkFun USB Type A Female Breakout
Connected to the usb hub and the speaker
×1
USB Hub with Power
The hub is connected to a wall outlet to supply power for the LED strip, bluetooth adaptor and the speaker
×1
USB Speaker
×1
Bluetooth Adaptor
Not used in the project right now, plan to use it for a bluetooth speaker in the future
×1
PocketBeagle
BeagleBoard.org PocketBeagle
Of course! PocketBeagle!
×1
Jumper wires (generic)
Jumper wires (generic)
As expected, a ton of wires
×1
Gravity:Digital Push Button (Yellow)
DFRobot Gravity:Digital Push Button (Yellow)
A normal push button
×1

Software apps and online services

SolidWorks
Built the bracelet in SolidWorks

Hand tools and fabrication machines

Prusa 3D Printer
Printed the bracelet with a 3d printer and flexible filament

Story

Read more

Custom parts and enclosures

CAD File for the Bracelet

This file can be 3d printed with flexible filament, and is created using solidworks

Schematics

Schematics for the whole project

This schematics include:
- connections to the usb port (which is then connected to speaker)
- connections to the SPI screen and a button
- connections to the level shifter & led strip

Code

SPI Screen Test

Python
A test file for the SPI screen created by Erik Welsh
"""
--------------------------------------------------------------------------
SPI Screen Test
--------------------------------------------------------------------------
License:   
Copyright 2021 Erik Welsh

Redistribution and use in source and binary forms, with or without 
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this 
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, 
this list of conditions and the following disclaimer in the documentation 
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors 
may be used to endorse or promote products derived from this software without 
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------

Test SPI Screen

"""
import time
import busio
import board
import digitalio


from adafruit_rgb_display import color565
import adafruit_rgb_display.ili9341 as ili9341


# Configuration for CS and DC pins:
reset_pin = digitalio.DigitalInOut(board.P2_35)
dc_pin    = digitalio.DigitalInOut(board.P2_33)
cs_pin    = digitalio.DigitalInOut(board.P2_31)

# Setup SPI bus using hardware SPI
spi = busio.SPI(clock=board.SCLK_1, MISO=board.MISO_1, MOSI=board.MOSI_1)

# Create the ILI9341 display:
display = ili9341.ILI9341(spi, cs=cs_pin, dc=dc_pin)

# Main loop:
while True:
    print("Test Display")
    # Clear the display
    display.fill(0)
    # Draw a red pixel in the center.
    display.pixel(120, 160, color565(255, 0, 0))
    # Pause 2 seconds.
    time.sleep(2)
    # Clear the screen blue.
    display.fill(color565(0, 0, 255))
    # Pause 2 seconds.
    time.sleep(2)

LED Strip Light Test

Python
A test file for the LED strip created by Erik Welsh
"""
--------------------------------------------------------------------------
LED Strip Light Test
--------------------------------------------------------------------------
License:   
Copyright 2021 Erik Welsh

Based on Code from:  https://github.com/rpliu3/ENGI301/tree/master/Project_01/code
Copyright 2019 Rebecca Liu

Redistribution and use in source and binary forms, with or without 
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this 
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, 
this list of conditions and the following disclaimer in the documentation 
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors 
may be used to endorse or promote products derived from this software without 
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------
Software API:

  * opc.client ensures that server is running so that LED string can be displayed
  
--------------------------------------------------------------------------
Background Information: 
 
   * Base code for LED functions came from the following repositories:
        https://markayoder.github.io/PRUCookbook/01case/case.html#_neopixels_5050_rgb_leds_with_integrated_drivers_ledscape
        https://markayoder.github.io/PRUCookbook/06io/io.html#io_uio
        https://github.com/Yona-Appletree/LEDscape.git
        https://github.com/zestyping/openpixelcontrol

"""

import time
import opc

ADDRESS = 'localhost:7890'

# Create a client object
client = opc.Client(ADDRESS)

# Test if it can connect
if client.can_connect():
    print ('connected to %s' % ADDRESS)
else:
    # We could exit here, but instead let's just print a warning
    # and then keep trying to send pixels in case the server
    # appears later
    print ('WARNING: could not connect to %s' % ADDRESS)
    
# Define Pixel String
STR_LEN=10
for i in range(STR_LEN):
    leds = [(255, 255, 255)] * STR_LEN

if not client.put_pixels(leds, channel=0):
    print ('not connected')

time.sleep(1)

# Uses each light's address to set display to set a color
def task():
    while True:
        print("loop")
        for i in range (0, 255):
            for j in range(STR_LEN):
                leds[j] = (i, i, i)
    
            if not client.put_pixels(leds, channel=0):
                print ('not connected')
            
            time.sleep(0.1)

# End def            
        
if __name__ == '__main__':    
    try:
        task()
    except KeyboardInterrupt:
        pass

    print("Program Complete.")        

Buzzer Test

Python
A test file for the vibration motor/ buzzer created by Erik Welsh
# -*- coding: utf-8 -*-
"""
--------------------------------------------------------------------------
Buzzer Test
--------------------------------------------------------------------------
License:   
Copyright 2021 Erik Welsh

Based on library from

Copyright 2018 Nicholas Lester

Redistribution and use in source and binary forms, with or without 
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this 
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, 
this list of conditions and the following disclaimer in the documentation 
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors 
may be used to endorse or promote products derived from this software without 
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------



"""
import sys

import time
import math
import random

import Adafruit_BBIO.PWM as PWM

# ------------------------------------------------------------------------
# Global variables
# ------------------------------------------------------------------------


# ------------------------------------------------------------------------
# Main Tasks
# ------------------------------------------------------------------------

class BuzzerSound():
    pin       = None
    
    def __init__(self, pin):
        self.pin = pin
    
    # End def
    
    def play_tone(self, frequency, length):
        """Plays a given note for a given length."""
        PWM.start(self.pin, 50, frequency)
        time.sleep(length)
    # end def
    
    def end(self):
        PWM.stop(self.pin)
        PWM.cleanup()
    # End def
    
    
# End class

# ------------------------------------------------------------------------
# Main script
# ------------------------------------------------------------------------

if __name__ == '__main__':
    print("Buzzer Test")
    
    buzzer = BuzzerSound("P2_1")
    
    print("Play tone")
    
    buzzer.play_tone(440, 1)        # Play 440Hz for 1 second

    buzzer.end()
    
    print("Test Complete")

vibration.py

Python
Make motors vibrate!
# -*- coding: utf-8 -*-
"""
--------------------------------------------------------------------------
Vibration
--------------------------------------------------------------------------
License:   
Copyright 2021 Lisa Zhu

Based on library from

Copyright 2018 Nicholas Lester

Redistribution and use in source and binary forms, with or without 
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this 
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, 
this list of conditions and the following disclaimer in the documentation 
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors 
may be used to endorse or promote products derived from this software without 
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------



"""

import sys

import time
import math
import random

import Adafruit_BBIO.PWM as PWM
# ------------------------------------------------------------------------
# Global variables
# ------------------------------------------------------------------------


# ------------------------------------------------------------------------
# Main Tasks
# ------------------------------------------------------------------------

class Vibration():
    pin       = None
    
    def __init__(self, pin):
        self.pin = pin
    
    # End def
    
    def vibrate(self, frequency):
        """Plays a given note for a given length."""
        PWM.start(self.pin, 100, frequency)
    # end def
    def end(self):
        PWM.stop(self.pin)
        PWM.cleanup()
        # End def

led_display.py

Python
Let the LEDs blink!
# -*- coding: utf-8 -*-

"""
--------------------------------------------------------------------------
LED Music Visualizer & Vibrator
--------------------------------------------------------------------------
License:   
Copyright 2021 Lisa Zhu

Redistribution and use in source and binary forms, with or without 
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this 
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, 
this list of conditions and the following disclaimer in the documentation 
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors 
may be used to endorse or promote products derived from this software without 
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------
Control LED strip and vibration motors with WAV file data
  
LED lights and vibrations according to tuple values extracted from wav file

--------------------------------------------------------------------------
Background Information: 
 
  * Setting up the LED strip:
  https://markayoder.github.io/PRUCookbook/01case/case.html#_neopixels_5050_rgb_leds_with_integrated_drivers_ledscape (Section 1.3. NeoPixels - 5050 RGB LEDs with Integrated Drivers (LEDScape))
  
  * Unpacking and analyzing wav file:
  https://stackoverflow.com/questions/2226853/interpreting-wav-data (Comment by SapphireSun on Feb 9 '10 at 6:18)
  
Copyright Information:
    Adopted from code by Juliana Wang:
    https://www.hackster.io/juliana-wang/pocketbeagle-led-music-visualizer-3e6c7c
"""

# ------------------------------------------------------------------------
# ------------------------------------------------------------------------
# PART 1: READ/UNPACK WAV FILE DATA
# ------------------------------------------------------------------------
# ------------------------------------------------------------------------

import time
import wave
import struct

import opc
import vibration as vibration
from multiprocessing import Process
# ------------------------------------------------------------------------
# Constants
# ------------------------------------------------------------------------

ADDRESS = 'localhost:7890'

# ------------------------------------------------------------------------
# Global variables
# ------------------------------------------------------------------------
integer_data = []



# ------------------------------------------------------------------------
# Functions
# ------------------------------------------------------------------------


def pcm_channels(wave_file):
    """Given a file-like object or file path representing a wave file,
    decompose it into its constituent PCM data streams.

    Input: A file like object or file path
    Output: A list of lists of integers representing the PCM coded data stream channels
        and the sample rate of the channels (mixed rate channels not supported)
    """
    global integer_data
    stream = wave.open(wave_file,"rb")

    num_channels = stream.getnchannels()
    sample_rate  = stream.getframerate()
    sample_width = stream.getsampwidth()
    num_frames   = stream.getnframes()
    
    raw_data = stream.readframes( num_frames ) # Returns byte data
    stream.close()

    total_samples = num_frames * num_channels
 

    if sample_width == 1: 
        fmt = "%iB" % total_samples # read unsigned chars
    elif sample_width == 2:
        fmt = "%ih" % total_samples # read signed 2 byte shorts
    else:
        raise ValueError("Only supports 8 and 16 bit audio formats.")

    integer_data = struct.unpack(fmt, raw_data)
    del raw_data # Keep memory tidy (who knows how big it might be)

# ------------------------------------------------------------------------
# ------------------------------------------------------------------------
# PART 2: TRIGGER LED LIGHT STRIP WITH WAV DATA
# ------------------------------------------------------------------------
# ------------------------------------------------------------------------
    
def led_strip(wave_file):
    global integer_data
    
    pcm_channels(wave_file)
    
    vib1 = vibration.Vibration("P2_1")
    vib2 = vibration.Vibration("P2_3")
    vib3 = vibration.Vibration("P1_33")
    vib4 = vibration.Vibration("P1_36")

    client = opc.Client(ADDRESS)

    stop_time = time.time() + 60
    STR_LEN = 10
    
    offset      = 0
    data_length = len(integer_data)
    
    # Test if it can connect
    if client.can_connect():
        print ('connected to %s' % ADDRESS)
    else:
        # We could exit here, but instead let's just print a warning
        # and then keep trying to send pixels in case the server
        # appears later
        print ('WARNING: could not connect to %s' % ADDRESS)
        
    leds = [(0, 0, 0)] * STR_LEN
    
    while time.time() < stop_time:
        vib_freq = 0
        
        for i in range(STR_LEN):
            datavalue = abs(integer_data[(i+offset)])//16
            vib_freq += datavalue
            leds[i]  = (datavalue,datavalue,datavalue)

        offset = offset + STR_LEN   #Leaves remainder numebr of pixels to shift
        vib_freq = vib_freq // STR_LEN

        if vib_freq == 0: # frequency can't be zero
            vib_freq = 1
        
        if offset > data_length:
            break
        
        if not client.put_pixels(leds, channel=0):
            print('not connected')
        
        # Do vibration
        
        process_1 = Process(target=vib1.vibrate,args=(vib_freq,))
        process_2 = Process(target=vib2.vibrate,args=(vib_freq,))
        process_3 = Process(target=vib3.vibrate,args=(vib_freq,))
        process_4 = Process(target=vib4.vibrate,args=(vib_freq,))

        processes = [process_1, process_2, process_3, process_4]
        for process in processes:
            process.start() #start vibration
        
        process_1.join()
        process_2.join()
        process_3.join()
        process_4.join()
        
        time.sleep(0.001)
    
    vib1.end()
    vib2.end()
    vib3.end()
    vib4.end()

song_names.py

Python
Call led_strip and vibration to execute the program
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT
"""
--------------------------------------------------------------------------
Song Name Display & Music Player
--------------------------------------------------------------------------
License:   
Copyright 2021 <Lisa Zhu>

Redistribution and use in source and binary forms, with or without 
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this 
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, 
this list of conditions and the following disclaimer in the documentation 
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors 
may be used to endorse or promote products derived from this software without 
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Reference of SPI display related code: Melissa LeBlanc-Williams for Adafruit Industries
--------------------------------------------------------------------------

Use the ili9341 Display, a button, five vibration motors, a led strip and a speaker to 
create a music player with selectable songs, with led color change and vibrations to
enhance the experience.

Requirements:
  - Display all selectable songs on the screen
  - Increment the counter by one each time the button is pressed
  - Stop incrementing the counter 5 seconds after the button is released
  - Play the song corresponding to the counter
  - Sync vibrations and LEDs with the music
Uses:
  - digitalio, board, busio, PIL, adafruit_rgb_display.ili9341 libraries are used to control the display
  - time library is used to time the program and exit when appropriate
  - Adafruit_BBIO.GPIO library is used to take input from the button
  - os library is used to play the music
  - multiprocessing library is used to sync vibration and led with the music
"""

import digitalio
import board
import busio
from PIL import Image, ImageDraw, ImageFont
import adafruit_rgb_display.ili9341 as ili9341

import time

import Adafruit_BBIO.GPIO as GPIO
import os
from multiprocessing import Process

import led_display as led
import vibration as vibration

# First define some constants to allow easy resizing of shapes.
BORDER = 20
FONTSIZE = 18
class SongNames():
    vib1       = None
    vib2       = None
    vib3       = None
    vib4       = None
    button     = None
    display    = None
    
    def __init__(self, reset_time=5.0, button="P1_26", spi = busio.SPI(board.SCLK_1, board.MOSI_1, board.MISO_1)):
        """ intialize variables and set up display """
        self.vib1 = vibration.Vibration("P2_1")
        self.vib2 = vibration.Vibration("P2_3")
        self.vib3 = vibration.Vibration("P1_33")
        self.vib4 = vibration.Vibration("P1_36")

        # Configuration for CS and DC pins (these are PiTFT defaults):
        cs_pin = digitalio.DigitalInOut(board.P2_31)
        dc_pin = digitalio.DigitalInOut(board.P2_33)
        reset_pin = digitalio.DigitalInOut(board.P2_35)
        
        # Config for display baudrate (default max is 24mhz):
        BAUDRATE = 24000000

        self.button    =button
        self.display   =ili9341.ILI9341(
                        spi,
                        rotation=90,  # 2.2", 2.4", 2.8", 3.2" ILI9341
                        cs=cs_pin,
                        dc=dc_pin,
                        rst=reset_pin,
                        baudrate=BAUDRATE,
                    )
        self._setup()

   
    def _setup(self):
       
        # Create blank image for drawing.
        # Make sure to create image with mode 'RGB' for full color.
        if self.display.rotation % 180 == 90:
            height = self.display.width  # we swap height/width to rotate it to landscape!
            width = self.display.height
        else:
            width = self.display.width  # we swap height/width to rotate it to landscape!
            height = self.display.height
        
        image = Image.new("RGB", (width, height))
        
        # Get drawing object to draw on image.
        draw = ImageDraw.Draw(image)
        
        # Draw a black box as the background
        draw.rectangle((0, 0, width, height), fill=0)
        self.display.image(image)
        
        # Draw a smaller inner purple rectangle
        draw.rectangle(
            (BORDER, BORDER, width - BORDER - 1, height - BORDER - 1), fill=(170, 0, 136)
        )
        # Initialize Button
        GPIO.setup(self.button, GPIO.IN)
        
        # Load a TTF Font
        font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", FONTSIZE)
        padding = BORDER+1
        x= BORDER+2
        # Display song names
        song1 = "Stay with Me -- Press Once"
        song2 = "Glassy Sky    -- Press Twice"
        song3 = "Verona          -- Press 3 Times"
        song4 = "Aimer           -- Press 4 Times"
        y=padding+15
        draw.text(
            (x, y),
            song1,
            font=font,
            fill=(255, 255, 0),
        )
        y+=font.getsize(song1)[1]+15
        draw.text(
            (x, y),
            song2,
            font=font,
            fill=(255, 255, 0),
        )
        y+=font.getsize(song2)[1]+15
        draw.text(
            (x, y),
            song3,
            font=font,
            fill=(255, 255, 0),
        )
        y+=font.getsize(song3)[1]+15
        draw.text(
            (x, y),
            song4,
            font=font,
            fill=(255, 255, 0),
        )

        # Display image.
        self.display.image(image)
        
    def run(self):
        """Execute the main program."""
        press_count         = 0      # Number of times button was pressed
        button_press_done   = False
        timeout             = False
        
        while(not button_press_done):
            
            while(GPIO.input(self.button) == 1):
                if press_count != 0:
                    if (time.time() - initial_time) > 5: #stop counting if the button remains unpressed for 5 seconds
                        button_press_done = True
                        timeout = True
                        break
                time.sleep(0.1)
            
            if press_count == 0:
                initial_time = time.time()

            if not timeout:            
                press_count += 1
                print(press_count)
                
            # Wait for button release
            while(GPIO.input(self.button) == 0):
                if (button_press_done):
                    break
                time.sleep(0.1)
            
        #Each button press count corresponds to a different set of music, vibration and led effects
        if (press_count ==1):
            process1=Process(target=os.system, args=("mplayer ../speaker/music/stay_with_me.mp3",))
            process2=Process(target=led.led_strip, args=("/var/lib/cloud9/ENGI301/Project_1/speaker/music/stay_with_me.wav",))
        if (press_count ==2):
            process1=Process(target=os.system, args=("mplayer ../speaker/music/glassy_sky.mp3",))
            process2=Process(target=led.led_strip, args=("/var/lib/cloud9/ENGI301/Project_1/speaker/music/glassy_sky.wav",))
        if (press_count ==3):
            process1=Process(target=os.system, args=("mplayer ../speaker/music/verona.mp3",))
            process2=Process(target=led.led_strip, args=("/var/lib/cloud9/ENGI301/Project_1/speaker/music/verona.wav",))
        if (press_count ==4):
            process1=Process(target=os.system, args=("mplayer ../speaker/music/aimer.mp3",))
            process2=Process(target=led.led_strip, args=("/var/lib/cloud9/ENGI301/Project_1/speaker/music/aimer.wav",))
            
        processes = [process1, process2]
        
        for process in processes:
            process.start() #start vibration, music and led effects
        
        process1.join()
        process2.join()
        
    def cleanup(self):
        self.vib1.end()
        self.vib2.end()
        self.vib3.end()
        self.vib4.end()

if __name__ == '__main__':
    print("Program Start")
    
    # Create instantiation of song name display
    song_name=SongNames()
    try:
        # Run the song name display
        song_name.run()
    except KeyboardInterrupt:
        # Clean up hardware when exiting
        song_name.setup()

    song_name.cleanup()

    print("Program Complete")    
    

Lisa Zhu Github Repository

Credits

Lisa Zhu
1 project • 0 followers
Contact
Thanks to Juliana Wang and Erik Welsh.

Comments

Please log in or sign up to comment.