Every track that appears in NEON DJ’s genre dropdown was synthesized entirely in JavaScript — no audio files are loaded from a server, and no copyrighted samples are used. TheDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/kepabilbao67-bot/musicplayer2/llms.txt
Use this file to discover all available pages before exploring further.
generateTrack(def) function renders a full multi-bar loop offline in faster-than-real-time, producing an AudioBuffer that the deck can loop indefinitely. This document explains how that function works, how genre definitions control the output, and how the scheduling model maps musical time to Web Audio timestamps.
Track generation happens once during the loading screen, before the user interface becomes interactive. Subsequent plays of the same genre reuse the pre-rendered
AudioBuffer — generateTrack is never called again. The progress bar shown at load time advances as each genre is rendered sequentially.The midiToFreq Utility
All melodic frequencies in NEON DJ are specified as MIDI note numbers and converted to Hz at render time:
| MIDI | Note | Frequency |
|---|---|---|
| 21 | A1 | 55.00 Hz |
| 28 | E2 | 82.41 Hz |
| 33 | A2 | 110.00 Hz |
| 40 | E3 | 164.81 Hz |
| 45 | A3 | 220.00 Hz |
| 69 | A4 | 440.00 Hz |
generateTrack(def) — Function Signature
A genre definition object from the
TRACKS map. See the definition shape below.Promise<AudioBuffer>. The buffer has two channels at 44100 Hz. Two extra properties are attached after rendering: _bpm (the genre’s BPM, used by the deck’s SYNC feature) and _loop = true (tells AudioBufferSourceNode to loop seamlessly).
Genre Definition Object Shape
Each genre in theTRACKS map is a plain object with the following properties:
Human-readable name shown in the track dropdown. Example:
"House · 124 BPM".Tempo in beats per minute. Controls step duration and delay times.
Number of bars in the loop. All genres use 8 bars.
Array of 16th-note step indices (0–15) on which a kick drum fires each bar.
Step indices for clap/snare hits.
Step indices for open hi-hat hits (
synthHat with open = true).Step indices for closed hi-hat hits (
synthHat with open = false).Array of MIDI note numbers used as bass/chord roots, one per pair of bars (
Math.floor(bar / 2) % length). Used by electronic genres (House, Hip-Hop, Techno, etc.).Array of MIDI root notes for chord-based genres (Rock, Metal, Pop, Punk, Ska, Grunge). Each chord is a power chord (root + fifth + octave) passed to
synthChord.build(ctx, master, noise, bar, step16, t) — called once per 16th-note step. Contains the melodic/harmonic scheduling logic specific to each genre. Parameters: the offline audio context, the master gain node, the noise buffer, the current bar index (0-based), the step within the bar (0–15), and the absolute timestamp t in seconds.How Rendering Works
Create OfflineAudioContext
A fresh
OfflineAudioContext is created for each genre with a length precisely matching the number of steps × step duration × sample rate:Create shared resources
A single 1.5-second white noise buffer is created once via
makeNoise(ctx, 1.5) and reused by all percussion scheduling calls. A master gain node (gain.value = 0.85) connects to ctx.destination.Schedule all notes
A single The
for loop iterates over every step from 0 to totalSteps - 1. For each step, the absolute timestamp t = step * stepDur is computed. The loop then checks which instruments fire on this step:def.build() call is where bass lines, arpeggios, leads, and chords are scheduled. Build functions read from bassRoots or chords arrays, cycling through harmonic changes every two bars: Math.floor(bar / 2) % array.length.Step Timing Model
All musical timing is derived from one value:stepDur = (60 / bpm) / 4 (the duration of a 16th note in seconds). Bar boundaries occur every 16 steps. Beat (quarter-note) boundaries occur every 4 steps. This makes the grid layout immediately readable from the pattern arrays:
[0, 4, 8, 12] places a kick on every quarter note — the classic four-on-the-floor pattern.
Genre Table
| Genre | BPM | Kick Pattern | Primary Instruments |
|---|---|---|---|
| House | 124 | 0, 4, 8, 12 (four-on-floor) | Bass (sawtooth), pad stabs (sawtooth lead) |
| Hip-Hop | 88 | 0, 7, 10 (boom-bap) | Sub bass, triangle lead melody |
| Techno | 130 | 0, 4, 8, 12 (four-on-floor) | Off-beat bass, sawtooth lead on bar 3 |
| Synthwave | 110 | 0, 4, 8, 12 | Bass + square-wave arpeggio (8-note pattern) |
| Reggaeton | 96 | 0, 8, 10 (dembow) | Bass, square-wave melody |
| Drum & Bass | 174 | 0, 10 (breakbeat-style) | Sub bass + mid bass, sawtooth chord stabs |
| Trap | 140 | 0, 6, 10 | Long sub bass (0.55 s), triangle ornament |
| Funk | 108 | 0, 10 | Tight 16th-note bass, square-wave punctuation |
| Rock Español 80/90 | 132 | 0, 8 | Power chords (drive 16), bass guitar |
| Heavy Metal 80/90 | 160 | Dense (12 of 16 steps) | Distorted power chords (drive 26), bass |
| Pop Español 80/90 | 118 | 0, 4, 8, 12 | Bass, sawtooth chord stabs, square melody |
| Punk 80/90 | 172 | 0, 4, 8, 12 | Power chords (drive 20), straight bass |
| Ska 80/90 | 150 | 0, 8 | Upstroke chord “chink” (off-beats), bass |
| Grunge 90 | 115 | 0, 8, 10 | Heavy power chords (drive 24), bass |
| Salsa | 95 | 3, 11 | Triangle montuno arpeggio, syncopated bass |
| Cumbia | 92 | 0, 8 | Sawtooth + triangle melodic line, bass |
| Jungle / DnB | 165 | 0, 6, 10 (jungle breaks) | Sub bass + mid bass |
| Dubstep | 140 | 0 (half-time) | Wobble bass (LFO 5 Hz / 8 Hz) |
The build Function Pattern
Each genre’s build function follows the same contract, illustrated here with House:
if (step16 === X) conditionals inside build is how every melodic event is placed. Chord changes happen by indexing into bassRoots or chords based on bar. This gives each genre its own harmonic character over 8 bars before the loop repeats.
Why OfflineAudioContext instead of real-time rendering?
Why OfflineAudioContext instead of real-time rendering?
An
OfflineAudioContext renders audio as fast as the CPU can process it — typically 10–50× faster than real time. A single 8-bar House loop at 124 BPM lasts about 15.5 seconds; rendering it offline takes only a few hundred milliseconds. This approach also avoids the complexity of managing a live audio graph during the loading phase before the user interface is visible. The rendered AudioBuffer is a standard PCM buffer that any AudioBufferSourceNode can play, loop, pitch-shift, and seek within.