mirror of
https://github.com/pschatzmann/arduino-audio-tools.git
synced 2024-09-21 10:27:27 +00:00
Introduce BaseStream class
This commit is contained in:
parent
cb5b33231f
commit
727985d94f
@ -1,40 +1,18 @@
|
|||||||
../examples/examples-basic-api/base-adc-a2dp -> rc=0
|
|
||||||
../examples/examples-basic-api/base-adc-average-mono-serial -> rc=0
|
../examples/examples-basic-api/base-adc-average-mono-serial -> rc=0
|
||||||
../examples/examples-basic-api/base-adc-measure -> rc=0
|
../examples/examples-basic-api/base-adc-measure -> rc=0
|
||||||
../examples/examples-basic-api/base-adc-serial -> rc=0
|
../examples/examples-basic-api/base-adc-serial -> rc=0
|
||||||
../examples/examples-basic-api/base-file_raw-serial -> rc=0
|
../examples/examples-basic-api/base-file_raw-serial -> rc=0
|
||||||
../examples/examples-basic-api/base-generator-a2dp -> rc=0
|
|
||||||
../examples/examples-basic-api/base-i2s-a2dp -> rc=0
|
|
||||||
../examples/examples-basic-api/base-player-a2dp -> rc=0
|
|
||||||
../examples/examples-basic-api/base-SynchronizedBufferRTOS -> rc=0
|
../examples/examples-basic-api/base-SynchronizedBufferRTOS -> rc=0
|
||||||
../examples/examples-player/player-callback-i2s -> rc=0
|
../examples/examples-player/player-callback-i2s -> rc=0
|
||||||
../examples/examples-player/player-littlefs-i2s -> rc=0
|
../examples/examples-player/player-littlefs-i2s -> rc=0
|
||||||
../examples/examples-player/player-sdfat-a2dp -> rc=0
|
|
||||||
../examples/examples-player/player-sdfat-analog -> rc=0
|
../examples/examples-player/player-sdfat-analog -> rc=0
|
||||||
../examples/examples-player/player-sdfat-ffti2s -> rc=0
|
../examples/examples-player/player-sdfat-ffti2s -> rc=0
|
||||||
../examples/examples-player/player-sdfat-i2s -> rc=0
|
../examples/examples-player/player-sdfat-i2s -> rc=0
|
||||||
../examples/examples-player/player-sd-i2s -> rc=0
|
../examples/examples-player/player-sd-i2s -> rc=0
|
||||||
../examples/examples-player/player-spiffs-i2s -> rc=0
|
../examples/examples-player/player-spiffs-i2s -> rc=0
|
||||||
../examples/examples-player/player-url-i2s -> rc=0
|
|
||||||
../examples/examples-player/player-url_icy-i2s -> rc=0
|
|
||||||
../examples/examples-player/player-url_subclass-i2s -> rc=0
|
|
||||||
../examples/examples-webserver/streams-effect-webserver_wav -> rc=0
|
|
||||||
../examples/examples-webserver/streams-flite-webserver_wav -> rc=1
|
|
||||||
../examples/examples-webserver/streams-generator-webserver_aac -> rc=0
|
|
||||||
../examples/examples-webserver/streams-generator-webserverex_wav -> rc=0
|
|
||||||
../examples/examples-webserver/streams-generator-webserverex_wav1 -> rc=0
|
|
||||||
../examples/examples-webserver/streams-generator-webserver_mp3 -> rc=0
|
|
||||||
../examples/examples-webserver/streams-generator-webserver_ogg -> rc=0
|
|
||||||
../examples/examples-webserver/streams-generator-webserver_wav -> rc=0
|
|
||||||
../examples/examples-webserver/streams-i2s-webserver_wav -> rc=0
|
|
||||||
../examples/examples-webserver/streams-sam-webserver_wav -> rc=0
|
|
||||||
../examples/examples-webserver/streams-tts-webserver_wav -> rc=0
|
|
||||||
../examples/examples-stream/streams-a2dp-serial -> rc=0
|
|
||||||
../examples/examples-stream/streams-adc-i2s -> rc=0
|
../examples/examples-stream/streams-adc-i2s -> rc=0
|
||||||
../examples/examples-stream/streams-adc-serial -> rc=0
|
../examples/examples-stream/streams-adc-serial -> rc=0
|
||||||
../examples/examples-stream/streams-adsr-i2s -> rc=0
|
../examples/examples-stream/streams-adsr-i2s -> rc=0
|
||||||
../examples/examples-stream/streams-eth_url_mp3_helix-i2s -> rc=1
|
|
||||||
../examples/examples-stream/streams-generator-a2dp -> rc=0
|
|
||||||
../examples/examples-stream/streams-generator-analog -> rc=0
|
../examples/examples-stream/streams-generator-analog -> rc=0
|
||||||
../examples/examples-stream/streams_generator_bin_serial -> rc=0
|
../examples/examples-stream/streams_generator_bin_serial -> rc=0
|
||||||
../examples/examples-stream/streams-generator-formatconverter-i2s -> rc=0
|
../examples/examples-stream/streams-generator-formatconverter-i2s -> rc=0
|
||||||
@ -46,11 +24,10 @@
|
|||||||
../examples/examples-stream/streams-generator-spdif -> rc=0
|
../examples/examples-stream/streams-generator-spdif -> rc=0
|
||||||
../examples/examples-stream/streams-generator-volume -> rc=0
|
../examples/examples-stream/streams-generator-volume -> rc=0
|
||||||
../examples/examples-stream/streams-generator-wm8960 -> rc=0
|
../examples/examples-stream/streams-generator-wm8960 -> rc=0
|
||||||
../examples/examples-stream/streams-i2s-a2dp -> rc=0
|
|
||||||
../examples/examples-stream/streams-i2s-filter-i2s -> rc=0
|
../examples/examples-stream/streams-i2s-filter-i2s -> rc=0
|
||||||
../examples/examples-stream/streams-i2s-i2s -> rc=0
|
../examples/examples-stream/streams-i2s-i2s -> rc=0
|
||||||
../examples/examples-stream/streams-i2s-i2s-2 -> rc=0
|
../examples/examples-stream/streams-i2s-i2s-2 -> rc=0
|
||||||
../examples/examples-stream/streams-i2s_pdm-serial -> rc=1
|
../examples/examples-stream/streams-i2s_pdm-serial -> rc=0
|
||||||
../examples/examples-stream/streams-i2s-serial -> rc=0
|
../examples/examples-stream/streams-i2s-serial -> rc=0
|
||||||
../examples/examples-stream/streams-i2s-serial_16bit -> rc=0
|
../examples/examples-stream/streams-i2s-serial_16bit -> rc=0
|
||||||
../examples/examples-stream/streams-i2s-tf -> rc=0
|
../examples/examples-stream/streams-i2s-tf -> rc=0
|
||||||
@ -67,35 +44,14 @@
|
|||||||
../examples/examples-stream/streams-sd_mp3-i2s -> rc=0
|
../examples/examples-stream/streams-sd_mp3-i2s -> rc=0
|
||||||
../examples/examples-stream/streams-sd_wav4-i2s -> rc=0
|
../examples/examples-stream/streams-sd_wav4-i2s -> rc=0
|
||||||
../examples/examples-stream/streams-tf-i2s -> rc=0
|
../examples/examples-stream/streams-tf-i2s -> rc=0
|
||||||
../examples/examples-stream/streams-url_aac-i2s -> rc=0
|
|
||||||
../examples/examples-stream/streams-url-file -> rc=0
|
|
||||||
../examples/examples-stream/streams-url_flac-i2s -> rc=0
|
|
||||||
../examples/examples-stream/streams-url-measuring -> rc=0
|
|
||||||
../examples/examples-stream/streams-url_mp3-analog -> rc=0
|
|
||||||
../examples/examples-stream/streams-url_mp3_helix-i2s -> rc=0
|
|
||||||
../examples/examples-stream/streams-url_mp3_helix-i2s_32bit -> rc=0
|
|
||||||
../examples/examples-stream/streams-url_mp3_mad-i2s -> rc=0
|
|
||||||
../examples/examples-stream/streams-url_mp3-metadata -> rc=0
|
|
||||||
../examples/examples-stream/streams-url_mp3-metadata2 -> rc=0
|
|
||||||
../examples/examples-stream/streams-url_mts-hex -> rc=1
|
|
||||||
../examples/examples-stream/streams-url_raw-i2s -> rc=0
|
|
||||||
../examples/examples-stream/streams-url_raw-serial -> rc=0
|
|
||||||
../examples/examples-stream/streams-url_vorbis_i2s -> rc=0
|
|
||||||
../examples/examples-audiokit/basic-a2dp-audiokit -> rc=0
|
|
||||||
../examples/examples-audiokit/basic-a2dp-eq-audiokit -> rc=0
|
|
||||||
../examples/examples-audiokit/basic-audiokit-a2dp -> rc=0
|
|
||||||
../examples/examples-audiokit/player-sd_a2dp-audiokit -> rc=0
|
|
||||||
../examples/examples-audiokit/player-sd-audiokit -> rc=0
|
../examples/examples-audiokit/player-sd-audiokit -> rc=0
|
||||||
../examples/examples-audiokit/player-sdfat-audiokit -> rc=0
|
../examples/examples-audiokit/player-sdfat-audiokit -> rc=0
|
||||||
../examples/examples-audiokit/player-sdmmc-audiokit -> rc=0
|
../examples/examples-audiokit/player-sdmmc-audiokit -> rc=0
|
||||||
../examples/examples-audiokit/player-url_icy-audiokit -> rc=0
|
|
||||||
../examples/examples-audiokit/README.md -> rc=1
|
../examples/examples-audiokit/README.md -> rc=1
|
||||||
../examples/examples-audiokit/stream-hls-audiokit -> rc=1
|
|
||||||
../examples/examples-audiokit/streams-a2dp-audiokit -> rc=0
|
|
||||||
../examples/examples-audiokit/streams-audiokit-audiokit -> rc=0
|
../examples/examples-audiokit/streams-audiokit-audiokit -> rc=0
|
||||||
../examples/examples-audiokit/streams-audiokit-effects-audiokit -> rc=0
|
../examples/examples-audiokit/streams-audiokit-effects-audiokit -> rc=0
|
||||||
../examples/examples-audiokit/streams-audiokit-fft -> rc=0
|
../examples/examples-audiokit/streams-audiokit-fft -> rc=0
|
||||||
../examples/examples-audiokit/streams-audiokit-fft-led -> rc=1
|
../examples/examples-audiokit/streams-audiokit-fft-led -> rc=0
|
||||||
../examples/examples-audiokit/streams-audiokit-filter-audiokit -> rc=0
|
../examples/examples-audiokit/streams-audiokit-filter-audiokit -> rc=0
|
||||||
../examples/examples-audiokit/streams-audiokit-multioutput -> rc=0
|
../examples/examples-audiokit/streams-audiokit-multioutput -> rc=0
|
||||||
../examples/examples-audiokit/streams-audiokit-multioutput-server -> rc=0
|
../examples/examples-audiokit/streams-audiokit-multioutput-server -> rc=0
|
||||||
@ -105,9 +61,6 @@
|
|||||||
../examples/examples-audiokit/streams-audiokit-sd_wav -> rc=0
|
../examples/examples-audiokit/streams-audiokit-sd_wav -> rc=0
|
||||||
../examples/examples-audiokit/streams-audiokit-serial -> rc=0
|
../examples/examples-audiokit/streams-audiokit-serial -> rc=0
|
||||||
../examples/examples-audiokit/streams-audiokit-tf -> rc=0
|
../examples/examples-audiokit/streams-audiokit-tf -> rc=0
|
||||||
../examples/examples-audiokit/streams-audiokit-webserver_aac -> rc=0
|
|
||||||
../examples/examples-audiokit/streams-audiokit-webserver_mp3 -> rc=1
|
|
||||||
../examples/examples-audiokit/streams-audiokit-webserver_wav -> rc=0
|
|
||||||
../examples/examples-audiokit/streams-file_loop-audiokit -> rc=0
|
../examples/examples-audiokit/streams-file_loop-audiokit -> rc=0
|
||||||
../examples/examples-audiokit/streams-generator-audiokit -> rc=0
|
../examples/examples-audiokit/streams-generator-audiokit -> rc=0
|
||||||
../examples/examples-audiokit/streams-generator_fromarray-audiokit -> rc=0
|
../examples/examples-audiokit/streams-generator_fromarray-audiokit -> rc=0
|
||||||
@ -116,23 +69,20 @@
|
|||||||
../examples/examples-audiokit/streams-generator_sinfromtable-audiokit -> rc=0
|
../examples/examples-audiokit/streams-generator_sinfromtable-audiokit -> rc=0
|
||||||
../examples/examples-audiokit/streams-memory_mp3-audiokit -> rc=0
|
../examples/examples-audiokit/streams-memory_mp3-audiokit -> rc=0
|
||||||
../examples/examples-audiokit/streams-memory_pcm-mixer-audiokit -> rc=0
|
../examples/examples-audiokit/streams-memory_pcm-mixer-audiokit -> rc=0
|
||||||
../examples/examples-audiokit/streams-pins-audiokit -> rc=1
|
../examples/examples-audiokit/streams-pins-audiokit -> rc=0
|
||||||
../examples/examples-audiokit/streams-sd-audiokit -> rc=0
|
../examples/examples-audiokit/streams-sd-audiokit -> rc=0
|
||||||
../examples/examples-audiokit/streams-sdmmc_wav-audiokit -> rc=0
|
../examples/examples-audiokit/streams-sdmmc_wav-audiokit -> rc=0
|
||||||
../examples/examples-audiokit/streams-synth-a2dp -> rc=1
|
|
||||||
../examples/examples-audiokit/streams-synth-audiokit -> rc=0
|
../examples/examples-audiokit/streams-synth-audiokit -> rc=0
|
||||||
../examples/examples-audiokit/streams-synthbasic1-audiokit -> rc=0
|
../examples/examples-audiokit/streams-synthbasic1-audiokit -> rc=0
|
||||||
../examples/examples-audiokit/streams-synthbasic2-audiokit -> rc=0
|
../examples/examples-audiokit/streams-synthbasic2-audiokit -> rc=0
|
||||||
../examples/examples-audiokit/streams-synthbasic3-audiokit -> rc=1
|
../examples/examples-audiokit/streams-synthbasic3-audiokit -> rc=1
|
||||||
../examples/examples-audiokit/streams-synthstk-audiokit -> rc=0
|
../examples/examples-audiokit/streams-synthstk-audiokit -> rc=0
|
||||||
../examples/examples-audiokit/streams-tf-audiokit -> rc=0
|
../examples/examples-audiokit/streams-tf-audiokit -> rc=0
|
||||||
../examples/examples-audiokit/streams-url_aac-audiokit -> rc=0
|
|
||||||
../examples/examples-audiokit/streams-url_mp3-audiokit -> rc=0
|
|
||||||
../examples/examples-tts/streams-azure_tts-i2s -> rc=0
|
../examples/examples-tts/streams-azure_tts-i2s -> rc=0
|
||||||
../examples/examples-tts/streams-espeak-audiokit -> rc=1
|
../examples/examples-tts/streams-espeak-audiokit -> rc=0
|
||||||
../examples/examples-tts/streams-espeak-i2s -> rc=1
|
../examples/examples-tts/streams-espeak-i2s -> rc=0
|
||||||
../examples/examples-tts/streams-flite-audiokit -> rc=1
|
../examples/examples-tts/streams-flite-audiokit -> rc=0
|
||||||
../examples/examples-tts/streams-flite-i2s -> rc=1
|
../examples/examples-tts/streams-flite-i2s -> rc=0
|
||||||
../examples/examples-tts/streams-google-audiokit -> rc=0
|
../examples/examples-tts/streams-google-audiokit -> rc=0
|
||||||
../examples/examples-tts/streams-sam-audiokit -> rc=0
|
../examples/examples-tts/streams-sam-audiokit -> rc=0
|
||||||
../examples/examples-tts/streams-sam-i2s -> rc=0
|
../examples/examples-tts/streams-sam-i2s -> rc=0
|
||||||
@ -185,6 +135,25 @@
|
|||||||
../examples/examples-dsp/examples-faust/streams-i2s-faust_copy-i2s -> rc=0
|
../examples/examples-dsp/examples-faust/streams-i2s-faust_copy-i2s -> rc=0
|
||||||
../examples/examples-dsp/examples-faust/streams-i2s-faust_guitarix-i2s -> rc=0
|
../examples/examples-dsp/examples-faust/streams-i2s-faust_guitarix-i2s -> rc=0
|
||||||
../examples/examples-dsp/examples-faust/streams-i2s-faust_pitchshift-i2s -> rc=0
|
../examples/examples-dsp/examples-faust/streams-i2s-faust_pitchshift-i2s -> rc=0
|
||||||
|
../examples/examples-communication/a2dp/base-adc-a2dp -> rc=0
|
||||||
|
../examples/examples-communication/a2dp/base-generator-a2dp -> rc=0
|
||||||
|
../examples/examples-communication/a2dp/base-i2s-a2dp -> rc=0
|
||||||
|
../examples/examples-communication/a2dp/base-player-a2dp -> rc=0
|
||||||
|
../examples/examples-communication/a2dp/basic-a2dp-audiokit -> rc=0
|
||||||
|
../examples/examples-communication/a2dp/basic-a2dp-eq-audiokit -> rc=0
|
||||||
|
../examples/examples-communication/a2dp/basic-a2dp-fft -> rc=0
|
||||||
|
../examples/examples-communication/a2dp/basic-a2dp-fft-led -> rc=0
|
||||||
|
../examples/examples-communication/a2dp/basic-a2dp-i2s -> rc=1
|
||||||
|
../examples/examples-communication/a2dp/basic-a2dp-mixer-i2s -> rc=0
|
||||||
|
../examples/examples-communication/a2dp/basic-a2dp-spdif -> rc=0
|
||||||
|
../examples/examples-communication/a2dp/basic-audiokit-a2dp -> rc=0
|
||||||
|
../examples/examples-communication/a2dp/player-sd_a2dp-audiokit -> rc=0
|
||||||
|
../examples/examples-communication/a2dp/player-sdfat-a2dp -> rc=0
|
||||||
|
../examples/examples-communication/a2dp/streams-a2dp-audiokit -> rc=0
|
||||||
|
../examples/examples-communication/a2dp/streams-a2dp-serial -> rc=0
|
||||||
|
../examples/examples-communication/a2dp/streams-generator-a2dp -> rc=0
|
||||||
|
../examples/examples-communication/a2dp/streams-i2s-a2dp -> rc=0
|
||||||
|
../examples/examples-communication/a2dp/streams-synth-a2dp -> rc=1
|
||||||
../examples/examples-communication/esp-now/codec/communication-codec-espnow-receive -> rc=0
|
../examples/examples-communication/esp-now/codec/communication-codec-espnow-receive -> rc=0
|
||||||
../examples/examples-communication/esp-now/codec/communication-codec-espnow-receive_measure -> rc=0
|
../examples/examples-communication/esp-now/codec/communication-codec-espnow-receive_measure -> rc=0
|
||||||
../examples/examples-communication/esp-now/codec/communication-codec-espnow-send -> rc=0
|
../examples/examples-communication/esp-now/codec/communication-codec-espnow-send -> rc=0
|
||||||
@ -197,11 +166,62 @@
|
|||||||
../examples/examples-communication/ip/communication-ip-receive -> rc=0
|
../examples/examples-communication/ip/communication-ip-receive -> rc=0
|
||||||
../examples/examples-communication/ip/communication-ip-receive_measure -> rc=0
|
../examples/examples-communication/ip/communication-ip-receive_measure -> rc=0
|
||||||
../examples/examples-communication/ip/communication-ip-send -> rc=0
|
../examples/examples-communication/ip/communication-ip-send -> rc=0
|
||||||
../examples/examples-communication/rtsp/communication-audiokit-rtsp -> rc=0
|
../examples/examples-communication/udp/communication-udp-receive -> rc=0
|
||||||
../examples/examples-communication/rtsp/communication-codec-rtsp -> rc=0
|
../examples/examples-communication/udp/communication-udp-send -> rc=0
|
||||||
../examples/examples-communication/rtsp/communication-generator-rtsp -> rc=0
|
../examples/examples-communication/vban/player-sdmmc-vban -> rc=0
|
||||||
|
../examples/examples-communication/vban/streams-audiokit-vban -> rc=0
|
||||||
|
../examples/examples-communication/vban/streams-generator-vban -> rc=0
|
||||||
|
../examples/examples-communication/vban/streams-vban-audiokit -> rc=0
|
||||||
|
../examples/examples-communication/rtsp/communication-audiokit-rtsp -> rc=1
|
||||||
|
../examples/examples-communication/rtsp/communication-codec-rtsp -> rc=1
|
||||||
|
../examples/examples-communication/rtsp/communication-generator-rtsp -> rc=1
|
||||||
../examples/examples-communication/rtsp/communication-rtsp-audiokit -> rc=0
|
../examples/examples-communication/rtsp/communication-rtsp-audiokit -> rc=0
|
||||||
../examples/examples-communication/rtsp/communication-rtsp-i2s -> rc=0
|
../examples/examples-communication/rtsp/communication-rtsp-i2s -> rc=0
|
||||||
|
../examples/examples-communication/serial/send-8bit-receive -> rc=0
|
||||||
|
../examples/examples-communication/serial/send-adpcm_framed-receive -> rc=1
|
||||||
|
../examples/examples-communication/serial/send-adpcm-receive -> rc=0
|
||||||
|
../examples/examples-communication/serial/send-receive -> rc=0
|
||||||
|
../examples/examples-communication/snapcast/snapclient-i2s -> rc=1
|
||||||
|
../examples/examples-communication/spi/spi-master -> rc=0
|
||||||
|
../examples/examples-communication/spi/spi-slave-esp32 -> rc=0
|
||||||
|
../examples/examples-communication/spi/spi-slave-rp2040 -> rc=1
|
||||||
|
../examples/examples-communication/http-client/player-url-i2s -> rc=0
|
||||||
|
../examples/examples-communication/http-client/player-url_icy-audiokit -> rc=0
|
||||||
|
../examples/examples-communication/http-client/player-url_icy-i2s -> rc=0
|
||||||
|
../examples/examples-communication/http-client/player-url_subclass-i2s -> rc=0
|
||||||
|
../examples/examples-communication/http-client/streams-eth_url_mp3_helix-i2s -> rc=1
|
||||||
|
../examples/examples-communication/http-client/streams-url_aac-audiokit -> rc=0
|
||||||
|
../examples/examples-communication/http-client/streams-url_aac-i2s -> rc=0
|
||||||
|
../examples/examples-communication/http-client/streams-url-file -> rc=0
|
||||||
|
../examples/examples-communication/http-client/streams-url_flac-i2s -> rc=0
|
||||||
|
../examples/examples-communication/http-client/streams-url-measuring -> rc=0
|
||||||
|
../examples/examples-communication/http-client/streams-url_mp3-analog -> rc=0
|
||||||
|
../examples/examples-communication/http-client/streams-url_mp3-audiokit -> rc=0
|
||||||
|
../examples/examples-communication/http-client/streams-url_mp3_helix-i2s -> rc=0
|
||||||
|
../examples/examples-communication/http-client/streams-url_mp3_helix-i2s_32bit -> rc=0
|
||||||
|
../examples/examples-communication/http-client/streams-url_mp3_mad-i2s -> rc=0
|
||||||
|
../examples/examples-communication/http-client/streams-url_mp3-metadata -> rc=0
|
||||||
|
../examples/examples-communication/http-client/streams-url_mp3-metadata2 -> rc=0
|
||||||
|
../examples/examples-communication/http-client/streams-url_mts-hex -> rc=1
|
||||||
|
../examples/examples-communication/http-client/streams-url_raw-i2s -> rc=0
|
||||||
|
../examples/examples-communication/http-client/streams-url_raw-serial -> rc=0
|
||||||
|
../examples/examples-communication/http-client/streams-url_vorbis_i2s -> rc=0
|
||||||
|
../examples/examples-communication/http-server/player-sd-webserverex_mp3 -> rc=0
|
||||||
|
../examples/examples-communication/http-server/README.md -> rc=1
|
||||||
|
../examples/examples-communication/http-server/streams-audiokit-webserver_aac -> rc=0
|
||||||
|
../examples/examples-communication/http-server/streams-audiokit-webserver_mp3 -> rc=0
|
||||||
|
../examples/examples-communication/http-server/streams-audiokit-webserver_wav -> rc=0
|
||||||
|
../examples/examples-communication/http-server/streams-effect-webserver_wav -> rc=0
|
||||||
|
../examples/examples-communication/http-server/streams-flite-webserver_wav -> rc=0
|
||||||
|
../examples/examples-communication/http-server/streams-generator-webserver_aac -> rc=0
|
||||||
|
../examples/examples-communication/http-server/streams-generator-webserverex_wav -> rc=0
|
||||||
|
../examples/examples-communication/http-server/streams-generator-webserverex_wav1 -> rc=0
|
||||||
|
../examples/examples-communication/http-server/streams-generator-webserver_mp3 -> rc=0
|
||||||
|
../examples/examples-communication/http-server/streams-generator-webserver_ogg -> rc=0
|
||||||
|
../examples/examples-communication/http-server/streams-generator-webserver_wav -> rc=0
|
||||||
|
../examples/examples-communication/http-server/streams-i2s-webserver_wav -> rc=0
|
||||||
|
../examples/examples-communication/http-server/streams-sam-webserver_wav -> rc=0
|
||||||
|
../examples/examples-communication/http-server/streams-tts-webserver_wav -> rc=0
|
||||||
../examples/tests/adc/read-csv -> rc=0
|
../examples/tests/adc/read-csv -> rc=0
|
||||||
../examples/tests/adc/read-csv_unsigned -> rc=0
|
../examples/tests/adc/read-csv_unsigned -> rc=0
|
||||||
../examples/tests/adc/read-speed -> rc=0
|
../examples/tests/adc/read-speed -> rc=0
|
||||||
@ -213,7 +233,7 @@
|
|||||||
../examples/tests/codecs/test-codec-adpcm-xq -> rc=0
|
../examples/tests/codecs/test-codec-adpcm-xq -> rc=0
|
||||||
../examples/tests/codecs/test-codec-aptx -> rc=0
|
../examples/tests/codecs/test-codec-aptx -> rc=0
|
||||||
../examples/tests/codecs/test-codec-base64 -> rc=0
|
../examples/tests/codecs/test-codec-base64 -> rc=0
|
||||||
../examples/tests/codecs/test-codec-codec2 -> rc=1
|
../examples/tests/codecs/test-codec-codec2 -> rc=0
|
||||||
../examples/tests/codecs/test-codec-flac -> rc=0
|
../examples/tests/codecs/test-codec-flac -> rc=0
|
||||||
../examples/tests/codecs/test-codec-g711_alaw -> rc=0
|
../examples/tests/codecs/test-codec-g711_alaw -> rc=0
|
||||||
../examples/tests/codecs/test-codec-g711_ulaw -> rc=0
|
../examples/tests/codecs/test-codec-g711_ulaw -> rc=0
|
||||||
@ -247,6 +267,9 @@
|
|||||||
../examples/tests/conversion/channel-converter-reduce-in -> rc=0
|
../examples/tests/conversion/channel-converter-reduce-in -> rc=0
|
||||||
../examples/tests/conversion/channel-converter-reduce-out -> rc=0
|
../examples/tests/conversion/channel-converter-reduce-out -> rc=0
|
||||||
../examples/tests/conversion/format-converter-in -> rc=0
|
../examples/tests/conversion/format-converter-in -> rc=0
|
||||||
|
../examples/tests/conversion/pipeline-in -> rc=0
|
||||||
|
../examples/tests/conversion/pipeline-out -> rc=0
|
||||||
|
../examples/tests/conversion/resample-mixer-in -> rc=0
|
||||||
../examples/tests/conversion/test-panning -> rc=0
|
../examples/tests/conversion/test-panning -> rc=0
|
||||||
../examples/tests/conversion/test-resample-in -> rc=0
|
../examples/tests/conversion/test-resample-in -> rc=0
|
||||||
../examples/tests/conversion/test-resample-out -> rc=0
|
../examples/tests/conversion/test-resample-out -> rc=0
|
||||||
@ -261,12 +284,12 @@
|
|||||||
../examples/tests/etc/test-mulit-compilation-units -> rc=0
|
../examples/tests/etc/test-mulit-compilation-units -> rc=0
|
||||||
../examples/tests/etc/test-pins -> rc=0
|
../examples/tests/etc/test-pins -> rc=0
|
||||||
../examples/tests/etc/test-ringbufferfile -> rc=0
|
../examples/tests/etc/test-ringbufferfile -> rc=0
|
||||||
../examples/tests/etc/test-tdm -> rc=1
|
../examples/tests/etc/test-tdm -> rc=0
|
||||||
../examples/tests/etc/test-write-memory -> rc=0
|
../examples/tests/etc/test-write-memory -> rc=0
|
||||||
../examples/tests/fft/fft-cmsis -> rc=1
|
../examples/tests/fft/fft-cmsis -> rc=1
|
||||||
../examples/tests/fft/fft-esp32 -> rc=1
|
../examples/tests/fft/fft-esp32 -> rc=0
|
||||||
../examples/tests/fft/fft-espressif -> rc=0
|
../examples/tests/fft/fft-espressif -> rc=0
|
||||||
../examples/tests/fft/fft-kiss -> rc=1
|
../examples/tests/fft/fft-kiss -> rc=0
|
||||||
../examples/tests/fft/fft-real -> rc=0
|
../examples/tests/fft/fft-real -> rc=0
|
||||||
../examples/tests/fft/fft-topn -> rc=0
|
../examples/tests/fft/fft-topn -> rc=0
|
||||||
../examples/tests/fft/fft-window -> rc=0
|
../examples/tests/fft/fft-window -> rc=0
|
||||||
|
@ -31,7 +31,6 @@ function compile_example {
|
|||||||
rm build-examples-log.txt
|
rm build-examples-log.txt
|
||||||
compile_example "esp32:esp32:esp32" "../examples/examples-basic-api/base*"
|
compile_example "esp32:esp32:esp32" "../examples/examples-basic-api/base*"
|
||||||
compile_example "esp32:esp32:esp32" "../examples/examples-player/player*"
|
compile_example "esp32:esp32:esp32" "../examples/examples-player/player*"
|
||||||
compile_example "esp32:esp32:esp32" "../examples/examples-webserver/str*"
|
|
||||||
compile_example "esp32:esp32:esp32" "../examples/examples-stream/streams*"
|
compile_example "esp32:esp32:esp32" "../examples/examples-stream/streams*"
|
||||||
compile_example "esp32:esp32:esp32" "../examples/examples-audiokit/*"
|
compile_example "esp32:esp32:esp32" "../examples/examples-audiokit/*"
|
||||||
compile_example "esp32:esp32:esp32" "../examples/examples-tts/streams*"
|
compile_example "esp32:esp32:esp32" "../examples/examples-tts/streams*"
|
||||||
@ -40,11 +39,19 @@ compile_example "esp32:esp32:esp32" "../examples/examples-dsp/examples-mozzi/*"
|
|||||||
compile_example "esp32:esp32:esp32" "../examples/examples-dsp/examples-pd/*"
|
compile_example "esp32:esp32:esp32" "../examples/examples-dsp/examples-pd/*"
|
||||||
compile_example "esp32:esp32:esp32" "../examples/examples-dsp/examples-stk/*"
|
compile_example "esp32:esp32:esp32" "../examples/examples-dsp/examples-stk/*"
|
||||||
compile_example "esp32:esp32:esp32" "../examples/examples-dsp/examples-faust/streams*"
|
compile_example "esp32:esp32:esp32" "../examples/examples-dsp/examples-faust/streams*"
|
||||||
|
compile_example "esp32:esp32:esp32" "../examples/examples-communication/a2dp/*"
|
||||||
compile_example "esp32:esp32:esp32" "../examples/examples-communication/esp-now/codec/*"
|
compile_example "esp32:esp32:esp32" "../examples/examples-communication/esp-now/codec/*"
|
||||||
compile_example "esp32:esp32:esp32" "../examples/examples-communication/esp-now/pcm/*"
|
compile_example "esp32:esp32:esp32" "../examples/examples-communication/esp-now/pcm/*"
|
||||||
compile_example "esp32:esp32:esp32" "../examples/examples-communication/esp-now/speed-test/*"
|
compile_example "esp32:esp32:esp32" "../examples/examples-communication/esp-now/speed-test/*"
|
||||||
compile_example "esp32:esp32:esp32" "../examples/examples-communication/ip/*"
|
compile_example "esp32:esp32:esp32" "../examples/examples-communication/ip/*"
|
||||||
|
compile_example "esp32:esp32:esp32" "../examples/examples-communication/udp/*"
|
||||||
|
compile_example "esp32:esp32:esp32" "../examples/examples-communication/vban/*"
|
||||||
compile_example "esp32:esp32:esp32" "../examples/examples-communication/rtsp/*"
|
compile_example "esp32:esp32:esp32" "../examples/examples-communication/rtsp/*"
|
||||||
|
compile_example "esp32:esp32:esp32" "../examples/examples-communication/serial/*"
|
||||||
|
compile_example "esp32:esp32:esp32" "../examples/examples-communication/snapcast/*"
|
||||||
|
compile_example "esp32:esp32:esp32" "../examples/examples-communication/spi/*"
|
||||||
|
compile_example "esp32:esp32:esp32" "../examples/examples-communication/http-client/*"
|
||||||
|
compile_example "esp32:esp32:esp32" "../examples/examples-communication/http-server/*"
|
||||||
compile_example "esp32:esp32:esp32" "../examples/tests/adc/*"
|
compile_example "esp32:esp32:esp32" "../examples/tests/adc/*"
|
||||||
compile_example "esp32:esp32:esp32" "../examples/tests/basic/*"
|
compile_example "esp32:esp32:esp32" "../examples/tests/basic/*"
|
||||||
compile_example "esp32:esp32:esp32" "../examples/tests/codecs/*"
|
compile_example "esp32:esp32:esp32" "../examples/tests/codecs/*"
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define USE_MIDI
|
#define USE_MIDI
|
||||||
#include "BluetoothA2DPSource.h"
|
#include "AudioTools.h" // must be first
|
||||||
#include "AudioTools.h"
|
#include "AudioLibs/AudioBoardStream.h" // https://github.com/pschatzmann/arduino-audio-driver
|
||||||
#include "AudioLibs/AudioBoardStream.h"
|
#include "BluetoothA2DPSource.h" // https://github.com/pschatzmann/ESP32-A2DP
|
||||||
|
|
||||||
BluetoothA2DPSource a2dp_source;
|
BluetoothA2DPSource a2dp_source;
|
||||||
|
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#define I2S_BUFFER_COUNT 8
|
|
||||||
#define I2S_BUFFER_SIZE 256
|
|
||||||
#define DEFAULT_BUFFER_SIZE 2048
|
|
@ -6,7 +6,6 @@
|
|||||||
* @copyright GPLv3
|
* @copyright GPLv3
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "AudioConfigLocal.h"
|
|
||||||
#include "AudioTools.h"
|
#include "AudioTools.h"
|
||||||
|
|
||||||
|
|
||||||
@ -15,7 +14,7 @@ AudioInfo info(44100, 2, 16);
|
|||||||
SineWaveGenerator<sound_t> sineWave(32000); // subclass of SoundGenerator with max amplitude of 32000
|
SineWaveGenerator<sound_t> sineWave(32000); // subclass of SoundGenerator with max amplitude of 32000
|
||||||
GeneratedSoundStream<sound_t> sound(sineWave); // Stream generated from sine wave
|
GeneratedSoundStream<sound_t> sound(sineWave); // Stream generated from sine wave
|
||||||
SPDIFOutput out;
|
SPDIFOutput out;
|
||||||
StreamCopy copier(out, sound); // copies sound into i2s
|
StreamCopy copier(out, sound, 2048); // copies sound into i2s
|
||||||
|
|
||||||
// Arduino Setup
|
// Arduino Setup
|
||||||
void setup(void) {
|
void setup(void) {
|
||||||
@ -28,6 +27,9 @@ void setup(void) {
|
|||||||
auto config = out.defaultConfig();
|
auto config = out.defaultConfig();
|
||||||
config.copyFrom(info);
|
config.copyFrom(info);
|
||||||
config.pin_data = 23;
|
config.pin_data = 23;
|
||||||
|
config.buffer_size = 384;
|
||||||
|
config.buffer_count = 8;
|
||||||
|
|
||||||
out.begin(config);
|
out.begin(config);
|
||||||
|
|
||||||
// Setup sine wave
|
// Setup sine wave
|
||||||
|
@ -25,9 +25,10 @@ void setup(){
|
|||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
AudioLogger::instance().begin(Serial, AudioLogger::Info);
|
AudioLogger::instance().begin(Serial, AudioLogger::Info);
|
||||||
|
|
||||||
|
analog.begin(analog.defaultConfig(TX_MODE));
|
||||||
|
|
||||||
// begin processing
|
// begin processing
|
||||||
auto cfg = out.defaultConfig();
|
out.begin();
|
||||||
out.begin(cfg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop(){
|
void loop(){
|
||||||
|
@ -568,6 +568,11 @@ class EncodedAudioStream : public ReformatBaseStream {
|
|||||||
enc_out.setOutput(&out);
|
enc_out.setOutput(&out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudioInfo defaultConfig() {
|
||||||
|
AudioInfo ai;
|
||||||
|
return ai;
|
||||||
|
}
|
||||||
|
|
||||||
bool begin(AudioInfo info) {
|
bool begin(AudioInfo info) {
|
||||||
setAudioInfo(info);
|
setAudioInfo(info);
|
||||||
return begin();
|
return begin();
|
||||||
@ -601,6 +606,9 @@ class EncodedAudioStream : public ReformatBaseStream {
|
|||||||
|
|
||||||
float getByteFactor() { return 1.0f; }
|
float getByteFactor() { return 1.0f; }
|
||||||
|
|
||||||
|
/// Defines the class specific custom log level
|
||||||
|
void setLogLevel(AudioLogger::LogLevel level) { enc_out.setLogLevel(level); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
EncodedAudioOutput enc_out;
|
EncodedAudioOutput enc_out;
|
||||||
|
|
||||||
|
@ -76,6 +76,7 @@ enum MTSStreamType {
|
|||||||
* @brief MPEG-TS (MTS) decoder. Extracts the AAC audio data from a MPEG-TS (MTS) data stream. You can
|
* @brief MPEG-TS (MTS) decoder. Extracts the AAC audio data from a MPEG-TS (MTS) data stream. You can
|
||||||
* define the relevant stream types via the API.
|
* define the relevant stream types via the API.
|
||||||
* The parsing logic was taken from: https://github.com/Yokohama-Miyazawa/M5HLSPlayer/blob/main/src/AudioGeneratorTS.cpp
|
* The parsing logic was taken from: https://github.com/Yokohama-Miyazawa/M5HLSPlayer/blob/main/src/AudioGeneratorTS.cpp
|
||||||
|
* Status: experimental!
|
||||||
* @ingroup codecs
|
* @ingroup codecs
|
||||||
* @ingroup decoder
|
* @ingroup decoder
|
||||||
* @author Phil Schatzmann
|
* @author Phil Schatzmann
|
||||||
@ -86,7 +87,7 @@ class MTSDecoder : public AudioDecoder {
|
|||||||
public:
|
public:
|
||||||
MTSDecoder() = default;
|
MTSDecoder() = default;
|
||||||
|
|
||||||
void begin() override {
|
bool begin() override {
|
||||||
TRACED();
|
TRACED();
|
||||||
|
|
||||||
// default supported stream types
|
// default supported stream types
|
||||||
@ -103,6 +104,7 @@ class MTSDecoder : public AudioDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
is_active = true;
|
is_active = true;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void end() override {
|
void end() override {
|
@ -431,7 +431,7 @@ public:
|
|||||||
|
|
||||||
// output values
|
// output values
|
||||||
T out_value = pitchShift(value);
|
T out_value = pitchShift(value);
|
||||||
LOGD("PitchShiftOutput %d -> %d", value, out_value);
|
LOGD("PitchShiftOutput %f -> %d", value, (int) out_value);
|
||||||
T out_array[channels];
|
T out_array[channels];
|
||||||
for (int ch = 0; ch < channels; ch++) {
|
for (int ch = 0; ch < channels; ch++) {
|
||||||
out_array[ch] = out_value;
|
out_array[ch] = out_value;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "AudioTools/AudioStreams.h"
|
#include "AudioTools/BaseStream.h"
|
||||||
#ifdef ARDUINO
|
#ifdef ARDUINO
|
||||||
# include "FS.h"
|
# include "FS.h"
|
||||||
# define READTYPE char
|
# define READTYPE char
|
||||||
@ -20,7 +20,7 @@ namespace audio_tools {
|
|||||||
* @author Phil Schatzmann
|
* @author Phil Schatzmann
|
||||||
* @copyright GPLv3
|
* @copyright GPLv3
|
||||||
*/
|
*/
|
||||||
template <class FileType> class FileLoopT : public AudioStream {
|
template <class FileType> class FileLoopT : public BaseStream {
|
||||||
public:
|
public:
|
||||||
FileLoopT() = default;
|
FileLoopT() = default;
|
||||||
FileLoopT(FileType file, int count = -1, int rewindPos = -1) {
|
FileLoopT(FileType file, int count = -1, int rewindPos = -1) {
|
||||||
@ -30,7 +30,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// restarts the file from the beginning
|
// restarts the file from the beginning
|
||||||
bool begin() override {
|
bool begin() {
|
||||||
TRACEI();
|
TRACEI();
|
||||||
// automatic determination of start pos
|
// automatic determination of start pos
|
||||||
if (start_pos <= 0){
|
if (start_pos <= 0){
|
||||||
@ -48,7 +48,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// closes the file
|
// closes the file
|
||||||
void end() override {
|
void end() {
|
||||||
TRACEI();
|
TRACEI();
|
||||||
current_file.close();
|
current_file.close();
|
||||||
}
|
}
|
||||||
@ -135,6 +135,8 @@ public:
|
|||||||
/// @return true as long as we are looping
|
/// @return true as long as we are looping
|
||||||
bool isLoopActive() { return loop_count > 0 || loop_count == -1; }
|
bool isLoopActive() { return loop_count > 0 || loop_count == -1; }
|
||||||
|
|
||||||
|
size_t write(const uint8_t* data, size_t len) { return current_file.write(data, len);}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int start_pos = -1;
|
int start_pos = -1;
|
||||||
int loop_count = -1;
|
int loop_count = -1;
|
||||||
|
@ -57,7 +57,7 @@ class PureDataStream : public AudioStream {
|
|||||||
out_channels = p_heavy->getNumOutputChannels();
|
out_channels = p_heavy->getNumOutputChannels();
|
||||||
if (out_channels > 0) buffer_read.resize(buffer_size);
|
if (out_channels > 0) buffer_read.resize(buffer_size);
|
||||||
if (in_channels > 0) buffer_write.resize(buffer_size);
|
if (in_channels > 0) buffer_write.resize(buffer_size);
|
||||||
if (audioInfo() != audioInfoIn()) {
|
if (audioInfo() != audioInfoOut()) {
|
||||||
LOGW("rate: %d, channels: in=%d, out=%d", sample_rate, in_channels,
|
LOGW("rate: %d, channels: in=%d, out=%d", sample_rate, in_channels,
|
||||||
out_channels);
|
out_channels);
|
||||||
} else {
|
} else {
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
* @copyright GPLv3
|
* @copyright GPLv3
|
||||||
*/
|
*/
|
||||||
namespace audio_tools {
|
namespace audio_tools {
|
||||||
class StdioStream : public AudioStream {
|
class StdioStream : public BaseStream {
|
||||||
public:
|
public:
|
||||||
AudioInfo defaultConfig() {
|
AudioInfo defaultConfig() {
|
||||||
AudioInfo def;
|
AudioInfo def;
|
||||||
@ -19,12 +19,7 @@ public:
|
|||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool begin(AudioInfo cfg) {
|
bool begin() {
|
||||||
info = cfg;
|
|
||||||
return begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool begin() override {
|
|
||||||
is_open = true;
|
is_open = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -46,13 +41,12 @@ public:
|
|||||||
return ::write(1, buffer, len);
|
return ::write(1, buffer, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void end() override {
|
void end() {
|
||||||
is_open = false;
|
is_open = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool is_open = false;
|
bool is_open = false;
|
||||||
FILE *out;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace audio_tools
|
} // namespace audio_tools
|
@ -127,7 +127,7 @@ class SPDIFOutput : public AudioStream {
|
|||||||
/// destructor
|
/// destructor
|
||||||
virtual ~SPDIFOutput() { end(); }
|
virtual ~SPDIFOutput() { end(); }
|
||||||
|
|
||||||
/// Starting with default settings
|
/// Starting with last or default settings
|
||||||
bool begin() { return begin(cfg); }
|
bool begin() { return begin(cfg); }
|
||||||
|
|
||||||
/// Start with the provided parameters
|
/// Start with the provided parameters
|
||||||
|
@ -6,28 +6,12 @@
|
|||||||
#include "AudioTools/AudioLogger.h"
|
#include "AudioTools/AudioLogger.h"
|
||||||
#include "AudioTools/BaseConverter.h"
|
#include "AudioTools/BaseConverter.h"
|
||||||
#include "AudioEffects/SoundGenerator.h"
|
#include "AudioEffects/SoundGenerator.h"
|
||||||
|
#include "AudioTools/BaseStream.h"
|
||||||
|
|
||||||
#ifndef IRAM_ATTR
|
#ifndef IRAM_ATTR
|
||||||
# define IRAM_ATTR
|
# define IRAM_ATTR
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_STREAM_WRITE_OVERRIDE
|
|
||||||
# define STREAM_WRITE_OVERRIDE override
|
|
||||||
#else
|
|
||||||
# define STREAM_WRITE_OVERRIDE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_STREAM_READ_OVERRIDE
|
|
||||||
# define STREAM_READ_OVERRIDE override
|
|
||||||
#else
|
|
||||||
# define STREAM_READ_OVERRIDE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_STREAM_READCHAR_OVERRIDE
|
|
||||||
# define STREAM_READCHAR_OVERRIDE override
|
|
||||||
#else
|
|
||||||
# define STREAM_READCHAR_OVERRIDE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace audio_tools {
|
namespace audio_tools {
|
||||||
|
|
||||||
@ -37,15 +21,12 @@ namespace audio_tools {
|
|||||||
* @author Phil Schatzmann
|
* @author Phil Schatzmann
|
||||||
* @copyright GPLv3
|
* @copyright GPLv3
|
||||||
*/
|
*/
|
||||||
class AudioStream : public Stream, public AudioInfoSupport, public AudioInfoSource {
|
class AudioStream : public BaseStream, public AudioInfoSupport, public AudioInfoSource {
|
||||||
public:
|
public:
|
||||||
AudioStream() = default;
|
AudioStream() = default;
|
||||||
virtual ~AudioStream() = default;
|
virtual ~AudioStream() = default;
|
||||||
AudioStream(AudioStream const&) = delete;
|
AudioStream(AudioStream const&) = delete;
|
||||||
AudioStream& operator=(AudioStream const&) = delete;
|
AudioStream& operator=(AudioStream const&) = delete;
|
||||||
|
|
||||||
virtual bool begin(){return true;}
|
|
||||||
virtual void end(){}
|
|
||||||
|
|
||||||
// Call from subclass or overwrite to do something useful
|
// Call from subclass or overwrite to do something useful
|
||||||
virtual void setAudioInfo(AudioInfo newInfo) override {
|
virtual void setAudioInfo(AudioInfo newInfo) override {
|
||||||
@ -64,34 +45,17 @@ class AudioStream : public Stream, public AudioInfoSupport, public AudioInfoSour
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual size_t readBytes(uint8_t *buffer, size_t length) STREAM_READ_OVERRIDE { return not_supported(0, "readBytes"); }
|
virtual size_t readBytes(uint8_t *buffer, size_t length) override { return not_supported(0, "readBytes"); }
|
||||||
|
|
||||||
virtual size_t write(const uint8_t *buffer, size_t size) override{ return not_supported(0,"write"); }
|
virtual size_t write(const uint8_t *buffer, size_t size) override{ return not_supported(0,"write"); }
|
||||||
|
|
||||||
virtual size_t write(uint8_t ch) override {
|
|
||||||
tmp_out.resize(MAX_SINGLE_CHARS);
|
|
||||||
if (tmp_out.isFull()){
|
|
||||||
flush();
|
|
||||||
}
|
|
||||||
return tmp_out.write(ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int available() override { return DEFAULT_BUFFER_SIZE; };
|
operator bool() { return info && available() > 0; }
|
||||||
|
|
||||||
|
|
||||||
operator bool() { return available() > 0; }
|
|
||||||
|
|
||||||
virtual AudioInfo audioInfo() override {
|
virtual AudioInfo audioInfo() override {
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int availableForWrite() override { return DEFAULT_BUFFER_SIZE; }
|
|
||||||
|
|
||||||
virtual void flush() override {
|
|
||||||
if (tmp_out.available()>0){
|
|
||||||
write((const uint8_t*)tmp_out.address(), tmp_out.available());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Writes len bytes of silence (=0).
|
/// Writes len bytes of silence (=0).
|
||||||
virtual void writeSilence(size_t len){
|
virtual void writeSilence(size_t len){
|
||||||
@ -107,52 +71,15 @@ class AudioStream : public Stream, public AudioInfoSupport, public AudioInfoSour
|
|||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Methods which should be suppressed in the documentation
|
|
||||||
#ifndef DOXYGEN
|
|
||||||
|
|
||||||
virtual size_t readBytes(char *buffer, size_t length) STREAM_READCHAR_OVERRIDE {
|
|
||||||
return readBytes((uint8_t *)buffer, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int read() override {
|
|
||||||
refillReadBuffer();
|
|
||||||
return tmp_in.read();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int peek() override {
|
|
||||||
refillReadBuffer();
|
|
||||||
return tmp_in.peek();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AudioInfo info;
|
AudioInfo info;
|
||||||
RingBuffer<uint8_t> tmp_in{0};
|
virtual int not_supported(int out, const char *msg = "") {
|
||||||
RingBuffer<uint8_t> tmp_out{0};
|
|
||||||
|
|
||||||
|
|
||||||
virtual int not_supported(int out, const char* msg="") {
|
|
||||||
LOGE("AudioStream: %s unsupported operation!", msg);
|
LOGE("AudioStream: %s unsupported operation!", msg);
|
||||||
// trigger stacktrace
|
// trigger stacktrace
|
||||||
assert(false);
|
assert(false);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void refillReadBuffer() {
|
|
||||||
tmp_in.resize(MAX_SINGLE_CHARS);
|
|
||||||
if (tmp_in.isEmpty()){
|
|
||||||
TRACED();
|
|
||||||
const int len = tmp_in.size();
|
|
||||||
uint8_t bytes[len];
|
|
||||||
int len_eff = readBytes(bytes, len);
|
|
||||||
//LOGD("tmp_in available: %d / size: %d / to be written %d", tmp_in.available(), tmp_in.size(), len_eff);
|
|
||||||
tmp_in.writeArray(bytes,len_eff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -240,7 +167,7 @@ class MemoryStream : public AudioStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Copy Constructor
|
/// Copy Constructor
|
||||||
MemoryStream(MemoryStream& source) {
|
MemoryStream(MemoryStream& source) : AudioStream() {
|
||||||
copy(source);
|
copy(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,200 +388,46 @@ class MemoryStream : public AudioStream {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief MemoryStream which is written and read using the internal RAM. For each write the data is allocated
|
* @brief An AudioStream backed by a Ringbuffer. We can write to the end and read from
|
||||||
* on the heap.
|
* the beginning of the stream
|
||||||
* @ingroup io
|
* @ingroup io
|
||||||
* @author Phil Schatzmann
|
* @author Phil Schatzmann
|
||||||
* @copyright GPLv3
|
* @copyright GPLv3
|
||||||
*/
|
*/
|
||||||
class DynamicMemoryStream : public AudioStream {
|
class RingBufferStream : public AudioStream {
|
||||||
public:
|
public:
|
||||||
struct DataNode {
|
RingBufferStream(int size = DEFAULT_BUFFER_SIZE) { resize(size); }
|
||||||
size_t len=0;
|
|
||||||
uint8_t* data=nullptr;
|
|
||||||
|
|
||||||
DataNode() = default;
|
virtual int available() override {
|
||||||
/// Constructor
|
// LOGD("RingBufferStream::available: %zu",buffer->available());
|
||||||
DataNode(void*inData, int len){
|
return buffer.available();
|
||||||
this->len = len;
|
|
||||||
this->data = (uint8_t*) malloc(len);
|
|
||||||
assert(this->data!=nullptr);
|
|
||||||
memcpy(this->data, inData, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
~DataNode(){
|
|
||||||
if (data!=nullptr) {
|
|
||||||
free(data);
|
|
||||||
data = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
DynamicMemoryStream() = default;
|
|
||||||
|
|
||||||
DynamicMemoryStream(bool isLoop, int defaultBufferSize=DEFAULT_BUFFER_SIZE ) {
|
|
||||||
this->default_buffer_size = defaultBufferSize;
|
|
||||||
is_loop = isLoop;
|
|
||||||
}
|
|
||||||
// Assign values from ref, clearing the original ref
|
|
||||||
void assign(DynamicMemoryStream &ref){
|
|
||||||
audio_list.swap(ref.audio_list);
|
|
||||||
it = ref.it;
|
|
||||||
total_available=ref.total_available;
|
|
||||||
default_buffer_size = ref.default_buffer_size;
|
|
||||||
alloc_failed = ref.alloc_failed;;
|
|
||||||
is_loop = ref.is_loop;
|
|
||||||
ref.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Intializes the processing
|
|
||||||
virtual bool begin() override {
|
|
||||||
clear();
|
|
||||||
temp_audio.resize(default_buffer_size);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void end() override {
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Automatically rewinds to the beginning when reaching the end
|
|
||||||
virtual void setLoop(bool loop){
|
|
||||||
is_loop = loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear() {
|
|
||||||
DataNode *p_node;
|
|
||||||
bool ok;
|
|
||||||
do{
|
|
||||||
ok = audio_list.pop_front(p_node);
|
|
||||||
if (ok){
|
|
||||||
delete p_node;
|
|
||||||
}
|
|
||||||
} while (ok);
|
|
||||||
|
|
||||||
temp_audio.reset();
|
|
||||||
total_available = 0;
|
|
||||||
alloc_failed = false;
|
|
||||||
rewind();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t size(){
|
|
||||||
return total_available;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the read position to the beginning
|
|
||||||
void rewind() {
|
|
||||||
it = audio_list.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual size_t write(const uint8_t *buffer, size_t size) override {
|
|
||||||
DataNode *p_node = new DataNode((void*)buffer, size);
|
|
||||||
if (p_node->data!=nullptr){
|
|
||||||
alloc_failed = false;
|
|
||||||
total_available += size;
|
|
||||||
audio_list.push_back(p_node);
|
|
||||||
|
|
||||||
// setup interator to point to first record
|
|
||||||
if (it == audio_list.end()){
|
|
||||||
it = audio_list.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
alloc_failed = true;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int availableForWrite() override {
|
virtual int availableForWrite() override {
|
||||||
return alloc_failed ? 0 : default_buffer_size;
|
return buffer.availableForWrite();
|
||||||
}
|
|
||||||
|
|
||||||
virtual int available() override {
|
|
||||||
if (it == audio_list.end()){
|
|
||||||
if (is_loop) rewind();
|
|
||||||
if (it == audio_list.end()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (*it)->len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual size_t readBytes(uint8_t *buffer, size_t length) override {
|
virtual void flush() override {}
|
||||||
// provide unprocessed data
|
virtual int peek() override { return buffer.peek(); }
|
||||||
if (temp_audio.available()>0){
|
virtual int read() override { return buffer.read(); }
|
||||||
return temp_audio.readArray(buffer, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We have no more data
|
virtual size_t readBytes(uint8_t *data, size_t length) override {
|
||||||
if (it==audio_list.end()){
|
return buffer.readArray(data, length);
|
||||||
if (is_loop){
|
|
||||||
rewind();
|
|
||||||
} else {
|
|
||||||
// stop the processing
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// provide data from next node
|
|
||||||
DataNode *p_node = *it;
|
|
||||||
int result_len = min(length, (size_t) p_node->len);
|
|
||||||
memcpy(buffer, p_node->data, result_len);
|
|
||||||
// save unprocessed data to temp buffer
|
|
||||||
if (p_node->len>length){
|
|
||||||
uint8_t *start = p_node->data+result_len;
|
|
||||||
int uprocessed_len = p_node->len - length;
|
|
||||||
temp_audio.writeArray(start, uprocessed_len);
|
|
||||||
}
|
|
||||||
//move to next pos
|
|
||||||
++it;
|
|
||||||
return result_len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<DataNode*> &list() {
|
virtual size_t write(const uint8_t *data, size_t len) override {
|
||||||
return audio_list;
|
// LOGD("RingBufferStream::write: %zu",len);
|
||||||
|
return buffer.writeArray(data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Post processing after the recording. We add a smooth transition at the beginning and at the end
|
virtual size_t write(uint8_t c) override { return buffer.write(c); }
|
||||||
/// @tparam T
|
|
||||||
/// @param factor
|
|
||||||
template<typename T>
|
|
||||||
void postProcessSmoothTransition(int channels, float factor = 0.01, int remove=0){
|
|
||||||
if (remove>0){
|
|
||||||
for (int j=0;j<remove;j++){
|
|
||||||
DataNode* node = nullptr;
|
|
||||||
audio_list.pop_front(node);
|
|
||||||
if (node!=nullptr) delete node;
|
|
||||||
node = nullptr;
|
|
||||||
audio_list.pop_back(node);
|
|
||||||
if (node!=nullptr) delete node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove popping noise
|
void resize(int size) { buffer.resize(size); }
|
||||||
SmoothTransition<T> clean_start(channels, true, false, factor);
|
|
||||||
auto first = *list().begin();
|
|
||||||
if (first!=nullptr){
|
|
||||||
clean_start.convert(first->data,first->len);
|
|
||||||
}
|
|
||||||
|
|
||||||
SmoothTransition<T> clean_end(channels, false, true, factor);
|
size_t size() { return buffer.size(); }
|
||||||
auto last = * (--(list().end()));
|
|
||||||
if (last!=nullptr){
|
|
||||||
clean_end.convert(last->data,last->len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
|
||||||
List<DataNode*> audio_list;
|
|
||||||
List<DataNode*>::Iterator it = audio_list.end();
|
|
||||||
size_t total_available=0;
|
|
||||||
int default_buffer_size=DEFAULT_BUFFER_SIZE;
|
|
||||||
bool alloc_failed = false;
|
|
||||||
RingBuffer<uint8_t> temp_audio{DEFAULT_BUFFER_SIZE};
|
|
||||||
bool is_loop = false;
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
RingBuffer<uint8_t> buffer{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -865,200 +638,6 @@ class BufferedStream : public ModifyingStream {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The Arduino Stream which provides silence and simulates a null device
|
|
||||||
* when used as audio target or audio source
|
|
||||||
* @ingroup io
|
|
||||||
* @author Phil Schatzmann
|
|
||||||
* @copyright GPLv3
|
|
||||||
*/
|
|
||||||
class NullStream : public AudioStream {
|
|
||||||
public:
|
|
||||||
|
|
||||||
bool begin(AudioInfo info) {
|
|
||||||
this->info = info;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioInfo defaultConfig() {
|
|
||||||
AudioInfo info;
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t write(const uint8_t *buffer, size_t len) override{
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t readBytes(uint8_t *buffer, size_t len) override{
|
|
||||||
memset(buffer,0, len);
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setAudioInfo(AudioInfo info) override {
|
|
||||||
this->info = info;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A Stream backed by a Ringbuffer. We can write to the end and read from
|
|
||||||
* the beginning of the stream
|
|
||||||
* @ingroup io
|
|
||||||
* @author Phil Schatzmann
|
|
||||||
* @copyright GPLv3
|
|
||||||
*/
|
|
||||||
class RingBufferStream : public AudioStream {
|
|
||||||
public:
|
|
||||||
RingBufferStream(int size = DEFAULT_BUFFER_SIZE) {
|
|
||||||
resize(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int available() override {
|
|
||||||
// LOGD("RingBufferStream::available: %zu",buffer->available());
|
|
||||||
return buffer.available();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int availableForWrite() override {
|
|
||||||
return buffer.availableForWrite();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void flush() override {}
|
|
||||||
virtual int peek() override { return buffer.peek(); }
|
|
||||||
virtual int read() override { return buffer.read(); }
|
|
||||||
|
|
||||||
virtual size_t readBytes(uint8_t *data, size_t length) override {
|
|
||||||
return buffer.readArray(data, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual size_t write(const uint8_t *data, size_t len) override {
|
|
||||||
// LOGD("RingBufferStream::write: %zu",len);
|
|
||||||
return buffer.writeArray(data, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual size_t write(uint8_t c) override { return buffer.write(c); }
|
|
||||||
|
|
||||||
void resize(int size){
|
|
||||||
buffer.resize(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t size() {
|
|
||||||
return buffer.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
|
||||||
RingBuffer<uint8_t> buffer{0};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief AudioStream class which stores the data in a temporary queue buffer.
|
|
||||||
* The queue can be consumed e.g. by a callback function by calling readBytes();
|
|
||||||
* @ingroup io
|
|
||||||
* @author Phil Schatzmann
|
|
||||||
* @copyright GPLv3
|
|
||||||
*/
|
|
||||||
template <class T>
|
|
||||||
class QueueStream : public AudioStream {
|
|
||||||
public:
|
|
||||||
/// Default constructor
|
|
||||||
QueueStream(int bufferSize, int bufferCount, bool autoRemoveOldestDataIfFull=false)
|
|
||||||
: AudioStream() {
|
|
||||||
owns_buffer = true;
|
|
||||||
callback_buffer_ptr = new NBuffer<T>(bufferSize, bufferCount);
|
|
||||||
remove_oldest_data = autoRemoveOldestDataIfFull;
|
|
||||||
}
|
|
||||||
/// Create stream from any BaseBuffer subclass
|
|
||||||
QueueStream(BaseBuffer<T> &buffer){
|
|
||||||
owns_buffer = false;
|
|
||||||
callback_buffer_ptr = &buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~QueueStream() {
|
|
||||||
if(owns_buffer) {
|
|
||||||
delete callback_buffer_ptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Activates the output
|
|
||||||
virtual bool begin() override {
|
|
||||||
TRACED();
|
|
||||||
active = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Activate only when filled buffer reached %
|
|
||||||
virtual bool begin(size_t activeWhenPercentFilled){
|
|
||||||
// determine total buffer size in bytes
|
|
||||||
size_t size = callback_buffer_ptr->size() * sizeof(T);
|
|
||||||
// calculate limit
|
|
||||||
active_limit = size * activeWhenPercentFilled / 100;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// stops the processing
|
|
||||||
virtual void end() override {
|
|
||||||
TRACED();
|
|
||||||
active = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
int available() override {
|
|
||||||
return active ? callback_buffer_ptr->available()*sizeof(T) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int availableForWrite() override {
|
|
||||||
return callback_buffer_ptr->availableForWrite()*sizeof(T);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual size_t write(const uint8_t *data, size_t len) override {
|
|
||||||
if (active_limit==0 && !active) return 0;
|
|
||||||
|
|
||||||
// activate automaticaly when limit has been reached
|
|
||||||
if (active_limit > 0 && !active && available() >= active_limit){
|
|
||||||
this->active = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// make space by deleting oldest entries
|
|
||||||
if (remove_oldest_data){
|
|
||||||
int available_bytes = callback_buffer_ptr->availableForWrite()*sizeof(T);
|
|
||||||
if ((int)len>available_bytes){
|
|
||||||
int gap = len-available_bytes;
|
|
||||||
uint8_t tmp[gap];
|
|
||||||
readBytes(tmp, gap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return callback_buffer_ptr->writeArray(data, len / sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual size_t readBytes(uint8_t *data, size_t len) override {
|
|
||||||
if (!active) return 0;
|
|
||||||
return callback_buffer_ptr->readArray(data, len / sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clears the data in the buffer
|
|
||||||
void clear() {
|
|
||||||
if (active){
|
|
||||||
callback_buffer_ptr->reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if active
|
|
||||||
operator bool(){
|
|
||||||
return active;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
BaseBuffer<T> *callback_buffer_ptr;
|
|
||||||
size_t active_limit = 0;
|
|
||||||
bool active;
|
|
||||||
bool remove_oldest_data;
|
|
||||||
bool owns_buffer;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// support legacy name
|
|
||||||
template <typename T>
|
|
||||||
using CallbackBufferedStream = QueueStream<T>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Both the data of the read or write
|
* @brief Both the data of the read or write
|
||||||
@ -1868,11 +1447,11 @@ class CallbackStream : public ModifyingStream {
|
|||||||
setAudioInfo(info);
|
setAudioInfo(info);
|
||||||
return begin();
|
return begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool begin() override {
|
virtual bool begin() override {
|
||||||
active = true;
|
active = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void end() override { active = false;}
|
void end() override { active = false;}
|
||||||
|
|
||||||
int available() override {
|
int available() override {
|
||||||
@ -1966,105 +1545,6 @@ class CallbackStream : public ModifyingStream {
|
|||||||
int available_bytes = -1;
|
int available_bytes = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Provides data from a concatenation of Streams. Please note that the provided
|
|
||||||
* Streams can be played only once! You will need to reset them (e.g. moving the file pointer to the beginning)
|
|
||||||
* and readd them back if you want to process them a second time. The default timeout on the available() method
|
|
||||||
* is set to 0. This might be not good if you use e.g. a URLStream.
|
|
||||||
* @ingroup io
|
|
||||||
* @author Phil Schatzmann
|
|
||||||
* @copyright GPLv3
|
|
||||||
*/
|
|
||||||
class CatStream : public AudioStream {
|
|
||||||
public:
|
|
||||||
CatStream(){
|
|
||||||
_timeout = 0;
|
|
||||||
}
|
|
||||||
void add(Stream *stream){
|
|
||||||
input_streams.push_back(stream);
|
|
||||||
}
|
|
||||||
void add(Stream &stream){
|
|
||||||
input_streams.push_back(&stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool begin() override {
|
|
||||||
is_active = true;
|
|
||||||
return AudioStream::begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
void end() override {
|
|
||||||
is_active = false;
|
|
||||||
return AudioStream::end();
|
|
||||||
}
|
|
||||||
|
|
||||||
int available() override {
|
|
||||||
if (!is_active) return 0;
|
|
||||||
if (!moveToNextStreamOnEnd()){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return availableWithTimout();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t readBytes(uint8_t* data, size_t len) override {
|
|
||||||
if (!is_active) return 0;
|
|
||||||
if (!moveToNextStreamOnEnd()){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return p_current_stream->readBytes(data, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if active and we still have data
|
|
||||||
operator bool(){
|
|
||||||
return is_active && available()>0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setOnBeginCallback(void (*callback)(Stream* stream) ){
|
|
||||||
begin_callback = callback;
|
|
||||||
}
|
|
||||||
void setOnEndCallback(void (*callback)(Stream* stream) ){
|
|
||||||
end_callback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Vector<Stream*> input_streams;
|
|
||||||
Stream *p_current_stream = nullptr;
|
|
||||||
bool is_active = false;
|
|
||||||
void (*begin_callback)(Stream* stream) = nullptr;
|
|
||||||
void (*end_callback)(Stream* stream) = nullptr;
|
|
||||||
|
|
||||||
/// moves to the next stream if necessary: returns true if we still have a valid stream
|
|
||||||
bool moveToNextStreamOnEnd(){
|
|
||||||
// keep on running
|
|
||||||
if (p_current_stream!=nullptr && p_current_stream->available()>0) return true;
|
|
||||||
// at end?
|
|
||||||
if ((p_current_stream==nullptr || availableWithTimout()==0)){
|
|
||||||
if (end_callback && p_current_stream) end_callback(p_current_stream);
|
|
||||||
if (!input_streams.empty()) {
|
|
||||||
LOGI("using next stream");
|
|
||||||
p_current_stream = input_streams[0];
|
|
||||||
input_streams.pop_front();
|
|
||||||
if (begin_callback && p_current_stream) begin_callback(p_current_stream);
|
|
||||||
} else {
|
|
||||||
p_current_stream = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// returns true if we have a valid stream
|
|
||||||
return p_current_stream!=nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int availableWithTimout(){
|
|
||||||
int result = p_current_stream->available();
|
|
||||||
if (result==0){
|
|
||||||
for (int j=0; j <_timeout/10;j++){
|
|
||||||
delay(10);
|
|
||||||
result = p_current_stream->available();
|
|
||||||
if (result!=0) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Stream to which we can apply Filters for each channel. The filter
|
* @brief Stream to which we can apply Filters for each channel. The filter
|
||||||
|
@ -595,6 +595,11 @@ struct AppropriateSumType<int32_t> {
|
|||||||
using type = int64_t;
|
using type = int64_t;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Provides reduced sampling rates through binning: typed implementation
|
||||||
|
* @ingroup convert
|
||||||
|
*/
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class BinT : public BaseConverter {
|
class BinT : public BaseConverter {
|
||||||
public:
|
public:
|
||||||
|
524
src/AudioTools/BaseStream.h
Normal file
524
src/AudioTools/BaseStream.h
Normal file
@ -0,0 +1,524 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "AudioTools/Buffers.h"
|
||||||
|
|
||||||
|
#ifdef ARDUINO
|
||||||
|
#include "Stream.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_STREAM_WRITE_OVERRIDE
|
||||||
|
#define STREAM_WRITE_OVERRIDE override
|
||||||
|
#else
|
||||||
|
#define STREAM_WRITE_OVERRIDE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_STREAM_READ_OVERRIDE
|
||||||
|
#define STREAM_READ_OVERRIDE override
|
||||||
|
#else
|
||||||
|
#define STREAM_READ_OVERRIDE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_STREAM_READCHAR_OVERRIDE
|
||||||
|
#define STREAM_READCHAR_OVERRIDE override
|
||||||
|
#else
|
||||||
|
#define STREAM_READCHAR_OVERRIDE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace audio_tools {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Base class for all Streams. It relies on write(const uint8_t *buffer,
|
||||||
|
* size_t size) and readBytes(uint8_t *buffer, size_t length).
|
||||||
|
* @author Phil Schatzmann
|
||||||
|
* @copyright GPLv3
|
||||||
|
*/
|
||||||
|
class BaseStream : public Stream {
|
||||||
|
public:
|
||||||
|
BaseStream() = default;
|
||||||
|
virtual ~BaseStream() = default;
|
||||||
|
BaseStream(BaseStream const &) = delete;
|
||||||
|
BaseStream &operator=(BaseStream const &) = delete;
|
||||||
|
|
||||||
|
virtual bool begin(){return true;}
|
||||||
|
virtual void end(){}
|
||||||
|
|
||||||
|
virtual size_t readBytes(uint8_t *buffer,
|
||||||
|
size_t length) STREAM_READ_OVERRIDE = 0;
|
||||||
|
virtual size_t write(const uint8_t *buffer, size_t size) override = 0;
|
||||||
|
|
||||||
|
virtual size_t write(uint8_t ch) override {
|
||||||
|
tmp_out.resize(MAX_SINGLE_CHARS);
|
||||||
|
if (tmp_out.isFull()) {
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
return tmp_out.write(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int available() override { return DEFAULT_BUFFER_SIZE; };
|
||||||
|
|
||||||
|
virtual int availableForWrite() override { return DEFAULT_BUFFER_SIZE; }
|
||||||
|
|
||||||
|
virtual void flush() override {
|
||||||
|
if (tmp_out.available() > 0) {
|
||||||
|
write((const uint8_t *)tmp_out.address(), tmp_out.available());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Methods which should be suppressed in the documentation
|
||||||
|
#ifndef DOXYGEN
|
||||||
|
|
||||||
|
virtual size_t readBytes(char *buffer,
|
||||||
|
size_t length) STREAM_READCHAR_OVERRIDE {
|
||||||
|
return readBytes((uint8_t *)buffer, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int read() override {
|
||||||
|
refillReadBuffer();
|
||||||
|
return tmp_in.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int peek() override {
|
||||||
|
refillReadBuffer();
|
||||||
|
return tmp_in.peek();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
RingBuffer<uint8_t> tmp_in{0};
|
||||||
|
RingBuffer<uint8_t> tmp_out{0};
|
||||||
|
|
||||||
|
void refillReadBuffer() {
|
||||||
|
tmp_in.resize(MAX_SINGLE_CHARS);
|
||||||
|
if (tmp_in.isEmpty()) {
|
||||||
|
TRACED();
|
||||||
|
const int len = tmp_in.size();
|
||||||
|
uint8_t bytes[len];
|
||||||
|
int len_eff = readBytes(bytes, len);
|
||||||
|
// LOGD("tmp_in available: %d / size: %d / to be written %d",
|
||||||
|
// tmp_in.available(), tmp_in.size(), len_eff);
|
||||||
|
tmp_in.writeArray(bytes, len_eff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Provides data from a concatenation of Streams. Please note that the
|
||||||
|
* provided Streams can be played only once! You will need to reset them (e.g.
|
||||||
|
* moving the file pointer to the beginning) and readd them back if you want to
|
||||||
|
* process them a second time. The default timeout on the available() method is
|
||||||
|
* set to 0. This might be not good if you use e.g. a URLStream.
|
||||||
|
* @ingroup io
|
||||||
|
* @author Phil Schatzmann
|
||||||
|
* @copyright GPLv3
|
||||||
|
*/
|
||||||
|
class CatStream : public BaseStream {
|
||||||
|
public:
|
||||||
|
CatStream() = default;
|
||||||
|
|
||||||
|
void add(Stream *stream) { input_streams.push_back(stream); }
|
||||||
|
void add(Stream &stream) { input_streams.push_back(&stream); }
|
||||||
|
|
||||||
|
bool begin() {
|
||||||
|
is_active = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void end() { is_active = false; }
|
||||||
|
|
||||||
|
int available() override {
|
||||||
|
if (!is_active) return 0;
|
||||||
|
if (!moveToNextStreamOnEnd()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return availableWithTimout();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t readBytes(uint8_t *data, size_t len) override {
|
||||||
|
if (!is_active) return 0;
|
||||||
|
if (!moveToNextStreamOnEnd()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return p_current_stream->readBytes(data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if active and we still have data
|
||||||
|
operator bool() { return is_active && available() > 0; }
|
||||||
|
|
||||||
|
void setOnBeginCallback(void (*callback)(Stream *stream)) {
|
||||||
|
begin_callback = callback;
|
||||||
|
}
|
||||||
|
void setOnEndCallback(void (*callback)(Stream *stream)) {
|
||||||
|
end_callback = callback;
|
||||||
|
}
|
||||||
|
void setTimeout(uint32_t t) { _timeout = t; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Vector<Stream *> input_streams;
|
||||||
|
Stream *p_current_stream = nullptr;
|
||||||
|
bool is_active = false;
|
||||||
|
void (*begin_callback)(Stream *stream) = nullptr;
|
||||||
|
void (*end_callback)(Stream *stream) = nullptr;
|
||||||
|
uint_fast32_t _timeout = 0;
|
||||||
|
|
||||||
|
/// moves to the next stream if necessary: returns true if we still have a
|
||||||
|
/// valid stream
|
||||||
|
bool moveToNextStreamOnEnd() {
|
||||||
|
// keep on running
|
||||||
|
if (p_current_stream != nullptr && p_current_stream->available() > 0)
|
||||||
|
return true;
|
||||||
|
// at end?
|
||||||
|
if ((p_current_stream == nullptr || availableWithTimout() == 0)) {
|
||||||
|
if (end_callback && p_current_stream) end_callback(p_current_stream);
|
||||||
|
if (!input_streams.empty()) {
|
||||||
|
LOGI("using next stream");
|
||||||
|
p_current_stream = input_streams[0];
|
||||||
|
input_streams.pop_front();
|
||||||
|
if (begin_callback && p_current_stream)
|
||||||
|
begin_callback(p_current_stream);
|
||||||
|
} else {
|
||||||
|
p_current_stream = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// returns true if we have a valid stream
|
||||||
|
return p_current_stream != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int availableWithTimout() {
|
||||||
|
int result = p_current_stream->available();
|
||||||
|
if (result == 0) {
|
||||||
|
for (int j = 0; j < _timeout / 10; j++) {
|
||||||
|
delay(10);
|
||||||
|
result = p_current_stream->available();
|
||||||
|
if (result != 0) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The Arduino Stream which provides silence and simulates a null device
|
||||||
|
* when used as audio target or audio source
|
||||||
|
* @ingroup io
|
||||||
|
* @author Phil Schatzmann
|
||||||
|
* @copyright GPLv3
|
||||||
|
*/
|
||||||
|
class NullStream : public BaseStream {
|
||||||
|
public:
|
||||||
|
size_t write(const uint8_t *buffer, size_t len) override { return len; }
|
||||||
|
|
||||||
|
size_t readBytes(uint8_t *buffer, size_t len) override {
|
||||||
|
memset(buffer, 0, len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stream class which stores the data in a temporary queue buffer.
|
||||||
|
* The queue can be consumed e.g. by a callback function by calling readBytes();
|
||||||
|
* @ingroup io
|
||||||
|
* @author Phil Schatzmann
|
||||||
|
* @copyright GPLv3
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
class QueueStream : public BaseStream {
|
||||||
|
public:
|
||||||
|
/// Default constructor
|
||||||
|
QueueStream(int bufferSize, int bufferCount,
|
||||||
|
bool autoRemoveOldestDataIfFull = false) {
|
||||||
|
owns_buffer = true;
|
||||||
|
callback_buffer_ptr = new NBuffer<T>(bufferSize, bufferCount);
|
||||||
|
remove_oldest_data = autoRemoveOldestDataIfFull;
|
||||||
|
}
|
||||||
|
/// Create stream from any BaseBuffer subclass
|
||||||
|
QueueStream(BaseBuffer<T> &buffer) {
|
||||||
|
owns_buffer = false;
|
||||||
|
callback_buffer_ptr = &buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~QueueStream() {
|
||||||
|
if (owns_buffer) {
|
||||||
|
delete callback_buffer_ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Activates the output
|
||||||
|
virtual bool begin() {
|
||||||
|
TRACED();
|
||||||
|
active = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Activate only when filled buffer reached %
|
||||||
|
virtual bool begin(size_t activeWhenPercentFilled) {
|
||||||
|
// determine total buffer size in bytes
|
||||||
|
size_t size = callback_buffer_ptr->size() * sizeof(T);
|
||||||
|
// calculate limit
|
||||||
|
active_limit = size * activeWhenPercentFilled / 100;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// stops the processing
|
||||||
|
virtual void end() {
|
||||||
|
TRACED();
|
||||||
|
active = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
int available() override {
|
||||||
|
return active ? callback_buffer_ptr->available() * sizeof(T) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int availableForWrite() override {
|
||||||
|
return callback_buffer_ptr->availableForWrite() * sizeof(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual size_t write(const uint8_t *data, size_t len) override {
|
||||||
|
if (active_limit == 0 && !active) return 0;
|
||||||
|
|
||||||
|
// activate automaticaly when limit has been reached
|
||||||
|
if (active_limit > 0 && !active && available() >= active_limit) {
|
||||||
|
this->active = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make space by deleting oldest entries
|
||||||
|
if (remove_oldest_data) {
|
||||||
|
int available_bytes =
|
||||||
|
callback_buffer_ptr->availableForWrite() * sizeof(T);
|
||||||
|
if ((int)len > available_bytes) {
|
||||||
|
int gap = len - available_bytes;
|
||||||
|
uint8_t tmp[gap];
|
||||||
|
readBytes(tmp, gap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return callback_buffer_ptr->writeArray(data, len / sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual size_t readBytes(uint8_t *data, size_t len) override {
|
||||||
|
if (!active) return 0;
|
||||||
|
return callback_buffer_ptr->readArray(data, len / sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears the data in the buffer
|
||||||
|
void clear() {
|
||||||
|
if (active) {
|
||||||
|
callback_buffer_ptr->reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if active
|
||||||
|
operator bool() { return active; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BaseBuffer<T> *callback_buffer_ptr;
|
||||||
|
size_t active_limit = 0;
|
||||||
|
bool active;
|
||||||
|
bool remove_oldest_data;
|
||||||
|
bool owns_buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
// support legacy name
|
||||||
|
template <typename T>
|
||||||
|
using CallbackBufferedStream = QueueStream<T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MemoryStream which is written and read using the internal RAM. For each write the data is allocated
|
||||||
|
* on the heap.
|
||||||
|
* @ingroup io
|
||||||
|
* @author Phil Schatzmann
|
||||||
|
* @copyright GPLv3
|
||||||
|
*/
|
||||||
|
class DynamicMemoryStream : public BaseStream {
|
||||||
|
public:
|
||||||
|
struct DataNode {
|
||||||
|
size_t len=0;
|
||||||
|
uint8_t* data=nullptr;
|
||||||
|
|
||||||
|
DataNode() = default;
|
||||||
|
/// Constructor
|
||||||
|
DataNode(void*inData, int len){
|
||||||
|
this->len = len;
|
||||||
|
this->data = (uint8_t*) malloc(len);
|
||||||
|
assert(this->data!=nullptr);
|
||||||
|
memcpy(this->data, inData, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
~DataNode(){
|
||||||
|
if (data!=nullptr) {
|
||||||
|
free(data);
|
||||||
|
data = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DynamicMemoryStream() = default;
|
||||||
|
|
||||||
|
DynamicMemoryStream(bool isLoop, int defaultBufferSize=DEFAULT_BUFFER_SIZE ) {
|
||||||
|
this->default_buffer_size = defaultBufferSize;
|
||||||
|
is_loop = isLoop;
|
||||||
|
}
|
||||||
|
// Assign values from ref, clearing the original ref
|
||||||
|
void assign(DynamicMemoryStream &ref){
|
||||||
|
audio_list.swap(ref.audio_list);
|
||||||
|
it = ref.it;
|
||||||
|
total_available=ref.total_available;
|
||||||
|
default_buffer_size = ref.default_buffer_size;
|
||||||
|
alloc_failed = ref.alloc_failed;;
|
||||||
|
is_loop = ref.is_loop;
|
||||||
|
ref.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Intializes the processing
|
||||||
|
virtual bool begin() {
|
||||||
|
clear();
|
||||||
|
temp_audio.resize(default_buffer_size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void end() {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Automatically rewinds to the beginning when reaching the end
|
||||||
|
virtual void setLoop(bool loop){
|
||||||
|
is_loop = loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
DataNode *p_node;
|
||||||
|
bool ok;
|
||||||
|
do{
|
||||||
|
ok = audio_list.pop_front(p_node);
|
||||||
|
if (ok){
|
||||||
|
delete p_node;
|
||||||
|
}
|
||||||
|
} while (ok);
|
||||||
|
|
||||||
|
temp_audio.reset();
|
||||||
|
total_available = 0;
|
||||||
|
alloc_failed = false;
|
||||||
|
rewind();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size(){
|
||||||
|
return total_available;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the read position to the beginning
|
||||||
|
void rewind() {
|
||||||
|
it = audio_list.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual size_t write(const uint8_t *buffer, size_t size) override {
|
||||||
|
DataNode *p_node = new DataNode((void*)buffer, size);
|
||||||
|
if (p_node->data!=nullptr){
|
||||||
|
alloc_failed = false;
|
||||||
|
total_available += size;
|
||||||
|
audio_list.push_back(p_node);
|
||||||
|
|
||||||
|
// setup interator to point to first record
|
||||||
|
if (it == audio_list.end()){
|
||||||
|
it = audio_list.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
alloc_failed = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int availableForWrite() override {
|
||||||
|
return alloc_failed ? 0 : default_buffer_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int available() override {
|
||||||
|
if (it == audio_list.end()){
|
||||||
|
if (is_loop) rewind();
|
||||||
|
if (it == audio_list.end()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (*it)->len;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual size_t readBytes(uint8_t *buffer, size_t length) override {
|
||||||
|
// provide unprocessed data
|
||||||
|
if (temp_audio.available()>0){
|
||||||
|
return temp_audio.readArray(buffer, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have no more data
|
||||||
|
if (it==audio_list.end()){
|
||||||
|
if (is_loop){
|
||||||
|
rewind();
|
||||||
|
} else {
|
||||||
|
// stop the processing
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// provide data from next node
|
||||||
|
DataNode *p_node = *it;
|
||||||
|
int result_len = min(length, (size_t) p_node->len);
|
||||||
|
memcpy(buffer, p_node->data, result_len);
|
||||||
|
// save unprocessed data to temp buffer
|
||||||
|
if (p_node->len>length){
|
||||||
|
uint8_t *start = p_node->data+result_len;
|
||||||
|
int uprocessed_len = p_node->len - length;
|
||||||
|
temp_audio.writeArray(start, uprocessed_len);
|
||||||
|
}
|
||||||
|
//move to next pos
|
||||||
|
++it;
|
||||||
|
return result_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<DataNode*> &list() {
|
||||||
|
return audio_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Post processing after the recording. We add a smooth transition at the beginning and at the end
|
||||||
|
/// @tparam T
|
||||||
|
/// @param factor
|
||||||
|
template<typename T>
|
||||||
|
void postProcessSmoothTransition(int channels, float factor = 0.01, int remove=0){
|
||||||
|
if (remove>0){
|
||||||
|
for (int j=0;j<remove;j++){
|
||||||
|
DataNode* node = nullptr;
|
||||||
|
audio_list.pop_front(node);
|
||||||
|
if (node!=nullptr) delete node;
|
||||||
|
node = nullptr;
|
||||||
|
audio_list.pop_back(node);
|
||||||
|
if (node!=nullptr) delete node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove popping noise
|
||||||
|
SmoothTransition<T> clean_start(channels, true, false, factor);
|
||||||
|
auto first = *list().begin();
|
||||||
|
if (first!=nullptr){
|
||||||
|
clean_start.convert(first->data,first->len);
|
||||||
|
}
|
||||||
|
|
||||||
|
SmoothTransition<T> clean_end(channels, false, true, factor);
|
||||||
|
auto last = * (--(list().end()));
|
||||||
|
if (last!=nullptr){
|
||||||
|
clean_end.convert(last->data,last->len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
List<DataNode*> audio_list;
|
||||||
|
List<DataNode*>::Iterator it = audio_list.end();
|
||||||
|
size_t total_available=0;
|
||||||
|
int default_buffer_size=DEFAULT_BUFFER_SIZE;
|
||||||
|
bool alloc_failed = false;
|
||||||
|
RingBuffer<uint8_t> temp_audio{DEFAULT_BUFFER_SIZE};
|
||||||
|
bool is_loop = false;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace audio_tools
|
@ -2,9 +2,9 @@
|
|||||||
#include <WiFiUdp.h>
|
#include <WiFiUdp.h>
|
||||||
#include <esp_now.h>
|
#include <esp_now.h>
|
||||||
|
|
||||||
#include "AudioTools/AudioStreams.h"
|
#include "AudioTools/BaseStream.h"
|
||||||
#include "AudioTools/Buffers.h"
|
|
||||||
#include "AudioBasic/Str.h"
|
#include "AudioBasic/Str.h"
|
||||||
|
#include "AudioTools/Buffers.h"
|
||||||
|
|
||||||
|
|
||||||
namespace audio_tools {
|
namespace audio_tools {
|
||||||
@ -70,7 +70,7 @@ struct ESPNowStreamConfig {
|
|||||||
* @author Phil Schatzmann
|
* @author Phil Schatzmann
|
||||||
* @copyright GPLv3
|
* @copyright GPLv3
|
||||||
*/
|
*/
|
||||||
class ESPNowStream : public AudioStream {
|
class ESPNowStream : public BaseStream {
|
||||||
public:
|
public:
|
||||||
ESPNowStream() { ESPNowStreamSelf = this; };
|
ESPNowStream() { ESPNowStreamSelf = this; };
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "AudioConfig.h"
|
#include "AudioConfig.h"
|
||||||
#include "AudioTools/AudioStreams.h"
|
#include "AudioTools/BaseStream.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -27,7 +27,7 @@ namespace audio_tools {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
template <int bytecount, class block_t>
|
template <int bytecount, class block_t>
|
||||||
class HammingFEC : public Stream {
|
class HammingFEC : public BaseStream {
|
||||||
public:
|
public:
|
||||||
HammingFEC(Stream &stream){
|
HammingFEC(Stream &stream){
|
||||||
p_stream = &stream;
|
p_stream = &stream;
|
||||||
@ -72,21 +72,6 @@ class HammingFEC : public Stream {
|
|||||||
return raw.readArray(data, len);
|
return raw.readArray(data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// To be avoided
|
|
||||||
size_t write(uint8_t c) override {
|
|
||||||
return write(&c, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// To be avoided
|
|
||||||
int read() override {
|
|
||||||
uint8_t ch;
|
|
||||||
size_t len = readBytes(&ch, 1);
|
|
||||||
return len == 1 ? ch : -1;
|
|
||||||
}
|
|
||||||
/// To be avoided
|
|
||||||
int peek() override {return -1;}
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SingleBuffer<uint8_t> raw{bytecount};
|
SingleBuffer<uint8_t> raw{bytecount};
|
||||||
SingleBuffer<uint8_t> encoded{encodedSize()};
|
SingleBuffer<uint8_t> encoded{encodedSize()};
|
||||||
|
73
src/Communication/RadioHeadStream.h
Normal file
73
src/Communication/RadioHeadStream.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "AudioTools/BaseStream.h"
|
||||||
|
#include "RHGenericDriver.h"
|
||||||
|
|
||||||
|
namespace audio_tools {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Arduino Stream which is using the RadioHead library to send and
|
||||||
|
* receive data. We use the river API directly.
|
||||||
|
* @ingroup communications
|
||||||
|
* @author Phil Schatzmann
|
||||||
|
* @copyright GPLv3
|
||||||
|
*/
|
||||||
|
class ReadioHeadStream : public Stream {
|
||||||
|
public:
|
||||||
|
ReadioHeadStream(RHGenericDriver &driver) { setDriver(driver); }
|
||||||
|
|
||||||
|
void setDriver(RHGenericDriver &driver) { p_driver = &driver; }
|
||||||
|
|
||||||
|
bool begin() {
|
||||||
|
if (p_driver == nullptr) return false;
|
||||||
|
p_driver->setMode(mode == RX_MODE ? RHGenericDriver::RHMode::RHModeRx
|
||||||
|
: RHGenericDriver::RHMode::RHModeTx);
|
||||||
|
return p_driver->init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void end() { p_driver->setMode(RHGenericDriver::RHMode::RHModeSleep); }
|
||||||
|
|
||||||
|
int available() override {
|
||||||
|
if (mode == TX_MODE) return 0;
|
||||||
|
return p_driver->available() ? p_driver->maxMessageLength() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t readBytes(uint8_t *data, size_t len) override {
|
||||||
|
if (mode == TX_MODE) return 0;
|
||||||
|
int open = len;
|
||||||
|
int processed = 0;
|
||||||
|
while (open > 0) {
|
||||||
|
uint8_t av = available();
|
||||||
|
if (av == 0) break;
|
||||||
|
p_driver->recv(data + processed, &av);
|
||||||
|
open -= av;
|
||||||
|
processed += av;
|
||||||
|
}
|
||||||
|
return processed;
|
||||||
|
}
|
||||||
|
|
||||||
|
int availableForWrite() override {
|
||||||
|
if (mode == RX_MODE) return 0;
|
||||||
|
return p_driver->maxMessageLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t write(const uint8_t *data, size_t len) override {
|
||||||
|
if (mode == RX_MODE) return 0;
|
||||||
|
int open = len;
|
||||||
|
int processed = 0;
|
||||||
|
while (open > 0) {
|
||||||
|
int av = available();
|
||||||
|
if (av == 0) break;
|
||||||
|
p_driver->send(data + processed, av);
|
||||||
|
open -= av;
|
||||||
|
processed += av;
|
||||||
|
}
|
||||||
|
return processed;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
RHGenericDriver *p_driver = nullptr;
|
||||||
|
RxTxMode mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace audio_tools
|
@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "AudioConfig.h"
|
#include "AudioConfig.h"
|
||||||
#include "AudioTools/AudioStreams.h"
|
#include "AudioTools/BaseStream.h"
|
||||||
#include "FEC/ReedSolomon/rs.hpp"
|
#include "FEC/ReedSolomon/rs.hpp"
|
||||||
|
|
||||||
namespace audio_tools {
|
namespace audio_tools {
|
||||||
@ -14,7 +14,7 @@ namespace audio_tools {
|
|||||||
* @copyright GPLv3
|
* @copyright GPLv3
|
||||||
**/
|
**/
|
||||||
template <int bytecount, int additional_bytes>
|
template <int bytecount, int additional_bytes>
|
||||||
class ReedSolomonFEC : public Stream {
|
class ReedSolomonFEC : public BaseStream {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ReedSolomonFEC(Stream &stream){
|
ReedSolomonFEC(Stream &stream){
|
||||||
@ -57,20 +57,6 @@ class ReedSolomonFEC : public Stream {
|
|||||||
return encoded.readArray(data, len);
|
return encoded.readArray(data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// To be avoided
|
|
||||||
size_t write(uint8_t c) override {
|
|
||||||
return write(&c, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// To be avoided
|
|
||||||
int read() override {
|
|
||||||
uint8_t ch;
|
|
||||||
size_t len = readBytes(&ch, 1);
|
|
||||||
return len == 1 ? ch : -1;
|
|
||||||
}
|
|
||||||
/// To be avoided
|
|
||||||
int peek() override {return -1;}
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SingleBuffer<uint8_t> raw{bytecount};
|
SingleBuffer<uint8_t> raw{bytecount};
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include <esp_now.h>
|
#include <esp_now.h>
|
||||||
|
|
||||||
#include "AudioBasic/Str.h"
|
#include "AudioBasic/Str.h"
|
||||||
#include "AudioTools/AudioStreams.h"
|
#include "AudioTools/BaseStream.h"
|
||||||
#include "AudioTools/Buffers.h"
|
#include "AudioTools/Buffers.h"
|
||||||
|
|
||||||
namespace audio_tools {
|
namespace audio_tools {
|
||||||
@ -18,7 +18,7 @@ namespace audio_tools {
|
|||||||
* @copyright GPLv3
|
* @copyright GPLv3
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class UDPStream : public Stream {
|
class UDPStream : public BaseStream {
|
||||||
public:
|
public:
|
||||||
/// Default Constructor
|
/// Default Constructor
|
||||||
UDPStream() = default;
|
UDPStream() = default;
|
||||||
@ -118,10 +118,6 @@ public:
|
|||||||
return bytes_read;
|
return bytes_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual size_t write(uint8_t) { return 0; }
|
|
||||||
virtual int read() { return -1; }
|
|
||||||
virtual int peek() { return -1; }
|
|
||||||
|
|
||||||
void setSSID(const char *ssid) { this->ssid = ssid; }
|
void setSSID(const char *ssid) { this->ssid = ssid; }
|
||||||
|
|
||||||
void setPassword(const char *pwd) { this->password = pwd; }
|
void setPassword(const char *pwd) { this->password = pwd; }
|
||||||
|
@ -78,9 +78,11 @@ class Task {
|
|||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ESP32
|
||||||
int getCoreID() {
|
int getCoreID() {
|
||||||
return xPortGetCoreID();
|
return xPortGetCoreID();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TaskHandle_t xHandle = nullptr;
|
TaskHandle_t xHandle = nullptr;
|
||||||
|
Loading…
Reference in New Issue
Block a user