Somewhere inbetween. Everything broken

This commit is contained in:
Anne de Jong 2019-12-08 14:19:10 +01:00
parent 59f82ae14c
commit a39d8300a1
10 changed files with 544 additions and 136 deletions

2
.gitignore vendored
View File

@ -1,5 +1,6 @@
*.a
*.pyc
lasp_rtaudio.cxx
dist
CMakeFiles
CMakeCache.txt
@ -23,6 +24,5 @@ LASP.egg-info
lasp_octave_fir.*
lasp/ui_*
resources_rc.py
lasp/device/lasp_daqdevice.c
.ropeproject
.spyproject

View File

@ -1,5 +1,5 @@
cmake_minimum_required (VERSION 3.0)
project(beamforming)
project(LASP)
# Whether we want to use blas yes or no
set(LASP_USE_BLAS TRUE)
@ -39,6 +39,7 @@ set(Python_ADDITIONAL_VERSIONS "3")
if(LASP_DEBUG)
set(TRACERNAME LASPTracer)
set(LASP_DEBUG_CYTHON=True)
set(CMAKE_BUILD_TYPE Debug)
message("Building debug code")
set(CMAKE_BUILD_TYPE Debug)
@ -46,8 +47,6 @@ if(LASP_DEBUG)
add_definitions(-DTRACERNAME=${TRACERNAME})
add_definitions(-DDEBUG)
add_definitions(-DTRACER=1)
set(CYTHON_VARIABLES "#cython: boundscheck=True")
# This will produce html files
set(CYTHON_ANNOTATE ON)
# Add the __FILENAME__ macro
@ -55,9 +54,9 @@ if(LASP_DEBUG)
else()
message("Building LASP for release")
set(CMAKE_BUILD_TYPE Release)
set(LASP_DEBUG_CYTHON=False)
set(CYTHON_ANNOTATE OFF)
set(CYTHON_NO_DOCSTRINGS ON)
set(CYTHON_VARIABLES "#cython: boundscheck=False,wraparound=False,embedsignature=False,emit_code_comments=False")
# Strip unnecessary symbols
# set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--gc-sections")
# set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--gc-sections")

View File

@ -1,6 +1,7 @@
configure_file(config.pxi.in config.pxi)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
set(CYTHON_EXECUTABLE "cython3")
include(UseCython)
find_package(Numpy REQUIRED )

View File

@ -1,68 +1,7 @@
import numpy as np
cimport numpy as np
from libcpp cimport bool
cimport numpy as cnp
DEF LASP_FLOAT = "@LASP_FLOAT@"
DEF LASP_DEBUG_CYTHON = "@LASP_DEBUG_CYTHON@"
IF LASP_FLOAT == "double":
ctypedef double d
ctypedef double complex c
NUMPY_FLOAT_TYPE = np.float64
NUMPY_COMPLEX_TYPE = np.complex128
CYTHON_NUMPY_FLOAT_t = np.NPY_FLOAT64
CYTHON_NUMPY_COMPLEX_t = np.NPY_COMPLEX128
ELSE:
ctypedef float d
ctypedef float complex c
NUMPY_FLOAT_TYPE = np.float32
NUMPY_COMPLEX_TYPE = np.complex64
CYTHON_NUMPY_FLOAT_t = np.NPY_FLOAT32
CYTHON_NUMPY_COMPLEX_t = np.NPY_COMPLEX64
ctypedef size_t us
cdef extern from "lasp_tracer.h":
void setTracerLevel(int)
void TRACE(int,const char*)
void fsTRACE(int)
void feTRACE(int)
void clearScreen()
cdef extern from "lasp_mat.h":
ctypedef struct dmat:
us n_cols
us n_rows
d* _data
bint _foreign_data
ctypedef struct cmat:
pass
ctypedef cmat vc
ctypedef dmat vd
dmat dmat_foreign_data(us n_rows,
us n_cols,
d* data,
bint own_data)
cmat cmat_foreign_data(us n_rows,
us n_cols,
c* data,
bint own_data)
cmat cmat_alloc(us n_rows,us n_cols)
dmat dmat_alloc(us n_rows,us n_cols)
vd vd_foreign(const us size,d* data)
void vd_free(vd*)
void dmat_free(dmat*)
void cmat_free(cmat*)
void cmat_copy(cmat* to,cmat* from_)
cdef extern from "numpy/arrayobject.h":
void PyArray_ENABLEFLAGS(np.ndarray arr, int flags)
cdef extern from "lasp_python.h":
object dmat_to_ndarray(dmat*,bint transfer_ownership)
from libcpp cimport bool

