← All Stories
JMOVE·February 12, 2026Feb 12, 2026·16 min read

Walking Bass from First Principles

Inside walkingBass.ts: 1,831 lines of contour-based interpolation, per-style approach vocabularies, two-bar phrasing bias, and the question of why Dorian mode is the only correct answer for minor sevenths

Before there were bass generators, there were bass players. And before bass players codified the walking bass line into a teachable system, they learned it the only way anyone learned anything in jazz: by listening. Paul Chambers listened to Ray Brown. Ron Carter listened to Paul Chambers. Christian McBride listened to Ron Carter. Each generation absorbed the tradition, internalized its logic, and added something personal. The walking bass line as we know it today is the product of a seventy-year conversation between musicians who mostly never discussed it in words.

Writing a bass line generator means joining that conversation - translating what great bass players do instinctively into rules explicit enough for a computer to follow. The result is walkingBass.ts: 1,831 lines of TypeScript that cover 18 styles, 45 chord qualities, 8 time signatures, and produce lines that pass musicality tests validated against 20 real jazz standards. It's a humbling exercise. You quickly discover that the things that sound simplest are governed by the most sophisticated musical logic, and the "rules" are really tendencies with exceptions that depend on context, taste, and the ineffable quality of feel.

The Range

Every note the generator produces falls between MIDI 28 and MIDI 55 - E1 to G3. This is the acoustic range of a standard upright bass, from the lowest open string to roughly the end of thumb position. Any pitch that wanders outside this range is wrapped by plus or minus twelve semitones until it fits. The constraint is both practical and musical: bass lines that venture above G3 start competing with the piano's register, and lines below E1 turn to mud on most speakers. The great players knew this instinctively. The code enforces it with two constants and a clamp function.

The Anatomy of a Walking Bar

A single bar of walking bass in 4/4 time contains four notes, and each beat has a job. Beat one is the foundation - it states the root of the chord, establishing the harmonic ground. This is non-negotiable. If the pianist is playing rootless voicings (as any competent jazz pianist does), the bass is the only instrument telling the listener what chord they're hearing. Miss the root on beat one and the whole ensemble loses its center of gravity.

Beat two gets a chord tone - the third, fifth, or seventh of the current chord. This reinforces the harmony while adding melodic interest. The generator avoids repeating beat one's note here, because a walking line that goes root-root on beats one and two sounds static. Motion is the point. The line has to walk.

Beat three is the wild card - a chord tone, a scale tone, or a chromatic passing tone. This is where the line gets personality. The best bass players use beat three to set up beat four, creating a narrative arc within a single bar. Problem, tension, resolution. Four notes. One story.

But here's the architectural insight that makes the generator work: it doesn't build the bar from left to right. It builds it from the outside in. Beat one is fixed (the root). Beat four is computed next (the approach tone to the next chord). Then beats two and three are interpolated to create a smooth contour between the two endpoints. This backward planning is the key to the algorithm. The destination determines the journey.

Beat Four: The Most Important Note in Jazz

If there's one thing I obsessed over while building this generator, it's beat four. The approach note. The note that leads into the next bar's downbeat. This single note is the engine of forward motion in a walking bass line, and getting it right is the difference between a line that swings and a line that plods.

The approach tone isn't a single rule - it's a vocabulary with per-style weights. The APPROACH_VOCAB object defines three types of approach and their probabilities for each style. A chromatic approach is a half step above or below the target. A diatonic approach is a whole step from within the scale. A double chromatic approach is two consecutive half steps from the same direction - Eb-D approaching C from above, for instance, creating a little chromatic cascade that bebop players use constantly.

typescript
// Per-style approach vocabulary weights
const APPROACH_VOCAB: Record<string, ApproachWeights> = {
  swing:             { chromatic: 0.75, diatonic: 0.15, doubleChrm: 0.10 },
  hardBop:           { chromatic: 0.70, diatonic: 0.15, doubleChrm: 0.15 },
  coolJazz:          { chromatic: 0.55, diatonic: 0.35, doubleChrm: 0.10 },
  shuffleBlues:      { chromatic: 0.85, diatonic: 0.10, doubleChrm: 0.05 },
  contemporaryJazz:  { chromatic: 0.50, diatonic: 0.20, doubleChrm: 0.30 },
  // fallback:       { chromatic: 0.80, diatonic: 0.12, doubleChrm: 0.08 }
};

// The numbers tell a story about style:
// Swing: 75% chromatic — the classic half-step pull
// Cool jazz: only 55% chromatic — more scalar, relaxed
// Shuffle blues: 85% chromatic — maximum tension before the root
// Contemporary: 30% double chromatic — Avishai Cohen-style cascades

