First work in the direction of getting a recording running again

This commit is contained in:
Anne de Jong 2019-12-17 14:09:45 +01:00
parent 9715f3e844
commit 3ea745245f
6 changed files with 112 additions and 128 deletions

View File

@ -115,7 +115,7 @@ set(SETUP_PY "${CMAKE_CURRENT_BINARY_DIR}/setup.py")
set(DEPS "${CMAKE_CURRENT_SOURCE_DIR}/*.py"
"${CMAKE_CURRENT_SOURCE_DIR}/lasp/*.py"
"wrappers"
"lasp_daqdevice")
"lasp_rtaudio")
# )
set(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/build/timestamp")

View File

@ -1,6 +1,4 @@
#!/usr/bin/python3
__all__ = ['DAQDevice', 'DAQConfiguration', 'configs', 'query_devices',
'roga_plugndaq', 'default_soundcard']
from .lasp_daqdevice import DAQDevice, query_devices
from .lasp_daqconfig import (DAQConfiguration, configs, roga_plugndaq,
default_soundcard)
__all__ = ['DAQConfiguration']
from .lasp_daqconfig import DAQConfiguration, DAQInputChannel
from .lasp_rtaudio import RtAudio

View File

@ -10,12 +10,30 @@ Data Acquistiion (DAQ) device descriptors, and the DAQ devices themselves
"""
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
class DAQInputChannel:
channel_enabled: bool
channel_name: str
sensitivity: float
@dataclass
class DAQConfiguration:
"""
@ -24,6 +42,8 @@ class DAQConfiguration:
Args:
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
==============================
en_format: index of the format in the list of sample formats
en_input_rate: index of enabled input sampling frequency [Hz]
in the list of frequencies.
@ -38,61 +58,43 @@ class DAQConfiguration:
en_output_rate: index in the list of possible output sampling
frequencies.
en_output_channels: list of enabled output channels
===============================
"""
input_device_name: bytes
output_device_name: bytes
en_bit_depth: int
duplex_mode: bool
input_device_name: str
output_device_name: str
en_input_sample_format: str
en_output_sample_format: str
en_input_rate: int
en_output_rate: int
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
def emptyFromDeviceAndSettings(device):
return DAQConfiguration(
name = 'UNKNOWN'
input_device_name =
def loadConfigs():
"""
Returns a list of currently available configurations
"""
with lasp_shelve() as sh:
return sh['daqconfigs'] if 'daqconfigs' in sh.keys() else {}
def findDAQDevice(config: DAQConfiguration) -> DeviceInfo:
"""
Search for a DaQ device for the given configuration.
def saveConfig(self, name):
with lasp_shelve() as sh:
if 'daqconfigs' in sh.keys():
cur_configs = sh['daqconfigs']
else:
cur_configs = {}
cur_configs[name] = self
sh['daqconfigs'] = cur_configs
Args:
config: configuration to search a device for
"""
devices = query_devices()
@staticmethod
def deleteConfig(name):
with lasp_shelve() as sh:
cur_configs = sh['daqconfigs']
del cur_configs[name]
sh['daqconfigs'] = cur_configs
for device in devices:
if config.match(device):
return device
return None

View File

@ -1,6 +1,7 @@
import sys
include "config.pxi"
cimport cython
from .lasp_daqconfig import DeviceInfo
from libcpp.string cimport string
from libcpp.vector cimport vector
from libc.string cimport memcpy
@ -99,57 +100,27 @@ cdef extern from "RtAudio.h" nogil:
unsigned int getStreamSampleRate()
void showWarnings(bool value)
cdef class SampleFormat:
cdef:
RtAudioFormat _format
string _name
public:
# The size in bytes of a single audio sample, for the current
# format
unsigned int sampleSize
def __cinit__(self, RtAudioFormat format_):
self._format = format_
if format_ == RTAUDIO_SINT8:
self._name = b'8-bit integers'
self.sampleSize = 1
elif format_ == RTAUDIO_SINT16:
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)
_formats_strkey = {
'8-bit integers': (RTAUDIO_SINT8, 1),
'16-bit integers': (RTAUDIO_SINT16,2),
'24-bit integers': (RTAUDIO_SINT24,3),
'32-bit integers': (RTAUDIO_SINT32,4),
'32-bit floats': (RTAUDIO_FLOAT32, 4),
'64-bit floats': (RTAUDIO_FLOAT64, 8),
}
_formats_rtkey = {
RTAUDIO_SINT8: ('8-bit integers', 1),
RTAUDIO_SINT16: ('16-bit integers',2),
RTAUDIO_SINT24: ('24-bit integers',3),
RTAUDIO_SINT32: ('32-bit integers',4),
RTAUDIO_FLOAT32: ('32-bit floats', 4),
RTAUDIO_FLOAT64: ('64-bit floats', 8),
}
cdef class _Stream:
cdef:
object pyCallback
RtAudioFormat format
unsigned int sampleSize
RtAudioFormat sampleformat
cppRtAudio.StreamParameters inputParams
cppRtAudio.StreamParameters outputParams
# 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 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.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:
print(e)
fromNPYToBuffer(npy_output, outputBuffer)
@ -236,6 +207,8 @@ cdef void errorCallback(RtAudioError.Type _type,const string& errortxt) nogil:
pass
cdef class RtAudio:
cdef:
cppRtAudio _rtaudio
@ -263,31 +236,26 @@ cdef class RtAudio:
Return device information of the current 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 = []
nf = devinfo.nativeFormats
for format_ in [ RTAUDIO_SINT8, RTAUDIO_SINT16, RTAUDIO_SINT24,
RTAUDIO_SINT32, RTAUDIO_FLOAT32, RTAUDIO_FLOAT64]:
if nf & format_:
sampleformats.append(SampleFormat(format_))
pydevinfo['sampleformats'] = sampleformats
return pydevinfo
sampleformats.append(_formats_rtkey[format_][0])
return DeviceInfo(
index = device,
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,
object inputParams,
SampleFormat format,
str sampleformat,
unsigned int sampleRate,
unsigned int bufferFrames,
object pyCallback,
@ -342,7 +310,7 @@ cdef class RtAudio:
self._stream.bufferFrames = bufferFrames
self._rtaudio.openStream(rtOutputParams_ptr,
rtInputParams_ptr,
format._format,
_formats_strkey[sampleformat][0],
sampleRate,
&self._stream.bufferFrames,
audioCallback,

View File

@ -7,7 +7,7 @@ import cv2 as cv
from .lasp_atomic import Atomic
from threading import Thread, Condition, Lock
import time
from .device import DAQDevice, roga_plugndaq
from .device import DAQConfiguration
import numpy as np
__all__ = ['AvType', 'AvStream']
@ -21,9 +21,16 @@ class AvType:
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.input_device = input_device
self.output_device = output_device
try:
daq = DAQDevice(daqconfig)
self.nchannels = len(daq.channels_en)

View File

@ -8,7 +8,7 @@ Common definitions used throughout the code.
"""
__all__ = ['P_REF', 'FreqWeighting', 'TimeWeighting', 'getTime',
'getFreq', 'lasp_shelve'
'getFreq', 'lasp_shelve',
'W_REF', 'U_REF', 'I_REF']
lasp_appdir = appdirs.user_data_dir('Lasp', 'ASCEE')
@ -23,12 +23,21 @@ if not os.path.exists(lasp_appdir):
class lasp_shelve:
refcount = 0
shelve = None
def __enter__(self):
self.shelve = shelve.open(os.path.join(lasp_appdir, 'config.shelve'))
return self.shelve
if lasp_shelve.shelve is None:
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):
self.shelve.close()
lasp_shelve.refcount -= 1
if lasp_shelve.refcount == 0:
lasp_shelve.shelve.close()
lasp_shelve.shelve = None