View File

@ -1,4 +1,13 @@
set_source_files_properties(lasp_daqdevice.c PROPERTIES COMPILE_FLAGS "${CMAKE_C_FLAGS} ${CYTHON_EXTRA_C_FLAGS}")
# set_source_files_properties(lasp_portaudio.c PROPERTIES COMPILE_FLAGS "${CMAKE_C_FLAGS} ${CYTHON_EXTRA_C_FLAGS}")
include_directories(/usr/include/rtaudio)
set_source_files_properties(lasp_rtaudio.pyx PROPERTIES CYTHON_IS_CXX TRUE)
set_source_files_properties(lasp_rtaudio.cxx PROPERTIES COMPILE_FLAGS
"${CMAKE_CXX_FLAGS} ${CYTHON_EXTRA_CXX_FLAGS}")
cython_add_module(lasp_daqdevice lasp_daqdevice.pyx)
# cython_add_module(lasp_portaudio lasp_portaudio.pyx) */
cython_add_module(lasp_rtaudio lasp_rtaudio.pyx)
# target_link_libraries(lasp_portaudio portaudio) */
target_link_libraries(lasp_rtaudio rtaudio)
target_link_libraries(lasp_daqdevice asound)

View File

@ -9,11 +9,12 @@ Data Acquistiion (DAQ) device descriptors, and the DAQ devices themselves
"""
from dataclasses import dataclass, field
from .lasp_daqdevice import query_devices, DeviceInfo
__all__ = ['DAQConfiguration', 'roga_plugndaq', 'umik',
'default_soundcard', 'configs',
'findDAQDevice']
@dataclass
class DAQInputChannel:
channel_enabled: bool
channel_name: str
sensitivity: float
@dataclass
class DAQConfiguration:
@ -21,11 +22,9 @@ class DAQConfiguration:
Initialize a device descriptor
Args:
name: Name of the device to appear to the user
cardname: ALSA name identifier
cardlongnamematch: Long name according to ALSA
device_name: ASCII name with which to open the device when connected
en_format: index in the list of sample formats
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.
en_input_channels: list of channel indices which are used to
@ -42,19 +41,13 @@ class DAQConfiguration:
"""
name: str
cardname: str
cardlongnamematch: str
device_name: str
en_format: int
input_device_name: bytes
output_device_name: bytes
en_bit_depth: int
en_input_rate: int
en_input_channels: list
input_sensitivity: list
input_gain_settings: list
en_input_gain_settings: list = field(default_factory=list)
en_output_rate: int = -1
en_output_channels: list = field(default_factory=list)
def match(self, device):
"""
@ -83,50 +76,12 @@ class DAQConfiguration:
return match
roga_plugndaq = DAQConfiguration(name='Roga-instruments Plug.n.DAQ USB',
cardname='USB Audio CODEC',
cardlongnamematch='Burr-Brown from TI USB'
' Audio CODEC',
device_name='iec958:CARD=CODEC,DEV=0',
en_format=0,
en_input_rate=2,
en_input_channels=[0],
input_sensitivity=[46.92e-3, 46.92e-3],
input_gain_settings=[-20, 0, 20],
en_input_gain_settings=[1, 1],
en_output_rate=1,
en_output_channels=[False, False]
)
umik = DAQConfiguration(name='UMIK-1',
cardname='Umik-1 Gain: 18dB',
cardlongnamematch='miniDSP Umik-1 Gain: 18dB',
device_name='iec958:CARD=U18dB,DEV=0',
en_format=0,
en_input_rate=0,
en_input_channels=[0],
input_sensitivity=[1., 1.],
input_gain_settings=[0., 0.],
en_input_gain_settings=[0, 0],
en_output_rate=0,
en_output_channels=[True, True]
)
default_soundcard = DAQConfiguration(name="Default device",
cardname=None,
cardlongnamematch=None,
device_name='default',
en_format=0,
en_input_rate=2,
en_input_channels=[0],
input_sensitivity=[1.0, 1.0],
input_gain_settings=[0],
en_input_gain_settings=[0, 0],
en_output_rate=1,
en_output_channels=[]
)
configs = (roga_plugndaq, default_soundcard)
@staticmethod
def emptyFromDeviceAndSettings(device):
return DAQConfiguration(
name = 'UNKNOWN'
input_device_name =
def findDAQDevice(config: DAQConfiguration) -> DeviceInfo:
"""

