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()))}
 | |
| }
 |