The reason swing gets 75% chromatic is gravitational. A half step creates maximum tension and maximum resolution. When the bass plays B natural on beat four and lands on C on beat one, there's a pull - an almost physical sense of inevitability - that a whole-step approach from D doesn't quite achieve. D to C is correct. B to C is compelling. The 15% diatonic keeps the line from becoming predictable. If every single approach note is a half step, the listener's ear starts to expect it, and expectation is the enemy of swing. The occasional whole-step approach is a small surprise - just enough to keep the line alive without breaking its logic.

Cool jazz drops to 55% chromatic because the West Coast players - Chet Baker, Gerry Mulligan, Paul Desmond - favored a more relaxed, scalar approach. Their bass lines breathe. The 35% diatonic rate gives the cool jazz bass a stepwise, legato quality that matches the softer velocity curve: beat one at 80 instead of swing's 100, beat four at 60 instead of 70. Contemporary jazz pushes double chromatic to 30% - those two-note cascades that Avishai Cohen and other modern players use to add melodic complexity to the approach. The style isn't just a tempo label. It's a complete harmonic and rhythmic personality.

Contour-Based Interpolation

With beat one (root) and beat four (approach) fixed, the generator fills beats two and three using contour-based interpolation. It computes the interval between the two endpoints, divides the span into thirds, and places the inner beats near those division points. Beat two lands near the one-third mark, preferring chord tones - the third, fifth, or seventh that reinforce the harmony. Beat three lands near the two-thirds mark, preferring scale or passing tones - the connecting tissue that creates stepwise motion.

When the span between beat one and beat four is small (two semitones or less), the algorithm switches strategies: it picks a chord tone within five semitones of beat one for beat two, then finds a passing tone between beat two and beat four for beat three. This prevents the line from sounding stuck when consecutive chords share similar bass notes. When the span is larger, the thirds-based interpolation creates a smooth, arc-shaped contour - rising or falling in a curve that the ear perceives as melodic direction rather than random note selection.

A hard constraint enforces the result: no two consecutive notes within a measure can be more than five semitones apart (except the approach note). The constrainStepwise() function walks the generated pitches and pulls any outlier back toward its neighbor. This prevents melodic "jumps" that break the walking feel - the line should step, not leap. Five semitones is roughly a perfect fourth, which is the widest interval that still sounds stepwise in the bass register. Anything wider sounds like a deliberate skip, and walking bass lines skip only when the harmony forces it.

Two-Bar Phrasing

Great bass players don't think one bar at a time. They think in phrases - typically two bars, sometimes four. The line rises for a bar, then falls for a bar, creating a pendulum motion that gives the walking feel its characteristic sway. The generator captures this through a prevDirection state variable that tracks whether the last measure moved up or down. With 60% probability, the next measure is biased to move in the opposite direction.

typescript
// Two-bar phrasing: bias toward alternating contour direction
if (prevDirection === "up" && target >= beat1 && Math.random() < 0.6) {
  const lower = clamp(target - 12);
  if (lower >= BASS_LOW) target = lower;   // shift down one octave
} else if (prevDirection === "down" && target <= beat1 && Math.random() < 0.6) {
  const higher = clamp(target + 12);
  if (higher <= BASS_HIGH) target = higher; // shift up one octave
}

// After generating the measure, update direction
if (measureNotes.length >= 2) {
  const first = measureNotes[0].pitch;
  const last = measureNotes[measureNotes.length - 1].pitch;
  prevDirection = last > first ? "up" : last < first ? "down" : prevDirection;
}

The 60% probability is calibrated by ear, not by math. At 50%, the alternation feels random. At 70%, it becomes predictable. At 60%, the phrasing has a shape - a tendency toward arcs - without becoming mechanical. The remaining 40% allows the line to occasionally continue in the same direction for two bars, creating longer ascending or descending runs that break the pendulum pattern just often enough to sound human. Ray Brown did this constantly: two bars of ascent followed by a quick drop, like a wave building and crashing. The algorithm doesn't know about Ray Brown. But it produces lines that follow the same logic, because the logic is embedded in the probability.

The Dorian Question

