barnard/gumble/go-openal/openal/alcCore.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()))}
}