• I make libraries for gamedev in Go • I write talks and articles about gamedev in Go • t.me/go_gamedev (Russian-speaking) creator I’m using Ebitengine for around 2-3 years now
box • Your own stream reader implementation is possible • Works with 16-bit 2-channel PCM LE streams • Works well on every platform I tested my games on
the audio driver as a final step • OGG and MP3 formats allow compact storage • A ~4 min PCM data can have a size of ~50MB This is why most players “decode” OGG/MP3 into PCM on-the-fly, so you can avoid this large memory overhead.
audio system API object. It’s a bridge between your stream implementation and the underlying audio system. Players are reusable, they wrap a single stream at a time. You can create tons of Player objects in your game.
IT format) • Unreal Tournament (1998, IT format) • Age of Wonders (1996, IT format) • Star Control 2 (1992, MOD format) • Several first Final Fantasy games (MOD format) …most modular formats can be converted to XM
instructions about how to play the music and samples data Can’t be edited by a human Can be easily edited using a Tracker software Can’t be transformed on-the-fly during the playback Can be manipulated by a program in many ways
instructions about how to play the music and samples data Can’t be edited by a human Can be easily edited using a Tracker software Can’t be transformed on-the-fly during the playback Can be manipulated by a program in many ways Avg. size is 3-7 MB Avg. size is 50-500 KB
for j := range p.Rows { row := &p.Rows[j] for _, noteID := range row.Notes { n := module.Notes[noteID] kind := t.GetInstrumentKind(n.Instrument) if kind != edrum.UndefinedInstrument { // Skip this instrument. It will be played by the player. continue } // Remove this note from the track. } } }
rhythm consistency • Create tab sheets for an XM track automatically • Play XM tracks at different speed and effects • This is not limited to drums-only, any MIDI-device will do • Record the player and build a combined XM track • Build colored sound wave based on inst&chan index
Evaluating the effects/notes for a “tick” 2. Rendering the PCM bytes for the given tick (1) is XM-specific, (2) is what any player would do Rendering the PCM dominates the run time: 90-95%
generate PCM bytes from the module Compilation happens only once. A module can be played multiple times. This library favors the playback efficiency (zero alloc).
numRampPoints for i := 0; i < rampBytes; i += 4 { // ... generate PCM with ramping } // 80-90% of bytes don’t need ramping: for i := rampBytes; i < n; i += 4 { // ... generate PCM without ramping (super fast) }
to XM easily: • MOD -> XM (I use MilkyTracker for this conversion) • S3M -> XM (MilkyTracker and modplug) • IT -> XM (MilkyTracker) Amiga frequencies can be converted to linear too.
player implementation in C • MilkyTracker sources (implements XM as well) • Modarchive (modular music collection) • My XM library for Go • Ebitengine Discord channel (international)
Game development in Go is a thing (try it out!) • Modular music (esp. XM) is still relevant • You can play the XM music in Ebitengine directly • Modular music can sound cool (Deus Ex OST, Drozerix)
Game development in Go is a thing (try it out!) • Modular music (esp. XM) is still relevant • You can play the XM music in Ebitengine directly • Modular music can sound cool (Deus Ex OST, Drozerix) • XM players are not slow (see benchmarks)