DaqConfiguration and device info will have a direct Cython wrapper

This commit is contained in:
Anne de Jong 2020-10-07 21:10:19 +02:00
parent a3963c4595
commit a43857070b
12 changed files with 280 additions and 291 deletions

View File

@ -4,12 +4,19 @@ include_directories(/usr/include/rtaudio)
add_library(cpp_daq lasp_cppdaq.cpp lasp_cppuldaq.cpp ) add_library(cpp_daq lasp_cppdaq.cpp lasp_cppuldaq.cpp )
set_source_files_properties(lasp_daq.pyx PROPERTIES CYTHON_IS_CXX TRUE) set_source_files_properties(lasp_daq.pyx PROPERTIES CYTHON_IS_CXX TRUE)
set_source_files_properties(lasp_deviceinfo.pyx PROPERTIES CYTHON_IS_CXX TRUE)
set_source_files_properties(lasp_daq.cxx PROPERTIES COMPILE_FLAGS set_source_files_properties(lasp_daq.cxx PROPERTIES COMPILE_FLAGS
"${CMAKE_CXX_FLAGS} ${CYTHON_EXTRA_CXX_FLAGS}") "${CMAKE_CXX_FLAGS} ${CYTHON_EXTRA_CXX_FLAGS}")
set_source_files_properties(lasp_deviceinfo.cxx PROPERTIES COMPILE_FLAGS
"${CMAKE_CXX_FLAGS} ${CYTHON_EXTRA_CXX_FLAGS}")
cython_add_module(lasp_daq lasp_daq.pyx) cython_add_module(lasp_daq lasp_daq.pyx)
cython_add_module(lasp_deviceinfo lasp_deviceinfo.pyx)
target_link_libraries(lasp_daq cpp_daq uldaq rtaudio pthread) target_link_libraries(lasp_daq cpp_daq uldaq rtaudio pthread)
target_link_libraries(lasp_deviceinfo cpp_daq uldaq rtaudio pthread)
if(win32) if(win32)
target_link_libraries(lasp_daq python37) target_link_libraries(lasp_daq python37)
endif(win32) endif(win32)

View File

@ -2,4 +2,5 @@
from .lasp_daqconfig import * from .lasp_daqconfig import *
from .lasp_avtype import * from .lasp_avtype import *
from .lasp_daq import * from .lasp_daq import *
from .lasp_deviceinfo import *

View File

