Blog

Luis Majano

October 20, 2026

Spread the word


Share your thoughts

Ortus Solutions today announces the general availability of BxAudio 1.0, the audio module for BoxLang. Synthesize instruments and drums, arrange them on a beat grid, master to a loudness target, speak text with open license voices, score a video and play sound in a game. All of it from BoxLang, on the JVM. No Python. Nothing native to install.

Before we explain anything, press play. This is the BxAudio theme, and it was not recorded. It was written in BoxLang and rendered by the module, mastered to -14 LUFS. 🎵

Here is your first sound, a two second A minor chord with a filter and a fade:

// first.bxs
notes = [ "A3", "C4", "E4" ].map( ( n ) => audioOsc( "saw", audioFreq( n ), 2 ) )
chord = audioFilter( audioMix( notes ), "lowpass", 1800, 0.8 )
chord = audioFade( audioGain( chord, -10 ), 0.05, 0.6, "smooth" )

audioSave( chord, "chord.wav" )
audioSave( chord, "chord.mp3" )
println( audioInfo( "chord.wav" ) )
install-bx-module bx-audio
boxlang first.bxs

Why BxAudio 🎧

Audio on the server has always meant shelling out to Python scripts, native binaries and a pile of tools you hope are installed in production. BxAudio puts the whole pipeline inside the JVM and soon RUST via MatchBox, as BoxLang functions you already know how to call.

  • Pure JVM. WAV, MP3 and FLAC read and write in plain Java. Nothing native to compile, nothing to break on the next server.
  • 83 functions. Synthesis, mixing, effects, mastering, analysis, speech, tags, video and game audio in one module.
  • Buffers are values. Every function that changes audio returns a new buffer and leaves the one you gave it alone. Easy to reason about, easy to test.
  • Repeatable. Noise and random choices take a seed, so the same code gives the same sound on any machine.
  • Measured, not guessed. Loudness follows EBU R128 and ITU-R BS.1770, and agrees with the industry reference tools within 0.1 LU.
  • A real command line. bx-audio info, master, speak, render and more, with tab completion.
  • Free and open source. Apache 2.0.

Every one of these was written, not recorded 🎹

BxAudio ships sixteen complete pieces, each one a readable BoxLang script of a few dozen lines, covered by tests that render it and measure what it sounds like. All the music is original, so there are no samples and no licensing questions. A few to try:

Synthwave. A night drive: pulsing bass, a gated snare in a huge room, wide pads, an arpeggio and a lead melody.

Lofi. Swing, humanised timing, tape wobble and vinyl crackle over jazzy seventh chords.

Jazz. A trio on a twelve bar blues in F, with a solo improvised by rules that follow the chords. Change the seed for another solo.

Cinematic. Tension, a build, one silent beat, then a huge boom and taiko drums.

Chiptune. Original 8 bit music for an imaginary console: two pulse channels, a triangle bass and noise drums.

Render any of them yourself, with your own settings:

bx-audio pieces                                   # the list
bx-audio render synthwave --out=night.mp3         # synthesize one
bx-audio render lofi --bpm=72 --seed=12           # same piece, your way
bx-audio explorer                                 # play them all in the browser

Pop, house, ambient, techno, rock, game sound effects, a sampler and more are on the examples page, each with a player.

What's in the box 📦

  • Synthesis and mixing: band-limited oscillators, drums, noise, envelopes, filters, delay, reverb and chorus, plus a timeline with a tempo grid, named tracks and kick pumping
  • Text to speech: open license voices that download on first use, with speed, pauses and captions timed to the words
  • Score a video: cut music to the exact length of a picture, add a voice-over with captions, duck the music under it and mux the result
  • Loudness and mastering: measure the EBU R128 way and deliver to streaming (-14 LUFS), podcast (-16), broadcast (-23) or your own target, with compressor, limiter and EQ
  • Game audio: a real time mixer with buses, loops, crossfades, varied effects and audio sprites
  • Time and pitch: stretch, pitch shift and fit a clip to an exact length without the chipmunk
  • Analysis: FFT, spectrum, tempo and silence detection, plus true peak
  • Modulation and real rooms: LFOs, curves, automation lanes, a sampler that plays your recordings as instruments, and convolution reverb
  • Tags, chapters and cover art: read and write ID3, FLAC and WAV tags, chapter marks and artwork with no native library
  • Web delivery and pictures: serve audio with Range and ETag support, encode to bytes, and draw waveforms and spectrograms as PNG or SVG
  • Command line: info, loudness, master, speak, render, mux and more, with doctor to check your setup

