Skip to content

oceaneboulais/singBubbles

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 

Repository files navigation

🫧 Bubble Breath

An interactive visual art installation that generates underwater bubble effects synchronized with your voice and facial movements using computer vision and audio processing.

🎯 What It Does

Bubble Breath uses your webcam and microphone to create an immersive underwater experience:

  • Detects your face and mouth position in real-time
  • Spawns colorful bubbles when you speak, sing, or blow
  • Color maps to pitch — low notes produce deep blue bubbles, high notes produce vivid yellow ones
  • Bubble trail — bubbles gently follow your face as you move while making sound
  • Controls bubble rise speed from glacial drift to racing float
  • Shows live frequency (Hz) and volume in the HUD
  • Adds animated underwater caustic light effects
  • Supports multiple faces simultaneously (up to 4)

📋 Requirements

Python Version

  • Python 3.7 or higher

Dependencies

Install all required packages using pip:

pip install opencv-python mediapipe numpy sounddevice

Or if you have a requirements.txt:

pip install -r requirements.txt

Hardware Requirements

  • Webcam: Any USB or built-in camera
  • Microphone: Built-in or external microphone
  • Recommended: Good lighting for optimal face detection

🚀 Quick Start

  1. Clone or download this repository
git clone https://github.com/oceaneboulais/singBubbles.git
cd singBubbles
  1. Install dependencies
pip install opencv-python mediapipe numpy sounddevice
  1. Run the program
python main.py
  1. Interact with the program
    • Position your face in the camera frame
    • Speak, sing, blow, or make sounds to generate bubbles
    • Press Q to quit

🎛️ Tunable Parameters

All tunable parameters are located in the main() function under the "Tunable knobs" section (around line 166-169). You can adjust these to customize the bubble effect:

Core Parameters

SPAWN_THRESHOLD

Default: 0.012
Range: 0.001 to 0.1
What it does: Minimum microphone loudness required to spawn bubbles

Examples:

  • 0.005 - Very sensitive, bubbles spawn from quiet breath
  • 0.012 - Medium sensitivity (default), normal speaking volume
  • 0.025 - Less sensitive, requires louder sounds
  • 0.050 - Very loud sounds only (shouting, blowing hard)

Effect: Lower values make it spawn bubbles more easily; higher values require louder sounds.


MAX_BUBBLES

Default: 30
Range: 10 to 200
What it does: Maximum number of bubbles allowed on screen simultaneously

Examples:

  • 15 - Sparse, minimal bubbles (better performance on slower computers)
  • 30 - Moderate bubble density (default)
  • 60 - Dense bubble field (more dramatic effect)
  • 100 - Very dense, chaotic bubble storm (may slow down on weaker systems)

Effect: Higher values create more visual density but may impact performance.


BUBBLE_TRAIL

Default: True
Options: True or False
What it does: Makes bubbles gently follow your face as you move while making sound

Examples:

  • True - Bubbles trail behind your face, creating flowing patterns when you move
  • False - Bubbles float straight up independently of face movement

Effect: When enabled, bubbles have a subtle attraction to the mouth position, creating a flowing trail effect when you move your head while speaking or singing.


BUBBLE_RISE_SPEED

Default: 0.50
Range: 0.1 to 2.0
What it does: Scales how fast every bubble floats upward each frame

How it works (pseudocode):

base_vy  = random(−3.2, −1.2)       ← pixels/frame; negative = upward in screen coords
vy       = base_vy × BUBBLE_RISE_SPEED
each frame: bubble.y += bubble.vy   ← more-negative vy = moves up faster

Examples:

Value Effect
0.10 Glacial — barely moves, meditative
0.30 Slow, gentle drift
0.50 Default — dreamy underwater float
1.00 Original full speed
1.50 Noticeably energetic
2.00 Racing upward — chaotic energy

Effect: At lower values bubbles linger on screen longer and feel weightless. Higher values create a more energetic, fizzy look.


SHOW_FREQUENCY

Default: True
Options: True or False
What it does: Shows the detected dominant frequency (Hz) in the bottom-left HUD

Effect: When enabled, displays the live pitch of your voice in cyan. Useful for understanding the color-to-pitch mapping and for tuning your performance.


Advanced Bubble Customization

You can modify these properties in the Bubble class (__init__ method, around line 30-44):

Bubble Size

self.radius = random.randint(8, 28) + int(amplitude * 180)
  • random.randint(8, 28) - Base size range (8-28 pixels)
  • int(amplitude * 180) - Loudness bonus (louder = bigger)

