2013-02-10

Go-SDL with callback support: done!

It is always fashioning to discover the type of big challenges that can arise from an apparently trivial task, like porting an ncurses game to Go! language. It's like watching the unexpected chessboard developments that can happen between two beginners.

This time I wanted to add support for sound through SDL_Audio, so I came up with a decent square-wave generator and started using this Go-SDL fork for audio output.
Problem: SDL audio works with samples or callbacks, and my samples are generated on the fly, being simple PC-buzzer-like sounds.

Strangely enough, that Go-SDL package I found uses a very complex architecture of mutexes and hard-coded hacks to simulate possibility of sending audio synchronously from Go, and only continuous streaming is supported, no custom samples playing, although the API fingerprint seems like it could support it.

Without continuous playback, my game was condemned to display
ALSA lib pcm.c:7339:(snd_pcm_recover) underrun occurred
 from time to time during gameplay. And that sucks.

The cage of Love where Go
is currently held prisoner without
proper support of C integration
I came in contact with author, and the end of a short discussion I wanted to roll my own version using CGO callbacks, easy done, but then I met this guy:
runtime: cgo callback on thread not created by Go.
runtime: signal received on thread not created by Go.
I digged a bit and found out the reason behind it, basically Go language is not (yet) that well-integrated with C language.
However, thanks to Roger Peppe's callback package it is possible to use C callbacks in Go, like Gordon K. did for PortAudio. It is a hack, but a nice one.
At this point I was going to use PortAudio because it already uses that callback package, but PortAudio has an extra "feature": incredible garbage in the console terminal, and that was not going to be bearable for my little ncurses game.

So I armed my fingers and started coding a fix, here's the result:
https://github.com/neagix/Go-SDL
I removed most mutexes and synchronization black magic and I am now using a single synchronous channel for samples mixing, and it has also support of custom sound-generation callbacks. The cherry on top is that it comes with a nice PC-speaker buzz sound simulator, for all you nostalgic BEEP guys :)

Talk about how much you can learn with a such a simple game :)

At the end of this coding adventure I have to agree with Otstol that it is a huge limitation (to usage&adoption) that Go! language does not sport better callbacks support. I am quite sure all these fireworks will soon be obsolete because the Go Authors will fix this ;)

* = the game in question is Langwar, my battering ram used to discover the Go! language and also bring back what I recognize with some nostalgia as a classic game useful for learning programming

Update 16 June 2013: thanks to G. Klaus for letting me know about Go having fixed the issue, I have now updated my fork of Go-SDL

3 comments:

  1. FYI, the Go runtime was fixed 10 days after your post :-)
    https://code.google.com/p/go/source/detail?r=1d5a80b07916

    ReplyDelete
    Replies
    1. oh, this is amazing! thanks for sharing, I never noticed :)

      Delete
    2. FYI, I have updated my fork to not use anymore that callback package

      Delete