Makestreme
Published © GPL3+

A Piano Doorbell That Sounds Beautiful!

This is a beautiful looking and sounding doorbell with piano keys that will take your visitors' experience to a whole new level

IntermediateFull instructions provided10 hours1,081
A Piano Doorbell That Sounds Beautiful!

Things used in this project

Hardware components

Seeed Studio esp32s3
×1
Limit Switch, 5 A
Limit Switch, 5 A
×5
Resistor 10k ohm
Resistor 10k ohm
×5
Through Hole Resistor, 470 ohm
Through Hole Resistor, 470 ohm
×1

Software apps and online services

Arduino IDE
Arduino IDE
Audacity

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Custom parts and enclosures

White keys

Sketchfab still processing.

Black key

Print two of these

Sketchfab still processing.

Baseplate

Sketchfab still processing.

Frame

Sketchfab still processing.

Schematics

Circuit

Code

Main arduino code

Arduino
#include <Arduino.h>
#include "driver/i2s.h"

// Include your converted 16-bit PCM .h files
#include "A4.h"
#include "F5.h"
#include "C5.h"
#include "Db4.h"
#include "Eb5.h"

#define SAMPLE_RATE 16000
#define I2S_NUM I2S_NUM_0

// For analog output using built-in DAC emulation mode
// These are the pins that will output the differential signal
#define I2S_DATA_OUT_PIN D1  // Connect to amplifier input

void setup() {
  Serial.begin(115200);
  
  // Initialize I2S in PDM mode (for analog output without external DAC)
  i2s_config_t i2s_config = {
    .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_PDM),
    .sample_rate = SAMPLE_RATE * 2, // PDM requires double sample rate
    .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
    .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
    .communication_format = I2S_COMM_FORMAT_STAND_I2S,
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count = 8,
    .dma_buf_len = 64,
    .use_apll = false,
    .tx_desc_auto_clear = true,
    .fixed_mclk = 0
  };
  
  i2s_pin_config_t pin_config = {
    .bck_io_num = I2S_PIN_NO_CHANGE,
    .ws_io_num = I2S_PIN_NO_CHANGE,
    .data_out_num = I2S_DATA_OUT_PIN,
    .data_in_num = I2S_PIN_NO_CHANGE
  };
  
  i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
  i2s_set_pin(I2S_NUM, &pin_config);

  pinMode(D2, INPUT);
  
  Serial.println("I2S PDM initialized");
}

// Function to play a 16-bit PCM sound with full resolution
void playSound(const int16_t* sound, unsigned int length) {
  Serial.println("Playing sound...");
  
  size_t bytes_written;
  
  // Directly write the 16-bit samples to I2S
  i2s_write(I2S_NUM, (const char*)sound, length * 2, &bytes_written, portMAX_DELAY);
  
  // Wait for playback to complete
  i2s_zero_dma_buffer(I2S_NUM);
  
  Serial.println("Finished playing.");
}

void loop() {
  int key = analogRead(D2);

  if(key > 4000){
  playSound(A4_raw, A4_raw_len / 2);  // Divide by 2 if length is in bytes
  delay(2000);
  }
  
  else if(key > 3000){
  playSound(F5_raw, F5_raw_len / 2);
  delay(2000);
  }
  
  else if(key > 2000){
  playSound(C5_raw, C5_raw_len / 2);
  delay(2000);
  }
  
  else if(key > 1500){
  playSound(Db4_raw, Db4_raw_len / 2);
  delay(2000);
  }
  
  else{
  playSound(Eb5_raw, Eb5_raw_len / 2);
  delay(2000);
  }
  delay(200);
}

Python code to convert audio

Python
import numpy as np
filename = "A4"
# Read the 16-bit PCM raw file
with open(f"{filename}.raw", "rb") as f:
data = np.frombuffer (f.read(), dtype=np.int16) # Read as 16-bit PCM
# Write as a C header file
with open(f" {filename} .h", "w") as f:
    f.write(f"#ifndef (filename.upper()}_H\n#define {filename.upper()}_H\n\n")
    f.write("#include <Arduino.h>\n\n")
    f.write("const int16_t %s_raw[] PROGMEM = {"%filename)
    f.write(", ".join(str(sample) for sample in data))
    f.write("};\n")
    f.write(f" const unsigned int {filename}_raw_len = {len(data) * 2};\n") # Length in bytes f.write("#endif")

Credits

Makestreme
9 projects • 10 followers
I make DIY projects that are fun and interesting! An engineer by profession :) youtube.com/@makestreme

Comments