312 lines
7.9 KiB
Go
312 lines
7.9 KiB
Go
// Forked by Tim Shannon 2012
|
|
// Copyright 2009 Peter H. Froehlich. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// C-level binding for OpenAL's "alc" API.
|
|
//
|
|
// Please consider using the Go-level binding instead.
|
|
//
|
|
// Note that "alc" introduces the exact same types as "al"
|
|
// but with different names. Check the documentation of
|
|
// openal/al for more information about the mapping to
|
|
// Go types.
|
|
//
|
|
// XXX: Sadly we have to returns pointers for both Device
|
|
// and Context to avoid problems with implicit assignments
|
|
// in clients. It's sad because it makes the overhead a
|
|
// lot higher, each of those calls triggers an allocation.
|
|
package openal
|
|
|
|
//#cgo linux LDFLAGS: -lopenal
|
|
//#cgo darwin LDFLAGS: -framework OpenAL
|
|
//#include <stdlib.h>
|
|
//#include <string.h>
|
|
//#include "local.h"
|
|
/*
|
|
ALCdevice *walcOpenDevice(const char *devicename) {
|
|
return alcOpenDevice(devicename);
|
|
}
|
|
const ALCchar *alcGetString( ALCdevice *device, ALCenum param );
|
|
void walcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, void *data) {
|
|
alcGetIntegerv(device, param, size, data);
|
|
}
|
|
ALCdevice *walcCaptureOpenDevice(const char *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize) {
|
|
return alcCaptureOpenDevice(devicename, frequency, format, buffersize);
|
|
}
|
|
ALCint walcGetInteger(ALCdevice *device, ALCenum param) {
|
|
ALCint result;
|
|
alcGetIntegerv(device, param, 1, &result);
|
|
return result;
|
|
}
|
|
*/
|
|
import "C"
|
|
import "unsafe"
|
|
|
|
const (
|
|
Frequency = 0x1007 // int Hz
|
|
Refresh = 0x1008 // int Hz
|
|
Sync = 0x1009 // bool
|
|
MonoSources = 0x1010 // int
|
|
StereoSources = 0x1011 // int
|
|
)
|
|
|
|
// The Specifier string for default device?
|
|
const (
|
|
DefaultDeviceSpecifier = 0x1004
|
|
DeviceSpecifier = 0x1005
|
|
Extensions = 0x1006
|
|
AllDevicesSpecifier = 0x1013
|
|
)
|
|
|
|
// ?
|
|
const (
|
|
MajorVersion = 0x1000
|
|
MinorVersion = 0x1001
|
|
)
|
|
|
|
// ?
|
|
const (
|
|
AttributesSize = 0x1002
|
|
AllAttributes = 0x1003
|
|
)
|
|
|
|
// Capture extension
|
|
const (
|
|
CaptureDeviceSpecifier = 0x310
|
|
CaptureDefaultDeviceSpecifier = 0x311
|
|
CaptureSamples = 0x312
|
|
)
|
|
|
|
// warning: this function does not free internal pointers
|
|
// warning: memory leak
|
|
func GetStrings(param int32) []string {
|
|
start := C.alcGetString(nil, C.ALenum(param))
|
|
ptr := unsafe.Pointer(start)
|
|
if ptr == nil {
|
|
return nil
|
|
}
|
|
ret := make([]string, 0)
|
|
offset := uint(0)
|
|
for {
|
|
slen := uint(C.strlen((*C.char)(ptr)))
|
|
if slen == 0 {
|
|
break
|
|
}
|
|
ret = append(ret, C.GoStringN((*C.char)(ptr), C.int(slen)))
|
|
ptr = unsafe.Pointer(uintptr(ptr) + uintptr(slen+1))
|
|
offset += (slen + 1)
|
|
}
|
|
ptr = unsafe.Pointer(uintptr(ptr) - uintptr(offset))
|
|
// This should be freeable; I've tried everything I can think of to free the returned pointer.
|
|
// need to make sure alcchar doesn't have a weird free thingie, but that's all I can think of.
|
|
// C.free(unsafe.Pointer(start))
|
|
return ret
|
|
}
|
|
|
|
type Device struct {
|
|
handle *C.ALCdevice
|
|
}
|
|
|
|
func (self *Device) getError() uint32 {
|
|
return uint32(C.alcGetError(self.handle))
|
|
}
|
|
|
|
// Err() returns the most recent error generated
|
|
// in the AL state machine.
|
|
func (self *Device) Err() error {
|
|
switch code := self.getError(); code {
|
|
case 0x0000:
|
|
return nil
|
|
case 0xA001:
|
|
return ErrInvalidDevice
|
|
case 0xA002:
|
|
return ErrInvalidContext
|
|
case 0xA003:
|
|
return ErrInvalidEnum
|
|
case 0xA004:
|
|
return ErrInvalidValue
|
|
case 0xA005:
|
|
return ErrOutOfMemory
|
|
default:
|
|
return ErrorCode(code)
|
|
}
|
|
}
|
|
|
|
func OpenDevice(name string) *Device {
|
|
// TODO: turn empty string into nil?
|
|
// TODO: what about an error return?
|
|
p := C.CString(name)
|
|
h := C.walcOpenDevice(p)
|
|
C.free(unsafe.Pointer(p))
|
|
if h == nil {
|
|
return nil
|
|
}
|
|
return &Device{h}
|
|
}
|
|
|
|
func (self *Device) cHandle() *C.ALCdevice { return self.handle }
|
|
|
|
func (self *Device) CloseDevice() bool {
|
|
//TODO: really a method? or not?
|
|
return C.alcCloseDevice(self.cHandle()) != 0
|
|
}
|
|
|
|
func (self *Device) CreateContext() *Context {
|
|
// TODO: really a method?
|
|
// TODO: attrlist support
|
|
c := C.alcCreateContext(self.cHandle(), nil)
|
|
if c == nil {
|
|
return nil
|
|
}
|
|
return &Context{c}
|
|
}
|
|
|
|
func (self *Device) GetIntegerv(param uint32, size uint32) (result []int32) {
|
|
if size == 0 {
|
|
return []int32{}
|
|
}
|
|
result = make([]int32, size)
|
|
C.walcGetIntegerv(self.cHandle(), C.ALCenum(param), C.ALCsizei(size), unsafe.Pointer(&result[0]))
|
|
return
|
|
}
|
|
|
|
func (self *Device) GetInteger(param uint32) int32 {
|
|
return int32(C.walcGetInteger(self.cHandle(), C.ALCenum(param)))
|
|
}
|
|
|
|
type CaptureDevice struct {
|
|
Device
|
|
sampleSize uint32
|
|
}
|
|
|
|
func CaptureOpenDevice(name string, freq uint32, format Format, size uint32) *CaptureDevice {
|
|
// TODO: turn empty string into nil?
|
|
// TODO: what about an error return?
|
|
p := C.CString(name)
|
|
h := C.walcCaptureOpenDevice(p, C.ALCuint(freq), C.ALCenum(format), C.ALCsizei(size))
|
|
C.free(unsafe.Pointer(p))
|
|
if h == nil {
|
|
return nil
|
|
}
|
|
return &CaptureDevice{Device{h}, uint32(format.SampleSize())}
|
|
}
|
|
|
|
// XXX: Override Device.CloseDevice to make sure the correct
|
|
// C function is called even if someone decides to use this
|
|
// behind an interface.
|
|
func (self *CaptureDevice) CloseDevice() bool {
|
|
return C.alcCaptureCloseDevice(self.cHandle()) != 0
|
|
}
|
|
|
|
func (self *CaptureDevice) CaptureCloseDevice() bool {
|
|
return self.CloseDevice()
|
|
}
|
|
|
|
func (self *CaptureDevice) CaptureStart() {
|
|
C.alcCaptureStart(self.cHandle())
|
|
}
|
|
|
|
func (self *CaptureDevice) CaptureStop() {
|
|
C.alcCaptureStop(self.cHandle())
|
|
}
|
|
|
|
func (self *CaptureDevice) CaptureTo(data []byte) {
|
|
if len(data) == 0 {
|
|
return
|
|
}
|
|
C.alcCaptureSamples(self.cHandle(), unsafe.Pointer(&data[0]), C.ALCsizei(uint32(len(data))/self.sampleSize))
|
|
}
|
|
|
|
func (self *CaptureDevice) CaptureToInt16(data []int16) {
|
|
if len(data) == 0 {
|
|
return
|
|
}
|
|
C.alcCaptureSamples(self.cHandle(), unsafe.Pointer(&data[0]), C.ALCsizei(uint32(len(data))*2/self.sampleSize))
|
|
}
|
|
|
|
func (self *CaptureDevice) CaptureMono8To(data []byte) {
|
|
self.CaptureTo(data)
|
|
}
|
|
|
|
func (self *CaptureDevice) CaptureMono16To(data []int16) {
|
|
self.CaptureToInt16(data)
|
|
}
|
|
|
|
func (self *CaptureDevice) CaptureStereo8To(data [][2]byte) {
|
|
if len(data) == 0 {
|
|
return
|
|
}
|
|
C.alcCaptureSamples(self.cHandle(), unsafe.Pointer(&data[0]), C.ALCsizei(uint32(len(data))*2/self.sampleSize))
|
|
}
|
|
|
|
func (self *CaptureDevice) CaptureStereo16To(data [][2]int16) {
|
|
if len(data) == 0 {
|
|
return
|
|
}
|
|
C.alcCaptureSamples(self.cHandle(), unsafe.Pointer(&data[0]), C.ALCsizei(uint32(len(data))*4/self.sampleSize))
|
|
}
|
|
|
|
func (self *CaptureDevice) CaptureSamples(size uint32) (data []byte) {
|
|
data = make([]byte, size*self.sampleSize)
|
|
self.CaptureTo(data)
|
|
return
|
|
}
|
|
|
|
func (self *CaptureDevice) CaptureSamplesInt16(size uint32) (data []int16) {
|
|
data = make([]int16, size*self.sampleSize/2)
|
|
self.CaptureToInt16(data)
|
|
return
|
|
}
|
|
|
|
func (self *CaptureDevice) CapturedSamples() (size uint32) {
|
|
return uint32(self.GetInteger(CaptureSamples))
|
|
}
|
|
|
|
///// Context ///////////////////////////////////////////////////////
|
|
|
|
// Context encapsulates the state of a given instance
|
|
// of the OpenAL state machine. Only one context can
|
|
// be active in a given process.
|
|
type Context struct {
|
|
handle *C.ALCcontext
|
|
}
|
|
|
|
// A context that doesn't exist, useful for certain
|
|
// context operations (see OpenAL documentation for
|
|
// details).
|
|
var NullContext Context
|
|
|
|
func (self *Context) cHandle() *C.ALCcontext { return self.handle }
|
|
|
|
// Renamed, was MakeContextCurrent.
|
|
func (self *Context) Activate() bool {
|
|
return C.alcMakeContextCurrent(self.cHandle()) != alFalse
|
|
}
|
|
|
|
// Renamed, was ProcessContext.
|
|
func (self *Context) Process() {
|
|
C.alcProcessContext(self.cHandle())
|
|
}
|
|
|
|
// Renamed, was SuspendContext.
|
|
func (self *Context) Suspend() {
|
|
C.alcSuspendContext(self.cHandle())
|
|
}
|
|
|
|
// Renamed, was DestroyContext.
|
|
func (self *Context) Destroy() {
|
|
C.alcDestroyContext(self.cHandle())
|
|
self.handle = nil
|
|
}
|
|
|
|
// Renamed, was GetContextsDevice.
|
|
func (self *Context) GetDevice() *Device {
|
|
return &Device{C.alcGetContextsDevice(self.cHandle())}
|
|
}
|
|
|
|
// Renamed, was GetCurrentContext.
|
|
func CurrentContext() *Context {
|
|
return &Context{C.alcGetCurrentContext()}
|
|
}
|