Ox0badf00d is a native Swift tracker module package for loading and rendering classic module music.
The initial engine supports:
- ProTracker-style
MODfiles with 4/6/8+ channel signatures. - FastTracker II
XMfiles with packed pattern data, note-to-sample instrument maps, volume/panning envelopes, and delta-decoded 8/16-bit samples. - Impulse Tracker
ITfiles with packed pattern data and uncompressed PCM samples. - Tick-based playback for core tracker effects: arpeggio, portamento, tone portamento, vibrato, tremolo, volume slides, panning, sample offsets, retrigger, note cut/delay, pattern break/jump, pattern delay, tempo/speed, and global volume changes.
- Streaming-style stereo
FloatPCM rendering with no libopenmpt, no ffmpeg, and no external decoder. - Optional psychoacoustic 3D spatialization using interaural time differences, level differences, head-shadow filtering, crossfeed, and early reflection cues.
This is intentionally a Swift package rather than app-only code so SwiftBuilder can use it as the real playback core later.
import Foundation
import Ox0badf00d
let data = try Data(contentsOf: moduleURL)
let module = try ModuleLoader.load(data: data)
let renderer = ModuleRenderer(module: module, sampleRate: 44_100)
let pcm = renderer.renderSong(maxSeconds: 600, tailSeconds: 2)PCMBuffer.interleavedSamples contains stereo samples in left/right order.
For spatial playback:
let renderer = ModuleRenderer(
module: module,
sampleRate: 44_100,
options: RenderOptions(spatialization: .psychoacoustic3D(.spacious))
)This is a real parser, tick scheduler, effect engine, and PCM renderer. The goal is capability parity with mature tracker players, then to go beyond them with modern spatial rendering.
We've now added a rendering module for Apple platforms that provides an AVAudioEngine session for your convenience. Feedback appreciated.
Still to do for that bar:
- Full Impulse Tracker (
IT) playback. Only uncompressed IT samples decode today; a module can parse structurally yet render pure silence (seeTrackerModule.isRenderable). Needed:- IT 2.14 compressed sample decoding —
ITParser.parseSamplecurrently returns an empty sample for theflags & 0x08(compressed) path, so any IT relying on compression comes back silent. - Verify/repair IT packed-pattern decoding — a 982-byte size-coded
1kb.itdecoded to zero note events, so patterns need a second look, not just samples. - Confirm the IT note range maps correctly: values are 0–119 (0 = C-0), but
pitch(fromITNote:)starts its note case at 1, dropping C-0. - IT instrument envelope playback and New Note Actions.
- IT 2.14 compressed sample decoding —
- More exact XM envelope edge cases and fadeout behavior.
- More exact per-format effect memory and edge-case compatibility.
- Filter/resonance commands where formats provide them.
- Golden-file render tests against known-good tracker engines.