# Project export: EaseDJ

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: Cal Hacks 11.0
- Tagline: beginner friendly portable dj station
- Devpost: https://devpost.com/software/easedj
- GitHub: https://github.com/Deetschoe/easeDJ
- Video: https://www.youtube.com/embed/7gjYoUgeyIw?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — deetschoe (3 commits)

## Devpost submission (written by the team)

### Overview

Why this project? I have a big interest in music, but my wallet doesn’t want to drop $200+ on a DJ kit. What does EaseDJ do? Mix and play music in real-time with laser visuals on the go. How was it built? I used an Arduino 101 kit, added a knob, 2 touch sensors, and 2 buttons. Each has its own purpose. I programmed, designed, soldered, and assembled the entire kit into two small Amazon boxes the size of a laptop case. Challenges? I did not want to rely on a laptop, but the Raspberry Pi kits were all gone and taken. The Arduino 101 kit has Bluetooth, but it’s very low strength, so real-time audio doesn’t function properly. I wasted a lot of time trying to get around that because standalone is appealing. What did I learn? I learned a lot about soldering, Arduinos, and GPIO pins. I had never done a project solo and was worried I might not finish because of the lack of a team, but I proved myself wrong. I also miss my friends and working with other people. Never take building with friends for granted! It was my first time doing a hardware hackathon project, and I want to do it more.

## README (from the GitHub repository)

<img src="https://media.tenor.com/DTMj3wH9xFAAAAAM/nariukiyo-dj-khaled.webp" alt="Khalid" style="width:8%;">

## Why this project?  
I have a big interest in music, but my wallet doesn’t want to drop $200+ on a DJ kit.  
<img src="https://i.ibb.co/d4YGxbY/Screenshot-2024-10-20-at-7-11-32-AM.png" alt="Project" style="width:30%;">


## What does EaseDJ do?  
Mix and play music in real-time with laser visuals on the go.  
<img src="https://i.ibb.co/rZzbMVg/Screenshot-2024-10-20-at-8-28-23-AM.png" alt="Project" style="width:30%;">


## How was it built?  
I used an Arduino 101 kit, added a knob, 2 touch sensors, and 2 buttons. Each has its own purpose. I programmed, designed, soldered, and assembled the entire kit into two small Amazon boxes the size of a laptop case.  
<img src="https://i.ibb.co/9gbhvFz/Screenshot-2024-10-20-at-8-28-29-AM.png" alt="Project" style="width:30%;">


## Challenges?  
I did not want to rely on a laptop, but the Raspberry Pi kits were all gone and taken. The Arduino 101 kit has Bluetooth, but it’s very low strength, so real-time audio doesn’t function properly. I wasted a lot of time trying to get around that because standalone is appealing.  
<img src="https://i.ibb.co/y53mt0P/IMG-1018.jpg" alt="Project" style="width:30%;">


## What did I learn?  
I learned a lot about soldering, Arduinos, and GPIO pins. I had never done a project solo and was worried I might not finish because of the lack of a team, but I proved myself wrong. I also miss my friends and working with other people. Never take building with friends for granted!  
<img src="https://i.ibb.co/wpQKNwH/IMG-1020.jpg" alt="Project" style="width:30%;">


It was my first time doing a hardware hackathon project, and I want to do it more.  
<img src="https://i.ibb.co/q000GP2/IMG-1019.jpg" alt="Project" style="width:30%;">

<a href="https://www.youtube.com/watch?v=YOUR_VIDEO_ID" target="_blank">
  <img src="https://img.youtube.com/vi/YOUR_VIDEO_ID/0.jpg" alt="Link to demo video" style="width: 30%;">
</a>


## Detected evidence (automated analysis)

Indexed codebase: 2 recognized source files, 6 KB.
- Python (language) — detected in the code

## Codebase structure (from repository index)

### Files (14 of 14)

```
.DS_Store
app.py
ardWORKING 2.0
packs/.DS_Store
packs/acoustic/.DS_Store
packs/default/.DS_Store
packs/electric/.DS_Store
packs/guitar/.DS_Store
packs/licks/.DS_Store
packs/ukelele/.DS_Store
packs/wacky/.DS_Store
pyworking1.
README.md
workiong 3
```

