Example #1
0
func main() {

	// Initial setup, open device and initialize context
	device, err := alc.OpenDefaultDevice()
	if err != nil {
		fmt.Println(err)
	}

	context, err := alc.CreateDefaultContext(device)
	if err != nil {
		panic(err)
	}

	if err = context.MakeCurrent(); err != nil {
		panic(err)
	}
	if err = context.Process(); err != nil {
		panic(err)
	}

	// Print version information and such, mostly for fun
	deviceName, _ := device.DeviceSpecifier()
	version, _ := al.GetVersion()
	vendor, _ := al.GetVendor()
	extensions, _ := al.GetExtensions()
	fmt.Println("Using default device: ", deviceName)
	fmt.Println("OpenAL version: ", version)
	fmt.Println("Device vendor: ", vendor)
	fmt.Println("Extensions available: ", extensions)

	// Make our default audio source, it makes more sense when doing 3D positional audio
	// since it defines where the sound is coming from, but for such a simple endeavor
	// it just sits there
	source, err := al.GenSource()
	if err != nil {
		panic(err)
	}

	// Set the Pitch and Gain (volume), because you won't hear anything if you don't
	source.SetPitch(1.0)
	source.SetGain(1.0)
	source.SetLooping(false)

	// Get a few buffers to gradually fill the audio stream, like how Youtube videos and such buffer
	// 3 is just an arbitrary number
	bufs, err := al.GenBuffers(3)
	if err != nil {
		panic(err)
	}

	defer Cleanup(source, bufs, context, device)

	// Find the name of whatever .wav file we want
	if len(os.Args) < 2 {
		panic("Need to know what wav file to play! List it as an argument")
	}

	// Begin streaming that file (in another goroutine)
	requestChan, fillChan, header, err := wav.StreamFromFile(os.Args[1])
	if err != nil {
		panic(err)
	}

	// Convert the wav metadata into a struct easy to pass into OpenAL
	bufData, err := wav.ToEmptyALData(header)
	if err != nil {
		panic(err)
	}

	var ok bool = true

	// Initial fill
	// We can either use a func and return for loop control,
	// or use a labelled break. I prefer the anonymous func and return, but
	// it's really just a matter of taste
	func() {
		for i := 0; i < 3; i++ {
			select {
			case requestChan <- bufData.Data:
			case _, ok = <-fillChan:
				if !ok {
					return
				}
			}

			bufData.Data, ok = <-fillChan
			if !ok {
				return
			}

			bufs[i].BufferData(bufData)
		}
	}()

	// Only do this if we still have data left
	if ok {

		// Setup
		err = source.QueueBuffers(bufs...)
		if err != nil {
			panic(err)
		}

		err = source.Play()
		if err != nil {
			panic(err)
		}

		//Keep filling the stream
		func() {
			for i := 0; ; i = (i + 1) % 3 {

				// Ugly spin loop, but there's really no other way to poll if AL is done with some data,
				// if we don't check for this, we'll get an error when we try to unqueue a buffer
				for j, _ := source.BuffersProcessed(); j < 1; j, _ = source.BuffersProcessed() {
				}

				err = source.UnqueueBuffers(bufs[i])
				if err != nil {
					panic(err)
				}

				select {
				case requestChan <- bufData.Data:
				case _, ok = <-fillChan:
					if !ok {
						return
					}
				}

				bufData.Data, ok = <-fillChan
				if !ok {
					return
				}

				err = bufs[i].BufferData(bufData)
				if err != nil {
					panic(err)
				}

				err = source.QueueBuffers(bufs[i])
				if err != nil {
					panic(err)
				}

				if state, _ := source.GetSourceState(); state != al.Playing {
					source.Play()
				}
			}
		}()

	} else {
		// This doesn't work well for short files
		return
	}

	close(requestChan)

	// Keep playing until it's done
	for state, _ := source.GetSourceState(); state == al.Playing; state, _ = source.GetSourceState() {
		source.Play()
	}

}
Example #2
0
func main() {

	device, err := alc.OpenDefaultDevice()
	if err != nil {
		fmt.Println(err)
	}

	fmt.Println(device.DeviceSpecifier())

	context, err := alc.CreateDefaultContext(device)
	if err != nil {
		panic(err)
	}

	if err = context.MakeCurrent(); err != nil {
		panic(err)
	}
	if err = context.Process(); err != nil {
		panic(err)
	}

	fmt.Println(al.GetVersion())
	fmt.Println(al.GetVendor())
	fmt.Println(al.GetExtensions())

	source, err := al.GenSource()
	rawDat, err := wav.LoadWavFile("gameover.wav")

	if err != nil {
		panic(err)
	}

	dat, err := wav.ToALData(rawDat)
	if err != nil {
		panic(err)
	}

	buf, _ := al.GenBuffer()
	err = buf.BufferData(dat)
	if err != nil {
		panic(err)
	}

	err = source.SetBuffer(buf)
	if err != nil {
		panic(err)
	}
	source.SetPitch(1.0)
	source.SetGain(1.0)
	source.SetLooping(false)

	err = source.Play()

	time.Sleep(1500 * time.Millisecond)

	source.Stop()
	source.Delete()
	buf.Delete()
	context.Destroy()
	device.Close()
}