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 )
|
||||
|
||||
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
|
||||
"${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_deviceinfo lasp_deviceinfo.pyx)
|
||||
|
||||
target_link_libraries(lasp_daq cpp_daq uldaq rtaudio pthread)
|
||||
target_link_libraries(lasp_deviceinfo cpp_daq uldaq rtaudio pthread)
|
||||
if(win32)
|
||||
target_link_libraries(lasp_daq python37)
|
||||
endif(win32)
|
||||
|
@ -2,4 +2,5 @@
|
||||
from .lasp_daqconfig import *
|
||||
from .lasp_avtype import *
|
||||
from .lasp_daq import *
|
||||
from .lasp_deviceinfo import *
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
import sys
|
||||
include "config.pxi"
|
||||
cimport cython
|
||||
from .lasp_daqconfig import DeviceInfo
|
||||
from .lasp_avtype import AvType
|
||||
from libcpp.string cimport string
|
||||
from libcpp.vector cimport vector
|
||||
@ -10,10 +9,6 @@ from libc.stdio cimport printf, fprintf, stderr
|
||||
from libc.string cimport memcpy, memset
|
||||
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 cppclass CPPThread[T,F]:
|
||||
CPPThread(F threadfunction, T data)
|
||||
@ -30,7 +25,6 @@ cdef extern from "lasp_cppqueue.h" nogil:
|
||||
size_t size() const
|
||||
bool empty() const
|
||||
|
||||
|
||||
cdef extern from "atomic" namespace "std" nogil:
|
||||
cdef cppclass atomic[T]:
|
||||
T load()
|
||||
@ -43,13 +37,60 @@ cdef extern from "lasp_pyarray.h":
|
||||
bool transfer_ownership,
|
||||
bool F_contiguous)
|
||||
|
||||
ctypedef unsigned us
|
||||
ctypedef vector[bool] boolvec
|
||||
|
||||
cdef inline void copyChannel(void* to, void* from_,
|
||||
unsigned bytesperchan,
|
||||
unsigned toindex,
|
||||
unsigned fromindex) nogil:
|
||||
memcpy(<void*> &((<char*> to)[bytesperchan*toindex]),
|
||||
<void*> &((<char*> from_)[bytesperchan*fromindex]),
|
||||
bytesperchan)
|
||||
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
|
||||
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)
|
||||
: 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_int8("8-bits integers", 1, false);
|
||||
const DataType dtype_int16("16-bits integers", 2, false);
|
||||
@ -100,6 +104,10 @@ class DeviceInfo {
|
||||
bool hasInputIEPE = false;
|
||||
bool hasInputACCouplingSwitch = false;
|
||||
bool hasInputTrigger = false;
|
||||
vector<double> inputRanges;
|
||||
|
||||
/* DeviceInfo(): */
|
||||
/* datatype(dtype_invalid) { } */
|
||||
|
||||
double prefSampleRate() const {
|
||||
if ((prefSampleRateIndex < availableSampleRates.size()) &&
|
||||
|
@ -1,66 +1,10 @@
|
||||
cimport cython
|
||||
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)
|
||||
from .lasp_avtype import AvType
|
||||
|
||||
__all__ = ['UlDaq']
|
||||
|
||||
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&)
|
||||
__all__ = ['Daq']
|
||||
|
||||
|
||||
ctypedef struct PyStreamData:
|
||||
@ -80,7 +24,7 @@ ctypedef struct PyStreamData:
|
||||
|
||||
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.
|
||||
SafeQueue[void*] *inQueue
|
||||
SafeQueue[void*] *outQueue
|
||||
@ -196,139 +140,135 @@ cdef class Daq:
|
||||
def isRunning(self):
|
||||
return self.sd is not NULL
|
||||
|
||||
@cython.nonecheck(True)
|
||||
def start(self, avstream):
|
||||
"""
|
||||
Opens a stream with specified parameters
|
||||
# @cython.nonecheck(True)
|
||||
# def start(self, avstream):
|
||||
# """
|
||||
# Opens a stream with specified parameters
|
||||
|
||||
Args:
|
||||
avstream: AvStream instance
|
||||
# Args:
|
||||
# avstream: AvStream instance
|
||||
|
||||
Returns: None
|
||||
"""
|
||||
# Returns: None
|
||||
# """
|
||||
|
||||
if self.sd is not NULL:
|
||||
assert self.daq_device is not NULL
|
||||
raise RuntimeError('Stream is already opened.')
|
||||
# if self.sd is not NULL:
|
||||
# assert self.daq_device is not NULL
|
||||
# raise RuntimeError('Stream is already opened.')
|
||||
|
||||
daqconfig = avstream.daqconfig
|
||||
avtype = avstream.avtype
|
||||
device = avstream.device
|
||||
# daqconfig = avstream.daqconfig
|
||||
# avtype = avstream.avtype
|
||||
# device = avstream.device
|
||||
|
||||
cdef:
|
||||
bint duplex_mode = daqconfig.duplex_mode
|
||||
bint monitorOutput = daqconfig.monitor_gen
|
||||
# cdef:
|
||||
# bint duplex_mode = daqconfig.duplex_mode
|
||||
# bint monitorOutput = daqconfig.monitor_gen
|
||||
|
||||
unsigned int nFramesPerBlock = daqconfig.nFramesPerBlock
|
||||
unsigned int samplerate
|
||||
# unsigned int nFramesPerBlock = daqconfig.nFramesPerBlock
|
||||
# unsigned int samplerate
|
||||
|
||||
int i
|
||||
bint in_stream=False
|
||||
bint out_stream=False
|
||||
# int i
|
||||
# bint in_stream=False
|
||||
# bint out_stream=False
|
||||
|
||||
cppDaq* daq_device
|
||||
# cppDeviceInfo devinfo
|
||||
# DaqConfiguration cppconfig
|
||||
|
||||
if daqconfig.nFramesPerBlock > 8192 or daqconfig.nFramesPerBlock < 512:
|
||||
raise ValueError('Invalid number of nFramesPerBlock')
|
||||
# cppDaq* daq_device
|
||||
|
||||
if daqconfig.outputDelayBlocks != 0:
|
||||
print('WARNING: OutputDelayBlocks not supported by API')
|
||||
|
||||
# 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')
|
||||
# if daqconfig.nFramesPerBlock > 8192 or daqconfig.nFramesPerBlock < 512:
|
||||
# raise ValueError('Invalid number of nFramesPerBlock')
|
||||
|
||||
|
||||
# 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)
|
||||
self.sd.inQueue = NULL
|
||||
self.sd.outQueue = NULL
|
||||
# # 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}')
|
||||
|
||||
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:
|
||||
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)
|
||||
# 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 RuntimeError(f'Device {device.name} not found or not configured')
|
||||
# raise ValueError(f'Invalid stream type {avtype}')
|
||||
|
||||
self.sd.pyCallback = <PyObject*> avstream._audioCallback
|
||||
self.sd.ninchannels = daq_device.neninchannels()
|
||||
self.sd.noutchannels = daq_device.nenoutchannels()
|
||||
# if out_stream and daqconfig.firstEnabledOutputChannelNumber() == -1:
|
||||
# raise RuntimeError('No output channels enabled')
|
||||
|
||||
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:
|
||||
self.sd.thread = new CPPThread[void*, void (*)(void*)](audioCallbackPythonThreadFunction,
|
||||
<void*> self.sd)
|
||||
# # All set, allocate the stream!
|
||||
# self.sd = <PyStreamData*> malloc(sizeof(PyStreamData))
|
||||
# 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.inQueue,
|
||||
self.sd.outQueue)
|
||||
# self.sd.stopThread.store(False)
|
||||
# self.sd.inQueue = NULL
|
||||
# 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):
|
||||
if self.sd is NULL:
|
||||
@ -341,7 +281,6 @@ cdef class Daq:
|
||||
self.cleanupStream(self.sd)
|
||||
self.sd = NULL
|
||||
|
||||
|
||||
cdef cleanupStream(self, PyStreamData* sd):
|
||||
|
||||
with nogil:
|
||||
@ -375,62 +314,3 @@ cdef class Daq:
|
||||
|
||||
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 dataclasses_json import dataclass_json
|
||||
|
||||
from ..lasp_common import Qty, SIQtys, lasp_shelve
|
||||
|
||||
@dataclass
|
||||
class DAQApi:
|
||||
backendname: str
|
||||
apiname: str
|
||||
internal_nr: int
|
||||
|
||||
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 InputMode:
|
||||
# differential = 'Differential'
|
||||
# single_ended = 'Single-ended'
|
||||
# pseudo_differential = 'Pseudo-differential'
|
||||
# undefined = 'Undefined'
|
||||
|
||||
class CouplingMode:
|
||||
ac = 'AC'
|
||||
@ -53,21 +32,6 @@ class Range:
|
||||
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
|
||||
class DAQChannel:
|
||||
@ -79,7 +43,6 @@ class DAQChannel:
|
||||
IEPE_enabled: bool = False
|
||||
|
||||
|
||||
|
||||
@dataclass_json
|
||||
@dataclass
|
||||
class DAQConfiguration:
|
||||
@ -130,7 +93,7 @@ class DAQConfiguration:
|
||||
monitor_gen: bool = False
|
||||
|
||||
outputDelayBlocks: int = 0
|
||||
nFramesPerBlock: int = 512
|
||||
nFramesPerBlock: int = 1024
|
||||
|
||||
def getInputChannels(self):
|
||||
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',
|
||||
'get_sampwidth_from_format_string']
|
||||
|
||||
|
||||
cdef extern from "RtAudio.h" nogil:
|
||||
ctypedef unsigned long RtAudioStreamStatus
|
||||
RtAudioStreamStatus RTAUDIO_INPUT_OVERFLOW
|
||||
@ -442,9 +441,12 @@ cdef class RtAudio:
|
||||
PyStreamData* sd
|
||||
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:
|
||||
cppRtAudio.Api api = <cppRtAudio.Api> iapi
|
||||
cppRtAudio.Api api = <cppRtAudio.Api> pyapi.internalnr
|
||||
|
||||
self._rtaudio = new cppRtAudio(api)
|
||||
self.sd = NULL
|
||||
self._rtaudio.showWarnings(True)
|
||||
@ -453,22 +455,29 @@ cdef class RtAudio:
|
||||
def __dealloc__(self):
|
||||
if self.sd is not NULL:
|
||||
# fprintf(stderr, 'Force closing stream...')
|
||||
if self._rtaudio.isStreamRunning():
|
||||
self._rtaudio.stopStream()
|
||||
self._rtaudio.closeStream()
|
||||
|
||||
self.cleanupStream(self.sd)
|
||||
self.sd = NULL
|
||||
del self._rtaudio
|
||||
|
||||
@staticmethod
|
||||
def getApi():
|
||||
def getApis():
|
||||
cdef:
|
||||
vector[cppRtAudio.Api] apis
|
||||
cppRtAudio.getCompiledApi(apis)
|
||||
apidict = {}
|
||||
|
||||
apilist = []
|
||||
for api in apis:
|
||||
apidict[<int> api] = {
|
||||
'displayname': 'RtAudio - ' + cppRtAudio.getApiDisplayName(api).decode('utf-8'),
|
||||
'name': cppRtAudio.getApiName(api).decode('utf-8')
|
||||
}
|
||||
return apidict
|
||||
apilist.append(
|
||||
DAQApi(
|
||||
backendname= 'RtAudio',
|
||||
apiname = cppRtAudio.getApiName(api).decode('utf-8'),
|
||||
internalnr=<int> api))
|
||||
|
||||
return apilist
|
||||
|
||||
cpdef unsigned int getDefaultOutputDevice(self):
|
||||
return self._rtaudio.getDefaultOutputDevice()
|
||||
|
@ -9,10 +9,11 @@ from threading import Thread, Condition, Lock
|
||||
import numpy as np
|
||||
|
||||
import time
|
||||
from .device import (RtAudio, DeviceInfo, DAQConfiguration,
|
||||
get_numpy_dtype_from_format_string,
|
||||
get_sampwidth_from_format_string, AvType,
|
||||
UlDaq)
|
||||
from .device import (Daq, DeviceInfo, DAQConfiguration,
|
||||
# get_numpy_dtype_from_format_string,
|
||||
# get_sampwidth_from_format_string,
|
||||
AvType,
|
||||
)
|
||||
|
||||
__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