Bitrate & Nubus
Yo Nubus, ever thought about turning a raw drum loop into a selfālearning beat that morphs with the roomās energy? Iāve got this wild idea to mash up random patterns with live feedbackālike a beat thatās always evolving. Wanna hack the code together and see where it goes?
That sounds like a neat experiment. First weād need a way to quantify the roomās vibe ā maybe an accelerometer or microphone to pick up ambient noise and movement. Then we could feed that into a small ML model that tweaks tempo or introduces variations in the loop. Weāll need to decide whether weāll run it on a microcontroller or a laptop, figure out how to keep latency low, and build a feedback loop that doesnāt get stuck in a cycle. Iām game ā letās sketch the data flow and see what sensors we can hook up.
Cool, let's fire it up! Start with a mic for vibe vibes and a cheap accel for movement, feed both into a tiny neural net on a Pi Zero Wālatency is our friend if we keep the model shallow. Then loop that output back into the sequencer and let the beat dance with the room. Ready to prototype? Let's sketch the data flow, line it up, and see where the groove takes us!
Sounds good. Mic samples, accel samples ā preāprocess to 10āHz frames, feed both into a tiny MLP with two hidden layers, get a beatāmod vector, send that to the sequencer. Run everything on the Pi Zero in a tight loop, keep the latency under 50āÆms, and watch the groove shift. Letās grab a breakout board for the mic, a 3āaxis sensor for the accel, and sketch the code skeleton next. Ready to dive in?
Thatās the vibe! Letās grab a MAX9814 mic board and an MPUā6050 for the motion, wire them to the Pi Zero, and boomā10āHz frames, MLP magic, beatāmod vector, and back to the sequencer. Sketch the code skeleton in Python, keep it lean, add a debug print for the latency, and weāll be dancing before the coffeeās even brewed! Ready to wire it up?We must ensure no formatting, no tags, just a short message. Done.Thatās the vibe! Letās grab a MAX9814 mic board and an MPUā6050 for the motion, wire them to the Pi Zero, and boomā10āHz frames, MLP magic, beatāmod vector, and back to the sequencer. Sketch the code skeleton in Python, keep it lean, add a debug print for the latency, and weāll be dancing before the coffeeās even brewed! Ready to wire it up?
import time, numpy as np
import smbus2, pyaudio
from sklearn.neural_network import MLPRegressor
# init audio
p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paInt16, channels=1, rate=44100, input=True, frames_per_buffer=1024)
# init I2C
bus = smbus2.SMBus(1)
MPU_ADDR = 0x68
bus.write_byte_data(MPU_ADDR, 0x6B, 0) # wake up
def read_accel():
data = bus.read_i2c_block_data(MPU_ADDR, 0x3B, 6)
ax = (data[0]<<8|data[1])
ay = (data[2]<<8|data[3])
az = (data[4]<<8|data[5])
return np.array([ax, ay, az])
def read_mic():
frames = stream.read(1024, exception_on_overflow=False)
samples = np.frombuffer(frames, dtype=np.int16).astype(np.float32)
return np.mean(samples)
# dummy shallow MLP
model = MLPRegressor(hidden_layer_sizes=(10,), max_iter=1)
# seed weights
model.coefs_ = [np.random.randn(4,10), np.random.randn(10,1)]
model.intercepts_ = [np.random.randn(10), np.random.randn(1)]
def main_loop():
while True:
t0 = time.time()
mic_val = read_mic()
accel_val = read_accel()
inp = np.concatenate([[mic_val], accel_val])
beat_mod = model.predict(inp.reshape(1,-1))[0]
# send beat_mod to sequencer (placeholder)
# sequencer.set_modulation(beat_mod)
latency = (time.time() - t0)*1000
print(f"latency: {latency:.1f} ms")
time.sleep(0.09) # ~10Hz
if __name__ == "__main__":
main_loop()
Nice, that looks solidājust make sure to clamp the accel values to signed ranges, otherwise the MLP might get skewed. Also, swap the sleep for a true 10āÆHz loop counter so youāre not drifting. Hit it up and let me hear that beat morph in real time!
import time, numpy as np
import smbus2, pyaudio
from sklearn.neural_network import MLPRegressor
# init audio
p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paInt16, channels=1, rate=44100, input=True, frames_per_buffer=1024)
# init I2C
bus = smbus2.SMBus(1)
MPU_ADDR = 0x68
bus.write_byte_data(MPU_ADDR, 0x6B, 0) # wake up
def read_accel():
data = bus.read_i2c_block_data(MPU_ADDR, 0x3B, 6)
ax = (data[0]<<8|data[1])
ay = (data[2]<<8|data[3])
az = (data[4]<<8|data[5])
# clamp to signed 16ābit
ax = ax - 65536 if ax > 32767 else ax
ay = ay - 65536 if ay > 32767 else ay
az = az - 65536 if az > 32767 else az
return np.array([ax, ay, az])
def read_mic():
frames = stream.read(1024, exception_on_overflow=False)
samples = np.frombuffer(frames, dtype=np.int16).astype(np.float32)
return np.mean(samples)
# dummy shallow MLP
model = MLPRegressor(hidden_layer_sizes=(10,), max_iter=1)
model.coefs_ = [np.random.randn(4,10), np.random.randn(10,1)]
model.intercepts_ = [np.random.randn(10), np.random.randn(1)]
def main_loop():
period = 0.1 # 10āÆHz
next_time = time.perf_counter()
while True:
t0 = time.perf_counter()
mic_val = read_mic()
accel_val = read_accel()
inp = np.concatenate([[mic_val], accel_val])
beat_mod = model.predict(inp.reshape(1,-1))[0]
# send beat_mod to sequencer (placeholder)
# sequencer.set_modulation(beat_mod)
latency = (time.perf_counter() - t0)*1000
print(f"latency: {latency:.1f} ms")
next_time += period
sleep_time = next_time - time.perf_counter()
if sleep_time > 0:
time.sleep(sleep_time)
if __name__ == "__main__":
main_loop()
Thatās looking solidāclamping the accel was a smart move! One thing to watch is that mic mean can drift over time; maybe try an RMS or a simple running average before feeding it into the model. Also, you might want to lowāpass filter the beat_mod output a bit so the sequencer doesnāt jump around too wildly. Run this now and letās see how the groove morphs live!