@ -1,7 +1,6 @@
import sys import sys
include "config.pxi" include "config.pxi"
cimport cython cimport cython
from .lasp_daqconfig import DeviceInfo
from .lasp_avtype import AvType from .lasp_avtype import AvType
from libcpp.string cimport string from libcpp.string cimport string
from libcpp.vector cimport vector from libcpp.vector cimport vector
@ -10,10 +9,6 @@ from libc.stdio cimport printf, fprintf, stderr
from libc.string cimport memcpy, memset from libc.string cimport memcpy, memset
from cpython.ref cimport PyObject,Py_INCREF, Py_DECREF from cpython.ref cimport PyObject,Py_INCREF, Py_DECREF
__all__ = ['RtAudio', 'get_numpy_dtype_from_format_string',
'get_sampwidth_from_format_string']
cdef extern from "lasp_cppthread.h" nogil: cdef extern from "lasp_cppthread.h" nogil:
cdef cppclass CPPThread[T,F]: cdef cppclass CPPThread[T,F]:
CPPThread(F threadfunction, T data) CPPThread(F threadfunction, T data)
@ -30,7 +25,6 @@ cdef extern from "lasp_cppqueue.h" nogil:
size_t size() const size_t size() const
bool empty() const bool empty() const
cdef extern from "atomic" namespace "std" nogil: cdef extern from "atomic" namespace "std" nogil:
cdef cppclass atomic[T]: cdef cppclass atomic[T]:
T load() T load()
@ -43,13 +37,60 @@ cdef extern from "lasp_pyarray.h":
bool transfer_ownership, bool transfer_ownership,
bool F_contiguous) bool F_contiguous)
ctypedef unsigned us
ctypedef vector[bool] boolvec
cdef inline void copyChannel(void* to, void* from_, cdef extern from "lasp_cppdaq.h" nogil:
unsigned bytesperchan, cdef cppclass cppDaq "Daq":
unsigned toindex, void start(SafeQueue[void*] *inQueue,
unsigned fromindex) nogil: SafeQueue[void*] *outQueue) except +
memcpy(<void*> &((<char*> to)[bytesperchan*toindex]), void stop()
<void*> &((<char*> from_)[bytesperchan*fromindex]), double samplerate()
bytesperchan) us neninchannels()
us nenoutchannels()
DataType getDataType()
cdef cppclass DaqApi:
string apiname
unsigned apicode
unsigned api_specific_subcode
cdef cppclass DataType:
string name
unsigned sw
bool is_floating
DataType dtype_fl64
cdef cppclass cppDeviceInfo "DeviceInfo":
DaqApi api
string name
unsigned devindex
vector[DataType] availableDataTypes
vector[double] availableSampleRates
int prefSampleRateIndex
unsigned ninchannels
unsigned noutchannels
bool hasInputIEPE
bool hasInputACCouplingSwitch
bool hasInputTrigger
vector[double] inputRanges
cdef cppclass DaqConfiguration:
boolvec eninchannels
boolvec enoutchannels
unsigned sampleRateIndex
DataType datatype
bool monitorOutput
unsigned nFramesPerBlock;
boolvec inputIEPEEnabled;
boolvec inputACCouplingMode;
boolvec inputHighRange;
cdef cppclass DaqDevices:
@staticmethod
cppDaq* createDaqDevice(cppDeviceInfo&, DaqConfiguration&)
@staticmethod
vector[cppDeviceInfo] getDeviceInfo()

View File

