Project 38: Audio Beat Stamps 🥁¶
Difficulty: 🔴 Advanced
Run cells top to bottom. Each step builds on the previous one and saves real files under outputs/audio_beat_stamps/.
In [1]:
# Install dependencies for this project (safe to re-run)
import sys
!{sys.executable} -m pip install pillow numpy matplotlib wordcloud qrcode[pil] python-barcode fpdf2 jinja2 folium plotly pandas scipy ipywidgets -q
Skipping pip install (already installed)
In [2]:
# Interactive Jupyter setup — run this cell first
%matplotlib inline
from pathlib import Path
from IPython.display import display, Image as IPImage, HTML, Markdown, Audio, IFrame
OUTPUT_DIR = Path("outputs") / "audio_beat_stamps"
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
print(f"✅ Outputs folder: {OUTPUT_DIR.resolve()}")
✅ Outputs folder: C:\Users\Hansel Yan\Projects\CodeItAll\outputs\audio_beat_stamps
Step 1 — Synthesize kick + hihat hits¶
In [3]:
import numpy as np
# 🎛️ TWEAK THESE
BPM = 96
BARS = 2
SR = 22050
KICK_PAT = "x---x---x---x---"
HAT_PAT = "x-x-x-x-x-x-x-x-"
def env_noise(n, decay=0.001):
t = np.arange(n) / SR
return (np.random.randn(n) * np.exp(-t / decay)).astype(np.float64)
def kick(n):
t = np.arange(n) / SR
freq = np.linspace(140, 40, n)
return 0.9 * np.sin(2 * np.pi * freq * t) * np.exp(-t * 8)
step = int(SR * 60 / BPM / 4)
total = step * 16 * BARS
mix = np.zeros(total)
rng = np.random.default_rng(0)
def stamp(pattern, sound_fn, gain=1.0):
for bar in range(BARS):
for i, ch in enumerate(pattern):
if ch.lower() == "x":
pos = (bar * 16 + i) * step
burst = sound_fn(step)
end = min(pos + len(burst), total)
mix[pos:end] += gain * burst[: end - pos]
stamp(KICK_PAT, kick, 0.9)
stamp(HAT_PAT, lambda n: env_noise(n, 0.004), 0.25)
mix = mix / max(1e-9, np.max(np.abs(mix)))
print("Audio samples:", len(mix), "duration sec:", len(mix) / SR)
Audio samples: 110240 duration sec: 4.999546485260771
Step 2 — Write WAV + beat plot¶
In [4]:
import matplotlib.pyplot as plt
from scipy.io import wavfile
audio = (mix * 32767).astype(np.int16)
wav_path = OUTPUT_DIR / "beat_stamps.wav"
wavfile.write(str(wav_path), SR, audio)
fig, ax = plt.subplots(figsize=(10, 3))
ax.plot(mix[: SR], color="#111111", linewidth=0.6)
ax.set_title("Audio Beat Stamps — first second")
ax.set_yticks([])
fig.tight_layout()
png = OUTPUT_DIR / "beat_waveform.png"
fig.savefig(png, dpi=140)
plt.show()
print(f"Saved {wav_path.name} and {png.name}")
Saved beat_stamps.wav and beat_waveform.png
✅ Project complete¶
Check your output folder: outputs/audio_beat_stamps/
Next: Project 39: Choropleth Lite · Index