View File

@ -0,0 +1,389 @@
import sys
include "config.pxi"
cimport cython
from libcpp.string cimport string
from libcpp.vector cimport vector
from libc.string cimport memcpy
cdef extern from "RtAudio.h" nogil:
ctypedef unsigned long RtAudioStreamStatus
RtAudioStreamStatus RTAUDIO_INPUT_OVERFLOW
RtAudioStreamStatus RTAUDIO_OUTPUT_UNDERFLOW
cdef cppclass RtAudioError:
ctypedef enum Type:
WARNING
DEBUG_WARNING
UNSPECIFIED
NO_DEVICES_FOUND
INVALID_DEVICE
MEMORY_ERROR
INVALID_PARAMETER
INVALID_USE
DRIVER_ERROR
SYSTEM_ERROR
THREAD_ERROR
ctypedef unsigned long RtAudioStreamFlags
RtAudioStreamFlags RT_AUDIO_NONINTERLEAVED
RtAudioStreamFlags RTAUDIO_MINIMIZE_LATENCY
RtAudioStreamFlags RTAUDIO_HOG_DEVICE
RtAudioStreamFlags RTAUDIO_ALSA_USE_DEFAULT
RtAudioStreamFlags RTAUDIO_JACK_DONT_CONNECT
ctypedef unsigned long RtAudioFormat
RtAudioFormat RTAUDIO_SINT8
RtAudioFormat RTAUDIO_SINT16
RtAudioFormat RTAUDIO_SINT24
RtAudioFormat RTAUDIO_SINT32
RtAudioFormat RTAUDIO_FLOAT32
RtAudioFormat RTAUDIO_FLOAT64
ctypedef int (*RtAudioCallback)(void* outputBuffer,
void* inputBuffer,
unsigned int nFrames,
double streamTime,
RtAudioStreamStatus status,
void* userData)
ctypedef void (*RtAudioErrorCallback)(RtAudioError.Type _type,
const string& errortxt)
cdef cppclass cppRtAudio "RtAudio":
cppclass DeviceInfo:
bool probed
string name
unsigned int outputChannels
unsigned int inputChannels
unsigned int duplexChannels
bool isDefaultOutput
bool isDefaultInput
vector[unsigned int] sampleRates
unsigned int preferredSampleRate
RtAudioFormat nativeFormats
cppclass StreamOptions:
RtAudioStreamFlags flags
unsigned int numberOfBuffers
string streamName
int priority
cppclass StreamParameters:
unsigned int deviceId
unsigned int nChannels
unsigned int firstChannel
RtAudio() except +
# ~RtAudio() Destructors should not be listed
unsigned int getDeviceCount()
DeviceInfo getDeviceInfo(unsigned int device)
unsigned int getDefaultOutputDevice()
unsigned int getDefaultInputDevice()
void openStream(StreamParameters* outputParameters,
StreamParameters* intputParameters,
RtAudioFormat _format,
unsigned int sampleRate,
unsigned int* bufferFrames,
RtAudioCallback callback,
void* userData,
void* StreamOptions,
RtAudioErrorCallback) except +
void closeStream()
void startStream() except +
void stopStream() except +
void abortStream() except +
bool isStreamOpen()
bool isStreamRunning()
double getStreamTime()
void setStreamTime(double) except +
long getStreamLatency()
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)
cdef class _Stream:
cdef:
object pyCallback
RtAudioFormat format
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
# concerning C(++) callbacks, the GIL and passing Python objects as pointers
# into C(++) functions. But finally, here it is!
cdef object fromBufferToNPYNoCopy(buffer_format_type,
void* buf,
size_t nchannels,
size_t nframes):
cdef cnp.npy_intp[2] dims = [nchannels, nframes];
array = cnp.PyArray_SimpleNewFromData(2, dims, buffer_format_type,
buf)
return array
cdef void fromNPYToBuffer(cnp.ndarray arr,
void* buf):
"""
Copy a Python numpy array over to a buffer
No checks, just memcpy! Careful!
"""
memcpy(buf, arr.data, arr.size*arr.itemsize)
cdef int audioCallback(void* outputBuffer,
void* inputBuffer,
unsigned int nFrames,
double streamTime,
RtAudioStreamStatus status,
void* userData) nogil:
"""
Calls the Python callback function and converts data
"""
cdef int rval = 0
with gil:
if status == RTAUDIO_INPUT_OVERFLOW:
print('Input overflow.')
return 0
if status == RTAUDIO_OUTPUT_UNDERFLOW:
print('Output underflow.')
return 0
stream = <_Stream>(userData)
# Obtain stream information
npy_input = None
if stream.hasInput:
assert inputBuffer != NULL
# cdef
try:
npy_output, rval = stream.pyCallback(npy_input,
nFrames,
streamTime)
except Exception as e:
print('Exception in Python callback: ', str(e))
return 1
if stream.hasOutput:
if npy_output is None:
print('No output buffer given!')
return 1
IF LASP_DEBUG_CYTHON:
try:
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!"
except AssertionError as e:
print(e)
fromNPYToBuffer(npy_output, outputBuffer)
return rval
cdef void errorCallback(RtAudioError.Type _type,const string& errortxt) nogil:
pass
cdef class RtAudio:
cdef:
cppRtAudio _rtaudio
_Stream _stream
def __cinit__(self):
self._stream = None
def __dealloc__(self):
if self._stream is not None:
print('Force closing stream')
self._rtaudio.closeStream()
cpdef unsigned int getDeviceCount(self):
return self._rtaudio.getDeviceCount()
cpdef unsigned int getDefaultOutputDevice(self):
return self._rtaudio.getDefaultOutputDevice()
cpdef unsigned int getDefaultInputDevice(self):
return self._rtaudio.getDefaultInputDevice()
def getDeviceInfo(self, unsigned int device):
"""
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 = []
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
def openStream(self,object outputParams,
object inputParams,
SampleFormat format,
unsigned int sampleRate,
unsigned int bufferFrames,
object pyCallback,
object options = None,
object pyErrorCallback = None):
"""
Opening a stream with specified parameters
Args:
outputParams: dictionary of stream outputParameters, set to None
if no outputPararms are specified
inputParams: dictionary of stream inputParameters, set to None
if no inputPararms are specified
sampleRate: desired sample rate.
bufferFrames: the amount of frames in a callback buffer
callback: callback to call. Note: this callback is called on a
different thread!
options: A dictionary of optional additional stream options
errorCallback: client-defined function that will be invoked when an
error has occured.
Returns: None
"""
if self._stream is not None:
raise RuntimeError('Stream is already opened.')
cdef cppRtAudio.StreamParameters *rtOutputParams_ptr = NULL
cdef cppRtAudio.StreamParameters *rtInputParams_ptr = NULL
cdef cppRtAudio.StreamOptions streamoptions
streamoptions.flags = RTAUDIO_HOG_DEVICE
streamoptions.numberOfBuffers = 4
self._stream = _Stream()
self._stream.pyCallback = pyCallback
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
if inputParams is not None:
rtOutputParams_ptr = &self._stream.inputParams
rtInputParams_ptr.deviceId = inputParams['deviceid']
rtInputParams_ptr.nChannels = inputParams['nchannels']
rtInputParams_ptr.firstChannel = inputParams['firstchannel']
self._stream.hasInput = True
try:
self._stream.bufferFrames = bufferFrames
self._rtaudio.openStream(rtOutputParams_ptr,
rtInputParams_ptr,
format._format,
sampleRate,
&self._stream.bufferFrames,
audioCallback,
<void*> self._stream,
&streamoptions, # Stream options
errorCallback # Error callback
)
except Exception as e:
print('Exception occured in stream opening: ', str(e))
self._stream = None
def startStream(self):
self._rtaudio.startStream()
def stopStream(self):
if not self._stream:
raise RuntimeError('Stream is not opened')
self._rtaudio.stopStream()
def closeStream(self):
if not self._stream:
raise RuntimeError('Stream is not opened')
# Closing stream
self._rtaudio.closeStream()
self._stream = None
def abortStream(self):
if not self._stream:
raise RuntimeError('Stream is not opened')
self._rtaudio.abortStream()
def isStreamOpen(self):
return self._rtaudio.isStreamOpen()
def isStreamRunning(self):
return self._rtaudio.isStreamRunning()
def getStreamTime(self):
return self._rtaudio.getStreamTime()
def setStreamTime(self, double time):
return self._rtaudio.setStreamTime(time)

View File

@ -2,14 +2,36 @@
# -*- coding: utf-8 -*-
import numpy as np
from .wrappers import Window as wWindow
import appdirs, os, shelve
"""
Common definitions used throughout the code.
"""
__all__ = ['P_REF', 'FreqWeighting', 'TimeWeighting', 'getTime', 'calfile',
'getFreq',
__all__ = ['P_REF', 'FreqWeighting', 'TimeWeighting', 'getTime',
'getFreq', 'lasp_shelve'
'W_REF', 'U_REF', 'I_REF']
lasp_appdir = appdirs.user_data_dir('Lasp', 'ASCEE')
if not os.path.exists(lasp_appdir):
try:
os.mkdir(lasp_appdir)
except:
print('Fatal error: could not create application directory')
exit(1)
class lasp_shelve:
def __enter__(self):
self.shelve = shelve.open(os.path.join(lasp_appdir, 'config.shelve'))
return self.shelve
def __exit__(self, type, value, traceback):
self.shelve.close()
# Reference sound pressure level
P_REF = 2e-5
@ -19,9 +41,6 @@ I_REF = 1e-12 # 1 picoWatt/ m^2
# Reference velocity for sound velocity level
U_REF = 5e-8
# Todo: fix This
calfile = None
class Window:
hann = (wWindow.hann, 'Hann')

View File

@ -2,6 +2,68 @@
This file contains the Cython wrapper functions to C implementations.
"""
include "config.pxi"
IF LASP_FLOAT == "double":
ctypedef double d
ctypedef double complex c
NUMPY_FLOAT_TYPE = np.float64
NUMPY_COMPLEX_TYPE = np.complex128
CYTHON_NUMPY_FLOAT_t = cnp.NPY_FLOAT64
CYTHON_NUMPY_COMPLEX_t = cnp.NPY_COMPLEX128
ELSE:
ctypedef float d
ctypedef float complex c
NUMPY_FLOAT_TYPE = np.float32
NUMPY_COMPLEX_TYPE = np.complex64
CYTHON_NUMPY_FLOAT_t = cnp.NPY_FLOAT32
CYTHON_NUMPY_COMPLEX_t = cnp.NPY_COMPLEX64
ctypedef size_t us
cdef extern from "lasp_tracer.h":
void setTracerLevel(int)
void TRACE(int,const char*)
void fsTRACE(int)
void feTRACE(int)
void clearScreen()
cdef extern from "lasp_mat.h":
ctypedef struct dmat:
us n_cols
us n_rows
d* _data
bint _foreign_data
ctypedef struct cmat:
pass
ctypedef cmat vc
ctypedef dmat vd
dmat dmat_foreign_data(us n_rows,
us n_cols,
d* data,
bint own_data)
cmat cmat_foreign_data(us n_rows,
us n_cols,
c* data,
bint own_data)
cmat cmat_alloc(us n_rows,us n_cols)
dmat dmat_alloc(us n_rows,us n_cols)
vd vd_foreign(const us size,d* data)
void vd_free(vd*)
void dmat_free(dmat*)
void cmat_free(cmat*)
void cmat_copy(cmat* to,cmat* from_)
cdef extern from "numpy/arrayobject.h":
void PyArray_ENABLEFLAGS(cnp.ndarray arr, int flags)
cdef extern from "lasp_python.h":
object dmat_to_ndarray(dmat*,bint transfer_ownership)
__all__ = ['AvPowerSpectra']

35
test/test_rtaudio.py Normal file
View File

@ -0,0 +1,35 @@
#!/usr/bin/python3
import numpy as np
from lasp_rtaudio import RtAudio, SampleFormat, Format_SINT32, Format_FLOAT64
import time
nframes = 0
samplerate = 48000
omg = 2*np.pi*1000
def mycallback(input_, nframes, streamtime):
t = np.linspace(streamtime, streamtime + nframes/samplerate,
nframes)[np.newaxis,:]
outp = 0.1*np.sin(omg*t)
return outp, 0
if __name__ == '__main__':
pa = RtAudio()
count = pa.getDeviceCount()
# dev = pa.getDeviceInfo(0)
for i in range(count):
dev = pa.getDeviceInfo(i)
print(dev)
outputparams = {'deviceid': 0, 'nchannels': 1, 'firstchannel': 0}
pa.openStream(outputparams, None , Format_FLOAT64,samplerate, 512, mycallback)
pa.startStream()
input()
pa.stopStream()
pa.closeStream()