@ -28,9 +28,13 @@ class DataType {
DataType(const char *name, unsigned sw, bool is_floating) DataType(const char *name, unsigned sw, bool is_floating)
: name(name), sw(sw), is_floating(is_floating) {} : name(name), sw(sw), is_floating(is_floating) {}
DataType():
name("invalid data type"),
sw(0),
is_floating(false) {}
}; };
const DataType dtype_invalid("invalid data type", 0, false); const DataType dtype_invalid;
const DataType dtype_fl64("64-bits floating point", 4, true); const DataType dtype_fl64("64-bits floating point", 4, true);
const DataType dtype_int8("8-bits integers", 1, false); const DataType dtype_int8("8-bits integers", 1, false);
const DataType dtype_int16("16-bits integers", 2, false); const DataType dtype_int16("16-bits integers", 2, false);
@ -100,6 +104,10 @@ class DeviceInfo {
bool hasInputIEPE = false; bool hasInputIEPE = false;
bool hasInputACCouplingSwitch = false; bool hasInputACCouplingSwitch = false;
bool hasInputTrigger = false; bool hasInputTrigger = false;
vector<double> inputRanges;
/* DeviceInfo(): */
/* datatype(dtype_invalid) { } */
double prefSampleRate() const { double prefSampleRate() const {
if ((prefSampleRateIndex < availableSampleRates.size()) && if ((prefSampleRateIndex < availableSampleRates.size()) &&

View File

@ -1,66 +1,10 @@
cimport cython cimport cython
from cpython.ref cimport PyObject,Py_INCREF, Py_DECREF from cpython.ref cimport PyObject,Py_INCREF, Py_DECREF
from .lasp_daqconfig import (DeviceInfo, InputMode, Range as pyRange, from .lasp_daqconfig import (Range as pyRange,
DAQChannel) DAQChannel)
from .lasp_avtype import AvType from .lasp_avtype import AvType
__all__ = ['UlDaq'] __all__ = ['Daq']
DEF MAX_DEF_COUNT = 100
DEF UL_ERR_MSG_LEN = 512
ctypedef unsigned us
ctypedef vector[bool] boolvec
cdef extern from "lasp_cppdaq.h" nogil:
cdef cppclass cppDaq "Daq":
void start(SafeQueue[void*] *inQueue,
SafeQueue[void*] *outQueue) except +
void stop()
double samplerate()
us neninchannels()
us nenoutchannels()
DataType getDataType()
cdef cppclass DaqApi:
string apiname
unsigned apicode
unsigned api_specific_subcode
cdef cppclass DataType:
string name
unsigned sw
bool is_floating
DataType dtype_fl64
cdef cppclass cppDeviceInfo "DeviceInfo":
DaqApi api
string name
unsigned devindex
vector[DataType] availableDataTypes
vector[double] availableSampleRates
int prefSampleRateIndex
unsigned ninchannels
unsigned noutchannels
bool hasInputIEPE
bool hasInputACCouplingSwitch
bool hasInputTrigger
cdef cppclass DaqConfiguration:
boolvec eninchannels
boolvec enoutchannels
unsigned sampleRateIndex
DataType datatype
bool monitorOutput
unsigned nFramesPerBlock;
boolvec inputIEPEEnabled;
boolvec inputACCouplingMode;
boolvec inputHighRange;
cdef cppclass DaqDevices:
@staticmethod
cppDaq* createDaqDevice(cppDeviceInfo&, DaqConfiguration&)
ctypedef struct PyStreamData: ctypedef struct PyStreamData:
@ -80,7 +24,7 @@ ctypedef struct PyStreamData:
double samplerate double samplerate
# If these queue pointers are NULL, it means the stream does not have an # If either of these queue pointers are NULL, it means the stream does not have an
# input, or output. # input, or output.
SafeQueue[void*] *inQueue SafeQueue[void*] *inQueue
SafeQueue[void*] *outQueue SafeQueue[void*] *outQueue
@ -196,139 +140,135 @@ cdef class Daq:
def isRunning(self): def isRunning(self):
return self.sd is not NULL return self.sd is not NULL
@cython.nonecheck(True) # @cython.nonecheck(True)
def start(self, avstream): # def start(self, avstream):
""" # """
Opens a stream with specified parameters # Opens a stream with specified parameters
Args: # Args:
avstream: AvStream instance # avstream: AvStream instance
Returns: None # Returns: None
""" # """
if self.sd is not NULL: # if self.sd is not NULL:
assert self.daq_device is not NULL # assert self.daq_device is not NULL
raise RuntimeError('Stream is already opened.') # raise RuntimeError('Stream is already opened.')
daqconfig = avstream.daqconfig # daqconfig = avstream.daqconfig
avtype = avstream.avtype # avtype = avstream.avtype
device = avstream.device # device = avstream.device
cdef: # cdef:
bint duplex_mode = daqconfig.duplex_mode # bint duplex_mode = daqconfig.duplex_mode
bint monitorOutput = daqconfig.monitor_gen # bint monitorOutput = daqconfig.monitor_gen
unsigned int nFramesPerBlock = daqconfig.nFramesPerBlock # unsigned int nFramesPerBlock = daqconfig.nFramesPerBlock
unsigned int samplerate # unsigned int samplerate
int i # int i
bint in_stream=False # bint in_stream=False
bint out_stream=False # bint out_stream=False
cppDaq* daq_device # cppDeviceInfo devinfo
# DaqConfiguration cppconfig
if daqconfig.nFramesPerBlock > 8192 or daqconfig.nFramesPerBlock < 512: # cppDaq* daq_device
raise ValueError('Invalid number of nFramesPerBlock')
if daqconfig.outputDelayBlocks != 0: # if daqconfig.nFramesPerBlock > 8192 or daqconfig.nFramesPerBlock < 512:
print('WARNING: OutputDelayBlocks not supported by API') # raise ValueError('Invalid number of nFramesPerBlock')
# Determine sample rate and sample format, determine whether we are an
# in or an output stream, or both
print(f'AvType: {avtype}')
print(f'Dup: {duplex_mode}')
if avtype == AvType.audio_input or duplex_mode:
# Here, we override the sample format in case of duplex mode.
sampleformat = daqconfig.en_input_sample_format
samplerate = int(daqconfig.en_input_rate)
in_stream = True
if duplex_mode:
fprintf(stderr, 'Duplex mode enabled\n')
out_stream = True
elif avtype == AvType.audio_output:
sampleformat = daqconfig.en_output_sample_format
samplerate = int(daqconfig.en_output_rate)
out_stream = True
else:
raise ValueError(f'Invalid stream type {avtype}')
if out_stream and daqconfig.firstEnabledOutputChannelNumber() == -1:
raise RuntimeError('No output channels enabled')
if in_stream and daqconfig.firstEnabledInputChannelNumber() == -1:
raise RuntimeError('No input channels enabled')
# All set, allocate the stream!
self.sd = <PyStreamData*> malloc(sizeof(PyStreamData))
if self.sd == NULL:
raise MemoryError('Could not allocate stream: memory error.')
# # if daqconfig.outputDelayBlocks != 0:
# # print('WARNING: OutputDelayBlocks not supported by API')
self.sd.stopThread.store(False) # # Determine sample rate and sample format, determine whether we are an
self.sd.inQueue = NULL # # in or an output stream, or both
self.sd.outQueue = NULL # # print(f'AvType: {avtype}')
# # print(f'Dup: {duplex_mode}')
self.sd.thread = NULL # if avtype == AvType.audio_input or duplex_mode:
self.sd.samplerate = <double> samplerate # # Here, we override the sample format in case of duplex mode.
# sampleformat = daqconfig.en_input_sample_format
self.sd.ninchannels = 0 # samplerate = int(daqconfig.en_input_rate)
self.sd.noutchannels = 0 # in_stream = True
self.sd.nBytesPerChan = daqconfig.nFramesPerBlock*sizeof(double) # if duplex_mode:
self.sd.nFramesPerBlock = daqconfig.nFramesPerBlock # fprintf(stderr, 'Duplex mode enabled\n')
# out_stream = True
# elif avtype == AvType.audio_output:
# Create channel maps for in channels, set in stream # sampleformat = daqconfig.en_output_sample_format
# parameters # samplerate = int(daqconfig.en_output_rate)
inch_enabled = 4*[False] # out_stream = True
if in_stream:
inch_enabled = [True if ch.channel_enabled else False for ch in
daqconfig.getInputChannels()]
self.sd.inQueue = new SafeQueue[void*]()
# Create channel maps for output channels
outch_enabled = 1*[False]
if out_stream:
print('Stream is output stream')
outch_enabled = [True if ch.channel_enabled else False for ch in
daqconfig.getOutputChannels()]
self.sd.outQueue = new SafeQueue[void*]()
# if 'DT9837A' in device.name:
# daq_device = new DT9837A(
# daqconfig.nFramesPerBlock,
# inch_enabled,
# outch_enabled,
# samplerate,
# monitorOutput,
# device.index)
# else: # else:
# raise RuntimeError(f'Device {device.name} not found or not configured') # raise ValueError(f'Invalid stream type {avtype}')
self.sd.pyCallback = <PyObject*> avstream._audioCallback # if out_stream and daqconfig.firstEnabledOutputChannelNumber() == -1:
self.sd.ninchannels = daq_device.neninchannels() # raise RuntimeError('No output channels enabled')
self.sd.noutchannels = daq_device.nenoutchannels()
self.daq_device = daq_device # if in_stream and daqconfig.firstEnabledInputChannelNumber() == -1:
# raise RuntimeError('No input channels enabled')
# Increase reference count to the callback
Py_INCREF(<object> avstream._audioCallback)
with nogil: # # All set, allocate the stream!
self.sd.thread = new CPPThread[void*, void (*)(void*)](audioCallbackPythonThreadFunction, # self.sd = <PyStreamData*> malloc(sizeof(PyStreamData))
<void*> self.sd) # if self.sd == NULL:
# raise MemoryError('Could not allocate stream: memory error.')
# Allow it to start
CPPsleep_ms(500)
self.daq_device.start( # self.sd.stopThread.store(False)
self.sd.inQueue, # self.sd.inQueue = NULL
self.sd.outQueue) # self.sd.outQueue = NULL
return nFramesPerBlock, self.daq_device.samplerate() # self.sd.thread = NULL
# self.sd.samplerate = <double> samplerate
# self.sd.ninchannels = 0
# self.sd.noutchannels = 0
# self.sd.nBytesPerChan = daqconfig.nFramesPerBlock*sizeof(double)
# self.sd.nFramesPerBlock = daqconfig.nFramesPerBlock
# # Create channel maps for in channels, set in stream
# # parameters
# inch_enabled = 4*[False]
# if in_stream:
# inch_enabled = [True if ch.channel_enabled else False for ch in
# daqconfig.getInputChannels()]
# self.sd.inQueue = new SafeQueue[void*]()
# # Create channel maps for output channels
# outch_enabled = 1*[False]
# if out_stream:
# outch_enabled = [True if ch.channel_enabled else False for ch in
# daqconfig.getOutputChannels()]
# self.sd.outQueue = new SafeQueue[void*]()
# daq_device = createDaqDevice(devinfo, cppconfig)
# self.sd.pyCallback = <PyObject*> avstream._audioCallback
# self.sd.ninchannels = daq_device.neninchannels()
# self.sd.noutchannels = daq_device.nenoutchannels()
# self.daq_device = daq_device
# # Increase reference count to the callback
# Py_INCREF(<object> avstream._audioCallback)
# with nogil:
# self.sd.thread = new CPPThread[void*, void (*)(void*)](audioCallbackPythonThreadFunction,
# <void*> self.sd)
# # Allow it to start
# CPPsleep_ms(500)
# self.daq_device.start(
# self.sd.inQueue,
# self.sd.outQueue)
# return nFramesPerBlock, self.daq_device.samplerate()
def stop(self): def stop(self):
if self.sd is NULL: if self.sd is NULL:
@ -341,7 +281,6 @@ cdef class Daq:
self.cleanupStream(self.sd) self.cleanupStream(self.sd)
self.sd = NULL self.sd = NULL
cdef cleanupStream(self, PyStreamData* sd): cdef cleanupStream(self, PyStreamData* sd):
with nogil: with nogil:
@ -375,62 +314,3 @@ cdef class Daq:
free(sd) free(sd)
def getDeviceInfo(self):
"""
Returns device information objects (DeviceInfo) for all available
devices
"""
cdef:
pass
# DaqDeviceDescriptor devdescriptors[MAX_DEF_COUNT]
# DaqDeviceDescriptor descriptor
# DaqDeviceInterface interfaceType = ANY_IFC
# DaqDeviceHandle handle
# UlError err
# unsigned int numdevs = MAX_DEF_COUNT
# unsigned deviceno
# if self.sd is not NULL:
# assert self.daq_device is not NULL
# raise RuntimeError('Cannot acquire device info: stream is already opened.')
# err = ulGetDaqDeviceInventory(interfaceType,
# devdescriptors,
# &numdevs)
# if(err != ERR_NO_ERROR):
# raise RuntimeError(f'Device inventarization failed: {err}')
# py_devinfo = []
# for deviceno in range(numdevs):
# descriptor = devdescriptors[deviceno]
# if descriptor.productName == b'DT9837A':
# # Create proper interface name
# if descriptor.devInterface == DaqDeviceInterface.USB_IFC:
# name = 'USB - '
# elif descriptor.devInterface == DaqDeviceInterface.BLUETOOTH_IFC:
# name = 'Bluetooth - '
# elif descriptor.devInterface == DaqDeviceInterface.ETHERNET_IFC:
# name = 'Ethernet - '
# name += descriptor.productName.decode('utf-8') + ', id ' + \
# descriptor.uniqueId.decode('utf-8')
# d = DeviceInfo(
# api = -1,
# index = deviceno,
# probed = True,
# name = name,
# outputchannels = 1,
# inputchannels = 4,
# duplexchannels = 0,
# samplerates = [10000, 16000, 20000, 32000, 48000, 50000] ,
# sampleformats = ['64-bit floats'],
# prefsamplerate = 48000,
# hasInputIEPE = True)
# py_devinfo.append(d)
# return py_devinfo

View File

@ -12,34 +12,13 @@ from dataclasses import dataclass, field
from typing import List from typing import List
from dataclasses_json import dataclass_json from dataclasses_json import dataclass_json
from ..lasp_common import Qty, SIQtys, lasp_shelve from ..lasp_common import Qty, SIQtys, lasp_shelve
@dataclass # class InputMode:
class DAQApi: # differential = 'Differential'
backendname: str # single_ended = 'Single-ended'
apiname: str # pseudo_differential = 'Pseudo-differential'
internal_nr: int # undefined = 'Undefined'
def description(self):
return self.backendname + ' - ' + self.apiname
class DAQApis:
apis = []
@staticmethod
def addApi(api):
DAQApis.apis.append(api)
class InputMode:
differential = 'Differential'
single_ended = 'Single-ended'
pseudo_differential = 'Pseudo-differential'
undefined = 'Undefined'
class CouplingMode: class CouplingMode:
ac = 'AC' ac = 'AC'
@ -53,21 +32,6 @@ class Range:
undefined = 'Undefined' undefined = 'Undefined'
@dataclass
class DeviceInfo:
api: int
index: int
probed: bool #
name: str
outputchannels: int
inputchannels: int
duplexchannels: int
samplerates: list
sampleformats: list
prefsamplerate: int
hasInputIEPE: bool = False
@dataclass_json @dataclass_json
@dataclass @dataclass
class DAQChannel: class DAQChannel:
@ -79,7 +43,6 @@ class DAQChannel:
IEPE_enabled: bool = False IEPE_enabled: bool = False
@dataclass_json @dataclass_json
@dataclass @dataclass
class DAQConfiguration: class DAQConfiguration:
@ -130,7 +93,7 @@ class DAQConfiguration:
monitor_gen: bool = False monitor_gen: bool = False
outputDelayBlocks: int = 0 outputDelayBlocks: int = 0
nFramesPerBlock: int = 512 nFramesPerBlock: int = 1024
def getInputChannels(self): def getInputChannels(self):
return self.input_channel_configs return self.input_channel_configs

View File

@ -0,0 +1,5 @@
include "lasp_common_decls.pxd"
cdef class DeviceInfo:
cdef:
cppDeviceInfo devinfo

View File

@ -0,0 +1,74 @@
__all__ = ['DeviceInfo']
cdef class DeviceInfo:
def __cinit__(self):
pass
@property
def api(self): return self.devinfo.api.apiname.decode('utf-8')
@property
def name(self): return self.devinfo.name.decode('utf-8')
@property
def devindex(self): return self.devinfo.devindex
@property
def ninchannels(self): return self.devinfo.ninchannels
@property
def noutchannels(self): return self.devinfo.noutchannels
@property
def availableSampleRates(self): return self.devinfo.availableSampleRates
@property
def availableDataTypes(self):
pydtypes = []
for datatype in self.devinfo.availableDataTypes:
pydtypes.append(datatype.name.decode('utf-8'))
return pydtypes
@property
def prefSampleRateIndex(self):
return self.devinfo.prefSampleRateIndex
@property
def hasInputIEPE(self):
return self.devinfo.hasInputIEPE
@property
def hasInputACCouplingSwitch(self):
return self.devinfo.hasInputACCouplingSwitch
@property
def hasInputTrigger(self):
return self.devinfo.hasInputTrigger
@property
def inputRanges(self):
return self.devinfo.inputRanges
@staticmethod
def getDeviceInfo():
"""
Returns device information objects (DeviceInfo) for all available
devices
"""
cdef:
vector[cppDeviceInfo] devinfos
us numdevs, devno
cppDeviceInfo* devinfo
devinfos = DaqDevices.getDeviceInfo()
numdevs = devinfos.size()
pydevinfos = []
for devno in range(numdevs):
devinfo = &(devinfos[devno])
d = DeviceInfo()
d.devinfo = devinfo[0]
pydevinfos.append(d)
return pydevinfos

View File

@ -3,7 +3,6 @@ include "lasp_common_decls.pxd"
__all__ = ['RtAudio', 'get_numpy_dtype_from_format_string', __all__ = ['RtAudio', 'get_numpy_dtype_from_format_string',
'get_sampwidth_from_format_string'] 'get_sampwidth_from_format_string']
cdef extern from "RtAudio.h" nogil: cdef extern from "RtAudio.h" nogil:
ctypedef unsigned long RtAudioStreamStatus ctypedef unsigned long RtAudioStreamStatus
RtAudioStreamStatus RTAUDIO_INPUT_OVERFLOW RtAudioStreamStatus RTAUDIO_INPUT_OVERFLOW
@ -442,9 +441,12 @@ cdef class RtAudio:
PyStreamData* sd PyStreamData* sd
int api int api
def __cinit__(self, unsigned int iapi): def __cinit__(self, pyapi):
if pyapi.apiname != 'RtAudio':
raise RuntimeError('RtAudio constructor called with invalid Api instance')
cdef: cdef:
cppRtAudio.Api api = <cppRtAudio.Api> iapi cppRtAudio.Api api = <cppRtAudio.Api> pyapi.internalnr
self._rtaudio = new cppRtAudio(api) self._rtaudio = new cppRtAudio(api)
self.sd = NULL self.sd = NULL
self._rtaudio.showWarnings(True) self._rtaudio.showWarnings(True)
@ -453,22 +455,29 @@ cdef class RtAudio:
def __dealloc__(self): def __dealloc__(self):
if self.sd is not NULL: if self.sd is not NULL:
# fprintf(stderr, 'Force closing stream...') # fprintf(stderr, 'Force closing stream...')
if self._rtaudio.isStreamRunning():
self._rtaudio.stopStream()
self._rtaudio.closeStream() self._rtaudio.closeStream()
self.cleanupStream(self.sd) self.cleanupStream(self.sd)
self.sd = NULL
del self._rtaudio del self._rtaudio
@staticmethod @staticmethod
def getApi(): def getApis():
cdef: cdef:
vector[cppRtAudio.Api] apis vector[cppRtAudio.Api] apis
cppRtAudio.getCompiledApi(apis) cppRtAudio.getCompiledApi(apis)
apidict = {}
apilist = []
for api in apis: for api in apis:
apidict[<int> api] = { apilist.append(
'displayname': 'RtAudio - ' + cppRtAudio.getApiDisplayName(api).decode('utf-8'), DAQApi(
'name': cppRtAudio.getApiName(api).decode('utf-8') backendname= 'RtAudio',
} apiname = cppRtAudio.getApiName(api).decode('utf-8'),
return apidict internalnr=<int> api))
return apilist
cpdef unsigned int getDefaultOutputDevice(self): cpdef unsigned int getDefaultOutputDevice(self):
return self._rtaudio.getDefaultOutputDevice() return self._rtaudio.getDefaultOutputDevice()

View File

@ -9,10 +9,11 @@ from threading import Thread, Condition, Lock
import numpy as np import numpy as np
import time import time
from .device import (RtAudio, DeviceInfo, DAQConfiguration, from .device import (Daq, DeviceInfo, DAQConfiguration,
get_numpy_dtype_from_format_string, # get_numpy_dtype_from_format_string,
get_sampwidth_from_format_string, AvType, # get_sampwidth_from_format_string,
UlDaq) AvType,
)
__all__ = ['AvStream'] __all__ = ['AvStream']

0
lasp_daqconfig.pxd Normal file
View File

0
lasp_daqconfig.pyx Normal file
View File