添加一些关于midi播放的项目

This commit is contained in:
terryLP
2025-03-24 14:30:56 +08:00
parent e31eb22077
commit 498b4ef13b
699 changed files with 186162 additions and 1 deletions
@@ -0,0 +1,563 @@
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 -lksuser -lmfplat -lmfuuid -lwmcodecdspuuid -lwinmm -lole32 -static
#cgo darwin CXXFLAGS: -D__MACOSX_CORE__
#cgo darwin LDFLAGS: -framework CoreAudio -framework CoreFoundation
#include <stdlib.h>
#include <stdint.h>
#include "rtaudio_stub.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 DirectSound 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 << 27]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 << 29]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 << 28]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 << 27]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 << 27]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 << 23]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)
}
}
@@ -0,0 +1,4 @@
#include "../../../RtAudio.h"
#include "../../../RtAudio.cpp"
#include "../../../rtaudio_c.cpp"
@@ -0,0 +1 @@
#include "../../../rtaudio_c.h"
@@ -0,0 +1,71 @@
package rtaudio
import (
"log"
"math"
"time"
)
func ExampleCompiledAPI() {
log.Println("RtAudio version: ", Version())
for _, api := range CompiledAPI() {
log.Println("Compiled API: ", api)
}
}
func ExampleRtAudio_Devices() {
audio, err := Create(APIUnspecified)
if err != nil {
log.Fatal(err)
}
defer audio.Destroy()
devices, err := audio.Devices()
if err != nil {
log.Fatal(err)
}
for _, d := range devices {
log.Printf("Audio device: %#v\n", d)
}
}
func ExampleRtAudio_Open() {
const (
sampleRate = 44100
bufSz = 512
freq = 440.0
)
phase := 0.0
audio, err := Create(APIUnspecified)
if err != nil {
log.Fatal(err)
}
defer audio.Destroy()
params := StreamParams{
DeviceID: uint(audio.DefaultOutputDevice()),
NumChannels: 2,
FirstChannel: 0,
}
options := StreamOptions{
Flags: FlagsAlsaUseDefault,
}
cb := func(out, in Buffer, dur time.Duration, status StreamStatus) int {
samples := out.Float32()
for i := 0; i < len(samples)/2; i++ {
sample := float32(math.Sin(2 * math.Pi * phase))
phase += freq / sampleRate
samples[i*2] = sample
samples[i*2+1] = sample
}
return 0
}
err = audio.Open(&params, nil, FormatFloat32, sampleRate, bufSz, cb, &options)
if err != nil {
log.Fatal(err)
}
defer audio.Close()
audio.Start()
defer audio.Stop()
time.Sleep(3 * time.Second)
}
@@ -0,0 +1,106 @@
from __future__ import print_function
import threading
import rtaudio as rt
from math import cos
import struct
class audio_generator:
def __init__(self):
self.idx = -1
self.freq = 440.
def __call__(self):
self.idx += 1
if self.idx%48000 == 0:
self.freq *= 2**(1/12.)
return 0.5*cos(2.*3.1416*self.freq*self.idx/48000.)
class callback:
def __init__(self, gen):
self.gen = gen
self.i = 0
def __call__(self,playback, capture):
[struct.pack_into("f", playback, 4*o, self.gen()) for o in range(256)]
self.i = self.i + 256
if self.i > 48000*10:
print('.')
return 1
try:
# if we have numpy, replace the above class
import numpy as np
class callback:
def __init__(self, gen):
print('Using Numpy.')
self.freq = 440.
t = np.arange(256, dtype=np.float32) / 48000.0
self.phase = 2*np.pi*t
self.inc = 2*np.pi*256/48000
self.k = 0
def __call__(self, playback, capture):
# Calculate sinusoid using numpy vector operation, as
# opposed to per-sample computations in the generator
# above that must be collected and packed one at a time.
self.k += 256
if self.k > 48000:
self.freq *= 2**(1/12.)
self.k = 0
self.phase += self.inc
samples = 0.5*np.cos(self.phase * self.freq)
# Ensure result is the right size!
assert samples.shape[0] == 256
assert samples.dtype == np.float32
# Use numpy array view to do a once-copy into memoryview
# (ie. we only do a single byte-wise copy of the final
# result into 'playback')
usamples = samples.view(dtype=np.uint8)
playback_array = np.array(playback, copy=False)
np.copyto(playback_array, usamples)
except ModuleNotFoundError:
print('Numpy not available, using struct.')
dac = rt.RtAudio()
n = dac.getDeviceCount()
print('Number of devices available: ', n)
for i in range(n):
try:
print(dac.getDeviceInfo(i))
except rt.RtError as e:
print(e)
print('Default output device: ', dac.getDefaultOutputDevice())
print('Default input device: ', dac.getDefaultInputDevice())
print('is stream open: ', dac.isStreamOpen())
print('is stream running: ', dac.isStreamRunning())
oParams = {'deviceId': 0, 'nChannels': 1, 'firstChannel': 0}
iParams = {'deviceId': 0, 'nChannels': 1, 'firstChannel': 0}
try:
dac.openStream(oParams,oParams,48000,256,callback(audio_generator()) )
except rt.RtError as e:
print(e)
else:
dac.startStream()
import time
print('latency: ', dac.getStreamLatency())
while (dac.isStreamRunning()):
time.sleep(0.1)
print(dac.getStreamTime())
dac.stopStream()
dac.abortStream()
dac.closeStream()
@@ -0,0 +1,57 @@
PyRtAudio - a python wrapper around RtAudio that allows to perform audio i/o operations in real-time from the python language.
By Antoine Lefebvre, 2011
This software is in the development stage. Do not expect compatibility
with future versions. Comments, suggestions, new features, bug fixes,
etc. are welcome.
This distribution of PyRtAudio contains the following:
- rtaudiomodule.cpp: the python wrapper code
- setup.py: a setup script use to compile and install PyRtAudio
- examples: a single PyRtAudioTest.py script
INSTALLATION
The compilation and installation of the PyRtAudio module is handled by
the python Distribution Utilities ("Distutils"). Provided that your
system has a C++ compiler and is properly configure, the following
command should be sufficient:
>> python setup.py install
Please refer to the distutils documentation for installation problems: http://docs.python.org/distutils/index.html
LEGAL AND ETHICAL:
The PyRtAudio license is the same as the RtAudio license:
PyRtAudio: a python wrapper around RtAudio
Copyright (c)2011 Antoine Lefebvre
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
Any person wishing to distribute modifications to the Software is
asked to send the modifications to the original developer so that
they can be incorporated into the canonical version. This is,
however, not a binding provision of this license.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,711 @@
/************************************************************************/
/* PyRtAudio: a python wrapper around RtAudio
Copyright (c) 2011 Antoine Lefebvre
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
Any person wishing to distribute modifications to the Software is
asked to send the modifications to the original developer so that
they can be incorporated into the canonical version. This is,
however, not a binding provision of this license.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/************************************************************************/
// This software is in the development stage
// Do not expect compatibility with future versions.
// Comments, suggestions, new features, bug fixes, etc. are welcome
#include <Python.h>
#include "RtAudio.h"
extern "C" {
typedef struct
{
PyObject_HEAD
#if PY_MAJOR_VERSION < 3
void *padding; // python 2.7 seems to set dac to bad value
// after print_function, causing a crash, no
// idea why, but this fixes it.
#endif
RtAudio *dac;
RtAudioFormat _format;
int _bufferSize;
unsigned int inputChannels;
PyObject *callback_func;
} PyRtAudio;
static PyObject *RtAudioErrorException;
static int callback(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
double streamTime, RtAudioStreamStatus status, void *data )
{
PyRtAudio* self = (PyRtAudio*) data;
if (status == RTAUDIO_OUTPUT_UNDERFLOW)
printf("underflow.\n");
if (self == NULL) return -1;
float* in = (float *) inputBuffer;
float* out = (float *) outputBuffer;
PyObject *py_callback_func = self->callback_func;
int retval = 0;
if (py_callback_func) {
PyGILState_STATE gstate = PyGILState_Ensure();
#if PY_MAJOR_VERSION >= 3
PyObject* iBuffer = PyMemoryView_FromMemory((char*)in, sizeof(float) * self->inputChannels * nBufferFrames, PyBUF_READ);
PyObject* oBuffer = PyMemoryView_FromMemory((char*)out, sizeof(float) * nBufferFrames, PyBUF_WRITE);
#else
PyObject* iBuffer = PyBuffer_FromMemory(in, sizeof(float) * self->inputChannels * nBufferFrames);
PyObject* oBuffer = PyBuffer_FromReadWriteMemory(out, sizeof(float) * nBufferFrames);
#endif
PyObject *arglist = Py_BuildValue("(O,O)", oBuffer, iBuffer);
if (arglist == NULL) {
printf("error.\n");
PyErr_Print();
PyGILState_Release(gstate);
return 2;
}
// Calling the callback
PyObject *result = PyEval_CallObject(py_callback_func, arglist);
if (PyErr_Occurred() != NULL) {
PyErr_Print();
}
#if PY_MAJOR_VERSION >= 3
else if (result == NULL)
retval = 0;
else if (PyLong_Check(result)) {
retval = PyLong_AsLong(result);
}
#else
else if (PyInt_Check(result)) {
retval = PyInt_AsLong(result);
}
#endif
Py_DECREF(arglist);
Py_DECREF(oBuffer);
Py_DECREF(iBuffer);
Py_XDECREF(result);
PyGILState_Release(gstate);
}
return retval;
}
static void RtAudio_dealloc(PyRtAudio *self)
{
printf("RtAudio_dealloc.\n");
if (self == NULL) return;
if (self->dac) {
self->dac->closeStream();
Py_CLEAR(self->callback_func);
delete self->dac;
}
Py_TYPE(self)->tp_free((PyObject *) self);
}
static PyObject* RtAudio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
printf("RtAudio_new.\n");
PyRtAudio *self;
char *api = NULL;
if(!PyArg_ParseTuple(args, "|s", &api))
return NULL;
self = (PyRtAudio *) type->tp_alloc(type, 0);
if(self == NULL) return NULL;
self->dac = NULL;
self->callback_func = NULL;
try {
if (api == NULL)
self->dac = new RtAudio;
else if(!strcmp(api, "jack"))
self->dac = new RtAudio(RtAudio::UNIX_JACK);
else if(!strcmp(api, "alsa"))
self->dac = new RtAudio(RtAudio::LINUX_ALSA);
else if(!strcmp(api, "oss"))
self->dac = new RtAudio(RtAudio::LINUX_ALSA);
else if(!strcmp(api, "core"))
self->dac = new RtAudio(RtAudio::MACOSX_CORE);
else if(!strcmp(api, "asio"))
self->dac = new RtAudio(RtAudio::WINDOWS_ASIO);
else if(!strcmp(api, "directsound"))
self->dac = new RtAudio(RtAudio::WINDOWS_DS);
}
catch (RtAudioError &error) {
PyErr_SetString(RtAudioErrorException, error.getMessage().c_str());
Py_INCREF(RtAudioErrorException);
return NULL;
}
self->dac->showWarnings(false);
//Py_XINCREF(self);
return (PyObject *) self;
}
static int RtAudio_init(PyRtAudio *self, PyObject *args, PyObject *kwds)
{
printf("RtAudio_init.\n");
//if (self == NULL) return 0;
return 0;
}
// This functions does not yet support all the features of the RtAudio::openStream method.
// Please send your patches if you improves this.
static PyObject* RtAudio_openStream(PyRtAudio *self, PyObject *args)
{
if (self == NULL) return NULL;
if (self->dac == NULL) {
printf("the dac is null.\n");
Py_RETURN_NONE;
}
PyObject *oParamsObj;
PyObject *iParamsObj;
int fs;
unsigned int bf;
PyObject *pycallback;
if (!PyArg_ParseTuple(args, "OOiiO", &oParamsObj, &iParamsObj, &fs, &bf, &pycallback))
return NULL;
RtAudio::StreamParameters oParams;
oParams.deviceId = 1;
oParams.nChannels = 1;
oParams.firstChannel = 0;
if (PyDict_Check(oParamsObj)) {
#if PY_MAJOR_VERSION >= 3
if (PyDict_Contains(oParamsObj, PyUnicode_FromString("deviceId"))) {
PyObject *value = PyDict_GetItem(oParamsObj, PyUnicode_FromString("deviceId"));
oParams.deviceId = PyLong_AsLong(value);
}
if (PyDict_Contains(oParamsObj, PyUnicode_FromString("nChannels"))) {
PyObject *value = PyDict_GetItem(oParamsObj, PyUnicode_FromString("nChannels"));
oParams.nChannels = PyLong_AsLong(value);
}
if (PyDict_Contains(oParamsObj, PyUnicode_FromString("firstChannel"))) {
PyObject *value = PyDict_GetItem(oParamsObj, PyUnicode_FromString("firstChannel"));
oParams.firstChannel = PyLong_AsLong(value);
}
#else
if (PyDict_Contains(oParamsObj, PyString_FromString("deviceId"))) {
PyObject *value = PyDict_GetItem(oParamsObj, PyString_FromString("deviceId"));
oParams.deviceId = PyInt_AsLong(value);
}
if (PyDict_Contains(oParamsObj, PyString_FromString("nChannels"))) {
PyObject *value = PyDict_GetItem(oParamsObj, PyString_FromString("nChannels"));
oParams.nChannels = PyInt_AsLong(value);
}
if (PyDict_Contains(oParamsObj, PyString_FromString("firstChannel"))) {
PyObject *value = PyDict_GetItem(oParamsObj, PyString_FromString("firstChannel"));
oParams.firstChannel = PyInt_AsLong(value);
}
#endif
}
else {
printf("First argument must be a dictionary. Default values will be used.\n");
}
RtAudio::StreamParameters iParams;
iParams.deviceId = 1;
iParams.nChannels = 2;
iParams.firstChannel = 0;
if (PyDict_Check(iParamsObj)) {
#if PY_MAJOR_VERSION >= 3
if (PyDict_Contains(iParamsObj, PyUnicode_FromString("deviceId"))) {
PyObject *value = PyDict_GetItem(iParamsObj, PyUnicode_FromString("deviceId"));
iParams.deviceId = PyLong_AsLong(value);
}
if (PyDict_Contains(iParamsObj, PyUnicode_FromString("nChannels"))) {
PyObject *value = PyDict_GetItem(iParamsObj, PyUnicode_FromString("nChannels"));
iParams.nChannels = PyLong_AsLong(value);
}
if (PyDict_Contains(iParamsObj, PyUnicode_FromString("firstChannel"))) {
PyObject *value = PyDict_GetItem(iParamsObj, PyUnicode_FromString("firstChannel"));
iParams.firstChannel = PyLong_AsLong(value);
}
#else
if (PyDict_Contains(iParamsObj, PyString_FromString("deviceId"))) {
PyObject *value = PyDict_GetItem(iParamsObj, PyString_FromString("deviceId"));
iParams.deviceId = PyInt_AsLong(value);
}
if (PyDict_Contains(iParamsObj, PyString_FromString("nChannels"))) {
PyObject *value = PyDict_GetItem(iParamsObj, PyString_FromString("nChannels"));
iParams.nChannels = PyInt_AsLong(value);
}
if (PyDict_Contains(iParamsObj, PyString_FromString("firstChannel"))) {
PyObject *value = PyDict_GetItem(iParamsObj, PyString_FromString("firstChannel"));
iParams.firstChannel = PyInt_AsLong(value);
}
#endif
}
else {
printf("Second argument must be a dictionary. Default values will be used.\n");
}
if (!PyCallable_Check(pycallback)) {
PyErr_SetString(PyExc_TypeError, "Need a callable object!");
Py_XINCREF(PyExc_TypeError);
return NULL;
}
// sanity check the callback ?
Py_INCREF(pycallback); /* Add a reference to new callback */
self->callback_func = pycallback; /*Remember new callback */
// add support for other format
self->_format = RTAUDIO_FLOAT32;
// add support for other options
RtAudio::StreamOptions options;
options.flags = RTAUDIO_NONINTERLEAVED;
try {
if (self->dac->isStreamOpen())
self->dac->closeStream();
self->dac->openStream(&oParams, &iParams, self->_format, fs, &bf, &callback, self, &options);
}
catch ( RtAudioError& error ) {
PyErr_SetString(RtAudioErrorException, error.getMessage().c_str());
Py_INCREF(RtAudioErrorException);
return NULL;
}
self->inputChannels = iParams.nChannels;
Py_RETURN_NONE;
}
static PyObject* RtAudio_closeStream(PyRtAudio *self, PyObject *args)
{
printf("RtAudio_closeStream.\n");
if (self == NULL || self->dac == NULL) return NULL;
try {
self->dac->closeStream();
Py_CLEAR(self->callback_func);
}
catch(RtAudioError &error) {
PyErr_SetString(RtAudioErrorException, error.getMessage().c_str());
Py_INCREF(RtAudioErrorException);
return NULL;
}
Py_RETURN_NONE;
}
static PyObject* RtAudio_startStream(PyRtAudio *self, PyObject *args)
{
if (self == NULL || self->dac == NULL) return NULL;
try {
self->dac->startStream();
}
catch(RtAudioError &error) {
PyErr_SetString(RtAudioErrorException, error.getMessage().c_str());
Py_INCREF(RtAudioErrorException);
return NULL;
}
Py_RETURN_NONE;
}
static PyObject* RtAudio_stopStream(PyRtAudio *self, PyObject *args)
{
printf("RtAudio_stopStream.\n");
if (self == NULL || self->dac == NULL) return NULL;
try {
self->dac->stopStream();
}
catch(RtAudioError &error) {
PyErr_SetString(RtAudioErrorException, error.getMessage().c_str());
Py_INCREF(RtAudioErrorException);
return NULL;
}
Py_RETURN_NONE;
}
static PyObject* RtAudio_abortStream(PyRtAudio *self, PyObject *args)
{
printf("RtAudio_abortStream.\n");
if (self == NULL || self->dac == NULL) return NULL;
try {
self->dac->abortStream();
}
catch(RtAudioError &error) {
PyErr_SetString(RtAudioErrorException, error.getMessage().c_str());
Py_INCREF(RtAudioErrorException);
return NULL;
}
Py_RETURN_NONE;
}
static PyObject* RtAudio_isStreamRunning(PyRtAudio *self, PyObject *args)
{
if (self == NULL || self->dac == NULL) return NULL;
if (self->dac == NULL) {
Py_RETURN_FALSE;
}
if (self->dac->isStreamRunning())
Py_RETURN_TRUE;
else
Py_RETURN_FALSE;
}
static PyObject* RtAudio_isStreamOpen(PyRtAudio *self, PyObject *args)
{
if (self == NULL || self->dac == NULL) return NULL;
if (self->dac == NULL) {
Py_RETURN_FALSE;
}
if (self->dac->isStreamOpen())
Py_RETURN_TRUE;
else
Py_RETURN_FALSE;
}
static PyObject* RtAudio_getDeviceCount(PyRtAudio *self, PyObject *args)
{
if (self == NULL || self->dac == NULL) return NULL;
#if PY_MAJOR_VERSION >= 3
return PyLong_FromLong(self->dac->getDeviceCount());
#else
return PyInt_FromLong(self->dac->getDeviceCount());
#endif
}
static PyObject* RtAudio_getDeviceInfo(PyRtAudio *self, PyObject *args)
{
if (self == NULL || self->dac == NULL) return NULL;
int device;
if (!PyArg_ParseTuple(args, "i", &device))
return NULL;
try {
RtAudio::DeviceInfo info = self->dac->getDeviceInfo(device);
PyObject* info_dict = PyDict_New();
if (info.probed) {
Py_INCREF(Py_True);
PyDict_SetItemString(info_dict, "probed", Py_True);
}
else {
Py_INCREF(Py_False);
PyDict_SetItemString(info_dict, "probed", Py_False);
}
PyObject* obj;
#if PY_MAJOR_VERSION >= 3
obj = PyUnicode_FromString(info.name.c_str());
PyDict_SetItemString(info_dict, "name", obj);
obj = PyLong_FromLong(info.outputChannels);
PyDict_SetItemString(info_dict, "outputChannels", obj);
obj = PyLong_FromLong(info.inputChannels);
PyDict_SetItemString(info_dict, "inputChannels", obj);
obj = PyLong_FromLong(info.duplexChannels);
PyDict_SetItemString(info_dict, "duplexChannels", obj);
#else
obj = PyString_FromString(info.name.c_str());
PyDict_SetItemString(info_dict, "name", obj);
obj = PyInt_FromLong(info.outputChannels);
PyDict_SetItemString(info_dict, "outputChannels", obj);
obj = PyInt_FromLong(info.inputChannels);
PyDict_SetItemString(info_dict, "inputChannels", obj);
obj = PyInt_FromLong(info.duplexChannels);
PyDict_SetItemString(info_dict, "duplexChannels", obj);
#endif
if (info.isDefaultOutput) {
Py_INCREF(Py_True);
PyDict_SetItemString(info_dict, "isDefaultOutput", Py_True);
}
else {
Py_INCREF(Py_False);
PyDict_SetItemString(info_dict, "isDefaultOutput", Py_False);
}
if (info.isDefaultInput) {
Py_INCREF(Py_True);
PyDict_SetItemString(info_dict, "isDefaultInput", Py_True);
}
else {
Py_INCREF(Py_False);
PyDict_SetItemString(info_dict, "isDefaultInput", Py_False);
}
return info_dict;
}
catch(RtAudioError &error) {
PyErr_SetString(RtAudioErrorException, error.getMessage().c_str());
Py_INCREF(RtAudioErrorException);
return NULL;
}
}
static PyObject* RtAudio_getDefaultOutputDevice(PyRtAudio *self, PyObject *args)
{
if (self == NULL || self->dac == NULL) return NULL;
#if PY_MAJOR_VERSION >= 3
return PyLong_FromLong(self->dac->getDefaultOutputDevice());
#else
return PyInt_FromLong(self->dac->getDefaultOutputDevice());
#endif
}
static PyObject* RtAudio_getDefaultInputDevice(PyRtAudio *self, PyObject *args)
{
if (self == NULL || self->dac == NULL) return NULL;
#if PY_MAJOR_VERSION >= 3
return PyLong_FromLong(self->dac->getDefaultInputDevice());
#else
return PyInt_FromLong(self->dac->getDefaultInputDevice());
#endif
}
static PyObject* RtAudio_getStreamTime(PyRtAudio *self, PyObject *args)
{
if (self == NULL || self->dac == NULL) return NULL;
return PyFloat_FromDouble( self->dac->getStreamTime() );
}
static PyObject* RtAudio_getStreamLatency(PyRtAudio *self, PyObject *args)
{
if (self == NULL || self->dac == NULL) return NULL;
#if PY_MAJOR_VERSION >= 3
return PyLong_FromLong( self->dac->getStreamLatency() );
#else
return PyInt_FromLong( self->dac->getStreamLatency() );
#endif
}
static PyObject* RtAudio_getStreamSampleRate(PyRtAudio *self, PyObject *args)
{
if (self == NULL || self->dac == NULL) return NULL;
#if PY_MAJOR_VERSION >= 3
return PyLong_FromLong( self->dac->getStreamSampleRate() );
#else
return PyInt_FromLong( self->dac->getStreamSampleRate() );
#endif
}
static PyObject* RtAudio_showWarnings(PyRtAudio *self, PyObject *args)
{
if (self == NULL || self->dac == NULL) return NULL;
PyObject *obj;
if (!PyArg_ParseTuple(args, "O", &obj))
return NULL;
if (!PyBool_Check(obj))
return NULL;
if (obj == Py_True)
self->dac->showWarnings(true);
else if (obj == Py_False)
self->dac->showWarnings(false);
else {
printf("not true nor false\n");
}
Py_RETURN_NONE;
}
static PyMethodDef RtAudio_methods[] =
{
// TO BE DONE: getCurrentApi(void)
{"getDeviceCount", (PyCFunction) RtAudio_getDeviceCount, METH_NOARGS,
"A public function that queries for the number of audio devices available."},
{"getDeviceInfo", (PyCFunction) RtAudio_getDeviceInfo, METH_VARARGS,
"Return a dictionary with information for a specified device number."},
{"getDefaultOutputDevice", (PyCFunction) RtAudio_getDefaultOutputDevice, METH_NOARGS,
"A function that returns the index of the default output device."},
{"getDefaultInputDevice", (PyCFunction) RtAudio_getDefaultInputDevice, METH_NOARGS,
"A function that returns the index of the default input device."},
{"openStream", (PyCFunction) RtAudio_openStream, METH_VARARGS,
"A public method for opening a stream with the specified parameters."},
{"closeStream", (PyCFunction) RtAudio_closeStream, METH_NOARGS,
"A function that closes a stream and frees any associated stream memory. "},
{"startStream", (PyCFunction) RtAudio_startStream, METH_NOARGS,
"A function that starts a stream. "},
{"stopStream", (PyCFunction) RtAudio_stopStream, METH_NOARGS,
"Stop a stream, allowing any samples remaining in the output queue to be played. "},
{"abortStream", (PyCFunction) RtAudio_abortStream, METH_NOARGS,
"Stop a stream, discarding any samples remaining in the input/output queue."},
{"isStreamOpen", (PyCFunction) RtAudio_isStreamOpen, METH_NOARGS,
"Returns true if a stream is open and false if not."},
{"isStreamRunning", (PyCFunction) RtAudio_isStreamRunning, METH_NOARGS,
"Returns true if the stream is running and false if it is stopped or not open."},
{"getStreamTime", (PyCFunction) RtAudio_getStreamTime, METH_NOARGS,
"Returns the number of elapsed seconds since the stream was started."},
{"getStreamLatency", (PyCFunction) RtAudio_getStreamLatency, METH_NOARGS,
"Returns the internal stream latency in sample frames."},
{"getStreamSampleRate", (PyCFunction) RtAudio_getStreamSampleRate, METH_NOARGS,
"Returns actual sample rate in use by the stream."},
{"showWarnings", (PyCFunction) RtAudio_showWarnings, METH_VARARGS,
"Specify whether warning messages should be printed to stderr."},
// TO BE DONE: getCompiledApi (std::vector< RtAudio::Api > &apis) throw ()
{NULL}
};
static PyTypeObject RtAudio_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"rtaudio.RtAudio", /*tp_name*/
sizeof(RtAudio), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor) RtAudio_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
"Audio input device", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
RtAudio_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)RtAudio_init, /* tp_init */
0, /* tp_alloc */
RtAudio_new, /* tp_new */
0, /* Low-level free-memory routine */
0, /* For PyObject_IS_GC */
0, // PyObject *tp_bases;
0, // PyObject *tp_mro; /* method resolution order */
0, //PyObject *tp_cache;
0, //PyObject *tp_subclasses;
0, //PyObject *tp_weaklist;
0, //destructor tp_del;
//0, /* Type attribute cache version tag. Added in version 2.6 */
};
#if PY_MAJOR_VERSION >= 3
static PyModuleDef RtAudio_module = {
PyModuleDef_HEAD_INIT,
"RtAudio",
"RtAudio wrapper.",
};
#endif
#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
#define PyMODINIT_FUNC void
#endif
PyMODINIT_FUNC
#if PY_MAJOR_VERSION >= 3
PyInit_rtaudio(void)
#else
initrtaudio(void)
#endif
{
if (!PyEval_ThreadsInitialized())
PyEval_InitThreads();
if (PyType_Ready(&RtAudio_type) < 0)
#if PY_MAJOR_VERSION >= 3
return NULL;
#else
return;
#endif
#if PY_MAJOR_VERSION >= 3
PyObject* module = PyModule_Create(&RtAudio_module);
if (module == NULL)
return NULL;
#else
PyObject* module = Py_InitModule3("rtaudio", NULL, "RtAudio wrapper.");
if (module == NULL)
return;
#endif
Py_INCREF(&RtAudio_type);
PyModule_AddObject(module, "RtAudio", (PyObject *)&RtAudio_type);
RtAudioErrorException = PyErr_NewException("rtaudio.RtError", NULL, NULL);
Py_INCREF(RtAudioErrorException);
PyModule_AddObject(module, "RtError", RtAudioErrorException);
#if PY_MAJOR_VERSION >= 3
return module;
#else
return;
#endif
}
}
@@ -0,0 +1,56 @@
#!/bin/env python
import os
from distutils.core import setup, Extension
if hasattr(os, 'uname'):
OSNAME = os.uname()[0]
else:
OSNAME = 'Windows'
define_macros = []
libraries = []
extra_link_args = []
extra_compile_args = ['-I../../../']
sources = ['rtaudiomodule.cpp', '../../../RtAudio.cpp']
if OSNAME == 'Linux':
define_macros=[("__LINUX_ALSA__", ''),
('__LINUX_JACK__', '')]
libraries = ['asound', 'jack', 'pthread']
elif OSNAME == 'Darwin':
define_macros = [('__MACOSX_CORE__', '')]
libraries = ['pthread', 'stdc++']
extra_link_args = ['-framework', 'CoreAudio']
elif OSNAME == 'Windows':
define_macros = [('__WINDOWS_DS__', None),
('__WINDOWS_ASIO__', None),
('__LITTLE_ENDIAN__',None),
('WIN32',None)]
libraries = ['winmm', 'dsound', 'Advapi32','Ole32','User32']
sources += ['../../../include/asio.cpp',
'../../../include/asiodrivers.cpp',
'../../../include/asiolist.cpp',
'../../../include/iasiothiscallresolver.cpp']
extra_compile_args.append('-I../../../include/')
extra_compile_args.append('-EHsc')
audio = Extension('rtaudio',
sources=sources,
libraries=libraries,
define_macros=define_macros,
extra_compile_args = extra_compile_args,
extra_link_args = extra_link_args,
)
setup(name = 'rtaudio',
version = '0.1',
description = 'Python RtAudio interface',
ext_modules = [audio])