305 lines
8.1 KiB
Go
305 lines
8.1 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 {
|
|
// Use uintptr instead of *C.ALCdevice.
|
|
// On Mac OS X, this value is 0x18 and might cause crash with a raw pointer.
|
|
handle uintptr
|
|
}
|
|
|
|
func (self *Device) getError() uint32 {
|
|
return uint32(C.alcGetError((*C.ALCdevice)(unsafe.Pointer(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{uintptr((unsafe.Pointer)(h))}
|
|
}
|
|
|
|
func (self *Device) cHandle() *C.ALCdevice {
|
|
return (*C.ALCdevice)(unsafe.Pointer(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{uintptr(unsafe.Pointer(c))}
|
|
}
|
|
|
|
func (self *Device) GetIntegerv(param uint32, size uint32) (result []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{uintptr(unsafe.Pointer(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) {
|
|
C.alcCaptureSamples(self.cHandle(), unsafe.Pointer(&data[0]), C.ALCsizei(uint32(len(data))/self.sampleSize))
|
|
}
|
|
|
|
func (self *CaptureDevice) CaptureToInt16(data []int16) {
|
|
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) {
|
|
C.alcCaptureSamples(self.cHandle(), unsafe.Pointer(&data[0]), C.ALCsizei(uint32(len(data))*2/self.sampleSize))
|
|
}
|
|
|
|
func (self *CaptureDevice) CaptureStereo16To(data [][2]int16) {
|
|
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 {
|
|
// Use uintptr instead of *C.ALCcontext
|
|
// On Mac OS X, this value is 0x19 and might cause crash with a raw pointer.
|
|
handle uintptr
|
|
}
|
|
|
|
// 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 (*C.ALCcontext)(unsafe.Pointer(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 = uintptr(unsafe.Pointer(nil))
|
|
}
|
|
|
|
// Renamed, was GetContextsDevice.
|
|
func (self *Context) GetDevice() *Device {
|
|
return &Device{uintptr(unsafe.Pointer(C.alcGetContextsDevice(self.cHandle())))}
|
|
}
|
|
|
|
// Renamed, was GetCurrentContext.
|
|
func CurrentContext() *Context {
|
|
return &Context{uintptr(unsafe.Pointer(C.alcGetCurrentContext()))}
|
|
}
|