Examples:

  • Small bubbles: random.randint(5, 15) + int(amplitude * 100)
  • Large bubbles: random.randint(15, 40) + int(amplitude * 250)
  • Uniform size: 20 (no randomness)

Bubble Speed & Movement

Note: Prefer adjusting BUBBLE_RISE_SPEED in the tunable knobs section rather than editing the raw velocity values here — it's the intended high-level control.

The raw base velocities (before rise-speed scaling) are:

self.vx = random.uniform(-1.2, 1.2)      # Horizontal drift
self.vy = random.uniform(-3.2, -1.2)     # Upward velocity (scaled by BUBBLE_RISE_SPEED)

Examples:

  • No horizontal drift: self.vx = 0
  • More horizontal movement: self.vx = random.uniform(-3.0, 3.0)

Bubble Opacity

self.alpha = random.uniform(0.25, 0.55)

Default: 0.25 to 0.55 (moderately transparent)

Examples:

  • More transparent: random.uniform(0.15, 0.40)
  • More opaque: random.uniform(0.40, 0.75)
  • Fully opaque: random.uniform(0.75, 0.95)

Bubble Lifetime

self.lifetime = random.randint(90, 180)  # frames (at ~30 fps = 3-6 seconds)

Examples:

  • Short-lived bubbles: random.randint(45, 90) (~1.5-3 seconds)
  • Long-lived bubbles: random.randint(150, 300) (~5-10 seconds)
  • Very persistent: random.randint(300, 600) (~10-20 seconds)

Bubble Colors — Frequency Mapping

Bubble color is automatically driven by pitch. You don't need to set a hue manually; it's computed from the detected microphone frequency:

pseudocode:
  t        = clamp((frequency − 60) / (1200 − 60), 0, 1)   ← normalise Hz to 0-1
  hue      = 0.62 − t × 0.48                                ← blue (0.62) → yellow (0.14)
  hue     += random jitter ±0.03                             ← keeps individual bubbles unique
  sat      = 0.35 + t × 0.30                                ← pastels at low pitch, vivid at high

Frequency → color table:

Pitch (Hz) Color
~60 Hz — very low / bass Deep blue
~300 Hz — speaking voice Blue-cyan
~600 Hz — mid singing Cyan-green
~900 Hz — high singing Green-gold
~1200 Hz — soprano / whistle Vivid yellow

To override and use a fixed palette instead, replace the frequency-mapping block in Bubble.__init__ with:

h = random.uniform(0.50, 0.72)   # fixed blue-violet palette
r, g, b = colorsys.hsv_to_rgb(h, 0.35, 1.0)
self.color = (int(b*255), int(g*255), int(r*255))

Hue reference (0.0 → 1.0):

  • 0.00–0.10 Red → orange
  • 0.10–0.17 Yellow
  • 0.17–0.33 Green
  • 0.33–0.50 Cyan
  • 0.50–0.72 Blue → violet
  • 0.72–0.83 Magenta
  • 0.83–1.00 Pink → red

Wobble Effect

self.wobble_speed = random.uniform(0.025, 0.06)  # Oscillation speed
# Applied in update():
self.x += self.vx + math.sin(self.wobble_phase) * 0.7  # 0.7 = wobble amount

Examples:

  • Gentle wobble: 0.70.3
  • Extreme wobble: 0.72.0
  • No wobble: 0.70.0
  • Fast oscillation: random.uniform(0.08, 0.15)

Trail Strength (when BUBBLE_TRAIL = True)

trail_strength = 0.08  # In update() method, around line 56

Examples:

  • Subtle follow: 0.03 - Bubbles barely track the face
  • Strong follow: 0.15 - Bubbles stick closely to mouth
  • Default: 0.08 - Moderate trailing effect

Camera Settings

In the main() function:

cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)

Common resolutions:

  • 640 x 480 - Low quality, best performance
  • 1280 x 720 - HD (default)
  • 1920 x 1080 - Full HD (may reduce frame rate)

Face Detection Settings

face_mesh = mp_fm.FaceMesh(
    max_num_faces=4,              # Number of faces to track
    min_detection_confidence=0.5,  # Detection threshold
    min_tracking_confidence=0.5,   # Tracking threshold
)

Examples:

  • Single person: max_num_faces=1
  • Group performance: max_num_faces=6
  • More sensitive detection: min_detection_confidence=0.3
  • More strict detection: min_detection_confidence=0.7

Underwater Effect Customization

Water Tint Color

In draw_water_overlay() function (~line 117):

tint = np.full_like(frame, (52, 28, 6), dtype=np.uint8)  # BGR: blue=52, green=28, red=6