### Dependencies

No dependency index available.

### Recent commits (newest first)

- Update README.md
- python part of the project
- first commit
- first commit

## Key source files (fetched from GitHub, selected and truncated for size)

### app.py

```python
import serial
import pygame
from pygame import mixer
import os
import time
import glob

# Initialize pygame mixer
pygame.mixer.init()

# Configure the serial connection
port = '/dev/tty.usbmodem11101'
max_retries = 5
retry_delay = 2  # seconds

def connect_serial(port, max_retries, retry_delay):
    for attempt in range(max_retries):
        try:
            print(f"Attempt {attempt + 1} to connect to {port}")
            ser = serial.Serial(port, 9600, timeout=0.1)
            print(f"Successfully connected to {port}")
            return ser
        except serial.SerialException as e:
            print(f"Error connecting to {port}: {e}")
            if attempt < max_retries - 1:
                print(f"Retrying in {retry_delay} seconds...")
                time.sleep(retry_delay)
            else:
                print("Max retries reached. Unable to connect.")
                return None

ser = connect_serial(port, max_retries, retry_delay)
if ser is None:
    exit(1)

# Load packs
def load_packs():
    packs = []
    pack_folders = sorted(glob.glob('packs/*'))
    default_index = pack_folders.index('packs/default') if 'packs/default' in pack_folders else 0
    pack_folders = pack_folders[default_index:] + pack_folders[:default_index]
    
    for folder in pack_folders:
        pack = {
            'B1': os.path.join(folder, 'amen.wav'),
            'T1': os.path.join(folder, 'morph.wav'),
            'T2': os.path.join(folder, 'vocal.wav')
        }
        packs.append(pack)
    return packs

packs = load_packs()
current_pack_index = 0

# Load sounds for the current pack
def load_sounds(pack):
    sounds = {}
    for key, file in pack.items():
        if os.path.exists(file):
            sounds[key] = pygame.mixer.Sound(file)
            print(f"Loaded {file}")
        else:
            print(f"Warning: {file} not found")
            sounds[key] = None
    return sounds

sounds = load_sounds(packs[current_pack_index])

# Keep track of which sounds are playing
sound_channels = {key: pygame.mixer.Channel(i) for i, key in enumerate(sounds)}
sound_states = {key: False for key in sounds}

# Knob state
knob_state = False

print("Listening for Arduino input...")

while True:
    try:
        if ser.in_waiting:
            message = ser.readline().decode('utf-8').strip()
            print(f"Received message: {message}")
            if ':' in message:
                input_key, state = message.split(':')
                if input_key == "KNOB":
                    knob_state = (state == "1")
                    print(f"Knob state: {'On' if knob_state else 'Off'}")
                elif input_key in sounds and sounds[input_key] is not None:
                    if state == '1' or (knob_state and sound_states[input_key]):
                        # Start or continue looping the sound
                        if not sound_channels[input_key].get_busy():
                            sound_channels[input_key].play(sounds[input_key], loops=-1)
                        sound_states[input_key] = True
                        print(f"Playing {input_key} (looping)")
                    elif state == '0' and not knob_state:
                        # Stop the sound
                        sound_channels[input_key].stop()
                        sound_states[input_key] = False
                        print(f"Stopped playing {input_key}")
                    
                    print(f"{input_key}: {'Playing' if sound_states[input_key] else 'Stopped'}")
            elif message == "PACK_SWITCH":
                current_pack_index = (current_pack_index + 1) % len(packs)
                sounds = load_sounds(packs[current_pack_index])
                print(f"Switched to pack: {os.path.basename(os.path.dirname(packs[current_pack_index]['B1']))}")
    except serial.SerialException as e:
        print(f"Serial connection lost: {e}")
        ser.close()
        ser = connect_serial(port, max_retries, retry_delay)
        if ser is None:
            break
    except KeyboardInterrupt:
        print("Program terminated by user")
        break
    except Exception as e:
        print(f"An unexpected error occurred: {e}")
        print(f"Error details: {type(e).__name__}, {str(e)}")

# Clean up
if ser and ser.is_open:
    ser.close()
pygame.mixer.quit()
```