Make a beat

A timeline turns beats and bars into seconds. Drop sounds on the grid and render:

t    = audioTimeline( bpm = 120, beatsPerBar = 4, sampleRate = 44100, channels = 2 )
kick = audioDrum( "kick" )
hat  = audioDrum( type = "hat", seed = 2, level = 0.5 )
pad  = audioGain( audioFilter( audioOsc( "saw", audioFreq( "A2" ), 4 ), "lowpass", 900, 0.8 ), -12 )

audioAdd( timeline = t, sound = pad, at = 0, track = "music" )
audioBeats( t, 0, 16 ).each( ( at ) => audioAdd( timeline = t, sound = kick, at = at, track = "drums", gainDb = -4 ) )
audioBeats( t, 0.5, 16, 1 ).each( ( at ) => audioAdd( timeline = t, sound = hat, at = at, track = "drums", gainDb = -12, pan = 0.3 ) )

audioSave( audioRender( timeline = t, tail = 1 ), "beat.wav" )

Master it

One call reaches the loudness target, and a look-ahead limiter keeps true peaks under your ceiling:

final = audioMaster( audio = mix, target = "streaming", truePeakDb = -1 )
println( audioLoudness( final ).integrated )   // -14

Cleaning up a podcast recording reads like the checklist an audio engineer would give you:

cleaned = audioTrimSilence( audio = recording, thresholdDb = -50, pad = 0.25 )
cleaned = audioFilter( cleaned, "highpass", 80, 0.7071 )
cleaned = audioCompress( audio = cleaned, thresholdDb = -22, ratio = 3, attackMs = 8, releaseMs = 120 )
cleaned = audioMaster( audio = cleaned, target = "podcast", truePeakDb = -1 )

Make it speak 🗣️

voice = audioSpeak( text = "Meet BoxLang. Fast, friendly and made for the JVM.", voice = "joe" )
audioSave( voice, "hello.mp3" )

Or straight from the terminal:

bx-audio speak "Hello from BoxLang." --voice=joe --out=hello.mp3

The speech engine and the voice download once, are checked against checksums and live in ~/.bxaudio. After that, speech works offline. Here is a spoken announcement over music that ducks under the voice, rendered by the 12-voiceover example:

Score a video 🎬

Fit the music to the picture, speak the voice-over with timed captions, duck, master and mux:

info  = videoInfo( "clip.mp4" )
music = audioFitTo( audioLoad( "cue.wav" ), info.seconds )

spoken = audioSpeakCues(
	text   = "One module. Pure JVM. No Python. BoxLang Audio.",
	voice  = "joe",
	pauses = { sentence : 0.45, paragraph : 0.9 }
)
audioSubtitles( cues = spoken.cues, format = "srt", path = "trailer.srt", offset = 1.5 )

t = audioTimeline( bpm = 100, sampleRate = 44100, channels = 2 )
audioAdd( timeline = t, sound = music, at = 0, track = "music" )
audioAdd( timeline = t, sound = spoken.audio, at = 1.5, track = "voice" )
audioTrackGain( t, "music", -6 )
audioDuck( t, "music", "voice", -9 )

final = audioMaster( audio = audioTrim( audioRender( timeline = t ), 0, info.seconds ), target = "streaming" )
audioMux( video = "clip.mp4", audio = final, output = "scored.mp4" )

The picture is copied, never re-encoded, so muxing is fast and lossless. Hear the full 13-trailer example:

Video, OGG, Opus and AAC go through FFmpeg as an optional separate program. BxAudio finds it on your machine or downloads a pinned, checksum verified build for you. WAV, MP3 and FLAC never need it.

Play it in a game 🎮

mixer = audioMixer( output = "speakers", buses = { music : 0.7, sfx : 1.0 } )

theme = mixer.play( song, { bus : "music", loop : true, fadeIn : 0.3 } )
mixer.play( jump, { bus : "sfx", pan : -0.4, pitch : 1.1 } )
mixer.setVolume( "music", 0.3 )   // duck the music

