move go bindings into contrib/go/rtaudio subdirectory
[rtaudio-cdist.git] / rtaudio.go
diff --git a/rtaudio.go b/rtaudio.go
deleted file mode 100644 (file)
index 8b0f644..0000000
+++ /dev/null
@@ -1,563 +0,0 @@
-package rtaudio
-
-/*
-
-#cgo CXXFLAGS: -g
-#cgo LDFLAGS: -lstdc++ -g
-
-#cgo linux CXXFLAGS: -D__LINUX_ALSA__
-#cgo linux LDFLAGS: -lm -lasound -pthread
-
-#cgo linux,pulseaudio CXXFLAGS: -D__LINUX_PULSE__
-#cgo linux,pulseaudio LDFLAGS: -lpulse -lpulse-simple
-
-#cgo jack CXXFLAGS: -D__UNIX_JACK__
-#cgo jack LDFLAGS: -ljack
-
-#cgo windows CXXFLAGS: -D__WINDOWS_WASAPI__
-#cgo windows LDFLAGS: -lm -luuid -lksuser -lwinmm -lole32
-
-#cgo darwin CXXFLAGS: -D__MACOSX_CORE__
-#cgo darwin LDFLAGS: -framework CoreAudio -framework CoreFoundation
-
-#include <stdlib.h>
-#include <stdint.h>
-#include "rtaudio_c.h"
-
-extern int goCallback(void *out, void *in, unsigned int nFrames,
-       double stream_time, rtaudio_stream_status_t status, void *userdata);
-
-static inline void cgoRtAudioOpenStream(rtaudio_t audio,
-       rtaudio_stream_parameters_t *output_params,
-       rtaudio_stream_parameters_t *input_params,
-       rtaudio_format_t format,
-       unsigned int sample_rate,
-       unsigned int *buffer_frames,
-       int cb_id,
-       rtaudio_stream_options_t *options) {
-               rtaudio_open_stream(audio, output_params, input_params,
-                       format, sample_rate, buffer_frames,
-                       goCallback, (void *)(uintptr_t)cb_id, options, NULL);
-}
-*/
-import "C"
-import (
-       "errors"
-       "sync"
-       "time"
-       "unsafe"
-)
-
-// API is an enumeration of available compiled APIs. Supported API include
-// Alsa/PulseAudio/OSS, Jack, CoreAudio, WASAPI/ASIO/DS and dummy API.
-type API C.rtaudio_api_t
-
-const (
-       // APIUnspecified looks for a working compiled API.
-       APIUnspecified API = C.RTAUDIO_API_UNSPECIFIED
-       // APILinuxALSA uses the Advanced Linux Sound Architecture API.
-       APILinuxALSA = C.RTAUDIO_API_LINUX_ALSA
-       // APILinuxPulse uses the Linux PulseAudio API.
-       APILinuxPulse = C.RTAUDIO_API_LINUX_PULSE
-       // APILinuxOSS uses the Linux Open Sound System API.
-       APILinuxOSS = C.RTAUDIO_API_LINUX_OSS
-       // APIUnixJack uses the Jack Low-Latency Audio Server API.
-       APIUnixJack = C.RTAUDIO_API_UNIX_JACK
-       // APIMacOSXCore uses Macintosh OS-X Core Audio API.
-       APIMacOSXCore = C.RTAUDIO_API_MACOSX_CORE
-       // APIWindowsWASAPI uses the Microsoft WASAPI API.
-       APIWindowsWASAPI = C.RTAUDIO_API_WINDOWS_WASAPI
-       // APIWindowsASIO uses the Steinberg Audio Stream I/O API.
-       APIWindowsASIO = C.RTAUDIO_API_WINDOWS_ASIO
-       // APIWindowsDS uses the Microsoft Direct Sound API.
-       APIWindowsDS = C.RTAUDIO_API_WINDOWS_DS
-       // APIDummy is a compilable but non-functional API.
-       APIDummy = C.RTAUDIO_API_DUMMY
-)
-
-func (api API) String() string {
-       switch api {
-       case APIUnspecified:
-               return "unspecified"
-       case APILinuxALSA:
-               return "alsa"
-       case APILinuxPulse:
-               return "pulse"
-       case APILinuxOSS:
-               return "oss"
-       case APIUnixJack:
-               return "jack"
-       case APIMacOSXCore:
-               return "coreaudio"
-       case APIWindowsWASAPI:
-               return "wasapi"
-       case APIWindowsASIO:
-               return "asio"
-       case APIWindowsDS:
-               return "directsound"
-       case APIDummy:
-               return "dummy"
-       }
-       return "?"
-}
-
-// StreamStatus defines over- or underflow flags in the audio callback.
-type StreamStatus C.rtaudio_stream_status_t
-
-const (
-       // StatusInputOverflow indicates that data was discarded because of an
-       // overflow condition at the driver.
-       StatusInputOverflow StreamStatus = C.RTAUDIO_STATUS_INPUT_OVERFLOW
-       // StatusOutputUnderflow indicates that the output buffer ran low, likely
-       // producing a break in the output sound.
-       StatusOutputUnderflow StreamStatus = C.RTAUDIO_STATUS_OUTPUT_UNDERFLOW
-)
-
-// Version returns current RtAudio library version string.
-func Version() string {
-       return C.GoString(C.rtaudio_version())
-}
-
-// CompiledAPI determines the available compiled audio APIs.
-func CompiledAPI() (apis []API) {
-       capis := (*[1 << 30]C.rtaudio_api_t)(unsafe.Pointer(C.rtaudio_compiled_api()))
-       for i := 0; ; i++ {
-               api := capis[i]
-               if api == C.RTAUDIO_API_UNSPECIFIED {
-                       break
-               }
-               apis = append(apis, API(api))
-       }
-       return apis
-}
-
-// DeviceInfo is the public device information structure for returning queried values.
-type DeviceInfo struct {
-       Name              string
-       Probed            bool
-       NumOutputChannels int
-       NumInputChannels  int
-       NumDuplexChannels int
-       IsDefaultOutput   bool
-       IsDefaultInput    bool
-
-       //rtaudio_format_t native_formats;
-
-       PreferredSampleRate uint
-       SampleRates         []int
-}
-
-// StreamParams is the structure for specifying input or output stream parameters.
-type StreamParams struct {
-       DeviceID     uint
-       NumChannels  uint
-       FirstChannel uint
-}
-
-// StreamFlags is a set of RtAudio stream option flags.
-type StreamFlags C.rtaudio_stream_flags_t
-
-const (
-       // FlagsNoninterleaved is set to use non-interleaved buffers (default = interleaved).
-       FlagsNoninterleaved = C.RTAUDIO_FLAGS_NONINTERLEAVED
-       // FlagsMinimizeLatency when set attempts to configure stream parameters for lowest possible latency.
-       FlagsMinimizeLatency = C.RTAUDIO_FLAGS_MINIMIZE_LATENCY
-       // FlagsHogDevice when set attempts to grab device for exclusive use.
-       FlagsHogDevice = C.RTAUDIO_FLAGS_HOG_DEVICE
-       // FlagsScheduleRealtime is set in attempt to select realtime scheduling (round-robin) for the callback thread.
-       FlagsScheduleRealtime = C.RTAUDIO_FLAGS_SCHEDULE_REALTIME
-       // FlagsAlsaUseDefault is set to use the "default" PCM device (ALSA only).
-       FlagsAlsaUseDefault = C.RTAUDIO_FLAGS_ALSA_USE_DEFAULT
-)
-
-// StreamOptions is the structure for specifying stream options.
-type StreamOptions struct {
-       Flags      StreamFlags
-       NumBuffers uint
-       Priotity   int
-       Name       string
-}
-
-// RtAudio is a "controller" used to select an available audio i/o interface.
-type RtAudio interface {
-       Destroy()
-       CurrentAPI() API
-       Devices() ([]DeviceInfo, error)
-       DefaultOutputDevice() int
-       DefaultInputDevice() int
-
-       Open(out, in *StreamParams, format Format, sampleRate uint, frames uint, cb Callback, opts *StreamOptions) error
-       Close()
-       Start() error
-       Stop() error
-       Abort() error
-
-       IsOpen() bool
-       IsRunning() bool
-
-       Latency() (int, error)
-       SampleRate() (uint, error)
-       Time() (time.Duration, error)
-       SetTime(time.Duration) error
-
-       ShowWarnings(bool)
-}
-
-type rtaudio struct {
-       audio          C.rtaudio_t
-       cb             Callback
-       inputChannels  int
-       outputChannels int
-       format         Format
-}
-
-var _ RtAudio = &rtaudio{}
-
-// Create a new RtAudio instance using the given API.
-func Create(api API) (RtAudio, error) {
-       audio := C.rtaudio_create(C.rtaudio_api_t(api))
-       if C.rtaudio_error(audio) != nil {
-               return nil, errors.New(C.GoString(C.rtaudio_error(audio)))
-       }
-       return &rtaudio{audio: audio}, nil
-}
-
-func (audio *rtaudio) Destroy() {
-       C.rtaudio_destroy(audio.audio)
-}
-
-func (audio *rtaudio) CurrentAPI() API {
-       return API(C.rtaudio_current_api(audio.audio))
-}
-
-func (audio *rtaudio) DefaultInputDevice() int {
-       return int(C.rtaudio_get_default_input_device(audio.audio))
-}
-
-func (audio *rtaudio) DefaultOutputDevice() int {
-       return int(C.rtaudio_get_default_output_device(audio.audio))
-}
-
-func (audio *rtaudio) Devices() ([]DeviceInfo, error) {
-       n := C.rtaudio_device_count(audio.audio)
-       devices := []DeviceInfo{}
-       for i := C.int(0); i < n; i++ {
-               cinfo := C.rtaudio_get_device_info(audio.audio, i)
-               if C.rtaudio_error(audio.audio) != nil {
-                       return nil, errors.New(C.GoString(C.rtaudio_error(audio.audio)))
-               }
-               sr := []int{}
-               for _, r := range cinfo.sample_rates {
-                       if r == 0 {
-                               break
-                       }
-                       sr = append(sr, int(r))
-               }
-               devices = append(devices, DeviceInfo{
-                       Name:                C.GoString(&cinfo.name[0]),
-                       Probed:              cinfo.probed != 0,
-                       NumInputChannels:    int(cinfo.input_channels),
-                       NumOutputChannels:   int(cinfo.output_channels),
-                       NumDuplexChannels:   int(cinfo.duplex_channels),
-                       IsDefaultOutput:     cinfo.is_default_output != 0,
-                       IsDefaultInput:      cinfo.is_default_input != 0,
-                       PreferredSampleRate: uint(cinfo.preferred_sample_rate),
-                       SampleRates:         sr,
-               })
-               // TODO: formats
-       }
-       return devices, nil
-}
-
-// Format defines RtAudio data format type.
-type Format int
-
-const (
-       // FormatInt8 uses 8-bit signed integer.
-       FormatInt8 Format = C.RTAUDIO_FORMAT_SINT8
-       // FormatInt16 uses 16-bit signed integer.
-       FormatInt16 = C.RTAUDIO_FORMAT_SINT16
-       // FormatInt24 uses 24-bit signed integer.
-       FormatInt24 = C.RTAUDIO_FORMAT_SINT24
-       // FormatInt32 uses 32-bit signed integer.
-       FormatInt32 = C.RTAUDIO_FORMAT_SINT32
-       // FormatFloat32 uses 32-bit floating point values normalized between (-1..1).
-       FormatFloat32 = C.RTAUDIO_FORMAT_FLOAT32
-       // FormatFloat64 uses 64-bit floating point values normalized between (-1..1).
-       FormatFloat64 = C.RTAUDIO_FORMAT_FLOAT64
-)
-
-// Buffer is a common interface for audio buffers of various data format types.
-type Buffer interface {
-       Len() int
-       Int8() []int8
-       Int16() []int16
-       Int24() []Int24
-       Int32() []int32
-       Float32() []float32
-       Float64() []float64
-}
-
-// Int24 is a helper type to convert int32 values to int24 and back.
-type Int24 [3]byte
-
-// Set Int24 value using the least significant bytes of the given number n.
-func (i *Int24) Set(n int32) {
-       (*i)[0], (*i)[1], (*i)[2] = byte(n&0xff), byte((n&0xff00)>>8), byte((n&0xff0000)>>16)
-}
-
-// Get Int24 value as int32.
-func (i Int24) Get() int32 {
-       n := int32(i[0]) | int32(i[1])<<8 | int32(i[2])<<16
-       if n&0x800000 != 0 {
-               n |= ^0xffffff
-       }
-       return n
-}
-
-type buffer struct {
-       format      Format
-       length      int
-       numChannels int
-       ptr         unsafe.Pointer
-}
-
-func (b *buffer) Len() int {
-       if b.ptr == nil {
-               return 0
-       }
-       return b.length
-}
-
-func (b *buffer) Int8() []int8 {
-       if b.format != FormatInt8 {
-               return nil
-       }
-       if b.ptr == nil {
-               return nil
-       }
-       return (*[1 << 30]int8)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
-}
-
-func (b *buffer) Int16() []int16 {
-       if b.format != FormatInt16 {
-               return nil
-       }
-       if b.ptr == nil {
-               return nil
-       }
-       return (*[1 << 30]int16)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
-}
-
-func (b *buffer) Int24() []Int24 {
-       if b.format != FormatInt24 {
-               return nil
-       }
-       if b.ptr == nil {
-               return nil
-       }
-       return (*[1 << 30]Int24)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
-}
-
-func (b *buffer) Int32() []int32 {
-       if b.format != FormatInt32 {
-               return nil
-       }
-       if b.ptr == nil {
-               return nil
-       }
-       return (*[1 << 30]int32)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
-}
-
-func (b *buffer) Float32() []float32 {
-       if b.format != FormatFloat32 {
-               return nil
-       }
-       if b.ptr == nil {
-               return nil
-       }
-       return (*[1 << 30]float32)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
-}
-
-func (b *buffer) Float64() []float64 {
-       if b.format != FormatFloat64 {
-               return nil
-       }
-       if b.ptr == nil {
-               return nil
-       }
-       return (*[1 << 30]float64)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
-}
-
-// Callback is a client-defined function that will be invoked when input data
-// is available and/or output data is needed.
-type Callback func(out Buffer, in Buffer, dur time.Duration, status StreamStatus) int
-
-var (
-       mu     sync.Mutex
-       audios = map[int]*rtaudio{}
-)
-
-func registerAudio(a *rtaudio) int {
-       mu.Lock()
-       defer mu.Unlock()
-       for i := 0; ; i++ {
-               if _, ok := audios[i]; !ok {
-                       audios[i] = a
-                       return i
-               }
-       }
-}
-
-func unregisterAudio(a *rtaudio) {
-       mu.Lock()
-       defer mu.Unlock()
-       for i := 0; i < len(audios); i++ {
-               if audios[i] == a {
-                       delete(audios, i)
-                       return
-               }
-       }
-}
-
-func findAudio(k int) *rtaudio {
-       mu.Lock()
-       defer mu.Unlock()
-       return audios[k]
-}
-
-//export goCallback
-func goCallback(out, in unsafe.Pointer, frames C.uint, sec C.double,
-       status C.rtaudio_stream_status_t, userdata unsafe.Pointer) C.int {
-
-       k := int(uintptr(userdata))
-       audio := findAudio(k)
-       dur := time.Duration(time.Microsecond * time.Duration(sec*1000000.0))
-       inbuf := &buffer{audio.format, int(frames), audio.inputChannels, in}
-       outbuf := &buffer{audio.format, int(frames), audio.outputChannels, out}
-       return C.int(audio.cb(outbuf, inbuf, dur, StreamStatus(status)))
-}
-
-func (audio *rtaudio) Open(out, in *StreamParams, format Format, sampleRate uint,
-       frames uint, cb Callback, opts *StreamOptions) error {
-       var (
-               cInPtr   *C.rtaudio_stream_parameters_t
-               cOutPtr  *C.rtaudio_stream_parameters_t
-               cOptsPtr *C.rtaudio_stream_options_t
-               cIn      C.rtaudio_stream_parameters_t
-               cOut     C.rtaudio_stream_parameters_t
-               cOpts    C.rtaudio_stream_options_t
-       )
-
-       audio.inputChannels = 0
-       audio.outputChannels = 0
-       if out != nil {
-               audio.outputChannels = int(out.NumChannels)
-               cOut.device_id = C.uint(out.DeviceID)
-               cOut.num_channels = C.uint(out.NumChannels)
-               cOut.first_channel = C.uint(out.FirstChannel)
-               cOutPtr = &cOut
-       }
-       if in != nil {
-               audio.inputChannels = int(in.NumChannels)
-               cIn.device_id = C.uint(in.DeviceID)
-               cIn.num_channels = C.uint(in.NumChannels)
-               cIn.first_channel = C.uint(in.FirstChannel)
-               cInPtr = &cIn
-       }
-       if opts != nil {
-               cOpts.flags = C.rtaudio_stream_flags_t(opts.Flags)
-               cOpts.num_buffers = C.uint(opts.NumBuffers)
-               cOpts.priority = C.int(opts.Priotity)
-               cOptsPtr = &cOpts
-       }
-       framesCount := C.uint(frames)
-       audio.format = format
-       audio.cb = cb
-
-       k := registerAudio(audio)
-       C.cgoRtAudioOpenStream(audio.audio, cOutPtr, cInPtr,
-               C.rtaudio_format_t(format), C.uint(sampleRate), &framesCount, C.int(k), cOptsPtr)
-       if C.rtaudio_error(audio.audio) != nil {
-               return errors.New(C.GoString(C.rtaudio_error(audio.audio)))
-       }
-       return nil
-}
-
-func (audio *rtaudio) Close() {
-       unregisterAudio(audio)
-       C.rtaudio_close_stream(audio.audio)
-}
-
-func (audio *rtaudio) Start() error {
-       C.rtaudio_start_stream(audio.audio)
-       if C.rtaudio_error(audio.audio) != nil {
-               return errors.New(C.GoString(C.rtaudio_error(audio.audio)))
-       }
-       return nil
-}
-
-func (audio *rtaudio) Stop() error {
-       C.rtaudio_stop_stream(audio.audio)
-       if C.rtaudio_error(audio.audio) != nil {
-               return errors.New(C.GoString(C.rtaudio_error(audio.audio)))
-       }
-       return nil
-}
-
-func (audio *rtaudio) Abort() error {
-       C.rtaudio_abort_stream(audio.audio)
-       if C.rtaudio_error(audio.audio) != nil {
-               return errors.New(C.GoString(C.rtaudio_error(audio.audio)))
-       }
-       return nil
-}
-
-func (audio *rtaudio) IsOpen() bool {
-       return C.rtaudio_is_stream_open(audio.audio) != 0
-}
-
-func (audio *rtaudio) IsRunning() bool {
-       return C.rtaudio_is_stream_running(audio.audio) != 0
-}
-
-func (audio *rtaudio) Latency() (int, error) {
-       latency := C.rtaudio_get_stream_latency(audio.audio)
-       if C.rtaudio_error(audio.audio) != nil {
-               return 0, errors.New(C.GoString(C.rtaudio_error(audio.audio)))
-       }
-       return int(latency), nil
-}
-
-func (audio *rtaudio) SampleRate() (uint, error) {
-       sampleRate := C.rtaudio_get_stream_sample_rate(audio.audio)
-       if C.rtaudio_error(audio.audio) != nil {
-               return 0, errors.New(C.GoString(C.rtaudio_error(audio.audio)))
-       }
-       return uint(sampleRate), nil
-}
-
-func (audio *rtaudio) Time() (time.Duration, error) {
-       sec := C.rtaudio_get_stream_time(audio.audio)
-       if C.rtaudio_error(audio.audio) != nil {
-               return 0, errors.New(C.GoString(C.rtaudio_error(audio.audio)))
-       }
-       return time.Duration(time.Microsecond * time.Duration(sec*1000000.0)), nil
-}
-
-func (audio *rtaudio) SetTime(t time.Duration) error {
-       sec := float64(t) * 1000000.0 / float64(time.Microsecond)
-       C.rtaudio_set_stream_time(audio.audio, C.double(sec))
-       if C.rtaudio_error(audio.audio) != nil {
-               return errors.New(C.GoString(C.rtaudio_error(audio.audio)))
-       }
-       return nil
-}
-
-func (audio *rtaudio) ShowWarnings(show bool) {
-       if show {
-               C.rtaudio_show_warnings(audio.audio, 1)
-       } else {
-               C.rtaudio_show_warnings(audio.audio, 0)
-       }
-}