Language & sound library New here? Open the step-by-step Manual → tempo 60*2 bd([]*4) hh([1 0]*(2+2)).velocity(10*8).volume(-3*2)Numbers accept +, −, *, /, % (remainder), parentheses and numeric variables. [] followed by * repeats that group within the bar; note * still sets its time weight. Use parentheses for calculated scale degrees, such as [(1+2)]. Re-evaluate applies at the next bar; invalid drafts keep the last valid music.
strength = 80 hh([1 0]*4).velocity(strength, strength/2)Define name = expression on its own line. Values outside passages are shared; values inside a passage belong to it. Use unique names for variables and tracks. Ordinary parameters calculate on re-evaluation.
hh([?0.7]*16) keys([?0.7]*8).scale("C3 minor")[?0.7]*N divides the whole bar into N equal slots. Each slot has a 70% chance to sound, otherwise it rests; each bar makes new choices. Drums keep their sound; melody chooses from one octave of its scale. ? alone means 50%, ?1 always sounds, ?0 rests. Use ?(density) for a variable. Type ? inside [] for probability suggestions.
fill(freq) = 4 fill(len) = 2Every fourth bar, replace the drum groove's final two beats with a familiar fill. It uses existing snare/rim/tom tracks first, or the other drums if none are present. Melody continues. Natural density and repeatable variation are automatic. Add fill(style) = "" to see phrase choices.
Optional fill controls fill(parts) selects exact tracks; fill(hits) sets a total attack count; fill(grid) changes subdivision; fill(seed) fixes or calculates the variation. Default seed is fillIndex. bar counts passage bars; fillIndex counts fill occurrences, both starting at 1. These clocks work in numeric fill rules except fill(freq). To write your own fill, add fill(sd) = [1 1][1 1 1 1] instead of generated controls. The Manual explains both modes.
chords = keys([C3&E3&G3]).volume(-12) melody = keys([C4][E4][G4][E4]).volume(-6)Optional track names let several rows use the same instrument independently. Write name = instrument(...). Use letters, digits and underscores, starting with a letter or underscore; names are case-sensitive, up to 48 characters and unique within a passage. Other passages may use the same name. Names are not shared pattern variables. Unnamed rows still work. All edits apply on re-evaluation.
solo(melody, kick) mute(chords)Write mute(...) or solo(...) on its own line inside a passage, below the instruments. Use comma-separated track names without quotes; unnamed instruments use their part name, such as bd. Type inside the parentheses for inline track suggestions. Solo selects tracks, then mute excludes tracks. Empty () or removing the line clears that filter; with neither filter, all tracks play. Each passage keeps its own selection. Cmd/Ctrl+Enter applies on the next bar without resetting loops. Mute silences the whole track, including effects, with a short click-free fade.
Binary drums: each [] is one beat; 1 triggers a hit. If a drum row uses ?, its groups divide the whole bar equally in every written bar. Notes: bracket groups divide the whole bar equally. Empty groups and ~ are rests. In 4/4: [Cmajor] = four beats; [Cmajor][Dminor] = two beats each; [Cmajor][][][] = one beat, then three silent beats. [C4 D4 E4] divides its group into three equal notes; * changes shares within that group. [C3&E3&G3] writes each tone; [Cmajor] names a chord
bass([C2][G2]).timbre("sub").volume(-6) keys([Cmaj7]).voicing(above: C3).timbre("piano").volume(-9).volume(-6) lowers one instrument by 6 dB. Default 0; range −60 to +6 dB. It works before or after .timbre(). Changes enter on the next bar.
hh([1 1][1 1][1 1][1 1]).velocity(90, 45).swing(60) keys([Cmajor Dminor][][][]).voicing(above: C3).velocity(100, 70).swing(60).velocity() repeats MIDI strengths (1–127) across actual hits; rests do not advance, and a chord uses one value. 127 is the original level. .volume() still controls the whole instrument. .swing(50) is straight; 60 divides each beat 60:40; range 50–75%. Straight subdivisions move, triplets and * weights stay as written. Notes' gates follow their swung timing; bar lengths stay fixed.
Type a dot after an instrument to see available modifiers. Empty quotes show compatible choices; typing filters them. ↑↓ chooses, Tab/Enter inserts, Esc hides. Parameter hints explain numeric units and ranges. Suggestions only edit the draft; Cmd/Ctrl+Enter applies it at the next bar.
Use note names with an octave, sharps or flats: C4, F#3, Bb3. Without an octave, notes use octave 4. Named chords: major/maj, minor/min/m, major7/maj7, minor7/min7/m7, dom7, dim, sus2, sus4. Earlier C3maj notation still works. C7 means the note in octave 7; write Cdom7 for a dominant chord.
keys([Amajor][Dminor]).voicing(above: C3) keys([Amajor][Dminor]).voicing(below: C4).sidechain(low) receives a control pulse from each low note/beat and ducks the entire track, including effect tails. .sidechain(low, 10, 150, 4): attack ms, release ms, ratio. Ratio 4 means 25% level at full trigger; Ratio 1 bypasses. Attack sets the dip speed and Release restores the level. Neither track’s audio level is measured; source mute/solo does not stop pulses. Click the row for sliders. Older five-argument calls still load; the removed last value is ignored and sliders remove it. Legacy .sidechain(low, 12, 0.5) keeps reduction/recovery in dB/beats.
keys([Cm7]).adsr(10, 200, 70, 300)ADSR: attack ms, decay ms, sustain %, release ms. A/D/R: 0–5000; S: 0–100. Overrides the soundbank amplitude envelope; omit to keep the original sound. Short notes release from their current level. Drums use their natural layer length as the gate. Click the row for four sliders.
.voicing(above: C3) keeps the lowest tone at or above C3; below: C4 keeps the highest at or below C4. The anchor itself is allowed. Write a note with an octave, without quotes. Each pitch class appears once in a compact inversion; rhythm stays the same. It also re-registers single notes and scale/follow notes. Omit it to preserve a written spread or melodic contour. Inversions do not change the harmonic root used by .follow().
keys([1&3&5]).scale("C3 major") bass([1][3][5][8]).scale("C1 minor")Scale belongs after each melodic instrument, never before a passage. Root + octave + mode: major/ionian, minor/aeolian, dorian, phrygian, lydian, mixolydian, locrian, chromatic. 1 is the root; 8 is always the next octave. 0 and ~ rest. Chromatic uses 1 #1 2 … or 7 b7 6 …, with major-degree positions; b3 is flat third, B3 is a named note. Other modes use their own scale degrees without #/b prefixes. Type .sc to insert .scale(), then C3 m inside it to search. Changes apply only on re-evaluation.
A comma adds a bar, up to 4 per instrument. One bar loops on its own; different lengths loop independently. In 6/8, each binary drum [] is one eighth-note beat. Random drum rows and melodic rows divide the whole bar. Spaces are ordinary spaces.
Drums: bd · sd · hh · oh · cym · rd · rim · t1 · t2 · t3 · ft Melodic instruments: bass · keys · piano · synth · pad · pluck · guitar
bd("x ~ x ~") hh("x*8")Older drum 0/1 rows and | bar separators still work. Steps edits drums only; melodic notes stay in text.
Drum kits: studio · 808 · lofi · 909 · 606 · house · techno · boombap · trap · breakbeat · electro · minimal · industrial · brush
Melodic sounds: sub · round-bass · saw-bass · piano · electric-piano · organ · sine · saw · square · fm · warm-pad · strings · air-pad · pluck · bell · mallet · guitar · acid-bass · reese-bass · fm-bass · pluck-bass · rubber-bass · felt-piano · bright-piano · fm-keys · clav · music-box · supersaw · soft-lead · chip-lead · synth-brass · dark-pad · glass-pad · choir-pad · slow-strings · synth-harp · muted-guitar · marimba · vibraphone · synth-flute · synth-reed
All sounds are original browser synthesis. Piano, strings and guitar are synthesized approximations, not recorded acoustic instruments. The electronic drum names describe styles, not exact hardware emulations.
55 built-in sounds: 14 drum kits and 41 melodic presets. Inside .timbre(), search a name or category such as bass, keys, lead, pad, pluck, mallet or wind. Each suggestion describes the sound. ↑↓ chooses; Enter / Tab completes; Esc hides. ⌘ / Ctrl + Enter applies edits on the next bar without restarting playback.
keys([Cmajor]).voicing(above: C3).effects("reverb", 25) hh("x*8").effects("delay", 20, "1/8", 35) synth([C3]).effects("filter", 1800) keys([Cmajor]).effects("compressor", -24, 4, 10, 150).effects("reverb", 25, 2, 25, 150, 6000)Type a name inside .effects() to search Reverb, Delay, Filter or Compressor. Mix and feedback use percentages. Reverb: mix %, decay seconds, pre-delay ms, low cut Hz, high cut Hz. Compressor: threshold dB, ratio, attack ms, release ms, knee dB, makeup dB. Filter is low-pass, in Hz. Delay follows the tempo and note length (dotted . / triplet t supported). Effects process left to right; volume is before the effects.
Select a row with effects to reveal its sliders below the editor. Sliders update the code and apply on the next bar for the playing passage; another passage stays a draft. Removing an effect in code bypasses it after re-evaluation. Natural effect tails continue across edits; Stop clears them.
Your code, song name and editing passage auto-save in this browser, including unfinished drafts. Open/New stop playback; restored projects never auto-play. Export .ohcodes or ⌘ / Ctrl + S makes a portable file. Older .ohsounds files and browser drafts still open. This is not cloud sync; clearing browser data or switching browsers/sites does not carry your draft over. Previous draft recovers the last replaced local project.
song{ "Verse" 8 "Chorus" 8 }Song mode follows this order once and stops. Numbers count bars, not repetitions of the instrument pattern. Every section starts its passage at bar 1. Its controls edit the same code; save/export includes the order. Song re-evaluation compiles all referenced passages and applies on the next bar, preserving elapsed song bars. Live mode loops; manually launching a passage leaves Song mode on the next bar. Switching back to Song starts at its first section. Restored projects open stopped in Live mode.
Click a passage name to edit without changing playback. ▶ or ⌘ / Ctrl + Shift + 1–9 launches it on the next bar. Imported samples, audio recording and audio export are not connected yet.