diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
deleted file mode 100644
index 3fa32fb536..0000000000
--- a/.github/FUNDING.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-# These are supported funding model platforms
-
-github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
-patreon: # Replace with a single Patreon username
-open_collective: # Replace with a single Open Collective username
-ko_fi: # Replace with a single Ko-fi username
-tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
-community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
-liberapay: # Replace with a single Liberapay username
-issuehunt: # Replace with a single IssueHunt username
-lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
-polar: # Replace with a single Polar username
-buy_me_a_coffee: philschatzh
-custom: ['https://www.paypal.com/paypalme/pschatzmann?country.x=CH&locale.x=en_US']
diff --git a/.github/ISSUE_TEMPLATE/Issue-report.yml b/.github/ISSUE_TEMPLATE/Issue-report.yml
deleted file mode 100644
index 6f1ea95fc9..0000000000
--- a/.github/ISSUE_TEMPLATE/Issue-report.yml
+++ /dev/null
@@ -1,58 +0,0 @@
-name: Bug report
-description: Report only a bugs here!
-body:
- - type: markdown
- attributes:
- value: |
- * Before reporting a new bug please check and search the [list of existing issues](https://github.com/pschatzmann/arduino-audio-tools/issues?q=)
- * Please check [the Readme](https://github.com/pschatzmann/arduino-audio-tools) and [Wiki](https://github.com/pschatzmann/arduino-audio-tools/wiki)
- * Don't forget to check [the discusions](https://github.com/pschatzmann/arduino-audio-tools/discussions)
- * If still experiencing the issue, please provide as many details as possible below about your hardware, computer setup and code.
- - type: textarea
- id: Description
- attributes:
- label: Problem Description
- description: Please describe your problem here and expected behaviour
- placeholder: ex. Can't connect/weird behaviour/wrong function/missing parameter..
- validations:
- required: true
- - type: textarea
- id: Board
- attributes:
- label: Device Description
- description: What development board are you using
- placeholder: e.g. ESP32 Wroom, Desktop Build, RP2040
- validations:
- required: true
- - type: textarea
- id: sketch
- attributes:
- label: Sketch
- description: Please provide full minimal sketch/code which can be run to reproduce your issue
- placeholder: ex. Related part of the code to replicate the issue
- render: cpp
- validations:
- required: true
-
- - type: textarea
- id: other-remarks
- attributes:
- label: Other Steps to Reproduce
- description: Is there any other information you can think of which will help us reproduce this problem? Any additional info can be added as well.
- placeholder: ex. I also tried on other OS, HW...it works correctly on that setup.
-
- - type: textarea
- id: sceanario
- attributes:
- label: What is your development environment (incl. core version info)
- description: Please provide the information about your development/runtime environment
- placeholder: Arduino ESP 2.0.14, IDF 5.3.2, STM32-Cube MX, PlatformIO ESP32 6.10.0, JupyterLab, Desktop Build
-
- - type: checkboxes
- id: confirmation
- attributes:
- label: I have checked existing issues, discussions and online documentation
- description: You agree to check all the resources above before opening a new issue.
- options:
- - label: I confirm I have checked existing issues, discussions and online documentation
- required: true
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
deleted file mode 100644
index 3ba13e0cec..0000000000
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ /dev/null
@@ -1 +0,0 @@
-blank_issues_enabled: false
diff --git a/.gitignore b/.gitignore
index 76eef990ea..f151f16db9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,233 @@
-docs/html/
-build/
+#################
+## Eclipse
+#################
+
+*.pydevproject
+.project
+.metadata
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.classpath
+.settings/
+.loadpath
+debug.cfg
+debug_custom.json
+esp32*.svd
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# CDT-specific
+.cproject
+
+# PDT-specific
+.buildpath
+
+
+#################
+## Visual Studio
+#################
+
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.sln.docstates
.vscode/
-_deps/
+
+# Build results
+
+[Dd]ebug/
+[Rr]elease/
+x64/
+build/
+[Bb]in/
+[Oo]bj/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+*_i.c
+*_p.c
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.log
+*.scc
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opensdf
+*.sdf
+*.cachefile
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+*.ncrunch*
+.*crunch*.local.xml
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.Publish.xml
+*.pubxml
+
+# NuGet Packages Directory
+## TODO: If you have NuGet Package Restore enabled, uncomment the next line
+#packages/
+
+# Windows Azure Build Output
+csx
+*.build.csdef
+
+# Windows Store app package directory
+AppPackages/
+
+# Others
+sql/
+*.Cache
+ClientBin/
+[Ss]tyle[Cc]op.*
+~$*
+*~
+*.dbmdl
+*.[Pp]ublish.xml
+*.pfx
+*.publishsettings
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file to a newer
+# Visual Studio version. Backup files are not needed, because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+App_Data/*.mdf
+App_Data/*.ldf
+
+#############
+## Windows detritus
+#############
+
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Mac crap
+.DS_Store
+
+
+#############
+## Python
+#############
+
+*.py[co]
+
+# Packages
+*.egg
+*.egg-info
+dist/
+build/
+eggs/
+parts/
+var/
+sdist/
+develop-eggs/
+.installed.cfg
+
+# Installer logs
+pip-log.txt
+
+# Unit test / coverage reports
+.coverage
+.tox
+
+# Translations
+*.mo
+
+# Mr Developer
+.mr.developer.cfg
+
+# Doxygen
+.DS_Store
+/.vs
+
+# Jupyter
.ipynb_checkpoints/
-.DS_Store
\ No newline at end of file
+jupyter/*.wav
+.DS_Store
+
+# doxygen
+docs/html/
+
+debug.svd
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b3ed3f92ea..94f5c53b57 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,63 +1,49 @@
cmake_minimum_required(VERSION 3.16)
-if (DEFINED ESP_PLATFORM)
+# set the project name
+project(arduino-audio-tools)
- # idf component
- idf_component_register(
- # SRC_DIRS src
- INCLUDE_DIRS src
- REQUIRES bt esp_common freertos hal log nvs_flash driver esp_adc esp_http_client
- )
+set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0")
+set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0")
+add_compile_options(-Wno-deprecated-declarations)
- target_compile_options(${COMPONENT_LIB} INTERFACE -DESP32_CMAKE=1 -Wno-error -Wno-format -fpermissive)
+include(FetchContent)
-else()
+add_library(arduino-audio-tools INTERFACE)
- # set the project name
- project(arduino-audio-tools)
+option(BUILD_SHARED_LIBS "Build using shared libraries" OFF)
+option(ADD_PORTAUDIO "Add Portaudio Library" ON)
+option(ADD_ARDUINO_EMULATOR "Add Arduino Emulator Library" ON)
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0")
- set(FETCHCONTENT_UPDATES_DISCONNECTED ON)
- include(FetchContent)
+# make include directory available to calling projects
+target_include_directories (arduino-audio-tools INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/src)
- add_library(arduino-audio-tools INTERFACE)
-
- option(BUILD_SHARED_LIBS "Build using shared libraries" OFF)
- option(ADD_PORTAUDIO "Add Portaudio Library" OFF)
- option(ADD_ARDUINO_EMULATOR "Add Arduino Emulator Library" ON)
-
-
- # make include directory available to calling projects
- target_include_directories (arduino-audio-tools INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/src)
-
- # installation of all header files
- install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/" # source directory
- DESTINATION "include/arduino-audio-tools" # target directory
- FILES_MATCHING # install only matched files
- PATTERN "*.h" # select header files
- )
-
- if (ADD_PORTAUDIO)
- # Add Portaduio for desktop build
- FetchContent_Declare(portaudio GIT_REPOSITORY "https://github.com/PortAudio/portaudio.git" GIT_TAG v19.7.0 )
- FetchContent_GetProperties(portaudio)
- if(NOT portaudio_POPULATED)
- FetchContent_Populate(portaudio)
- add_subdirectory(${portaudio_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/portaudio)
- endif()
+# installation of all header files
+install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/" # source directory
+ DESTINATION "include/arduino-audio-tools" # target directory
+ FILES_MATCHING # install only matched files
+ PATTERN "*.h" # select header files
+)
+if (ADD_PORTAUDIO)
+ add_compile_options(-DIS_DESKTOP)
+ # Add Portaduio for desktop build
+ FetchContent_Declare(portaudio GIT_REPOSITORY "https://github.com/PortAudio/portaudio.git" GIT_TAG v19.7.0 )
+ FetchContent_GetProperties(portaudio)
+ if(NOT portaudio_POPULATED)
+ FetchContent_Populate(portaudio)
+ add_subdirectory(${portaudio_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/portaudio)
endif()
+endif()
- if (ADD_ARDUINO_EMULATOR)
- # Build with Linux Arduino Emulator
- FetchContent_Declare(arduino_emulator GIT_REPOSITORY "https://github.com/pschatzmann/Arduino-Emulator.git" GIT_TAG main )
- FetchContent_GetProperties(arduino_emulator)
- if(NOT arduino_emulator_POPULATED)
- FetchContent_Populate(arduino_emulator)
- add_subdirectory(${arduino_emulator_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/emulator)
- endif()
+if (ADD_ARDUINO_EMULATOR)
+ # Build with Linux Arduino Emulator
+ FetchContent_Declare(arduino_emulator GIT_REPOSITORY "https://github.com/pschatzmann/Arduino-Emulator.git" GIT_TAG main )
+ FetchContent_GetProperties(arduino_emulator)
+ if(NOT arduino_emulator_POPULATED)
+ FetchContent_Populate(arduino_emulator)
+ add_subdirectory(${arduino_emulator_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/emulator)
endif()
-
endif()
diff --git a/Doxyfile b/Doxyfile
index 5002c3d09b..30120e20d9 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -953,7 +953,7 @@ RECURSIVE = YES
# Note that relative paths are relative to the directory from which doxygen is
# run.
-EXCLUDE = examples, tests, docs/html, docs/resources, src/Sandbox
+EXCLUDE = examples, tests, docs/html, docs/resources, src/Experiments
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
@@ -980,7 +980,7 @@ EXCLUDE_PATTERNS =
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories use the pattern */test/*
-EXCLUDE_SYMBOLS = audio_tools::IO16Bit, std::initializer_list
+EXCLUDE_SYMBOLS =
# The EXAMPLE_PATH tag can be used to specify one or more files or directories
# that contain example code fragments that are included (see the \include
@@ -2217,7 +2217,7 @@ INCLUDE_FILE_PATTERNS =
# recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-PREDEFINED = DOXYGEN IS_DESKTOP ESP32 ESP8266 ARDUINO_ARCH_MBED_RP2040 ARDUINO_ARCH_RP2040 USE_NANO33BLE ARDUINO_ARCH_MBED ARDUINO_ARCH_RENESAS __AVR__ STM32 ARDUINO_ARCH_SAMD USE_URL_ARDUINO USE_TIMER USE_ANALOG USE_I2S USE_PWM USE_AUDIO_SERVER USE_ANALOG_ARDUINO USE_CONCURRENCY IS_I2S_IMPLEMENTED USE_WIFI
+PREDEFINED = DOXYGEN IS_DESKTOP ESP32 ESP8266 ARDUINO_ARCH_MBED_RP2040 ARDUINO_ARCH_RP2040 __AVR__ STM32 ARDUINO_ARCH_SAMD USE_URL_ARDUINO USE_TIMER USE_I2S_ANALOG USE_I2S USE_PWM USE_AUDIO_SERVER
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The
diff --git a/README.md b/README.md
index e5bf7efe94..93689907f0 100644
--- a/README.md
+++ b/README.md
@@ -2,30 +2,72 @@
Some basic __header-only C++ classes__ that can be used for __Audio Processing__ provided as __Arduino and cmake C++ Library__:
-- We provide different ["Audio Sources" and "Audio Sinks"](https://github.com/pschatzmann/arduino-audio-tools/wiki/Audio-Sources-and-Sinks)
+- We provide different "Audio Sources" and "Audio Sinks" (see next section)
- Support for different [Encoders](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_audio_encoder.html) and [Decoders](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_audio_decoder.html) for MP3, AAC, WAV, FLAC, etc for [EncodedAudioStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_encoded_audio_stream.html)
-- Integrates with different [DSP libraries](https://github.com/pschatzmann/arduino-audio-tools/wiki/DSP-Libraries)
-- Helps to [communicate](https://github.com/pschatzmann/arduino-audio-tools/wiki/Communication) audio over the wire or wirelessly
- Different [Sound Generators](https://pschatzmann.github.io/arduino-audio-tools/group__generator.html) (e.g. to generate a sine tone) for [GeneratedSoundStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_generated_sound_stream.html)
- Support for [Sound Effects](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_audio_effect_stream.html) with different [Effect Implementations](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_audio_effect.html) (e.g. Boost, Distortion, Echo, Reverb...) for [AudioEffectStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_audio_effect_stream_t.html)
-- Provides a [3 Band Equalizer](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_equalizer3_bands.html)
+- Different [Buffer Implementations](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_base_buffer.html) for [QueueStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_queue_stream.html)
- Different [Converters](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_base_converter.html) for [ConverterStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_converter_stream.html)
- Different [Filters](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_filter.html) for [FilteredStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_filtered_stream.html)
- [Musical Notes](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_musical_notes.html) (with frequencies of notes)
-- Different [Buffer Implementations](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_base_buffer.html) for [QueueStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_queue_stream.html)
- A [Repeating Timer](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_timer_alarm_repeating.html) (e.g. for sampling audio data using exact times) for [TimerCallbackAudioStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_timer_callback_audio_stream.html)
- Desktop Integration: Building of Arduino Audio Sketches to be run on [Linux, Windows and OS/X](https://github.com/pschatzmann/arduino-audio-tools/wiki/Running-an-Audio-Sketch-on-the-Desktop)
-This functionality provides the glue which makes different audio processing components and [libraries](https://github.com/pschatzmann/arduino-audio-tools/wiki/Optional-Libraries) work together.
-
-We also provide [plenty of examples](https://github.com/pschatzmann/arduino-audio-tools/wiki/Examples) that demonstrate how to implement the different scenarios. The __design philosophy__ is based on the Arduino conventions: we use the ```begin()``` and ```end()``` methods to start and stop the processing and we propagate the __use of Streams__.
-
-We all know the Arduino [Print](https://www.arduino.cc/reference/en/language/functions/communication/print/) and [Stream](https://www.arduino.cc/reference/en/language/functions/communication/stream) classes: We usually use them to write out print messages and sometimes we use them to read the output from Serial, Files, Ethernet, etc. The same thing applies to “Audio Streams”: You can read audio data from [“Audio Sources” and you write them to “Audio Sinks”](https://github.com/pschatzmann/arduino-audio-tools/wiki/Audio-Sources-and-Sinks).
-
-
-### Example
-
-Here is a simple example which streams a file from the Flash Memory and writes it to I2S:
+This functionality provides the glue which makes different audio processing components and libraries work together.
+We also provide [plenty of examples](https://github.com/pschatzmann/arduino-audio-tools/wiki/Examples) that demonstrate how to implement the different scenarios. The __design philosophy__ is based on the Arduino conventions: we use the ```begin()``` and ```end()``` methods to start and stop the processing and we propagate the __use of Streams__. We all know the [Arduino Streams](https://pschatzmann.github.io/arduino-audio-tools/class_stream.html): We usually use them to write out print messages and sometimes we use them to read the output from Serial devices. The same thing applies to “Audio Streams”: You can read audio data from “Audio Sources” and you write them to “Audio Sinks”.
+
+As “Audio Sources” we will have e.g.:
+
+- Digital Microphones – [I2SStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_i2_s_stream.html)
+- Analog Microphones – [AnalogAudioStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_analog_audio_stream.html)
+- Files on the Internet – [URLStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_u_r_l_stream.html)
+- Streaming Internet Radios - [ICYStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_i_c_y_stream.html)
+- Generated Sound – [GeneratedSoundStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_generated_sound_stream.html)
+- Encoded Audio - [EncodedAudioStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_encoded_audio_stream.html)
+- Mobile Phone A2DP Bluetooth – [A2DPStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_a2_d_p_stream.html)
+- Binary Data in Flash Memory – [MemoryStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_memory_stream.html)
+- Audio generated by STK Framwork - [STKStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_s_t_k_stream.html)
+- Desktop Integration - [PortAudioStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_port_audio_stream.html) [MiniAudioStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_mini_audio_stream.html) [StdioStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_stdio_stream.html)
+- A Timer based Source - [TimerCallbackAudioStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_timer_callback_audio_stream.html)
+- ESP32 Lyrat/AudioKit - [AudioKitStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_audio_kit_stream.html)
+- Input using FIR, IIR Filters - [FilteredStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_filtered_stream.html)
+- Tensorflow Lite - [TfLiteAudioStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_tf_lite_audio_stream.html)
+- [Converting Streams](https://pschatzmann.github.io/arduino-audio-tools/group__transform.html)
+- Communication - [ESPNowStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_e_s_p_now_stream.html), [UDPStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_u_d_p_stream.html)
+- Any other Arduino Classes implementing Streams: SD, Ethernet etc
+
+As “Audio Sinks” we will have e.g:
+
+- external DAC – [I2SStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_i2_s_stream.html)
+- Analog output e.g. to an Amplifier – [AnalogAudioStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_analog_audio_stream.html)
+- Output using PWM – [PWMAudioOutput](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_p_w_m_audio_output.html)
+- Output to SPDIF/TOSLINK - [SPDIFOutput](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_s_p_d_i_f_output.html)
+- Encoded Audio - [EncodedAudioStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_encoded_audio_stream.html)
+- Bluetooth Speakers – [A2DPStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_a2_d_p_stream.html)
+- Serial to display the data as CSV – [CsvOutput](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_csv_output.html)
+- Serial to display the data as hex dump - [HexDumpOutput](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_hex_dump_output.html)
+- Encoding and Decoding of Audio [EncodedAudioStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_encoded_audio_stream.html)
+- Desktop Integration - [PortAudioStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_port_audio_stream.html) [MiniAudioStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_mini_audio_stream.html) [StdioStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_stdio_stream.html)
+- ID3 Metadata for MP3 - [MetaDataID3](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_meta_data_i_d3.html)
+- A Timer based Sink - [TimerCallbackAudioStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_timer_callback_audio_stream.html)
+- ESP32 Lyrat/AudioKit - [AudioKitStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_audio_kit_stream.html)
+- VS1053 Codec Module - [VS1053Stream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_v_s1053_stream.html)
+- Callback integration e.g. with ESP8266Audio [AudioOutputWithCallback](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_audio_output_with_callback.html)
+- Output using FIR, IRR Filters - [FilteredStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_filtered_stream.html)
+- Determine the Volume - [VolumeOutput](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_volume_output.html)
+- Split the Output to different Destinations - [MultiOutput](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_multi_output.html)
+- 3 Band Equilizer - [Equilizer3Bands](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_equilizer3_bands.html)
+- LED Strip/Matrix - [LEDOutput](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_l_e_d_output.html)
+- FFT - [AudioRealFFT](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_audio_real_f_f_t.html) and [AudioKissFFT](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_audio_kiss_f_f_t.html)
+- Tensorflow Lite - [TfLiteAudioStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_tf_lite_audio_stream.html)
+- [Converting Streams](https://pschatzmann.github.io/arduino-audio-tools/group__transform.html)
+- Communication - [ESPNowStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_e_s_p_now_stream.html), [UDPStream](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_u_d_p_stream.html)
+- Multiuser-Webserver for PCM Output - [AudioWAVServerEx](https://pschatzmann.github.io/arduino-audio-tools/classaudio__tools_1_1_audio_w_a_v_server_ex.html)
+- Any other Arduino Classes implementing Streams: SD, Ethernet etc
+
+### Examples
+
+Here is an simple example which streams a file from the Flash Memory and writes it to I2S:
```C++
#include "AudioTools.h"
@@ -33,7 +75,6 @@ Here is a simple example which streams a file from the Flash Memory and writes i
uint8_t channels = 2;
uint16_t sample_rate = 22050;
-uint8_t bits_per_sample = 16;
MemoryStream music(StarWars30_raw, StarWars30_raw_len);
I2SStream i2s; // Output to I2S
@@ -45,10 +86,8 @@ void setup(){
auto config = i2s.defaultConfig(TX_MODE);
config.sample_rate = sample_rate;
config.channels = channels;
- config.bits_per_sample = bits_per_sample;
+ config.bits_per_sample = 16;
i2s.begin(config);
-
- music.begin();
}
void loop(){
@@ -63,7 +102,7 @@ I suggest you continue to read the more [detailed introduction](https://github.c
Further examples can be found in the [Wiki](https://github.com/pschatzmann/arduino-audio-tools/wiki/Examples).
-Dependent on the example you might need to install some [additional libaries](https://github.com/pschatzmann/arduino-audio-tools/wiki/Optional-Libraries)
+Dependent on the example you might need to install some [addional libaries](https://github.com/pschatzmann/arduino-audio-tools/wiki/Optional-Libraries)
### AudioPlayer
@@ -72,20 +111,21 @@ The library also provides a versatile [AudioPlayer](https://pschatzmann.github.i
### Logging
-The application uses a built in logger: By default we use the log level warning and the logging output is going to Serial. You can change this in your sketch by calling e.g:
+The application uses a built in logger (see AudioLogger.h and AudioConfig.h). You can e.g. deactivate the logging by changing USE_AUDIO_LOGGING to false in the AudioConfig.h:
```C++
-AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Debug);
+#define USE_AUDIO_LOGGING false
+#define LOG_LEVEL AudioLogger::Warning
+#define LOG_STREAM Serial
```
-You can log to any object that is a subclass of Print and valid log level values are: Debug, Info, Warning, Error.
-
-You can also deactivate the logging by changing USE_AUDIO_LOGGING to false in the AudioConfig.h to decrease the memory usage:
+Per default we use the log level warning and the logging output is going to Serial. You can also change this in your sketch by calling AudioLogger begin with the output stream and the log level e.g:
```C++
-#define USE_AUDIO_LOGGING false
+AudioLogger::instance().begin(Serial, AudioLogger::Debug);
```
+
## Show and Tell
Get some inspiration [from projects that were using this library](https://github.com/pschatzmann/arduino-audio-tools/discussions/categories/show-and-tell) or share your projects with the community.
@@ -95,29 +135,11 @@ Get some inspiration [from projects that were using this library](https://github
Please use this before you raise any issue or start a discussion!
-- Read the [Tutorial & Documentation in the Wiki](https://github.com/pschatzmann/arduino-audio-tools/wiki)
-- Have a look at the [Examples](https://github.com/pschatzmann/arduino-audio-tools/wiki/Examples)
-- Check the [Class Documentation by Topic](https://pschatzmann.github.io/arduino-audio-tools/topics.html).
+- Read the [Tutorial in the Wiki](https://github.com/pschatzmann/arduino-audio-tools/wiki)
+- Check the [Class Documentation by Topic](https://pschatzmann.github.io/arduino-audio-tools/modules.html).
- Find your class in [All Classes Alphabetically](https://pschatzmann.github.io/arduino-audio-tools/namespaceaudio__tools.html)
- You also might find further information in [one of my Blogs](https://www.pschatzmann.ch/home/category/machine-sound/)
-## Support
-
-I spent a lot of time to provide a comprehensive and complete documentation.
-So please read the documentation first and check the issues and discussions before posting any new ones on Github.
-
-Open __issues only for bugs__ and if it is not a bug, use a discussion: Provide enough information about
-- the selected scenario/sketch
-- what exactly you are trying to do
-- your hardware
-- your software version (from the Boards Manager) and library versions
-- what exactly your problem is
-
-to enable others to understand and reproduce your issue.
-
-Finally, __don't__ send me any e-mails or post questions on my personal website!
-
-Please note that discussions and issues which have already been answered before or where the answer can be found in the documentation may get deleted w/o reply.
## Installation in Arduino
@@ -129,7 +151,7 @@ git clone https://github.com/pschatzmann/arduino-audio-tools.git
```
I recommend to use git because you can easily update to the latest version just by executing the ```git pull``` command in the project folder.
-If you want to use the library on other patforms, you can find [further information in the Wiki](https://github.com/pschatzmann/arduino-audio-tools/wiki).
+If you want to use the library in PlatformIO, you can find a [detailed description in the Wiki](https://github.com/pschatzmann/arduino-audio-tools/wiki/Working-with-PlatformIO).
## Sponsor Me
diff --git a/component.mk b/component.mk
deleted file mode 100644
index a98f634eae..0000000000
--- a/component.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-#
-# "main" pseudo-component makefile.
-#
-# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
diff --git a/docs/index.html b/docs/index.html
index fbb86a45e5..1147729dc1 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -1,6 +1,6 @@
-
+
-If you are not redirected, click here .
+If you are not redirected, click here .
diff --git a/docs/tensorflow/Dockerfile b/docs/tensorflow/Dockerfile
new file mode 100644
index 0000000000..9e8589a8a9
--- /dev/null
+++ b/docs/tensorflow/Dockerfile
@@ -0,0 +1,16 @@
+FROM snowzach/tensorflow-multiarch
+#FROM tensorflow/tensorflow:latest-jupyter
+LABEL maintainer="phil schatzmann"
+RUN /usr/bin/python3 -m pip install --upgrade pip
+RUN pip3 install seaborn matplotlib jupyterlab
+
+# Working directory
+RUN mkdir /content
+WORKDIR /content
+VOLUME /content
+ADD micro_speech_with_lstm_op.ipynb /content
+ADD train_micro_speech_model.ipynb /content
+ADD train_hello_world_model.ipynb /content
+RUN apt-get update && apt-get install git -y && apt-get upgrade -y
+EXPOSE 8888
+CMD ["jupyter", "lab", "--no-browser", "--allow-root", "--ip=0.0.0.0" ]
diff --git a/docs/tensorflow/docker-compose.yml b/docs/tensorflow/docker-compose.yml
new file mode 100644
index 0000000000..ec6b41a930
--- /dev/null
+++ b/docs/tensorflow/docker-compose.yml
@@ -0,0 +1,9 @@
+version: "3.3"
+services:
+ tensorflow:
+ container_name: tensorflow
+ ports:
+ - "8888:8888"
+ - "6006:6006"
+ restart: always
+ build: .
diff --git a/docs/tensorflow/micro_speech_with_lstm_op.ipynb b/docs/tensorflow/micro_speech_with_lstm_op.ipynb
new file mode 100644
index 0000000000..5f06b3d4c2
--- /dev/null
+++ b/docs/tensorflow/micro_speech_with_lstm_op.ipynb
@@ -0,0 +1,2601 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "fluF3_oOgkWF"
+ },
+ "source": [
+ "##### Copyright 2021 The TensorFlow Authors."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 112,
+ "metadata": {
+ "cellView": "form",
+ "id": "AJs7HHFmg1M9"
+ },
+ "outputs": [],
+ "source": [
+ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
+ "# you may not use this file except in compliance with the License.\n",
+ "# You may obtain a copy of the License at\n",
+ "#\n",
+ "# https://www.apache.org/licenses/LICENSE-2.0\n",
+ "#\n",
+ "# Unless required by applicable law or agreed to in writing, software\n",
+ "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
+ "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
+ "# See the License for the specific language governing permissions and\n",
+ "# limitations under the License."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "jYysdyb-CaWM"
+ },
+ "source": [
+ "# Simple audio recognition: Recognizing keywords"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "SPfDNFlb66XF"
+ },
+ "source": [
+ "This tutorial will show you how to build a basic speech recognition network that recognizes ten different words. It's important to know that real speech and audio recognition systems are much more complex, but like MNIST for images, it should give you a basic understanding of the techniques involved. Once you've completed this tutorial, you'll have a model that tries to classify a one second audio clip as \"down\", \"go\", \"left\", \"no\", \"right\", \"stop\", \"up\" and \"yes\"."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "Go9C3uLL8Izc"
+ },
+ "source": [
+ "## Setup\n",
+ "\n",
+ "Import necessary modules and dependencies."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 113,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "dzLKpmZICaWN",
+ "outputId": "9ba23229-9705-42df-8f7b-c4c321660a9b"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "2.5.0\n"
+ ]
+ }
+ ],
+ "source": [
+ "import os\n",
+ "import pathlib\n",
+ "\n",
+ "import matplotlib.pyplot as plt\n",
+ "import numpy as np\n",
+ "import seaborn as sns\n",
+ "import tensorflow as tf\n",
+ "print(tf.version.VERSION)\n",
+ "from tensorflow.keras.layers.experimental import preprocessing\n",
+ "from tensorflow.keras import layers\n",
+ "from tensorflow.keras import models\n",
+ "from IPython import display\n",
+ "\n",
+ "# Set seed for experiment reproducibility\n",
+ "seed = 42\n",
+ "tf.random.set_seed(seed)\n",
+ "np.random.seed(seed)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "yR0EdgrLCaWR"
+ },
+ "source": [
+ "## Import the Speech Commands dataset\n",
+ "\n",
+ "You'll write a script to download a portion of the [Speech Commands dataset](https://www.tensorflow.org/datasets/catalog/speech_commands). The original dataset consists of over 105,000 WAV audio files of people saying thirty different words. This data was collected by Google and released under a CC BY license.\n",
+ "\n",
+ "You'll be using a portion of the dataset to save time with data loading. Extract the `mini_speech_commands.zip` and load it in using the `tf.data` API."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 114,
+ "metadata": {
+ "id": "2-rayb7-3Y0I"
+ },
+ "outputs": [],
+ "source": [
+ "data_dir = pathlib.Path('data/mini_speech_commands')\n",
+ "if not data_dir.exists():\n",
+ " tf.keras.utils.get_file(\n",
+ " 'mini_speech_commands.zip',\n",
+ " origin=\"http://storage.googleapis.com/download.tensorflow.org/data/mini_speech_commands.zip/",\n",
+ " extract=True,\n",
+ " cache_dir='.', cache_subdir='data')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "h_72nZHA9UH9"
+ },
+ "source": [
+ "Moving wav files from command directories to unknown sub-directory (Factory Reset to reset data directory)\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "vB4Jq4Qg35iZ",
+ "outputId": "85d90934-908c-48b2-85b7-8500ad302e04"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "mkdir: /content: No such file or directory\n",
+ "mkdir: /content/data/mini_speech_commands: No such file or directory\n",
+ "mv: rename /content/data/mini_speech_commands/down/* to /content/data/mini_speech_commands/unknown: No such file or directory\n",
+ "rm: /content/data/mini_speech_commands/down: No such file or directory\n",
+ "mv: rename /content/data/mini_speech_commands/go/* to /content/data/mini_speech_commands/unknown: No such file or directory\n",
+ "rm: /content/data/mini_speech_commands/go: No such file or directory\n",
+ "mv: rename /content/data/mini_speech_commands/left/* to /content/data/mini_speech_commands/unknown: No such file or directory\n",
+ "rm: /content/data/mini_speech_commands/left: No such file or directory\n",
+ "mv: rename /content/data/mini_speech_commands/right/* to /content/data/mini_speech_commands/unknown: No such file or directory\n",
+ "rm: /content/data/mini_speech_commands/right: No such file or directory\n",
+ "mv: rename /content/data/mini_speech_commands/stop/* to /content/data/mini_speech_commands/unknown: No such file or directory\n",
+ "rm: /content/data/mini_speech_commands/stop: No such file or directory\n",
+ "mv: rename /content/data/mini_speech_commands/up/* to /content/data/mini_speech_commands/unknown: No such file or directory\n",
+ "rm: /content/data/mini_speech_commands/up: No such file or directory\n",
+ "rm: /content/data/mini_speech_commands/README.md: No such file or directory\n",
+ "ls: /content/data/mini_speech_commands/unknown: No such file or directory\n",
+ " 0\n"
+ ]
+ }
+ ],
+ "source": [
+ "!mkdir /content/keras_lstm\n",
+ "# comment out below line if \"unknown\" directory already exists\n",
+ "!mkdir /content/data/mini_speech_commands/unknown\n",
+ "# moves files from their specific commands directory to the \"unknown\" directory (replaces all files with an existing name therefore example set is smaller)\n",
+ "!mv /content/data/mini_speech_commands/down/* /content/data/mini_speech_commands/unknown\n",
+ "!rm -d /content/data/mini_speech_commands/down\n",
+ "!mv /content/data/mini_speech_commands/go/* /content/data/mini_speech_commands/unknown\n",
+ "!rm -d /content/data/mini_speech_commands/go\n",
+ "!mv /content/data/mini_speech_commands/left/* /content/data/mini_speech_commands/unknown\n",
+ "!rm -d /content/data/mini_speech_commands/left\n",
+ "!mv /content/data/mini_speech_commands/right/* /content/data/mini_speech_commands/unknown\n",
+ "!rm -d /content/data/mini_speech_commands/right\n",
+ "!mv /content/data/mini_speech_commands/stop/* /content/data/mini_speech_commands/unknown\n",
+ "!rm -d /content/data/mini_speech_commands/stop\n",
+ "!mv /content/data/mini_speech_commands/up/* /content/data/mini_speech_commands/unknown\n",
+ "!rm -d /content/data/mini_speech_commands/up\n",
+ "!rm /content/data/mini_speech_commands/README.md\n",
+ "!ls /content/data/mini_speech_commands/unknown | wc -l"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "BgvFq3uYiS5G"
+ },
+ "source": [
+ "Sets wanted commands for training (Available commands: Down, Go, Left, No, Right, Stop, Up, Yes, and Unknown for commands that are not to be tested"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 116,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "70IBxSKxA1N9",
+ "outputId": "a22025ee-8e85-4377-b223-b1d804fe5a25"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Commands: ['yes', 'no', 'unknown']\n"
+ ]
+ }
+ ],
+ "source": [
+ "commands = np.array(tf.io.gfile.listdir(str(data_dir)))\n",
+ "commands = [\"yes\",\"no\", \"unknown\"]\n",
+ "print('Commands:', commands)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "aMvdU9SY8WXN"
+ },
+ "source": [
+ "Extract the audio files into a list and shuffle it."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 117,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "hlX685l1wD9k",
+ "outputId": "c1847369-0ba1-4ddc-f817-e55e08fdced2"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Number of total examples: 5311\n",
+ "Number of examples per label: 1000\n",
+ "Example file tensor: tf.Tensor(b'data/mini_speech_commands/no/53458368_nohash_0.wav', shape=(), dtype=string)\n"
+ ]
+ }
+ ],
+ "source": [
+ "filenames = tf.io.gfile.glob(str(data_dir) + '/*/*')\n",
+ "filenames = tf.random.shuffle(filenames)\n",
+ "num_samples = len(filenames)\n",
+ "print('Number of total examples:', num_samples)\n",
+ "print('Number of examples per label:',\n",
+ " len(tf.io.gfile.listdir(str(data_dir/commands[0]))))\n",
+ "print('Example file tensor:', filenames[0])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "9vK3ymy23MCP"
+ },
+ "source": [
+ "Split the files into training, validation and test sets using a 80:10:10 ratio, respectively."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 118,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "Cv_wts-l3KgD",
+ "outputId": "8d1c6417-0157-4945-f0ef-864a87ce6679"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Training set size 4249\n",
+ "Validation set size 531\n",
+ "Test set size 531\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Take 80% of total number examples for training set files\n",
+ "train_files = filenames[:4249]\n",
+ "# Take 10% of total number examples adding to 80% of total examples for validation set files\n",
+ "val_files = filenames[4249: 4249 + 531]\n",
+ "# Take -10% of total number examples for test set files\n",
+ "test_files = filenames[-531:]\n",
+ "\n",
+ "print('Training set size', len(train_files))\n",
+ "print('Validation set size', len(val_files))\n",
+ "print('Test set size', len(test_files))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "g2Cj9FyvfweD"
+ },
+ "source": [
+ "## Reading audio files and their labels"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "j1zjcWteOcBy"
+ },
+ "source": [
+ "The audio file will initially be read as a binary file, which you'll want to convert into a numerical tensor.\n",
+ "\n",
+ "To load an audio file, you will use [`tf.audio.decode_wav`](https://www.tensorflow.org/api_docs/python/tf/audio/decode_wav), which returns the WAV-encoded audio as a Tensor and the sample rate.\n",
+ "\n",
+ "A WAV file contains time series data with a set number of samples per second. \n",
+ "Each sample represents the amplitude of the audio signal at that specific time. In a 16-bit system, like the files in `mini_speech_commands`, the values range from -32768 to 32767. \n",
+ "The sample rate for this dataset is 16kHz.\n",
+ "Note that `tf.audio.decode_wav` will normalize the values to the range [-1.0, 1.0]."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 119,
+ "metadata": {
+ "id": "9PjJ2iXYwftD"
+ },
+ "outputs": [],
+ "source": [
+ "def decode_audio(audio_binary):\n",
+ " audio, _ = tf.audio.decode_wav(audio_binary)\n",
+ " return tf.squeeze(audio, axis=-1)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "GPQseZElOjVN"
+ },
+ "source": [
+ "The label for each WAV file is its parent directory."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 120,
+ "metadata": {
+ "id": "8VTtX1nr3YT-"
+ },
+ "outputs": [],
+ "source": [
+ "def get_label(file_path):\n",
+ " parts = tf.strings.split(file_path, os.path.sep)\n",
+ "\n",
+ " # Note: You'll use indexing here instead of tuple unpacking to enable this \n",
+ " # to work in a TensorFlow graph.\n",
+ " return parts[-2] "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "E8Y9w_5MOsr-"
+ },
+ "source": [
+ "Let's define a method that will take in the filename of the WAV file and output a tuple containing the audio and labels for supervised training."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 121,
+ "metadata": {
+ "id": "WdgUD5T93NyT"
+ },
+ "outputs": [],
+ "source": [
+ "def get_waveform_and_label(file_path):\n",
+ " label = get_label(file_path)\n",
+ " audio_binary = tf.io.read_file(file_path)\n",
+ " waveform = decode_audio(audio_binary)\n",
+ " return waveform, label"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "nvN8W_dDjYjc"
+ },
+ "source": [
+ "You will now apply `process_path` to build your training set to extract the audio-label pairs and check the results. You'll build the validation and test sets using a similar procedure later on."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 122,
+ "metadata": {
+ "id": "0SQl8yXl3kNP"
+ },
+ "outputs": [],
+ "source": [
+ "AUTOTUNE = tf.data.AUTOTUNE\n",
+ "files_ds = tf.data.Dataset.from_tensor_slices(train_files)\n",
+ "waveform_ds = files_ds.map(get_waveform_and_label, num_parallel_calls=AUTOTUNE)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "voxGEwvuh2L7"
+ },
+ "source": [
+ "Let's examine a few audio waveforms with their corresponding labels."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 123,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 716
+ },
+ "id": "8yuX6Nqzf6wT",
+ "outputId": "8575133a-16c0-4d08-9857-ee4ecbfbe2fd"
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "rows = 3\n",
+ "cols = 3\n",
+ "n = rows*cols\n",
+ "fig, axes = plt.subplots(rows, cols, figsize=(10, 12))\n",
+ "for i, (audio, label) in enumerate(waveform_ds.take(n)):\n",
+ " r = i // cols\n",
+ " c = i % cols\n",
+ " ax = axes[r][c]\n",
+ " ax.plot(audio.numpy())\n",
+ " ax.set_yticks(np.arange(-1.2, 1.2, 0.2))\n",
+ " label = label.numpy().decode('utf-8')\n",
+ " ax.set_title(label)\n",
+ "\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "EWXPphxm0B4m"
+ },
+ "source": [
+ "## Spectrogram\n",
+ "\n",
+ "You'll convert the waveform into a spectrogram, which shows frequency changes over time and can be represented as a 2D image. This can be done by applying the short-time Fourier transform (STFT) to convert the audio into the time-frequency domain.\n",
+ "\n",
+ "A Fourier transform ([`tf.signal.fft`](https://www.tensorflow.org/api_docs/python/tf/signal/fft)) converts a signal to its component frequencies, but loses all time information. The STFT ([`tf.signal.stft`](https://www.tensorflow.org/api_docs/python/tf/signal/stft)) splits the signal into windows of time and runs a Fourier transform on each window, preserving some time information, and returning a 2D tensor that you can run standard convolutions on.\n",
+ "\n",
+ "STFT produces an array of complex numbers representing magnitude and phase. However, you'll only need the magnitude for this tutorial, which can be derived by applying `tf.abs` on the output of `tf.signal.stft`. \n",
+ "\n",
+ "Choose `frame_length` and `frame_step` parameters such that the generated spectrogram \"image\" is almost square. For more information on STFT parameters choice, you can refer to [this video](https://www.coursera.org/lecture/audio-signal-processing/stft-2-tjEQe) on audio signal processing. \n",
+ "\n",
+ "You also want the waveforms to have the same length, so that when you convert it to a spectrogram image, the results will have similar dimensions. This can be done by simply zero padding the audio clips that are shorter than one second.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 124,
+ "metadata": {
+ "id": "_4CK75DHz_OR"
+ },
+ "outputs": [],
+ "source": [
+ "def get_spectrogram(waveform):\n",
+ " # Padding for files with less than 16000 samples\n",
+ " zero_padding = tf.zeros([16000] - tf.shape(waveform), dtype=tf.float32)\n",
+ "\n",
+ " # Concatenate audio with padding so that all audio clips will be of the \n",
+ " # same length\n",
+ " waveform = tf.cast(waveform, tf.float32)\n",
+ " equal_length = tf.concat([waveform, zero_padding], 0)\n",
+ " spectrogram = tf.signal.stft(\n",
+ " equal_length, frame_length=480, frame_step=320, fft_length=512)\n",
+ " \n",
+ " spectrogram = tf.abs(spectrogram)\n",
+ "\n",
+ " return spectrogram"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "5rdPiPYJphs2"
+ },
+ "source": [
+ "Next, you will explore the data. Compare the waveform, the spectrogram and the actual audio of one example from the dataset."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 125,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 145
+ },
+ "id": "4Mu6Y7Yz3C-V",
+ "outputId": "cdb225d1-54f2-4554-e518-a9f32865f728"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Label: no\n",
+ "Waveform shape: (16000,)\n",
+ "Spectrogram shape: (49, 257)\n",
+ "Audio playback\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ " \n",
+ " \n",
+ " Your browser does not support the audio element.\n",
+ " \n",
+ " "
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "tags": []
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "for waveform, label in waveform_ds.take(1):\n",
+ " label = label.numpy().decode('utf-8')\n",
+ " spectrogram = get_spectrogram(waveform)\n",
+ "\n",
+ "print('Label:', label)\n",
+ "print('Waveform shape:', waveform.shape)\n",
+ "print('Spectrogram shape:', spectrogram.shape)\n",
+ "print('Audio playback')\n",
+ "display.display(display.Audio(waveform, rate=16000))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 126,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 499
+ },
+ "id": "e62jzb36-Jog",
+ "outputId": "bc3a0ea2-38d7-496a-d1d5-5048f99eeed6"
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "def plot_spectrogram(spectrogram, ax):\n",
+ " # Convert to frequencies to log scale and transpose so that the time is\n",
+ " # represented in the x-axis (columns).\n",
+ " log_spec = np.log(spectrogram.T)\n",
+ " height = log_spec.shape[0]\n",
+ " width = log_spec.shape[1]\n",
+ " X = np.linspace(0, np.size(spectrogram), num=width, dtype=int)\n",
+ " Y = range(height)\n",
+ " ax.pcolormesh(X, Y, log_spec)\n",
+ "\n",
+ "\n",
+ "fig, axes = plt.subplots(2, figsize=(12, 8))\n",
+ "timescale = np.arange(waveform.shape[0])\n",
+ "axes[0].plot(timescale, waveform.numpy())\n",
+ "axes[0].set_title('Waveform')\n",
+ "axes[0].set_xlim([0, 16000])\n",
+ "plot_spectrogram(spectrogram.numpy(), axes[1])\n",
+ "axes[1].set_title('Spectrogram')\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "GyYXjW07jCHA"
+ },
+ "source": [
+ "Now transform the waveform dataset to have spectrogram images and their corresponding labels as integer IDs."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 127,
+ "metadata": {
+ "id": "43IS2IouEV40"
+ },
+ "outputs": [],
+ "source": [
+ "def get_spectrogram_and_label_id(audio, label):\n",
+ " spectrogram = get_spectrogram(audio)\n",
+ " spectrogram = tf.expand_dims(spectrogram, -1)\n",
+ " label_id = tf.argmax(label == commands)\n",
+ " return spectrogram, label_id"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 128,
+ "metadata": {
+ "id": "yEVb_oK0oBLQ"
+ },
+ "outputs": [],
+ "source": [
+ "spectrogram_ds = waveform_ds.map(\n",
+ " get_spectrogram_and_label_id, num_parallel_calls=AUTOTUNE)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "6gQpAAgMnyDi"
+ },
+ "source": [
+ "Examine the spectrogram \"images\" for different samples of the dataset."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 129,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 646
+ },
+ "id": "QUbHfTuon4iF",
+ "outputId": "f5057001-c343-43c3-ca64-cff3030d3380"
+ },
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:4: RuntimeWarning: divide by zero encountered in log\n",
+ " after removing the cwd from sys.path.\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "rows = 3\n",
+ "cols = 3\n",
+ "n = rows*cols\n",
+ "fig, axes = plt.subplots(rows, cols, figsize=(10, 10))\n",
+ "for i, (spectrogram, label_id) in enumerate(spectrogram_ds.take(n)):\n",
+ " r = i // cols\n",
+ " c = i % cols\n",
+ " ax = axes[r][c]\n",
+ " plot_spectrogram(np.squeeze(spectrogram.numpy()), ax)\n",
+ " ax.set_title(commands[label_id.numpy()])\n",
+ " ax.axis('off')\n",
+ " \n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "z5KdY8IF8rkt"
+ },
+ "source": [
+ "## Build and train the model\n",
+ "\n",
+ "Now you can build and train your model. But before you do that, you'll need to repeat the training set preprocessing on the validation and test sets."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 130,
+ "metadata": {
+ "id": "10UI32QH_45b"
+ },
+ "outputs": [],
+ "source": [
+ "def preprocess_dataset(files):\n",
+ " files_ds = tf.data.Dataset.from_tensor_slices(files)\n",
+ " output_ds = files_ds.map(get_waveform_and_label, num_parallel_calls=AUTOTUNE)\n",
+ " output_ds = output_ds.map(\n",
+ " get_spectrogram_and_label_id, num_parallel_calls=AUTOTUNE)\n",
+ " return output_ds"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 131,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "HNv4xwYkB2P6",
+ "outputId": "19e46c86-5f05-4bf2-ac06-1ea1e5f03dfd"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "train_ds = spectrogram_ds\n",
+ "val_ds = preprocess_dataset(val_files)\n",
+ "test_ds = preprocess_dataset(test_files)\n",
+ "print(val_ds)\n",
+ "print(test_ds)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "assnWo6SB3lR"
+ },
+ "source": [
+ "Batch the training and validation sets for model training."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 132,
+ "metadata": {
+ "id": "UgY9WYzn61EX"
+ },
+ "outputs": [],
+ "source": [
+ "batch_size = 64\n",
+ "train_ds = train_ds.batch(batch_size)\n",
+ "val_ds = val_ds.batch(batch_size)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "GS1uIh6F_TN9"
+ },
+ "source": [
+ "Add dataset [`cache()`](https://www.tensorflow.org/api_docs/python/tf/data/Dataset#cache) and [`prefetch()`](https://www.tensorflow.org/api_docs/python/tf/data/Dataset#prefetch) operations to reduce read latency while training the model."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 133,
+ "metadata": {
+ "id": "fdZ6M-F5_QzY"
+ },
+ "outputs": [],
+ "source": [
+ "train_ds = train_ds.cache().prefetch(AUTOTUNE)\n",
+ "val_ds = val_ds.cache().prefetch(AUTOTUNE)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "rwHkKCQQb5oW"
+ },
+ "source": [
+ "For the model, you'll use a simple convolutional neural network (CNN), since you have transformed the audio files into spectrogram images.\n",
+ "The model also has the following additional preprocessing layers:\n",
+ "- A [`Resizing`](https://www.tensorflow.org/api_docs/python/tf/keras/layers/experimental/preprocessing/Resizing) layer to downsample the input to enable the model to train faster.\n",
+ "- A [`Normalization`](https://www.tensorflow.org/api_docs/python/tf/keras/layers/experimental/preprocessing/Normalization) layer to normalize each pixel in the image based on its mean and standard deviation.\n",
+ "\n",
+ "For the `Normalization` layer, its `adapt` method would first need to be called on the training data in order to compute aggregate statistics (i.e. mean and standard deviation)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 134,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "ALYz7PFCHblP",
+ "outputId": "41f2133f-823d-471f-9172-ece3c0b6ea03"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Input shape: (49, 257, 1)\n",
+ "num_labels: 3\n",
+ "WARNING:tensorflow:Please add `keras.layers.InputLayer` instead of `keras.Input` to Sequential model. `keras.Input` is intended to be used by Functional model.\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "WARNING:tensorflow:Please add `keras.layers.InputLayer` instead of `keras.Input` to Sequential model. `keras.Input` is intended to be used by Functional model.\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Model: \"sequential_3\"\n",
+ "_________________________________________________________________\n",
+ "Layer (type) Output Shape Param # \n",
+ "=================================================================\n",
+ "reshape_3 (Reshape) (None, 49, 257) 0 \n",
+ "_________________________________________________________________\n",
+ "lstm_3 (LSTM) (None, 49, 80) 108160 \n",
+ "_________________________________________________________________\n",
+ "flatten_3 (Flatten) (None, 3920) 0 \n",
+ "_________________________________________________________________\n",
+ "output (Dense) (None, 3) 11763 \n",
+ "=================================================================\n",
+ "Total params: 119,923\n",
+ "Trainable params: 119,923\n",
+ "Non-trainable params: 0\n",
+ "_________________________________________________________________\n"
+ ]
+ }
+ ],
+ "source": [
+ "for spectrogram, _ in spectrogram_ds.take(1):\n",
+ " input_shape = spectrogram.shape\n",
+ "print('Input shape:', input_shape)\n",
+ "num_labels = len(commands)\n",
+ "print('num_labels:', num_labels)\n",
+ "\n",
+ "model = models.Sequential([\n",
+ " layers.Input(shape=(49, 257), name='input'),\n",
+ " layers.Reshape(target_shape=(49, 257)),\n",
+ " layers.LSTM(80, time_major=False, return_sequences=True),\n",
+ " layers.Flatten(),\n",
+ " layers.Dense(3, activation=tf.nn.softmax, name='output')\n",
+ "])\n",
+ "model.summary()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 135,
+ "metadata": {
+ "id": "wFjj7-EmsTD-"
+ },
+ "outputs": [],
+ "source": [
+ "model.compile(optimizer='adam',\n",
+ " loss='sparse_categorical_crossentropy',\n",
+ " metrics=['accuracy'])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 136,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "ttioPJVMcGtq",
+ "outputId": "2fcf46d7-5704-4547-e8f4-b28e93cf474b"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Epoch 1/100\n",
+ "67/67 [==============================] - 10s 132ms/step - loss: 0.5685 - accuracy: 0.7677 - val_loss: 0.4034 - val_accuracy: 0.8249\n",
+ "Epoch 2/100\n",
+ "67/67 [==============================] - 0s 7ms/step - loss: 0.3422 - accuracy: 0.8647 - val_loss: 0.3415 - val_accuracy: 0.8663\n",
+ "Epoch 3/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.2520 - accuracy: 0.9028 - val_loss: 0.3160 - val_accuracy: 0.8908\n",
+ "Epoch 4/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.1916 - accuracy: 0.9303 - val_loss: 0.3530 - val_accuracy: 0.8814\n",
+ "Epoch 5/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.1372 - accuracy: 0.9525 - val_loss: 0.3112 - val_accuracy: 0.8964\n",
+ "Epoch 6/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.1110 - accuracy: 0.9598 - val_loss: 0.3256 - val_accuracy: 0.9021\n",
+ "Epoch 7/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0946 - accuracy: 0.9635 - val_loss: 0.2767 - val_accuracy: 0.9153\n",
+ "Epoch 8/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0748 - accuracy: 0.9718 - val_loss: 0.2612 - val_accuracy: 0.9115\n",
+ "Epoch 9/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0688 - accuracy: 0.9741 - val_loss: 0.2760 - val_accuracy: 0.9209\n",
+ "Epoch 10/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0646 - accuracy: 0.9769 - val_loss: 0.2664 - val_accuracy: 0.9228\n",
+ "Epoch 11/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0605 - accuracy: 0.9769 - val_loss: 0.2673 - val_accuracy: 0.9303\n",
+ "Epoch 12/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0572 - accuracy: 0.9798 - val_loss: 0.3040 - val_accuracy: 0.9058\n",
+ "Epoch 13/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0606 - accuracy: 0.9788 - val_loss: 0.2745 - val_accuracy: 0.9153\n",
+ "Epoch 14/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0579 - accuracy: 0.9805 - val_loss: 0.2417 - val_accuracy: 0.9266\n",
+ "Epoch 15/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0419 - accuracy: 0.9873 - val_loss: 0.2764 - val_accuracy: 0.9190\n",
+ "Epoch 16/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0395 - accuracy: 0.9840 - val_loss: 0.2875 - val_accuracy: 0.9266\n",
+ "Epoch 17/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0335 - accuracy: 0.9868 - val_loss: 0.2856 - val_accuracy: 0.9303\n",
+ "Epoch 18/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0417 - accuracy: 0.9842 - val_loss: 0.3096 - val_accuracy: 0.9171\n",
+ "Epoch 19/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0319 - accuracy: 0.9885 - val_loss: 0.3236 - val_accuracy: 0.9209\n",
+ "Epoch 20/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0337 - accuracy: 0.9887 - val_loss: 0.3286 - val_accuracy: 0.9303\n",
+ "Epoch 21/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0357 - accuracy: 0.9845 - val_loss: 0.3146 - val_accuracy: 0.9077\n",
+ "Epoch 22/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0333 - accuracy: 0.9871 - val_loss: 0.3545 - val_accuracy: 0.9228\n",
+ "Epoch 23/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0261 - accuracy: 0.9899 - val_loss: 0.3522 - val_accuracy: 0.9247\n",
+ "Epoch 24/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0232 - accuracy: 0.9913 - val_loss: 0.3834 - val_accuracy: 0.9171\n",
+ "Epoch 25/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0221 - accuracy: 0.9911 - val_loss: 0.4048 - val_accuracy: 0.9228\n",
+ "Epoch 26/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0199 - accuracy: 0.9922 - val_loss: 0.3371 - val_accuracy: 0.9209\n",
+ "Epoch 27/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0185 - accuracy: 0.9927 - val_loss: 0.4103 - val_accuracy: 0.9115\n",
+ "Epoch 28/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0176 - accuracy: 0.9939 - val_loss: 0.3697 - val_accuracy: 0.9284\n",
+ "Epoch 29/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0161 - accuracy: 0.9939 - val_loss: 0.3608 - val_accuracy: 0.9341\n",
+ "Epoch 30/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0159 - accuracy: 0.9941 - val_loss: 0.3661 - val_accuracy: 0.9397\n",
+ "Epoch 31/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0298 - accuracy: 0.9906 - val_loss: 0.3248 - val_accuracy: 0.9266\n",
+ "Epoch 32/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0360 - accuracy: 0.9868 - val_loss: 0.3489 - val_accuracy: 0.9303\n",
+ "Epoch 33/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0273 - accuracy: 0.9913 - val_loss: 0.3359 - val_accuracy: 0.9171\n",
+ "Epoch 34/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0229 - accuracy: 0.9918 - val_loss: 0.2956 - val_accuracy: 0.9360\n",
+ "Epoch 35/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0228 - accuracy: 0.9934 - val_loss: 0.2775 - val_accuracy: 0.9341\n",
+ "Epoch 36/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0313 - accuracy: 0.9894 - val_loss: 0.4389 - val_accuracy: 0.9096\n",
+ "Epoch 37/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0386 - accuracy: 0.9871 - val_loss: 0.3137 - val_accuracy: 0.9247\n",
+ "Epoch 38/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0254 - accuracy: 0.9901 - val_loss: 0.3331 - val_accuracy: 0.9228\n",
+ "Epoch 39/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0157 - accuracy: 0.9944 - val_loss: 0.3147 - val_accuracy: 0.9303\n",
+ "Epoch 40/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0134 - accuracy: 0.9955 - val_loss: 0.3165 - val_accuracy: 0.9228\n",
+ "Epoch 41/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0107 - accuracy: 0.9960 - val_loss: 0.3198 - val_accuracy: 0.9247\n",
+ "Epoch 42/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0097 - accuracy: 0.9967 - val_loss: 0.3278 - val_accuracy: 0.9303\n",
+ "Epoch 43/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0091 - accuracy: 0.9967 - val_loss: 0.3395 - val_accuracy: 0.9266\n",
+ "Epoch 44/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0086 - accuracy: 0.9967 - val_loss: 0.3511 - val_accuracy: 0.9266\n",
+ "Epoch 45/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0081 - accuracy: 0.9972 - val_loss: 0.3581 - val_accuracy: 0.9266\n",
+ "Epoch 46/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0077 - accuracy: 0.9974 - val_loss: 0.3642 - val_accuracy: 0.9284\n",
+ "Epoch 47/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0075 - accuracy: 0.9974 - val_loss: 0.3716 - val_accuracy: 0.9303\n",
+ "Epoch 48/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0073 - accuracy: 0.9976 - val_loss: 0.3778 - val_accuracy: 0.9303\n",
+ "Epoch 49/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0072 - accuracy: 0.9974 - val_loss: 0.3856 - val_accuracy: 0.9341\n",
+ "Epoch 50/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0070 - accuracy: 0.9974 - val_loss: 0.3949 - val_accuracy: 0.9303\n",
+ "Epoch 51/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0068 - accuracy: 0.9974 - val_loss: 0.4079 - val_accuracy: 0.9322\n",
+ "Epoch 52/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0067 - accuracy: 0.9974 - val_loss: 0.4251 - val_accuracy: 0.9303\n",
+ "Epoch 53/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0064 - accuracy: 0.9976 - val_loss: 0.4374 - val_accuracy: 0.9303\n",
+ "Epoch 54/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0063 - accuracy: 0.9976 - val_loss: 0.4655 - val_accuracy: 0.9228\n",
+ "Epoch 55/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0061 - accuracy: 0.9976 - val_loss: 0.4864 - val_accuracy: 0.9266\n",
+ "Epoch 56/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0059 - accuracy: 0.9976 - val_loss: 0.4829 - val_accuracy: 0.9266\n",
+ "Epoch 57/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0221 - accuracy: 0.9932 - val_loss: 0.4664 - val_accuracy: 0.9134\n",
+ "Epoch 58/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.1001 - accuracy: 0.9682 - val_loss: 0.5172 - val_accuracy: 0.9040\n",
+ "Epoch 59/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0591 - accuracy: 0.9788 - val_loss: 0.3654 - val_accuracy: 0.9190\n",
+ "Epoch 60/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0334 - accuracy: 0.9889 - val_loss: 0.3255 - val_accuracy: 0.9284\n",
+ "Epoch 61/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0174 - accuracy: 0.9941 - val_loss: 0.3431 - val_accuracy: 0.9228\n",
+ "Epoch 62/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0102 - accuracy: 0.9974 - val_loss: 0.3411 - val_accuracy: 0.9303\n",
+ "Epoch 63/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0114 - accuracy: 0.9951 - val_loss: 0.3733 - val_accuracy: 0.9397\n",
+ "Epoch 64/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0101 - accuracy: 0.9969 - val_loss: 0.3541 - val_accuracy: 0.9360\n",
+ "Epoch 65/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0128 - accuracy: 0.9969 - val_loss: 0.4403 - val_accuracy: 0.9228\n",
+ "Epoch 66/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0150 - accuracy: 0.9951 - val_loss: 0.3882 - val_accuracy: 0.9190\n",
+ "Epoch 67/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0092 - accuracy: 0.9974 - val_loss: 0.3697 - val_accuracy: 0.9266\n",
+ "Epoch 68/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0083 - accuracy: 0.9969 - val_loss: 0.4283 - val_accuracy: 0.9209\n",
+ "Epoch 69/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0149 - accuracy: 0.9955 - val_loss: 0.3324 - val_accuracy: 0.9303\n",
+ "Epoch 70/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0097 - accuracy: 0.9967 - val_loss: 0.3717 - val_accuracy: 0.9247\n",
+ "Epoch 71/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0163 - accuracy: 0.9946 - val_loss: 0.3632 - val_accuracy: 0.9341\n",
+ "Epoch 72/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0103 - accuracy: 0.9969 - val_loss: 0.4045 - val_accuracy: 0.9228\n",
+ "Epoch 73/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0128 - accuracy: 0.9962 - val_loss: 0.3544 - val_accuracy: 0.9284\n",
+ "Epoch 74/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0136 - accuracy: 0.9953 - val_loss: 0.3371 - val_accuracy: 0.9341\n",
+ "Epoch 75/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0126 - accuracy: 0.9955 - val_loss: 0.3302 - val_accuracy: 0.9303\n",
+ "Epoch 76/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0132 - accuracy: 0.9958 - val_loss: 0.3230 - val_accuracy: 0.9435\n",
+ "Epoch 77/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0122 - accuracy: 0.9962 - val_loss: 0.3205 - val_accuracy: 0.9397\n",
+ "Epoch 78/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0062 - accuracy: 0.9979 - val_loss: 0.3369 - val_accuracy: 0.9379\n",
+ "Epoch 79/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0053 - accuracy: 0.9976 - val_loss: 0.3293 - val_accuracy: 0.9416\n",
+ "Epoch 80/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0051 - accuracy: 0.9976 - val_loss: 0.3313 - val_accuracy: 0.9416\n",
+ "Epoch 81/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0050 - accuracy: 0.9979 - val_loss: 0.3335 - val_accuracy: 0.9416\n",
+ "Epoch 82/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0048 - accuracy: 0.9979 - val_loss: 0.3360 - val_accuracy: 0.9416\n",
+ "Epoch 83/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0046 - accuracy: 0.9981 - val_loss: 0.3389 - val_accuracy: 0.9435\n",
+ "Epoch 84/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0044 - accuracy: 0.9981 - val_loss: 0.3422 - val_accuracy: 0.9454\n",
+ "Epoch 85/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0043 - accuracy: 0.9979 - val_loss: 0.3463 - val_accuracy: 0.9454\n",
+ "Epoch 86/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0040 - accuracy: 0.9979 - val_loss: 0.3507 - val_accuracy: 0.9435\n",
+ "Epoch 87/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0038 - accuracy: 0.9981 - val_loss: 0.3550 - val_accuracy: 0.9454\n",
+ "Epoch 88/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0035 - accuracy: 0.9986 - val_loss: 0.3626 - val_accuracy: 0.9435\n",
+ "Epoch 89/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0031 - accuracy: 0.9986 - val_loss: 0.3761 - val_accuracy: 0.9435\n",
+ "Epoch 90/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0028 - accuracy: 0.9986 - val_loss: 0.3837 - val_accuracy: 0.9416\n",
+ "Epoch 91/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0059 - accuracy: 0.9981 - val_loss: 0.3513 - val_accuracy: 0.9416\n",
+ "Epoch 92/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0088 - accuracy: 0.9965 - val_loss: 0.3317 - val_accuracy: 0.9360\n",
+ "Epoch 93/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0187 - accuracy: 0.9936 - val_loss: 0.3797 - val_accuracy: 0.9209\n",
+ "Epoch 94/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0458 - accuracy: 0.9863 - val_loss: 0.4049 - val_accuracy: 0.9284\n",
+ "Epoch 95/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0402 - accuracy: 0.9859 - val_loss: 0.4151 - val_accuracy: 0.9322\n",
+ "Epoch 96/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0212 - accuracy: 0.9932 - val_loss: 0.3317 - val_accuracy: 0.9322\n",
+ "Epoch 97/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0124 - accuracy: 0.9960 - val_loss: 0.3416 - val_accuracy: 0.9416\n",
+ "Epoch 98/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0066 - accuracy: 0.9976 - val_loss: 0.3828 - val_accuracy: 0.9379\n",
+ "Epoch 99/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0056 - accuracy: 0.9976 - val_loss: 0.3558 - val_accuracy: 0.9379\n",
+ "Epoch 100/100\n",
+ "67/67 [==============================] - 0s 6ms/step - loss: 0.0049 - accuracy: 0.9979 - val_loss: 0.3675 - val_accuracy: 0.9360\n"
+ ]
+ }
+ ],
+ "source": [
+ "EPOCHS = 100\n",
+ "history = model.fit(\n",
+ " train_ds, \n",
+ " validation_data=val_ds, \n",
+ " epochs=EPOCHS,\n",
+ " # callbacks=tf.keras.callbacks.EarlyStopping(verbose=1, patience=2),\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "gjpCDeQ4mUfS"
+ },
+ "source": [
+ "Let's check the training and validation loss curves to see how your model has improved during training."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 137,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 265
+ },
+ "id": "nzhipg3Gu2AY",
+ "outputId": "a006e1e9-da10-4617-e699-01c5b04763dc"
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "metrics = history.history\n",
+ "plt.plot(history.epoch, metrics['loss'], metrics['val_loss'])\n",
+ "plt.legend(['loss', 'val_loss'])\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "5ZTt3kO3mfm4"
+ },
+ "source": [
+ "## Evaluate test set performance\n",
+ "\n",
+ "Let's run the model on the test set and check performance."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 138,
+ "metadata": {
+ "id": "biU2MwzyAo8o"
+ },
+ "outputs": [],
+ "source": [
+ "test_audio = []\n",
+ "test_labels = []\n",
+ "\n",
+ "for audio, label in test_ds:\n",
+ " test_audio.append(audio.numpy())\n",
+ " test_labels.append(label.numpy())\n",
+ "\n",
+ "test_audio = np.array(test_audio)\n",
+ "test_labels = np.array(test_labels)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 139,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "ktUanr9mRZky",
+ "outputId": "475fcebb-64af-4c8e-e4af-784289106a5b"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Test set accuracy: 95%\n"
+ ]
+ }
+ ],
+ "source": [
+ "y_pred = np.argmax(model.predict(test_audio), axis=1)\n",
+ "y_true = test_labels\n",
+ "\n",
+ "test_acc = sum(y_pred == y_true) / len(y_true)\n",
+ "print(f'Test set accuracy: {test_acc:.0%}')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "en9Znt1NOabH"
+ },
+ "source": [
+ "### Display a confusion matrix\n",
+ "\n",
+ "A confusion matrix is helpful to see how well the model did on each of the commands in the test set."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 140,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 497
+ },
+ "id": "LvoSAOiXU3lL",
+ "outputId": "d3a37e34-55f8-4ca6-d826-ac8255e8f36c"
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "confusion_mtx = tf.math.confusion_matrix(y_true, y_pred) \n",
+ "plt.figure(figsize=(10, 8))\n",
+ "sns.heatmap(confusion_mtx, xticklabels=commands, yticklabels=commands, \n",
+ " annot=True, fmt='g')\n",
+ "plt.xlabel('Prediction')\n",
+ "plt.ylabel('Label')\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "mQGi_mzPcLvl"
+ },
+ "source": [
+ "## Run inference on an audio file\n",
+ "\n",
+ "Finally, verify the model's prediction output using an input audio file of someone saying \"yes.\" How well does your model perform?"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 141,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 333
+ },
+ "id": "zRxauKMdhofU",
+ "outputId": "de931674-31e5-42af-c7f2-30420aad5dbe"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "3\n",
+ "tf.Tensor([0.57611686 0.21194157 0.21194157], shape=(3,), dtype=float32)\n",
+ "tf.Tensor([[0.57611686 0.21194157 0.21194157]], shape=(1, 3), dtype=float32)\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "sample_file = '/content/data/mini_speech_commands/yes/0132a06d_nohash_1.wav'\n",
+ "\n",
+ "sample_ds = preprocess_dataset([str(sample_file)])\n",
+ "for spectrogram, label in sample_ds.batch(1):\n",
+ " prediction = model(spectrogram)\n",
+ " print(len(commands))\n",
+ " print(tf.nn.softmax(prediction[0]))\n",
+ " print(tf.nn.softmax(prediction))\n",
+ " plt.bar(commands, tf.nn.softmax(prediction[0]))\n",
+ " plt.title(f'Predictions for \"{commands[label[0]]}\"')\n",
+ " plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "VgWICqdqQNaQ"
+ },
+ "source": [
+ "You can see that your model very clearly recognized the audio command as \"yes.\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "NNPrzNrcDqq8"
+ },
+ "source": [
+ "## Run TF inference on multiple audio files"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 150,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 1000
+ },
+ "id": "GmyOg4kwDEVH",
+ "outputId": "b770a9ce-6797-42bc-8b2f-06523463c84a"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/4c77947d_nohash_0.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAEICAYAAABPgw/pAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAUd0lEQVR4nO3df7RdZX3n8feHxGAFV7FytZIEQyE6RseCvUa7BixF7ApSwapUGDsVrWbsNFNsrRqnlnFSO0WZZWdNTSvYYUGdkUAd0XRIh7Yqv6pALhTUgMg1gkkoGH6O6AgEvvPH2ZeeXO7NPUlOuOTJ+7XWWdk/nr339+xz7ufs8+yzd1JVSJL2fvvNdgGSpOEw0CWpEQa6JDXCQJekRhjoktQIA12SGmGga7ckOT/JR7vhY5Lcuovr+VSSPxhudTNu81eSbEryUJKjnsptDypJJTlituvQ3mHubBegPS/J7cDzgceAHwJ/A6yoqoeGuZ2qugp48QD1nA68q6qO7lv2PcOsZUD/hd5++OIwVpbkcuAjwLEAVfWRYaz36SrJ+cDl3eixVXX6rBUjwCP0fckbqupA4BXAKPDhyQ2S7Gsf8C8ENuzKgknmDLkWabcZ6PuYqtpC7wj9ZfDEV/rfSnIbcFs37ZeT3JjkgSRfTfLyieWTHJXkhiQ/SHIR8My+eccm2dw3vjDJ55NsTXJvkk8meQnwKeDnu66OB7q2T3TddOPvTjKe5L4ka5Mc0jevkrwnyW1djauTpJt3RJIrkjyY5J6uxu0k2T/JQ8Ac4KYk3+mmvyTJ5d06NyQ5qW+Z85P8eZJ1SX4I/OIg+zvJ6UmunjTtiW6Ubr2rk1za7dNrkxw+zbqO7rqIjh1gP+yX5MNJ7kjy/SR/meQnu3kXJHlfNzx/4j3QjR/e7fP9Jl7PJO/r1vFPSd4xyPPWLKkqH40/gNuB47vhhfSOSv+wGy/g74CfAn4COAr4PvAqeoH39m75/YF5wB3A7wDPAN4CPAp8tFvXscDmbngOcBPwJ8AB9IL/6G7e6cDVk2o8v289xwH30Ps2sT/wp8CVfW0L+N/AQcChwFZgWTfvQuD36R2sPLHNafZLAUd0w88AxoH/0D3P44AfAC/uq+9B4F9NrHvAfT/Vc+3f7vnAvcBSel2g/xNYM7ktsAzYBCwdcD+8s3s+PwMcCHwe+EzfvL/uhv818B3gor55X+x7PbcBq7r983rgR8BzZvs97WPqh0fo+44vdEfDVwNXAP+5b94fV9V9VfX/gOXAOVV1bVU9VlUXAA8Dr+4ezwD+a1U9WlWfA9ZPs72lwCHA+6vqh1X146q6epq2k70NOK+qbqiqh4EP0TuiX9TX5qyqeqCqvgd8BTiym/4ova6UQ3Zym6+mF3xnVdUjVfVlemF5Wl+bL1bVP1TV41X14wHXO4hLquq6qtpGL9CPnDT/FOAc4ISqum7SvOn2w9uAT1TVxuqdK/kQcGrXrXYFcHSS/YDXAB+n90EF8Avd/AmPAqu613sd8BADnCfR7DDQ9x1vrKqDquqFVfXvuvCesKlv+IXA+7qv8A90HwIL6YXzIcCWquq/o9sd02xvIXBHF1I765D+9XaBdC8wv6/NXX3DP6IXxgAfAAJc13WbvHMntrmpqh7vm3bHpG1uYs+Y7rlMeC9wcVV9cyeW3W4fdsNzgedX1XfonRw/EjiG3gfXnUlezJMD/d5Jr+FU9elpwkAX9L66T9gE/FEX/hOPZ1XVhcA/AfMn+mk7h06zzk3AodOcaJ3pFp930vtgASDJAcBzgS0zPpGqu6rq3VV1CPBvgT8b8Gd/dwILu6PWCYdO2uau3Jr0h8CzJkaS/PQurOMU4I1JztiJZbbbh/Seyzbg7m78CnpdZvOqd17lCnrda88BbtyFGvU0YKBrsk8D70nyqvQckOTEJM8GvkYvFH47yTOSvIle18pUrqP3AXBWt45nJpn4Wn83sCDJvGmWvRB4R5Ijk+xPr3vo2qq6fabik5ySZEE3ej+9EH58B4tMuJbe0ecHuud2LPAGYM0Ay+7ITcBLu+fyTHo/a9xZdwKvBc5I8psDLnMh8DtJDktyIL19eFHf0fYVwArgym788m786qp6bBdq1NOAga7tVNUY8G7gk/QCcZzeiT2q6hHgTd34fcBb6Z1sm2o9j9ELxCOA7wGbu/YAX6Z3YvauJPdMsezfA38A/C96HwqHA6cO+BReCVzb/YplLXBGVW2caaHuub0BOIHeCdk/A369qr414HanW++36Z1U/Ht6vyIatE9/8nq+Ry/UVyZ51wCLnAd8hl5gfxf4MfDv++ZfATybfw70q+l9k7gS7bWyfXeoJGlv5RG6JDXCQJekRhjoktSIgQI9ybIkt3aXYq+cps2vJrm5++3vZ4dbpiRpJjOeFE3vJkTfBl5H75cK64HTqurmvjaLgYuB46rq/iTPq6rv72i9Bx98cC1atGg3y5ekfcv1119/T1WNTDVvkLvrLQXGJ376lWQNcDJwc1+bdwOrq+p+gJnCHGDRokWMjY0NsHlJ0oQk012dPVCXy3y2v+R5M9tfDg3wIuBFSf4hyTVJlk1TyPIkY0nGtm7dOsCmJUmDGtZJ0bnAYnp3ZzsN+HSSgyY3qqpzq2q0qkZHRqb8xiBJ2kWDBPoWejdamrCAJ99TYzOwtrsj23fp9bkvHk6JkqRBDBLo64HF3T0h5tG7BHvtpDZfoPtvt5IcTK8LZsbLrSVJwzNjoHc381kBXAbcQu82nhuSrOr7H10uA+5NcjO9ezK/v6ru3VNFS5KebNbu5TI6Olr+ykWSdk6S66tqdKp5XikqSY0w0CWpEQa6JDVikCtFJe2DFq28dLZLaNbtZ524R9brEbokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQa6JDXCQJekRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWqEgS5JjRgo0JMsS3JrkvEkK6eYf3qSrUlu7B7vGn6pkqQdmTtTgyRzgNXA64DNwPoka6vq5klNL6qqFXugRknSAAY5Ql8KjFfVxqp6BFgDnLxny5Ik7axBAn0+sKlvfHM3bbI3J/l6ks8lWTjVipIsTzKWZGzr1q27UK4kaTrDOin618Ciqno58HfABVM1qqpzq2q0qkZHRkaGtGlJEgwW6FuA/iPuBd20J1TVvVX1cDf6F8DPDac8SdKgBgn09cDiJIclmQecCqztb5DkBX2jJwG3DK9ESdIgZvyVS1VtS7ICuAyYA5xXVRuSrALGqmot8NtJTgK2AfcBp+/BmiVJU5gx0AGqah2wbtK0M/uGPwR8aLilSZJ2hleKSlIjDHRJaoSBLkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWqEgS5JjTDQJakRBrokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQa6JDXCQJekRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNGCjQkyxLcmuS8SQrd9DuzUkqyejwSpQkDWLGQE8yB1gNnAAsAU5LsmSKds8GzgCuHXaRkqSZDXKEvhQYr6qNVfUIsAY4eYp2fwh8DPjxEOuTJA1okECfD2zqG9/cTXtCklcAC6vq0h2tKMnyJGNJxrZu3brTxUqSprfbJ0WT7Ad8AnjfTG2r6tyqGq2q0ZGRkd3dtCSpzyCBvgVY2De+oJs24dnAy4DLk9wOvBpY64lRSXpqDRLo64HFSQ5LMg84FVg7MbOqHqyqg6tqUVUtAq4BTqqqsT1SsSRpSjMGelVtA1YAlwG3ABdX1YYkq5KctKcLlCQNZu4gjapqHbBu0rQzp2l77O6XJUnaWV4pKkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWqEgS5JjTDQJakRBrokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQa6JDXCQJekRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNMNAlqREGuiQ1YqBAT7Isya1JxpOsnGL+e5J8I8mNSa5OsmT4pUqSdmTGQE8yB1gNnAAsAU6bIrA/W1X/sqqOBD4OfGLolUqSdmiQI/SlwHhVbayqR4A1wMn9Darq//aNHgDU8EqUJA1i7gBt5gOb+sY3A6+a3CjJbwG/C8wDjptqRUmWA8sBDj300J2tVZK0A0M7KVpVq6vqcOCDwIenaXNuVY1W1ejIyMiwNi1JYrBA3wIs7Btf0E2bzhrgjbtTlCRp5w0S6OuBxUkOSzIPOBVY298gyeK+0ROB24ZXoiRpEDP2oVfVtiQrgMuAOcB5VbUhySpgrKrWAiuSHA88CtwPvH1PFi1JerJBTopSVeuAdZOmndk3fMaQ65Ik7SSvFJWkRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWqEgS5JjTDQJakRBrokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQa6JDXCQJekRhjoktSIubNdwK5YtPLS2S6hWbefdeIeWa+v2Z6zp14z7X0GOkJPsizJrUnGk6ycYv7vJrk5ydeTfCnJC4dfqiRpR2YM9CRzgNXACcAS4LQkSyY1+0dgtKpeDnwO+PiwC5Uk7dggR+hLgfGq2lhVjwBrgJP7G1TVV6rqR93oNcCC4ZYpSZrJIIE+H9jUN765mzad3wD+ZqoZSZYnGUsytnXr1sGrlCTNaKi/cknya8AocPZU86vq3KoararRkZGRYW5akvZ5g/zKZQuwsG98QTdtO0mOB34f+IWqeng45UmSBjXIEfp6YHGSw5LMA04F1vY3SHIUcA5wUlV9f/hlSpJmMmOgV9U2YAVwGXALcHFVbUiyKslJXbOzgQOBv0pyY5K106xOkrSHDHRhUVWtA9ZNmnZm3/DxQ65LkrSTvPRfkhphoEtSIwx0SWqEgS5JjTDQJakRBrokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQa6JDXCQJekRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWrEQIGeZFmSW5OMJ1k5xfzXJLkhybYkbxl+mZKkmcwY6EnmAKuBE4AlwGlJlkxq9j3gdOCzwy5QkjSYuQO0WQqMV9VGgCRrgJOBmycaVNXt3bzH90CNkqQBDNLlMh/Y1De+uZu205IsTzKWZGzr1q27sgpJ0jSe0pOiVXVuVY1W1ejIyMhTuWlJat4ggb4FWNg3vqCbJkl6Ghkk0NcDi5MclmQecCqwds+WJUnaWTMGelVtA1YAlwG3ABdX1YYkq5KcBJDklUk2A6cA5yTZsCeLliQ92SC/cqGq1gHrJk07s294Pb2uGEnSLPFKUUlqhIEuSY0w0CWpEQa6JDXCQJekRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWqEgS5JjTDQJakRBrokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQMFepJlSW5NMp5k5RTz909yUTf/2iSLhl2oJGnHZgz0JHOA1cAJwBLgtCRLJjX7DeD+qjoC+BPgY8MuVJK0Y4McoS8FxqtqY1U9AqwBTp7U5mTggm74c8Brk2R4ZUqSZjJ3gDbzgU1945uBV03Xpqq2JXkQeC5wT3+jJMuB5d3oQ0lu3ZWi90IHM2lfPF3F71awF71e4GvW2ZdesxdON2OQQB+aqjoXOPep3ObTQZKxqhqd7To0GF+vvY+vWc8gXS5bgIV94wu6aVO2STIX+Eng3mEUKEkazCCBvh5YnOSwJPOAU4G1k9qsBd7eDb8F+HJV1fDKlCTNZMYul65PfAVwGTAHOK+qNiRZBYxV1VrgvwOfSTIO3Ecv9PXP9rlupr2cr9fex9cMiAfSktQGrxSVpEYY6JLUCANd0tNWktOTfHK269hbGOiS1AgDfTclWZXkvX3jf5TkjCTvT7I+ydeT/Kdu3gFJLk1yU5JvJnnr7FUugCSLktyS5NNJNiT52yQ/keTIJNd0r98lSZ4z27W2oNvf3+wb/70kH0lyeZKPJbkuybeTHDPFsicm+VqSg5Ocn+S/Jflqko1J3tK1SZKzu7+vb0z8jSVZneSkbviSJOd1w+/s/manfB88NXtleAz03Xce8OsASfaj95PNu4DF9O6DcyTwc0leAywD7qyqn62qlwH/Z3ZK1iSLgdVV9VLgAeDNwF8CH6yqlwPfAP7jLNa3r5hbVUuB9zJpfyf5FWAl8PqqmrjE/wXA0cAvA2d1095E72/uZ4HjgbOTvAC4Cpj4kJhP70aDdNOu7Ianeh/sVQz03VRVtwP3JjkK+CXgH4FX9g3fAPwLem+WbwCv645EjqmqB2enak3y3aq6sRu+HjgcOKiqruimXQC8ZlYq27d8vvv3emBR3/TjgA8CJ1bV/X3Tv1BVj1fVzcDzu2lHAxdW1WNVdTdwBb2/x6uAY7o7xd4M3N0F/c8DX+2Wnfw+6K9hr/CU3sulYX8BnA78NL0j9tcCf1xV50xumOQVwOuBjyb5UlWteioL1ZQe7ht+DDhotgrZB2xj+wPJZ/YNT7wOj7F9Nn0H+BngRcDYFO0Bdnh316rakuQget+SrwR+CvhV4KGq+kGS5/Lk94FdLvuoS+i9UV5J74ray4B3JjkQIMn8JM9Lcgjwo6r6H8DZwCtmq2Dt0IPA/X39uP+G3pGedt/dwPOSPDfJ/vS6S2ZyB103WJKXztD2KuCtSeYkGaH3zeq6bt419Lpzruza/V73bzM8Qh+CqnokyVeAB6rqMeBvk7wE+Fp3W/iHgF8DjqDXp/c48Cjwm7NVs2b0duBTSZ4FbATeMcv1NKGqHu1uG3IdvZv6fWvA5b6V5G3AXyV5ww6aXkKvG+UmoIAPVNVd3byrgF+qqvEkd9A7Sm8q0L30fwi6k6E3AKdU1W2zXY+kfZNdLrupO8kyDnzJMJc0mzxCl6RGeIQuSY0w0CWpEQa6JDXCQJekRhjoktSI/w/TIK6YopbnBgAAAABJRU5ErkJggg==",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/b737ee80_nohash_1.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/feb1d305_nohash_2.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/07ad9b59_nohash_2.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/5c39594f_nohash_4.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/2d92f18b_nohash_0.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/b83c1acf_nohash_2.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAEICAYAAABPgw/pAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAUd0lEQVR4nO3df7RdZX3n8feHxGAFV7FytZIEQyE6RseCvUa7BixF7ApSwapUGDsVrWbsNFNsrRqnlnFSO0WZZWdNTSvYYUGdkUAd0XRIh7Yqv6pALhTUgMg1gkkoGH6O6AgEvvPH2ZeeXO7NPUlOuOTJ+7XWWdk/nr339+xz7ufs8+yzd1JVSJL2fvvNdgGSpOEw0CWpEQa6JDXCQJekRhjoktQIA12SGmGga7ckOT/JR7vhY5Lcuovr+VSSPxhudTNu81eSbEryUJKjnsptDypJJTlituvQ3mHubBegPS/J7cDzgceAHwJ/A6yoqoeGuZ2qugp48QD1nA68q6qO7lv2PcOsZUD/hd5++OIwVpbkcuAjwLEAVfWRYaz36SrJ+cDl3eixVXX6rBUjwCP0fckbqupA4BXAKPDhyQ2S7Gsf8C8ENuzKgknmDLkWabcZ6PuYqtpC7wj9ZfDEV/rfSnIbcFs37ZeT3JjkgSRfTfLyieWTHJXkhiQ/SHIR8My+eccm2dw3vjDJ55NsTXJvkk8meQnwKeDnu66OB7q2T3TddOPvTjKe5L4ka5Mc0jevkrwnyW1djauTpJt3RJIrkjyY5J6uxu0k2T/JQ8Ac4KYk3+mmvyTJ5d06NyQ5qW+Z85P8eZJ1SX4I/OIg+zvJ6UmunjTtiW6Ubr2rk1za7dNrkxw+zbqO7rqIjh1gP+yX5MNJ7kjy/SR/meQnu3kXJHlfNzx/4j3QjR/e7fP9Jl7PJO/r1vFPSd4xyPPWLKkqH40/gNuB47vhhfSOSv+wGy/g74CfAn4COAr4PvAqeoH39m75/YF5wB3A7wDPAN4CPAp8tFvXscDmbngOcBPwJ8AB9IL/6G7e6cDVk2o8v289xwH30Ps2sT/wp8CVfW0L+N/AQcChwFZgWTfvQuD36R2sPLHNafZLAUd0w88AxoH/0D3P44AfAC/uq+9B4F9NrHvAfT/Vc+3f7vnAvcBSel2g/xNYM7ktsAzYBCwdcD+8s3s+PwMcCHwe+EzfvL/uhv818B3gor55X+x7PbcBq7r983rgR8BzZvs97WPqh0fo+44vdEfDVwNXAP+5b94fV9V9VfX/gOXAOVV1bVU9VlUXAA8Dr+4ezwD+a1U9WlWfA9ZPs72lwCHA+6vqh1X146q6epq2k70NOK+qbqiqh4EP0TuiX9TX5qyqeqCqvgd8BTiym/4ova6UQ3Zym6+mF3xnVdUjVfVlemF5Wl+bL1bVP1TV41X14wHXO4hLquq6qtpGL9CPnDT/FOAc4ISqum7SvOn2w9uAT1TVxuqdK/kQcGrXrXYFcHSS/YDXAB+n90EF8Avd/AmPAqu613sd8BADnCfR7DDQ9x1vrKqDquqFVfXvuvCesKlv+IXA+7qv8A90HwIL6YXzIcCWquq/o9sd02xvIXBHF1I765D+9XaBdC8wv6/NXX3DP6IXxgAfAAJc13WbvHMntrmpqh7vm3bHpG1uYs+Y7rlMeC9wcVV9cyeW3W4fdsNzgedX1XfonRw/EjiG3gfXnUlezJMD/d5Jr+FU9elpwkAX9L66T9gE/FEX/hOPZ1XVhcA/AfMn+mk7h06zzk3AodOcaJ3pFp930vtgASDJAcBzgS0zPpGqu6rq3VV1CPBvgT8b8Gd/dwILu6PWCYdO2uau3Jr0h8CzJkaS/PQurOMU4I1JztiJZbbbh/Seyzbg7m78CnpdZvOqd17lCnrda88BbtyFGvU0YKBrsk8D70nyqvQckOTEJM8GvkYvFH47yTOSvIle18pUrqP3AXBWt45nJpn4Wn83sCDJvGmWvRB4R5Ijk+xPr3vo2qq6fabik5ySZEE3ej+9EH58B4tMuJbe0ecHuud2LPAGYM0Ay+7ITcBLu+fyTHo/a9xZdwKvBc5I8psDLnMh8DtJDktyIL19eFHf0fYVwArgym788m786qp6bBdq1NOAga7tVNUY8G7gk/QCcZzeiT2q6hHgTd34fcBb6Z1sm2o9j9ELxCOA7wGbu/YAX6Z3YvauJPdMsezfA38A/C96HwqHA6cO+BReCVzb/YplLXBGVW2caaHuub0BOIHeCdk/A369qr414HanW++36Z1U/Ht6vyIatE9/8nq+Ry/UVyZ51wCLnAd8hl5gfxf4MfDv++ZfATybfw70q+l9k7gS7bWyfXeoJGlv5RG6JDXCQJekRhjoktSIgQI9ybIkt3aXYq+cps2vJrm5++3vZ4dbpiRpJjOeFE3vJkTfBl5H75cK64HTqurmvjaLgYuB46rq/iTPq6rv72i9Bx98cC1atGg3y5ekfcv1119/T1WNTDVvkLvrLQXGJ376lWQNcDJwc1+bdwOrq+p+gJnCHGDRokWMjY0NsHlJ0oQk012dPVCXy3y2v+R5M9tfDg3wIuBFSf4hyTVJlk1TyPIkY0nGtm7dOsCmJUmDGtZJ0bnAYnp3ZzsN+HSSgyY3qqpzq2q0qkZHRqb8xiBJ2kWDBPoWejdamrCAJ99TYzOwtrsj23fp9bkvHk6JkqRBDBLo64HF3T0h5tG7BHvtpDZfoPtvt5IcTK8LZsbLrSVJwzNjoHc381kBXAbcQu82nhuSrOr7H10uA+5NcjO9ezK/v6ru3VNFS5KebNbu5TI6Olr+ykWSdk6S66tqdKp5XikqSY0w0CWpEQa6JDVikCtFJe2DFq28dLZLaNbtZ524R9brEbokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQa6JDXCQJekRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWqEgS5JjRgo0JMsS3JrkvEkK6eYf3qSrUlu7B7vGn6pkqQdmTtTgyRzgNXA64DNwPoka6vq5klNL6qqFXugRknSAAY5Ql8KjFfVxqp6BFgDnLxny5Ik7axBAn0+sKlvfHM3bbI3J/l6ks8lWTjVipIsTzKWZGzr1q27UK4kaTrDOin618Ciqno58HfABVM1qqpzq2q0qkZHRkaGtGlJEgwW6FuA/iPuBd20J1TVvVX1cDf6F8DPDac8SdKgBgn09cDiJIclmQecCqztb5DkBX2jJwG3DK9ESdIgZvyVS1VtS7ICuAyYA5xXVRuSrALGqmot8NtJTgK2AfcBp+/BmiVJU5gx0AGqah2wbtK0M/uGPwR8aLilSZJ2hleKSlIjDHRJaoSBLkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWqEgS5JjTDQJakRBrokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQa6JDXCQJekRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNGCjQkyxLcmuS8SQrd9DuzUkqyejwSpQkDWLGQE8yB1gNnAAsAU5LsmSKds8GzgCuHXaRkqSZDXKEvhQYr6qNVfUIsAY4eYp2fwh8DPjxEOuTJA1okECfD2zqG9/cTXtCklcAC6vq0h2tKMnyJGNJxrZu3brTxUqSprfbJ0WT7Ad8AnjfTG2r6tyqGq2q0ZGRkd3dtCSpzyCBvgVY2De+oJs24dnAy4DLk9wOvBpY64lRSXpqDRLo64HFSQ5LMg84FVg7MbOqHqyqg6tqUVUtAq4BTqqqsT1SsSRpSjMGelVtA1YAlwG3ABdX1YYkq5KctKcLlCQNZu4gjapqHbBu0rQzp2l77O6XJUnaWV4pKkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWqEgS5JjTDQJakRBrokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQa6JDXCQJekRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNMNAlqREGuiQ1YqBAT7Isya1JxpOsnGL+e5J8I8mNSa5OsmT4pUqSdmTGQE8yB1gNnAAsAU6bIrA/W1X/sqqOBD4OfGLolUqSdmiQI/SlwHhVbayqR4A1wMn9Darq//aNHgDU8EqUJA1i7gBt5gOb+sY3A6+a3CjJbwG/C8wDjptqRUmWA8sBDj300J2tVZK0A0M7KVpVq6vqcOCDwIenaXNuVY1W1ejIyMiwNi1JYrBA3wIs7Btf0E2bzhrgjbtTlCRp5w0S6OuBxUkOSzIPOBVY298gyeK+0ROB24ZXoiRpEDP2oVfVtiQrgMuAOcB5VbUhySpgrKrWAiuSHA88CtwPvH1PFi1JerJBTopSVeuAdZOmndk3fMaQ65Ik7SSvFJWkRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWqEgS5JjTDQJakRBrokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQa6JDXCQJekRhjoktSIubNdwK5YtPLS2S6hWbefdeIeWa+v2Z6zp14z7X0GOkJPsizJrUnGk6ycYv7vJrk5ydeTfCnJC4dfqiRpR2YM9CRzgNXACcAS4LQkSyY1+0dgtKpeDnwO+PiwC5Uk7dggR+hLgfGq2lhVjwBrgJP7G1TVV6rqR93oNcCC4ZYpSZrJIIE+H9jUN765mzad3wD+ZqoZSZYnGUsytnXr1sGrlCTNaKi/cknya8AocPZU86vq3KoararRkZGRYW5akvZ5g/zKZQuwsG98QTdtO0mOB34f+IWqeng45UmSBjXIEfp6YHGSw5LMA04F1vY3SHIUcA5wUlV9f/hlSpJmMmOgV9U2YAVwGXALcHFVbUiyKslJXbOzgQOBv0pyY5K106xOkrSHDHRhUVWtA9ZNmnZm3/DxQ65LkrSTvPRfkhphoEtSIwx0SWqEgS5JjTDQJakRBrokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQa6JDXCQJekRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWrEQIGeZFmSW5OMJ1k5xfzXJLkhybYkbxl+mZKkmcwY6EnmAKuBE4AlwGlJlkxq9j3gdOCzwy5QkjSYuQO0WQqMV9VGgCRrgJOBmycaVNXt3bzH90CNkqQBDNLlMh/Y1De+uZu205IsTzKWZGzr1q27sgpJ0jSe0pOiVXVuVY1W1ejIyMhTuWlJat4ggb4FWNg3vqCbJkl6Ghkk0NcDi5MclmQecCqwds+WJUnaWTMGelVtA1YAlwG3ABdX1YYkq5KcBJDklUk2A6cA5yTZsCeLliQ92SC/cqGq1gHrJk07s294Pb2uGEnSLPFKUUlqhIEuSY0w0CWpEQa6JDXCQJekRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWqEgS5JjTDQJakRBrokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQMFepJlSW5NMp5k5RTz909yUTf/2iSLhl2oJGnHZgz0JHOA1cAJwBLgtCRLJjX7DeD+qjoC+BPgY8MuVJK0Y4McoS8FxqtqY1U9AqwBTp7U5mTggm74c8Brk2R4ZUqSZjJ3gDbzgU1945uBV03Xpqq2JXkQeC5wT3+jJMuB5d3oQ0lu3ZWi90IHM2lfPF3F71awF71e4GvW2ZdesxdON2OQQB+aqjoXOPep3ObTQZKxqhqd7To0GF+vvY+vWc8gXS5bgIV94wu6aVO2STIX+Eng3mEUKEkazCCBvh5YnOSwJPOAU4G1k9qsBd7eDb8F+HJV1fDKlCTNZMYul65PfAVwGTAHOK+qNiRZBYxV1VrgvwOfSTIO3Ecv9PXP9rlupr2cr9fex9cMiAfSktQGrxSVpEYY6JLUCANd0tNWktOTfHK269hbGOiS1AgDfTclWZXkvX3jf5TkjCTvT7I+ydeT/Kdu3gFJLk1yU5JvJnnr7FUugCSLktyS5NNJNiT52yQ/keTIJNd0r98lSZ4z27W2oNvf3+wb/70kH0lyeZKPJbkuybeTHDPFsicm+VqSg5Ocn+S/Jflqko1J3tK1SZKzu7+vb0z8jSVZneSkbviSJOd1w+/s/manfB88NXtleAz03Xce8OsASfaj95PNu4DF9O6DcyTwc0leAywD7qyqn62qlwH/Z3ZK1iSLgdVV9VLgAeDNwF8CH6yqlwPfAP7jLNa3r5hbVUuB9zJpfyf5FWAl8PqqmrjE/wXA0cAvA2d1095E72/uZ4HjgbOTvAC4Cpj4kJhP70aDdNOu7Ianeh/sVQz03VRVtwP3JjkK+CXgH4FX9g3fAPwLem+WbwCv645EjqmqB2enak3y3aq6sRu+HjgcOKiqruimXQC8ZlYq27d8vvv3emBR3/TjgA8CJ1bV/X3Tv1BVj1fVzcDzu2lHAxdW1WNVdTdwBb2/x6uAY7o7xd4M3N0F/c8DX+2Wnfw+6K9hr/CU3sulYX8BnA78NL0j9tcCf1xV50xumOQVwOuBjyb5UlWteioL1ZQe7ht+DDhotgrZB2xj+wPJZ/YNT7wOj7F9Nn0H+BngRcDYFO0Bdnh316rakuQget+SrwR+CvhV4KGq+kGS5/Lk94FdLvuoS+i9UV5J74ray4B3JjkQIMn8JM9Lcgjwo6r6H8DZwCtmq2Dt0IPA/X39uP+G3pGedt/dwPOSPDfJ/vS6S2ZyB103WJKXztD2KuCtSeYkGaH3zeq6bt419Lpzruza/V73bzM8Qh+CqnokyVeAB6rqMeBvk7wE+Fp3W/iHgF8DjqDXp/c48Cjwm7NVs2b0duBTSZ4FbATeMcv1NKGqHu1uG3IdvZv6fWvA5b6V5G3AXyV5ww6aXkKvG+UmoIAPVNVd3byrgF+qqvEkd9A7Sm8q0L30fwi6k6E3AKdU1W2zXY+kfZNdLrupO8kyDnzJMJc0mzxCl6RGeIQuSY0w0CWpEQa6JDXCQJekRhjoktSI/w/TIK6YopbnBgAAAABJRU5ErkJggg==",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/4a1e736b_nohash_4.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/8012c69d_nohash_2.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/71f6fed7_nohash_2.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/ec21c46b_nohash_2.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/2f0a410b_nohash_1.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/f2a90886_nohash_0.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/dbb40d24_nohash_0.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/b9515bf3_nohash_1.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/15c563d7_nohash_3.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/f4504600_nohash_1.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/da76aa58_nohash_1.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/dedc7fab_nohash_1.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAEICAYAAABPgw/pAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAUd0lEQVR4nO3df7RdZX3n8feHxGAFV7FytZIEQyE6RseCvUa7BixF7ApSwapUGDsVrWbsNFNsrRqnlnFSO0WZZWdNTSvYYUGdkUAd0XRIh7Yqv6pALhTUgMg1gkkoGH6O6AgEvvPH2ZeeXO7NPUlOuOTJ+7XWWdk/nr339+xz7ufs8+yzd1JVSJL2fvvNdgGSpOEw0CWpEQa6JDXCQJekRhjoktQIA12SGmGga7ckOT/JR7vhY5Lcuovr+VSSPxhudTNu81eSbEryUJKjnsptDypJJTlituvQ3mHubBegPS/J7cDzgceAHwJ/A6yoqoeGuZ2qugp48QD1nA68q6qO7lv2PcOsZUD/hd5++OIwVpbkcuAjwLEAVfWRYaz36SrJ+cDl3eixVXX6rBUjwCP0fckbqupA4BXAKPDhyQ2S7Gsf8C8ENuzKgknmDLkWabcZ6PuYqtpC7wj9ZfDEV/rfSnIbcFs37ZeT3JjkgSRfTfLyieWTHJXkhiQ/SHIR8My+eccm2dw3vjDJ55NsTXJvkk8meQnwKeDnu66OB7q2T3TddOPvTjKe5L4ka5Mc0jevkrwnyW1djauTpJt3RJIrkjyY5J6uxu0k2T/JQ8Ac4KYk3+mmvyTJ5d06NyQ5qW+Z85P8eZJ1SX4I/OIg+zvJ6UmunjTtiW6Ubr2rk1za7dNrkxw+zbqO7rqIjh1gP+yX5MNJ7kjy/SR/meQnu3kXJHlfNzx/4j3QjR/e7fP9Jl7PJO/r1vFPSd4xyPPWLKkqH40/gNuB47vhhfSOSv+wGy/g74CfAn4COAr4PvAqeoH39m75/YF5wB3A7wDPAN4CPAp8tFvXscDmbngOcBPwJ8AB9IL/6G7e6cDVk2o8v289xwH30Ps2sT/wp8CVfW0L+N/AQcChwFZgWTfvQuD36R2sPLHNafZLAUd0w88AxoH/0D3P44AfAC/uq+9B4F9NrHvAfT/Vc+3f7vnAvcBSel2g/xNYM7ktsAzYBCwdcD+8s3s+PwMcCHwe+EzfvL/uhv818B3gor55X+x7PbcBq7r983rgR8BzZvs97WPqh0fo+44vdEfDVwNXAP+5b94fV9V9VfX/gOXAOVV1bVU9VlUXAA8Dr+4ezwD+a1U9WlWfA9ZPs72lwCHA+6vqh1X146q6epq2k70NOK+qbqiqh4EP0TuiX9TX5qyqeqCqvgd8BTiym/4ova6UQ3Zym6+mF3xnVdUjVfVlemF5Wl+bL1bVP1TV41X14wHXO4hLquq6qtpGL9CPnDT/FOAc4ISqum7SvOn2w9uAT1TVxuqdK/kQcGrXrXYFcHSS/YDXAB+n90EF8Avd/AmPAqu613sd8BADnCfR7DDQ9x1vrKqDquqFVfXvuvCesKlv+IXA+7qv8A90HwIL6YXzIcCWquq/o9sd02xvIXBHF1I765D+9XaBdC8wv6/NXX3DP6IXxgAfAAJc13WbvHMntrmpqh7vm3bHpG1uYs+Y7rlMeC9wcVV9cyeW3W4fdsNzgedX1XfonRw/EjiG3gfXnUlezJMD/d5Jr+FU9elpwkAX9L66T9gE/FEX/hOPZ1XVhcA/AfMn+mk7h06zzk3AodOcaJ3pFp930vtgASDJAcBzgS0zPpGqu6rq3VV1CPBvgT8b8Gd/dwILu6PWCYdO2uau3Jr0h8CzJkaS/PQurOMU4I1JztiJZbbbh/Seyzbg7m78CnpdZvOqd17lCnrda88BbtyFGvU0YKBrsk8D70nyqvQckOTEJM8GvkYvFH47yTOSvIle18pUrqP3AXBWt45nJpn4Wn83sCDJvGmWvRB4R5Ijk+xPr3vo2qq6fabik5ySZEE3ej+9EH58B4tMuJbe0ecHuud2LPAGYM0Ay+7ITcBLu+fyTHo/a9xZdwKvBc5I8psDLnMh8DtJDktyIL19eFHf0fYVwArgym788m786qp6bBdq1NOAga7tVNUY8G7gk/QCcZzeiT2q6hHgTd34fcBb6Z1sm2o9j9ELxCOA7wGbu/YAX6Z3YvauJPdMsezfA38A/C96HwqHA6cO+BReCVzb/YplLXBGVW2caaHuub0BOIHeCdk/A369qr414HanW++36Z1U/Ht6vyIatE9/8nq+Ry/UVyZ51wCLnAd8hl5gfxf4MfDv++ZfATybfw70q+l9k7gS7bWyfXeoJGlv5RG6JDXCQJekRhjoktSIgQI9ybIkt3aXYq+cps2vJrm5++3vZ4dbpiRpJjOeFE3vJkTfBl5H75cK64HTqurmvjaLgYuB46rq/iTPq6rv72i9Bx98cC1atGg3y5ekfcv1119/T1WNTDVvkLvrLQXGJ376lWQNcDJwc1+bdwOrq+p+gJnCHGDRokWMjY0NsHlJ0oQk012dPVCXy3y2v+R5M9tfDg3wIuBFSf4hyTVJlk1TyPIkY0nGtm7dOsCmJUmDGtZJ0bnAYnp3ZzsN+HSSgyY3qqpzq2q0qkZHRqb8xiBJ2kWDBPoWejdamrCAJ99TYzOwtrsj23fp9bkvHk6JkqRBDBLo64HF3T0h5tG7BHvtpDZfoPtvt5IcTK8LZsbLrSVJwzNjoHc381kBXAbcQu82nhuSrOr7H10uA+5NcjO9ezK/v6ru3VNFS5KebNbu5TI6Olr+ykWSdk6S66tqdKp5XikqSY0w0CWpEQa6JDVikCtFJe2DFq28dLZLaNbtZ524R9brEbokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQa6JDXCQJekRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWqEgS5JjRgo0JMsS3JrkvEkK6eYf3qSrUlu7B7vGn6pkqQdmTtTgyRzgNXA64DNwPoka6vq5klNL6qqFXugRknSAAY5Ql8KjFfVxqp6BFgDnLxny5Ik7axBAn0+sKlvfHM3bbI3J/l6ks8lWTjVipIsTzKWZGzr1q27UK4kaTrDOin618Ciqno58HfABVM1qqpzq2q0qkZHRkaGtGlJEgwW6FuA/iPuBd20J1TVvVX1cDf6F8DPDac8SdKgBgn09cDiJIclmQecCqztb5DkBX2jJwG3DK9ESdIgZvyVS1VtS7ICuAyYA5xXVRuSrALGqmot8NtJTgK2AfcBp+/BmiVJU5gx0AGqah2wbtK0M/uGPwR8aLilSZJ2hleKSlIjDHRJaoSBLkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWqEgS5JjTDQJakRBrokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQa6JDXCQJekRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNGCjQkyxLcmuS8SQrd9DuzUkqyejwSpQkDWLGQE8yB1gNnAAsAU5LsmSKds8GzgCuHXaRkqSZDXKEvhQYr6qNVfUIsAY4eYp2fwh8DPjxEOuTJA1okECfD2zqG9/cTXtCklcAC6vq0h2tKMnyJGNJxrZu3brTxUqSprfbJ0WT7Ad8AnjfTG2r6tyqGq2q0ZGRkd3dtCSpzyCBvgVY2De+oJs24dnAy4DLk9wOvBpY64lRSXpqDRLo64HFSQ5LMg84FVg7MbOqHqyqg6tqUVUtAq4BTqqqsT1SsSRpSjMGelVtA1YAlwG3ABdX1YYkq5KctKcLlCQNZu4gjapqHbBu0rQzp2l77O6XJUnaWV4pKkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWqEgS5JjTDQJakRBrokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQa6JDXCQJekRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNMNAlqREGuiQ1YqBAT7Isya1JxpOsnGL+e5J8I8mNSa5OsmT4pUqSdmTGQE8yB1gNnAAsAU6bIrA/W1X/sqqOBD4OfGLolUqSdmiQI/SlwHhVbayqR4A1wMn9Darq//aNHgDU8EqUJA1i7gBt5gOb+sY3A6+a3CjJbwG/C8wDjptqRUmWA8sBDj300J2tVZK0A0M7KVpVq6vqcOCDwIenaXNuVY1W1ejIyMiwNi1JYrBA3wIs7Btf0E2bzhrgjbtTlCRp5w0S6OuBxUkOSzIPOBVY298gyeK+0ROB24ZXoiRpEDP2oVfVtiQrgMuAOcB5VbUhySpgrKrWAiuSHA88CtwPvH1PFi1JerJBTopSVeuAdZOmndk3fMaQ65Ik7SSvFJWkRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWqEgS5JjTDQJakRBrokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQa6JDXCQJekRhjoktSIubNdwK5YtPLS2S6hWbefdeIeWa+v2Z6zp14z7X0GOkJPsizJrUnGk6ycYv7vJrk5ydeTfCnJC4dfqiRpR2YM9CRzgNXACcAS4LQkSyY1+0dgtKpeDnwO+PiwC5Uk7dggR+hLgfGq2lhVjwBrgJP7G1TVV6rqR93oNcCC4ZYpSZrJIIE+H9jUN765mzad3wD+ZqoZSZYnGUsytnXr1sGrlCTNaKi/cknya8AocPZU86vq3KoararRkZGRYW5akvZ5g/zKZQuwsG98QTdtO0mOB34f+IWqeng45UmSBjXIEfp6YHGSw5LMA04F1vY3SHIUcA5wUlV9f/hlSpJmMmOgV9U2YAVwGXALcHFVbUiyKslJXbOzgQOBv0pyY5K106xOkrSHDHRhUVWtA9ZNmnZm3/DxQ65LkrSTvPRfkhphoEtSIwx0SWqEgS5JjTDQJakRBrokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQa6JDXCQJekRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWrEQIGeZFmSW5OMJ1k5xfzXJLkhybYkbxl+mZKkmcwY6EnmAKuBE4AlwGlJlkxq9j3gdOCzwy5QkjSYuQO0WQqMV9VGgCRrgJOBmycaVNXt3bzH90CNkqQBDNLlMh/Y1De+uZu205IsTzKWZGzr1q27sgpJ0jSe0pOiVXVuVY1W1ejIyMhTuWlJat4ggb4FWNg3vqCbJkl6Ghkk0NcDi5MclmQecCqwds+WJUnaWTMGelVtA1YAlwG3ABdX1YYkq5KcBJDklUk2A6cA5yTZsCeLliQ92SC/cqGq1gHrJk07s294Pb2uGEnSLPFKUUlqhIEuSY0w0CWpEQa6JDXCQJekRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWqEgS5JjTDQJakRBrokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQMFepJlSW5NMp5k5RTz909yUTf/2iSLhl2oJGnHZgz0JHOA1cAJwBLgtCRLJjX7DeD+qjoC+BPgY8MuVJK0Y4McoS8FxqtqY1U9AqwBTp7U5mTggm74c8Brk2R4ZUqSZjJ3gDbzgU1945uBV03Xpqq2JXkQeC5wT3+jJMuB5d3oQ0lu3ZWi90IHM2lfPF3F71awF71e4GvW2ZdesxdON2OQQB+aqjoXOPep3ObTQZKxqhqd7To0GF+vvY+vWc8gXS5bgIV94wu6aVO2STIX+Eng3mEUKEkazCCBvh5YnOSwJPOAU4G1k9qsBd7eDb8F+HJV1fDKlCTNZMYul65PfAVwGTAHOK+qNiRZBYxV1VrgvwOfSTIO3Ecv9PXP9rlupr2cr9fex9cMiAfSktQGrxSVpEYY6JLUCANd0tNWktOTfHK269hbGOiS1AgDfTclWZXkvX3jf5TkjCTvT7I+ydeT/Kdu3gFJLk1yU5JvJnnr7FUugCSLktyS5NNJNiT52yQ/keTIJNd0r98lSZ4z27W2oNvf3+wb/70kH0lyeZKPJbkuybeTHDPFsicm+VqSg5Ocn+S/Jflqko1J3tK1SZKzu7+vb0z8jSVZneSkbviSJOd1w+/s/manfB88NXtleAz03Xce8OsASfaj95PNu4DF9O6DcyTwc0leAywD7qyqn62qlwH/Z3ZK1iSLgdVV9VLgAeDNwF8CH6yqlwPfAP7jLNa3r5hbVUuB9zJpfyf5FWAl8PqqmrjE/wXA0cAvA2d1095E72/uZ4HjgbOTvAC4Cpj4kJhP70aDdNOu7Ianeh/sVQz03VRVtwP3JjkK+CXgH4FX9g3fAPwLem+WbwCv645EjqmqB2enak3y3aq6sRu+HjgcOKiqruimXQC8ZlYq27d8vvv3emBR3/TjgA8CJ1bV/X3Tv1BVj1fVzcDzu2lHAxdW1WNVdTdwBb2/x6uAY7o7xd4M3N0F/c8DX+2Wnfw+6K9hr/CU3sulYX8BnA78NL0j9tcCf1xV50xumOQVwOuBjyb5UlWteioL1ZQe7ht+DDhotgrZB2xj+wPJZ/YNT7wOj7F9Nn0H+BngRcDYFO0Bdnh316rakuQget+SrwR+CvhV4KGq+kGS5/Lk94FdLvuoS+i9UV5J74ray4B3JjkQIMn8JM9Lcgjwo6r6H8DZwCtmq2Dt0IPA/X39uP+G3pGedt/dwPOSPDfJ/vS6S2ZyB103WJKXztD2KuCtSeYkGaH3zeq6bt419Lpzruza/V73bzM8Qh+CqnokyVeAB6rqMeBvk7wE+Fp3W/iHgF8DjqDXp/c48Cjwm7NVs2b0duBTSZ4FbATeMcv1NKGqHu1uG3IdvZv6fWvA5b6V5G3AXyV5ww6aXkKvG+UmoIAPVNVd3byrgF+qqvEkd9A7Sm8q0L30fwi6k6E3AKdU1W2zXY+kfZNdLrupO8kyDnzJMJc0mzxCl6RGeIQuSY0w0CWpEQa6JDXCQJekRhjoktSI/w/TIK6YopbnBgAAAABJRU5ErkJggg==",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/a527cb3c_nohash_0.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/26b28ea7_nohash_0.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/d84829e0_nohash_0.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAEICAYAAABPgw/pAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAUd0lEQVR4nO3df7RdZX3n8feHxGAFV7FytZIEQyE6RseCvUa7BixF7ApSwapUGDsVrWbsNFNsrRqnlnFSO0WZZWdNTSvYYUGdkUAd0XRIh7Yqv6pALhTUgMg1gkkoGH6O6AgEvvPH2ZeeXO7NPUlOuOTJ+7XWWdk/nr339+xz7ufs8+yzd1JVSJL2fvvNdgGSpOEw0CWpEQa6JDXCQJekRhjoktQIA12SGmGga7ckOT/JR7vhY5Lcuovr+VSSPxhudTNu81eSbEryUJKjnsptDypJJTlituvQ3mHubBegPS/J7cDzgceAHwJ/A6yoqoeGuZ2qugp48QD1nA68q6qO7lv2PcOsZUD/hd5++OIwVpbkcuAjwLEAVfWRYaz36SrJ+cDl3eixVXX6rBUjwCP0fckbqupA4BXAKPDhyQ2S7Gsf8C8ENuzKgknmDLkWabcZ6PuYqtpC7wj9ZfDEV/rfSnIbcFs37ZeT3JjkgSRfTfLyieWTHJXkhiQ/SHIR8My+eccm2dw3vjDJ55NsTXJvkk8meQnwKeDnu66OB7q2T3TddOPvTjKe5L4ka5Mc0jevkrwnyW1djauTpJt3RJIrkjyY5J6uxu0k2T/JQ8Ac4KYk3+mmvyTJ5d06NyQ5qW+Z85P8eZJ1SX4I/OIg+zvJ6UmunjTtiW6Ubr2rk1za7dNrkxw+zbqO7rqIjh1gP+yX5MNJ7kjy/SR/meQnu3kXJHlfNzx/4j3QjR/e7fP9Jl7PJO/r1vFPSd4xyPPWLKkqH40/gNuB47vhhfSOSv+wGy/g74CfAn4COAr4PvAqeoH39m75/YF5wB3A7wDPAN4CPAp8tFvXscDmbngOcBPwJ8AB9IL/6G7e6cDVk2o8v289xwH30Ps2sT/wp8CVfW0L+N/AQcChwFZgWTfvQuD36R2sPLHNafZLAUd0w88AxoH/0D3P44AfAC/uq+9B4F9NrHvAfT/Vc+3f7vnAvcBSel2g/xNYM7ktsAzYBCwdcD+8s3s+PwMcCHwe+EzfvL/uhv818B3gor55X+x7PbcBq7r983rgR8BzZvs97WPqh0fo+44vdEfDVwNXAP+5b94fV9V9VfX/gOXAOVV1bVU9VlUXAA8Dr+4ezwD+a1U9WlWfA9ZPs72lwCHA+6vqh1X146q6epq2k70NOK+qbqiqh4EP0TuiX9TX5qyqeqCqvgd8BTiym/4ova6UQ3Zym6+mF3xnVdUjVfVlemF5Wl+bL1bVP1TV41X14wHXO4hLquq6qtpGL9CPnDT/FOAc4ISqum7SvOn2w9uAT1TVxuqdK/kQcGrXrXYFcHSS/YDXAB+n90EF8Avd/AmPAqu613sd8BADnCfR7DDQ9x1vrKqDquqFVfXvuvCesKlv+IXA+7qv8A90HwIL6YXzIcCWquq/o9sd02xvIXBHF1I765D+9XaBdC8wv6/NXX3DP6IXxgAfAAJc13WbvHMntrmpqh7vm3bHpG1uYs+Y7rlMeC9wcVV9cyeW3W4fdsNzgedX1XfonRw/EjiG3gfXnUlezJMD/d5Jr+FU9elpwkAX9L66T9gE/FEX/hOPZ1XVhcA/AfMn+mk7h06zzk3AodOcaJ3pFp930vtgASDJAcBzgS0zPpGqu6rq3VV1CPBvgT8b8Gd/dwILu6PWCYdO2uau3Jr0h8CzJkaS/PQurOMU4I1JztiJZbbbh/Seyzbg7m78CnpdZvOqd17lCnrda88BbtyFGvU0YKBrsk8D70nyqvQckOTEJM8GvkYvFH47yTOSvIle18pUrqP3AXBWt45nJpn4Wn83sCDJvGmWvRB4R5Ijk+xPr3vo2qq6fabik5ySZEE3ej+9EH58B4tMuJbe0ecHuud2LPAGYM0Ay+7ITcBLu+fyTHo/a9xZdwKvBc5I8psDLnMh8DtJDktyIL19eFHf0fYVwArgym788m786qp6bBdq1NOAga7tVNUY8G7gk/QCcZzeiT2q6hHgTd34fcBb6Z1sm2o9j9ELxCOA7wGbu/YAX6Z3YvauJPdMsezfA38A/C96HwqHA6cO+BReCVzb/YplLXBGVW2caaHuub0BOIHeCdk/A369qr414HanW++36Z1U/Ht6vyIatE9/8nq+Ry/UVyZ51wCLnAd8hl5gfxf4MfDv++ZfATybfw70q+l9k7gS7bWyfXeoJGlv5RG6JDXCQJekRhjoktSIgQI9ybIkt3aXYq+cps2vJrm5++3vZ4dbpiRpJjOeFE3vJkTfBl5H75cK64HTqurmvjaLgYuB46rq/iTPq6rv72i9Bx98cC1atGg3y5ekfcv1119/T1WNTDVvkLvrLQXGJ376lWQNcDJwc1+bdwOrq+p+gJnCHGDRokWMjY0NsHlJ0oQk012dPVCXy3y2v+R5M9tfDg3wIuBFSf4hyTVJlk1TyPIkY0nGtm7dOsCmJUmDGtZJ0bnAYnp3ZzsN+HSSgyY3qqpzq2q0qkZHRqb8xiBJ2kWDBPoWejdamrCAJ99TYzOwtrsj23fp9bkvHk6JkqRBDBLo64HF3T0h5tG7BHvtpDZfoPtvt5IcTK8LZsbLrSVJwzNjoHc381kBXAbcQu82nhuSrOr7H10uA+5NcjO9ezK/v6ru3VNFS5KebNbu5TI6Olr+ykWSdk6S66tqdKp5XikqSY0w0CWpEQa6JDVikCtFJe2DFq28dLZLaNbtZ524R9brEbokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQa6JDXCQJekRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWqEgS5JjRgo0JMsS3JrkvEkK6eYf3qSrUlu7B7vGn6pkqQdmTtTgyRzgNXA64DNwPoka6vq5klNL6qqFXugRknSAAY5Ql8KjFfVxqp6BFgDnLxny5Ik7axBAn0+sKlvfHM3bbI3J/l6ks8lWTjVipIsTzKWZGzr1q27UK4kaTrDOin618Ciqno58HfABVM1qqpzq2q0qkZHRkaGtGlJEgwW6FuA/iPuBd20J1TVvVX1cDf6F8DPDac8SdKgBgn09cDiJIclmQecCqztb5DkBX2jJwG3DK9ESdIgZvyVS1VtS7ICuAyYA5xXVRuSrALGqmot8NtJTgK2AfcBp+/BmiVJU5gx0AGqah2wbtK0M/uGPwR8aLilSZJ2hleKSlIjDHRJaoSBLkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWqEgS5JjTDQJakRBrokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQa6JDXCQJekRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNGCjQkyxLcmuS8SQrd9DuzUkqyejwSpQkDWLGQE8yB1gNnAAsAU5LsmSKds8GzgCuHXaRkqSZDXKEvhQYr6qNVfUIsAY4eYp2fwh8DPjxEOuTJA1okECfD2zqG9/cTXtCklcAC6vq0h2tKMnyJGNJxrZu3brTxUqSprfbJ0WT7Ad8AnjfTG2r6tyqGq2q0ZGRkd3dtCSpzyCBvgVY2De+oJs24dnAy4DLk9wOvBpY64lRSXpqDRLo64HFSQ5LMg84FVg7MbOqHqyqg6tqUVUtAq4BTqqqsT1SsSRpSjMGelVtA1YAlwG3ABdX1YYkq5KctKcLlCQNZu4gjapqHbBu0rQzp2l77O6XJUnaWV4pKkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWqEgS5JjTDQJakRBrokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQa6JDXCQJekRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNMNAlqREGuiQ1YqBAT7Isya1JxpOsnGL+e5J8I8mNSa5OsmT4pUqSdmTGQE8yB1gNnAAsAU6bIrA/W1X/sqqOBD4OfGLolUqSdmiQI/SlwHhVbayqR4A1wMn9Darq//aNHgDU8EqUJA1i7gBt5gOb+sY3A6+a3CjJbwG/C8wDjptqRUmWA8sBDj300J2tVZK0A0M7KVpVq6vqcOCDwIenaXNuVY1W1ejIyMiwNi1JYrBA3wIs7Btf0E2bzhrgjbtTlCRp5w0S6OuBxUkOSzIPOBVY298gyeK+0ROB24ZXoiRpEDP2oVfVtiQrgMuAOcB5VbUhySpgrKrWAiuSHA88CtwPvH1PFi1JerJBTopSVeuAdZOmndk3fMaQ65Ik7SSvFJWkRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWqEgS5JjTDQJakRBrokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQa6JDXCQJekRhjoktSIubNdwK5YtPLS2S6hWbefdeIeWa+v2Z6zp14z7X0GOkJPsizJrUnGk6ycYv7vJrk5ydeTfCnJC4dfqiRpR2YM9CRzgNXACcAS4LQkSyY1+0dgtKpeDnwO+PiwC5Uk7dggR+hLgfGq2lhVjwBrgJP7G1TVV6rqR93oNcCC4ZYpSZrJIIE+H9jUN765mzad3wD+ZqoZSZYnGUsytnXr1sGrlCTNaKi/cknya8AocPZU86vq3KoararRkZGRYW5akvZ5g/zKZQuwsG98QTdtO0mOB34f+IWqeng45UmSBjXIEfp6YHGSw5LMA04F1vY3SHIUcA5wUlV9f/hlSpJmMmOgV9U2YAVwGXALcHFVbUiyKslJXbOzgQOBv0pyY5K106xOkrSHDHRhUVWtA9ZNmnZm3/DxQ65LkrSTvPRfkhphoEtSIwx0SWqEgS5JjTDQJakRBrokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQa6JDXCQJekRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWrEQIGeZFmSW5OMJ1k5xfzXJLkhybYkbxl+mZKkmcwY6EnmAKuBE4AlwGlJlkxq9j3gdOCzwy5QkjSYuQO0WQqMV9VGgCRrgJOBmycaVNXt3bzH90CNkqQBDNLlMh/Y1De+uZu205IsTzKWZGzr1q27sgpJ0jSe0pOiVXVuVY1W1ejIyMhTuWlJat4ggb4FWNg3vqCbJkl6Ghkk0NcDi5MclmQecCqwds+WJUnaWTMGelVtA1YAlwG3ABdX1YYkq5KcBJDklUk2A6cA5yTZsCeLliQ92SC/cqGq1gHrJk07s294Pb2uGEnSLPFKUUlqhIEuSY0w0CWpEQa6JDXCQJekRhjoktQIA12SGmGgS1IjDHRJaoSBLkmNMNAlqREGuiQ1wkCXpEYY6JLUCANdkhphoEtSIwx0SWqEgS5JjTDQJakRBrokNcJAl6RGGOiS1AgDXZIaYaBLUiMMdElqhIEuSY0w0CWpEQMFepJlSW5NMp5k5RTz909yUTf/2iSLhl2oJGnHZgz0JHOA1cAJwBLgtCRLJjX7DeD+qjoC+BPgY8MuVJK0Y4McoS8FxqtqY1U9AqwBTp7U5mTggm74c8Brk2R4ZUqSZjJ3gDbzgU1945uBV03Xpqq2JXkQeC5wT3+jJMuB5d3oQ0lu3ZWi90IHM2lfPF3F71awF71e4GvW2ZdesxdON2OQQB+aqjoXOPep3ObTQZKxqhqd7To0GF+vvY+vWc8gXS5bgIV94wu6aVO2STIX+Eng3mEUKEkazCCBvh5YnOSwJPOAU4G1k9qsBd7eDb8F+HJV1fDKlCTNZMYul65PfAVwGTAHOK+qNiRZBYxV1VrgvwOfSTIO3Ecv9PXP9rlupr2cr9fex9cMiAfSktQGrxSVpEYY6JLUCANd0tNWktOTfHK269hbGOiS1AgDfTclWZXkvX3jf5TkjCTvT7I+ydeT/Kdu3gFJLk1yU5JvJnnr7FUugCSLktyS5NNJNiT52yQ/keTIJNd0r98lSZ4z27W2oNvf3+wb/70kH0lyeZKPJbkuybeTHDPFsicm+VqSg5Ocn+S/Jflqko1J3tK1SZKzu7+vb0z8jSVZneSkbviSJOd1w+/s/manfB88NXtleAz03Xce8OsASfaj95PNu4DF9O6DcyTwc0leAywD7qyqn62qlwH/Z3ZK1iSLgdVV9VLgAeDNwF8CH6yqlwPfAP7jLNa3r5hbVUuB9zJpfyf5FWAl8PqqmrjE/wXA0cAvA2d1095E72/uZ4HjgbOTvAC4Cpj4kJhP70aDdNOu7Ianeh/sVQz03VRVtwP3JjkK+CXgH4FX9g3fAPwLem+WbwCv645EjqmqB2enak3y3aq6sRu+HjgcOKiqruimXQC8ZlYq27d8vvv3emBR3/TjgA8CJ1bV/X3Tv1BVj1fVzcDzu2lHAxdW1WNVdTdwBb2/x6uAY7o7xd4M3N0F/c8DX+2Wnfw+6K9hr/CU3sulYX8BnA78NL0j9tcCf1xV50xumOQVwOuBjyb5UlWteioL1ZQe7ht+DDhotgrZB2xj+wPJZ/YNT7wOj7F9Nn0H+BngRcDYFO0Bdnh316rakuQget+SrwR+CvhV4KGq+kGS5/Lk94FdLvuoS+i9UV5J74ray4B3JjkQIMn8JM9Lcgjwo6r6H8DZwCtmq2Dt0IPA/X39uP+G3pGedt/dwPOSPDfJ/vS6S2ZyB103WJKXztD2KuCtSeYkGaH3zeq6bt419Lpzruza/V73bzM8Qh+CqnokyVeAB6rqMeBvk7wE+Fp3W/iHgF8DjqDXp/c48Cjwm7NVs2b0duBTSZ4FbATeMcv1NKGqHu1uG3IdvZv6fWvA5b6V5G3AXyV5ww6aXkKvG+UmoIAPVNVd3byrgF+qqvEkd9A7Sm8q0L30fwi6k6E3AKdU1W2zXY+kfZNdLrupO8kyDnzJMJc0mzxCl6RGeIQuSY0w0CWpEQa6JDXCQJekRhjoktSI/w/TIK6YopbnBgAAAABJRU5ErkJggg==",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/2313e093_nohash_0.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/763188c4_nohash_1.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/7ea032f3_nohash_3.wav\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light",
+ "tags": []
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "import glob\n",
+ "import pandas as pd\n",
+ "pd.set_option(\"display.precision\", 2)\n",
+ "\n",
+ "txtfiles = []\n",
+ "for file in glob.glob(\"/content/data/mini_speech_commands/unknown/*.wav\"):\n",
+ " txtfiles.append(file)\n",
+ "\n",
+ "for i in range(25):\n",
+ " print(txtfiles[i])\n",
+ " sample_ds = preprocess_dataset([str(txtfiles[i])])\n",
+ " for spectrogram, label in sample_ds.batch(1):\n",
+ " prediction = model(spectrogram)\n",
+ " plt.bar(commands, tf.nn.softmax(prediction[0]))\n",
+ " plt.title(f'Predictions for \"{commands[label[0]]}\"')\n",
+ " plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "E8IcErTDyudr"
+ },
+ "source": [
+ "## Generate TF Lite float32 model"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 143,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "nlP5R7Y7ytYU",
+ "outputId": "7b8fee49-7b77-4bf5-fe17-aa593fafaa52"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "2.5.0\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "WARNING:absl:Found untraced functions such as lstm_cell_3_layer_call_and_return_conditional_losses, lstm_cell_3_layer_call_fn, lstm_cell_3_layer_call_fn, lstm_cell_3_layer_call_and_return_conditional_losses, lstm_cell_3_layer_call_and_return_conditional_losses while saving (showing 5 of 5). These functions will not be directly callable after loading.\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "INFO:tensorflow:Assets written to: keras_lstm/assets\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "INFO:tensorflow:Assets written to: keras_lstm/assets\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "483000"
+ ]
+ },
+ "execution_count": 143,
+ "metadata": {
+ "tags": []
+ },
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import tensorflow\n",
+ "print(tensorflow.__version__)\n",
+ "\n",
+ "run_model = tf.function(lambda x: model(x))\n",
+ "# This is important, let's fix the input size.\n",
+ "BATCH_SIZE = 1\n",
+ "STEPS = 49\n",
+ "INPUT_SIZE = 257\n",
+ "\n",
+ "concrete_func = run_model.get_concrete_function(\n",
+ " tf.TensorSpec([BATCH_SIZE, STEPS, INPUT_SIZE], model.inputs[0].dtype))\n",
+ "\n",
+ "# model directory.\n",
+ "MODEL_DIR = \"keras_lstm\"\n",
+ "model.save(MODEL_DIR, save_format=\"tf\", signatures=concrete_func)\n",
+ "\n",
+ "#Float LSTM model\n",
+ "converter = tf.lite.TFLiteConverter.from_saved_model(MODEL_DIR)\n",
+ "tflite_float_model = converter.convert()\n",
+ "open('/content/keras_lstm/model_float.tflite', \"wb\").write(tflite_float_model)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "6lo_G30v0raq"
+ },
+ "source": [
+ "## Validate audio files using TFLite float32 model"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 144,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "t807WqXQ0qEJ",
+ "outputId": "16c5640e-e982-47ad-b25a-c414bc2e2780"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/no/5c39594f_nohash_4.wav\n",
+ " yes no unknown\n",
+ "0 4.0e-13 1.0 5.8e-09\n",
+ "/content/data/mini_speech_commands/no/b83c1acf_nohash_2.wav\n",
+ " yes no unknown\n",
+ "0 3.1e-08 1.0 7.1e-04\n",
+ "/content/data/mini_speech_commands/no/8012c69d_nohash_2.wav\n",
+ " yes no unknown\n",
+ "0 2.1e-10 1.0 2.4e-10\n",
+ "/content/data/mini_speech_commands/no/dbb40d24_nohash_0.wav\n",
+ " yes no unknown\n",
+ "0 1.1e-06 1.3e-06 1.0\n",
+ "/content/data/mini_speech_commands/no/f4504600_nohash_1.wav\n",
+ " yes no unknown\n",
+ "0 1.9e-16 1.0 2.4e-13\n",
+ "/content/data/mini_speech_commands/no/c79159aa_nohash_4.wav\n",
+ " yes no unknown\n",
+ "0 1.6e-11 1.0 6.5e-11\n",
+ "/content/data/mini_speech_commands/no/c7aa72e6_nohash_1.wav\n",
+ " yes no unknown\n",
+ "0 4.3e-04 0.4 0.6\n",
+ "/content/data/mini_speech_commands/no/a527cb3c_nohash_0.wav\n",
+ " yes no unknown\n",
+ "0 5.2e-12 1.0 1.6e-07\n",
+ "/content/data/mini_speech_commands/no/26b28ea7_nohash_0.wav\n",
+ " yes no unknown\n",
+ "0 5.3e-08 1.0 2.7e-03\n",
+ "/content/data/mini_speech_commands/no/765ffccb_nohash_3.wav\n",
+ " yes no unknown\n",
+ "0 7.8e-10 1.0 2.0e-09\n",
+ "/content/data/mini_speech_commands/no/735845ab_nohash_2.wav\n",
+ " yes no unknown\n",
+ "0 0.2 0.8 1.2e-02\n",
+ "/content/data/mini_speech_commands/no/38d78313_nohash_3.wav\n",
+ " yes no unknown\n",
+ "0 4.6e-13 1.0 7.4e-16\n",
+ "/content/data/mini_speech_commands/no/89f680f3_nohash_1.wav\n",
+ " yes no unknown\n",
+ "0 1.4e-10 0.3 0.7\n",
+ "/content/data/mini_speech_commands/no/c661be6e_nohash_1.wav\n",
+ " yes no unknown\n",
+ "0 2.2e-12 1.0 1.9e-10\n",
+ "/content/data/mini_speech_commands/no/c33682f0_nohash_0.wav\n",
+ " yes no unknown\n",
+ "0 3.7e-08 1.0 5.8e-03\n",
+ "/content/data/mini_speech_commands/no/2e73212b_nohash_0.wav\n",
+ " yes no unknown\n",
+ "0 4.7e-03 1.0 1.6e-05\n",
+ "/content/data/mini_speech_commands/no/cb802c63_nohash_0.wav\n",
+ " yes no unknown\n",
+ "0 1.9e-07 1.0 3.3e-05\n",
+ "/content/data/mini_speech_commands/no/2903efb3_nohash_0.wav\n",
+ " yes no unknown\n",
+ "0 1.3e-04 1.0 9.5e-07\n",
+ "/content/data/mini_speech_commands/no/1657c9fa_nohash_1.wav\n",
+ " yes no unknown\n",
+ "0 3.0e-11 1.0 7.3e-10\n",
+ "/content/data/mini_speech_commands/no/24befdb3_nohash_4.wav\n",
+ " yes no unknown\n",
+ "0 1.2e-06 1.0 3.8e-04\n",
+ "/content/data/mini_speech_commands/no/bfdb9801_nohash_0.wav\n",
+ " yes no unknown\n",
+ "0 1.7e-04 1.0 2.5e-08\n",
+ "/content/data/mini_speech_commands/no/dc75148d_nohash_0.wav\n",
+ " yes no unknown\n",
+ "0 1.6e-07 1.0 1.2e-10\n",
+ "/content/data/mini_speech_commands/no/07ad9b59_nohash_0.wav\n",
+ " yes no unknown\n",
+ "0 2.3e-03 1.0 2.8e-04\n",
+ "/content/data/mini_speech_commands/no/ac7840d8_nohash_1.wav\n",
+ " yes no unknown\n",
+ "0 1.8e-06 1.0 1.4e-05\n",
+ "/content/data/mini_speech_commands/no/e14a99a5_nohash_0.wav\n",
+ " yes no unknown\n",
+ "0 1.3e-06 1.0 2.1e-06\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Load quantized TFLite model\n",
+ "tflite_interpreter_float = tf.lite.Interpreter(model_path='/content/keras_lstm/model_float.tflite')\n",
+ "# Learn about its input and output details\n",
+ "input_details = tflite_interpreter_float.get_input_details()\n",
+ "output_details = tflite_interpreter_float.get_output_details()\n",
+ "tflite_interpreter_float.allocate_tensors()\n",
+ "\n",
+ "import glob\n",
+ "import pandas as pd\n",
+ "pd.set_option(\"display.precision\", 2)\n",
+ "\n",
+ "txtfiles = []\n",
+ "for file in glob.glob(\"/content/data/mini_speech_commands/no/*.wav\"):\n",
+ " txtfiles.append(file)\n",
+ "\n",
+ "for i in range(25):\n",
+ " sample_ds = preprocess_dataset([str(txtfiles[i])])\n",
+ " print(txtfiles[i])\n",
+ " # Run inference\n",
+ " for spectrogram, label in sample_ds.batch(1):\n",
+ " tflite_interpreter_float.set_tensor(input_details[0]['index'],np.array(spectrogram, dtype=np.float32).reshape(1,49, 257) )\n",
+ " tflite_interpreter_float.invoke()\n",
+ " tflite_float_model_predictions = tflite_interpreter_float.get_tensor(output_details[0]['index'])\n",
+ " # Convert prediction results to Pandas dataframe, for better visualization\n",
+ " # Increase precision of presented data for better side-by-side comparison\n",
+ " tflite_pred_dataframe = pd.DataFrame(tflite_float_model_predictions)\n",
+ " tflite_pred_dataframe.columns = commands\n",
+ " pd.set_option(\"display.precision\",1)\n",
+ " print(tflite_pred_dataframe)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "VJANb9Uk-Xw-"
+ },
+ "source": [
+ "##Generate Quantized int8 model\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 145,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "nfMYKQgz-W_X",
+ "outputId": "28dc6ce9-24ab-44b6-bc79-4e65708b1d2c"
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "124768"
+ ]
+ },
+ "execution_count": 145,
+ "metadata": {
+ "tags": []
+ },
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "def representative_dataset_3():\n",
+ " for spectrogram, _ in spectrogram_ds.take(800):\n",
+ " # print('test')\n",
+ " flattened_data = np.array(spectrogram, dtype=np.float32).reshape(1,49, 257)\n",
+ " yield [flattened_data]\n",
+ "\n",
+ "converter.representative_dataset = representative_dataset_3\n",
+ "converter.optimizations = [tf.lite.Optimize.OPTIMIZE_FOR_SIZE]\n",
+ "converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]\n",
+ "converter.inference_input_type = tf.int8\n",
+ "converter.inference_output_type = tf.int8\n",
+ "quantized_tflite_model = converter.convert()\n",
+ "open('/content/keras_lstm/model_quantized_minispeech.tflite', \"wb\").write(quantized_tflite_model)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "HX4Ib7o4-kcH"
+ },
+ "source": [
+ "## Validate Quantized int8 model"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 152,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "K0fLf2sx-jHx",
+ "outputId": "710765e4-05e8-4eec-98b2-36a693465370"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/unknown/4c77947d_nohash_0.wav\n",
+ " yes no unknown\n",
+ "0 -128 -128 127\n",
+ "/content/data/mini_speech_commands/unknown/b737ee80_nohash_1.wav\n",
+ " yes no unknown\n",
+ "0 -128 -128 127\n",
+ "/content/data/mini_speech_commands/unknown/feb1d305_nohash_2.wav\n",
+ " yes no unknown\n",
+ "0 -128 -128 127\n",
+ "/content/data/mini_speech_commands/unknown/07ad9b59_nohash_2.wav\n",
+ " yes no unknown\n",
+ "0 -128 -128 127\n",
+ "/content/data/mini_speech_commands/unknown/5c39594f_nohash_4.wav\n",
+ " yes no unknown\n",
+ "0 -128 -127 127\n",
+ "/content/data/mini_speech_commands/unknown/2d92f18b_nohash_0.wav\n",
+ " yes no unknown\n",
+ "0 -124 -124 120\n",
+ "/content/data/mini_speech_commands/unknown/b83c1acf_nohash_2.wav\n",
+ " yes no unknown\n",
+ "0 -128 -128 127\n",
+ "/content/data/mini_speech_commands/unknown/4a1e736b_nohash_4.wav\n",
+ " yes no unknown\n",
+ "0 -128 -128 127\n",
+ "/content/data/mini_speech_commands/unknown/8012c69d_nohash_2.wav\n",
+ " yes no unknown\n",
+ "0 -128 127 -128\n",
+ "/content/data/mini_speech_commands/unknown/71f6fed7_nohash_2.wav\n",
+ " yes no unknown\n",
+ "0 -128 -128 127\n",
+ "/content/data/mini_speech_commands/unknown/ec21c46b_nohash_2.wav\n",
+ " yes no unknown\n",
+ "0 -128 -128 127\n",
+ "/content/data/mini_speech_commands/unknown/2f0a410b_nohash_1.wav\n",
+ " yes no unknown\n",
+ "0 -128 -128 127\n",
+ "/content/data/mini_speech_commands/unknown/f2a90886_nohash_0.wav\n",
+ " yes no unknown\n",
+ "0 -128 -128 127\n",
+ "/content/data/mini_speech_commands/unknown/dbb40d24_nohash_0.wav\n",
+ " yes no unknown\n",
+ "0 -126 -1 -1\n",
+ "/content/data/mini_speech_commands/unknown/b9515bf3_nohash_1.wav\n",
+ " yes no unknown\n",
+ "0 -128 -128 127\n",
+ "/content/data/mini_speech_commands/unknown/15c563d7_nohash_3.wav\n",
+ " yes no unknown\n",
+ "0 -128 127 -128\n",
+ "/content/data/mini_speech_commands/unknown/f4504600_nohash_1.wav\n",
+ " yes no unknown\n",
+ "0 -128 -128 127\n",
+ "/content/data/mini_speech_commands/unknown/da76aa58_nohash_1.wav\n",
+ " yes no unknown\n",
+ "0 -128 -128 127\n",
+ "/content/data/mini_speech_commands/unknown/dedc7fab_nohash_1.wav\n",
+ " yes no unknown\n",
+ "0 -128 -128 127\n",
+ "/content/data/mini_speech_commands/unknown/a527cb3c_nohash_0.wav\n",
+ " yes no unknown\n",
+ "0 -128 -128 127\n",
+ "/content/data/mini_speech_commands/unknown/26b28ea7_nohash_0.wav\n",
+ " yes no unknown\n",
+ "0 -128 -128 127\n",
+ "/content/data/mini_speech_commands/unknown/d84829e0_nohash_0.wav\n",
+ " yes no unknown\n",
+ "0 -125 -122 119\n",
+ "/content/data/mini_speech_commands/unknown/2313e093_nohash_0.wav\n",
+ " yes no unknown\n",
+ "0 -128 -128 127\n",
+ "/content/data/mini_speech_commands/unknown/763188c4_nohash_1.wav\n",
+ " yes no unknown\n",
+ "0 -128 -128 127\n",
+ "/content/data/mini_speech_commands/unknown/7ea032f3_nohash_3.wav\n",
+ " yes no unknown\n",
+ "0 -31 -128 30\n"
+ ]
+ }
+ ],
+ "source": [
+ "\n",
+ "# Load quantized TFLite model\n",
+ "tflite_interpreter_quant = tf.lite.Interpreter(model_path='/content/keras_lstm/model_quantized_minispeech.tflite')\n",
+ "# Learn about its input and output details\n",
+ "input_details = tflite_interpreter_quant.get_input_details()\n",
+ "\n",
+ "output_details = tflite_interpreter_quant.get_output_details()\n",
+ "\n",
+ "tflite_interpreter_quant.allocate_tensors()\n",
+ "\n",
+ "import glob\n",
+ "import pandas as pd\n",
+ "pd.set_option(\"display.precision\", 2)\n",
+ "\n",
+ "txtfiles = []\n",
+ "for file in glob.glob(\"/content/data/mini_speech_commands/unknown/*.wav\"):\n",
+ " txtfiles.append(file)\n",
+ "\n",
+ "for i in range(25):\n",
+ " print(txtfiles[i])\n",
+ " sample_ds = preprocess_dataset([str(txtfiles[i])])\n",
+ " # Run inference\n",
+ " for spectrogram, label in sample_ds.batch(1):\n",
+ " spectrogram_t = np.array(spectrogram, dtype=np.uint8).reshape(1,49, 257)\n",
+ " spectrogram_t = np.array(spectrogram_t-128, dtype=np.int8)\n",
+ " tflite_interpreter_quant.set_tensor(input_details[0]['index'],spectrogram_t )\n",
+ " tflite_interpreter_quant.invoke()\n",
+ " tflite_q_model_predictions = tflite_interpreter_quant.get_tensor(output_details[0]['index'])\n",
+ " tflite_pred_dataframe = pd.DataFrame(tflite_q_model_predictions)\n",
+ " tflite_pred_dataframe.columns = commands\n",
+ " print(tflite_pred_dataframe)\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "qg8U2AZkSfCH"
+ },
+ "source": [
+ "## Evaluate int8 model using floor and inputscale and zeropoint"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 147,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "cEwmoArnIcK9",
+ "outputId": "887b437e-0a79-4ff6-e422-0bf6d8e0d8aa"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "/content/data/mini_speech_commands/no/5c39594f_nohash_4.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-128 127 -128]]\n",
+ " yes no unknown\n",
+ "0 0.0 1.0 0.0\n",
+ "/content/data/mini_speech_commands/no/b83c1acf_nohash_2.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-128 125 -125]]\n",
+ " yes no unknown\n",
+ "0 0.0 0.99 0.01\n",
+ "/content/data/mini_speech_commands/no/8012c69d_nohash_2.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-128 127 -128]]\n",
+ " yes no unknown\n",
+ "0 0.0 1.0 0.0\n",
+ "/content/data/mini_speech_commands/no/dbb40d24_nohash_0.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-120 -128 120]]\n",
+ " yes no unknown\n",
+ "0 0.03 0.0 0.97\n",
+ "/content/data/mini_speech_commands/no/f4504600_nohash_1.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-128 127 -128]]\n",
+ " yes no unknown\n",
+ "0 0.0 1.0 0.0\n",
+ "/content/data/mini_speech_commands/no/c79159aa_nohash_4.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-128 127 -128]]\n",
+ " yes no unknown\n",
+ "0 0.0 1.0 0.0\n",
+ "/content/data/mini_speech_commands/no/c7aa72e6_nohash_1.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-128 127 -127]]\n",
+ " yes no unknown\n",
+ "0 0.0 1.0 3.91e-03\n",
+ "/content/data/mini_speech_commands/no/a527cb3c_nohash_0.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-128 127 -128]]\n",
+ " yes no unknown\n",
+ "0 0.0 1.0 0.0\n",
+ "/content/data/mini_speech_commands/no/26b28ea7_nohash_0.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-128 118 -118]]\n",
+ " yes no unknown\n",
+ "0 0.0 0.96 0.04\n",
+ "/content/data/mini_speech_commands/no/765ffccb_nohash_3.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-128 127 -128]]\n",
+ " yes no unknown\n",
+ "0 0.0 1.0 0.0\n",
+ "/content/data/mini_speech_commands/no/735845ab_nohash_2.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[ 126 -128 -126]]\n",
+ " yes no unknown\n",
+ "0 0.99 0.0 7.81e-03\n",
+ "/content/data/mini_speech_commands/no/38d78313_nohash_3.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-128 127 -128]]\n",
+ " yes no unknown\n",
+ "0 0.0 1.0 0.0\n",
+ "/content/data/mini_speech_commands/no/89f680f3_nohash_1.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-128 31 -31]]\n",
+ " yes no unknown\n",
+ "0 0.0 0.62 0.38\n",
+ "/content/data/mini_speech_commands/no/c661be6e_nohash_1.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-128 127 -128]]\n",
+ " yes no unknown\n",
+ "0 0.0 1.0 0.0\n",
+ "/content/data/mini_speech_commands/no/c33682f0_nohash_0.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-128 -107 107]]\n",
+ " yes no unknown\n",
+ "0 0.0 0.08 0.92\n",
+ "/content/data/mini_speech_commands/no/2e73212b_nohash_0.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-127 -128 127]]\n",
+ " yes no unknown\n",
+ "0 3.91e-03 0.0 1.0\n",
+ "/content/data/mini_speech_commands/no/cb802c63_nohash_0.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-128 127 -127]]\n",
+ " yes no unknown\n",
+ "0 0.0 1.0 3.91e-03\n",
+ "/content/data/mini_speech_commands/no/2903efb3_nohash_0.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-128 127 -128]]\n",
+ " yes no unknown\n",
+ "0 0.0 1.0 0.0\n",
+ "/content/data/mini_speech_commands/no/1657c9fa_nohash_1.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-128 127 -128]]\n",
+ " yes no unknown\n",
+ "0 0.0 1.0 0.0\n",
+ "/content/data/mini_speech_commands/no/24befdb3_nohash_4.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-128 127 -128]]\n",
+ " yes no unknown\n",
+ "0 0.0 1.0 0.0\n",
+ "/content/data/mini_speech_commands/no/bfdb9801_nohash_0.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-128 127 -128]]\n",
+ " yes no unknown\n",
+ "0 0.0 1.0 0.0\n",
+ "/content/data/mini_speech_commands/no/dc75148d_nohash_0.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-115 115 -128]]\n",
+ " yes no unknown\n",
+ "0 0.05 0.95 0.0\n",
+ "/content/data/mini_speech_commands/no/07ad9b59_nohash_0.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-128 127 -128]]\n",
+ " yes no unknown\n",
+ "0 0.0 1.0 0.0\n",
+ "/content/data/mini_speech_commands/no/ac7840d8_nohash_1.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[-128 127 -128]]\n",
+ " yes no unknown\n",
+ "0 0.0 1.0 0.0\n",
+ "/content/data/mini_speech_commands/no/e14a99a5_nohash_0.wav\n",
+ "0.7175403237342834\n",
+ "-128\n",
+ "[[ 118 -122 -124]]\n",
+ " yes no unknown\n",
+ "0 0.96 0.02 0.02\n"
+ ]
+ }
+ ],
+ "source": [
+ "#test\n",
+ "# Load quantized TFLite model\n",
+ "tflite_interpreter_quant_int8 = tf.lite.Interpreter(model_path='/content/keras_lstm/model_quantized_minispeech.tflite')\n",
+ "# Learn about its input and output details\n",
+ "input_details = tflite_interpreter_quant_int8.get_input_details()\n",
+ "\n",
+ "output_details = tflite_interpreter_quant_int8.get_output_details()\n",
+ "\n",
+ "tflite_interpreter_quant_int8.allocate_tensors()\n",
+ "\n",
+ "import glob\n",
+ "import pandas as pd\n",
+ "pd.set_option(\"display.precision\", 2)\n",
+ "\n",
+ "txtfiles = []\n",
+ "for file in glob.glob(\"/content/data/mini_speech_commands/no/*.wav\"):\n",
+ " txtfiles.append(file)\n",
+ "\n",
+ "\n",
+ "for i in range(25):\n",
+ " print(txtfiles[i])\n",
+ " sample_ds = preprocess_dataset([str(txtfiles[i])])\n",
+ " # Run inference\n",
+ " for spectrogram, label in sample_ds.batch(1):\n",
+ " input_scale, input_zero_point = input_details[0][\"quantization\"]\n",
+ " print(input_scale)\n",
+ " print(input_zero_point)\n",
+ " spectrogram = np.array(spectrogram)\n",
+ " spectrogram = np.clip(np.floor(spectrogram / input_scale + input_zero_point), -128, 127) # for int8 validation\n",
+ " q_spectrogram = np.array(spectrogram, dtype=np.int8).reshape(1,49, 257)\n",
+ " tflite_interpreter_quant_int8.set_tensor(input_details[0]['index'], q_spectrogram )\n",
+ " tflite_interpreter_quant_int8.invoke()\n",
+ " tflite_q_model_predictions = tflite_interpreter_quant_int8.get_tensor(output_details[0]['index'])\n",
+ " print(tflite_q_model_predictions)\n",
+ " output_scale, output_zero_point = output_details[0][\"quantization\"]\n",
+ " tflite_model_predictions = (np.array(tflite_q_model_predictions, dtype=np.float32) - output_zero_point) * output_scale\n",
+ " tflite_pred_dataframe = pd.DataFrame(tflite_model_predictions)\n",
+ " tflite_pred_dataframe.columns = commands\n",
+ " print(tflite_pred_dataframe)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "tUToqbr-OqKp"
+ },
+ "source": [
+ "## Generate a TensorFlow Lite for MicroControllers Model\n",
+ "Convert the TensorFlow Lite model into a C source file that can be loaded by TensorFlow Lite for Microcontrollers."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 148,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "_y90gcAtOs0-",
+ "outputId": "a422f82c-7a13-4d1e-8642-e8f7d63a114d"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\r0% [Working]\r \rHit:1 https://cloud.r-project.org/bin/linux/ubuntu bionic-cran40/ InRelease\n",
+ "\r0% [Connecting to archive.ubuntu.com (91.189.88.142)] [Waiting for headers] [Co\r \rIgn:2 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64 InRelease\n",
+ "\r0% [Connecting to archive.ubuntu.com (91.189.88.142)] [Waiting for headers] [Co\r0% [1 InRelease gpgv 3,626 B] [Connecting to archive.ubuntu.com (91.189.88.142)\r \rIgn:3 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64 InRelease\n",
+ "Hit:4 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64 Release\n",
+ "Get:5 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB]\n",
+ "Hit:6 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64 Release\n",
+ "Hit:7 http://ppa.launchpad.net/c2d4u.team/c2d4u4.0+/ubuntu bionic InRelease\n",
+ "Hit:8 http://archive.ubuntu.com/ubuntu bionic InRelease\n",
+ "Get:10 http://archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB]\n",
+ "Hit:12 http://ppa.launchpad.net/cran/libgit2/ubuntu bionic InRelease\n",
+ "Hit:13 http://ppa.launchpad.net/deadsnakes/ppa/ubuntu bionic InRelease\n",
+ "Get:14 http://archive.ubuntu.com/ubuntu bionic-backports InRelease [74.6 kB]\n",
+ "Hit:15 http://ppa.launchpad.net/graphics-drivers/ppa/ubuntu bionic InRelease\n",
+ "Fetched 252 kB in 2s (142 kB/s)\n",
+ "Reading package lists... Done\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Install xxd if it is not available\n",
+ "!apt-get update && apt-get -qq install xxd\n",
+ "# Convert to a C source file\n",
+ "!xxd -i /content/keras_lstm/model_quantized_minispeech.tflite > /content/keras_lstm/model.cc\n",
+ "!cat /content/keras_lstm/model.cc"
+ ]
+ }
+ ],
+ "metadata": {
+ "accelerator": "GPU",
+ "colab": {
+ "collapsed_sections": [],
+ "name": "micro_speech_with_lstm_op.ipynb",
+ "provenance": []
+ },
+ "kernelspec": {
+ "display_name": "Python 3",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/docs/tensorflow/train_hello_world_model.ipynb b/docs/tensorflow/train_hello_world_model.ipynb
new file mode 100644
index 0000000000..3281ce5e9e
--- /dev/null
+++ b/docs/tensorflow/train_hello_world_model.ipynb
@@ -0,0 +1,3691 @@
+{
+ "nbformat": 4,
+ "nbformat_minor": 0,
+ "metadata": {
+ "colab": {
+ "name": "train_hello_world_model.ipynb",
+ "provenance": [],
+ "collapsed_sections": [],
+ "toc_visible": true
+ },
+ "kernelspec": {
+ "name": "python3",
+ "display_name": "Python 3"
+ }
+ },
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "aCZBFzjClURz"
+ },
+ "source": [
+ "# Train a Simple TensorFlow Lite for Microcontrollers model\n",
+ "\n",
+ "This notebook demonstrates the process of training a 2.5 kB model using TensorFlow and converting it for use with TensorFlow Lite for Microcontrollers. \n",
+ "\n",
+ "Deep learning networks learn to model patterns in underlying data. Here, we're going to train a network to model data generated by a [sine](https://en.wikipedia.org/wiki/Sine) function. This will result in a model that can take a value, `x`, and predict its sine, `y`.\n",
+ "\n",
+ "The model created in this notebook is used in the [hello_world](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/examples/hello_world) example for [TensorFlow Lite for MicroControllers](https://www.tensorflow.org/lite/microcontrollers/overview).\n",
+ "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "_UQblnrLd_ET"
+ },
+ "source": [
+ "## Configure Defaults"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "5PYwRFppd-WB"
+ },
+ "source": [
+ "# Define paths to model files\n",
+ "import os\n",
+ "MODELS_DIR = 'models/'\n",
+ "if not os.path.exists(MODELS_DIR):\n",
+ " os.mkdir(MODELS_DIR)\n",
+ "MODEL_TF = MODELS_DIR + 'model'\n",
+ "MODEL_NO_QUANT_TFLITE = MODELS_DIR + 'model_no_quant.tflite'\n",
+ "MODEL_TFLITE = MODELS_DIR + 'model.tflite'\n",
+ "MODEL_TFLITE_MICRO = MODELS_DIR + 'model.cc'"
+ ],
+ "execution_count": null,
+ "outputs": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "dh4AXGuHWeu1"
+ },
+ "source": [
+ "## Setup Environment\n",
+ "\n",
+ "Install Dependencies"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "cr1VLfotanf6",
+ "outputId": "510567d6-300e-40e2-f5b8-c3520a3f3a8b",
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ }
+ },
+ "source": [
+ "! pip install tensorflow==2.4.0"
+ ],
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "text": [
+ "Requirement already satisfied: tensorflow==2.4.0rc0 in /usr/local/lib/python3.6/dist-packages (2.4.0rc0)\n",
+ "Requirement already satisfied: termcolor~=1.1.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow==2.4.0rc0) (1.1.0)\n",
+ "Requirement already satisfied: gast==0.3.3 in /usr/local/lib/python3.6/dist-packages (from tensorflow==2.4.0rc0) (0.3.3)\n",
+ "Requirement already satisfied: astunparse~=1.6.3 in /usr/local/lib/python3.6/dist-packages (from tensorflow==2.4.0rc0) (1.6.3)\n",
+ "Requirement already satisfied: absl-py~=0.10 in /usr/local/lib/python3.6/dist-packages (from tensorflow==2.4.0rc0) (0.10.0)\n",
+ "Requirement already satisfied: keras-preprocessing~=1.1.2 in /usr/local/lib/python3.6/dist-packages (from tensorflow==2.4.0rc0) (1.1.2)\n",
+ "Requirement already satisfied: six~=1.15.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow==2.4.0rc0) (1.15.0)\n",
+ "Requirement already satisfied: tensorboard~=2.3 in /usr/local/lib/python3.6/dist-packages (from tensorflow==2.4.0rc0) (2.3.0)\n",
+ "Requirement already satisfied: tensorflow-estimator~=2.3.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow==2.4.0rc0) (2.3.0)\n",
+ "Requirement already satisfied: flatbuffers~=1.12.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow==2.4.0rc0) (1.12)\n",
+ "Requirement already satisfied: google-pasta~=0.2 in /usr/local/lib/python3.6/dist-packages (from tensorflow==2.4.0rc0) (0.2.0)\n",
+ "Requirement already satisfied: protobuf~=3.13.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow==2.4.0rc0) (3.13.0)\n",
+ "Requirement already satisfied: grpcio~=1.32.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow==2.4.0rc0) (1.32.0)\n",
+ "Requirement already satisfied: h5py~=2.10.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow==2.4.0rc0) (2.10.0)\n",
+ "Requirement already satisfied: wrapt~=1.12.1 in /usr/local/lib/python3.6/dist-packages (from tensorflow==2.4.0rc0) (1.12.1)\n",
+ "Requirement already satisfied: opt-einsum~=3.3.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow==2.4.0rc0) (3.3.0)\n",
+ "Requirement already satisfied: numpy~=1.19.2 in /usr/local/lib/python3.6/dist-packages (from tensorflow==2.4.0rc0) (1.19.4)\n",
+ "Requirement already satisfied: typing-extensions~=3.7.4 in /usr/local/lib/python3.6/dist-packages (from tensorflow==2.4.0rc0) (3.7.4.3)\n",
+ "Requirement already satisfied: wheel~=0.35 in /usr/local/lib/python3.6/dist-packages (from tensorflow==2.4.0rc0) (0.35.1)\n",
+ "Requirement already satisfied: werkzeug>=0.11.15 in /usr/local/lib/python3.6/dist-packages (from tensorboard~=2.3->tensorflow==2.4.0rc0) (1.0.1)\n",
+ "Requirement already satisfied: markdown>=2.6.8 in /usr/local/lib/python3.6/dist-packages (from tensorboard~=2.3->tensorflow==2.4.0rc0) (3.3.3)\n",
+ "Requirement already satisfied: google-auth-oauthlib<0.5,>=0.4.1 in /usr/local/lib/python3.6/dist-packages (from tensorboard~=2.3->tensorflow==2.4.0rc0) (0.4.2)\n",
+ "Requirement already satisfied: tensorboard-plugin-wit>=1.6.0 in /usr/local/lib/python3.6/dist-packages (from tensorboard~=2.3->tensorflow==2.4.0rc0) (1.7.0)\n",
+ "Requirement already satisfied: requests<3,>=2.21.0 in /usr/local/lib/python3.6/dist-packages (from tensorboard~=2.3->tensorflow==2.4.0rc0) (2.23.0)\n",
+ "Requirement already satisfied: setuptools>=41.0.0 in /usr/local/lib/python3.6/dist-packages (from tensorboard~=2.3->tensorflow==2.4.0rc0) (50.3.2)\n",
+ "Requirement already satisfied: google-auth<2,>=1.6.3 in /usr/local/lib/python3.6/dist-packages (from tensorboard~=2.3->tensorflow==2.4.0rc0) (1.17.2)\n",
+ "Requirement already satisfied: importlib-metadata; python_version < \"3.8\" in /usr/local/lib/python3.6/dist-packages (from markdown>=2.6.8->tensorboard~=2.3->tensorflow==2.4.0rc0) (2.0.0)\n",
+ "Requirement already satisfied: requests-oauthlib>=0.7.0 in /usr/local/lib/python3.6/dist-packages (from google-auth-oauthlib<0.5,>=0.4.1->tensorboard~=2.3->tensorflow==2.4.0rc0) (1.3.0)\n",
+ "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.6/dist-packages (from requests<3,>=2.21.0->tensorboard~=2.3->tensorflow==2.4.0rc0) (2020.6.20)\n",
+ "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /usr/local/lib/python3.6/dist-packages (from requests<3,>=2.21.0->tensorboard~=2.3->tensorflow==2.4.0rc0) (1.24.3)\n",
+ "Requirement already satisfied: chardet<4,>=3.0.2 in /usr/local/lib/python3.6/dist-packages (from requests<3,>=2.21.0->tensorboard~=2.3->tensorflow==2.4.0rc0) (3.0.4)\n",
+ "Requirement already satisfied: idna<3,>=2.5 in /usr/local/lib/python3.6/dist-packages (from requests<3,>=2.21.0->tensorboard~=2.3->tensorflow==2.4.0rc0) (2.10)\n",
+ "Requirement already satisfied: cachetools<5.0,>=2.0.0 in /usr/local/lib/python3.6/dist-packages (from google-auth<2,>=1.6.3->tensorboard~=2.3->tensorflow==2.4.0rc0) (4.1.1)\n",
+ "Requirement already satisfied: rsa<5,>=3.1.4; python_version >= \"3\" in /usr/local/lib/python3.6/dist-packages (from google-auth<2,>=1.6.3->tensorboard~=2.3->tensorflow==2.4.0rc0) (4.6)\n",
+ "Requirement already satisfied: pyasn1-modules>=0.2.1 in /usr/local/lib/python3.6/dist-packages (from google-auth<2,>=1.6.3->tensorboard~=2.3->tensorflow==2.4.0rc0) (0.2.8)\n",
+ "Requirement already satisfied: zipp>=0.5 in /usr/local/lib/python3.6/dist-packages (from importlib-metadata; python_version < \"3.8\"->markdown>=2.6.8->tensorboard~=2.3->tensorflow==2.4.0rc0) (3.4.0)\n",
+ "Requirement already satisfied: oauthlib>=3.0.0 in /usr/local/lib/python3.6/dist-packages (from requests-oauthlib>=0.7.0->google-auth-oauthlib<0.5,>=0.4.1->tensorboard~=2.3->tensorflow==2.4.0rc0) (3.1.0)\n",
+ "Requirement already satisfied: pyasn1>=0.1.3 in /usr/local/lib/python3.6/dist-packages (from rsa<5,>=3.1.4; python_version >= \"3\"->google-auth<2,>=1.6.3->tensorboard~=2.3->tensorflow==2.4.0rc0) (0.4.8)\n"
+ ],
+ "name": "stdout"
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "tx9lOPWh9grN"
+ },
+ "source": [
+ "Import Dependencies"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "53PBJBv1jEtJ"
+ },
+ "source": [
+ "# TensorFlow is an open source machine learning library\n",
+ "import tensorflow as tf\n",
+ "\n",
+ "# Keras is TensorFlow's high-level API for deep learning\n",
+ "from tensorflow import keras\n",
+ "# Numpy is a math library\n",
+ "import numpy as np\n",
+ "# Pandas is a data manipulation library \n",
+ "import pandas as pd\n",
+ "# Matplotlib is a graphing library\n",
+ "import matplotlib.pyplot as plt\n",
+ "# Math is Python's math library\n",
+ "import math\n",
+ "\n",
+ "# Set seed for experiment reproducibility\n",
+ "seed = 1\n",
+ "np.random.seed(seed)\n",
+ "tf.random.set_seed(seed)"
+ ],
+ "execution_count": null,
+ "outputs": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "p-PuBEb6CMeo"
+ },
+ "source": [
+ "## Dataset"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "7gB0-dlNmLT-"
+ },
+ "source": [
+ "### 1. Generate Data\n",
+ "\n",
+ "The code in the following cell will generate a set of random `x` values, calculate their sine values, and display them on a graph."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "uKjg7QeMDsDx",
+ "outputId": "2ded7790-62a2-40df-a4f9-429f2dd5357f",
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 265
+ }
+ },
+ "source": [
+ "# Number of sample datapoints\n",
+ "SAMPLES = 1000\n",
+ "\n",
+ "# Generate a uniformly distributed set of random numbers in the range from\n",
+ "# 0 to 2π, which covers a complete sine wave oscillation\n",
+ "x_values = np.random.uniform(\n",
+ " low=0, high=2*math.pi, size=SAMPLES).astype(np.float32)\n",
+ "\n",
+ "# Shuffle the values to guarantee they're not in order\n",
+ "np.random.shuffle(x_values)\n",
+ "\n",
+ "# Calculate the corresponding sine values\n",
+ "y_values = np.sin(x_values).astype(np.float32)\n",
+ "\n",
+ "# Plot our data. The 'b.' argument tells the library to print blue dots.\n",
+ "plt.plot(x_values, y_values, 'b.')\n",
+ "plt.show()"
+ ],
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "display_data",
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "tags": [],
+ "needs_background": "light"
+ }
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "iWOlC7W_FYvA"
+ },
+ "source": [
+ "### 2. Add Noise\n",
+ "Since it was generated directly by the sine function, our data fits a nice, smooth curve.\n",
+ "\n",
+ "However, machine learning models are good at extracting underlying meaning from messy, real world data. To demonstrate this, we can add some noise to our data to approximate something more life-like.\n",
+ "\n",
+ "In the following cell, we'll add some random noise to each value, then draw a new graph:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "i0FJe3Y-Gkac",
+ "outputId": "10d4d994-3b78-4512-a029-5ef0e444d75c",
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 265
+ }
+ },
+ "source": [
+ "# Add a small random number to each y value\n",
+ "y_values += 0.1 * np.random.randn(*y_values.shape)\n",
+ "\n",
+ "# Plot our data\n",
+ "plt.plot(x_values, y_values, 'b.')\n",
+ "plt.show()"
+ ],
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "display_data",
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "tags": [],
+ "needs_background": "light"
+ }
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "Up8Xk_pMH4Rt"
+ },
+ "source": [
+ "### 3. Split the Data\n",
+ "We now have a noisy dataset that approximates real world data. We'll be using this to train our model.\n",
+ "\n",
+ "To evaluate the accuracy of the model we train, we'll need to compare its predictions to real data and check how well they match up. This evaluation happens during training (where it is referred to as validation) and after training (referred to as testing) It's important in both cases that we use fresh data that was not already used to train the model.\n",
+ "\n",
+ "The data is split as follows:\n",
+ " 1. Training: 60%\n",
+ " 2. Validation: 20%\n",
+ " 3. Testing: 20% \n",
+ "\n",
+ "The following code will split our data and then plots each set as a different color:\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "nNYko5L1keqZ",
+ "outputId": "e1e6915d-5cfe-4086-d20f-8e3aebd80292",
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 265
+ }
+ },
+ "source": [
+ "# We'll use 60% of our data for training and 20% for testing. The remaining 20%\n",
+ "# will be used for validation. Calculate the indices of each section.\n",
+ "TRAIN_SPLIT = int(0.6 * SAMPLES)\n",
+ "TEST_SPLIT = int(0.2 * SAMPLES + TRAIN_SPLIT)\n",
+ "\n",
+ "# Use np.split to chop our data into three parts.\n",
+ "# The second argument to np.split is an array of indices where the data will be\n",
+ "# split. We provide two indices, so the data will be divided into three chunks.\n",
+ "x_train, x_test, x_validate = np.split(x_values, [TRAIN_SPLIT, TEST_SPLIT])\n",
+ "y_train, y_test, y_validate = np.split(y_values, [TRAIN_SPLIT, TEST_SPLIT])\n",
+ "\n",
+ "# Double check that our splits add up correctly\n",
+ "assert (x_train.size + x_validate.size + x_test.size) == SAMPLES\n",
+ "\n",
+ "# Plot the data in each partition in different colors:\n",
+ "plt.plot(x_train, y_train, 'b.', label=\"Train\")\n",
+ "plt.plot(x_test, y_test, 'r.', label=\"Test\")\n",
+ "plt.plot(x_validate, y_validate, 'y.', label=\"Validate\")\n",
+ "plt.legend()\n",
+ "plt.show()\n"
+ ],
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "display_data",
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "tags": [],
+ "needs_background": "light"
+ }
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "Wfdelu1TmgPk"
+ },
+ "source": [
+ "## Training"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "t5McVnHmNiDw"
+ },
+ "source": [
+ "### 1. Design the Model\n",
+ "We're going to build a simple neural network model that will take an input value (in this case, `x`) and use it to predict a numeric output value (the sine of `x`). This type of problem is called a _regression_. It will use _layers_ of _neurons_ to attempt to learn any patterns underlying the training data, so it can make predictions.\n",
+ "\n",
+ "To begin with, we'll define two layers. The first layer takes a single input (our `x` value) and runs it through 8 neurons. Based on this input, each neuron will become _activated_ to a certain degree based on its internal state (its _weight_ and _bias_ values). A neuron's degree of activation is expressed as a number.\n",
+ "\n",
+ "The activation numbers from our first layer will be fed as inputs to our second layer, which is a single neuron. It will apply its own weights and bias to these inputs and calculate its own activation, which will be output as our `y` value.\n",
+ "\n",
+ "**Note:** To learn more about how neural networks function, you can explore the [Learn TensorFlow](https://codelabs.developers.google.com/codelabs/tensorflow-lab1-helloworld) codelabs.\n",
+ "\n",
+ "The code in the following cell defines our model using [Keras](https://www.tensorflow.org/guide/keras), TensorFlow's high-level API for creating deep learning networks. Once the network is defined, we _compile_ it, specifying parameters that determine how it will be trained:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "gD60bE8cXQId"
+ },
+ "source": [
+ "# We'll use Keras to create a simple model architecture\n",
+ "model_1 = tf.keras.Sequential()\n",
+ "\n",
+ "# First layer takes a scalar input and feeds it through 8 \"neurons\". The\n",
+ "# neurons decide whether to activate based on the 'relu' activation function.\n",
+ "model_1.add(keras.layers.Dense(8, activation='relu', input_shape=(1,)))\n",
+ "\n",
+ "# Final layer is a single neuron, since we want to output a single value\n",
+ "model_1.add(keras.layers.Dense(1))\n",
+ "\n",
+ "# Compile the model using the standard 'adam' optimizer and the mean squared error or 'mse' loss function for regression.\n",
+ "model_1.compile(optimizer='adam', loss='mse', metrics=['mae'])"
+ ],
+ "execution_count": null,
+ "outputs": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "O0idLyRLQeGj"
+ },
+ "source": [
+ "### 2. Train the Model\n",
+ "Once we've defined the model, we can use our data to _train_ it. Training involves passing an `x` value into the neural network, checking how far the network's output deviates from the expected `y` value, and adjusting the neurons' weights and biases so that the output is more likely to be correct the next time.\n",
+ "\n",
+ "Training runs this process on the full dataset multiple times, and each full run-through is known as an _epoch_. The number of epochs to run during training is a parameter we can set.\n",
+ "\n",
+ "During each epoch, data is run through the network in multiple _batches_. Each batch, several pieces of data are passed into the network, producing output values. These outputs' correctness is measured in aggregate and the network's weights and biases are adjusted accordingly, once per batch. The _batch size_ is also a parameter we can set.\n",
+ "\n",
+ "The code in the following cell uses the `x` and `y` values from our training data to train the model. It runs for 500 _epochs_, with 64 pieces of data in each _batch_. We also pass in some data for _validation_. As you will see when you run the cell, training can take a while to complete:\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "p8hQKr4cVOdE",
+ "outputId": "e275e119-9fea-451e-89ae-6b3746cbf96d",
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ }
+ },
+ "source": [
+ "# Train the model on our training data while validating on our validation set\n",
+ "history_1 = model_1.fit(x_train, y_train, epochs=500, batch_size=64,\n",
+ " validation_data=(x_validate, y_validate))"
+ ],
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "text": [
+ "Epoch 1/500\n",
+ "10/10 [==============================] - 1s 47ms/step - loss: 0.7289 - mae: 0.7120 - val_loss: 0.6401 - val_mae: 0.6504\n",
+ "Epoch 2/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.6329 - mae: 0.6488 - val_loss: 0.5587 - val_mae: 0.6031\n",
+ "Epoch 3/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.5201 - mae: 0.5735 - val_loss: 0.5014 - val_mae: 0.5763\n",
+ "Epoch 4/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.5057 - mae: 0.5760 - val_loss: 0.4632 - val_mae: 0.5615\n",
+ "Epoch 5/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.4502 - mae: 0.5459 - val_loss: 0.4386 - val_mae: 0.5536\n",
+ "Epoch 6/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.4168 - mae: 0.5332 - val_loss: 0.4227 - val_mae: 0.5490\n",
+ "Epoch 7/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.4211 - mae: 0.5341 - val_loss: 0.4125 - val_mae: 0.5464\n",
+ "Epoch 8/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.3988 - mae: 0.5287 - val_loss: 0.4060 - val_mae: 0.5452\n",
+ "Epoch 9/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3901 - mae: 0.5230 - val_loss: 0.4014 - val_mae: 0.5440\n",
+ "Epoch 10/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3804 - mae: 0.5179 - val_loss: 0.3979 - val_mae: 0.5426\n",
+ "Epoch 11/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3695 - mae: 0.5150 - val_loss: 0.3950 - val_mae: 0.5412\n",
+ "Epoch 12/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3856 - mae: 0.5245 - val_loss: 0.3921 - val_mae: 0.5399\n",
+ "Epoch 13/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.3744 - mae: 0.5184 - val_loss: 0.3893 - val_mae: 0.5386\n",
+ "Epoch 14/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.3749 - mae: 0.5175 - val_loss: 0.3865 - val_mae: 0.5371\n",
+ "Epoch 15/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3467 - mae: 0.4993 - val_loss: 0.3837 - val_mae: 0.5354\n",
+ "Epoch 16/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.3736 - mae: 0.5234 - val_loss: 0.3808 - val_mae: 0.5336\n",
+ "Epoch 17/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.3655 - mae: 0.5148 - val_loss: 0.3778 - val_mae: 0.5318\n",
+ "Epoch 18/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3558 - mae: 0.5067 - val_loss: 0.3747 - val_mae: 0.5297\n",
+ "Epoch 19/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3343 - mae: 0.4908 - val_loss: 0.3716 - val_mae: 0.5275\n",
+ "Epoch 20/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3742 - mae: 0.5257 - val_loss: 0.3686 - val_mae: 0.5258\n",
+ "Epoch 21/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3296 - mae: 0.4831 - val_loss: 0.3654 - val_mae: 0.5235\n",
+ "Epoch 22/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3432 - mae: 0.4962 - val_loss: 0.3622 - val_mae: 0.5214\n",
+ "Epoch 23/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3397 - mae: 0.4951 - val_loss: 0.3589 - val_mae: 0.5191\n",
+ "Epoch 24/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.3229 - mae: 0.4803 - val_loss: 0.3558 - val_mae: 0.5172\n",
+ "Epoch 25/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.3562 - mae: 0.5105 - val_loss: 0.3524 - val_mae: 0.5150\n",
+ "Epoch 26/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3458 - mae: 0.5042 - val_loss: 0.3492 - val_mae: 0.5128\n",
+ "Epoch 27/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3163 - mae: 0.4764 - val_loss: 0.3459 - val_mae: 0.5106\n",
+ "Epoch 28/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3441 - mae: 0.5018 - val_loss: 0.3427 - val_mae: 0.5086\n",
+ "Epoch 29/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3062 - mae: 0.4705 - val_loss: 0.3395 - val_mae: 0.5065\n",
+ "Epoch 30/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3202 - mae: 0.4808 - val_loss: 0.3362 - val_mae: 0.5043\n",
+ "Epoch 31/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.3313 - mae: 0.4919 - val_loss: 0.3330 - val_mae: 0.5022\n",
+ "Epoch 32/500\n",
+ "10/10 [==============================] - 0s 18ms/step - loss: 0.3028 - mae: 0.4682 - val_loss: 0.3297 - val_mae: 0.4996\n",
+ "Epoch 33/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3056 - mae: 0.4670 - val_loss: 0.3264 - val_mae: 0.4972\n",
+ "Epoch 34/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3203 - mae: 0.4781 - val_loss: 0.3233 - val_mae: 0.4954\n",
+ "Epoch 35/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.3256 - mae: 0.4912 - val_loss: 0.3201 - val_mae: 0.4929\n",
+ "Epoch 36/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3079 - mae: 0.4728 - val_loss: 0.3170 - val_mae: 0.4905\n",
+ "Epoch 37/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2969 - mae: 0.4641 - val_loss: 0.3139 - val_mae: 0.4885\n",
+ "Epoch 38/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.3043 - mae: 0.4693 - val_loss: 0.3108 - val_mae: 0.4863\n",
+ "Epoch 39/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2902 - mae: 0.4549 - val_loss: 0.3078 - val_mae: 0.4843\n",
+ "Epoch 40/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.3003 - mae: 0.4720 - val_loss: 0.3047 - val_mae: 0.4823\n",
+ "Epoch 41/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2970 - mae: 0.4678 - val_loss: 0.3017 - val_mae: 0.4804\n",
+ "Epoch 42/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2903 - mae: 0.4582 - val_loss: 0.2988 - val_mae: 0.4787\n",
+ "Epoch 43/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2853 - mae: 0.4553 - val_loss: 0.2960 - val_mae: 0.4769\n",
+ "Epoch 44/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2910 - mae: 0.4603 - val_loss: 0.2931 - val_mae: 0.4748\n",
+ "Epoch 45/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2819 - mae: 0.4533 - val_loss: 0.2902 - val_mae: 0.4727\n",
+ "Epoch 46/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2744 - mae: 0.4525 - val_loss: 0.2872 - val_mae: 0.4697\n",
+ "Epoch 47/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.2707 - mae: 0.4411 - val_loss: 0.2845 - val_mae: 0.4680\n",
+ "Epoch 48/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2641 - mae: 0.4414 - val_loss: 0.2818 - val_mae: 0.4661\n",
+ "Epoch 49/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2642 - mae: 0.4378 - val_loss: 0.2793 - val_mae: 0.4647\n",
+ "Epoch 50/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2603 - mae: 0.4385 - val_loss: 0.2767 - val_mae: 0.4628\n",
+ "Epoch 51/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2684 - mae: 0.4473 - val_loss: 0.2740 - val_mae: 0.4604\n",
+ "Epoch 52/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2539 - mae: 0.4312 - val_loss: 0.2714 - val_mae: 0.4583\n",
+ "Epoch 53/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2621 - mae: 0.4417 - val_loss: 0.2690 - val_mae: 0.4568\n",
+ "Epoch 54/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2556 - mae: 0.4366 - val_loss: 0.2664 - val_mae: 0.4545\n",
+ "Epoch 55/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2524 - mae: 0.4309 - val_loss: 0.2639 - val_mae: 0.4525\n",
+ "Epoch 56/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2555 - mae: 0.4364 - val_loss: 0.2614 - val_mae: 0.4507\n",
+ "Epoch 57/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2483 - mae: 0.4264 - val_loss: 0.2589 - val_mae: 0.4485\n",
+ "Epoch 58/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.2403 - mae: 0.4212 - val_loss: 0.2564 - val_mae: 0.4460\n",
+ "Epoch 59/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2462 - mae: 0.4274 - val_loss: 0.2542 - val_mae: 0.4446\n",
+ "Epoch 60/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.2364 - mae: 0.4178 - val_loss: 0.2522 - val_mae: 0.4437\n",
+ "Epoch 61/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2409 - mae: 0.4254 - val_loss: 0.2500 - val_mae: 0.4418\n",
+ "Epoch 62/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.2338 - mae: 0.4172 - val_loss: 0.2478 - val_mae: 0.4400\n",
+ "Epoch 63/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2283 - mae: 0.4132 - val_loss: 0.2456 - val_mae: 0.4381\n",
+ "Epoch 64/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2438 - mae: 0.4330 - val_loss: 0.2433 - val_mae: 0.4360\n",
+ "Epoch 65/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.2169 - mae: 0.4049 - val_loss: 0.2415 - val_mae: 0.4348\n",
+ "Epoch 66/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.2208 - mae: 0.4087 - val_loss: 0.2393 - val_mae: 0.4329\n",
+ "Epoch 67/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.2440 - mae: 0.4321 - val_loss: 0.2373 - val_mae: 0.4312\n",
+ "Epoch 68/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.2250 - mae: 0.4131 - val_loss: 0.2353 - val_mae: 0.4295\n",
+ "Epoch 69/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2222 - mae: 0.4081 - val_loss: 0.2334 - val_mae: 0.4277\n",
+ "Epoch 70/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.2245 - mae: 0.4138 - val_loss: 0.2316 - val_mae: 0.4261\n",
+ "Epoch 71/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2132 - mae: 0.3983 - val_loss: 0.2298 - val_mae: 0.4244\n",
+ "Epoch 72/500\n",
+ "10/10 [==============================] - 0s 18ms/step - loss: 0.2232 - mae: 0.4144 - val_loss: 0.2280 - val_mae: 0.4227\n",
+ "Epoch 73/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.2077 - mae: 0.3941 - val_loss: 0.2265 - val_mae: 0.4219\n",
+ "Epoch 74/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.2116 - mae: 0.3993 - val_loss: 0.2249 - val_mae: 0.4205\n",
+ "Epoch 75/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.2227 - mae: 0.4148 - val_loss: 0.2235 - val_mae: 0.4198\n",
+ "Epoch 76/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.2026 - mae: 0.3917 - val_loss: 0.2216 - val_mae: 0.4175\n",
+ "Epoch 77/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2083 - mae: 0.3966 - val_loss: 0.2200 - val_mae: 0.4157\n",
+ "Epoch 78/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.2055 - mae: 0.3947 - val_loss: 0.2186 - val_mae: 0.4144\n",
+ "Epoch 79/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.2069 - mae: 0.3965 - val_loss: 0.2171 - val_mae: 0.4128\n",
+ "Epoch 80/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1983 - mae: 0.3871 - val_loss: 0.2158 - val_mae: 0.4117\n",
+ "Epoch 81/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1994 - mae: 0.3876 - val_loss: 0.2146 - val_mae: 0.4109\n",
+ "Epoch 82/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1971 - mae: 0.3824 - val_loss: 0.2135 - val_mae: 0.4104\n",
+ "Epoch 83/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1965 - mae: 0.3879 - val_loss: 0.2120 - val_mae: 0.4085\n",
+ "Epoch 84/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.2006 - mae: 0.3906 - val_loss: 0.2109 - val_mae: 0.4074\n",
+ "Epoch 85/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2048 - mae: 0.3979 - val_loss: 0.2096 - val_mae: 0.4057\n",
+ "Epoch 86/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1932 - mae: 0.3864 - val_loss: 0.2083 - val_mae: 0.4042\n",
+ "Epoch 87/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1916 - mae: 0.3830 - val_loss: 0.2073 - val_mae: 0.4036\n",
+ "Epoch 88/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1984 - mae: 0.3905 - val_loss: 0.2062 - val_mae: 0.4023\n",
+ "Epoch 89/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1939 - mae: 0.3874 - val_loss: 0.2052 - val_mae: 0.4010\n",
+ "Epoch 90/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1902 - mae: 0.3827 - val_loss: 0.2042 - val_mae: 0.4001\n",
+ "Epoch 91/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1888 - mae: 0.3784 - val_loss: 0.2038 - val_mae: 0.4009\n",
+ "Epoch 92/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1927 - mae: 0.3843 - val_loss: 0.2030 - val_mae: 0.4003\n",
+ "Epoch 93/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1851 - mae: 0.3730 - val_loss: 0.2018 - val_mae: 0.3981\n",
+ "Epoch 94/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1984 - mae: 0.3916 - val_loss: 0.2008 - val_mae: 0.3963\n",
+ "Epoch 95/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1851 - mae: 0.3733 - val_loss: 0.2001 - val_mae: 0.3960\n",
+ "Epoch 96/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1881 - mae: 0.3796 - val_loss: 0.1994 - val_mae: 0.3953\n",
+ "Epoch 97/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1859 - mae: 0.3765 - val_loss: 0.1987 - val_mae: 0.3949\n",
+ "Epoch 98/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1822 - mae: 0.3711 - val_loss: 0.1979 - val_mae: 0.3935\n",
+ "Epoch 99/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1886 - mae: 0.3764 - val_loss: 0.1970 - val_mae: 0.3915\n",
+ "Epoch 100/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1878 - mae: 0.3758 - val_loss: 0.1964 - val_mae: 0.3908\n",
+ "Epoch 101/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1769 - mae: 0.3670 - val_loss: 0.1958 - val_mae: 0.3897\n",
+ "Epoch 102/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1832 - mae: 0.3731 - val_loss: 0.1953 - val_mae: 0.3897\n",
+ "Epoch 103/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1827 - mae: 0.3728 - val_loss: 0.1952 - val_mae: 0.3910\n",
+ "Epoch 104/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1867 - mae: 0.3783 - val_loss: 0.1945 - val_mae: 0.3898\n",
+ "Epoch 105/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1813 - mae: 0.3691 - val_loss: 0.1937 - val_mae: 0.3869\n",
+ "Epoch 106/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1715 - mae: 0.3605 - val_loss: 0.1932 - val_mae: 0.3869\n",
+ "Epoch 107/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1800 - mae: 0.3692 - val_loss: 0.1928 - val_mae: 0.3859\n",
+ "Epoch 108/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1884 - mae: 0.3725 - val_loss: 0.1925 - val_mae: 0.3863\n",
+ "Epoch 109/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1777 - mae: 0.3686 - val_loss: 0.1922 - val_mae: 0.3862\n",
+ "Epoch 110/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1801 - mae: 0.3715 - val_loss: 0.1917 - val_mae: 0.3853\n",
+ "Epoch 111/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1794 - mae: 0.3665 - val_loss: 0.1913 - val_mae: 0.3846\n",
+ "Epoch 112/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1811 - mae: 0.3664 - val_loss: 0.1908 - val_mae: 0.3831\n",
+ "Epoch 113/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1821 - mae: 0.3655 - val_loss: 0.1904 - val_mae: 0.3823\n",
+ "Epoch 114/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1755 - mae: 0.3621 - val_loss: 0.1901 - val_mae: 0.3818\n",
+ "Epoch 115/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1718 - mae: 0.3584 - val_loss: 0.1899 - val_mae: 0.3820\n",
+ "Epoch 116/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1684 - mae: 0.3516 - val_loss: 0.1896 - val_mae: 0.3815\n",
+ "Epoch 117/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1760 - mae: 0.3618 - val_loss: 0.1894 - val_mae: 0.3816\n",
+ "Epoch 118/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1748 - mae: 0.3587 - val_loss: 0.1890 - val_mae: 0.3804\n",
+ "Epoch 119/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1749 - mae: 0.3626 - val_loss: 0.1887 - val_mae: 0.3792\n",
+ "Epoch 120/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1620 - mae: 0.3493 - val_loss: 0.1884 - val_mae: 0.3779\n",
+ "Epoch 121/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1720 - mae: 0.3573 - val_loss: 0.1883 - val_mae: 0.3789\n",
+ "Epoch 122/500\n",
+ "10/10 [==============================] - 0s 18ms/step - loss: 0.1767 - mae: 0.3623 - val_loss: 0.1881 - val_mae: 0.3787\n",
+ "Epoch 123/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1835 - mae: 0.3729 - val_loss: 0.1881 - val_mae: 0.3794\n",
+ "Epoch 124/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1782 - mae: 0.3691 - val_loss: 0.1876 - val_mae: 0.3775\n",
+ "Epoch 125/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1669 - mae: 0.3548 - val_loss: 0.1877 - val_mae: 0.3784\n",
+ "Epoch 126/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1819 - mae: 0.3693 - val_loss: 0.1878 - val_mae: 0.3791\n",
+ "Epoch 127/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1731 - mae: 0.3626 - val_loss: 0.1877 - val_mae: 0.3789\n",
+ "Epoch 128/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1696 - mae: 0.3556 - val_loss: 0.1872 - val_mae: 0.3773\n",
+ "Epoch 129/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1764 - mae: 0.3649 - val_loss: 0.1869 - val_mae: 0.3758\n",
+ "Epoch 130/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1770 - mae: 0.3649 - val_loss: 0.1867 - val_mae: 0.3750\n",
+ "Epoch 131/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1857 - mae: 0.3696 - val_loss: 0.1867 - val_mae: 0.3760\n",
+ "Epoch 132/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1715 - mae: 0.3566 - val_loss: 0.1865 - val_mae: 0.3754\n",
+ "Epoch 133/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1717 - mae: 0.3536 - val_loss: 0.1869 - val_mae: 0.3772\n",
+ "Epoch 134/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1692 - mae: 0.3558 - val_loss: 0.1863 - val_mae: 0.3751\n",
+ "Epoch 135/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1844 - mae: 0.3690 - val_loss: 0.1862 - val_mae: 0.3744\n",
+ "Epoch 136/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1608 - mae: 0.3431 - val_loss: 0.1861 - val_mae: 0.3737\n",
+ "Epoch 137/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1626 - mae: 0.3457 - val_loss: 0.1860 - val_mae: 0.3739\n",
+ "Epoch 138/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1705 - mae: 0.3598 - val_loss: 0.1861 - val_mae: 0.3748\n",
+ "Epoch 139/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1797 - mae: 0.3651 - val_loss: 0.1863 - val_mae: 0.3759\n",
+ "Epoch 140/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1692 - mae: 0.3543 - val_loss: 0.1858 - val_mae: 0.3739\n",
+ "Epoch 141/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1696 - mae: 0.3572 - val_loss: 0.1859 - val_mae: 0.3743\n",
+ "Epoch 142/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1652 - mae: 0.3503 - val_loss: 0.1861 - val_mae: 0.3754\n",
+ "Epoch 143/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1644 - mae: 0.3504 - val_loss: 0.1857 - val_mae: 0.3734\n",
+ "Epoch 144/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1721 - mae: 0.3567 - val_loss: 0.1855 - val_mae: 0.3728\n",
+ "Epoch 145/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1772 - mae: 0.3612 - val_loss: 0.1856 - val_mae: 0.3737\n",
+ "Epoch 146/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1654 - mae: 0.3502 - val_loss: 0.1856 - val_mae: 0.3736\n",
+ "Epoch 147/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1761 - mae: 0.3575 - val_loss: 0.1856 - val_mae: 0.3738\n",
+ "Epoch 148/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1693 - mae: 0.3542 - val_loss: 0.1853 - val_mae: 0.3719\n",
+ "Epoch 149/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1634 - mae: 0.3450 - val_loss: 0.1854 - val_mae: 0.3727\n",
+ "Epoch 150/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1642 - mae: 0.3457 - val_loss: 0.1853 - val_mae: 0.3723\n",
+ "Epoch 151/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1868 - mae: 0.3703 - val_loss: 0.1854 - val_mae: 0.3731\n",
+ "Epoch 152/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1797 - mae: 0.3615 - val_loss: 0.1852 - val_mae: 0.3716\n",
+ "Epoch 153/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1739 - mae: 0.3548 - val_loss: 0.1851 - val_mae: 0.3716\n",
+ "Epoch 154/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1779 - mae: 0.3633 - val_loss: 0.1851 - val_mae: 0.3711\n",
+ "Epoch 155/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1606 - mae: 0.3401 - val_loss: 0.1850 - val_mae: 0.3709\n",
+ "Epoch 156/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1834 - mae: 0.3646 - val_loss: 0.1853 - val_mae: 0.3728\n",
+ "Epoch 157/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1704 - mae: 0.3552 - val_loss: 0.1850 - val_mae: 0.3712\n",
+ "Epoch 158/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1741 - mae: 0.3575 - val_loss: 0.1850 - val_mae: 0.3714\n",
+ "Epoch 159/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1624 - mae: 0.3450 - val_loss: 0.1849 - val_mae: 0.3705\n",
+ "Epoch 160/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1691 - mae: 0.3547 - val_loss: 0.1850 - val_mae: 0.3712\n",
+ "Epoch 161/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1604 - mae: 0.3414 - val_loss: 0.1849 - val_mae: 0.3703\n",
+ "Epoch 162/500\n",
+ "10/10 [==============================] - 0s 18ms/step - loss: 0.1600 - mae: 0.3412 - val_loss: 0.1848 - val_mae: 0.3700\n",
+ "Epoch 163/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1564 - mae: 0.3413 - val_loss: 0.1848 - val_mae: 0.3694\n",
+ "Epoch 164/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1664 - mae: 0.3461 - val_loss: 0.1851 - val_mae: 0.3719\n",
+ "Epoch 165/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1672 - mae: 0.3500 - val_loss: 0.1848 - val_mae: 0.3698\n",
+ "Epoch 166/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1717 - mae: 0.3600 - val_loss: 0.1847 - val_mae: 0.3694\n",
+ "Epoch 167/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1645 - mae: 0.3450 - val_loss: 0.1849 - val_mae: 0.3707\n",
+ "Epoch 168/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1697 - mae: 0.3467 - val_loss: 0.1853 - val_mae: 0.3724\n",
+ "Epoch 169/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1742 - mae: 0.3566 - val_loss: 0.1850 - val_mae: 0.3712\n",
+ "Epoch 170/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1650 - mae: 0.3455 - val_loss: 0.1847 - val_mae: 0.3693\n",
+ "Epoch 171/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1667 - mae: 0.3511 - val_loss: 0.1847 - val_mae: 0.3693\n",
+ "Epoch 172/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1689 - mae: 0.3476 - val_loss: 0.1849 - val_mae: 0.3710\n",
+ "Epoch 173/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1709 - mae: 0.3538 - val_loss: 0.1848 - val_mae: 0.3706\n",
+ "Epoch 174/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1794 - mae: 0.3588 - val_loss: 0.1847 - val_mae: 0.3696\n",
+ "Epoch 175/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1753 - mae: 0.3539 - val_loss: 0.1846 - val_mae: 0.3680\n",
+ "Epoch 176/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1704 - mae: 0.3511 - val_loss: 0.1846 - val_mae: 0.3686\n",
+ "Epoch 177/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1635 - mae: 0.3465 - val_loss: 0.1846 - val_mae: 0.3691\n",
+ "Epoch 178/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1669 - mae: 0.3508 - val_loss: 0.1850 - val_mae: 0.3712\n",
+ "Epoch 179/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1661 - mae: 0.3434 - val_loss: 0.1847 - val_mae: 0.3696\n",
+ "Epoch 180/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1668 - mae: 0.3500 - val_loss: 0.1847 - val_mae: 0.3696\n",
+ "Epoch 181/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1600 - mae: 0.3416 - val_loss: 0.1846 - val_mae: 0.3689\n",
+ "Epoch 182/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1672 - mae: 0.3500 - val_loss: 0.1846 - val_mae: 0.3693\n",
+ "Epoch 183/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1663 - mae: 0.3461 - val_loss: 0.1847 - val_mae: 0.3698\n",
+ "Epoch 184/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.1690 - mae: 0.3494 - val_loss: 0.1847 - val_mae: 0.3695\n",
+ "Epoch 185/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1716 - mae: 0.3513 - val_loss: 0.1846 - val_mae: 0.3690\n",
+ "Epoch 186/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1748 - mae: 0.3588 - val_loss: 0.1847 - val_mae: 0.3696\n",
+ "Epoch 187/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1588 - mae: 0.3364 - val_loss: 0.1849 - val_mae: 0.3705\n",
+ "Epoch 188/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1739 - mae: 0.3539 - val_loss: 0.1849 - val_mae: 0.3704\n",
+ "Epoch 189/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1711 - mae: 0.3497 - val_loss: 0.1846 - val_mae: 0.3690\n",
+ "Epoch 190/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1706 - mae: 0.3525 - val_loss: 0.1845 - val_mae: 0.3678\n",
+ "Epoch 191/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1621 - mae: 0.3447 - val_loss: 0.1846 - val_mae: 0.3688\n",
+ "Epoch 192/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1669 - mae: 0.3485 - val_loss: 0.1847 - val_mae: 0.3699\n",
+ "Epoch 193/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1694 - mae: 0.3498 - val_loss: 0.1847 - val_mae: 0.3697\n",
+ "Epoch 194/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1708 - mae: 0.3520 - val_loss: 0.1846 - val_mae: 0.3694\n",
+ "Epoch 195/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1796 - mae: 0.3623 - val_loss: 0.1849 - val_mae: 0.3708\n",
+ "Epoch 196/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1624 - mae: 0.3417 - val_loss: 0.1849 - val_mae: 0.3706\n",
+ "Epoch 197/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1671 - mae: 0.3529 - val_loss: 0.1848 - val_mae: 0.3703\n",
+ "Epoch 198/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1680 - mae: 0.3479 - val_loss: 0.1845 - val_mae: 0.3690\n",
+ "Epoch 199/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1750 - mae: 0.3587 - val_loss: 0.1844 - val_mae: 0.3677\n",
+ "Epoch 200/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1613 - mae: 0.3419 - val_loss: 0.1845 - val_mae: 0.3684\n",
+ "Epoch 201/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1625 - mae: 0.3434 - val_loss: 0.1845 - val_mae: 0.3684\n",
+ "Epoch 202/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1780 - mae: 0.3576 - val_loss: 0.1845 - val_mae: 0.3688\n",
+ "Epoch 203/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1567 - mae: 0.3381 - val_loss: 0.1845 - val_mae: 0.3677\n",
+ "Epoch 204/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1675 - mae: 0.3489 - val_loss: 0.1846 - val_mae: 0.3692\n",
+ "Epoch 205/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1766 - mae: 0.3609 - val_loss: 0.1847 - val_mae: 0.3694\n",
+ "Epoch 206/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1649 - mae: 0.3489 - val_loss: 0.1845 - val_mae: 0.3685\n",
+ "Epoch 207/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1723 - mae: 0.3526 - val_loss: 0.1845 - val_mae: 0.3679\n",
+ "Epoch 208/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1788 - mae: 0.3573 - val_loss: 0.1846 - val_mae: 0.3689\n",
+ "Epoch 209/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1659 - mae: 0.3427 - val_loss: 0.1847 - val_mae: 0.3694\n",
+ "Epoch 210/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1737 - mae: 0.3549 - val_loss: 0.1845 - val_mae: 0.3684\n",
+ "Epoch 211/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1616 - mae: 0.3437 - val_loss: 0.1845 - val_mae: 0.3686\n",
+ "Epoch 212/500\n",
+ "10/10 [==============================] - 0s 18ms/step - loss: 0.1665 - mae: 0.3466 - val_loss: 0.1847 - val_mae: 0.3696\n",
+ "Epoch 213/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1726 - mae: 0.3560 - val_loss: 0.1846 - val_mae: 0.3692\n",
+ "Epoch 214/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1716 - mae: 0.3516 - val_loss: 0.1844 - val_mae: 0.3673\n",
+ "Epoch 215/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1662 - mae: 0.3398 - val_loss: 0.1845 - val_mae: 0.3685\n",
+ "Epoch 216/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1773 - mae: 0.3588 - val_loss: 0.1845 - val_mae: 0.3686\n",
+ "Epoch 217/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1645 - mae: 0.3485 - val_loss: 0.1846 - val_mae: 0.3690\n",
+ "Epoch 218/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1664 - mae: 0.3514 - val_loss: 0.1848 - val_mae: 0.3700\n",
+ "Epoch 219/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1775 - mae: 0.3572 - val_loss: 0.1848 - val_mae: 0.3700\n",
+ "Epoch 220/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1650 - mae: 0.3451 - val_loss: 0.1846 - val_mae: 0.3693\n",
+ "Epoch 221/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1607 - mae: 0.3393 - val_loss: 0.1845 - val_mae: 0.3686\n",
+ "Epoch 222/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1796 - mae: 0.3623 - val_loss: 0.1845 - val_mae: 0.3685\n",
+ "Epoch 223/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1759 - mae: 0.3592 - val_loss: 0.1845 - val_mae: 0.3682\n",
+ "Epoch 224/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1702 - mae: 0.3513 - val_loss: 0.1845 - val_mae: 0.3685\n",
+ "Epoch 225/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1823 - mae: 0.3648 - val_loss: 0.1852 - val_mae: 0.3715\n",
+ "Epoch 226/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1698 - mae: 0.3515 - val_loss: 0.1848 - val_mae: 0.3701\n",
+ "Epoch 227/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1658 - mae: 0.3447 - val_loss: 0.1847 - val_mae: 0.3699\n",
+ "Epoch 228/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1756 - mae: 0.3553 - val_loss: 0.1846 - val_mae: 0.3694\n",
+ "Epoch 229/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1670 - mae: 0.3549 - val_loss: 0.1844 - val_mae: 0.3671\n",
+ "Epoch 230/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1685 - mae: 0.3480 - val_loss: 0.1845 - val_mae: 0.3682\n",
+ "Epoch 231/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1740 - mae: 0.3578 - val_loss: 0.1846 - val_mae: 0.3691\n",
+ "Epoch 232/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1774 - mae: 0.3602 - val_loss: 0.1846 - val_mae: 0.3692\n",
+ "Epoch 233/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1566 - mae: 0.3383 - val_loss: 0.1846 - val_mae: 0.3693\n",
+ "Epoch 234/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1714 - mae: 0.3518 - val_loss: 0.1847 - val_mae: 0.3696\n",
+ "Epoch 235/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1650 - mae: 0.3435 - val_loss: 0.1847 - val_mae: 0.3697\n",
+ "Epoch 236/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1721 - mae: 0.3513 - val_loss: 0.1846 - val_mae: 0.3694\n",
+ "Epoch 237/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1710 - mae: 0.3535 - val_loss: 0.1845 - val_mae: 0.3683\n",
+ "Epoch 238/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1638 - mae: 0.3453 - val_loss: 0.1846 - val_mae: 0.3692\n",
+ "Epoch 239/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1687 - mae: 0.3518 - val_loss: 0.1845 - val_mae: 0.3687\n",
+ "Epoch 240/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1701 - mae: 0.3519 - val_loss: 0.1847 - val_mae: 0.3697\n",
+ "Epoch 241/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1721 - mae: 0.3530 - val_loss: 0.1849 - val_mae: 0.3703\n",
+ "Epoch 242/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1610 - mae: 0.3413 - val_loss: 0.1846 - val_mae: 0.3691\n",
+ "Epoch 243/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1556 - mae: 0.3387 - val_loss: 0.1845 - val_mae: 0.3685\n",
+ "Epoch 244/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1663 - mae: 0.3485 - val_loss: 0.1845 - val_mae: 0.3688\n",
+ "Epoch 245/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1761 - mae: 0.3585 - val_loss: 0.1848 - val_mae: 0.3703\n",
+ "Epoch 246/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1592 - mae: 0.3394 - val_loss: 0.1849 - val_mae: 0.3706\n",
+ "Epoch 247/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1724 - mae: 0.3568 - val_loss: 0.1845 - val_mae: 0.3682\n",
+ "Epoch 248/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1668 - mae: 0.3516 - val_loss: 0.1844 - val_mae: 0.3671\n",
+ "Epoch 249/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1676 - mae: 0.3474 - val_loss: 0.1845 - val_mae: 0.3688\n",
+ "Epoch 250/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1747 - mae: 0.3563 - val_loss: 0.1844 - val_mae: 0.3680\n",
+ "Epoch 251/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1766 - mae: 0.3607 - val_loss: 0.1844 - val_mae: 0.3676\n",
+ "Epoch 252/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1693 - mae: 0.3522 - val_loss: 0.1847 - val_mae: 0.3696\n",
+ "Epoch 253/500\n",
+ "10/10 [==============================] - 0s 19ms/step - loss: 0.1632 - mae: 0.3429 - val_loss: 0.1844 - val_mae: 0.3675\n",
+ "Epoch 254/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1747 - mae: 0.3537 - val_loss: 0.1846 - val_mae: 0.3689\n",
+ "Epoch 255/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1731 - mae: 0.3574 - val_loss: 0.1847 - val_mae: 0.3695\n",
+ "Epoch 256/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1696 - mae: 0.3525 - val_loss: 0.1845 - val_mae: 0.3676\n",
+ "Epoch 257/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1572 - mae: 0.3387 - val_loss: 0.1845 - val_mae: 0.3681\n",
+ "Epoch 258/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1617 - mae: 0.3409 - val_loss: 0.1849 - val_mae: 0.3702\n",
+ "Epoch 259/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1809 - mae: 0.3600 - val_loss: 0.1850 - val_mae: 0.3707\n",
+ "Epoch 260/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1633 - mae: 0.3435 - val_loss: 0.1846 - val_mae: 0.3689\n",
+ "Epoch 261/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1684 - mae: 0.3506 - val_loss: 0.1846 - val_mae: 0.3689\n",
+ "Epoch 262/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1710 - mae: 0.3512 - val_loss: 0.1848 - val_mae: 0.3703\n",
+ "Epoch 263/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1657 - mae: 0.3471 - val_loss: 0.1850 - val_mae: 0.3709\n",
+ "Epoch 264/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1764 - mae: 0.3611 - val_loss: 0.1849 - val_mae: 0.3704\n",
+ "Epoch 265/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1710 - mae: 0.3487 - val_loss: 0.1846 - val_mae: 0.3691\n",
+ "Epoch 266/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1759 - mae: 0.3565 - val_loss: 0.1845 - val_mae: 0.3685\n",
+ "Epoch 267/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1680 - mae: 0.3505 - val_loss: 0.1844 - val_mae: 0.3669\n",
+ "Epoch 268/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1764 - mae: 0.3597 - val_loss: 0.1844 - val_mae: 0.3671\n",
+ "Epoch 269/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1676 - mae: 0.3494 - val_loss: 0.1847 - val_mae: 0.3693\n",
+ "Epoch 270/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1641 - mae: 0.3478 - val_loss: 0.1846 - val_mae: 0.3687\n",
+ "Epoch 271/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1784 - mae: 0.3615 - val_loss: 0.1846 - val_mae: 0.3689\n",
+ "Epoch 272/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1767 - mae: 0.3571 - val_loss: 0.1846 - val_mae: 0.3687\n",
+ "Epoch 273/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1714 - mae: 0.3521 - val_loss: 0.1845 - val_mae: 0.3676\n",
+ "Epoch 274/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1710 - mae: 0.3503 - val_loss: 0.1845 - val_mae: 0.3678\n",
+ "Epoch 275/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1729 - mae: 0.3507 - val_loss: 0.1845 - val_mae: 0.3683\n",
+ "Epoch 276/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1754 - mae: 0.3579 - val_loss: 0.1845 - val_mae: 0.3677\n",
+ "Epoch 277/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1705 - mae: 0.3504 - val_loss: 0.1845 - val_mae: 0.3672\n",
+ "Epoch 278/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1721 - mae: 0.3553 - val_loss: 0.1846 - val_mae: 0.3686\n",
+ "Epoch 279/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1664 - mae: 0.3476 - val_loss: 0.1847 - val_mae: 0.3692\n",
+ "Epoch 280/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1655 - mae: 0.3467 - val_loss: 0.1847 - val_mae: 0.3692\n",
+ "Epoch 281/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1693 - mae: 0.3534 - val_loss: 0.1846 - val_mae: 0.3687\n",
+ "Epoch 282/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1732 - mae: 0.3580 - val_loss: 0.1847 - val_mae: 0.3692\n",
+ "Epoch 283/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1779 - mae: 0.3598 - val_loss: 0.1847 - val_mae: 0.3694\n",
+ "Epoch 284/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1763 - mae: 0.3570 - val_loss: 0.1849 - val_mae: 0.3705\n",
+ "Epoch 285/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1636 - mae: 0.3474 - val_loss: 0.1845 - val_mae: 0.3674\n",
+ "Epoch 286/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1716 - mae: 0.3496 - val_loss: 0.1845 - val_mae: 0.3680\n",
+ "Epoch 287/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1769 - mae: 0.3579 - val_loss: 0.1846 - val_mae: 0.3691\n",
+ "Epoch 288/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1771 - mae: 0.3565 - val_loss: 0.1856 - val_mae: 0.3726\n",
+ "Epoch 289/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1709 - mae: 0.3516 - val_loss: 0.1848 - val_mae: 0.3703\n",
+ "Epoch 290/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1719 - mae: 0.3584 - val_loss: 0.1844 - val_mae: 0.3675\n",
+ "Epoch 291/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.1730 - mae: 0.3544 - val_loss: 0.1846 - val_mae: 0.3693\n",
+ "Epoch 292/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.1751 - mae: 0.3558 - val_loss: 0.1846 - val_mae: 0.3694\n",
+ "Epoch 293/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1658 - mae: 0.3511 - val_loss: 0.1846 - val_mae: 0.3693\n",
+ "Epoch 294/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1713 - mae: 0.3536 - val_loss: 0.1846 - val_mae: 0.3693\n",
+ "Epoch 295/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1725 - mae: 0.3565 - val_loss: 0.1844 - val_mae: 0.3678\n",
+ "Epoch 296/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1724 - mae: 0.3513 - val_loss: 0.1846 - val_mae: 0.3691\n",
+ "Epoch 297/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1680 - mae: 0.3520 - val_loss: 0.1845 - val_mae: 0.3683\n",
+ "Epoch 298/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1734 - mae: 0.3523 - val_loss: 0.1848 - val_mae: 0.3704\n",
+ "Epoch 299/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1756 - mae: 0.3561 - val_loss: 0.1846 - val_mae: 0.3695\n",
+ "Epoch 300/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1650 - mae: 0.3467 - val_loss: 0.1844 - val_mae: 0.3675\n",
+ "Epoch 301/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1690 - mae: 0.3495 - val_loss: 0.1844 - val_mae: 0.3669\n",
+ "Epoch 302/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1642 - mae: 0.3458 - val_loss: 0.1846 - val_mae: 0.3655\n",
+ "Epoch 303/500\n",
+ "10/10 [==============================] - 0s 19ms/step - loss: 0.1732 - mae: 0.3490 - val_loss: 0.1846 - val_mae: 0.3690\n",
+ "Epoch 304/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1686 - mae: 0.3514 - val_loss: 0.1847 - val_mae: 0.3698\n",
+ "Epoch 305/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1757 - mae: 0.3568 - val_loss: 0.1847 - val_mae: 0.3696\n",
+ "Epoch 306/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1650 - mae: 0.3475 - val_loss: 0.1846 - val_mae: 0.3689\n",
+ "Epoch 307/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1544 - mae: 0.3364 - val_loss: 0.1845 - val_mae: 0.3673\n",
+ "Epoch 308/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1714 - mae: 0.3512 - val_loss: 0.1849 - val_mae: 0.3703\n",
+ "Epoch 309/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1729 - mae: 0.3549 - val_loss: 0.1853 - val_mae: 0.3718\n",
+ "Epoch 310/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1677 - mae: 0.3540 - val_loss: 0.1845 - val_mae: 0.3679\n",
+ "Epoch 311/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1731 - mae: 0.3513 - val_loss: 0.1845 - val_mae: 0.3678\n",
+ "Epoch 312/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.1717 - mae: 0.3521 - val_loss: 0.1845 - val_mae: 0.3687\n",
+ "Epoch 313/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1656 - mae: 0.3425 - val_loss: 0.1846 - val_mae: 0.3689\n",
+ "Epoch 314/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1632 - mae: 0.3439 - val_loss: 0.1847 - val_mae: 0.3694\n",
+ "Epoch 315/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1694 - mae: 0.3512 - val_loss: 0.1846 - val_mae: 0.3690\n",
+ "Epoch 316/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1679 - mae: 0.3496 - val_loss: 0.1851 - val_mae: 0.3712\n",
+ "Epoch 317/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1754 - mae: 0.3533 - val_loss: 0.1851 - val_mae: 0.3712\n",
+ "Epoch 318/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1757 - mae: 0.3582 - val_loss: 0.1847 - val_mae: 0.3694\n",
+ "Epoch 319/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1705 - mae: 0.3522 - val_loss: 0.1845 - val_mae: 0.3679\n",
+ "Epoch 320/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1539 - mae: 0.3368 - val_loss: 0.1845 - val_mae: 0.3679\n",
+ "Epoch 321/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1691 - mae: 0.3523 - val_loss: 0.1849 - val_mae: 0.3704\n",
+ "Epoch 322/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1695 - mae: 0.3494 - val_loss: 0.1854 - val_mae: 0.3720\n",
+ "Epoch 323/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1648 - mae: 0.3469 - val_loss: 0.1845 - val_mae: 0.3680\n",
+ "Epoch 324/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1781 - mae: 0.3610 - val_loss: 0.1845 - val_mae: 0.3684\n",
+ "Epoch 325/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1565 - mae: 0.3364 - val_loss: 0.1850 - val_mae: 0.3707\n",
+ "Epoch 326/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1680 - mae: 0.3496 - val_loss: 0.1849 - val_mae: 0.3706\n",
+ "Epoch 327/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1680 - mae: 0.3463 - val_loss: 0.1849 - val_mae: 0.3704\n",
+ "Epoch 328/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1699 - mae: 0.3538 - val_loss: 0.1846 - val_mae: 0.3693\n",
+ "Epoch 329/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1782 - mae: 0.3604 - val_loss: 0.1848 - val_mae: 0.3704\n",
+ "Epoch 330/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1746 - mae: 0.3527 - val_loss: 0.1848 - val_mae: 0.3704\n",
+ "Epoch 331/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1695 - mae: 0.3496 - val_loss: 0.1846 - val_mae: 0.3695\n",
+ "Epoch 332/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1635 - mae: 0.3445 - val_loss: 0.1846 - val_mae: 0.3689\n",
+ "Epoch 333/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1611 - mae: 0.3453 - val_loss: 0.1845 - val_mae: 0.3678\n",
+ "Epoch 334/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1595 - mae: 0.3416 - val_loss: 0.1846 - val_mae: 0.3692\n",
+ "Epoch 335/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1733 - mae: 0.3562 - val_loss: 0.1846 - val_mae: 0.3690\n",
+ "Epoch 336/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1668 - mae: 0.3458 - val_loss: 0.1845 - val_mae: 0.3676\n",
+ "Epoch 337/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1678 - mae: 0.3455 - val_loss: 0.1846 - val_mae: 0.3685\n",
+ "Epoch 338/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1768 - mae: 0.3578 - val_loss: 0.1846 - val_mae: 0.3692\n",
+ "Epoch 339/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1674 - mae: 0.3485 - val_loss: 0.1846 - val_mae: 0.3690\n",
+ "Epoch 340/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1736 - mae: 0.3536 - val_loss: 0.1848 - val_mae: 0.3700\n",
+ "Epoch 341/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1655 - mae: 0.3474 - val_loss: 0.1846 - val_mae: 0.3686\n",
+ "Epoch 342/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1727 - mae: 0.3539 - val_loss: 0.1846 - val_mae: 0.3686\n",
+ "Epoch 343/500\n",
+ "10/10 [==============================] - 0s 19ms/step - loss: 0.1721 - mae: 0.3489 - val_loss: 0.1846 - val_mae: 0.3690\n",
+ "Epoch 344/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1620 - mae: 0.3464 - val_loss: 0.1845 - val_mae: 0.3675\n",
+ "Epoch 345/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1757 - mae: 0.3548 - val_loss: 0.1845 - val_mae: 0.3681\n",
+ "Epoch 346/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1753 - mae: 0.3576 - val_loss: 0.1846 - val_mae: 0.3685\n",
+ "Epoch 347/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1698 - mae: 0.3471 - val_loss: 0.1845 - val_mae: 0.3678\n",
+ "Epoch 348/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1793 - mae: 0.3578 - val_loss: 0.1845 - val_mae: 0.3676\n",
+ "Epoch 349/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1677 - mae: 0.3506 - val_loss: 0.1846 - val_mae: 0.3683\n",
+ "Epoch 350/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1683 - mae: 0.3502 - val_loss: 0.1847 - val_mae: 0.3686\n",
+ "Epoch 351/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1813 - mae: 0.3624 - val_loss: 0.1846 - val_mae: 0.3678\n",
+ "Epoch 352/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1656 - mae: 0.3440 - val_loss: 0.1846 - val_mae: 0.3674\n",
+ "Epoch 353/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1705 - mae: 0.3515 - val_loss: 0.1848 - val_mae: 0.3692\n",
+ "Epoch 354/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1786 - mae: 0.3562 - val_loss: 0.1850 - val_mae: 0.3703\n",
+ "Epoch 355/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1719 - mae: 0.3518 - val_loss: 0.1847 - val_mae: 0.3683\n",
+ "Epoch 356/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1698 - mae: 0.3528 - val_loss: 0.1846 - val_mae: 0.3679\n",
+ "Epoch 357/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1682 - mae: 0.3499 - val_loss: 0.1846 - val_mae: 0.3678\n",
+ "Epoch 358/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1627 - mae: 0.3442 - val_loss: 0.1848 - val_mae: 0.3694\n",
+ "Epoch 359/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1634 - mae: 0.3428 - val_loss: 0.1855 - val_mae: 0.3718\n",
+ "Epoch 360/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1671 - mae: 0.3486 - val_loss: 0.1848 - val_mae: 0.3694\n",
+ "Epoch 361/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1748 - mae: 0.3609 - val_loss: 0.1846 - val_mae: 0.3681\n",
+ "Epoch 362/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1655 - mae: 0.3470 - val_loss: 0.1846 - val_mae: 0.3673\n",
+ "Epoch 363/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1610 - mae: 0.3395 - val_loss: 0.1848 - val_mae: 0.3693\n",
+ "Epoch 364/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1713 - mae: 0.3539 - val_loss: 0.1847 - val_mae: 0.3688\n",
+ "Epoch 365/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1664 - mae: 0.3484 - val_loss: 0.1847 - val_mae: 0.3691\n",
+ "Epoch 366/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1554 - mae: 0.3350 - val_loss: 0.1847 - val_mae: 0.3691\n",
+ "Epoch 367/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1701 - mae: 0.3511 - val_loss: 0.1845 - val_mae: 0.3679\n",
+ "Epoch 368/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1720 - mae: 0.3546 - val_loss: 0.1847 - val_mae: 0.3691\n",
+ "Epoch 369/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1675 - mae: 0.3495 - val_loss: 0.1847 - val_mae: 0.3695\n",
+ "Epoch 370/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1645 - mae: 0.3449 - val_loss: 0.1846 - val_mae: 0.3684\n",
+ "Epoch 371/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.1790 - mae: 0.3588 - val_loss: 0.1846 - val_mae: 0.3687\n",
+ "Epoch 372/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.1662 - mae: 0.3466 - val_loss: 0.1847 - val_mae: 0.3689\n",
+ "Epoch 373/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1693 - mae: 0.3557 - val_loss: 0.1850 - val_mae: 0.3707\n",
+ "Epoch 374/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1682 - mae: 0.3493 - val_loss: 0.1851 - val_mae: 0.3711\n",
+ "Epoch 375/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1777 - mae: 0.3612 - val_loss: 0.1846 - val_mae: 0.3690\n",
+ "Epoch 376/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1682 - mae: 0.3517 - val_loss: 0.1846 - val_mae: 0.3687\n",
+ "Epoch 377/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1623 - mae: 0.3432 - val_loss: 0.1847 - val_mae: 0.3696\n",
+ "Epoch 378/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1790 - mae: 0.3576 - val_loss: 0.1850 - val_mae: 0.3709\n",
+ "Epoch 379/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1795 - mae: 0.3594 - val_loss: 0.1846 - val_mae: 0.3685\n",
+ "Epoch 380/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1635 - mae: 0.3440 - val_loss: 0.1846 - val_mae: 0.3691\n",
+ "Epoch 381/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1727 - mae: 0.3509 - val_loss: 0.1847 - val_mae: 0.3697\n",
+ "Epoch 382/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1671 - mae: 0.3511 - val_loss: 0.1848 - val_mae: 0.3703\n",
+ "Epoch 383/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1748 - mae: 0.3557 - val_loss: 0.1848 - val_mae: 0.3701\n",
+ "Epoch 384/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1745 - mae: 0.3581 - val_loss: 0.1848 - val_mae: 0.3703\n",
+ "Epoch 385/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1728 - mae: 0.3566 - val_loss: 0.1846 - val_mae: 0.3693\n",
+ "Epoch 386/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1679 - mae: 0.3499 - val_loss: 0.1847 - val_mae: 0.3696\n",
+ "Epoch 387/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1647 - mae: 0.3420 - val_loss: 0.1849 - val_mae: 0.3704\n",
+ "Epoch 388/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1685 - mae: 0.3485 - val_loss: 0.1846 - val_mae: 0.3684\n",
+ "Epoch 389/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1622 - mae: 0.3443 - val_loss: 0.1847 - val_mae: 0.3692\n",
+ "Epoch 390/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1656 - mae: 0.3495 - val_loss: 0.1847 - val_mae: 0.3692\n",
+ "Epoch 391/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1680 - mae: 0.3484 - val_loss: 0.1848 - val_mae: 0.3700\n",
+ "Epoch 392/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.1779 - mae: 0.3601 - val_loss: 0.1846 - val_mae: 0.3688\n",
+ "Epoch 393/500\n",
+ "10/10 [==============================] - 0s 19ms/step - loss: 0.1667 - mae: 0.3450 - val_loss: 0.1847 - val_mae: 0.3695\n",
+ "Epoch 394/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1668 - mae: 0.3466 - val_loss: 0.1846 - val_mae: 0.3689\n",
+ "Epoch 395/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1751 - mae: 0.3564 - val_loss: 0.1845 - val_mae: 0.3683\n",
+ "Epoch 396/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1742 - mae: 0.3558 - val_loss: 0.1845 - val_mae: 0.3686\n",
+ "Epoch 397/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1800 - mae: 0.3653 - val_loss: 0.1845 - val_mae: 0.3676\n",
+ "Epoch 398/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1663 - mae: 0.3425 - val_loss: 0.1845 - val_mae: 0.3678\n",
+ "Epoch 399/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1731 - mae: 0.3566 - val_loss: 0.1845 - val_mae: 0.3683\n",
+ "Epoch 400/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1656 - mae: 0.3431 - val_loss: 0.1846 - val_mae: 0.3691\n",
+ "Epoch 401/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1603 - mae: 0.3438 - val_loss: 0.1846 - val_mae: 0.3688\n",
+ "Epoch 402/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1670 - mae: 0.3487 - val_loss: 0.1848 - val_mae: 0.3701\n",
+ "Epoch 403/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1762 - mae: 0.3544 - val_loss: 0.1846 - val_mae: 0.3692\n",
+ "Epoch 404/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1714 - mae: 0.3497 - val_loss: 0.1845 - val_mae: 0.3685\n",
+ "Epoch 405/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1652 - mae: 0.3454 - val_loss: 0.1846 - val_mae: 0.3689\n",
+ "Epoch 406/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1663 - mae: 0.3471 - val_loss: 0.1851 - val_mae: 0.3710\n",
+ "Epoch 407/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1604 - mae: 0.3435 - val_loss: 0.1845 - val_mae: 0.3679\n",
+ "Epoch 408/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1710 - mae: 0.3495 - val_loss: 0.1845 - val_mae: 0.3671\n",
+ "Epoch 409/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1716 - mae: 0.3498 - val_loss: 0.1846 - val_mae: 0.3689\n",
+ "Epoch 410/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1906 - mae: 0.3736 - val_loss: 0.1848 - val_mae: 0.3700\n",
+ "Epoch 411/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1804 - mae: 0.3610 - val_loss: 0.1848 - val_mae: 0.3703\n",
+ "Epoch 412/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1685 - mae: 0.3505 - val_loss: 0.1848 - val_mae: 0.3700\n",
+ "Epoch 413/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1598 - mae: 0.3406 - val_loss: 0.1846 - val_mae: 0.3686\n",
+ "Epoch 414/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1619 - mae: 0.3453 - val_loss: 0.1846 - val_mae: 0.3686\n",
+ "Epoch 415/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1786 - mae: 0.3603 - val_loss: 0.1849 - val_mae: 0.3704\n",
+ "Epoch 416/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1803 - mae: 0.3594 - val_loss: 0.1847 - val_mae: 0.3698\n",
+ "Epoch 417/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.1714 - mae: 0.3564 - val_loss: 0.1845 - val_mae: 0.3681\n",
+ "Epoch 418/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1673 - mae: 0.3479 - val_loss: 0.1845 - val_mae: 0.3674\n",
+ "Epoch 419/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1648 - mae: 0.3469 - val_loss: 0.1847 - val_mae: 0.3695\n",
+ "Epoch 420/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1642 - mae: 0.3439 - val_loss: 0.1847 - val_mae: 0.3698\n",
+ "Epoch 421/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1738 - mae: 0.3554 - val_loss: 0.1848 - val_mae: 0.3700\n",
+ "Epoch 422/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1662 - mae: 0.3466 - val_loss: 0.1845 - val_mae: 0.3681\n",
+ "Epoch 423/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1678 - mae: 0.3476 - val_loss: 0.1845 - val_mae: 0.3686\n",
+ "Epoch 424/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1762 - mae: 0.3599 - val_loss: 0.1845 - val_mae: 0.3684\n",
+ "Epoch 425/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1688 - mae: 0.3467 - val_loss: 0.1846 - val_mae: 0.3693\n",
+ "Epoch 426/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1708 - mae: 0.3483 - val_loss: 0.1846 - val_mae: 0.3687\n",
+ "Epoch 427/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1641 - mae: 0.3435 - val_loss: 0.1845 - val_mae: 0.3680\n",
+ "Epoch 428/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1683 - mae: 0.3438 - val_loss: 0.1845 - val_mae: 0.3683\n",
+ "Epoch 429/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1659 - mae: 0.3468 - val_loss: 0.1845 - val_mae: 0.3667\n",
+ "Epoch 430/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1630 - mae: 0.3462 - val_loss: 0.1845 - val_mae: 0.3670\n",
+ "Epoch 431/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1713 - mae: 0.3480 - val_loss: 0.1849 - val_mae: 0.3703\n",
+ "Epoch 432/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1818 - mae: 0.3676 - val_loss: 0.1851 - val_mae: 0.3712\n",
+ "Epoch 433/500\n",
+ "10/10 [==============================] - 0s 19ms/step - loss: 0.1833 - mae: 0.3606 - val_loss: 0.1847 - val_mae: 0.3697\n",
+ "Epoch 434/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1676 - mae: 0.3489 - val_loss: 0.1845 - val_mae: 0.3669\n",
+ "Epoch 435/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1651 - mae: 0.3451 - val_loss: 0.1845 - val_mae: 0.3679\n",
+ "Epoch 436/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1736 - mae: 0.3534 - val_loss: 0.1845 - val_mae: 0.3685\n",
+ "Epoch 437/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1700 - mae: 0.3531 - val_loss: 0.1847 - val_mae: 0.3697\n",
+ "Epoch 438/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1799 - mae: 0.3615 - val_loss: 0.1845 - val_mae: 0.3685\n",
+ "Epoch 439/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1684 - mae: 0.3535 - val_loss: 0.1846 - val_mae: 0.3686\n",
+ "Epoch 440/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1644 - mae: 0.3445 - val_loss: 0.1848 - val_mae: 0.3699\n",
+ "Epoch 441/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1702 - mae: 0.3541 - val_loss: 0.1845 - val_mae: 0.3682\n",
+ "Epoch 442/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1621 - mae: 0.3424 - val_loss: 0.1845 - val_mae: 0.3666\n",
+ "Epoch 443/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1757 - mae: 0.3551 - val_loss: 0.1845 - val_mae: 0.3670\n",
+ "Epoch 444/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1639 - mae: 0.3403 - val_loss: 0.1845 - val_mae: 0.3682\n",
+ "Epoch 445/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1739 - mae: 0.3512 - val_loss: 0.1848 - val_mae: 0.3695\n",
+ "Epoch 446/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1712 - mae: 0.3530 - val_loss: 0.1848 - val_mae: 0.3700\n",
+ "Epoch 447/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1630 - mae: 0.3460 - val_loss: 0.1848 - val_mae: 0.3698\n",
+ "Epoch 448/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1670 - mae: 0.3458 - val_loss: 0.1846 - val_mae: 0.3687\n",
+ "Epoch 449/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1576 - mae: 0.3345 - val_loss: 0.1846 - val_mae: 0.3685\n",
+ "Epoch 450/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1603 - mae: 0.3429 - val_loss: 0.1847 - val_mae: 0.3694\n",
+ "Epoch 451/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1689 - mae: 0.3507 - val_loss: 0.1848 - val_mae: 0.3697\n",
+ "Epoch 452/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1692 - mae: 0.3490 - val_loss: 0.1848 - val_mae: 0.3699\n",
+ "Epoch 453/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1685 - mae: 0.3514 - val_loss: 0.1845 - val_mae: 0.3679\n",
+ "Epoch 454/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1774 - mae: 0.3588 - val_loss: 0.1846 - val_mae: 0.3692\n",
+ "Epoch 455/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1672 - mae: 0.3472 - val_loss: 0.1846 - val_mae: 0.3690\n",
+ "Epoch 456/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.1731 - mae: 0.3566 - val_loss: 0.1846 - val_mae: 0.3688\n",
+ "Epoch 457/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1658 - mae: 0.3454 - val_loss: 0.1847 - val_mae: 0.3693\n",
+ "Epoch 458/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1702 - mae: 0.3520 - val_loss: 0.1845 - val_mae: 0.3683\n",
+ "Epoch 459/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1739 - mae: 0.3532 - val_loss: 0.1846 - val_mae: 0.3684\n",
+ "Epoch 460/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1699 - mae: 0.3490 - val_loss: 0.1846 - val_mae: 0.3688\n",
+ "Epoch 461/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1703 - mae: 0.3547 - val_loss: 0.1845 - val_mae: 0.3671\n",
+ "Epoch 462/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1694 - mae: 0.3505 - val_loss: 0.1846 - val_mae: 0.3682\n",
+ "Epoch 463/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1728 - mae: 0.3542 - val_loss: 0.1848 - val_mae: 0.3698\n",
+ "Epoch 464/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1638 - mae: 0.3433 - val_loss: 0.1847 - val_mae: 0.3691\n",
+ "Epoch 465/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1648 - mae: 0.3382 - val_loss: 0.1845 - val_mae: 0.3676\n",
+ "Epoch 466/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1713 - mae: 0.3515 - val_loss: 0.1845 - val_mae: 0.3670\n",
+ "Epoch 467/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1660 - mae: 0.3467 - val_loss: 0.1846 - val_mae: 0.3684\n",
+ "Epoch 468/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1815 - mae: 0.3630 - val_loss: 0.1852 - val_mae: 0.3714\n",
+ "Epoch 469/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1685 - mae: 0.3455 - val_loss: 0.1852 - val_mae: 0.3712\n",
+ "Epoch 470/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1791 - mae: 0.3612 - val_loss: 0.1846 - val_mae: 0.3686\n",
+ "Epoch 471/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1707 - mae: 0.3523 - val_loss: 0.1846 - val_mae: 0.3685\n",
+ "Epoch 472/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1703 - mae: 0.3525 - val_loss: 0.1846 - val_mae: 0.3683\n",
+ "Epoch 473/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1608 - mae: 0.3447 - val_loss: 0.1846 - val_mae: 0.3671\n",
+ "Epoch 474/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1675 - mae: 0.3465 - val_loss: 0.1848 - val_mae: 0.3693\n",
+ "Epoch 475/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.1689 - mae: 0.3513 - val_loss: 0.1846 - val_mae: 0.3683\n",
+ "Epoch 476/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1632 - mae: 0.3431 - val_loss: 0.1847 - val_mae: 0.3692\n",
+ "Epoch 477/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1642 - mae: 0.3464 - val_loss: 0.1846 - val_mae: 0.3674\n",
+ "Epoch 478/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1734 - mae: 0.3511 - val_loss: 0.1851 - val_mae: 0.3707\n",
+ "Epoch 479/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1803 - mae: 0.3612 - val_loss: 0.1847 - val_mae: 0.3687\n",
+ "Epoch 480/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1679 - mae: 0.3531 - val_loss: 0.1846 - val_mae: 0.3677\n",
+ "Epoch 481/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1597 - mae: 0.3406 - val_loss: 0.1846 - val_mae: 0.3677\n",
+ "Epoch 482/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1761 - mae: 0.3575 - val_loss: 0.1850 - val_mae: 0.3701\n",
+ "Epoch 483/500\n",
+ "10/10 [==============================] - 0s 20ms/step - loss: 0.1707 - mae: 0.3541 - val_loss: 0.1847 - val_mae: 0.3692\n",
+ "Epoch 484/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1746 - mae: 0.3534 - val_loss: 0.1847 - val_mae: 0.3686\n",
+ "Epoch 485/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1644 - mae: 0.3457 - val_loss: 0.1846 - val_mae: 0.3675\n",
+ "Epoch 486/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1724 - mae: 0.3497 - val_loss: 0.1849 - val_mae: 0.3699\n",
+ "Epoch 487/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1743 - mae: 0.3552 - val_loss: 0.1849 - val_mae: 0.3699\n",
+ "Epoch 488/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.1662 - mae: 0.3468 - val_loss: 0.1846 - val_mae: 0.3678\n",
+ "Epoch 489/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1742 - mae: 0.3513 - val_loss: 0.1847 - val_mae: 0.3686\n",
+ "Epoch 490/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1695 - mae: 0.3481 - val_loss: 0.1846 - val_mae: 0.3674\n",
+ "Epoch 491/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1736 - mae: 0.3521 - val_loss: 0.1847 - val_mae: 0.3689\n",
+ "Epoch 492/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1554 - mae: 0.3364 - val_loss: 0.1846 - val_mae: 0.3664\n",
+ "Epoch 493/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1760 - mae: 0.3597 - val_loss: 0.1847 - val_mae: 0.3685\n",
+ "Epoch 494/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1666 - mae: 0.3457 - val_loss: 0.1849 - val_mae: 0.3697\n",
+ "Epoch 495/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1673 - mae: 0.3484 - val_loss: 0.1848 - val_mae: 0.3695\n",
+ "Epoch 496/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1754 - mae: 0.3581 - val_loss: 0.1848 - val_mae: 0.3695\n",
+ "Epoch 497/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1729 - mae: 0.3563 - val_loss: 0.1847 - val_mae: 0.3687\n",
+ "Epoch 498/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1727 - mae: 0.3584 - val_loss: 0.1847 - val_mae: 0.3688\n",
+ "Epoch 499/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1713 - mae: 0.3522 - val_loss: 0.1847 - val_mae: 0.3685\n",
+ "Epoch 500/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1634 - mae: 0.3428 - val_loss: 0.1846 - val_mae: 0.3680\n"
+ ],
+ "name": "stdout"
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "cRE8KpEqVfaS"
+ },
+ "source": [
+ "### 3. Plot Metrics"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "SDsjqfjFm7Fz"
+ },
+ "source": [
+ "**1. Loss (or Mean Squared Error)**\n",
+ "\n",
+ "During training, the model's performance is constantly being measured against both our training data and the validation data that we set aside earlier. Training produces a log of data that tells us how the model's performance changed over the course of the training process.\n",
+ "\n",
+ "The following cells will display some of that data in a graphical form:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "CmvA-ksoln8r",
+ "outputId": "220ea767-6ffd-4eab-c327-c82a016c10eb",
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 295
+ }
+ },
+ "source": [
+ "# Draw a graph of the loss, which is the distance between\n",
+ "# the predicted and actual values during training and validation.\n",
+ "train_loss = history_1.history['loss']\n",
+ "val_loss = history_1.history['val_loss']\n",
+ "\n",
+ "epochs = range(1, len(train_loss) + 1)\n",
+ "\n",
+ "plt.plot(epochs, train_loss, 'g.', label='Training loss')\n",
+ "plt.plot(epochs, val_loss, 'b', label='Validation loss')\n",
+ "plt.title('Training and validation loss')\n",
+ "plt.xlabel('Epochs')\n",
+ "plt.ylabel('Loss')\n",
+ "plt.legend()\n",
+ "plt.show()"
+ ],
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "display_data",
+ "data": {
+ "image/png": "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1KlT+eY3v8kvfvELysvL2bZtW4O9T3VJmkQgIo2npn65KBLBBRdcQGpqKgAbN25k9OjRLF++HDOjtLS0xm2GDx9ORkYGGRkZHHjggXz55ZdkZ2dXWmfw4MEVy/r3709RURFZWVkcfvjhFefnjxw5kqlTp+4xvldffbUiGZ166qkUFxezadMmhg4dyjXXXMNFF13EueeeS3Z2NoMGDeLiiy+mtLSUc845h/79++/Xe7M3msrpoyLSgsT65VItNdJ+ubZt21ZM//KXv+SUU05h0aJFPPXUU7WeS5+RkVExnZqaSllZ2T6tsz8mTpzIAw88wPbt2xk6dChLly7lpJNOYu7cuXTv3p0xY8bwyCOPNOgx90Q1AhFpcLF+uTlFcyjILWiUZtmNGzfSvXtwzerDDz/c4Pvv3bs3H3/8MUVFReTm5vL444/Xuc2JJ57ItGnT+OUvf8mcOXPo0qULBxxwAB999BF9+/alb9++zJ8/n6VLl9K6dWuys7MZO3YsO3fu5O2332bUqFENXo6aKBGISCQau19uwoQJjB49ml//+tcMHz68wfffunVr7rvvPk4//XTatm3LoEGD6twm1jl9zDHH0KZNG/7yl78AcM899zB79mxSUlI4+uijOeOMM5g+fTp33nknaWlpZGVlNWqNoNndszgvL891YxqRxvXBBx9w1FFHJTqMhNuyZQtZWVm4Oz/+8Y/p2bMnV199dd0bNrKaPi8ze8vdazyPVn0EIiL1dP/999O/f3+OPvpoNm7cyGWXXZbokBqEmoZEROrp6quvbpI1gP2lGoGISJJTIhARSXJKBCIiSU6JQEQkySkRiEiTd8opp/D8889XWnbPPfcwfvz4WrcpKCggdqr5mWeeyYYNG6qtM2nSJO666649HnvGjBksWbL7Drs33XQTL7744t6EX6OmNFy1EoGINHkjR45k+vTplZZNnz69XgO/QTBqaIcOHfbp2FUTwS233MJpp522T/tqqpQIRKTJO//883nmmWcqbkJTVFTEZ599xoknnsj48ePJy8vj6KOP5uabb65x+9zcXNauXQvAbbfdRq9evTjhhBMqhqqG4BqBQYMG0a9fP8477zy2bdvGvHnzmDlzJtdeey39+/fno48+YsyYMfzjH/8AYNasWQwYMIC+ffty8cUXs3Pnzorj3XzzzRx77LH07duXpUuX7rF8iR6u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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "tags": [],
+ "needs_background": "light"
+ }
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "iOFBSbPcYCN4"
+ },
+ "source": [
+ "The graph shows the _loss_ (or the difference between the model's predictions and the actual data) for each epoch. There are several ways to calculate loss, and the method we have used is _mean squared error_. There is a distinct loss value given for the training and the validation data.\n",
+ "\n",
+ "As we can see, the amount of loss rapidly decreases over the first 25 epochs, before flattening out. This means that the model is improving and producing more accurate predictions!\n",
+ "\n",
+ "Our goal is to stop training when either the model is no longer improving, or when the _training loss_ is less than the _validation loss_, which would mean that the model has learned to predict the training data so well that it can no longer generalize to new data.\n",
+ "\n",
+ "To make the flatter part of the graph more readable, let's skip the first 50 epochs:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "Zo0RYroFZYIV",
+ "outputId": "8dc7544d-9504-4ec8-e362-d8dab905a474",
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 295
+ }
+ },
+ "source": [
+ "# Exclude the first few epochs so the graph is easier to read\n",
+ "SKIP = 50\n",
+ "\n",
+ "plt.plot(epochs[SKIP:], train_loss[SKIP:], 'g.', label='Training loss')\n",
+ "plt.plot(epochs[SKIP:], val_loss[SKIP:], 'b.', label='Validation loss')\n",
+ "plt.title('Training and validation loss')\n",
+ "plt.xlabel('Epochs')\n",
+ "plt.ylabel('Loss')\n",
+ "plt.legend()\n",
+ "plt.show()"
+ ],
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "display_data",
+ "data": {
+ "image/png": "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lHvvvZfly5dzwgkn1G2/d+9eJk+ezFNPPcWqVauorq7moYceqlvft29fli5dyvTp05tsxopOC75y5Up++tOf1s3BFJ0WfPny5SxcuJBDDjmEJ598kq985SssX76cFStWpGTWVwWIkHIQIumXjp+z2Gam2Oalp59+mjPOOIOCggJWr15drzko3sKFC7niiis49NBD6dWrF5deemndunfffZdzzz2X4cOH88QTT7B69epGy/P+++8zZMgQTjrpJAAmTZrEggUL6tZfeeWVAJx55plUVFQ0eqw33niDb33rW0DiacHvv/9+tm/fTrdu3Rg1ahSPP/44d911F6tWreLwww9v9NjJUIAIKQchkn7p+Dm77LLLKC0tZenSpezevZszzzyTv/zlL9x3332UlpaycuVKLr744gan+W7K5MmT+cUvfsGqVau48847W3ycqOiU4a2ZLrytpgVXgAjp0aMi6ZeOn7Pc3FzOP/98pkyZUld72LFjB4cddhhHHHEEn3zySV0TVEPGjRvHc889x549e9i5cye///3v69bt3LmTY445hv379/PEE0/ULT/88MPZuXPnQcc6+eSTqaioYP369QD85je/4bzzzmvRtUWnBQcSTgt+6623MmrUKNauXcuGDRs4+uijuf766/n2t7/N0qVLW3TOWBoHQfAYxOj89EVFEQ2WE0mjSCT1P1sTJ07kiiuuqGtqGjFiBAUFBZxyyikMGjSIsWPHNrr/GWecwde//nVGjBjBUUcdVW/K7nvuuYfRo0fTr18/Ro8eXRcUrrnmGq6//nruv//+uuQ0QM+ePXn88cf56le/SnV1NaNGjeKGG25o0XW197TgaZ3u28wmAP8OZAOPuvv/i1t/M/BtoBrYCkxx9w3huuOAR4FBgAMXuXtFQ+dq6XTfsc/Izf74HGxuKdX7szVYTiQJmu67c2nudN9pa2Iys2zgAeBCYBgw0cyGxW22DCh099OBZ4BZMevmAve6+6nAWcCn6Shn7DNy938wlqoqU6JaRIT05iDOAta7+4fuXgXMAy6L3cDd57v77vDt28BAgDCQdHP3P4Xb7YrZLqVin5Hb/YQ3yclxJapFREhvDmIAsDHm/SZgdCPbXwdEM0knAdvN7L+BIcCrwG3uXpPqQsY/I5fJ2ZrVVaQZ3B0za+9iSBNakk7oEElqM/smUAhEU/3dgHOBAuAj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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "tags": [],
+ "needs_background": "light"
+ }
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "W4EQD-Bb8hLM"
+ },
+ "source": [
+ "From the plot, we can see that loss continues to reduce until around 200 epochs, at which point it is mostly stable. This means that there's no need to train our network beyond 200 epochs.\n",
+ "\n",
+ "However, we can also see that the lowest loss value is still around 0.155. This means that our network's predictions are off by an average of ~15%. In addition, the validation loss values jump around a lot, and is sometimes even higher.\n",
+ "\n",
+ "**2. Mean Absolute Error**\n",
+ "\n",
+ "To gain more insight into our model's performance we can plot some more data. This time, we'll plot the _mean absolute error_, which is another way of measuring how far the network's predictions are from the actual numbers:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "Md9E_azmpkZU",
+ "outputId": "e47fe879-5e16-4e3c-9e98-279059955384",
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 295
+ }
+ },
+ "source": [
+ "plt.clf()\n",
+ "\n",
+ "# Draw a graph of mean absolute error, which is another way of\n",
+ "# measuring the amount of error in the prediction.\n",
+ "train_mae = history_1.history['mae']\n",
+ "val_mae = history_1.history['val_mae']\n",
+ "\n",
+ "plt.plot(epochs[SKIP:], train_mae[SKIP:], 'g.', label='Training MAE')\n",
+ "plt.plot(epochs[SKIP:], val_mae[SKIP:], 'b.', label='Validation MAE')\n",
+ "plt.title('Training and validation mean absolute error')\n",
+ "plt.xlabel('Epochs')\n",
+ "plt.ylabel('MAE')\n",
+ "plt.legend()\n",
+ "plt.show()"
+ ],
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "display_data",
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYgAAAEWCAYAAAB8LwAVAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAgAElEQVR4nO2de5wU1ZX4v6ebmQEEJQ6YUUGGKKAoy1O0UXEM0fURFUUTDbvIYuShGDGJaB4a4zOSbGRVVDAGYWNAXX+yqKir6CjKRAVBEJVIdBRUEEcBDTLDzJzfH7eqp7qnu6d76J7n+c6nP1N161bVqVvddeqec+65oqoYhmEYRjyh5hbAMAzDaJmYgjAMwzASYgrCMAzDSIgpCMMwDCMhpiAMwzCMhJiCMAzDMBJiCqKFIyJPichF2a7bnIhIuYh8LwfHVRE5zFu+V0SuTaduI84zTkT+r7FytjVE5AERuSnLx5wgIi9n85hG5nRobgHaIiLydWC1M1AJ1Hjrk1X1wXSPpaqn5aJuW0dVp2TjOCJSDHwA5KlqtXfsB4G076GRW0RkAvBjVT2+uWVpa5iCyAGq2sVfFpFy3Jf3ufh6ItLBf+gYhtHySfSbzfR33Jp+92ZiakJEpERENovI1SKyBZgnIt8SkSdEZJuIfOkt9wzsUyoiP/aWJ4jIyyLyB6/uByJyWiPr9hGRl0TkKxF5TkRmi8hfksidjow3isgr3vH+T0S6B7b/u4h8KCIVIvKrFO1zjIhsEZFwoOwcEVnrLY8QkTIR2S4in4rIXSKSn+RYMWYPEbnK2+cTEZkYV/cMEVktIjtFZJOIXB/Y/JL3f7uIfC0ikXjzh4iMFJHXRWSH939kum0TJ4f//ZghIp958o4RkdNF5O8i8oWI/DJQPyQi14jIP7y2fVhE9g9sf8Rrzx3evT4yrn1mi8iTnlyvisihKe5N0mN5dBeRZ71jvSgivb39RERu965np4isE5GjvG37icgC73v1oYj8WkTqPZNEpFicSbBDoKxURH4sIkcA9wIR7/5s97YXeN/9j0RkqziTY6cU1zdRRN7xvt/P+PJ721RELhOR94D3JPHvuEBEZnnfr0+85YK4+xqtn0yOloYpiKanCNgf6A1Mwt2Ded76IcA3wF0p9j8G2AB0B2YC94uINKLuX4HXgELgeuDfU5wzHRl/BPwHcACQD/wcQEQGAPd4xz/IO19PEqCqrwL/BL4bd9y/ess1wJXe9USA0cClKeTGk+FUT56Tgb5AvP/jn8B4oBtwBjBVRMZ420Z5/7upahdVLYs79v7Ak8Ad3rX9EXhSRArjrqFe2yShCOgIHAxcB9wH/BswDDgBuFZE+nh1LwfGACfi2vZLYHbgWE9513sA8Ab1zWIXAL8FvgVsBG5OIVdDxxoH3Ii7N2sC20/BtWE/YD/gB0CFt+1Or+w73jWMx7VT2qjqO8AUoMy7P928Tb/zzjkYOIy69qyHiJwN/BI4F+gBLAcWxlUbg/s9DfDW43/HvwKO9c43CBgB/Dqwf3z91oGq2ieHH6Ac+J63XAJUAR1T1B8MfBlYL8WZqAAmABsD2zoDChRlUhf3kK8GOge2/wX4S5rXlEjGXwfWLwWe9pavAxYFtu3jtcH3khz7JuDP3nJX3MO7d5K604HHAusKHOYtPwDc5C3/GfhdoF6/YN0Ex50F3O4tF3t1OwS2TwBe9pb/HXgtbv8yYEJDbZPgvCU45RsOXL8CxwTqrALGeMvvAKMD2w4E9gRlDWzr5h1rv0D7/Cmw/XTg3TTvf6JjBe9xF5wy74VT9n/HPTxDgTph73swIFA2GShN0MaJ7kEpsd/1lwPbxPveHBooiwAfJLmep4CLA+shYJf/vfPO/d24+xTzOwb+AZweWP9XoDzd331L/VgPounZpqq7/RUR6Swic7wu9k6cSaObBMwscWzxF1R1l7fYJcO6BwFfBMoANiUTOE0ZtwSWdwVkOih4bFX9J3VvkIn4K3Cu1z0/F3hDVT/05Ognzry1xZPjFtwba0PEyAB8GHd9x4jIC56pYwfujTSd4/rH/jCu7EPcG6tPsrZJRIWq+gEN33j/twa2fxPYvzfwmDiT23acwqgBvi0iYRH5nWd+2ol7UYHY60pLrjSPFbzHXwNfAAep6vO43uZs4DMRmSsi+3r75hHbdvHt1lh64F6IVgXa5mmvPBG9gf8K1P0Cp2SCssT/PmJ+x9T/HnzolSWr3yowBdH0xKfP/RnQH/eWuC91Jo1kZqNs8Cmwv4h0DpT1SlF/b2T8NHhs75yFySqr6tu4H9dpxJqXwJmq3gX6enL8sjEy4HpQQf4KLAF6qep+OJu2f9yG0h1/gnvABDkE+DgNufaWTcBpqtot8Omoqh/j2u5snDltP9xbODTue5XOsYL3uAvOnPIJgKreoarDcOaZfsBVwOe43k6w7ZK12z+9/8Hva1FgOf4efY5TpEcG2mU/DQSPxLEJF10YbMdOqroixTni1+O/B4d4ZcnqtwpMQTQ/XXFf5u2ePfs3uT6h90a+ErheRPJFJAKcmSMZ/wf4vogcL86hfAMNf+/+ClyBU0SPxMmxE/haRA4HpqYpw8PABBEZ4CmoePm74npUu0VkBO6B6LMNqMXZyROxFOgnIj8SkQ4i8kPcg/CJNGXbG+4Fbg44hHt49nRw11SJ6611xvW2Gks6xzo9cI9vBP6mqptE5Givh5aHe9DvBmq9XtLDnvxdvWv4Kc7UGYOqbsMpjn/zejMTgaBDfSvQ0zs3qlqL893cLiIHAIjIwSLyr0mu717gF+I53j3n+fkZtA84n8WvvXvQHWdaTRj00ZowBdH8zAI64d56/obrCjcF43B22Qqc3f8h3EMgEY2WUVXXA5fhHvqf4hypmxvYbSHOafm8qn4eKP857uH9Fe4B8FCaMjzlXcPzOGfs83FVLgVuEJGvcD/shwP77sI5b1/xTBDHxh27Avg+rpdVAcwAvh8nd674L1zP5/882f+Gc6QCLMD1xD4G3va2NZZ0jvVXnOL9AudQ/zevfF/cvfrSO0YF8Htv2+U4pfE+8LJ3jD8nkeESXM+jAjgSCL7dPw+sB7aIiN/uV+Pu9d88s9hzuF5wPVT1MeA2YJFX9y1cDzYTbsK9dK0F1uEc+VkdPNgciOdEMdo5IvIQzkmZ8x6MYRitA+tBtFO8rv+h4mLpT8XZmBc3t1yGYbQcbCR1+6UI+H84h/FmYKqqrm5ekQzDaEmYickwDMNIiJmYDMMwjIS0GRNT9+7dtbi4uLnFMAzDaFWsWrXqc1VNOIiwzSiI4uJiVq5c2dxiGIZhtCpEJD4TQBQzMRmGYRgJMQVhGIZhJMQUhGEYhpGQNuODMAyj6dizZw+bN29m9+5Wl6C03dKxY0d69uxJXl5e2vuYgjAMI2M2b95M165dKS4uJvl8VUZLQVWpqKhg8+bN9OnTp+EdPMzEZBhGxuzevZvCwkJTDq0EEaGwsDDjHl9OFYSInCoiG0Rko4hck6LeWG/e1+GBsn8RN//wenHz2HbMlZxlZXDrre6/YRjpYcqhddGY+5UzE5M329hs3DzAm4HXRWSJNyFMsF5XXO7/VwNlHXC51P9dVd/05vfdkws5y8pg9GioqoL8fFi2DCKRXJzJMAyjdZHLHsQI3JzI76tqFbAIlzE0nhtxudiDfZ9TgLWq+ia4nPuBaRizSmmpUw41Ne5/aWkuzmIYRjapqKhg8ODBDB48mKKiIg4++ODoelVVVcp9V65cyU9+8pMGzzFy5MisyFpaWoqI8Kc//SlatmbNGkSEP/zhD9Gy6upqevTowTXXxBpbSkpK6N+/f/T6zjvvvKzIlQ65VBAHEzuP62bi5psVkaG4aR6fjNu3H6Ai8oyIvCEiMxKdQEQmichKEVm5bdu2RglZUuJ6DuGw+19S0qjDGIbRhBQWFrJmzRrWrFnDlClTuPLKK6Pr+fn5VFdXJ913+PDh3HHHHQ2eY8WKFQ3WSZejjjqKhx+OzkPFwoULGTRoUEydZ599ln79+vHII48Qn0T1wQcfjF7f//zP/2RNroZoNie1iISAP+Jm4oqnA3A8btaz44FzRGR0fCVVnauqw1V1eI8eyeYjT00kArNmOTPTrFlmXjKMXFG2qYxbl99K2abcOPsmTJjAlClTOOaYY5gxYwavvfYakUiEIUOGMHLkSDZs2AC4N/rvf//7AFx//fVMnDiRkpISvvOd78Qoji5dukTrl5SUcN5553H44Yczbty46AN86dKlHH744QwbNoyf/OQn0ePG07t3b3bv3s3WrVtRVZ5++mlOOy120rqFCxdyxRVXcMghh1DWQhyiuQxz/ZjYieJ7EjsheVfgKKDUc54UAUtE5Cxcb+Mlf9pGEVkKDAWWZVvIsjKYPt2Zl5Yvh4EDTUkYRrYp21TG6AWjqaqpIj+cz7Lxy4j0yv4PbfPmzaxYsYJwOMzOnTtZvnw5HTp04LnnnuOXv/wljz76aL193n33XV544QW++uor+vfvz9SpU+uNFVi9ejXr16/noIMO4rjjjuOVV15h+PDhTJ48mZdeeok+ffpw4YUXppTtvPPO45FHHmHIkCEMHTqUgoKC6Lbdu3fz3HPPMWfOHLZv387ChQtjTFzjxo2jU6dOAJx88sn8/ve/r3f8XJDLHsTrQF8R6eNNJn4Bbv5cAFR1h6p2V9ViVS3GzXN7lqquBJ4BBopIZ89hfSJuLtysYz4Iw8g9peWlVNVUUaM1VNVUUVpempPznH/++YTDYQB27NjB+eefz1FHHcWVV17J+vXrE+5zxhlnUFBQQPfu3TnggAPYunVrvTojRoygZ8+ehEIhBg8eTHl5Oe+++y7f+c53ouMKGlIQP/jBD3jkkUdYuHBhvbpPPPEEJ510Ep06dWLs2LEsXryYmpo6t2vQxNRUygFyqCBUtRqYhnvYvwM8rKrrReQGr5eQat8vcean14E1wBsJ/BRZwfdBhEIgAoWFuTiLYbRvSopLyA/nE5Yw+eF8SopLcnKeffbZJ7p87bXXctJJJ/HWW2/x+OOPJx0DEHyTD4fDCf0X6dRpiKKiIvLy8nj22WcZPTrWYr5w4UKee+45iouLGTZsGBUVFTz//PMZnyPb5HQktaouBZbGlV2XpG5J3PpfcKGuOcX3QUyb5noR06ebmckwsk2kV4Rl45dRWl5KSXFJTsxL8ezYsYODD3ZxMQ888EDWj9+/f3/ef/99ysvLKS4u5qGHHmpwnxtuuIHPPvss2ssBoqawTZs2RRXRvHnzWLhwISeffHLW5c4ES7UBVFRAba37+GYmUxCGkV0ivSJNohh8ZsyYwUUXXcRNN93EGWeckfXjd+rUibvvvptTTz2VffbZh6OPPrrBfRKFzj722GN897vfjemlnH322cyYMYPKykog1gfRvXt3nnvuuSxdRWrazJzUw4cP18ZOGGSD5QwjM9555x2OOOKI5haj2fn666/p0qULqspll11G3759ufLKK5tbrKQkum8iskpVhyeqbz0InDJYtgwWLGhuSQzDaE3cd999zJ8/n6qqKoYMGcLkyZObW6SsYgoiwPz5rhcxf771IgzDaJgrr7yyRfcY9hbL5uph4a6GYRixmILwKClx6TZE3H9LuWEYRnvHFEQAPxuuZTE2DMMwBRGltBSqq0HV/TcTk2EY7R1TEB6W1dUwWg8nnXQSzzzzTEzZrFmzmDp1atJ9SkpK8EPhTz/9dLZv316vzvXXXx+TgjsRixcv5u236zL/XHfddVkZl9AS04KbgvDwQ10vuQQuuqi5pTEMIxUXXnghixYtiilbtGhRg/mQfJYuXUq3bt0ade54BXHDDTfwve99r1HHiqelpQU3BRHH/Plw331u4FwLybhrGG2CbE7te9555/Hkk09GJwcqLy/nk08+4YQTTmDq1KkMHz6cI488kt/85jcJ9y8uLubzzz8H4Oabb6Zfv34cf/zx0ZTg4MY4HH300QwaNIixY8eya9cuVqxYwZIlS7jqqqsYPHgw//jHP5gwYUL0Ybxs2TKGDBnCwIEDmThxYnQkdHFxMb/5zW8YOnQoAwcO5N13300oV0tLC24KIoCFuhpGbvCzFVx7bXZevvbff39GjBjBU089Bbjeww9+8ANEhJtvvpmVK1eydu1aXnzxRdauXZv0OKtWrWLRokWsWbOGpUuX8vrrr0e3nXvuubz++uu8+eabHHHEEdx///2MHDmSs846i9///vesWbOGQw89NFp/9+7dTJgwgYceeoh169ZRXV3NPffcE93evXt33njjDaZOnZrSjOWnBV+xYkXStOBnnnkmF154IQsXLozZd9y4cVET01VXXZV+gybBFEQAy+xqGLkhFy9fQTNT0Lz08MMPM3ToUIYMGcL69etjzEHxLF++nHPOOYfOnTuz7777ctZZdYmm33rrLU444QQGDhzIgw8+mDRduM+GDRvo06cP/fr1A+Ciiy7ipZdeim4/99xzARg2bBjl5eVJj9OS0oKbggjgZ3YNh13ivunTzcxkGNkgF0EgZ599NsuWLeONN95g165dDBs2jA8++IA//OEPLFu2jLVr13LGGWckTfPdEBMmTOCuu+5i3bp1/OY3v2n0cXz8nkBD6cJbUlpwUxBxJMrsahjG3uEHgdx4Y/bS2HTp0oWTTjqJiRMnRt+0d+7cyT777MN+++3H1q1boyaoZIwaNYrFixfzzTff8NVXX/H4449Ht3311VcceOCB7NmzhwcffDBa3rVrV7766qt6x+rfvz/l5eVs3LgRgP/+7//mxBNPbNS13XDDDdx2220J04J/9NFHlJeXU15ezuzZs+uZmbKJ5WKKw3/T8TO7WrirYWSHSCT7+c0uvPBCzjnnnKipadCgQQwZMoTDDz+cXr16cdxxx6Xcf+jQofzwhz9k0KBBHHDAATEpu2+88UaOOeYYevTowTHHHBNVChdccAGXXHIJd9xxR0ykUMeOHZk3bx7nn38+1dXVHH300UyZMqVR19VS0oJbuu8ElJW5nkNJiSXsM4xEWLrv1kmm6b7NxGQYhmEkxExMcdjkQYZhGA7rQcQRDMfbvdsmETKMZLQV83R7oTH3yxREHH7ab3CJ++bNs1BXw4inY8eOVFRUmJJoJagqFRUVdOzYMaP9zMQURyQCEyfCnDlOQVRVuV6EmZkMo46ePXuyefNmtm3b1tyiGGnSsWNHevbsmdE+FsWUgLIy15Pw0rxQUAAvvGBKwjCMtodFMWWI34vwJw6y+SEMw2iPmIJIwvjx0LGjzQ9hGEb7xXwQSfDzMj36KIwda+YlwzDaH6YgklBW5pL1VVXB8uUwcKApCcMw2hc5NTGJyKkiskFENorINSnqjRURFZHhceWHiMjXIvLzXMqZCJsbwjCM9k7OFISIhIHZwGnAAOBCERmQoF5X4Arg1QSH+SOQOh1jjrC5IQzDaO/ksgcxAtioqu+rahWwCDg7Qb0bgduAmGTrIjIG+ABIPUtHjrC5IQzDaO/kUkEcDGwKrG/2yqKIyFCgl6o+GVfeBbga+G2qE4jIJBFZKSIr92bATtmmMm5dfitlm2I1gM0NYRhGe6bZnNQiEsKZkCYk2Hw9cLuqfi3+YIQEqOpcYC64gXKNkaNsUxmjF4ymqqaK/HA+y8YvI9LLeaN9M1NlpZmZDMNof+SyB/Ex0Cuw3tMr8+kKHAWUikg5cCywxHNUHwPM9MqnA78UkWm5ELK0vJSqmipqtIaqmipKy0uj28zMZBhGeyaXPYjXgb4i0genGC4AfuRvVNUdQHd/XURKgZ+r6krghED59cDXqnpXLoQsKS4hP5wf7UGUFJfEbE9kZrJwV8Mw2gM5UxCqWu299T8DhIE/q+p6EbkBWKmqS3J17kyI9Iow69RZPPr2o4wdMDZqXvKxKUgNw2ivtPtkfal8ED5z59aNqJ40KVsSG4ZhND+WrC8FqXwQUDeietky80EYhtG+aPcKwvdBhAghIhR2jg1VshnmDMNor7R7BeH7IMKhMLVay/Snp8eMh7AZ5gzDaK+0ewUBULGrglqtpVZrE4a62twQhmG0R0xB0LCZyZ8bwvIyGYbRnjAFQcNmJhswZxhGe8QUhEcqMxNYXibDMNofpiA8fDNTWMIJR1T7zmoR998GzBmG0daxGeU8GhpRDXWO6hT5Aw3DMNoMpiA8yjaVMf3p6VTVVLH8o+UMPGBgjJIoLXURTKp1kUyWk8kwjLaMmZg8GhpRbTPMGYbR3jAF4dFQqKtFMhmG0d4wBeHRUKgrWCSTYRjtC1MQARoKdfXNTOGwpf42DKPtY07qAL6ZqbK6MqmZadkyS9hnGEb7wHoQAdIxMwHMnw/33QejR5sfwjCMtospiDgaMjOVlkJlpUv/XVlpfgjDMNoupiDiKCkuIRwKIwjhULjeiOrCQuekBvffwl0Nw2irmIJIgCAx/4NUVLixEOD+V1Q0pWSGYRhNhymIOErLS6murUZRqmurE0YyFRS4SKaCAotkMgyj7WJRTHH4kUxVNVUJk/ZZJJNhGO0FUxBxRHpFWDZ+GQveTK0B5s93g+Xmz3cKw/IyGYbR1jATUxLmvzmf+964j9ELRtcLdS0tdcqhpsZGVBuG0XYxBZGAYOK+3dW76/UmLHGfYRjtAVMQCfBDXQEUZd6aeQmnIBVxvYjLL7cBc4ZhtD1MQSQg0ivCxMETo2GuiaKZVq92ykHVmZnMaW0YRlsjpwpCRE4VkQ0islFErklRb6yIqIgM99ZPFpFVIrLO+//dXMqZiPGDxpMXzks6YM4wDKOtkzMFISJhYDZwGjAAuFBEBiSo1xW4Ang1UPw5cKaqDgQuAv47V3KmItWAufHj3TgIcGMihgxpSskMwzByTy57ECOAjar6vqpWAYuAsxPUuxG4DdjtF6jqalX9xFtdD3QSkYIcylqPhgbMRSJwxx2Ql+dSblx2Gcyd25QSGoZh5JZcKoiDgU2B9c1eWRQRGQr0UtUnUxxnLPCGqlbGbxCRSSKyUkRWbtu2LRsyR2lohjlwaTZ8P0R1NUybZs5qwzDaDs3mpBaREPBH4Gcp6hyJ611MTrRdVeeq6nBVHd6jR4+sypdO6u+Skrq8TOCUhY2JMAyjrZBLBfEx0Cuw3tMr8+kKHAWUikg5cCywJOCo7gk8BoxX1X/kUM6kNJT6OxKB2bOdmSkUstxMhmG0LXKZauN1oK+I9MEphguAH/kbVXUH0N1fF5FS4OequlJEugFPAteo6is5lDElDc0wBzBpkvv/6KMwdqyl3DAMo+2Qsx6EqlYD04BngHeAh1V1vYjcICJnNbD7NOAw4DoRWeN9DsiVrMlIx8xUVgbTp7t8TNOnmw/CMIy2Q06T9anqUmBpXNl1SeqWBJZvAm7KpWzpksjMFOlV101IlJfJehGGYbQFbCR1AzQ0w5zlZTIMo61iCiINUg2Y8/MyhcNuPISZmQzDaCuYgmiAhgbMgRsPUVvrPrt3W14mwzDaBqYgGiCdAXMlJa4HAW7Q3Lx51oswDKP1YwqiAdKJZIpEYOJE54MAN6raBswZhtHaMQWRBg0NmAOXvK9jR3NWG4bRdjAFkQbpmJnMWW0YRlvDFEQapGNmgrrkfbW1UFlpZibDMFo3piDSJB0zU2GhUw7g/puZyTCM1owpiDRpaMAcuB6En91VxE1LahiG0VoxBZEBqQbMgQt37eAlL1GF++6zSYQMw2i9mIJIk3QGzPnhrj41NTaJkGEYrRdTEGmSTiQTuHDXDoEUiDaJkGEYrZWUCkJE9k2x7ZDsi9NySTeSyZ9EKBx2fogOHWwSIcMwWicN9SBK/QURWRa3bXHWpWnhpBPJBDBwYF0vQhK7KwzDMFo8DSmI4ONt/xTb2gXpmplKS126DVU3R4Ql7zMMozXSkILQJMuJ1ts86ZqZLHmfYRhtgYYUxAEi8lMR+Vlg2V/v0QTytTgqdlVQU1tDrdZSWV2ZMprJkvcZhtGaaUhB3Ad0BboElv31P+VWtJZJYedCanHDpWupTRnNZMn7DMNozaSck1pVf5tsm4gcnX1xWj4VuyoISYharSUkISp2VSSs5yfvmzbNhbpOn+6c1zZftWEYrYWMxkGIyAARuVFENgL35EimFk1JcQkF4QJChAhJKGkPAmJnmquqMjOTYRitiwYVhIgUi8gvRGQt8N/AVOB7qjo859K1QNJ1VEOds1rE/bfxEIZhtCYaGihXBjyJM0WNVdVhwFeqWt4EsrVYguMhdlfvZsGbyeNYRVwkU00NrFvXhEIahmHsJQ31ILbinNLfpi5qqd2Ft8bjZ3YFUJR5a+Yl7EWUlsKePW7Z8jIZhtHaSKkgVHUMMBBYBVwvIh8A3xKREU0hXEsl0ivCxMETo1ldkyXvKympS/8NLtzVBs0ZhtFaaNAHoao7VHWeqp4CHAtcB9wuIptyLl0LZvyg8eSF81LODxHMywQ2aM4wjNZFRlFMqrpVVe9U1eOA43MkU6uhofkhACZNgksuqVvfs8eimQzDaB005KRekuwD3NnQwUXkVBHZICIbReSaFPXGioiKyPBA2S+8/TaIyL9mdFVNQHB+iKqaqpSO6iFD6pZra+G116wXYRhGyyflQDkgAmwCFgKvkkGCPhEJA7OBk4HNwOsiskRV346r1xW4wju+XzYAuAA4EjgIeE5E+qlqTbrnzzW+o7qmpibqqB4/aDyRXvVHwvlTkfrzVS9eDEuXup6EDZwzDKOl0pCJqQj4JXAU8F+4h/3nqvqiqr7YwL4jgI2q+r6qVgGLgLMT1LsRuA3YHSg7G1ikqpWq+gGw0TteiyHeUZ2qFxGcitTHsrwahtHSaSiKqUZVn1bVi3AO6o1AqYhMS+PYB+N6Hz6bvbIoIjIU6KWqT2a6r7f/JBFZKSIrt23bloZI2cV3VEPqcNf4qUgNwzBaA+mMpC4QkXOBvwCXAXcAj+3tiUUkBPwR+Fljj6Gqc1V1uKoO79Gj6ZPL+r0Inz01e5JOIjR+POTn163n5bkywzCMlkpKH4SILMCZl5YCv1XVtzI49sdAr8B6T6/Mp6t37FJxebGLgCUiclYa+7YYhhxY54FOld01EnE+hwULYMsWKCpqIgENwzAaSUNO6n8D/olzIv9E6ubPFEBVNUdT+BAAACAASURBVOmc1cDrQF8R6YN7uF8A/MjfqKo7gO7RA4qUAj9X1ZUi8g3wVxH5I85J3Rd4LYPrajLSze4KdQ7p0aOdD2L+fFi2zBzVhmG0TBpK953ROIm4fas9X8UzQBj4s6quF5EbgJWquiTFvutF5GHgbaAauKwlRTAF8bO7VlZXNpjdFVwvoqrKpd7wM7yagjAMoyXSaAWQDqq6VFX7qeqhqnqzV3ZdIuWgqiWqujKwfrO3X39VfSqXcu4NmWR3BRfRlJ9fl8Rv+/amk9UwDCMTcqog2gvB7K5VNVVJHdXgeguXX+6UQ20tzJwJc+c2nayGYRjpYgoiC5QUl5AfzidECBFp0My0Zk3s+o032shqwzBaHqYgskCmZqaxY2PXN2+Gk04yJWEYRsvCFESWyGQSoUmTYMyY2DKbktQwjJaGKYgske4kQj4zZsQOnOvQwaYkNQyjZWEKIktkMqoanLP6zjvr5qwO2Z0wDKOFYY+lLJLuqGqfCm9Mnaqbbc5MTIZhtCRMQWQRf1Q1uEmEVn+6OmV9f0xEKOR6EYWp9YlhGEaTYgoii5QUl9Ah5Aanp+OHiERg1ixnZqqthenT3ZiIW2+1iCbDMJofUxBZJJM5InwqKpxyqK2Fb76BSy+Fa691+ZpMSRiG0ZyYgsgy6c4R4VNS4noQPjU17lNZaT4JwzCaF1MQWaYx0UyJJhOqrTWfhGEYzYspiByQaTTTkCH1y0KhuignwzCM5sAURA7INJqposJFMQUJh23gnGEYzYspiByQaTRTSYmbgtQnHIa77rJ5IgzDaF5MQeSA+Gim6trqBv0QpaUwZYr7LF/u8jUZhmE0J6YgcsT4QePp2KFj2inAIxG45x73AZg61X0s1NUwjObCFESOyDQFuE9ZmTM53Xuv+4wcCSeeaIrCMIymxxREDqnYVUFNbQ21WktldWVKM5NPaSns2RNb9tJLcPzxNvOcYRhNiymIHFLYuZBaaoH0wl2hvsPap7YWpk2znoRhGE2HKYgckmm4K9Q5rEeNqr/NMr4ahtGUmILIIZmGu/pEIvDiizBnDvTuXVeuaqOrDcNoOkxB5JDGJO8LMmkSTJ5cN5mQCKxuuBNiGIaRFUxB5JhMk/fFU1LipiMF14OYN8/8EIZhNA2mIHJMpsn76u3vJfPzU3FUVrp5I0xJGIaRa0xBNAHxyfu2V27PaP/x42Mjm157DY47Dq6+OlsSGoZh1McURBNQsasi6ocAuL3s9ozMTJEInH56bJkqzJxpYyMMw8gdOVUQInKqiGwQkY0ick2C7VNEZJ2IrBGRl0VkgFeeJyLzvW3viMgvcilnrikpLiEcqpsVqLq2OiNnNUBRUeLy++/fG8kMwzCSkzMFISJhYDZwGjAAuNBXAAH+qqoDVXUwMBP4o1d+PlCgqgOBYcBkESnOlay5JtIrwuzTZxMWpyQU5f7V92fUixg/HgoK6pevXm3+CMMwckMuexAjgI2q+r6qVgGLgLODFVR1Z2B1H0D9TcA+ItIB6ARUAcG6rY5JwyZxZr8zo+t7avdk1IuIROCFF+CWW2IH0VVXO1PTrbc6c9Ott5rCMAwjO3TI4bEPBjYF1jcDx8RXEpHLgJ8C+cB3veL/wSmTT4HOwJWq+kWCfScBkwAOOeSQbMqeE4q6xNqJtny9JaP9IxH3KSlxn6oq54tYvNh9wEU7hcMwe7alDDcMY+9odie1qs5W1UOBq4Ffe8UjgBrgIKAP8DMR+U6Cfeeq6nBVHd6jR48mk7mxjB80nrxQXTjSUxufysjM5JNsHmtwCqO62vI2GYax9+RSQXwM9Aqs9/TKkrEIGOMt/wh4WlX3qOpnwCvA8JxI2YREekW4eMjFjR5ZHWT8eNdTSEZNjeVtMgxj78ilgngd6CsifUQkH7gAWBKsICJ9A6tnAO95yx/hmZtEZB/gWODdHMraZMSPrM7UWR0k1MDdKyx0vQjzSxiG0RhypiBUtRqYBjwDvAM8rKrrReQGETnLqzZNRNaLyBqcH+Iir3w20EVE1uMUzTxVXZsrWZuSSK8Ipx9WN6hhT+0eZr4yM+PjlJa6FODJUIXLL4eTToJrr4XRo01JGIaRGbl0UqOqS4GlcWXXBZavSLLf17hQ1zZJvLP68b8/TtmmMiK9Imkfo6QE8vOdozocds5pf6Kh2lqnIKqq6upXVdWZnEpL3f6R9E9nGEY7JKcKwkjM+EHjue+N+6jRGgBqtZYFby7ISEFEIrBsWd3DHtzy9u0u7DWeDh2cyWn06DqlMnGi82WYojAMIxHNHsXUHon0inD3GXfHDJzLNMsruAf7L35RF/76i19At26JfROHHuoG1VVWOgd2VZWbb8JMT4ZhJMMURDMxadgkLhl6SXQ90yyvyQimBw/y9ttw332xfgtVpzAs2skwjESYgmhG9jbLayJSjZGoqalfVlsLTz8N55wDU6dab8IwjDpMQTQje5vlNRnjx0OnTs7UJNJw/ZdeciOx770XTjzRFIVhGA5TEM1INrK8JsJ3YN90k3vopxpQF8+ePbG+CRtHkXusjY2Wiqhqw7VaAcOHD9eVK1c2txgZM3fVXC598tJoRFNeKI8XJ7yYUURTg+eYC5demtjElIxQyOVymj/fObTz853SiUTcgyw+esrCZhtHWVldZFmwjbN5fLs/RipEZJWqJsxUYWGuzcykYZN46r2nWLzBZdvzs7xmU0FMmgQDB8ICr3MyZIiLaLrvvuRKw/dNVFa65d276/YPhsqKuNxPuXi47Q2t5cFYWura0o8sKy1NX96GrjHXyiddOQxHa2wnUxAtgPiBcy99+FLGA+cawg+FDTJkiEvqV13tIpriKS+vW1Z1CmXLlroHmh8RpeoUyMyZMGJE3Q8gkx9ENn88TfVg9M+1N3IHBzzm59f1ytI5b6JrLCurU+RQd68qK+H6690n2z2UdNs6Vz3PbH13cvkA99upstL1zltLtmVTEC2A8YPGc//q+9lT64ZCv/3525z4wIlZNzXFE+xZzJtXlz48GTU1zpntz48tUjdq2087/r//67bfeSdMn574wTF3Ljz6KIwd62QI/nhE4MwzYcaMxv9IM30rj39w+Q/YZIMI/Yfwli3w5JPObxMOw913p/+jD55z2bLYh3qyekFZSkvrenfBUGU/DTy4+xAK1SnzZ5915zruONh/fzdLYWMHSvpyffRRem1dVubSvlRVuTDsUKiu5zlrluvRgntpqahI/yGdSEH57VNYmP6x5s51L0s1NW5irmy/VATvV22tO9fAgXXnaLG9C1VtE59hw4Zpa2bK41OU64n5THl8SpOdf8UK1VtuUZ0xQ1XEf+Qn/wwerBoOJ98+YIBqKOSWRVTHjKk7frDejBmqI0bU37+gwMmULnPmqJ5yivu/YoVqp07u/OGwO3fwWPF1CwqcjHl57pNKhhUrVPPzE19zOJyezL584bD7P2dO7Lp/jPh6K1bE3qfguefMceXx9y7VPUp0jf7xU11HUK78fHeMeNnjmTIl9ry+nCL1ZQ6F6tolmSy+nFOm1F2jf6+D1yyi2qGDO1bwvscfq0OH2H2mTHHHj5dhxQq3bcoUt5zsmPFyzpkTe45QyJUn+z74+wTPlck9ygRgpSZ5rpqTuoVQtqmME+adEHVWA4zpP4bHLnisyWWZO9eFuqZKBpgtRBL3WkTg5pvdG1XwjR7qUoqsWeN6IQCTJ9ftO2OGGzkedMyHw3DBBfDyy/Dhh3V1DzwQPv00uWy+DP4b6aOPujfxZD+bMWNizWxB/J7HSy+5gYvg3qSHD4fXX687Zu/e8O1vQ8eOsHy5KxeBs8+GZ55xb6JQd39CIRexVlgYe81+iHNDP/FTTnGmp3Xr0nuLnjrVRbqpunY980z45BM46CA47TTXG9gSmAurqMit+5Na+TI39P3yvxsdOsSaZPy3/epqdxz/WOGwK0t03Pjv2YwZLuuAf29/9avY7Xl5dT2vUMi1x6xZ7rx+zrP4axgzxl2/32uBWLPSD38IDz9c176zZrm6r73met6qdaHp8b7BggI3o6R/zN27Xb2f/xxuuy11OzZEKid1s7/5Z+vT2nsQqqpzVs7R0PWhaA8i/NuwzlmZ5NUkx/hvSmPG1H8ra4pPXp57S45/G/R7JcFPt271ywYNyo4MY8bU9TDS3c+Xc8CAujfLOXOSt2G6bZvo2kMh9xY/alTscUKhOplDIff2muoagvX9T8+esW/G/nci2MuK73WlapNUvYZ0PmPG1H8T92UfMcK1QSb3yO9dzJhRvweRqFeTqKeb7Nj5+a5+8Dh5eXW9Av97leieprr+RDKMGrV3vQlS9CASFrbGT1tQEKr1TU15N+Tpio+y1JfcC1ascA+8vX3opvvDTfTAaspPcXH2lGL8wzubnyOOaPgBfcQR7uHS2Ps3apTbP9F59t23ae9LLr4TIqrjxrnr85VponqHHbb35xkxIj2FmuknFEpu5mqIVArCTEwtjLJNZYx6YBTVtdXRsuYyNcXjOxp9E4dIXd4nv9udzGSUDuGw2zfbpq29kamlM2BAnbkqXVpie4jUBT00B36QgW/yCZrDWgvhsDNJZurkTmVispHULYxIrwizT59NKHBrFm9YzNXPXd2MUjkiEWcHveUWZ4O++WZ48UX3mTLFfc4+O3afUaNcdEkQ324cZMwY9wNNlGhwb8jLgxNOiC0bMMCdL5vnyMtruF4Q/4EYpKEZAv39gvXfTTDPYkPpVU4+2dngMxlhnyv8l4x773X+oREj0ksPk4pQKPP7UVPjfCeFhfD445nt2xztmOi7Ulubg8SbyboWre3TVkxMPiPmjogxNcn10mz+iEzwo3x8O2ww8iYYERKMaglGdMRHuyTrqofD9W3uc+Y4e7JvnvLty8GoIz9qJxjplKheOp8jjoiNZknHjBQK1UWmBO3PoVBs1Feq/X1zSKJ6Y8a4qJpkxwhGLU2ZUr+ebwYpLs7czBH8BKPY/E847NrZv/5EUUqJInrGjEl8PUcckdg/FLT1x5vVUtn8479ToNq7d/19CgrcdZxySuKoqWybjxK1rf+dC8qWaeSfD+aDaH3MWTmnXthr+LfhFuGPaIhMQyUThXYGnYh+OGXwoRIMb/TDEhOd/5Zb0qsXXE/2QPIdskHl55NuiKmvDBMpqPjQUT9MN16RnHJK4mOnUn7JwiX9ev6xg+G0/n1Ipaz8T9AJ7ivB4PXEnzvT70+8As7Li335CN6zcDg2hNRXIgUFsaGjc+ak9sv45xgzJrZ8zJjk3+M5c+o7p+OXfWdzqrbNy0vuxA4qgviw28aQSkGYD6IFc/VzV9ebr3rKsCnc8/17mkmi7JJscFA6I27THcHbmFHVwX3CYTj99LpBZankCQ5SKyiAO+5wZou334ZXXnE/72D4aPz1J7tuP/y0utrJ89OfuoGIieTLdOCVXy/RoLLgtuBANn852B6FhfUHRiZrq8YSHCUeP8Av1X1O1RZTpzrzlo/vBwuOdo6vM2UK3BP4CSa6j0FZLr8cbr89NnwY6s/umKpt77+/LhQ6HIYbb3QThGWDVD4IUxAtnHMeOofF79Z5zFqKw7olkOlDMJMHVWP3SfUA25uHZfxIXz+GviWNvG3u0cCNvWclJS7Iws8AkEhRBuukky8rlfJvzOjpXKaPMQXRiinbVMaJD5wYTcMRljB3n3E3k4a1gkQuRta49Va49lqnILL9BtneSedB3dzKL5cymIJo5Ux9Yir3rqrr44YlzPL/WJ7TPE1Gy6IpExAa7QsLc23ljB80nrDUxdLVaA1jFo1h7qq5zSiV0ZT4k0DdeKMpB6PpsGyurYBIrwhn9j8zxhfx2a7PmPyES0Bk5qb2QaKU7YaRS6wH0UqYMXJGTC/C5/437m8GaQzDaA+YgmglRHpFuPuMu2NGWAOs/HSlmZoMw8gJOVUQInKqiGwQkY0ick2C7VNEZJ2IrBGRl0VkQGDbv4hImYis9+p0zKWsrYFJwybx8sSXGdA92kzUai1TnphiSsIwjKyTMwUhImFgNnAaMAC4MKgAPP6qqgNVdTAwE/ijt28H4C/AFFU9EigB9uRK1tZEpFeEP531pxhzk6JMfmJyi8jXZBhG2yGXPYgRwEZVfV9Vq4BFQEwqN1XdGVjdB/Bjbk8B1qrqm169ClWNm0Kj/eI7reOZ+cpMUxKGYWSNXCqIg4FNgfXNXlkMInKZiPwD14P4iVfcD1AReUZE3hCRGTmUs1UyY+QM8kL1U1bOfGUmJz5wImWbyppBKsMw2hLN7qRW1dmqeihwNfBrr7gDcDwwzvt/joiMjt9XRCaJyEoRWblt27Ymk7klEOkV4cUJLzLqkFH1tr304UscP+9480sYhrFX5FJBfAz0Cqz39MqSsQjws/RvBl5S1c9VdRewFBgav4OqzlXV4ao6vEePHlkSu/UQ6RXhxf94kRnH1e9g1Wot05ZOs56EYRiNJpcK4nWgr4j0EZF84AJgSbCCiPQNrJ4BvOctPwMMFJHOnsP6RCDDebPaD7d977aESmJP7R5mvjKTW5ffaorCMIyMydlIalWtFpFpuId9GPizqq4XkRtw+ceXANNE5Hu4CKUvgYu8fb8UkT/ilIwCS1X1yVzJ2ha47Xu3cei3DuWW5bfw4Y4Po+WLNyxm8YbFdAh1YPbps23UtWEYaWPJ+toYty6/lV89/yuU+vfVkvwZhhGPJetrR5QUl5AXTjwhb43WcO5D5zJg9gDOeegcMzsZhpESUxBtjEivCKUXlSaMbgLY8s8tvPP5Oyx+dzEj/zzSQmINw0iKKYg2iB/dNOf7cxhx0AhCkvw2W0isYRjJMAXRhpk0bBKvXvIq95xxT8JMsD61WsvkJyZz5N1HmqIwDCOKOanbCWWbyljw5gLe3vY2f6/4O1v+uSVp3aIuRRzb81hmjHShs6XlpZQUl5hz2zDaIDblqFGPuavm8uvnf822XalHoAuCojYXtmG0UUxBGAkp21TGiQ+cyJ7a9BPljuo9inEDx1Gxq4KS4hIAFry5AHBTo1ovwzBaF6YgjKT4pqe/bf4ba7auyXh/v4cBECJE/+796d+9PzNGzmDdZ+t49O1HGTtgrPU8UuDfA8hMyZZtKmvQ/NfYY7dH0mnP1nCOTDEFYaRF2aYyZr4yk79t/ltKH0VjmHHcDMb0H0NpeSnbK7ez5tM1MYoj6CPZXb2bi4denJFSif/h+cfb8rW7jqIuRWk/INN98JaWl1LYuZDVn64GGvdwL+xcyOVPXU5VTRUABeECXrjohehxEj3g/bJ5a+axp2YPoVAoOko+/rqffO/JaA8xL5THGX3PAOCLb75oVDsnaiNIrxcZvJYhBw6J6YXOfGUmGyo20GOfHgzoPoDxg8YD6fm/4mWZ+cpMPvnqE0r6lLBz986oXKmOV7apjJL5Jeyp2UNeOI/Si0qz/gAv21TG6AWjqaqpIj+cz7Lxy2Luc3MpDlMQRsbMXTWX+9+4n455Hdm5e2ejehfxBHsbPkVdiuia35WNX2yst21w0WCOPfhYhhw4hNWfrmbL11v44psv2LZrGwUdCsgP5VPSp4S/f/53lvx9CbVaiyD07tabTTs2URM3hYj/gPSP0WOfHuzfcf/oev/u/elX2I//XPGf1Gpt9EEBRB/mFbsq2F65nf9c8Z/1ji8IVx13FWP6j4k+pOIfwL4SXvL3JagqIQlRq7Ux1957v950zutMQYcC1m5ZSy21gFMeVxx7RcJzhyXMcb2OY/lHyxOOok9FsJ2feu+peg/qRA/T0QtGU1ldiYgAROXxZSz9oJSOeR3Zv+P+0f0e//vj9eROhf99EYTD9j+Mb3X8FhcPvZiBBwyMKpSCDgWs27qOWq0lJCFUNdpeQUKECIVCVNdWEyLE8b2PZ/+O+0dfHBa8uYB7V90brT/qkFEM6DGg3gsGEKOAg9/HyurKeu0WVIpb/rmF/333f6PXNHnYZO75/j0x7RkKhfjhkT9k2z+3MfjAwUkV3LrP1nH/G/dz0L4HMWPkjL1SKqYgjL1m7qq59fI8tQe6FXRjR+WOjB+6QYq6FNGvsB8ojXqANyeCMKhoEJXVldGH4Pbd2/n060+bW7SsIQhFXYoavKawhOsp81QUdSli69dbU9Yv7lZMZXVlWu3pj2cSpJ6iHdV7FL8b/btGKQpTEEbWmLtqLo++/Sg99unBexXvcdC+B9GvsB+3l92ekbPbMIzskhfK48UJL2asJFIpiJxlczXaJpOGTUpos/b9C4WdC5m2dFpUWYQIJezyJ6Nn155s/mpz1uQ1Wg/7d3LmPqNx7KndQ2l5dn0npiCMrBDpFYl+MQceMDDGaenbS32bdFGXohh7t+9P8O31c1fN5dInL01or/Z9DHmhvBi/hSCc0PsEdu7eyZtb34yW+9OyxvduiroU8dk/P4v6Lb7V6VsZP5wGFw2meL9iiroU8VXVVzy47sGM9k/kk/HLv93l21H5MpXp2IOPZd+O+9bzVQhCOBTmx0N+HL0vido5Ww/qRNcXIkQ4FKamtgYRYeC3B8bc+/hghb6FfXmv4j2+3P0l733xXsyxiroUUdSliHVb19W7hnEDx/Hw+oeprq2OkUFwPpNkZh/x/tJ9qfG/j906duPLb77kox0fNZsJMS+UF3XUZwszMRktEj+qw494GnzgYLoVdIuJ8kgWwhlfDnWOxWA0U3zkiG8+G3zgYO589U52V+8GYFDRoKgi2LfjvvUisHx8xeY7uO887U6eeu8pVm9ZHX1whAhx1uFnRUepB+UKRvYE5Yt3iueF8rjr9Lui0VPJZEoWNRR8w4xvZ/8YwWioeEdsMEBg5+6dUfn37bgvpR+URh2nQMJIL78804gd38Ef7/xPdQ2pzl/YuZCn3nuKJRuWUEttdDBo8AXHf5FZvGFxVI74sUDx7ekruPjAh+D9CwZL+O3Zt7AvD69/mBqtoUOoA6cfdnq0XR/f8Djvfv5uVPn4sgJ77aw2H4RhZEhjww6T7be3YYw2niF3pHNv/JeHxo7pSff+pZIlV98BUxCGYRhGQmzCIMMwDCNjTEEYhmEYCTEFYRiGYSTEFIRhGIaREFMQhmEYRkJMQRiGYRgJaTNhriKyDWjtmeS6A583txAtCGuPOqwtYrH2iGVv2qO3qvZItKHNKIi2gIisTBaP3B6x9qjD2iIWa49YctUeZmIyDMMwEmIKwjAMw0iIKYiWxdzmFqCFYe1Rh7VFLNYeseSkPcwHYRiGYSTEehCGYRhGQkxBGIZhGAkxBdFEiMifReQzEXkrULa/iDwrIu95/7/llYuI3CEiG0VkrYgMbT7Jc4OI9BKRF0TkbRFZLyJXeOXtsk1EpKOIvCYib3rt8VuvvI+IvOpd90Miku+VF3jrG73txc0pfy4QkbCIrBaRJ7z19twW5SKyTkTWiMhKryznvxVTEE3HA8CpcWXXAMtUtS+wzFsHOA3o630mAfc0kYxNSTXwM1UdABwLXCYiA2i/bVIJfFdVBwGDgVNF5FjgNuB2VT0M+BK42Kt/MfClV367V6+tcQXwTmC9PbcFwEmqOjgw3iH3vxVVtU8TfYBi4K3A+gbgQG/5QGCDtzwHuDBRvbb6Af4XONnaRAE6A28Ax+BGx3bwyiPAM97yM0DEW+7g1ZPmlj2LbdDTe+h9F3gCkPbaFt51lQPd48py/luxHkTz8m1V/dRb3gJ821s+GNgUqLfZK2uTeCaBIcCrtOM28Uwqa4DPgGeBfwDbVbXaqxK85mh7eNt3AIVNK3FOmQXMAGq99ULab1sAKPB/IrJKRPw5T3P+W+nQmJ2M7KOqKiLtLuZYRLoAjwLTVXWniES3tbc2UdUaYLCIdAMeAw5vZpGaBRH5PvCZqq4SkZLmlqeFcLyqfiwiBwDPisi7wY25+q1YD6J52SoiBwJ4/z/zyj8GegXq9fTK2hQikodTDg+q6v/zitt1mwCo6nbgBZwZpZuI+C9ywWuOtoe3fT+goolFzRXHAWeJSDmwCGdm+i/aZ1sAoKofe/8/w708jKAJfiumIJqXJcBF3vJFODu8Xz7ei0Y4FtgR6Eq2CcR1Fe4H3lHVPwY2tcs2EZEeXs8BEemE88e8g1MU53nV4tvDb6fzgOfVMzi3dlT1F6raU1WLgQtw1zaOdtgWACKyj4h09ZeBU4C3aIrfSnM7X9rLB1gIfArswdkEL8bZSZcB7wHPAft7dQWYjbNBrwOGN7f8OWiP43F21bXAGu9zenttE+BfgNVee7wFXOeVfwd4DdgIPAIUeOUdvfWN3vbvNPc15KhdSoAn2nNbeNf9pvdZD/zKK8/5b8VSbRiGYRgJMROTYRiGkRBTEIZhGEZCTEEYhmEYCTEFYRiGYSTEFIRhGIaREFMQhtEAIlLjZdH0P9c0vFfaxy6WQIZfw2hJWKoNw2iYb1R1cHMLYRhNjfUgDKOReDn6Z3p5+l8TkcO88mIRed7Lxb9MRA7xyr8tIo95cz68KSIjvUOFReQ+bx6I//NGUiMiPxE3X8ZaEVnUTJdptGNMQRhGw3SKMzH9MLBth6oOBO7CZSAFuBOYr6r/AjwI3OGV3wG8qG7Oh6G4UbHg8vbPVtUjge3AWK/8GmCId5wpubo4w0iGjaQ2jAYQka9VtUuC8nLcJD/ve4kHt6hqoYh8jsu/v8cr/1RVu4vINqCnqlYGjlEMPKtu0hdE5GogT1VvEpGnga+BxcBiVf06x5dqGDFYD8Iw9g5NspwJlYHlGup8g2fgcuoMBV4PZDI1jCbBFIRh7B0/DPwv85ZX4LKQAowDlnvLy4CpEJ0caL9kBxWRENBLVV8ArsalsK7XizGMXGJvJIbRMJ28md58nlZVP9T1WyKyFtcLuNAruxyYJyJXAduA//DKrwDmisjFuJ7CVFyG30SEgb94SkSAO9TNE2EYTYb5IAyjkXg+iOGq+nlzy2IYucBMTIZhGEZCrAdhGIZhJMR6oBY/ZwAAAClJREFUEIZhGEZCTEEYhmEYCTEFYRiGYSTEFIRhGIaREFMQhmEYRkL+P94K4Phwv1s2AAAAAElFTkSuQmCC\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "tags": [],
+ "needs_background": "light"
+ }
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "ctawd0CXAVEw"
+ },
+ "source": [
+ "This graph of _mean absolute error_ tells another story. We can see that training data shows consistently lower error than validation data, which means that the network may have _overfit_, or learned the training data so rigidly that it can't make effective predictions about new data.\n",
+ "\n",
+ "In addition, the mean absolute error values are quite high, ~0.305 at best, which means some of the model's predictions are at least 30% off. A 30% error means we are very far from accurately modelling the sine wave function.\n",
+ "\n",
+ "**3. Actual vs Predicted Outputs**\n",
+ "\n",
+ "To get more insight into what is happening, let's check its predictions against the test dataset we set aside earlier:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "i13eVIT3B9Mj",
+ "outputId": "6004cf7f-77d3-4cb9-fa0d-49bdc591301e",
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 299
+ }
+ },
+ "source": [
+ "# Calculate and print the loss on our test dataset\n",
+ "test_loss, test_mae = model_1.evaluate(x_test, y_test)\n",
+ "\n",
+ "# Make predictions based on our test dataset\n",
+ "y_test_pred = model_1.predict(x_test)\n",
+ "\n",
+ "# Graph the predictions against the actual values\n",
+ "plt.clf()\n",
+ "plt.title('Comparison of predictions and actual values')\n",
+ "plt.plot(x_test, y_test, 'b.', label='Actual values')\n",
+ "plt.plot(x_test, y_test_pred, 'r.', label='TF predictions')\n",
+ "plt.legend()\n",
+ "plt.show()"
+ ],
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "text": [
+ "7/7 [==============================] - 0s 2ms/step - loss: 0.1627 - mae: 0.3434\n"
+ ],
+ "name": "stdout"
+ },
+ {
+ "output_type": "display_data",
+ "data": {
+ "image/png": "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+IqiKBWCunQURVEqBLXwFUVRKoTAFqDab7/9TJ8+fYothqIoSkmxevXqfxtj9vfbFliF36dPH1atWlVsMRRFUUoKEUk4klpdOoqiKBWCKnxFUZQKQRW+oihKhRBYH76iKMVj586dNDU1sX379mKLoiSgW7du9OrVi+rq6tQ7O6jCVxSlA01NTey111706dMHn7lulCJjjKG5uZmmpiYOO+yw1F9wUJeOoigd2L59OzU1NarsA4qIUFNTk/ETmCr8MiUahalT7buiZIMq+2CTzf1Rl04ZEo3CyJGwYwd06QJPPw2RSLGlUhSl2KiFX4Y0Nlpl39pq3xsbiy2RomTHokWLEBFeeSX1lAozZ87ks88+S7lfIu6//34mTpyY9ffz3U4hUIVfhtTWWss+HLbvtbXFlkhRsmP+/PkMHTqU+fPnp9w3V4VfCajCL0MiEevG+dnP0nPnqL9fyQf5/h198sknrFixgtmzZ/PQQ7FZMltbW7nmmms45phj6N+/P7fffju33XYbW7ZsYcSIEYwYMQKAPffcc/d3HnnkES688EIAnnjiCY4//ngGDRrESSedxLvvvptQhra2Nvr06cOHH364e13fvn15991302rnwgsv5JFHHtm97JXpl7/8Jccddxz9+/fnpptuAuDTTz/ltNNOY8CAARxzzDE8/PDDHdrMBfXhlymRSHp++2z8/dGodRPV1mpsQLEUIm702GOPccopp3DkkUdSU1PD6tWrOfbYY6mvr2fjxo2sWbOGqqoq3n//ffbdd19+85vfsHTpUvbbb7+k7Q4dOpS//vWviAj33nsvM2bM4Ne//rXvvqFQiNGjR7Nw4UIuuuginnvuOb7whS9w4IEHZtROPIsXL+a1117j+eefxxjDmWeeybJly9i6dSs9e/bkj3/8IwAfffRRZhctBarwK5x4f39DQ3JlrgFhxQ+/uFGuv4v58+fzwx/+EIDvfOc7zJ8/n2OPPZYlS5YwYcIEqqqs+tp3330zarepqYlzzjmHt99+mx07dqTMYz/nnHO4+eabueiii3jooYc455xzsmrHy+LFi1m8eDGDBg0C7NPMa6+9xrBhw7j66qu57rrrOP300xk2bFhG55YKdelUOLW11tcvAqEQzJkDN95olbrfo3mygLC6hiqXfMeN3n//ff7yl79w6aWX0qdPH375y1/y+9//nkwmbPKmLXrz1a+44gomTpzIyy+/zKxZs1LmskciETZs2MDWrVtZtGgRZ599dtrtVFVV0dbWBlj30I4ddm57YwyTJ09mzZo1rFmzhg0bNnDJJZdw5JFH8sILL9CvXz9uuOEGbr755rTPNx1U4VcQiRSy+79oa4Ndu6wy377dWvvxJPpju5Z/ss5CKV8yjRul4pFHHuF73/seb775Jhs3bmTTpk0cdthhLF++nK9//evMmjWLXbt2AbZzANhrr734+OOPd7dx4IEHsn79etra2li4cOHu9R999BGHHHIIAA888EBKWUSEs846i6uuuoqjjjqKmpqatNvp06cPq1evBuDxxx9n586dAJx88snMmTOHTz75BIDNmzfz3nvvsWXLFnr06MH555/PtddeywsvvJD+RUsDdemUCLn6zb2umKoquOgiGDfOtrlrFxhjX67yNwbuu8/u4z2e+8eOl6UQj/RKaZFu3Cgd5s+fz3XXXddu3dixY5k/fz633347r776Kv3796e6uprvf//7TJw4kbq6Ok455RR69uzJ0qVLmTZtGqeffjr7778/gwcP3q1cp0yZwre+9S0+//nP87WvfY1//etfKeU555xzOO6447j//vt3r0unne9///uMHj2aAQMGcMopp7DHHnsAMGrUKNavX0/EuWB77rknc+fOZcOGDVx77bWEQiGqq6u5++67s72E/hhjcn4Bc4D3gL8n2C7AbcAG4CXgK6naPPbYY41iWbnSmO7djQmH7fvKlZl995ZbjBkzxhgRV63bz927GzNrVvu2x4yJ7RMK2e/Gt+V3/FxkVILHunXrii2CkgZ+9wlYZRLo1XxZ+PcDdwA+TgAATgX6Oq/jgbuddyUNsrWe6+th4sSYBe/FGNtWc3N7i/3ll2HRIrtPWxs4T68pg7WJLH9FUYJDXhS+MWaZiPRJsstooMHpff4qIvuIyMHGmLfzcfxyx/Wbu8o2nYBYNAqXX26VvRc3OAuxtryP4o2Ndntbm31vbo6tT9XpeNvwLiuKEgw6y4d/CLDJs9zkrGun8EWkDqgD6N27dyeJVhpccIF9j/epJ6Kx0SptL6EQdO0KM2daRe5nidfW2n3iO5d0Oh1N2VSUYBOooK0xph6oBxg8eHD6+VdlTLwSHTcuve+5irulxSr6q66CffZJ7W5J5JpJx2WjgVtFCTadpfA3A4d6lns565QU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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "tags": [],
+ "needs_background": "light"
+ }
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "Wokallj1D21L"
+ },
+ "source": [
+ "Oh dear! The graph makes it clear that our network has learned to approximate the sine function in a very limited way.\n",
+ "\n",
+ "The rigidity of this fit suggests that the model does not have enough capacity to learn the full complexity of the sine wave function, so it's only able to approximate it in an overly simplistic way. By making our model bigger, we should be able to improve its performance."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "T7sL-hWtoAZC"
+ },
+ "source": [
+ "## Training a Larger Model"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "aQd0JSdOoAbw"
+ },
+ "source": [
+ "### 1. Design the Model\n",
+ "To make our model bigger, let's add an additional layer of neurons. The following cell redefines our model in the same way as earlier, but with 16 neurons in the first layer and an additional layer of 16 neurons in the middle:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "oW0xus6AF-4o"
+ },
+ "source": [
+ "model = tf.keras.Sequential()\n",
+ "\n",
+ "# First layer takes a scalar input and feeds it through 16 \"neurons\". The\n",
+ "# neurons decide whether to activate based on the 'relu' activation function.\n",
+ "model.add(keras.layers.Dense(16, activation='relu', input_shape=(1,)))\n",
+ "\n",
+ "# The new second and third layer will help the network learn more complex representations\n",
+ "model.add(keras.layers.Dense(16, activation='relu'))\n",
+ "\n",
+ "# Final layer is a single neuron, since we want to output a single value\n",
+ "model.add(keras.layers.Dense(1))\n",
+ "\n",
+ "# Compile the model using the standard 'adam' optimizer and the mean squared error or 'mse' loss function for regression.\n",
+ "model.compile(optimizer='adam', loss=\"mse\", metrics=[\"mae\"])"
+ ],
+ "execution_count": null,
+ "outputs": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "Dv2SC409Grap"
+ },
+ "source": [
+ "### 2. Train the Model ###\n",
+ "\n",
+ "We'll now train and save the new model."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "DPAUrdkmGq1M",
+ "outputId": "b0b50b8b-f5fc-4433-db0e-703697443b76",
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ }
+ },
+ "source": [
+ "# Train the model\n",
+ "history = model.fit(x_train, y_train, epochs=500, batch_size=64,\n",
+ " validation_data=(x_validate, y_validate))\n",
+ "\n",
+ "# Save the model to disk\n",
+ "model.save(MODEL_TF)"
+ ],
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "text": [
+ "Epoch 1/500\n",
+ "10/10 [==============================] - 1s 20ms/step - loss: 0.4355 - mae: 0.5542 - val_loss: 0.4315 - val_mae: 0.5685\n",
+ "Epoch 2/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.4183 - mae: 0.5548 - val_loss: 0.4157 - val_mae: 0.5581\n",
+ "Epoch 3/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.3871 - mae: 0.5322 - val_loss: 0.3988 - val_mae: 0.5444\n",
+ "Epoch 4/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3954 - mae: 0.5348 - val_loss: 0.3834 - val_mae: 0.5350\n",
+ "Epoch 5/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3670 - mae: 0.5163 - val_loss: 0.3684 - val_mae: 0.5257\n",
+ "Epoch 6/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3426 - mae: 0.4999 - val_loss: 0.3532 - val_mae: 0.5166\n",
+ "Epoch 7/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3453 - mae: 0.5006 - val_loss: 0.3369 - val_mae: 0.5055\n",
+ "Epoch 8/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.3182 - mae: 0.4830 - val_loss: 0.3203 - val_mae: 0.4940\n",
+ "Epoch 9/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.3013 - mae: 0.4691 - val_loss: 0.3041 - val_mae: 0.4833\n",
+ "Epoch 10/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.2795 - mae: 0.4523 - val_loss: 0.2867 - val_mae: 0.4699\n",
+ "Epoch 11/500\n",
+ "10/10 [==============================] - 0s 20ms/step - loss: 0.2632 - mae: 0.4395 - val_loss: 0.2698 - val_mae: 0.4558\n",
+ "Epoch 12/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.2581 - mae: 0.4331 - val_loss: 0.2534 - val_mae: 0.4436\n",
+ "Epoch 13/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.2363 - mae: 0.4185 - val_loss: 0.2381 - val_mae: 0.4318\n",
+ "Epoch 14/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.2171 - mae: 0.3972 - val_loss: 0.2220 - val_mae: 0.4151\n",
+ "Epoch 15/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1944 - mae: 0.3783 - val_loss: 0.2095 - val_mae: 0.4041\n",
+ "Epoch 16/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1948 - mae: 0.3796 - val_loss: 0.1969 - val_mae: 0.3902\n",
+ "Epoch 17/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1842 - mae: 0.3642 - val_loss: 0.1868 - val_mae: 0.3790\n",
+ "Epoch 18/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1706 - mae: 0.3480 - val_loss: 0.1781 - val_mae: 0.3677\n",
+ "Epoch 19/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1599 - mae: 0.3348 - val_loss: 0.1713 - val_mae: 0.3576\n",
+ "Epoch 20/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1563 - mae: 0.3340 - val_loss: 0.1653 - val_mae: 0.3468\n",
+ "Epoch 21/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1487 - mae: 0.3161 - val_loss: 0.1613 - val_mae: 0.3391\n",
+ "Epoch 22/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1425 - mae: 0.3061 - val_loss: 0.1577 - val_mae: 0.3306\n",
+ "Epoch 23/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1347 - mae: 0.3005 - val_loss: 0.1552 - val_mae: 0.3235\n",
+ "Epoch 24/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1411 - mae: 0.2995 - val_loss: 0.1533 - val_mae: 0.3185\n",
+ "Epoch 25/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1414 - mae: 0.2992 - val_loss: 0.1517 - val_mae: 0.3122\n",
+ "Epoch 26/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1397 - mae: 0.3011 - val_loss: 0.1517 - val_mae: 0.3129\n",
+ "Epoch 27/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1335 - mae: 0.2879 - val_loss: 0.1494 - val_mae: 0.3057\n",
+ "Epoch 28/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1335 - mae: 0.2897 - val_loss: 0.1490 - val_mae: 0.3049\n",
+ "Epoch 29/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1287 - mae: 0.2792 - val_loss: 0.1478 - val_mae: 0.3010\n",
+ "Epoch 30/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1291 - mae: 0.2774 - val_loss: 0.1472 - val_mae: 0.2992\n",
+ "Epoch 31/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1245 - mae: 0.2756 - val_loss: 0.1467 - val_mae: 0.2991\n",
+ "Epoch 32/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1327 - mae: 0.2775 - val_loss: 0.1460 - val_mae: 0.2977\n",
+ "Epoch 33/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1163 - mae: 0.2613 - val_loss: 0.1453 - val_mae: 0.2955\n",
+ "Epoch 34/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1251 - mae: 0.2731 - val_loss: 0.1443 - val_mae: 0.2922\n",
+ "Epoch 35/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1365 - mae: 0.2829 - val_loss: 0.1441 - val_mae: 0.2951\n",
+ "Epoch 36/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1283 - mae: 0.2757 - val_loss: 0.1427 - val_mae: 0.2905\n",
+ "Epoch 37/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1146 - mae: 0.2567 - val_loss: 0.1432 - val_mae: 0.2930\n",
+ "Epoch 38/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1231 - mae: 0.2655 - val_loss: 0.1412 - val_mae: 0.2869\n",
+ "Epoch 39/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1263 - mae: 0.2739 - val_loss: 0.1407 - val_mae: 0.2890\n",
+ "Epoch 40/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1396 - mae: 0.2878 - val_loss: 0.1398 - val_mae: 0.2867\n",
+ "Epoch 41/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1194 - mae: 0.2651 - val_loss: 0.1390 - val_mae: 0.2835\n",
+ "Epoch 42/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1206 - mae: 0.2607 - val_loss: 0.1379 - val_mae: 0.2831\n",
+ "Epoch 43/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1296 - mae: 0.2716 - val_loss: 0.1373 - val_mae: 0.2850\n",
+ "Epoch 44/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1155 - mae: 0.2545 - val_loss: 0.1362 - val_mae: 0.2814\n",
+ "Epoch 45/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1237 - mae: 0.2610 - val_loss: 0.1353 - val_mae: 0.2806\n",
+ "Epoch 46/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1163 - mae: 0.2529 - val_loss: 0.1350 - val_mae: 0.2815\n",
+ "Epoch 47/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1123 - mae: 0.2527 - val_loss: 0.1339 - val_mae: 0.2814\n",
+ "Epoch 48/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1136 - mae: 0.2541 - val_loss: 0.1325 - val_mae: 0.2775\n",
+ "Epoch 49/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1154 - mae: 0.2535 - val_loss: 0.1318 - val_mae: 0.2783\n",
+ "Epoch 50/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1249 - mae: 0.2632 - val_loss: 0.1312 - val_mae: 0.2715\n",
+ "Epoch 51/500\n",
+ "10/10 [==============================] - 0s 17ms/step - loss: 0.1117 - mae: 0.2534 - val_loss: 0.1319 - val_mae: 0.2801\n",
+ "Epoch 52/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1088 - mae: 0.2529 - val_loss: 0.1289 - val_mae: 0.2727\n",
+ "Epoch 53/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1166 - mae: 0.2611 - val_loss: 0.1290 - val_mae: 0.2760\n",
+ "Epoch 54/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1137 - mae: 0.2537 - val_loss: 0.1270 - val_mae: 0.2696\n",
+ "Epoch 55/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1063 - mae: 0.2480 - val_loss: 0.1268 - val_mae: 0.2726\n",
+ "Epoch 56/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1083 - mae: 0.2461 - val_loss: 0.1253 - val_mae: 0.2655\n",
+ "Epoch 57/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0997 - mae: 0.2326 - val_loss: 0.1245 - val_mae: 0.2668\n",
+ "Epoch 58/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1066 - mae: 0.2470 - val_loss: 0.1235 - val_mae: 0.2644\n",
+ "Epoch 59/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.1068 - mae: 0.2399 - val_loss: 0.1231 - val_mae: 0.2662\n",
+ "Epoch 60/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1055 - mae: 0.2396 - val_loss: 0.1217 - val_mae: 0.2618\n",
+ "Epoch 61/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1034 - mae: 0.2338 - val_loss: 0.1207 - val_mae: 0.2606\n",
+ "Epoch 62/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1057 - mae: 0.2456 - val_loss: 0.1217 - val_mae: 0.2662\n",
+ "Epoch 63/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1067 - mae: 0.2439 - val_loss: 0.1189 - val_mae: 0.2564\n",
+ "Epoch 64/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0984 - mae: 0.2338 - val_loss: 0.1185 - val_mae: 0.2593\n",
+ "Epoch 65/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0974 - mae: 0.2356 - val_loss: 0.1175 - val_mae: 0.2598\n",
+ "Epoch 66/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0982 - mae: 0.2355 - val_loss: 0.1161 - val_mae: 0.2540\n",
+ "Epoch 67/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.1027 - mae: 0.2385 - val_loss: 0.1159 - val_mae: 0.2556\n",
+ "Epoch 68/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1017 - mae: 0.2356 - val_loss: 0.1144 - val_mae: 0.2511\n",
+ "Epoch 69/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0948 - mae: 0.2266 - val_loss: 0.1136 - val_mae: 0.2529\n",
+ "Epoch 70/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0969 - mae: 0.2316 - val_loss: 0.1127 - val_mae: 0.2516\n",
+ "Epoch 71/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0959 - mae: 0.2247 - val_loss: 0.1116 - val_mae: 0.2473\n",
+ "Epoch 72/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0988 - mae: 0.2279 - val_loss: 0.1107 - val_mae: 0.2468\n",
+ "Epoch 73/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.1069 - mae: 0.2367 - val_loss: 0.1097 - val_mae: 0.2461\n",
+ "Epoch 74/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0924 - mae: 0.2292 - val_loss: 0.1090 - val_mae: 0.2463\n",
+ "Epoch 75/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0967 - mae: 0.2268 - val_loss: 0.1080 - val_mae: 0.2454\n",
+ "Epoch 76/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0892 - mae: 0.2194 - val_loss: 0.1070 - val_mae: 0.2415\n",
+ "Epoch 77/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0939 - mae: 0.2265 - val_loss: 0.1064 - val_mae: 0.2431\n",
+ "Epoch 78/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0874 - mae: 0.2146 - val_loss: 0.1056 - val_mae: 0.2370\n",
+ "Epoch 79/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0895 - mae: 0.2188 - val_loss: 0.1050 - val_mae: 0.2413\n",
+ "Epoch 80/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0820 - mae: 0.2127 - val_loss: 0.1036 - val_mae: 0.2366\n",
+ "Epoch 81/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0890 - mae: 0.2167 - val_loss: 0.1027 - val_mae: 0.2380\n",
+ "Epoch 82/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0905 - mae: 0.2191 - val_loss: 0.1018 - val_mae: 0.2359\n",
+ "Epoch 83/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0822 - mae: 0.2072 - val_loss: 0.1012 - val_mae: 0.2346\n",
+ "Epoch 84/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0870 - mae: 0.2135 - val_loss: 0.1001 - val_mae: 0.2334\n",
+ "Epoch 85/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0936 - mae: 0.2228 - val_loss: 0.0993 - val_mae: 0.2310\n",
+ "Epoch 86/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0762 - mae: 0.2036 - val_loss: 0.0990 - val_mae: 0.2330\n",
+ "Epoch 87/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0781 - mae: 0.2018 - val_loss: 0.0978 - val_mae: 0.2314\n",
+ "Epoch 88/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0835 - mae: 0.2111 - val_loss: 0.0969 - val_mae: 0.2289\n",
+ "Epoch 89/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0814 - mae: 0.2084 - val_loss: 0.0961 - val_mae: 0.2279\n",
+ "Epoch 90/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0791 - mae: 0.2048 - val_loss: 0.0953 - val_mae: 0.2268\n",
+ "Epoch 91/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0816 - mae: 0.2088 - val_loss: 0.0948 - val_mae: 0.2288\n",
+ "Epoch 92/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0818 - mae: 0.2083 - val_loss: 0.0939 - val_mae: 0.2217\n",
+ "Epoch 93/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0735 - mae: 0.1931 - val_loss: 0.0934 - val_mae: 0.2255\n",
+ "Epoch 94/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0812 - mae: 0.2072 - val_loss: 0.0921 - val_mae: 0.2217\n",
+ "Epoch 95/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0815 - mae: 0.2055 - val_loss: 0.0913 - val_mae: 0.2205\n",
+ "Epoch 96/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0766 - mae: 0.2003 - val_loss: 0.0905 - val_mae: 0.2187\n",
+ "Epoch 97/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0803 - mae: 0.2053 - val_loss: 0.0898 - val_mae: 0.2202\n",
+ "Epoch 98/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0748 - mae: 0.1963 - val_loss: 0.0890 - val_mae: 0.2184\n",
+ "Epoch 99/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0754 - mae: 0.1959 - val_loss: 0.0885 - val_mae: 0.2134\n",
+ "Epoch 100/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0785 - mae: 0.2020 - val_loss: 0.0876 - val_mae: 0.2138\n",
+ "Epoch 101/500\n",
+ "10/10 [==============================] - 0s 19ms/step - loss: 0.0724 - mae: 0.1939 - val_loss: 0.0868 - val_mae: 0.2148\n",
+ "Epoch 102/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0742 - mae: 0.1977 - val_loss: 0.0861 - val_mae: 0.2130\n",
+ "Epoch 103/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0714 - mae: 0.1943 - val_loss: 0.0855 - val_mae: 0.2151\n",
+ "Epoch 104/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0777 - mae: 0.2017 - val_loss: 0.0845 - val_mae: 0.2110\n",
+ "Epoch 105/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0689 - mae: 0.1883 - val_loss: 0.0845 - val_mae: 0.2105\n",
+ "Epoch 106/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0660 - mae: 0.1848 - val_loss: 0.0832 - val_mae: 0.2100\n",
+ "Epoch 107/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0721 - mae: 0.1913 - val_loss: 0.0825 - val_mae: 0.2089\n",
+ "Epoch 108/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0819 - mae: 0.2055 - val_loss: 0.0819 - val_mae: 0.2077\n",
+ "Epoch 109/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0731 - mae: 0.1940 - val_loss: 0.0812 - val_mae: 0.2072\n",
+ "Epoch 110/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0678 - mae: 0.1863 - val_loss: 0.0805 - val_mae: 0.2051\n",
+ "Epoch 111/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0688 - mae: 0.1840 - val_loss: 0.0799 - val_mae: 0.2031\n",
+ "Epoch 112/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0739 - mae: 0.1874 - val_loss: 0.0792 - val_mae: 0.2031\n",
+ "Epoch 113/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0745 - mae: 0.1944 - val_loss: 0.0788 - val_mae: 0.2023\n",
+ "Epoch 114/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0704 - mae: 0.1902 - val_loss: 0.0780 - val_mae: 0.2016\n",
+ "Epoch 115/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0664 - mae: 0.1864 - val_loss: 0.0774 - val_mae: 0.2016\n",
+ "Epoch 116/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0624 - mae: 0.1774 - val_loss: 0.0769 - val_mae: 0.1986\n",
+ "Epoch 117/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.0688 - mae: 0.1869 - val_loss: 0.0761 - val_mae: 0.1991\n",
+ "Epoch 118/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0671 - mae: 0.1801 - val_loss: 0.0756 - val_mae: 0.1975\n",
+ "Epoch 119/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0656 - mae: 0.1839 - val_loss: 0.0750 - val_mae: 0.1986\n",
+ "Epoch 120/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0554 - mae: 0.1686 - val_loss: 0.0742 - val_mae: 0.1973\n",
+ "Epoch 121/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0627 - mae: 0.1815 - val_loss: 0.0737 - val_mae: 0.1971\n",
+ "Epoch 122/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0668 - mae: 0.1842 - val_loss: 0.0733 - val_mae: 0.1955\n",
+ "Epoch 123/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0683 - mae: 0.1886 - val_loss: 0.0726 - val_mae: 0.1935\n",
+ "Epoch 124/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0601 - mae: 0.1734 - val_loss: 0.0726 - val_mae: 0.1966\n",
+ "Epoch 125/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0608 - mae: 0.1845 - val_loss: 0.0715 - val_mae: 0.1950\n",
+ "Epoch 126/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0644 - mae: 0.1833 - val_loss: 0.0709 - val_mae: 0.1940\n",
+ "Epoch 127/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0572 - mae: 0.1708 - val_loss: 0.0703 - val_mae: 0.1916\n",
+ "Epoch 128/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0571 - mae: 0.1712 - val_loss: 0.0698 - val_mae: 0.1901\n",
+ "Epoch 129/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0593 - mae: 0.1732 - val_loss: 0.0692 - val_mae: 0.1899\n",
+ "Epoch 130/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0583 - mae: 0.1718 - val_loss: 0.0688 - val_mae: 0.1914\n",
+ "Epoch 131/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0659 - mae: 0.1828 - val_loss: 0.0681 - val_mae: 0.1880\n",
+ "Epoch 132/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0601 - mae: 0.1734 - val_loss: 0.0686 - val_mae: 0.1927\n",
+ "Epoch 133/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0614 - mae: 0.1796 - val_loss: 0.0675 - val_mae: 0.1877\n",
+ "Epoch 134/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0575 - mae: 0.1725 - val_loss: 0.0670 - val_mae: 0.1899\n",
+ "Epoch 135/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0638 - mae: 0.1833 - val_loss: 0.0663 - val_mae: 0.1832\n",
+ "Epoch 136/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0519 - mae: 0.1603 - val_loss: 0.0661 - val_mae: 0.1886\n",
+ "Epoch 137/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0523 - mae: 0.1655 - val_loss: 0.0650 - val_mae: 0.1851\n",
+ "Epoch 138/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0499 - mae: 0.1625 - val_loss: 0.0645 - val_mae: 0.1841\n",
+ "Epoch 139/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0582 - mae: 0.1712 - val_loss: 0.0640 - val_mae: 0.1838\n",
+ "Epoch 140/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0520 - mae: 0.1618 - val_loss: 0.0640 - val_mae: 0.1853\n",
+ "Epoch 141/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0509 - mae: 0.1662 - val_loss: 0.0630 - val_mae: 0.1824\n",
+ "Epoch 142/500\n",
+ "10/10 [==============================] - 0s 18ms/step - loss: 0.0508 - mae: 0.1620 - val_loss: 0.0625 - val_mae: 0.1832\n",
+ "Epoch 143/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0484 - mae: 0.1564 - val_loss: 0.0624 - val_mae: 0.1823\n",
+ "Epoch 144/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0526 - mae: 0.1651 - val_loss: 0.0615 - val_mae: 0.1791\n",
+ "Epoch 145/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0536 - mae: 0.1649 - val_loss: 0.0611 - val_mae: 0.1809\n",
+ "Epoch 146/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0484 - mae: 0.1590 - val_loss: 0.0606 - val_mae: 0.1786\n",
+ "Epoch 147/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0555 - mae: 0.1652 - val_loss: 0.0601 - val_mae: 0.1770\n",
+ "Epoch 148/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0493 - mae: 0.1578 - val_loss: 0.0597 - val_mae: 0.1778\n",
+ "Epoch 149/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0475 - mae: 0.1538 - val_loss: 0.0591 - val_mae: 0.1779\n",
+ "Epoch 150/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0484 - mae: 0.1541 - val_loss: 0.0589 - val_mae: 0.1765\n",
+ "Epoch 151/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0580 - mae: 0.1705 - val_loss: 0.0584 - val_mae: 0.1741\n",
+ "Epoch 152/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0556 - mae: 0.1653 - val_loss: 0.0579 - val_mae: 0.1759\n",
+ "Epoch 153/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0491 - mae: 0.1562 - val_loss: 0.0576 - val_mae: 0.1714\n",
+ "Epoch 154/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0526 - mae: 0.1610 - val_loss: 0.0569 - val_mae: 0.1756\n",
+ "Epoch 155/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0460 - mae: 0.1538 - val_loss: 0.0563 - val_mae: 0.1722\n",
+ "Epoch 156/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0530 - mae: 0.1634 - val_loss: 0.0558 - val_mae: 0.1721\n",
+ "Epoch 157/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0464 - mae: 0.1522 - val_loss: 0.0556 - val_mae: 0.1710\n",
+ "Epoch 158/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0477 - mae: 0.1548 - val_loss: 0.0550 - val_mae: 0.1701\n",
+ "Epoch 159/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0447 - mae: 0.1499 - val_loss: 0.0546 - val_mae: 0.1706\n",
+ "Epoch 160/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0428 - mae: 0.1500 - val_loss: 0.0541 - val_mae: 0.1686\n",
+ "Epoch 161/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0436 - mae: 0.1471 - val_loss: 0.0540 - val_mae: 0.1717\n",
+ "Epoch 162/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0400 - mae: 0.1434 - val_loss: 0.0534 - val_mae: 0.1664\n",
+ "Epoch 163/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0361 - mae: 0.1362 - val_loss: 0.0540 - val_mae: 0.1735\n",
+ "Epoch 164/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0431 - mae: 0.1522 - val_loss: 0.0536 - val_mae: 0.1694\n",
+ "Epoch 165/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0444 - mae: 0.1504 - val_loss: 0.0531 - val_mae: 0.1711\n",
+ "Epoch 166/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0448 - mae: 0.1549 - val_loss: 0.0516 - val_mae: 0.1643\n",
+ "Epoch 167/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0417 - mae: 0.1455 - val_loss: 0.0511 - val_mae: 0.1664\n",
+ "Epoch 168/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0454 - mae: 0.1517 - val_loss: 0.0510 - val_mae: 0.1636\n",
+ "Epoch 169/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0439 - mae: 0.1469 - val_loss: 0.0506 - val_mae: 0.1663\n",
+ "Epoch 170/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0410 - mae: 0.1447 - val_loss: 0.0501 - val_mae: 0.1610\n",
+ "Epoch 171/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0404 - mae: 0.1449 - val_loss: 0.0495 - val_mae: 0.1643\n",
+ "Epoch 172/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0427 - mae: 0.1489 - val_loss: 0.0491 - val_mae: 0.1626\n",
+ "Epoch 173/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0421 - mae: 0.1473 - val_loss: 0.0490 - val_mae: 0.1632\n",
+ "Epoch 174/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0460 - mae: 0.1511 - val_loss: 0.0486 - val_mae: 0.1590\n",
+ "Epoch 175/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0431 - mae: 0.1461 - val_loss: 0.0480 - val_mae: 0.1602\n",
+ "Epoch 176/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0426 - mae: 0.1484 - val_loss: 0.0473 - val_mae: 0.1597\n",
+ "Epoch 177/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0380 - mae: 0.1396 - val_loss: 0.0473 - val_mae: 0.1617\n",
+ "Epoch 178/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0367 - mae: 0.1401 - val_loss: 0.0467 - val_mae: 0.1582\n",
+ "Epoch 179/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0406 - mae: 0.1438 - val_loss: 0.0462 - val_mae: 0.1578\n",
+ "Epoch 180/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0378 - mae: 0.1410 - val_loss: 0.0461 - val_mae: 0.1566\n",
+ "Epoch 181/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0353 - mae: 0.1352 - val_loss: 0.0457 - val_mae: 0.1591\n",
+ "Epoch 182/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0381 - mae: 0.1427 - val_loss: 0.0451 - val_mae: 0.1558\n",
+ "Epoch 183/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0372 - mae: 0.1353 - val_loss: 0.0448 - val_mae: 0.1562\n",
+ "Epoch 184/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0400 - mae: 0.1428 - val_loss: 0.0442 - val_mae: 0.1548\n",
+ "Epoch 185/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.0378 - mae: 0.1393 - val_loss: 0.0438 - val_mae: 0.1541\n",
+ "Epoch 186/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0379 - mae: 0.1409 - val_loss: 0.0434 - val_mae: 0.1540\n",
+ "Epoch 187/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0357 - mae: 0.1355 - val_loss: 0.0431 - val_mae: 0.1535\n",
+ "Epoch 188/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0405 - mae: 0.1478 - val_loss: 0.0427 - val_mae: 0.1514\n",
+ "Epoch 189/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0375 - mae: 0.1384 - val_loss: 0.0423 - val_mae: 0.1512\n",
+ "Epoch 190/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0387 - mae: 0.1432 - val_loss: 0.0425 - val_mae: 0.1541\n",
+ "Epoch 191/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0347 - mae: 0.1374 - val_loss: 0.0418 - val_mae: 0.1500\n",
+ "Epoch 192/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0336 - mae: 0.1321 - val_loss: 0.0413 - val_mae: 0.1518\n",
+ "Epoch 193/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0369 - mae: 0.1356 - val_loss: 0.0409 - val_mae: 0.1506\n",
+ "Epoch 194/500\n",
+ "10/10 [==============================] - 0s 19ms/step - loss: 0.0355 - mae: 0.1353 - val_loss: 0.0405 - val_mae: 0.1480\n",
+ "Epoch 195/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0396 - mae: 0.1430 - val_loss: 0.0401 - val_mae: 0.1487\n",
+ "Epoch 196/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0348 - mae: 0.1352 - val_loss: 0.0403 - val_mae: 0.1510\n",
+ "Epoch 197/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0320 - mae: 0.1299 - val_loss: 0.0396 - val_mae: 0.1464\n",
+ "Epoch 198/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0349 - mae: 0.1328 - val_loss: 0.0393 - val_mae: 0.1484\n",
+ "Epoch 199/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0362 - mae: 0.1389 - val_loss: 0.0387 - val_mae: 0.1446\n",
+ "Epoch 200/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0303 - mae: 0.1235 - val_loss: 0.0384 - val_mae: 0.1446\n",
+ "Epoch 201/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0326 - mae: 0.1310 - val_loss: 0.0394 - val_mae: 0.1510\n",
+ "Epoch 202/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0345 - mae: 0.1359 - val_loss: 0.0389 - val_mae: 0.1460\n",
+ "Epoch 203/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0294 - mae: 0.1263 - val_loss: 0.0388 - val_mae: 0.1494\n",
+ "Epoch 204/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0336 - mae: 0.1355 - val_loss: 0.0373 - val_mae: 0.1438\n",
+ "Epoch 205/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0323 - mae: 0.1316 - val_loss: 0.0368 - val_mae: 0.1418\n",
+ "Epoch 206/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0294 - mae: 0.1234 - val_loss: 0.0366 - val_mae: 0.1427\n",
+ "Epoch 207/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0330 - mae: 0.1294 - val_loss: 0.0360 - val_mae: 0.1410\n",
+ "Epoch 208/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0333 - mae: 0.1314 - val_loss: 0.0357 - val_mae: 0.1417\n",
+ "Epoch 209/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0295 - mae: 0.1240 - val_loss: 0.0360 - val_mae: 0.1401\n",
+ "Epoch 210/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0313 - mae: 0.1265 - val_loss: 0.0356 - val_mae: 0.1434\n",
+ "Epoch 211/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0301 - mae: 0.1257 - val_loss: 0.0348 - val_mae: 0.1396\n",
+ "Epoch 212/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0295 - mae: 0.1253 - val_loss: 0.0349 - val_mae: 0.1390\n",
+ "Epoch 213/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0314 - mae: 0.1312 - val_loss: 0.0341 - val_mae: 0.1387\n",
+ "Epoch 214/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0332 - mae: 0.1322 - val_loss: 0.0341 - val_mae: 0.1381\n",
+ "Epoch 215/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0310 - mae: 0.1268 - val_loss: 0.0344 - val_mae: 0.1396\n",
+ "Epoch 216/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0310 - mae: 0.1300 - val_loss: 0.0331 - val_mae: 0.1369\n",
+ "Epoch 217/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0273 - mae: 0.1208 - val_loss: 0.0329 - val_mae: 0.1352\n",
+ "Epoch 218/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0278 - mae: 0.1210 - val_loss: 0.0326 - val_mae: 0.1368\n",
+ "Epoch 219/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0308 - mae: 0.1274 - val_loss: 0.0327 - val_mae: 0.1341\n",
+ "Epoch 220/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0267 - mae: 0.1191 - val_loss: 0.0319 - val_mae: 0.1340\n",
+ "Epoch 221/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0258 - mae: 0.1150 - val_loss: 0.0318 - val_mae: 0.1359\n",
+ "Epoch 222/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0307 - mae: 0.1293 - val_loss: 0.0326 - val_mae: 0.1346\n",
+ "Epoch 223/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0305 - mae: 0.1271 - val_loss: 0.0320 - val_mae: 0.1380\n",
+ "Epoch 224/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0284 - mae: 0.1225 - val_loss: 0.0306 - val_mae: 0.1320\n",
+ "Epoch 225/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0305 - mae: 0.1289 - val_loss: 0.0313 - val_mae: 0.1332\n",
+ "Epoch 226/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0281 - mae: 0.1235 - val_loss: 0.0309 - val_mae: 0.1355\n",
+ "Epoch 227/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0266 - mae: 0.1183 - val_loss: 0.0320 - val_mae: 0.1343\n",
+ "Epoch 228/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0306 - mae: 0.1269 - val_loss: 0.0294 - val_mae: 0.1294\n",
+ "Epoch 229/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0257 - mae: 0.1170 - val_loss: 0.0316 - val_mae: 0.1385\n",
+ "Epoch 230/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0275 - mae: 0.1260 - val_loss: 0.0293 - val_mae: 0.1300\n",
+ "Epoch 231/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0268 - mae: 0.1226 - val_loss: 0.0286 - val_mae: 0.1288\n",
+ "Epoch 232/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0270 - mae: 0.1187 - val_loss: 0.0291 - val_mae: 0.1270\n",
+ "Epoch 233/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0236 - mae: 0.1130 - val_loss: 0.0281 - val_mae: 0.1288\n",
+ "Epoch 234/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0263 - mae: 0.1200 - val_loss: 0.0276 - val_mae: 0.1266\n",
+ "Epoch 235/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0249 - mae: 0.1160 - val_loss: 0.0282 - val_mae: 0.1251\n",
+ "Epoch 236/500\n",
+ "10/10 [==============================] - 0s 18ms/step - loss: 0.0265 - mae: 0.1175 - val_loss: 0.0272 - val_mae: 0.1249\n",
+ "Epoch 237/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0263 - mae: 0.1169 - val_loss: 0.0273 - val_mae: 0.1278\n",
+ "Epoch 238/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0232 - mae: 0.1113 - val_loss: 0.0269 - val_mae: 0.1241\n",
+ "Epoch 239/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0234 - mae: 0.1135 - val_loss: 0.0263 - val_mae: 0.1240\n",
+ "Epoch 240/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0234 - mae: 0.1114 - val_loss: 0.0261 - val_mae: 0.1247\n",
+ "Epoch 241/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0241 - mae: 0.1151 - val_loss: 0.0263 - val_mae: 0.1229\n",
+ "Epoch 242/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0225 - mae: 0.1123 - val_loss: 0.0257 - val_mae: 0.1235\n",
+ "Epoch 243/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0217 - mae: 0.1099 - val_loss: 0.0253 - val_mae: 0.1234\n",
+ "Epoch 244/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0247 - mae: 0.1167 - val_loss: 0.0249 - val_mae: 0.1222\n",
+ "Epoch 245/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0243 - mae: 0.1174 - val_loss: 0.0247 - val_mae: 0.1216\n",
+ "Epoch 246/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0207 - mae: 0.1061 - val_loss: 0.0245 - val_mae: 0.1210\n",
+ "Epoch 247/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0224 - mae: 0.1101 - val_loss: 0.0244 - val_mae: 0.1203\n",
+ "Epoch 248/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0212 - mae: 0.1060 - val_loss: 0.0240 - val_mae: 0.1203\n",
+ "Epoch 249/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0200 - mae: 0.1066 - val_loss: 0.0237 - val_mae: 0.1199\n",
+ "Epoch 250/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0221 - mae: 0.1084 - val_loss: 0.0241 - val_mae: 0.1182\n",
+ "Epoch 251/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0230 - mae: 0.1124 - val_loss: 0.0235 - val_mae: 0.1195\n",
+ "Epoch 252/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0206 - mae: 0.1072 - val_loss: 0.0237 - val_mae: 0.1199\n",
+ "Epoch 253/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0205 - mae: 0.1058 - val_loss: 0.0235 - val_mae: 0.1192\n",
+ "Epoch 254/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0221 - mae: 0.1101 - val_loss: 0.0230 - val_mae: 0.1177\n",
+ "Epoch 255/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0215 - mae: 0.1077 - val_loss: 0.0225 - val_mae: 0.1171\n",
+ "Epoch 256/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0202 - mae: 0.1054 - val_loss: 0.0235 - val_mae: 0.1206\n",
+ "Epoch 257/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0205 - mae: 0.1071 - val_loss: 0.0220 - val_mae: 0.1163\n",
+ "Epoch 258/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0208 - mae: 0.1110 - val_loss: 0.0218 - val_mae: 0.1163\n",
+ "Epoch 259/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0224 - mae: 0.1096 - val_loss: 0.0219 - val_mae: 0.1151\n",
+ "Epoch 260/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0206 - mae: 0.1071 - val_loss: 0.0222 - val_mae: 0.1178\n",
+ "Epoch 261/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0209 - mae: 0.1093 - val_loss: 0.0214 - val_mae: 0.1157\n",
+ "Epoch 262/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0211 - mae: 0.1089 - val_loss: 0.0226 - val_mae: 0.1142\n",
+ "Epoch 263/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0201 - mae: 0.1063 - val_loss: 0.0208 - val_mae: 0.1141\n",
+ "Epoch 264/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0186 - mae: 0.1007 - val_loss: 0.0207 - val_mae: 0.1134\n",
+ "Epoch 265/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0195 - mae: 0.1037 - val_loss: 0.0209 - val_mae: 0.1129\n",
+ "Epoch 266/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0208 - mae: 0.1072 - val_loss: 0.0207 - val_mae: 0.1124\n",
+ "Epoch 267/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0186 - mae: 0.1016 - val_loss: 0.0216 - val_mae: 0.1167\n",
+ "Epoch 268/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0193 - mae: 0.1050 - val_loss: 0.0206 - val_mae: 0.1119\n",
+ "Epoch 269/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0193 - mae: 0.1063 - val_loss: 0.0198 - val_mae: 0.1116\n",
+ "Epoch 270/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0175 - mae: 0.0996 - val_loss: 0.0197 - val_mae: 0.1114\n",
+ "Epoch 271/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0194 - mae: 0.1037 - val_loss: 0.0196 - val_mae: 0.1107\n",
+ "Epoch 272/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0191 - mae: 0.1032 - val_loss: 0.0194 - val_mae: 0.1106\n",
+ "Epoch 273/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0182 - mae: 0.1026 - val_loss: 0.0193 - val_mae: 0.1106\n",
+ "Epoch 274/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0189 - mae: 0.1042 - val_loss: 0.0197 - val_mae: 0.1105\n",
+ "Epoch 275/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0192 - mae: 0.1077 - val_loss: 0.0189 - val_mae: 0.1098\n",
+ "Epoch 276/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0199 - mae: 0.1072 - val_loss: 0.0204 - val_mae: 0.1141\n",
+ "Epoch 277/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0197 - mae: 0.1104 - val_loss: 0.0195 - val_mae: 0.1116\n",
+ "Epoch 278/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0194 - mae: 0.1074 - val_loss: 0.0192 - val_mae: 0.1091\n",
+ "Epoch 279/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0179 - mae: 0.1027 - val_loss: 0.0183 - val_mae: 0.1081\n",
+ "Epoch 280/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0177 - mae: 0.1019 - val_loss: 0.0182 - val_mae: 0.1076\n",
+ "Epoch 281/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0170 - mae: 0.0987 - val_loss: 0.0181 - val_mae: 0.1079\n",
+ "Epoch 282/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0167 - mae: 0.0997 - val_loss: 0.0182 - val_mae: 0.1069\n",
+ "Epoch 283/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0182 - mae: 0.1022 - val_loss: 0.0177 - val_mae: 0.1069\n",
+ "Epoch 284/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0199 - mae: 0.1073 - val_loss: 0.0192 - val_mae: 0.1088\n",
+ "Epoch 285/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0179 - mae: 0.1033 - val_loss: 0.0177 - val_mae: 0.1061\n",
+ "Epoch 286/500\n",
+ "10/10 [==============================] - 0s 21ms/step - loss: 0.0171 - mae: 0.1013 - val_loss: 0.0173 - val_mae: 0.1060\n",
+ "Epoch 287/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0179 - mae: 0.1022 - val_loss: 0.0174 - val_mae: 0.1053\n",
+ "Epoch 288/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0185 - mae: 0.1055 - val_loss: 0.0182 - val_mae: 0.1070\n",
+ "Epoch 289/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0182 - mae: 0.1038 - val_loss: 0.0176 - val_mae: 0.1047\n",
+ "Epoch 290/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0173 - mae: 0.1032 - val_loss: 0.0177 - val_mae: 0.1069\n",
+ "Epoch 291/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0176 - mae: 0.1015 - val_loss: 0.0169 - val_mae: 0.1044\n",
+ "Epoch 292/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0173 - mae: 0.1022 - val_loss: 0.0171 - val_mae: 0.1044\n",
+ "Epoch 293/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0152 - mae: 0.0967 - val_loss: 0.0166 - val_mae: 0.1037\n",
+ "Epoch 294/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0165 - mae: 0.0998 - val_loss: 0.0164 - val_mae: 0.1027\n",
+ "Epoch 295/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0165 - mae: 0.0986 - val_loss: 0.0163 - val_mae: 0.1024\n",
+ "Epoch 296/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0165 - mae: 0.0979 - val_loss: 0.0163 - val_mae: 0.1026\n",
+ "Epoch 297/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.0162 - mae: 0.0987 - val_loss: 0.0162 - val_mae: 0.1020\n",
+ "Epoch 298/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0173 - mae: 0.1011 - val_loss: 0.0160 - val_mae: 0.1021\n",
+ "Epoch 299/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0170 - mae: 0.1019 - val_loss: 0.0165 - val_mae: 0.1029\n",
+ "Epoch 300/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0164 - mae: 0.0996 - val_loss: 0.0155 - val_mae: 0.1005\n",
+ "Epoch 301/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0161 - mae: 0.0987 - val_loss: 0.0156 - val_mae: 0.1005\n",
+ "Epoch 302/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0147 - mae: 0.0952 - val_loss: 0.0162 - val_mae: 0.1029\n",
+ "Epoch 303/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0161 - mae: 0.0999 - val_loss: 0.0171 - val_mae: 0.1027\n",
+ "Epoch 304/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0164 - mae: 0.0990 - val_loss: 0.0161 - val_mae: 0.1007\n",
+ "Epoch 305/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0161 - mae: 0.0975 - val_loss: 0.0156 - val_mae: 0.1001\n",
+ "Epoch 306/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0159 - mae: 0.0982 - val_loss: 0.0167 - val_mae: 0.1039\n",
+ "Epoch 307/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0150 - mae: 0.0951 - val_loss: 0.0162 - val_mae: 0.1023\n",
+ "Epoch 308/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.0175 - mae: 0.1035 - val_loss: 0.0148 - val_mae: 0.0985\n",
+ "Epoch 309/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0152 - mae: 0.0970 - val_loss: 0.0187 - val_mae: 0.1059\n",
+ "Epoch 310/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0172 - mae: 0.1025 - val_loss: 0.0154 - val_mae: 0.1006\n",
+ "Epoch 311/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0162 - mae: 0.0999 - val_loss: 0.0180 - val_mae: 0.1055\n",
+ "Epoch 312/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0162 - mae: 0.1019 - val_loss: 0.0149 - val_mae: 0.0978\n",
+ "Epoch 313/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.0151 - mae: 0.0991 - val_loss: 0.0157 - val_mae: 0.0996\n",
+ "Epoch 314/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.0150 - mae: 0.0951 - val_loss: 0.0148 - val_mae: 0.0983\n",
+ "Epoch 315/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0151 - mae: 0.0974 - val_loss: 0.0150 - val_mae: 0.0988\n",
+ "Epoch 316/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0156 - mae: 0.0987 - val_loss: 0.0146 - val_mae: 0.0977\n",
+ "Epoch 317/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0160 - mae: 0.0987 - val_loss: 0.0151 - val_mae: 0.0971\n",
+ "Epoch 318/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0154 - mae: 0.0973 - val_loss: 0.0141 - val_mae: 0.0960\n",
+ "Epoch 319/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0143 - mae: 0.0940 - val_loss: 0.0141 - val_mae: 0.0963\n",
+ "Epoch 320/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.0131 - mae: 0.0904 - val_loss: 0.0143 - val_mae: 0.0965\n",
+ "Epoch 321/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0142 - mae: 0.0952 - val_loss: 0.0144 - val_mae: 0.0972\n",
+ "Epoch 322/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0146 - mae: 0.0954 - val_loss: 0.0147 - val_mae: 0.0964\n",
+ "Epoch 323/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0143 - mae: 0.0941 - val_loss: 0.0147 - val_mae: 0.0973\n",
+ "Epoch 324/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0149 - mae: 0.0952 - val_loss: 0.0150 - val_mae: 0.0984\n",
+ "Epoch 325/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0154 - mae: 0.0975 - val_loss: 0.0137 - val_mae: 0.0945\n",
+ "Epoch 326/500\n",
+ "10/10 [==============================] - 0s 18ms/step - loss: 0.0135 - mae: 0.0925 - val_loss: 0.0137 - val_mae: 0.0944\n",
+ "Epoch 327/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0134 - mae: 0.0913 - val_loss: 0.0142 - val_mae: 0.0962\n",
+ "Epoch 328/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0143 - mae: 0.0955 - val_loss: 0.0135 - val_mae: 0.0937\n",
+ "Epoch 329/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0142 - mae: 0.0938 - val_loss: 0.0145 - val_mae: 0.0957\n",
+ "Epoch 330/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0150 - mae: 0.0955 - val_loss: 0.0160 - val_mae: 0.1011\n",
+ "Epoch 331/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0162 - mae: 0.0996 - val_loss: 0.0136 - val_mae: 0.0940\n",
+ "Epoch 332/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0135 - mae: 0.0913 - val_loss: 0.0134 - val_mae: 0.0933\n",
+ "Epoch 333/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0133 - mae: 0.0900 - val_loss: 0.0141 - val_mae: 0.0953\n",
+ "Epoch 334/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0144 - mae: 0.0954 - val_loss: 0.0132 - val_mae: 0.0929\n",
+ "Epoch 335/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0134 - mae: 0.0895 - val_loss: 0.0144 - val_mae: 0.0956\n",
+ "Epoch 336/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0142 - mae: 0.0930 - val_loss: 0.0136 - val_mae: 0.0939\n",
+ "Epoch 337/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0135 - mae: 0.0924 - val_loss: 0.0130 - val_mae: 0.0922\n",
+ "Epoch 338/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0133 - mae: 0.0918 - val_loss: 0.0130 - val_mae: 0.0920\n",
+ "Epoch 339/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0132 - mae: 0.0921 - val_loss: 0.0131 - val_mae: 0.0920\n",
+ "Epoch 340/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0125 - mae: 0.0890 - val_loss: 0.0134 - val_mae: 0.0928\n",
+ "Epoch 341/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0139 - mae: 0.0937 - val_loss: 0.0135 - val_mae: 0.0929\n",
+ "Epoch 342/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0141 - mae: 0.0948 - val_loss: 0.0131 - val_mae: 0.0919\n",
+ "Epoch 343/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.0154 - mae: 0.0979 - val_loss: 0.0143 - val_mae: 0.0955\n",
+ "Epoch 344/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0139 - mae: 0.0927 - val_loss: 0.0136 - val_mae: 0.0932\n",
+ "Epoch 345/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0136 - mae: 0.0914 - val_loss: 0.0127 - val_mae: 0.0906\n",
+ "Epoch 346/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0139 - mae: 0.0944 - val_loss: 0.0142 - val_mae: 0.0951\n",
+ "Epoch 347/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0129 - mae: 0.0892 - val_loss: 0.0129 - val_mae: 0.0910\n",
+ "Epoch 348/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0148 - mae: 0.0956 - val_loss: 0.0134 - val_mae: 0.0925\n",
+ "Epoch 349/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0127 - mae: 0.0886 - val_loss: 0.0141 - val_mae: 0.0943\n",
+ "Epoch 350/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0130 - mae: 0.0918 - val_loss: 0.0130 - val_mae: 0.0915\n",
+ "Epoch 351/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0144 - mae: 0.0945 - val_loss: 0.0131 - val_mae: 0.0920\n",
+ "Epoch 352/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0128 - mae: 0.0893 - val_loss: 0.0127 - val_mae: 0.0907\n",
+ "Epoch 353/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0132 - mae: 0.0926 - val_loss: 0.0135 - val_mae: 0.0927\n",
+ "Epoch 354/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0136 - mae: 0.0945 - val_loss: 0.0127 - val_mae: 0.0904\n",
+ "Epoch 355/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0127 - mae: 0.0893 - val_loss: 0.0136 - val_mae: 0.0937\n",
+ "Epoch 356/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0137 - mae: 0.0936 - val_loss: 0.0135 - val_mae: 0.0937\n",
+ "Epoch 357/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0144 - mae: 0.0973 - val_loss: 0.0128 - val_mae: 0.0906\n",
+ "Epoch 358/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0130 - mae: 0.0906 - val_loss: 0.0125 - val_mae: 0.0893\n",
+ "Epoch 359/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0126 - mae: 0.0896 - val_loss: 0.0125 - val_mae: 0.0899\n",
+ "Epoch 360/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0136 - mae: 0.0931 - val_loss: 0.0134 - val_mae: 0.0935\n",
+ "Epoch 361/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0139 - mae: 0.0942 - val_loss: 0.0124 - val_mae: 0.0892\n",
+ "Epoch 362/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0133 - mae: 0.0922 - val_loss: 0.0125 - val_mae: 0.0894\n",
+ "Epoch 363/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0127 - mae: 0.0894 - val_loss: 0.0126 - val_mae: 0.0904\n",
+ "Epoch 364/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0126 - mae: 0.0910 - val_loss: 0.0124 - val_mae: 0.0895\n",
+ "Epoch 365/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0121 - mae: 0.0883 - val_loss: 0.0123 - val_mae: 0.0892\n",
+ "Epoch 366/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0118 - mae: 0.0867 - val_loss: 0.0124 - val_mae: 0.0896\n",
+ "Epoch 367/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0122 - mae: 0.0872 - val_loss: 0.0121 - val_mae: 0.0881\n",
+ "Epoch 368/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0118 - mae: 0.0865 - val_loss: 0.0125 - val_mae: 0.0903\n",
+ "Epoch 369/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0131 - mae: 0.0908 - val_loss: 0.0121 - val_mae: 0.0885\n",
+ "Epoch 370/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0131 - mae: 0.0910 - val_loss: 0.0120 - val_mae: 0.0879\n",
+ "Epoch 371/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0127 - mae: 0.0897 - val_loss: 0.0129 - val_mae: 0.0906\n",
+ "Epoch 372/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0137 - mae: 0.0928 - val_loss: 0.0129 - val_mae: 0.0904\n",
+ "Epoch 373/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0128 - mae: 0.0900 - val_loss: 0.0123 - val_mae: 0.0886\n",
+ "Epoch 374/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.0125 - mae: 0.0898 - val_loss: 0.0125 - val_mae: 0.0901\n",
+ "Epoch 375/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0131 - mae: 0.0911 - val_loss: 0.0120 - val_mae: 0.0877\n",
+ "Epoch 376/500\n",
+ "10/10 [==============================] - 0s 18ms/step - loss: 0.0121 - mae: 0.0889 - val_loss: 0.0121 - val_mae: 0.0878\n",
+ "Epoch 377/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0112 - mae: 0.0845 - val_loss: 0.0125 - val_mae: 0.0889\n",
+ "Epoch 378/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0123 - mae: 0.0869 - val_loss: 0.0122 - val_mae: 0.0880\n",
+ "Epoch 379/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0123 - mae: 0.0886 - val_loss: 0.0128 - val_mae: 0.0911\n",
+ "Epoch 380/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0125 - mae: 0.0904 - val_loss: 0.0119 - val_mae: 0.0878\n",
+ "Epoch 381/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0125 - mae: 0.0897 - val_loss: 0.0124 - val_mae: 0.0897\n",
+ "Epoch 382/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0127 - mae: 0.0904 - val_loss: 0.0119 - val_mae: 0.0872\n",
+ "Epoch 383/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0125 - mae: 0.0896 - val_loss: 0.0118 - val_mae: 0.0872\n",
+ "Epoch 384/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0127 - mae: 0.0895 - val_loss: 0.0120 - val_mae: 0.0881\n",
+ "Epoch 385/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0127 - mae: 0.0897 - val_loss: 0.0120 - val_mae: 0.0884\n",
+ "Epoch 386/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0120 - mae: 0.0875 - val_loss: 0.0120 - val_mae: 0.0882\n",
+ "Epoch 387/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0124 - mae: 0.0889 - val_loss: 0.0118 - val_mae: 0.0874\n",
+ "Epoch 388/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0135 - mae: 0.0933 - val_loss: 0.0132 - val_mae: 0.0915\n",
+ "Epoch 389/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0133 - mae: 0.0926 - val_loss: 0.0125 - val_mae: 0.0892\n",
+ "Epoch 390/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0130 - mae: 0.0903 - val_loss: 0.0130 - val_mae: 0.0909\n",
+ "Epoch 391/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0126 - mae: 0.0899 - val_loss: 0.0126 - val_mae: 0.0896\n",
+ "Epoch 392/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0132 - mae: 0.0906 - val_loss: 0.0121 - val_mae: 0.0878\n",
+ "Epoch 393/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0129 - mae: 0.0902 - val_loss: 0.0122 - val_mae: 0.0887\n",
+ "Epoch 394/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0123 - mae: 0.0901 - val_loss: 0.0117 - val_mae: 0.0870\n",
+ "Epoch 395/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0126 - mae: 0.0909 - val_loss: 0.0120 - val_mae: 0.0882\n",
+ "Epoch 396/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0125 - mae: 0.0885 - val_loss: 0.0117 - val_mae: 0.0869\n",
+ "Epoch 397/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0123 - mae: 0.0885 - val_loss: 0.0120 - val_mae: 0.0883\n",
+ "Epoch 398/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0130 - mae: 0.0907 - val_loss: 0.0120 - val_mae: 0.0882\n",
+ "Epoch 399/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.0128 - mae: 0.0918 - val_loss: 0.0122 - val_mae: 0.0889\n",
+ "Epoch 400/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0124 - mae: 0.0901 - val_loss: 0.0119 - val_mae: 0.0878\n",
+ "Epoch 401/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0116 - mae: 0.0862 - val_loss: 0.0117 - val_mae: 0.0868\n",
+ "Epoch 402/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0126 - mae: 0.0900 - val_loss: 0.0119 - val_mae: 0.0878\n",
+ "Epoch 403/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0118 - mae: 0.0861 - val_loss: 0.0124 - val_mae: 0.0896\n",
+ "Epoch 404/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0125 - mae: 0.0893 - val_loss: 0.0118 - val_mae: 0.0875\n",
+ "Epoch 405/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0119 - mae: 0.0881 - val_loss: 0.0121 - val_mae: 0.0879\n",
+ "Epoch 406/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.0122 - mae: 0.0884 - val_loss: 0.0115 - val_mae: 0.0862\n",
+ "Epoch 407/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0115 - mae: 0.0864 - val_loss: 0.0121 - val_mae: 0.0880\n",
+ "Epoch 408/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0127 - mae: 0.0901 - val_loss: 0.0121 - val_mae: 0.0886\n",
+ "Epoch 409/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0123 - mae: 0.0882 - val_loss: 0.0127 - val_mae: 0.0906\n",
+ "Epoch 410/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0130 - mae: 0.0898 - val_loss: 0.0119 - val_mae: 0.0875\n",
+ "Epoch 411/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.0127 - mae: 0.0903 - val_loss: 0.0126 - val_mae: 0.0896\n",
+ "Epoch 412/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0119 - mae: 0.0872 - val_loss: 0.0115 - val_mae: 0.0864\n",
+ "Epoch 413/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0117 - mae: 0.0867 - val_loss: 0.0127 - val_mae: 0.0896\n",
+ "Epoch 414/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0117 - mae: 0.0874 - val_loss: 0.0127 - val_mae: 0.0898\n",
+ "Epoch 415/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.0134 - mae: 0.0921 - val_loss: 0.0120 - val_mae: 0.0876\n",
+ "Epoch 416/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0139 - mae: 0.0941 - val_loss: 0.0117 - val_mae: 0.0869\n",
+ "Epoch 417/500\n",
+ "10/10 [==============================] - 0s 18ms/step - loss: 0.0122 - mae: 0.0889 - val_loss: 0.0120 - val_mae: 0.0879\n",
+ "Epoch 418/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0120 - mae: 0.0868 - val_loss: 0.0120 - val_mae: 0.0882\n",
+ "Epoch 419/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0122 - mae: 0.0884 - val_loss: 0.0119 - val_mae: 0.0877\n",
+ "Epoch 420/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0123 - mae: 0.0895 - val_loss: 0.0127 - val_mae: 0.0902\n",
+ "Epoch 421/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0126 - mae: 0.0901 - val_loss: 0.0128 - val_mae: 0.0911\n",
+ "Epoch 422/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0134 - mae: 0.0921 - val_loss: 0.0117 - val_mae: 0.0868\n",
+ "Epoch 423/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0119 - mae: 0.0880 - val_loss: 0.0118 - val_mae: 0.0871\n",
+ "Epoch 424/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0127 - mae: 0.0910 - val_loss: 0.0117 - val_mae: 0.0868\n",
+ "Epoch 425/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0120 - mae: 0.0881 - val_loss: 0.0117 - val_mae: 0.0869\n",
+ "Epoch 426/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0127 - mae: 0.0896 - val_loss: 0.0118 - val_mae: 0.0870\n",
+ "Epoch 427/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0117 - mae: 0.0870 - val_loss: 0.0116 - val_mae: 0.0865\n",
+ "Epoch 428/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0126 - mae: 0.0909 - val_loss: 0.0119 - val_mae: 0.0874\n",
+ "Epoch 429/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0115 - mae: 0.0848 - val_loss: 0.0119 - val_mae: 0.0877\n",
+ "Epoch 430/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0118 - mae: 0.0878 - val_loss: 0.0122 - val_mae: 0.0883\n",
+ "Epoch 431/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0123 - mae: 0.0889 - val_loss: 0.0118 - val_mae: 0.0871\n",
+ "Epoch 432/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0124 - mae: 0.0885 - val_loss: 0.0120 - val_mae: 0.0878\n",
+ "Epoch 433/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0124 - mae: 0.0891 - val_loss: 0.0116 - val_mae: 0.0863\n",
+ "Epoch 434/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0117 - mae: 0.0879 - val_loss: 0.0119 - val_mae: 0.0877\n",
+ "Epoch 435/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0124 - mae: 0.0891 - val_loss: 0.0126 - val_mae: 0.0901\n",
+ "Epoch 436/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0125 - mae: 0.0887 - val_loss: 0.0126 - val_mae: 0.0901\n",
+ "Epoch 437/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0129 - mae: 0.0913 - val_loss: 0.0123 - val_mae: 0.0886\n",
+ "Epoch 438/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0120 - mae: 0.0868 - val_loss: 0.0116 - val_mae: 0.0868\n",
+ "Epoch 439/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0128 - mae: 0.0894 - val_loss: 0.0132 - val_mae: 0.0911\n",
+ "Epoch 440/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0111 - mae: 0.0849 - val_loss: 0.0115 - val_mae: 0.0865\n",
+ "Epoch 441/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0121 - mae: 0.0866 - val_loss: 0.0118 - val_mae: 0.0875\n",
+ "Epoch 442/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0116 - mae: 0.0868 - val_loss: 0.0119 - val_mae: 0.0875\n",
+ "Epoch 443/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0118 - mae: 0.0861 - val_loss: 0.0124 - val_mae: 0.0891\n",
+ "Epoch 444/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0125 - mae: 0.0883 - val_loss: 0.0121 - val_mae: 0.0883\n",
+ "Epoch 445/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0114 - mae: 0.0854 - val_loss: 0.0122 - val_mae: 0.0884\n",
+ "Epoch 446/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0126 - mae: 0.0893 - val_loss: 0.0116 - val_mae: 0.0866\n",
+ "Epoch 447/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0125 - mae: 0.0879 - val_loss: 0.0122 - val_mae: 0.0885\n",
+ "Epoch 448/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0121 - mae: 0.0878 - val_loss: 0.0117 - val_mae: 0.0868\n",
+ "Epoch 449/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0113 - mae: 0.0865 - val_loss: 0.0117 - val_mae: 0.0866\n",
+ "Epoch 450/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0112 - mae: 0.0855 - val_loss: 0.0133 - val_mae: 0.0930\n",
+ "Epoch 451/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0137 - mae: 0.0931 - val_loss: 0.0121 - val_mae: 0.0883\n",
+ "Epoch 452/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0117 - mae: 0.0861 - val_loss: 0.0114 - val_mae: 0.0862\n",
+ "Epoch 453/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0113 - mae: 0.0855 - val_loss: 0.0117 - val_mae: 0.0870\n",
+ "Epoch 454/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0135 - mae: 0.0928 - val_loss: 0.0118 - val_mae: 0.0870\n",
+ "Epoch 455/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0125 - mae: 0.0884 - val_loss: 0.0114 - val_mae: 0.0860\n",
+ "Epoch 456/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0125 - mae: 0.0904 - val_loss: 0.0117 - val_mae: 0.0869\n",
+ "Epoch 457/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0124 - mae: 0.0883 - val_loss: 0.0114 - val_mae: 0.0862\n",
+ "Epoch 458/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0122 - mae: 0.0873 - val_loss: 0.0117 - val_mae: 0.0869\n",
+ "Epoch 459/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0122 - mae: 0.0887 - val_loss: 0.0116 - val_mae: 0.0865\n",
+ "Epoch 460/500\n",
+ "10/10 [==============================] - 0s 5ms/step - loss: 0.0125 - mae: 0.0894 - val_loss: 0.0118 - val_mae: 0.0874\n",
+ "Epoch 461/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0115 - mae: 0.0857 - val_loss: 0.0115 - val_mae: 0.0863\n",
+ "Epoch 462/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0115 - mae: 0.0862 - val_loss: 0.0117 - val_mae: 0.0874\n",
+ "Epoch 463/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0118 - mae: 0.0880 - val_loss: 0.0119 - val_mae: 0.0876\n",
+ "Epoch 464/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0132 - mae: 0.0928 - val_loss: 0.0116 - val_mae: 0.0865\n",
+ "Epoch 465/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0135 - mae: 0.0922 - val_loss: 0.0116 - val_mae: 0.0865\n",
+ "Epoch 466/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0121 - mae: 0.0885 - val_loss: 0.0115 - val_mae: 0.0863\n",
+ "Epoch 467/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0117 - mae: 0.0868 - val_loss: 0.0116 - val_mae: 0.0871\n",
+ "Epoch 468/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0117 - mae: 0.0861 - val_loss: 0.0117 - val_mae: 0.0872\n",
+ "Epoch 469/500\n",
+ "10/10 [==============================] - 0s 17ms/step - loss: 0.0121 - mae: 0.0896 - val_loss: 0.0115 - val_mae: 0.0863\n",
+ "Epoch 470/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0123 - mae: 0.0896 - val_loss: 0.0125 - val_mae: 0.0895\n",
+ "Epoch 471/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0126 - mae: 0.0916 - val_loss: 0.0114 - val_mae: 0.0862\n",
+ "Epoch 472/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0113 - mae: 0.0854 - val_loss: 0.0114 - val_mae: 0.0861\n",
+ "Epoch 473/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0116 - mae: 0.0862 - val_loss: 0.0129 - val_mae: 0.0904\n",
+ "Epoch 474/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0138 - mae: 0.0954 - val_loss: 0.0127 - val_mae: 0.0901\n",
+ "Epoch 475/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0134 - mae: 0.0923 - val_loss: 0.0118 - val_mae: 0.0877\n",
+ "Epoch 476/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0121 - mae: 0.0877 - val_loss: 0.0115 - val_mae: 0.0862\n",
+ "Epoch 477/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0117 - mae: 0.0865 - val_loss: 0.0117 - val_mae: 0.0874\n",
+ "Epoch 478/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0130 - mae: 0.0899 - val_loss: 0.0113 - val_mae: 0.0859\n",
+ "Epoch 479/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0131 - mae: 0.0907 - val_loss: 0.0115 - val_mae: 0.0864\n",
+ "Epoch 480/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0122 - mae: 0.0877 - val_loss: 0.0118 - val_mae: 0.0877\n",
+ "Epoch 481/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0119 - mae: 0.0866 - val_loss: 0.0115 - val_mae: 0.0864\n",
+ "Epoch 482/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0118 - mae: 0.0874 - val_loss: 0.0115 - val_mae: 0.0866\n",
+ "Epoch 483/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0121 - mae: 0.0873 - val_loss: 0.0123 - val_mae: 0.0890\n",
+ "Epoch 484/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0127 - mae: 0.0898 - val_loss: 0.0116 - val_mae: 0.0868\n",
+ "Epoch 485/500\n",
+ "10/10 [==============================] - 0s 9ms/step - loss: 0.0112 - mae: 0.0845 - val_loss: 0.0123 - val_mae: 0.0890\n",
+ "Epoch 486/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0123 - mae: 0.0876 - val_loss: 0.0114 - val_mae: 0.0860\n",
+ "Epoch 487/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0116 - mae: 0.0852 - val_loss: 0.0118 - val_mae: 0.0873\n",
+ "Epoch 488/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0114 - mae: 0.0859 - val_loss: 0.0114 - val_mae: 0.0859\n",
+ "Epoch 489/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0117 - mae: 0.0871 - val_loss: 0.0130 - val_mae: 0.0917\n",
+ "Epoch 490/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0135 - mae: 0.0933 - val_loss: 0.0131 - val_mae: 0.0920\n",
+ "Epoch 491/500\n",
+ "10/10 [==============================] - 0s 8ms/step - loss: 0.0120 - mae: 0.0879 - val_loss: 0.0119 - val_mae: 0.0881\n",
+ "Epoch 492/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0115 - mae: 0.0859 - val_loss: 0.0115 - val_mae: 0.0863\n",
+ "Epoch 493/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0113 - mae: 0.0854 - val_loss: 0.0114 - val_mae: 0.0862\n",
+ "Epoch 494/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0114 - mae: 0.0866 - val_loss: 0.0116 - val_mae: 0.0868\n",
+ "Epoch 495/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0119 - mae: 0.0875 - val_loss: 0.0113 - val_mae: 0.0860\n",
+ "Epoch 496/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0118 - mae: 0.0861 - val_loss: 0.0114 - val_mae: 0.0863\n",
+ "Epoch 497/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0107 - mae: 0.0818 - val_loss: 0.0115 - val_mae: 0.0864\n",
+ "Epoch 498/500\n",
+ "10/10 [==============================] - 0s 7ms/step - loss: 0.0123 - mae: 0.0894 - val_loss: 0.0114 - val_mae: 0.0862\n",
+ "Epoch 499/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0126 - mae: 0.0895 - val_loss: 0.0113 - val_mae: 0.0857\n",
+ "Epoch 500/500\n",
+ "10/10 [==============================] - 0s 6ms/step - loss: 0.0121 - mae: 0.0882 - val_loss: 0.0115 - val_mae: 0.0865\n"
+ ],
+ "name": "stdout"
+ },
+ {
+ "output_type": "stream",
+ "text": [
+ "/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/training.py:2325: UserWarning: `Model.state_updates` will be removed in a future version. This property should not be used in TensorFlow 2.0, as `updates` are applied automatically.\n",
+ " warnings.warn('`Model.state_updates` will be removed in a future version. '\n",
+ "/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/base_layer.py:1397: UserWarning: `layer.updates` will be removed in a future version. This property should not be used in TensorFlow 2.0, as `updates` are applied automatically.\n",
+ " warnings.warn('`layer.updates` will be removed in a future version. '\n"
+ ],
+ "name": "stderr"
+ },
+ {
+ "output_type": "stream",
+ "text": [
+ "WARNING:tensorflow:FOR KERAS USERS: The object that you are saving contains one or more Keras models or layers. If you are loading the SavedModel with `tf.keras.models.load_model`, continue reading (otherwise, you may ignore the following instructions). Please change your code to save with `tf.keras.models.save_model` or `model.save`, and confirm that the file \"keras.metadata\" exists in the export directory. In the future, Keras will only load the SavedModels that have this file. In other words, `tf.saved_model.save` will no longer write SavedModels that can be recovered as Keras models (this will apply in TF 2.5).\n",
+ "\n",
+ "FOR DEVS: If you are overwriting _tracking_metadata in your class, this property has been used to save metadata in the SavedModel. The metadta field will be deprecated soon, so please move the metadata to a different file.\n",
+ "INFO:tensorflow:Assets written to: models/model/assets\n"
+ ],
+ "name": "stdout"
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "Mc_CQu2_IvOP"
+ },
+ "source": [
+ "### 3. Plot Metrics\n",
+ "Each training epoch, the model prints out its loss and mean absolute error for training and validation. You can read this in the output above (note that your exact numbers may differ): \n",
+ "\n",
+ "```\n",
+ "Epoch 500/500\n",
+ "10/10 [==============================] - 0s 10ms/step - loss: 0.0121 - mae: 0.0882 - val_loss: 0.0115 - val_mae: 0.0865\n",
+ "```\n",
+ "\n",
+ "You can see that we've already got a huge improvement - validation loss has dropped from 0.15 to 0.01, and validation MAE has dropped from 0.33 to 0.08.\n",
+ "\n",
+ "The following cell will print the same graphs we used to evaluate our original model, but showing our new training history:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "SYHGswAJJgrC",
+ "outputId": "0b4baed5-9565-45c7-9fcc-2fd59a86d438",
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 297
+ }
+ },
+ "source": [
+ "# Draw a graph of the loss, which is the distance between\n",
+ "# the predicted and actual values during training and validation.\n",
+ "train_loss = history.history['loss']\n",
+ "val_loss = history.history['val_loss']\n",
+ "\n",
+ "epochs = range(1, len(train_loss) + 1)\n",
+ "\n",
+ "# Exclude the first few epochs so the graph is easier to read\n",
+ "SKIP = 100\n",
+ "\n",
+ "plt.figure(figsize=(10, 4))\n",
+ "plt.subplot(1, 2, 1)\n",
+ "\n",
+ "plt.plot(epochs[SKIP:], train_loss[SKIP:], 'g.', label='Training loss')\n",
+ "plt.plot(epochs[SKIP:], val_loss[SKIP:], 'b.', label='Validation loss')\n",
+ "plt.title('Training and validation loss')\n",
+ "plt.xlabel('Epochs')\n",
+ "plt.ylabel('Loss')\n",
+ "plt.legend()\n",
+ "\n",
+ "plt.subplot(1, 2, 2)\n",
+ "\n",
+ "# Draw a graph of mean absolute error, which is another way of\n",
+ "# measuring the amount of error in the prediction.\n",
+ "train_mae = history.history['mae']\n",
+ "val_mae = history.history['val_mae']\n",
+ "\n",
+ "plt.plot(epochs[SKIP:], train_mae[SKIP:], 'g.', label='Training MAE')\n",
+ "plt.plot(epochs[SKIP:], val_mae[SKIP:], 'b.', label='Validation MAE')\n",
+ "plt.title('Training and validation mean absolute error')\n",
+ "plt.xlabel('Epochs')\n",
+ "plt.ylabel('MAE')\n",
+ "plt.legend()\n",
+ "\n",
+ "plt.tight_layout()"
+ ],
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "display_data",
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "tags": [],
+ "needs_background": "light"
+ }
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "f86dWOyZKmN9"
+ },
+ "source": [
+ "Great results! From these graphs, we can see several exciting things:\n",
+ "\n",
+ "* The overall loss and MAE are much better than our previous network\n",
+ "* Metrics are better for validation than training, which means the network is not overfitting\n",
+ "\n",
+ "The reason the metrics for validation are better than those for training is that validation metrics are calculated at the end of each epoch, while training metrics are calculated throughout the epoch, so validation happens on a model that has been trained slightly longer.\n",
+ "\n",
+ "This all means our network seems to be performing well! To confirm, let's check its predictions against the test dataset we set aside earlier:\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "lZfztKKyhLxX",
+ "outputId": "f48f33ad-aba0-4c62-ba15-cc742bd23805",
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 299
+ }
+ },
+ "source": [
+ "# Calculate and print the loss on our test dataset\n",
+ "test_loss, test_mae = model.evaluate(x_test, y_test)\n",
+ "\n",
+ "# Make predictions based on our test dataset\n",
+ "y_test_pred = model.predict(x_test)\n",
+ "\n",
+ "# Graph the predictions against the actual values\n",
+ "plt.clf()\n",
+ "plt.title('Comparison of predictions and actual values')\n",
+ "plt.plot(x_test, y_test, 'b.', label='Actual values')\n",
+ "plt.plot(x_test, y_test_pred, 'r.', label='TF predicted')\n",
+ "plt.legend()\n",
+ "plt.show()"
+ ],
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "text": [
+ "7/7 [==============================] - 0s 2ms/step - loss: 0.0102 - mae: 0.0815\n"
+ ],
+ "name": "stdout"
+ },
+ {
+ "output_type": "display_data",
+ "data": {
+ "image/png": "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/fgVpb1RC19RFCVLUMFXFEXJEtSloyiKkiWoha8oipIlpGwCqq5du5pevXoluxmKoihpxfr16/9tjOkWa13KCn6vXr1Yt25dspuhKIqSVohI3JHU6tJRFEXJElTwFUVRsgQVfEVRlCwhZX34iqKkBjU1NezYsYO9e/cmuylKBPn5+fTo0YPc3NymC7uo4CuK0ig7duzgwAMPpFevXsSY90ZJAsYYKisr2bFjB8ccc0zTG7ioS0dRlEbZu3cvBQUFKvYphIhQUFDQ4qcuFfwMJRCAKVPsu6K0FRX71KM110RdOhlIIABDhkB1NeTlQUUFOE6yW6UoSrJRCz8D8fut2AeD9t3vT3aLFKXtLFmyBBHhn/9senqF6dOn8+233zZZLh6PPfYY48aNa/X2ia4nUajgZyA+n7XsvV777vMlu0WK0nYWLlzIwIEDWbhwYZNl2yr4mYoKfgbiONaNc/fdzXPnqL9fSTSJ/k19/fXXrF69mjlz5vDkk/UzZgaDQW677TZOPvlkTjnlFGbMmMGf/vQnPvroI8455xzOOeccADp37ly3zTPPPMPIkSMBWLp0KWeccQb9+vXjvPPO45NPPonbhlAoRK9evfjiiy/qlh133HF88sknzapn5MiRPPPMM3XfI9t07733cvrpp3PKKadw5513AvDNN99w4YUX0qdPH04++WSeeuqpfepsKerDz1Acp3l++9b4+wMB6yby+bRvQNmX9uhDeu655zj//PM5/vjjKSgoYP369Zx22mmUlZWxfft2Nm7cSE5ODp999hmHHnoof/jDH1ixYgVdu3ZttN6BAwfy6quvIiLMnj2b0tJSfv/738cs6/F4uPTSS1m8eDHXX389r732GkcffTSHHXZYi+qJZtmyZbzzzju8/vrrGGO45JJLWLlyJbt376Z79+68+OKLAHz55ZctO2kxUMHPcqL9/eXljYu5dggrTRGrD6mtv5GFCxdyyy23APDjH/+YhQsXctppp7F8+XLGjBlDTo6VskMPPbRF9e7YsYMrr7ySXbt2UV1d3WRM+5VXXsldd93F9ddfz5NPPsmVV17ZqnoiWbZsGcuWLaNfv36AfZp55513GDRoELfeeiuTJk3ioosuYtCgQS06tlioSyfL8flgFGX8L8O40ZQxdy7ccYcV9ViP4411CKtrSIHE9yF99tlnvPzyy9x444306tWL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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "tags": [],
+ "needs_background": "light"
+ }
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "3h7IcvuOOS4J"
+ },
+ "source": [
+ "Much better! The evaluation metrics we printed show that the model has a low loss and MAE on the test data, and the predictions line up visually with our data fairly well.\n",
+ "\n",
+ "The model isn't perfect; its predictions don't form a smooth sine curve. For instance, the line is almost straight when `x` is between 4.2 and 5.2. If we wanted to go further, we could try further increasing the capacity of the model, perhaps using some techniques to defend from overfitting.\n",
+ "\n",
+ "However, an important part of machine learning is *knowing when to stop*. This model is good enough for our use case - which is to make some LEDs blink in a pleasing pattern.\n",
+ "\n",
+ "## Generate a TensorFlow Lite Model"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "sHe-Wv47rhm8"
+ },
+ "source": [
+ "### 1. Generate Models with or without Quantization\n",
+ "We now have an acceptably accurate model. We'll use the [TensorFlow Lite Converter](https://www.tensorflow.org/lite/convert) to convert the model into a special, space-efficient format for use on memory-constrained devices.\n",
+ "\n",
+ "Since this model is going to be deployed on a microcontroller, we want it to be as tiny as possible! One technique for reducing the size of a model is called [quantization](https://www.tensorflow.org/lite/performance/post_training_quantization). It reduces the precision of the model's weights, and possibly the activations (output of each layer) as well, which saves memory, often without much impact on accuracy. Quantized models also run faster, since the calculations required are simpler.\n",
+ "\n",
+ "In the following cell, we'll convert the model twice: once with quantization, once without."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "1muAoUm8lSXL",
+ "outputId": "aad8259e-df57-4f03-da77-d490e5609d9f",
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ }
+ },
+ "source": [
+ "# Convert the model to the TensorFlow Lite format without quantization\n",
+ "converter = tf.lite.TFLiteConverter.from_saved_model(MODEL_TF)\n",
+ "model_no_quant_tflite = converter.convert()\n",
+ "\n",
+ "# Save the model to disk\n",
+ "open(MODEL_NO_QUANT_TFLITE, \"wb\").write(model_no_quant_tflite)\n",
+ "\n",
+ "# Convert the model to the TensorFlow Lite format with quantization\n",
+ "def representative_dataset():\n",
+ " for i in range(500):\n",
+ " yield([x_train[i].reshape(1, 1)])\n",
+ "# Set the optimization flag.\n",
+ "converter.optimizations = [tf.lite.Optimize.DEFAULT]\n",
+ "# Enforce integer only quantization\n",
+ "converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]\n",
+ "converter.inference_input_type = tf.int8\n",
+ "converter.inference_output_type = tf.int8\n",
+ "# Provide a representative dataset to ensure we quantize correctly.\n",
+ "converter.representative_dataset = representative_dataset\n",
+ "model_tflite = converter.convert()\n",
+ "\n",
+ "# Save the model to disk\n",
+ "open(MODEL_TFLITE, \"wb\").write(model_tflite)"
+ ],
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/plain": [
+ "2488"
+ ]
+ },
+ "metadata": {
+ "tags": []
+ },
+ "execution_count": 17
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "L_vE-ZDkHVxe"
+ },
+ "source": [
+ "### 2. Compare Model Performance\n",
+ "\n",
+ "To prove these models are accurate even after conversion and quantization, we'll compare their predictions and loss on our test dataset.\n",
+ "\n",
+ "**Helper functions**\n",
+ "\n",
+ "We define the `predict` (for predictions) and `evaluate` (for loss) functions for TFLite models. *Note: These are already included in a TF model, but not in a TFLite model.*"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "NKtmxEhko1S1",
+ "cellView": "code"
+ },
+ "source": [
+ "def predict_tflite(tflite_model, x_test):\n",
+ " # Prepare the test data\n",
+ " x_test_ = x_test.copy()\n",
+ " x_test_ = x_test_.reshape((x_test.size, 1))\n",
+ " x_test_ = x_test_.astype(np.float32)\n",
+ "\n",
+ " # Initialize the TFLite interpreter\n",
+ " interpreter = tf.lite.Interpreter(model_content=tflite_model)\n",
+ " interpreter.allocate_tensors()\n",
+ "\n",
+ " input_details = interpreter.get_input_details()[0]\n",
+ " output_details = interpreter.get_output_details()[0]\n",
+ "\n",
+ " # If required, quantize the input layer (from float to integer)\n",
+ " input_scale, input_zero_point = input_details[\"quantization\"]\n",
+ " if (input_scale, input_zero_point) != (0.0, 0):\n",
+ " x_test_ = x_test_ / input_scale + input_zero_point\n",
+ " x_test_ = x_test_.astype(input_details[\"dtype\"])\n",
+ " \n",
+ " # Invoke the interpreter\n",
+ " y_pred = np.empty(x_test_.size, dtype=output_details[\"dtype\"])\n",
+ " for i in range(len(x_test_)):\n",
+ " interpreter.set_tensor(input_details[\"index\"], [x_test_[i]])\n",
+ " interpreter.invoke()\n",
+ " y_pred[i] = interpreter.get_tensor(output_details[\"index\"])[0]\n",
+ " \n",
+ " # If required, dequantized the output layer (from integer to float)\n",
+ " output_scale, output_zero_point = output_details[\"quantization\"]\n",
+ " if (output_scale, output_zero_point) != (0.0, 0):\n",
+ " y_pred = y_pred.astype(np.float32)\n",
+ " y_pred = (y_pred - output_zero_point) * output_scale\n",
+ "\n",
+ " return y_pred\n",
+ "\n",
+ "def evaluate_tflite(tflite_model, x_test, y_true):\n",
+ " global model\n",
+ " y_pred = predict_tflite(tflite_model, x_test)\n",
+ " loss_function = tf.keras.losses.get(model.loss)\n",
+ " loss = loss_function(y_true, y_pred).numpy()\n",
+ " return loss"
+ ],
+ "execution_count": null,
+ "outputs": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "pLZLY0D4gl6U"
+ },
+ "source": [
+ "**1. Predictions**"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "0RS3zni1gkrt"
+ },
+ "source": [
+ "# Calculate predictions\n",
+ "y_test_pred_tf = model.predict(x_test)\n",
+ "y_test_pred_no_quant_tflite = predict_tflite(model_no_quant_tflite, x_test)\n",
+ "y_test_pred_tflite = predict_tflite(model_tflite, x_test)"
+ ],
+ "execution_count": null,
+ "outputs": []
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "-J7IKlXiYVPz",
+ "outputId": "24017e5e-7672-460c-8b76-c0ed71f3ec27",
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 281
+ }
+ },
+ "source": [
+ "# Compare predictions\n",
+ "plt.clf()\n",
+ "plt.title('Comparison of various models against actual values')\n",
+ "plt.plot(x_test, y_test, 'bo', label='Actual values')\n",
+ "plt.plot(x_test, y_test_pred_tf, 'ro', label='TF predictions')\n",
+ "plt.plot(x_test, y_test_pred_no_quant_tflite, 'bx', label='TFLite predictions')\n",
+ "plt.plot(x_test, y_test_pred_tflite, 'gx', label='TFLite quantized predictions')\n",
+ "plt.legend()\n",
+ "plt.show()"
+ ],
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "display_data",
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "tags": [],
+ "needs_background": "light"
+ }
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "V7vlfJqbiZMU"
+ },
+ "source": [
+ "**2. Loss (MSE/Mean Squared Error)**"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "IpHifyGZRhw8"
+ },
+ "source": [
+ "# Calculate loss\n",
+ "loss_tf, _ = model.evaluate(x_test, y_test, verbose=0)\n",
+ "loss_no_quant_tflite = evaluate_tflite(model_no_quant_tflite, x_test, y_test)\n",
+ "loss_tflite = evaluate_tflite(model_tflite, x_test, y_test)"
+ ],
+ "execution_count": null,
+ "outputs": []
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "g3HLT0UOjTY_",
+ "outputId": "0c1c279a-96bd-4e8d-8a65-6a071376825b",
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 171
+ }
+ },
+ "source": [
+ "# Compare loss\n",
+ "df = pd.DataFrame.from_records(\n",
+ " [[\"TensorFlow\", loss_tf],\n",
+ " [\"TensorFlow Lite\", loss_no_quant_tflite],\n",
+ " [\"TensorFlow Lite Quantized\", loss_tflite]],\n",
+ " columns = [\"Model\", \"Loss/MSE\"], index=\"Model\").round(4)\n",
+ "df"
+ ],
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " Loss/MSE \n",
+ " \n",
+ " \n",
+ " Model \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " TensorFlow \n",
+ " 0.0102 \n",
+ " \n",
+ " \n",
+ " TensorFlow Lite \n",
+ " 0.0102 \n",
+ " \n",
+ " \n",
+ " TensorFlow Lite Quantized \n",
+ " 0.0108 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " Loss/MSE\n",
+ "Model \n",
+ "TensorFlow 0.0102\n",
+ "TensorFlow Lite 0.0102\n",
+ "TensorFlow Lite Quantized 0.0108"
+ ]
+ },
+ "metadata": {
+ "tags": []
+ },
+ "execution_count": 31
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "E7Vjw7VckLu1"
+ },
+ "source": [
+ "**3. Size**"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "wEXiJ8dFkL2R"
+ },
+ "source": [
+ "# Calculate size\n",
+ "size_tf = os.path.getsize(MODEL_TF)\n",
+ "size_no_quant_tflite = os.path.getsize(MODEL_NO_QUANT_TFLITE)\n",
+ "size_tflite = os.path.getsize(MODEL_TFLITE)"
+ ],
+ "execution_count": null,
+ "outputs": []
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "8DdsCaL7kL4u",
+ "outputId": "9644f10d-0914-4939-b596-facb90e4b961",
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 171
+ }
+ },
+ "source": [
+ "# Compare size\n",
+ "pd.DataFrame.from_records(\n",
+ " [[\"TensorFlow\", f\"{size_tf} bytes\", \"\"],\n",
+ " [\"TensorFlow Lite\", f\"{size_no_quant_tflite} bytes \", f\"(reduced by {size_tf - size_no_quant_tflite} bytes)\"],\n",
+ " [\"TensorFlow Lite Quantized\", f\"{size_tflite} bytes\", f\"(reduced by {size_no_quant_tflite - size_tflite} bytes)\"]],\n",
+ " columns = [\"Model\", \"Size\", \"\"], index=\"Model\")"
+ ],
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " Size \n",
+ " \n",
+ " \n",
+ " \n",
+ " Model \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " TensorFlow \n",
+ " 4096 bytes \n",
+ " \n",
+ " \n",
+ " \n",
+ " TensorFlow Lite \n",
+ " 2788 bytes \n",
+ " (reduced by 1308 bytes) \n",
+ " \n",
+ " \n",
+ " TensorFlow Lite Quantized \n",
+ " 2488 bytes \n",
+ " (reduced by 300 bytes) \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " Size \n",
+ "Model \n",
+ "TensorFlow 4096 bytes \n",
+ "TensorFlow Lite 2788 bytes (reduced by 1308 bytes)\n",
+ "TensorFlow Lite Quantized 2488 bytes (reduced by 300 bytes)"
+ ]
+ },
+ "metadata": {
+ "tags": []
+ },
+ "execution_count": 33
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "qXdmfo7imGMB"
+ },
+ "source": [
+ "**Summary**"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "R1LVMA2nkM_l"
+ },
+ "source": [
+ "We can see from the predictions (graph) and loss (table) that the original TF model, the TFLite model, and the quantized TFLite model are all close enough to be indistinguishable - even though they differ in size (table). This implies that the quantized (smallest) model is ready to use!\n",
+ "\n",
+ "*Note: The quantized (integer) TFLite model is just 300 bytes smaller than the original (float) TFLite model - a tiny reduction in size! This is because the model is already so small that quantization has little effect. Complex models with more weights, can have upto a 4x reduction in size!*"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "HPSFmDL7pv2L"
+ },
+ "source": [
+ "## Generate a TensorFlow Lite for Microcontrollers Model\n",
+ "Convert the TensorFlow Lite quantized model into a C source file that can be loaded by TensorFlow Lite for Microcontrollers."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "j1FB4ieeg0lw",
+ "outputId": "c25b75c6-a28d-47b1-9b3a-b7ba821ee310",
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ }
+ },
+ "source": [
+ "# Install xxd if it is not available\n",
+ "!apt-get update && apt-get -qq install xxd\n",
+ "# Convert to a C source file, i.e, a TensorFlow Lite for Microcontrollers model\n",
+ "!xxd -i {MODEL_TFLITE} > {MODEL_TFLITE_MICRO}\n",
+ "# Update variable names\n",
+ "REPLACE_TEXT = MODEL_TFLITE.replace('/', '_').replace('.', '_')\n",
+ "!sed -i 's/'{REPLACE_TEXT}'/g_model/g' {MODEL_TFLITE_MICRO}"
+ ],
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "text": [
+ "\r0% [Working]\r \rIgn:1 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64 InRelease\n",
+ "\r0% [Waiting for headers] [Waiting for headers] [Waiting for headers] [Waiting f\r \rHit:2 https://cloud.r-project.org/bin/linux/ubuntu bionic-cran40/ InRelease\n",
+ "\r0% [Waiting for headers] [Waiting for headers] [Waiting for headers] [Waiting f\r0% [2 InRelease gpgv 3,626 B] [Waiting for headers] [Waiting for headers] [Wait\r \rIgn:3 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64 InRelease\n",
+ "\r0% [2 InRelease gpgv 3,626 B] [Waiting for headers] [Waiting for headers] [Wait\r \rHit:4 http://ppa.launchpad.net/c2d4u.team/c2d4u4.0+/ubuntu bionic InRelease\n",
+ "\r0% [2 InRelease gpgv 3,626 B] [Waiting for headers] [Waiting for headers] [Conn\r \rHit:5 http://archive.ubuntu.com/ubuntu bionic InRelease\n",
+ "\r0% [2 InRelease gpgv 3,626 B] [Waiting for headers] [Waiting for headers] [Conn\r \rHit:6 http://security.ubuntu.com/ubuntu bionic-security InRelease\n",
+ "Hit:7 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64 Release\n",
+ "Hit:8 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64 Release\n",
+ "Hit:9 http://archive.ubuntu.com/ubuntu bionic-updates InRelease\n",
+ "Hit:10 http://ppa.launchpad.net/graphics-drivers/ppa/ubuntu bionic InRelease\n",
+ "Hit:11 http://archive.ubuntu.com/ubuntu bionic-backports InRelease\n",
+ "Reading package lists... Done\n"
+ ],
+ "name": "stdout"
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "JvRy0ZyMhQOX"
+ },
+ "source": [
+ "## Deploy to a Microcontroller\n",
+ "\n",
+ "Follow the instructions in the [hello_world](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/examples/hello_world) README.md for [TensorFlow Lite for MicroControllers](https://www.tensorflow.org/lite/microcontrollers/overview) to deploy this model on a specific microcontroller.\n",
+ "\n",
+ "**Reference Model:** If you have not modified this notebook, you can follow the instructions as is, to deploy the model. Refer to the [`hello_world/train/models`](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/examples/hello_world/train/models) directory to access the models generated in this notebook.\n",
+ "\n",
+ "**New Model:** If you have generated a new model, then update the values assigned to the variables defined in [`hello_world/model.cc`](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/examples/hello_world/model.cc) with values displayed after running the following cell."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "id": "l4-WhtGpvb-E",
+ "outputId": "4c7925a5-4cf3-4f7a-fcbc-c8c2857423ea",
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ }
+ },
+ "source": [
+ "# Print the C source file\n",
+ "!cat {MODEL_TFLITE_MICRO}"
+ ],
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "text": [
+ "unsigned char g_model[] = {\n",
+ " 0x1c, 0x00, 0x00, 0x00, 0x54, 0x46, 0x4c, 0x33, 0x14, 0x00, 0x20, 0x00,\n",
+ " 0x1c, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00,\n",
+ " 0x08, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,\n",
+ " 0x98, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x1c, 0x03, 0x00, 0x00,\n",
+ " 0x2c, 0x03, 0x00, 0x00, 0x30, 0x09, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n",
+ " 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x60, 0xf7, 0xff, 0xff,\n",
+ " 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,\n",
+ " 0x44, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x73, 0x65, 0x72, 0x76,\n",
+ " 0x65, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x73, 0x65, 0x72, 0x76,\n",
+ " 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00,\n",
+ " 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xbc, 0xff, 0xff, 0xff,\n",
+ " 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n",
+ " 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x34, 0x00, 0x01, 0x00, 0x00, 0x00,\n",
+ " 0x04, 0x00, 0x00, 0x00, 0x76, 0xfd, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00,\n",
+ " 0x0d, 0x00, 0x00, 0x00, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x32, 0x5f,\n",
+ " 0x69, 0x6e, 0x70, 0x75, 0x74, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n",
+ " 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00,\n",
+ " 0x08, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n",
+ " 0x13, 0x00, 0x00, 0x00, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x75, 0x6e, 0x74,\n",
+ " 0x69, 0x6d, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00,\n",
+ " 0x0c, 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x48, 0x02, 0x00, 0x00,\n",
+ " 0x34, 0x02, 0x00, 0x00, 0xdc, 0x01, 0x00, 0x00, 0x8c, 0x01, 0x00, 0x00,\n",
+ " 0x6c, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00,\n",
+ " 0x34, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,\n",
+ " 0x04, 0x00, 0x00, 0x00, 0xfa, 0xfd, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00,\n",
+ " 0x10, 0x00, 0x00, 0x00, 0x31, 0x2e, 0x35, 0x2e, 0x30, 0x00, 0x00, 0x00,\n",
+ " 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0xfd, 0xff, 0xff,\n",
+ " 0x88, 0xfd, 0xff, 0xff, 0x8c, 0xfd, 0xff, 0xff, 0x22, 0xfe, 0xff, 0xff,\n",
+ " 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x21, 0xa5, 0x8b, 0xca,\n",
+ " 0x5e, 0x1d, 0xce, 0x42, 0x9d, 0xce, 0x1f, 0xb0, 0xdf, 0x54, 0x2f, 0x81,\n",
+ " 0x3e, 0xfe, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,\n",
+ " 0xee, 0xfc, 0x00, 0xec, 0x05, 0x17, 0xef, 0xec, 0xe6, 0xf8, 0x03, 0x01,\n",
+ " 0x00, 0xfa, 0xf8, 0xf5, 0xdc, 0xeb, 0x27, 0x14, 0xf1, 0xde, 0xe2, 0xdb,\n",
+ " 0xf0, 0xde, 0x31, 0x06, 0x02, 0xe6, 0xee, 0xf9, 0x00, 0x16, 0x07, 0xe0,\n",
+ " 0xfe, 0xff, 0xe9, 0x06, 0xe7, 0xef, 0x81, 0x1b, 0x18, 0xea, 0xc9, 0x01,\n",
+ " 0x0f, 0x00, 0xda, 0xf7, 0x0e, 0xec, 0x13, 0x1f, 0x04, 0x13, 0xb4, 0xe6,\n",
+ " 0xfd, 0x06, 0xb9, 0xe0, 0x0d, 0xec, 0xf0, 0xde, 0xeb, 0xf7, 0x05, 0x26,\n",
+ " 0x1a, 0xe4, 0x6f, 0x1a, 0xea, 0x1e, 0x35, 0xdf, 0x1a, 0xf3, 0xf1, 0x19,\n",
+ " 0x0f, 0x03, 0x1b, 0xe1, 0xde, 0x13, 0xf6, 0x19, 0xff, 0xf6, 0x1b, 0x18,\n",
+ " 0xf0, 0x1c, 0xda, 0x1b, 0x1b, 0x20, 0xe5, 0x1a, 0xf5, 0xff, 0x96, 0x0b,\n",
+ " 0x00, 0x01, 0xcd, 0xde, 0x0d, 0xf6, 0x16, 0xe3, 0xed, 0xfc, 0x0e, 0xe9,\n",
+ " 0xfa, 0xeb, 0x5c, 0xfc, 0x1d, 0x02, 0x5b, 0xe2, 0xe1, 0xf5, 0x15, 0xec,\n",
+ " 0xf4, 0x00, 0x13, 0x05, 0xec, 0x0c, 0x1d, 0x14, 0x0e, 0xe7, 0x0b, 0xf4,\n",
+ " 0x19, 0x00, 0xd7, 0x05, 0x27, 0x02, 0x15, 0xea, 0xea, 0x02, 0x9b, 0x00,\n",
+ " 0x0c, 0xfa, 0xe8, 0xea, 0xfd, 0x00, 0x14, 0xfd, 0x0b, 0x02, 0xef, 0xee,\n",
+ " 0x06, 0xee, 0x01, 0x0d, 0x06, 0xe6, 0xf7, 0x11, 0xf7, 0x09, 0xf8, 0xf1,\n",
+ " 0x21, 0xff, 0x0e, 0xf3, 0xec, 0x12, 0x26, 0x1d, 0xf2, 0xe9, 0x28, 0x18,\n",
+ " 0xe0, 0xfb, 0xf3, 0xf4, 0x05, 0x1d, 0x1d, 0xfb, 0xfd, 0x1e, 0xfc, 0x11,\n",
+ " 0xe8, 0x07, 0x09, 0x03, 0x12, 0xf2, 0x36, 0xfb, 0xdc, 0x1c, 0xf9, 0xef,\n",
+ " 0xf3, 0xe7, 0x6f, 0x0c, 0x1d, 0x00, 0x45, 0xfd, 0x0e, 0xf0, 0x0b, 0x19,\n",
+ " 0x1a, 0xfa, 0xe0, 0x19, 0x1f, 0x13, 0x36, 0x1c, 0x12, 0xeb, 0x3b, 0x0c,\n",
+ " 0xb4, 0xcb, 0xe6, 0x13, 0xfa, 0xeb, 0xf1, 0x06, 0x1c, 0xfa, 0x18, 0xe5,\n",
+ " 0xeb, 0xcb, 0x0c, 0xf4, 0x4a, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00,\n",
+ " 0x10, 0x00, 0x00, 0x00, 0x75, 0x1c, 0x11, 0xe1, 0x0c, 0x81, 0xa5, 0x42,\n",
+ " 0xfe, 0xd5, 0xd4, 0xb2, 0x61, 0x78, 0x19, 0xdf, 0x66, 0xff, 0xff, 0xff,\n",
+ " 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n",
+ " 0x77, 0x0b, 0x00, 0x00, 0x53, 0xf6, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\n",
+ " 0x77, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n",
+ " 0xd3, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n",
+ " 0x72, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x07, 0x00, 0x00,\n",
+ " 0x67, 0xf5, 0xff, 0xff, 0x34, 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\n",
+ " 0xb2, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n",
+ " 0x00, 0x00, 0x00, 0x00, 0xb5, 0x04, 0x00, 0x00, 0x78, 0x0a, 0x00, 0x00,\n",
+ " 0x2d, 0x06, 0x00, 0x00, 0x71, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\n",
+ " 0x9a, 0x0a, 0x00, 0x00, 0xfe, 0xf7, 0xff, 0xff, 0x0e, 0x05, 0x00, 0x00,\n",
+ " 0xd4, 0x09, 0x00, 0x00, 0x47, 0xfe, 0xff, 0xff, 0xb6, 0x04, 0x00, 0x00,\n",
+ " 0x00, 0x00, 0x00, 0x00, 0xac, 0xf7, 0xff, 0xff, 0x4b, 0xf9, 0xff, 0xff,\n",
+ " 0x4a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00,\n",
+ " 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n",
+ " 0x8c, 0xef, 0xff, 0xff, 0x84, 0xff, 0xff, 0xff, 0x88, 0xff, 0xff, 0xff,\n",
+ " 0x0f, 0x00, 0x00, 0x00, 0x4d, 0x4c, 0x49, 0x52, 0x20, 0x43, 0x6f, 0x6e,\n",
+ " 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x2e, 0x00, 0x01, 0x00, 0x00, 0x00,\n",
+ " 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00,\n",
+ " 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00,\n",
+ " 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00,\n",
+ " 0xe0, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n",
+ " 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n",
+ " 0x84, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n",
+ " 0x96, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,\n",
+ " 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00,\n",
+ " 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n",
+ " 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n",
+ " 0x01, 0x00, 0x00, 0x00, 0xca, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00,\n",
+ " 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n",
+ " 0xba, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00,\n",
+ " 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n",
+ " 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00,\n",
+ " 0x16, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x04, 0x00,\n",
+ " 0x0e, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,\n",
+ " 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,\n",
+ " 0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\n",
+ " 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n",
+ " 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n",
+ " 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n",
+ " 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x4c, 0x04, 0x00, 0x00,\n",
+ " 0xd0, 0x03, 0x00, 0x00, 0x68, 0x03, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00,\n",
+ " 0x98, 0x02, 0x00, 0x00, 0x24, 0x02, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,\n",
+ " 0x24, 0x01, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n",
+ " 0xf0, 0xfb, 0xff, 0xff, 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n",
+ " 0x54, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,\n",
+ " 0x6c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,\n",
+ " 0x01, 0x00, 0x00, 0x00, 0xdc, 0xfb, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00,\n",
+ " 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n",
+ " 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n",
+ " 0x01, 0x00, 0x00, 0x00, 0x4a, 0xce, 0x0a, 0x3c, 0x01, 0x00, 0x00, 0x00,\n",
+ " 0x34, 0x84, 0x85, 0x3f, 0x01, 0x00, 0x00, 0x00, 0xc5, 0x02, 0x8f, 0xbf,\n",
+ " 0x1e, 0x00, 0x00, 0x00, 0x53, 0x74, 0x61, 0x74, 0x65, 0x66, 0x75, 0x6c,\n",
+ " 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x43,\n",
+ " 0x61, 0x6c, 0x6c, 0x3a, 0x30, 0x5f, 0x69, 0x6e, 0x74, 0x38, 0x00, 0x00,\n",
+ " 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n",
+ " 0x80, 0xfc, 0xff, 0xff, 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n",
+ " 0x54, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,\n",
+ " 0x64, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,\n",
+ " 0x10, 0x00, 0x00, 0x00, 0x6c, 0xfc, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00,\n",
+ " 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n",
+ " 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n",
+ " 0x01, 0x00, 0x00, 0x00, 0x93, 0xd0, 0xc0, 0x3b, 0x01, 0x00, 0x00, 0x00,\n",
+ " 0xc2, 0x0f, 0xc0, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n",
+ " 0x14, 0x00, 0x00, 0x00, 0x74, 0x66, 0x6c, 0x2e, 0x66, 0x75, 0x6c, 0x6c,\n",
+ " 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x31,\n",
+ " 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n",
+ " 0x10, 0x00, 0x00, 0x00, 0x08, 0xfd, 0xff, 0xff, 0x18, 0x00, 0x00, 0x00,\n",
+ " 0x20, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n",
+ " 0x00, 0x00, 0x00, 0x09, 0x64, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n",
+ " 0xff, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0xf4, 0xfc, 0xff, 0xff,\n",
+ " 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n",
+ " 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff,\n",
+ " 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n",
+ " 0xe0, 0xdb, 0x47, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x04, 0x14, 0x47, 0x40,\n",
+ " 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n",
+ " 0x74, 0x66, 0x6c, 0x2e, 0x66, 0x75, 0x6c, 0x6c, 0x79, 0x5f, 0x63, 0x6f,\n",
+ " 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x00, 0x02, 0x00, 0x00, 0x00,\n",
+ " 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0xfe, 0xff, 0xff,\n",
+ " 0x14, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n",
+ " 0x00, 0x00, 0x00, 0x09, 0x50, 0x00, 0x00, 0x00, 0x6c, 0xfd, 0xff, 0xff,\n",
+ " 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,\n",
+ " 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n",
+ " 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xfb, 0x4b, 0x0b, 0x3c,\n",
+ " 0x01, 0x00, 0x00, 0x00, 0x40, 0x84, 0x4b, 0x3f, 0x01, 0x00, 0x00, 0x00,\n",
+ " 0x63, 0x35, 0x8a, 0xbf, 0x0d, 0x00, 0x00, 0x00, 0x73, 0x74, 0x64, 0x2e,\n",
+ " 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x32, 0x00, 0x00, 0x00,\n",
+ " 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n",
+ " 0x72, 0xfe, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,\n",
+ " 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x50, 0x00, 0x00, 0x00,\n",
+ " 0xdc, 0xfd, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n",
+ " 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n",
+ " 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n",
+ " 0x60, 0x01, 0x4f, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x47, 0x6d, 0xb3, 0x3f,\n",
+ " 0x01, 0x00, 0x00, 0x00, 0x5d, 0x63, 0xcd, 0xbf, 0x0d, 0x00, 0x00, 0x00,\n",
+ " 0x73, 0x74, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74,\n",
+ " 0x31, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n",
+ " 0x10, 0x00, 0x00, 0x00, 0xe2, 0xfe, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00,\n",
+ " 0x48, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,\n",
+ " 0x50, 0x00, 0x00, 0x00, 0x4c, 0xfe, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00,\n",
+ " 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n",
+ " 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n",
+ " 0x01, 0x00, 0x00, 0x00, 0xd5, 0x6b, 0x8a, 0x3b, 0x01, 0x00, 0x00, 0x00,\n",
+ " 0xab, 0x49, 0x01, 0x3f, 0x01, 0x00, 0x00, 0x00, 0xfd, 0x56, 0x09, 0xbf,\n",
+ " 0x0c, 0x00, 0x00, 0x00, 0x73, 0x74, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x73,\n",
+ " 0x74, 0x61, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n",
+ " 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x52, 0xff, 0xff, 0xff,\n",
+ " 0x14, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n",
+ " 0x00, 0x00, 0x00, 0x02, 0x3c, 0x00, 0x00, 0x00, 0x44, 0xff, 0xff, 0xff,\n",
+ " 0x08, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n",
+ " 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n",
+ " 0x01, 0x00, 0x00, 0x00, 0x28, 0xb3, 0xd9, 0x38, 0x0c, 0x00, 0x00, 0x00,\n",
+ " 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x32, 0x2f, 0x62, 0x69, 0x61, 0x73,\n",
+ " 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n",
+ " 0xaa, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,\n",
+ " 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x38, 0x00, 0x00, 0x00,\n",
+ " 0x9c, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n",
+ " 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n",
+ " 0x01, 0x00, 0x00, 0x00, 0xdd, 0x9b, 0x21, 0x39, 0x0c, 0x00, 0x00, 0x00,\n",
+ " 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x33, 0x2f, 0x62, 0x69, 0x61, 0x73,\n",
+ " 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n",
+ " 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x13, 0x00, 0x0c, 0x00,\n",
+ " 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n",
+ " 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,\n",
+ " 0x48, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,\n",
+ " 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n",
+ " 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n",
+ " 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n",
+ " 0xf4, 0xd4, 0x51, 0x38, 0x0c, 0x00, 0x00, 0x00, 0x64, 0x65, 0x6e, 0x73,\n",
+ " 0x65, 0x5f, 0x34, 0x2f, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x00, 0x00,\n",
+ " 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x1c, 0x00,\n",
+ " 0x18, 0x00, 0x17, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00,\n",
+ " 0x00, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n",
+ " 0x2c, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n",
+ " 0x00, 0x00, 0x00, 0x09, 0x84, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n",
+ " 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00,\n",
+ " 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00,\n",
+ " 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n",
+ " 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff,\n",
+ " 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n",
+ " 0x5d, 0x4f, 0xc9, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x86, 0xc8, 0x40,\n",
+ " 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,\n",
+ " 0x73, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x66, 0x61,\n",
+ " 0x75, 0x6c, 0x74, 0x5f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x32, 0x5f,\n",
+ " 0x69, 0x6e, 0x70, 0x75, 0x74, 0x3a, 0x30, 0x5f, 0x69, 0x6e, 0x74, 0x38,\n",
+ " 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n",
+ " 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n",
+ " 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xd8, 0xff, 0xff, 0xff,\n",
+ " 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,\n",
+ " 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,\n",
+ " 0x0c, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72,\n",
+ " 0x0c, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00,\n",
+ " 0x0c, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n",
+ " 0x00, 0x00, 0x00, 0x09\n",
+ "};\n",
+ "unsigned int g_model_len = 2488;\n"
+ ],
+ "name": "stdout"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/docs/tensorflow/train_micro_speech_model.ipynb b/docs/tensorflow/train_micro_speech_model.ipynb
new file mode 100644
index 0000000000..bdaf4539cf
--- /dev/null
+++ b/docs/tensorflow/train_micro_speech_model.ipynb
@@ -0,0 +1,554 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "pO4-CY_TCZZS"
+ },
+ "source": [
+ "# Train a Simple Audio Recognition Model"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "BaFfr7DHRmGF"
+ },
+ "source": [
+ "*This* notebook demonstrates how to train a 20 kB [Simple Audio Recognition](https://www.tensorflow.org/tutorials/sequences/audio_recognition) model to recognize keywords in speech.\n",
+ "\n",
+ "The model created in this notebook is used in the [micro_speech](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/examples/micro_speech) example for [TensorFlow Lite for MicroControllers](https://www.tensorflow.org/lite/microcontrollers/overview).\n",
+ "\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "XaVtYN4nlCft"
+ },
+ "source": [
+ "**Training is much faster using GPU acceleration.** Before you proceed, ensure you are using a GPU runtime by going to **Runtime -> Change runtime type** and set **Hardware accelerator: GPU**. Training 15,000 iterations will take 1.5 - 2 hours on a GPU runtime.\n",
+ "\n",
+ "## Configure Defaults\n",
+ "\n",
+ "**MODIFY** the following constants for your specific use case."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "ludfxbNIaegy"
+ },
+ "outputs": [],
+ "source": [
+ "# A comma-delimited list of the words you want to train for.\n",
+ "# The options are: yes,no,up,down,left,right,on,off,stop,go\n",
+ "# All the other words will be used to train an \"unknown\" label and silent\n",
+ "# audio data with no spoken words will be used to train a \"silence\" label.\n",
+ "WANTED_WORDS = \"yes,no\"\n",
+ "\n",
+ "# The number of steps and learning rates can be specified as comma-separated\n",
+ "# lists to define the rate at each stage. For example,\n",
+ "# TRAINING_STEPS=12000,3000 and LEARNING_RATE=0.001,0.0001\n",
+ "# will run 12,000 training loops in total, with a rate of 0.001 for the first\n",
+ "# 8,000, and 0.0001 for the final 3,000.\n",
+ "TRAINING_STEPS = \"12000,3000\"\n",
+ "LEARNING_RATE = \"0.001,0.0001\"\n",
+ "\n",
+ "# Calculate the total number of steps, which is used to identify the checkpoint\n",
+ "# file name.\n",
+ "TOTAL_STEPS = str(sum(map(lambda string: int(string), TRAINING_STEPS.split(\",\"))))\n",
+ "\n",
+ "# Print the configuration to confirm it\n",
+ "print(\"Training these words: %s\" % WANTED_WORDS)\n",
+ "print(\"Training steps in each stage: %s\" % TRAINING_STEPS)\n",
+ "print(\"Learning rate in each stage: %s\" % LEARNING_RATE)\n",
+ "print(\"Total number of training steps: %s\" % TOTAL_STEPS)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "gCgeOpvY9pAi"
+ },
+ "source": [
+ "**DO NOT MODIFY** the following constants as they include filepaths used in this notebook and data that is shared during training and inference."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "Nd1iM1o2ymvA"
+ },
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "\n",
+ "# Calculate the percentage of 'silence' and 'unknown' training samples required\n",
+ "# to ensure that we have equal number of samples for each label.\n",
+ "number_of_labels = WANTED_WORDS.count(',') + 1\n",
+ "number_of_total_labels = number_of_labels + 2 # for 'silence' and 'unknown' label\n",
+ "equal_percentage_of_training_samples = int(100.0/(number_of_total_labels))\n",
+ "SILENT_PERCENTAGE = equal_percentage_of_training_samples\n",
+ "UNKNOWN_PERCENTAGE = equal_percentage_of_training_samples\n",
+ "\n",
+ "# Constants which are shared during training and inference\n",
+ "PREPROCESS = 'micro'\n",
+ "WINDOW_STRIDE = 20\n",
+ "MODEL_ARCHITECTURE = 'tiny_conv' # Other options include: single_fc, conv,\n",
+ " # low_latency_conv, low_latency_svdf, tiny_embedding_conv\n",
+ "\n",
+ "# Constants used during training only\n",
+ "VERBOSITY = 'WARN'\n",
+ "EVAL_STEP_INTERVAL = '1000'\n",
+ "SAVE_STEP_INTERVAL = '1000'\n",
+ "\n",
+ "# Constants for training directories and filepaths\n",
+ "DATASET_DIR = 'dataset/'\n",
+ "LOGS_DIR = 'logs/'\n",
+ "TRAIN_DIR = 'train/' # for training checkpoints and other files.\n",
+ "\n",
+ "# Constants for inference directories and filepaths\n",
+ "MODELS_DIR = 'models'\n",
+ "MODEL_TF = os.path.join(MODELS_DIR, 'model.pb')\n",
+ "MODEL_TFLITE = os.path.join(MODELS_DIR, 'model.tflite')\n",
+ "FLOAT_MODEL_TFLITE = os.path.join(MODELS_DIR, 'float_model.tflite')\n",
+ "MODEL_TFLITE_MICRO = os.path.join(MODELS_DIR, 'model.cc')\n",
+ "SAVED_MODEL = os.path.join(MODELS_DIR, 'saved_model')\n",
+ "\n",
+ "QUANT_INPUT_MIN = 0.0\n",
+ "QUANT_INPUT_MAX = 26.0\n",
+ "QUANT_INPUT_RANGE = QUANT_INPUT_MAX - QUANT_INPUT_MIN\n",
+ "\n",
+ "if not os.path.exists(MODELS_DIR):\n",
+ " os.mkdir(MODELS_DIR)\n",
+ "if not os.path.exists(LOGS_DIR):\n",
+ " os.mkdir(LOGS_DIR)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "6rLYpvtg9P4o"
+ },
+ "source": [
+ "## Setup Environment\n",
+ "\n",
+ "Install Dependencies"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "ed_XpUrU5DvY"
+ },
+ "outputs": [],
+ "source": [
+ "# %tensorflow_version 1.x\n",
+ "import tensorflow as tf"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "T9Ty5mR58E4i"
+ },
+ "source": [
+ "**DELETE** any old data from previous runs\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "APGx0fEh7hFF"
+ },
+ "outputs": [],
+ "source": [
+ "!rm -rf {DATASET_DIR} {LOGS_DIR} {TRAIN_DIR} {MODELS_DIR}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "GfEUlfFBizio"
+ },
+ "source": [
+ "Clone the TensorFlow Github Repository, which contains the relevant code required to run this tutorial."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "yZArmzT85SLq"
+ },
+ "outputs": [],
+ "source": [
+ "!git clone -q --depth 1 https://github.com/tensorflow/tensorflow"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "nS9swHLSi7Bi"
+ },
+ "source": [
+ "Load TensorBoard to visualize the accuracy and loss as training proceeds.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "q4qF1VxP3UE4"
+ },
+ "outputs": [],
+ "source": [
+ "%load_ext tensorboard\n",
+ "%tensorboard --logdir {LOGS_DIR} --bind_all --port=6006\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "x1J96Ron-O4R"
+ },
+ "source": [
+ "## Training\n",
+ "\n",
+ "The following script downloads the dataset and begin training."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "VJsEZx6lynbY"
+ },
+ "outputs": [],
+ "source": [
+ "!python tensorflow/tensorflow/examples/speech_commands/train.py \\\n",
+ "--data_dir={DATASET_DIR} \\\n",
+ "--wanted_words={WANTED_WORDS} \\\n",
+ "--silence_percentage={SILENT_PERCENTAGE} \\\n",
+ "--unknown_percentage={UNKNOWN_PERCENTAGE} \\\n",
+ "--preprocess={PREPROCESS} \\\n",
+ "--window_stride={WINDOW_STRIDE} \\\n",
+ "--model_architecture={MODEL_ARCHITECTURE} \\\n",
+ "--how_many_training_steps={TRAINING_STEPS} \\\n",
+ "--learning_rate={LEARNING_RATE} \\\n",
+ "--train_dir={TRAIN_DIR} \\\n",
+ "--summaries_dir={LOGS_DIR} \\\n",
+ "--verbosity={VERBOSITY} \\\n",
+ "--eval_step_interval={EVAL_STEP_INTERVAL} \\\n",
+ "--save_step_interval={SAVE_STEP_INTERVAL}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "UczQKtqLi7OJ"
+ },
+ "source": [
+ "# Skipping the training\n",
+ "\n",
+ "If you don't want to spend an hour or two training the model from scratch, you can download pretrained checkpoints by uncommenting the lines below (removing the '#'s at the start of each line) and running them."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "RZw3VNlnla-J"
+ },
+ "outputs": [],
+ "source": [
+ "#!curl -O \"https://storage.googleapis.com/download.tensorflow.org/models/tflite/speech_micro_train_2020_05_10.tgz/"\n",
+ "#!tar xzf speech_micro_train_2020_05_10.tgz"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "XQUJLrdS-ftl"
+ },
+ "source": [
+ "## Generate a TensorFlow Model for Inference\n",
+ "\n",
+ "Combine relevant training results (graph, weights, etc) into a single file for inference. This process is known as freezing a model and the resulting model is known as a frozen model/graph, as it cannot be further re-trained after this process."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "xyc3_eLh9sAg"
+ },
+ "outputs": [],
+ "source": [
+ "!rm -rf {SAVED_MODEL}\n",
+ "!python tensorflow/tensorflow/examples/speech_commands/freeze.py \\\n",
+ "--wanted_words=$WANTED_WORDS \\\n",
+ "--window_stride_ms=$WINDOW_STRIDE \\\n",
+ "--preprocess=$PREPROCESS \\\n",
+ "--model_architecture=$MODEL_ARCHITECTURE \\\n",
+ "--start_checkpoint=$TRAIN_DIR$MODEL_ARCHITECTURE'.ckpt-'{TOTAL_STEPS} \\\n",
+ "--save_format=saved_model \\\n",
+ "--output_file={SAVED_MODEL}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "_DBGDxVI-nKG"
+ },
+ "source": [
+ "## Generate a TensorFlow Lite Model\n",
+ "\n",
+ "Convert the frozen graph into a TensorFlow Lite model, which is fully quantized for use with embedded devices.\n",
+ "\n",
+ "The following cell will also print the model size, which will be under 20 kilobytes."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "RIitkqvGWmre"
+ },
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "# We add this path so we can import the speech processing modules.\n",
+ "sys.path.append(\"/content/tensorflow/tensorflow/examples/speech_commands/\")\n",
+ "import input_data\n",
+ "import models\n",
+ "import numpy as np"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "kzqECqMxgBh4"
+ },
+ "outputs": [],
+ "source": [
+ "SAMPLE_RATE = 16000\n",
+ "CLIP_DURATION_MS = 1000\n",
+ "WINDOW_SIZE_MS = 30.0\n",
+ "FEATURE_BIN_COUNT = 40\n",
+ "BACKGROUND_FREQUENCY = 0.8\n",
+ "BACKGROUND_VOLUME_RANGE = 0.1\n",
+ "TIME_SHIFT_MS = 100.0\n",
+ "\n",
+ "DATA_URL = 'https://storage.googleapis.com/download.tensorflow.org/data/speech_commands_v0.02.tar.gz'\n",
+ "VALIDATION_PERCENTAGE = 10\n",
+ "TESTING_PERCENTAGE = 10"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "rNQdAplJV1fz"
+ },
+ "outputs": [],
+ "source": [
+ "model_settings = models.prepare_model_settings(\n",
+ " len(input_data.prepare_words_list(WANTED_WORDS.split(','))),\n",
+ " SAMPLE_RATE, CLIP_DURATION_MS, WINDOW_SIZE_MS,\n",
+ " WINDOW_STRIDE, FEATURE_BIN_COUNT, PREPROCESS)\n",
+ "audio_processor = input_data.AudioProcessor(\n",
+ " DATA_URL, DATASET_DIR,\n",
+ " SILENT_PERCENTAGE, UNKNOWN_PERCENTAGE,\n",
+ " WANTED_WORDS.split(','), VALIDATION_PERCENTAGE,\n",
+ " TESTING_PERCENTAGE, model_settings, LOGS_DIR)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "lBj_AyCh1cC0"
+ },
+ "outputs": [],
+ "source": [
+ "with tf.compat.v1.Session() as sess:\n",
+ " float_converter = tf.lite.TFLiteConverter.from_saved_model(SAVED_MODEL)\n",
+ " float_tflite_model = float_converter.convert()\n",
+ " float_tflite_model_size = open(FLOAT_MODEL_TFLITE, \"wb\").write(float_tflite_model)\n",
+ " print(\"Float model is %d bytes\" % float_tflite_model_size)\n",
+ "\n",
+ " converter = tf.lite.TFLiteConverter.from_saved_model(SAVED_MODEL)\n",
+ " converter.optimizations = [tf.lite.Optimize.DEFAULT]\n",
+ " converter.inference_input_type = tf.compat.v1.lite.constants.INT8\n",
+ " converter.inference_output_type = tf.compat.v1.lite.constants.INT8\n",
+ " def representative_dataset_gen():\n",
+ " for i in range(100):\n",
+ " data, _ = audio_processor.get_data(1, i*1, model_settings,\n",
+ " BACKGROUND_FREQUENCY, \n",
+ " BACKGROUND_VOLUME_RANGE,\n",
+ " TIME_SHIFT_MS,\n",
+ " 'testing',\n",
+ " sess)\n",
+ " flattened_data = np.array(data.flatten(), dtype=np.float32).reshape(1, 1960)\n",
+ " yield [flattened_data]\n",
+ " converter.representative_dataset = representative_dataset_gen\n",
+ " tflite_model = converter.convert()\n",
+ " tflite_model_size = open(MODEL_TFLITE, \"wb\").write(tflite_model)\n",
+ " print(\"Quantized model is %d bytes\" % tflite_model_size)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "EeLiDZTbLkzv"
+ },
+ "source": [
+ "## Testing the TensorFlow Lite model's accuracy\n",
+ "\n",
+ "Verify that the model we've exported is still accurate, using the TF Lite Python API and our test set."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "wQsEteKRLryJ"
+ },
+ "outputs": [],
+ "source": [
+ "# Helper function to run inference\n",
+ "def run_tflite_inference(tflite_model_path, model_type=\"Float\"):\n",
+ " # Load test data\n",
+ " np.random.seed(0) # set random seed for reproducible test results.\n",
+ " with tf.compat.v1.Session() as sess:\n",
+ " test_data, test_labels = audio_processor.get_data(\n",
+ " -1, 0, model_settings, BACKGROUND_FREQUENCY, BACKGROUND_VOLUME_RANGE,\n",
+ " TIME_SHIFT_MS, 'testing', sess)\n",
+ " test_data = np.expand_dims(test_data, axis=1).astype(np.float32)\n",
+ "\n",
+ " # Initialize the interpreter\n",
+ " interpreter = tf.lite.Interpreter(tflite_model_path)\n",
+ " interpreter.allocate_tensors()\n",
+ "\n",
+ " input_details = interpreter.get_input_details()[0]\n",
+ " output_details = interpreter.get_output_details()[0]\n",
+ "\n",
+ " # For quantized models, manually quantize the input data from float to integer\n",
+ " if model_type == \"Quantized\":\n",
+ " input_scale, input_zero_point = input_details[\"quantization\"]\n",
+ " test_data = test_data / input_scale + input_zero_point\n",
+ " test_data = test_data.astype(input_details[\"dtype\"])\n",
+ "\n",
+ " correct_predictions = 0\n",
+ " for i in range(len(test_data)):\n",
+ " interpreter.set_tensor(input_details[\"index\"], test_data[i])\n",
+ " interpreter.invoke()\n",
+ " output = interpreter.get_tensor(output_details[\"index\"])[0]\n",
+ " top_prediction = output.argmax()\n",
+ " correct_predictions += (top_prediction == test_labels[i])\n",
+ "\n",
+ " print('%s model accuracy is %f%% (Number of test samples=%d)' % (\n",
+ " model_type, (correct_predictions * 100) / len(test_data), len(test_data)))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "l-pD52Na6jRa"
+ },
+ "outputs": [],
+ "source": [
+ "# Compute float model accuracy\n",
+ "run_tflite_inference(FLOAT_MODEL_TFLITE)\n",
+ "\n",
+ "# Compute quantized model accuracy\n",
+ "run_tflite_inference(MODEL_TFLITE, model_type='Quantized')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "dt6Zqbxu-wIi"
+ },
+ "source": [
+ "## Generate a TensorFlow Lite for MicroControllers Model\n",
+ "Convert the TensorFlow Lite model into a C source file that can be loaded by TensorFlow Lite for Microcontrollers."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "XohZOTjR8ZyE"
+ },
+ "outputs": [],
+ "source": [
+ "# Install xxd if it is not available\n",
+ "!apt-get update && apt-get -qq install xxd\n",
+ "# Convert to a C source file\n",
+ "!xxd -i {MODEL_TFLITE} > {MODEL_TFLITE_MICRO}\n",
+ "# Update variable names\n",
+ "REPLACE_TEXT = MODEL_TFLITE.replace('/', '_').replace('.', '_')\n",
+ "!sed -i 's/'{REPLACE_TEXT}'/g_model/g' {MODEL_TFLITE_MICRO}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "2pQnN0i_-0L2"
+ },
+ "source": [
+ "## Deploy to a Microcontroller\n",
+ "\n",
+ "Follow the instructions in the [micro_speech](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/examples/micro_speech) README.md for [TensorFlow Lite for MicroControllers](https://www.tensorflow.org/lite/microcontrollers/overview) to deploy this model on a specific microcontroller.\n",
+ "\n",
+ "**Reference Model:** If you have not modified this notebook, you can follow the instructions as is, to deploy the model. Refer to the [`micro_speech/train/models`](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/examples/micro_speech/train/models) directory to access the models generated in this notebook.\n",
+ "\n",
+ "**New Model:** If you have generated a new model to identify different words: (i) Update `kCategoryCount` and `kCategoryLabels` in [`micro_speech/micro_features/micro_model_settings.h`](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/examples/micro_speech/micro_features/micro_model_settings.h) and (ii) Update the values assigned to the variables defined in [`micro_speech/micro_features/model.cc`](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/examples/micro_speech/micro_features/model.cc) with values displayed after running the following cell."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "eoYyh0VU8pca"
+ },
+ "outputs": [],
+ "source": [
+ "# Print the C source file\n",
+ "!cat {MODEL_TFLITE_MICRO}"
+ ]
+ }
+ ],
+ "metadata": {
+ "accelerator": "GPU",
+ "colab": {
+ "collapsed_sections": [],
+ "name": "Copy of train_micro_speech_model.ipynb",
+ "provenance": [],
+ "toc_visible": true
+ },
+ "kernelspec": {
+ "display_name": "Python 3",
+ "name": "python3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/examples/README_ESP32.md b/examples/README_ESP32.md
deleted file mode 100644
index 610586343a..0000000000
--- a/examples/README_ESP32.md
+++ /dev/null
@@ -1,154 +0,0 @@
-# ESP32 Configuration
-
-If you are using ESP32 by Espressif Systems version 3.0.0 and later, audio tools will use the new adc_continuous API.
-
-For the adc_continuous API, audio tools provides the following options:
-
-- **sample_rate** (per channel), the effective ADC sampling rate is the number of channels x sample rate and can be:
- - ESP32: 20kHz to 2MHz
- - ESP32 S2, S3, H2, C6, C3: 611Hz to 83.333kHz
-
-for example:
-
- - 306
- - 4,000
- - 5,000
- - 8,000
- - 10,000
- - 11,025
- - 16,000
- - 20,000
- - 22,050
- - 40,000
- - 44,100
- - 48,000
- - 88,200
- - 96,000
- - 176,400
- - 192,200
- - 352,800
- - 384,000
- - 500,000
- - 1,000,000
-
-- **adc_bit_with**
- - 9, 10, 11, 12 depending on ESP32 model
- - audio stream is int16_t
-- **adc_calibration_active**: values measured are in mV
-- **is_auto_center_read**: subtraction of current estimated average from samples
-- **adc_attenuation**:
-
- | attenuation | range | accurate range |
- | ------------ | --------| -------------- |
- | ADC_ATTEN_DB_0 | 0..1.1V | 100-950mV |
- | ADC_ATTEN_DB_2_5| 0..1.5V | 100-1250mV |
- | ADC_ATTEN_DB_6 | 0..2.2V | 150-1750mV |
- | ADC_ATTEN_DB_12 | 0..3.9V | 150-2450mV |
-
-- **channels**:
- - mono = 1
- - stereo = 2
-- **adc_channels**: defining the channels (only channels on ADC unit 1 are supported) e.g.:
- - A3 on Sparkfun ESP32 Thing Plus is ADC_CHANNEL_3
- - A4 on Sparkfun ESP32 Thing Plus is ADC_CHANNEL_0
- - D5 on Adafruit ESP32-S3 is ADC_CHANNEL_4
- - D6 on Adafruit ESP32-S3 is ADC_CHANNEL_5
-
-- **buffer_size**
- - maximum is 2048
- - minimum is number of channels
- - number needs to be devisible by number of channels
- - care must be taken because some streams in audio tools can not exceed 1024 bytes
-
-## Example Configuration
-```
-auto adcConfig = adc.defaultConfig(RX_MODE);
-adcConfig.sample_rate = 44100;
-adcConfig.adc_bit_width = 12;
-adcConfig.adc_calibration_active = true;
-adcConfig.is_auto_center_read = false;
-adcConfig.adc_attenuation = ADC_ATTEN_DB_12;
-adcConfig.channels = 2;
-adcConfig.adc_channels[0] = ADC_CHANNEL_4;
-adcConfig.adc_channels[1] = ADC_CHANNEL_5;
-```
-
-## ADC unit 1 channels on common ESP32 boards
-Audio tools continous ADC framewaork supports ADC Unit 1 only.
-
-### Sparkfun ESP32 Thing Plus (ESP32)
-- A2, ADC1_CH6
-- A3, ADC1_CH3
-- A4, ADC1_CH0
-- 32, ADC1_CH4
-- 33, ADC1_CH5
-
-### Sparkfun ESP32 Thing Plus C (ESP32)
-- A2, ADC1_CH6
-- A3, ADC1_CH3
-- A4, ADC1_CH0
-- A5, ADC1_CH7
-- 32/6, ADC1_CH4
-- 33/10, ADC1_CH5
-
-### Sparkfun ESP32 Qwiic Pocket Development (ESP32C6)
-- 2, ADC1_CH2
-- 3, ADC1_CH3
-- 4, ADC1_CH4
-- 5, ADC1_CH5
-
-### ESP32-C6-DevKit
-- 4, ADC1_CH4
-- 5, ADC1_CH5
-- 6, ADC1_CH6
-- 7, ADC1_CH0
-- 0, ADC1_CH1
-- 2, ADC1_CH2
-- 3, ADC1_CH3
-
-### ESP32-H2-DevKit
-- 1, ADC1_CH0
-- 2, ADC1_CH1
-- 3, ADC1_CH2
-- 4, ADC1_CH3
-- 5, ADC1_CH4
-
-### ESP32-S3-DevKit
-- 1, ADC1_CH0
-- 2, ADC1_CH1
-- 4, ADC1_CH3
-- 5, ADC1_CH4
-- 6, ADC1_CH5
-- 7, ADC1_CH6
-- 8, ADC1_CH7
-- 3, ADC1_CH2
-- 9, ADC1_CH8
-- 10, ADC1_CH9
-
-### ESP32-C3-DevKit
-- 4, IO2, ADC1_CH2
-- 5, IO3, ADC1_CH3
-- 9, IO0, ADC1_CH0
-- 10, IO1, ADC1_CH1
-- 11, IO4, ADC1_CH4
-
-### Adafruit ESP32 Feather V2
-- D32, ADC1_CH4
-- D33, ADC1_CH5
-- A2, ADC1_CH6
-- A3, ADC1_CH3
-- A4, ADC1_CH0
-- D37, ADC1_CH1
-
-### Adafruit ESP32-S3 Feather
-- D5, ADC1_CH4
-- D6, ADC1_CH5
-- D9, ADC1_CH8
-- D10, ADC1_CH9
-- A5, ADC1_CH7
-
-### Adafruit QT Py ESP32-C3
-- A0, ADC1-CH4
-- A1, ADC1-CH3
-- A2, ADC1-CH1
-- A3, ADC1-CH0
diff --git a/examples/build-arch-log.txt b/examples/build-arch-log.txt
index 06d6508da4..f44f0fd469 100644
--- a/examples/build-arch-log.txt
+++ b/examples/build-arch-log.txt
@@ -2,12 +2,8 @@ esp32:esp32:esp32 ./examples-stream/streams-generator-serial -> rc=0
esp32:esp32:esp32c3 ./examples-stream/streams-generator-serial -> rc=0
esp32:esp32:esp32s3 ./examples-stream/streams-generator-serial -> rc=0
esp32:esp32:esp32s2 ./examples-stream/streams-generator-serial -> rc=0
-esp32:esp32:esp32c6 ./examples-stream/streams-generator-serial -> rc=0
-esp32:esp32:esp32h2 ./examples-stream/streams-generator-serial -> rc=0
esp8266:esp8266:generic ./examples-stream/streams-generator-serial -> rc=0
+arduino:mbed_rp2040:pico ./examples-stream/streams-generator-serial -> rc=0
rp2040:rp2040:generic ./examples-stream/streams-generator-serial -> rc=0
arduino:avr:nano ./examples-stream/streams-generator-serial -> rc=0
arduino:samd:arduino_zero_native ./examples-stream/streams-generator-serial -> rc=0
-arduino:renesas_uno:unor4wifi ./examples-stream/streams-generator-serial -> rc=0
-arduino:mbed_nano:nano33ble ./examples-stream/streams-generator-serial -> rc=0
-arduino:mbed_rp2040:pico ./examples-stream/streams-generator-serial -> rc=0
diff --git a/examples/build-arch.sh b/examples/build-arch.sh
index f6b8e46b24..6cc242f8db 100755
--- a/examples/build-arch.sh
+++ b/examples/build-arch.sh
@@ -22,16 +22,11 @@ compile_example "esp32:esp32:esp32"
compile_example "esp32:esp32:esp32c3"
compile_example "esp32:esp32:esp32s3"
compile_example "esp32:esp32:esp32s2"
-compile_example "esp32:esp32:esp32c6"
-compile_example "esp32:esp32:esp32h2"
compile_example "esp8266:esp8266:generic"
+compile_example "arduino:mbed_rp2040:pico"
compile_example "rp2040:rp2040:generic"
compile_example "arduino:avr:nano"
compile_example "arduino:samd:arduino_zero_native"
-compile_example "arduino:renesas_uno:unor4wifi"
-compile_example "arduino:mbed_nano:nano33ble"
-compile_example "arduino:mbed_rp2040:pico"
-#compile_example "arduino:zephyr:nano33ble"
#compile_example "STMicroelectronics:stm32:GenF4"
./cleanup.sh
diff --git a/examples/build-examples-log.txt b/examples/build-examples-log.txt
index 0afdfbc579..a222c65f29 100644
--- a/examples/build-examples-log.txt
+++ b/examples/build-examples-log.txt
@@ -1,38 +1,46 @@
-../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-a2dp -> 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-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-player/player-callback-i2s -> rc=0
../examples/examples-player/player-littlefs-i2s -> rc=0
-../examples/examples-player/player-sd-audiokit -> rc=0
+../examples/examples-player/player-sdfat-a2dp -> rc=0
../examples/examples-player/player-sdfat-analog -> rc=0
-../examples/examples-player/player-sdfat-audiokit -> rc=0
../examples/examples-player/player-sdfat-ffti2s -> rc=0
../examples/examples-player/player-sdfat-i2s -> rc=0
../examples/examples-player/player-sd-i2s -> rc=0
-../examples/examples-player/player-sdmmc-audiokit -> 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=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_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-serial -> rc=0
../examples/examples-stream/streams-adsr-i2s -> rc=0
+../examples/examples-stream/streams-generator-a2dp -> rc=0
../examples/examples-stream/streams-generator-analog -> 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_fromarray-analog -> rc=0
../examples/examples-stream/streams-generator-i2s -> rc=0
-../examples/examples-stream/streams-generator-merge-pwm -> rc=0
../examples/examples-stream/streams-generator-pwm -> rc=0
-../examples/examples-stream/streams-generator-r2r -> rc=0
../examples/examples-stream/streams-generator-serial -> rc=0
../examples/examples-stream/streams-generator-spdif -> rc=0
-../examples/examples-stream/streams-generator-timedstream-serial -> rc=0
-../examples/examples-stream/streams-generator-volume -> 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-i2s -> rc=0
../examples/examples-stream/streams-i2s-i2s-2 -> rc=0
-../examples/examples-stream/streams-i2s_pdm-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-tf -> rc=0
@@ -42,14 +50,34 @@
../examples/examples-stream/streams-memory_mp3_short-i2s -> rc=0
../examples/examples-stream/streams-memory_mp3_short-i2s-2 -> rc=0
../examples/examples-stream/streams-memory_raw-i2s -> rc=0
-../examples/examples-stream/streams-memory_wav-pwm -> rc=0
+../examples/examples-stream/streams-memory_wav-pwm -> rc=1/0
../examples/examples-stream/streams-memory_wav-serial -> rc=0
../examples/examples-stream/streams-mp34dt05-serial -> rc=1
../examples/examples-stream/streams-sdfat_mp3-metadata -> rc=0
../examples/examples-stream/streams-sd_mp3-i2s -> rc=0
-../examples/examples-stream/streams-sd_wav4-i2s -> rc=0
../examples/examples-stream/streams-tf-i2s -> rc=0
-../examples/examples-audiokit/README.md -> rc=1
+../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_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_raw-i2s -> rc=0
+../examples/examples-stream/streams-url_raw-serial -> rc=0
+../examples/examples-stream/streams-url_vorbis_i2s -> rc=0
+../examples/examples-stream/streams-url_wav-i2s -> rc=1
+../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-sdfat-audiokit -> rc=0
+../examples/examples-audiokit/player-sdmmc-audiokit -> rc=0
+../examples/examples-audiokit/player-url_icy-audiokit -> rc=0
+../examples/examples-audiokit/streams-a2dp-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-fft -> rc=0
@@ -63,6 +91,7 @@
../examples/examples-audiokit/streams-audiokit-sd_wav -> rc=0
../examples/examples-audiokit/streams-audiokit-serial -> rc=0
../examples/examples-audiokit/streams-audiokit-tf -> rc=0
+../examples/examples-audiokit/streams-audiokit-webserver_wav -> rc=0
../examples/examples-audiokit/streams-file_loop-audiokit -> rc=0
../examples/examples-audiokit/streams-generator-audiokit -> rc=0
../examples/examples-audiokit/streams-generator_fromarray-audiokit -> rc=0
@@ -72,97 +101,54 @@
../examples/examples-audiokit/streams-memory_mp3-audiokit -> rc=0
../examples/examples-audiokit/streams-memory_pcm-mixer-audiokit -> rc=0
../examples/examples-audiokit/streams-pins-audiokit -> rc=0
-../examples/examples-audiokit/streams-sd_flac-audiokit -> rc=0
-../examples/examples-audiokit/streams-sdmmc_wav-audiokit -> rc=0
-../examples/examples-audiokit/streams-sd_mp3-audiokit -> rc=0
+../examples/examples-audiokit/streams-sd-audiokit -> rc=0
+../examples/examples-audiokit/streams-synth-a2dp -> rc=0
../examples/examples-audiokit/streams-synth-audiokit -> rc=0
../examples/examples-audiokit/streams-synthbasic1-audiokit -> rc=0
../examples/examples-audiokit/streams-synthbasic2-audiokit -> rc=0
../examples/examples-audiokit/streams-synthbasic3-audiokit -> rc=0
../examples/examples-audiokit/streams-synthstk-audiokit -> rc=0
../examples/examples-audiokit/streams-tf-audiokit -> rc=0
-../examples/examples-tts/streams-azure_tts-i2s -> rc=0
+../examples/examples-audiokit/streams-url_aac-audiokit -> rc=0
+../examples/examples-audiokit/streams-url_mp3-audiokit -> rc=0
+../examples/examples-maximilian/01-TestTone -> rc=0
+../examples/examples-maximilian/02-TwoTones -> rc=0
+../examples/examples-maximilian/03-AM1 -> rc=0
+../examples/examples-maximilian/04-AM2 -> rc=0
+../examples/examples-maximilian/05-FM1 -> rc=0
+../examples/examples-maximilian/06-FM2 -> rc=0
+../examples/examples-maximilian/07-Counting1 -> rc=0
+../examples/examples-maximilian/08-Counting2 -> rc=0
+../examples/examples-maximilian/08-Counting3 -> rc=0
+../examples/examples-maximilian/08-Counting4 -> rc=0
+../examples/examples-maximilian/09-Envelopes -> rc=0
+../examples/examples-maximilian/10-Filters -> rc=0
+../examples/examples-maximilian/11-Mixing -> rc=0
+../examples/examples-maximilian/12-SamplePlayer -> rc=0
+../examples/examples-maximilian/13-AdvancedFilters -> rc=0
+../examples/examples-maximilian/14-MonoSynth -> rc=0
+../examples/examples-maximilian/15-PolySynth -> rc=0
+../examples/examples-maximilian/16-Replicant -> rc=0
+../examples/examples-maximilian/17-Compressor -> rc=0
+../examples/examples-maximilian/18-DrumMachine -> rc=0
+../examples/examples-maximilian/19-Enveloping2 -> rc=0
+../examples/examples-maximilian/20-FFT -> rc=0
+../examples/examples-tts/streams-azure_tts-i2s -> rc=1
../examples/examples-tts/streams-espeak-audiokit -> rc=0
../examples/examples-tts/streams-espeak-i2s -> rc=0
../examples/examples-tts/streams-flite-audiokit -> rc=0
../examples/examples-tts/streams-flite-i2s -> rc=0
-../examples/examples-tts/streams-google-audiokit -> rc=0
../examples/examples-tts/streams-sam-audiokit -> rc=0
../examples/examples-tts/streams-sam-i2s -> rc=0
-../examples/examples-tts/streams-simple_tts-a2dp -> rc=0
../examples/examples-tts/streams-simple_tts-i2s -> rc=0
-../examples/examples-tts/streams-talkie-a2dp -> rc=0
-../examples/examples-tts/streams-talkie-audiokit -> rc=0
../examples/examples-tts/streams-tts-i2s -> rc=0
-../examples/examples-tts/streams-url_wav-i2s -> rc=0
-../examples/examples-dsp/examples-maximilian/01-TestTone -> rc=0
-../examples/examples-dsp/examples-maximilian/02-TwoTones -> rc=0
-../examples/examples-dsp/examples-maximilian/03-AM1 -> rc=0
-../examples/examples-dsp/examples-maximilian/04-AM2 -> rc=0
-../examples/examples-dsp/examples-maximilian/05-FM1 -> rc=0
-../examples/examples-dsp/examples-maximilian/06-FM2 -> rc=0
-../examples/examples-dsp/examples-maximilian/07-Counting1 -> rc=0
-../examples/examples-dsp/examples-maximilian/08-Counting2 -> rc=0
-../examples/examples-dsp/examples-maximilian/08-Counting3 -> rc=0
-../examples/examples-dsp/examples-maximilian/08-Counting4 -> rc=0
-../examples/examples-dsp/examples-maximilian/09-Envelopes -> rc=0
-../examples/examples-dsp/examples-maximilian/10-Filters -> rc=0
-../examples/examples-dsp/examples-maximilian/11-Mixing -> rc=0
-../examples/examples-dsp/examples-maximilian/12-SamplePlayer -> rc=0
-../examples/examples-dsp/examples-maximilian/13-AdvancedFilters -> rc=0
-../examples/examples-dsp/examples-maximilian/14-MonoSynth -> rc=0
-../examples/examples-dsp/examples-maximilian/15-PolySynth -> rc=0
-../examples/examples-dsp/examples-maximilian/16-Replicant -> rc=0
-../examples/examples-dsp/examples-maximilian/17-Compressor -> rc=0
-../examples/examples-dsp/examples-maximilian/18-DrumMachine -> rc=0
-../examples/examples-dsp/examples-maximilian/19-Enveloping2 -> rc=0
-../examples/examples-dsp/examples-maximilian/20-FFT -> rc=0
-../examples/examples-dsp/examples-maximilian/README.md -> rc=1
-../examples/examples-dsp/examples-mozzi/audio_input -> rc=0
-../examples/examples-dsp/examples-mozzi/control_gain -> rc=0
-../examples/examples-dsp/examples-mozzi/control_gain-a2dp -> rc=0
-../examples/examples-dsp/examples-pd/README.md -> rc=1
-../examples/examples-dsp/examples-pd/streams-generator-pd-audiokit -> rc=1
-../examples/examples-dsp/examples-pd/streams-pd-audiokit -> rc=1
-../examples/examples-dsp/examples-stk/README.md -> rc=1
-../examples/examples-dsp/examples-stk/streams-stk_allinstruments-audiokit -> rc=0
-../examples/examples-dsp/examples-stk/streams-stk-audiokit -> rc=0
-../examples/examples-dsp/examples-stk/streams-stk-desktop -> rc=1
-../examples/examples-dsp/examples-stk/streams-stk_files-audiokit -> rc=0
-../examples/examples-dsp/examples-stk/streams-stk_generator-audiokit -> rc=0
-../examples/examples-dsp/examples-stk/streams-stk_loop-audiokit -> rc=0
-../examples/examples-dsp/examples-stk/streams-stk_myinstrument-audiokit -> rc=0
-../examples/examples-dsp/examples-stk/streams-stk_sine-audiokit -> rc=0
-../examples/examples-dsp/examples-stk/streams-stk_synth-audiokit -> rc=0
-../examples/examples-dsp/examples-faust/streams-faust_flute-i2s -> rc=0
-../examples/examples-dsp/examples-faust/streams-faust_noise-i2s -> rc=0
-../examples/examples-dsp/examples-faust/streams-generator-faust-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_pitchshift-i2s -> 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=0
-../examples/examples-communication/a2dp/basic-a2dp-mixer-i2s -> rc=0
-../examples/examples-communication/a2dp/basic-adc-a2dp -> rc=0
-../examples/examples-communication/a2dp/basic-audiokit-a2dp -> rc=0
-../examples/examples-communication/a2dp/basic-file_mp3-a2dp -> rc=0
-../examples/examples-communication/a2dp/basic-generator-a2dp -> rc=0
-../examples/examples-communication/a2dp/basic-i2s-a2dp -> rc=0
-../examples/examples-communication/a2dp/basic-player-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-a2dp-spdif -> 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=0
+../examples/examples-faust/streams-faust_flute-i2s -> rc=0
+../examples/examples-faust/streams-faust_noise-i2s -> rc=0
+../examples/examples-faust/streams-generator-faust-i2s -> rc=0
+../examples/examples-faust/streams-i2s-faust_guitarix-i2s -> 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-send -> rc=0
+../examples/examples-communication/esp-now/codec/communication-codec-espnow-send -> rc=1/0
../examples/examples-communication/esp-now/pcm/communication-espnow-receive -> rc=0
../examples/examples-communication/esp-now/pcm/communication-espnow-receive_csv -> rc=0
../examples/examples-communication/esp-now/pcm/communication-espnow-receive_measure -> rc=0
@@ -172,80 +158,20 @@
../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-send -> rc=0
-../examples/examples-communication/udp/communication-udp-receive -> rc=0
-../examples/examples-communication/udp/communication-udp-send -> 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=0
../examples/examples-communication/rtsp/communication-codec-rtsp -> rc=0
../examples/examples-communication/rtsp/communication-generator-rtsp -> rc=0
-../examples/examples-communication/rtsp/communication-rtsp-audiokit -> 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=0
-../examples/examples-communication/serial/send-adpcm-receive -> rc=0
-../examples/examples-communication/serial/send-receive -> rc=0
-../examples/examples-communication/snapcast/snapclient-i2s -> rc=0
-../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=0
-../examples/examples-communication/http-client/streams-http_post -> rc=0
-../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_foxen-i2s -> 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_mp3-pwm -> rc=0
-../examples/examples-communication/http-client/streams-url_mts-hex -> rc=0
-../examples/examples-communication/http-client/streams-url_post -> rc=0
-../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/python-post-server -> rc=1
-../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_unsigned -> rc=0
-../examples/tests/adc/read-esp32-multi-channel-csv -> rc=0
-../examples/tests/adc/read-speed -> rc=0
-../examples/tests/basic/24bits-write -> rc=0
-../examples/tests/basic/test-allocator -> rc=0
-../examples/tests/basic/test-buffer -> rc=0
-../examples/tests/basic/test-queue -> rc=0
-../examples/tests/basic/test-vector -> rc=0
-../examples/tests/codecs/test-codec-aac-fdk -> rc=0
-../examples/tests/codecs/test-codec-aac-fdk-dec -> rc=0
-../examples/tests/codecs/test-codec-adpcm -> rc=0
-../examples/tests/codecs/test-codec-adpcm-xq -> rc=0
+../examples/tests/test-ads1015 -> rc=0
+../examples/tests/test-bitvector -> rc=0
+../examples/tests/test-filter -> rc=0
+../examples/tests/test-list -> rc=0
+../examples/tests/test-memory-helix -> rc=0
+../examples/tests/test-mulit-compilation-units -> rc=0
+../examples/tests/test-pins -> rc=0
+../examples/tests/test-player -> rc=0
+../examples/tests/test-resample-in -> rc=0
+../examples/tests/test-resample-out -> rc=0
+../examples/tests/24bits/24bits-write -> rc=0
../examples/tests/codecs/test-codec-aptx -> rc=0
../examples/tests/codecs/test-codec-base64 -> rc=0
../examples/tests/codecs/test-codec-codec2 -> rc=0
@@ -260,88 +186,40 @@
../examples/tests/codecs/test-codec-iLBC -> rc=0
../examples/tests/codecs/test-codec-l8 -> rc=0
../examples/tests/codecs/test-codec-lc3 -> rc=0
+../examples/tests/codecs/test-codec-ogg -> rc=0
../examples/tests/codecs/test-codec-opus -> rc=0
../examples/tests/codecs/test-codec-opusogg -> rc=0
../examples/tests/codecs/test-codec-sbc -> rc=0
-../examples/tests/codecs/test-codec-wav-adpcm -> rc=0
-../examples/tests/codecs/test-compile-all -> rc=0
+../examples/tests/codecs/test-container-avi -> rc=1/0
../examples/tests/codecs/test-container-binary -> rc=0
-../examples/tests/codecs/test-container-binary-meta -> rc=0
-../examples/tests/codecs/test-container-ogg -> rc=0
-../examples/tests/codecs/test-memory-helix -> rc=0
../examples/tests/codecs/test-mp3-helix -> rc=0
../examples/tests/codecs/test-mp3-helix-reading -> rc=0
../examples/tests/codecs/test-mp3-mad -> rc=0
-../examples/tests/codecs/test-mp3_parser -> rc=0
-../examples/tests/codecs/test-streaming-adapter -> rc=0
-../examples/tests/concurrency/audio-test -> rc=0
-../examples/tests/concurrency/BufferRTOS -> rc=0
../examples/tests/concurrency/NBuffer -> rc=0
+../examples/tests/concurrency/synchBufferRTOS -> rc=0
../examples/tests/concurrency/synchNBuffer -> rc=0
../examples/tests/concurrency/synchRingBuffer -> rc=0
-../examples/tests/conversion/channel-converter-avg -> rc=0
-../examples/tests/conversion/channel-converter-bin -> rc=0
-../examples/tests/conversion/channel-converter-bindiff -> rc=0
-../examples/tests/conversion/channel-converter-decimate -> rc=0
-../examples/tests/conversion/channel-converter-diff -> rc=0
../examples/tests/conversion/channel-converter-increase-in -> rc=0
../examples/tests/conversion/channel-converter-increase-out -> rc=0
../examples/tests/conversion/channel-converter-reduce-in -> rc=0
../examples/tests/conversion/channel-converter-reduce-out -> rc=0
-../examples/tests/conversion/format-converter-in -> rc=0
-../examples/tests/conversion/numberformat-converter -> rc=0
-../examples/tests/conversion/numberformat-converter-typed -> 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-resample-in -> rc=0
-../examples/tests/conversion/test-resample-out -> rc=0
-../examples/tests/conversion/test-volumestream -> rc=0
../examples/tests/effects/delay-in -> rc=0
../examples/tests/effects/delay-out -> rc=0
-../examples/tests/effects/pitch-shift -> rc=0
-../examples/tests/effects/pitch-shift-180 -> rc=0
-../examples/tests/effects/pitch-shift-simple -> rc=0
-../examples/tests/etc/callback-write -> rc=0
-../examples/tests/etc/test-ads1015 -> rc=0
-../examples/tests/etc/test-audiolibs -> rc=0
-../examples/tests/etc/test-mulit-compilation-units -> rc=0
-../examples/tests/etc/test-pins -> rc=0
-../examples/tests/etc/test-ringbufferfile -> rc=0
-../examples/tests/etc/test-tdm -> rc=0
-../examples/tests/etc/test-write-memory -> rc=0
../examples/tests/fft/fft-cmsis -> rc=1
../examples/tests/fft/fft-esp32 -> rc=0
../examples/tests/fft/fft-espressif -> rc=0
-../examples/tests/fft/fft-ifft -> rc=0
../examples/tests/fft/fft-kiss -> rc=0
../examples/tests/fft/fft-real -> rc=0
../examples/tests/fft/fft-topn -> rc=0
../examples/tests/fft/fft-window -> rc=0
-../examples/tests/filters/test-90deg -> rc=0
-../examples/tests/filters/test-filter -> rc=0
-../examples/tests/filters/test-lowpass -> rc=0
-../examples/tests/filters/test-median-filter -> rc=0
-../examples/tests/performance/file-speeds-sd -> rc=0
-../examples/tests/performance/file-speeds-sdfat -> rc=0
-../examples/tests/performance/file-speeds-sdmmc -> rc=0
-../examples/tests/performance/file-speeds-vfssd -> rc=0
-../examples/tests/performance/file-speeds-vfssdmmc -> rc=0
../examples/tests/performance/mp3-Speed -> rc=0
../examples/tests/performance/mp3-SynchronizedBufferRTOS -> rc=0
../examples/tests/performance/mp3-SynchronizedNBuffer -> rc=0
../examples/tests/performance/mp3-SynchronizedRingBuffer -> rc=0
-../examples/tests/performance/sine -> rc=0
-../examples/tests/performance/throttle -> rc=0
-../examples/tests/performance/wifi -> rc=0
-../examples/tests/player/test-index-sd -> rc=0
-../examples/tests/player/test-index-sdfat -> rc=0
-../examples/tests/player/test-index-sdmmc -> rc=0
-../examples/tests/player/test-player -> rc=0
-../examples/tests/player/test-vfs -> rc=0
-../examples/tests/timer/test-timer -> rc=0
-../examples/tests/timer/test-timercb_rx -> rc=0
-../examples/tests/timer/test-timercb_tx -> rc=0
-../examples/tests/timer/test-timercbx_rx -> rc=0
-../examples/tests/timer/test-timercbx_tx -> rc=0
+../examples/tests/performance/sine -> rc=1
+../examples/tests/pitch-shift/pitch-shift -> rc=0
+../examples/tests/pitch-shift/pitch-shift-180 -> rc=0
+../examples/tests/pitch-shift/pitch-shift-simple -> rc=0
+../examples/tests/sd/test-index-sd -> rc=0
+../examples/tests/sd/test-index-sdfat -> rc=0
+../examples/tests/sd/test-index-sdmmc -> rc=0
diff --git a/examples/build-examples.sh b/examples/build-examples.sh
index 1feb2da7bb..6fdb8c29c8 100755
--- a/examples/build-examples.sh
+++ b/examples/build-examples.sh
@@ -10,8 +10,6 @@
#arduino-cli lib linstall
git -C .. pull
git -C ../../ESP32-A2DP pull
-git -C ../../arduino-audio-driver pull
-git -C ../../arduino-libhelix pull
function compile_example {
ARCH=$1
@@ -21,7 +19,7 @@ function compile_example {
echo "Processing $f ..."
# take action on each file. $f store current file name
#arduino-cli compile -b "$ARCH" "$f"
- arduino-cli compile -b "$ARCH" --build-property "build.partitions=rainmaker" --build-property "upload.maximum_size=3145728" "$f"
+ arduino-cli compile -b "$ARCH" --build-property "build.partitions=huge_app" --build-property "upload.maximum_size=3145728" "$f"
EC=$?
#if [ $EC -ne 0 ]; then
#break
@@ -33,39 +31,26 @@ function compile_example {
rm build-examples-log.txt
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-webserver/str*"
compile_example "esp32:esp32:esp32" "../examples/examples-stream/streams*"
compile_example "esp32:esp32:esp32" "../examples/examples-audiokit/*"
+compile_example "esp32:esp32:esp32" "../examples/examples-maximilian/*"
compile_example "esp32:esp32:esp32" "../examples/examples-tts/streams*"
-compile_example "esp32:esp32:esp32" "../examples/examples-dsp/examples-maximilian/*"
-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-stk/*"
-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-faust/streams*"
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/speed-test/*"
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/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/basic/*"
+compile_example "esp32:esp32:esp32" "../examples/tests/test*"
+compile_example "esp32:esp32:esp32" "../examples/tests/24bits/*"
compile_example "esp32:esp32:esp32" "../examples/tests/codecs/*"
compile_example "esp32:esp32:esp32" "../examples/tests/concurrency/*"
compile_example "esp32:esp32:esp32" "../examples/tests/conversion/*"
compile_example "esp32:esp32:esp32" "../examples/tests/effects/*"
-compile_example "esp32:esp32:esp32" "../examples/tests/etc/*"
compile_example "esp32:esp32:esp32" "../examples/tests/fft/*"
-compile_example "esp32:esp32:esp32" "../examples/tests/filters/*"
compile_example "esp32:esp32:esp32" "../examples/tests/performance/*"
-compile_example "esp32:esp32:esp32" "../examples/tests/player/*"
-compile_example "esp32:esp32:esp32" "../examples/tests/timer/*"
-rm -rf /tmp/arduino
+compile_example "esp32:esp32:esp32" "../examples/tests/pitch-shift/*"
+compile_example "esp32:esp32:esp32" "../examples/tests/sd/*"
./cleanup.sh
\ No newline at end of file
diff --git a/examples/examples-audiokit/README.md b/examples/examples-audiokit/README.md
index 03dbc78cef..752187c8a6 100644
--- a/examples/examples-audiokit/README.md
+++ b/examples/examples-audiokit/README.md
@@ -1,7 +1,3 @@
# AudioKit
-Please read the [Audio Boards Wiki](https://github.com/pschatzmann/arduino-audio-tools/wiki/Audio-Boards) first.
-
-These sketches work on the AI Thinker AudioKit, the LyraT or any other board that is supported by the [arduino-audio-driver](https://github.com/pschatzmann/arduino-audio-driver) library.
-
-If you want to use them on any other board, you just pass the corresponding board variable in the constructor or you compose your own board. Further information can be found in [this Wiki](https://github.com/pschatzmann/arduino-audio-driver/wiki).
+These sketches work on the AI Thinker AudioKit or the LyraT Audio Boards. If you want to use them on any other board you usually just need to replace the AudioKitStream with an I2SStream!
\ No newline at end of file
diff --git a/examples/examples-communication/a2dp/basic-a2dp-audiokit/README.md b/examples/examples-audiokit/basic-a2dp-audiokit/README.md
similarity index 90%
rename from examples/examples-communication/a2dp/basic-a2dp-audiokit/README.md
rename to examples/examples-audiokit/basic-a2dp-audiokit/README.md
index d1551b8033..94f979849e 100644
--- a/examples/examples-communication/a2dp/basic-a2dp-audiokit/README.md
+++ b/examples/examples-audiokit/basic-a2dp-audiokit/README.md
@@ -4,7 +4,7 @@ I found some cheap [AI Thinker ESP32 Audio Kit V2.2](https://docs.ai-thinker.com
-I am using the data callback of the A2DP library to feed the AudioBoardStream
+I am using the data callback of the A2DP library to feed the AudioKitStream
You dont need to bother about any wires because everything is on one nice board. Just just need to install the dependencies:
@@ -14,4 +14,4 @@ You need to install the following libraries:
- https://github.com/pschatzmann/arduino-audio-tools
- https://github.com/pschatzmann/ESP32-A2DP
-- https://github.com/pschatzmann/arduino-audio-driver
+- https://github.com/pschatzmann/arduino-audiokit
diff --git a/examples/examples-communication/a2dp/basic-a2dp-audiokit/basic-a2dp-audiokit.ino b/examples/examples-audiokit/basic-a2dp-audiokit/basic-a2dp-audiokit.ino
similarity index 68%
rename from examples/examples-communication/a2dp/basic-a2dp-audiokit/basic-a2dp-audiokit.ino
rename to examples/examples-audiokit/basic-a2dp-audiokit/basic-a2dp-audiokit.ino
index aa33497b4d..825ea2829f 100644
--- a/examples/examples-communication/a2dp/basic-a2dp-audiokit/basic-a2dp-audiokit.ino
+++ b/examples/examples-audiokit/basic-a2dp-audiokit/basic-a2dp-audiokit.ino
@@ -7,12 +7,12 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/A2DPStream.h" // install https://github.com/pschatzmann/ESP32-A2DP
-#include "AudioTools/AudioLibs/AudioBoardStream.h" // install https://github.com/pschatzmann/arduino-audio-driver
+#include "AudioLibs/AudioKit.h"
+#include "AudioLibs/AudioA2DP.h"
BluetoothA2DPSink a2dp_sink;
-AudioBoardStream kit(AudioKitEs8388V1);
+AudioKitStream kit;
// Write data to AudioKit in callback
void read_data_stream(const uint8_t *data, uint32_t length) {
@@ -21,7 +21,7 @@ void read_data_stream(const uint8_t *data, uint32_t length) {
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// setup output
auto cfg = kit.defaultConfig(TX_MODE);
@@ -34,4 +34,5 @@ void setup() {
}
void loop() {
+ kit.processActions();
}
\ No newline at end of file
diff --git a/examples/examples-communication/a2dp/basic-a2dp-eq-audiokit/README.md b/examples/examples-audiokit/basic-a2dp-eq-audiokit/README.md
similarity index 84%
rename from examples/examples-communication/a2dp/basic-a2dp-eq-audiokit/README.md
rename to examples/examples-audiokit/basic-a2dp-eq-audiokit/README.md
index 775d5d0a05..a061eddd64 100644
--- a/examples/examples-communication/a2dp/basic-a2dp-eq-audiokit/README.md
+++ b/examples/examples-audiokit/basic-a2dp-eq-audiokit/README.md
@@ -1,10 +1,10 @@
-## Using the AI Thinker ESP32 Audio Kit as A2DP Receiver with Equalizer
+## Using the AI Thinker ESP32 Audio Kit as A2DP Receiver with Equilizer
I found some cheap [AI Thinker ESP32 Audio Kit V2.2](https://docs.ai-thinker.com/en/esp32-audio-kit) on AliExpress.
-I am using the data callback of the A2DP library to feed the AudioBoardStream that will be controlled by an Equalizer
+I am using the data callback of the A2DP library to feed the AudioKitStream that will be controlled by an Equilizer
You dont need to bother about any wires because everything is on one nice board. Just just need to install the dependencies:
@@ -14,4 +14,4 @@ You need to install the following libraries:
- https://github.com/pschatzmann/arduino-audio-tools
- https://github.com/pschatzmann/ESP32-A2DP
-- https://github.com/pschatzmann/arduino-audio-driver
+- https://github.com/pschatzmann/arduino-audiokit
diff --git a/examples/examples-communication/a2dp/basic-a2dp-eq-audiokit/basic-a2dp-eq-audiokit.ino b/examples/examples-audiokit/basic-a2dp-eq-audiokit/basic-a2dp-eq-audiokit.ino
similarity index 69%
rename from examples/examples-communication/a2dp/basic-a2dp-eq-audiokit/basic-a2dp-eq-audiokit.ino
rename to examples/examples-audiokit/basic-a2dp-eq-audiokit/basic-a2dp-eq-audiokit.ino
index f4dac39893..f1d8fb74b7 100644
--- a/examples/examples-communication/a2dp/basic-a2dp-eq-audiokit/basic-a2dp-eq-audiokit.ino
+++ b/examples/examples-audiokit/basic-a2dp-eq-audiokit/basic-a2dp-eq-audiokit.ino
@@ -7,14 +7,14 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/A2DPStream.h" // install https://github.com/pschatzmann/ESP32-A2DP
-#include "AudioTools/AudioLibs/AudioBoardStream.h" // install https://github.com/pschatzmann/arduino-audio-driver
+#include "AudioLibs/AudioKit.h"
+#include "AudioLibs/AudioA2DP.h"
BluetoothA2DPSink a2dp_sink;
-AudioBoardStream kit(AudioKitEs8388V1);
-Equalizer3Bands eq(kit);
-ConfigEqualizer3Bands cfg_eq;
+AudioKitStream kit;
+Equilizer3Bands eq(kit);
+ConfigEquilizer3Bands cfg_eq;
// Write data to AudioKit in callback
@@ -24,16 +24,13 @@ void read_data_stream(const uint8_t *data, uint32_t length) {
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// setup output
auto cfg = kit.defaultConfig(TX_MODE);
cfg.sd_active = false;
kit.begin(cfg);
- // max volume
- kit.setVolume(1.0);
-
// setup equilizer
cfg_eq = eq.defaultConfig();
cfg_eq.setAudioInfo(cfg); // use channels, bits_per_sample and sample_rate from kit
@@ -48,4 +45,5 @@ void setup() {
}
void loop() {
+ // kit.processActions(); // uncomment for default button commands
}
\ No newline at end of file
diff --git a/examples/examples-communication/a2dp/basic-audiokit-a2dp/basic-audiokit-a2dp.ino b/examples/examples-audiokit/basic-audiokit-a2dp/basic-audiokit-a2dp.ino
similarity index 63%
rename from examples/examples-communication/a2dp/basic-audiokit-a2dp/basic-audiokit-a2dp.ino
rename to examples/examples-audiokit/basic-audiokit-a2dp/basic-audiokit-a2dp.ino
index 965c0c0d75..fd0be25ac0 100644
--- a/examples/examples-communication/a2dp/basic-audiokit-a2dp/basic-audiokit-a2dp.ino
+++ b/examples/examples-audiokit/basic-audiokit-a2dp/basic-audiokit-a2dp.ino
@@ -1,17 +1,17 @@
/**
* @file base-audiokit-a2dp.ino
* @author Phil Schatzmann
- * @brief We play the input from the ADC to an A2DP speaker
+ * @brief We play mp4 files to an A2DP speaker
+ * make sure that you compile with partition scheme: huge app
* @copyright GPLv3
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/AudioLibs/A2DPStream.h"
+#include "AudioLibs/AudioKit.h"
+#include "AudioLibs/AudioA2DP.h"
-AudioInfo info(44100, 2, 16);
BluetoothA2DPSource a2dp_source;
-AudioBoardStream i2s(AudioKitEs8388V1);
+AudioKitStream i2s;
const int16_t BYTES_PER_FRAME = 4;
// callback used by A2DP to provide the sound data - usually len is 128 2 channel int16 frames
@@ -22,23 +22,23 @@ int32_t get_sound_data(Frame* data, int32_t frameCount) {
// Arduino Setup
void setup(void) {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// start i2s input with default configuration
Serial.println("starting I2S...");
auto cfg = i2s.defaultConfig(RX_MODE);
cfg.i2s_format = I2S_STD_FORMAT; // or try with I2S_LSB_FORMAT
- cfg.copyFrom(info);
- cfg.input_device = ADC_INPUT_LINE2; // microphone
+ cfg.bits_per_sample = 16;
+ cfg.channels = 2;
+ cfg.sample_rate = 44100;
+ cfg.input_device = AUDIO_HAL_ADC_INPUT_LINE2; // microphone
i2s.begin(cfg);
// start the bluetooth
Serial.println("starting A2DP...");
- a2dp_source.set_data_callback_in_frames(get_sound_data);
- a2dp_source.start("LEXON MINO L");
+ a2dp_source.start("LEXON MINO L", get_sound_data);
}
// Arduino loop - repeated processing
void loop() {
- delay(1000);
-}
+}
\ No newline at end of file
diff --git a/examples/examples-player/player-sd-audiokit/README.md b/examples/examples-audiokit/player-sd-audiokit/README.md
similarity index 94%
rename from examples/examples-player/player-sd-audiokit/README.md
rename to examples/examples-audiokit/player-sd-audiokit/README.md
index 74004fe988..0ad58f2f2f 100644
--- a/examples/examples-player/player-sd-audiokit/README.md
+++ b/examples/examples-audiokit/player-sd-audiokit/README.md
@@ -18,4 +18,4 @@ You need to install the following libraries:
- https://github.com/pschatzmann/arduino-audio-tools
- https://github.com/pschatzmann/arduino-libhelix
-- https://github.com/pschatzmann/arduino-audio-driver
+- https://github.com/pschatzmann/arduino-audiokit
diff --git a/examples/examples-player/player-sd-audiokit/player-sd-audiokit.ino b/examples/examples-audiokit/player-sd-audiokit/player-sd-audiokit.ino
similarity index 76%
rename from examples/examples-player/player-sd-audiokit/player-sd-audiokit.ino
rename to examples/examples-audiokit/player-sd-audiokit/player-sd-audiokit.ino
index 678f957317..894784fd84 100644
--- a/examples/examples-player/player-sd-audiokit/player-sd-audiokit.ino
+++ b/examples/examples-audiokit/player-sd-audiokit/player-sd-audiokit.ino
@@ -8,14 +8,14 @@
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/Disk/AudioSourceSD.h" // or AudioSourceIdxSD.h
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
+#include "AudioLibs/AudioKit.h"
+#include "AudioLibs/AudioSourceSD.h" // or AudioSourceIdxSD.h
+#include "AudioCodecs/CodecMP3Helix.h"
const char *startFilePath="/";
const char* ext="mp3";
AudioSourceSD source(startFilePath, ext, PIN_AUDIO_KIT_SD_CARD_CS);
-AudioBoardStream kit(AudioKitEs8388V1);
+AudioKitStream kit;
MP3DecoderHelix decoder; // or change to MP3DecoderMAD
AudioPlayer player(source, kit, decoder);
@@ -33,7 +33,7 @@ void startStop(bool, int, void*) {
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// setup output
auto cfg = kit.defaultConfig(TX_MODE);
@@ -43,10 +43,9 @@ void setup() {
kit.begin(cfg);
// setup additional buttons
- kit.addDefaultActions();
- kit.addAction(kit.getKey(1), startStop);
- kit.addAction(kit.getKey(4), next);
- kit.addAction(kit.getKey(3), previous);
+ kit.addAction(PIN_KEY1, startStop);
+ kit.addAction(PIN_KEY4, next);
+ kit.addAction(PIN_KEY3, previous);
// setup player
diff --git a/examples/examples-communication/a2dp/player-sd_a2dp-audiokit/player-sd_a2dp-audiokit.ino b/examples/examples-audiokit/player-sd_a2dp-audiokit/player-sd_a2dp-audiokit.ino
similarity index 82%
rename from examples/examples-communication/a2dp/player-sd_a2dp-audiokit/player-sd_a2dp-audiokit.ino
rename to examples/examples-audiokit/player-sd_a2dp-audiokit/player-sd_a2dp-audiokit.ino
index 1de620e9ad..fcf171e9ae 100644
--- a/examples/examples-communication/a2dp/player-sd_a2dp-audiokit/player-sd_a2dp-audiokit.ino
+++ b/examples/examples-audiokit/player-sd_a2dp-audiokit/player-sd_a2dp-audiokit.ino
@@ -12,15 +12,15 @@
// install https://github.com/greiman/SdFat.git
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/A2DPStream.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/Disk/AudioSourceSDFAT.h"
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
+#include "AudioLibs/AudioA2DP.h"
+#include "AudioLibs/AudioKit.h"
+#include "AudioLibs/AudioSourceSDFAT.h"
+#include "AudioCodecs/CodecMP3Helix.h"
const char *startFilePath="/";
const char* ext="mp3";
-AudioBoardStream kit(AudioKitEs8388V1);
-SdSpiConfig sdcfg(PIN_AUDIO_KIT_SD_CARD_CS, DEDICATED_SPI, SD_SCK_MHZ(10) , &SPI);
+AudioKitStream kit;
+SdSpiConfig sdcfg(PIN_AUDIO_KIT_SD_CARD_CS, DEDICATED_SPI, SD_SCK_MHZ(10) , &AUDIOKIT_SD_SPI);
AudioSourceSDFAT source(startFilePath, ext, sdcfg);
MP3DecoderHelix decoder;
AudioPlayer player(source, kit, decoder);
@@ -57,7 +57,7 @@ void mode(bool, int, void*) {
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// provide a2dp data
a2dp_sink.set_stream_reader(read_data_stream, false);
@@ -68,8 +68,7 @@ void setup() {
kit.begin(cfg);
// setup additional buttons
- kit.addDefaultActions();
- kit.addAction(kit.getKey(4), mode);
+ kit.addAction(PIN_KEY4, mode);
// setup player
player.setVolume(0.7);
diff --git a/examples/examples-player/player-sdfat-audiokit/README.md b/examples/examples-audiokit/player-sdfat-audiokit/README.md
similarity index 95%
rename from examples/examples-player/player-sdfat-audiokit/README.md
rename to examples/examples-audiokit/player-sdfat-audiokit/README.md
index 64ac89621c..95936b6932 100644
--- a/examples/examples-player/player-sdfat-audiokit/README.md
+++ b/examples/examples-audiokit/player-sdfat-audiokit/README.md
@@ -18,5 +18,5 @@ You need to install the following libraries:
- https://github.com/pschatzmann/arduino-audio-tools
- https://github.com/pschatzmann/arduino-libhelix
-- https://github.com/pschatzmann/arduino-audio-driver
+- https://github.com/pschatzmann/arduino-audiokit
- https://github.com/greiman/SdFat
diff --git a/examples/examples-player/player-sdfat-audiokit/player-sdfat-audiokit.ino b/examples/examples-audiokit/player-sdfat-audiokit/player-sdfat-audiokit.ino
similarity index 72%
rename from examples/examples-player/player-sdfat-audiokit/player-sdfat-audiokit.ino
rename to examples/examples-audiokit/player-sdfat-audiokit/player-sdfat-audiokit.ino
index 2c0942e22f..59880f814d 100644
--- a/examples/examples-player/player-sdfat-audiokit/player-sdfat-audiokit.ino
+++ b/examples/examples-audiokit/player-sdfat-audiokit/player-sdfat-audiokit.ino
@@ -8,15 +8,15 @@
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/Disk/AudioSourceSDFAT.h" // or AudioSourceIdxSDFAT.h
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
+#include "AudioLibs/AudioKit.h"
+#include "AudioLibs/AudioSourceSDFAT.h" // or AudioSourceIdxSDFAT.h
+#include "AudioCodecs/CodecMP3Helix.h"
const char *startFilePath="/";
const char* ext="mp3";
-SdSpiConfig sdcfg(PIN_AUDIO_KIT_SD_CARD_CS, DEDICATED_SPI, SD_SCK_MHZ(10) , &SPI);
+SdSpiConfig sdcfg(PIN_AUDIO_KIT_SD_CARD_CS, DEDICATED_SPI, SD_SCK_MHZ(10) , &AUDIOKIT_SD_SPI);
AudioSourceSDFAT source(startFilePath, ext, sdcfg);
-AudioBoardStream kit(AudioKitEs8388V1);
+AudioKitStream kit;
MP3DecoderHelix decoder; // or change to MP3DecoderMAD
AudioPlayer player(source, kit, decoder);
@@ -34,17 +34,16 @@ void startStop(bool, int, void*) {
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// setup output
auto cfg = kit.defaultConfig(TX_MODE);
kit.begin(cfg);
// setup additional buttons
- kit.addDefaultActions();
- kit.addAction(kit.getKey(1), startStop);
- kit.addAction(kit.getKey(4), next);
- kit.addAction(kit.getKey(3), previous);
+ kit.addAction(PIN_KEY1, startStop);
+ kit.addAction(PIN_KEY4, next);
+ kit.addAction(PIN_KEY3, previous);
// setup player
diff --git a/examples/examples-player/player-sdmmc-audiokit/README.md b/examples/examples-audiokit/player-sdmmc-audiokit/README.md
similarity index 95%
rename from examples/examples-player/player-sdmmc-audiokit/README.md
rename to examples/examples-audiokit/player-sdmmc-audiokit/README.md
index 85fc694fc1..5baa0397ab 100644
--- a/examples/examples-player/player-sdmmc-audiokit/README.md
+++ b/examples/examples-audiokit/player-sdmmc-audiokit/README.md
@@ -19,4 +19,4 @@ You need to install the following libraries:
- https://github.com/pschatzmann/arduino-audio-tools
- https://github.com/pschatzmann/arduino-libhelix
-- https://github.com/pschatzmann/arduino-audio-driver
+- https://github.com/pschatzmann/arduino-audiokit
diff --git a/examples/examples-player/player-sdmmc-audiokit/player-sdmmc-audiokit.ino b/examples/examples-audiokit/player-sdmmc-audiokit/player-sdmmc-audiokit.ino
similarity index 76%
rename from examples/examples-player/player-sdmmc-audiokit/player-sdmmc-audiokit.ino
rename to examples/examples-audiokit/player-sdmmc-audiokit/player-sdmmc-audiokit.ino
index af8191a210..1639f2bd05 100644
--- a/examples/examples-player/player-sdmmc-audiokit/player-sdmmc-audiokit.ino
+++ b/examples/examples-audiokit/player-sdmmc-audiokit/player-sdmmc-audiokit.ino
@@ -7,20 +7,20 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/Disk/AudioSourceSDMMC.h" // or AudioSourceIdxSDMMC.h
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
+#include "AudioLibs/AudioKit.h"
+#include "AudioLibs/AudioSourceSDMMC.h" // or AudioSourceIdxSDMMC.h
+#include "AudioCodecs/CodecMP3Helix.h"
const char *startFilePath="/";
const char* ext="mp3";
AudioSourceSDMMC source(startFilePath, ext);
-AudioBoardStream kit(AudioKitEs8388V1);
+AudioKitStream kit;
MP3DecoderHelix decoder; // or change to MP3DecoderMAD
AudioPlayer player(source, kit, decoder);
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// setup output
auto cfg = kit.defaultConfig(TX_MODE);
diff --git a/examples/examples-communication/http-client/player-url_icy-audiokit/README.md b/examples/examples-audiokit/player-url_icy-audiokit/README.md
similarity index 93%
rename from examples/examples-communication/http-client/player-url_icy-audiokit/README.md
rename to examples/examples-audiokit/player-url_icy-audiokit/README.md
index 1e5bb0e59d..bef056ac6b 100644
--- a/examples/examples-communication/http-client/player-url_icy-audiokit/README.md
+++ b/examples/examples-audiokit/player-url_icy-audiokit/README.md
@@ -18,4 +18,4 @@ I also demonstrate how to assign your own actions to the buttons of the audio ki
- https://github.com/pschatzmann/arduino-audio-tools
- https://github.com/pschatzmann/arduino-libhelix
-- https://github.com/pschatzmann/arduino-audio-driver
+- https://github.com/pschatzmann/arduino-audiokit
diff --git a/examples/examples-communication/http-client/player-url_icy-audiokit/player-url_icy-audiokit.ino b/examples/examples-audiokit/player-url_icy-audiokit/player-url_icy-audiokit.ino
similarity index 79%
rename from examples/examples-communication/http-client/player-url_icy-audiokit/player-url_icy-audiokit.ino
rename to examples/examples-audiokit/player-url_icy-audiokit/player-url_icy-audiokit.ino
index 2f510092bf..579a227824 100644
--- a/examples/examples-communication/http-client/player-url_icy-audiokit/player-url_icy-audiokit.ino
+++ b/examples/examples-audiokit/player-url_icy-audiokit/player-url_icy-audiokit.ino
@@ -7,9 +7,8 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/Disk/AudioSourceURL.h"
+#include "AudioCodecs/CodecMP3Helix.h"
+#include "AudioLibs/AudioKit.h"
const char *urls[] = {
"http://stream.srg-ssr.ch/m/rsj/mp3_128",
@@ -23,7 +22,7 @@ const char *password = "password";
ICYStream urlStream(wifi, password);
AudioSourceURL source(urlStream, urls, "audio/mp3");
-AudioBoardStream kit(AudioKitEs8388V1);
+AudioKitStream kit;
MP3DecoderHelix decoder;
AudioPlayer player(source, kit, decoder);
@@ -46,7 +45,7 @@ void stopResume(bool, int, void*){
// Arduino setup
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// setup output
auto cfg = kit.defaultConfig(TX_MODE);
@@ -54,8 +53,8 @@ void setup() {
kit.begin(cfg);
// setup navigation
- kit.addAction(kit.getKey(4), next);
- kit.addAction(kit.getKey(3), previous);
+ kit.addAction(PIN_KEY4, next);
+ kit.addAction(PIN_KEY3, previous);
// setup player
player.setVolume(0.7);
diff --git a/examples/examples-communication/a2dp/streams-a2dp-audiokit/streams-a2dp-audiokit.ino b/examples/examples-audiokit/streams-a2dp-audiokit/streams-a2dp-audiokit.ino
similarity index 78%
rename from examples/examples-communication/a2dp/streams-a2dp-audiokit/streams-a2dp-audiokit.ino
rename to examples/examples-audiokit/streams-a2dp-audiokit/streams-a2dp-audiokit.ino
index 15daf91042..f15ce732fc 100644
--- a/examples/examples-communication/a2dp/streams-a2dp-audiokit/streams-a2dp-audiokit.ino
+++ b/examples/examples-audiokit/streams-a2dp-audiokit/streams-a2dp-audiokit.ino
@@ -9,18 +9,18 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/A2DPStream.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/AudioA2DP.h"
+#include "AudioLibs/AudioKit.h"
A2DPStream in;
-AudioBoardStream kit(AudioKitEs8388V1);
+AudioKitStream kit;
StreamCopy copier(kit, in); // copy in to out
// Arduino Setup
void setup(void) {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
// start the bluetooth audio receiver
Serial.println("starting A2DP...");
diff --git a/examples/examples-audiokit/streams-audiokit-audiokit/README.md b/examples/examples-audiokit/streams-audiokit-audiokit/README.md
index e01ffbb347..3f8e9c24b7 100644
--- a/examples/examples-audiokit/streams-audiokit-audiokit/README.md
+++ b/examples/examples-audiokit/streams-audiokit-audiokit/README.md
@@ -12,4 +12,4 @@ We implement a AudioKit source and sink: We stream the sound input which we read
You need to install the following libraries:
- https://github.com/pschatzmann/arduino-audio-tools
-- https://github.com/pschatzmann/arduino-audio-driver
+- https://github.com/pschatzmann/arduino-audiokit
diff --git a/examples/examples-audiokit/streams-audiokit-audiokit/streams-audiokit-audiokit.ino b/examples/examples-audiokit/streams-audiokit-audiokit/streams-audiokit-audiokit.ino
index 4a797b1af3..eb14a17777 100644
--- a/examples/examples-audiokit/streams-audiokit-audiokit/streams-audiokit-audiokit.ino
+++ b/examples/examples-audiokit/streams-audiokit-audiokit/streams-audiokit-audiokit.ino
@@ -9,19 +9,19 @@
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/AudioKit.h"
-AudioBoardStream kit(AudioKitEs8388V1); // Access I2S as stream
+AudioKitStream kit; // Access I2S as stream
StreamCopy copier(kit, kit); // copy kit to kit
// Arduino Setup
void setup(void) {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
auto cfg = kit.defaultConfig(RXTX_MODE);
cfg.sd_active = false;
- cfg.input_device = ADC_INPUT_LINE2;
+ cfg.input_device = AUDIO_HAL_ADC_INPUT_LINE2;
kit.begin(cfg);
}
diff --git a/examples/examples-audiokit/streams-audiokit-effects-audiokit/streams-audiokit-effects-audiokit.ino b/examples/examples-audiokit/streams-audiokit-effects-audiokit/streams-audiokit-effects-audiokit.ino
index b5d837c7e1..9519adcf69 100644
--- a/examples/examples-audiokit/streams-audiokit-effects-audiokit/streams-audiokit-effects-audiokit.ino
+++ b/examples/examples-audiokit/streams-audiokit-effects-audiokit/streams-audiokit-effects-audiokit.ino
@@ -11,7 +11,7 @@
#include // https://arduinojson.org/
#include "HttpServer.h" // https://github.com/pschatzmann/TinyHttp
#include "AudioTools.h" // https://github.com/pschatzmann/arduino-audio-tools.git
-#include "AudioTools/AudioLibs/AudioBoardStream.h" // https://github.com/pschatzmann/arduino-audio-driver.git
+#include "AudioLibs/AudioKit.h" // https://github.com/pschatzmann/arduino-audiokit.git
// Server
WiFiServer wifi;
@@ -39,7 +39,7 @@ Fuzz fuzz(fuzzEffectValue);
Tremolo tremolo(tremoloDuration, tremoloDepth, sample_rate);
// Audio
-AudioBoardStream kit(AudioKitEs8388V1); // Access I2S as stream
+AudioKitStream kit; // Access I2S as stream
AudioEffectStream effects(kit); // input from kit
StreamCopy copier(kit, effects); // copy effects to kit
@@ -118,7 +118,7 @@ void postJson(HttpServer *server, const char*requestPath, HttpRequestHandlerLine
// Arduino Setup
void setup(void) {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
// Setup Server
static HttpTunnel tunnel_url("https://pschatzmann.github.io/TinyHttp/app/guitar-effects.html");
@@ -131,7 +131,7 @@ void setup(void) {
// Setup Kit
auto cfg = kit.defaultConfig(RXTX_MODE);
cfg.sd_active = false;
- cfg.input_device = ADC_INPUT_LINE2;
+ cfg.input_device = AUDIO_HAL_ADC_INPUT_LINE2;
cfg.sample_rate = sample_rate;
cfg.channels = channels;
// minimize lag
diff --git a/examples/examples-audiokit/streams-audiokit-fft-led/streams-audiokit-fft-led.ino b/examples/examples-audiokit/streams-audiokit-fft-led/streams-audiokit-fft-led.ino
index e27ff93c55..542b5b1caf 100644
--- a/examples/examples-audiokit/streams-audiokit-fft-led/streams-audiokit-fft-led.ino
+++ b/examples/examples-audiokit/streams-audiokit-fft-led/streams-audiokit-fft-led.ino
@@ -1,62 +1,46 @@
-/**
- * @file streams-audiokit-fft-led.ino
- * @author Phil Schatzmann
- * @brief We peform FFT on the microphone input of the AudioKit and display the
- * result on a 32*8 LED matrix
- * @version 0.1
- * @date 2022-10-14
- *
- * @copyright Copyright (c) 2022
- *
- */
-#include // to prevent conflicts introduced with 3.9
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/AudioLibs/AudioRealFFT.h" // or AudioKissFFT
-#include "AudioTools/AudioLibs/LEDOutput.h"
+#include "AudioLibs/AudioKit.h"
+#include "AudioLibs/AudioRealFFT.h" // or AudioKissFFT
+#include "AudioLibs/LEDOutput.h"
#define PIN_LEDS 22
#define LED_X 32
#define LED_Y 8
-AudioBoardStream kit(AudioKitEs8388V1); // Audio source
-AudioRealFFT fft; // or AudioKissFFT
-FFTDisplay fft_dis(fft);
-LEDOutput led(fft_dis); // output to LED matrix
+AudioKitStream kit; // Audio source
+AudioRealFFT fft; // or AudioKissFFT
StreamCopy copier(fft, kit); // copy mic to fft
+LEDOutput led(fft); // output to LED matrix
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// setup Audiokit as input device
auto cfg = kit.defaultConfig(RX_MODE);
- cfg.input_device = ADC_INPUT_LINE2;
+ cfg.input_device = AUDIO_HAL_ADC_INPUT_LINE2;
kit.begin(cfg);
// Setup FFT output
auto tcfg = fft.defaultConfig();
- tcfg.length = 1024;
+ tcfg.length = 1024;
tcfg.copyFrom(cfg);
fft.begin(tcfg);
- // Setup FFT Display
- fft_dis.fft_group_bin = 3;
- fft_dis.fft_start_bin = 0;
- fft_dis.fft_max_magnitude = 40000;
- fft_dis.begin();
-
// Setup LED matrix output
auto lcfg = led.defaultConfig();
lcfg.x = LED_X;
lcfg.y = LED_Y;
+ lcfg.fft_group_bin = 3;
+ lcfg.fft_start_bin = 0;
+ lcfg.fft_max_magnitude = 40000;
led.begin(lcfg);
// add LEDs
FastLED.addLeds(led.ledData(), led.ledCount());
}
-void loop() {
+void loop() {
// update FFT
copier.copy();
// update LEDs
diff --git a/examples/examples-audiokit/streams-audiokit-fft/README.md b/examples/examples-audiokit/streams-audiokit-fft/README.md
index 275bf8b336..d2a0420672 100644
--- a/examples/examples-audiokit/streams-audiokit-fft/README.md
+++ b/examples/examples-audiokit/streams-audiokit-fft/README.md
@@ -18,4 +18,4 @@ The log level has been set to Info to help you to identify any problems. Please
You need to install the following libraries:
- https://github.com/pschatzmann/arduino-audio-tools
-- https://github.com/pschatzmann/arduino-audio-driver
+- https://github.com/pschatzmann/arduino-audiokit
diff --git a/examples/examples-audiokit/streams-audiokit-fft/streams-audiokit-fft.ino b/examples/examples-audiokit/streams-audiokit-fft/streams-audiokit-fft.ino
index e428ca0371..50bf3e8114 100644
--- a/examples/examples-audiokit/streams-audiokit-fft/streams-audiokit-fft.ino
+++ b/examples/examples-audiokit/streams-audiokit-fft/streams-audiokit-fft.ino
@@ -1,9 +1,9 @@
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/AudioLibs/AudioRealFFT.h" // or AudioKissFFT
+#include "AudioLibs/AudioKit.h"
+#include "AudioLibs/AudioRealFFT.h" // or AudioKissFFT
-AudioBoardStream kit(AudioKitEs8388V1); // Audio source
+AudioKitStream kit; // Audio source
AudioRealFFT fft; // or AudioKissFFT
StreamCopy copier(fft, kit); // copy mic to tfl
int channels = 2;
@@ -28,11 +28,11 @@ void fftResult(AudioFFTBase &fft){
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
// setup Audiokit
auto cfg = kit.defaultConfig(RX_MODE);
- cfg.input_device = ADC_INPUT_LINE2;
+ cfg.input_device = AUDIO_HAL_ADC_INPUT_LINE2;
cfg.channels = channels;
cfg.sample_rate = samples_per_second;
cfg.bits_per_sample = bits_per_sample;
diff --git a/examples/examples-audiokit/streams-audiokit-filter-audiokit/streams-audiokit-filter-audiokit.ino b/examples/examples-audiokit/streams-audiokit-filter-audiokit/streams-audiokit-filter-audiokit.ino
index b9343c6d6a..5dfef7d56f 100644
--- a/examples/examples-audiokit/streams-audiokit-filter-audiokit/streams-audiokit-filter-audiokit.ino
+++ b/examples/examples-audiokit/streams-audiokit-filter-audiokit/streams-audiokit-filter-audiokit.ino
@@ -6,13 +6,13 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/AudioKit.h"
AudioInfo info(44100, 2, 16);
-AudioBoardStream kit(AudioKitEs8388V1);
+AudioKitStream kit;
// copy filtered values
-FilteredStream filtered(kit, info.channels); // Defiles the filter as BaseConverter
+FilteredStream filtered(kit, channels); // Defiles the filter as BaseConverter
StreamCopy copier(filtered, kit); // copies sound into i2s (both from kit to filtered or filered to kit are supported)
// define FIR filter
@@ -23,7 +23,7 @@ void setup(void) {
// Open Serial
Serial.begin(115200);
// change to Warning to improve the quality
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// setup filters for all available channels
filtered.setFilter(0, new FIR(coef));
@@ -34,7 +34,7 @@ void setup(void) {
auto config = kit.defaultConfig(RXTX_MODE);
config.copyFrom(info);
config.sd_active = false;
- config.input_device = ADC_INPUT_LINE2;
+ config.input_device = AUDIO_HAL_ADC_INPUT_LINE2;
kit.begin(config);
Serial.println("KIT started...");
diff --git a/examples/examples-audiokit/streams-audiokit-multioutput-server/streams-audiokit-multioutput-server.ino b/examples/examples-audiokit/streams-audiokit-multioutput-server/streams-audiokit-multioutput-server.ino
index 653992abfc..a2f3e2e5b0 100644
--- a/examples/examples-audiokit/streams-audiokit-multioutput-server/streams-audiokit-multioutput-server.ino
+++ b/examples/examples-audiokit/streams-audiokit-multioutput-server/streams-audiokit-multioutput-server.ino
@@ -10,11 +10,11 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/AudioKit.h"
const int buffer_count = 10;
const int buffer_size = 1024;
-AudioBoardStream kit(AudioKitEs8388V1); // input & output
+AudioKitStream kit; // input & output
QueueStream queue(buffer_size, buffer_count, true);
AudioEncoderServer server(new WAVEncoder(),"WIFI","password");
MultiOutput out(queue, kit);
@@ -23,12 +23,12 @@ StreamCopy copier(out, kit); // copy kit to kit
// Arduino Setup
void setup(void) {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// setup audiokit
auto cfg = kit.defaultConfig(RXTX_MODE);
cfg.sd_active = false;
- cfg.input_device = ADC_INPUT_LINE2; // input from microphone
+ cfg.input_device = AUDIO_HAL_ADC_INPUT_LINE2; // input from microphone
cfg.sample_rate = 16000;
kit.setVolume(0.5);
kit.begin(cfg);
diff --git a/examples/examples-audiokit/streams-audiokit-multioutput/streams-audiokit-multioutput.ino b/examples/examples-audiokit/streams-audiokit-multioutput/streams-audiokit-multioutput.ino
index 118b678d29..47a7b1a670 100644
--- a/examples/examples-audiokit/streams-audiokit-multioutput/streams-audiokit-multioutput.ino
+++ b/examples/examples-audiokit/streams-audiokit-multioutput/streams-audiokit-multioutput.ino
@@ -10,30 +10,27 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/AudioKit.h"
-AudioInfo info(8000, 2, 16);
-AudioBoardStream kit(AudioKitEs8388V1); // Access I2S as stream
-CsvOutput csv(Serial);
+AudioKitStream kit; // Access I2S as stream
+CsvOutput csv(Serial,2);
MultiOutput out;
StreamCopy copier(out, kit); // copy kit to kit
// Arduino Setup
void setup(void) {
Serial.begin(230400);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
out.add(csv);
out.add(kit);
auto cfg = kit.defaultConfig(RXTX_MODE);
- cfg.copyFrom(info);
cfg.sd_active = false;
- cfg.input_device = ADC_INPUT_LINE2; // input from microphone
+ cfg.input_device = AUDIO_HAL_ADC_INPUT_LINE2; // input from microphone
+ cfg.sample_rate = 8000;
kit.setVolume(0.5);
kit.begin(cfg);
-
- csv.begin(info);
}
// Arduino loop - copy data
diff --git a/examples/examples-audiokit/streams-audiokit-ram-audiokit/streams-audiokit-ram-audiokit.ino b/examples/examples-audiokit/streams-audiokit-ram-audiokit/streams-audiokit-ram-audiokit.ino
index 6be14925f0..68a645159c 100644
--- a/examples/examples-audiokit/streams-audiokit-ram-audiokit/streams-audiokit-ram-audiokit.ino
+++ b/examples/examples-audiokit/streams-audiokit-ram-audiokit/streams-audiokit-ram-audiokit.ino
@@ -10,11 +10,11 @@
*
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/AudioLibs/MemoryManager.h"
+#include "AudioLibs/AudioKit.h"
+#include "AudioLibs/MemoryManager.h"
AudioInfo info(16000, 1, 16);
-AudioBoardStream kit(AudioKitEs8388V1);
+AudioKitStream kit;
MemoryManager memory(500); // Activate SPI RAM for objects > 500 bytes
DynamicMemoryStream recording(true); // Audio stored on heap
StreamCopy copier; // copies data
@@ -32,7 +32,7 @@ void record_end(bool pinStatus, int pin, void* ref){
// Remove popping noise, from button: we delete 6 segments at the beginning and end
// and on the resulting audio we slowly raise the volume on the first segment
// end decrease it on the last segment
- recording.postProcessSmoothTransition(info.channels, 0.01, 6);
+ recording.postProcessSmoothTransition(channels, 0.01, 6);
copier.begin(kit, recording); // start playback
}
@@ -40,18 +40,18 @@ void record_end(bool pinStatus, int pin, void* ref){
void setup(){
Serial.begin(115200);
while(!Serial); // wait for serial to be ready
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// setup input and output
auto cfg = kit.defaultConfig(RXTX_MODE);
cfg.sd_active = true;
cfg.copyFrom(info);
- cfg.input_device = ADC_INPUT_LINE2;
+ cfg.input_device = AUDIO_HAL_ADC_INPUT_LINE2;
kit.begin(cfg);
kit.setVolume(1.0);
// record when key 1 is pressed
- kit.audioActions().add(kit.getKey(1), record_start, record_end);
+ kit.audioActions().add(PIN_KEY1, record_start, record_end);
Serial.println("Press Key 1 to record");
}
diff --git a/examples/examples-audiokit/streams-audiokit-ram-ptichshift-audiokit/streams-audiokit-ram-ptichshift-audiokit.ino b/examples/examples-audiokit/streams-audiokit-ram-ptichshift-audiokit/streams-audiokit-ram-ptichshift-audiokit.ino
index 2f1070e699..a94172b980 100644
--- a/examples/examples-audiokit/streams-audiokit-ram-ptichshift-audiokit/streams-audiokit-ram-ptichshift-audiokit.ino
+++ b/examples/examples-audiokit/streams-audiokit-ram-ptichshift-audiokit/streams-audiokit-ram-ptichshift-audiokit.ino
@@ -11,12 +11,12 @@
*
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/AudioLibs/MemoryManager.h"
+#include "AudioLibs/AudioKit.h"
+#include "AudioLibs/MemoryManager.h"
AudioInfo info(16000, 1, 16);
MemoryManager memory(500); // Activate SPI RAM for objects > 500 bytes
-AudioBoardStream kit(AudioKitEs8388V1);
+AudioKitStream kit;
//use one of VariableSpeedRingBufferSimple, VariableSpeedRingBuffer, VariableSpeedRingBuffer180
PitchShiftOutput> pitch_shift(kit);
DynamicMemoryStream recording(false); // Audio stored on heap, non repeating
@@ -35,7 +35,7 @@ void record_end(bool pinStatus, int pin, void* ref){
// Remove popping noise, from button: we delete 6 segments at the beginning and end
// and on the resulting audio we slowly raise the volume on the first segment
// end decrease it on the last segment
- recording.postProcessSmoothTransition(info.channels, 0.01, 6);
+ recording.postProcessSmoothTransition(channels, 0.01, 6);
// output with pitch shifting
copier.begin(pitch_shift, recording); // start playback
@@ -44,13 +44,13 @@ void record_end(bool pinStatus, int pin, void* ref){
void setup(){
Serial.begin(115200);
while(!Serial); // wait for serial to be ready
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// setup input and output
auto cfg = kit.defaultConfig(RXTX_MODE);
cfg.sd_active = true;
cfg.copyFrom(info);
- cfg.input_device = ADC_INPUT_LINE2;
+ cfg.input_device = AUDIO_HAL_ADC_INPUT_LINE2;
kit.begin(cfg);
kit.setVolume(1.0);
@@ -62,14 +62,17 @@ void setup(){
pitch_shift.begin(cfg_pc);
// record when key 1 is pressed
- kit.audioActions().add(kit.getKey(1), record_start, record_end);
+ kit.audioActions().add(PIN_KEY1, record_start, record_end);
Serial.println("Press Key 1 to record");
+
}
void loop(){
+
// record or play recording
copier.copy();
// Process keys
kit.processActions();
+
}
diff --git a/examples/examples-audiokit/streams-audiokit-sd-audiokit/streams-audiokit-sd-audiokit.ino b/examples/examples-audiokit/streams-audiokit-sd-audiokit/streams-audiokit-sd-audiokit.ino
index 65a178757a..e0054c496b 100644
--- a/examples/examples-audiokit/streams-audiokit-sd-audiokit/streams-audiokit-sd-audiokit.ino
+++ b/examples/examples-audiokit/streams-audiokit-sd-audiokit/streams-audiokit-sd-audiokit.ino
@@ -10,13 +10,13 @@
*
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/AudioKit.h"
#include
#include
const char *file_name = "/rec.raw";
AudioInfo info(16000, 1, 16);
-AudioBoardStream kit(AudioKitEs8388V1);
+AudioKitStream kit;
File file; // final output stream
StreamCopy copier; // copies data
bool recording = false; // flag to make sure that close is only executed one
@@ -44,15 +44,7 @@ void record_end(bool pinStatus, int pin, void* ref){
void setup(){
Serial.begin(115200);
while(!Serial); // wait for serial to be ready
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
-
- // setup input and output: setup audiokit before SD!
- auto cfg = kit.defaultConfig(RXTX_MODE);
- cfg.sd_active = true;
- cfg.copyFrom(info);
- cfg.input_device = ADC_INPUT_LINE2;
- kit.begin(cfg);
- kit.setVolume(1.0);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
// Open SD drive
if (!SD.begin(PIN_AUDIO_KIT_SD_CARD_CS)) {
@@ -61,9 +53,16 @@ void setup(){
}
Serial.println("Initialization done.");
+ // setup input and output
+ auto cfg = kit.defaultConfig(RXTX_MODE);
+ cfg.sd_active = true;
+ cfg.copyFrom(info);
+ cfg.input_device = AUDIO_HAL_ADC_INPUT_LINE2;
+ kit.begin(cfg);
+ kit.setVolume(1.0);
// record when key 1 is pressed
- kit.audioActions().add(kit.getKey(1), record_start, record_end);
+ kit.audioActions().add(PIN_KEY1, record_start, record_end);
Serial.println("Press Key 1 to record");
}
diff --git a/examples/examples-audiokit/streams-audiokit-sd_wav/streams-audiokit-sd_wav.ino b/examples/examples-audiokit/streams-audiokit-sd_wav/streams-audiokit-sd_wav.ino
index 654dc39844..c415ae2dc5 100644
--- a/examples/examples-audiokit/streams-audiokit-sd_wav/streams-audiokit-sd_wav.ino
+++ b/examples/examples-audiokit/streams-audiokit-sd_wav/streams-audiokit-sd_wav.ino
@@ -13,11 +13,11 @@
#include
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/AudioKit.h"
const char* file_name = "/rec.wav";
AudioInfo info(16000, 1, 16);
-AudioBoardStream in(AudioKitEs8388V1);
+AudioKitStream in;
File file; // final output stream
EncodedAudioStream out(&file, new WAVEncoder());
StreamCopy copier(out, in); // copies data
@@ -26,13 +26,13 @@ uint64_t timeout;
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// setup input
auto cfg = in.defaultConfig(RX_MODE);
cfg.sd_active = true;
cfg.copyFrom(info);
- cfg.input_device = ADC_INPUT_LINE2; // microphone
+ cfg.input_device = AUDIO_HAL_ADC_INPUT_LINE2; // microphone
in.begin(cfg);
// Open SD drive
diff --git a/examples/examples-audiokit/streams-audiokit-serial/README.md b/examples/examples-audiokit/streams-audiokit-serial/README.md
index 10a2da3001..93eff73a8c 100644
--- a/examples/examples-audiokit/streams-audiokit-serial/README.md
+++ b/examples/examples-audiokit/streams-audiokit-serial/README.md
@@ -12,4 +12,4 @@ We implement a AudioKit source: We stream the sound input which we read in from
You need to install the following libraries:
- https://github.com/pschatzmann/arduino-audio-tools
-- https://github.com/pschatzmann/arduino-audio-driver
+- https://github.com/pschatzmann/arduino-audiokit
diff --git a/examples/examples-audiokit/streams-audiokit-serial/streams-audiokit-serial.ino b/examples/examples-audiokit/streams-audiokit-serial/streams-audiokit-serial.ino
index c0f0987b6a..910450eaaf 100644
--- a/examples/examples-audiokit/streams-audiokit-serial/streams-audiokit-serial.ino
+++ b/examples/examples-audiokit/streams-audiokit-serial/streams-audiokit-serial.ino
@@ -9,25 +9,23 @@
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/AudioKit.h"
-AudioInfo info(44100, 2, 16);
-AudioBoardStream kit(AudioKitEs8388V1); // Access I2S as stream
-CsvOutput csvOutput(Serial);
-StreamCopy copier(csvOutput, kit); // copy kit to csvOutput
+AudioKitStream kit; // Access I2S as stream
+CsvOutput csvStream(Serial);
+StreamCopy copier(csvStream, kit); // copy kit to csvStream
// Arduino Setup
void setup(void) {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
auto cfg = kit.defaultConfig(RX_MODE);
- cfg.copyFrom(info);
- cfg.input_device = ADC_INPUT_LINE2;
+ cfg.input_device = AUDIO_HAL_ADC_INPUT_LINE2;
kit.begin(cfg);
// make sure that we have the correct channels set up
- csvOutput.begin(info);
+ csvStream.begin();
}
diff --git a/examples/examples-audiokit/streams-audiokit-tf/README.md b/examples/examples-audiokit/streams-audiokit-tf/README.md
index 80157a08f9..3b25ab4bc4 100644
--- a/examples/examples-audiokit/streams-audiokit-tf/README.md
+++ b/examples/examples-audiokit/streams-audiokit-tf/README.md
@@ -22,5 +22,5 @@ The log level has been set to Info to help you to identify any problems. Please
You need to install the following libraries:
- https://github.com/pschatzmann/arduino-audio-tools
-- https://github.com/pschatzmann/arduino-audio-driver
+- https://github.com/pschatzmann/arduino-audiokit
- https://github.com/pschatzmann/tflite-micro-arduino-examples
\ No newline at end of file
diff --git a/examples/examples-audiokit/streams-audiokit-tf/streams-audiokit-tf.ino b/examples/examples-audiokit/streams-audiokit-tf/streams-audiokit-tf.ino
index 509011b157..8cc39d8dd1 100644
--- a/examples/examples-audiokit/streams-audiokit-tf/streams-audiokit-tf.ino
+++ b/examples/examples-audiokit/streams-audiokit-tf/streams-audiokit-tf.ino
@@ -1,10 +1,10 @@
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/AudioLibs/TfLiteAudioStream.h"
+#include "AudioLibs/AudioKit.h"
+#include "AudioLibs/TfLiteAudioStream.h"
#include "model.h" // tensorflow model
-AudioBoardStream kit(AudioKitEs8388V1); // Audio source
+AudioKitStream kit; // Audio source
TfLiteAudioStream tfl; // Audio sink
const char* kCategoryLabels[4] = {
"silence",
@@ -28,15 +28,15 @@ void respondToCommand(const char* found_command, uint8_t score,
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
// setup Audiokit
auto cfg = kit.defaultConfig(RX_MODE);
- cfg.input_device = ADC_INPUT_LINE2;
+ cfg.input_device = AUDIO_HAL_ADC_INPUT_LINE2;
cfg.channels = channels;
cfg.sample_rate = samples_per_second;
cfg.use_apll = false;
- //cfg.auto_clear = true;
+ cfg.auto_clear = true;
cfg.buffer_size = 512;
cfg.buffer_count = 16;
kit.begin(cfg);
diff --git a/examples/examples-communication/http-server/streams-audiokit-webserver_aac/streams-audiokit-webserver_aac.ino b/examples/examples-audiokit/streams-audiokit-webserver_aac/streams-audiokit-webserver_aac.ino
similarity index 52%
rename from examples/examples-communication/http-server/streams-audiokit-webserver_aac/streams-audiokit-webserver_aac.ino
rename to examples/examples-audiokit/streams-audiokit-webserver_aac/streams-audiokit-webserver_aac.ino
index f5cf208039..f282174fbc 100644
--- a/examples/examples-communication/http-server/streams-audiokit-webserver_aac/streams-audiokit-webserver_aac.ino
+++ b/examples/examples-audiokit/streams-audiokit-webserver_aac/streams-audiokit-webserver_aac.ino
@@ -8,42 +8,41 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/AudioCodecs/CodecAACFDK.h"
+#include "AudioLibs/AudioKit.h"
+#include "AudioCodecs/CodecAACFDK.h"
-// WIFI
-const char *ssid = "ssid";
-const char *password = "password";
-
-AudioInfo info(16000,1,16);
-AACEncoderFDK fdk;
-AudioEncoderServer server(&fdk, ssid, password);
-AudioBoardStream kit(AudioKitEs8388V1);
+AudioKitStream kit;
+AACEncoderFDK *fdk=nullptr;
+AudioEncoderServer *server=nullptr;
// Arduino setup
void setup(){
Serial.begin(115200);
// Defining Loglevels for the different libraries
- //AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ //AudioLogger::instance().begin(Serial, AudioLogger::Info);
//LOGLEVEL_FDK = FDKInfo;
//LOGLEVEL_AUDIOKIT = AudioKitInfo;
- // setup and configure fdk (not necessary if you activate PSRAM)
- fdk.setAudioObjectType(2); // AAC low complexity
- fdk.setOutputBufferSize(1024); // decrease output buffer size
- fdk.setVariableBitrateMode(2); // low variable bitrate
+ // setup and configure fdk
+ fdk = new AACEncoderFDK();
+ fdk->setAudioObjectType(2); // AAC low complexity
+ fdk->setOutputBufferSize(1024); // decrease output buffer size
+ fdk->setVariableBitrateMode(2); // low variable bitrate
+ server = new AudioEncoderServer(fdk,"WIFI","password");
// start i2s input with default configuration
Serial.println("starting AudioKit...");
auto config = kit.defaultConfig(RX_MODE);
- config.input_device = ADC_INPUT_LINE2;
- config.copyFrom(info);
+ config.input_device = AUDIO_HAL_ADC_INPUT_LINE2;
+ config.sample_rate = 44100;
+ config.default_actions_active = false;
+ config.channels = 2;
config.sd_active = false;
kit.begin(config);
Serial.println("AudioKit started");
// start data sink
- server.begin(kit, info);
+ server->begin(kit, config);
Serial.println("Server started");
}
@@ -51,5 +50,5 @@ void setup(){
// Arduino loop
void loop() {
// Handle new connections
- server.doLoop();
+ server->doLoop();
}
diff --git a/examples/examples-communication/http-server/streams-audiokit-webserver_wav/streams-audiokit-webserver_wav.ino b/examples/examples-audiokit/streams-audiokit-webserver_wav/streams-audiokit-webserver_wav.ino
similarity index 79%
rename from examples/examples-communication/http-server/streams-audiokit-webserver_wav/streams-audiokit-webserver_wav.ino
rename to examples/examples-audiokit/streams-audiokit-webserver_wav/streams-audiokit-webserver_wav.ino
index 0bc0a7a35d..3868d22f7b 100644
--- a/examples/examples-communication/http-server/streams-audiokit-webserver_wav/streams-audiokit-webserver_wav.ino
+++ b/examples/examples-audiokit/streams-audiokit-webserver_wav/streams-audiokit-webserver_wav.ino
@@ -8,20 +8,20 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/AudioKit.h"
AudioEncoderServer server(new WAVEncoder(),"ssid","password");
-AudioBoardStream kit(AudioKitEs8388V1);
+AudioKitStream kit;
// Arduino setup
void setup(){
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
// start i2s input with default configuration
Serial.println("starting AudioKit...");
auto config = kit.defaultConfig(RX_MODE);
- config.input_device = ADC_INPUT_LINE1;
+ config.input_device = AUDIO_HAL_ADC_INPUT_LINE1;
config.sample_rate = 44100;
config.sd_active = false;
kit.begin(config);
diff --git a/examples/examples-audiokit/streams-file_loop-audiokit/streams-file_loop-audiokit.ino b/examples/examples-audiokit/streams-file_loop-audiokit/streams-file_loop-audiokit.ino
index 3e9649bb5b..a0324f7448 100644
--- a/examples/examples-audiokit/streams-file_loop-audiokit/streams-file_loop-audiokit.ino
+++ b/examples/examples-audiokit/streams-file_loop-audiokit/streams-file_loop-audiokit.ino
@@ -11,20 +11,20 @@
#include
#include
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/Disk/FileLoop.h"
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
+#include "AudioLibs/AudioKit.h"
+#include "AudioLibs/FileLoop.h"
+#include "AudioCodecs/CodecMP3Helix.h"
const int chipSelect=PIN_AUDIO_KIT_SD_CARD_CS;
-AudioBoardStream i2s(AudioKitEs8388V1); // final output of decoded stream
+AudioKitStream i2s; // final output of decoded stream
EncodedAudioStream decoder(&i2s, new MP3DecoderHelix()); // Decoding stream
FileLoop loopingFile;
StreamCopy copier(decoder, loopingFile);
void setup(){
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// setup audiokit before SD!
auto config = i2s.defaultConfig(TX_MODE);
@@ -37,7 +37,6 @@ void setup(){
//loopingFile.setLoopCount(-1); // define loop count
//audioFile.setStartPos(44); // restart from pos 44
//if ((audioFile.size()-44) % 1024!=0) audioFile.setSize((((audioFile.size()-44)/1024)+1)*1024+44);
- loopingFile.begin();
// setup I2S based on sampling rate provided by decoder
decoder.begin();
diff --git a/examples/examples-audiokit/streams-generator-audiokit/streams-generator-audiokit.ino b/examples/examples-audiokit/streams-generator-audiokit/streams-generator-audiokit.ino
index b26d95ea2f..eeb713e28f 100644
--- a/examples/examples-audiokit/streams-generator-audiokit/streams-generator-audiokit.ino
+++ b/examples/examples-audiokit/streams-generator-audiokit/streams-generator-audiokit.ino
@@ -6,19 +6,19 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/AudioKit.h"
AudioInfo info(32000, 2, 16);
SineWaveGenerator sineWave(32000); // subclass of SoundGenerator with max amplitude of 32000
GeneratedSoundStream sound(sineWave); // Stream generated from sine wave
-AudioBoardStream out(AudioKitEs8388V1);
+AudioKitStream out;
StreamCopy copier(out, sound); // copies sound into i2s
// Arduino Setup
void setup(void) {
// Open Serial
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// start I2S
Serial.println("starting I2S...");
diff --git a/examples/examples-audiokit/streams-generator_fromarray-audiokit/streams-generator_fromarray-audiokit.ino b/examples/examples-audiokit/streams-generator_fromarray-audiokit/streams-generator_fromarray-audiokit.ino
index 0916c9feaa..71b0afced3 100644
--- a/examples/examples-audiokit/streams-generator_fromarray-audiokit/streams-generator_fromarray-audiokit.ino
+++ b/examples/examples-audiokit/streams-generator_fromarray-audiokit/streams-generator_fromarray-audiokit.ino
@@ -6,13 +6,13 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/AudioKit.h"
AudioInfo info(44100, 2, 16);
int16_t sine_array[] = {0, 2285, 4560, 6812, 9031, 11206, 13327, 15383, 17363, 19259, 21062, 22761, 24350, 25820, 27165, 28377, 29450, 30381, 31163, 31793, 32269, 32587, 32747, 32747, 32587, 32269, 31793, 31163, 30381, 29450, 28377, 27165, 25820, 24350, 22761, 21062, 19259, 17363, 15383, 13327, 11206, 9031, 6812, 4560, 2285, 0, -2285, -4560, -6812, -9031, -11206, -13327, -15383, -17363, -19259, -21062, -22761, -24350, -25820, -27165, -28377, -29450, -30381, -31163, -31793, -32269, -32587, -32747, -32747, -32587, -32269, -31793, -31163, -30381, -29450, -28377, -27165, -25820, -24350, -22761, -21062, -19259, -17363, -15383, -13327, -11206, -9031, -6812, -4560, -2285 };
GeneratorFromArray sineWave(sine_array,0,false);
GeneratedSoundStream sound(sineWave); // Stream generated from sine wave
-AudioBoardStream out(AudioKitEs8388V1);
+AudioKitStream out;
StreamCopy copier(out, sound); // copies sound into i2s
@@ -20,7 +20,7 @@ StreamCopy copier(out, sound); // copies sound into
void setup(void) {
// Open Serial
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
// start I2S
Serial.println("starting I2S...");
diff --git a/examples/examples-audiokit/streams-generator_inputmixer-audiokit/streams-generator_inputmixer-audiokit.ino b/examples/examples-audiokit/streams-generator_inputmixer-audiokit/streams-generator_inputmixer-audiokit.ino
index 59ffc5d4fe..071ed9d483 100644
--- a/examples/examples-audiokit/streams-generator_inputmixer-audiokit/streams-generator_inputmixer-audiokit.ino
+++ b/examples/examples-audiokit/streams-generator_inputmixer-audiokit/streams-generator_inputmixer-audiokit.ino
@@ -6,7 +6,7 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/AudioKit.h"
AudioInfo info(32000, 2, 16);
SineWaveGenerator sineWave1(32000); // subclass of SoundGenerator with max amplitude of 32000
@@ -14,14 +14,15 @@ SineWaveGenerator sineWave2(32000); // subclass of Sound
GeneratedSoundStream sound1(sineWave1); // Stream generated from sine wave
GeneratedSoundStream sound2(sineWave2); // Stream generated from sine wave
InputMixer mixer;
-AudioBoardStream out(AudioKitEs8388V1);
+AudioKitStream out;
StreamCopy copier(out, mixer); // copies sound into i2s
+AudioInfo info;
// Arduino Setup
void setup(void) {
// Open Serial
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// start I2S
Serial.println("starting I2S...");
diff --git a/examples/examples-audiokit/streams-generator_outputmixer-audiokit/streams-generator_outputmixer-audiokit.ino b/examples/examples-audiokit/streams-generator_outputmixer-audiokit/streams-generator_outputmixer-audiokit.ino
index 1def1bfdeb..6d01af6fd4 100644
--- a/examples/examples-audiokit/streams-generator_outputmixer-audiokit/streams-generator_outputmixer-audiokit.ino
+++ b/examples/examples-audiokit/streams-generator_outputmixer-audiokit/streams-generator_outputmixer-audiokit.ino
@@ -6,23 +6,24 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/AudioKit.h"
AudioInfo info(32000, 2, 16);
SineWaveGenerator sineWave1(32000); // subclass of SoundGenerator with max amplitude of 32000
SineWaveGenerator sineWave2(32000); // subclass of SoundGenerator with max amplitude of 32000
GeneratedSoundStream sound1(sineWave1); // Stream generated from sine wave
GeneratedSoundStream sound2(sineWave2); // Stream generated from sine wave
-AudioBoardStream out(AudioKitEs8388V1);
-OutputMixer mixer(out, 2); // output mixer with 2 outputs mixing to AudioBoardStream
+AudioKitStream out;
+OutputMixer mixer(out, 2); // output mixer with 2 outputs mixing to AudioKitStream
StreamCopy copier1(mixer, sound1); // copies sound into mixer
StreamCopy copier2(mixer, sound2); // copies sound into mixer
+AudioInfo info;
// Arduino Setup
void setup(void) {
// Open Serial
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
// start I2S
Serial.println("starting I2S...");
diff --git a/examples/examples-audiokit/streams-generator_sinfromtable-audiokit/streams-generator_sinfromtable-audiokit.ino b/examples/examples-audiokit/streams-generator_sinfromtable-audiokit/streams-generator_sinfromtable-audiokit.ino
index 1a5b5c7ea8..e0720fa08e 100644
--- a/examples/examples-audiokit/streams-generator_sinfromtable-audiokit/streams-generator_sinfromtable-audiokit.ino
+++ b/examples/examples-audiokit/streams-generator_sinfromtable-audiokit/streams-generator_sinfromtable-audiokit.ino
@@ -6,12 +6,12 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/AudioKit.h"
AudioInfo info(32000, 2, 16);
SineFromTable sineWave(32000); // subclass of SoundGenerator with max amplitude of 32000
GeneratedSoundStream sound(sineWave); // Stream generated from sine wave
-AudioBoardStream out(AudioKitEs8388V1);
+AudioKitStream out;
//CsvOutput out(Serial);
int sound_len=1024;
StreamCopy copier(out, sound, sound_len); // copies sound into i2s
@@ -21,7 +21,7 @@ int freq = 122;
void setup(void) {
// Open Serial
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
// start I2S
Serial.println("starting I2S...");
diff --git a/examples/examples-audiokit/streams-memory_mp3-audiokit/streams-memory_mp3-audiokit.ino b/examples/examples-audiokit/streams-memory_mp3-audiokit/streams-memory_mp3-audiokit.ino
index b58e537787..6d97696355 100644
--- a/examples/examples-audiokit/streams-memory_mp3-audiokit/streams-memory_mp3-audiokit.ino
+++ b/examples/examples-audiokit/streams-memory_mp3-audiokit/streams-memory_mp3-audiokit.ino
@@ -10,19 +10,19 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioCodecs/CodecMP3Helix.h"
+#include "AudioLibs/AudioKit.h"
#include "zero.h"
MemoryStream mp3(zero_mp3, zero_mp3_len);
-AudioBoardStream i2s(AudioKitEs8388V1);
+AudioKitStream i2s;
MP3DecoderHelix helix;
EncodedAudioStream out(&i2s, &helix); // output to decoder
StreamCopy copier(out, mp3); // copy in to i2s
void setup(){
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// begin processing
auto cfg = i2s.defaultConfig();
diff --git a/examples/examples-audiokit/streams-memory_pcm-mixer-audiokit/streams-memory_pcm-mixer-audiokit.ino b/examples/examples-audiokit/streams-memory_pcm-mixer-audiokit/streams-memory_pcm-mixer-audiokit.ino
index 8d8e9c94d2..d492b640ff 100644
--- a/examples/examples-audiokit/streams-memory_pcm-mixer-audiokit/streams-memory_pcm-mixer-audiokit.ino
+++ b/examples/examples-audiokit/streams-memory_pcm-mixer-audiokit/streams-memory_pcm-mixer-audiokit.ino
@@ -9,19 +9,17 @@
*
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/AudioKit.h"
#include "drums.h"
#include "guitar.h"
InputMixer mixer;
-AudioBoardStream kit(AudioKitEs8388V1);
+AudioKitStream kit;
MemoryStream drums(drums_raw, drums_raw_len);
MemoryStream guitar(guitar_raw, guitar_raw_len);
StreamCopy copier(kit, mixer);
void setup() {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
// auto restart when MemoryStream has ended
drums.setLoop(true);
diff --git a/examples/examples-audiokit/streams-pins-audiokit/README.md b/examples/examples-audiokit/streams-pins-audiokit/README.md
index d4afb88957..f8097ca8e1 100644
--- a/examples/examples-audiokit/streams-pins-audiokit/README.md
+++ b/examples/examples-audiokit/streams-pins-audiokit/README.md
@@ -13,6 +13,6 @@ You just need to define you __handler methods__ (button1, button2...) and assign
You need to install the following libraries:
- [Arduino Audio Tools](https://github.com/pschatzmann/arduino-audio-tools)
-- [Audio Driver](https://github.com/pschatzmann/arduino-audio-driver)
+- [AudioKit](https://github.com/pschatzmann/arduino-audiokit)
- [FLITE](https://github.com/pschatzmann/arduino-flite)
diff --git a/examples/examples-audiokit/streams-pins-audiokit/streams-pins-audiokit.ino b/examples/examples-audiokit/streams-pins-audiokit/streams-pins-audiokit.ino
index f285a09a1b..7ec8e1ec6f 100644
--- a/examples/examples-audiokit/streams-pins-audiokit/streams-pins-audiokit.ino
+++ b/examples/examples-audiokit/streams-pins-audiokit/streams-pins-audiokit.ino
@@ -7,10 +7,10 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/AudioKit.h"
#include "flite_arduino.h"
-AudioBoardStream kit(AudioKitEs8388V1);
+AudioKitStream kit;
Flite flite(kit);
void button1(bool, int, void*) { flite.say("Button One"); }
@@ -21,7 +21,7 @@ void button4(bool, int, void*) { flite.say("Button Four"); }
// Arduino setup
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
//AUDIOKIT_LOG_LEVEL = AudioKitDebug;
auto cfg = kit.defaultConfig(TX_MODE);
@@ -32,16 +32,16 @@ void setup() {
kit.begin(cfg);
// Assign pins to methods
- kit.addAction(kit.getKey(1), button1);
- kit.addAction(kit.getKey(2), button2);
- kit.addAction(kit.getKey(3), button3);
- kit.addAction(kit.getKey(4), button4);
+ kit.addAction(PIN_KEY1, button1);
+ kit.addAction(PIN_KEY2, button2);
+ kit.addAction(PIN_KEY3, button3);
+ kit.addAction(PIN_KEY4, button4);
// example with actions using lambda expression
- auto down = [](bool,int,void*) { AudioBoardStream::actionVolumeDown(true, -1, nullptr); flite.say("Volume down"); };
- kit.addAction(kit.getKey(5), down);
- auto up = [](bool,int,void*) { AudioBoardStream::actionVolumeUp(true, -1, nullptr ); flite.say("Volume up"); };
- kit.addAction(kit.getKey(6), up);
+ auto down = [](bool,int,void*) { AudioKitStream::actionVolumeDown(true, -1, nullptr); flite.say("Volume down"); };
+ kit.addAction(PIN_KEY5, down);
+ auto up = [](bool,int,void*) { AudioKitStream::actionVolumeUp(true, -1, nullptr ); flite.say("Volume up"); };
+ kit.addAction(PIN_KEY6, up);
flite.say("Please push a button");
}
diff --git a/examples/examples-audiokit/streams-sd_mp3-audiokit/streams-sd_mp3-audiokit.ino b/examples/examples-audiokit/streams-sd-audiokit/streams-sd-audiokit.ino
similarity index 78%
rename from examples/examples-audiokit/streams-sd_mp3-audiokit/streams-sd_mp3-audiokit.ino
rename to examples/examples-audiokit/streams-sd-audiokit/streams-sd-audiokit.ino
index 65ccb94081..27b39f39ac 100644
--- a/examples/examples-audiokit/streams-sd_mp3-audiokit/streams-sd_mp3-audiokit.ino
+++ b/examples/examples-audiokit/streams-sd-audiokit/streams-sd-audiokit.ino
@@ -11,19 +11,19 @@
#include
#include
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
+#include "AudioLibs/AudioKit.h"
+#include "AudioCodecs/CodecMP3Helix.h"
const int chipSelect=PIN_AUDIO_KIT_SD_CARD_CS;
-AudioBoardStream i2s(AudioKitEs8388V1); // final output of decoded stream
+AudioKitStream i2s; // final output of decoded stream
EncodedAudioStream decoder(&i2s, new MP3DecoderHelix()); // Decoding stream
StreamCopy copier;
File audioFile;
void setup(){
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// setup audiokit before SD!
auto config = i2s.defaultConfig(TX_MODE);
@@ -38,6 +38,7 @@ void setup(){
decoder.begin();
// begin copy
+ copier.setCheckAvailableForWrite(false);
copier.begin(decoder, audioFile);
}
diff --git a/examples/examples-audiokit/streams-sd_flac-audiokit/streams-sd_flac-audiokit.ino b/examples/examples-audiokit/streams-sd_flac-audiokit/streams-sd_flac-audiokit.ino
deleted file mode 100644
index 39009c8835..0000000000
--- a/examples/examples-audiokit/streams-sd_flac-audiokit/streams-sd_flac-audiokit.ino
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * @file streams-sd-audiokit.ino
- * @author Phil Schatzmann
- * @brief Just a small demo, how to use files with the SD library with a streaming decoder
- * @version 0.1
- * @date 2022-10-09
- *
- * @copyright Copyright (c) 2022
- *
- */
-#include
-#include
-#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/AudioCodecs/CodecFLAC.h"
-
-
-const int chipSelect=PIN_AUDIO_KIT_SD_CARD_CS;
-AudioBoardStream i2s(AudioKitEs8388V1); // final output of decoded stream
-FLACDecoder dec;
-File audioFile;
-
-void setup(){
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- // setup audiokit before SD!
- auto config = i2s.defaultConfig(TX_MODE);
- config.sd_active = true;
- i2s.begin(config);
-
- // setup file
- SD.begin(chipSelect);
- audioFile = SD.open("/flac/test2.flac");
-
- // setup decoder
- dec.setInput(audioFile);
- dec.setOutput(i2s);
- dec.begin();
-
-}
-
-void loop(){
- dec.copy();
-}
\ No newline at end of file
diff --git a/examples/examples-audiokit/streams-sd_m4a-audiokit/streams-sd_m4a-audiokit.ino b/examples/examples-audiokit/streams-sd_m4a-audiokit/streams-sd_m4a-audiokit.ino
deleted file mode 100644
index 49269acd09..0000000000
--- a/examples/examples-audiokit/streams-sd_m4a-audiokit/streams-sd_m4a-audiokit.ino
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
-* @file streams-sd_m4a-audiokit.ino
-* @author Peter Schatzmann
-* @brief Example for decoding M4A files on the AudioKit using the AudioBoardStream
-* @version 0.1
-* @date 2023-10-01
-*/
-
-#include "AudioTools.h"
-#include "AudioTools/AudioCodecs/CodecALAC.h"
-#include "AudioTools/AudioCodecs/CodecAACHelix.h"
-#include "AudioTools/AudioCodecs/ContainerM4A.h"
-#include "AudioTools/AudioCodecs/MultiDecoder.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h" // install https://github.com/pschatzmann/arduino-audio-driver
-#include "SD.h"
-
-MultiDecoder multi_decoder;
-ContainerM4A dec_m4a(multi_decoder);
-AACDecoderHelix dec_aac;
-DecoderALAC dec_alac;
-AudioBoardStream out(AudioKitEs8388V1);
-EncodedAudioOutput decoder_output(&out, &dec_m4a);
-File file;
-StreamCopy copier(decoder_output, file);
-
-void setup() {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- // start AudioBoard with setup of CD pins
- auto cfg = out.defaultConfig(TX_MODE);
- cfg.sd_active = true;
- if (!out.begin(cfg)){
- Serial.println("Failed to start CSV output!");
- return;
- }
-
- if (!SD.begin(PIN_AUDIO_KIT_SD_CARD_CS)){
- Serial.println("SD Card initialization failed!");
- return;
- }
-
- file = SD.open("/m4a/aac.m4a");
- if (!file) {
- Serial.println("Failed to open file!");
- return;
- }
-
- // mp4 supports alac and aac
- multi_decoder.addDecoder(dec_alac,"audio/alac");
- multi_decoder.addDecoder(dec_aac,"audio/aac");
-
- // start decoder output
- if(!decoder_output.begin()) {
- Serial.println("Failed to start decoder output!");
- return;
- }
-
- Serial.println("M4A decoding started...");
-}
-
-
-void loop() {
- copier.copy();
-}
\ No newline at end of file
diff --git a/examples/examples-audiokit/streams-sdmmc_wav-audiokit/streams-sdmmc_wav-audiokit.ino b/examples/examples-audiokit/streams-sdmmc_wav-audiokit/streams-sdmmc_wav-audiokit.ino
deleted file mode 100644
index 31a6a2d2d9..0000000000
--- a/examples/examples-audiokit/streams-sdmmc_wav-audiokit/streams-sdmmc_wav-audiokit.ino
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * @file streams-sdmmc_wav-audiokit.ino
- * @author Phil Schatzmann
- * @brief A simple example that shows how to play (eg. a 24bit) wav file
- * @date 2021-11-07
- *
- * @copyright Copyright (c) 2021
- */
-
-
-#include "FS.h"
-#include "SD_MMC.h"
-#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-
-AudioBoardStream i2s(AudioKitEs8388V1);
-WAVDecoder wav;
-EncodedAudioStream encoded(&i2s, &wav); // Decoding stream
-File audioFile;
-StreamCopy copier(encoded, audioFile);
-
-void setup(){
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
-
- // setup audiokit before SD!
- auto config = i2s.defaultConfig(TX_MODE);
- config.sd_active = false;
- i2s.begin(config);
- i2s.setVolume(1.0);
-
- // open sdmmc
- if (!SD_MMC.begin("/sdcard", false)){
- Serial.println("SD_MMC Error");
- stop();
- }
- // open file
- audioFile = SD_MMC.open("/wav24/test.wav");
- if (!audioFile){
- Serial.println("File does not exist");
- stop();
- }
-
- // start decoder stream
- encoded.begin();
-}
-
-void loop(){
- copier.copy();
-}
\ No newline at end of file
diff --git a/examples/examples-communication/a2dp/streams-synth-a2dp/README.md b/examples/examples-audiokit/streams-synth-a2dp/README.md
similarity index 100%
rename from examples/examples-communication/a2dp/streams-synth-a2dp/README.md
rename to examples/examples-audiokit/streams-synth-a2dp/README.md
diff --git a/examples/examples-communication/a2dp/streams-synth-a2dp/streams-synth-a2dp.ino b/examples/examples-audiokit/streams-synth-a2dp/streams-synth-a2dp.ino
similarity index 66%
rename from examples/examples-communication/a2dp/streams-synth-a2dp/streams-synth-a2dp.ino
rename to examples/examples-audiokit/streams-synth-a2dp/streams-synth-a2dp.ino
index 37a24e15a3..6b5be3eb4a 100644
--- a/examples/examples-communication/a2dp/streams-synth-a2dp/streams-synth-a2dp.ino
+++ b/examples/examples-audiokit/streams-synth-a2dp/streams-synth-a2dp.ino
@@ -6,17 +6,17 @@
*/
#define USE_MIDI
-#include "AudioTools.h" // must be first
-#include "AudioTools/AudioLibs/AudioBoardStream.h" // https://github.com/pschatzmann/arduino-audio-driver
-#include "BluetoothA2DPSource.h" // https://github.com/pschatzmann/ESP32-A2DP
+#include "BluetoothA2DPSource.h"
+#include "AudioTools.h"
+#include "AudioLibs/AudioKit.h"
BluetoothA2DPSource a2dp_source;
int channels = 2;
-AudioBoardStream kit(AudioKitEs8388V1);
+AudioKitStream kit;
Synthesizer synthesizer;
GeneratedSoundStream in(synthesizer);
-SynthesizerKey keys[] = {{kit.getKey(1), N_C3},{kit.getKey(2), N_D3},{kit.getKey(3), N_E3},{kit.getKey(4), N_F3},{kit.getKey(5), N_G3},{kit.getKey(6), N_A3},{0,0}};
+SynthesizerKey keys[] = {{PIN_KEY1, N_C3},{PIN_KEY2, N_D3},{PIN_KEY3, N_E3},{PIN_KEY4, N_F3},{PIN_KEY5, N_G3},{PIN_KEY6, N_A3},{0,0}};
int32_t get_sound_data(Frame *data, int32_t frameCount) {
int frame_size = sizeof(int16_t)*channels;
@@ -41,8 +41,7 @@ void setup() {
cfg.sample_rate = 44100;
in.begin(cfg);
- a2dp_source.set_data_callback_in_frames(get_sound_data);
- a2dp_source.start("LEXON MINO L");
+ a2dp_source.start("LEXON MINO L", get_sound_data);
a2dp_source.set_volume(20);
}
diff --git a/examples/examples-audiokit/streams-synth-audiokit/streams-synth-audiokit.ino b/examples/examples-audiokit/streams-synth-audiokit/streams-synth-audiokit.ino
index 5a10942501..70e8a54191 100644
--- a/examples/examples-audiokit/streams-synth-audiokit/streams-synth-audiokit.ino
+++ b/examples/examples-audiokit/streams-synth-audiokit/streams-synth-audiokit.ino
@@ -6,13 +6,13 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/AudioKit.h"
-AudioBoardStream kit(AudioKitEs8388V1);
+AudioKitStream kit;
Synthesizer synthesizer;
GeneratedSoundStream in(synthesizer);
StreamCopy copier(kit, in);
-SynthesizerKey keys[] = {{kit.getKey(1), N_C3},{kit.getKey(2), N_D3},{kit.getKey(3), N_E3},{kit.getKey(4), N_F3},{kit.getKey(5), N_G3},{kit.getKey(6), N_A3},{0,0}};
+SynthesizerKey keys[] = {{PIN_KEY1, N_C3},{PIN_KEY2, N_D3},{PIN_KEY3, N_E3},{PIN_KEY4, N_F3},{PIN_KEY5, N_G3},{PIN_KEY6, N_A3},{0,0}};
void setup() {
Serial.begin(115200);
diff --git a/examples/examples-audiokit/streams-synthbasic1-audiokit/streams-synthbasic1-audiokit.ino b/examples/examples-audiokit/streams-synthbasic1-audiokit/streams-synthbasic1-audiokit.ino
index bb627585d8..fd1cbe3f55 100644
--- a/examples/examples-audiokit/streams-synthbasic1-audiokit/streams-synthbasic1-audiokit.ino
+++ b/examples/examples-audiokit/streams-synthbasic1-audiokit/streams-synthbasic1-audiokit.ino
@@ -6,9 +6,9 @@
*
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/AudioKit.h"
-AudioBoardStream kit(AudioKitEs8388V1);
+AudioKitStream kit;
SineWaveGenerator sine;
GeneratedSoundStream in(sine);
StreamCopy copier(kit, in);
@@ -28,12 +28,12 @@ void setupActions(){
// assign buttons to notes
auto act_low = AudioActions::ActiveLow;
static float note[] = {N_C3, N_D3, N_E3, N_F3, N_G3, N_A3}; // frequencies
- kit.audioActions().add(kit.getKey(1), actionKeyOn, actionKeyOff, act_low, &(note[0])); // C3
- kit.audioActions().add(kit.getKey(2), actionKeyOn, actionKeyOff, act_low, &(note[1])); // D3
- kit.audioActions().add(kit.getKey(3), actionKeyOn, actionKeyOff, act_low, &(note[2])); // E3
- kit.audioActions().add(kit.getKey(4), actionKeyOn, actionKeyOff, act_low, &(note[3])); // F3
- kit.audioActions().add(kit.getKey(5), actionKeyOn, actionKeyOff, act_low, &(note[4])); // G3
- kit.audioActions().add(kit.getKey(6), actionKeyOn, actionKeyOff, act_low, &(note[5])); // A3
+ kit.audioActions().add(PIN_KEY1, actionKeyOn, actionKeyOff, act_low, &(note[0])); // C3
+ kit.audioActions().add(PIN_KEY2, actionKeyOn, actionKeyOff, act_low, &(note[1])); // D3
+ kit.audioActions().add(PIN_KEY3, actionKeyOn, actionKeyOff, act_low, &(note[2])); // E3
+ kit.audioActions().add(PIN_KEY4, actionKeyOn, actionKeyOff, act_low, &(note[3])); // F3
+ kit.audioActions().add(PIN_KEY5, actionKeyOn, actionKeyOff, act_low, &(note[4])); // G3
+ kit.audioActions().add(PIN_KEY6, actionKeyOn, actionKeyOff, act_low, &(note[5])); // A3
}
void setup() {
diff --git a/examples/examples-audiokit/streams-synthbasic2-audiokit/streams-synthbasic2-audiokit.ino b/examples/examples-audiokit/streams-synthbasic2-audiokit/streams-synthbasic2-audiokit.ino
index d9a0f66e00..f944c04534 100644
--- a/examples/examples-audiokit/streams-synthbasic2-audiokit/streams-synthbasic2-audiokit.ino
+++ b/examples/examples-audiokit/streams-synthbasic2-audiokit/streams-synthbasic2-audiokit.ino
@@ -7,9 +7,9 @@
*
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/AudioKit.h"
-AudioBoardStream kit(AudioKitEs8388V1);
+AudioKitStream kit;
SineWaveGenerator sine;
GeneratedSoundStream sine_stream(sine);
AudioEffectStream effects(sine_stream);
@@ -33,12 +33,12 @@ void setupActions(){
// assign buttons to notes
auto act_low = AudioActions::ActiveLow;
static float note[] = {N_C3, N_D3, N_E3, N_F3, N_G3, N_A3}; // frequencies
- kit.audioActions().add(kit.getKey(1), actionKeyOn, actionKeyOff, act_low, &(note[0])); // C3
- kit.audioActions().add(kit.getKey(2), actionKeyOn, actionKeyOff, act_low, &(note[1])); // D3
- kit.audioActions().add(kit.getKey(3), actionKeyOn, actionKeyOff, act_low, &(note[2])); // E3
- kit.audioActions().add(kit.getKey(4), actionKeyOn, actionKeyOff, act_low, &(note[3])); // F3
- kit.audioActions().add(kit.getKey(5), actionKeyOn, actionKeyOff, act_low, &(note[4])); // G3
- kit.audioActions().add(kit.getKey(6), actionKeyOn, actionKeyOff, act_low, &(note[5])); // A3
+ kit.audioActions().add(PIN_KEY1, actionKeyOn, actionKeyOff, act_low, &(note[0])); // C3
+ kit.audioActions().add(PIN_KEY2, actionKeyOn, actionKeyOff, act_low, &(note[1])); // D3
+ kit.audioActions().add(PIN_KEY3, actionKeyOn, actionKeyOff, act_low, &(note[2])); // E3
+ kit.audioActions().add(PIN_KEY4, actionKeyOn, actionKeyOff, act_low, &(note[3])); // F3
+ kit.audioActions().add(PIN_KEY5, actionKeyOn, actionKeyOff, act_low, &(note[4])); // G3
+ kit.audioActions().add(PIN_KEY6, actionKeyOn, actionKeyOff, act_low, &(note[5])); // A3
}
void setup() {
diff --git a/examples/examples-audiokit/streams-synthbasic3-audiokit/streams-synthbasic3-audiokit.ino b/examples/examples-audiokit/streams-synthbasic3-audiokit/streams-synthbasic3-audiokit.ino
index a6a693cd64..957d8ffb11 100644
--- a/examples/examples-audiokit/streams-synthbasic3-audiokit/streams-synthbasic3-audiokit.ino
+++ b/examples/examples-audiokit/streams-synthbasic3-audiokit/streams-synthbasic3-audiokit.ino
@@ -8,14 +8,14 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/AudioKit.h"
#include
SineWaveGenerator sine;
GeneratedSoundStream sine_stream(sine);
ADSRGain adsr(0.0001,0.0001, 0.9 , 0.0002);
AudioEffectStream effects(sine_stream);
-AudioBoardStream kit(AudioKitEs8388V1);
+AudioKitStream kit;
StreamCopy copier(kit, effects);
class SynthAction : public MidiAction {
@@ -52,12 +52,12 @@ void setupActions(){
// assign buttons to notes
auto act_low = AudioActions::ActiveLow;
static float note[] = {N_C3, N_D3, N_E3, N_F3, N_G3, N_A3}; // frequencies
- kit.audioActions().add(kit.getKey(1), actionKeyOn, actionKeyOff, act_low, &(note[0])); // C3
- kit.audioActions().add(kit.getKey(2), actionKeyOn, actionKeyOff, act_low, &(note[1])); // D3
- kit.audioActions().add(kit.getKey(3), actionKeyOn, actionKeyOff, act_low, &(note[2])); // E3
- kit.audioActions().add(kit.getKey(4), actionKeyOn, actionKeyOff, act_low, &(note[3])); // F3
- kit.audioActions().add(kit.getKey(5), actionKeyOn, actionKeyOff, act_low, &(note[4])); // G3
- kit.audioActions().add(kit.getKey(6), actionKeyOn, actionKeyOff, act_low, &(note[5])); // A3
+ kit.audioActions().add(PIN_KEY1, actionKeyOn, actionKeyOff, act_low, &(note[0])); // C3
+ kit.audioActions().add(PIN_KEY2, actionKeyOn, actionKeyOff, act_low, &(note[1])); // D3
+ kit.audioActions().add(PIN_KEY3, actionKeyOn, actionKeyOff, act_low, &(note[2])); // E3
+ kit.audioActions().add(PIN_KEY4, actionKeyOn, actionKeyOff, act_low, &(note[3])); // F3
+ kit.audioActions().add(PIN_KEY5, actionKeyOn, actionKeyOff, act_low, &(note[4])); // G3
+ kit.audioActions().add(PIN_KEY6, actionKeyOn, actionKeyOff, act_low, &(note[5])); // A3
}
void setup() {
diff --git a/examples/examples-audiokit/streams-synthstk-audiokit/README.md b/examples/examples-audiokit/streams-synthstk-audiokit/README.md
index f908a65f20..3bfb6b0f35 100644
--- a/examples/examples-audiokit/streams-synthstk-audiokit/README.md
+++ b/examples/examples-audiokit/streams-synthstk-audiokit/README.md
@@ -8,6 +8,6 @@ For [further info see my blog](https://www.pschatzmann.ch/home/2021/12/21/ai-thi
### Dependencies
- https://github.com/pschatzmann/arduino-audio-tools
-- https://github.com/pschatzmann/arduino-audio-driver
+- https://github.com/pschatzmann/arduino-audiokit
- https://github.com/pschatzmann/arduino-midi
- https://github.com/pschatzmann/Arduino-STK
diff --git a/examples/examples-audiokit/streams-synthstk-audiokit/streams-synthstk-audiokit.ino b/examples/examples-audiokit/streams-synthstk-audiokit/streams-synthstk-audiokit.ino
index fb92df2468..3569e3f800 100644
--- a/examples/examples-audiokit/streams-synthstk-audiokit/streams-synthstk-audiokit.ino
+++ b/examples/examples-audiokit/streams-synthstk-audiokit/streams-synthstk-audiokit.ino
@@ -5,10 +5,10 @@
* @copyright Copyright (c) 2021
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/AudioKit.h"
#include "StkAll.h"
-AudioBoardStream kit(AudioKitEs8388V1);
+AudioKitStream kit;
Clarinet clarinet(440);
Voicer voicer;
ArdStreamOut output(&kit);
@@ -16,12 +16,12 @@ float noteAmplitude = 128;
int group = 0;
void actionKeyOn(bool active, int pin, void* ptr){
- float note = *((float*)ptr);
+ int note = *((int*)ptr);
voicer.noteOn(note, noteAmplitude, group);
}
void actionKeyOff(bool active, int pin, void* ptr){
- float note = *((float*)ptr);
+ int note = *((int*)ptr);
voicer.noteOff(note, noteAmplitude, group);
}
@@ -30,12 +30,12 @@ void setupActions(){
// assign buttons to notes
auto act_low = AudioActions::ActiveLow;
static int note[] = {48,50,52,53,55,57}; // midi keys
- kit.audioActions().add(kit.getKey(1), actionKeyOn, actionKeyOff, act_low, &(note[0])); // C3
- kit.audioActions().add(kit.getKey(2), actionKeyOn, actionKeyOff, act_low, &(note[1])); // D3
- kit.audioActions().add(kit.getKey(3), actionKeyOn, actionKeyOff, act_low, &(note[2])); // E3
- kit.audioActions().add(kit.getKey(4), actionKeyOn, actionKeyOff, act_low, &(note[3])); // F3
- kit.audioActions().add(kit.getKey(5), actionKeyOn, actionKeyOff, act_low, &(note[4])); // G3
- kit.audioActions().add(kit.getKey(6), actionKeyOn, actionKeyOff, act_low, &(note[5])); // A3
+ kit.audioActions().add(PIN_KEY1, actionKeyOn, actionKeyOff, act_low, &(note[0])); // C3
+ kit.audioActions().add(PIN_KEY2, actionKeyOn, actionKeyOff, act_low, &(note[1])); // D3
+ kit.audioActions().add(PIN_KEY3, actionKeyOn, actionKeyOff, act_low, &(note[2])); // E3
+ kit.audioActions().add(PIN_KEY4, actionKeyOn, actionKeyOff, act_low, &(note[3])); // F3
+ kit.audioActions().add(PIN_KEY5, actionKeyOn, actionKeyOff, act_low, &(note[4])); // G3
+ kit.audioActions().add(PIN_KEY6, actionKeyOn, actionKeyOff, act_low, &(note[5])); // A3
}
void setup() {
diff --git a/examples/examples-audiokit/streams-tf-audiokit/README.md b/examples/examples-audiokit/streams-tf-audiokit/README.md
index 54f2564410..db28b232a7 100644
--- a/examples/examples-audiokit/streams-tf-audiokit/README.md
+++ b/examples/examples-audiokit/streams-tf-audiokit/README.md
@@ -18,5 +18,5 @@ The log level has been set to Info to help you to identify any problems. Please
You need to install the following libraries:
- https://github.com/pschatzmann/arduino-audio-tools
-- https://github.com/pschatzmann/arduino-audio-driver
+- https://github.com/pschatzmann/arduino-audiokit
- https://github.com/pschatzmann/tflite-micro-arduino-examples
\ No newline at end of file
diff --git a/examples/examples-audiokit/streams-tf-audiokit/streams-tf-audiokit.ino b/examples/examples-audiokit/streams-tf-audiokit/streams-tf-audiokit.ino
index d34d5d5ffb..34a5f158b4 100644
--- a/examples/examples-audiokit/streams-tf-audiokit/streams-tf-audiokit.ino
+++ b/examples/examples-audiokit/streams-tf-audiokit/streams-tf-audiokit.ino
@@ -9,13 +9,13 @@
*
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/TfLiteAudioStream.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/TfLiteAudioStream.h"
+#include "AudioLibs/AudioKit.h"
#include "model.h"
TfLiteSineReader tf_reader(20000,0.3); // Audio generation logic
TfLiteAudioStream tf_stream; // Audio source -> no classification so N is 0
-AudioBoardStream i2s(AudioKitEs8388V1); // Audio destination
+AudioKitStream i2s; // Audio destination
StreamCopy copier(i2s, tf_stream); // copy tf_stream to i2s
int channels = 1;
int samples_per_second = 16000;
@@ -23,7 +23,7 @@ int samples_per_second = 16000;
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
// Setup tensorflow input
auto tcfg = tf_stream.defaultConfig();
diff --git a/examples/examples-communication/http-client/streams-url_aac-audiokit/README.md b/examples/examples-audiokit/streams-url_aac-audiokit/README.md
similarity index 100%
rename from examples/examples-communication/http-client/streams-url_aac-audiokit/README.md
rename to examples/examples-audiokit/streams-url_aac-audiokit/README.md
diff --git a/examples/examples-communication/http-client/streams-url_aac-audiokit/streams-url_aac-audiokit.ino b/examples/examples-audiokit/streams-url_aac-audiokit/streams-url_aac-audiokit.ino
similarity index 78%
rename from examples/examples-communication/http-client/streams-url_aac-audiokit/streams-url_aac-audiokit.ino
rename to examples/examples-audiokit/streams-url_aac-audiokit/streams-url_aac-audiokit.ino
index 3ba8b078e4..874403f32e 100644
--- a/examples/examples-communication/http-client/streams-url_aac-audiokit/streams-url_aac-audiokit.ino
+++ b/examples/examples-audiokit/streams-url_aac-audiokit/streams-url_aac-audiokit.ino
@@ -11,19 +11,19 @@
// install https://github.com/pschatzmann/arduino-libhelix.git
#include "AudioTools.h"
-#include "AudioTools/AudioCodecs/CodecAACHelix.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioCodecs/CodecAACHelix.h"
+#include "AudioLibs/AudioKit.h"
URLStream url("http://github.com/ssid%22,%22password"); // or replace with ICYStream to get metadata
-AudioBoardStream i2s(AudioKitEs8388V1); // final output of decoded stream
+AudioKitStream i2s; // final output of decoded stream
EncodedAudioStream dec(&i2s, new AACDecoderHelix()); // Decoding stream
StreamCopy copier(dec, url); // copy url to decoder
void setup(){
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// setup i2s
auto config = i2s.defaultConfig(TX_MODE);
diff --git a/examples/examples-communication/http-client/streams-url_mp3-audiokit/README.md b/examples/examples-audiokit/streams-url_mp3-audiokit/README.md
similarity index 100%
rename from examples/examples-communication/http-client/streams-url_mp3-audiokit/README.md
rename to examples/examples-audiokit/streams-url_mp3-audiokit/README.md
diff --git a/examples/examples-communication/http-client/streams-url_mp3-audiokit/streams-url_mp3-audiokit.ino b/examples/examples-audiokit/streams-url_mp3-audiokit/streams-url_mp3-audiokit.ino
similarity index 77%
rename from examples/examples-communication/http-client/streams-url_mp3-audiokit/streams-url_mp3-audiokit.ino
rename to examples/examples-audiokit/streams-url_mp3-audiokit/streams-url_mp3-audiokit.ino
index c3a80676f2..f9f2fd062a 100644
--- a/examples/examples-communication/http-client/streams-url_mp3-audiokit/streams-url_mp3-audiokit.ino
+++ b/examples/examples-audiokit/streams-url_mp3-audiokit/streams-url_mp3-audiokit.ino
@@ -11,19 +11,19 @@
// install https://github.com/pschatzmann/arduino-libhelix.git
#include "AudioTools.h"
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioCodecs/CodecMP3Helix.h"
+#include "AudioLibs/AudioKit.h"
URLStream url("http://github.com/ssid%22,%22password"); // or replace with ICYStream to get metadata
-AudioBoardStream i2s(AudioKitEs8388V1); // final output of decoded stream
+AudioKitStream i2s; // final output of decoded stream
EncodedAudioStream dec(&i2s, new MP3DecoderHelix()); // Decoding stream
StreamCopy copier(dec, url); // copy url to decoder
void setup(){
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// setup i2s
auto config = i2s.defaultConfig(TX_MODE);
diff --git a/examples/examples-basic-api/base-SynchronizedBufferRTOS/base-SynchronizedBufferRTOS.ino b/examples/examples-basic-api/base-SynchronizedBufferRTOS/base-SynchronizedBufferRTOS.ino
index 74801edf79..b769d3a48e 100644
--- a/examples/examples-basic-api/base-SynchronizedBufferRTOS/base-SynchronizedBufferRTOS.ino
+++ b/examples/examples-basic-api/base-SynchronizedBufferRTOS/base-SynchronizedBufferRTOS.ino
@@ -1,5 +1,5 @@
/**
- * @file base-BufferRTOS.ino
+ * @file base-SynchronizedBufferRTOS.ino
* @author Phil Schatzmann
* @brief Data provider on core 0 with data consumer on core 1
* @version 0.1
@@ -9,11 +9,11 @@
*
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/Concurrency.h" // https://github.com/pschatzmann/arduino-freertos-addons
+#include "freertos-all.h" // https://github.com/pschatzmann/arduino-freertos-addons
-BufferRTOS buffer(1024);
+SynchronizedBufferRTOS buffer(1024);
void doWrite(); // forward declaration
-Task writeTask("write",5000,10, 0); // FreeRTOS task from addons
+Task writeTask("write",5000,10, doWrite); // FreeRTOS task from addons
// create data and write it to buffer
void doWrite() {
@@ -27,10 +27,10 @@ void doWrite() {
void setup(){
// Setup logging
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// start on core 0
- writeTask.begin(doWrite);
+ writeTask.Start(0);
}
// The loop runs on core 1: We read back the data
diff --git a/examples/examples-communication/a2dp/basic-adc-a2dp/README.md b/examples/examples-basic-api/base-adc-a2dp/README.md
similarity index 100%
rename from examples/examples-communication/a2dp/basic-adc-a2dp/README.md
rename to examples/examples-basic-api/base-adc-a2dp/README.md
diff --git a/examples/examples-communication/a2dp/basic-adc-a2dp/basic-adc-a2dp.ino b/examples/examples-basic-api/base-adc-a2dp/base-adc-a2dp.ino
similarity index 75%
rename from examples/examples-communication/a2dp/basic-adc-a2dp/basic-adc-a2dp.ino
rename to examples/examples-basic-api/base-adc-a2dp/base-adc-a2dp.ino
index 63bbe47e52..9ab807ca03 100644
--- a/examples/examples-communication/a2dp/basic-adc-a2dp/basic-adc-a2dp.ino
+++ b/examples/examples-basic-api/base-adc-a2dp/base-adc-a2dp.ino
@@ -1,15 +1,16 @@
/**
- * @file basic-adc-a2dp.ino
+ * @file adc-a2dp.ino
* @author Phil Schatzmann
- * @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-communication/a2dp/basic-adc-a2dp/README.md
+ * @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/adc-a2dp/README.md
*
* @author Phil Schatzmann
* @copyright GPLv3
*
*/
-#include "AudioTools.h"
+#include "Arduino.h"
#include "BluetoothA2DPSource.h"
+#include "AudioTools.h"
/**
* @brief We use a mcp6022 analog microphone as input and send the data to A2DP
@@ -17,12 +18,15 @@
AnalogAudioStream adc;
BluetoothA2DPSource a2dp_source;
+// The data has a center of around 26427, so we we need to shift it down to bring the center to 0
+ConverterScaler scaler(1.0, -26427, 32700 );
// callback used by A2DP to provide the sound data
int32_t get_sound_data(Frame* frames, int32_t frameCount) {
uint8_t *data = (uint8_t*)frames;
int frameSize = 4;
size_t resultBytes = adc.readBytes(data, frameCount*frameSize);
+ scaler.convert(data, resultBytes);
return resultBytes/frameSize;
}
@@ -37,11 +41,9 @@ void setup(void) {
// start the bluetooth
Serial.println("starting A2DP...");
a2dp_source.set_auto_reconnect(false);
- a2dp_source.set_data_callback_in_frames(get_sound_data);
- a2dp_source.start("MyMusic");
+ a2dp_source.start("MyMusic", get_sound_data);
}
// Arduino loop - repeated processing
void loop() {
- delay(1000);
}
\ No newline at end of file
diff --git a/examples/examples-basic-api/base-adc-average-mono-serial/base-adc-average-mono-serial.ino b/examples/examples-basic-api/base-adc-average-mono-serial/base-adc-average-mono-serial.ino
deleted file mode 100644
index 12fc9ca771..0000000000
--- a/examples/examples-basic-api/base-adc-average-mono-serial/base-adc-average-mono-serial.ino
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * @file base-adc-average-mono-serial.ino
- * @brief Attempts down sampling with binning of a mono audio signal by AVG_LEN
- * @author Urs Utzinger
- * @copyright GPLv3
- **/
-
-#include "Arduino.h"
-#include "AudioTools.h"
-
-// On board analog to digital converter
-AnalogAudioStream analog_in;
-
-// Serial terminal output
-CsvOutput serial_out(Serial);
-
-#define BAUD_RATE 500000
-#define SAMPLE_RATE 44100
-#define BUFFER_SIZE 256
-#define AVG_LEN 64
-#define BYTES_PER_SAMPLE sizeof(int16_t)
-
-// buffer to read samples and store the average samples
-int16_t buffer[BUFFER_SIZE];
-
-void setup() {
-
- delay(3000); // wait for serial to become available
-
- // Serial Interface
- Serial.begin(BAUD_RATE);
-
- // Include logging to serial
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Error); // Debug, Warning, Info, Error
-
- // Start ADC input
- Serial.println("Starting ADC...");
- auto adcConfig = analog_in.defaultConfig(RX_MODE);
- adcConfig.sample_rate = SAMPLE_RATE;
- adcConfig.channels = 1;
-
- // For ESP32 by Espressif Systems version 3.0.0 and later:
- // see examples/README_ESP32.md
- // adcConfig.sample_rate = 44100;
- // adcConfig.adc_bit_width = 12;
- // adcConfig.adc_calibration_active = true;
- // adcConfig.is_auto_center_read = false;
- // adcConfig.adc_attenuation = ADC_ATTEN_DB_12;
- // adcConfig.channels = 1;
- // adcConfig.adc_channels[0] = ADC_CHANNEL_4;
-
- analog_in.begin(adcConfig);
-
- // Start Serial Output CSV
- Serial.println("Starting Serial Out...");
- auto csvConfig = serial_out.defaultConfig();
- csvConfig.sample_rate = SAMPLE_RATE/AVG_LEN;
- csvConfig.channels = 1;
- csvConfig.bits_per_sample = 16;
- serial_out.begin(csvConfig);
-}
-
-
-void loop() {
-
- // Read the values from the ADC buffer to local buffer
- size_t bytes_read = analog_in.readBytes((uint8_t*) buffer, BUFFER_SIZE * BYTES_PER_SAMPLE); // read byte stream and cast to destination type
- size_t samples_read = bytes_read/BYTES_PER_SAMPLE;
- size_t avg_samples = samples_read/AVG_LEN;
-
- // Average the samples over AVG_LEN
- int32_t sum; // register to hold summed values
- int16_t *sample = (int16_t*) buffer; // sample pointer (input)
- int16_t *avg = (int16_t*) buffer; // result pointer (output)
- // each time we access a sample we increment sample pointer
- for(uint16_t j=0; j scaler(1.0, -26427, 32700 );
// Arduino Setup
void setup(void) {
-
- delay(3000); // wait for serial to become available
-
Serial.begin(115200);
- // Include logging to serial
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info); //Warning, Info, Error, Debug
- Serial.println("starting ADC...");
- auto adcConfig = adc.defaultConfig(RX_MODE);
- // For ESP32 by Espressif Systems version 3.0.0 and later:
- // see examples/README_ESP32.md
- // adcConfig.sample_rate = 44100;
- // adcConfig.adc_bit_width = 12;
- // adcConfig.adc_calibration_active = true;
- // adcConfig.is_auto_center_read = false;
- // adcConfig.adc_attenuation = ADC_ATTEN_DB_12;
- // adcConfig.channels = 2;
- // adcConfig.adc_channels[0] = ADC_CHANNEL_4;
- // adcConfig.adc_channels[1] = ADC_CHANNEL_5;
+ // start i2s input with default configuration
+ Serial.println("starting I2S-ADC...");
+ adc.begin(adc.defaultConfig(RX_MODE));
- adc.begin(adcConfig);
}
// Arduino loop - repeated processing
diff --git a/examples/examples-basic-api/base-file_raw-serial/README.md b/examples/examples-basic-api/base-file_raw-serial/README.md
new file mode 100644
index 0000000000..47ab8cfe13
--- /dev/null
+++ b/examples/examples-basic-api/base-file_raw-serial/README.md
@@ -0,0 +1,24 @@
+# Stream SD File to A2DP Bluetooth
+
+We are reading a raw audio file from the SD card and send it to a Bluetooth A2DP device. The audio file must be available using 16 bit integers with 2 channels.
+
+[Audacity](https://www.audacityteam.org/) might help you out here: export with the file name audio.raw as RAW signed 16 bit PCM and copy it to the SD card. In my example I was using the file [audio.raw](https://pschatzmann.github.io/Resources/img/audio.raw).
+
+
+
+The SD module is connected with the help of the SPI bus
+
+### Pins:
+
+We connect the SD to the ESP32:
+
+| SD | ESP32
+|---------|---------------
+| VCC | 5V
+| GND | GND
+| CS | CS GP5
+| SCK | SCK GP18
+| MOSI | MOSI GP23
+| MISO | MISO GP19
+
+
diff --git a/examples/examples-communication/a2dp/basic-generator-a2dp/basic-generator-a2dp.ino b/examples/examples-basic-api/base-generator-a2dp/base-generator-a2dp.ino
similarity index 73%
rename from examples/examples-communication/a2dp/basic-generator-a2dp/basic-generator-a2dp.ino
rename to examples/examples-basic-api/base-generator-a2dp/base-generator-a2dp.ino
index a8b9e29d48..45a8a603a7 100644
--- a/examples/examples-communication/a2dp/basic-generator-a2dp/basic-generator-a2dp.ino
+++ b/examples/examples-basic-api/base-generator-a2dp/base-generator-a2dp.ino
@@ -1,12 +1,18 @@
/**
- * @file basic-generator-a2dp.ino
+ * @file base-generator-a2dp.ino
* @author Phil Schatzmann
* @brief We send a test sine signal to a bluetooth speaker
- * @copyright GPLv3
+ * @copyright GPLv3
*/
+/**
+ * @file base-generator-a2dp.ino
+ * @author Phil Schatzmann
+ * @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/base-generator-a2dp/README.md
+ * @copyright GPLv3
+*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/A2DPStream.h"
+#include "AudioLibs/AudioA2DP.h"
const char* name = "LEXON MINO L"; // Replace with your bluetooth speaker name
SineWaveGenerator sineWave(15000); // subclass of SoundGenerator, set max amplitude (=volume)
@@ -21,7 +27,7 @@ int32_t get_sound_data(uint8_t * data, int32_t len) {
// Arduino Setup
void setup(void) {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
// start input
auto cfg = in_stream.defaultConfig();
@@ -35,11 +41,9 @@ void setup(void) {
// start the bluetooth
Serial.println("starting A2DP...");
a2dp_source.set_auto_reconnect(false);
- a2dp_source.set_data_callback(get_sound_data);
- a2dp_source.start(name);
+ a2dp_source.start_raw(name, get_sound_data);
}
// Arduino loop - repeated processing
void loop() {
- delay(1000);
}
\ No newline at end of file
diff --git a/examples/examples-communication/a2dp/basic-i2s-a2dp/README.md b/examples/examples-basic-api/base-i2s-a2dp/README.md
similarity index 100%
rename from examples/examples-communication/a2dp/basic-i2s-a2dp/README.md
rename to examples/examples-basic-api/base-i2s-a2dp/README.md
diff --git a/examples/examples-basic-api/base-i2s-a2dp/base-i2s-a2dp.ino b/examples/examples-basic-api/base-i2s-a2dp/base-i2s-a2dp.ino
new file mode 100644
index 0000000000..11c99740af
--- /dev/null
+++ b/examples/examples-basic-api/base-i2s-a2dp/base-i2s-a2dp.ino
@@ -0,0 +1,58 @@
+/**
+ * @file base-i2s-a2dp.ino
+ * @author Phil Schatzmann
+ * @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/base-i2s-a2dp/README.md
+ * @copyright GPLv3
+*/
+
+#include "AudioTools.h"
+#include "AudioLibs/AudioA2DP.h"
+
+/**
+ * @brief We use a INMP441 I2S microphone as input and send the data to A2DP
+ * Unfortunatly the data type from the microphone (int32_t) does not match with the required data type by A2DP (int16_t),
+ * so we need to convert.
+ */
+
+BluetoothA2DPSource a2dp_source;
+I2SStream i2s;
+ConverterFillLeftAndRight bothChannels(LeftIsEmpty);
+const size_t max_buffer_len = 150;
+const int channels = 2;
+const size_t max_buffer_bytes = max_buffer_len * sizeof(int16_t) * channels;
+uint8_t buffer[max_buffer_bytes]={0};
+
+// callback used by A2DP to provide the sound data - usually len is 128 2 channel int16 frames
+int32_t get_sound_data(Frame* data, int32_t len) {
+ size_t req_bytes = min(max_buffer_bytes, len*2*sizeof(int16_t));
+ // the microphone provides data in int32_t -> we read it into the buffer of int32_t data so *2
+ size_t result_bytes = i2s.readBytes((uint8_t*)buffer, req_bytes*2);
+ // we have data only in 1 channel but we want to fill both
+ return bothChannels.convert((uint8_t*)buffer, result_bytes);
+}
+
+
+// Arduino Setup
+void setup(void) {
+ Serial.begin(115200);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
+
+ // start i2s input with default configuration
+ Serial.println("starting I2S...");
+ auto cfg = i2s.defaultConfig(RX_MODE);
+ cfg.i2s_format = I2S_STD_FORMAT; // or try with I2S_LSB_FORMAT
+ cfg.bits_per_sample = 16;
+ cfg.channels = 2;
+ cfg.sample_rate = 44100;
+ cfg.is_master = true;
+ i2s.begin(cfg);
+
+ // start the bluetooth
+ Serial.println("starting A2DP...");
+ a2dp_source.set_auto_reconnect(false);
+ a2dp_source.start("LEXON MINO L", get_sound_data);
+}
+
+// Arduino loop - repeated processing
+void loop() {
+}
\ No newline at end of file
diff --git a/examples/examples-basic-api/base-player-a2dp/base-player-a2dp.ino b/examples/examples-basic-api/base-player-a2dp/base-player-a2dp.ino
new file mode 100644
index 0000000000..d028abe165
--- /dev/null
+++ b/examples/examples-basic-api/base-player-a2dp/base-player-a2dp.ino
@@ -0,0 +1,66 @@
+/**
+ * @file base-player-a2dp.ino
+ * @author Phil Schatzmann
+ * @brief Sketch which uses the A2DP callback to provide data from the AudioPlayer via a Queue
+ *
+ * @version 0.1
+ * @date 2022-12-04
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+
+#include "AudioTools.h"
+#include "AudioLibs/AudioA2DP.h"
+#include "AudioLibs/AudioSourceSDFAT.h"
+#include "AudioCodecs/CodecMP3Helix.h"
+#include "AudioLibs/AudioKit.h"
+
+int buffer_count = 30;
+int buffer_size = 512;
+const char *startFilePath="/";
+const char* ext="mp3";
+AudioSourceSDFAT source(startFilePath, ext, PIN_AUDIO_KIT_SD_CARD_CS);
+MP3DecoderHelix decoder;
+//Setup of synchronized buffer
+SynchronizedNBuffer buffer(buffer_size,buffer_count, portMAX_DELAY, 10);
+QueueStream out(buffer); // convert Buffer to Stream
+AudioPlayer player(source, out, decoder);
+BluetoothA2DPSource a2dp;
+
+// Provide data to A2DP
+int32_t get_data(uint8_t *data, int32_t bytes) {
+ size_t result_bytes = buffer.readArray(data, bytes);
+ //LOGI("get_data_channels %d -> %d of (%d)", bytes, result_bytes , buffer.available());
+ return result_bytes;
+}
+
+void setup() {
+ Serial.begin(115200);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
+
+ // sd_active is setting up SPI with the right SD pins by calling
+ SPI.begin(PIN_AUDIO_KIT_SD_CARD_CLK, PIN_AUDIO_KIT_SD_CARD_MISO, PIN_AUDIO_KIT_SD_CARD_MOSI, PIN_AUDIO_KIT_SD_CARD_CS);
+
+ // start QueueStream
+ out.begin();
+
+ // setup player
+ player.setDelayIfOutputFull(0);
+ player.setVolume(0.1);
+ player.begin();
+
+ // fill buffer with some data
+ player.getStreamCopy().copyN(5);
+
+ // start a2dp source
+ Serial.println("starting A2DP...");
+ a2dp.start_raw("LEXON MINO L", get_data);
+ Serial.println("Started!");
+
+}
+
+void loop() {
+ // decode data to buffer
+ player.copy();
+}
\ No newline at end of file
diff --git a/examples/examples-communication/a2dp/basic-a2dp-fft-led/basic-a2dp-fft-led.ino b/examples/examples-basic-api/basic-a2dp-fft-led/basic-a2dp-fft-led.ino
similarity index 74%
rename from examples/examples-communication/a2dp/basic-a2dp-fft-led/basic-a2dp-fft-led.ino
rename to examples/examples-basic-api/basic-a2dp-fft-led/basic-a2dp-fft-led.ino
index deefeda564..b22b70429d 100644
--- a/examples/examples-communication/a2dp/basic-a2dp-fft-led/basic-a2dp-fft-led.ino
+++ b/examples/examples-basic-api/basic-a2dp-fft-led/basic-a2dp-fft-led.ino
@@ -6,10 +6,9 @@
* @copyright GPLv3
*/
-#include // to prevent conflicts introduced with 3.9
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioRealFFT.h" // or any other supported inplementation
-#include "AudioTools/AudioLibs/LEDOutput.h"
+#include "AudioLibs/AudioRealFFT.h" // or any other supported inplementation
+#include "AudioLibs/LEDOutput.h"
#include "BluetoothA2DPSink.h"
#define PIN_LEDS 22
@@ -18,8 +17,7 @@
BluetoothA2DPSink a2dp_sink;
AudioRealFFT fft; // or any other supported inplementation
-FFTDisplay fft_dis(fft);
-LEDOutput led(fft_dis); // output to LED matrix
+LEDOutput led(fft); // output to LED matrix
// Provide data to FFT
void writeDataStream(const uint8_t *data, uint32_t length) {
@@ -28,7 +26,7 @@ void writeDataStream(const uint8_t *data, uint32_t length) {
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// Setup FFT
auto tcfg = fft.defaultConfig();
@@ -42,13 +40,11 @@ void setup() {
auto lcfg = led.defaultConfig();
lcfg.x = LED_X;
lcfg.y = LED_Y;
+ lcfg.fft_group_bin = 3;
+ lcfg.fft_start_bin = 0;
+ lcfg.fft_max_magnitude = 40000;
led.begin(lcfg);
- fft_dis.fft_group_bin = 3;
- fft_dis.fft_start_bin = 0;
- fft_dis.fft_max_magnitude = 40000;
- fft_dis.begin();
-
// add LEDs
FastLED.addLeds(led.ledData(), led.ledCount());
diff --git a/examples/examples-communication/a2dp/basic-a2dp-fft/basic-a2dp-fft.ino b/examples/examples-basic-api/basic-a2dp-fft/basic-a2dp-fft.ino
similarity index 90%
rename from examples/examples-communication/a2dp/basic-a2dp-fft/basic-a2dp-fft.ino
rename to examples/examples-basic-api/basic-a2dp-fft/basic-a2dp-fft.ino
index e822e50848..ae24641eac 100644
--- a/examples/examples-communication/a2dp/basic-a2dp-fft/basic-a2dp-fft.ino
+++ b/examples/examples-basic-api/basic-a2dp-fft/basic-a2dp-fft.ino
@@ -7,7 +7,7 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioRealFFT.h" // or any other supported inplementation
+#include "AudioLibs/AudioRealFFT.h" // or any other supported inplementation
#include "BluetoothA2DPSink.h"
BluetoothA2DPSink a2dp_sink;
@@ -35,7 +35,7 @@ void fftResult(AudioFFTBase &fft){
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// Setup FFT
auto tcfg = fft.defaultConfig();
diff --git a/examples/examples-basic-api/basic-a2dp-i2s/AudioConfigLocal.h b/examples/examples-basic-api/basic-a2dp-i2s/AudioConfigLocal.h
new file mode 100644
index 0000000000..8b1ee2548e
--- /dev/null
+++ b/examples/examples-basic-api/basic-a2dp-i2s/AudioConfigLocal.h
@@ -0,0 +1,4 @@
+#pragma once
+
+#define I2S_BUFFER_COUNT 8
+#define I2S_BUFFER_SIZE 256
diff --git a/examples/examples-communication/a2dp/basic-a2dp-i2s/basic-a2dp-i2s.ino b/examples/examples-basic-api/basic-a2dp-i2s/basic-a2dp-i2s.ino
similarity index 86%
rename from examples/examples-communication/a2dp/basic-a2dp-i2s/basic-a2dp-i2s.ino
rename to examples/examples-basic-api/basic-a2dp-i2s/basic-a2dp-i2s.ino
index 8d85a5c490..b2cf2e437d 100644
--- a/examples/examples-communication/a2dp/basic-a2dp-i2s/basic-a2dp-i2s.ino
+++ b/examples/examples-basic-api/basic-a2dp-i2s/basic-a2dp-i2s.ino
@@ -7,20 +7,21 @@
* @copyright GPLv3
*/
-#include "AudioTools.h"
#include "BluetoothA2DPSink.h"
+#include "AudioConfigLocal.h"
+#include "AudioTools.h"
BluetoothA2DPSink a2dp_sink;
I2SStream i2s;
-// Write data to I2S
+// Write data to SPDIF in callback
void read_data_stream(const uint8_t *data, uint32_t length) {
i2s.write(data, length);
}
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
// register callback
a2dp_sink.set_stream_reader(read_data_stream, false);
@@ -35,8 +36,6 @@ void setup() {
cfg.sample_rate = a2dp_sink.sample_rate();
cfg.channels = 2;
cfg.bits_per_sample = 16;
- cfg.buffer_count = 8;
- cfg.buffer_size = 256;
i2s.begin(cfg);
}
diff --git a/examples/examples-basic-api/basic-a2dp-spdif/AudioConfigLocal.h b/examples/examples-basic-api/basic-a2dp-spdif/AudioConfigLocal.h
new file mode 100644
index 0000000000..c118898465
--- /dev/null
+++ b/examples/examples-basic-api/basic-a2dp-spdif/AudioConfigLocal.h
@@ -0,0 +1,4 @@
+#pragma once
+
+#define I2S_BUFFER_COUNT 30
+#define I2S_BUFFER_SIZE 384
\ No newline at end of file
diff --git a/examples/examples-basic-api/basic-a2dp-spdif/basic-a2dp-spdif.ino b/examples/examples-basic-api/basic-a2dp-spdif/basic-a2dp-spdif.ino
new file mode 100644
index 0000000000..c952cf146d
--- /dev/null
+++ b/examples/examples-basic-api/basic-a2dp-spdif/basic-a2dp-spdif.ino
@@ -0,0 +1,44 @@
+/**
+ * @file basic-a2dp-audiospdif.ino
+ * @brief A2DP Sink with output to SPDIFOutput
+ *
+ * @author Phil Schatzmann
+ * @copyright GPLv3
+ */
+
+#include "AudioConfigLocal.h"
+#include "BluetoothA2DPSink.h"
+#include "AudioTools.h"
+
+BluetoothA2DPSink a2dp_sink;
+SPDIFOutput spdif;
+
+// Write data to SPDIF in callback
+void read_data_stream(const uint8_t *data, uint32_t length) {
+ spdif.write(data, length);
+}
+
+void setup() {
+ Serial.begin(115200);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
+
+ // register callback
+ a2dp_sink.set_stream_reader(read_data_stream, false);
+
+ // Start Bluetooth Audio Receiver
+ a2dp_sink.set_auto_reconnect(false);
+ a2dp_sink.start("a2dp-spdif");
+
+ // setup output
+ auto cfg = spdif.defaultConfig();
+ cfg.pin_data = 23;
+ cfg.sample_rate = a2dp_sink.sample_rate();
+ cfg.channels = 2;
+ cfg.bits_per_sample = 16;
+ spdif.begin(cfg);
+
+}
+
+void loop() {
+ delay(100);
+}
\ No newline at end of file
diff --git a/examples/examples-communication/a2dp/basic-a2dp-mixer-i2s/basic-a2dp-mixer-i2s.ino b/examples/examples-communication/a2dp/basic-a2dp-mixer-i2s/basic-a2dp-mixer-i2s.ino
deleted file mode 100644
index 1f01a3ebc9..0000000000
--- a/examples/examples-communication/a2dp/basic-a2dp-mixer-i2s/basic-a2dp-mixer-i2s.ino
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * @file basic-a2dp-mixer-i2s.ino
- * @brief A2DP Sink with output to mixer: I think this is the most efficient way
- * of mixing a signal that is coming from A2DP which requires only 160 byte of additional RAM.
- *
- * @author Phil Schatzmann
- * @copyright GPLv3
- */
-
-#include "AudioTools.h"
-#include "BluetoothA2DPSink.h"
-
-AudioInfo info(44100, 2, 16);
-BluetoothA2DPSink a2dp_sink;
-I2SStream i2s;
-SineWaveGenerator sineWave(10000); // subclass of SoundGenerator with max amplitude of 10000
-GeneratedSoundStream sound(sineWave); // Stream generated from sine wave
-OutputMixer mixer(i2s, 2); // output mixer with 2 outputs
-const int buffer_size = 80; // split up the output into small chunks
-uint8_t sound_buffer[buffer_size];
-
-// Write data to mixer
-void read_data_stream(const uint8_t *data, uint32_t length) {
- // To keep the mixing buffer small we split up the output into small chunks
- int count = length / buffer_size + 1;
- for (int j = 0; j < count; j++) {
- const uint8_t *start = data + (j * buffer_size);
- const uint8_t *end = min(data + length, start + buffer_size);
- int len = end - start;
- if (len > 0) {
- // write a2dp
- mixer.write(start, len);
-
- // write sine tone with identical length
- sound.readBytes(sound_buffer, len);
- mixer.write(sound_buffer, len);
-
- // We could flush to force the output but this is not necessary because we
- // were already writing all 2 streams mixer.flushMixer();
- }
- }
-}
-
-void setup() {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
-
- // setup Output mixer with min necessary memory
- mixer.begin(buffer_size);
-
- // Register data callback
- a2dp_sink.set_stream_reader(read_data_stream, false);
-
- // Start Bluetooth Audio Receiver
- a2dp_sink.set_auto_reconnect(false);
- a2dp_sink.start("a2dp-i2s");
-
- // Update sample rate
- info.sample_rate = a2dp_sink.sample_rate();
-
- // start sine wave
- sineWave.begin(info, N_B4);
-
- // setup output
- auto cfg = i2s.defaultConfig();
- cfg.copyFrom(info);
- // cfg.pin_data = 23;
- cfg.buffer_count = 8;
- cfg.buffer_size = 256;
- i2s.begin(cfg);
-}
-
-void loop() { delay(100); }
\ No newline at end of file
diff --git a/examples/examples-communication/a2dp/basic-file_mp3-a2dp/basic-file_mp3-a2dp.ino b/examples/examples-communication/a2dp/basic-file_mp3-a2dp/basic-file_mp3-a2dp.ino
deleted file mode 100644
index 15408212f1..0000000000
--- a/examples/examples-communication/a2dp/basic-file_mp3-a2dp/basic-file_mp3-a2dp.ino
+++ /dev/null
@@ -1,53 +0,0 @@
-// We use the decoding on the input side to provid pcm data
-
-#include "SPI.h"
-#include "SD.h"
-#include "AudioTools.h"
-#include "AudioTools/AudioLibs/A2DPStream.h"
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
-//#include "AudioTools/AudioLibs/AudioBoardStream.h" // for SPI pins
-
-File file;
-MP3DecoderHelix mp3; // or change to MP3DecoderMAD
-EncodedAudioStream decoder(&file, &mp3);
-BluetoothA2DPSource a2dp_source;
-const int chipSelect = SS; //PIN_AUDIO_KIT_SD_CARD_CS;
-
-// callback used by A2DP to provide the sound data - usually len is 128 2 channel int16 frames
-int32_t get_sound_data(uint8_t* data, int32_t size) {
- int32_t result = decoder.readBytes((uint8_t*)data, size);
- delay(1); // feed the dog
- return result;
-}
-
-// Arduino Setup
-void setup(void) {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- // open file
- //SPI.begin(PIN_AUDIO_KIT_SD_CARD_CLK, PIN_AUDIO_KIT_SD_CARD_MISO, PIN_AUDIO_KIT_SD_CARD_MOSI, PIN_AUDIO_KIT_SD_CARD_CS);
- SD.begin(chipSelect);
- file = SD.open("/test.mp3", FILE_READ);
- if (!file) {
- Serial.println("file failed");
- stop();
- }
-
- // make sure we have enough space for the pcm data
- decoder.transformationReader().resizeResultQueue(1024 * 8);
- if (!decoder.begin()) {
- Serial.println("decoder failed");
- stop();
- }
-
- // start the bluetooth
- Serial.println("starting A2DP...");
- a2dp_source.set_data_callback(get_sound_data);
- a2dp_source.start("LEXON MINO L");
-}
-
-// Arduino loop - repeated processing
-void loop() {
- delay(1000);
-}
diff --git a/examples/examples-communication/a2dp/basic-i2s-a2dp/basic-i2s-a2dp.ino b/examples/examples-communication/a2dp/basic-i2s-a2dp/basic-i2s-a2dp.ino
deleted file mode 100644
index dba0f2b9c5..0000000000
--- a/examples/examples-communication/a2dp/basic-i2s-a2dp/basic-i2s-a2dp.ino
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * @file basic-i2s-a2dp.ino
- * @author Phil Schatzmann
- * @brief We use a INMP441 I2S microphone as input and send the data to A2DP
- * Unfortunatly the data type from the microphone (int32_t) does not match with
- * the required data type by A2DP (int16_t), so we need to convert.
- * @copyright GPLv3
- */
-
-#include "AudioTools.h"
-#include "AudioTools/AudioLibs/A2DPStream.h"
-
-AudioInfo info32(44100, 2, 32);
-AudioInfo info16(44100, 2, 16);
-BluetoothA2DPSource a2dp_source;
-I2SStream i2s;
-FormatConverterStream conv(i2s);
-const int BYTES_PER_FRAME = 4;
-
-
-int32_t get_sound_data(Frame* data, int32_t frameCount) {
- return conv.readBytes((uint8_t*)data, frameCount*BYTES_PER_FRAME)/BYTES_PER_FRAME;
-}
-
-// Arduino Setup
-void setup(void) {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- // setup conversion
- conv.begin(info32, info16);
-
- // start i2s input with default configuration
- Serial.println("starting I2S...");
- auto cfg = i2s.defaultConfig(RX_MODE);
- cfg.i2s_format = I2S_STD_FORMAT; // or try with I2S_LSB_FORMAT
- cfg.copyFrom(info32);
- cfg.is_master = true;
- i2s.begin(cfg);
-
- // start the bluetooth
- Serial.println("starting A2DP...");
- // a2dp_source.set_auto_reconnect(false);
- a2dp_source.set_data_callback_in_frames(get_sound_data);
- a2dp_source.start("LEXON MINO L");
-
- Serial.println("A2DP started");
-}
-
-// Arduino loop - repeated processing
-void loop() { delay(1000); }
\ No newline at end of file
diff --git a/examples/examples-communication/a2dp/basic-player-a2dp/basic-player-a2dp.ino b/examples/examples-communication/a2dp/basic-player-a2dp/basic-player-a2dp.ino
deleted file mode 100644
index 06638dacc3..0000000000
--- a/examples/examples-communication/a2dp/basic-player-a2dp/basic-player-a2dp.ino
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * @file basic-player-a2dp.ino
- * @author Phil Schatzmann
- * @brief Sketch which uses the A2DP callback to provide data from the AudioPlayer via a Queue
- * The queue is filled by the Arduino loop.
- * @version 0.1
- * @date 2022-12-04
- *
- * @copyright Copyright (c) 2022
- *
- */
-
- #include "AudioTools.h"
- #include "AudioTools/AudioLibs/A2DPStream.h"
- #include "AudioTools/Disk/AudioSourceSDFAT.h"
- #include "AudioTools/AudioCodecs/CodecMP3Helix.h"
- //#include "AudioTools/AudioLibs/AudioBoardStream.h" // for SD Pins
-
- const int cs = 33; //PIN_AUDIO_KIT_SD_CARD_CS;
- const int buffer_size = 15*1024;
- const char *startFilePath = "/";
- const char *ext = "mp3";
- AudioSourceSDFAT source(startFilePath, ext, cs);
- MP3DecoderHelix decoder;
- //Setup of synchronized buffer
- BufferRTOS buffer(0);
- QueueStream out(buffer); // convert Buffer to Stream
- AudioPlayer player(source, out, decoder);
- BluetoothA2DPSource a2dp;
-
- // Provide data to A2DP
- int32_t get_data(uint8_t *data, int32_t bytes) {
- size_t result_bytes = buffer.readArray(data, bytes);
- //LOGI("get_data_channels %d -> %d of (%d)", bytes, result_bytes , buffer.available());
- return result_bytes;
- }
-
- void setup() {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- // allocate in PSRAM only possible in setup or loop
- buffer.resize(buffer_size);
-
- // sd_active is setting up SPI with the right SD pins by calling
- // SPI.begin(PIN_AUDIO_KIT_SD_CARD_CLK, PIN_AUDIO_KIT_SD_CARD_MISO, PIN_AUDIO_KIT_SD_CARD_MOSI, PIN_AUDIO_KIT_SD_CARD_CS);
-
- // start QueueStream when 95% full
- out.begin(95);
-
- // setup player
- player.setDelayIfOutputFull(0);
- player.setVolume(0.1);
- player.begin();
-
- // start a2dp source
- Serial.println("starting A2DP...");
- a2dp.set_data_callback(get_data);
- a2dp.start("LEXON MINO L");
- Serial.println("Started!");
- }
-
- void loop() {
- // decode data to buffer
- player.copy();
- }
\ No newline at end of file
diff --git a/examples/examples-communication/a2dp/streams-a2dp-spdif/streams-a2dp-spdif.ino b/examples/examples-communication/a2dp/streams-a2dp-spdif/streams-a2dp-spdif.ino
deleted file mode 100644
index c94faf49e5..0000000000
--- a/examples/examples-communication/a2dp/streams-a2dp-spdif/streams-a2dp-spdif.ino
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * @file basic-a2dp-audiospdif.ino
- * @brief A2DP Sink with output to SPDIFOutput
- *
- * @author Phil Schatzmann
- * @copyright GPLv3
- */
-#include "AudioTools.h"
-#include "AudioTools/AudioLibs/SPDIFOutput.h"
-#include "BluetoothA2DPSink.h"
-
-AudioInfo info(44100, 2, 16);
-SPDIFOutput spdif;
-BluetoothA2DPSink a2dp_sink(spdif);
-
-void setup() {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
-
- // setup output
- auto cfg = spdif.defaultConfig();
- cfg.copyFrom(info);
- cfg.buffer_size = 384;
- cfg.buffer_count = 30;
- cfg.pin_data = 23;
- spdif.begin(cfg);
-
- // Start Bluetooth Audio Receiver
- a2dp_sink.start("a2dp-spdif");
-
-}
-
-void loop() {
- delay(100);
-}
diff --git a/examples/examples-communication/esp-now/codec/communication-codec-espnow-receive/communication-codec-espnow-receive.ino b/examples/examples-communication/esp-now/codec/communication-codec-espnow-receive/communication-codec-espnow-receive.ino
index a8bb0c99a5..010fb4e0a9 100644
--- a/examples/examples-communication/esp-now/codec/communication-codec-espnow-receive/communication-codec-espnow-receive.ino
+++ b/examples/examples-communication/esp-now/codec/communication-codec-espnow-receive/communication-codec-espnow-receive.ino
@@ -9,20 +9,20 @@
*/
#include "AudioTools.h"
-#include "AudioTools/Communication/ESPNowStream.h"
-#include "AudioTools/AudioCodecs/CodecSBC.h"
-// #include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/Communication.h"
+#include "AudioCodecs/CodecSBC.h"
+// #include "AudioLibs/AudioKit.h"
ESPNowStream now;
-I2SStream out; // or AudioBoardStream
+I2SStream out; // or AudioKitStream
EncodedAudioStream decoder(&out, new SBCDecoder(256)); // decode and write to I2S - ESP Now is limited to 256 bytes
StreamCopy copier(decoder, now);
const char *peers[] = {"A8:48:FA:0B:93:02"};
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
// setup esp-now
auto cfg = now.defaultConfig();
diff --git a/examples/examples-communication/esp-now/codec/communication-codec-espnow-receive_measure/communication-codec-espnow-receive_measure.ino b/examples/examples-communication/esp-now/codec/communication-codec-espnow-receive_measure/communication-codec-espnow-receive_measure.ino
index 0111cd0de7..35c9ac393f 100644
--- a/examples/examples-communication/esp-now/codec/communication-codec-espnow-receive_measure/communication-codec-espnow-receive_measure.ino
+++ b/examples/examples-communication/esp-now/codec/communication-codec-espnow-receive_measure/communication-codec-espnow-receive_measure.ino
@@ -10,8 +10,8 @@
*/
#include "AudioTools.h"
-#include "AudioTools/Communication/ESPNowStream.h"
-#include "AudioTools/AudioCodecs/CodecSBC.h"
+#include "AudioLibs/Communication.h"
+#include "AudioCodecs/CodecSBC.h"
ESPNowStream now;
MeasuringStream out(1000, &Serial);
@@ -21,7 +21,7 @@ const char *peers[] = {"A8:48:FA:0B:93:02"};
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
// start esp-now
auto cfg = now.defaultConfig();
diff --git a/examples/examples-communication/esp-now/codec/communication-codec-espnow-send/communication-codec-espnow-send.ino b/examples/examples-communication/esp-now/codec/communication-codec-espnow-send/communication-codec-espnow-send.ino
index c97e93bf0e..06196262c5 100644
--- a/examples/examples-communication/esp-now/codec/communication-codec-espnow-send/communication-codec-espnow-send.ino
+++ b/examples/examples-communication/esp-now/codec/communication-codec-espnow-send/communication-codec-espnow-send.ino
@@ -9,8 +9,8 @@
*/
#include "AudioTools.h"
-#include "AudioTools/Communication/ESPNowStream.h"
-#include "AudioTools/AudioCodecs/CodecSBC.h"
+#include "AudioLibs/Communication.h"
+#include "AudioCodecs/CodecSBC.h"
AudioInfo info(32000,1,16);
SineWaveGenerator sineWave( 32000); // subclass of SoundGenerator with max amplitude of 32000
@@ -23,7 +23,7 @@ const char *peers[] = {"A8:48:FA:0B:93:01"};
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
auto cfg = now.defaultConfig();
cfg.mac_address = "A8:48:FA:0B:93:02";
diff --git a/examples/examples-communication/esp-now/pcm/communication-espnow-receive/communication-espnow-receive.ino b/examples/examples-communication/esp-now/pcm/communication-espnow-receive/communication-espnow-receive.ino
index e111495917..6f5ebc0c82 100644
--- a/examples/examples-communication/esp-now/pcm/communication-espnow-receive/communication-espnow-receive.ino
+++ b/examples/examples-communication/esp-now/pcm/communication-espnow-receive/communication-espnow-receive.ino
@@ -1,5 +1,5 @@
/**
- * @file example-espnow-receive.ino
+ * @file example-serial-receive.ino
* @author Phil Schatzmann
* @brief Receiving audio via ESPNow
* @version 0.1
@@ -9,7 +9,7 @@
*/
#include "AudioTools.h"
-#include "AudioTools/Communication/ESPNowStream.h"
+#include "AudioLibs/Communication.h"
AudioInfo info(8000, 1, 16);
ESPNowStream now;
@@ -21,7 +21,7 @@ const char *peers[] = {"A8:48:FA:0B:93:02"};
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
auto cfg = now.defaultConfig();
cfg.mac_address = "A8:48:FA:0B:93:01";
diff --git a/examples/examples-communication/esp-now/pcm/communication-espnow-receive_csv/communication-espnow-receive_csv.ino b/examples/examples-communication/esp-now/pcm/communication-espnow-receive_csv/communication-espnow-receive_csv.ino
index 9da044bcdd..79e8cdca60 100644
--- a/examples/examples-communication/esp-now/pcm/communication-espnow-receive_csv/communication-espnow-receive_csv.ino
+++ b/examples/examples-communication/esp-now/pcm/communication-espnow-receive_csv/communication-espnow-receive_csv.ino
@@ -1,5 +1,5 @@
/**
- * @file example-espnow-receive_csv.ino
+ * @file example-serial-receive_csv.ino
* @author Phil Schatzmann
* @brief Receiving audio via ESPNow
* @version 0.1
@@ -9,14 +9,14 @@
*/
#include "AudioTools.h"
-#include "AudioTools/Communication/ESPNowStream.h"
+#include "AudioLibs/Communication.h"
ESPNowStream now;
const char *peers[] = {"A8:48:FA:0B:93:02"};
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
auto cfg = now.defaultConfig();
cfg.mac_address = "A8:48:FA:0B:93:01";
diff --git a/examples/examples-communication/esp-now/pcm/communication-espnow-receive_measure/communication-espnow-receive_measure.ino b/examples/examples-communication/esp-now/pcm/communication-espnow-receive_measure/communication-espnow-receive_measure.ino
index a31d5cf19c..522a1c8e9b 100644
--- a/examples/examples-communication/esp-now/pcm/communication-espnow-receive_measure/communication-espnow-receive_measure.ino
+++ b/examples/examples-communication/esp-now/pcm/communication-espnow-receive_measure/communication-espnow-receive_measure.ino
@@ -1,5 +1,5 @@
/**
- * @file example-espnow-receive_measure.ino
+ * @file example-serial-receive_measure.ino
* @author Phil Schatzmann
* @brief Receiving audio via ESPNow with max speed to measure thruput
* @version 0.1
@@ -10,7 +10,7 @@
*/
#include "AudioTools.h"
-#include "AudioTools/Communication/ESPNowStream.h"
+#include "AudioLibs/Communication.h"
ESPNowStream now;
MeasuringStream out;
@@ -19,7 +19,7 @@ const char *peers[] = {"A8:48:FA:0B:93:02"};
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
auto cfg = now.defaultConfig();
cfg.mac_address = "A8:48:FA:0B:93:01";
diff --git a/examples/examples-communication/esp-now/pcm/communication-espnow-send/communication-espnow-send.ino b/examples/examples-communication/esp-now/pcm/communication-espnow-send/communication-espnow-send.ino
index 4180a82f06..9058540083 100644
--- a/examples/examples-communication/esp-now/pcm/communication-espnow-send/communication-espnow-send.ino
+++ b/examples/examples-communication/esp-now/pcm/communication-espnow-send/communication-espnow-send.ino
@@ -1,5 +1,5 @@
/**
- * @file example-espnow-send.ino
+ * @file example-serial-send.ino
* @author Phil Schatzmann
* @brief Sending audio over ESPNow
* @version 0.1
@@ -9,7 +9,7 @@
*/
#include "AudioTools.h"
-#include "AudioTools/Communication/ESPNowStream.h"
+#include "AudioLibs/Communication.h"
AudioInfo info(8000, 1, 16);
SineWaveGenerator sineWave( 32000); // subclass of SoundGenerator with max amplitude of 32000
@@ -20,7 +20,7 @@ const char *peers[] = {"A8:48:FA:0B:93:01"};
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
auto cfg = now.defaultConfig();
cfg.mac_address = "A8:48:FA:0B:93:02";
diff --git a/examples/examples-communication/esp-now/speed-test/communication-espnow-receive_measure/communication-espnow-receive_measure.ino b/examples/examples-communication/esp-now/speed-test/communication-espnow-receive_measure/communication-espnow-receive_measure.ino
index c801ea1adb..d3a58cc793 100644
--- a/examples/examples-communication/esp-now/speed-test/communication-espnow-receive_measure/communication-espnow-receive_measure.ino
+++ b/examples/examples-communication/esp-now/speed-test/communication-espnow-receive_measure/communication-espnow-receive_measure.ino
@@ -10,7 +10,7 @@
*/
#include "AudioTools.h"
-#include "AudioTools/Communication/ESPNowStream.h"
+#include "AudioLibs/Communication.h"
ESPNowStream now;
MeasuringStream out;
@@ -19,7 +19,7 @@ const char *peers[] = {"A8:48:FA:0B:93:02"};
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
auto cfg = now.defaultConfig();
cfg.mac_address = "A8:48:FA:0B:93:01";
diff --git a/examples/examples-communication/esp-now/speed-test/communication-espnow-send/communication-espnow-send.ino b/examples/examples-communication/esp-now/speed-test/communication-espnow-send/communication-espnow-send.ino
index 51948991c9..293cd9c421 100644
--- a/examples/examples-communication/esp-now/speed-test/communication-espnow-send/communication-espnow-send.ino
+++ b/examples/examples-communication/esp-now/speed-test/communication-espnow-send/communication-espnow-send.ino
@@ -9,7 +9,7 @@
*/
#include "AudioTools.h"
-#include "AudioTools/Communication/ESPNowStream.h"
+#include "AudioLibs/Communication.h"
ESPNowStream now;
const char *peers[] = {"A8:48:FA:0B:93:01"};
@@ -17,7 +17,7 @@ uint8_t buffer[1024] = {0};
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
auto cfg = now.defaultConfig();
cfg.mac_address = "A8:48:FA:0B:93:02";
diff --git a/examples/examples-communication/ftp/ftp-client/ftp-client.ino b/examples/examples-communication/ftp/ftp-client/ftp-client.ino
deleted file mode 100644
index a74ccb98a7..0000000000
--- a/examples/examples-communication/ftp/ftp-client/ftp-client.ino
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * @file ftp-client.ino
- * @author Phil Schatzmann
- * @brief Receiving audio via FTP and writing to I2S of the AudioKit.
- * Replace the userids, passwords and ip adresses with your own!
- * And don't forget to read the Wiki of the imported projects
- * @version 0.1
- * @date 2023-11-09
- *
- * @copyright Copyright (c) 2023
- */
-
-#include "WiFi.h"
-#include "FTPClient.h" // install https://github.com/pschatzmann/TinyFTPClient
-#include "AudioTools.h" // https://github.com/pschatzmann/arduino-audio-tools
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h" // https://github.com/pschatzmann/arduino-libhelix
-#include "AudioTools/AudioLibs/AudioBoardStream.h" // https://github.com/pschatzmann/arduino-audio-driver
-
-FTPClient client;
-FTPFile file;
-AudioBoardStream kit(AudioKitEs8388V1); // or replace with e.g. I2SStream
-MP3DecoderHelix mp3;
-EncodedAudioStream decoder(&kit, &mp3);
-StreamCopy copier(decoder, file);
-
-void setup() {
- Serial.begin(115200);
-
- // connect to WIFI
- WiFi.begin("network name", "password");
- while (WiFi.status() != WL_CONNECTED) {
- delay(500);
- Serial.print(".");
- }
-
- // optional logging
- FTPLogger::setOutput(Serial);
- // FTPLogger::setLogLevel(LOG_DEBUG);
-
- // open connection
- client.begin(IPAddress(192, 168, 1, 10), "user", "password");
-
- // copy data from file
- file = client.open("/data/music/Neil Young/After the Gold Rush/08 Birds.mp3");
-
- // open output device
- kit.begin();
- decoder.begin();
-
-}
-
-void loop() { copier.copy(); }
\ No newline at end of file
diff --git a/examples/examples-communication/hls/hls-buffer-i2s/hls-buffer-i2s.ino b/examples/examples-communication/hls/hls-buffer-i2s/hls-buffer-i2s.ino
deleted file mode 100644
index 992cf35e60..0000000000
--- a/examples/examples-communication/hls/hls-buffer-i2s/hls-buffer-i2s.ino
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * @file hls-buffer-i2s.ino
- * @brief Buffered playback of HLSStream: activate PSRAM!
- * We use a MultiDecoder to handle different formats.
- * For MPEG-TS (MTS) you need to set the log level to Warning or higher.
- *
- * @author Phil Schatzmann
- * @copyright GPLv3
- */
-
-#include "AudioTools.h"
-#include "AudioTools/AudioCodecs/CodecHelix.h"
-#include "AudioTools/AudioCodecs/CodecMTS.h"
-#include "AudioTools/AudioLibs/HLSStream.h"
-#include "AudioTools/Concurrency/RTOS.h"
-// #include "AudioTools/AudioLibs/AudioBoardStream.h"
-
-// AudioBoardStream out(AudioKitEs8388V1); // final output of decoded stream
-I2SStream out; // audio output
-BufferRTOS buffer(0);
-QueueStream queue(buffer);
-HLSStream hls_stream("ssid", "password"); // audio data source
-// decoder
-MP3DecoderHelix mp3;
-AACDecoderHelix aac;
-MTSDecoder mts(aac); // MPEG-TS (MTS) decoder
-MultiDecoder multi(hls_stream); // MultiDecoder using mime from hls_stream
-EncodedAudioOutput dec(&out, &multi);
-// 2 separate copy processes
-StreamCopy copier_play(dec, queue);
-StreamCopy copier_write_queue(queue, hls_stream);
-Task writeTask("write", 1024 * 8, 10, 0);
-
-// Arduino Setup
-void setup(void) {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- // https://streams.radiomast.io/ref-128k-mp3-stereo/hls.m3u8
- // https://streams.radiomast.io/ref-128k-aaclc-stereo/hls.m3u8
- // https://streams.radiomast.io/ref-64k-heaacv1-stereo/hls.m3u8
- if (!hls_stream.begin(
- "https://streams.radiomast.io/ref-128k-mp3-stereo/hls.m3u8"))
- stop();
-
- // register decoders with mime types
- multi.addDecoder(mp3, "audio/mpeg");
- multi.addDecoder(aac, "audio/aac");
- multi.addDecoder(mts, "video/MP2T"); // MPEG-TS
-
- // start output
- auto cfg = out.defaultConfig(TX_MODE);
- // add optional configuration here: e.g. pins
- out.begin(cfg);
-
- buffer.resize(10 * 1024); // increase to 50k psram
- dec.begin(); // start decoder
- queue.begin(100); // activate read when 100% full
-
- writeTask.begin([]() { copier_write_queue.copy(); });
-}
-
-// Arduino loop
-void loop() { copier_play.copy(); }
diff --git a/examples/examples-communication/hls/hls-i2s/hls-i2s.ino b/examples/examples-communication/hls/hls-i2s/hls-i2s.ino
deleted file mode 100644
index ffdfd338dd..0000000000
--- a/examples/examples-communication/hls/hls-i2s/hls-i2s.ino
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * @file hls-i2s.ino
- * @brief Copy hls stream to decoder: the re-loading of data is causig pauses
- * We use a MultiDecoder to handle different formats.
- * For MPEG-TS (MTS) you need to set the log level to Warning or higher.
- *
- * @author Phil Schatzmann
- * @copyright GPLv3
- */
-
-#include "AudioTools.h"
-#include "AudioTools/AudioLibs/HLSStream.h"
-#include "AudioTools/AudioCodecs/CodecHelix.h"
-//#include "AudioTools/AudioLibs/AudioBoardStream.h"
-
-//AudioBoardStream out(AudioKitEs8388V1);
-I2SStream out;
-HLSStream hls_stream("ssid", "password");
-MP3DecoderHelix mp3;
-AACDecoderHelix aac;
-MultiDecoder multi(hls_stream); // MultiDecoder using mime from hls_stream
-EncodedAudioOutput dec(&out, &multi);
-StreamCopy copier(dec, hls_stream);
-
-// Arduino Setup
-void setup(void) {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- // https://streams.radiomast.io/ref-128k-mp3-stereo/hls.m3u8
- // https://streams.radiomast.io/ref-128k-aaclc-stereo/hls.m3u8
- // https://streams.radiomast.io/ref-64k-heaacv1-stereo/hls.m3u8
- if (!hls_stream.begin("https://streams.radiomast.io/ref-128k-mp3-stereo/hls.m3u8"))
- stop();
-
- multi.addDecoder(mp3, "audio/mpeg");
- multi.addDecoder(aac, "audio/aac");
-
- auto cfg = out.defaultConfig(TX_MODE);
- out.begin(cfg);
-
- dec.begin(); // start decoder
-}
-
-// Arduino loop
-void loop() {
- copier.copy();
-}
\ No newline at end of file
diff --git a/examples/examples-communication/http-client/streams-eth_url_mp3_helix-i2s/streams-eth_url_mp3_helix-i2s.ino b/examples/examples-communication/http-client/streams-eth_url_mp3_helix-i2s/streams-eth_url_mp3_helix-i2s.ino
deleted file mode 100644
index 68857587c0..0000000000
--- a/examples/examples-communication/http-client/streams-eth_url_mp3_helix-i2s/streams-eth_url_mp3_helix-i2s.ino
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * @file streams-url_mp3-i2s.ino
- * @author Phil Schatzmann
- * @brief decode MP3 stream from url and output it on I2S
- * @version 0.1
- * @date 2021-96-25
- *
- * @copyright Copyright (c) 2021
- */
-
-// install https://github.com/pschatzmann/arduino-libhelix.git
-
-#include "AudioTools.h"
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
-#include
-#include
-
-// Enter a MAC address for your controller below.
-// Newer Ethernet shields have a MAC address printed on a sticker on the shield
-byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
-const int CS = SS;
-EthernetClient eth;
-URLStream url(http://github.com/eth);
-I2SStream i2s; // final output of decoded stream
-EncodedAudioStream dec(&i2s, new MP3DecoderHelix()); // Decoding stream
-StreamCopy copier(dec, url); // copy url to decoder
-
-void setupEthernet() {
- // You can use Ethernet.init(pin) to configure the CS pin
- Ethernet.init(CS);
-
- // start the Ethernet connection:
- Serial.println("Initialize Ethernet with DHCP:");
- if (Ethernet.begin(mac)) {
- Serial.print(" DHCP assigned IP ");
- Serial.println(Ethernet.localIP());
- } else {
- Serial.println("Failed to configure Ethernet using DHCP");
- stop();
- }
-}
-
-void setup(){
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- setupEthernet();
-
- // setup i2s
- auto config = i2s.defaultConfig(TX_MODE);
- // you could define e.g your pins and change other settings
- //config.pin_ws = 10;
- //config.pin_bck = 11;
- //config.pin_data = 12;
- //config.mode = I2S_STD_FORMAT;
- i2s.begin(config);
-
- // setup I2S based on sampling rate provided by decoder
- dec.begin();
-
-// mp3 radio
- url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128","audio/mp3");
-
-}
-
-void loop(){
- copier.copy();
-}
diff --git a/examples/examples-communication/http-client/streams-http_post/streams-http_post.ino b/examples/examples-communication/http-client/streams-http_post/streams-http_post.ino
deleted file mode 100644
index 54186a978b..0000000000
--- a/examples/examples-communication/http-client/streams-http_post/streams-http_post.ino
+++ /dev/null
@@ -1,66 +0,0 @@
-
-/**
- * @file streams-url-post.ino
- * @author Phil Schatzmann
- * @brief example how to http post data from an input stream using the
- * HttpRequest class.
- * @copyright GPLv3
- */
-
-#include "AudioTools.h"
-
-const char *ssid = "your SSID";
-const char *password = "your PASSWORD";
-const char *url_str = "http://192.168.1.44:9988/";
-AudioInfo info(44100, 2, 16);
-SineWaveGenerator sineWave(32000);
-GeneratedSoundStream sound(sineWave);
-TimedStream timed(sound);
-WiFiClient client;
-HttpRequest http(client);
-StreamCopy copier(http, timed);
-
-void startWiFi() {
- WiFi.mode(WIFI_STA);
- WiFi.begin(ssid, password);
- Serial.print("Connecting to WiFi ..");
- while (WiFi.status() != WL_CONNECTED) {
- Serial.print('.');
- delay(1000);
- }
- Serial.println();
- Serial.println(WiFi.localIP());
-}
-
-// Arduino Setup
-void setup(void) {
- // Open Serial
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- startWiFi();
-
- // Setup sine wave
- sineWave.begin(info, N_B4);
-
- // limit the size of the input stream to 60 seconds
- timed.setEndSec(60);
- timed.begin();
-
- // start post
- Url url(http://github.com/url_str);
- http.header().put(TRANSFER_ENCODING, CHUNKED); // uncomment if chunked
- if (!http.processBegin(POST, url, "audio/pcm")){
- Serial.println("post failed");
- stop();
- }
-}
-
-// Arduino loop - copy sound to out
-void loop() {
- // posting the data
- if (copier.copy() == 0) {
- // closing the post
- http.processEnd();
- }
-}
\ No newline at end of file
diff --git a/examples/examples-communication/http-client/streams-url_flac_foxen-i2s/streams-url_flac_foxen-i2s.ino b/examples/examples-communication/http-client/streams-url_flac_foxen-i2s/streams-url_flac_foxen-i2s.ino
deleted file mode 100644
index 0bb8b9faa7..0000000000
--- a/examples/examples-communication/http-client/streams-url_flac_foxen-i2s/streams-url_flac_foxen-i2s.ino
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * @file streams-url_flac_foxen-i2s.ino
- * @author Phil Schatzmann
- * @brief Demo using the Foxen FLAC decoder
- * @version 0.1
- * @date 2025-01-09
- *
- * @copyright Copyright (c) 2022
- *
- * Warning: The WIFI speed is quite limited and the FLAC files are quite big. So there
- * is a big chance that the WIFI is just not fast enough. For my test I was downsampling
- * the file to 8000 samples per second!
- */
-#include "AudioTools.h"
-#include "AudioTools/AudioCodecs/CodecFLACFoxen.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-
-const char* ssid = "ssid";
-const char* pwd = "password";
-URLStream url(http://github.com/ssid,%20pwd);
-AudioBoardStream i2s(AudioKitEs8388V1); // or replace with e.g. I2SStream i2s;
-
-FLACDecoderFoxen flac(5*1024, 2);
-EncodedAudioStream dec(&i2s, &flac); // Decoding to i2s
-StreamCopy copier(dec, url, 1024); // copy url to decoder
-
-void setup() {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
- while(!Serial);
- Serial.println("starting...");
-
- // Open I2S: if the buffer is too slow audio is breaking up
- auto cfg =i2s.defaultConfig(TX_MODE);
- cfg.buffer_size= 1024;
- cfg.buffer_count = 20;
- if (!i2s.begin(cfg)){
- Serial.println("i2s error");
- stop();
- }
-
- // Open url
- url.begin("https://pschatzmann.github.io/Resources/audio/audio.flac", "audio/flac");
-
- // Start decoder
- if (!dec.begin()){
- Serial.println("Decoder failed");
- }
-}
-
-void loop() {
- copier.copy();
-}
\ No newline at end of file
diff --git a/examples/examples-communication/http-client/streams-url_mp3-pwm/streams-url_mp3-pwm.ino b/examples/examples-communication/http-client/streams-url_mp3-pwm/streams-url_mp3-pwm.ino
deleted file mode 100644
index 15b96d25b5..0000000000
--- a/examples/examples-communication/http-client/streams-url_mp3-pwm/streams-url_mp3-pwm.ino
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * @file streams-url_mp3-out.ino
- * @author Phil Schatzmann
- * @brief decode MP3 stream from url and output it with the help of PWM
- * @version 0.1
- * @date 2021-96-25
- *
- * @copyright Copyright (c) 2021
- */
-
-// install https://github.com/pschatzmann/arduino-libhelix.git
-
-#include "AudioTools.h"
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
-
-
-URLStream url("http://github.com/ssid%22,%22password");
-PWMAudioOutput out; // final output of decoded stream
-EncodedAudioStream dec(&out, new MP3DecoderHelix()); // Decoding stream
-StreamCopy copier(dec, url); // copy url to decoder
-
-
-void setup(){
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- // setup out
- auto config = out.defaultConfig(TX_MODE);
- //config.resolution = 8; // must be between 8 and 11 -> drives pwm frequency (8 is default)
- // alternative 1
- //config.start_pin = 3;
- // alternative 2
- int pins[] = {22, 23};
- // alternative 3
- //Pins pins = {3};
- //config.setPins(pins);
- out.begin(config);
-
- // setup I2S based on sampling rate provided by decoder
- dec.begin();
-
-// mp3 radio
- url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128","audio/mp3");
-
-}
-
-void loop(){
- copier.copy();
-}
diff --git a/examples/examples-communication/http-client/streams-url_mp3_helix-i2s_32bit/streams-url_mp3_helix-i2s_32bit.ino b/examples/examples-communication/http-client/streams-url_mp3_helix-i2s_32bit/streams-url_mp3_helix-i2s_32bit.ino
deleted file mode 100644
index 705d8bb202..0000000000
--- a/examples/examples-communication/http-client/streams-url_mp3_helix-i2s_32bit/streams-url_mp3_helix-i2s_32bit.ino
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * @file streams-url_mp3-i2s_24bit.ino
- * @author Phil Schatzmann
- * @brief decode MP3 stream from url and output it on I2S. The data is converted from
- * 16 to 32 bit
- * @version 0.1
- * @date 2021-96-25
- *
- * @copyright Copyright (c) 2021
- */
-
-// install https://github.com/pschatzmann/arduino-libhelix.git
-
-#include "AudioTools.h"
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
-
-
-URLStream url("http://github.com/ssid%22,%22password");
-I2SStream i2s; // final output of decoded stream
-NumberFormatConverterStream nfc(i2s);
-EncodedAudioStream dec(&nfc, new MP3DecoderHelix()); // Decoding stream
-StreamCopy copier(dec, url); // copy url to decoder
-
-
-void setup(){
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- // convert 16 bits to 32, you could also change the gain
- nfc.begin(16, 32);
-
- // setup i2s
- auto config = i2s.defaultConfig(TX_MODE);
- // you could define e.g your pins and change other settings
- //config.pin_ws = 10;
- //config.pin_bck = 11;
- //config.pin_data = 12;
- //config.mode = I2S_STD_FORMAT;
- //config.bits_per_sample = 32; // we coult do this explicitly
- i2s.begin(config);
-
- // setup I2S based on sampling rate provided by decoder
- dec.begin();
-
-// mp3 radio
- url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128","audio/mp3");
-
-}
-
-void loop(){
- copier.copy();
-}
diff --git a/examples/examples-communication/http-client/streams-url_mts-hex/streams-url_mts-hex.ino b/examples/examples-communication/http-client/streams-url_mts-hex/streams-url_mts-hex.ino
deleted file mode 100644
index f180512d93..0000000000
--- a/examples/examples-communication/http-client/streams-url_mts-hex/streams-url_mts-hex.ino
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * @file url_mts-hex.ino
- * @author Phil Schatzmann
-
- * @copyright GPLv3
- */
-
-#include "AudioTools.h"
-#include "AudioTools/AudioCodecs/CodecMTS.h"
-#include "AudioTools/AudioLibs/HLSStream.h"
-
-HexDumpOutput out(Serial);
-HLSStream hls_stream("SSID", "password");
-MTSDecoder mts;
-EncodedAudioStream mts_stream(&out, &mts);
-StreamCopy copier(mts_stream, hls_stream);
-
-// Arduino Setup
-void setup(void) {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- mts_stream.begin();
-
- hls_stream.begin("http://a.files.bbci.co.uk/media/live/manifesto/audio/simulcast/hls/nonuk/sbr_vlow/ak/bbc_world_service.m3u8");
-
-}
-
-// Arduino loop
-void loop() {
- copier.copy();
-}
\ No newline at end of file
diff --git a/examples/examples-communication/http-client/streams-url_post/streams-url_post.ino b/examples/examples-communication/http-client/streams-url_post/streams-url_post.ino
deleted file mode 100644
index 721f6a506e..0000000000
--- a/examples/examples-communication/http-client/streams-url_post/streams-url_post.ino
+++ /dev/null
@@ -1,35 +0,0 @@
-
-/**
- * @file streams-url-post.ino
- * @author Phil Schatzmann
- * @brief example how to http post data from an input stream
- * @copyright GPLv3
- */
-
-#include "AudioTools.h"
-
-AudioInfo info(44100, 2, 16);
-SineWaveGenerator sineWave(32000);
-GeneratedSoundStream sound(sineWave);
-TimedStream timed(sound);
-URLStream url("http://github.com/ssid%22,%20%22password");
-
-// Arduino Setup
-void setup(void) {
- // Open Serial
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- // Setup sine wave
- sineWave.begin(info, N_B4);
-
- // limit the size of the input stream
- timed.setEndSec(60);
- timed.begin();
-
- // post the data
- url.begin("http://192.168.1.35:8000/", "audio/bin", POST, "text/html", timed);
-}
-
-// Arduino loop - copy sound to out
-void loop() {}
diff --git a/examples/examples-communication/http-server/python-post-server/README.md b/examples/examples-communication/http-server/python-post-server/README.md
deleted file mode 100644
index ca24566e93..0000000000
--- a/examples/examples-communication/http-server/python-post-server/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-
-This directory contains a server in Python that was used to test the [Arduino
-post sketch](https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-communication/http-client/streams-http_post/streams-http_post.ino) using chunged writes.
-
-The server logs each written line and writes the data to a file.
diff --git a/examples/examples-communication/http-server/python-post-server/server.py b/examples/examples-communication/http-server/python-post-server/server.py
deleted file mode 100755
index a63e4d1d32..0000000000
--- a/examples/examples-communication/http-server/python-post-server/server.py
+++ /dev/null
@@ -1,48 +0,0 @@
-
-#!/usr/bin/env python3
-
-from http.server import HTTPServer, SimpleHTTPRequestHandler
-
-HOST = ""
-PORT = 9988
-path = "./audio.pcm"
-
-class TestHTTPRequestHandler(SimpleHTTPRequestHandler):
- def do_POST(self):
- self.send_response(200)
- self.end_headers()
-
- if "Content-Length" in self.headers:
- content_length = int(self.headers["Content-Length"])
- body = self.rfile.read(content_length)
- with open(path, "wb") as out_file:
- print("writing:", content_length)
- out_file.write(body)
- elif "chunked" in self.headers.get("Transfer-Encoding", ""):
- with open(path, "wb") as out_file:
- while True:
- line = self.rfile.readline().strip()
- print(line)
- chunk_length = int(line, 16)
-
- if chunk_length != 0:
- print("writing chunk:", chunk_length)
- chunk = self.rfile.read(chunk_length)
- out_file.write(chunk)
-
- # Each chunk is followed by an additional empty newline
- # that we have to consume.
- self.rfile.readline()
-
- # Finally, a chunk size of 0 is an end indication
- if chunk_length == 0:
- break
-
-def main():
- httpd = HTTPServer((HOST, PORT), TestHTTPRequestHandler)
- print("Serving at port:", httpd.server_port)
- httpd.serve_forever()
-
-
-if __name__ == "__main__":
- main()
diff --git a/examples/examples-communication/http-server/streams-audiokit-webserver_mp3/streams-audiokit-webserver_mp3.ino b/examples/examples-communication/http-server/streams-audiokit-webserver_mp3/streams-audiokit-webserver_mp3.ino
deleted file mode 100644
index 24025fb94a..0000000000
--- a/examples/examples-communication/http-server/streams-audiokit-webserver_mp3/streams-audiokit-webserver_mp3.ino
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * @file streams-audiokit-webserver_mp3.ino
- *
- * This sketch reads sound data from the AudioKit. The result is provided as MP3 stream which can be listened to in a Web Browser
- *
- * @author Phil Schatzmann, Thorsten Godau (changed AAC example to MP3, added optional static IP)
- * @copyright GPLv3
- */
-
-#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/AudioCodecs/CodecMP3LAME.h"
-
-// Set static IP address and stuff (optional)
-IPAddress IPA_address(192, 168, 0, 222);
-IPAddress IPA_gateway(192, 168, 0, 1);
-IPAddress IPA_subnet(255, 255, 0, 0);
-IPAddress IPA_primaryDNS(192, 168, 0, 1); //optional
-IPAddress IPA_secondaryDNS(8, 8, 8, 8); //optional
-
-// WIFI
-const char *ssid = "ssid";
-const char *password = "password";
-
-AudioInfo info(16000,1,16);
-MP3EncoderLAME mp3;
-AudioEncoderServer server(&mp3, ssid, password);
-AudioBoardStream kit(AudioKitEs8388V1);
-
-// Arduino setup
-void setup(){
- Serial.begin(115200);
- // Defining Loglevels for the different libraries
- //AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
- //LOGLEVEL_AUDIOKIT = AudioKitInfo;
-
- // Configures static IP address (optional)
- if (!WiFi.config(IPA_address, IPA_gateway, IPA_subnet, IPA_primaryDNS, IPA_secondaryDNS))
- {
- Serial.println("WiFi.config: Failed to configure static IPv4...");
- }
-
- // start i2s input with default configuration
- Serial.println("starting AudioKit...");
- auto config = kit.defaultConfig(RX_MODE);
- config.input_device = ADC_INPUT_LINE2;
- config.copyFrom(info);
- config.sd_active = false;
- kit.begin(config);
- Serial.println("AudioKit started");
-
- // start data sink
- server.begin(kit, config);
- Serial.println("Server started");
-
-}
-
-// Arduino loop
-void loop() {
- // Handle new connections
- server.doLoop();
-}
diff --git a/examples/examples-communication/ip/communication-ip-receive/communication-ip-receive.ino b/examples/examples-communication/ip/communication-ip-receive/communication-ip-receive.ino
index 64eb6d00c0..2e17dae7c6 100644
--- a/examples/examples-communication/ip/communication-ip-receive/communication-ip-receive.ino
+++ b/examples/examples-communication/ip/communication-ip-receive/communication-ip-receive.ino
@@ -11,9 +11,6 @@
#include "AudioTools.h"
#include
-const char *ssid = "ssid";
-const char *password = "password";
-
AudioInfo info(16000, 1, 16);
uint16_t port = 8000;
WiFiServer server(port);
@@ -21,6 +18,8 @@ WiFiClient client;
I2SStream out;
MeasuringStream outTimed(out);
StreamCopy copier(outTimed, client);
+const char *ssid = "ssid";
+const char *password = "password";
void connectWifi(){
// connect to WIFI
@@ -33,12 +32,12 @@ void connectWifi(){
Serial.println(WiFi. localIP());
// Performance Hack
- WiFi.setSleep(false);
+ esp_wifi_set_ps(WIFI_PS_NONE);
}
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
connectWifi();
@@ -61,12 +60,8 @@ void loop() {
if (!client){
client = server.available();
}
-
// copy data if we are connected
if (client.connected()){
copier.copy();
- } else {
- // feed the dog
- delay(100);
}
}
diff --git a/examples/examples-communication/ip/communication-ip-receive_measure/communication-ip-receive_measure.ino b/examples/examples-communication/ip/communication-ip-receive_measure/communication-ip-receive_measure.ino
index 5a1852a4f5..fd1281d3dd 100644
--- a/examples/examples-communication/ip/communication-ip-receive_measure/communication-ip-receive_measure.ino
+++ b/examples/examples-communication/ip/communication-ip-receive_measure/communication-ip-receive_measure.ino
@@ -11,15 +11,14 @@
#include "AudioTools.h"
#include
-const char *ssid = "ssid";
-const char *password = "password";
-
AudioInfo info(16000, 1, 16);
uint16_t port = 8000;
WiFiServer server(port);
WiFiClient client;
MeasuringStream out;
StreamCopy copier(out, client);
+const char *ssid = "ssid";
+const char *password = "password";
void connectWifi() {
// connect to WIFI
@@ -32,12 +31,12 @@ void connectWifi() {
Serial.println(WiFi. localIP());
// Performance Hack
- WiFi.setSleep(false);
+ esp_wifi_set_ps(WIFI_PS_NONE);
}
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
connectWifi();
@@ -58,8 +57,5 @@ void loop() {
// copy data if we are connected
if (client.connected()){
copier.copy();
- } else {
- // feed the dog
- delay(100);
}
}
\ No newline at end of file
diff --git a/examples/examples-communication/ip/communication-ip-send/communication-ip-send.ino b/examples/examples-communication/ip/communication-ip-send/communication-ip-send.ino
index 43d1c4c28e..304d4ac3f2 100644
--- a/examples/examples-communication/ip/communication-ip-send/communication-ip-send.ino
+++ b/examples/examples-communication/ip/communication-ip-send/communication-ip-send.ino
@@ -48,7 +48,7 @@ void connectIP() {
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
connectWifi();
// Setup sine wave
diff --git a/examples/examples-communication/lora/communication-lora-receive/communication-lora-receive.ino b/examples/examples-communication/lora/communication-lora-receive/communication-lora-receive.ino
deleted file mode 100644
index 0af5c92d45..0000000000
--- a/examples/examples-communication/lora/communication-lora-receive/communication-lora-receive.ino
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * @file example-lora-receive_measure.ino
- * @author Phil Schatzmann
- * @brief Receiving audio via LoRa with max speed to measure thruput.
- * @version 0.1
- * @date 2023-11-09
- *
- * @copyright Copyright (c) 2022
- *
- */
-
-#include "AudioTools.h"
-#include "AudioTools/Communication/LoRaStream.h"
-
-LoRaStream lora;
-MeasuringStream out; // or CsvOutput
-StreamCopy copier(out, lora);
-
-void setup() {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
- while(!Serial);
-
- auto cfg = lora.defaultConfig();
- lora.begin(cfg);
-
- // start output
- Serial.println("starting Out...");
- out.begin();
-
- Serial.println("Receiver started...");
-}
-
-void loop() {
- copier.copy();
-}
\ No newline at end of file
diff --git a/examples/examples-communication/lora/communication-lora-send/communication-lora-send.ino b/examples/examples-communication/lora/communication-lora-send/communication-lora-send.ino
deleted file mode 100644
index d7658b3cde..0000000000
--- a/examples/examples-communication/lora/communication-lora-send/communication-lora-send.ino
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * @file example-lora-send.ino
- * @author Phil Schatzmann
- * @brief Sending data over LoRa. We use a Heltec WiFi LoRa V3 board for testing.
- * V3 boards use the SX1262.
- * @version 0.1
- * @date 2023-11-09
- *
- * @copyright Copyright (c) 2022
- */
-
-#include "AudioTools.h"
-#include "AudioTools/Communication/LoRaStream.h"
-
-AudioInfo info(8000, 1, 16);
-SineWaveGenerator sineWave( 32000); // subclass of SoundGenerator with max amplitude of 32000
-GeneratedSoundStream sound( sineWave); // Stream generated from sine wave
-LoRaStream lora;
-StreamCopy copier(lora, sound); // copies sound into i2s
-
-void setup() {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
- while(!Serial);
- Serial.println("starting...");
-
- // Setup LoRa
- Serial.printf("SCK: %d, MISO: %d, MOSI: %d, SS=%d", SCK,MISO,MOSI,SS);
- SPI.begin(SCK, MISO, MOSI, SS);
- auto cfg = lora.defaultConfig();
- cfg.copyFrom(info);
- if (!lora.begin(cfg)){
- Serial.println("LoRa failed");
- stop();
- }
-
- // Setup sine wave
- sineWave.begin(info, N_B4);
-
- Serial.println("Sender started...");
-}
-
-void loop() {
- copier.copy();
-}
\ No newline at end of file
diff --git a/examples/examples-communication/mqtt/communication-mqtt-send/communication-mqtt-send.ino b/examples/examples-communication/mqtt/communication-mqtt-send/communication-mqtt-send.ino
deleted file mode 100644
index 5f601955b6..0000000000
--- a/examples/examples-communication/mqtt/communication-mqtt-send/communication-mqtt-send.ino
+++ /dev/null
@@ -1,113 +0,0 @@
-/**
- * @file communication-mqtt-send.ino
- * @author Phil Schatzmann
- * @brief Send Audio File to MQTT.
- * I am using the ArduinoMQTTClient library from Arduino provided by the library manager.
- * We can just copy the audio data to the MQTT client!
- * @version 0.1
- * @date 2023-09-07
- *
- * @copyright Copyright (c) 2023
- */
-
-#include "WiFi.h"
-#include "ArduinoMqttClient.h"
-#include "AudioTools.h"
-
-#define SIZE 1024
-#define N 100
-
-// Communication
-const char* ssid = "SSID"; // your network SSID (name)
-const char* password = "PASSWORD"; // your network password (use for WPA, or use as key for WEP)
-const char* broker = "test.mosquitto.org";
-const char* topic = "audio.wav";
-int port = 1883;
-WiFiClient wifiClient;
-MqttClient mqttClient(wifiClient);
-
-// Audio
-AudioInfo info(8000, 1, 16);
-WhiteNoiseGenerator noise(32000); // subclass of SoundGenerator with max amplitude of 32000
-GeneratedSoundStream in_stream(noise); // Stream generated from noise
-EncodedAudioStream out_stream(&mqttClient, new WAVEncoder()); // encode as wav file
-StreamCopy copier(out_stream, in_stream, SIZE); // copies sound to MQTT client
-
-// Connect to Wifi
-void connectWIFI() {
- // attempt to connect to WiFi network:
- Serial.print("Attempting to connect to WPA SSID: ");
- Serial.println(ssid);
- WiFi.begin(ssid, password);
-
- Serial.print("Connecting to WiFi ..");
- while (WiFi.status() != WL_CONNECTED) {
- Serial.print('.');
- delay(1000);
- }
-
- Serial.println("You're connected to the network");
- Serial.println();
-}
-
-// Connect to MQTT Server
-void connectMQTT() {
- // You can provide a unique client ID, if not set the library uses Arduino-millis()
- // Each client must have a unique client ID
- mqttClient.setId("AudioTools");
-
- // You can provide a username and password for authentication
- // mqttClient.setUsernamePassword("username", "password");
-
- Serial.print("Attempting to connect to the MQTT broker: ");
- Serial.println(broker);
-
- if (!mqttClient.connect(broker, port)) {
- Serial.print("MQTT connection failed! Error code = ");
- Serial.println(mqttClient.connectError());
-
- stop();
- }
-
- Serial.println("You're connected to the MQTT broker!");
- Serial.println();
-}
-
-// Send audio to MQTT Server
-void sendMQTT() {
- // make sure that we write wav header
- out_stream.begin(info);
-
- // send message, the Print interface can be used to set the message contents
- mqttClient.beginMessage(topic, SIZE * N, true);
-
- // copy audio data to mqtt: 100 * 1024 bytes
- copier.copyN(N);
-
- mqttClient.endMessage();
-}
-
-
-void setup() {
- // Initialize logger
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- // connect
- connectWIFI();
- connectMQTT();
-
- // setup audio
- noise.begin(info);
- in_stream.begin(info);
-
- // send Audio
- sendMQTT();
-}
-
-void loop() {
- // call poll() regularly to allow the library to send MQTT keep alives which
- // avoids being disconnected by the broker
- mqttClient.poll();
- delay(1000);
-}
\ No newline at end of file
diff --git a/examples/examples-communication/rtsp/communication-audiokit-rtsp/communication-audiokit-rtsp.ino b/examples/examples-communication/rtsp/communication-audiokit-rtsp/communication-audiokit-rtsp.ino
index 26ff8315ea..fc346013cb 100644
--- a/examples/examples-communication/rtsp/communication-audiokit-rtsp/communication-audiokit-rtsp.ino
+++ b/examples/examples-communication/rtsp/communication-audiokit-rtsp/communication-audiokit-rtsp.ino
@@ -10,13 +10,13 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/AudioLibs/RTSP.h"
+#include "AudioLibs/AudioKit.h"
+#include "AudioLibs/RTSP.h"
#include "AudioStreamer.h"
#include "RTSPServer.h"
int port = 554;
-AudioBoardStream kit(AudioKitEs8388V1); // Audio source
+AudioKitStream kit; // Audio source
RTSPSourceFromAudioStream source(kit); // IAudioSource for RTSP
AudioStreamer streamer = AudioStreamer(&source); // Stream audio via RTSP
RTSPServer rtsp = RTSPServer(&streamer, port);
@@ -26,11 +26,11 @@ const char* password = "password";
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// setup Audiokit as source
auto cfg = kit.defaultConfig(RX_MODE);
- cfg.input_device = ADC_INPUT_LINE2;
+ cfg.input_device = AUDIO_HAL_ADC_INPUT_LINE2;
cfg.channels = 1;
cfg.sample_rate = 8000;
cfg.bits_per_sample = 16;
diff --git a/examples/examples-communication/rtsp/communication-codec-rtsp/communication-codec-rtsp.ino b/examples/examples-communication/rtsp/communication-codec-rtsp/communication-codec-rtsp.ino
index 52c9370248..823de66ff3 100644
--- a/examples/examples-communication/rtsp/communication-codec-rtsp/communication-codec-rtsp.ino
+++ b/examples/examples-communication/rtsp/communication-codec-rtsp/communication-codec-rtsp.ino
@@ -1,16 +1,6 @@
-/**
- * @file communication-codec-rtsp.ino
- * @author Phil Schatzmann
- * @brief Provide Audio via RTSP using a codec. Depends on https://github.com/pschatzmann/Micro-RTSP-Audio
- * @version 0.1
- * @date 2022-05-02
- *
- * @copyright Copyright (c) 2022
- *
- */
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/RTSP.h" // https://github.com/pschatzmann/Micro-RTSP-Audio
-#include "AudioTools/AudioCodecs/CodecG7xx.h" // https://github.com/pschatzmann/arduino-libg7xx.git
+#include "AudioLibs/RTSP.h"
+#include "AudioCodecs/CodecG7xx.h"
#include "RTSPServer.h"
int port = 554;
@@ -32,7 +22,10 @@ RTSPServer rtsp(rtsp_stream.streamer(), port);
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ AudioLogger::instance().begin(Serial, AudioLogger::Warning);
+
+ // Start Wifi & rtsp server
+ rtsp.begin(wifi, password);
// Setup sine wave
sineWave.begin(info, N_B4);
@@ -40,9 +33,6 @@ void setup() {
// Start Output Stream
rtsp_stream.begin(info);
- // Start Wifi & rtsp server
- rtsp.begin(wifi, password);
-
}
void loop() {
diff --git a/examples/examples-communication/rtsp/communication-generator-rtsp/communication-generator-rtsp.ino b/examples/examples-communication/rtsp/communication-generator-rtsp/communication-generator-rtsp.ino
index b473adea39..1dd232802e 100644
--- a/examples/examples-communication/rtsp/communication-generator-rtsp/communication-generator-rtsp.ino
+++ b/examples/examples-communication/rtsp/communication-generator-rtsp/communication-generator-rtsp.ino
@@ -10,7 +10,7 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/RTSP.h"
+#include "AudioLibs/RTSP.h"
#include "AudioStreamer.h"
#include "RTSPServer.h"
@@ -30,7 +30,7 @@ RTSPServer rtsp = RTSPServer(&streamer, port);
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// Setup sine wave
auto cfgS = sineWave.defaultConfig();
diff --git a/examples/examples-communication/rtsp/communication-rtsp-audiokit/communication-rtsp-audiokit.ino b/examples/examples-communication/rtsp/communication-rtsp-audiokit/communication-rtsp-audiokit.ino
deleted file mode 100644
index 3243ecd693..0000000000
--- a/examples/examples-communication/rtsp/communication-rtsp-audiokit/communication-rtsp-audiokit.ino
+++ /dev/null
@@ -1,28 +0,0 @@
-
-/**
- * @file communication-rtsp-i2s.ino
- * @author Phil Schatzmann
- * @brief Demo for RTSP Client that is playing mp3. I tested with the live555 server with linux
- * @version 0.1
- * @date 2022-05-02
- *
- * @copyright Copyright (c) 2022
- *
- */
-#include "AudioTools.h" // https://github.com/pschatzmann/arduino-audio-tools
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h" // https://github.com/pschatzmann/arduino-libhelix
-#include "AudioTools/AudioLibs/AudioBoardStream.h" // https://github.com/pschatzmann/arduino-audio-driver
-#include "AudioTools/AudioLibs/AudioClientRTSP.h" // install https://github.com/pschatzmann/arduino-live555
-
-AudioBoardStream i2s(AudioKitEs8388V1); // final output of decoded stream
-EncodedAudioStream out_mp3(&i2s, new MP3DecoderHelix()); // Decoding stream
-AudioClientRTSP rtsp(1024);
-
-void setup(){
- rtsp.setLogin("ssid", "password");
- rtsp.begin("https://samples.mplayerhq.hu/A-codecs/MP3/01%20-%20Charity%20Case.mp3", out_mp3);
-}
-
-void loop() {
- rtsp.loop();
-}
\ No newline at end of file
diff --git a/examples/examples-communication/rtsp/communication-rtsp-i2s/communication-rtsp-i2s.ino b/examples/examples-communication/rtsp/communication-rtsp-i2s/communication-rtsp-i2s.ino
deleted file mode 100644
index 00bb1f1605..0000000000
--- a/examples/examples-communication/rtsp/communication-rtsp-i2s/communication-rtsp-i2s.ino
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * @file communication-rtsp-i2s.ino
- * @author Phil Schatzmann
- * @brief Demo for RTSP Client that is playing mp3: tested with the live555 server with linux
- * @version 0.1
- * @date 2022-05-02
- *
- * @copyright Copyright (c) 2022
- *
- */
-
-#include "AudioTools.h" // https://github.com/pschatzmann/arduino-audio-tools
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h" // https://github.com/pschatzmann/arduino-libhelix
-#include "RTSPSimpleClient.hh" // https://github.com/pschatzmann/arduino-live555.git
-
-I2SStream i2s;
-EncodedAudioStream out_mp3(&i2s, new MP3DecoderHelix()); // Decoding stream
-RTSPSimpleClient rtsp;
-
-void setup() {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- // setup output: make sure we can buffer 1 decoded frame
- auto cfg_i2s = i2s.defaultConfig(TX_MODE);
- cfg_i2s.buffer_size = 1024;
- cfg_i2s.buffer_count = 10;
- i2s.begin(cfg_i2s);
-
- out_mp3.begin();
-
- // setup rtsp data source
- auto cfg = rtsp.defaultConfig();
- cfg.ssid = "ssid";
- cfg.password = "password";
- cfg.url = "rtsp://192.168.1.38:8554/test.mp3";
- cfg.output = &out_mp3;
- cfg.buffer_size = 1024*2; // space for 1 encoded frame
- //cfg.is_tcp = false; // use udp when false (default false)
- //cfg.is_blocking = false; // call singleStep in loop if false (default false)
- rtsp.begin(cfg);
-}
-
-void loop() {
- rtsp.singleStep();
-}
\ No newline at end of file
diff --git a/examples/examples-communication/serial/mp3-custom/receive-mp3/receive-mp3.ino b/examples/examples-communication/serial/mp3-custom/receive-mp3/receive-mp3.ino
deleted file mode 100644
index f866a45b00..0000000000
--- a/examples/examples-communication/serial/mp3-custom/receive-mp3/receive-mp3.ino
+++ /dev/null
@@ -1,61 +0,0 @@
-
-/**
- * @file receive-mp3.ino
- * @brief Example of receiving an mp3 stream over serial and playing it over I2S
- * using the AudioTools library.
- * The processing implements a flow control using a custom digital pin. We process
- * the data receiving in a separate task and the playback in the main loop.
- */
-
-#include "AudioTools.h"
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/Concurrency/RTOS.h"
-
-const int flowControlPin = 17; // flow control pin acitive low
-const int min_percent = 10;
-const int max_percent = 90;
-
-AudioBoardStream i2s(AudioKitEs8388V1); // final output of decoded stream
-MP3DecoderHelix helix;
-EncodedAudioStream dec(&i2s, &helix); // Decoding stream
-// queue
-BufferRTOS buffer(0);
-QueueStream queue(buffer);
-// copy
-StreamCopy copierFill(queue, Serial1);
-StreamCopy copierPlay(dec, queue);
-
-Task task("mp3-copy", 10000, 1, 0);
-
-void setup() {
- Serial.begin(115200);
- AudioLogger::instance().begin(Serial, AudioLogger::Info);
-
- Serial1.begin(115200);
- pinMode(flowControlPin, OUTPUT); // flow control pin
-
- // set up buffer here to allow PSRAM usage
- buffer.resize(1024 * 10); // 10kB buffer
- queue.begin(50); // start when half full
-
- // setup i2s
- auto config = i2s.defaultConfig(TX_MODE);
- i2s.begin(config);
-
- // setup decoder
- dec.begin();
-
- // start fill buffer copy task
- task.begin([]() {
- copierFill.copy();
- // data synchronization to prevent buffer overflow
- if (buffer.levelPercent() >= max_percent) {
- digitalWrite(flowControlPin, HIGH); // stop receiving
- } else if (buffer.levelPercent() <= min_percent) {
- digitalWrite(flowControlPin, LOW); // start receiving
- }
- });
-}
-
-void loop() { copierPlay.copy(); }
diff --git a/examples/examples-communication/serial/mp3-custom/send-mp3/send-mp3.ino b/examples/examples-communication/serial/mp3-custom/send-mp3/send-mp3.ino
deleted file mode 100644
index 66a096ce00..0000000000
--- a/examples/examples-communication/serial/mp3-custom/send-mp3/send-mp3.ino
+++ /dev/null
@@ -1,35 +0,0 @@
-
-/**
- * @file send-mp3.ino
- * @brief Example of sending an mp3 stream over Serial the AudioTools library.
- * We use a custom pin to control the flow of the data. If we are ready to
- * receive data, we set the pin to LOW.
- */
-
-#include "AudioTools.h"
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
-
-URLStream url("http://github.com/ssid%22,%20%22password"); // or replace with ICYStream to get metadata
-StreamCopy copier(Serial1, url); // copy url to decoder
-// pins
-const int flowControlPin = 17;
-
-void setup() {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Error);
-
- // setup flow control pin
- pinMode(flowControlPin, INPUT_PULLUP); // flow control pin
-
- // setup serial data sink
- Serial1.begin(115200);
-
- // mp3 radio
- url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128", "audio/mp3");
-}
-
-void loop() {
- if (digitalRead(flowControlPin) == LOW) {
- copier.copy();
- }
-}
\ No newline at end of file
diff --git a/examples/examples-communication/serial/mp3-xon-xoff/receive-mp3/receive-mp3.ino b/examples/examples-communication/serial/mp3-xon-xoff/receive-mp3/receive-mp3.ino
deleted file mode 100644
index 7641a3d03b..0000000000
--- a/examples/examples-communication/serial/mp3-xon-xoff/receive-mp3/receive-mp3.ino
+++ /dev/null
@@ -1,65 +0,0 @@
-
-/**
- * @file receive-mp3.ino
- * @brief Example of receiving an mp3 stream over serial and playing it over I2S
- * using the AudioTools library.
- * The processing implements a xon-xoff flow control over Serial. We
- * process the data receiving in a separate task and the playback in the main
- * loop.
- */
-
-#include "AudioTools.h"
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/Concurrency/RTOS.h"
-
-// xon/xoff flow control
-const char xon = 17;
-const char xoff = 19;
-const int min_percent = 10;
-const int max_percent = 90;
-
-AudioBoardStream i2s(AudioKitEs8388V1); // final output of decoded stream
-MP3DecoderHelix helix;
-EncodedAudioStream dec(&i2s, &helix); // Decoding stream
-// queue
-BufferRTOS buffer(0);
-QueueStream queue(buffer);
-// copy
-StreamCopy copierFill(queue, Serial1);
-StreamCopy copierPlay(dec, queue);
-
-Task task("mp3-copy", 10000, 1, 0);
-
-void setup() {
- Serial.begin(115200);
- AudioLogger::instance().begin(Serial, AudioLogger::Info);
-
- Serial0.begin(115200);
-
- // set up buffer here to allow PSRAM usage
- buffer.resize(1024 * 10); // 10kB buffer
- queue.begin(50); // start when half full
-
- // setup i2s
- auto config = i2s.defaultConfig(TX_MODE);
- i2s.begin(config);
-
- // setup decoder
- dec.begin();
-
- // start fill buffer copy task
- task.begin([]() {
- copierFill.copy();
- // data synchronization to prevent buffer overflow
- if (buffer.levelPercent() >= max_percent) {
- Serial1.write(xoff); // stop receiving
- Serial1.flush();
- } else if (buffer.levelPercent() <= min_percent) {
- Serial1.write(xon); // start receiving
- Serial1.flush();
- }
- });
-}
-
-void loop() { copierPlay.copy(); }
diff --git a/examples/examples-communication/serial/mp3-xon-xoff/send-mp3/send-mp3.ino b/examples/examples-communication/serial/mp3-xon-xoff/send-mp3/send-mp3.ino
deleted file mode 100644
index 709249ae1c..0000000000
--- a/examples/examples-communication/serial/mp3-xon-xoff/send-mp3/send-mp3.ino
+++ /dev/null
@@ -1,47 +0,0 @@
-
-/**
- * @file send-mp3.ino
- * @brief Example of sending an mp3 stream over Serial the AudioTools library.
- * We use xon/xoff to control the flow of the data.
- * I am using an ESP32 Dev Module for the test with the pins TX=17 and RX=16.
- */
-
-#include "AudioTools.h"
-
-URLStream url("http://github.com/ssid%22,%20%22password"); // or replace with ICYStream to get metadata
-StreamCopy copier(Serial1, url); // copy url to decoder
-// xon/xoff flow control
-const char xon = 17;
-const char xoff = 19;
-bool is_active = false;
-
-void setup() {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Error);
-
- // setup serial data sink
- Serial2.begin(115200);
-
- // mp3 radio
- url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128", "audio/mp3");
-}
-
-// Determine if we can send data from the flow control sent by the receiver
-bool isActive() {
- char c = Serial2.read();
- switch (c) {
- case xon:
- is_active = true;
- break;
- case xoff:
- is_active = false;
- break;
- }
- return is_active;
-}
-
-void loop() {
- if (isActive()) {
- copier.copy();
- }
-}
\ No newline at end of file
diff --git a/examples/examples-communication/serial/mp3/receive-mp3/receive-mp3.ino b/examples/examples-communication/serial/mp3/receive-mp3/receive-mp3.ino
deleted file mode 100644
index db847a61ed..0000000000
--- a/examples/examples-communication/serial/mp3/receive-mp3/receive-mp3.ino
+++ /dev/null
@@ -1,42 +0,0 @@
-
-/**
- * @file receive-mp3.ino
- * @brief Example of receiving an mp3 stream over serial and playing it over I2S
- * using the AudioTools library.
- * The processing must be synchronized with RTS/CTS flow control to prevent a
- * buffer overflow and lost data.
- */
-#include "AudioTools.h"
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-
-
-AudioBoardStream i2s(AudioKitEs8388V1); // final output of decoded stream
-EncodedAudioStream dec(&i2s, new MP3DecoderHelix()); // Decoding stream
-HardwareSerial MP3Serial(1); // define a Serial for UART1
-StreamCopy copier(dec, MP3Serial); // copy url to decoder
-// pins
-const int MySerialTX = -1;
-const int MySerialRX = 18;
-const int MySerialRTS = -1;
-const int MySerialCTS = 20;
-
-void setup() {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- // setup serial data source with flow control
- MP3Serial.begin(115200, SERIAL_8N1);
- MP3Serial.setPins(MySerialRX, MySerialTX, MySerialCTS, MySerialRTS);
- MP3Serial.setHwFlowCtrlMode(UART_HW_FLOWCTRL_CTS_RTS);
-
- // setup i2s
- auto config = i2s.defaultConfig(TX_MODE);
- i2s.begin(config);
-
- // setup I2S based on sampling rate provided by decoder
- dec.begin();
-
-}
-
-void loop() { copier.copy(); }
\ No newline at end of file
diff --git a/examples/examples-communication/serial/mp3/send-mp3/send-mp3.ino b/examples/examples-communication/serial/mp3/send-mp3/send-mp3.ino
deleted file mode 100644
index ae0223f8fd..0000000000
--- a/examples/examples-communication/serial/mp3/send-mp3/send-mp3.ino
+++ /dev/null
@@ -1,39 +0,0 @@
-
-/**
- * @file send-mp3.ino
- * @brief ESP32 Example of sending an mp3 stream over Serial the AudioTools library.
- * The processing must be synchronized with RTS/CTS flow control to prevent a
- * buffer overflow and lost data. We get the mp3 from an URLStream.
- * We used a ESP32 Dev Module for the test.
- */
-#include
-
-#include "AudioTools.h"
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
-
-URLStream url("http://github.com/ssid%22,%20%22password"); // or replace with ICYStream to get metadata
-HardwareSerial MP3Serial(1); // define a Serial for UART1
-StreamCopy copier(MP3Serial, url); // copy url to decoder
-// pins
-const int MySerialTX = 17; // TX2
-const int MySerialRX = -1; // not used
-const int MySerialRTS = 4; // GPIO 4
-const int MySerialCTS = -1; // not useed
-
-void setup() {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- // improve performance
- MP3Serial.setTxBufferSize(1024); // must be called before begin
-
- // setup serial data sink with flow control
- MP3Serial.begin(115200, SERIAL_8N1);
- MP3Serial.setPins(MySerialRX, MySerialTX, MySerialCTS, MySerialRTS);
- MP3Serial.setHwFlowCtrlMode(UART_HW_FLOWCTRL_CTS_RTS);
-
- // mp3 radio
- url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128", "audio/mp3");
-}
-
-void loop() { copier.copy(); }
\ No newline at end of file
diff --git a/examples/examples-communication/serial/send-8bit-receive/send-8bit-receive.ino b/examples/examples-communication/serial/send-8bit-receive/send-8bit-receive.ino
deleted file mode 100644
index 9e852559a2..0000000000
--- a/examples/examples-communication/serial/send-8bit-receive/send-8bit-receive.ino
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * @file send-8bit-receive.ino
- * @author Phil Schatzmann
- * @brief Sending and receiving audio via Serial. You need to connect the RX pin
- * with the TX pin!
- *
- * We send 8bit data over the wire, so any (small) data loss will not be audible
- *
- * @version 0.1
- * @date 2023-11-25
- *
- * @copyright Copyright (c) 2022
- */
-
-#include "AudioTools.h"
-// #include "AudioTools/AudioLibs/AudioBoardStream.h"
-
-AudioInfo info(44100, 2, 16);
-I2SStream out; // or AnalogAudioStream, AudioBoardStream etc
-SineWaveGenerator sineWave(32000);
-GeneratedSoundStream sound(sineWave);
-auto &serial = Serial2;
-EncoderL8 enc;
-DecoderL8 dec;
-EncodedAudioStream enc_stream(&serial, &enc);
-EncodedAudioStream dec_stream(&out, &dec);
-Throttle throttle(enc_stream);
-StreamCopy copierOut(throttle, sound, 256); // copies sound into Serial
-StreamCopy copierIn(dec_stream, serial, 256); // copies sound from Serial
-
-void setup() {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
-
- // Note the format for setting a serial port is as follows:
- // Serial.begin(baud-rate, protocol, RX pin, TX pin);
- Serial2.begin(3000000, SERIAL_8N1);
-
- sineWave.begin(info, N_B4);
- throttle.begin(info);
- enc_stream.begin(info);
- dec_stream.begin(info);
-
- // start I2S
- auto config = out.defaultConfig(TX_MODE);
- config.copyFrom(info);
- out.begin(config);
-
- // better visibility in logging
- copierOut.setLogName("out");
- copierIn.setLogName("in");
-}
-
-void loop() {
- // copy to serial
- copierOut.copy();
- // copy from serial
- copierIn.copy();
-}
\ No newline at end of file
diff --git a/examples/examples-communication/serial/send-adpcm-receive/send-adpcm-receive.ino b/examples/examples-communication/serial/send-adpcm-receive/send-adpcm-receive.ino
deleted file mode 100644
index bcf104e3d0..0000000000
--- a/examples/examples-communication/serial/send-adpcm-receive/send-adpcm-receive.ino
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * @file send-adpcm-receive.ino
- * @author Phil Schatzmann
- * @brief Sending and receiving audio via Serial. You need to connect the RX pin
- * with the TX pin!
- *
- * We send encoded ADPCM audio over the serial wire: The higher the transmission rate
- * the higher the risk of data loss!
- *
- * @version 0.1
- * @date 2023-11-25
- *
- * @copyright Copyright (c) 2022
- */
-
-#include "AudioTools.h"
-#include "AudioTools/AudioCodecs/CodecADPCM.h" // https://github.com/pschatzmann/adpcm
-//#include "AudioTools/AudioLibs/AudioBoardStream.h"
-
-AudioInfo info(22000, 1, 16);
-I2SStream out; // or AnalogAudioStream, AudioBoardStream etc
-SineWaveGenerator sineWave(32000);
-GeneratedSoundStream sound(sineWave);
-
-auto &serial = Serial2;
-ADPCMEncoder enc(AV_CODEC_ID_ADPCM_IMA_WAV);
-ADPCMDecoder dec(AV_CODEC_ID_ADPCM_IMA_WAV);
-EncodedAudioStream enc_stream(&serial, &enc);
-EncodedAudioStream dec_stream(&out, &dec);
-Throttle throttle(enc_stream);
-static int frame_size = 498;
-StreamCopy copierOut(throttle, sound, frame_size); // copies sound into Serial
-StreamCopy copierIn(dec_stream, serial, frame_size); // copies sound from Serial
-
-void setup() {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
-
- // Note the format for setting a serial port is as follows:
- // Serial.begin(baud-rate, protocol, RX pin, TX pin);
- Serial2.begin(115200, SERIAL_8N1);
-
- sineWave.begin(info, N_B4);
- throttle.begin(info);
- enc_stream.begin(info);
- dec_stream.begin(info);
-
- // start I2S
- auto config = out.defaultConfig(TX_MODE);
- config.copyFrom(info);
- out.begin(config);
-
- // better visibility in logging
- copierOut.setLogName("out");
- copierIn.setLogName("in");
-
-}
-
-void loop() {
- // copy to serial
- copierOut.copy();
- // copy from serial
- copierIn.copy();
-}
\ No newline at end of file
diff --git a/examples/examples-communication/serial/send-adpcm_framed-receive/send-adpcm_framed-receive.ino b/examples/examples-communication/serial/send-adpcm_framed-receive/send-adpcm_framed-receive.ino
deleted file mode 100644
index a25b96545d..0000000000
--- a/examples/examples-communication/serial/send-adpcm_framed-receive/send-adpcm_framed-receive.ino
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * @file send-adpcm-receive.ino
- * @author Phil Schatzmann
- * @brief Sending and receiving audio via Serial. You need to connect the RX pin
- * with the TX pin!
- *
- * We send encoded ADPCM audio over the serial wire. In order to be able to recover
- * from data loss in the encoded frames we use a Container
- *
- * @version 0.1
- * @date 2023-11-25
- *
- * @copyright Copyright (c) 2022
- */
-
-#include "AudioTools.h"
-#include "AudioTools/AudioCodecs/CodecADPCM.h" // https://github.com/pschatzmann/adpcm
-#include "AudioTools/AudioCodecs/ContainerBinary.h"
-// #include "AudioTools/AudioLibs/AudioBoardStream.h"
-
-AudioInfo info(44100, 2, 16);
-I2SStream out; // or AnalogAudioStream, AudioBoardStream etc
-SineWaveGenerator sineWave(32000);
-GeneratedSoundStream sound(sineWave);
-
-auto &serial = Serial2;
-ADPCMEncoder enc(AV_CODEC_ID_ADPCM_IMA_WAV);
-ADPCMDecoder dec(AV_CODEC_ID_ADPCM_IMA_WAV);
-BinaryContainerEncoder bin_enc(&enc);
-BinaryContainerDecoder bin_dec(&dec);
-EncodedAudioOutput enc_stream(&serial, &bin_enc);
-EncodedAudioOutput dec_stream(&out, &bin_dec);
-Throttle throttle(enc_stream);
-static int frame_size = 498;
-StreamCopy copierOut(throttle, sound, frame_size); // copies sound into Serial
-StreamCopy copierIn(dec_stream, serial, frame_size); // copies sound from Serial
-
-void setup() {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
-
- // Note the format for setting a serial port is as follows:
- // Serial.begin(baud-rate, protocol, RX pin, TX pin);
- Serial2.begin(1100000, SERIAL_8N1);
-
- sineWave.begin(info, N_B4);
- throttle.begin(info);
-
-// increase the reliability
- dec_stream.setFrameSize(frame_size);
- enc_stream.setFrameSize(frame_size);
-
- enc_stream.begin(info);
- dec_stream.begin(info);
-
-
- // start I2S
- auto config = out.defaultConfig(TX_MODE);
- config.copyFrom(info);
- out.begin(config);
-
- // better visibility in logging
- copierOut.setLogName("out");
- copierIn.setLogName("in");
-
-}
-
-void loop() {
- // copy to serial
- copierOut.copy();
- // copy from serial
- copierIn.copy();
-}
\ No newline at end of file
diff --git a/examples/examples-communication/serial/send-receive/send-receive.ino b/examples/examples-communication/serial/send-receive/send-receive.ino
index 0227ca1fb7..4286c8969e 100644
--- a/examples/examples-communication/serial/send-receive/send-receive.ino
+++ b/examples/examples-communication/serial/send-receive/send-receive.ino
@@ -3,9 +3,6 @@
* @author Phil Schatzmann
* @brief Sending and receiving audio via Serial. You need to connect the RX pin
* with the TX pin!
- * The sine wave generator is providing the data as fast as possible, therefore we
- * throttle on the sending side to prevent that the receiver is getting the data
- * too fast.
*
* @version 0.1
* @date 2022-03-09
@@ -14,38 +11,33 @@
*/
#include "AudioTools.h"
-// #include "AudioTools/AudioLibs/AudioBoardStream.h"
+// #include "AudioLibs/AudioKit.h"
AudioInfo info(22000, 1, 16);
SineWaveGenerator sineWave(32000);
GeneratedSoundStream sound(sineWave);
-I2SStream out; // or AnalogAudioStream, AudioBoardStream etc
-auto &serial = Serial2;
-Throttle throttle(serial);
-StreamCopy copierOut(throttle, sound, 256); // copies sound into Serial
-StreamCopy copierIn(out, serial, 256); // copies sound from Serial
+I2SStream out; // or AudioKitStream
+StreamCopy copierOut(Serial, sound, 256); // copies sound into Serial
+StreamCopy copierIn(out, Serial, 256); // copies sound from Serial
void setup() {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
+ Serial2.begin(115200);
+ AudioLogger::instance().begin(Serial2, AudioLogger::Warning);
// Note the format for setting a serial port is as follows:
// Serial.begin(baud-rate, protocol, RX pin, TX pin);
- Serial2.begin(3000000, SERIAL_8N1 );
+ Serial.begin(1000000, SERIAL_8N1);
// Setup sine wave
sineWave.begin(info, N_B4);
- throttle.begin(info);
// start I2S
+ Serial.println("starting I2S...");
auto config = out.defaultConfig(TX_MODE);
config.copyFrom(info);
out.begin(config);
- // better visibility in logging
- copierOut.setLogName("out");
- copierIn.setLogName("in");
-
+ Serial.println("started...");
}
void loop() {
diff --git a/examples/examples-communication/snapcast/snapclient-i2s/snapclient-i2s.ino b/examples/examples-communication/snapcast/snapclient-i2s/snapclient-i2s.ino
deleted file mode 100644
index fe5ef1ab43..0000000000
--- a/examples/examples-communication/snapcast/snapclient-i2s/snapclient-i2s.ino
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * @file send-receive.ino
- * @author Phil Schatzmann
- * @brief Receive audio sent by snapcast on an ESP32 and output to i2s.
- * I was testing with ffmpeg -i http://stream.srg-ssr.ch/m/rsj/mp3_128 -f s16le -ar 48000 /tmp/snapfifo
- * More examples can be found at https://github.com/pschatzmann/arduino-snapclient/tree/main/examples
- * @version 0.1
- * @date 2023-09-25
- *
- * @copyright Copyright (c) 2022
- */
-
-/**
- * @brief SnapClient with Opus decoder: I2S OUtput
- * @author Phil Schatzmann
- * @copyright GPLv3
- */
-
-#include "AudioTools.h"
-#include "SnapClient.h"
-#include "AudioTools/AudioCodecs/CodecOpus.h"
-
-#define ARDUINO_LOOP_STACK_SIZE (10 * 1024)
-
-OpusAudioDecoder opus;
-I2SStream out;
-WiFiClient wifi;
-SnapTimeSyncDynamic synch(172, 10); // optional configuratioin
-SnapClient client(wifi, out, opus);
-
-void setup() {
- Serial.begin(115200);
-
- // login to wifi -> Define values in SnapConfig.h or replace them here
- WiFi.begin(CONFIG_WIFI_SSID, CONFIG_WIFI_PASSWORD);
- Serial.print("Connecting to WiFi ..");
- while (WiFi.status() != WL_CONNECTED) {
- Serial.print('.');
- delay(1000);
- }
-
- // print ip address
- Serial.println();
- Serial.println(WiFi.localIP());
-
- // setup I2S to define custom pins
- auto cfg = out.defaultConfig();
- cfg.pin_bck = 14;
- cfg.pin_ws = 15;
- cfg.pin_data = 22;
- //cfg.buffer_size = 512;
- //cfg.buffer_count = 6;
- out.begin(cfg);
-
- // Define CONFIG_SNAPCAST_SERVER_HOST in SnapConfig.h or here
- // client.setServerIP(IPAddress(192,168,1,38));
-
- // start snap client
- client.begin(synch);
-}
-
-void loop() {
- client.doLoop();
-}
\ No newline at end of file
diff --git a/examples/examples-communication/udp/communication-udp-receive/communication-udp-receive.ino b/examples/examples-communication/udp/communication-udp-receive/communication-udp-receive.ino
index 1333980e10..a2649e083f 100644
--- a/examples/examples-communication/udp/communication-udp-receive/communication-udp-receive.ino
+++ b/examples/examples-communication/udp/communication-udp-receive/communication-udp-receive.ino
@@ -11,20 +11,20 @@
* */
#include "AudioTools.h"
-#include "AudioTools/Communication/UDPStream.h"
-// #include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/Communication.h"
+// #include "AudioLibs/AudioKit.h"
const char* ssid="SSID";
const char* password="password";
AudioInfo info(22000, 1, 16);
UDPStream udp(ssid, password);
const int udpPort = 7000;
-I2SStream out; // or ony other e.g. AudioBoardStream
+I2SStream out; // or ony other e.g. AudioKitStream
StreamCopy copier(out, udp);
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// start UDP receive
udp.begin(udpPort);
diff --git a/examples/examples-communication/udp/communication-udp-send/communication-udp-send.ino b/examples/examples-communication/udp/communication-udp-send/communication-udp-send.ino
index b46fb3bbd2..4b075066d4 100644
--- a/examples/examples-communication/udp/communication-udp-send/communication-udp-send.ino
+++ b/examples/examples-communication/udp/communication-udp-send/communication-udp-send.ino
@@ -10,7 +10,7 @@
*/
#include "AudioTools.h"
-#include "AudioTools/Communication/UDPStream.h"
+#include "AudioLibs/Communication.h"
const char *ssid = "ssid";
const char *password = "password";
@@ -18,18 +18,15 @@ AudioInfo info(22000, 1, 16);
SineWaveGenerator sineWave( 32000); // subclass of SoundGenerator with max amplitude of 32000
GeneratedSoundStream sound( sineWave); // Stream generated from sine wave
UDPStream udp(ssid, password);
-Throttle throttle(udp);
+Throttle throttle;
IPAddress udpAddress(192, 168, 1, 255);
const int udpPort = 7000;
-StreamCopy copier(throttle, sound); // copies sound into i2s
+StreamCopy copier(udp, sound); // copies sound into i2s
void setup() {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- // Setup sine wave
- sineWave.begin(info, N_B4);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// Define udp address and port
udp.begin(udpAddress, udpPort);
@@ -40,9 +37,13 @@ void setup() {
//cfg.correction_ms = 0;
throttle.begin(cfg);
+ // Setup sine wave
+ sineWave.begin(info, N_B4);
Serial.println("started...");
}
void loop() {
- copier.copy();
+ throttle.startDelay();
+ int bytes = copier.copy();
+ throttle.delayBytes(bytes);
}
\ No newline at end of file
diff --git a/examples/examples-communication/usb/adafruit/adafruit.ino b/examples/examples-communication/usb/adafruit/adafruit.ino
deleted file mode 100644
index d1a0ed26f6..0000000000
--- a/examples/examples-communication/usb/adafruit/adafruit.ino
+++ /dev/null
@@ -1,69 +0,0 @@
-#include "AudioTools.h"
-#include "AudioTools/Sandbox/USB/USBDeviceAudioAdafruit.h"
-
-size_t sample_count_mic = 0;
-size_t sample_count_spk = 0;
-
-// Microphone: generate data for USB
-size_t readCB(uint8_t* data, size_t len, USBDeviceAudio& ref) {
- int16_t* data16 = (int16_t*)data;
- size_t samples = len / sizeof(int16_t);
- size_t result = 0;
- // generate random stereo data
- for (int j = 0; j < samples; j+=2) {
- data16[j] = random(-32000, 32000);
- data16[j+1] = random(-32000, 32000);;
- result += sizeof(int16_t)*2;
- sample_count_mic += 2;
- }
- return result;
-}
-
-// Speaker: receive data from USB and write them to the final destination
-size_t writeCB(const uint8_t* data, size_t len, USBDeviceAudio & ref) {
- int16_t* data16 = (int16_t*)data;
- size_t samples = len / sizeof(int16_t);
- sample_count_spk += samples;
- return len;
-}
-
-auto config() {
- USBAudioConfig result;
- result.p_read_callback = readCB;
- result.p_write_callback = writeCB;
- return result;
-}
-
-USBDeviceAudioAdafruit usb{config()};
-
-void setup() {
- // Manual begin() is required on core without built-in support e.g. mbed rp2040
- if (!TinyUSBDevice.isInitialized()) {
- TinyUSBDevice.begin(0);
- }
-
- Serial.begin(115200);
-
- // If already enumerated, additional class driver begin() e.g msc, hid, midi won't take effect until re-enumeration
- if (TinyUSBDevice.mounted()) {
- TinyUSBDevice.detach();
- delay(10);
- TinyUSBDevice.attach();
- }
-}
-
-void loop() {
- #ifdef TINYUSB_NEED_POLLING_TASK
- // Manual call tud_task since it isn't called by Core's background
- TinyUSBDevice.task();
- #endif
- // use LED do display status
- if (usb.updateLED(LED_BUILTIN)){
- Serial.print("Total Microphone samples: ");
- Serial.print(sample_count_mic);
- Serial.print(" / Speaker samples: ");
- Serial.print(sample_count_spk);
- Serial.print(" / Sample rate: ");
- Serial.println(usb.rate());
- }
-}
\ No newline at end of file
diff --git a/examples/examples-communication/usb/microphone/microphone.ino b/examples/examples-communication/usb/microphone/microphone.ino
deleted file mode 100644
index ab84042728..0000000000
--- a/examples/examples-communication/usb/microphone/microphone.ino
+++ /dev/null
@@ -1,51 +0,0 @@
-/*********************************************************************
- This example generates a sawtooth that you can output on your PC
- We use the AudioTools to generate the data input.
-
- We could use the callback function here as well, but we demo how
- to integrate with a (fast) Arduino Stream.
-
- Please read the Wiki of the project for the supported platforms!
-
-*********************************************************************/
-
-#include "Adafruit_TinyUSB.h" // https://github.com/pschatzmann/Adafruit_TinyUSB_Arduino
-#include "AudioTools.h" // https://github.com/pschatzmann/arduino-audio-tools
-
-Adafruit_USBD_Audio usb;
-AudioInfo info(44100, 2, 16);
-SawToothGenerator sawtooth;
-GeneratedSoundStream sawthooth_stream(sawtooth);
-
-void setup() {
- // Manual begin() is required on core without built-in support e.g. mbed rp2040
- if (!TinyUSBDevice.isInitialized()) {
- TinyUSBDevice.begin(0);
- }
-
- Serial.begin(115200);
- //while(!Serial); // wait for serial
-
- // generate 493 hz (note B4)
- sawtooth.begin(info, 493.0f);
-
- // Start USB device as Audio Source
- usb.setInput(sawthooth_stream);
- usb.begin(info.sample_rate, info.channels, info.bits_per_sample);
-
- // If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
- if (TinyUSBDevice.mounted()) {
- TinyUSBDevice.detach();
- delay(10);
- TinyUSBDevice.attach();
- }
-}
-
-void loop() {
- #ifdef TINYUSB_NEED_POLLING_TASK
- // Manual call tud_task since it isn't called by Core's background
- TinyUSBDevice.task();
- #endif
- // optional: use LED do display status
- usb.updateLED();
-}
\ No newline at end of file
diff --git a/examples/examples-communication/vban/player-sdmmc-vban/player-sdmmc-vban.ino b/examples/examples-communication/vban/player-sdmmc-vban/player-sdmmc-vban.ino
deleted file mode 100644
index 3dd3f51443..0000000000
--- a/examples/examples-communication/vban/player-sdmmc-vban/player-sdmmc-vban.ino
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * @file player-sdmmc-vban.ino
- * @author Phil Schatzmann
- * @brief decodes mp3 to vban: We need to use a queue to prevent delays to get too big.
- * We try to keep the queue filled, so that we can always provide pcm data to vban
- */
-
-#include "AudioTools.h"
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
-#include "AudioTools/AudioLibs/VBANStream.h"
-#include "AudioTools/Disk/AudioSourceSDMMC.h" // or AudioSourceIdxSDMMC.h
-
-const char *startFilePath="/";
-const char* ext="mp3";
-const int mp3_pcm_size = 14000;
-AudioInfo info(44100,2,16);
-AudioSourceSDMMC source(startFilePath, ext);
-RingBuffer ring_buffer(mp3_pcm_size*3);
-QueueStream queue(ring_buffer);
-MP3DecoderHelix decoder; // or change to MP3DecoderMAD
-AudioPlayer player(source, queue, decoder);
-
-VBANStream out;
-StreamCopy copier(out, queue, 2048); // 44100 needs 2048
-
-
-void fillQueue(){
- // fill queue when smaller then limit
- if(ring_buffer.availableForWrite() >= mp3_pcm_size){
- player.copy();
- // activate copy when limit is reached
- if (!copier.isActive() && ring_buffer.available()>=23000){
- copier.setActive(true);
- LOGI("copier active");
- }
- }
- LOGI("available: %d - avail to write: %d", ring_buffer.available(), ring_buffer.availableForWrite());
-}
-
-
-void setup() {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
-
- // setup output
- auto cfg = out.defaultConfig(TX_MODE);
- cfg.copyFrom(info);
- cfg.ssid = "ssid";
- cfg.password = "password";
- cfg.stream_name = "Stream1";
- cfg.target_ip = IPAddress{192,168,1,37};
- cfg.throttle_active = true;
- //cfg.throttle_correction_us = 0;
- if (!out.begin(cfg)) stop();
-
- // setup player
- player.setVolume(0.7);
- player.begin();
-
- // select file with setPath() or setIndex()
- //player.setPath("/ZZ Top/Unknown Album/Lowrider.mp3");
- //player.setIndex(1); // 2nd file
-
- queue.begin(); // start queue
- copier.setActive(false); // deactivate copy
-
-}
-
-void loop() {
- fillQueue();
- // output from queue
- copier.copy();
-}
\ No newline at end of file
diff --git a/examples/examples-communication/vban/streams-audiokit-vban/streams-audiokit-vban.ino b/examples/examples-communication/vban/streams-audiokit-vban/streams-audiokit-vban.ino
deleted file mode 100644
index c356859ded..0000000000
--- a/examples/examples-communication/vban/streams-audiokit-vban/streams-audiokit-vban.ino
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * @file streams-i2s-vban.ino
- * @author Phil Schatzmann
- * @brief sends signal from i2s (using an AudioKit) to VBAN Receptor App
- */
-
-#include "AudioTools.h"
-#include "AudioTools/AudioLibs/VBANStream.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h" // comment out when not using AudioKit
-
-AudioInfo info(44100, 2, 16);
-AudioBoardStream in(AudioKitEs8388V1); // Audio source e.g. replace with I2SStream
-VBANStream out;
-StreamCopy copier(out, in, 2048); // copies sound into i2s
-
-// Arduino Setup
-void setup(void) {
- // Open Serial
- Serial.begin(115200);
- while(!Serial);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- // setup output
- auto cfg = out.defaultConfig(TX_MODE);
- cfg.copyFrom(info);
- cfg.ssid = "ssid";
- cfg.password = "password";
- cfg.stream_name = "Stream1";
- cfg.target_ip = IPAddress{192,168,1,37}; // comment out to broadcast
- cfg.throttle_active = false; // generator is much too fast, we need to stall
- if (!out.begin(cfg)) stop();
-
- // Setup input from mic
- // setup input
- auto cfg_in = in.defaultConfig(RX_MODE);
- cfg_in.sd_active = false;
- cfg_in.buffer_size = 256;
- cfg_in.buffer_count = 4;
- cfg_in.copyFrom(info);
- cfg_in.input_device = ADC_INPUT_LINE2; // microphone
- in.begin(cfg_in);
-}
-
-// Arduino loop - copy sound to out
-void loop() {
- copier.copy();
-}
\ No newline at end of file
diff --git a/examples/examples-communication/vban/streams-generator-vban/streams-generator-vban.ino b/examples/examples-communication/vban/streams-generator-vban/streams-generator-vban.ino
deleted file mode 100644
index 2a149c8342..0000000000
--- a/examples/examples-communication/vban/streams-generator-vban/streams-generator-vban.ino
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * @file streams-generator-vban.ino
- * @author Phil Schatzmann
- * @brief sends sine test signal to VBAN Receptor App
- */
-
-#include "AudioTools.h"
-#include "AudioTools/AudioLibs/VBANStream.h"
-
-AudioInfo info(44100, 2, 16);
-SineWaveGenerator sineWave(32000); // subclass of SoundGenerator with max amplitude of 32000
-GeneratedSoundStream sound(sineWave); // Stream generated from sine wave
-VBANStream out;
-StreamCopy copier(out, sound, 2048); // 44100 needs 2048
-
-// Arduino Setup
-void setup(void) {
- // Open Serial
- Serial.begin(115200);
- while(!Serial);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- // setup output
- auto cfg = out.defaultConfig(TX_MODE);
- cfg.copyFrom(info);
- cfg.ssid = "ssid";
- cfg.password = "password";
- cfg.stream_name = "Stream1";
- cfg.target_ip = IPAddress{192,168,1,37};
- cfg.throttle_active = true;
- //cfg.throttle_correction_us = 0; // optimize overload and underrun
- if (!out.begin(cfg)) stop();
-
- // Setup sine wave
- sineWave.begin(info, N_B4);
- Serial.println("started...");
-}
-
-// Arduino loop - copy sound to out
-void loop() {
- copier.copy();
-}
\ No newline at end of file
diff --git a/examples/examples-communication/vban/streams-vban-audiokit/streams-vban-audiokit.ino b/examples/examples-communication/vban/streams-vban-audiokit/streams-vban-audiokit.ino
deleted file mode 100644
index a82dbfcbc4..0000000000
--- a/examples/examples-communication/vban/streams-vban-audiokit/streams-vban-audiokit.ino
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * @file streams-i2s-vban.ino
- * @author Phil Schatzmann
- * @brief sends signal from i2s (using an AudioKit) to VBAN Receptor App
- */
-
-#include "AudioTools.h"
-#include "AudioTools/AudioLibs/VBANStream.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h" // comment out when not using AudioKit
-
-AudioBoardStream out(AudioKitEs8388V1); // Audio source e.g. replace with I2SStream
-VBANStream in;
-StreamCopy copier(out, in); // copies sound into i2s
-
-// Arduino Setup
-void setup(void) {
- // Open Serial
- Serial.begin(115200);
- while(!Serial);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- // setup output
- auto cfg_out = out.defaultConfig(TX_MODE);
- if (!out.begin(cfg_out)) stop();
-
- // format changes in vban must change the output as well
- in.addNotifyAudioChange(out);
-
- // setup input from vban
- auto cfg_in = in.defaultConfig(RX_MODE);
- cfg_in.ssid = "ssid";
- cfg_in.password = "password";
- cfg_in.stream_name = "Talkie";
- in.begin(cfg_in);
-}
-
-// Arduino loop - copy sound to out
-void loop() {
- copier.copy();
-}
\ No newline at end of file
diff --git a/examples/examples-custom-boards/cross_band_handy_walkie_talkie/cross_band_handy_walkie_talkie.ino b/examples/examples-custom-boards/cross_band_handy_walkie_talkie/cross_band_handy_walkie_talkie.ino
index b16295bf75..1c9475d3ca 100644
--- a/examples/examples-custom-boards/cross_band_handy_walkie_talkie/cross_band_handy_walkie_talkie.ino
+++ b/examples/examples-custom-boards/cross_band_handy_walkie_talkie/cross_band_handy_walkie_talkie.ino
@@ -8,42 +8,48 @@
*/
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
+#include "AudioLibs/AudioKit.h"
#include "SD.h"
AudioInfo info(32000, 2, 16);
-SineWaveGenerator sineWave(
- 32000); // subclass of SoundGenerator with max amplitude of 32000
-GeneratedSoundStream sound(
- sineWave); // Stream generated from sine wave
-DriverPins my_pins;
-AudioBoard board(AudioDriverES8388, my_pins);
-AudioBoardStream out(board);
-StreamCopy copier(out, sound); // copies sound into i2s
+SineWaveGenerator sineWave(32000); // subclass of SoundGenerator with max amplitude of 32000
+GeneratedSoundStream sound(sineWave); // Stream generated from sine wave
+AudioKitStream out;
+StreamCopy copier(out, sound); // copies sound into i2s
// Arduino Setup
void setup(void) {
// Open Serial
Serial.begin(115200);
- while (!Serial);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- // sd pins: clk, miso, mosi,cs,
- my_pins.addSPI(ESP32PinsSD{PinFunction::SD, 44, 42, 43, 2, SPI});
- // add i2c codec pins: scl, sda, port, frequency
- my_pins.addI2C(PinFunction::CODEC, 35, 36);
- // add i2s pins: mclk, bck, ws,data_out, data_in ,(port)
- my_pins.addI2S(PinFunction::CODEC, 47, 21, 12, 14, 11);
+ while(!Serial);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
+ //LOGLEVEL_AUDIOKIT = AudioKitDebug;
// start I2S
Serial.println("starting I2S...");
auto config = out.defaultConfig(TX_MODE);
config.copyFrom(info);
- config.sd_active = true;
+ config.sd_active = false;
+ config.default_actions_active = flase;
+ // i2c
+ config.pins.i2c_sda = 36;
+ config.pins.i2c_scl = 35;
+ // i2s
+ config.pin_mclk = 47
+ config.pin_bck = 21;
+ config.pin_ws = 12;
+ config.pin_data = 14;
+ config.pin_data_in = 11;
+
+ //config.sd_active = false;
+ config.pins.sd_cs = 2;
+ config.pins.sd_miso = 42;
+ config.pins.sd_mosi = 43;
+ config.pins.sd_clk = 44;
out.begin(config);
// check SD drive
- if (!SD.begin(2)) {
+ if(!SD.begin(config.pins.sd_cs)){
Serial.println("Card Mount Failed");
stop();
}
@@ -54,4 +60,6 @@ void setup(void) {
}
// Arduino loop - copy sound to out
-void loop() { copier.copy(); }
\ No newline at end of file
+void loop() {
+ copier.copy();
+}
\ No newline at end of file
diff --git a/examples/examples-custom-boards/esp32-audio-dev-mini/esp32-audio-dev-mini.ino b/examples/examples-custom-boards/esp32-audio-dev-mini/esp32-audio-dev-mini.ino
index ca08ee228d..7bbde9a3f2 100644
--- a/examples/examples-custom-boards/esp32-audio-dev-mini/esp32-audio-dev-mini.ino
+++ b/examples/examples-custom-boards/esp32-audio-dev-mini/esp32-audio-dev-mini.ino
@@ -18,7 +18,7 @@ void setup(void) {
// Open Serial
Serial.begin(115200);
while(!Serial);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// start I2S
Serial.println("starting I2S...");
diff --git a/examples/examples-custom-boards/esp32s3-mic-cam/Overview.jpg b/examples/examples-custom-boards/esp32s3-mic-cam/Overview.jpg
deleted file mode 100644
index 668e75eb30..0000000000
Binary files a/examples/examples-custom-boards/esp32s3-mic-cam/Overview.jpg and /dev/null differ
diff --git a/examples/examples-custom-boards/esp32s3-mic-cam/README.md b/examples/examples-custom-boards/esp32s3-mic-cam/README.md
deleted file mode 100644
index 3ab9848c5d..0000000000
--- a/examples/examples-custom-boards/esp32s3-mic-cam/README.md
+++ /dev/null
@@ -1,16 +0,0 @@
-
-## ESP32S3 Camera Baord
-
-Here are the sketches which test the functionality of this ESP32 S3 camera board
-
-
-
-
-Here is a summary of the limitations/issues that I have found:
-
-- I could not make the 4 pin SDMMC to work.
-- The microphone just provides noise
-- The board has no Boot button, so you can not set the board easily into upload mode. Here is the work around:
- - connect GND with Pin 0
- - press and release the SWT2 (Reset/EN button)
- - disconnect Pin 0
\ No newline at end of file
diff --git a/examples/examples-custom-boards/esp32s3-mic-cam/Schematic Diagram.pdf b/examples/examples-custom-boards/esp32s3-mic-cam/Schematic Diagram.pdf
deleted file mode 100644
index c2bc7369e2..0000000000
Binary files a/examples/examples-custom-boards/esp32s3-mic-cam/Schematic Diagram.pdf and /dev/null differ
diff --git a/examples/examples-custom-boards/esp32s3-mic-cam/button/button.ino b/examples/examples-custom-boards/esp32s3-mic-cam/button/button.ino
deleted file mode 100644
index c89172ad8e..0000000000
--- a/examples/examples-custom-boards/esp32s3-mic-cam/button/button.ino
+++ /dev/null
@@ -1,13 +0,0 @@
-
-/// If button is pressed it is pulled low
-
-const int BUTTON = 38;
-
-void setup() {
- Serial.begin(115200);
- pinMode(BUTTON, INPUT);
-}
-
-void loop() {
- Serial.println(digitalRead(BUTTON));
-}
\ No newline at end of file
diff --git a/examples/examples-custom-boards/esp32s3-mic-cam/camera/Camera.h b/examples/examples-custom-boards/esp32s3-mic-cam/camera/Camera.h
deleted file mode 100644
index ff53fd02a8..0000000000
--- a/examples/examples-custom-boards/esp32s3-mic-cam/camera/Camera.h
+++ /dev/null
@@ -1,89 +0,0 @@
-#pragma once
-
-#include
-#include "esp_camera.h"
-
-class Camera;
-
-/***
- * @brief A simple Arduino C++ API over the ESP32 camera functionality.
- * @author Phil Schatzmann
- */
-
-class Camera {
- // esp_camera_fb_return
- struct Deleter {
- void operator()(camera_fb_t *ptr) const {
- if (ptr) {
- esp_camera_fb_return(ptr);
- }
- }
- };
-
- public:
- Camera() = default;
- /**
- * @brief Initialize the camera driver
- *
- * @note call camera_probe before calling this function
- *
- * This function detects and configures camera over I2C interface,
- * allocates framebuffer and DMA buffers,
- * initializes parallel I2S input, and sets up DMA descriptors.
- *
- * Currently this function can only be called once and there is
- * no way to de-initialize this module.
- *
- * @param config Camera configuration parameters
- *
- * @return RESULT_OK on success
- */
- bool begin(const camera_config_t &config) {
- return esp_camera_init(&config) == ESP_OK;
- }
-
- /**
- * @brief Deinitialize the camera driver
- *
- * @return
- * - RESULT_OK on success
- * - ERR_INVALID_STATE if the driver hasn't been initialized yet
- */
- bool end(void) { return esp_camera_deinit() == ESP_OK; }
-
- /**
- * @brief Obtain unique_ptr to a frame buffer.
- *
- * @return pointer to the frame buffer
- */
- auto frameBuffer(void) {
- return std::unique_ptr(esp_camera_fb_get());
- }
-
- /**
- * @brief Save camera settings to non-volatile-storage (NVS)
- *
- * @param key A unique nvs key name for the camera settings
- */
- bool settingsSave(const char *key) {
- return esp_camera_save_to_nvs(key) == ESP_OK;
- }
-
- /**
- * @brief Load camera settings from non-volatile-storage (NVS)
- *
- * @param key A unique nvs key name for the camera settings
- */
- bool settingsLoad(const char *key) {
- return esp_camera_load_from_nvs(key) == ESP_OK;
- }
-
- /**
- * @brief Return the frame buffer to be reused again.
- *
- * @param fb Pointer to the frame buffer
- */
- void returnFrameBuffer(camera_fb_t &fb) { return esp_camera_fb_return(&fb); }
-};
-
-
diff --git a/examples/examples-custom-boards/esp32s3-mic-cam/camera/camera.ino b/examples/examples-custom-boards/esp32s3-mic-cam/camera/camera.ino
deleted file mode 100644
index 8592486b60..0000000000
--- a/examples/examples-custom-boards/esp32s3-mic-cam/camera/camera.ino
+++ /dev/null
@@ -1,68 +0,0 @@
-
-// important settings:
-// - USB CDC on Boot: Enabled (to see the Serial.print)
-// - PSRAM: QSPI PSRAM (to have enough memory for the framebuffer)
-
-#include "Camera.h"
-
-#define XCLK_GPIO_NUM 10
-#define SIOD_GPIO_NUM 21
-#define SIOC_GPIO_NUM 14
-#define Y9_GPIO_NUM 11
-#define Y8_GPIO_NUM 9
-#define Y7_GPIO_NUM 8
-#define Y6_GPIO_NUM 6
-#define Y5_GPIO_NUM 4
-#define Y4_GPIO_NUM 2
-#define Y3_GPIO_NUM 3
-#define Y2_GPIO_NUM 5
-#define VSYNC_GPIO_NUM 13
-#define HREF_GPIO_NUM 12
-#define PCLK_GPIO_NUM 7
-#define LED_GPIO_NUM 34
-
-Camera camera;
-camera_config_t config;
-
-void setup() {
- Serial.begin(115200);
- while(!Serial);
-
- config.ledc_timer = LEDC_TIMER_0;
- config.pin_d0 = Y2_GPIO_NUM;
- config.pin_d1 = Y3_GPIO_NUM;
- config.pin_d2 = Y4_GPIO_NUM;
- config.pin_d3 = Y5_GPIO_NUM;
- config.pin_d4 = Y6_GPIO_NUM;
- config.pin_d5 = Y7_GPIO_NUM;
- config.pin_d6 = Y8_GPIO_NUM;
- config.pin_d7 = Y9_GPIO_NUM;
- config.pin_xclk = XCLK_GPIO_NUM;
- config.pin_pclk = PCLK_GPIO_NUM;
- config.pin_vsync = VSYNC_GPIO_NUM;
- config.pin_href = HREF_GPIO_NUM;
- config.pin_sccb_sda = SIOD_GPIO_NUM;
- config.pin_sccb_scl = SIOC_GPIO_NUM;
- config.xclk_freq_hz = 20000000;
- config.pixel_format = PIXFORMAT_JPEG; // YUV422,GRAYSCALE,RGB565,JPEG
- config.frame_size = FRAMESIZE_HD; //
- config.jpeg_quality = 16;
- config.fb_count = 2; // 8
- config.fb_location = CAMERA_FB_IN_PSRAM; /*!< The location where the frame
- buffer will be allocated */
- config.grab_mode = CAMERA_GRAB_LATEST; /*!< When buffers should be filled */
-
-
- if (!camera.begin(config)){
- Serial.println("Camera failed");
- while(true);
- }
- Serial.print("Recording...");
-}
-
-void loop() {
-
- auto fb = camera.frameBuffer();
- Serial.println(fb->len);
-
-}
\ No newline at end of file
diff --git a/examples/examples-custom-boards/esp32s3-mic-cam/color-led/color-led.ino b/examples/examples-custom-boards/esp32s3-mic-cam/color-led/color-led.ino
deleted file mode 100644
index 3c90c9115b..0000000000
--- a/examples/examples-custom-boards/esp32s3-mic-cam/color-led/color-led.ino
+++ /dev/null
@@ -1,19 +0,0 @@
-// Demo for the color LED (SK6812)
-
-#include
-
-const int NUM_LEDS = 1;
-const int DATA_PIN = 33;
-CRGB led;
-
-void setup() {
- FastLED.addLeds(&led, NUM_LEDS);
-}
-void loop() {
- led = CRGB::Red;
- FastLED.show();
- delay(1000);
- led = CRGB::Black;
- FastLED.show();
- delay(1000);
-}
\ No newline at end of file
diff --git a/examples/examples-custom-boards/esp32s3-mic-cam/led/led.ino b/examples/examples-custom-boards/esp32s3-mic-cam/led/led.ino
deleted file mode 100644
index 3bc620056f..0000000000
--- a/examples/examples-custom-boards/esp32s3-mic-cam/led/led.ino
+++ /dev/null
@@ -1,17 +0,0 @@
-// Demo for the LED
-
-const int LED=34;
-
-// the setup function runs once when you press reset or power the board
-void setup() {
- // initialize digital pin as an output.
- pinMode(LED, OUTPUT);
-}
-
-// the loop function runs over and over again forever
-void loop() {
- digitalWrite(LED, HIGH); // turn the LED on (HIGH is the voltage level)
- delay(1000); // wait for a second
- digitalWrite(LED, LOW); // turn the LED off by making the voltage LOW
- delay(1000); // wait for a second
-}
\ No newline at end of file
diff --git a/examples/examples-custom-boards/esp32s3-mic-cam/mic/mic.ino b/examples/examples-custom-boards/esp32s3-mic-cam/mic/mic.ino
deleted file mode 100644
index 815e08e67b..0000000000
--- a/examples/examples-custom-boards/esp32s3-mic-cam/mic/mic.ino
+++ /dev/null
@@ -1,37 +0,0 @@
-// The module comes with a MSM261 I2S Microphone
-// Make sure that USB CDC on Boot is enabled
-
-
-const int I2S_WS = 37;
-const int I2S_SCK = 36;
-const int I2S_SD = 35;
-const AudioInfo info(8000, 1, 16);
-I2SStream i2sStream; // Access I2S as stream
-CsvOutput csvOutput(Serial);
-StreamCopy copier(csvOutput, i2sStream); // copy i2sStream to csvOutput
-
-// Arduino Setup
-void setup(void) {
- Serial.begin(115200);
- AudioLogger::instance().begin(Serial, AudioLogger::Info);
-
- auto cfg = i2sStream.defaultConfig(RX_MODE);
- cfg.copyFrom(info);
- cfg.i2s_format = I2S_STD_FORMAT; // or try with I2S_LSB_FORMAT
- cfg.use_apll = false;
- cfg.pin_data = I2S_SD;
- cfg.pin_mck = I2S_SCK;
- cfg.pin_ws = I2S_WS;
- i2sStream.begin(cfg);
-
- // make sure that we have the correct channels set up
- csvOutput.begin(info);
-
- Serial.println("starting...");
-
-}
-
-// Arduino loop - copy data
-void loop() {
- copier.copy();
-}
\ No newline at end of file
diff --git a/examples/examples-custom-boards/esp32s3-mic-cam/psram/psram.ino b/examples/examples-custom-boards/esp32s3-mic-cam/psram/psram.ino
deleted file mode 100644
index 2d24c17b8e..0000000000
--- a/examples/examples-custom-boards/esp32s3-mic-cam/psram/psram.ino
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-/// set
-/// - USB CDC on Boot: enabled
-/// - PSRAM: QSPI RAM
-
-#include
-
-void setup() {
- Serial.begin(115200);
-
- Serial.printf("Total heap: %d\n", ESP.getHeapSize());
- Serial.printf("Free heap: %d\n", ESP.getFreeHeap());
- Serial.printf("Total PSRAM: %d\n", ESP.getPsramSize());
- Serial.printf("Free PSRAM: %d\n", ESP.getFreePsram());
-}
-
-void loop() {
-
-}
\ No newline at end of file
diff --git a/examples/examples-custom-boards/esp32s3-mic-cam/sd/sd.ino b/examples/examples-custom-boards/esp32s3-mic-cam/sd/sd.ino
deleted file mode 100644
index d046e50635..0000000000
--- a/examples/examples-custom-boards/esp32s3-mic-cam/sd/sd.ino
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * pin 1 - not used | Micro SD card |
- * pin 2 - CS (SS) | /
- * pin 3 - DI (MOSI) | |__
- * pin 4 - VDD (3.3V) | |
- * pin 5 - SCK (SCLK) | 8 7 6 5 4 3 2 1 /
- * pin 6 - VSS (GND) | ▄ ▄ ▄ ▄ ▄ ▄ ▄ ▄ /
- * pin 7 - DO (MISO) | ▀ ▀ █ ▀ █ ▀ ▀ ▀ |
- * pin 8 - not used |_________________|
- * ║ ║ ║ ║ ║ ║ ║ ║
- * ╔═══════╝ ║ ║ ║ ║ ║ ║ ╚═════════╗
- * ║ ║ ║ ║ ║ ║ ╚══════╗ ║
- * ║ ╔═════╝ ║ ║ ║ ╚═════╗ ║ ║
- * Connections for ║ ║ ╔═══╩═║═║═══╗ ║ ║ ║
- * full-sized ║ ║ ║ ╔═╝ ║ ║ ║ ║ ║
- * SD card ║ ║ ║ ║ ║ ║ ║ ║ ║
- * Pin name | - DO VSS SCK VDD VSS DI CS - |
- * SD pin number | 8 7 6 5 4 3 2 1 9 /
- * | █/
- * |__▍___▊___█___█___█___█___█___█___/
- *
- * Note: The SPI pins can be manually configured by using `SPI.begin(sck, miso, mosi, cs).`
- * Alternatively, you can change the CS pin and use the other default settings by using `SD.begin(cs)`.
- *
- * +--------------+---------+-------+----------+----------+----------+----------+----------+
- * | SPI Pin Name | ESP8266 | ESP32 | ESP32‑S2 | ESP32‑S3 | ESP32‑C3 | ESP32‑C6 | ESP32‑H2 |
- * +==============+=========+=======+==========+==========+==========+==========+==========+
- * | CS (SS) | GPIO15 | GPIO5 | GPIO34 | GPIO10 | GPIO7 | GPIO18 | GPIO0 |
- * +--------------+---------+-------+----------+----------+----------+----------+----------+
- * | DI (MOSI) | GPIO13 | GPIO23| GPIO35 | GPIO11 | GPIO6 | GPIO19 | GPIO25 |
- * +--------------+---------+-------+----------+----------+----------+----------+----------+
- * | DO (MISO) | GPIO12 | GPIO19| GPIO37 | GPIO13 | GPIO5 | GPIO20 | GPIO11 |
- * +--------------+---------+-------+----------+----------+----------+----------+----------+
- * | SCK (SCLK) | GPIO14 | GPIO18| GPIO36 | GPIO12 | GPIO4 | GPIO21 | GPIO10 |
- * +--------------+---------+-------+----------+----------+----------+----------+----------+
- *
- * For more info see file README.md in this library or on URL:
- * https://github.com/espressif/arduino-esp32/tree/master/libraries/SD
- */
-
-#include "FS.h"
-#include "SD.h"
-#include "SPI.h"
-
-#define REASSIGN_PINS
-int sck = 42;
-int miso = 41;
-int mosi = 39;
-int cs = 38;
-
-void listDir(fs::FS &fs, const char *dirname, uint8_t levels) {
- Serial.printf("Listing directory: %s\n", dirname);
-
- File root = fs.open(dirname);
- if (!root) {
- Serial.println("Failed to open directory");
- return;
- }
- if (!root.isDirectory()) {
- Serial.println("Not a directory");
- return;
- }
-
- File file = root.openNextFile();
- while (file) {
- if (file.isDirectory()) {
- Serial.print(" DIR : ");
- Serial.println(file.name());
- if (levels) {
- listDir(fs, file.path(), levels - 1);
- }
- } else {
- Serial.print(" FILE: ");
- Serial.print(file.name());
- Serial.print(" SIZE: ");
- Serial.println(file.size());
- }
- file = root.openNextFile();
- }
-}
-
-void createDir(fs::FS &fs, const char *path) {
- Serial.printf("Creating Dir: %s\n", path);
- if (fs.mkdir(path)) {
- Serial.println("Dir created");
- } else {
- Serial.println("mkdir failed");
- }
-}
-
-void removeDir(fs::FS &fs, const char *path) {
- Serial.printf("Removing Dir: %s\n", path);
- if (fs.rmdir(path)) {
- Serial.println("Dir removed");
- } else {
- Serial.println("rmdir failed");
- }
-}
-
-void readFile(fs::FS &fs, const char *path) {
- Serial.printf("Reading file: %s\n", path);
-
- File file = fs.open(path);
- if (!file) {
- Serial.println("Failed to open file for reading");
- return;
- }
-
- Serial.print("Read from file: ");
- while (file.available()) {
- Serial.write(file.read());
- }
- file.close();
-}
-
-void writeFile(fs::FS &fs, const char *path, const char *message) {
- Serial.printf("Writing file: %s\n", path);
-
- File file = fs.open(path, FILE_WRITE);
- if (!file) {
- Serial.println("Failed to open file for writing");
- return;
- }
- if (file.print(message)) {
- Serial.println("File written");
- } else {
- Serial.println("Write failed");
- }
- file.close();
-}
-
-void appendFile(fs::FS &fs, const char *path, const char *message) {
- Serial.printf("Appending to file: %s\n", path);
-
- File file = fs.open(path, FILE_APPEND);
- if (!file) {
- Serial.println("Failed to open file for appending");
- return;
- }
- if (file.print(message)) {
- Serial.println("Message appended");
- } else {
- Serial.println("Append failed");
- }
- file.close();
-}
-
-void renameFile(fs::FS &fs, const char *path1, const char *path2) {
- Serial.printf("Renaming file %s to %s\n", path1, path2);
- if (fs.rename(path1, path2)) {
- Serial.println("File renamed");
- } else {
- Serial.println("Rename failed");
- }
-}
-
-void deleteFile(fs::FS &fs, const char *path) {
- Serial.printf("Deleting file: %s\n", path);
- if (fs.remove(path)) {
- Serial.println("File deleted");
- } else {
- Serial.println("Delete failed");
- }
-}
-
-void testFileIO(fs::FS &fs, const char *path) {
- File file = fs.open(path);
- static uint8_t buf[512];
- size_t len = 0;
- uint32_t start = millis();
- uint32_t end = start;
- if (file) {
- len = file.size();
- size_t flen = len;
- start = millis();
- while (len) {
- size_t toRead = len;
- if (toRead > 512) {
- toRead = 512;
- }
- file.read(buf, toRead);
- len -= toRead;
- }
- end = millis() - start;
- Serial.printf("%u bytes read for %lu ms\n", flen, end);
- file.close();
- } else {
- Serial.println("Failed to open file for reading");
- }
-
- file = fs.open(path, FILE_WRITE);
- if (!file) {
- Serial.println("Failed to open file for writing");
- return;
- }
-
- size_t i;
- start = millis();
- for (i = 0; i < 2048; i++) {
- file.write(buf, 512);
- }
- end = millis() - start;
- Serial.printf("%u bytes written for %lu ms\n", 2048 * 512, end);
- file.close();
-}
-
-void setup() {
- Serial.begin(115200);
- while (!Serial) {
- delay(10);
- }
-
-#ifdef REASSIGN_PINS
- SPI.begin(sck, miso, mosi, cs);
- if (!SD.begin(cs)) {
-#else
- if (!SD.begin()) {
-#endif
- Serial.println("Card Mount Failed");
- return;
- }
- uint8_t cardType = SD.cardType();
-
- if (cardType == CARD_NONE) {
- Serial.println("No SD card attached");
- return;
- }
-
- Serial.print("SD Card Type: ");
- if (cardType == CARD_MMC) {
- Serial.println("MMC");
- } else if (cardType == CARD_SD) {
- Serial.println("SDSC");
- } else if (cardType == CARD_SDHC) {
- Serial.println("SDHC");
- } else {
- Serial.println("UNKNOWN");
- }
-
- uint64_t cardSize = SD.cardSize() / (1024 * 1024);
- Serial.printf("SD Card Size: %lluMB\n", cardSize);
-
- listDir(SD, "/", 0);
- createDir(SD, "/mydir");
- listDir(SD, "/", 0);
- removeDir(SD, "/mydir");
- listDir(SD, "/", 2);
- writeFile(SD, "/hello.txt", "Hello ");
- appendFile(SD, "/hello.txt", "World!\n");
- readFile(SD, "/hello.txt");
- deleteFile(SD, "/foo.txt");
- renameFile(SD, "/hello.txt", "/foo.txt");
- readFile(SD, "/foo.txt");
- testFileIO(SD, "/test.txt");
- Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
- Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
-}
-
-void loop() {}
\ No newline at end of file
diff --git a/examples/examples-custom-boards/esp32s3-mic-cam/sdmmc/sdmmc.ino b/examples/examples-custom-boards/esp32s3-mic-cam/sdmmc/sdmmc.ino
deleted file mode 100644
index 909c951ceb..0000000000
--- a/examples/examples-custom-boards/esp32s3-mic-cam/sdmmc/sdmmc.ino
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * pin 1 - D2 | Micro SD card |
- * pin 2 - D3 | /
- * pin 3 - CMD | |__
- * pin 4 - VDD (3.3V) | |
- * pin 5 - CLK | 8 7 6 5 4 3 2 1 /
- * pin 6 - VSS (GND) | ▄ ▄ ▄ ▄ ▄ ▄ ▄ ▄ /
- * pin 7 - D0 | ▀ ▀ █ ▀ █ ▀ ▀ ▀ |
- * pin 8 - D1 |_________________|
- * ║ ║ ║ ║ ║ ║ ║ ║
- * ╔═══════╝ ║ ║ ║ ║ ║ ║ ╚═════════╗
- * ║ ║ ║ ║ ║ ║ ╚══════╗ ║
- * ║ ╔═════╝ ║ ║ ║ ╚═════╗ ║ ║
- * Connections for ║ ║ ╔═══╩═║═║═══╗ ║ ║ ║
- * full-sized ║ ║ ║ ╔═╝ ║ ║ ║ ║ ║
- * SD card ║ ║ ║ ║ ║ ║ ║ ║ ║
- * ESP32-S3 DevKit | 21 47 GND 39 3V3 GND 40 41 42 |
- * ESP32-S3-USB-OTG | 38 37 GND 36 3V3 GND 35 34 33 |
- * ESP32 | 4 2 GND 14 3V3 GND 15 13 12 |
- * ESP32-S3-Camera 40 41 42 39 38 37
- * Pin name | D1 D0 VSS CLK VDD VSS CMD D3 D2 |
- * SD pin number | 8 7 6 5 4 3 2 1 9 /
- * | █/
- * |__▍___▊___█___█___█___█___█___█___/
- * WARNING: ALL data pins must be pulled up to 3.3V with an external 10k Ohm resistor!
- * Note to ESP32 pin 2 (D0): Add a 1K Ohm pull-up resistor to 3.3V after flashing
- *
- *
- * For more info see file README.md in this library or on URL:
- * https://github.com/espressif/arduino-esp32/tree/master/libraries/SD_MMC
- */
-
-#include "FS.h"
-#include "SD_MMC.h"
-
-// Default pins for ESP-S3
-// Warning: ESP32-S3-WROOM-2 is using most of the default GPIOs (33-37) to interface with on-board OPI flash.
-// If the SD_MMC is initialized with default pins it will result in rebooting loop - please
-// reassign the pins elsewhere using the mentioned command `setPins`.
-// Note: ESP32-S3-WROOM-1 does not have GPIO 33 and 34 broken out.
-// Note: if it's ok to use default pins, you do not need to call the setPins
-int clk = 42;
-int cmd = 39;
-int d0 = 41;
-int d1 = 40;
-int d2 = 37;
-int d3 = 38;
-
-void listDir(fs::FS &fs, const char *dirname, uint8_t levels) {
- Serial.printf("Listing directory: %s\n", dirname);
-
- File root = fs.open(dirname);
- if (!root) {
- Serial.println("Failed to open directory");
- return;
- }
- if (!root.isDirectory()) {
- Serial.println("Not a directory");
- return;
- }
-
- File file = root.openNextFile();
- while (file) {
- if (file.isDirectory()) {
- Serial.print(" DIR : ");
- Serial.println(file.name());
- if (levels) {
- listDir(fs, file.path(), levels - 1);
- }
- } else {
- Serial.print(" FILE: ");
- Serial.print(file.name());
- Serial.print(" SIZE: ");
- Serial.println(file.size());
- }
- file = root.openNextFile();
- }
-}
-
-void createDir(fs::FS &fs, const char *path) {
- Serial.printf("Creating Dir: %s\n", path);
- if (fs.mkdir(path)) {
- Serial.println("Dir created");
- } else {
- Serial.println("mkdir failed");
- }
-}
-
-void removeDir(fs::FS &fs, const char *path) {
- Serial.printf("Removing Dir: %s\n", path);
- if (fs.rmdir(path)) {
- Serial.println("Dir removed");
- } else {
- Serial.println("rmdir failed");
- }
-}
-
-void readFile(fs::FS &fs, const char *path) {
- Serial.printf("Reading file: %s\n", path);
-
- File file = fs.open(path);
- if (!file) {
- Serial.println("Failed to open file for reading");
- return;
- }
-
- Serial.print("Read from file: ");
- while (file.available()) {
- Serial.write(file.read());
- }
-}
-
-void writeFile(fs::FS &fs, const char *path, const char *message) {
- Serial.printf("Writing file: %s\n", path);
-
- File file = fs.open(path, FILE_WRITE);
- if (!file) {
- Serial.println("Failed to open file for writing");
- return;
- }
- if (file.print(message)) {
- Serial.println("File written");
- } else {
- Serial.println("Write failed");
- }
-}
-
-void appendFile(fs::FS &fs, const char *path, const char *message) {
- Serial.printf("Appending to file: %s\n", path);
-
- File file = fs.open(path, FILE_APPEND);
- if (!file) {
- Serial.println("Failed to open file for appending");
- return;
- }
- if (file.print(message)) {
- Serial.println("Message appended");
- } else {
- Serial.println("Append failed");
- }
-}
-
-void renameFile(fs::FS &fs, const char *path1, const char *path2) {
- Serial.printf("Renaming file %s to %s\n", path1, path2);
- if (fs.rename(path1, path2)) {
- Serial.println("File renamed");
- } else {
- Serial.println("Rename failed");
- }
-}
-
-void deleteFile(fs::FS &fs, const char *path) {
- Serial.printf("Deleting file: %s\n", path);
- if (fs.remove(path)) {
- Serial.println("File deleted");
- } else {
- Serial.println("Delete failed");
- }
-}
-
-void testFileIO(fs::FS &fs, const char *path) {
- File file = fs.open(path);
- static uint8_t buf[512];
- size_t len = 0;
- uint32_t start = millis();
- uint32_t end = start;
- if (file) {
- len = file.size();
- size_t flen = len;
- start = millis();
- while (len) {
- size_t toRead = len;
- if (toRead > 512) {
- toRead = 512;
- }
- file.read(buf, toRead);
- len -= toRead;
- }
- end = millis() - start;
- Serial.printf("%u bytes read for %lu ms\n", flen, end);
- file.close();
- } else {
- Serial.println("Failed to open file for reading");
- }
-
- file = fs.open(path, FILE_WRITE);
- if (!file) {
- Serial.println("Failed to open file for writing");
- return;
- }
-
- size_t i;
- start = millis();
- for (i = 0; i < 2048; i++) {
- file.write(buf, 512);
- }
- end = millis() - start;
- Serial.printf("%u bytes written for %lu ms\n", 2048 * 512, end);
- file.close();
-}
-
-void setup() {
- Serial.begin(115200);
- while (!Serial)
- ;
- Serial.println("starting...");
- /*
- // If you want to change the pin assignment on ESP32-S3 uncomment this block and the appropriate
- // line depending if you want to use 1-bit or 4-bit line.
- // Please note that ESP32 does not allow pin change and will always fail.
- //if(! SD_MMC.setPins(clk, cmd, d0)){
- if(! SD_MMC.setPins(clk, cmd, d0, d1, d2, d3)){
- Serial.println("Pin change failed!");
- return;
- }
- */
- if (!SD_MMC.setPins(clk, cmd, d0)) {
- Serial.println("Pin change failed!");
- return;
- }
- if (!SD_MMC.begin("/sdcard", true)) {
- Serial.println("Card Mount Failed");
- return;
- }
- uint8_t cardType = SD_MMC.cardType();
-
- if (cardType == CARD_NONE) {
- Serial.println("No SD_MMC card attached");
- return;
- }
-
- Serial.print("SD_MMC Card Type: ");
- if (cardType == CARD_MMC) {
- Serial.println("MMC");
- } else if (cardType == CARD_SD) {
- Serial.println("SDSC");
- } else if (cardType == CARD_SDHC) {
- Serial.println("SDHC");
- } else {
- Serial.println("UNKNOWN");
- }
-
- uint64_t cardSize = SD_MMC.cardSize() / (1024 * 1024);
- Serial.printf("SD_MMC Card Size: %lluMB\n", cardSize);
-
- listDir(SD_MMC, "/", 0);
- createDir(SD_MMC, "/mydir");
- listDir(SD_MMC, "/", 0);
- removeDir(SD_MMC, "/mydir");
- listDir(SD_MMC, "/", 2);
- writeFile(SD_MMC, "/hello.txt", "Hello ");
- appendFile(SD_MMC, "/hello.txt", "World!\n");
- readFile(SD_MMC, "/hello.txt");
- deleteFile(SD_MMC, "/foo.txt");
- renameFile(SD_MMC, "/hello.txt", "/foo.txt");
- readFile(SD_MMC, "/foo.txt");
- testFileIO(SD_MMC, "/test.txt");
- Serial.printf("Total space: %lluMB\n", SD_MMC.totalBytes() / (1024 * 1024));
- Serial.printf("Used space: %lluMB\n", SD_MMC.usedBytes() / (1024 * 1024));
-}
-
-void loop() {}
\ No newline at end of file
diff --git a/examples/examples-custom-boards/lyrat-mini/README.md b/examples/examples-custom-boards/lyrat-mini/README.md
deleted file mode 100644
index 2df1341074..0000000000
--- a/examples/examples-custom-boards/lyrat-mini/README.md
+++ /dev/null
@@ -1,10 +0,0 @@
-The LyraT Mini is a bit tricky to use because it has a ES8311 which is handling the output and a
-ES7243 which is handling the microphone input: both need to be on separate I2S ports.
-
-You should be able to use the examples that can be found in the [audiokit directory](https://github.com/pschatzmann/arduino-audio-tools/tree/main/examples/examples-audiokit): just replace the
-driver with LyratMini!
-
-For the examples install:
-
-- [Arduino AudioTools](https://github.com/pschatzmann/arduino-audio-tools)
-- [Arduino Audio Driver](https://github.com/pschatzmann/arduino-audio-driver)
\ No newline at end of file
diff --git a/examples/examples-custom-boards/lyrat-mini/buttons/buttons.ino b/examples/examples-custom-boards/lyrat-mini/buttons/buttons.ino
deleted file mode 100644
index 51962e008c..0000000000
--- a/examples/examples-custom-boards/lyrat-mini/buttons/buttons.ino
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * @file buttons.ino
- * @author Phil Schatzmann
- * @brief Demo how to use the buttons.
- * @version 0.1
- * @date 2024-11-03
- *
- * The button values are determined with an analogRead(39) via the driver library.
- * This demo shows how to use the integrated AudioActions class via the AudioBoardStream
- *
- * @copyright Copyright (c) 2022
- */
-
-
-#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-
-AudioBoardStream lyrat(LyratMini);
-
-void rec(bool, int, void*) {
- Serial.println("rec");
-}
-
-void mode(bool, int, void*) {
- Serial.println("mode");
-}
-
-void play(bool, int, void*) {
- Serial.println("play");
-}
-
-void set(bool, int, void*) {
- Serial.println("set");
-}
-
-void volUp(bool, int, void*) {
- Serial.println("vol+");
-}
-
-void volDown(bool, int, void*) {
- Serial.println("vol-");
-}
-
-
-// Arduino Setup
-void setup(void) {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
-
- // start board
- lyrat.begin(lyrat.defaultConfig(TX_MODE));
-
- lyrat.addAction(KEY_REC, rec);
- lyrat.addAction(KEY_MODE, mode);
- lyrat.addAction(KEY_PLAY, play);
- lyrat.addAction(KEY_SET, set);
- lyrat.addAction(KEY_VOLUME_UP, volUp);
- lyrat.addAction(KEY_VOLUME_DOWN, volDown);
-
-}
-
-void loop() {
- lyrat.processActions();
-}
diff --git a/examples/examples-custom-boards/lyrat-mini/mic/mic.ino b/examples/examples-custom-boards/lyrat-mini/mic/mic.ino
deleted file mode 100644
index 317fc756fd..0000000000
--- a/examples/examples-custom-boards/lyrat-mini/mic/mic.ino
+++ /dev/null
@@ -1,49 +0,0 @@
-
-/**
- * @file output.ino
- * @author Phil Schatzmann
- * @brief Demo how to use the microphone.
- * @version 0.1
- * @date 2024-11-03
- *
- * The microphone seems to be attached to 2 different i2s ports. In addition to the
- * ES8311, the ES7243 is also started.
- * The I2S pins can be selected via cfg.i2s_function: CODEC uses the ES8311 I2S pins
- * and CODEC_ADC uses the ES7243 I2S pins; By default the CODEC value is used.
- *
- * Only CODEC_ADC will give a proper microphone input!
- *
- * @copyright Copyright (c) 2022
- */
-
-
-#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-
-AudioInfo info(44100, 2, 16);
-AudioBoardStream i2s(LyratMini); // Access I2S as stream
-CsvOutput csvOutput(Serial);
-StreamCopy copier(csvOutput, i2s); // copy i2s to csvOutput
-
-// Arduino Setup
-void setup(void) {
- Serial.begin(115200);
- // Display details what is going on
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
- AudioDriverLogger.begin(Serial, AudioDriverLogLevel::Info);
-
- auto cfg = i2s.defaultConfig(RX_MODE);
- cfg.copyFrom(info);
- // cfg.i2s_function = PinFunction::CODEC_ADC; // determined automatically
- // cfg.i2s_port_no = 0; // or 1 if 0 is already in use
- i2s.begin(cfg);
-
- // make sure that we have the correct number of channels set up
- csvOutput.begin(info);
-
-}
-
-// Arduino loop - copy data
-void loop() {
- copier.copy();
-}
\ No newline at end of file
diff --git a/examples/examples-custom-boards/lyrat-mini/output/output.ino b/examples/examples-custom-boards/lyrat-mini/output/output.ino
deleted file mode 100644
index c9707ba6e6..0000000000
--- a/examples/examples-custom-boards/lyrat-mini/output/output.ino
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * @file output.ino
- * @author Phil Schatzmann
- * @brief Demo to output audio on a lyrat-mini board: with headphone detection
- * active to switch the power amplifier on and off.
- * I2S is used and the ES8311 is initialized via the driver library.
- * @version 0.1
- * @date 2024-11-03
- *
- * @copyright Copyright (c) 2022
- */
-
-#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-
-AudioInfo info(44100, 2, 16);
-SineWaveGenerator sineWave(32000); // subclass of SoundGenerator with max amplitude of 32000
-GeneratedSoundStream sound(sineWave); // Stream generated from sine wave
-AudioBoardStream out(LyratMini);
-StreamCopy copier(out, sound); // copies sound into i2s
-
-// Arduino Setup
-void setup(void) {
- // Open Serial
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
-
- // start I2S
- Serial.println("starting I2S...");
- auto config = out.defaultConfig(TX_MODE);
- config.copyFrom(info);
- // cfg.i2s_function = PinFunction::CODEC; // determined automatically
- // cfg.i2s_port_no = 0; // or 1 if 0 is already in use
- out.begin(config);
-
- // additinal settings
- out.setVolume(0.5);
- out.addHeadphoneDetectionAction();
-
- // start sine wave
- sineWave.begin(info, N_B4);
- Serial.println("started...");
-}
-
-void loop() {
- copier.copy();
- out.processActions();
-}
\ No newline at end of file
diff --git a/examples/examples-custom-boards/lyrat-mini/sd/sd.ino b/examples/examples-custom-boards/lyrat-mini/sd/sd.ino
deleted file mode 100644
index c847c29b09..0000000000
--- a/examples/examples-custom-boards/lyrat-mini/sd/sd.ino
+++ /dev/null
@@ -1,55 +0,0 @@
-
-/**
- * @file sd.ino
- * @author Phil Schatzmann
- * @brief Test/Demo that SD is not working!
- * @version 0.1
- * @date 2024-11-03
- *
- * @copyright Copyright (c) 2022
- */
-
-#include
-#include
-
-// These pins are defined in the HAL
-#define PIN_SD_CARD_CS 13
-#define PIN_SD_CARD_MISO 2
-#define PIN_SD_CARD_MOSI 15
-#define PIN_SD_CARD_CLK 14
-#define PIN_SD_CARD_DET 34
-
-
-// Arduino Setup
-void setup(void) {
- Serial.begin(115200);
-
- // setup SPI
- SPI.begin(PIN_SD_CARD_CLK, PIN_SD_CARD_MISO, PIN_SD_CARD_MOSI, PIN_SD_CARD_CS);
-
- // Optionally determine if there is an SD card
- pinMode(PIN_SD_CARD_DET, INPUT);
- if (digitalRead(PIN_SD_CARD_DET)!=0){
- Serial.println("No SD Card detected");
- }
-
- // Open SD library
- if (!SD.begin(PIN_SD_CARD_CS)){
- Serial.println("SD.begin failed");
- while(true);
- }
-
- // Open an existing file
- auto file = SD.open("/audio8000.raw", FILE_READ);
- if (!file){
- Serial.println("file open failed");
- while(true);
- }
-
- file.close();
-
- Serial.println("Success");
-}
-
-// Arduino loop - repeated processing
-void loop() {}
\ No newline at end of file
diff --git a/examples/examples-custom-boards/lyrat-mini/sdmmc/sdmmc.ino b/examples/examples-custom-boards/lyrat-mini/sdmmc/sdmmc.ino
deleted file mode 100644
index 4b19010191..0000000000
--- a/examples/examples-custom-boards/lyrat-mini/sdmmc/sdmmc.ino
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * @file sdmmc.ino
- * @author Phil Schatzmann
- * @brief Test/Demo how to use the SD_MMC API in Arduino with the LyraT Mini
- * @version 0.1
- * @date 2024-11-03
- *
- * @copyright Copyright (c) 2022
- */
-
-#include "FS.h"
-#include "SD_MMC.h"
-
-// These pins are defined in the HAL
-const int PIN_SD_CARD_POWER = 13;
-const int PIN_SD_CARD_DET = 34;
-
-
-// Arduino Setup
-void setup(void) {
- Serial.begin(115200);
-
- // Mandatory: set power pin to low
- pinMode(PIN_SD_CARD_POWER, OUTPUT);
- digitalWrite(PIN_SD_CARD_POWER, LOW);
-
- // Optionally: Determine if there is an SD card
- pinMode(PIN_SD_CARD_DET, INPUT);
- if (digitalRead(PIN_SD_CARD_DET)!=0){
- Serial.println("No SD Card detected");
- }
-
- // open SDMMC in 1 bit mode
- if (!SD_MMC.begin("/sdcard", true)) {
- Serial.println("Card Mount Failed");
- while(true);
- }
-
- // open an existing file
- auto file = SD_MMC.open("/test.mp3", FILE_READ);
- if (!file){
- Serial.println("file open failed");
- while(true);
- }
-
- file.close();
-
- Serial.println("Success");
-}
-
-// Arduino loop - repeated processing
-void loop() {}
\ No newline at end of file
diff --git a/examples/examples-custom/README.md b/examples/examples-custom/README.md
new file mode 100644
index 0000000000..2352fb9e5f
--- /dev/null
+++ b/examples/examples-custom/README.md
@@ -0,0 +1,2 @@
+
+Some Examples that show how to use some custom boards with their corresponding I2S pins
\ No newline at end of file
diff --git a/examples/examples-custom/cross_band_handy_walkie_talkie/cross_band_handy_walkie_talkie.ino b/examples/examples-custom/cross_band_handy_walkie_talkie/cross_band_handy_walkie_talkie.ino
new file mode 100644
index 0000000000..577d824927
--- /dev/null
+++ b/examples/examples-custom/cross_band_handy_walkie_talkie/cross_band_handy_walkie_talkie.ino
@@ -0,0 +1,65 @@
+/**
+ @file streams-generator-audiokit.ino
+ @brief Tesing I2S output on the cross band handy walkie talkie
+ https://github.com/immortal-sniper1/cross_band_handy_walkie_talkie
+
+ @author Phil Schatzmann
+ @copyright GPLv3
+*/
+
+#include "AudioTools.h"
+#include "AudioLibs/AudioKit.h"
+#include "SD.h"
+
+AudioInfo info(32000, 2, 16);
+SineWaveGenerator sineWave(32000); // subclass of SoundGenerator with max amplitude of 32000
+GeneratedSoundStream sound(sineWave); // Stream generated from sine wave
+AudioKitStream out;
+StreamCopy copier(out, sound); // copies sound into i2s
+
+// Arduino Setup
+void setup(void) {
+ // Open Serial
+ Serial.begin(115200);
+ while(!Serial);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
+ //LOGLEVEL_AUDIOKIT = AudioKitDebug;
+
+ // start I2S
+ Serial.println("starting I2S...");
+ auto config = out.defaultConfig(TX_MODE);
+ config.copyFrom(info);
+ config.sd_active = false;
+ config.default_actions_active = flase;
+ // i2c
+ config.pins.i2c_sda = 36;
+ config.pins.i2c_scl = 35;
+ // i2s
+ config.pin_mclk = 47
+ config.pin_bck = 21;
+ config.pin_ws = 12;
+ config.pin_data = 11;
+ config.pin_data_in = 14;
+
+ //config.sd_active = false;
+ config.pins.sd_cs = 2;
+ config.pins.sd_miso = 42;
+ config.pins.sd_mosi = 43;
+ config.pins.sd_clk = 44;
+ out.begin(config);
+
+ // check SD drive
+ if(!SD.begin(config.pins.sd_cs)){
+ Serial.println("Card Mount Failed");
+ stop();
+ }
+
+ // Setup sine wave
+ sineWave.begin(info, N_B4);
+ Serial.println("started...");
+}
+
+// Arduino loop - copy sound to out
+void loop() {
+ copier.copy();
+}
\ No newline at end of file
diff --git a/examples/tests/conversion/numberformat-converter/numberformat-converter.ino b/examples/examples-custom/esp32-audio-dev-mini/esp32-audio-dev-mini.ino
similarity index 57%
rename from examples/tests/conversion/numberformat-converter/numberformat-converter.ino
rename to examples/examples-custom/esp32-audio-dev-mini/esp32-audio-dev-mini.ino
index 8361180a4d..7bbde9a3f2 100644
--- a/examples/tests/conversion/numberformat-converter/numberformat-converter.ino
+++ b/examples/examples-custom/esp32-audio-dev-mini/esp32-audio-dev-mini.ino
@@ -1,26 +1,33 @@
+/**
+ * @file AudioMini.ino
+ * See https://github.com/sonocotta/esp32-audio-development-kit
+ * @author Phil Schatzmann
+ * @copyright GPLv3
+ */
+
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-AudioInfo info(48000, 2, 16);
-AudioInfo info_to(48000, 2, 32);
+AudioInfo info(44100, 2, 16);
SineWaveGenerator sineWave(32000); // subclass of SoundGenerator with max amplitude of 32000
GeneratedSoundStream sound(sineWave); // Stream generated from sine wave
-AudioBoardStream out(AudioKitEs8388V1);
-NumberFormatConverterStream nfc(out);
-StreamCopy copier(nfc, sound); // copies sound into i2s
+I2SStream out;
+StreamCopy copier(out, sound); // copies sound into i2s
// Arduino Setup
void setup(void) {
// Open Serial
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- nfc.begin(info.bits_per_sample, info_to.bits_per_sample);
+ while(!Serial);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// start I2S
Serial.println("starting I2S...");
auto config = out.defaultConfig(TX_MODE);
- config.copyFrom(info_to);
+ config.copyFrom(info);
+ // Custom I2S output pins
+ config.pin_bck = 26;
+ config.pin_ws = 25;
+ config.pin_data = 22;
out.begin(config);
// Setup sine wave
@@ -31,4 +38,4 @@ void setup(void) {
// Arduino loop - copy sound to out
void loop() {
copier.copy();
-}
+}
\ No newline at end of file
diff --git a/examples/examples-desktop/generator/CMakeLists.txt b/examples/examples-desktop/generator/CMakeLists.txt
index 8d299050de..ed596bbb21 100644
--- a/examples/examples-desktop/generator/CMakeLists.txt
+++ b/examples/examples-desktop/generator/CMakeLists.txt
@@ -12,23 +12,13 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../.. ${CMAKE_CURRENT_BINARY_DIR}/arduino-audio-tools )
endif()
-# Add Portaduio for desktop build
-add_compile_options(-DIS_DESKTOP)
-FetchContent_Declare(portaudio GIT_REPOSITORY "https://github.com/PortAudio/portaudio.git" GIT_TAG v19.7.0 )
-FetchContent_GetProperties(portaudio)
-if(NOT portaudio_POPULATED)
- FetchContent_Populate(portaudio)
- add_subdirectory(${portaudio_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/portaudio)
-endif()
-
-
# build sketch as executable
set_source_files_properties(generator.ino PROPERTIES LANGUAGE CXX)
add_executable (generator generator.ino)
# set preprocessor defines
target_compile_definitions(arduino_emulator PUBLIC -DDEFINE_MAIN)
-target_compile_definitions(generator PUBLIC -DARDUINO -DIS_DESKTOP)
+target_compile_definitions(generator PUBLIC -DARDUINO -DIS_DESKTOP -DEXIT_ON_STOP)
# specify libraries
target_link_libraries(generator portaudio arduino_emulator arduino-audio-tools)
diff --git a/examples/examples-desktop/generator/generator.ino b/examples/examples-desktop/generator/generator.ino
index eb9cb40148..8adc17bdc5 100644
--- a/examples/examples-desktop/generator/generator.ino
+++ b/examples/examples-desktop/generator/generator.ino
@@ -1,5 +1,5 @@
#include "AudioTools.h"
-#include "AudioTools/AudioLibs/PortAudioStream.h"
+#include "AudioLibs/PortAudioStream.h"
AudioInfo info(44100, 1, 16);
SineWaveGenerator sineWave(32000); // subclass of SoundGenerator with max amplitude of 32000
@@ -10,7 +10,7 @@ StreamCopy copier(out, in); // copy in to out
// Arduino Setup
void setup(void) {
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// open output
auto config = out.defaultConfig();
diff --git a/examples/examples-desktop/min-generator/CMakeLists.txt b/examples/examples-desktop/min-generator/CMakeLists.txt
index 14cee42ead..0c171c2fa6 100644
--- a/examples/examples-desktop/min-generator/CMakeLists.txt
+++ b/examples/examples-desktop/min-generator/CMakeLists.txt
@@ -21,7 +21,7 @@ set_source_files_properties(min-generator.ino PROPERTIES LANGUAGE CXX)
add_executable (min-generator min-generator.ino)
# set preprocessor defines
-target_compile_definitions(min-generator PUBLIC -DIS_MIN_DESKTOP)
+target_compile_definitions(min-generator PUBLIC -DIS_MIN_DESKTOP -DEXIT_ON_STOP)
# specify libraries
target_link_libraries(min-generator arduino-audio-tools)
diff --git a/examples/examples-desktop/min-generator/min-generator.ino b/examples/examples-desktop/min-generator/min-generator.ino
index 89ef874a3f..74eb007b41 100644
--- a/examples/examples-desktop/min-generator/min-generator.ino
+++ b/examples/examples-desktop/min-generator/min-generator.ino
@@ -8,7 +8,7 @@ StreamCopy copier(out, in); // copy in to out
// Arduino Setup
void setup(void) {
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
// open output
auto config = out.defaultConfig();
diff --git a/examples/examples-desktop/mp3/CMakeLists.txt b/examples/examples-desktop/mp3/CMakeLists.txt
index 461f47f231..12f602a479 100644
--- a/examples/examples-desktop/mp3/CMakeLists.txt
+++ b/examples/examples-desktop/mp3/CMakeLists.txt
@@ -7,7 +7,6 @@ set (DCMAKE_CXX_FLAGS "-Werror")
include(FetchContent)
option(BUILD_SHARED_LIBS "Build using shared libraries" OFF)
-option(ADD_PORTAUDIO "Add Portaudio Library" ON)
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../.. ${CMAKE_CURRENT_BINARY_DIR}/arduino-audio-tools )
@@ -27,8 +26,8 @@ add_executable (mp3_dt mp3.ino)
# set preprocessor defines
target_compile_definitions(arduino_emulator PUBLIC -DDEFINE_MAIN)
-target_compile_definitions(arduino_helix PUBLIC -DARDUINO -DHELIX_LOGGING_ACTIVE=0)
-target_compile_definitions(mp3_dt PUBLIC -DIS_DESKTOP)
+target_compile_definitions(arduino_helix PUBLIC -DARDUINO)
+target_compile_definitions(mp3_dt PUBLIC -DARDUINO -DIS_DESKTOP -DEXIT_ON_STOP)
# OS/X might need this setting for core audio
target_compile_options(portaudio PRIVATE -Wno-deprecated)
diff --git a/examples/examples-desktop/mp3/mp3.ino b/examples/examples-desktop/mp3/mp3.ino
index 61b9f393ee..815667e743 100644
--- a/examples/examples-desktop/mp3/mp3.ino
+++ b/examples/examples-desktop/mp3/mp3.ino
@@ -2,8 +2,8 @@
#include "Arduino.h"
#include "AudioTools.h"
#include "BabyElephantWalk60_mp3.h"
-#include "AudioTools/AudioLibs/PortAudioStream.h"
-#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
+#include "AudioLibs/PortAudioStream.h"
+#include "AudioCodecs/CodecMP3Helix.h"
MemoryStream mp3(BabyElephantWalk60_mp3, BabyElephantWalk60_mp3_len);
@@ -13,7 +13,7 @@ StreamCopy copier(dec, mp3); // copy in to out
void setup(){
Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
+ AudioLogger::instance().begin(Serial, AudioLogger::Info);
out.begin();
mp3.begin();
diff --git a/examples/examples-dsp/examples-faust/streams-i2s-faust_copy-i2s/Copy.dsp b/examples/examples-dsp/examples-faust/streams-i2s-faust_copy-i2s/Copy.dsp
deleted file mode 100644
index 0d393a2447..0000000000
--- a/examples/examples-dsp/examples-faust/streams-i2s-faust_copy-i2s/Copy.dsp
+++ /dev/null
@@ -1,3 +0,0 @@
-declare filename "copy.dsp";
-declare name "copy";
-process = _,_;
diff --git a/examples/examples-dsp/examples-faust/streams-i2s-faust_copy-i2s/Copy.h b/examples/examples-dsp/examples-faust/streams-i2s-faust_copy-i2s/Copy.h
deleted file mode 100644
index bc14205f09..0000000000
--- a/examples/examples-dsp/examples-faust/streams-i2s-faust_copy-i2s/Copy.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/* ------------------------------------------------------------
-name: "Copy"
-Code generated with Faust 2.68.1 (https://faust.grame.fr)
-Compilation options: -lang cpp -ct 1 -es 1 -mcd 16 -single -ftz 0
------------------------------------------------------------- */
-
-#ifndef __mydsp_H__
-#define __mydsp_H__
-
-#ifndef FAUSTFLOAT
-#define FAUSTFLOAT float
-#endif
-
-#include
-#include
-#include
-
-#ifndef FAUSTCLASS
-#define FAUSTCLASS mydsp
-#endif
-
-#ifdef __APPLE__
-#define exp10f __exp10f
-#define exp10 __exp10
-#endif
-
-#if defined(_WIN32)
-#define RESTRICT __restrict
-#else
-#define RESTRICT __restrict__
-#endif
-
-
-class mydsp : public dsp {
-
- private:
-
- int fSampleRate;
-
- public:
- mydsp() {}
-
- void metadata(Meta* m) {
- m->declare("compile_options", "-lang cpp -ct 1 -es 1 -mcd 16 -single -ftz 0");
- m->declare("filename", "Copy.dsp");
- m->declare("name", "Copy");
- }
-
- virtual int getNumInputs() {
- return 2;
- }
- virtual int getNumOutputs() {
- return 2;
- }
-
- static void classInit(int sample_rate) {
- }
-
- virtual void instanceConstants(int sample_rate) {
- fSampleRate = sample_rate;
- }
-
- virtual void instanceResetUserInterface() {
- }
-
- virtual void instanceClear() {
- }
-
- virtual void init(int sample_rate) {
- classInit(sample_rate);
- instanceInit(sample_rate);
- }
-
- virtual void instanceInit(int sample_rate) {
- instanceConstants(sample_rate);
- instanceResetUserInterface();
- instanceClear();
- }
-
- virtual mydsp* clone() {
- return new mydsp();
- }
-
- virtual int getSampleRate() {
- return fSampleRate;
- }
-
- virtual void buildUserInterface(UI* ui_interface) {
- ui_interface->openVerticalBox("Copy");
- ui_interface->closeBox();
- }
-
- virtual void compute(int count, FAUSTFLOAT** RESTRICT inputs, FAUSTFLOAT** RESTRICT outputs) {
- FAUSTFLOAT* input0 = inputs[0];
- FAUSTFLOAT* input1 = inputs[1];
- FAUSTFLOAT* output0 = outputs[0];
- FAUSTFLOAT* output1 = outputs[1];
- for (int i0 = 0; i0 < count; i0 = i0 + 1) {
- output0[i0] = FAUSTFLOAT(float(input0[i0]));
- output1[i0] = FAUSTFLOAT(float(input1[i0]));
- }
- }
-
-};
-
-#endif
diff --git a/examples/examples-dsp/examples-faust/streams-i2s-faust_copy-i2s/streams-i2s-faust_copy-i2s.ino b/examples/examples-dsp/examples-faust/streams-i2s-faust_copy-i2s/streams-i2s-faust_copy-i2s.ino
deleted file mode 100644
index e4e6ce8c72..0000000000
--- a/examples/examples-dsp/examples-faust/streams-i2s-faust_copy-i2s/streams-i2s-faust_copy-i2s.ino
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * @file streams-i2s-faust_copy-i2s.ino
- * @author Phil Schatzmann
- * @brief Example how to use Faust to write and process a stereo signal. The data
- * is just copied, keeping the left and right signal separate.
- * @version 0.1
- * @date 2022-04-22
- *
- * @copyright Copyright (c) 2022
- *
- */
-
-#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/AudioLibs/AudioFaust.h"
-#include "Copy.h"
-
-AudioBoardStream io(AudioKitEs8388V1);
-FaustStream faust(io); // final output to io
-StreamCopy copier(faust, io); // copy mic to faust
-
-// Arduino Setup
-void setup(void) {
- // Open Serial
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
-
- // Setup Faust
- auto cfg = faust.defaultConfig();
- faust.begin(cfg);
-
-
- // start I2S
- auto cfg_i2s = io.defaultConfig(RXTX_MODE);
- cfg_i2s.copyFrom(cfg);
- io.begin(cfg_i2s);
-
-}
-
-// Arduino loop - copy sound to out
-void loop() {
- copier.copy();
-}
\ No newline at end of file
diff --git a/examples/examples-dsp/examples-faust/streams-i2s-faust_pitchshift-i2s/pitchShifter.dsp b/examples/examples-dsp/examples-faust/streams-i2s-faust_pitchshift-i2s/pitchShifter.dsp
deleted file mode 100644
index da9ec9e101..0000000000
--- a/examples/examples-dsp/examples-faust/streams-i2s-faust_pitchshift-i2s/pitchShifter.dsp
+++ /dev/null
@@ -1,22 +0,0 @@
-declare filename "pitchShifter.dsp";
-declare name "pitchShifter";
-declare name "pitchShifter";
-declare version "1.0";
-declare author "Grame";
-declare license "BSD";
-declare copyright "(c)GRAME 2006";
-
- //--------------------------------------
- // very simple real time pitch shifter
- //--------------------------------------
-
-import("stdfaust.lib");
-
-pitchshifter = vgroup("Pitch Shifter", ef.transpose(
- hslider("window (samples)", 1000, 50, 10000, 1),
- hslider("xfade (samples)", 10, 1, 10000, 1),
- hslider("shift (semitones) ", 0, -12, +12, 0.1)
- )
- );
-
-process = (pitchshifter, pitchshifter);
diff --git a/examples/examples-dsp/examples-faust/streams-i2s-faust_pitchshift-i2s/pitchShifter.h b/examples/examples-dsp/examples-faust/streams-i2s-faust_pitchshift-i2s/pitchShifter.h
deleted file mode 100644
index 39550954de..0000000000
--- a/examples/examples-dsp/examples-faust/streams-i2s-faust_pitchshift-i2s/pitchShifter.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/* ------------------------------------------------------------
-author: "Grame"
-copyright: "(c)GRAME 2006"
-license: "BSD"
-name: "pitchShifter"
-version: "1.0"
-Code generated with Faust 2.68.1 (https://faust.grame.fr)
-Compilation options: -lang cpp -ct 1 -es 1 -mcd 16 -single -ftz 0
------------------------------------------------------------- */
-
-#ifndef __mydsp_H__
-#define __mydsp_H__
-
-#ifndef FAUSTFLOAT
-#define FAUSTFLOAT float
-#endif
-
-#include
-#include
-#include
-
-#ifndef FAUSTCLASS
-#define FAUSTCLASS mydsp
-#endif
-
-#ifdef __APPLE__
-#define exp10f __exp10f
-#define exp10 __exp10
-#endif
-
-#if defined(_WIN32)
-#define RESTRICT __restrict
-#else
-#define RESTRICT __restrict__
-#endif
-
-
-class mydsp : public dsp {
-
- private:
-
- FAUSTFLOAT fHslider0;
- FAUSTFLOAT fHslider1;
- float fRec0[2];
- FAUSTFLOAT fHslider2;
- int IOTA0;
- float fVec0[131072];
- float fVec1[131072];
- int fSampleRate;
-
- public:
- mydsp() {}
-
- void metadata(Meta* m) {
- m->declare("author", "Grame");
- m->declare("compile_options", "-lang cpp -ct 1 -es 1 -mcd 16 -single -ftz 0");
- m->declare("copyright", "(c)GRAME 2006");
- m->declare("delays.lib/name", "Faust Delay Library");
- m->declare("delays.lib/version", "1.1.0");
- m->declare("filename", "pitchShifter.dsp");
- m->declare("license", "BSD");
- m->declare("maths.lib/author", "GRAME");
- m->declare("maths.lib/copyright", "GRAME");
- m->declare("maths.lib/license", "LGPL with exception");
- m->declare("maths.lib/name", "Faust Math Library");
- m->declare("maths.lib/version", "2.6.0");
- m->declare("misceffects.lib/name", "Misc Effects Library");
- m->declare("misceffects.lib/version", "2.1.0");
- m->declare("name", "pitchShifter");
- m->declare("version", "1.0");
- }
-
- virtual int getNumInputs() {
- return 2;
- }
- virtual int getNumOutputs() {
- return 2;
- }
-
- static void classInit(int sample_rate) {
- }
-
- virtual void instanceConstants(int sample_rate) {
- fSampleRate = sample_rate;
- }
-
- virtual void instanceResetUserInterface() {
- fHslider0 = FAUSTFLOAT(0.0f);
- fHslider1 = FAUSTFLOAT(1e+03f);
- fHslider2 = FAUSTFLOAT(1e+01f);
- }
-
- virtual void instanceClear() {
- for (int l0 = 0; l0 < 2; l0 = l0 + 1) {
- fRec0[l0] = 0.0f;
- }
- IOTA0 = 0;
- for (int l1 = 0; l1 < 131072; l1 = l1 + 1) {
- fVec0[l1] = 0.0f;
- }
- for (int l2 = 0; l2 < 131072; l2 = l2 + 1) {
- fVec1[l2] = 0.0f;
- }
- }
-
- virtual void init(int sample_rate) {
- classInit(sample_rate);
- instanceInit(sample_rate);
- }
-
- virtual void instanceInit(int sample_rate) {
- instanceConstants(sample_rate);
- instanceResetUserInterface();
- instanceClear();
- }
-
- virtual mydsp* clone() {
- return new mydsp();
- }
-
- virtual int getSampleRate() {
- return fSampleRate;
- }
-
- virtual void buildUserInterface(UI* ui_interface) {
- ui_interface->openVerticalBox("Pitch Shifter");
- ui_interface->addHorizontalSlider("shift (semitones)", &fHslider0, FAUSTFLOAT(0.0f), FAUSTFLOAT(-12.0f), FAUSTFLOAT(12.0f), FAUSTFLOAT(0.1f));
- ui_interface->addHorizontalSlider("window (samples)", &fHslider1, FAUSTFLOAT(1e+03f), FAUSTFLOAT(5e+01f), FAUSTFLOAT(1e+04f), FAUSTFLOAT(1.0f));
- ui_interface->addHorizontalSlider("xfade (samples)", &fHslider2, FAUSTFLOAT(1e+01f), FAUSTFLOAT(1.0f), FAUSTFLOAT(1e+04f), FAUSTFLOAT(1.0f));
- ui_interface->closeBox();
- }
-
- virtual void compute(int count, FAUSTFLOAT** RESTRICT inputs, FAUSTFLOAT** RESTRICT outputs) {
- FAUSTFLOAT* input0 = inputs[0];
- FAUSTFLOAT* input1 = inputs[1];
- FAUSTFLOAT* output0 = outputs[0];
- FAUSTFLOAT* output1 = outputs[1];
- float fSlow0 = std::pow(2.0f, 0.083333336f * float(fHslider0));
- float fSlow1 = float(fHslider1);
- float fSlow2 = 1.0f / float(fHslider2);
- for (int i0 = 0; i0 < count; i0 = i0 + 1) {
- fRec0[0] = std::fmod(fSlow1 + (fRec0[1] + 1.0f - fSlow0), fSlow1);
- float fTemp0 = std::min(fSlow2 * fRec0[0], 1.0f);
- float fTemp1 = 1.0f - fTemp0;
- float fTemp2 = float(input0[i0]);
- fVec0[IOTA0 & 131071] = fTemp2;
- float fTemp3 = fSlow1 + fRec0[0];
- int iTemp4 = int(fTemp3);
- int iTemp5 = std::min(65537, std::max(0, iTemp4 + 1));
- float fTemp6 = std::floor(fTemp3);
- float fTemp7 = fSlow1 + (fRec0[0] - fTemp6);
- float fTemp8 = 1.0f - fRec0[0];
- float fTemp9 = fTemp6 + fTemp8 - fSlow1;
- int iTemp10 = std::min(65537, std::max(0, iTemp4));
- int iTemp11 = int(fRec0[0]);
- int iTemp12 = std::min(65537, std::max(0, iTemp11 + 1));
- float fTemp13 = std::floor(fRec0[0]);
- float fTemp14 = fRec0[0] - fTemp13;
- float fTemp15 = fTemp13 + fTemp8;
- int iTemp16 = std::min(65537, std::max(0, iTemp11));
- output0[i0] = FAUSTFLOAT((fVec0[(IOTA0 - iTemp16) & 131071] * fTemp15 + fTemp14 * fVec0[(IOTA0 - iTemp12) & 131071]) * fTemp0 + (fVec0[(IOTA0 - iTemp10) & 131071] * fTemp9 + fTemp7 * fVec0[(IOTA0 - iTemp5) & 131071]) * fTemp1);
- float fTemp17 = float(input1[i0]);
- fVec1[IOTA0 & 131071] = fTemp17;
- output1[i0] = FAUSTFLOAT(fTemp0 * (fVec1[(IOTA0 - iTemp16) & 131071] * fTemp15 + fTemp14 * fVec1[(IOTA0 - iTemp12) & 131071]) + fTemp1 * (fTemp9 * fVec1[(IOTA0 - iTemp10) & 131071] + fTemp7 * fVec1[(IOTA0 - iTemp5) & 131071]));
- fRec0[1] = fRec0[0];
- IOTA0 = IOTA0 + 1;
- }
- }
-
-};
-
-#endif
diff --git a/examples/examples-dsp/examples-faust/streams-i2s-faust_pitchshift-i2s/streams-i2s-faust_pitchshift-i2s.ino b/examples/examples-dsp/examples-faust/streams-i2s-faust_pitchshift-i2s/streams-i2s-faust_pitchshift-i2s.ino
deleted file mode 100644
index 51ae33d776..0000000000
--- a/examples/examples-dsp/examples-faust/streams-i2s-faust_pitchshift-i2s/streams-i2s-faust_pitchshift-i2s.ino
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * @file streams-i2s-faust_pitchshift-i2s.ino
- * @author Phil Schatzmann
- * @brief Example how to use Faust for pitch shifting in stereo
- * @version 0.1
- * @date 2022-04-22
- *
- * @copyright Copyright (c) 2022
- *
- */
-
-#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/AudioLibs/AudioFaust.h"
-#include "pitchShifter.h"
-
-AudioBoardStream io(AudioKitEs8388V1);
-FaustStream faust(io); // final output to io
-StreamCopy copier(faust, io); // copy mic to faust
-
-// Arduino Setup
-void setup(void) {
- // Open Serial
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
-
- // Setup Faust
- auto cfg = faust.defaultConfig();
- faust.begin(cfg);
-
-
- // start I2S
- auto cfg_i2s = io.defaultConfig(RXTX_MODE);
- cfg_i2s.copyFrom(cfg);
- io.begin(cfg_i2s);
-
-}
-
-// Arduino loop - copy sound to out
-void loop() {
- copier.copy();
-}
\ No newline at end of file
diff --git a/examples/examples-dsp/examples-mozzi/audio_input/audio_input.ino b/examples/examples-dsp/examples-mozzi/audio_input/audio_input.ino
deleted file mode 100644
index 3277897e0d..0000000000
--- a/examples/examples-dsp/examples-mozzi/audio_input/audio_input.ino
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * Mozzi Input example: we get the input from a generator and
- * output the audio via i2s again. In this example we use the
- * default value range of 0-1023 for the getAudioInput() method.
- * However usually it is easier to define the desired range in
- * the Mozzi configuration object: e.g. cfg.input_range_from = -244;
- * cfg.input_range_to = 243;
- */
-#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/AudioLibs/MozziStream.h"
-
-const int sample_rate = 16000;
-AudioInfo info(sample_rate, 1, 16);
-AudioBoardStream i2s(AudioKitEs8388V1); // final output of decoded stream
-MozziStream mozzi;
-SineWaveGenerator sineWave; // subclass of SoundGenerator with max amplitude of 32000
-GeneratedSoundStream sound(sineWave); // Stream generated from sine wave
-
-StreamCopy copier(i2s, mozzi);
-// use: Oscil oscilName (wavetable), look in .h file
-
-void setup() {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
-
- // setup mozzi
- auto cfg = mozzi.defaultConfig();
- cfg.control_rate = CONTROL_RATE;
- cfg.copyFrom(info);
- mozzi.begin(cfg);
-
- // setup data source for mozzi
- mozzi.setInput(sound);
- sineWave.begin(info, N_B4);
-
- // setup output
- auto out_cfg = i2s.defaultConfig(RXTX_MODE);
- out_cfg.copyFrom(info);
- i2s.begin(out_cfg);
- i2s.setVolume(1.0);
-}
-
-void updateControl() {}
-
-AudioOutputMozzi updateAudio() {
- int asig = mozzi.getAudioInput(); // range 0-1023
- asig = asig - 512; // now range is -512 to 511
- // output range in STANDARD mode is -244 to 243,
- // so you might need to adjust your signal to suit
- return asig;
-}
-
-void loop() { copier.copy(); }
\ No newline at end of file
diff --git a/examples/examples-dsp/examples-mozzi/control_gain-a2dp/control_gain-a2dp.ino b/examples/examples-dsp/examples-mozzi/control_gain-a2dp/control_gain-a2dp.ino
deleted file mode 100644
index 3356bde6f0..0000000000
--- a/examples/examples-dsp/examples-mozzi/control_gain-a2dp/control_gain-a2dp.ino
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * Demo how to use the Mozzi API to provide a stream of int16_t data.
- * Inspired by https://sensorium.github.io/Mozzi/examples/#01.Basics
- * The result is published to a bluetooth speaker. We use the more efficient
- * A2DP base API with a callback
- */
-#include "AudioTools.h"
-#include "AudioTools/AudioLibs/A2DPStream.h"
-#include "AudioTools/AudioLibs/MozziStream.h"
-#include // oscillator template
-#include // sine table for oscillator
-
-const int sample_rate = 44100;
-AudioInfo info(sample_rate, 2, 16); // bluetooth requires 44100, stereo, 16 bits
-BluetoothA2DPSource a2dp_source;
-MozziStream mozzi; // audio source
-const int16_t BYTES_PER_FRAME = 4;
-// use: Oscil oscilName (wavetable), look in .h file
-// of table #included above
-Oscil aSin(SIN2048_DATA);
-// control variable, use the smallest data size you can for anything used in
-// audio
-byte gain = 255;
-
-// callback used by A2DP to provide the sound data - usually len is 128 2 channel int16 frames
-int32_t get_sound_data(uint8_t* data, int32_t size) {
- int32_t result = mozzi.readBytes(data, size);
- //LOGI("get_sound_data %d->%d",size, result);
- return result;
-}
-
-// Arduino Setup
-void setup(void) {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- // setup mozzi
- auto cfg = mozzi.defaultConfig();
- cfg.control_rate = CONTROL_RATE;
- cfg.copyFrom(info);
- mozzi.begin(cfg);
-
- aSin.setFreq(3320); // set the frequency
-
- // start the bluetooth
- Serial.println("starting A2DP...");
- a2dp_source.set_data_callback(get_sound_data);
- a2dp_source.start("LEXON MINO L");
- //a2dp_source.set_volume(100);
-}
-
-void updateControl() {
- // as byte, this will automatically roll around to 255 when it passes 0
- gain = gain - 3;
-}
-
-AudioOutputMozzi updateAudio() {
- // shift back to STANDARD audio range, like /256 but faster
- return (aSin.next() * gain) >> 8;
-}
-
-// Arduino loop - repeated processing
-void loop() {
- delay(1000);
-}
\ No newline at end of file
diff --git a/examples/examples-dsp/examples-mozzi/control_gain/control_gain.ino b/examples/examples-dsp/examples-mozzi/control_gain/control_gain.ino
deleted file mode 100644
index 0b5770e961..0000000000
--- a/examples/examples-dsp/examples-mozzi/control_gain/control_gain.ino
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * Demo how to use the Mozzi API to provide a stream of int16_t data.
- * Inspired by https://sensorium.github.io/Mozzi/examples/#01.Basics
- */
-#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "AudioTools/AudioLibs/MozziStream.h"
-#include // oscillator template
-#include // sine table for oscillator
-
-const int sample_rate = 16000;
-AudioInfo info(sample_rate, 1, 16);
-AudioBoardStream i2s(AudioKitEs8388V1); // audio sink
-MozziStream mozzi; // audio source
-StreamCopy copier(i2s, mozzi); // copy source to sink
-// use: Oscil oscilName (wavetable), look in .h file
-// of table #included above
-Oscil aSin(SIN2048_DATA);
-// control variable, use the smallest data size you can for anything used in
-// audio
-byte gain = 255;
-
-void setup() {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
-
- // setup mozzi
- auto cfg = mozzi.defaultConfig();
- cfg.control_rate = CONTROL_RATE;
- cfg.copyFrom(info);
- mozzi.begin(cfg);
-
- // setup output
- auto out_cfg = i2s.defaultConfig();
- out_cfg.copyFrom(info);
- i2s.begin(out_cfg);
-
- // setup mozzi sine
- aSin.setFreq(3320); // set the frequency
-}
-
-void loop() { copier.copy(); }
-
-void updateControl() {
- // as byte, this will automatically roll around to 255 when it passes 0
- gain = gain - 3;
-}
-
-AudioOutputMozzi updateAudio() {
- return (aSin.next() * gain) >>
- 8; // shift back to STANDARD audio range, like /256 but faster
-}
\ No newline at end of file
diff --git a/examples/examples-dsp/examples-pd/README.md b/examples/examples-dsp/examples-pd/README.md
deleted file mode 100644
index d5ed42f4c6..0000000000
--- a/examples/examples-dsp/examples-pd/README.md
+++ /dev/null
@@ -1 +0,0 @@
-Pure Data (or just "Pd") is an open source visual programming language for multimedia. Further information can be found in the [Wiki](https://github.com/pschatzmann/arduino-audio-tools/wiki/Pure-Data)
\ No newline at end of file
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HeavyContext.cpp b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HeavyContext.cpp
deleted file mode 100644
index 88fa134215..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HeavyContext.cpp
+++ /dev/null
@@ -1,264 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "HeavyContext.hpp"
-#include "HvTable.h"
-
-void defaultSendHook(HeavyContextInterface *context,
- const char *sendName, hv_uint32_t sendHash, const HvMessage *msg) {
- HeavyContext *thisContext = reinterpret_cast(context);
- const hv_uint32_t numBytes = sizeof(ReceiverMessagePair) + msg_getSize(msg) - sizeof(HvMessage);
- ReceiverMessagePair *p = reinterpret_cast(hLp_getWriteBuffer(&thisContext->outQueue, numBytes));
- if (p != nullptr) {
- p->receiverHash = sendHash;
- msg_copyToBuffer(msg, (char *) &p->msg, msg_getSize(msg));
- hLp_produce(&thisContext->outQueue, numBytes);
- } else {
- hv_assert(false &&
- "::defaultSendHook - The out message queue is full and cannot accept more messages until they "
- "have been processed. Try increasing the outQueueKb size in the new_with_options() constructor.");
- }
-}
-
-HeavyContext::HeavyContext(double sampleRate, int poolKb, int inQueueKb, int outQueueKb) :
- sampleRate(sampleRate) {
-
- hv_assert(sampleRate > 0.0); // sample rate must be positive
- hv_assert(poolKb > 0);
- hv_assert(inQueueKb > 0);
- hv_assert(outQueueKb >= 0);
-
- blockStartTimestamp = 0;
- printHook = nullptr;
- userData = nullptr;
-
- // if outQueueKb is positive, then the outQueue is allocated and the default sendhook is set.
- // Otherwise outQueue and the sendhook are set to NULL.
- sendHook = (outQueueKb > 0) ? &defaultSendHook : nullptr;
-
- HV_SPINLOCK_RELEASE(inQueueLock);
- HV_SPINLOCK_RELEASE(outQueueLock);
-
- numBytes = sizeof(HeavyContext);
-
- numBytes += mq_initWithPoolSize(&mq, poolKb);
- numBytes += hLp_init(&inQueue, inQueueKb * 1024);
- numBytes += hLp_init(&outQueue, outQueueKb * 1024); // outQueueKb value of 0 sets everything to NULL
-}
-
-HeavyContext::~HeavyContext() {
- mq_free(&mq);
- hLp_free(&inQueue);
- hLp_free(&outQueue);
-}
-
-bool HeavyContext::sendBangToReceiver(hv_uint32_t receiverHash) {
- HvMessage *m = HV_MESSAGE_ON_STACK(1);
- msg_initWithBang(m, 0);
- bool success = sendMessageToReceiver(receiverHash, 0.0, m);
- return success;
-}
-
-bool HeavyContext::sendFloatToReceiver(hv_uint32_t receiverHash, float f) {
- HvMessage *m = HV_MESSAGE_ON_STACK(1);
- msg_initWithFloat(m, 0, f);
- bool success = sendMessageToReceiver(receiverHash, 0.0, m);
- return success;
-}
-
-bool HeavyContext::sendSymbolToReceiver(hv_uint32_t receiverHash, const char *s) {
- hv_assert(s != nullptr);
- HvMessage *m = HV_MESSAGE_ON_STACK(1);
- msg_initWithSymbol(m, 0, (char *) s);
- bool success = sendMessageToReceiver(receiverHash, 0.0, m);
- return success;
-}
-
-bool HeavyContext::sendMessageToReceiverV(hv_uint32_t receiverHash, double delayMs, const char *format, ...) {
- hv_assert(delayMs >= 0.0);
- hv_assert(format != nullptr);
-
- va_list ap;
- va_start(ap, format);
- const int numElem = (int) hv_strlen(format);
- HvMessage *m = HV_MESSAGE_ON_STACK(numElem);
- msg_init(m, numElem, blockStartTimestamp + (hv_uint32_t) (hv_max_d(0.0, delayMs)*getSampleRate()/1000.0));
- for (int i = 0; i < numElem; i++) {
- switch (format[i]) {
- case 'b': msg_setBang(m, i); break;
- case 'f': msg_setFloat(m, i, (float) va_arg(ap, double)); break;
- case 'h': msg_setHash(m, i, (int) va_arg(ap, int)); break;
- case 's': msg_setSymbol(m, i, (char *) va_arg(ap, char *)); break;
- default: break;
- }
- }
- va_end(ap);
-
- bool success = sendMessageToReceiver(receiverHash, delayMs, m);
- return success;
-}
-
-bool HeavyContext::sendMessageToReceiver(hv_uint32_t receiverHash, double delayMs, HvMessage *m) {
- hv_assert(delayMs >= 0.0);
- hv_assert(m != nullptr);
-
- const hv_uint32_t timestamp = blockStartTimestamp +
- (hv_uint32_t) (hv_max_d(0.0, delayMs)*(getSampleRate()/1000.0));
-
- ReceiverMessagePair *p = nullptr;
- HV_SPINLOCK_ACQUIRE(inQueueLock);
- const hv_uint32_t numBytes = sizeof(ReceiverMessagePair) + msg_getSize(m) - sizeof(HvMessage);
- p = (ReceiverMessagePair *) hLp_getWriteBuffer(&inQueue, numBytes);
- if (p != nullptr) {
- p->receiverHash = receiverHash;
- msg_copyToBuffer(m, (char *) &p->msg, msg_getSize(m));
- msg_setTimestamp(&p->msg, timestamp);
- hLp_produce(&inQueue, numBytes);
- } else {
- hv_assert(false &&
- "::sendMessageToReceiver - The input message queue is full and cannot accept more messages until they "
- "have been processed. Try increasing the inQueueKb size in the new_with_options() constructor.");
- }
- HV_SPINLOCK_RELEASE(inQueueLock);
- return (p != nullptr);
-}
-
-bool HeavyContext::cancelMessage(HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
- return mq_removeMessage(&mq, m, sendMessage);
-}
-
-HvMessage *HeavyContext::scheduleMessageForObject(const HvMessage *m,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
- int letIndex) {
- HvMessage *n = mq_addMessageByTimestamp(&mq, m, letIndex, sendMessage);
- return n;
-}
-
-float *HeavyContext::getBufferForTable(hv_uint32_t tableHash) {
- HvTable *t = getTableForHash(tableHash);
- if (t != nullptr) {
- return hTable_getBuffer(t);
- } else return nullptr;
-}
-
-int HeavyContext::getLengthForTable(hv_uint32_t tableHash) {
- HvTable *t = getTableForHash(tableHash);
- if (t != nullptr) {
- return hTable_getLength(t);
- } else return 0;
-}
-
-bool HeavyContext::setLengthForTable(hv_uint32_t tableHash, hv_uint32_t newSampleLength) {
- HvTable *t = getTableForHash(tableHash);
- if (t != nullptr) {
- hTable_resize(t, newSampleLength);
- return true;
- } else return false;
-}
-
-void HeavyContext::lockAcquire() {
- HV_SPINLOCK_ACQUIRE(inQueueLock);
-}
-
-bool HeavyContext::lockTry() {
- HV_SPINLOCK_TRY(inQueueLock);
-}
-
-void HeavyContext::lockRelease() {
- HV_SPINLOCK_RELEASE(inQueueLock);
-}
-
-void HeavyContext::setInputMessageQueueSize(int inQueueKb) {
- hv_assert(inQueueKb > 0);
- hLp_free(&inQueue);
- hLp_init(&inQueue, inQueueKb*1024);
-}
-
-void HeavyContext::setOutputMessageQueueSize(int outQueueKb) {
- hv_assert(outQueueKb > 0);
- hLp_free(&outQueue);
- hLp_init(&outQueue, outQueueKb*1024);
-}
-
-bool HeavyContext::getNextSentMessage(hv_uint32_t *destinationHash, HvMessage *outMsg, hv_size_t msgLengthBytes) {
- *destinationHash = 0;
- ReceiverMessagePair *p = nullptr;
- hv_assert((sendHook == &defaultSendHook) &&
- "::getNextSentMessage - this function won't do anything if the msg outQueue "
- "size is 0, or you've overriden the default sendhook.");
- if (sendHook == &defaultSendHook) {
- HV_SPINLOCK_ACQUIRE(outQueueLock);
- if (hLp_hasData(&outQueue)) {
- hv_uint32_t numBytes = 0;
- p = reinterpret_cast(hLp_getReadBuffer(&outQueue, &numBytes));
- hv_assert((p != nullptr) && "::getNextSentMessage - something bad happened.");
- hv_assert(numBytes >= sizeof(ReceiverMessagePair));
- hv_assert((numBytes <= msgLengthBytes) &&
- "::getNextSentMessage - the sent message is bigger than the message "
- "passed to handle it.");
- *destinationHash = p->receiverHash;
- hv_memcpy(outMsg, &p->msg, numBytes);
- hLp_consume(&outQueue);
- }
- HV_SPINLOCK_RELEASE(outQueueLock);
- }
- return (p != nullptr);
-}
-
-hv_uint32_t HeavyContext::getHashForString(const char *str) {
- return hv_string_to_hash(str);
-}
-
-HvTable *_hv_table_get(HeavyContextInterface *c, hv_uint32_t tableHash) {
- hv_assert(c != nullptr);
- return reinterpret_cast(c)->getTableForHash(tableHash);
-}
-
-void _hv_scheduleMessageForReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, HvMessage *m) {
- hv_assert(c != nullptr);
- reinterpret_cast(c)->scheduleMessageForReceiver(receiverHash, m);
-}
-
-HvMessage *_hv_scheduleMessageForObject(HeavyContextInterface *c, const HvMessage *m,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
- int letIndex) {
- hv_assert(c != nullptr);
- HvMessage *n = reinterpret_cast(c)->scheduleMessageForObject(
- m, sendMessage, letIndex);
- return n;
-}
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-HvTable *hv_table_get(HeavyContextInterface *c, hv_uint32_t tableHash) {
- return _hv_table_get(c, tableHash);
-}
-
-void hv_scheduleMessageForReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, HvMessage *m) {
- _hv_scheduleMessageForReceiver(c, receiverHash, m);
-}
-
-HvMessage *hv_scheduleMessageForObject(HeavyContextInterface *c, const HvMessage *m,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
- int letIndex) {
- return _hv_scheduleMessageForObject(c, m, sendMessage, letIndex);
-}
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HeavyContext.hpp b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HeavyContext.hpp
deleted file mode 100644
index 87b95d74c2..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HeavyContext.hpp
+++ /dev/null
@@ -1,107 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _HEAVY_CONTEXT_H_
-#define _HEAVY_CONTEXT_H_
-
-#include "HeavyContextInterface.hpp"
-#include "HvLightPipe.h"
-#include "HvMessageQueue.h"
-#include "HvMath.h"
-
-struct HvTable;
-
-class HeavyContext : public HeavyContextInterface {
-
- public:
- HeavyContext(double sampleRate, int poolKb=10, int inQueueKb=2, int outQueueKb=0);
- virtual ~HeavyContext();
-
- int getSize() override { return (int) numBytes; }
-
- double getSampleRate() override { return sampleRate; }
-
- hv_uint32_t getCurrentSample() override { return blockStartTimestamp; }
- float samplesToMilliseconds(hv_uint32_t numSamples) override { return (float) (1000.0*numSamples/sampleRate); }
- hv_uint32_t millisecondsToSamples(float ms) override { return (hv_uint32_t) (hv_max_f(0.0f,ms)*sampleRate/1000.0); }
-
- void setUserData(void *x) override { userData = x; }
- void *getUserData() override { return userData; }
-
- // hook management
- void setSendHook(HvSendHook_t *f) override { sendHook = f; }
- HvSendHook_t *getSendHook() override { return sendHook; }
-
- void setPrintHook(HvPrintHook_t *f) override { printHook = f; }
- HvPrintHook_t *getPrintHook() override { return printHook; }
-
- // message scheduling
- bool sendMessageToReceiver(hv_uint32_t receiverHash, double delayMs, HvMessage *m) override;
- bool sendMessageToReceiverV(hv_uint32_t receiverHash, double delayMs, const char *fmt, ...) override;
- bool sendFloatToReceiver(hv_uint32_t receiverHash, float f) override;
- bool sendBangToReceiver(hv_uint32_t receiverHash) override;
- bool sendSymbolToReceiver(hv_uint32_t receiverHash, const char *symbol) override;
- bool cancelMessage(HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) override;
-
- // table manipulation
- float *getBufferForTable(hv_uint32_t tableHash) override;
- int getLengthForTable(hv_uint32_t tableHash) override;
- bool setLengthForTable(hv_uint32_t tableHash, hv_uint32_t newSampleLength) override;
-
- // lock control
- void lockAcquire() override;
- bool lockTry() override;
- void lockRelease() override;
-
- // message queue management
- void setInputMessageQueueSize(int inQueueKb) override;
- void setOutputMessageQueueSize(int outQueueKb) override;
- bool getNextSentMessage(hv_uint32_t *destinationHash, HvMessage *outMsg, hv_size_t msgLength) override;
-
- // utility functions
- static hv_uint32_t getHashForString(const char *str);
-
- protected:
- virtual HvTable *getTableForHash(hv_uint32_t tableHash) = 0;
- friend HvTable *_hv_table_get(HeavyContextInterface *, hv_uint32_t);
-
- virtual void scheduleMessageForReceiver(hv_uint32_t receiverHash, HvMessage *m) = 0;
- friend void _hv_scheduleMessageForReceiver(HeavyContextInterface *, hv_uint32_t, HvMessage *);
-
- HvMessage *scheduleMessageForObject(const HvMessage *,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
- int);
- friend HvMessage *_hv_scheduleMessageForObject(HeavyContextInterface *, const HvMessage *,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
- int);
-
- friend void defaultSendHook(HeavyContextInterface *, const char *, hv_uint32_t, const HvMessage *);
-
- // object state
- double sampleRate;
- hv_uint32_t blockStartTimestamp;
- hv_size_t numBytes;
- HvMessageQueue mq;
- HvSendHook_t *sendHook;
- HvPrintHook_t *printHook;
- void *userData;
- HvLightPipe inQueue;
- HvLightPipe outQueue;
- hv_atomic_bool inQueueLock;
- hv_atomic_bool outQueueLock;
-};
-
-#endif // _HEAVY_CONTEXT_H_
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HeavyContextInterface.hpp b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HeavyContextInterface.hpp
deleted file mode 100644
index a78fcbf396..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HeavyContextInterface.hpp
+++ /dev/null
@@ -1,291 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _HEAVY_CONTEXT_INTERFACE_H_
-#define _HEAVY_CONTEXT_INTERFACE_H_
-
-#include "HvUtils.h"
-
-#ifndef _HEAVY_DECLARATIONS_
-#define _HEAVY_DECLARATIONS_
-
-class HeavyContextInterface;
-struct HvMessage;
-
-typedef enum {
- HV_PARAM_TYPE_PARAMETER_IN,
- HV_PARAM_TYPE_PARAMETER_OUT,
- HV_PARAM_TYPE_EVENT_IN,
- HV_PARAM_TYPE_EVENT_OUT
-} HvParameterType;
-
-typedef struct HvParameterInfo {
- const char *name; // the human readable parameter name
- hv_uint32_t hash; // an integer identified used by heavy for this parameter
- HvParameterType type; // type of this parameter
- float minVal; // the minimum value of this parameter
- float maxVal; // the maximum value of this parameter
- float defaultVal; // the default value of this parameter
-} HvParameterInfo;
-
-typedef void (HvSendHook_t) (HeavyContextInterface *context, const char *sendName, hv_uint32_t sendHash, const HvMessage *msg);
-typedef void (HvPrintHook_t) (HeavyContextInterface *context, const char *printName, const char *str, const HvMessage *msg);
-
-#endif // _HEAVY_DECLARATIONS_
-
-
-
-class HeavyContextInterface {
-
- public:
- HeavyContextInterface() {}
- virtual ~HeavyContextInterface() {};
-
- /** Returns the read-only user-assigned name of this patch. */
- virtual const char *getName() = 0;
-
- /** Returns the number of input channels with which this context has been configured. */
- virtual int getNumInputChannels() = 0;
-
- /** Returns the number of output channels with which this context has been configured. */
- virtual int getNumOutputChannels() = 0;
-
- /**
- * Returns the total size in bytes of the context.
- * This value may change if tables are resized.
- */
- virtual int getSize() = 0;
-
- /** Returns the sample rate with which this context has been configured. */
- virtual double getSampleRate() = 0;
-
- /** Returns the current patch time in samples. This value is always exact. */
- virtual hv_uint32_t getCurrentSample() = 0;
- virtual float samplesToMilliseconds(hv_uint32_t numSamples) = 0;
-
- /** Converts milliseconds to samples. Input is limited to non-negative range. */
- virtual hv_uint32_t millisecondsToSamples(float ms) = 0;
-
- /** Sets a user-definable value. This value is never manipulated by Heavy. */
- virtual void setUserData(void *x) = 0;
-
- /** Returns the user-defined data. */
- virtual void *getUserData() = 0;
-
- /**
- * Set the send hook. The function is called whenever a message is sent to any send object.
- * Messages returned by this function should NEVER be freed. If the message must persist, call
- * hv_msg_copy() first.
- */
- virtual void setSendHook(HvSendHook_t *f) = 0;
-
- /** Returns the send hook, or NULL if unset. */
- virtual HvSendHook_t *getSendHook() = 0;
-
- /** Set the print hook. The function is called whenever a message is sent to a print object. */
- virtual void setPrintHook(HvPrintHook_t *f) = 0;
-
- /** Returns the print hook, or NULL if unset. */
- virtual HvPrintHook_t *getPrintHook() = 0;
-
- /**
- * Processes one block of samples for a patch instance. The buffer format is an array of float channel arrays.
- * If the context has not input or output channels, the respective argument may be NULL.
- * The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
- * no, SSE or NEON, or AVX optimisation is being used, respectively.
- * e.g. [[LLLL][RRRR]]
- *
- * @return The number of samples processed.
- *
- * This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
- */
- virtual int process(float **inputBuffers, float **outputBuffer, int n) = 0;
-
- /**
- * Processes one block of samples for a patch instance. The buffer format is an uninterleaved float array of channels.
- * If the context has not input or output channels, the respective argument may be NULL.
- * The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
- * no, SSE or NEON, or AVX optimisation is being used, respectively.
- * e.g. [LLLLRRRR]
- *
- * @return The number of samples processed.
- *
- * This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
- */
- virtual int processInline(float *inputBuffers, float *outputBuffer, int n) = 0;
-
- /**
- * Processes one block of samples for a patch instance. The buffer format is an interleaved float array of channels.
- * If the context has not input or output channels, the respective argument may be NULL.
- * The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
- * no, SSE or NEON, or AVX optimisation is being used, respectively.
- * e.g. [LRLRLRLR]
- *
- * @return The number of samples processed.
- *
- * This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
- */
- virtual int processInlineInterleaved(float *inputBuffers, float *outputBuffer, int n) = 0;
-
- /**
- * Sends a formatted message to a receiver that can be scheduled for the future.
- * The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
- * This function is thread-safe.
- *
- * @return True if the message was accepted. False if the message could not fit onto
- * the message queue to be processed this block.
- */
- virtual bool sendMessageToReceiver(hv_uint32_t receiverHash, double delayMs, HvMessage *m) = 0;
-
- /**
- * Sends a formatted message to a receiver that can be scheduled for the future.
- * The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
- * This function is thread-safe.
- *
- * @return True if the message was accepted. False if the message could not fit onto
- * the message queue to be processed this block.
- */
- virtual bool sendMessageToReceiverV(hv_uint32_t receiverHash, double delayMs, const char *fmt, ...) = 0;
-
- /**
- * A convenience function to send a float to a receiver to be processed immediately.
- * The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
- * This function is thread-safe.
- *
- * @return True if the message was accepted. False if the message could not fit onto
- * the message queue to be processed this block.
- */
- virtual bool sendFloatToReceiver(hv_uint32_t receiverHash, float f) = 0;
-
- /**
- * A convenience function to send a bang to a receiver to be processed immediately.
- * The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
- * This function is thread-safe.
- *
- * @return True if the message was accepted. False if the message could not fit onto
- * the message queue to be processed this block.
- */
- virtual bool sendBangToReceiver(hv_uint32_t receiverHash) = 0;
-
- /**
- * A convenience function to send a symbol to a receiver to be processed immediately.
- * The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
- * This function is thread-safe.
- *
- * @return True if the message was accepted. False if the message could not fit onto
- * the message queue to be processed this block.
- */
- virtual bool sendSymbolToReceiver(hv_uint32_t receiverHash, const char *symbol) = 0;
-
- /**
- * Cancels a previously scheduled message.
- *
- * @param sendMessage May be NULL.
- */
- virtual bool cancelMessage(HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)=nullptr) = 0;
-
- /**
- * Returns information about each parameter such as name, hash, and range.
- * The total number of parameters is always returned.
- *
- * @param index The parameter index.
- * @param info A pointer to a HvParameterInfo struct. May be null.
- *
- * @return The total number of parameters.
- */
- virtual int getParameterInfo(int index, HvParameterInfo *info) = 0;
-
- /** Returns a pointer to the raw buffer backing this table. DO NOT free it. */
- virtual float *getBufferForTable(hv_uint32_t tableHash) = 0;
-
- /** Returns the length of this table in samples. */
- virtual int getLengthForTable(hv_uint32_t tableHash) = 0;
-
- /**
- * Resizes the table to the given length.
- *
- * Existing contents are copied to the new table. Remaining space is cleared
- * if the table is longer than the original, truncated otherwise.
- *
- * @param tableHash The table identifier.
- * @param newSampleLength The new length of the table, in samples.
- *
- * @return False if the table could not be found. True otherwise.
- */
- virtual bool setLengthForTable(hv_uint32_t tableHash, hv_uint32_t newSampleLength) = 0;
-
- /**
- * Acquire the input message queue lock.
- *
- * This function will block until the message lock as been acquired.
- * Typical applications will not require the use of this function.
- */
- virtual void lockAcquire() = 0;
-
- /**
- * Try to acquire the input message queue lock.
- *
- * If the lock has been acquired, hv_lock_release() must be called to release it.
- * Typical applications will not require the use of this function.
- *
- * @return Returns true if the lock has been acquired, false otherwise.
- */
- virtual bool lockTry() = 0;
-
- /**
- * Release the input message queue lock.
- *
- * Typical applications will not require the use of this function.
- */
- virtual void lockRelease() = 0;
-
- /**
- * Set the size of the input message queue in kilobytes.
- *
- * The buffer is reset and all existing contents are lost on resize.
- *
- * @param inQueueKb Must be positive i.e. at least one.
- */
- virtual void setInputMessageQueueSize(int inQueueKb) = 0;
-
- /**
- * Set the size of the output message queue in kilobytes.
- *
- * The buffer is reset and all existing contents are lost on resize.
- * Only the default sendhook uses the outgoing message queue. If the default
- * sendhook is not being used, then this function is not useful.
- *
- * @param outQueueKb Must be postive i.e. at least one.
- */
- virtual void setOutputMessageQueueSize(int outQueueKb) = 0;
-
- /**
- * Get the next message in the outgoing queue, will also consume the message.
- * Returns false if there are no messages.
- *
- * @param destinationHash a hash of the name of the receiver the message was sent to.
- * @param outMsg message pointer that is filled by the next message contents.
- * @param msgLengthBytes max length of outMsg in bytes.
- *
- * @return True if there is a message in the outgoing queue.
- */
- virtual bool getNextSentMessage(hv_uint32_t *destinationHash, HvMessage *outMsg, hv_size_t msgLengthBytes) = 0;
-
- /** Returns a 32-bit hash of any string. Returns 0 if string is NULL. */
- static hv_uint32_t getHashForString(const char *str);
-};
-
-#endif // _HEAVY_CONTEXT_INTERFACE_H_
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/Heavy_Adc2Dac.cpp b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/Heavy_Adc2Dac.cpp
deleted file mode 100644
index 5c88136494..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/Heavy_Adc2Dac.cpp
+++ /dev/null
@@ -1,274 +0,0 @@
-/**
- * Copyright (c) 2024 Enzien Audio, Ltd.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions, and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the phrase "powered by heavy",
- * the heavy logo, and a hyperlink to https://enzienaudio.com, all in a visible
- * form.
- *
- * 2.1 If the Application is distributed in a store system (for example,
- * the Apple "App Store" or "Google Play"), the phrase "powered by heavy"
- * shall be included in the app description or the copyright text as well as
- * the in the app itself. The heavy logo will shall be visible in the app
- * itself as well.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "Heavy_Adc2Dac.hpp"
-
-#include
-
-#define Context(_c) static_cast(_c)
-
-
-/*
- * C Functions
- */
-
-extern "C" {
- HV_EXPORT HeavyContextInterface *hv_Adc2Dac_new(double sampleRate) {
- // allocate aligned memory
- void *ptr = hv_malloc(sizeof(Heavy_Adc2Dac));
- // ensure non-null
- if (!ptr) return nullptr;
- // call constructor
- new(ptr) Heavy_Adc2Dac(sampleRate);
- return Context(ptr);
- }
-
- HV_EXPORT HeavyContextInterface *hv_Adc2Dac_new_with_options(double sampleRate,
- int poolKb, int inQueueKb, int outQueueKb) {
- // allocate aligned memory
- void *ptr = hv_malloc(sizeof(Heavy_Adc2Dac));
- // ensure non-null
- if (!ptr) return nullptr;
- // call constructor
- new(ptr) Heavy_Adc2Dac(sampleRate, poolKb, inQueueKb, outQueueKb);
- return Context(ptr);
- }
-
- HV_EXPORT void hv_Adc2Dac_free(HeavyContextInterface *instance) {
- // call destructor
- Context(instance)->~Heavy_Adc2Dac();
- // free memory
- hv_free(instance);
- }
-} // extern "C"
-
-
-
-
-
-
-
-/*
- * Class Functions
- */
-
-Heavy_Adc2Dac::Heavy_Adc2Dac(double sampleRate, int poolKb, int inQueueKb, int outQueueKb)
- : HeavyContext(sampleRate, poolKb, inQueueKb, outQueueKb) {
-
-}
-
-Heavy_Adc2Dac::~Heavy_Adc2Dac() {
- // nothing to free
-}
-
-HvTable *Heavy_Adc2Dac::getTableForHash(hv_uint32_t tableHash) {
- return nullptr;
-}
-
-void Heavy_Adc2Dac::scheduleMessageForReceiver(hv_uint32_t receiverHash, HvMessage *m) {
- switch (receiverHash) {
- default: return;
- }
-}
-
-int Heavy_Adc2Dac::getParameterInfo(int index, HvParameterInfo *info) {
- if (info != nullptr) {
- switch (index) {
- default: {
- info->name = "invalid parameter index";
- info->hash = 0;
- info->type = HvParameterType::HV_PARAM_TYPE_PARAMETER_IN;
- info->minVal = 0.0f;
- info->maxVal = 0.0f;
- info->defaultVal = 0.0f;
- break;
- }
- }
- }
- return 0;
-}
-
-
-
-/*
- * Send Function Implementations
- */
-
-
-
-
-
-/*
- * Context Process Implementation
- */
-
-int Heavy_Adc2Dac::process(float **inputBuffers, float **outputBuffers, int n) {
- while (hLp_hasData(&inQueue)) {
- hv_uint32_t numBytes = 0;
- ReceiverMessagePair *p = reinterpret_cast(hLp_getReadBuffer(&inQueue, &numBytes));
- hv_assert(numBytes >= sizeof(ReceiverMessagePair));
- scheduleMessageForReceiver(p->receiverHash, &p->msg);
- hLp_consume(&inQueue);
- }
-
- sendBangToReceiver(0xDD21C0EB); // send to __hv_bang~ on next cycle
- const int n4 = n & ~HV_N_SIMD_MASK; // ensure that the block size is a multiple of HV_N_SIMD
-
- // temporary signal vars
-
- // input and output vars
- hv_bufferf_t O0, O1;
- hv_bufferf_t I0, I1;
-
- // declare and init the zero buffer
- hv_bufferf_t ZERO; __hv_zero_f(VOf(ZERO));
-
- hv_uint32_t nextBlock = blockStartTimestamp;
- for (int n = 0; n < n4; n += HV_N_SIMD) {
-
- // process all of the messages for this block
- nextBlock += HV_N_SIMD;
- while (mq_hasMessageBefore(&mq, nextBlock)) {
- MessageNode *const node = mq_peek(&mq);
- node->sendMessage(this, node->let, node->m);
- mq_pop(&mq);
- }
-
- // load input buffers
- __hv_load_f(inputBuffers[0]+n, VOf(I0));
- __hv_load_f(inputBuffers[1]+n, VOf(I1));
-
- // zero output buffers
- __hv_zero_f(VOf(O0));
- __hv_zero_f(VOf(O1));
-
- // process all signal functions
- __hv_add_f(VIf(I0), VIf(O0), VOf(O0));
- __hv_add_f(VIf(I1), VIf(O1), VOf(O1));
-
- // save output vars to output buffer
- __hv_store_f(outputBuffers[0]+n, VIf(O0));
- __hv_store_f(outputBuffers[1]+n, VIf(O1));
- }
-
- blockStartTimestamp = nextBlock;
-
- return n4; // return the number of frames processed
-
-}
-
-int Heavy_Adc2Dac::processInline(float *inputBuffers, float *outputBuffers, int n4) {
- hv_assert(!(n4 & HV_N_SIMD_MASK)); // ensure that n4 is a multiple of HV_N_SIMD
-
- // define the heavy input buffer for 2 channel(s)
- float **const bIn = reinterpret_cast(hv_alloca(2*sizeof(float *)));
- bIn[0] = inputBuffers+(0*n4);
- bIn[1] = inputBuffers+(1*n4);
-
- // define the heavy output buffer for 2 channel(s)
- float **const bOut = reinterpret_cast(hv_alloca(2*sizeof(float *)));
- bOut[0] = outputBuffers+(0*n4);
- bOut[1] = outputBuffers+(1*n4);
-
- int n = process(bIn, bOut, n4);
- return n;
-}
-
-int Heavy_Adc2Dac::processInlineInterleaved(float *inputBuffers, float *outputBuffers, int n4) {
- hv_assert(n4 & ~HV_N_SIMD_MASK); // ensure that n4 is a multiple of HV_N_SIMD
-
- // define the heavy input buffer for 2 channel(s), uninterleave
- float *const bIn = reinterpret_cast(hv_alloca(2*n4*sizeof(float)));
- #if HV_SIMD_SSE || HV_SIMD_AVX
- for (int i = 0, j = 0; j < n4; j += 4, i += 8) {
- __m128 a = _mm_load_ps(inputBuffers+i); // LRLR
- __m128 b = _mm_load_ps(inputBuffers+4+i); // LRLR
- __m128 x = _mm_shuffle_ps(a, b, _MM_SHUFFLE(2,0,2,0)); // LLLL
- __m128 y = _mm_shuffle_ps(a, b, _MM_SHUFFLE(3,1,3,1)); // RRRR
- _mm_store_ps(bIn+j, x);
- _mm_store_ps(bIn+n4+j, y);
- }
- #elif HV_SIMD_NEON
- for (int i = 0, j = 0; j < n4; j += 4, i += 8) {
- float32x4x2_t a = vld2q_f32(inputBuffers+i); // load and uninterleave
- vst1q_f32(bIn+j, a.val[0]);
- vst1q_f32(bIn+n4+j, a.val[1]);
- }
- #else // HV_SIMD_NONE
- for (int j = 0; j < n4; ++j) {
- bIn[0*n4+j] = inputBuffers[0+2*j];
- bIn[1*n4+j] = inputBuffers[1+2*j];
- }
- #endif
-
- // define the heavy output buffer for 2 channel(s)
- float *const bOut = reinterpret_cast(hv_alloca(2*n4*sizeof(float)));
-
- int n = processInline(bIn, bOut, n4);
-
- // interleave the heavy output into the output buffer
- #if HV_SIMD_AVX
- for (int i = 0, j = 0; j < n4; j += 8, i += 16) {
- __m256 x = _mm256_load_ps(bOut+j); // LLLLLLLL
- __m256 y = _mm256_load_ps(bOut+n4+j); // RRRRRRRR
- __m256 a = _mm256_unpacklo_ps(x, y); // LRLRLRLR
- __m256 b = _mm256_unpackhi_ps(x, y); // LRLRLRLR
- _mm256_store_ps(outputBuffers+i, a);
- _mm256_store_ps(outputBuffers+8+i, b);
- }
- #elif HV_SIMD_SSE
- for (int i = 0, j = 0; j < n4; j += 4, i += 8) {
- __m128 x = _mm_load_ps(bOut+j); // LLLL
- __m128 y = _mm_load_ps(bOut+n4+j); // RRRR
- __m128 a = _mm_unpacklo_ps(x, y); // LRLR
- __m128 b = _mm_unpackhi_ps(x, y); // LRLR
- _mm_store_ps(outputBuffers+i, a);
- _mm_store_ps(outputBuffers+4+i, b);
- }
- #elif HV_SIMD_NEON
- // https://community.arm.com/groups/processors/blog/2012/03/13/coding-for-neon--part-5-rearranging-vectors
- for (int i = 0, j = 0; j < n4; j += 4, i += 8) {
- float32x4_t x = vld1q_f32(bOut+j);
- float32x4_t y = vld1q_f32(bOut+n4+j);
- float32x4x2_t z = {x, y};
- vst2q_f32(outputBuffers+i, z); // interleave and store
- }
- #else // HV_SIMD_NONE
- for (int i = 0; i < 2; ++i) {
- for (int j = 0; j < n4; ++j) {
- outputBuffers[i+2*j] = bOut[i*n4+j];
- }
- }
- #endif
-
- return n;
-}
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/Heavy_Adc2Dac.h b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/Heavy_Adc2Dac.h
deleted file mode 100644
index ad55758b73..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/Heavy_Adc2Dac.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/**
- * Copyright (c) 2024 Enzien Audio, Ltd.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions, and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the phrase "powered by heavy",
- * the heavy logo, and a hyperlink to https://enzienaudio.com, all in a visible
- * form.
- *
- * 2.1 If the Application is distributed in a store system (for example,
- * the Apple "App Store" or "Google Play"), the phrase "powered by heavy"
- * shall be included in the app description or the copyright text as well as
- * the in the app itself. The heavy logo will shall be visible in the app
- * itself as well.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef _HEAVY_ADC2DAC_H_
-#define _HEAVY_ADC2DAC_H_
-
-#include "HvHeavy.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if HV_APPLE
-#pragma mark - Heavy Context
-#endif
-
-
-
-/**
- * Creates a new patch instance.
- * Sample rate should be positive and in Hertz, e.g. 44100.0.
- */
-HeavyContextInterface *hv_Adc2Dac_new(double sampleRate);
-
-/**
- * Creates a new patch instance.
- * @param sampleRate Sample rate should be positive (> 0) and in Hertz, e.g. 48000.0.
- * @param poolKb Pool size is in kilobytes, and determines the maximum amount of memory
- * allocated to messages at any time. By default this is 10 KB.
- * @param inQueueKb The size of the input message queue in kilobytes. It determines the
- * amount of memory dedicated to holding scheduled messages between calls to
- * process(). Default is 2 KB.
- * @param outQueueKb The size of the output message queue in kilobytes. It determines the
- * amount of memory dedicated to holding scheduled messages to the default sendHook.
- * See getNextSentMessage() for info on accessing these messages. Default is 0 KB.
- */
-HeavyContextInterface *hv_Adc2Dac_new_with_options(double sampleRate, int poolKb, int inQueueKb, int outQueueKb);
-
-/**
- * Free the patch instance.
- */
-void hv_Adc2Dac_free(HeavyContextInterface *instance);
-
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // _HEAVY_ADC2DAC_H_
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/Heavy_Adc2Dac.hpp b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/Heavy_Adc2Dac.hpp
deleted file mode 100644
index 37a5f0c563..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/Heavy_Adc2Dac.hpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * Copyright (c) 2024 Enzien Audio, Ltd.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions, and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the phrase "powered by heavy",
- * the heavy logo, and a hyperlink to https://enzienaudio.com, all in a visible
- * form.
- *
- * 2.1 If the Application is distributed in a store system (for example,
- * the Apple "App Store" or "Google Play"), the phrase "powered by heavy"
- * shall be included in the app description or the copyright text as well as
- * the in the app itself. The heavy logo will shall be visible in the app
- * itself as well.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef _HEAVY_CONTEXT_ADC2DAC_HPP_
-#define _HEAVY_CONTEXT_ADC2DAC_HPP_
-
-// object includes
-#include "HeavyContext.hpp"
-#include "HvMath.h"
-
-class Heavy_Adc2Dac : public HeavyContext {
-
- public:
- Heavy_Adc2Dac(double sampleRate, int poolKb=10, int inQueueKb=2, int outQueueKb=0);
- ~Heavy_Adc2Dac();
-
- const char *getName() override { return "Adc2Dac"; }
- int getNumInputChannels() override { return 2; }
- int getNumOutputChannels() override { return 2; }
-
- int process(float **inputBuffers, float **outputBuffer, int n) override;
- int processInline(float *inputBuffers, float *outputBuffer, int n) override;
- int processInlineInterleaved(float *inputBuffers, float *outputBuffer, int n) override;
-
- int getParameterInfo(int index, HvParameterInfo *info) override;
-
- private:
- HvTable *getTableForHash(hv_uint32_t tableHash) override;
- void scheduleMessageForReceiver(hv_uint32_t receiverHash, HvMessage *m) override;
-
- // static sendMessage functions
-
- // objects
-};
-
-#endif // _HEAVY_CONTEXT_ADC2DAC_HPP_
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvHeavy.cpp b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvHeavy.cpp
deleted file mode 100644
index 19ca4128d8..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvHeavy.cpp
+++ /dev/null
@@ -1,318 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "HeavyContext.hpp"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if HV_APPLE
-#pragma mark - Heavy Table
-#endif
-
-HV_EXPORT bool hv_table_setLength(HeavyContextInterface *c, hv_uint32_t tableHash, hv_uint32_t newSampleLength) {
- hv_assert(c != nullptr);
- return c->setLengthForTable(tableHash, newSampleLength);
-}
-
-HV_EXPORT float *hv_table_getBuffer(HeavyContextInterface *c, hv_uint32_t tableHash) {
- hv_assert(c != nullptr);
- return c->getBufferForTable(tableHash);
-}
-
-HV_EXPORT hv_uint32_t hv_table_getLength(HeavyContextInterface *c, hv_uint32_t tableHash) {
- hv_assert(c != nullptr);
- return c->getLengthForTable(tableHash);
-}
-
-
-
-#if HV_APPLE
-#pragma mark - Heavy Message
-#endif
-
-HV_EXPORT hv_size_t hv_msg_getByteSize(hv_uint32_t numElements) {
- return msg_getCoreSize(numElements);
-}
-
-HV_EXPORT void hv_msg_init(HvMessage *m, int numElements, hv_uint32_t timestamp) {
- msg_init(m, numElements, timestamp);
-}
-
-HV_EXPORT hv_size_t hv_msg_getNumElements(const HvMessage *m) {
- return msg_getNumElements(m);
-}
-
-HV_EXPORT hv_uint32_t hv_msg_getTimestamp(const HvMessage *m) {
- return msg_getTimestamp(m);
-}
-
-HV_EXPORT void hv_msg_setTimestamp(HvMessage *m, hv_uint32_t timestamp) {
- msg_setTimestamp(m, timestamp);
-}
-
-HV_EXPORT bool hv_msg_isBang(const HvMessage *const m, int i) {
- return msg_isBang(m,i);
-}
-
-HV_EXPORT void hv_msg_setBang(HvMessage *m, int i) {
- msg_setBang(m,i);
-}
-
-HV_EXPORT bool hv_msg_isFloat(const HvMessage *const m, int i) {
- return msg_isFloat(m, i);
-}
-
-HV_EXPORT float hv_msg_getFloat(const HvMessage *const m, int i) {
- return msg_getFloat(m,i);
-}
-
-HV_EXPORT void hv_msg_setFloat(HvMessage *m, int i, float f) {
- msg_setFloat(m,i,f);
-}
-
-HV_EXPORT bool hv_msg_isSymbol(const HvMessage *const m, int i) {
- return msg_isSymbol(m,i);
-}
-
-HV_EXPORT const char *hv_msg_getSymbol(const HvMessage *const m, int i) {
- return msg_getSymbol(m,i);
-}
-
-HV_EXPORT void hv_msg_setSymbol(HvMessage *m, int i, const char *s) {
- msg_setSymbol(m,i,s);
-}
-
-HV_EXPORT bool hv_msg_isHash(const HvMessage *const m, int i) {
- return msg_isHash(m, i);
-}
-
-HV_EXPORT hv_uint32_t hv_msg_getHash(const HvMessage *const m, int i) {
- return msg_getHash(m, i);
-}
-
-HV_EXPORT bool hv_msg_hasFormat(const HvMessage *const m, const char *fmt) {
- return msg_hasFormat(m, fmt);
-}
-
-HV_EXPORT char *hv_msg_toString(const HvMessage *const m) {
- return msg_toString(m);
-}
-
-HV_EXPORT HvMessage *hv_msg_copy(const HvMessage *const m) {
- return msg_copy(m);
-}
-
-HV_EXPORT void hv_msg_free(HvMessage *m) {
- msg_free(m);
-}
-
-
-
-#if HV_APPLE
-#pragma mark - Heavy Common
-#endif
-
-HV_EXPORT int hv_getSize(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- return (int) c->getSize();
-}
-
-HV_EXPORT double hv_getSampleRate(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- return c->getSampleRate();
-}
-
-HV_EXPORT int hv_getNumInputChannels(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- return c->getNumInputChannels();
-}
-
-HV_EXPORT int hv_getNumOutputChannels(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- return c->getNumOutputChannels();
-}
-
-HV_EXPORT void hv_setPrintHook(HeavyContextInterface *c, HvPrintHook_t *f) {
- hv_assert(c != nullptr);
- c->setPrintHook(f);
-}
-
-HV_EXPORT HvPrintHook_t *hv_getPrintHook(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- return c->getPrintHook();
-}
-
-HV_EXPORT void hv_setSendHook(HeavyContextInterface *c, HvSendHook_t *f) {
- hv_assert(c != nullptr);
- c->setSendHook(f);
-}
-
-HV_EXPORT hv_uint32_t hv_stringToHash(const char *s) {
- return hv_string_to_hash(s);
-}
-
-HV_EXPORT bool hv_sendBangToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash) {
- hv_assert(c != nullptr);
- return c->sendBangToReceiver(receiverHash);
-}
-
-HV_EXPORT bool hv_sendFloatToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, float x) {
- hv_assert(c != nullptr);
- return c->sendFloatToReceiver(receiverHash, x);
-}
-
-HV_EXPORT bool hv_sendSymbolToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, char *s) {
- hv_assert(c != nullptr);
- return c->sendSymbolToReceiver(receiverHash, s);
-}
-
-HV_EXPORT bool hv_sendMessageToReceiverV(
- HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, const char *format, ...) {
- hv_assert(c != nullptr);
- hv_assert(delayMs >= 0.0);
- hv_assert(format != nullptr);
-
- va_list ap;
- va_start(ap, format);
- const int numElem = (int) hv_strlen(format);
- HvMessage *m = HV_MESSAGE_ON_STACK(numElem);
- msg_init(m, numElem, c->getCurrentSample() + (hv_uint32_t) (hv_max_d(0.0, delayMs)*c->getSampleRate()/1000.0));
- for (int i = 0; i < numElem; i++) {
- switch (format[i]) {
- case 'b': msg_setBang(m, i); break;
- case 'f': msg_setFloat(m, i, (float) va_arg(ap, double)); break;
- case 'h': msg_setHash(m, i, (int) va_arg(ap, int)); break;
- case 's': msg_setSymbol(m, i, (char *) va_arg(ap, char *)); break;
- default: break;
- }
- }
- va_end(ap);
-
- return c->sendMessageToReceiver(receiverHash, delayMs, m);
-}
-
-HV_EXPORT bool hv_sendMessageToReceiver(
- HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, HvMessage *m) {
- hv_assert(c != nullptr);
- return c->sendMessageToReceiver(receiverHash, delayMs, m);
-}
-
-HV_EXPORT void hv_cancelMessage(HeavyContextInterface *c, HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
- hv_assert(c != nullptr);
- c->cancelMessage(m, sendMessage);
-}
-
-HV_EXPORT const char *hv_getName(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- return c->getName();
-}
-
-HV_EXPORT void hv_setUserData(HeavyContextInterface *c, void *userData) {
- hv_assert(c != nullptr);
- c->setUserData(userData);
-}
-
-HV_EXPORT void *hv_getUserData(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- return c->getUserData();
-}
-
-HV_EXPORT double hv_getCurrentTime(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- return (double) c->samplesToMilliseconds(c->getCurrentSample());
-}
-
-HV_EXPORT hv_uint32_t hv_getCurrentSample(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- return c->getCurrentSample();
-}
-
-HV_EXPORT float hv_samplesToMilliseconds(HeavyContextInterface *c, hv_uint32_t numSamples) {
- hv_assert(c != nullptr);
- return c->samplesToMilliseconds(numSamples);
-}
-
-HV_EXPORT hv_uint32_t hv_millisecondsToSamples(HeavyContextInterface *c, float ms) {
- hv_assert(c != nullptr);
- return c->millisecondsToSamples(ms);
-}
-
-HV_EXPORT int hv_getParameterInfo(HeavyContextInterface *c, int index, HvParameterInfo *info) {
- hv_assert(c != nullptr);
- return c->getParameterInfo(index, info);
-}
-
-HV_EXPORT void hv_lock_acquire(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- c->lockAcquire();
-}
-
-HV_EXPORT bool hv_lock_try(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- return c->lockTry();
-}
-
-HV_EXPORT void hv_lock_release(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- c->lockRelease();
-}
-
-HV_EXPORT void hv_setInputMessageQueueSize(HeavyContextInterface *c, hv_uint32_t inQueueKb) {
- hv_assert(c != nullptr);
- c->setInputMessageQueueSize(inQueueKb);
-}
-
-HV_EXPORT void hv_setOutputMessageQueueSize(HeavyContextInterface *c, hv_uint32_t outQueueKb) {
- hv_assert(c != nullptr);
- c->setOutputMessageQueueSize(outQueueKb);
-}
-
-HV_EXPORT bool hv_getNextSentMessage(HeavyContextInterface *c, hv_uint32_t *destinationHash, HvMessage *outMsg, hv_uint32_t msgLength) {
- hv_assert(c != nullptr);
- hv_assert(destinationHash != nullptr);
- hv_assert(outMsg != nullptr);
- return c->getNextSentMessage(destinationHash, outMsg, msgLength);
-}
-
-
-#if HV_APPLE
-#pragma mark - Heavy Common
-#endif
-
-HV_EXPORT int hv_process(HeavyContextInterface *c, float **inputBuffers, float **outputBuffers, int n) {
- hv_assert(c != nullptr);
- return c->process(inputBuffers, outputBuffers, n);
-}
-
-HV_EXPORT int hv_processInline(HeavyContextInterface *c, float *inputBuffers, float *outputBuffers, int n) {
- hv_assert(c != nullptr);
- return c->processInline(inputBuffers, outputBuffers, n);
-}
-
-HV_EXPORT int hv_processInlineInterleaved(HeavyContextInterface *c, float *inputBuffers, float *outputBuffers, int n) {
- hv_assert(c != nullptr);
- return c->processInlineInterleaved(inputBuffers, outputBuffers, n);
-}
-
-HV_EXPORT void hv_delete(HeavyContextInterface *c) {
- delete c;
-}
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvHeavy.h b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvHeavy.h
deleted file mode 100644
index cb1aecfa98..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvHeavy.h
+++ /dev/null
@@ -1,413 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _HEAVY_H_
-#define _HEAVY_H_
-
-#include "HvUtils.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef _HEAVY_DECLARATIONS_
-#define _HEAVY_DECLARATIONS_
-
-#ifdef __cplusplus
-class HeavyContextInterface;
-#else
-typedef struct HeavyContextInterface HeavyContextInterface;
-#endif
-
-typedef struct HvMessage HvMessage;
-
-typedef enum {
- HV_PARAM_TYPE_PARAMETER_IN,
- HV_PARAM_TYPE_PARAMETER_OUT,
- HV_PARAM_TYPE_EVENT_IN,
- HV_PARAM_TYPE_EVENT_OUT
-} HvParameterType;
-
-typedef struct HvParameterInfo {
- const char *name; // the human readable parameter name
- hv_uint32_t hash; // an integer identified used by heavy for this parameter
- HvParameterType type; // type of this parameter
- float minVal; // the minimum value of this parameter
- float maxVal; // the maximum value of this parameter
- float defaultVal; // the default value of this parameter
-} HvParameterInfo;
-
-typedef void (HvSendHook_t) (HeavyContextInterface *context, const char *sendName, hv_uint32_t sendHash, const HvMessage *msg);
-typedef void (HvPrintHook_t) (HeavyContextInterface *context, const char *printName, const char *str, const HvMessage *msg);
-
-#endif // _HEAVY_DECLARATIONS_
-
-
-
-#if HV_APPLE
-#pragma mark - Heavy Context
-#endif
-
-/** Deletes a patch instance. */
-void hv_delete(HeavyContextInterface *c);
-
-
-
-#if HV_APPLE
-#pragma mark - Heavy Process
-#endif
-
-/**
- * Processes one block of samples for a patch instance. The buffer format is an array of float channel arrays.
- * If the context has not input or output channels, the respective argument may be NULL.
- * The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
- * no, SSE or NEON, or AVX optimisation is being used, respectively.
- * e.g. [[LLLL][RRRR]]
- * This function support in-place processing.
- *
- * @return The number of samples processed.
- *
- * This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
- */
-int hv_process(HeavyContextInterface *c, float **inputBuffers, float **outputBuffers, int n);
-
-/**
- * Processes one block of samples for a patch instance. The buffer format is an uninterleaved float array of channels.
- * If the context has not input or output channels, the respective argument may be NULL.
- * The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
- * no, SSE or NEON, or AVX optimisation is being used, respectively.
- * e.g. [LLLLRRRR]
- * This function support in-place processing.
- *
- * @return The number of samples processed.
- *
- * This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
- */
-int hv_processInline(HeavyContextInterface *c, float *inputBuffers, float *outputBuffers, int n);
-
-/**
- * Processes one block of samples for a patch instance. The buffer format is an interleaved float array of channels.
- * If the context has not input or output channels, the respective argument may be NULL.
- * The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
- * no, SSE or NEON, or AVX optimisation is being used, respectively.
- * e.g. [LRLRLRLR]
- * This function support in-place processing.
- *
- * @return The number of samples processed.
- *
- * This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
- */
-int hv_processInlineInterleaved(HeavyContextInterface *c, float *inputBuffers, float *outputBuffers, int n);
-
-
-
-#if HV_APPLE
-#pragma mark - Heavy Common
-#endif
-
-/**
- * Returns the total size in bytes of the context.
- * This value may change if tables are resized.
- */
-int hv_getSize(HeavyContextInterface *c);
-
-/** Returns the sample rate with which this context has been configured. */
-double hv_getSampleRate(HeavyContextInterface *c);
-
-/** Returns the number of input channels with which this context has been configured. */
-int hv_getNumInputChannels(HeavyContextInterface *c);
-
-/** Returns the number of output channels with which this context has been configured. */
-int hv_getNumOutputChannels(HeavyContextInterface *c);
-
-/** Set the print hook. The function is called whenever a message is sent to a print object. */
-void hv_setPrintHook(HeavyContextInterface *c, HvPrintHook_t *f);
-
-/** Returns the print hook, or NULL. */
-HvPrintHook_t *hv_getPrintHook(HeavyContextInterface *c);
-
-/**
- * Set the send hook. The function is called whenever a message is sent to any send object.
- * Messages returned by this function should NEVER be freed. If the message must persist, call
- * hv_msg_copy() first.
- */
-void hv_setSendHook(HeavyContextInterface *c, HvSendHook_t *f);
-
-/** Returns a 32-bit hash of any string. Returns 0 if string is NULL. */
-hv_uint32_t hv_stringToHash(const char *s);
-
-/**
- * A convenience function to send a bang to a receiver to be processed immediately.
- * The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
- * This function is thread-safe.
- *
- * @return True if the message was accepted. False if the message could not fit onto
- * the message queue to be processed this block.
- */
-bool hv_sendBangToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash);
-
-/**
- * A convenience function to send a float to a receiver to be processed immediately.
- * The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
- * This function is thread-safe.
- *
- * @return True if the message was accepted. False if the message could not fit onto
- * the message queue to be processed this block.
- */
-bool hv_sendFloatToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, const float x);
-
-/**
- * A convenience function to send a symbol to a receiver to be processed immediately.
- * The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
- * This function is thread-safe.
- *
- * @return True if the message was accepted. False if the message could not fit onto
- * the message queue to be processed this block.
- */
-bool hv_sendSymbolToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, char *s);
-
-/**
- * Sends a formatted message to a receiver that can be scheduled for the future.
- * The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
- * This function is thread-safe.
- *
- * @return True if the message was accepted. False if the message could not fit onto
- * the message queue to be processed this block.
- */
-bool hv_sendMessageToReceiverV(HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, const char *format, ...);
-
-/**
- * Sends a message to a receiver that can be scheduled for the future.
- * The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
- * This function is thread-safe.
- *
- * @return True if the message was accepted. False if the message could not fit onto
- * the message queue to be processed this block.
- */
-bool hv_sendMessageToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, HvMessage *m);
-
-/**
- * Cancels a previously scheduled message.
- *
- * @param sendMessage May be NULL.
- */
-void hv_cancelMessage(HeavyContextInterface *c, HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
-
-/** Returns the read-only user-assigned name of this patch. */
-const char *hv_getName(HeavyContextInterface *c);
-
-/** Sets a user-definable value. This value is never manipulated by Heavy. */
-void hv_setUserData(HeavyContextInterface *c, void *userData);
-
-/** Returns the user-defined data. */
-void *hv_getUserData(HeavyContextInterface *c);
-
-/** Returns the current patch time in milliseconds. This value may have rounding errors. */
-double hv_getCurrentTime(HeavyContextInterface *c);
-
-/** Returns the current patch time in samples. This value is always exact. */
-hv_uint32_t hv_getCurrentSample(HeavyContextInterface *c);
-
-/**
- * Returns information about each parameter such as name, hash, and range.
- * The total number of parameters is always returned.
- *
- * @param index The parameter index.
- * @param info A pointer to a HvParameterInfo struct. May be null.
- *
- * @return The total number of parameters.
- */
-int hv_getParameterInfo(HeavyContextInterface *c, int index, HvParameterInfo *info);
-
-/** */
-float hv_samplesToMilliseconds(HeavyContextInterface *c, hv_uint32_t numSamples);
-
-/** Converts milliseconds to samples. Input is limited to non-negative range. */
-hv_uint32_t hv_millisecondsToSamples(HeavyContextInterface *c, float ms);
-
-/**
- * Acquire the input message queue lock.
- *
- * This function will block until the message lock as been acquired.
- * Typical applications will not require the use of this function.
- *
- * @param c A Heavy context.
- */
-void hv_lock_acquire(HeavyContextInterface *c);
-
-/**
- * Try to acquire the input message queue lock.
- *
- * If the lock has been acquired, hv_lock_release() must be called to release it.
- * Typical applications will not require the use of this function.
- *
- * @param c A Heavy context.
- *
- * @return Returns true if the lock has been acquired, false otherwise.
- */
-bool hv_lock_try(HeavyContextInterface *c);
-
-/**
- * Release the input message queue lock.
- *
- * Typical applications will not require the use of this function.
- *
- * @param c A Heavy context.
- */
-void hv_lock_release(HeavyContextInterface *c);
-
-/**
- * Set the size of the input message queue in kilobytes.
- *
- * The buffer is reset and all existing contents are lost on resize.
- *
- * @param c A Heavy context.
- * @param inQueueKb Must be positive i.e. at least one.
- */
-void hv_setInputMessageQueueSize(HeavyContextInterface *c, hv_uint32_t inQueueKb);
-
-/**
- * Set the size of the output message queue in kilobytes.
- *
- * The buffer is reset and all existing contents are lost on resize.
- * Only the default sendhook uses the outgoing message queue. If the default
- * sendhook is not being used, then this function is not useful.
- *
- * @param c A Heavy context.
- * @param outQueueKb Must be postive i.e. at least one.
- */
-void hv_setOutputMessageQueueSize(HeavyContextInterface *c, hv_uint32_t outQueueKb);
-
-/**
- * Get the next message in the outgoing queue, will also consume the message.
- * Returns false if there are no messages.
- *
- * @param c A Heavy context.
- * @param destinationHash a hash of the name of the receiver the message was sent to.
- * @param outMsg message pointer that is filled by the next message contents.
- * @param msgLength length of outMsg in bytes.
- *
- * @return True if there is a message in the outgoing queue.
-*/
-bool hv_getNextSentMessage(HeavyContextInterface *c, hv_uint32_t *destinationHash, HvMessage *outMsg, hv_uint32_t msgLength);
-
-
-
-#if HV_APPLE
-#pragma mark - Heavy Message
-#endif
-
-typedef struct HvMessage HvMessage;
-
-/** Returns the total size in bytes of a HvMessage with a number of elements on the heap. */
-unsigned long hv_msg_getByteSize(hv_uint32_t numElements);
-
-/** Initialise a HvMessage structure with the number of elements and a timestamp (in samples). */
-void hv_msg_init(HvMessage *m, int numElements, hv_uint32_t timestamp);
-
-/** Returns the number of elements in this message. */
-unsigned long hv_msg_getNumElements(const HvMessage *m);
-
-/** Returns the time at which this message exists (in samples). */
-hv_uint32_t hv_msg_getTimestamp(const HvMessage *m);
-
-/** Set the time at which this message should be executed (in samples). */
-void hv_msg_setTimestamp(HvMessage *m, hv_uint32_t timestamp);
-
-/** Returns true of the indexed element is a bang. False otherwise. Index is not bounds checked. */
-bool hv_msg_isBang(const HvMessage *const m, int i);
-
-/** Sets the indexed element to a bang. Index is not bounds checked. */
-void hv_msg_setBang(HvMessage *m, int i);
-
-/** Returns true of the indexed element is a float. False otherwise. Index is not bounds checked. */
-bool hv_msg_isFloat(const HvMessage *const m, int i);
-
-/** Returns the indexed element as a float value. Index is not bounds checked. */
-float hv_msg_getFloat(const HvMessage *const m, int i);
-
-/** Sets the indexed element to float value. Index is not bounds checked. */
-void hv_msg_setFloat(HvMessage *m, int i, float f);
-
-/** Returns true of the indexed element is a symbol. False otherwise. Index is not bounds checked. */
-bool hv_msg_isSymbol(const HvMessage *const m, int i);
-
-/** Returns the indexed element as a symbol value. Index is not bounds checked. */
-const char *hv_msg_getSymbol(const HvMessage *const m, int i);
-
-/** Returns true of the indexed element is a hash. False otherwise. Index is not bounds checked. */
-bool hv_msg_isHash(const HvMessage *const m, int i);
-
-/** Returns the indexed element as a hash value. Index is not bounds checked. */
-hv_uint32_t hv_msg_getHash(const HvMessage *const m, int i);
-
-/** Sets the indexed element to symbol value. Index is not bounds checked. */
-void hv_msg_setSymbol(HvMessage *m, int i, const char *s);
-
-/**
- * Returns true if the message has the given format, in number of elements and type. False otherwise.
- * Valid element types are:
- * 'b': bang
- * 'f': float
- * 's': symbol
- *
- * For example, a message with three floats would have a format of "fff". A single bang is "b".
- * A message with two symbols is "ss". These types can be mixed and matched in any way.
- */
-bool hv_msg_hasFormat(const HvMessage *const m, const char *fmt);
-
-/**
- * Returns a basic string representation of the message.
- * The character array MUST be deallocated by the caller.
- */
-char *hv_msg_toString(const HvMessage *const m);
-
-/** Copy a message onto the stack. The message persists. */
-HvMessage *hv_msg_copy(const HvMessage *const m);
-
-/** Free a copied message. */
-void hv_msg_free(HvMessage *m);
-
-
-
-#if HV_APPLE
-#pragma mark - Heavy Table
-#endif
-
-/**
- * Resizes the table to the given length.
- *
- * Existing contents are copied to the new table. Remaining space is cleared
- * if the table is longer than the original, truncated otherwise.
- *
- * @param tableHash The table identifier.
- * @param newSampleLength The new length of the table, in samples. Must be positive.
- *
- * @return False if the table could not be found. True otherwise.
- */
-bool hv_table_setLength(HeavyContextInterface *c, hv_uint32_t tableHash, hv_uint32_t newSampleLength);
-
-/** Returns a pointer to the raw buffer backing this table. DO NOT free it. */
-float *hv_table_getBuffer(HeavyContextInterface *c, hv_uint32_t tableHash);
-
-/** Returns the length of this table in samples. */
-hv_uint32_t hv_table_getLength(HeavyContextInterface *c, hv_uint32_t tableHash);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // _HEAVY_H_
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvHeavyInternal.h b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvHeavyInternal.h
deleted file mode 100644
index e10b944410..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvHeavyInternal.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _HEAVY_INTERNAL_H_
-#define _HEAVY_INTERNAL_H_
-
-#include "HvHeavy.h"
-#include "HvUtils.h"
-#include "HvTable.h"
-#include "HvMessage.h"
-#include "HvMath.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- *
- */
-HvTable *hv_table_get(HeavyContextInterface *c, hv_uint32_t tableHash);
-
-/**
- *
- */
-void hv_scheduleMessageForReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, HvMessage *m);
-
-/**
- *
- */
-HvMessage *hv_scheduleMessageForObject(HeavyContextInterface *c, const HvMessage *m,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
- int letIndex);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvLightPipe.c b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvLightPipe.c
deleted file mode 100644
index 98de428312..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvLightPipe.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "HvLightPipe.h"
-
-#if __SSE__ || HV_SIMD_SSE
-#include
-#define hv_sfence() _mm_sfence()
-#elif __arm__ || HV_SIMD_NEON
- #if __ARM_ACLE
- #include
- // https://msdn.microsoft.com/en-us/library/hh875058.aspx#BarrierRestrictions
- // http://doxygen.reactos.org/d8/d47/armintr_8h_a02be7ec76ca51842bc90d9b466b54752.html
- #define hv_sfence() __dmb(0xE) /* _ARM_BARRIER_ST */
- #elif defined(__GNUC__)
- #define hv_sfence() __asm__ volatile ("dmb 0xE":::"memory")
- #else
- // http://stackoverflow.com/questions/19965076/gcc-memory-barrier-sync-synchronize-vs-asm-volatile-memory
- #define hv_sfence() __sync_synchronize()
- #endif
-#elif HV_WIN
-// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684208(v=vs.85).aspx
-#define hv_sfence() _WriteBarrier()
-#else
-#define hv_sfence() __asm__ volatile("" : : : "memory")
-#endif
-
-#define HLP_STOP 0
-#define HLP_LOOP 0xFFFFFFFF
-#define HLP_SET_UINT32_AT_BUFFER(a, b) (*((hv_uint32_t *) (a)) = (b))
-#define HLP_GET_UINT32_AT_BUFFER(a) (*((hv_uint32_t *) (a)))
-
-hv_uint32_t hLp_init(HvLightPipe *q, hv_uint32_t numBytes) {
- if (numBytes > 0) {
- q->buffer = (char *) hv_malloc(numBytes);
- hv_assert(q->buffer != NULL);
- HLP_SET_UINT32_AT_BUFFER(q->buffer, HLP_STOP);
- } else {
- q->buffer = NULL;
- }
- q->writeHead = q->buffer;
- q->readHead = q->buffer;
- q->len = numBytes;
- q->remainingBytes = numBytes;
- return numBytes;
-}
-
-void hLp_free(HvLightPipe *q) {
- hv_free(q->buffer);
-}
-
-hv_uint32_t hLp_hasData(HvLightPipe *q) {
- hv_uint32_t x = HLP_GET_UINT32_AT_BUFFER(q->readHead);
- if (x == HLP_LOOP) {
- q->readHead = q->buffer;
- x = HLP_GET_UINT32_AT_BUFFER(q->readHead);
- }
- return x;
-}
-
-char *hLp_getWriteBuffer(HvLightPipe *q, hv_uint32_t bytesToWrite) {
- char *const readHead = q->readHead;
- char *const oldWriteHead = q->writeHead;
- const hv_uint32_t totalByteRequirement = bytesToWrite + 2*sizeof(hv_uint32_t);
-
- // check if there is enough space to write the data in the remaining
- // length of the buffer
- if (totalByteRequirement <= q->remainingBytes) {
- char *const newWriteHead = oldWriteHead + sizeof(hv_uint32_t) + bytesToWrite;
-
- // check if writing would overwrite existing data in the pipe (return NULL if so)
- if ((oldWriteHead < readHead) && (newWriteHead >= readHead)) return NULL;
- else return (oldWriteHead + sizeof(hv_uint32_t));
- } else {
- // there isn't enough space, try looping around to the start
- if (totalByteRequirement <= q->len) {
- if ((oldWriteHead < readHead) || ((q->buffer + totalByteRequirement) > readHead)) {
- return NULL; // overwrite condition
- } else {
- q->writeHead = q->buffer;
- q->remainingBytes = q->len;
- HLP_SET_UINT32_AT_BUFFER(q->buffer, HLP_STOP);
- hv_sfence();
- HLP_SET_UINT32_AT_BUFFER(oldWriteHead, HLP_LOOP);
- return q->buffer + sizeof(hv_uint32_t);
- }
- } else {
- return NULL; // there isn't enough space to write the data
- }
- }
-}
-
-void hLp_produce(HvLightPipe *q, hv_uint32_t numBytes) {
- hv_assert(q->remainingBytes >= (numBytes + 2*sizeof(hv_uint32_t)));
- q->remainingBytes -= (sizeof(hv_uint32_t) + numBytes);
- char *const oldWriteHead = q->writeHead;
- q->writeHead += (sizeof(hv_uint32_t) + numBytes);
- HLP_SET_UINT32_AT_BUFFER(q->writeHead, HLP_STOP);
-
- // save everything before this point to memory
- hv_sfence();
-
- // then save this
- HLP_SET_UINT32_AT_BUFFER(oldWriteHead, numBytes);
-}
-
-char *hLp_getReadBuffer(HvLightPipe *q, hv_uint32_t *numBytes) {
- *numBytes = HLP_GET_UINT32_AT_BUFFER(q->readHead);
- char *const readBuffer = q->readHead + sizeof(hv_uint32_t);
- return readBuffer;
-}
-
-void hLp_consume(HvLightPipe *q) {
- hv_assert(HLP_GET_UINT32_AT_BUFFER(q->readHead) != HLP_STOP);
- q->readHead += sizeof(hv_uint32_t) + HLP_GET_UINT32_AT_BUFFER(q->readHead);
-}
-
-void hLp_reset(HvLightPipe *q) {
- q->writeHead = q->buffer;
- q->readHead = q->buffer;
- q->remainingBytes = q->len;
- memset(q->buffer, 0, q->len);
-}
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvLightPipe.h b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvLightPipe.h
deleted file mode 100644
index 438f7261dc..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvLightPipe.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _HEAVY_LIGHTPIPE_H_
-#define _HEAVY_LIGHTPIPE_H_
-
-#include "HvUtils.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * This pipe assumes that there is only one producer thread and one consumer
- * thread. This data structure does not support any other configuration.
- */
-typedef struct HvLightPipe {
- char *buffer;
- char *writeHead;
- char *readHead;
- hv_uint32_t len;
- hv_uint32_t remainingBytes; // total bytes from write head to end
-} HvLightPipe;
-
-/**
- * Initialise the pipe with a given length, in bytes.
- * @return Returns the size of the pipe in bytes.
- */
-hv_uint32_t hLp_init(HvLightPipe *q, hv_uint32_t numBytes);
-
-/**
- * Frees the internal buffer.
- * @param q The light pipe.
- */
-void hLp_free(HvLightPipe *q);
-
-/**
- * Indicates if data is available for reading.
- * @param q The light pipe.
- *
- * @return Returns the number of bytes available for reading. Zero if no bytes
- * are available.
- */
-hv_uint32_t hLp_hasData(HvLightPipe *q);
-
-/**
- * Returns a pointer to a location in the pipe where numBytes can be written.
- *
- * @param numBytes The number of bytes to be written.
- * @return A pointer to a location where those bytes can be written. Returns
- * NULL if no more space is available. Successive calls to this
- * function may eventually return a valid pointer because the readhead
- * has been advanced on another thread.
- */
-char *hLp_getWriteBuffer(HvLightPipe *q, hv_uint32_t numBytes);
-
-/**
- * Indicates to the pipe how many bytes have been written.
- *
- * @param numBytes The number of bytes written. In general this should be the
- * same value as was passed to the preceeding call to
- * hLp_getWriteBuffer().
- */
-void hLp_produce(HvLightPipe *q, hv_uint32_t numBytes);
-
-/**
- * Returns the current read buffer, indicating the number of bytes available
- * for reading.
- * @param q The light pipe.
- * @param numBytes This value will be filled with the number of bytes available
- * for reading.
- *
- * @return A pointer to the read buffer.
- */
-char *hLp_getReadBuffer(HvLightPipe *q, hv_uint32_t *numBytes);
-
-/**
- * Indicates that the next set of bytes have been read and are no longer needed.
- * @param q The light pipe.
- */
-void hLp_consume(HvLightPipe *q);
-
-// resets the queue to it's initialised state
-// This should be done when only one thread is accessing the pipe.
-void hLp_reset(HvLightPipe *q);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _HEAVY_LIGHTPIPE_H_
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvMath.h b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvMath.h
deleted file mode 100644
index d25de2df98..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvMath.h
+++ /dev/null
@@ -1,736 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _HEAVY_MATH_H_
-#define _HEAVY_MATH_H_
-
-#include "HvUtils.h"
-
-// https://software.intel.com/sites/landingpage/IntrinsicsGuide/
-// https://gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/ARM-NEON-Intrinsics.html
-// http://codesuppository.blogspot.co.uk/2015/02/sse2neonh-porting-guide-and-header-file.html
-
-static inline void __hv_zero_f(hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_setzero_ps();
-#elif HV_SIMD_SSE
- *bOut = _mm_setzero_ps();
-#elif HV_SIMD_NEON
- *bOut = vdupq_n_f32(0.0f);
-#else // HV_SIMD_NONE
- *bOut = 0.0f;
-#endif
-}
-
-static inline void __hv_zero_i(hv_bOuti_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_setzero_si256();
-#elif HV_SIMD_SSE
- *bOut = _mm_setzero_si128();
-#elif HV_SIMD_NEON
- *bOut = vdupq_n_s32(0);
-#else // HV_SIMD_NONE
- *bOut = 0;
-#endif
-}
-
-static inline void __hv_load_f(float *bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_load_ps(bIn);
-#elif HV_SIMD_SSE
- *bOut = _mm_load_ps(bIn);
-#elif HV_SIMD_NEON
- *bOut = vld1q_f32(bIn);
-#else // HV_SIMD_NONE
- *bOut = *bIn;
-#endif
-}
-
-static inline void __hv_store_f(float *bOut, hv_bInf_t bIn) {
-#if HV_SIMD_AVX
- _mm256_store_ps(bOut, bIn);
-#elif HV_SIMD_SSE
- _mm_store_ps(bOut, bIn);
-#elif HV_SIMD_NEON
- vst1q_f32(bOut, bIn);
-#else // HV_SIMD_NONE
- *bOut = bIn;
-#endif
-}
-
-static inline void __hv_log2_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_log2_f() not implemented
-#elif HV_SIMD_SSE
- // https://en.wikipedia.org/wiki/Fast_inverse_square_root
- __m128i a = _mm_castps_si128(bIn);
- __m128i b = _mm_srli_epi32(a, 23);
- __m128i c = _mm_sub_epi32(b, _mm_set1_epi32(127)); // exponent (int)
- __m128 d = _mm_cvtepi32_ps(c); // exponent (float)
- __m128i e = _mm_or_si128(_mm_andnot_si128(_mm_set1_epi32(0xFF800000), a), _mm_set1_epi32(0x3F800000));
- __m128 f = _mm_castsi128_ps(e); // 1+m (float)
- __m128 g = _mm_add_ps(d, f); // e + 1 + m
- __m128 h = _mm_add_ps(g, _mm_set1_ps(-0.9569643f)); // e + 1 + m + (sigma-1)
- *bOut = h;
-#elif HV_SIMD_NEON
- int32x4_t a = vreinterpretq_s32_f32(bIn);
- int32x4_t b = vshrq_n_s32(a, 23);
- int32x4_t c = vsubq_s32(b, vdupq_n_s32(127));
- float32x4_t d = vcvtq_f32_s32(c);
- int32x4_t e = vorrq_s32(vbicq_s32(a, vdupq_n_s32(0xFF800000)), vdupq_n_s32(0x3F800000));
- float32x4_t f = vreinterpretq_f32_s32(e);
- float32x4_t g = vaddq_f32(d, f);
- float32x4_t h = vaddq_f32(g, vdupq_n_f32(-0.9569643f));
- *bOut = h;
-#else // HV_SIMD_NONE
- *bOut = 1.442695040888963f * hv_log_f(bIn);
-#endif
-}
-
-// NOTE(mhroth): this is a pretty ghetto implementation
-static inline void __hv_cos_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_set_ps(
- hv_cos_f(bIn[7]), hv_cos_f(bIn[6]), hv_cos_f(bIn[5]), hv_cos_f(bIn[4]),
- hv_cos_f(bIn[3]), hv_cos_f(bIn[2]), hv_cos_f(bIn[1]), hv_cos_f(bIn[0]));
-#elif HV_SIMD_SSE
- const float *const b = (float *) &bIn;
- *bOut = _mm_set_ps(hv_cos_f(b[3]), hv_cos_f(b[2]), hv_cos_f(b[1]), hv_cos_f(b[0]));
-#elif HV_SIMD_NEON
- *bOut = (float32x4_t) {hv_cos_f(bIn[0]), hv_cos_f(bIn[1]), hv_cos_f(bIn[2]), hv_cos_f(bIn[3])};
-#else // HV_SIMD_NONE
- *bOut = hv_cos_f(bIn);
-#endif
-}
-
-static inline void __hv_acos_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_acos_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_acos_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_acos_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_acos_f(bIn);
-#endif
-}
-
-static inline void __hv_cosh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_cosh_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_cosh_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_cosh_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_cosh_f(bIn);
-#endif
-}
-
-static inline void __hv_acosh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_acosh_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_acosh_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_acosh_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_acosh_f(bIn);
-#endif
-}
-
-static inline void __hv_sin_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_sin_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_sin_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_sin_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_sin_f(bIn);
-#endif
-}
-
-static inline void __hv_asin_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_asin_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_asin_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_asin_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_asin_f(bIn);
-#endif
-}
-
-static inline void __hv_sinh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_sinh_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_sinh_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_sinh_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_sinh_f(bIn);
-#endif
-}
-
-static inline void __hv_asinh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_asinh_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_asinh_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_asinh_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_asinh_f(bIn);
-#endif
-}
-
-static inline void __hv_tan_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_tan_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_tan_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_tan_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_tan_f(bIn);
-#endif
-}
-
-static inline void __hv_atan_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_atan_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_atan_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_atan_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_atan_f(bIn);
-#endif
-}
-
-static inline void __hv_atan2_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_atan2_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_atan2_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_atan2_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_atan2_f(bIn0, bIn1);
-#endif
-}
-
-static inline void __hv_tanh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_tanh_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_tanh_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_tanh_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_tanh_f(bIn);
-#endif
-}
-
-static inline void __hv_atanh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_atanh_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_atanh_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_atanh_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_atanh_f(bIn);
-#endif
-}
-
-static inline void __hv_sqrt_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_sqrt_ps(bIn);
-#elif HV_SIMD_SSE
- *bOut = _mm_sqrt_ps(bIn);
-#elif HV_SIMD_NEON
- const float32x4_t y = vrsqrteq_f32(bIn);
- *bOut = vmulq_f32(bIn, vmulq_f32(vrsqrtsq_f32(vmulq_f32(bIn, y), y), y)); // numerical results may be inexact
-#else // HV_SIMD_NONE
- *bOut = hv_sqrt_f(bIn);
-#endif
-}
-
-static inline void __hv_rsqrt_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_rsqrt_ps(bIn);
-#elif HV_SIMD_SSE
- *bOut = _mm_rsqrt_ps(bIn);
-#elif HV_SIMD_NEON
- const float32x4_t y = vrsqrteq_f32(bIn);
- *bOut = vmulq_f32(vrsqrtsq_f32(vmulq_f32(bIn, y), y), y); // numerical results may be inexact
-#else // HV_SIMD_NONE
- *bOut = 1.0f/hv_sqrt_f(bIn);
-#endif
-}
-
-static inline void __hv_abs_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_andnot_ps(_mm256_set1_ps(-0.0f), bIn);
-#elif HV_SIMD_SSE
- *bOut = _mm_andnot_ps(_mm_set1_ps(-0.0f), bIn); // == 1 << 31
-#elif HV_SIMD_NEON
- *bOut = vabsq_f32(bIn);
-#else // HV_SIMD_NONE
- *bOut = hv_abs_f(bIn);
-#endif
-}
-
-static inline void __hv_neg_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_xor_ps(bIn, _mm256_set1_ps(-0.0f));
-#elif HV_SIMD_SSE
- *bOut = _mm_xor_ps(bIn, _mm_set1_ps(-0.0f));
-#elif HV_SIMD_NEON
- *bOut = vnegq_f32(bIn);
-#else // HV_SIMD_NONE
- *bOut = bIn * -1.0f;
-#endif
-}
-
-static inline void __hv_exp_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- float *const b = (float *) hv_alloca(HV_N_SIMD*sizeof(float));
- _mm256_store_ps(b, bIn);
- *bOut = _mm256_set_ps(
- hv_exp_f(b[7]), hv_exp_f(b[6]), hv_exp_f(b[5]), hv_exp_f(b[4]),
- hv_exp_f(b[3]), hv_exp_f(b[2]), hv_exp_f(b[1]), hv_exp_f(b[0]));
-#elif HV_SIMD_SSE
- float *const b = (float *) hv_alloca(HV_N_SIMD*sizeof(float));
- _mm_store_ps(b, bIn);
- *bOut = _mm_set_ps(hv_exp_f(b[3]), hv_exp_f(b[2]), hv_exp_f(b[1]), hv_exp_f(b[0]));
-#elif HV_SIMD_NEON
- *bOut = (float32x4_t) {
- hv_exp_f(bIn[0]),
- hv_exp_f(bIn[1]),
- hv_exp_f(bIn[2]),
- hv_exp_f(bIn[3])};
-#else // HV_SIMD_NONE
- *bOut = hv_exp_f(bIn);
-#endif
-}
-
-static inline void __hv_ceil_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_ceil_ps(bIn);
-#elif HV_SIMD_SSE
- *bOut = _mm_ceil_ps(bIn);
-#elif HV_SIMD_NEON
-#if __ARM_ARCH >= 8
- *bOut = vrndpq_f32(bIn);
-#else
- // A slow NEON implementation of __hv_ceil_f() is being used because
- // the necessary intrinsic cannot be found. It is only available in ARMv8.
- *bOut = (float32x4_t) {hv_ceil_f(bIn[0]), hv_ceil_f(bIn[1]), hv_ceil_f(bIn[2]), hv_ceil_f(bIn[3])};
-#endif // vrndpq_f32
-#else // HV_SIMD_NONE
- *bOut = hv_ceil_f(bIn);
-#endif
-}
-
-static inline void __hv_floor_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_floor_ps(bIn);
-#elif HV_SIMD_SSE
- *bOut = _mm_floor_ps(bIn);
-#elif HV_SIMD_NEON
-#if __ARM_ARCH >= 8
- *bOut = vrndmq_f32(bIn);
-#else
- // A slow implementation of __hv_floor_f() is being used because
- // the necessary intrinsic cannot be found. It is only available from ARMv8.
- *bOut = (float32x4_t) {hv_floor_f(bIn[0]), hv_floor_f(bIn[1]), hv_floor_f(bIn[2]), hv_floor_f(bIn[3])};
-#endif // vrndmq_f32
-#else // HV_SIMD_NONE
- *bOut = hv_floor_f(bIn);
-#endif
-}
-
-// __add~f
-static inline void __hv_add_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_add_ps(bIn0, bIn1);
-#elif HV_SIMD_SSE
- *bOut = _mm_add_ps(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vaddq_f32(bIn0, bIn1);
-#else // HV_SIMD_NONE
- *bOut = bIn0 + bIn1;
-#endif
-}
-
-// __add~i
-static inline void __hv_add_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) {
-#if HV_SIMD_AVX
- __m128i x = _mm_add_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1));
- __m128i y = _mm_add_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1));
- *bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1);
-#elif HV_SIMD_SSE
- *bOut = _mm_add_epi32(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vaddq_s32(bIn0, bIn1);
-#else // HV_SIMD_NONE
- *bOut = bIn0 + bIn1;
-#endif
-}
-
-// __sub~f
-static inline void __hv_sub_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_sub_ps(bIn0, bIn1);
-#elif HV_SIMD_SSE
- *bOut = _mm_sub_ps(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vsubq_f32(bIn0, bIn1);
-#else // HV_SIMD_NONE
- *bOut = bIn0 - bIn1;
-#endif
-}
-
-// __mul~f
-static inline void __hv_mul_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_mul_ps(bIn0, bIn1);
-#elif HV_SIMD_SSE
- *bOut = _mm_mul_ps(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vmulq_f32(bIn0, bIn1);
-#else // HV_SIMD_NONE
- *bOut = bIn0 * bIn1;
-#endif
-}
-
-// __*~i
-static inline void __hv_mul_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) {
-#if HV_SIMD_AVX
- __m128i x = _mm_mullo_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1));
- __m128i y = _mm_mullo_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1));
- *bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1);
-#elif HV_SIMD_SSE
- *bOut = _mm_mullo_epi32(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vmulq_s32(bIn0, bIn1);
-#else // HV_SIMD_NONE
- *bOut = bIn0 * bIn1;
-#endif
-}
-
-// __cast~if
-static inline void __hv_cast_if(hv_bIni_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_cvtepi32_ps(bIn);
-#elif HV_SIMD_SSE
- *bOut = _mm_cvtepi32_ps(bIn);
-#elif HV_SIMD_NEON
- *bOut = vcvtq_f32_s32(bIn);
-#else // HV_SIMD_NONE
- *bOut = (float) bIn;
-#endif
-}
-
-// __cast~fi
-static inline void __hv_cast_fi(hv_bInf_t bIn, hv_bOuti_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_cvtps_epi32(bIn);
-#elif HV_SIMD_SSE
- *bOut = _mm_cvtps_epi32(bIn);
-#elif HV_SIMD_NEON
- *bOut = vcvtq_s32_f32(bIn);
-#else // HV_SIMD_NONE
- *bOut = (int) bIn;
-#endif
-}
-
-static inline void __hv_div_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- __m256 a = _mm256_cmp_ps(bIn1, _mm256_setzero_ps(), _CMP_EQ_OQ);
- __m256 b = _mm256_div_ps(bIn0, bIn1);
- *bOut = _mm256_andnot_ps(a, b);
-#elif HV_SIMD_SSE
- __m128 a = _mm_cmpeq_ps(bIn1, _mm_setzero_ps());
- __m128 b = _mm_div_ps(bIn0, bIn1);
- *bOut = _mm_andnot_ps(a, b);
-#elif HV_SIMD_NEON
- uint32x4_t a = vceqq_f32(bIn1, vdupq_n_f32(0.0f));
- float32x4_t b = vmulq_f32(bIn0, vrecpeq_f32(bIn1)); // NOTE(mhroth): numerical results may be inexact
- *bOut = vreinterpretq_f32_u32(vbicq_u32(vreinterpretq_u32_f32(b), a));
-#else // HV_SIMD_NONE
- *bOut = (bIn1 != 0.0f) ? (bIn0 / bIn1) : 0.0f;
-#endif
-}
-
-static inline void __hv_min_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_min_ps(bIn0, bIn1);
-#elif HV_SIMD_SSE
- *bOut = _mm_min_ps(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vminq_f32(bIn0, bIn1);
-#else // HV_SIMD_NONE
- *bOut = hv_min_f(bIn0, bIn1);
-#endif
-}
-
-static inline void __hv_min_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) {
-#if HV_SIMD_AVX
- __m128i x = _mm_min_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1));
- __m128i y = _mm_min_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1));
- *bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1);
-#elif HV_SIMD_SSE
- *bOut = _mm_min_epi32(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vminq_s32(bIn0, bIn1);
-#else // HV_SIMD_NONE
- *bOut = hv_min_i(bIn0, bIn1);
-#endif
-}
-
-static inline void __hv_max_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_max_ps(bIn0, bIn1);
-#elif HV_SIMD_SSE
- *bOut = _mm_max_ps(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vmaxq_f32(bIn0, bIn1);
-#else // HV_SIMD_NONE
- *bOut = hv_max_f(bIn0, bIn1);
-#endif
-}
-
-static inline void __hv_max_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) {
-#if HV_SIMD_AVX
- __m128i x = _mm_max_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1));
- __m128i y = _mm_max_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1));
- *bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1);
-#elif HV_SIMD_SSE
- *bOut = _mm_max_epi32(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vmaxq_s32(bIn0, bIn1);
-#else // HV_SIMD_NONE
- *bOut = hv_max_i(bIn0, bIn1);
-#endif
-}
-
-static inline void __hv_pow_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- float *b = (float *) hv_alloca(16*sizeof(float));
- _mm256_store_ps(b, bIn0);
- _mm256_store_ps(b+8, bIn1);
- *bOut = _mm256_set_ps(
- hv_pow_f(b[7], b[15]),
- hv_pow_f(b[6], b[14]),
- hv_pow_f(b[5], b[13]),
- hv_pow_f(b[4], b[12]),
- hv_pow_f(b[3], b[11]),
- hv_pow_f(b[2], b[10]),
- hv_pow_f(b[1], b[9]),
- hv_pow_f(b[0], b[8]));
-#elif HV_SIMD_SSE
- float *b = (float *) hv_alloca(8*sizeof(float));
- _mm_store_ps(b, bIn0);
- _mm_store_ps(b+4, bIn1);
- *bOut = _mm_set_ps(
- hv_pow_f(b[3], b[7]),
- hv_pow_f(b[2], b[6]),
- hv_pow_f(b[1], b[5]),
- hv_pow_f(b[0], b[4]));
-#elif HV_SIMD_NEON
- *bOut = (float32x4_t) {
- hv_pow_f(bIn0[0], bIn1[0]),
- hv_pow_f(bIn0[1], bIn1[1]),
- hv_pow_f(bIn0[2], bIn1[2]),
- hv_pow_f(bIn0[3], bIn1[3])};
-#else // HV_SIMD_NONE
- *bOut = hv_pow_f(bIn0, bIn1);
-#endif
-}
-
-static inline void __hv_gt_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_GT_OQ);
-#elif HV_SIMD_SSE
- *bOut = _mm_cmpgt_ps(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vreinterpretq_f32_u32(vcgtq_f32(bIn0, bIn1));
-#else // HV_SIMD_NONE
- *bOut = (bIn0 > bIn1) ? 1.0f : 0.0f;
-#endif
-}
-
-static inline void __hv_gte_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_GE_OQ);
-#elif HV_SIMD_SSE
- *bOut = _mm_cmpge_ps(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vreinterpretq_f32_u32(vcgeq_f32(bIn0, bIn1));
-#else // HV_SIMD_NONE
- *bOut = (bIn0 >= bIn1) ? 1.0f : 0.0f;
-#endif
-}
-
-static inline void __hv_lt_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_LT_OQ);
-#elif HV_SIMD_SSE
- *bOut = _mm_cmplt_ps(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vreinterpretq_f32_u32(vcltq_f32(bIn0, bIn1));
-#else // HV_SIMD_NONE
- *bOut = (bIn0 < bIn1) ? 1.0f : 0.0f;
-#endif
-}
-
-static inline void __hv_lte_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_LE_OQ);
-#elif HV_SIMD_SSE
- *bOut = _mm_cmple_ps(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vreinterpretq_f32_u32(vcleq_f32(bIn0, bIn1));
-#else // HV_SIMD_NONE
- *bOut = (bIn0 <= bIn1) ? 1.0f : 0.0f;
-#endif
-}
-
-static inline void __hv_eq_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_EQ_OQ);
-#elif HV_SIMD_SSE
- *bOut = _mm_cmpeq_ps(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vreinterpretq_f32_u32(vceqq_f32(bIn0, bIn1));
-#else // HV_SIMD_NONE
- *bOut = (bIn0 == bIn1) ? 1.0f : 0.0f;
-#endif
-}
-
-static inline void __hv_neq_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_NEQ_OQ);
-#elif HV_SIMD_SSE
- *bOut = _mm_cmpneq_ps(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vreinterpretq_f32_u32(vmvnq_u32(vceqq_f32(bIn0, bIn1)));
-#else // HV_SIMD_NONE
- *bOut = (bIn0 != bIn1) ? 1.0f : 0.0f;
-#endif
-}
-
-static inline void __hv_or_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_or_ps(bIn1, bIn0);
-#elif HV_SIMD_SSE
- *bOut = _mm_or_ps(bIn1, bIn0);
-#elif HV_SIMD_NEON
- *bOut = vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(bIn1), vreinterpretq_u32_f32(bIn0)));
-#else // HV_SIMD_NONE
- if (bIn0 == 0.0f && bIn1 == 0.0f) *bOut = 0.0f;
- else if (bIn0 == 0.0f) *bOut = bIn1;
- else if (bIn1 == 0.0f) *bOut = bIn0;
- else hv_assert(0);
-#endif
-}
-
-static inline void __hv_and_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_and_ps(bIn1, bIn0);
-#elif HV_SIMD_SSE
- *bOut = _mm_and_ps(bIn1, bIn0);
-#elif HV_SIMD_NEON
- *bOut = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(bIn1), vreinterpretq_u32_f32(bIn0)));
-#else // HV_SIMD_NONE
- if (bIn0 == 0.0f || bIn1 == 0.0f) *bOut = 0.0f;
- else if (bIn0 == 1.0f) *bOut = bIn1;
- else if (bIn1 == 1.0f) *bOut = bIn0;
- else hv_assert(0);
-#endif
-}
-
-static inline void __hv_andnot_f(hv_bInf_t bIn0_mask, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_andnot_ps(bIn0_mask, bIn1);
-#elif HV_SIMD_SSE
- *bOut = _mm_andnot_ps(bIn0_mask, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vreinterpretq_f32_s32(vbicq_s32(vreinterpretq_s32_f32(bIn1), vreinterpretq_s32_f32(bIn0_mask)));
-#else // HV_SIMD_NONE
- *bOut = (bIn0_mask == 0.0f) ? bIn1 : 0.0f;
-#endif
-}
-
-// bOut = (bIn0 * bIn1) + bIn2
-static inline void __hv_fma_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bInf_t bIn2, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
-#if HV_SIMD_FMA
- *bOut = _mm256_fmadd_ps(bIn0, bIn1, bIn2);
-#else
- *bOut = _mm256_add_ps(_mm256_mul_ps(bIn0, bIn1), bIn2);
-#endif // HV_SIMD_FMA
-#elif HV_SIMD_SSE
-#if HV_SIMD_FMA
- *bOut = _mm_fmadd_ps(bIn0, bIn1, bIn2);
-#else
- *bOut = _mm_add_ps(_mm_mul_ps(bIn0, bIn1), bIn2);
-#endif // HV_SIMD_FMA
-#elif HV_SIMD_NEON
-#if __ARM_ARCH >= 8
- *bOut = vfmaq_f32(bIn2, bIn0, bIn1);
-#else
- // NOTE(mhroth): it turns out, fma SUUUUCKS on lesser ARM architectures
- *bOut = vaddq_f32(vmulq_f32(bIn0, bIn1), bIn2);
-#endif
-#else // HV_SIMD_NONE
- *bOut = hv_fma_f(bIn0, bIn1, bIn2);
-#endif
-}
-
-// bOut = (bIn0 * bIn1) - bIn2
-static inline void __hv_fms_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bInf_t bIn2, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
-#if HV_SIMD_FMA
- *bOut = _mm256_fmsub_ps(bIn0, bIn1, bIn2);
-#else
- *bOut = _mm256_sub_ps(_mm256_mul_ps(bIn0, bIn1), bIn2);
-#endif // HV_SIMD_FMA
-#elif HV_SIMD_SSE
-#if HV_SIMD_FMA
- *bOut = _mm_fmsub_ps(bIn0, bIn1, bIn2);
-#else
- *bOut = _mm_sub_ps(_mm_mul_ps(bIn0, bIn1), bIn2);
-#endif // HV_SIMD_FMA
-#elif HV_SIMD_NEON
-#if __ARM_ARCH >= 8
- *bOut = vfmsq_f32(bIn2, bIn0, bIn1);
-#else
- // NOTE(mhroth): it turns out, fma SUUUUCKS on lesser ARM architectures
- *bOut = vsubq_f32(vmulq_f32(bIn0, bIn1), bIn2);
-#endif
-#else // HV_SIMD_NONE
- *bOut = (bIn0 * bIn1) - bIn2;
-#endif
-}
-
-#endif // _HEAVY_MATH_H_
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvMessage.c b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvMessage.c
deleted file mode 100644
index 0f1ac5d7c2..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvMessage.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "HvMessage.h"
-
-HvMessage *msg_init(HvMessage *m, hv_size_t numElements, hv_uint32_t timestamp) {
- m->timestamp = timestamp;
- m->numElements = (hv_uint16_t) numElements;
- m->numBytes = (hv_uint16_t) msg_getCoreSize(numElements);
- return m;
-}
-
-HvMessage *msg_initWithFloat(HvMessage *m, hv_uint32_t timestamp, float f) {
- m->timestamp = timestamp;
- m->numElements = 1;
- m->numBytes = sizeof(HvMessage);
- msg_setFloat(m, 0, f);
- return m;
-}
-
-HvMessage *msg_initWithBang(HvMessage *m, hv_uint32_t timestamp) {
- m->timestamp = timestamp;
- m->numElements = 1;
- m->numBytes = sizeof(HvMessage);
- msg_setBang(m, 0);
- return m;
-}
-
-HvMessage *msg_initWithSymbol(HvMessage *m, hv_uint32_t timestamp, const char *s) {
- m->timestamp = timestamp;
- m->numElements = 1;
- m->numBytes = sizeof(HvMessage) + (hv_uint16_t) hv_strlen(s);
- msg_setSymbol(m, 0, s);
- return m;
-}
-
-HvMessage *msg_initWithHash(HvMessage *m, hv_uint32_t timestamp, hv_uint32_t h) {
- m->timestamp = timestamp;
- m->numElements = 1;
- m->numBytes = sizeof(HvMessage);
- msg_setHash(m, 0, h);
- return m;
-}
-
-void msg_copyToBuffer(const HvMessage *m, char *buffer, hv_size_t len) {
- HvMessage *r = (HvMessage *) buffer;
-
- hv_size_t len_r = msg_getCoreSize(msg_getNumElements(m));
-
- // assert that the message is not already larger than the length of the buffer
- hv_assert(len_r <= len);
-
- // copy the basic message to the buffer
- hv_memcpy(r, m, len_r);
-
- char *p = buffer + len_r; // points to the end of the base message
- for (int i = 0; i < msg_getNumElements(m); ++i) {
- if (msg_isSymbol(m,i)) {
- const hv_size_t symLen = (hv_size_t) hv_strlen(msg_getSymbol(m,i)) + 1; // include the trailing null char
- hv_assert(len_r + symLen <= len); // stay safe!
- hv_strncpy(p, msg_getSymbol(m,i), symLen);
- msg_setSymbol(r, i, p);
- p += symLen;
- len_r += symLen;
- }
- }
-
- r->numBytes = (hv_uint16_t) len_r; // update the message size in memory
-}
-
-// the message is serialised such that all symbol elements are placed in order at the end of the buffer
-HvMessage *msg_copy(const HvMessage *m) {
- const hv_uint32_t heapSize = msg_getSize(m);
- char *r = (char *) hv_malloc(heapSize);
- hv_assert(r != NULL);
- msg_copyToBuffer(m, r, heapSize);
- return (HvMessage *) r;
-}
-
-void msg_free(HvMessage *m) {
- hv_free(m); // because heap messages are serialised in memory, a simple call to free releases the message
-}
-
-bool msg_hasFormat(const HvMessage *m, const char *fmt) {
- hv_assert(fmt != NULL);
- const int n = msg_getNumElements(m);
- for (int i = 0; i < n; ++i) {
- switch (fmt[i]) {
- case 'b': if (!msg_isBang(m, i)) return false; break;
- case 'f': if (!msg_isFloat(m, i)) return false; break;
- case 'h': if (!msg_isHash(m, i)) return false; break;
- case 's': if (!msg_isSymbol(m, i)) return false; break;
- default: return false;
- }
- }
- return (fmt[n] == '\0');
-}
-
-bool msg_compareSymbol(const HvMessage *m, int i, const char *s) {
- switch (msg_getType(m,i)) {
- case HV_MSG_SYMBOL: return !hv_strcmp(msg_getSymbol(m, i), s);
- case HV_MSG_HASH: return (msg_getHash(m,i) == hv_string_to_hash(s));
- default: return false;
- }
-}
-
-bool msg_equalsElement(const HvMessage *m, int i_m, const HvMessage *n, int i_n) {
- if (i_m < msg_getNumElements(m) && i_n < msg_getNumElements(n)) {
- if (msg_getType(m, i_m) == msg_getType(n, i_n)) {
- switch (msg_getType(m, i_m)) {
- case HV_MSG_BANG: return true;
- case HV_MSG_FLOAT: return (msg_getFloat(m, i_m) == msg_getFloat(n, i_n));
- case HV_MSG_SYMBOL: return msg_compareSymbol(m, i_m, msg_getSymbol(n, i_n));
- case HV_MSG_HASH: return msg_getHash(m,i_m) == msg_getHash(n,i_n);
- default: break;
- }
- }
- }
- return false;
-}
-
-void msg_setElementToFrom(HvMessage *n, int i_n, const HvMessage *const m, int i_m) {
- switch (msg_getType(m, i_m)) {
- case HV_MSG_BANG: msg_setBang(n, i_n); break;
- case HV_MSG_FLOAT: msg_setFloat(n, i_n, msg_getFloat(m, i_m)); break;
- case HV_MSG_SYMBOL: msg_setSymbol(n, i_n, msg_getSymbol(m, i_m)); break;
- case HV_MSG_HASH: msg_setHash(n, i_n, msg_getHash(m, i_m));
- default: break;
- }
-}
-
-hv_uint32_t msg_getHash(const HvMessage *const m, int i) {
- hv_assert(i < msg_getNumElements(m)); // invalid index
- switch (msg_getType(m,i)) {
- case HV_MSG_BANG: return 0xFFFFFFFF;
- case HV_MSG_FLOAT: {
- float f = msg_getFloat(m,i);
- return *((hv_uint32_t *) &f);
- }
- case HV_MSG_SYMBOL: return hv_string_to_hash(msg_getSymbol(m,i));
- case HV_MSG_HASH: return (&(m->elem)+i)->data.h;
- default: return 0;
- }
-}
-
-char *msg_toString(const HvMessage *m) {
- hv_assert(msg_getNumElements(m) > 0);
- int *len = (int *) hv_alloca(msg_getNumElements(m)*sizeof(int));
- int size = 0; // the total length of our final buffer
-
- // loop through every element in our list of atoms
- // first loop figures out how long our buffer should be
- for (int i = 0; i < msg_getNumElements(m); i++) {
- // length of our string is each atom plus a space, or \0 on the end
- switch (msg_getType(m, i)) {
- case HV_MSG_BANG: len[i] = hv_snprintf(NULL, 0, "%s", "bang") + 1; break;
- case HV_MSG_FLOAT: len[i] = hv_snprintf(NULL, 0, "%g", msg_getFloat(m, i)) + 1; break;
- case HV_MSG_SYMBOL: len[i] = hv_snprintf(NULL, 0, "%s", msg_getSymbol(m, i)) + 1; break;
- case HV_MSG_HASH: len[i] = hv_snprintf(NULL, 0, "0x%X", msg_getHash(m, i)) + 1; break;
- default: break;
- }
- size += len[i];
- }
-
- hv_assert(size > 0);
-
- // now we do the piecewise concatenation into our final string
- // the final buffer we will pass back after concatenating all strings - user should free it
- char *finalString = (char *) hv_malloc(size*sizeof(char));
- hv_assert(finalString != NULL);
- int pos = 0;
- for (int i = 0; i < msg_getNumElements(m); i++) {
- // put a string representation of each atom into the final string
- switch (msg_getType(m, i)) {
- case HV_MSG_BANG: hv_snprintf(finalString+pos, len[i], "%s", "bang"); break;
- case HV_MSG_FLOAT: hv_snprintf(finalString+pos, len[i], "%g", msg_getFloat(m, i)); break;
- case HV_MSG_SYMBOL: hv_snprintf(finalString+pos, len[i], "%s", msg_getSymbol(m, i)); break;
- case HV_MSG_HASH: hv_snprintf(finalString+pos, len[i], "0x%X", msg_getHash(m, i)); break;
- default: break;
- }
- pos += len[i];
- finalString[pos-1] = 32; // ASCII space
- }
- finalString[size-1] = '\0'; // ensure that the string is null terminated
- return finalString;
-}
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvMessage.h b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvMessage.h
deleted file mode 100644
index a3fdd1c9e6..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvMessage.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _HEAVY_MESSAGE_H_
-#define _HEAVY_MESSAGE_H_
-
-#include "HvUtils.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum ElementType {
- HV_MSG_BANG = 0,
- HV_MSG_FLOAT = 1,
- HV_MSG_SYMBOL = 2,
- HV_MSG_HASH = 3
-} ElementType;
-
-typedef struct Element {
- ElementType type;
- union {
- float f; // float
- const char *s; // symbol
- hv_uint32_t h; // hash
- } data;
-} Element;
-
-typedef struct HvMessage {
- hv_uint32_t timestamp; // the sample at which this message should be processed
- hv_uint16_t numElements;
- hv_uint16_t numBytes; // the total number of bytes that this message occupies in memory, including strings
- Element elem;
-} HvMessage;
-
-typedef struct ReceiverMessagePair {
- hv_uint32_t receiverHash;
- HvMessage msg;
-} ReceiverMessagePair;
-
-#define HV_MESSAGE_ON_STACK(_x) (HvMessage *) hv_alloca(msg_getCoreSize(_x))
-
-/** Returns the number of bytes that this message consumes in memory, not including strings. */
-static inline hv_size_t msg_getCoreSize(hv_size_t numElements) {
- hv_assert(numElements > 0);
- return sizeof(HvMessage) + ((numElements-1) * sizeof(Element));
-}
-
-HvMessage *msg_copy(const HvMessage *m);
-
-/** Copies the message into the given buffer. The buffer must be at least as large as msg_getNumHeapBytes(). */
-void msg_copyToBuffer(const HvMessage *m, char *buffer, hv_size_t len);
-
-void msg_setElementToFrom(HvMessage *n, int indexN, const HvMessage *const m, int indexM);
-
-/** Frees a message on the heap. Does nothing if argument is NULL. */
-void msg_free(HvMessage *m);
-
-HvMessage *msg_init(HvMessage *m, hv_size_t numElements, hv_uint32_t timestamp);
-
-HvMessage *msg_initWithFloat(HvMessage *m, hv_uint32_t timestamp, float f);
-
-HvMessage *msg_initWithBang(HvMessage *m, hv_uint32_t timestamp);
-
-HvMessage *msg_initWithSymbol(HvMessage *m, hv_uint32_t timestamp, const char *s);
-
-HvMessage *msg_initWithHash(HvMessage *m, hv_uint32_t timestamp, hv_uint32_t h);
-
-static inline hv_uint32_t msg_getTimestamp(const HvMessage *m) {
- return m->timestamp;
-}
-
-static inline void msg_setTimestamp(HvMessage *m, hv_uint32_t timestamp) {
- m->timestamp = timestamp;
-}
-
-static inline int msg_getNumElements(const HvMessage *m) {
- return (int) m->numElements;
-}
-
-/** Returns the total number of bytes this message consumes in memory. */
-static inline hv_uint32_t msg_getSize(const HvMessage *m) {
- return m->numBytes;
-}
-
-static inline ElementType msg_getType(const HvMessage *m, int index) {
- hv_assert(index < msg_getNumElements(m)); // invalid index
- return (&(m->elem)+index)->type;
-}
-
-static inline void msg_setBang(HvMessage *m, int index) {
- hv_assert(index < msg_getNumElements(m)); // invalid index
- (&(m->elem)+index)->type = HV_MSG_BANG;
- (&(m->elem)+index)->data.s = NULL;
-}
-
-static inline bool msg_isBang(const HvMessage *m, int index) {
- return (index < msg_getNumElements(m)) ? (msg_getType(m,index) == HV_MSG_BANG) : false;
-}
-
-static inline void msg_setFloat(HvMessage *m, int index, float f) {
- hv_assert(index < msg_getNumElements(m)); // invalid index
- (&(m->elem)+index)->type = HV_MSG_FLOAT;
- (&(m->elem)+index)->data.f = f;
-}
-
-static inline float msg_getFloat(const HvMessage *const m, int index) {
- hv_assert(index < msg_getNumElements(m)); // invalid index
- return (&(m->elem)+index)->data.f;
-}
-
-static inline bool msg_isFloat(const HvMessage *const m, int index) {
- return (index < msg_getNumElements(m)) ? (msg_getType(m,index) == HV_MSG_FLOAT) : false;
-}
-
-static inline void msg_setHash(HvMessage *m, int index, hv_uint32_t h) {
- hv_assert(index < msg_getNumElements(m)); // invalid index
- (&(m->elem)+index)->type = HV_MSG_HASH;
- (&(m->elem)+index)->data.h = h;
-}
-
-static inline bool msg_isHash(const HvMessage *m, int index) {
- return (index < msg_getNumElements(m)) ? (msg_getType(m, index) == HV_MSG_HASH) : false;
-}
-
-/** Returns true if the element is a hash or symbol. False otherwise. */
-static inline bool msg_isHashLike(const HvMessage *m, int index) {
- return (index < msg_getNumElements(m)) ? ((msg_getType(m, index) == HV_MSG_HASH) || (msg_getType(m, index) == HV_MSG_SYMBOL)) : false;
-}
-
-/** Returns a 32-bit hash of the given element. */
-hv_uint32_t msg_getHash(const HvMessage *const m, int i);
-
-static inline void msg_setSymbol(HvMessage *m, int index, const char *s) {
- hv_assert(index < msg_getNumElements(m)); // invalid index
- hv_assert(s != NULL);
- (&(m->elem)+index)->type = HV_MSG_SYMBOL;
- (&(m->elem)+index)->data.s = s;
- // NOTE(mhroth): if the same message container is reused and string reset,
- // then the message size will be overcounted
- m->numBytes += (hv_uint16_t) (hv_strlen(s) + 1); // also count '\0'
-}
-
-static inline const char *msg_getSymbol(const HvMessage *m, int index) {
- hv_assert(index < msg_getNumElements(m)); // invalid index
- return (&(m->elem)+index)->data.s;
-}
-
-static inline bool msg_isSymbol(const HvMessage *m, int index) {
- return (index < msg_getNumElements(m)) ? (msg_getType(m, index) == HV_MSG_SYMBOL) : false;
-}
-
-bool msg_compareSymbol(const HvMessage *m, int i, const char *s);
-
-/** Returns 1 if the element i_m of message m is equal to element i_n of message n. */
-bool msg_equalsElement(const HvMessage *m, int i_m, const HvMessage *n, int i_n);
-
-bool msg_hasFormat(const HvMessage *m, const char *fmt);
-
-/**
- * Create a string representation of the message. Suitable for use by the print object.
- * The resulting string must be freed by the caller.
- */
-char *msg_toString(const HvMessage *msg);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _HEAVY_MESSAGE_H_
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvMessagePool.c b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvMessagePool.c
deleted file mode 100644
index dbddb1d1dc..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvMessagePool.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "HvMessagePool.h"
-#include "HvMessage.h"
-
-// the number of bytes reserved at a time from the pool
-#define MP_BLOCK_SIZE_BYTES 512
-
-#if HV_APPLE
-#pragma mark - MessageList
-#endif
-
-typedef struct MessageListNode {
- char *p;
- struct MessageListNode *next;
-} MessageListNode;
-
-static inline bool ml_hasAvailable(HvMessagePoolList *ml) {
- return (ml->head != NULL);
-}
-
-static char *ml_pop(HvMessagePoolList *ml) {
- MessageListNode *n = ml->head;
- ml->head = n->next;
- n->next = ml->pool;
- ml->pool = n;
- char *const p = n->p;
- n->p = NULL; // set to NULL to make it clear that this node does not have a valid buffer
- return p;
-}
-
-/** Push a MessageListNode with the given pointer onto the head of the queue. */
-static void ml_push(HvMessagePoolList *ml, void *p) {
- MessageListNode *n = NULL;
- if (ml->pool != NULL) {
- // take an empty MessageListNode from the pool
- n = ml->pool;
- ml->pool = n->next;
- } else {
- // a MessageListNode is not available, allocate one
- n = (MessageListNode *) hv_malloc(sizeof(MessageListNode));
- hv_assert(n != NULL);
- }
- n->p = (char *) p;
- n->next = ml->head;
- ml->head = n; // push to the front of the queue
-}
-
-static void ml_free(HvMessagePoolList *ml) {
- if (ml != NULL) {
- while (ml_hasAvailable(ml)) {
- ml_pop(ml);
- }
- while (ml->pool != NULL) {
- MessageListNode *n = ml->pool;
- ml->pool = n->next;
- hv_free(n);
- }
- }
-}
-
-#if HV_APPLE
-#pragma mark - HvMessagePool
-#endif
-
-static hv_size_t mp_messagelistIndexForSize(hv_size_t byteSize) {
- return (hv_size_t) hv_max_i((hv_min_max_log2((hv_uint32_t) byteSize) - 5), 0);
-}
-
-hv_size_t mp_init(HvMessagePool *mp, hv_size_t numKB) {
- mp->bufferSize = numKB * 1024;
- mp->buffer = (char *) hv_malloc(mp->bufferSize);
- hv_assert(mp->buffer != NULL);
- mp->bufferIndex = 0;
-
- // initialise all message lists
- for (int i = 0; i < MP_NUM_MESSAGE_LISTS; i++) {
- mp->lists[i].head = NULL;
- mp->lists[i].pool = NULL;
- }
-
- return mp->bufferSize;
-}
-
-void mp_free(HvMessagePool *mp) {
- hv_free(mp->buffer);
- for (int i = 0; i < MP_NUM_MESSAGE_LISTS; i++) {
- ml_free(&mp->lists[i]);
- }
-}
-
-void mp_freeMessage(HvMessagePool *mp, HvMessage *m) {
- const hv_size_t b = msg_getSize(m); // the number of bytes that a message occupies in memory
- const hv_size_t i = mp_messagelistIndexForSize(b); // the HvMessagePoolList index in the pool
- HvMessagePoolList *ml = &mp->lists[i];
- const hv_size_t chunkSize = 32 << i;
- hv_memclear(m, chunkSize); // clear the chunk, just in case
- ml_push(ml, m);
-}
-
-HvMessage *mp_addMessage(HvMessagePool *mp, const HvMessage *m) {
- const hv_size_t b = msg_getSize(m);
- // determine the message list index to allocate data from based on the msg size
- // smallest chunk size is 32 bytes
- const hv_size_t i = mp_messagelistIndexForSize(b);
-
- hv_assert(i < MP_NUM_MESSAGE_LISTS); // how many chunk sizes do we want to support? 32, 64, 128, 256 at the moment
- HvMessagePoolList *ml = &mp->lists[i];
- const hv_size_t chunkSize = 32 << i;
-
- if (ml_hasAvailable(ml)) {
- char *buf = ml_pop(ml);
- msg_copyToBuffer(m, buf, chunkSize);
- return (HvMessage *) buf;
- } else {
- // if no appropriately sized buffer is immediately available, increase the size of the used buffer
- const hv_size_t newIndex = mp->bufferIndex + MP_BLOCK_SIZE_BYTES;
- hv_assert((newIndex <= mp->bufferSize) &&
- "The message pool buffer size has been exceeded. The context cannot store more messages. "
- "Try using the new_with_options() initialiser with a larger pool size (default is 10KB).");
-
- for (hv_size_t j = mp->bufferIndex; j < newIndex; j += chunkSize) {
- ml_push(ml, mp->buffer + j); // push new nodes onto the list with chunk pointers
- }
- mp->bufferIndex = newIndex;
- char *buf = ml_pop(ml);
- msg_copyToBuffer(m, buf, chunkSize);
- return (HvMessage *) buf;
- }
-}
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvMessagePool.h b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvMessagePool.h
deleted file mode 100644
index 693e470e12..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvMessagePool.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _MESSAGE_POOL_H_
-#define _MESSAGE_POOL_H_
-
-#include "HvUtils.h"
-
-#ifdef HV_MP_NUM_MESSAGE_LISTS
-#define MP_NUM_MESSAGE_LISTS HV_MP_NUM_MESSAGE_LISTS
-#else // HV_MP_NUM_MESSAGE_LISTS
-#define MP_NUM_MESSAGE_LISTS 4
-#endif // HV_MP_NUM_MESSAGE_LISTS
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct HvMessagePoolList {
- struct MessageListNode *head; // list of currently available blocks
- struct MessageListNode *pool; // list of currently used blocks
-} HvMessagePoolList;
-
-typedef struct HvMessagePool {
- char *buffer; // the buffer of all messages
- hv_size_t bufferSize; // in bytes
- hv_size_t bufferIndex; // the number of total reserved bytes
-
- HvMessagePoolList lists[MP_NUM_MESSAGE_LISTS];
-} HvMessagePool;
-
-/**
- * The HvMessagePool is a basic memory management system. It reserves a large block of memory at initialisation
- * and proceeds to divide this block into smaller chunks (usually 512 bytes) as they are needed. These chunks are
- * further divided into 32, 64, 128, or 256 sections. Each of these sections is managed by a HvMessagePoolList (MPL).
- * An MPL is a linked-list data structure which is initialised such that its own pool of listnodes is filled with nodes
- * that point at each subblock (e.g. each 32-byte block of a 512-block chunk).
- *
- * HvMessagePool is loosely inspired by TCMalloc. http://goog-perftools.sourceforge.net/doc/tcmalloc.html
- */
-
-hv_size_t mp_init(struct HvMessagePool *mp, hv_size_t numKB);
-
-void mp_free(struct HvMessagePool *mp);
-
-/**
- * Adds a message to the pool and returns a pointer to the copy. Returns NULL
- * if no space was available in the pool.
- */
-struct HvMessage *mp_addMessage(struct HvMessagePool *mp, const struct HvMessage *m);
-
-void mp_freeMessage(struct HvMessagePool *mp, struct HvMessage *m);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _MESSAGE_POOL_H_
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvMessageQueue.c b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvMessageQueue.c
deleted file mode 100644
index 2eeab8ff8a..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvMessageQueue.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "HvMessageQueue.h"
-
-hv_size_t mq_initWithPoolSize(HvMessageQueue *q, hv_size_t poolSizeKB) {
- hv_assert(poolSizeKB > 0);
- q->head = NULL;
- q->tail = NULL;
- q->pool = NULL;
- return mp_init(&q->mp, poolSizeKB);
-}
-
-void mq_free(HvMessageQueue *q) {
- mq_clear(q);
- while (q->pool != NULL) {
- MessageNode *n = q->pool;
- q->pool = q->pool->next;
- hv_free(n);
- }
- mp_free(&q->mp);
-}
-
-static MessageNode *mq_getOrCreateNodeFromPool(HvMessageQueue *q) {
- if (q->pool == NULL) {
- // if necessary, create a new empty node
- q->pool = (MessageNode *) hv_malloc(sizeof(MessageNode));
- hv_assert(q->pool != NULL);
- q->pool->next = NULL;
- }
- MessageNode *node = q->pool;
- q->pool = q->pool->next;
- return node;
-}
-
-int mq_size(HvMessageQueue *q) {
- int size = 0;
- MessageNode *n = q->head;
- while (n != NULL) {
- ++size;
- n = n->next;
- }
- return size;
-}
-
-HvMessage *mq_addMessage(HvMessageQueue *q, const HvMessage *m, int let,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
- MessageNode *node = mq_getOrCreateNodeFromPool(q);
- node->m = mp_addMessage(&q->mp, m);
- node->let = let;
- node->sendMessage = sendMessage;
- node->prev = NULL;
- node->next = NULL;
-
- if (q->tail != NULL) {
- // the list already contains elements
- q->tail->next = node;
- node->prev = q->tail;
- q->tail = node;
- } else {
- // the list is empty
- node->prev = NULL;
- q->head = node;
- q->tail = node;
- }
- return mq_node_getMessage(node);
-}
-
-HvMessage *mq_addMessageByTimestamp(HvMessageQueue *q, const HvMessage *m, int let,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
- if (mq_hasMessage(q)) {
- MessageNode *n = mq_getOrCreateNodeFromPool(q);
- n->m = mp_addMessage(&q->mp, m);
- n->let = let;
- n->sendMessage = sendMessage;
-
- if (msg_getTimestamp(m) < msg_getTimestamp(q->head->m)) {
- // the message occurs before the current head
- n->next = q->head;
- q->head->prev = n;
- n->prev = NULL;
- q->head = n;
- } else if (msg_getTimestamp(m) >= msg_getTimestamp(q->tail->m)) {
- // the message occurs after the current tail
- n->next = NULL;
- n->prev = q->tail;
- q->tail->next = n;
- q->tail = n;
- } else {
- // the message occurs somewhere between the head and tail
- MessageNode *node = q->head;
- while (node != NULL) {
- if (msg_getTimestamp(m) < msg_getTimestamp(node->next->m)) {
- MessageNode *r = node->next;
- node->next = n;
- n->next = r;
- n->prev = node;
- r->prev = n;
- break;
- }
- node = node->next;
- }
- }
- return n->m;
- } else {
- // add a message to the head
- return mq_addMessage(q, m, let, sendMessage);
- }
-}
-
-void mq_pop(HvMessageQueue *q) {
- if (mq_hasMessage(q)) {
- MessageNode *n = q->head;
-
- mp_freeMessage(&q->mp, n->m);
- n->m = NULL;
-
- n->let = 0;
- n->sendMessage = NULL;
-
- q->head = n->next;
- if (q->head == NULL) {
- q->tail = NULL;
- } else {
- q->head->prev = NULL;
- }
- n->next = q->pool;
- n->prev = NULL;
- q->pool = n;
- }
-}
-
-bool mq_removeMessage(HvMessageQueue *q, HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
- if (mq_hasMessage(q)) {
- if (mq_node_getMessage(q->head) == m) { // msg in head node
- // only remove the message if sendMessage is the same as the stored one,
- // if the sendMessage argument is NULL, it is not checked and will remove any matching message pointer
- if (sendMessage == NULL || q->head->sendMessage == sendMessage) {
- mq_pop(q);
- return true;
- }
- } else {
- MessageNode *prevNode = q->head;
- MessageNode *currNode = q->head->next;
- while ((currNode != NULL) && (currNode->m != m)) {
- prevNode = currNode;
- currNode = currNode->next;
- }
- if (currNode != NULL) {
- if (sendMessage == NULL || currNode->sendMessage == sendMessage) {
- mp_freeMessage(&q->mp, m);
- currNode->m = NULL;
- currNode->let = 0;
- currNode->sendMessage = NULL;
- if (currNode == q->tail) { // msg in tail node
- prevNode->next = NULL;
- q->tail = prevNode;
- } else { // msg in middle node
- prevNode->next = currNode->next;
- currNode->next->prev = prevNode;
- }
- currNode->next = (q->pool == NULL) ? NULL : q->pool;
- currNode->prev = NULL;
- q->pool = currNode;
- return true;
- }
- }
- }
- }
- return false;
-}
-
-void mq_clear(HvMessageQueue *q) {
- while (mq_hasMessage(q)) {
- mq_pop(q);
- }
-}
-
-void mq_clearAfter(HvMessageQueue *q, const hv_uint32_t timestamp) {
- MessageNode *n = q->tail;
- while (n != NULL && timestamp <= msg_getTimestamp(n->m)) {
- // free the node's message
- mp_freeMessage(&q->mp, n->m);
- n->m = NULL;
- n->let = 0;
- n->sendMessage = NULL;
-
- // the tail points at the previous node
- q->tail = n->prev;
-
- // put the node back in the pool
- n->next = q->pool;
- n->prev = NULL;
- if (q->pool != NULL) q->pool->prev = n;
- q->pool = n;
-
- // update the tail node
- n = q->tail;
- }
-
- if (q->tail == NULL) q->head = NULL;
-}
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvMessageQueue.h b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvMessageQueue.h
deleted file mode 100644
index a35e4aa579..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvMessageQueue.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _MESSAGE_QUEUE_H_
-#define _MESSAGE_QUEUE_H_
-
-#include "HvMessage.h"
-#include "HvMessagePool.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-class HeavyContextInterface;
-#else
-typedef struct HeavyContextInterface HeavyContextInterface;
-#endif
-
-typedef struct MessageNode {
- struct MessageNode *prev; // doubly linked list
- struct MessageNode *next;
- HvMessage *m;
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *);
- int let;
-} MessageNode;
-
-/** A doubly linked list containing scheduled messages. */
-typedef struct HvMessageQueue {
- MessageNode *head; // the head of the queue
- MessageNode *tail; // the tail of the queue
- MessageNode *pool; // the head of the reserve pool
- HvMessagePool mp;
-} HvMessageQueue;
-
-hv_size_t mq_initWithPoolSize(HvMessageQueue *q, hv_size_t poolSizeKB);
-
-void mq_free(HvMessageQueue *q);
-
-int mq_size(HvMessageQueue *q);
-
-static inline HvMessage *mq_node_getMessage(MessageNode *n) {
- return n->m;
-}
-
-static inline int mq_node_getLet(MessageNode *n) {
- return n->let;
-}
-
-static inline bool mq_hasMessage(HvMessageQueue *q) {
- return (q->head != NULL);
-}
-
-// true if there is a message and it occurs before (<) timestamp
-static inline bool mq_hasMessageBefore(HvMessageQueue *const q, const hv_uint32_t timestamp) {
- return mq_hasMessage(q) && (msg_getTimestamp(mq_node_getMessage(q->head)) < timestamp);
-}
-
-static inline MessageNode *mq_peek(HvMessageQueue *q) {
- return q->head;
-}
-
-/** Appends the message to the end of the queue. */
-HvMessage *mq_addMessage(HvMessageQueue *q, const HvMessage *m, int let,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
-
-/** Insert in ascending order the message acccording to its timestamp. */
-HvMessage *mq_addMessageByTimestamp(HvMessageQueue *q, const HvMessage *m, int let,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
-
-/** Pop the message at the head of the queue (and free its memory). */
-void mq_pop(HvMessageQueue *q);
-
-/** Remove a message from the queue (and free its memory) */
-bool mq_removeMessage(HvMessageQueue *q, HvMessage *m,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
-
-/** Clears (and frees) all messages in the queue. */
-void mq_clear(HvMessageQueue *q);
-
-/** Removes all messages occuring at or after the given timestamp. */
-void mq_clearAfter(HvMessageQueue *q, const hv_uint32_t timestamp);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _MESSAGE_QUEUE_H_
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvTable.c b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvTable.c
deleted file mode 100644
index 1b2cd38315..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvTable.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "HvTable.h"
-#include "HvMessage.h"
-
-hv_size_t hTable_init(HvTable *o, int length) {
- o->length = length;
- // true size of the table is always an integer multple of HV_N_SIMD
- o->size = (length + HV_N_SIMD_MASK) & ~HV_N_SIMD_MASK;
- // add an extra length for mirroring
- o->allocated = o->size + HV_N_SIMD;
- o->head = 0;
- hv_size_t numBytes = o->allocated * sizeof(float);
- o->buffer = (float *) hv_malloc(numBytes);
- hv_assert(o->buffer != NULL);
- hv_memclear(o->buffer, numBytes);
- return numBytes;
-}
-
-hv_size_t hTable_initWithData(HvTable *o, int length, const float *data) {
- o->length = length;
- o->size = (length + HV_N_SIMD_MASK) & ~HV_N_SIMD_MASK;
- o->allocated = o->size + HV_N_SIMD;
- o->head = 0;
- hv_size_t numBytes = o->size * sizeof(float);
- o->buffer = (float *) hv_malloc(numBytes);
- hv_assert(o->buffer != NULL);
- hv_memclear(o->buffer, numBytes);
- hv_memcpy(o->buffer, data, length*sizeof(float));
- return numBytes;
-}
-
-hv_size_t hTable_initWithFinalData(HvTable *o, int length, float *data) {
- o->length = length;
- o->size = length;
- o->allocated = length;
- o->buffer = data;
- o->head = 0;
- return 0;
-}
-
-void hTable_free(HvTable *o) {
- hv_free(o->buffer);
-}
-
-int hTable_resize(HvTable *o, hv_uint32_t newLength) {
- // TODO(mhroth): update context with memory allocated by table
- // NOTE(mhroth): mirrored bytes are not necessarily carried over
- const hv_uint32_t newSize = (newLength + HV_N_SIMD_MASK) & ~HV_N_SIMD_MASK;
- if (newSize == o->size) return 0; // early exit if no change in size
- const hv_uint32_t oldSizeBytes = (hv_uint32_t) (o->size * sizeof(float));
- const hv_uint32_t newAllocated = newSize + HV_N_SIMD;
- const hv_uint32_t newAllocatedBytes = (hv_uint32_t) (newAllocated * sizeof(float));
-
- float *b = (float *) hv_realloc(o->buffer, newAllocatedBytes);
- hv_assert(b != NULL); // error while reallocing!
- // ensure that hv_realloc has given us a correctly aligned buffer
- if ((((hv_uintptr_t) (const void *) b) & ((0x1< o->size) {
- hv_memclear(b + o->size, (newAllocated - o->size) * sizeof(float)); // clear new parts of the buffer
- }
- o->buffer = b;
- } else {
- // if not, we have to re-malloc ourselves
- char *c = (char *) hv_malloc(newAllocatedBytes);
- hv_assert(c != NULL); // error while allocating new buffer!
- if (newAllocatedBytes > oldSizeBytes) {
- hv_memcpy(c, b, oldSizeBytes);
- hv_memclear(c + oldSizeBytes, newAllocatedBytes - oldSizeBytes);
- } else {
- hv_memcpy(c, b, newAllocatedBytes);
- }
- hv_free(b);
- o->buffer = (float *) c;
- }
- o->length = newLength;
- o->size = newSize;
- o->allocated = newAllocated;
- return (int) (newAllocated - oldSizeBytes - (HV_N_SIMD*sizeof(float)));
-}
-
-void hTable_onMessage(HeavyContextInterface *_c, HvTable *o, int letIn, const HvMessage *m,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
- if (msg_compareSymbol(m,0,"resize") && msg_isFloat(m,1) && msg_getFloat(m,1) >= 0.0f) {
- hTable_resize(o, (int) hv_ceil_f(msg_getFloat(m,1))); // apply ceil to ensure that tables always have enough space
-
- // send out the new size of the table
- HvMessage *n = HV_MESSAGE_ON_STACK(1);
- msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getSize(o));
- sendMessage(_c, 0, n);
- }
-
- else if (msg_compareSymbol(m,0,"mirror")) {
- hv_memcpy(o->buffer+o->size, o->buffer, HV_N_SIMD*sizeof(float));
- }
-}
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvTable.h b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvTable.h
deleted file mode 100644
index 1d748874ea..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvTable.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _HEAVY_TABLE_H_
-#define _HEAVY_TABLE_H_
-
-#include "HvHeavy.h"
-#include "HvUtils.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct HvTable {
- float *buffer;
- // the number of values that the table is requested to have
- hv_uint32_t length;
-
- // the number of usable values that the table actually has
- // this is always an even multiple of HV_N_SIMD
- hv_uint32_t size;
-
- // Note that the true size of the table is (size + HV_N_SIMD),
- // with the trailing values used by the system, e.g. to create a circular
- // buffer
- hv_uint32_t allocated;
-
- hv_uint32_t head; // the most recently written point
-} HvTable;
-
-hv_size_t hTable_init(HvTable *o, int length);
-
-hv_size_t hTable_initWithData(HvTable *o, int length, const float *data);
-
-hv_size_t hTable_initWithFinalData(HvTable *o, int length, float *data);
-
-void hTable_free(HvTable *o);
-
-int hTable_resize(HvTable *o, hv_uint32_t newLength);
-
-void hTable_onMessage(HeavyContextInterface *_c, HvTable *o, int letIn, const HvMessage *m,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
-
-static inline float *hTable_getBuffer(HvTable *o) {
- return o->buffer;
-}
-
-// the user-requested length of the table (number of floats)
-static inline hv_uint32_t hTable_getLength(HvTable *o) {
- return o->length;
-}
-
-// the usable length of the table (an even multiple of HV_N_SIMD)
-static inline hv_uint32_t hTable_getSize(HvTable *o) {
- return o->size;
-}
-
-// the number of floats allocated to this table (usually size + HV_N_SIMD)
-static inline hv_uint32_t hTable_getAllocated(HvTable *o) {
- return o->allocated;
-}
-
-static inline hv_uint32_t hTable_getHead(HvTable *o) {
- return o->head;
-}
-
-static inline void hTable_setHead(HvTable *o, hv_uint32_t head) {
- o->head = head;
-}
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // _HEAVY_TABLE_H_
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvUtils.c b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvUtils.c
deleted file mode 100644
index 2fdf682c4c..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvUtils.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "HvUtils.h"
-
-hv_uint32_t hv_string_to_hash(const char *str) {
- // this hash is based MurmurHash2
- // http://en.wikipedia.org/wiki/MurmurHash
- // https://sites.google.com/site/murmurhash/
- static const hv_uint32_t n = 0x5bd1e995;
- static const hv_int32_t r = 24;
-
- if (str == NULL) return 0;
-
- hv_uint32_t len = (hv_uint32_t) hv_strlen(str);
- hv_uint32_t x = len; // seed (0) ^ len
-
- while (len >= 4) {
-#if HV_EMSCRIPTEN
- hv_uint32_t k = str[0] | (str[1] << 8) | (str[2] << 16) | (str[3] << 24);
-#else
- hv_uint32_t k = *((hv_uint32_t *) str);
-#endif
- k *= n;
- k ^= (k >> r);
- k *= n;
- x *= n;
- x ^= k;
- str += 4; len -= 4;
- }
- switch (len) {
- case 3: x ^= (str[2] << 16);
- case 2: x ^= (str[1] << 8);
- case 1: x ^= str[0]; x *= n;
- default: break;
- }
- x ^= (x >> 13);
- x *= n;
- x ^= (x >> 15);
- return x;
-}
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvUtils.h b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvUtils.h
deleted file mode 100644
index 2186f547c0..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/HvUtils.h
+++ /dev/null
@@ -1,319 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _HEAVY_UTILS_H_
-#define _HEAVY_UTILS_H_
-
-// platform definitions
-#if _WIN32 || _WIN64 || _MSC_VER
- #define HV_WIN 1
-#elif __APPLE__
- #define HV_APPLE 1
-#elif __ANDROID__
- #define HV_ANDROID 1
-#elif __unix__ || __unix
- #define HV_UNIX 1
-#else
- #warning Could not detect platform. Assuming Unix-like.
-#endif
-
-#ifdef EMSCRIPTEN
-#define HV_EMSCRIPTEN 1
-#endif
-
-// basic includes
-#include
-#include
-#include
-
-// type definitions
-#include
-#include
-#define hv_uint8_t uint8_t
-#define hv_int16_t int16_t
-#define hv_uint16_t uint16_t
-#define hv_int32_t int32_t
-#define hv_uint32_t uint32_t
-#define hv_uint64_t uint64_t
-#define hv_size_t size_t
-#define hv_uintptr_t uintptr_t
-
-// SIMD-specific includes
-#if !(HV_SIMD_NONE || HV_SIMD_NEON || HV_SIMD_SSE || HV_SIMD_AVX)
- #define HV_SIMD_NEON __ARM_NEON__
- #define HV_SIMD_SSE (__SSE__ && __SSE2__ && __SSE3__ && __SSSE3__ && __SSE4_1__)
- #define HV_SIMD_AVX (__AVX__ && HV_SIMD_SSE)
-#endif
-#ifndef HV_SIMD_FMA
- #define HV_SIMD_FMA __FMA__
-#endif
-
-#if HV_SIMD_AVX || HV_SIMD_SSE
- #include
-#elif HV_SIMD_NEON
- #include
-#endif
-
-#if HV_SIMD_NEON // NEON
- #define HV_N_SIMD 4
- #define hv_bufferf_t float32x4_t
- #define hv_bufferi_t int32x4_t
- #define hv_bInf_t float32x4_t
- #define hv_bOutf_t float32x4_t*
- #define hv_bIni_t int32x4_t
- #define hv_bOuti_t int32x4_t*
- #define VIf(_x) (_x)
- #define VOf(_x) (&_x)
- #define VIi(_x) (_x)
- #define VOi(_x) (&_x)
-#elif HV_SIMD_AVX // AVX
- #define HV_N_SIMD 8
- #define hv_bufferf_t __m256
- #define hv_bufferi_t __m256i
- #define hv_bInf_t __m256
- #define hv_bOutf_t __m256*
- #define hv_bIni_t __m256i
- #define hv_bOuti_t __m256i*
- #define VIf(_x) (_x)
- #define VOf(_x) (&_x)
- #define VIi(_x) (_x)
- #define VOi(_x) (&_x)
-#elif HV_SIMD_SSE // SSE
- #define HV_N_SIMD 4
- #define hv_bufferf_t __m128
- #define hv_bufferi_t __m128i
- #define hv_bInf_t __m128
- #define hv_bOutf_t __m128*
- #define hv_bIni_t __m128i
- #define hv_bOuti_t __m128i*
- #define VIf(_x) (_x)
- #define VOf(_x) (&_x)
- #define VIi(_x) (_x)
- #define VOi(_x) (&_x)
-#else // DEFAULT
- #define HV_N_SIMD 1
- #undef HV_SIMD_NONE
- #define HV_SIMD_NONE 1
- #define hv_bufferf_t float
- #define hv_bufferi_t int
- #define hv_bInf_t float
- #define hv_bOutf_t float*
- #define hv_bIni_t int
- #define hv_bOuti_t int*
- #define VIf(_x) (_x)
- #define VOf(_x) (&_x)
- #define VIi(_x) (_x)
- #define VOi(_x) (&_x)
-#endif
-
-#define HV_N_SIMD_MASK (HV_N_SIMD-1)
-
-// Strings
-#include
-#define hv_strlen(a) strlen(a)
-#define hv_strcmp(a, b) strcmp(a, b)
-#define hv_snprintf(a, b, c, ...) snprintf(a, b, c, __VA_ARGS__)
-#if HV_WIN
-#define hv_strncpy(_dst, _src, _len) strncpy_s(_dst, _len, _src, _TRUNCATE)
-#else
-#define hv_strncpy(_dst, _src, _len) strncpy(_dst, _src, _len)
-#endif
-
-// Memory management
-#define hv_memcpy(a, b, c) memcpy(a, b, c)
-#define hv_memclear(a, b) memset(a, 0, b)
-#if HV_WIN
- #include
- #define hv_alloca(_n) _alloca(_n)
- #if HV_SIMD_AVX
- #define hv_malloc(_n) _aligned_malloc(_n, 32)
- #define hv_realloc(a, b) _aligned_realloc(a, b, 32)
- #define hv_free(x) _aligned_free(x)
- #elif HV_SIMD_SSE || HV_SIMD_NEON
- #define hv_malloc(_n) _aligned_malloc(_n, 16)
- #define hv_realloc(a, b) _aligned_realloc(a, b, 16)
- #define hv_free(x) _aligned_free(x)
- #else // HV_SIMD_NONE
- #define hv_malloc(_n) malloc(_n)
- #define hv_realloc(a, b) realloc(a, b)
- #define hv_free(_n) free(_n)
- #endif
-#elif HV_APPLE
- #define hv_alloca(_n) alloca(_n)
- #define hv_realloc(a, b) realloc(a, b)
- #if HV_SIMD_AVX
- #include
- #define hv_malloc(_n) _mm_malloc(_n, 32)
- #define hv_free(x) _mm_free(x)
- #elif HV_SIMD_SSE
- #include
- #define hv_malloc(_n) _mm_malloc(_n, 16)
- #define hv_free(x) _mm_free(x)
- #elif HV_SIMD_NEON
- // malloc on ios always has 16-byte alignment
- #define hv_malloc(_n) malloc(_n)
- #define hv_free(x) free(x)
- #else // HV_SIMD_NONE
- #define hv_malloc(_n) malloc(_n)
- #define hv_free(x) free(x)
- #endif
-#else
- #include
- #define hv_alloca(_n) alloca(_n)
- #define hv_realloc(a, b) realloc(a, b)
- #if HV_SIMD_AVX
- #define hv_malloc(_n) aligned_alloc(32, _n)
- #define hv_free(x) free(x)
- #elif HV_SIMD_SSE
- #define hv_malloc(_n) aligned_alloc(16, _n)
- #define hv_free(x) free(x)
- #elif HV_SIMD_NEON
- #if HV_ANDROID
- #define hv_malloc(_n) memalign(16, _n)
- #define hv_free(x) free(x)
- #else
- #define hv_malloc(_n) aligned_alloc(16, _n)
- #define hv_free(x) free(x)
- #endif
- #else // HV_SIMD_NONE
- #define hv_malloc(_n) malloc(_n)
- #define hv_free(_n) free(_n)
- #endif
-#endif
-
-// Assert
-#include
-#define hv_assert(e) assert(e)
-
-// Export and Inline
-#if HV_WIN
-#define HV_EXPORT __declspec(dllexport)
-#ifndef __cplusplus // MSVC doesn't like redefining "inline" keyword
-#define inline __inline
-#endif
-#define HV_FORCE_INLINE __forceinline
-#else
-#define HV_EXPORT
-#define HV_FORCE_INLINE inline __attribute__((always_inline))
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
- // Returns a 32-bit hash of any string. Returns 0 if string is NULL.
- hv_uint32_t hv_string_to_hash(const char *str);
-#ifdef __cplusplus
-}
-#endif
-
-// Math
-#include
-static inline hv_size_t __hv_utils_max_ui(hv_size_t x, hv_size_t y) { return (x > y) ? x : y; }
-static inline hv_size_t __hv_utils_min_ui(hv_size_t x, hv_size_t y) { return (x < y) ? x : y; }
-static inline hv_int32_t __hv_utils_max_i(hv_int32_t x, hv_int32_t y) { return (x > y) ? x : y; }
-static inline hv_int32_t __hv_utils_min_i(hv_int32_t x, hv_int32_t y) { return (x < y) ? x : y; }
-#define hv_max_ui(a, b) __hv_utils_max_ui(a, b)
-#define hv_min_ui(a, b) __hv_utils_min_ui(a, b)
-#define hv_max_i(a, b) __hv_utils_max_i(a, b)
-#define hv_min_i(a, b) __hv_utils_min_i(a, b)
-#define hv_max_f(a, b) fmaxf(a, b)
-#define hv_min_f(a, b) fminf(a, b)
-#define hv_max_d(a, b) fmax(a, b)
-#define hv_min_d(a, b) fmin(a, b)
-#define hv_sin_f(a) sinf(a)
-#define hv_sinh_f(a) sinhf(a)
-#define hv_cos_f(a) cosf(a)
-#define hv_cosh_f(a) coshf(a)
-#define hv_tan_f(a) tanf(a)
-#define hv_tanh_f(a) tanhf(a)
-#define hv_asin_f(a) asinf(a)
-#define hv_asinh_f(a) asinhf(a)
-#define hv_acos_f(a) acosf(a)
-#define hv_acosh_f(a) acoshf(a)
-#define hv_atan_f(a) atanf(a)
-#define hv_atanh_f(a) atanhf(a)
-#define hv_atan2_f(a, b) atan2f(a, b)
-#define hv_exp_f(a) expf(a)
-#define hv_abs_f(a) fabsf(a)
-#define hv_sqrt_f(a) sqrtf(a)
-#define hv_log_f(a) logf(a)
-#define hv_ceil_f(a) ceilf(a)
-#define hv_floor_f(a) floorf(a)
-#define hv_round_f(a) roundf(a)
-#define hv_pow_f(a, b) powf(a, b)
-#if HV_EMSCRIPTEN
-#define hv_fma_f(a, b, c) ((a*b)+c) // emscripten does not support fmaf (yet?)
-#else
-#define hv_fma_f(a, b, c) fmaf(a, b, c)
-#endif
-#if HV_WIN
- // finds ceil(log2(x))
- #include
- static inline hv_uint32_t __hv_utils_min_max_log2(hv_uint32_t x) {
- unsigned long z = 0;
- _BitScanReverse(&z, x);
- return (hv_uint32_t) (z+1);
- }
-#else
- static inline hv_uint32_t __hv_utils_min_max_log2(hv_uint32_t x) {
- return (hv_uint32_t) (32 - __builtin_clz(x-1));
- }
-#endif
-#define hv_min_max_log2(a) __hv_utils_min_max_log2(a)
-
-// Atomics
-#if HV_WIN
- #include
- #define hv_atomic_bool volatile LONG
- #define HV_SPINLOCK_ACQUIRE(_x) while (InterlockedCompareExchange(&_x, true, false)) { }
- #define HV_SPINLOCK_TRY(_x) return !InterlockedCompareExchange(&_x, true, false)
- #define HV_SPINLOCK_RELEASE(_x) (_x = false)
-#elif HV_ANDROID
- // Android support for atomics isn't that great, we'll do it manually
- // https://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html
- #define hv_atomic_bool hv_uint8_t
- #define HV_SPINLOCK_ACQUIRE(_x) while (__sync_lock_test_and_set(&_x, 1))
- #define HV_SPINLOCK_TRY(_x) return !__sync_lock_test_and_set(&_x, 1)
- #define HV_SPINLOCK_RELEASE(_x) __sync_lock_release(&_x)
-#elif __cplusplus
- #include
- #define hv_atomic_bool std::atomic_flag
- #define HV_SPINLOCK_ACQUIRE(_x) while (_x.test_and_set(std::memory_order_acquire))
- #define HV_SPINLOCK_TRY(_x) return !_x.test_and_set(std::memory_order_acquire)
- #define HV_SPINLOCK_RELEASE(_x) _x.clear(std::memory_order_release)
-#elif defined(__has_include)
- #if __has_include()
- #include
- #define hv_atomic_bool atomic_flag
- #define HV_SPINLOCK_ACQUIRE(_x) while (atomic_flag_test_and_set_explicit(&_x, memory_order_acquire))
- #define HV_SPINLOCK_TRY(_x) return !atomic_flag_test_and_set_explicit(&_x, memory_order_acquire)
- #define HV_SPINLOCK_RELEASE(_x) atomic_flag_clear_explicit(memory_order_release)
- #endif
-#endif
-#ifndef hv_atomic_bool
- #define hv_atomic_bool volatile bool
- #define HV_SPINLOCK_ACQUIRE(_x) \
- while (_x) {} \
- _x = true;
- #define HV_SPINLOCK_TRY(_x) \
- if (!_x) { \
- _x = true; \
- return true; \
- } else return false;
- #define HV_SPINLOCK_RELEASE(_x) (_x = false)
-#endif
-
-#endif // _HEAVY_UTILS_H_
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/adc2dac.pd b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/adc2dac.pd
deleted file mode 100644
index 710804d5bc..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/adc2dac.pd
+++ /dev/null
@@ -1,5 +0,0 @@
-#N canvas 0 0 450 300 12;
-#X obj 93 88 adc~;
-#X obj 93 173 dac~;
-#X connect 0 0 1 0;
-#X connect 0 1 1 1;
diff --git a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/streams-generator-pd-audiokit.ino b/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/streams-generator-pd-audiokit.ino
deleted file mode 100644
index fff1ae6d9f..0000000000
--- a/examples/examples-dsp/examples-pd/streams-generator-pd-audiokit/streams-generator-pd-audiokit.ino
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * Test sketch for adc2dac.pd that was compiled with hvcc -n Adc2Dac adc2dac.pd
- * The ADC receives data from the SineWaveGenerator and the output from the
- * DAC is copied to I2S (AudioBoardStream)
- */
-
-#include "AudioTools.h"
-#include "AudioTools/AudioLibs/AudioBoardStream.h"
-#include "Heavy_Adc2Dac.hpp"
-#include "AudioTools/AudioLibs/PureDataStream.h"
-
-AudioInfo info(44100, 2, 16);
-Heavy_Adc2Dac pd_test(info.sample_rate);
-PureDataStream pd(pd_test);
-AudioBoardStream i2s(AudioKitEs8388V1); // final output of decoded stream
-SineWaveGenerator sineWave; // subclass of SoundGenerator with max amplitude of 32000
-GeneratedSoundStream sound(sineWave); // Stream generated from sine wave
-
-StreamCopy copierToPd(pd, sound, 1024);
-StreamCopy copierFromPd(i2s, pd, 1024);
-
-void setup() {
- Serial.begin(115200);
- AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
-
- // setup output
- auto config = i2s.defaultConfig(TX_MODE);
- config.sd_active = false;
- config.copyFrom(info);
- i2s.begin(config);
-
- // setup input
- sineWave.begin(info, N_B4);
-
- // setup pd
- pd.begin();
-
-}
-
-void loop() {
- // provide data to adc
- copierToPd.copy();
- // get data from dac
- copierFromPd.copy();
-}
-
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HeavyContext.cpp b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HeavyContext.cpp
deleted file mode 100644
index 88fa134215..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HeavyContext.cpp
+++ /dev/null
@@ -1,264 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "HeavyContext.hpp"
-#include "HvTable.h"
-
-void defaultSendHook(HeavyContextInterface *context,
- const char *sendName, hv_uint32_t sendHash, const HvMessage *msg) {
- HeavyContext *thisContext = reinterpret_cast(context);
- const hv_uint32_t numBytes = sizeof(ReceiverMessagePair) + msg_getSize(msg) - sizeof(HvMessage);
- ReceiverMessagePair *p = reinterpret_cast(hLp_getWriteBuffer(&thisContext->outQueue, numBytes));
- if (p != nullptr) {
- p->receiverHash = sendHash;
- msg_copyToBuffer(msg, (char *) &p->msg, msg_getSize(msg));
- hLp_produce(&thisContext->outQueue, numBytes);
- } else {
- hv_assert(false &&
- "::defaultSendHook - The out message queue is full and cannot accept more messages until they "
- "have been processed. Try increasing the outQueueKb size in the new_with_options() constructor.");
- }
-}
-
-HeavyContext::HeavyContext(double sampleRate, int poolKb, int inQueueKb, int outQueueKb) :
- sampleRate(sampleRate) {
-
- hv_assert(sampleRate > 0.0); // sample rate must be positive
- hv_assert(poolKb > 0);
- hv_assert(inQueueKb > 0);
- hv_assert(outQueueKb >= 0);
-
- blockStartTimestamp = 0;
- printHook = nullptr;
- userData = nullptr;
-
- // if outQueueKb is positive, then the outQueue is allocated and the default sendhook is set.
- // Otherwise outQueue and the sendhook are set to NULL.
- sendHook = (outQueueKb > 0) ? &defaultSendHook : nullptr;
-
- HV_SPINLOCK_RELEASE(inQueueLock);
- HV_SPINLOCK_RELEASE(outQueueLock);
-
- numBytes = sizeof(HeavyContext);
-
- numBytes += mq_initWithPoolSize(&mq, poolKb);
- numBytes += hLp_init(&inQueue, inQueueKb * 1024);
- numBytes += hLp_init(&outQueue, outQueueKb * 1024); // outQueueKb value of 0 sets everything to NULL
-}
-
-HeavyContext::~HeavyContext() {
- mq_free(&mq);
- hLp_free(&inQueue);
- hLp_free(&outQueue);
-}
-
-bool HeavyContext::sendBangToReceiver(hv_uint32_t receiverHash) {
- HvMessage *m = HV_MESSAGE_ON_STACK(1);
- msg_initWithBang(m, 0);
- bool success = sendMessageToReceiver(receiverHash, 0.0, m);
- return success;
-}
-
-bool HeavyContext::sendFloatToReceiver(hv_uint32_t receiverHash, float f) {
- HvMessage *m = HV_MESSAGE_ON_STACK(1);
- msg_initWithFloat(m, 0, f);
- bool success = sendMessageToReceiver(receiverHash, 0.0, m);
- return success;
-}
-
-bool HeavyContext::sendSymbolToReceiver(hv_uint32_t receiverHash, const char *s) {
- hv_assert(s != nullptr);
- HvMessage *m = HV_MESSAGE_ON_STACK(1);
- msg_initWithSymbol(m, 0, (char *) s);
- bool success = sendMessageToReceiver(receiverHash, 0.0, m);
- return success;
-}
-
-bool HeavyContext::sendMessageToReceiverV(hv_uint32_t receiverHash, double delayMs, const char *format, ...) {
- hv_assert(delayMs >= 0.0);
- hv_assert(format != nullptr);
-
- va_list ap;
- va_start(ap, format);
- const int numElem = (int) hv_strlen(format);
- HvMessage *m = HV_MESSAGE_ON_STACK(numElem);
- msg_init(m, numElem, blockStartTimestamp + (hv_uint32_t) (hv_max_d(0.0, delayMs)*getSampleRate()/1000.0));
- for (int i = 0; i < numElem; i++) {
- switch (format[i]) {
- case 'b': msg_setBang(m, i); break;
- case 'f': msg_setFloat(m, i, (float) va_arg(ap, double)); break;
- case 'h': msg_setHash(m, i, (int) va_arg(ap, int)); break;
- case 's': msg_setSymbol(m, i, (char *) va_arg(ap, char *)); break;
- default: break;
- }
- }
- va_end(ap);
-
- bool success = sendMessageToReceiver(receiverHash, delayMs, m);
- return success;
-}
-
-bool HeavyContext::sendMessageToReceiver(hv_uint32_t receiverHash, double delayMs, HvMessage *m) {
- hv_assert(delayMs >= 0.0);
- hv_assert(m != nullptr);
-
- const hv_uint32_t timestamp = blockStartTimestamp +
- (hv_uint32_t) (hv_max_d(0.0, delayMs)*(getSampleRate()/1000.0));
-
- ReceiverMessagePair *p = nullptr;
- HV_SPINLOCK_ACQUIRE(inQueueLock);
- const hv_uint32_t numBytes = sizeof(ReceiverMessagePair) + msg_getSize(m) - sizeof(HvMessage);
- p = (ReceiverMessagePair *) hLp_getWriteBuffer(&inQueue, numBytes);
- if (p != nullptr) {
- p->receiverHash = receiverHash;
- msg_copyToBuffer(m, (char *) &p->msg, msg_getSize(m));
- msg_setTimestamp(&p->msg, timestamp);
- hLp_produce(&inQueue, numBytes);
- } else {
- hv_assert(false &&
- "::sendMessageToReceiver - The input message queue is full and cannot accept more messages until they "
- "have been processed. Try increasing the inQueueKb size in the new_with_options() constructor.");
- }
- HV_SPINLOCK_RELEASE(inQueueLock);
- return (p != nullptr);
-}
-
-bool HeavyContext::cancelMessage(HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
- return mq_removeMessage(&mq, m, sendMessage);
-}
-
-HvMessage *HeavyContext::scheduleMessageForObject(const HvMessage *m,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
- int letIndex) {
- HvMessage *n = mq_addMessageByTimestamp(&mq, m, letIndex, sendMessage);
- return n;
-}
-
-float *HeavyContext::getBufferForTable(hv_uint32_t tableHash) {
- HvTable *t = getTableForHash(tableHash);
- if (t != nullptr) {
- return hTable_getBuffer(t);
- } else return nullptr;
-}
-
-int HeavyContext::getLengthForTable(hv_uint32_t tableHash) {
- HvTable *t = getTableForHash(tableHash);
- if (t != nullptr) {
- return hTable_getLength(t);
- } else return 0;
-}
-
-bool HeavyContext::setLengthForTable(hv_uint32_t tableHash, hv_uint32_t newSampleLength) {
- HvTable *t = getTableForHash(tableHash);
- if (t != nullptr) {
- hTable_resize(t, newSampleLength);
- return true;
- } else return false;
-}
-
-void HeavyContext::lockAcquire() {
- HV_SPINLOCK_ACQUIRE(inQueueLock);
-}
-
-bool HeavyContext::lockTry() {
- HV_SPINLOCK_TRY(inQueueLock);
-}
-
-void HeavyContext::lockRelease() {
- HV_SPINLOCK_RELEASE(inQueueLock);
-}
-
-void HeavyContext::setInputMessageQueueSize(int inQueueKb) {
- hv_assert(inQueueKb > 0);
- hLp_free(&inQueue);
- hLp_init(&inQueue, inQueueKb*1024);
-}
-
-void HeavyContext::setOutputMessageQueueSize(int outQueueKb) {
- hv_assert(outQueueKb > 0);
- hLp_free(&outQueue);
- hLp_init(&outQueue, outQueueKb*1024);
-}
-
-bool HeavyContext::getNextSentMessage(hv_uint32_t *destinationHash, HvMessage *outMsg, hv_size_t msgLengthBytes) {
- *destinationHash = 0;
- ReceiverMessagePair *p = nullptr;
- hv_assert((sendHook == &defaultSendHook) &&
- "::getNextSentMessage - this function won't do anything if the msg outQueue "
- "size is 0, or you've overriden the default sendhook.");
- if (sendHook == &defaultSendHook) {
- HV_SPINLOCK_ACQUIRE(outQueueLock);
- if (hLp_hasData(&outQueue)) {
- hv_uint32_t numBytes = 0;
- p = reinterpret_cast(hLp_getReadBuffer(&outQueue, &numBytes));
- hv_assert((p != nullptr) && "::getNextSentMessage - something bad happened.");
- hv_assert(numBytes >= sizeof(ReceiverMessagePair));
- hv_assert((numBytes <= msgLengthBytes) &&
- "::getNextSentMessage - the sent message is bigger than the message "
- "passed to handle it.");
- *destinationHash = p->receiverHash;
- hv_memcpy(outMsg, &p->msg, numBytes);
- hLp_consume(&outQueue);
- }
- HV_SPINLOCK_RELEASE(outQueueLock);
- }
- return (p != nullptr);
-}
-
-hv_uint32_t HeavyContext::getHashForString(const char *str) {
- return hv_string_to_hash(str);
-}
-
-HvTable *_hv_table_get(HeavyContextInterface *c, hv_uint32_t tableHash) {
- hv_assert(c != nullptr);
- return reinterpret_cast(c)->getTableForHash(tableHash);
-}
-
-void _hv_scheduleMessageForReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, HvMessage *m) {
- hv_assert(c != nullptr);
- reinterpret_cast(c)->scheduleMessageForReceiver(receiverHash, m);
-}
-
-HvMessage *_hv_scheduleMessageForObject(HeavyContextInterface *c, const HvMessage *m,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
- int letIndex) {
- hv_assert(c != nullptr);
- HvMessage *n = reinterpret_cast(c)->scheduleMessageForObject(
- m, sendMessage, letIndex);
- return n;
-}
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-HvTable *hv_table_get(HeavyContextInterface *c, hv_uint32_t tableHash) {
- return _hv_table_get(c, tableHash);
-}
-
-void hv_scheduleMessageForReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, HvMessage *m) {
- _hv_scheduleMessageForReceiver(c, receiverHash, m);
-}
-
-HvMessage *hv_scheduleMessageForObject(HeavyContextInterface *c, const HvMessage *m,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
- int letIndex) {
- return _hv_scheduleMessageForObject(c, m, sendMessage, letIndex);
-}
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HeavyContext.hpp b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HeavyContext.hpp
deleted file mode 100644
index 87b95d74c2..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HeavyContext.hpp
+++ /dev/null
@@ -1,107 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _HEAVY_CONTEXT_H_
-#define _HEAVY_CONTEXT_H_
-
-#include "HeavyContextInterface.hpp"
-#include "HvLightPipe.h"
-#include "HvMessageQueue.h"
-#include "HvMath.h"
-
-struct HvTable;
-
-class HeavyContext : public HeavyContextInterface {
-
- public:
- HeavyContext(double sampleRate, int poolKb=10, int inQueueKb=2, int outQueueKb=0);
- virtual ~HeavyContext();
-
- int getSize() override { return (int) numBytes; }
-
- double getSampleRate() override { return sampleRate; }
-
- hv_uint32_t getCurrentSample() override { return blockStartTimestamp; }
- float samplesToMilliseconds(hv_uint32_t numSamples) override { return (float) (1000.0*numSamples/sampleRate); }
- hv_uint32_t millisecondsToSamples(float ms) override { return (hv_uint32_t) (hv_max_f(0.0f,ms)*sampleRate/1000.0); }
-
- void setUserData(void *x) override { userData = x; }
- void *getUserData() override { return userData; }
-
- // hook management
- void setSendHook(HvSendHook_t *f) override { sendHook = f; }
- HvSendHook_t *getSendHook() override { return sendHook; }
-
- void setPrintHook(HvPrintHook_t *f) override { printHook = f; }
- HvPrintHook_t *getPrintHook() override { return printHook; }
-
- // message scheduling
- bool sendMessageToReceiver(hv_uint32_t receiverHash, double delayMs, HvMessage *m) override;
- bool sendMessageToReceiverV(hv_uint32_t receiverHash, double delayMs, const char *fmt, ...) override;
- bool sendFloatToReceiver(hv_uint32_t receiverHash, float f) override;
- bool sendBangToReceiver(hv_uint32_t receiverHash) override;
- bool sendSymbolToReceiver(hv_uint32_t receiverHash, const char *symbol) override;
- bool cancelMessage(HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) override;
-
- // table manipulation
- float *getBufferForTable(hv_uint32_t tableHash) override;
- int getLengthForTable(hv_uint32_t tableHash) override;
- bool setLengthForTable(hv_uint32_t tableHash, hv_uint32_t newSampleLength) override;
-
- // lock control
- void lockAcquire() override;
- bool lockTry() override;
- void lockRelease() override;
-
- // message queue management
- void setInputMessageQueueSize(int inQueueKb) override;
- void setOutputMessageQueueSize(int outQueueKb) override;
- bool getNextSentMessage(hv_uint32_t *destinationHash, HvMessage *outMsg, hv_size_t msgLength) override;
-
- // utility functions
- static hv_uint32_t getHashForString(const char *str);
-
- protected:
- virtual HvTable *getTableForHash(hv_uint32_t tableHash) = 0;
- friend HvTable *_hv_table_get(HeavyContextInterface *, hv_uint32_t);
-
- virtual void scheduleMessageForReceiver(hv_uint32_t receiverHash, HvMessage *m) = 0;
- friend void _hv_scheduleMessageForReceiver(HeavyContextInterface *, hv_uint32_t, HvMessage *);
-
- HvMessage *scheduleMessageForObject(const HvMessage *,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
- int);
- friend HvMessage *_hv_scheduleMessageForObject(HeavyContextInterface *, const HvMessage *,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
- int);
-
- friend void defaultSendHook(HeavyContextInterface *, const char *, hv_uint32_t, const HvMessage *);
-
- // object state
- double sampleRate;
- hv_uint32_t blockStartTimestamp;
- hv_size_t numBytes;
- HvMessageQueue mq;
- HvSendHook_t *sendHook;
- HvPrintHook_t *printHook;
- void *userData;
- HvLightPipe inQueue;
- HvLightPipe outQueue;
- hv_atomic_bool inQueueLock;
- hv_atomic_bool outQueueLock;
-};
-
-#endif // _HEAVY_CONTEXT_H_
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HeavyContextInterface.hpp b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HeavyContextInterface.hpp
deleted file mode 100644
index a78fcbf396..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HeavyContextInterface.hpp
+++ /dev/null
@@ -1,291 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _HEAVY_CONTEXT_INTERFACE_H_
-#define _HEAVY_CONTEXT_INTERFACE_H_
-
-#include "HvUtils.h"
-
-#ifndef _HEAVY_DECLARATIONS_
-#define _HEAVY_DECLARATIONS_
-
-class HeavyContextInterface;
-struct HvMessage;
-
-typedef enum {
- HV_PARAM_TYPE_PARAMETER_IN,
- HV_PARAM_TYPE_PARAMETER_OUT,
- HV_PARAM_TYPE_EVENT_IN,
- HV_PARAM_TYPE_EVENT_OUT
-} HvParameterType;
-
-typedef struct HvParameterInfo {
- const char *name; // the human readable parameter name
- hv_uint32_t hash; // an integer identified used by heavy for this parameter
- HvParameterType type; // type of this parameter
- float minVal; // the minimum value of this parameter
- float maxVal; // the maximum value of this parameter
- float defaultVal; // the default value of this parameter
-} HvParameterInfo;
-
-typedef void (HvSendHook_t) (HeavyContextInterface *context, const char *sendName, hv_uint32_t sendHash, const HvMessage *msg);
-typedef void (HvPrintHook_t) (HeavyContextInterface *context, const char *printName, const char *str, const HvMessage *msg);
-
-#endif // _HEAVY_DECLARATIONS_
-
-
-
-class HeavyContextInterface {
-
- public:
- HeavyContextInterface() {}
- virtual ~HeavyContextInterface() {};
-
- /** Returns the read-only user-assigned name of this patch. */
- virtual const char *getName() = 0;
-
- /** Returns the number of input channels with which this context has been configured. */
- virtual int getNumInputChannels() = 0;
-
- /** Returns the number of output channels with which this context has been configured. */
- virtual int getNumOutputChannels() = 0;
-
- /**
- * Returns the total size in bytes of the context.
- * This value may change if tables are resized.
- */
- virtual int getSize() = 0;
-
- /** Returns the sample rate with which this context has been configured. */
- virtual double getSampleRate() = 0;
-
- /** Returns the current patch time in samples. This value is always exact. */
- virtual hv_uint32_t getCurrentSample() = 0;
- virtual float samplesToMilliseconds(hv_uint32_t numSamples) = 0;
-
- /** Converts milliseconds to samples. Input is limited to non-negative range. */
- virtual hv_uint32_t millisecondsToSamples(float ms) = 0;
-
- /** Sets a user-definable value. This value is never manipulated by Heavy. */
- virtual void setUserData(void *x) = 0;
-
- /** Returns the user-defined data. */
- virtual void *getUserData() = 0;
-
- /**
- * Set the send hook. The function is called whenever a message is sent to any send object.
- * Messages returned by this function should NEVER be freed. If the message must persist, call
- * hv_msg_copy() first.
- */
- virtual void setSendHook(HvSendHook_t *f) = 0;
-
- /** Returns the send hook, or NULL if unset. */
- virtual HvSendHook_t *getSendHook() = 0;
-
- /** Set the print hook. The function is called whenever a message is sent to a print object. */
- virtual void setPrintHook(HvPrintHook_t *f) = 0;
-
- /** Returns the print hook, or NULL if unset. */
- virtual HvPrintHook_t *getPrintHook() = 0;
-
- /**
- * Processes one block of samples for a patch instance. The buffer format is an array of float channel arrays.
- * If the context has not input or output channels, the respective argument may be NULL.
- * The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
- * no, SSE or NEON, or AVX optimisation is being used, respectively.
- * e.g. [[LLLL][RRRR]]
- *
- * @return The number of samples processed.
- *
- * This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
- */
- virtual int process(float **inputBuffers, float **outputBuffer, int n) = 0;
-
- /**
- * Processes one block of samples for a patch instance. The buffer format is an uninterleaved float array of channels.
- * If the context has not input or output channels, the respective argument may be NULL.
- * The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
- * no, SSE or NEON, or AVX optimisation is being used, respectively.
- * e.g. [LLLLRRRR]
- *
- * @return The number of samples processed.
- *
- * This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
- */
- virtual int processInline(float *inputBuffers, float *outputBuffer, int n) = 0;
-
- /**
- * Processes one block of samples for a patch instance. The buffer format is an interleaved float array of channels.
- * If the context has not input or output channels, the respective argument may be NULL.
- * The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
- * no, SSE or NEON, or AVX optimisation is being used, respectively.
- * e.g. [LRLRLRLR]
- *
- * @return The number of samples processed.
- *
- * This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
- */
- virtual int processInlineInterleaved(float *inputBuffers, float *outputBuffer, int n) = 0;
-
- /**
- * Sends a formatted message to a receiver that can be scheduled for the future.
- * The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
- * This function is thread-safe.
- *
- * @return True if the message was accepted. False if the message could not fit onto
- * the message queue to be processed this block.
- */
- virtual bool sendMessageToReceiver(hv_uint32_t receiverHash, double delayMs, HvMessage *m) = 0;
-
- /**
- * Sends a formatted message to a receiver that can be scheduled for the future.
- * The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
- * This function is thread-safe.
- *
- * @return True if the message was accepted. False if the message could not fit onto
- * the message queue to be processed this block.
- */
- virtual bool sendMessageToReceiverV(hv_uint32_t receiverHash, double delayMs, const char *fmt, ...) = 0;
-
- /**
- * A convenience function to send a float to a receiver to be processed immediately.
- * The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
- * This function is thread-safe.
- *
- * @return True if the message was accepted. False if the message could not fit onto
- * the message queue to be processed this block.
- */
- virtual bool sendFloatToReceiver(hv_uint32_t receiverHash, float f) = 0;
-
- /**
- * A convenience function to send a bang to a receiver to be processed immediately.
- * The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
- * This function is thread-safe.
- *
- * @return True if the message was accepted. False if the message could not fit onto
- * the message queue to be processed this block.
- */
- virtual bool sendBangToReceiver(hv_uint32_t receiverHash) = 0;
-
- /**
- * A convenience function to send a symbol to a receiver to be processed immediately.
- * The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
- * This function is thread-safe.
- *
- * @return True if the message was accepted. False if the message could not fit onto
- * the message queue to be processed this block.
- */
- virtual bool sendSymbolToReceiver(hv_uint32_t receiverHash, const char *symbol) = 0;
-
- /**
- * Cancels a previously scheduled message.
- *
- * @param sendMessage May be NULL.
- */
- virtual bool cancelMessage(HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)=nullptr) = 0;
-
- /**
- * Returns information about each parameter such as name, hash, and range.
- * The total number of parameters is always returned.
- *
- * @param index The parameter index.
- * @param info A pointer to a HvParameterInfo struct. May be null.
- *
- * @return The total number of parameters.
- */
- virtual int getParameterInfo(int index, HvParameterInfo *info) = 0;
-
- /** Returns a pointer to the raw buffer backing this table. DO NOT free it. */
- virtual float *getBufferForTable(hv_uint32_t tableHash) = 0;
-
- /** Returns the length of this table in samples. */
- virtual int getLengthForTable(hv_uint32_t tableHash) = 0;
-
- /**
- * Resizes the table to the given length.
- *
- * Existing contents are copied to the new table. Remaining space is cleared
- * if the table is longer than the original, truncated otherwise.
- *
- * @param tableHash The table identifier.
- * @param newSampleLength The new length of the table, in samples.
- *
- * @return False if the table could not be found. True otherwise.
- */
- virtual bool setLengthForTable(hv_uint32_t tableHash, hv_uint32_t newSampleLength) = 0;
-
- /**
- * Acquire the input message queue lock.
- *
- * This function will block until the message lock as been acquired.
- * Typical applications will not require the use of this function.
- */
- virtual void lockAcquire() = 0;
-
- /**
- * Try to acquire the input message queue lock.
- *
- * If the lock has been acquired, hv_lock_release() must be called to release it.
- * Typical applications will not require the use of this function.
- *
- * @return Returns true if the lock has been acquired, false otherwise.
- */
- virtual bool lockTry() = 0;
-
- /**
- * Release the input message queue lock.
- *
- * Typical applications will not require the use of this function.
- */
- virtual void lockRelease() = 0;
-
- /**
- * Set the size of the input message queue in kilobytes.
- *
- * The buffer is reset and all existing contents are lost on resize.
- *
- * @param inQueueKb Must be positive i.e. at least one.
- */
- virtual void setInputMessageQueueSize(int inQueueKb) = 0;
-
- /**
- * Set the size of the output message queue in kilobytes.
- *
- * The buffer is reset and all existing contents are lost on resize.
- * Only the default sendhook uses the outgoing message queue. If the default
- * sendhook is not being used, then this function is not useful.
- *
- * @param outQueueKb Must be postive i.e. at least one.
- */
- virtual void setOutputMessageQueueSize(int outQueueKb) = 0;
-
- /**
- * Get the next message in the outgoing queue, will also consume the message.
- * Returns false if there are no messages.
- *
- * @param destinationHash a hash of the name of the receiver the message was sent to.
- * @param outMsg message pointer that is filled by the next message contents.
- * @param msgLengthBytes max length of outMsg in bytes.
- *
- * @return True if there is a message in the outgoing queue.
- */
- virtual bool getNextSentMessage(hv_uint32_t *destinationHash, HvMessage *outMsg, hv_size_t msgLengthBytes) = 0;
-
- /** Returns a 32-bit hash of any string. Returns 0 if string is NULL. */
- static hv_uint32_t getHashForString(const char *str);
-};
-
-#endif // _HEAVY_CONTEXT_INTERFACE_H_
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/Heavy_test.cpp b/examples/examples-dsp/examples-pd/streams-pd-audiokit/Heavy_test.cpp
deleted file mode 100644
index 65cd042e34..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/Heavy_test.cpp
+++ /dev/null
@@ -1,264 +0,0 @@
-/**
- * Copyright (c) 2024 Enzien Audio, Ltd.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions, and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the phrase "powered by heavy",
- * the heavy logo, and a hyperlink to https://enzienaudio.com, all in a visible
- * form.
- *
- * 2.1 If the Application is distributed in a store system (for example,
- * the Apple "App Store" or "Google Play"), the phrase "powered by heavy"
- * shall be included in the app description or the copyright text as well as
- * the in the app itself. The heavy logo will shall be visible in the app
- * itself as well.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "Heavy_test.hpp"
-
-#include
-
-#define Context(_c) static_cast(_c)
-
-
-/*
- * C Functions
- */
-
-extern "C" {
- HV_EXPORT HeavyContextInterface *hv_test_new(double sampleRate) {
- // allocate aligned memory
- void *ptr = hv_malloc(sizeof(Heavy_test));
- // ensure non-null
- if (!ptr) return nullptr;
- // call constructor
- new(ptr) Heavy_test(sampleRate);
- return Context(ptr);
- }
-
- HV_EXPORT HeavyContextInterface *hv_test_new_with_options(double sampleRate,
- int poolKb, int inQueueKb, int outQueueKb) {
- // allocate aligned memory
- void *ptr = hv_malloc(sizeof(Heavy_test));
- // ensure non-null
- if (!ptr) return nullptr;
- // call constructor
- new(ptr) Heavy_test(sampleRate, poolKb, inQueueKb, outQueueKb);
- return Context(ptr);
- }
-
- HV_EXPORT void hv_test_free(HeavyContextInterface *instance) {
- // call destructor
- Context(instance)->~Heavy_test();
- // free memory
- hv_free(instance);
- }
-} // extern "C"
-
-
-
-
-
-
-
-/*
- * Class Functions
- */
-
-Heavy_test::Heavy_test(double sampleRate, int poolKb, int inQueueKb, int outQueueKb)
- : HeavyContext(sampleRate, poolKb, inQueueKb, outQueueKb) {
- numBytes += sPhasor_k_init(&sPhasor_GM4o5ge7, 220.0f, sampleRate);
-
-}
-
-Heavy_test::~Heavy_test() {
- // nothing to free
-}
-
-HvTable *Heavy_test::getTableForHash(hv_uint32_t tableHash) {
- return nullptr;
-}
-
-void Heavy_test::scheduleMessageForReceiver(hv_uint32_t receiverHash, HvMessage *m) {
- switch (receiverHash) {
- default: return;
- }
-}
-
-int Heavy_test::getParameterInfo(int index, HvParameterInfo *info) {
- if (info != nullptr) {
- switch (index) {
- default: {
- info->name = "invalid parameter index";
- info->hash = 0;
- info->type = HvParameterType::HV_PARAM_TYPE_PARAMETER_IN;
- info->minVal = 0.0f;
- info->maxVal = 0.0f;
- info->defaultVal = 0.0f;
- break;
- }
- }
- }
- return 0;
-}
-
-
-
-/*
- * Send Function Implementations
- */
-
-
-
-
-
-/*
- * Context Process Implementation
- */
-
-int Heavy_test::process(float **inputBuffers, float **outputBuffers, int n) {
- while (hLp_hasData(&inQueue)) {
- hv_uint32_t numBytes = 0;
- ReceiverMessagePair *p = reinterpret_cast(hLp_getReadBuffer(&inQueue, &numBytes));
- hv_assert(numBytes >= sizeof(ReceiverMessagePair));
- scheduleMessageForReceiver(p->receiverHash, &p->msg);
- hLp_consume(&inQueue);
- }
-
- sendBangToReceiver(0xDD21C0EB); // send to __hv_bang~ on next cycle
- const int n4 = n & ~HV_N_SIMD_MASK; // ensure that the block size is a multiple of HV_N_SIMD
-
- // temporary signal vars
- hv_bufferf_t Bf0, Bf1, Bf2, Bf3, Bf4;
-
- // input and output vars
- hv_bufferf_t O0, O1;
-
- // declare and init the zero buffer
- hv_bufferf_t ZERO; __hv_zero_f(VOf(ZERO));
-
- hv_uint32_t nextBlock = blockStartTimestamp;
- for (int n = 0; n < n4; n += HV_N_SIMD) {
-
- // process all of the messages for this block
- nextBlock += HV_N_SIMD;
- while (mq_hasMessageBefore(&mq, nextBlock)) {
- MessageNode *const node = mq_peek(&mq);
- node->sendMessage(this, node->let, node->m);
- mq_pop(&mq);
- }
-
-
-
- // zero output buffers
- __hv_zero_f(VOf(O0));
- __hv_zero_f(VOf(O1));
-
- // process all signal functions
- __hv_phasor_k_f(&sPhasor_GM4o5ge7, VOf(Bf0));
- __hv_var_k_f(VOf(Bf1), 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f);
- __hv_sub_f(VIf(Bf0), VIf(Bf1), VOf(Bf1));
- __hv_abs_f(VIf(Bf1), VOf(Bf1));
- __hv_var_k_f(VOf(Bf0), 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f);
- __hv_sub_f(VIf(Bf1), VIf(Bf0), VOf(Bf0));
- __hv_var_k_f(VOf(Bf1), 6.283185307179586f, 6.283185307179586f, 6.283185307179586f, 6.283185307179586f, 6.283185307179586f, 6.283185307179586f, 6.283185307179586f, 6.283185307179586f);
- __hv_mul_f(VIf(Bf0), VIf(Bf1), VOf(Bf1));
- __hv_mul_f(VIf(Bf1), VIf(Bf1), VOf(Bf0));
- __hv_mul_f(VIf(Bf1), VIf(Bf0), VOf(Bf2));
- __hv_mul_f(VIf(Bf2), VIf(Bf0), VOf(Bf0));
- __hv_var_k_f(VOf(Bf3), 0.007833333333333f, 0.007833333333333f, 0.007833333333333f, 0.007833333333333f, 0.007833333333333f, 0.007833333333333f, 0.007833333333333f, 0.007833333333333f);
- __hv_var_k_f(VOf(Bf4), -0.166666666666667f, -0.166666666666667f, -0.166666666666667f, -0.166666666666667f, -0.166666666666667f, -0.166666666666667f, -0.166666666666667f, -0.166666666666667f);
- __hv_fma_f(VIf(Bf2), VIf(Bf4), VIf(Bf1), VOf(Bf1));
- __hv_fma_f(VIf(Bf0), VIf(Bf3), VIf(Bf1), VOf(Bf1));
- __hv_add_f(VIf(Bf1), VIf(O0), VOf(O0));
-
- // save output vars to output buffer
- __hv_store_f(outputBuffers[0]+n, VIf(O0));
- __hv_store_f(outputBuffers[1]+n, VIf(O1));
- }
-
- blockStartTimestamp = nextBlock;
-
- return n4; // return the number of frames processed
-
-}
-
-int Heavy_test::processInline(float *inputBuffers, float *outputBuffers, int n4) {
- hv_assert(!(n4 & HV_N_SIMD_MASK)); // ensure that n4 is a multiple of HV_N_SIMD
-
- // define the heavy input buffer for 0 channel(s)
- float **const bIn = NULL;
-
- // define the heavy output buffer for 2 channel(s)
- float **const bOut = reinterpret_cast(hv_alloca(2*sizeof(float *)));
- bOut[0] = outputBuffers+(0*n4);
- bOut[1] = outputBuffers+(1*n4);
-
- int n = process(bIn, bOut, n4);
- return n;
-}
-
-int Heavy_test::processInlineInterleaved(float *inputBuffers, float *outputBuffers, int n4) {
- // ps hv_assert(n4 & ~HV_N_SIMD_MASK); // ensure that n4 is a multiple of HV_N_SIMD
-
- // define the heavy input buffer for 0 channel(s), uninterleave
- float *const bIn = NULL;
-
- // define the heavy output buffer for 2 channel(s)
- float *const bOut = reinterpret_cast(hv_alloca(2*n4*sizeof(float)));
-
- int n = processInline(bIn, bOut, n4);
-
- // interleave the heavy output into the output buffer
- #if HV_SIMD_AVX
- for (int i = 0, j = 0; j < n4; j += 8, i += 16) {
- __m256 x = _mm256_load_ps(bOut+j); // LLLLLLLL
- __m256 y = _mm256_load_ps(bOut+n4+j); // RRRRRRRR
- __m256 a = _mm256_unpacklo_ps(x, y); // LRLRLRLR
- __m256 b = _mm256_unpackhi_ps(x, y); // LRLRLRLR
- _mm256_store_ps(outputBuffers+i, a);
- _mm256_store_ps(outputBuffers+8+i, b);
- }
- #elif HV_SIMD_SSE
- for (int i = 0, j = 0; j < n4; j += 4, i += 8) {
- __m128 x = _mm_load_ps(bOut+j); // LLLL
- __m128 y = _mm_load_ps(bOut+n4+j); // RRRR
- __m128 a = _mm_unpacklo_ps(x, y); // LRLR
- __m128 b = _mm_unpackhi_ps(x, y); // LRLR
- _mm_store_ps(outputBuffers+i, a);
- _mm_store_ps(outputBuffers+4+i, b);
- }
- #elif HV_SIMD_NEON
- // https://community.arm.com/groups/processors/blog/2012/03/13/coding-for-neon--part-5-rearranging-vectors
- for (int i = 0, j = 0; j < n4; j += 4, i += 8) {
- float32x4_t x = vld1q_f32(bOut+j);
- float32x4_t y = vld1q_f32(bOut+n4+j);
- float32x4x2_t z = {x, y};
- vst2q_f32(outputBuffers+i, z); // interleave and store
- }
- #else // HV_SIMD_NONE
- for (int i = 0; i < 2; ++i) {
- for (int j = 0; j < n4; ++j) {
- outputBuffers[i+2*j] = bOut[i*n4+j];
- }
- }
- #endif
-
- return n;
-}
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/Heavy_test.h b/examples/examples-dsp/examples-pd/streams-pd-audiokit/Heavy_test.h
deleted file mode 100644
index 18213d89b5..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/Heavy_test.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/**
- * Copyright (c) 2024 Enzien Audio, Ltd.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions, and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the phrase "powered by heavy",
- * the heavy logo, and a hyperlink to https://enzienaudio.com, all in a visible
- * form.
- *
- * 2.1 If the Application is distributed in a store system (for example,
- * the Apple "App Store" or "Google Play"), the phrase "powered by heavy"
- * shall be included in the app description or the copyright text as well as
- * the in the app itself. The heavy logo will shall be visible in the app
- * itself as well.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef _HEAVY_TEST_H_
-#define _HEAVY_TEST_H_
-
-#include "HvHeavy.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if HV_APPLE
-#pragma mark - Heavy Context
-#endif
-
-
-
-/**
- * Creates a new patch instance.
- * Sample rate should be positive and in Hertz, e.g. 44100.0.
- */
-HeavyContextInterface *hv_test_new(double sampleRate);
-
-/**
- * Creates a new patch instance.
- * @param sampleRate Sample rate should be positive (> 0) and in Hertz, e.g. 48000.0.
- * @param poolKb Pool size is in kilobytes, and determines the maximum amount of memory
- * allocated to messages at any time. By default this is 10 KB.
- * @param inQueueKb The size of the input message queue in kilobytes. It determines the
- * amount of memory dedicated to holding scheduled messages between calls to
- * process(). Default is 2 KB.
- * @param outQueueKb The size of the output message queue in kilobytes. It determines the
- * amount of memory dedicated to holding scheduled messages to the default sendHook.
- * See getNextSentMessage() for info on accessing these messages. Default is 0 KB.
- */
-HeavyContextInterface *hv_test_new_with_options(double sampleRate, int poolKb, int inQueueKb, int outQueueKb);
-
-/**
- * Free the patch instance.
- */
-void hv_test_free(HeavyContextInterface *instance);
-
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // _HEAVY_TEST_H_
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/Heavy_test.hpp b/examples/examples-dsp/examples-pd/streams-pd-audiokit/Heavy_test.hpp
deleted file mode 100644
index a9f015a541..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/Heavy_test.hpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * Copyright (c) 2024 Enzien Audio, Ltd.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions, and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the phrase "powered by heavy",
- * the heavy logo, and a hyperlink to https://enzienaudio.com, all in a visible
- * form.
- *
- * 2.1 If the Application is distributed in a store system (for example,
- * the Apple "App Store" or "Google Play"), the phrase "powered by heavy"
- * shall be included in the app description or the copyright text as well as
- * the in the app itself. The heavy logo will shall be visible in the app
- * itself as well.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef _HEAVY_CONTEXT_TEST_HPP_
-#define _HEAVY_CONTEXT_TEST_HPP_
-
-// object includes
-#include "HeavyContext.hpp"
-#include "HvSignalVar.h"
-#include "HvSignalPhasor.h"
-#include "HvMath.h"
-
-class Heavy_test : public HeavyContext {
-
- public:
- Heavy_test(double sampleRate, int poolKb=10, int inQueueKb=2, int outQueueKb=0);
- ~Heavy_test();
-
- const char *getName() override { return "test"; }
- int getNumInputChannels() override { return 0; }
- int getNumOutputChannels() override { return 2; }
-
- int process(float **inputBuffers, float **outputBuffer, int n) override;
- int processInline(float *inputBuffers, float *outputBuffer, int n) override;
- int processInlineInterleaved(float *inputBuffers, float *outputBuffer, int n) override;
-
- int getParameterInfo(int index, HvParameterInfo *info) override;
-
- private:
- HvTable *getTableForHash(hv_uint32_t tableHash) override;
- void scheduleMessageForReceiver(hv_uint32_t receiverHash, HvMessage *m) override;
-
- // static sendMessage functions
-
- // objects
- SignalPhasor sPhasor_GM4o5ge7;
-};
-
-#endif // _HEAVY_CONTEXT_TEST_HPP_
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvHeavy.cpp b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvHeavy.cpp
deleted file mode 100644
index 19ca4128d8..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvHeavy.cpp
+++ /dev/null
@@ -1,318 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "HeavyContext.hpp"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if HV_APPLE
-#pragma mark - Heavy Table
-#endif
-
-HV_EXPORT bool hv_table_setLength(HeavyContextInterface *c, hv_uint32_t tableHash, hv_uint32_t newSampleLength) {
- hv_assert(c != nullptr);
- return c->setLengthForTable(tableHash, newSampleLength);
-}
-
-HV_EXPORT float *hv_table_getBuffer(HeavyContextInterface *c, hv_uint32_t tableHash) {
- hv_assert(c != nullptr);
- return c->getBufferForTable(tableHash);
-}
-
-HV_EXPORT hv_uint32_t hv_table_getLength(HeavyContextInterface *c, hv_uint32_t tableHash) {
- hv_assert(c != nullptr);
- return c->getLengthForTable(tableHash);
-}
-
-
-
-#if HV_APPLE
-#pragma mark - Heavy Message
-#endif
-
-HV_EXPORT hv_size_t hv_msg_getByteSize(hv_uint32_t numElements) {
- return msg_getCoreSize(numElements);
-}
-
-HV_EXPORT void hv_msg_init(HvMessage *m, int numElements, hv_uint32_t timestamp) {
- msg_init(m, numElements, timestamp);
-}
-
-HV_EXPORT hv_size_t hv_msg_getNumElements(const HvMessage *m) {
- return msg_getNumElements(m);
-}
-
-HV_EXPORT hv_uint32_t hv_msg_getTimestamp(const HvMessage *m) {
- return msg_getTimestamp(m);
-}
-
-HV_EXPORT void hv_msg_setTimestamp(HvMessage *m, hv_uint32_t timestamp) {
- msg_setTimestamp(m, timestamp);
-}
-
-HV_EXPORT bool hv_msg_isBang(const HvMessage *const m, int i) {
- return msg_isBang(m,i);
-}
-
-HV_EXPORT void hv_msg_setBang(HvMessage *m, int i) {
- msg_setBang(m,i);
-}
-
-HV_EXPORT bool hv_msg_isFloat(const HvMessage *const m, int i) {
- return msg_isFloat(m, i);
-}
-
-HV_EXPORT float hv_msg_getFloat(const HvMessage *const m, int i) {
- return msg_getFloat(m,i);
-}
-
-HV_EXPORT void hv_msg_setFloat(HvMessage *m, int i, float f) {
- msg_setFloat(m,i,f);
-}
-
-HV_EXPORT bool hv_msg_isSymbol(const HvMessage *const m, int i) {
- return msg_isSymbol(m,i);
-}
-
-HV_EXPORT const char *hv_msg_getSymbol(const HvMessage *const m, int i) {
- return msg_getSymbol(m,i);
-}
-
-HV_EXPORT void hv_msg_setSymbol(HvMessage *m, int i, const char *s) {
- msg_setSymbol(m,i,s);
-}
-
-HV_EXPORT bool hv_msg_isHash(const HvMessage *const m, int i) {
- return msg_isHash(m, i);
-}
-
-HV_EXPORT hv_uint32_t hv_msg_getHash(const HvMessage *const m, int i) {
- return msg_getHash(m, i);
-}
-
-HV_EXPORT bool hv_msg_hasFormat(const HvMessage *const m, const char *fmt) {
- return msg_hasFormat(m, fmt);
-}
-
-HV_EXPORT char *hv_msg_toString(const HvMessage *const m) {
- return msg_toString(m);
-}
-
-HV_EXPORT HvMessage *hv_msg_copy(const HvMessage *const m) {
- return msg_copy(m);
-}
-
-HV_EXPORT void hv_msg_free(HvMessage *m) {
- msg_free(m);
-}
-
-
-
-#if HV_APPLE
-#pragma mark - Heavy Common
-#endif
-
-HV_EXPORT int hv_getSize(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- return (int) c->getSize();
-}
-
-HV_EXPORT double hv_getSampleRate(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- return c->getSampleRate();
-}
-
-HV_EXPORT int hv_getNumInputChannels(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- return c->getNumInputChannels();
-}
-
-HV_EXPORT int hv_getNumOutputChannels(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- return c->getNumOutputChannels();
-}
-
-HV_EXPORT void hv_setPrintHook(HeavyContextInterface *c, HvPrintHook_t *f) {
- hv_assert(c != nullptr);
- c->setPrintHook(f);
-}
-
-HV_EXPORT HvPrintHook_t *hv_getPrintHook(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- return c->getPrintHook();
-}
-
-HV_EXPORT void hv_setSendHook(HeavyContextInterface *c, HvSendHook_t *f) {
- hv_assert(c != nullptr);
- c->setSendHook(f);
-}
-
-HV_EXPORT hv_uint32_t hv_stringToHash(const char *s) {
- return hv_string_to_hash(s);
-}
-
-HV_EXPORT bool hv_sendBangToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash) {
- hv_assert(c != nullptr);
- return c->sendBangToReceiver(receiverHash);
-}
-
-HV_EXPORT bool hv_sendFloatToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, float x) {
- hv_assert(c != nullptr);
- return c->sendFloatToReceiver(receiverHash, x);
-}
-
-HV_EXPORT bool hv_sendSymbolToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, char *s) {
- hv_assert(c != nullptr);
- return c->sendSymbolToReceiver(receiverHash, s);
-}
-
-HV_EXPORT bool hv_sendMessageToReceiverV(
- HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, const char *format, ...) {
- hv_assert(c != nullptr);
- hv_assert(delayMs >= 0.0);
- hv_assert(format != nullptr);
-
- va_list ap;
- va_start(ap, format);
- const int numElem = (int) hv_strlen(format);
- HvMessage *m = HV_MESSAGE_ON_STACK(numElem);
- msg_init(m, numElem, c->getCurrentSample() + (hv_uint32_t) (hv_max_d(0.0, delayMs)*c->getSampleRate()/1000.0));
- for (int i = 0; i < numElem; i++) {
- switch (format[i]) {
- case 'b': msg_setBang(m, i); break;
- case 'f': msg_setFloat(m, i, (float) va_arg(ap, double)); break;
- case 'h': msg_setHash(m, i, (int) va_arg(ap, int)); break;
- case 's': msg_setSymbol(m, i, (char *) va_arg(ap, char *)); break;
- default: break;
- }
- }
- va_end(ap);
-
- return c->sendMessageToReceiver(receiverHash, delayMs, m);
-}
-
-HV_EXPORT bool hv_sendMessageToReceiver(
- HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, HvMessage *m) {
- hv_assert(c != nullptr);
- return c->sendMessageToReceiver(receiverHash, delayMs, m);
-}
-
-HV_EXPORT void hv_cancelMessage(HeavyContextInterface *c, HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
- hv_assert(c != nullptr);
- c->cancelMessage(m, sendMessage);
-}
-
-HV_EXPORT const char *hv_getName(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- return c->getName();
-}
-
-HV_EXPORT void hv_setUserData(HeavyContextInterface *c, void *userData) {
- hv_assert(c != nullptr);
- c->setUserData(userData);
-}
-
-HV_EXPORT void *hv_getUserData(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- return c->getUserData();
-}
-
-HV_EXPORT double hv_getCurrentTime(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- return (double) c->samplesToMilliseconds(c->getCurrentSample());
-}
-
-HV_EXPORT hv_uint32_t hv_getCurrentSample(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- return c->getCurrentSample();
-}
-
-HV_EXPORT float hv_samplesToMilliseconds(HeavyContextInterface *c, hv_uint32_t numSamples) {
- hv_assert(c != nullptr);
- return c->samplesToMilliseconds(numSamples);
-}
-
-HV_EXPORT hv_uint32_t hv_millisecondsToSamples(HeavyContextInterface *c, float ms) {
- hv_assert(c != nullptr);
- return c->millisecondsToSamples(ms);
-}
-
-HV_EXPORT int hv_getParameterInfo(HeavyContextInterface *c, int index, HvParameterInfo *info) {
- hv_assert(c != nullptr);
- return c->getParameterInfo(index, info);
-}
-
-HV_EXPORT void hv_lock_acquire(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- c->lockAcquire();
-}
-
-HV_EXPORT bool hv_lock_try(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- return c->lockTry();
-}
-
-HV_EXPORT void hv_lock_release(HeavyContextInterface *c) {
- hv_assert(c != nullptr);
- c->lockRelease();
-}
-
-HV_EXPORT void hv_setInputMessageQueueSize(HeavyContextInterface *c, hv_uint32_t inQueueKb) {
- hv_assert(c != nullptr);
- c->setInputMessageQueueSize(inQueueKb);
-}
-
-HV_EXPORT void hv_setOutputMessageQueueSize(HeavyContextInterface *c, hv_uint32_t outQueueKb) {
- hv_assert(c != nullptr);
- c->setOutputMessageQueueSize(outQueueKb);
-}
-
-HV_EXPORT bool hv_getNextSentMessage(HeavyContextInterface *c, hv_uint32_t *destinationHash, HvMessage *outMsg, hv_uint32_t msgLength) {
- hv_assert(c != nullptr);
- hv_assert(destinationHash != nullptr);
- hv_assert(outMsg != nullptr);
- return c->getNextSentMessage(destinationHash, outMsg, msgLength);
-}
-
-
-#if HV_APPLE
-#pragma mark - Heavy Common
-#endif
-
-HV_EXPORT int hv_process(HeavyContextInterface *c, float **inputBuffers, float **outputBuffers, int n) {
- hv_assert(c != nullptr);
- return c->process(inputBuffers, outputBuffers, n);
-}
-
-HV_EXPORT int hv_processInline(HeavyContextInterface *c, float *inputBuffers, float *outputBuffers, int n) {
- hv_assert(c != nullptr);
- return c->processInline(inputBuffers, outputBuffers, n);
-}
-
-HV_EXPORT int hv_processInlineInterleaved(HeavyContextInterface *c, float *inputBuffers, float *outputBuffers, int n) {
- hv_assert(c != nullptr);
- return c->processInlineInterleaved(inputBuffers, outputBuffers, n);
-}
-
-HV_EXPORT void hv_delete(HeavyContextInterface *c) {
- delete c;
-}
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvHeavy.h b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvHeavy.h
deleted file mode 100644
index cb1aecfa98..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvHeavy.h
+++ /dev/null
@@ -1,413 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _HEAVY_H_
-#define _HEAVY_H_
-
-#include "HvUtils.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef _HEAVY_DECLARATIONS_
-#define _HEAVY_DECLARATIONS_
-
-#ifdef __cplusplus
-class HeavyContextInterface;
-#else
-typedef struct HeavyContextInterface HeavyContextInterface;
-#endif
-
-typedef struct HvMessage HvMessage;
-
-typedef enum {
- HV_PARAM_TYPE_PARAMETER_IN,
- HV_PARAM_TYPE_PARAMETER_OUT,
- HV_PARAM_TYPE_EVENT_IN,
- HV_PARAM_TYPE_EVENT_OUT
-} HvParameterType;
-
-typedef struct HvParameterInfo {
- const char *name; // the human readable parameter name
- hv_uint32_t hash; // an integer identified used by heavy for this parameter
- HvParameterType type; // type of this parameter
- float minVal; // the minimum value of this parameter
- float maxVal; // the maximum value of this parameter
- float defaultVal; // the default value of this parameter
-} HvParameterInfo;
-
-typedef void (HvSendHook_t) (HeavyContextInterface *context, const char *sendName, hv_uint32_t sendHash, const HvMessage *msg);
-typedef void (HvPrintHook_t) (HeavyContextInterface *context, const char *printName, const char *str, const HvMessage *msg);
-
-#endif // _HEAVY_DECLARATIONS_
-
-
-
-#if HV_APPLE
-#pragma mark - Heavy Context
-#endif
-
-/** Deletes a patch instance. */
-void hv_delete(HeavyContextInterface *c);
-
-
-
-#if HV_APPLE
-#pragma mark - Heavy Process
-#endif
-
-/**
- * Processes one block of samples for a patch instance. The buffer format is an array of float channel arrays.
- * If the context has not input or output channels, the respective argument may be NULL.
- * The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
- * no, SSE or NEON, or AVX optimisation is being used, respectively.
- * e.g. [[LLLL][RRRR]]
- * This function support in-place processing.
- *
- * @return The number of samples processed.
- *
- * This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
- */
-int hv_process(HeavyContextInterface *c, float **inputBuffers, float **outputBuffers, int n);
-
-/**
- * Processes one block of samples for a patch instance. The buffer format is an uninterleaved float array of channels.
- * If the context has not input or output channels, the respective argument may be NULL.
- * The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
- * no, SSE or NEON, or AVX optimisation is being used, respectively.
- * e.g. [LLLLRRRR]
- * This function support in-place processing.
- *
- * @return The number of samples processed.
- *
- * This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
- */
-int hv_processInline(HeavyContextInterface *c, float *inputBuffers, float *outputBuffers, int n);
-
-/**
- * Processes one block of samples for a patch instance. The buffer format is an interleaved float array of channels.
- * If the context has not input or output channels, the respective argument may be NULL.
- * The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
- * no, SSE or NEON, or AVX optimisation is being used, respectively.
- * e.g. [LRLRLRLR]
- * This function support in-place processing.
- *
- * @return The number of samples processed.
- *
- * This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
- */
-int hv_processInlineInterleaved(HeavyContextInterface *c, float *inputBuffers, float *outputBuffers, int n);
-
-
-
-#if HV_APPLE
-#pragma mark - Heavy Common
-#endif
-
-/**
- * Returns the total size in bytes of the context.
- * This value may change if tables are resized.
- */
-int hv_getSize(HeavyContextInterface *c);
-
-/** Returns the sample rate with which this context has been configured. */
-double hv_getSampleRate(HeavyContextInterface *c);
-
-/** Returns the number of input channels with which this context has been configured. */
-int hv_getNumInputChannels(HeavyContextInterface *c);
-
-/** Returns the number of output channels with which this context has been configured. */
-int hv_getNumOutputChannels(HeavyContextInterface *c);
-
-/** Set the print hook. The function is called whenever a message is sent to a print object. */
-void hv_setPrintHook(HeavyContextInterface *c, HvPrintHook_t *f);
-
-/** Returns the print hook, or NULL. */
-HvPrintHook_t *hv_getPrintHook(HeavyContextInterface *c);
-
-/**
- * Set the send hook. The function is called whenever a message is sent to any send object.
- * Messages returned by this function should NEVER be freed. If the message must persist, call
- * hv_msg_copy() first.
- */
-void hv_setSendHook(HeavyContextInterface *c, HvSendHook_t *f);
-
-/** Returns a 32-bit hash of any string. Returns 0 if string is NULL. */
-hv_uint32_t hv_stringToHash(const char *s);
-
-/**
- * A convenience function to send a bang to a receiver to be processed immediately.
- * The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
- * This function is thread-safe.
- *
- * @return True if the message was accepted. False if the message could not fit onto
- * the message queue to be processed this block.
- */
-bool hv_sendBangToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash);
-
-/**
- * A convenience function to send a float to a receiver to be processed immediately.
- * The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
- * This function is thread-safe.
- *
- * @return True if the message was accepted. False if the message could not fit onto
- * the message queue to be processed this block.
- */
-bool hv_sendFloatToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, const float x);
-
-/**
- * A convenience function to send a symbol to a receiver to be processed immediately.
- * The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
- * This function is thread-safe.
- *
- * @return True if the message was accepted. False if the message could not fit onto
- * the message queue to be processed this block.
- */
-bool hv_sendSymbolToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, char *s);
-
-/**
- * Sends a formatted message to a receiver that can be scheduled for the future.
- * The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
- * This function is thread-safe.
- *
- * @return True if the message was accepted. False if the message could not fit onto
- * the message queue to be processed this block.
- */
-bool hv_sendMessageToReceiverV(HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, const char *format, ...);
-
-/**
- * Sends a message to a receiver that can be scheduled for the future.
- * The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
- * This function is thread-safe.
- *
- * @return True if the message was accepted. False if the message could not fit onto
- * the message queue to be processed this block.
- */
-bool hv_sendMessageToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, HvMessage *m);
-
-/**
- * Cancels a previously scheduled message.
- *
- * @param sendMessage May be NULL.
- */
-void hv_cancelMessage(HeavyContextInterface *c, HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
-
-/** Returns the read-only user-assigned name of this patch. */
-const char *hv_getName(HeavyContextInterface *c);
-
-/** Sets a user-definable value. This value is never manipulated by Heavy. */
-void hv_setUserData(HeavyContextInterface *c, void *userData);
-
-/** Returns the user-defined data. */
-void *hv_getUserData(HeavyContextInterface *c);
-
-/** Returns the current patch time in milliseconds. This value may have rounding errors. */
-double hv_getCurrentTime(HeavyContextInterface *c);
-
-/** Returns the current patch time in samples. This value is always exact. */
-hv_uint32_t hv_getCurrentSample(HeavyContextInterface *c);
-
-/**
- * Returns information about each parameter such as name, hash, and range.
- * The total number of parameters is always returned.
- *
- * @param index The parameter index.
- * @param info A pointer to a HvParameterInfo struct. May be null.
- *
- * @return The total number of parameters.
- */
-int hv_getParameterInfo(HeavyContextInterface *c, int index, HvParameterInfo *info);
-
-/** */
-float hv_samplesToMilliseconds(HeavyContextInterface *c, hv_uint32_t numSamples);
-
-/** Converts milliseconds to samples. Input is limited to non-negative range. */
-hv_uint32_t hv_millisecondsToSamples(HeavyContextInterface *c, float ms);
-
-/**
- * Acquire the input message queue lock.
- *
- * This function will block until the message lock as been acquired.
- * Typical applications will not require the use of this function.
- *
- * @param c A Heavy context.
- */
-void hv_lock_acquire(HeavyContextInterface *c);
-
-/**
- * Try to acquire the input message queue lock.
- *
- * If the lock has been acquired, hv_lock_release() must be called to release it.
- * Typical applications will not require the use of this function.
- *
- * @param c A Heavy context.
- *
- * @return Returns true if the lock has been acquired, false otherwise.
- */
-bool hv_lock_try(HeavyContextInterface *c);
-
-/**
- * Release the input message queue lock.
- *
- * Typical applications will not require the use of this function.
- *
- * @param c A Heavy context.
- */
-void hv_lock_release(HeavyContextInterface *c);
-
-/**
- * Set the size of the input message queue in kilobytes.
- *
- * The buffer is reset and all existing contents are lost on resize.
- *
- * @param c A Heavy context.
- * @param inQueueKb Must be positive i.e. at least one.
- */
-void hv_setInputMessageQueueSize(HeavyContextInterface *c, hv_uint32_t inQueueKb);
-
-/**
- * Set the size of the output message queue in kilobytes.
- *
- * The buffer is reset and all existing contents are lost on resize.
- * Only the default sendhook uses the outgoing message queue. If the default
- * sendhook is not being used, then this function is not useful.
- *
- * @param c A Heavy context.
- * @param outQueueKb Must be postive i.e. at least one.
- */
-void hv_setOutputMessageQueueSize(HeavyContextInterface *c, hv_uint32_t outQueueKb);
-
-/**
- * Get the next message in the outgoing queue, will also consume the message.
- * Returns false if there are no messages.
- *
- * @param c A Heavy context.
- * @param destinationHash a hash of the name of the receiver the message was sent to.
- * @param outMsg message pointer that is filled by the next message contents.
- * @param msgLength length of outMsg in bytes.
- *
- * @return True if there is a message in the outgoing queue.
-*/
-bool hv_getNextSentMessage(HeavyContextInterface *c, hv_uint32_t *destinationHash, HvMessage *outMsg, hv_uint32_t msgLength);
-
-
-
-#if HV_APPLE
-#pragma mark - Heavy Message
-#endif
-
-typedef struct HvMessage HvMessage;
-
-/** Returns the total size in bytes of a HvMessage with a number of elements on the heap. */
-unsigned long hv_msg_getByteSize(hv_uint32_t numElements);
-
-/** Initialise a HvMessage structure with the number of elements and a timestamp (in samples). */
-void hv_msg_init(HvMessage *m, int numElements, hv_uint32_t timestamp);
-
-/** Returns the number of elements in this message. */
-unsigned long hv_msg_getNumElements(const HvMessage *m);
-
-/** Returns the time at which this message exists (in samples). */
-hv_uint32_t hv_msg_getTimestamp(const HvMessage *m);
-
-/** Set the time at which this message should be executed (in samples). */
-void hv_msg_setTimestamp(HvMessage *m, hv_uint32_t timestamp);
-
-/** Returns true of the indexed element is a bang. False otherwise. Index is not bounds checked. */
-bool hv_msg_isBang(const HvMessage *const m, int i);
-
-/** Sets the indexed element to a bang. Index is not bounds checked. */
-void hv_msg_setBang(HvMessage *m, int i);
-
-/** Returns true of the indexed element is a float. False otherwise. Index is not bounds checked. */
-bool hv_msg_isFloat(const HvMessage *const m, int i);
-
-/** Returns the indexed element as a float value. Index is not bounds checked. */
-float hv_msg_getFloat(const HvMessage *const m, int i);
-
-/** Sets the indexed element to float value. Index is not bounds checked. */
-void hv_msg_setFloat(HvMessage *m, int i, float f);
-
-/** Returns true of the indexed element is a symbol. False otherwise. Index is not bounds checked. */
-bool hv_msg_isSymbol(const HvMessage *const m, int i);
-
-/** Returns the indexed element as a symbol value. Index is not bounds checked. */
-const char *hv_msg_getSymbol(const HvMessage *const m, int i);
-
-/** Returns true of the indexed element is a hash. False otherwise. Index is not bounds checked. */
-bool hv_msg_isHash(const HvMessage *const m, int i);
-
-/** Returns the indexed element as a hash value. Index is not bounds checked. */
-hv_uint32_t hv_msg_getHash(const HvMessage *const m, int i);
-
-/** Sets the indexed element to symbol value. Index is not bounds checked. */
-void hv_msg_setSymbol(HvMessage *m, int i, const char *s);
-
-/**
- * Returns true if the message has the given format, in number of elements and type. False otherwise.
- * Valid element types are:
- * 'b': bang
- * 'f': float
- * 's': symbol
- *
- * For example, a message with three floats would have a format of "fff". A single bang is "b".
- * A message with two symbols is "ss". These types can be mixed and matched in any way.
- */
-bool hv_msg_hasFormat(const HvMessage *const m, const char *fmt);
-
-/**
- * Returns a basic string representation of the message.
- * The character array MUST be deallocated by the caller.
- */
-char *hv_msg_toString(const HvMessage *const m);
-
-/** Copy a message onto the stack. The message persists. */
-HvMessage *hv_msg_copy(const HvMessage *const m);
-
-/** Free a copied message. */
-void hv_msg_free(HvMessage *m);
-
-
-
-#if HV_APPLE
-#pragma mark - Heavy Table
-#endif
-
-/**
- * Resizes the table to the given length.
- *
- * Existing contents are copied to the new table. Remaining space is cleared
- * if the table is longer than the original, truncated otherwise.
- *
- * @param tableHash The table identifier.
- * @param newSampleLength The new length of the table, in samples. Must be positive.
- *
- * @return False if the table could not be found. True otherwise.
- */
-bool hv_table_setLength(HeavyContextInterface *c, hv_uint32_t tableHash, hv_uint32_t newSampleLength);
-
-/** Returns a pointer to the raw buffer backing this table. DO NOT free it. */
-float *hv_table_getBuffer(HeavyContextInterface *c, hv_uint32_t tableHash);
-
-/** Returns the length of this table in samples. */
-hv_uint32_t hv_table_getLength(HeavyContextInterface *c, hv_uint32_t tableHash);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // _HEAVY_H_
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvHeavyInternal.h b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvHeavyInternal.h
deleted file mode 100644
index e10b944410..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvHeavyInternal.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _HEAVY_INTERNAL_H_
-#define _HEAVY_INTERNAL_H_
-
-#include "HvHeavy.h"
-#include "HvUtils.h"
-#include "HvTable.h"
-#include "HvMessage.h"
-#include "HvMath.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- *
- */
-HvTable *hv_table_get(HeavyContextInterface *c, hv_uint32_t tableHash);
-
-/**
- *
- */
-void hv_scheduleMessageForReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, HvMessage *m);
-
-/**
- *
- */
-HvMessage *hv_scheduleMessageForObject(HeavyContextInterface *c, const HvMessage *m,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
- int letIndex);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvLightPipe.c b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvLightPipe.c
deleted file mode 100644
index 98de428312..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvLightPipe.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "HvLightPipe.h"
-
-#if __SSE__ || HV_SIMD_SSE
-#include
-#define hv_sfence() _mm_sfence()
-#elif __arm__ || HV_SIMD_NEON
- #if __ARM_ACLE
- #include
- // https://msdn.microsoft.com/en-us/library/hh875058.aspx#BarrierRestrictions
- // http://doxygen.reactos.org/d8/d47/armintr_8h_a02be7ec76ca51842bc90d9b466b54752.html
- #define hv_sfence() __dmb(0xE) /* _ARM_BARRIER_ST */
- #elif defined(__GNUC__)
- #define hv_sfence() __asm__ volatile ("dmb 0xE":::"memory")
- #else
- // http://stackoverflow.com/questions/19965076/gcc-memory-barrier-sync-synchronize-vs-asm-volatile-memory
- #define hv_sfence() __sync_synchronize()
- #endif
-#elif HV_WIN
-// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684208(v=vs.85).aspx
-#define hv_sfence() _WriteBarrier()
-#else
-#define hv_sfence() __asm__ volatile("" : : : "memory")
-#endif
-
-#define HLP_STOP 0
-#define HLP_LOOP 0xFFFFFFFF
-#define HLP_SET_UINT32_AT_BUFFER(a, b) (*((hv_uint32_t *) (a)) = (b))
-#define HLP_GET_UINT32_AT_BUFFER(a) (*((hv_uint32_t *) (a)))
-
-hv_uint32_t hLp_init(HvLightPipe *q, hv_uint32_t numBytes) {
- if (numBytes > 0) {
- q->buffer = (char *) hv_malloc(numBytes);
- hv_assert(q->buffer != NULL);
- HLP_SET_UINT32_AT_BUFFER(q->buffer, HLP_STOP);
- } else {
- q->buffer = NULL;
- }
- q->writeHead = q->buffer;
- q->readHead = q->buffer;
- q->len = numBytes;
- q->remainingBytes = numBytes;
- return numBytes;
-}
-
-void hLp_free(HvLightPipe *q) {
- hv_free(q->buffer);
-}
-
-hv_uint32_t hLp_hasData(HvLightPipe *q) {
- hv_uint32_t x = HLP_GET_UINT32_AT_BUFFER(q->readHead);
- if (x == HLP_LOOP) {
- q->readHead = q->buffer;
- x = HLP_GET_UINT32_AT_BUFFER(q->readHead);
- }
- return x;
-}
-
-char *hLp_getWriteBuffer(HvLightPipe *q, hv_uint32_t bytesToWrite) {
- char *const readHead = q->readHead;
- char *const oldWriteHead = q->writeHead;
- const hv_uint32_t totalByteRequirement = bytesToWrite + 2*sizeof(hv_uint32_t);
-
- // check if there is enough space to write the data in the remaining
- // length of the buffer
- if (totalByteRequirement <= q->remainingBytes) {
- char *const newWriteHead = oldWriteHead + sizeof(hv_uint32_t) + bytesToWrite;
-
- // check if writing would overwrite existing data in the pipe (return NULL if so)
- if ((oldWriteHead < readHead) && (newWriteHead >= readHead)) return NULL;
- else return (oldWriteHead + sizeof(hv_uint32_t));
- } else {
- // there isn't enough space, try looping around to the start
- if (totalByteRequirement <= q->len) {
- if ((oldWriteHead < readHead) || ((q->buffer + totalByteRequirement) > readHead)) {
- return NULL; // overwrite condition
- } else {
- q->writeHead = q->buffer;
- q->remainingBytes = q->len;
- HLP_SET_UINT32_AT_BUFFER(q->buffer, HLP_STOP);
- hv_sfence();
- HLP_SET_UINT32_AT_BUFFER(oldWriteHead, HLP_LOOP);
- return q->buffer + sizeof(hv_uint32_t);
- }
- } else {
- return NULL; // there isn't enough space to write the data
- }
- }
-}
-
-void hLp_produce(HvLightPipe *q, hv_uint32_t numBytes) {
- hv_assert(q->remainingBytes >= (numBytes + 2*sizeof(hv_uint32_t)));
- q->remainingBytes -= (sizeof(hv_uint32_t) + numBytes);
- char *const oldWriteHead = q->writeHead;
- q->writeHead += (sizeof(hv_uint32_t) + numBytes);
- HLP_SET_UINT32_AT_BUFFER(q->writeHead, HLP_STOP);
-
- // save everything before this point to memory
- hv_sfence();
-
- // then save this
- HLP_SET_UINT32_AT_BUFFER(oldWriteHead, numBytes);
-}
-
-char *hLp_getReadBuffer(HvLightPipe *q, hv_uint32_t *numBytes) {
- *numBytes = HLP_GET_UINT32_AT_BUFFER(q->readHead);
- char *const readBuffer = q->readHead + sizeof(hv_uint32_t);
- return readBuffer;
-}
-
-void hLp_consume(HvLightPipe *q) {
- hv_assert(HLP_GET_UINT32_AT_BUFFER(q->readHead) != HLP_STOP);
- q->readHead += sizeof(hv_uint32_t) + HLP_GET_UINT32_AT_BUFFER(q->readHead);
-}
-
-void hLp_reset(HvLightPipe *q) {
- q->writeHead = q->buffer;
- q->readHead = q->buffer;
- q->remainingBytes = q->len;
- memset(q->buffer, 0, q->len);
-}
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvLightPipe.h b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvLightPipe.h
deleted file mode 100644
index 438f7261dc..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvLightPipe.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _HEAVY_LIGHTPIPE_H_
-#define _HEAVY_LIGHTPIPE_H_
-
-#include "HvUtils.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * This pipe assumes that there is only one producer thread and one consumer
- * thread. This data structure does not support any other configuration.
- */
-typedef struct HvLightPipe {
- char *buffer;
- char *writeHead;
- char *readHead;
- hv_uint32_t len;
- hv_uint32_t remainingBytes; // total bytes from write head to end
-} HvLightPipe;
-
-/**
- * Initialise the pipe with a given length, in bytes.
- * @return Returns the size of the pipe in bytes.
- */
-hv_uint32_t hLp_init(HvLightPipe *q, hv_uint32_t numBytes);
-
-/**
- * Frees the internal buffer.
- * @param q The light pipe.
- */
-void hLp_free(HvLightPipe *q);
-
-/**
- * Indicates if data is available for reading.
- * @param q The light pipe.
- *
- * @return Returns the number of bytes available for reading. Zero if no bytes
- * are available.
- */
-hv_uint32_t hLp_hasData(HvLightPipe *q);
-
-/**
- * Returns a pointer to a location in the pipe where numBytes can be written.
- *
- * @param numBytes The number of bytes to be written.
- * @return A pointer to a location where those bytes can be written. Returns
- * NULL if no more space is available. Successive calls to this
- * function may eventually return a valid pointer because the readhead
- * has been advanced on another thread.
- */
-char *hLp_getWriteBuffer(HvLightPipe *q, hv_uint32_t numBytes);
-
-/**
- * Indicates to the pipe how many bytes have been written.
- *
- * @param numBytes The number of bytes written. In general this should be the
- * same value as was passed to the preceeding call to
- * hLp_getWriteBuffer().
- */
-void hLp_produce(HvLightPipe *q, hv_uint32_t numBytes);
-
-/**
- * Returns the current read buffer, indicating the number of bytes available
- * for reading.
- * @param q The light pipe.
- * @param numBytes This value will be filled with the number of bytes available
- * for reading.
- *
- * @return A pointer to the read buffer.
- */
-char *hLp_getReadBuffer(HvLightPipe *q, hv_uint32_t *numBytes);
-
-/**
- * Indicates that the next set of bytes have been read and are no longer needed.
- * @param q The light pipe.
- */
-void hLp_consume(HvLightPipe *q);
-
-// resets the queue to it's initialised state
-// This should be done when only one thread is accessing the pipe.
-void hLp_reset(HvLightPipe *q);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _HEAVY_LIGHTPIPE_H_
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvMath.h b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvMath.h
deleted file mode 100644
index d25de2df98..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvMath.h
+++ /dev/null
@@ -1,736 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _HEAVY_MATH_H_
-#define _HEAVY_MATH_H_
-
-#include "HvUtils.h"
-
-// https://software.intel.com/sites/landingpage/IntrinsicsGuide/
-// https://gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/ARM-NEON-Intrinsics.html
-// http://codesuppository.blogspot.co.uk/2015/02/sse2neonh-porting-guide-and-header-file.html
-
-static inline void __hv_zero_f(hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_setzero_ps();
-#elif HV_SIMD_SSE
- *bOut = _mm_setzero_ps();
-#elif HV_SIMD_NEON
- *bOut = vdupq_n_f32(0.0f);
-#else // HV_SIMD_NONE
- *bOut = 0.0f;
-#endif
-}
-
-static inline void __hv_zero_i(hv_bOuti_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_setzero_si256();
-#elif HV_SIMD_SSE
- *bOut = _mm_setzero_si128();
-#elif HV_SIMD_NEON
- *bOut = vdupq_n_s32(0);
-#else // HV_SIMD_NONE
- *bOut = 0;
-#endif
-}
-
-static inline void __hv_load_f(float *bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_load_ps(bIn);
-#elif HV_SIMD_SSE
- *bOut = _mm_load_ps(bIn);
-#elif HV_SIMD_NEON
- *bOut = vld1q_f32(bIn);
-#else // HV_SIMD_NONE
- *bOut = *bIn;
-#endif
-}
-
-static inline void __hv_store_f(float *bOut, hv_bInf_t bIn) {
-#if HV_SIMD_AVX
- _mm256_store_ps(bOut, bIn);
-#elif HV_SIMD_SSE
- _mm_store_ps(bOut, bIn);
-#elif HV_SIMD_NEON
- vst1q_f32(bOut, bIn);
-#else // HV_SIMD_NONE
- *bOut = bIn;
-#endif
-}
-
-static inline void __hv_log2_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_log2_f() not implemented
-#elif HV_SIMD_SSE
- // https://en.wikipedia.org/wiki/Fast_inverse_square_root
- __m128i a = _mm_castps_si128(bIn);
- __m128i b = _mm_srli_epi32(a, 23);
- __m128i c = _mm_sub_epi32(b, _mm_set1_epi32(127)); // exponent (int)
- __m128 d = _mm_cvtepi32_ps(c); // exponent (float)
- __m128i e = _mm_or_si128(_mm_andnot_si128(_mm_set1_epi32(0xFF800000), a), _mm_set1_epi32(0x3F800000));
- __m128 f = _mm_castsi128_ps(e); // 1+m (float)
- __m128 g = _mm_add_ps(d, f); // e + 1 + m
- __m128 h = _mm_add_ps(g, _mm_set1_ps(-0.9569643f)); // e + 1 + m + (sigma-1)
- *bOut = h;
-#elif HV_SIMD_NEON
- int32x4_t a = vreinterpretq_s32_f32(bIn);
- int32x4_t b = vshrq_n_s32(a, 23);
- int32x4_t c = vsubq_s32(b, vdupq_n_s32(127));
- float32x4_t d = vcvtq_f32_s32(c);
- int32x4_t e = vorrq_s32(vbicq_s32(a, vdupq_n_s32(0xFF800000)), vdupq_n_s32(0x3F800000));
- float32x4_t f = vreinterpretq_f32_s32(e);
- float32x4_t g = vaddq_f32(d, f);
- float32x4_t h = vaddq_f32(g, vdupq_n_f32(-0.9569643f));
- *bOut = h;
-#else // HV_SIMD_NONE
- *bOut = 1.442695040888963f * hv_log_f(bIn);
-#endif
-}
-
-// NOTE(mhroth): this is a pretty ghetto implementation
-static inline void __hv_cos_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_set_ps(
- hv_cos_f(bIn[7]), hv_cos_f(bIn[6]), hv_cos_f(bIn[5]), hv_cos_f(bIn[4]),
- hv_cos_f(bIn[3]), hv_cos_f(bIn[2]), hv_cos_f(bIn[1]), hv_cos_f(bIn[0]));
-#elif HV_SIMD_SSE
- const float *const b = (float *) &bIn;
- *bOut = _mm_set_ps(hv_cos_f(b[3]), hv_cos_f(b[2]), hv_cos_f(b[1]), hv_cos_f(b[0]));
-#elif HV_SIMD_NEON
- *bOut = (float32x4_t) {hv_cos_f(bIn[0]), hv_cos_f(bIn[1]), hv_cos_f(bIn[2]), hv_cos_f(bIn[3])};
-#else // HV_SIMD_NONE
- *bOut = hv_cos_f(bIn);
-#endif
-}
-
-static inline void __hv_acos_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_acos_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_acos_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_acos_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_acos_f(bIn);
-#endif
-}
-
-static inline void __hv_cosh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_cosh_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_cosh_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_cosh_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_cosh_f(bIn);
-#endif
-}
-
-static inline void __hv_acosh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_acosh_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_acosh_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_acosh_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_acosh_f(bIn);
-#endif
-}
-
-static inline void __hv_sin_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_sin_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_sin_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_sin_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_sin_f(bIn);
-#endif
-}
-
-static inline void __hv_asin_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_asin_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_asin_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_asin_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_asin_f(bIn);
-#endif
-}
-
-static inline void __hv_sinh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_sinh_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_sinh_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_sinh_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_sinh_f(bIn);
-#endif
-}
-
-static inline void __hv_asinh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_asinh_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_asinh_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_asinh_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_asinh_f(bIn);
-#endif
-}
-
-static inline void __hv_tan_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_tan_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_tan_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_tan_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_tan_f(bIn);
-#endif
-}
-
-static inline void __hv_atan_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_atan_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_atan_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_atan_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_atan_f(bIn);
-#endif
-}
-
-static inline void __hv_atan2_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_atan2_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_atan2_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_atan2_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_atan2_f(bIn0, bIn1);
-#endif
-}
-
-static inline void __hv_tanh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_tanh_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_tanh_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_tanh_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_tanh_f(bIn);
-#endif
-}
-
-static inline void __hv_atanh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- hv_assert(0); // __hv_atanh_f() not implemented
-#elif HV_SIMD_SSE
- hv_assert(0); // __hv_atanh_f() not implemented
-#elif HV_SIMD_NEON
- hv_assert(0); // __hv_atanh_f() not implemented
-#else // HV_SIMD_NONE
- *bOut = hv_atanh_f(bIn);
-#endif
-}
-
-static inline void __hv_sqrt_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_sqrt_ps(bIn);
-#elif HV_SIMD_SSE
- *bOut = _mm_sqrt_ps(bIn);
-#elif HV_SIMD_NEON
- const float32x4_t y = vrsqrteq_f32(bIn);
- *bOut = vmulq_f32(bIn, vmulq_f32(vrsqrtsq_f32(vmulq_f32(bIn, y), y), y)); // numerical results may be inexact
-#else // HV_SIMD_NONE
- *bOut = hv_sqrt_f(bIn);
-#endif
-}
-
-static inline void __hv_rsqrt_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_rsqrt_ps(bIn);
-#elif HV_SIMD_SSE
- *bOut = _mm_rsqrt_ps(bIn);
-#elif HV_SIMD_NEON
- const float32x4_t y = vrsqrteq_f32(bIn);
- *bOut = vmulq_f32(vrsqrtsq_f32(vmulq_f32(bIn, y), y), y); // numerical results may be inexact
-#else // HV_SIMD_NONE
- *bOut = 1.0f/hv_sqrt_f(bIn);
-#endif
-}
-
-static inline void __hv_abs_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_andnot_ps(_mm256_set1_ps(-0.0f), bIn);
-#elif HV_SIMD_SSE
- *bOut = _mm_andnot_ps(_mm_set1_ps(-0.0f), bIn); // == 1 << 31
-#elif HV_SIMD_NEON
- *bOut = vabsq_f32(bIn);
-#else // HV_SIMD_NONE
- *bOut = hv_abs_f(bIn);
-#endif
-}
-
-static inline void __hv_neg_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_xor_ps(bIn, _mm256_set1_ps(-0.0f));
-#elif HV_SIMD_SSE
- *bOut = _mm_xor_ps(bIn, _mm_set1_ps(-0.0f));
-#elif HV_SIMD_NEON
- *bOut = vnegq_f32(bIn);
-#else // HV_SIMD_NONE
- *bOut = bIn * -1.0f;
-#endif
-}
-
-static inline void __hv_exp_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- float *const b = (float *) hv_alloca(HV_N_SIMD*sizeof(float));
- _mm256_store_ps(b, bIn);
- *bOut = _mm256_set_ps(
- hv_exp_f(b[7]), hv_exp_f(b[6]), hv_exp_f(b[5]), hv_exp_f(b[4]),
- hv_exp_f(b[3]), hv_exp_f(b[2]), hv_exp_f(b[1]), hv_exp_f(b[0]));
-#elif HV_SIMD_SSE
- float *const b = (float *) hv_alloca(HV_N_SIMD*sizeof(float));
- _mm_store_ps(b, bIn);
- *bOut = _mm_set_ps(hv_exp_f(b[3]), hv_exp_f(b[2]), hv_exp_f(b[1]), hv_exp_f(b[0]));
-#elif HV_SIMD_NEON
- *bOut = (float32x4_t) {
- hv_exp_f(bIn[0]),
- hv_exp_f(bIn[1]),
- hv_exp_f(bIn[2]),
- hv_exp_f(bIn[3])};
-#else // HV_SIMD_NONE
- *bOut = hv_exp_f(bIn);
-#endif
-}
-
-static inline void __hv_ceil_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_ceil_ps(bIn);
-#elif HV_SIMD_SSE
- *bOut = _mm_ceil_ps(bIn);
-#elif HV_SIMD_NEON
-#if __ARM_ARCH >= 8
- *bOut = vrndpq_f32(bIn);
-#else
- // A slow NEON implementation of __hv_ceil_f() is being used because
- // the necessary intrinsic cannot be found. It is only available in ARMv8.
- *bOut = (float32x4_t) {hv_ceil_f(bIn[0]), hv_ceil_f(bIn[1]), hv_ceil_f(bIn[2]), hv_ceil_f(bIn[3])};
-#endif // vrndpq_f32
-#else // HV_SIMD_NONE
- *bOut = hv_ceil_f(bIn);
-#endif
-}
-
-static inline void __hv_floor_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_floor_ps(bIn);
-#elif HV_SIMD_SSE
- *bOut = _mm_floor_ps(bIn);
-#elif HV_SIMD_NEON
-#if __ARM_ARCH >= 8
- *bOut = vrndmq_f32(bIn);
-#else
- // A slow implementation of __hv_floor_f() is being used because
- // the necessary intrinsic cannot be found. It is only available from ARMv8.
- *bOut = (float32x4_t) {hv_floor_f(bIn[0]), hv_floor_f(bIn[1]), hv_floor_f(bIn[2]), hv_floor_f(bIn[3])};
-#endif // vrndmq_f32
-#else // HV_SIMD_NONE
- *bOut = hv_floor_f(bIn);
-#endif
-}
-
-// __add~f
-static inline void __hv_add_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_add_ps(bIn0, bIn1);
-#elif HV_SIMD_SSE
- *bOut = _mm_add_ps(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vaddq_f32(bIn0, bIn1);
-#else // HV_SIMD_NONE
- *bOut = bIn0 + bIn1;
-#endif
-}
-
-// __add~i
-static inline void __hv_add_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) {
-#if HV_SIMD_AVX
- __m128i x = _mm_add_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1));
- __m128i y = _mm_add_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1));
- *bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1);
-#elif HV_SIMD_SSE
- *bOut = _mm_add_epi32(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vaddq_s32(bIn0, bIn1);
-#else // HV_SIMD_NONE
- *bOut = bIn0 + bIn1;
-#endif
-}
-
-// __sub~f
-static inline void __hv_sub_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_sub_ps(bIn0, bIn1);
-#elif HV_SIMD_SSE
- *bOut = _mm_sub_ps(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vsubq_f32(bIn0, bIn1);
-#else // HV_SIMD_NONE
- *bOut = bIn0 - bIn1;
-#endif
-}
-
-// __mul~f
-static inline void __hv_mul_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_mul_ps(bIn0, bIn1);
-#elif HV_SIMD_SSE
- *bOut = _mm_mul_ps(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vmulq_f32(bIn0, bIn1);
-#else // HV_SIMD_NONE
- *bOut = bIn0 * bIn1;
-#endif
-}
-
-// __*~i
-static inline void __hv_mul_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) {
-#if HV_SIMD_AVX
- __m128i x = _mm_mullo_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1));
- __m128i y = _mm_mullo_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1));
- *bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1);
-#elif HV_SIMD_SSE
- *bOut = _mm_mullo_epi32(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vmulq_s32(bIn0, bIn1);
-#else // HV_SIMD_NONE
- *bOut = bIn0 * bIn1;
-#endif
-}
-
-// __cast~if
-static inline void __hv_cast_if(hv_bIni_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_cvtepi32_ps(bIn);
-#elif HV_SIMD_SSE
- *bOut = _mm_cvtepi32_ps(bIn);
-#elif HV_SIMD_NEON
- *bOut = vcvtq_f32_s32(bIn);
-#else // HV_SIMD_NONE
- *bOut = (float) bIn;
-#endif
-}
-
-// __cast~fi
-static inline void __hv_cast_fi(hv_bInf_t bIn, hv_bOuti_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_cvtps_epi32(bIn);
-#elif HV_SIMD_SSE
- *bOut = _mm_cvtps_epi32(bIn);
-#elif HV_SIMD_NEON
- *bOut = vcvtq_s32_f32(bIn);
-#else // HV_SIMD_NONE
- *bOut = (int) bIn;
-#endif
-}
-
-static inline void __hv_div_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- __m256 a = _mm256_cmp_ps(bIn1, _mm256_setzero_ps(), _CMP_EQ_OQ);
- __m256 b = _mm256_div_ps(bIn0, bIn1);
- *bOut = _mm256_andnot_ps(a, b);
-#elif HV_SIMD_SSE
- __m128 a = _mm_cmpeq_ps(bIn1, _mm_setzero_ps());
- __m128 b = _mm_div_ps(bIn0, bIn1);
- *bOut = _mm_andnot_ps(a, b);
-#elif HV_SIMD_NEON
- uint32x4_t a = vceqq_f32(bIn1, vdupq_n_f32(0.0f));
- float32x4_t b = vmulq_f32(bIn0, vrecpeq_f32(bIn1)); // NOTE(mhroth): numerical results may be inexact
- *bOut = vreinterpretq_f32_u32(vbicq_u32(vreinterpretq_u32_f32(b), a));
-#else // HV_SIMD_NONE
- *bOut = (bIn1 != 0.0f) ? (bIn0 / bIn1) : 0.0f;
-#endif
-}
-
-static inline void __hv_min_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_min_ps(bIn0, bIn1);
-#elif HV_SIMD_SSE
- *bOut = _mm_min_ps(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vminq_f32(bIn0, bIn1);
-#else // HV_SIMD_NONE
- *bOut = hv_min_f(bIn0, bIn1);
-#endif
-}
-
-static inline void __hv_min_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) {
-#if HV_SIMD_AVX
- __m128i x = _mm_min_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1));
- __m128i y = _mm_min_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1));
- *bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1);
-#elif HV_SIMD_SSE
- *bOut = _mm_min_epi32(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vminq_s32(bIn0, bIn1);
-#else // HV_SIMD_NONE
- *bOut = hv_min_i(bIn0, bIn1);
-#endif
-}
-
-static inline void __hv_max_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_max_ps(bIn0, bIn1);
-#elif HV_SIMD_SSE
- *bOut = _mm_max_ps(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vmaxq_f32(bIn0, bIn1);
-#else // HV_SIMD_NONE
- *bOut = hv_max_f(bIn0, bIn1);
-#endif
-}
-
-static inline void __hv_max_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) {
-#if HV_SIMD_AVX
- __m128i x = _mm_max_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1));
- __m128i y = _mm_max_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1));
- *bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1);
-#elif HV_SIMD_SSE
- *bOut = _mm_max_epi32(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vmaxq_s32(bIn0, bIn1);
-#else // HV_SIMD_NONE
- *bOut = hv_max_i(bIn0, bIn1);
-#endif
-}
-
-static inline void __hv_pow_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- float *b = (float *) hv_alloca(16*sizeof(float));
- _mm256_store_ps(b, bIn0);
- _mm256_store_ps(b+8, bIn1);
- *bOut = _mm256_set_ps(
- hv_pow_f(b[7], b[15]),
- hv_pow_f(b[6], b[14]),
- hv_pow_f(b[5], b[13]),
- hv_pow_f(b[4], b[12]),
- hv_pow_f(b[3], b[11]),
- hv_pow_f(b[2], b[10]),
- hv_pow_f(b[1], b[9]),
- hv_pow_f(b[0], b[8]));
-#elif HV_SIMD_SSE
- float *b = (float *) hv_alloca(8*sizeof(float));
- _mm_store_ps(b, bIn0);
- _mm_store_ps(b+4, bIn1);
- *bOut = _mm_set_ps(
- hv_pow_f(b[3], b[7]),
- hv_pow_f(b[2], b[6]),
- hv_pow_f(b[1], b[5]),
- hv_pow_f(b[0], b[4]));
-#elif HV_SIMD_NEON
- *bOut = (float32x4_t) {
- hv_pow_f(bIn0[0], bIn1[0]),
- hv_pow_f(bIn0[1], bIn1[1]),
- hv_pow_f(bIn0[2], bIn1[2]),
- hv_pow_f(bIn0[3], bIn1[3])};
-#else // HV_SIMD_NONE
- *bOut = hv_pow_f(bIn0, bIn1);
-#endif
-}
-
-static inline void __hv_gt_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_GT_OQ);
-#elif HV_SIMD_SSE
- *bOut = _mm_cmpgt_ps(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vreinterpretq_f32_u32(vcgtq_f32(bIn0, bIn1));
-#else // HV_SIMD_NONE
- *bOut = (bIn0 > bIn1) ? 1.0f : 0.0f;
-#endif
-}
-
-static inline void __hv_gte_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_GE_OQ);
-#elif HV_SIMD_SSE
- *bOut = _mm_cmpge_ps(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vreinterpretq_f32_u32(vcgeq_f32(bIn0, bIn1));
-#else // HV_SIMD_NONE
- *bOut = (bIn0 >= bIn1) ? 1.0f : 0.0f;
-#endif
-}
-
-static inline void __hv_lt_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_LT_OQ);
-#elif HV_SIMD_SSE
- *bOut = _mm_cmplt_ps(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vreinterpretq_f32_u32(vcltq_f32(bIn0, bIn1));
-#else // HV_SIMD_NONE
- *bOut = (bIn0 < bIn1) ? 1.0f : 0.0f;
-#endif
-}
-
-static inline void __hv_lte_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_LE_OQ);
-#elif HV_SIMD_SSE
- *bOut = _mm_cmple_ps(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vreinterpretq_f32_u32(vcleq_f32(bIn0, bIn1));
-#else // HV_SIMD_NONE
- *bOut = (bIn0 <= bIn1) ? 1.0f : 0.0f;
-#endif
-}
-
-static inline void __hv_eq_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_EQ_OQ);
-#elif HV_SIMD_SSE
- *bOut = _mm_cmpeq_ps(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vreinterpretq_f32_u32(vceqq_f32(bIn0, bIn1));
-#else // HV_SIMD_NONE
- *bOut = (bIn0 == bIn1) ? 1.0f : 0.0f;
-#endif
-}
-
-static inline void __hv_neq_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_NEQ_OQ);
-#elif HV_SIMD_SSE
- *bOut = _mm_cmpneq_ps(bIn0, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vreinterpretq_f32_u32(vmvnq_u32(vceqq_f32(bIn0, bIn1)));
-#else // HV_SIMD_NONE
- *bOut = (bIn0 != bIn1) ? 1.0f : 0.0f;
-#endif
-}
-
-static inline void __hv_or_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_or_ps(bIn1, bIn0);
-#elif HV_SIMD_SSE
- *bOut = _mm_or_ps(bIn1, bIn0);
-#elif HV_SIMD_NEON
- *bOut = vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(bIn1), vreinterpretq_u32_f32(bIn0)));
-#else // HV_SIMD_NONE
- if (bIn0 == 0.0f && bIn1 == 0.0f) *bOut = 0.0f;
- else if (bIn0 == 0.0f) *bOut = bIn1;
- else if (bIn1 == 0.0f) *bOut = bIn0;
- else hv_assert(0);
-#endif
-}
-
-static inline void __hv_and_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_and_ps(bIn1, bIn0);
-#elif HV_SIMD_SSE
- *bOut = _mm_and_ps(bIn1, bIn0);
-#elif HV_SIMD_NEON
- *bOut = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(bIn1), vreinterpretq_u32_f32(bIn0)));
-#else // HV_SIMD_NONE
- if (bIn0 == 0.0f || bIn1 == 0.0f) *bOut = 0.0f;
- else if (bIn0 == 1.0f) *bOut = bIn1;
- else if (bIn1 == 1.0f) *bOut = bIn0;
- else hv_assert(0);
-#endif
-}
-
-static inline void __hv_andnot_f(hv_bInf_t bIn0_mask, hv_bInf_t bIn1, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_andnot_ps(bIn0_mask, bIn1);
-#elif HV_SIMD_SSE
- *bOut = _mm_andnot_ps(bIn0_mask, bIn1);
-#elif HV_SIMD_NEON
- *bOut = vreinterpretq_f32_s32(vbicq_s32(vreinterpretq_s32_f32(bIn1), vreinterpretq_s32_f32(bIn0_mask)));
-#else // HV_SIMD_NONE
- *bOut = (bIn0_mask == 0.0f) ? bIn1 : 0.0f;
-#endif
-}
-
-// bOut = (bIn0 * bIn1) + bIn2
-static inline void __hv_fma_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bInf_t bIn2, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
-#if HV_SIMD_FMA
- *bOut = _mm256_fmadd_ps(bIn0, bIn1, bIn2);
-#else
- *bOut = _mm256_add_ps(_mm256_mul_ps(bIn0, bIn1), bIn2);
-#endif // HV_SIMD_FMA
-#elif HV_SIMD_SSE
-#if HV_SIMD_FMA
- *bOut = _mm_fmadd_ps(bIn0, bIn1, bIn2);
-#else
- *bOut = _mm_add_ps(_mm_mul_ps(bIn0, bIn1), bIn2);
-#endif // HV_SIMD_FMA
-#elif HV_SIMD_NEON
-#if __ARM_ARCH >= 8
- *bOut = vfmaq_f32(bIn2, bIn0, bIn1);
-#else
- // NOTE(mhroth): it turns out, fma SUUUUCKS on lesser ARM architectures
- *bOut = vaddq_f32(vmulq_f32(bIn0, bIn1), bIn2);
-#endif
-#else // HV_SIMD_NONE
- *bOut = hv_fma_f(bIn0, bIn1, bIn2);
-#endif
-}
-
-// bOut = (bIn0 * bIn1) - bIn2
-static inline void __hv_fms_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bInf_t bIn2, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
-#if HV_SIMD_FMA
- *bOut = _mm256_fmsub_ps(bIn0, bIn1, bIn2);
-#else
- *bOut = _mm256_sub_ps(_mm256_mul_ps(bIn0, bIn1), bIn2);
-#endif // HV_SIMD_FMA
-#elif HV_SIMD_SSE
-#if HV_SIMD_FMA
- *bOut = _mm_fmsub_ps(bIn0, bIn1, bIn2);
-#else
- *bOut = _mm_sub_ps(_mm_mul_ps(bIn0, bIn1), bIn2);
-#endif // HV_SIMD_FMA
-#elif HV_SIMD_NEON
-#if __ARM_ARCH >= 8
- *bOut = vfmsq_f32(bIn2, bIn0, bIn1);
-#else
- // NOTE(mhroth): it turns out, fma SUUUUCKS on lesser ARM architectures
- *bOut = vsubq_f32(vmulq_f32(bIn0, bIn1), bIn2);
-#endif
-#else // HV_SIMD_NONE
- *bOut = (bIn0 * bIn1) - bIn2;
-#endif
-}
-
-#endif // _HEAVY_MATH_H_
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvMessage.c b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvMessage.c
deleted file mode 100644
index 0f1ac5d7c2..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvMessage.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "HvMessage.h"
-
-HvMessage *msg_init(HvMessage *m, hv_size_t numElements, hv_uint32_t timestamp) {
- m->timestamp = timestamp;
- m->numElements = (hv_uint16_t) numElements;
- m->numBytes = (hv_uint16_t) msg_getCoreSize(numElements);
- return m;
-}
-
-HvMessage *msg_initWithFloat(HvMessage *m, hv_uint32_t timestamp, float f) {
- m->timestamp = timestamp;
- m->numElements = 1;
- m->numBytes = sizeof(HvMessage);
- msg_setFloat(m, 0, f);
- return m;
-}
-
-HvMessage *msg_initWithBang(HvMessage *m, hv_uint32_t timestamp) {
- m->timestamp = timestamp;
- m->numElements = 1;
- m->numBytes = sizeof(HvMessage);
- msg_setBang(m, 0);
- return m;
-}
-
-HvMessage *msg_initWithSymbol(HvMessage *m, hv_uint32_t timestamp, const char *s) {
- m->timestamp = timestamp;
- m->numElements = 1;
- m->numBytes = sizeof(HvMessage) + (hv_uint16_t) hv_strlen(s);
- msg_setSymbol(m, 0, s);
- return m;
-}
-
-HvMessage *msg_initWithHash(HvMessage *m, hv_uint32_t timestamp, hv_uint32_t h) {
- m->timestamp = timestamp;
- m->numElements = 1;
- m->numBytes = sizeof(HvMessage);
- msg_setHash(m, 0, h);
- return m;
-}
-
-void msg_copyToBuffer(const HvMessage *m, char *buffer, hv_size_t len) {
- HvMessage *r = (HvMessage *) buffer;
-
- hv_size_t len_r = msg_getCoreSize(msg_getNumElements(m));
-
- // assert that the message is not already larger than the length of the buffer
- hv_assert(len_r <= len);
-
- // copy the basic message to the buffer
- hv_memcpy(r, m, len_r);
-
- char *p = buffer + len_r; // points to the end of the base message
- for (int i = 0; i < msg_getNumElements(m); ++i) {
- if (msg_isSymbol(m,i)) {
- const hv_size_t symLen = (hv_size_t) hv_strlen(msg_getSymbol(m,i)) + 1; // include the trailing null char
- hv_assert(len_r + symLen <= len); // stay safe!
- hv_strncpy(p, msg_getSymbol(m,i), symLen);
- msg_setSymbol(r, i, p);
- p += symLen;
- len_r += symLen;
- }
- }
-
- r->numBytes = (hv_uint16_t) len_r; // update the message size in memory
-}
-
-// the message is serialised such that all symbol elements are placed in order at the end of the buffer
-HvMessage *msg_copy(const HvMessage *m) {
- const hv_uint32_t heapSize = msg_getSize(m);
- char *r = (char *) hv_malloc(heapSize);
- hv_assert(r != NULL);
- msg_copyToBuffer(m, r, heapSize);
- return (HvMessage *) r;
-}
-
-void msg_free(HvMessage *m) {
- hv_free(m); // because heap messages are serialised in memory, a simple call to free releases the message
-}
-
-bool msg_hasFormat(const HvMessage *m, const char *fmt) {
- hv_assert(fmt != NULL);
- const int n = msg_getNumElements(m);
- for (int i = 0; i < n; ++i) {
- switch (fmt[i]) {
- case 'b': if (!msg_isBang(m, i)) return false; break;
- case 'f': if (!msg_isFloat(m, i)) return false; break;
- case 'h': if (!msg_isHash(m, i)) return false; break;
- case 's': if (!msg_isSymbol(m, i)) return false; break;
- default: return false;
- }
- }
- return (fmt[n] == '\0');
-}
-
-bool msg_compareSymbol(const HvMessage *m, int i, const char *s) {
- switch (msg_getType(m,i)) {
- case HV_MSG_SYMBOL: return !hv_strcmp(msg_getSymbol(m, i), s);
- case HV_MSG_HASH: return (msg_getHash(m,i) == hv_string_to_hash(s));
- default: return false;
- }
-}
-
-bool msg_equalsElement(const HvMessage *m, int i_m, const HvMessage *n, int i_n) {
- if (i_m < msg_getNumElements(m) && i_n < msg_getNumElements(n)) {
- if (msg_getType(m, i_m) == msg_getType(n, i_n)) {
- switch (msg_getType(m, i_m)) {
- case HV_MSG_BANG: return true;
- case HV_MSG_FLOAT: return (msg_getFloat(m, i_m) == msg_getFloat(n, i_n));
- case HV_MSG_SYMBOL: return msg_compareSymbol(m, i_m, msg_getSymbol(n, i_n));
- case HV_MSG_HASH: return msg_getHash(m,i_m) == msg_getHash(n,i_n);
- default: break;
- }
- }
- }
- return false;
-}
-
-void msg_setElementToFrom(HvMessage *n, int i_n, const HvMessage *const m, int i_m) {
- switch (msg_getType(m, i_m)) {
- case HV_MSG_BANG: msg_setBang(n, i_n); break;
- case HV_MSG_FLOAT: msg_setFloat(n, i_n, msg_getFloat(m, i_m)); break;
- case HV_MSG_SYMBOL: msg_setSymbol(n, i_n, msg_getSymbol(m, i_m)); break;
- case HV_MSG_HASH: msg_setHash(n, i_n, msg_getHash(m, i_m));
- default: break;
- }
-}
-
-hv_uint32_t msg_getHash(const HvMessage *const m, int i) {
- hv_assert(i < msg_getNumElements(m)); // invalid index
- switch (msg_getType(m,i)) {
- case HV_MSG_BANG: return 0xFFFFFFFF;
- case HV_MSG_FLOAT: {
- float f = msg_getFloat(m,i);
- return *((hv_uint32_t *) &f);
- }
- case HV_MSG_SYMBOL: return hv_string_to_hash(msg_getSymbol(m,i));
- case HV_MSG_HASH: return (&(m->elem)+i)->data.h;
- default: return 0;
- }
-}
-
-char *msg_toString(const HvMessage *m) {
- hv_assert(msg_getNumElements(m) > 0);
- int *len = (int *) hv_alloca(msg_getNumElements(m)*sizeof(int));
- int size = 0; // the total length of our final buffer
-
- // loop through every element in our list of atoms
- // first loop figures out how long our buffer should be
- for (int i = 0; i < msg_getNumElements(m); i++) {
- // length of our string is each atom plus a space, or \0 on the end
- switch (msg_getType(m, i)) {
- case HV_MSG_BANG: len[i] = hv_snprintf(NULL, 0, "%s", "bang") + 1; break;
- case HV_MSG_FLOAT: len[i] = hv_snprintf(NULL, 0, "%g", msg_getFloat(m, i)) + 1; break;
- case HV_MSG_SYMBOL: len[i] = hv_snprintf(NULL, 0, "%s", msg_getSymbol(m, i)) + 1; break;
- case HV_MSG_HASH: len[i] = hv_snprintf(NULL, 0, "0x%X", msg_getHash(m, i)) + 1; break;
- default: break;
- }
- size += len[i];
- }
-
- hv_assert(size > 0);
-
- // now we do the piecewise concatenation into our final string
- // the final buffer we will pass back after concatenating all strings - user should free it
- char *finalString = (char *) hv_malloc(size*sizeof(char));
- hv_assert(finalString != NULL);
- int pos = 0;
- for (int i = 0; i < msg_getNumElements(m); i++) {
- // put a string representation of each atom into the final string
- switch (msg_getType(m, i)) {
- case HV_MSG_BANG: hv_snprintf(finalString+pos, len[i], "%s", "bang"); break;
- case HV_MSG_FLOAT: hv_snprintf(finalString+pos, len[i], "%g", msg_getFloat(m, i)); break;
- case HV_MSG_SYMBOL: hv_snprintf(finalString+pos, len[i], "%s", msg_getSymbol(m, i)); break;
- case HV_MSG_HASH: hv_snprintf(finalString+pos, len[i], "0x%X", msg_getHash(m, i)); break;
- default: break;
- }
- pos += len[i];
- finalString[pos-1] = 32; // ASCII space
- }
- finalString[size-1] = '\0'; // ensure that the string is null terminated
- return finalString;
-}
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvMessage.h b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvMessage.h
deleted file mode 100644
index a3fdd1c9e6..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvMessage.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _HEAVY_MESSAGE_H_
-#define _HEAVY_MESSAGE_H_
-
-#include "HvUtils.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum ElementType {
- HV_MSG_BANG = 0,
- HV_MSG_FLOAT = 1,
- HV_MSG_SYMBOL = 2,
- HV_MSG_HASH = 3
-} ElementType;
-
-typedef struct Element {
- ElementType type;
- union {
- float f; // float
- const char *s; // symbol
- hv_uint32_t h; // hash
- } data;
-} Element;
-
-typedef struct HvMessage {
- hv_uint32_t timestamp; // the sample at which this message should be processed
- hv_uint16_t numElements;
- hv_uint16_t numBytes; // the total number of bytes that this message occupies in memory, including strings
- Element elem;
-} HvMessage;
-
-typedef struct ReceiverMessagePair {
- hv_uint32_t receiverHash;
- HvMessage msg;
-} ReceiverMessagePair;
-
-#define HV_MESSAGE_ON_STACK(_x) (HvMessage *) hv_alloca(msg_getCoreSize(_x))
-
-/** Returns the number of bytes that this message consumes in memory, not including strings. */
-static inline hv_size_t msg_getCoreSize(hv_size_t numElements) {
- hv_assert(numElements > 0);
- return sizeof(HvMessage) + ((numElements-1) * sizeof(Element));
-}
-
-HvMessage *msg_copy(const HvMessage *m);
-
-/** Copies the message into the given buffer. The buffer must be at least as large as msg_getNumHeapBytes(). */
-void msg_copyToBuffer(const HvMessage *m, char *buffer, hv_size_t len);
-
-void msg_setElementToFrom(HvMessage *n, int indexN, const HvMessage *const m, int indexM);
-
-/** Frees a message on the heap. Does nothing if argument is NULL. */
-void msg_free(HvMessage *m);
-
-HvMessage *msg_init(HvMessage *m, hv_size_t numElements, hv_uint32_t timestamp);
-
-HvMessage *msg_initWithFloat(HvMessage *m, hv_uint32_t timestamp, float f);
-
-HvMessage *msg_initWithBang(HvMessage *m, hv_uint32_t timestamp);
-
-HvMessage *msg_initWithSymbol(HvMessage *m, hv_uint32_t timestamp, const char *s);
-
-HvMessage *msg_initWithHash(HvMessage *m, hv_uint32_t timestamp, hv_uint32_t h);
-
-static inline hv_uint32_t msg_getTimestamp(const HvMessage *m) {
- return m->timestamp;
-}
-
-static inline void msg_setTimestamp(HvMessage *m, hv_uint32_t timestamp) {
- m->timestamp = timestamp;
-}
-
-static inline int msg_getNumElements(const HvMessage *m) {
- return (int) m->numElements;
-}
-
-/** Returns the total number of bytes this message consumes in memory. */
-static inline hv_uint32_t msg_getSize(const HvMessage *m) {
- return m->numBytes;
-}
-
-static inline ElementType msg_getType(const HvMessage *m, int index) {
- hv_assert(index < msg_getNumElements(m)); // invalid index
- return (&(m->elem)+index)->type;
-}
-
-static inline void msg_setBang(HvMessage *m, int index) {
- hv_assert(index < msg_getNumElements(m)); // invalid index
- (&(m->elem)+index)->type = HV_MSG_BANG;
- (&(m->elem)+index)->data.s = NULL;
-}
-
-static inline bool msg_isBang(const HvMessage *m, int index) {
- return (index < msg_getNumElements(m)) ? (msg_getType(m,index) == HV_MSG_BANG) : false;
-}
-
-static inline void msg_setFloat(HvMessage *m, int index, float f) {
- hv_assert(index < msg_getNumElements(m)); // invalid index
- (&(m->elem)+index)->type = HV_MSG_FLOAT;
- (&(m->elem)+index)->data.f = f;
-}
-
-static inline float msg_getFloat(const HvMessage *const m, int index) {
- hv_assert(index < msg_getNumElements(m)); // invalid index
- return (&(m->elem)+index)->data.f;
-}
-
-static inline bool msg_isFloat(const HvMessage *const m, int index) {
- return (index < msg_getNumElements(m)) ? (msg_getType(m,index) == HV_MSG_FLOAT) : false;
-}
-
-static inline void msg_setHash(HvMessage *m, int index, hv_uint32_t h) {
- hv_assert(index < msg_getNumElements(m)); // invalid index
- (&(m->elem)+index)->type = HV_MSG_HASH;
- (&(m->elem)+index)->data.h = h;
-}
-
-static inline bool msg_isHash(const HvMessage *m, int index) {
- return (index < msg_getNumElements(m)) ? (msg_getType(m, index) == HV_MSG_HASH) : false;
-}
-
-/** Returns true if the element is a hash or symbol. False otherwise. */
-static inline bool msg_isHashLike(const HvMessage *m, int index) {
- return (index < msg_getNumElements(m)) ? ((msg_getType(m, index) == HV_MSG_HASH) || (msg_getType(m, index) == HV_MSG_SYMBOL)) : false;
-}
-
-/** Returns a 32-bit hash of the given element. */
-hv_uint32_t msg_getHash(const HvMessage *const m, int i);
-
-static inline void msg_setSymbol(HvMessage *m, int index, const char *s) {
- hv_assert(index < msg_getNumElements(m)); // invalid index
- hv_assert(s != NULL);
- (&(m->elem)+index)->type = HV_MSG_SYMBOL;
- (&(m->elem)+index)->data.s = s;
- // NOTE(mhroth): if the same message container is reused and string reset,
- // then the message size will be overcounted
- m->numBytes += (hv_uint16_t) (hv_strlen(s) + 1); // also count '\0'
-}
-
-static inline const char *msg_getSymbol(const HvMessage *m, int index) {
- hv_assert(index < msg_getNumElements(m)); // invalid index
- return (&(m->elem)+index)->data.s;
-}
-
-static inline bool msg_isSymbol(const HvMessage *m, int index) {
- return (index < msg_getNumElements(m)) ? (msg_getType(m, index) == HV_MSG_SYMBOL) : false;
-}
-
-bool msg_compareSymbol(const HvMessage *m, int i, const char *s);
-
-/** Returns 1 if the element i_m of message m is equal to element i_n of message n. */
-bool msg_equalsElement(const HvMessage *m, int i_m, const HvMessage *n, int i_n);
-
-bool msg_hasFormat(const HvMessage *m, const char *fmt);
-
-/**
- * Create a string representation of the message. Suitable for use by the print object.
- * The resulting string must be freed by the caller.
- */
-char *msg_toString(const HvMessage *msg);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _HEAVY_MESSAGE_H_
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvMessagePool.c b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvMessagePool.c
deleted file mode 100644
index dbddb1d1dc..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvMessagePool.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "HvMessagePool.h"
-#include "HvMessage.h"
-
-// the number of bytes reserved at a time from the pool
-#define MP_BLOCK_SIZE_BYTES 512
-
-#if HV_APPLE
-#pragma mark - MessageList
-#endif
-
-typedef struct MessageListNode {
- char *p;
- struct MessageListNode *next;
-} MessageListNode;
-
-static inline bool ml_hasAvailable(HvMessagePoolList *ml) {
- return (ml->head != NULL);
-}
-
-static char *ml_pop(HvMessagePoolList *ml) {
- MessageListNode *n = ml->head;
- ml->head = n->next;
- n->next = ml->pool;
- ml->pool = n;
- char *const p = n->p;
- n->p = NULL; // set to NULL to make it clear that this node does not have a valid buffer
- return p;
-}
-
-/** Push a MessageListNode with the given pointer onto the head of the queue. */
-static void ml_push(HvMessagePoolList *ml, void *p) {
- MessageListNode *n = NULL;
- if (ml->pool != NULL) {
- // take an empty MessageListNode from the pool
- n = ml->pool;
- ml->pool = n->next;
- } else {
- // a MessageListNode is not available, allocate one
- n = (MessageListNode *) hv_malloc(sizeof(MessageListNode));
- hv_assert(n != NULL);
- }
- n->p = (char *) p;
- n->next = ml->head;
- ml->head = n; // push to the front of the queue
-}
-
-static void ml_free(HvMessagePoolList *ml) {
- if (ml != NULL) {
- while (ml_hasAvailable(ml)) {
- ml_pop(ml);
- }
- while (ml->pool != NULL) {
- MessageListNode *n = ml->pool;
- ml->pool = n->next;
- hv_free(n);
- }
- }
-}
-
-#if HV_APPLE
-#pragma mark - HvMessagePool
-#endif
-
-static hv_size_t mp_messagelistIndexForSize(hv_size_t byteSize) {
- return (hv_size_t) hv_max_i((hv_min_max_log2((hv_uint32_t) byteSize) - 5), 0);
-}
-
-hv_size_t mp_init(HvMessagePool *mp, hv_size_t numKB) {
- mp->bufferSize = numKB * 1024;
- mp->buffer = (char *) hv_malloc(mp->bufferSize);
- hv_assert(mp->buffer != NULL);
- mp->bufferIndex = 0;
-
- // initialise all message lists
- for (int i = 0; i < MP_NUM_MESSAGE_LISTS; i++) {
- mp->lists[i].head = NULL;
- mp->lists[i].pool = NULL;
- }
-
- return mp->bufferSize;
-}
-
-void mp_free(HvMessagePool *mp) {
- hv_free(mp->buffer);
- for (int i = 0; i < MP_NUM_MESSAGE_LISTS; i++) {
- ml_free(&mp->lists[i]);
- }
-}
-
-void mp_freeMessage(HvMessagePool *mp, HvMessage *m) {
- const hv_size_t b = msg_getSize(m); // the number of bytes that a message occupies in memory
- const hv_size_t i = mp_messagelistIndexForSize(b); // the HvMessagePoolList index in the pool
- HvMessagePoolList *ml = &mp->lists[i];
- const hv_size_t chunkSize = 32 << i;
- hv_memclear(m, chunkSize); // clear the chunk, just in case
- ml_push(ml, m);
-}
-
-HvMessage *mp_addMessage(HvMessagePool *mp, const HvMessage *m) {
- const hv_size_t b = msg_getSize(m);
- // determine the message list index to allocate data from based on the msg size
- // smallest chunk size is 32 bytes
- const hv_size_t i = mp_messagelistIndexForSize(b);
-
- hv_assert(i < MP_NUM_MESSAGE_LISTS); // how many chunk sizes do we want to support? 32, 64, 128, 256 at the moment
- HvMessagePoolList *ml = &mp->lists[i];
- const hv_size_t chunkSize = 32 << i;
-
- if (ml_hasAvailable(ml)) {
- char *buf = ml_pop(ml);
- msg_copyToBuffer(m, buf, chunkSize);
- return (HvMessage *) buf;
- } else {
- // if no appropriately sized buffer is immediately available, increase the size of the used buffer
- const hv_size_t newIndex = mp->bufferIndex + MP_BLOCK_SIZE_BYTES;
- hv_assert((newIndex <= mp->bufferSize) &&
- "The message pool buffer size has been exceeded. The context cannot store more messages. "
- "Try using the new_with_options() initialiser with a larger pool size (default is 10KB).");
-
- for (hv_size_t j = mp->bufferIndex; j < newIndex; j += chunkSize) {
- ml_push(ml, mp->buffer + j); // push new nodes onto the list with chunk pointers
- }
- mp->bufferIndex = newIndex;
- char *buf = ml_pop(ml);
- msg_copyToBuffer(m, buf, chunkSize);
- return (HvMessage *) buf;
- }
-}
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvMessagePool.h b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvMessagePool.h
deleted file mode 100644
index 693e470e12..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvMessagePool.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _MESSAGE_POOL_H_
-#define _MESSAGE_POOL_H_
-
-#include "HvUtils.h"
-
-#ifdef HV_MP_NUM_MESSAGE_LISTS
-#define MP_NUM_MESSAGE_LISTS HV_MP_NUM_MESSAGE_LISTS
-#else // HV_MP_NUM_MESSAGE_LISTS
-#define MP_NUM_MESSAGE_LISTS 4
-#endif // HV_MP_NUM_MESSAGE_LISTS
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct HvMessagePoolList {
- struct MessageListNode *head; // list of currently available blocks
- struct MessageListNode *pool; // list of currently used blocks
-} HvMessagePoolList;
-
-typedef struct HvMessagePool {
- char *buffer; // the buffer of all messages
- hv_size_t bufferSize; // in bytes
- hv_size_t bufferIndex; // the number of total reserved bytes
-
- HvMessagePoolList lists[MP_NUM_MESSAGE_LISTS];
-} HvMessagePool;
-
-/**
- * The HvMessagePool is a basic memory management system. It reserves a large block of memory at initialisation
- * and proceeds to divide this block into smaller chunks (usually 512 bytes) as they are needed. These chunks are
- * further divided into 32, 64, 128, or 256 sections. Each of these sections is managed by a HvMessagePoolList (MPL).
- * An MPL is a linked-list data structure which is initialised such that its own pool of listnodes is filled with nodes
- * that point at each subblock (e.g. each 32-byte block of a 512-block chunk).
- *
- * HvMessagePool is loosely inspired by TCMalloc. http://goog-perftools.sourceforge.net/doc/tcmalloc.html
- */
-
-hv_size_t mp_init(struct HvMessagePool *mp, hv_size_t numKB);
-
-void mp_free(struct HvMessagePool *mp);
-
-/**
- * Adds a message to the pool and returns a pointer to the copy. Returns NULL
- * if no space was available in the pool.
- */
-struct HvMessage *mp_addMessage(struct HvMessagePool *mp, const struct HvMessage *m);
-
-void mp_freeMessage(struct HvMessagePool *mp, struct HvMessage *m);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _MESSAGE_POOL_H_
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvMessageQueue.c b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvMessageQueue.c
deleted file mode 100644
index 2eeab8ff8a..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvMessageQueue.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "HvMessageQueue.h"
-
-hv_size_t mq_initWithPoolSize(HvMessageQueue *q, hv_size_t poolSizeKB) {
- hv_assert(poolSizeKB > 0);
- q->head = NULL;
- q->tail = NULL;
- q->pool = NULL;
- return mp_init(&q->mp, poolSizeKB);
-}
-
-void mq_free(HvMessageQueue *q) {
- mq_clear(q);
- while (q->pool != NULL) {
- MessageNode *n = q->pool;
- q->pool = q->pool->next;
- hv_free(n);
- }
- mp_free(&q->mp);
-}
-
-static MessageNode *mq_getOrCreateNodeFromPool(HvMessageQueue *q) {
- if (q->pool == NULL) {
- // if necessary, create a new empty node
- q->pool = (MessageNode *) hv_malloc(sizeof(MessageNode));
- hv_assert(q->pool != NULL);
- q->pool->next = NULL;
- }
- MessageNode *node = q->pool;
- q->pool = q->pool->next;
- return node;
-}
-
-int mq_size(HvMessageQueue *q) {
- int size = 0;
- MessageNode *n = q->head;
- while (n != NULL) {
- ++size;
- n = n->next;
- }
- return size;
-}
-
-HvMessage *mq_addMessage(HvMessageQueue *q, const HvMessage *m, int let,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
- MessageNode *node = mq_getOrCreateNodeFromPool(q);
- node->m = mp_addMessage(&q->mp, m);
- node->let = let;
- node->sendMessage = sendMessage;
- node->prev = NULL;
- node->next = NULL;
-
- if (q->tail != NULL) {
- // the list already contains elements
- q->tail->next = node;
- node->prev = q->tail;
- q->tail = node;
- } else {
- // the list is empty
- node->prev = NULL;
- q->head = node;
- q->tail = node;
- }
- return mq_node_getMessage(node);
-}
-
-HvMessage *mq_addMessageByTimestamp(HvMessageQueue *q, const HvMessage *m, int let,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
- if (mq_hasMessage(q)) {
- MessageNode *n = mq_getOrCreateNodeFromPool(q);
- n->m = mp_addMessage(&q->mp, m);
- n->let = let;
- n->sendMessage = sendMessage;
-
- if (msg_getTimestamp(m) < msg_getTimestamp(q->head->m)) {
- // the message occurs before the current head
- n->next = q->head;
- q->head->prev = n;
- n->prev = NULL;
- q->head = n;
- } else if (msg_getTimestamp(m) >= msg_getTimestamp(q->tail->m)) {
- // the message occurs after the current tail
- n->next = NULL;
- n->prev = q->tail;
- q->tail->next = n;
- q->tail = n;
- } else {
- // the message occurs somewhere between the head and tail
- MessageNode *node = q->head;
- while (node != NULL) {
- if (msg_getTimestamp(m) < msg_getTimestamp(node->next->m)) {
- MessageNode *r = node->next;
- node->next = n;
- n->next = r;
- n->prev = node;
- r->prev = n;
- break;
- }
- node = node->next;
- }
- }
- return n->m;
- } else {
- // add a message to the head
- return mq_addMessage(q, m, let, sendMessage);
- }
-}
-
-void mq_pop(HvMessageQueue *q) {
- if (mq_hasMessage(q)) {
- MessageNode *n = q->head;
-
- mp_freeMessage(&q->mp, n->m);
- n->m = NULL;
-
- n->let = 0;
- n->sendMessage = NULL;
-
- q->head = n->next;
- if (q->head == NULL) {
- q->tail = NULL;
- } else {
- q->head->prev = NULL;
- }
- n->next = q->pool;
- n->prev = NULL;
- q->pool = n;
- }
-}
-
-bool mq_removeMessage(HvMessageQueue *q, HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
- if (mq_hasMessage(q)) {
- if (mq_node_getMessage(q->head) == m) { // msg in head node
- // only remove the message if sendMessage is the same as the stored one,
- // if the sendMessage argument is NULL, it is not checked and will remove any matching message pointer
- if (sendMessage == NULL || q->head->sendMessage == sendMessage) {
- mq_pop(q);
- return true;
- }
- } else {
- MessageNode *prevNode = q->head;
- MessageNode *currNode = q->head->next;
- while ((currNode != NULL) && (currNode->m != m)) {
- prevNode = currNode;
- currNode = currNode->next;
- }
- if (currNode != NULL) {
- if (sendMessage == NULL || currNode->sendMessage == sendMessage) {
- mp_freeMessage(&q->mp, m);
- currNode->m = NULL;
- currNode->let = 0;
- currNode->sendMessage = NULL;
- if (currNode == q->tail) { // msg in tail node
- prevNode->next = NULL;
- q->tail = prevNode;
- } else { // msg in middle node
- prevNode->next = currNode->next;
- currNode->next->prev = prevNode;
- }
- currNode->next = (q->pool == NULL) ? NULL : q->pool;
- currNode->prev = NULL;
- q->pool = currNode;
- return true;
- }
- }
- }
- }
- return false;
-}
-
-void mq_clear(HvMessageQueue *q) {
- while (mq_hasMessage(q)) {
- mq_pop(q);
- }
-}
-
-void mq_clearAfter(HvMessageQueue *q, const hv_uint32_t timestamp) {
- MessageNode *n = q->tail;
- while (n != NULL && timestamp <= msg_getTimestamp(n->m)) {
- // free the node's message
- mp_freeMessage(&q->mp, n->m);
- n->m = NULL;
- n->let = 0;
- n->sendMessage = NULL;
-
- // the tail points at the previous node
- q->tail = n->prev;
-
- // put the node back in the pool
- n->next = q->pool;
- n->prev = NULL;
- if (q->pool != NULL) q->pool->prev = n;
- q->pool = n;
-
- // update the tail node
- n = q->tail;
- }
-
- if (q->tail == NULL) q->head = NULL;
-}
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvMessageQueue.h b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvMessageQueue.h
deleted file mode 100644
index a35e4aa579..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvMessageQueue.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _MESSAGE_QUEUE_H_
-#define _MESSAGE_QUEUE_H_
-
-#include "HvMessage.h"
-#include "HvMessagePool.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-class HeavyContextInterface;
-#else
-typedef struct HeavyContextInterface HeavyContextInterface;
-#endif
-
-typedef struct MessageNode {
- struct MessageNode *prev; // doubly linked list
- struct MessageNode *next;
- HvMessage *m;
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *);
- int let;
-} MessageNode;
-
-/** A doubly linked list containing scheduled messages. */
-typedef struct HvMessageQueue {
- MessageNode *head; // the head of the queue
- MessageNode *tail; // the tail of the queue
- MessageNode *pool; // the head of the reserve pool
- HvMessagePool mp;
-} HvMessageQueue;
-
-hv_size_t mq_initWithPoolSize(HvMessageQueue *q, hv_size_t poolSizeKB);
-
-void mq_free(HvMessageQueue *q);
-
-int mq_size(HvMessageQueue *q);
-
-static inline HvMessage *mq_node_getMessage(MessageNode *n) {
- return n->m;
-}
-
-static inline int mq_node_getLet(MessageNode *n) {
- return n->let;
-}
-
-static inline bool mq_hasMessage(HvMessageQueue *q) {
- return (q->head != NULL);
-}
-
-// true if there is a message and it occurs before (<) timestamp
-static inline bool mq_hasMessageBefore(HvMessageQueue *const q, const hv_uint32_t timestamp) {
- return mq_hasMessage(q) && (msg_getTimestamp(mq_node_getMessage(q->head)) < timestamp);
-}
-
-static inline MessageNode *mq_peek(HvMessageQueue *q) {
- return q->head;
-}
-
-/** Appends the message to the end of the queue. */
-HvMessage *mq_addMessage(HvMessageQueue *q, const HvMessage *m, int let,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
-
-/** Insert in ascending order the message acccording to its timestamp. */
-HvMessage *mq_addMessageByTimestamp(HvMessageQueue *q, const HvMessage *m, int let,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
-
-/** Pop the message at the head of the queue (and free its memory). */
-void mq_pop(HvMessageQueue *q);
-
-/** Remove a message from the queue (and free its memory) */
-bool mq_removeMessage(HvMessageQueue *q, HvMessage *m,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
-
-/** Clears (and frees) all messages in the queue. */
-void mq_clear(HvMessageQueue *q);
-
-/** Removes all messages occuring at or after the given timestamp. */
-void mq_clearAfter(HvMessageQueue *q, const hv_uint32_t timestamp);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _MESSAGE_QUEUE_H_
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvSignalPhasor.c b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvSignalPhasor.c
deleted file mode 100644
index b763b95a16..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvSignalPhasor.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "HvSignalPhasor.h"
-
-#define HV_PHASOR_2_32 4294967296.0
-
-#if HV_SIMD_AVX
-static void sPhasor_updatePhase(SignalPhasor *o, float p) {
- o->phase = _mm256_set1_ps(p+1.0f); // o->phase is in range [1,2]
-#elif HV_SIMD_SSE
- static void sPhasor_updatePhase(SignalPhasor *o, hv_uint32_t p) {
- o->phase = _mm_set1_epi32(p);
-#elif HV_SIMD_NEON
- static void sPhasor_updatePhase(SignalPhasor *o, hv_uint32_t p) {
- o->phase = vdupq_n_u32(p);
-#else // HV_SIMD_NONE
- static void sPhasor_updatePhase(SignalPhasor *o, hv_uint32_t p) {
- o->phase = p;
-#endif
-}
-
-// input phase is in the range of [0,1]. It is independent of o->phase.
-#if HV_SIMD_AVX
-static void sPhasor_k_updatePhase(SignalPhasor *o, float p) {
- o->phase = _mm256_set_ps(
- p+1.0f+7.0f*o->step.f2sc, p+1.0f+6.0f*o->step.f2sc,
- p+1.0f+5.0f*o->step.f2sc, p+1.0f+4.0f*o->step.f2sc,
- p+1.0f+3.0f*o->step.f2sc, p+1.0f+2.0f*o->step.f2sc,
- p+1.0f+o->step.f2sc, p+1.0f);
-
- // ensure that o->phase is still in range [1,2]
- o->phase = _mm256_or_ps(_mm256_andnot_ps(
- _mm256_set1_ps(-INFINITY), o->phase), _mm256_set1_ps(1.0f));
-#elif HV_SIMD_SSE
-static void sPhasor_k_updatePhase(SignalPhasor *o, hv_uint32_t p) {
- o->phase = _mm_set_epi32(3*o->step.s+p, 2*o->step.s+p, o->step.s+p, p);
-#elif HV_SIMD_NEON
-static void sPhasor_k_updatePhase(SignalPhasor *o, hv_uint32_t p) {
- o->phase = (uint32x4_t) {p, o->step.s+p, 2*o->step.s+p, 3*o->step.s+p};
-#else // HV_SIMD_NONE
-static void sPhasor_k_updatePhase(SignalPhasor *o, hv_uint32_t p) {
- o->phase = p;
-#endif
-}
-
-static void sPhasor_k_updateFrequency(SignalPhasor *o, float f, double r) {
-#if HV_SIMD_AVX
- o->step.f2sc = (float) (f/r);
- o->inc = _mm256_set1_ps((float) (8.0f*f/r));
- sPhasor_k_updatePhase(o, o->phase[0]);
-#elif HV_SIMD_SSE
- o->step.s = (hv_int32_t) (f*(HV_PHASOR_2_32/r));
- o->inc = _mm_set1_epi32(4*o->step.s);
- const hv_uint32_t *const p = (hv_uint32_t *) &o->phase;
- sPhasor_k_updatePhase(o, p[0]);
-#elif HV_SIMD_NEON
- o->step.s = (hv_int32_t) (f*(HV_PHASOR_2_32/r));
- o->inc = vdupq_n_s32(4*o->step.s);
- sPhasor_k_updatePhase(o, vgetq_lane_u32(o->phase, 0));
-#else // HV_SIMD_NONE
- o->step.s = (hv_int32_t) (f*(HV_PHASOR_2_32/r));
- o->inc = o->step.s;
- // no need to update phase
-#endif
-}
-
-hv_size_t sPhasor_init(SignalPhasor *o, double samplerate) {
-#if HV_SIMD_AVX
- o->phase = _mm256_set1_ps(1.0f);
- o->inc = _mm256_setzero_ps();
- o->step.f2sc = (float) (1.0/samplerate);
-#elif HV_SIMD_SSE
- o->phase = _mm_setzero_si128();
- o->inc = _mm_setzero_si128();
- o->step.f2sc = (float) (HV_PHASOR_2_32/samplerate);
-#elif HV_SIMD_NEON
- o->phase = vdupq_n_u32(0);
- o->inc = vdupq_n_s32(0);
- o->step.f2sc = (float) (HV_PHASOR_2_32/samplerate);
-#else // HV_SIMD_NONE
- o->phase = 0;
- o->inc = 0;
- o->step.f2sc = (float) (HV_PHASOR_2_32/samplerate);
-#endif
- return 0;
-}
-
-void sPhasor_onMessage(HeavyContextInterface *_c, SignalPhasor *o, int letIn, const HvMessage *m) {
- if (letIn == 1) {
- if (msg_isFloat(m,0)) {
- float p = msg_getFloat(m,0);
- while (p < 0.0f) p += 1.0f; // wrap phase to [0,1]
- while (p > 1.0f) p -= 1.0f;
-#if HV_SIMD_AVX
- sPhasor_updatePhase(o, p);
-#else // HV_SIMD_SSE || HV_SIMD_NEON || HV_SIMD_NONE
- sPhasor_updatePhase(o, (hv_uint32_t) (p * HV_PHASOR_2_32));
-#endif
- }
- }
-}
-
-hv_size_t sPhasor_k_init(SignalPhasor *o, float frequency, double samplerate) {
- __hv_zero_i((hv_bOuti_t) &o->phase);
- sPhasor_k_updateFrequency(o, frequency, samplerate);
- return 0;
-}
-
-void sPhasor_k_onMessage(HeavyContextInterface *_c, SignalPhasor *o, int letIn, const HvMessage *m) {
- if (msg_isFloat(m,0)) {
- switch (letIn) {
- case 0: sPhasor_k_updateFrequency(o, msg_getFloat(m,0), hv_getSampleRate(_c)); break;
- case 1: {
- float p = msg_getFloat(m,0);
- while (p < 0.0f) p += 1.0f; // wrap phase to [0,1]
- while (p > 1.0f) p -= 1.0f;
-#if HV_SIMD_AVX
- sPhasor_k_updatePhase(o, p);
-#else // HV_SIMD_SSE || HV_SIMD_NEON || HV_SIMD_NONE
- sPhasor_k_updatePhase(o, (hv_uint32_t) (p * HV_PHASOR_2_32));
-#endif
- break;
- }
- default: break;
- }
- }
-}
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvSignalPhasor.h b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvSignalPhasor.h
deleted file mode 100644
index 08c6464978..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvSignalPhasor.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _HEAVY_SIGNAL_PHASOR_H_
-#define _HEAVY_SIGNAL_PHASOR_H_
-
-#include "HvHeavyInternal.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct SignalPhasor {
-#if HV_SIMD_AVX
- __m256 phase; // current phase
- __m256 inc; // phase increment
-#elif HV_SIMD_SSE
- __m128i phase;
- __m128i inc;
-#elif HV_SIMD_NEON
- uint32x4_t phase;
- int32x4_t inc;
-#else // HV_SIMD_NONE
- hv_uint32_t phase;
- hv_int32_t inc;
-#endif
- union {
- float f2sc; // float to step conversion (used for __phasor~f)
- hv_int32_t s; // step value (used for __phasor_k~f)
- } step;
-} SignalPhasor;
-
-hv_size_t sPhasor_init(SignalPhasor *o, double samplerate);
-
-hv_size_t sPhasor_k_init(SignalPhasor *o, float frequency, double samplerate);
-
-void sPhasor_k_onMessage(HeavyContextInterface *_c, SignalPhasor *o, int letIn, const HvMessage *m);
-
-void sPhasor_onMessage(HeavyContextInterface *_c, SignalPhasor *o, int letIn, const HvMessage *m);
-
-static inline void __hv_phasor_f(SignalPhasor *o, hv_bInf_t bIn, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- __m256 p = _mm256_mul_ps(bIn, _mm256_set1_ps(o->step.f2sc)); // a b c d e f g h
-
- __m256 z = _mm256_setzero_ps();
-
- // http://stackoverflow.com/questions/11906814/how-to-rotate-an-sse-avx-vector
- __m256 a = _mm256_permute_ps(p, _MM_SHUFFLE(2,1,0,3)); // d a b c h e f g
- __m256 b = _mm256_permute2f128_ps(a, a, 0x01); // h e f g d a b c
- __m256 c = _mm256_blend_ps(a, b, 0x10); // d a b c d e f g
- __m256 d = _mm256_blend_ps(c, z, 0x01); // 0 a b c d e f g
- __m256 e = _mm256_add_ps(p, d); // a (a+b) (b+c) (c+d) (d+e) (e+f) (f+g) (g+h)
-
- __m256 f = _mm256_permute_ps(e, _MM_SHUFFLE(1,0,3,2)); // (b+c) (c+d) a (a+b) (f+g) (g+h) (d+e) (e+f)
- __m256 g = _mm256_permute2f128_ps(f, f, 0x01); // (f+g) (g+h) (d+e) (e+f) (b+c) (c+d) a (a+b)
- __m256 h = _mm256_blend_ps(f, g, 0x33); // (b+c) (c+d) a (a+b) (b+c) (c+d) (d+e) (e+f)
- __m256 i = _mm256_blend_ps(h, z, 0x03); // 0 0 a (a+b) (b+c) (c+d) (d+e) (e+f)
- __m256 j = _mm256_add_ps(e, i); // a (a+b) (a+b+c) (a+b+c+d) (b+c+d+e) (c+d+e+f) (d+e+f+g) (e+f+g+h)
-
- __m256 k = _mm256_permute2f128_ps(j, z, 0x02); // 0 0 0 0 a (a+b) (a+b+c) (a+b+c+d) (b+c+d+e)
- __m256 m = _mm256_add_ps(j, k); // a (a+b) (a+b+c) (a+b+c+d) (a+b+c+d+e) (a+b+c+d+e+f) (a+b+c+d+e+f+g) (a+b+c+d+e+f+g+h)
-
- __m256 n = _mm256_or_ps(_mm256_andnot_ps(
- _mm256_set1_ps(-INFINITY),
- _mm256_add_ps(o->phase, m)),
- _mm256_set1_ps(1.0f));
-
- *bOut = _mm256_sub_ps(n, _mm256_set1_ps(1.0f));
-
- __m256 x = _mm256_permute_ps(n, _MM_SHUFFLE(3,3,3,3));
- o->phase = _mm256_permute2f128_ps(x, x, 0x11);
-#elif HV_SIMD_SSE
- __m128i p = _mm_cvtps_epi32(_mm_mul_ps(bIn, _mm_set1_ps(o->step.f2sc))); // convert frequency to step
- p = _mm_add_epi32(p, _mm_slli_si128(p, 4)); // add incremental steps to phase (prefix sum)
- p = _mm_add_epi32(p, _mm_slli_si128(p, 8)); // http://stackoverflow.com/questions/10587598/simd-prefix-sum-on-intel-cpu?rq=1
- p = _mm_add_epi32(o->phase, p);
- *bOut = _mm_sub_ps(_mm_castsi128_ps(
- _mm_or_si128(_mm_srli_epi32(p, 9),
- _mm_set_epi32(0x3F800000, 0x3F800000, 0x3F800000, 0x3F800000))),
- _mm_set1_ps(1.0f));
- o->phase = _mm_shuffle_epi32(p, _MM_SHUFFLE(3,3,3,3));
-#elif HV_SIMD_NEON
- int32x4_t p = vcvtq_s32_f32(vmulq_n_f32(bIn, o->step.f2sc));
- p = vaddq_s32(p, vextq_s32(vdupq_n_s32(0), p, 3)); // http://stackoverflow.com/questions/11259596/arm-neon-intrinsics-rotation
- p = vaddq_s32(p, vextq_s32(vdupq_n_s32(0), p, 2));
- uint32x4_t pp = vaddq_u32(o->phase, vreinterpretq_u32_s32(p));
- *bOut = vsubq_f32(vreinterpretq_f32_u32(vorrq_u32(vshrq_n_u32(pp, 9), vdupq_n_u32(0x3F800000))), vdupq_n_f32(1.0f));
- o->phase = vdupq_n_u32(pp[3]);
-#else // HV_SIMD_NONE
- const hv_uint32_t p = (o->phase >> 9) | 0x3F800000;
- *bOut = *((float *) (&p)) - 1.0f;
- o->phase += ((int) (bIn * o->step.f2sc));
-#endif
-}
-
-static inline void __hv_phasor_k_f(SignalPhasor *o, hv_bOutf_t bOut) {
-#if HV_SIMD_AVX
- *bOut = _mm256_sub_ps(o->phase, _mm256_set1_ps(1.0f));
- o->phase = _mm256_or_ps(_mm256_andnot_ps(
- _mm256_set1_ps(-INFINITY),
- _mm256_add_ps(o->phase, o->inc)),
- _mm256_set1_ps(1.0f));
-#elif HV_SIMD_SSE
- *bOut = _mm_sub_ps(_mm_castsi128_ps(
- _mm_or_si128(_mm_srli_epi32(o->phase, 9),
- _mm_set_epi32(0x3F800000, 0x3F800000, 0x3F800000, 0x3F800000))),
- _mm_set1_ps(1.0f));
- o->phase = _mm_add_epi32(o->phase, o->inc);
-#elif HV_SIMD_NEON
- *bOut = vsubq_f32(vreinterpretq_f32_u32(
- vorrq_u32(vshrq_n_u32(o->phase, 9),
- vdupq_n_u32(0x3F800000))),
- vdupq_n_f32(1.0f));
- o->phase = vaddq_u32(o->phase, vreinterpretq_u32_s32(o->inc));
-#else // HV_SIMD_NONE
- const hv_uint32_t p = (o->phase >> 9) | 0x3F800000;
- *bOut = *((float *) (&p)) - 1.0f;
- o->phase += o->inc;
-#endif
-}
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // _HEAVY_SIGNAL_PHASOR_H_
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvSignalVar.c b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvSignalVar.c
deleted file mode 100644
index 393cd23424..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvSignalVar.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "HvSignalVar.h"
-
-// __var~f
-
-static void sVarf_update(SignalVarf *o, float k, float step, bool reverse) {
-#if HV_SIMD_AVX
- if (reverse) o->v = _mm256_setr_ps(k+7.0f*step, k+6.0f*step, k+5.0f*step, k+4.0f*step, k+3.0f*step, k+2.0f*step, k+step, k);
- else o->v = _mm256_set_ps(k+7.0f*step, k+6.0f*step, k+5.0f*step, k+4.0f*step, k+3.0f*step, k+2.0f*step, k+step, k);
-#elif HV_SIMD_SSE
- if (reverse) o->v = _mm_setr_ps(k+3.0f*step, k+2.0f*step, k+step, k);
- else o->v = _mm_set_ps(k+3.0f*step, k+2.0f*step, k+step, k);
-#elif HV_SIMD_NEON
- if (reverse) o->v = (float32x4_t) {3.0f*step+k, 2.0f*step+k, step+k, k};
- else o->v = (float32x4_t) {k, step+k, 2.0f*step+k, 3.0f*step+k};
-#else // HV_SIMD_NONE
- o->v = k;
-#endif
-}
-
-hv_size_t sVarf_init(SignalVarf *o, float k, float step, bool reverse) {
- sVarf_update(o, k, step, reverse);
- return 0;
-}
-
-void sVarf_onMessage(HeavyContextInterface *_c, SignalVarf *o, const HvMessage *m) {
- if (msg_isFloat(m,0)) {
- sVarf_update(o, msg_getFloat(m,0), msg_isFloat(m,1) ? msg_getFloat(m,1) : 0.0f, msg_getNumElements(m) == 3);
- }
-}
-
-
-
-// __var~i
-
-static void sVari_update(SignalVari *o, int k, int step, bool reverse) {
-#if HV_SIMD_AVX
- if (reverse) o->v = _mm256_setr_epi32(k+7*step, k+6*step, k+5*step, k+4*step, k+3*step, k+2*step, k+step, k);
- else o->v = _mm256_set_epi32(k+7*step, k+6*step, k+5*step, k+4*step, k+3*step, k+2*step, k+step, k);
-#elif HV_SIMD_SSE
- if (reverse) o->v = _mm_setr_epi32(k+3*step, k+2*step, k+step, k);
- else o->v = _mm_set_epi32(k+3*step, k+2*step, k+step, k);
-#elif HV_SIMD_NEON
- if (reverse) o->v = (int32x4_t) {3*step+k, 2*step+k, step+k, k};
- else o->v = (int32x4_t) {k, step+k, 2*step+k, 3*step+k};
-#else // HV_SIMD_NEON
- o->v = k;
-#endif
-}
-
-hv_size_t sVari_init(SignalVari *o, int k, int step, bool reverse) {
- sVari_update(o, k, step, reverse);
- return 0;
-}
-
-void sVari_onMessage(HeavyContextInterface *_c, SignalVari *o, const HvMessage *m) {
- if (msg_isFloat(m,0)) {
- sVari_update(o, (int) msg_getFloat(m,0), msg_isFloat(m,1) ? (int) msg_getFloat(m,1) : 0, msg_getNumElements(m) == 3);
- }
-}
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvSignalVar.h b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvSignalVar.h
deleted file mode 100644
index 6502f6b5cc..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvSignalVar.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _HEAVY_SIGNAL_VAR_H_
-#define _HEAVY_SIGNAL_VAR_H_
-
-#include "HvHeavyInternal.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// __var~f, __varread~f, __varwrite~f
-
-typedef struct SignalVarf {
- hv_bufferf_t v;
-} SignalVarf;
-
-hv_size_t sVarf_init(SignalVarf *o, float k, float step, bool reverse);
-
-static inline void __hv_varread_f(SignalVarf *o, hv_bOutf_t bOut) {
- *bOut = o->v;
-}
-
-static inline void __hv_varwrite_f(SignalVarf *o, hv_bInf_t bIn) {
- o->v = bIn;
-}
-
-void sVarf_onMessage(HeavyContextInterface *_c, SignalVarf *o, const HvMessage *m);
-
-
-
-// __var~i, __varread~i, __varwrite~i
-
-typedef struct SignalVari {
- hv_bufferi_t v;
-} SignalVari;
-
-hv_size_t sVari_init(SignalVari *o, int k, int step, bool reverse);
-
-static inline void __hv_varread_i(SignalVari *o, hv_bOuti_t bOut) {
- *bOut = o->v;
-}
-
-static inline void __hv_varwrite_i(SignalVari *o, hv_bIni_t bIn) {
- o->v = bIn;
-}
-
-void sVari_onMessage(HeavyContextInterface *_c, SignalVari *o, const HvMessage *m);
-
-
-
-// __var_k~f, __var_k~i
-
-#if HV_SIMD_AVX
-#define __hv_var_k_i(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm256_set_epi32(_h,_g,_f,_e,_d,_c,_b,_a)
-#define __hv_var_k_i_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm256_set_epi32(_a,_b,_c,_d,_e,_f,_g,_h)
-#define __hv_var_k_f(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm256_set_ps(_h,_g,_f,_e,_d,_c,_b,_a)
-#define __hv_var_k_f_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm256_set_ps(_a,_b,_c,_d,_e,_f,_g,_h)
-#elif HV_SIMD_SSE
-#define __hv_var_k_i(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm_set_epi32(_d,_c,_b,_a)
-#define __hv_var_k_i_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm_set_epi32(_a,_b,_c,_d)
-#define __hv_var_k_f(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm_set_ps(_d,_c,_b,_a)
-#define __hv_var_k_f_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm_set_ps(_a,_b,_c,_d)
-#elif HV_SIMD_NEON
-#define __hv_var_k_i(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((int32x4_t) {_a,_b,_c,_d})
-#define __hv_var_k_i_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((int32x4_t) {_d,_c,_b,_a})
-#define __hv_var_k_f(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((float32x4_t) {_a,_b,_c,_d})
-#define __hv_var_k_f_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((float32x4_t) {_d,_c,_b,_a})
-#else // HV_SIMD_NONE
-#define __hv_var_k_i(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a
-#define __hv_var_k_i_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a
-#define __hv_var_k_f(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a
-#define __hv_var_k_f_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a
-#endif
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // _HEAVY_SIGNAL_VAR_H_
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvTable.c b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvTable.c
deleted file mode 100644
index 1b2cd38315..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvTable.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "HvTable.h"
-#include "HvMessage.h"
-
-hv_size_t hTable_init(HvTable *o, int length) {
- o->length = length;
- // true size of the table is always an integer multple of HV_N_SIMD
- o->size = (length + HV_N_SIMD_MASK) & ~HV_N_SIMD_MASK;
- // add an extra length for mirroring
- o->allocated = o->size + HV_N_SIMD;
- o->head = 0;
- hv_size_t numBytes = o->allocated * sizeof(float);
- o->buffer = (float *) hv_malloc(numBytes);
- hv_assert(o->buffer != NULL);
- hv_memclear(o->buffer, numBytes);
- return numBytes;
-}
-
-hv_size_t hTable_initWithData(HvTable *o, int length, const float *data) {
- o->length = length;
- o->size = (length + HV_N_SIMD_MASK) & ~HV_N_SIMD_MASK;
- o->allocated = o->size + HV_N_SIMD;
- o->head = 0;
- hv_size_t numBytes = o->size * sizeof(float);
- o->buffer = (float *) hv_malloc(numBytes);
- hv_assert(o->buffer != NULL);
- hv_memclear(o->buffer, numBytes);
- hv_memcpy(o->buffer, data, length*sizeof(float));
- return numBytes;
-}
-
-hv_size_t hTable_initWithFinalData(HvTable *o, int length, float *data) {
- o->length = length;
- o->size = length;
- o->allocated = length;
- o->buffer = data;
- o->head = 0;
- return 0;
-}
-
-void hTable_free(HvTable *o) {
- hv_free(o->buffer);
-}
-
-int hTable_resize(HvTable *o, hv_uint32_t newLength) {
- // TODO(mhroth): update context with memory allocated by table
- // NOTE(mhroth): mirrored bytes are not necessarily carried over
- const hv_uint32_t newSize = (newLength + HV_N_SIMD_MASK) & ~HV_N_SIMD_MASK;
- if (newSize == o->size) return 0; // early exit if no change in size
- const hv_uint32_t oldSizeBytes = (hv_uint32_t) (o->size * sizeof(float));
- const hv_uint32_t newAllocated = newSize + HV_N_SIMD;
- const hv_uint32_t newAllocatedBytes = (hv_uint32_t) (newAllocated * sizeof(float));
-
- float *b = (float *) hv_realloc(o->buffer, newAllocatedBytes);
- hv_assert(b != NULL); // error while reallocing!
- // ensure that hv_realloc has given us a correctly aligned buffer
- if ((((hv_uintptr_t) (const void *) b) & ((0x1< o->size) {
- hv_memclear(b + o->size, (newAllocated - o->size) * sizeof(float)); // clear new parts of the buffer
- }
- o->buffer = b;
- } else {
- // if not, we have to re-malloc ourselves
- char *c = (char *) hv_malloc(newAllocatedBytes);
- hv_assert(c != NULL); // error while allocating new buffer!
- if (newAllocatedBytes > oldSizeBytes) {
- hv_memcpy(c, b, oldSizeBytes);
- hv_memclear(c + oldSizeBytes, newAllocatedBytes - oldSizeBytes);
- } else {
- hv_memcpy(c, b, newAllocatedBytes);
- }
- hv_free(b);
- o->buffer = (float *) c;
- }
- o->length = newLength;
- o->size = newSize;
- o->allocated = newAllocated;
- return (int) (newAllocated - oldSizeBytes - (HV_N_SIMD*sizeof(float)));
-}
-
-void hTable_onMessage(HeavyContextInterface *_c, HvTable *o, int letIn, const HvMessage *m,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
- if (msg_compareSymbol(m,0,"resize") && msg_isFloat(m,1) && msg_getFloat(m,1) >= 0.0f) {
- hTable_resize(o, (int) hv_ceil_f(msg_getFloat(m,1))); // apply ceil to ensure that tables always have enough space
-
- // send out the new size of the table
- HvMessage *n = HV_MESSAGE_ON_STACK(1);
- msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getSize(o));
- sendMessage(_c, 0, n);
- }
-
- else if (msg_compareSymbol(m,0,"mirror")) {
- hv_memcpy(o->buffer+o->size, o->buffer, HV_N_SIMD*sizeof(float));
- }
-}
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvTable.h b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvTable.h
deleted file mode 100644
index 1d748874ea..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvTable.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _HEAVY_TABLE_H_
-#define _HEAVY_TABLE_H_
-
-#include "HvHeavy.h"
-#include "HvUtils.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct HvTable {
- float *buffer;
- // the number of values that the table is requested to have
- hv_uint32_t length;
-
- // the number of usable values that the table actually has
- // this is always an even multiple of HV_N_SIMD
- hv_uint32_t size;
-
- // Note that the true size of the table is (size + HV_N_SIMD),
- // with the trailing values used by the system, e.g. to create a circular
- // buffer
- hv_uint32_t allocated;
-
- hv_uint32_t head; // the most recently written point
-} HvTable;
-
-hv_size_t hTable_init(HvTable *o, int length);
-
-hv_size_t hTable_initWithData(HvTable *o, int length, const float *data);
-
-hv_size_t hTable_initWithFinalData(HvTable *o, int length, float *data);
-
-void hTable_free(HvTable *o);
-
-int hTable_resize(HvTable *o, hv_uint32_t newLength);
-
-void hTable_onMessage(HeavyContextInterface *_c, HvTable *o, int letIn, const HvMessage *m,
- void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
-
-static inline float *hTable_getBuffer(HvTable *o) {
- return o->buffer;
-}
-
-// the user-requested length of the table (number of floats)
-static inline hv_uint32_t hTable_getLength(HvTable *o) {
- return o->length;
-}
-
-// the usable length of the table (an even multiple of HV_N_SIMD)
-static inline hv_uint32_t hTable_getSize(HvTable *o) {
- return o->size;
-}
-
-// the number of floats allocated to this table (usually size + HV_N_SIMD)
-static inline hv_uint32_t hTable_getAllocated(HvTable *o) {
- return o->allocated;
-}
-
-static inline hv_uint32_t hTable_getHead(HvTable *o) {
- return o->head;
-}
-
-static inline void hTable_setHead(HvTable *o, hv_uint32_t head) {
- o->head = head;
-}
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // _HEAVY_TABLE_H_
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvUtils.c b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvUtils.c
deleted file mode 100644
index 2fdf682c4c..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvUtils.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "HvUtils.h"
-
-hv_uint32_t hv_string_to_hash(const char *str) {
- // this hash is based MurmurHash2
- // http://en.wikipedia.org/wiki/MurmurHash
- // https://sites.google.com/site/murmurhash/
- static const hv_uint32_t n = 0x5bd1e995;
- static const hv_int32_t r = 24;
-
- if (str == NULL) return 0;
-
- hv_uint32_t len = (hv_uint32_t) hv_strlen(str);
- hv_uint32_t x = len; // seed (0) ^ len
-
- while (len >= 4) {
-#if HV_EMSCRIPTEN
- hv_uint32_t k = str[0] | (str[1] << 8) | (str[2] << 16) | (str[3] << 24);
-#else
- hv_uint32_t k = *((hv_uint32_t *) str);
-#endif
- k *= n;
- k ^= (k >> r);
- k *= n;
- x *= n;
- x ^= k;
- str += 4; len -= 4;
- }
- switch (len) {
- case 3: x ^= (str[2] << 16);
- case 2: x ^= (str[1] << 8);
- case 1: x ^= str[0]; x *= n;
- default: break;
- }
- x ^= (x >> 13);
- x *= n;
- x ^= (x >> 15);
- return x;
-}
diff --git a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvUtils.h b/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvUtils.h
deleted file mode 100644
index 2186f547c0..0000000000
--- a/examples/examples-dsp/examples-pd/streams-pd-audiokit/HvUtils.h
+++ /dev/null
@@ -1,319 +0,0 @@
-/**
- * Copyright (c) 2014-2018 Enzien Audio Ltd.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _HEAVY_UTILS_H_
-#define _HEAVY_UTILS_H_
-
-// platform definitions
-#if _WIN32 || _WIN64 || _MSC_VER
- #define HV_WIN 1
-#elif __APPLE__
- #define HV_APPLE 1
-#elif __ANDROID__
- #define HV_ANDROID 1
-#elif __unix__ || __unix
- #define HV_UNIX 1
-#else
- #warning Could not detect platform. Assuming Unix-like.
-#endif
-
-#ifdef EMSCRIPTEN
-#define HV_EMSCRIPTEN 1
-#endif
-
-// basic includes
-#include
-#include
-#include