DaqConfiguration and device info will have a direct Cython wrapper
This commit is contained in:
parent
a3963c4595
commit
a43857070b
@ -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)
|
||||||
|
@ -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 *
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
@ -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()) &&
|
||||||
|
@ -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:
|
# # if daqconfig.outputDelayBlocks != 0:
|
||||||
raise RuntimeError('No output channels enabled')
|
# # print('WARNING: OutputDelayBlocks not supported by API')
|
||||||
|
|
||||||
if in_stream and daqconfig.firstEnabledInputChannelNumber() == -1:
|
# # Determine sample rate and sample format, determine whether we are an
|
||||||
raise RuntimeError('No input channels enabled')
|
# # 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!
|
# # All set, allocate the stream!
|
||||||
self.sd = <PyStreamData*> malloc(sizeof(PyStreamData))
|
# self.sd = <PyStreamData*> malloc(sizeof(PyStreamData))
|
||||||
if self.sd == NULL:
|
# if self.sd == NULL:
|
||||||
raise MemoryError('Could not allocate stream: memory error.')
|
# raise MemoryError('Could not allocate stream: memory error.')
|
||||||
|
|
||||||
|
|
||||||
self.sd.stopThread.store(False)
|
# self.sd.stopThread.store(False)
|
||||||
self.sd.inQueue = NULL
|
# self.sd.inQueue = NULL
|
||||||
self.sd.outQueue = NULL
|
# self.sd.outQueue = NULL
|
||||||
|
|
||||||
self.sd.thread = NULL
|
# self.sd.thread = NULL
|
||||||
self.sd.samplerate = <double> samplerate
|
# self.sd.samplerate = <double> samplerate
|
||||||
|
|
||||||
self.sd.ninchannels = 0
|
# self.sd.ninchannels = 0
|
||||||
self.sd.noutchannels = 0
|
# self.sd.noutchannels = 0
|
||||||
self.sd.nBytesPerChan = daqconfig.nFramesPerBlock*sizeof(double)
|
# self.sd.nBytesPerChan = daqconfig.nFramesPerBlock*sizeof(double)
|
||||||
self.sd.nFramesPerBlock = daqconfig.nFramesPerBlock
|
# self.sd.nFramesPerBlock = daqconfig.nFramesPerBlock
|
||||||
|
|
||||||
|
|
||||||
# Create channel maps for in channels, set in stream
|
# # Create channel maps for in channels, set in stream
|
||||||
# parameters
|
# # parameters
|
||||||
inch_enabled = 4*[False]
|
# inch_enabled = 4*[False]
|
||||||
if in_stream:
|
# if in_stream:
|
||||||
inch_enabled = [True if ch.channel_enabled else False for ch in
|
# inch_enabled = [True if ch.channel_enabled else False for ch in
|
||||||
daqconfig.getInputChannels()]
|
# daqconfig.getInputChannels()]
|
||||||
|
|
||||||
self.sd.inQueue = new SafeQueue[void*]()
|
# self.sd.inQueue = new SafeQueue[void*]()
|
||||||
|
|
||||||
# Create channel maps for output channels
|
# # Create channel maps for output channels
|
||||||
outch_enabled = 1*[False]
|
# outch_enabled = 1*[False]
|
||||||
if out_stream:
|
# if out_stream:
|
||||||
print('Stream is output stream')
|
# outch_enabled = [True if ch.channel_enabled else False for ch in
|
||||||
outch_enabled = [True if ch.channel_enabled else False for ch in
|
# daqconfig.getOutputChannels()]
|
||||||
daqconfig.getOutputChannels()]
|
|
||||||
|
|
||||||
self.sd.outQueue = new SafeQueue[void*]()
|
# self.sd.outQueue = new SafeQueue[void*]()
|
||||||
|
|
||||||
# if 'DT9837A' in device.name:
|
# daq_device = createDaqDevice(devinfo, cppconfig)
|
||||||
# daq_device = new DT9837A(
|
|
||||||
# daqconfig.nFramesPerBlock,
|
|
||||||
# inch_enabled,
|
|
||||||
# outch_enabled,
|
|
||||||
# samplerate,
|
|
||||||
# monitorOutput,
|
|
||||||
# device.index)
|
|
||||||
# else:
|
|
||||||
# raise RuntimeError(f'Device {device.name} not found or not configured')
|
|
||||||
|
|
||||||
self.sd.pyCallback = <PyObject*> avstream._audioCallback
|
# self.sd.pyCallback = <PyObject*> avstream._audioCallback
|
||||||
self.sd.ninchannels = daq_device.neninchannels()
|
# self.sd.ninchannels = daq_device.neninchannels()
|
||||||
self.sd.noutchannels = daq_device.nenoutchannels()
|
# self.sd.noutchannels = daq_device.nenoutchannels()
|
||||||
|
|
||||||
self.daq_device = daq_device
|
# self.daq_device = daq_device
|
||||||
|
|
||||||
# Increase reference count to the callback
|
# # Increase reference count to the callback
|
||||||
Py_INCREF(<object> avstream._audioCallback)
|
# Py_INCREF(<object> avstream._audioCallback)
|
||||||
|
|
||||||
with nogil:
|
# with nogil:
|
||||||
self.sd.thread = new CPPThread[void*, void (*)(void*)](audioCallbackPythonThreadFunction,
|
# self.sd.thread = new CPPThread[void*, void (*)(void*)](audioCallbackPythonThreadFunction,
|
||||||
<void*> self.sd)
|
# <void*> self.sd)
|
||||||
|
|
||||||
# Allow it to start
|
# # Allow it to start
|
||||||
CPPsleep_ms(500)
|
# CPPsleep_ms(500)
|
||||||
|
|
||||||
self.daq_device.start(
|
# self.daq_device.start(
|
||||||
self.sd.inQueue,
|
# self.sd.inQueue,
|
||||||
self.sd.outQueue)
|
# self.sd.outQueue)
|
||||||
|
|
||||||
return nFramesPerBlock, self.daq_device.samplerate()
|
# 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
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
5
lasp/device/lasp_deviceinfo.pxd
Normal file
5
lasp/device/lasp_deviceinfo.pxd
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
include "lasp_common_decls.pxd"
|
||||||
|
|
||||||
|
cdef class DeviceInfo:
|
||||||
|
cdef:
|
||||||
|
cppDeviceInfo devinfo
|
74
lasp/device/lasp_deviceinfo.pyx
Normal file
74
lasp/device/lasp_deviceinfo.pyx
Normal 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
|
@ -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()
|
||||||
|
@ -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
0
lasp_daqconfig.pxd
Normal file
0
lasp_daqconfig.pyx
Normal file
0
lasp_daqconfig.pyx
Normal file
Loading…
Reference in New Issue
Block a user