Open omlins opened 2 years ago
PortAudioStreams are conceptually a steam of audio samples, so readbytes
doesn’t really fit the model. That said, it could be thought of as a lower-level function that fills up a raw byte array rather than a SampleBuf
, and it’s up to the caller to convert into samples of the appropriate type. Not sure how useful that is though. What’s your use case?
@ssfrr, thanks a lot for your reply. The use case is an offline, low-latency speech to command software and API (to be made public in a few days for open community development). Currently, an OS-specific recorder is used and the recording via byte stream read into the application. More precisely, the recorder process is simply run and output captured by doing stream = open(``$RECORDER_BACKEND $RECORDER_ARGS``)
. Then, this stream is read in a while loop
with readbytes!
as follows:
bytes_read = readbytes!(stream, audio_chunk);
The audio-chunk
is then passed to the speech recognition backend. The read operation which could be potentially reading chunks as small as 8 bytes per iteration (however rather 32-1024 - a parameter still to be optimized), needs to be done at maximal perfomance (avoiding, e.g., allocations) in order allow minimal latency between the completion of the reading of a command and its execution.
With the current implementation, this works beautifully (enabling to run a command as little as 5-50 ms after read-in is completed). However, the recording is not portable: this is what should be solved by using PortAudio instead.
@ssfrr : I understand your thoughts about readbytes!
. I think one can work with SamplBuf
s and extract the raw bytes when needed using reinterpret
. In the following is an example. Do you see any issue with that?
julia> using PortAudio, SampledSignals
julia> stream = PortAudioStream(1, 0; eltype=Int16, samplerate=44100.0, latency=0.001)
PortAudioStream{Int16}
Samplerate: 44100.0Hz
1 channel source: "default"
julia> buf = SampleBuf(zeros(eltype(stream), 8, nchannels(stream.source)), samplerate(stream))
8-frame, 1-channel SampleBuf{Int16, 2}
0.00018140589569160998s sampled at 44100.0Hz
▁▁▁▁▁▁▁▁
julia> read!(stream, buf)
8
julia> buf
8-frame, 1-channel SampleBuf{Int16, 2}
0.00018140589569160998s sampled at 44100.0Hz
▁█▁█▁█▁█
julia> buf_bytes = reinterpret(UInt8, buf.data)
16×1 reinterpret(UInt8, ::Matrix{Int16}):
0x00
0x00
0xc0
0xb8
0x00
0x00
0xa0
0xb9
0x00
0x00
0xa0
0xb9
0x00
0x00
0x90
0xb9
This would give basically the functionality of readbytes!
with one exception: readbytes!(stream, b)
reads at most nb=length(b)
bytes, while read!
of an PortAudioStream
reads always a fixed amount, rather than allowing to set a maximum.
That said, I am not sure if it would make sense to support the equivivalent functionality in read!
- meaning allowing to set a maxium of samples that are read at most?
Thanks a lot for looking into that!
The functions
read
andread!
being supported forPortAudioStream
, is adding support forreadbytes!
feasible?