From 7e0f9a30e700d63d2cfef456aeb488f433c80f40 Mon Sep 17 00:00:00 2001 From: "Andie.Phan" Date: Mon, 19 Sep 2022 16:37:54 -0700 Subject: [PATCH 1/2] audiostream example --- streamlitfront/examples/audiostream.py | 96 ++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 streamlitfront/examples/audiostream.py diff --git a/streamlitfront/examples/audiostream.py b/streamlitfront/examples/audiostream.py new file mode 100644 index 0000000..251860f --- /dev/null +++ b/streamlitfront/examples/audiostream.py @@ -0,0 +1,96 @@ +"""Render a stream""" +from collections import deque +from functools import partial + +import numpy as np +from audiostream2py import PyAudioSourceReader, PaStatusFlags + +import streamlit as st +from front import APP_KEY, RENDERING_KEY, ELEMENT_KEY, Crudifier, NAME_KEY +from front.elements import OutputBase +import matplotlib.pyplot as plt + +from streamlitfront import mk_app, binder as b +from streamlitfront.elements import SelectBox + + +if not b.mall(): + b.mall = dict( + input_device=PyAudioSourceReader.list_recording_devices(), source=None, + ) + +mall = b.mall() +crudifier = partial(Crudifier, mall=mall) + + +class AudioStreamInfo(OutputBase): + def render(self): + if self.output: + box = st.empty() + data = deque(maxlen=10) + for d in self.output: + timestamp, in_data, _, _, status_flags = d + arr = np.frombuffer(in_data, dtype='int16') + item = dict( + timestamp=timestamp, + wf=arr, + mean=np.mean(arr), + max=np.max(arr), + flag=str(PaStatusFlags(status_flags)), + ) + data.append(item) + wf_arr = ( + np.concatenate(tuple(i['wf'] for i in data)) + if len(data) > 1 + else arr + ) + with box.container(): + fig, ax = plt.subplots(figsize=(15, 5)) + st.markdown('## waveform') + ax.plot(wf_arr, label='wf') + st.pyplot(fig) + st.write(item) + + +@crudifier(output_store='source') +def audio_stream(input_device, rate=44100, width=2, channels=1): + source = PyAudioSourceReader( + rate=rate, + width=width, + channels=channels, + input_device=input_device, + frames_per_buffer=int(rate), + ) + if mall['source']: # DO THIS IN crudifier + try: + mall['source'].close() + mall['source'] = None + except Exception as e: + print(e) + source.open() + return source + + +if __name__ == '__main__': + app = mk_app( + [audio_stream], + config={ + APP_KEY: {'title': 'My Stream App'}, + RENDERING_KEY: { + 'audio_stream': { + NAME_KEY: 'Get Data Stream', + 'description': {'content': 'Configure soundcard for data stream'}, + 'execution': { + 'inputs': { + 'input_device': { + ELEMENT_KEY: SelectBox, + 'options': mall['input_device'], + } + }, + 'output': {ELEMENT_KEY: AudioStreamInfo}, + }, + }, + }, + }, + ) + app() From 710e84250b958f2a4149eddf1299ebc96e6e9dfd Mon Sep 17 00:00:00 2001 From: "Andie.Phan" Date: Mon, 26 Sep 2022 17:12:26 -0700 Subject: [PATCH 2/2] audiostream example with StreamBuffer --- streamlitfront/examples/audiostream.py | 76 +++++++++++++++++++------- 1 file changed, 55 insertions(+), 21 deletions(-) diff --git a/streamlitfront/examples/audiostream.py b/streamlitfront/examples/audiostream.py index 251860f..54b83a2 100644 --- a/streamlitfront/examples/audiostream.py +++ b/streamlitfront/examples/audiostream.py @@ -1,8 +1,10 @@ """Render a stream""" +import time from collections import deque from functools import partial import numpy as np +from stream2py import StreamBuffer from audiostream2py import PyAudioSourceReader, PaStatusFlags import streamlit as st @@ -23,51 +25,83 @@ crudifier = partial(Crudifier, mall=mall) +def window_gen(data_gen, window_size=10): + timestamp, in_data, _, _, status_flags = next(iter(data_gen), None) + arr = np.frombuffer(in_data, dtype='int16') + data = deque(maxlen=window_size) + wf_arr = np.ones(len(arr) * window_size) + item = dict( + timestamp=timestamp, + wf=arr, + mean=np.mean(arr), + max=np.max(arr), + flag=str(PaStatusFlags(status_flags)), + ) + yield wf_arr, item + for d in data_gen: + timestamp, in_data, _, _, status_flags = d + arr = np.frombuffer(in_data, dtype='int16') + item = dict( + timestamp=timestamp, + wf=arr, + mean=np.mean(arr), + max=np.max(arr), + flag=str(PaStatusFlags(status_flags)), + ) + data.append(item) + wf_arr = np.concatenate((wf_arr[len(arr) :], arr)) + yield wf_arr, item + + class AudioStreamInfo(OutputBase): def render(self): if self.output: box = st.empty() - data = deque(maxlen=10) - for d in self.output: - timestamp, in_data, _, _, status_flags = d - arr = np.frombuffer(in_data, dtype='int16') - item = dict( - timestamp=timestamp, - wf=arr, - mean=np.mean(arr), - max=np.max(arr), - flag=str(PaStatusFlags(status_flags)), - ) - data.append(item) - wf_arr = ( - np.concatenate(tuple(i['wf'] for i in data)) - if len(data) > 1 - else arr - ) + chart = st.line_chart([1]) + buffer_reader = self.output.mk_reader() + for wf_arr, item in window_gen(buffer_reader): + new_chart = st.line_chart(wf_arr, width=800, height=600) + chart.empty() + chart = new_chart + with box.container(): + st.write( + f'Render delay: {time.time() - item["timestamp"] / 1e6:.2f}s' + ) + + +class AudioStreamInfo1(OutputBase): + def render(self): + if self.output: + box = st.empty() + buffer_reader = self.output.mk_reader() + for wf_arr, item in window_gen(buffer_reader): with box.container(): fig, ax = plt.subplots(figsize=(15, 5)) st.markdown('## waveform') ax.plot(wf_arr, label='wf') st.pyplot(fig) st.write(item) + st.write(f'Render delay: {time.time()-item["timestamp"]/1e6:.2f}s') + plt.close(fig) @crudifier(output_store='source') def audio_stream(input_device, rate=44100, width=2, channels=1): - source = PyAudioSourceReader( + source_reader = PyAudioSourceReader( rate=rate, width=width, channels=channels, input_device=input_device, - frames_per_buffer=int(rate), + frames_per_buffer=int(rate / 5), ) + source = StreamBuffer(source_reader=source_reader, maxlen=100) # buffer if mall['source']: # DO THIS IN crudifier try: - mall['source'].close() + mall['source'].stop() mall['source'] = None except Exception as e: print(e) - source.open() + source.start() return source