func update() { lock.Lock() defer lock.Unlock() _, write, err := dsound.GetPlayAndWriteCursors() if err != nil { lastError = err return } if write != writeCursor { var delta uint if write > writeCursor { delta = write - writeCursor } else { // wrap-around happened in DirectSound's ring buffer delta = write + dsound.BufferSize() - writeCursor } advanceSoundsByBytes(int(delta)) // rewrite the whole look-ahead with newly mixed data lastError = dsound.WriteToSoundBuffer(mix(), write) if lastError != nil { return } } writeCursor = write }
// Init sets up DirectSound and prepares for mixing and playing sounds. It // starts a Go routine that periodically writes to the sound buffer to output // to the sound card. // Call Close when you are done with the mixer. func Init() error { initLock.Lock() defer initLock.Unlock() if inited { return nil } if err := dsound.Init(44100); err != nil { return err } writeAheadByteCount := bytesPerSecond / 10 // buffer 100ms // make sure it is evenly dividable into samples writeAheadByteCount -= writeAheadByteCount % bytesPerSample writeAheadBuffer = make([]byte, writeAheadByteCount) mixBuffer = make([]float32, writeAheadByteCount/2) // 2 bytes form one value leftBuffer = mixBuffer[:len(mixBuffer)/2] rightBuffer = mixBuffer[len(mixBuffer)/2:] volume = 1 // initially write silence to sound buffer if err := dsound.WriteToSoundBuffer(writeAheadBuffer, 0); err != nil { return err } if err := dsound.StartSound(); err != nil { return err } stop = make(chan bool) go func() { pulse := time.Tick(10 * time.Millisecond) for { select { case <-pulse: update() if lastError != nil { return } case <-stop: return default: time.Sleep(1 * time.Millisecond) } } }() inited = true return nil }