First work in the direction of getting a recording running again
This commit is contained in:
parent
9715f3e844
commit
3ea745245f
@ -115,7 +115,7 @@ set(SETUP_PY "${CMAKE_CURRENT_BINARY_DIR}/setup.py")
|
|||||||
set(DEPS "${CMAKE_CURRENT_SOURCE_DIR}/*.py"
|
set(DEPS "${CMAKE_CURRENT_SOURCE_DIR}/*.py"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/lasp/*.py"
|
"${CMAKE_CURRENT_SOURCE_DIR}/lasp/*.py"
|
||||||
"wrappers"
|
"wrappers"
|
||||||
"lasp_daqdevice")
|
"lasp_rtaudio")
|
||||||
|
|
||||||
# )
|
# )
|
||||||
set(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/build/timestamp")
|
set(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/build/timestamp")
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
__all__ = ['DAQDevice', 'DAQConfiguration', 'configs', 'query_devices',
|
__all__ = ['DAQConfiguration']
|
||||||
'roga_plugndaq', 'default_soundcard']
|
from .lasp_daqconfig import DAQConfiguration, DAQInputChannel
|
||||||
from .lasp_daqdevice import DAQDevice, query_devices
|
from .lasp_rtaudio import RtAudio
|
||||||
from .lasp_daqconfig import (DAQConfiguration, configs, roga_plugndaq,
|
|
||||||
default_soundcard)
|
|
||||||
|
@ -10,12 +10,30 @@ Data Acquistiion (DAQ) device descriptors, and the DAQ devices themselves
|
|||||||
"""
|
"""
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class DeviceInfo:
|
||||||
|
index: int
|
||||||
|
probed: bool
|
||||||
|
name: str
|
||||||
|
outputchannels: int
|
||||||
|
inputchannels: int
|
||||||
|
duplexchannels: int
|
||||||
|
samplerates: list
|
||||||
|
sampleformats: list
|
||||||
|
prefsamplerate: int
|
||||||
|
|
||||||
|
|
||||||
|
from ..lasp_common import lasp_shelve
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class DAQInputChannel:
|
class DAQInputChannel:
|
||||||
channel_enabled: bool
|
channel_enabled: bool
|
||||||
channel_name: str
|
channel_name: str
|
||||||
sensitivity: float
|
sensitivity: float
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class DAQConfiguration:
|
class DAQConfiguration:
|
||||||
"""
|
"""
|
||||||
@ -24,6 +42,8 @@ class DAQConfiguration:
|
|||||||
Args:
|
Args:
|
||||||
input_device_name: ASCII name with which to open the device when connected
|
input_device_name: ASCII name with which to open the device when connected
|
||||||
outut_device_name: ASCII name with which to open the device when connected
|
outut_device_name: ASCII name with which to open the device when connected
|
||||||
|
|
||||||
|
==============================
|
||||||
en_format: index of the format in the list of sample formats
|
en_format: index of the format in the list of sample formats
|
||||||
en_input_rate: index of enabled input sampling frequency [Hz]
|
en_input_rate: index of enabled input sampling frequency [Hz]
|
||||||
in the list of frequencies.
|
in the list of frequencies.
|
||||||
@ -38,61 +58,43 @@ class DAQConfiguration:
|
|||||||
en_output_rate: index in the list of possible output sampling
|
en_output_rate: index in the list of possible output sampling
|
||||||
frequencies.
|
frequencies.
|
||||||
en_output_channels: list of enabled output channels
|
en_output_channels: list of enabled output channels
|
||||||
|
===============================
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
input_device_name: bytes
|
duplex_mode: bool
|
||||||
output_device_name: bytes
|
|
||||||
en_bit_depth: int
|
input_device_name: str
|
||||||
|
output_device_name: str
|
||||||
|
|
||||||
|
en_input_sample_format: str
|
||||||
|
en_output_sample_format: str
|
||||||
en_input_rate: int
|
en_input_rate: int
|
||||||
|
en_output_rate: int
|
||||||
|
|
||||||
en_input_channels: list
|
en_input_channels: list
|
||||||
en_input_gain_settings: list = field(default_factory=list)
|
|
||||||
en_output_rate: int = -1
|
|
||||||
|
|
||||||
def match(self, device):
|
|
||||||
"""
|
|
||||||
Returns True when a device specification dictionary matches to the
|
|
||||||
configuration.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
device: dictionary specifying device settings
|
|
||||||
"""
|
|
||||||
match = True
|
|
||||||
if self.cardlongnamematch is not None:
|
|
||||||
match &= self.cardlongnamematch in device.cardlongname
|
|
||||||
if self.cardname is not None:
|
|
||||||
match &= self.cardname == device.cardname
|
|
||||||
if self.device_name is not None:
|
|
||||||
match &= self.device_name == device.device_name
|
|
||||||
match &= self.en_format < len(device.available_formats)
|
|
||||||
match &= self.en_input_rate < len(device.available_input_rates)
|
|
||||||
match &= max(
|
|
||||||
self.en_input_channels) < device.max_input_channels
|
|
||||||
if len(self.en_output_channels) > 0:
|
|
||||||
match &= max(
|
|
||||||
self.en_output_channels) < device.max_output_channels
|
|
||||||
match &= self.en_output_rate < len(
|
|
||||||
device.available_output_rates)
|
|
||||||
|
|
||||||
return match
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def emptyFromDeviceAndSettings(device):
|
def loadConfigs():
|
||||||
return DAQConfiguration(
|
"""
|
||||||
name = 'UNKNOWN'
|
Returns a list of currently available configurations
|
||||||
input_device_name =
|
"""
|
||||||
|
with lasp_shelve() as sh:
|
||||||
|
return sh['daqconfigs'] if 'daqconfigs' in sh.keys() else {}
|
||||||
|
|
||||||
def findDAQDevice(config: DAQConfiguration) -> DeviceInfo:
|
def saveConfig(self, name):
|
||||||
"""
|
with lasp_shelve() as sh:
|
||||||
Search for a DaQ device for the given configuration.
|
if 'daqconfigs' in sh.keys():
|
||||||
|
cur_configs = sh['daqconfigs']
|
||||||
|
else:
|
||||||
|
cur_configs = {}
|
||||||
|
cur_configs[name] = self
|
||||||
|
sh['daqconfigs'] = cur_configs
|
||||||
|
|
||||||
Args:
|
@staticmethod
|
||||||
config: configuration to search a device for
|
def deleteConfig(name):
|
||||||
"""
|
with lasp_shelve() as sh:
|
||||||
devices = query_devices()
|
cur_configs = sh['daqconfigs']
|
||||||
|
del cur_configs[name]
|
||||||
|
sh['daqconfigs'] = cur_configs
|
||||||
|
|
||||||
for device in devices:
|
|
||||||
if config.match(device):
|
|
||||||
return device
|
|
||||||
return None
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import sys
|
import sys
|
||||||
include "config.pxi"
|
include "config.pxi"
|
||||||
cimport cython
|
cimport cython
|
||||||
|
from .lasp_daqconfig import DeviceInfo
|
||||||
from libcpp.string cimport string
|
from libcpp.string cimport string
|
||||||
from libcpp.vector cimport vector
|
from libcpp.vector cimport vector
|
||||||
from libc.string cimport memcpy
|
from libc.string cimport memcpy
|
||||||
@ -99,57 +100,27 @@ cdef extern from "RtAudio.h" nogil:
|
|||||||
unsigned int getStreamSampleRate()
|
unsigned int getStreamSampleRate()
|
||||||
void showWarnings(bool value)
|
void showWarnings(bool value)
|
||||||
|
|
||||||
cdef class SampleFormat:
|
_formats_strkey = {
|
||||||
cdef:
|
'8-bit integers': (RTAUDIO_SINT8, 1),
|
||||||
RtAudioFormat _format
|
'16-bit integers': (RTAUDIO_SINT16,2),
|
||||||
string _name
|
'24-bit integers': (RTAUDIO_SINT24,3),
|
||||||
public:
|
'32-bit integers': (RTAUDIO_SINT32,4),
|
||||||
# The size in bytes of a single audio sample, for the current
|
'32-bit floats': (RTAUDIO_FLOAT32, 4),
|
||||||
# format
|
'64-bit floats': (RTAUDIO_FLOAT64, 8),
|
||||||
unsigned int sampleSize
|
}
|
||||||
|
_formats_rtkey = {
|
||||||
def __cinit__(self, RtAudioFormat format_):
|
RTAUDIO_SINT8: ('8-bit integers', 1),
|
||||||
self._format = format_
|
RTAUDIO_SINT16: ('16-bit integers',2),
|
||||||
if format_ == RTAUDIO_SINT8:
|
RTAUDIO_SINT24: ('24-bit integers',3),
|
||||||
self._name = b'8-bit integers'
|
RTAUDIO_SINT32: ('32-bit integers',4),
|
||||||
self.sampleSize = 1
|
RTAUDIO_FLOAT32: ('32-bit floats', 4),
|
||||||
elif format_ == RTAUDIO_SINT16:
|
RTAUDIO_FLOAT64: ('64-bit floats', 8),
|
||||||
self._name = b'16-bit integers'
|
}
|
||||||
self.sampleSize = 2
|
|
||||||
elif format_ == RTAUDIO_SINT24:
|
|
||||||
self._name = b'24-bit integers'
|
|
||||||
self.sampleSize = 3
|
|
||||||
elif format_ == RTAUDIO_SINT32:
|
|
||||||
self._name = b'32-bit integers'
|
|
||||||
self.sampleSize = 4
|
|
||||||
elif format_ == RTAUDIO_FLOAT32:
|
|
||||||
self._name = b'32-bit floats'
|
|
||||||
self.sampleSize = 4
|
|
||||||
elif format_ == RTAUDIO_FLOAT64:
|
|
||||||
self._name = b'64-bit floats'
|
|
||||||
self.sampleSize = 8
|
|
||||||
else:
|
|
||||||
raise ValueError('Invalid RtAudioFormat code')
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return self._name.decode('utf-8')
|
|
||||||
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.__repr__()
|
|
||||||
|
|
||||||
# Pre-define format and expose to Python
|
|
||||||
Format_SINT8 = SampleFormat(RTAUDIO_SINT8)
|
|
||||||
Format_SINT16 = SampleFormat(RTAUDIO_SINT16)
|
|
||||||
Format_SINT24 = SampleFormat(RTAUDIO_SINT24)
|
|
||||||
Format_SINT32 = SampleFormat(RTAUDIO_SINT32)
|
|
||||||
Format_FLOAT32 = SampleFormat(RTAUDIO_FLOAT32)
|
|
||||||
Format_FLOAT64 = SampleFormat(RTAUDIO_FLOAT64)
|
|
||||||
|
|
||||||
cdef class _Stream:
|
cdef class _Stream:
|
||||||
cdef:
|
cdef:
|
||||||
object pyCallback
|
object pyCallback
|
||||||
RtAudioFormat format
|
unsigned int sampleSize
|
||||||
|
RtAudioFormat sampleformat
|
||||||
cppRtAudio.StreamParameters inputParams
|
cppRtAudio.StreamParameters inputParams
|
||||||
cppRtAudio.StreamParameters outputParams
|
cppRtAudio.StreamParameters outputParams
|
||||||
# These boolean values tell us whether the structs above here are
|
# These boolean values tell us whether the structs above here are
|
||||||
@ -226,7 +197,7 @@ cdef int audioCallback(void* outputBuffer,
|
|||||||
assert outputBuffer != NULL, "Bug: RtAudio does not give output buffer!"
|
assert outputBuffer != NULL, "Bug: RtAudio does not give output buffer!"
|
||||||
assert npy_output.shape[0] == stream.outputParams.nChannels, "Bug: channel mismatch in output buffer!"
|
assert npy_output.shape[0] == stream.outputParams.nChannels, "Bug: channel mismatch in output buffer!"
|
||||||
assert npy_output.shape[1] == nFrames, "Bug: frame mismatch in output buffer!"
|
assert npy_output.shape[1] == nFrames, "Bug: frame mismatch in output buffer!"
|
||||||
assert npy_output.itemsize == stream._format.sampleSize, "Bug: invalid sample type in output buffer!"
|
assert npy_output.itemsize == stream.sampleSize, "Bug: invalid sample type in output buffer!"
|
||||||
except AssertionError as e:
|
except AssertionError as e:
|
||||||
print(e)
|
print(e)
|
||||||
fromNPYToBuffer(npy_output, outputBuffer)
|
fromNPYToBuffer(npy_output, outputBuffer)
|
||||||
@ -236,6 +207,8 @@ cdef void errorCallback(RtAudioError.Type _type,const string& errortxt) nogil:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cdef class RtAudio:
|
cdef class RtAudio:
|
||||||
cdef:
|
cdef:
|
||||||
cppRtAudio _rtaudio
|
cppRtAudio _rtaudio
|
||||||
@ -263,31 +236,26 @@ cdef class RtAudio:
|
|||||||
Return device information of the current device
|
Return device information of the current device
|
||||||
"""
|
"""
|
||||||
cdef cppRtAudio.DeviceInfo devinfo = self._rtaudio.getDeviceInfo(device)
|
cdef cppRtAudio.DeviceInfo devinfo = self._rtaudio.getDeviceInfo(device)
|
||||||
pydevinfo = {}
|
|
||||||
pydevinfo['index'] = device
|
|
||||||
pydevinfo['probed'] = devinfo.probed
|
|
||||||
pydevinfo['name'] = devinfo.name.decode('utf-8')
|
|
||||||
pydevinfo['outputchannels'] = devinfo.outputChannels
|
|
||||||
pydevinfo['inputchannels'] = devinfo.inputChannels
|
|
||||||
pydevinfo['duplexchannels'] = devinfo.duplexChannels
|
|
||||||
pydevinfo['isdefaultoutput'] = devinfo.isDefaultOutput
|
|
||||||
pydevinfo['isdefaultinpput'] = devinfo.isDefaultInput
|
|
||||||
pydevinfo['samplerates'] = devinfo.sampleRates
|
|
||||||
pydevinfo['prefsamprate'] = devinfo.preferredSampleRate
|
|
||||||
# Manually add these
|
|
||||||
nf = devinfo.nativeFormats
|
|
||||||
sampleformats = []
|
sampleformats = []
|
||||||
|
nf = devinfo.nativeFormats
|
||||||
for format_ in [ RTAUDIO_SINT8, RTAUDIO_SINT16, RTAUDIO_SINT24,
|
for format_ in [ RTAUDIO_SINT8, RTAUDIO_SINT16, RTAUDIO_SINT24,
|
||||||
RTAUDIO_SINT32, RTAUDIO_FLOAT32, RTAUDIO_FLOAT64]:
|
RTAUDIO_SINT32, RTAUDIO_FLOAT32, RTAUDIO_FLOAT64]:
|
||||||
if nf & format_:
|
if nf & format_:
|
||||||
sampleformats.append(SampleFormat(format_))
|
sampleformats.append(_formats_rtkey[format_][0])
|
||||||
|
return DeviceInfo(
|
||||||
pydevinfo['sampleformats'] = sampleformats
|
index = device,
|
||||||
return pydevinfo
|
probed = devinfo.probed,
|
||||||
|
name = devinfo.name.decode('utf-8'),
|
||||||
|
outputchannels = devinfo.outputChannels,
|
||||||
|
inputchannels = devinfo.inputChannels,
|
||||||
|
duplexchannels = devinfo.duplexChannels,
|
||||||
|
samplerates = devinfo.sampleRates,
|
||||||
|
sampleformats = sampleformats,
|
||||||
|
prefsamplerate = devinfo.preferredSampleRate)
|
||||||
|
|
||||||
def openStream(self,object outputParams,
|
def openStream(self,object outputParams,
|
||||||
object inputParams,
|
object inputParams,
|
||||||
SampleFormat format,
|
str sampleformat,
|
||||||
unsigned int sampleRate,
|
unsigned int sampleRate,
|
||||||
unsigned int bufferFrames,
|
unsigned int bufferFrames,
|
||||||
object pyCallback,
|
object pyCallback,
|
||||||
@ -342,7 +310,7 @@ cdef class RtAudio:
|
|||||||
self._stream.bufferFrames = bufferFrames
|
self._stream.bufferFrames = bufferFrames
|
||||||
self._rtaudio.openStream(rtOutputParams_ptr,
|
self._rtaudio.openStream(rtOutputParams_ptr,
|
||||||
rtInputParams_ptr,
|
rtInputParams_ptr,
|
||||||
format._format,
|
_formats_strkey[sampleformat][0],
|
||||||
sampleRate,
|
sampleRate,
|
||||||
&self._stream.bufferFrames,
|
&self._stream.bufferFrames,
|
||||||
audioCallback,
|
audioCallback,
|
||||||
|
@ -7,7 +7,7 @@ import cv2 as cv
|
|||||||
from .lasp_atomic import Atomic
|
from .lasp_atomic import Atomic
|
||||||
from threading import Thread, Condition, Lock
|
from threading import Thread, Condition, Lock
|
||||||
import time
|
import time
|
||||||
from .device import DAQDevice, roga_plugndaq
|
from .device import DAQConfiguration
|
||||||
import numpy as np
|
import numpy as np
|
||||||
__all__ = ['AvType', 'AvStream']
|
__all__ = ['AvType', 'AvStream']
|
||||||
|
|
||||||
@ -21,9 +21,16 @@ class AvType:
|
|||||||
|
|
||||||
|
|
||||||
class AvStream:
|
class AvStream:
|
||||||
def __init__(self, daqconfig=roga_plugndaq, video=None):
|
def __init__(self,
|
||||||
|
rtaudio_input,
|
||||||
|
rtaudio_output,
|
||||||
|
input_device,
|
||||||
|
output_device, daqconfig, video=None):
|
||||||
|
|
||||||
|
|
||||||
self.daqconfig = daqconfig
|
self.daqconfig = daqconfig
|
||||||
|
self.input_device = input_device
|
||||||
|
self.output_device = output_device
|
||||||
try:
|
try:
|
||||||
daq = DAQDevice(daqconfig)
|
daq = DAQDevice(daqconfig)
|
||||||
self.nchannels = len(daq.channels_en)
|
self.nchannels = len(daq.channels_en)
|
||||||
|
@ -8,7 +8,7 @@ Common definitions used throughout the code.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
__all__ = ['P_REF', 'FreqWeighting', 'TimeWeighting', 'getTime',
|
__all__ = ['P_REF', 'FreqWeighting', 'TimeWeighting', 'getTime',
|
||||||
'getFreq', 'lasp_shelve'
|
'getFreq', 'lasp_shelve',
|
||||||
'W_REF', 'U_REF', 'I_REF']
|
'W_REF', 'U_REF', 'I_REF']
|
||||||
|
|
||||||
lasp_appdir = appdirs.user_data_dir('Lasp', 'ASCEE')
|
lasp_appdir = appdirs.user_data_dir('Lasp', 'ASCEE')
|
||||||
@ -23,12 +23,21 @@ if not os.path.exists(lasp_appdir):
|
|||||||
|
|
||||||
|
|
||||||
class lasp_shelve:
|
class lasp_shelve:
|
||||||
|
refcount = 0
|
||||||
|
shelve = None
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
self.shelve = shelve.open(os.path.join(lasp_appdir, 'config.shelve'))
|
if lasp_shelve.shelve is None:
|
||||||
return self.shelve
|
assert lasp_shelve.refcount == 0
|
||||||
|
lasp_shelve.shelve = shelve.open(os.path.join(lasp_appdir, 'config.shelve'))
|
||||||
|
lasp_shelve.refcount += 1
|
||||||
|
return lasp_shelve.shelve
|
||||||
|
|
||||||
def __exit__(self, type, value, traceback):
|
def __exit__(self, type, value, traceback):
|
||||||
self.shelve.close()
|
lasp_shelve.refcount -= 1
|
||||||
|
if lasp_shelve.refcount == 0:
|
||||||
|
lasp_shelve.shelve.close()
|
||||||
|
lasp_shelve.shelve = None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user