
What you'll build
This guide walks you through creating a laser harp synthesizer with an ESP32, a set of light-dependent resistors arranged in a row, a piezo speaker, and an OLED display that visualizes which notes are playing. Each LDR sits beneath a beam of light -- from small laser diodes or bright LEDs mounted opposite -- and when you break a beam with your hand, the ESP32 detects the drop in light level and triggers the corresponding musical note through the speaker. Multiple beams can be broken simultaneously to play chords, and the OLED renders a real-time staff notation showing which notes are active.
Building a laser harp teaches you analog sensor reading and calibration on the ESP32's ADC channels, threshold-based event detection that adapts to ambient lighting conditions, tone generation using the ESP32's LEDC PWM peripheral, and simultaneous multi-channel output. You will calibrate each LDR at startup to establish baseline light levels, implement hysteresis to prevent flickering triggers near the threshold, and generate musically accurate frequencies for a full octave of notes. The project also introduces basic concepts of digital audio -- frequency ratios between semitones, square-wave harmonics, and how duty cycle affects timbre.
When complete you will have a playable musical instrument that feels theatrical and impressive despite its simple construction. The code is organized so you can swap the pentatonic scale for any scale you like, add octave shifting with a dedicated button, or replace the piezo with an I2S DAC and amplifier for richer sound. Pair it with the mood lamp project to add synchronized LED animations that respond to the notes being played, creating a full audio-visual performance piece that is perfect for maker faires and classroom demonstrations.
Wiring diagram
Wiring diagram
Components needed
Assembly
Place beam channels
Connect three LDR channels to GPIO34, GPIO35, and GPIO32.
- Calibrate threshold with room lighting before mounting lasers.
Add sound and display
Wire piezo to GPIO25 and OLED on GPIO21/22 for live feedback.
- Use narrow laser beams for clearer channel separation.
Pin assignments
| Pin | Connection | Type |
|---|---|---|
| GPIO 34 | laser-ldr-1 LDR1 | ANALOG |
| GPIO 35 | laser-ldr-1 LDR2 | ANALOG |
| GPIO 32 | laser-ldr-1 LDR3 | ANALOG |
| GPIO 25 | laser-speaker-1 SIG | PWM |
| GPIO 21 | laser-oled-1 SDA | I2C |
| GPIO 22 | laser-oled-1 SCL | I2C |
Code
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#define LDR_1 34
#define LDR_2 35
#define LDR_3 32
#define BUZZER_PIN 25
#define SDA_PIN 21
#define SCL_PIN 22
Adafruit_SSD1306 display(128, 64, &Wire, -1);
int threshold = 1800;
void setup() {
Wire.begin(SDA_PIN, SCL_PIN);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
pinMode(BUZZER_PIN, OUTPUT);
}
void loop() {
int n1 = analogRead(LDR_1);
int n2 = analogRead(LDR_2);
int n3 = analogRead(LDR_3);
int note = 0;
if (n1 < threshold) note = 523;
else if (n2 < threshold) note = 659;
else if (n3 < threshold) note = 784;
if (note > 0) tone(BUZZER_PIN, note, 30);
display.clearDisplay();
display.setCursor(0, 0);
display.println("Laser Harp");
display.printf("L1:%d L2:%d L3:%d\n", n1, n2, n3);
display.printf("Note: %d Hz", note);
display.display();
delay(30);
}
// Run this and build other cool things at schematik.ioReady to build this?
Open this project in Schematik to get the full wiring diagram, pin assignments, and deployable code for the Laser Harp Synth.
Open in Schematik →


