When I first started thinking about a virtual backing band, I did not want to write a synthesizer from scratch. I just wanted to see if I could write something that parsed a chord sheet and played the chords in real time.
For the initial prototype, I built a tool called Strudel Lab. It was powered by Strudel, a JavaScript live-coding environment based on TidalCycles.
The Strudel Experiment
Strudel was a great way to validate the idea. It made scheduling patterns extremely fast. I could write a few lines of code to represent a drum beat or a chord progression, and Strudel would loop it. It proved that the parser worked and that a browser-based jam room was actually possible.
However, it had one massive drawback: it sounded like a flat, sterile MIDI synthesizer.
If you are trying to sing along with a band, the vibe matters. A computer playing perfect, beep-boop MIDI notes does not feel like a band. It feels like a metronome with pitches.
To make the app feel like a real garage jam, I needed three things that Strudel could not easily provide:
- High-fidelity acoustic and electric instrument samples instead of synthesized soundwaves.
- Micro-variations in timing and velocity so the band does not sound robotic.
- Simple, client-side caching so the samples load instantly without hitting external CDNs every time you open a page.
Transitioning to Tone.js and Sample Maps
I decided to drop Strudel and rebuild the audio layer using Tone.js.
Tone.js gives me direct access to the Web Audio API while providing a clean Tone.Sampler class. Instead of generating sounds programmatically, I mapped actual audio samples (recorded notes from a Salamander Piano and organic acoustic/electric guitar strums) to specific pitches.
This change immediately resolved the sound quality issue. When the virtual guitarist plays a D minor chord, you are hearing real strings resonating, not an oscillator.
Introducing the Humanizer
To break the robotic grid, I wrote a lightweight humanizer utility. It applies a small random offset (between 8 and 15 milliseconds) to note start times, and varies the velocity (volume) of each stroke by about 5 to 10 percent.
Drums are kept relatively tight to act as the clock, while guitars are given a slightly looser feel.
The repo is now set up with this new audio architecture. The difference in sound quality is night and day. Now that the virtual band actually sounds like a band, the next step is building a parser that can read any messy chord sheet from the web and translate it into clean instructions for the engine.