Moved stream data to a C struct
This commit is contained in:
parent
04c3631a72
commit
5516fe44ce
@ -31,7 +31,7 @@ JobQueue* JobQueue_alloc(const us max_msg);
|
||||
void JobQueue_free(JobQueue* jq);
|
||||
|
||||
/**
|
||||
* Pops a job from the queue. Waits indefinetely until some job is
|
||||
* Pops a job from the queue. Waits indefinitely until some job is
|
||||
* available.
|
||||
*
|
||||
* @param jq: JobQueue handle
|
||||
|
@ -4,7 +4,11 @@ cimport cython
|
||||
from .lasp_daqconfig import DeviceInfo
|
||||
from libcpp.string cimport string
|
||||
from libcpp.vector cimport vector
|
||||
from libc.stdlib cimport malloc, free
|
||||
from libc.string cimport memcpy
|
||||
from cpython.ref cimport PyObject,Py_INCREF, Py_DECREF
|
||||
|
||||
# cdef extern from "lasp_worker.h":
|
||||
|
||||
cdef extern from "RtAudio.h" nogil:
|
||||
ctypedef unsigned long RtAudioStreamStatus
|
||||
@ -123,18 +127,17 @@ def get_numpy_dtype_from_format_string(format_string):
|
||||
def get_sampwidth_from_format_string(format_string):
|
||||
return _formats_strkey[format_string][-2]
|
||||
|
||||
cdef class _Stream:
|
||||
cdef:
|
||||
object pyCallback
|
||||
unsigned int sampleSize
|
||||
RtAudioFormat sampleformat
|
||||
cppRtAudio.StreamParameters inputParams
|
||||
cppRtAudio.StreamParameters outputParams
|
||||
# These boolean values tell us whether the structs above here are
|
||||
# initialized and contain valid data
|
||||
bool hasInput
|
||||
bool hasOutput
|
||||
unsigned int bufferFrames
|
||||
ctypedef struct _Stream:
|
||||
PyObject* pyCallback
|
||||
RtAudioFormat sampleformat
|
||||
cppRtAudio.StreamParameters inputParams
|
||||
cppRtAudio.StreamParameters outputParams
|
||||
# These boolean values tell us whether the structs above here are
|
||||
# initialized and contain valid data
|
||||
bool hasInput
|
||||
bool hasOutput
|
||||
unsigned int bufferFrames
|
||||
|
||||
|
||||
|
||||
# It took me quite a long time to fully understand Cython's idiosyncrasies
|
||||
@ -154,6 +157,7 @@ cdef object fromBufferToNPYNoCopy(
|
||||
|
||||
return array
|
||||
|
||||
|
||||
cdef void fromNPYToBuffer(cnp.ndarray arr,
|
||||
void* buf):
|
||||
"""
|
||||
@ -177,14 +181,18 @@ cdef int audioCallback(void* outputbuffer,
|
||||
int rval = 0
|
||||
cnp.NPY_TYPES npy_format
|
||||
|
||||
|
||||
with gil:
|
||||
if status == RTAUDIO_INPUT_OVERFLOW:
|
||||
print('Input overflow.')
|
||||
return 0
|
||||
if status == RTAUDIO_OUTPUT_UNDERFLOW:
|
||||
elif status == RTAUDIO_OUTPUT_UNDERFLOW:
|
||||
print('Output underflow.')
|
||||
return 0
|
||||
stream = <_Stream>(userData)
|
||||
else:
|
||||
pass
|
||||
stream = <_Stream*>(userData)
|
||||
callback = <object> stream[0].pyCallback
|
||||
|
||||
# Obtain stream information
|
||||
npy_input = None
|
||||
@ -196,37 +204,40 @@ cdef int audioCallback(void* outputbuffer,
|
||||
npy_input = fromBufferToNPYNoCopy(
|
||||
npy_format,
|
||||
inputbuffer,
|
||||
stream.inputParams.nChannels,
|
||||
stream[0].inputParams.nChannels,
|
||||
nFrames)
|
||||
|
||||
except Exception as e:
|
||||
print('exception in cython callback: ', str(e))
|
||||
print('exception in cython callback for input: ', str(e))
|
||||
return 1
|
||||
|
||||
if stream.hasOutput:
|
||||
if stream[0].hasOutput:
|
||||
try:
|
||||
assert outputbuffer != NULL
|
||||
npy_format = _formats_rtkey[stream.sampleformat][2]
|
||||
npy_format = _formats_rtkey[stream[0].sampleformat][2]
|
||||
npy_output = fromBufferToNPYNoCopy(
|
||||
npy_format,
|
||||
outputbuffer,
|
||||
stream.outputParams.nChannels,
|
||||
stream[0].outputParams.nChannels,
|
||||
nFrames)
|
||||
|
||||
except Exception as e:
|
||||
print('exception in cython callback: ', str(e))
|
||||
print('exception in Cython callback for output: ', str(e))
|
||||
return 1
|
||||
try:
|
||||
rval = stream.pyCallback(npy_input,
|
||||
rval = callback(npy_input,
|
||||
npy_output,
|
||||
nFrames,
|
||||
streamTime)
|
||||
except Exception as e:
|
||||
print('Exception in Python callback: ', str(e))
|
||||
print('Exception in Cython callback: ', str(e))
|
||||
return 1
|
||||
|
||||
return rval
|
||||
|
||||
cdef void errorCallback(RtAudioError.Type _type,const string& errortxt) nogil:
|
||||
pass
|
||||
with gil:
|
||||
print('Error callback called: %s', errortxt)
|
||||
|
||||
|
||||
|
||||
@ -234,13 +245,13 @@ cdef void errorCallback(RtAudioError.Type _type,const string& errortxt) nogil:
|
||||
cdef class RtAudio:
|
||||
cdef:
|
||||
cppRtAudio _rtaudio
|
||||
_Stream _stream
|
||||
_Stream* _stream
|
||||
|
||||
def __cinit__(self):
|
||||
self._stream = None
|
||||
self._stream = NULL
|
||||
|
||||
def __dealloc__(self):
|
||||
if self._stream is not None:
|
||||
if self._stream is not NULL:
|
||||
print('Force closing stream')
|
||||
self._rtaudio.closeStream()
|
||||
|
||||
@ -302,7 +313,7 @@ cdef class RtAudio:
|
||||
|
||||
Returns: None
|
||||
"""
|
||||
if self._stream is not None:
|
||||
if self._stream is not NULL:
|
||||
raise RuntimeError('Stream is already opened.')
|
||||
|
||||
cdef cppRtAudio.StreamParameters *rtOutputParams_ptr = NULL
|
||||
@ -312,23 +323,29 @@ cdef class RtAudio:
|
||||
streamoptions.flags = RTAUDIO_HOG_DEVICE
|
||||
streamoptions.numberOfBuffers = 4
|
||||
|
||||
self._stream = _Stream()
|
||||
self._stream.pyCallback = pyCallback
|
||||
self._stream.sampleformat = _formats_strkey[sampleformat][0]
|
||||
self._stream = <_Stream*> malloc(sizeof(_Stream))
|
||||
self._stream.hasInput = False
|
||||
self._stream.hasInput = False
|
||||
if self._stream is NULL:
|
||||
raise MemoryError()
|
||||
|
||||
self._stream[0].pyCallback = <PyObject*> pyCallback
|
||||
Py_INCREF(pyCallback)
|
||||
self._stream[0].sampleformat = _formats_strkey[sampleformat][0]
|
||||
|
||||
if outputParams is not None:
|
||||
rtOutputParams_ptr = &self._stream.outputParams
|
||||
rtOutputParams_ptr.deviceId = outputParams['deviceid']
|
||||
rtOutputParams_ptr.nChannels = outputParams['nchannels']
|
||||
rtOutputParams_ptr.firstChannel = outputParams['firstchannel']
|
||||
self._stream.hasOutput = True
|
||||
self._stream[0].hasOutput = True
|
||||
|
||||
if inputParams is not None:
|
||||
rtInputParams_ptr = &self._stream.inputParams
|
||||
rtInputParams_ptr.deviceId = inputParams['deviceid']
|
||||
rtInputParams_ptr.nChannels = inputParams['nchannels']
|
||||
rtInputParams_ptr.firstChannel = inputParams['firstchannel']
|
||||
self._stream.hasInput = True
|
||||
self._stream[0].hasInput = True
|
||||
|
||||
try:
|
||||
self._stream.bufferFrames = bufferFrames
|
||||
@ -336,7 +353,7 @@ cdef class RtAudio:
|
||||
rtInputParams_ptr,
|
||||
_formats_strkey[sampleformat][0],
|
||||
sampleRate,
|
||||
&self._stream.bufferFrames,
|
||||
&self._stream[0].bufferFrames,
|
||||
audioCallback,
|
||||
<void*> self._stream,
|
||||
&streamoptions, # Stream options
|
||||
@ -344,7 +361,9 @@ cdef class RtAudio:
|
||||
)
|
||||
except Exception as e:
|
||||
print('Exception occured in stream opening: ', str(e))
|
||||
self._stream = None
|
||||
self._stream = NULL
|
||||
free(self._stream)
|
||||
Py_INCREF(pyCallback)
|
||||
raise
|
||||
|
||||
return self._stream.bufferFrames
|
||||
@ -353,19 +372,21 @@ cdef class RtAudio:
|
||||
self._rtaudio.startStream()
|
||||
|
||||
def stopStream(self):
|
||||
if not self._stream:
|
||||
if self._stream is NULL:
|
||||
raise RuntimeError('Stream is not opened')
|
||||
self._rtaudio.stopStream()
|
||||
|
||||
def closeStream(self):
|
||||
if not self._stream:
|
||||
if self._stream is NULL:
|
||||
raise RuntimeError('Stream is not opened')
|
||||
# Closing stream
|
||||
self._rtaudio.closeStream()
|
||||
self._stream = None
|
||||
Py_DECREF(<object> self._stream[0].pyCallback)
|
||||
free(self._stream)
|
||||
self._stream = NULL
|
||||
|
||||
def abortStream(self):
|
||||
if not self._stream:
|
||||
if self._stream is NULL:
|
||||
raise RuntimeError('Stream is not opened')
|
||||
self._rtaudio.abortStream()
|
||||
|
||||
|
@ -55,20 +55,25 @@ class AvStream:
|
||||
self.monitor_gen = daqconfig.monitor_gen
|
||||
|
||||
# Determine highest input channel number
|
||||
channelconfigs = daqconfig.en_input_channels
|
||||
channelconfigs = daqconfig.input_channel_configs
|
||||
firstchannel = daqconfig.firstEnabledInputChannelNumber()
|
||||
if firstchannel < 0:
|
||||
raise ValueError('No input channels enabled')
|
||||
|
||||
self.channel_names = []
|
||||
self.sensitivity = self.daqconfig.getSensitivities()
|
||||
self.sensitivity = self.daqconfig.getEnabledChannelSensitivities()
|
||||
|
||||
if daqconfig.monitor_gen:
|
||||
assert self.duplex_mode
|
||||
self.channel_names.append('Generated signal')
|
||||
self.sensitivity = np.concatenate([np.array([1.]),
|
||||
self.sensitivity])
|
||||
|
||||
|
||||
rtaudio_inputparams = None
|
||||
rtaudio_outputparams = None
|
||||
|
||||
self.nframes_per_block = 2048
|
||||
self.nframes_per_block = 512
|
||||
|
||||
if self.duplex_mode or avtype == AvType.audio_output:
|
||||
rtaudio_outputparams = {'deviceid': device.index,
|
||||
|
Loading…
x
Reference in New Issue
Block a user