1

I'm trying to play audio in Go, asynchronously, using PortAudio. As far as I'm aware PortAudio handles its own threading, so I don't need to use any of Go's build-in concurrency stuff. I'm using libsndfile to load the file (also Go bindings). Here is my code:

type Track struct {
    stream   *portaudio.Stream
    playhead int
    buffer   []int32
}

func LoadTrackFilesize(filename string, loop bool, bytes int) *Track {
    // Load file
    var info sndfile.Info
    soundFile, err := sndfile.Open(filename, sndfile.Read, &info)
    if err != nil {
        fmt.Printf("Could not open file: %s\n", filename)
        panic(err)
    }
    buffer := make([]int32, bytes)
    numRead, err := soundFile.ReadItems(buffer)
    if err != nil {
        fmt.Printf("Error reading from file: %s\n", filename)
        panic(err)
    }
    defer soundFile.Close()

    // Create track
    track := Track{
        buffer: buffer[:numRead],
    }

    // Create stream
    stream, err := portaudio.OpenDefaultStream(
        0, 2, float64(44100), portaudio.FramesPerBufferUnspecified, track.playCallback,
    )
    if err != nil {
        fmt.Printf("Couldn't get stream for file: %s\n", filename)
    }
    track.stream = stream

    return &track
}

func (t *Track) playCallback(out []int32) {
    for i := range out {
        out[i] = t.buffer[(t.playhead+i)%len(t.buffer)]
    }
    t.playhead += len(out) % len(t.buffer)
}

func (t *Track) Play() {
    t.stream.Start()
}

Using these functions, after initialising PortAudio and all the rest, plays the audio track I supply - just. It's very laggy, and slows down the rest of my application (a game loop).

However, if I change the frames per buffer value from FramesPerBufferUnspecified to something high, say, 1024, the audio plays fine and doesn't interfere with the rest of my application.

Why is this? The PortAudio documentation suggests that using the unspecified value will 'choose a value for optimum latency', but I'm definitely not seeing that.

Additionally, when playing with this very high value, I notice some tiny artefacts - little 'popping' noises - in the audio.

Is there something wrong with my callback function, or anything else, that could be causing one or both of these problems?

I'm using OSX 10.10.5, with Go 1.3.3 and the libsndfile and portaudio from Homebrew.

Thanks.

Joel Auterson
  • 728
  • 1
  • 7
  • 26
  • I recommend upgrading to 1.5 and trying again, then update the question if you still have the same problem. – OneOfOne Sep 01 '15 at 00:21
  • you can make a prof to find out the `laggy` codes – Jiang YD Sep 01 '15 at 00:41
  • @OneOfOne Thanks, that seems to have helped with the first issue - I'm still getting a lot of these odd audio artefacts, though. – Joel Auterson Sep 01 '15 at 06:35
  • @OneOfOne Looks like using float32s instead of int32s in the buffer fixed the previous issue - I checked with sndfile-info and it seems the track I was using has places where the signal is above 1, which mustn't be represented correctly in the ints? Not sure exactly. If you want to add the above as an answer I'll mark it correct. Thanks again. – Joel Auterson Sep 01 '15 at 06:49

1 Answers1

1

Moving to the comment to an answer:

Always test with the latest version of Go.

Also, @Joel figured out that you need to use float32 instead of int32.

OneOfOne
  • 95,033
  • 20
  • 184
  • 185