Examples:

  • Deep ocean blue: (80, 40, 10)
  • Turquoise pool: (60, 60, 30)
  • Green swamp: (30, 60, 20)
  • Purple twilight: (70, 30, 50)

Caustic Intensity

caus_bgr = np.stack([
    (caustic * 58).astype(np.uint8),  # Blue channel
    (caustic * 46).astype(np.uint8),  # Green channel
    (caustic * 20).astype(np.uint8),  # Red channel
], axis=2)

Examples:

  • Brighter caustics: Multiply by 90, 70, 30
  • Dimmer caustics: Multiply by 30, 20, 10
  • Warmer caustics: Multiply by 30, 50, 80 (more red)

💡 Creative Tips & Tricks

Effect Presets

🌊 Gentle Ocean Breeze

SPAWN_THRESHOLD   = 0.008
MAX_BUBBLES       = 20
BUBBLE_TRAIL      = True
BUBBLE_RISE_SPEED = 0.30   # slow dream-like drift
# In Bubble class:
self.alpha = random.uniform(0.15, 0.35)

🎤 Concert Vocalist

SPAWN_THRESHOLD   = 0.015
MAX_BUBBLES       = 50
BUBBLE_TRAIL      = True
BUBBLE_RISE_SPEED = 0.70   # energetic but not frantic
# In Bubble class:
self.radius = random.randint(12, 35) + int(amplitude * 220)
self.alpha  = random.uniform(0.35, 0.65)

💥 Bubble Storm

SPAWN_THRESHOLD   = 0.005
MAX_BUBBLES       = 100
BUBBLE_TRAIL      = False
BUBBLE_RISE_SPEED = 1.60   # racing upward
# In Bubble class:
self.lifetime = random.randint(40, 100)
self.vx       = random.uniform(-3.0, 3.0)

🧘 Zen Meditation

SPAWN_THRESHOLD   = 0.010
MAX_BUBBLES       = 15
BUBBLE_TRAIL      = True
BUBBLE_RISE_SPEED = 0.15   # glacial float
# In Bubble class:
self.alpha = random.uniform(0.20, 0.40)
# note: low frequencies = blue, which suits the peaceful mood

🐛 Troubleshooting

No bubbles appearing

  • Check your microphone is connected and working
  • Lower SPAWN_THRESHOLD to make it more sensitive
  • Speak louder or blow into the microphone
  • Check microphone permissions on your system

Face not detected

  • Ensure good lighting on your face
  • Center yourself in the camera frame
  • Try adjusting min_detection_confidence to a lower value (e.g., 0.3)

Performance issues / Low frame rate

  • Reduce MAX_BUBBLES to a lower number (e.g., 15)
  • Lower camera resolution to 640x480
  • Close other applications
  • Set max_num_faces=1 if tracking only yourself

Bubbles too transparent

  • Increase opacity range: self.alpha = random.uniform(0.40, 0.75)

Bubbles moving too fast/slow

  • Adjust self.vy in the Bubble class
  • Faster: random.uniform(-5.0, -2.5)
  • Slower: random.uniform(-1.5, -0.5)

🎨 Technical Details

How It Works

  1. Face Detection: MediaPipe FaceMesh detects facial landmarks in real-time
  2. Mouth Tracking: Specific landmarks around the mouth are averaged to find the bubble spawn point
  3. Audio Analysis: Microphone input is analyzed for RMS (root mean square) amplitude
  4. Bubble Spawning: When audio exceeds threshold, bubbles are created near the mouth
  5. Physics Simulation: Each bubble has velocity, acceleration, wobble, and fade-out behavior
  6. Trail Effect: If enabled, bubbles gently accelerate toward the current mouth position
  7. Underwater Overlay: Sine wave caustics and color tinting create an underwater atmosphere

Frame Rate

  • Target: ~30 FPS
  • Actual FPS depends on your hardware and parameter settings

Audio Processing

  • Sample Rate: 44.1 kHz (CD quality)
  • Block Size: 512 samples (~12ms latency)
  • Threading: Audio runs in background thread for smooth performance

📝 License

Feel free to use, modify, and share this project!


🙏 Credits

Built with:

  • OpenCV - Computer vision and image processing
  • MediaPipe - Face mesh detection by Google
  • NumPy - Numerical computing
  • SoundDevice - Real-time audio I/O

🤝 Contributing

Feel free to fork this project and experiment! Some ideas:

  • Add different bubble shapes (hearts, stars)
  • Implement particle emitters for different sounds (low vs high pitch)
  • Add recording/export functionality
  • Create beat detection for music synchronization
  • Implement gesture controls

Enjoy creating bubble art! 🫧✨

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages