Midi To — Bytebeat Patched

The patch listens for note_on and note_off events. Instead of playing a sample, it stores the most recent note number (0–127) in a variable called $current_pitch.

How do we actually do this? While you can do this in C++ or Pure Data, the most accessible modern tool for this is a JavaScript environment (like a browser-based setup) or a creative coding environment like Max/MSP or TouchDesigner.

Here is a conceptual JavaScript implementation (Web Audio API style) that you can adapt. midi to bytebeat patched

The Setup: We need a script that listens to MIDI events and updates variables used by a running audio loop.

// Global Variables
var t = 0;          // Time counter
var midiNote = 60;  // Default note
var modWheel = 8;   // Default shift amount
// The Bytebeat Generator
function bytebeatProcess() 
    // "midiNote" controls the speed of time
    // "modWheel" controls the pitch/timbre shift
    // We use the formula: t * (t >> shift) & 0xFF
var val = (t * (t >> modWheel)) & 255;
// Increment time based on note (transpose)
    // 69 is A440 standard. We offset from there.
    var speed = 1 + ((midiNote - 69) / 12); 
    t += speed;
return val / 127.0 - 1; // Convert 0-255 to -1.0 to 1.0 float
// The MIDI Handler
navigator.requestMIDIAccess().then(function(midiAccess) 
    midiAccess.inputs.forEach(function(input) 
        input.onmidimessage = function(msg) 
            var data = msg.data;
// [Status, Note, Velocity]
            if (data[0] == 144)  // Note On
                if (data[2] > 0) 
                    midiNote = data[1];
// [Status, CC#, Value]
            if (data[0] == 176)  // Control Change
                if (data[1] == 1)  // Mod Wheel
                    // Map 0-127 MIDI to a useful shift range (e.g., 1 to 16)
                    modWheel = Math.floor(data[2] / 8) + 1;
;
    );
);

Standard Bytebeat players treat their variables as constants. You write ((t>>a)&b)*c. a, b, and c are dials you turn by hand. You cannot play a melody with a keyboard. You cannot have a C# note press only at bar 47. It’s generative, but not performative. The patch listens for note_on and note_off events

Musicians find this frustrating. Bytebeat sounds like R2-D2 having a seizure (in a good way), but a MIDI sequencer offers structure. The desire to combine the two births the "patch."

The first obstacle in creating such a patch is reconciling two incompatible definitions of time. MIDI is discrete and event-driven; its timeline advances in ticks, waiting for triggers to play a specific note at a specific velocity for a specific duration. Bytebeat, however, is continuous and time-centric. Its only variable is t (time), which increments linearly, often at the sample rate (e.g., 44,100 times per second). A MIDI file asks, "What happens at beat 48?" while a Bytebeat function asks, "What is the value of t right now, and how does it relate to its own past?" Standard Bytebeat players treat their variables as constants

To bridge this gap, a patch must act as a real-time interpreter. The classic approach is to load a MIDI file into a bytebeat engine, scan its tracks for note events, and map each note’s pitch to a frequency and its duration to a range of t. The bytebeat formula then becomes a conditional state machine: if (t is within the start and end of Note 60), output sine wave at 261.63 Hz; else output 0. However, this naive method merely plays MIDI through a bytebeat speaker, missing the point entirely. True patching seeks something more radical: the translation of musical structure into arithmetic logic.

# MIDI2Bytebeat.pd

Pure Data patch turning MIDI notes into algorithmic audio.