Here's a detail that reveals the gap between textbook theory and real jazz practice. When the generator encounters a minor seventh chord - say Am7 - which scale does it use for passing tones? The code is explicit: MINOR_SCALE = [0, 2, 3, 5, 7, 9, 10]. That's Dorian. Not Aeolian (natural minor), which would be [0, 2, 3, 5, 7, 8, 10]. The difference is one note - the sixth degree. Dorian has a natural sixth (F# in A Dorian). Aeolian has a flat sixth (F natural in A natural minor). One semitone. And it changes everything.

The natural sixth is brighter, more consonant against the minor seventh chord, and avoids the dark half step between the fifth and sixth degrees that makes Aeolian sound heavy. This isn't written in most theory textbooks as a "rule." It's an unspoken assumption of the idiom, absorbed through listening. Miles Davis built an entire musical revolution around Dorian mode - "So What" is D Dorian for sixteen bars, Eb Dorian for eight, back to D Dorian for eight. Every jazz musician after 1959 internalized that sound.

typescript
// Scale selection: the Dorian default for minor chords
const MAJOR_SCALE    = [0, 2, 4, 5, 7, 9, 11]; // Ionian
const MINOR_SCALE    = [0, 2, 3, 5, 7, 9, 10]; // Dorian (jazz standard for m7)
const DOMINANT_SCALE = [0, 2, 4, 5, 7, 9, 10]; // Mixolydian

// Selection logic
if (q.includes("dim"))                        scale = DIMINISHED;
else if (q.includes("sus"))                   scale = DOMINANT_SCALE;
else if (q.startsWith("m") && !q.startsWith("maj")) scale = MINOR_SCALE;
else if (q === "7" || q.startsWith("7"))      scale = DOMINANT_SCALE;
else                                           scale = MAJOR_SCALE;

// Dorian for minor because Ron Carter said so, every time he played.

The scale selection extends beyond the three main families. Diminished chords get the symmetric diminished scale [0, 2, 3, 5, 6, 8, 9, 11] - alternating whole and half steps, the scale that Bud Powell and Barry Harris used over diminished passing chords. Suspended chords get Mixolydian - the dominant scale but without the major third, avoiding the note that would destroy the suspension. The logic cascades through a chain of string checks, from most specific (contains "dim") to least specific (default to Ionian). Forty-five chord qualities, four scale families, one decision tree.

Enclosures: The Bebop Detail

About 15% of the time, the generator replaces the single quarter-note approach on beat four with a pair of eighth notes - a chromatic enclosure. Two notes, one from above and one from below (or vice versa), that surround the target like parentheses. The enclosure figure is one of the defining gestures of bebop: Charlie Parker used it constantly in his melodies, and bebop bass players adopted it to add rhythmic energy to the approach.

The enclosure is excluded on the last chord of the progression (there's nothing to approach), near the boundary of the bass range (not enough room above or below), and on styles where it would sound wrong (bossa, ballad, ECM). When it fires, the two eighth notes are swung - offset by the swingAmount parameter - so they fit naturally into the rhythmic feel. The first note gets velocity 75, the second gets 70, both slightly softer than the surrounding quarter notes. This dynamic shaping makes the enclosure sound like a quick ornament rather than a deliberate figure. It should feel tossed off, the way a great player throws in a passing gesture without thinking about it. The code thinks about it. The result shouldn't sound like it did.

Velocity and Dynamics

The velocity curve tells the story of each beat's role. In swing, beat one gets velocity 100 - it's the anchor, the loudest note. Beats two and three get 85 - present but subordinate. Beat four gets 70 - the approach note is the softest, creating a natural diminuendo within each bar that gives the walking feel its characteristic "lean forward" quality. The quieter approach pulls the ear toward the next downbeat, setting up the resolution.

Each style has its own velocity curve. Hard bop runs hotter: 110, 95, 95, 85. The louder approach note reflects hard bop's more aggressive energy - Art Blakey's bands played like the roof was on fire, and the bass had to match. Cool jazz runs cooler: 80, 70, 70, 60. The entire dynamic range sits lower, matching the understated West Coast aesthetic. Bossa gets 95 for the root and 80 for the fifth - only two notes per bar, both played with the even, singing quality that Joao Gilberto's bass players maintained throughout those long, hypnotic bossa grooves.

On top of the per-beat velocities, a dynamicMultiplier function shapes the volume arc across the entire performance. Each style defines an opening level, a peak, and a taper. Hard bop starts at 75% and peaks at 105% with a 30% dynamic range. ECM starts at 92% and barely moves - a 10% range that reflects the Nordic label's aesthetic of controlled intensity. Alfa Mist gets the widest range at 45% - whispering verses that explode into choruses, the signature dynamic of London's new jazz scene. Finally, a humanization pass adds ±5 velocity jitter to every note, preventing the mechanical uniformity that immediately betrays a computer-generated bass line.

Beyond Walking: 18 Style Generators

Walking bass is the default, but the generator contains 18 distinct style generators, each with its own note selection, rhythm, articulation, and velocity rules. Bossa nova produces two notes per bar - root and fifth in half notes, creating the gentle rocking motion that grounds the samba rhythm. Antonio Carlos Jobim's recordings with Sebastião Neto established this pattern, and it's become as canonical for bossa as walking is for swing. The generator doesn't "simplify" the walking algorithm to produce bossa bass. It uses a completely separate function that thinks in a fundamentally different rhythmic language.

Latin bass plays tumbao - four syncopated notes emphasizing the "and" of beat two and beat four. The anticipated bass note, landing just before the downbeat, is what gives Latin jazz its forward lean. Fusion bass cycles through four pattern variants: the Jaco-style sixteenth-note syncopation, the Weather Report chromatic approach, the Marcus Miller octave-jump snap, and a sparser space groove. Each variant is selected randomly, preventing the fusion bass from locking into a single groove for the whole tune.

The artist-specific generators go further. The Holdsworth preset produces a Jimmy Johnson-style melodic counterpoint with wide intervals and chord extensions. The Alfa Mist preset alternates between six patterns at 15% probability each: syncopated groove, chromatic approach, pedal point, dead-note ghost patterns, melodic stepwise, and driving electric. The Metheny preset channels Jaco Pastorius on Bright Size Life - a singing fretless quality with sixteenth-note runs, quarter-note triplets, and arpeggio outlines that treat the bass as a melody instrument.

Monophonic Enforcement

A bass plays one note at a time. The generator enforces this constraint through three mechanisms. First, each note's duration is set to exactly the time until the next note begins - no overlaps, no gaps. Second, a cross-bar repeat fix detects when the first note of a new measure duplicates the last note of the previous measure (which would sound like one sustained note instead of two separate attacks) and nudges the approach note by a semitone. Third, a multi-pass deduplication algorithm runs up to three convergence passes over the entire line, finding any adjacent pair of identical pitches and shifting one of them by a semitone - but never shifting beat one, because the root is sacred.

The deduplication is surprisingly subtle. When two adjacent notes match, the algorithm prefers to shift the earlier one (giving the later note priority as it's usually a more structurally important arrival). But it never shifts a beat-one note, tracked through a Set of beat-one indices. And it checks both directions (up and down) to avoid creating a new collision with the note on the other side. Three passes because a single pass can create new collisions while fixing old ones. After three passes, the system converges. In testing across 20 real standards, three passes have always been sufficient.

Odd Meters

Not all jazz lives in 4/4. The generator handles seven additional time signatures: 5/4 (Take Five), 7/8 (much of Avishai Cohen's work), 6/8 (Afro-Cuban and blues-influenced jazz), 9/8 (Dave Brubeck's "Blue Rondo a la Turk"), 6/4 (Miles Davis's "All Blues"), 7/4 (Don Ellis territory), and 11/8 (the outer edge of jazz meter). Each odd-meter generator produces the right number of notes with appropriate groupings - 5/4 groups as 3+2, 7/4 as 4+3 - and the final beat always carries an approach tone to the next bar's root.

Odd-meter walking bass is rare in the tradition because the tradition is overwhelmingly in 4/4. But when Dave Brubeck recorded Time Out in 1959, he proved that jazz could swing in any meter. When Avishai Cohen plays in 7/8, the bass line doesn't sound academic or forced - it grooves. The generator's odd-meter support exists because a practice tool should never tell you "that meter isn't supported." If you want to practice a 7/8 tune, the bass should walk in seven.

The Test Suite as Jazz Education

The walking bass tests aren't unit tests in the traditional sense. They're musical assertions. Does beat one always land on the root or fifth? Is every note within the E1-G3 range? Does the approach note on beat four fall within two semitones of the next chord's root? Do consecutive bars alternate direction more than 50% of the time (the two-bar phrasing test)? Do enclosures appear in roughly 10-15% of bars? Are all 34 chord qualities handled without error? These questions encode the rules of walking bass as boolean checks. The test suite is, in a way, a codified jazz education - it knows what a walking bass line should sound like even though it can't hear.

Twenty real jazz standards serve as the musicality test fixtures: Summertime, Giant Steps, All The Things You Are, Autumn Leaves, and sixteen more. The generator runs each standard through the full algorithm and checks: are the wrong notes below 10%? Does beat one hit root or fifth at least 95% of the time? Are guide tones (the third and seventh) present in the chord tone selections? The fixtures aren't random chord progressions - they're the actual harmonic sequences that define the jazz canon. If the generator can walk through Giant Steps without producing wrong notes, it can walk through anything.

1,831 lines of TypeScript. 45 chord qualities. 18 style generators. 8 time signatures. Three approach types with per-style probability weights. Two-bar phrasing with 60% alternation bias. Contour-based interpolation that plans beat four before beat two. Enclosure patterns at 15% density. Monophonic enforcement through three convergence passes. Dynamic arcs from ECM's whisper to hard bop's roar. And underneath all of it, a single conviction: the approach note on beat four is a half step, because that's what Ron Carter would play, and Ron Carter is never wrong about the bass.

Explore the full generator: bass, piano, and drums
Hear the Bass Walk