theme.stop( 0.5 )                 // fade out and stop

Output to the speakers, to a silent clock for servers and tests, or to memory to render a whole scripted session to a file.

Voices with the paperwork done 📜

Text to speech is only useful if you can ship it. So we read the license of every voice in the collection, and of the data each was trained on.

  • 177 voices reviewed
  • 11 offered, every one with an open license that allows commercial use (CC0, Public Domain, Apache 2.0, or CC BY and CC BY-SA with a credit)
  • 166 left out, each listed with the reason

audioCredits() prints the credit lines for your about page, and bx-audio voices --excluded shows you exactly what was left out and why. Today the voices speak US English. Spanish, German, Italian, French and Portuguese are planned. Hear them all on the voices page.

Built for AI agents 🤖

Audio tools for BoxLang AI

Install BoxLang AI next to BxAudio and 26 audio tools land in its global tool registry as name@bxaudio. Any agent you give them to can inspect, edit, master and create audio files:

agent = aiAgent(
	name  : "sound-editor",
	tools : [ "audioInfo@bxaudio", "audioTrim@bxaudio", "audioNormalize@bxaudio" ]
)

agent.run( "Cut the first 5 seconds off intro.wav and normalize it" )

Or hand an agent the whole studio:

agent = aiAgent( name : "studio", tools : aiToolRegistry().getByModule( "bxaudio" ) )

Safety is built in. Tools work on files by path, every path is checked against the folders you allow (ai.allowedPaths), symlinks and ../ cannot escape them, and a tool never writes over an existing file or its own input. Registered is not given: an agent only sees the tools you name.

Agent Skills

The official BxAudio skill teaches your coding agent synthesis, mixing, mastering, speech, video and the AI tools, along with the rules that matter, like never mixing positional and named arguments in one call:

npx skills add ortus-boxlang/skills/boxlang-modules/bx-audio

Browse it, alongside every other BoxLang skill, on skills.boxlang.io.

Part of the BoxLang productivity stack

  • BoxLang MatchBox: BoxLang powered by RUST (WASM, ESP32, Binaries and more)
  • BoxLang AI: generate scripts and narration text, then render them with BxAudio
  • ColdBox: serve generated audio from the apps you already build
  • BxSites: the static site generator that builds the BxAudio docs
  • BxPlaywright: browser automation and testing for BoxLang
  • BxAgents: build AI agents by convention, powered by BoxLang AI

Get started

Requirements: BoxLang 1.18+ on Java 21+.

# BoxLang OS binary (also installs the bx-audio command and completions)
install-bx-module bx-audio

# CommandBox
box install bx-audio

# Check MP3, FFmpeg, the sound card, the examples and the explorer
bx-audio doctor

Then hear something in under two minutes:

bx-audio render theme --out=theme.mp3
bx-audio speak "Hello from BoxLang." --voice=joe --out=hello.mp3
bx-audio master theme.mp3 loud.mp3

Full walkthrough in the Getting Started guide, or open the Try it page for a run-tested recipe for every feature.

Need audio in production?

Ortus Solutions offers professional support, architecture reviews and custom development for BoxLang, including audio pipelines, narration and video workflows. Talk to us or see the BoxLang+ plans.

Resources

Your code could already build the app. Now it can score it, master it and give it a voice. 🎙️

Add Your Comment

Recent Entries

BoxLang Under the Lens: Observability Meets AI - Free Webinar

BoxLang Under the Lens: Observability Meets AI - Free Webinar

Your application is slow. Something is failing. Where do you start looking?

On October 28, 2026, at 11:00 AM CDT, join Luis Majano, Ortus Solutions CEO and BoxLang creator, for a live, hands-on look at how observability and AI come together in BoxLang.

BoxLang Under the Lens: Observability Meets AI introduces BxLens, Lensy, and the additional monitoring capabilities of BoxLang+....

Victor Campos
Victor Campos
October 19, 2026
QR Codes Come to BoxLang Images

QR Codes Come to BoxLang Images

The bx-image module can now generate and read QR codes. Two new functions, a string member function, and two new bx:image actions. No extra dependencies for you to manage.

Luis Majano
Luis Majano
October 14, 2026