New upstream version 1.4.1+ds0
authorIOhannes m zmölnig (Debian/GNU) <umlaeute@debian.org>
Wed, 24 Nov 2021 15:44:52 +0000 (16:44 +0100)
committerIOhannes m zmölnig (Debian/GNU) <umlaeute@debian.org>
Wed, 24 Nov 2021 15:44:52 +0000 (16:44 +0100)
180 files changed:
.clang-format [new file with mode: 0644]
.clang-tidy [new file with mode: 0644]
.gitignore [deleted file]
.mailmap [new file with mode: 0644]
.travis.yml [deleted file]
CHANGESLOG.txt [deleted file]
CMakeLists.txt [new file with mode: 0644]
Doxyfile [new file with mode: 0644]
INSTALL.txt [deleted file]
INSTALL_meson.md [deleted file]
LICENSE [deleted file]
LICENSE.md [new file with mode: 0644]
LICENSES/GPL-3.0.txt [new file with mode: 0644]
LICENSES/LGPL-3.0-only.txt [new file with mode: 0644]
LICENSES/MIT.txt [new file with mode: 0644]
QJackTrip.kdev4 [new file with mode: 0644]
README.md
TODO.txt [deleted file]
build [new file with mode: 0755]
cross/x86_mingw64.txt [new file with mode: 0644]
cross/x86_mingw64_static.txt [new file with mode: 0644]
docs/About/CHANGELOG.md [new file with mode: 0644]
docs/About/Contributors.md [new file with mode: 0644]
docs/About/License.md [new file with mode: 0644]
docs/About/Resources.md [new file with mode: 0644]
docs/Build/CrossCompile.md [new file with mode: 0644]
docs/Build/Linux.md [new file with mode: 0644]
docs/Build/Mac.md [new file with mode: 0644]
docs/Build/Meson_build.md [new file with mode: 0644]
docs/Build/Windows.md [new file with mode: 0644]
docs/DevTools/Formatting.md [new file with mode: 0644]
docs/DevTools/StaticAnalysis.md [new file with mode: 0644]
docs/Documentation/MkDocs.md [new file with mode: 0644]
docs/Install.md [new file with mode: 0644]
docs/index.md [new file with mode: 0644]
documentation/documentation.cpp
documentation/footer.html [new file with mode: 0644]
documentation/header.html [new file with mode: 0644]
documentation/html_footer.html [deleted file]
faust-src/faust2header.cpp
faust-src/minimal.cpp
jacktrip.pro [new file with mode: 0644]
jacktrip_and_rtaudio.pro [new file with mode: 0644]
jacktrip_doxygen [deleted file]
linux/flatpak/org.jacktrip.JackTrip.Devel.yml [new file with mode: 0644]
linux/flatpak/org.jacktrip.JackTrip.Devel.yml.j2 [new file with mode: 0644]
linux/flatpak/org.jacktrip.JackTrip.yml [new file with mode: 0644]
linux/icons/jacktrip-symbolic.svg [new file with mode: 0644]
linux/icons/jacktrip.svg [new file with mode: 0644]
linux/icons/jacktrip_48x48.png [new file with mode: 0644]
linux/meson.build [new file with mode: 0644]
linux/org.jacktrip.JackTrip.desktop.in [new file with mode: 0644]
linux/org.jacktrip.JackTrip.metainfo.xml.in [new file with mode: 0644]
macos/JackTrip.app_template/Contents/Info.plist [new file with mode: 0644]
macos/JackTrip.app_template/Contents/PkgInfo [new file with mode: 0644]
macos/JackTrip.app_template/Contents/Resources/jacktrip.icns [new file with mode: 0644]
macos/assemble_app.sh [new file with mode: 0755]
macos/entitlements.plist [new file with mode: 0644]
macos/jacktrip.iconset/icon_128x128.png [new file with mode: 0644]
macos/jacktrip.iconset/icon_128x128@2x.png [new file with mode: 0644]
macos/jacktrip.iconset/icon_16x16.png [new file with mode: 0644]
macos/jacktrip.iconset/icon_16x16@2x.png [new file with mode: 0644]
macos/jacktrip.iconset/icon_256x256.png [new file with mode: 0644]
macos/jacktrip.iconset/icon_256x256@2x.png [new file with mode: 0644]
macos/jacktrip.iconset/icon_32x32.png [new file with mode: 0644]
macos/jacktrip.iconset/icon_32x32@2x.png [new file with mode: 0644]
macos/jacktrip.iconset/icon_512x512.png [new file with mode: 0644]
macos/jacktrip.iconset/icon_512x512@2x.png [new file with mode: 0644]
macos/package/JackTrip.pkgproj_template [new file with mode: 0644]
macos/package/link.sh [new file with mode: 0644]
meson.build
meson_options.txt [new file with mode: 0644]
mkdocs.yml [new file with mode: 0644]
rtaudio.pro [new file with mode: 0644]
scripts/hubMode/art.sh
scripts/hubMode/startJacktripHubClient.sh
scripts/hubMode/startJacktripHubServer.sh
scripts/hubMode/test_hub_mode_server_and_client.sh
scripts/utility/generate_auth.sh [new file with mode: 0755]
scripts/utility/record_jack_receiving_ports.sh
src/AudioInterface.cpp
src/AudioInterface.h
src/AudioTester.cpp
src/AudioTester.h
src/Auth.cpp [new file with mode: 0644]
src/Auth.h [new file with mode: 0644]
src/Compressor.cpp
src/Compressor.h
src/CompressorPresets.h
src/DataProtocol.cpp
src/DataProtocol.h
src/DataProtocolPOSIX.cpp.tmp [deleted file]
src/DataProtocolPOSIX.h.tmp [deleted file]
src/Effects.h
src/JMess.cpp
src/JMess.h
src/JackAudioInterface.cpp
src/JackAudioInterface.h
src/JackTrip.cpp
src/JackTrip.h
src/JackTripThread.cpp [deleted file]
src/JackTripThread.h [deleted file]
src/JackTripWorker.cpp
src/JackTripWorker.h
src/JackTripWorkerMessages.h [deleted file]
src/JitterBuffer.cpp
src/JitterBuffer.h
src/Limiter.cpp
src/Limiter.h
src/LoopBack.cpp
src/LoopBack.h
src/NetKS.h [deleted file]
src/PacketHeader.cpp
src/PacketHeader.h
src/Patcher.cpp [new file with mode: 0644]
src/Patcher.h [new file with mode: 0644]
src/PoolBuffer.cpp [new file with mode: 0644]
src/PoolBuffer.h [new file with mode: 0644]
src/ProcessPlugin.cpp
src/ProcessPlugin.h
src/Reverb.cpp
src/Reverb.h
src/RingBuffer.cpp
src/RingBuffer.h
src/RingBufferWavetable.h
src/RtAudioInterface.cpp
src/RtAudioInterface.h
src/Settings.cpp
src/Settings.h
src/SslServer.cpp [new file with mode: 0644]
src/SslServer.h [new file with mode: 0644]
src/TestRingBuffer.h [deleted file]
src/ThreadPoolTest.h [deleted file]
src/UdpDataProtocol.cpp
src/UdpDataProtocol.h
src/UdpDataProtocolPOSIX.cpp.tmp [deleted file]
src/UdpDataProtocolPOSIX.h.tmp [deleted file]
src/UdpHubListener.cpp
src/UdpHubListener.h
src/build
src/compressordsp.h
src/freeverbdsp.h
src/freeverbmonodsp.h
src/gui/Jacktrip.ai [new file with mode: 0644]
src/gui/NoNap.h [new file with mode: 0644]
src/gui/NoNap.mm [new file with mode: 0644]
src/gui/about.cpp [new file with mode: 0644]
src/gui/about.h [new file with mode: 0644]
src/gui/about.png [new file with mode: 0644]
src/gui/about.ui [new file with mode: 0644]
src/gui/about@2x.png [new file with mode: 0644]
src/gui/icon.png [new file with mode: 0644]
src/gui/messageDialog.cpp [new file with mode: 0644]
src/gui/messageDialog.h [new file with mode: 0644]
src/gui/messageDialog.ui [new file with mode: 0644]
src/gui/qjacktrip.cpp [new file with mode: 0644]
src/gui/qjacktrip.h [new file with mode: 0644]
src/gui/qjacktrip.qrc [new file with mode: 0644]
src/gui/qjacktrip.ui [new file with mode: 0644]
src/jacktrip.pro [deleted file]
src/jacktrip_globals.cpp
src/jacktrip_globals.h
src/jacktrip_main.cpp [deleted file]
src/jacktrip_tests.cpp [deleted file]
src/jacktrip_types.h
src/jacktrip_types_alt.h [deleted file]
src/limiterdsp.h
src/main.cpp [new file with mode: 0644]
src/makeXcodeproj.sh
src/zitarevdsp.h
src/zitarevmonodsp.h
subprojects/rtaudio.wrap [new file with mode: 0644]
subprojects/wingetopt.wrap [new file with mode: 0644]
tests/jacktrip_tests.cpp [new file with mode: 0644]
win/build_installer.bat [new file with mode: 0755]
win/dialog.bmp [new file with mode: 0644]
win/files.wxs [new file with mode: 0644]
win/jacktrip.ico [new file with mode: 0644]
win/jacktrip.wxs [new file with mode: 0644]
win/qjacktrip.rc [new file with mode: 0644]

diff --git a/.clang-format b/.clang-format
new file mode 100644 (file)
index 0000000..31204cb
--- /dev/null
@@ -0,0 +1,182 @@
+---
+Language:        Cpp
+# BasedOnStyle:  Google
+AccessModifierOffset: -1
+AlignAfterOpenBracket: Align
+AlignConsecutiveMacros: true
+AlignConsecutiveAssignments: true
+AlignConsecutiveBitFields: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlines: Left
+AlignOperands:   Align
+AlignTrailingComments: true
+AllowAllArgumentsOnNextLine: true
+AllowAllConstructorInitializersOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortEnumsOnASingleLine: true
+AllowShortBlocksOnASingleLine: Empty
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: All
+AllowShortLambdasOnASingleLine: All
+AllowShortIfStatementsOnASingleLine: WithoutElse
+AllowShortLoopsOnASingleLine: true
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: true
+AlwaysBreakTemplateDeclarations: Yes
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+  AfterCaseLabel:  false
+  AfterClass:      false
+  AfterControlStatement: Never
+  AfterEnum:       false
+  AfterFunction:   false
+  AfterNamespace:  false
+  AfterObjCDeclaration: false
+  AfterStruct:     false
+  AfterUnion:      false
+  AfterExternBlock: false
+  BeforeCatch:     false
+  BeforeElse:      false
+  BeforeLambdaBody: false
+  BeforeWhile:     false
+  IndentBraces:    false
+  SplitEmptyFunction: true
+  SplitEmptyRecord: true
+  SplitEmptyNamespace: true
+BreakBeforeBinaryOperators: NonAssignment
+BreakBeforeBraces: Linux
+BreakBeforeInheritanceComma: false
+BreakInheritanceList: BeforeComma
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+BreakConstructorInitializers: BeforeComma
+BreakAfterJavaFieldAnnotations: false
+BreakStringLiterals: true
+ColumnLimit:     90
+CommentPragmas: '( \| |\*--|<li>|@ref | @p | @param  |@returns |@warning |@ingroup |@author |@date |@related |@relates |@relatesalso |@deprecated |@image |@return |@brief |@attention |@copydoc |@addtogroup |@todo |@tparam |@see |@note |@skip |@skipline |@until |@line |@dontinclude |@include)'
+CompactNamespaces: false
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DeriveLineEnding: true
+DerivePointerAlignment: false
+DisableFormat:   false
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: true
+ForEachMacros:
+  - foreach
+  - Q_FOREACH
+  - BOOST_FOREACH
+IncludeBlocks:   Regroup
+IncludeCategories:
+  - Regex:           '^<ext/.*\.h>'
+    Priority:        2
+    SortPriority:    0
+  - Regex:           '^<.*\.h>'
+    Priority:        1
+    SortPriority:    0
+  - Regex:           '^<.*'
+    Priority:        2
+    SortPriority:    0
+  - Regex:           '.*'
+    Priority:        3
+    SortPriority:    0
+IncludeIsMainRegex: '([-_](test|unittest))?$'
+IncludeIsMainSourceRegex: ''
+IndentCaseLabels: false
+IndentCaseBlocks: false
+IndentGotoLabels: true
+IndentPPDirectives: None
+IndentExternBlock: AfterExternBlock
+IndentWidth:     4
+IndentWrappedFunctionNames: false
+InsertTrailingCommas: None
+JavaScriptQuotes: Leave
+JavaScriptWrapImports: true
+KeepEmptyLinesAtTheStartOfBlocks: false
+MacroBlockBegin: ''
+MacroBlockEnd:   ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBinPackProtocolList: Never
+ObjCBlockIndentWidth: 2
+ObjCBreakBeforeNestedBlockParam: true
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakAssignment: 2
+PenaltyBreakBeforeFirstCallParameter: 1
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyBreakTemplateDeclaration: 10
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 200
+PointerAlignment: Left
+RawStringFormats:
+  - Language:        Cpp
+    Delimiters:
+      - cc
+      - CC
+      - cpp
+      - Cpp
+      - CPP
+      - 'c++'
+      - 'C++'
+    CanonicalDelimiter: ''
+    BasedOnStyle:    google
+  - Language:        TextProto
+    Delimiters:
+      - pb
+      - PB
+      - proto
+      - PROTO
+    EnclosingFunctions:
+      - EqualsProto
+      - EquivToProto
+      - PARSE_PARTIAL_TEXT_PROTO
+      - PARSE_TEST_PROTO
+      - PARSE_TEXT_PROTO
+      - ParseTextOrDie
+      - ParseTextProtoOrDie
+      - ParseTestProto
+      - ParsePartialTestProto
+    CanonicalDelimiter: ''
+    BasedOnStyle:    google
+ReflowComments:  true
+SortIncludes:    true
+SortUsingDeclarations: true
+SpaceAfterCStyleCast: false
+SpaceAfterLogicalNot: false
+SpaceAfterTemplateKeyword: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCpp11BracedList: false
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeParens: ControlStatements
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceInEmptyBlock: false
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 2
+SpacesInAngles:  false
+SpacesInConditionalStatement: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+SpaceBeforeSquareBrackets: false
+Standard:        Auto
+StatementMacros:
+  - Q_UNUSED
+  - QT_REQUIRE_VERSION
+TabWidth:        8
+UseCRLF:         false
+UseTab:          Never
+WhitespaceSensitiveMacros:
+  - STRINGIZE
+  - PP_STRINGIZE
+  - BOOST_PP_STRINGIZE
+...
+
diff --git a/.clang-tidy b/.clang-tidy
new file mode 100644 (file)
index 0000000..5c342d6
--- /dev/null
@@ -0,0 +1 @@
+Checks: '-*,modernize-deprecated-headers,modernize-loop-convert'
diff --git a/.gitignore b/.gitignore
deleted file mode 100644 (file)
index c9dcabe..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-# QtCreator user files
-*.pro.user
-*.pro.user.*
-
-# build directory
-builddir/
diff --git a/.mailmap b/.mailmap
new file mode 100644 (file)
index 0000000..982e71f
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,35 @@
+Nils Tonnätt <nils.tonnaett@posteo.de>
+Nils Tonnätt <nils.tonnaett@posteo.de> studio <akkijyrkkae@campus.tu-berlin.de>
+
+Marcin Pączkowski <dyfeer@gmail.com>
+
+Maximilian Wagenbach <maximilian.wagenbach@native-instruments.de>
+
+Julius Smith <jos@ccrma.stanford.edu>
+Julius Smith <jos@ccrma.stanford.edu> Julius Smith <julius.smith@gmail.com>
+
+Juan-Pablo Caceres <caceres@adobe.com> <jcacerec@gmail.com>
+Juan-Pablo Caceres <caceres@adobe.com> <jcacerec@users.noreply.github.com>
+Juan-Pablo Caceres <caceres@adobe.com> <jcacerec@3532cb72-8e7e-11dd-98a5-cbe9a756ba3b>
+Juan-Pablo Caceres <caceres@adobe.com> jcaceres <jcaceres@3532cb72-8e7e-11dd-98a5-cbe9a756ba3b>
+Juan-Pablo Caceres <caceres@adobe.com> jua20133 <jua20133@adobe.com>
+Juan-Pablo Caceres <caceres@adobe.com> jcaceres <jcaceres@ccrma.stanford.edu>
+
+Aaron Wyatt <github@psi-borg.org>
+Aaron Wyatt <github@psi-borg.org> psiborg112 <psiborg112@users.noreply.github.com>
+
+Chris Chafe <cc@ccrma.stanford.edu>
+Chris Chafe <cc@ccrma.stanford.edu> cc <xxx>
+Chris Chafe <cc@ccrma.stanford.edu> <cc@localhost.localdomain>
+Chris Chafe <cc@ccrma.stanford.edu> <4406287+cchafe@users.noreply.github.com>
+
+
+Bonnie Kwong <tersewings@protonmail.com>
+Bonnie Kwong <tersewings@protonmail.com> Bonnie Kwong <bonniekwong@Bonnies-MBP-2.attlocal.net>
+
+Omar Costa Hamido <omarcostinha@gmail.com>
+
+Mike Dickey <mike@mikedickey.com>
+Mike Dickey <mike@mikedickey.com> Mike Dickey <mdickey@splunk.com>
+
+IOhannes m zmölnig <zmoelnig@umlautQ.umlaeute.mur.at> <zmoelnig@umlautS.umlaeute.mur.at>
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644 (file)
index c6ff4a8..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-os:
-  - linux
-  - osx
-
-language: 
-  - cpp
-
-# force updated ubuntu distribution with up-to-date gcc
-dist: bionic
-
-branches:
-  - main
-  - dev
-  
-env:
-  global:
-  - PKGS_OSX="jack qt rt-audio"
-  
-addons:
-  apt:
-    update: true
-    packages:
-      - qt5-default
-      - qttools5-dev-tools
-      - libjack-dev 
-      - librtaudio-dev
-
-before_script:
-  # manually install brew packages as addon: homebrew is broken in the default osx image
-  - if [ "$TRAVIS_OS_NAME" = "osx" ]; then HOMEBREW_NO_AUTO_UPDATE=1 brew install $PKGS_OSX; fi
-  # mac: workaround for homebrew qmake not being symlinked into $PATH
-  # see https://stackoverflow.com/questions/48847505/why-cant-i-use-qmake-on-mac-after-installing-it
-  - if [ "$TRAVIS_OS_NAME" = "osx" ]; then export PATH="/usr/local/opt/qt/bin:$PATH"; fi
-
-script: 
-  - cd src
-  - ./build
-  
-after_success:
-  - echo "Success!"
-
-after_failure:
-  - echo "Something went wrong :("
diff --git a/CHANGESLOG.txt b/CHANGESLOG.txt
deleted file mode 100644 (file)
index 139ba35..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
----
-1.3.0
-- (added) async networking in hub listener
-- (added) limiter, compressor, reverb
-- (added) examine audio delay
-- (added) jitter buffer alternatives
-- (added) broadcast output ports
-- (added) PREFIX variable for installation path
-- (added) disconnect on timeout
-- (added) SIGTERM
-- (added) simulate packet loss, jitter
-- (added) hubpatch 5, no auto patching
-- (added) jack client name length check
-- (added) scripts/hubMode/test_hub_mode_server_and_client.sh
-- (fixed) misc. typos, indentation
-- (fixed) short form IO stat options
-- (fixed) nullptr jack server name when creating jack client
-- (fixed) stop ring buffer blocking when jack has been stopped
-- (fixed) JMess handling of non-western characters
-- (fixed) closing curly brace on mJackTrip client creation
-- (fixed) Warnings
-- (fixed) remove rtaudio device and mpeeraddress msgs.
-- (fixed) signal and slot connections
-- (fixed) incorrect dependency from jacktrip_main
-- (update) RT thread priority for network I/O
-- (update) clipping to saturation
-- (update) build instructions
-
----
-1.2.2 (main)
-- (added) bindPort range to reject oddball connections
-- (fixed) jack client name strings
-
----
-1.2.1 (master) (branch name will be deprecated)
-(main and dev) (new branches, respectively for stable and development)
-- (added) src/build script builds in ../builddir
-- (fixed) refactor "Master" to be "Hub"
-- (fixed) 1.2.1 correctly versioned and tagged
-
----
-1.2 (release candidate, not yet tagged)
-- (added) jack patching modes (-p) for Hub Mode server (-S)
-- (fixed) Compilation under ubuntu
-- (removed) setRealtimeProcessPriority()
-- (removed) Rtaudio mode (but still has dependencies)
-- (fixed) IPv4-mapped IPv6 addressing bug
-...
-- (fixed) Fixed compilation for  MacOSX10.11.sdk.
-- (update) Updated to RtAudio 4.1.1, and using shared lib in linux.
-
----
-1.1
-- (added) Support for RtAudio. Jacktrip can now be used without Jack
-- (added) DNS Look-up support, now one machine can have a private IP (but still needs to have UDP ports open)
-- (added) New port to Windows XP and Windows Vista (experimental and not tested for a long time, only when using jacktrip as a library)
-- (added) Multiclient Server (experimental and not exposed in the executable)
-
----
-1.0.5
-- (added) Compatibility with JamLink boxes (restricted at the moment to 48KHz, 64 buffer size and 1 channel)
-- (added) New port structure that allows the communication between a public server and a local client
-- (added) Option for packets without header
-- (added) Option to change default client name
-- (fixed) General optimizations and code cleanup
-- (added) Improved, now cross-platform build script
-
----
-1.0.4
-- (fixed) Buss error caused when no physical inputs or outputs ports are available
-
----
-1.0.3
-- (added) Redundancy Algorithm for UDP Packets to avoid glitches with packet losses
-- (fixed) Now compiles on 64bits machines
-- (fixed) Improved exceptions handling
-- (added) Basic Karplus-Strong model added as Plug-in
-- (added) Some functionality reimplemented using signals and slots for
-          more flexibility
-- (added) Multiple-Client-Server in alpha testing, expect it working in the next release
-
----
-1.0.2 Alpha
-- (added) Port offset mode, to use a different UDP port than the default one.
-- (fixed) Improved thread behavior
-
----
-1.0.1 Alpha
-- (added) jamlink mode to connect with jamlink boxes
-- (fixed) thread priority in both Linux and Mac OS X (still need some work on the Mac OS X version)
-- (fixed) Bug that was causing plug-ins not to behave correctly
-- (added) Loopback mode
-- (added) Underrun Modes: Wavetable (default) and set to zeros
-- (added) Check for peer audio settings, program exists if they don't match
-- (added) Automatically connect ports to available physical audio interface.
-
----
-1.0 Alpha  - initial release
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..aaa2511
--- /dev/null
@@ -0,0 +1,159 @@
+cmake_minimum_required(VERSION 3.12)
+set(CMAKE_OSX_DEPLOYMENT_TARGET 10.13)
+project(QJackTrip)
+
+set(nogui FALSE)
+set(rtaudio TRUE)
+set(weakjack TRUE)
+add_compile_definitions(QT_OPENSOURCE)
+
+if (nogui)
+  add_compile_definitions(NO_GUI)
+endif ()
+
+if (rtaudio)
+  add_compile_definitions(__RT_AUDIO__)
+endif ()
+
+if (weakjack)
+  add_compile_definitions(USE_WEAK_JACK)
+  include_directories("externals/weakjack")
+endif()
+
+if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+  add_compile_definitions(__LINUX__)
+elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+  add_compile_definitions (__MAC_OSX__)
+  set (ENV{PKG_CONFIG_PATH} "/usr/local/lib/pkgconfig")
+elseif (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+  add_compile_definitions(__WIN_32__ _WIN32_WINNT=0x0600 WIN32_LEAN_AND_MEAN)
+  if (EXISTS "C:/Program Files/JACK2/include")
+    include_directories("C:/Program Files/JACK2/include")
+    set (jacklib "C:/Program Files/JACK2/lib/libjack64.lib")
+  else ()
+    include_directories("C:/Program Files (x86)/Jack/includes")
+    set (jacklib "C:/Program Files (x86)/Jack/lib/libjack64.lib")
+  endif ()
+  set (CMAKE_PREFIX_PATH "C:/Qt/5.15.2/mingw81_64/lib/cmake")
+  if (rtaudio)
+    include_directories("C:/Program Files (x86)/RtAudio/include")
+    set (rtaudiolib "C:/Program Files (x86)/RtAudio/lib/librtaudio.dll.a")
+  endif ()
+endif ()
+
+if (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+  find_package(PkgConfig REQUIRED)
+  pkg_check_modules(JACK REQUIRED IMPORTED_TARGET jack)
+  if (weakjack)
+    # On mac, weakjack doesnt't find jack unless this is explicitly included.
+    include_directories(${JACK_INCLUDE_DIRS})
+  endif ()
+  if (rtaudio)
+    pkg_check_modules(RTAUDIO REQUIRED IMPORTED_TARGET rtaudio)
+  endif ()
+endif ()
+
+# Find includes in corresponding build directories
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+# Instruct CMake to run moc automatically when needed.
+set(CMAKE_AUTOMOC ON)
+# Instruct CMake to create code from Qt designer ui files
+set(CMAKE_AUTOUIC ON)
+
+set(CMAKE_AUTORCC ON)
+
+# Find the QtWidgets library
+if (NOT nogui)
+  find_package(Qt5Widgets CONFIG REQUIRED)
+endif ()
+find_package(Qt5Network CONFIG REQUIRED)
+
+set(qjacktrip_SRC
+  src/main.cpp
+  src/Settings.cpp
+  src/jacktrip_globals.cpp
+  src/JackTrip.cpp
+  src/UdpHubListener.cpp
+  src/JackTripWorker.cpp
+  src/DataProtocol.cpp
+  src/UdpDataProtocol.cpp
+  src/AudioInterface.cpp
+  src/JackAudioInterface.cpp
+  src/JMess.cpp
+  src/LoopBack.cpp
+  src/PacketHeader.cpp
+  src/RingBuffer.cpp
+  src/JitterBuffer.cpp
+  src/PoolBuffer.cpp
+  src/Compressor.cpp
+  src/Limiter.cpp
+  src/Reverb.cpp
+  src/AudioTester.cpp
+  src/Patcher.cpp
+  src/SslServer.cpp
+  src/Auth.cpp
+)
+
+if (rtaudio)
+  set (qjacktrip_SRC ${qjacktrip_SRC}
+    src/RtAudioInterface.cpp
+  )
+endif ()
+
+if (weakjack)
+  set (qjacktrip_SRC ${qjacktrip_SRC}
+    externals/weakjack/weak_libjack.c
+  )
+endif ()
+
+if (NOT nogui)
+  set (qjacktrip_SRC ${qjacktrip_SRC}
+    src/gui/qjacktrip.cpp
+    src/gui/about.cpp
+    src/gui/messageDialog.cpp
+    src/gui/qjacktrip.qrc
+  )
+
+  if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+    set (qjacktrip_SRC ${qjacktrip_SRC} win/qjacktrip.rc)
+  elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+    set (qjacktrip_SRC ${qjacktrip_SRC} src/gui/NoNap.mm)
+    set (CMAKE_C_FLAGS "-x objective-c")
+    set (CMAKE_EXE_LINKER_FLAGS "-framework Foundation")
+  endif ()
+endif ()
+
+add_compile_definitions(WAIRTOHUB)
+
+# Tell CMake to create the executable
+add_executable(jacktrip ${qjacktrip_SRC})
+
+# Set our libraries for our linker
+set (qjacktrip_LIBS Qt5::Widgets)
+if (NOT nogui)
+  set (qjacktrip_LIBS ${qjacktrip_LIBS} Qt5::Network)
+endif ()
+
+if (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+  if (weakjack)
+    set (qjacktrip_LIBS ${qjacktrip_LIBS} dl)
+  else ()
+    set (qjacktrip_LIBS ${qjacktrip_LIBS} PkgConfig::JACK)
+  endif ()
+  if (rtaudio)
+    set (qjacktrip_LIBS ${qjacktrip_LIBS} PkgConfig::RTAUDIO)
+  endif ()
+elseif (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+  set (qjacktrip_LIBS ${qjacktrip_LIBS} ws2_32)
+  if (NOT weakjack)
+    set (qjacktrip_LIBS ${qjacktrip_LIBS} ${jacklib})
+  endif ()
+  if (rtaudio)
+    set (qjacktrip_LIBS ${qjacktrip_LIBS} ${rtaudiolib})
+  endif ()
+endif ()
+
+target_link_libraries(jacktrip ${qjacktrip_LIBS})
+
+# Install the executable
+install(TARGETS jacktrip DESTINATION bin)
diff --git a/Doxyfile b/Doxyfile
new file mode 100644 (file)
index 0000000..44a9421
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,2603 @@
+# Doxyfile 1.9.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the configuration
+# file that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = JackTrip
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           = linux/icons/jacktrip.svg
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = .
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = YES
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all generated output in the proper direction.
+# Possible values are: None, LTR, RTL and Context.
+# The default value is: None.
+
+OUTPUT_TEXT_DIRECTION  = None
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
+# such as
+# /***************
+# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
+# Javadoc-style will behave just like regular comments and it will not be
+# interpreted by doxygen.
+# The default value is: NO.
+
+JAVADOC_BANNER         = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# By default Python docstrings are displayed as preformatted text and doxygen's
+# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
+# doxygen's special commands can be used and the contents of the docstring
+# documentation blocks is shown as doxygen documentation.
+# The default value is: YES.
+
+PYTHON_DOCSTRING       = YES
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines (in the resulting output). You can put ^^ in the value part of an
+# alias to insert a newline as if a physical newline was in the original file.
+# When you need a literal { or } or , in the value part of an alias you have to
+# escape them by means of a backslash (\), this can lead to conflicts with the
+# commands \{ and \} for these it is advised to use the version @{ and @} or use
+# a double escape (\\{ and \\})
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
+# sources only. Doxygen will then generate output that is more tailored for that
+# language. For instance, namespaces will be presented as modules, types will be
+# separated into more groups, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_SLICE  = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
+# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL,
+# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
+# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
+# tries to guess whether the code is fixed or free formatted code, this is the
+# default for Fortran type files). For instance to make doxygen treat .inc files
+# as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen. When specifying no_extension you should add
+# * to the FILE_PATTERNS.
+#
+# Note see also the list of default file extension mappings.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See https://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 5.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS   = 5
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
+# during processing. When set to 0 doxygen will based this on the number of
+# cores available in the system. You can set it explicitly to a value larger
+# than 0 to get more control over the balance between CPU load and processing
+# speed. At this moment only the input processing can be done using multiple
+# threads. Since this is still an experimental feature the default is set to 1,
+# which efficively disables parallel processing. Please report any issues you
+# encounter. Generating dot graphs in parallel is controlled by the
+# DOT_NUM_THREADS setting.
+# Minimum value: 0, maximum value: 32, default value: 1.
+
+NUM_PROC_THREADS       = 1
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
+# methods of a class will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIV_VIRTUAL   = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If this flag is set to YES, the name of an unnamed parameter in a declaration
+# will be determined by the corresponding definition. By default unnamed
+# parameters remain unnamed in the output.
+# The default value is: YES.
+
+RESOLVE_UNNAMED_PARAMS = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# declarations. If set to NO, these declarations will be included in the
+# documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
+# able to match the capabilities of the underlying filesystem. In case the
+# filesystem is case sensitive (i.e. it supports files in the same directory
+# whose names only differ in casing), the option must be set to YES to properly
+# deal with such files in case they appear in the input. For filesystems that
+# are not case sensitive the option should be be set to NO to properly deal with
+# output files written for symbols that only differ in casing, such as for two
+# classes, one named CLASS and the other named Class, and to also support
+# references to files without having to specify the exact matching casing. On
+# Windows (including Cygwin) and MacOS, users should typically set this option
+# to NO, whereas on Linux or other Unix flavors it should typically be set to
+# YES.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation. If
+# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
+# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
+# at the end of the doxygen process doxygen will return with a non-zero status.
+# Possible values are: NO, YES and FAIL_ON_WARNINGS.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = ./src \
+                         ./documentation
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see:
+# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# Note the list of default checked file patterns might differ from the list of
+# default file extension mappings.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment),
+# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl,
+# *.ucf, *.qsf and *.ice.
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# 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
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+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
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             = ./documentation/img
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# entity all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see https://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see:
+# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
+# performance. This can be particularly helpful with template rich C++ code for
+# which doxygen's built-in parser lacks the necessary type information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to
+# YES then doxygen will add the directory of each input to the include path.
+# The default value is: YES.
+
+CLANG_ADD_INC_PATHS    = YES
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS          =
+
+# If clang assisted parsing is enabled you can provide the clang parser with the
+# path to the directory containing a file called compile_commands.json. This
+# file is the compilation database (see:
+# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
+# options used when the source files were built. This is equivalent to
+# specifying the -p option to a clang tool, such as clang-check. These options
+# will then be passed to the parser. Any options specified with CLANG_OPTIONS
+# will be added as well.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+
+CLANG_DATABASE_PATH    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = NO
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            = ./documentation/header.html
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            = ./documentation/footer.html
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  = externals/doxygen-awesome-css/doxygen-awesome.css externals/doxygen-awesome-css/doxygen-awesome-sidebar-only.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = NO
+
+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
+# documentation will contain a main index with vertical navigation menus that
+# are dynamically created via JavaScript. If disabled, the navigation index will
+# consists of multiple levels of tabs that are statically embedded in every HTML
+# page. Disable this option to support browsers that do not have JavaScript,
+# like the Qt help browser.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_MENUS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see:
+# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
+# create a documentation set, doxygen will generate a Makefile in the HTML
+# output directory. Running make will produce the docset in that directory and
+# running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
+# genXcode/_index.html for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see:
+# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the main .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location (absolute path
+# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
+# run qhelpgenerator on the generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
+# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
+# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
+# the HTML output. These images will generally look nicer at scaled resolutions.
+# Possible values are: png (the default) and svg (looks nicer but requires the
+# pdf2svg or inkscape tool).
+# The default value is: png.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FORMULA_FORMAT    = png
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
+# to create new LaTeX commands to be used in formulas as building blocks. See
+# the section "Including formulas" for details.
+
+FORMULA_MACROFILE      =
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# https://www.mathjax.org) which uses client side JavaScript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from https://www.mathjax.org before deployment.
+# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = https://cdn.jsdelivr.net/npm/mathjax@2
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using JavaScript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/). See the section "External Indexing and Searching" for
+# details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when not enabling USE_PDFLATEX the default is latex when enabling
+# USE_PDFLATEX the default is pdflatex and when in the later case latex is
+# chosen this is overwritten by pdflatex. For specific output languages the
+# default can have been set differently, this depends on the implementation of
+# the output language.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# Note: This tag is used in the Makefile / make.bat.
+# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
+# (.tex).
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
+# generate index for LaTeX. In case there is no backslash (\) as first character
+# it will be automatically added in the LaTeX code.
+# Note: This tag is used in the generated output file (.tex).
+# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
+# The default value is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_MAKEINDEX_CMD    = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
+# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
+# files. Set this option to YES, to get a higher quality PDF documentation.
+#
+# See also section LATEX_CMD_NAME for selecting the engine.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP        = NO
+
+# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
+# path from which the emoji images will be read. If a relative path is entered,
+# it will be relative to the LATEX_OUTPUT directory. If left blank the
+# LATEX_OUTPUT directory will be used.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EMOJI_DIRECTORY  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# configuration file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's configuration file. A template extensions file can be
+# generated using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
+# namespace members in file scope as well, matching the HTML output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_NS_MEMB_FILE_SCOPE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# 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
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Sans
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
+# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
+# tag is set to YES, doxygen will add type and arguments for attributes and
+# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
+# will not generate fields with class member information in the UML graphs. The
+# class diagrams will look similar to the default class diagrams but using UML
+# notation for the relationships.
+# Possible values are: NO, YES and NONE.
+# The default value is: NO.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+DOT_UML_DETAILS        = NO
+
+# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
+# to display on a single line. If the actual line length exceeds this threshold
+# significantly it will wrapped across multiple lines. Some heuristics are apply
+# to avoid ugly line breaks.
+# Minimum value: 0, maximum value: 1000, default value: 17.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_WRAP_THRESHOLD     = 17
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = svg
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = YES
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
+# files that are used to generate the various graphs.
+#
+# Note: This setting is not only used for dot files but also for msc and
+# plantuml temporary files.
+# The default value is: YES.
+
+DOT_CLEANUP            = YES
diff --git a/INSTALL.txt b/INSTALL.txt
deleted file mode 100644 (file)
index 9d3ed50..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-Jacktrip : Build Instructions\r
-\r
-JackTrip: A System for High-Quality Audio Network Performance over the Internet.\r
-\r
-The following are instructions for compiling Jacktrip from source.  Compiling from source is the best way to keep up with the latest changes, both stable and experimental.  For quicker ways to install Jacktrip, go to README.md in the root directory of the project.\r
-\r
-Steps:\r
-Dependencies\r
-Build\r
-Installation (Linux and OS X only)\r
-Installation or Build Verification\r
----\r
-Dependencies(for all operating systems):\r
-g++\r
-Qt 5.14.2\r
-Jack\r
-Note: rtaudio is no longer a dependency\r
-\r
-All Linux\r
-\r
-Fedora:\r
-dnf install qt5-devel\r
-dnf groupinstall "C Development Tools and Libraries"\r
-dnf groupinstall "Development Tools"\r
-dnf install jack-audio-connection-kit-devel alsa-lib-devel iperf qjackctl audacity git\r
-Clone the git repo and run ./build in the src directory or use QtCreator to compile\r
-\r
-Ubuntu and Debian/Raspbian:\r
-apt install -y --no-install-recommends build-essential librtaudio-dev qt5-default autoconf automake libtool make libjack-jackd2-dev qjackctl audacity git\r
-Clone the git repo and run ./build in the src directory or use QtCreator to compile\r
-\r
-Other Linux distributions:\r
-the latest Qt\r
-jack-audio-connection-kit-devel\r
-Clone the git repo and run ./build in the src directory or use QtCreator to compile\r
-\r
-If you are using yum you can just install them (as root) with:\r
-   yum install jack-audio-connection-kit-devel\r
-and install qt from the qt site.\r
-\r
-OSX (skip the steps you don't need):\r
-\r
-Install Jack2 https://jackaudio.org/downloads/\r
-If this command returns the XCode version, you have it installed:\r
-xcodebuild -version\r
-If you don't have XCode, go to the AppStore to download and install it.\r
-If this command returns the version number of the package manager Homebrew, you have it installed:\r
-brew -v\r
-If you don't have Homebrew, install it:\r
-/bin/bash -c "$(curl -fsSLhttps://raw.githubusercontent.com/Homebrew/install/master/install.sh)"\r
-To install git if you don't have it:\r
-brew install git\r
-brew install qjackctl\r
-Install and link qt5:\r
-brew install qt5\r
-brew link qt5 --force\r
-Clone the git repo and run ./build in the src directory or use QtCreator to compile\r
-\r
----\r
-Build (Linux or Mac OS X):\r
-You can compile using the build script or QtCreator.\r
-\r
-To clone the repo in the Terminal:\r
-$ git clone https://github.com/jacktrip/jacktrip.git\r
-\r
-To compile using the build script:\r
-$ cd jacktrip/src\r
-$ ./build\r
-$ cd ../builddir\r
-$ ls\r
-You should see a 'jacktrip' executable in this folder.\r
-\r
-If the build script doesn't work on a different Linux flavor, try building\r
-the Makefiles yourself. You'd need qmake. Then you can build by:\r
-$ qmake jacktrip.pro\r
-$ make release\r
-\r
-To build using QtCreator:\r
-  * Open jacktrip.pro using QtCreator\r
-  * Choose a correctly configured Kit\r
-\r
-On MacOS X, QtCreator places the 'jacktrip' executabe by default in a folder with a name like 'build-jacktrip-Desktop_x86_darwin_generic_mach_o_64bit-Release.'\r
-\r
----\r
-Installation on MacOS X (10.9 or higher) or Linux:\r
-\r
-You need to have a working Jack installation on your machine (see Dependencies above).\r
-\r
-To install using Terminal (skip the first three steps if you've already followed the Build instructions above):\r
-\r
-$ git clone https://github.com/jacktrip/jacktrip.git\r
-$ cd jacktrip/src\r
-$ ./build\r
-$ cd ../builddir\r
-$ sudo cp jacktrip /usr/local/bin/\r
-  (enter your password when prompted)\r
-\r
-$ sudo chmod 755 /usr/local/bin/jacktrip\r
-  (now you can run jacktrip from any directory using Terminal)\r
-  \r
----\r
-Installation Verification on MacOS X or Linux:\r
-If you have installed jacktrip, from anywhere in the Terminal, type:\r
-$ jacktrip -v\r
-\r
-If you have compiled from source without installing, in the /builddir directory type:\r
-$ ./jacktrip -v\r
-\r
-If you see something like this, you have successfully installed Jacktrip:\r
-JackTrip VERSION: 1.xx\r
-Copyright (c) 2008-2020 Juan-Pablo Caceres, Chris Chafe.\r
-SoundWIRE group at CCRMA, Stanford University\r
-\r
-Follow the link at the bottom of the page to use Jacktrip.\r
-\r
----\r
-WINDOWS (XP and later)\r
-- ASIO4all audio driver is required even with Audio interfaces that support ASIO: www.asio4all.com.\r
-- Note: Some users have reported success using the PortAudio driver, though it is not currently supported.\r
-\r
-Building\r
-Note: WIN10BUILDINSTRUCTIONS.pdf (in the same directory as this file) has screenshots of the Windows 10 build process and step-by-step instructions.\r
-If you do not have Git installed, download it from https://git-scm.com/download/win.\r
-Open the command line by typing cmd.exe in the Windows search bar.\r
-Use the `cd` command to navigate to the directory where you would like to install jacktrip, e.g. `cd C:\Users\Your User Name\`.\r
-Use `git clone https://github.com/jacktrip/jacktrip.git` to download a fresh copy of the repo or `git pull` to update your repo.\r
-\r
-On Windows 10, the easiest way to build is in the command line:\r
-To add the location of qmake to the path, in the Windows search bar, type "environment variable" and click on the Environment Variables button in the Advanced tab of System Properties.  Find the Path variable in System variables, click Edit, and enter the location of qmake, e.g. `C:\Qt\5.15.0\mingw81_64\bin`, where 5.15.0 is the version of Qt you installed.\r
-To verify you have g++ installed, type `where g++` in the command line.  If the command returns `not found` rather than a path, go to the Qt Maintenance Tool, which might be in a directory such as `C:\Qt\maintenancetool.exe`, and remove, then reinstall Qt.\r
-In the command line, use the `cd` command to navigate to the project directory, e.g. `cd jacktrip` and execute the following commands:\r
-mkdir builddir (this step creates the build directory, and is only necessary if you're building for the first time)\r
-cd builddir\r
-qmake -spec win32-g++ ../src/jacktrip.pro (you may skip this step if you're building for the first time)\r
-mingw32-make clean (you may skip this step if you're building for the first time)\r
-qmake -spec win32-g++ ../src/jacktrip.pro\r
-mingw32-make release\r
-\r
-On earlier Windows versions, the easiest way to build is to download the free Qt Creator IDE from https://www.qt.io/download since the jacktrip buildscript is written in qmake.\r
-Open the `src/jacktrip.pro` and configure the project.\r
-Make sure to select the MinGW compiler (for example the one shipped with QtCreator).\r
-Building with Clang or Microsoft Visual Studio Compilers is currently not supported!\r
-\r
-Download Jack2 from https://jackaudio.org/downloads/\r
-Make sure to install Jack into `C:\Program Files (x86)\Jack` (as this is the path where the jacktrip build script will look for it).\r
-\r
-Hit build in QtCreator.\r
-Copy the dll files `Qt5Core.dll` and `Qt5Network.dll` from your compiler's bin directory, e.g. `C:\Qt\5.15.0\mingw81_64\bin` to the folder in your project where your `jacktrip.exe` is located, e.g. `C:\Users\Your Name\jacktrip\build-jacktrip-Desktop-Qt_5_15_0_MinGW_64_bit-Release\release`\r
-In the above example, 5.15.0 is the version of Qt MinGW 64 bit is the compiler.  The folder names may vary according to the Qt and compiler versions you are using.\r
-\r
-Note: compiling with modifications in the .pro file (like adding a new source or header file) requires\r
-qmake which is only available in the Qt Creator package.\r
-\r
-Build Verification:\r
-In the search field (Windows key + R), enter cmd.exe to open the command line.  Use the `cd` command to navigate to the directory where the executable jacktrip.exe is located, e.g. `C:\Users\Your Name\jacktrip\build-jacktrip-Desktop-Qt_5_15_0_MinGW_64_bit-Release\release`.\r
-\r
-From there, the following command should return the version of Jacktrip you installed:\r
-jacktrip.exe -v\r
-\r
-If you see something like this, you have successfully installed Jacktrip:\r
-JackTrip VERSION: 1.xx\r
-Copyright (c) 2008-2020 Juan-Pablo Caceres, Chris Chafe.\r
-SoundWIRE group at CCRMA, Stanford University\r
-\r
-Follow the link below for instructions on how to use Jacktrip.\r
-\r
----\r
-Post Configuration & Using Jacktrip:\r
-Detailed instructions at\r
-https://ccrma.stanford.edu/docs/common/IETF.html\r
diff --git a/INSTALL_meson.md b/INSTALL_meson.md
deleted file mode 100644 (file)
index fda5b39..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-# Build and Installation Instructions with Meson
-
-## Install Dependencies
-
-Fedora:
-dnf install meson qt5-qtbase-devel rtaudio-devel jack-audio-connection-kit-devel
-
-Debian/Ubuntu:
-apt install meson build-essential qtbase5-dev librtaudio-dev libjack-jackd2-dev
-
-MacOS with brew (not tested):
-brew install meson qt rt-audio jack
-
-## Build
-
-Prepare your build directory (by default debug and nonoptimized):
-meson builddir
-
-Now build with:
-ninja -C builddir
-
-Install with:
-ninja -C builddir install
diff --git a/LICENSE b/LICENSE
deleted file mode 100644 (file)
index a843d97..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,23 +0,0 @@
-  Copyright (c) 2020 Juan-Pablo Caceres, Chris Chafe.
-  SoundWIRE group at CCRMA, Stanford University.
-
-  Permission is hereby granted, free of charge, to any person
-  obtaining a copy of this software and associated documentation
-  files (the "Software"), to deal in the Software without
-  restriction, including without limitation the rights to use,
-  copy, modify, merge, publish, distribute, sublicense, and/or sell
-  copies of the Software, and to permit persons to whom the
-  Software is furnished to do so, subject to the following
-  conditions:
-
-  The above copyright notice and this permission notice shall be
-  included in all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-  OTHER DEALINGS IN THE SOFTWARE.
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644 (file)
index 0000000..517bd08
--- /dev/null
@@ -0,0 +1,17 @@
+# JackTrip License
+
+Copyright © 2020 Juan-Pablo Caceres, Chris Chafe.  
+SoundWIRE group at CCRMA, Stanford University.  
+Graphical user interface originally released as QJackTrip, 
+Copyright © 2020 Aaron Wyatt
+
+JackTrip project consists of files under MIT and GPL licenses, indicated in the
+header of individual files. Early versions of JackTrip were licensed under MIT.
+
+JackTrip uses Qt library throughout the project so the resulting binaries are
+also subject to Qt's license. The builds provided on GitHub's Releases page use
+open source distribution of Qt, licensed under LGPL.
+
+The text of individual licenses is provided in the `LICENSES/` folder. Qt's
+source code can be downloaded from
+[https://download.qt.io/official_releases/qt/](https://download.qt.io/official_releases/qt/).
diff --git a/LICENSES/GPL-3.0.txt b/LICENSES/GPL-3.0.txt
new file mode 100644 (file)
index 0000000..f288702
--- /dev/null
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<https://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<https://www.gnu.org/licenses/why-not-lgpl.html>.
diff --git a/LICENSES/LGPL-3.0-only.txt b/LICENSES/LGPL-3.0-only.txt
new file mode 100644 (file)
index 0000000..0a04128
--- /dev/null
@@ -0,0 +1,165 @@
+                   GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions.
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version.
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/LICENSES/MIT.txt b/LICENSES/MIT.txt
new file mode 100644 (file)
index 0000000..a843d97
--- /dev/null
@@ -0,0 +1,23 @@
+  Copyright (c) 2020 Juan-Pablo Caceres, Chris Chafe.
+  SoundWIRE group at CCRMA, Stanford University.
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation
+  files (the "Software"), to deal in the Software without
+  restriction, including without limitation the rights to use,
+  copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the
+  Software is furnished to do so, subject to the following
+  conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+  OTHER DEALINGS IN THE SOFTWARE.
diff --git a/QJackTrip.kdev4 b/QJackTrip.kdev4
new file mode 100644 (file)
index 0000000..ec8f93a
--- /dev/null
@@ -0,0 +1,3 @@
+[Project]
+Name=QJackTrip
+Manager=KDevCMakeManager
index 717a575f46a5a8de36d8280eeba4a44a9d919a8c..46a08f2fea76ac8e9a3d50fab0deb9c01395a69c 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,38 +1,7 @@
-# JackTrip is a Linux, Mac OSX, or Windows multi-machine audio system used for network music performance over the Internet.
-It supports any number of channels (as many as the computer/network can handle) of bidirectional, high quality, uncompressed audio signal streaming.
-
-You can use it between any combination of machines e.g., one end using Linux can connect to another using Mac OSX.
-
-# Installation
-## Linux ##
-Linux installation instructions can be found in INSTALL.txt in the src directory of the project.
-
-## OSX or Windows ##
-Installers and executables are the easiest way to install Jacktrip.
-
-OSX installer or executable: https://ccrma.stanford.edu/software/jacktrip/osx/index.html 
-- Temporary [link](https://www.dropbox.com/s/jb7vh9oiew50cm6/jacktrip-macos-installer-x64-1.2.1.pkg?dl=0) to JackTrip 1.2.1 installer (see more details [here](https://github.com/jacktrip/jacktrip/issues/158#issuecomment-699215590))
-
-Windows installer or executable: https://ccrma.stanford.edu/software/jacktrip/windows/index.html
-
-To keep up with the latest changes, both experimental and stable, follow instructions to compile from source in INSTALL.txt in the src directory of the project.
-
-# Raspberry Pi
-
-[paper](https://lac.linuxaudio.org/2019/doc/chafe2.pdf) accompanying jacktrip demo at [Linux Audio Conference 2019](https://lac.linuxaudio.org/2019/)
-
-# Other Repos
-jacktrip (1.0) was released on google code. When that shut down, it migrated to github (1.05, 1.1).
-It then moved to the CCRMA's cm-gitlab for version 1.2.
-And as of spring 2020 it moved back to GitHub for the current development.
+# JackTrip is a multi-machine audio system used for network music performance over the Internet.
 
+It supports any number of channels (as many as the computer/network can handle) of bidirectional, high quality, uncompressed audio signal streaming.
 
-## Links ##
-  * Preliminary [Documentation](http://ccrma.stanford.edu/groups/soundwire/software/jacktrip/) and [API](http://ccrma.stanford.edu/groups/soundwire/software/jacktrip/annotated.html).
-  * Subscribe to the [Mailing List](http://groups.google.com/group/jacktrip-users).
-  * [CCRMA](http://ccrma.stanford.edu/).
-  * [SoundWIRE group](http://ccrma.stanford.edu/groups/soundwire/).
-  * [Juan-Pablo Caceres](https://ccrma.stanford.edu/~jcaceres/).
+It runs on several platforms, such as Linux, macOS, Windows or FreeBSD. You can use it between any combination of machines e.g., one end using Linux can connect to another using macOS.
 
-## Related Software ##
-[JMess](https://github.com/jcacerec/jmess-jack): A utility to save your audio connections (mess).
+Further information and instructions are available on https://jacktrip.github.io/jacktrip/. 
diff --git a/TODO.txt b/TODO.txt
deleted file mode 100644 (file)
index 9b5e4d7..0000000
--- a/TODO.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-High Priority TODOS:
---------------------
-
-- Add redundancy to UDP (DONE)
-- Finish header implementation, add run-time check
-
-
-Plug-ins:
----------
-- Extend Plugin structure to include more than 1 plug-in and add the mode for local effect (not loopback)
-- add the offset option to process starting from a different channel
-- Set the faust compiler to automatically generate plugins
-- Add low latency compression www.celt-codec.org
-
-Protocol:
----------
-- Add TCP clacc
-- Add SCTP class
-- Maybe add a layer of OSC communication for control messages
diff --git a/build b/build
new file mode 100755 (executable)
index 0000000..90c0a52
--- /dev/null
+++ b/build
@@ -0,0 +1,160 @@
+#!/bin/bash
+## Created by Juan-Pablo Caceres
+
+# Parse command line options
+clean=1
+install=0
+CONFIG=
+UNKNOWN_OPTIONS=
+BUILD_RTAUDIO=0
+RTAUDIO=0
+NO_SYSTEM_RTAUDIO=0
+PRO_FILE="../jacktrip.pro"
+HELP_STR="usage:\n
+./build [noclean nojack rtaudio nogui static install [-config static]]\n\n
+options:\n
+noclean - do not run \"make clean\" first\n
+nojack - build without jack\n
+rtaudio - build with RtAudio\n
+no-system-rtaudio - use bundled RtAudio library even if it's available in the system\n
+nogui - build without the gui\n
+static - build with static libraries\n
+weakjack - build with weak linking of jack libraries\n
+install - install jacktrip in system location (uses sudo)\n
+"
+while [[ "$#" -gt 0 ]]; do
+  if [[ -z "$UNKNOWN_OPTIONS" ]]; then
+    case $1 in
+      noclean) clean=0 ;;
+      nojack)
+      echo "Building without jack"
+      CONFIG="-config nojack $CONFIG" 
+      ;;
+      rtaudio) 
+      RTAUDIO=1
+      ;;
+      no-system-rtaudio) 
+      NO_SYSTEM_RTAUDIO=1
+      ;;
+      nogui)
+      echo "Building without the gui"
+      CONFIG="-config nogui $CONFIG" 
+      ;;
+      static)
+      echo "Building with static libraries"
+      CONFIG="-config static $CONFIG" 
+      ;;
+      weakjack)
+      echo "Building with weak linking of jack"
+      CONFIG="-config weakjack $CONFIG"
+      ;;
+      install)
+      echo "Will install JackTrip in system location"
+      install=1
+      ;;
+      -h|--help) 
+      echo -e $HELP_STR; exit 
+      ;;
+      *) UNKNOWN_OPTIONS="$UNKNOWN_OPTIONS $1" ;;
+    esac
+    shift
+  else
+    case $1 in
+      *) UNKNOWN_OPTIONS="$UNKNOWN_OPTIONS $1" ;;
+    esac
+    shift
+  fi
+done
+
+# Check for Platform
+platform='unknown'
+unamestr=`uname`
+if [[ "$unamestr" == 'Linux' ]]; then
+  echo "Building on Linux"
+  platform='linux'
+elif [[ "$unamestr" == 'Darwin' ]]; then
+  echo "Building on macOS"
+  platform='macosx'
+elif [[ "$unamestr" == 'MINGW'* ]]; then
+  echo "Building on Windows (MinGW)"
+  platform='mingw'
+fi
+
+# Set qmake command name
+if [[ $platform == 'linux' ]]; then
+  if hash qmake-qt5 2>/dev/null; then
+    echo "Using qmake-qt5"
+    QCMD=qmake-qt5
+  elif hash qmake 2>/dev/null; then #in case qt was compiled by user
+  echo "Using qmake"
+  QCMD=qmake
+fi
+QSPEC=linux-g++
+MCMD=make
+elif [[ $platform == 'macosx' ]]; then
+  QCMD=qmake
+  QSPEC=macx-clang
+  # if qmake is not in path, try homebrew qt5
+  if ! command -v $QCMD &> /dev/null; then
+    # echo "qmake not found in \$PATH, searching for homebrew qt5"
+    QT_PREFIX=`brew --prefix qt5`
+    if [[ -n $QT_PREFIX ]]; then
+      QCMD="$QT_PREFIX/bin/$QCMD"
+      echo "Using qmake at $QCMD"
+    else
+      echo "Homebrew installation of qt5 not found"
+      exit
+    fi
+  fi
+  MCMD=make
+elif [[ $platform == 'mingw' ]]; then
+  QCMD=qmake
+  QSPEC=win32-g++
+  MCMD=mingw32-make
+elif [[ $platform == 'unknown' ]]; then
+  echo "Unregonized platform, exiting"
+  exit
+fi
+
+# check for RtAudio
+if [[ $RTAUDIO == 1 ]]; then
+  pkg-config --exists rtaudio 2> /dev/null
+  if [[ $? -eq 0 ]]; then
+    if [[ $NO_SYSTEM_RTAUDIO == 1 ]]; then
+      echo "RtAudio library found, but using the bundled library anyway"
+      BUILD_RTAUDIO=1
+    else
+      echo "Using system-provided RtAudio library"
+    fi
+  else
+    echo "Using bundled RtAudio library"
+    BUILD_RTAUDIO=1
+  fi
+fi
+
+if [[ $BUILD_RTAUDIO == 1 ]]; then
+  PRO_FILE="../jacktrip_and_rtaudio.pro";
+  CONFIG="-config bundled_rtaudio $CONFIG"
+elif [[ $RTAUDIO == 1 ]]; then
+  echo "Building with RtAudio"
+  CONFIG="-config rtaudio $CONFIG"
+fi
+
+# Create our build directory
+mkdir -p builddir
+cd builddir
+
+# Build
+echo "qmake command:"
+echo "$QCMD -spec $QSPEC $CONFIG $PRO_FILE" $UNKNOWN_OPTIONS
+if [[ $clean == 1 ]]; then
+  $QCMD -spec $QSPEC $CONFIG $PRO_FILE $UNKNOWN_OPTIONS
+  $MCMD clean
+fi
+$QCMD -spec $QSPEC $CONFIG $PRO_FILE $UNKNOWN_OPTIONS
+$MCMD release
+if [[ "$install" == 1 ]]; then
+  echo "*** Installing JackTrip ***"
+  echo "We need elevated privileges to install JackTrip in the system location"
+  sudo $MCMD release-install
+fi
diff --git a/cross/x86_mingw64.txt b/cross/x86_mingw64.txt
new file mode 100644 (file)
index 0000000..7a07b2c
--- /dev/null
@@ -0,0 +1,20 @@
+[host_machine]
+system = 'windows'
+cpu_family = 'x86_64'
+cpu = 'x86_64'
+endian = 'little'
+
+[binaries]
+exe_wrapper =  'wine64'
+c = 'x86_64-w64-mingw32-gcc'
+cpp = 'x86_64-w64-mingw32-g++'
+ar = 'x86_64-w64-mingw32-ar'
+ld = 'x86_64-w64-mingw32-ld'
+objcopy = 'x86_64-w64-mingw32-objcopy'
+strip = 'x86_64-w64-mingw32-strip'
+pkgconfig = 'x86_64-w64-mingw32-pkg-config'
+windres = 'x86_64-w64-mingw32-windres'
+
+[project options]
+rtaudio = 'enabled'
+rtaudio:wasapi = 'true'
diff --git a/cross/x86_mingw64_static.txt b/cross/x86_mingw64_static.txt
new file mode 100644 (file)
index 0000000..43cb85a
--- /dev/null
@@ -0,0 +1,24 @@
+[host_machine]
+system = 'windows'
+cpu_family = 'x86_64'
+cpu = 'x86_64'
+endian = 'little'
+
+[binaries]
+exe_wrapper =  'wine64'
+c = 'x86_64-w64-mingw32-gcc'
+cpp = 'x86_64-w64-mingw32-g++'
+ar = 'x86_64-w64-mingw32-ar'
+ld = 'x86_64-w64-mingw32-ld'
+objcopy = 'x86_64-w64-mingw32-objcopy'
+strip = 'x86_64-w64-mingw32-strip'
+pkgconfig = 'x86_64-w64-mingw32-pkg-config'
+windres = 'x86_64-w64-mingw32-windres'
+
+[built-in options]
+cpp_link_args = ['-static-libgcc', '-static-libstdc++']
+
+[project options]
+default_library = 'static'
+rtaudio = 'enabled'
+rtaudio:wasapi = 'true'
diff --git a/docs/About/CHANGELOG.md b/docs/About/CHANGELOG.md
new file mode 100644 (file)
index 0000000..1d7ba81
--- /dev/null
@@ -0,0 +1,129 @@
+Changelog
+=========
+
+1.4.0
+---
+- (added) optional GUI from QJackTrip
+- (added) authentication in hub server mode
+- (added) different number of sending and receiving channels
+- (added) append thread IDs to jack client names
+- (added) new patcher mechanism that doesn't delete existing connections
+- (added) MkDocs based documentation
+- (added) weak jack linking
+- (added) manpage
+- (added) MSVC build
+- (added) RtAudio Meson subproject
+- (added) formatting with clang-format
+- (added) static analysis with clang-tidy
+- (added) cross compilation for Windows
+- (added) flatpaks
+- (added) appstream
+- (added) automated builds and deployment for Linux, macOS and Windows
+- (added) macOS and Windows Installers
+- (fixed) regression in remote client name handling
+- (fixed) long jack client names (> 27 characters) in 1.9.11
+- (fixed) Hardcode Derived Class Names of ProcessPlugins to prevent undefined behavior
+- (update) QJackTrip and JackTrip are now identical
+- (update) Change helpscreen wording for --broadcast argument
+- (update) jitter buffer alternatives
+- (update) RtAudio revive
+- (update) RtAudio device selection
+- (update) build script moved to root directory
+
+1.3.0
+---
+- (added) async networking in hub listener
+- (added) limiter, compressor, reverb
+- (added) examine audio delay
+- (added) jitter buffer alternatives
+- (added) broadcast output ports
+- (added) PREFIX variable for installation path
+- (added) disconnect on timeout
+- (added) SIGTERM
+- (added) simulate packet loss, jitter
+- (added) hubpatch 5, no auto patching
+- (added) jack client name length check
+- (added) scripts/hubMode/test_hub_mode_server_and_client.sh
+- (added) Meson build
+- (fixed) misc. typos, indentation
+- (fixed) short form IO stat options
+- (fixed) nullptr jack server name when creating jack client
+- (fixed) stop ring buffer blocking when jack has been stopped
+- (fixed) JMess handling of non-western characters
+- (fixed) closing curly brace on mJackTrip client creation
+- (fixed) Warnings
+- (fixed) remove rtaudio device and mpeeraddress msgs.
+- (fixed) signal and slot connections
+- (fixed) incorrect dependency from jacktrip_main
+- (update) RT thread priority for network I/O
+- (update) clipping to saturation
+- (update) build instructions
+
+1.2.2
+---
+- (added) bindPort range to reject oddball connections
+- (fixed) jack client name strings
+
+1.2.1
+---
+- (added) src/build script builds in ../builddir
+- (fixed) refactor "Master" to be "Hub"
+- (fixed) 1.2.1 correctly versioned and tagged
+
+1.2
+---
+- (added) jack patching modes (-p) for Hub Mode server (-S)
+- (fixed) Compilation under ubuntu
+- (removed) setRealtimeProcessPriority()
+- (removed) Rtaudio mode (but still has dependencies)
+- (fixed) IPv4-mapped IPv6 addressing bug
+...
+- (fixed) Fixed compilation for  MacOSX10.11.sdk.
+- (update) Updated to RtAudio 4.1.1, and using shared lib in linux.
+
+1.1
+---
+- (added) Support for RtAudio. Jacktrip can now be used without Jack
+- (added) DNS Look-up support, now one machine can have a private IP (but still needs to have UDP ports open)
+- (added) New port to Windows XP and Windows Vista (experimental and not tested for a long time, only when using jacktrip as a library)
+- (added) Multiclient Server (experimental and not exposed in the executable)
+
+1.0.5
+---
+- (added) Compatibility with JamLink boxes (restricted at the moment to 48KHz, 64 buffer size and 1 channel)
+- (added) New port structure that allows the communication between a public server and a local client
+- (added) Option for packets without header
+- (added) Option to change default client name
+- (fixed) General optimizations and code cleanup
+- (added) Improved, now cross-platform build script
+
+1.0.4
+---
+- (fixed) Buss error caused when no physical inputs or outputs ports are available
+
+1.0.3
+---
+- (added) Redundancy Algorithm for UDP Packets to avoid glitches with packet losses
+- (fixed) Now compiles on 64bits machines
+- (fixed) Improved exceptions handling
+- (added) Basic Karplus-Strong model added as Plug-in
+- (added) Some functionality reimplemented using signals and slots for more flexibility
+- (added) Multiple-Client-Server in alpha testing, expect it working in the next release
+
+1.0.2 Alpha
+---
+- (added) Port offset mode, to use a different UDP port than the default one.
+- (fixed) Improved thread behavior
+
+1.0.1 Alpha
+---
+- (added) jamlink mode to connect with jamlink boxes
+- (fixed) thread priority in both Linux and Mac OS X (still need some work on the Mac OS X version)
+- (fixed) Bug that was causing plug-ins not to behave correctly
+- (added) Loopback mode
+- (added) Underrun Modes: Wavetable (default) and set to zeros
+- (added) Check for peer audio settings, program exists if they don't match
+- (added) Automatically connect ports to available physical audio interface.
+
+1.0 Alpha  - initial release
+---
diff --git a/docs/About/Contributors.md b/docs/About/Contributors.md
new file mode 100644 (file)
index 0000000..c82541d
--- /dev/null
@@ -0,0 +1,93 @@
+# Contributors
+
+In order of first contribution
+
+## 2008
+
+??? note "Chris Chafe /// ***CCRMA, Stanford University*** /// ***JackTrip Foundation***"
+
+    **2008 - **
+
+??? note  "Juan-Pablo Caceres /// ***CCRMA, Stanford University***"
+
+    **2008 - 2018**
+
+## 2019
+
+??? note "Nils Tonnätt /// ***Audiocommunication, TU Berlin***"
+
+    **2019 - **
+
+    Feature Work
+
+    * Different number of input and output channels
+    * Append Thread ID to JACK client names
+    * Meson build
+    * RtAudio backend
+    * MkDocs based documentation
+    * Github Actions
+
+## 2020
+
+??? note "Aaron Wyatt /// ***Monash University***"
+
+    **2020 - **
+
+    Feature Work
+
+    * Graphical User Interface (QJackTrip)
+    * IPv6 support
+    * Authentication
+    * Installer Creation Scripts
+
+??? note "Marcin Pączkowski /// ***Composer***"
+
+    **2020 - **
+
+    Feature Work
+
+    * Github Actions
+
+## 2021
+
+??? note  "Olivier Humbert" 
+
+    **2021**
+
+    * French Translation Work
+
+## unknown
+
+??? note "Julius Smith /// ***CCRMA, Stanford University***"
+
+??? note "Bonnie Kwong"
+
+??? note "Mike Dickey /// ***JackTrip Foundation***"
+
+??? note  "Anton Runov"
+
+??? note "Maximilian Wagenbach"
+
+??? note "Spencer Salazar"
+
+??? note "Omar Costa Hamido"
+
+??? note "Bruno Ruviaro"
+
+??? note "Daniel Riechers"
+
+??? note "Jasper Mackenzie"
+
+??? note "Michael Dessen"
+
+??? note "Gerald Mwangi"
+
+??? note "James Borden"
+
+??? note "Nicolas Kaiser"
+
+??? note "Noah Horn"
+
+??? note "Tom Ward"
+
+??? note "Ronen Barzel"
diff --git a/docs/About/License.md b/docs/About/License.md
new file mode 100644 (file)
index 0000000..9535e11
--- /dev/null
@@ -0,0 +1,14 @@
+--8<-- "LICENSE.md"
+
+---
+### MIT License
+--8<-- "LICENSES/MIT.txt"
+
+
+---
+### GPL License
+--8<-- "LICENSES/GPL-3.0.txt"
+
+---
+### LGPL License
+--8<-- "LICENSES/LGPL-3.0-only.txt"
\ No newline at end of file
diff --git a/docs/About/Resources.md b/docs/About/Resources.md
new file mode 100644 (file)
index 0000000..32e493d
--- /dev/null
@@ -0,0 +1,22 @@
+## Post Configuration & Using Jacktrip
+Detailed instructions at [CCRMA](https://ccrma.stanford.edu/docs/common/IETF.html)
+
+## Raspberry Pi
+
+[paper](https://lac.linuxaudio.org/2019/doc/chafe2.pdf) accompanying jacktrip demo at [Linux Audio Conference 2019](https://lac.linuxaudio.org/2019/)
+
+## Other Repos
+jacktrip (1.0) was released on google code. When that shut down, it migrated to github (1.05, 1.1).
+It then moved to the CCRMA's cm-gitlab for version 1.2.
+And as of spring 2020 it moved back to GitHub for the current development.
+
+
+## Links
+  * Preliminary [Documentation](http://ccrma.stanford.edu/groups/soundwire/software/jacktrip/) and [API](http://ccrma.stanford.edu/groups/soundwire/software/jacktrip/annotated.html).
+  * Subscribe to the [Mailing List](http://groups.google.com/group/jacktrip-users).
+  * [CCRMA](http://ccrma.stanford.edu/).
+  * [SoundWIRE group](http://ccrma.stanford.edu/groups/soundwire/).
+  * [Juan-Pablo Caceres](https://ccrma.stanford.edu/~jcaceres/).
+
+## Related Software
+[JMess](https://github.com/jcacerec/jmess-jack): A utility to save your audio connections (mess).
diff --git a/docs/Build/CrossCompile.md b/docs/Build/CrossCompile.md
new file mode 100644 (file)
index 0000000..b554a2c
--- /dev/null
@@ -0,0 +1,19 @@
+# Cross Compile JackTrip for Windows on Fedora
+
+```bash
+sudo dnf install mingw64-gcc mingw64-gcc-c++ mingw64-pkg-config mingw64-qt5-qtbase-static
+```
+
+```bash
+meson --cross-file win/cross_file.txt build_win
+cd build_win
+meson compile
+```
+
+```bash
+export WINEPATH=/usr/x86_64-w64-mingw32/sys-root/mingw/bin/
+wine64 ./jacktrip.exe
+```
+
+You might want to copy all necessary DLLs to the same directory as the jacktrip.exe
+binary.
diff --git a/docs/Build/Linux.md b/docs/Build/Linux.md
new file mode 100644 (file)
index 0000000..12c995a
--- /dev/null
@@ -0,0 +1,136 @@
+# Build Instructions
+
+The following are instructions for compiling Jacktrip from source.  Compiling
+from source is the best way to keep up with the latest changes, both stable and
+experimental.  For quicker ways to install Jacktrip, go to README.md in the root
+directory of the project.
+
+## Dependencies
+- C++ compiler
+- Qt5
+
+Optional:
+
+- JACK (preferred) or RtAudio (not fully functional)
+- help2man for generating the manpage
+
+### Fedora
+```sh
+dnf install qt5-devel
+dnf groupinstall "C Development Tools and Libraries"
+dnf groupinstall "Development Tools"
+dnf install "pkgconfig(jack)" alsa-lib-devel git help2man
+dnf install qjackctl
+```
+
+Clone the git repo with submodules and run `./build install` in the project
+directory or use QtCreator to compile.
+
+### Ubuntu and Debian/Raspbian
+```sh
+apt install --no-install-recommends build-essential qt5-default autoconf automake libtool make libjack-jackd2-dev git help2man
+apt install qjackctl
+apt install librtaudio-dev # if building with RtAudio
+```
+
+Clone the git repo with submodules and run `./build install` in the project
+directory or use QtCreator to compile.
+
+### Building and Installation instructions
+
+For other Linux distributions, install the dependencies listed above. Clone the
+git repo and run `./build install` (or `./build` to skip installation) in the
+project directory, or use QtCreator to compile.
+
+To clone the repo in the Terminal:
+```sh
+$ git clone --recurse-submodules https://github.com/jacktrip/jacktrip.git
+```
+Note that we need `--recurse-submodules` to also get the submodules!
+
+Next, navigate to the cloned repository:
+```sh
+$ cd jacktrip
+```
+
+JackTrip provides a build script designed to simplify the build process and
+providing a number of options. To list them, run:
+```sh
+$ ./build -h
+```
+This should print:
+```sh
+usage:
+ ./build [noclean nojack rtaudio nogui static install [-config static]]
+
+ options:
+ noclean - do not run "make clean" first
+ nojack - build without jack
+ rtaudio - build with rtaudio
+ nogui - build without the gui
+ static - build with static libraries
+ weakjack - build with weak linking of jack libraries
+ install - install jacktrip in system location (uses sudo)
+```
+
+To just compile JackTrip using the build script, run:
+```sh
+$ ./build
+$ cd builddir
+$ ls
+```
+
+You should see a `jacktrip` in this folder.
+
+To compile **and install** using the build script, run:
+```sh
+$ ./build install
+# enter your password when prompted
+```
+
+If the build script doesn't work, try running qmake directly. You'd need to have
+qmake in your `$PATH`. Then you can build with:
+
+```sh
+$ mkdir builddir
+$ cd builddir
+$ qmake ../jacktrip.pro
+$ make release
+$ sudo make release-install # to install JackTrip system-wide
+```
+
+You can pass configuration options to qmake with `-config <option>`, e.g. `qmake
+-config nogui ../jacktrip.pro`. Relevant options include:
+
+- `-config rtaudio` - build with rtaudio support
+- `-config nogui` - build without the GUI
+- `-config static` - build with static libraries
+- `-config weakjack` - build using weak linking of jack
+- `-config nojack` - build without jack support
+
+To build using QtCreator:
+
+  * Open jacktrip.pro using QtCreator
+  * Choose a correctly configured Kit
+
+### Verification
+
+If you have installed jacktrip, from anywhere in the Terminal, type:
+```sh
+$ jacktrip -v
+```
+
+If you have compiled from source without installing, in the `/builddir`
+directory type:
+```sh
+$ ./jacktrip -v
+```
+
+If you see something like this, you have successfully installed JackTrip:
+
+```
+JackTrip VERSION: 1.x.x
+Copyright (c) 2008-2020 Juan-Pablo Caceres, Chris Chafe.
+SoundWIRE group at CCRMA, Stanford University
+```
+
diff --git a/docs/Build/Mac.md b/docs/Build/Mac.md
new file mode 100644 (file)
index 0000000..69c0428
--- /dev/null
@@ -0,0 +1,114 @@
+# Build Instructions
+
+The following are instructions for compiling Jacktrip from source.  Compiling
+from source is the best way to keep up with the latest changes, both stable and
+experimental.  For quicker ways to install Jacktrip, go to README.md in the root
+directory of the project.
+
+## Dependencies
+- C++ compiler
+- Qt5
+- JACK
+
+RtAudio is no longer a dependency.
+You might want to skip the steps you don't need.
+Install Jack2 https://jackaudio.org/downloads/
+
+If this command returns the XCode version, you have it installed:
+```sh
+xcodebuild -version
+```
+If you don't have XCode, go to the AppStore to download and install it.
+
+If this command returns the version number of the package manager Homebrew, you have it installed:
+```sh
+brew -v
+```
+If you don't have Homebrew, install it:
+```sh
+/bin/bash -c "$(curl -fsSLhttps://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
+```
+
+To install git if you don't have it:
+```sh
+brew install git
+```
+
+Install and link qt5:
+```sh
+brew install qt5
+brew link qt5 --force
+```
+
+Clone the git repo and run `./build` in the src directory or use QtCreator to compile
+
+## Build
+You can compile using the build script or QtCreator.
+
+To clone the repo in the Terminal:
+$ git clone --recurse-submodules https://github.com/jacktrip/jacktrip.git
+
+To compile using the build script:
+```sh
+$ cd jacktrip
+$ ./build
+$ cd builddir
+$ ls
+```
+
+You should see a `jacktrip` executable in this folder.
+
+If the build script doesn't work, try building
+the Makefiles yourself. You'd need qmake. Then you can build by:
+
+```sh
+$ qmake jacktrip.pro
+$ make release
+```
+
+To build using QtCreator:
+
+  * Open jacktrip.pro using QtCreator
+  * Choose a correctly configured Kit
+
+QtCreator places the `jacktrip` executabe by default in a folder
+with a name like `build-jacktrip-Desktop_x86_darwin_generic_mach_o_64bit-Release/`.
+
+## Installation
+You need to have a working Jack installation on your machine (see Dependencies above).
+
+To install using Terminal (skip the first three steps if you've already followed
+the Build instructions above):
+
+```sh
+$ git clone --recurse-submodules https://github.com/jacktrip/jacktrip.git
+$ cd jacktrip
+$ ./build
+$ cd builddir
+$ sudo cp qjacktrip /usr/local/bin/
+  (enter your password when prompted)
+$ sudo cp jacktrip /usr/local/bin/
+
+$ sudo chmod 755 /usr/local/bin/qjacktrip
+  (now you can run jacktrip from any directory using Terminal)
+```
+  
+### Verification
+
+If you have installed jacktrip, from anywhere in the Terminal, type:
+```sh
+$ jacktrip -v
+```
+
+If you have compiled from source without installing, in the /builddir directory type:
+```sh
+$ ./jacktrip -v
+```
+
+If you see something like this, you have successfully installed Jacktrip:
+
+>     JackTrip VERSION: 1.xx
+>     Copyright (c) 2008-2020 Juan-Pablo Caceres, Chris Chafe.
+>     SoundWIRE group at CCRMA, Stanford University
+
diff --git a/docs/Build/Meson_build.md b/docs/Build/Meson_build.md
new file mode 100644 (file)
index 0000000..3ece861
--- /dev/null
@@ -0,0 +1,83 @@
+# Build and Installation Instructions with Meson
+
+Meson is a modern and fast build system with a lot of features. You can
+find its documentation at [mesonbuild.com](https://mesonbuild.com/).
+
+## Install Dependencies
+
+=== "Fedora"
+
+    ```bash
+    dnf install meson qt5-qtbase-devel rtaudio-devel "pkgconfig(jack)" help2man
+    ```
+
+=== "Debian/Ubuntu"
+
+    ```bash
+    apt install meson build-essential qtbase5-dev librtaudio-dev libjack-jackd2-dev help2man
+    ```
+
+=== "MacOS"
+
+    ```bash
+    brew install meson qt5 rt-audio help2man
+    ```
+    
+    You also need to install Jack, unless you want to disable jack support
+    (`-Djack=disabled`). On macOS Jack is often installed using an installer
+    from the [Jack2 release
+    page](https://github.com/jackaudio/jack2-releases/releases). You can also
+    install it using homebrew (`brew install jack`), but you should not use both
+    installation methods simultaneously.
+
+    Meson might not find qt when installed with brew. But brew tells you to set
+    PKG_CONFIG_PATH to a directory where it finds qt's pkgconfig file.
+    This directory has to be set as additional pkgconfig path in meson:
+
+    ```bash
+    meson --buildtype release --pkg-config-path `brew --prefix qt5`/lib/pkgconfig build_release
+    ``` 
+
+## Configuration
+
+If you are in a build directory, `meson configure` shows you all available options.
+Current project options are `jack`, `nogui`, `rtaudio` and `wair`.
+Meson shows you also the options of subprojects like RtAudio.
+
+## Build
+
+Meson builds in a separate directory. It doesn't touch anything of your project.
+This way you can have seperate debug and release build directories for example. 
+
+Prepare your build directory:
+```bash
+meson builddir                                  # defaults to debug build
+
+## Additional build directories
+meson --buildtype release build_release         # release build
+meson --buildtype debugoptimized build_debug    # optimized debug build
+```
+
+Meson can download and build RtAudio as a subproject, if RtAudio is not available
+on your system. By default it only checks the dependency on your system. If you
+want to use the subproject you have to explicitly enable rtaudio.
+
+```bash
+cd builddir
+meson configure -Drtaudio=enabled
+```
+
+If `help2man` is found, Meson will create a manpage from `jacktrip --help`.
+
+Now build with:
+```bash
+cd builddir
+ninja
+```
+
+Install with:
+```bash
+sudo ninja install
+```
+
+
diff --git a/docs/Build/Windows.md b/docs/Build/Windows.md
new file mode 100644 (file)
index 0000000..bd7dc90
--- /dev/null
@@ -0,0 +1,84 @@
+# WINDOWS (XP and later)
+- Note: Some users have reported success using the PortAudio driver, though it
+  is not currently supported.
+
+## Build
+Note: [WIN10BUILDINSTRUCTIONS.pdf](WIN10BUILDINSTRUCTIONS.pdf)
+(in the same directory as this file) has screenshots of the Windows 10 build process
+and step-by-step instructions.
+
+If you do not have Git installed, download it from https://git-scm.com/download/win.
+Open the command line by typing cmd.exe in the Windows search bar.
+
+Use the `cd` command to navigate to the directory where you would like to
+install jacktrip, e.g. `cd C:\Users\Your User Name\`.
+
+Use `git clone --recurse-submodules https://github.com/jacktrip/jacktrip.git` to
+download a fresh copy of the repo or `git pull` to update your repo.
+
+On Windows 10, the easiest way to build is in the command line:
+
+- To add the location of qmake to the path, in the Windows search bar, type
+"environment variable" and click on the Environment Variables button in the
+Advanced tab of System Properties.  Find the Path variable in System variables,
+click Edit, and enter the location of qmake, e.g. `C:\Qt\5.15.0\mingw81_64\bin`,
+where 5.15.0 is the version of Qt you installed.
+To verify you have g++ installed, type `where g++` in the command line.  If the
+command returns `not found` rather than a path, go to the Qt Maintenance Tool,
+which might be in a directory such as `C:\Qt\maintenancetool.exe`, and remove,
+then reinstall Qt.
+In the command line, use the `cd` command to navigate to the project directory,
+e.g. `cd jacktrip` and execute the following commands:
+mkdir builddir (this step creates the build directory, and is only necessary if
+you're building for the first time)
+
+```sh
+$ cd builddir
+$ qmake -spec win32-g++ ../src/jacktrip.pro # you may skip this step if you're building for the first time
+$ mingw32-make clean # you may skip this step if you're building for the first time
+$ qmake -spec win32-g++ ../src/jacktrip.pro
+$ mingw32-make release
+```
+
+On earlier Windows versions, the easiest way to build is to download the free
+*Qt Creator IDE* from https://www.qt.io/download since the jacktrip buildscript is
+written in qmake.
+Open the `src/jacktrip.pro` and configure the project.
+Make sure to select the MinGW compiler (for example the one shipped with QtCreator).
+Building with Clang or Microsoft Visual Studio Compilers is currently not supported!
+
+Download Jack2 from https://jackaudio.org/downloads/
+Make sure to install Jack into `C:\Program Files (x86)\Jack` (as this is the
+path where the jacktrip build script will look for it).
+
+Hit <kbd>build</kbd> in QtCreator.
+
+Copy the dll files `Qt5Core.dll` and `Qt5Network.dll` from your compiler's bin
+directory, e.g. `C:\Qt\5.15.0\mingw81_64\bin` to the folder in your project
+where your `jacktrip.exe` is located, e.g.
+`C:\Users\Your Name\jacktrip\build-jacktrip-Desktop-Qt_5_15_0_MinGW_64_bit-Release\release`.
+In the above example, 5.15.0 is the version of Qt, MinGW 64 bit is the compiler.
+The folder names may vary according to the Qt and compiler versions you are
+using.
+
+Note: compiling with modifications in the .pro file (like adding a new source or
+      header file) requires qmake which is only available in the Qt Creator
+      package.
+
+## Verification
+In the search field (Windows key + R), enter cmd.exe to open the command line.
+Use the `cd` command to navigate to the directory where the executable
+jacktrip.exe is located, e.g.
+`C:\Users\Your Name\jacktrip\build-jacktrip-Desktop-Qt_5_15_0_MinGW_64_bit-Release\release`.
+
+From there, the following command should return the version of Jacktrip you installed:
+~~~sh
+jacktrip.exe -v
+~~~
+
+If you see something like this, you have successfully installed Jacktrip:
+
+>     JackTrip VERSION: 1.xx
+>     Copyright (c) 2008-2020 Juan-Pablo Caceres, Chris Chafe.
+>     SoundWIRE group at CCRMA, Stanford University
+
diff --git a/docs/DevTools/Formatting.md b/docs/DevTools/Formatting.md
new file mode 100644 (file)
index 0000000..17f88c1
--- /dev/null
@@ -0,0 +1,34 @@
+# Formatting with clang-format
+
+JackTrip uses clang-format to specify the Code Formatting Style.
+Most IDEs are able to recognize the `.clang-format` file in JackTrip's project
+directory and integrate the formatting capabilities.
+
+Formatting specific files is done like this:
+
+```bash
+clang-format -i class.cpp class.h
+```
+
+This overrides all given files. If you only want to check the formatting `-i` has
+to be removed.
+
+Areas in the source code that must not be formatted have to be embraced in following statements:
+
+```c++
+this = is.formatted;
+// clang-format off
+this+=   isnot     ;
+// clang-format on
+this = again;
+```
+
+## Formatting the entire code base
+
+Formatting the entire code base can be done with specifying all code files of the project
+or be invoking Meson's clang-format target:
+
+```bash
+ninja -C builddir clang-format
+```
+
diff --git a/docs/DevTools/StaticAnalysis.md b/docs/DevTools/StaticAnalysis.md
new file mode 100644 (file)
index 0000000..6145c28
--- /dev/null
@@ -0,0 +1,48 @@
+# Static Analysis
+
+Static analysis tools usually needs a `compile_commands.json` file.
+If you use Meson to build JackTrip, it already created this file in your build
+directory.
+
+## Scan-Build
+
+If you only want to run basic static analysis on JackTrip, you can install
+scan-build. Meson will automatically generate a scan-build target for you:
+
+```bash
+ninja -C builddir scan-build
+```
+
+This should never show any warnings or errors.
+
+## Clang-Tidy
+
+If you installed [clang-tidy](https://clang.llvm.org/extra/clang-tidy/) and
+there's a `.clang-tidy` file in the project directory,
+Meson generates a clang-tidy target, too. 
+The `.clang-tidy` file defines which [checks](https://clang.llvm.org/extra/clang-tidy/checks/list.html)
+should be run.
+Running clang-tidy on the entire code base:
+
+```bash
+ninja -C builddir clang-tidy
+```
+
+In most cases you want to run clang-tidy on single files.
+
+```bash
+cd src
+run-clang-tidy.py -j 4 -p ../builddir singlefile.cpp
+```
+
+In `-j #`, `#` specifies the number of tidy instances that run in parallel.
+
+### Fixes
+
+For some checks clang-tidy offers automatic fixes. Some of these are save to apply
+without worries. Others should be checked afterwards.
+
+```bash
+run-clang-tidy.py -fix -j 4 -p ../builddir singlefile.cpp
+```
+
diff --git a/docs/Documentation/MkDocs.md b/docs/Documentation/MkDocs.md
new file mode 100644 (file)
index 0000000..9339448
--- /dev/null
@@ -0,0 +1,20 @@
+# Write Documentation
+
+This documentation of JackTrip is generated with [Material](https://squidfunk.github.io/mkdocs-material/)
+for [MkDocs](https://www.mkdocs.org/). All pages are derived from Markdown files in the subdirectory `docs`
+in JackTrip's git repository. Setup and table of contents is found in a YAML file called mkdocs.yml in
+the root directory.
+
+If you only want to edit a page you can click on the pen symbol at the top of each page.
+
+## Run MkDocs on Your System
+
+MkDocs and Material for MkDocs are installed from pip:
+```bash
+pip install mkdocs mkdocs-material
+``` 
+
+When writing documentation it is very handy to run `mkdocs serve`. This will open
+a local webserver (usually at [http://127.0.0.1:8000/](http://127.0.0.1:8000/)).
+If you change Markdown files of the documentation and save them, the website automatically
+updates. 
diff --git a/docs/Install.md b/docs/Install.md
new file mode 100644 (file)
index 0000000..7acdb37
--- /dev/null
@@ -0,0 +1,30 @@
+# Installation
+## Linux
+On Linux the easiest way to install JackTrip is to use the distribution's package manager.
+
+=== "Fedora"
+
+    ```bash
+    sudo dnf install jacktrip
+    ```
+
+=== "Debian/Ubuntu"
+
+    ```bash
+    sudo apt install jacktrip
+    ```
+
+The [GitHub releases page](https://github.com/jacktrip/jacktrip/releases) also includes a binary which should run on most Linux distributions (x64). This build is known to not look well under Wayland.
+
+## macOS
+macOS installer and application bundle are available on the [GitHub releases page](https://github.com/jacktrip/jacktrip/releases). The installer will install the JackTrip app in `/Applications`, as well as create a link to the `jacktrip` executable in `/usr/local/bin` for use in the command line.
+
+## Windows
+Windows installer and executable are available on the [GitHub releases page](https://github.com/jacktrip/jacktrip/releases). The installer will add a shortcut to your Start menu.
+
+# Experimental builds
+
+To keep up with the latest changes, including experimental functionality, you can access builds from the `dev` branch for Linux, macOS and Windows at [https://nightly.link/jacktrip/jacktrip/workflows/jacktrip/dev](https://nightly.link/jacktrip/jacktrip/workflows/jacktrip/dev). Please note that macOS binaries are not signed, so you need to right-click and select "Open" in order to run them.
+
+# Build from Source
+To build JackTrip yourself, follow instructions to compile for [Linux](Build/Linux.md), [MacOS](Build/Mac.md) or [Windows](Build/Windows.md).
diff --git a/docs/index.md b/docs/index.md
new file mode 100644 (file)
index 0000000..8c39f3a
--- /dev/null
@@ -0,0 +1,6 @@
+# Welcome to JackTrip
+
+JackTrip is a Linux, macOS, or Windows multi-machine audio system used for network music performance over the Internet.
+It supports any number of channels (as many as the computer/network can handle) of bidirectional, high quality, uncompressed audio signal streaming.
+
+You can use it between any combination of machines e.g., one end using Linux can connect to another using macOS.
index fd7d3abe80818dc090eb052f922fbfcffcff07da..e19bf51d9e06af01428860ec30dc4368503d4954 100644 (file)
@@ -5,7 +5,7 @@
 
   Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
-  
+
   Permission is hereby granted, free of charge, to any person
   obtaining a copy of this software and associated documentation
   files (the "Software"), to deal in the Software without
   copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following
   conditions:
-  
+
   The above copyright notice and this permission notice shall be
   included in all copies or substantial portions of the Software.
-  
+
   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  * \date July 2008
  */
 
-
 // Main Page Documentation
 //-----------------------------------------------------------------
 /**
-\mainpage JackTrip Documentation
-    
+\mainpage JackTrip API Documentation
+
 \section intro_sec About JackTrip
 
 JackTrip: A System for High-Quality Audio Network Performance
 over the Internet.
 
-JackTrip is a Linux and Mac OS X-based system used for multi-machine network
-performance over the Internet. It supports any number of channels
+JackTrip is a multi-machine network music
+performance system over the Internet. It supports any number of channels
 (as many as the computer/network can handle) of bidirectional, high quality,
 uncompressed audio signal steaming.
 
-You can use it between any combination of Linux and Mac OS X
-(i.e., one end using Linux can connect to the other using Mac OS X).
-
-It is currently being developed and actively tested at CCRMA by the SoundWIRE group.
-
-
-
-\section install_sec Installation
-
-Download the latest release:
-<a href="http://code.google.com/p/jacktrip/">Download</a>
-
-Please read the documentation inside the packet to install.
-
-\subsection install_subsec_osx Mac OS X Requirements
-
-You'll need: <a href="https://jackaudio.org/downloads/">Jack OS X</a>.
-The documentation explains how to install it and set it up, and it's highly recommended.
-
-Jack OS X comes with JackPilot to do the audio routing.
-An alternative is <a href="http://qjackctl.sourceforge.net/">qjackctl</a>,
-which I find easier to use. You can find the binary here:
-<a href="http://www.ardour.org/osx_system_requirements">qjackctl mac binary</a>
-
-If you use Leopard, you won't need to configure the UDP ports manually.
-
-\subsubsection install_linux Linux Requirements
+General information for users and developers can be found at
+<a href="https://jacktrip.github.io/jacktrip/">the JackTrip documentation</a>.
 
-Please read the documentation inside the packet to compile and install in linux.\n
-The older version of JackTrip is documented 
-<a href="http://ccrma.stanford.edu/groups/soundwire/software/jacktrip/">here</a>.
-Please follow those instructions to configure the firewall under 
-
-
-
-\section using Using JackTrip
-
-Type jacktrip in a terminal window to display a help list with all the options.
-JackTrip uses Jack as its audio server. You have to make sure that the settings in
-Jack are the same in the local and remote machine.
-
-There are two parameters that you want to tweak: Frames/Period and Sample Rate.
-The Lower the Frames/Period, the lower the latency.
-The higher the Sampling Rate, the higher the bandwidth requirements.
-You have to make sure these settings match in both machines. 
-
-\image html jack_main_settings.jpg
-
-You also may want to look at the internal buffering
-<tt>-q, --queue</tt> parameter in JackTrip. If your connection is very unstable, with a lot of jitter,
-you should increase this number at the expense of a higher latency.
-
-The audio bit resolution parameter, <tt>-b, --bitres</tt>, can be use to decrease (or increase)
-the bandwidth requirements, at the expense of a lower audio quality.
-
-A basic connection will have one of the nodes as a server:
-
-<tt>jacktrip -s</tt>
-
-And the other as a client
-
-<tt>jacktrip -c [SERVER-IP-NUMBER]</tt>
-
-You'll see a JackTrip client in Jack. Everything you connect into the send ports
-will be transmitted to your peer. You'll receive what your peer sends you on the receive ports. 
-
-\image html jack_routing.png
+This is JackTrip's API documentation.
 
 */
-
-
diff --git a/documentation/footer.html b/documentation/footer.html
new file mode 100644 (file)
index 0000000..efa3357
--- /dev/null
@@ -0,0 +1,17 @@
+<!-- HTML footer for doxygen 1.9.1-->
+<!-- start footer part -->
+<!--BEGIN GENERATE_TREEVIEW-->
+<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
+  <ul>
+    $navpath
+    <li class="footer">$generatedby <a href="https://www.doxygen.org/index.html"><img class="footer" src="$relpath^doxygen.svg" width="104" height="31" alt="doxygen"/></a> $doxygenversion </li>
+  </ul>
+</div>
+<!--END GENERATE_TREEVIEW-->
+<!--BEGIN !GENERATE_TREEVIEW-->
+<hr class="footer"/><address class="footer"><small>
+$generatedby&#160;<a href="https://www.doxygen.org/index.html"><img class="footer" src="$relpath^doxygen.svg" width="104" height="31" alt="doxygen"/></a> $doxygenversion
+</small></address>
+<!--END !GENERATE_TREEVIEW-->
+</body>
+</html>
diff --git a/documentation/header.html b/documentation/header.html
new file mode 100644 (file)
index 0000000..9c4751e
--- /dev/null
@@ -0,0 +1,56 @@
+<!-- HTML header for doxygen 1.9.1-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<meta http-equiv="X-UA-Compatible" content="IE=9"/>
+<meta name="generator" content="Doxygen $doxygenversion"/>
+<meta name="viewport" content="width=device-width, initial-scale=1"/>
+<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
+<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
+<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
+<script type="text/javascript" src="$relpath^jquery.js"></script>
+<script type="text/javascript" src="$relpath^dynsections.js"></script>
+$treeview
+$search
+$mathjax
+<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
+$extrastylesheet
+</head>
+<body>
+<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
+
+<!--BEGIN TITLEAREA-->
+<div id="titlearea">
+<table cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr style="height: 56px;">
+  <!--BEGIN PROJECT_LOGO-->
+  <td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
+  <!--END PROJECT_LOGO-->
+  <!--BEGIN PROJECT_NAME-->
+  <td id="projectalign" style="padding-left: 0.5em;">
+   <div id="projectname">$projectname
+   <!--BEGIN PROJECT_NUMBER-->&#160;<span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
+   </div>
+   <!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
+  </td>
+  <!--END PROJECT_NAME-->
+  <!--BEGIN !PROJECT_NAME-->
+   <!--BEGIN PROJECT_BRIEF-->
+    <td style="padding-left: 0.5em;">
+    <div id="projectbrief">$projectbrief</div>
+    </td>
+   <!--END PROJECT_BRIEF-->
+  <!--END !PROJECT_NAME-->
+  <!--BEGIN DISABLE_INDEX-->
+   <!--BEGIN SEARCHENGINE-->
+   <td>$searchbox</td>
+   <!--END SEARCHENGINE-->
+  <!--END DISABLE_INDEX-->
+ </tr>
+ </tbody>
+</table>
+</div>
+<!--END TITLEAREA-->
+<!-- end header part -->
diff --git a/documentation/html_footer.html b/documentation/html_footer.html
deleted file mode 100644 (file)
index d23d80d..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-</BODY>
-</HTML>
-<center>
-<footer>
-<p>&nbsp</p>
-<font size="1">
-<p>Documentation generated by Doxygen $doxygenversion</p>
-<p>
-&copy; 2008 by Juan-Pablo Caceres (jcaceres <em>at</em> ccrma <em>dot</em> stanford <em>dot</em> edu) and
-Chris Chafe<br />
-<a href="http://ccrma.stanford.edu/groups/soundwire/" title="SoundWIRE Group">SoundWIRE Group</a> at 
-<a href="http://ccrma.stanford.edu/" title="CCRMA home">CCRMA</a> - 
-<a href="http://www.stanford.edu/" title="Stanford home">Stanford University</a>
-</font>
-<p>
-<a href="http://sourceforge.net">SourceForge</a>
-</p>
-</center>
-</footer>
index 3404470d60be84d0b1b850b329fe74c403afbf76..8c7259fa5a357840ce85578bfe08aea31f660215 100644 (file)
@@ -6,7 +6,6 @@
 // See the Makefile for how to use it.
 
 #include <faust/dsp/dsp.h>
-
 #include <faust/gui/APIUI.h>
 
 // NOTE: "faust -scn name" changes the last line above to
@@ -15,7 +14,9 @@
 //----------------------------------------------------------------------------
 //  FAUST Generated Code
 //----------------------------------------------------------------------------
-
+// clang-format off
 <<includeIntrinsic>>
 
-<<includeclass>>
+    <<includeclass>>
+
+    // clang-format on
index 2d1222ade8f7bd65fe559943afabda19c50d84db..3310519d01953973cad561e8a74ea7c39b448757 100644 (file)
 #ifdef __GNUC__
 
-#define max(x,y) (((x)>(y)) ? (x) : (y))
-#define min(x,y) (((x)<(y)) ? (x) : (y))
+#define max(x, y) (((x) > (y)) ? (x) : (y))
+#define min(x, y) (((x) < (y)) ? (x) : (y))
 
 // abs is now predefined
-//template<typename T> T abs (T a)                     { return (a<T(0)) ? -a : a; }
+// template<typename T> T abs (T a)                    { return (a<T(0)) ? -a : a; }
 
-
-inline int             lsr (int x, int n)                      { return int(((unsigned int)x) >> n); }
+inline int lsr(int x, int n) { return int(((unsigned int)x) >> n); }
 
 /******************************************************************************
 *******************************************************************************
 
-                                                              VECTOR INTRINSICS
+                                                               VECTOR INTRINSICS
 
 *******************************************************************************
 *******************************************************************************/
 
-//inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((unsigned)(calloc((nmemb*size)+15,sizeof(char)))+15 & 0xfffffff0); }
-inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((size_t)(calloc((nmemb*size)+15,sizeof(char)))+15 & ~15); }
+// inline void *aligned_calloc(size_t nmemb, size_t size) { return
+// (void*)((unsigned)(calloc((nmemb*size)+15,sizeof(char)))+15 & 0xfffffff0); }
+inline void* aligned_calloc(size_t nmemb, size_t size)
+{
+    return (void*)((size_t)(calloc((nmemb * size) + 15, sizeof(char))) + 15 & ~15);
+}
 
+// clang-format off
 <<includeIntrinsic>>
+    // clang-format on
 
-/******************************************************************************
+    /******************************************************************************
 *******************************************************************************
 
-                       ABSTRACT USER INTERFACE
+                        ABSTRACT USER INTERFACE
 
 *******************************************************************************
 *******************************************************************************/
 
-class UI
+    class UI
 {
-       bool    fStopped;
-public:
-               
-       UI() : fStopped(false) {}
-       virtual ~UI() {}
-       
-       virtual void addButton(char* label, float* zone) = 0;
-       virtual void addToggleButton(char* label, float* zone) = 0;
-       virtual void addCheckButton(char* label, float* zone) = 0;
-       virtual void addVerticalSlider(char* label, float* zone, float init, float min, float max, float step) = 0;
-       virtual void addHorizontalSlider(char* label, float* zone, float init, float min, float max, float step) = 0;
-       virtual void addNumEntry(char* label, float* zone, float init, float min, float max, float step) = 0;
-       
-       virtual void openFrameBox(char* label) = 0;
-       virtual void openTabBox(char* label) = 0;
-       virtual void openHorizontalBox(char* label) = 0;
-       virtual void openVerticalBox(char* label) = 0;
-       virtual void closeBox() = 0;
-       
-       virtual void run() = 0;
-       
-       void stop()     { fStopped = true; }
-       bool stopped()  { return fStopped; }
+    bool fStopped;
+
+   public:
+    UI() : fStopped(false) {}
+    virtual ~UI() {}
+
+    virtual void addButton(char* label, float* zone)        = 0;
+    virtual void addToggleButton(char* label, float* zone)  = 0;
+    virtual void addCheckButton(char* label, float* zone)   = 0;
+    virtual void addVerticalSlider(char* label, float* zone, float init, float min,
+                                   float max, float step)   = 0;
+    virtual void addHorizontalSlider(char* label, float* zone, float init, float min,
+                                     float max, float step) = 0;
+    virtual void addNumEntry(char* label, float* zone, float init, float min, float max,
+                             float step)                    = 0;
+
+    virtual void openFrameBox(char* label)      = 0;
+    virtual void openTabBox(char* label)        = 0;
+    virtual void openHorizontalBox(char* label) = 0;
+    virtual void openVerticalBox(char* label)   = 0;
+    virtual void closeBox()                     = 0;
+
+    virtual void run() = 0;
+
+    void stop() { fStopped = true; }
+    bool stopped() { return fStopped; }
 };
 
-
-
-
 /******************************************************************************
 *******************************************************************************
 
-                           FAUST DSP
+                            FAUST DSP
 
 *******************************************************************************
 *******************************************************************************/
 
-
-
 //----------------------------------------------------------------
 //  abstract definition of a signal processor
 //----------------------------------------------------------------
-                       
-class dsp {
- protected:
-       int fSamplingFreq;
- public:
-       dsp() {}
-       virtual ~dsp() {}
-
-       virtual int getNumInputs()                                              = 0;
-       virtual int getNumOutputs()                                     = 0;
-       virtual void buildUserInterface(UI* interface)  = 0;
-       virtual void init(int samplingRate)                     = 0;
-       virtual void compute(int len, float** inputs, float** outputs)  = 0;
+
+class dsp
+{
+   protected:
+    int fSamplingFreq;
+
+   public:
+    dsp() {}
+    virtual ~dsp() {}
+
+    virtual int getNumInputs()                                     = 0;
+    virtual int getNumOutputs()                                    = 0;
+    virtual void buildUserInterface(UI* interface)                 = 0;
+    virtual void init(int samplingRate)                            = 0;
+    virtual void compute(int len, float** inputs, float** outputs) = 0;
 };
-               
 
 //----------------------------------------------------------------------------
 //  FAUST generated signal processor
 //----------------------------------------------------------------------------
-               
-
+// clang-format off
 <<includeclass>>
+    // clang-format on
diff --git a/jacktrip.pro b/jacktrip.pro
new file mode 100644 (file)
index 0000000..3a86ce3
--- /dev/null
@@ -0,0 +1,344 @@
+#******************************
+# Created by Juan-Pablo Caceres
+#******************************
+
+CONFIG += c++11 console
+CONFIG -= app_bundle
+
+CONFIG += qt thread debug_and_release build_all
+CONFIG(debug, debug|release) {
+    TARGET = jacktrip_debug
+    application_id = 'org.jacktrip.JackTrip.Devel'
+    name_suffix = ' (Development Snapshot)'
+  } else {
+    TARGET = jacktrip
+    application_id = 'org.jacktrip.JackTrip'
+    name_suffix = ''
+}
+
+equals(QT_EDITION, "OpenSource") {
+    DEFINES += QT_OPENSOURCE
+}
+
+nogui {
+  DEFINES += NO_GUI
+} else {
+  QT += gui
+  QT += widgets
+}
+
+QT += network
+
+# switch added in rc.1.2 enables wair build, some of it merged as WAIRTOHUB
+# DEFINES += WAIR
+DEFINES += WAIRTOHUB
+
+# configuration with RtAudio
+rtaudio|bundled_rtaudio {
+  message(Building with RtAudio)
+  DEFINES += __RT_AUDIO__
+}
+# Configuration without Jack
+nojack {
+  DEFINES += __NO_JACK__
+}
+
+# for plugins
+INCLUDEPATH += faust-src-lair/stk
+
+!win32 {
+  INCLUDEPATH+=/usr/local/include
+# wair needs stk, can be had from linux this way
+# INCLUDEPATH+=/usr/include/stk
+# LIBS += -L/usr/local/lib -ljack -lstk -lm
+  LIBS += -L/usr/local/lib -lm
+  weakjack {
+    message(Building with weak linking of JACK)
+    INCLUDEPATH += externals/weakjack
+    DEFINES += USE_WEAK_JACK
+  } else {
+    nojack {
+      message(Building NONJACK)
+    } else {
+      CONFIG += link_pkgconfig
+      PKGCONFIG += jack
+    }
+  }
+}
+
+bundled_rtaudio {
+  INCLUDEPATH += externals/rtaudio/
+  LIBS += -L$${OUT_PWD} -L$${OUT_PWD}/debug -L$${OUT_PWD}/release -lrtaudio
+  linux-g++ | linux-g++-64 {
+    LIBS += -lasound -lpthread -lpulse-simple -lpulse
+  }
+  macx {
+    LIBS += -lpthread -framework CoreAudio -framework CoreFoundation
+  }
+  win32 {
+    LIBS += -lole32 -lwinmm -lksuser -lmfplat -lmfuuid -lwmcodecdspuuid
+  }
+} else {
+  rtaudio {
+    # pkg-config is required for building with system-provided rtaudio
+    CONFIG += link_pkgconfig
+    PKGCONFIG += rtaudio
+    win32 {
+      # even though we get linker flags from pkg-config, define -lrtaudio again to enforce linking order
+      CONFIG += no_lflags_merge    
+      LIBS += -lrtaudio -lole32 -lwinmm -lksuser -lmfplat -lmfuuid -lwmcodecdspuuid # -ldsound # -ldsound only needed if rtaudio is built with directsound support
+    }
+  }
+}
+
+macx {
+  message(Building on MAC OS X)
+  QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.9
+  #QMAKE_MAC_SDK = macosx10.9
+  CONFIG -= app_bundle
+  #CONFIG += x86 #ppc #### If you have both libraries installed, you
+  # can change between 32bits (x86) or 64bits(x86_64) Change this to go back to 32 bits (x86)
+  LIBS += -framework CoreAudio -framework CoreFoundation
+  DEFINES += __MAC_OSX__
+  !nogui {
+    LIBS += -framework Foundation
+    CONFIG += objective_c
+  }
+}
+
+linux-g++ | linux-g++-64 {
+  
+  FEDORA = $$system(cat /proc/version | grep -o fc)
+  
+  contains( FEDORA, fc): {
+    message(building on fedora)
+  }
+  
+  UBUNTU = $$system(cat /proc/version | grep -o Ubuntu)
+  
+  contains( UBUNTU, Ubuntu): {
+    message(building on  Ubuntu)
+    
+    # workaround for Qt bug under ubuntu 18.04
+    # gcc version 7.3.0 (Ubuntu 7.3.0-16ubuntu3)
+    # QMake version 3.1
+    # Using Qt version 5.9.5 in /usr/lib/x86_64-linux-gnu
+    INCLUDEPATH += /usr/include/x86_64-linux-gnu/c++/7
+    
+    # sets differences from original fedora version
+    DEFINES += __UBUNTU__
+  }
+  
+  QMAKE_CXXFLAGS += -g -O2
+  DEFINES += __LINUX__
+}
+
+linux-g++ {
+  message(Linux)
+}
+
+linux-g++-64 {
+  message(Linux 64bit)
+}
+
+
+win32 {
+  message(Building on win32)
+#cc  CONFIG += x86 console
+  CONFIG += c++11 console
+  exists("C:\Program Files\JACK2") {
+    message("using Jack in C:\Program Files\JACK2")
+    INCLUDEPATH += "C:\Program Files\JACK2\include"
+    weakjack {
+      message(Building with weak linking of JACK)
+      INCLUDEPATH += externals/weakjack
+      DEFINES += USE_WEAK_JACK
+    } else {
+      LIBS += "C:\Program Files\JACK2\lib\libjack64.lib"
+      LIBS += "C:\Program Files\JACK2\lib\libjackserver64.lib"
+    }
+  } else {
+    exists("C:\Program Files (x86)\Jack") {
+      message("using Jack in C:\Program Files (x86)\Jack")
+      INCLUDEPATH += "C:\Program Files (x86)\Jack\includes"
+      weakjack {
+        message(Building with weak linking of JACK)
+        INCLUDEPATH += externals/weakjack
+        DEFINES += USE_WEAK_JACK
+      } else {
+        LIBS += "C:\Program Files (x86)\Jack\lib\libjack64.lib"
+        LIBS += "C:\Program Files (x86)\Jack\lib\libjackserver64.lib"
+      }
+    } else {
+      message("Jack library not found")
+    }
+  }
+  LIBS += -lWs2_32
+  DEFINES += __WIN_32__
+  DEFINES += _WIN32_WINNT=0x0600 #needed for inet_pton
+  DEFINES += WIN32_LEAN_AND_MEAN
+}
+
+DESTDIR = .
+QMAKE_CLEAN += -r ./jacktrip ./jacktrip_debug ./release/* ./debug/* ./$${application_id}.xml ./$${application_id}.desktop ./$${application_id}.png ./$${application_id}.svg ./jacktrip.1 ./librtaudio.a
+
+# isEmpty(PREFIX) will allow path to be changed during the command line
+# call to qmake, e.g. qmake PREFIX=/usr
+isEmpty(PREFIX) {
+ PREFIX = /usr/local
+}
+target.path = $$PREFIX/bin/
+INSTALLS += target
+
+# for plugins
+INCLUDEPATH += faust-src-lair
+
+# Input
+HEADERS += src/DataProtocol.h \
+           src/JackTrip.h \
+           src/Effects.h \
+           src/Compressor.h \
+           src/CompressorPresets.h \
+           src/Limiter.h \
+           src/PoolBuffer.h \
+           src/Reverb.h \
+           src/AudioTester.h \
+           src/jacktrip_globals.h \
+           src/jacktrip_types.h \
+           src/JackTripWorker.h \
+           src/JitterBuffer.h \
+           src/LoopBack.h \
+           src/PacketHeader.h \
+           src/ProcessPlugin.h \
+           src/RingBuffer.h \
+           src/RingBufferWavetable.h \
+           src/Settings.h \
+           src/UdpDataProtocol.h \
+           src/UdpHubListener.h \
+           src/AudioInterface.h \
+           src/compressordsp.h \
+           src/limiterdsp.h \
+           src/freeverbdsp.h \
+           src/SslServer.h \
+           src/Auth.h
+#(Removed JackTripThread.h JackTripWorkerMessages.h NetKS.h TestRingBuffer.h ThreadPoolTest.h)
+
+!nojack {
+HEADERS += src/JackAudioInterface.h \
+           src/JMess.h \
+           src/Patcher.h
+}
+
+!nogui {
+HEADERS += src/gui/about.h \
+           src/gui/messageDialog.h \
+           src/gui/qjacktrip.h
+}
+
+rtaudio|bundled_rtaudio {
+    HEADERS += src/RtAudioInterface.h
+}
+
+SOURCES += src/DataProtocol.cpp \
+           src/JackTrip.cpp \
+           src/Compressor.cpp \
+           src/Limiter.cpp \
+           src/PoolBuffer.cpp \
+           src/Reverb.cpp \
+           src/AudioTester.cpp \
+           src/jacktrip_globals.cpp \
+           src/JackTripWorker.cpp \
+           src/JitterBuffer.cpp \
+           src/LoopBack.cpp \
+           src/PacketHeader.cpp \
+           src/RingBuffer.cpp \
+           src/Settings.cpp \
+           src/UdpDataProtocol.cpp \
+           src/UdpHubListener.cpp \
+           src/AudioInterface.cpp \
+           src/main.cpp \
+           src/SslServer.cpp \
+           src/Auth.cpp
+#(Removed jacktrip_main.cpp jacktrip_tests.cpp JackTripThread.cpp ProcessPlugin.cpp)
+
+!nojack {
+SOURCES += src/JackAudioInterface.cpp \
+           src/JMess.cpp \
+           src/Patcher.cpp
+}
+
+!nogui {
+SOURCES += src/gui/messageDialog.cpp \
+           src/gui/qjacktrip.cpp \
+           src/gui/about.cpp
+}
+
+!nogui {
+  macx {
+    HEADERS += src/gui/NoNap.h
+    OBJECTIVE_SOURCES += src/gui/NoNap.mm
+  }
+
+  FORMS += src/gui/qjacktrip.ui src/gui/about.ui src/gui/messageDialog.ui
+  RESOURCES += src/gui/qjacktrip.qrc
+}
+
+rtaudio|bundled_rtaudio {
+    SOURCES += src/RtAudioInterface.cpp
+}
+
+weakjack {
+  SOURCES += externals/weakjack/weak_libjack.c
+}
+
+# install man page
+!win32 {
+    HELP2MAN_BIN = $$system(which help2man)
+
+    isEmpty(HELP2MAN_BIN) {
+        message("help2man not found")
+    } else {
+        message("Building man page with help2man")
+        man.extra = $${HELP2MAN_BIN} --no-info --section=1 --output $${OUT_PWD}/jacktrip.1 $${OUT_PWD}/jacktrip
+        man.CONFIG += no_check_exist
+        man.files = $${OUT_PWD}/jacktrip.1
+        man.path = $${PREFIX}/share/man/man1
+        INSTALLS += man
+    }
+}
+
+# install Linux desktop integration resources
+if(linux-g++ | linux-g++-64):!nogui {
+    appdata = $$cat($${PWD}/linux/org.jacktrip.JackTrip.metainfo.xml.in, blob)
+    appdata = $$replace(appdata, @appid@, $${application_id})
+    write_file($${OUT_PWD}/$${application_id}.metainfo.xml, appdata)
+
+    metainfo.files = $${OUT_PWD}/$${application_id}.metainfo.xml
+    metainfo.path = $${PREFIX}/share/metainfo
+
+    desktop_conf = $$cat($${PWD}/linux/org.jacktrip.JackTrip.desktop.in, blob)
+    desktop_conf = $$replace(desktop_conf, @icon@, $${application_id})
+    desktop_conf = $$replace(desktop_conf, @wmclass@, $$lower($${application_id}))
+    desktop_conf = $$replace(desktop_conf, @name_suffix@, $${name_suffix})
+    write_file($${OUT_PWD}/$${application_id}.desktop, desktop_conf)
+
+    desktop.files = $${OUT_PWD}/$${application_id}.desktop
+    desktop.path = $${PREFIX}/share/applications
+
+    icon48.extra = cp $${PWD}/linux/icons/jacktrip_48x48.png $${OUT_PWD}/$${application_id}.png
+    icon48.CONFIG += no_check_exist
+    icon48.files = $${OUT_PWD}/$${application_id}.png
+    icon48.path = $${PREFIX}/share/icons/hicolor/48x48/apps
+
+    icon_svg.extra = cp $${PWD}/linux/icons/jacktrip.svg $${OUT_PWD}/$${application_id}.svg
+    icon_svg.CONFIG += no_check_exist
+    icon_svg.files = $${OUT_PWD}/$${application_id}.svg
+    icon_svg.path = $${PREFIX}/share/icons/hicolor/scalable/apps
+
+    icon_symbolic.extra = cp $${PWD}/linux/icons/jacktrip-symbolic.svg $${OUT_PWD}/$${application_id}-symbolic.svg
+    icon_symbolic.CONFIG += no_check_exist
+    icon_symbolic.files = $${OUT_PWD}/$${application_id}-symbolic.svg
+    icon_symbolic.path = $${PREFIX}/share/icons/hicolor/symbolic/apps
+
+    INSTALLS += metainfo desktop icon48 icon_svg icon_symbolic
+}
diff --git a/jacktrip_and_rtaudio.pro b/jacktrip_and_rtaudio.pro
new file mode 100644 (file)
index 0000000..5d603ef
--- /dev/null
@@ -0,0 +1,14 @@
+# created by Marcin Pączkowski 
+# configuration for building JackTrip with the bundled RtAudio library
+# make sure to specify '-config bundled_rtaudio' when running qmake
+
+TEMPLATE = subdirs
+SUBDIRS = jacktrip \
+          rtaudio 
+
+jacktrip.file = jacktrip.pro
+rtaudio.file = rtaudio.pro
+
+jacktrip.depends = rtaudio
+
+CONFIG += debug_and_release
diff --git a/jacktrip_doxygen b/jacktrip_doxygen
deleted file mode 100644 (file)
index 8682067..0000000
+++ /dev/null
@@ -1,1418 +0,0 @@
-# Doxyfile 1.5.6
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project
-#
-# All text after a hash (#) is considered a comment and will be ignored
-# The format is:
-#       TAG = value [value, ...]
-# For lists items can also be appended using:
-#       TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (" ")
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# This tag specifies the encoding used for all characters in the config file 
-# that follow. The default is UTF-8 which is also the encoding used for all 
-# text before the first occurrence of this tag. Doxygen uses libiconv (or the 
-# iconv built into libc) for the transcoding. See 
-# http://www.gnu.org/software/libiconv for the list of possible encodings.
-
-DOXYFILE_ENCODING      = UTF-8
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
-# by quotes) that should identify the project.
-
-PROJECT_NAME           = JackTrip
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
-# This could be handy for archiving the generated documentation or 
-# if some version control system is used.
-
-PROJECT_NUMBER         = 
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
-# base path where the generated documentation will be put. 
-# If a relative path is entered, it will be relative to the location 
-# where doxygen was started. If left blank the current directory will be used.
-
-OUTPUT_DIRECTORY       = ./WWW/
-
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
-# 4096 sub-directories (in 2 levels) under the output directory of each output 
-# format and will distribute the generated files over these directories. 
-# Enabling this option can be useful when feeding doxygen a huge amount of 
-# source files, where putting all generated files in the same directory would 
-# otherwise cause performance problems for the file system.
-
-CREATE_SUBDIRS         = NO
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
-# documentation generated by doxygen is written. Doxygen will use this 
-# information to generate all constant output in the proper language. 
-# The default language is English, other supported languages are: 
-# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
-# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, 
-# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), 
-# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, 
-# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, 
-# and Ukrainian.
-
-OUTPUT_LANGUAGE        = English
-
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
-# include brief member descriptions after the members that are listed in 
-# the file and class documentation (similar to JavaDoc). 
-# Set to NO to disable this.
-
-BRIEF_MEMBER_DESC      = YES
-
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
-# the brief description of a member or function before the detailed description. 
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
-# brief descriptions will be completely suppressed.
-
-REPEAT_BRIEF           = YES
-
-# This tag implements a quasi-intelligent brief description abbreviator 
-# that is used to form the text in various listings. Each string 
-# in this list, if found as the leading text of the brief description, will be 
-# stripped from the text and the result after processing the whole list, is 
-# used as the annotated text. Otherwise, the brief description is used as-is. 
-# If left blank, the following values are used ("$name" is automatically 
-# replaced with the name of the entity): "The $name class" "The $name widget" 
-# "The $name file" "is" "provides" "specifies" "contains" 
-# "represents" "a" "an" "the"
-
-ABBREVIATE_BRIEF       = 
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
-# Doxygen will generate a detailed section even if there is only a brief 
-# description.
-
-ALWAYS_DETAILED_SEC    = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
-# inherited members of a class in the documentation of that class as if those 
-# members were ordinary class members. Constructors, destructors and assignment 
-# operators of the base classes will not be shown.
-
-INLINE_INHERITED_MEMB  = NO
-
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
-# path before files name in the file list and in the header files. If set 
-# to NO the shortest path that makes the file name unique will be used.
-
-FULL_PATH_NAMES        = YES
-
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
-# can be used to strip a user-defined part of the path. Stripping is 
-# only done if one of the specified strings matches the left-hand part of 
-# the path. The tag can be used to show relative paths in the file list. 
-# If left blank the directory from which doxygen is run is used as the 
-# path to strip.
-
-STRIP_FROM_PATH        = 
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
-# the path mentioned in the documentation of a class, which tells 
-# the reader which header file to include in order to use a class. 
-# If left blank only the name of the header file containing the class 
-# definition is used. Otherwise one should specify the include paths that 
-# are normally passed to the compiler using the -I flag.
-
-STRIP_FROM_INC_PATH    = 
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
-# (but less readable) file names. This can be useful is your file systems 
-# doesn't support long names like on DOS, Mac, or CD-ROM.
-
-SHORT_NAMES            = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
-# will interpret the first line (until the first dot) of a JavaDoc-style 
-# comment as the brief description. If set to NO, the JavaDoc 
-# comments will behave just like regular Qt-style comments 
-# (thus requiring an explicit @brief command for a brief description.)
-
-JAVADOC_AUTOBRIEF      = NO
-
-# If the QT_AUTOBRIEF tag is set to YES then Doxygen will 
-# interpret the first line (until the first dot) of a Qt-style 
-# comment as the brief description. If set to NO, the comments 
-# will behave just like regular Qt-style comments (thus requiring 
-# an explicit \brief command for a brief description.)
-
-QT_AUTOBRIEF           = NO
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
-# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
-# comments) as a brief description. This used to be the default behaviour. 
-# The new default is to treat a multi-line C++ comment block as a detailed 
-# description. Set this tag to YES if you prefer the old behaviour instead.
-
-MULTILINE_CPP_IS_BRIEF = NO
-
-# If the DETAILS_AT_TOP tag is set to YES then Doxygen 
-# will output the detailed description near the top, like JavaDoc.
-# If set to NO, the detailed description appears after the member 
-# documentation.
-
-DETAILS_AT_TOP         = NO
-
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
-# member inherits the documentation from any documented member that it 
-# re-implements.
-
-INHERIT_DOCS           = YES
-
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
-# a new page for each member. If set to NO, the documentation of a member will 
-# be part of the file/class/namespace that contains it.
-
-SEPARATE_MEMBER_PAGES  = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
-# Doxygen uses this value to replace tabs by spaces in code fragments.
-
-TAB_SIZE               = 8
-
-# This tag can be used to specify a number of aliases that acts 
-# as commands in the documentation. An alias has the form "name=value". 
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
-# put the command \sideeffect (or @sideeffect) in the documentation, which 
-# will result in a user-defined paragraph with heading "Side Effects:". 
-# You can put \n's in the value part of an alias to insert newlines.
-
-ALIASES                = 
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
-# sources only. Doxygen will then generate output that is more tailored for C. 
-# For instance, some of the names that are used will be different. The list 
-# of all members will be omitted, etc.
-
-OPTIMIZE_OUTPUT_FOR_C  = NO
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
-# sources only. Doxygen will then generate output that is more tailored for 
-# Java. For instance, namespaces will be presented as packages, qualified 
-# scopes will look different, etc.
-
-OPTIMIZE_OUTPUT_JAVA   = NO
-
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran 
-# sources only. Doxygen will then generate output that is more tailored for 
-# Fortran.
-
-OPTIMIZE_FOR_FORTRAN   = NO
-
-# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL 
-# sources. Doxygen will then generate output that is tailored for 
-# VHDL.
-
-OPTIMIZE_OUTPUT_VHDL   = NO
-
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 
-# to include (a tag file for) the STL sources as input, then you should 
-# set this tag to YES in order to let doxygen match functions declarations and 
-# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
-# func(std::string) {}). This also make the inheritance and collaboration 
-# diagrams that involve STL classes more complete and accurate.
-
-BUILTIN_STL_SUPPORT    = NO
-
-# If you use Microsoft's C++/CLI language, you should set this option to YES to
-# enable parsing support.
-
-CPP_CLI_SUPPORT        = NO
-
-# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. 
-# Doxygen will parse them like normal C++ but will assume all classes use public 
-# instead of private inheritance when no explicit protection keyword is present.
-
-SIP_SUPPORT            = NO
-
-# For Microsoft's IDL there are propget and propput attributes to indicate getter 
-# and setter methods for a property. Setting this option to YES (the default) 
-# will make doxygen to replace the get and set methods by a property in the 
-# documentation. This will only work if the methods are indeed getting or 
-# setting a simple type. If this is not the case, or you want to show the 
-# methods anyway, you should set this option to NO.
-
-IDL_PROPERTY_SUPPORT   = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
-# tag is set to YES, then doxygen will reuse the documentation of the first 
-# member in the group (if any) for the other members of the group. By default 
-# all members of a group must be documented explicitly.
-
-DISTRIBUTE_GROUP_DOC   = NO
-
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
-# the same type (for instance a group of public functions) to be put as a 
-# subgroup of that type (e.g. under the Public Functions section). Set it to 
-# NO to prevent subgrouping. Alternatively, this can be done per class using 
-# the \nosubgrouping command.
-
-SUBGROUPING            = YES
-
-# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum 
-# is documented as struct, union, or enum with the name of the typedef. So 
-# typedef struct TypeS {} TypeT, will appear in the documentation as a struct 
-# with name TypeT. When disabled the typedef will appear as a member of a file, 
-# namespace, or class. And the struct will be named TypeS. This can typically 
-# be useful for C code in case the coding convention dictates that all compound 
-# types are typedef'ed and only the typedef is referenced, never the tag name.
-
-TYPEDEF_HIDES_STRUCT   = NO
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
-# documentation are documented, even if no documentation was available. 
-# Private class members and static file members will be hidden unless 
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
-
-EXTRACT_ALL            = YES
-
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
-# will be included in the documentation.
-
-EXTRACT_PRIVATE        = NO
-
-# If the EXTRACT_STATIC tag is set to YES all static members of a file 
-# will be included in the documentation.
-
-EXTRACT_STATIC         = NO
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
-# defined locally in source files will be included in the documentation. 
-# If set to NO only classes defined in header files are included.
-
-EXTRACT_LOCAL_CLASSES  = YES
-
-# This flag is only useful for Objective-C code. When set to YES local 
-# methods, which are defined in the implementation section but not in 
-# the interface are included in the documentation. 
-# If set to NO (the default) only methods in the interface are included.
-
-EXTRACT_LOCAL_METHODS  = NO
-
-# If this flag is set to YES, the members of anonymous namespaces will be 
-# extracted and appear in the documentation as a namespace called 
-# 'anonymous_namespace{file}', where file will be replaced with the base 
-# name of the file that contains the anonymous namespace. By default 
-# anonymous namespace are hidden.
-
-EXTRACT_ANON_NSPACES   = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
-# undocumented members of documented classes, files or namespaces. 
-# If set to NO (the default) these members will be included in the 
-# various overviews, but no documentation section is generated. 
-# This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_MEMBERS     = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
-# undocumented classes that are normally visible in the class hierarchy. 
-# If set to NO (the default) these classes will be included in the various 
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_CLASSES     = NO
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
-# friend (class|struct|union) declarations. 
-# If set to NO (the default) these declarations will be included in the 
-# documentation.
-
-HIDE_FRIEND_COMPOUNDS  = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
-# documentation blocks found inside the body of a function. 
-# If set to NO (the default) these blocks will be appended to the 
-# function's detailed documentation block.
-
-HIDE_IN_BODY_DOCS      = NO
-
-# The INTERNAL_DOCS tag determines if documentation 
-# that is typed after a \internal command is included. If the tag is set 
-# to NO (the default) then the documentation will be excluded. 
-# Set it to YES to include the internal documentation.
-
-INTERNAL_DOCS          = NO
-
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
-# file names in lower-case letters. If set to YES upper-case letters are also 
-# allowed. This is useful if you have classes or files whose names only differ 
-# in case and if your file system supports case sensitive file names. Windows 
-# and Mac users are advised to set this option to NO.
-
-CASE_SENSE_NAMES       = NO
-
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
-# will show members with their full class and namespace scopes in the 
-# documentation. If set to YES the scope will be hidden.
-
-HIDE_SCOPE_NAMES       = NO
-
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
-# will put a list of the files that are included by a file in the documentation 
-# of that file.
-
-SHOW_INCLUDE_FILES     = YES
-
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
-# is inserted in the documentation for inline members.
-
-INLINE_INFO            = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
-# will sort the (detailed) documentation of file and class members 
-# alphabetically by member name. If set to NO the members will appear in 
-# declaration order.
-
-SORT_MEMBER_DOCS       = YES
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
-# brief documentation of file, namespace and class members alphabetically 
-# by member name. If set to NO (the default) the members will appear in 
-# declaration order.
-
-SORT_BRIEF_DOCS        = NO
-
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the 
-# hierarchy of group names into alphabetical order. If set to NO (the default) 
-# the group names will appear in their defined order.
-
-SORT_GROUP_NAMES       = NO
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
-# sorted by fully-qualified names, including namespaces. If set to 
-# NO (the default), the class list will be sorted only by class name, 
-# not including the namespace part. 
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the 
-# alphabetical list.
-
-SORT_BY_SCOPE_NAME     = NO
-
-# The GENERATE_TODOLIST tag can be used to enable (YES) or 
-# disable (NO) the todo list. This list is created by putting \todo 
-# commands in the documentation.
-
-GENERATE_TODOLIST      = YES
-
-# The GENERATE_TESTLIST tag can be used to enable (YES) or 
-# disable (NO) the test list. This list is created by putting \test 
-# commands in the documentation.
-
-GENERATE_TESTLIST      = YES
-
-# The GENERATE_BUGLIST tag can be used to enable (YES) or 
-# disable (NO) the bug list. This list is created by putting \bug 
-# commands in the documentation.
-
-GENERATE_BUGLIST       = YES
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
-# disable (NO) the deprecated list. This list is created by putting 
-# \deprecated commands in the documentation.
-
-GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional 
-# documentation sections, marked by \if sectionname ... \endif.
-
-ENABLED_SECTIONS       = 
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
-# the initial value of a variable or define consists of for it to appear in 
-# the documentation. If the initializer consists of more lines than specified 
-# here it will be hidden. Use a value of 0 to hide initializers completely. 
-# The appearance of the initializer of individual variables and defines in the 
-# documentation can be controlled using \showinitializer or \hideinitializer 
-# command in the documentation regardless of this setting.
-
-MAX_INITIALIZER_LINES  = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
-# at the bottom of the documentation of classes and structs. If set to YES the 
-# list will mention the files that were used to generate the documentation.
-
-SHOW_USED_FILES        = YES
-
-# If the sources in your project are distributed over multiple directories 
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
-# in the documentation. The default is NO.
-
-SHOW_DIRECTORIES       = NO
-
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
-# This will remove the Files entry from the Quick Index and from the 
-# Folder Tree View (if specified). The default is YES.
-
-SHOW_FILES             = YES
-
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the 
-# Namespaces page.  This will remove the Namespaces entry from the Quick Index
-# and from the Folder Tree View (if specified). The default is YES.
-
-SHOW_NAMESPACES        = YES
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
-# doxygen should invoke to get the current version for each file (typically from 
-# the version control system). Doxygen will invoke the program by executing (via 
-# popen()) the command <command> <input-file>, where <command> is the value of 
-# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
-# provided by doxygen. Whatever the program writes to standard output 
-# is used as the file version. See the manual for examples.
-
-FILE_VERSION_FILTER    = 
-
-#---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated 
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
-
-QUIET                  = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are 
-# generated by doxygen. Possible values are YES and NO. If left blank 
-# NO is used.
-
-WARNINGS               = YES
-
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
-# automatically be disabled.
-
-WARN_IF_UNDOCUMENTED   = YES
-
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
-# potential errors in the documentation, such as not documenting some 
-# parameters in a documented function, or documenting parameters that 
-# don't exist or using markup commands wrongly.
-
-WARN_IF_DOC_ERROR      = YES
-
-# This WARN_NO_PARAMDOC option can be abled to get warnings for 
-# functions that are documented, but have no documentation for their parameters 
-# or return value. If set to NO (the default) doxygen will only warn about 
-# wrong or incomplete parameter documentation, but not about the absence of 
-# documentation.
-
-WARN_NO_PARAMDOC       = NO
-
-# The WARN_FORMAT tag determines the format of the warning messages that 
-# doxygen can produce. The string should contain the $file, $line, and $text 
-# tags, which will be replaced by the file and line number from which the 
-# warning originated and the warning text. Optionally the format may contain 
-# $version, which will be replaced by the version of the file (if it could 
-# be obtained via FILE_VERSION_FILTER)
-
-WARN_FORMAT            = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning 
-# and error messages should be written. If left blank the output is written 
-# to stderr.
-
-WARN_LOGFILE           = 
-
-#---------------------------------------------------------------------------
-# configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag can be used to specify the files and/or directories that contain 
-# documented source files. You may enter file names like "myfile.cpp" or 
-# directories like "/usr/src/myproject". Separate the files or directories 
-# with spaces.
-
-INPUT                  = ./src ./documentation
-
-# This tag can be used to specify the character encoding of the source files 
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is 
-# also the default input encoding. Doxygen uses libiconv (or the iconv built 
-# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for 
-# the list of possible encodings.
-
-INPUT_ENCODING         = UTF-8
-
-# If the value of the INPUT tag contains directories, you can use the 
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
-# and *.h) to filter out the source-files in the directories. If left 
-# blank the following patterns are tested: 
-# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx 
-# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
-
-FILE_PATTERNS          = 
-
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
-# should be searched for input files as well. Possible values are YES and NO. 
-# If left blank NO is used.
-
-RECURSIVE              = YES
-
-# The EXCLUDE tag can be used to specify files and/or directories that should 
-# excluded from the INPUT source files. This way you can easily exclude a 
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-
-EXCLUDE                = 
-
-# The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
-# directories that are symbolic links (a Unix filesystem feature) are excluded 
-# from the input.
-
-EXCLUDE_SYMLINKS       = NO
-
-# If the value of the INPUT tag contains directories, you can use the 
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
-# certain files from those directories. Note that the wildcards are matched 
-# against the file with absolute path, so to exclude all test directories 
-# for example use the pattern */test/*
-
-EXCLUDE_PATTERNS       = 
-
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 
-# (namespaces, classes, functions, etc.) that should be excluded from the 
-# output. The symbol name can be a fully qualified name, a word, or if the 
-# wildcard * is used, a substring. Examples: ANamespace, AClass, 
-# AClass::ANamespace, ANamespace::*Test
-
-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 command).
-
-EXAMPLE_PATH           = 
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
-# and *.h) to filter out the source-files in the directories. If left 
-# blank all files are included.
-
-EXAMPLE_PATTERNS       = 
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
-# searched for input files to be used with the \include or \dontinclude 
-# commands irrespective of the value of the RECURSIVE tag. 
-# Possible values are YES and NO. If left blank NO is used.
-
-EXAMPLE_RECURSIVE      = NO
-
-# The IMAGE_PATH tag can be used to specify one or more files or 
-# directories that contain image that are included in the documentation (see 
-# the \image command).
-
-IMAGE_PATH             = ./documentation/img
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should 
-# invoke to filter for each input file. Doxygen will invoke the filter program 
-# by executing (via popen()) the command <filter> <input-file>, where <filter> 
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
-# input file. Doxygen will then use the output that the filter program writes 
-# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
-# ignored.
-
-INPUT_FILTER           = 
-
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
-# basis.  Doxygen will compare the file name with each pattern and apply the 
-# filter if there is a match.  The filters are a list of the form: 
-# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
-# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
-# is applied to all files.
-
-FILTER_PATTERNS        = 
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
-# INPUT_FILTER) will be used to filter the input files when producing source 
-# files to browse (i.e. when SOURCE_BROWSER is set to YES).
-
-FILTER_SOURCE_FILES    = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
-# be generated. Documented entities will be cross-referenced with these sources. 
-# Note: To get rid of all source code in the generated output, make sure also 
-# VERBATIM_HEADERS is set to NO.
-
-SOURCE_BROWSER         = NO
-
-# Setting the INLINE_SOURCES tag to YES will include the body 
-# of functions and classes directly in the documentation.
-
-INLINE_SOURCES         = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
-# doxygen to hide any special comment blocks from generated source code 
-# fragments. Normal C and C++ comments will always remain visible.
-
-STRIP_CODE_COMMENTS    = YES
-
-# If the REFERENCED_BY_RELATION tag is set to YES 
-# then for each documented function all documented 
-# functions referencing it will be listed.
-
-REFERENCED_BY_RELATION = NO
-
-# If the REFERENCES_RELATION tag is set to YES 
-# then for each documented function all documented entities 
-# called/used by that function will be listed.
-
-REFERENCES_RELATION    = NO
-
-# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
-# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
-# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
-# link to the source code.  Otherwise they will link to the documentstion.
-
-REFERENCES_LINK_SOURCE = YES
-
-# If the USE_HTAGS tag is set to YES then the references to source code 
-# will point to the HTML generated by the htags(1) tool instead of doxygen 
-# built-in source browser. The htags tool is part of GNU's global source 
-# tagging system (see http://www.gnu.org/software/global/global.html). You 
-# will need version 4.8.6 or higher.
-
-USE_HTAGS              = NO
-
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
-# will generate a verbatim copy of the header file for each class for 
-# which an include is specified. Set to NO to disable this.
-
-VERBATIM_HEADERS       = YES
-
-#---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
-# of all compounds will be generated. Enable this if the project 
-# contains a lot of classes, structs, unions or interfaces.
-
-ALPHABETICAL_INDEX     = NO
-
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
-# in which this list will be split (can be a number in the range [1..20])
-
-COLS_IN_ALPHA_INDEX    = 5
-
-# In case all classes in a project start with a common prefix, all 
-# classes will be put under the same header in the alphabetical index. 
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
-# should be ignored while generating the index headers.
-
-IGNORE_PREFIX          = 
-
-#---------------------------------------------------------------------------
-# configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
-# generate HTML output.
-
-GENERATE_HTML          = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
-# put in front of it. If left blank `html' will be used as the default path.
-
-HTML_OUTPUT            = html
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
-# doxygen will generate files with .html extension.
-
-HTML_FILE_EXTENSION    = .html
-
-# The HTML_HEADER tag can be used to specify a personal HTML header for 
-# each generated HTML page. If it is left blank doxygen will generate a 
-# standard header.
-
-HTML_HEADER            = 
-
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
-# each generated HTML page. If it is left blank doxygen will generate a 
-# standard footer.
-
-HTML_FOOTER            = ./documentation/html_footer.html
-
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
-# style sheet that is used by each HTML page. It can be used to 
-# fine-tune the look of the HTML output. If the tag is left blank doxygen 
-# will generate a default style sheet. Note that doxygen will try to copy 
-# the style sheet file to the HTML output directory, so don't put your own 
-# stylesheet in the HTML output directory as well, or it will be erased!
-
-HTML_STYLESHEET        = 
-
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
-# files or namespaces will be aligned in HTML using tables. If set to 
-# NO a bullet list will be used.
-
-HTML_ALIGN_MEMBERS     = YES
-
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
-# will be generated that can be used as input for tools like the 
-# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) 
-# of the generated HTML documentation.
-
-GENERATE_HTMLHELP      = NO
-
-# If the GENERATE_DOCSET tag is set to YES, additional index files 
-# will be generated that can be used as input for Apple's Xcode 3 
-# integrated development environment, introduced with OSX 10.5 (Leopard). 
-# To create a documentation set, doxygen will generate a Makefile in the 
-# HTML output directory. Running make will produce the docset in that 
-# directory and running "make install" will install the docset in 
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find 
-# it at startup.
-
-GENERATE_DOCSET        = NO
-
-# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the 
-# feed. A documentation feed provides an umbrella under which multiple 
-# documentation sets from a single provider (such as a company or product suite) 
-# can be grouped.
-
-DOCSET_FEEDNAME        = "Doxygen generated docs"
-
-# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that 
-# should uniquely identify the documentation set bundle. This should be a 
-# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen 
-# will append .docset to the name.
-
-DOCSET_BUNDLE_ID       = org.doxygen.Project
-
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 
-# documentation will contain sections that can be hidden and shown after the 
-# page has loaded. For this to work a browser that supports 
-# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox 
-# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
-
-HTML_DYNAMIC_SECTIONS  = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
-# be used to specify the file name of the resulting .chm file. You 
-# can add a path in front of the file if the result should not be 
-# written to the html output directory.
-
-CHM_FILE               = 
-
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
-# be used to specify the location (absolute path including file name) of 
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
-# the HTML help compiler on the generated index.hhp.
-
-HHC_LOCATION           = 
-
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
-# controls if a separate .chi index file is generated (YES) or that 
-# it should be included in the master .chm file (NO).
-
-GENERATE_CHI           = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
-# is used to encode HtmlHelp index (hhk), content (hhc) and project file
-# content.
-
-CHM_INDEX_ENCODING     = 
-
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
-# controls whether a binary table of contents is generated (YES) or a 
-# normal table of contents (NO) in the .chm file.
-
-BINARY_TOC             = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members 
-# to the contents of the HTML help documentation and to the tree view.
-
-TOC_EXPAND             = NO
-
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
-# top of each HTML page. The value NO (the default) enables the index and 
-# the value YES disables it.
-
-DISABLE_INDEX          = NO
-
-# This tag can be used to set the number of enum values (range [1..20]) 
-# that doxygen will group on one line in the generated HTML documentation.
-
-ENUM_VALUES_PER_LINE   = 4
-
-# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information.
-# If the tag value is set to FRAME, a side panel will be generated
-# containing a tree-like index structure (just like the one that 
-# is generated for HTML Help). For this to work a browser that supports 
-# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
-# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
-# probably better off using the HTML help feature. Other possible values 
-# for this tag are: HIERARCHIES, which will generate the Groups, Directories,
-# and Class Hiererachy pages using a tree view instead of an ordered list;
-# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which
-# disables this behavior completely. For backwards compatibility with previous
-# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE
-# respectively.
-
-GENERATE_TREEVIEW      = NONE
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
-# used to set the initial width (in pixels) of the frame in which the tree 
-# is shown.
-
-TREEVIEW_WIDTH         = 250
-
-# Use this tag to change the font size of Latex formulas included 
-# as images in the HTML documentation. The default is 10. Note that 
-# when you change the font size after a successful doxygen run you need 
-# to manually remove any form_*.png images from the HTML output directory 
-# to force them to be regenerated.
-
-FORMULA_FONTSIZE       = 10
-
-#---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
-# generate Latex output.
-
-GENERATE_LATEX         = NO
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
-# put in front of it. If left blank `latex' will be used as the default path.
-
-LATEX_OUTPUT           = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
-# invoked. If left blank `latex' will be used as the default command name.
-
-LATEX_CMD_NAME         = latex
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
-# generate index for LaTeX. If left blank `makeindex' will be used as the 
-# default command name.
-
-MAKEINDEX_CMD_NAME     = makeindex
-
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
-# LaTeX documents. This may be useful for small projects and may help to 
-# save some trees in general.
-
-COMPACT_LATEX          = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used 
-# by the printer. Possible values are: a4, a4wide, letter, legal and 
-# executive. If left blank a4wide will be used.
-
-PAPER_TYPE             = a4wide
-
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
-# packages that should be included in the LaTeX output.
-
-EXTRA_PACKAGES         = 
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
-# the generated latex document. The header should contain everything until 
-# the first chapter. If it is left blank doxygen will generate a 
-# standard header. Notice: only use this tag if you know what you are doing!
-
-LATEX_HEADER           = 
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
-# contain links (just like the HTML output) instead of page references 
-# This makes the output suitable for online browsing using a pdf viewer.
-
-PDF_HYPERLINKS         = YES
-
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
-# plain latex in the generated Makefile. Set this option to YES to get a 
-# higher quality PDF documentation.
-
-USE_PDFLATEX           = YES
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
-# command to the generated LaTeX files. This will instruct LaTeX to keep 
-# running if errors occur, instead of asking the user for help. 
-# This option is also used when generating formulas in HTML.
-
-LATEX_BATCHMODE        = NO
-
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
-# include the index chapters (such as File Index, Compound Index, etc.) 
-# in the output.
-
-LATEX_HIDE_INDICES     = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
-# The RTF output is optimized for Word 97 and may not look very pretty with 
-# other RTF readers or editors.
-
-GENERATE_RTF           = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
-# put in front of it. If left blank `rtf' will be used as the default path.
-
-RTF_OUTPUT             = rtf
-
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
-# RTF documents. This may be useful for small projects and may help to 
-# save some trees in general.
-
-COMPACT_RTF            = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
-# will contain hyperlink fields. The RTF file will 
-# contain links (just like the HTML output) instead of page references. 
-# This makes the output suitable for online browsing using WORD or other 
-# programs which support those fields. 
-# Note: wordpad (write) and others do not support links.
-
-RTF_HYPERLINKS         = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's 
-# config file, i.e. a series of assignments. You only have to provide 
-# replacements, missing definitions are set to their default value.
-
-RTF_STYLESHEET_FILE    = 
-
-# Set optional variables used in the generation of an rtf document. 
-# Syntax is similar to doxygen's config file.
-
-RTF_EXTENSIONS_FILE    = 
-
-#---------------------------------------------------------------------------
-# configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
-# generate man pages
-
-GENERATE_MAN           = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
-# put in front of it. If left blank `man' will be used as the default path.
-
-MAN_OUTPUT             = man
-
-# The MAN_EXTENSION tag determines the extension that is added to 
-# the generated man pages (default is the subroutine's section .3)
-
-MAN_EXTENSION          = .3
-
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
-# then it will generate one additional man file for each entity 
-# documented in the real man page(s). These additional files 
-# only source the real man page, but without them the man command 
-# would be unable to find the correct page. The default is NO.
-
-MAN_LINKS              = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES Doxygen will 
-# generate an XML file that captures the structure of 
-# the code including all documentation.
-
-GENERATE_XML           = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
-# put in front of it. If left blank `xml' will be used as the default path.
-
-XML_OUTPUT             = xml
-
-# The XML_SCHEMA tag can be used to specify an XML schema, 
-# which can be used by a validating XML parser to check the 
-# syntax of the XML files.
-
-XML_SCHEMA             = 
-
-# The XML_DTD tag can be used to specify an XML DTD, 
-# which can be used by a validating XML parser to check the 
-# syntax of the XML files.
-
-XML_DTD                = 
-
-# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
-# dump the program listings (including syntax highlighting 
-# and cross-referencing information) to the XML output. Note that 
-# enabling this will significantly increase the size of the XML output.
-
-XML_PROGRAMLISTING     = YES
-
-#---------------------------------------------------------------------------
-# configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
-# generate an AutoGen Definitions (see autogen.sf.net) file 
-# that captures the structure of the code including all 
-# documentation. Note that this feature is still experimental 
-# and incomplete at the moment.
-
-GENERATE_AUTOGEN_DEF   = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
-# generate a Perl module file that captures the structure of 
-# the code including all documentation. Note that this 
-# feature is still experimental and incomplete at the 
-# moment.
-
-GENERATE_PERLMOD       = NO
-
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
-# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
-# to generate PDF and DVI output from the Perl module output.
-
-PERLMOD_LATEX          = NO
-
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
-# nicely formatted so it can be parsed by a human reader.  This is useful 
-# if you want to understand what is going on.  On the other hand, if this 
-# tag is set to NO the size of the Perl module output will be much smaller 
-# and Perl will parse it just the same.
-
-PERLMOD_PRETTY         = YES
-
-# The names of the make variables in the generated doxyrules.make file 
-# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
-# This is useful so different doxyrules.make files included by the same 
-# Makefile don't overwrite each other's variables.
-
-PERLMOD_MAKEVAR_PREFIX = 
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor   
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
-# evaluate all C-preprocessor directives found in the sources and include 
-# files.
-
-ENABLE_PREPROCESSING   = YES
-
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
-# names in the source code. If set to NO (the default) only conditional 
-# compilation will be performed. Macro expansion can be done in a controlled 
-# way by setting EXPAND_ONLY_PREDEF to YES.
-
-MACRO_EXPANSION        = NO
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
-# then the macro expansion is limited to the macros specified with the 
-# PREDEFINED and EXPAND_AS_DEFINED tags.
-
-EXPAND_ONLY_PREDEF     = NO
-
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
-# in the INCLUDE_PATH (see below) will be search if a #include is found.
-
-SEARCH_INCLUDES        = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that 
-# contain include files that are not input files but should be processed by 
-# the preprocessor.
-
-INCLUDE_PATH           = 
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
-# patterns (like *.h and *.hpp) to filter out the header-files in the 
-# directories. If left blank, the patterns specified with FILE_PATTERNS will 
-# be used.
-
-INCLUDE_FILE_PATTERNS  = 
-
-# The PREDEFINED tag can be used to specify one or more macro names that 
-# are defined before the preprocessor is started (similar to the -D option of 
-# gcc). The argument of the tag is a list of macros of the form: name 
-# or name=definition (no spaces). If the definition and the = are 
-# omitted =1 is assumed. To prevent a macro definition from being 
-# undefined via #undef or recursively expanded use the := operator 
-# instead of the = operator.
-
-PREDEFINED             = 
-
-# 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 macro definition that is found in the sources will be used. 
-# Use the PREDEFINED tag if you want to use a different macro definition.
-
-EXPAND_AS_DEFINED      = 
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
-# doxygen's preprocessor will remove all function-like macros that are alone 
-# on a line, have an all uppercase name, and do not end with a semicolon. Such 
-# function macros are typically used for boiler-plate code, and will confuse 
-# the parser if not removed.
-
-SKIP_FUNCTION_MACROS   = YES
-
-#---------------------------------------------------------------------------
-# Configuration::additions related to external references   
-#---------------------------------------------------------------------------
-
-# The TAGFILES option can be used to specify one or more tagfiles. 
-# Optionally an initial location of the external documentation 
-# can be added for each tagfile. The format of a tag file without 
-# this location is as follows: 
-#   TAGFILES = file1 file2 ... 
-# Adding location for the tag files is done as follows: 
-#   TAGFILES = file1=loc1 "file2 = loc2" ... 
-# where "loc1" and "loc2" can be relative or absolute paths or 
-# URLs. If a location is present for each tag, the installdox tool 
-# does not have to be run to correct the links.
-# Note that each tag file must have a unique name
-# (where the name does NOT include the path)
-# If a tag file is not located in the directory in which doxygen 
-# is run, you must also specify the path to the tagfile here.
-
-TAGFILES               = 
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
-# a tag file that is based on the input files it reads.
-
-GENERATE_TAGFILE       = 
-
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
-# in the class index. If set to NO only the inherited external classes 
-# will be listed.
-
-ALLEXTERNALS           = NO
-
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
-# in the modules index. If set to NO, only the current project's groups will 
-# be listed.
-
-EXTERNAL_GROUPS        = YES
-
-# The PERL_PATH should be the absolute path and name of the perl script 
-# interpreter (i.e. the result of `which perl').
-
-PERL_PATH              = /usr/bin/perl
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool   
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
-# or super classes. Setting the tag to NO turns the diagrams off. Note that 
-# this option is superseded by the HAVE_DOT option below. This is only a 
-# fallback. It is recommended to install and use dot, since it yields more 
-# powerful graphs.
-
-CLASS_DIAGRAMS         = YES
-
-# You can define message sequence charts within doxygen comments using the \msc 
-# command. Doxygen will then run the mscgen tool (see 
-# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the 
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where 
-# the mscgen tool resides. If left empty the tool is assumed to be found in the 
-# default search path.
-
-MSCGEN_PATH            = 
-
-# If set to YES, the inheritance and collaboration graphs will hide 
-# inheritance and usage relations if the target is undocumented 
-# or is not a class.
-
-HIDE_UNDOC_RELATIONS   = YES
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
-# available from the path. This tool is part of Graphviz, a graph visualization 
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
-# have no effect if this option is set to NO (the default)
-
-HAVE_DOT               = YES
-
-# By default doxygen will write a font called FreeSans.ttf to the output 
-# directory and reference it in all dot files that doxygen generates. This 
-# font does not include all possible unicode characters however, so when you need 
-# these (or just want a differently looking font) you can specify the font name 
-# using DOT_FONTNAME. You need need to make sure dot is able to find the font, 
-# which can be done by putting it in a standard location or by setting the 
-# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory 
-# containing the font.
-
-DOT_FONTNAME           = Sans
-
-# By default doxygen will tell dot to use the output directory to look for the 
-# FreeSans.ttf font (which doxygen will put there itself). If you specify a 
-# different font using DOT_FONTNAME you can set the path where dot 
-# can find it using this tag.
-
-DOT_FONTPATH           = 
-
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
-# will generate a graph for each documented class showing the direct and 
-# indirect inheritance relations. Setting this tag to YES will force the 
-# the CLASS_DIAGRAMS tag to NO.
-
-CLASS_GRAPH            = YES
-
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
-# will generate a graph for each documented class showing the direct and 
-# indirect implementation dependencies (inheritance, containment, and 
-# class references variables) of the class with other documented classes.
-
-COLLABORATION_GRAPH    = YES
-
-# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
-# will generate a graph for groups, showing the direct groups dependencies
-
-GROUP_GRAPHS           = YES
-
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
-# collaboration diagrams in a style similar to the OMG's Unified Modeling 
-# Language.
-
-UML_LOOK               = NO
-
-# If set to YES, the inheritance and collaboration graphs will show the 
-# relations between templates and their instances.
-
-TEMPLATE_RELATIONS     = NO
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
-# tags are set to YES then doxygen will generate a graph for each documented 
-# file showing the direct and indirect include dependencies of the file with 
-# other documented files.
-
-INCLUDE_GRAPH          = YES
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
-# documented header file showing the documented files that directly or 
-# indirectly include this file.
-
-INCLUDED_BY_GRAPH      = YES
-
-# If the CALL_GRAPH and HAVE_DOT options are set to YES then 
-# doxygen will generate a call dependency graph for every global function 
-# or class method. Note that enabling this option will significantly increase 
-# the time of a run. So in most cases it will be better to enable call graphs 
-# for selected functions only using the \callgraph command.
-
-CALL_GRAPH             = NO
-
-# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then 
-# doxygen will generate a caller dependency graph for every global function 
-# or class method. Note that enabling this option will significantly increase 
-# the time of a run. So in most cases it will be better to enable caller 
-# graphs for selected functions only using the \callergraph command.
-
-CALLER_GRAPH           = NO
-
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
-# will graphical hierarchy of all classes instead of a textual one.
-
-GRAPHICAL_HIERARCHY    = YES
-
-# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
-# then doxygen will show the dependencies a directory has on other directories 
-# in a graphical way. The dependency relations are determined by the #include
-# relations between the files in the directories.
-
-DIRECTORY_GRAPH        = YES
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
-# generated by dot. Possible values are png, jpg, or gif
-# If left blank png will be used.
-
-DOT_IMAGE_FORMAT       = png
-
-# The tag DOT_PATH can be used to specify the path where the dot tool can be 
-# found. If left blank, it is assumed the dot tool can be found in the path.
-
-DOT_PATH               = 
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that 
-# contain dot files that are included in the documentation (see the 
-# \dotfile command).
-
-DOTFILE_DIRS           = 
-
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 
-# nodes that will be shown in the graph. If the number of nodes in a graph 
-# becomes larger than this value, doxygen will truncate the graph, which is 
-# visualized by representing a node as a red box. Note that doxygen if the 
-# number of direct children of the root node in a graph is already larger than 
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note 
-# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
-
-DOT_GRAPH_MAX_NODES    = 50
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
-# graphs generated by dot. A depth value of 3 means that only nodes reachable 
-# from the root by following a path via at most 3 edges will be shown. Nodes 
-# that lay further from the root node will be omitted. Note that setting this 
-# option to 1 or 2 may greatly reduce the computation time needed for large 
-# code bases. Also note that the size of a graph can be further restricted by 
-# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
-
-MAX_DOT_GRAPH_DEPTH    = 0
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
-# background. This is enabled by default, which results in a transparent 
-# background. Warning: Depending on the platform used, enabling this option 
-# may lead to badly anti-aliased labels on the edges of a graph (i.e. they 
-# become hard to read).
-
-DOT_TRANSPARENT        = YES
-
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
-# files in one run (i.e. multiple -o and -T options on the command line). This 
-# makes dot run faster, but since only newer versions of dot (>1.8.10) 
-# support this, this feature is disabled by default.
-
-DOT_MULTI_TARGETS      = NO
-
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
-# generate a legend page explaining the meaning of the various boxes and 
-# arrows in the dot generated graphs.
-
-GENERATE_LEGEND        = YES
-
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
-# remove the intermediate dot files that are used to generate 
-# the various graphs.
-
-DOT_CLEANUP            = YES
-
-#---------------------------------------------------------------------------
-# Configuration::additions related to the search engine   
-#---------------------------------------------------------------------------
-
-# The SEARCHENGINE tag specifies whether or not a search engine should be 
-# used. If set to NO the values of all tags below this one will be ignored.
-
-SEARCHENGINE           = NO
diff --git a/linux/flatpak/org.jacktrip.JackTrip.Devel.yml b/linux/flatpak/org.jacktrip.JackTrip.Devel.yml
new file mode 100644 (file)
index 0000000..6e1cf9b
--- /dev/null
@@ -0,0 +1,29 @@
+app-id: org.jacktrip.JackTrip.Devel
+runtime: org.kde.Platform
+runtime-version: '5.15'
+sdk: org.kde.Sdk
+command: jacktrip
+finish-args:
+  # X11 + XShm access
+  - --share=ipc
+  - --socket=x11
+  - --socket=fallback-x11
+  - --device=dri
+  # Wayland access
+  - --socket=wayland
+  # Needs network access
+  - --share=network
+  # Pipewire/Jack
+  - --filesystem=xdg-run/pipewire-0
+  - --system-talk-name=org.freedesktop.RealtimeKit1
+  - --socket=system-bus
+modules:
+  - shared-modules/linux-audio/jack2.json
+  - name: jacktrip
+    buildsystem: meson
+    config-opts:
+      - -Dprofile=development
+    sources:
+      - type: git
+        url: https://github.com/jacktrip/jacktrip.git
+        branch: dev
diff --git a/linux/flatpak/org.jacktrip.JackTrip.Devel.yml.j2 b/linux/flatpak/org.jacktrip.JackTrip.Devel.yml.j2
new file mode 100644 (file)
index 0000000..2b683b5
--- /dev/null
@@ -0,0 +1,29 @@
+app-id: org.jacktrip.JackTrip.Devel
+runtime: org.kde.Platform
+runtime-version: '5.15'
+sdk: org.kde.Sdk
+command: jacktrip
+finish-args:
+  # X11 + XShm access
+  - --share=ipc
+  - --socket=x11
+  - --socket=fallback-x11
+  - --device=dri
+  # Wayland access
+  - --socket=wayland
+  # Needs network access
+  - --share=network
+  # Pipewire/Jack
+  - --filesystem=xdg-run/pipewire-0
+  - --system-talk-name=org.freedesktop.RealtimeKit1
+  - --socket=system-bus
+modules:
+  - shared-modules/linux-audio/jack2.json
+  - name: jacktrip
+    buildsystem: meson
+    config-opts:
+      - -Dprofile=development
+    sources:
+      - type: git
+        url: {{ env['REPO'] }}
+        branch: {{ env['REF'] }}
diff --git a/linux/flatpak/org.jacktrip.JackTrip.yml b/linux/flatpak/org.jacktrip.JackTrip.yml
new file mode 100644 (file)
index 0000000..2d8a881
--- /dev/null
@@ -0,0 +1,27 @@
+app-id: org.jacktrip.JackTrip
+runtime: org.kde.Platform
+runtime-version: '5.15'
+sdk: org.kde.Sdk
+command: jacktrip
+finish-args:
+  # X11 + XShm access
+  - --share=ipc
+  - --socket=x11
+  - --socket=fallback-x11
+  - --device=dri
+  # Wayland access
+  - --socket=wayland
+  # Needs network access
+  - --share=network
+  # Pipewire/Jack
+  - --filesystem=xdg-run/pipewire-0
+  - --system-talk-name=org.freedesktop.RealtimeKit1
+  - --socket=system-bus
+modules:
+  - shared-modules/linux-audio/jack2.json
+  - name: jacktrip
+    buildsystem: meson
+    sources:
+      - type: git
+        url: https://github.com/jacktrip/jacktrip.git
+        branch: main
diff --git a/linux/icons/jacktrip-symbolic.svg b/linux/icons/jacktrip-symbolic.svg
new file mode 100644 (file)
index 0000000..cbb1f7b
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>Artboard Copy 2</title>
+    <g id="Artboard-Copy-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <path d="M6.64639356,12.2679165 C6.65038057,12.2752708 6.6540828,12.2825243 6.65750023,12.2899793 L7.05325841,13.017447 C7.36339081,13.5859417 7.86480474,13.9691694 8.42289117,14.1277394 C8.98135732,14.2866117 9.59602131,14.2210278 10.1314198,13.8929067 C10.1378749,13.8889777 10.1442351,13.8853509 10.1506903,13.8818249 C10.6759314,13.5532001 11.0302057,13.0264132 11.1781997,12.4400869 C11.3279973,11.8467086 11.2661987,11.1938917 10.9568257,10.6251955 L8.43589642,5.99120302 C8.05883921,5.9779049 7.75687069,5.64938084 7.75687069,5.245803 C7.75687069,4.83396419 8.07155967,4.5 8.45972355,4.5 C8.84788742,4.5 9.16248147,4.83396419 9.16248147,5.245803 C9.16248147,5.37354556 9.13219918,5.49363163 9.07903905,5.59870694 L11.6000633,10.2329009 C12.0125289,10.9909946 12.0954967,11.8580926 11.8970955,12.6439914 C11.7016371,13.4181033 11.2325939,14.1155495 10.5356266,14.554992 C10.5174952,14.5688945 10.4980348,14.5810845 10.4775302,14.591461 C9.7693613,15.0154898 8.9628462,15.0988045 8.23075527,14.8906688 C7.49771506,14.6823315 6.83786496,14.1814356 6.42473481,13.4380505 C6.41267885,13.4194129 6.40214176,13.3995665 6.39312352,13.3787126 L6.01492717,12.6833821 C6.01094016,12.6768337 6.00685822,12.6701847 6.003156,12.6633341 C5.95948875,12.5831424 5.88629864,12.528338 5.80428016,12.5050663 C5.72207181,12.4817946 5.6330286,12.4901563 5.55803484,12.5359945 C5.38042305,12.6450996 5.15297364,12.5809261 5.05007082,12.3924353 C4.94726293,12.2039445 5.00782751,11.9625634 5.18543929,11.8533576 C5.43927891,11.6977092 5.73203934,11.6670832 5.99641605,11.742137 C6.26117248,11.8173922 6.50010828,11.9990325 6.64639356,12.2679165 Z M9.30469654,1.73361307 C9.30469654,2.13876486 8.96448358,2.46712705 8.54470965,2.46712705 C8.4146403,2.46712705 8.2922704,2.43551947 8.18509408,2.3800328 L6.66460699,3.22729446 C6.65793413,3.23155504 6.65115862,3.23571654 6.64417779,3.23958079 C6.24401178,3.4626174 5.97442843,3.82397435 5.86283775,4.22625272 C5.75104176,4.62882834 5.79693047,5.07173088 6.02760595,5.45736325 L6.04208091,5.4814405 C6.04639261,5.4885745 6.05039632,5.49580759 6.05419471,5.50313975 L9.20275585,10.7666451 C9.21938666,10.789137 9.233143,10.8130161 9.24423021,10.837886 C9.3830256,11.0932238 9.40786915,11.3818536 9.33518636,11.6435327 C9.26137431,11.9097696 9.08685348,12.1509385 8.82907595,12.3047158 C8.67190454,12.4111313 8.45344552,12.3967642 8.31300758,12.2612182 C8.15573351,12.1094225 8.15573351,11.8631013 8.31300758,11.7113057 C8.33795379,11.6885165 8.36546649,11.6678081 8.3964696,11.6504685 C8.47828907,11.6048902 8.53403308,11.528596 8.55774738,11.4430871 C8.581667,11.3569836 8.57324894,11.2638453 8.52674427,11.1853713 L5.35929382,5.89006021 C5.35487947,5.88361979 5.35056778,5.87708029 5.34656407,5.87034262 L5.33198645,5.84626537 C4.98961764,5.27376181 4.92073324,4.61911817 5.08539878,4.02570803 C5.25016697,3.43209973 5.64879309,2.89833776 6.24123998,2.56819206 C6.24863145,2.56403056 6.25612558,2.5602654 6.26372237,2.55659931 L7.78513339,1.70884223 C7.79868442,1.31518411 8.1335591,1 8.54470965,1 C8.96448358,1 9.30469654,1.32846128 9.30469654,1.73361307 Z" id="Fill-3" stroke="#FFFFFF" stroke-width="0.5" fill="#FFFFFF" fill-rule="nonzero"></path>
+    </g>
+</svg>
\ No newline at end of file
diff --git a/linux/icons/jacktrip.svg b/linux/icons/jacktrip.svg
new file mode 100644 (file)
index 0000000..2d1d67f
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="1366px" height="1366px" viewBox="0 0 1366 1366" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>jacktrip</title>
+    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="jacktrip">
+            <path d="M754.755517,107 C789.35747,107 817.401215,135.042996 817.401215,169.633588 C817.401215,204.22418 789.35747,232.258717 754.755517,232.258717 C744.033904,232.258717 733.946957,229.56016 725.112416,224.822882 L599.778709,297.159431 C599.228666,297.523187 598.67016,297.878483 598.09473,298.2084 C565.109058,317.250568 542.88731,348.102093 533.688894,382.447362 C524.473554,416.818009 528.256159,454.631642 547.270732,487.555727 L548.463903,489.611367 C548.819315,490.220446 549.149341,490.837984 549.462443,491.463982 L808.998246,940.845596 C810.369123,942.765886 811.503059,944.804608 812.416977,946.927923 C823.857877,968.727864 825.90573,993.370171 819.91449,1015.71151 C813.830165,1038.44199 799.444418,1059.03223 778.195823,1072.16126 C765.240188,1081.24669 747.232618,1080.02007 735.656322,1068.44757 C722.692225,1055.48773 722.692225,1034.4576 735.656322,1021.49776 L735.664784,1021.49776 L735.715558,1021.54006 C737.712638,1019.55209 739.980509,1017.78407 742.536094,1016.30367 C749.280471,1012.41234 753.875448,1005.89858 755.830217,998.598096 C757.801911,991.246855 757.10801,983.294995 753.274631,976.59513 L753.23232,976.518995 L492.181782,524.498039 C491.817908,523.948176 491.462495,523.389854 491.132469,522.814613 L489.930836,520.758973 C461.709385,471.880411 456.031246,415.988985 469.604622,365.325484 C483.186459,314.645065 516.045198,269.074138 564.880579,240.887331 C565.489858,240.532035 566.107599,240.210577 566.733802,239.897579 L692.143668,167.518732 C693.260679,133.909433 720.864389,107 754.755517,107 M517.763026,1028.58676 C518.118438,1029.2043 518.448464,1029.81338 518.753104,1030.43937 L554.032033,1091.52489 L554.082806,1091.49105 C581.678054,1139.26143 626.375417,1171.44108 676.124716,1184.75622 C725.907863,1198.09673 780.700635,1192.58965 828.427467,1165.0373 C829.002897,1164.70738 829.569865,1164.40284 830.145295,1164.10676 C876.966671,1136.51211 908.547617,1092.27778 921.740193,1043.04392 C935.093551,993.217901 929.584656,938.400822 902.006333,890.647364 L677.284038,501.530698 C643.672162,500.414054 616.753891,472.827867 616.753891,438.939407 C616.753891,404.357275 644.806098,376.314278 679.408051,376.314278 C714.010004,376.314278 742.053749,404.357275 742.053749,438.939407 C742.053749,449.665959 739.354306,459.749594 734.615471,468.572775 L959.346229,857.70636 C996.114506,921.363539 1003.51047,994.173816 985.824466,1060.1658 C968.400787,1125.16802 926.589036,1183.73263 864.459533,1220.6411 C862.843252,1221.80004 861.1085,1222.82363 859.280664,1223.69496 C796.15262,1259.30068 724.257733,1266.29662 658.997214,1248.81945 C593.652073,1231.32536 534.831292,1189.27355 498.003779,1126.84299 C496.929079,1125.278 495.989774,1123.61149 495.185865,1121.86039 L461.472443,1063.47343 C461.117031,1062.92357 460.753156,1062.36525 460.42313,1061.79001 C456.530516,1055.0563 450.006157,1050.45438 442.694812,1048.50025 C435.366543,1046.54612 427.428996,1047.24825 420.743854,1051.10575 C404.91107,1060.26731 384.635629,1054.8702 375.4626,1039.04261 C366.298033,1023.21502 371.696919,1002.94624 387.529703,993.776223 C410.157637,980.706411 436.255075,978.143205 459.822314,984.437017 C483.423401,990.756208 504.722769,1006.00855 517.763026,1028.58676" id="Fill-1" fill="#F21B1B"></path>
+            <rect id="Rectangle" x="0" y="0" width="1365.33" height="1365.33"></rect>
+        </g>
+    </g>
+</svg>
\ No newline at end of file
diff --git a/linux/icons/jacktrip_48x48.png b/linux/icons/jacktrip_48x48.png
new file mode 100644 (file)
index 0000000..f8036d9
Binary files /dev/null and b/linux/icons/jacktrip_48x48.png differ
diff --git a/linux/meson.build b/linux/meson.build
new file mode 100644 (file)
index 0000000..f0c9208
--- /dev/null
@@ -0,0 +1,25 @@
+if host_machine.system() == 'linux'
+       install_data('icons/jacktrip.svg', rename: '@0@.svg'.format(application_id), install_dir: get_option('datadir') / 'icons' / 'hicolor' / 'scalable' / 'apps')
+       install_data('icons/jacktrip_48x48.png', rename: '@0@.png'.format(application_id), install_dir: get_option('datadir') / 'icons' / 'hicolor' / '48x48' / 'apps')
+       install_data('icons/jacktrip-symbolic.svg', rename: '@0@-symbolic.svg'.format(application_id), install_dir: get_option('datadir') / 'icons' / 'hicolor' / 'symbolic' / 'apps')
+       desktop_conf = configuration_data()
+       desktop_conf.set('icon', application_id)
+       desktop_conf.set('wmclass', application_id.to_lower())
+       desktop_conf.set('name_suffix', name_suffix)
+       configure_file(
+           input: files('org.jacktrip.JackTrip.desktop.in'),
+           output: '@0@.desktop'.format(application_id),
+           configuration: desktop_conf,
+           install_dir: get_option('datadir') / 'applications'
+       )
+
+       appdata_conf = configuration_data()
+       appdata_conf.set('appid', application_id)
+       configure_file(
+           input: files('org.jacktrip.JackTrip.metainfo.xml.in'),
+           output: '@0@.metainfo.xml'.format(application_id),
+           configuration: appdata_conf,
+           install_dir: get_option('datadir') / 'metainfo'
+       )
+
+endif
diff --git a/linux/org.jacktrip.JackTrip.desktop.in b/linux/org.jacktrip.JackTrip.desktop.in
new file mode 100644 (file)
index 0000000..2b77704
--- /dev/null
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Type=Application
+Name=JackTrip@name_suffix@
+Comment=Network Music Performance over the Internet
+Comment[fr]=Performance de musique en réseau sur internet
+Exec=jacktrip
+Icon=@icon@
+Terminal=false
+StartupWMClass=@wmclass@
diff --git a/linux/org.jacktrip.JackTrip.metainfo.xml.in b/linux/org.jacktrip.JackTrip.metainfo.xml.in
new file mode 100644 (file)
index 0000000..6509402
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright 2021 Nils Tonnätt <nils.tonnaett@posteo.de> -->
+<component type="desktop-application">
+  <id>@appid@</id>
+  <metadata_license>MIT</metadata_license>
+  <project_license>GPL-3.0+</project_license>
+  <name>JackTrip</name>
+  <summary>Connect and play with other musicians</summary>
+
+  <description>
+    <p>
+      JackTrip is a cross-platform multi-machine audio system
+      used for network music performance over the Internet.
+      It supports any number of channels (as many as the computer/network can handle)
+      of bidirectional, high quality, uncompressed audio signal streaming.
+    </p>
+    <p>
+      You can use it between any combination of machines e.g., one end using
+      Linux can connect to another using Mac OSX.
+    </p>
+  </description>
+
+  <launchable type="desktop-id">@appid@.desktop</launchable>
+
+  <url type="homepage">https://jacktrip.github.io/jacktrip/</url>
+  <project_group>JackTrip</project_group>
+
+  <provides>
+    <binary>jacktrip</binary>
+  </provides>
+
+  <content_rating type="oars-1.1">
+    <content_attribute id="social-audio">intense</content_attribute>
+  </content_rating>
+
+</component>
diff --git a/macos/JackTrip.app_template/Contents/Info.plist b/macos/JackTrip.app_template/Contents/Info.plist
new file mode 100644 (file)
index 0000000..58cd87e
--- /dev/null
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>BuildMachineOSBuild</key>
+       <string>19E287</string>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>en</string>
+       <key>CFBundleExecutable</key>
+       <string>jacktrip</string>
+       <key>CFBundleIconFile</key>
+       <string>jacktrip</string>
+       <key>CFBundleIdentifier</key>
+       <string>%BUNDLEID%</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>%BUNDLENAME%</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string>%VERSION%</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleSupportedPlatforms</key>
+       <array>
+               <string>MacOSX</string>
+       </array>
+       <key>CFBundleVersion</key>
+       <string>16</string>
+       <key>DTCompiler</key>
+       <string>com.apple.compilers.llvm.clang.1_0</string>
+       <key>DTPlatformBuild</key>
+       <string>11E503a</string>
+       <key>DTPlatformVersion</key>
+       <string>GM</string>
+       <key>DTSDKBuild</key>
+       <string>19E258</string>
+       <key>DTSDKName</key>
+       <string>macosx10.15</string>
+       <key>DTXcode</key>
+       <string>1141</string>
+       <key>DTXcodeBuild</key>
+       <string>11E503a</string>
+       <key>LSMinimumSystemVersion</key>
+       <string>10.13</string>
+       <key>NSHighResolutionCapable</key>
+       <true/>
+       <key>NSHumanReadableCopyright</key>
+       <string>Copyright © 2020 Juan-Pablo Caceres, Chris Chafe, Aaron Wyatt, et al. All rights reserved.</string>
+       <key>NSMicrophoneUsageDescription</key>
+       <string>This app requires microphone access to allow the jack server to capture audio.</string>
+</dict>
+</plist>
diff --git a/macos/JackTrip.app_template/Contents/PkgInfo b/macos/JackTrip.app_template/Contents/PkgInfo
new file mode 100644 (file)
index 0000000..bd04210
--- /dev/null
@@ -0,0 +1 @@
+APPL????
\ No newline at end of file
diff --git a/macos/JackTrip.app_template/Contents/Resources/jacktrip.icns b/macos/JackTrip.app_template/Contents/Resources/jacktrip.icns
new file mode 100644 (file)
index 0000000..532faa2
Binary files /dev/null and b/macos/JackTrip.app_template/Contents/Resources/jacktrip.icns differ
diff --git a/macos/assemble_app.sh b/macos/assemble_app.sh
new file mode 100755 (executable)
index 0000000..1d89e3f
--- /dev/null
@@ -0,0 +1,144 @@
+#!/bin/sh
+
+APPNAME="JackTrip"
+BUNDLE_ID="org.jacktrip.jacktrip"
+BUILD_INSTALLER=false
+
+#If you're lazy like I am, you can pre-populate these variables to save you stuffing about with command line options.
+#CERTIFICATE=""
+#USERNAME=""
+#PASSWORD=""
+#ASC_PROVIDER=""
+BINARY="../builddir/jacktrip"
+
+OPTIND=1
+
+while getopts ":ic:u:p:a:b:" opt; do
+    case $opt in
+      i)
+        BUILD_INSTALLER=true
+        ;;
+      c)
+        CERTIFICATE=$OPTARG
+        ;;
+      u)
+        USERNAME=$OPTARG
+        ;;
+      p)
+        PASSWORD=$OPTARG
+        ;;
+      a)
+        ASC_PROVIDER=$OPTARG
+        ;;
+      b)
+        BINARY=$OPTARG
+        ;;
+      \?)
+        echo "Invalid option -$OPTARG ignored."
+        ;;
+      :)
+        echo "Option $OPTARG requires an argument."
+        exit 1
+        ;;
+     esac
+done
+
+shift $((OPTIND - 1))
+[ "${1:-}" = "--" ] && shift
+
+[ "$#" -gt 0 ] && APPNAME="$1"
+[ "$#" -gt 1 ] && BUNDLE_ID="$2"
+
+VERSION="$($BINARY -v | awk '/VERSION/{print $NF}')"
+[ -z "$VERSION" ] && { echo "Unable to determine binary version. Quitting."; exit 1; }
+
+# Make sure that jacktrip has been built with GUI support.
+$BINARY --test-gui || { echo "You need to build jacktrip with GUI support to build an app bundle."; exit 1; }
+
+echo "Building bundle $APPNAME (id: $BUNDLE_ID)"
+echo "for binary version $VERSION"
+
+rm -rf "$APPNAME.app"
+[ ! -d "JackTrip.app_template/Contents/MacOS" ] && mkdir JackTrip.app_template/Contents/MacOS
+cp -a JackTrip.app_template "$APPNAME.app"
+cp -f $BINARY "$APPNAME.app/Contents/MacOS/"
+# copy licenses
+cp -f ../LICENSE.md "$APPNAME.app/Contents/Resources/"
+cp -Rf ../LICENSES "$APPNAME.app/Contents/Resources/"
+sed -i '' "s/%VERSION%/$VERSION/" "$APPNAME.app/Contents/Info.plist"
+sed -i '' "s/%BUNDLENAME%/$APPNAME/" "$APPNAME.app/Contents/Info.plist"
+sed -i '' "s/%BUNDLEID%/$BUNDLE_ID/" "$APPNAME.app/Contents/Info.plist"
+
+DYNAMIC_QT=$(otool -L ../builddir/jacktrip | grep QtCore)
+if [ ! -z "$DYNAMIC_QT" ]; then
+    DEPLOY_CMD="$(which macdeployqt)"
+    if [ -z "$DEPLOY_CMD" ]; then
+        # Attempt to find macdeployqt. Try macports location first, then brew.
+        if [ -x "/opt/local/libexec/qt5/bin/macdeployqt" ]; then
+            DEPLOY_CMD="/opt/local/libexec/qt5/bin/macdeployqt"
+        elif [ ! -z $(which brew) ] && [ ! -z $(brew --prefix qt5) ]; then
+            DEPLOY_CMD="$(brew --prefix qt5)/bin/macdeployqt"
+        else
+            echo "The Qt bin folder needs to be in your PATH for this script to work."
+            exit 1
+        fi
+    fi
+    if [ ! -z "$CERTIFICATE" ]; then
+        $DEPLOY_CMD "$APPNAME.app" -codesign="$CERTIFICATE"
+    else
+        $DEPLOY_CMD "$APPNAME.app"
+    fi
+fi
+
+[ "$BUILD_INSTALLER" = true ] || exit 0
+
+# If you have Packages installed, you can build an installer for the newly created app bundle.
+[ -z $(which packagesbuild) ] && { echo "You need to have Packages installed to build a package."; exit 1; }
+
+# Needed for notarization.
+[ ! -z "$CERTIFICATE" ] && codesign -f -s "$CERTIFICATE" --entitlements entitlements.plist --options "runtime" "$APPNAME.app"
+
+# prepare license
+LICENSE_PATH="package/license.txt"
+cat ../LICENSE.md > "$LICENSE_PATH"
+printf "\n\n" >> "$LICENSE_PATH"
+cat ../LICENSES/MIT.txt >> "$LICENSE_PATH"
+printf "\n\n" >> "$LICENSE_PATH"
+cat ../LICENSES/GPL-3.0.txt >> "$LICENSE_PATH"
+printf "\n\n" >> "$LICENSE_PATH"
+cat ../LICENSES/LGPL-3.0-only.txt >> "$LICENSE_PATH"
+
+sed -i '' "s/# //" "$LICENSE_PATH" # remove markdown header
+perl -ane 'chop;print "\n\n" if(/^\s*$/); map{print "$_ ";}@F;' "$LICENSE_PATH" > tmp && mv tmp "$LICENSE_PATH" # unwrap lines
+
+
+# prepare readme
+README_PATH="package/readme.txt"
+cp ../README.md "$README_PATH"
+sed -i '' "s/# //" "$README_PATH" # remove markdown header
+perl -ane 'chop;print "\n\n" if(/^\s*$/); map{print "$_ ";}@F;' "$README_PATH" > tmp && mv tmp "$README_PATH" # unwrap lines
+
+cp package/JackTrip.pkgproj_template package/JackTrip.pkgproj
+sed -i '' "s/%VERSION%/$VERSION/" package/JackTrip.pkgproj
+sed -i '' "s/%BUNDLENAME%/$APPNAME/" package/JackTrip.pkgproj
+sed -i '' "s/%BUNDLEID%/$BUNDLE_ID/" package/JackTrip.pkgproj
+
+packagesbuild package/JackTrip.pkgproj
+
+# Offer to submit a notarization request to apple if we have the required credentials.
+if [ -z "$CERTIFICATE" ] || [ -z "$USERNAME" ] || [ -z "$PASSWORD" ]; then
+    echo "Not sending notarization request: incomplete credentials."
+    exit 0
+fi
+
+ASC=""
+if [ ! -z "$ASC_PROVIDER" ]; then
+    ASC=" --asc-provider \"$ASC_PROVIDER\""
+fi
+
+read -n1 -rsp "Press any key to submit a notarization request to apple..."
+echo
+xcrun altool --notarize-app --primary-bundle-id "$BUNDLE_ID" --username "$USERNAME" --password "$PASSWORD"$ASC --file "package/build/$APPNAME.pkg"
+read -n1 -rsp "Press any key to staple the notarization once it's been approved..."
+echo
+xcrun stapler staple "package/build/$APPNAME.pkg"
diff --git a/macos/entitlements.plist b/macos/entitlements.plist
new file mode 100644 (file)
index 0000000..8f4b16d
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>com.apple.security.cs.allow-dyld-environment-variables</key>
+       <true/>
+       <key>com.apple.security.cs.disable-library-validation</key>
+       <true/>
+       <key>com.apple.security.device.audio-input</key>
+       <true/>
+</dict>
+</plist>
diff --git a/macos/jacktrip.iconset/icon_128x128.png b/macos/jacktrip.iconset/icon_128x128.png
new file mode 100644 (file)
index 0000000..d80ff94
Binary files /dev/null and b/macos/jacktrip.iconset/icon_128x128.png differ
diff --git a/macos/jacktrip.iconset/icon_128x128@2x.png b/macos/jacktrip.iconset/icon_128x128@2x.png
new file mode 100644 (file)
index 0000000..63a9bd7
Binary files /dev/null and b/macos/jacktrip.iconset/icon_128x128@2x.png differ
diff --git a/macos/jacktrip.iconset/icon_16x16.png b/macos/jacktrip.iconset/icon_16x16.png
new file mode 100644 (file)
index 0000000..df9ffcd
Binary files /dev/null and b/macos/jacktrip.iconset/icon_16x16.png differ
diff --git a/macos/jacktrip.iconset/icon_16x16@2x.png b/macos/jacktrip.iconset/icon_16x16@2x.png
new file mode 100644 (file)
index 0000000..78ed69f
Binary files /dev/null and b/macos/jacktrip.iconset/icon_16x16@2x.png differ
diff --git a/macos/jacktrip.iconset/icon_256x256.png b/macos/jacktrip.iconset/icon_256x256.png
new file mode 100644 (file)
index 0000000..bc44f30
Binary files /dev/null and b/macos/jacktrip.iconset/icon_256x256.png differ
diff --git a/macos/jacktrip.iconset/icon_256x256@2x.png b/macos/jacktrip.iconset/icon_256x256@2x.png
new file mode 100644 (file)
index 0000000..d86ef17
Binary files /dev/null and b/macos/jacktrip.iconset/icon_256x256@2x.png differ
diff --git a/macos/jacktrip.iconset/icon_32x32.png b/macos/jacktrip.iconset/icon_32x32.png
new file mode 100644 (file)
index 0000000..9c8f5a7
Binary files /dev/null and b/macos/jacktrip.iconset/icon_32x32.png differ
diff --git a/macos/jacktrip.iconset/icon_32x32@2x.png b/macos/jacktrip.iconset/icon_32x32@2x.png
new file mode 100644 (file)
index 0000000..cfd969a
Binary files /dev/null and b/macos/jacktrip.iconset/icon_32x32@2x.png differ
diff --git a/macos/jacktrip.iconset/icon_512x512.png b/macos/jacktrip.iconset/icon_512x512.png
new file mode 100644 (file)
index 0000000..c0e615e
Binary files /dev/null and b/macos/jacktrip.iconset/icon_512x512.png differ
diff --git a/macos/jacktrip.iconset/icon_512x512@2x.png b/macos/jacktrip.iconset/icon_512x512@2x.png
new file mode 100644 (file)
index 0000000..dc87eb2
Binary files /dev/null and b/macos/jacktrip.iconset/icon_512x512@2x.png differ
diff --git a/macos/package/JackTrip.pkgproj_template b/macos/package/JackTrip.pkgproj_template
new file mode 100644 (file)
index 0000000..f5f2af4
--- /dev/null
@@ -0,0 +1,1182 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>PACKAGES</key>
+       <array>
+               <dict>
+                       <key>MUST-CLOSE-APPLICATION-ITEMS</key>
+                       <array/>
+                       <key>MUST-CLOSE-APPLICATIONS</key>
+                       <false/>
+                       <key>PACKAGE_FILES</key>
+                       <dict>
+                               <key>DEFAULT_INSTALL_LOCATION</key>
+                               <string>/</string>
+                               <key>HIERARCHY</key>
+                               <dict>
+                                       <key>CHILDREN</key>
+                                       <array>
+                                               <dict>
+                                                       <key>CHILDREN</key>
+                                                       <array>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>80</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>Jack</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>2</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>509</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>2</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>BUNDLE_CAN_DOWNGRADE</key>
+                                                                       <false/>
+                                                                       <key>BUNDLE_POSTINSTALL_PATH</key>
+                                                                       <dict>
+                                                                               <key>PATH</key>
+                                                                               <string>link.sh</string>
+                                                                               <key>PATH_TYPE</key>
+                                                                               <integer>1</integer>
+                                                                       </dict>
+                                                                       <key>BUNDLE_PREINSTALL_PATH</key>
+                                                                       <dict>
+                                                                               <key>PATH_TYPE</key>
+                                                                               <integer>0</integer>
+                                                                       </dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>80</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>../%BUNDLENAME%.app</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>3</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>80</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>Utilities</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>-1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                       </array>
+                                                       <key>GID</key>
+                                                       <integer>80</integer>
+                                                       <key>PATH</key>
+                                                       <string>Applications</string>
+                                                       <key>PATH_TYPE</key>
+                                                       <integer>0</integer>
+                                                       <key>PERMISSIONS</key>
+                                                       <integer>509</integer>
+                                                       <key>TYPE</key>
+                                                       <integer>1</integer>
+                                                       <key>UID</key>
+                                                       <integer>0</integer>
+                                               </dict>
+                                               <dict>
+                                                       <key>CHILDREN</key>
+                                                       <array/>
+                                                       <key>GID</key>
+                                                       <integer>0</integer>
+                                                       <key>PATH</key>
+                                                       <string>bin</string>
+                                                       <key>PATH_TYPE</key>
+                                                       <integer>0</integer>
+                                                       <key>PERMISSIONS</key>
+                                                       <integer>493</integer>
+                                                       <key>TYPE</key>
+                                                       <integer>-1</integer>
+                                                       <key>UID</key>
+                                                       <integer>0</integer>
+                                               </dict>
+                                               <dict>
+                                                       <key>CHILDREN</key>
+                                                       <array>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>80</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>Application Support</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>Audio</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>Automator</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>ColorPickers</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>Documentation</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>Extensions</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>Filesystems</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>80</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>Fonts</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>1021</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>Frameworks</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>Input Methods</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>Internet Plug-Ins</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>LaunchAgents</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>LaunchDaemons</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>PreferencePanes</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>Preferences</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>80</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>Printers</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>PrivilegedHelperTools</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>1005</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>QuickLook</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>QuickTime</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>Screen Savers</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>Scripts</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>Services</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>Widgets</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                       </array>
+                                                       <key>GID</key>
+                                                       <integer>0</integer>
+                                                       <key>PATH</key>
+                                                       <string>Library</string>
+                                                       <key>PATH_TYPE</key>
+                                                       <integer>0</integer>
+                                                       <key>PERMISSIONS</key>
+                                                       <integer>493</integer>
+                                                       <key>TYPE</key>
+                                                       <integer>1</integer>
+                                                       <key>UID</key>
+                                                       <integer>0</integer>
+                                               </dict>
+                                               <dict>
+                                                       <key>CHILDREN</key>
+                                                       <array>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>etc</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>-1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>var</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>-1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                       </array>
+                                                       <key>GID</key>
+                                                       <integer>0</integer>
+                                                       <key>PATH</key>
+                                                       <string>private</string>
+                                                       <key>PATH_TYPE</key>
+                                                       <integer>0</integer>
+                                                       <key>PERMISSIONS</key>
+                                                       <integer>493</integer>
+                                                       <key>TYPE</key>
+                                                       <integer>-1</integer>
+                                                       <key>UID</key>
+                                                       <integer>0</integer>
+                                               </dict>
+                                               <dict>
+                                                       <key>CHILDREN</key>
+                                                       <array/>
+                                                       <key>GID</key>
+                                                       <integer>0</integer>
+                                                       <key>PATH</key>
+                                                       <string>sbin</string>
+                                                       <key>PATH_TYPE</key>
+                                                       <integer>0</integer>
+                                                       <key>PERMISSIONS</key>
+                                                       <integer>493</integer>
+                                                       <key>TYPE</key>
+                                                       <integer>-1</integer>
+                                                       <key>UID</key>
+                                                       <integer>0</integer>
+                                               </dict>
+                                               <dict>
+                                                       <key>CHILDREN</key>
+                                                       <array>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array>
+                                                                               <dict>
+                                                                                       <key>CHILDREN</key>
+                                                                                       <array/>
+                                                                                       <key>GID</key>
+                                                                                       <integer>0</integer>
+                                                                                       <key>PATH</key>
+                                                                                       <string>Extensions</string>
+                                                                                       <key>PATH_TYPE</key>
+                                                                                       <integer>0</integer>
+                                                                                       <key>PERMISSIONS</key>
+                                                                                       <integer>493</integer>
+                                                                                       <key>TYPE</key>
+                                                                                       <integer>1</integer>
+                                                                                       <key>UID</key>
+                                                                                       <integer>0</integer>
+                                                                               </dict>
+                                                                       </array>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>Library</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                       </array>
+                                                       <key>GID</key>
+                                                       <integer>0</integer>
+                                                       <key>PATH</key>
+                                                       <string>System</string>
+                                                       <key>PATH_TYPE</key>
+                                                       <integer>0</integer>
+                                                       <key>PERMISSIONS</key>
+                                                       <integer>493</integer>
+                                                       <key>TYPE</key>
+                                                       <integer>1</integer>
+                                                       <key>UID</key>
+                                                       <integer>0</integer>
+                                               </dict>
+                                               <dict>
+                                                       <key>CHILDREN</key>
+                                                       <array>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>Shared</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>1023</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                       </array>
+                                                       <key>GID</key>
+                                                       <integer>80</integer>
+                                                       <key>PATH</key>
+                                                       <string>Users</string>
+                                                       <key>PATH_TYPE</key>
+                                                       <integer>0</integer>
+                                                       <key>PERMISSIONS</key>
+                                                       <integer>493</integer>
+                                                       <key>TYPE</key>
+                                                       <integer>1</integer>
+                                                       <key>UID</key>
+                                                       <integer>0</integer>
+                                               </dict>
+                                               <dict>
+                                                       <key>CHILDREN</key>
+                                                       <array>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>bin</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>-1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>include</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>-1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>lib</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>-1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array>
+                                                                               <dict>
+                                                                                       <key>CHILDREN</key>
+                                                                                       <array/>
+                                                                                       <key>GID</key>
+                                                                                       <integer>0</integer>
+                                                                                       <key>PATH</key>
+                                                                                       <string>bin</string>
+                                                                                       <key>PATH_TYPE</key>
+                                                                                       <integer>0</integer>
+                                                                                       <key>PERMISSIONS</key>
+                                                                                       <integer>493</integer>
+                                                                                       <key>TYPE</key>
+                                                                                       <integer>-1</integer>
+                                                                                       <key>UID</key>
+                                                                                       <integer>0</integer>
+                                                                               </dict>
+                                                                       </array>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>local</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>-1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>sbin</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>-1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                               <dict>
+                                                                       <key>CHILDREN</key>
+                                                                       <array/>
+                                                                       <key>GID</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PATH</key>
+                                                                       <string>share</string>
+                                                                       <key>PATH_TYPE</key>
+                                                                       <integer>0</integer>
+                                                                       <key>PERMISSIONS</key>
+                                                                       <integer>493</integer>
+                                                                       <key>TYPE</key>
+                                                                       <integer>-1</integer>
+                                                                       <key>UID</key>
+                                                                       <integer>0</integer>
+                                                               </dict>
+                                                       </array>
+                                                       <key>GID</key>
+                                                       <integer>0</integer>
+                                                       <key>PATH</key>
+                                                       <string>usr</string>
+                                                       <key>PATH_TYPE</key>
+                                                       <integer>0</integer>
+                                                       <key>PERMISSIONS</key>
+                                                       <integer>493</integer>
+                                                       <key>TYPE</key>
+                                                       <integer>-1</integer>
+                                                       <key>UID</key>
+                                                       <integer>0</integer>
+                                               </dict>
+                                       </array>
+                                       <key>GID</key>
+                                       <integer>0</integer>
+                                       <key>PATH</key>
+                                       <string>/</string>
+                                       <key>PATH_TYPE</key>
+                                       <integer>0</integer>
+                                       <key>PERMISSIONS</key>
+                                       <integer>493</integer>
+                                       <key>TYPE</key>
+                                       <integer>1</integer>
+                                       <key>UID</key>
+                                       <integer>0</integer>
+                               </dict>
+                               <key>PAYLOAD_TYPE</key>
+                               <integer>0</integer>
+                               <key>PRESERVE_EXTENDED_ATTRIBUTES</key>
+                               <false/>
+                               <key>SHOW_INVISIBLE</key>
+                               <true/>
+                               <key>SPLIT_FORKS</key>
+                               <true/>
+                               <key>TREAT_MISSING_FILES_AS_WARNING</key>
+                               <false/>
+                               <key>VERSION</key>
+                               <integer>5</integer>
+                       </dict>
+                       <key>PACKAGE_SCRIPTS</key>
+                       <dict>
+                               <key>POSTINSTALL_PATH</key>
+                               <dict>
+                                       <key>PATH_TYPE</key>
+                                       <integer>0</integer>
+                               </dict>
+                               <key>PREINSTALL_PATH</key>
+                               <dict>
+                                       <key>PATH_TYPE</key>
+                                       <integer>0</integer>
+                               </dict>
+                               <key>RESOURCES</key>
+                               <array/>
+                       </dict>
+                       <key>PACKAGE_SETTINGS</key>
+                       <dict>
+                               <key>AUTHENTICATION</key>
+                               <integer>1</integer>
+                               <key>CONCLUSION_ACTION</key>
+                               <integer>0</integer>
+                               <key>FOLLOW_SYMBOLIC_LINKS</key>
+                               <false/>
+                               <key>IDENTIFIER</key>
+                               <string>%BUNDLEID%</string>
+                               <key>LOCATION</key>
+                               <integer>0</integer>
+                               <key>NAME</key>
+                               <string>%BUNDLENAME%</string>
+                               <key>OVERWRITE_PERMISSIONS</key>
+                               <true/>
+                               <key>PAYLOAD_SIZE</key>
+                               <integer>-1</integer>
+                               <key>REFERENCE_PATH</key>
+                               <string></string>
+                               <key>RELOCATABLE</key>
+                               <false/>
+                               <key>USE_HFS+_COMPRESSION</key>
+                               <false/>
+                               <key>VERSION</key>
+                               <string>%VERSION%</string>
+                       </dict>
+                       <key>TYPE</key>
+                       <integer>0</integer>
+                       <key>UUID</key>
+                       <string>10E1CE8D-C84E-45FC-81DA-B174548AE779</string>
+               </dict>
+       </array>
+       <key>PROJECT</key>
+       <dict>
+               <key>PROJECT_COMMENTS</key>
+               <dict>
+                       <key>NOTES</key>
+                       <data>
+                       </data>
+               </dict>
+               <key>PROJECT_PRESENTATION</key>
+               <dict>
+                       <key>BACKGROUND</key>
+                       <dict>
+                               <key>APPAREANCES</key>
+                               <dict>
+                                       <key>DARK_AQUA</key>
+                                       <dict/>
+                                       <key>LIGHT_AQUA</key>
+                                       <dict/>
+                               </dict>
+                               <key>SHARED_SETTINGS_FOR_ALL_APPAREANCES</key>
+                               <true/>
+                       </dict>
+                       <key>INSTALLATION_STEPS</key>
+                       <array>
+                               <dict>
+                                       <key>ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS</key>
+                                       <string>ICPresentationViewIntroductionController</string>
+                                       <key>INSTALLER_PLUGIN</key>
+                                       <string>Introduction</string>
+                                       <key>LIST_TITLE_KEY</key>
+                                       <string>InstallerSectionTitle</string>
+                               </dict>
+                               <dict>
+                                       <key>ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS</key>
+                                       <string>ICPresentationViewReadMeController</string>
+                                       <key>INSTALLER_PLUGIN</key>
+                                       <string>ReadMe</string>
+                                       <key>LIST_TITLE_KEY</key>
+                                       <string>InstallerSectionTitle</string>
+                               </dict>
+                               <dict>
+                                       <key>ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS</key>
+                                       <string>ICPresentationViewLicenseController</string>
+                                       <key>INSTALLER_PLUGIN</key>
+                                       <string>License</string>
+                                       <key>LIST_TITLE_KEY</key>
+                                       <string>InstallerSectionTitle</string>
+                               </dict>
+                               <dict>
+                                       <key>ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS</key>
+                                       <string>ICPresentationViewDestinationSelectController</string>
+                                       <key>INSTALLER_PLUGIN</key>
+                                       <string>TargetSelect</string>
+                                       <key>LIST_TITLE_KEY</key>
+                                       <string>InstallerSectionTitle</string>
+                               </dict>
+                               <dict>
+                                       <key>ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS</key>
+                                       <string>ICPresentationViewInstallationTypeController</string>
+                                       <key>INSTALLER_PLUGIN</key>
+                                       <string>PackageSelection</string>
+                                       <key>LIST_TITLE_KEY</key>
+                                       <string>InstallerSectionTitle</string>
+                               </dict>
+                               <dict>
+                                       <key>ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS</key>
+                                       <string>ICPresentationViewInstallationController</string>
+                                       <key>INSTALLER_PLUGIN</key>
+                                       <string>Install</string>
+                                       <key>LIST_TITLE_KEY</key>
+                                       <string>InstallerSectionTitle</string>
+                               </dict>
+                               <dict>
+                                       <key>ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS</key>
+                                       <string>ICPresentationViewSummaryController</string>
+                                       <key>INSTALLER_PLUGIN</key>
+                                       <string>Summary</string>
+                                       <key>LIST_TITLE_KEY</key>
+                                       <string>InstallerSectionTitle</string>
+                               </dict>
+                       </array>
+                       <key>INTRODUCTION</key>
+                       <dict>
+                               <key>LOCALIZATIONS</key>
+                               <array/>
+                       </dict>
+                       <key>LICENSE</key>
+                       <dict>
+                               <key>LOCALIZATIONS</key>
+                               <array>
+                                       <dict>
+                                               <key>LANGUAGE</key>
+                                               <string>English</string>
+                                               <key>VALUE</key>
+                                               <dict>
+                                                       <key>PATH</key>
+                                                       <string>license.txt</string>
+                                                       <key>PATH_TYPE</key>
+                                                       <integer>3</integer>
+                                               </dict>
+                                       </dict>
+                               </array>
+                               <key>MODE</key>
+                               <integer>0</integer>
+                       </dict>
+                       <key>README</key>
+                       <dict>
+                               <key>LOCALIZATIONS</key>
+                               <array>
+                                       <dict>
+                                               <key>LANGUAGE</key>
+                                               <string>English</string>
+                                               <key>VALUE</key>
+                                               <dict>
+                                                       <key>PATH</key>
+                                                       <string>readme.txt</string>
+                                                       <key>PATH_TYPE</key>
+                                                       <integer>3</integer>
+                                               </dict>
+                                       </dict>
+                               </array>
+                       </dict>
+                       <key>TITLE</key>
+                       <dict>
+                               <key>LOCALIZATIONS</key>
+                               <array/>
+                       </dict>
+               </dict>
+               <key>PROJECT_REQUIREMENTS</key>
+               <dict>
+                       <key>LIST</key>
+                       <array/>
+                       <key>RESOURCES</key>
+                       <array/>
+                       <key>ROOT_VOLUME_ONLY</key>
+                       <false/>
+               </dict>
+               <key>PROJECT_SETTINGS</key>
+               <dict>
+                       <key>BUILD_FORMAT</key>
+                       <integer>0</integer>
+                       <key>BUILD_PATH</key>
+                       <dict>
+                               <key>PATH</key>
+                               <string>build</string>
+                               <key>PATH_TYPE</key>
+                               <integer>1</integer>
+                       </dict>
+                       <key>EXCLUDED_FILES</key>
+                       <array>
+                               <dict>
+                                       <key>PATTERNS_ARRAY</key>
+                                       <array>
+                                               <dict>
+                                                       <key>REGULAR_EXPRESSION</key>
+                                                       <false/>
+                                                       <key>STRING</key>
+                                                       <string>.DS_Store</string>
+                                                       <key>TYPE</key>
+                                                       <integer>0</integer>
+                                               </dict>
+                                       </array>
+                                       <key>PROTECTED</key>
+                                       <true/>
+                                       <key>PROXY_NAME</key>
+                                       <string>Remove .DS_Store files</string>
+                                       <key>PROXY_TOOLTIP</key>
+                                       <string>Remove ".DS_Store" files created by the Finder.</string>
+                                       <key>STATE</key>
+                                       <true/>
+                               </dict>
+                               <dict>
+                                       <key>PATTERNS_ARRAY</key>
+                                       <array>
+                                               <dict>
+                                                       <key>REGULAR_EXPRESSION</key>
+                                                       <false/>
+                                                       <key>STRING</key>
+                                                       <string>.pbdevelopment</string>
+                                                       <key>TYPE</key>
+                                                       <integer>0</integer>
+                                               </dict>
+                                       </array>
+                                       <key>PROTECTED</key>
+                                       <true/>
+                                       <key>PROXY_NAME</key>
+                                       <string>Remove .pbdevelopment files</string>
+                                       <key>PROXY_TOOLTIP</key>
+                                       <string>Remove ".pbdevelopment" files created by ProjectBuilder or Xcode.</string>
+                                       <key>STATE</key>
+                                       <true/>
+                               </dict>
+                               <dict>
+                                       <key>PATTERNS_ARRAY</key>
+                                       <array>
+                                               <dict>
+                                                       <key>REGULAR_EXPRESSION</key>
+                                                       <false/>
+                                                       <key>STRING</key>
+                                                       <string>CVS</string>
+                                                       <key>TYPE</key>
+                                                       <integer>1</integer>
+                                               </dict>
+                                               <dict>
+                                                       <key>REGULAR_EXPRESSION</key>
+                                                       <false/>
+                                                       <key>STRING</key>
+                                                       <string>.cvsignore</string>
+                                                       <key>TYPE</key>
+                                                       <integer>0</integer>
+                                               </dict>
+                                               <dict>
+                                                       <key>REGULAR_EXPRESSION</key>
+                                                       <false/>
+                                                       <key>STRING</key>
+                                                       <string>.cvspass</string>
+                                                       <key>TYPE</key>
+                                                       <integer>0</integer>
+                                               </dict>
+                                               <dict>
+                                                       <key>REGULAR_EXPRESSION</key>
+                                                       <false/>
+                                                       <key>STRING</key>
+                                                       <string>.svn</string>
+                                                       <key>TYPE</key>
+                                                       <integer>1</integer>
+                                               </dict>
+                                               <dict>
+                                                       <key>REGULAR_EXPRESSION</key>
+                                                       <false/>
+                                                       <key>STRING</key>
+                                                       <string>.git</string>
+                                                       <key>TYPE</key>
+                                                       <integer>1</integer>
+                                               </dict>
+                                               <dict>
+                                                       <key>REGULAR_EXPRESSION</key>
+                                                       <false/>
+                                                       <key>STRING</key>
+                                                       <string>.gitignore</string>
+                                                       <key>TYPE</key>
+                                                       <integer>0</integer>
+                                               </dict>
+                                       </array>
+                                       <key>PROTECTED</key>
+                                       <true/>
+                                       <key>PROXY_NAME</key>
+                                       <string>Remove SCM metadata</string>
+                                       <key>PROXY_TOOLTIP</key>
+                                       <string>Remove helper files and folders used by the CVS, SVN or Git Source Code Management systems.</string>
+                                       <key>STATE</key>
+                                       <true/>
+                               </dict>
+                               <dict>
+                                       <key>PATTERNS_ARRAY</key>
+                                       <array>
+                                               <dict>
+                                                       <key>REGULAR_EXPRESSION</key>
+                                                       <false/>
+                                                       <key>STRING</key>
+                                                       <string>classes.nib</string>
+                                                       <key>TYPE</key>
+                                                       <integer>0</integer>
+                                               </dict>
+                                               <dict>
+                                                       <key>REGULAR_EXPRESSION</key>
+                                                       <false/>
+                                                       <key>STRING</key>
+                                                       <string>designable.db</string>
+                                                       <key>TYPE</key>
+                                                       <integer>0</integer>
+                                               </dict>
+                                               <dict>
+                                                       <key>REGULAR_EXPRESSION</key>
+                                                       <false/>
+                                                       <key>STRING</key>
+                                                       <string>info.nib</string>
+                                                       <key>TYPE</key>
+                                                       <integer>0</integer>
+                                               </dict>
+                                       </array>
+                                       <key>PROTECTED</key>
+                                       <true/>
+                                       <key>PROXY_NAME</key>
+                                       <string>Optimize nib files</string>
+                                       <key>PROXY_TOOLTIP</key>
+                                       <string>Remove "classes.nib", "info.nib" and "designable.nib" files within .nib bundles.</string>
+                                       <key>STATE</key>
+                                       <true/>
+                               </dict>
+                               <dict>
+                                       <key>PATTERNS_ARRAY</key>
+                                       <array>
+                                               <dict>
+                                                       <key>REGULAR_EXPRESSION</key>
+                                                       <false/>
+                                                       <key>STRING</key>
+                                                       <string>Resources Disabled</string>
+                                                       <key>TYPE</key>
+                                                       <integer>1</integer>
+                                               </dict>
+                                       </array>
+                                       <key>PROTECTED</key>
+                                       <true/>
+                                       <key>PROXY_NAME</key>
+                                       <string>Remove Resources Disabled folders</string>
+                                       <key>PROXY_TOOLTIP</key>
+                                       <string>Remove "Resources Disabled" folders.</string>
+                                       <key>STATE</key>
+                                       <true/>
+                               </dict>
+                               <dict>
+                                       <key>SEPARATOR</key>
+                                       <true/>
+                               </dict>
+                       </array>
+                       <key>NAME</key>
+                       <string>%BUNDLENAME%</string>
+                       <key>PAYLOAD_ONLY</key>
+                       <false/>
+                       <key>TREAT_MISSING_PRESENTATION_DOCUMENTS_AS_WARNING</key>
+                       <false/>
+               </dict>
+       </dict>
+       <key>TYPE</key>
+       <integer>0</integer>
+       <key>VERSION</key>
+       <integer>2</integer>
+</dict>
+</plist>
diff --git a/macos/package/link.sh b/macos/package/link.sh
new file mode 100644 (file)
index 0000000..350da28
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+mkdir -p /usr/local/bin
+rm -f /usr/local/bin/jacktrip
+ln -s "$2"/Contents/MacOS/jacktrip /usr/local/bin/jacktrip
index c7130975a07a4708a6bf1f8e61b884fac315aa11..565d37617ce764b0f188ee55ab9545c36c8c8f8b 100644 (file)
-project('jacktrip', 'cpp', version: '1.2',
-               default_options: ['cpp_std=c++11'])
+project('jacktrip', ['cpp','c'],
+               default_options: ['cpp_std=c++17','warning_level=2'])
+
+if get_option('profile') == 'development'
+  application_id = 'org.jacktrip.JackTrip.Devel'
+  name_suffix = ' (Development Snapshot)'
+else
+  application_id = 'org.jacktrip.JackTrip'
+  name_suffix = ''
+endif
+
 qt5 = import('qt5')
-qt5_dep = dependency('qt5', modules: ['Core', 'Network'])
-jack_dep = dependency('jack')
-thread_dep = dependency('threads')
+cmake = import('cmake')
 
-defines = []
+compiler = meson.get_compiler('cpp')
+
+defines = ['-DWAIRTOHUB']
+c_defines = []
 if host_machine.system() == 'linux'
        defines += '-D__LINUX__'
 elif host_machine.system() == 'darwin'
        defines += '-D__MAC_OSX__'
 elif host_machine.system() == 'windows'
        defines += '-D__WIN_32__'
+       defines += '-D_WIN32_WINNT=0x0600'
+       defines += '-DWIN32_LEAN_AND_MEAN'
+       defines += '-DNOMINMAX'
 endif
 
-moc_h = ['src/DataProtocol.h',
-       'src/JackTrip.h',
-       'src/JackTripWorker.h',
-       'src/JackTripWorkerMessages.h',
-       'src/NetKS.h',
-       'src/PacketHeader.h',
-       'src/Settings.h',
-       'src/UdpDataProtocol.h',
-       'src/UdpHubListener.h']
-moc_files = qt5.preprocess(moc_headers : moc_h)
+incdir = include_directories('externals/weakjack')
 
-src = ['src/DataProtocol.cpp',
-       'src/JMess.cpp',
+src = [        'src/DataProtocol.cpp',
        'src/JackTrip.cpp',
        'src/AudioTester.cpp',
        'src/jacktrip_globals.cpp',
-       'src/jacktrip_main.cpp',
-       'src/JackTripThread.cpp',
        'src/JackTripWorker.cpp',
        'src/LoopBack.cpp',
        'src/PacketHeader.cpp',
-       'src/ProcessPlugin.cpp',
        'src/RingBuffer.cpp',
        'src/JitterBuffer.cpp',
+       'src/PoolBuffer.cpp',
        'src/Settings.cpp',
        'src/UdpDataProtocol.cpp',
        'src/UdpHubListener.cpp',
        'src/AudioInterface.cpp',
-       'src/JackAudioInterface.cpp',
        'src/Compressor.cpp',
        'src/Limiter.cpp',
-       'src/Reverb.cpp']
+       'src/Reverb.cpp',
+       'src/main.cpp',
+       'src/SslServer.cpp',
+       'src/Auth.cpp']
+
+moc_h = ['src/DataProtocol.h',
+       'src/JackTrip.h',
+       'src/JackTripWorker.h',
+       'src/PacketHeader.h',
+       'src/Settings.h',
+       'src/UdpDataProtocol.h',
+       'src/UdpHubListener.h',
+       'src/Auth.h',
+       'src/SslServer.h']
+
+ui_h = []
+qres = []
+
+deps = [dependency('threads')]
+jack_dep = dependency('jack', required: get_option('jack'))
+if not jack_dep.found()
+       defines += '-D__NO_JACK__'
+else
+       src +=  ['src/JackAudioInterface.cpp',
+               'src/JMess.cpp',
+               'src/Patcher.cpp']
+       moc_h += ['src/Patcher.h']
+       if get_option('weakjack') == true
+               src += 'externals/weakjack/weak_libjack.c'
+               defines += '-DUSE_WEAK_JACK'
+               c_defines += '-DUSE_WEAK_JACK'
+               deps += jack_dep.partial_dependency(includes: true)
+               deps += compiler.find_library('dl', required : false)
+       else
+               deps += jack_dep
+       endif
+endif
+
+if get_option('nogui') == true
+       defines += '-DNO_GUI'
+       qt5_dep = dependency('qt5', modules: ['Core', 'Network'], include_type: 'system')
+else
+       qt5_dep = dependency('qt5', modules: ['Core', 'Gui', 'Network', 'Widgets'], include_type: 'system')
+       src += ['src/gui/qjacktrip.cpp',
+               'src/gui/about.cpp',
+               'src/gui/messageDialog.cpp']
+       ui_h += ['src/gui/qjacktrip.ui',
+               'src/gui/messageDialog.ui',
+               'src/gui/about.ui']
+       moc_h += ['src/gui/about.h',
+               'src/gui/qjacktrip.h',
+               'src/gui/messageDialog.h']
+       qres = ['src/gui/qjacktrip.qrc']
+endif
+deps += qt5_dep
+
+prepro_files = qt5.preprocess(moc_headers : moc_h, ui_files : ui_h, qresources : qres)
+
+# TODO: QT_OPENSOURCE should only be defined for open source Qt distribution
+# in QMake this can be checked with QT_EDITION == 'OpenSource'
+defines += '-DQT_OPENSOURCE'
+
+rtaudio_dep = dependency('rtaudio', required: get_option('rtaudio'))
+if rtaudio_dep.found() == true
+       defines += '-D__RT_AUDIO__'
+       src += 'src/RtAudioInterface.cpp'
+       deps += rtaudio_dep
+endif
+
+if host_machine.system() == 'windows'
+       deps += compiler.find_library('ws2_32', required: true)
+endif
+
+if compiler.get_id() == 'msvc'
+       opt_var = cmake.subproject_options()
+       if get_option('buildtype') == 'release'
+               opt_var.add_cmake_defines({'CMAKE_BUILD_TYPE': 'Release'})
+       else
+               opt_var.add_cmake_defines({'CMAKE_BUILD_TYPE': 'Debug'})
+       endif
+       wingetopt = cmake.subproject('wingetopt', options: opt_var)
+       deps += wingetopt.dependency('wingetopt')
+endif
+
+if host_machine.system() == 'darwin'
+       src += ['src/gui/NoNap.mm']
+       # Adding CoreAudio here is a workaround and should be removed
+       # when https://github.com/thestk/rtaudio/issues/302 is fixed
+       # and arrived in all common package managers
+       # Check at 2022-07-30
+       apple_dep = dependency('appleframeworks', modules : ['foundation','coreaudio'])
+       deps += apple_dep
+       add_languages('objcpp')
+endif
+
+subdir('linux')
+
+jacktrip = executable('jacktrip', src, prepro_files, include_directories: incdir, dependencies: deps, c_args: c_defines, cpp_args: defines, install: true )
+
+help2man = find_program('help2man', required: false)
+if not (host_machine.system() == 'windows')
+       if help2man.found()
+               help2man_opts = [
+                       '--no-info',
+                       '--section=1']
+               custom_target('jacktrip.1',
+                       output: 'jacktrip.1',
+                       command: [help2man, help2man_opts, '--output=@OUTPUT@', jacktrip],
+                       install: true,
+                       install_dir: get_option('mandir') / 'man1')
+       endif
+endif
+
+summary({'JACK': jack_dep.found(),
+       'Weak JACK Linking': get_option('weakjack'),
+       'RtAudio': rtaudio_dep.found()}, bool_yn: true, section: 'Audio Backends')
+
+summary({'Application ID': application_id,
+       'GUI': not get_option('nogui'),
+       'WAIR': get_option('wair'),
+       'Manpage': help2man.found()}, bool_yn: true, section: 'Configuration')
 
-executable('jacktrip', src, moc_files, dependencies: [qt5_dep, jack_dep, thread_dep], cpp_args: defines, install: true )
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644 (file)
index 0000000..6d93cd7
--- /dev/null
@@ -0,0 +1,6 @@
+option('wair', type : 'boolean', value : 'false', description: 'WAIR')
+option('rtaudio', type : 'feature', value : 'auto', description: 'Build with RtAudio Backend')
+option('jack', type : 'feature', value : 'auto', description: 'Build with JACK Backend')
+option('weakjack', type : 'boolean', value : 'false', description: 'Weak link JACK library')
+option('nogui', type : 'boolean', value : 'false', description: 'Build without graphical user interface')
+option('profile', type: 'combo', choices: ['default', 'development'], value: 'default', description: 'Choose build profile / Sets desktop id accordingly')
diff --git a/mkdocs.yml b/mkdocs.yml
new file mode 100644 (file)
index 0000000..de40622
--- /dev/null
@@ -0,0 +1,32 @@
+site_name: JackTrip
+repo_url: https://github.com/jacktrip/jacktrip
+edit_uri: edit/dev/docs/
+nav:
+  - Home: index.md
+  - User Guide:
+    - Installation: Install.md
+  - Developer Guide:
+    - QMake Build:
+      - Linux: Build/Linux.md
+      - Mac OS: Build/Mac.md
+      - Windows: Build/Windows.md
+    - Meson Build: Build/Meson_build.md
+    - Development Tools:
+      - Formatting: DevTools/Formatting.md
+      - Static Analysis: DevTools/StaticAnalysis.md
+    - Write Documentation: Documentation/MkDocs.md
+  - About:
+    - Contributors: About/Contributors.md
+    - Resources: About/Resources.md
+    - Changelog: About/CHANGELOG.md
+    - License: About/License.md
+theme:
+  name: material
+  features:
+    - navigation.tabs
+markdown_extensions:
+  - pymdownx.snippets
+  - pymdownx.tabbed
+  - pymdownx.superfences
+  - pymdownx.details
+  - admonition
diff --git a/rtaudio.pro b/rtaudio.pro
new file mode 100644 (file)
index 0000000..6934b19
--- /dev/null
@@ -0,0 +1,35 @@
+# created by Marcin Pączkowski 
+# configuration for building RtAudio library using qmake
+
+TEMPLATE = lib
+INCLUDEPATH += . externals/rtaudio
+
+CONFIG += debug_and_release staticlib
+
+# Input
+HEADERS += externals/rtaudio/RtAudio.h
+SOURCES += externals/rtaudio/RtAudio.cpp
+
+linux-g++ | linux-g++-64 {
+  QMAKE_CXXFLAGS += -D__LINUX_PULSE__ -D__LINUX_ALSA__
+}
+macx {
+  QMAKE_CXXFLAGS += -D__MACOSX_CORE__
+}
+win32 {
+  QMAKE_CXXFLAGS += -D__WINDOWS_ASIO__ -D__WINDOWS_WASAPI__
+  INCLUDEPATH += externals/rtaudio/include
+  HEADERS += externals/rtaudio/include/asio.h \
+             externals/rtaudio/include/asiodrivers.h \
+             externals/rtaudio/include/asiolist.h \
+             externals/rtaudio/include/asiodrvr.h \
+             externals/rtaudio/include/asiosys.h \
+             externals/rtaudio/include/ginclude.h \
+             externals/rtaudio/include/iasiodrv.h \
+             externals/rtaudio/include/iasiothiscallresolver.h \
+             externals/rtaudio/include/functiondiscoverykeys_devpkey.h
+  SOURCES += externals/rtaudio/include/asio.cpp \
+             externals/rtaudio/include/asiodrivers.cpp \
+             externals/rtaudio/include/asiolist.cpp \
+             externals/rtaudio/include/iasiothiscallresolver.cpp
+}
index 77af9a3c532544324ca5b4f8ebac9531bce2a3a0..a30239fbb1cb3af357aa68d7250d3c20e583c17b 100755 (executable)
@@ -1,23 +1,24 @@
+#!/bin/bash
+# bash script for jacktrip automation, Chris Chafe
+# art.sh <FPP>
+
+FPP=$1
+
 echo calculate audio round trip
 rm /tmp/art.dat
-$( jack_iodelay > /tmp/art.dat 2>&1 & )
-# jack_iodelay  &
-sleep 1
-# jack_connect jack_delay:out jackloop$1.stanford.edu:send_2
-# jack_connect jackloop$1.stanford.edu:receive_2 jack_delay:in
-jack_disconnect __1:receive_1 __1:send_1
-jack_disconnect __1:receive_2 __1:send_2
-# jack_disconnect localhost:receive_1 localhost:send_1
-# jack_disconnect localhost:receive_2 localhost:send_2
-jack_connect jack_delay:out __1:send_1
-jack_connect __1:receive_1 jack_delay:in
+$(PIPEWIRE_LATENCY="$FPP/48000" jack_iodelay > /tmp/art.dat 2>&1 & )
+
+$(jmess -D)
+
+# correct in main not in dev -- jack_connect JackTrip:receive_1 JackTrip:send_1
+jack_connect __1:receive_1 __1:send_1
+jack_connect jack_delay:out HUBCLIENT:send_1
+jack_connect HUBCLIENT:receive_1 jack_delay:in
 
 sleep 8
 killall jack_iodelay
-sleep 1
 
 killall jacktrip
-killall jackd
 
 DEFAULTOUTPUT=-1
 AWKOUTPUT=$(grep total  /tmp/art.dat | \
index 598c8d322d2bae596b0498a98d81025479654440..db495c1a41464074507cf98853ee23c55fc79f54 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/bash
 # bash script for jacktrip automation, Chris Chafe
-# startJacktripHubClient.sh <FPP>
+# startJacktripHubClient.sh <JACKTRIP> <FPP>
 # 
 # /home/cc/Desktop/sh/startJacktripHubClient.sh /home/cc/jacktrip/builddir/jacktrip %p
 
@@ -32,19 +32,12 @@ JACKTRIP=$1
 # /home/cc/startJacktrip.sh %p
 
 
-if [ -z "$2" ]
-  then
-    SERVER=localhost
-  else
-    FPP=$2
-    SERVER=jackloop$FPP.stanford.edu
-fi
+FPP=$2
+SERVER=localhost
 
+echo starting hub client of a server running on $SERVER
 
-echo starting hub client of server running on $SERVER
-
-$( $JACKTRIP -C $SERVER > /dev/null 2>&1 & )
-
+$(PIPEWIRE_LATENCY="$FPP/48000" $JACKTRIP -C $SERVER -J HUBCLIENT --udprt  --bufstrategy 3 --pktpool 3 -q1 > /dev/null 2>&1 & )
 
 
 
index 3079ea99bdcfe0aaf91b39d31349a0490145be59..b3942253c8d9d9e31a48638266683219cd186d96 100755 (executable)
@@ -1,13 +1,13 @@
 #!/bin/bash
 # bash script for jacktrip automation, Chris Chafe
-# startJacktripHubServer.sh <FPP>
+# startJacktripHubServer.sh <JACKTRIP> <FPP>
 
 JACKTRIP=$1
-
+FPP=$2
 
 echo starting $JACKTRIP server
 
-$( $JACKTRIP -S -p1 > /dev/null 2>&1 & )
+$(PIPEWIRE_LATENCY="$FPP/48000" $JACKTRIP -S -p1 --udprt  --bufstrategy 3 --pktpool 3 -q1 > /dev/null 2>&1 & )
 
 
 
index 7e0502f015689057df5560585ec835c8016c3fa0..ff499802c429d84f0c0021664073a37495d80d17 100755 (executable)
@@ -1,67 +1,68 @@
 #!/bin/bash
-# test_hub_mode_server_and_client.sh
-# bash script for automatic testing of jacktrip in hub mode , Chris Chafe
+# test_hub_mode_server_and_client.sh <JACKTRIP> <FPP> <JACKD>
+
+# bash script for automatic testing of jacktrip in hub mode, Chris Chafe
 # connects a hub client to a hub server (started with with -p1) on the same host
+
+# to run jackd automatically, set JACKD to anything (e.g., 1)
+#    for example, for CI testing
+# prints avg audio RTT after about 20 sec, or -1 if fail 
+
+# to not run jackd automatically, leave off the 3rd argument
+#     for example, if starting jackd manually with qjackctl or using 
 # prints avg audio RTT after 8 sec, or -1 if fail 
-# ./test_hub_mode_server_and_client.sh <path-to-executable> <FPP>
-# requires 3 helper scripts
+
+# requires jack_iodelay be installed and available from system
+
+# # requires 3 helper scripts in the same directory
 # -- startJacktripHubServer.sh
 # -- startJacktripHubClient.sh
 # -- art.sh
-# requires jackd be available on the host
-# uses the "dummy" interface, so no audio interface needed
-# first does some jackd cleanup 
-# takes approx. 20 sec to complete
 
-# a passing test prints to the console
-# [cc@localhost sh]$ ./test.sh /home/cc/jacktrip/builddir/jacktrip 32
+# example session:
+
+# [cc@localhost sh]$ ./test_hub_mode_server_and_client.sh /home/cc/jacktrip/builddir/jacktrip 32
 # starting /home/cc/jacktrip/builddir/jacktrip hub mode test at 32 FPP
 # starting hub client for server localhost
 # calculate audio round trip
 # 4
 
 # a failed test prints to the console
-# [cc@localhost functionTests]$ ./test.sh ~/jacktrip/builddir/jacktrip 32
-# starting /home/cc/jacktrip/builddir/jacktrip hub mode test at 32 FPP
-# starting /home/cc/jacktrip/builddir/jacktrip server
-# starting hub client of server running on localhost
-# calculate audio round trip
-# ERROR ..1:send_1 not a valid port
-# ERROR ..1:send_2 not a valid port
-# ERROR ..1:send_1 not a valid port
-# ERROR ..1:receive_1 not a valid port
-# jacktrip: no process found
 # -1
 
-
 JACKTRIP=$1
+FPP=$2
 
-if [ -z "$2" ]
+if [ -z "$3" ]
   then
-    FPP=128
+    JACKD=0
   else
-    FPP=$2
+    JACKD=$3
 fi
 
+echo starting $JACKTRIP hub mode test at $FPP FPP with JACKD = $JACKD
+
+if [ $JACKD != 0 ]
+  then
+    echo starting JACKD
 # killall jackd
-if [ "$(ps -aux | grep -c jackd)" != 1 ]; then killall jackd; fi;
+    if [ "$(ps -aux | grep -c jackd)" != 1 ]; then killall jackd; fi;
 # if jackd is or has been running with another driver
 # much experimenation shows it literally takes this long
-sleep 17
+    sleep 17
 # to flush old connections before starting the dummy driver
 
 # start jack with dummy driver, or change to an audio interface by switching these lines
-$( /usr/bin/jackd  -ddummy -r48000 -p$FPP > /dev/null 2>&1 & )
+    $( /usr/bin/jackd  -ddummy -r48000 -p$FPP > /dev/null 2>&1 & )
 # $( /usr/bin/jackd  -dalsa -dhw:A96 -r48000 -p$FPP -n2  > /dev/null 2>&1 & )
 # $( /usr/bin/jackd  -dalsa -dhw:PCH -r48000 -p$FPP -n2  > /dev/null 2>&1 & )
 
-sleep 1
-
-echo starting $JACKTRIP hub mode test at $FPP FPP
+    sleep 1
+fi
 
-$PWD/startJacktripHubServer.sh $JACKTRIP
+$PWD/startJacktripHubServer.sh $JACKTRIP $FPP
 sleep 1
-$PWD/startJacktripHubClient.sh $JACKTRIP
+$PWD/startJacktripHubClient.sh $JACKTRIP $FPP
 
 sleep 1
 
diff --git a/scripts/utility/generate_auth.sh b/scripts/utility/generate_auth.sh
new file mode 100755 (executable)
index 0000000..8bf3965
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/bash
+echo "This script will create a private key, certificate and credentials file for use with a hub server."
+echo "(You need to have openssl installed to successfully run it.)"
+echo
+echo "When generating the SSL certificate, you should enter the hostname and domain of the machine that"
+echo "you intend to run the server on as the \"Common Name\""
+echo ""
+read -n1 -rsp "Press any key to start..."
+openssl req -x509 -sha256 -nodes -days 3650 -newkey rsa:2048 -keyout jacktrip.key -out jacktrip.crt
+echo ""
+echo "Key created as jacktrip.key. Certificate created as jacktrip.crt."
+echo ""
+echo "Creating auth file. The username and password entered here can be used to access the server with"
+echo "no time restrictions."
+read -p "Username: " USERNAME
+PASSWD=`openssl passwd -6`
+echo "$USERNAME:$PASSWD:*" > auth
+echo "Credentials written to auth"
index ce792c11355be07ca5b5338a5153f59949b23d08..ac4a2cc27de4a6e036e6dabc3d2aad8c07490703 100755 (executable)
@@ -1,21 +1,26 @@
 #!/bin/bash
+#use this script to record jacktrip receive & broadcast channels on ecasound
+#Dependency: Ecasound https://ecasound.seul.org/ecasound/README
+#Make sure you have ecasound installed in the recording environment (server or client)
+#Start JACK and JackTrip on the server or the client you want to record from
+#IMPORTANT: Wait till all clients have connected
+#cd to the folder where this script is located
+#Start the script from the terminal: ./record_jack_receiving_ports.sh
+#Press ESC to stop recording.
+#Recording should appear as a .wav file in the same folder as the script
 
 if ! pgrep -x "jackd" ; then
   printf "Please start jack with a 48K sample rate before running this script."
   exit
 fi
 
-IPs=($(jack_lsp | grep ":receive_*" | cut -d: -f1))
-uniqIPs=($(printf "%s\n" "${IPs[@]}" | sort -u | tr '\n' ' '))
+IPs=($(jack_lsp | grep ':receive_*\|:broadcast_*' | cut -d: -f1))
 
-uniqLength=${#uniqIPs[@]}
-printf '%s\n' "number of unique IP's: ${uniqLength}"
-
-for IP in "${uniqIPs[@]}"
+for IP in "${IPs[@]}"
 do
   printf '%s\n' "IP: ${IP}"
   NOW=$( date '+%F_%H:%M:%S' )
-  ecasound -f:,1,48000 -i jack,${IP} -o rec_${IP}_${NOW}_output.wav &
+  ecasound -f:,4,48000 -i jack,${IP} -o rec_${IP}_${NOW}_output.wav &
 done 
 
 echo "Press ESC key to stop recording"
index 8caf34827f3c70269f51dc20922a951e41f624c9..c49855772dc44d37e9030929f3e8aceaf17512c2 100644 (file)
  */
 
 #include "AudioInterface.h"
-#include "JackTrip.h"
-#include <iostream>
+
+#include <cassert>
 #include <cmath>
-#include <assert.h>
+#include <iostream>
 
-using std::cout; using std::endl;
+#include "JackTrip.h"
+
+using std::cout;
+using std::endl;
 
 //*******************************************************************************
-AudioInterface::AudioInterface(JackTrip* jacktrip,
-                               int NumInChans, int NumOutChans,
-                               #ifdef WAIR // wair
+AudioInterface::AudioInterface(JackTrip* jacktrip, int NumInChans, int NumOutChans,
+#ifdef WAIR  // wair
                                int NumNetRevChans,
-                               #endif // endwhere
-                               audioBitResolutionT AudioBitResolution) :
-    mJackTrip(jacktrip),
-    mNumInChans(NumInChans), mNumOutChans(NumOutChans),
-    #ifdef WAIR // WAIR
-    mNumNetRevChans(NumNetRevChans),
-    #endif // endwhere
-    mAudioBitResolution(AudioBitResolution*8),
-    mBitResolutionMode(AudioBitResolution),
-    mSampleRate(gDefaultSampleRate), mBufferSizeInSamples(gDefaultBufferSizeInSamples),
-    mInputPacket(NULL), mOutputPacket(NULL), mLoopBack(false), mProcessingAudio(false)
+#endif  // endwhere
+                               audioBitResolutionT AudioBitResolution)
+    : mJackTrip(jacktrip)
+    , mNumInChans(NumInChans)
+    , mNumOutChans(NumOutChans)
+    ,
+#ifdef WAIR  // WAIR
+    mNumNetRevChans(NumNetRevChans)
+    ,
+#endif  // endwhere
+    mAudioBitResolution(AudioBitResolution * 8)
+    , mBitResolutionMode(AudioBitResolution)
+    , mSampleRate(gDefaultSampleRate)
+    , mBufferSizeInSamples(gDefaultBufferSizeInSamples)
+    , mAudioInputPacket(NULL)
+    , mAudioOutputPacket(NULL)
+    , mLoopBack(false)
+    , mProcessingAudio(false)
 {
 #ifndef WAIR
-    //cc
+    // cc
     // Initialize and assign memory for ProcessPlugins Buffers
     mInProcessBuffer.resize(mNumInChans);
     mOutProcessBuffer.resize(mNumOutChans);
     // Set pointer to NULL
-    for (int i = 0; i < mNumInChans; i++) {
-        mInProcessBuffer[i] = NULL;
-    }
-    for (int i = 0; i < mNumOutChans; i++) {
-        mOutProcessBuffer[i] = NULL;
-    }
-#else // WAIR
+    for (int i = 0; i < mNumInChans; i++) { mInProcessBuffer[i] = NULL; }
+    for (int i = 0; i < mNumOutChans; i++) { mOutProcessBuffer[i] = NULL; }
+#else   // WAIR
     int iCnt = (mNumInChans > mNumNetRevChans) ? mNumInChans : mNumNetRevChans;
     int oCnt = (mNumOutChans > mNumNetRevChans) ? mNumOutChans : mNumNetRevChans;
     int aCnt = (mNumNetRevChans) ? mNumInChans : 0;
-    for (int i = 0; i < iCnt; i++) {
-        mInProcessBuffer[i] = NULL;
-    }
-    for (int i = 0; i < oCnt; i++) {
-        mOutProcessBuffer[i] = NULL;
-    }
-    for (int i = 0; i < aCnt; i++) {
-        mAPInBuffer[i] = NULL;
-    }
-#endif // endwhere
+    for (int i = 0; i < iCnt; i++) { mInProcessBuffer[i] = NULL; }
+    for (int i = 0; i < oCnt; i++) { mOutProcessBuffer[i] = NULL; }
+    for (int i = 0; i < aCnt; i++) { mAPInBuffer[i] = NULL; }
+#endif  // endwhere
 
     mInBufCopy.resize(mNumInChans);
-    for (int i=0; i<mNumInChans; i++) {
-      mInBufCopy[i] = new sample_t[MAX_AUDIO_BUFFER_SIZE]; // required for processing audio input
+    for (int i = 0; i < mNumInChans; i++) {
+        mInBufCopy[i] =
+            new sample_t[MAX_AUDIO_BUFFER_SIZE];  // required for processing audio input
     }
 }
 
-
 //*******************************************************************************
 AudioInterface::~AudioInterface()
 {
-    delete[] mInputPacket;
-    delete[] mOutputPacket;
-#ifndef WAIR // NOT WAIR:
-    for (int i = 0; i < mNumInChans; i++) {
-        delete[] mInProcessBuffer[i];
-    }
+    delete[] mAudioInputPacket;
+    delete[] mAudioOutputPacket;
+#ifndef WAIR  // NOT WAIR:
+    for (int i = 0; i < mNumInChans; i++) { delete[] mInProcessBuffer[i]; }
 
-    for (int i = 0; i < mNumOutChans; i++) {
-        delete[] mOutProcessBuffer[i];
-    }
-#else // WAIR
+    for (int i = 0; i < mNumOutChans; i++) { delete[] mOutProcessBuffer[i]; }
+#else   // WAIR
     int iCnt = (mNumInChans > mNumNetRevChans) ? mNumInChans : mNumNetRevChans;
     int oCnt = (mNumOutChans > mNumNetRevChans) ? mNumOutChans : mNumNetRevChans;
     int aCnt = (mNumNetRevChans) ? mNumInChans : 0;
-    for (int i = 0; i < iCnt; i++) {
-        delete[] mInProcessBuffer[i];
-    }
-    for (int i = 0; i < oCnt; i++) {
-        delete[] mOutProcessBuffer[i];
-    }
-    for (int i = 0; i < aCnt; i++) {
-        delete[] mAPInBuffer[i];
-    }
-#endif // endwhere
-
-    for (int i = 0; i < mProcessPluginsFromNetwork.size(); i++) {
-      delete mProcessPluginsFromNetwork[i];
-    }
-    for (int i = 0; i < mProcessPluginsToNetwork.size(); i++) {
-      delete mProcessPluginsToNetwork[i];
-    }
-    for (int i=0; i<mNumInChans; i++) {
-      delete mInBufCopy[i];
-    }
+    for (int i = 0; i < iCnt; i++) { delete[] mInProcessBuffer[i]; }
+    for (int i = 0; i < oCnt; i++) { delete[] mOutProcessBuffer[i]; }
+    for (int i = 0; i < aCnt; i++) { delete[] mAPInBuffer[i]; }
+#endif  // endwhere
+
+    for (auto* i : qAsConst(mProcessPluginsFromNetwork)) { delete i; }
+    for (auto* i : qAsConst(mProcessPluginsToNetwork)) { delete i; }
+    for (int i = 0; i < mNumInChans; i++) { delete[] mInBufCopy[i]; }
 }
 
-
 //*******************************************************************************
 void AudioInterface::setup()
 {
     // Allocate buffer memory to read and write
     mSizeInBytesPerChannel = getSizeInBytesPerChannel();
 
-    int size_input  = mSizeInBytesPerChannel * getNumInputChannels();
-    int size_output = mSizeInBytesPerChannel * getNumOutputChannels();
-#ifdef WAIR // WAIR
-    if(mNumNetRevChans) // else don't change sizes
+    int size_audio_input  = mSizeInBytesPerChannel * getNumInputChannels();
+    int size_audio_output = mSizeInBytesPerChannel * getNumOutputChannels();
+#ifdef WAIR               // WAIR
+    if (mNumNetRevChans)  // else don't change sizes
     {
-        size_input  = mSizeInBytesPerChannel * mNumNetRevChans;
-        size_output = mSizeInBytesPerChannel * mNumNetRevChans;
+        size_audio_input  = mSizeInBytesPerChannel * mNumNetRevChans;
+        size_audio_output = mSizeInBytesPerChannel * mNumNetRevChans;
     }
-#endif // endwhere
-    mInputPacket = new int8_t[size_input];
-    mOutputPacket = new int8_t[size_output];
+#endif  // endwhere
+    mAudioInputPacket  = new int8_t[size_audio_input];
+    mAudioOutputPacket = new int8_t[size_audio_output];
 
     // Initialize and asign memory for ProcessPlugins Buffers
-#ifdef WAIR // WAIR
-    if(mNumNetRevChans)
-    {
+#ifdef WAIR  // WAIR
+    if (mNumNetRevChans) {
         mInProcessBuffer.resize(mNumNetRevChans);
         mOutProcessBuffer.resize(mNumNetRevChans);
         mAPInBuffer.resize(mNumInChans);
         mNetInBuffer.resize(mNumNetRevChans);
-    } else // don't change sizes
-#endif // endwhere
+    } else  // don't change sizes
+#endif      // endwhere
     {
         mInProcessBuffer.resize(mNumInChans);
         mOutProcessBuffer.resize(mNumOutChans);
@@ -169,7 +150,7 @@ void AudioInterface::setup()
 
     int nframes = getBufferSizeInSamples();
 
-#ifndef WAIR // NOT WAIR:
+#ifndef WAIR  // NOT WAIR:
     for (int i = 0; i < mNumInChans; i++) {
         mInProcessBuffer[i] = new sample_t[nframes];
         // set memory to 0
@@ -180,18 +161,18 @@ void AudioInterface::setup()
         // set memory to 0
         std::memset(mOutProcessBuffer[i], 0, sizeof(sample_t) * nframes);
     }
-#else // WAIR
-    for (int i = 0; i < ((mNumNetRevChans)?mNumNetRevChans:mNumInChans); i++) {
+#else   // WAIR
+    for (int i = 0; i < ((mNumNetRevChans) ? mNumNetRevChans : mNumInChans); i++) {
         mInProcessBuffer[i] = new sample_t[nframes];
         // set memory to 0
         std::memset(mInProcessBuffer[i], 0, sizeof(sample_t) * nframes);
     }
-    for (int i = 0; i < ((mNumNetRevChans)?mNumNetRevChans:mNumOutChans); i++) {
+    for (int i = 0; i < ((mNumNetRevChans) ? mNumNetRevChans : mNumOutChans); i++) {
         mOutProcessBuffer[i] = new sample_t[nframes];
         // set memory to 0
         std::memset(mOutProcessBuffer[i], 0, sizeof(sample_t) * nframes);
     }
-    for (int i = 0; i < ((mNumNetRevChans)?mNumInChans:0); i++) {
+    for (int i = 0; i < ((mNumNetRevChans) ? mNumInChans : 0); i++) {
         mAPInBuffer[i] = new sample_t[nframes];
         // set memory to 0
         std::memset(mAPInBuffer[i], 0, sizeof(sample_t) * nframes);
@@ -201,18 +182,15 @@ void AudioInterface::setup()
         // set memory to 0
         std::memset(mNetInBuffer[i], 0, sizeof(sample_t) * nframes);
     }
-#endif // endwhere
-
+#endif  // endwhere
 }
 
-
 //*******************************************************************************
 size_t AudioInterface::getSizeInBytesPerChannel() const
 {
-    return (getBufferSizeInSamples() * getAudioBitResolution()/8);
+    return (getBufferSizeInSamples() * getAudioBitResolution() / 8);
 }
 
-
 //*******************************************************************************
 void AudioInterface::callback(QVarLengthArray<sample_t*>& in_buffer,
                               QVarLengthArray<sample_t*>& out_buffer,
@@ -223,16 +201,16 @@ void AudioInterface::callback(QVarLengthArray<sample_t*>& in_buffer,
     // 1) First, process incoming packets
     // ----------------------------------
 
-#ifdef WAIR // WAIR
+#ifdef WAIR  // WAIR
     //    qDebug() << "--" << mProcessPluginsFromNetwork.size();
     bool client = (mProcessPluginsFromNetwork.size() == 2);
-#define COMBDSP 1 // client
-#define APDSP 0 // client
-#define DCBDSP 0 // server
+#define COMBDSP 1  // client
+#define APDSP   0  // client
+#define DCBDSP  0  // server
     for (int i = 0; i < mNumNetRevChans; i++) {
         std::memset(mNetInBuffer[i], 0, sizeof(sample_t) * n_frames);
     }
-#endif // endwhere
+#endif  // endwhere
 
     // ==== RECEIVE AUDIO CHANNELS FROM NETWORK ====
     computeProcessFromNetwork(out_buffer, n_frames);
@@ -243,89 +221,93 @@ void AudioInterface::callback(QVarLengthArray<sample_t*>& in_buffer,
 
     // mAudioTesterP will be nullptr for hub server's JackTripWorker instances
     if (mAudioTesterP && mAudioTesterP->getEnabled()) {
-      mAudioTesterP->lookForReturnPulse(out_buffer, n_frames);
+        mAudioTesterP->lookForReturnPulse(out_buffer, n_frames);
     }
 
-#ifdef WAIR // WAIR
+#ifdef WAIR  // WAIR
     // nib16 result now in mNetInBuffer
-#endif // endwhere
+#endif  // endwhere
 
     // 2) Dynamically allocate ProcessPlugin processes
     // -----------------------------------------------
     // The processing will be done in order of allocation
-    /// \todo Implement for more than one process plugin, now it just works propertely with one.
-    /// do it chaining outputs to inputs in the buffers. May need a tempo buffer
-
-#ifndef WAIR // NOT WAIR:
-    for (int i = 0; i < mProcessPluginsFromNetwork.size(); i++) {
-      ProcessPlugin* p = mProcessPluginsFromNetwork[i];
-      if (p->getInited()) {
-        p->compute(n_frames, out_buffer.data(), out_buffer.data());
-      }
+    /// \todo Implement for more than one process plugin, now it just works propertely
+    /// with one. do it chaining outputs to inputs in the buffers. May need a tempo buffer
+
+#ifndef WAIR  // NOT WAIR:
+    for (auto* p : qAsConst(mProcessPluginsFromNetwork)) {
+        if (p->getInited()) {
+            p->compute(n_frames, out_buffer.data(), out_buffer.data());
+        }
     }
-#else // WAIR:
-    for (int i = 0; i < ((mNumNetRevChans)?mNumNetRevChans:mNumOutChans); i++) {
+#else   // WAIR:
+    for (int i = 0; i < ((mNumNetRevChans) ? mNumNetRevChans : mNumOutChans); i++) {
         std::memset(mOutProcessBuffer[i], 0, sizeof(sample_t) * n_frames);
     }
-    for (int i = 0; i < ((mNumNetRevChans)?mNumNetRevChans:mNumInChans); i++) {
+    for (int i = 0; i < ((mNumNetRevChans) ? mNumNetRevChans : mNumInChans); i++) {
         std::memset(mInProcessBuffer[i], 0, sizeof(sample_t) * n_frames);
-        if (mNumNetRevChans)
-        {
+        if (mNumNetRevChans) {
             if (client)
-                std::memcpy(mInProcessBuffer[i], mNetInBuffer[i], sizeof(sample_t) * n_frames);
+                std::memcpy(mInProcessBuffer[i], mNetInBuffer[i],
+                            sizeof(sample_t) * n_frames);
             else
-                std::memcpy(mOutProcessBuffer[i], mNetInBuffer[i], sizeof(sample_t) * n_frames);
+                std::memcpy(mOutProcessBuffer[i], mNetInBuffer[i],
+                            sizeof(sample_t) * n_frames);
         }
     }
     // nib16 to cib16
 
     if (mNumNetRevChans && client) {
-      mProcessPluginsFromNetwork[COMBDSP]->compute(n_frames, mInProcessBuffer.data(), mOutProcessBuffer.data());
+        mProcessPluginsFromNetwork[COMBDSP]->compute(n_frames, mInProcessBuffer.data(),
+                                                     mOutProcessBuffer.data());
     }
     // compute cob16
-#endif // endwhere
+#endif  // endwhere
 
     // 3) Send packets to network:
     // mAudioTesterP will be nullptr for hub server's JackTripWorker instances:
     bool audioTesting = (mAudioTesterP && mAudioTesterP->getEnabled());
-    int nop = mProcessPluginsToNetwork.size(); // number of OUTGOING processing modules
-    if (nop>0 || audioTesting) { // cannot modify in_buffer, so make a copy
-      // in_buffer is "in" from local audio hardware via JACK
-      if (mInBufCopy.size() < mNumInChans) { // created in constructor above
-        std::cerr << "*** AudioInterface.cpp: Number of Input Channels changed - insufficient room reserved\n";
-        exit(1);
-      }
-      if (MAX_AUDIO_BUFFER_SIZE < n_frames) { // allocated in constructor above
-        std::cerr << "*** AudioInterface.cpp: n_frames = " << n_frames
-                  << " larger than expected max = " << MAX_AUDIO_BUFFER_SIZE << "\n";
-        exit(1);
-      }
-      for (int i=0; i<mNumInChans; i++) {
-        std::memcpy(mInBufCopy[i], in_buffer[i], sizeof(sample_t) * n_frames);
-      }
-      for (int i = 0; i < nop; i++) {
-        // process all outgoing channels with ProcessPlugins:
-        ProcessPlugin* p = mProcessPluginsToNetwork[i];
-        if (p->getInited()) {
-          p->compute(n_frames, mInBufCopy.data(), mInBufCopy.data());
+    int nop = mProcessPluginsToNetwork.size();  // number of OUTGOING processing modules
+    if (nop > 0 || audioTesting) {              // cannot modify in_buffer, so make a copy
+        // in_buffer is "in" from local audio hardware via JACK
+        if (mInBufCopy.size() < mNumInChans) {  // created in constructor above
+            std::cerr << "*** AudioInterface.cpp: Number of Input Channels changed - "
+                         "insufficient room reserved\n";
+            exit(1);
+        }
+        if (MAX_AUDIO_BUFFER_SIZE < n_frames) {  // allocated in constructor above
+            std::cerr << "*** AudioInterface.cpp: n_frames = " << n_frames
+                      << " larger than expected max = " << MAX_AUDIO_BUFFER_SIZE << "\n";
+            exit(1);
+        }
+        for (int i = 0; i < mNumInChans; i++) {
+            std::memcpy(mInBufCopy[i], in_buffer[i], sizeof(sample_t) * n_frames);
+        }
+        for (int i = 0; i < nop; i++) {
+            // process all outgoing channels with ProcessPlugins:
+            ProcessPlugin* p = mProcessPluginsToNetwork[i];
+            if (p->getInited()) {
+                p->compute(n_frames, mInBufCopy.data(), mInBufCopy.data());
+            }
+        }
+        if (audioTesting) {
+            mAudioTesterP->writeImpulse(
+                mInBufCopy,
+                n_frames);  // writes last channel of mInBufCopy with test impulse
         }
-      }
-      if (audioTesting) {
-        mAudioTesterP->writeImpulse(mInBufCopy, n_frames); // writes last channel of mInBufCopy with test impulse
-      }
-      computeProcessToNetwork(mInBufCopy, n_frames);
-    } else { // copy saved if no plugins and no audio testing in progress:
-      computeProcessToNetwork(in_buffer, n_frames); // send processed input audio to network - OUTGOING
+        computeProcessToNetwork(mInBufCopy, n_frames);
+    } else {  // copy saved if no plugins and no audio testing in progress:
+        computeProcessToNetwork(
+            in_buffer, n_frames);  // send processed input audio to network - OUTGOING
     }
 
-#ifdef WAIR // WAIR
+#ifdef WAIR  // WAIR
     // aib2 + cob16 to nob16
-#endif // endwhere
+#endif  // endwhere
 
-#ifdef WAIR // WAIR
-    if (mNumNetRevChans) // else not wair, so skip all this
+#ifdef WAIR               // WAIR
+    if (mNumNetRevChans)  // else not wair, so skip all this
     {
-        ///////////////////////////////////////////////////////////////////////////////
 #define AP
 #ifndef AP
         // straight to audio out
@@ -333,13 +315,12 @@ void AudioInterface::callback(QVarLengthArray<sample_t*>& in_buffer,
             std::memset(out_buffer[i], 0, sizeof(sample_t) * n_frames);
         }
         for (int i = 0; i < mNumNetRevChans; i++) {
-            sample_t* mix_sample = out_buffer[i%mNumOutChans];
-            sample_t* tmp_sample = mNetInBuffer[i]; //mNetInBuffer
-            for (int j = 0; j < (int)n_frames; j++) {mix_sample[j] += tmp_sample[j];}
-        }                                         // nib6 to aob2
-        ///////////////////////////////////////////////////////////////////////////////
-#else // AP
-        ///////////////////////////////////////////////////////////////////////////////
+            sample_t* mix_sample = out_buffer[i % mNumOutChans];
+            sample_t* tmp_sample = mNetInBuffer[i];  // mNetInBuffer
+            for (int j = 0; j < (int)n_frames; j++) { mix_sample[j] += tmp_sample[j]; }
+        }  // nib6 to aob2
+#else      // AP
+
         // output through all-pass cascade
         // AP2 is 2 channel, mixes inputs to mono, then splits to two parallel AP chains
         // AP8 is 2 channel, two parallel AP chains
@@ -347,14 +328,15 @@ void AudioInterface::callback(QVarLengthArray<sample_t*>& in_buffer,
             std::memset(mAPInBuffer[i], 0, sizeof(sample_t) * n_frames);
         }
         for (int i = 0; i < mNumNetRevChans; i++) {
-            sample_t* mix_sample = mAPInBuffer[i%mNumOutChans];
+            sample_t* mix_sample = mAPInBuffer[i % mNumOutChans];
             sample_t* tmp_sample = mNetInBuffer[i];
-            for (int j = 0; j < n_frames; j++) {mix_sample[j] += tmp_sample[j];}
-        }                                         // nib16 to apib2
+            for (int j = 0; j < n_frames; j++) { mix_sample[j] += tmp_sample[j]; }
+        }  // nib16 to apib2
         for (int i = 0; i < mNumOutChans; i++) {
             std::memset(out_buffer[i], 0, sizeof(sample_t) * n_frames);
         }
-        mProcessPluginsFromNetwork[APDSP]->compute(n_frames, mAPInBuffer.data(), out_buffer.data());
+        mProcessPluginsFromNetwork[APDSP]->compute(n_frames, mAPInBuffer.data(),
+                                                   out_buffer.data());
         // compute ap2 into aob2
 
         //#define ADD_DIRECT
@@ -362,14 +344,13 @@ void AudioInterface::callback(QVarLengthArray<sample_t*>& in_buffer,
         for (int i = 0; i < mNumInChans; i++) {
             sample_t* mix_sample = out_buffer[i];
             sample_t* tmp_sample = in_buffer[i];
-            for (int j = 0; j < n_frames; j++) {mix_sample[j] += tmp_sample[j];}
+            for (int j = 0; j < n_frames; j++) { mix_sample[j] += tmp_sample[j]; }
         }
         // add aib2 to aob2
-#endif // ADD_DIRECT
-#endif // AP
-        ///////////////////////////////////////////////////////////////////////////////
+#endif  // ADD_DIRECT
+#endif  // AP
     }
-#endif // endwhere
+#endif  // endwhere
 
     ///************PROTOTYPE FOR CELT**************************
     ///********************************************************
@@ -378,37 +359,37 @@ void AudioInterface::callback(QVarLengthArray<sample_t*>& in_buffer,
   int* error;
   mode = celt_mode_create(48000, 2, 64, error);
   */
-    //celt_mode_create(48000, 2, 64, NULL);
-    //unsigned char* compressed;
-    //CELTEncoder* celtEncoder;
-    //celt_encode_float(celtEncoder, mInBuffer, NULL, compressed, );
+    // celt_mode_create(48000, 2, 64, NULL);
+    // unsigned char* compressed;
+    // CELTEncoder* celtEncoder;
+    // celt_encode_float(celtEncoder, mInBuffer, NULL, compressed, );
 
     ///********************************************************
     ///********************************************************
-
 }
 
 //*******************************************************************************
 void AudioInterface::broadcastCallback(QVarLengthArray<sample_t*>& mon_buffer,
-                                               unsigned int n_frames)
+                                       unsigned int n_frames)
 {
     /// \todo cast *mInBuffer[i] to the bit resolution
     // Output Process (from NETWORK to JACK)
     // ----------------------------------------------------------------
     // Read Audio buffer from RingBuffer (read from incoming packets)
-    mJackTrip->receiveBroadcastPacket(mOutputPacket);
-        // Extract separate channels to send to Jack
-        for (int i = 0; i < mNumOutChans; i++) {
-            sample_t* tmp_sample = mon_buffer[i]; //sample buffer for channel i
-            for (unsigned int j = 0; j < n_frames; j++) {
-                // Change the bit resolution on each sample
-                fromBitToSampleConversion(
-                            // use interleaved channel layout
-                            //&mOutputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
-                            &mOutputPacket[(j*mBitResolutionMode*mNumOutChans) + (i*mBitResolutionMode)],
-                        &tmp_sample[j], mBitResolutionMode );
-            }
+    mJackTrip->receiveBroadcastPacket(mAudioOutputPacket);
+    // Extract separate channels to send to Jack
+    for (int i = 0; i < mNumOutChans; i++) {
+        sample_t* tmp_sample = mon_buffer[i];  // sample buffer for channel i
+        for (unsigned int j = 0; j < n_frames; j++) {
+            // Change the bit resolution on each sample
+            fromBitToSampleConversion(
+                // use interleaved channel layout
+                //&mOutputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
+                &mAudioOutputPacket[(j * mBitResolutionMode * mNumOutChans)
+                                    + (i * mBitResolutionMode)],
+                &tmp_sample[j], mBitResolutionMode);
         }
+    }
 }
 
 //*******************************************************************************
@@ -422,45 +403,46 @@ void AudioInterface::computeProcessFromNetwork(QVarLengthArray<sample_t*>& out_b
     // Output Process (from NETWORK to JACK)
     // ----------------------------------------------------------------
     // Read Audio buffer from RingBuffer (read from incoming packets)
-    mJackTrip->receiveNetworkPacket( mOutputPacket );
+    mJackTrip->receiveNetworkPacket(mAudioOutputPacket);
 
-#ifdef WAIR // WAIR
+#ifdef WAIR  // WAIR
     if (mNumNetRevChans)
         // Extract separate channels
         for (int i = 0; i < mNumNetRevChans; i++) {
-            sample_t* tmp_sample = mNetInBuffer[i]; //sample buffer for channel i
+            sample_t* tmp_sample = mNetInBuffer[i];  // sample buffer for channel i
             for (unsigned int j = 0; j < n_frames; j++) {
                 // Change the bit resolution on each sample
                 fromBitToSampleConversion(
-                            // use interleaved channel layout
-                            //&mOutputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
-                            &mOutputPacket[(j*mBitResolutionMode*mNumOutChans) + (i*mBitResolutionMode)],
-                        &tmp_sample[j], mBitResolutionMode );
+                    // use interleaved channel layout
+                    //&mOutputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
+                    &mOutputPacket[(j * mBitResolutionMode * mNumOutChans)
+                                   + (i * mBitResolutionMode)],
+                    &tmp_sample[j], mBitResolutionMode);
             }
         }
-    else // not wair
-#endif // endwhere
+    else  // not wair
+#endif    // endwhere
 
         // Extract separate channels to send to Jack
         for (int i = 0; i < mNumOutChans; i++) {
             //--------
             // This should be faster for 32 bits
-            //std::memcpy(mOutBuffer[i], &mOutputPacket[i*mSizeInBytesPerChannel],
+            // std::memcpy(mOutBuffer[i], &mOutputPacket[i*mSizeInBytesPerChannel],
             //         mSizeInBytesPerChannel);
             //--------
-            sample_t* tmp_sample = out_buffer[i]; //sample buffer for channel i
+            sample_t* tmp_sample = out_buffer[i];  // sample buffer for channel i
             for (unsigned int j = 0; j < n_frames; j++) {
                 // Change the bit resolution on each sample
                 fromBitToSampleConversion(
-                            // use interleaved channel layout
-                            //&mOutputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
-                            &mOutputPacket[(j*mBitResolutionMode*mNumOutChans) + (i*mBitResolutionMode)],
-                        &tmp_sample[j], mBitResolutionMode );
+                    // use interleaved channel layout
+                    //&mOutputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
+                    &mAudioOutputPacket[(j * mBitResolutionMode * mNumOutChans)
+                                        + (i * mBitResolutionMode)],
+                    &tmp_sample[j], mBitResolutionMode);
             }
         }
 }
 
-
 //*******************************************************************************
 void AudioInterface::computeProcessToNetwork(QVarLengthArray<sample_t*>& in_buffer,
                                              unsigned int n_frames)
@@ -469,115 +451,124 @@ void AudioInterface::computeProcessToNetwork(QVarLengthArray<sample_t*>& in_buff
     // ----------------------------------------------------------------
     // Concatenate  all the channels from jack to form packet
 
-#ifdef WAIR // WAIR
+#ifdef WAIR  // WAIR
     if (mNumNetRevChans)
         for (int i = 0; i < mNumNetRevChans; i++) {
-            sample_t* tmp_sample = in_buffer[i%mNumInChans]; //sample buffer for channel i
-            sample_t* tmp_process_sample = mOutProcessBuffer[i]; //sample buffer from the output process
+            sample_t* tmp_sample =
+                in_buffer[i % mNumInChans];  // sample buffer for channel i
+            sample_t* tmp_process_sample =
+                mInProcessBuffer[i];  // sample buffer from the output process
             sample_t tmp_result;
             for (unsigned int j = 0; j < n_frames; j++) {
                 // Change the bit resolution on each sample
-                // Add the input jack buffer to the buffer resulting from the output process
-#define INGAIN (0.9999) // 0.9999 because 1.0 can saturate the fixed pt rounding on output
+                // Add the input jack buffer to the buffer resulting from the output
+                // process
+#define INGAIN \
+    (0.9999)  // 0.9999 because 1.0 can saturate the fixed pt rounding on output
 #define COMBGAIN (1.0)
-                tmp_result = INGAIN*tmp_sample[j] + COMBGAIN*tmp_process_sample[j];
+                tmp_result = INGAIN * tmp_sample[j] + COMBGAIN * tmp_process_sample[j];
                 fromSampleToBitConversion(
-                            &tmp_result,
-                            // use interleaved channel layout
-                            //&mInputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
-                            &mInputPacket[(j*mBitResolutionMode*mNumOutChans) + (i*mBitResolutionMode)],
-                        mBitResolutionMode );
+                    &tmp_result,
+                    // use interleaved channel layout
+                    //&mInputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
+                    &mInputPacket[(j * mBitResolutionMode * mNumOutChans)
+                                  + (i * mBitResolutionMode)],
+                    mBitResolutionMode);
             }
         }
-    else // not wair
-#endif // endwhere
+    else  // not wair
+#endif    // endwhere
 
         for (int i = 0; i < mNumInChans; i++) {
             //--------
             // This should be faster for 32 bits
-            //std::memcpy(&mInputPacket[i*mSizeInBytesPerChannel], mInBuffer[i],
+            // std::memcpy(&mInputPacket[i*mSizeInBytesPerChannel], mInBuffer[i],
             //         mSizeInBytesPerChannel);
             //--------
-            sample_t* tmp_sample = in_buffer[i]; //sample buffer for channel i
-            sample_t* tmp_process_sample = mOutProcessBuffer[i]; //sample buffer from the output process
+            sample_t* tmp_sample = in_buffer[i];  // sample buffer for channel i
+            sample_t* tmp_process_sample =
+                mInProcessBuffer[i];  // sample buffer from the output process
             sample_t tmp_result;
             for (unsigned int j = 0; j < n_frames; j++) {
                 // Change the bit resolution on each sample
-                // Add the input jack buffer to the buffer resulting from the output process
+                // Add the input jack buffer to the buffer resulting from the output
+                // process
                 tmp_result = tmp_sample[j] + tmp_process_sample[j];
                 fromSampleToBitConversion(
-                            &tmp_result,
-                            // use interleaved channel layout
-                            //&mInputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
-                            &mInputPacket[(j*mBitResolutionMode*mNumOutChans) + (i*mBitResolutionMode)],
-                        mBitResolutionMode );
+                    &tmp_result,
+                    // use interleaved channel layout
+                    //&mInputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
+                    &mAudioInputPacket[(j * mBitResolutionMode * mNumInChans)
+                                       + (i * mBitResolutionMode)],
+                    mBitResolutionMode);
             }
         }
     // Send Audio buffer to Network
-    mJackTrip->sendNetworkPacket( mInputPacket );
-} // /computeProcessToNetwork
+    mJackTrip->sendNetworkPacket(mAudioInputPacket);
+}  // /computeProcessToNetwork
 
 //*******************************************************************************
 // This function quantize from 32 bit to a lower bit resolution
 // 24 bit is not working yet
-void AudioInterface::fromSampleToBitConversion
-(const sample_t* const input,
- int8_t* output,
- const AudioInterface::audioBitResolutionT targetBitResolution)
+void AudioInterface::fromSampleToBitConversion(
+    const sample_t* const input, int8_t* output,
+    const AudioInterface::audioBitResolutionT targetBitResolution)
 {
     int8_t tmp_8;
-    uint8_t tmp_u8; // unsigned to quantize the remainder in 24bits
+    uint8_t tmp_u8;  // unsigned to quantize the remainder in 24bits
     int16_t tmp_16;
     double tmp_sample;
     sample_t tmp_sample16;
     sample_t tmp_sample8;
-    switch (targetBitResolution)
-    {
-    case BIT8 :
+    switch (targetBitResolution) {
+    case BIT8:
         // 8bit integer between -128 to 127
-        tmp_sample = std::max(-127.0, std::min(127.0, std::round( (*input) * 127.0 ))); // 2^7 = 128
+        tmp_sample =
+            std::max(-127.0, std::min(127.0, std::round((*input) * 127.0)));  // 2^7 = 128
         tmp_8 = static_cast<int8_t>(tmp_sample);
-        std::memcpy(output, &tmp_8, 1); // 8bits = 1 bytes
+        std::memcpy(output, &tmp_8, 1);  // 8bits = 1 bytes
         break;
-    case BIT16 :
+    case BIT16:
         // 16bit integer between -32768 to 32767
         // original scaling: tmp_sample = floor( (*input) * 32768.0 ); // 2^15 = 32768.0
-        tmp_sample = std::max(-32767.0, std::min(32767.0, std::round( (*input) * 32767.0 ))); // 2^15 = 32768
+        tmp_sample = std::max(
+            -32767.0, std::min(32767.0, std::round((*input) * 32767.0)));  // 2^15 = 32768
         tmp_16 = static_cast<int16_t>(tmp_sample);
-        std::memcpy(output, &tmp_16, 2); // 2 bytes output in Little Endian order (LSB -> smallest address)
+        std::memcpy(
+            output, &tmp_16,
+            2);  // 2 bytes output in Little Endian order (LSB -> smallest address)
         break;
-    case BIT24 :
+    case BIT24:
         // To convert to 24 bits, we first quantize the number to 16bit
-        tmp_sample = (*input) * 32768.0; // 2^15 = 32768.0
+        tmp_sample   = (*input) * 32768.0;  // 2^15 = 32768.0
         tmp_sample16 = floor(tmp_sample);
-        tmp_16 = static_cast<int16_t>(tmp_sample16);
+        tmp_16       = static_cast<int16_t>(tmp_sample16);
 
         // Then we compute the remainder error, and quantize that part into an 8bit number
         // Note that this remainder is always positive, so we use an unsigned integer
-        tmp_sample8 = floor ((tmp_sample - tmp_sample16)  //this is a positive number, between 0.0-1.0
-                             * 256.0);
+        tmp_sample8 = floor(
+            (tmp_sample - tmp_sample16)  // this is a positive number, between 0.0-1.0
+            * 256.0);
         tmp_u8 = static_cast<uint8_t>(tmp_sample8);
 
         // Finally, we copy the 16bit number in the first 2 bytes,
         // and the 8bit number in the third bite
-        std::memcpy(output, &tmp_16, 2); // 16bits = 2 bytes
-        std::memcpy(output+2, &tmp_u8, 1); // 8bits = 1 bytes
+        std::memcpy(output, &tmp_16, 2);      // 16bits = 2 bytes
+        std::memcpy(output + 2, &tmp_u8, 1);  // 8bits = 1 bytes
         break;
-    case BIT32 :
+    case BIT32:
         tmp_sample = *input;
         // not necessary yet:
         // tmp_sample = std::max(-1.0, std::min(1.0, tmp_sample));
-        std::memcpy(output, &tmp_sample, 4); // 32bit = 4 bytes
+        std::memcpy(output, &tmp_sample, 4);  // 32bit = 4 bytes
         break;
     }
 }
 
-
 //*******************************************************************************
-void AudioInterface::fromBitToSampleConversion
-(const int8_t* const input,
- sample_t* output,
- const AudioInterface::audioBitResolutionT sourceBitResolution)
+void AudioInterface::fromBitToSampleConversion(
+    const int8_t* const input, sample_t* output,
+    const AudioInterface::audioBitResolutionT sourceBitResolution)
 {
     int8_t tmp_8;
     uint8_t tmp_u8;
@@ -585,82 +576,82 @@ void AudioInterface::fromBitToSampleConversion
     sample_t tmp_sample;
     sample_t tmp_sample16;
     sample_t tmp_sample8;
-    switch (sourceBitResolution)
-    {
-    case BIT8 :
-        tmp_8 = *input;
+    switch (sourceBitResolution) {
+    case BIT8:
+        tmp_8      = *input;
         tmp_sample = static_cast<sample_t>(tmp_8) / 128.0;
-        std::memcpy(output, &tmp_sample, 4); // 4 bytes
+        std::memcpy(output, &tmp_sample, 4);  // 4 bytes
         break;
-    case BIT16 :
-        tmp_16 = *( reinterpret_cast<const int16_t*>(input) ); // *((int16_t*) input);
+    case BIT16:
+        tmp_16     = *(reinterpret_cast<const int16_t*>(input));  // *((int16_t*) input);
         tmp_sample = static_cast<sample_t>(tmp_16) / 32768.0;
-        std::memcpy(output, &tmp_sample, 4); // 4 bytes
+        std::memcpy(output, &tmp_sample, 4);  // 4 bytes
         break;
-    case BIT24 :
+    case BIT24:
         // We first extract the 16bit and 8bit number from the 3 bytes
-        tmp_16 = *( reinterpret_cast<const int16_t*>(input) );
-        tmp_u8 = *( reinterpret_cast<const uint8_t*>(input+2) );
+        tmp_16 = *(reinterpret_cast<const int16_t*>(input));
+        tmp_u8 = *(reinterpret_cast<const uint8_t*>(input + 2));
 
         // Then we recover the number
         tmp_sample16 = static_cast<sample_t>(tmp_16);
-        tmp_sample8 = static_cast<sample_t>(tmp_u8) / 256.0;
-        tmp_sample =  (tmp_sample16 +  tmp_sample8) / 32768.0;
-        std::memcpy(output, &tmp_sample, 4); // 4 bytes
+        tmp_sample8  = static_cast<sample_t>(tmp_u8) / 256.0;
+        tmp_sample   = (tmp_sample16 + tmp_sample8) / 32768.0;
+        std::memcpy(output, &tmp_sample, 4);  // 4 bytes
         break;
-    case BIT32 :
-        std::memcpy(output, input, 4); // 4 bytes
+    case BIT32:
+        std::memcpy(output, input, 4);  // 4 bytes
         break;
     }
 }
 
-
 //*******************************************************************************
 void AudioInterface::appendProcessPluginToNetwork(ProcessPlugin* plugin)
 {
-  if (not plugin) { return; }
-  int nTestChans = (mAudioTesterP && mAudioTesterP->getEnabled()) ? 1 : 0;
-  int nPluginChans = mNumInChans - nTestChans;
-  assert(nTestChans==0 || (mAudioTesterP->getSendChannel() == mNumInChans-1));
-  if (plugin->getNumInputs() < nPluginChans) {
-    std::cerr << "*** AudioInterface.cpp: appendProcessPluginToNetwork: ProcessPlugin "
-              << typeid(plugin).name() << " REJECTED due to having "
-              << plugin->getNumInputs() << " inputs, while the audio to JACK needs "
-              << nPluginChans << " inputs\n";
-    return;
-  }
-  mProcessPluginsToNetwork.append(plugin);
+    if (not plugin) { return; }
+    int nTestChans   = (mAudioTesterP && mAudioTesterP->getEnabled()) ? 1 : 0;
+    int nPluginChans = mNumInChans - nTestChans;
+    assert(nTestChans == 0 || (mAudioTesterP->getSendChannel() == mNumInChans - 1));
+    if (plugin->getNumInputs() < nPluginChans) {
+        std::cerr
+            << "*** AudioInterface.cpp: appendProcessPluginToNetwork: ProcessPlugin "
+            << typeid(plugin).name() << " REJECTED due to having "
+            << plugin->getNumInputs() << " inputs, while the audio to JACK needs "
+            << nPluginChans << " inputs\n";
+        return;
+    }
+    mProcessPluginsToNetwork.append(plugin);
 }
 
 void AudioInterface::appendProcessPluginFromNetwork(ProcessPlugin* plugin)
 {
-  if (not plugin) { return; }
-  int nTestChans = (mAudioTesterP && mAudioTesterP->getEnabled()) ? 1 : 0;
-  int nPluginChans = mNumOutChans - nTestChans;
-  assert(nTestChans==0 || (mAudioTesterP->getSendChannel() == mNumOutChans-1));
-  if (plugin->getNumOutputs() > nPluginChans) {
-    std::cerr << "*** AudioInterface.cpp: appendProcessPluginFromNetwork: ProcessPlugin "
-              << typeid(plugin).name() << " REJECTED due to having "
-              << plugin->getNumOutputs() << " inputs, while the JACK audio output requires "
-              << nPluginChans << " outputs\n";
-    return;
-  }
-  mProcessPluginsFromNetwork.append(plugin);
+    if (not plugin) { return; }
+    int nTestChans   = (mAudioTesterP && mAudioTesterP->getEnabled()) ? 1 : 0;
+    int nPluginChans = mNumOutChans - nTestChans;
+    assert(nTestChans == 0 || (mAudioTesterP->getSendChannel() == mNumOutChans - 1));
+    if (plugin->getNumOutputs() > nPluginChans) {
+        std::cerr
+            << "*** AudioInterface.cpp: appendProcessPluginFromNetwork: ProcessPlugin "
+            << typeid(plugin).name() << " REJECTED due to having "
+            << plugin->getNumOutputs() << " inputs, while the JACK audio output requires "
+            << nPluginChans << " outputs\n";
+        return;
+    }
+    mProcessPluginsFromNetwork.append(plugin);
 }
 
 void AudioInterface::initPlugins()
 {
-  int nPlugins = mProcessPluginsFromNetwork.size() + mProcessPluginsToNetwork.size();
-  if (nPlugins > 0) {
-    std::cout << "Initializing Faust plugins (have " << nPlugins
-              << ") at sampling rate " << mSampleRate << "\n";
-    for (ProcessPlugin* plugin : mProcessPluginsFromNetwork) {
-      plugin->init(mSampleRate);
-    }
-    for (ProcessPlugin* plugin : mProcessPluginsToNetwork) {
-      plugin->init(mSampleRate);
+    int nPlugins = mProcessPluginsFromNetwork.size() + mProcessPluginsToNetwork.size();
+    if (nPlugins > 0) {
+        std::cout << "Initializing Faust plugins (have " << nPlugins
+                  << ") at sampling rate " << mSampleRate << "\n";
+        for (ProcessPlugin* plugin : qAsConst(mProcessPluginsFromNetwork)) {
+            plugin->init(mSampleRate);
+        }
+        for (ProcessPlugin* plugin : qAsConst(mProcessPluginsToNetwork)) {
+            plugin->init(mSampleRate);
+        }
     }
-  }
 }
 
 //*******************************************************************************
@@ -668,20 +659,21 @@ AudioInterface::samplingRateT AudioInterface::getSampleRateType() const
 {
     int32_t rate = getSampleRate();
 
-    if      ( 100 > qAbs(rate - 22050) ) {
-        return AudioInterface::SR22; }
-    else if ( 100 > qAbs(rate - 32000) ) {
-        return AudioInterface::SR32; }
-    else if ( 100 > qAbs(rate - 44100) ) {
-        return AudioInterface::SR44; }
-    else if ( 100 > qAbs(rate - 48000) ) {
-        return AudioInterface::SR48; }
-    else if ( 100 > qAbs(rate - 88200) ) {
-        return AudioInterface::SR88; }
-    else if ( 100 > qAbs(rate - 96000) ) {
-        return AudioInterface::SR96; }
-    else if ( 100 > qAbs(rate - 19200) ) {
-        return AudioInterface::SR192; }
+    if (100 > qAbs(rate - 22050)) {
+        return AudioInterface::SR22;
+    } else if (100 > qAbs(rate - 32000)) {
+        return AudioInterface::SR32;
+    } else if (100 > qAbs(rate - 44100)) {
+        return AudioInterface::SR44;
+    } else if (100 > qAbs(rate - 48000)) {
+        return AudioInterface::SR48;
+    } else if (100 > qAbs(rate - 88200)) {
+        return AudioInterface::SR88;
+    } else if (100 > qAbs(rate - 96000)) {
+        return AudioInterface::SR96;
+    } else if (100 > qAbs(rate - 19200)) {
+        return AudioInterface::SR192;
+    }
 
     return AudioInterface::UNDEF;
 }
@@ -690,33 +682,32 @@ AudioInterface::samplingRateT AudioInterface::getSampleRateType() const
 int AudioInterface::getSampleRateFromType(samplingRateT rate_type)
 {
     int sample_rate = 0;
-    switch (rate_type)
-    {
-    case SR22 :
+    switch (rate_type) {
+    case SR22:
         sample_rate = 22050;
         return sample_rate;
         break;
-    case SR32 :
+    case SR32:
         sample_rate = 32000;
         return sample_rate;
         break;
-    case SR44 :
+    case SR44:
         sample_rate = 44100;
         return sample_rate;
         break;
-    case SR48 :
+    case SR48:
         sample_rate = 48000;
         return sample_rate;
         break;
-    case SR88 :
+    case SR88:
         sample_rate = 88200;
         return sample_rate;
         break;
-    case SR96 :
+    case SR96:
         sample_rate = 96000;
         return sample_rate;
         break;
-    case SR192 :
+    case SR192:
         sample_rate = 192000;
         return sample_rate;
         break;
index f5089ebe593378264e1615e83d456c7d4f1d8b72..7885e4c19c4c4d35f50ae9f4fdd622fc333b7fb4 100644 (file)
 #ifndef __AUDIOINTERFACE_H__
 #define __AUDIOINTERFACE_H__
 
-#include "ProcessPlugin.h"
-#include "jacktrip_types.h"
-#include "AudioTester.h"
-
 #include <QVarLengthArray>
 #include <QVector>
+
+#include "AudioTester.h"
+#include "ProcessPlugin.h"
+#include "jacktrip_types.h"
 //#include "jacktrip_globals.h"
 
 // Forward declarations
 class JackTrip;
 
-//using namespace JackTripNamespace;
-
+// using namespace JackTripNamespace;
 
 /** \brief Base Class that provides an interface with audio
  */
 class AudioInterface
 {
-public:
-
+   public:
     /// \brief Enum for Audio Resolution in bits
     enum audioBitResolutionT {
-        BIT8  = 1, ///< 8 bits
-        BIT16 = 2, ///< 16 bits (default)
-        BIT24 = 3, ///< 24 bits
-        BIT32 = 4  ///< 32 bits
+        BIT8  = 1,  ///< 8 bits
+        BIT16 = 2,  ///< 16 bits (default)
+        BIT24 = 3,  ///< 24 bits
+        BIT32 = 4   ///< 32 bits
     };
 
     /// \brief Sampling Rates supported by JACK
     enum samplingRateT {
-        SR22, ///<  22050 Hz
-        SR32, ///<  32000 Hz
-        SR44, ///<  44100 Hz
-        SR48, ///<  48000 Hz
-        SR88, ///<  88200 Hz
-        SR96, ///<  96000 Hz
-        SR192, ///< 192000 Hz
-        UNDEF ///< Undefined
+        SR22,   ///<  22050 Hz
+        SR32,   ///<  32000 Hz
+        SR44,   ///<  44100 Hz
+        SR48,   ///<  48000 Hz
+        SR88,   ///<  88200 Hz
+        SR96,   ///<  96000 Hz
+        SR192,  ///< 192000 Hz
+        UNDEF   ///< Undefined
     };
 
     /** \brief The class constructor
-   * \param jacktrip Pointer to the JackTrip class that connects all classes (mediator)
-   * \param NumInChans Number of Input Channels
-   * \param NumOutChans Number of Output Channels
-   * \param AudioBitResolution Audio Sample Resolutions in bits
-   */
-    AudioInterface(JackTrip* jacktrip,
-                   int NumInChans, int NumOutChans,
-               #ifdef WAIR // wair
-                   int NumNetRevChans,
-               #endif // endwhere
-                   AudioInterface::audioBitResolutionT AudioBitResolution =
-            AudioInterface::BIT16);
+     * \param jacktrip Pointer to the JackTrip class that connects all classes (mediator)
+     * \param NumInChans Number of Input Channels
+     * \param NumOutChans Number of Output Channels
+     * \param AudioBitResolution Audio Sample Resolutions in bits
+     */
+    AudioInterface(
+        JackTrip* jacktrip, int NumInChans, int NumOutChans,
+#ifdef WAIR  // wair
+        int NumNetRevChans,
+#endif  // endwhere
+        AudioInterface::audioBitResolutionT AudioBitResolution = AudioInterface::BIT16);
     /// \brief The class destructor
     virtual ~AudioInterface();
 
     /** \brief Setup the client. This function should be called just before
-    *
-    * starting the audio processes, it will setup the audio client with
-    * the class parameters, like Sampling Rate,
-    * Packet Size, Bit Resolution, etc... Sub-classes should also call the parent
-    * method to ensure correct inizialization.
-    */
+     *
+     * starting the audio processes, it will setup the audio client with
+     * the class parameters, like Sampling Rate,
+     * Packet Size, Bit Resolution, etc... Sub-classes should also call the parent
+     * method to ensure correct inizialization.
+     */
     virtual void setup();
     /// \brief Tell the audio server that we are ready to roll. The
     /// process-callback will start running. This runs on its own thread.
@@ -117,65 +114,71 @@ public:
     * is reponsible to check that each channel has n_frames samplers
     */
     virtual void broadcastCallback(QVarLengthArray<sample_t*>& mon_buffer,
-                          unsigned int n_frames);
+                                   unsigned int n_frames);
     virtual void callback(QVarLengthArray<sample_t*>& in_buffer,
-                          QVarLengthArray<sample_t*>& out_buffer,
-                          unsigned int n_frames);
-   /** \brief appendProcessPluginToNetwork(): Append a ProcessPlugin for outgoing audio. 
-   * The processing order equals order they were appended.
-   * This processing is in the JackTrip client before sending to the network.
-   * \param plugin a ProcessPlugin smart pointer. Create the object instance
-   * using something like:\n
-   * <tt>std::tr1::shared_ptr<ProcessPluginName> loopback(new ProcessPluginName);</tt>
-   */
+                          QVarLengthArray<sample_t*>& out_buffer, unsigned int n_frames);
+    /** \brief appendProcessPluginToNetwork(): Append a ProcessPlugin for outgoing audio.
+     * The processing order equals order they were appended.
+     * This processing is in the JackTrip client before sending to the network.
+     * \param plugin a ProcessPlugin smart pointer. Create the object instance
+     * using something like:\n
+     * <tt>std::tr1::shared_ptr<ProcessPluginName> loopback(new ProcessPluginName);</tt>
+     */
     virtual void appendProcessPluginToNetwork(ProcessPlugin* plugin);
-   /** \brief appendProcessPluginFromNetwork():
-   * Same as appendProcessPluginToNetwork() except that these plugins operate
-   * on the audio received from the network (typically from a JackTrip server).
-   * The complete processing chain then looks like this:
-   * audio -> JACK -> JackTrip client -> processPlugin to network
-   *               -> remote JackTrip server
-   *               -> JackTrip client -> processPlugin from network -> JACK -> audio
-   */
+    /** \brief appendProcessPluginFromNetwork():
+     * Same as appendProcessPluginToNetwork() except that these plugins operate
+     * on the audio received from the network (typically from a JackTrip server).
+     * The complete processing chain then looks like this:
+     * audio -> JACK -> JackTrip client -> processPlugin to network
+     *               -> remote JackTrip server
+     *               -> JackTrip client -> processPlugin from network -> JACK -> audio
+     */
     virtual void appendProcessPluginFromNetwork(ProcessPlugin* plugin);
-   /** \brief initPlugins():
-   * Initialize all ProcessPlugin modules.
-   * The audio sampling rate (mSampleRate) must be set at this time.
-   */
+    /** \brief initPlugins():
+     * Initialize all ProcessPlugin modules.
+     * The audio sampling rate (mSampleRate) must be set at this time.
+     */
     void initPlugins();
     virtual void connectDefaultPorts() = 0;
     /** \brief Convert a 32bit number (sample_t) into one of the bit resolution
-   * supported (audioBitResolutionT).
-   *
-   * The result is stored in an int_8 array of the
-   * appropriate size to hold the value. The caller is responsible to allocate
-   * enough space to store the result.
-   */
-    static void fromSampleToBitConversion(const sample_t* const input,
-                                          int8_t* output,
-                                          const AudioInterface::audioBitResolutionT targetBitResolution);
+     * supported (audioBitResolutionT).
+     *
+     * The result is stored in an int_8 array of the
+     * appropriate size to hold the value. The caller is responsible to allocate
+     * enough space to store the result.
+     */
+    static void fromSampleToBitConversion(
+        const sample_t* const input, int8_t* output,
+        const AudioInterface::audioBitResolutionT targetBitResolution);
     /** \brief Convert a audioBitResolutionT bit resolution number into a
-   * 32bit number (sample_t)
-   *
-   * The result is stored in an sample_t array of the
-   * appropriate size to hold the value. The caller is responsible to allocate
-   * enough space to store the result.
-   */
-    static void fromBitToSampleConversion(const int8_t* const input,
-                                          sample_t* output,
-                                          const AudioInterface::audioBitResolutionT sourceBitResolution);
+     * 32bit number (sample_t)
+     *
+     * The result is stored in an sample_t array of the
+     * appropriate size to hold the value. The caller is responsible to allocate
+     * enough space to store the result.
+     */
+    static void fromBitToSampleConversion(
+        const int8_t* const input, sample_t* output,
+        const AudioInterface::audioBitResolutionT sourceBitResolution);
 
     //--------------SETTERS---------------------------------------------
-    virtual void setNumInputChannels(int nchannels)
-    { mNumInChans = nchannels; }
-    virtual void setNumOutputChannels(int nchannels)
-    { mNumOutChans = nchannels; }
-    virtual void setSampleRate(uint32_t sample_rate)
-    { mSampleRate = sample_rate; }
-    virtual void setDeviceID(uint32_t device_id)
-    { mDeviceID = device_id; }
+    virtual void setNumInputChannels(int nchannels) { mNumInChans = nchannels; }
+    virtual void setNumOutputChannels(int nchannels) { mNumOutChans = nchannels; }
+    virtual void setSampleRate(uint32_t sample_rate) { mSampleRate = sample_rate; }
+    virtual void setBufferSize(uint32_t buffersize) { mBufferSizeInSamples = buffersize; }
+    virtual void setDeviceID(uint32_t device_id) { mDeviceID = device_id; }
+    virtual void setInputDevice(std::string device_name)
+    {
+        mInputDeviceName = device_name;
+    }
+    virtual void setOutputDevice(std::string device_name)
+    {
+        mOutputDeviceName = device_name;
+    }
     virtual void setBufferSizeInSamples(uint32_t buf_size)
-    { mBufferSizeInSamples = buf_size; }
+    {
+        mBufferSizeInSamples = buf_size;
+    }
     /// \brief Set Client Name to something different that the default (JackTrip)
     virtual void setClientName(QString ClientName) = 0;
     virtual void setLoopBack(bool b) { mLoopBack = b; }
@@ -187,34 +190,31 @@ public:
     /// \brief Get Number of Input Channels
     virtual int getNumInputChannels() const { return mNumInChans; }
     /// \brief Get Number of Output Channels
-    virtual int getNumOutputChannels() const  { return mNumOutChans; }
-    virtual uint32_t getBufferSizeInSamples() const
-    { return mBufferSizeInSamples; }
-    virtual uint32_t getDeviceID() const
-    { return mDeviceID; }
+    virtual int getNumOutputChannels() const { return mNumOutChans; }
+    virtual uint32_t getBufferSizeInSamples() const { return mBufferSizeInSamples; }
+    virtual uint32_t getDeviceID() const { return mDeviceID; }
+    virtual std::string getInputDevice() const { return mInputDeviceName; }
+    virtual std::string getOutputDevice() const { return mOutputDeviceName; }
     virtual size_t getSizeInBytesPerChannel() const;
     /// \brief Get the Jack Server Sampling Rate, in samples/second
-    virtual uint32_t getSampleRate() const
-    { return mSampleRate; }
+    virtual uint32_t getSampleRate() const { return mSampleRate; }
     /// \brief Get the Jack Server Sampling Rate Enum Type samplingRateT
     /// \return  AudioInterface::samplingRateT enum type
     virtual samplingRateT getSampleRateType() const;
     /** \brief Get the Audio Bit Resolution, in bits
-   *
-   * This is one of the audioBitResolutionT set in construction
-   */
+     *
+     * This is one of the audioBitResolutionT set in construction
+     */
     virtual int getAudioBitResolution() const { return mAudioBitResolution; }
     /** \brief Helper function to get the sample rate (in Hz) for a
-   * JackAudioInterface::samplingRateT
-   * \param rate_type  JackAudioInterface::samplingRateT enum type
-   * \return Sample Rate in Hz
-   */
+     * JackAudioInterface::samplingRateT
+     * \param rate_type  JackAudioInterface::samplingRateT enum type
+     * \return Sample Rate in Hz
+     */
     static int getSampleRateFromType(samplingRateT rate_type);
     //------------------------------------------------------------------
 
-
-private:
-
+   private:
     /// \brief Compute the process to receive packets
     void computeProcessFromNetwork(QVarLengthArray<sample_t*>& out_buffer,
                                    unsigned int n_frames);
@@ -222,32 +222,44 @@ private:
     void computeProcessToNetwork(QVarLengthArray<sample_t*>& in_buffer,
                                  unsigned int n_frames);
 
-    JackTrip* mJackTrip; ///< JackTrip Mediator Class pointer
-    int mNumInChans;///< Number of Input Channels
-    int mNumOutChans; ///<  Number of Output Channels
-#ifdef WAIR // wair
-    int mNumNetRevChans; ///<  Number of Network Audio Channels (net comb filters)
-    QVarLengthArray<sample_t*> mNetInBuffer; ///< Vector of Input buffers/channel read from net
-    QVarLengthArray<sample_t*> mAPInBuffer; ///< Vector of Input buffers/channel for AllPass input
-#endif // endwhere
-    QVarLengthArray<sample_t*> mInBufCopy; ///< needed in callback() to modify JACK audio input
-    int mAudioBitResolution; ///< Bit resolution in audio samples
-    AudioInterface::audioBitResolutionT mBitResolutionMode; ///< Bit resolution (audioBitResolutionT) mode
-    uint32_t mSampleRate; ///< Sampling Rate
-    uint32_t mDeviceID; ///< RTAudio DeviceID
-    uint32_t mBufferSizeInSamples; ///< Buffer size in samples
-    size_t mSizeInBytesPerChannel; ///< Size in bytes per audio channel
-    QVector<ProcessPlugin*> mProcessPluginsFromNetwork; ///< Vector of ProcessPlugin<EM>s</EM>
-    QVector<ProcessPlugin*> mProcessPluginsToNetwork; ///< Vector of ProcessPlugin<EM>s</EM>
-    QVarLengthArray<sample_t*> mInProcessBuffer;///< Vector of Input buffers/channel for ProcessPlugin
-    QVarLengthArray<sample_t*> mOutProcessBuffer;///< Vector of Output buffers/channel for ProcessPlugin
-    int8_t* mInputPacket; ///< Packet containing all the channels to read from the RingBuffer
-    int8_t* mOutputPacket;  ///< Packet containing all the channels to send to the RingBuffer
+    JackTrip* mJackTrip;  ///< JackTrip Mediator Class pointer
+    int mNumInChans;      ///< Number of Input Channels
+    int mNumOutChans;     ///<  Number of Output Channels
+#ifdef WAIR               // wair
+    int mNumNetRevChans;  ///<  Number of Network Audio Channels (net comb filters)
+    QVarLengthArray<sample_t*>
+        mNetInBuffer;  ///< Vector of Input buffers/channel read from net
+    QVarLengthArray<sample_t*>
+        mAPInBuffer;  ///< Vector of Input buffers/channel for AllPass input
+#endif                // endwhere
+    QVarLengthArray<sample_t*>
+        mInBufCopy;           ///< needed in callback() to modify JACK audio input
+    int mAudioBitResolution;  ///< Bit resolution in audio samples
+    AudioInterface::audioBitResolutionT
+        mBitResolutionMode;  ///< Bit resolution (audioBitResolutionT) mode
+    uint32_t mSampleRate;    ///< Sampling Rate
+    uint32_t mDeviceID;      ///< RTAudio DeviceID
+    std::string mInputDeviceName, mOutputDeviceName;  ///< RTAudio device names
+    uint32_t mBufferSizeInSamples;                    ///< Buffer size in samples
+    size_t mSizeInBytesPerChannel;                    ///< Size in bytes per audio channel
+    QVector<ProcessPlugin*>
+        mProcessPluginsFromNetwork;  ///< Vector of ProcessPlugin<EM>s</EM>
+    QVector<ProcessPlugin*>
+        mProcessPluginsToNetwork;  ///< Vector of ProcessPlugin<EM>s</EM>
+    QVarLengthArray<sample_t*>
+        mInProcessBuffer;  ///< Vector of Input buffers/channel for ProcessPlugin
+    QVarLengthArray<sample_t*>
+        mOutProcessBuffer;       ///< Vector of Output buffers/channel for ProcessPlugin
+    int8_t* mAudioInputPacket;   ///< Packet containing all the channels to read from the
+                                 ///< RingBuffer
+    int8_t* mAudioOutputPacket;  ///< Packet containing all the channels to send to the
+                                 ///< RingBuffer
     bool mLoopBack;
-    AudioTester* mAudioTesterP { nullptr };
-protected:
+    AudioTester* mAudioTesterP{nullptr};
+
+   protected:
     bool mProcessingAudio;  ///< Set when processing an audio callback buffer pair
     const uint32_t MAX_AUDIO_BUFFER_SIZE = 8192;
 };
 
-#endif // __AUDIOINTERFACE_H__
+#endif  // __AUDIOINTERFACE_H__
index 136c1d40e0862bf66b608c0f19a5fa16be550f46..85bf867a486c2bab8265fdae6405b39e872a6e37 100644 (file)
  */
 
 #include "AudioTester.h"
-#include <assert.h>
+
+#include <cassert>
 
 // Called 1st in Audiointerface.cpp
 void AudioTester::lookForReturnPulse(QVarLengthArray<sample_t*>& out_buffer,
-                                     unsigned int n_frames) {
-  if (not enabled) {
-    std::cerr << "*** AudioTester.h: lookForReturnPulse: NOT ENABLED\n";
-    return;
-  }
-  if (impulsePending) { // look for return impulse in channel sendChannel:
-    assert(sendChannel<out_buffer.size());
-    for (uint n=0; n<n_frames; n++) {
-      float amp = out_buffer[sendChannel][n];
-      if (amp > 0.5 * ampCellHeight) { // got something
-        int cellNum =  getImpulseCellNum(out_buffer[sendChannel][n]);
-        if (cellNum != pendingCell) { // not our impulse!
-          std::cerr <<
-            "*** AudioTester.h: computeProcessFromNetwork: Received pulse amplitude "
-                    << amp << " (cell " << cellNum << ") while looking for cell "
-                    << pendingCell << "\n";
+                                     unsigned int n_frames)
+{
+    if (not enabled) {
+        std::cerr << "*** AudioTester.h: lookForReturnPulse: NOT ENABLED\n";
+        return;
+    }
+    if (impulsePending) {  // look for return impulse in channel sendChannel:
+        assert(sendChannel < out_buffer.size());
+        for (uint n = 0; n < n_frames; n++) {
+            float amp = out_buffer[sendChannel][n];
+            if (amp > 0.5 * ampCellHeight) {  // got something
+                int cellNum = getImpulseCellNum(out_buffer[sendChannel][n]);
+                if (cellNum != pendingCell) {  // not our impulse!
+                    std::cerr << "*** AudioTester.h: computeProcessFromNetwork: Received "
+                                 "pulse amplitude "
+                              << amp << " (cell " << cellNum
+                              << ") while looking for cell " << pendingCell << "\n";
 
-          if (cellNum > pendingCell) { // we missed it
-            std::cerr << " - ABORTING CURRENT PULSE\n";
-            impulsePending = false;
-          } else { // somehow we got the previous pulse again - repeated packet or underrun-caused repetition (old buffer)
-            std::cerr << " - IGNORING FOUND PULSE WAITING FURTHER\n";
-          }
-        } else { // found our impulse:
-          int64_t elapsedSamples = -1;
-          if (n >= n_frames-1) {
-            // Impulse timestamp didn't make it so we skip this one.
-          } else {
-            float sampleCountWhenImpulseSent = - 32768.0f * out_buffer[sendChannel][n+1];
-            elapsedSamples = sampleCountSinceImpulse + n - int64_t(sampleCountWhenImpulseSent);
-            sampleCountSinceImpulse = 1; // reset sample counter between impulses
-            roundTripCount += 1.0;
-          }
-          // int64_t curTimeUS = timeMicroSec(); // time since launch in us
-          // int64_t impulseDelayUS = curTimeUS - ImpulseTimeUS;
-          // float impulseDelaySec = float(impulseDelayUS) * 1.0e-6;
-          // float impulseDelayBuffers = impulseDelaySec / (float(n_frames)/float(sampleRate));
-          // int64_t impulseDelayMS = (int64_t)round(double(impulseDelayUS)/1000.0);
-          if (elapsedSamples > 0) { // found impulse and reset, time to print buffer results:
-            double elapsedSamplesMS = 1000.0 * double(elapsedSamples)/double(sampleRate); // ms
-            extendLatencyHistogram(elapsedSamplesMS);
-            if (roundTripCount > 1.0) {
-              double prevSum = roundTripMean * (roundTripCount-1.0); // undo previous normalization
-              roundTripMean = (prevSum + elapsedSamplesMS) / roundTripCount; // add latest and renormalize
-              double prevSumSq = roundTripMeanSquare * (roundTripCount-1.0); // undo previous normalization
-              roundTripMeanSquare = (prevSumSq + elapsedSamplesMS*elapsedSamplesMS) / roundTripCount;
-            } else { // just getting started:
-              roundTripMean = elapsedSamplesMS;
-              roundTripMeanSquare = elapsedSamplesMS * elapsedSamplesMS;
-            }
-            if (roundTripCount == 1.0) {
-              printf("JackTrip Test Mode (option -x printIntervalInSeconds=%0.3f)\n",printIntervalSec);
-              printf("\tA test impulse-train is output on channel %d (from 0) with repeatedly ramping amplitude\n",
-                     sendChannel);
-              if (printIntervalSec == 0.0) {
-                printf("\tPrinting each audio buffer round-trip latency in ms followed by cumulative (mean and [standard deviation])");
-              } else {
-                printf("\tPrinting cumulative mean and [standard deviation] of audio round-trip latency in ms");
-                printf(" every %0.3f seconds", printIntervalSec);
-              }
-              printf(" after skipping first %d buffers:\n", bufferSkipStart);
-              // not printing this presently: printf("( * means buffer skipped due missing timestamp or lost impulse)\n");
-              lastPrintTimeUS = timeMicroSec();
-            }
-            //printf("%d (%d) ", elapsedSamplesMS, impulseDelayMS); // measured time is "buffer time" not sample time
-            int64_t curTimeUS = timeMicroSec(); // time since launch in us
-            double timeSinceLastPrintUS = double(curTimeUS - lastPrintTimeUS);
-            double stdDev = sqrt(std::max(0.0, (roundTripMeanSquare - (roundTripMean*roundTripMean))));
-            if (timeSinceLastPrintUS >= printIntervalSec * 1.0e6) {
-              if (printIntervalSec == 0.0) { printf("%0.1f (", elapsedSamplesMS); }
-              printf("%0.1f [%0.1f]", roundTripMean, stdDev);
-              if (printIntervalSec == 0.0) { printf(") "); } else { printf(" "); }
-              lastPrintTimeUS = curTimeUS;
-              if (printIntervalSec >= 1.0) { // print histogram
-                std::cout << "\n" << getLatencyHistogramString() << "\n";
-              }
-            }
-            std::cout << std::flush;
-          } else {
-            // not printing this presently: printf("* "); // we got the impulse but lost its timestamp in samples
-          }
-          impulsePending = false;
-        } // found our impulse
-          // remain pending until timeout, hoping to find our return pulse
-      } // got something
-    } // loop over samples
-    sampleCountSinceImpulse += n_frames; // gets reset to 1 when impulse is found, counts freely until then
-  } // ImpulsePending
+                    if (cellNum > pendingCell) {  // we missed it
+                        std::cerr << " - ABORTING CURRENT PULSE\n";
+                        impulsePending = false;
+                    } else {  // somehow we got the previous pulse again - repeated packet
+                              // or underrun-caused repetition (old buffer)
+                        std::cerr << " - IGNORING FOUND PULSE WAITING FURTHER\n";
+                    }
+                } else {  // found our impulse:
+                    int64_t elapsedSamples = -1;
+                    if (n >= n_frames - 1) {
+                        // Impulse timestamp didn't make it so we skip this one.
+                    } else {
+                        float sampleCountWhenImpulseSent =
+                            -32768.0f * out_buffer[sendChannel][n + 1];
+                        elapsedSamples = sampleCountSinceImpulse + n
+                                         - int64_t(sampleCountWhenImpulseSent);
+                        sampleCountSinceImpulse =
+                            1;  // reset sample counter between impulses
+                        roundTripCount += 1.0;
+                    }
+                    // int64_t curTimeUS = timeMicroSec(); // time since launch in us
+                    // int64_t impulseDelayUS = curTimeUS - ImpulseTimeUS;
+                    // float impulseDelaySec = float(impulseDelayUS) * 1.0e-6;
+                    // float impulseDelayBuffers = impulseDelaySec /
+                    // (float(n_frames)/float(sampleRate)); int64_t impulseDelayMS =
+                    // (int64_t)round(double(impulseDelayUS)/1000.0);
+                    if (elapsedSamples
+                        > 0) {  // found impulse and reset, time to print buffer results:
+                        double elapsedSamplesMS =
+                            1000.0 * double(elapsedSamples) / double(sampleRate);  // ms
+                        extendLatencyHistogram(elapsedSamplesMS);
+                        if (roundTripCount > 1.0) {
+                            double prevSum =
+                                roundTripMean
+                                * (roundTripCount - 1.0);  // undo previous normalization
+                            roundTripMean =
+                                (prevSum + elapsedSamplesMS)
+                                / roundTripCount;  // add latest and renormalize
+                            double prevSumSq =
+                                roundTripMeanSquare
+                                * (roundTripCount - 1.0);  // undo previous normalization
+                            roundTripMeanSquare =
+                                (prevSumSq + elapsedSamplesMS * elapsedSamplesMS)
+                                / roundTripCount;
+                        } else {  // just getting started:
+                            roundTripMean       = elapsedSamplesMS;
+                            roundTripMeanSquare = elapsedSamplesMS * elapsedSamplesMS;
+                        }
+                        if (roundTripCount == 1.0) {
+                            printf(
+                                "JackTrip Test Mode (option -x "
+                                "printIntervalInSeconds=%0.3f)\n",
+                                printIntervalSec);
+                            printf(
+                                "\tA test impulse-train is output on channel %d (from 0) "
+                                "with repeatedly ramping amplitude\n",
+                                sendChannel);
+                            if (printIntervalSec == 0.0) {
+                                printf(
+                                    "\tPrinting each audio buffer round-trip latency in "
+                                    "ms followed by cumulative (mean and [standard "
+                                    "deviation])");
+                            } else {
+                                printf(
+                                    "\tPrinting cumulative mean and [standard deviation] "
+                                    "of audio round-trip latency in ms");
+                                printf(" every %0.3f seconds", printIntervalSec);
+                            }
+                            printf(" after skipping first %d buffers:\n",
+                                   bufferSkipStart);
+                            // not printing this presently: printf("( * means buffer
+                            // skipped due missing timestamp or lost impulse)\n");
+                            lastPrintTimeUS = timeMicroSec();
+                        }
+                        // printf("%d (%d) ", elapsedSamplesMS, impulseDelayMS); //
+                        // measured time is "buffer time" not sample time
+                        int64_t curTimeUS = timeMicroSec();  // time since launch in us
+                        double timeSinceLastPrintUS = double(curTimeUS - lastPrintTimeUS);
+                        double stdDev =
+                            sqrt(std::max(0.0, (roundTripMeanSquare
+                                                - (roundTripMean * roundTripMean))));
+                        if (timeSinceLastPrintUS >= printIntervalSec * 1.0e6) {
+                            if (printIntervalSec == 0.0) {
+                                printf("%0.1f (", elapsedSamplesMS);
+                            }
+                            printf("%0.1f [%0.1f]", roundTripMean, stdDev);
+                            if (printIntervalSec == 0.0) {
+                                printf(") ");
+                            } else {
+                                printf(" ");
+                            }
+                            lastPrintTimeUS = curTimeUS;
+                            if (printIntervalSec >= 1.0) {  // print histogram
+                                std::cout << "\n" << getLatencyHistogramString() << "\n";
+                            }
+                        }
+                        std::cout << std::flush;
+                    } else {
+                        // not printing this presently: printf("* "); // we got the
+                        // impulse but lost its timestamp in samples
+                    }
+                    impulsePending = false;
+                }  // found our impulse
+                // remain pending until timeout, hoping to find our return pulse
+            }  // got something
+        }      // loop over samples
+        sampleCountSinceImpulse +=
+            n_frames;  // gets reset to 1 when impulse is found, counts freely until then
+    }                  // ImpulsePending
 }
 
 // Called 2nd in Audiointerface.cpp
 void AudioTester::writeImpulse(QVarLengthArray<sample_t*>& mInBufCopy,
-                               unsigned int n_frames) {
-  if (not enabled) {
-    std::cerr << "*** AudioTester.h: writeImpulse: NOT ENABLED\n";
-    return;
-  }
-  if (bufferSkip <= 0) { // send test signals (-x option)
-    bool sendImpulse;
-    if (impulsePending) {
-      sendImpulse = false; // unless:
-      const uint64_t timeOut = 500e3; // time out after waiting 500 ms
-      if (timeMicroSec() > (impulseTimeUS + timeOut)) {
-        sendImpulse = true;
-        std::cout << "\n*** Audio Latency Test (-x): TIMED OUT waiting for return impulse *** sending a new one\n";
-      }
-    } else { // time for the next repeating impulse:
-      sendImpulse = true;
+                               unsigned int n_frames)
+{
+    if (not enabled) {
+        std::cerr << "*** AudioTester.h: writeImpulse: NOT ENABLED\n";
+        return;
     }
-    if (sendImpulse) {
-      assert(sendChannel < mInBufCopy.size());
-      mInBufCopy[sendChannel][0] = getImpulseAmp();
-      for (uint n=1; n<n_frames; n++) {
-        mInBufCopy[sendChannel][n] = 0;
-      }
-      impulsePending = true;
-      impulseTimeUS = timeMicroSec();
-      impulseTimeSamples = sampleCountSinceImpulse; // timer in samples for current impulse loopback test
-      // Also send impulse time:
-      if (n_frames>1) { // always true?
-        mInBufCopy[sendChannel][1] = -float(impulseTimeSamples)/32768.0f; // survives if there is no digital processing at the server
-      } else {
-        std::cerr << "\n*** AudioTester.h: Timestamp cannot fit into a lenth " << n_frames << " buffer ***\n";
-      }
+    if (bufferSkip <= 0) {  // send test signals (-x option)
+        bool sendImpulse;
+        if (impulsePending) {
+            sendImpulse            = false;  // unless:
+            const uint64_t timeOut = 500e3;  // time out after waiting 500 ms
+            if (timeMicroSec() > (impulseTimeUS + timeOut)) {
+                sendImpulse = true;
+                std::cout << "\n*** Audio Latency Test (-x): TIMED OUT waiting for "
+                             "return impulse *** sending a new one\n";
+            }
+        } else {  // time for the next repeating impulse:
+            sendImpulse = true;
+        }
+        if (sendImpulse) {
+            assert(sendChannel < mInBufCopy.size());
+            mInBufCopy[sendChannel][0] = getImpulseAmp();
+            for (uint n = 1; n < n_frames; n++) { mInBufCopy[sendChannel][n] = 0; }
+            impulsePending     = true;
+            impulseTimeUS      = timeMicroSec();
+            impulseTimeSamples = sampleCountSinceImpulse;  // timer in samples for current
+                                                           // impulse loopback test
+            // Also send impulse time:
+            if (n_frames > 1) {  // always true?
+                mInBufCopy[sendChannel][1] =
+                    -float(impulseTimeSamples)
+                    / 32768.0f;  // survives if there is no digital processing at the
+                                 // server
+            } else {
+                std::cerr << "\n*** AudioTester.h: Timestamp cannot fit into a length "
+                          << n_frames << " buffer ***\n";
+            }
+        } else {
+            mInBufCopy[sendChannel][0] =
+                0.0f;  // send zeros until a new impulse is needed
+            if (n_frames > 1) { mInBufCopy[sendChannel][1] = 0.0f; }
+        }
     } else {
-      mInBufCopy[sendChannel][0] = 0.0f; // send zeros until a new impulse is needed
-      if (n_frames>1) {
-        mInBufCopy[sendChannel][1] = 0.0f;
-      }
+        bufferSkip--;
     }
-  } else {
-    bufferSkip--;
-  }
 }
 
-void AudioTester::printHelp(char* command, [[maybe_unused]] char helpCase) {
-  std::cout << "HELP for \"" << command << " printIntervalSec\" // (end-of-line comments start with `//'):\n";
-  std::cout << "\n";
-  std::cout << "Print roundtrip audio delay statistics for the highest-numbered audio channel every printIntervalSec seconds,\n";
-  std::cout << "including an ASCII latency histogram if printIntervalSec is 1.0 or more.\n";
-  std::cout << "\n";
-  std::cout << "A test impulse is sent to the server in the last audio channel,\n";
-  std::cout << "  the number of samples until it returns is measured, and this repeats.\n";
-  std::cout << "The jacktrip server must provide audio loopback (e.g., -p4).\n";
-  std::cout << "The cumulative mean and standard-deviation (\"statistics\") are computed for the measured loopback times,\n";
-  std::cout << "  and printed every printIntervalSec seconds.\n";
-  std::cout << "If printIntervalSec is zero, the roundtrip-time and statistics in milliseconds are printed for each individual impulse.\n";
-  std::cout << "If printIntervalSec is positive, statistics are printed after each print interval, with no individual measurements.\n";
-  std::cout << "If printIntervalSec is 1.0 or larger, a cumulative histogram of all impulse roundtrip-times is printed as well.\n";
-  std::cout << "The first 100 audio buffers are skipped in order to measure only steady-state network-audio-delay performance.\n";
-  std::cout << "Lower audio channels are not affected, enabling latency measurement and display during normal operation.\n";
+void AudioTester::printHelp(char* command, [[maybe_unused]] char helpCase)
+{
+    std::cout << "HELP for \"" << command
+              << " printIntervalSec\" // (end-of-line comments start with `//'):\n";
+    std::cout << "\n";
+    std::cout << "Print roundtrip audio delay statistics for the highest-numbered audio "
+                 "channel every printIntervalSec seconds,\n";
+    std::cout
+        << "including an ASCII latency histogram if printIntervalSec is 1.0 or more.\n";
+    std::cout << "\n";
+    std::cout << "A test impulse is sent to the server in the last audio channel,\n";
+    std::cout
+        << "  the number of samples until it returns is measured, and this repeats.\n";
+    std::cout << "The jacktrip server must provide audio loopback (e.g., -p4).\n";
+    std::cout << "The cumulative mean and standard-deviation (\"statistics\") are "
+                 "computed for the measured loopback times,\n";
+    std::cout << "  and printed every printIntervalSec seconds.\n";
+    std::cout << "If printIntervalSec is zero, the roundtrip-time and statistics in "
+                 "milliseconds are printed for each individual impulse.\n";
+    std::cout << "If printIntervalSec is positive, statistics are printed after each "
+                 "print interval, with no individual measurements.\n";
+    std::cout << "If printIntervalSec is 1.0 or larger, a cumulative histogram of all "
+                 "impulse roundtrip-times is printed as well.\n";
+    std::cout << "The first 100 audio buffers are skipped in order to measure only "
+                 "steady-state network-audio-delay performance.\n";
+    std::cout << "Lower audio channels are not affected, enabling latency measurement "
+                 "and display during normal operation.\n";
 }
index 4a08f78c4e728132d505ed08282fdc95d0b1f004..6e2d55da94e62082ae5082128c9e54c6f563575b 100644 (file)
 
 #pragma once
 
-#include "jacktrip_types.h" // sample_t
-
 #include <iostream>
+
+#include "jacktrip_types.h"  // sample_t
 //#include <ctime>
+#include <QVarLengthArray>
 #include <chrono>
-#include <cstdint>
 #include <cmath>
-#include <string>
+#include <cstdint>
 #include <map>
-
-#include <QVarLengthArray>
+#include <string>
 
 class AudioTester
 {
-  bool enabled { false };
-  float printIntervalSec { 1.0f };
-  int sendChannel { 0 };
-
-  bool impulsePending { false };
-  int64_t lastPrintTimeUS { 0 };
-  int64_t impulseTimeUS { 0 };
-  int64_t impulseTimeSamples { 0 };
-  uint64_t sampleCountSinceImpulse { 1 }; // 0 not used
-  double roundTripMean { 0.0 };
-  double roundTripMeanSquare { 0.0 };
-  double roundTripCount { 0.0 };
-  const int bufferSkipStart { 100 };
-  int bufferSkip { bufferSkipStart };
-  const float impulseAmplitude { 0.1f };
-  const int numAmpCells { 10 };
-  const float ampCellHeight { impulseAmplitude/numAmpCells };
-
-  const double latencyHistogramCellWidth { 5.0 }; // latency range in ms covered one cell
-  const double latencyHistogramCellMin { 0.0 };
-  const double latencyHistogramCellMax { 19.0 };  // in cells, so 5x this is max latency in ms
-  const int latencyHistogramPrintCountMax { 72 }; // normalize when asterisks exceed this number
-
-  int pendingCell { 0 }; // 0 is not used
-  float sampleRate { 48000.0f };
-
-public:
-  AudioTester() {}
-  ~AudioTester() = default;
-
-  void lookForReturnPulse(QVarLengthArray<sample_t*>& out_buffer,
-                                       unsigned int n_frames);
-
-  void writeImpulse(QVarLengthArray<sample_t*>& mInBufCopy,
-                    unsigned int n_frames);
-
-  bool getEnabled() { return enabled; }
-  void setEnabled(bool e) { enabled = e; }
-  void setPrintIntervalSec(float s) { printIntervalSec = s; }
-  void setSendChannel(int c) { sendChannel = c; }
-  int getSendChannel() { return sendChannel; }
-  int getPendingCell() { return pendingCell; }
-  void setPendingCell(int pc) { pendingCell = pc; }
-  void setSampleRate(float fs) { sampleRate = fs; }
-  int getBufferSkip() { return bufferSkip; } // used for debugging breakpoints
-  void printHelp(char* command, char helpCase);
-
-private:
-
-  float getImpulseAmp() {
-    pendingCell += 1; // only called when no impulse is pending
-    if (pendingCell >= numAmpCells) {
-      pendingCell = 1; // wrap-around, not using zero
+    bool enabled{false};
+    float printIntervalSec{1.0f};
+    int sendChannel{0};
+
+    bool impulsePending{false};
+    int64_t lastPrintTimeUS{0};
+    int64_t impulseTimeUS{0};
+    int64_t impulseTimeSamples{0};
+    uint64_t sampleCountSinceImpulse{1};  // 0 not used
+    double roundTripMean{0.0};
+    double roundTripMeanSquare{0.0};
+    double roundTripCount{0.0};
+    const int bufferSkipStart{100};
+    int bufferSkip{bufferSkipStart};
+    const float impulseAmplitude{0.1f};
+    const int numAmpCells{10};
+    const float ampCellHeight{impulseAmplitude / numAmpCells};
+
+    const double latencyHistogramCellWidth{5.0};  // latency range in ms covered one cell
+    const double latencyHistogramCellMin{0.0};
+    const double latencyHistogramCellMax{
+        19.0};  // in cells, so 5x this is max latency in ms
+    const int latencyHistogramPrintCountMax{
+        72};  // normalize when asterisks exceed this number
+
+    int pendingCell{0};  // 0 is not used
+    float sampleRate{48000.0f};
+
+   public:
+    AudioTester() {}
+    ~AudioTester() = default;
+
+    void lookForReturnPulse(QVarLengthArray<sample_t*>& out_buffer,
+                            unsigned int n_frames);
+
+    void writeImpulse(QVarLengthArray<sample_t*>& mInBufCopy, unsigned int n_frames);
+
+    bool getEnabled() { return enabled; }
+    void setEnabled(bool e) { enabled = e; }
+    void setPrintIntervalSec(float s) { printIntervalSec = s; }
+    void setSendChannel(int c) { sendChannel = c; }
+    int getSendChannel() { return sendChannel; }
+    int getPendingCell() { return pendingCell; }
+    void setPendingCell(int pc) { pendingCell = pc; }
+    void setSampleRate(float fs) { sampleRate = fs; }
+    int getBufferSkip() { return bufferSkip; }  // used for debugging breakpoints
+    void printHelp(char* command, char helpCase);
+
+   private:
+    float getImpulseAmp()
+    {
+        pendingCell += 1;  // only called when no impulse is pending
+        if (pendingCell >= numAmpCells) {
+            pendingCell = 1;  // wrap-around, not using zero
+        }
+        float imp = float(pendingCell) * (impulseAmplitude / float(numAmpCells));
+        return imp;
     }
-    float imp = float(pendingCell) * (impulseAmplitude/float(numAmpCells));
-    return imp;
-  }
-
-  int getImpulseCellNum(float amp) {
-    float ch = ampCellHeight;
-    float cell = amp / ch;
-    int iCell = int(std::floor(0.5f + cell));
-    if (iCell > numAmpCells - 1) {
-      std::cerr << "*** AudioTester.h: getImpulseCellNum("<<amp<<"): Return pulse amplitude is beyond maximum expected\n";
-      iCell = numAmpCells-1;
-    } else if (iCell < 0) {
-      std::cerr << "*** AudioTester.h: getImpulseCellNum("<<amp<<"): Return pulse amplitude is below minimum expected\n";
-      iCell = 0;
+
+    int getImpulseCellNum(float amp)
+    {
+        float ch   = ampCellHeight;
+        float cell = amp / ch;
+        int iCell  = int(std::floor(0.5f + cell));
+        if (iCell > numAmpCells - 1) {
+            std::cerr << "*** AudioTester.h: getImpulseCellNum(" << amp
+                      << "): Return pulse amplitude is beyond maximum expected\n";
+            iCell = numAmpCells - 1;
+        } else if (iCell < 0) {
+            std::cerr << "*** AudioTester.h: getImpulseCellNum(" << amp
+                      << "): Return pulse amplitude is below minimum expected\n";
+            iCell = 0;
+        }
+        return iCell;
     }
-    return iCell;
-  }
 
-  uint64_t timeMicroSec() {
+    uint64_t timeMicroSec()
+    {
 #if 1
-    using namespace std::chrono;
-    // return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
-    return duration_cast<microseconds>(high_resolution_clock::now().time_since_epoch()).count();
+        using namespace std::chrono;
+        // return
+        // duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
+        return duration_cast<microseconds>(
+                   high_resolution_clock::now().time_since_epoch())
+            .count();
 #else
-    clock_t tics_since_launch = std::clock();
-    double timeUS = double(tics_since_launch)/double(CLOCKS_PER_SEC);
-    return (uint64_t)timeUS;
+        clock_t tics_since_launch = std::clock();
+        double timeUS             = double(tics_since_launch) / double(CLOCKS_PER_SEC);
+        return (uint64_t)timeUS;
 #endif
-  }
-
-  std::map<int, int> latencyHistogram;
-
-  std::map<int, int> getLatencyHistogram() {
-    return latencyHistogram;
-  }
-
-  void extendLatencyHistogram(double latencyMS) {
-    int latencyCell = static_cast<int>(floor(std::max(latencyHistogramCellMin,
-                                                      std::min(latencyHistogramCellMax,
-                                                               std::floor(latencyMS / latencyHistogramCellWidth)))));
-    latencyHistogram[latencyCell] += 1;
-  }
-
-  int latencyHistogramCountMax() {
-    int lhMax = 0;
-    int histStart = latencyHistogramFirstNonzeroCellIndex();
-    int histLast = latencyHistogramLastNonzeroCellIndex();
-    for (int i = histStart; i <= histLast; ++i) {
-      int lhi = latencyHistogram[i];
-      if (lhi > lhMax) {
-        lhMax = lhi;
-      }
-    }
-    return lhMax;
-  }
-
-  int latencyHistogramFirstNonzeroCellIndex() {
-    for (int i=latencyHistogramCellMin; i <= latencyHistogramCellMax; i++) {
-      if (latencyHistogram[i]>0) {
-        return i;
-      }
     }
-    std::cerr << "*** AudioTester: LATENCY HISTOGRAM IS EMPTY!\n";
-    return -1;
-  }
-
-  int latencyHistogramLastNonzeroCellIndex() {
-    for (int i=latencyHistogramCellMax; i>=latencyHistogramCellMin; i--) {
-      if (latencyHistogram[i]>0) {
-        return i;
-      }
+
+    std::map<int, int> latencyHistogram;
+
+    std::map<int, int> getLatencyHistogram() { return latencyHistogram; }
+
+    void extendLatencyHistogram(double latencyMS)
+    {
+        int latencyCell = static_cast<int>(
+            floor(std::max(latencyHistogramCellMin,
+                           std::min(latencyHistogramCellMax,
+                                    std::floor(latencyMS / latencyHistogramCellWidth)))));
+        latencyHistogram[latencyCell] += 1;
     }
-    std::cerr << "*** AudioTester: LATENCY HISTOGRAM IS EMPTY!\n";
-    return -1;
-  }
-
-  std::string getLatencyHistogramString() {
-    int histStart = latencyHistogramFirstNonzeroCellIndex();
-    int histLast = latencyHistogramLastNonzeroCellIndex();
-    std::string marker = "*";
-    double histScale = 1.0;
-    int lhcm = latencyHistogramCountMax();
-    int lhpcm = latencyHistogramPrintCountMax;
-    bool normalizing = lhpcm < lhcm;
-    if (normalizing) {
-      marker = "#";
-      histScale = double(lhpcm) / double(lhcm);
+
+    int latencyHistogramCountMax()
+    {
+        int lhMax     = 0;
+        int histStart = latencyHistogramFirstNonzeroCellIndex();
+        int histLast  = latencyHistogramLastNonzeroCellIndex();
+        for (int i = histStart; i <= histLast; ++i) {
+            int lhi = latencyHistogram[i];
+            if (lhi > lhMax) { lhMax = lhi; }
+        }
+        return lhMax;
     }
-    std::string rows = "";
-    for (int i = histStart; i <= histLast; ++i) {
-      int hi = latencyHistogram[i];
-      int hin = int(std::round(histScale * double(hi)));
-      std::string istrm1 = std::to_string(int(latencyHistogramCellWidth * double(i)));
-      std::string istr = std::to_string(int(latencyHistogramCellWidth * double(i+1)));
-      // std::string histr = boost::format("%02d",hi);
-      std::string histr = std::to_string(hi);
-      while (histr.length()<3) {
-        histr = " " + histr;
-      }
-      std::string row = "["+istrm1+"-"+istr+"ms]="+histr+":";
-      for (int j=0; j<hin; j++) {
-        row += marker;
-      }
-      rows += row + "\n";
+
+    int latencyHistogramFirstNonzeroCellIndex()
+    {
+        for (int i = latencyHistogramCellMin; i <= latencyHistogramCellMax; i++) {
+            if (latencyHistogram[i] > 0) { return i; }
+        }
+        std::cerr << "*** AudioTester: LATENCY HISTOGRAM IS EMPTY!\n";
+        return -1;
     }
-    if (histLast == latencyHistogramCellMax) {
-      rows += " and above\n";
+
+    int latencyHistogramLastNonzeroCellIndex()
+    {
+        for (int i = latencyHistogramCellMax; i >= latencyHistogramCellMin; i--) {
+            if (latencyHistogram[i] > 0) { return i; }
+        }
+        std::cerr << "*** AudioTester: LATENCY HISTOGRAM IS EMPTY!\n";
+        return -1;
     }
-    return rows;
-  }
 
+    std::string getLatencyHistogramString()
+    {
+        int histStart      = latencyHistogramFirstNonzeroCellIndex();
+        int histLast       = latencyHistogramLastNonzeroCellIndex();
+        std::string marker = "*";
+        double histScale   = 1.0;
+        int lhcm           = latencyHistogramCountMax();
+        int lhpcm          = latencyHistogramPrintCountMax;
+        bool normalizing   = lhpcm < lhcm;
+        if (normalizing) {
+            marker    = "#";
+            histScale = double(lhpcm) / double(lhcm);
+        }
+        std::string rows = "";
+        for (int i = histStart; i <= histLast; ++i) {
+            int hi  = latencyHistogram[i];
+            int hin = int(std::round(histScale * double(hi)));
+            std::string istrm1 =
+                std::to_string(int(latencyHistogramCellWidth * double(i)));
+            std::string istr =
+                std::to_string(int(latencyHistogramCellWidth * double(i + 1)));
+            // std::string histr = boost::format("%02d",hi);
+            std::string histr = std::to_string(hi);
+            while (histr.length() < 3) { histr = " " + histr; }
+            std::string row = "[" + istrm1 + "-" + istr + "ms]=" + histr + ":";
+            for (int j = 0; j < hin; j++) { row += marker; }
+            rows += row + "\n";
+        }
+        if (histLast == latencyHistogramCellMax) { rows += " and above\n"; }
+        return rows;
+    }
 };
diff --git a/src/Auth.cpp b/src/Auth.cpp
new file mode 100644 (file)
index 0000000..10dc553
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+  JackTrip: A System for High-Quality Audio Network Performance
+  over the Internet
+
+  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  SoundWIRE group at CCRMA, Stanford University.
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation
+  files (the "Software"), to deal in the Software without
+  restriction, including without limitation the rights to use,
+  copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the
+  Software is furnished to do so, subject to the following
+  conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+  OTHER DEALINGS IN THE SOFTWARE.
+*/
+//*****************************************************************
+
+/**
+ * \file Auth.cpp
+ * \author Aaron Wyatt
+ * \date September 2020
+ */
+
+#include "Auth.h"
+
+#include <QCryptographicHash>
+#include <QDate>
+#include <QFile>
+#include <QTextStream>
+#include <QThread>
+#include <iostream>
+
+Auth::Auth(QString fileName)
+    : m_days({"Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"}), m_authFileName(fileName)
+{
+    // Load our credentials file.
+    loadAuthFile(m_authFileName);
+
+    // Monitor the file for any changes. (Reload when it does.)
+    m_authFileWatcher.addPath(m_authFileName);
+    QObject::connect(&m_authFileWatcher, &QFileSystemWatcher::fileChanged, this,
+                     &Auth::reloadAuthFile, Qt::QueuedConnection);
+}
+
+Auth::AuthResponseT Auth::checkCredentials(QString username, QString password)
+{
+    if (username.isEmpty() || password.isEmpty()) { return WRONGCREDS; }
+
+    if (m_passwordTable.contains(username)) {
+        // Check our generated hash against our stored hash.
+        QString salt = m_passwordTable[username].section("$", 2, 2);
+        QString hash(generateSha512Hash(password, salt));
+
+        if (hash == m_passwordTable[username]) {
+            if (checkTime(username)) {
+                return OK;
+            } else {
+                return WRONGTIME;
+            }
+        }
+    }
+
+    return WRONGCREDS;
+}
+
+void Auth::reloadAuthFile()
+{
+    // Some text editors will replace the original file instead of modifying the existing
+    // one. Re-add our file to the watcher. (This has no effect if it's still there.)
+    QThread::msleep(200);
+    std::cout << "Auth file changed. Reloading..." << std::endl;
+    m_authFileWatcher.addPath(m_authFileName);
+    loadAuthFile(m_authFileName);
+}
+
+void Auth::loadAuthFile(QString filename)
+{
+    QFile file(filename);
+    if (file.open(QIODevice::ReadOnly)) {
+        m_passwordTable.clear();
+        m_timesTable.clear();
+
+        // Read our file into our password table
+        QTextStream input(&file);
+        int lineNumber = 0;
+        while (!input.atEnd()) {
+            lineNumber++;
+            QStringList lineParts = input.readLine().split(":");
+            if (lineParts.count() < 3) {
+                // We don't have a correctly formatted line. Ignore it.
+                std::cout
+                    << "WARNING: Incorrectly formatted line in auth file ignored. (Line "
+                    << lineNumber << ")" << std::endl;
+                continue;
+            }
+
+            // Check that our password hash is useable.
+            bool invalid = false;
+            if (lineParts.at(1).startsWith("$6$")) {
+                QStringList hashParts = lineParts.at(1).split("$");
+                if (hashParts.count() < 4) {
+                    invalid = true;
+                } else if (hashParts.at(2).isEmpty() || hashParts.at(3).isEmpty()) {
+                    invalid = true;
+                }
+            } else {
+                invalid = true;
+            }
+            if (invalid) {
+                std::cout << "WARNING: Invalid password hash in auth file. (Line "
+                          << lineNumber << ")" << std::endl;
+                continue;
+            }
+
+            m_passwordTable[lineParts.at(0)] = lineParts.at(1);
+            m_timesTable[lineParts.at(0)]    = lineParts.at(2);
+        }
+        file.close();
+    }
+}
+
+bool Auth::checkTime(QString username)
+{
+    QStringList times = m_timesTable[username].split(",");
+    // First check for the all or none cases.
+    if (times.count() == 1 && times.at(0).isEmpty()) {
+        return false;
+    } else if (times.contains("*")) {
+        return true;
+    }
+
+    // Now check for weekly schedule information.
+    QString dayOfWeek = m_days.at(QDate::currentDate().dayOfWeek() - 1);
+    for (int i = 0; i < times.count(); i++) {
+        if (times.at(i).startsWith(dayOfWeek)) {
+            QString accessTime = QString(times.at(i)).remove(0, 2);
+            // Check for the all day option first.
+            if (accessTime == "*") { return true; }
+
+            // See if we can interpret it as a time range.
+            bool valid        = false;
+            QStringList range = accessTime.split("-");
+            if (range.count() == 2) {
+                QTime start = QTime::fromString(range.at(0), "hhmm");
+                QTime end   = QTime::fromString(range.at(1), "hhmm");
+
+                if (start.isValid() && end.isValid()) {
+                    valid = true;
+                    if (QTime::currentTime() >= start && QTime::currentTime() <= end) {
+                        return true;
+                    }
+                }
+            }
+            if (!valid) {
+                std::cout << "WARNING: The access time \"" << times.at(i).toStdString()
+                          << "\" in the auth file for user \"" << username.toStdString()
+                          << "\" is not valid." << std::endl;
+            }
+        }
+    }
+
+    // We didn't find a match.
+    return false;
+}
+
+char Auth::char64(int value)
+{
+    // Returns a base 64 enconding using the following characters:
+    // ./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+    if (value < 0 || value >= 64) { return 0; }
+
+    if (value < 12) {
+        return (value + 46);
+    } else if (value < 38) {
+        return (value + 53);
+    } else {
+        return (value + 59);
+    }
+}
+
+QByteArray Auth::charGroup(unsigned char byte2, unsigned char byte1, unsigned char byte0,
+                           unsigned int n)
+{
+    // Returns n base64 encoded characters from 24bits of input.
+    // Based on the SHA-crypt algorithm.
+
+    unsigned int w = (byte2 << 16) | (byte1 << 8) | byte0;
+    QByteArray output;
+    while (n-- > 0) {
+        output.append(char64(w & 0x3f));
+        w >>= 6;
+    }
+    return output;
+}
+
+QByteArray Auth::generateSha512Hash(QString passwordString, QString saltString)
+{
+    // Qt implementation of the unix crypt using SHA-512
+    // (Should give the same output as openssl passwd -6)
+
+    // For details on the algorithm see https://www.akkadia.org/drepper/SHA-crypt.txt
+    // (The steps referred to here follow the implementation instructions.)
+    QByteArray passwd = passwordString.toUtf8();
+    passwd.truncate(256);
+    QByteArray salt = saltString.toUtf8();
+    salt.truncate(16);
+
+    int rounds = 5000;
+    QCryptographicHash a(QCryptographicHash::Sha512);
+    QCryptographicHash b(QCryptographicHash::Sha512);
+
+    a.addData(passwd);
+    a.addData(salt);
+
+    b.addData(passwd);
+    b.addData(salt);
+    b.addData(passwd);
+    QByteArray bResult = b.result();
+
+    // Step 9 and 10
+    int n;
+    for (n = passwd.length(); n > 64; n -= 64) { a.addData(bResult); }
+    a.addData(bResult.constData(), n);
+
+    // Step 11
+    n = passwd.length();
+    while (n) {
+        if (n & 1) {
+            a.addData(bResult);
+        } else {
+            a.addData(passwd);
+        }
+        n >>= 1;
+    }
+    QByteArray aResult = a.result();
+
+    // Step 13
+    // Reuse a as dp.
+    a.reset();
+    for (n = 0; n < passwd.length(); n++) { a.addData(passwd); }
+    QByteArray dp = a.result();
+
+    // Step 16
+    QByteArray p;
+    for (n = passwd.length(); n > 64; n -= 64) { p.append(dp); }
+    p.append(dp.constData(), n);
+
+    // Step 17
+    // Reuse b as ds
+    b.reset();
+    for (n = 16 + (unsigned char)aResult.at(0); n > 0; n--) { b.addData(salt); }
+    QByteArray ds = b.result();
+
+    // Step 20
+    QByteArray s;
+    for (n = salt.length(); n > 64; n -= 64) { s.append(ds); }
+    s.append(ds.constData(), n);
+
+    // Step 21
+    for (n = 0; n < rounds; n++) {
+        // Reuse a as c.
+        a.reset();
+        if (n & 1) {
+            a.addData(p);
+        } else {
+            a.addData(aResult);
+        }
+
+        if (n % 3) { a.addData(s); }
+        if (n % 7) { a.addData(p); }
+
+        if (n & 1) {
+            a.addData(aResult);
+        } else {
+            a.addData(p);
+        }
+
+        aResult = a.result();
+    }
+
+    // Step 22
+    QByteArray output("$6$");
+    output.append(salt);
+    output.append("$");
+    output.append(charGroup(aResult.at(0), aResult.at(21), aResult.at(42), 4));
+    output.append(charGroup(aResult.at(22), aResult.at(43), aResult.at(1), 4));
+    output.append(charGroup(aResult.at(44), aResult.at(2), aResult.at(23), 4));
+    output.append(charGroup(aResult.at(3), aResult.at(24), aResult.at(45), 4));
+    output.append(charGroup(aResult.at(25), aResult.at(46), aResult.at(4), 4));
+    output.append(charGroup(aResult.at(47), aResult.at(5), aResult.at(26), 4));
+    output.append(charGroup(aResult.at(6), aResult.at(27), aResult.at(48), 4));
+    output.append(charGroup(aResult.at(28), aResult.at(49), aResult.at(7), 4));
+    output.append(charGroup(aResult.at(50), aResult.at(8), aResult.at(29), 4));
+    output.append(charGroup(aResult.at(9), aResult.at(30), aResult.at(51), 4));
+    output.append(charGroup(aResult.at(31), aResult.at(52), aResult.at(10), 4));
+    output.append(charGroup(aResult.at(53), aResult.at(11), aResult.at(32), 4));
+    output.append(charGroup(aResult.at(12), aResult.at(33), aResult.at(54), 4));
+    output.append(charGroup(aResult.at(34), aResult.at(55), aResult.at(13), 4));
+    output.append(charGroup(aResult.at(56), aResult.at(14), aResult.at(35), 4));
+    output.append(charGroup(aResult.at(15), aResult.at(36), aResult.at(57), 4));
+    output.append(charGroup(aResult.at(37), aResult.at(58), aResult.at(16), 4));
+    output.append(charGroup(aResult.at(59), aResult.at(17), aResult.at(38), 4));
+    output.append(charGroup(aResult.at(18), aResult.at(39), aResult.at(60), 4));
+    output.append(charGroup(aResult.at(40), aResult.at(61), aResult.at(19), 4));
+    output.append(charGroup(aResult.at(62), aResult.at(20), aResult.at(41), 4));
+    output.append(charGroup(0, 0, aResult.at(63), 2));
+
+    return output;
+}
+
+Auth::Auth::~Auth() = default;
diff --git a/src/Auth.h b/src/Auth.h
new file mode 100644 (file)
index 0000000..875d78b
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+  JackTrip: A System for High-Quality Audio Network Performance
+  over the Internet
+
+  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  SoundWIRE group at CCRMA, Stanford University.
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation
+  files (the "Software"), to deal in the Software without
+  restriction, including without limitation the rights to use,
+  copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the
+  Software is furnished to do so, subject to the following
+  conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+  OTHER DEALINGS IN THE SOFTWARE.
+*/
+//*****************************************************************
+
+/**
+ * \file Auth.h
+ * \author Aaron Wyatt
+ * \date September 2020
+ */
+
+#ifndef __AUTH_H__
+#define __AUTH_H__
+
+#include <QFileSystemWatcher>
+#include <QHash>
+#include <QObject>
+
+class Auth : public QObject
+{
+    Q_OBJECT;
+
+   public:
+    enum AuthResponseT {
+        OK          = 1 << 16,
+        REQUIRED    = 2 << 16,
+        NOTREQUIRED = 3 << 16,
+        WRONGCREDS  = 4 << 16,
+        WRONGTIME   = 5 << 16
+    };
+
+    Auth(QString fileName);
+    ~Auth();
+
+    AuthResponseT checkCredentials(QString username, QString password);
+
+   private slots:
+    void reloadAuthFile();
+
+   private:
+    void loadAuthFile(QString filename);
+    bool checkTime(QString username);
+
+    char char64(int value);
+    QByteArray charGroup(unsigned char byte3, unsigned char byte2, unsigned char byte1,
+                         unsigned int n);
+    QByteArray generateSha512Hash(QString passwordString, QString saltString);
+
+    QStringList m_days;
+    QHash<QString, QString> m_passwordTable;
+    QHash<QString, QString> m_timesTable;
+
+    QString m_authFileName;
+    QFileSystemWatcher m_authFileWatcher;
+};
+
+#endif  // __AUTH_H__
index a1ed346813d3c8fa592d52ce501e5a98be71f622..954a749e6bfb18f62d1488b2105aba84a5a1db1b 100644 (file)
@@ -35,7 +35,6 @@
  * \date July 2008
  */
 
-
 #include "Compressor.h"
 
 #include <iostream>
 //*******************************************************************************
 void Compressor::compute(int nframes, float** inputs, float** outputs)
 {
-  if (not inited) {
-    std::cerr << "*** Compressor " << this << ": init never called! Doing it now.\n";
-    if (fSamplingFreq <= 0) {
-      fSamplingFreq = 48000;
-      std::cout << "Compressor " << this << ": *** HAD TO GUESS the sampling rate (chose 48000 Hz) ***\n";
+    if (not inited) {
+        std::cerr << "*** Compressor " << this << ": init never called! Doing it now.\n";
+        if (fSamplingFreq <= 0) {
+            fSamplingFreq = 48000;
+            std::cout << "Compressor " << this
+                      << ": *** HAD TO GUESS the sampling rate (chose 48000 Hz) ***\n";
+        }
+        init(fSamplingFreq);
+    }
+    for (int i = 0; i < mNumChannels; i++) {
+        compressorP[i]->compute(nframes, &inputs[i], &outputs[i]);
     }
-    init(fSamplingFreq);
-  }
-  for ( int i = 0; i < mNumChannels; i++ ) {
-    compressorP[i]->compute(nframes, &inputs[i], &outputs[i]);
-  }
 }
index d5f41eaa068eb865833d30292eee2b910f5b1d75..120877921d638efe8879618bb41cba68b056077d 100644 (file)
  * \date August 2020
  */
 
-
 /** \brief Applies compressor_mono from the faustlibraries distribution, compressors.lib
  *
  */
 #ifndef __COMPRESSOR_H__
 #define __COMPRESSOR_H__
 
+#include <vector>
+
+#include "CompressorPresets.h"
 #include "ProcessPlugin.h"
 #include "compressordsp.h"
-#include "CompressorPresets.h"
-#include <vector>
 
 /** \brief A Compressor reduces the output dynamic range when the
  *         signal level exceeds the threshold.
  */
 class Compressor : public ProcessPlugin
 {
-public:
-  /// \brief The class constructor sets the number of audio channels and default parameters.
-  Compressor(int numchans, // xtor
-             bool verboseIn = false,
-             float ratioIn = 2.0f,
-             float thresholdDBIn = -24.0f,
-             float attackMSIn = 15.0f,
-             float releaseMSIn = 40.0f,
-             float makeUpGainDBIn = 2.0f)
-    : mNumChannels(numchans)
-    , ratio(ratioIn)
-    , thresholdDB(thresholdDBIn)
-    , attackMS(attackMSIn)
-    , releaseMS(releaseMSIn)
-    , makeUpGainDB(makeUpGainDBIn)
-  {
-    setVerbose(verboseIn);
-    // presets.push_back(std::make_unique<CompressorPreset>(ratio,thresholdDB,attackMS,releaseMS,makeUpGainDB));
-    for ( int i = 0; i < mNumChannels; i++ ) {
-      compressorP.push_back(new compressordsp);
-      compressorUIP.push_back(new APIUI); // #included in compressordsp.h
-      compressorP[i]->buildUserInterface(compressorUIP[i]);
+   public:
+    /// \brief The class constructor sets the number of audio channels and default
+    /// parameters.
+    Compressor(int numchans,  // xtor
+               bool verboseIn = false, float ratioIn = 2.0f, float thresholdDBIn = -24.0f,
+               float attackMSIn = 15.0f, float releaseMSIn = 40.0f,
+               float makeUpGainDBIn = 2.0f)
+        : mNumChannels(numchans)
+        , ratio(ratioIn)
+        , thresholdDB(thresholdDBIn)
+        , attackMS(attackMSIn)
+        , releaseMS(releaseMSIn)
+        , makeUpGainDB(makeUpGainDBIn)
+    {
+        setVerbose(verboseIn);
+        // presets.push_back(std::make_unique<CompressorPreset>(ratio,thresholdDB,attackMS,releaseMS,makeUpGainDB));
+        for (int i = 0; i < mNumChannels; i++) {
+            compressorP.push_back(new compressordsp);
+            compressorUIP.push_back(new APIUI);  // #included in compressordsp.h
+            compressorP[i]->buildUserInterface(compressorUIP[i]);
+        }
     }
-  }
 
-  Compressor(int numchans, // xtor
-             bool verboseIn = false,
-             CompressorPreset preset = CompressorPresets::voice) :
-    Compressor(numchans,verboseIn,
-               preset.ratio,
-               preset.thresholdDB,
-               preset.attackMS,
-               preset.releaseMS,
-               preset.makeUpGainDB)
-  {}
-  /// \brief The class destructor
-  virtual ~Compressor() {
-    for ( int i = 0; i < mNumChannels; i++ ) {
-      delete compressorP[i];
-      delete compressorUIP[i];
+    Compressor(int numchans,  // xtor
+               bool verboseIn = false, CompressorPreset preset = CompressorPresets::voice)
+        : Compressor(numchans, verboseIn, preset.ratio, preset.thresholdDB,
+                     preset.attackMS, preset.releaseMS, preset.makeUpGainDB)
+    {
+    }
+    /// \brief The class destructor
+    virtual ~Compressor()
+    {
+        for (int i = 0; i < mNumChannels; i++) {
+            delete compressorP[i];
+            delete compressorUIP[i];
+        }
+        compressorP.clear();
+        compressorUIP.clear();
     }
-    compressorP.clear();
-    compressorUIP.clear();
-  }
 
-  //  void setParamAllChannels(std::string& pName, float p) {
-  void setParamAllChannels(const char pName[], float p) {
-    for ( int i = 0; i < mNumChannels; i++ ) {
-      int ndx = compressorUIP[i]->getParamIndex(pName);
-      if (ndx >= 0) {
-        compressorUIP[i]->setParamValue(ndx, p);
-        if (verbose) {
-          std::cout << "Compressor.h: parameter " << pName << " set to " << p << " on audio channel " << i << "\n";
+    //  void setParamAllChannels(std::string& pName, float p) {
+    void setParamAllChannels(const char pName[], float p)
+    {
+        for (int i = 0; i < mNumChannels; i++) {
+            int ndx = compressorUIP[i]->getParamIndex(pName);
+            if (ndx >= 0) {
+                compressorUIP[i]->setParamValue(ndx, p);
+                if (verbose) {
+                    std::cout << "Compressor.h: parameter " << pName << " set to " << p
+                              << " on audio channel " << i << "\n";
+                }
+            } else {
+                std::cerr << "*** Compressor.h: Could not find parameter named " << pName
+                          << "\n";
+            }
         }
-      } else {
-        std::cerr << "*** Compressor.h: Could not find parameter named " << pName << "\n";
-      }
     }
-  }
 
-  void init(int samplingRate) override {
-    ProcessPlugin::init(samplingRate);
-    if (samplingRate != fSamplingFreq) {
-      std::cerr << "Sampling rate not set by superclass!\n";
-      std::exit(1); }
-    fs = float(fSamplingFreq);
-    for ( int i = 0; i < mNumChannels; i++ ) {
-      compressorP[i]->init(fs); // compression filter parameters depend on sampling rate
+    void init(int samplingRate) override
+    {
+        ProcessPlugin::init(samplingRate);
+        if (samplingRate != fSamplingFreq) {
+            std::cerr << "Sampling rate not set by superclass!\n";
+            std::exit(1);
+        }
+        fs = float(fSamplingFreq);
+        for (int i = 0; i < mNumChannels; i++) {
+            compressorP[i]->init(
+                fs);  // compression filter parameters depend on sampling rate
+        }
+        setParamAllChannels("Ratio", ratio);
+        setParamAllChannels("Threshold", thresholdDB);
+        setParamAllChannels("Attack", attackMS);
+        setParamAllChannels("Release", releaseMS);
+        setParamAllChannels("MakeUpGain", makeUpGainDB);
+        inited = true;
     }
-    setParamAllChannels("Ratio", ratio);
-    setParamAllChannels("Threshold", thresholdDB);
-    setParamAllChannels("Attack", attackMS);
-    setParamAllChannels("Release", releaseMS);
-    setParamAllChannels("MakeUpGain", makeUpGainDB);
-    inited = true;
-  }
 
-  int getNumInputs() override { return(mNumChannels); }
-  int getNumOutputs() override { return(mNumChannels); }
-  void compute(int nframes, float** inputs, float** outputs) override;
+    int getNumInputs() override { return (mNumChannels); }
+    int getNumOutputs() override { return (mNumChannels); }
+    void compute(int nframes, float** inputs, float** outputs) override;
+    const char* getName() const override { return "Compressor"; }
 
-private:
-  float fs;
-  int mNumChannels;
-  std::vector<compressordsp*> compressorP;
-  std::vector<APIUI*> compressorUIP;
-  float ratio;
-  float thresholdDB;
-  float attackMS;
-  float releaseMS;
-  float makeUpGainDB;
+   private:
+    float fs;
+    int mNumChannels;
+    std::vector<compressordsp*> compressorP;
+    std::vector<APIUI*> compressorUIP;
+    float ratio;
+    float thresholdDB;
+    float attackMS;
+    float releaseMS;
+    float makeUpGainDB;
 };
 
 #endif
index 2a12db129e3014667059807ebc31a7e352ad2561..ab7745ec83dbb329f8ea77512f59ea530008fd2a 100644 (file)
@@ -3,33 +3,25 @@
 #include <array>
 
 struct CompressorPreset {
-  float ratio;
-  float thresholdDB;
-  float attackMS;
-  float releaseMS;
-  float makeUpGainDB;
-  CompressorPreset(float r, float t, float a, float rel, float m)
-    : ratio(r)
-    , thresholdDB(t)
-    , attackMS(a)
-    , releaseMS(rel)
-    , makeUpGainDB(m)
-  {}
-  ~CompressorPreset() = default;
+    float ratio;
+    float thresholdDB;
+    float attackMS;
+    float releaseMS;
+    float makeUpGainDB;
 };
 
 namespace CompressorPresets
 {
-  //                     name   ratio  thresh  attack  rel  mugain
-  const CompressorPreset voice { 2.0f, -24.0f, 15.0f, 40.0f, 2.0f };
-  const CompressorPreset horns { 3.0f, -10.0f, 100.0f, 250.0f, 2.0f };
-  const CompressorPreset snare { 5.0f, -4.0f, 5.0f, 150.0f, 3.0f };
-  const uint numPresets { 3 };
-  const std::array<CompressorPreset,numPresets> standardPresets { voice, horns, snare };
-  enum CompressorPresetNames { CPN_VOICE, CPN_BRASS, CPN_SNARE, CPN_NUMPRESETS };
-}
+//                     name   ratio  thresh  attack  rel  mugain
+const CompressorPreset voice{2.0f, -24.0f, 15.0f, 40.0f, 2.0f};
+const CompressorPreset horns{3.0f, -10.0f, 100.0f, 250.0f, 2.0f};
+const CompressorPreset snare{5.0f, -4.0f, 5.0f, 150.0f, 3.0f};
+const unsigned int numPresets{3};
+const std::array<CompressorPreset, numPresets> standardPresets{voice, horns, snare};
+enum CompressorPresetNames { CPN_VOICE, CPN_BRASS, CPN_SNARE, CPN_NUMPRESETS };
+}  // namespace CompressorPresets
 
-#if 0 // not yet using this
+#if 0  // not yet using this
 // Dynamic extension of CompressorPresets:
 struct CompressorPresetList {
   std::vector<CompressorPreset*> presets;
@@ -42,6 +34,8 @@ struct CompressorPresetList {
 };
 #endif
 
+// clang-format off
+
 /* Settings from http://www.anythingpeaceful.org/sonar/settings/comp.html
 
    Name     Thresh(dB) Att(ms) Rel(ms) Ratio:1 Gain(dB)    Comments
@@ -79,3 +73,5 @@ struct CompressorPresetList {
    Perc.       -10     10-20   50      3-6     3       Transient overdrive protection in mix
 
 */
+
+// clang-format on
index aac86eb03e896656e6b6780ac5639fad64a979b5..93c458fd016f654d25b84d180521bc0e86d57fba 100644 (file)
  */
 
 #include "DataProtocol.h"
-#include "jacktrip_globals.h"
-#include "JackTrip.h"
-
-#include <iostream>
-#include <cstdlib>
 
-#include <QHostInfo>
 #include <QHostAddress>
+#include <QHostInfo>
+#include <cstdlib>
+#include <iostream>
 
-using std::cout; using std::endl;
+#include "JackTrip.h"
+#include "jacktrip_globals.h"
 
+using std::cout;
+using std::endl;
 
 //*******************************************************************************
-DataProtocol::DataProtocol(JackTrip* jacktrip,
-                           const runModeT runmode,
-                           int /*bind_port*/, int /*peer_port*/) :
-    mStopped(false), mHasPacketsToReceive(false), mRunMode(runmode), mJackTrip(jacktrip), mUseRtPriority(false)
-{}
-
+DataProtocol::DataProtocol(JackTrip* jacktrip, const runModeT runmode, int /*bind_port*/,
+                           int /*peer_port*/)
+    : mStopped(false)
+    , mHasPacketsToReceive(false)
+    , mRunMode(runmode)
+    , mJackTrip(jacktrip)
+    , mUseRtPriority(false)
+{
+}
 
 //*******************************************************************************
-DataProtocol::~DataProtocol()
-{}
+DataProtocol::~DataProtocol() {}
index 6be9a5a6ae0aa7ac87a9e1e3986fb476f23962c7..81bbada2e7a9095fa83f8d047b25bd421c8eaf4d 100644 (file)
 #endif
 
 #ifndef __WIN_32__
-#include <netinet/in.h> //sockaddr_in{} and other Internet defns
-#include <arpa/inet.h> //inet(3) functions
+#include <arpa/inet.h>  //inet(3) functions
 #include <netdb.h>
+#include <netinet/in.h>  //sockaddr_in{} and other Internet defns
 //#include <tr1/memory> //for shared_ptr
 #endif
 
-#include <iostream>
-
-#include <QThread>
 #include <QHostAddress>
 #include <QMutex>
 #include <QMutexLocker>
+#include <QThread>
+#include <iostream>
 
-class JackTrip; // forward declaration
-
+class JackTrip;  // forward declaration
 
 /** \brief Base class that defines the transmission protocol.
  *
@@ -76,10 +74,10 @@ class JackTrip; // forward declaration
  * Redundancy and forward error correction should be implemented on each
  * Transport protocol, cause they depend on the protocol itself
  *
- * \todo This Class should contain definition of jacktrip header and basic funcionality to obtain
- * local machine IPs and maybe functions to manipulate IPs.
- * Redundancy and forward error correction should be implemented on each
- * Transport protocol, cause they depend on the protocol itself
+ * \todo This Class should contain definition of jacktrip header and basic funcionality to
+ * obtain local machine IPs and maybe functions to manipulate IPs. Redundancy and forward
+ * error correction should be implemented on each Transport protocol, cause they depend on
+ * the protocol itself
  *
  * \todo The transport protocol itself has to be implemented subclassing this class, i.e.,
  * using a TCP or UDP protocol.
@@ -94,81 +92,80 @@ class DataProtocol : public QThread
 {
     Q_OBJECT;
 
-public:
-
+   public:
     //----------ENUMS------------------------------------------
     /// \brief Enum to define packet header types
     enum packetHeaderTypeT {
-        DEFAULT, ///< Default application header
-        JAMLINK, ///< Header to use with Jamlinks
-        EMPTY    ///< Empty Header
+        DEFAULT,  ///< Default application header
+        JAMLINK,  ///< Header to use with Jamlinks
+        EMPTY     ///< Empty Header
     };
 
     /// \brief Enum to define class modes, SENDER or RECEIVER
     enum runModeT {
-        SENDER, ///< Set class as a Sender (send packets)
-        RECEIVER ///< Set class as a Receiver (receives packets)
+        SENDER,   ///< Set class as a Sender (send packets)
+        RECEIVER  ///< Set class as a Receiver (receives packets)
     };
     //---------------------------------------------------------
 
-
     /** \brief The class constructor
-   * \param jacktrip Pointer to the JackTrip class that connects all classes (mediator)
-   * \param runmode Sets the run mode, use either DataProtocol::SENDER or
-   * DataProtocol::RECEIVER
-   * \param headertype packetHeaderTypeT header type to use for packets
-   * \param bind_port Port number to bind for this socket (this is the receive or send port depending on the runmode)
-   * \param peer_port Peer port number (this is the receive or send port depending on the runmode)
-   */
-    DataProtocol(JackTrip* jacktrip,
-                 const runModeT runmode,
-                 int bind_port, int peer_port);
+     * \param jacktrip Pointer to the JackTrip class that connects all classes (mediator)
+     * \param runmode Sets the run mode, use either DataProtocol::SENDER or
+     * DataProtocol::RECEIVER
+     * \param headertype packetHeaderTypeT header type to use for packets
+     * \param bind_port Port number to bind for this socket (this is the receive or send
+     * port depending on the runmode) \param peer_port Peer port number (this is the
+     * receive or send port depending on the runmode)
+     */
+    DataProtocol(JackTrip* jacktrip, const runModeT runmode, int bind_port,
+                 int peer_port);
 
     /// \brief The class destructor
     virtual ~DataProtocol();
 
     /** \brief Implements the thread loop
-   *
-   * Depending on the runmode, with will run a DataProtocol::SENDER thread or
-   * DataProtocol::RECEIVER thread
-   */
+     *
+     * Depending on the runmode, with will run a DataProtocol::SENDER thread or
+     * DataProtocol::RECEIVER thread
+     */
     virtual void run() = 0;
 
     /// \brief Stops the execution of the Thread
-    virtual void stop() {
+    virtual void stop()
+    {
         QMutexLocker lock(&mMutex);
         mStopped = true;
     }
 
     /** \brief Sets the size of the audio part of the packets
-   * \param size_bytes Size in bytes
-   */
-    void setAudioPacketSize(const size_t size_bytes){ mAudioPacketSize = size_bytes; }
+     * \param size_bytes Size in bytes
+     */
+    void setAudioPacketSize(const size_t size_bytes) { mAudioPacketSize = size_bytes; }
 
     /** \brief Get the size of the audio part of the packets
-   * \return size_bytes Size in bytes
-   */
-    size_t getAudioPacketSizeInBites() { return(mAudioPacketSize); }
+     * \return size_bytes Size in bytes
+     */
+    size_t getAudioPacketSizeInBites() { return (mAudioPacketSize); }
 
     /** \brief Set the peer address
-   * \param peerHostOrIP IPv4 number or host name
-   * \todo implement here instead of in the subclass UDP
-   */
+     * \param peerHostOrIP IPv4 number or host name
+     * \todo implement here instead of in the subclass UDP
+     */
     virtual void setPeerAddress(const char* peerHostOrIP) = 0;
 
     /** \brief Set the peer incomming (receiving) port number
-   * \param port Port number
-   * \todo implement here instead of in the subclass UDP
-   */
+     * \param port Port number
+     * \todo implement here instead of in the subclass UDP
+     */
     virtual void setPeerPort(int port) = 0;
 
-    //virtual void getPeerAddressFromFirstPacket(QHostAddress& peerHostAddress,
+    // virtual void getPeerAddressFromFirstPacket(QHostAddress& peerHostAddress,
     //                              uint16_t& port) = 0;
 
-#if defined (__WIN_32__)
-    virtual void setSocket(SOCKET &socket) = 0;
+#if defined(__WIN_32__)
+    virtual void setSocket(SOCKETsocket) = 0;
 #else
-    virtual void setSocket(int &socket) = 0;
+    virtual void setSocket(intsocket) = 0;
 #endif
 
     struct PktStat {
@@ -178,22 +175,24 @@ public:
         uint32_t revived;
         uint32_t statCount;
     };
-    virtual bool getStats(PktStat*) {return false;}
+    virtual bool getStats(PktStat*) { return false; }
 
-    virtual void setIssueSimulation(double /*loss*/, double /*jitter*/, double /*max_delay*/) {}
-    void setUseRtPriority(bool use) {mUseRtPriority = use;}
+    virtual void setIssueSimulation(double /*loss*/, double /*jitter*/,
+                                    double /*max_delay*/)
+    {
+    }
+    void setUseRtPriority(bool use) { mUseRtPriority = use; }
 
-signals:
+   signals:
 
     void signalError(const char* error_message);
     void signalReceivedConnectionFromPeer();
-    void signalCeaseTransmission(const QString &reason = "");
-
-protected:
+    void signalCeaseTransmission(const QString& reason = "");
 
+   protected:
     /** \brief Get the Run Mode of the object
-   * \return SENDER or RECEIVER
-   */
+     * \return SENDER or RECEIVER
+     */
     runModeT getRunMode() const { return mRunMode; }
 
     /// Boolean stop the execution of the thread
@@ -204,29 +203,25 @@ protected:
     volatile bool mHasPacketsToReceive;
     QMutex mMutex;
 
+   private:
+    int mLocalPort;           ///< Local Port number to Bind
+    int mPeerPort;            ///< Peer Port number to Bind
+    const runModeT mRunMode;  ///< Run mode, either SENDER or RECEIVER
 
-private:
-
-    int mLocalPort; ///< Local Port number to Bind
-    int mPeerPort; ///< Peer Port number to Bind
-    const runModeT mRunMode; ///< Run mode, either SENDER or RECEIVER
-
-    struct sockaddr_in mLocalIPv4Addr; ///< Local IPv4 Address struct
-    struct sockaddr_in mPeerIPv4Addr; ///< Peer IPv4 Address struct
+    struct sockaddr_in mLocalIPv4Addr;  ///< Local IPv4 Address struct
+    struct sockaddr_in mPeerIPv4Addr;   ///< Peer IPv4 Address struct
 
     /// Number of clients running to check for ports already used
     /// \note Unimplemented, try to find another way to check for used ports
     static int sClientsRunning;
 
-    size_t mAudioPacketSize; ///< Packet audio part size
-
+    size_t mAudioPacketSize;  ///< Packet audio part size
 
     /// \todo check a better way to access the header from the subclasses
-protected:
-    //PacketHeader* mHeader; ///< Packet Header
-    JackTrip* mJackTrip; ///< JackTrip mediator class
+   protected:
+    // PacketHeader* mHeader; ///< Packet Header
+    JackTrip* mJackTrip;  ///< JackTrip mediator class
     bool mUseRtPriority;
-
 };
 
 #endif
diff --git a/src/DataProtocolPOSIX.cpp.tmp b/src/DataProtocolPOSIX.cpp.tmp
deleted file mode 100644 (file)
index 2884664..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-//*****************************************************************
-/*
-  JackTrip: A System for High-Quality Audio Network Performance
-  over the Internet
-
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
-  SoundWIRE group at CCRMA, Stanford University.
-
-  Permission is hereby granted, free of charge, to any person
-  obtaining a copy of this software and associated documentation
-  files (the "Software"), to deal in the Software without
-  restriction, including without limitation the rights to use,
-  copy, modify, merge, publish, distribute, sublicense, and/or sell
-  copies of the Software, and to permit persons to whom the
-  Software is furnished to do so, subject to the following
-  conditions:
-
-  The above copyright notice and this permission notice shall be
-  included in all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-  OTHER DEALINGS IN THE SOFTWARE.
-*/
-//*****************************************************************
-
-/**
- * \file DataProtocol.cpp
- * \author Juan-Pablo Caceres
- * \date June 2008
- */
-
-#include "DataProtocol.h"
-#include "jacktrip_globals.h"
-#include "JackAudioInterface.h"
-#include "PacketHeader.h"
-
-#include <iostream>
-#include <cstdlib>
-
-#include <QHostInfo>
-#include <QHostAddress>
-
-using std::cout; using std::endl;
-
-//*******************************************************************************
-DataProtocol::DataProtocol(const runModeT runmode,
-                           const packetHeaderTypeT headertype) :
-    mRunMode(runmode), mStopped(false), mHasPacketsToReceive(false), mHeader(NULL)
-{
-    //--------PROTOTYPE-------------------------
-    if ( headertype == DEFAULT ) {
-        mHeader = new DefaultHeader;
-    }
-    else if ( headertype == JAMLINK ) {
-        mHeader = new JamLinkHeader;
-    }
-    //------------------------------------------
-
-    // Base ports gInputPort_0 and gOutputPort_0defined at globals.h
-    if (mRunMode == RECEIVER) {
-        mLocalPort = gInputPort_0;
-        mPeerPort = gOutputPort_0;
-    }
-    else if (mRunMode == SENDER) {
-        mLocalPort = gOutputPort_0;
-        mPeerPort = gInputPort_0;
-    }
-
-    this->setLocalIPv4Address();
-}
-
-
-//*******************************************************************************
-DataProtocol::~DataProtocol()
-{
-    delete mHeader;
-}
-
-
-//*******************************************************************************
-void DataProtocol::stop()
-{
-    mStopped = true;
-}
-
-
-//*******************************************************************************
-void DataProtocol::setLocalIPv4Address()
-{
-    bzero(&mLocalIPv4Addr, sizeof(mLocalIPv4Addr));
-    mLocalIPv4Addr.sin_family = AF_INET;//AF_INET: IPv4 Protocol
-    mLocalIPv4Addr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY: let the kernel decide the active address
-    mLocalIPv4Addr.sin_port = htons(mLocalPort);//set local port
-    //std::cout << "mLocalPort = " << mLocalPort << std::endl;
-}
-
-
-//*******************************************************************************
-void DataProtocol::setPeerIPv4Address(const char* peerHostOrIP)
-{
-    const char* peerAddress; // dotted decimal address to use in the struct below
-
-    /// \todo Improve this to make it work also with local ip numbers, in a LAN,
-    /// that don't have an assigned host name
-    /*
-  // Resolve Peer IPv4 with either doted integer IP or hostname
-  //----------------------------------------------------------
-  std::cout << "Resolving Peer IPv4 address..." << std::endl;
-  QHostInfo info = QHostInfo::fromName(peerHostOrIP);
-  if ( !info.addresses().isEmpty() ) {
-    std::cout << "Peer Address Found" << std::endl;
-    QHostAddress address = info.addresses().first(); // use the first address in list
-    peerAddress = address.toString().toLatin1();
-  }
-  else {
-    std::cerr << "ERROR: Could not set Peer IP Address" << std::endl;
-    std::cerr << "Check that it's public or that the hostname exists" << std::endl;
-    std::exit(1);
-  }
-  */
-
-    // temporary implementation to make this work
-    /// \todo change this
-    peerAddress = peerHostOrIP;
-
-    // Set the Peer IPv4 Address struct
-    //---------------------------------
-    bzero(&mPeerIPv4Addr, sizeof(mPeerIPv4Addr));
-    mPeerIPv4Addr.sin_family = AF_INET;//AF_INET: IPv4 Protocol
-    mPeerIPv4Addr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY: let the kernel decide the active address
-    mPeerIPv4Addr.sin_port = htons(mPeerPort);//set Peer port
-    //std::cout << "mPeerPort = " << mPeerPort << std::endl;
-    int nPeer = inet_pton(AF_INET, peerAddress, &mPeerIPv4Addr.sin_addr);
-    if ( nPeer == 1 ) {
-        std::cout << "Successful Set Peer Address" << std::endl;
-    }
-    else if ( nPeer == 0 ) {
-        std::cout << "Error: Incorrect presentation format for address" << std::endl;
-        std::exit(1);
-    }
-    else {
-        std::cout << "Error: Could not set Peer Address" << std::endl;
-        std::exit(1);
-    }
-
-}
-
-
-//*******************************************************************************
-void DataProtocol::setRingBuffer(std::tr1::shared_ptr<RingBuffer> RingBuffer)
-{
-    mRingBuffer = RingBuffer;
-}
-
-
-//*******************************************************************************
-void DataProtocol::run()
-{
-    std::cout << "Running DataProtocol Thread" << std::endl;
-    std::cout << gPrintSeparator << std::endl;
-    size_t packet_size = getAudioPacketSize();
-    int8_t packet[packet_size];
-
-    switch ( mRunMode )
-    {
-    case RECEIVER :
-        //-----------------------------------------------------------------------------------
-        // Wait for the first packet to be ready and obtain address
-        // from that packet
-        /// \todo here is the place to read the datagram and check if the settings match
-        /// the local ones. Extract this information from the header
-        std::cout << "Waiting for Peer..." << std::endl;
-        this->receivePacket( (char*) packet, packet_size); // This blocks waiting for the first packet
-        std::cout << "Received Connection for Peer!" << std::endl;
-
-        while ( !mStopped )
-        {
-            //std::cout << "RECEIVING PACKETS" << std::endl;
-            /// \todo Set a timer to report packats arriving too late
-            //std::cout << "RECIEVING THREAD" << std::endl;
-
-            this->receivePacket( (char*) packet, packet_size);
-            /// \todo Change this to match buffer size
-            //std::cout << "PACKET RECIEVED" << std::endl;
-            mRingBuffer->insertSlotBlocking(packet);
-            //std::cout << buf << std::endl;
-        }
-        break;
-
-
-    case SENDER :
-        //-----------------------------------------------------------------------------------
-        while ( !mStopped )
-        {
-            //std::cout << "SENDING PACKETS --------------------------" << std::endl;
-            /// \todo This should be blocking, since we don't want to send trash
-            mRingBuffer->readSlotBlocking(packet);
-            //std::cout << "SENDING PACKETS" << std::endl;
-            this->sendPacket( (char*) packet, packet_size);
-            //std::cout << "SENDING PACKETS DONE!!!" << std::endl;
-            //this->sendPacket( sendtest, 64);
-        }
-        break;
-    }
-}
-
-void DataProtocol::setAudioPacketSize(size_t size_bytes)
-{
-    mAudioPacketSize = size_bytes;
-}
-
-
-size_t DataProtocol::getAudioPacketSize()
-{
-    return(mAudioPacketSize);
-}
diff --git a/src/DataProtocolPOSIX.h.tmp b/src/DataProtocolPOSIX.h.tmp
deleted file mode 100644 (file)
index 68e22bd..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-//*****************************************************************
-/*
-  JackTrip: A System for High-Quality Audio Network Performance
-  over the Internet
-
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
-  SoundWIRE group at CCRMA, Stanford University.
-
-  Permission is hereby granted, free of charge, to any person
-  obtaining a copy of this software and associated documentation
-  files (the "Software"), to deal in the Software without
-  restriction, including without limitation the rights to use,
-  copy, modify, merge, publish, distribute, sublicense, and/or sell
-  copies of the Software, and to permit persons to whom the
-  Software is furnished to do so, subject to the following
-  conditions:
-
-  The above copyright notice and this permission notice shall be
-  included in all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-  OTHER DEALINGS IN THE SOFTWARE.
-*/
-//*****************************************************************
-
-/**
- * \file DataProtocol.h
- * \author Juan-Pablo Caceres
- * \date June 2008
- */
-
-#ifndef __DATAPROTOCOL_H__
-#define __DATAPROTOCOL_H__
-
-//#include <sys/socket.h> //basic socket definitions
-#include <netinet/in.h> //sockaddr_in{} and other Internet defns
-#include <arpa/inet.h> //inet(3) functions
-#include <netdb.h>
-#include <tr1/memory> //for shared_ptr
-
-#include <QThread>
-
-#include "RingBuffer.h"
-//#include "PacketHeader.h"
-class PacketHeader; // forward declaration
-
-
-/** \brief Base class that defines the transmission protocol.
- *
- * This base class defines most of the common method to setup and connect
- * sockets using the individual protocols (UDP, TCP, SCTP, etc).
- *
- * The class has to be constructed using one of two modes (runModeT):\n
- * - SENDER
- * - RECEIVER
- *
- * This has to be specified as a constructor argument. When using, create two instances
- * of the class, one to receive and one to send packets. Each instance will run on a
- * separate thread.
- *
- * Redundancy and forward error correction should be implemented on each
- * Transport protocol, cause they depend on the protocol itself
- *
- * \todo This Class should contain definition of jacktrip header and basic funcionality to obtain
- * local machine IPs and maybe functions to manipulate IPs.
- * Redundancy and forward error correction should be implemented on each
- * Transport protocol, cause they depend on the protocol itself
- *
- * \todo The transport protocol itself has to be implemented subclassing this class, i.e.,
- * using a TCP or UDP protocol.
- *
- * Even if the underlined transmission protocol is stream oriented (as in TCP),
- * we send packets that are the size of the audio processing buffer.
- * Use AudioInterface::getBufferSize to obtain this value.
- *
- * Each transmission (i.e., inputs and outputs) run on its own thread.
- */
-class DataProtocol : public QThread
-{
-public:
-
-    /// \brief Enum to define packet header types
-    enum packetHeaderTypeT {
-        DEFAULT, ///< Default application header
-        JAMLINK ///< Header to use with Jamlinks
-    };
-
-    /// \brief Enum to define class modes, SENDER or RECEIVER
-    enum runModeT {
-        SENDER, ///< Set class as a Sender (send packets)
-        RECEIVER ///< Set class as a Receiver (receives packets)
-    };
-
-
-    /** \brief The class constructor
-   * \param runmode Sets the run mode, use either SENDER or RECEIVER
-   */
-    DataProtocol(const runModeT runmode,
-                 const packetHeaderTypeT headertype = DEFAULT);
-
-    /// \brief The class destructor
-    virtual ~DataProtocol();
-
-    /** \brief Sets the peer (remote) IPv4 address struct
-   * \param peerHostOrIP Either an IPv4 dotted integer number or a hostname
-   */
-    virtual void setPeerIPv4Address(const char* peerHostOrIP);
-
-    /** \brief Receive a packet from the UDPSocket
-   *
-   * This method has to be implemented in the sub-classes
-   * \param buf Location at which to store the buffer
-   * \param n size of packet to receive in bytes
-   * \return number of bytes read, -1 on error
-   */
-    virtual size_t receivePacket(char* buf, size_t n) = 0;
-
-    /** \brief Sends a packet
-   *
-   * This method has to be implemented in the sub-classes
-   * \param buff Buffer to send
-   * \param n size of packet to receive in bytes
-   * \return number of bytes read, -1 on error
-   */
-    virtual size_t sendPacket(const char* buff, size_t n) = 0;
-
-    /** \brief Implements the thread loop
-   *
-   * Depending on the runmode, with will run a RECEIVE thread or
-   * SEND thread
-   */
-    virtual void run();
-
-    /** \brief Set the pointer to the RingBuffer that'll be use to read
-   * or write
-   */
-    void setRingBuffer(std::tr1::shared_ptr<RingBuffer> RingBuffer);
-
-    /// \brief Stops the execution of the Thread
-    void stop();
-
-    /** \brief Sets the size of the audio part of the packets
-   * \param size_bytes Size in bytes
-   */
-    void setAudioPacketSize(size_t size_bytes);
-
-    /** \brief Get the size of the audio part of the packets
-   * \return size_bytes Size in bytes
-   */
-    size_t getAudioPacketSize();
-
-    //virtual void getIPAddressFromFirstPacket() = 0;
-
-
-protected:
-
-    /** \brief Sets the local IPv4 address struct
-   *
-   * It uses the default active device.
-   */
-    virtual void setLocalIPv4Address();
-
-    /** \brief Get the Run Mode of the object
-   * \return SENDER or RECEIVER
-   */
-    runModeT getRunMode() const { return mRunMode; };
-
-    /** \brief Returns the Local machine IPv4 socket address stuct
-   * \return Socket address stuct
-   */
-    const sockaddr_in& getLocalIPv4AddressStruct() const { return mLocalIPv4Addr; };
-
-    /** \brief Returns the Peer  IPv4 socket address stuct
-   * \return Socket address stuct
-   */
-    const sockaddr_in& getPeerIPv4AddressStruct() const { return mPeerIPv4Addr; };
-
-
-private:
-
-    int mLocalPort; ///< Local Port number to Bind
-    int mPeerPort; ///< Peer Port number to Bind
-    const runModeT mRunMode; ///< Run mode, either SENDER or RECEIVER
-
-    struct sockaddr_in mLocalIPv4Addr; ///< Local IPv4 Address struct
-    struct sockaddr_in mPeerIPv4Addr; ///< Peer IPv4 Address struct
-
-    /// Smart Pointer to RingBuffer to read (for SENDER) or write (for RECEIVER)
-    std::tr1::shared_ptr<RingBuffer> mRingBuffer;
-
-    /// Boolean stop the execution of the thread
-    volatile bool mStopped;
-    /// Boolean to indicate if the RECEIVER is waiting to obtain peer address
-    volatile bool mHasPeerAddress;
-    /// Boolean that indicates if a packet was received
-    volatile bool mHasPacketsToReceive;
-
-    /// Number of clients running to check for ports already used
-    /// \note Unimplemented, try to find another way to check for used ports
-    static int sClientsRunning;
-
-    size_t mAudioPacketSize; ///< Packet audio part size
-
-    PacketHeader* mHeader; ///< Packet Header
-};
-
-#endif
index 086d40e03b05ba1fef13c99a572284619b251b36..ad2acd126c6d85f69eabf3315b2a30db92e15742 100644 (file)
 
 #pragma once
 
-#include "ProcessPlugin.h"
-#include "Limiter.h"
+#include <cassert>
+#include <vector>
+
 #include "Compressor.h"
 #include "CompressorPresets.h"
+#include "Limiter.h"
+#include "ProcessPlugin.h"
 #include "Reverb.h"
-#include <assert.h>
-#include <vector>
 
 class Effects
 {
-  int mNumIncomingChans;
-  int mNumOutgoingChans;
-  int gVerboseFlag = 0;
-public:
-  enum LIMITER_MODE {
-                     LIMITER_NONE,
-                     LIMITER_INCOMING, // from network
-                     LIMITER_OUTGOING, // to network
-                     LIMITER_BOTH
-  };
-private:
-  LIMITER_MODE mLimit; ///< audio limiter controls
-  unsigned int mNumClientsAssumed; ///< assumed number of clients (audio sources)
-  double limiterWarningAmplitude;
-
-  enum InOrOut { IO_NEITHER, IO_IN, IO_OUT } io;
-  bool inCompressor = false;
-  bool outCompressor = false;
-  bool inZitarev = false;
-  bool outZitarev = false;
-  bool inFreeverb = false;
-  bool outFreeverb = false;
-  bool incomingEffectsAllocated = false;
-  bool outgoingEffectsAllocated = false;
-  Compressor* inCompressorP = nullptr;
-  Compressor* outCompressorP = nullptr;
-  CompressorPreset inCompressorPreset = CompressorPresets::voice; // ./CompressorPresets.h
-  CompressorPreset outCompressorPreset = CompressorPresets::voice;
-  Reverb* inZitarevP = nullptr;
-  Reverb* outZitarevP = nullptr;
-  Reverb* inFreeverbP = nullptr;
-  Reverb* outFreeverbP = nullptr;
-  int parenLevel = 0;
-  char lastEffect = '\0';
-  float zitarevInLevel = 1.0f; // "Level" = wetness from 0 to 1
-  float freeverbInLevel = 1.0f;
-  float zitarevOutLevel = 1.0f;
-  float freeverbOutLevel = 1.0f;
-  float mReverbLevel; // for backward compatibility: 0-1 Freeverb, 1-2 Zitarev
-  Limiter* inLimiterP = nullptr;
-  Limiter* outLimiterP = nullptr;
-
-public:
-
-  Effects(bool outGoingLimiterOn=true) :
-    mNumIncomingChans(2),
-    mNumOutgoingChans(2),
-    mLimit(outGoingLimiterOn ? LIMITER_OUTGOING : LIMITER_NONE),
-    mNumClientsAssumed(2),
-    limiterWarningAmplitude(0.0)
-  {}
-
-  ~Effects() {
-    /*
+    int mNumIncomingChans;
+    int mNumOutgoingChans;
+    int gVerboseFlag = 0;
+
+   public:
+    enum LIMITER_MODE {
+        LIMITER_NONE,
+        LIMITER_INCOMING,  // from network
+        LIMITER_OUTGOING,  // to network
+        LIMITER_BOTH
+    };
+
+   private:
+    LIMITER_MODE mLimit;              ///< audio limiter controls
+    unsigned int mNumClientsAssumed;  ///< assumed number of clients (audio sources)
+    double limiterWarningAmplitude;
+
+    enum InOrOut { IO_NEITHER, IO_IN, IO_OUT } io;
+    bool inCompressor             = false;
+    bool outCompressor            = false;
+    bool inZitarev                = false;
+    bool outZitarev               = false;
+    bool inFreeverb               = false;
+    bool outFreeverb              = false;
+    bool incomingEffectsAllocated = false;
+    bool outgoingEffectsAllocated = false;
+    Compressor* inCompressorP     = nullptr;
+    Compressor* outCompressorP    = nullptr;
+    CompressorPreset inCompressorPreset =
+        CompressorPresets::voice;  // ./CompressorPresets.h
+    CompressorPreset outCompressorPreset = CompressorPresets::voice;
+    Reverb* inZitarevP                   = nullptr;
+    Reverb* outZitarevP                  = nullptr;
+    Reverb* inFreeverbP                  = nullptr;
+    Reverb* outFreeverbP                 = nullptr;
+    int parenLevel                       = 0;
+    char lastEffect                      = '\0';
+    float zitarevInLevel                 = 1.0f;  // "Level" = wetness from 0 to 1
+    float freeverbInLevel                = 1.0f;
+    float zitarevOutLevel                = 1.0f;
+    float freeverbOutLevel               = 1.0f;
+    float mReverbLevel;  // for backward compatibility: 0-1 Freeverb, 1-2 Zitarev
+    Limiter* inLimiterP  = nullptr;
+    Limiter* outLimiterP = nullptr;
+
+   public:
+    Effects(bool outGoingLimiterOn = true)
+        : mNumIncomingChans(2)
+        , mNumOutgoingChans(2)
+        , mLimit(outGoingLimiterOn ? LIMITER_OUTGOING : LIMITER_NONE)
+        , mNumClientsAssumed(2)
+        , limiterWarningAmplitude(0.0)
+    {
+    }
+
+    ~Effects()
+    {
+        /*
       Plugin ownership presently passes to JackTrip,
       and deletion occurs in AudioInterface.cpp. See
         delete mProcessPluginsFromNetwork[i];
@@ -115,457 +120,576 @@ public:
       but if everyone can compile C++11,
       let's switch to using std::unique_ptr.
     */
-  }
-
-  unsigned int getNumClientsAssumed() { return mNumClientsAssumed; }
-
-  LIMITER_MODE getLimit() { return mLimit; }
-  void setNoLimiters() { mLimit = LIMITER_NONE; }
-
-  ProcessPlugin* getInCompressor() { return inCompressorP; }
-  ProcessPlugin* getOutCompressor() { return outCompressorP; }
-  ProcessPlugin* getInZitarev() { return inZitarevP; }
-  ProcessPlugin* getOutZitarev() { return outZitarevP; }
-  ProcessPlugin* getInFreeverb() { return inFreeverbP; }
-  ProcessPlugin* getOutFreeverb() { return outFreeverbP; }
-  ProcessPlugin* getInLimiter() { return inLimiterP; }
-  ProcessPlugin* getOutLimiter() { return outLimiterP; }
-
-  bool getHaveEffect() {
-    return
-      inCompressor || outCompressor ||
-      inZitarev || outZitarev ||
-      inFreeverb || outFreeverb ;
-  }
-
-  bool getHaveLimiter() {
-    return mLimit != LIMITER_NONE;
-  }
-
-  void setVerboseFlag(int v) {
-    gVerboseFlag = v;
-  }
-
-  int getNumIncomingChans() {
-    return mNumIncomingChans;
-  }
-
-  int getOutgoingNumChans() {
-    return mNumOutgoingChans;
-  }
-
-  // call these next two after it is decided what effects we will be using for the duration:
-
-  std::vector<ProcessPlugin*> allocateIncomingEffects(int nIncomingChans) {
-    mNumIncomingChans = nIncomingChans;
-    if (incomingEffectsAllocated) {
-      std::cerr << "*** Effects.h: attempt to allocate incoming effects more than once\n";
-      std::exit(1);
     }
-    std::vector<ProcessPlugin*> incomingEffects;
-    if (inCompressor) {
-      assert(inCompressorP == nullptr);
-      inCompressorP = new Compressor(mNumIncomingChans, gVerboseFlag, inCompressorPreset);
-      if (gVerboseFlag) { std::cout << "Set up INCOMING COMPRESSOR\n"; }
-      incomingEffects.push_back(inCompressorP);
-    }
-    if (inZitarev) {
-      assert(inZitarevP == nullptr);
-      inZitarevP = new Reverb(mNumIncomingChans,mNumIncomingChans, 1.0 + zitarevInLevel);
-      if (gVerboseFlag) { std::cout << "Set up INCOMING REVERB (Zitarev)\n"; }
-      incomingEffects.push_back(inZitarevP);
-    }
-    if (inFreeverb) {
-      assert(inFreeverbP == nullptr);
-      inFreeverbP = new Reverb(mNumIncomingChans, mNumIncomingChans, freeverbInLevel);
-      if (gVerboseFlag) { std::cout << "Set up INCOMING REVERB (Freeverb)\n"; }
-      incomingEffects.push_back(inFreeverbP);
-    }
-    // LIMITER MUST GO LAST:
-    if ( mLimit == LIMITER_INCOMING || mLimit == LIMITER_BOTH) {
-      if (gVerboseFlag) {
-        std::cout << "Set up INCOMING LIMITER for " << mNumIncomingChans << " input channels\n";
-      }
-      assert(inLimiterP == nullptr);
-      inLimiterP = new Limiter(mNumIncomingChans, 1, gVerboseFlag); // mNumClientsAssumed not needed this direction
-      // Never needed in normal practice for incoming limiter: inLimiterP->setWarningAmplitude(limiterWarningAmplitude);
-      incomingEffects.push_back(inLimiterP);
-    }
-    incomingEffectsAllocated = true;
-    return incomingEffects;
-  }
-
-  std::vector<ProcessPlugin*> allocateOutgoingEffects(int nOutgoingChans) {
-    mNumOutgoingChans = nOutgoingChans;
-    if (outgoingEffectsAllocated) {
-      std::cerr << "*** Effects.h: attempt to allocate outgoing effects more than once\n";
-      std::exit(1);
-    }
-    std::vector<ProcessPlugin*> outgoingEffects;
-    if (outCompressor) {
-      assert(outCompressorP == nullptr);
-      outCompressorP = new Compressor(mNumOutgoingChans, gVerboseFlag, outCompressorPreset);
-      if (gVerboseFlag) { std::cout << "Set up OUTGOING COMPRESSOR\n"; }
-      outgoingEffects.push_back(outCompressorP);
-    }
-    if (outZitarev) {
-      assert(outZitarevP == nullptr);
-      outZitarevP = new Reverb(mNumOutgoingChans, mNumOutgoingChans, 1.0 + zitarevOutLevel);
-      if (gVerboseFlag) { std::cout << "Set up OUTGOING REVERB (Zitarev)\n"; }
-      outgoingEffects.push_back(outZitarevP);
-    }
-    if (outFreeverb) {
-      assert(outFreeverbP == nullptr);
-      outFreeverbP = new Reverb(mNumOutgoingChans, mNumOutgoingChans, freeverbOutLevel);
-      if (gVerboseFlag) { std::cout << "Set up OUTGOING REVERB (Freeverb)\n"; }
-      outgoingEffects.push_back(outFreeverbP);
+
+    unsigned int getNumClientsAssumed() { return mNumClientsAssumed; }
+
+    LIMITER_MODE getLimit() { return mLimit; }
+    void setNoLimiters() { mLimit = LIMITER_NONE; }
+
+    ProcessPlugin* getInCompressor() { return inCompressorP; }
+    ProcessPlugin* getOutCompressor() { return outCompressorP; }
+    ProcessPlugin* getInZitarev() { return inZitarevP; }
+    ProcessPlugin* getOutZitarev() { return outZitarevP; }
+    ProcessPlugin* getInFreeverb() { return inFreeverbP; }
+    ProcessPlugin* getOutFreeverb() { return outFreeverbP; }
+    ProcessPlugin* getInLimiter() { return inLimiterP; }
+    ProcessPlugin* getOutLimiter() { return outLimiterP; }
+
+    bool getHaveEffect()
+    {
+        return inCompressor || outCompressor || inZitarev || outZitarev || inFreeverb
+               || outFreeverb;
     }
-    // LIMITER MUST GO LAST:
-    if ( mLimit != LIMITER_NONE) {
-      if ( mLimit == LIMITER_OUTGOING || mLimit == LIMITER_BOTH) {
-        if (gVerboseFlag) {
-          std::cout << "Set up OUTGOING LIMITER for "
-                    << mNumOutgoingChans << " output channels and "
-                    << mNumClientsAssumed << " assumed client(s) ...\n";
+
+    bool getHaveLimiter() { return mLimit != LIMITER_NONE; }
+
+    void setVerboseFlag(int v) { gVerboseFlag = v; }
+
+    int getNumIncomingChans() { return mNumIncomingChans; }
+
+    int getOutgoingNumChans() { return mNumOutgoingChans; }
+
+    // call these next two after it is decided what effects we will be using for the
+    // duration:
+
+    std::vector<ProcessPlugin*> allocateIncomingEffects(int nIncomingChans)
+    {
+        mNumIncomingChans = nIncomingChans;
+        if (incomingEffectsAllocated) {
+            std::cerr
+                << "*** Effects.h: attempt to allocate incoming effects more than once\n";
+            std::exit(1);
         }
-        assert(outLimiterP == nullptr);
-        outLimiterP = new Limiter(mNumOutgoingChans,mNumClientsAssumed);
-        outLimiterP->setWarningAmplitude(limiterWarningAmplitude);
-        // do not have mSampleRate yet, so cannot call limiter->init(mSampleRate) here
-        outgoingEffects.push_back(outLimiterP);
-      }
-    }
-    outgoingEffectsAllocated = true;
-    return outgoingEffects;
-  }
-
-  void printHelp(char* command, char helpCase) {
-    std::cout << "HELP for `" << command << "' (end-of-line comments start with `//')\n";
-    std::cout << "\n";
-    std::cout << "Examples:\n";
-    std::cout << "\n";
-    if (helpCase == 0 || helpCase == 'f') { //
-      std::cout << command << " 0.3 // add a default outgoing compressor (for voice) and incoming reverb (freeverb) with wetness 0.3 (wetness from 0 to 1)\n";
-      std::cout << command << " 1.3 // add a default outgoing compressor (for voice) and incoming reverb (zitarev) with wetness 0.3 = 1.3-1 (i.e., 1+ to 2 is for zitarev)\n";
-      std::cout << "\n";
-      std::cout << command << " \"o:c i:f(0.3)\" // outgoing-compressor and incoming-freeverb example above using more general string argument\n";
-      std::cout << command << " \"o:c i:z(0.3)\" // outgoing-compressor and incoming-zitarev example above using more general string argument\n";
-      std::cout << command << " \"o:c(1)\" // outgoing compressor, using preset 1 (designed for voice - see below for details)\n";
-      std::cout << command << " \"o:c(2)\" // outgoing compressor, using preset 2 (for horns)\n";
-      std::cout << command << " \"o:c(3)\" // outgoing compressor, using preset 3 (for snare)\n";
-      std::cout << command << " \"o:c(c:compressionRatio t:thresholdDB a:attackTimeMS r:releaseTimeMS g:makeUpGainDB)\" // general compression parameter specification (all floats)\n";
-      std::cout << command << " \"o:c(c:2 t:-24 a:15 r:40 g:2)\"   // outgoing compressor, preset 1 details\n";
-      std::cout << command << " \"o:c(c:3 t:-10 a:100 r:250 g:2)\" // outgoing compressor, preset 2 details\n";
-      std::cout << command << " \"o:c(c:5 t:-4 a:5 r:150 g:3)\"    // outgoing compressor, preset 3 details\n";
-      std::cout << "  For these and more suggested compression settings, see http://www.anythingpeaceful.org/sonar/settings/comp.html\n";
-      std::cout << "\n";
-    }
-    if (helpCase == 0 || helpCase == 'O') { // limiter (-O option most likely)
-      std::cout << command << " i   // add limiter to INCOMING audio from network (only helpful for floats, i.e., -b32 used by server)\n";
-      std::cout << command << " o   // add limiter to OUTGOING audio to network (prevents your sound from harshly clipping going out)\n";
-      std::cout << command << " ow  // also warn and advise on levels when outgoing limiter compresses audio near clipping\n";
-      std::cout << command << " io  // add limiter to both INCOMING and OUTGOING audio\n";
-      std::cout << command << " iow // limiters both ways and compression warnings on outgoing direction only\n";
-      std::cout << "\n";
-    }
-    if (helpCase == 0 || helpCase == 'a') { // assumedNumClients (-a option)
-      std::cout << command << " 1 // assume 1 client - fine for loopback test, or if only one client plays at a time, or server uses -b32 and -Oi is used\n";
-      std::cout << command << " 2 // assume 2 clients possibly playing at the same time\n";
-      std::cout << command << " N // any integer N>0 can be used - the outgoing limiter will divide final amplitude by 1/sqrt(N) to reduce overages in server\n";
-      std::cout << "\n";
-    }
-  }
-
-  // ----------- Compressor stuff --------------
-
-  int setCompressorPresetIndexFrom1(unsigned long presetIndexFrom1, InOrOut io) {
-    int returnCode = 0;
-    if (presetIndexFrom1 <= 0 || presetIndexFrom1 > CompressorPresets::numPresets) {
-      std::cerr << "*** Effects.h: setCompressorPresetFrom1: Index " << presetIndexFrom1 << " out of range\n";
-      returnCode = 1;
-    } else {
-      CompressorPreset stdPreset = CompressorPresets::standardPresets[presetIndexFrom1-1];
-      if (io == IO_IN) {
-        inCompressorPreset = stdPreset;
-      } else if (io == IO_OUT) {
-        outCompressorPreset = stdPreset;
-      } else if (io != IO_NEITHER) {
-        std::cerr << "*** Effects.h: setCompressorPresetFrom1: Invalid InOrOut value " << io << "\n";
-        returnCode = 1;
-      }
+        std::vector<ProcessPlugin*> incomingEffects;
+        if (inCompressor) {
+            assert(inCompressorP == nullptr);
+            inCompressorP =
+                new Compressor(mNumIncomingChans, gVerboseFlag, inCompressorPreset);
+            if (gVerboseFlag) { std::cout << "Set up INCOMING COMPRESSOR\n"; }
+            incomingEffects.push_back(inCompressorP);
+        }
+        if (inZitarev) {
+            assert(inZitarevP == nullptr);
+            inZitarevP =
+                new Reverb(mNumIncomingChans, mNumIncomingChans, 1.0 + zitarevInLevel);
+            if (gVerboseFlag) { std::cout << "Set up INCOMING REVERB (Zitarev)\n"; }
+            incomingEffects.push_back(inZitarevP);
+        }
+        if (inFreeverb) {
+            assert(inFreeverbP == nullptr);
+            inFreeverbP =
+                new Reverb(mNumIncomingChans, mNumIncomingChans, freeverbInLevel);
+            if (gVerboseFlag) { std::cout << "Set up INCOMING REVERB (Freeverb)\n"; }
+            incomingEffects.push_back(inFreeverbP);
+        }
+        // LIMITER MUST GO LAST:
+        if (mLimit == LIMITER_INCOMING || mLimit == LIMITER_BOTH) {
+            if (gVerboseFlag) {
+                std::cout << "Set up INCOMING LIMITER for " << mNumIncomingChans
+                          << " input channels\n";
+            }
+            assert(inLimiterP == nullptr);
+            inLimiterP = new Limiter(
+                mNumIncomingChans, 1,
+                gVerboseFlag);  // mNumClientsAssumed not needed this direction
+            // Never needed in normal practice for incoming limiter:
+            // inLimiterP->setWarningAmplitude(limiterWarningAmplitude);
+            incomingEffects.push_back(inLimiterP);
+        }
+        incomingEffectsAllocated = true;
+        return incomingEffects;
     }
-    return returnCode;
-  }
-
-  int parseCompresserArgs(char* args, InOrOut inOrOut) {
-    // args can be integerPresetNumberFrom1 or (all optional, any order):
-    // c:compressionRatio, a:attackTimeMS, r:releaseTimeMS, g:makeUpGain
-    int returnCode = 0;
-    if (not isalpha(args[0])) {
-      int presetIndexFrom1 = atoi(args);
-      setCompressorPresetIndexFrom1(presetIndexFrom1,inOrOut);
-    } else {
-      // args can be presetIndexFrom1, handled above, or (all optional, any order):
-      // c(c:compressionRatio, t:thresholdDB, a:attackTimeMS, r:releaseTimeMS, g:makeUpGainDB)
-      // See ./CompressorPresets.h for example settings.
-      if (gVerboseFlag) {
-        std::cout << "parseCompressorArgs = " << args << std::endl;
-      }
-      ulong argLen = strlen(args);
-      char lastParam = '\0';
-
-      CompressorPreset newPreset(CompressorPresets::voice); // Anything unset gets voice value (most gentle)
-
-      int nSkip = 0;
-      for (ulong i=0; i<argLen; i++) {
-        if (nSkip > 0) {
-          nSkip--;
-          continue;
+
+    std::vector<ProcessPlugin*> allocateOutgoingEffects(int nOutgoingChans)
+    {
+        mNumOutgoingChans = nOutgoingChans;
+        if (outgoingEffectsAllocated) {
+            std::cerr
+                << "*** Effects.h: attempt to allocate outgoing effects more than once\n";
+            std::exit(1);
         }
-        char ch = args[i];
-        switch(ch) {
-        case ' ': break;
-        case '\t': break;
-        case 'c': case 't': case 'a': case 'r': case 'g':
-          lastParam = ch;
-          break;
-        case ':': break;
-        default: // must be a floating-point number at this point:
-          if (ch!='-' && isalpha(ch)) {
-            std::cerr << "*** Effects.h: parseCompressorArgs: " << ch << " not recognized in args = " << args << "\n";
-            returnCode = 2;
-          } else { // must have a digit or '-' or '.'
-            assert(ch=='-'||ch=='.'||isdigit(ch));
-            float paramValue = -1.0e10;
-            for (ulong j=i; j<argLen; j++) { // scan ahead for end of number
-              if (args[j] == ',' || args[j] == ' ' || j==argLen-1) { // comma or space required between parameters
-                char argsj = args[j];
-                if (j<argLen-1) { // there's more
-                  args[j] = '\0';
+        std::vector<ProcessPlugin*> outgoingEffects;
+        if (outCompressor) {
+            assert(outCompressorP == nullptr);
+            outCompressorP =
+                new Compressor(mNumOutgoingChans, gVerboseFlag, outCompressorPreset);
+            if (gVerboseFlag) { std::cout << "Set up OUTGOING COMPRESSOR\n"; }
+            outgoingEffects.push_back(outCompressorP);
+        }
+        if (outZitarev) {
+            assert(outZitarevP == nullptr);
+            outZitarevP =
+                new Reverb(mNumOutgoingChans, mNumOutgoingChans, 1.0 + zitarevOutLevel);
+            if (gVerboseFlag) { std::cout << "Set up OUTGOING REVERB (Zitarev)\n"; }
+            outgoingEffects.push_back(outZitarevP);
+        }
+        if (outFreeverb) {
+            assert(outFreeverbP == nullptr);
+            outFreeverbP =
+                new Reverb(mNumOutgoingChans, mNumOutgoingChans, freeverbOutLevel);
+            if (gVerboseFlag) { std::cout << "Set up OUTGOING REVERB (Freeverb)\n"; }
+            outgoingEffects.push_back(outFreeverbP);
+        }
+        // LIMITER MUST GO LAST:
+        if (mLimit != LIMITER_NONE) {
+            if (mLimit == LIMITER_OUTGOING || mLimit == LIMITER_BOTH) {
+                if (gVerboseFlag) {
+                    std::cout << "Set up OUTGOING LIMITER for " << mNumOutgoingChans
+                              << " output channels and " << mNumClientsAssumed
+                              << " assumed client(s) ...\n";
                 }
-                paramValue = atof(&args[i]);
-                args[j] = argsj;
-                nSkip = j-i;
-                break;
-              }
-            }
-            if (paramValue == -1.0e10) {
-              std::cerr << "*** Effects.h: parseCompressorArgs: Could not find parameter for "
-                        << lastParam << " in args = " << args << "\n";
-              returnCode = 2;
-            } else {
-              switch (lastParam) {
-              case 'c':
-                newPreset.ratio = paramValue;
-                break;
-              case 't':
-                  newPreset.thresholdDB = paramValue;
-                break;
-              case 'a':
-                  newPreset.attackMS = paramValue;
-                break;
-              case 'r':
-                  newPreset.releaseMS = paramValue;
-                break;
-              case 'g':
-                  newPreset.makeUpGainDB = paramValue;
-                break;
-              default: // cannot happen:
-                std::cerr << "*** Effects.h: parseCompressorArgs: lastParam " << lastParam << " invalid\n";
-                returnCode = 3; // "reality failure"
-              } // switch(lastParam)
-            } // have valid parameter from atof
-          } // have valid non-alpha char for parameter
-        } // switch(ch)
-      } // for (ulong i=0; i<argLen; i++) {
-      if (inOrOut == IO_IN) {
-        inCompressorPreset = newPreset;
-      } else if (inOrOut == IO_OUT) {
-        outCompressorPreset = newPreset;
-      } else if (inOrOut != IO_NEITHER) {
-        std::cerr << "*** Effects.h: parseCompressorArgs: invalid InOrOut value " << inOrOut << "\n";
-        returnCode = 2;
-      }
-    } // long-form compressor args
-    return returnCode;
-  } // int parseCompresserArgs(char* args, InOrOut inOrOut)
-
-  // ============== General argument processing for all effects =================
-
-  int parseEffectsOptArg(char* cmd, char* optarg) {
-    int returnCode = 0; // 0 means go, 1 means exit without error, higher => error exit
-
-    char c = optarg[0];
-    if (c == '-' || c==0) {
-      // happens when no -f argument specified
-      returnCode = 2;
-    } else if (not isalpha(c)) { // backward compatibility why not?, e.g., "-f 0.5"
-      // -f reverbLevelFloat
-      mReverbLevel = atof(optarg);
-      outCompressor = true;
-      inZitarev = mReverbLevel > 1.0;
-      inFreeverb = mReverbLevel <= 1.0;
-      if (inZitarev) {
-        zitarevInLevel = mReverbLevel - 1.0; // wetness from 0 to 1
-      }
-      if (inFreeverb) {
-        freeverbInLevel = mReverbLevel; // wetness from 0 to 1
-      }
-    } else { // long-form argument:
-      // -f "i:[c][f|z][(reverbLevel)]], o:[c][f|z][(rl)]"
-      // c can be c(integerPresetNumberFrom1) or (all optional, any order):
-      // c(c:compressionRatio, a:attackTimeMS, r:releaseTimeMS, g:makeUpGain)
-      if (gVerboseFlag) {
-        std::cout << cmd << " argument = " << optarg << std::endl;
-      }
-      ulong argLen = strlen(optarg);
-
-      for (ulong i=0; i<argLen; i++) {
-        if (optarg[i]!=')' && parenLevel>0) { continue; }
-        switch(optarg[i]) {
-        case ' ': break;
-        case ',': break;
-        case ';': break;
-        case '\t': break;
-        case 'h': printHelp(cmd,'f'); returnCode = 1; break;
-        case 'i': io=IO_IN; break;
-        case 'o': io=IO_OUT; break;
-        case ':': break;
-        case 'c': if (io==IO_IN) { inCompressor = true; } else if (io==IO_OUT) { outCompressor = true; }
-          else { std::cerr << "-f arg `" << optarg << "' malformed\n"; exit(1); }
-          lastEffect = 'c';
-          break;
-        case 'f': if (io==IO_IN) { inFreeverb = true; } else if (io==IO_OUT) { outFreeverb = true; }
-          else { std::cerr << "-f arg `" << optarg << "' malformed\n"; exit(1); }
-          lastEffect = 'f';
-          break;
-        case 'z': if (io==IO_IN) { inZitarev = true; } else if (io==IO_OUT) { outZitarev = true; }
-          else { std::cerr << "-f arg `" << optarg << "' malformed\n"; exit(1); }
-          lastEffect = 'z';
-          break;
-        case '(': parenLevel++;
-          for (ulong j=i+1; j<argLen; j++) {
-            if (optarg[j] == ')') {
-              optarg[j] = '\0';
-              switch(lastEffect) {
-              case 'c': {
-                returnCode += parseCompresserArgs(&optarg[i+1],io);
-                break; }
-              case 'z': {
-              float farg = atof(&optarg[i+1]);
-              if (io==IO_IN) {
-                  zitarevInLevel = farg;
-              } else if (io==IO_OUT) {
-                  zitarevOutLevel = farg;
-                } // else ignore the argument
-                break; }
-              case 'f': {
-                float farg = atof(&optarg[i+1]);
-                if (io==IO_IN) {
-                  freeverbInLevel = farg;
-                } else if (io==IO_OUT) {
-                  freeverbOutLevel = farg;
-                } // else ignore the argument
-                break; }
-              default: { // ignore
-                break; }
-              }
-              optarg[j] = ')';
-              break;
+                assert(outLimiterP == nullptr);
+                outLimiterP = new Limiter(mNumOutgoingChans, mNumClientsAssumed);
+                outLimiterP->setWarningAmplitude(limiterWarningAmplitude);
+                // do not have mSampleRate yet, so cannot call limiter->init(mSampleRate)
+                // here
+                outgoingEffects.push_back(outLimiterP);
             }
-          }
-          break;
-        case ')': parenLevel--;
-          break;
-        default:
-          break; // ignore
-        } // switch(optarg[i])
-      }
+        }
+        outgoingEffectsAllocated = true;
+        return outgoingEffects;
     }
-    return returnCode;
-  }
-
-  int parseLimiterOptArg(char* cmd, char* optarg) {
-    int returnCode = 0;
-    lastEffect = 'O'; // OverflowLimiter
-    char ch = tolower(optarg[0]);
-    if (ch == '-' || ch == 0) {
-      std::cerr << cmd << " argument i, o, or io is REQUIRED\n";
-      returnCode = 2;
-    } else if (ch == 'h') {
-      printHelp(cmd,'O');
-      returnCode = 1;
-    } else {
-      bool haveIncoming = false;
-      bool haveOutgoing = false;
-      bool haveWarnings = false;
-      for (int i=0; i<strlen(optarg); i++) {
-        ch = tolower(optarg[i]);
-        switch(ch) {
-        case ' ': break;
-        case '\t': break;
-        case 'i':
-          haveIncoming = true;
-          break;
-        case 'o':
-          haveOutgoing = true;
-          break;
-        case 'w':
-          haveWarnings = true;
-          break;
-        case 'n':
-          haveIncoming = false;
-          haveOutgoing = false;
-          break;
-        default:
-          std::cerr << "*** Effects.h: parseLimiterOptArg: Unrecognized option " << ch << "\n";
-          returnCode = 2;
-        } // switch(ch)
-      } // process optarg char ch
-      mLimit = (haveIncoming && haveOutgoing ? LIMITER_BOTH
-                : (haveIncoming ? LIMITER_INCOMING
-                   : (haveOutgoing ? LIMITER_OUTGOING : LIMITER_NONE)));
-      if (haveWarnings) {
-        limiterWarningAmplitude = 0.5; // KEEP IN SYNC WITH LIMITER THRESHOLD/CEILING 'softClipLevel' in ../faust-src/limiterdsp.dsp
-        // the warning amplitude and limiter compression threshold can of course be brought as a parameters, e.g. w(0.5)
-      }
-      if (gVerboseFlag) {
-        if(haveIncoming) {
-          std::cout << "Set up INCOMING Overflow Limiter\n";
+
+    void printHelp(char* command, char helpCase)
+    {
+        std::cout << "HELP for `" << command
+                  << "' (end-of-line comments start with `//')\n";
+        std::cout << "\n";
+        std::cout << "Examples:\n";
+        std::cout << "\n";
+        if (helpCase == 0 || helpCase == 'f') {  //
+            std::cout
+                << command
+                << " 0.3 // add a default outgoing compressor (for voice) and incoming "
+                   "reverb (freeverb) with wetness 0.3 (wetness from 0 to 1)\n";
+            std::cout << command
+                      << " 1.3 // add a default outgoing compressor (for voice) and "
+                         "incoming reverb (zitarev) with wetness 0.3 = 1.3-1 (i.e., 1+ "
+                         "to 2 is for zitarev)\n";
+            std::cout << "\n";
+            std::cout << command
+                      << " \"o:c i:f(0.3)\" // outgoing-compressor and incoming-freeverb "
+                         "example above using more general string argument\n";
+            std::cout << command
+                      << " \"o:c i:z(0.3)\" // outgoing-compressor and incoming-zitarev "
+                         "example above using more general string argument\n";
+            std::cout << command
+                      << " \"o:c(1)\" // outgoing compressor, using preset 1 (designed "
+                         "for voice - see below for details)\n";
+            std::cout
+                << command
+                << " \"o:c(2)\" // outgoing compressor, using preset 2 (for horns)\n";
+            std::cout
+                << command
+                << " \"o:c(3)\" // outgoing compressor, using preset 3 (for snare)\n";
+            std::cout << command
+                      << " \"o:c(c:compressionRatio t:thresholdDB a:attackTimeMS "
+                         "r:releaseTimeMS g:makeUpGainDB)\" // general compression "
+                         "parameter specification (all floats)\n";
+            std::cout << command
+                      << " \"o:c(c:2 t:-24 a:15 r:40 g:2)\"   // outgoing compressor, "
+                         "preset 1 details\n";
+            std::cout << command
+                      << " \"o:c(c:3 t:-10 a:100 r:250 g:2)\" // outgoing compressor, "
+                         "preset 2 details\n";
+            std::cout << command
+                      << " \"o:c(c:5 t:-4 a:5 r:150 g:3)\"    // outgoing compressor, "
+                         "preset 3 details\n";
+            std::cout << "  For these and more suggested compression settings, see "
+                         "http://www.anythingpeaceful.org/sonar/settings/comp.html\n";
+            std::cout << "\n";
         }
-        if(haveOutgoing) {
-          std::cout << "Set up OUTGOING Overflow Limiter\n";
+        if (helpCase == 0 || helpCase == 'O') {  // limiter (-O option most likely)
+            std::cout << command
+                      << " i   // add limiter to INCOMING audio from network (only "
+                         "helpful for floats, i.e., -b32 used by server)\n";
+            std::cout << command
+                      << " o   // add limiter to OUTGOING audio to network (prevents "
+                         "your sound from harshly clipping going out)\n";
+            std::cout << command
+                      << " ow  // also warn and advise on levels when outgoing limiter "
+                         "compresses audio near clipping\n";
+            std::cout << command
+                      << " io  // add limiter to both INCOMING and OUTGOING audio\n";
+            std::cout << command
+                      << " iow // limiters both ways and compression warnings on "
+                         "outgoing direction only\n";
+            std::cout << "\n";
         }
-        if(haveWarnings) {
-          std::cout << "Enable DISTORTION WARNINGS in Overflow Limiters\n";
+        if (helpCase == 0 || helpCase == 'a') {  // assumedNumClients (-a option)
+            std::cout << command
+                      << " 1 // assume 1 client - fine for loopback test, or if only one "
+                         "client plays at a time, or server uses -b32 and -Oi is used\n";
+            std::cout << command
+                      << " 2 // assume 2 clients possibly playing at the same time\n";
+            std::cout
+                << command
+                << " N // any integer N>0 can be used - the outgoing limiter will divide "
+                   "final amplitude by 1/sqrt(N) to reduce overages in server\n";
+            std::cout << "\n";
         }
-        if(not haveIncoming and not haveOutgoing) {
-          std::cout << "Set up NO Overflow Limiters\n";
+    }
+
+    // ----------- Compressor stuff --------------
+
+    int setCompressorPresetIndexFrom1(unsigned long presetIndexFrom1, InOrOut io)
+    {
+        int returnCode = 0;
+        if (presetIndexFrom1 <= 0 || presetIndexFrom1 > CompressorPresets::numPresets) {
+            std::cerr << "*** Effects.h: setCompressorPresetFrom1: Index "
+                      << presetIndexFrom1 << " out of range\n";
+            returnCode = 1;
+        } else {
+            CompressorPreset stdPreset =
+                CompressorPresets::standardPresets[presetIndexFrom1 - 1];
+            if (io == IO_IN) {
+                inCompressorPreset = stdPreset;
+            } else if (io == IO_OUT) {
+                outCompressorPreset = stdPreset;
+            } else if (io != IO_NEITHER) {
+                std::cerr
+                    << "*** Effects.h: setCompressorPresetFrom1: Invalid InOrOut value "
+                    << io << "\n";
+                returnCode = 1;
+            }
+        }
+        return returnCode;
+    }
+
+    int parseCompresserArgs(char* args, InOrOut inOrOut)
+    {
+        // args can be integerPresetNumberFrom1 or (all optional, any order):
+        // c:compressionRatio, a:attackTimeMS, r:releaseTimeMS, g:makeUpGain
+        int returnCode = 0;
+        if (not isalpha(args[0])) {
+            int presetIndexFrom1 = atoi(args);
+            setCompressorPresetIndexFrom1(presetIndexFrom1, inOrOut);
+        } else {
+            // args can be presetIndexFrom1, handled above, or (all optional, any order):
+            // c(c:compressionRatio, t:thresholdDB, a:attackTimeMS, r:releaseTimeMS,
+            // g:makeUpGainDB) See ./CompressorPresets.h for example settings.
+            if (gVerboseFlag) {
+                std::cout << "parseCompressorArgs = " << args << std::endl;
+            }
+            ulong argLen   = strlen(args);
+            char lastParam = '\0';
+
+            CompressorPreset newPreset(
+                CompressorPresets::voice);  // Anything unset gets voice value (most
+                                            // gentle)
+
+            int nSkip = 0;
+            for (ulong i = 0; i < argLen; i++) {
+                if (nSkip > 0) {
+                    nSkip--;
+                    continue;
+                }
+                char ch = args[i];
+                switch (ch) {
+                case ' ':
+                    break;
+                case '\t':
+                    break;
+                case 'c':
+                case 't':
+                case 'a':
+                case 'r':
+                case 'g':
+                    lastParam = ch;
+                    break;
+                case ':':
+                    break;
+                default:  // must be a floating-point number at this point:
+                    if (ch != '-' && isalpha(ch)) {
+                        std::cerr << "*** Effects.h: parseCompressorArgs: " << ch
+                                  << " not recognized in args = " << args << "\n";
+                        returnCode = 2;
+                    } else {  // must have a digit or '-' or '.'
+                        assert(ch == '-' || ch == '.' || isdigit(ch));
+                        float paramValue = -1.0e10;
+                        for (ulong j = i; j < argLen;
+                             j++) {  // scan ahead for end of number
+                            if (args[j] == ',' || args[j] == ' '
+                                || j == argLen - 1) {  // comma or space required between
+                                                       // parameters
+                                char argsj = args[j];
+                                if (j < argLen - 1) {  // there's more
+                                    args[j] = '\0';
+                                }
+                                paramValue = atof(&args[i]);
+                                args[j]    = argsj;
+                                nSkip      = j - i;
+                                break;
+                            }
+                        }
+                        if (paramValue == -1.0e10) {
+                            std::cerr << "*** Effects.h: parseCompressorArgs: Could not "
+                                         "find parameter for "
+                                      << lastParam << " in args = " << args << "\n";
+                            returnCode = 2;
+                        } else {
+                            switch (lastParam) {
+                            case 'c':
+                                newPreset.ratio = paramValue;
+                                break;
+                            case 't':
+                                newPreset.thresholdDB = paramValue;
+                                break;
+                            case 'a':
+                                newPreset.attackMS = paramValue;
+                                break;
+                            case 'r':
+                                newPreset.releaseMS = paramValue;
+                                break;
+                            case 'g':
+                                newPreset.makeUpGainDB = paramValue;
+                                break;
+                            default:  // cannot happen:
+                                std::cerr
+                                    << "*** Effects.h: parseCompressorArgs: lastParam "
+                                    << lastParam << " invalid\n";
+                                returnCode = 3;  // "reality failure"
+                            }                    // switch(lastParam)
+                        }                        // have valid parameter from atof
+                    }  // have valid non-alpha char for parameter
+                }      // switch(ch)
+            }          // for (ulong i=0; i<argLen; i++) {
+            if (inOrOut == IO_IN) {
+                inCompressorPreset = newPreset;
+            } else if (inOrOut == IO_OUT) {
+                outCompressorPreset = newPreset;
+            } else if (inOrOut != IO_NEITHER) {
+                std::cerr << "*** Effects.h: parseCompressorArgs: invalid InOrOut value "
+                          << inOrOut << "\n";
+                returnCode = 2;
+            }
+        }  // long-form compressor args
+        return returnCode;
+    }  // int parseCompresserArgs(char* args, InOrOut inOrOut)
+
+    // ============== General argument processing for all effects =================
+
+    int parseEffectsOptArg(char* cmd, char* optarg)
+    {
+        int returnCode =
+            0;  // 0 means go, 1 means exit without error, higher => error exit
+
+        char c = optarg[0];
+        if (c == '-' || c == 0) {
+            // happens when no -f argument specified
+            returnCode = 2;
+        } else if (not isalpha(c)) {  // backward compatibility why not?, e.g., "-f 0.5"
+            // -f reverbLevelFloat
+            mReverbLevel  = atof(optarg);
+            outCompressor = true;
+            inZitarev     = mReverbLevel > 1.0;
+            inFreeverb    = mReverbLevel <= 1.0;
+            if (inZitarev) {
+                zitarevInLevel = mReverbLevel - 1.0;  // wetness from 0 to 1
+            }
+            if (inFreeverb) {
+                freeverbInLevel = mReverbLevel;  // wetness from 0 to 1
+            }
+        } else {  // long-form argument:
+            // -f "i:[c][f|z][(reverbLevel)]], o:[c][f|z][(rl)]"
+            // c can be c(integerPresetNumberFrom1) or (all optional, any order):
+            // c(c:compressionRatio, a:attackTimeMS, r:releaseTimeMS, g:makeUpGain)
+            if (gVerboseFlag) {
+                std::cout << cmd << " argument = " << optarg << std::endl;
+            }
+            ulong argLen = strlen(optarg);
+
+            for (ulong i = 0; i < argLen; i++) {
+                if (optarg[i] != ')' && parenLevel > 0) { continue; }
+                switch (optarg[i]) {
+                case ' ':
+                    break;
+                case ',':
+                    break;
+                case ';':
+                    break;
+                case '\t':
+                    break;
+                case 'h':
+                    printHelp(cmd, 'f');
+                    returnCode = 1;
+                    break;
+                case 'i':
+                    io = IO_IN;
+                    break;
+                case 'o':
+                    io = IO_OUT;
+                    break;
+                case ':':
+                    break;
+                case 'c':
+                    if (io == IO_IN) {
+                        inCompressor = true;
+                    } else if (io == IO_OUT) {
+                        outCompressor = true;
+                    } else {
+                        std::cerr << "-f arg `" << optarg << "' malformed\n";
+                        exit(1);
+                    }
+                    lastEffect = 'c';
+                    break;
+                case 'f':
+                    if (io == IO_IN) {
+                        inFreeverb = true;
+                    } else if (io == IO_OUT) {
+                        outFreeverb = true;
+                    } else {
+                        std::cerr << "-f arg `" << optarg << "' malformed\n";
+                        exit(1);
+                    }
+                    lastEffect = 'f';
+                    break;
+                case 'z':
+                    if (io == IO_IN) {
+                        inZitarev = true;
+                    } else if (io == IO_OUT) {
+                        outZitarev = true;
+                    } else {
+                        std::cerr << "-f arg `" << optarg << "' malformed\n";
+                        exit(1);
+                    }
+                    lastEffect = 'z';
+                    break;
+                case '(':
+                    parenLevel++;
+                    for (ulong j = i + 1; j < argLen; j++) {
+                        if (optarg[j] == ')') {
+                            optarg[j] = '\0';
+                            switch (lastEffect) {
+                            case 'c': {
+                                returnCode += parseCompresserArgs(&optarg[i + 1], io);
+                                break;
+                            }
+                            case 'z': {
+                                float farg = atof(&optarg[i + 1]);
+                                if (io == IO_IN) {
+                                    zitarevInLevel = farg;
+                                } else if (io == IO_OUT) {
+                                    zitarevOutLevel = farg;
+                                }  // else ignore the argument
+                                break;
+                            }
+                            case 'f': {
+                                float farg = atof(&optarg[i + 1]);
+                                if (io == IO_IN) {
+                                    freeverbInLevel = farg;
+                                } else if (io == IO_OUT) {
+                                    freeverbOutLevel = farg;
+                                }  // else ignore the argument
+                                break;
+                            }
+                            default: {  // ignore
+                                break;
+                            }
+                            }
+                            optarg[j] = ')';
+                            break;
+                        }
+                    }
+                    break;
+                case ')':
+                    parenLevel--;
+                    break;
+                default:
+                    break;  // ignore
+                }           // switch(optarg[i])
+            }
         }
-      } // gVerboseFlag
-    } // optarg cases
-    return returnCode;
-  } // parseLimiterOptArg()
-
-  int parseAssumedNumClientsOptArg(char* cmd, char* optarg) {
-    int returnCode = 0;
-    lastEffect = 'a'; // assumedNumClients
-    char ch = optarg[0];
-    if (ch == 'h') {
-      printHelp(cmd,'a');
-      returnCode = 1;
-    } else if (ch == '-' || isalpha(ch) || ch == 0) {
-      std::cerr << cmd << " argument help or integer > 0 is REQUIRED\n";
-      returnCode = 2;
-    } else {
-    mNumClientsAssumed = atoi(optarg);
-    if(mNumClientsAssumed < 1) {
-      std::cerr << "-p ERROR: Must have at least one assumed sound source: "
-                << atoi(optarg) << " is not supported." << std::endl;
-        returnCode = 2;
-      }
+        return returnCode;
     }
-    return returnCode;
-  }
 
+    int parseLimiterOptArg(char* cmd, char* optarg)
+    {
+        int returnCode = 0;
+        lastEffect     = 'O';  // OverflowLimiter
+        char ch        = tolower(optarg[0]);
+        if (ch == '-' || ch == 0) {
+            std::cerr << cmd << " argument i, o, or io is REQUIRED\n";
+            returnCode = 2;
+        } else if (ch == 'h') {
+            printHelp(cmd, 'O');
+            returnCode = 1;
+        } else {
+            bool haveIncoming = false;
+            bool haveOutgoing = false;
+            bool haveWarnings = false;
+            for (uint i = 0; i < strlen(optarg); i++) {
+                ch = tolower(optarg[i]);
+                switch (ch) {
+                case ' ':
+                    break;
+                case '\t':
+                    break;
+                case 'i':
+                    haveIncoming = true;
+                    break;
+                case 'o':
+                    haveOutgoing = true;
+                    break;
+                case 'w':
+                    haveWarnings = true;
+                    break;
+                case 'n':
+                    haveIncoming = false;
+                    haveOutgoing = false;
+                    break;
+                default:
+                    std::cerr << "*** Effects.h: parseLimiterOptArg: Unrecognized option "
+                              << ch << "\n";
+                    returnCode = 2;
+                }  // switch(ch)
+            }      // process optarg char ch
+            mLimit =
+                (haveIncoming && haveOutgoing
+                     ? LIMITER_BOTH
+                     : (haveIncoming ? LIMITER_INCOMING
+                                     : (haveOutgoing ? LIMITER_OUTGOING : LIMITER_NONE)));
+            if (haveWarnings) {
+                limiterWarningAmplitude =
+                    0.5;  // KEEP IN SYNC WITH LIMITER THRESHOLD/CEILING 'softClipLevel'
+                          // in ../faust-src/limiterdsp.dsp
+                // the warning amplitude and limiter compression threshold can of course
+                // be brought as a parameters, e.g. w(0.5)
+            }
+            if (gVerboseFlag) {
+                if (haveIncoming) { std::cout << "Set up INCOMING Overflow Limiter\n"; }
+                if (haveOutgoing) { std::cout << "Set up OUTGOING Overflow Limiter\n"; }
+                if (haveWarnings) {
+                    std::cout << "Enable DISTORTION WARNINGS in Overflow Limiters\n";
+                }
+                if (not haveIncoming and not haveOutgoing) {
+                    std::cout << "Set up NO Overflow Limiters\n";
+                }
+            }  // gVerboseFlag
+        }      // optarg cases
+        return returnCode;
+    }  // parseLimiterOptArg()
+
+    int parseAssumedNumClientsOptArg(char* cmd, char* optarg)
+    {
+        int returnCode = 0;
+        lastEffect     = 'a';  // assumedNumClients
+        char ch        = optarg[0];
+        if (ch == 'h') {
+            printHelp(cmd, 'a');
+            returnCode = 1;
+        } else if (ch == '-' || isalpha(ch) || ch == 0) {
+            std::cerr << cmd << " argument help or integer > 0 is REQUIRED\n";
+            returnCode = 2;
+        } else {
+            mNumClientsAssumed = atoi(optarg);
+            if (mNumClientsAssumed < 1) {
+                std::cerr << "-p ERROR: Must have at least one assumed sound source: "
+                          << atoi(optarg) << " is not supported." << std::endl;
+                returnCode = 2;
+            }
+        }
+        return returnCode;
+    }
 };
index f34861702a084bcf4fb240fd55bebc5597d778a9..9b296ce0954cae10269d529f33cde0b6e2eeeece 100644 (file)
@@ -1,6 +1,9 @@
 /*
   JMess: A simple utility so save your jack-audio mess.
-
+  Incorporated into JackTrip:
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
+  SoundWIRE group at CCRMA, Stanford University.
+  JMess itself is:
   Copyright (C) 2007-2010 Juan-Pablo Caceres.
 
   Permission is hereby granted, free of charge, to any person
   OTHER DEALINGS IN THE SOFTWARE.
 */
 
-
 /*
  * JMess.cpp
  */
 
 #include "JMess.h"
+
+#include <QDebug>
+
 #include "JackTrip.h"
 #include "jacktrip_globals.h"
-#include <QDebug>
 
 // sJackMutex definition
 QMutex JMess::sJMessMutex;
@@ -45,22 +49,22 @@ QMutex JMess::sJMessMutex;
 //-------------------------------------------------------------------------------
 JMess::JMess()
 {
-    //Open a client connection to the JACK server.  Starting a
-    //new server only to list its ports seems pointless, so we
-    //specify JackNoStartServer.
-    mClient = jack_client_open ("lsp", JackNoStartServer, &mStatus);
+    // Open a client connection to the JACK server.  Starting a
+    // new server only to list its ports seems pointless, so we
+    // specify JackNoStartServer.
+    mClient = jack_client_open("lsp", JackNoStartServer, &mStatus);
     if (mClient == NULL) {
         if (mStatus & JackServerFailed) {
             cerr << "JACK server not running" << endl;
         } else {
             cerr << "jack_client_open() failed, "
-                 << "status = 0x%2.0x\n" << mStatus << endl;
+                 << "status = 0x%2.0x\n"
+                 << mStatus << endl;
         }
         exit(1);
     }
 }
 
-
 //-------------------------------------------------------------------------------
 /*! \brief Distructor closes the jmess jack audio client.
  *
@@ -72,13 +76,12 @@ JMess::~JMess()
         cerr << "ERROR: Could not close the hidden jmess jack client." << endl;
 }
 
-
 //-------------------------------------------------------------------------------
 /*! \brief Write an XML file with the name specified at xmlOutFile.
  *
  */
 //-------------------------------------------------------------------------------
-void JMess::writeOutput(__attribute__((unused)) QString xmlOutFile)
+void JMess::writeOutput(QString /*xmlOutFile*/)
 {
     //  QDomDocument jmess_xml;   QDomElement root;
     //  QDomElement connection;   QDomElement output;
@@ -136,7 +139,6 @@ void JMess::writeOutput(__attribute__((unused)) QString xmlOutFile)
     //  }
 }
 
-
 //-------------------------------------------------------------------------------
 /*! \brief Set list of ouput ports that have connections.
  *
@@ -146,15 +148,16 @@ void JMess::setConnectedPorts()
 {
     mConnectedPorts.clear();
 
-    const char **ports, **connections; //vector of ports and connections
-    QVector<QString> OutputInput(2); //helper variable
+    const char **ports, **connections;  // vector of ports and connections
+    QVector<QString> OutputInput(2);    // helper variable
 
-    //Get active output ports.
-    ports = jack_get_ports (mClient, NULL, NULL, JackPortIsOutput);
+    // Get active output ports.
+    ports = jack_get_ports(mClient, NULL, NULL, JackPortIsOutput);
 
     for (unsigned int out_i = 0; ports[out_i]; ++out_i) {
-        if ((connections = jack_port_get_all_connections
-             (mClient, jack_port_by_name(mClient, ports[out_i]))) != 0) {
+        if ((connections = jack_port_get_all_connections(
+                 mClient, jack_port_by_name(mClient, ports[out_i])))
+            != 0) {
             for (unsigned int in_i = 0; connections[in_i]; ++in_i) {
                 OutputInput[0] = ports[out_i];
                 //    cout << "Output ===> " <<qPrintable(OutputInput[0]) << endl;
@@ -172,15 +175,14 @@ void JMess::connectSpawnedPorts(int nChans, int hubPatch)
 // called from UdpHubListener::connectMesh
 {
     QMutexLocker locker(&sJMessMutex);
-    
+
     QString IPS[gMAX_WAIRS];
     int ctr = 0;
 
-    const char **ports; //, **connections; //vector of ports and connections
-    QVector<QString> OutputInput(2); //helper variable
+    const char** ports;  //, **connections; //vector of ports and connections
 
-    //Get active output ports.
-    ports = jack_get_ports (mClient, NULL, NULL, JackPortIsOutput);
+    // Get active output ports.
+    ports = jack_get_ports(mClient, NULL, NULL, JackPortIsOutput);
 
     for (unsigned int out_i = 0; ports[out_i]; ++out_i) {
         //        qDebug() << QString(ports[out_i]);
@@ -193,41 +195,41 @@ void JMess::connectSpawnedPorts(int nChans, int hubPatch)
         //  for example              "171.64.197.121"
 
         bool newOne = !systemPort;
-        for (int i = 0; i<ctr; i++) if (newOne && (IPS[i]==s)) newOne = false;
-        if (newOne)
-        {
+        for (int i = 0; i < ctr; i++)
+            if (newOne && (IPS[i] == s)) newOne = false;
+        if (newOne) {
             IPS[ctr] = s;
             ctr++;
             //                        qDebug() << ports[out_i] << systemPort << s;
         }
     }
-    //for (int i = 0; i<ctr; i++) qDebug() << IPS[i];
+    // for (int i = 0; i<ctr; i++) qDebug() << IPS[i];
     disconnectAll();
 
-    int k = 0;
+    int k      = 0;
     int jLimit = 1;
 
     // FULLMIX is the union of CLIENTFOFI, CLIENTECHO
 
     // implements CLIENTFOFI, CLIENTECHO -- also FULLMIX part which is CLIENTECHO
-    for (int i = 0; i<ctr; i++) {
-        if (hubPatch == JackTrip::CLIENTFOFI) jLimit = (ctr-1);
-        for (int j = 0; j<jLimit; j++) {
-            if ((hubPatch == JackTrip::CLIENTECHO)||(hubPatch == JackTrip::FULLMIX)) k = i;
-            else if (hubPatch == JackTrip::CLIENTFOFI) k = (j+(i+1))%ctr;
-            for (int l = 1; l<=nChans; l++) { // chans are 1-based
-                //qDebug() << "connect " << IPS[i]+":receive_"+QString::number(l)
-                         //<<"with " << IPS[k]+":send_"+QString::number(l);
-
-                QString left = IPS[i] +
-                        ":receive_" + QString::number(l);
-                QString right = IPS[k] +
-                        ":send_" + QString::number(l);
-
-                if (0 !=
-                        jack_connect(mClient, left.toStdString().c_str(), right.toStdString().c_str())) {
-                    qDebug() << "WARNING: port: " << left
-                             << "and port: " << right
+    for (int i = 0; i < ctr; i++) {
+        if (hubPatch == JackTrip::CLIENTFOFI) jLimit = (ctr - 1);
+        for (int j = 0; j < jLimit; j++) {
+            if ((hubPatch == JackTrip::CLIENTECHO) || (hubPatch == JackTrip::FULLMIX))
+                k = i;
+            else if (hubPatch == JackTrip::CLIENTFOFI)
+                k = (j + (i + 1)) % ctr;
+            for (int l = 1; l <= nChans; l++) {  // chans are 1-based
+                // qDebug() << "connect " << IPS[i]+":receive_"+QString::number(l)
+                //<<"with " << IPS[k]+":send_"+QString::number(l);
+
+                QString left  = IPS[i] + ":receive_" + QString::number(l);
+                QString right = IPS[k] + ":send_" + QString::number(l);
+
+                if (0
+                    != jack_connect(mClient, left.toStdString().c_str(),
+                                    right.toStdString().c_str())) {
+                    qDebug() << "WARNING: port: " << left << "and port: " << right
                              << " could not be connected.";
                 }
             }
@@ -236,25 +238,23 @@ void JMess::connectSpawnedPorts(int nChans, int hubPatch)
 
     // do it again to implement the FULLMIX part which is CLIENTFOFI
     if (hubPatch == JackTrip::FULLMIX) {
-        jLimit = (ctr-1); // same as CLIENTFOFI
+        jLimit = (ctr - 1);  // same as CLIENTFOFI
         /*************/
         // todo: the next block should be in a method, it's a repeat of the above
-        for (int i = 0; i<ctr; i++) {
-            for (int j = 0; j<jLimit; j++) {
-                k = (j+(i+1))%ctr;
-                for (int l = 1; l<=nChans; l++) { // chans are 1-based
-                    //qDebug() << "connect " << IPS[i]+":receive_"+QString::number(l)
-                             //<<"with " << IPS[k]+":send_"+QString::number(l);
-
-                    QString left = IPS[i] +
-                            ":receive_" + QString::number(l);
-                    QString right = IPS[k] +
-                            ":send_" + QString::number(l);
-
-                    if (0 !=
-                            jack_connect(mClient, left.toStdString().c_str(), right.toStdString().c_str())) {
-                        qDebug() << "WARNING: port: " << left
-                                 << "and port: " << right
+        for (int i = 0; i < ctr; i++) {
+            for (int j = 0; j < jLimit; j++) {
+                k = (j + (i + 1)) % ctr;
+                for (int l = 1; l <= nChans; l++) {  // chans are 1-based
+                    // qDebug() << "connect " << IPS[i]+":receive_"+QString::number(l)
+                    //<<"with " << IPS[k]+":send_"+QString::number(l);
+
+                    QString left  = IPS[i] + ":receive_" + QString::number(l);
+                    QString right = IPS[k] + ":send_" + QString::number(l);
+
+                    if (0
+                        != jack_connect(mClient, left.toStdString().c_str(),
+                                        right.toStdString().c_str())) {
+                        qDebug() << "WARNING: port: " << left << "and port: " << right
                                  << " could not be connected.";
                     }
                 }
@@ -298,8 +298,8 @@ void JMess::connectSpawnedPorts(int nChans, int hubPatch)
 // const int gMAX_TUB = 20; // highest client address
 // and give the proper audio process and connection names
 
-#define HARDWIRED_AUDIO_PROCESS_ON_SERVER "SuperCollider"
-#define HARDWIRED_AUDIO_PROCESS_ON_SERVER_IN ":in_"
+#define HARDWIRED_AUDIO_PROCESS_ON_SERVER     "SuperCollider"
+#define HARDWIRED_AUDIO_PROCESS_ON_SERVER_IN  ":in_"
 #define HARDWIRED_AUDIO_PROCESS_ON_SERVER_OUT ":out_"
 // On server side it is SC jack-clients with indivisual names:
 // POE_0...POE_16
@@ -308,50 +308,49 @@ void JMess::connectSpawnedPorts(int nChans, int hubPatch)
 // send_1
 // I think it should be extended to 4 in/out ports per client.
 
-// this is brute force, does not look at individual clients, just patches the whole ensemble
-// each time
+// this is brute force, does not look at individual clients, just patches the whole
+// ensemble each time
 void JMess::connectTUB(int /*nChans*/)
 // called from UdpHubListener::connectPatch
 {
-    for (int i = 0; i<=gMAX_TUB-gMIN_TUB; i++) // last IP decimal octet
-        for (int l = 1; l<=1; l++) // mono for now // chans are 1-based, 1...2
+    for (int i = 0; i <= gMAX_TUB - gMIN_TUB; i++)  // last IP decimal octet
+        for (int l = 1; l <= 1; l++)  // mono for now // chans are 1-based, 1...2
         {
             // jacktrip to SC
-            QString client = gDOMAIN_TRIPLE + QString(".") + QString::number(gMIN_TUB+i);
+            QString client =
+                gDOMAIN_TRIPLE + QString(".") + QString::number(gMIN_TUB + i);
             QString serverAudio = QString(HARDWIRED_AUDIO_PROCESS_ON_SERVER);
-            int tmp = i + l; // only works for mono... completely wrong for 2 or more chans
-            qDebug() << "connect " << client << ":receive_ " << l
-                     <<"with " << serverAudio << HARDWIRED_AUDIO_PROCESS_ON_SERVER_IN << tmp;
-
-            QString left = QString(client + ":receive_" + QString::number(l));
-            QString right = QString(serverAudio + HARDWIRED_AUDIO_PROCESS_ON_SERVER_IN +
-                                    QString::number(tmp));
-
-            if (0 !=
-                    jack_connect(mClient, left.toStdString().c_str(),
-                                 right.toStdString().c_str())) {
-                qDebug() << "WARNING: port: " << left
-                         << "and port: " << right
+            int tmp =
+                i + l;  // only works for mono... completely wrong for 2 or more chans
+            qDebug() << "connect " << client << ":receive_ " << l << "with "
+                     << serverAudio << HARDWIRED_AUDIO_PROCESS_ON_SERVER_IN << tmp;
+
+            QString left  = QString(client + ":receive_" + QString::number(l));
+            QString right = QString(serverAudio + HARDWIRED_AUDIO_PROCESS_ON_SERVER_IN
+                                    + QString::number(tmp));
+
+            if (0
+                != jack_connect(mClient, left.toStdString().c_str(),
+                                right.toStdString().c_str())) {
+                qDebug() << "WARNING: port: " << left << "and port: " << right
                          << " could not be connected.";
             }
 
             // SC to jacktrip
-            tmp += 4; // increase tmp for port offest
+            tmp += 4;  // increase tmp for port offest
             qDebug() << "connect " << serverAudio << HARDWIRED_AUDIO_PROCESS_ON_SERVER_OUT
-                     << tmp <<"with " << client << ":send_" << l;
+                     << tmp << "with " << client << ":send_" << l;
 
-            left = QString(serverAudio + HARDWIRED_AUDIO_PROCESS_ON_SERVER_OUT +
-                           QString::number(tmp));
+            left  = QString(serverAudio + HARDWIRED_AUDIO_PROCESS_ON_SERVER_OUT
+                           QString::number(tmp));
             right = QString(client + ":send_" + QString::number(l));
 
-            if (0 !=
-                    jack_connect(mClient, left.toStdString().c_str(),
-                                 right.toStdString().c_str())) {
-                qDebug() << "WARNING: port: " << left
-                         << "and port: " << right
+            if (0
+                != jack_connect(mClient, left.toStdString().c_str(),
+                                right.toStdString().c_str())) {
+                qDebug() << "WARNING: port: " << left << "and port: " << right
                          << " could not be connected.";
             }
-
         }
 }
 
@@ -362,24 +361,17 @@ void JMess::connectTUB(int /*nChans*/)
 //-------------------------------------------------------------------------------
 void JMess::disconnectAll()
 {
-    QVector<QString> OutputInput(2);
-
     this->setConnectedPorts();
 
-    for (QVector<QVector<QString> >::iterator it = mConnectedPorts.begin();
-         it != mConnectedPorts.end(); ++it) {
-        OutputInput = *it;
-
+    for (auto& OutputInput : mConnectedPorts) {
         if (jack_disconnect(mClient, OutputInput[0].toUtf8(), OutputInput[1].toUtf8())) {
             cerr << "WARNING: port: " << qPrintable(OutputInput[0])
-                    << "and port: " << qPrintable(OutputInput[1])
-                    << " could not be disconnected.\n";
+                 << "and port: " << qPrintable(OutputInput[1])
+                 << " could not be disconnected.\n";
         }
     }
-
 }
 
-
 //-------------------------------------------------------------------------------
 /*! \brief Parse the XML input file.
  *
@@ -387,7 +379,7 @@ void JMess::disconnectAll()
  * read the file.
  */
 //-------------------------------------------------------------------------------
-int JMess::parseXML(__attribute__((unused)) QString xmlInFile)
+int JMess::parseXML(QString /*xmlInFile*/)
 {
     //  mPortsToConnect.clear();
     //  QString errorStr;
@@ -420,7 +412,6 @@ int JMess::parseXML(__attribute__((unused)) QString xmlInFile)
     //    return 1;
     //  }
 
-
     //  QVector<QString> OutputInput(2);
     //  //First check for <connection> tag
     //  for(QDomNode n_cntn = jmess.firstChild();
@@ -445,29 +436,29 @@ int JMess::parseXML(__attribute__((unused)) QString xmlInFile)
     //  }
 
     return 0;
-
 }
 
-
 //-------------------------------------------------------------------------------
 /*! \brief Connect ports specified in input XML file xmlInFile
  *
  */
 //-------------------------------------------------------------------------------
-void JMess::connectPorts(__attribute__((unused)) QString xmlInFile)
+void JMess::connectPorts(QString /*xmlInFile*/)
 {
-    QVector<QString> OutputInput(2);
+    //    QVector<QString> OutputInput(2);
 
     //  if ( !(this->parseXML(xmlInFile)) ) {
     //    for (QVector<QVector<QString> >::iterator it = mPortsToConnect.begin();
     //  it != mPortsToConnect.end(); ++it) {
     //      OutputInput = *it;
 
-    //      if (jack_connect(mClient, OutputInput[0].toLatin1(), OutputInput[1].toLatin1())) {
+    //      if (jack_connect(mClient, OutputInput[0].toLatin1(),
+    //      OutputInput[1].toLatin1())) {
     // //Display a warining only if the error is not because the ports are already
     // //connected, in case the program doesn't display anyting.
     // if (EEXIST !=
-    //        jack_connect(mClient, OutputInput[0].toLatin1(), OutputInput[1].toLatin1())) {
+    //        jack_connect(mClient, OutputInput[0].toLatin1(), OutputInput[1].toLatin1()))
+    //        {
     //   cerr << "WARNING: port: " << qPrintable(OutputInput[0])
     //        << "and port: " << qPrintable(OutputInput[1])
     //        << " could not be connected.\n";
@@ -475,6 +466,4 @@ void JMess::connectPorts(__attribute__((unused)) QString xmlInFile)
     //      }
     //    }
     //  }
-
 }
-
index 3096ceff5e0e73f60be3e0cd1170f220571b50e9..f801a94a284814fcd64ce2f78f1960cb774e4d6c 100644 (file)
@@ -1,6 +1,9 @@
 /*
   JMess: A simple utility so save your jack-audio mess.
-
+  Incorporated into JackTrip:
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
+  SoundWIRE group at CCRMA, Stanford University.
+  JMess itself is:
   Copyright (C) 2007-2010 Juan-Pablo Caceres.
 
   Permission is hereby granted, free of charge, to any person
@@ -25,7 +28,6 @@
   OTHER DEALINGS IN THE SOFTWARE.
 */
 
-
 /*
  * JMess.h
  */
 #ifndef __JMESS_H
 #define __JMESS_H
 
-#include <iostream>
-#include <string>
-#include <errno.h>
-
 #include <QIODevice>
 #include <QString>
 #include <QVector>
+#include <cerrno>
+#include <iostream>
+#include <string>
 //#include <QtXml>
 //#include <QXmlSimpleReader>
 //#include <QXmlInputSource>
 //#include <QXmlContentHandler>
-#include <QMutexLocker>
-
+#ifdef USE_WEAK_JACK
+#include "weak_libjack.h"
+#else
 #include <jack/jack.h>
+#endif
+
+#include <QMutexLocker>
 
 using namespace std;
 
@@ -61,33 +66,33 @@ const int Indent = 2;
  * Has also an option to disconnect all the clients.
  */
 //-------------------------------------------------------------------------------
-class JMess {
-
-public:
-  JMess();
-  virtual ~JMess();
-
-  void disconnectAll();
-  void writeOutput(QString xmlOutFile);
-  void connectPorts(QString xmlInFile);
-  void setConnectedPorts();
-  /// \brief Cross connect ports between net combs, -l LAIR mode
-  void connectSpawnedPorts(int nChans, int hubPatch);
-  void connectTUB(int nChans);
-
-private:
-  int parseXML(QString xmlInFile);
-
-  jack_client_t *mClient; //Class client
-  jack_status_t mStatus; //Class client status
-
-  //Vectors of Connected Ports and Ports to connects
-  //This are a matrix (Nx2) of string like this:
-  //OuputPort1 InputPort1
-  // ...
-  //OuputPortN InputPortN
-  QVector<QVector<QString> > mConnectedPorts;
-  QVector<QVector<QString> > mPortsToConnect;
-  static QMutex sJMessMutex; ///< Mutex to make thread safe jack functions that are not
+class JMess
+{
+   public:
+    JMess();
+    virtual ~JMess();
+
+    void disconnectAll();
+    void writeOutput(QString xmlOutFile);
+    void connectPorts(QString xmlInFile);
+    void setConnectedPorts();
+    /// \brief Cross connect ports between net combs, -l LAIR mode
+    void connectSpawnedPorts(int nChans, int hubPatch);
+    void connectTUB(int nChans);
+
+   private:
+    int parseXML(QString xmlInFile);
+
+    jack_client_t* mClient;  // Class client
+    jack_status_t mStatus;   // Class client status
+
+    // Vectors of Connected Ports and Ports to connects
+    // This are a matrix (Nx2) of string like this:
+    // OuputPort1 InputPort1
+    // ...
+    // OuputPortN InputPortN
+    QVector<QVector<QString> > mConnectedPorts;
+    QVector<QVector<QString> > mPortsToConnect;
+    static QMutex sJMessMutex;  ///< Mutex to make thread safe jack functions that are not
 };
 #endif
index 06ff4c815869998e5be69bc0e8eca05ce87fcb9a..9f02a237a17d96d6f48201457aba7a4b18db6763 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
  */
 
 #include "JackAudioInterface.h"
-#include "jacktrip_globals.h"
-#include "JackTrip.h"
 
+#include <cmath>
 #include <cstdlib>
 #include <cstring>
-#include <cmath>
 #include <stdexcept>
 
+#include "JackTrip.h"
+#include "jacktrip_globals.h"
+
 ///************PROTORYPE FOR CELT**************************
 //#include <celt/celt.h>
 //#include <celt/celt_header.h>
 //#include <celt/celt_types.h>
 ///********************************************************
 
-#include <QTextStream>
 #include <QMutexLocker>
+#include <QTextStream>
 
-using std::cout; using std::endl;
+using std::cout;
+using std::endl;
 
 // sJackMutex definition
 QMutex JackAudioInterface::sJackMutex;
 
-
 //*******************************************************************************
-JackAudioInterface::JackAudioInterface(JackTrip* jacktrip,
-                                       int NumInChans, int NumOutChans,
-                                       #ifdef WAIR // wair
-                                       int NumNetRevChans,
-                                       #endif // endwhere
-                                       AudioInterface::audioBitResolutionT AudioBitResolution,
-                                       QString ClientName) :
-    AudioInterface(jacktrip,
-                   NumInChans, NumOutChans,
-                   #ifdef WAIR // wair
-                   NumNetRevChans,
-                   #endif // endwhere
-                   AudioBitResolution),
-    mNumInChans(NumInChans), mNumOutChans(NumOutChans),
-    #ifdef WAIR // WAIR
-    mNumNetRevChans(NumNetRevChans),
-    #endif // endwhere
-    //mAudioBitResolution(AudioBitResolution*8),
-    mBitResolutionMode(AudioBitResolution),
-    mClient(NULL),
-    mClientName(ClientName),
-    mBroadcast(false),
-    mJackTrip(jacktrip)
-{}
-
+JackAudioInterface::JackAudioInterface(
+    JackTrip* jacktrip, int NumInChans, int NumOutChans,
+#ifdef WAIR  // wair
+    int NumNetRevChans,
+#endif  // endwhere
+    AudioInterface::audioBitResolutionT AudioBitResolution, QString ClientName)
+    : AudioInterface(jacktrip, NumInChans, NumOutChans,
+#ifdef WAIR  // wair
+                     NumNetRevChans,
+#endif  // endwhere
+                     AudioBitResolution)
+    , mNumInChans(NumInChans)
+    , mNumOutChans(NumOutChans)
+#ifdef WAIR  // WAIR
+    , mNumNetRevChans(NumNetRevChans)
+#endif  // endwhere
+    , mClient(NULL)
+    , mClientName(ClientName)
+    , mBroadcast(false)
+{
+}
 
 //*******************************************************************************
-JackAudioInterface::~JackAudioInterface()
-{}
-
+JackAudioInterface::~JackAudioInterface() {}
 
 //*******************************************************************************
 void JackAudioInterface::setup()
@@ -99,30 +94,21 @@ void JackAudioInterface::setup()
     setProcessCallback();
 }
 
-
 //*******************************************************************************
 void JackAudioInterface::setupClient()
 {
     QByteArray clientName = mClientName.toUtf8();
-//    const char* server_name = NULL;
-#ifdef __MAC_OSX__
-    //Jack seems to have an issue with client names over 27 bytes in OS X
-    int maxSize = 27;
-#else
-    int maxSize = jack_client_name_size();
-#endif
+    int maxSize           = jack_client_name_size();
     if (clientName.length() > maxSize) {
         int length = maxSize;
-        //Make sure we don't cut mid multi-byte character.
-        while ((length > 0) && ((clientName.at(length) & 0xc0) == 0x80)) {
-            length--;
-        }
+        // Make sure we don't cut mid multi-byte character.
+        while ((length > 0) && ((clientName.at(length) & 0xc0) == 0x80)) { length--; }
         clientName.truncate(length);
     }
 
     // was  jack_options_t options = JackNoStartServer;
     // and then jack_options_t options = JackLoadName;
-    jack_options_t options = JackNullOption; // from jackSimpleClient example
+    jack_options_t options = JackNullOption;  // from jackSimpleClient example
     jack_status_t status;
 
     // Try to connect to the server
@@ -133,35 +119,37 @@ void JackAudioInterface::setupClient()
 //#ifndef WAIR // WAIR
 //        mClient = jack_client_open (client_name, options, &status, server_name);
 //#else
-//        mClient = jack_client_open (client_name, JackUseExactName, &status, server_name);
+//        mClient = jack_client_open (client_name, JackUseExactName, &status,
+//        server_name);
 //#endif // endwhere
-#ifndef WAIR // WAIR
-        mClient = jack_client_open (clientName.constData(), options, &status);
+#ifndef WAIR  // WAIR
+        mClient = jack_client_open(clientName.constData(), options, &status);
 #else
-        mClient = jack_client_open (clientName.constData(), JackUseExactName, &status);
-#endif // endwhere
+        mClient = jack_client_open(clientName.constData(), JackUseExactName, &status);
+#endif  // endwhere
     }
 
     if (mClient == NULL) {
-        //fprintf (stderr, "jack_client_open() failed, "
+        // fprintf (stderr, "jack_client_open() failed, "
         //          "status = 0x%2.0x\n", status);
         if (status & JackServerFailed) {
-            fprintf (stderr, "Unable to connect to JACK server\n");
-            //std::cerr << "ERROR: Maybe the JACK server is not running?" << std::endl;
-            //std::cerr << gPrintSeparator << std::endl;
+            fprintf(stderr, "Unable to connect to JACK server\n");
+            // std::cerr << "ERROR: Maybe the JACK server is not running?" << std::endl;
+            // std::cerr << gPrintSeparator << std::endl;
         }
-        //std::exit(1);
+        // std::exit(1);
         throw std::runtime_error("Maybe the JACK server is not running?");
     }
-    if (status & JackServerStarted) {
-        fprintf (stderr, "JACK server started\n");
-    }
+
+    mAssignedClientName = jack_get_client_name(mClient);
+    if (status & JackServerStarted) { fprintf(stderr, "JACK server started\n"); }
     if (status & JackNameNotUnique) {
-        fprintf (stderr, "unique name `%s' assigned\n", jack_get_client_name(mClient));
+        fprintf(stderr, "unique name `%s' assigned\n",
+                mAssignedClientName.toUtf8().constData());
     }
 
     // Set function to call if Jack shuts down
-    jack_on_shutdown (mClient, this->jackShutdown, 0);
+    jack_on_shutdown(mClient, this->jackShutdown, 0);
 
     // Create input and output channels
     createChannels();
@@ -175,151 +163,142 @@ void JackAudioInterface::setupClient()
     mBroadcastBuffer.resize(mNumOutChans);
 }
 
-
 //*******************************************************************************
 void JackAudioInterface::createChannels()
 {
-    //Create Input Ports
+    // Create Input Ports
     mInPorts.resize(mNumInChans);
-    for (int i = 0; i < mNumInChans; i++)
-    {
+    for (int i = 0; i < mNumInChans; i++) {
         QString inName;
-        QTextStream (&inName) << "send_" << i+1;
-        mInPorts[i] = jack_port_register (mClient, inName.toLatin1(),
-                                          JACK_DEFAULT_AUDIO_TYPE,
-                                          JackPortIsInput, 0);
+        QTextStream(&inName) << "send_" << i + 1;
+        mInPorts[i] =
+            jack_port_register(mClient, inName.toLatin1(), JACK_DEFAULT_AUDIO_TYPE,
+                               JackPortIsInput | JackPortIsTerminal, 0);
     }
 
-    //Create Output Ports
+    // Create Output Ports
     mOutPorts.resize(mNumOutChans);
-    for (int i = 0; i < mNumInChans; i++)
-    {
+    for (int i = 0; i < mNumOutChans; i++) {
         QString outName;
-        QTextStream (&outName) << "receive_" << i+1;
-        mOutPorts[i] = jack_port_register (mClient, outName.toLatin1(),
-                                           JACK_DEFAULT_AUDIO_TYPE,
-                                           JackPortIsOutput, 0);
+        QTextStream(&outName) << "receive_" << i + 1;
+        mOutPorts[i] =
+            jack_port_register(mClient, outName.toLatin1(), JACK_DEFAULT_AUDIO_TYPE,
+                               JackPortIsOutput | JackPortIsTerminal, 0);
     }
-    //Create Broadcast Ports
+    // Create Broadcast Ports
     if (mBroadcast) {
         mBroadcastPorts.resize(mNumOutChans);
-        for (int i = 0; i < mNumInChans; i++)
-        {
+        for (int i = 0; i < mNumOutChans; i++) {
             QString outName;
-            QTextStream (&outName) << "broadcast_" << i+1;
-            mBroadcastPorts[i] = jack_port_register (mClient, outName.toLatin1(),
-                                               JACK_DEFAULT_AUDIO_TYPE,
-                                               JackPortIsOutput, 0);
+            QTextStream(&outName) << "broadcast_" << i + 1;
+            mBroadcastPorts[i] =
+                jack_port_register(mClient, outName.toLatin1(), JACK_DEFAULT_AUDIO_TYPE,
+                                   JackPortIsOutput | JackPortIsTerminal, 0);
         }
     }
 }
 
-
 //*******************************************************************************
 uint32_t JackAudioInterface::getSampleRate() const
 {
     return jack_get_sample_rate(mClient);
 }
 
-
 //*******************************************************************************
 uint32_t JackAudioInterface::getBufferSizeInSamples() const
 {
     return jack_get_buffer_size(mClient);
 }
 
-
 //*******************************************************************************
 size_t JackAudioInterface::getSizeInBytesPerChannel() const
 {
-    return (getBufferSizeInSamples() * getAudioBitResolution()/8);
+    return (getBufferSizeInSamples() * getAudioBitResolution() / 8);
 }
 
 //*******************************************************************************
 void JackAudioInterface::setProcessCallback()
 {
     std::cout << "Setting JACK Process Callback..." << std::endl;
-    if ( int code =
-         jack_set_process_callback(mClient, JackAudioInterface::wrapperProcessCallback, this)
-         )
-    {
-        //std::cerr << "Could not set the process callback" << std::endl;
-        //return(code);
-        (void) code; // to avoid compiler warnings
+    if (int code = jack_set_process_callback(
+            mClient, JackAudioInterface::wrapperProcessCallback, this)) {
+        // std::cerr << "Could not set the process callback" << std::endl;
+        // return(code);
+        (void)code;  // to avoid compiler warnings
         throw std::runtime_error("Could not set the Jack process callback");
-        //std::exit(1);
+        // std::exit(1);
     }
     std::cout << "SUCCESS" << std::endl;
     std::cout << gPrintSeparator << std::endl;
-    //return(0);
+    // return(0);
 }
 
-
 //*******************************************************************************
 int JackAudioInterface::startProcess() const
 {
-    //Tell the JACK server that we are ready to roll.  Our
-    //process() callback will start running now.
-    if ( int code = (jack_activate(mClient)) )
-    {
-        std::cerr << "Cannot activate client" << std::endl;
-        return(code);
+    // Tell the JACK server that we are ready to roll.  Our
+    // process() callback will start running now.
+    if (int code = (jack_activate(mClient))) {
+        std::cerr << "Cannot activate JACK client" << std::endl;
+        return (code);
     }
-    return(0);
+    return (0);
 }
 
-
 //*******************************************************************************
 int JackAudioInterface::stopProcess() const
 {
     QMutexLocker locker(&sJackMutex);
-    int code = (jack_client_close(mClient));
-    if ( code != 0  )
-    {
-        std::cerr << "Cannot disconnect client" << std::endl;
-        return(code);
+    int code = (jack_deactivate(mClient));
+    if (code != 0) {
+        std::cerr << "Cannot deactivate JACK client" << std::endl;
+        return (code);
+    }
+    code = (jack_client_close(mClient));
+    if (code != 0) {
+        std::cerr << "Cannot disconnect JACK client" << std::endl;
+        return (code);
     }
-    return(0);
+    return (0);
 }
 
-
 //*******************************************************************************
-void JackAudioInterface::jackShutdown (void*)
+void JackAudioInterface::jackShutdown(void*)
 {
-    //std::cout << "The Jack Server was shut down!" << std::endl;
+    // std::cout << "The Jack Server was shut down!" << std::endl;
     JackTrip::sJackStopped = true;
     std::cout << "The Jack Server was shut down!" << std::endl;
-    //throw std::runtime_error("The Jack Server was shut down!");
-    //std::cout << "Exiting program..." << std::endl;
-    //std::exit(1);
+    // throw std::runtime_error("The Jack Server was shut down!");
+    // std::cout << "Exiting program..." << std::endl;
+    // std::exit(1);
 }
 
-
-
 //*******************************************************************************
 int JackAudioInterface::processCallback(jack_nframes_t nframes)
 {
-  if(mProcessingAudio) {
-    std::cerr << "*** JackAudioInterface.cpp: DROPPED A BUFFER because AudioInterface::callback() not finished\n";
-    return 1;
-  }
+    if (mProcessingAudio) {
+        std::cerr << "*** JackAudioInterface.cpp: DROPPED A BUFFER because "
+                     "AudioInterface::callback() not finished\n";
+        return 1;
+    }
 
     // Get input and output buffers from JACK
     //-------------------------------------------------------------------
     for (int i = 0; i < mNumInChans; i++) {
-        // Input Ports are READ ONLY and change as needed (no locks) - make a copy for debugging
-        mInBuffer[i] = (sample_t*) jack_port_get_buffer(mInPorts[i], nframes);
+        // Input Ports are READ ONLY and change as needed (no locks) - make a copy for
+        // debugging
+        mInBuffer[i] = (sample_t*)jack_port_get_buffer(mInPorts[i], nframes);
     }
     for (int i = 0; i < mNumOutChans; i++) {
         // Output Ports are WRITABLE
-        mOutBuffer[i] = (sample_t*) jack_port_get_buffer(mOutPorts[i], nframes);
+        mOutBuffer[i] = (sample_t*)jack_port_get_buffer(mOutPorts[i], nframes);
     }
     //-------------------------------------------------------------------
     // TEST: Loopback
     // To test, uncomment and send audio to client input. The same audio
     // should come out as output in the first channel
-    //memcpy (mOutBuffer[0], mInBuffer[0], sizeof(sample_t) * nframes);
-    //memcpy (mOutBuffer[1], mInBuffer[1], sizeof(sample_t) * nframes);
+    // memcpy (mOutBuffer[0], mInBuffer[0], sizeof(sample_t) * nframes);
+    // memcpy (mOutBuffer[1], mInBuffer[1], sizeof(sample_t) * nframes);
     //-------------------------------------------------------------------
 
     AudioInterface::callback(mInBuffer, mOutBuffer, nframes);
@@ -327,250 +306,58 @@ int JackAudioInterface::processCallback(jack_nframes_t nframes)
     if (mBroadcast) {
         for (int i = 0; i < mNumOutChans; i++) {
             // Broadcast Ports are WRITABLE
-            mBroadcastBuffer[i] = (sample_t*) jack_port_get_buffer(mBroadcastPorts[i], nframes);
+            mBroadcastBuffer[i] =
+                (sample_t*)jack_port_get_buffer(mBroadcastPorts[i], nframes);
         }
         AudioInterface::broadcastCallback(mBroadcastBuffer, nframes);
     }
     return 0;
 }
 
-
 //*******************************************************************************
-int JackAudioInterface::wrapperProcessCallback(jack_nframes_t nframes, void *arg)
+int JackAudioInterface::wrapperProcessCallback(jack_nframes_t nframes, voidarg)
 {
     return static_cast<JackAudioInterface*>(arg)->processCallback(nframes);
 }
 
-
 //*******************************************************************************
 void JackAudioInterface::connectDefaultPorts()
 {
     const char** ports;
 
     // Get physical output (capture) ports
-    if ( (ports =
-          jack_get_ports (mClient, NULL, NULL,
-                          JackPortIsPhysical | JackPortIsOutput)) == NULL)
-    {
+    if ((ports =
+             jack_get_ports(mClient, NULL, NULL, JackPortIsPhysical | JackPortIsOutput))
+        == NULL) {
         cout << "WARNING: Cannot find any physical capture ports" << endl;
-    }
-    else
-    {
+    } else {
         // Connect capure ports to jacktrip send
-        for (int i = 0; i < mNumInChans; i++)
-        {
+        for (int i = 0; i < mNumInChans; i++) {
             // Check that we don't run out of capture ports
-            if ( ports[i] != NULL ) {
+            if (ports[i] != NULL) {
                 jack_connect(mClient, ports[i], jack_port_name(mInPorts[i]));
+            } else {
+                break;
             }
         }
         std::free(ports);
     }
 
     // Get physical input (playback) ports
-    if ( (ports =
-          jack_get_ports (mClient, NULL, NULL,
-                          JackPortIsPhysical | JackPortIsInput)) == NULL)
-    {
+    if ((ports =
+             jack_get_ports(mClient, NULL, NULL, JackPortIsPhysical | JackPortIsInput))
+        == NULL) {
         cout << "WARNING: Cannot find any physical playback ports" << endl;
-    }
-    else
-    {
+    } else {
         // Connect playback ports to jacktrip receive
-        for (int i = 0; i < mNumOutChans; i++)
-        {
+        for (int i = 0; i < mNumOutChans; i++) {
             // Check that we don't run out of capture ports
-            if ( ports[i] != NULL ) {
+            if (ports[i] != NULL) {
                 jack_connect(mClient, jack_port_name(mOutPorts[i]), ports[i]);
+            } else {
+                break;
             }
         }
         std::free(ports);
     }
 }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-// OLD CODE (some moved to parent class AudioInterface.cpp)
-// ==============================================================================
-
-//*******************************************************************************
-/*
-int JackAudioInterface::processCallback(jack_nframes_t nframes)
-{
-  // Get input and output buffers from JACK
-  //-------------------------------------------------------------------
-  for (int i = 0; i < mNumInChans; i++) {
-    // Input Ports are READ ONLY
-    mInBuffer[i] = (sample_t*) jack_port_get_buffer(mInPorts[i], nframes);
-  }
-  for (int i = 0; i < mNumOutChans; i++) {
-    // Output Ports are WRITABLE
-    mOutBuffer[i] = (sample_t*) jack_port_get_buffer(mOutPorts[i], nframes);
-  }
-  //-------------------------------------------------------------------
-  // TEST: Loopback
-  // To test, uncomment and send audio to client input. The same audio
-  // should come out as output in the first channel
-  //memcpy (mOutBuffer[0], mInBuffer[0], sizeof(sample_t) * nframes);
-  //memcpy (mOutBuffer[1], mInBuffer[1], sizeof(sample_t) * nframes);
-  //-------------------------------------------------------------------
-
-  // Allocate the Process Callback
-  //-------------------------------------------------------------------
-  // 1) First, process incoming packets
-  // ----------------------------------
-  computeNetworkProcessFromNetwork();
-
-
-  // 2) Dynamically allocate ProcessPlugin processes
-  // -----------------------------------------------
-  // The processing will be done in order of allocation
-
-  ///\todo Implement for more than one process plugin, now it just works propertely with one.
-  /// do it chaining outputs to inputs in the buffers. May need a tempo buffer
-  for (int i = 0; i < mNumInChans; i++) {
-    std::memset(mInProcessBuffer[i], 0, sizeof(sample_t) * nframes);
-    std::memcpy(mInProcessBuffer[i], mOutBuffer[i], sizeof(sample_t) * nframes);
-  }
-  for (int i = 0; i < mNumOutChans; i++) {
-    std::memset(mOutProcessBuffer[i], 0, sizeof(sample_t) * nframes);
-  }
-
-  for (int i = 0; i < mProcessPlugins.size(); i++) {
-    //mProcessPlugins[i]->compute(nframes, mOutBuffer.data(), mInBuffer.data());
-    mProcessPlugins[i]->compute(nframes, mInProcessBuffer.data(), mOutProcessBuffer.data());
-  }
-
-
-  // 3) Finally, send packets to peer
-  // --------------------------------
-  computeNetworkProcessToNetwork();
-*/
-///************PROTORYPE FOR CELT**************************
-///********************************************************
-/*
-  CELTMode* mode;
-  int* error;
-  mode = celt_mode_create(48000, 2, 64, error);
-  */
-//celt_mode_create(48000, 2, 64, NULL);
-//unsigned char* compressed;
-//CELTEncoder* celtEncoder;
-//celt_encode_float(celtEncoder, mInBuffer, NULL, compressed, );
-
-///********************************************************
-///********************************************************
-//  return 0;
-//}
-
-
-
-//*******************************************************************************
-/*
-void JackAudioInterface::setRingBuffers
-(const std::tr1::shared_ptr<RingBuffer> InRingBuffer,
- const std::tr1::shared_ptr<RingBuffer> OutRingBuffer)
-{
-  mInRingBuffer = InRingBuffer;
-  mOutRingBuffer = OutRingBuffer;
-}
-*/
-
-
-//*******************************************************************************
-// Before sending and reading to Jack, we have to round to the sample resolution
-// that the program is using. Jack uses 32 bits (gJackBitResolution in globals.h)
-// by default
-/*
-void JackAudioInterface::computeNetworkProcessFromNetwork()
-{
-  /// \todo cast *mInBuffer[i] to the bit resolution
-  //cout << mNumFrames << endl;
-  // Output Process (from NETWORK to JACK)
-  // ----------------------------------------------------------------
-  // Read Audio buffer from RingBuffer (read from incoming packets)
-  //mOutRingBuffer->readSlotNonBlocking( mOutputPacket );
-  mJackTrip->receiveNetworkPacket( mOutputPacket );
-
-  // Extract separate channels to send to Jack
-  for (int i = 0; i < mNumOutChans; i++) {
-    //--------
-    // This should be faster for 32 bits
-    //std::memcpy(mOutBuffer[i], &mOutputPacket[i*mSizeInBytesPerChannel],
-    //         mSizeInBytesPerChannel);
-    //--------
-    sample_t* tmp_sample = mOutBuffer[i]; //sample buffer for channel i
-    for (int j = 0; j < mNumFrames; j++) {
-      //std::memcpy(&tmp_sample[j], &mOutputPacket[(i*mSizeInBytesPerChannel) + (j*4)], 4);
-      // Change the bit resolution on each sample
-      //cout << tmp_sample[j] << endl;
-      fromBitToSampleConversion(&mOutputPacket[(i*mSizeInBytesPerChannel)
-                 + (j*mBitResolutionMode)],
-        &tmp_sample[j],
-        mBitResolutionMode);
-    }
-  }
-}
-*/
-
-//*******************************************************************************
-/*
-void JackAudioInterface::computeNetworkProcessToNetwork()
-{
-  // Input Process (from JACK to NETWORK)
-  // ----------------------------------------------------------------
-  // Concatenate  all the channels from jack to form packet
-  for (int i = 0; i < mNumInChans; i++) {
-    //--------
-    // This should be faster for 32 bits
-    //std::memcpy(&mInputPacket[i*mSizeInBytesPerChannel], mInBuffer[i],
-    //         mSizeInBytesPerChannel);
-    //--------
-    sample_t* tmp_sample = mInBuffer[i]; //sample buffer for channel i
-    sample_t* tmp_process_sample = mOutProcessBuffer[i]; //sample buffer from the output process
-    sample_t tmp_result;
-    for (int j = 0; j < mNumFrames; j++) {
-      //std::memcpy(&tmp_sample[j], &mOutputPacket[(i*mSizeInBytesPerChannel) + (j*4)], 4);
-      // Change the bit resolution on each sample
-
-      // Add the input jack buffer to the buffer resulting from the output process
-      tmp_result = tmp_sample[j] + tmp_process_sample[j];
-      fromSampleToBitConversion(&tmp_result,
-        &mInputPacket[(i*mSizeInBytesPerChannel)
-                + (j*mBitResolutionMode)],
-        mBitResolutionMode);
-    }
-  }
-  // Send Audio buffer to RingBuffer (these goes out as outgoing packets)
-  //mInRingBuffer->insertSlotNonBlocking( mInputPacket );
-  mJackTrip->sendNetworkPacket( mInputPacket );
-}
-*/
-
-
-//*******************************************************************************
-/*
-//void JackAudioInterface::appendProcessPlugin(const std::tr1::shared_ptr<ProcessPlugin> plugin)
-void JackAudioInterface::appendProcessPlugin(ProcessPlugin* plugin)
-{
-  /// \todo check that channels in ProcessPlugins are less or same that jack channels
-  if ( plugin->getNumInputs() ) {}
-  mProcessPlugins.append(plugin);
-}
-*/
index 5a1b4b0c13c4b2a450a5f0defdc5f95b15eee937..369a25baf7bd6652529aab8afe10a0aa8f95fde8 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
  * \date June 2008
  */
 
-
 #ifndef __JACKAUDIOINTERFACE_H__
 #define __JACKAUDIOINTERFACE_H__
 
 #include <iostream>
 //#include <tr1/memory> //for shared_ptr
-#include <functional> //for mem_fun_ref
+#ifdef USE_WEAK_JACK
+#include "weak_libjack.h"
+#else
 #include <jack/jack.h>
+#endif
 
-#include <QVector>
-#include <QVarLengthArray>
 #include <QMutex>
+#include <QVarLengthArray>
+#include <QVector>
+#include <functional>  //for mem_fun_ref
 
-
-#include "jacktrip_types.h"
-#include "ProcessPlugin.h"
 #include "AudioInterface.h"
+#include "ProcessPlugin.h"
+#include "jacktrip_types.h"
 
-//class JackTrip; //forward declaration
-
+// class JackTrip; //forward declaration
 
 /** \brief Class that provides an interface with the Jack Audio Server
  *
  * \todo implement srate_callback
- * \todo automatically starts jack with buffer and sample rate settings specified by the user
+ * \todo automatically starts jack with buffer and sample rate settings specified by the
+ * user
  */
 class JackAudioInterface : public AudioInterface
 {
-public:
-
+   public:
     /** \brief The class constructor
-   * \param jacktrip Pointer to the JackTrip class that connects all classes (mediator)
-   * \param NumInChans Number of Input Channels
-   * \param NumOutChans Number of Output Channels
-   * \param AudioBitResolution Audio Sample Resolutions in bits
-   * \param ClientName Client name in Jack
-   */
-    JackAudioInterface(JackTrip* jacktrip,
-                       int NumInChans, int NumOutChans,
-                   #ifdef WAIR // wair
-                       int NumNetRevChans,
-                   #endif // endwhere
-                       AudioInterface::audioBitResolutionT AudioBitResolution = AudioInterface::BIT16,
-                       QString ClientName = "JackTrip");
+     * \param jacktrip Pointer to the JackTrip class that connects all classes (mediator)
+     * \param NumInChans Number of Input Channels
+     * \param NumOutChans Number of Output Channels
+     * \param AudioBitResolution Audio Sample Resolutions in bits
+     * \param ClientName Client name in Jack
+     */
+    JackAudioInterface(
+        JackTrip* jacktrip, int NumInChans, int NumOutChans,
+#ifdef WAIR  // wair
+        int NumNetRevChans,
+#endif  // endwhere
+        AudioInterface::audioBitResolutionT AudioBitResolution = AudioInterface::BIT16,
+        QString ClientName                                     = "JackTrip");
     /// \brief The class destructor
     virtual ~JackAudioInterface();
 
     /// \brief Setup the client
     virtual void setup();
     /** \brief Tell the JACK server that we are ready to roll. The
-   * process-callback will start running. This runs on its own thread.
-   * \return 0 on success, otherwise a non-zero error code
-   */
+     * process-callback will start running. This runs on its own thread.
+     * \return 0 on success, otherwise a non-zero error code
+     */
     virtual int startProcess() const;
     /** \brief Stops the process-callback thread
-   * \return 0 on success, otherwise a non-zero error code
-   */
+     * \return 0 on success, otherwise a non-zero error code
+     */
     virtual int stopProcess() const;
     /// \brief Connect the default ports, capture to sends, and receives to playback
     void connectDefaultPorts();
 
     //--------------SETTERS---------------------------------------------
     /// \brief Set Client Name to something different that the default (JackTrip)
-    virtual void setClientName(QString ClientName)
-    { mClientName = ClientName; }
+    virtual void setClientName(QString ClientName) { mClientName = ClientName; }
     virtual void setSampleRate(uint32_t /*sample_rate*/)
-    { std::cout << "WARNING: Setting the Sample Rate in Jack mode has no effect." << std::endl; }
+    {
+        std::cout << "WARNING: Setting the Sample Rate in Jack mode has no effect."
+                  << std::endl;
+    }
     virtual void setBufferSizeInSamples(uint32_t /*buf_size*/)
-    { std::cout << "WARNING: Setting the Sample Rate in Jack mode has no effect." << std::endl; }
-    virtual void enableBroadcastOutput() {mBroadcast = true;}
+    {
+        std::cout << "WARNING: Setting the Sample Rate in Jack mode has no effect."
+                  << std::endl;
+    }
+    virtual void enableBroadcastOutput() { mBroadcast = true; }
     //------------------------------------------------------------------
 
     //--------------GETTERS---------------------------------------------
+    /// \brief Get the actual client name assigned by the Jack server
+    virtual QString getAssignedClientName() final { return mAssignedClientName; }
     /// \brief Get the Jack Server Sampling Rate, in samples/second
     virtual uint32_t getSampleRate() const;
     /// \brief Get the Jack Server Buffer Size, in samples
     virtual uint32_t getBufferSizeInSamples() const;
     /// \brief Get the Jack Server Buffer Size, in bytes
     virtual uint32_t getBufferSizeInBytes() const
-    { return (getBufferSizeInSamples() * getAudioBitResolution() / 8); }
+    {
+        return (getBufferSizeInSamples() * getAudioBitResolution() / 8);
+    }
     /// \brief Get size of each audio per channel, in bytes
     virtual size_t getSizeInBytesPerChannel() const;
     //------------------------------------------------------------------
 
-private:
-
+   private:
     /** \brief Private method to setup a client of the Jack server.
-   * \exception std::runtime_error Can't start Jack
-   *
-   * This method is called by the class constructors. It does the following:\n
-   *  - Connects to the JACK server
-   *  - Sets the shutdown process callback
-   *  - Creates the appropriate number of input and output channels
-   */
+     * \exception std::runtime_error Can't start Jack
+     *
+     * This method is called by the class constructors. It does the following:\n
+     *  - Connects to the JACK server
+     *  - Sets the shutdown process callback
+     *  - Creates the appropriate number of input and output channels
+     */
     void setupClient();
     /// \brief Creates input and output channels in the Jack client
     void createChannels();
     /** \brief JACK calls this shutdown_callback if the server ever shuts down or
-   * decides to disconnect the client.
-   */
+     * decides to disconnect the client.
+     */
     static void jackShutdown(void*);
     /** \brief Set the process callback of the member function processCallback.
-   * This process will be called by the JACK server whenever there is work to be done.
-   */
+     * This process will be called by the JACK server whenever there is work to be done.
+     */
     void setProcessCallback();
     /** \brief JACK process callback
-   *
-   * This is the function to be called to process audio. This function is
-   * of the type JackProcessCallback, which is defined as:\n
-   * <tt>typedef int(* JackProcessCallback)(jack_nframes_t nframes, void *arg)</tt>
-   * \n
-   * See
-   * http://jackaudio.org/files/docs/html/types_8h.html#4923142208a8e7dacf00ca7a10681d2b
-   * for more details
-   */
+     *
+     * This is the function to be called to process audio. This function is
+     * of the type JackProcessCallback, which is defined as:\n
+     * <tt>typedef int(* JackProcessCallback)(jack_nframes_t nframes, void *arg)</tt>
+     * \n
+     * See
+     * http://jackaudio.org/files/docs/html/types_8h.html#4923142208a8e7dacf00ca7a10681d2b
+     * for more details
+     */
     int processCallback(jack_nframes_t nframes);
     /** \brief Wrapper to cast the member processCallback to a static function pointer
-   * that can be used with <tt>jack_set_process_callback</tt>
-   *
-   * <tt>jack_set_process_callback</tt> needs a static member function pointer. A normal
-   * member function won't work because a <b><i>this</i></b> pointer is passed under the scenes.
-   * That's why we
-   * need to cast the member funcion processCallback to the static function
-   * wrapperProcessCallback. The callback is then set as:\n
-   * <tt>jack_set_process_callback(mClient, JackAudioInterface::wrapperProcessCallback,
-   *                              this)</tt>
-   */
+     * that can be used with <tt>jack_set_process_callback</tt>
+     *
+     * <tt>jack_set_process_callback</tt> needs a static member function pointer. A normal
+     * member function won't work because a <b><i>this</i></b> pointer is passed under the
+     * scenes. That's why we need to cast the member funcion processCallback to the static
+     * function wrapperProcessCallback. The callback is then set as:\n
+     * <tt>jack_set_process_callback(mClient, JackAudioInterface::wrapperProcessCallback,
+     *                              this)</tt>
+     */
     // reference : http://article.gmane.org/gmane.comp.audio.jackit/12873
-    static int wrapperProcessCallback(jack_nframes_t nframes, void *arg) ;
-
-    int mNumInChans;///< Number of Input Channels
-    int mNumOutChans; ///<  Number of Output Channels
-#ifdef WAIR // WAIR
-    int mNumNetRevChans; ///<  Number of Network Audio Channels (network comb filters
-#endif // endwhere
-    int mNumFrames; ///< Buffer block size, in samples
-    //int mAudioBitResolution; ///< Bit resolution in audio samples
-    AudioInterface::audioBitResolutionT mBitResolutionMode; ///< Bit resolution (audioBitResolutionT) mode
-
-    jack_client_t* mClient; ///< Jack Client
-    QString mClientName; ///< Jack Client Name
-    QVarLengthArray<jack_port_t*> mInPorts; ///< Vector of Input Ports (Channels)
-    QVarLengthArray<jack_port_t*> mOutPorts; ///< Vector of Output Ports (Channels)
-    QVarLengthArray<jack_port_t*> mBroadcastPorts; ///< Vector of Output Ports (Channels)
-    QVarLengthArray<sample_t*> mInBuffer; ///< Vector of Input buffers/channel read from JACK
-    QVarLengthArray<sample_t*> mOutBuffer; ///< Vector of Output buffer/channel to write to JACK
-    QVarLengthArray<sample_t*> mBroadcastBuffer; ///< Vector of Output buffer/channel to write to JACK
+    static int wrapperProcessCallback(jack_nframes_t nframes, void* arg);
+
+    int mNumInChans;      ///< Number of Input Channels
+    int mNumOutChans;     ///<  Number of Output Channels
+#ifdef WAIR               // WAIR
+    int mNumNetRevChans;  ///<  Number of Network Audio Channels (network comb filters
+#endif                    // endwhere
+    int mNumFrames;       ///< Buffer block size, in samples
+
+    jack_client_t* mClient;  ///< Jack Client
+    QString mClientName;     ///< Jack Client Name
+    QString mAssignedClientName;
+    QVarLengthArray<jack_port_t*> mInPorts;         ///< Vector of Input Ports (Channels)
+    QVarLengthArray<jack_port_t*> mOutPorts;        ///< Vector of Output Ports (Channels)
+    QVarLengthArray<jack_port_t*> mBroadcastPorts;  ///< Vector of Output Ports (Channels)
+    QVarLengthArray<sample_t*>
+        mInBuffer;  ///< Vector of Input buffers/channel read from JACK
+    QVarLengthArray<sample_t*>
+        mOutBuffer;  ///< Vector of Output buffer/channel to write to JACK
+    QVarLengthArray<sample_t*>
+        mBroadcastBuffer;  ///< Vector of Output buffer/channel to write to JACK
     bool mBroadcast;
-    size_t mSizeInBytesPerChannel; ///< Size in bytes per audio channel
-    QVector<ProcessPlugin*> mProcessPlugins; ///< Vector of ProcesPlugin<EM>s</EM>
-    JackTrip* mJackTrip; ///< JackTrip mediator class
-    static QMutex sJackMutex; ///< Mutex to make thread safe jack functions that are not
+    QVector<ProcessPlugin*> mProcessPlugins;  ///< Vector of ProcesPlugin<EM>s</EM>
+    static QMutex sJackMutex;  ///< Mutex to make thread safe jack functions that are not
 };
 
-
 #endif
index f67298440acc5d861a687cc74d4dee5b1221ba1c..c489e6f2022fb5bf8ed4b091c1a20febd933b852 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
  */
 
 #include "JackTrip.h"
-#include "UdpDataProtocol.h"
-#include "RingBufferWavetable.h"
+
+#ifndef __NO_JACK__
+#include "JackAudioInterface.h"
+#endif
+#include "Auth.h"
 #include "JitterBuffer.h"
+#include "PoolBuffer.h"
+#include "RingBufferWavetable.h"
+#include "UdpDataProtocol.h"
 #include "jacktrip_globals.h"
-#include "JackAudioInterface.h"
 #ifdef __RT_AUDIO__
 #include "RtAudioInterface.h"
 #endif
 
-#include <iostream>
-#include <cstdlib>
-#include <stdexcept>
-
+#include <QDateTime>
 #include <QHostAddress>
 #include <QHostInfo>
 #include <QThread>
 #include <QTimer>
-#include <QDateTime>
+#include <QtEndian>
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
 
-using std::cout; using std::endl;
+using std::cout;
+using std::endl;
 
-//the following function has to remain outside the Jacktrip class definition
-//its purpose is to close the app when control c is hit by the user in rtaudio/asio4all mode
+// the following function has to remain outside the Jacktrip class definition
+// its purpose is to close the app when control c is hit by the user in rtaudio/asio4all
+// mode
 /*if defined __WIN_32__
 void sigint_handler(int sig)
 {
@@ -66,83 +73,81 @@ void sigint_handler(int sig)
 }
 #endif*/
 
-bool JackTrip::sSigInt = false;
+bool JackTrip::sSigInt      = false;
 bool JackTrip::sJackStopped = false;
 
 //*******************************************************************************
-JackTrip::JackTrip(jacktripModeT JacktripMode,
-                   dataProtocolT DataProtocolType,
-                   int NumChans,
-                   #ifdef WAIR // WAIR
+JackTrip::JackTrip(jacktripModeT JacktripMode, dataProtocolT DataProtocolType,
+                   int NumChansIn, int NumChansOut,
+#ifdef WAIR  // WAIR
                    int NumNetRevChans,
-                   #endif // endwhere
-                   int BufferQueueLength,
-                   unsigned int redundancy,
+#endif  // endwhere
+                   int BufferQueueLength, unsigned int redundancy,
                    AudioInterface::audioBitResolutionT AudioBitResolution,
                    DataProtocol::packetHeaderTypeT PacketHeaderType,
-                   underrunModeT UnderRunMode,
-                   int receiver_bind_port, int sender_bind_port,
-                   int receiver_peer_port, int sender_peer_port, int tcp_peer_port) :
-    mJackTripMode(JacktripMode),
-    mDataProtocol(DataProtocolType),
-    mPacketHeaderType(PacketHeaderType),
-    mAudiointerfaceMode(JackTrip::JACK),
-    mNumChans(NumChans),
-    #ifdef WAIR // WAIR
-    mNumNetRevChans(NumNetRevChans),
-    #endif // endwhere
-    mBufferQueueLength(BufferQueueLength),
-    mBufferStrategy(1),
-    mBroadcastQueueLength(0),
-    mSampleRate(gDefaultSampleRate),
-    mDeviceID(gDefaultDeviceID),
-    mAudioBufferSize(gDefaultBufferSizeInSamples),
-    mAudioBitResolution(AudioBitResolution),
-    mLoopBack(false),
-    mDataProtocolSender(NULL),
-    mDataProtocolReceiver(NULL),
-    mAudioInterface(NULL),
-    mPacketHeader(NULL),
-    mUnderRunMode(UnderRunMode),
-    mStopOnTimeout(false),
-    mSendRingBuffer(NULL),
-    mReceiveRingBuffer(NULL),
-    mReceiverBindPort(receiver_bind_port),
-    mSenderPeerPort(sender_peer_port),
-    mSenderBindPort(sender_bind_port),
-    mReceiverPeerPort(receiver_peer_port),
-    mTcpServerPort(tcp_peer_port),
-    mRedundancy(redundancy),
-    mJackClientName(gJackDefaultClientName),
-    mConnectionMode(JackTrip::NORMAL),
-    mTimeoutTimer(this),
-    mSleepTime(100),
-    mElapsedTime(0),
-    mEndTime(0),
-    mTcpClient(this),
-    mUdpSockTemp(this),
-    mReceivedConnection(false),
-    mTcpConnectionError(false),
-    mStopped(false),
-    mHasShutdown(false),
-    mConnectDefaultAudioPorts(true),
-    mIOStatTimeout(0),
-    mIOStatLogStream(std::cout.rdbuf()),
-    mSimulatedLossRate(0.0),
-    mSimulatedJitterRate(0.0),
-    mSimulatedDelayRel(0.0),
-    mUseRtUdpPriority(false),
-    mAudioTesterP(nullptr)
+                   underrunModeT UnderRunMode, int receiver_bind_port,
+                   int sender_bind_port, int receiver_peer_port, int sender_peer_port,
+                   int tcp_peer_port)
+    : mJackTripMode(JacktripMode)
+    , mDataProtocol(DataProtocolType)
+    , mPacketHeaderType(PacketHeaderType)
+    , mAudiointerfaceMode(JackTrip::JACK)
+    , mNumAudioChansIn(NumChansIn)
+    , mNumAudioChansOut(NumChansOut)
+#ifdef WAIR  // WAIR
+    , mNumNetRevChans(NumNetRevChans)
+#endif  // endwhere
+    , mBufferQueueLength(BufferQueueLength)
+    , mBufferStrategy(1)
+    , mBroadcastQueueLength(0)
+    , mSampleRate(gDefaultSampleRate)
+    , mDeviceID(gDefaultDeviceID)
+    , mAudioBufferSize(gDefaultBufferSizeInSamples)
+    , mAudioBitResolution(AudioBitResolution)
+    , mLoopBack(false)
+    , mDataProtocolSender(NULL)
+    , mDataProtocolReceiver(NULL)
+    , mAudioInterface(NULL)
+    , mPacketHeader(NULL)
+    , mUnderRunMode(UnderRunMode)
+    , mStopOnTimeout(false)
+    , mSendRingBuffer(NULL)
+    , mReceiveRingBuffer(NULL)
+    , mReceiverBindPort(receiver_bind_port)
+    , mSenderPeerPort(sender_peer_port)
+    , mSenderBindPort(sender_bind_port)
+    , mReceiverPeerPort(receiver_peer_port)
+    , mTcpServerPort(tcp_peer_port)
+    , mUseAuth(false)
+    , mRedundancy(redundancy)
+    , mTimeoutTimer(this)
+    , mSleepTime(100)
+    , mElapsedTime(0)
+    , mEndTime(0)
+    , mTcpClient(this)
+    , mUdpSockTemp(this)
+    , mAwaitingUdp(false)
+    , mAwaitingTcp(false)
+    , mReceivedConnection(false)
+    , mTcpConnectionError(false)
+    , mStopped(false)
+    , mHasShutdown(false)
+    , mConnectDefaultAudioPorts(true)
+    , mIOStatTimeout(0)
+    , mIOStatLogStream(std::cout.rdbuf())
+    , mSimulatedLossRate(0.0)
+    , mSimulatedJitterRate(0.0)
+    , mSimulatedDelayRel(0.0)
+    , mUseRtUdpPriority(false)
 {
     createHeader(mPacketHeaderType);
     sJackStopped = false;
 }
 
-
 //*******************************************************************************
 JackTrip::~JackTrip()
 {
-    //wait();
+    // wait();
     delete mDataProtocolSender;
     delete mDataProtocolReceiver;
     delete mAudioInterface;
@@ -151,16 +156,16 @@ JackTrip::~JackTrip()
     delete mReceiveRingBuffer;
 }
 
-
 //*******************************************************************************
 void JackTrip::setupAudio(
-        #ifdef WAIRTOHUB // WAIR
-        __attribute__((unused)) int ID
-        #endif // endwhere
-        )
+#ifdef WAIRTOHUB  // WAIR
+    [[maybe_unused]] int ID
+#endif  // endwhere
+)
 {
     // Check if mAudioInterface has already been created or not
-    if (mAudioInterface != NULL)  { // if it has been created, disconnet it from JACK and delete it
+    if (mAudioInterface
+        != NULL) {  // if it has been created, disconnet it from JACK and delete it
         cout << "WARINING: JackAudio interface was setup already:" << endl;
         cout << "It will be erased and setup again." << endl;
         cout << gPrintSeparator << endl;
@@ -168,72 +173,104 @@ void JackTrip::setupAudio(
     }
 
     // Create AudioInterface Client Object
-    if ( mAudiointerfaceMode == JackTrip::JACK ) {
+    if (mAudiointerfaceMode == JackTrip::JACK) {
 #ifndef __NO_JACK__
-        if (gVerboseFlag) std::cout << "  JackTrip:setupAudio before new JackAudioInterface" << std::endl;
-        mAudioInterface = new JackAudioInterface(this, mNumChans, mNumChans,
-                                         #ifdef WAIR // wair
-                                                 mNumNetRevChans,
-                                         #endif // endwhere
-                                                 mAudioBitResolution);
-
-#ifdef WAIRTOHUB // WAIR
-        QString VARIABLE_AUDIO_NAME = WAIR_AUDIO_NAME; // legacy for WAIR
-        //Set our Jack client name if we're a hub server or a custom name hasn't been set
-        if (!mPeerAddress.isEmpty() && (mJackClientName.constData() == gJackDefaultClientName.constData())) {
-            mJackClientName = QString(mPeerAddress).replace(":", "_");
+        if (gVerboseFlag)
+            std::cout << "  JackTrip:setupAudio before new JackAudioInterface"
+                      << std::endl;
+        mAudioInterface =
+            new JackAudioInterface(this, mNumAudioChansIn, mNumAudioChansOut,
+#ifdef WAIR  // wair
+                                   mNumNetRevChans,
+#endif  // endwhere
+                                   mAudioBitResolution);
+
+#ifdef WAIRTOHUB  // WAIR
+
+        // Set our Jack client name if we're a hub server or a custom name hasn't been set
+        if (mJackClientName.isEmpty()) {
+            if (!mPeerAddress.isEmpty()) {
+                mJackClientName = QString(mPeerAddress).replace(":", "_");
+            } else {
+                mJackClientName = gJackDefaultClientName;
+            }
         }
-        //std::cout  << "WAIR ID " << ID << " jacktrip client name set to=" <<
+        // std::cout  << "WAIR ID " << ID << " jacktrip client name set to=" <<
         //              mJackClientName.toStdString() << std::endl;
 
-#endif // endwhere
+#endif  // endwhere
         mAudioInterface->setClientName(mJackClientName);
-        if (0 < mBroadcastQueueLength) {
-            mAudioInterface->enableBroadcastOutput();
-        }
+        if (0 < mBroadcastQueueLength) { mAudioInterface->enableBroadcastOutput(); }
 
-        if (gVerboseFlag) std::cout << "  JackTrip:setupAudio before mAudioInterface->setup" << std::endl;
+        if (gVerboseFlag)
+            std::cout << "  JackTrip:setupAudio before mAudioInterface->setup"
+                      << std::endl;
         mAudioInterface->setup();
-        if (gVerboseFlag) std::cout << "  JackTrip:setupAudio before mAudioInterface->getSampleRate" << std::endl;
+        if (gVerboseFlag)
+            std::cout << "  JackTrip:setupAudio before mAudioInterface->getSampleRate"
+                      << std::endl;
         mSampleRate = mAudioInterface->getSampleRate();
-        if (gVerboseFlag) std::cout << "  JackTrip:setupAudio before mAudioInterface->getDeviceID" << std::endl;
+        if (gVerboseFlag)
+            std::cout << "  JackTrip:setupAudio before mAudioInterface->getDeviceID"
+                      << std::endl;
         mDeviceID = mAudioInterface->getDeviceID();
-        if (gVerboseFlag) std::cout << "  JackTrip:setupAudio before mAudioInterface->getBufferSizeInSamples" << std::endl;
+        if (gVerboseFlag)
+            std::cout
+                << "  JackTrip:setupAudio before mAudioInterface->getBufferSizeInSamples"
+                << std::endl;
         mAudioBufferSize = mAudioInterface->getBufferSizeInSamples();
-#endif //__NON_JACK__
-#ifdef __NO_JACK__ /// \todo FIX THIS REPETITION OF CODE
+#endif              //__NON_JACK__
+#ifdef __NO_JACK__  /// \todo FIX THIS REPETITION OF CODE
 #ifdef __RT_AUDIO__
         cout << "Warning: using non jack version, RtAudio will be used instead" << endl;
-        mAudioInterface = new RtAudioInterface(this, mNumChans, mNumChans, mAudioBitResolution);
+        mAudioInterface = new RtAudioInterface(this, mNumAudioChansIn, mNumAudioChansOut,
+                                               mAudioBitResolution);
         mAudioInterface->setSampleRate(mSampleRate);
         mAudioInterface->setDeviceID(mDeviceID);
+        mAudioInterface->setInputDevice(mInputDeviceName);
+        mAudioInterface->setOutputDevice(mOutputDeviceName);
         mAudioInterface->setBufferSizeInSamples(mAudioBufferSize);
         mAudioInterface->setup();
+        // Setup might have reduced number of channels
+        mNumAudioChansIn  = mAudioInterface->getNumInputChannels();
+        mNumAudioChansOut = mAudioInterface->getNumOutputChannels();
+        // Setup might have changed buffer size
+        mAudioBufferSize = mAudioInterface->getBufferSizeInSamples();
 #endif
 #endif
-    }
-    else if ( mAudiointerfaceMode == JackTrip::RTAUDIO ) {
+    } else if (mAudiointerfaceMode == JackTrip::RTAUDIO) {
 #ifdef __RT_AUDIO__
-        mAudioInterface = new RtAudioInterface(this, mNumChans, mNumChans, mAudioBitResolution);
+        mAudioInterface = new RtAudioInterface(this, mNumAudioChansIn, mNumAudioChansOut,
+                                               mAudioBitResolution);
         mAudioInterface->setSampleRate(mSampleRate);
         mAudioInterface->setDeviceID(mDeviceID);
+        mAudioInterface->setInputDevice(mInputDeviceName);
+        mAudioInterface->setOutputDevice(mOutputDeviceName);
         mAudioInterface->setBufferSizeInSamples(mAudioBufferSize);
         mAudioInterface->setup();
+        // Setup might have reduced number of channels
+        mNumAudioChansIn  = mAudioInterface->getNumInputChannels();
+        mNumAudioChansOut = mAudioInterface->getNumOutputChannels();
+        // Setup might have changed buffer size
+        mAudioBufferSize = mAudioInterface->getBufferSizeInSamples();
 #endif
     }
 
     mAudioInterface->setLoopBack(mLoopBack);
-    if (mAudioTesterP) { // if we're a hub server, this will be a nullptr - MAJOR REFACTOR NEEDED, in my opinion
-      mAudioTesterP->setSampleRate(mSampleRate);
+    if (!mAudioTesterP
+             .isNull()) {  // if we're a hub server, this will be a nullptr - MAJOR
+                           // REFACTOR NEEDED, in my opinion
+        mAudioTesterP->setSampleRate(mSampleRate);
     }
-    mAudioInterface->setAudioTesterP(mAudioTesterP);
+    mAudioInterface->setAudioTesterP(mAudioTesterP.data());
 
     std::cout << "The Sampling Rate is: " << mSampleRate << std::endl;
     std::cout << gPrintSeparator << std::endl;
-    int AudioBufferSizeInBytes = mAudioBufferSize*sizeof(sample_t);
-    std::cout << "The Audio Buffer Size is: " << mAudioBufferSize << " samples" << std::endl;
-    std::cout << "                      or: " << AudioBufferSizeInBytes
-              << " bytes" << std::endl;
+    int AudioBufferSizeInBytes = mAudioBufferSize * sizeof(sample_t);
+    std::cout << "The Audio Buffer Size is: " << mAudioBufferSize << " samples"
+              << std::endl;
+    std::cout << "                      or: " << AudioBufferSizeInBytes << " bytes"
+              << std::endl;
     if (0 < mBroadcastQueueLength) {
         std::cout << gPrintSeparator << std::endl;
         cout << "Broadcast Output is enabled, delay = "
@@ -241,42 +278,44 @@ void JackTrip::setupAudio(
              << " (" << mBroadcastQueueLength * mAudioBufferSize << " samples)" << endl;
     }
     std::cout << gPrintSeparator << std::endl;
-    cout << "The Number of Channels is: " << mAudioInterface->getNumInputChannels() << endl;
+    cout << "The Number of Channels is: " << mAudioInterface->getNumInputChannels()
+         << endl;
     std::cout << gPrintSeparator << std::endl;
     QThread::usleep(100);
 }
 
-
 //*******************************************************************************
 void JackTrip::closeAudio()
 {
-    //mAudioInterface->close();
-    if ( mAudioInterface != NULL ) {
+    // mAudioInterface->close();
+    if (mAudioInterface != NULL) {
         mAudioInterface->stopProcess();
         delete mAudioInterface;
         mAudioInterface = NULL;
     }
 }
 
-
 //*******************************************************************************
 void JackTrip::setupDataProtocol()
 {
-    double simulated_max_delay = mSimulatedDelayRel * getBufferSizeInSamples() / getSampleRate();
+    double simulated_max_delay =
+        mSimulatedDelayRel * getBufferSizeInSamples() / getSampleRate();
     // Create DataProtocol Objects
     switch (mDataProtocol) {
     case UDP:
         std::cout << "Using UDP Protocol" << std::endl;
         QThread::usleep(100);
-        mDataProtocolSender = new UdpDataProtocol(this, DataProtocol::SENDER,
-                                                  //mSenderPeerPort, mSenderBindPort,
-                                                  mSenderBindPort, mSenderPeerPort,
-                                                  mRedundancy);
-        mDataProtocolReceiver =  new UdpDataProtocol(this, DataProtocol::RECEIVER,
-                                                     mReceiverBindPort, mReceiverPeerPort,
-                                                     mRedundancy);
-        if (0.0 < mSimulatedLossRate || 0.0 < mSimulatedJitterRate || 0.0 < simulated_max_delay) {
-            mDataProtocolReceiver->setIssueSimulation(mSimulatedLossRate, mSimulatedJitterRate, simulated_max_delay);
+        mDataProtocolSender =
+            new UdpDataProtocol(this, DataProtocol::SENDER,
+                                // mSenderPeerPort, mSenderBindPort,
+                                mSenderBindPort, mSenderPeerPort, mRedundancy);
+        mDataProtocolReceiver =
+            new UdpDataProtocol(this, DataProtocol::RECEIVER, mReceiverBindPort,
+                                mReceiverPeerPort, mRedundancy);
+        if (0.0 < mSimulatedLossRate || 0.0 < mSimulatedJitterRate
+            || 0.0 < simulated_max_delay) {
+            mDataProtocolReceiver->setIssueSimulation(
+                mSimulatedLossRate, mSimulatedJitterRate, simulated_max_delay);
         }
         mDataProtocolSender->setUseRtPriority(mUseRtUdpPriority);
         mDataProtocolReceiver->setUseRtPriority(mUseRtUdpPriority);
@@ -296,65 +335,64 @@ void JackTrip::setupDataProtocol()
         break;
     }
 
-    // Set Audio Packet Size
-    //mDataProtocolSender->setAudioPacketSize
-    //  (mAudioInterface->getSizeInBytesPerChannel() * mNumChans);
-    //mDataProtocolReceiver->setAudioPacketSize
-    //  (mAudioInterface->getSizeInBytesPerChannel() * mNumChans);
-    mDataProtocolSender->setAudioPacketSize(getTotalAudioPacketSizeInBytes());
-    mDataProtocolReceiver->setAudioPacketSize(getTotalAudioPacketSizeInBytes());
-}
+    // JackTrip's inputs send to the network
+    mDataProtocolSender->setAudioPacketSize(getTotalAudioInputPacketSizeInBytes());
 
+    // JackTrip's outputs receive from the network
+    mDataProtocolReceiver->setAudioPacketSize(getTotalAudioOutputPacketSizeInBytes());
+}
 
 //*******************************************************************************
 void JackTrip::setupRingBuffers()
 {
     // Create RingBuffers with the apprioprate size
     /// \todo Make all this operations cleaner
-    //int total_audio_packet_size = getTotalAudioPacketSizeInBytes();
-    int slot_size = getRingBuffersSlotSize();
-    if (0 <=  mBufferStrategy) {
+    // int total_audio_packet_size = getTotalAudioPacketSizeInBytes();
+    int audio_input_slot_size  = getInputRingBuffersSlotSize();
+    int audio_output_slot_size = getOutputRingBuffersSlotSize();
+    if (0 <= mBufferStrategy) {
         mUnderRunMode = ZEROS;
-    }
-    else if (0 > mBufferQueueLength) {
-      throw std::invalid_argument("Auto queue is not supported by RingBuffer");
+    } else if (0 > mBufferQueueLength) {
+        throw std::invalid_argument("Auto queue is not supported by RingBuffer");
     }
 
     switch (mUnderRunMode) {
     case WAVETABLE:
-        mSendRingBuffer = new RingBufferWavetable(slot_size,
-                                                  gDefaultOutputQueueLength);
-        mReceiveRingBuffer = new RingBufferWavetable(slot_size,
-                                                     mBufferQueueLength);
-        /*
-    mSendRingBuffer = new RingBufferWavetable(mAudioInterface->getSizeInBytesPerChannel() * mNumChans,
-                gDefaultOutputQueueLength);
-    mReceiveRingBuffer = new RingBufferWavetable(mAudioInterface->getSizeInBytesPerChannel() * mNumChans,
-             mBufferQueueLength);
-             */
+        mSendRingBuffer =
+            new RingBufferWavetable(audio_input_slot_size, gDefaultOutputQueueLength);
+        mReceiveRingBuffer =
+            new RingBufferWavetable(audio_output_slot_size, mBufferQueueLength);
+        mPacketHeader->setBufferRequiresSameSettings(true);
         break;
     case ZEROS:
-        mSendRingBuffer = new RingBuffer(slot_size,
-                                         gDefaultOutputQueueLength);
+        mSendRingBuffer =
+            new RingBuffer(audio_input_slot_size, gDefaultOutputQueueLength);
         if (0 > mBufferStrategy) {
-            mReceiveRingBuffer = new RingBuffer(slot_size,
-                                                mBufferQueueLength);
-        }
-        else {
+            mReceiveRingBuffer =
+                new RingBuffer(audio_output_slot_size, mBufferQueueLength);
+            mPacketHeader->setBufferRequiresSameSettings(true);
+        } else if (mBufferStrategy == 3) {
+            qDebug() << "experimental buffer strategy 3 -- pool buffer with PLC";
+            mSendRingBuffer =
+                new RingBuffer(audio_input_slot_size, gDefaultOutputQueueLength);
+            mReceiveRingBuffer =
+                new PoolBuffer(mSampleRate, mNumAudioChansIn, mAudioBitResolution,
+                               mAudioBufferSize, mBufferQueueLength);
+            //            connect(mReceiveRingBuffer, SIGNAL(print(QString)), this,
+            //            SLOT(onStatTimer(QString))); connect(mReceiveRingBuffer,
+            //            SIGNAL(printStats(QString)), this, SLOT(onStatTimer(QString)));
+
+            mPacketHeader->setBufferRequiresSameSettings(true);
+        } else {
             cout << "Using JitterBuffer strategy " << mBufferStrategy << endl;
             if (0 > mBufferQueueLength) {
                 cout << "Using AutoQueue 1/" << -mBufferQueueLength << endl;
             }
-            mReceiveRingBuffer = new JitterBuffer(mAudioBufferSize, mBufferQueueLength,
-                                        mSampleRate, mBufferStrategy,
-                                        mBroadcastQueueLength, mNumChans, mAudioBitResolution);
+            mReceiveRingBuffer = new JitterBuffer(
+                mAudioBufferSize, mBufferQueueLength, mSampleRate, mBufferStrategy,
+                mBroadcastQueueLength, mNumAudioChansOut, mAudioBitResolution);
+            static_cast<JitterBuffer*>(mReceiveRingBuffer)->setJackTrip(this);
         }
-        /*
-    mSendRingBuffer = new RingBuffer(mAudioInterface->getSizeInBytesPerChannel() * mNumChans,
-             gDefaultOutputQueueLength);
-    mReceiveRingBuffer = new RingBuffer(mAudioInterface->getSizeInBytesPerChannel() * mNumChans,
-          mBufferQueueLength);
-          */
         break;
     default:
         throw std::invalid_argument("Underrun Mode undefined");
@@ -362,41 +400,35 @@ void JackTrip::setupRingBuffers()
     }
 }
 
-
 //*******************************************************************************
-void JackTrip::setPeerAddress(QString PeerHostOrIP)
-{
-    mPeerAddress = PeerHostOrIP;
-}
-
+void JackTrip::setPeerAddress(QString PeerHostOrIP) { mPeerAddress = PeerHostOrIP; }
 
 //*******************************************************************************
 void JackTrip::appendProcessPluginToNetwork(ProcessPlugin* plugin)
 {
-  if (plugin) {
-    mProcessPluginsToNetwork.append(plugin); // ownership transferred
-    //mAudioInterface->appendProcessPluginToNetwork(plugin);
-  }
+    if (plugin) {
+        mProcessPluginsToNetwork.append(plugin);  // ownership transferred
+        // mAudioInterface->appendProcessPluginToNetwork(plugin);
+    }
 }
 
 //*******************************************************************************
 void JackTrip::appendProcessPluginFromNetwork(ProcessPlugin* plugin)
 {
-  if (plugin) {
-    mProcessPluginsFromNetwork.append(plugin); // ownership transferred
-    //mAudioInterface->appendProcessPluginFromNetwork(plugin);
-  }
+    if (plugin) {
+        mProcessPluginsFromNetwork.append(plugin);  // ownership transferred
+        // mAudioInterface->appendProcessPluginFromNetwork(plugin);
+    }
 }
 
-
 //*******************************************************************************
 void JackTrip::startProcess(
-        #ifdef WAIRTOHUB // WAIR
-        int ID
-        #endif // endwhere
-        )
-{ //signal that catches ctrl c in rtaudio-asio mode
-/*#if defined (__WIN_32__)
+#ifdef WAIRTOHUB  // WAIR
+    int ID
+#endif  // endwhere
+)
+{  // signal that catches ctrl c in rtaudio-asio mode
+    /*#if defined (__WIN_32__)
     if (signal(SIGINT, sigint_handler) == SIG_ERR) {
         perror("signal");
         exit(1);
@@ -406,73 +438,92 @@ void JackTrip::startProcess(
     // ------------------------------------------------------------------
     if (gVerboseFlag) std::cout << "step 1" << std::endl;
 
-    if (gVerboseFlag) std::cout << "  JackTrip:startProcess before checkIfPortIsBinded(mReceiverBindPort)" << std::endl;
+    if (gVerboseFlag)
+        std::cout
+            << "  JackTrip:startProcess before checkIfPortIsBinded(mReceiverBindPort)"
+            << std::endl;
 #if defined __WIN_32__
-    //cc fixed windows crash with this print statement!
-    //qDebug() << "before mJackTrip->startProcess" << mReceiverBindPort<< mSenderBindPort;
+        // cc fixed windows crash with this print statement!
+        // qDebug() << "before mJackTrip->startProcess" << mReceiverBindPort<<
+        // mSenderBindPort;
 #endif
     checkIfPortIsBinded(mReceiverBindPort);
-    if (gVerboseFlag) std::cout << "  JackTrip:startProcess before checkIfPortIsBinded(mSenderBindPort)" << std::endl;
+    if (gVerboseFlag)
+        std::cout << "  JackTrip:startProcess before checkIfPortIsBinded(mSenderBindPort)"
+                  << std::endl;
     checkIfPortIsBinded(mSenderBindPort);
     // Set all classes and parameters
     // ------------------------------
-    if (gVerboseFlag) std::cout << "  JackTrip:startProcess before setupAudio" << std::endl;
+    if (gVerboseFlag)
+        std::cout << "  JackTrip:startProcess before setupAudio" << std::endl;
     setupAudio(
-            #ifdef WAIRTOHUB // wair
-                ID
-            #endif // endwhere
-                );
-    //cc redundant with instance creator  createHeader(mPacketHeaderType); next line fixme
+#ifdef WAIRTOHUB  // wair
+        ID
+#endif  // endwhere
+    );
+    // cc redundant with instance creator  createHeader(mPacketHeaderType); next line
+    // fixme
     createHeader(mPacketHeaderType);
     setupDataProtocol();
     setupRingBuffers();
     // Connect Signals and Slots
     // -------------------------
-    QObject::connect(mPacketHeader, &PacketHeader::signalError,
-                     this, &JackTrip::slotStopProcessesDueToError, Qt::QueuedConnection);
+    QObject::connect(mPacketHeader, &PacketHeader::signalError, this,
+                     &JackTrip::slotStopProcessesDueToError, Qt::QueuedConnection);
     QObject::connect(mDataProtocolReceiver, SIGNAL(signalReceivedConnectionFromPeer()),
-                     this, SLOT(slotReceivedConnectionFromPeer()),
-                     Qt::QueuedConnection);
-    //QObject::connect(this, SIGNAL(signalUdpTimeOut()),
+                     this, SLOT(slotReceivedConnectionFromPeer()), Qt::QueuedConnection);
+    // QObject::connect(this, SIGNAL(signalUdpTimeOut()),
     //                 this, SLOT(slotStopProcesses()), Qt::QueuedConnection);
-    QObject::connect((UdpDataProtocol *)mDataProtocolReceiver, &UdpDataProtocol::signalUdpWaitingTooLong, this,
+    QObject::connect(static_cast<UdpDataProtocol*>(mDataProtocolReceiver),
+                     &UdpDataProtocol::signalUdpWaitingTooLong, this,
                      &JackTrip::slotUdpWaitingTooLong, Qt::QueuedConnection);
-    QObject::connect(mDataProtocolSender, &DataProtocol::signalCeaseTransmission,
-                     this, &JackTrip::slotStopProcessesDueToError, Qt::QueuedConnection);
-    QObject::connect(mDataProtocolReceiver, &DataProtocol::signalCeaseTransmission,
-                     this, &JackTrip::slotStopProcessesDueToError, Qt::QueuedConnection);
+    QObject::connect(mDataProtocolSender, &DataProtocol::signalCeaseTransmission, this,
+                     &JackTrip::slotStopProcessesDueToError, Qt::QueuedConnection);
+    QObject::connect(mDataProtocolReceiver, &DataProtocol::signalCeaseTransmission, this,
+                     &JackTrip::slotStopProcessesDueToError, Qt::QueuedConnection);
 
-    //QObject::connect(mDataProtocolSender, SIGNAL(signalError(const char*)),
+    // QObject::connect(mDataProtocolSender, SIGNAL(signalError(const char*)),
     //                 this, SLOT(slotStopProcesses()), Qt::QueuedConnection);
-    QObject::connect(mDataProtocolReceiver, SIGNAL(signalError(const char*)),
-                     this, SLOT(slotStopProcesses()), Qt::QueuedConnection);
+    QObject::connect(mDataProtocolReceiver, &DataProtocol::signalError, this,
+                     &JackTrip::slotStopProcessesDueToError, Qt::QueuedConnection);
 
     // Start the threads for the specific mode
     // ---------------------------------------
-    switch ( mJackTripMode )
-    {
-    case CLIENT :
+    switch (mJackTripMode) {
+    case CLIENT:
         if (gVerboseFlag) std::cout << "step 2c client only" << std::endl;
-        if (gVerboseFlag) std::cout << "  JackTrip:startProcess case CLIENT before clientStart" << std::endl;
+        if (gVerboseFlag)
+            std::cout << "  JackTrip:startProcess case CLIENT before clientStart"
+                      << std::endl;
         clientStart();
         break;
-    case SERVER :
+    case SERVER:
         if (gVerboseFlag) std::cout << "step 2s server only" << std::endl;
-        if (gVerboseFlag) std::cout << "  JackTrip:startProcess case SERVER before serverStart" << std::endl;
+        if (gVerboseFlag)
+            std::cout << "  JackTrip:startProcess case SERVER before serverStart"
+                      << std::endl;
         serverStart();
         break;
-    case CLIENTTOPINGSERVER :
+    case CLIENTTOPINGSERVER:
         if (gVerboseFlag) std::cout << "step 2C client only" << std::endl;
-        if (gVerboseFlag) std::cout << "  JackTrip:startProcess case CLIENTTOPINGSERVER before clientPingToServerStart" << std::endl;
-        if ( clientPingToServerStart() == -1 ) { // if error on server start (-1) we return inmediatly
+        if (gVerboseFlag)
+            std::cout << "  JackTrip:startProcess case CLIENTTOPINGSERVER before "
+                         "clientPingToServerStart"
+                      << std::endl;
+        if (clientPingToServerStart()
+            == -1) {  // if error on server start (-1) we return inmediatly
             stop("Peer Address has to be set if you run in CLIENTTOPINGSERVER mode");
             return;
         }
         break;
-    case SERVERPINGSERVER :
+    case SERVERPINGSERVER:
         if (gVerboseFlag) std::cout << "step 2S server only (same as 2s)" << std::endl;
-        if (gVerboseFlag) std::cout << "  JackTrip:startProcess case SERVERPINGSERVER before serverStart" << std::endl;
-        if ( serverStart(true) == -1 ) { // if error on server start (-1) we return inmediatly
+        if (gVerboseFlag)
+            std::cout
+                << "  JackTrip:startProcess case SERVERPINGSERVER before serverStart"
+                << std::endl;
+        if (serverStart(true)
+            == -1) {  // if error on server start (-1) we return inmediatly
             stop();
             return;
         }
@@ -486,7 +537,7 @@ void JackTrip::startProcess(
 void JackTrip::completeConnection()
 {
     // Have the threads share a single socket that operates at full duplex.
-#if defined (__WIN_32__)
+#if defined(__WIN_32__)
     SOCKET sock_fd = INVALID_SOCKET;
 #else
     int sock_fd = -1;
@@ -495,41 +546,48 @@ void JackTrip::completeConnection()
     mDataProtocolSender->setSocket(sock_fd);
 
     // Start Threads
-    if (gVerboseFlag) std::cout << "  JackTrip:startProcess before mDataProtocolReceiver->start" << std::endl;
+    if (gVerboseFlag)
+        std::cout << "  JackTrip:startProcess before mDataProtocolReceiver->start"
+                  << std::endl;
     mDataProtocolReceiver->start();
     QThread::msleep(1);
-    if (gVerboseFlag) std::cout << "  JackTrip:startProcess before mDataProtocolSender->start" << std::endl;
+    if (gVerboseFlag)
+        std::cout << "  JackTrip:startProcess before mDataProtocolSender->start"
+                  << std::endl;
     mDataProtocolSender->start();
     /*
      * changed order so that audio starts after receiver and sender
      * because UdpDataProtocol:run0 before setRealtimeProcessPriority()
-     * causes an audio hiccup from jack JackPosixSemaphore::TimedWait err = Interrupted system call
-     * new QThread::msleep(1);
-     * to allow sender to start
+     * causes an audio hiccup from jack JackPosixSemaphore::TimedWait err = Interrupted
+     * system call new QThread::msleep(1); to allow sender to start
      */
     QThread::msleep(1);
     if (gVerboseFlag) std::cout << "step 5" << std::endl;
-    if (gVerboseFlag) std::cout << "  JackTrip:startProcess before mAudioInterface->startProcess" << std::endl;
-    for (int i = 0; i < mProcessPluginsFromNetwork.size(); ++i) {
-        mAudioInterface->appendProcessPluginFromNetwork(mProcessPluginsFromNetwork[i]);
+    if (gVerboseFlag)
+        std::cout << "  JackTrip:startProcess before mAudioInterface->startProcess"
+                  << std::endl;
+    for (auto& i : mProcessPluginsFromNetwork) {
+        mAudioInterface->appendProcessPluginFromNetwork(i);
     }
-    for (int i = 0; i < mProcessPluginsToNetwork.size(); ++i) {
-        mAudioInterface->appendProcessPluginToNetwork(mProcessPluginsToNetwork[i]);
+    for (auto& i : mProcessPluginsToNetwork) {
+        mAudioInterface->appendProcessPluginToNetwork(i);
     }
-    mAudioInterface->initPlugins();  // mSampleRate known now, which plugins require
-    mAudioInterface->startProcess(); // Tell JACK server we are ready for audio flow now
+    mAudioInterface->initPlugins();   // mSampleRate known now, which plugins require
+    mAudioInterface->startProcess();  // Tell JACK server we are ready for audio flow now
+
+    if (mConnectDefaultAudioPorts) { mAudioInterface->connectDefaultPorts(); }
+    emit signalAudioStarted();
 
-    if (mConnectDefaultAudioPorts) {  mAudioInterface->connectDefaultPorts(); }
-    
-    //Start our IO stat timer
+    // Start our IO stat timer
     if (mIOStatTimeout > 0) {
         cout << "STATS" << mIOStatTimeout << endl;
         if (!mIOStatStream.isNull()) {
-            mIOStatLogStream.rdbuf(((std::ostream *)mIOStatStream.data())->rdbuf());
+            mIOStatLogStream.rdbuf(
+                (reinterpret_cast<std::ostream*>(mIOStatStream.data()))->rdbuf());
         }
-        QTimer *timer = new QTimer(this);
+        QTimertimer = new QTimer(this);
         connect(timer, SIGNAL(timeout()), this, SLOT(onStatTimer()));
-        timer->start(mIOStatTimeout*1000);
+        timer->start(mIOStatTimeout * 1000);
     }
 }
 
@@ -537,81 +595,79 @@ void JackTrip::completeConnection()
 void JackTrip::onStatTimer()
 {
     DataProtocol::PktStat pkt_stat;
-    if (!mDataProtocolReceiver->getStats(&pkt_stat)) {
-        return;
-    }
+    if (!mDataProtocolReceiver->getStats(&pkt_stat)) { return; }
     bool reset = (0 == pkt_stat.statCount);
     RingBuffer::IOStat recv_io_stat;
-    if (!mReceiveRingBuffer->getStats(&recv_io_stat, reset)) {
-        return;
-    }
+    if (!mReceiveRingBuffer->getStats(&recv_io_stat, reset)) { return; }
     RingBuffer::IOStat send_io_stat;
-    if (!mSendRingBuffer->getStats(&send_io_stat, reset)) {
-        return;
-    }
+    if (!mSendRingBuffer->getStats(&send_io_stat, reset)) { return; }
     QString now = QDateTime::currentDateTime().toString(Qt::ISODate);
 
     static QMutex mutex;
     QMutexLocker locker(&mutex);
-    if (mAudioTesterP && mAudioTesterP->getEnabled()) {
-      mIOStatLogStream << "\n";
+    if (!mAudioTesterP.isNull() && mAudioTesterP->getEnabled()) {
+        mIOStatLogStream << "\n";
     }
-    mIOStatLogStream << now.toLocal8Bit().constData()
-      << " " << getPeerAddress().toLocal8Bit().constData()
-      << " send: "
-      << send_io_stat.underruns
-      << "/" << send_io_stat.overflows
-      << " recv: "
-      << recv_io_stat.underruns
-      << "/" << recv_io_stat.overflows
-      << " prot: "
-      << pkt_stat.lost
-      << "/" << pkt_stat.outOfOrder
-      << "/" << pkt_stat.revived
-      << " tot: "
-      << pkt_stat.tot
-      << " sync: "
-      << recv_io_stat.level
-      << "/" << recv_io_stat.buf_inc_underrun
-      << "/" << recv_io_stat.buf_inc_compensate
-      << "/" << recv_io_stat.buf_dec_overflows
-      << "/" << recv_io_stat.buf_dec_pktloss
-      << " skew: " << recv_io_stat.skew
-      << "/" << recv_io_stat.skew_raw
-      << " bcast: " << recv_io_stat.broadcast_skew
-      << "/" << recv_io_stat.broadcast_delta
-      << " autoq: " << 0.1*recv_io_stat.autoq_corr
-      << "/" << 0.1*recv_io_stat.autoq_rate
-      << endl;
+    mIOStatLogStream << now.toLocal8Bit().constData() << " "
+                     << getPeerAddress().toLocal8Bit().constData()
+                     << " send: " << send_io_stat.underruns << "/"
+                     << send_io_stat.overflows << " recv: " << recv_io_stat.underruns
+                     << "/" << recv_io_stat.overflows << " prot: " << pkt_stat.lost << "/"
+                     << pkt_stat.outOfOrder << "/" << pkt_stat.revived
+                     << " tot: " << pkt_stat.tot << " sync: " << recv_io_stat.level << "/"
+                     << recv_io_stat.buf_inc_underrun << "/"
+                     << recv_io_stat.buf_inc_compensate << "/"
+                     << recv_io_stat.buf_dec_overflows << "/"
+                     << recv_io_stat.buf_dec_pktloss << " skew: " << recv_io_stat.skew
+                     << "/" << recv_io_stat.skew_raw
+                     << " bcast: " << recv_io_stat.broadcast_skew << "/"
+                     << recv_io_stat.broadcast_delta
+                     << " autoq: " << 0.1 * recv_io_stat.autoq_corr << "/"
+                     << 0.1 * recv_io_stat.autoq_rate << endl;
 }
 
 void JackTrip::receivedConnectionTCP()
 {
-    mTimeoutTimer.stop();
+    {
+        QMutexLocker lock(&mTimerMutex);
+        if (!mAwaitingTcp) { return; }
+        mAwaitingTcp = false;
+        mTimeoutTimer.stop();
+    }
     if (gVerboseFlag) cout << "TCP Socket Connected to Server!" << endl;
     emit signalTcpClientConnected();
 
+    // If we're planning to authenticate, signal the server.
+    if (mUseAuth) {
+        char port_buf[sizeof(qint32)];
+        qToLittleEndian<qint32>(Auth::OK, port_buf);
+        mTcpClient.write(port_buf, sizeof(port_buf));
+        if (gVerboseFlag) cout << "Auth request sent to Server" << endl;
+        return;
+    }
     // Send Client Port Number to Server
     // ---------------------------------
-    char port_buf[sizeof(mReceiverBindPort) + gMaxRemoteNameLength];
-    std::memcpy(port_buf, &mReceiverBindPort, sizeof(mReceiverBindPort));
-    std::memset(port_buf + sizeof(mReceiverBindPort), 0, gMaxRemoteNameLength);
+    char port_buf[sizeof(qint32) + gMaxRemoteNameLength];
+    qToLittleEndian<qint32>(mReceiverBindPort, port_buf);
+    // std::memcpy(port_buf, &mReceiverBindPort, sizeof(mReceiverBindPort));
+
+    std::memset(port_buf + sizeof(qint32), 0, gMaxRemoteNameLength);
     if (!mRemoteClientName.isEmpty()) {
-        //If our remote client name is set, send it too.
+        // If our remote client name is set, send it too.
         QByteArray name = mRemoteClientName.toUtf8();
         // Find a clean place to truncate if we're over length.
         // (Make sure we're not in the middle of a multi-byte characetr.)
         int length = name.length();
-        //Need to take the final null terminator into account here.
+        // Need to take the final null terminator into account here.
         if (length > gMaxRemoteNameLength - 1) {
             length = gMaxRemoteNameLength - 1;
             while ((length > 0) && ((name.at(length) & 0xc0) == 0x80)) {
-                //We're in the middle of a multi-byte character. Work back.
+                // We're in the middle of a multi-byte character. Work back.
                 length--;
             }
         }
         name.truncate(length);
-        std::memcpy(port_buf + sizeof(mReceiverBindPort), name.data(), length + 1);
+        std::memcpy(port_buf + sizeof(qint32), name.data(), length + 1);
     }
 
     mTcpClient.write(port_buf, sizeof(port_buf));
@@ -619,15 +675,56 @@ void JackTrip::receivedConnectionTCP()
         mTcpClient.waitForBytesWritten(-1);
     }*/
     if (gVerboseFlag) cout << "Port " << mReceiverBindPort << " sent to Server" << endl;
-    //Continued in receivedDataTCP slot
+    // Continued in receivedDataTCP slot
 }
 
 void JackTrip::receivedDataTCP()
 {
-    if (mTcpClient.bytesAvailable() < (int)sizeof(uint16_t)) {
+    if (mUseAuth && !mTcpClient.isEncrypted()) {
+        // If we're using authentication and haven't established a secure connection yet
+        // check that our server supports it.
+        qint32 authResponse;
+        int size       = sizeof(authResponse);
+        char* auth_buf = new char[size];
+        mTcpClient.read(auth_buf, size);
+        authResponse = qFromLittleEndian<qint32>(auth_buf);
+        delete[] auth_buf;
+        if (authResponse == Auth::OK) {
+            mTcpClient.startClientEncryption();
+        } else {
+            if (authResponse == Auth::NOTREQUIRED) {
+                std::cout << "ERROR: The Server does not require authentication."
+                          << std::endl;
+                stop("The server does not require authentication");
+            } else {
+                std::cout << "ERROR: The Server does not support authentication."
+                          << std::endl;
+                stop("The server does not support authentication");
+                // Send a header sized packet to the server so we don't lock up the
+                // main/UdpHubListener thread on the server. (Prevents a denial of
+                // service.) TODO: This should ultimately be fixed server side, but work
+                // around it here so we don't interfere with older deployments.
+                if (mUdpSockTemp.bind(QHostAddress::Any, mReceiverBindPort,
+                                      QUdpSocket::DefaultForPlatform)) {
+                    QThread::msleep(100);
+                    DefaultHeader temp(nullptr);
+                    size           = temp.getHeaderSizeInBytes();
+                    int8_t* header = new int8_t[size];
+                    // The header doesn't need to make sense, it just has to be non-zero
+                    // so we don't cause any divide by zero errors on the other end.
+                    memset(header, 1, size);
+                    mUdpSockTemp.writeDatagram((const char*)header, size,
+                                               mTcpClient.peerAddress(), authResponse);
+                    mUdpSockTemp.close();
+                }
+            }
+            mTcpClient.close();
+        }
         return;
     }
-    
+
+    if (mTcpClient.bytesAvailable() < (int)sizeof(qint32)) { return; }
+
     // Read the size of the package
     // ----------------------------
     if (gVerboseFlag) cout << "Reading UDP port from Server..." << endl;
@@ -636,47 +733,129 @@ void JackTrip::receivedDataTCP()
     // Read UDP Port Number from Server
     // --------------------------------
     uint32_t udp_port;
-    int size = sizeof(udp_port);
-    char port_buf[sizeof(mReceiverBindPort)];
-    //char port_buf[size];
+    int size       = sizeof(udp_port);
+    char* port_buf = new char[size];
     mTcpClient.read(port_buf, size);
-    std::memcpy(&udp_port, port_buf, size);
-    //cout << "Received UDP Port Number: " << udp_port << endl;
+    udp_port = qFromLittleEndian<qint32>(port_buf);
+    delete[] port_buf;
+    // std::memcpy(&udp_port, port_buf, size);
+    // cout << "Received UDP Port Number: " << udp_port << endl;
 
     // Close the TCP Socket
     // --------------------
-    mTcpClient.close(); // Close the socket
-    //cout << "TCP Socket Closed!" << endl;
+    mTcpClient.close();  // Close the socket
+    // cout << "TCP Socket Closed!" << endl;
+
+    // If we sent authentication data, check if our authentication attempt was succesfull
+    if (mUseAuth && udp_port > 65535) {
+        QString error_message;
+        if (udp_port == Auth::WRONGCREDS) {
+            error_message = "Incorrect username or password.";
+        } else if (udp_port == Auth::WRONGTIME) {
+            error_message = "You are not authorized to access the server at this time.";
+        } else {
+            error_message = "Unknown authentication error.";
+        }
+        std::cout << "ERROR: " << error_message.toStdString() << std::endl;
+        stop(error_message);
+        return;
+    } else if (udp_port > 65535) {
+        QString error_message;
+        if (udp_port == Auth::REQUIRED) {
+            error_message =
+                "The server you are attempting to connect to requires authentication.";
+        } else {
+            error_message = "Unknown authentication error.";
+        }
+        std::cout << "ERROR: " << error_message.toStdString() << std::endl;
+        stop(error_message);
+        return;
+    }
+
     if (gVerboseFlag) cout << "Connection Succesfull!" << endl;
 
     // Set with the received UDP port
     // ------------------------------
     setPeerPorts(udp_port);
-    mDataProtocolReceiver->setPeerAddress( mPeerAddress.toLatin1().data() );
-    mDataProtocolSender->setPeerAddress( mPeerAddress.toLatin1().data() );
+    mDataProtocolReceiver->setPeerAddress(mPeerAddress.toLatin1().data());
+    mDataProtocolSender->setPeerAddress(mPeerAddress.toLatin1().data());
     mDataProtocolSender->setPeerPort(udp_port);
     mDataProtocolReceiver->setPeerPort(udp_port);
-    cout << "Server Address set to: " << mPeerAddress.toStdString() << " Port: " << udp_port << std::endl;
+    cout << "Server Address set to: " << mPeerAddress.toStdString()
+         << " Port: " << udp_port << std::endl;
     cout << gPrintSeparator << endl;
     completeConnection();
 }
 
+void JackTrip::connectionSecured()
+{
+    // Now that the connection is encrypted, send out port, and credentials.
+    //(Remember to include an additional 2 bytes for the username and password
+    // terminators.)
+    QByteArray username = mUsername.toUtf8();
+    QByteArray password = mPassword.toUtf8();
+    int size            = (sizeof(qint32) * 3) + gMaxRemoteNameLength + username.length()
+               + password.length() + 2;
+    char* buf    = new char[size];
+    int location = sizeof(qint32);
+    std::memset(buf, 0, size);
+    qToLittleEndian<qint32>(mReceiverBindPort, buf);
+
+    if (!mRemoteClientName.isEmpty()) {
+        // If our remote client name is set, send it too.
+        QByteArray name = mRemoteClientName.toUtf8();
+        // Find a clean place to truncate if we're over length.
+        // (Make sure we're not in the middle of a multi-byte character.)
+        int length = name.length();
+        // Need to take the final null terminator into account here.
+        if (length > gMaxRemoteNameLength - 1) {
+            length = gMaxRemoteNameLength - 1;
+            while ((length > 0) && ((name.at(length) & 0xc0) == 0x80)) {
+                // We're in the middle of a multi-byte character. Work back.
+                length--;
+            }
+        }
+        name.truncate(length);
+        std::memcpy(buf + location, name.data(), length + 1);
+    }
+    location += gMaxRemoteNameLength;
+
+    qToLittleEndian<qint32>(username.length(), buf + location);
+    location += sizeof(qint32);
+    qToLittleEndian<qint32>(password.length(), buf + location);
+    location += sizeof(qint32);
+
+    std::memcpy(buf + location, username.data(), username.length() + 1);
+    location += username.length() + 1;
+    std::memcpy(buf + location, password.data(), password.length() + 1);
+
+    mTcpClient.write(buf, size);
+    if (gVerboseFlag)
+        cout << "Port " << mReceiverBindPort << " sent to Server with credentials"
+             << endl;
+}
+
 void JackTrip::receivedDataUDP()
 {
-    //Stop our timer.
-    mTimeoutTimer.stop();
-    
+    // Stop our timer.
+    {
+        QMutexLocker lock(&mTimerMutex);
+        if (!mAwaitingUdp) { return; }
+        mAwaitingUdp = false;
+        mTimeoutTimer.stop();
+    }
+
     QHostAddress peerHostAddress;
     uint16_t peer_port;
-    
+
     // IPv6 addition from fyfe
     // Get the datagram size to avoid problems with IPv6
     qint64 datagramSize = mUdpSockTemp.pendingDatagramSize();
-    char buf[datagramSize];
+    char* buf           = new char[datagramSize];
     // set client address
     mUdpSockTemp.readDatagram(buf, datagramSize, &peerHostAddress, &peer_port);
-    mUdpSockTemp.close(); // close the socket
-
+    mUdpSockTemp.close();  // close the socket
+    delete[] buf;
     // Check for mapped IPv4->IPv6 addresses that look like ::ffff:x.x.x.x
     if (peerHostAddress.protocol() == QAbstractSocket::IPv6Protocol) {
         bool mappedIPv4;
@@ -684,20 +863,23 @@ void JackTrip::receivedDataUDP()
         // If the IPv4 address is mapped to IPv6, convert it to IPv4
         if (mappedIPv4) {
             QHostAddress ipv4Address = QHostAddress(address);
-            mPeerAddress = ipv4Address.toString();
+            mPeerAddress             = ipv4Address.toString();
         } else {
             mPeerAddress = peerHostAddress.toString();
         }
-    }
-    else {
+    } else {
         mPeerAddress = peerHostAddress.toString();
     }
 
     // Set the peer address to send packets (in the protocol sender)
-    if (gVerboseFlag) std::cout << "JackTrip:serverStart before mDataProtocolSender->setPeerAddress()" << std::endl;
-    mDataProtocolSender->setPeerAddress( mPeerAddress.toLatin1().constData() );
-    if (gVerboseFlag) std::cout << "JackTrip:serverStart before mDataProtocolReceiver->setPeerAddress()" << std::endl;
-    mDataProtocolReceiver->setPeerAddress( mPeerAddress.toLatin1().constData() );
+    if (gVerboseFlag)
+        std::cout << "JackTrip:serverStart before mDataProtocolSender->setPeerAddress()"
+                  << std::endl;
+    mDataProtocolSender->setPeerAddress(mPeerAddress.toLatin1().constData());
+    if (gVerboseFlag)
+        std::cout << "JackTrip:serverStart before mDataProtocolReceiver->setPeerAddress()"
+                  << std::endl;
+    mDataProtocolReceiver->setPeerAddress(mPeerAddress.toLatin1().constData());
     //     We reply to the same port the peer sent the packets from
     //     This way we can go through NAT
     //     Because of the NAT traversal scheme, the portn need to be
@@ -705,7 +887,9 @@ void JackTrip::receivedDataUDP()
     //     from Client to Server : src = 4474, dest = 4464
     //     from Server to Client : src = 4464, dest = 4474
     // no -- all are the same -- 4464
-    if (gVerboseFlag) std::cout << "JackTrip:serverStart before setting all peer_port instances to " << peer_port << std::endl;
+    if (gVerboseFlag)
+        std::cout << "JackTrip:serverStart before setting all peer_port instances to "
+                  << peer_port << std::endl;
     mDataProtocolSender->setPeerPort(peer_port);
     mDataProtocolReceiver->setPeerPort(peer_port);
     setPeerPorts(peer_port);
@@ -714,16 +898,21 @@ void JackTrip::receivedDataUDP()
 
 void JackTrip::udpTimerTick()
 {
+    QMutexLocker lock(&mTimerMutex);
+    if (!mAwaitingUdp) { return; }
+
     if (mStopped || sSigInt || sJackStopped) {
-        //Stop everything.
+        // Stop everything.
+        mAwaitingUdp = false;
         mUdpSockTemp.close();
         mTimeoutTimer.stop();
         stop();
     }
-    
+
     if (gVerboseFlag) std::cout << mSleepTime << "ms  " << std::flush;
     mElapsedTime += mSleepTime;
     if (mEndTime > 0 && mElapsedTime >= mEndTime) {
+        mAwaitingUdp = false;
         mUdpSockTemp.close();
         mTimeoutTimer.stop();
         cout << "JackTrip Server Timed Out!" << endl;
@@ -733,34 +922,36 @@ void JackTrip::udpTimerTick()
 
 void JackTrip::tcpTimerTick()
 {
+    QMutexLocker lock(&mTimerMutex);
+    if (!mAwaitingTcp) { return; }
+
     if (mStopped || sSigInt || sJackStopped) {
-        //Stop everything.
+        // Stop everything.
+        mAwaitingTcp = false;
         mTcpClient.close();
         mTimeoutTimer.stop();
         stop();
     }
-    
+
     mElapsedTime += mSleepTime;
     if (mEndTime > 0 && mElapsedTime >= mEndTime) {
+        mAwaitingTcp = false;
         mTcpClient.close();
         mTimeoutTimer.stop();
         cout << "JackTrip Server Timed Out!" << endl;
         stop("Initial TCP Connection Timed Out");
     }
-    
 }
 
 //*******************************************************************************
 void JackTrip::stop(QString errorMessage)
 {
     mStopped = true;
-    //Make sure we're only run once
-    if (mHasShutdown) {
-        return;
-    }
+    // Make sure we're only run once
+    if (mHasShutdown) { return; }
     mHasShutdown = true;
     std::cout << "Stopping JackTrip..." << std::endl;
-    
+
     // Stop The Sender
     mDataProtocolSender->stop();
     mDataProtocolSender->wait();
@@ -770,9 +961,9 @@ void JackTrip::stop(QString errorMessage)
     mDataProtocolReceiver->wait();
 
     // Stop the audio processes
-    //mAudioInterface->stopProcess();
+    // mAudioInterface->stopProcess();
     closeAudio();
-    
+
     cout << "JackTrip Processes STOPPED!" << endl;
     cout << gPrintSeparator << endl;
 
@@ -786,7 +977,6 @@ void JackTrip::stop(QString errorMessage)
     }
 }
 
-
 //*******************************************************************************
 void JackTrip::waitThreads()
 {
@@ -794,56 +984,67 @@ void JackTrip::waitThreads()
     mDataProtocolReceiver->wait();
 }
 
-
 //*******************************************************************************
 void JackTrip::clientStart()
 {
     // For the Client mode, the peer (or server) address has to be specified by the user
-    if ( mPeerAddress.isEmpty() ) {
-        throw std::invalid_argument("Peer Address has to be set if you run in CLIENT mode");
-    }
-    else {
-        mDataProtocolSender->setPeerAddress( mPeerAddress.toLatin1().data() );
-        mDataProtocolReceiver->setPeerAddress( mPeerAddress.toLatin1().data() );
+    if (mPeerAddress.isEmpty()) {
+        throw std::invalid_argument(
+            "Peer Address has to be set if you run in CLIENT mode");
+    else {
+        mDataProtocolSender->setPeerAddress(mPeerAddress.toLatin1().data());
+        mDataProtocolReceiver->setPeerAddress(mPeerAddress.toLatin1().data());
         cout << "Peer Address set to: " << mPeerAddress.toStdString() << std::endl;
         cout << gPrintSeparator << endl;
         completeConnection();
     }
 }
 
-
 //*******************************************************************************
-int JackTrip::serverStart(bool timeout, int udpTimeout) // udpTimeout unused
+int JackTrip::serverStart(bool timeout, int udpTimeout)  // udpTimeout unused
 {
     // Set the peer address
-    if ( !mPeerAddress.isEmpty() ) {
-        if (gVerboseFlag) std::cout << "WARNING: SERVER mode: Peer Address was set but will be deleted." << endl;
-        //throw std::invalid_argument("Peer Address has to be set if you run in CLIENT mode");
+    if (!mPeerAddress.isEmpty()) {
+        if (gVerboseFlag)
+            std::cout << "WARNING: SERVER mode: Peer Address was set but will be deleted."
+                      << endl;
+        // throw std::invalid_argument("Peer Address has to be set if you run in CLIENT
+        // mode");
         mPeerAddress.clear();
-        //return;
+        // return;
+    }
+
+    // Start timer before binding our port and waiting for datagrams
+    {
+        QMutexLocker lock(&mTimerMutex);
+        mAwaitingUdp = true;
+        mElapsedTime = 0;
+        if (timeout) { mEndTime = udpTimeout; }
+        mTimeoutTimer.setInterval(mSleepTime);
+        connect(&mTimeoutTimer, &QTimer::timeout, this, &JackTrip::udpTimerTick);
+        mTimeoutTimer.start();
     }
 
     // Get the client address when it connects
-    if (gVerboseFlag) std::cout << "JackTrip:serverStart before mUdpSockTemp.bind(Any)" << std::endl;
+    if (gVerboseFlag)
+        std::cout << "JackTrip:serverStart before mUdpSockTemp.bind(Any)" << std::endl;
     // Bind the socket
-    if ( !mUdpSockTemp.bind(QHostAddress::Any, mReceiverBindPort,
-                           QUdpSocket::DefaultForPlatform) )
-    {
-        std::cerr << "in JackTrip: Could not bind UDP socket. It may be already binded." << endl;
+    if (!mUdpSockTemp.bind(QHostAddress::Any, mReceiverBindPort,
+                           QUdpSocket::DefaultForPlatform)) {
+        {
+            QMutexLocker lock(&mTimerMutex);
+            mAwaitingUdp = false;
+            mTimeoutTimer.stop();
+        }
+        std::cerr << "in JackTrip: Could not bind UDP socket. It may be already binded."
+                  << endl;
         throw std::runtime_error("Could not bind UDP socket. It may be already binded.");
     }
     connect(&mUdpSockTemp, &QUdpSocket::readyRead, this, &JackTrip::receivedDataUDP);
-    
-    // Start timer and then wait for a signal to read datagrams.
-    mElapsedTime = 0;
-    if (timeout) {
-        mEndTime = udpTimeout;
-    }
-    mTimeoutTimer.setInterval(mSleepTime);
-    connect(&mTimeoutTimer, &QTimer::timeout, this, &JackTrip::udpTimerTick);
-    mTimeoutTimer.start();
-    
-    if (gVerboseFlag) std::cout << "JackTrip:serverStart before !UdpSockTemp.hasPendingDatagrams()" << std::endl;
+
+    if (gVerboseFlag)
+        std::cout << "JackTrip:serverStart before !UdpSockTemp.hasPendingDatagrams()"
+                  << std::endl;
     cout << "Waiting for Connection From a Client..." << endl;
     return 0;
     // Continued in the receivedDataUDP slot.
@@ -854,21 +1055,45 @@ int JackTrip::serverStart(bool timeout, int udpTimeout) // udpTimeout unused
     //    UdpSockTemp.close(); // close the socket
 }
 
-
 //*******************************************************************************
 int JackTrip::clientPingToServerStart()
 {
-    //mConnectionMode = JackTrip::KSTRONG;
-    //mConnectionMode = JackTrip::JAMTEST;
+    // mConnectionMode = JackTrip::KSTRONG;
+    // mConnectionMode = JackTrip::JAMTEST;
 
     // Set Peer (server in this case) address
     // --------------------------------------
     // For the Client mode, the peer (or server) address has to be specified by the user
-    if ( mPeerAddress.isEmpty() ) {
-        throw std::invalid_argument("Peer Address has to be set if you run in CLIENTTOPINGSERVER mode");
+    if (mPeerAddress.isEmpty()) {
+        throw std::invalid_argument(
+            "Peer Address has to be set if you run in CLIENTTOPINGSERVER mode");
         return -1;
     }
 
+    // If we're using authentication, check that SSL support is available.
+    if (mUseAuth) {
+        if (!QSslSocket::supportsSsl()) {
+            QString error_message =
+                "SSL not supported. Make sure you have the appropriate SSL "
+                "libraries\ninstalled to enable authentication.";
+            std::cerr << "ERROR: " << error_message.toStdString() << std::endl;
+            stop(error_message);
+            return -1;
+        } else if (mUsername.isEmpty() || mPassword.isEmpty()) {
+            QString error_message =
+                "You must supply a username and password to authenticate with a hub "
+                "server.";
+            std::cerr << "ERROR: " << error_message.toStdString() << std::endl;
+            stop(error_message);
+            return -1;
+        } else {
+            // At the moment, don't verify the certificate so we can use self signed ones.
+            mTcpClient.setPeerVerifyMode(QSslSocket::VerifyNone);
+            QObject::connect(&mTcpClient, &QSslSocket::encrypted, this,
+                             &JackTrip::connectionSecured, Qt::QueuedConnection);
+        }
+    }
+
     // Create Socket Objects
     // --------------------
     QHostAddress serverHostAddress;
@@ -884,14 +1109,21 @@ int JackTrip::clientPingToServerStart()
     // ----------------------------------------------
     connect(&mTcpClient, &QTcpSocket::readyRead, this, &JackTrip::receivedDataTCP);
     connect(&mTcpClient, &QTcpSocket::connected, this, &JackTrip::receivedConnectionTCP);
-    mElapsedTime = 0;
-    mEndTime = 5000; //Timeout after 5 seconds.
-    mTimeoutTimer.setInterval(mSleepTime);
-    connect(&mTimeoutTimer, &QTimer::timeout, this, &JackTrip::tcpTimerTick);
-    mTimeoutTimer.start();
+    {
+        QMutexLocker lock(&mTimerMutex);
+        mAwaitingTcp = true;
+        mElapsedTime = 0;
+        mEndTime     = 5000;  // Timeout after 5 seconds.
+        mTimeoutTimer.setInterval(mSleepTime);
+        connect(&mTimeoutTimer, &QTimer::timeout, this, &JackTrip::tcpTimerTick);
+        mTimeoutTimer.start();
+    }
     mTcpClient.connectToHost(serverHostAddress, mTcpServerPort);
-    
-    if (gVerboseFlag) cout << "Connecting to TCP Server at " <<  serverHostAddress.toString().toLatin1().constData() << " port " << mTcpServerPort << "..." << endl;
+
+    if (gVerboseFlag)
+        cout << "Connecting to TCP Server at "
+             << serverHostAddress.toString().toLatin1().constData() << " port "
+             << mTcpServerPort << "..." << endl;
     return 0;
     // Continued in the receivedConnectionTCP slot.
 
@@ -920,7 +1152,8 @@ int JackTrip::clientPingToServerStart()
   if ( !UdpSockTemp.bind(QHostAddress::Any,
                          mReceiverBindPort,
                          QUdpSocket::ShareAddress) ) {
-    //throw std::runtime_error("Could not bind PingToServer UDP socket. It may be already binded.");
+    //throw std::runtime_error("Could not bind PingToServer UDP socket. It may be already
+  binded.");
   }
 
   // Listen to server response
@@ -947,7 +1180,6 @@ int JackTrip::clientPingToServerStart()
   */
 }
 
-
 //*******************************************************************************
 /*
 void JackTrip::bindReceiveSocket(QUdpSocket& UdpSocket, int bind_port,
@@ -961,8 +1193,8 @@ throw(std::runtime_error)
   struct sockaddr_in local_addr;
   ::bzero(&local_addr, sizeof(local_addr));
   local_addr.sin_family = AF_INET; //AF_INET: IPv4 Protocol
-  local_addr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY: let the kernel decide the active address
-  local_addr.sin_port = htons(bind_port); //set bind port
+  local_addr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY: let the kernel decide the
+active address local_addr.sin_port = htons(bind_port); //set bind port
 
   // Set socket to be reusable, this is platform dependent
   int one = 1;
@@ -985,8 +1217,8 @@ throw(std::runtime_error)
   struct sockaddr_in peer_addr;
   bzero(&peer_addr, sizeof(peer_addr));
   peer_addr.sin_family = AF_INET; //AF_INET: IPv4 Protocol
-  peer_addr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY: let the kernel decide the active address
-  peer_addr.sin_port = htons(peer_port); //set local port
+  peer_addr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY: let the kernel decide the
+active address peer_addr.sin_port = htons(peer_port); //set local port
   // Connect the socket and issue a Write shutdown (to make it a
   // reader socket only)
   if ( (::inet_pton(AF_INET, PeerHostAddress.toString().toLatin1().constData(),
@@ -1004,82 +1236,84 @@ throw(std::runtime_error)
 }
 */
 
-
 //*******************************************************************************
 void JackTrip::createHeader(const DataProtocol::packetHeaderTypeT headertype)
 {
-    delete mPacketHeader; //Just in case it has already been allocated
+    delete mPacketHeader;  // Just in case it has already been allocated
     switch (headertype) {
-    case DataProtocol::DEFAULT :
+    case DataProtocol::DEFAULT:
         mPacketHeader = new DefaultHeader(this);
         break;
-    case DataProtocol::JAMLINK :
+    case DataProtocol::JAMLINK:
         mPacketHeader = new JamLinkHeader(this);
         break;
-    case DataProtocol::EMPTY :
+    case DataProtocol::EMPTY:
         mPacketHeader = new EmptyHeader(this);
         break;
-    default :
+    default:
         throw std::invalid_argument("Undefined Header Type");
         break;
     }
 }
 
-
 //*******************************************************************************
-void JackTrip::putHeaderInPacket(int8_t* full_packet, int8_t* audio_packet)
+void JackTrip::putHeaderInIncomingPacket(int8_t* full_packet, int8_t* audio_packet)
 {
     mPacketHeader->fillHeaderCommonFromAudio();
     mPacketHeader->putHeaderInPacket(full_packet);
 
     int8_t* audio_part;
     audio_part = full_packet + mPacketHeader->getHeaderSizeInBytes();
-    //std::memcpy(audio_part, audio_packet, mAudioInterface->getBufferSizeInBytes());
-    //std::memcpy(audio_part, audio_packet, mAudioInterface->getSizeInBytesPerChannel() * mNumChans);
-    std::memcpy(audio_part, audio_packet, getTotalAudioPacketSizeInBytes());
+    // std::memcpy(audio_part, audio_packet, mAudioInterface->getBufferSizeInBytes());
+    // std::memcpy(audio_part, audio_packet, mAudioInterface->getSizeInBytesPerChannel() *
+    // mNumChans);
+    std::memcpy(audio_part, audio_packet, getTotalAudioOutputPacketSizeInBytes());
 }
 
+void JackTrip::putHeaderInOutgoingPacket(int8_t* full_packet, int8_t* audio_packet)
+{
+    mPacketHeader->fillHeaderCommonFromAudio();
+    mPacketHeader->putHeaderInPacket(full_packet);
+
+    int8_t* audio_part;
+    audio_part = full_packet + mPacketHeader->getHeaderSizeInBytes();
+    // std::memcpy(audio_part, audio_packet, mAudioInterface->getBufferSizeInBytes());
+    // std::memcpy(audio_part, audio_packet, mAudioInterface->getSizeInBytesPerChannel() *
+    // mNumChans);
+    std::memcpy(audio_part, audio_packet, getTotalAudioInputPacketSizeInBytes());
+}
 
 //*******************************************************************************
-int JackTrip::getPacketSizeInBytes()
+int JackTrip::getSendPacketSizeInBytes() const
 {
-    //return (mAudioInterface->getBufferSizeInBytes() + mPacketHeader->getHeaderSizeInBytes());
-    //return (mAudioInterface->getSizeInBytesPerChannel() * mNumChans  +
-    //mPacketHeader->getHeaderSizeInBytes());
-    return (getTotalAudioPacketSizeInBytes()  +
-            mPacketHeader->getHeaderSizeInBytes());
+    return (getTotalAudioInputPacketSizeInBytes()
+            + mPacketHeader->getHeaderSizeInBytes());
 }
 
-
-//*******************************************************************************
-void JackTrip::parseAudioPacket(int8_t* full_packet, int8_t* audio_packet)
+int JackTrip::getReceivePacketSizeInBytes() const
 {
-    int8_t* audio_part;
-    audio_part = full_packet + mPacketHeader->getHeaderSizeInBytes();
-    //std::memcpy(audio_packet, audio_part, mAudioInterface->getBufferSizeInBytes());
-    //std::memcpy(audio_packet, audio_part, mAudioInterface->getSizeInBytesPerChannel() * mNumChans);
-    std::memcpy(audio_packet, audio_part, getTotalAudioPacketSizeInBytes());
+    return (getTotalAudioOutputPacketSizeInBytes()
+            + mPacketHeader->getHeaderSizeInBytes());
 }
 
 //*******************************************************************************
-void JackTrip::checkPeerSettings(int8_t* full_packet)
+bool JackTrip::checkPeerSettings(int8_t* full_packet)
 {
-    mPacketHeader->checkPeerSettings(full_packet);
+    return mPacketHeader->checkPeerSettings(full_packet);
 }
 
-
 //*******************************************************************************
 void JackTrip::checkIfPortIsBinded(int port)
 {
-    QUdpSocket UdpSockTemp;// Create socket to wait for client
+    QUdpSocket UdpSockTemp;  // Create socket to wait for client
     // Bind the socket
-    //cc        if ( !UdpSockTemp.bind(QHostAddress::AnyIPv4, port, QUdpSocket::DontShareAddress) )
-    if ( !UdpSockTemp.bind(QHostAddress::Any, port,
-                           QUdpSocket::DontShareAddress) )
-    {
-        UdpSockTemp.close(); // close the socket
+    // cc        if ( !UdpSockTemp.bind(QHostAddress::AnyIPv4, port,
+    // QUdpSocket::DontShareAddress) )
+    if (!UdpSockTemp.bind(QHostAddress::Any, port, QUdpSocket::DontShareAddress)) {
+        UdpSockTemp.close();  // close the socket
         throw std::runtime_error(
-                    "Could not bind UDP socket. It may already be binded by another process on your machine. Try using a different port number");
+            "Could not bind UDP socket. It may already be binded by another process on "
+            "your machine. Try using a different port number");
     }
-    UdpSockTemp.close(); // close the socket
+    UdpSockTemp.close();  // close the socket
 }
index 50e90ed550a516fb7360e737cf94fb78fd7faa33..5d3dde712b684537f00eee04708da5ea85427788 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
 #define __JACKTRIP_H__
 
 //#include <tr1/memory> //for shared_ptr
-#include <stdexcept>
-
 #include <QObject>
+#include <QSharedPointer>
+#include <QSslSocket>
 #include <QString>
-#include <QUdpSocket>
-#include <QTcpSocket>
 #include <QTimer>
-#include <QSharedPointer>
+#include <QUdpSocket>
+#include <stdexcept>
 
-#include "DataProtocol.h"
 #include "AudioInterface.h"
+#include "DataProtocol.h"
 
 #ifndef __NO_JACK__
 #include "JackAudioInterface.h"
-#endif //__NO_JACK__
+#endif  //__NO_JACK__
 
+#include "AudioTester.h"
 #include "PacketHeader.h"
 #include "RingBuffer.h"
-#include "AudioTester.h"
 
 //#include <signal.h>
 /** \brief Main class to creates a SERVER (to listen) or a CLIENT (to connect
@@ -72,111 +71,112 @@ class JackTrip : public QObject
 {
     Q_OBJECT;
 
-public:
-
+   public:
     //----------ENUMS------------------------------------------
     /// \brief Enum for the data Protocol. At this time only UDP is implemented
     enum dataProtocolT {
-        UDP, ///< Use UDP (User Datagram Protocol)
-        TCP, ///< <B>NOT IMPLEMENTED</B>: Use TCP (Transmission Control Protocol)
-        SCTP ///< <B>NOT IMPLEMENTED</B>: Use SCTP (Stream Control Transmission Protocol)
+        UDP,  ///< Use UDP (User Datagram Protocol)
+        TCP,  ///< <B>NOT IMPLEMENTED</B>: Use TCP (Transmission Control Protocol)
+        SCTP  ///< <B>NOT IMPLEMENTED</B>: Use SCTP (Stream Control Transmission Protocol)
     };
 
     /// \brief Enum for the JackTrip mode
     enum jacktripModeT {
-        SERVER, ///< Run in P2P Server Mode
-        CLIENT,  ///< Run in P2P Client Mode
-        CLIENTTOPINGSERVER, ///< Client of the Ping Server Mode
-        SERVERPINGSERVER ///< Server of the MultiThreaded JackTrip
+        SERVER,              ///< Run in P2P Server Mode
+        CLIENT,              ///< Run in P2P Client Mode
+        CLIENTTOPINGSERVER,  ///< Client of the Ping Server Mode
+        SERVERPINGSERVER     ///< Server of the MultiThreaded JackTrip
     };
 
     /// \brief Enum for the JackTrip Underrun Mode, when packets
     enum underrunModeT {
-        WAVETABLE, ///< Loops on the last received packet
-        ZEROS  ///< Set new buffers to zero if there are no new ones
+        WAVETABLE,  ///< Loops on the last received packet
+        ZEROS       ///< Set new buffers to zero if there are no new ones
     };
 
     /// \brief Enum for Audio Interface Mode
     enum audiointerfaceModeT {
-        JACK, ///< Jack Mode
+        JACK,    ///< Jack Mode
         RTAUDIO  ///< RtAudio Mode
     };
 
     /// \brief Enum for Connection Mode (in packet header)
     enum connectionModeT {
-        NORMAL, ///< Normal Mode
+        NORMAL,   ///< Normal Mode
         KSTRONG,  ///< Karplus Strong
-        JAMTEST  ///< Karplus Strong
+        JAMTEST   ///< Karplus Strong
     };
 
-    /// \brief Enum for Hub Server Audio Connection Mode (connections to hub server are automatically patched in Jack)
+    /// \brief Enum for Hub Server Audio Connection Mode (connections to hub server are
+    /// automatically patched in Jack)
     enum hubConnectionModeT {
-        SERVERTOCLIENT, ///< Normal Mode, Sever to All Clients (but not client to any client)
-        CLIENTECHO,  ///< Client Echo (client self-to-self)
-        CLIENTFOFI,  ///< Client Fan Out to Clients and Fan In from Clients (but not self-to-self)
+        SERVERTOCLIENT,  ///< Normal Mode, Sever to All Clients (but not client to any
+                         ///< client)
+        CLIENTECHO,      ///< Client Echo (client self-to-self)
+        CLIENTFOFI,      ///< Client Fan Out to Clients and Fan In from Clients (but not
+                         ///< self-to-self)
         RESERVEDMATRIX,  ///< Reserved for custom patch matrix (for TUB ensemble)
-        FULLMIX,  ///< Client Fan Out to Clients and Fan In from Clients (including self-to-self)
-        NOAUTO  ///< No automatic patching
+        FULLMIX,         ///< Client Fan Out to Clients and Fan In from Clients (including
+                         ///< self-to-self)
+        NOAUTO           ///< No automatic patching
     };
     //---------------------------------------------------------
 
-
     /** \brief The class Constructor with Default Parameters
-   * \param JacktripMode JackTrip::CLIENT or JackTrip::SERVER
-   * \param DataProtocolType JackTrip::dataProtocolT
-   * \param NumChans Number of Audio Channels (same for inputs and outputs)
-   * \param BufferQueueLength Audio Buffer for receiving packets
-   * \param AudioBitResolution Audio Sample Resolutions in bits
-   * \param redundancy redundancy factor for network data
-   */
-    JackTrip(jacktripModeT JacktripMode = CLIENT,
-             dataProtocolT DataProtocolType = UDP,
-             int NumChans = gDefaultNumInChannels,
-         #ifdef WAIR // wair
-             int NumNetRevChans = 0,
-         #endif // endwhere
-             int BufferQueueLength = gDefaultQueueLength,
-             unsigned int redundancy = gDefaultRedundancy,
-             AudioInterface::audioBitResolutionT AudioBitResolution =
-             AudioInterface::BIT16,
-             DataProtocol::packetHeaderTypeT PacketHeaderType =
-             DataProtocol::DEFAULT,
-             underrunModeT UnderRunMode = WAVETABLE,
-             int receiver_bind_port = gDefaultPort,
-             int sender_bind_port = gDefaultPort,
-             int receiver_peer_port = gDefaultPort,
-             int sender_peer_port = gDefaultPort,
-             int tcp_peer_port = gDefaultPort);
+     * \param JacktripMode JackTrip::CLIENT or JackTrip::SERVER
+     * \param DataProtocolType JackTrip::dataProtocolT
+     * \param NumChans Number of Audio Channels (same for inputs and outputs)
+     * \param BufferQueueLength Audio Buffer for receiving packets
+     * \param AudioBitResolution Audio Sample Resolutions in bits
+     * \param redundancy redundancy factor for network data
+     */
+    JackTrip(
+        jacktripModeT JacktripMode = CLIENT, dataProtocolT DataProtocolType = UDP,
+        int NumChansIn = gDefaultNumInChannels, int NumChansOut = gDefaultNumInChannels,
+#ifdef WAIR  // wair
+        int NumNetRevChans = 0,
+#endif  // endwhere
+        int BufferQueueLength                                  = gDefaultQueueLength,
+        unsigned int redundancy                                = gDefaultRedundancy,
+        AudioInterface::audioBitResolutionT AudioBitResolution = AudioInterface::BIT16,
+        DataProtocol::packetHeaderTypeT PacketHeaderType       = DataProtocol::DEFAULT,
+        underrunModeT UnderRunMode = WAVETABLE, int receiver_bind_port = gDefaultPort,
+        int sender_bind_port = gDefaultPort, int receiver_peer_port = gDefaultPort,
+        int sender_peer_port = gDefaultPort, int tcp_peer_port = gDefaultPort);
 
     /// \brief The class destructor
     virtual ~JackTrip();
-    
-    static void sigIntHandler(__attribute__((unused)) int unused)
-    { std::cout << std::endl << "Shutting Down..." << std::endl; sSigInt = true; }
+
+    static void sigIntHandler(int /*unused*/)
+    {
+        std::cout << std::endl << "Shutting Down..." << std::endl;
+        sSigInt = true;
+    }
     static bool sSigInt;
     static bool sJackStopped;
 
     /// \brief Starting point for the thread
     /*virtual void run() {
-        if (gVerboseFlag) std::cout << "Settings:startJackTrip before mJackTrip->run" << std::endl;
+        if (gVerboseFlag) std::cout << "Settings:startJackTrip before mJackTrip->run" <<
+    std::endl;
     }*/
 
     /// \brief Set the Peer Address for jacktripModeT::CLIENT mode only
     virtual void setPeerAddress(QString PeerHostOrIP);
 
     /** \brief Append a process plugin. Processes will be appended in order
-   * \param plugin Pointer to ProcessPlugin Class
-   */
-    //void appendProcessPlugin(const std::tr1::shared_ptr<ProcessPlugin> plugin);
+     * \param plugin Pointer to ProcessPlugin Class
+     */
+    // void appendProcessPlugin(const std::tr1::shared_ptr<ProcessPlugin> plugin);
     virtual void appendProcessPluginToNetwork(ProcessPlugin* plugin);
     virtual void appendProcessPluginFromNetwork(ProcessPlugin* plugin);
 
     /// \brief Start the processing threads
     virtual void startProcess(
-        #ifdef WAIRTOHUB // wair
-            int ID
-        #endif // endwhere
-            );
+#ifdef WAIRTOHUB  // wair
+        int ID
+#endif  // endwhere
+    );
     virtual void completeConnection();
 
     /// \brief Stop the processing threads
@@ -196,10 +196,14 @@ public:
     //
     /// \brief Sets (override) JackTrip Mode after construction
     virtual void setJackTripMode(jacktripModeT JacktripMode)
-    { mJackTripMode = JacktripMode; }
+    {
+        mJackTripMode = JacktripMode;
+    }
     /// \brief Sets (override) DataProtocol Type after construction
     virtual void setDataProtocoType(dataProtocolT DataProtocolType)
-    { mDataProtocol = DataProtocolType; }
+    {
+        mDataProtocol = DataProtocolType;
+    }
     /// \brief Sets the Packet header type
     virtual void setPacketHeaderType(DataProtocol::packetHeaderTypeT PacketHeaderType)
     {
@@ -210,282 +214,371 @@ public:
     }
     /// \brief Sets (override) Buffer Queue Length Mode after construction
     virtual void setBufferQueueLength(int BufferQueueLength)
-    { mBufferQueueLength = BufferQueueLength; }
+    {
+        mBufferQueueLength = BufferQueueLength;
+    }
     virtual void setBufferStrategy(int BufferStrategy)
-    { mBufferStrategy = BufferStrategy; }
+    {
+        mBufferStrategy = BufferStrategy;
+    }
     /// \brief Sets (override) Audio Bit Resolution after construction
-    virtual void setAudioBitResolution(AudioInterface::audioBitResolutionT AudioBitResolution)
-    { mAudioBitResolution = AudioBitResolution; }
+    virtual void setAudioBitResolution(
+        AudioInterface::audioBitResolutionT AudioBitResolution)
+    {
+        mAudioBitResolution = AudioBitResolution;
+    }
     /// \brief Sets (override) Underrun Mode
     virtual void setUnderRunMode(underrunModeT UnderRunMode)
-    { mUnderRunMode = UnderRunMode; }
+    {
+        mUnderRunMode = UnderRunMode;
+    }
     /// \brief Sets whether to quit on timeout.
-    virtual void setStopOnTimeout(bool stopOnTimeout)
-    { mStopOnTimeout = stopOnTimeout; }
+    virtual void setStopOnTimeout(bool stopOnTimeout) { mStopOnTimeout = stopOnTimeout; }
     /// \brief Sets port numbers for the local and peer machine.
     /// Receive port is <tt>port</tt>
     virtual void setAllPorts(int port)
     {
         mReceiverBindPort = port;
-        mSenderPeerPort = port;
-        mSenderBindPort = port;
+        mSenderPeerPort   = port;
+        mSenderBindPort   = port;
         mReceiverPeerPort = port;
     }
     /// \brief Sets port numbers to bind in RECEIVER and SENDER sockets.
     void setBindPorts(int port)
     {
         mReceiverBindPort = port;
-        mSenderBindPort = port;
+        mSenderBindPort   = port;
     }
     /// \brief Sets port numbers for the peer (remote) machine.
     void setPeerPorts(int port)
     {
-        mSenderPeerPort = port;
+        mSenderPeerPort   = port;
         mReceiverPeerPort = port;
     }
+    void setPeerHandshakePort(int port) { mTcpServerPort = port; }
+    void setUseAuth(bool auth) { mUseAuth = auth; }
+    void setUsername(QString username) { mUsername = username; }
+    void setPassword(QString password) { mPassword = password; }
     /// \brief Set Client Name to something different that the default (JackTrip)
-    virtual void setClientName(QString clientName)
-    { mJackClientName = clientName; }
+    virtual void setClientName(QString clientName) { mJackClientName = clientName; }
     virtual void setRemoteClientName(QString remoteClientName)
-    { mRemoteClientName = remoteClientName; }
-    /// \brief Set the number of audio channels
-    virtual void setNumChannels(int num_chans)
-    { mNumChans = num_chans; }
-    
+    {
+        mRemoteClientName = remoteClientName;
+    }
+    /// \brief Set the number of audio input channels
+    virtual void setNumInputChannels(int num_chans) { mNumAudioChansIn = num_chans; }
+    /// \brief Set the number of audio output channels
+    virtual void setNumOutputChannels(int num_chans) { mNumAudioChansOut = num_chans; }
+
     virtual void setIOStatTimeout(int timeout) { mIOStatTimeout = timeout; }
-    virtual void setIOStatStream(QSharedPointer<std::ofstream> statStream) { mIOStatStream = statStream; }
+    virtual void setIOStatStream(QSharedPointer<std::ofstream> statStream)
+    {
+        mIOStatStream = statStream;
+    }
 
     /// Set to connect or not default audio ports (only implemented in Jack)
     virtual void setConnectDefaultAudioPorts(bool connect)
-    {mConnectDefaultAudioPorts = connect;}
-
-    virtual int getReceiverBindPort() const
-    { return mReceiverBindPort; }
-    virtual int getSenderPeerPort() const
-    { return mSenderPeerPort; }
-    virtual int getSenderBindPort() const
-    { return mSenderBindPort; }
-    virtual int getReceiverPeerPort() const
-    { return mReceiverPeerPort; }
-
-    virtual DataProtocol* getDataProtocolSender() const
-    { return mDataProtocolSender; }
+    {
+        mConnectDefaultAudioPorts = connect;
+    }
+
+    virtual int getReceiverBindPort() const { return mReceiverBindPort; }
+    virtual int getSenderPeerPort() const { return mSenderPeerPort; }
+    virtual int getSenderBindPort() const { return mSenderBindPort; }
+    virtual int getReceiverPeerPort() const { return mReceiverPeerPort; }
+
+    virtual DataProtocol* getDataProtocolSender() const { return mDataProtocolSender; }
     virtual DataProtocol* getDataProtocolReceiver() const
-    { return mDataProtocolReceiver; }
+    {
+        return mDataProtocolReceiver;
+    }
     virtual void setDataProtocolSender(DataProtocol* const DataProtocolSender)
-    { mDataProtocolSender = DataProtocolSender; }
+    {
+        mDataProtocolSender = DataProtocolSender;
+    }
     virtual void setDataProtocolReceiver(DataProtocol* const DataProtocolReceiver)
-    { mDataProtocolReceiver = DataProtocolReceiver; }
+    {
+        mDataProtocolReceiver = DataProtocolReceiver;
+    }
 
-    virtual RingBuffer* getSendRingBuffer() const
-    { return mSendRingBuffer; }
-    virtual RingBuffer* getReceiveRingBuffer() const
-    { return mReceiveRingBuffer; }
+    virtual RingBuffer* getSendRingBuffer() const { return mSendRingBuffer; }
+    virtual RingBuffer* getReceiveRingBuffer() const { return mReceiveRingBuffer; }
     virtual void setSendRingBuffer(RingBuffer* const SendRingBuffer)
-    { mSendRingBuffer = SendRingBuffer; }
+    {
+        mSendRingBuffer = SendRingBuffer;
+    }
     virtual void setReceiveRingBuffer(RingBuffer* const ReceiveRingBuffer)
-    { mReceiveRingBuffer = ReceiveRingBuffer; }
+    {
+        mReceiveRingBuffer = ReceiveRingBuffer;
+    }
 
     virtual void setPacketHeader(PacketHeader* const PacketHeader)
-    { mPacketHeader = PacketHeader; }
+    {
+        mPacketHeader = PacketHeader;
+    }
 
-    virtual int getRingBuffersSlotSize()
-    { return getTotalAudioPacketSizeInBytes(); }
+    virtual int getInputRingBuffersSlotSize()
+    {
+        return getTotalAudioInputPacketSizeInBytes();
+    }
+    virtual int getOutputRingBuffersSlotSize()
+    {
+        return getTotalAudioOutputPacketSizeInBytes();
+    }
 
     virtual void setAudiointerfaceMode(JackTrip::audiointerfaceModeT audiointerface_mode)
-    { mAudiointerfaceMode = audiointerface_mode; }
+    {
+        mAudiointerfaceMode = audiointerface_mode;
+    }
     virtual void setAudioInterface(AudioInterface* const AudioInterface)
-    { mAudioInterface = AudioInterface; }
-    virtual void setLoopBack(bool b)
-    { mLoopBack = b; }
-    virtual void setAudioTesterP(AudioTester* atp) { mAudioTesterP = atp; }
-
-    void setSampleRate(uint32_t sample_rate)
-    { mSampleRate = sample_rate; }
-    void setDeviceID(uint32_t device_id)
-    { mDeviceID = device_id; }
-    void setAudioBufferSizeInSamples(uint32_t buf_size)
-    { mAudioBufferSize = buf_size; }
-
+    {
+        mAudioInterface = AudioInterface;
+    }
+    virtual void setLoopBack(bool b) { mLoopBack = b; }
+    virtual void setAudioTesterP(QSharedPointer<AudioTester> atp) { mAudioTesterP = atp; }
 
-    JackTrip::connectionModeT getConnectionMode() const
-    { return mConnectionMode; }
-    void setConnectionMode(JackTrip::connectionModeT connection_mode)
-    { mConnectionMode = connection_mode; }
+    void setSampleRate(uint32_t sample_rate) { mSampleRate = sample_rate; }
+    void setDeviceID(uint32_t device_id) { mDeviceID = device_id; }
+    void setInputDevice(std::string device_name) { mInputDeviceName = device_name; }
+    void setOutputDevice(std::string device_name) { mOutputDeviceName = device_name; }
+    void setAudioBufferSizeInSamples(uint32_t buf_size) { mAudioBufferSize = buf_size; }
 
     JackTrip::hubConnectionModeT getHubConnectionModeT() const
-    { return mHubConnectionModeT; }
+    {
+        return mHubConnectionModeT;
+    }
     void setHubConnectionModeT(JackTrip::hubConnectionModeT connection_mode)
-    { mHubConnectionModeT = connection_mode; }
+    {
+        mHubConnectionModeT = connection_mode;
+    }
 
-    JackTrip::jacktripModeT getJackTripMode() const
-    { return mJackTripMode; }
+    JackTrip::jacktripModeT getJackTripMode() const { return mJackTripMode; }
 
-    QString getPeerAddress() const
-    { return mPeerAddress; }
+    QString getPeerAddress() const { return mPeerAddress; }
 
-    bool receivedConnectionFromPeer()
-    { return mReceivedConnection; }
+    bool receivedConnectionFromPeer() { return mReceivedConnection; }
 
-    bool tcpConnectionError()
-    { return mTcpConnectionError; }
+    bool tcpConnectionError() { return mTcpConnectionError; }
 
     //@}
     //------------------------------------------------------------------------------------
 
-
     //------------------------------------------------------------------------------------
     /// \name Mediator Functions
     //@{
     /// \todo Document all these functions
     virtual void createHeader(const DataProtocol::packetHeaderTypeT headertype);
-    void putHeaderInPacket(int8_t* full_packet, int8_t* audio_packet);
-    virtual int getPacketSizeInBytes();
-    void parseAudioPacket(int8_t* full_packet, int8_t* audio_packet);
+    void putHeaderInIncomingPacket(int8_t* full_packet, int8_t* audio_packet);
+    void putHeaderInOutgoingPacket(int8_t* full_packet, int8_t* audio_packet);
+    int getSendPacketSizeInBytes() const;
+    int getReceivePacketSizeInBytes() const;
     virtual void sendNetworkPacket(const int8_t* ptrToSlot)
-    { mSendRingBuffer->insertSlotNonBlocking(ptrToSlot, 0, 0); }
+    {
+        mSendRingBuffer->insertSlotNonBlocking(ptrToSlot, 0, 0);
+    }
     virtual void receiveBroadcastPacket(int8_t* ptrToReadSlot)
-    { mReceiveRingBuffer->readBroadcastSlot(ptrToReadSlot); }
+    {
+        mReceiveRingBuffer->readBroadcastSlot(ptrToReadSlot);
+    }
     virtual void receiveNetworkPacket(int8_t* ptrToReadSlot)
-    { mReceiveRingBuffer->readSlotNonBlocking(ptrToReadSlot); }
+    {
+        mReceiveRingBuffer->readSlotNonBlocking(ptrToReadSlot);
+    }
     virtual void readAudioBuffer(int8_t* ptrToReadSlot)
-    { mSendRingBuffer->readSlotBlocking(ptrToReadSlot); }
+    {
+        mSendRingBuffer->readSlotBlocking(ptrToReadSlot);
+    }
     virtual bool writeAudioBuffer(const int8_t* ptrToSlot, int len, int lostLen)
-    { return mReceiveRingBuffer->insertSlotNonBlocking(ptrToSlot, len, lostLen); }
+    {
+        return mReceiveRingBuffer->insertSlotNonBlocking(ptrToSlot, len, lostLen);
+    }
     uint32_t getBufferSizeInSamples() const
-    { return mAudioBufferSize; /*return mAudioInterface->getBufferSizeInSamples();*/ }
+    {
+        return mAudioBufferSize; /*return mAudioInterface->getBufferSizeInSamples();*/
+    }
     uint32_t getDeviceID() const
-    { return mDeviceID; /*return mAudioInterface->mDeviceID();*/ }
+    {
+        return mDeviceID; /*return mAudioInterface->mDeviceID();*/
+    }
 
     AudioInterface::samplingRateT getSampleRateType() const
-    { return mAudioInterface->getSampleRateType(); }
+    {
+        return mAudioInterface->getSampleRateType();
+    }
     int getSampleRate() const
-    { return mSampleRate; /*return mAudioInterface->getSampleRate();*/ }
+    {
+        return mSampleRate; /*return mAudioInterface->getSampleRate();*/
+    }
 
     uint8_t getAudioBitResolution() const
-    { return mAudioBitResolution*8; /*return mAudioInterface->getAudioBitResolution();*/ }
+    {
+        return mAudioBitResolution
+               * 8; /*return mAudioInterface->getAudioBitResolution();*/
+    }
     unsigned int getNumInputChannels() const
-    { return mNumChans; /*return mAudioInterface->getNumInputChannels();*/ }
+    {
+        return mNumAudioChansIn; /*return mAudioInterface->getNumInputChannels();*/
+    }
     unsigned int getNumOutputChannels() const
-    { return mNumChans; /*return mAudioInterface->getNumOutputChannels();*/ }
-    unsigned int getNumChannels() const
     {
-        if (getNumInputChannels() == getNumOutputChannels())
-        { return getNumInputChannels(); }
-        else { return 0; }
+        return mNumAudioChansOut; /*return mAudioInterface->getNumOutputChannels();*/
+    }
+#ifndef __NO_JACK__
+    QString getAssignedClientName()
+    {
+        if (mAudioInterface && mAudiointerfaceMode == JackTrip::JACK) {
+            return static_cast<JackAudioInterface*>(mAudioInterface)
+                ->getAssignedClientName();
+        } else {
+            return "";
+        }
     }
-    virtual void checkPeerSettings(int8_t* full_packet);
-    void increaseSequenceNumber()
-    { mPacketHeader->increaseSequenceNumber(); }
-    int getSequenceNumber() const
-    { return mPacketHeader->getSequenceNumber(); }
+#endif
+    virtual bool checkPeerSettings(int8_t* full_packet);
+    void increaseSequenceNumber() { mPacketHeader->increaseSequenceNumber(); }
+    int getSequenceNumber() const { return mPacketHeader->getSequenceNumber(); }
 
     uint64_t getPeerTimeStamp(int8_t* full_packet) const
-    { return mPacketHeader->getPeerTimeStamp(full_packet); }
+    {
+        return mPacketHeader->getPeerTimeStamp(full_packet);
+    }
 
     uint16_t getPeerSequenceNumber(int8_t* full_packet) const
-    { return mPacketHeader->getPeerSequenceNumber(full_packet); }
+    {
+        return mPacketHeader->getPeerSequenceNumber(full_packet);
+    }
 
     uint16_t getPeerBufferSize(int8_t* full_packet) const
-    { return mPacketHeader->getPeerBufferSize(full_packet); }
+    {
+        return mPacketHeader->getPeerBufferSize(full_packet);
+    }
 
     uint8_t getPeerSamplingRate(int8_t* full_packet) const
-    { return mPacketHeader->getPeerSamplingRate(full_packet); }
+    {
+        return mPacketHeader->getPeerSamplingRate(full_packet);
+    }
 
     uint8_t getPeerBitResolution(int8_t* full_packet) const
-    { return mPacketHeader->getPeerBitResolution(full_packet); }
+    {
+        return mPacketHeader->getPeerBitResolution(full_packet);
+    }
 
-    uint8_t  getPeerNumChannels(int8_t* full_packet) const
-    { return mPacketHeader->getPeerNumChannels(full_packet); }
+    uint8_t getPeerNumIncomingChannels(int8_t* full_packet) const
+    {
+        return mPacketHeader->getPeerNumIncomingChannels(full_packet);
+    }
 
-    uint8_t  getPeerConnectionMode(int8_t* full_packet) const
-    { return mPacketHeader->getPeerConnectionMode(full_packet); }
+    uint8_t getPeerNumOutgoingChannels(int8_t* full_packet) const
+    {
+        if (0 == mPacketHeader->getPeerNumOutgoingChannels(full_packet)) {
+            return mPacketHeader->getPeerNumIncomingChannels(full_packet);
+        } else {
+            return mPacketHeader->getPeerNumOutgoingChannels(full_packet);
+        }
+    }
 
     size_t getSizeInBytesPerChannel() const
-    { return mAudioInterface->getSizeInBytesPerChannel(); }
-    int getHeaderSizeInBytes() const
-    { return mPacketHeader->getHeaderSizeInBytes(); }
-    virtual int getTotalAudioPacketSizeInBytes() const
     {
-#ifdef WAIR // WAIR
+        return mAudioInterface->getSizeInBytesPerChannel();
+    }
+    int getHeaderSizeInBytes() const { return mPacketHeader->getHeaderSizeInBytes(); }
+    int getTotalAudioInputPacketSizeInBytes() const
+    {
+#ifdef WAIR  // WAIR
         if (mNumNetRevChans)
             return mAudioInterface->getSizeInBytesPerChannel() * mNumNetRevChans;
-        else // not wair
-#endif // endwhere
-            return mAudioInterface->getSizeInBytesPerChannel() * mNumChans;
+        else  // not wair
+#endif        // endwhere
+            return mAudioInterface->getSizeInBytesPerChannel() * mNumAudioChansIn;
+    }
+
+    int getTotalAudioOutputPacketSizeInBytes() const
+    {
+#ifdef WAIR  // WAIR
+        if (mNumNetRevChans)
+            return mAudioInterface->getSizeInBytesPerChannel() * mNumNetRevChans;
+        else  // not wair
+#endif        // endwhere
+            return mAudioInterface->getSizeInBytesPerChannel() * mNumAudioChansOut;
     }
     //@}
     //------------------------------------------------------------------------------------
 
-    void printTextTest() {std::cout << "=== JackTrip PRINT ===" << std::endl;}
-    void printTextTest2() {std::cout << "=== JackTrip PRINT2 ===" << std::endl;}
+    void printTextTest() { std::cout << "=== JackTrip PRINT ===" << std::endl; }
+    void printTextTest2() { std::cout << "=== JackTrip PRINT2 ===" << std::endl; }
 
     void setNetIssuesSimulation(double loss, double jitter, double delay_rel)
     {
-        mSimulatedLossRate = loss;
+        mSimulatedLossRate   = loss;
         mSimulatedJitterRate = jitter;
-        mSimulatedDelayRel = delay_rel;
+        mSimulatedDelayRel   = delay_rel;
+    }
+    void setBroadcast(int broadcast_queue) { mBroadcastQueueLength = broadcast_queue; }
+    void queueLengthChanged(int queueLength)
+    {
+        emit signalQueueLengthChanged(queueLength);
     }
-    void setBroadcast(int broadcast_queue) {mBroadcastQueueLength = broadcast_queue;}
-    void setUseRtUdpPriority(bool use) {mUseRtUdpPriority = use;}
+    void setUseRtUdpPriority(bool use) { mUseRtUdpPriority = use; }
 
-public slots:
+   public slots:
     /// \brief Slot to stop all the processes and threads
-    virtual void slotStopProcesses()
-    { this->stop(); }
-    virtual void slotStopProcessesDueToError(const QString &errorMessage)
-    { this->stop(errorMessage); }
+    virtual void slotStopProcesses() { this->stop(); }
+    virtual void slotStopProcessesDueToError(const QString& errorMessage)
+    {
+        this->stop(errorMessage);
+    }
 
     /** \brief This slot emits in turn the signal signalNoUdpPacketsForSeconds
-   * when UDP has waited for more than 30 seconds.
-   *
-   * It is used to remove the thread from the server.
-   */
+     * when UDP has waited for more than 30 seconds.
+     *
+     * It is used to remove the thread from the server.
+     */
     void slotUdpWaitingTooLongClientGoneProbably(int wait_msec)
     {
-        int wait_time = 10000; // msec
-        if ( !(wait_msec%wait_time) ) {
+        int wait_time = 10000;  // msec
+        if (!(wait_msec % wait_time)) {
             std::cerr << "UDP WAITED MORE THAN 10 seconds." << std::endl;
-            if (mStopOnTimeout) {
-                stop("No network data received for 10 seconds");
-            }
+            if (mStopOnTimeout) { stop("No network data received for 10 seconds"); }
             emit signalNoUdpPacketsForSeconds();
         }
     }
-    void slotUdpWaitingTooLong()
-    { emit signalUdpWaitingTooLong(); }
-    void slotPrintTest()
-    { std::cout << "=== TESTING ===" << std::endl; }
+    void slotUdpWaitingTooLong() { emit signalUdpWaitingTooLong(); }
+    void slotPrintTest() { std::cout << "=== TESTING ===" << std::endl; }
     void slotReceivedConnectionFromPeer()
-    { mReceivedConnection = true; emit signalReceivedConnectionFromPeer(); }
+    {
+        mReceivedConnection = true;
+        emit signalReceivedConnectionFromPeer();
+    }
     void onStatTimer();
-    
-private slots:
+
+   private slots:
     void receivedConnectionTCP();
     void receivedDataTCP();
+    void connectionSecured();
     void receivedDataUDP();
     void udpTimerTick();
     void tcpTimerTick();
 
-signals:
-    //void signalUdpTimeOut();
+   signals:
+    // void signalUdpTimeOut();
     /// \brief Signal emitted when all the processes and threads are stopped
     void signalProcessesStopped();
     /// \brief Signal emitted when no UDP Packets have been received for a while
     void signalNoUdpPacketsForSeconds();
     void signalTcpClientConnected();
-    void signalError(const QString &errorMessage);
+    void signalError(const QStringerrorMessage);
     void signalReceivedConnectionFromPeer();
     void signalUdpWaitingTooLong();
+    void signalQueueLengthChanged(int queueLength);
+    void signalAudioStarted();
 
-public:
-
+   public:
     /// \brief Set the AudioInteface object
     virtual void setupAudio(
-        #ifdef WAIRTOHUB // WAIR
-            int ID
-        #endif // endwhere
-            );
+#ifdef WAIRTOHUB  // WAIR
+        int ID
+#endif  // endwhere
+    );
     /// \brief Close the JackAudioInteface and disconnects it from JACK
     void closeAudio();
     /// \brief Set the DataProtocol objects
@@ -495,82 +588,96 @@ public:
     /// \brief Starts for the CLIENT mode
     void clientStart();
     /// \brief Starts for the SERVER mode
-    /// \param timout Set the server to timeout after 2 seconds if no client connections are received.
-    /// Usefull for the multithreaded server
-    /// \return 0 on success, -1 on error
+    /// \param timout Set the server to timeout after 2 seconds if no client connections
+    /// are received. Usefull for the multithreaded server \return 0 on success, -1 on
+    /// error
     int serverStart(bool timeout = false, int udpTimeout = gTimeOutMultiThreadedServer);
     /// \brief Stats for the Client to Ping Server
     /// \return -1 on error, 0 on success
     virtual int clientPingToServerStart();
-
-private:
-    //void bindReceiveSocket(QUdpSocket& UdpSocket, int bind_port,
-    //                       QHostAddress PeerHostAddress, int peer_port)
-    //throw(std::runtime_error);
-
-
-    jacktripModeT mJackTripMode; ///< JackTrip::jacktripModeT
-    dataProtocolT mDataProtocol; ///< Data Protocol Tipe
-    DataProtocol::packetHeaderTypeT mPacketHeaderType; ///< Packet Header Type
+    /// \brief Sets the client ID
+    ///
+    void setID(int ID) { mID = ID; }
+    /// \brief Gets the client ID
+    ///
+    int getID() { return mID; }
+
+   private:
+    int mID = 0;
+    jacktripModeT mJackTripMode;                        ///< JackTrip::jacktripModeT
+    dataProtocolT mDataProtocol;                        ///< Data Protocol Tipe
+    DataProtocol::packetHeaderTypeT mPacketHeaderType;  ///< Packet Header Type
     JackTrip::audiointerfaceModeT mAudiointerfaceMode;
 
-    int mNumChans; ///< Number of Channels (inputs = outputs)
-#ifdef WAIR // WAIR
-    int mNumNetRevChans; ///< Number of Network Audio Channels (net comb filters)
-#endif // endwhere
-    int mBufferQueueLength; ///< Audio Buffer from network queue length
+    int mNumAudioChansIn;    ///< Number of Audio Input Channels
+    int mNumAudioChansOut;   ///< Number of Audio Output Channels
+#ifdef WAIR                  // WAIR
+    int mNumNetRevChans;     ///< Number of Network Audio Channels (net comb filters)
+#endif                       // endwhere
+    int mBufferQueueLength;  ///< Audio Buffer from network queue length
     int mBufferStrategy;
     int mBroadcastQueueLength;
-    uint32_t mSampleRate; ///< Sample Rate
-    uint32_t mDeviceID; ///< RTAudio DeviceID
-    uint32_t mAudioBufferSize; ///< Audio buffer size to process on each callback
-    AudioInterface::audioBitResolutionT mAudioBitResolution; ///< Audio Bit Resolutions
+    uint32_t mSampleRate;                             ///< Sample Rate
+    uint32_t mDeviceID;                               ///< RTAudio DeviceID
+    std::string mInputDeviceName, mOutputDeviceName;  ///< RTAudio device names
+    uint32_t mAudioBufferSize;  ///< Audio buffer size to process on each callback
+    AudioInterface::audioBitResolutionT mAudioBitResolution;  ///< Audio Bit Resolutions
     bool mLoopBack;
-    QString mPeerAddress; ///< Peer Address to use in jacktripModeT::CLIENT Mode
+    QString mPeerAddress;  ///< Peer Address to use in jacktripModeT::CLIENT Mode
 
     /// Pointer to Abstract Type DataProtocol that sends packets
     DataProtocol* mDataProtocolSender;
     /// Pointer to Abstract Type DataProtocol that receives packets
     DataProtocol* mDataProtocolReceiver;
-    AudioInterface* mAudioInterface; ///< Interface to Jack Client
-    PacketHeader* mPacketHeader; ///< Pointer to Packet Header
-    underrunModeT mUnderRunMode; ///< underrunModeT Mode
-    bool mStopOnTimeout; ///< Stop on 10 second timeout
+    AudioInterface* mAudioInterface;  ///< Interface to Jack Client
+    PacketHeader* mPacketHeader;      ///< Pointer to Packet Header
+    underrunModeT mUnderRunMode;      ///< underrunModeT Mode
+    bool mStopOnTimeout;              ///< Stop on 10 second timeout
 
     /// Pointer for the Send RingBuffer
     RingBuffer* mSendRingBuffer;
     /// Pointer for the Receive RingBuffer
     RingBuffer* mReceiveRingBuffer;
 
-    int mReceiverBindPort; ///< Incoming (receiving) port for local machine
-    int mSenderPeerPort; ///< Incoming (receiving) port for peer machine
-    int mSenderBindPort; ///< Outgoing (sending) port for local machine
-    int mReceiverPeerPort; ///< Outgoing (sending) port for peer machine
+    int mReceiverBindPort;  ///< Incoming (receiving) port for local machine
+    int mSenderPeerPort;    ///< Incoming (receiving) port for peer machine
+    int mSenderBindPort;    ///< Outgoing (sending) port for local machine
+    int mReceiverPeerPort;  ///< Outgoing (sending) port for peer machine
     int mTcpServerPort;
 
-    unsigned int mRedundancy; ///< Redundancy factor in network data
-    QString mJackClientName; ///< JackAudio Client Name
-    QString mRemoteClientName; ///< Remote JackAudio Client Name for hub client mode
+    bool mUseAuth;
+    QString mUsername;
+    QString mPassword;
+
+    unsigned int mRedundancy;   ///< Redundancy factor in network data
+    QString mJackClientName;    ///< JackAudio Client Name
+    QString mRemoteClientName;  ///< Remote JackAudio Client Name for hub client mode
+
+    // JackTrip::connectionModeT mConnectionMode;  ///< Connection Mode
+    JackTrip::hubConnectionModeT
+        mHubConnectionModeT;  ///< Hub Server Jack Audio Patch Connection Mode
 
-    JackTrip::connectionModeT mConnectionMode; ///< Connection Mode
-    JackTrip::hubConnectionModeT mHubConnectionModeT; ///< Hub Server Jack Audio Patch Connection Mode
+    QVector<ProcessPlugin*>
+        mProcessPluginsFromNetwork;  ///< Vector of ProcessPlugin<EM>s</EM>
+    QVector<ProcessPlugin*>
+        mProcessPluginsToNetwork;  ///< Vector of ProcessPlugin<EM>s</EM>
 
-    QVector<ProcessPlugin*> mProcessPluginsFromNetwork; ///< Vector of ProcessPlugin<EM>s</EM>
-    QVector<ProcessPlugin*> mProcessPluginsToNetwork; ///< Vector of ProcessPlugin<EM>s</EM>
-    
     QTimer mTimeoutTimer;
     int mSleepTime;
     int mElapsedTime;
     int mEndTime;
-    QTcpSocket mTcpClient;
+    QSslSocket mTcpClient;
     QUdpSocket mUdpSockTemp;
+    QMutex mTimerMutex;
+    bool mAwaitingUdp;
+    bool mAwaitingTcp;
 
-    volatile bool mReceivedConnection; ///< Bool of received connection from peer
+    volatile bool mReceivedConnection;  ///< Bool of received connection from peer
     volatile bool mTcpConnectionError;
     volatile bool mStopped;
     volatile bool mHasShutdown;
 
-    bool mConnectDefaultAudioPorts; ///< Connect or not default audio ports
+    bool mConnectDefaultAudioPorts;  ///< Connect or not default audio ports
     QSharedPointer<std::ofstream> mIOStatStream;
     int mIOStatTimeout;
     std::ostream mIOStatLogStream;
@@ -579,7 +686,7 @@ private:
     double mSimulatedDelayRel;
     bool mUseRtUdpPriority;
 
-    AudioTester* mAudioTesterP;
+    QSharedPointer<AudioTester> mAudioTesterP;
 };
 
 #endif
diff --git a/src/JackTripThread.cpp b/src/JackTripThread.cpp
deleted file mode 100644 (file)
index bcaeaf0..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-//*****************************************************************
-/*
-  JackTrip: A System for High-Quality Audio Network Performance
-  over the Internet
-
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
-  SoundWIRE group at CCRMA, Stanford University.
-
-  Permission is hereby granted, free of charge, to any person
-  obtaining a copy of this software and associated documentation
-  files (the "Software"), to deal in the Software without
-  restriction, including without limitation the rights to use,
-  copy, modify, merge, publish, distribute, sublicense, and/or sell
-  copies of the Software, and to permit persons to whom the
-  Software is furnished to do so, subject to the following
-  conditions:
-
-  The above copyright notice and this permission notice shall be
-  included in all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-  OTHER DEALINGS IN THE SOFTWARE.
-*/
-//*****************************************************************
-
-/**
- * \file JackTripThread.cpp
- * \author Juan-Pablo Caceres
- * \date September 2008
- */
-
-
-#include "JackTripThread.h"
-#include "NetKS.h"
-
-#include <iostream>
-#include <cstdlib>
-
-using std::cout; using std::endl;
-
-
-//*******************************************************************************
-void JackTripThread::run()
-{
-    JackTrip jacktrip(mJackTripMode);
-    jacktrip.setAllPorts(mPortNum);
-
-    if ( mJackTripMode == JackTrip::CLIENT )
-    {
-        jacktrip.setPeerAddress(mPeerAddress);
-    }
-
-    NetKS netks;
-    jacktrip.appendProcessPluginFromNetwork(&netks);
-    //netks.play();
-
-
-    //QThread::sleep(1);
-    //jacktrip.start();
-    //netks.play();
-    //jacktrip.wait();
-
-
-    cout << "******** AFTER JACKTRIPTHREAD START **************" << endl;
-    //QThread::sleep(9999999);
-
-
-
-    /*
-  jack_client_t* mClient;
-  const char* client_name = "JackThread";
-  const char* server_name = NULL;
-  jack_options_t options = JackNoStartServer;
-  jack_status_t status;
-
-  mClient = jack_client_open (client_name, options, &status, server_name);
-
-  if (mClient == NULL) {
-    fprintf (stderr, "jack_client_open() failed, "
-             "status = 0x%2.0x\n", status);
-    if (status & JackServerFailed) {
-      fprintf (stderr, "Unable to connect to JACK server\n");
-    }
-    std::exit(1);
-  }
-  if (status & JackServerStarted) {
-    fprintf (stderr, "JACK server started\n");
-  }
-  if (status & JackNameNotUnique) {
-    client_name = jack_get_client_name(mClient);
-    fprintf (stderr, "unique name `%s' assigned\n", client_name);
-  }
-  */
-
-
-}
diff --git a/src/JackTripThread.h b/src/JackTripThread.h
deleted file mode 100644 (file)
index fe7e6d7..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-//*****************************************************************
-/*
-  JackTrip: A System for High-Quality Audio Network Performance
-  over the Internet
-
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
-  SoundWIRE group at CCRMA, Stanford University.
-
-  Permission is hereby granted, free of charge, to any person
-  obtaining a copy of this software and associated documentation
-  files (the "Software"), to deal in the Software without
-  restriction, including without limitation the rights to use,
-  copy, modify, merge, publish, distribute, sublicense, and/or sell
-  copies of the Software, and to permit persons to whom the
-  Software is furnished to do so, subject to the following
-  conditions:
-
-  The above copyright notice and this permission notice shall be
-  included in all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-  OTHER DEALINGS IN THE SOFTWARE.
-*/
-//*****************************************************************
-
-/**
- * \file JackTripThread.h
- * \author Juan-Pablo Caceres
- * \date September 2008
- */
-
-#ifndef __JACKTRIPTHREAD_H__
-#define __JACKTRIPTHREAD_H__
-
-#include <QThread>
-
-#include "JackTrip.h"
-
-/** \brief Test class that runs JackTrip inside a thread
- */
-class JackTripThread : public QThread
-{
-public:
-    JackTripThread(JackTrip::jacktripModeT JacktripMode) : mJackTripMode(JacktripMode) {}
-    virtual ~JackTripThread(){}
-    void run();
-
-    void setPort(int port_num) { mPortNum = port_num; }
-    void setPeerAddress(const char* PeerHostOrIP) { mPeerAddress = PeerHostOrIP; }
-
-private:
-    JackTrip::jacktripModeT mJackTripMode; ///< JackTrip::jacktripModeT
-    int mPortNum;
-    const char* mPeerAddress; ///< Peer Address to use in jacktripModeT::CLIENT Mode
-};
-
-
-#endif //__JACKTRIPTHREAD_H__
index 995c4a262fad4cecd13d0f71c32e0cb2d11e04e3..560eba2120873c372592921b4f4ddc46f5cdd49d 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
  * \date September 2008
  */
 
-#include <iostream>
-#include <unistd.h>
+#include "JackTripWorker.h"
 
-#include <QTimer>
 #include <QMutexLocker>
+#include <QTimer>
 #include <QWaitCondition>
+#include <iostream>
+#include <limits>
 
-#include "JackTripWorker.h"
 #include "JackTrip.h"
 #include "UdpHubListener.h"
 //#include "NetKS.h"
 #include "LoopBack.h"
 #include "Settings.h"
-#ifdef WAIR // wair
+#ifdef WAIR  // wair
 #include "dcblock2gain.dsp.h"
-#endif // endwhere
-#ifdef __JAMTEST__
-#include "JamTest.h"
-#endif
-
-using std::cout; using std::endl;
-
-//*******************************************************************************
-JackTripWorker::JackTripWorker(UdpHubListener* udphublistener, int BufferQueueLength, JackTrip::underrunModeT UnderRunMode, QString clientName) :
-    mUdpHubListener(udphublistener),
-    m_connectDefaultAudioPorts(false),
-    mBufferQueueLength(BufferQueueLength),
-    mUnderRunMode(UnderRunMode),
-    mClientName(clientName),
-    mSpawning(false),
-    mID(0),
-    mNumChans(1),
-    mIOStatTimeout(0)
-  #ifdef WAIR // wair
-  ,mNumNetRevChans(0),
-    mWAIR(false)
-  #endif // endwhere
-{
-    setAutoDelete(false); // stick around after calling run()
-    //mNetks = new NetKS;
-    //mNetks->play();
-    mBufferStrategy = 1;
-    mBroadcastQueue = 0;
-    mSimulatedLossRate = 0.0;
-    mSimulatedJitterRate = 0.0;
-    mSimulatedDelayRel = 0.0;
-    mUseRtUdpPriority = false;
-}
+#endif  // endwhere
 
+using std::cout;
+using std::endl;
 
 //*******************************************************************************
-JackTripWorker::~JackTripWorker()
+JackTripWorker::JackTripWorker(UdpHubListener* udphublistener, int BufferQueueLength,
+                               JackTrip::underrunModeT UnderRunMode, QString clientName)
+    : mAppendThreadID(false)
+    , mSleepTime(100)
+    , mUdpHubListener(udphublistener)
+    , mBufferQueueLength(BufferQueueLength)
+    , mUnderRunMode(UnderRunMode)
+    , mClientName(clientName)
 {
-    //delete mUdpHubListener;
+    // mNetks = new NetKS;
+    // mNetks->play();
+    connect(&mUdpSockTemp, &QUdpSocket::readyRead, this,
+            &JackTripWorker::receivedDataUDP);
 }
 
-
 //*******************************************************************************
-void JackTripWorker::setJackTrip(int id,
-                                 QString client_address,
-                                 uint16_t server_port,
-                                 uint16_t client_port,
-                                 int num_channels,
-                                 bool connectDefaultAudioPorts)
+void JackTripWorker::setJackTrip(int id, QString client_address, uint16_t server_port,
+                                 uint16_t client_port, bool connectDefaultAudioPorts)
 {
-    { //Start Spawning, so lock mSpawning
-        QMutexLocker locker(&mMutex);
-        mSpawning = true;
+    QMutexLocker locker(&mMutex);
+    mUdpSockTemp.close();
+    if (mRunning) {
+        mJackTrip->slotStopProcesses();
+#ifndef __NO_JACK__
+        if (mPatched) {
+            mUdpHubListener->unregisterClientWithPatcher(mAssignedClientName);
+            mPatched = false;
+        }
+#endif
+        mRunning = false;
     }
+    // Set as spawning from this point on.
+    mSpawning = true;
+
     mID = id;
     // Set the jacktrip address and ports
-    //mClientAddress.setAddress(client_address);
-    mClientAddress = client_address;
-    mServerPort = server_port;
-    mClientPort = client_port;
-    mNumChans = num_channels;
+    mClientAddress             = client_address;
+    mServerPort                = server_port;
+    mClientPort                = client_port;
     m_connectDefaultAudioPorts = connectDefaultAudioPorts;
-}
+    mAssignedClientName        = "";
 
+    // Create and setup JackTrip Object
+    // JackTrip jacktrip(JackTrip::SERVER, JackTrip::UDP, mNumChans, 2);
+    if (gVerboseFlag) cout << "---> JackTripWorker: Creating jacktrip objects..." << endl;
 
-//*******************************************************************************
-void JackTripWorker::run()
-{
-    /* NOTE: This is the message that qt prints when an exception is thrown:
-    'Qt Concurrent has caught an exception thrown from a worker thread.
-    This is not supported, exceptions thrown in worker threads must be
-    caught before control returns to Qt Concurrent.'*/
-
-    { QMutexLocker locker(&mMutex); mSpawning = true; }
-
-    //QHostAddress ClientAddress;
-
-    // Try catching any exceptions that come from JackTrip
-    try
-    {
-        // Local event loop. this is necesary because QRunnables don't have their own as QThreads
-        QEventLoop event_loop;
-
-        // Create and setup JackTrip Object
-        //JackTrip jacktrip(JackTrip::SERVER, JackTrip::UDP, mNumChans, 2);
-        if (gVerboseFlag) cout << "---> JackTripWorker: Creating jacktrip objects..." << endl;
-
-#ifdef WAIR // WAIR
-        // forces    BufferQueueLength to 2
-        // need to parse numNetChans from incoming header
-        // but force to 16 for now
+#ifdef WAIR  // WAIR
+             // forces    BufferQueueLength to 2
+             // need to parse numNetChans from incoming header
+             // but force to 16 for now
 #define FORCEBUFFERQ 2
-        if (mUdpHubListener->isWAIR()) { // invoked with -Sw
-            mWAIR = true;
-            mNumNetRevChans = NUMNETREVCHANSbecauseNOTINRECEIVEDheader;
-        } else {};
-#endif // endwhere
+    if (mUdpHubListener->isWAIR()) {  // invoked with -Sw
+        mWAIR           = true;
+        mNumNetRevChans = NUMNETREVCHANSbecauseNOTINRECEIVEDheader;
+    } else {
+    };
+#endif  // endwhere
 
 #ifndef __JAMTEST__
-#ifdef WAIR // WAIR
-        //        bool tmp = mJTWorkers->at(id)->isWAIR();
-        //        qDebug() << "is WAIR?" <<  tmp ;
-        qDebug() << "mNumNetRevChans" <<  mNumNetRevChans ;
-
-        JackTrip jacktrip(JackTrip::SERVERPINGSERVER, JackTrip::UDP, mNumChans,
-                          mNumNetRevChans, FORCEBUFFERQ);
-        JackTrip * mJackTrip = &jacktrip;
-#else // endwhere
-        JackTrip jacktrip(JackTrip::SERVERPINGSERVER, JackTrip::UDP, mNumChans, mBufferQueueLength);
-#endif // not wair
-
-#ifdef WAIR // WAIR
-        // Add Plugins
-        if ( mWAIR ) {
-            cout << "Running in WAIR Mode..." << endl;
-            cout << gPrintSeparator << std::endl;
-            switch ( mNumNetRevChans )
-            {
-            case 16 : // freeverb
-                mJackTrip->appendProcessPluginFromNetwork(new dcblock2gain(mNumChans)); // plugin slot 0
-                ///////////////
-                //            mJackTrip->appendProcessPlugin(new comb16server(mNumNetChans));
-                // -S LAIR no AP  mJackTrip->appendProcessPlugin(new AP8(mNumChans));
-                break;
-            default:
-                throw std::invalid_argument("Settings: mNumNetChans doesn't correspond to Faust plugin");
-                break;
-            }
+#ifdef WAIR  // WAIR
+    //        bool tmp = mJTWorkers->at(id)->isWAIR();
+    //        qDebug() << "is WAIR?" <<  tmp ;
+    qDebug() << "mNumNetRevChans" << mNumNetRevChans;
+
+    mJackTrip.reset(new JackTrip(JackTrip::SERVERPINGSERVER, JackTrip::UDP, 1, 1,
+                                 mNumNetRevChans, FORCEBUFFERQ));
+    // Add Plugins
+    if (mWAIR) {
+        cout << "Running in WAIR Mode..." << endl;
+        cout << gPrintSeparator << std::endl;
+        switch (mNumNetRevChans) {
+        case 16:  // freeverb
+            mJackTrip->appendProcessPluginFromNetwork(
+                new dcblock2gain(1));  // plugin slot 0
+            ///////////////
+            //            mJackTrip->appendProcessPlugin(new comb16server(mNumNetChans));
+            // -S LAIR no AP  mJackTrip->appendProcessPlugin(new AP8(mNumChans));
+            break;
+        default:
+            throw std::invalid_argument(
+                "Settings: mNumNetChans doesn't correspond to Faust plugin");
+            break;
         }
-#endif // endwhere
-#endif // ifndef __JAMTEST__
+    }
+#else   // endwhere
+    mJackTrip.reset(new JackTrip(JackTrip::SERVERPINGSERVER, JackTrip::UDP, 1, 1,
+                                 mBufferQueueLength));
+#endif  // not wair
+#endif  // ifndef __JAMTEST__
 
 #ifdef __JAMTEST__
-        JamTest jacktrip(JackTrip::SERVERPINGSERVER); // ########### JamTest #################
-        //JackTrip jacktrip(JackTrip::SERVERPINGSERVER, JackTrip::UDP, mNumChans, 2);
+    mJackTrip.reset(new JamTest(
+        JackTrip::SERVERPINGSERVER));  // ########### JamTest #################
+    // JackTrip jacktrip(JackTrip::SERVERPINGSERVER, JackTrip::UDP, mNumChans, 2);
 #endif
+}
 
-        jacktrip.setConnectDefaultAudioPorts(m_connectDefaultAudioPorts);
-
-        // Set our underrun mode
-        jacktrip.setUnderRunMode(mUnderRunMode);
-        if (mIOStatTimeout > 0) {
-            jacktrip.setIOStatTimeout(mIOStatTimeout);
-            jacktrip.setIOStatStream(mIOStatStream);
-        }
-        
-        if (!mClientName.isEmpty()) {
-            jacktrip.setClientName(mClientName);
-        }
+//*******************************************************************************
+void JackTripWorker::start()
+{
+    QMutexLocker lock(&mMutex);
+    if (!mSpawning) {
+        // Something else has aborted the connection.
+        return;
+    }
 
-        // Connect signals and slots
-        // -------------------------
-        if (gVerboseFlag) cout << "---> JackTripWorker: Connecting signals and slots..." << endl;
-        // Connection to terminate JackTrip when packets haven't arrive for
-        // a certain amount of time
-        QObject::connect(&jacktrip, SIGNAL(signalNoUdpPacketsForSeconds()),
-                         &jacktrip, SLOT(slotStopProcesses()), Qt::QueuedConnection);
-        // Connection to terminate the local eventloop when jacktrip is done
-        QObject::connect(&jacktrip, SIGNAL(signalProcessesStopped()),
-                         &event_loop, SLOT(quit()), Qt::QueuedConnection);
-        QObject::connect(&jacktrip, &JackTrip::signalError, &event_loop, &QEventLoop::quit, Qt::QueuedConnection);
-        QObject::connect(this, SIGNAL(signalRemoveThread()),
-                         &jacktrip, SLOT(slotStopProcesses()), Qt::QueuedConnection);
-
-        //ClientAddress.setAddress(mClientAddress);
-        // If I don't type this line, I get a bus error in the next line.
-        // I still haven't figure out why
-        //ClientAddress.toString().toLatin1().constData();
-        //jacktrip.setPeerAddress(ClientAddress.toString().toLatin1().constData());
-        jacktrip.setPeerAddress(mClientAddress);
-        jacktrip.setBindPorts(mServerPort);
-        //jacktrip.setPeerPorts(mClientPort);
-        jacktrip.setBufferStrategy(mBufferStrategy);
-        jacktrip.setNetIssuesSimulation(mSimulatedLossRate,
-            mSimulatedJitterRate, mSimulatedDelayRel);
-        jacktrip.setBroadcast(mBroadcastQueue);
-        jacktrip.setUseRtUdpPriority(mUseRtUdpPriority);
-
-        if (gVerboseFlag) cout << "---> JackTripWorker: setJackTripFromClientHeader..." << endl;
-        int PeerConnectionMode = setJackTripFromClientHeader(jacktrip);
-        if ( PeerConnectionMode == -1 ) {
-            mUdpHubListener->releaseThread(mID);
-            { QMutexLocker locker(&mMutex); mSpawning = false; }
-            return;
-        }
+    mJackTrip->setConnectDefaultAudioPorts(m_connectDefaultAudioPorts);
 
-        // Start Threads and event loop
-        if (gVerboseFlag) cout << "---> JackTripWorker: startProcess..." << endl;
-        jacktrip.startProcess(
-            #ifdef WAIRTOHUB // wair
-                    mID
-            #endif // endwhere
-                    );
-        // if (gVerboseFlag) cout << "---> JackTripWorker: start..." << endl;
-        // jacktrip.start(); // ########### JamTest Only #################
+    // Set our underrun mode
+    mJackTrip->setUnderRunMode(mUnderRunMode);
+    if (mIOStatTimeout > 0) {
+        mJackTrip->setIOStatTimeout(mIOStatTimeout);
+        mJackTrip->setIOStatStream(mIOStatStream);
+    }
 
-        // Thread is already spawning, so release the lock
-        { QMutexLocker locker(&mMutex); mSpawning = false; }
+    if (!mClientName.isEmpty()) { mJackTrip->setClientName(mClientName); }
+
+    // ClientAddress.setAddress(mClientAddress);
+    // If I don't type this line, I get a bus error in the next line.
+    // I still haven't figure out why
+    // ClientAddress.toString().toLatin1().constData();
+    // jacktrip.setPeerAddress(ClientAddress.toString().toLatin1().constData());
+    if (mAppendThreadID) { mJackTrip->setID(mID + 1); }
+    mJackTrip->setPeerAddress(mClientAddress);
+    mJackTrip->setBindPorts(mServerPort);
+    // jacktrip.setPeerPorts(mClientPort);
+    mJackTrip->setBufferStrategy(mBufferStrategy);
+    mJackTrip->setNetIssuesSimulation(mSimulatedLossRate, mSimulatedJitterRate,
+                                      mSimulatedDelayRel);
+    mJackTrip->setBroadcast(mBroadcastQueue);
+    mJackTrip->setUseRtUdpPriority(mUseRtUdpPriority);
+
+    mTimeoutTimer.setInterval(mSleepTime);
+    connect(&mTimeoutTimer, &QTimer::timeout, this, &JackTripWorker::udpTimerTick);
+    mElapsedTime = 0;
+    mTimeoutTimer.start();
+    if (gVerboseFlag)
+        cout << "---> JackTripWorker: setJackTripFromClientHeader..." << endl;
+    if (!mUdpSockTemp.bind(QHostAddress::Any, mServerPort,
+                           QUdpSocket::DefaultForPlatform)) {
+        std::cerr
+            << "in JackTripWorker: Could not bind UDP socket. It may already be bound."
+            << endl;
+        throw std::runtime_error("Could not bind UDP socket. It may already be bound.");
+    }
+}
 
-        event_loop.exec(); // Excecution will block here until exit() the QEventLoop
-        //--------------------------------------------------------------------------
-        
-        { QMutexLocker locker(&mMutex); mSpawning = true; }
+//*******************************************************************************
+void JackTripWorker::stopThread()
+{
+    QMutexLocker locker(&mMutex);
+    if (mRunning) {
+        mRunning = false;
+        mJackTrip->slotStopProcesses();
+#ifndef __NO_JACK__
+        if (mPatched) {
+            mUdpHubListener->unregisterClientWithPatcher(mAssignedClientName);
+            mPatched = false;
+        }
+#endif
+    } else if (mSpawning) {
+        mSpawning = false;
+        mUdpSockTemp.close();
+        mTimeoutTimer.stop();
+    }
+}
 
-        // wait for jacktrip to be done before exiting the Worker Thread
-        //jacktrip.wait();
+void JackTripWorker::receivedDataUDP()
+{
+    QMutexLocker lock(&mMutex);
 
-    }
-    catch ( const std::exception & e )
-    {
-        std::cerr << "Couldn't send thread to the Pool" << endl;
-        std::cerr << e.what() << endl;
-        std::cerr << gPrintSeparator << endl;
-        mUdpHubListener->releaseThread(mID);
-        { QMutexLocker locker(&mMutex); mSpawning = false; }
+    if (!mSpawning || mUdpSockTemp.state() != QAbstractSocket::BoundState) {
+        // Check if something has interrupted the process.
         return;
     }
+    mTimeoutTimer.stop();
+
+    // Set our jacktrip parameters from the received header data.
+    quint16 port;
+    int packet_size     = mUdpSockTemp.pendingDatagramSize();
+    int8_t* full_packet = new int8_t[packet_size];
+    mUdpSockTemp.readDatagram(reinterpret_cast<char*>(full_packet), packet_size, nullptr,
+                              &port);
+    mUdpSockTemp.close();  // close the socket
+
+    // Alert the hub listener of the actual client port for incoming packets.
+    // This will remove any old worker objects, and will set the client port member
+    // variable on this object.
+    mUdpHubListener->releaseDuplicateThreads(this, port);
+
+    int PeerBufferSize          = mJackTrip->getPeerBufferSize(full_packet);
+    int PeerSamplingRate        = mJackTrip->getPeerSamplingRate(full_packet);
+    int PeerBitResolution       = mJackTrip->getPeerBitResolution(full_packet);
+    int PeerNumIncomingChannels = mJackTrip->getPeerNumIncomingChannels(full_packet);
+    int PeerNumOutgoingChannels = mJackTrip->getPeerNumOutgoingChannels(full_packet);
+    delete[] full_packet;
+
+    if (gVerboseFlag) {
+        cout << "JackTripWorker: getPeerBufferSize       = " << PeerBufferSize << "\n"
+             << "JackTripWorker: getPeerSamplingRate     = " << PeerSamplingRate << "\n"
+             << "JackTripWorker: getPeerBitResolution    = " << PeerBitResolution << "\n"
+             << "JackTripWorker: PeerNumIncomingChannels = " << PeerNumIncomingChannels
+             << "\n"
+             << "JackTripWorker: PeerNumOutgoingChannels = " << PeerNumOutgoingChannels
+             << "\n";
+    }
 
-    {
-        QMutexLocker locker(&mMutex);
-        mUdpHubListener->releaseThread(mID);
+    // The header field for NumOutgoingChannels was used for the ConnectionMode.
+    // Only the first Mode was used (NORMAL == 0). If this field is set to 0, we
+    // can assume the peer is using an old version, and the last field doesn't reflect the
+    // number of Outgoing Channels.
+    // The maximum of this field will be used as 0.
+    if (JackTrip::NORMAL == PeerNumOutgoingChannels) {
+        mJackTrip->setNumInputChannels(PeerNumIncomingChannels);
+        mJackTrip->setNumOutputChannels(PeerNumIncomingChannels);
+    } else if (std::numeric_limits<uint8_t>::max() == PeerNumOutgoingChannels) {
+        mJackTrip->setNumInputChannels(PeerNumIncomingChannels);
+        mJackTrip->setNumOutputChannels(0);
+    } else {
+        mJackTrip->setNumInputChannels(PeerNumIncomingChannels);
+        mJackTrip->setNumOutputChannels(PeerNumOutgoingChannels);
     }
 
-    cout << "JackTrip ID = " << mID << " released from the THREAD POOL" << endl;
-    cout << gPrintSeparator << endl;
-    {
-        // Thread is already spawning, so release the lock
-        QMutexLocker locker(&mMutex);
+    if (PeerNumOutgoingChannels == -1) {
+        // Shut it down
         mSpawning = false;
+        mUdpHubListener->releaseThread(mID);
     }
-}
 
+    // Connect signals and slots
+    // -------------------------
+    if (gVerboseFlag)
+        cout << "---> JackTripWorker: Connecting signals and slots..." << endl;
+    // Connection to terminate JackTrip when packets haven't arrive for
+    // a certain amount of time
+    connect(mJackTrip.data(), &JackTrip::signalNoUdpPacketsForSeconds, mJackTrip.data(),
+            &JackTrip::slotStopProcesses, Qt::QueuedConnection);
+    connect(mJackTrip.data(), &JackTrip::signalProcessesStopped, this,
+            &JackTripWorker::jacktripStopped, Qt::QueuedConnection);
+    connect(mJackTrip.data(), &JackTrip::signalError, this,
+            &JackTripWorker::jacktripStopped, Qt::QueuedConnection);
+#ifndef __NO_JACK__
+    connect(mJackTrip.data(), &JackTrip::signalAudioStarted, this,
+            &JackTripWorker::alertPatcher, Qt::QueuedConnection);
+#endif
+    connect(this, &JackTripWorker::signalRemoveThread, mJackTrip.data(),
+            &JackTrip::slotStopProcesses, Qt::QueuedConnection);
+
+    if (gVerboseFlag) cout << "---> JackTripWorker: startProcess..." << endl;
+    mJackTrip->startProcess(
+#ifdef WAIRTOHUB  // wair
+        mID
+#endif  // endwhere
+    );
+    mRunning  = true;
+    mSpawning = false;
+    // if (gVerboseFlag) cout << "---> JackTripWorker: start..." << endl;
+    // jacktrip.start(); // ########### JamTest Only #################
+}
 
-//*******************************************************************************
-// returns -1 on error
-int JackTripWorker::setJackTripFromClientHeader(JackTrip& jacktrip)
+void JackTripWorker::udpTimerTick()
 {
-    //QHostAddress peerHostAddress;
-    //uint16_t peer_port;
-    QUdpSocket UdpSockTemp;// Create socket to wait for client
-
-    // Bind the socket
-    if ( !UdpSockTemp.bind(QHostAddress::Any, mServerPort,
-                           QUdpSocket::DefaultForPlatform) )
-    {
-        std::cerr << "in JackTripWorker: Could not bind UDP socket. It may be already binded." << endl;
-        throw std::runtime_error("Could not bind UDP socket. It may be already binded.");
-    }
-
-    // Listen to client
-    QWaitCondition sleep; // time is in milliseconds
-    QMutex mutex;
-    int sleepTime = 100; // ms
-    int udpTimeout = gTimeOutMultiThreadedServer; // gTimeOutMultiThreadedServer mseconds
-    int elapsedTime = 0;
-    {
-        QMutexLocker lock(&mutex);
-        while ( (!UdpSockTemp.hasPendingDatagrams()) && (elapsedTime <= udpTimeout) ) {
-            sleep.wait(&mutex,sleepTime);
-            elapsedTime += sleepTime;
-            if (gVerboseFlag) cout << "---------> ELAPSED TIME: " << elapsedTime << endl;
-        }
+    QMutexLocker lock(&mMutex);
+    if (!mSpawning) {
+        mTimeoutTimer.stop();
+        return;
     }
-    // Check if we time out or not
-    if (!UdpSockTemp.hasPendingDatagrams()) {
+    mElapsedTime += mSleepTime;
+    if (gVerboseFlag) cout << "---------> ELAPSED TIME: " << mElapsedTime << endl;
+    // Check if we've timed out.
+    if (gTimeOutMultiThreadedServer > 0 && mElapsedTime >= gTimeOutMultiThreadedServer) {
         std::cerr << "--->JackTripWorker: is not receiving Datagrams (timeout)" << endl;
-        UdpSockTemp.close();
-        return -1;
+        mTimeoutTimer.stop();
+        mUdpSockTemp.close();
+        mSpawning = false;
+        mUdpHubListener->releaseThread(mID);
     }
-    int packet_size = UdpSockTemp.pendingDatagramSize();
-    char packet[packet_size];
-    UdpSockTemp.readDatagram(packet, packet_size);
-    UdpSockTemp.close(); // close the socket
-    int8_t* full_packet = reinterpret_cast<int8_t*>(packet);
-
-    int PeerBufferSize = jacktrip.getPeerBufferSize(full_packet);
-    int PeerSamplingRate = jacktrip.getPeerSamplingRate(full_packet);
-    int PeerBitResolution = jacktrip.getPeerBitResolution(full_packet);
-    int PeerNumChannels = jacktrip.getPeerNumChannels(full_packet);
-    int PeerConnectionMode = jacktrip.getPeerConnectionMode(full_packet);
-
-    if (gVerboseFlag) cout << "--->JackTripWorker: getPeerBufferSize = " << PeerBufferSize << endl;
-    if (gVerboseFlag) cout << "--->JackTripWorker: getPeerSamplingRate = " << PeerSamplingRate << endl;
-    if (gVerboseFlag) cout << "--->JackTripWorker: getPeerBitResolution = " << PeerBitResolution << endl;
-    cout << "--->JackTripWorker: PeerNumChannels = " << PeerNumChannels << endl;
-    if (gVerboseFlag) cout << "--->JackTripWorker: getPeerConnectionMode = " << PeerConnectionMode << endl;
-
-    jacktrip.setNumChannels(PeerNumChannels);
-    return PeerConnectionMode;
 }
 
-
-//*******************************************************************************
-bool JackTripWorker::isSpawning()
+void JackTripWorker::jacktripStopped()
 {
-    QMutexLocker locker(&mMutex);
-    return mSpawning;
+    QMutexLocker lock(&mMutex);
+    if (mSpawning || !mRunning) {
+        // This has already been taken care of elsewhere.
+        return;
+    }
+    mRunning = false;
+#ifndef __NO_JACK__
+    if (mPatched) {
+        mUdpHubListener->unregisterClientWithPatcher(mAssignedClientName);
+        mPatched = false;
+    }
+#endif
+    mUdpHubListener->releaseThread(mID);
 }
 
-
-//*******************************************************************************
-void JackTripWorker::stopThread()
+void JackTripWorker::alertPatcher()
 {
-    QMutexLocker locker(&mMutex);
-    emit signalRemoveThread();
+#ifndef __NO_JACK__
+    QMutexLocker lock(&mMutex);
+    if (mRunning) {
+        mAssignedClientName = mJackTrip->getAssignedClientName();
+        mUdpHubListener->registerClientWithPatcher(mAssignedClientName);
+        mPatched = true;
+    }
+#endif
 }
index 98524cf72bb84768aea5a40a47bfaa40b4c03215..bc6665fab5cfa8ab91a4265682e6efd4cded583a 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
 #ifndef __JACKTRIPWORKER_H__
 #define __JACKTRIPWORKER_H__
 
-#include <iostream>
-
-#include <QThreadPool>
-#include <QObject>
-#include <QEventLoop>
 #include <QHostAddress>
 #include <QMutex>
+#include <QObject>
+#include <QUdpSocket>
+#include <iostream>
 
 #include "JackTrip.h"
 #include "jacktrip_globals.h"
+#ifdef __JAMTEST__
+#include "JamTest.h"
+#endif
 
-//class JackTrip; // forward declaration
-class UdpHubListener; // forward declaration
-
+// class JackTrip; // forward declaration
+class UdpHubListener;  // forward declaration
 
-/** \brief Prototype of the worker class that will be cloned through sending threads to the
- * Thread Pool
+/** \brief Prototype of the worker class that will be cloned through sending threads to
+ * the Thread Pool
  *
  * This class can be send to the ThreadPool using the start() method. Each time
  * it is sent, it'll became "independent" of the prototype, which means
@@ -62,101 +62,130 @@ class UdpHubListener; // forward declaration
  * another thread into the pool. setAutoDelete must be set to false
  * in order for this to work.
  */
-// Note that it is not possible to start run() as an event loop. That has to be implemented
-// inside a QThread
-class JackTripWorker : public QObject, public QRunnable
+// Note that it is not possible to start run() as an event loop. That has to be
+// implemented inside a QThread
+class JackTripWorker : public QObject
 {
-    Q_OBJECT; // QRunnable is not a QObject, so I have to inherit from QObject as well
+    Q_OBJECT;
 
-public:
+   public:
     /// \brief The class constructor
-    JackTripWorker(UdpHubListener* udphublistener, int BufferQueueLength = gDefaultQueueLength, JackTrip::underrunModeT UnderRunMode = JackTrip::WAVETABLE, QString clientName = "");
+    JackTripWorker(UdpHubListener* udphublistener,
+                   int BufferQueueLength                = gDefaultQueueLength,
+                   JackTrip::underrunModeT UnderRunMode = JackTrip::WAVETABLE,
+                   QString clientName                   = "");
     /// \brief The class destructor
-    virtual ~JackTripWorker();
+    ~JackTripWorker() = default;
 
-    /// \brief Implements the Thread Loop.
-    /// To start the thread, call start() ( DO NOT CALL run() ).
-    void run();
+    /// \brief Starts the jacktrip process
+    void start();
     /// \brief Check if the Thread is Spawning
     /// \return true is it is spawning, false if it's already running
-    bool isSpawning();
+    bool isSpawning()
+    {
+        QMutexLocker lock(&mMutex);
+        return mSpawning;
+    }
+    /// \brief Check if jacktrip is running
+    /// \return true if it is running, false if not
+    bool isRunning()
+    {
+        QMutexLocker lock(&mMutex);
+        return mRunning;
+    }
     /// \brief Sets the JackTripWorker properties
     /// \param id ID number
     /// \param address
-    void setJackTrip(int id,
-                     QString client_address,
-                     uint16_t server_port,
-                     uint16_t client_port,
-                     int num_channels,
-                     bool connectDefaultAudioPorts
-                     );
-    /// Stop and remove thread from pool
+    void setJackTrip(int id, QString client_address, uint16_t server_port,
+                     uint16_t client_port, bool connectDefaultAudioPorts);
+    /// Stop thread
     void stopThread();
-    int getID()
-    {
-        return mID;
-    }
+    int getID() { return mID; }
 
     void setBufferStrategy(int BufferStrategy) { mBufferStrategy = BufferStrategy; }
     void setNetIssuesSimulation(double loss, double jitter, double delay_rel)
     {
-        mSimulatedLossRate = loss;
+        mSimulatedLossRate   = loss;
         mSimulatedJitterRate = jitter;
-        mSimulatedDelayRel = delay_rel;
+        mSimulatedDelayRel   = delay_rel;
     }
-    void setBroadcast(int broadcast_queue) {mBroadcastQueue = broadcast_queue;}
-    void setUseRtUdpPriority(bool use) {mUseRtUdpPriority = use;}
-    
+    void setBroadcast(int broadcast_queue) { mBroadcastQueue = broadcast_queue; }
+    void setUseRtUdpPriority(bool use) { mUseRtUdpPriority = use; }
+
     void setIOStatTimeout(int timeout) { mIOStatTimeout = timeout; }
-    void setIOStatStream(QSharedPointer<std::ofstream> statStream) { mIOStatStream = statStream; }
-    
-private slots:
-    void slotTest()
-    { std::cout << "--- JackTripWorker TEST SLOT ---" << std::endl; }
+    void setIOStatStream(QSharedPointer<std::ofstream> statStream)
+    {
+        mIOStatStream = statStream;
+    }
+
+    bool mAppendThreadID;
+
+    void setClientPort(uint16_t port) { mClientPort = port; }
+    QString getAssignedClientName() { return mAssignedClientName; }
+    uint16_t getServerPort() { return mServerPort; }
+    uint16_t getClientPort() { return mClientPort; }
+    QString getClientAddress() { return mClientAddress; }
 
+   private slots:
+    void slotTest() { std::cout << "--- JackTripWorker TEST SLOT ---" << std::endl; }
+    void receivedDataUDP();
+    void udpTimerTick();
+    void jacktripStopped();
+    void alertPatcher();
 
-signals:
+   signals:
     void signalRemoveThread();
 
-private:
-    int setJackTripFromClientHeader(JackTrip& jacktrip);
+   private:
     JackTrip::connectionModeT getConnectionModeFromHeader();
 
-    UdpHubListener* mUdpHubListener; ///< Hub Listener Socket
-    //QHostAddress mClientAddress; ///< Client Address
+    QUdpSocket mUdpSockTemp;
+    QTimer mTimeoutTimer;
+    int mSleepTime;
+    int mElapsedTime;
+#ifdef __JAMTEST__
+    QScopedPointer<JamTest> mJackTrip;
+#else
+    QScopedPointer<JackTrip> mJackTrip;
+#endif
+
+    UdpHubListener* mUdpHubListener;  ///< Hub Listener Socket
+    // QHostAddress mClientAddress; ///< Client Address
     QString mClientAddress;
-    uint16_t mServerPort; ///< Server Ephemeral Incomming Port to use with Client
-    bool m_connectDefaultAudioPorts;
+    uint16_t mServerPort;  ///< Server Ephemeral Incomming Port to use with Client
+    bool m_connectDefaultAudioPorts = false;
 
-    /// Client Outgoing Port. By convention, the receving port will be <tt>mClientPort -1</tt>
+    /// Client Outgoing Port. By convention, the receving port will be <tt>mClientPort
+    /// -1</tt>
     uint16_t mClientPort;
-    
+
     int mBufferQueueLength;
     JackTrip::underrunModeT mUnderRunMode;
     QString mClientName;
+    QString mAssignedClientName;
 
     /// Thread spawning internal lock.
     /// If true, the prototype is working on creating (spawning) a new thread
-    volatile bool mSpawning;
-    QMutex mMutex; ///< Mutex to protect mSpawning
-
-    int mID; ///< ID thread number
-    int mNumChans; ///< Number of Channels
-
-    int mBufferStrategy;
-    int mBroadcastQueue;
-    double mSimulatedLossRate;
-    double mSimulatedJitterRate;
-    double mSimulatedDelayRel;
-    bool mUseRtUdpPriority;
-    
-    int mIOStatTimeout;
+    volatile bool mSpawning = false;
+    volatile bool mRunning  = false;
+    volatile bool mPatched  = false;
+    QMutex mMutex;  ///< Mutex to protect mSpawning
+
+    int mID = 0;  ///< ID thread number
+
+    int mBufferStrategy         = 1;
+    int mBroadcastQueue         = 0;
+    double mSimulatedLossRate   = 0.0;
+    double mSimulatedJitterRate = 0.0;
+    double mSimulatedDelayRel   = 0.0;
+    bool mUseRtUdpPriority      = false;
+
+    int mIOStatTimeout = 0;
     QSharedPointer<std::ofstream> mIOStatStream;
-#ifdef WAIR // wair
-    int mNumNetRevChans; ///< Number of Net Channels = net combs
-    bool mWAIR;
-#endif // endwhere
+#ifdef WAIR                   // wair
+    int mNumNetRevChans = 0;  ///< Number of Net Channels = net combs
+    bool mWAIR          = false;
+#endif  // endwhere
 };
 
-
-#endif //__JACKTRIPWORKER_H__
+#endif  //__JACKTRIPWORKER_H__
diff --git a/src/JackTripWorkerMessages.h b/src/JackTripWorkerMessages.h
deleted file mode 100644 (file)
index 5813f62..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-//*****************************************************************
-/*
-  JackTrip: A System for High-Quality Audio Network Performance
-  over the Internet
-
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
-  SoundWIRE group at CCRMA, Stanford University.
-
-  Permission is hereby granted, free of charge, to any person
-  obtaining a copy of this software and associated documentation
-  files (the "Software"), to deal in the Software without
-  restriction, including without limitation the rights to use,
-  copy, modify, merge, publish, distribute, sublicense, and/or sell
-  copies of the Software, and to permit persons to whom the
-  Software is furnished to do so, subject to the following
-  conditions:
-
-  The above copyright notice and this permission notice shall be
-  included in all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-  OTHER DEALINGS IN THE SOFTWARE.
-*/
-//*****************************************************************
-
-/**
- * \file JackTripWorkerMessages.h
- * \author Juan-Pablo Caceres
- * \date October 2008
- */
-
-#ifndef __JACKTRIPWORKERMESSAGES_H__
-#define __JACKTRIPWORKERMESSAGES_H__
-
-#include <QObject>
-#include <QTimer>
-
-#include <iostream>
-
-class JackTripWorkerMessages : public QObject
-{
-    Q_OBJECT;
-
-public:
-    JackTripWorkerMessages() {};
-    virtual ~JackTripWorkerMessages() {};
-
-    void play()
-    {
-        std::cout << "********** PALYING ***********************************" << std::endl;
-        QTimer *timer = new QTimer(this);
-        QObject::connect(timer, SIGNAL(timeout()), this, SLOT(slotTest()), Qt::QueuedConnection);
-        timer->start(300);
-    }
-
-public slots:
-    void slotTest()
-    {
-        std::cout << "---JackTripWorkerMessages slotTest()---" << std::endl;
-    }
-
-signals:
-    void signalTest();
-    /// Signal to stop the event loop inside the JackTripWorker Thread
-    void signalStopEventLoop();
-
-};
-
-#endif //__JACKTRIPWORKERMESSAGES_H__
index 9f73d532678d714b98891daa59aa3a8290dddfd7..27385f728540c4192b39822f9a9cc5ee24e741fb 100644 (file)
  * \date June 2020
  */
 
-
 #include "JitterBuffer.h"
 
-#include <iostream>
-#include <cstring>
+#include <cmath>
 #include <cstdlib>
+#include <cstring>
+#include <iostream>
 #include <stdexcept>
-#include <cmath>
-
-using std::cout; using std::endl;
 
+using std::cout;
+using std::endl;
 
 //*******************************************************************************
 JitterBuffer::JitterBuffer(int buf_samples, int qlen, int sample_rate, int strategy,
-                                          int bcast_qlen, int channels, int bit_res) :
-    RingBuffer(0, 0)
+                           int bcast_qlen, int channels, int bit_res)
+    RingBuffer(0, 0)
 {
-    int total_size = sample_rate * channels * bit_res * 2; // 2 secs of audio
-    int slot_size = buf_samples * channels * bit_res;
-    mSlotSize = slot_size;
-    mInSlotSize = slot_size;
+    int total_size = sample_rate * channels * bit_res * 2;  // 2 secs of audio
+    int slot_size  = buf_samples * channels * bit_res;
+    mSlotSize      = slot_size;
+    mInSlotSize    = slot_size;
     if (0 < qlen) {
         mMaxLatency = qlen * slot_size;
-        mAutoQueue = 0;
-    }
-    else {
+        mAutoQueue  = 0;
+    } else {
         // AutoQueue
-        mMaxLatency = 3*slot_size;
-        mAutoQueue = 1;
+        mMaxLatency = 3 * slot_size;
+        mAutoQueue  = 1;
     }
-    mTotalSize = total_size;
+    mTotalSize        = total_size;
     mBroadcastLatency = bcast_qlen * mSlotSize;
-    mNumChannels = channels;
-    mAudioBitRes = bit_res;
-    mMinStepSize = channels * bit_res;
-    mFPP = buf_samples;
-    mSampleRate = sample_rate;
-    mActive = false;
+    mNumChannels      = channels;
+    mAudioBitRes      = bit_res;
+    mMinStepSize      = channels * bit_res;
+    mFPP              = buf_samples;
+    mSampleRate       = sample_rate;
+    mActive           = false;
 
     // Defaults for zero strategy
     mUnderrunIncTolerance = -10 * mSlotSize;
-    mCorrIncTolerance = 100*mMaxLatency;     // should be greater than mUnderrunIncTolerance
-    mOverflowDecTolerance = 100*mMaxLatency;
-    mWritePosition = mMaxLatency;
-    mStatUnit = mSlotSize;
-    mLevelDownRate = std::min(256, mFPP) / (5.0*sample_rate) * mSlotSize;
-    mOverflowDropStep = mMaxLatency / 2;
-    mLevelCur = mMaxLatency;
-    mLevel = mLevelCur;
-    mMinLevelThreshold = 1.9 * mSlotSize;
-    mBroadcastPosition = 0;
+    mCorrIncTolerance =
+        100 * mMaxLatency;  // should be greater than mUnderrunIncTolerance
+    mOverflowDecTolerance  = 100 * mMaxLatency;
+    mWritePosition         = mMaxLatency;
+    mStatUnit              = mSlotSize;
+    mLevelDownRate         = std::min(256, mFPP) / (5.0 * sample_rate) * mSlotSize;
+    mOverflowDropStep      = mMaxLatency / 2;
+    mLevelCur              = mMaxLatency;
+    mLevel                 = mLevelCur;
+    mMinLevelThreshold     = 1.9 * mSlotSize;
+    mBroadcastPosition     = 0;
     mBroadcastPositionCorr = 0.0;
-    mLastCorrCounter = 0;
-    mLastCorrDirection = 0;
+    mLastCorrCounter       = 0;
+    mLastCorrDirection     = 0;
 
     switch (strategy) {
-      case 1:
+    case 1:
         mOverflowDropStep = mSlotSize;
         break;
-      case 2:
+    case 2:
         mUnderrunIncTolerance = 1.1 * mSlotSize;
-        mCorrIncTolerance = 1.9 * mSlotSize;     // should be greater than mUnderrunIncTolerance
-        mOverflowDecTolerance = 0.1*mSlotSize;
-        mOverflowDropStep = mSlotSize;
+        mCorrIncTolerance =
+            1.9 * mSlotSize;  // should be greater than mUnderrunIncTolerance
+        mOverflowDecTolerance = 0.1 * mSlotSize;
+        mOverflowDropStep     = mSlotSize;
         break;
     }
 
     mRingBuffer = new int8_t[mTotalSize];
     std::memset(mRingBuffer, 0, mTotalSize);
 
-    mAutoQueueCorr = 2*mSlotSize;
+    mAutoQueueCorr = 2 * mSlotSize;
     if (0 > qlen) {
-        mAutoQFactor = 1.0/-qlen;
-    }
-    else {
-        mAutoQFactor = 1.0/500;
+        mAutoQFactor = 1.0 / -qlen;
+    } else {
+        mAutoQFactor = 1.0 / 500;
     }
-    mAutoQRate = mSlotSize * 0.5;
-    mAutoQRateMin = mSlotSize * 0.0005;
-    mAutoQRateDecay = 1.0 - std::min(mFPP*1.2e-6, 0.0005);
+    mAutoQRate      = mSlotSize * 0.5;
+    mAutoQRateMin   = mSlotSize * 0.0005;
+    mAutoQRateDecay = 1.0 - std::min(mFPP * 1.2e-6, 0.0005);
 }
 
 //*******************************************************************************
 bool JitterBuffer::insertSlotNonBlocking(const int8_t* ptrToSlot, int len, int lostLen)
 {
-    if (0 == len) {
-        len = mSlotSize;
-    }
+    if (0 == len) { len = mSlotSize; }
     QMutexLocker locker(&mMutex);
     mInSlotSize = len;
-    if (!mActive) {
-        mActive = true;
-    }
-    if (mMaxLatency < len + mSlotSize) {
-        mMaxLatency = len + mSlotSize;
-    }
-    if (0 < lostLen) {
-        processPacketLoss(lostLen);
-    }
+    if (!mActive) { mActive = true; }
+    if (mMaxLatency < len + mSlotSize) { mMaxLatency = len + mSlotSize; }
+    if (0 < lostLen) { processPacketLoss(lostLen); }
     mSkewRaw += mReadsNew - len;
     mReadsNew = 0;
     mUnderruns += mUnderrunsNew;
     mUnderrunsNew = 0;
-    mLevel = mSlotSize*std::ceil(mLevelCur/mSlotSize);
+    mLevel        = mSlotSize * std::ceil(mLevelCur / mSlotSize);
 
     // Update positions if necessary
     int32_t available = mWritePosition - mReadPosition;
 
     int delta = 0;
-    if (available < -10*mMaxLatency) {
+    if (available < -10 * mMaxLatency) {
         delta = available;
         mBufIncUnderrun += -delta;
         mLevelCur = len;
-        //cout << "reset" << endl;
-    }
-    else if (available + len > mMaxLatency) {
+        // cout << "reset" << endl;
+    } else if (available + len > mMaxLatency) {
         delta = mOverflowDropStep;
         mOverflows += delta;
         mBufDecOverflow += delta;
         mLevelCur = mMaxLatency;
-    }
-    else if (0 > available &&
-          mLevelCur < std::max(mInSlotSize + mMinLevelThreshold,
-              mMaxLatency - mUnderrunIncTolerance - 2*mSlotSize*lastCorrFactor())) {
+    } else if (0 > available
+               && mLevelCur < std::max(mInSlotSize + mMinLevelThreshold,
+                                       mMaxLatency - mUnderrunIncTolerance
+                                           - 2 * mSlotSize * lastCorrFactor())) {
         delta = -std::min(-available, mSlotSize);
         mBufIncUnderrun += -delta;
-    }
-    else if (mLevelCur < mMaxLatency - mCorrIncTolerance - 6*mSlotSize*lastCorrFactor()) {
+    } else if (mLevelCur
+               < mMaxLatency - mCorrIncTolerance - 6 * mSlotSize * lastCorrFactor()) {
         delta = -mSlotSize;
         mUnderruns += -delta;
         mBufIncCompensate += -delta;
     }
 
     if (0 != delta) {
-      mReadPosition += delta;
-      mLastCorrCounter = 0;
-      mLastCorrDirection = 0 < delta ? 1 : -1;
-    }
-    else {
-      ++mLastCorrCounter;
+        mReadPosition += delta;
+        mLastCorrCounter   = 0;
+        mLastCorrDirection = 0 < delta ? 1 : -1;
+    } else {
+        ++mLastCorrCounter;
     }
 
     int wpos = mWritePosition % mTotalSize;
-    int n = std::min(mTotalSize - wpos, len);
-    std::memcpy(mRingBuffer+wpos, ptrToSlot, n);
+    int n    = std::min(mTotalSize - wpos, len);
+    std::memcpy(mRingBuffer + wpos, ptrToSlot, n);
     if (n < len) {
-        //cout << "split write: " << len << "-" << n << endl;
-        std::memcpy(mRingBuffer, ptrToSlot+n, len-n);
+        // cout << "split write: " << len << "-" << n << endl;
+        std::memcpy(mRingBuffer, ptrToSlot + n, len - n);
     }
     mWritePosition += len;
 
@@ -201,45 +190,45 @@ void JitterBuffer::readSlotNonBlocking(int8_t* ptrToReadSlot)
     mReadsNew += len;
     int32_t available = mWritePosition - mReadPosition;
     if (available < mLevelCur) {
-        mLevelCur = std::max((double)available, mLevelCur-mLevelDownRate);
-    }
-    else {
+        mLevelCur = std::max((double)available, mLevelCur - mLevelDownRate);
+    } else {
         mLevelCur = available;
     }
 
     // auto queue correction
     if (0 > available + mAutoQueueCorr - mLevelCur) {
         mAutoQueueCorr += mAutoQRate;
-    }
-    else if (mInSlotSize + mSlotSize < mAutoQueueCorr) {
+    } else if (mInSlotSize + mSlotSize < mAutoQueueCorr) {
         mAutoQueueCorr -= mAutoQRate * mAutoQFactor;
     }
-    if (mAutoQRate > mAutoQRateMin) {
-        mAutoQRate *= mAutoQRateDecay;
-    }
+    if (mAutoQRate > mAutoQRateMin) { mAutoQRate *= mAutoQRateDecay; }
     if (0 != mAutoQueue) {
         int PPS = mSampleRate / mFPP;
-        if (2*PPS == mAutoQueue++ % (4*PPS)) {
-            double k = 1.0 + 1e-5/mAutoQFactor;
-            if (12*PPS > mAutoQueue ||
-                    std::abs(mAutoQueueCorr*k - mMaxLatency + mSlotSize/2) > 0.6*mSlotSize) {
-                mMaxLatency = mSlotSize * std::ceil(mAutoQueueCorr*k/mSlotSize);
+        if (2 * PPS == mAutoQueue++ % (4 * PPS)) {
+            double k = 1.0 + 1e-5 / mAutoQFactor;
+            if (12 * PPS > mAutoQueue
+                || std::abs(mAutoQueueCorr * k - mMaxLatency + mSlotSize / 2)
+                       > 0.6 * mSlotSize) {
+                mMaxLatency = mSlotSize * std::ceil(mAutoQueueCorr * k / mSlotSize);
                 cout << "AutoQueue: " << mMaxLatency / mSlotSize << endl;
+                if (mJackTrip != nullptr) {
+                    mJackTrip->queueLengthChanged(mMaxLatency / mSlotSize);
+                }
             }
         }
     }
 
     int read_len = qBound(0, available, len);
-    int rpos = mReadPosition % mTotalSize;
-    int n = std::min(mTotalSize - rpos, read_len);
-    std::memcpy(ptrToReadSlot, mRingBuffer+rpos, n);
+    int rpos     = mReadPosition % mTotalSize;
+    int n        = std::min(mTotalSize - rpos, read_len);
+    std::memcpy(ptrToReadSlot, mRingBuffer + rpos, n);
     if (n < read_len) {
-        //cout << "split read: " << read_len << "-" << n << endl;
-        std::memcpy(ptrToReadSlot+n, mRingBuffer, read_len-n);
+        // cout << "split read: " << read_len << "-" << n << endl;
+        std::memcpy(ptrToReadSlot + n, mRingBuffer, read_len - n);
     }
     if (read_len < len) {
-        std::memset(ptrToReadSlot+read_len, 0, len-read_len);
-        mUnderrunsNew += len-read_len;
+        std::memset(ptrToReadSlot + read_len, 0, len - read_len);
+        mUnderrunsNew += len - read_len;
     }
     mReadPosition += len;
 }
@@ -255,61 +244,57 @@ void JitterBuffer::readBroadcastSlot(int8_t* ptrToReadSlot)
     }
     // latency correction
     int32_t d = mReadPosition - mBroadcastLatency - mBroadcastPosition - len;
-    if (std::abs(d) > mBroadcastLatency / 2) {
-        mBroadcastPosition = mReadPosition - mBroadcastLatency - len;
+    if (static_cast<uint32_t>(std::abs(d)) > mBroadcastLatency / 2) {
+        mBroadcastPosition     = mReadPosition - mBroadcastLatency - len;
         mBroadcastPositionCorr = 0.0;
         mBroadcastSkew += d / mMinStepSize;
-    }
-    else {
+    } else {
         mBroadcastPositionCorr += 0.0003 * d;
         int delta = mBroadcastPositionCorr / mMinStepSize;
         if (0 != delta) {
             mBroadcastPositionCorr -= delta * mMinStepSize;
-            if (2 == mAudioBitRes && (int32_t)(mWritePosition - mBroadcastPosition) > len) {
+            if (2 == mAudioBitRes
+                && (int32_t)(mWritePosition - mBroadcastPosition) > len) {
                 // interpolate
                 len += delta * mMinStepSize;
-            }
-            else {
+            } else {
                 // skip
                 mBroadcastPosition += delta * mMinStepSize;
             }
             mBroadcastSkew += delta;
         }
     }
-    mBroadcastDelta = d / mMinStepSize;
+    mBroadcastDelta   = d / mMinStepSize;
     int32_t available = mWritePosition - mBroadcastPosition;
-    int read_len = qBound(0, available, len);
+    int read_len      = qBound(0, available, len);
     if (len == mSlotSize) {
         int rpos = mBroadcastPosition % mTotalSize;
-        int n = std::min(mTotalSize - rpos, read_len);
-        std::memcpy(ptrToReadSlot, mRingBuffer+rpos, n);
+        int n    = std::min(mTotalSize - rpos, read_len);
+        std::memcpy(ptrToReadSlot, mRingBuffer + rpos, n);
         if (n < read_len) {
-            //cout << "split read: " << read_len << "-" << n << endl;
-            std::memcpy(ptrToReadSlot+n, mRingBuffer, read_len-n);
-        }
-        if (read_len < len) {
-            std::memset(ptrToReadSlot+read_len, 0, len-read_len);
+            // cout << "split read: " << read_len << "-" << n << endl;
+            std::memcpy(ptrToReadSlot + n, mRingBuffer, read_len - n);
         }
-    }
-    else {
+        if (read_len < len) { std::memset(ptrToReadSlot + read_len, 0, len - read_len); }
+    else {
         // interpolation len => mSlotSize
         double K = 1.0 * len / mSlotSize;
-        for (int c=0; c < mMinStepSize; c+=sizeof(int16_t)) {
-            for (int j=0; j < mSlotSize/mMinStepSize; ++j) {
-                int j1 = std::floor(j*K);
-                double a = j*K - j1;
-                int rpos = (mBroadcastPosition + j1*mMinStepSize + c) % mTotalSize;
+        for (int c = 0; c < mMinStepSize; c += sizeof(int16_t)) {
+            for (int j = 0; j < mSlotSize / mMinStepSize; ++j) {
+                int j1     = std::floor(j * K);
+                double a   = j * K - j1;
+                int rpos   = (mBroadcastPosition + j1 * mMinStepSize + c) % mTotalSize;
                 int16_t v1 = *(int16_t*)(mRingBuffer + rpos);
-                rpos = (rpos + mMinStepSize) % mTotalSize;
+                rpos       = (rpos + mMinStepSize) % mTotalSize;
                 int16_t v2 = *(int16_t*)(mRingBuffer + rpos);
-                *(int16_t*)(ptrToReadSlot + j*mMinStepSize + c) = std::round((1-a)*v1 + a*v2);
+                *(int16_t*)(ptrToReadSlot + j * mMinStepSize + c) =
+                    std::round((1 - a) * v1 + a * v2);
             }
         }
     }
     mBroadcastPosition += len;
 }
 
-
 //*******************************************************************************
 void JitterBuffer::processPacketLoss(int lostLen)
 {
@@ -320,33 +305,32 @@ void JitterBuffer::processPacketLoss(int lostLen)
     if (0 < delta) {
         lostLen -= delta;
         mBufDecPktLoss += delta;
-        mLevelCur = mMaxLatency;
-        mLastCorrCounter = 0;
+        mLevelCur          = mMaxLatency;
+        mLastCorrCounter   = 0;
         mLastCorrDirection = 1;
-    }
-    else if (mSlotSize < available + lostLen && (
-            mOverflowDecTolerance > mMaxLatency   // for strategies 0,1
-            || (0 < mLastCorrDirection && mLevelCur >
-                    mMaxLatency - mOverflowDecTolerance*(1.1 - lastCorrFactor()))
-            )) {
+    } else if (mSlotSize < available + lostLen
+               && (mOverflowDecTolerance > mMaxLatency  // for strategies 0,1
+                   || (0 < mLastCorrDirection
+                       && mLevelCur > mMaxLatency
+                                          - mOverflowDecTolerance
+                                                * (1.1 - lastCorrFactor())))) {
         delta = std::min(lostLen, mSlotSize);
         lostLen -= delta;
         mBufDecPktLoss += delta;
         mLevelCur -= delta;
-        mLastCorrCounter = 0;
+        mLastCorrCounter   = 0;
         mLastCorrDirection = 1;
     }
     if (lostLen >= mTotalSize) {
         std::memset(mRingBuffer, 0, mTotalSize);
         mUnderruns += std::max(0, lostLen - std::max(0, -available));
-    }
-    else if (0 < lostLen) {
+    } else if (0 < lostLen) {
         int wpos = mWritePosition % mTotalSize;
-        int n = std::min(mTotalSize - wpos, lostLen);
-        std::memset(mRingBuffer+wpos, 0, n);
+        int n    = std::min(mTotalSize - wpos, lostLen);
+        std::memset(mRingBuffer + wpos, 0, n);
         if (n < lostLen) {
-            //cout << "split write: " << lostLen << "-" << n << endl;
-            std::memset(mRingBuffer, 0, lostLen-n);
+            // cout << "split write: " << lostLen << "-" << n << endl;
+            std::memset(mRingBuffer, 0, lostLen - n);
         }
         mUnderruns += std::max(0, lostLen - std::max(0, -available));
     }
@@ -358,32 +342,32 @@ bool JitterBuffer::getStats(RingBuffer::IOStat* stat, bool reset)
 {
     QMutexLocker locker(&mMutex);
     if (reset) {
-        mUnderruns = 0;
-        mOverflows = 0;
-        mSkew0 = mLevel;
-        mSkewRaw = 0;
-        mBufDecOverflow = 0;
-        mBufDecPktLoss = 0;
-        mBufIncUnderrun = 0;
+        mUnderruns        = 0;
+        mOverflows        = 0;
+        mSkew0            = mLevel;
+        mSkewRaw          = 0;
+        mBufDecOverflow   = 0;
+        mBufDecPktLoss    = 0;
+        mBufIncUnderrun   = 0;
         mBufIncCompensate = 0;
-        mBroadcastSkew = 0;
+        mBroadcastSkew    = 0;
     }
     stat->underruns = mUnderruns / mStatUnit;
     stat->overflows = mOverflows / mStatUnit;
-    stat->skew = (int32_t)((mSkew0 - mLevel + mBufIncUnderrun + mBufIncCompensate
-                        - mBufDecOverflow - mBufDecPktLoss)) / mStatUnit;
+    stat->skew      = (int32_t)((mSkew0 - mLevel + mBufIncUnderrun + mBufIncCompensate
+                            - mBufDecOverflow - mBufDecPktLoss))
+                 / mStatUnit;
     stat->skew_raw = mSkewRaw / mStatUnit;
-    stat->level = mLevel / mStatUnit;
+    stat->level    = mLevel / mStatUnit;
 
-    stat->buf_dec_overflows = mBufDecOverflow / mStatUnit;
-    stat->buf_dec_pktloss = mBufDecPktLoss / mStatUnit;
-    stat->buf_inc_underrun = mBufIncUnderrun / mStatUnit;
+    stat->buf_dec_overflows  = mBufDecOverflow / mStatUnit;
+    stat->buf_dec_pktloss    = mBufDecPktLoss / mStatUnit;
+    stat->buf_inc_underrun   = mBufIncUnderrun / mStatUnit;
     stat->buf_inc_compensate = mBufIncCompensate / mStatUnit;
-    stat->broadcast_skew = mBroadcastSkew;
-    stat->broadcast_delta = mBroadcastDelta;
+    stat->broadcast_skew     = mBroadcastSkew;
+    stat->broadcast_delta    = mBroadcastDelta;
 
     stat->autoq_corr = mAutoQueueCorr / mStatUnit * 10;
     stat->autoq_rate = mAutoQRate / mStatUnit * 1000;
     return true;
 }
-
index 6be4069dd79ba0d499470e15bad20f7b3ff2ada6..c61a02eaa09ae5f42da41baefa3e42dfecef1ded 100644 (file)
 #ifndef __JITTERBUFFER_H__
 #define __JITTERBUFFER_H__
 
+#include "JackTrip.h"
 #include "RingBuffer.h"
 
 class JitterBuffer : public RingBuffer
 {
-public:
-    JitterBuffer(int buf_samples, int qlen, int sample_rate, int strategy,
-                                int bcast_qlen, int channels, int bit_res);
+   public:
+    JitterBuffer(int buf_samples, int qlen, int sample_rate, int strategy, int bcast_qlen,
+                 int channels, int bit_res);
     virtual ~JitterBuffer() {}
 
     virtual bool insertSlotNonBlocking(const int8_t* ptrToSlot, int len, int lostLen);
@@ -53,10 +54,12 @@ public:
 
     virtual bool getStats(IOStat* stat, bool reset);
 
-protected:
+    void setJackTrip(JackTrip* jackTrip) { mJackTrip = jackTrip; }
+
+   protected:
     void processPacketLoss(int lostLen);
 
-protected:
+   protected:
     int mMaxLatency;
     int mNumChannels;
     int mAudioBitRes;
@@ -67,24 +70,25 @@ protected:
     bool mActive;
     uint32_t mBroadcastLatency;
     uint32_t mBroadcastPosition;
-    double  mBroadcastPositionCorr;
+    double mBroadcastPositionCorr;
 
     double mUnderrunIncTolerance;
     double mCorrIncTolerance;
     double mOverflowDecTolerance;
-    int    mOverflowDropStep;
+    int mOverflowDropStep;
     uint32_t mLastCorrCounter;
-    int    mLastCorrDirection;
+    int mLastCorrDirection;
     double mMinLevelThreshold;
-    double lastCorrFactor() const {return 500.0 / std::max(500U, mLastCorrCounter);}
+    double lastCorrFactor() const { return 500.0 / std::max(500U, mLastCorrCounter); }
 
-    int    mAutoQueue;
+    int mAutoQueue;
     double mAutoQueueCorr;
     double mAutoQFactor;
     double mAutoQRate;
     double mAutoQRateMin;
     double mAutoQRateDecay;
-};
 
+    JackTrip* mJackTrip;
+};
 
-#endif //__JITTERBUFFER_H__
+#endif  //__JITTERBUFFER_H__
index 91a918f1f9722b37472fc81f91d27427caf617e2..80213f7f611fb3902d63b53ab41e854617cb14ab 100644 (file)
  */
 
 #include "Limiter.h"
-#include "jacktrip_types.h"
 
 #include <iostream>
 
+#include "jacktrip_types.h"
+
 //*******************************************************************************
 void Limiter::compute(int nframes, float** inputs, float** outputs)
 {
-  if (not inited) {
-    std::cerr << "*** Limiter " << this << ": init never called! Doing it now.\n";
-    if (fSamplingFreq <= 0) {
-      fSamplingFreq = 48000;
-      std::cout << "Limiter " << this << ": *** HAD TO GUESS the sampling rate (chose 48000 Hz) ***\n";
+    if (not inited) {
+        std::cerr << "*** Limiter " << this << ": init never called! Doing it now.\n";
+        if (fSamplingFreq <= 0) {
+            fSamplingFreq = 48000;
+            std::cout << "Limiter " << this
+                      << ": *** HAD TO GUESS the sampling rate (chose 48000 Hz) ***\n";
+        }
+        init(fSamplingFreq);
     }
-    init(fSamplingFreq);
-  }
 #ifdef SINE_TEST
-  float sineTestOut[nframes];
-  float* faustSigs[1] { sineTestOut };
+    float sineTestOut[nframes];
+    float* faustSigs[1]{sineTestOut};
 #endif
-  for ( int i = 0; i < mNumChannels; i++ ) {
-    if (warningAmp > 0.0) {
-      checkAmplitudes(nframes, inputs[i]); // we presently do one check across all channels
-    }
-    limiterP[i]->compute(nframes, &inputs[i], &outputs[i]);
+    for (int i = 0; i < mNumChannels; i++) {
+        if (warningAmp > 0.0) {
+            checkAmplitudes(nframes,
+                            inputs[i]);  // we presently do one check across all channels
+        }
+        limiterP[i]->compute(nframes, &inputs[i], &outputs[i]);
 #ifdef SINE_TEST
-    limiterTestP[i]->compute(nframes, faustSigs, faustSigs);
-    for ( int n = 0; n < nframes; n++ ) {
-      outputs[i][n] = outputs[i][n] + sineTestOut[n];
-    }
+        limiterTestP[i]->compute(nframes, faustSigs, faustSigs);
+        for (int n = 0; n < nframes; n++) {
+            outputs[i][n] = outputs[i][n] + sineTestOut[n];
+        }
 #endif
-  }
+    }
 }
index 6318d22cd8fb87ca3e09a66b731bf846616504d4..f31130847fc065d6db8084e302b6a84b5613cc0c 100644 (file)
 #include "limitertest.h"
 #endif
 
+#include <cassert>
+#include <vector>
+
 #include "ProcessPlugin.h"
 #include "limiterdsp.h"
-#include <vector>
-#include "assert.h"
 
 /** \brief The Limiter class confines the output dynamic range to a
  *  "dynamic range lane" determined by the assumed number of clients.
  */
 class Limiter : public ProcessPlugin
 {
-public:
-  /// \brief The class constructor sets the number of channels to limit
-  Limiter(int numchans, int numclients, bool verboseFlag = false) // xtor
-    : mNumChannels(numchans), mNumClients(numclients)
-    , warningAmp(0.0), warnCount(0), peakMagnitude(0.0), nextWarning(1)
-  {
-    setVerbose(verboseFlag);
-    for ( int i = 0; i < mNumChannels; i++ ) {
-      limiterP.push_back(new limiterdsp);
-      limiterUIP.push_back(new APIUI); // #included in limiterdsp.h
-      limiterP[i]->buildUserInterface(limiterUIP[i]);
+   public:
+    /// \brief The class constructor sets the number of channels to limit
+    Limiter(int numchans, int numclients, bool verboseFlag = false)  // xtor
+        : mNumChannels(numchans)
+        , mNumClients(numclients)
+        , warningAmp(0.0)
+        , warnCount(0)
+        , peakMagnitude(0.0)
+        , nextWarning(1)
+    {
+        setVerbose(verboseFlag);
+        for (int i = 0; i < mNumChannels; i++) {
+            limiterP.push_back(new limiterdsp);
+            limiterUIP.push_back(new APIUI);  // #included in limiterdsp.h
+            limiterP[i]->buildUserInterface(limiterUIP[i]);
 #ifdef SINE_TEST
-      limiterTestP.push_back(new limitertest);
-      limiterTestUIP.push_back(new APIUI); // #included in limitertest.h
-      limiterTestP[i]->buildUserInterface(limiterTestUIP[i]);
+            limiterTestP.push_back(new limitertest);
+            limiterTestUIP.push_back(new APIUI);  // #included in limitertest.h
+            limiterTestP[i]->buildUserInterface(limiterTestUIP[i]);
 #endif
+        }
+        //    std::cout << "Limiter: constructed for "
+        // << mNumChannels << " channels and "
+        // << mNumClients << " assumed clients\n";
     }
-    //    std::cout << "Limiter: constructed for "
-    // << mNumChannels << " channels and "
-    // << mNumClients << " assumed clients\n";
-  }
-
-  /// \brief The class destructor
-  virtual ~Limiter() {
-    for ( int i = 0; i < mNumChannels; i++ ) {
-      delete limiterP[i];
-      delete limiterUIP[i];
+
+    /// \brief The class destructor
+    virtual ~Limiter()
+    {
+        for (int i = 0; i < mNumChannels; i++) {
+            delete limiterP[i];
+            delete limiterUIP[i];
+        }
+        limiterP.clear();
+        limiterUIP.clear();
     }
-    limiterP.clear();
-    limiterUIP.clear();
-  }
-
-  void init(int samplingRate) override {
-    ProcessPlugin::init(samplingRate);
-    if (samplingRate != fSamplingFreq) {
-      std::cerr << "Sampling rate not set by superclass!\n";
-      std::exit(1); }
-    fs = float(fSamplingFreq);
-    for ( int i = 0; i < mNumChannels; i++ ) {
-      limiterP[i]->init(fs); // compression filter parameters depend on sampling rate
-      int ndx = limiterUIP[i]->getParamIndex("NumClientsAssumed");
-      limiterUIP[i]->setParamValue(ndx, mNumClients);
+
+    void init(int samplingRate) override
+    {
+        ProcessPlugin::init(samplingRate);
+        if (samplingRate != fSamplingFreq) {
+            std::cerr << "Sampling rate not set by superclass!\n";
+            std::exit(1);
+        }
+        fs = float(fSamplingFreq);
+        for (int i = 0; i < mNumChannels; i++) {
+            limiterP[i]->init(
+                fs);  // compression filter parameters depend on sampling rate
+            int ndx = limiterUIP[i]->getParamIndex("NumClientsAssumed");
+            limiterUIP[i]->setParamValue(ndx, mNumClients);
 #ifdef SINE_TEST
-      limiterTestP[i]->init(fs); // oscillator parameters depend on sampling rate
-      ndx = limiterTestUIP[i]->getParamIndex("Amp");
-      limiterTestUIP[i]->setParamValue(ndx, 0.2);
-      ndx = limiterTestUIP[i]->getParamIndex("Freq");
-      float sineFreq = 110.0 * pow(1.5,double(i)) * (mNumClients>1?1.25:1.0); // Maj 7 chord for stereo in & out
-      limiterTestUIP[i]->setParamValue(ndx, sineFreq);
+            limiterTestP[i]->init(fs);  // oscillator parameters depend on sampling rate
+            ndx = limiterTestUIP[i]->getParamIndex("Amp");
+            limiterTestUIP[i]->setParamValue(ndx, 0.2);
+            ndx = limiterTestUIP[i]->getParamIndex("Freq");
+            float sineFreq =
+                110.0 * pow(1.5, double(i))
+                * (mNumClients > 1 ? 1.25 : 1.0);  // Maj 7 chord for stereo in & out
+            limiterTestUIP[i]->setParamValue(ndx, sineFreq);
 #endif
+        }
+        inited = true;
+    }
+    int getNumInputs() override { return (mNumChannels); }
+    int getNumOutputs() override { return (mNumChannels); }
+    void compute(int nframes, float** inputs, float** outputs) override;
+    const char* getName() const override { return "Limiter"; }
+
+    void setWarningAmplitude(double wa)
+    {  // setting to 0 turns off warnings
+        warningAmp = std::max(0.0, std::min(1.0, wa));
     }
-    inited = true;
-  }
-  int getNumInputs() override { return(mNumChannels); }
-  int getNumOutputs() override { return(mNumChannels); }
-  void compute(int nframes, float** inputs, float** outputs) override;
-
-  void setWarningAmplitude(double wa) { // setting to 0 turns off warnings
-    warningAmp = std::max(0.0,std::min(1.0,wa));
-  }
-
- private:
-
-  void checkAmplitudes(int nframes, float* buf) {
-    const int maxWarningInterval { 10000 }; // this could become an option
-    assert(warningAmp > 0.0);
-    assert(mNumClients > 0);
-    for (int i=0; i<nframes; i++) {
-      double tmp_sample = double(buf[i]);
-      double limiterAmp = fabs(tmp_sample)/sqrt(double(mNumClients)); // KEEP IN SYNC with gain in ../faust-src/limiterdsp.dsp
-      if (limiterAmp >= warningAmp) {
-        warnCount++;
-        peakMagnitude = std::max(peakMagnitude,limiterAmp);
-        if (warnCount==nextWarning) {
-          double peakMagnitudeDB = 20.0 * std::log10(peakMagnitude);
-          double warningAmpDB = 20.0 * std::log10(warningAmp);
-          if (warnCount==1) {
-            if (warningAmp == 1.0) {
-              std::cerr << "*** Limiter.cpp: Audio HARD-CLIPPED!\n";
-              fprintf(stderr, "\tReduce your audio input level(s) by %0.1f dB to avoid this.\n", peakMagnitudeDB);
-            } else {
-              fprintf(stderr,
-                      "*** Limiter.cpp: Amplitude levels must stay below %0.1f dBFS to avoid compression.\n",
-                      warningAmpDB);
-              fprintf(stderr, "\tReduce input level(s) by %0.1f dB to achieve this.\n",
-                      peakMagnitudeDB-warningAmpDB);
-            }
-          } else {
-            fprintf(stderr, "\tReduce audio input level(s) by %0.1f dB to avoid limiter compression distortion.\n",
-                    peakMagnitudeDB-warningAmpDB);
-          }
-          peakMagnitude = 0.0; // reset for next group measurement
-          if (nextWarning < maxWarningInterval) { // don't let it stop reporting for too long
-            nextWarning *= 10;
-          } else {
-            warnCount=0;
-          }
-        } // warnCount==nextWarning
-      } // above warningAmp
-    } // loop over frames
-  } // checkAmplitudes()
-
-private:
-  float fs;
-  int mNumChannels;
-  int mNumClients;
-  std::vector<limiterdsp*> limiterP;
-  std::vector<APIUI*> limiterUIP;
+
+   private:
+    void checkAmplitudes(int nframes, float* buf)
+    {
+        const int maxWarningInterval{10000};  // this could become an option
+        assert(warningAmp > 0.0);
+        assert(mNumClients > 0);
+        for (int i = 0; i < nframes; i++) {
+            double tmp_sample = double(buf[i]);
+            double limiterAmp =
+                fabs(tmp_sample)
+                / sqrt(double(mNumClients));  // KEEP IN SYNC with gain in
+                                              // ../faust-src/limiterdsp.dsp
+            if (limiterAmp >= warningAmp) {
+                warnCount++;
+                peakMagnitude = std::max(peakMagnitude, limiterAmp);
+                if (warnCount == nextWarning) {
+                    double peakMagnitudeDB = 20.0 * std::log10(peakMagnitude);
+                    double warningAmpDB    = 20.0 * std::log10(warningAmp);
+                    if (warnCount == 1) {
+                        if (warningAmp == 1.0) {
+                            std::cerr << "*** Limiter.cpp: Audio HARD-CLIPPED!\n";
+                            fprintf(stderr,
+                                    "\tReduce your audio input level(s) by %0.1f dB to "
+                                    "avoid this.\n",
+                                    peakMagnitudeDB);
+                        } else {
+                            fprintf(stderr,
+                                    "*** Limiter.cpp: Amplitude levels must stay below "
+                                    "%0.1f dBFS to avoid compression.\n",
+                                    warningAmpDB);
+                            fprintf(
+                                stderr,
+                                "\tReduce input level(s) by %0.1f dB to achieve this.\n",
+                                peakMagnitudeDB - warningAmpDB);
+                        }
+                    } else {
+                        fprintf(stderr,
+                                "\tReduce audio input level(s) by %0.1f dB to avoid "
+                                "limiter compression distortion.\n",
+                                peakMagnitudeDB - warningAmpDB);
+                    }
+                    peakMagnitude = 0.0;  // reset for next group measurement
+                    if (nextWarning < maxWarningInterval) {  // don't let it stop
+                                                             // reporting for too long
+                        nextWarning *= 10;
+                    } else {
+                        warnCount = 0;
+                    }
+                }  // warnCount==nextWarning
+            }      // above warningAmp
+        }          // loop over frames
+    }              // checkAmplitudes()
+
+   private:
+    float fs;
+    int mNumChannels;
+    int mNumClients;
+    std::vector<limiterdsp*> limiterP;
+    std::vector<APIUI*> limiterUIP;
 #ifdef SINE_TEST
-  std::vector<limitertest*> limiterTestP;
-  std::vector<APIUI*> limiterTestUIP;
+    std::vector<limitertest*> limiterTestP;
+    std::vector<APIUI*> limiterTestUIP;
 #endif
-  double warningAmp;
-  uint32_t warnCount;
-  double peakMagnitude;
-  uint32_t nextWarning;
+    double warningAmp;
+    uint32_t warnCount;
+    double peakMagnitude;
+    uint32_t nextWarning;
 };
 
 #endif
index 448ce415c25c21b92040b874d92ab35c55207a8f..f17d181a8a38b32d2c387b7e5da0cd8acc4728e0 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
  * \date July 2008
  */
 
-
 #include "LoopBack.h"
-#include "jacktrip_types.h"
 
-#include <cstring> // for memcpy
+#include <cstring>  // for memcpy
 #include <iostream>
 
-using std::cout; using std::endl;
-//using namespace JackTripNamespace;
+#include "jacktrip_types.h"
 
+using std::cout;
+using std::endl;
+// using namespace JackTripNamespace;
 
 //*******************************************************************************
 void LoopBack::compute(int nframes, float** inputs, float** outputs)
 {
-    for ( int i = 0; i < getNumInputs(); i++ ) {
+    for (int i = 0; i < getNumInputs(); i++) {
         // Everything that comes out, copy back to inputs
-        //memcpy(inputs[i], outputs[i], sizeof(sample_t) * nframes);
+        // memcpy(inputs[i], outputs[i], sizeof(sample_t) * nframes);
         memcpy(outputs[i], inputs[i], sizeof(sample_t) * nframes);
     }
 }
index 797898df75efdcd3773b8991739ec9725be63dd3..763da69df1575c319ac74df026155e3e16c1d3ac 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
@@ -35,7 +35,6 @@
  * \date July 2008
  */
 
-
 /** \brief Connect Inputs to Outputs
  *
  */
@@ -44,7 +43,6 @@
 
 #include "ProcessPlugin.h"
 
-
 /** \brief This Class just copy audio from its inputs to its outputs.
  *
  * It can be use to do loopback without the need to externally connect channels
  */
 class LoopBack : public ProcessPlugin
 {
-public:
+   public:
     /// \brief The class constructor sets the number of channels to connect as loopback
     LoopBack(int numchans) { mNumChannels = numchans; };
     /// \brief The class destructor
-    virtual ~LoopBack() {};
+    virtual ~LoopBack(){};
 
-    virtual int getNumInputs() { return(mNumChannels); };
-    virtual int getNumOutputs() { return(mNumChannels); };
+    virtual int getNumInputs() { return (mNumChannels); };
+    virtual int getNumOutputs() { return (mNumChannels); };
     virtual void compute(int nframes, float** inputs, float** outputs);
 
-private:
+   private:
     int mNumChannels;
 };
 
diff --git a/src/NetKS.h b/src/NetKS.h
deleted file mode 100644 (file)
index ea3a788..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-//*****************************************************************
-/*
-  JackTrip: A System for High-Quality Audio Network Performance
-  over the Internet
-
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
-  SoundWIRE group at CCRMA, Stanford University.
-
-  Permission is hereby granted, free of charge, to any person
-  obtaining a copy of this software and associated documentation
-  files (the "Software"), to deal in the Software without
-  restriction, including without limitation the rights to use,
-  copy, modify, merge, publish, distribute, sublicense, and/or sell
-  copies of the Software, and to permit persons to whom the
-  Software is furnished to do so, subject to the following
-  conditions:
-
-  The above copyright notice and this permission notice shall be
-  included in all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-  OTHER DEALINGS IN THE SOFTWARE.
-*/
-//*****************************************************************
-
-/**
- * \file JackTrip.h
- * \author Juan-Pablo Caceres
- * \date October 2008
- */
-
-#ifndef __NETKS_H__
-#define __NETKS_H__
-
-#include <iostream>
-//#include <unistd.h>
-
-#include <QTimer>
-
-#include "ProcessPlugin.h"
-
-/** \brief A simple (basic) network Karplus Strong.
- *
- * This plugin creates a one channel network karplus strong.
- */
-class NetKS : public ProcessPlugin
-{
-    Q_OBJECT;
-
-
-public:
-    /*
-  void play()
-  {
-    std::cout << "********** PALYING ***********************************" << std::endl;
-    QTimer *timer = new QTimer(this);
-    QObject::connect(timer, SIGNAL(timeout()),  this, SLOT(exciteString()));
-    timer->start(300);
-  }
-  */
-
-private slots:
-
-    /// \brief Stlot to excite (play) the string
-    void exciteString()
-    {
-        std::cout << "========= EXTICING STRING ===========" << std::endl;
-        fbutton0 = 1.0;
-        //std::cout << fbutton0 << std::endl;
-        QThread::usleep(280000); /// \todo Define this number based on the sampling rate and buffer size
-        fbutton0 = 0.0;
-        //std::cout << fbutton0 << std::endl;
-    }
-
-    //=========== FROM FAUST ===================================================
-private:
-    float fbutton0;
-    float fVec0[2];
-    float fRec0[2];
-    int   iRec1[2];
-    float fVec1[2];
-public:
-    virtual int getNumInputs() { return 1; }
-    virtual int getNumOutputs() { return 1; }
-    static void classInit(int /*samplingFreq*/) {}
-    virtual void instanceInit(int samplingFreq) {
-        fSamplingFreq = samplingFreq;
-        fbutton0 = 0.0;
-        for (int i=0; i<2; i++) fVec0[i] = 0;
-        for (int i=0; i<2; i++) fRec0[i] = 0;
-        for (int i=0; i<2; i++) iRec1[i] = 0;
-        for (int i=0; i<2; i++) fVec1[i] = 0;
-    }
-    virtual void init(int samplingFreq) {
-        classInit(samplingFreq);
-        instanceInit(samplingFreq);
-    }
-    /*
-        virtual void buildUserInterface(UI* interface) {
-                interface->openVerticalBox("excitator");
-                interface->addButton("play", &fbutton0);
-                interface->closeBox();
-        }
-  */
-    virtual void compute (int count, float** input, float** output) {
-        float* input0 = input[0];
-        float* output0 = output[0];
-        float fSlow0 = fbutton0;
-        for (int i=0; i<count; i++) {
-            fVec0[0] = fSlow0;
-            fRec0[0] = ((((fSlow0 - fVec0[1]) > 0.000000f) + fRec0[1]) - (3.333333e-03f * (fRec0[1] > 0.000000f)));
-            iRec1[0] = (12345 + (1103515245 * iRec1[1]));
-            float fTemp0 = ((4.190951e-10f * iRec1[0]) * (fRec0[0] > 0.000000f));
-            float fTemp1 = input0[i];
-            fVec1[0] = (fTemp1 + fTemp0);
-            output0[i] = (0.500000f * ((fTemp0 + fTemp1) + fVec1[1]));
-            // post processing
-            fVec1[1] = fVec1[0];
-            iRec1[1] = iRec1[0];
-            fRec0[1] = fRec0[0];
-            fVec0[1] = fVec0[0];
-        }
-    }
-
-    //============================================================================
-
-};
-
-
-#endif // __NETKS_H__
index 5511f940b701a68144c9b25d7b3d9f81ab1e96ba..a9e0c5af6f2e4432311e78951133a979c5926838 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
  */
 
 #include "PacketHeader.h"
-#include "JackTrip.h"
 
+#if defined(__LINUX__) || defined(__MAC_OSX__)
 #include <sys/time.h>
+#endif
+
 #include <cstdlib>
 #include <iostream>
+#include <limits>
 #include <stdexcept>
 
-using std::cout; using std::endl;
+#include "JackTrip.h"
 
+using std::cout;
+using std::endl;
 
-// below is the gettimeofday definition for windows: this function is not defined in sys/time.h as it is in unix
-// for more info check: http://www.halcode.com/archives/2008/08/26/retrieving-system-time-gettimeofday/
+// below is the gettimeofday definition for windows: this function is not defined in
+// sys/time.h as it is in unix for more info check:
+// http://www.halcode.com/archives/2008/08/26/retrieving-system-time-gettimeofday/
 #if defined __WIN_32__
 #ifdef __cplusplus
-void GetSystemTimeAsFileTime(FILETIME*);
+// void GetSystemTimeAsFileTime(FILETIME*);
 inline int gettimeofday(struct timeval* p, void* tz /* IGNORED */)
 {
     union {
         long long ns100; /*time since 1 Jan 1601 in 100ns units */
         FILETIME ft;
     } now;
-    GetSystemTimeAsFileTime( &(now.ft) );
-    p->tv_usec=(long)((now.ns100 / 10LL) % 1000000LL );
-    p->tv_sec= (long)((now.ns100-(116444736000000000LL))/10000000LL);
+    GetSystemTimeAsFileTime(&(now.ft));
+    p->tv_usec = (long)((now.ns100 / 10LL) % 1000000LL);
+    p->tv_sec  = (long)((now.ns100 - (116444736000000000LL)) / 10000000LL);
     return 0;
 }
-#else
-/* Must be defined somewhere else */
-int gettimeofday(struct timeval* p, void* tz /* IGNORED */);
 #endif
 #endif
 
-
 //#######################################################################
 //####################### PacketHeader ##################################
 //#######################################################################
 //***********************************************************************
-PacketHeader::PacketHeader(JackTrip* jacktrip) :
-    mSeqNumber(0), mJackTrip(jacktrip)
-{}
-
+PacketHeader::PacketHeader(JackTrip* jacktrip)
+    : mBufferRequiresSameSettings(false), mJackTrip(jacktrip), mSeqNumber(0)
+{
+}
 
 //***********************************************************************
 uint64_t PacketHeader::usecTime()
 {
     struct timeval tv;
-    gettimeofday (&tv, NULL);
-    return ( (tv.tv_sec * 1000000)  + // seconds
-             (tv.tv_usec) );  // plus the microseconds. Type suseconds_t, range [-1, 1000000]
+    gettimeofday(&tv, NULL);
+    return (
+        (tv.tv_sec * 1000000) +  // seconds
+        (tv.tv_usec));  // plus the microseconds. Type suseconds_t, range [-1, 1000000]
 }
 
-
-
-
 //#######################################################################
 //####################### DefaultHeader #################################
 //#######################################################################
 //***********************************************************************
-DefaultHeader::DefaultHeader(JackTrip* jacktrip) :
-    PacketHeader(jacktrip), mJackTrip(jacktrip)
+DefaultHeader::DefaultHeader(JackTrip* jacktrip) : PacketHeader(jacktrip)
 {
-    mHeader.TimeStamp = 0;
-    mHeader.SeqNumber = 0;
-    mHeader.BufferSize = 0;
-    mHeader.SamplingRate = 0;
-    mHeader.BitResolution = 0;
-    //mHeader.NumInChannels = 0;
-    //mHeader.NumOutChannels = 0;
-    mHeader.NumChannels = 0;
-    mHeader.ConnectionMode = 0;
+    mHeader.TimeStamp                  = 0;
+    mHeader.SeqNumber                  = 0;
+    mHeader.BufferSize                 = 0;
+    mHeader.SamplingRate               = 0;
+    mHeader.BitResolution              = 0;
+    mHeader.NumIncomingChannelsFromNet = 0;
+    mHeader.NumOutgoingChannelsToNet   = 0;
 }
 
-
 //***********************************************************************
 void DefaultHeader::fillHeaderCommonFromAudio()
 {
-    mHeader.TimeStamp = PacketHeader::usecTime();
-    mHeader.BufferSize = mJackTrip->getBufferSizeInSamples();
-    mHeader.SamplingRate = mJackTrip->getSampleRateType ();
-    mHeader.BitResolution = mJackTrip->getAudioBitResolution();
-    mHeader.NumChannels = mJackTrip->getNumChannels();
-    mHeader.ConnectionMode = static_cast<int>(mJackTrip->getConnectionMode());
-    //printHeader();
+    mHeader.TimeStamp                  = PacketHeader::usecTime();
+    mHeader.BufferSize                 = mJackTrip->getBufferSizeInSamples();
+    mHeader.SamplingRate               = mJackTrip->getSampleRateType();
+    mHeader.BitResolution              = mJackTrip->getAudioBitResolution();
+    mHeader.NumIncomingChannelsFromNet = mJackTrip->getNumOutputChannels();
+
+    if (mJackTrip->getNumInputChannels() == mJackTrip->getNumOutputChannels()) {
+        mHeader.NumOutgoingChannelsToNet = 0;
+    } else if (0 == mJackTrip->getNumInputChannels()) {
+        mHeader.NumOutgoingChannelsToNet = std::numeric_limits<uint8_t>::max();
+    } else {
+        mHeader.NumOutgoingChannelsToNet = mJackTrip->getNumInputChannels();
+    }
 }
 
-
 //***********************************************************************
-void DefaultHeader::checkPeerSettings(int8_t* full_packet)
+bool DefaultHeader::checkPeerSettings(int8_t* full_packet)
 {
     bool error = false;
+    QString report;
 
     DefaultHeaderStruct* peer_header;
-    peer_header =  reinterpret_cast<DefaultHeaderStruct*>(full_packet);
+    peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
 
     // Check Buffer Size
-    if ( peer_header->BufferSize != mHeader.BufferSize )
-    {
-        std::cerr << "WARNING: Peer Buffer Size is  : " << peer_header->BufferSize << endl;
-        std::cerr << "         Local Buffer Size is : " << mHeader.BufferSize << endl;
-        //std::cerr << "Make sure both machines use same buffer size" << endl;
-        //std::cerr << gPrintSeparator << endl;
-        //error = true;
+    if (peer_header->BufferSize != mHeader.BufferSize) {
+        if (mBufferRequiresSameSettings) {
+            std::cerr << "ERROR: Peer Buffer Size is  : " << peer_header->BufferSize
+                      << endl;
+            std::cerr << "       Local Buffer Size is : " << mHeader.BufferSize << endl;
+            std::cerr << "Make sure both machines use same buffer size" << endl;
+            std::cerr << gPrintSeparator << endl;
+            error = true;
+            report.append(QString("\n\nPeer Buffer Size is %1\nLocal Buffer Size is "
+                                  "%2\nMake sure both machines use the same Buffer Size")
+                              .arg(peer_header->BufferSize)
+                              .arg(mHeader.BufferSize));
+        } else {
+            std::cerr << "WARNING: Peer Buffer Size is  : " << peer_header->BufferSize
+                      << endl;
+            std::cerr << "         Local Buffer Size is : " << mHeader.BufferSize << endl;
+        }
     }
 
     // Check Sampling Rate
-    if ( peer_header->SamplingRate != mHeader.SamplingRate )
-    {
-        std::cerr << "ERROR: Peer Sampling Rate is   : " <<
-                     AudioInterface::getSampleRateFromType
-                     ( static_cast<AudioInterface::samplingRateT>(peer_header->SamplingRate) ) << endl;
-        std::cerr << "       Local Sampling Rate is  : " <<
-                     AudioInterface::getSampleRateFromType
-                     ( static_cast<AudioInterface::samplingRateT>(mHeader.SamplingRate) ) << endl;
+    if (peer_header->SamplingRate != mHeader.SamplingRate) {
+        int peerRate = AudioInterface::getSampleRateFromType(
+            static_cast<AudioInterface::samplingRateT>(peer_header->SamplingRate));
+        int localRate = AudioInterface::getSampleRateFromType(
+            static_cast<AudioInterface::samplingRateT>(mHeader.SamplingRate));
+        std::cerr << "ERROR: Peer Sampling Rate is   : " << peerRate << endl;
+        std::cerr << "       Local Sampling Rate is  : " << localRate << endl;
         std::cerr << "Make sure both machines use the same Sampling Rate" << endl;
         std::cerr << gPrintSeparator << endl;
         error = true;
+        report.append(QString("\n\nPeer Sampling Rate is %1\nLocal Sampling Rate is "
+                              "%2\nMake sure both machines use the same Sampling Rate")
+                          .arg(peerRate)
+                          .arg(localRate));
     }
 
     // Check Audio Bit Resolution
-    if ( peer_header->BitResolution != mHeader.BitResolution )
-    {
+    if (peer_header->BitResolution != mHeader.BitResolution) {
         std::cerr << "ERROR: Peer Audio Bit Resolution is  : "
                   << static_cast<int>(peer_header->BitResolution) << endl;
         std::cerr << "       Local Audio Bit Resolution is : "
@@ -164,187 +178,174 @@ void DefaultHeader::checkPeerSettings(int8_t* full_packet)
         std::cerr << "Make sure both machines use the same Bit Resolution" << endl;
         std::cerr << gPrintSeparator << endl;
         error = true;
+        report.append(
+            QString("\n\nPeer Audio Bit Resolution is %1\nLocal Audio Bit Resolution is "
+                    "%2\nMake sure both machines use the same Bit Resolution")
+                .arg(peer_header->BitResolution)
+                .arg(mHeader.BitResolution));
     }
 
     // Exit program if error
-    if (error)
-    {
-        //std::cerr << "Exiting program..." << endl;
-        //std::exit(1);
-        //throw std::logic_error("Local and Peer Settings don't match");
-        emit signalError("Local and Peer Settings don't match");
+    if (error) {
+        // std::cerr << "Exiting program..." << endl;
+        // std::exit(1);
+        // throw std::logic_error("Local and Peer Settings don't match");
+        emit signalError(QString("Local and Peer Settings don't match").append(report));
     }
+
+    return !error;
     /// \todo Check number of channels and other parameters
 }
 
-
 //***********************************************************************
 void DefaultHeader::printHeader() const
 {
     cout << "Default Packet Header:" << endl;
-    cout << "Buffer Size               = " << static_cast<int>(mHeader.BufferSize) << endl;
+    cout << "Buffer Size               = " << static_cast<int>(mHeader.BufferSize)
+         << endl;
     // Get the sample rate in Hz form the AudioInterface::samplingRateT
-    int sample_rate =
-            AudioInterface::getSampleRateFromType
-            ( static_cast<AudioInterface::samplingRateT>(mHeader.SamplingRate) );
-    cout << "Sampling Rate             = " << sample_rate << endl;
-    cout << "Audio Bit Resolutions     = " << static_cast<int>(mHeader.BitResolution) << endl;
-    //cout << "Number of Input Channels  = " << static_cast<int>(mHeader.NumInChannels) << endl;
-    //cout << "Number of Output Channels = " << static_cast<int>(mHeader.NumOutChannels) << endl;
-    cout << "Number of Channels        = " << static_cast<int>(mHeader.NumChannels) << endl;
-    cout << "Sequence Number           = " << static_cast<int>(mHeader.SeqNumber) << endl;
-    cout << "Time Stamp                = " << mHeader.TimeStamp << endl;
-    cout << "Connection Mode           = " << static_cast<int>(mHeader.ConnectionMode) << endl;
-    cout << gPrintSeparator << endl;
-    //cout << sizeof(mHeader) << endl;
+    int sample_rate = AudioInterface::getSampleRateFromType(
+        static_cast<AudioInterface::samplingRateT>(mHeader.SamplingRate));
+    // clang-format off
+    cout << "Sampling Rate               = " << sample_rate << "\n"
+            "Audio Bit Resolutions       = " << static_cast<int>(mHeader.BitResolution) << "\n"
+            "Number of Incoming Channels = " << static_cast<int>(mHeader.NumIncomingChannelsFromNet) << "\n"
+            "Number of Outgoing Channels = " << static_cast<int>(mHeader.NumOutgoingChannelsToNet) << "\n"
+            "Sequence Number             = " << static_cast<int>(mHeader.SeqNumber) << "\n"
+            "Time Stamp                  = " << mHeader.TimeStamp << "\n"
+            << gPrintSeparator << "\n";
+    // clang-format on
 }
 
-
-
 //***********************************************************************
 uint64_t DefaultHeader::getPeerTimeStamp(int8_t* full_packet) const
 {
     DefaultHeaderStruct* peer_header;
-    peer_header =  reinterpret_cast<DefaultHeaderStruct*>(full_packet);
+    peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
     return peer_header->TimeStamp;
 }
 
-
 //***********************************************************************
 uint16_t DefaultHeader::getPeerSequenceNumber(int8_t* full_packet) const
 {
     DefaultHeaderStruct* peer_header;
-    peer_header =  reinterpret_cast<DefaultHeaderStruct*>(full_packet);
+    peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
     return peer_header->SeqNumber;
 }
 
-
 //***********************************************************************
 uint16_t DefaultHeader::getPeerBufferSize(int8_t* full_packet) const
 {
     DefaultHeaderStruct* peer_header;
-    peer_header =  reinterpret_cast<DefaultHeaderStruct*>(full_packet);
+    peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
     return peer_header->BufferSize;
 }
 
-
 //***********************************************************************
-uint8_t  DefaultHeader::getPeerSamplingRate(int8_t* full_packet) const
+uint8_t DefaultHeader::getPeerSamplingRate(int8_t* full_packet) const
 {
     DefaultHeaderStruct* peer_header;
-    peer_header =  reinterpret_cast<DefaultHeaderStruct*>(full_packet);
+    peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
     return peer_header->SamplingRate;
 }
 
-
 //***********************************************************************
 uint8_t DefaultHeader::getPeerBitResolution(int8_t* full_packet) const
 {
     DefaultHeaderStruct* peer_header;
-    peer_header =  reinterpret_cast<DefaultHeaderStruct*>(full_packet);
+    peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
     return peer_header->BitResolution;
 }
 
-
 //***********************************************************************
-uint8_t DefaultHeader::getPeerNumChannels(int8_t* full_packet) const
+uint8_t DefaultHeader::getPeerNumIncomingChannels(int8_t* full_packet) const
 {
     DefaultHeaderStruct* peer_header;
-    peer_header =  reinterpret_cast<DefaultHeaderStruct*>(full_packet);
-    return peer_header->NumChannels;
+    peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
+    return peer_header->NumIncomingChannelsFromNet;
 }
 
-
-//***********************************************************************
-uint8_t DefaultHeader::getPeerConnectionMode(int8_t* full_packet) const
+uint8_t DefaultHeader::getPeerNumOutgoingChannels(int8_t* full_packet) const
 {
     DefaultHeaderStruct* peer_header;
-    peer_header =  reinterpret_cast<DefaultHeaderStruct*>(full_packet);
-    return static_cast<uint8_t>(peer_header->ConnectionMode);
+    peer_header = reinterpret_cast<DefaultHeaderStruct*>(full_packet);
+    return peer_header->NumOutgoingChannelsToNet;
 }
 
-
-
-
-
-
 //#######################################################################
 //####################### JamLinkHeader #################################
 //#######################################################################
 //***********************************************************************
-JamLinkHeader::JamLinkHeader(JackTrip* jacktrip) :
-    PacketHeader(jacktrip), mJackTrip(jacktrip)
+JamLinkHeader::JamLinkHeader(JackTrip* jacktrip) : PacketHeader(jacktrip)
 {
-    mHeader.Common = 0;
+    mHeader.Common    = 0;
     mHeader.SeqNumber = 0;
     mHeader.TimeStamp = 0;
 }
 
-
 //***********************************************************************
 void JamLinkHeader::fillHeaderCommonFromAudio()
 {
     // Check number of channels
     int num_inchannels = mJackTrip->getNumInputChannels();
-    if ( num_inchannels != 1 ) {
-        //std::cerr << "ERROR: JamLink only support ONE channel. Run JackTrip using only one channel"
+    if (num_inchannels != 1) {
+        // std::cerr << "ERROR: JamLink only support ONE channel. Run JackTrip using only
+        // one channel"
         //           << endl;
-        //std::exit(1);
-        //std::cerr << "WARINING: JamLink only support ONE channel. Run JackTrip using only one channel" << endl;
-        //throw std::logic_error("JamLink only support ONE channel. Run JackTrip using only one channel");
-        emit signalError("JamLink only support ONE channel. Run JackTrip using only one channel");
-
+        // std::exit(1);
+        // std::cerr << "WARINING: JamLink only support ONE channel. Run JackTrip using
+        // only one channel" << endl; throw std::logic_error("JamLink only support ONE
+        // channel. Run JackTrip using only one channel");
+        emit signalError(
+            "JamLink only supports ONE channel. Run JackTrip using only one channel");
     }
 
     // Sampling Rate
     int rate_type = mJackTrip->getSampleRateType();
-    if ( rate_type != AudioInterface::SR48 ) {
-        //std::cerr << "WARINING: JamLink only support 48kHz for communication with JackTrip at the moment." << endl;
-        //throw std::logic_error("ERROR: JamLink only support 48kHz for communication with JackTrip at the moment.");
-        emit signalError("ERROR: JamLink only support 48kHz for communication with JackTrip at the moment.");
+    if (rate_type != AudioInterface::SR48) {
+        // std::cerr << "WARINING: JamLink only support 48kHz for communication with
+        // JackTrip at the moment." << endl; throw std::logic_error("ERROR: JamLink only
+        // support 48kHz for communication with JackTrip at the moment.");
+        emit signalError(
+            "JamLink only supports 48kHz for communication with JackTrip at the moment.");
     }
 
     // Check Buffer Size
     int buf_size = mJackTrip->getBufferSizeInSamples();
-    if ( buf_size != 64 ) {
-        //std::cerr << "WARINING: JamLink only support 64 buffer size for communication with JackTrip at the moment." << endl;
-        //throw std::logic_error("ERROR: JamLink only support 64 buffer size for communication with JackTrip at the moment.");
-        emit signalError("ERROR: JamLink only support 64 buffer size for communication with JackTrip at the moment.");
+    if (buf_size != 64) {
+        // std::cerr << "WARINING: JamLink only support 64 buffer size for communication
+        // with JackTrip at the moment." << endl; throw std::logic_error("ERROR: JamLink
+        // only support 64 buffer size for communication with JackTrip at the moment.");
+        emit signalError(
+            "JamLink only supports a buffer size of 64 for communication with JackTrip "
+            "at the moment.");
     }
 
     mHeader.Common = (ETX_MONO | ETX_16BIT | ETX_XTND) + 64;
-    switch (rate_type)
-    {
-    case AudioInterface::SR48 :
+    switch (rate_type) {
+    case AudioInterface::SR48:
         mHeader.Common = (mHeader.Common | ETX_48KHZ);
         break;
-    case AudioInterface::SR44 :
+    case AudioInterface::SR44:
         mHeader.Common = (mHeader.Common | ETX_44KHZ);
         break;
-    case AudioInterface::SR32 :
+    case AudioInterface::SR32:
         mHeader.Common = (mHeader.Common | ETX_32KHZ);
         break;
-    case AudioInterface::SR22 :
+    case AudioInterface::SR22:
         mHeader.Common = (mHeader.Common | ETX_22KHZ);
         break;
     default:
-        //std::cerr << "ERROR: Sample rate not supported by JamLink" << endl;
-        //std::exit(1);
-        //throw std::out_of_range("Sample rate not supported by JamLink");
+        // std::cerr << "ERROR: Sample rate not supported by JamLink" << endl;
+        // std::exit(1);
+        // throw std::out_of_range("Sample rate not supported by JamLink");
         emit signalError("Sample rate not supported by JamLink.");
         break;
     }
 }
 
-
-
-
-
-
 //#######################################################################
 //####################### EmptyHeader #################################
 //#######################################################################
 //***********************************************************************
-EmptyHeader::EmptyHeader(JackTrip* jacktrip) :
-    PacketHeader(jacktrip), mJackTrip(jacktrip)
-{}
+EmptyHeader::EmptyHeader(JackTrip* jacktrip) : PacketHeader(jacktrip) {}
index 80f38b888ccbe7d67d62ab5b40bf6977c9f2ac64..b835dc0b32ec214c55797b39b3732cb8f6e90ac8 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
 
 #include <iostream>
 //#include <tr1/memory> // for shared_ptr
-#include <cstring>
-
 #include <QObject>
 #include <QString>
+#include <cstring>
 
-#include "jacktrip_types.h"
 #include "jacktrip_globals.h"
-class JackTrip; // Forward Declaration
-
+#include "jacktrip_types.h"
+class JackTrip;  // Forward Declaration
 
 /// \brief Abstract Header Struct, Header Stucts should subclass it
-struct HeaderStruct{};
+struct HeaderStruct {
+};
 
 /// \brief Default Header Struct
-struct DefaultHeaderStruct : public HeaderStruct
-{
-public:
+struct DefaultHeaderStruct : public HeaderStruct {
+   public:
     // watch out for alignment...
-    uint64_t TimeStamp; ///< Time Stamp
-    uint16_t SeqNumber; ///< Sequence Number
-    uint16_t BufferSize; ///< Buffer Size in Samples
-    uint8_t  SamplingRate; ///< Sampling Rate in JackAudioInterface::samplingRateT
-    uint8_t BitResolution; ///< Audio Bit Resolution
-    //uint8_t  NumInChannels; ///< Number of Input Channels
-    //uint8_t  NumOutChannels; ///<  Number of Output Channels
-    uint8_t  NumChannels; ///< Number of Channels, we assume input and outputs are the same
-    uint8_t  ConnectionMode;
+    uint64_t TimeStamp;     ///< Time Stamp
+    uint16_t SeqNumber;     ///< Sequence Number
+    uint16_t BufferSize;    ///< Buffer Size in Samples
+    uint8_t SamplingRate;   ///< Sampling Rate in JackAudioInterface::samplingRateT
+    uint8_t BitResolution;  ///< Audio Bit Resolution
+    uint8_t NumIncomingChannelsFromNet;  ///< Number of incoming Channels from the network
+    uint8_t NumOutgoingChannelsToNet;    ///< Number of outgoing Channels to the network
 };
 
 //---------------------------------------------------------
-//JamLink UDP Header:
+// JamLink UDP Header:
 /************************************************************************/
 /* values for the UDP stream type                                       */
 /* streamType is a 16-bit value at the head of each UDP stream          */
@@ -80,34 +76,31 @@ public:
 /*         4-22 Khz, 5-16 Khz, 6-11 Khz, 7-8 Khz                        */
 /* B8-0: Samples in packet                                              */
 /************************************************************************/
-const unsigned short ETX_RSVD = (0<<15);
-const unsigned short ETX_XTND = (1<<14);
-const unsigned short ETX_STEREO = (1<<13);
-const unsigned short ETX_MONO = (0<<13);
-const unsigned short ETX_16BIT = (0<<12);
-//inline unsigned short ETX_RATE_MASK(const unsigned short a) { a&(0x7<<9); }
-const unsigned short ETX_48KHZ = (0<<9);
-const unsigned short ETX_44KHZ = (1<<9);
-const unsigned short ETX_32KHZ = (2<<9);
-const unsigned short ETX_24KHZ = (3<<9);
-const unsigned short ETX_22KHZ = (4<<9);
-const unsigned short ETX_16KHZ = (5<<9);
-const unsigned short ETX_11KHZ = (6<<9);
-const unsigned short ETX_8KHZ  = (7<<9);
+const unsigned short ETX_RSVD   = (0 << 15);
+const unsigned short ETX_XTND   = (1 << 14);
+const unsigned short ETX_STEREO = (1 << 13);
+const unsigned short ETX_MONO   = (0 << 13);
+const unsigned short ETX_16BIT  = (0 << 12);
+// inline unsigned short ETX_RATE_MASK(const unsigned short a) { a&(0x7<<9); }
+const unsigned short ETX_48KHZ = (0 << 9);
+const unsigned short ETX_44KHZ = (1 << 9);
+const unsigned short ETX_32KHZ = (2 << 9);
+const unsigned short ETX_24KHZ = (3 << 9);
+const unsigned short ETX_22KHZ = (4 << 9);
+const unsigned short ETX_16KHZ = (5 << 9);
+const unsigned short ETX_11KHZ = (6 << 9);
+const unsigned short ETX_8KHZ  = (7 << 9);
 // able to express up to 512 SPP
-//inline unsigned short  ETX_SPP(const unsigned short a) { (a&0x01FF); }
+// inline unsigned short  ETX_SPP(const unsigned short a) { (a&0x01FF); }
 
 /// \brief JamLink Header Struct
-struct JamLinkHeaderStuct : public HeaderStruct
-{
+struct JamLinkHeaderStuct : public HeaderStruct {
     // watch out for alignment -- need to be on 4 byte chunks
-    uint16_t Common; ///< Common part of the header, 16 bit
-    uint16_t SeqNumber; ///< Sequence Number
-    uint32_t TimeStamp; ///< Time Stamp
+    uint16_t Common;     ///< Common part of the header, 16 bit
+    uint16_t SeqNumber;  ///< Sequence Number
+    uint32_t TimeStamp;  ///< Time Stamp
 };
 
-
-
 //#######################################################################
 //####################### PacketHeader ##################################
 //#######################################################################
@@ -118,7 +111,7 @@ class PacketHeader : public QObject
 {
     Q_OBJECT;
 
-public:
+   public:
     /// \brief The class Constructor
     PacketHeader(JackTrip* jacktrip);
     /// \brief The class Destructor
@@ -130,52 +123,54 @@ public:
     /// \todo Implement this using a JackTrip Method (Mediator) member instead of the
     /// reference to JackAudio
     virtual void fillHeaderCommonFromAudio() = 0;
-    /// \brief Parse the packet header and take appropriate measures (like change settings, or
-    /// quit the program if peer settings don't match)
+    /// \brief Parse the packet header and take appropriate measures (like change
+    /// settings, or quit the program if peer settings don't match)
     virtual void parseHeader() = 0;
-    virtual void checkPeerSettings(int8_t* full_packet) = 0;
-
-    virtual uint64_t getPeerTimeStamp(int8_t* full_packet) const = 0;
-    virtual uint16_t getPeerSequenceNumber(int8_t* full_packet) const = 0;
-    virtual uint16_t getPeerBufferSize(int8_t* full_packet) const = 0;
-    virtual uint8_t  getPeerSamplingRate(int8_t* full_packet) const = 0;
-    virtual uint8_t getPeerBitResolution(int8_t* full_packet) const = 0;
-    virtual uint8_t  getPeerNumChannels(int8_t* full_packet) const = 0;
-    virtual uint8_t  getPeerConnectionMode(int8_t* full_packet) const = 0;
+    /// \brief Check that the settings in the supplied packet header match the server's
+    /// settings \return True if settings match, false otherwise
+    virtual bool checkPeerSettings(int8_t* full_packet) = 0;
+
+    virtual uint64_t getPeerTimeStamp(int8_t* full_packet) const          = 0;
+    virtual uint16_t getPeerSequenceNumber(int8_t* full_packet) const     = 0;
+    virtual uint16_t getPeerBufferSize(int8_t* full_packet) const         = 0;
+    virtual uint8_t getPeerSamplingRate(int8_t* full_packet) const        = 0;
+    virtual uint8_t getPeerBitResolution(int8_t* full_packet) const       = 0;
+    virtual uint8_t getPeerNumIncomingChannels(int8_t* full_packet) const = 0;
+    virtual uint8_t getPeerNumOutgoingChannels(int8_t* full_packet) const = 0;
 
     /// \brief Increase sequence number for counter, a 16bit number
-    virtual void increaseSequenceNumber()
-    { mSeqNumber++; }
+    virtual void increaseSequenceNumber() { mSeqNumber++; }
     /// \brief Returns the current sequence number
     /// \return 16bit Sequence number
-    virtual uint16_t getSequenceNumber() const
-    { return mSeqNumber; }
+    virtual uint16_t getSequenceNumber() const { return mSeqNumber; }
     /// \brief Get the header size in bytes
     virtual int getHeaderSizeInBytes() const = 0;
     virtual void putHeaderInPacketBaseClass(int8_t* full_packet,
                                             const HeaderStruct& header_struct)
     {
         std::memcpy(full_packet, reinterpret_cast<const void*>(&header_struct),
-                    getHeaderSizeInBytes() );
+                    getHeaderSizeInBytes());
     }
     /// \brief Put the header in buffer pointed by full_packet
     /// \param full_packet Pointer to full packet (audio+header). Size must be
     /// sizeof(header part) + sizeof(audio part)
     virtual void putHeaderInPacket(int8_t* full_packet) = 0;
+    void setBufferRequiresSameSettings(bool sameSettings)
+    {
+        mBufferRequiresSameSettings = sameSettings;
+    }
 
+   signals:
+    void signalError(const QString& error_message);
 
-signals:
-    void signalError(const QString &error_message);
-
+   protected:
+    bool mBufferRequiresSameSettings;
+    JackTrip* mJackTrip;  ///< JackTrip mediator class
 
-private:
+   private:
     uint16_t mSeqNumber;
-    JackTrip* mJackTrip; ///< JackTrip mediator class
 };
 
-
-
-
 //#######################################################################
 //####################### DefaultHeader #################################
 //#######################################################################
@@ -183,45 +178,41 @@ private:
  */
 class DefaultHeader : public PacketHeader
 {
-public:
-
+   public:
     DefaultHeader(JackTrip* jacktrip);
     virtual ~DefaultHeader() {}
 
-    virtual void fillHeaderCommonFromAudio();
-    virtual void parseHeader() {}
-    virtual void checkPeerSettings(int8_t* full_packet);
-    virtual void increaseSequenceNumber()
-    { mHeader.SeqNumber++; }
-    virtual uint16_t getSequenceNumber() const
-    { return mHeader.SeqNumber; }
-    virtual int getHeaderSizeInBytes() const { return sizeof(mHeader); }
-    virtual void putHeaderInPacket(int8_t* full_packet)
-    { putHeaderInPacketBaseClass(full_packet, mHeader); }
+    virtual void fillHeaderCommonFromAudio() override;
+    virtual void parseHeader() override {}
+    virtual bool checkPeerSettings(int8_t* full_packet) override;
+    virtual void increaseSequenceNumber() override { mHeader.SeqNumber++; }
+    virtual uint16_t getSequenceNumber() const override { return mHeader.SeqNumber; }
+    virtual int getHeaderSizeInBytes() const override { return sizeof(mHeader); }
+    virtual void putHeaderInPacket(int8_t* full_packet) override
+    {
+        putHeaderInPacketBaseClass(full_packet, mHeader);
+    }
     void printHeader() const;
-    uint8_t getConnectionMode() const
-    { return mHeader.ConnectionMode; }
-    uint8_t getNumChannels() const
-    { return mHeader.NumChannels; }
-
-
-    virtual uint64_t getPeerTimeStamp(int8_t* full_packet) const;
-    virtual uint16_t getPeerSequenceNumber(int8_t* full_packet) const;
-    virtual uint16_t getPeerBufferSize(int8_t* full_packet) const;
-    virtual uint8_t  getPeerSamplingRate(int8_t* full_packet) const;
-    virtual uint8_t getPeerBitResolution(int8_t* full_packet) const;
-    virtual uint8_t  getPeerNumChannels(int8_t* full_packet) const;
-    virtual uint8_t  getPeerConnectionMode(int8_t* full_packet) const;
-
-
-private:
-    DefaultHeaderStruct mHeader;///< Default Header Struct
-    JackTrip* mJackTrip; ///< JackTrip mediator class
+    uint8_t getNumIncomingChannelsFromNet() const
+    {
+        return mHeader.NumIncomingChannelsFromNet;
+    }
+    uint8_t getNumOutgoingChannelsToNet() const
+    {
+        return mHeader.NumOutgoingChannelsToNet;
+    }
+    virtual uint64_t getPeerTimeStamp(int8_t* full_packet) const override;
+    virtual uint16_t getPeerSequenceNumber(int8_t* full_packet) const override;
+    virtual uint16_t getPeerBufferSize(int8_t* full_packet) const override;
+    virtual uint8_t getPeerSamplingRate(int8_t* full_packet) const override;
+    virtual uint8_t getPeerBitResolution(int8_t* full_packet) const override;
+    uint8_t getPeerNumIncomingChannels(int8_t* full_packet) const override;
+    uint8_t getPeerNumOutgoingChannels(int8_t* full_packet) const override;
+
+   private:
+    DefaultHeaderStruct mHeader;  ///< Default Header Struct
 };
 
-
-
-
 //#######################################################################
 //####################### JamLinkHeader #################################
 //#######################################################################
@@ -230,34 +221,53 @@ private:
  */
 class JamLinkHeader : public PacketHeader
 {
-public:
-
+   public:
     JamLinkHeader(JackTrip* jacktrip);
     virtual ~JamLinkHeader() {}
 
-    virtual void fillHeaderCommonFromAudio();
-    virtual void parseHeader() {}
-    virtual void checkPeerSettings(int8_t* /*full_packet*/) {}
-
-    virtual uint64_t getPeerTimeStamp(int8_t* /*full_packet*/) const { return 0; }
-    virtual uint16_t getPeerSequenceNumber(int8_t* /*full_packet*/) const { return 0; }
-    virtual uint16_t getPeerBufferSize(int8_t* /*full_packet*/) const { return 0; }
-    virtual uint8_t  getPeerSamplingRate(int8_t* /*full_packet*/) const { return 0; }
-    virtual uint8_t getPeerBitResolution(int8_t* /*full_packet*/) const { return 0; }
-    virtual uint8_t  getPeerNumChannels(int8_t* /*full_packet*/) const { return 0; }
-    virtual uint8_t  getPeerConnectionMode(int8_t* /*full_packet*/) const { return 0; }
-
-    virtual void increaseSequenceNumber() {}
-    virtual int getHeaderSizeInBytes() const { return sizeof(mHeader); }
-    virtual void putHeaderInPacket(int8_t* full_packet)
-    { putHeaderInPacketBaseClass(full_packet, mHeader); }
-
-private:
-    JamLinkHeaderStuct mHeader; ///< JamLink Header Struct
-    JackTrip* mJackTrip; ///< JackTrip mediator class
-};
+    virtual void fillHeaderCommonFromAudio() override;
+    virtual void parseHeader() override {}
+    virtual bool checkPeerSettings(int8_t* /*full_packet*/) override { return true; }
 
+    virtual uint64_t getPeerTimeStamp(int8_t* /*full_packet*/) const override
+    {
+        return 0;
+    }
+    virtual uint16_t getPeerSequenceNumber(int8_t* /*full_packet*/) const override
+    {
+        return 0;
+    }
+    virtual uint16_t getPeerBufferSize(int8_t* /*full_packet*/) const override
+    {
+        return 0;
+    }
+    virtual uint8_t getPeerSamplingRate(int8_t* /*full_packet*/) const override
+    {
+        return 0;
+    }
+    virtual uint8_t getPeerBitResolution(int8_t* /*full_packet*/) const override
+    {
+        return 0;
+    }
+    uint8_t getPeerNumIncomingChannels(int8_t* /*full_packet*/) const override
+    {
+        return 0;
+    }
+    uint8_t getPeerNumOutgoingChannels(int8_t* /*full_packet*/) const override
+    {
+        return 0;
+    }
 
+    virtual void increaseSequenceNumber() override {}
+    virtual int getHeaderSizeInBytes() const override { return sizeof(mHeader); }
+    virtual void putHeaderInPacket(int8_t* full_packet) override
+    {
+        putHeaderInPacketBaseClass(full_packet, mHeader);
+    }
+
+   private:
+    JamLinkHeaderStuct mHeader;  ///< JamLink Header Struct
+};
 
 //#######################################################################
 //####################### EmptyHeader #################################
@@ -267,30 +277,46 @@ private:
  */
 class EmptyHeader : public PacketHeader
 {
-public:
-
+   public:
     EmptyHeader(JackTrip* jacktrip);
     virtual ~EmptyHeader() {}
 
-    virtual void fillHeaderCommonFromAudio() {}
-    virtual void parseHeader() {}
-    virtual void checkPeerSettings(int8_t* /*full_packet*/) {}
-    virtual void increaseSequenceNumber() {}
-    virtual int getHeaderSizeInBytes() const { return 0; }
-
-    virtual uint64_t getPeerTimeStamp(int8_t* /*full_packet*/) const { return 0; }
-    virtual uint16_t getPeerSequenceNumber(int8_t* /*full_packet*/) const { return 0; }
-    virtual uint16_t getPeerBufferSize(int8_t* /*full_packet*/) const { return 0; }
-    virtual uint8_t  getPeerSamplingRate(int8_t* /*full_packet*/) const { return 0; }
-    virtual uint8_t getPeerBitResolution(int8_t* /*full_packet*/) const { return 0; }
-    virtual uint8_t  getPeerNumChannels(int8_t* /*full_packet*/) const { return 0; }
-    virtual uint8_t  getPeerConnectionMode(int8_t* /*full_packet*/) const { return 0; }
+    virtual void fillHeaderCommonFromAudio() override {}
+    virtual void parseHeader() override {}
+    virtual bool checkPeerSettings(int8_t* /*full_packet*/) override { return true; }
+    virtual void increaseSequenceNumber() override {}
+    virtual int getHeaderSizeInBytes() const override { return 0; }
 
-    virtual void putHeaderInPacket(int8_t* /*full_packet*/) {}
+    virtual uint64_t getPeerTimeStamp(int8_t* /*full_packet*/) const override
+    {
+        return 0;
+    }
+    virtual uint16_t getPeerSequenceNumber(int8_t* /*full_packet*/) const override
+    {
+        return 0;
+    }
+    virtual uint16_t getPeerBufferSize(int8_t* /*full_packet*/) const override
+    {
+        return 0;
+    }
+    virtual uint8_t getPeerSamplingRate(int8_t* /*full_packet*/) const override
+    {
+        return 0;
+    }
+    virtual uint8_t getPeerBitResolution(int8_t* /*full_packet*/) const override
+    {
+        return 0;
+    }
+    uint8_t getPeerNumIncomingChannels(int8_t* /*full_packet*/) const override
+    {
+        return 0;
+    }
+    uint8_t getPeerNumOutgoingChannels(int8_t* /*full_packet*/) const override
+    {
+        return 0;
+    }
 
-private:
-    JackTrip* mJackTrip; ///< JackTrip mediator class
+    virtual void putHeaderInPacket(int8_t* /*full_packet*/) override {}
 };
 
-
-#endif //__PACKETHEADER_H__
+#endif  //__PACKETHEADER_H__
diff --git a/src/Patcher.cpp b/src/Patcher.cpp
new file mode 100644 (file)
index 0000000..daa47a7
--- /dev/null
@@ -0,0 +1,142 @@
+//*****************************************************************
+/*
+  JackTrip: A System for High-Quality Audio Network Performance
+  over the Internet
+
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
+  SoundWIRE group at CCRMA, Stanford University.
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation
+  files (the "Software"), to deal in the Software without
+  restriction, including without limitation the rights to use,
+  copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the
+  Software is furnished to do so, subject to the following
+  conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+  OTHER DEALINGS IN THE SOFTWARE.
+*/
+//*****************************************************************
+
+/**
+ * \file Patcher.cpp
+ * \author Aaron Wyatt
+ * \date September 2020
+ */
+
+#include "Patcher.h"
+
+Patcher::Patcher() : m_patchMode(JackTrip::SERVERTOCLIENT), m_jackClient(nullptr) {}
+
+void Patcher::setPatchMode(JackTrip::hubConnectionModeT patchMode)
+{
+    m_patchMode = patchMode;
+}
+
+void Patcher::registerClient(const QString& clientName)
+{
+    QMutexLocker locker(&m_connectionMutex);
+
+    if (!(m_patchMode == JackTrip::CLIENTECHO || m_patchMode == JackTrip::CLIENTFOFI
+          || m_patchMode == JackTrip::FULLMIX)) {
+        // Nothing to do here other than track our clients.
+        m_clients.append(clientName);
+        return;
+    }
+
+    // If our jack client isn't running, start it.
+    if (!m_jackClient) {
+        m_jackClient = jack_client_open("jthubpatcher", JackNoStartServer, &m_status);
+        if (!m_jackClient) {
+            std::cout << "Unable to start patcher JACK client: Patching disabled\n"
+                      << std::endl;
+            return;
+        } else {
+            jack_on_shutdown(m_jackClient, &Patcher::shutdownCallback, this);
+        }
+    }
+
+    const char **outPorts, **inPorts;
+    outPorts = jack_get_ports(m_jackClient, NULL, NULL, JackPortIsOutput);
+    inPorts  = jack_get_ports(m_jackClient, NULL, NULL, JackPortIsInput);
+
+    // Start with our receiving ports.
+    for (int i = 0; outPorts[i]; i++) {
+        QString client = QString(outPorts[i]).section(":", 0, 0);
+        if (client == clientName) {
+            QString channel = QString(outPorts[i]).section("_", -1, -1);
+            for (int j = 0; inPorts[j]; j++) {
+                // First check if this is one of our other clients. (Fan out/in and full
+                // mix.)
+                if (m_patchMode == JackTrip::CLIENTFOFI
+                    || m_patchMode == JackTrip::FULLMIX) {
+                    if (m_clients.contains(QString(inPorts[j]).section(":", 0, 0))
+                        && QString(inPorts[j]).section("_", -1, -1) == channel
+                        && !QString(outPorts[i]).contains("broadcast")) {
+                        jack_connect(m_jackClient, outPorts[i], inPorts[j]);
+                    }
+                }
+                // Then check if it's our registering client. (Client Echo and full mix.)
+                if (m_patchMode == JackTrip::CLIENTECHO
+                    || m_patchMode == JackTrip::FULLMIX) {
+                    if (QString(inPorts[j]).section(":", 0, 0) == clientName
+                        && QString(inPorts[j]).section("_", -1, -1) == channel
+                        && !QString(outPorts[i]).contains("broadcast")) {
+                        jack_connect(m_jackClient, outPorts[i], inPorts[j]);
+                    }
+                }
+            }
+        }
+    }
+
+    // Then our sending ports. We only need to check for other clients here.
+    //(Any loopback connections will have been made in the previous loop.)
+    if (m_patchMode == JackTrip::CLIENTFOFI || m_patchMode == JackTrip::FULLMIX) {
+        for (int i = 0; inPorts[i]; i++) {
+            QString client = QString(inPorts[i]).section(":", 0, 0);
+            if (client == clientName) {
+                QString channel = QString(inPorts[i]).section("_", -1, -1);
+                for (int j = 0; outPorts[j]; j++) {
+                    if (m_clients.contains(QString(outPorts[j]).section(":", 0, 0))
+                        && QString(outPorts[j]).section("_", -1, -1) == channel
+                        && !QString(outPorts[j]).contains("broadcast")) {
+                        jack_connect(m_jackClient, outPorts[j], inPorts[i]);
+                    }
+                }
+            }
+        }
+    }
+
+    m_clients.append(clientName);
+    jack_free(outPorts);
+    jack_free(inPorts);
+}
+
+void Patcher::unregisterClient(const QString& clientName)
+{
+    QMutexLocker locker(&m_connectionMutex);
+    m_clients.removeAll(clientName);
+}
+
+void Patcher::shutdownCallback(void* arg)
+{
+    Patcher* patcher = static_cast<Patcher*>(arg);
+    jack_client_close(patcher->m_jackClient);
+    patcher->m_jackClient = nullptr;
+}
+
+Patcher::~Patcher()
+{
+    if (m_jackClient) { jack_client_close(m_jackClient); }
+}
diff --git a/src/Patcher.h b/src/Patcher.h
new file mode 100644 (file)
index 0000000..5233524
--- /dev/null
@@ -0,0 +1,76 @@
+//*****************************************************************
+/*
+  JackTrip: A System for High-Quality Audio Network Performance
+  over the Internet
+
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
+  SoundWIRE group at CCRMA, Stanford University.
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation
+  files (the "Software"), to deal in the Software without
+  restriction, including without limitation the rights to use,
+  copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the
+  Software is furnished to do so, subject to the following
+  conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+  OTHER DEALINGS IN THE SOFTWARE.
+*/
+//*****************************************************************
+
+/**
+ * \file Patcher.h
+ * \author Aaron Wyatt
+ * \date September 2020
+ */
+
+#ifndef __PATCHER_H__
+#define __PATCHER_H__
+
+#include "JackTrip.h"
+#ifdef USE_WEAK_JACK
+#include "weak_libjack.h"
+#else
+#include <jack/jack.h>
+#endif
+#include <QMutex>
+#include <QStringList>
+
+class Patcher : public QObject
+{
+    Q_OBJECT
+
+   public:
+    Patcher();
+    virtual ~Patcher();
+
+    void setPatchMode(JackTrip::hubConnectionModeT patchMode);
+
+    void registerClient(const QString& clientName);
+    void unregisterClient(const QString& clientName);
+
+    // Jack shutdown callback
+    static void shutdownCallback(void* arg);
+
+   private:
+    QStringList m_clients;
+    JackTrip::hubConnectionModeT m_patchMode;
+
+    jack_client_t* m_jackClient;
+    jack_status_t m_status;
+
+    QMutex m_connectionMutex;
+};
+
+#endif  // __PATCHER_H__
diff --git a/src/PoolBuffer.cpp b/src/PoolBuffer.cpp
new file mode 100644 (file)
index 0000000..f07d77a
--- /dev/null
@@ -0,0 +1,511 @@
+//*****************************************************************
+/*
+  JackTrip: A System for High-Quality Audio Network Performance
+  over the Internet
+
+  Copyright (c) 2021 Juan-Pablo Caceres, Chris Chafe.
+  SoundWIRE group at CCRMA, Stanford University.
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation
+  files (the "Software"), to deal in the Software without
+  restriction, including without limitation the rights to use,
+  copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the
+  Software is furnished to do so, subject to the following
+  conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+  OTHER DEALINGS IN THE SOFTWARE.
+*/
+//*****************************************************************
+
+/**
+ * \file PoolBuffer.cpp
+ * \author Chris Chafe
+ * \date May 2021
+ */
+
+// EXPERIMENTAL for testing in JackTrip v1.4.0
+// runs ok from FPP 16 up to 512, but don't try 1024 yet
+// in / out channels are the same -- mono, stereo and -n3 tested fine
+
+// for example, server
+// jacktrip -S --udprt  -p1 --bufstrategy 3 -q2
+// and client
+// jacktrip -C cmn9.stanford.edu --udprt --bufstrategy 3 -q2
+
+#include "PoolBuffer.h"
+
+#include <iomanip>
+
+#include "jacktrip_globals.h"
+using std::cout;
+using std::endl;
+using std::setw;
+
+#define STDDEVINDOW     200  // packets
+#define STDDEV2POOLSIZE 30.0
+#define MAXPOOLSIZE     6000  // insanely large pool, 2 sec FPP16
+#define HIST            6     // at FPP32
+#define OUT(x, ch, s)   sampleToBits(x, ch, s)
+// from listening tests iteration performs better than '=' operator
+#define PACKETSAMP (int s = 0; s < mFPP; s++)
+
+//*******************************************************************************
+PoolBuffer::PoolBuffer(int /*sample_rate*/, int channels, int bit_res, int FPP, int qLen)
+    : RingBuffer(0, 0)
+    , mNumChannels(channels)
+    , mAudioBitRes(bit_res)
+    , mFPP(FPP)
+    , mPoolSize(qLen)
+    , mQlen(qLen)
+{
+    switch (mAudioBitRes) {  // int from JitterBuffer to AudioInterface enum
+    case 1:
+        mBitResolutionMode = AudioInterface::audioBitResolutionT::BIT8;
+        break;
+    case 2:
+        mBitResolutionMode = AudioInterface::audioBitResolutionT::BIT16;
+        break;
+    case 3:
+        mBitResolutionMode = AudioInterface::audioBitResolutionT::BIT24;
+        break;
+    case 4:
+        mBitResolutionMode = AudioInterface::audioBitResolutionT::BIT32;
+        break;
+    }
+    mHist            = 6 * 32;                // samples, from original settings
+    double histFloat = mHist / (double)mFPP;  // packets for other FPP
+    mHist            = (int)histFloat;
+    if (!mHist)
+        mHist++;  // min packets
+    else if (mHist > 6)
+        mHist = 6;  // max packets
+    if (gVerboseFlag) cout << "mHist = " << mHist << " at " << mFPP << "\n";
+    //    qDebug() << "mHist =" << mHist << "@" << mFPP;
+    mBytes     = mFPP * mNumChannels * mBitResolutionMode;
+    mXfrBuffer = new int8_t[mBytes];
+    mPacketCnt = 0;  // burg
+    mFadeUp.resize(mFPP, 0.0);
+    mFadeDown.resize(mFPP, 0.0);
+    for (int i = 0; i < mFPP; i++) {
+        mFadeUp[i]   = (double)i / (double)mFPP;
+        mFadeDown[i] = 1.0 - mFadeUp[i];
+    }
+    mLastWasGlitch = false;
+    mOutgoingCnt   = 0;
+    for (int i = 0; i < mPoolSize; i++) {
+        int8_t* tmp = new int8_t[mBytes];
+        mIncomingDat.push_back(tmp);
+    }
+    mZeros = new int8_t[mBytes];
+    for
+        PACKETSAMP OUT(0.0, 0, s);
+    for
+        PACKETSAMP OUT(0.0, 1, s);
+    memcpy(mZeros, mXfrBuffer, mBytes);
+    mIncomingCnt = 0;
+    mIndexPool.resize(mPoolSize);
+    for (int i = 0; i < mPoolSize; i++) mIndexPool[i] = -1;
+    mTimer0 = new QElapsedTimer();
+    mTimer0->start();
+    mGlitchCnt = 0;
+    mGlitchMax = mHist * 2 * mFPP;  // tested with 400 @ FPP32
+    for (int i = 0; i < mNumChannels; i++) {
+        ChanData* tmp = new ChanData(i, mFPP, mHist);
+        mChanData.push_back(tmp);
+    }
+    stdDev = new StdDev(STDDEVINDOW);
+}
+
+//*******************************************************************************
+bool PoolBuffer::pushPacket(const int8_t* buf)
+{
+    QMutexLocker locker(&mMutex);
+
+    mIncomingCnt++;
+    if (mGlitchCnt > mGlitchMax) {
+        //        double elapsed0 = (double)mTimer0->nsecsElapsed() / 1000000.0;
+        //        qDebug() << mGlitchCnt << mIncomingCnt << mOutgoingCnt
+        //                 << elapsed0/1000.0 << "\n";
+        mIncomingCnt = mOutgoingCnt;
+        mGlitchCnt   = 0;
+    }
+    int oldest      = 214748364;  // not so BIGNUM, approx. 2^31-1 / 10
+    int oldestIndex = 0;
+    for (int i = 0; i < mPoolSize; i++) {
+        if (mIndexPool[i] < oldest) {
+            oldest      = mIndexPool[i];
+            oldestIndex = i;
+        }
+    }
+    mIndexPool[oldestIndex] = mIncomingCnt;
+    memcpy(mIncomingDat[oldestIndex], buf, mBytes);
+    //        qDebug() << oldestIndex << mIndexPool[oldestIndex];
+
+    stdDev->tick();
+    if (stdDev->longTermStdDevAcc > 0.0) {
+        double FPPfactor = 0.25 + (32 / (double)mFPP);
+        int newPoolSize  = (int)(stdDev->longTermStdDev * STDDEV2POOLSIZE * FPPfactor);
+        if (newPoolSize > mPoolSize) {
+            if (newPoolSize > MAXPOOLSIZE)
+                newPoolSize = MAXPOOLSIZE;  // avoid insanely large pool
+            mIndexPool.resize(newPoolSize);
+            for (int i = mPoolSize; i < newPoolSize; i++) {
+                int8_t* tmp = new int8_t[mBytes];
+                mIncomingDat.push_back(tmp);
+            }
+            if (gVerboseFlag)
+                cout << "growing to " << newPoolSize << " from " << mPoolSize << "\n";
+            mPoolSize = newPoolSize;
+        }
+        if (newPoolSize != mPoolSize) {
+            if (newPoolSize < mQlen) newPoolSize = mQlen;  // avoid insanely small pool
+            if (gVerboseFlag)
+                cout << "shrinking to " << newPoolSize << " from " << mPoolSize << "\n";
+            mPoolSize = newPoolSize;
+        }
+        //            qDebug() << (int) (stdDev->longTermStdDev*30.0);
+    }
+    return true;
+};
+
+//*******************************************************************************
+void PoolBuffer::pullPacket(int8_t* buf)
+{
+    QMutexLocker locker(&mMutex);
+    mOutgoingCnt++;  // will saturate in 33 days at FPP 32
+    //    (/ (* (- (expt 2 32) 1) (/ 32 48000.0)) (* 60 60 24))
+    bool glitch     = false;
+    int target      = mOutgoingCnt - mQlen;
+    int targetIndex = mPoolSize;
+    int oldest      = 999999;
+    int oldestIndex = 0;
+    for (int i = 0; i < mPoolSize; i++) {
+        if (mIndexPool[i] == target) { targetIndex = i; }
+        if (mIndexPool[i] < oldest) {
+            oldest      = mIndexPool[i];
+            oldestIndex = i;
+        }
+    }
+    if (targetIndex == mPoolSize) {
+        //            qDebug() << " ";
+        //            qDebug() << "!available" << target;
+        //            for ( int i = 0; i < POOLSIZE; i++ ) qDebug() << i << mIndexPool[i];
+        //            qDebug() << " ";
+        targetIndex             = oldestIndex;
+        mIndexPool[targetIndex] = -1;
+        glitch                  = true;
+        mGlitchCnt++;
+        //            QThread::usleep(450); force lateness for debugging
+    } else {
+        mIndexPool[targetIndex] = 0;
+        memcpy(mXfrBuffer, mIncomingDat[targetIndex], mBytes);
+    }
+    if (mIncomingCnt) {
+        processPacket(glitch);
+    } else {
+        memcpy(mXfrBuffer, mZeros, mBytes);
+    }
+    memcpy(buf, mXfrBuffer, mBytes);
+};
+
+//*******************************************************************************
+void PoolBuffer::processPacket(bool glitch)
+{
+    for (int ch = 0; ch < mNumChannels; ch++)
+        processChannel(ch, glitch, mPacketCnt, mLastWasGlitch);
+    mLastWasGlitch = glitch;
+    mPacketCnt++;
+}
+
+//*******************************************************************************
+void PoolBuffer::processChannel(int ch, bool glitch, int packetCnt, bool lastWasGlitch)
+{
+    //    if(glitch) qDebug() << "glitch"; else fprintf(stderr,".");
+
+    ChanData* cd = mChanData[ch];
+    for
+        PACKETSAMP cd->mTruth[s] = bitsToSample(ch, s);
+    if (packetCnt) {
+        for (int i = 0; i < mHist; i++) {
+            for
+                PACKETSAMP cd->mTrain[s + ((mHist - (i + 1)) * mFPP)] =
+                    cd->mLastPackets[i][s];
+        }
+
+        // GET LINEAR PREDICTION COEFFICIENTS
+        ba.train(cd->mCoeffs, cd->mTrain);
+
+        // LINEAR PREDICT DATA
+        vector<sample_t> tail(cd->mTrain);
+
+        ba.predict(cd->mCoeffs, tail);  // resizes to TRAINSAMPS-2 + TRAINSAMPS
+
+        for (int i = 0; i < (cd->trainSamps - 1); i++)
+            cd->mPrediction[i] = tail[i + cd->trainSamps];
+
+        for
+            PACKETSAMP cd->mXfadedPred[s] =
+                cd->mTruth[s] * mFadeUp[s] + cd->mNextPred[s] * mFadeDown[s];
+
+        for
+            PACKETSAMP
+        OUT((glitch) ? cd->mPrediction[s]
+                     : ((lastWasGlitch) ? cd->mXfadedPred[s] : cd->mTruth[s]),
+            ch, s);
+
+        for
+            PACKETSAMP cd->mNextPred[s] = cd->mPrediction[s + mFPP];
+    }
+
+    // if mPacketCnt==0 initialization follows
+    for (int i = mHist - 1; i > 0; i--) {
+        for
+            PACKETSAMP cd->mLastPackets[i][s] = cd->mLastPackets[i - 1][s];
+    }
+
+    // will only be able to glitch if mPacketCnt>0
+    for
+        PACKETSAMP cd->mLastPackets[0][s] =
+            ((!glitch) || (packetCnt < mHist)) ? cd->mTruth[s] : cd->mPrediction[s];
+}
+
+//*******************************************************************************
+// copped from AudioInterface.cpp
+
+sample_t PoolBuffer::bitsToSample(int ch, int frame)
+{
+    sample_t sample = 0.0;
+    AudioInterface::fromBitToSampleConversion(
+        &mXfrBuffer[(frame * mBitResolutionMode * mNumChannels)
+                    + (ch * mBitResolutionMode)],
+        &sample, mBitResolutionMode);
+    return sample;
+}
+
+void PoolBuffer::sampleToBits(sample_t sample, int ch, int frame)
+{
+    AudioInterface::fromSampleToBitConversion(
+        &sample,
+        &mXfrBuffer[(frame * mBitResolutionMode * mNumChannels)
+                    + (ch * mBitResolutionMode)],
+        mBitResolutionMode);
+}
+
+//*******************************************************************************
+bool BurgAlgorithm::classify(double d)
+{
+    bool tmp = false;
+    switch (fpclassify(d)) {
+    case FP_INFINITE:
+        qDebug() << ("infinite");
+        tmp = true;
+        break;
+    case FP_NAN:
+        qDebug() << ("NaN");
+        tmp = true;
+        break;
+    case FP_ZERO:
+        //      qDebug() <<  ("zero");
+        tmp = true;
+        break;
+    case FP_SUBNORMAL:
+        qDebug() << ("subnormal");
+        tmp = true;
+        break;
+        //    case FP_NORMAL:    qDebug() <<  ("normal");    break;
+    }
+    //  if (signbit(d)) qDebug() <<  (" negative\n"); else qDebug() <<  (" positive or
+    //  unsigned\n");
+    return tmp;
+}
+
+void BurgAlgorithm::train(vector<long double>& coeffs, const vector<float>& x)
+{
+    // GET SIZE FROM INPUT VECTORS
+    size_t N = x.size() - 1;
+    size_t m = coeffs.size();
+
+    //        if (x.size() < m) qDebug() << "time_series should have more elements than
+    //        the AR order is";
+
+    // INITIALIZE Ak
+    vector<long double> Ak(m + 1, 0.0);
+    Ak[0] = 1.0;
+
+    // INITIALIZE f and b
+    vector<long double> f;
+    f.resize(x.size());
+    for (unsigned int i = 0; i < x.size(); i++) f[i] = x[i];
+    vector<long double> b(f);
+
+    // INITIALIZE Dk
+    long double Dk = 0.0;
+    for (size_t j = 0; j <= N; j++)  // CC: N is $#x-1 in C++ but $#x in perl
+    {
+        Dk += 2.00001 * f[j] * f[j];  // CC: needs more damping than orig 2.0
+    }
+    Dk -= f[0] * f[0] + b[N] * b[N];
+
+    //    qDebug() << "Dk" << qStringFromLongDouble1(Dk);
+    //        if ( classify(Dk) )
+    //        { qDebug() << pCnt << "init";
+    //        }
+
+    // BURG RECURSION
+    for (size_t k = 0; k < m; k++) {
+        // COMPUTE MU
+        long double mu = 0.0;
+        for (size_t n = 0; n <= N - k - 1; n++) { mu += f[n + k + 1] * b[n]; }
+
+        if (Dk == 0.0) Dk = 0.0000001;  // CC: from testing, needs eps
+        //            if ( classify(Dk) ) qDebug() << pCnt << "run";
+
+        mu *= -2.0 / Dk;
+        //            if ( isnan(Dk) )  { qDebug() << "k" << k; }
+        //            if (Dk==0.0) qDebug() << "k" << k << "Dk==0";
+
+        // UPDATE Ak
+        for (size_t n = 0; n <= (k + 1) / 2; n++) {
+            long double t1 = Ak[n] + mu * Ak[k + 1 - n];
+            long double t2 = Ak[k + 1 - n] + mu * Ak[n];
+            Ak[n]          = t1;
+            Ak[k + 1 - n]  = t2;
+        }
+
+        // UPDATE f and b
+        for (size_t n = 0; n <= N - k - 1; n++) {
+            long double t1 = f[n + k + 1] + mu * b[n];  // were double
+            long double t2 = b[n] + mu * f[n + k + 1];
+            f[n + k + 1]   = t1;
+            b[n]           = t2;
+        }
+
+        // UPDATE Dk
+        Dk = (1.0 - mu * mu) * Dk - f[k + 1] * f[k + 1] - b[N - k - 1] * b[N - k - 1];
+    }
+    // ASSIGN COEFFICIENTS
+    coeffs.assign(++Ak.begin(), Ak.end());
+}
+
+void BurgAlgorithm::predict(vector<long double>& coeffs, vector<float>& tail)
+{
+    size_t m = coeffs.size();
+    //    qDebug() << "tail.at(0)" << tail[0]*32768;
+    //    qDebug() << "tail.at(1)" << tail[1]*32768;
+    tail.resize(m + tail.size());
+    //    qDebug() << "tail.at(m)" << tail[m]*32768;
+    //    qDebug() << "tail.at(...end...)" << tail[tail.size()-1]*32768;
+    //    qDebug() << "m" << m << "tail.size()" << tail.size();
+    for (size_t i = m; i < tail.size(); i++) {
+        tail[i] = 0.0;
+        for (size_t j = 0; j < m; j++) { tail[i] -= coeffs[j] * tail[i - 1 - j]; }
+    }
+}
+
+//*******************************************************************************
+ChanData::ChanData(int i, int FPP, int hist) : ch(i)
+{
+    trainSamps = (hist * FPP);
+    mTruth.resize(FPP, 0.0);
+    mXfadedPred.resize(FPP, 0.0);
+    mNextPred.resize(FPP, 0.0);
+    for (int i = 0; i < hist; i++) {
+        vector<sample_t> tmp(FPP, 0.0);
+        mLastPackets.push_back(tmp);
+    }
+    mTrain.resize(trainSamps, 0.0);
+    mPrediction.resize(trainSamps - 1, 0.0);  // ORDER
+    mCoeffs.resize(trainSamps - 2, 0.0);
+}
+
+//*******************************************************************************
+StdDev::StdDev(int w) : window(w)
+{
+    reset();
+    longTermStdDev    = 0.0;
+    longTermStdDevAcc = 0.0;
+    longTermCnt       = 0;
+    lastMean          = 0.0;
+    lastMin           = 0;
+    lastMax           = 0;
+    mTimer            = new QElapsedTimer();
+    mTimer->start();
+    data.resize(w, 0.0);
+}
+
+void StdDev::reset()
+{
+    mean = 0.0;
+    //        varRunning = 0.0;
+    acc = 0.0;
+    min = 999999.0;
+    max = 0.0;
+    ctr = 0;
+};
+
+void StdDev::tick()
+{  // stdDev based on mean of last windowful
+    double msElapsed = (double)mTimer->nsecsElapsed() / 1000000.0;
+    mTimer->start();
+    if (ctr != window) {
+        data[ctr] = msElapsed;
+        if (msElapsed < min)
+            min = msElapsed;
+        else if (msElapsed > max)
+            max = msElapsed;
+        acc += msElapsed;
+        //        double tmp = msElapsed - mean; // last window
+        //        varRunning += (tmp*tmp);
+        ctr++;
+    } else {
+        mean       = (double)acc / (double)window;
+        double var = 0.0;
+        for (int i = 0; i < window; i++) {
+            double tmp = data[i] - mean;
+            var += (tmp * tmp);
+        }
+        //        varRunning /= (double) window;
+        //        stdDev = sqrt(varRunning);
+        //        qDebug() << mean << min << max << stdDev;
+        var /= (double)window;
+        double stdDev = sqrt(var);
+        if (longTermCnt) {
+            longTermStdDevAcc += stdDev;
+            longTermStdDev = longTermStdDevAcc / (double)longTermCnt;
+            //            qDebug() << mean << min << max << stdDev << longTermStdDev;
+            if (gVerboseFlag)
+                cout << setw(10) << mean << setw(10) << min << setw(10) << max << setw(10)
+                     << stdDev << setw(10) << longTermStdDev << endl;
+        } else if (gVerboseFlag)
+            cout << "printing from PoolBuffer->stdDev->tick:\n (mean / min / max / "
+                    "stdDev / longTermStdDev) \n";
+
+        longTermCnt++;
+        //            QString out;
+        //            out += (QString::number(msNow) + QString("\t"));
+        //            out += (QString::number(mean) + QString("\t"));
+        //            out += (QString::number(min) + QString("\t"));
+        //            out += (QString::number(max) + QString("\t"));
+        //            out += (QString::number(stdDev) + QString("\t"));
+        //                        emit printStats(out);
+        // build-jacktrip-Desktop-Release/jacktrip -C cmn9.stanford.edu --bufstrategy 3 -I
+        // 1 -G /tmp/iostat.log plot 'iostat.log' u  1:2 w l, 'iostat.log' u  1:3 w l,
+        // 'iostat.log' u  1:4 w l, 'iostat.log' u  1:5 w l,
+        lastMean = mean;
+        lastMin  = min;
+        lastMax  = max;
+        reset();
+    }
+}
diff --git a/src/PoolBuffer.h b/src/PoolBuffer.h
new file mode 100644 (file)
index 0000000..b7c4d7a
--- /dev/null
@@ -0,0 +1,159 @@
+//*****************************************************************
+/*
+  JackTrip: A System for High-Quality Audio Network Performance
+  over the Internet
+
+  Copyright (c) 2021 Juan-Pablo Caceres, Chris Chafe.
+  SoundWIRE group at CCRMA, Stanford University.
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation
+  files (the "Software"), to deal in the Software without
+  restriction, including without limitation the rights to use,
+  copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the
+  Software is furnished to do so, subject to the following
+  conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+  OTHER DEALINGS IN THE SOFTWARE.
+*/
+//*****************************************************************
+
+/**
+ * \file PoolBuffer.h
+ * \author Chris Chafe
+ * \date May 2021
+ */
+
+// EXPERIMENTAL for testing in JackTrip v1.4.0
+// Initial references and starter code
+// http://www.emptyloop.com/technotes/A%20tutorial%20on%20Burg's%20method,%20algorithm%20and%20recursion.pdf
+// https://metacpan.org/source/SYP/Algorithm-Burg-0.001/README
+
+#ifndef __POOLUFFER_H__
+#define __POOLUFFER_H__
+
+#include <QDebug>
+#include <QElapsedTimer>
+
+#include "AudioInterface.h"
+#include "RingBuffer.h"
+using std::vector;
+#include <math.h>
+
+class BurgAlgorithm
+{
+   public:
+    bool classify(double d);
+    void train(vector<long double>& coeffs, const vector<float>& x);
+    void predict(vector<long double>& coeffs, vector<float>& tail);
+};
+
+class ChanData
+{
+   public:
+    ChanData(int i, int FPP, int hist);
+    int ch;
+    int trainSamps;
+    vector<sample_t> mTruth;
+    vector<sample_t> mTrain;
+    vector<sample_t> mPrediction;  // ORDER
+    vector<long double> mCoeffs;
+    vector<sample_t> mXfadedPred;
+    vector<sample_t> mNextPred;
+    vector<vector<sample_t>> mLastPackets;
+};
+
+class StdDev
+{
+   public:
+    StdDev(int w);
+    void reset();
+    void tick();
+    QElapsedTimer* mTimer;
+    vector<double> data;
+    double mean;
+    double var;
+    //    double varRunning;
+    int window;
+    double acc;
+    double min;
+    double max;
+    int ctr;
+    double lastMean;
+    double lastMin;
+    double lastMax;
+    double longTermStdDev;
+    double longTermStdDevAcc;
+    int longTermCnt;
+};
+
+class PoolBuffer : public RingBuffer
+{
+    //    Q_OBJECT;
+
+   public:
+    PoolBuffer(int sample_rate, int channels, int bit_res, int FPP, int qLen);
+    virtual ~PoolBuffer() {}
+
+    bool pushPacket(const int8_t* buf);
+    // can hijack unused2 to propagate incoming seq num if needed
+    // option is in UdpDataProtocol
+    // if (!mJackTrip->writeAudioBuffer(src, host_buf_size, last_seq_num))
+    // instread of
+    // if (!mJackTrip->writeAudioBuffer(src, host_buf_size, gap_size))
+    virtual bool insertSlotNonBlocking(const int8_t* ptrToSlot,
+                                       [[maybe_unused]] int unused,
+                                       [[maybe_unused]] int unused2)
+    {
+        pushPacket(ptrToSlot);
+        return (true);
+    }
+
+    void pullPacket(int8_t* buf);
+
+    virtual void readSlotNonBlocking(int8_t* ptrToReadSlot) { pullPacket(ptrToReadSlot); }
+
+   private:
+    void processPacket(bool glitch);
+    void processChannel(int ch, bool glitch, int packetCnt, bool lastWasGlitch);
+    int mNumChannels;
+    int mAudioBitRes;
+    int mFPP;
+
+    int mPoolSize;
+    int mHist;
+    AudioInterface::audioBitResolutionT mBitResolutionMode;
+    BurgAlgorithm ba;
+    int8_t* mXfrBuffer;
+    int mPacketCnt;
+    sample_t bitsToSample(int ch, int frame);
+    void sampleToBits(sample_t sample, int ch, int frame);
+    vector<sample_t> mFadeUp;
+    vector<sample_t> mFadeDown;
+    bool mLastWasGlitch;
+    unsigned int mOutgoingCnt;
+    int mBytes;
+    vector<int8_t*> mIncomingDat;
+    int8_t* mZeros;
+    QElapsedTimer* mTimer0;
+    unsigned int mIncomingCnt;
+    vector<int> mIndexPool;
+    int mQlen;
+    int mGlitchCnt;
+    int mGlitchMax;
+    vector<ChanData*> mChanData;
+    StdDev* stdDev;
+};
+
+#endif  //__POOLUFFER_H__
index be26a31465d7643af543075d378f8bb65aa73a78..6f708aab430768f941177064e15cc25bef9c83b2 100644 (file)
@@ -2,7 +2,7 @@
 
 /*
 //----------------------------------------------------------------------------
-// Jack Callbacks 
+// Jack Callbacks
 //----------------------------------------------------------------------------
 
 int srate(jack_nframes_t nframes, void *arg)
@@ -13,7 +13,7 @@ int srate(jack_nframes_t nframes, void *arg)
 
 void jack_shutdown(void *arg)
 {
-  std::cout << "" << std::endl; 
+  std::cout << "" << std::endl;
   std::exit(1);
 }
 
index fb48cca54f4640335536370db0b79c83fbdaab88..4f4862e9782890d0c350b97ea69d5649fac03a17 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
 #ifndef __PROCESSPLUGIN_H__
 #define __PROCESSPLUGIN_H__
 
-#include <jack/jack.h>
 #include <QThread>
 
 /** \brief Interface for the process plugins to add to the JACK callback process in
  * JackAudioInterface
  *
- * This class contains the same methods of the FAUST dsp class. A mydsp class can inherit from
- * this class the same way it inherits from dsp. Subclass should implement all methods
- * except init, which is optional for processing that are sampling rate dependent or
- * that need specific initialization.
+ * This class contains the same methods of the FAUST dsp class. A mydsp class can inherit
+ * from this class the same way it inherits from dsp. Subclass should implement all
+ * methods except init, which is optional for processing that are sampling rate dependent
+ * or that need specific initialization.
  */
-class ProcessPlugin : public QThread
+class ProcessPlugin : public QObject
 {
-public:
-
+   public:
     /// \brief The Class Constructor
-    ProcessPlugin() {};
+    ProcessPlugin(){};
     /// \brief The Class Destructor
-    virtual ~ProcessPlugin() {};
+    virtual ~ProcessPlugin(){};
 
     /// \brief Return Number of Input Channels
     virtual int getNumInputs() = 0;
     /// \brief Return Number of Output Channels
     virtual int getNumOutputs() = 0;
 
-    //virtual void buildUserInterface(UI* interface) = 0;
+    // virtual void buildUserInterface(UI* interface) = 0;
 
-    virtual char* getName() {
-      char* pluginName { const_cast<char*>(typeid(*this).name()) }; // get name of DERIVED class
-      while (isdigit(*pluginName)) { pluginName++; }
-      return pluginName;
-    }
+    virtual const char* getName() const = 0;  // get name of DERIVED class
 
     /** \brief Do proper Initialization of members and class instances. By default this
-   * initializes the Sampling Frequency. If a class instance depends on the
-   * sampling frequency, it should be initialize here.
-   */
-    virtual void init(int samplingRate) {
-      fSamplingFreq = samplingRate;
-      if (verbose) {
-        char* derivedClassName = getName();
-        printf("%s: init(%d)\n",derivedClassName,samplingRate);
-      }
+     * initializes the Sampling Frequency. If a class instance depends on the
+     * sampling frequency, it should be initialize here.
+     */
+    virtual void init(int samplingRate)
+    {
+        fSamplingFreq = samplingRate;
+        if (verbose) { printf("%s: init(%d)\n", getName(), samplingRate); }
     }
     virtual bool getInited() { return inited; }
     virtual void setVerbose(bool v) { verbose = v; }
@@ -88,9 +80,9 @@ public:
     /// \brief Compute process
     virtual void compute(int nframes, float** inputs, float** outputs) = 0;
 
-protected:
-    int fSamplingFreq; ///< Faust Data member, Sampling Rate
-    bool inited = false;
+   protected:
+    int fSamplingFreq;  ///< Faust Data member, Sampling Rate
+    bool inited  = false;
     bool verbose = false;
 };
 
index abc2c5f301337687b6c343ebbb6d5af8aa43e486..977fcbd06bc49386770bfc23c78b961edf00b165 100644 (file)
  * \date August 2020
  */
 
-
 #include "Reverb.h"
-#include "jacktrip_types.h"
 
 #include <iostream>
 
+#include "jacktrip_types.h"
+
 //*******************************************************************************
 void Reverb::compute(int nframes, float** inputs, float** outputs)
 {
-  if (not inited) {
-    std::cerr << "*** Reverb " << this << ": init never called! Doing it now.\n";
-    if (fSamplingFreq <= 0) {
-      fSamplingFreq = 48000;
-      std::cout << "Reverb " << this << ": *** HAD TO GUESS the sampling rate (chose 48000 Hz) ***\n";
-    }
-    init(fSamplingFreq);
-  }
-  if (mReverbLevel <= 1.0) {
-    if (mNumInChannels == 1) {
-      freeverbMonoP->compute(nframes, inputs, outputs);
-    } else {
-      assert(mNumInChannels == 2);
-      freeverbStereoP->compute(nframes, inputs, outputs);
+    if (not inited) {
+        std::cerr << "*** Reverb " << this << ": init never called! Doing it now.\n";
+        if (fSamplingFreq <= 0) {
+            fSamplingFreq = 48000;
+            std::cout << "Reverb " << this
+                      << ": *** HAD TO GUESS the sampling rate (chose 48000 Hz) ***\n";
+        }
+        init(fSamplingFreq);
     }
-  } else {
-    if (mNumInChannels == 1) {
-      zitarevMonoP->compute(nframes, inputs, outputs);
+    if (mReverbLevel <= 1.0) {
+        if (mNumInChannels == 1) {
+            freeverbMonoP->compute(nframes, inputs, outputs);
+        } else {
+            assert(mNumInChannels == 2);
+            freeverbStereoP->compute(nframes, inputs, outputs);
+        }
     } else {
-      assert(mNumInChannels == 2);
-      zitarevStereoP->compute(nframes, inputs, outputs);
+        if (mNumInChannels == 1) {
+            zitarevMonoP->compute(nframes, inputs, outputs);
+        } else {
+            assert(mNumInChannels == 2);
+            zitarevStereoP->compute(nframes, inputs, outputs);
+        }
     }
-  }
 }
index 3a7fd846707ceb0a8bfa4d79ef747361ad74f89e..34646601a188ddcbe82a9c31d166e6cc3ad851e0 100644 (file)
@@ -35,7 +35,6 @@
  * \date August 2020
  */
 
-
 /** \brief Applies freeverb or zitarev from the faustlibraries distribution: reverbs.lib
  *
  */
 //#define SINE_TEST
 
 #include "ProcessPlugin.h"
-#include "freeverbdsp.h" // stereo in and out
-#include "freeverbmonodsp.h" // mono in and out (there is no mono to stereo case in jacktrip as yet)
-#include "zitarevdsp.h" // stereo in and out
-#include "zitarevmonodsp.h" // mono in and out
+#include "freeverbdsp.h"  // stereo in and out
+#include "freeverbmonodsp.h"  // mono in and out (there is no mono to stereo case in jacktrip as yet)
+#include "zitarevdsp.h"      // stereo in and out
+#include "zitarevmonodsp.h"  // mono in and out
 
 /** \brief A Reverb is an echo-based delay effect,
  *  providing a virtual acoustic listening space.
  */
 class Reverb : public ProcessPlugin
 {
-public:
-  /// \brief The class constructor sets the number of channels to limit
-  Reverb(int numInChans, int numOutChans, float reverbLevel = 1.0, bool verboseFlag = false) // xtor
-    : mNumInChannels(numInChans), mNumOutChannels(numOutChans), mReverbLevel(reverbLevel)
-  {
-    setVerbose(verboseFlag);
-    if ( mNumInChannels < 1 ) {
-      std::cerr << "*** Reverb.h: must have at least one input audio channels\n";
-      mNumInChannels = 1;
-    }
-    if ( mNumInChannels > 2 ) {
-      std::cerr << "*** Reverb.h: limiting number of audio output channels to 2\n";
-      mNumInChannels = 2;
-    }
+   public:
+    /// \brief The class constructor sets the number of channels to limit
+    Reverb(int numInChans, int numOutChans, float reverbLevel = 1.0,
+           bool verboseFlag = false)  // xtor
+        : mNumInChannels(numInChans)
+        , mNumOutChannels(numOutChans)
+        , mReverbLevel(reverbLevel)
+    {
+        setVerbose(verboseFlag);
+        if (mNumInChannels < 1) {
+            std::cerr << "*** Reverb.h: must have at least one input audio channels\n";
+            mNumInChannels = 1;
+        }
+        if (mNumInChannels > 2) {
+            std::cerr << "*** Reverb.h: limiting number of audio output channels to 2\n";
+            mNumInChannels = 2;
+        }
 #if 0
     std::cout << "Reverb: constructed for "
               << mNumInChannels << " input channels and "
@@ -76,83 +78,92 @@ public:
               << mReverbLevel << "\n";
 #endif
 
-    if (mReverbLevel <= 1.0) { // freeverb:
-      freeverbStereoP = new freeverbdsp; // stereo input and output
-      freeverbMonoP = new freeverbmonodsp; // mono input, stereo output
-      freeverbStereoUIP = new APIUI; // #included in *dsp.h
-      freeverbMonoUIP = new APIUI;
-      freeverbStereoP->buildUserInterface(freeverbStereoUIP);
-      freeverbMonoP->buildUserInterface(freeverbMonoUIP);
-      // std::cout << "Using freeverb\n";
-    } else {
-      zitarevStereoP = new zitarevdsp; // stereo input and output
-      zitarevMonoP = new zitarevmonodsp; // mono input, stereo output
-      zitarevStereoUIP = new APIUI;
-      zitarevMonoUIP = new APIUI;
-      zitarevStereoP->buildUserInterface(zitarevStereoUIP);
-      zitarevMonoP->buildUserInterface(zitarevMonoUIP);
-      // std::cout << "Using zitarev\n";
+        if (mReverbLevel <= 1.0) {                    // freeverb:
+            freeverbStereoP   = new freeverbdsp;      // stereo input and output
+            freeverbMonoP     = new freeverbmonodsp;  // mono input, stereo output
+            freeverbStereoUIP = new APIUI;            // #included in *dsp.h
+            freeverbMonoUIP   = new APIUI;
+            freeverbStereoP->buildUserInterface(freeverbStereoUIP);
+            freeverbMonoP->buildUserInterface(freeverbMonoUIP);
+            // std::cout << "Using freeverb\n";
+        } else {
+            zitarevStereoP   = new zitarevdsp;      // stereo input and output
+            zitarevMonoP     = new zitarevmonodsp;  // mono input, stereo output
+            zitarevStereoUIP = new APIUI;
+            zitarevMonoUIP   = new APIUI;
+            zitarevStereoP->buildUserInterface(zitarevStereoUIP);
+            zitarevMonoP->buildUserInterface(zitarevMonoUIP);
+            // std::cout << "Using zitarev\n";
+        }
     }
-  }
-
-  /// \brief The class destructor
-  virtual ~Reverb() {
-    if (mReverbLevel <= 1.0) { // freeverb:
-      delete freeverbStereoP;
-      delete freeverbMonoP;
-      delete freeverbStereoUIP;
-      delete freeverbMonoUIP;
-    } else {
-      delete zitarevStereoP;
-      delete zitarevMonoP;
-      delete zitarevStereoUIP;
-      delete zitarevMonoUIP;
+
+    /// \brief The class destructor
+    virtual ~Reverb()
+    {
+        if (mReverbLevel <= 1.0) {  // freeverb:
+            delete freeverbStereoP;
+            delete freeverbMonoP;
+            delete freeverbStereoUIP;
+            delete freeverbMonoUIP;
+        } else {
+            delete zitarevStereoP;
+            delete zitarevMonoP;
+            delete zitarevStereoUIP;
+            delete zitarevMonoUIP;
+        }
     }
-  }
-
-  void init(int samplingRate) override {
-    ProcessPlugin::init(samplingRate);
-    // std::cout << "Reverb: init(" << samplingRate << ")\n";
-    if (samplingRate != fSamplingFreq) {
-      std::cerr << "Sampling rate not set by superclass!\n";
-      std::exit(1); }
-    fs = float(fSamplingFreq);
-    if (mReverbLevel <= 1.0) { // freeverb:
-      freeverbStereoP->init(fs); // compression filter parameters depend on sampling rate
-      freeverbMonoP->init(fs); // compression filter parameters depend on sampling rate
-      int ndx = freeverbStereoUIP->getParamIndex("Wet");
-      freeverbStereoUIP->setParamValue(ndx, mReverbLevel);
-      freeverbMonoUIP->setParamValue(ndx, mReverbLevel);
-    } else { // zitarev:
-      zitarevStereoP->init(fs); // compression filter parameters depend on sampling rate
-      zitarevMonoP->init(fs); // compression filter parameters depend on sampling rate
-      int ndx = zitarevStereoUIP->getParamIndex("Wet");
-      float zitaLevel = mReverbLevel-1.0f; // range within zitarev is 0 to 1 (our version only)
-      zitarevStereoUIP->setParamValue(ndx, zitaLevel);
-      zitarevMonoUIP->setParamValue(ndx, zitaLevel);
+
+    void init(int samplingRate) override
+    {
+        ProcessPlugin::init(samplingRate);
+        // std::cout << "Reverb: init(" << samplingRate << ")\n";
+        if (samplingRate != fSamplingFreq) {
+            std::cerr << "Sampling rate not set by superclass!\n";
+            std::exit(1);
+        }
+        fs = float(fSamplingFreq);
+        if (mReverbLevel <= 1.0) {  // freeverb:
+            freeverbStereoP->init(
+                fs);  // compression filter parameters depend on sampling rate
+            freeverbMonoP->init(
+                fs);  // compression filter parameters depend on sampling rate
+            int ndx = freeverbStereoUIP->getParamIndex("Wet");
+            freeverbStereoUIP->setParamValue(ndx, mReverbLevel);
+            freeverbMonoUIP->setParamValue(ndx, mReverbLevel);
+        } else {  // zitarev:
+            zitarevStereoP->init(
+                fs);  // compression filter parameters depend on sampling rate
+            zitarevMonoP->init(
+                fs);  // compression filter parameters depend on sampling rate
+            int ndx = zitarevStereoUIP->getParamIndex("Wet");
+            float zitaLevel =
+                mReverbLevel - 1.0f;  // range within zitarev is 0 to 1 (our version only)
+            zitarevStereoUIP->setParamValue(ndx, zitaLevel);
+            zitarevMonoUIP->setParamValue(ndx, zitaLevel);
+        }
+        inited = true;
     }
-    inited = true;
-  }
-  int getNumInputs() override { return(mNumInChannels); }
-  int getNumOutputs() override { return(mNumOutChannels); }
-  void compute(int nframes, float** inputs, float** outputs) override;
-
-private:
-  float fs;
-  int mNumInChannels;
-  int mNumOutChannels;
-
-  float mReverbLevel;
-
-  freeverbdsp* freeverbStereoP;
-  freeverbmonodsp* freeverbMonoP;
-  APIUI* freeverbStereoUIP;
-  APIUI* freeverbMonoUIP;
-
-  zitarevdsp* zitarevStereoP;
-  zitarevmonodsp* zitarevMonoP;
-  APIUI* zitarevStereoUIP;
-  APIUI* zitarevMonoUIP;
+    int getNumInputs() override { return (mNumInChannels); }
+    int getNumOutputs() override { return (mNumOutChannels); }
+    void compute(int nframes, float** inputs, float** outputs) override;
+    const char* getName() const override { return "Reverb"; }
+
+   private:
+    float fs;
+    int mNumInChannels;
+    int mNumOutChannels;
+
+    float mReverbLevel;
+
+    freeverbdsp* freeverbStereoP;
+    freeverbmonodsp* freeverbMonoP;
+    APIUI* freeverbStereoUIP;
+    APIUI* freeverbMonoUIP;
+
+    zitarevdsp* zitarevStereoP;
+    zitarevmonodsp* zitarevMonoP;
+    APIUI* zitarevStereoUIP;
+    APIUI* zitarevMonoUIP;
 };
 
 #endif
index e9ff28cb8d57f2e63399194b89764857810cb65c..e4b23c611b0c4381d172bbe672a86e4c80d3c910 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
  * \date July 2008
  */
 
-
 #include "RingBuffer.h"
 
-#include <iostream>
-#include <cstring>
+#include <cmath>
 #include <cstdlib>
+#include <cstring>
+#include <iostream>
 #include <stdexcept>
-#include <cmath>
-#include "JackTrip.h"
 
-using std::cout; using std::endl;
+#include "JackTrip.h"
 
+using std::cout;
+using std::endl;
 
 //*******************************************************************************
-RingBuffer::RingBuffer(int SlotSize, int NumSlots) :
-    mSlotSize(SlotSize),
-    mNumSlots(NumSlots),
-    mTotalSize(mSlotSize*mNumSlots),
-    mReadPosition(0),
-    mWritePosition(0),
-    mFullSlots(0),
-    mRingBuffer(NULL),
-    mLastReadSlot(NULL)
+RingBuffer::RingBuffer(int SlotSize, int NumSlots)
+    : mSlotSize(SlotSize)
+    , mNumSlots(NumSlots)
+    , mTotalSize(mSlotSize * mNumSlots)
+    , mReadPosition(0)
+    , mWritePosition(0)
+    , mFullSlots(0)
+    , mRingBuffer(NULL)
+    mLastReadSlot(NULL)
 {
     if (0 < mTotalSize) {
-        mRingBuffer = new int8_t[mTotalSize];
+        mRingBuffer   = new int8_t[mTotalSize];
         mLastReadSlot = new int8_t[mSlotSize];
-        //QMutexLocker locker(&mMutex); // lock the mutex
-
-        // Verify if there's enough space to for the buffers
-        if ( (mRingBuffer == NULL) || (mLastReadSlot == NULL) ) {
-            //std::cerr << "ERROR: RingBuffer out of memory!" << endl;
-            //std::cerr << "Exiting program..." << endl;
-            //std::exit(1);
-            throw std::length_error("RingBuffer out of memory!");
-        }
-
-        // Set the buffers to zeros
-        /*
-      for (int i=0; i<mTotalSize; i++) {
-        mRingBuffer[i] = 0;    // Initialize all elements to zero.
-      }
-      */
-        std::memset(mRingBuffer, 0, mTotalSize); // set buffer to 0
-        /*
-      for (int i=0; i<mSlotSize; i++) {
-        mLastReadSlot[i] = 0;    // Initialize all elements to zero.
-      }
-      */
-        std::memset(mLastReadSlot, 0, mSlotSize); // set buffer to 0
-        mWritePosition = ( (NumSlots/2) * SlotSize ) % mTotalSize;
+        std::memset(mRingBuffer, 0, mTotalSize);   // set buffer to 0
+        std::memset(mLastReadSlot, 0, mSlotSize);  // set buffer to 0
+
+        mWritePosition = ((NumSlots / 2) * SlotSize) % mTotalSize;
     }
 
     // Advance write position to half of the RingBuffer
     // Udpate Full Slots accordingly
-    mFullSlots = (NumSlots/2);
-    mLevelDownRate = 0.01;
-    mStatUnit = 1;
-    mUnderruns = 0;
-    mOverflows = 0;
-    mSkew0 = 0;
-    mSkewRaw = 0;
-    mLevelCur = mFullSlots;
-    mLevel = mLevelCur;
-    mBufDecOverflow = 0;
-    mBufDecPktLoss = 0;
-    mBufIncUnderrun = 0;
+    mFullSlots        = (NumSlots / 2);
+    mLevelDownRate    = 0.01;
+    mStatUnit         = 1;
+    mUnderruns        = 0;
+    mOverflows        = 0;
+    mSkew0            = 0;
+    mSkewRaw          = 0;
+    mLevelCur         = mFullSlots;
+    mLevel            = mLevelCur;
+    mBufDecOverflow   = 0;
+    mBufDecPktLoss    = 0;
+    mBufIncUnderrun   = 0;
     mBufIncCompensate = 0;
-    mBroadcastSkew = 0;
-    mBroadcastDelta = 0;
+    mBroadcastSkew    = 0;
+    mBroadcastDelta   = 0;
 }
 
-
 //*******************************************************************************
 RingBuffer::~RingBuffer()
 {
-    delete[] mRingBuffer; // Free memory
-    mRingBuffer = NULL; // Clear to prevent using invalid memory reference
+    delete[] mRingBuffer;  // Free memory
+    mRingBuffer = NULL;    // Clear to prevent using invalid memory reference
     delete[] mLastReadSlot;
     mLastReadSlot = NULL;
 }
 
-
 //*******************************************************************************
 void RingBuffer::insertSlotBlocking(const int8_t* ptrToSlot)
 {
-    QMutexLocker locker(&mMutex); // lock the mutex
+    QMutexLocker locker(&mMutex);  // lock the mutex
     updateReadStats();
 
     // Check if there is space available to write a slot
     // If the Ringbuffer is full, it waits for the bufferIsNotFull condition
     while (mFullSlots == mNumSlots) {
-        //std::cout << "OUPUT OVERFLOW BLOCKING" << std::endl;
+        // std::cout << "OUTPUT OVERFLOW BLOCKING" << std::endl;
         mBufferIsNotFull.wait(&mMutex);
     }
 
     // Copy mSlotSize bytes to mRingBuffer
-    std::memcpy(mRingBuffer+mWritePosition, ptrToSlot, mSlotSize);
+    std::memcpy(mRingBuffer + mWritePosition, ptrToSlot, mSlotSize);
     // Update write position
-    mWritePosition = (mWritePosition+mSlotSize) % mTotalSize;
-    mFullSlots++; //update full slots
+    mWritePosition = (mWritePosition + mSlotSize) % mTotalSize;
+    mFullSlots++;  // update full slots
     // Wake threads waitng for bufferIsNotFull condition
     mBufferIsNotEmpty.wakeAll();
 }
 
-
 //*******************************************************************************
 void RingBuffer::readSlotBlocking(int8_t* ptrToReadSlot)
 {
-    QMutexLocker locker(&mMutex); // lock the mutex
+    QMutexLocker locker(&mMutex);  // lock the mutex
     ++mReadsNew;
 
     // Check if there are slots available to read
     // If the Ringbuffer is empty, it waits for the bufferIsNotEmpty condition
     while (mFullSlots == 0) {
-        //std::cerr << "READ UNDER-RUN BLOCKING before" << endl;
+        // std::cerr << "READ UNDER-RUN BLOCKING before" << endl;
         mBufferIsNotEmpty.wait(&mMutex, 200);
-        if (JackTrip::sJackStopped) {
-            return;
-        }
+        if (JackTrip::sJackStopped) { return; }
     }
 
     // Copy mSlotSize bytes to ReadSlot
-    std::memcpy(ptrToReadSlot, mRingBuffer+mReadPosition, mSlotSize);
+    std::memcpy(ptrToReadSlot, mRingBuffer + mReadPosition, mSlotSize);
     // Always save memory of the last read slot
-    std::memcpy(mLastReadSlot, mRingBuffer+mReadPosition, mSlotSize);
+    std::memcpy(mLastReadSlot, mRingBuffer + mReadPosition, mSlotSize);
     // Update write position
-    mReadPosition = (mReadPosition+mSlotSize) % mTotalSize;
-    mFullSlots--; //update full slots
+    mReadPosition =
+        (0 == mTotalSize) ? mReadPosition : (mReadPosition + mSlotSize) % mTotalSize;
+    mFullSlots--;  // update full slots
     // Wake threads waitng for bufferIsNotFull condition
     mBufferIsNotFull.wakeAll();
 }
 
-
 //*******************************************************************************
 bool RingBuffer::insertSlotNonBlocking(const int8_t* ptrToSlot, int len, int lostLen)
 {
@@ -176,7 +151,7 @@ bool RingBuffer::insertSlotNonBlocking(const int8_t* ptrToSlot, int len, int los
         // RingBuffer does not suppport mixed buf sizes
         return false;
     }
-    QMutexLocker locker(&mMutex); // lock the mutex
+    QMutexLocker locker(&mMutex);  // lock the mutex
     if (0 < lostLen) {
         int lostCount = lostLen / mSlotSize;
         mBufDecPktLoss += lostCount;
@@ -191,31 +166,29 @@ bool RingBuffer::insertSlotNonBlocking(const int8_t* ptrToSlot, int len, int los
     /// \todo It may be better here to insert the slot anyways,
     /// instead of not writing anything
     if (mFullSlots == mNumSlots) {
-        //std::cout << "OUPUT OVERFLOW NON BLOCKING = " << mNumSlots << std::endl;
+        // std::cout << "OUPUT OVERFLOW NON BLOCKING = " << mNumSlots << std::endl;
         overflowReset();
         return true;
     }
 
     // Copy mSlotSize bytes to mRingBuffer
-    std::memcpy(mRingBuffer+mWritePosition, ptrToSlot, mSlotSize);
+    std::memcpy(mRingBuffer + mWritePosition, ptrToSlot, mSlotSize);
     // Update write position
-    mWritePosition = (mWritePosition+mSlotSize) % mTotalSize;
-    mFullSlots++; //update full slots
+    mWritePosition = (mWritePosition + mSlotSize) % mTotalSize;
+    mFullSlots++;  // update full slots
     // Wake threads waitng for bufferIsNotFull condition
     mBufferIsNotEmpty.wakeAll();
     return true;
 }
 
-
 //*******************************************************************************
 void RingBuffer::readSlotNonBlocking(int8_t* ptrToReadSlot)
 {
-    QMutexLocker locker(&mMutex); // lock the mutex
+    QMutexLocker locker(&mMutex);  // lock the mutex
     ++mReadsNew;
     if (mFullSlots < mLevelCur) {
-        mLevelCur = std::max((double)mFullSlots, mLevelCur-mLevelDownRate);
-    }
-    else {
+        mLevelCur = std::max((double)mFullSlots, mLevelCur - mLevelDownRate);
+    } else {
         mLevelCur = mFullSlots;
     }
 
@@ -223,25 +196,24 @@ void RingBuffer::readSlotNonBlocking(int8_t* ptrToReadSlot)
     // If the Ringbuffer is empty, it returns a buffer of zeros and rests the buffer
     if (mFullSlots <= 0) {
         // Returns a buffer of zeros if there's nothing to read
-        //std::cerr << "READ UNDER-RUN NON BLOCKING = " << mNumSlots << endl;
-        //std::memset(ptrToReadSlot, 0, mSlotSize);
+        // std::cerr << "READ UNDER-RUN NON BLOCKING = " << mNumSlots << endl;
+        // std::memset(ptrToReadSlot, 0, mSlotSize);
         setUnderrunReadSlot(ptrToReadSlot);
         underrunReset();
         return;
     }
 
     // Copy mSlotSize bytes to ReadSlot
-    std::memcpy(ptrToReadSlot, mRingBuffer+mReadPosition, mSlotSize);
+    std::memcpy(ptrToReadSlot, mRingBuffer + mReadPosition, mSlotSize);
     // Always save memory of the last read slot
-    std::memcpy(mLastReadSlot, mRingBuffer+mReadPosition, mSlotSize);
+    std::memcpy(mLastReadSlot, mRingBuffer + mReadPosition, mSlotSize);
     // Update write position
-    mReadPosition = (mReadPosition+mSlotSize) % mTotalSize;
-    mFullSlots--; //update full slots
+    mReadPosition = (mReadPosition + mSlotSize) % mTotalSize;
+    mFullSlots--;  // update full slots
     // Wake threads waitng for bufferIsNotFull condition
     mBufferIsNotFull.wakeAll();
 }
 
-
 //*******************************************************************************
 // Not supported in RingBuffer
 void RingBuffer::readBroadcastSlot(int8_t* ptrToReadSlot)
@@ -249,59 +221,53 @@ void RingBuffer::readBroadcastSlot(int8_t* ptrToReadSlot)
     std::memset(ptrToReadSlot, 0, mSlotSize);
 }
 
-
 //*******************************************************************************
 void RingBuffer::setUnderrunReadSlot(int8_t* ptrToReadSlot)
 {
     std::memset(ptrToReadSlot, 0, mSlotSize);
 }
 
-
 //*******************************************************************************
 void RingBuffer::setMemoryInReadSlotWithLastReadSlot(int8_t* ptrToReadSlot)
 {
     std::memcpy(ptrToReadSlot, mLastReadSlot, mSlotSize);
 }
 
-
-
-
 //*******************************************************************************
 // Under-run happens when there's nothing to read.
 void RingBuffer::underrunReset()
 {
     // Advance the write pointer 1/2 the ring buffer
-    //mWritePosition = ( mReadPosition + ( (mNumSlots/2) * mSlotSize ) ) % mTotalSize;
-    //mWritePosition = ( mWritePosition + ( (mNumSlots/2) * mSlotSize ) ) % mTotalSize;
-    //mFullSlots += mNumSlots/2;
-    // There's nothing new to read, so we clear the whole buffer (Set the entire buffer to 0)
+    // mWritePosition = ( mReadPosition + ( (mNumSlots/2) * mSlotSize ) ) % mTotalSize;
+    // mWritePosition = ( mWritePosition + ( (mNumSlots/2) * mSlotSize ) ) % mTotalSize;
+    // mFullSlots += mNumSlots/2;
+    // There's nothing new to read, so we clear the whole buffer (Set the entire buffer to
+    // 0)
     std::memset(mRingBuffer, 0, mTotalSize);
     ++mUnderrunsNew;
 }
 
-
 //*******************************************************************************
 // Over-flow happens when there's no space to write more slots.
 void RingBuffer::overflowReset()
 {
     // Advance the read pointer 1/2 the ring buffer
-    //mReadPosition = ( mWritePosition + ( (mNumSlots/2) * mSlotSize ) ) % mTotalSize;
-    int d = mNumSlots / 2;
-    mReadPosition = ( mReadPosition + ( d * mSlotSize ) ) % mTotalSize;
+    // mReadPosition = ( mWritePosition + ( (mNumSlots/2) * mSlotSize ) ) % mTotalSize;
+    int d         = mNumSlots / 2;
+    mReadPosition = (mReadPosition + (d * mSlotSize)) % mTotalSize;
     mFullSlots -= d;
     mOverflows += d + 1;
     mBufDecOverflow += d + 1;
     mLevelCur -= d;
 }
 
-
 //*******************************************************************************
 void RingBuffer::debugDump() const
 {
     cout << "mTotalSize = " << mTotalSize << endl;
     cout << "mReadPosition = " << mReadPosition << endl;
     cout << "mWritePosition = " << mWritePosition << endl;
-    cout <<  "mFullSlots = " << mFullSlots << endl;
+    cout << "mFullSlots = " << mFullSlots << endl;
 }
 
 //*******************************************************************************
@@ -309,29 +275,30 @@ bool RingBuffer::getStats(RingBuffer::IOStat* stat, bool reset)
 {
     QMutexLocker locker(&mMutex);
     if (reset) {
-        mUnderruns = 0;
-        mOverflows = 0;
-        mSkew0 = mLevel;
-        mSkewRaw = 0;
-        mBufDecOverflow = 0;
-        mBufDecPktLoss = 0;
-        mBufIncUnderrun = 0;
+        mUnderruns        = 0;
+        mOverflows        = 0;
+        mSkew0            = mLevel;
+        mSkewRaw          = 0;
+        mBufDecOverflow   = 0;
+        mBufDecPktLoss    = 0;
+        mBufIncUnderrun   = 0;
         mBufIncCompensate = 0;
-        mBroadcastSkew = 0;
+        mBroadcastSkew    = 0;
     }
     stat->underruns = mUnderruns / mStatUnit;
     stat->overflows = mOverflows / mStatUnit;
-    stat->skew = (int32_t)((mSkew0 - mLevel + mBufIncUnderrun + mBufIncCompensate
-                        - mBufDecOverflow - mBufDecPktLoss)) / mStatUnit;
+    stat->skew      = (int32_t)((mSkew0 - mLevel + mBufIncUnderrun + mBufIncCompensate
+                            - mBufDecOverflow - mBufDecPktLoss))
+                 / mStatUnit;
     stat->skew_raw = mSkewRaw / mStatUnit;
-    stat->level = mLevel / mStatUnit;
+    stat->level    = mLevel / mStatUnit;
 
-    stat->buf_dec_overflows = mBufDecOverflow / mStatUnit;
-    stat->buf_dec_pktloss = mBufDecPktLoss / mStatUnit;
-    stat->buf_inc_underrun = mBufIncUnderrun / mStatUnit;
+    stat->buf_dec_overflows  = mBufDecOverflow / mStatUnit;
+    stat->buf_dec_pktloss    = mBufDecPktLoss / mStatUnit;
+    stat->buf_inc_underrun   = mBufIncUnderrun / mStatUnit;
     stat->buf_inc_compensate = mBufIncCompensate / mStatUnit;
-    stat->broadcast_skew = mBroadcastSkew;
-    stat->broadcast_delta = mBroadcastDelta;
+    stat->broadcast_skew     = mBroadcastSkew;
+    stat->broadcast_delta    = mBroadcastDelta;
 
     stat->autoq_corr = 0;
     stat->autoq_rate = 0;
@@ -347,5 +314,5 @@ void RingBuffer::updateReadStats()
     mUnderruns += mUnderrunsNew;
     mBufIncUnderrun += mUnderrunsNew;
     mUnderrunsNew = 0;
-    mLevel = std::ceil(mLevelCur);
+    mLevel        = std::ceil(mLevelCur);
 }
index e68d625d43131d011c8fc2cf6654c9aa94c52def..b5175118e27777863777d331720fd4dfcbd59fef 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
 #ifndef __RINGBUFFER_H__
 #define __RINGBUFFER_H__
 
-#include <QWaitCondition>
 #include <QMutex>
 #include <QMutexLocker>
-
-#include "jacktrip_types.h"
-
+#include <QWaitCondition>
 #include <atomic>
 
-//using namespace JackTripNamespace;
+#include "jacktrip_types.h"
 
+// using namespace JackTripNamespace;
 
-/** \brief Provides a ring-buffer (or circular-buffer) that can be written to and read from
- * asynchronously (blocking) or synchronously (non-blocking).
+/** \brief Provides a ring-buffer (or circular-buffer) that can be written to and read
+ * from asynchronously (blocking) or synchronously (non-blocking).
  *
  * The RingBuffer is an array of \b NumSlots slots of memory
  * each of which is of size \b SlotSize bytes (8-bits). Slots can be read and
  */
 class RingBuffer
 {
-public:
-
+   public:
     /** \brief The class constructor
-   * \param SlotSize Size of one slot in bytes
-   * \param NumSlots Number of slots
-   */
+     * \param SlotSize Size of one slot in bytes
+     * \param NumSlots Number of slots
+     */
     RingBuffer(int SlotSize, int NumSlots);
 
     /** \brief The class destructor
-   */
+     */
     virtual ~RingBuffer();
 
-    /** \brief Insert a slot into the RingBuffer from ptrToSlot. This method will block until
-   * there's space in the buffer.
-   *
-   * The caller is responsible to make sure sizeof(WriteSlot) = SlotSize. This
-   * method should be use when the caller can block against its output, like
-   * sending/receiving UDP packets. It shouldn't be used by audio. For that, use the
-   * insertSlotNonBlocking.
-   * \param ptrToSlot Pointer to slot to insert into the RingBuffer
-   */
+    /** \brief Insert a slot into the RingBuffer from ptrToSlot. This method will block
+     * until there's space in the buffer.
+     *
+     * The caller is responsible to make sure sizeof(WriteSlot) = SlotSize. This
+     * method should be use when the caller can block against its output, like
+     * sending/receiving UDP packets. It shouldn't be used by audio. For that, use the
+     * insertSlotNonBlocking.
+     * \param ptrToSlot Pointer to slot to insert into the RingBuffer
+     */
     void insertSlotBlocking(const int8_t* ptrToSlot);
 
-    /** \brief Read a slot from the RingBuffer into ptrToReadSlot. This method will block until
-   * there's space in the buffer.
-   *
-   * The caller is responsible to make sure sizeof(ptrToReadSlot) = SlotSize. This
-   * method should be use when the caller can block against its input, like
-   * sending/receiving UDP packets. It shouldn't be used by audio. For that, use the
-   * readSlotNonBlocking.
-   * \param ptrToReadSlot Pointer to read slot from the RingBuffer
-   */
+    /** \brief Read a slot from the RingBuffer into ptrToReadSlot. This method will block
+     * until there's space in the buffer.
+     *
+     * The caller is responsible to make sure sizeof(ptrToReadSlot) = SlotSize. This
+     * method should be use when the caller can block against its input, like
+     * sending/receiving UDP packets. It shouldn't be used by audio. For that, use the
+     * readSlotNonBlocking.
+     * \param ptrToReadSlot Pointer to read slot from the RingBuffer
+     */
     void readSlotBlocking(int8_t* ptrToReadSlot);
 
     /** \brief Same as insertSlotBlocking but non-blocking (asynchronous)
-   * \param ptrToSlot Pointer to slot to insert into the RingBuffer
-   */
+     * \param ptrToSlot Pointer to slot to insert into the RingBuffer
+     */
     virtual bool insertSlotNonBlocking(const int8_t* ptrToSlot, int len, int lostLen);
 
     /** \brief Same as readSlotBlocking but non-blocking (asynchronous)
-   * \param ptrToReadSlot Pointer to read slot from the RingBuffer
-   */
+     * \param ptrToReadSlot Pointer to read slot from the RingBuffer
+     */
     virtual void readSlotNonBlocking(int8_t* ptrToReadSlot);
     virtual void readBroadcastSlot(int8_t* ptrToReadSlot);
 
@@ -121,20 +118,19 @@ public:
     };
     virtual bool getStats(IOStat* stat, bool reset);
 
-protected:
-
+   protected:
     /** \brief Sets the memory in the Read Slot when uderrun occurs. By default,
-   * this sets it to 0. Override this method in a subclass for a different behavior.
-   * \param ptrToReadSlot Pointer to read slot from the RingBuffer
-   */
+     * this sets it to 0. Override this method in a subclass for a different behavior.
+     * \param ptrToReadSlot Pointer to read slot from the RingBuffer
+     */
     virtual void setUnderrunReadSlot(int8_t* ptrToReadSlot);
 
     /** \brief Uses the last read slot to set the memory in the Read Slot.
-   *
-   * The last read slot is the last packet that arrived, so if no new packets are received,
-   * it keeps looping the same packet.
-   * \param ptrToReadSlot Pointer to read slot from the RingBuffer
-   */
+     *
+     * The last read slot is the last packet that arrived, so if no new packets are
+     * received, it keeps looping the same packet. \param ptrToReadSlot Pointer to read
+     * slot from the RingBuffer
+     */
     virtual void setMemoryInReadSlotWithLastReadSlot(int8_t* ptrToReadSlot);
 
     /// \brief Resets the ring buffer for reads under-runs non-blocking
@@ -145,28 +141,28 @@ protected:
     void debugDump() const;
     void updateReadStats();
 
-    /*const*/ int mSlotSize; ///< The size of one slot in byes
-    /*const*/ int mNumSlots; ///< Number of Slots
-    /*const*/ int mTotalSize; ///< Total size of the mRingBuffer = mSlotSize*mNumSlotss
-    uint32_t mReadPosition; ///< Read Positions in the RingBuffer (Tail)
-    uint32_t mWritePosition; ///< Write Position in the RingBuffer (Head)
-    int mFullSlots; ///< Number of used (full) slots, in slot-size
-    int8_t* mRingBuffer; ///< 8-bit array of data (1-byte)
-    int8_t* mLastReadSlot; ///< Last slot read
+    /*const*/ int mSlotSize;   ///< The size of one slot in byes
+    /*const*/ int mNumSlots;   ///< Number of Slots
+    /*const*/ int mTotalSize;  ///< Total size of the mRingBuffer = mSlotSize*mNumSlotss
+    uint32_t mReadPosition;    ///< Read Positions in the RingBuffer (Tail)
+    uint32_t mWritePosition;   ///< Write Position in the RingBuffer (Head)
+    int mFullSlots;            ///< Number of used (full) slots, in slot-size
+    int8_t* mRingBuffer;       ///< 8-bit array of data (1-byte)
+    int8_t* mLastReadSlot;     ///< Last slot read
 
     // Thread Synchronization Private Members
-    QMutex mMutex; ///< Mutex to protect read and write operations
-    QWaitCondition mBufferIsNotFull; ///< Buffer not full condition to monitor threads
-    QWaitCondition mBufferIsNotEmpty; ///< Buffer not empty condition to monitor threads
+    QMutex mMutex;                     ///< Mutex to protect read and write operations
+    QWaitCondition mBufferIsNotFull;   ///< Buffer not full condition to monitor threads
+    QWaitCondition mBufferIsNotEmpty;  ///< Buffer not empty condition to monitor threads
 
     // IO stat
     int mStatUnit;
     uint32_t mUnderruns;
     uint32_t mOverflows;
-    int32_t  mSkewRaw;
-    double   mLevelCur;
-    double   mLevelDownRate;
-    int32_t  mLevel;
+    int32_t mSkewRaw;
+    double mLevelCur;
+    double mLevelDownRate;
+    int32_t mLevel;
 
     uint32_t mBufDecOverflow;
     uint32_t mBufDecPktLoss;
@@ -176,7 +172,7 @@ protected:
     // temp counters for reads
     uint32_t mReadsNew;
     uint32_t mUnderrunsNew;
-    int32_t  mSkew0;
+    int32_t mSkew0;
 
     // broadcast counters
     int32_t mBroadcastSkew;
index 93e652f84107f7a0f803a253a7b0e6191ebfb143..9412f5f3c5fca4e5facde9a2288bb255a2e6eb25 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
 #ifndef __RINGBUFFERWAVETABLE_H__
 #define __RINGBUFFERWAVETABLE_H__
 
-
 /** \brief Same as RingBuffer, except that it uses the Wavetable mode for
  * lost or late packets.
  */
 class RingBufferWavetable : public RingBuffer
 {
-public:
+   public:
     /** \brief The class constructor
-   * \param SlotSize Size of one slot in bytes
-   * \param NumSlots Number of slots
-   */
+     * \param SlotSize Size of one slot in bytes
+     * \param NumSlots Number of slots
+     */
     RingBufferWavetable(int SlotSize, int NumSlots) : RingBuffer(SlotSize, NumSlots) {}
 
     /** \brief The class destructor
-   */
+     */
     virtual ~RingBufferWavetable() {}
 
-protected:
+   protected:
     /** \brief Sets the memory in the Read Slot when uderrun occurs. This loops as a
-   * wavetable in the last received packet.
-   * \param ptrToReadSlot Pointer to read slot from the RingBuffer
-   */
+     * wavetable in the last received packet.
+     * \param ptrToReadSlot Pointer to read slot from the RingBuffer
+     */
     virtual void setUnderrunReadSlot(int8_t* ptrToReadSlot)
     {
         setMemoryInReadSlotWithLastReadSlot(ptrToReadSlot);
     }
-
 };
 
-
-#endif //__RINGBUFFERWAVETABLE_H__
+#endif  //__RINGBUFFERWAVETABLE_H__
index 071802f3591e6be519dd95a327a1302787e8e2a3..de98d5a5e834508ed8967d08068a3779c8d9f427 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
  */
 
 #include "RtAudioInterface.h"
-#include "JackTrip.h"
-#include "jacktrip_globals.h"
 
 #include <cstdlib>
 
+#include "JackTrip.h"
+#include "jacktrip_globals.h"
 
-using std::cout; using std::endl;
-
-
-//*******************************************************************************
-RtAudioInterface::RtAudioInterface(JackTrip* jacktrip,
-                                   int NumInChans, int NumOutChans,
-                                   audioBitResolutionT AudioBitResolution) :
-    AudioInterface(jacktrip,
-                   NumInChans, NumOutChans,
-                   AudioBitResolution),
-    mJackTrip(jacktrip),
-    mRtAudio(NULL)
-{}
-
+using std::cout;
+using std::endl;
 
 //*******************************************************************************
-RtAudioInterface::~RtAudioInterface()
+RtAudioInterface::RtAudioInterface(JackTrip* jacktrip, int NumInChans, int NumOutChans,
+                                   audioBitResolutionT AudioBitResolution)
+    : AudioInterface(jacktrip, NumInChans, NumOutChans, AudioBitResolution)
+    , mRtAudio(NULL)
 {
-    delete mRtAudio;
 }
 
+//*******************************************************************************
+RtAudioInterface::~RtAudioInterface() { delete mRtAudio; }
 
 //*******************************************************************************
 void RtAudioInterface::setup()
 {
     // Initialize Buffer array to read and write audio and members
-    mNumInChans = getNumInputChannels();
+    mNumInChans  = getNumInputChannels();
     mNumOutChans = getNumOutputChannels();
     mInBuffer.resize(getNumInputChannels());
     mOutBuffer.resize(getNumOutputChannels());
 
-    cout << "Settin Up Default RtAudio Interface" << endl;
+    cout << "Setting Up RtAudio Interface" << endl;
     cout << gPrintSeparator << endl;
     mRtAudio = new RtAudio;
-    if ( mRtAudio->getDeviceCount() < 1 ) {
+
+    int deviceId_input;
+    int deviceId_output;
+    unsigned int n_devices = mRtAudio->getDeviceCount();
+    if (n_devices < 1) {
         cout << "No audio devices found!" << endl;
         std::exit(0);
+    } else {
+        deviceId_input = getDeviceID();
+        if (deviceId_input < 0) {
+            auto inName    = getInputDevice();
+            deviceId_input = getDeviceIdFromName(inName, true);
+            if (!inName.empty() && (deviceId_input < 0)) {
+                throw std::runtime_error("Requested input device \"" + inName
+                                         + "\" not found.");
+            }
+        }
+        if (deviceId_input < 0) {
+            cout << "Selecting default INPUT device" << endl;
+            if (mRtAudio->getCurrentApi() == RtAudio::LINUX_PULSE) {
+                deviceId_input = getDefaultDevice(true);
+            } else {
+                deviceId_input = mRtAudio->getDefaultInputDevice();
+            }
+        }
+
+        deviceId_output = getDeviceID();
+        if (deviceId_output < 0) {
+            auto outName    = getOutputDevice();
+            deviceId_output = getDeviceIdFromName(outName, false);
+            if (!outName.empty() && (deviceId_output < 0)) {
+                throw std::runtime_error("Requested output device \"" + outName
+                                         + "\" not found.");
+            }
+        }
+        if (deviceId_output < 0) {
+            cout << "Selecting default OUTPUT device" << endl;
+            if (mRtAudio->getCurrentApi() == RtAudio::LINUX_PULSE) {
+                deviceId_output = getDefaultDevice(false);
+            } else {
+                deviceId_output = mRtAudio->getDefaultOutputDevice();
+            }
+        }
     }
 
-    // Get and print default devices
-    RtAudio::DeviceInfo info_input;
-    RtAudio::DeviceInfo info_output;
+    auto dev_info_input  = mRtAudio->getDeviceInfo(deviceId_input);
+    auto dev_info_output = mRtAudio->getDeviceInfo(deviceId_output);
 
-    uint32_t deviceId_input; uint32_t deviceId_output;
-    // use default devices
-    deviceId_input = mJackTrip->getDeviceID();
-    deviceId_output = mJackTrip->getDeviceID();
+    if (static_cast<unsigned int>(getNumInputChannels()) > dev_info_input.inputChannels) {
+        setNumInputChannels(dev_info_input.inputChannels);
+    }
+    if (static_cast<unsigned int>(getNumOutputChannels())
+        > dev_info_output.outputChannels) {
+        setNumOutputChannels(dev_info_output.outputChannels);
+    }
 
-    cout << "DEFAULT INPUT DEVICE  : " << endl;
+    cout << "INPUT DEVICE:" << endl;
     printDeviceInfo(deviceId_input);
     cout << gPrintSeparator << endl;
-    cout << "DEFAULT OUTPUT DEVICE : " << endl;
+    cout << "OUTPUT DEVICE:" << endl;
     printDeviceInfo(deviceId_output);
     cout << gPrintSeparator << endl;
 
     RtAudio::StreamParameters in_params, out_params;
-    in_params.deviceId = deviceId_input;
-    out_params.deviceId = deviceId_output;
-    in_params.nChannels = getNumInputChannels();
+    in_params.deviceId   = deviceId_input;
+    out_params.deviceId  = deviceId_output;
+    in_params.nChannels  = getNumInputChannels();
     out_params.nChannels = getNumOutputChannels();
 
     RtAudio::StreamOptions options;
-    //The second flag affects linux and mac only
+    // The second flag affects linux and mac only
     options.flags = RTAUDIO_NONINTERLEAVED | RTAUDIO_SCHEDULE_REALTIME;
 #ifdef __WIN_32__
     options.flags = options.flags | RTAUDIO_MINIMIZE_LATENCY;
 #endif
-    //linux only
-    options.priority = 99;
+    // linux only
+    options.priority   = 30;
+    options.streamName = gJackDefaultClientName;
 
-    unsigned int sampleRate = getSampleRate();//mSamplingRate;
-    unsigned int bufferFrames = getBufferSizeInSamples();//mBufferSize;
+    unsigned int sampleRate   = getSampleRate();           // mSamplingRate;
+    unsigned int bufferFrames = getBufferSizeInSamples();  // mBufferSize;
 
     try {
         // IMPORTANT NOTE: It's VERY important to remember to pass this
         // as the user data in the process callback, otherwise memeber won't
         // be accessible
-        mRtAudio->openStream(&out_params, &in_params, RTAUDIO_FLOAT32,
-                             sampleRate, &bufferFrames,
-                             &RtAudioInterface::wrapperRtAudioCallback, this, &options);
-    }
-    catch ( RtAudioError & e ) {
+        mRtAudio->openStream(&out_params, &in_params, RTAUDIO_FLOAT32, sampleRate,
+                             &bufferFrames, &RtAudioInterface::wrapperRtAudioCallback,
+                             this, &options);
+        setBufferSize(bufferFrames);
+    } catch (RtAudioError& e) {
         std::cout << '\n' << e.getMessage() << '\n' << std::endl;
-        exit( 0 );
+        exit(0);
     }
 
     // Setup parent class
     AudioInterface::setup();
 }
 
-
 //*******************************************************************************
 void RtAudioInterface::listAllInterfaces()
 {
     RtAudio rtaudio;
-    if ( rtaudio.getDeviceCount() < 1 ) {
-        cout << "No audio devices found!" << endl; }
-    else {
+    if (rtaudio.getDeviceCount() < 1) {
+        cout << "No audio devices found!" << endl;
+    else {
         for (unsigned int i = 0; i < rtaudio.getDeviceCount(); i++) {
             printDeviceInfo(i);
             cout << gPrintSeparator << endl;
@@ -147,6 +181,68 @@ void RtAudioInterface::listAllInterfaces()
     }
 }
 
+//*******************************************************************************
+void RtAudioInterface::printDevices()
+{
+    // TODO: evenntually list devices for all RtAudio-compiled backends
+    RtAudio audio;
+    audio.showWarnings(false);
+    cout << "Available audio devices: " << endl;
+    unsigned int devices = audio.getDeviceCount();
+    RtAudio::DeviceInfo info;
+    for (unsigned int i = 0; i < devices; i++) {
+        info = audio.getDeviceInfo(i);
+        if (info.probed == true) {
+            std::cout << i << ": \"" << info.name << "\" ";
+            std::cout << "(" << info.inputChannels << " ins, " << info.outputChannels
+                      << " outs)" << endl;
+        }
+    }
+}
+
+//*******************************************************************************
+int RtAudioInterface::getDeviceIdFromName(std::string deviceName, bool isInput)
+{
+    RtAudio rtaudio;
+    for (unsigned int i = 0; i < rtaudio.getDeviceCount(); i++) {
+        auto info = rtaudio.getDeviceInfo(i);
+        if (info.probed == true) {
+            if (info.name == deviceName) {
+                if (isInput && info.inputChannels > 0) {
+                    return i;
+                } else if (!isInput && info.outputChannels > 0) {
+                    return i;
+                }
+            }
+        }
+    }
+    return -1;
+}
+
+//*******************************************************************************
+// Use this for getting the default device with PulseAudio
+// At the time of writing this, the latest RtAudio release did not properly
+// select default devices with PulseAudio
+// Once this functinoality is provided upstream and in the distributions'
+// package managers, the following function can be removed and the default device
+// can be obtained by calls to getDefaultInputDevice() / getDefaultOutputDevice()
+unsigned int RtAudioInterface::getDefaultDevice(bool isInput)
+{
+    RtAudio rtaudio;
+    for (unsigned int i = 0; i < rtaudio.getDeviceCount(); i++) {
+        auto info = rtaudio.getDeviceInfo(i);
+        if (info.probed == true) {
+            if (info.isDefaultInput && isInput) {
+                return i;
+            } else if (info.isDefaultOutput && !isInput) {
+                return i;
+            }
+        }
+    }
+    // return the first device if default was not found
+    // this is consistent with RtAudio API
+    return 0;
+}
 
 //*******************************************************************************
 void RtAudioInterface::printDeviceInfo(unsigned int deviceId)
@@ -154,299 +250,74 @@ void RtAudioInterface::printDeviceInfo(unsigned int deviceId)
     RtAudio rtaudio;
     RtAudio::DeviceInfo info;
     int i = deviceId;
-    info = rtaudio.getDeviceInfo(i);
+    info  = rtaudio.getDeviceInfo(i);
     std::vector<unsigned int> sampleRates;
-    cout << "Audio Device  [" << i << "] : "  << info.name << endl;
+    cout << "Audio Device  [" << i << "] : " << info.name << endl;
     cout << "  Output Channels : " << info.outputChannels << endl;
     cout << "  Input Channels  : " << info.inputChannels << endl;
     sampleRates = info.sampleRates;
     cout << "  Supported Sampling Rates: ";
-    for (unsigned int ii = 0; ii<sampleRates.size();ii++) {
+    for (unsigned int ii = 0; ii < sampleRates.size(); ii++) {
         cout << sampleRates[ii] << " ";
     }
     cout << endl;
-    if (info.isDefaultOutput) {
-        cout << "  --Default Output Device--" << endl; }
-    if (info.isDefaultInput) {
-        cout << "  --Default Intput Device--" << endl; }
-    if (info.probed) {
-        cout << "  --Probed Successful--" << endl; }
+    if (info.isDefaultOutput) { cout << "  --Default Output Device--" << endl; }
+    if (info.isDefaultInput) { cout << "  --Default Intput Device--" << endl; }
+    if (info.probed) { cout << "  --Probed Successful--" << endl; }
 }
 
-
 //*******************************************************************************
-int RtAudioInterface::RtAudioCallback(void *outputBuffer, void *inputBuffer,
-                                      unsigned int nFrames,
-                                      double /*streamTime*/, RtAudioStreamStatus /*status*/)
+int RtAudioInterface::RtAudioCallback(void* outputBuffer, void* inputBuffer,
+                                      unsigned int nFrames, double /*streamTime*/,
+                                      RtAudioStreamStatus /*status*/)
 {
-    sample_t* inputBuffer_sample = (sample_t*) inputBuffer;
-    sample_t* outputBuffer_sample = (sample_t*) outputBuffer;
+    sample_t* inputBuffer_sample  = (sample_t*)inputBuffer;
+    sample_t* outputBuffer_sample = (sample_t*)outputBuffer;
 
     // Get input and output buffers
     //-------------------------------------------------------------------
     for (int i = 0; i < mNumInChans; i++) {
         // Input Ports are READ ONLY
-        mInBuffer[i] = inputBuffer_sample+(nFrames*i);
+        mInBuffer[i] = inputBuffer_sample + (nFrames * i);
     }
     for (int i = 0; i < mNumOutChans; i++) {
         // Output Ports are WRITABLE
-        mOutBuffer[i] = outputBuffer_sample+(nFrames*i);
+        mOutBuffer[i] = outputBuffer_sample + (nFrames * i);
     }
 
     AudioInterface::callback(mInBuffer, mOutBuffer, nFrames);
     return 0;
 }
 
-
 //*******************************************************************************
-int RtAudioInterface::wrapperRtAudioCallback(void *outputBuffer, void *inputBuffer,
+int RtAudioInterface::wrapperRtAudioCallback(void* outputBuffer, void* inputBuffer,
                                              unsigned int nFrames, double streamTime,
-                                             RtAudioStreamStatus status, void *userData)
+                                             RtAudioStreamStatus status, voiduserData)
 {
-    return static_cast<RtAudioInterface*>(userData)->RtAudioCallback(outputBuffer,inputBuffer,
-                                                                     nFrames,
-                                                                     streamTime, status);
+    return static_cast<RtAudioInterface*>(userData)->RtAudioCallback(
+        outputBuffer, inputBuffer, nFrames, streamTime, status);
 }
 
-
 //*******************************************************************************
 int RtAudioInterface::startProcess() const
 {
-    try { mRtAudio->startStream(); }
-    catch ( RtAudioError& e ) {
+    try {
+        mRtAudio->startStream();
+    } catch (RtAudioError& e) {
         std::cout << '\n' << e.getMessage() << '\n' << std::endl;
-        return(-1);
+        return (-1);
     }
-    return(0);
+    return (0);
 }
 
-
 //*******************************************************************************
 int RtAudioInterface::stopProcess() const
 {
-    try { mRtAudio->closeStream(); }
-    catch ( RtAudioError& e ) {
+    try {
+        mRtAudio->closeStream();
+    } catch (RtAudioError& e) {
         std::cout << '\n' << e.getMessage() << '\n' << std::endl;
-        return(-1);
+        return (-1);
     }
     return 0;
 }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-// OLD CODE
-// =============================================================================
-
-/*
-int RtAudioInterface::processCallback(jack_nframes_t nframes)
-{
-  mJackTrip->printTextTest();
-  return JackAudioInterface::processCallback(nframes);
-}
-*/
-
-
-//*******************************************************************************
-//int RtAudioInterface::RtAudioCallback(void *outputBuffer, void *inputBuffer,
-//                                      unsigned int nFrames,
-//                                      double /*streamTime*/, RtAudioStreamStatus /*status*/)
-//{
-/*
-  mInBuffer[0] = (sample_t*) inputBuffer;
-  mOutBuffer[0] = (sample_t*) outputBuffer;
-  //AudioInterface::callback(mInBuffer, mOutBuffer, mInputPacket, mOutputPacket,
-  //                         nFrames, mInProcessBuffer, mOutProcessBuffer);
-
-
-  // Output Process (from NETWORK to JACK)
-  // ----------------------------------------------------------------
-  // Read Audio buffer from RingBuffer (read from incoming packets)
-  //mOutRingBuffer->readSlotNonBlocking( mOutputPacket );
-  mJackTrip->receiveNetworkPacket( mOutputPacket );
-
-
-  // Extract separate channels to send to Jack
-  for (int i = 0; i < getNumOutputChannels(); i++) {
-    //--------
-    // This should be faster for 32 bits
-    //std::memcpy(mOutBuffer[i], &mOutputPacket[i*mSizeInBytesPerChannel],
-    //         mSizeInBytesPerChannel);
-    //--------
-    sample_t* tmp_sample = mOutBuffer[i]; //sample buffer for channel i
-    for (unsigned int j = 0; j < nFrames; j++) {
-      //std::memcpy(&tmp_sample[j], &mOutputPacket[(i*mSizeInBytesPerChannel) + (j*4)], 4);
-      // Change the bit resolution on each sample
-      //cout << tmp_sample[j] << endl;
-      AudioInterface::fromBitToSampleConversion(&mOutputPacket[(i*getSizeInBytesPerChannel())
-                 + (j*BIT16)],
-        &tmp_sample[j],
-        BIT16);
-    }
-  }
-
-
-
-  // Input Process (from JACK to NETWORK)
-  // ----------------------------------------------------------------
-  // Concatenate  all the channels from jack to form packet
-  for (int i = 0; i < getNumInputChannels(); i++) {
-    //--------
-    // This should be faster for 32 bits
-    //std::memcpy(&mInputPacket[i*getSizeInBytesPerChannel()], mInBuffer[i],
-    //         mSizeInBytesPerChannel);
-    //--------
-    sample_t* tmp_sample = mInBuffer[i]; //sample buffer for channel i
-    sample_t tmp_result;
-    for (unsigned int j = 0; j < nFrames; j++) {
-      // Add the input jack buffer to the buffer resulting from the output process
-      tmp_result = tmp_sample[j];
-      AudioInterface::fromSampleToBitConversion(&tmp_result,
-                                                    &mInputPacket[(i*getSizeInBytesPerChannel())
-                                                                  + (j*BIT16)],
-                                                    BIT16);
-    }
-  }
-  // Send Audio buffer to RingBuffer (these goes out as outgoing packets)
-  //mInRingBuffer->insertSlotNonBlocking( mInputPacket );
-  mJackTrip->sendNetworkPacket( mInputPacket );
-
-*/
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-//mTestJackTrip->printTextTest();
-
-//if (mJackTrip != NULL)
-//  cout << "(mJackTrip != NULL)" << endl;
-
-
-//if (mJackTrip == NULL) { cout << " === JACKTRIPNULL === " << endl; }
-
-//const int8_t* caca;
-//mJackTrip->sendNetworkPacket( mInputPacket );
-
-//in_buffer = mInBuffer.data();
-//mInBuffer.data() = (float*) inputBuffer;
-
-//mInBuffer[0] = static_cast<float*>(outputBuffer);
-//mOutBuffer[0] = static_cast<sample_t*>(inputBuffer);
-//float* in_buffer = static_cast<float*>(inputBuffer);
-//float* out_buffer = static_cast<float*>(outputBuffer);
-
-
-//cout << "nFrames = ==================== = = = = = = = ======== " << this->getBufferSizeInSamples() << endl;
-//int8_t* input_packet = new int8_t[nFrames*2];
-
-//tmp_sample = floor( (*input) * 32768.0 ); // 2^15 = 32768.0
-
-//JackAudioInterface::fromSampleToBitConversion(in_buffer, input_packet, BIT16);
-//for (int i = 0; i<nFrames; i++) {
-//  cout << in_buffer[i] << endl;
-//}
-//mJackTrip->sendNetworkPacket(input_packet);
-//cout << mJackTrip->getRingBuffersSlotSize() << endl;
-//delete[] input_packet;
-
-
-//mOutputPacket = static_cast<int8_t*>(inputBuffer);
-//mInputPacket = static_cast<int8_t*>(outputBuffer);
-
-// Allocate the Process Callback
-//-------------------------------------------------------------------
-// 1) First, process incoming packets
-// ----------------------------------
-/*
-  mJackTrip->receiveNetworkPacket( mOutputPacket );
-  // Extract separate channels to send to Jack
-  for (int i = 0; i < getNumInputChannels(); i++) {
-    sample_t* tmp_sample = mOutBuffer[i]; //sample buffer for channel i
-    for (int j = 0; j < mBufferSize; j++) {
-      fromBitToSampleConversion(&mOutputPacket[(i*getSizeInBytesPerChannel()) + (j*BIT16)],
-                                &tmp_sample[j],
-                                BIT16);
-    }
-  }
-  */
-
-
-// 3) Finally, send packets to peer
-// --------------------------------
-// Input Process (from JACK to NETWORK)
-// ----------------------------------------------------------------
-// Concatenate  all the channels from jack to form packet
-/*
-  for (int i = 0; i < getNumOutputChannels(); i++) {
-    //--------
-    // This should be faster for 32 bits
-    //std::memcpy(&mInputPacket[i*mSizeInBytesPerChannel], mInBuffer[i],
-    //         mSizeInBytesPerChannel);
-    //--------
-    float* tmp_sample = in_buffer; //sample buffer for channel i
-    //sample_t* tmp_process_sample = mOutProcessBuffer[i]; //sample buffer from the output process
-    sample_t tmp_result;
-    for (int j = 0; j < mBufferSize; j++) {
-      //std::memcpy(&tmp_sample[j], &mOutputPacket[(i*mSizeInBytesPerChannel) + (j*4)], 4);
-      // Change the bit resolution on each sample
-
-      // Add the input jack buffer to the buffer resulting from the output process
-      //tmp_result = tmp_sample[j] + tmp_process_sample[j];
-
-      fromSampleToBitConversion(tmp_sample,
-                                &mInputPacket[(i*getSizeInBytesPerChannel())
-                                              + (j*BIT16)],
-                                BIT16);
-
-
-
-    }
-  }
-  // Send Audio buffer to RingBuffer (these goes out as outgoing packets)
-  //mInRingBuffer->insertSlotNonBlocking( mInputPacket );
-  mJackTrip->sendNetworkPacket( mInputPacket );
-  */
-//return 0;
-//}
-
index 051892fcc0ec2f7e233dc58e01beed7beca0655c..e3fc7d6d81a6c04e65ac95a7c7f9008f2e2c28ff 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
 
 #include "AudioInterface.h"
 #include "jacktrip_globals.h"
-class JackTrip; // Forward declaration
+class JackTrip;  // Forward declaration
 
 /// \brief Base Class that provides an interface with RtAudio
 class RtAudioInterface : public AudioInterface
 {
-public:
-
+   public:
     /** \brief The class constructor
-   * \param jacktrip Pointer to the JackTrip class that connects all classes (mediator)
-   * \param NumInChans Number of Input Channels
-   * \param NumOutChans Number of Output Channels
-   * \param AudioBitResolution Audio Sample Resolutions in bits
-   */
-    RtAudioInterface(JackTrip* jacktrip,
-                     int NumInChans = gDefaultNumInChannels,
-                     int NumOutChans = gDefaultNumOutChannels,
+     * \param jacktrip Pointer to the JackTrip class that connects all classes (mediator)
+     * \param NumInChans Number of Input Channels
+     * \param NumOutChans Number of Output Channels
+     * \param AudioBitResolution Audio Sample Resolutions in bits
+     */
+    RtAudioInterface(JackTrip* jacktrip, int NumInChans = gDefaultNumInChannels,
+                     int NumOutChans                        = gDefaultNumOutChannels,
                      audioBitResolutionT AudioBitResolution = BIT16);
     /// \brief The class destructor
     virtual ~RtAudioInterface();
 
     /// \brief List all avialable audio interfaces, with its properties
     virtual void listAllInterfaces();
+    static void printDevices();
+    virtual int getDeviceIdFromName(std::string deviceName, bool isInput);
     virtual void setup();
     virtual int startProcess() const;
     virtual int stopProcess() const;
@@ -72,26 +72,28 @@ public:
 
     //--------------SETTERS---------------------------------------------
     /// \brief This has no effect in RtAudio
-    virtual void setClientName(const char* /*ClientName*/) {}
+    virtual void setClientName(QString /*ClientName*/) {}
     //------------------------------------------------------------------
 
     //--------------GETTERS---------------------------------------------
     //------------------------------------------------------------------
 
-
-private:
-    int RtAudioCallback(void *outputBuffer, void *inputBuffer, unsigned int nFrames,
+   private:
+    int RtAudioCallback(void* outputBuffer, void* inputBuffer, unsigned int nFrames,
                         double streamTime, RtAudioStreamStatus status);
-    static int wrapperRtAudioCallback(void *outputBuffer, void *inputBuffer, unsigned int nFrames,
-                                      double streamTime, RtAudioStreamStatus status, void *userData);
+    static int wrapperRtAudioCallback(void* outputBuffer, void* inputBuffer,
+                                      unsigned int nFrames, double streamTime,
+                                      RtAudioStreamStatus status, void* userData);
     void printDeviceInfo(unsigned int deviceId);
 
-    JackTrip* mJackTrip; ///< JackTrip Mediator Class pointer
-    int mNumInChans;///< Number of Input Channels
-    int mNumOutChans; ///<  Number of Output Channels
-    QVarLengthArray<float*> mInBuffer; ///< Vector of Input buffers/channel read from JACK
-    QVarLengthArray<float*> mOutBuffer; ///< Vector of Output buffer/channel to write to JACK
-    RtAudio* mRtAudio; ///< RtAudio class
+    int mNumInChans;   ///< Number of Input Channels
+    int mNumOutChans;  ///<  Number of Output Channels
+    QVarLengthArray<float*>
+        mInBuffer;  ///< Vector of Input buffers/channel read from JACK
+    QVarLengthArray<float*>
+        mOutBuffer;     ///< Vector of Output buffer/channel to write to JACK
+    RtAudio* mRtAudio;  ///< RtAudio class
+    unsigned int getDefaultDevice(bool isInput);
 };
 
-#endif // __RTAUDIOINTERFACE_H__
+#endif  // __RTAUDIOINTERFACE_H__
index 4d0802144f0d1eeac57ec1c66723a878dce9e36d..84299b806abffc5627369779540af7c26b8e7716 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
  */
 
 #include "Settings.h"
+
 #include "LoopBack.h"
 //#include "NetKS.h"
 #include "Effects.h"
 
-#ifdef WAIR // wair
-#include "ap8x2.dsp.h"
+#ifdef WAIR  // wair
 #include "Stk16.dsp.h"
-#endif // endwhere
+#include "ap8x2.dsp.h"
+#endif  // endwhere
 
 //#include "JackTripWorker.h"
-#include "jacktrip_globals.h"
+#include <getopt.h>  // for command line parsing
 
-#include <iostream>
-#include <getopt.h> // for command line parsing
+#include <cassert>
+#include <cctype>
 #include <cstdlib>
-#include <assert.h>
-#include <ctype.h>
+#include <iostream>
+
+#include "jacktrip_globals.h"
+
+#ifdef __WIN_32__
+#include <windows.h>
+#else
+#include <termios.h>
+#include <unistd.h>
+#endif
+
+#ifdef __RT_AUDIO__
+#include "RtAudioInterface.h"
+#endif
 
 //#include "ThreadPoolTest.h"
 
-using std::cout; using std::endl;
+using std::cout;
+using std::endl;
 
 int gVerboseFlag = 0;
 
 enum JTLongOptIDS {
-  OPT_BUFSTRATEGY = 1001,
-  OPT_SIMLOSS,
-  OPT_SIMJITTER,
-  OPT_BROADCAST,
-  OPT_RTUDPPRIORITY,
+    OPT_BUFSTRATEGY = 1001,
+    OPT_SIMLOSS,
+    OPT_SIMJITTER,
+    OPT_BROADCAST,
+    OPT_RTUDPPRIORITY,
+    OPT_AUTHCERT,
+    OPT_AUTHKEY,
+    OPT_AUTHCREDS,
+    OPT_AUTHUSER,
+    OPT_AUTHPASS,
+    OPT_NUMRECEIVE,
+    OPT_NUMSEND,
+    OPT_APPENDTHREADID,
+    OPT_LISTDEVICES,
+    OPT_AUDIODEVICE
 };
 
-//*******************************************************************************
-Settings::Settings() :
-    mJackTripMode(JackTrip::SERVER),
-    mDataProtocol(JackTrip::UDP),
-    mNumChans(2),
-    mBufferQueueLength(gDefaultQueueLength),
-    mAudioBitResolution(AudioInterface::BIT16),
-    mBindPortNum(gDefaultPort), mPeerPortNum(gDefaultPort),
-    mServerUdpPortNum(0),
-    mUnderrunMode(JackTrip::WAVETABLE),
-    mStopOnTimeout(false),
-    mBufferStrategy(1),
-    mLoopBack(false),
-    #ifdef WAIR // WAIR
-    mNumNetRevChans(0),
-    mWAIR(false),
-    #endif // endwhere
-    mJamLink(false),
-    mEmptyHeader(false),
-    mJackTripServer(false),
-    mLocalAddress(gDefaultLocalAddress),
-    mRedundancy(1),
-    mUseJack(true),
-    mChanfeDefaultSR(false),
-    mChanfeDefaultID(0),
-    mChanfeDefaultBS(false),
-    mHubConnectionMode(JackTrip::SERVERTOCLIENT),
-    mConnectDefaultAudioPorts(true),
-    mIOStatTimeout(0),
-    mEffects(false), // outgoing limiter OFF by default
-    mSimulatedLossRate(0.0),
-    mSimulatedJitterRate(0.0),
-    mSimulatedDelayRel(0.0),
-    mBroadcastQueue(0),
-    mUseRtUdpPriority(false)
-{}
-
-//*******************************************************************************
-Settings::~Settings() = default;
-
 //*******************************************************************************
 void Settings::parseInput(int argc, char** argv)
 {
     // Always use decimal point for floating point numbers
-    setlocale( LC_NUMERIC, "C" );
+    setlocale(LC_NUMERIC, "C");
     // If no command arguments are given, print instructions
-    if(argc == 1) {
+    if (argc == 1) {
         printUsage();
         std::exit(0);
     }
@@ -125,122 +109,195 @@ void Settings::parseInput(int argc, char** argv)
     //----------------------------------------------------------------------------
     static struct option longopts[] = {
         // These options don't set a flag.
-        { "numchannels", required_argument, NULL, 'n' }, // Number of input and output channels
-#ifdef WAIR // WAIR
-        { "wair", no_argument, NULL, 'w' }, // Run in LAIR mode, sets numnetrevchannels
-        { "addcombfilterlength", required_argument, NULL, 'N' }, // added comb filter length
-        { "combfilterfeedback", required_argument, NULL, 'H' }, // comb filter feedback
-#endif // endwhere
-        { "server", no_argument, NULL, 's' }, // Run in P2P server mode
-        { "client", required_argument, NULL, 'c' }, // Run in P2P client mode, set server IP address
-        { "localaddress", required_argument, NULL, 'L' }, // set local address e.g., 127.0.0.2 for second instance on same host
-        { "jacktripserver", no_argument, NULL, 'S' }, // Run in JamLink mode
-        { "pingtoserver", required_argument, NULL, 'C' }, // Run in ping to server mode, set server IP address
-        { "portoffset", required_argument, NULL, 'o' }, // Port Offset from 4464
-        { "bindport", required_argument, NULL, 'B' }, // Port Offset from 4464
-        { "peerport", required_argument, NULL, 'P' }, // Port Offset from 4464
-        { "udpbaseport", required_argument, NULL, 'U' }, // Server udp base port (defaults to 61002)
-        { "queue", required_argument, NULL, 'q' }, // Queue Length
-        { "redundancy", required_argument, NULL, 'r' }, // Redundancy
-        { "bitres", required_argument, NULL, 'b' }, // Audio Bit Resolution
-        { "zerounderrun", no_argument, NULL, 'z' }, // Use Underrun to Zeros Mode
-        { "timeout", no_argument, NULL, 't' }, // Quit after 10 second network timeout
-        { "loopback", no_argument, NULL, 'l' }, // Run in loopback mode
-        { "jamlink", no_argument, NULL, 'j' }, // Run in JamLink mode
-        { "emptyheader", no_argument, NULL, 'e' }, // Run in JamLink mode
-        { "clientname", required_argument, NULL, 'J' }, // Run in JamLink mode
-        { "remotename", required_argument, NULL, 'K' }, // Client name on hub server
-        { "rtaudio", no_argument, NULL, 'R' }, // Run in JamLink mode
-        { "srate", required_argument, NULL, 'T' }, // Set Sample Rate
-        { "deviceid", required_argument, NULL, 'd' }, // Set RTAudio device id to use
-        { "bufsize", required_argument, NULL, 'F' }, // Set buffer Size
-        { "nojackportsconnect" , no_argument, NULL,  'D'}, // Don't connect default Audio Ports
-        { "version", no_argument, NULL, 'v' }, // Version Number
-        { "verbose", no_argument, NULL, 'V' }, // Verbose mode
-        { "hubpatch", required_argument, NULL, 'p' }, // Set hubConnectionMode for auto patch in Jack
-        { "iostat", required_argument, NULL, 'I' }, // Set IO stat timeout
-        { "iostatlog", required_argument, NULL, 'G' }, // Set IO stat log file
-        { "effects", required_argument, NULL, 'f' }, // Turn on outgoing compressor and incoming reverb, reverbLevel arg
-        { "overflowlimiting", required_argument, NULL, 'O' }, // Turn On limiter, cases 'i', 'o', 'io'
-        { "assumednumclients", required_argument, NULL, 'a' }, // assumed number of clients (sound sources) (otherwise 2)
-        { "bufstrategy", required_argument, NULL, OPT_BUFSTRATEGY }, // Set bufstrategy
-        { "simloss", required_argument, NULL, OPT_SIMLOSS },
-        { "simjitter", required_argument, NULL, OPT_SIMJITTER },
-        { "broadcast", required_argument, NULL, OPT_BROADCAST },
-        { "udprt", no_argument, NULL, OPT_RTUDPPRIORITY },
-        { "help", no_argument, NULL, 'h' }, // Print Help
-        { "examine-audio-delay", required_argument, NULL, 'x' }, // test mode - measure audio round-trip latency statistics
-        { NULL, 0, NULL, 0 }
-    };
+        {"numchannels", required_argument, NULL,
+         'n'},  // Number of input and output channels
+        {"receivechannels", required_argument, NULL,
+         OPT_NUMRECEIVE},  // Number of incoming channels
+        {"sendchannels", required_argument, NULL,
+         OPT_NUMSEND},                     // Number of outgoing channels
+#ifdef WAIR                                // WAIR
+        {"wair", no_argument, NULL, 'w'},  // Run in LAIR mode, sets numnetrevchannels
+        {"addcombfilterlength", required_argument, NULL,
+         'N'},                                                 // added comb filter length
+        {"combfilterfeedback", required_argument, NULL, 'H'},  // comb filter feedback
+#endif                                                         // endwhere
+        {"server", no_argument, NULL, 's'},                    // Run in P2P server mode
+        {"client", required_argument, NULL,
+         'c'},  // Run in P2P client mode, set server IP address
+        {"localaddress", required_argument, NULL,
+         'L'},  // set local address e.g., 127.0.0.2 for second instance on same host
+        {"jacktripserver", no_argument, NULL, 'S'},  // Run in JamLink mode
+        {"pingtoserver", required_argument, NULL,
+         'C'},  // Run in ping to server mode, set server IP address
+        {"portoffset", required_argument, NULL, 'o'},  // Port Offset from 4464
+        {"bindport", required_argument, NULL, 'B'},    // Port Offset from 4464
+        {"peerport", required_argument, NULL, 'P'},    // Port Offset from 4464
+        {"udpbaseport", required_argument, NULL,
+         'U'},  // Server udp base port (defaults to 61002)
+        {"queue", required_argument, NULL, 'q'},       // Queue Length
+        {"redundancy", required_argument, NULL, 'r'},  // Redundancy
+        {"bitres", required_argument, NULL, 'b'},      // Audio Bit Resolution
+        {"zerounderrun", no_argument, NULL, 'z'},      // Use Underrun to Zeros Mode
+        {"timeout", no_argument, NULL, 't'},      // Quit after 10 second network timeout
+        {"loopback", no_argument, NULL, 'l'},     // Run in loopback mode
+        {"jamlink", no_argument, NULL, 'j'},      // Run in JamLink mode
+        {"emptyheader", no_argument, NULL, 'e'},  // Run in JamLink mode
+        {"clientname", required_argument, NULL, 'J'},  // Run in JamLink mode
+        {"remotename", required_argument, NULL, 'K'},  // Client name on hub server
+        {"appendthreadid", no_argument, NULL,
+         OPT_APPENDTHREADID},  // Append thread id to client names
+#ifdef __RT_AUDIO__
+        {"rtaudio", no_argument, NULL, 'R'},      // Run in JamLink mode
+        {"srate", required_argument, NULL, 'T'},  // Set Sample Rate
+        {"deviceid", required_argument, NULL,
+         'd'},  // Set RTAudio device id to use (DEPRECATED)
+        {"audiodevice", required_argument, NULL,
+         OPT_AUDIODEVICE},  // Set RTAudio devices by name
+        {"listdevices", no_argument, NULL,
+         OPT_LISTDEVICES},                          // Set RTAudio device id to use
+        {"bufsize", required_argument, NULL, 'F'},  // Set buffer Size
+#endif
+        {"nojackportsconnect", no_argument, NULL,
+         'D'},                                // Don't connect default Audio Ports
+        {"version", no_argument, NULL, 'v'},  // Version Number
+        {"verbose", no_argument, NULL, 'V'},  // Verbose mode
+        {"hubpatch", required_argument, NULL,
+         'p'},  // Set hubConnectionMode for auto patch in Jack
+        {"iostat", required_argument, NULL, 'I'},     // Set IO stat timeout
+        {"iostatlog", required_argument, NULL, 'G'},  // Set IO stat log file
+        {"effects", required_argument, NULL,
+         'f'},  // Turn on outgoing compressor and incoming reverb, reverbLevel arg
+        {"overflowlimiting", required_argument, NULL,
+         'O'},  // Turn On limiter, cases 'i', 'o', 'io'
+        {"assumednumclients", required_argument, NULL,
+         'a'},  // assumed number of clients (sound sources) (otherwise 2)
+        {"bufstrategy", required_argument, NULL, OPT_BUFSTRATEGY},  // Set bufstrategy
+        {"simloss", required_argument, NULL, OPT_SIMLOSS},
+        {"simjitter", required_argument, NULL, OPT_SIMJITTER},
+        {"broadcast", required_argument, NULL, OPT_BROADCAST},
+        {"udprt", no_argument, NULL, OPT_RTUDPPRIORITY},
+        {"auth", no_argument, NULL,
+         'A'},  // Enable authentication between hub client and hub server
+        {"certfile", required_argument, NULL,
+         OPT_AUTHCERT},  // Certificate for server authentication
+        {"keyfile", required_argument, NULL,
+         OPT_AUTHKEY},  // Private key for server authentication
+        {"credsfile", required_argument, NULL,
+         OPT_AUTHCREDS},  // Username and password store for server authentication
+        {"username", required_argument, NULL,
+         OPT_AUTHUSER},  // Username when using authentication as a hub client
+        {"password", required_argument, NULL,
+         OPT_AUTHPASS},  // Password when using authentication as a hub client
+        {"help", no_argument, NULL, 'h'},  // Print Help
+        {"examine-audio-delay", required_argument, NULL,
+         'x'},  // test mode - measure audio round-trip latency statistics
+        {NULL, 0, NULL, 0}};
 
     // Parse Command Line Arguments
     //----------------------------------------------------------------------------
     /// \todo Specify mandatory arguments
     int ch;
-    while ((ch = getopt_long(argc, argv,
-                             "n:N:H:sc:SC:o:B:P:U:q:r:b:ztlwjeJ:K:RTd:F:p:DvVhI:G:f:O:a:x:", longopts, NULL)) != -1)
+    while (
+        (ch = getopt_long(argc, argv,
+                          "n:N:H:sc:SC:o:B:P:U:q:r:b:ztlwjeJ:K:RTd:F:p:DvVhI:G:f:O:a:x:A",
+                          longopts, NULL))
+        != -1)
         switch (ch) {
-
-        case 'n': // Number of input and output channels
+        case OPT_NUMRECEIVE:
+            if (0 < atoi(optarg)) {
+                mNumAudioOutputChans = atoi(optarg);
+            } else {
+                std::cerr << "--receivechannels ERROR: Number of channels must be "
+                             "greater than 0\n";
+                std::exit(1);
+            }
+            break;
+        case OPT_NUMSEND:
+            if (0 < atoi(optarg)) {
+                mNumAudioInputChans = atoi(optarg);
+            } else {
+                std::cerr << "--sendchannels ERROR: Number of channels must be greater "
+                             "than 0\n";
+                std::exit(1);
+            }
+            break;
+        case 'n':  // Number of input and output channels
             //-------------------------------------------------------
-            mNumChans = atoi(optarg);
+            if (0 < atoi(optarg)) {
+                mNumAudioInputChans  = atoi(optarg);
+                mNumAudioOutputChans = atoi(optarg);
+            } else {
+                std::cerr << "-n --numchannels ERROR: Number of channels must be greater "
+                             "than 0\n";
+                std::exit(1);
+            }
             break;
-        case 'U': // UDP Bind Port
+        case 'U':  // UDP Bind Port
             mServerUdpPortNum = atoi(optarg);
             break;
 #ifdef WAIR
         case 'w':
             //-------------------------------------------------------
             mWAIR = true;
-            mNumNetRevChans = gDefaultNumNetRevChannels; // fixed amount sets number of network channels and comb filters for WAIR
+            mNumNetRevChans =
+                gDefaultNumNetRevChannels;  // fixed amount sets number of network
+                                            // channels and comb filters for WAIR
             break;
         case 'N':
             //-------------------------------------------------------
-            mClientAddCombLen = atoi(optarg); // cmd line comb length adjustment
+            mClientAddCombLen = atoi(optarg);  // cmd line comb length adjustment
             break;
-        case 'H': // comb feedback adjustment
+        case 'H':  // comb feedback adjustment
             //-------------------------------------------------------
-            mClientRoomSize = atof(optarg); // cmd line comb feedback adjustment
+            mClientRoomSize = atof(optarg);  // cmd line comb feedback adjustment
             break;
-#endif // endwhere
-        case 's': // Run in P2P server mode
+#endif             // endwhere
+        case 's':  // Run in P2P server mode
             //-------------------------------------------------------
             mJackTripMode = JackTrip::SERVER;
             break;
-        case 'S': // Run in Hub server mode
+        case 'S':  // Run in Hub server mode
             //-------------------------------------------------------
             mJackTripServer = true;
             break;
-        case 'c': // P2P client mode
+        case 'c':  // P2P client mode
             //-------------------------------------------------------
             mJackTripMode = JackTrip::CLIENT;
-            mPeerAddress = optarg;
+            mPeerAddress  = optarg;
             break;
-        case 'L': // set optional local host address
+        case 'L':  // set optional local host address
             //-------------------------------------------------------
             mLocalAddress = optarg;
             break;
-        case 'C': // Ping to server
+        case 'C':  // Ping to server
             //-------------------------------------------------------
             mJackTripMode = JackTrip::CLIENTTOPINGSERVER;
-            mPeerAddress = optarg;
+            mPeerAddress  = optarg;
             break;
-        case 'o': // Port Offset
+        case 'o':  // Port Offset
             //-------------------------------------------------------
             mBindPortNum += atoi(optarg);
             mPeerPortNum += atoi(optarg);
-            if (gVerboseFlag) std::cout << "SETTINGS: argument parsed for TCP Bind Port: " << mBindPortNum << std::endl;
-            if (gVerboseFlag) std::cout << "SETTINGS: argument parsed for TCP Peer Port: " << mPeerPortNum << std::endl;
+            if (gVerboseFlag)
+                std::cout << "SETTINGS: argument parsed for TCP Bind Port: "
+                          << mBindPortNum << std::endl;
+            if (gVerboseFlag)
+                std::cout << "SETTINGS: argument parsed for TCP Peer Port: "
+                          << mPeerPortNum << std::endl;
             break;
-        case 'B': // Bind Port
+        case 'B':  // Bind Port
             //-------------------------------------------------------
             mBindPortNum = atoi(optarg);
-            if (gVerboseFlag) std::cout << "SETTINGS: argument parsed for TCP Bind Port: " << mBindPortNum << std::endl;
+            if (gVerboseFlag)
+                std::cout << "SETTINGS: argument parsed for TCP Bind Port: "
+                          << mBindPortNum << std::endl;
             break;
-        case 'P': // Peer Port
+        case 'P':  // Peer Port
             //-------------------------------------------------------
             mPeerPortNum = atoi(optarg);
-            if (gVerboseFlag) std::cout << "SETTINGS: argument parsed for TCP Peer Port: " << mPeerPortNum << std::endl;
+            if (gVerboseFlag)
+                std::cout << "SETTINGS: argument parsed for TCP Peer Port: "
+                          << mPeerPortNum << std::endl;
             break;
         case 'b':
             //-------------------------------------------------------
@@ -254,83 +311,100 @@ void Settings::parseInput(int argc, char** argv)
                 mAudioBitResolution = AudioInterface::BIT32;
             } else {
                 printUsage();
-                std::cerr << "--bitres ERROR: Bit resolution: "
-                          << atoi(optarg) << " is not supported." << endl;
+                std::cerr << "--bitres ERROR: Bit resolution: " << atoi(optarg)
+                          << " is not supported." << endl;
                 std::exit(1);
             }
             break;
         case 'q':
             //-------------------------------------------------------
             if (0 == strncmp(optarg, "auto", 4)) {
-              mBufferQueueLength = -atoi(optarg+4);
-              if (0 == mBufferQueueLength) {
-                mBufferQueueLength = -500;
-              }
-            }
-            else if ( atoi(optarg) <= 0 ) {
+                mBufferQueueLength = -atoi(optarg + 4);
+                if (0 == mBufferQueueLength) { mBufferQueueLength = -500; }
+            } else if (atoi(optarg) <= 0) {
                 printUsage();
-                std::cerr << "--queue ERROR: The queue has to be equal or greater than 2" << endl;
-                std::exit(1); }
-            else {
+                std::cerr << "--queue ERROR: The queue has to be equal or greater than 2"
+                          << endl;
+                std::exit(1);
+            } else {
                 mBufferQueueLength = atoi(optarg);
             }
             break;
         case 'r':
             //-------------------------------------------------------
-            if ( atoi(optarg) <= 0 ) {
+            if (atoi(optarg) <= 0) {
                 printUsage();
-                std::cerr << "--redundancy ERROR: The redundancy has to be a positive integer" << endl;
-                std::exit(1); }
-            else {
+                std::cerr
+                    << "--redundancy ERROR: The redundancy has to be a positive integer"
+                    << endl;
+                std::exit(1);
+            } else {
                 mRedundancy = atoi(optarg);
             }
             break;
-        case 'z': // underrun to zero
+        case 'z':  // underrun to zero
             //-------------------------------------------------------
             mUnderrunMode = JackTrip::ZEROS;
             break;
-        case 't': // quit on timeout
+        case 't':  // quit on timeout
             mStopOnTimeout = true;
             break;
-        case 'l': // loopback
+        case 'l':  // loopback
             //-------------------------------------------------------
             mLoopBack = true;
             break;
-        case 'e': // jamlink
+        case 'e':  // jamlink
             //-------------------------------------------------------
             mEmptyHeader = true;
             break;
-        case 'j': // jamlink
+        case 'j':  // jamlink
             //-------------------------------------------------------
             mJamLink = true;
             break;
-        case 'J': // Set client Name
+        case 'J':  // Set client Name
             //-------------------------------------------------------
             mClientName = optarg;
             break;
-        case 'K': // Set Remote client Name
+        case 'K':  // Set Remote client Name
             //-------------------------------------------------------
             mRemoteClientName = optarg;
             break;
-        case 'R': // RtAudio
+        case OPT_APPENDTHREADID:
+            mAppendThreadID = true;
+            break;
+#ifdef __RT_AUDIO__
+        case 'R':  // RtAudio
             //-------------------------------------------------------
             mUseJack = false;
             break;
-        case 'T': // Sampling Rate
+        case 'T':  // Sampling Rate
             //-------------------------------------------------------
-            mChanfeDefaultSR = true;
-            mSampleRate = atoi(optarg);
+            mChangeDefaultSR = true;
+            mSampleRate      = atoi(optarg);
             break;
-        case 'd': // RTAudio device id
+        case 'd':  // RTAudio device id
             //-------------------------------------------------------
-            mChanfeDefaultID = true;
-            mDeviceID = atoi(optarg);
+            cout << "WARNING: Setting device ID is deprecated and will be removed in the "
+                    "future."
+                 << endl;
+            mChangeDefaultID = true;
+            mDeviceID        = atoi(optarg);
             break;
-        case 'F': // Buffer Size
+        case 'F':  // Buffer Size
             //-------------------------------------------------------
-            mChanfeDefaultBS = true;
+            mChangeDefaultBS = true;
             mAudioBufferSize = atoi(optarg);
             break;
+        case OPT_AUDIODEVICE:  // Set audio device
+            //-------------------------------------------------------
+            setDevicesByString(optarg);
+            break;
+        case OPT_LISTDEVICES:  // List audio devices
+            //-------------------------------------------------------
+            RtAudioInterface::printDevices();
+            std::exit(0);
+            break;
+#endif
         case 'D':
             //-------------------------------------------------------
             mConnectDefaultAudioPorts = false;
@@ -338,8 +412,14 @@ void Settings::parseInput(int argc, char** argv)
         case 'v':
             //-------------------------------------------------------
             cout << "JackTrip VERSION: " << gVersion << endl;
-            cout << "Copyright (c) 2008-2020 Juan-Pablo Caceres, Chris Chafe." << endl;
+            cout << "Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe." << endl;
             cout << "SoundWIRE group at CCRMA, Stanford University" << endl;
+#ifdef QT_OPENSOURCE
+            cout << "This build of JackTrip is subject to LGPL license." << endl;
+#endif
+            cout << "JackTrip source code is released under MIT and GPL licenses."
+                 << endl;
+            cout << "See LICENSE.md file for more information." << endl;
             cout << "" << endl;
             std::exit(0);
             break;
@@ -351,26 +431,26 @@ void Settings::parseInput(int argc, char** argv)
             break;
         case 'p':
             //-------------------------------------------------------
-            if ( atoi(optarg) == 0 ) {
+            if (atoi(optarg) == 0) {
                 mHubConnectionMode = JackTrip::SERVERTOCLIENT;
-            } else if ( atoi(optarg) == 1 ) {
+            } else if (atoi(optarg) == 1) {
                 mHubConnectionMode = JackTrip::CLIENTECHO;
-            } else if ( atoi(optarg) == 2 ) {
+            } else if (atoi(optarg) == 2) {
                 mHubConnectionMode = JackTrip::CLIENTFOFI;
-            } else if ( atoi(optarg) == 3 ) {
+            } else if (atoi(optarg) == 3) {
                 mHubConnectionMode = JackTrip::RESERVEDMATRIX;
-            } else if ( atoi(optarg) == 4 ) {
+            } else if (atoi(optarg) == 4) {
                 mHubConnectionMode = JackTrip::FULLMIX;
-            } else if ( atoi(optarg) == 5 ) {
+            } else if (atoi(optarg) == 5) {
                 mHubConnectionMode = JackTrip::NOAUTO;
             } else {
                 printUsage();
-                std::cerr << "-p ERROR: Wrong HubConnectionMode: "
-                          << atoi(optarg) << " is not supported." << endl;
+                std::cerr << "-p ERROR: Wrong HubConnectionMode: " << atoi(optarg)
+                          << " is not supported." << endl;
                 std::exit(1);
             }
             break;
-        case 'I': // IO Stat timeout
+        case 'I':  // IO Stat timeout
             //-------------------------------------------------------
             mIOStatTimeout = atoi(optarg);
             if (0 > mIOStatTimeout) {
@@ -379,41 +459,40 @@ void Settings::parseInput(int argc, char** argv)
                 std::exit(1);
             }
             break;
-        case 'G': // IO Stat log file
+        case 'G':  // IO Stat log file
             //-------------------------------------------------------
             mIOStatStream.reset(new std::ofstream(optarg));
             if (!mIOStatStream->is_open()) {
                 printUsage();
-                std::cerr << "--iostatlog FAILED to open " << optarg
-                          << " for writing." << endl;
+                std::cerr << "--iostatlog FAILED to open " << optarg << " for writing."
+                          << endl;
                 std::exit(1);
             }
             break;
-        case OPT_BUFSTRATEGY: // Buf strategy
+        case OPT_BUFSTRATEGY:  // Buf strategy
             mBufferStrategy = atoi(optarg);
-            if (-1 > mBufferStrategy || 2 < mBufferStrategy) {
+            if (-1 > mBufferStrategy || 3 < mBufferStrategy) {
                 std::cerr << "Unsupported buffer strategy " << optarg << endl;
                 printUsage();
                 std::exit(1);
             }
             break;
-        case OPT_SIMLOSS: // Simulate packet loss
+        case OPT_SIMLOSS:  // Simulate packet loss
             mSimulatedLossRate = atof(optarg);
             break;
-        case OPT_SIMJITTER: // Simulate jitter
+        case OPT_SIMJITTER:  // Simulate jitter
             char* endp;
             mSimulatedJitterRate = strtod(optarg, &endp);
             if (0 == *endp) {
                 mSimulatedDelayRel = 1.0;
-            }
-            else {
-                mSimulatedDelayRel = atof(endp+1);
+            } else {
+                mSimulatedDelayRel = atof(endp + 1);
             }
             break;
-        case OPT_BROADCAST: // Broadcast output
+        case OPT_BROADCAST:  // Broadcast output
             mBroadcastQueue = atoi(optarg);
             break;
-        case OPT_RTUDPPRIORITY: // Use RT priority for UDPDataProtocol thread
+        case OPT_RTUDPPRIORITY:  // Use RT priority for UDPDataProtocol thread
             mUseRtUdpPriority = true;
             break;
         case 'h':
@@ -421,139 +500,181 @@ void Settings::parseInput(int argc, char** argv)
             printUsage();
             std::exit(0);
             break;
-        case 'O': { // Overflow limiter (i, o, or io)
-          //-------------------------------------------------------
-          char cmd[] { "--overflowlimiting (-O)" };
-          if (gVerboseFlag) {
-            printf("%s argument = %s\n",cmd,optarg);
-          }
-          int returnCode = mEffects.parseLimiterOptArg(cmd,optarg);
-          if (returnCode > 1) {
-            mEffects.printHelp(cmd,ch);
-            std::cerr << cmd << " required argument `" << optarg << "' is malformed\n";
-            std::exit(1);
-          } else if (returnCode == 1) {
-            std::exit(0); // benign but not continuing such as "help"
-          }
-          break; }
-        case 'a': { // assumed number of clients (applies to outgoing limiter)
-          //-------------------------------------------------------
-          char cmd[] { "--assumednumclients (-a)" };
-          if (gVerboseFlag) {
-            printf("%s argument = %s\n",cmd,optarg);
-          }
-          int returnCode = mEffects.parseAssumedNumClientsOptArg(cmd,optarg);
-          if (returnCode > 1) {
-            mEffects.printHelp(cmd,ch);
-            std::cerr << cmd << " required argument `" << optarg << "' is malformed\n";
-            std::exit(1);
-          } else if (returnCode == 1) {
-            std::exit(0); // help printed
-          }
-          break; }
-        case 'f': { // --effects (-f) effectsSpecArg
-          //-------------------------------------------------------
-          char cmd[] { "--effects (-f)" };
-          int returnCode = mEffects.parseEffectsOptArg(cmd,optarg);
-          if (returnCode > 1) {
-            mEffects.printHelp(cmd,ch);
-            std::cerr << cmd << " required argument `" << optarg << "' is malformed\n";
-            std::exit(1);
-          } else if (returnCode == 1) {
-            std::exit(0); // something benign but non-continuing like "help"
-          }
-          break; }
-        case 'x': { // examine connection (test mode)
-          //-------------------------------------------------------
-          char cmd[] { "--examine-audio-delay (-x)" };
-          if (tolower(optarg[0])=='h') {
-            mAudioTester.printHelp(cmd,ch);
-            std::exit(0);
-          }
-          mAudioTester.setEnabled(true);
-          if (optarg == 0 || optarg[0] == '-' || optarg[0] == 0) { // happens when no -f argument specified
-            printUsage();
-            std::cerr << cmd << " ERROR: Print-interval argument REQUIRED (set to 0.0 to see every delay)\n";
-            std::exit(1);
-          }
-          mAudioTester.setPrintIntervalSec(atof(optarg));
-          break; }
+        case 'O': {  // Overflow limiter (i, o, or io)
+            //-------------------------------------------------------
+            char cmd[]{"--overflowlimiting (-O)"};
+            if (gVerboseFlag) { printf("%s argument = %s\n", cmd, optarg); }
+            int returnCode = mEffects.parseLimiterOptArg(cmd, optarg);
+            if (returnCode > 1) {
+                mEffects.printHelp(cmd, ch);
+                std::cerr << cmd << " required argument `" << optarg
+                          << "' is malformed\n";
+                std::exit(1);
+            } else if (returnCode == 1) {
+                std::exit(0);  // benign but not continuing such as "help"
+            }
+            break;
+        }
+        case 'a': {  // assumed number of clients (applies to outgoing limiter)
+            //-------------------------------------------------------
+            char cmd[]{"--assumednumclients (-a)"};
+            if (gVerboseFlag) { printf("%s argument = %s\n", cmd, optarg); }
+            int returnCode = mEffects.parseAssumedNumClientsOptArg(cmd, optarg);
+            if (returnCode > 1) {
+                mEffects.printHelp(cmd, ch);
+                std::cerr << cmd << " required argument `" << optarg
+                          << "' is malformed\n";
+                std::exit(1);
+            } else if (returnCode == 1) {
+                std::exit(0);  // help printed
+            }
+            break;
+        }
+        case 'f': {  // --effects (-f) effectsSpecArg
+            //-------------------------------------------------------
+            char cmd[]{"--effects (-f)"};
+            int returnCode = mEffects.parseEffectsOptArg(cmd, optarg);
+            if (returnCode > 1) {
+                mEffects.printHelp(cmd, ch);
+                std::cerr << cmd << " required argument `" << optarg
+                          << "' is malformed\n";
+                std::exit(1);
+            } else if (returnCode == 1) {
+                std::exit(0);  // something benign but non-continuing like "help"
+            }
+            break;
+        }
+        case 'A':
+            mAuth = true;
+            break;
+        case OPT_AUTHCERT:
+            mCertFile = optarg;
+            break;
+        case OPT_AUTHKEY:
+            mKeyFile = optarg;
+            break;
+        case OPT_AUTHCREDS:
+            mCredsFile = optarg;
+            break;
+        case OPT_AUTHUSER:
+            mUsername = optarg;
+            break;
+        case OPT_AUTHPASS:
+            mPassword = optarg;
+            break;
+        case 'x': {  // examine connection (test mode)
+            //-------------------------------------------------------
+            char cmd[]{"--examine-audio-delay (-x)"};
+            if (tolower(optarg[0]) == 'h') {
+                mAudioTester->printHelp(cmd, ch);
+                std::exit(0);
+            }
+            mAudioTester->setEnabled(true);
+            if (optarg == 0 || optarg[0] == '-'
+                || optarg[0] == 0) {  // happens when no -f argument specified
+                printUsage();
+                std::cerr << cmd
+                          << " ERROR: Print-interval argument REQUIRED (set to 0.0 to "
+                             "see every delay)\n";
+                std::exit(1);
+            }
+            mAudioTester->setPrintIntervalSec(atof(optarg));
+            break;
+        }
         case ':': {
-          printUsage();
-          printf("*** Missing option argument *** see above for usage\n\n");
-          break; }
+            printUsage();
+            printf("*** Missing option argument *** see above for usage\n\n");
+            break;
+        }
         case '?': {
-          printUsage();
-          printf("*** Unknown, missing, or ambiguous option argument *** see above for usage\n\n");
-          std::exit(1);
-          break; }
+            printUsage();
+            printf(
+                "*** Unknown, missing, or ambiguous option argument *** see above for "
+                "usage\n\n");
+            std::exit(1);
+            break;
+        }
         default: {
             //-------------------------------------------------------
             printUsage();
-            printf("*** Unrecognized option -%c *** see above for usage\n",ch);
+            printf("*** Unrecognized option -%c *** see above for usage\n", ch);
             std::exit(1);
-            break; }
+            break;
+        }
         }
 
     // Warn user if undefined options where entered
     //----------------------------------------------------------------------------
     if (optind < argc) {
-      if (strcmp(argv[optind],"help")!=0) {
-        cout << gPrintSeparator << endl;
-        cout << "*** Unexpected command-line argument(s): ";
-        for( ; optind < argc; optind++) {
-          cout << argv[optind] << " ";
+        if (strcmp(argv[optind], "help") != 0) {
+            cout << gPrintSeparator << endl;
+            cout << "*** Unexpected command-line argument(s): ";
+            for (; optind < argc; optind++) { cout << argv[optind] << " "; }
+            cout << endl << gPrintSeparator << endl;
         }
-        cout << endl << gPrintSeparator << endl;
-      }
-      printUsage();
-      std::exit(1);
+        printUsage();
+        std::exit(1);
     }
 
-    assert(mNumChans>0);
-    mAudioTester.setSendChannel(mNumChans-1); // use last channel for latency testing
-    // Originally, testing only in the last channel was adopted
-    // because channel 0 ("left") was a clap track on CCRMA loopback
-    // servers.  Now, however, we also do it in order to easily keep
-    // effects in all but the last channel, enabling silent testing
-    // in the last channel in parallel with normal operation of the others.
-
+    if (true == mAudioTester->getEnabled()) {
+        assert(mNumAudioInputChans > 0);
+        mAudioTester->setSendChannel(mNumAudioInputChans
+                                     - 1);  // use last channel for latency testing
+        // Originally, testing only in the last channel was adopted
+        // because channel 0 ("left") was a clap track on CCRMA loopback
+        // servers.  Now, however, we also do it in order to easily keep
+        // effects in all but the last channel, enabling silent testing
+        // in the last channel in parallel with normal operation of the others.
+    }
     // Exit if options are incompatible
     //----------------------------------------------------------------------------
-    bool haveSomeServerMode = not ((mJackTripMode == JackTrip::CLIENT) || (mJackTripMode == JackTrip::CLIENTTOPINGSERVER));
+    bool haveSomeServerMode = not((mJackTripMode == JackTrip::CLIENT)
+                                  || (mJackTripMode == JackTrip::CLIENTTOPINGSERVER));
     if (mEffects.getHaveEffect() && haveSomeServerMode) {
-      std::cerr << "*** --effects (-f) ERROR: Effects not yet supported server modes (-S and -s).\n\n";
-      std::exit(1);
+        std::cerr << "*** --effects (-f) ERROR: Effects not yet supported server modes "
+                     "(-S and -s).\n\n";
+        std::exit(1);
     }
     if (mEffects.getHaveLimiter() && haveSomeServerMode) {
-      if (mEffects.getLimit() != Effects::LIMITER_MODE::LIMITER_OUTGOING) { // default case
-        std::cerr << "*** --overflowlimiting (-O) ERROR: Limiters not yet supported server modes (-S and -s).\n\n";
-      }
-      mEffects.setNoLimiters();
-      // don't exit since an outgoing limiter should be the default (could exit for incoming case):
-      // std::exit(1);
+        if (mEffects.getLimit()
+            != Effects::LIMITER_MODE::LIMITER_OUTGOING) {  // default case
+            std::cerr << "*** --overflowlimiting (-O) ERROR: Limiters not yet supported "
+                         "server modes (-S and -s).\n\n";
+        }
+        mEffects.setNoLimiters();
+        // don't exit since an outgoing limiter should be the default (could exit for
+        // incoming case): std::exit(1);
     }
-    if (mAudioTester.getEnabled() && haveSomeServerMode) {
-      std::cerr << "*** --examine-audio-delay (-x) ERROR: Audio latency measurement not supported in server modes (-S and -s)\n\n";
-      std::exit(1);
+    if (mAudioTester->getEnabled() && haveSomeServerMode) {
+        std::cerr << "*** --examine-audio-delay (-x) ERROR: Audio latency measurement "
+                     "not supported in server modes (-S and -s)\n\n";
+        std::exit(1);
     }
-    if (mAudioTester.getEnabled()
-        && (mAudioBitResolution != AudioInterface::BIT16)
-        && (mAudioBitResolution != AudioInterface::BIT32) ) { // BIT32 not tested but should be ok
-      // BIT24 should work also, but there's a comment saying it's broken right now, so exclude it
-      std::cerr << "*** --examine-audio-delay (-x) ERROR: Only --bitres (-b) 16 and 32 presently supported for audio latency measurement.\n\n";
-      std::exit(1);
+    if (mAudioTester->getEnabled() && (mAudioBitResolution != AudioInterface::BIT16)
+        && (mAudioBitResolution
+            != AudioInterface::BIT32)) {  // BIT32 not tested but should be ok
+        // BIT24 should work also, but there's a comment saying it's broken right now, so
+        // exclude it
+        std::cerr << "*** --examine-audio-delay (-x) ERROR: Only --bitres (-b) 16 and 32 "
+                     "presently supported for audio latency measurement.\n\n";
+        std::exit(1);
     }
 }
 
 //*******************************************************************************
 void Settings::printUsage()
 {
+    // clang-format off
     cout << "" << endl;
     cout << "JackTrip: A System for High-Quality Audio Network Performance" << endl;
     cout << "over the Internet" << endl;
-    cout << "Copyright (c) 2008-2020 Juan-Pablo Caceres, Chris Chafe." << endl;
+    cout << "Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe." << endl;
     cout << "SoundWIRE group at CCRMA, Stanford University" << endl;
+#ifdef QT_OPENSOURCE
+    cout << "This build of JackTrip is subject to LGPL license." << endl;
+#endif
+    cout << "JackTrip source code is released under MIT and GPL licenses." << endl;
+    cout << "See LICENSE.md file for more information." << endl;
     cout << "VERSION: " << gVersion << endl;
     cout << "" << endl;
     cout << "Usage: jacktrip [-s|-c|-S|-C hostIPAddressOrURL] [options]" << endl;
@@ -566,87 +687,189 @@ void Settings::printUsage()
     cout << " -C, --pingtoserver <peer_name_or_IP>     Run in Hub Client Mode" << endl;
     cout << endl;
     cout << "OPTIONAL ARGUMENTS: " << endl;
-    cout << " -n, --numchannels #                      Number of Input and Output Channels (default: "
+    cout << " -n, --numchannels #                      Number of Input and Output "
+            "Channels (# greater than 0, default: "
          << 2 << ")" << endl;
-#ifdef WAIR // WAIR
+    cout << "     --receivechannels #                       Number of receive Channels from "
+            "the network (# greater than 0)\n";
+    cout << "     --sendchannels #                          Number of send Channels to "
+            "the network (# greater than 0)\n";
+#ifdef WAIR  // WAIR
     cout << " -w, --wair                               Run in WAIR Mode" << endl;
-    cout << " -N, --addcombfilterlength #              comb length adjustment for WAIR (default "
+    cout << " -N, --addcombfilterlength #              comb length adjustment for WAIR "
+            "(default "
          << gDefaultAddCombFilterLength << ")" << endl;
-    cout << " -H, --combfilterfeedback # (roomSize)    comb feedback adjustment for WAIR (default "
+    cout << " -H, --combfilterfeedback # (roomSize)    comb feedback adjustment for WAIR "
+            "(default "
          << gDefaultCombFilterFeedback << ")" << endl;
-#endif // endwhere
-    cout << " -q, --queue       # (2 or more)          Queue Buffer Length, in Packet Size (default: "
+#endif  // endwhere
+    cout << " -q, --queue # (2 or more)                Queue Buffer Length, in Packet "
+            "Size (default: "
          << gDefaultQueueLength << ")" << endl;
-    cout << " -r, --redundancy  # (1 or more)          Packet Redundancy to avoid glitches with packet losses (default: 1)"
+    cout << " -r, --redundancy # (1 or more)           Packet Redundancy to avoid "
+            "glitches with packet losses (default: 1)"
+         << endl;
+    cout << " -o, --portoffset #                       Receiving bind port and peer port "
+            "offset from default "
+         << gDefaultPort << endl;
+    cout << " -B, --bindport #                         Set only the bind port number "
+            "(default: "
+         << gDefaultPort << ")" << endl;
+    cout << " -P, --peerport #                         Set only the peer port number "
+            "(default: "
+         << gDefaultPort << ")" << endl;
+    cout << " -U, --udpbaseport                        Set only the server udp base port "
+            "number (default: 61002)"
+         << endl;
+    cout << " -b, --bitres # (8, 16, 24, 32)           Audio Bit Rate Resolutions "
+            "(default: 16, 32 uses floating-point)"
+         << endl;
+    cout << " -p, --hubpatch # (0, 1, 2, 3, 4, 5)      Hub auto audio patch, only has "
+            "effect if running HUB SERVER mode, 0=server-to-clients, 1=client loopback, "
+            "2=client fan out/in but not loopback, 3=reserved for TUB, 4=full mix, 5=no "
+            "auto patching (default: 0)"
+         << endl;
+    cout << " -z, --zerounderrun                       Set buffer to zeros when underrun "
+            "occurs (default: wavetable)"
+         << endl;
+    cout << " -t, --timeout                            Quit after 10 seconds of no "
+            "network activity"
          << endl;
-    cout << " -o, --portoffset  #                      Receiving bind port and peer port offset from default " << gDefaultPort << endl;
-    cout << " -B, --bindport        #                  Set only the bind port number (default: " << gDefaultPort << ")" << endl;
-    cout << " -P, --peerport        #                  Set only the peer port number (default: " << gDefaultPort << ")" << endl;
-    cout << " -U, --udpbaseport                        Set only the server udp base port number (default: 61002)" << endl;
-    cout << " -b, --bitres      # (8, 16, 24, 32)      Audio Bit Rate Resolutions (default: 16, 32 uses floating-point)" << endl;
-    cout << " -p, --hubpatch    # (0, 1, 2, 3, 4, 5)   Hub auto audio patch, only has effect if running HUB SERVER mode, 0=server-to-clients, 1=client loopback, 2=client fan out/in but not loopback, 3=reserved for TUB, 4=full mix, 5=no auto patching (default: 0)" << endl;
-    cout << " -z, --zerounderrun                       Set buffer to zeros when underrun occurs (default: wavetable)" << endl;
-    cout << " -t, --timeout                            Quit after 10 seconds of no network activity" << endl;
     cout << " -l, --loopback                           Run in Loop-Back Mode" << endl;
-    cout << " -j, --jamlink                            Run in JamLink Mode (Connect to a JamLink Box)" << endl;
-    cout << " -J, --clientname                         Change default client name (default: JackTrip)" << endl;
-    cout << " -K, --remotename                         Change default remote client name when connecting to a hub server (the default is derived from this computer's external facing IP address)" << endl;
-    cout << " -L, --localaddress                       Change default local host IP address (default: 127.0.0.1)" << endl;
-    cout << " -D, --nojackportsconnect                 Don't connect default audio ports in jack" << endl;
-    cout << " --bufstrategy     # (0, 1, 2)            Use alternative jitter buffer" << endl;
-    cout << " --broadcast <broadcast_queue>            Turn on broadcast output ports with extra queue (requires new jitter buffer)" << endl;
-    cout << " --udprt                                  Use RT thread priority for network I/O" << endl;
+    cout << " -j, --jamlink                            Run in JamLink Mode (Connect to a "
+            "JamLink Box)"
+         << endl;
+    cout << " -J, --clientname                         Change default client name "
+            "(default: JackTrip)"
+         << endl;
+    cout << " -K, --remotename                         Change default remote client name "
+            "when connecting to a hub server (the default is derived from this "
+            "computer's external facing IP address)"
+         << endl;
+    cout << " --appendthreadid                         Append thread ID to client names\n";
+    cout << " -L, --localaddress                       Change default local host IP "
+            "address (default: 127.0.0.1)"
+         << endl;
+    cout << " -D, --nojackportsconnect                 Don't connect default audio ports "
+            "in jack"
+         << endl;
+    cout << " --bufstrategy # (0, 1, 2)                Use alternative jitter buffer"
+         << endl;
+    cout << " --broadcast <broadcast_queue>            Duplicate receive ports with the specified broadcast_queue length. "
+                                                       "Broadcast outputs have higher latency but less packet loss.\n";
+    cout << " --udprt                                  Use RT thread priority for "
+            "network I/O"
+         << endl;
     cout << endl;
     cout << "OPTIONAL SIGNAL PROCESSING: " << endl;
-    cout << " -f, --effects # | paramString | help     Turn on incoming and/or outgoing compressor and/or reverb in Client - see `-f help' for details" << endl;
+    cout << " -f, --effects # | paramString | help     Turn on incoming and/or outgoing "
+            "compressor and/or reverb in Client - see `-f help' for details"
+         << endl;
     cout << " -O, --overflowlimiting i|o[w]|io[w]|n|help" << endl;
-    cout << "                                          Use audio limiter(s) in Client, i=incoming from network, o=outgoing to network, io=both, n=no limiters, w=warn if limiting (default=n). Say -O help for more." << endl;
-    cout << " -a, --assumednumclients help|# (1,2,...) Assumed number of Clients (sources) mixing at Hub Server (otherwise 2 assumed by -O)" << endl;
+    cout << "                                          Use audio limiter(s) in Client, "
+            "i=incoming from network, o=outgoing to network, io=both, n=no limiters, "
+            "w=warn if limiting (default=n). Say -O help for more."
+         << endl;
+    cout << " -a, --assumednumclients help|# (1,2,..)  Assumed number of Clients "
+            "(sources) mixing at Hub Server (otherwise 2 assumed by -O)"
+         << endl;
     cout << endl;
+#ifdef __RT_AUDIO__
     cout << "ARGUMENTS TO USE JACKTRIP WITHOUT JACK:" << endl;
-    cout << " -R, --rtaudio                            Use system's default sound system instead of Jack" << endl;
-    cout << " -T, --srate         #                    Set the sampling rate, works on --rtaudio mode only (default: 48000)" << endl;
-    cout << " -F, --bufsize       #                    Set the buffer size, works on --rtaudio mode only (default: 128)" << endl;
-    cout << " -d, --deviceid      #                    The rtaudio device id --rtaudio mode only (default: 0)" << endl;
+    cout << " -R, --rtaudio                            Use system's default sound system "
+            "instead of Jack"
+         << endl;
+    cout << " -T, --srate #                            Set the sampling rate, works on "
+            "--rtaudio mode only (default: 48000)"
+         << endl;
+    cout << " -F, --bufsize #                          Set the buffer size, works on "
+            "--rtaudio mode only (default: 128)"
+         << endl;
+    cout << " --audiodevice \"input-output device name\"" << endl;
+    cout << " --audiodevice \"input device name\",\"output device name\"" << endl;
+    cout << "                                          Set audio device to use; if not set, "
+            "the default device will be used"
+         << endl;
+    cout << " --listdevices                            List available audio devices"
+         << endl;
+    cout << " -d, --deviceid #                         Set rtaudio device id (DEPRECATED, "
+            "use --audiodevice instead)"
+         << endl;
     cout << endl;
+#endif
     cout << "ARGUMENTS TO DISPLAY IO STATISTICS:" << endl;
-    cout << " -I, --iostat <time_in_secs>              Turn on IO stat reporting with specified interval (in seconds)" << endl;
-    cout << " -G, --iostatlog <log_file>               Save stat log into a file (default: print in stdout)" << endl;
+    cout << " -I, --iostat <time_in_secs>              Turn on IO stat reporting with "
+            "specified interval (in seconds)"
+         << endl;
+    cout << " -G, --iostatlog <log_file>               Save stat log into a file "
+            "(default: print in stdout)"
+         << endl;
     cout << " -x, --examine-audio-delay <print_interval_in_secs> | help\n";
-    cout << "                                          Print round-trip audio delay statistics. See `-x help' for details." << endl;
+    cout << "                                          Print round-trip audio delay "
+            "statistics. See `-x help' for details."
+         << endl;
     cout << endl;
     cout << "ARGUMENTS TO SIMULATE NETWORK ISSUES:" << endl;
     cout << " --simloss <rate>                         Simulate packet loss" << endl;
-    cout << " --simjitter <rate>,<d>                   Simulate jitter, d is max delay in packets" << endl;
+    cout << " --simjitter <rate>,<d>                   Simulate jitter, d is max delay "
+            "in packets"
+         << endl;
+    cout << endl;
+    cout << "ARGUMENTS FOR HUB CLIENT/SERVER AUTHENTICATION:" << endl;
+    cout << " -A, --auth                               Use authentication on the client side, or require it on the server side" << endl;
+    cout << " --certfile                               The certificate file to use on the hub server" << endl;
+    cout << " --keyfile                                The private key file to use on the hub server" << endl;
+    cout << " --credsfile                              The file containing the stored usernames and passwords" << endl;
+    cout << " --username                               The username to use when connecting as a hub client (if not supplied here, this is read from standard input)" << endl;
+    cout << " --password                               The password to use when connecting as a hub client (if not supplied here, this is read from standard input)" << endl;
     cout << endl;
     cout << "HELP ARGUMENTS: " << endl;
     cout << " -v, --version                            Prints Version Number" << endl;
-    cout << " -V, --verbose                            Verbose mode, prints debug messages" << endl;
+    cout << " -V, --verbose                            Verbose mode, prints debug messages"
+         << endl;
     cout << " -h, --help                               Prints this Help" << endl;
     cout << "" << endl;
+    // clang-format on
 }
 
+#ifdef __RT_AUDIO__
+void Settings::setDevicesByString(std::string nameArg)
+{
+    size_t commaPos;
+    char delim = ',';
+    if (std::count(nameArg.begin(), nameArg.end(), delim) > 1) {
+        throw std::invalid_argument(
+            "Found multiple commas in the --audiodevice argument, cannot parse "
+            "reliably.");
+    }
+    commaPos = nameArg.rfind(delim);
+    if (commaPos || nameArg[0] == delim) {
+        mInputDeviceName  = nameArg.substr(0, commaPos);
+        mOutputDeviceName = nameArg.substr(commaPos + 1);
+    } else {
+        mInputDeviceName = mOutputDeviceName = nameArg;
+    }
+}
+#endif
 
 //*******************************************************************************
-UdpHubListener *Settings::getConfiguredHubServer()
+UdpHubListenerSettings::getConfiguredHubServer()
 {
     if ((mBindPortNum < gBindPortLow) || (mBindPortNum > gBindPortHigh))
-        std::cout << "BindPort: "<< mBindPortNum << " outside range"  << std::endl;
+        std::cout << "BindPort: " << mBindPortNum << " outside range" << std::endl;
 
-    if (gVerboseFlag) std::cout << "JackTrip HUB SERVER TCP Bind Port: " << mBindPortNum << std::endl;
-    UdpHubListener *udpHub = new UdpHubListener(mBindPortNum, mServerUdpPortNum);
-    //udpHub->setSettings(this);
-#ifdef WAIR // WAIR
+    if (gVerboseFlag)
+        std::cout << "JackTrip HUB SERVER TCP Bind Port: " << mBindPortNum << std::endl;
+    UdpHubListener* udpHub = new UdpHubListener(mBindPortNum, mServerUdpPortNum);
+    // udpHub->setSettings(this);
+#ifdef WAIR  // WAIR
     udpHub->setWAIR(mWAIR);
-#endif // endwhere
+#endif  // endwhere
     udpHub->setHubPatch(mHubConnectionMode);
-    if (mHubConnectionMode == JackTrip::NOAUTO) {
-        udpHub->setConnectDefaultAudioPorts(false);
-    } else {
-        udpHub->setConnectDefaultAudioPorts(mConnectDefaultAudioPorts);
-    }
+    // Connect default audio ports must be set after the connection mode.
+    udpHub->setConnectDefaultAudioPorts(mConnectDefaultAudioPorts);
     // Set buffers to zero when underrun
-    if ( mUnderrunMode == JackTrip::ZEROS ) {
+    if (mUnderrunMode == JackTrip::ZEROS) {
         cout << "Setting buffers to zero when underrun..." << endl;
         cout << gPrintSeparator << std::endl;
         udpHub->setUnderRunMode(mUnderrunMode);
@@ -654,44 +877,55 @@ UdpHubListener *Settings::getConfiguredHubServer()
     udpHub->setBufferQueueLength(mBufferQueueLength);
 
     udpHub->setBufferStrategy(mBufferStrategy);
-    udpHub->setNetIssuesSimulation(mSimulatedLossRate,
-        mSimulatedJitterRate, mSimulatedDelayRel);
+    udpHub->setNetIssuesSimulation(mSimulatedLossRate, mSimulatedJitterRate,
+                                   mSimulatedDelayRel);
     udpHub->setBroadcast(mBroadcastQueue);
     udpHub->setUseRtUdpPriority(mUseRtUdpPriority);
-    
+
+    if (true == mAppendThreadID) { udpHub->mAppendThreadID = true; }
+
     if (mIOStatTimeout > 0) {
         udpHub->setIOStatTimeout(mIOStatTimeout);
         udpHub->setIOStatStream(mIOStatStream);
     }
+
+    if (mAuth) {
+        //(We don't need to check the validity of these files because it's done by the
+        // UdpHubListener.)
+        udpHub->setRequireAuth(mAuth);
+        udpHub->setCertFile(mCertFile);
+        udpHub->setKeyFile(mKeyFile);
+        udpHub->setCredsFile(mCredsFile);
+    }
     return udpHub;
 }
 
-JackTrip *Settings::getConfiguredJackTrip()
+JackTripSettings::getConfiguredJackTrip()
 {
-#ifdef WAIR // WAIR
-    if (gVerboseFlag) std::cout << "Settings:startJackTrip mNumNetRevChans = " << mNumNetRevChans << std::endl;
-#endif // endwhere
-    if (gVerboseFlag) std::cout << "Settings:startJackTrip before new JackTrip" << std::endl;
-    JackTrip *jackTrip = new JackTrip(mJackTripMode, mDataProtocol, mNumChans,
-#ifdef WAIR // wair
-                                      mNumNetRevChans,
-#endif // endwhere
-                                      mBufferQueueLength, mRedundancy, mAudioBitResolution,
-                                      /*DataProtocol::packetHeaderTypeT PacketHeaderType = */DataProtocol::DEFAULT,
-                                      /*underrunModeT UnderRunMode = */ mUnderrunMode,
-                                      /* int receiver_bind_port = */ mBindPortNum,
-                                      /*int sender_bind_port = */ mBindPortNum,
-                                      /*int receiver_peer_port = */ mPeerPortNum,
-                                      /* int sender_peer_port = */ mPeerPortNum,
-                                      mPeerPortNum
-                                      );
+#ifdef WAIR  // WAIR
+    if (gVerboseFlag)
+        std::cout << "Settings:startJackTrip mNumNetRevChans = " << mNumNetRevChans
+                  << std::endl;
+#endif  // endwhere
+    if (gVerboseFlag)
+        std::cout << "Settings:startJackTrip before new JackTrip" << std::endl;
+    JackTrip* jackTrip = new JackTrip(
+        mJackTripMode, mDataProtocol, mNumAudioInputChans, mNumAudioOutputChans,
+#ifdef WAIR  // wair
+        mNumNetRevChans,
+#endif  // endwhere
+        mBufferQueueLength, mRedundancy, mAudioBitResolution,
+        /*DataProtocol::packetHeaderTypeT PacketHeaderType = */ DataProtocol::DEFAULT,
+        /*underrunModeT UnderRunMode = */ mUnderrunMode,
+        /* int receiver_bind_port = */ mBindPortNum,
+        /*int sender_bind_port = */ mBindPortNum,
+        /*int receiver_peer_port = */ mPeerPortNum,
+        /* int sender_peer_port = */ mPeerPortNum, mPeerPortNum);
     // Set connect or not default audio ports. Only work for jack
     jackTrip->setConnectDefaultAudioPorts(mConnectDefaultAudioPorts);
 
     // Change client name if different from default
-    if (!mClientName.isEmpty()) {
-        jackTrip->setClientName(mClientName);
-    }
+    if (!mClientName.isEmpty()) { jackTrip->setClientName(mClientName); }
 
     if (!mRemoteClientName.isEmpty() && (mJackTripMode == JackTrip::CLIENTTOPINGSERVER)) {
         jackTrip->setRemoteClientName(mRemoteClientName);
@@ -706,23 +940,13 @@ JackTrip *Settings::getConfiguredJackTrip()
     jackTrip->setStopOnTimeout(mStopOnTimeout);
 
     // Set peer address in server mode
-    if (mJackTripMode == JackTrip::CLIENT || mJackTripMode == JackTrip::CLIENTTOPINGSERVER) {
-        jackTrip->setPeerAddress(mPeerAddress); }
-
-    //        if(mLocalAddress!=QString()) // default
-    //            mJackTrip->setLocalAddress(QHostAddress(mLocalAddress.toLatin1().data()));
-    //        else
-    //            mJackTrip->setLocalAddress(QHostAddress::Any);
-
-    // Set Ports - Done in constructor now.
-    //cout << "SETTING ALL PORTS" << endl;
-    /*if (gVerboseFlag) std::cout << "Settings:startJackTrip before mJackTrip->setBindPorts" << std::endl;
-    jackTrip->setBindPorts(mBindPortNum);
-    if (gVerboseFlag) std::cout << "Settings:startJackTrip before mJackTrip->setPeerPorts" << std::endl;
-    jackTrip->setPeerPorts(mPeerPortNum);*/
+    if (mJackTripMode == JackTrip::CLIENT
+        || mJackTripMode == JackTrip::CLIENTTOPINGSERVER) {
+        jackTrip->setPeerAddress(mPeerAddress);
+    }
 
     // Set in JamLink Mode
-    if ( mJamLink ) {
+    if (mJamLink) {
         cout << "Running in JamLink Mode..." << endl;
         cout << gPrintSeparator << std::endl;
         jackTrip->setPacketHeaderType(DataProtocol::JAMLINK);
@@ -737,52 +961,70 @@ JackTrip *Settings::getConfiguredJackTrip()
 
     // Set RtAudio
 #ifdef __RT_AUDIO__
-    if (!mUseJack) {
-        mJackTrip->setAudiointerfaceMode(JackTrip::RTAUDIO);
-    }
-#endif
+    if (!mUseJack) { jackTrip->setAudiointerfaceMode(JackTrip::RTAUDIO); }
 
-    // Chanfe default Sampling Rate
-    if (mChanfeDefaultSR) {
-        jackTrip->setSampleRate(mSampleRate);
-    }
+    // Change default Sampling Rate
+    if (mChangeDefaultSR) { jackTrip->setSampleRate(mSampleRate); }
 
-    // Chanfe defualt device ID
-    if (mChanfeDefaultID) {
-        jackTrip->setDeviceID(mDeviceID);
-    }
+    // Change defualt device ID
+    if (mChangeDefaultID) { jackTrip->setDeviceID(mDeviceID); }
+
+    // Change default Buffer Size
+    if (mChangeDefaultBS) { jackTrip->setAudioBufferSizeInSamples(mAudioBufferSize); }
+
+    // Set device names
+    jackTrip->setInputDevice(mInputDeviceName);
+    jackTrip->setOutputDevice(mOutputDeviceName);
+#endif
 
-    // Chanfe default Buffer Size
-    if (mChanfeDefaultBS) {
-        jackTrip->setAudioBufferSizeInSamples(mAudioBufferSize);
-    }
     jackTrip->setBufferStrategy(mBufferStrategy);
-    jackTrip->setNetIssuesSimulation(mSimulatedLossRate,
-        mSimulatedJitterRate, mSimulatedDelayRel);
+    jackTrip->setNetIssuesSimulation(mSimulatedLossRate, mSimulatedJitterRate,
+                                     mSimulatedDelayRel);
     jackTrip->setBroadcast(mBroadcastQueue);
     jackTrip->setUseRtUdpPriority(mUseRtUdpPriority);
 
+    // Set auth details if we're in hub client mode
+    if (mAuth && mJackTripMode == JackTrip::CLIENTTOPINGSERVER) {
+        jackTrip->setUseAuth(true);
+        if (mUsername.isEmpty()) {
+            std::cout << "Username: ";
+            std::string username;
+            std::cin >> username;
+            mUsername = QString(username.c_str());
+        }
+        if (mPassword.isEmpty()) {
+            std::cout << "Password: ";
+            disableEcho(true);
+            std::string password;
+            std::cin >> password;
+            mPassword = QString(password.c_str());
+            disableEcho(false);
+        }
+        jackTrip->setUsername(mUsername);
+        jackTrip->setPassword(mPassword);
+    }
+
     // Add Plugins
     if (mLoopBack) {
         cout << "Running in Loop-Back Mode..." << endl;
         cout << gPrintSeparator << std::endl;
-        //std::tr1::shared_ptr<LoopBack> loopback(new LoopBack(mNumChans));
-        //mJackTrip->appendProcessPlugin(loopback.get());
+        // std::tr1::shared_ptr<LoopBack> loopback(new LoopBack(mNumChans));
+        // mJackTrip->appendProcessPlugin(loopback.get());
 
-#if 0 // previous technique:
+#if 0  // previous technique:
         LoopBack* loopback = new LoopBack(mNumChans);
         jackTrip->appendProcessPlugin(loopback);
-#else // simpler method ( see AudioInterface.cpp callback() ):
+#else  // simpler method ( see AudioInterface.cpp callback() ):
         jackTrip->setLoopBack(true);
 #endif
 
         // ----- Test Karplus Strong -----------------------------------
-        //std::tr1::shared_ptr<NetKS> loopback(new NetKS());
-        //mJackTrip->appendProcessPlugin(loopback);
-        //loopback->play();
-        //NetKS* netks = new NetKS;
-        //mJackTrip->appendProcessPlugin(netks);
-        //netks->play();
+        // std::tr1::shared_ptr<NetKS> loopback(new NetKS());
+        // mJackTrip->appendProcessPlugin(loopback);
+        // loopback->play();
+        // NetKS* netks = new NetKS;
+        // mJackTrip->appendProcessPlugin(netks);
+        // netks->play();
         // -------------------------------------------------------------
     }
 
@@ -791,45 +1033,71 @@ JackTrip *Settings::getConfiguredJackTrip()
         jackTrip->setIOStatStream(mIOStatStream);
     }
 
-    jackTrip->setAudioTesterP(&mAudioTester);
+    jackTrip->setAudioTesterP(mAudioTester);
 
     // Allocate audio effects in client, if any:
-    int nReservedChans = mAudioTester.getEnabled() ? 1 : 0; // no fx allowed on tester channel
-    std::vector<ProcessPlugin*> outgoingEffects = mEffects.allocateOutgoingEffects(mNumChans-nReservedChans);
-    for (auto p : outgoingEffects) {
-      jackTrip->appendProcessPluginToNetwork( p );
-    }
-    std::vector<ProcessPlugin*> incomingEffects = mEffects.allocateIncomingEffects(mNumChans-nReservedChans);
-    for (auto p : incomingEffects) {
-      jackTrip->appendProcessPluginFromNetwork( p );
-    }
+    int nReservedChans =
+        mAudioTester->getEnabled() ? 1 : 0;  // no fx allowed on tester channel
 
-#ifdef WAIR // WAIR
-    if ( mWAIR ) {
+    std::vector<ProcessPlugin*> outgoingEffects =
+        mEffects.allocateOutgoingEffects(mNumAudioInputChans - nReservedChans);
+    for (auto p : outgoingEffects) { jackTrip->appendProcessPluginToNetwork(p); }
+
+    std::vector<ProcessPlugin*> incomingEffects =
+        mEffects.allocateIncomingEffects(mNumAudioOutputChans - nReservedChans);
+    for (auto p : incomingEffects) { jackTrip->appendProcessPluginFromNetwork(p); }
+
+#ifdef WAIR  // WAIR
+    if (mWAIR) {
         cout << "Running in WAIR Mode..." << endl;
         cout << gPrintSeparator << std::endl;
-        switch ( mNumNetRevChans )
-        {
-        case 16 :
-        {
-            jackTrip->appendProcessPluginFromNetwork(new ap8x2(mNumChans)); // plugin slot 0
+        switch (mNumNetRevChans) {
+        case 16: {
+            jackTrip->appendProcessPluginFromNetwork(
+                new ap8x2(mNumChansOut));  // plugin slot 0
             /////////////////////////////////////////////////////////
             Stk16* plugin = new Stk16(mNumNetRevChans);
             plugin->Stk16::initCombClient(mClientAddCombLen, mClientRoomSize);
-            jackTrip->appendProcessPluginFromNetwork(plugin); // plugin slot 1
-        }
-            break;
-        default:
-            throw std::invalid_argument("Settings: mNumNetRevChans doesn't correspond to Faust plugin");
-            break;
-        }
-            break;
+            jackTrip->appendProcessPluginFromNetwork(plugin);  // plugin slot 1
+        } break;
         default:
-            throw std::invalid_argument("Settings: mNumNetRevChans doesn't correspond to Faust plugin");
+            throw std::invalid_argument(
+                "Settings: mNumNetRevChans doesn't correspond to Faust plugin");
             break;
         }
+        break;
+    default:
+        throw std::invalid_argument(
+            "Settings: mNumNetRevChans doesn't correspond to Faust plugin");
+        break;
     }
-#endif // endwhere
+}
+#endif  // endwhere
+
+return jackTrip;
+}
+
+void Settings::disableEcho(bool disabled)
+{
+#ifdef __WIN_32__
+    HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
+    DWORD mode;
+    GetConsoleMode(hStdin, &mode);
 
-    return jackTrip;
+    if (disabled) {
+        mode &= ~ENABLE_ECHO_INPUT;
+    } else {
+        mode |= ENABLE_ECHO_INPUT;
+    }
+    SetConsoleMode(hStdin, mode);
+#else
+    struct termios tty;
+    tcgetattr(STDIN_FILENO, &tty);
+    if (disabled) {
+        tty.c_lflag &= ~ECHO;
+    } else {
+        tty.c_lflag |= ECHO;
+    }
+    tcsetattr(STDIN_FILENO, TCSANOW, &tty);
+#endif
 }
index 569b451d4a7562de5a81409434f22f41e934d65e..2dd12b3393575f3138f485cfffd2334536942721 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
@@ -35,7 +35,6 @@
  * \date July 2008
  */
 
-
 #ifndef __SETTINGS_H__
 #define __SETTINGS_H__
 
 
 #ifndef __NO_JACK__
 #include "JackAudioInterface.h"
-#endif //__NO_JACK__
+#endif  //__NO_JACK__
 
+#include "AudioTester.h"
+#include "Effects.h"
 #include "JackTrip.h"
 #include "UdpHubListener.h"
 
-#include "Effects.h"
-#include "AudioTester.h"
-
 /** \brief Class to set usage options and parse settings from input
  */
 class Settings : public QObject
 {
     Q_OBJECT;
 
-public:
-    Settings();
-    virtual ~Settings();
+   public:
+    Settings() : mAudioTester(new AudioTester) {}
 
     /// \brief Parses command line input
     void parseInput(int argc, char** argv);
 
-    UdpHubListener *getConfiguredHubServer();
-    JackTrip *getConfiguredJackTrip();
+    UdpHubListenergetConfiguredHubServer();
+    JackTripgetConfiguredJackTrip();
 
     /// \brief Prints usage help
     void printUsage();
+#ifdef __RT_AUDIO__
+    void setDevicesByString(std::string nameArg);
+#endif
 
     bool getLoopBack() { return mLoopBack; }
     bool isHubServer() { return mJackTripServer; }
 
-private:
-    JackTrip::jacktripModeT mJackTripMode; ///< JackTrip::jacktripModeT
-    JackTrip::dataProtocolT mDataProtocol; ///< Data Protocol
-    int mNumChans; ///< Number of Channels (inputs = outputs)
-    int mBufferQueueLength; ///< Audio Buffer from network queue length
-    AudioInterface::audioBitResolutionT mAudioBitResolution;
-    QString mPeerAddress; ///< Peer Address to use in jacktripModeT::CLIENT Mode
-    int mBindPortNum; ///< Bind Port Number
-    int mPeerPortNum; ///< Peer Port Number
-    int mServerUdpPortNum;
-    QString mClientName; ///< JackClient Name
+   private:
+    void disableEcho(bool disabled);
+
+    JackTrip::jacktripModeT mJackTripMode =
+        JackTrip::SERVER;                                   ///< JackTrip::jacktripModeT
+    JackTrip::dataProtocolT mDataProtocol = JackTrip::UDP;  ///< Data Protocol
+    int mNumAudioInputChans               = 2;              ///< Number of Input Channels
+    int mNumAudioOutputChans              = 2;              ///< Number of Output Channels
+    int mBufferQueueLength =
+        gDefaultQueueLength;  ///< Audio Buffer from network queue length
+    AudioInterface::audioBitResolutionT mAudioBitResolution = AudioInterface::BIT16;
+    QString mPeerAddress;  ///< Peer Address to use in jacktripModeT::CLIENT Mode
+    int mBindPortNum      = gDefaultPort;  ///< Bind Port Number
+    int mPeerPortNum      = gDefaultPort;  ///< Peer Port Number
+    int mServerUdpPortNum = 0;
+    QString mClientName;  ///< JackClient Name
     QString mRemoteClientName;
-    JackTrip::underrunModeT mUnderrunMode; ///< Underrun mode
-    bool mStopOnTimeout; /// < Stop jacktrip after 10 second network timeout
-    int mBufferStrategy;
-
-#ifdef WAIR // wair
-    int mNumNetRevChans; ///< Number of Network Audio Channels (net comb filters)
-    int mClientAddCombLen; ///< cmd line adjustment of net comb
-    double mClientRoomSize; ///< freeverb room size
-    bool mWAIR; ///< WAIR mode
-#endif // endwhere
-
-    bool mLoopBack; ///< Loop-back mode
-    bool mJamLink; ///< JamLink mode
-    bool mEmptyHeader; ///< EmptyHeader mode
-    bool mJackTripServer; ///< JackTrip Server mode
-    QString mLocalAddress; ///< Local Address
-    unsigned int mRedundancy; ///< Redundancy factor for data in the network
-    bool mUseJack; ///< Use or not JackAduio
-    bool mChanfeDefaultSR; ///< Change Default Sampling Rate
-    bool mChanfeDefaultID; ///< Change Default device ID
-    bool mChanfeDefaultBS; ///< Change Default Buffer Size
+    bool mAppendThreadID{false};
+    JackTrip::underrunModeT mUnderrunMode{JackTrip::WAVETABLE};  ///< Underrun mode
+    bool mStopOnTimeout{false};  /// < Stop jacktrip after 10 second network timeout
+    int mBufferStrategy{1};
+
+#ifdef WAIR                   // wair
+    int mNumNetRevChans = 0;  ///< Number of Network Audio Channels (net comb filters)
+    int mClientAddCombLen;    ///< cmd line adjustment of net comb
+    double mClientRoomSize;   ///< freeverb room size
+    bool mWAIR = false;       ///< WAIR mode
+#endif                        // endwhere
+
+    bool mLoopBack           = false;                 ///< Loop-back mode
+    bool mJamLink            = false;                 ///< JamLink mode
+    bool mEmptyHeader        = false;                 ///< EmptyHeader mode
+    bool mJackTripServer     = false;                 ///< JackTrip Server mode
+    QString mLocalAddress    = gDefaultLocalAddress;  ///< Local Address
+    unsigned int mRedundancy = 1;      ///< Redundancy factor for data in the network
+    bool mUseJack            = true;   ///< Use or not JackAduio
+    bool mChangeDefaultSR    = false;  ///< Change Default Sampling Rate
+    bool mChangeDefaultID    = 0;      ///< Change Default device ID
+    bool mChangeDefaultBS    = false;  ///< Change Default Buffer Size
+#ifdef __RT_AUDIO__
     unsigned int mSampleRate;
     unsigned int mDeviceID;
     unsigned int mAudioBufferSize;
-    unsigned int mHubConnectionMode;
-    bool mConnectDefaultAudioPorts; ///< Connect or not jack audio ports
-    int mIOStatTimeout;
+    std::string mInputDeviceName, mOutputDeviceName;
+#endif
+    unsigned int mHubConnectionMode = JackTrip::SERVERTOCLIENT;
+    bool mConnectDefaultAudioPorts  = true;  ///< Connect or not jack audio ports
+    int mIOStatTimeout              = 0;
     QSharedPointer<std::ofstream> mIOStatStream;
-    Effects mEffects;
-    double mSimulatedLossRate;
-    double mSimulatedJitterRate;
-    double mSimulatedDelayRel;
-    int mBroadcastQueue;
-    bool mUseRtUdpPriority;
-    AudioTester mAudioTester;
+    Effects mEffects            = false;  // outgoing limiter OFF by default
+    double mSimulatedLossRate   = 0.0;
+    double mSimulatedJitterRate = 0.0;
+    double mSimulatedDelayRel   = 0.0;
+    int mBroadcastQueue         = 0;
+    bool mUseRtUdpPriority      = false;
+
+    bool mAuth = false;
+    QString mCertFile;
+    QString mKeyFile;
+    QString mCredsFile;
+    QString mUsername;
+    QString mPassword;
+
+    QSharedPointer<AudioTester> mAudioTester;
 };
 
 #endif
diff --git a/src/SslServer.cpp b/src/SslServer.cpp
new file mode 100644 (file)
index 0000000..b371268
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+  JackTrip: A System for High-Quality Audio Network Performance
+  over the Internet
+
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
+  SoundWIRE group at CCRMA, Stanford University.
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation
+  files (the "Software"), to deal in the Software without
+  restriction, including without limitation the rights to use,
+  copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the
+  Software is furnished to do so, subject to the following
+  conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+  OTHER DEALINGS IN THE SOFTWARE.
+*/
+//*****************************************************************
+
+/**
+ * \file SslServer.cpp
+ * \author Aaron Wyatt
+ * \date September 2020
+ */
+
+#include "SslServer.h"
+
+#include <QSslSocket>
+
+SslServer::SslServer(QObject* parent) : QTcpServer(parent) {}
+
+void SslServer::incomingConnection(qintptr socketDescriptor)
+{
+    // Override of the QTcpServer incomingConnection function to create
+    // an SslSocket rather than a regular socket.
+    QSslSocket* sslSocket = new QSslSocket(this);
+    sslSocket->setSocketDescriptor(socketDescriptor);
+    sslSocket->setLocalCertificate(m_certificate);
+    sslSocket->setPrivateKey(m_privateKey);
+    this->addPendingConnection(sslSocket);
+}
+
+void SslServer::setCertificate(const QSslCertificate& certificate)
+{
+    m_certificate = certificate;
+}
+
+void SslServer::setPrivateKey(const QSslKey& key) { m_privateKey = key; }
+
+SslServer::~SslServer() = default;
diff --git a/src/SslServer.h b/src/SslServer.h
new file mode 100644 (file)
index 0000000..f3fd1fa
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+  JackTrip: A System for High-Quality Audio Network Performance
+  over the Internet
+
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
+  SoundWIRE group at CCRMA, Stanford University.
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation
+  files (the "Software"), to deal in the Software without
+  restriction, including without limitation the rights to use,
+  copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the
+  Software is furnished to do so, subject to the following
+  conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+  OTHER DEALINGS IN THE SOFTWARE.
+*/
+//*****************************************************************
+
+/**
+ * \file SslServer.h
+ * \author Aaron Wyatt
+ * \date September 2020
+ */
+
+#ifndef __SSLSERVER_H__
+#define __SSLSERVER_H__
+
+#include <QSslCertificate>
+#include <QSslKey>
+#include <QTcpServer>
+
+class SslServer : public QTcpServer
+{
+    Q_OBJECT
+
+   public:
+    SslServer(QObject* parent);
+    ~SslServer();
+
+    void incomingConnection(qintptr socketDescriptor) override;
+    void setCertificate(const QSslCertificate& certificate);
+    void setPrivateKey(const QSslKey& key);
+
+   private:
+    QSslCertificate m_certificate;
+    QSslKey m_privateKey;
+};
+
+#endif  // __SSLSERVER_H__
diff --git a/src/TestRingBuffer.h b/src/TestRingBuffer.h
deleted file mode 100644 (file)
index 0f6296d..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef __TESTRINGBUFFER__
-#define __TESTRINGBUFFER__
-
-#include "RingBuffer.h"
-#include <QThread>
-#include <iostream>
-
-static RingBuffer rb(2,100);
-
-class TestRingBufferWrite : public QThread
-{
-public:
-
-    void run()
-    {
-        int8_t* writeSlot;
-        writeSlot = new int8_t[2];
-        writeSlot[0] = *"a";
-        writeSlot[1] = *"b";
-        while (true) {
-            //std::cout << "writing BEFORE" << std::endl;
-            rb.insertSlotBlocking(writeSlot);
-            //std::cout << "writing AFTER" << std::endl;
-        }
-    }
-
-};
-
-
-class TestRingBufferRead : public QThread
-{
-public:
-
-    void run()
-    {
-        int8_t* readSlot;
-        readSlot = new int8_t[2];
-        while (true) {
-            //std::cout << "reading BEFORE" << std::endl;
-            rb.readSlotBlocking(readSlot);
-            //std::cout << "reading AFTER" << std::endl;
-            //std::cout << *(readSlot) << std::endl;
-            //std::cout << *(readSlot+1) << std::endl;
-        }
-    }
-};
-
-#endif
diff --git a/src/ThreadPoolTest.h b/src/ThreadPoolTest.h
deleted file mode 100644 (file)
index 5f7de67..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * \file ThreadPoolTest.h
- * \author Juan-Pablo Caceres
- * \date October 2008
- */
-
-#ifndef __THREADPOOLTEST_H__
-#define __THREADPOOLTEST_H__
-
-#include <QThreadPool>
-#include <QEventLoop>
-#include <QThread>
-#include <QObject>
-
-#include <iostream>
-
-#include "NetKS.h"
-#include "JackTripWorkerMessages.h"
-
-
-class ThreadPoolTest : public QObject, public QRunnable
-        //class ThreadPoolTest : public QThread
-{
-    Q_OBJECT;
-
-public:
-    ThreadPoolTest()
-    {
-        setAutoDelete(false);
-    }
-
-    void run()
-    {
-        JackTripWorkerMessages jtm;
-        QThread testThread;
-        //jtm.moveToThread(&testThread);
-
-        //QObject::connect(&jtm, SIGNAL(signalTest()), &jtm, SLOT(slotTest()), Qt::QueuedConnection);
-        testThread.start();
-        jtm.play();
-        //testThread.wait();
-
-        //std::cout << "--------------- BEFORE ---------------" << std::endl;
-        //NetKS netks;
-        //netks.play();
-        //std::cout << "--------------- AFTER ---------------" << std::endl;
-
-        QEventLoop loop;
-        //QObject::connect(this, SIGNAL(stopELoop()), &loop, SLOT(quit()), Qt::QueuedConnection);
-        loop.exec();
-        //std::cout << "--------------- EXITING QRUNNABLE---------------" << std::endl;
-        /*
-    while (true) {
-      std::cout << "Hello world from thread" << std::endl;
-      sleep(1);
-    }
-    */
-    }
-
-    void stop()
-    {
-        std::cout << "--------------- ELOOP STOP---------------" << std::endl;
-        emit stopELoop();
-    }
-
-signals:
-    void stopELoop();
-
-private slots:
-    void fromServer()
-    {
-        std::cout << "--------------- SIGNAL RECEIVED ---------------" << std::endl;
-    }
-
-};
-
-#endif //__THREADPOOLTEST_H__
index 3680185f0291c01952daa85eb5da330a0aefc817..7dab7c1a05e1c0d9ecee7475a8eef340284816c7 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
  * \date June 2008
  */
 
+//#define __MANUAL_POLL__
+
 #include "UdpDataProtocol.h"
-#include "jacktrip_globals.h"
-#include "JackTrip.h"
 
 #include <QHostInfo>
-
+#include <cerrno>
+#include <cstdlib>
 #include <cstring>
 #include <iostream>
-#include <cstdlib>
-#include <cerrno>
 #include <stdexcept>
+
+#include "JackTrip.h"
+#include "jacktrip_globals.h"
 #ifdef __WIN_32__
 //#include <winsock.h>
-#include <winsock2.h> //cc need SD_SEND
-#include <ws2tcpip.h> // for IPv6
+#include <winsock2.h>  //cc need SD_SEND
 #endif
-#if defined (__LINUX__) || (__MAC_OSX__)
-#include <sys/socket.h> // for POSIX Sockets
-#include <unistd.h>
+#if defined(__LINUX__) || defined(__MAC_OSX__)
 #include <sys/fcntl.h>
+#include <sys/socket.h>  // for POSIX Sockets
+#include <unistd.h>
+#endif
+#if defined(__MAC_OSX__) && !defined(__MANUAL_POLL__)
+#include <sys/event.h>
+#elif defined(__LINUX__) && !defined(__MANUAL_POLL__)
+#include <sys/epoll.h>
 #endif
 
-using std::cout; using std::endl;
+using std::cout;
+using std::endl;
 
 // NOTE: It's better not to use
 // using namespace std;
@@ -69,32 +76,34 @@ QMutex UdpDataProtocol::sUdpMutex;
 //*******************************************************************************
 UdpDataProtocol::UdpDataProtocol(JackTrip* jacktrip, const runModeT runmode,
                                  int bind_port, int peer_port,
-                                 unsigned int udp_redundancy_factor) :
-    DataProtocol(jacktrip, runmode, bind_port, peer_port),
-    mBindPort(bind_port), mPeerPort(peer_port),
-    mRunMode(runmode),
-    mAudioPacket(NULL), mFullPacket(NULL),
-    mUdpRedundancyFactor(udp_redundancy_factor),
-    mControlPacketSize(63),
-    mStopSignalSent(false)
+                                 unsigned int udp_redundancy_factor)
+    : DataProtocol(jacktrip, runmode, bind_port, peer_port)
+    , mBindPort(bind_port)
+    , mPeerPort(peer_port)
+    , mRunMode(runmode)
+    , mAudioPacket(NULL)
+    , mFullPacket(NULL)
+    , mUdpRedundancyFactor(udp_redundancy_factor)
+    , mControlPacketSize(63)
+    , mStopSignalSent(false)
 {
     mStopped = false;
-    mIPv6 = false;
+    mIPv6    = false;
     std::memset(&mPeerAddr, 0, sizeof(mPeerAddr));
     std::memset(&mPeerAddr6, 0, sizeof(mPeerAddr6));
-    mPeerAddr.sin_port = htons(mPeerPort);
+    mPeerAddr.sin_port   = htons(mPeerPort);
     mPeerAddr6.sin6_port = htons(mPeerPort);
-    
+
     if (mRunMode == RECEIVER) {
-        QObject::connect(this, SIGNAL(signalWaitingTooLong(int)),
-                         jacktrip, SLOT(slotUdpWaitingTooLongClientGoneProbably(int)), Qt::QueuedConnection);
+        QObject::connect(this, SIGNAL(signalWaitingTooLong(int)), jacktrip,
+                         SLOT(slotUdpWaitingTooLongClientGoneProbably(int)),
+                         Qt::QueuedConnection);
     }
-    mSimulatedLossRate = 0.0;
-    mSimulatedJitterRate = 0.0;
+    mSimulatedLossRate       = 0.0;
+    mSimulatedJitterRate     = 0.0;
     mSimulatedJitterMaxDelay = 0.0;
 }
 
-
 //*******************************************************************************
 UdpDataProtocol::~UdpDataProtocol()
 {
@@ -110,13 +119,12 @@ UdpDataProtocol::~UdpDataProtocol()
     wait();
 }
 
-
 //*******************************************************************************
 void UdpDataProtocol::setPeerAddress(const char* peerHostOrIP)
 {
     // Get DNS Address
-#if defined (__LINUX__) || (__MAC_OSX__)
-    //Don't make the following code conditional on windows
+#if defined(__LINUX__) || defined(__MAC_OSX__)
+    // Don't make the following code conditional on windows
     //(Addresses a weird timing bug when in hub client mode)
     if (!mPeerAddress.setAddress(peerHostOrIP)) {
 #endif
@@ -125,23 +133,23 @@ void UdpDataProtocol::setPeerAddress(const char* peerHostOrIP)
             // use the first IP address
             mPeerAddress = info.addresses().first();
         }
-        //cout << "UdpDataProtocol::setPeerAddress IP Address Number: "
+        // cout << "UdpDataProtocol::setPeerAddress IP Address Number: "
         //    << mPeerAddress.toString().toStdString() << endl;
-#if defined (__LINUX__) || (__MAC_OSX__)
+#if defined(__LINUX__) || defined(__MAC_OSX__)
     }
 #endif
 
     // check if the ip address is valid
-    if ( mPeerAddress.protocol() == QAbstractSocket::IPv6Protocol ) {
+    if (mPeerAddress.protocol() == QAbstractSocket::IPv6Protocol) {
         mIPv6 = true;
-    } else  if ( mPeerAddress.protocol() != QAbstractSocket::IPv4Protocol ) {
+    } else if (mPeerAddress.protocol() != QAbstractSocket::IPv4Protocol) {
         QString error_message = "Incorrect presentation format address\n'";
         error_message.append(peerHostOrIP);
         error_message.append("' is not a valid IP address or Host Name");
-        //std::cerr << "ERROR: Incorrect presentation format address" << endl;
-        //std::cerr << "'" << peerHostOrIP <<"' does not seem to be a valid IP address" << endl;
-        //throw std::invalid_argument("Incorrect presentation format address");
-        throw std::invalid_argument( error_message.toStdString());
+        // std::cerr << "ERROR: Incorrect presentation format address" << endl;
+        // std::cerr << "'" << peerHostOrIP <<"' does not seem to be a valid IP address"
+        // << endl; throw std::invalid_argument("Incorrect presentation format address");
+        throw std::invalid_argument(error_message.toStdString());
     }
     /*
     else {
@@ -164,32 +172,33 @@ void UdpDataProtocol::setPeerAddress(const char* peerHostOrIP)
     }
 }
 
-#if defined (__WIN_32__)
-void UdpDataProtocol::setSocket(SOCKET &socket)
+#if defined(__WIN_32__)
+void UdpDataProtocol::setSocket(SOCKETsocket)
 #else
-void UdpDataProtocol::setSocket(int &socket)
+void UdpDataProtocol::setSocket(intsocket)
 #endif
 {
-    //If we haven't been passed a valid socket, then we should bind one.
-#if defined (__WIN_32__)
+    // If we haven't been passed a valid socket, then we should bind one.
+#if defined(__WIN_32__)
     if (socket == INVALID_SOCKET) {
 #else
     if (socket == -1) {
 #endif
         try {
-            if (gVerboseFlag) std::cout << "    UdpDataProtocol:run" << mRunMode << " before bindSocket" << std::endl;
-            socket = bindSocket(); // Bind Socket
-        } catch ( const std::exception & e ) {
-            emit signalError( e.what() );
+            if (gVerboseFlag)
+                std::cout << "    UdpDataProtocol:run" << mRunMode << " before bindSocket"
+                          << std::endl;
+            socket = bindSocket();  // Bind Socket
+        } catch (const std::exception& e) {
+            emit signalError(e.what());
             return;
         }
     }
     mSocket = socket;
 }
 
-
 //*******************************************************************************
-#if defined (__WIN_32__)
+#if defined(__WIN_32__)
 SOCKET UdpDataProtocol::bindSocket()
 #else
 int UdpDataProtocol::bindSocket()
@@ -202,10 +211,10 @@ int UdpDataProtocol::bindSocket()
     WSADATA wsaData;
     int err;
 
-    wVersionRequested = MAKEWORD( 2, 2 );
+    wVersionRequested = MAKEWORD(2, 2);
 
-    err = WSAStartup( wVersionRequested, &wsaData );
-    if ( err != 0 ) {
+    err = WSAStartup(wVersionRequested, &wsaData);
+    if (err != 0) {
         // Tell the user that we couldn't find a useable
         // winsock.dll.
 
@@ -214,22 +223,21 @@ int UdpDataProtocol::bindSocket()
 
     // Confirm that the Windows Sockets DLL supports 1.1. or higher
 
-    if ( LOBYTE( wsaData.wVersion ) != 2 ||
-         HIBYTE( wsaData.wVersion ) != 2 ) {
+    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
         // Tell the user that we couldn't find a useable
         // winsock.dll.
-        WSACleanup( );
+        WSACleanup();
         return INVALID_SOCKET;
     }
 
     SOCKET sock_fd;
 #endif
 
-#if defined ( __LINUX__ ) || (__MAC_OSX__)
+#if defined(__LINUX__) || defined(__MAC_OSX__)
     int sock_fd;
 #endif
 
-    //Set local IPv4 or IPv6 Address
+    // Set local IPv4 or IPv6 Address
     struct sockaddr_in local_addr;
     struct sockaddr_in6 local_addr6;
 
@@ -238,40 +246,43 @@ int UdpDataProtocol::bindSocket()
         sock_fd = socket(AF_INET6, SOCK_DGRAM, 0);
         std::memset(&local_addr6, 0, sizeof(local_addr6));
         local_addr6.sin6_family = AF_INET6;
-        local_addr6.sin6_addr = in6addr_any;
-        local_addr6.sin6_port = htons(mBindPort);
+        local_addr6.sin6_addr   = in6addr_any;
+        local_addr6.sin6_port   = htons(mBindPort);
     } else {
         sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
 
         //::bzero(&local_addr, sizeof(local_addr));
-        std::memset(&local_addr, 0, sizeof(local_addr)); // set buffer to 0
-        local_addr.sin_family = AF_INET; //AF_INET: IPv4 Protocol
-        local_addr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY: let the kernel decide the active address
-        local_addr.sin_port = htons(mBindPort); //set local port
+        std::memset(&local_addr, 0, sizeof(local_addr));  // set buffer to 0
+        local_addr.sin_family = AF_INET;                  // AF_INET: IPv4 Protocol
+        local_addr.sin_addr.s_addr =
+            htonl(INADDR_ANY);  // INADDR_ANY: let the kernel decide the active address
+        local_addr.sin_port = htons(mBindPort);  // set local port
     }
 
     // Set socket to be reusable, this is platform dependent
     int one = 1;
-#if defined ( __LINUX__ )
+#if defined(__LINUX__)
     ::setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
 #endif
-#if defined ( __MAC_OSX__ )
+#if defined(__MAC_OSX__)
     // This option is not avialable on Linux, and without it MAC OS X
     // has problems rebinding a socket
     ::setsockopt(sock_fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
 #endif
-#if defined (__WIN_32__)
-    //make address/port reusable
+#if defined(__WIN_32__)
+    // make address/port reusable
     setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one));
 #endif
 
     // Bind the Socket
     if (mIPv6) {
-        if ( (::bind(sock_fd, (struct sockaddr *) &local_addr6, sizeof(local_addr6))) < 0 )
-        { throw std::runtime_error("ERROR: UDP Socket Bind Error"); }
+        if ((::bind(sock_fd, (struct sockaddr*)&local_addr6, sizeof(local_addr6))) < 0) {
+            throw std::runtime_error("ERROR: UDP Socket Bind Error");
+        }
     } else {
-        if ( (::bind(sock_fd, (struct sockaddr *) &local_addr, sizeof(local_addr))) < 0 )
-        { throw std::runtime_error("ERROR: UDP Socket Bind Error"); }
+        if ((::bind(sock_fd, (struct sockaddr*)&local_addr, sizeof(local_addr))) < 0) {
+            throw std::runtime_error("ERROR: UDP Socket Bind Error");
+        }
     }
 
     // To be able to use the two UDP sockets bound to the same port number,
@@ -285,12 +296,14 @@ int UdpDataProtocol::bindSocket()
     }*/
     if (!mIPv6) {
         // Connect only if we're using IPv4.
-        // (Connecting presents an issue when a host has multiple IP addresses and the peer decides to send from
-        // a different address. While this generally won't be a problem for IPv4, it will for IPv6.)
-        if ( (::connect(sock_fd, (struct sockaddr *) &mPeerAddr, sizeof(mPeerAddr))) < 0)
-        { throw std::runtime_error("ERROR: Could not connect UDP socket"); }
-#if defined (__LINUX__) || (__MAC_OSX__)
-        //if ( (::shutdown(sock_fd,SHUT_WR)) < 0)
+        // (Connecting presents an issue when a host has multiple IP addresses and the
+        // peer decides to send from a different address. While this generally won't be a
+        // problem for IPv4, it will for IPv6.)
+        if ((::connect(sock_fd, (struct sockaddr*)&mPeerAddr, sizeof(mPeerAddr))) < 0) {
+            throw std::runtime_error("ERROR: Could not connect UDP socket");
+        }
+#if defined(__LINUX__) || defined(__MAC_OSX__)
+        // if ( (::shutdown(sock_fd,SHUT_WR)) < 0)
         //{ throw std::runtime_error("ERROR: Could shutdown SHUT_WR UDP socket"); }
 #endif
 #if defined __WIN_32__
@@ -328,50 +341,41 @@ int UdpDataProtocol::bindSocket()
     // ----------------------------------------------------------------------------
 }
 
-
 //*******************************************************************************
 int UdpDataProtocol::receivePacket(char* buf, const size_t n)
 {
-    // Block until There's something to read
-    while ( !datagramAvailable() && !mStopped ) {
-        QThread::usleep(100);
-    }
     int n_bytes = ::recv(mSocket, buf, n, 0);
     if (n_bytes == mControlPacketSize) {
-        //Control signal (currently just check for exit packet);
+        // Control signal (currently just check for exit packet);
         bool exit = true;
         for (int i = 0; i < mControlPacketSize; i++) {
             if (buf[i] != char(0xff)) {
                 exit = false;
-                i = mControlPacketSize;
+                i    = mControlPacketSize;
             }
         }
         if (exit && !mStopSignalSent) {
             mStopSignalSent = true;
             emit signalCeaseTransmission("Peer Stopped");
-            std::cout << "Peer Stopped" <<std::endl;
+            std::cout << "Peer Stopped" << std::endl;
         }
         return 0;
     }
     return n_bytes;
 }
 
-
 //*******************************************************************************
 int UdpDataProtocol::sendPacket(const char* buf, const size_t n)
 {
-/*#if defined (__WIN_32__)
-    //Alternative windows specific code that uses winsock equivalents of the bsd socket functions.
-    DWORD n_bytes;
-    WSABUF buffer;
-    int error;
-    buffer.len = n;
-    buffer.buf = (char *)buf;
+    /*#if defined (__WIN_32__)
+    //Alternative windows specific code that uses winsock equivalents of the bsd socket
+functions. DWORD n_bytes; WSABUF buffer; int error; buffer.len = n; buffer.buf = (char
+*)buf;
 
     if (mIPv6) {
-        error = WSASendTo(mSocket, &buffer, 1, &n_bytes, 0, (struct sockaddr *) &mPeerAddr6, sizeof(mPeerAddr6), 0, 0);
-    } else {
-        error = WSASend(mSocket, &buffer, 1, &n_bytes, 0, 0, 0);
+        error = WSASendTo(mSocket, &buffer, 1, &n_bytes, 0, (struct sockaddr *)
+&mPeerAddr6, sizeof(mPeerAddr6), 0, 0); } else { error = WSASend(mSocket, &buffer, 1,
+&n_bytes, 0, 0, 0);
     }
     if (error == SOCKET_ERROR) {
         cout << "Socket Error: " << WSAGetLastError() << endl;
@@ -380,59 +384,57 @@ int UdpDataProtocol::sendPacket(const char* buf, const size_t n)
 #else*/
     int n_bytes;
     if (mIPv6) {
-        n_bytes = ::sendto(mSocket, buf, n, 0, (struct sockaddr *) &mPeerAddr6, sizeof(mPeerAddr6));
+        n_bytes = ::sendto(mSocket, buf, n, 0, (struct sockaddr*)&mPeerAddr6,
+                           sizeof(mPeerAddr6));
     } else {
         n_bytes = ::send(mSocket, buf, n, 0);
     }
     return n_bytes;
-//#endif
+    //#endif
 }
 
-
 //*******************************************************************************
 void UdpDataProtocol::getPeerAddressFromFirstPacket(QHostAddress& peerHostAddress,
                                                     uint16_t& port)
 {
-    while ( !datagramAvailable() ) {
-        msleep(100);
-    }
+    while (!datagramAvailable()) { msleep(100); }
     char buf[1];
-    
+
     struct sockaddr_storage addr;
     std::memset(&addr, 0, sizeof(addr));
     socklen_t sa_len = sizeof(addr);
-    ::recvfrom(mSocket, buf, 1, 0, (struct sockaddr*) &addr, &sa_len);
-    peerHostAddress.setAddress((struct sockaddr*) &addr);
+    ::recvfrom(mSocket, buf, 1, 0, (struct sockaddr*)&addr, &sa_len);
+    peerHostAddress.setAddress((struct sockaddr*)&addr);
     if (mIPv6) {
-        port = ((struct sockaddr_in6*) &addr)->sin6_port;
+        port = ((struct sockaddr_in6*)&addr)->sin6_port;
     } else {
-        port = ((struct sockaddr_in*) &addr)->sin_port;
+        port = ((struct sockaddr_in*)&addr)->sin_port;
     }
 }
 
-
 //*******************************************************************************
 void UdpDataProtocol::run()
 {
-    if (gVerboseFlag) switch ( mRunMode )
-    {
-    case RECEIVER : {
-        std::cout << "step 3" << std::endl;
-        break; }
+    if (gVerboseFlag) switch (mRunMode) {
+        case RECEIVER: {
+            std::cout << "step 3" << std::endl;
+            break;
+        }
 
-    case SENDER : {
-        std::cout << "step 4" << std::endl;
-        break; }
-    }
+        case SENDER: {
+            std::cout << "step 4" << std::endl;
+            break;
+        }
+        }
 
-    //QObject::connect(this, SIGNAL(signalError(const char*)),
+    // QObject::connect(this, SIGNAL(signalError(const char*)),
     //                 mJackTrip, SLOT(slotStopProcesses()),
     //                 Qt::QueuedConnection);
 
     if (mRunMode == RECEIVER) {
         cout << "UDP Socket Receiving in Port: " << mBindPort << endl;
         cout << gPrintSeparator << endl;
-        //Make sure our socket is in non-blocking mode.
+        // Make sure our socket is in non-blocking mode.
 #ifdef __WIN_32__
         u_long nonblock = 1;
         ioctlsocket(mSocket, FIONBIO, &nonblock);
@@ -442,41 +444,63 @@ void UdpDataProtocol::run()
 #endif
     }
 
-    if (gVerboseFlag) std::cout << "    UdpDataProtocol:run" << mRunMode << " before Setup Audio Packet buffer, Full Packet buffer, Redundancy Variables" << std::endl;
+    if (gVerboseFlag)
+        std::cout << "    UdpDataProtocol:run" << mRunMode
+                  << " before Setup Audio Packet buffer, Full Packet buffer, Redundancy "
+                     "Variables"
+                  << std::endl;
+
     // Setup Audio Packet buffer
     size_t audio_packet_size = getAudioPacketSizeInBites();
-    //cout << "audio_packet_size: " << audio_packet_size << endl;
+    // cout << "audio_packet_size: " << audio_packet_size << endl;
     mAudioPacket = new int8_t[audio_packet_size];
-    std::memset(mAudioPacket, 0, audio_packet_size); // set buffer to 0
+    std::memset(mAudioPacket, 0, audio_packet_size);  // set buffer to 0
     mBuffer.resize(audio_packet_size, 0);
-    mChans = mJackTrip->getNumChannels();
-    mSmplSize = mJackTrip->getAudioBitResolution() / 8;
 
-    // Setup Full Packet buffer
-    int full_packet_size = mJackTrip->getPacketSizeInBytes();
-    //cout << "full_packet_size: " << full_packet_size << endl;
-    mFullPacket = new int8_t[full_packet_size];
-    std::memset(mFullPacket, 0, full_packet_size); // set buffer to 0
+    int full_packet_size;
+    mSmplSize = mJackTrip->getAudioBitResolution() / 8;
 
-    //  bool timeout = false; // Time out flag for packets that arrive too late
+    if (mRunMode == RECEIVER) {
+        mChans = mJackTrip->getNumOutputChannels();
+        if (0 == mChans) return;
+        full_packet_size = mJackTrip->getReceivePacketSizeInBytes();
+        mFullPacket      = new int8_t[full_packet_size];
+        std::memset(mFullPacket, 0, full_packet_size);  // set buffer to 0
+        // Put header in first packet
+        mJackTrip->putHeaderInIncomingPacket(mFullPacket, mAudioPacket);
 
-    // Put header in first packet
-    mJackTrip->putHeaderInPacket(mFullPacket, mAudioPacket);
+    } else {
+        mChans = mJackTrip->getNumInputChannels();
+        if (0 == mChans) return;
+        full_packet_size = mJackTrip->getSendPacketSizeInBytes();
+        mFullPacket      = new int8_t[full_packet_size];
+        std::memset(mFullPacket, 0, full_packet_size);  // set buffer to 0
+        // Put header in first packet
+        mJackTrip->putHeaderInOutgoingPacket(mFullPacket, mAudioPacket);
+    }
 
     // Redundancy Variables
     // (Algorithm explained at the end of this file)
     // ---------------------------------------------
     int full_redundant_packet_size = full_packet_size * mUdpRedundancyFactor;
-    int8_t* full_redundant_packet = NULL;
+    int8_t* full_redundant_packet  = NULL;
 
     // Set realtime priority (function in jacktrip_globals.h)
-    if (gVerboseFlag) std::cout << "    UdpDataProtocol:run" << mRunMode << " before setRealtimeProcessPriority()" << std::endl;
-    //std::cout << "Experimental version -- not using setRealtimeProcessPriority()" << std::endl;
+    if (gVerboseFlag)
+        std::cout << "    UdpDataProtocol:run" << mRunMode
+                  << " before setRealtimeProcessPriority()" << std::endl;
+    // std::endl;
     // Anton Runov: making setRealtimeProcessPriority optional
     if (mUseRtPriority) {
+#if defined(__MAC_OSX__)
+        setRealtimeProcessPriority(mJackTrip->getBufferSizeInSamples(),
+                                   mJackTrip->getSampleRate());
+#else
         setRealtimeProcessPriority();
+#endif
     }
 
+    // clang-format off
     /////////////////////
     // to see thread priorities
     // sudo ps -eLo pri,rtprio,cls,pid,nice,cmd | grep -E 'jackd|jacktrip|rtc|RTPRI' | sort -r
@@ -536,35 +560,48 @@ void UdpDataProtocol::run()
     //         19      -  TS  4348   0 /usr/bin/jackd -dalsa -dhw:CODEC -r48000 -p128 -n2 -Xseq
 
     // jack puts its clients in FF at 5 points below itself
+    //
+    // clang-format off
 
-    switch ( mRunMode )
-    {
-    case RECEIVER : {
+    switch (mRunMode) {
+    case RECEIVER: {
         // Connect signals and slots for packets arriving too late notifications
-        QObject::connect(this, SIGNAL(signalWaitingTooLong(int)),
-                         this, SLOT(printUdpWaitedTooLong(int)),
-                         Qt::QueuedConnection);
+        QObject::connect(this, SIGNAL(signalWaitingTooLong(int)), this,
+                         SLOT(printUdpWaitedTooLong(int)), Qt::QueuedConnection);
         //-----------------------------------------------------------------------------------
         // Wait for the first packet to be ready and obtain address
         // from that packet
-        if (gVerboseFlag) std::cout << "    UdpDataProtocol:run" << mRunMode << " before !UdpSocket.hasPendingDatagrams()" << std::endl;
+        if (gVerboseFlag)
+            std::cout << "    UdpDataProtocol:run" << mRunMode
+                      << " before !UdpSocket.hasPendingDatagrams()" << std::endl;
         std::cout << "Waiting for Peer..." << std::endl;
         // This blocks waiting for the first packet
-        while ( !datagramAvailable() ) {
+        while (!datagramAvailable()) {
             if (mStopped) { return; }
             QThread::msleep(100);
             if (gVerboseFlag) std::cout << "100ms  " << std::flush;
         }
         full_redundant_packet_size = 0x10000;  // max UDP datagram size
-        full_redundant_packet = new int8_t[full_redundant_packet_size];
-        full_redundant_packet_size = receivePacket(reinterpret_cast<char*>(full_redundant_packet), full_redundant_packet_size);
+        full_redundant_packet      = new int8_t[full_redundant_packet_size];
+        full_redundant_packet_size = receivePacket(
+            reinterpret_cast<char*>(full_redundant_packet), full_redundant_packet_size);
         // Check that peer has the same audio settings
-        if (gVerboseFlag) std::cout << std::endl << "    UdpDataProtocol:run" << mRunMode << " before mJackTrip->checkPeerSettings()" << std::endl;
-        mJackTrip->checkPeerSettings(full_redundant_packet);
+        if (gVerboseFlag)
+            std::cout << std::endl
+                      << "    UdpDataProtocol:run" << mRunMode
+                      << " before mJackTrip->checkPeerSettings()" << std::endl;
+        if (!mJackTrip->checkPeerSettings(full_redundant_packet)) {
+            // If our peer settings aren't compatible, don't continue.
+            // (The checkPeerSettings function needs to signal the JackTrip instance with the exact error message.)
+            delete[] full_redundant_packet;
+            full_redundant_packet = nullptr;
+            return;
+        }
 
-        int peer_chans = mJackTrip->getPeerNumChannels(full_redundant_packet);
+        int peer_chans   = mJackTrip->getPeerNumOutgoingChannels(full_redundant_packet);
         full_packet_size = mJackTrip->getHeaderSizeInBytes()
-                           + mJackTrip->getPeerBufferSize(full_redundant_packet) * peer_chans * mSmplSize;
+                           + mJackTrip->getPeerBufferSize(full_redundant_packet)
+                                 * peer_chans * mSmplSize;
         /*
         cout << "peer sizes: " << mJackTrip->getHeaderSizeInBytes()
              << " + " << mJackTrip->getPeerBufferSize(full_redundant_packet)
@@ -574,7 +611,9 @@ void UdpDataProtocol::run()
         // */
 
         if (gVerboseFlag) std::cout << "step 7" << std::endl;
-        if (gVerboseFlag) std::cout << "    UdpDataProtocol:run" << mRunMode << " before mJackTrip->parseAudioPacket()" << std::endl;
+        if (gVerboseFlag)
+            std::cout << "    UdpDataProtocol:run" << mRunMode
+                      << " before mJackTrip->parseAudioPacket()" << std::endl;
         std::cout << "Received Connection from Peer!" << std::endl;
         emit signalReceivedConnectionFromPeer();
 
@@ -582,28 +621,53 @@ void UdpDataProtocol::run()
         // --------------------
         // NOTE: These types need to be the same unsigned integer as the sequence
         // number in the header. That way, they wrap around in the "same place"
-        uint16_t current_seq_num = 0; // Store current sequence number
-        uint16_t last_seq_num = 0;    // Store last package sequence number
-        uint16_t newer_seq_num = 0;   // Store newer sequence number
-        mTotCount = 0;
-        mLostCount = 0;
-        mOutOfOrderCount = 0;
-        mLastOutOfOrderCount = 0;
-        mInitialState = true;
-        mRevivedCount = 0;
-        mStatCount = 0;
+        uint16_t current_seq_num = 0;  // Store current sequence number
+        uint16_t last_seq_num    = 0;  // Store last package sequence number
+        uint16_t newer_seq_num   = 0;  // Store newer sequence number
+        mTotCount                = 0;
+        mLostCount               = 0;
+        mOutOfOrderCount         = 0;
+        mLastOutOfOrderCount     = 0;
+        mInitialState            = true;
+        mRevivedCount            = 0;
+        mStatCount               = 0;
+
+        //Set up our platform specific polling mechanism. (kqueue, epoll)
+#if !defined (__MANUAL_POLL__) && !defined (__WIN_32__)
+#if defined (__MAC_OSX__)
+        int kq = kqueue();
+        struct kevent change;
+        struct kevent event;
+        EV_SET(&change, mSocket, EVFILT_READ, EV_ADD, 0, 0, NULL);
+        struct timespec timeout;
+        timeout.tv_sec = 0;
+        timeout.tv_nsec = 10000000;
+#else
+        int epollfd = epoll_create1(0);
+        struct epoll_event change, event;
+        change.events = EPOLLIN;
+        change.data.fd = mSocket;
+        epoll_ctl(epollfd, EPOLL_CTL_ADD, mSocket, &change);
+#endif
+        int waitTime = 0;
+#endif // __MANUAL_POLL__
 
         if (gVerboseFlag) std::cout << "step 8" << std::endl;
-        while ( !mStopped )
-        {
+        while (!mStopped) {
             // Timer to report packets arriving too late
             // This QT method gave me a lot of trouble, so I replaced it with my own 'waitForReady'
             // that uses signals and slots and can also report with packets have not
             // arrive for a longer time
             //timeout = UdpSocket.waitForReadyRead(30);
             //        timeout = cc unused!
+#if defined (__WIN_32__) || defined (__MANUAL_POLL__)
             waitForReady(60000); //60 seconds
-
+            receivePacketRedundancy(full_redundant_packet, full_redundant_packet_size,
+                                    full_packet_size, current_seq_num, last_seq_num,
+                                    newer_seq_num);
+       }
+#else
+            
             // OLD CODE WITHOUT REDUNDANCY----------------------------------------------------
             /*
         // This is blocking until we get a packet...
@@ -617,35 +681,40 @@ void UdpDataProtocol::run()
         mJackTrip->writeAudioBuffer(mAudioPacket);
         */
             //----------------------------------------------------------------------------------
-            receivePacketRedundancy(full_redundant_packet,
-                                    full_redundant_packet_size,
-                                    full_packet_size,
-                                    current_seq_num,
-                                    last_seq_num,
-                                    newer_seq_num);
+
+#ifdef __MAC_OSX__
+            int n = kevent(kq, &change, 1, &event, 1, &timeout);
+#else
+            int n = epoll_wait(epollfd, &event, 1, 10);
+#endif
+            if (n > 0) {
+                waitTime = 0;
+                receivePacketRedundancy(full_redundant_packet, full_redundant_packet_size,
+                                        full_packet_size, current_seq_num, last_seq_num,
+                                        newer_seq_num);
+            } else {
+                waitTime += 10;
+                emit signalWaitingTooLong(waitTime);
+            }
         }
+#ifdef __MAC_OSX__
+        close(kq);
+#else
+        close(epollfd);
+#endif
+#endif // __WIN_32__ || __MANUAL_POLL__
         break; }
 
     case SENDER : {
+        delete[] full_redundant_packet;
         full_redundant_packet = new int8_t[full_redundant_packet_size];
-        std::memset(full_redundant_packet, 0, full_redundant_packet_size); // Initialize to 0
-        while ( !mStopped && !JackTrip::sSigInt && !JackTrip::sJackStopped )
-        {
-            // OLD CODE WITHOUT REDUNDANCY -----------------------------------------------------
-            /*
-        // We block until there's stuff available to read
-        mJackTrip->readAudioBuffer( mAudioPacket );
-        mJackTrip->putHeaderInPacket(mFullPacket, mAudioPacket);
-        // This will send the packet immediately
-        //int bytes_sent = sendPacket( reinterpret_cast<char*>(mFullPacket), full_packet_size);
-        sendPacket( UdpSocket, PeerAddress, reinterpret_cast<char*>(mFullPacket), full_packet_size);
-        */
-            //----------------------------------------------------------------------------------
-            sendPacketRedundancy(full_redundant_packet,
-                                 full_redundant_packet_size,
+        std::memset(full_redundant_packet, 0,
+                    full_redundant_packet_size); // Initialize to 0
+        while (!mStopped && !JackTrip::sSigInt && !JackTrip::sJackStopped) {
+            sendPacketRedundancy(full_redundant_packet, full_redundant_packet_size,
                                  full_packet_size);
         }
-        
+
         // Send exit packet (with 1 redundant packet).
         cout << "sending exit packet" << endl;
         QByteArray exitPacket = QByteArray(mControlPacketSize, 0xff);
@@ -661,25 +730,22 @@ void UdpDataProtocol::run()
     }
 }
 
-
 //*******************************************************************************
 //bool
 void UdpDataProtocol::waitForReady(int timeout_msec)
 {
-    int loop_resolution_usec = 100; // usecs to wait on each loop
-    int emit_resolution_usec = 10000; // 10 milliseconds
-    int timeout_usec = timeout_msec * 1000;
-    int elapsed_time_usec = 0; // Ellapsed time in milliseconds
-
-    while ( !datagramAvailable()
-            && (elapsed_time_usec <= timeout_usec)
-            && !mStopped ){
+    int loop_resolution_usec = 100;    // usecs to wait on each loop
+    int emit_resolution_usec = 10000;  // 10 milliseconds
+    int timeout_usec         = timeout_msec * 1000;
+    int elapsed_time_usec    = 0;  // Ellapsed time in milliseconds
+
+    while (!datagramAvailable() && (elapsed_time_usec <= timeout_usec) && !mStopped) {
         //    if (mStopped) { return false; }
         QThread::usleep(loop_resolution_usec);
         elapsed_time_usec += loop_resolution_usec;
 
-        if ( !(elapsed_time_usec % emit_resolution_usec) ) {
-            emit signalWaitingTooLong(static_cast<int>(elapsed_time_usec/1000));
+        if (!(elapsed_time_usec % emit_resolution_usec)) {
+            emit signalWaitingTooLong(static_cast<int>(elapsed_time_usec / 1000));
         }
     }
     // cc under what condition?
@@ -691,29 +757,26 @@ void UdpDataProtocol::waitForReady(int timeout_msec)
     //  return true;
 }
 
-
 //*******************************************************************************
 void UdpDataProtocol::printUdpWaitedTooLong(int wait_msec)
 {
-    int wait_time = 30; // msec
-    if ( !(wait_msec%wait_time) ) {
-        std::cerr << "UDP waiting too long (more than " << wait_time << "ms) for " << mPeerAddress.toString().toStdString() << "..." << endl;
+    int wait_time = 30;  // msec
+    if (!(wait_msec % wait_time)) {
+        std::cerr << "UDP waiting too long (more than " << wait_time << "ms) for "
+                  << mPeerAddress.toString().toStdString() << "..." << endl;
         emit signalUdpWaitingTooLong();
     }
 }
 
-
 //*******************************************************************************
-void UdpDataProtocol::receivePacketRedundancy(int8_t* full_redundant_packet,
-                                              int full_redundant_packet_size,
-                                              int full_packet_size,
-                                              uint16_t& current_seq_num,
-                                              uint16_t& last_seq_num,
-                                              uint16_t& newer_seq_num)
+void UdpDataProtocol::receivePacketRedundancy(
+    int8_t* full_redundant_packet, int full_redundant_packet_size, int full_packet_size,
+    uint16_t& current_seq_num, uint16_t& last_seq_num, uint16_t& newer_seq_num)
 {
     // This is blocking until we get a packet...
-    if (receivePacket( reinterpret_cast<char*>(full_redundant_packet), 
-                       full_redundant_packet_size) == 0) {
+    if (receivePacket(reinterpret_cast<char*>(full_redundant_packet),
+                      full_redundant_packet_size)
+        <= 0) {
         return;
     }
 
@@ -721,19 +784,14 @@ void UdpDataProtocol::receivePacketRedundancy(int8_t* full_redundant_packet,
         double x = mUniformDist(mRndEngine);
         // Drop packets
         x -= mSimulatedLossRate;
-        if (0 > x) {
-            return;
-        }
+        if (0 > x) { return; }
         // Delay packets
         x -= mSimulatedJitterRate;
-        if (0 > x) {
-            usleep(mUniformDist(mRndEngine) * mSimulatedJitterMaxDelay * 1e6);
-        }
+        if (0 > x) { usleep(mUniformDist(mRndEngine) * mSimulatedJitterMaxDelay * 1e6); }
     }
 
     // Get Packet Sequence Number
-    newer_seq_num =
-            mJackTrip->getPeerSequenceNumber(full_redundant_packet);
+    newer_seq_num   = mJackTrip->getPeerSequenceNumber(full_redundant_packet);
     current_seq_num = newer_seq_num;
 
     int16_t lost = 0;
@@ -744,57 +802,55 @@ void UdpDataProtocol::receivePacketRedundancy(int8_t* full_redundant_packet,
             ++mOutOfOrderCount;
             if (5 < ++mLastOutOfOrderCount) {
                 mInitialState = true;
-                mStatCount = 0;
-                mTotCount = 0;
+                mStatCount    = 0;
+                mTotCount     = 0;
             }
             return;
-        }
-        else if (0 != lost) {
+        } else if (0 != lost) {
             mLostCount += lost;
         }
         mTotCount += 1 + lost;
     }
     mLastOutOfOrderCount = 0;
-    mInitialState = false;
+    mInitialState        = false;
 
     //cout << current_seq_num << " ";
     int redun_last_index = 0;
-    for (unsigned int i = 1; i<mUdpRedundancyFactor; i++) {
+    for (unsigned int i = 1; i < mUdpRedundancyFactor; i++) {
         // Check if the package we receive is the next one expected, i.e.,
         // current_seq_num == (last_seq_num+1)
-        if ( current_seq_num == (last_seq_num+1) ) { break; }
+        if (current_seq_num == (last_seq_num + 1)) { break; }
 
         // if it's not, check the next one until it is the corresponding packet
         // or there aren't more available packets
-        redun_last_index = i; // index of packet to use in the redundant packet
-        current_seq_num =
-                mJackTrip->getPeerSequenceNumber( full_redundant_packet + (i*full_packet_size) );
+        redun_last_index = i;  // index of packet to use in the redundant packet
+        current_seq_num  = mJackTrip->getPeerSequenceNumber(full_redundant_packet
+                                                           + (i * full_packet_size));
         //cout << current_seq_num << " ";
     }
     mRevivedCount += redun_last_index;
     //cout << endl;
 
-    int peer_chans = mJackTrip->getPeerNumChannels(full_redundant_packet);
-    int N = mJackTrip->getPeerBufferSize(full_redundant_packet);
+    int peer_chans    = mJackTrip->getPeerNumOutgoingChannels(full_redundant_packet);
+    int N             = mJackTrip->getPeerBufferSize(full_redundant_packet);
     int host_buf_size = N * mChans * mSmplSize;
-    int hdr_size = mJackTrip->getHeaderSizeInBytes();
-    int gap_size = mInitialState ? 0 : (lost - redun_last_index) * host_buf_size;
+    int hdr_size      = mJackTrip->getHeaderSizeInBytes();
+    int gap_size      = mInitialState ? 0 : (lost - redun_last_index) * host_buf_size;
 
-    last_seq_num = newer_seq_num; // Save last read packet
+    last_seq_num = newer_seq_num;  // Save last read packet
 
-    if ((int)mBuffer.size() < host_buf_size) {
-        mBuffer.resize(host_buf_size, 0);
-    }
+    if ((int)mBuffer.size() < host_buf_size) { mBuffer.resize(host_buf_size, 0); }
     // Send to audio all available audio packets, in order
-    for (int i = redun_last_index; i>=0; i--) {
-        int8_t* src = full_redundant_packet + (i*full_packet_size) + hdr_size;
+    for (int i = redun_last_index; i >= 0; i--) {
+        int8_t* src = full_redundant_packet + (i * full_packet_size) + hdr_size;
         if (1 != mChans) {
             // Convert packet's non-interleaved layout to interleaved one used internally
             int8_t* dst = mBuffer.data();
-            int C = qMin(mChans, peer_chans);
-            for (int n=0; n<N; ++n) {
-                for (int c=0; c<C; ++c) {
-                    memcpy(dst + (n*mChans + c)*mSmplSize, src + (n + c*N)*mSmplSize, mSmplSize);
+            int C       = qMin(mChans, peer_chans);
+            for (int n = 0; n < N; ++n) {
+                for (int c = 0; c < C; ++c) {
+                    memcpy(dst + (n * mChans + c) * mSmplSize,
+                           src + (n + c * N) * mSmplSize, mSmplSize);
                 }
             }
             src = dst;
@@ -813,31 +869,33 @@ void UdpDataProtocol::receivePacketRedundancy(int8_t* full_redundant_packet,
 bool UdpDataProtocol::getStats(DataProtocol::PktStat* stat)
 {
     if (0 == mStatCount) {
-        mLostCount = 0;
+        mLostCount       = 0;
         mOutOfOrderCount = 0;
-        mRevivedCount = 0;
+        mRevivedCount    = 0;
     }
-    stat->tot = mTotCount;
-    stat->lost = mLostCount;
+    stat->tot        = mTotCount;
+    stat->lost       = mLostCount;
     stat->outOfOrder = mOutOfOrderCount;
-    stat->revived = mRevivedCount;
-    stat->statCount = mStatCount++;
+    stat->revived    = mRevivedCount;
+    stat->statCount  = mStatCount++;
     return true;
 }
 
 //*******************************************************************************
 void UdpDataProtocol::setIssueSimulation(double loss, double jitter, double max_delay)
 {
-    mSimulatedLossRate = loss;
-    mSimulatedJitterRate = jitter;
+    mSimulatedLossRate       = loss;
+    mSimulatedJitterRate     = jitter;
     mSimulatedJitterMaxDelay = max_delay;
 
     std::random_device r;
-    mRndEngine = std::default_random_engine(r());
+    mRndEngine   = std::default_random_engine(r());
     mUniformDist = std::uniform_real_distribution<double>(0.0, 1.0);
 
     cout << "Simulating network issues: "
-      "loss_rate=" << loss << ", jitter_rate=" << jitter << ", jitter_max_delay=" << max_delay << endl;
+            "loss_rate="
+         << loss << ", jitter_rate=" << jitter << ", jitter_max_delay=" << max_delay
+         << endl;
 }
 
 //*******************************************************************************
@@ -845,28 +903,27 @@ void UdpDataProtocol::sendPacketRedundancy(int8_t* full_redundant_packet,
                                            int full_redundant_packet_size,
                                            int full_packet_size)
 {
-    mJackTrip->readAudioBuffer( mAudioPacket );
+    mJackTrip->readAudioBuffer(mAudioPacket);
     int8_t* src = mAudioPacket;
-    if (1 != mChans) {
+    if (1 < mChans) {
         // Convert internal interleaved layout to non-interleaved
-        int N = getAudioPacketSizeInBites() / mChans / mSmplSize;
+        int N       = getAudioPacketSizeInBites() / mChans / mSmplSize;
         int8_t* dst = mBuffer.data();
-        for (int n=0; n<N; ++n) {
-            for (int c=0; c<mChans; ++c) {
-                memcpy(dst + (n + c*N)*mSmplSize, src + (n*mChans + c)*mSmplSize, mSmplSize);
+        for (int n = 0; n < N; ++n) {
+            for (int c = 0; c < mChans; ++c) {
+                memcpy(dst + (n + c * N) * mSmplSize, src + (n * mChans + c) * mSmplSize,
+                       mSmplSize);
             }
         }
         src = dst;
     }
-    mJackTrip->putHeaderInPacket(mFullPacket, src);
+    mJackTrip->putHeaderInOutgoingPacket(mFullPacket, src);
 
     // Move older packets to end of array of redundant packets
-    std::memmove(full_redundant_packet+full_packet_size,
-                 full_redundant_packet,
-                 full_packet_size*(mUdpRedundancyFactor-1));
+    std::memmove(full_redundant_packet + full_packet_size, full_redundant_packet,
+                 full_packet_size * (mUdpRedundancyFactor - 1));
     // Copy new packet to the begining of array
-    std::memcpy(full_redundant_packet,
-                mFullPacket, full_packet_size);
+    std::memcpy(full_redundant_packet, mFullPacket, full_packet_size);
 
     // 10% (or other number) packet lost simulation.
     // Uncomment the if to activate
@@ -874,15 +931,14 @@ void UdpDataProtocol::sendPacketRedundancy(int8_t* full_redundant_packet,
     //int random_integer = rand();
     //if ( random_integer > (RAND_MAX/10) )
     //{
-    sendPacket( reinterpret_cast<char*>(full_redundant_packet),
-                full_redundant_packet_size);
+    sendPacket(reinterpret_cast<char*>(full_redundant_packet),
+               full_redundant_packet_size);
     //}
     //---------------------------------------------------------------------------------
 
     mJackTrip->increaseSequenceNumber();
 }
 
-
 /*
   The Redundancy Algorythmn works as follows. We send a packet that contains
   a mUdpRedundancyFactor number of packets (header+audio). This big packet looks
@@ -927,14 +983,14 @@ bool UdpDataProtocol::datagramAvailable()
     //Currently using a simplified version of the way QUdpSocket checks for datagrams.
     //TODO: Consider changing to use poll() or select().
     char c;
-#if defined (__WIN_32__)
+#if defined(__WIN_32__)
     //Need to use the winsock version of the function for MSG_PEEK
     WSABUF buffer;
-    buffer.buf = &c;
-    buffer.len = sizeof(c);
-    DWORD n = 0;
+    buffer.buf  = &c;
+    buffer.len  = sizeof(c);
+    DWORD n     = 0;
     DWORD flags = MSG_PEEK;
-    int ret = WSARecv(mSocket, &buffer, 1, &n, &flags, NULL, NULL);
+    int ret     = WSARecv(mSocket, &buffer, 1, &n, &flags, NULL, NULL);
     if (ret == 0) {
         //True if no error,
         return true;
index f6f570c28c84335ee35ef4e59b6cfb6d20df5de6..3ba36fbda482b744289d20b9916a7daeb54c8deb 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
 #ifndef __UDPDATAPROTOCOL_H__
 #define __UDPDATAPROTOCOL_H__
 
-#include <stdexcept>
-
-#include <QThread>
 #include <QHostAddress>
 #include <QMutex>
-#include <vector>
+#include <QThread>
+#include <atomic>
 #include <random>
+#include <stdexcept>
+#include <vector>
 
 #include "DataProtocol.h"
-#include "jacktrip_types.h"
 #include "jacktrip_globals.h"
+#include "jacktrip_types.h"
 
 /** \brief UDP implementation of DataProtocol class
  *
  * The class has a <tt>bind port</tt> and a <tt>peer port</tt>. The meaning of these
  * depends on the runModeT. If it's a SENDER, <tt>bind port</tt> is the source port and
  * <tt>peer port</tt> is the destination port for each UDP packet. If it's a RECEIVER,
- * the <tt>bind port</tt> destination port (for incoming packets) and the <tt>peer port</tt>
- * is the source port.
+ * the <tt>bind port</tt> destination port (for incoming packets) and the <tt>peer
+ * port</tt> is the source port.
  *
  * The SENDER and RECEIVER socket can share the same port/address pair (for compatibility
  * with the JamLink boxes). This is achieved setting
@@ -68,164 +68,164 @@ class UdpDataProtocol : public DataProtocol
 {
     Q_OBJECT;
 
-public:
-
+   public:
     /** \brief The class constructor
-   * \param jacktrip Pointer to the JackTrip class that connects all classes (mediator)
-   * \param runmode Sets the run mode, use either SENDER or RECEIVER
-   * \param bind_port Port number to bind for this socket (this is the receive or send port depending on the runmode)
-   * \param peer_port Peer port number (this is the receive or send port depending on the runmode)
-   * \param udp_redundancy_factor Number of redundant packets
-   */
-    UdpDataProtocol(JackTrip* jacktrip, const runModeT runmode,
-                    int bind_port, int peer_port,
-                    unsigned int udp_redundancy_factor = 1);
+     * \param jacktrip Pointer to the JackTrip class that connects all classes (mediator)
+     * \param runmode Sets the run mode, use either SENDER or RECEIVER
+     * \param bind_port Port number to bind for this socket (this is the receive or send
+     * port depending on the runmode)
+     * \param peer_port Peer port number (this is the receive or send port depending on
+     * the runmode)
+     * \param udp_redundancy_factor Number of redundant packets
+     */
+    UdpDataProtocol(JackTrip* jacktrip, const runModeT runmode, int bind_port,
+                    int peer_port, unsigned int udp_redundancy_factor = 1);
 
     /** \brief The class destructor
-   */
+     */
     virtual ~UdpDataProtocol();
 
     /** \brief Set the Peer address to connect to
-   * \param peerHostOrIP IPv4 number or host name
-   */
+     * \param peerHostOrIP IPv4 number or host name
+     */
     void setPeerAddress(const char* peerHostOrIP);
 
-#if defined (__WIN_32__)
-    void setSocket(SOCKET &socket);
+#if defined(__WIN_32__)
+    void setSocket(SOCKETsocket);
 #else
-    void setSocket(int &socket);
+    void setSocket(intsocket);
 #endif
 
     /** \brief Receives a packet. It blocks until a packet is received
-   *
-   * This function makes sure we recieve a complete packet
-   * of size n
-   * \param buf Buffer to store the recieved packet
-   * \param n size of packet to receive
-   * \return number of bytes read, -1 on error
-   */
-    //virtual int receivePacket(char* buf, const size_t n);
+     *
+     * This function makes sure we recieve a complete packet
+     * of size n
+     * \param buf Buffer to store the recieved packet
+     * \param n size of packet to receive
+     * \return number of bytes read, -1 on error
+     */
+    // virtual int receivePacket(char* buf, const size_t n);
     virtual int receivePacket(char* buf, const size_t n);
 
     /** \brief Sends a packet
-   *
-   * This function meakes sure we send a complete packet
-   * of size n
-   * \param buf Buffer to send
-   * \param n size of packet to receive
-   * \return number of bytes read, -1 on error
-   */
+     *
+     * This function meakes sure we send a complete packet
+     * of size n
+     * \param buf Buffer to send
+     * \param n size of packet to receive
+     * \return number of bytes read, -1 on error
+     */
     virtual int sendPacket(const char* buf, const size_t n);
 
     /** \brief Obtains the peer address from the first UDP packet received. This address
-   * is used by the SERVER mode to connect back to the client.
-   * \param peerHostAddress QHostAddress to store the peer address
-   * \param port Receiving port
-   */
+     * is used by the SERVER mode to connect back to the client.
+     * \param peerHostAddress QHostAddress to store the peer address
+     * \param port Receiving port
+     */
     virtual void getPeerAddressFromFirstPacket(QHostAddress& peerHostAddress,
                                                uint16_t& port);
 
     /** \brief Sets the bind port number
-    */
-    void setBindPort(int port)
-    { mBindPort = port; }
+     */
+    void setBindPort(int port) { mBindPort = port; }
 
     /** \brief Sets the peer port number
-    */
+     */
     void setPeerPort(int port)
-    { mPeerPort = port; mPeerAddr.sin_port = htons(mPeerPort); mPeerAddr6.sin6_port = htons(mPeerPort); }
+    {
+        mPeerPort            = port;
+        mPeerAddr.sin_port   = htons(mPeerPort);
+        mPeerAddr6.sin6_port = htons(mPeerPort);
+    }
 
     /** \brief Implements the Thread Loop. To start the thread, call start()
-   * ( DO NOT CALL run() )
-   *
-   * This function creats and binds all the socket and start the connection loop thread.
-   */
+     * ( DO NOT CALL run() )
+     *
+     * This function creats and binds all the socket and start the connection loop thread.
+     */
     virtual void run();
 
     virtual bool getStats(PktStat* stat);
     virtual void setIssueSimulation(double loss, double jitter, double max_delay);
 
-private slots:
+   private slots:
     void printUdpWaitedTooLong(int wait_msec);
-    
 
-signals:
+   signals:
 
-    /// \brief Signals when waiting every 10 milliseconds, with the total wait on wait_msec
+    /// \brief Signals when waiting every 10 milliseconds, with the total wait on
+    /// wait_msec
     /// \param wait_msec Total wait in milliseconds
     void signalWaitingTooLong(int wait_msec);
     void signalUdpWaitingTooLong();
 
-    //private:
-protected:
-
+    // private:
+   protected:
     /** \brief Binds the UDP socket to the available address and specified port
-   */
-#if defined (__WIN_32__)
+     */
+#if defined(__WIN_32__)
     SOCKET bindSocket();
 #else
     int bindSocket();
 #endif
 
     /** \brief This function blocks until data is available for reading in the
-   * socket. The function will timeout after timeout_msec microseconds.
-   *
-   * This function is intended to replace QAbstractSocket::waitForReadyRead which has
-   * some problems with multithreading.
-   *
-   * \return returns true if there is data available for reading;
-   * otherwise it returns false (if an error occurred or the operation timed out)
-   */
+     * socket. The function will timeout after timeout_msec microseconds.
+     *
+     * This function is intended to replace QAbstractSocket::waitForReadyRead which has
+     * some problems with multithreading.
+     *
+     * \return returns true if there is data available for reading;
+     * otherwise it returns false (if an error occurred or the operation timed out)
+     */
     void waitForReady(int timeout_msec);
 
     /** \brief Redundancy algorythm at the receiving end
-    */
+     */
     virtual void receivePacketRedundancy(int8_t* full_redundant_packet,
                                          int full_redundant_packet_size,
-                                         int full_packet_size,
-                                         uint16_t& current_seq_num,
-                                         uint16_t& last_seq_num,
-                                         uint16_t& newer_seq_num);
+                                         int full_packet_size, uint16_t& current_seq_num,
+                                         uint16_t& last_seq_num, uint16_t& newer_seq_num);
 
     /** \brief Redundancy algorythm at the sender's end
-    */
+     */
     virtual void sendPacketRedundancy(int8_t* full_redundant_packet,
                                       int full_redundant_packet_size,
                                       int full_packet_size);
 
-private:
+   private:
     bool datagramAvailable();
-    
-    int mBindPort; ///< Local Port number to Bind
-    int mPeerPort; ///< Peer Port number
-    const runModeT mRunMode; ///< Run mode, either SENDER or RECEIVER
-    bool mIPv6; /// Use IPv6
 
-    QHostAddress mPeerAddress; ///< The Peer Address
+    int mBindPort;            ///< Local Port number to Bind
+    int mPeerPort;            ///< Peer Port number
+    const runModeT mRunMode;  ///< Run mode, either SENDER or RECEIVER
+    bool mIPv6;               /// Use IPv6
+
+    QHostAddress mPeerAddress;  ///< The Peer Address
     struct sockaddr_in mPeerAddr;
     struct sockaddr_in6 mPeerAddr6;
-#if defined (__WIN_32__)
+#if defined(__WIN_32__)
     SOCKET mSocket;
 #else
     int mSocket;
 #endif
 
-    int8_t* mAudioPacket; ///< Buffer to store Audio Packets
-    int8_t* mFullPacket; ///< Buffer to store Full Packet (audio+header)
+    int8_t* mAudioPacket;  ///< Buffer to store Audio Packets
+    int8_t* mFullPacket;   ///< Buffer to store Full Packet (audio+header)
     std::vector<int8_t> mBuffer;
     int mChans;
     int mSmplSize;
     int mLastOutOfOrderCount;
     bool mInitialState;
 
-    unsigned int mUdpRedundancyFactor; ///< Factor of redundancy
-    static QMutex sUdpMutex; ///< Mutex to make thread safe the binding process
+    unsigned int mUdpRedundancyFactor;  ///< Factor of redundancy
+    static QMutex sUdpMutex;            ///< Mutex to make thread safe the binding process
 
-    std::atomic<uint32_t>  mTotCount;
-    std::atomic<uint32_t>  mLostCount;
-    std::atomic<uint32_t>  mOutOfOrderCount;
-    std::atomic<uint32_t>  mRevivedCount;
-    uint32_t  mStatCount;
+    std::atomic<uint32_t> mTotCount;
+    std::atomic<uint32_t> mLostCount;
+    std::atomic<uint32_t> mOutOfOrderCount;
+    std::atomic<uint32_t> mRevivedCount;
+    uint32_t mStatCount;
 
     uint8_t mControlPacketSize;
     bool mStopSignalSent;
@@ -238,4 +238,4 @@ private:
     std::uniform_real_distribution<double> mUniformDist;
 };
 
-#endif // __UDPDATAPROTOCOL_H__
+#endif  // __UDPDATAPROTOCOL_H__
diff --git a/src/UdpDataProtocolPOSIX.cpp.tmp b/src/UdpDataProtocolPOSIX.cpp.tmp
deleted file mode 100644 (file)
index dbd27bf..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-//*****************************************************************
-/*
-  JackTrip: A System for High-Quality Audio Network Performance
-  over the Internet
-
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
-  SoundWIRE group at CCRMA, Stanford University.
-
-  Permission is hereby granted, free of charge, to any person
-  obtaining a copy of this software and associated documentation
-  files (the "Software"), to deal in the Software without
-  restriction, including without limitation the rights to use,
-  copy, modify, merge, publish, distribute, sublicense, and/or sell
-  copies of the Software, and to permit persons to whom the
-  Software is furnished to do so, subject to the following
-  conditions:
-
-  The above copyright notice and this permission notice shall be
-  included in all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-  OTHER DEALINGS IN THE SOFTWARE.
-*/
-//*****************************************************************
-
-/**
- * \file UdpDataProtocol.cpp
- * \author Juan-Pablo Caceres
- * \date June 2008
- */
-
-#include "UdpDataProtocol.h"
-
-#include <cstring>
-#include <iostream>
-#include <cstdlib>
-#include <cerrno>
-
-// NOTE: It's better not to use
-// using namespace std;
-// because some functions (like exit()) get confused with QT functions
-
-
-
-//*******************************************************************************
-UdpDataProtocol::UdpDataProtocol(const runModeT runmode, const char* peerHostOrIP)
-    : DataProtocol(runmode)
-{
-    setPeerIPv4Address(peerHostOrIP);
-    setBindSocket();
-}
-
-
-//*******************************************************************************
-void UdpDataProtocol::setBindSocket()
-{
-    // UDP socket creation
-    mSockFd = socket(AF_INET, SOCK_DGRAM, 0);
-    if ( mSockFd < 0 ) {
-        std::cerr << "ERROR: UDP Socket Error" << std::endl;
-        std::exit(0);
-    }
-
-    // Bind local address and port
-    /// \todo Bind to a different port in case this one is used by a different instance
-    /// of the program
-    struct sockaddr_in LocalIPv4Addr = getLocalIPv4AddressStruct();
-    int nBind = bind(mSockFd, (struct sockaddr *) &LocalIPv4Addr, sizeof(LocalIPv4Addr));
-    if ( nBind < 0 ) {
-        std::cerr << "ERROR: UDP Socket Bind Error" << std::endl;
-        std::exit(0);
-    }
-
-    std::cout << "Successful socket creation and port binding" << std::endl;
-
-    //Connected UDP
-    struct sockaddr_in PeerIPv4Addr = getPeerIPv4AddressStruct();
-    int nCon = ::connect(mSockFd, (struct sockaddr *) &PeerIPv4Addr, sizeof(PeerIPv4Addr));
-    if ( nCon < 0) {
-        std::cerr << "ERROR: UDP Socket Connect Error" << std::endl;
-        std::exit(0);
-    }
-}
-
-
-//*******************************************************************************
-// Adapted form Stevens' "Unix Network Programming", third edition
-// Page 88 (readn)
-size_t UdpDataProtocol::receivePacket(char* buff, size_t n)
-{
-    size_t nleft;
-    ssize_t nread;
-    char* ptr;
-
-    ptr = buff;
-    nleft = n;
-    while (nleft > 0) {
-        if ( (nread = ::read(mSockFd, ptr, nleft)) < 0) {
-            if (errno == EINTR)
-                nread = 0; // and call read() again
-            else
-                return(-1);
-        } else if (nread == 0)
-            break; // EOF
-
-        nleft -= nread;
-        ptr   += nread;
-    }
-    return(n - nleft);
-}
-
-
-
-//*******************************************************************************
-// Adapted form Stevens' "Unix Network Programming", third edition
-// Page 88 (writen)
-// Write "n" bytes to a descriptor
-size_t UdpDataProtocol::sendPacket(const char* buff, size_t n)
-{
-    size_t nleft;
-    ssize_t nwritten;
-    const char* ptr;
-
-    ptr = buff;
-    nleft = n;
-    while (nleft > 0) {
-        if ( (nwritten = ::write(mSockFd, ptr, nleft)) <= 0) {
-            if (nwritten < 0 && errno == EINTR)
-                nwritten = 0; // and call write() again
-            else
-                return(-1); // error
-        }
-
-        nleft -= nwritten;
-        ptr   += nwritten;
-    }
-    return(n);
-}
-
diff --git a/src/UdpDataProtocolPOSIX.h.tmp b/src/UdpDataProtocolPOSIX.h.tmp
deleted file mode 100644 (file)
index 49b1434..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-//*****************************************************************
-/*
-  JackTrip: A System for High-Quality Audio Network Performance
-  over the Internet
-
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
-  SoundWIRE group at CCRMA, Stanford University.
-
-  Permission is hereby granted, free of charge, to any person
-  obtaining a copy of this software and associated documentation
-  files (the "Software"), to deal in the Software without
-  restriction, including without limitation the rights to use,
-  copy, modify, merge, publish, distribute, sublicense, and/or sell
-  copies of the Software, and to permit persons to whom the
-  Software is furnished to do so, subject to the following
-  conditions:
-
-  The above copyright notice and this permission notice shall be
-  included in all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-  OTHER DEALINGS IN THE SOFTWARE.
-*/
-//*****************************************************************
-
-/**
- * \file UdpDataProtocol.h
- * \author Juan-Pablo Caceres
- * \date June 2008
- */
-
-#ifndef __UDPDATAPROTOCOL_H__
-#define __UDPDATAROTOCOL_H__
-
-#include "DataProtocol.h"
-
-/** \brief UDP implementation of DataProtocol class
- *
- *
- *
- */
-class UdpDataProtocol : public DataProtocol
-{
-public:
-
-    /** \brief The class constructor
-   * \param runmode Sets the run mode, use either SENDER or RECEIVER
-   * \param peerHostOrIP IPv4 number or host name
-   */
-    UdpDataProtocol(const runModeT runmode, const char* peerHostOrIP);
-
-    /** \brief The class destructor
-   */
-    virtual ~UdpDataProtocol() {};
-
-    /** \brief Receives a packet
-   *
-   * This function makes sure we recieve a complete packet
-   * of size n
-   * \param buf Buffer to store the recieved packet
-   * \param n size of packet to receive
-   * \return number of bytes read, -1 on error
-   */
-    virtual size_t receivePacket(char* buf, size_t n);
-
-    /** \brief Sends a packet
-   *
-   * This function meakes sure we send a complete packet
-   * of size n
-   * \param buff Buffer to send
-   * \param n size of packet to receive
-   * \return number of bytes read, -1 on error
-   */
-    virtual size_t sendPacket(const char* buff, size_t n);
-
-    //virtual void run();
-
-
-private:
-
-    void setBindSocket();
-
-    int mSockFd; ///< Socket file descriptor
-};
-
-#endif
index ec1b5085c7d6f07ad830c4bb2dd153f6755d6fed..2f2258317ac657d0f10f94510370200c1ed8798f 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
  * \date September 2008
  */
 
-#include <iostream>
+#include "UdpHubListener.h"
+
+#include <QFile>
+#include <QFileInfo>
+#include <QMutexLocker>
+#include <QSslKey>
+#include <QSslSocket>
+#include <QStringList>
+#include <QtEndian>
 #include <cstdlib>
-#include <stdexcept>
 #include <cstring>
+#include <iostream>
+#include <stdexcept>
 
-#include <QTcpServer>
-#include <QTcpSocket>
-#include <QStringList>
-#include <QMutexLocker>
+#ifndef __NO_JACK__
+#include "JMess.h"
+#endif
 
-#include "UdpHubListener.h"
 #include "JackTripWorker.h"
 #include "jacktrip_globals.h"
 
-using std::cout; using std::endl;
+using std::cout;
+using std::endl;
 
 bool UdpHubListener::sSigInt = false;
 
 //*******************************************************************************
-UdpHubListener::UdpHubListener(int server_port, int server_udp_port) :
-    //mJTWorker(NULL),
-    mTcpServer(this),
-    mServerPort(server_port),
-    mServerUdpPort(server_udp_port),//final udp base port number
-    mStopped(false),
-    #ifdef WAIR // wair
-    mWAIR(false),
-    #endif // endwhere
-    mTotalRunningThreads(0),
-    mHubPatchDescriptions({"server-to-clients", "client loopback", "client fan out/in but not loopback",
-                           "reserved for TUB", "full mix", "no auto patching"}),
-    m_connectDefaultAudioPorts(false),
-    mIOStatTimeout(0)
+UdpHubListener::UdpHubListener(int server_port, int server_udp_port)
+    : mTcpServer(this)
+    , mServerPort(server_port)
+    , mServerUdpPort(server_udp_port)
+    ,  // final udp base port number
+    mRequireAuth(false)
+    , mStopped(false)
+#ifdef WAIR  // wair
+    , mWAIR(false)
+#endif  // endwhere
+    , mTotalRunningThreads(0)
+    , mHubPatchDescriptions({"server-to-clients", "client loopback",
+                             "client fan out/in but not loopback", "reserved for TUB",
+                             "full mix", "no auto patching"})
+    , m_connectDefaultAudioPorts(false)
+    , mIOStatTimeout(0)
 {
     // Register JackTripWorker with the hub listener
-    //mJTWorker = new JackTripWorker(this);
+    // mJTWorker = new JackTripWorker(this);
     mJTWorkers = new QVector<JackTripWorker*>;
-    for (int i = 0; i<gMaxThreads; i++) {
-        mJTWorkers->insert(i, NULL);
-    }
+    for (int i = 0; i < gMaxThreads; i++) { mJTWorkers->append(nullptr); }
 
-    qDebug() << "mThreadPool default maxThreadCount =" << mThreadPool.maxThreadCount();
-    mThreadPool.setMaxThreadCount(mThreadPool.maxThreadCount() * 16);
-    qDebug() << "mThreadPool maxThreadCount set to" << mThreadPool.maxThreadCount();
+    qDebug() << "mThreadPool default maxThreadCount =" << QThread::idealThreadCount();
+    qDebug() << "mThreadPool maxThreadCount previously set to"
+             << QThread::idealThreadCount() * 16;
 
-    //mJTWorkers = new JackTripWorker(this);
-    mThreadPool.setExpiryTimeout(3000); // msec (-1) = forever
-    // Inizialize IP addresses
-    for (int i = 0; i<gMaxThreads; i++) {
-        mActiveAddress[i].address = ""; // Address strings
-        mActiveAddress[i].port = 0;
-    }
     // Set the base dynamic port
     // The Dynamic and/or Private Ports are those from 49152 through 65535
     // mBasePort = ( rand() % ( (65535 - gMaxThreads) - 49152 ) ) + 49152;
 
     // SoundWIRE ports open are UDP 61002-62000
     // (server_port - gDefaultPort) apply TCP offset to UDP too
-    if (mServerUdpPort != 0){
-      mBasePort = mServerUdpPort;
+    if (mServerUdpPort != 0) {
+        mBasePort = mServerUdpPort;
     } else {
-      mBasePort = 61002 + (server_port - gDefaultPort);
+        mBasePort = 61002 + (server_port - gDefaultPort);
     }
 
     cout << "JackTrip HUB SERVER: UDP Base Port set to " << mBasePort << endl;
 
-    mUnderRunMode = JackTrip::WAVETABLE;
+    mUnderRunMode      = JackTrip::WAVETABLE;
     mBufferQueueLength = gDefaultQueueLength;
 
-    mBufferStrategy = 1;
-    mBroadcastQueue = 0;
-    mSimulatedLossRate = 0.0;
+    mBufferStrategy      = 1;
+    mBroadcastQueue      = 0;
+    mSimulatedLossRate   = 0.0;
     mSimulatedJitterRate = 0.0;
-    mSimulatedDelayRel = 0.0;
+    mSimulatedDelayRel   = 0.0;
 
     mUseRtUdpPriority = false;
 }
 
-
 //*******************************************************************************
 UdpHubListener::~UdpHubListener()
 {
     QMutexLocker lock(&mMutex);
-    mThreadPool.waitForDone();
-    //delete mJTWorker;
-    for (int i = 0; i<gMaxThreads; i++) {
-        delete mJTWorkers->at(i);
-    }
+    // delete mJTWorker;
+    for (int i = 0; i < gMaxThreads; i++) { delete mJTWorkers->at(i); }
     delete mJTWorkers;
 }
 
-
 //*******************************************************************************
 // Now that the first handshake is with TCP server, if the addreess/peer port of
 // the client is already on the thread pool, it means that a new connection is
-// requested (the old was desconnected). So we have to remove that thread from
+// requested (the old was disconnected). So we have to remove that thread from
 // the pool and then connect again.
 void UdpHubListener::start()
 {
@@ -138,141 +134,213 @@ void UdpHubListener::start()
 
     // Bind the TCP server
     // ------------------------------
-    QObject::connect(&mTcpServer, &QTcpServer::newConnection, this, &UdpHubListener::receivedNewConnection);
-    if ( !mTcpServer.listen(QHostAddress::Any, mServerPort) ) {
-        QString error_message = QString("TCP Socket Server on Port %1 ERROR: %2").arg(mServerPort).arg(mTcpServer.errorString());
+    QObject::connect(&mTcpServer, &SslServer::newConnection, this,
+                     &UdpHubListener::receivedNewConnection);
+    if (!mTcpServer.listen(QHostAddress::Any, mServerPort)) {
+        QString error_message = QString("TCP Socket Server on Port %1 ERROR: %2")
+                                    .arg(mServerPort)
+                                    .arg(mTcpServer.errorString());
         std::cerr << error_message.toStdString() << endl;
         emit signalError(error_message);
         return;
     }
-    
+
+    if (mRequireAuth) {
+        cout << "JackTrip HUB SERVER: Enabling authentication" << endl;
+        // Check that SSL is avaialable
+        bool error = false;
+        QString error_message;
+        if (!QSslSocket::supportsSsl()) {
+            error = true;
+            error_message =
+                "SSL not supported. Make sure you have the appropriate SSL "
+                "libraries\ninstalled to enable authentication.";
+        }
+
+        if (mCertFile.isEmpty()) {
+            error         = true;
+            error_message = "No certificate file specified.";
+        } else if (mKeyFile.isEmpty()) {
+            error         = true;
+            error_message = "No private key file specified.";
+        }
+
+        // Load our certificate and private key
+        if (!error) {
+            QFile certFile(mCertFile);
+            if (certFile.open(QIODevice::ReadOnly)) {
+                QSslCertificate cert(certFile.readAll());
+                if (!cert.isNull()) {
+                    mTcpServer.setCertificate(cert);
+                } else {
+                    error         = true;
+                    error_message = "Unable to load certificate file.";
+                }
+            } else {
+                error         = true;
+                error_message = "Could not find certificate file.";
+            }
+        }
+
+        if (!error) {
+            QFile keyFile(mKeyFile);
+            if (keyFile.open(QIODevice::ReadOnly)) {
+                QSslKey key(&keyFile, QSsl::Rsa);
+                if (!key.isNull()) {
+                    mTcpServer.setPrivateKey(key);
+                } else {
+                    error         = true;
+                    error_message = "Unable to read RSA private key file.";
+                }
+            } else {
+                error         = true;
+                error_message = "Could not find RSA private key file.";
+            }
+        }
+
+        if (!error) {
+            QFileInfo credsInfo(mCredsFile);
+            if (!credsInfo.exists() || !credsInfo.isFile()) {
+                error         = true;
+                error_message = "Could not find credentials file.";
+            }
+        }
+
+        if (error) {
+            std::cerr << "ERROR: " << error_message.toStdString() << endl;
+            emit signalError(error_message);
+            return;
+        }
+        mAuth.reset(new Auth(mCredsFile));
+    }
+
     cout << "JackTrip HUB SERVER: Waiting for client connections..." << endl;
-    cout << "JackTrip HUB SERVER: Hub auto audio patch setting = " << mHubPatch 
-         << " (" << mHubPatchDescriptions.at(mHubPatch).toStdString() << ")" << endl;
+    cout << "JackTrip HUB SERVER: Hub auto audio patch setting = " << mHubPatch << " ("
+         << mHubPatchDescriptions.at(mHubPatch).toStdString() << ")" << endl;
     cout << "=======================================================" << endl;
-    
+
     // Start our monitoring timer
     mStopCheckTimer.setInterval(200);
     connect(&mStopCheckTimer, &QTimer::timeout, this, &UdpHubListener::stopCheck);
     mStopCheckTimer.start();
 }
-    
+
 void UdpHubListener::receivedNewConnection()
 {
-    QTcpSocket *clientSocket = mTcpServer.nextPendingConnection();
-    connect(clientSocket, &QAbstractSocket::readyRead, this, [=]{
-            receivedClientInfo(clientSocket);
-        });
+    QSslSocket* clientSocket =
+        static_cast<QSslSocket*>(mTcpServer.nextPendingConnection());
+    connect(clientSocket, &QAbstractSocket::readyRead, this,
+            [=] { receivedClientInfo(clientSocket); });
     cout << "JackTrip HUB SERVER: Client Connection Received!" << endl;
 }
 
-void UdpHubListener::receivedClientInfo(QTcpSocket *clientConnection)
+void UdpHubListener::receivedClientInfo(QSslSocket* clientConnection)
 {
     QHostAddress PeerAddress = clientConnection->peerAddress();
     cout << "JackTrip HUB SERVER: Client Connect Received from Address : "
          << PeerAddress.toString().toStdString() << endl;
-         
+
     // Get UDP port from client
     // ------------------------
     QString clientName = QString();
     cout << "JackTrip HUB SERVER: Reading UDP port from Client..." << endl;
-    if (clientConnection->bytesAvailable() < (qint64)sizeof(uint16_t)) {
-        // We don't have enough data. Wait for the next readyRead notification.
-        return;
+    int peer_udp_port;
+    if (!clientConnection->isEncrypted()) {
+        if (clientConnection->bytesAvailable() < (int)sizeof(qint32)) {
+            // We don't have enough data. Wait for the next readyRead notification.
+            return;
+        }
+        peer_udp_port = readClientUdpPort(clientConnection, clientName);
+        // Use our peer port to check if we need to authenticate our client.
+        // (We use values above the max port number of 65535 to achieve this. Since the
+        // port number was always sent as a 32 bit integer, it meants we can squeeze this
+        // functionality in here without breaking older clients when authentication isn't
+        // required.)
+        if (peer_udp_port == Auth::OK) {
+            if (!mRequireAuth) {
+                // We're not using authentication. Let the client know and close the
+                // connection.
+                cout << "JackTrip HUB SERVER: Client attempting unnecessary "
+                        "authentication. Disconnecting."
+                     << endl;
+                sendUdpPort(clientConnection, Auth::NOTREQUIRED);
+                clientConnection->close();
+                clientConnection->deleteLater();
+                return;
+            }
+            // Initiate the SSL handshake, and wait for more data to arrive once it's been
+            // established.
+            sendUdpPort(clientConnection, Auth::OK);
+            clientConnection->startServerEncryption();
+            return;
+        } else if (mRequireAuth) {
+            // Let our client know we're not accepting connections without authentication.
+            cout << "JackTrip HUB SERVER: Client not authenticating. Disconnecting."
+                 << endl;
+            sendUdpPort(clientConnection, Auth::REQUIRED);
+            clientConnection->close();
+            clientConnection->deleteLater();
+            return;
+        }
+    } else {
+        // This branch executes when our socket is already in SSL mode and we're expecting
+        // to read our authentication data.
+        peer_udp_port = checkAuthAndReadPort(clientConnection, clientName);
+        if (peer_udp_port > 65535) {
+            // Our client hasn't provided valid credentials. Send an error code and close
+            // the connection.
+            cout << "JackTrip HUB SERVER: Authentication failed. Disconnecting." << endl;
+            sendUdpPort(clientConnection, peer_udp_port);
+            clientConnection->close();
+            clientConnection->deleteLater();
+            return;
+        }
     }
-    uint16_t peer_udp_port= readClientUdpPort(clientConnection, clientName);
+    // If we haven't received our port, wait for more data to arrive.
+    if (peer_udp_port == 0) { return; }
 
+    // At this stage, we should definitely only be dealing with a 16 bit integer. (Ignore
+    // the upper bytes.)
+    peer_udp_port &= 0xffff;
     cout << "JackTrip HUB SERVER: Client UDP Port is = " << peer_udp_port << endl;
-    if ( peer_udp_port == 0 || peer_udp_port < gBindPortLow || peer_udp_port > gBindPortHigh ) {
-        cout << "JackTrip HUB SERVER: Exiting " << endl;
-        clientConnection->close();
-        clientConnection->deleteLater();
-        return;
-    }
-    
-    // Check is client is new or not
+
+    // Create a new JackTripWorker, but don't check if this is coming from an existing ip
+    // or port yet. We need to wait until we receive the port value from the UDP header to
+    // accomodate NAT.
     // -----------------------------
-    // Check if Address is not already in the thread pool
-    // check by comparing address strings (To handle IPv4 and IPv6.)
-    int id = isNewAddress(PeerAddress.toString(), peer_udp_port);
-    // If the address is not new, we need to remove the client from the pool
-    // before re-starting the connection
-
-    if (id == -1) {
-        int id_remove;
-        id_remove = getPoolID(PeerAddress.toString(), peer_udp_port);
-        // stop the thread
-        mJTWorkers->at(id_remove)->stopThread();
-        // block until the thread has been removed from the pool
-        while ( isNewAddress(PeerAddress.toString(), peer_udp_port) == -1 ) {
-            cout << "JackTrip HUB SERVER: Removing JackTripWorker from pool..." << endl;
-            QThread::msleep(10);
-        }
-        // Get a new ID for this client
-        //id = isNewAddress(PeerAddress.toIPv4Address(), peer_udp_port);
-        id = getPoolID(PeerAddress.toString(), peer_udp_port);
-    }
+    int id = getJackTripWorker(PeerAddress.toString(), peer_udp_port, clientName);
+
     // Assign server port and send it to Client
-    int server_udp_port = mBasePort+id;
-    cout << "JackTrip HUB SERVER: Sending Final UDP Port to Client: " << server_udp_port << endl;
-    
-     if ( sendUdpPort(clientConnection, server_udp_port) == 0 ) {
+    if (id != -1) {
+        cout << "JackTrip HUB SERVER: Sending Final UDP Port to Client: "
+             << mJTWorkers->at(id)->getServerPort() << endl;
+    }
+
+    if (id == -1
+        || sendUdpPort(clientConnection, mJTWorkers->at(id)->getServerPort()) == 0) {
         clientConnection->close();
         clientConnection->deleteLater();
         releaseThread(id);
         return;
     }
-    
+
     // Close and mark socket for deletion
     // ----------------------------------
     clientConnection->close();
     clientConnection->deleteLater();
     cout << "JackTrip HUB SERVER: Client TCP Connection Closed!" << endl;
 
-    // Spawn Thread to Pool
-    // --------------------
-    // Register JackTripWorker with the hub listener
-    delete mJTWorkers->at(id); // just in case the Worker was previously created
-    mJTWorkers->replace(id, new JackTripWorker(this, mBufferQueueLength, mUnderRunMode, clientName));
     if (mIOStatTimeout > 0) {
         mJTWorkers->at(id)->setIOStatTimeout(mIOStatTimeout);
         mJTWorkers->at(id)->setIOStatStream(mIOStatStream);
     }
     mJTWorkers->at(id)->setBufferStrategy(mBufferStrategy);
-    mJTWorkers->at(id)->setNetIssuesSimulation(mSimulatedLossRate,
-    mSimulatedJitterRate, mSimulatedDelayRel);
+    mJTWorkers->at(id)->setNetIssuesSimulation(mSimulatedLossRate, mSimulatedJitterRate,
+                                               mSimulatedDelayRel);
     mJTWorkers->at(id)->setBroadcast(mBroadcastQueue);
     mJTWorkers->at(id)->setUseRtUdpPriority(mUseRtUdpPriority);
-    // redirect port and spawn listener
-    cout << "JackTrip HUB SERVER: Spawning JackTripWorker..." << endl;
-    {
-        QMutexLocker lock(&mMutex);
-        mJTWorkers->at(id)->setJackTrip(id,
-                                        mActiveAddress[id].address,
-                                        server_udp_port,
-                                        mActiveAddress[id].port,
-                                        1,
-                                        m_connectDefaultAudioPorts
-                                        ); /// \todo temp default to 1 channel
-
-        //qDebug() << "mPeerAddress" << id <<  mActiveAddress[id].address << mActiveAddress[id].port;
-    }
-    //send one thread to the pool
     cout << "JackTrip HUB SERVER: Starting JackTripWorker..." << endl;
-    mThreadPool.start(mJTWorkers->at(id), QThread::TimeCriticalPriority);
-    // wait until one is complete before another spawns
-    while (mJTWorkers->at(id)->isSpawning()) { QThread::msleep(10); }
-    //mTotalRunningThreads++;
-    cout << "JackTrip HUB SERVER: Total Running Threads:  " << mTotalRunningThreads << endl;
-    cout << "===============================================================" << endl;
-    QThread::msleep(100);
-#ifdef WAIR // WAIR
-    if (isWAIR()) connectMesh(true); // invoked with -Sw
-#endif // endwhere
-
-    //qDebug() << "mPeerAddress" << mActiveAddress[id].address << mActiveAddress[id].port;
-
-    connectPatch(true);
+    mJTWorkers->at(id)->start();
 }
 
 void UdpHubListener::stopCheck()
@@ -286,210 +354,249 @@ void UdpHubListener::stopCheck()
     }
 }
 
-    /* From Old Runloop code
-  // Create objects on the stack
-  QUdpSocket HubUdpSocket;
-  QHostAddress PeerAddress;
-  uint16_t peer_port; // Ougoing Peer port, in case they're not using the default
-
-  // Bind the socket to the well known port
-  bindUdpSocket(HubUdpSocket, mServerPort);
-
-  char buf[1];
-  cout << "Server Listening in UDP Port: " << mServerPort << endl;
-  cout << "Waiting for client..." << endl;
-  cout << "=======================================================" << endl;
-  while ( !mStopped )
-  {
-    //cout << "WAITING........................." << endl;
-    while ( HubUdpSocket.hasPendingDatagrams() )
-    {
-      cout << "Received request from Client!" << endl;
-      // Get Client IP Address and outgoing port from packet
-      int rv = HubUdpSocket.readDatagram(buf, 1, &PeerAddress, &peer_port);
-      cout << "Peer Port in Server ==== " << peer_port << endl;
-      if (rv < 0) { std::cerr << "ERROR: Bad UDP packet read..." << endl; }
-
-      /// \todo Get number of channels in the client from header
-
-      // check by comparing 32-bit addresses
-      /// \todo Add the port number in the comparison
-      cout << "peer_portpeer_portpeer_port === " << peer_port << endl;
-      int id = isNewAddress(PeerAddress.toIPv4Address(), peer_port);
-
-      //cout << "IDIDIDIDIDDID === " << id << endl;
-
-      // If the address is new, create a new thread in the pool
-      if (id >= 0) // old address is -1
-      {
-        // redirect port and spawn listener
-        sendToPoolPrototype(id);
-        // wait until one is complete before another spawns
-        while (mJTWorker->isSpawning()) { QThread::msleep(10); }
-        mTotalRunningThreads++;
-        cout << "Total Running Threads:  " << mTotalRunningThreads << endl;
-        cout << "=======================================================" << endl;
-      }
-      //cout << "ENDDDDDDDDDDDDDDDDDd === " << id << endl;
-    }
-    QThread::msleep(100);
-  }
-  */
-
 //*******************************************************************************
 // Returns 0 on error
-uint16_t UdpHubListener::readClientUdpPort(QTcpSocket* clientConnection, QString &clientName)
+int UdpHubListener::readClientUdpPort(QSslSocket* clientConnection, QString& clientName)
 {
     if (gVerboseFlag) cout << "Ready To Read From Client!" << endl;
     // Read UDP Port Number from Server
     // --------------------------------
-    uint16_t udp_port;
-    qint64 size = sizeof(udp_port);
-    char port_buf[size];
+    qint32 udp_port;
+    int size       = sizeof(udp_port);
+    char* port_buf = new char[size];
     clientConnection->read(port_buf, size);
-    std::memcpy(&udp_port, port_buf, size);
-    
+    udp_port = qFromLittleEndian<qint32>(port_buf);
+    delete[] port_buf;
+    // std::memcpy(&udp_port, port_buf, size);
+
+    // Check if we have enough data available to set our remote client name
+    // (Optional so that we don't block here with earlier clients that don't send it.)
     if (clientConnection->bytesAvailable() == gMaxRemoteNameLength) {
         char name_buf[gMaxRemoteNameLength];
         clientConnection->read(name_buf, gMaxRemoteNameLength);
-        clientName = QString::fromUtf8((const char *)name_buf);
+        clientName = QString::fromUtf8((const char*)name_buf);
     }
-    
+
     return udp_port;
 }
 
+int UdpHubListener::checkAuthAndReadPort(QSslSocket* clientConnection,
+                                         QString& clientName)
+{
+    if (gVerboseFlag) cout << "Ready To Read Authentication Data From Client!" << endl;
+    // Because we don't know how long our username and password are, we have to peek at
+    // our data to read the expected lengths and know if we have enough to work with.
+
+    // Currently, we expect to receive:
+    // 4 bytes: LE int giving our port number.
+    // 64 bytes: Maximum 63 byte jack client name (with null terminator).
+    // 4 bytes: Username length, not including null terminator.
+    // 4 bytes: Password length, not including null terminator.
+    // Variable length: Our username and password, each with added null terminator.
+
+    int size = gMaxRemoteNameLength + (3 * sizeof(qint32));
+    if (clientConnection->bytesAvailable() < size) { return 0; }
+
+    qint32 usernameLength, passwordLength;
+    char* buf = new char[size];
+    clientConnection->peek(buf, size);
+    usernameLength =
+        qFromLittleEndian<qint32>(buf + gMaxRemoteNameLength + sizeof(qint32));
+    passwordLength =
+        qFromLittleEndian<qint32>(buf + gMaxRemoteNameLength + (2 * sizeof(qint32)));
+    delete[] buf;
+
+    // Check if we have enough data.
+    if (clientConnection->bytesAvailable() < size + usernameLength + passwordLength + 2) {
+        return 0;
+    }
+
+    // Get our port.
+    qint32 udp_port;
+    size           = sizeof(udp_port);
+    char* port_buf = new char[size];
+    clientConnection->read(port_buf, size);
+    udp_port = qFromLittleEndian<qint32>(port_buf);
+
+    // Then our jack client name.
+    char name_buf[gMaxRemoteNameLength];
+    clientConnection->read(name_buf, gMaxRemoteNameLength);
+    clientName = QString::fromUtf8((const char*)name_buf);
+
+    // We can discard our username and password length since we already have them.
+    clientConnection->read(port_buf, size);
+    clientConnection->read(port_buf, size);
+    delete[] port_buf;
+
+    // And then get our username and password.
+    QString username, password;
+    char* username_buf = new char[usernameLength + 1];
+    clientConnection->read(username_buf, usernameLength + 1);
+    username = QString::fromUtf8((const char*)username_buf);
+    delete[] username_buf;
+
+    char* password_buf = new char[passwordLength + 1];
+    clientConnection->read(password_buf, passwordLength + 1);
+    password = QString::fromUtf8((const char*)password_buf);
+    delete[] password_buf;
+
+    // Check if our credentials are valid, and return either an error code or our port.
+    Auth::AuthResponseT response = mAuth->checkCredentials(username, password);
+    if (response == Auth::OK) {
+        return udp_port;
+    } else {
+        return response;
+    }
+}
 
 //*******************************************************************************
-int UdpHubListener::sendUdpPort(QTcpSocket* clientConnection, int udp_port)
+int UdpHubListener::sendUdpPort(QSslSocket* clientConnection, qint32 udp_port)
 {
     // Send Port Number to Client
     // --------------------------
     char port_buf[sizeof(udp_port)];
-    std::memcpy(port_buf, &udp_port, sizeof(udp_port));
+    // std::memcpy(port_buf, &udp_port, sizeof(udp_port));
+    qToLittleEndian<qint32>(udp_port, port_buf);
+    if (udp_port < 65536) {
+        std::cout << "Writing port: " << udp_port << std::endl;
+    } else {
+        std::cout << "Writing auth response: " << udp_port << std::endl;
+    }
     clientConnection->write(port_buf, sizeof(udp_port));
-    while ( clientConnection->bytesToWrite() > 0 ) {
-        if ( clientConnection->state() == QAbstractSocket::ConnectedState ) {
+    while (clientConnection->bytesToWrite() > 0) {
+        if (clientConnection->state() == QAbstractSocket::ConnectedState) {
             clientConnection->waitForBytesWritten(-1);
-        }
-        else {
+        } else {
             return 0;
         }
     }
     return 1;
-    //cout << "Port sent to Client" << endl;
-}
-
-
-//*******************************************************************************
-/*
-void UdpHubListener::sendToPoolPrototype(int id)
-{
-  mJTWorker->setJackTrip(id, mActiveAddress[id][0],
-                         mBasePort+(2*id), mActiveAddress[id][1],
-                         1); /// \todo temp default to 1 channel
-  mThreadPool.start(mJTWorker, QThread::TimeCriticalPriority); //send one thread to the pool
+    // cout << "Port sent to Client" << endl;
 }
-*/
-
 
 //*******************************************************************************
 void UdpHubListener::bindUdpSocket(QUdpSocket& udpsocket, int port)
 {
     // QHostAddress::Any : let the kernel decide the active address
-    if ( !udpsocket.bind(QHostAddress::Any,
-                         port, QUdpSocket::DefaultForPlatform) ) {
-        //std::cerr << "ERROR: could not bind UDP socket" << endl;
-        //std::exit(1);
+    if (!udpsocket.bind(QHostAddress::Any, port, QUdpSocket::DefaultForPlatform)) {
+        // std::cerr << "ERROR: could not bind UDP socket" << endl;
+        // std::exit(1);
         throw std::runtime_error("Could not bind UDP socket. It may be already binded.");
-    }
-    else {
+    } else {
         cout << "UDP Socket Receiving in Port: " << port << endl;
     }
 }
 
-
 //*******************************************************************************
-// check by comparing 32-bit addresses
-int UdpHubListener::isNewAddress(QString address, uint16_t port)
+int UdpHubListener::getJackTripWorker(QString address, [[maybe_unused]] uint16_t port,
+                                      QString& clientName)
 {
+    // Find our first empty slot in our vector of worker object pointers.
+    // Return -1 if we have no space left for additional threads, or the index of the new
+    // JackTripWorker.
     QMutexLocker lock(&mMutex);
-    bool busyAddress = false;
-    int id = 0;
-
-    /*
-  while ( !busyAddress && (id<mThreadPool.activeThreadCount()) )
-  {
-    if ( address==mActiveAddress[id][0] &&  port==mActiveAddress[id][1]) { busyAddress = true; }
-    id++;
-  }
-  */
-    for (int i = 0; i<gMaxThreads; i++) {
-        if ( address==mActiveAddress[i].address &&  port==mActiveAddress[i].port) {
+    int id = -1;
+    for (int i = 0; i < gMaxThreads; i++) {
+        if (mJTWorkers->at(i) == nullptr) {
             id = i;
-            busyAddress = true;
-        }
-    }
-    if ( !busyAddress ) {
-        /*
-    mActiveAddress[id][0] = address;
-    mActiveAddress[id][1] = port;
-  } else {
-  */
-        id = 0;
-        bool foundEmptyAddress = false;
-        while ( !foundEmptyAddress && (id<gMaxThreads) ) {
-            if ( mActiveAddress[id].address.isEmpty() &&  (mActiveAddress[id].port == 0) ) {
-                foundEmptyAddress = true;
-                mActiveAddress[id].address = address;
-                mActiveAddress[id].port = port;
-            }  else {
-                id++;
-            }
+            i  = gMaxThreads;
         }
     }
-    if (!busyAddress) {
+
+    if (id >= 0) {
         mTotalRunningThreads++;
+        if (mAppendThreadID) { clientName = clientName + QString("_%1").arg(id + 1); }
+        mJTWorkers->replace(
+            id, new JackTripWorker(this, mBufferQueueLength, mUnderRunMode, clientName));
+        mJTWorkers->at(id)->setJackTrip(
+            id, address, mBasePort + id,
+            0,  // Set client port to 0 initially until we receive a UDP packet.
+            m_connectDefaultAudioPorts);  //
     }
-    return ((busyAddress) ? -1 : id);
-}
 
+    return id;
+}
 
 //*******************************************************************************
 int UdpHubListener::getPoolID(QString address, uint16_t port)
 {
     QMutexLocker lock(&mMutex);
-    //for (int id = 0; id<mThreadPool.activeThreadCount(); id++ )
-    for (int id = 0; id<gMaxThreads; id++ )
-    {
-        if ( address==mActiveAddress[id].address &&  port==mActiveAddress[id].port)
-        { return id; }
+    // for (int id = 0; id<mThreadPool.activeThreadCount(); id++ )
+    for (int id = 0; id < gMaxThreads; id++) {
+        if (mJTWorkers->at(id) != nullptr
+            && address == mJTWorkers->at(id)->getClientAddress()
+            && port == mJTWorkers->at(id)->getServerPort()) {
+            return id;
+        }
     }
     return -1;
 }
 
+#ifndef __NO_JACK__
+void UdpHubListener::registerClientWithPatcher(QString& clientName)
+{
+    cout << "JackTrip HUB SERVER: Total Running Threads:  " << mTotalRunningThreads
+         << endl;
+    cout << "===============================================================" << endl;
+#ifdef WAIR                           // WAIR
+    if (isWAIR()) connectMesh(true);  // invoked with -Sw
+#endif                                // endwhere
+    // qDebug() << "mPeerAddress" << mActiveAddress[id].address <<
+    // mActiveAddress[id].port;
+    connectPatch(true, clientName);
+}
+
+void UdpHubListener::unregisterClientWithPatcher(QString& clientName)
+{
+#ifdef WAIR                            // wair
+    if (isWAIR()) connectMesh(false);  // invoked with -Sw
+#endif                                 // endwhere
+    connectPatch(false, clientName);
+}
+#endif  // __NO_JACK__
 
 //*******************************************************************************
 int UdpHubListener::releaseThread(int id)
 {
     QMutexLocker lock(&mMutex);
-    mActiveAddress[id].address = "";
-    mActiveAddress[id].port = 0;
     mTotalRunningThreads--;
-#ifdef WAIR // wair
-    if (isWAIR()) connectMesh(false); // invoked with -Sw
-#endif // endwhere
-    if (getHubPatch()) connectPatch(false); // invoked with -p > 0
-    return 0; /// \todo Check if we really need to return an argument here
+#ifdef WAIR                            // wair
+    if (isWAIR()) connectMesh(false);  // invoked with -Sw
+#endif                                 // endwhere
+    mJTWorkers->at(id)->deleteLater();
+    mJTWorkers->replace(id, nullptr);
+    return 0;  /// \todo Check if we really need to return an argument here
 }
 
-#ifdef WAIR // wair
-#include "JMess.h"
+void UdpHubListener::releaseDuplicateThreads(JackTripWorker* worker,
+                                             uint16_t actual_peer_port)
+{
+    QMutexLocker lock(&mMutex);
+    // Now that we have our actual port, remove any duplicate workers.
+    for (int i = 0; i < gMaxThreads; i++) {
+        if (mJTWorkers->at(i) != nullptr
+            && worker->getClientAddress() == mJTWorkers->at(i)->getClientAddress()
+            && actual_peer_port == mJTWorkers->at(i)->getClientPort()) {
+            mJTWorkers->at(i)->stopThread();
+            mJTWorkers->at(i)->deleteLater();
+            mJTWorkers->replace(i, nullptr);
+            mTotalRunningThreads--;
+        }
+    }
+    worker->setClientPort(actual_peer_port);
+}
+
+#ifndef __NO_JACK__
+#ifdef WAIR  // wair
 //*******************************************************************************
 void UdpHubListener::connectMesh(bool spawn)
 {
-    cout << ((spawn)?"spawning":"releasing") << " jacktripWorker so change mesh" << endl;
+    cout << ((spawn) ? "spawning" : "releasing") << " jacktripWorker so change mesh"
+         << endl;
     JMess tmp;
-    tmp.connectSpawnedPorts(gDefaultNumInChannels); // change gDefaultNumInChannels if more than stereo LAIR interconnects
+    tmp.connectSpawnedPorts(
+        gDefaultNumInChannels);  // change gDefaultNumInChannels if more than stereo LAIR
+                                 // interconnects
     //  tmp.disconnectAll();
     //  enumerateRunningThreadIDs();
 }
@@ -497,34 +604,37 @@ void UdpHubListener::connectMesh(bool spawn)
 //*******************************************************************************
 void UdpHubListener::enumerateRunningThreadIDs()
 {
-    for (int id = 0; id<gMaxThreads; id++ )
-    {
-        if ( !mActiveAddress[id].address.isEmpty() )
-        { qDebug() << id; }
+    for (int id = 0; id < gMaxThreads; id++) {
+        if (mJTWorkers->at(id) != nullptr) { qDebug() << id; }
     }
 }
-#endif // endwhere
+#endif  // endwhere
 
-#include "JMess.h"
-void UdpHubListener::connectPatch(bool spawn)
+void UdpHubListener::connectPatch(bool spawn, const QString& clientName)
 {
-    if ((getHubPatch() == JackTrip::NOAUTO) ||
-        (getHubPatch() == JackTrip::SERVERTOCLIENT && !m_connectDefaultAudioPorts)) {
-        cout << ((spawn)?"spawning":"releasing") << " jacktripWorker (auto hub patching disabled)" << endl;
+    if ((getHubPatch() == JackTrip::NOAUTO)
+        || (getHubPatch() == JackTrip::SERVERTOCLIENT && !m_connectDefaultAudioPorts)) {
+        cout << ((spawn) ? "spawning" : "releasing")
+             << " jacktripWorker (auto hub patching disabled)" << endl;
         return;
     }
-    cout << ((spawn)?"spawning":"releasing") << " jacktripWorker so change patch" << endl;
-    JMess tmp;
-    // default is patch 0, which connects server audio to all clients
-    // these are the other cases:
-    if (getHubPatch() == JackTrip::RESERVEDMATRIX) // special patch for TU Berlin ensemble
+    cout << ((spawn) ? "spawning" : "releasing") << " jacktripWorker so change patch"
+         << endl;
+    if (getHubPatch() == JackTrip::RESERVEDMATRIX) {
+        // This is a special patch for the TU Berlin ensemble.
+        // Use the old JMess mechanism.
+        JMess tmp;
         tmp.connectTUB(gDefaultNumInChannels);
-    else if ((getHubPatch() == JackTrip::CLIENTECHO) || // client loopback for testing
-             (getHubPatch() == JackTrip::CLIENTFOFI) || // all clients to all clients except self
-             (getHubPatch() == JackTrip::FULLMIX)) // all clients to all clients including self
-        tmp.connectSpawnedPorts(gDefaultNumInChannels,getHubPatch());
-    // FIXME: need change to gDefaultNumInChannels if more than stereo
+        // FIXME: need change to gDefaultNumInChannels if more than stereo
+    } else {
+        if (spawn) {
+            mPatcher.registerClient(clientName);
+        } else {
+            mPatcher.unregisterClient(clientName);
+        }
+    }
 }
+#endif  // __NO_JACK__
 
 void UdpHubListener::stopAllThreads()
 {
@@ -536,7 +646,7 @@ void UdpHubListener::stopAllThreads()
             iterator.next();
         }
     }
-    mThreadPool.waitForDone();
 }
 // TODO:
-// USE bool QAbstractSocket::isValid () const to check if socket is connect. if not, exit loop
+// USE bool QAbstractSocket::isValid () const to check if socket is connect. if not, exit
+// loop
index 763cfea2f94518669e3e83413974bcf6e18ecbdc..e0208fa48a5ad9a35abc058ab2c921d84399e611 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
 #ifndef __UDPHUBLISTENER_H__
 #define __UDPHUBLISTENER_H__
 
-#include <iostream>
-#include <stdexcept>
-#include <fstream>
-
+#include <QHostAddress>
+#include <QMutex>
 #include <QThread>
 #include <QThreadPool>
 #include <QUdpSocket>
-#include <QHostAddress>
-#include <QTcpSocket>
-#include <QTcpServer>
-#include <QMutex>
+#include <fstream>
+#include <iostream>
+#include <stdexcept>
 
 #include "JackTrip.h"
-#include "jacktrip_types.h"
 #include "jacktrip_globals.h"
-class JackTripWorker; // forward declaration
-class Settings;
+#include "jacktrip_types.h"
+#ifndef __NO_JACK__
+#include "Patcher.h"
+#endif
+#include "Auth.h"
+#include "SslServer.h"
 
-typedef struct {
-    QString address;
-    int16_t port;
-} addressPortPair;
+class JackTripWorker;  // forward declaration
+class Settings;
 
 /** \brief Hub UDP listener on the Server.
  *
@@ -70,7 +68,7 @@ class UdpHubListener : public QObject
 {
     Q_OBJECT;
 
-public:
+   public:
     UdpHubListener(int server_port = gServerUdpPort, int server_udp_port = 0);
     virtual ~UdpHubListener();
 
@@ -80,83 +78,112 @@ public:
     /// \brief Stops the execution of the Thread
     void stop() { mStopped = true; }
 
+#ifndef __NO_JACK__
+    void registerClientWithPatcher(QString& clientName);
+    void unregisterClientWithPatcher(QString& clientName);
+#endif
     int releaseThread(int id);
+    void releaseDuplicateThreads(JackTripWorker* worker, uint16_t actual_peer_port);
 
-    void setConnectDefaultAudioPorts(bool connectDefaultAudioPorts) { m_connectDefaultAudioPorts = connectDefaultAudioPorts; }
-    
-    static void sigIntHandler(__attribute__((unused)) int unused)
-    { std::cout << std::endl << "Shutting Down..." << std::endl; sSigInt = true; }
+    void setConnectDefaultAudioPorts(bool connectDefaultAudioPorts)
+    {
+        // Only allow us to override this in the default patching mode. (Or TUB mode.)
+        //(Allows -D to continue to function as a synonym for -p5.)
+        if (mHubPatch == JackTrip::SERVERTOCLIENT
+            || mHubPatch == JackTrip::RESERVEDMATRIX) {
+            m_connectDefaultAudioPorts = connectDefaultAudioPorts;
+        }
+    }
 
-private slots:
+    static void sigIntHandler([[maybe_unused]] int unused)
+    {
+        std::cout << std::endl << "Shutting Down..." << std::endl;
+        sSigInt = true;
+    }
+
+   private slots:
     void testReceive()
-    { std::cout << "========= TEST RECEIVE SLOT ===========" << std::endl; }
+    {
+        std::cout << "========= TEST RECEIVE SLOT ===========" << std::endl;
+    }
     void receivedNewConnection();
     void stopCheck();
 
-signals:
+   signals:
     void Listening();
     void ClientAddressSet();
     void signalRemoveThread(int id);
     void signalStopped();
-    void signalError(const QString &errorMessage);
+    void signalError(const QStringerrorMessage);
 
-private:
+   private:
     /** \brief Binds a QUdpSocket. It chooses the available (active) interface.
-   * \param udpsocket a QUdpSocket
-   * \param port Port number
-   */
-    void receivedClientInfo(QTcpSocket *clientConnection);
+     * \param udpsocket a QUdpSocket
+     * \param port Port number
+     */
+    void receivedClientInfo(QSslSocket* clientConnection);
 
     static void bindUdpSocket(QUdpSocket& udpsocket, int port);
 
-    uint16_t readClientUdpPort(QTcpSocket* clientConnection, QString &clientName);
-    int sendUdpPort(QTcpSocket* clientConnection, int udp_port);
-
-
-    /** \brief Send the JackTripWorker to the thread pool. This will run
-   * until it's done. We still have control over the prototype class.
-   * \param id Identification Number
-   */
-    //void sendToPoolPrototype(int id);
-
-    /** \brief Check if address is already handled, if not add to array
-   * \param address as string (IPv4 or IPv6)
-   * \return -1 if address is busy, id number if not
-   */
-    int isNewAddress(QString address, uint16_t port);
+    int readClientUdpPort(QSslSocket* clientConnection, QString& clientName);
+    int checkAuthAndReadPort(QSslSocket* clientConnection, QString& clientName);
+    int sendUdpPort(QSslSocket* clientConnection, qint32 udp_port);
+
+    /**
+     * \brief Send the JackTripWorker to the thread pool. This will run
+     * until it's done. We still have control over the prototype class.
+     * \param id Identification Number
+     */
+    // void sendToPoolPrototype(int id);
+
+    /**
+     * \brief Check if address is already handled and reuse or create
+     * a JackTripWorker as appropriate
+     * \param address as string (IPv4 or IPv6)
+     * \return id number of JackTripWorker
+     */
+    int getJackTripWorker(QString address, uint16_t port, QString& clientName);
 
     /** \brief Returns the ID of the client in the pool. If the client
-    * is not in the pool yet, returns -1.
-    */
+     * is not in the pool yet, returns -1.
+     */
     int getPoolID(QString address, uint16_t port);
-    
+
     void stopAllThreads();
 
-    //QUdpSocket mUdpHubSocket; ///< The UDP socket
-    //QHostAddress mPeerAddress; ///< The Peer Address
+    // QUdpSocket mUdpHubSocket; ///< The UDP socket
+    // QHostAddress mPeerAddress; ///< The Peer Address
 
-    //JackTripWorker* mJTWorker; ///< Class that will be used as prototype
-    QVector<JackTripWorker*>* mJTWorkers; ///< Vector of JackTripWorker s
-    QThreadPool mThreadPool; ///< The Thread Pool
+    // JackTripWorker* mJTWorker; ///< Class that will be used as prototype
+    QVector<JackTripWorker*>* mJTWorkers;  ///< Vector of JackTripWorkers
 
-    QTcpServer mTcpServer;
-    int mServerPort; //< Server known port number
-    int mServerUdpPort; //< Server udp base port number
+    SslServer mTcpServer;
+    int mServerPort;     //< Server known port number
+    int mServerUdpPort;  //< Server udp base port number
     int mBasePort;
-    addressPortPair mActiveAddress[gMaxThreads]; ///< Active address pool addresses
-    QHash<QString, uint16_t> mActiveAddressPortPair;
+    // addressPortNameTriple mActiveAddress[gMaxThreads]; ///< Active address pool
+    // addresses QHash<QString, uint16_t> mActiveAddressPortPair;
+
+    bool mRequireAuth;
+    QString mCertFile;
+    QString mKeyFile;
+    QString mCredsFile;
+    QScopedPointer<Auth> mAuth;
 
     /// Boolean stop the execution of the thread
     volatile bool mStopped;
     static bool sSigInt;
     QTimer mStopCheckTimer;
-    int mTotalRunningThreads; ///< Number of Threads running in the pool
+    int mTotalRunningThreads;  ///< Number of Threads running in the pool
     QMutex mMutex;
     JackTrip::underrunModeT mUnderRunMode;
     int mBufferQueueLength;
-    
+
     QStringList mHubPatchDescriptions;
     bool m_connectDefaultAudioPorts;
+#ifndef __NO_JACK__
+    Patcher mPatcher;
+#endif
 
     int mIOStatTimeout;
     QSharedPointer<std::ofstream> mIOStatStream;
@@ -167,38 +194,67 @@ private:
     double mSimulatedJitterRate;
     double mSimulatedDelayRel;
     bool mUseRtUdpPriority;
-    
-#ifdef WAIR // wair
+
+#ifdef WAIR  // wair
     bool mWAIR;
     void connectMesh(bool spawn);
     void enumerateRunningThreadIDs();
-public :
-    void setWAIR(int b) {mWAIR = b;}
-    bool isWAIR() {return mWAIR;}
-#endif // endwhere
-    void connectPatch(bool spawn);
-public :
+
+   public:
+    void setWAIR(int b) { mWAIR = b; }
+    bool isWAIR() { return mWAIR; }
+#endif  // endwhere
+#ifndef __NO_JACK__
+    void connectPatch(bool spawn, const QString& clientName);
+#endif
+
+   public:
+    void setRequireAuth(bool requireAuth) { mRequireAuth = requireAuth; }
+    void setCertFile(QString certFile) { mCertFile = certFile; }
+    void setKeyFile(QString keyFile) { mKeyFile = keyFile; }
+    void setCredsFile(QString credsFile) { mCredsFile = credsFile; }
+
     unsigned int mHubPatch;
-    void setHubPatch(unsigned int p) {mHubPatch = p;}
-    unsigned int getHubPatch() {return mHubPatch;}
+    void setHubPatch(unsigned int p)
+    {
+        mHubPatch = p;
+#ifndef __NO_JACK__
+        mPatcher.setPatchMode(static_cast<JackTrip::hubConnectionModeT>(p));
+#endif
+        // Set the correct audio port connection setting for our chosen patch mode.
+        if (mHubPatch == JackTrip::SERVERTOCLIENT) {
+            m_connectDefaultAudioPorts = true;
+        } else {
+            m_connectDefaultAudioPorts = false;
+        }
+    }
+    unsigned int getHubPatch() { return mHubPatch; }
+
+    void setUnderRunMode(JackTrip::underrunModeT UnderRunMode)
+    {
+        mUnderRunMode = UnderRunMode;
+    }
+    void setBufferQueueLength(int BufferQueueLength)
+    {
+        mBufferQueueLength = BufferQueueLength;
+    }
 
-    void setUnderRunMode(JackTrip::underrunModeT UnderRunMode) { mUnderRunMode = UnderRunMode; }
-    void setBufferQueueLength(int BufferQueueLength) { mBufferQueueLength = BufferQueueLength; }
-    
     void setIOStatTimeout(int timeout) { mIOStatTimeout = timeout; }
-    void setIOStatStream(QSharedPointer<std::ofstream> statStream) { mIOStatStream = statStream; }
+    void setIOStatStream(QSharedPointer<std::ofstream> statStream)
+    {
+        mIOStatStream = statStream;
+    }
 
     void setBufferStrategy(int BufferStrategy) { mBufferStrategy = BufferStrategy; }
     void setNetIssuesSimulation(double loss, double jitter, double delay_rel)
     {
-        mSimulatedLossRate = loss;
+        mSimulatedLossRate   = loss;
         mSimulatedJitterRate = jitter;
-        mSimulatedDelayRel = delay_rel;
+        mSimulatedDelayRel   = delay_rel;
     }
-    void setBroadcast(int broadcast_queue) {mBroadcastQueue = broadcast_queue;}
-    void setUseRtUdpPriority(bool use) {mUseRtUdpPriority = use;}
-
+    void setBroadcast(int broadcast_queue) { mBroadcastQueue = broadcast_queue; }
+    void setUseRtUdpPriority(bool use) { mUseRtUdpPriority = use; }
+    bool mAppendThreadID = false;
 };
 
-
-#endif //__UDPHUBLISTENER_H__
+#endif  //__UDPHUBLISTENER_H__
index 65ce621754cc119a2448446667377f5d5aaf850a..5d361427bd6b3aa0876d8069323cca9992805fd3 100755 (executable)
--- a/src/build
+++ b/src/build
@@ -1,44 +1,20 @@
 #!/bin/bash
-## Created by Juan-Pablo Caceres
-
-# Check for Platform
-platform='unknown'
-unamestr=`uname`
-if [[ "$unamestr" == 'Linux' ]]; then
-    echo "Building on Linux"
-    platform='linux'
-elif [[ "$unamestr" == 'Darwin' ]]; then
-    echo "Building on Mac OS X"
-    platform='macosx'
-fi
-
-# Set qmake command name
-if [[ $platform == 'linux' ]]; then
-    if hash qmake-qt5 2>/dev/null; then
-       echo "Using qmake-qt5"
-       QCMD=qmake-qt5
-    elif hash qmake 2>/dev/null; then #in case qt was compiled by user
-       echo "Using qmake"
-       QCMD=qmake
-    fi
-    QSPEC=linux-g++
-elif [[ $platform == 'macosx' ]]; then
-    QCMD=qmake
-    QSPEC=macx-clang
-fi
-
-# Build
-mkdir -p ../builddir
-cd ../builddir
-if [[ $1 == 'nojack' ]]; then
-    echo "Building without Jack"
-    $QCMD -spec $QSPEC -config nojack ../src/jacktrip.pro
-    make clean
-    $QCMD -spec $QSPEC -config nojack ../src/jacktrip.pro
-    make release
-else
-    $QCMD -spec $QSPEC ../src/jacktrip.pro $@
-    make clean
-    $QCMD -spec $QSPEC ../src/jacktrip.pro $@
-    make release
+if [[ -t 1 ]]; then
+       echo
+       echo -e "\033[1;31mIMPORTANT\033[0m"
+       echo "The build script is now located in the root jacktrip folder and should"
+       echo "be run from there in future. (This script will eventually be removed and"
+       echo "is included for compatability during the transition.)"
+       echo
+       echo "In future, after cloning the repository with git use the following commands:"
+       echo -e "\033[1m$ cd jacktrip"
+       echo "$ ./build"
+       echo -e "$ cd builddir\033[0m"
+       echo
+       echo "This will build jacktrip and take you to the build directory."
+       echo
+       read -n1 -rsp "Press any key to continue the build process..."
+       echo
 fi
+cd ../
+./build $@
index 26b37ac06600342282402a30ae958c5fddac4ffb..556b8a56c4525071ab854d53e5bd61f63edfa78f 100644 (file)
@@ -7,8 +7,8 @@ Code generated with Faust 2.28.6 (https://faust.grame.fr)
 Compilation options: -lang cpp -inpl -scal -ftz 0
 ------------------------------------------------------------ */
 
-#ifndef  __compressordsp_H__
-#define  __compressordsp_H__
+#ifndef __compressordsp_H__
+#define __compressordsp_H__
 
 // NOTE: ANY INCLUDE-GUARD HERE MUST BE DERIVED FROM THE CLASS NAME
 //
@@ -26,15 +26,15 @@ Compilation options: -lang cpp -inpl -scal -ftz 0
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -59,165 +59,177 @@ struct Meta;
  */
 
 struct dsp_memory_manager {
-    
     virtual ~dsp_memory_manager() {}
-    
+
     virtual void* allocate(size_t size) = 0;
-    virtual void destroy(void* ptr) = 0;
-    
+    virtual void destroy(void* ptr)     = 0;
 };
 
 /**
-* Signal processor definition.
-*/
-
-class dsp {
-
-    public:
-
-        dsp() {}
-        virtual ~dsp() {}
-
-        /* Return instance number of audio inputs */
-        virtual int getNumInputs() = 0;
-    
-        /* Return instance number of audio outputs */
-        virtual int getNumOutputs() = 0;
-    
-        /**
-         * Trigger the ui_interface parameter with instance specific calls
-         * to 'openTabBox', 'addButton', 'addVerticalSlider'... in order to build the UI.
-         *
-         * @param ui_interface - the user interface builder
-         */
-        virtual void buildUserInterface(UI* ui_interface) = 0;
-    
-        /* Returns the sample rate currently used by the instance */
-        virtual int getSampleRate() = 0;
-    
-        /**
-         * Global init, calls the following methods:
-         * - static class 'classInit': static tables initialization
-         * - 'instanceInit': constants and instance state initialization
-         *
-         * @param sample_rate - the sampling rate in Hertz
-         */
-        virtual void init(int sample_rate) = 0;
-
-        /**
-         * Init instance state
-         *
-         * @param sample_rate - the sampling rate in Hertz
-         */
-        virtual void instanceInit(int sample_rate) = 0;
-
-        /**
-         * Init instance constant state
-         *
-         * @param sample_rate - the sampling rate in Hertz
-         */
-        virtual void instanceConstants(int sample_rate) = 0;
-    
-        /* Init default control parameters values */
-        virtual void instanceResetUserInterface() = 0;
-    
-        /* Init instance state (delay lines...) */
-        virtual void instanceClear() = 0;
-        /**
-         * Return a clone of the instance.
-         *
-         * @return a copy of the instance on success, otherwise a null pointer.
-         */
-        virtual dsp* clone() = 0;
-    
-        /**
-         * Trigger the Meta* parameter with instance specific calls to 'declare' (key, value) metadata.
-         *
-         * @param m - the Meta* meta user
-         */
-        virtual void metadata(Meta* m) = 0;
-    
-        /**
-         * DSP instance computation, to be called with successive in/out audio buffers.
-         *
-         * @param count - the number of frames to compute
-         * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
-         * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
-         *
-         */
-        virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) = 0;
-    
-        /**
-         * DSP instance computation: alternative method to be used by subclasses.
-         *
-         * @param date_usec - the timestamp in microsec given by audio driver.
-         * @param count - the number of frames to compute
-         * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
-         * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
-         *
-         */
-        virtual void compute(double /*date_usec*/, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { compute(count, inputs, outputs); }
-       
+ * Signal processor definition.
+ */
+
+class dsp
+{
+   public:
+    dsp() {}
+    virtual ~dsp() {}
+
+    /* Return instance number of audio inputs */
+    virtual int getNumInputs() = 0;
+
+    /* Return instance number of audio outputs */
+    virtual int getNumOutputs() = 0;
+
+    /**
+     * Trigger the ui_interface parameter with instance specific calls
+     * to 'openTabBox', 'addButton', 'addVerticalSlider'... in order to build the UI.
+     *
+     * @param ui_interface - the user interface builder
+     */
+    virtual void buildUserInterface(UI* ui_interface) = 0;
+
+    /* Returns the sample rate currently used by the instance */
+    virtual int getSampleRate() = 0;
+
+    /**
+     * Global init, calls the following methods:
+     * - static class 'classInit': static tables initialization
+     * - 'instanceInit': constants and instance state initialization
+     *
+     * @param sample_rate - the sampling rate in Hertz
+     */
+    virtual void init(int sample_rate) = 0;
+
+    /**
+     * Init instance state
+     *
+     * @param sample_rate - the sampling rate in Hertz
+     */
+    virtual void instanceInit(int sample_rate) = 0;
+
+    /**
+     * Init instance constant state
+     *
+     * @param sample_rate - the sampling rate in Hertz
+     */
+    virtual void instanceConstants(int sample_rate) = 0;
+
+    /* Init default control parameters values */
+    virtual void instanceResetUserInterface() = 0;
+
+    /* Init instance state (delay lines...) */
+    virtual void instanceClear() = 0;
+
+    /**
+     * Return a clone of the instance.
+     *
+     * @return a copy of the instance on success, otherwise a null pointer.
+     */
+    virtual dsp* clone() = 0;
+
+    /**
+     * Trigger the Meta* parameter with instance specific calls to 'declare' (key, value)
+     * metadata.
+     *
+     * @param m - the Meta* meta user
+     */
+    virtual void metadata(Meta* m) = 0;
+
+    /**
+     * DSP instance computation, to be called with successive in/out audio buffers.
+     *
+     * @param count - the number of frames to compute
+     * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (eiher float, double or quad)
+     * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (eiher float, double or quad)
+     *
+     */
+    virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) = 0;
+
+    /**
+     * DSP instance computation: alternative method to be used by subclasses.
+     *
+     * @param date_usec - the timestamp in microsec given by audio driver.
+     * @param count - the number of frames to compute
+     * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (either float, double or quad)
+     * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (either float, double or quad)
+     *
+     */
+    virtual void compute(double /*date_usec*/, int count, FAUSTFLOAT** inputs,
+                         FAUSTFLOAT** outputs)
+    {
+        compute(count, inputs, outputs);
+    }
 };
 
 /**
  * Generic DSP decorator.
  */
 
-class decorator_dsp : public dsp {
-
-    protected:
-
-        dsp* fDSP;
-
-    public:
-
-        decorator_dsp(dsp* dsp = nullptr):fDSP(dsp) {}
-        virtual ~decorator_dsp() { delete fDSP; }
-
-        virtual int getNumInputs() { return fDSP->getNumInputs(); }
-        virtual int getNumOutputs() { return fDSP->getNumOutputs(); }
-        virtual void buildUserInterface(UI* ui_interface) { fDSP->buildUserInterface(ui_interface); }
-        virtual int getSampleRate() { return fDSP->getSampleRate(); }
-        virtual void init(int sample_rate) { fDSP->init(sample_rate); }
-        virtual void instanceInit(int sample_rate) { fDSP->instanceInit(sample_rate); }
-        virtual void instanceConstants(int sample_rate) { fDSP->instanceConstants(sample_rate); }
-        virtual void instanceResetUserInterface() { fDSP->instanceResetUserInterface(); }
-        virtual void instanceClear() { fDSP->instanceClear(); }
-        virtual decorator_dsp* clone() { return new decorator_dsp(fDSP->clone()); }
-        virtual void metadata(Meta* m) { fDSP->metadata(m); }
-        // Beware: subclasses usually have to overload the two 'compute' methods
-        virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(count, inputs, outputs); }
-        virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(date_usec, count, inputs, outputs); }
-    
+class decorator_dsp : public dsp
+{
+   protected:
+    dsp* fDSP;
+
+   public:
+    decorator_dsp(dsp* dsp = nullptr) : fDSP(dsp) {}
+    virtual ~decorator_dsp() { delete fDSP; }
+
+    virtual int getNumInputs() { return fDSP->getNumInputs(); }
+    virtual int getNumOutputs() { return fDSP->getNumOutputs(); }
+    virtual void buildUserInterface(UI* ui_interface)
+    {
+        fDSP->buildUserInterface(ui_interface);
+    }
+    virtual int getSampleRate() { return fDSP->getSampleRate(); }
+    virtual void init(int sample_rate) { fDSP->init(sample_rate); }
+    virtual void instanceInit(int sample_rate) { fDSP->instanceInit(sample_rate); }
+    virtual void instanceConstants(int sample_rate)
+    {
+        fDSP->instanceConstants(sample_rate);
+    }
+    virtual void instanceResetUserInterface() { fDSP->instanceResetUserInterface(); }
+    virtual void instanceClear() { fDSP->instanceClear(); }
+    virtual decorator_dsp* clone() { return new decorator_dsp(fDSP->clone()); }
+    virtual void metadata(Meta* m) { fDSP->metadata(m); }
+    // Beware: subclasses usually have to overload the two 'compute' methods
+    virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
+    {
+        fDSP->compute(count, inputs, outputs);
+    }
+    virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs,
+                         FAUSTFLOAT** outputs)
+    {
+        fDSP->compute(date_usec, count, inputs, outputs);
+    }
 };
 
 /**
  * DSP factory class.
  */
 
-class dsp_factory {
-    
-    protected:
-    
-        // So that to force sub-classes to use deleteDSPFactory(dsp_factory* factory);
-        virtual ~dsp_factory() {}
-    
-    public:
-    
-        virtual std::string getName() = 0;
-        virtual std::string getSHAKey() = 0;
-        virtual std::string getDSPCode() = 0;
-        virtual std::string getCompileOptions() = 0;
-        virtual std::vector<std::string> getLibraryList() = 0;
-        virtual std::vector<std::string> getIncludePathnames() = 0;
-    
-        virtual dsp* createDSPInstance() = 0;
-    
-        virtual void setMemoryManager(dsp_memory_manager* manager) = 0;
-        virtual dsp_memory_manager* getMemoryManager() = 0;
-    
+class dsp_factory
+{
+   protected:
+    // So that to force sub-classes to use deleteDSPFactory(dsp_factory* factory);
+    virtual ~dsp_factory() {}
+
+   public:
+    virtual std::string getName()                          = 0;
+    virtual std::string getSHAKey()                        = 0;
+    virtual std::string getDSPCode()                       = 0;
+    virtual std::string getCompileOptions()                = 0;
+    virtual std::vector<std::string> getLibraryList()      = 0;
+    virtual std::vector<std::string> getIncludePathnames() = 0;
+
+    virtual dsp* createDSPInstance() = 0;
+
+    virtual void setMemoryManager(dsp_memory_manager* manager) = 0;
+    virtual dsp_memory_manager* getMemoryManager()             = 0;
 };
 
 /**
@@ -226,14 +238,14 @@ class dsp_factory {
  */
 
 #ifdef __SSE__
-    #include <xmmintrin.h>
-    #ifdef __SSE2__
-        #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
-    #else
-        #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
-    #endif
+#include <xmmintrin.h>
+#ifdef __SSE2__
+#define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
+#else
+#define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
+#endif
 #else
-    #define AVOIDDENORMALS
+#define AVOIDDENORMALS
 #endif
 
 #endif
@@ -248,15 +260,15 @@ class dsp_factory {
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -266,11 +278,11 @@ class dsp_factory {
 #ifndef API_UI_H
 #define API_UI_H
 
+#include <iostream>
+#include <map>
 #include <sstream>
 #include <string>
 #include <vector>
-#include <iostream>
-#include <map>
 
 /************************** BEGIN meta.h **************************/
 /************************************************************************
@@ -281,15 +293,15 @@ class dsp_factory {
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -299,11 +311,9 @@ class dsp_factory {
 #ifndef __meta__
 #define __meta__
 
-struct Meta
-{
-    virtual ~Meta() {};
+struct Meta {
+    virtual ~Meta(){};
     virtual void declare(const char* key, const char* value) = 0;
-    
 };
 
 #endif
@@ -317,15 +327,15 @@ struct Meta
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -348,43 +358,47 @@ struct Meta
 
 struct Soundfile;
 
-template <typename REAL>
-struct UIReal
-{
+template<typename REAL>
+struct UIReal {
     UIReal() {}
     virtual ~UIReal() {}
-    
+
     // -- widget's layouts
-    
-    virtual void openTabBox(const char* label) = 0;
+
+    virtual void openTabBox(const char* label)        = 0;
     virtual void openHorizontalBox(const char* label) = 0;
-    virtual void openVerticalBox(const char* label) = 0;
-    virtual void closeBox() = 0;
-    
+    virtual void openVerticalBox(const char* label)   = 0;
+    virtual void closeBox()                           = 0;
+
     // -- active widgets
-    
-    virtual void addButton(const char* label, REAL* zone) = 0;
+
+    virtual void addButton(const char* label, REAL* zone)      = 0;
     virtual void addCheckButton(const char* label, REAL* zone) = 0;
-    virtual void addVerticalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
-    virtual void addHorizontalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
-    virtual void addNumEntry(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
-    
+    virtual void addVerticalSlider(const char* label, REAL* zone, REAL init, REAL min,
+                                   REAL max, REAL step)        = 0;
+    virtual void addHorizontalSlider(const char* label, REAL* zone, REAL init, REAL min,
+                                     REAL max, REAL step)      = 0;
+    virtual void addNumEntry(const char* label, REAL* zone, REAL init, REAL min, REAL max,
+                             REAL step)                        = 0;
+
     // -- passive widgets
-    
-    virtual void addHorizontalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
-    virtual void addVerticalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
-    
+
+    virtual void addHorizontalBargraph(const char* label, REAL* zone, REAL min,
+                                       REAL max) = 0;
+    virtual void addVerticalBargraph(const char* label, REAL* zone, REAL min,
+                                     REAL max)   = 0;
+
     // -- soundfiles
-    
-    virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) = 0;
-    
+
+    virtual void addSoundfile(const char* label, const char* filename,
+                              Soundfile** sf_zone) = 0;
+
     // -- metadata declarations
-    
-    virtual void declare(REAL* zone, const char* key, const char* val) {}
+
+    virtual void declare(REAL* /*zone*/, const char* /*key*/, const char* /*val*/) {}
 };
 
-struct UI : public UIReal<FAUSTFLOAT>
-{
+struct UI : public UIReal<FAUSTFLOAT> {
     UI() {}
     virtual ~UI() {}
 };
@@ -400,15 +414,15 @@ struct UI : public UIReal<FAUSTFLOAT>
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -418,9 +432,9 @@ struct UI : public UIReal<FAUSTFLOAT>
 #ifndef FAUST_PATHBUILDER_H
 #define FAUST_PATHBUILDER_H
 
-#include <vector>
-#include <string>
 #include <algorithm>
+#include <string>
+#include <vector>
 
 /*******************************************************************************
  * PathBuilder : Faust User Interface
@@ -429,37 +443,33 @@ struct UI : public UIReal<FAUSTFLOAT>
 
 class PathBuilder
 {
-
-    protected:
-    
-        std::vector<std::string> fControlsLevel;
-       
-    public:
-    
-        PathBuilder() {}
-        virtual ~PathBuilder() {}
-    
-        std::string buildPath(const std::string& label) 
-        {
-            std::string res = "/";
-            for (size_t i = 0; i < fControlsLevel.size(); i++) {
-                res += fControlsLevel[i];
-                res += "/";
-            }
-            res += label;
-            std::replace(res.begin(), res.end(), ' ', '_');
-            return res;
-        }
-    
-        std::string buildLabel(std::string label)
-        {
-            std::replace(label.begin(), label.end(), ' ', '_');
-            return label;
+   protected:
+    std::vector<std::string> fControlsLevel;
+
+   public:
+    PathBuilder() {}
+    virtual ~PathBuilder() {}
+
+    std::string buildPath(const std::string& label)
+    {
+        std::string res = "/";
+        for (size_t i = 0; i < fControlsLevel.size(); i++) {
+            res += fControlsLevel[i];
+            res += "/";
         }
-    
-        void pushLabel(const std::string& label) { fControlsLevel.push_back(label); }
-        void popLabel() { fControlsLevel.pop_back(); }
-    
+        res += label;
+        std::replace(res.begin(), res.end(), ' ', '_');
+        return res;
+    }
+
+    std::string buildLabel(std::string label)
+    {
+        std::replace(label.begin(), label.end(), ' ', '_');
+        return label;
+    }
+
+    void pushLabel(const std::string& label) { fControlsLevel.push_back(label); }
+    void popLabel() { fControlsLevel.pop_back(); }
 };
 
 #endif  // FAUST_PATHBUILDER_H
@@ -473,15 +483,15 @@ class PathBuilder
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -492,7 +502,7 @@ class PathBuilder
 #define __ValueConverter__
 
 /***************************************************************************************
-                                                               ValueConverter.h
+                                                                ValueConverter.h
                             (GRAME, Copyright 2015-2019)
 
 Set of conversion objects used to map user interface values (for example a gui slider
@@ -502,8 +512,9 @@ delivering values between 0 and 1) to faust values (for example a vslider betwee
 -- Utilities
 
 Range(lo,hi) : clip a value x between lo and hi
-Interpolator(lo,hi,v1,v2) : Maps a value x between lo and hi to a value y between v1 and v2
-Interpolator3pt(lo,mi,hi,v1,vm,v2) : Map values between lo mid hi to values between v1 vm v2
+Interpolator(lo,hi,v1,v2) : Maps a value x between lo and hi to a value y between v1 and
+v2 Interpolator3pt(lo,mi,hi,v1,vm,v2) : Map values between lo mid hi to values between v1
+vm v2
 
 -- Value Converters
 
@@ -534,11 +545,11 @@ ZoneReader(zone, valueConverter) : a zone with a data converter
 
 ****************************************************************************************/
 
-#include <float.h>
-#include <algorithm>    // std::max
+#include <algorithm>  // std::max
+#include <cassert>
+#include <cfloat>
 #include <cmath>
 #include <vector>
-#include <assert.h>
 
 //--------------------------------------------------------------------------------------
 // Interpolator(lo,hi,v1,v2)
@@ -551,50 +562,49 @@ ZoneReader(zone, valueConverter) : a zone with a data converter
 //--------------------------------------------------------------------------------------
 class Interpolator
 {
-    private:
-
-        //--------------------------------------------------------------------------------------
-        // Range(lo,hi) clip a value between lo and hi
-        //--------------------------------------------------------------------------------------
-        struct Range
-        {
-            double fLo;
-            double fHi;
-
-            Range(double x, double y) : fLo(std::min<double>(x,y)), fHi(std::max<double>(x,y)) {}
-            double operator()(double x) { return (x<fLo) ? fLo : (x>fHi) ? fHi : x; }
-        };
-
-
-        Range fRange;
-        double fCoef;
-        double fOffset;
-
-    public:
-
-        Interpolator(double lo, double hi, double v1, double v2) : fRange(lo,hi)
-        {
-            if (hi != lo) {
-                // regular case
-                fCoef = (v2-v1)/(hi-lo);
-                fOffset = v1 - lo*fCoef;
-            } else {
-                // degenerate case, avoids division by zero
-                fCoef = 0;
-                fOffset = (v1+v2)/2;
-            }
-        }
-        double operator()(double v)
+   private:
+    //--------------------------------------------------------------------------------------
+    // Range(lo,hi) clip a value between lo and hi
+    //--------------------------------------------------------------------------------------
+    struct Range {
+        double fLo;
+        double fHi;
+
+        Range(double x, double y)
+            : fLo(std::min<double>(x, y)), fHi(std::max<double>(x, y))
         {
-            double x = fRange(v);
-            return  fOffset + x*fCoef;
         }
-
-        void getLowHigh(double& amin, double& amax)
-        {
-            amin = fRange.fLo;
-            amax = fRange.fHi;
+        double operator()(double x) { return (x < fLo) ? fLo : (x > fHi) ? fHi : x; }
+    };
+
+    Range fRange;
+    double fCoef;
+    double fOffset;
+
+   public:
+    Interpolator(double lo, double hi, double v1, double v2) : fRange(lo, hi)
+    {
+        if (hi != lo) {
+            // regular case
+            fCoef   = (v2 - v1) / (hi - lo);
+            fOffset = v1 - lo * fCoef;
+        } else {
+            // degenerate case, avoids division by zero
+            fCoef   = 0;
+            fOffset = (v1 + v2) / 2;
         }
+    }
+    double operator()(double v)
+    {
+        double x = fRange(v);
+        return fOffset + x * fCoef;
+    }
+
+    void getLowHigh(double& amin, double& amax)
+    {
+        amin = fRange.fLo;
+        amax = fRange.fHi;
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -603,26 +613,23 @@ class Interpolator
 //--------------------------------------------------------------------------------------
 class Interpolator3pt
 {
-
-    private:
-
-        Interpolator fSegment1;
-        Interpolator fSegment2;
-        double fMid;
-
-    public:
-
-        Interpolator3pt(double lo, double mi, double hi, double v1, double vm, double v2) :
-            fSegment1(lo, mi, v1, vm),
-            fSegment2(mi, hi, vm, v2),
-            fMid(mi) {}
-        double operator()(double x) { return  (x < fMid) ? fSegment1(x) : fSegment2(x); }
-
-        void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fSegment1.getLowHigh(amin, amid);
-            fSegment2.getLowHigh(amid, amax);
-        }
+   private:
+    Interpolator fSegment1;
+    Interpolator fSegment2;
+    double fMid;
+
+   public:
+    Interpolator3pt(double lo, double mi, double hi, double v1, double vm, double v2)
+        : fSegment1(lo, mi, v1, vm), fSegment2(mi, hi, vm, v2), fMid(mi)
+    {
+    }
+    double operator()(double x) { return (x < fMid) ? fSegment1(x) : fSegment2(x); }
+
+    void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fSegment1.getLowHigh(amin, amid);
+        fSegment2.getLowHigh(amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -630,62 +637,51 @@ class Interpolator3pt
 //--------------------------------------------------------------------------------------
 class ValueConverter
 {
-
-    public:
-
-        virtual ~ValueConverter() {}
-        virtual double ui2faust(double x) = 0;
-        virtual double faust2ui(double x) = 0;
+   public:
+    virtual ~ValueConverter() {}
+    virtual double ui2faust(double x) = 0;
+    virtual double faust2ui(double x) = 0;
 };
 
 //--------------------------------------------------------------------------------------
 // A converter than can be updated
 //--------------------------------------------------------------------------------------
 
-class UpdatableValueConverter : public ValueConverter {
-    
-    protected:
-        
-        bool fActive;
-        
-    public:
-        
-        UpdatableValueConverter():fActive(true)
-        {}
-        virtual ~UpdatableValueConverter()
-        {}
-        
-        virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max) = 0;
-        virtual void getMappingValues(double& amin, double& amid, double& amax) = 0;
-        
-        void setActive(bool on_off) { fActive = on_off; }
-        bool getActive() { return fActive; }
-    
-};
+class UpdatableValueConverter : public ValueConverter
+{
+   protected:
+    bool fActive;
 
+   public:
+    UpdatableValueConverter() : fActive(true) {}
+    virtual ~UpdatableValueConverter() {}
+
+    virtual void setMappingValues(double amin, double amid, double amax, double min,
+                                  double init, double max)                  = 0;
+    virtual void getMappingValues(double& amin, double& amid, double& amax) = 0;
+
+    void setActive(bool on_off) { fActive = on_off; }
+    bool getActive() { return fActive; }
+};
 
 //--------------------------------------------------------------------------------------
 // Linear conversion between ui and Faust values
 //--------------------------------------------------------------------------------------
 class LinearValueConverter : public ValueConverter
 {
-    
-    private:
-        
-        Interpolator fUI2F;
-        Interpolator fF2UI;
-        
-    public:
-        
-        LinearValueConverter(double umin, double umax, double fmin, double fmax) :
-            fUI2F(umin,umax,fmin,fmax), fF2UI(fmin,fmax,umin,umax)
-        {}
-        
-        LinearValueConverter() : fUI2F(0.,0.,0.,0.), fF2UI(0.,0.,0.,0.)
-        {}
-        virtual double ui2faust(double x) { return fUI2F(x); }
-        virtual double faust2ui(double x) { return fF2UI(x); }
-    
+   private:
+    Interpolator fUI2F;
+    Interpolator fF2UI;
+
+   public:
+    LinearValueConverter(double umin, double umax, double fmin, double fmax)
+        : fUI2F(umin, umax, fmin, fmax), fF2UI(fmin, fmax, umin, umax)
+    {
+    }
+
+    LinearValueConverter() : fUI2F(0., 0., 0., 0.), fF2UI(0., 0., 0., 0.) {}
+    virtual double ui2faust(double x) { return fUI2F(x); }
+    virtual double faust2ui(double x) { return fF2UI(x); }
 };
 
 //--------------------------------------------------------------------------------------
@@ -693,35 +689,35 @@ class LinearValueConverter : public ValueConverter
 //--------------------------------------------------------------------------------------
 class LinearValueConverter2 : public UpdatableValueConverter
 {
-    
-    private:
-    
-        Interpolator3pt fUI2F;
-        Interpolator3pt fF2UI;
-        
-    public:
-    
-        LinearValueConverter2(double amin, double amid, double amax, double min, double init, double max) :
-            fUI2F(amin, amid, amax, min, init, max), fF2UI(min, init, max, amin, amid, amax)
-        {}
-        
-        LinearValueConverter2() : fUI2F(0.,0.,0.,0.,0.,0.), fF2UI(0.,0.,0.,0.,0.,0.)
-        {}
-    
-        virtual double ui2faust(double x) { return fUI2F(x); }
-        virtual double faust2ui(double x) { return fF2UI(x); }
-    
-        virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max)
-        {
-            fUI2F = Interpolator3pt(amin, amid, amax, min, init, max);
-            fF2UI = Interpolator3pt(min, init, max, amin, amid, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fUI2F.getMappingValues(amin, amid, amax);
-        }
-    
+   private:
+    Interpolator3pt fUI2F;
+    Interpolator3pt fF2UI;
+
+   public:
+    LinearValueConverter2(double amin, double amid, double amax, double min, double init,
+                          double max)
+        : fUI2F(amin, amid, amax, min, init, max), fF2UI(min, init, max, amin, amid, amax)
+    {
+    }
+
+    LinearValueConverter2() : fUI2F(0., 0., 0., 0., 0., 0.), fF2UI(0., 0., 0., 0., 0., 0.)
+    {
+    }
+
+    virtual double ui2faust(double x) { return fUI2F(x); }
+    virtual double faust2ui(double x) { return fF2UI(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double min,
+                                  double init, double max)
+    {
+        fUI2F = Interpolator3pt(amin, amid, amax, min, init, max);
+        fF2UI = Interpolator3pt(min, init, max, amin, amid, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fUI2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -729,16 +725,21 @@ class LinearValueConverter2 : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class LogValueConverter : public LinearValueConverter
 {
-
-    public:
-
-        LogValueConverter(double umin, double umax, double fmin, double fmax) :
-            LinearValueConverter(umin, umax, std::log(std::max<double>(DBL_MIN, fmin)), std::log(std::max<double>(DBL_MIN, fmax)))
-        {}
-
-        virtual double ui2faust(double x) { return std::exp(LinearValueConverter::ui2faust(x)); }
-        virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::log(std::max<double>(x, DBL_MIN))); }
-
+   public:
+    LogValueConverter(double umin, double umax, double fmin, double fmax)
+        : LinearValueConverter(umin, umax, std::log(std::max<double>(DBL_MIN, fmin)),
+                               std::log(std::max<double>(DBL_MIN, fmax)))
+    {
+    }
+
+    virtual double ui2faust(double x)
+    {
+        return std::exp(LinearValueConverter::ui2faust(x));
+    }
+    virtual double faust2ui(double x)
+    {
+        return LinearValueConverter::faust2ui(std::log(std::max<double>(x, DBL_MIN)));
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -746,16 +747,21 @@ class LogValueConverter : public LinearValueConverter
 //--------------------------------------------------------------------------------------
 class ExpValueConverter : public LinearValueConverter
 {
-
-    public:
-
-        ExpValueConverter(double umin, double umax, double fmin, double fmax) :
-            LinearValueConverter(umin, umax, std::min<double>(DBL_MAX, std::exp(fmin)), std::min<double>(DBL_MAX, std::exp(fmax)))
-        {}
-
-        virtual double ui2faust(double x) { return std::log(LinearValueConverter::ui2faust(x)); }
-        virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::min<double>(DBL_MAX, std::exp(x))); }
-
+   public:
+    ExpValueConverter(double umin, double umax, double fmin, double fmax)
+        : LinearValueConverter(umin, umax, std::min<double>(DBL_MAX, std::exp(fmin)),
+                               std::min<double>(DBL_MAX, std::exp(fmax)))
+    {
+    }
+
+    virtual double ui2faust(double x)
+    {
+        return std::log(LinearValueConverter::ui2faust(x));
+    }
+    virtual double faust2ui(double x)
+    {
+        return LinearValueConverter::faust2ui(std::min<double>(DBL_MAX, std::exp(x)));
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -764,34 +770,34 @@ class ExpValueConverter : public LinearValueConverter
 //--------------------------------------------------------------------------------------
 class AccUpConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt fA2F;
-        Interpolator3pt fF2A;
-
-    public:
-
-        AccUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmin,fmid,fmax),
-            fF2A(fmin,fmid,fmax,amin,amid,amax)
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-            //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmin, fmid, fmax);
-            fF2A = Interpolator3pt(fmin, fmid, fmax, amin, amid, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
-
+   private:
+    Interpolator3pt fA2F;
+    Interpolator3pt fF2A;
+
+   public:
+    AccUpConverter(double amin, double amid, double amax, double fmin, double fmid,
+                   double fmax)
+        : fA2F(amin, amid, amax, fmin, fmid, fmax)
+        , fF2A(fmin, fmid, fmax, amin, amid, amax)
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double fmid, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpConverter update %f %f %f
+        //%f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmin, fmid, fmax);
+        fF2A = Interpolator3pt(fmin, fmid, fmax, amin, amid, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -800,33 +806,34 @@ class AccUpConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class AccDownConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt        fA2F;
-        Interpolator3pt        fF2A;
-
-    public:
-
-        AccDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmax,fmid,fmin),
-            fF2A(fmin,fmid,fmax,amax,amid,amin)
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-             //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmax, fmid, fmin);
-            fF2A = Interpolator3pt(fmin, fmid, fmax, amax, amid, amin);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
+   private:
+    Interpolator3pt fA2F;
+    Interpolator3pt fF2A;
+
+   public:
+    AccDownConverter(double amin, double amid, double amax, double fmin, double fmid,
+                     double fmax)
+        : fA2F(amin, amid, amax, fmax, fmid, fmin)
+        , fF2A(fmin, fmid, fmax, amax, amid, amin)
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double fmid, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownConverter update %f %f
+        //%f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmax, fmid, fmin);
+        fF2A = Interpolator3pt(fmin, fmid, fmax, amax, amid, amin);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -835,33 +842,35 @@ class AccDownConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class AccUpDownConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt        fA2F;
-        Interpolator fF2A;
-
-    public:
-
-        AccUpDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmin,fmax,fmin),
-            fF2A(fmin,fmax,amin,amax)                          // Special, pseudo inverse of a non monotonic function
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-            //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmin, fmax, fmin);
-            fF2A = Interpolator(fmin, fmax, amin, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
+   private:
+    Interpolator3pt fA2F;
+    Interpolator fF2A;
+
+   public:
+    AccUpDownConverter(double amin, double amid, double amax, double fmin,
+                       double /*fmid*/, double fmax)
+        : fA2F(amin, amid, amax, fmin, fmax, fmin)
+        , fF2A(fmin, fmax, amin,
+               amax)  // Special, pseudo inverse of a non monotonic function
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double /*fmid*/, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpDownConverter update %f %f
+        //%f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmin, fmax, fmin);
+        fF2A = Interpolator(fmin, fmax, amin, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -870,33 +879,35 @@ class AccUpDownConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class AccDownUpConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt        fA2F;
-        Interpolator fF2A;
-
-    public:
-
-        AccDownUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmax,fmin,fmax),
-            fF2A(fmin,fmax,amin,amax)                          // Special, pseudo inverse of a non monotonic function
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-            //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmax, fmin, fmax);
-            fF2A = Interpolator(fmin, fmax, amin, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
+   private:
+    Interpolator3pt fA2F;
+    Interpolator fF2A;
+
+   public:
+    AccDownUpConverter(double amin, double amid, double amax, double fmin,
+                       double /*fmid*/, double fmax)
+        : fA2F(amin, amid, amax, fmax, fmin, fmax)
+        , fF2A(fmin, fmax, amin,
+               amax)  // Special, pseudo inverse of a non monotonic function
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double /*fmid*/, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownUpConverter update %f %f
+        //%f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmax, fmin, fmax);
+        fF2A = Interpolator(fmin, fmax, amin, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -904,28 +915,28 @@ class AccDownUpConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class ZoneControl
 {
+   protected:
+    FAUSTFLOAT* fZone;
 
-    protected:
-
-        FAUSTFLOAT*    fZone;
-
-    public:
-
-        ZoneControl(FAUSTFLOAT* zone) : fZone(zone) {}
-        virtual ~ZoneControl() {}
+   public:
+    ZoneControl(FAUSTFLOAT* zone) : fZone(zone) {}
+    virtual ~ZoneControl() {}
 
-        virtual void update(double v) const {}
+    virtual void update(double /*v*/) const {}
 
-        virtual void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max) {}
-        virtual void getMappingValues(double& amin, double& amid, double& amax) {}
+    virtual void setMappingValues(int /*curve*/, double /*amin*/, double /*amid*/,
+                                  double /*amax*/, double /*min*/, double /*init*/,
+                                  double /*max*/)
+    {
+    }
+    virtual void getMappingValues(double& /*amin*/, double& /*amid*/, double& /*amax*/) {}
 
-        FAUSTFLOAT* getZone() { return fZone; }
+    FAUSTFLOAT* getZone() { return fZone; }
 
-        virtual void setActive(bool on_off) {}
-        virtual bool getActive() { return false; }
-
-        virtual int getCurve() { return -1; }
+    virtual void setActive(bool /*on_off*/) {}
+    virtual bool getActive() { return false; }
 
+    virtual int getCurve() { return -1; }
 };
 
 //--------------------------------------------------------------------------------------
@@ -933,20 +944,22 @@ class ZoneControl
 //--------------------------------------------------------------------------------------
 class ConverterZoneControl : public ZoneControl
 {
-
-    protected:
-
-        ValueConverter* fValueConverter;
-
-    public:
-
-        ConverterZoneControl(FAUSTFLOAT* zone, ValueConverter* converter) : ZoneControl(zone), fValueConverter(converter) {}
-        virtual ~ConverterZoneControl() { delete fValueConverter; } // Assuming fValueConverter is not kept elsewhere...
-
-        virtual void update(double v) const { *fZone = fValueConverter->ui2faust(v); }
-
-        ValueConverter* getConverter() { return fValueConverter; }
-
+   protected:
+    ValueConverter* fValueConverter;
+
+   public:
+    ConverterZoneControl(FAUSTFLOAT* zone, ValueConverter* converter)
+        : ZoneControl(zone), fValueConverter(converter)
+    {
+    }
+    virtual ~ConverterZoneControl()
+    {
+        delete fValueConverter;
+    }  // Assuming fValueConverter is not kept elsewhere...
+
+    virtual void update(double v) const { *fZone = fValueConverter->ui2faust(v); }
+
+    ValueConverter* getConverter() { return fValueConverter; }
 };
 
 //--------------------------------------------------------------------------------------
@@ -955,592 +968,613 @@ class ConverterZoneControl : public ZoneControl
 //--------------------------------------------------------------------------------------
 class CurveZoneControl : public ZoneControl
 {
-
-    private:
-
-        std::vector<UpdatableValueConverter*> fValueConverters;
-        int fCurve;
-
-    public:
-
-        CurveZoneControl(FAUSTFLOAT* zone, int curve, double amin, double amid, double amax, double min, double init, double max) : ZoneControl(zone), fCurve(0)
-        {
-            assert(curve >= 0 && curve <= 3);
-            fValueConverters.push_back(new AccUpConverter(amin, amid, amax, min, init, max));
-            fValueConverters.push_back(new AccDownConverter(amin, amid, amax, min, init, max));
-            fValueConverters.push_back(new AccUpDownConverter(amin, amid, amax, min, init, max));
-            fValueConverters.push_back(new AccDownUpConverter(amin, amid, amax, min, init, max));
-            fCurve = curve;
-        }
-        virtual ~CurveZoneControl()
-        {
-            std::vector<UpdatableValueConverter*>::iterator it;
-            for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
-                delete(*it);
-            }
-        }
-        void update(double v) const { if (fValueConverters[fCurve]->getActive()) *fZone = fValueConverters[fCurve]->ui2faust(v); }
-
-        void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max)
-        {
-            fValueConverters[curve]->setMappingValues(amin, amid, amax, min, init, max);
-            fCurve = curve;
-        }
-
-        void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fValueConverters[fCurve]->getMappingValues(amin, amid, amax);
+   private:
+    std::vector<UpdatableValueConverter*> fValueConverters;
+    int fCurve;
+
+   public:
+    CurveZoneControl(FAUSTFLOAT* zone, int curve, double amin, double amid, double amax,
+                     double min, double init, double max)
+        : ZoneControl(zone), fCurve(0)
+    {
+        assert(curve >= 0 && curve <= 3);
+        fValueConverters.push_back(new AccUpConverter(amin, amid, amax, min, init, max));
+        fValueConverters.push_back(
+            new AccDownConverter(amin, amid, amax, min, init, max));
+        fValueConverters.push_back(
+            new AccUpDownConverter(amin, amid, amax, min, init, max));
+        fValueConverters.push_back(
+            new AccDownUpConverter(amin, amid, amax, min, init, max));
+        fCurve = curve;
+    }
+    virtual ~CurveZoneControl()
+    {
+        std::vector<UpdatableValueConverter*>::iterator it;
+        for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+            delete (*it);
         }
-
-        void setActive(bool on_off)
-        {
-            std::vector<UpdatableValueConverter*>::iterator it;
-            for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
-                (*it)->setActive(on_off);
-            }
+    }
+    void update(double v) const
+    {
+        if (fValueConverters[fCurve]->getActive())
+            *fZone = fValueConverters[fCurve]->ui2faust(v);
+    }
+
+    void setMappingValues(int curve, double amin, double amid, double amax, double min,
+                          double init, double max)
+    {
+        fValueConverters[curve]->setMappingValues(amin, amid, amax, min, init, max);
+        fCurve = curve;
+    }
+
+    void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fValueConverters[fCurve]->getMappingValues(amin, amid, amax);
+    }
+
+    void setActive(bool on_off)
+    {
+        std::vector<UpdatableValueConverter*>::iterator it;
+        for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+            (*it)->setActive(on_off);
         }
+    }
 
-        int getCurve() { return fCurve; }
+    int getCurve() { return fCurve; }
 };
 
 class ZoneReader
 {
+   private:
+    FAUSTFLOAT* fZone;
+    Interpolator fInterpolator;
 
-    private:
+   public:
+    ZoneReader(FAUSTFLOAT* zone, double lo, double hi)
+        : fZone(zone), fInterpolator(lo, hi, 0, 255)
+    {
+    }
 
-        FAUSTFLOAT* fZone;
-        Interpolator fInterpolator;
-
-    public:
-
-        ZoneReader(FAUSTFLOAT* zone, double lo, double hi) : fZone(zone), fInterpolator(lo, hi, 0, 255) {}
-
-        virtual ~ZoneReader() {}
-
-        int getValue()
-        {
-            return (fZone != nullptr) ? int(fInterpolator(*fZone)) : 127;
-        }
+    virtual ~ZoneReader() {}
 
+    int getValue() { return (fZone != nullptr) ? int(fInterpolator(*fZone)) : 127; }
 };
 
 #endif
 /**************************  END  ValueConverter.h **************************/
 
-class APIUI : public PathBuilder, public Meta, public UI
+class APIUI
+    : public PathBuilder
+    , public Meta
+    , public UI
 {
-    public:
-    
-        enum ItemType { kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph };
-  
-    protected:
-    
-        enum { kLin = 0, kLog = 1, kExp = 2 };
-    
-        int fNumParameters;
-        std::vector<std::string> fPaths;
-        std::vector<std::string> fLabels;
-        std::map<std::string, int> fPathMap;
-        std::map<std::string, int> fLabelMap;
-        std::vector<ValueConverter*> fConversion;
-        std::vector<FAUSTFLOAT*> fZone;
-        std::vector<FAUSTFLOAT> fInit;
-        std::vector<FAUSTFLOAT> fMin;
-        std::vector<FAUSTFLOAT> fMax;
-        std::vector<FAUSTFLOAT> fStep;
-        std::vector<ItemType> fItemType;
-        std::vector<std::map<std::string, std::string> > fMetaData;
-        std::vector<ZoneControl*> fAcc[3];
-        std::vector<ZoneControl*> fGyr[3];
-
-        // Screen color control
-        // "...[screencolor:red]..." etc.
-        bool fHasScreenControl;      // true if control screen color metadata
-        ZoneReader* fRedReader;
-        ZoneReader* fGreenReader;
-        ZoneReader* fBlueReader;
-
-        // Current values controlled by metadata
-        std::string fCurrentUnit;
-        int fCurrentScale;
-        std::string fCurrentAcc;
-        std::string fCurrentGyr;
-        std::string fCurrentColor;
-        std::string fCurrentTooltip;
-        std::map<std::string, std::string> fCurrentMetadata;
-    
-        // Add a generic parameter
-        virtual void addParameter(const char* label,
-                                FAUSTFLOAT* zone,
-                                FAUSTFLOAT init,
-                                FAUSTFLOAT min,
-                                FAUSTFLOAT max,
-                                FAUSTFLOAT step,
-                                ItemType type)
-        {
-            std::string path = buildPath(label);
-            fPathMap[path] = fLabelMap[label] = fNumParameters++;
-            fPaths.push_back(path);
-            fLabels.push_back(label);
-            fZone.push_back(zone);
-            fInit.push_back(init);
-            fMin.push_back(min);
-            fMax.push_back(max);
-            fStep.push_back(step);
-            fItemType.push_back(type);
-            
-            // handle scale metadata
-            switch (fCurrentScale) {
-                case kLin:
-                    fConversion.push_back(new LinearValueConverter(0, 1, min, max));
-                    break;
-                case kLog:
-                    fConversion.push_back(new LogValueConverter(0, 1, min, max));
-                    break;
-                case kExp: fConversion.push_back(new ExpValueConverter(0, 1, min, max));
-                    break;
-            }
-            fCurrentScale = kLin;
-            
-            if (fCurrentAcc.size() > 0 && fCurrentGyr.size() > 0) {
-                std::cerr << "warning : 'acc' and 'gyr' metadata used for the same " << label << " parameter !!\n";
-            }
+   public:
+    enum ItemType {
+        kButton = 0,
+        kCheckButton,
+        kVSlider,
+        kHSlider,
+        kNumEntry,
+        kHBargraph,
+        kVBargraph
+    };
+
+   protected:
+    enum { kLin = 0, kLog = 1, kExp = 2 };
+
+    int fNumParameters;
+    std::vector<std::string> fPaths;
+    std::vector<std::string> fLabels;
+    std::map<std::string, int> fPathMap;
+    std::map<std::string, int> fLabelMap;
+    std::vector<ValueConverter*> fConversion;
+    std::vector<FAUSTFLOAT*> fZone;
+    std::vector<FAUSTFLOAT> fInit;
+    std::vector<FAUSTFLOAT> fMin;
+    std::vector<FAUSTFLOAT> fMax;
+    std::vector<FAUSTFLOAT> fStep;
+    std::vector<ItemType> fItemType;
+    std::vector<std::map<std::string, std::string> > fMetaData;
+    std::vector<ZoneControl*> fAcc[3];
+    std::vector<ZoneControl*> fGyr[3];
+
+    // Screen color control
+    // "...[screencolor:red]..." etc.
+    bool fHasScreenControl;  // true if control screen color metadata
+    ZoneReader* fRedReader;
+    ZoneReader* fGreenReader;
+    ZoneReader* fBlueReader;
+
+    // Current values controlled by metadata
+    std::string fCurrentUnit;
+    int fCurrentScale;
+    std::string fCurrentAcc;
+    std::string fCurrentGyr;
+    std::string fCurrentColor;
+    std::string fCurrentTooltip;
+    std::map<std::string, std::string> fCurrentMetadata;
+
+    // Add a generic parameter
+    virtual void addParameter(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                              FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step,
+                              ItemType type)
+    {
+        std::string path = buildPath(label);
+        fPathMap[path] = fLabelMap[label] = fNumParameters++;
+        fPaths.push_back(path);
+        fLabels.push_back(label);
+        fZone.push_back(zone);
+        fInit.push_back(init);
+        fMin.push_back(min);
+        fMax.push_back(max);
+        fStep.push_back(step);
+        fItemType.push_back(type);
+
+        // handle scale metadata
+        switch (fCurrentScale) {
+        case kLin:
+            fConversion.push_back(new LinearValueConverter(0, 1, min, max));
+            break;
+        case kLog:
+            fConversion.push_back(new LogValueConverter(0, 1, min, max));
+            break;
+        case kExp:
+            fConversion.push_back(new ExpValueConverter(0, 1, min, max));
+            break;
+        }
+        fCurrentScale = kLin;
 
-            // handle acc metadata "...[acc : <axe> <curve> <amin> <amid> <amax>]..."
-            if (fCurrentAcc.size() > 0) {
-                std::istringstream iss(fCurrentAcc);
-                int axe, curve;
-                double amin, amid, amax;
-                iss >> axe >> curve >> amin >> amid >> amax;
-
-                if ((0 <= axe) && (axe < 3) &&
-                    (0 <= curve) && (curve < 4) &&
-                    (amin < amax) && (amin <= amid) && (amid <= amax))
-                {
-                    fAcc[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
-                } else {
-                    std::cerr << "incorrect acc metadata : " << fCurrentAcc << std::endl;
-                }
-                fCurrentAcc = "";
-            }
-       
-            // handle gyr metadata "...[gyr : <axe> <curve> <amin> <amid> <amax>]..."
-            if (fCurrentGyr.size() > 0) {
-                std::istringstream iss(fCurrentGyr);
-                int axe, curve;
-                double amin, amid, amax;
-                iss >> axe >> curve >> amin >> amid >> amax;
-
-                if ((0 <= axe) && (axe < 3) &&
-                    (0 <= curve) && (curve < 4) &&
-                    (amin < amax) && (amin <= amid) && (amid <= amax))
-                {
-                    fGyr[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
-                } else {
-                    std::cerr << "incorrect gyr metadata : " << fCurrentGyr << std::endl;
-                }
-                fCurrentGyr = "";
-            }
-        
-            // handle screencolor metadata "...[screencolor:red|green|blue|white]..."
-            if (fCurrentColor.size() > 0) {
-                if ((fCurrentColor == "red") && (fRedReader == 0)) {
-                    fRedReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else if ((fCurrentColor == "green") && (fGreenReader == 0)) {
-                    fGreenReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else if ((fCurrentColor == "blue") && (fBlueReader == 0)) {
-                    fBlueReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else if ((fCurrentColor == "white") && (fRedReader == 0) && (fGreenReader == 0) && (fBlueReader == 0)) {
-                    fRedReader = new ZoneReader(zone, min, max);
-                    fGreenReader = new ZoneReader(zone, min, max);
-                    fBlueReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else {
-                    std::cerr << "incorrect screencolor metadata : " << fCurrentColor << std::endl;
-                }
-            }
-            fCurrentColor = "";
-            
-            fMetaData.push_back(fCurrentMetadata);
-            fCurrentMetadata.clear();
+        if (fCurrentAcc.size() > 0 && fCurrentGyr.size() > 0) {
+            std::cerr << "warning : 'acc' and 'gyr' metadata used for the same " << label
+                      << " parameter !!\n";
         }
 
-        int getZoneIndex(std::vector<ZoneControl*>* table, int p, int val)
-        {
-            FAUSTFLOAT* zone = fZone[p];
-            for (size_t i = 0; i < table[val].size(); i++) {
-                if (zone == table[val][i]->getZone()) return int(i);
+        // handle acc metadata "...[acc : <axe> <curve> <amin> <amid> <amax>]..."
+        if (fCurrentAcc.size() > 0) {
+            std::istringstream iss(fCurrentAcc);
+            int axe, curve;
+            double amin, amid, amax;
+            iss >> axe >> curve >> amin >> amid >> amax;
+
+            if ((0 <= axe) && (axe < 3) && (0 <= curve) && (curve < 4) && (amin < amax)
+                && (amin <= amid) && (amid <= amax)) {
+                fAcc[axe].push_back(
+                    new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
+            } else {
+                std::cerr << "incorrect acc metadata : " << fCurrentAcc << std::endl;
             }
-            return -1;
+            fCurrentAcc = "";
         }
-    
-        void setConverter(std::vector<ZoneControl*>* table, int p, int val, int curve, double amin, double amid, double amax)
-        {
-            int id1 = getZoneIndex(table, p, 0);
-            int id2 = getZoneIndex(table, p, 1);
-            int id3 = getZoneIndex(table, p, 2);
-            
-            // Deactivates everywhere..
-            if (id1 != -1) table[0][id1]->setActive(false);
-            if (id2 != -1) table[1][id2]->setActive(false);
-            if (id3 != -1) table[2][id3]->setActive(false);
-            
-            if (val == -1) { // Means: no more mapping...
-                // So stay all deactivated...
+
+        // handle gyr metadata "...[gyr : <axe> <curve> <amin> <amid> <amax>]..."
+        if (fCurrentGyr.size() > 0) {
+            std::istringstream iss(fCurrentGyr);
+            int axe, curve;
+            double amin, amid, amax;
+            iss >> axe >> curve >> amin >> amid >> amax;
+
+            if ((0 <= axe) && (axe < 3) && (0 <= curve) && (curve < 4) && (amin < amax)
+                && (amin <= amid) && (amid <= amax)) {
+                fGyr[axe].push_back(
+                    new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
             } else {
-                int id4 = getZoneIndex(table, p, val);
-                if (id4 != -1) {
-                    // Reactivate the one we edit...
-                    table[val][id4]->setMappingValues(curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]);
-                    table[val][id4]->setActive(true);
-                } else {
-                    // Allocate a new CurveZoneControl which is 'active' by default
-                    FAUSTFLOAT* zone = fZone[p];
-                    table[val].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]));
-                }
+                std::cerr << "incorrect gyr metadata : " << fCurrentGyr << std::endl;
             }
+            fCurrentGyr = "";
         }
-    
-        void getConverter(std::vector<ZoneControl*>* table, int p, int& val, int& curve, double& amin, double& amid, double& amax)
-        {
-            int id1 = getZoneIndex(table, p, 0);
-            int id2 = getZoneIndex(table, p, 1);
-            int id3 = getZoneIndex(table, p, 2);
-            
-            if (id1 != -1) {
-                val = 0;
-                curve = table[val][id1]->getCurve();
-                table[val][id1]->getMappingValues(amin, amid, amax);
-            } else if (id2 != -1) {
-                val = 1;
-                curve = table[val][id2]->getCurve();
-                table[val][id2]->getMappingValues(amin, amid, amax);
-            } else if (id3 != -1) {
-                val = 2;
-                curve = table[val][id3]->getCurve();
-                table[val][id3]->getMappingValues(amin, amid, amax);
+
+        // handle screencolor metadata "...[screencolor:red|green|blue|white]..."
+        if (fCurrentColor.size() > 0) {
+            if ((fCurrentColor == "red") && (fRedReader == 0)) {
+                fRedReader        = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
+            } else if ((fCurrentColor == "green") && (fGreenReader == 0)) {
+                fGreenReader      = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
+            } else if ((fCurrentColor == "blue") && (fBlueReader == 0)) {
+                fBlueReader       = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
+            } else if ((fCurrentColor == "white") && (fRedReader == 0)
+                       && (fGreenReader == 0) && (fBlueReader == 0)) {
+                fRedReader        = new ZoneReader(zone, min, max);
+                fGreenReader      = new ZoneReader(zone, min, max);
+                fBlueReader       = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
             } else {
-                val = -1; // No mapping
-                curve = 0;
-                amin = -100.;
-                amid = 0.;
-                amax = 100.;
+                std::cerr << "incorrect screencolor metadata : " << fCurrentColor
+                          << std::endl;
             }
         }
+        fCurrentColor = "";
 
-     public:
-    
-        enum Type { kAcc = 0, kGyr = 1, kNoType };
-   
-        APIUI() : fNumParameters(0), fHasScreenControl(false), fRedReader(0), fGreenReader(0), fBlueReader(0), fCurrentScale(kLin)
-        {}
+        fMetaData.push_back(fCurrentMetadata);
+        fCurrentMetadata.clear();
+    }
 
-        virtual ~APIUI()
-        {
-            for (auto& it : fConversion) delete it;
-            for (int i = 0; i < 3; i++) {
-                for (auto& it : fAcc[i]) delete it;
-                for (auto& it : fGyr[i]) delete it;
+    int getZoneIndex(std::vector<ZoneControl*>* table, int p, int val)
+    {
+        FAUSTFLOAT* zone = fZone[p];
+        for (size_t i = 0; i < table[val].size(); i++) {
+            if (zone == table[val][i]->getZone()) return int(i);
+        }
+        return -1;
+    }
+
+    void setConverter(std::vector<ZoneControl*>* table, int p, int val, int curve,
+                      double amin, double amid, double amax)
+    {
+        int id1 = getZoneIndex(table, p, 0);
+        int id2 = getZoneIndex(table, p, 1);
+        int id3 = getZoneIndex(table, p, 2);
+
+        // Deactivates everywhere..
+        if (id1 != -1) table[0][id1]->setActive(false);
+        if (id2 != -1) table[1][id2]->setActive(false);
+        if (id3 != -1) table[2][id3]->setActive(false);
+
+        if (val == -1) {  // Means: no more mapping...
+            // So stay all deactivated...
+        } else {
+            int id4 = getZoneIndex(table, p, val);
+            if (id4 != -1) {
+                // Reactivate the one we edit...
+                table[val][id4]->setMappingValues(curve, amin, amid, amax, fMin[p],
+                                                  fInit[p], fMax[p]);
+                table[val][id4]->setActive(true);
+            } else {
+                // Allocate a new CurveZoneControl which is 'active' by default
+                FAUSTFLOAT* zone = fZone[p];
+                table[val].push_back(new CurveZoneControl(zone, curve, amin, amid, amax,
+                                                          fMin[p], fInit[p], fMax[p]));
             }
-            delete fRedReader;
-            delete fGreenReader;
-            delete fBlueReader;
         }
-    
-        // -- widget's layouts
-
-        virtual void openTabBox(const char* label) { pushLabel(label); }
-        virtual void openHorizontalBox(const char* label) { pushLabel(label); }
-        virtual void openVerticalBox(const char* label) { pushLabel(label); }
-        virtual void closeBox() { popLabel(); }
-
-        // -- active widgets
-
-        virtual void addButton(const char* label, FAUSTFLOAT* zone)
-        {
-            addParameter(label, zone, 0, 0, 1, 1, kButton);
+    }
+
+    void getConverter(std::vector<ZoneControl*>* table, int p, int& val, int& curve,
+                      double& amin, double& amid, double& amax)
+    {
+        int id1 = getZoneIndex(table, p, 0);
+        int id2 = getZoneIndex(table, p, 1);
+        int id3 = getZoneIndex(table, p, 2);
+
+        if (id1 != -1) {
+            val   = 0;
+            curve = table[val][id1]->getCurve();
+            table[val][id1]->getMappingValues(amin, amid, amax);
+        } else if (id2 != -1) {
+            val   = 1;
+            curve = table[val][id2]->getCurve();
+            table[val][id2]->getMappingValues(amin, amid, amax);
+        } else if (id3 != -1) {
+            val   = 2;
+            curve = table[val][id3]->getCurve();
+            table[val][id3]->getMappingValues(amin, amid, amax);
+        } else {
+            val   = -1;  // No mapping
+            curve = 0;
+            amin  = -100.;
+            amid  = 0.;
+            amax  = 100.;
         }
-
-        virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
-        {
-            addParameter(label, zone, 0, 0, 1, 1, kCheckButton);
+    }
+
+   public:
+    enum Type { kAcc = 0, kGyr = 1, kNoType };
+
+    APIUI()
+        : fNumParameters(0)
+        , fHasScreenControl(false)
+        , fRedReader(0)
+        , fGreenReader(0)
+        , fBlueReader(0)
+        , fCurrentScale(kLin)
+    {
+    }
+
+    virtual ~APIUI()
+    {
+        for (auto& it : fConversion) delete it;
+        for (int i = 0; i < 3; i++) {
+            for (auto& it : fAcc[i]) delete it;
+            for (auto& it : fGyr[i]) delete it;
         }
+        delete fRedReader;
+        delete fGreenReader;
+        delete fBlueReader;
+    }
 
-        virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
-        {
-            addParameter(label, zone, init, min, max, step, kVSlider);
-        }
+    // -- widget's layouts
 
-        virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
-        {
-            addParameter(label, zone, init, min, max, step, kHSlider);
-        }
+    virtual void openTabBox(const char* label) { pushLabel(label); }
+    virtual void openHorizontalBox(const char* label) { pushLabel(label); }
+    virtual void openVerticalBox(const char* label) { pushLabel(label); }
+    virtual void closeBox() { popLabel(); }
 
-        virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
-        {
-            addParameter(label, zone, init, min, max, step, kNumEntry);
-        }
+    // -- active widgets
 
-        // -- passive widgets
+    virtual void addButton(const char* label, FAUSTFLOAT* zone)
+    {
+        addParameter(label, zone, 0, 0, 1, 1, kButton);
+    }
+
+    virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
+    {
+        addParameter(label, zone, 0, 0, 1, 1, kCheckButton);
+    }
+
+    virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                                   FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+    {
+        addParameter(label, zone, init, min, max, step, kVSlider);
+    }
+
+    virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                                     FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+    {
+        addParameter(label, zone, init, min, max, step, kHSlider);
+    }
+
+    virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                             FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+    {
+        addParameter(label, zone, init, min, max, step, kNumEntry);
+    }
 
-        virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
-        {
-            addParameter(label, zone, min, min, max, (max-min)/1000.0, kHBargraph);
-        }
+    // -- passive widgets
 
-        virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
-        {
-            addParameter(label, zone, min, min, max, (max-min)/1000.0, kVBargraph);
-        }
-    
-        // -- soundfiles
-    
-        virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) {}
+    virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone,
+                                       FAUSTFLOAT min, FAUSTFLOAT max)
+    {
+        addParameter(label, zone, min, min, max, (max - min) / 1000.0, kHBargraph);
+    }
 
-        // -- metadata declarations
+    virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min,
+                                     FAUSTFLOAT max)
+    {
+        addParameter(label, zone, min, min, max, (max - min) / 1000.0, kVBargraph);
+    }
 
-        virtual void declare(FAUSTFLOAT* zone, const char* key, const char* val)
-        {
-            // Keep metadata
-            fCurrentMetadata[key] = val;
-            
-            if (strcmp(key, "scale") == 0) {
-                if (strcmp(val, "log") == 0) {
-                    fCurrentScale = kLog;
-                } else if (strcmp(val, "exp") == 0) {
-                    fCurrentScale = kExp;
-                } else {
-                    fCurrentScale = kLin;
-                }
-            } else if (strcmp(key, "unit") == 0) {
-                fCurrentUnit = val;
-            } else if (strcmp(key, "acc") == 0) {
-                fCurrentAcc = val;
-            } else if (strcmp(key, "gyr") == 0) {
-                fCurrentGyr = val;
-            } else if (strcmp(key, "screencolor") == 0) {
-                fCurrentColor = val; // val = "red", "green", "blue" or "white"
-            } else if (strcmp(key, "tooltip") == 0) {
-                fCurrentTooltip = val;
-            }
-        }
+    // -- soundfiles
 
-        virtual void declare(const char* key, const char* val)
-        {}
+    virtual void addSoundfile(const char* /*label*/, const char* /*filename*/,
+                              Soundfile** /*sf_zone*/)
+    {
+    }
 
-               //-------------------------------------------------------------------------------
-               // Simple API part
-               //-------------------------------------------------------------------------------
-               int getParamsCount() { return fNumParameters; }
-        int getParamIndex(const char* path)
-        {
-            if (fPathMap.find(path) != fPathMap.end()) {
-                return fPathMap[path];
-            } else if (fLabelMap.find(path) != fLabelMap.end()) {
-                return fLabelMap[path];
-            } else {
-                return -1;
-            }
-        }
-        const char* getParamAddress(int p) { return fPaths[p].c_str(); }
-        const char* getParamLabel(int p) { return fLabels[p].c_str(); }
-        std::map<const char*, const char*> getMetadata(int p)
-        {
-            std::map<const char*, const char*> res;
-            std::map<std::string, std::string> metadata = fMetaData[p];
-            for (auto it : metadata) {
-                res[it.first.c_str()] = it.second.c_str();
-            }
-            return res;
-        }
+    // -- metadata declarations
 
-        const char* getMetadata(int p, const char* key)
-        {
-            return (fMetaData[p].find(key) != fMetaData[p].end()) ? fMetaData[p][key].c_str() : "";
-        }
-        FAUSTFLOAT getParamMin(int p) { return fMin[p]; }
-        FAUSTFLOAT getParamMax(int p) { return fMax[p]; }
-        FAUSTFLOAT getParamStep(int p) { return fStep[p]; }
-        FAUSTFLOAT getParamInit(int p) { return fInit[p]; }
-
-        FAUSTFLOAT* getParamZone(int p) { return fZone[p]; }
-        FAUSTFLOAT getParamValue(int p) { return *fZone[p]; }
-        void setParamValue(int p, FAUSTFLOAT v) { *fZone[p] = v; }
-
-        double getParamRatio(int p) { return fConversion[p]->faust2ui(*fZone[p]); }
-        void setParamRatio(int p, double r) { *fZone[p] = fConversion[p]->ui2faust(r); }
-
-        double value2ratio(int p, double r)    { return fConversion[p]->faust2ui(r); }
-        double ratio2value(int p, double r)    { return fConversion[p]->ui2faust(r); }
-    
-        /**
-         * Return the control type (kAcc, kGyr, or -1) for a given parameter
-         *
-         * @param p - the UI parameter index
-         *
-         * @return the type
-         */
-        Type getParamType(int p)
-        {
-            if (p >= 0) {
-                if (getZoneIndex(fAcc, p, 0) != -1
-                    || getZoneIndex(fAcc, p, 1) != -1
-                    || getZoneIndex(fAcc, p, 2) != -1) {
-                    return kAcc;
-                } else if (getZoneIndex(fGyr, p, 0) != -1
-                           || getZoneIndex(fGyr, p, 1) != -1
-                           || getZoneIndex(fGyr, p, 2) != -1) {
-                    return kGyr;
-                }
-            }
-            return kNoType;
-        }
-    
-        /**
-         * Return the Item type (kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph) for a given parameter
-         *
-         * @param p - the UI parameter index
-         *
-         * @return the Item type
-         */
-        ItemType getParamItemType(int p)
-        {
-            return fItemType[p];
-        }
-   
-        /**
-         * Set a new value coming from an accelerometer, propagate it to all relevant FAUSTFLOAT* zones.
-         *
-         * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
-         * @param value - the new value
-         *
-         */
-        void propagateAcc(int acc, double value)
-        {
-            for (size_t i = 0; i < fAcc[acc].size(); i++) {
-                fAcc[acc][i]->update(value);
-            }
-        }
-    
-        /**
-         * Used to edit accelerometer curves and mapping. Set curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer (-1 means "no mapping")
-         * @param curve - between 0 and 3
-         * @param amin - mapping 'min' point
-         * @param amid - mapping 'middle' point
-         * @param amax - mapping 'max' point
-         *
-         */
-        void setAccConverter(int p, int acc, int curve, double amin, double amid, double amax)
-        {
-            setConverter(fAcc, p, acc, curve, amin, amid, amax);
-        }
-    
-        /**
-         * Used to edit gyroscope curves and mapping. Set curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param acc - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope (-1 means "no mapping")
-         * @param curve - between 0 and 3
-         * @param amin - mapping 'min' point
-         * @param amid - mapping 'middle' point
-         * @param amax - mapping 'max' point
-         *
-         */
-        void setGyrConverter(int p, int gyr, int curve, double amin, double amid, double amax)
-        {
-             setConverter(fGyr, p, gyr, curve, amin, amid, amax);
-        }
-    
-        /**
-         * Used to edit accelerometer curves and mapping. Get curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param acc - the acc value to be retrieved (-1 means "no mapping")
-         * @param curve - the curve value to be retrieved
-         * @param amin - the amin value to be retrieved
-         * @param amid - the amid value to be retrieved
-         * @param amax - the amax value to be retrieved
-         *
-         */
-        void getAccConverter(int p, int& acc, int& curve, double& amin, double& amid, double& amax)
-        {
-            getConverter(fAcc, p, acc, curve, amin, amid, amax);
-        }
+    virtual void declare(FAUSTFLOAT* /*zone*/, const char* key, const char* val)
+    {
+        // Keep metadata
+        fCurrentMetadata[key] = val;
 
-        /**
-         * Used to edit gyroscope curves and mapping. Get curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param gyr - the gyr value to be retrieved (-1 means "no mapping")
-         * @param curve - the curve value to be retrieved
-         * @param amin - the amin value to be retrieved
-         * @param amid - the amid value to be retrieved
-         * @param amax - the amax value to be retrieved
-         *
-         */
-        void getGyrConverter(int p, int& gyr, int& curve, double& amin, double& amid, double& amax)
-        {
-            getConverter(fGyr, p, gyr, curve, amin, amid, amax);
-        }
-    
-        /**
-         * Set a new value coming from an gyroscope, propagate it to all relevant FAUSTFLOAT* zones.
-         *
-         * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
-         * @param value - the new value
-         *
-         */
-        void propagateGyr(int gyr, double value)
-        {
-            for (size_t i = 0; i < fGyr[gyr].size(); i++) {
-                fGyr[gyr][i]->update(value);
+        if (strcmp(key, "scale") == 0) {
+            if (strcmp(val, "log") == 0) {
+                fCurrentScale = kLog;
+            } else if (strcmp(val, "exp") == 0) {
+                fCurrentScale = kExp;
+            } else {
+                fCurrentScale = kLin;
             }
+        } else if (strcmp(key, "unit") == 0) {
+            fCurrentUnit = val;
+        } else if (strcmp(key, "acc") == 0) {
+            fCurrentAcc = val;
+        } else if (strcmp(key, "gyr") == 0) {
+            fCurrentGyr = val;
+        } else if (strcmp(key, "screencolor") == 0) {
+            fCurrentColor = val;  // val = "red", "green", "blue" or "white"
+        } else if (strcmp(key, "tooltip") == 0) {
+            fCurrentTooltip = val;
         }
-    
-        /**
-         * Get the number of FAUSTFLOAT* zones controlled with the accelerometer
-         *
-         * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
-         * @return the number of zones
-         *
-         */
-        int getAccCount(int acc)
-        {
-            return (acc >= 0 && acc < 3) ? int(fAcc[acc].size()) : 0;
-        }
-    
-        /**
-         * Get the number of FAUSTFLOAT* zones controlled with the gyroscope
-         *
-         * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
-         * @param the number of zones
-         *
-         */
-        int getGyrCount(int gyr)
-        {
-            return (gyr >= 0 && gyr < 3) ? int(fGyr[gyr].size()) : 0;
+    }
+
+    virtual void declare(const char* /*key*/, const char* /*val*/) {}
+
+    //-------------------------------------------------------------------------------
+    // Simple API part
+    //-------------------------------------------------------------------------------
+    int getParamsCount() { return fNumParameters; }
+    int getParamIndex(const char* path)
+    {
+        if (fPathMap.find(path) != fPathMap.end()) {
+            return fPathMap[path];
+        } else if (fLabelMap.find(path) != fLabelMap.end()) {
+            return fLabelMap[path];
+        } else {
+            return -1;
         }
-   
-        // getScreenColor() : -1 means no screen color control (no screencolor metadata found)
-        // otherwise return 0x00RRGGBB a ready to use color
-        int getScreenColor()
-        {
-            if (fHasScreenControl) {
-                int r = (fRedReader) ? fRedReader->getValue() : 0;
-                int g = (fGreenReader) ? fGreenReader->getValue() : 0;
-                int b = (fBlueReader) ? fBlueReader->getValue() : 0;
-                return (r<<16) | (g<<8) | b;
-            } else {
-                return -1;
+    }
+    const char* getParamAddress(int p) { return fPaths[p].c_str(); }
+    const char* getParamLabel(int p) { return fLabels[p].c_str(); }
+    std::map<const char*, const char*> getMetadata(int p)
+    {
+        std::map<const char*, const char*> res;
+        std::map<std::string, std::string> metadata = fMetaData[p];
+        for (const auto& it : metadata) { res[it.first.c_str()] = it.second.c_str(); }
+        return res;
+    }
+
+    const char* getMetadata(int p, const char* key)
+    {
+        return (fMetaData[p].find(key) != fMetaData[p].end()) ? fMetaData[p][key].c_str()
+                                                              : "";
+    }
+    FAUSTFLOAT getParamMin(int p) { return fMin[p]; }
+    FAUSTFLOAT getParamMax(int p) { return fMax[p]; }
+    FAUSTFLOAT getParamStep(int p) { return fStep[p]; }
+    FAUSTFLOAT getParamInit(int p) { return fInit[p]; }
+
+    FAUSTFLOAT* getParamZone(int p) { return fZone[p]; }
+    FAUSTFLOAT getParamValue(int p) { return *fZone[p]; }
+    void setParamValue(int p, FAUSTFLOAT v) { *fZone[p] = v; }
+
+    double getParamRatio(int p) { return fConversion[p]->faust2ui(*fZone[p]); }
+    void setParamRatio(int p, double r) { *fZone[p] = fConversion[p]->ui2faust(r); }
+
+    double value2ratio(int p, double r) { return fConversion[p]->faust2ui(r); }
+    double ratio2value(int p, double r) { return fConversion[p]->ui2faust(r); }
+
+    /**
+     * Return the control type (kAcc, kGyr, or -1) for a given parameter
+     *
+     * @param p - the UI parameter index
+     *
+     * @return the type
+     */
+    Type getParamType(int p)
+    {
+        if (p >= 0) {
+            if (getZoneIndex(fAcc, p, 0) != -1 || getZoneIndex(fAcc, p, 1) != -1
+                || getZoneIndex(fAcc, p, 2) != -1) {
+                return kAcc;
+            } else if (getZoneIndex(fGyr, p, 0) != -1 || getZoneIndex(fGyr, p, 1) != -1
+                       || getZoneIndex(fGyr, p, 2) != -1) {
+                return kGyr;
             }
         }
+        return kNoType;
+    }
+
+    /**
+     * Return the Item type (kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry,
+     * kHBargraph, kVBargraph) for a given parameter
+     *
+     * @param p - the UI parameter index
+     *
+     * @return the Item type
+     */
+    ItemType getParamItemType(int p) { return fItemType[p]; }
+
+    /**
+     * Set a new value coming from an accelerometer, propagate it to all relevant
+     * FAUSTFLOAT* zones.
+     *
+     * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+     * @param value - the new value
+     *
+     */
+    void propagateAcc(int acc, double value)
+    {
+        for (size_t i = 0; i < fAcc[acc].size(); i++) { fAcc[acc][i]->update(value); }
+    }
+
+    /**
+     * Used to edit accelerometer curves and mapping. Set curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+     * (-1 means "no mapping")
+     * @param curve - between 0 and 3
+     * @param amin - mapping 'min' point
+     * @param amid - mapping 'middle' point
+     * @param amax - mapping 'max' point
+     *
+     */
+    void setAccConverter(int p, int acc, int curve, double amin, double amid, double amax)
+    {
+        setConverter(fAcc, p, acc, curve, amin, amid, amax);
+    }
+
+    /**
+     * Used to edit gyroscope curves and mapping. Set curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param acc - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope (-1 means "no
+     * mapping")
+     * @param curve - between 0 and 3
+     * @param amin - mapping 'min' point
+     * @param amid - mapping 'middle' point
+     * @param amax - mapping 'max' point
+     *
+     */
+    void setGyrConverter(int p, int gyr, int curve, double amin, double amid, double amax)
+    {
+        setConverter(fGyr, p, gyr, curve, amin, amid, amax);
+    }
+
+    /**
+     * Used to edit accelerometer curves and mapping. Get curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param acc - the acc value to be retrieved (-1 means "no mapping")
+     * @param curve - the curve value to be retrieved
+     * @param amin - the amin value to be retrieved
+     * @param amid - the amid value to be retrieved
+     * @param amax - the amax value to be retrieved
+     *
+     */
+    void getAccConverter(int p, int& acc, int& curve, double& amin, double& amid,
+                         double& amax)
+    {
+        getConverter(fAcc, p, acc, curve, amin, amid, amax);
+    }
+
+    /**
+     * Used to edit gyroscope curves and mapping. Get curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param gyr - the gyr value to be retrieved (-1 means "no mapping")
+     * @param curve - the curve value to be retrieved
+     * @param amin - the amin value to be retrieved
+     * @param amid - the amid value to be retrieved
+     * @param amax - the amax value to be retrieved
+     *
+     */
+    void getGyrConverter(int p, int& gyr, int& curve, double& amin, double& amid,
+                         double& amax)
+    {
+        getConverter(fGyr, p, gyr, curve, amin, amid, amax);
+    }
+
+    /**
+     * Set a new value coming from an gyroscope, propagate it to all relevant FAUSTFLOAT*
+     * zones.
+     *
+     * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+     * @param value - the new value
+     *
+     */
+    void propagateGyr(int gyr, double value)
+    {
+        for (size_t i = 0; i < fGyr[gyr].size(); i++) { fGyr[gyr][i]->update(value); }
+    }
+
+    /**
+     * Get the number of FAUSTFLOAT* zones controlled with the accelerometer
+     *
+     * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+     * @return the number of zones
+     *
+     */
+    int getAccCount(int acc) { return (acc >= 0 && acc < 3) ? int(fAcc[acc].size()) : 0; }
+
+    /**
+     * Get the number of FAUSTFLOAT* zones controlled with the gyroscope
+     *
+     * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+     * @param the number of zones
+     *
+     */
+    int getGyrCount(int gyr) { return (gyr >= 0 && gyr < 3) ? int(fGyr[gyr].size()) : 0; }
+
+    // getScreenColor() : -1 means no screen color control (no screencolor metadata found)
+    // otherwise return 0x00RRGGBB a ready to use color
+    int getScreenColor()
+    {
+        if (fHasScreenControl) {
+            int r = (fRedReader) ? fRedReader->getValue() : 0;
+            int g = (fGreenReader) ? fGreenReader->getValue() : 0;
+            int b = (fBlueReader) ? fBlueReader->getValue() : 0;
+            return (r << 16) | (g << 8) | b;
+        } else {
+            return -1;
+        }
+    }
 };
 
 #endif
@@ -1553,264 +1587,302 @@ class APIUI : public PathBuilder, public Meta, public UI
 //  FAUST Generated Code
 //----------------------------------------------------------------------------
 
-
 #ifndef FAUSTFLOAT
 #define FAUSTFLOAT float
-#endif 
+#endif
 
 #include <algorithm>
 #include <cmath>
-#include <math.h>
 
-
-#ifndef FAUSTCLASS 
+#ifndef FAUSTCLASS
 #define FAUSTCLASS compressordsp
 #endif
 
-#ifdef __APPLE__ 
+#ifdef __APPLE__
 #define exp10f __exp10f
-#define exp10 __exp10
+#define exp10  __exp10
 #endif
 
-class compressordsp : public dsp {
-       
- private:
-       
-       FAUSTFLOAT fCheckbox0;
-       FAUSTFLOAT fHslider0;
-       int fSampleRate;
-       float fConst0;
-       FAUSTFLOAT fHslider1;
-       FAUSTFLOAT fHslider2;
-       FAUSTFLOAT fHslider3;
-       float fRec5[2];
-       float fRec4[2];
-       FAUSTFLOAT fHslider4;
-       float fRec3[2];
-       float fRec2[2];
-       float fRec1[2];
-       float fRec0[2];
-       FAUSTFLOAT fHbargraph0;
-       
- public:
-       
-       void metadata(Meta* m) { 
-               m->declare("analyzers.lib/name", "Faust Analyzer Library");
-               m->declare("analyzers.lib/version", "0.1");
-               m->declare("author", "Julius Smith");
-               m->declare("basics.lib/name", "Faust Basic Element Library");
-               m->declare("basics.lib/version", "0.1");
-               m->declare("compressors.lib/compression_gain_mono:author", "Julius O. Smith III");
-               m->declare("compressors.lib/compression_gain_mono:copyright", "Copyright (C) 2014-2020 by Julius O. Smith III <jos@ccrma.stanford.edu>");
-               m->declare("compressors.lib/compression_gain_mono:license", "MIT-style STK-4.3 license");
-               m->declare("compressors.lib/compressor_lad_mono:author", "Julius O. Smith III");
-               m->declare("compressors.lib/compressor_lad_mono:copyright", "Copyright (C) 2014-2020 by Julius O. Smith III <jos@ccrma.stanford.edu>");
-               m->declare("compressors.lib/compressor_lad_mono:license", "MIT-style STK-4.3 license");
-               m->declare("compressors.lib/compressor_mono:author", "Julius O. Smith III");
-               m->declare("compressors.lib/compressor_mono:copyright", "Copyright (C) 2014-2020 by Julius O. Smith III <jos@ccrma.stanford.edu>");
-               m->declare("compressors.lib/compressor_mono:license", "MIT-style STK-4.3 license");
-               m->declare("compressors.lib/name", "Faust Compressor Effect Library");
-               m->declare("compressors.lib/version", "0.0");
-               m->declare("description", "Compressor demo application, adapted from the Faust Library's dm.compressor_demo in demos.lib");
-               m->declare("documentation", "https://faustlibraries.grame.fr/libs/compressors/#cocompressor_mono");
-               m->declare("filename", "compressordsp.dsp");
-               m->declare("license", "MIT Style STK-4.2");
-               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.3");
-               m->declare("name", "compressor");
-               m->declare("platform.lib/name", "Generic Platform Library");
-               m->declare("platform.lib/version", "0.1");
-               m->declare("signals.lib/name", "Faust Signal Routing Library");
-               m->declare("signals.lib/version", "0.0");
-               m->declare("version", "0.0");
-       }
-
-       virtual int getNumInputs() {
-               return 1;
-       }
-       virtual int getNumOutputs() {
-               return 1;
-       }
-       virtual int getInputRate(int channel) {
-               int rate;
-               switch ((channel)) {
-                       case 0: {
-                               rate = 1;
-                               break;
-                       }
-                       default: {
-                               rate = -1;
-                               break;
-                       }
-               }
-               return rate;
-       }
-       virtual int getOutputRate(int channel) {
-               int rate;
-               switch ((channel)) {
-                       case 0: {
-                               rate = 1;
-                               break;
-                       }
-                       default: {
-                               rate = -1;
-                               break;
-                       }
-               }
-               return rate;
-       }
-       
-       static void classInit(int sample_rate) {
-       }
-       
-       virtual void instanceConstants(int sample_rate) {
-               fSampleRate = sample_rate;
-               fConst0 = (1.0f / std::min<float>(192000.0f, std::max<float>(1.0f, float(fSampleRate))));
-       }
-       
-       virtual void instanceResetUserInterface() {
-               fCheckbox0 = FAUSTFLOAT(0.0f);
-               fHslider0 = FAUSTFLOAT(2.0f);
-               fHslider1 = FAUSTFLOAT(15.0f);
-               fHslider2 = FAUSTFLOAT(2.0f);
-               fHslider3 = FAUSTFLOAT(40.0f);
-               fHslider4 = FAUSTFLOAT(-24.0f);
-       }
-       
-       virtual void instanceClear() {
-               for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) {
-                       fRec5[l0] = 0.0f;
-               }
-               for (int l1 = 0; (l1 < 2); l1 = (l1 + 1)) {
-                       fRec4[l1] = 0.0f;
-               }
-               for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) {
-                       fRec3[l2] = 0.0f;
-               }
-               for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) {
-                       fRec2[l3] = 0.0f;
-               }
-               for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) {
-                       fRec1[l4] = 0.0f;
-               }
-               for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) {
-                       fRec0[l5] = 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 compressordsp* clone() {
-               return new compressordsp();
-       }
-       
-       virtual int getSampleRate() {
-               return fSampleRate;
-       }
-       
-       virtual void buildUserInterface(UI* ui_interface) {
-               ui_interface->declare(0, "tooltip", "References:                 https://faustlibraries.grame.fr/libs/compressors/                 http://en.wikipedia.org/wiki/Dynamic_range_compression");
-               ui_interface->openVerticalBox("COMPRESSOR");
-               ui_interface->declare(0, "0", "");
-               ui_interface->openHorizontalBox("0x00");
-               ui_interface->declare(&fCheckbox0, "0", "");
-               ui_interface->declare(&fCheckbox0, "tooltip", "When this is checked, the compressor                 has no effect");
-               ui_interface->addCheckButton("Bypass", &fCheckbox0);
-               ui_interface->declare(&fHbargraph0, "1", "");
-               ui_interface->declare(&fHbargraph0, "tooltip", "Compressor gain in dB");
-               ui_interface->declare(&fHbargraph0, "unit", "dB");
-               ui_interface->addHorizontalBargraph("Compressor Gain", &fHbargraph0, -50.0f, 10.0f);
-               ui_interface->closeBox();
-               ui_interface->declare(0, "1", "");
-               ui_interface->openHorizontalBox("0x00");
-               ui_interface->declare(0, "3", "");
-               ui_interface->openHorizontalBox("Compression Control");
-               ui_interface->declare(&fHslider2, "0", "");
-               ui_interface->declare(&fHslider2, "style", "knob");
-               ui_interface->declare(&fHslider2, "tooltip", "A compression Ratio of N means that for each N dB increase in input         signal level above Threshold, the output level goes up 1 dB");
-               ui_interface->addHorizontalSlider("Ratio", &fHslider2, 2.0f, 1.0f, 20.0f, 0.100000001f);
-               ui_interface->declare(&fHslider4, "1", "");
-               ui_interface->declare(&fHslider4, "style", "knob");
-               ui_interface->declare(&fHslider4, "tooltip", "When the signal level exceeds the Threshold (in dB), its level         is compressed according to the Ratio");
-               ui_interface->declare(&fHslider4, "unit", "dB");
-               ui_interface->addHorizontalSlider("Threshold", &fHslider4, -24.0f, -100.0f, 10.0f, 0.100000001f);
-               ui_interface->closeBox();
-               ui_interface->declare(0, "4", "");
-               ui_interface->openHorizontalBox("Compression Response");
-               ui_interface->declare(&fHslider1, "1", "");
-               ui_interface->declare(&fHslider1, "scale", "log");
-               ui_interface->declare(&fHslider1, "style", "knob");
-               ui_interface->declare(&fHslider1, "tooltip", "Time constant in ms (1/e smoothing time) for the compression gain         to approach (exponentially) a new lower target level (the compression         `kicking in')");
-               ui_interface->declare(&fHslider1, "unit", "ms");
-               ui_interface->addHorizontalSlider("Attack", &fHslider1, 15.0f, 1.0f, 1000.0f, 0.100000001f);
-               ui_interface->declare(&fHslider3, "2", "");
-               ui_interface->declare(&fHslider3, "scale", "log");
-               ui_interface->declare(&fHslider3, "style", "knob");
-               ui_interface->declare(&fHslider3, "tooltip", "Time constant in ms (1/e smoothing time) for the compression gain         to approach (exponentially) a new higher target level (the compression         'releasing')");
-               ui_interface->declare(&fHslider3, "unit", "ms");
-               ui_interface->addHorizontalSlider("Release", &fHslider3, 40.0f, 1.0f, 1000.0f, 0.100000001f);
-               ui_interface->closeBox();
-               ui_interface->closeBox();
-               ui_interface->declare(&fHslider0, "5", "");
-               ui_interface->declare(&fHslider0, "tooltip", "The compressed-signal output level is increased by this amount         (in dB) to make up for the level lost due to compression");
-               ui_interface->declare(&fHslider0, "unit", "dB");
-               ui_interface->addHorizontalSlider("MakeUpGain", &fHslider0, 2.0f, -96.0f, 96.0f, 0.100000001f);
-               ui_interface->closeBox();
-       }
-       
-       virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
-               FAUSTFLOAT* input0 = inputs[0];
-               FAUSTFLOAT* output0 = outputs[0];
-               int iSlow0 = int(float(fCheckbox0));
-               float fSlow1 = std::pow(10.0f, (0.0500000007f * float(fHslider0)));
-               float fSlow2 = std::max<float>(fConst0, (0.00100000005f * float(fHslider1)));
-               float fSlow3 = (0.5f * fSlow2);
-               int iSlow4 = (std::fabs(fSlow3) < 1.1920929e-07f);
-               float fSlow5 = (iSlow4 ? 0.0f : std::exp((0.0f - (fConst0 / (iSlow4 ? 1.0f : fSlow3)))));
-               float fSlow6 = ((1.0f / std::max<float>(1.00000001e-07f, float(fHslider2))) + -1.0f);
-               int iSlow7 = (std::fabs(fSlow2) < 1.1920929e-07f);
-               float fSlow8 = (iSlow7 ? 0.0f : std::exp((0.0f - (fConst0 / (iSlow7 ? 1.0f : fSlow2)))));
-               float fSlow9 = std::max<float>(fConst0, (0.00100000005f * float(fHslider3)));
-               int iSlow10 = (std::fabs(fSlow9) < 1.1920929e-07f);
-               float fSlow11 = (iSlow10 ? 0.0f : std::exp((0.0f - (fConst0 / (iSlow10 ? 1.0f : fSlow9)))));
-               float fSlow12 = float(fHslider4);
-               float fSlow13 = (1.0f - fSlow5);
-               for (int i = 0; (i < count); i = (i + 1)) {
-                       float fTemp0 = float(input0[i]);
-                       float fTemp1 = (iSlow0 ? 0.0f : fTemp0);
-                       float fTemp2 = std::fabs(fTemp1);
-                       float fTemp3 = ((fRec4[1] > fTemp2) ? fSlow11 : fSlow8);
-                       fRec5[0] = ((fRec5[1] * fTemp3) + (fTemp2 * (1.0f - fTemp3)));
-                       fRec4[0] = fRec5[0];
-                       fRec3[0] = ((fRec3[1] * fSlow5) + (fSlow6 * (std::max<float>(((20.0f * std::log10(fRec4[0])) - fSlow12), 0.0f) * fSlow13)));
-                       float fTemp4 = (fTemp1 * std::pow(10.0f, (0.0500000007f * fRec3[0])));
-                       float fTemp5 = std::fabs(fTemp4);
-                       float fTemp6 = ((fRec1[1] > fTemp5) ? fSlow11 : fSlow8);
-                       fRec2[0] = ((fRec2[1] * fTemp6) + (fTemp5 * (1.0f - fTemp6)));
-                       fRec1[0] = fRec2[0];
-                       fRec0[0] = ((fSlow5 * fRec0[1]) + (fSlow6 * (std::max<float>(((20.0f * std::log10(fRec1[0])) - fSlow12), 0.0f) * fSlow13)));
-                       fHbargraph0 = FAUSTFLOAT((20.0f * std::log10(std::pow(10.0f, (0.0500000007f * fRec0[0])))));
-                       output0[i] = FAUSTFLOAT((iSlow0 ? fTemp0 : (fSlow1 * fTemp4)));
-                       fRec5[1] = fRec5[0];
-                       fRec4[1] = fRec4[0];
-                       fRec3[1] = fRec3[0];
-                       fRec2[1] = fRec2[0];
-                       fRec1[1] = fRec1[0];
-                       fRec0[1] = fRec0[0];
-               }
-       }
-
+class compressordsp : public dsp
+{
+   private:
+    FAUSTFLOAT fCheckbox0;
+    FAUSTFLOAT fHslider0;
+    int fSampleRate;
+    float fConst0;
+    FAUSTFLOAT fHslider1;
+    FAUSTFLOAT fHslider2;
+    FAUSTFLOAT fHslider3;
+    float fRec5[2];
+    float fRec4[2];
+    FAUSTFLOAT fHslider4;
+    float fRec3[2];
+    float fRec2[2];
+    float fRec1[2];
+    float fRec0[2];
+    FAUSTFLOAT fHbargraph0;
+
+   public:
+    void metadata(Meta* m)
+    {
+        m->declare("analyzers.lib/name", "Faust Analyzer Library");
+        m->declare("analyzers.lib/version", "0.1");
+        m->declare("author", "Julius Smith");
+        m->declare("basics.lib/name", "Faust Basic Element Library");
+        m->declare("basics.lib/version", "0.1");
+        m->declare("compressors.lib/compression_gain_mono:author", "Julius O. Smith III");
+        m->declare(
+            "compressors.lib/compression_gain_mono:copyright",
+            "Copyright (C) 2014-2020 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+        m->declare("compressors.lib/compression_gain_mono:license",
+                   "MIT-style STK-4.3 license");
+        m->declare("compressors.lib/compressor_lad_mono:author", "Julius O. Smith III");
+        m->declare(
+            "compressors.lib/compressor_lad_mono:copyright",
+            "Copyright (C) 2014-2020 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+        m->declare("compressors.lib/compressor_lad_mono:license",
+                   "MIT-style STK-4.3 license");
+        m->declare("compressors.lib/compressor_mono:author", "Julius O. Smith III");
+        m->declare(
+            "compressors.lib/compressor_mono:copyright",
+            "Copyright (C) 2014-2020 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+        m->declare("compressors.lib/compressor_mono:license",
+                   "MIT-style STK-4.3 license");
+        m->declare("compressors.lib/name", "Faust Compressor Effect Library");
+        m->declare("compressors.lib/version", "0.0");
+        m->declare("description",
+                   "Compressor demo application, adapted from the Faust Library's "
+                   "dm.compressor_demo in demos.lib");
+        m->declare("documentation",
+                   "https://faustlibraries.grame.fr/libs/compressors/#cocompressor_mono");
+        m->declare("filename", "compressordsp.dsp");
+        m->declare("license", "MIT Style STK-4.2");
+        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.3");
+        m->declare("name", "compressor");
+        m->declare("platform.lib/name", "Generic Platform Library");
+        m->declare("platform.lib/version", "0.1");
+        m->declare("signals.lib/name", "Faust Signal Routing Library");
+        m->declare("signals.lib/version", "0.0");
+        m->declare("version", "0.0");
+    }
+
+    virtual int getNumInputs() { return 1; }
+    virtual int getNumOutputs() { return 1; }
+    virtual int getInputRate(int channel)
+    {
+        int rate;
+        switch ((channel)) {
+        case 0: {
+            rate = 1;
+            break;
+        }
+        default: {
+            rate = -1;
+            break;
+        }
+        }
+        return rate;
+    }
+    virtual int getOutputRate(int channel)
+    {
+        int rate;
+        switch ((channel)) {
+        case 0: {
+            rate = 1;
+            break;
+        }
+        default: {
+            rate = -1;
+            break;
+        }
+        }
+        return rate;
+    }
+
+    static void classInit(int /*sample_rate*/) {}
+
+    virtual void instanceConstants(int sample_rate)
+    {
+        fSampleRate = sample_rate;
+        fConst0 =
+            (1.0f
+             / std::min<float>(192000.0f, std::max<float>(1.0f, float(fSampleRate))));
+    }
+
+    virtual void instanceResetUserInterface()
+    {
+        fCheckbox0 = FAUSTFLOAT(0.0f);
+        fHslider0  = FAUSTFLOAT(2.0f);
+        fHslider1  = FAUSTFLOAT(15.0f);
+        fHslider2  = FAUSTFLOAT(2.0f);
+        fHslider3  = FAUSTFLOAT(40.0f);
+        fHslider4  = FAUSTFLOAT(-24.0f);
+    }
+
+    virtual void instanceClear()
+    {
+        for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec5[l0] = 0.0f; }
+        for (int l1 = 0; (l1 < 2); l1 = (l1 + 1)) { fRec4[l1] = 0.0f; }
+        for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) { fRec3[l2] = 0.0f; }
+        for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) { fRec2[l3] = 0.0f; }
+        for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) { fRec1[l4] = 0.0f; }
+        for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) { fRec0[l5] = 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 compressordsp* clone() { return new compressordsp(); }
+
+    virtual int getSampleRate() { return fSampleRate; }
+
+    virtual void buildUserInterface(UI* ui_interface)
+    {
+        ui_interface->declare(
+            0, "tooltip",
+            "References:                 "
+            "https://faustlibraries.grame.fr/libs/compressors/                 "
+            "http://en.wikipedia.org/wiki/Dynamic_range_compression");
+        ui_interface->openVerticalBox("COMPRESSOR");
+        ui_interface->declare(0, "0", "");
+        ui_interface->openHorizontalBox("0x00");
+        ui_interface->declare(&fCheckbox0, "0", "");
+        ui_interface->declare(
+            &fCheckbox0, "tooltip",
+            "When this is checked, the compressor                 has no effect");
+        ui_interface->addCheckButton("Bypass", &fCheckbox0);
+        ui_interface->declare(&fHbargraph0, "1", "");
+        ui_interface->declare(&fHbargraph0, "tooltip", "Compressor gain in dB");
+        ui_interface->declare(&fHbargraph0, "unit", "dB");
+        ui_interface->addHorizontalBargraph("Compressor Gain", &fHbargraph0, -50.0f,
+                                            10.0f);
+        ui_interface->closeBox();
+        ui_interface->declare(0, "1", "");
+        ui_interface->openHorizontalBox("0x00");
+        ui_interface->declare(0, "3", "");
+        ui_interface->openHorizontalBox("Compression Control");
+        ui_interface->declare(&fHslider2, "0", "");
+        ui_interface->declare(&fHslider2, "style", "knob");
+        ui_interface->declare(
+            &fHslider2, "tooltip",
+            "A compression Ratio of N means that for each N dB increase in input         "
+            "signal level above Threshold, the output level goes up 1 dB");
+        ui_interface->addHorizontalSlider("Ratio", &fHslider2, 2.0f, 1.0f, 20.0f,
+                                          0.100000001f);
+        ui_interface->declare(&fHslider4, "1", "");
+        ui_interface->declare(&fHslider4, "style", "knob");
+        ui_interface->declare(&fHslider4, "tooltip",
+                              "When the signal level exceeds the Threshold (in dB), its "
+                              "level         is compressed according to the Ratio");
+        ui_interface->declare(&fHslider4, "unit", "dB");
+        ui_interface->addHorizontalSlider("Threshold", &fHslider4, -24.0f, -100.0f, 10.0f,
+                                          0.100000001f);
+        ui_interface->closeBox();
+        ui_interface->declare(0, "4", "");
+        ui_interface->openHorizontalBox("Compression Response");
+        ui_interface->declare(&fHslider1, "1", "");
+        ui_interface->declare(&fHslider1, "scale", "log");
+        ui_interface->declare(&fHslider1, "style", "knob");
+        ui_interface->declare(
+            &fHslider1, "tooltip",
+            "Time constant in ms (1/e smoothing time) for the compression gain         "
+            "to approach (exponentially) a new lower target level (the compression       "
+            "  `kicking in')");
+        ui_interface->declare(&fHslider1, "unit", "ms");
+        ui_interface->addHorizontalSlider("Attack", &fHslider1, 15.0f, 1.0f, 1000.0f,
+                                          0.100000001f);
+        ui_interface->declare(&fHslider3, "2", "");
+        ui_interface->declare(&fHslider3, "scale", "log");
+        ui_interface->declare(&fHslider3, "style", "knob");
+        ui_interface->declare(
+            &fHslider3, "tooltip",
+            "Time constant in ms (1/e smoothing time) for the compression gain         "
+            "to approach (exponentially) a new higher target level (the compression      "
+            "   'releasing')");
+        ui_interface->declare(&fHslider3, "unit", "ms");
+        ui_interface->addHorizontalSlider("Release", &fHslider3, 40.0f, 1.0f, 1000.0f,
+                                          0.100000001f);
+        ui_interface->closeBox();
+        ui_interface->closeBox();
+        ui_interface->declare(&fHslider0, "5", "");
+        ui_interface->declare(
+            &fHslider0, "tooltip",
+            "The compressed-signal output level is increased by this amount         (in "
+            "dB) to make up for the level lost due to compression");
+        ui_interface->declare(&fHslider0, "unit", "dB");
+        ui_interface->addHorizontalSlider("MakeUpGain", &fHslider0, 2.0f, -96.0f, 96.0f,
+                                          0.100000001f);
+        ui_interface->closeBox();
+    }
+
+    virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
+    {
+        FAUSTFLOAT* input0  = inputs[0];
+        FAUSTFLOAT* output0 = outputs[0];
+        int iSlow0          = int(float(fCheckbox0));
+        float fSlow1        = std::pow(10.0f, (0.0500000007f * float(fHslider0)));
+        float fSlow2 = std::max<float>(fConst0, (0.00100000005f * float(fHslider1)));
+        float fSlow3 = (0.5f * fSlow2);
+        int iSlow4   = (std::fabs(fSlow3) < 1.1920929e-07f);
+        float fSlow5 =
+            (iSlow4 ? 0.0f : std::exp((0.0f - (fConst0 / (iSlow4 ? 1.0f : fSlow3)))));
+        float fSlow6 =
+            ((1.0f / std::max<float>(1.00000001e-07f, float(fHslider2))) + -1.0f);
+        int iSlow7 = (std::fabs(fSlow2) < 1.1920929e-07f);
+        float fSlow8 =
+            (iSlow7 ? 0.0f : std::exp((0.0f - (fConst0 / (iSlow7 ? 1.0f : fSlow2)))));
+        float fSlow9 = std::max<float>(fConst0, (0.00100000005f * float(fHslider3)));
+        int iSlow10  = (std::fabs(fSlow9) < 1.1920929e-07f);
+        float fSlow11 =
+            (iSlow10 ? 0.0f : std::exp((0.0f - (fConst0 / (iSlow10 ? 1.0f : fSlow9)))));
+        float fSlow12 = float(fHslider4);
+        float fSlow13 = (1.0f - fSlow5);
+        for (int i = 0; (i < count); i = (i + 1)) {
+            float fTemp0 = float(input0[i]);
+            float fTemp1 = (iSlow0 ? 0.0f : fTemp0);
+            float fTemp2 = std::fabs(fTemp1);
+            float fTemp3 = ((fRec4[1] > fTemp2) ? fSlow11 : fSlow8);
+            fRec5[0]     = ((fRec5[1] * fTemp3) + (fTemp2 * (1.0f - fTemp3)));
+            fRec4[0]     = fRec5[0];
+            fRec3[0] =
+                ((fRec3[1] * fSlow5)
+                 + (fSlow6
+                    * (std::max<float>(((20.0f * std::log10(fRec4[0])) - fSlow12), 0.0f)
+                       * fSlow13)));
+            float fTemp4 = (fTemp1 * std::pow(10.0f, (0.0500000007f * fRec3[0])));
+            float fTemp5 = std::fabs(fTemp4);
+            float fTemp6 = ((fRec1[1] > fTemp5) ? fSlow11 : fSlow8);
+            fRec2[0]     = ((fRec2[1] * fTemp6) + (fTemp5 * (1.0f - fTemp6)));
+            fRec1[0]     = fRec2[0];
+            fRec0[0] =
+                ((fSlow5 * fRec0[1])
+                 + (fSlow6
+                    * (std::max<float>(((20.0f * std::log10(fRec1[0])) - fSlow12), 0.0f)
+                       * fSlow13)));
+            fHbargraph0 = FAUSTFLOAT(
+                (20.0f * std::log10(std::pow(10.0f, (0.0500000007f * fRec0[0])))));
+            output0[i] = FAUSTFLOAT((iSlow0 ? fTemp0 : (fSlow1 * fTemp4)));
+            fRec5[1]   = fRec5[0];
+            fRec4[1]   = fRec4[0];
+            fRec3[1]   = fRec3[0];
+            fRec2[1]   = fRec2[0];
+            fRec1[1]   = fRec1[0];
+            fRec0[1]   = fRec0[0];
+        }
+    }
 };
 
 #endif
index 4ccaa5e390730c08e56a89623a18d0d8ed65020f..e6c684fb639af70fd1a8588b790a0fdaad3b2983 100644 (file)
@@ -7,8 +7,8 @@ Code generated with Faust 2.28.6 (https://faust.grame.fr)
 Compilation options: -lang cpp -inpl -scal -ftz 0
 ------------------------------------------------------------ */
 
-#ifndef  __freeverbdsp_H__
-#define  __freeverbdsp_H__
+#ifndef __freeverbdsp_H__
+#define __freeverbdsp_H__
 
 // NOTE: ANY INCLUDE-GUARD HERE MUST BE DERIVED FROM THE CLASS NAME
 //
@@ -26,15 +26,15 @@ Compilation options: -lang cpp -inpl -scal -ftz 0
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -59,165 +59,177 @@ struct Meta;
  */
 
 struct dsp_memory_manager {
-    
     virtual ~dsp_memory_manager() {}
-    
+
     virtual void* allocate(size_t size) = 0;
-    virtual void destroy(void* ptr) = 0;
-    
+    virtual void destroy(void* ptr)     = 0;
 };
 
 /**
-* Signal processor definition.
-*/
-
-class dsp {
-
-    public:
-
-        dsp() {}
-        virtual ~dsp() {}
-
-        /* Return instance number of audio inputs */
-        virtual int getNumInputs() = 0;
-    
-        /* Return instance number of audio outputs */
-        virtual int getNumOutputs() = 0;
-    
-        /**
-         * Trigger the ui_interface parameter with instance specific calls
-         * to 'openTabBox', 'addButton', 'addVerticalSlider'... in order to build the UI.
-         *
-         * @param ui_interface - the user interface builder
-         */
-        virtual void buildUserInterface(UI* ui_interface) = 0;
-    
-        /* Returns the sample rate currently used by the instance */
-        virtual int getSampleRate() = 0;
-    
-        /**
-         * Global init, calls the following methods:
-         * - static class 'classInit': static tables initialization
-         * - 'instanceInit': constants and instance state initialization
-         *
-         * @param sample_rate - the sampling rate in Hertz
-         */
-        virtual void init(int sample_rate) = 0;
-
-        /**
-         * Init instance state
-         *
-         * @param sample_rate - the sampling rate in Hertz
-         */
-        virtual void instanceInit(int sample_rate) = 0;
-
-        /**
-         * Init instance constant state
-         *
-         * @param sample_rate - the sampling rate in Hertz
-         */
-        virtual void instanceConstants(int sample_rate) = 0;
-    
-        /* Init default control parameters values */
-        virtual void instanceResetUserInterface() = 0;
-    
-        /* Init instance state (delay lines...) */
-        virtual void instanceClear() = 0;
-        /**
-         * Return a clone of the instance.
-         *
-         * @return a copy of the instance on success, otherwise a null pointer.
-         */
-        virtual dsp* clone() = 0;
-    
-        /**
-         * Trigger the Meta* parameter with instance specific calls to 'declare' (key, value) metadata.
-         *
-         * @param m - the Meta* meta user
-         */
-        virtual void metadata(Meta* m) = 0;
-    
-        /**
-         * DSP instance computation, to be called with successive in/out audio buffers.
-         *
-         * @param count - the number of frames to compute
-         * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
-         * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
-         *
-         */
-        virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) = 0;
-    
-        /**
-         * DSP instance computation: alternative method to be used by subclasses.
-         *
-         * @param date_usec - the timestamp in microsec given by audio driver.
-         * @param count - the number of frames to compute
-         * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
-         * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
-         *
-         */
-        virtual void compute(double /*date_usec*/, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { compute(count, inputs, outputs); }
-       
+ * Signal processor definition.
+ */
+
+class dsp
+{
+   public:
+    dsp() {}
+    virtual ~dsp() {}
+
+    /* Return instance number of audio inputs */
+    virtual int getNumInputs() = 0;
+
+    /* Return instance number of audio outputs */
+    virtual int getNumOutputs() = 0;
+
+    /**
+     * Trigger the ui_interface parameter with instance specific calls
+     * to 'openTabBox', 'addButton', 'addVerticalSlider'... in order to build the UI.
+     *
+     * @param ui_interface - the user interface builder
+     */
+    virtual void buildUserInterface(UI* ui_interface) = 0;
+
+    /* Returns the sample rate currently used by the instance */
+    virtual int getSampleRate() = 0;
+
+    /**
+     * Global init, calls the following methods:
+     * - static class 'classInit': static tables initialization
+     * - 'instanceInit': constants and instance state initialization
+     *
+     * @param sample_rate - the sampling rate in Hertz
+     */
+    virtual void init(int sample_rate) = 0;
+
+    /**
+     * Init instance state
+     *
+     * @param sample_rate - the sampling rate in Hertz
+     */
+    virtual void instanceInit(int sample_rate) = 0;
+
+    /**
+     * Init instance constant state
+     *
+     * @param sample_rate - the sampling rate in Hertz
+     */
+    virtual void instanceConstants(int sample_rate) = 0;
+
+    /* Init default control parameters values */
+    virtual void instanceResetUserInterface() = 0;
+
+    /* Init instance state (delay lines...) */
+    virtual void instanceClear() = 0;
+
+    /**
+     * Return a clone of the instance.
+     *
+     * @return a copy of the instance on success, otherwise a null pointer.
+     */
+    virtual dsp* clone() = 0;
+
+    /**
+     * Trigger the Meta* parameter with instance specific calls to 'declare' (key, value)
+     * metadata.
+     *
+     * @param m - the Meta* meta user
+     */
+    virtual void metadata(Meta* m) = 0;
+
+    /**
+     * DSP instance computation, to be called with successive in/out audio buffers.
+     *
+     * @param count - the number of frames to compute
+     * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (eiher float, double or quad)
+     * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (eiher float, double or quad)
+     *
+     */
+    virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) = 0;
+
+    /**
+     * DSP instance computation: alternative method to be used by subclasses.
+     *
+     * @param date_usec - the timestamp in microsec given by audio driver.
+     * @param count - the number of frames to compute
+     * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (either float, double or quad)
+     * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (either float, double or quad)
+     *
+     */
+    virtual void compute(double /*date_usec*/, int count, FAUSTFLOAT** inputs,
+                         FAUSTFLOAT** outputs)
+    {
+        compute(count, inputs, outputs);
+    }
 };
 
 /**
  * Generic DSP decorator.
  */
 
-class decorator_dsp : public dsp {
-
-    protected:
-
-        dsp* fDSP;
-
-    public:
-
-        decorator_dsp(dsp* dsp = nullptr):fDSP(dsp) {}
-        virtual ~decorator_dsp() { delete fDSP; }
-
-        virtual int getNumInputs() { return fDSP->getNumInputs(); }
-        virtual int getNumOutputs() { return fDSP->getNumOutputs(); }
-        virtual void buildUserInterface(UI* ui_interface) { fDSP->buildUserInterface(ui_interface); }
-        virtual int getSampleRate() { return fDSP->getSampleRate(); }
-        virtual void init(int sample_rate) { fDSP->init(sample_rate); }
-        virtual void instanceInit(int sample_rate) { fDSP->instanceInit(sample_rate); }
-        virtual void instanceConstants(int sample_rate) { fDSP->instanceConstants(sample_rate); }
-        virtual void instanceResetUserInterface() { fDSP->instanceResetUserInterface(); }
-        virtual void instanceClear() { fDSP->instanceClear(); }
-        virtual decorator_dsp* clone() { return new decorator_dsp(fDSP->clone()); }
-        virtual void metadata(Meta* m) { fDSP->metadata(m); }
-        // Beware: subclasses usually have to overload the two 'compute' methods
-        virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(count, inputs, outputs); }
-        virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(date_usec, count, inputs, outputs); }
-    
+class decorator_dsp : public dsp
+{
+   protected:
+    dsp* fDSP;
+
+   public:
+    decorator_dsp(dsp* dsp = nullptr) : fDSP(dsp) {}
+    virtual ~decorator_dsp() { delete fDSP; }
+
+    virtual int getNumInputs() { return fDSP->getNumInputs(); }
+    virtual int getNumOutputs() { return fDSP->getNumOutputs(); }
+    virtual void buildUserInterface(UI* ui_interface)
+    {
+        fDSP->buildUserInterface(ui_interface);
+    }
+    virtual int getSampleRate() { return fDSP->getSampleRate(); }
+    virtual void init(int sample_rate) { fDSP->init(sample_rate); }
+    virtual void instanceInit(int sample_rate) { fDSP->instanceInit(sample_rate); }
+    virtual void instanceConstants(int sample_rate)
+    {
+        fDSP->instanceConstants(sample_rate);
+    }
+    virtual void instanceResetUserInterface() { fDSP->instanceResetUserInterface(); }
+    virtual void instanceClear() { fDSP->instanceClear(); }
+    virtual decorator_dsp* clone() { return new decorator_dsp(fDSP->clone()); }
+    virtual void metadata(Meta* m) { fDSP->metadata(m); }
+    // Beware: subclasses usually have to overload the two 'compute' methods
+    virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
+    {
+        fDSP->compute(count, inputs, outputs);
+    }
+    virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs,
+                         FAUSTFLOAT** outputs)
+    {
+        fDSP->compute(date_usec, count, inputs, outputs);
+    }
 };
 
 /**
  * DSP factory class.
  */
 
-class dsp_factory {
-    
-    protected:
-    
-        // So that to force sub-classes to use deleteDSPFactory(dsp_factory* factory);
-        virtual ~dsp_factory() {}
-    
-    public:
-    
-        virtual std::string getName() = 0;
-        virtual std::string getSHAKey() = 0;
-        virtual std::string getDSPCode() = 0;
-        virtual std::string getCompileOptions() = 0;
-        virtual std::vector<std::string> getLibraryList() = 0;
-        virtual std::vector<std::string> getIncludePathnames() = 0;
-    
-        virtual dsp* createDSPInstance() = 0;
-    
-        virtual void setMemoryManager(dsp_memory_manager* manager) = 0;
-        virtual dsp_memory_manager* getMemoryManager() = 0;
-    
+class dsp_factory
+{
+   protected:
+    // So that to force sub-classes to use deleteDSPFactory(dsp_factory* factory);
+    virtual ~dsp_factory() {}
+
+   public:
+    virtual std::string getName()                          = 0;
+    virtual std::string getSHAKey()                        = 0;
+    virtual std::string getDSPCode()                       = 0;
+    virtual std::string getCompileOptions()                = 0;
+    virtual std::vector<std::string> getLibraryList()      = 0;
+    virtual std::vector<std::string> getIncludePathnames() = 0;
+
+    virtual dsp* createDSPInstance() = 0;
+
+    virtual void setMemoryManager(dsp_memory_manager* manager) = 0;
+    virtual dsp_memory_manager* getMemoryManager()             = 0;
 };
 
 /**
@@ -226,14 +238,14 @@ class dsp_factory {
  */
 
 #ifdef __SSE__
-    #include <xmmintrin.h>
-    #ifdef __SSE2__
-        #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
-    #else
-        #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
-    #endif
+#include <xmmintrin.h>
+#ifdef __SSE2__
+#define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
+#else
+#define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
+#endif
 #else
-    #define AVOIDDENORMALS
+#define AVOIDDENORMALS
 #endif
 
 #endif
@@ -248,15 +260,15 @@ class dsp_factory {
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -266,11 +278,11 @@ class dsp_factory {
 #ifndef API_UI_H
 #define API_UI_H
 
+#include <iostream>
+#include <map>
 #include <sstream>
 #include <string>
 #include <vector>
-#include <iostream>
-#include <map>
 
 /************************** BEGIN meta.h **************************/
 /************************************************************************
@@ -281,15 +293,15 @@ class dsp_factory {
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -299,11 +311,9 @@ class dsp_factory {
 #ifndef __meta__
 #define __meta__
 
-struct Meta
-{
-    virtual ~Meta() {};
+struct Meta {
+    virtual ~Meta(){};
     virtual void declare(const char* key, const char* value) = 0;
-    
 };
 
 #endif
@@ -317,15 +327,15 @@ struct Meta
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -348,43 +358,47 @@ struct Meta
 
 struct Soundfile;
 
-template <typename REAL>
-struct UIReal
-{
+template<typename REAL>
+struct UIReal {
     UIReal() {}
     virtual ~UIReal() {}
-    
+
     // -- widget's layouts
-    
-    virtual void openTabBox(const char* label) = 0;
+
+    virtual void openTabBox(const char* label)        = 0;
     virtual void openHorizontalBox(const char* label) = 0;
-    virtual void openVerticalBox(const char* label) = 0;
-    virtual void closeBox() = 0;
-    
+    virtual void openVerticalBox(const char* label)   = 0;
+    virtual void closeBox()                           = 0;
+
     // -- active widgets
-    
-    virtual void addButton(const char* label, REAL* zone) = 0;
+
+    virtual void addButton(const char* label, REAL* zone)      = 0;
     virtual void addCheckButton(const char* label, REAL* zone) = 0;
-    virtual void addVerticalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
-    virtual void addHorizontalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
-    virtual void addNumEntry(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
-    
+    virtual void addVerticalSlider(const char* label, REAL* zone, REAL init, REAL min,
+                                   REAL max, REAL step)        = 0;
+    virtual void addHorizontalSlider(const char* label, REAL* zone, REAL init, REAL min,
+                                     REAL max, REAL step)      = 0;
+    virtual void addNumEntry(const char* label, REAL* zone, REAL init, REAL min, REAL max,
+                             REAL step)                        = 0;
+
     // -- passive widgets
-    
-    virtual void addHorizontalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
-    virtual void addVerticalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
-    
+
+    virtual void addHorizontalBargraph(const char* label, REAL* zone, REAL min,
+                                       REAL max) = 0;
+    virtual void addVerticalBargraph(const char* label, REAL* zone, REAL min,
+                                     REAL max)   = 0;
+
     // -- soundfiles
-    
-    virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) = 0;
-    
+
+    virtual void addSoundfile(const char* label, const char* filename,
+                              Soundfile** sf_zone) = 0;
+
     // -- metadata declarations
-    
-    virtual void declare(REAL* zone, const char* key, const char* val) {}
+
+    virtual void declare(REAL* /*zone*/, const char* /*key*/, const char* /*val*/) {}
 };
 
-struct UI : public UIReal<FAUSTFLOAT>
-{
+struct UI : public UIReal<FAUSTFLOAT> {
     UI() {}
     virtual ~UI() {}
 };
@@ -400,15 +414,15 @@ struct UI : public UIReal<FAUSTFLOAT>
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -418,9 +432,9 @@ struct UI : public UIReal<FAUSTFLOAT>
 #ifndef FAUST_PATHBUILDER_H
 #define FAUST_PATHBUILDER_H
 
-#include <vector>
-#include <string>
 #include <algorithm>
+#include <string>
+#include <vector>
 
 /*******************************************************************************
  * PathBuilder : Faust User Interface
@@ -429,37 +443,33 @@ struct UI : public UIReal<FAUSTFLOAT>
 
 class PathBuilder
 {
-
-    protected:
-    
-        std::vector<std::string> fControlsLevel;
-       
-    public:
-    
-        PathBuilder() {}
-        virtual ~PathBuilder() {}
-    
-        std::string buildPath(const std::string& label) 
-        {
-            std::string res = "/";
-            for (size_t i = 0; i < fControlsLevel.size(); i++) {
-                res += fControlsLevel[i];
-                res += "/";
-            }
-            res += label;
-            std::replace(res.begin(), res.end(), ' ', '_');
-            return res;
-        }
-    
-        std::string buildLabel(std::string label)
-        {
-            std::replace(label.begin(), label.end(), ' ', '_');
-            return label;
+   protected:
+    std::vector<std::string> fControlsLevel;
+
+   public:
+    PathBuilder() {}
+    virtual ~PathBuilder() {}
+
+    std::string buildPath(const std::string& label)
+    {
+        std::string res = "/";
+        for (size_t i = 0; i < fControlsLevel.size(); i++) {
+            res += fControlsLevel[i];
+            res += "/";
         }
-    
-        void pushLabel(const std::string& label) { fControlsLevel.push_back(label); }
-        void popLabel() { fControlsLevel.pop_back(); }
-    
+        res += label;
+        std::replace(res.begin(), res.end(), ' ', '_');
+        return res;
+    }
+
+    std::string buildLabel(std::string label)
+    {
+        std::replace(label.begin(), label.end(), ' ', '_');
+        return label;
+    }
+
+    void pushLabel(const std::string& label) { fControlsLevel.push_back(label); }
+    void popLabel() { fControlsLevel.pop_back(); }
 };
 
 #endif  // FAUST_PATHBUILDER_H
@@ -473,15 +483,15 @@ class PathBuilder
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -492,7 +502,7 @@ class PathBuilder
 #define __ValueConverter__
 
 /***************************************************************************************
-                                                               ValueConverter.h
+                                                                ValueConverter.h
                             (GRAME, Copyright 2015-2019)
 
 Set of conversion objects used to map user interface values (for example a gui slider
@@ -502,8 +512,9 @@ delivering values between 0 and 1) to faust values (for example a vslider betwee
 -- Utilities
 
 Range(lo,hi) : clip a value x between lo and hi
-Interpolator(lo,hi,v1,v2) : Maps a value x between lo and hi to a value y between v1 and v2
-Interpolator3pt(lo,mi,hi,v1,vm,v2) : Map values between lo mid hi to values between v1 vm v2
+Interpolator(lo,hi,v1,v2) : Maps a value x between lo and hi to a value y between v1 and
+v2 Interpolator3pt(lo,mi,hi,v1,vm,v2) : Map values between lo mid hi to values between v1
+vm v2
 
 -- Value Converters
 
@@ -534,11 +545,11 @@ ZoneReader(zone, valueConverter) : a zone with a data converter
 
 ****************************************************************************************/
 
-#include <float.h>
-#include <algorithm>    // std::max
+#include <algorithm>  // std::max
+#include <cassert>
+#include <cfloat>
 #include <cmath>
 #include <vector>
-#include <assert.h>
 
 //--------------------------------------------------------------------------------------
 // Interpolator(lo,hi,v1,v2)
@@ -551,50 +562,49 @@ ZoneReader(zone, valueConverter) : a zone with a data converter
 //--------------------------------------------------------------------------------------
 class Interpolator
 {
-    private:
-
-        //--------------------------------------------------------------------------------------
-        // Range(lo,hi) clip a value between lo and hi
-        //--------------------------------------------------------------------------------------
-        struct Range
-        {
-            double fLo;
-            double fHi;
-
-            Range(double x, double y) : fLo(std::min<double>(x,y)), fHi(std::max<double>(x,y)) {}
-            double operator()(double x) { return (x<fLo) ? fLo : (x>fHi) ? fHi : x; }
-        };
-
-
-        Range fRange;
-        double fCoef;
-        double fOffset;
-
-    public:
-
-        Interpolator(double lo, double hi, double v1, double v2) : fRange(lo,hi)
+   private:
+    //--------------------------------------------------------------------------------------
+    // Range(lo,hi) clip a value between lo and hi
+    //--------------------------------------------------------------------------------------
+    struct Range {
+        double fLo;
+        double fHi;
+
+        Range(double x, double y)
+            : fLo(std::min<double>(x, y)), fHi(std::max<double>(x, y))
         {
-            if (hi != lo) {
-                // regular case
-                fCoef = (v2-v1)/(hi-lo);
-                fOffset = v1 - lo*fCoef;
-            } else {
-                // degenerate case, avoids division by zero
-                fCoef = 0;
-                fOffset = (v1+v2)/2;
-            }
         }
-        double operator()(double v)
-        {
-            double x = fRange(v);
-            return  fOffset + x*fCoef;
-        }
-
-        void getLowHigh(double& amin, double& amax)
-        {
-            amin = fRange.fLo;
-            amax = fRange.fHi;
+        double operator()(double x) { return (x < fLo) ? fLo : (x > fHi) ? fHi : x; }
+    };
+
+    Range fRange;
+    double fCoef;
+    double fOffset;
+
+   public:
+    Interpolator(double lo, double hi, double v1, double v2) : fRange(lo, hi)
+    {
+        if (hi != lo) {
+            // regular case
+            fCoef   = (v2 - v1) / (hi - lo);
+            fOffset = v1 - lo * fCoef;
+        } else {
+            // degenerate case, avoids division by zero
+            fCoef   = 0;
+            fOffset = (v1 + v2) / 2;
         }
+    }
+    double operator()(double v)
+    {
+        double x = fRange(v);
+        return fOffset + x * fCoef;
+    }
+
+    void getLowHigh(double& amin, double& amax)
+    {
+        amin = fRange.fLo;
+        amax = fRange.fHi;
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -603,26 +613,23 @@ class Interpolator
 //--------------------------------------------------------------------------------------
 class Interpolator3pt
 {
-
-    private:
-
-        Interpolator fSegment1;
-        Interpolator fSegment2;
-        double fMid;
-
-    public:
-
-        Interpolator3pt(double lo, double mi, double hi, double v1, double vm, double v2) :
-            fSegment1(lo, mi, v1, vm),
-            fSegment2(mi, hi, vm, v2),
-            fMid(mi) {}
-        double operator()(double x) { return  (x < fMid) ? fSegment1(x) : fSegment2(x); }
-
-        void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fSegment1.getLowHigh(amin, amid);
-            fSegment2.getLowHigh(amid, amax);
-        }
+   private:
+    Interpolator fSegment1;
+    Interpolator fSegment2;
+    double fMid;
+
+   public:
+    Interpolator3pt(double lo, double mi, double hi, double v1, double vm, double v2)
+        : fSegment1(lo, mi, v1, vm), fSegment2(mi, hi, vm, v2), fMid(mi)
+    {
+    }
+    double operator()(double x) { return (x < fMid) ? fSegment1(x) : fSegment2(x); }
+
+    void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fSegment1.getLowHigh(amin, amid);
+        fSegment2.getLowHigh(amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -630,62 +637,51 @@ class Interpolator3pt
 //--------------------------------------------------------------------------------------
 class ValueConverter
 {
-
-    public:
-
-        virtual ~ValueConverter() {}
-        virtual double ui2faust(double x) = 0;
-        virtual double faust2ui(double x) = 0;
+   public:
+    virtual ~ValueConverter() {}
+    virtual double ui2faust(double x) = 0;
+    virtual double faust2ui(double x) = 0;
 };
 
 //--------------------------------------------------------------------------------------
 // A converter than can be updated
 //--------------------------------------------------------------------------------------
 
-class UpdatableValueConverter : public ValueConverter {
-    
-    protected:
-        
-        bool fActive;
-        
-    public:
-        
-        UpdatableValueConverter():fActive(true)
-        {}
-        virtual ~UpdatableValueConverter()
-        {}
-        
-        virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max) = 0;
-        virtual void getMappingValues(double& amin, double& amid, double& amax) = 0;
-        
-        void setActive(bool on_off) { fActive = on_off; }
-        bool getActive() { return fActive; }
-    
-};
+class UpdatableValueConverter : public ValueConverter
+{
+   protected:
+    bool fActive;
+
+   public:
+    UpdatableValueConverter() : fActive(true) {}
+    virtual ~UpdatableValueConverter() {}
 
+    virtual void setMappingValues(double amin, double amid, double amax, double min,
+                                  double init, double max)                  = 0;
+    virtual void getMappingValues(double& amin, double& amid, double& amax) = 0;
+
+    void setActive(bool on_off) { fActive = on_off; }
+    bool getActive() { return fActive; }
+};
 
 //--------------------------------------------------------------------------------------
 // Linear conversion between ui and Faust values
 //--------------------------------------------------------------------------------------
 class LinearValueConverter : public ValueConverter
 {
-    
-    private:
-        
-        Interpolator fUI2F;
-        Interpolator fF2UI;
-        
-    public:
-        
-        LinearValueConverter(double umin, double umax, double fmin, double fmax) :
-            fUI2F(umin,umax,fmin,fmax), fF2UI(fmin,fmax,umin,umax)
-        {}
-        
-        LinearValueConverter() : fUI2F(0.,0.,0.,0.), fF2UI(0.,0.,0.,0.)
-        {}
-        virtual double ui2faust(double x) { return fUI2F(x); }
-        virtual double faust2ui(double x) { return fF2UI(x); }
-    
+   private:
+    Interpolator fUI2F;
+    Interpolator fF2UI;
+
+   public:
+    LinearValueConverter(double umin, double umax, double fmin, double fmax)
+        : fUI2F(umin, umax, fmin, fmax), fF2UI(fmin, fmax, umin, umax)
+    {
+    }
+
+    LinearValueConverter() : fUI2F(0., 0., 0., 0.), fF2UI(0., 0., 0., 0.) {}
+    virtual double ui2faust(double x) { return fUI2F(x); }
+    virtual double faust2ui(double x) { return fF2UI(x); }
 };
 
 //--------------------------------------------------------------------------------------
@@ -693,35 +689,35 @@ class LinearValueConverter : public ValueConverter
 //--------------------------------------------------------------------------------------
 class LinearValueConverter2 : public UpdatableValueConverter
 {
-    
-    private:
-    
-        Interpolator3pt fUI2F;
-        Interpolator3pt fF2UI;
-        
-    public:
-    
-        LinearValueConverter2(double amin, double amid, double amax, double min, double init, double max) :
-            fUI2F(amin, amid, amax, min, init, max), fF2UI(min, init, max, amin, amid, amax)
-        {}
-        
-        LinearValueConverter2() : fUI2F(0.,0.,0.,0.,0.,0.), fF2UI(0.,0.,0.,0.,0.,0.)
-        {}
-    
-        virtual double ui2faust(double x) { return fUI2F(x); }
-        virtual double faust2ui(double x) { return fF2UI(x); }
-    
-        virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max)
-        {
-            fUI2F = Interpolator3pt(amin, amid, amax, min, init, max);
-            fF2UI = Interpolator3pt(min, init, max, amin, amid, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fUI2F.getMappingValues(amin, amid, amax);
-        }
-    
+   private:
+    Interpolator3pt fUI2F;
+    Interpolator3pt fF2UI;
+
+   public:
+    LinearValueConverter2(double amin, double amid, double amax, double min, double init,
+                          double max)
+        : fUI2F(amin, amid, amax, min, init, max), fF2UI(min, init, max, amin, amid, amax)
+    {
+    }
+
+    LinearValueConverter2() : fUI2F(0., 0., 0., 0., 0., 0.), fF2UI(0., 0., 0., 0., 0., 0.)
+    {
+    }
+
+    virtual double ui2faust(double x) { return fUI2F(x); }
+    virtual double faust2ui(double x) { return fF2UI(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double min,
+                                  double init, double max)
+    {
+        fUI2F = Interpolator3pt(amin, amid, amax, min, init, max);
+        fF2UI = Interpolator3pt(min, init, max, amin, amid, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fUI2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -729,16 +725,21 @@ class LinearValueConverter2 : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class LogValueConverter : public LinearValueConverter
 {
-
-    public:
-
-        LogValueConverter(double umin, double umax, double fmin, double fmax) :
-            LinearValueConverter(umin, umax, std::log(std::max<double>(DBL_MIN, fmin)), std::log(std::max<double>(DBL_MIN, fmax)))
-        {}
-
-        virtual double ui2faust(double x) { return std::exp(LinearValueConverter::ui2faust(x)); }
-        virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::log(std::max<double>(x, DBL_MIN))); }
-
+   public:
+    LogValueConverter(double umin, double umax, double fmin, double fmax)
+        : LinearValueConverter(umin, umax, std::log(std::max<double>(DBL_MIN, fmin)),
+                               std::log(std::max<double>(DBL_MIN, fmax)))
+    {
+    }
+
+    virtual double ui2faust(double x)
+    {
+        return std::exp(LinearValueConverter::ui2faust(x));
+    }
+    virtual double faust2ui(double x)
+    {
+        return LinearValueConverter::faust2ui(std::log(std::max<double>(x, DBL_MIN)));
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -746,16 +747,21 @@ class LogValueConverter : public LinearValueConverter
 //--------------------------------------------------------------------------------------
 class ExpValueConverter : public LinearValueConverter
 {
-
-    public:
-
-        ExpValueConverter(double umin, double umax, double fmin, double fmax) :
-            LinearValueConverter(umin, umax, std::min<double>(DBL_MAX, std::exp(fmin)), std::min<double>(DBL_MAX, std::exp(fmax)))
-        {}
-
-        virtual double ui2faust(double x) { return std::log(LinearValueConverter::ui2faust(x)); }
-        virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::min<double>(DBL_MAX, std::exp(x))); }
-
+   public:
+    ExpValueConverter(double umin, double umax, double fmin, double fmax)
+        : LinearValueConverter(umin, umax, std::min<double>(DBL_MAX, std::exp(fmin)),
+                               std::min<double>(DBL_MAX, std::exp(fmax)))
+    {
+    }
+
+    virtual double ui2faust(double x)
+    {
+        return std::log(LinearValueConverter::ui2faust(x));
+    }
+    virtual double faust2ui(double x)
+    {
+        return LinearValueConverter::faust2ui(std::min<double>(DBL_MAX, std::exp(x)));
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -764,34 +770,34 @@ class ExpValueConverter : public LinearValueConverter
 //--------------------------------------------------------------------------------------
 class AccUpConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt fA2F;
-        Interpolator3pt fF2A;
-
-    public:
-
-        AccUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmin,fmid,fmax),
-            fF2A(fmin,fmid,fmax,amin,amid,amax)
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-            //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmin, fmid, fmax);
-            fF2A = Interpolator3pt(fmin, fmid, fmax, amin, amid, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
-
+   private:
+    Interpolator3pt fA2F;
+    Interpolator3pt fF2A;
+
+   public:
+    AccUpConverter(double amin, double amid, double amax, double fmin, double fmid,
+                   double fmax)
+        : fA2F(amin, amid, amax, fmin, fmid, fmax)
+        , fF2A(fmin, fmid, fmax, amin, amid, amax)
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double fmid, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpConverter update %f %f %f
+        //%f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmin, fmid, fmax);
+        fF2A = Interpolator3pt(fmin, fmid, fmax, amin, amid, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -800,33 +806,34 @@ class AccUpConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class AccDownConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt        fA2F;
-        Interpolator3pt        fF2A;
-
-    public:
-
-        AccDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmax,fmid,fmin),
-            fF2A(fmin,fmid,fmax,amax,amid,amin)
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-             //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmax, fmid, fmin);
-            fF2A = Interpolator3pt(fmin, fmid, fmax, amax, amid, amin);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
+   private:
+    Interpolator3pt fA2F;
+    Interpolator3pt fF2A;
+
+   public:
+    AccDownConverter(double amin, double amid, double amax, double fmin, double fmid,
+                     double fmax)
+        : fA2F(amin, amid, amax, fmax, fmid, fmin)
+        , fF2A(fmin, fmid, fmax, amax, amid, amin)
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double fmid, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownConverter update %f %f
+        //%f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmax, fmid, fmin);
+        fF2A = Interpolator3pt(fmin, fmid, fmax, amax, amid, amin);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -835,33 +842,35 @@ class AccDownConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class AccUpDownConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt        fA2F;
-        Interpolator fF2A;
-
-    public:
-
-        AccUpDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmin,fmax,fmin),
-            fF2A(fmin,fmax,amin,amax)                          // Special, pseudo inverse of a non monotonic function
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-            //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmin, fmax, fmin);
-            fF2A = Interpolator(fmin, fmax, amin, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
+   private:
+    Interpolator3pt fA2F;
+    Interpolator fF2A;
+
+   public:
+    AccUpDownConverter(double amin, double amid, double amax, double fmin,
+                       double /*fmid*/, double fmax)
+        : fA2F(amin, amid, amax, fmin, fmax, fmin)
+        , fF2A(fmin, fmax, amin,
+               amax)  // Special, pseudo inverse of a non monotonic function
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double /*fmid*/, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpDownConverter update %f %f
+        //%f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmin, fmax, fmin);
+        fF2A = Interpolator(fmin, fmax, amin, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -870,33 +879,35 @@ class AccUpDownConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class AccDownUpConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt        fA2F;
-        Interpolator fF2A;
-
-    public:
-
-        AccDownUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmax,fmin,fmax),
-            fF2A(fmin,fmax,amin,amax)                          // Special, pseudo inverse of a non monotonic function
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-            //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmax, fmin, fmax);
-            fF2A = Interpolator(fmin, fmax, amin, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
+   private:
+    Interpolator3pt fA2F;
+    Interpolator fF2A;
+
+   public:
+    AccDownUpConverter(double amin, double amid, double amax, double fmin,
+                       double /*fmid*/, double fmax)
+        : fA2F(amin, amid, amax, fmax, fmin, fmax)
+        , fF2A(fmin, fmax, amin,
+               amax)  // Special, pseudo inverse of a non monotonic function
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double /*fmid*/, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownUpConverter update %f %f
+        //%f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmax, fmin, fmax);
+        fF2A = Interpolator(fmin, fmax, amin, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -904,28 +915,28 @@ class AccDownUpConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class ZoneControl
 {
+   protected:
+    FAUSTFLOAT* fZone;
 
-    protected:
+   public:
+    ZoneControl(FAUSTFLOAT* zone) : fZone(zone) {}
+    virtual ~ZoneControl() {}
 
-        FAUSTFLOAT*    fZone;
+    virtual void update(double /*v*/) const {}
 
-    public:
+    virtual void setMappingValues(int /*curve*/, double /*amin*/, double /*amid*/,
+                                  double /*amax*/, double /*min*/, double /*init*/,
+                                  double /*max*/)
+    {
+    }
+    virtual void getMappingValues(double& /*amin*/, double& /*amid*/, double& /*amax*/) {}
 
-        ZoneControl(FAUSTFLOAT* zone) : fZone(zone) {}
-        virtual ~ZoneControl() {}
+    FAUSTFLOAT* getZone() { return fZone; }
 
-        virtual void update(double v) const {}
-
-        virtual void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max) {}
-        virtual void getMappingValues(double& amin, double& amid, double& amax) {}
-
-        FAUSTFLOAT* getZone() { return fZone; }
-
-        virtual void setActive(bool on_off) {}
-        virtual bool getActive() { return false; }
-
-        virtual int getCurve() { return -1; }
+    virtual void setActive(bool /*on_off*/) {}
+    virtual bool getActive() { return false; }
 
+    virtual int getCurve() { return -1; }
 };
 
 //--------------------------------------------------------------------------------------
@@ -933,20 +944,22 @@ class ZoneControl
 //--------------------------------------------------------------------------------------
 class ConverterZoneControl : public ZoneControl
 {
-
-    protected:
-
-        ValueConverter* fValueConverter;
-
-    public:
-
-        ConverterZoneControl(FAUSTFLOAT* zone, ValueConverter* converter) : ZoneControl(zone), fValueConverter(converter) {}
-        virtual ~ConverterZoneControl() { delete fValueConverter; } // Assuming fValueConverter is not kept elsewhere...
-
-        virtual void update(double v) const { *fZone = fValueConverter->ui2faust(v); }
-
-        ValueConverter* getConverter() { return fValueConverter; }
-
+   protected:
+    ValueConverter* fValueConverter;
+
+   public:
+    ConverterZoneControl(FAUSTFLOAT* zone, ValueConverter* converter)
+        : ZoneControl(zone), fValueConverter(converter)
+    {
+    }
+    virtual ~ConverterZoneControl()
+    {
+        delete fValueConverter;
+    }  // Assuming fValueConverter is not kept elsewhere...
+
+    virtual void update(double v) const { *fZone = fValueConverter->ui2faust(v); }
+
+    ValueConverter* getConverter() { return fValueConverter; }
 };
 
 //--------------------------------------------------------------------------------------
@@ -955,592 +968,613 @@ class ConverterZoneControl : public ZoneControl
 //--------------------------------------------------------------------------------------
 class CurveZoneControl : public ZoneControl
 {
-
-    private:
-
-        std::vector<UpdatableValueConverter*> fValueConverters;
-        int fCurve;
-
-    public:
-
-        CurveZoneControl(FAUSTFLOAT* zone, int curve, double amin, double amid, double amax, double min, double init, double max) : ZoneControl(zone), fCurve(0)
-        {
-            assert(curve >= 0 && curve <= 3);
-            fValueConverters.push_back(new AccUpConverter(amin, amid, amax, min, init, max));
-            fValueConverters.push_back(new AccDownConverter(amin, amid, amax, min, init, max));
-            fValueConverters.push_back(new AccUpDownConverter(amin, amid, amax, min, init, max));
-            fValueConverters.push_back(new AccDownUpConverter(amin, amid, amax, min, init, max));
-            fCurve = curve;
+   private:
+    std::vector<UpdatableValueConverter*> fValueConverters;
+    int fCurve;
+
+   public:
+    CurveZoneControl(FAUSTFLOAT* zone, int curve, double amin, double amid, double amax,
+                     double min, double init, double max)
+        : ZoneControl(zone), fCurve(0)
+    {
+        assert(curve >= 0 && curve <= 3);
+        fValueConverters.push_back(new AccUpConverter(amin, amid, amax, min, init, max));
+        fValueConverters.push_back(
+            new AccDownConverter(amin, amid, amax, min, init, max));
+        fValueConverters.push_back(
+            new AccUpDownConverter(amin, amid, amax, min, init, max));
+        fValueConverters.push_back(
+            new AccDownUpConverter(amin, amid, amax, min, init, max));
+        fCurve = curve;
+    }
+    virtual ~CurveZoneControl()
+    {
+        std::vector<UpdatableValueConverter*>::iterator it;
+        for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+            delete (*it);
         }
-        virtual ~CurveZoneControl()
-        {
-            std::vector<UpdatableValueConverter*>::iterator it;
-            for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
-                delete(*it);
-            }
-        }
-        void update(double v) const { if (fValueConverters[fCurve]->getActive()) *fZone = fValueConverters[fCurve]->ui2faust(v); }
-
-        void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max)
-        {
-            fValueConverters[curve]->setMappingValues(amin, amid, amax, min, init, max);
-            fCurve = curve;
+    }
+    void update(double v) const
+    {
+        if (fValueConverters[fCurve]->getActive())
+            *fZone = fValueConverters[fCurve]->ui2faust(v);
+    }
+
+    void setMappingValues(int curve, double amin, double amid, double amax, double min,
+                          double init, double max)
+    {
+        fValueConverters[curve]->setMappingValues(amin, amid, amax, min, init, max);
+        fCurve = curve;
+    }
+
+    void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fValueConverters[fCurve]->getMappingValues(amin, amid, amax);
+    }
+
+    void setActive(bool on_off)
+    {
+        std::vector<UpdatableValueConverter*>::iterator it;
+        for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+            (*it)->setActive(on_off);
         }
+    }
 
-        void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fValueConverters[fCurve]->getMappingValues(amin, amid, amax);
-        }
-
-        void setActive(bool on_off)
-        {
-            std::vector<UpdatableValueConverter*>::iterator it;
-            for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
-                (*it)->setActive(on_off);
-            }
-        }
-
-        int getCurve() { return fCurve; }
+    int getCurve() { return fCurve; }
 };
 
 class ZoneReader
 {
+   private:
+    FAUSTFLOAT* fZone;
+    Interpolator fInterpolator;
 
-    private:
-
-        FAUSTFLOAT* fZone;
-        Interpolator fInterpolator;
-
-    public:
+   public:
+    ZoneReader(FAUSTFLOAT* zone, double lo, double hi)
+        : fZone(zone), fInterpolator(lo, hi, 0, 255)
+    {
+    }
 
-        ZoneReader(FAUSTFLOAT* zone, double lo, double hi) : fZone(zone), fInterpolator(lo, hi, 0, 255) {}
-
-        virtual ~ZoneReader() {}
-
-        int getValue()
-        {
-            return (fZone != nullptr) ? int(fInterpolator(*fZone)) : 127;
-        }
+    virtual ~ZoneReader() {}
 
+    int getValue() { return (fZone != nullptr) ? int(fInterpolator(*fZone)) : 127; }
 };
 
 #endif
 /**************************  END  ValueConverter.h **************************/
 
-class APIUI : public PathBuilder, public Meta, public UI
+class APIUI
+    : public PathBuilder
+    , public Meta
+    , public UI
 {
-    public:
-    
-        enum ItemType { kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph };
-  
-    protected:
-    
-        enum { kLin = 0, kLog = 1, kExp = 2 };
-    
-        int fNumParameters;
-        std::vector<std::string> fPaths;
-        std::vector<std::string> fLabels;
-        std::map<std::string, int> fPathMap;
-        std::map<std::string, int> fLabelMap;
-        std::vector<ValueConverter*> fConversion;
-        std::vector<FAUSTFLOAT*> fZone;
-        std::vector<FAUSTFLOAT> fInit;
-        std::vector<FAUSTFLOAT> fMin;
-        std::vector<FAUSTFLOAT> fMax;
-        std::vector<FAUSTFLOAT> fStep;
-        std::vector<ItemType> fItemType;
-        std::vector<std::map<std::string, std::string> > fMetaData;
-        std::vector<ZoneControl*> fAcc[3];
-        std::vector<ZoneControl*> fGyr[3];
-
-        // Screen color control
-        // "...[screencolor:red]..." etc.
-        bool fHasScreenControl;      // true if control screen color metadata
-        ZoneReader* fRedReader;
-        ZoneReader* fGreenReader;
-        ZoneReader* fBlueReader;
-
-        // Current values controlled by metadata
-        std::string fCurrentUnit;
-        int fCurrentScale;
-        std::string fCurrentAcc;
-        std::string fCurrentGyr;
-        std::string fCurrentColor;
-        std::string fCurrentTooltip;
-        std::map<std::string, std::string> fCurrentMetadata;
-    
-        // Add a generic parameter
-        virtual void addParameter(const char* label,
-                                FAUSTFLOAT* zone,
-                                FAUSTFLOAT init,
-                                FAUSTFLOAT min,
-                                FAUSTFLOAT max,
-                                FAUSTFLOAT step,
-                                ItemType type)
-        {
-            std::string path = buildPath(label);
-            fPathMap[path] = fLabelMap[label] = fNumParameters++;
-            fPaths.push_back(path);
-            fLabels.push_back(label);
-            fZone.push_back(zone);
-            fInit.push_back(init);
-            fMin.push_back(min);
-            fMax.push_back(max);
-            fStep.push_back(step);
-            fItemType.push_back(type);
-            
-            // handle scale metadata
-            switch (fCurrentScale) {
-                case kLin:
-                    fConversion.push_back(new LinearValueConverter(0, 1, min, max));
-                    break;
-                case kLog:
-                    fConversion.push_back(new LogValueConverter(0, 1, min, max));
-                    break;
-                case kExp: fConversion.push_back(new ExpValueConverter(0, 1, min, max));
-                    break;
-            }
-            fCurrentScale = kLin;
-            
-            if (fCurrentAcc.size() > 0 && fCurrentGyr.size() > 0) {
-                std::cerr << "warning : 'acc' and 'gyr' metadata used for the same " << label << " parameter !!\n";
-            }
+   public:
+    enum ItemType {
+        kButton = 0,
+        kCheckButton,
+        kVSlider,
+        kHSlider,
+        kNumEntry,
+        kHBargraph,
+        kVBargraph
+    };
+
+   protected:
+    enum { kLin = 0, kLog = 1, kExp = 2 };
+
+    int fNumParameters;
+    std::vector<std::string> fPaths;
+    std::vector<std::string> fLabels;
+    std::map<std::string, int> fPathMap;
+    std::map<std::string, int> fLabelMap;
+    std::vector<ValueConverter*> fConversion;
+    std::vector<FAUSTFLOAT*> fZone;
+    std::vector<FAUSTFLOAT> fInit;
+    std::vector<FAUSTFLOAT> fMin;
+    std::vector<FAUSTFLOAT> fMax;
+    std::vector<FAUSTFLOAT> fStep;
+    std::vector<ItemType> fItemType;
+    std::vector<std::map<std::string, std::string> > fMetaData;
+    std::vector<ZoneControl*> fAcc[3];
+    std::vector<ZoneControl*> fGyr[3];
+
+    // Screen color control
+    // "...[screencolor:red]..." etc.
+    bool fHasScreenControl;  // true if control screen color metadata
+    ZoneReader* fRedReader;
+    ZoneReader* fGreenReader;
+    ZoneReader* fBlueReader;
+
+    // Current values controlled by metadata
+    std::string fCurrentUnit;
+    int fCurrentScale;
+    std::string fCurrentAcc;
+    std::string fCurrentGyr;
+    std::string fCurrentColor;
+    std::string fCurrentTooltip;
+    std::map<std::string, std::string> fCurrentMetadata;
+
+    // Add a generic parameter
+    virtual void addParameter(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                              FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step,
+                              ItemType type)
+    {
+        std::string path = buildPath(label);
+        fPathMap[path] = fLabelMap[label] = fNumParameters++;
+        fPaths.push_back(path);
+        fLabels.push_back(label);
+        fZone.push_back(zone);
+        fInit.push_back(init);
+        fMin.push_back(min);
+        fMax.push_back(max);
+        fStep.push_back(step);
+        fItemType.push_back(type);
+
+        // handle scale metadata
+        switch (fCurrentScale) {
+        case kLin:
+            fConversion.push_back(new LinearValueConverter(0, 1, min, max));
+            break;
+        case kLog:
+            fConversion.push_back(new LogValueConverter(0, 1, min, max));
+            break;
+        case kExp:
+            fConversion.push_back(new ExpValueConverter(0, 1, min, max));
+            break;
+        }
+        fCurrentScale = kLin;
 
-            // handle acc metadata "...[acc : <axe> <curve> <amin> <amid> <amax>]..."
-            if (fCurrentAcc.size() > 0) {
-                std::istringstream iss(fCurrentAcc);
-                int axe, curve;
-                double amin, amid, amax;
-                iss >> axe >> curve >> amin >> amid >> amax;
-
-                if ((0 <= axe) && (axe < 3) &&
-                    (0 <= curve) && (curve < 4) &&
-                    (amin < amax) && (amin <= amid) && (amid <= amax))
-                {
-                    fAcc[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
-                } else {
-                    std::cerr << "incorrect acc metadata : " << fCurrentAcc << std::endl;
-                }
-                fCurrentAcc = "";
-            }
-       
-            // handle gyr metadata "...[gyr : <axe> <curve> <amin> <amid> <amax>]..."
-            if (fCurrentGyr.size() > 0) {
-                std::istringstream iss(fCurrentGyr);
-                int axe, curve;
-                double amin, amid, amax;
-                iss >> axe >> curve >> amin >> amid >> amax;
-
-                if ((0 <= axe) && (axe < 3) &&
-                    (0 <= curve) && (curve < 4) &&
-                    (amin < amax) && (amin <= amid) && (amid <= amax))
-                {
-                    fGyr[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
-                } else {
-                    std::cerr << "incorrect gyr metadata : " << fCurrentGyr << std::endl;
-                }
-                fCurrentGyr = "";
-            }
-        
-            // handle screencolor metadata "...[screencolor:red|green|blue|white]..."
-            if (fCurrentColor.size() > 0) {
-                if ((fCurrentColor == "red") && (fRedReader == 0)) {
-                    fRedReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else if ((fCurrentColor == "green") && (fGreenReader == 0)) {
-                    fGreenReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else if ((fCurrentColor == "blue") && (fBlueReader == 0)) {
-                    fBlueReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else if ((fCurrentColor == "white") && (fRedReader == 0) && (fGreenReader == 0) && (fBlueReader == 0)) {
-                    fRedReader = new ZoneReader(zone, min, max);
-                    fGreenReader = new ZoneReader(zone, min, max);
-                    fBlueReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else {
-                    std::cerr << "incorrect screencolor metadata : " << fCurrentColor << std::endl;
-                }
-            }
-            fCurrentColor = "";
-            
-            fMetaData.push_back(fCurrentMetadata);
-            fCurrentMetadata.clear();
+        if (fCurrentAcc.size() > 0 && fCurrentGyr.size() > 0) {
+            std::cerr << "warning : 'acc' and 'gyr' metadata used for the same " << label
+                      << " parameter !!\n";
         }
 
-        int getZoneIndex(std::vector<ZoneControl*>* table, int p, int val)
-        {
-            FAUSTFLOAT* zone = fZone[p];
-            for (size_t i = 0; i < table[val].size(); i++) {
-                if (zone == table[val][i]->getZone()) return int(i);
+        // handle acc metadata "...[acc : <axe> <curve> <amin> <amid> <amax>]..."
+        if (fCurrentAcc.size() > 0) {
+            std::istringstream iss(fCurrentAcc);
+            int axe, curve;
+            double amin, amid, amax;
+            iss >> axe >> curve >> amin >> amid >> amax;
+
+            if ((0 <= axe) && (axe < 3) && (0 <= curve) && (curve < 4) && (amin < amax)
+                && (amin <= amid) && (amid <= amax)) {
+                fAcc[axe].push_back(
+                    new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
+            } else {
+                std::cerr << "incorrect acc metadata : " << fCurrentAcc << std::endl;
             }
-            return -1;
+            fCurrentAcc = "";
         }
-    
-        void setConverter(std::vector<ZoneControl*>* table, int p, int val, int curve, double amin, double amid, double amax)
-        {
-            int id1 = getZoneIndex(table, p, 0);
-            int id2 = getZoneIndex(table, p, 1);
-            int id3 = getZoneIndex(table, p, 2);
-            
-            // Deactivates everywhere..
-            if (id1 != -1) table[0][id1]->setActive(false);
-            if (id2 != -1) table[1][id2]->setActive(false);
-            if (id3 != -1) table[2][id3]->setActive(false);
-            
-            if (val == -1) { // Means: no more mapping...
-                // So stay all deactivated...
+
+        // handle gyr metadata "...[gyr : <axe> <curve> <amin> <amid> <amax>]..."
+        if (fCurrentGyr.size() > 0) {
+            std::istringstream iss(fCurrentGyr);
+            int axe, curve;
+            double amin, amid, amax;
+            iss >> axe >> curve >> amin >> amid >> amax;
+
+            if ((0 <= axe) && (axe < 3) && (0 <= curve) && (curve < 4) && (amin < amax)
+                && (amin <= amid) && (amid <= amax)) {
+                fGyr[axe].push_back(
+                    new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
             } else {
-                int id4 = getZoneIndex(table, p, val);
-                if (id4 != -1) {
-                    // Reactivate the one we edit...
-                    table[val][id4]->setMappingValues(curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]);
-                    table[val][id4]->setActive(true);
-                } else {
-                    // Allocate a new CurveZoneControl which is 'active' by default
-                    FAUSTFLOAT* zone = fZone[p];
-                    table[val].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]));
-                }
+                std::cerr << "incorrect gyr metadata : " << fCurrentGyr << std::endl;
             }
+            fCurrentGyr = "";
         }
-    
-        void getConverter(std::vector<ZoneControl*>* table, int p, int& val, int& curve, double& amin, double& amid, double& amax)
-        {
-            int id1 = getZoneIndex(table, p, 0);
-            int id2 = getZoneIndex(table, p, 1);
-            int id3 = getZoneIndex(table, p, 2);
-            
-            if (id1 != -1) {
-                val = 0;
-                curve = table[val][id1]->getCurve();
-                table[val][id1]->getMappingValues(amin, amid, amax);
-            } else if (id2 != -1) {
-                val = 1;
-                curve = table[val][id2]->getCurve();
-                table[val][id2]->getMappingValues(amin, amid, amax);
-            } else if (id3 != -1) {
-                val = 2;
-                curve = table[val][id3]->getCurve();
-                table[val][id3]->getMappingValues(amin, amid, amax);
+
+        // handle screencolor metadata "...[screencolor:red|green|blue|white]..."
+        if (fCurrentColor.size() > 0) {
+            if ((fCurrentColor == "red") && (fRedReader == 0)) {
+                fRedReader        = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
+            } else if ((fCurrentColor == "green") && (fGreenReader == 0)) {
+                fGreenReader      = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
+            } else if ((fCurrentColor == "blue") && (fBlueReader == 0)) {
+                fBlueReader       = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
+            } else if ((fCurrentColor == "white") && (fRedReader == 0)
+                       && (fGreenReader == 0) && (fBlueReader == 0)) {
+                fRedReader        = new ZoneReader(zone, min, max);
+                fGreenReader      = new ZoneReader(zone, min, max);
+                fBlueReader       = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
             } else {
-                val = -1; // No mapping
-                curve = 0;
-                amin = -100.;
-                amid = 0.;
-                amax = 100.;
+                std::cerr << "incorrect screencolor metadata : " << fCurrentColor
+                          << std::endl;
             }
         }
+        fCurrentColor = "";
 
-     public:
-    
-        enum Type { kAcc = 0, kGyr = 1, kNoType };
-   
-        APIUI() : fNumParameters(0), fHasScreenControl(false), fRedReader(0), fGreenReader(0), fBlueReader(0), fCurrentScale(kLin)
-        {}
+        fMetaData.push_back(fCurrentMetadata);
+        fCurrentMetadata.clear();
+    }
 
-        virtual ~APIUI()
-        {
-            for (auto& it : fConversion) delete it;
-            for (int i = 0; i < 3; i++) {
-                for (auto& it : fAcc[i]) delete it;
-                for (auto& it : fGyr[i]) delete it;
+    int getZoneIndex(std::vector<ZoneControl*>* table, int p, int val)
+    {
+        FAUSTFLOAT* zone = fZone[p];
+        for (size_t i = 0; i < table[val].size(); i++) {
+            if (zone == table[val][i]->getZone()) return int(i);
+        }
+        return -1;
+    }
+
+    void setConverter(std::vector<ZoneControl*>* table, int p, int val, int curve,
+                      double amin, double amid, double amax)
+    {
+        int id1 = getZoneIndex(table, p, 0);
+        int id2 = getZoneIndex(table, p, 1);
+        int id3 = getZoneIndex(table, p, 2);
+
+        // Deactivates everywhere..
+        if (id1 != -1) table[0][id1]->setActive(false);
+        if (id2 != -1) table[1][id2]->setActive(false);
+        if (id3 != -1) table[2][id3]->setActive(false);
+
+        if (val == -1) {  // Means: no more mapping...
+            // So stay all deactivated...
+        } else {
+            int id4 = getZoneIndex(table, p, val);
+            if (id4 != -1) {
+                // Reactivate the one we edit...
+                table[val][id4]->setMappingValues(curve, amin, amid, amax, fMin[p],
+                                                  fInit[p], fMax[p]);
+                table[val][id4]->setActive(true);
+            } else {
+                // Allocate a new CurveZoneControl which is 'active' by default
+                FAUSTFLOAT* zone = fZone[p];
+                table[val].push_back(new CurveZoneControl(zone, curve, amin, amid, amax,
+                                                          fMin[p], fInit[p], fMax[p]));
             }
-            delete fRedReader;
-            delete fGreenReader;
-            delete fBlueReader;
         }
-    
-        // -- widget's layouts
-
-        virtual void openTabBox(const char* label) { pushLabel(label); }
-        virtual void openHorizontalBox(const char* label) { pushLabel(label); }
-        virtual void openVerticalBox(const char* label) { pushLabel(label); }
-        virtual void closeBox() { popLabel(); }
-
-        // -- active widgets
-
-        virtual void addButton(const char* label, FAUSTFLOAT* zone)
-        {
-            addParameter(label, zone, 0, 0, 1, 1, kButton);
+    }
+
+    void getConverter(std::vector<ZoneControl*>* table, int p, int& val, int& curve,
+                      double& amin, double& amid, double& amax)
+    {
+        int id1 = getZoneIndex(table, p, 0);
+        int id2 = getZoneIndex(table, p, 1);
+        int id3 = getZoneIndex(table, p, 2);
+
+        if (id1 != -1) {
+            val   = 0;
+            curve = table[val][id1]->getCurve();
+            table[val][id1]->getMappingValues(amin, amid, amax);
+        } else if (id2 != -1) {
+            val   = 1;
+            curve = table[val][id2]->getCurve();
+            table[val][id2]->getMappingValues(amin, amid, amax);
+        } else if (id3 != -1) {
+            val   = 2;
+            curve = table[val][id3]->getCurve();
+            table[val][id3]->getMappingValues(amin, amid, amax);
+        } else {
+            val   = -1;  // No mapping
+            curve = 0;
+            amin  = -100.;
+            amid  = 0.;
+            amax  = 100.;
         }
-
-        virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
-        {
-            addParameter(label, zone, 0, 0, 1, 1, kCheckButton);
+    }
+
+   public:
+    enum Type { kAcc = 0, kGyr = 1, kNoType };
+
+    APIUI()
+        : fNumParameters(0)
+        , fHasScreenControl(false)
+        , fRedReader(0)
+        , fGreenReader(0)
+        , fBlueReader(0)
+        , fCurrentScale(kLin)
+    {
+    }
+
+    virtual ~APIUI()
+    {
+        for (auto& it : fConversion) delete it;
+        for (int i = 0; i < 3; i++) {
+            for (auto& it : fAcc[i]) delete it;
+            for (auto& it : fGyr[i]) delete it;
         }
+        delete fRedReader;
+        delete fGreenReader;
+        delete fBlueReader;
+    }
 
-        virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
-        {
-            addParameter(label, zone, init, min, max, step, kVSlider);
-        }
+    // -- widget's layouts
 
-        virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
-        {
-            addParameter(label, zone, init, min, max, step, kHSlider);
-        }
+    virtual void openTabBox(const char* label) { pushLabel(label); }
+    virtual void openHorizontalBox(const char* label) { pushLabel(label); }
+    virtual void openVerticalBox(const char* label) { pushLabel(label); }
+    virtual void closeBox() { popLabel(); }
 
-        virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
-        {
-            addParameter(label, zone, init, min, max, step, kNumEntry);
-        }
+    // -- active widgets
 
-        // -- passive widgets
+    virtual void addButton(const char* label, FAUSTFLOAT* zone)
+    {
+        addParameter(label, zone, 0, 0, 1, 1, kButton);
+    }
+
+    virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
+    {
+        addParameter(label, zone, 0, 0, 1, 1, kCheckButton);
+    }
+
+    virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                                   FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+    {
+        addParameter(label, zone, init, min, max, step, kVSlider);
+    }
+
+    virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                                     FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+    {
+        addParameter(label, zone, init, min, max, step, kHSlider);
+    }
+
+    virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                             FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+    {
+        addParameter(label, zone, init, min, max, step, kNumEntry);
+    }
 
-        virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
-        {
-            addParameter(label, zone, min, min, max, (max-min)/1000.0, kHBargraph);
-        }
+    // -- passive widgets
 
-        virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
-        {
-            addParameter(label, zone, min, min, max, (max-min)/1000.0, kVBargraph);
-        }
-    
-        // -- soundfiles
-    
-        virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) {}
+    virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone,
+                                       FAUSTFLOAT min, FAUSTFLOAT max)
+    {
+        addParameter(label, zone, min, min, max, (max - min) / 1000.0, kHBargraph);
+    }
 
-        // -- metadata declarations
+    virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min,
+                                     FAUSTFLOAT max)
+    {
+        addParameter(label, zone, min, min, max, (max - min) / 1000.0, kVBargraph);
+    }
 
-        virtual void declare(FAUSTFLOAT* zone, const char* key, const char* val)
-        {
-            // Keep metadata
-            fCurrentMetadata[key] = val;
-            
-            if (strcmp(key, "scale") == 0) {
-                if (strcmp(val, "log") == 0) {
-                    fCurrentScale = kLog;
-                } else if (strcmp(val, "exp") == 0) {
-                    fCurrentScale = kExp;
-                } else {
-                    fCurrentScale = kLin;
-                }
-            } else if (strcmp(key, "unit") == 0) {
-                fCurrentUnit = val;
-            } else if (strcmp(key, "acc") == 0) {
-                fCurrentAcc = val;
-            } else if (strcmp(key, "gyr") == 0) {
-                fCurrentGyr = val;
-            } else if (strcmp(key, "screencolor") == 0) {
-                fCurrentColor = val; // val = "red", "green", "blue" or "white"
-            } else if (strcmp(key, "tooltip") == 0) {
-                fCurrentTooltip = val;
-            }
-        }
+    // -- soundfiles
 
-        virtual void declare(const char* key, const char* val)
-        {}
+    virtual void addSoundfile(const char* /*label*/, const char* /*filename*/,
+                              Soundfile** /*sf_zone*/)
+    {
+    }
 
-               //-------------------------------------------------------------------------------
-               // Simple API part
-               //-------------------------------------------------------------------------------
-               int getParamsCount() { return fNumParameters; }
-        int getParamIndex(const char* path)
-        {
-            if (fPathMap.find(path) != fPathMap.end()) {
-                return fPathMap[path];
-            } else if (fLabelMap.find(path) != fLabelMap.end()) {
-                return fLabelMap[path];
-            } else {
-                return -1;
-            }
-        }
-        const char* getParamAddress(int p) { return fPaths[p].c_str(); }
-        const char* getParamLabel(int p) { return fLabels[p].c_str(); }
-        std::map<const char*, const char*> getMetadata(int p)
-        {
-            std::map<const char*, const char*> res;
-            std::map<std::string, std::string> metadata = fMetaData[p];
-            for (auto it : metadata) {
-                res[it.first.c_str()] = it.second.c_str();
-            }
-            return res;
-        }
+    // -- metadata declarations
 
-        const char* getMetadata(int p, const char* key)
-        {
-            return (fMetaData[p].find(key) != fMetaData[p].end()) ? fMetaData[p][key].c_str() : "";
-        }
-        FAUSTFLOAT getParamMin(int p) { return fMin[p]; }
-        FAUSTFLOAT getParamMax(int p) { return fMax[p]; }
-        FAUSTFLOAT getParamStep(int p) { return fStep[p]; }
-        FAUSTFLOAT getParamInit(int p) { return fInit[p]; }
-
-        FAUSTFLOAT* getParamZone(int p) { return fZone[p]; }
-        FAUSTFLOAT getParamValue(int p) { return *fZone[p]; }
-        void setParamValue(int p, FAUSTFLOAT v) { *fZone[p] = v; }
-
-        double getParamRatio(int p) { return fConversion[p]->faust2ui(*fZone[p]); }
-        void setParamRatio(int p, double r) { *fZone[p] = fConversion[p]->ui2faust(r); }
-
-        double value2ratio(int p, double r)    { return fConversion[p]->faust2ui(r); }
-        double ratio2value(int p, double r)    { return fConversion[p]->ui2faust(r); }
-    
-        /**
-         * Return the control type (kAcc, kGyr, or -1) for a given parameter
-         *
-         * @param p - the UI parameter index
-         *
-         * @return the type
-         */
-        Type getParamType(int p)
-        {
-            if (p >= 0) {
-                if (getZoneIndex(fAcc, p, 0) != -1
-                    || getZoneIndex(fAcc, p, 1) != -1
-                    || getZoneIndex(fAcc, p, 2) != -1) {
-                    return kAcc;
-                } else if (getZoneIndex(fGyr, p, 0) != -1
-                           || getZoneIndex(fGyr, p, 1) != -1
-                           || getZoneIndex(fGyr, p, 2) != -1) {
-                    return kGyr;
-                }
-            }
-            return kNoType;
-        }
-    
-        /**
-         * Return the Item type (kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph) for a given parameter
-         *
-         * @param p - the UI parameter index
-         *
-         * @return the Item type
-         */
-        ItemType getParamItemType(int p)
-        {
-            return fItemType[p];
-        }
-   
-        /**
-         * Set a new value coming from an accelerometer, propagate it to all relevant FAUSTFLOAT* zones.
-         *
-         * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
-         * @param value - the new value
-         *
-         */
-        void propagateAcc(int acc, double value)
-        {
-            for (size_t i = 0; i < fAcc[acc].size(); i++) {
-                fAcc[acc][i]->update(value);
-            }
-        }
-    
-        /**
-         * Used to edit accelerometer curves and mapping. Set curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer (-1 means "no mapping")
-         * @param curve - between 0 and 3
-         * @param amin - mapping 'min' point
-         * @param amid - mapping 'middle' point
-         * @param amax - mapping 'max' point
-         *
-         */
-        void setAccConverter(int p, int acc, int curve, double amin, double amid, double amax)
-        {
-            setConverter(fAcc, p, acc, curve, amin, amid, amax);
-        }
-    
-        /**
-         * Used to edit gyroscope curves and mapping. Set curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param acc - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope (-1 means "no mapping")
-         * @param curve - between 0 and 3
-         * @param amin - mapping 'min' point
-         * @param amid - mapping 'middle' point
-         * @param amax - mapping 'max' point
-         *
-         */
-        void setGyrConverter(int p, int gyr, int curve, double amin, double amid, double amax)
-        {
-             setConverter(fGyr, p, gyr, curve, amin, amid, amax);
-        }
-    
-        /**
-         * Used to edit accelerometer curves and mapping. Get curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param acc - the acc value to be retrieved (-1 means "no mapping")
-         * @param curve - the curve value to be retrieved
-         * @param amin - the amin value to be retrieved
-         * @param amid - the amid value to be retrieved
-         * @param amax - the amax value to be retrieved
-         *
-         */
-        void getAccConverter(int p, int& acc, int& curve, double& amin, double& amid, double& amax)
-        {
-            getConverter(fAcc, p, acc, curve, amin, amid, amax);
-        }
+    virtual void declare(FAUSTFLOAT* /*zone*/, const char* key, const char* val)
+    {
+        // Keep metadata
+        fCurrentMetadata[key] = val;
 
-        /**
-         * Used to edit gyroscope curves and mapping. Get curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param gyr - the gyr value to be retrieved (-1 means "no mapping")
-         * @param curve - the curve value to be retrieved
-         * @param amin - the amin value to be retrieved
-         * @param amid - the amid value to be retrieved
-         * @param amax - the amax value to be retrieved
-         *
-         */
-        void getGyrConverter(int p, int& gyr, int& curve, double& amin, double& amid, double& amax)
-        {
-            getConverter(fGyr, p, gyr, curve, amin, amid, amax);
-        }
-    
-        /**
-         * Set a new value coming from an gyroscope, propagate it to all relevant FAUSTFLOAT* zones.
-         *
-         * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
-         * @param value - the new value
-         *
-         */
-        void propagateGyr(int gyr, double value)
-        {
-            for (size_t i = 0; i < fGyr[gyr].size(); i++) {
-                fGyr[gyr][i]->update(value);
+        if (strcmp(key, "scale") == 0) {
+            if (strcmp(val, "log") == 0) {
+                fCurrentScale = kLog;
+            } else if (strcmp(val, "exp") == 0) {
+                fCurrentScale = kExp;
+            } else {
+                fCurrentScale = kLin;
             }
+        } else if (strcmp(key, "unit") == 0) {
+            fCurrentUnit = val;
+        } else if (strcmp(key, "acc") == 0) {
+            fCurrentAcc = val;
+        } else if (strcmp(key, "gyr") == 0) {
+            fCurrentGyr = val;
+        } else if (strcmp(key, "screencolor") == 0) {
+            fCurrentColor = val;  // val = "red", "green", "blue" or "white"
+        } else if (strcmp(key, "tooltip") == 0) {
+            fCurrentTooltip = val;
         }
-    
-        /**
-         * Get the number of FAUSTFLOAT* zones controlled with the accelerometer
-         *
-         * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
-         * @return the number of zones
-         *
-         */
-        int getAccCount(int acc)
-        {
-            return (acc >= 0 && acc < 3) ? int(fAcc[acc].size()) : 0;
-        }
-    
-        /**
-         * Get the number of FAUSTFLOAT* zones controlled with the gyroscope
-         *
-         * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
-         * @param the number of zones
-         *
-         */
-        int getGyrCount(int gyr)
-        {
-            return (gyr >= 0 && gyr < 3) ? int(fGyr[gyr].size()) : 0;
+    }
+
+    virtual void declare(const char* /*key*/, const char* /*val*/) {}
+
+    //-------------------------------------------------------------------------------
+    // Simple API part
+    //-------------------------------------------------------------------------------
+    int getParamsCount() { return fNumParameters; }
+    int getParamIndex(const char* path)
+    {
+        if (fPathMap.find(path) != fPathMap.end()) {
+            return fPathMap[path];
+        } else if (fLabelMap.find(path) != fLabelMap.end()) {
+            return fLabelMap[path];
+        } else {
+            return -1;
         }
-   
-        // getScreenColor() : -1 means no screen color control (no screencolor metadata found)
-        // otherwise return 0x00RRGGBB a ready to use color
-        int getScreenColor()
-        {
-            if (fHasScreenControl) {
-                int r = (fRedReader) ? fRedReader->getValue() : 0;
-                int g = (fGreenReader) ? fGreenReader->getValue() : 0;
-                int b = (fBlueReader) ? fBlueReader->getValue() : 0;
-                return (r<<16) | (g<<8) | b;
-            } else {
-                return -1;
+    }
+    const char* getParamAddress(int p) { return fPaths[p].c_str(); }
+    const char* getParamLabel(int p) { return fLabels[p].c_str(); }
+    std::map<const char*, const char*> getMetadata(int p)
+    {
+        std::map<const char*, const char*> res;
+        std::map<std::string, std::string> metadata = fMetaData[p];
+        for (const auto& it : metadata) { res[it.first.c_str()] = it.second.c_str(); }
+        return res;
+    }
+
+    const char* getMetadata(int p, const char* key)
+    {
+        return (fMetaData[p].find(key) != fMetaData[p].end()) ? fMetaData[p][key].c_str()
+                                                              : "";
+    }
+    FAUSTFLOAT getParamMin(int p) { return fMin[p]; }
+    FAUSTFLOAT getParamMax(int p) { return fMax[p]; }
+    FAUSTFLOAT getParamStep(int p) { return fStep[p]; }
+    FAUSTFLOAT getParamInit(int p) { return fInit[p]; }
+
+    FAUSTFLOAT* getParamZone(int p) { return fZone[p]; }
+    FAUSTFLOAT getParamValue(int p) { return *fZone[p]; }
+    void setParamValue(int p, FAUSTFLOAT v) { *fZone[p] = v; }
+
+    double getParamRatio(int p) { return fConversion[p]->faust2ui(*fZone[p]); }
+    void setParamRatio(int p, double r) { *fZone[p] = fConversion[p]->ui2faust(r); }
+
+    double value2ratio(int p, double r) { return fConversion[p]->faust2ui(r); }
+    double ratio2value(int p, double r) { return fConversion[p]->ui2faust(r); }
+
+    /**
+     * Return the control type (kAcc, kGyr, or -1) for a given parameter
+     *
+     * @param p - the UI parameter index
+     *
+     * @return the type
+     */
+    Type getParamType(int p)
+    {
+        if (p >= 0) {
+            if (getZoneIndex(fAcc, p, 0) != -1 || getZoneIndex(fAcc, p, 1) != -1
+                || getZoneIndex(fAcc, p, 2) != -1) {
+                return kAcc;
+            } else if (getZoneIndex(fGyr, p, 0) != -1 || getZoneIndex(fGyr, p, 1) != -1
+                       || getZoneIndex(fGyr, p, 2) != -1) {
+                return kGyr;
             }
         }
+        return kNoType;
+    }
+
+    /**
+     * Return the Item type (kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry,
+     * kHBargraph, kVBargraph) for a given parameter
+     *
+     * @param p - the UI parameter index
+     *
+     * @return the Item type
+     */
+    ItemType getParamItemType(int p) { return fItemType[p]; }
+
+    /**
+     * Set a new value coming from an accelerometer, propagate it to all relevant
+     * FAUSTFLOAT* zones.
+     *
+     * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+     * @param value - the new value
+     *
+     */
+    void propagateAcc(int acc, double value)
+    {
+        for (size_t i = 0; i < fAcc[acc].size(); i++) { fAcc[acc][i]->update(value); }
+    }
+
+    /**
+     * Used to edit accelerometer curves and mapping. Set curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+     * (-1 means "no mapping")
+     * @param curve - between 0 and 3
+     * @param amin - mapping 'min' point
+     * @param amid - mapping 'middle' point
+     * @param amax - mapping 'max' point
+     *
+     */
+    void setAccConverter(int p, int acc, int curve, double amin, double amid, double amax)
+    {
+        setConverter(fAcc, p, acc, curve, amin, amid, amax);
+    }
+
+    /**
+     * Used to edit gyroscope curves and mapping. Set curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param acc - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope (-1 means "no
+     * mapping")
+     * @param curve - between 0 and 3
+     * @param amin - mapping 'min' point
+     * @param amid - mapping 'middle' point
+     * @param amax - mapping 'max' point
+     *
+     */
+    void setGyrConverter(int p, int gyr, int curve, double amin, double amid, double amax)
+    {
+        setConverter(fGyr, p, gyr, curve, amin, amid, amax);
+    }
+
+    /**
+     * Used to edit accelerometer curves and mapping. Get curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param acc - the acc value to be retrieved (-1 means "no mapping")
+     * @param curve - the curve value to be retrieved
+     * @param amin - the amin value to be retrieved
+     * @param amid - the amid value to be retrieved
+     * @param amax - the amax value to be retrieved
+     *
+     */
+    void getAccConverter(int p, int& acc, int& curve, double& amin, double& amid,
+                         double& amax)
+    {
+        getConverter(fAcc, p, acc, curve, amin, amid, amax);
+    }
+
+    /**
+     * Used to edit gyroscope curves and mapping. Get curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param gyr - the gyr value to be retrieved (-1 means "no mapping")
+     * @param curve - the curve value to be retrieved
+     * @param amin - the amin value to be retrieved
+     * @param amid - the amid value to be retrieved
+     * @param amax - the amax value to be retrieved
+     *
+     */
+    void getGyrConverter(int p, int& gyr, int& curve, double& amin, double& amid,
+                         double& amax)
+    {
+        getConverter(fGyr, p, gyr, curve, amin, amid, amax);
+    }
+
+    /**
+     * Set a new value coming from an gyroscope, propagate it to all relevant FAUSTFLOAT*
+     * zones.
+     *
+     * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+     * @param value - the new value
+     *
+     */
+    void propagateGyr(int gyr, double value)
+    {
+        for (size_t i = 0; i < fGyr[gyr].size(); i++) { fGyr[gyr][i]->update(value); }
+    }
+
+    /**
+     * Get the number of FAUSTFLOAT* zones controlled with the accelerometer
+     *
+     * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+     * @return the number of zones
+     *
+     */
+    int getAccCount(int acc) { return (acc >= 0 && acc < 3) ? int(fAcc[acc].size()) : 0; }
+
+    /**
+     * Get the number of FAUSTFLOAT* zones controlled with the gyroscope
+     *
+     * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+     * @param the number of zones
+     *
+     */
+    int getGyrCount(int gyr) { return (gyr >= 0 && gyr < 3) ? int(fGyr[gyr].size()) : 0; }
+
+    // getScreenColor() : -1 means no screen color control (no screencolor metadata found)
+    // otherwise return 0x00RRGGBB a ready to use color
+    int getScreenColor()
+    {
+        if (fHasScreenControl) {
+            int r = (fRedReader) ? fRedReader->getValue() : 0;
+            int g = (fGreenReader) ? fGreenReader->getValue() : 0;
+            int b = (fBlueReader) ? fBlueReader->getValue() : 0;
+            return (r << 16) | (g << 8) | b;
+        } else {
+            return -1;
+        }
+    }
 };
 
 #endif
@@ -1553,616 +1587,508 @@ class APIUI : public PathBuilder, public Meta, public UI
 //  FAUST Generated Code
 //----------------------------------------------------------------------------
 
-
 #ifndef FAUSTFLOAT
 #define FAUSTFLOAT float
-#endif 
+#endif
 
 #include <algorithm>
 #include <cmath>
-#include <math.h>
 
-
-#ifndef FAUSTCLASS 
+#ifndef FAUSTCLASS
 #define FAUSTCLASS freeverbdsp
 #endif
 
-#ifdef __APPLE__ 
+#ifdef __APPLE__
 #define exp10f __exp10f
-#define exp10 __exp10
+#define exp10  __exp10
 #endif
 
-class freeverbdsp : public dsp {
-       
- private:
-       
-       int fSampleRate;
-       float fConst0;
-       float fConst1;
-       FAUSTFLOAT fVslider0;
-       float fConst2;
-       FAUSTFLOAT fVslider1;
-       float fRec9[2];
-       FAUSTFLOAT fVslider2;
-       int IOTA;
-       float fVec0[8192];
-       int iConst3;
-       float fRec8[2];
-       float fRec11[2];
-       float fVec1[8192];
-       int iConst4;
-       float fRec10[2];
-       float fRec13[2];
-       float fVec2[8192];
-       int iConst5;
-       float fRec12[2];
-       float fRec15[2];
-       float fVec3[8192];
-       int iConst6;
-       float fRec14[2];
-       float fRec17[2];
-       float fVec4[8192];
-       int iConst7;
-       float fRec16[2];
-       float fRec19[2];
-       float fVec5[8192];
-       int iConst8;
-       float fRec18[2];
-       float fRec21[2];
-       float fVec6[8192];
-       int iConst9;
-       float fRec20[2];
-       float fRec23[2];
-       float fVec7[8192];
-       int iConst10;
-       float fRec22[2];
-       float fVec8[2048];
-       int iConst11;
-       int iConst12;
-       float fRec6[2];
-       float fVec9[2048];
-       int iConst13;
-       int iConst14;
-       float fRec4[2];
-       float fVec10[2048];
-       int iConst15;
-       int iConst16;
-       float fRec2[2];
-       float fVec11[1024];
-       int iConst17;
-       int iConst18;
-       float fRec0[2];
-       float fRec33[2];
-       float fVec12[8192];
-       float fConst19;
-       FAUSTFLOAT fVslider3;
-       float fRec32[2];
-       float fRec35[2];
-       float fVec13[8192];
-       float fRec34[2];
-       float fRec37[2];
-       float fVec14[8192];
-       float fRec36[2];
-       float fRec39[2];
-       float fVec15[8192];
-       float fRec38[2];
-       float fRec41[2];
-       float fVec16[8192];
-       float fRec40[2];
-       float fRec43[2];
-       float fVec17[8192];
-       float fRec42[2];
-       float fRec45[2];
-       float fVec18[8192];
-       float fRec44[2];
-       float fRec47[2];
-       float fVec19[8192];
-       float fRec46[2];
-       float fVec20[2048];
-       float fRec30[2];
-       float fVec21[2048];
-       float fRec28[2];
-       float fVec22[2048];
-       float fRec26[2];
-       float fVec23[2048];
-       float fRec24[2];
-       
- public:
-       
-       void metadata(Meta* m) { 
-               m->declare("author", "Romain Michon");
-               m->declare("delays.lib/name", "Faust Delay Library");
-               m->declare("delays.lib/version", "0.1");
-               m->declare("description", "Freeverb implementation in Faust, from the Faust Library's dm.freeverb_demo in demos.lib");
-               m->declare("filename", "freeverbdsp.dsp");
-               m->declare("filters.lib/allpass_comb:author", "Julius O. Smith III");
-               m->declare("filters.lib/allpass_comb:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
-               m->declare("filters.lib/allpass_comb:license", "MIT-style STK-4.3 license");
-               m->declare("filters.lib/lowpass0_highpass1", "MIT-style STK-4.3 license");
-               m->declare("filters.lib/name", "Faust Filters Library");
-               m->declare("license", "LGPL");
-               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.3");
-               m->declare("name", "freeverb");
-               m->declare("platform.lib/name", "Generic Platform Library");
-               m->declare("platform.lib/version", "0.1");
-               m->declare("reverbs.lib/name", "Faust Reverb Library");
-               m->declare("reverbs.lib/version", "0.0");
-               m->declare("version", "0.0");
-       }
-
-       virtual int getNumInputs() {
-               return 2;
-       }
-       virtual int getNumOutputs() {
-               return 2;
-       }
-       virtual int getInputRate(int channel) {
-               int rate;
-               switch ((channel)) {
-                       case 0: {
-                               rate = 1;
-                               break;
-                       }
-                       case 1: {
-                               rate = 1;
-                               break;
-                       }
-                       default: {
-                               rate = -1;
-                               break;
-                       }
-               }
-               return rate;
-       }
-       virtual int getOutputRate(int channel) {
-               int rate;
-               switch ((channel)) {
-                       case 0: {
-                               rate = 1;
-                               break;
-                       }
-                       case 1: {
-                               rate = 1;
-                               break;
-                       }
-                       default: {
-                               rate = -1;
-                               break;
-                       }
-               }
-               return rate;
-       }
-       
-       static void classInit(int sample_rate) {
-       }
-       
-       virtual void instanceConstants(int sample_rate) {
-               fSampleRate = sample_rate;
-               fConst0 = std::min<float>(192000.0f, std::max<float>(1.0f, float(fSampleRate)));
-               fConst1 = (12348.0f / fConst0);
-               fConst2 = (17640.0f / fConst0);
-               iConst3 = int((0.0253061224f * fConst0));
-               iConst4 = int((0.0269387756f * fConst0));
-               iConst5 = int((0.0289569162f * fConst0));
-               iConst6 = int((0.0307482984f * fConst0));
-               iConst7 = int((0.0322448984f * fConst0));
-               iConst8 = int((0.033809524f * fConst0));
-               iConst9 = int((0.0353061222f * fConst0));
-               iConst10 = int((0.0366666652f * fConst0));
-               iConst11 = int((0.0126077095f * fConst0));
-               iConst12 = std::min<int>(1024, std::max<int>(0, (iConst11 + -1)));
-               iConst13 = int((0.00999999978f * fConst0));
-               iConst14 = std::min<int>(1024, std::max<int>(0, (iConst13 + -1)));
-               iConst15 = int((0.00773242628f * fConst0));
-               iConst16 = std::min<int>(1024, std::max<int>(0, (iConst15 + -1)));
-               iConst17 = int((0.00510204071f * fConst0));
-               iConst18 = std::min<int>(1024, std::max<int>(0, (iConst17 + -1)));
-               fConst19 = (0.00104308384f * fConst0);
-       }
-       
-       virtual void instanceResetUserInterface() {
-               fVslider0 = FAUSTFLOAT(0.10000000000000001f);
-               fVslider1 = FAUSTFLOAT(0.5f);
-               fVslider2 = FAUSTFLOAT(0.10000000000000001f);
-               fVslider3 = FAUSTFLOAT(0.5f);
-       }
-       
-       virtual void instanceClear() {
-               for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) {
-                       fRec9[l0] = 0.0f;
-               }
-               IOTA = 0;
-               for (int l1 = 0; (l1 < 8192); l1 = (l1 + 1)) {
-                       fVec0[l1] = 0.0f;
-               }
-               for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) {
-                       fRec8[l2] = 0.0f;
-               }
-               for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) {
-                       fRec11[l3] = 0.0f;
-               }
-               for (int l4 = 0; (l4 < 8192); l4 = (l4 + 1)) {
-                       fVec1[l4] = 0.0f;
-               }
-               for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) {
-                       fRec10[l5] = 0.0f;
-               }
-               for (int l6 = 0; (l6 < 2); l6 = (l6 + 1)) {
-                       fRec13[l6] = 0.0f;
-               }
-               for (int l7 = 0; (l7 < 8192); l7 = (l7 + 1)) {
-                       fVec2[l7] = 0.0f;
-               }
-               for (int l8 = 0; (l8 < 2); l8 = (l8 + 1)) {
-                       fRec12[l8] = 0.0f;
-               }
-               for (int l9 = 0; (l9 < 2); l9 = (l9 + 1)) {
-                       fRec15[l9] = 0.0f;
-               }
-               for (int l10 = 0; (l10 < 8192); l10 = (l10 + 1)) {
-                       fVec3[l10] = 0.0f;
-               }
-               for (int l11 = 0; (l11 < 2); l11 = (l11 + 1)) {
-                       fRec14[l11] = 0.0f;
-               }
-               for (int l12 = 0; (l12 < 2); l12 = (l12 + 1)) {
-                       fRec17[l12] = 0.0f;
-               }
-               for (int l13 = 0; (l13 < 8192); l13 = (l13 + 1)) {
-                       fVec4[l13] = 0.0f;
-               }
-               for (int l14 = 0; (l14 < 2); l14 = (l14 + 1)) {
-                       fRec16[l14] = 0.0f;
-               }
-               for (int l15 = 0; (l15 < 2); l15 = (l15 + 1)) {
-                       fRec19[l15] = 0.0f;
-               }
-               for (int l16 = 0; (l16 < 8192); l16 = (l16 + 1)) {
-                       fVec5[l16] = 0.0f;
-               }
-               for (int l17 = 0; (l17 < 2); l17 = (l17 + 1)) {
-                       fRec18[l17] = 0.0f;
-               }
-               for (int l18 = 0; (l18 < 2); l18 = (l18 + 1)) {
-                       fRec21[l18] = 0.0f;
-               }
-               for (int l19 = 0; (l19 < 8192); l19 = (l19 + 1)) {
-                       fVec6[l19] = 0.0f;
-               }
-               for (int l20 = 0; (l20 < 2); l20 = (l20 + 1)) {
-                       fRec20[l20] = 0.0f;
-               }
-               for (int l21 = 0; (l21 < 2); l21 = (l21 + 1)) {
-                       fRec23[l21] = 0.0f;
-               }
-               for (int l22 = 0; (l22 < 8192); l22 = (l22 + 1)) {
-                       fVec7[l22] = 0.0f;
-               }
-               for (int l23 = 0; (l23 < 2); l23 = (l23 + 1)) {
-                       fRec22[l23] = 0.0f;
-               }
-               for (int l24 = 0; (l24 < 2048); l24 = (l24 + 1)) {
-                       fVec8[l24] = 0.0f;
-               }
-               for (int l25 = 0; (l25 < 2); l25 = (l25 + 1)) {
-                       fRec6[l25] = 0.0f;
-               }
-               for (int l26 = 0; (l26 < 2048); l26 = (l26 + 1)) {
-                       fVec9[l26] = 0.0f;
-               }
-               for (int l27 = 0; (l27 < 2); l27 = (l27 + 1)) {
-                       fRec4[l27] = 0.0f;
-               }
-               for (int l28 = 0; (l28 < 2048); l28 = (l28 + 1)) {
-                       fVec10[l28] = 0.0f;
-               }
-               for (int l29 = 0; (l29 < 2); l29 = (l29 + 1)) {
-                       fRec2[l29] = 0.0f;
-               }
-               for (int l30 = 0; (l30 < 1024); l30 = (l30 + 1)) {
-                       fVec11[l30] = 0.0f;
-               }
-               for (int l31 = 0; (l31 < 2); l31 = (l31 + 1)) {
-                       fRec0[l31] = 0.0f;
-               }
-               for (int l32 = 0; (l32 < 2); l32 = (l32 + 1)) {
-                       fRec33[l32] = 0.0f;
-               }
-               for (int l33 = 0; (l33 < 8192); l33 = (l33 + 1)) {
-                       fVec12[l33] = 0.0f;
-               }
-               for (int l34 = 0; (l34 < 2); l34 = (l34 + 1)) {
-                       fRec32[l34] = 0.0f;
-               }
-               for (int l35 = 0; (l35 < 2); l35 = (l35 + 1)) {
-                       fRec35[l35] = 0.0f;
-               }
-               for (int l36 = 0; (l36 < 8192); l36 = (l36 + 1)) {
-                       fVec13[l36] = 0.0f;
-               }
-               for (int l37 = 0; (l37 < 2); l37 = (l37 + 1)) {
-                       fRec34[l37] = 0.0f;
-               }
-               for (int l38 = 0; (l38 < 2); l38 = (l38 + 1)) {
-                       fRec37[l38] = 0.0f;
-               }
-               for (int l39 = 0; (l39 < 8192); l39 = (l39 + 1)) {
-                       fVec14[l39] = 0.0f;
-               }
-               for (int l40 = 0; (l40 < 2); l40 = (l40 + 1)) {
-                       fRec36[l40] = 0.0f;
-               }
-               for (int l41 = 0; (l41 < 2); l41 = (l41 + 1)) {
-                       fRec39[l41] = 0.0f;
-               }
-               for (int l42 = 0; (l42 < 8192); l42 = (l42 + 1)) {
-                       fVec15[l42] = 0.0f;
-               }
-               for (int l43 = 0; (l43 < 2); l43 = (l43 + 1)) {
-                       fRec38[l43] = 0.0f;
-               }
-               for (int l44 = 0; (l44 < 2); l44 = (l44 + 1)) {
-                       fRec41[l44] = 0.0f;
-               }
-               for (int l45 = 0; (l45 < 8192); l45 = (l45 + 1)) {
-                       fVec16[l45] = 0.0f;
-               }
-               for (int l46 = 0; (l46 < 2); l46 = (l46 + 1)) {
-                       fRec40[l46] = 0.0f;
-               }
-               for (int l47 = 0; (l47 < 2); l47 = (l47 + 1)) {
-                       fRec43[l47] = 0.0f;
-               }
-               for (int l48 = 0; (l48 < 8192); l48 = (l48 + 1)) {
-                       fVec17[l48] = 0.0f;
-               }
-               for (int l49 = 0; (l49 < 2); l49 = (l49 + 1)) {
-                       fRec42[l49] = 0.0f;
-               }
-               for (int l50 = 0; (l50 < 2); l50 = (l50 + 1)) {
-                       fRec45[l50] = 0.0f;
-               }
-               for (int l51 = 0; (l51 < 8192); l51 = (l51 + 1)) {
-                       fVec18[l51] = 0.0f;
-               }
-               for (int l52 = 0; (l52 < 2); l52 = (l52 + 1)) {
-                       fRec44[l52] = 0.0f;
-               }
-               for (int l53 = 0; (l53 < 2); l53 = (l53 + 1)) {
-                       fRec47[l53] = 0.0f;
-               }
-               for (int l54 = 0; (l54 < 8192); l54 = (l54 + 1)) {
-                       fVec19[l54] = 0.0f;
-               }
-               for (int l55 = 0; (l55 < 2); l55 = (l55 + 1)) {
-                       fRec46[l55] = 0.0f;
-               }
-               for (int l56 = 0; (l56 < 2048); l56 = (l56 + 1)) {
-                       fVec20[l56] = 0.0f;
-               }
-               for (int l57 = 0; (l57 < 2); l57 = (l57 + 1)) {
-                       fRec30[l57] = 0.0f;
-               }
-               for (int l58 = 0; (l58 < 2048); l58 = (l58 + 1)) {
-                       fVec21[l58] = 0.0f;
-               }
-               for (int l59 = 0; (l59 < 2); l59 = (l59 + 1)) {
-                       fRec28[l59] = 0.0f;
-               }
-               for (int l60 = 0; (l60 < 2048); l60 = (l60 + 1)) {
-                       fVec22[l60] = 0.0f;
-               }
-               for (int l61 = 0; (l61 < 2); l61 = (l61 + 1)) {
-                       fRec26[l61] = 0.0f;
-               }
-               for (int l62 = 0; (l62 < 2048); l62 = (l62 + 1)) {
-                       fVec23[l62] = 0.0f;
-               }
-               for (int l63 = 0; (l63 < 2); l63 = (l63 + 1)) {
-                       fRec24[l63] = 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 freeverbdsp* clone() {
-               return new freeverbdsp();
-       }
-       
-       virtual int getSampleRate() {
-               return fSampleRate;
-       }
-       
-       virtual void buildUserInterface(UI* ui_interface) {
-               ui_interface->openHorizontalBox("Freeverb");
-               ui_interface->declare(0, "0", "");
-               ui_interface->openVerticalBox("0x00");
-               ui_interface->declare(&fVslider1, "0", "");
-               ui_interface->declare(&fVslider1, "style", "knob");
-               ui_interface->declare(&fVslider1, "tooltip", "Somehow control the   density of the reverb.");
-               ui_interface->addVerticalSlider("Damp", &fVslider1, 0.5f, 0.0f, 1.0f, 0.0250000004f);
-               ui_interface->declare(&fVslider0, "1", "");
-               ui_interface->declare(&fVslider0, "style", "knob");
-               ui_interface->declare(&fVslider0, "tooltip", "The room size   between 0 and 1 with 1 for the largest room.");
-               ui_interface->addVerticalSlider("RoomSize", &fVslider0, 0.100000001f, 0.0f, 1.0f, 0.0250000004f);
-               ui_interface->declare(&fVslider3, "2", "");
-               ui_interface->declare(&fVslider3, "style", "knob");
-               ui_interface->declare(&fVslider3, "tooltip", "Spatial   spread between 0 and 1 with 1 for maximum spread.");
-               ui_interface->addVerticalSlider("Stereo Spread", &fVslider3, 0.5f, 0.0f, 1.0f, 0.00999999978f);
-               ui_interface->closeBox();
-               ui_interface->declare(&fVslider2, "1", "");
-               ui_interface->declare(&fVslider2, "tooltip", "The amount of reverb applied to the signal   between 0 and 1 with 1 for the maximum amount of reverb.");
-               ui_interface->addVerticalSlider("Wet", &fVslider2, 0.100000001f, 0.0f, 1.0f, 0.0250000004f);
-               ui_interface->closeBox();
-       }
-       
-       virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
-               FAUSTFLOAT* input0 = inputs[0];
-               FAUSTFLOAT* input1 = inputs[1];
-               FAUSTFLOAT* output0 = outputs[0];
-               FAUSTFLOAT* output1 = outputs[1];
-               float fSlow0 = ((fConst1 * float(fVslider0)) + 0.699999988f);
-               float fSlow1 = (fConst2 * float(fVslider1));
-               float fSlow2 = (1.0f - fSlow1);
-               float fSlow3 = float(fVslider2);
-               float fSlow4 = (0.100000001f * fSlow3);
-               float fSlow5 = (1.0f - fSlow3);
-               int iSlow6 = int((fConst19 * float(fVslider3)));
-               int iSlow7 = (iConst3 + iSlow6);
-               int iSlow8 = (iConst4 + iSlow6);
-               int iSlow9 = (iConst5 + iSlow6);
-               int iSlow10 = (iConst6 + iSlow6);
-               int iSlow11 = (iConst7 + iSlow6);
-               int iSlow12 = (iConst8 + iSlow6);
-               int iSlow13 = (iConst9 + iSlow6);
-               int iSlow14 = (iConst10 + iSlow6);
-               int iSlow15 = (iSlow6 + -1);
-               int iSlow16 = std::min<int>(1024, std::max<int>(0, (iConst11 + iSlow15)));
-               int iSlow17 = std::min<int>(1024, std::max<int>(0, (iConst13 + iSlow15)));
-               int iSlow18 = std::min<int>(1024, std::max<int>(0, (iConst15 + iSlow15)));
-               int iSlow19 = std::min<int>(1024, std::max<int>(0, (iConst17 + iSlow15)));
-               for (int i = 0; (i < count); i = (i + 1)) {
-                       float fTemp0 = float(input0[i]);
-                       float fTemp1 = float(input1[i]);
-                       fRec9[0] = ((fSlow1 * fRec9[1]) + (fSlow2 * fRec8[1]));
-                       float fTemp2 = (fSlow4 * (fTemp0 + fTemp1));
-                       fVec0[(IOTA & 8191)] = ((fSlow0 * fRec9[0]) + fTemp2);
-                       fRec8[0] = fVec0[((IOTA - iConst3) & 8191)];
-                       fRec11[0] = ((fSlow1 * fRec11[1]) + (fSlow2 * fRec10[1]));
-                       fVec1[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec11[0]));
-                       fRec10[0] = fVec1[((IOTA - iConst4) & 8191)];
-                       fRec13[0] = ((fSlow1 * fRec13[1]) + (fSlow2 * fRec12[1]));
-                       fVec2[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec13[0]));
-                       fRec12[0] = fVec2[((IOTA - iConst5) & 8191)];
-                       fRec15[0] = ((fSlow1 * fRec15[1]) + (fSlow2 * fRec14[1]));
-                       fVec3[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec15[0]));
-                       fRec14[0] = fVec3[((IOTA - iConst6) & 8191)];
-                       fRec17[0] = ((fSlow1 * fRec17[1]) + (fSlow2 * fRec16[1]));
-                       fVec4[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec17[0]));
-                       fRec16[0] = fVec4[((IOTA - iConst7) & 8191)];
-                       fRec19[0] = ((fSlow1 * fRec19[1]) + (fSlow2 * fRec18[1]));
-                       fVec5[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec19[0]));
-                       fRec18[0] = fVec5[((IOTA - iConst8) & 8191)];
-                       fRec21[0] = ((fSlow1 * fRec21[1]) + (fSlow2 * fRec20[1]));
-                       fVec6[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec21[0]));
-                       fRec20[0] = fVec6[((IOTA - iConst9) & 8191)];
-                       fRec23[0] = ((fSlow1 * fRec23[1]) + (fSlow2 * fRec22[1]));
-                       fVec7[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec23[0]));
-                       fRec22[0] = fVec7[((IOTA - iConst10) & 8191)];
-                       float fTemp3 = ((((((((fRec8[0] + fRec10[0]) + fRec12[0]) + fRec14[0]) + fRec16[0]) + fRec18[0]) + fRec20[0]) + fRec22[0]) + (0.5f * fRec6[1]));
-                       fVec8[(IOTA & 2047)] = fTemp3;
-                       fRec6[0] = fVec8[((IOTA - iConst12) & 2047)];
-                       float fRec7 = (0.0f - (0.5f * fTemp3));
-                       float fTemp4 = (fRec6[1] + (fRec7 + (0.5f * fRec4[1])));
-                       fVec9[(IOTA & 2047)] = fTemp4;
-                       fRec4[0] = fVec9[((IOTA - iConst14) & 2047)];
-                       float fRec5 = (0.0f - (0.5f * fTemp4));
-                       float fTemp5 = (fRec4[1] + (fRec5 + (0.5f * fRec2[1])));
-                       fVec10[(IOTA & 2047)] = fTemp5;
-                       fRec2[0] = fVec10[((IOTA - iConst16) & 2047)];
-                       float fRec3 = (0.0f - (0.5f * fTemp5));
-                       float fTemp6 = (fRec2[1] + (fRec3 + (0.5f * fRec0[1])));
-                       fVec11[(IOTA & 1023)] = fTemp6;
-                       fRec0[0] = fVec11[((IOTA - iConst18) & 1023)];
-                       float fRec1 = (0.0f - (0.5f * fTemp6));
-                       output0[i] = FAUSTFLOAT(((fRec1 + fRec0[1]) + (fSlow5 * fTemp0)));
-                       fRec33[0] = ((fSlow1 * fRec33[1]) + (fSlow2 * fRec32[1]));
-                       fVec12[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec33[0]));
-                       fRec32[0] = fVec12[((IOTA - iSlow7) & 8191)];
-                       fRec35[0] = ((fSlow1 * fRec35[1]) + (fSlow2 * fRec34[1]));
-                       fVec13[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec35[0]));
-                       fRec34[0] = fVec13[((IOTA - iSlow8) & 8191)];
-                       fRec37[0] = ((fSlow1 * fRec37[1]) + (fSlow2 * fRec36[1]));
-                       fVec14[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec37[0]));
-                       fRec36[0] = fVec14[((IOTA - iSlow9) & 8191)];
-                       fRec39[0] = ((fSlow1 * fRec39[1]) + (fSlow2 * fRec38[1]));
-                       fVec15[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec39[0]));
-                       fRec38[0] = fVec15[((IOTA - iSlow10) & 8191)];
-                       fRec41[0] = ((fSlow1 * fRec41[1]) + (fSlow2 * fRec40[1]));
-                       fVec16[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec41[0]));
-                       fRec40[0] = fVec16[((IOTA - iSlow11) & 8191)];
-                       fRec43[0] = ((fSlow1 * fRec43[1]) + (fSlow2 * fRec42[1]));
-                       fVec17[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec43[0]));
-                       fRec42[0] = fVec17[((IOTA - iSlow12) & 8191)];
-                       fRec45[0] = ((fSlow1 * fRec45[1]) + (fSlow2 * fRec44[1]));
-                       fVec18[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec45[0]));
-                       fRec44[0] = fVec18[((IOTA - iSlow13) & 8191)];
-                       fRec47[0] = ((fSlow1 * fRec47[1]) + (fSlow2 * fRec46[1]));
-                       fVec19[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec47[0]));
-                       fRec46[0] = fVec19[((IOTA - iSlow14) & 8191)];
-                       float fTemp7 = ((((((((fRec32[0] + fRec34[0]) + fRec36[0]) + fRec38[0]) + fRec40[0]) + fRec42[0]) + fRec44[0]) + fRec46[0]) + (0.5f * fRec30[1]));
-                       fVec20[(IOTA & 2047)] = fTemp7;
-                       fRec30[0] = fVec20[((IOTA - iSlow16) & 2047)];
-                       float fRec31 = (0.0f - (0.5f * fTemp7));
-                       float fTemp8 = (fRec30[1] + (fRec31 + (0.5f * fRec28[1])));
-                       fVec21[(IOTA & 2047)] = fTemp8;
-                       fRec28[0] = fVec21[((IOTA - iSlow17) & 2047)];
-                       float fRec29 = (0.0f - (0.5f * fTemp8));
-                       float fTemp9 = (fRec28[1] + (fRec29 + (0.5f * fRec26[1])));
-                       fVec22[(IOTA & 2047)] = fTemp9;
-                       fRec26[0] = fVec22[((IOTA - iSlow18) & 2047)];
-                       float fRec27 = (0.0f - (0.5f * fTemp9));
-                       float fTemp10 = (fRec26[1] + (fRec27 + (0.5f * fRec24[1])));
-                       fVec23[(IOTA & 2047)] = fTemp10;
-                       fRec24[0] = fVec23[((IOTA - iSlow19) & 2047)];
-                       float fRec25 = (0.0f - (0.5f * fTemp10));
-                       output1[i] = FAUSTFLOAT(((fRec25 + fRec24[1]) + (fSlow5 * fTemp1)));
-                       fRec9[1] = fRec9[0];
-                       IOTA = (IOTA + 1);
-                       fRec8[1] = fRec8[0];
-                       fRec11[1] = fRec11[0];
-                       fRec10[1] = fRec10[0];
-                       fRec13[1] = fRec13[0];
-                       fRec12[1] = fRec12[0];
-                       fRec15[1] = fRec15[0];
-                       fRec14[1] = fRec14[0];
-                       fRec17[1] = fRec17[0];
-                       fRec16[1] = fRec16[0];
-                       fRec19[1] = fRec19[0];
-                       fRec18[1] = fRec18[0];
-                       fRec21[1] = fRec21[0];
-                       fRec20[1] = fRec20[0];
-                       fRec23[1] = fRec23[0];
-                       fRec22[1] = fRec22[0];
-                       fRec6[1] = fRec6[0];
-                       fRec4[1] = fRec4[0];
-                       fRec2[1] = fRec2[0];
-                       fRec0[1] = fRec0[0];
-                       fRec33[1] = fRec33[0];
-                       fRec32[1] = fRec32[0];
-                       fRec35[1] = fRec35[0];
-                       fRec34[1] = fRec34[0];
-                       fRec37[1] = fRec37[0];
-                       fRec36[1] = fRec36[0];
-                       fRec39[1] = fRec39[0];
-                       fRec38[1] = fRec38[0];
-                       fRec41[1] = fRec41[0];
-                       fRec40[1] = fRec40[0];
-                       fRec43[1] = fRec43[0];
-                       fRec42[1] = fRec42[0];
-                       fRec45[1] = fRec45[0];
-                       fRec44[1] = fRec44[0];
-                       fRec47[1] = fRec47[0];
-                       fRec46[1] = fRec46[0];
-                       fRec30[1] = fRec30[0];
-                       fRec28[1] = fRec28[0];
-                       fRec26[1] = fRec26[0];
-                       fRec24[1] = fRec24[0];
-               }
-       }
-
+class freeverbdsp : public dsp
+{
+   private:
+    int fSampleRate;
+    float fConst0;
+    float fConst1;
+    FAUSTFLOAT fVslider0;
+    float fConst2;
+    FAUSTFLOAT fVslider1;
+    float fRec9[2];
+    FAUSTFLOAT fVslider2;
+    int IOTA;
+    float fVec0[8192];
+    int iConst3;
+    float fRec8[2];
+    float fRec11[2];
+    float fVec1[8192];
+    int iConst4;
+    float fRec10[2];
+    float fRec13[2];
+    float fVec2[8192];
+    int iConst5;
+    float fRec12[2];
+    float fRec15[2];
+    float fVec3[8192];
+    int iConst6;
+    float fRec14[2];
+    float fRec17[2];
+    float fVec4[8192];
+    int iConst7;
+    float fRec16[2];
+    float fRec19[2];
+    float fVec5[8192];
+    int iConst8;
+    float fRec18[2];
+    float fRec21[2];
+    float fVec6[8192];
+    int iConst9;
+    float fRec20[2];
+    float fRec23[2];
+    float fVec7[8192];
+    int iConst10;
+    float fRec22[2];
+    float fVec8[2048];
+    int iConst11;
+    int iConst12;
+    float fRec6[2];
+    float fVec9[2048];
+    int iConst13;
+    int iConst14;
+    float fRec4[2];
+    float fVec10[2048];
+    int iConst15;
+    int iConst16;
+    float fRec2[2];
+    float fVec11[1024];
+    int iConst17;
+    int iConst18;
+    float fRec0[2];
+    float fRec33[2];
+    float fVec12[8192];
+    float fConst19;
+    FAUSTFLOAT fVslider3;
+    float fRec32[2];
+    float fRec35[2];
+    float fVec13[8192];
+    float fRec34[2];
+    float fRec37[2];
+    float fVec14[8192];
+    float fRec36[2];
+    float fRec39[2];
+    float fVec15[8192];
+    float fRec38[2];
+    float fRec41[2];
+    float fVec16[8192];
+    float fRec40[2];
+    float fRec43[2];
+    float fVec17[8192];
+    float fRec42[2];
+    float fRec45[2];
+    float fVec18[8192];
+    float fRec44[2];
+    float fRec47[2];
+    float fVec19[8192];
+    float fRec46[2];
+    float fVec20[2048];
+    float fRec30[2];
+    float fVec21[2048];
+    float fRec28[2];
+    float fVec22[2048];
+    float fRec26[2];
+    float fVec23[2048];
+    float fRec24[2];
+
+   public:
+    void metadata(Meta* m)
+    {
+        m->declare("author", "Romain Michon");
+        m->declare("delays.lib/name", "Faust Delay Library");
+        m->declare("delays.lib/version", "0.1");
+        m->declare("description",
+                   "Freeverb implementation in Faust, from the Faust Library's "
+                   "dm.freeverb_demo in demos.lib");
+        m->declare("filename", "freeverbdsp.dsp");
+        m->declare("filters.lib/allpass_comb:author", "Julius O. Smith III");
+        m->declare(
+            "filters.lib/allpass_comb:copyright",
+            "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+        m->declare("filters.lib/allpass_comb:license", "MIT-style STK-4.3 license");
+        m->declare("filters.lib/lowpass0_highpass1", "MIT-style STK-4.3 license");
+        m->declare("filters.lib/name", "Faust Filters Library");
+        m->declare("license", "LGPL");
+        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.3");
+        m->declare("name", "freeverb");
+        m->declare("platform.lib/name", "Generic Platform Library");
+        m->declare("platform.lib/version", "0.1");
+        m->declare("reverbs.lib/name", "Faust Reverb Library");
+        m->declare("reverbs.lib/version", "0.0");
+        m->declare("version", "0.0");
+    }
+
+    virtual int getNumInputs() { return 2; }
+    virtual int getNumOutputs() { return 2; }
+    virtual int getInputRate(int channel)
+    {
+        int rate;
+        switch ((channel)) {
+        case 0: {
+            rate = 1;
+            break;
+        }
+        case 1: {
+            rate = 1;
+            break;
+        }
+        default: {
+            rate = -1;
+            break;
+        }
+        }
+        return rate;
+    }
+    virtual int getOutputRate(int channel)
+    {
+        int rate;
+        switch ((channel)) {
+        case 0: {
+            rate = 1;
+            break;
+        }
+        case 1: {
+            rate = 1;
+            break;
+        }
+        default: {
+            rate = -1;
+            break;
+        }
+        }
+        return rate;
+    }
+
+    static void classInit(int /*sample_rate*/) {}
+
+    virtual void instanceConstants(int sample_rate)
+    {
+        fSampleRate = sample_rate;
+        fConst0  = std::min<float>(192000.0f, std::max<float>(1.0f, float(fSampleRate)));
+        fConst1  = (12348.0f / fConst0);
+        fConst2  = (17640.0f / fConst0);
+        iConst3  = int((0.0253061224f * fConst0));
+        iConst4  = int((0.0269387756f * fConst0));
+        iConst5  = int((0.0289569162f * fConst0));
+        iConst6  = int((0.0307482984f * fConst0));
+        iConst7  = int((0.0322448984f * fConst0));
+        iConst8  = int((0.033809524f * fConst0));
+        iConst9  = int((0.0353061222f * fConst0));
+        iConst10 = int((0.0366666652f * fConst0));
+        iConst11 = int((0.0126077095f * fConst0));
+        iConst12 = std::min<int>(1024, std::max<int>(0, (iConst11 + -1)));
+        iConst13 = int((0.00999999978f * fConst0));
+        iConst14 = std::min<int>(1024, std::max<int>(0, (iConst13 + -1)));
+        iConst15 = int((0.00773242628f * fConst0));
+        iConst16 = std::min<int>(1024, std::max<int>(0, (iConst15 + -1)));
+        iConst17 = int((0.00510204071f * fConst0));
+        iConst18 = std::min<int>(1024, std::max<int>(0, (iConst17 + -1)));
+        fConst19 = (0.00104308384f * fConst0);
+    }
+
+    virtual void instanceResetUserInterface()
+    {
+        fVslider0 = FAUSTFLOAT(0.10000000000000001f);
+        fVslider1 = FAUSTFLOAT(0.5f);
+        fVslider2 = FAUSTFLOAT(0.10000000000000001f);
+        fVslider3 = FAUSTFLOAT(0.5f);
+    }
+
+    virtual void instanceClear()
+    {
+        for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec9[l0] = 0.0f; }
+        IOTA = 0;
+        for (int l1 = 0; (l1 < 8192); l1 = (l1 + 1)) { fVec0[l1] = 0.0f; }
+        for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) { fRec8[l2] = 0.0f; }
+        for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) { fRec11[l3] = 0.0f; }
+        for (int l4 = 0; (l4 < 8192); l4 = (l4 + 1)) { fVec1[l4] = 0.0f; }
+        for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) { fRec10[l5] = 0.0f; }
+        for (int l6 = 0; (l6 < 2); l6 = (l6 + 1)) { fRec13[l6] = 0.0f; }
+        for (int l7 = 0; (l7 < 8192); l7 = (l7 + 1)) { fVec2[l7] = 0.0f; }
+        for (int l8 = 0; (l8 < 2); l8 = (l8 + 1)) { fRec12[l8] = 0.0f; }
+        for (int l9 = 0; (l9 < 2); l9 = (l9 + 1)) { fRec15[l9] = 0.0f; }
+        for (int l10 = 0; (l10 < 8192); l10 = (l10 + 1)) { fVec3[l10] = 0.0f; }
+        for (int l11 = 0; (l11 < 2); l11 = (l11 + 1)) { fRec14[l11] = 0.0f; }
+        for (int l12 = 0; (l12 < 2); l12 = (l12 + 1)) { fRec17[l12] = 0.0f; }
+        for (int l13 = 0; (l13 < 8192); l13 = (l13 + 1)) { fVec4[l13] = 0.0f; }
+        for (int l14 = 0; (l14 < 2); l14 = (l14 + 1)) { fRec16[l14] = 0.0f; }
+        for (int l15 = 0; (l15 < 2); l15 = (l15 + 1)) { fRec19[l15] = 0.0f; }
+        for (int l16 = 0; (l16 < 8192); l16 = (l16 + 1)) { fVec5[l16] = 0.0f; }
+        for (int l17 = 0; (l17 < 2); l17 = (l17 + 1)) { fRec18[l17] = 0.0f; }
+        for (int l18 = 0; (l18 < 2); l18 = (l18 + 1)) { fRec21[l18] = 0.0f; }
+        for (int l19 = 0; (l19 < 8192); l19 = (l19 + 1)) { fVec6[l19] = 0.0f; }
+        for (int l20 = 0; (l20 < 2); l20 = (l20 + 1)) { fRec20[l20] = 0.0f; }
+        for (int l21 = 0; (l21 < 2); l21 = (l21 + 1)) { fRec23[l21] = 0.0f; }
+        for (int l22 = 0; (l22 < 8192); l22 = (l22 + 1)) { fVec7[l22] = 0.0f; }
+        for (int l23 = 0; (l23 < 2); l23 = (l23 + 1)) { fRec22[l23] = 0.0f; }
+        for (int l24 = 0; (l24 < 2048); l24 = (l24 + 1)) { fVec8[l24] = 0.0f; }
+        for (int l25 = 0; (l25 < 2); l25 = (l25 + 1)) { fRec6[l25] = 0.0f; }
+        for (int l26 = 0; (l26 < 2048); l26 = (l26 + 1)) { fVec9[l26] = 0.0f; }
+        for (int l27 = 0; (l27 < 2); l27 = (l27 + 1)) { fRec4[l27] = 0.0f; }
+        for (int l28 = 0; (l28 < 2048); l28 = (l28 + 1)) { fVec10[l28] = 0.0f; }
+        for (int l29 = 0; (l29 < 2); l29 = (l29 + 1)) { fRec2[l29] = 0.0f; }
+        for (int l30 = 0; (l30 < 1024); l30 = (l30 + 1)) { fVec11[l30] = 0.0f; }
+        for (int l31 = 0; (l31 < 2); l31 = (l31 + 1)) { fRec0[l31] = 0.0f; }
+        for (int l32 = 0; (l32 < 2); l32 = (l32 + 1)) { fRec33[l32] = 0.0f; }
+        for (int l33 = 0; (l33 < 8192); l33 = (l33 + 1)) { fVec12[l33] = 0.0f; }
+        for (int l34 = 0; (l34 < 2); l34 = (l34 + 1)) { fRec32[l34] = 0.0f; }
+        for (int l35 = 0; (l35 < 2); l35 = (l35 + 1)) { fRec35[l35] = 0.0f; }
+        for (int l36 = 0; (l36 < 8192); l36 = (l36 + 1)) { fVec13[l36] = 0.0f; }
+        for (int l37 = 0; (l37 < 2); l37 = (l37 + 1)) { fRec34[l37] = 0.0f; }
+        for (int l38 = 0; (l38 < 2); l38 = (l38 + 1)) { fRec37[l38] = 0.0f; }
+        for (int l39 = 0; (l39 < 8192); l39 = (l39 + 1)) { fVec14[l39] = 0.0f; }
+        for (int l40 = 0; (l40 < 2); l40 = (l40 + 1)) { fRec36[l40] = 0.0f; }
+        for (int l41 = 0; (l41 < 2); l41 = (l41 + 1)) { fRec39[l41] = 0.0f; }
+        for (int l42 = 0; (l42 < 8192); l42 = (l42 + 1)) { fVec15[l42] = 0.0f; }
+        for (int l43 = 0; (l43 < 2); l43 = (l43 + 1)) { fRec38[l43] = 0.0f; }
+        for (int l44 = 0; (l44 < 2); l44 = (l44 + 1)) { fRec41[l44] = 0.0f; }
+        for (int l45 = 0; (l45 < 8192); l45 = (l45 + 1)) { fVec16[l45] = 0.0f; }
+        for (int l46 = 0; (l46 < 2); l46 = (l46 + 1)) { fRec40[l46] = 0.0f; }
+        for (int l47 = 0; (l47 < 2); l47 = (l47 + 1)) { fRec43[l47] = 0.0f; }
+        for (int l48 = 0; (l48 < 8192); l48 = (l48 + 1)) { fVec17[l48] = 0.0f; }
+        for (int l49 = 0; (l49 < 2); l49 = (l49 + 1)) { fRec42[l49] = 0.0f; }
+        for (int l50 = 0; (l50 < 2); l50 = (l50 + 1)) { fRec45[l50] = 0.0f; }
+        for (int l51 = 0; (l51 < 8192); l51 = (l51 + 1)) { fVec18[l51] = 0.0f; }
+        for (int l52 = 0; (l52 < 2); l52 = (l52 + 1)) { fRec44[l52] = 0.0f; }
+        for (int l53 = 0; (l53 < 2); l53 = (l53 + 1)) { fRec47[l53] = 0.0f; }
+        for (int l54 = 0; (l54 < 8192); l54 = (l54 + 1)) { fVec19[l54] = 0.0f; }
+        for (int l55 = 0; (l55 < 2); l55 = (l55 + 1)) { fRec46[l55] = 0.0f; }
+        for (int l56 = 0; (l56 < 2048); l56 = (l56 + 1)) { fVec20[l56] = 0.0f; }
+        for (int l57 = 0; (l57 < 2); l57 = (l57 + 1)) { fRec30[l57] = 0.0f; }
+        for (int l58 = 0; (l58 < 2048); l58 = (l58 + 1)) { fVec21[l58] = 0.0f; }
+        for (int l59 = 0; (l59 < 2); l59 = (l59 + 1)) { fRec28[l59] = 0.0f; }
+        for (int l60 = 0; (l60 < 2048); l60 = (l60 + 1)) { fVec22[l60] = 0.0f; }
+        for (int l61 = 0; (l61 < 2); l61 = (l61 + 1)) { fRec26[l61] = 0.0f; }
+        for (int l62 = 0; (l62 < 2048); l62 = (l62 + 1)) { fVec23[l62] = 0.0f; }
+        for (int l63 = 0; (l63 < 2); l63 = (l63 + 1)) { fRec24[l63] = 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 freeverbdsp* clone() { return new freeverbdsp(); }
+
+    virtual int getSampleRate() { return fSampleRate; }
+
+    virtual void buildUserInterface(UI* ui_interface)
+    {
+        ui_interface->openHorizontalBox("Freeverb");
+        ui_interface->declare(0, "0", "");
+        ui_interface->openVerticalBox("0x00");
+        ui_interface->declare(&fVslider1, "0", "");
+        ui_interface->declare(&fVslider1, "style", "knob");
+        ui_interface->declare(&fVslider1, "tooltip",
+                              "Somehow control the   density of the reverb.");
+        ui_interface->addVerticalSlider("Damp", &fVslider1, 0.5f, 0.0f, 1.0f,
+                                        0.0250000004f);
+        ui_interface->declare(&fVslider0, "1", "");
+        ui_interface->declare(&fVslider0, "style", "knob");
+        ui_interface->declare(
+            &fVslider0, "tooltip",
+            "The room size   between 0 and 1 with 1 for the largest room.");
+        ui_interface->addVerticalSlider("RoomSize", &fVslider0, 0.100000001f, 0.0f, 1.0f,
+                                        0.0250000004f);
+        ui_interface->declare(&fVslider3, "2", "");
+        ui_interface->declare(&fVslider3, "style", "knob");
+        ui_interface->declare(
+            &fVslider3, "tooltip",
+            "Spatial   spread between 0 and 1 with 1 for maximum spread.");
+        ui_interface->addVerticalSlider("Stereo Spread", &fVslider3, 0.5f, 0.0f, 1.0f,
+                                        0.00999999978f);
+        ui_interface->closeBox();
+        ui_interface->declare(&fVslider2, "1", "");
+        ui_interface->declare(&fVslider2, "tooltip",
+                              "The amount of reverb applied to the signal   between 0 "
+                              "and 1 with 1 for the maximum amount of reverb.");
+        ui_interface->addVerticalSlider("Wet", &fVslider2, 0.100000001f, 0.0f, 1.0f,
+                                        0.0250000004f);
+        ui_interface->closeBox();
+    }
+
+    virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
+    {
+        FAUSTFLOAT* input0  = inputs[0];
+        FAUSTFLOAT* input1  = inputs[1];
+        FAUSTFLOAT* output0 = outputs[0];
+        FAUSTFLOAT* output1 = outputs[1];
+        float fSlow0        = ((fConst1 * float(fVslider0)) + 0.699999988f);
+        float fSlow1        = (fConst2 * float(fVslider1));
+        float fSlow2        = (1.0f - fSlow1);
+        float fSlow3        = float(fVslider2);
+        float fSlow4        = (0.100000001f * fSlow3);
+        float fSlow5        = (1.0f - fSlow3);
+        int iSlow6          = int((fConst19 * float(fVslider3)));
+        int iSlow7          = (iConst3 + iSlow6);
+        int iSlow8          = (iConst4 + iSlow6);
+        int iSlow9          = (iConst5 + iSlow6);
+        int iSlow10         = (iConst6 + iSlow6);
+        int iSlow11         = (iConst7 + iSlow6);
+        int iSlow12         = (iConst8 + iSlow6);
+        int iSlow13         = (iConst9 + iSlow6);
+        int iSlow14         = (iConst10 + iSlow6);
+        int iSlow15         = (iSlow6 + -1);
+        int iSlow16         = std::min<int>(1024, std::max<int>(0, (iConst11 + iSlow15)));
+        int iSlow17         = std::min<int>(1024, std::max<int>(0, (iConst13 + iSlow15)));
+        int iSlow18         = std::min<int>(1024, std::max<int>(0, (iConst15 + iSlow15)));
+        int iSlow19         = std::min<int>(1024, std::max<int>(0, (iConst17 + iSlow15)));
+        for (int i = 0; (i < count); i = (i + 1)) {
+            float fTemp0         = float(input0[i]);
+            float fTemp1         = float(input1[i]);
+            fRec9[0]             = ((fSlow1 * fRec9[1]) + (fSlow2 * fRec8[1]));
+            float fTemp2         = (fSlow4 * (fTemp0 + fTemp1));
+            fVec0[(IOTA & 8191)] = ((fSlow0 * fRec9[0]) + fTemp2);
+            fRec8[0]             = fVec0[((IOTA - iConst3) & 8191)];
+            fRec11[0]            = ((fSlow1 * fRec11[1]) + (fSlow2 * fRec10[1]));
+            fVec1[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec11[0]));
+            fRec10[0]            = fVec1[((IOTA - iConst4) & 8191)];
+            fRec13[0]            = ((fSlow1 * fRec13[1]) + (fSlow2 * fRec12[1]));
+            fVec2[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec13[0]));
+            fRec12[0]            = fVec2[((IOTA - iConst5) & 8191)];
+            fRec15[0]            = ((fSlow1 * fRec15[1]) + (fSlow2 * fRec14[1]));
+            fVec3[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec15[0]));
+            fRec14[0]            = fVec3[((IOTA - iConst6) & 8191)];
+            fRec17[0]            = ((fSlow1 * fRec17[1]) + (fSlow2 * fRec16[1]));
+            fVec4[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec17[0]));
+            fRec16[0]            = fVec4[((IOTA - iConst7) & 8191)];
+            fRec19[0]            = ((fSlow1 * fRec19[1]) + (fSlow2 * fRec18[1]));
+            fVec5[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec19[0]));
+            fRec18[0]            = fVec5[((IOTA - iConst8) & 8191)];
+            fRec21[0]            = ((fSlow1 * fRec21[1]) + (fSlow2 * fRec20[1]));
+            fVec6[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec21[0]));
+            fRec20[0]            = fVec6[((IOTA - iConst9) & 8191)];
+            fRec23[0]            = ((fSlow1 * fRec23[1]) + (fSlow2 * fRec22[1]));
+            fVec7[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec23[0]));
+            fRec22[0]            = fVec7[((IOTA - iConst10) & 8191)];
+            float fTemp3 =
+                ((((((((fRec8[0] + fRec10[0]) + fRec12[0]) + fRec14[0]) + fRec16[0])
+                    + fRec18[0])
+                   + fRec20[0])
+                  + fRec22[0])
+                 + (0.5f * fRec6[1]));
+            fVec8[(IOTA & 2047)]  = fTemp3;
+            fRec6[0]              = fVec8[((IOTA - iConst12) & 2047)];
+            float fRec7           = (0.0f - (0.5f * fTemp3));
+            float fTemp4          = (fRec6[1] + (fRec7 + (0.5f * fRec4[1])));
+            fVec9[(IOTA & 2047)]  = fTemp4;
+            fRec4[0]              = fVec9[((IOTA - iConst14) & 2047)];
+            float fRec5           = (0.0f - (0.5f * fTemp4));
+            float fTemp5          = (fRec4[1] + (fRec5 + (0.5f * fRec2[1])));
+            fVec10[(IOTA & 2047)] = fTemp5;
+            fRec2[0]              = fVec10[((IOTA - iConst16) & 2047)];
+            float fRec3           = (0.0f - (0.5f * fTemp5));
+            float fTemp6          = (fRec2[1] + (fRec3 + (0.5f * fRec0[1])));
+            fVec11[(IOTA & 1023)] = fTemp6;
+            fRec0[0]              = fVec11[((IOTA - iConst18) & 1023)];
+            float fRec1           = (0.0f - (0.5f * fTemp6));
+            output0[i]            = FAUSTFLOAT(((fRec1 + fRec0[1]) + (fSlow5 * fTemp0)));
+            fRec33[0]             = ((fSlow1 * fRec33[1]) + (fSlow2 * fRec32[1]));
+            fVec12[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec33[0]));
+            fRec32[0]             = fVec12[((IOTA - iSlow7) & 8191)];
+            fRec35[0]             = ((fSlow1 * fRec35[1]) + (fSlow2 * fRec34[1]));
+            fVec13[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec35[0]));
+            fRec34[0]             = fVec13[((IOTA - iSlow8) & 8191)];
+            fRec37[0]             = ((fSlow1 * fRec37[1]) + (fSlow2 * fRec36[1]));
+            fVec14[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec37[0]));
+            fRec36[0]             = fVec14[((IOTA - iSlow9) & 8191)];
+            fRec39[0]             = ((fSlow1 * fRec39[1]) + (fSlow2 * fRec38[1]));
+            fVec15[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec39[0]));
+            fRec38[0]             = fVec15[((IOTA - iSlow10) & 8191)];
+            fRec41[0]             = ((fSlow1 * fRec41[1]) + (fSlow2 * fRec40[1]));
+            fVec16[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec41[0]));
+            fRec40[0]             = fVec16[((IOTA - iSlow11) & 8191)];
+            fRec43[0]             = ((fSlow1 * fRec43[1]) + (fSlow2 * fRec42[1]));
+            fVec17[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec43[0]));
+            fRec42[0]             = fVec17[((IOTA - iSlow12) & 8191)];
+            fRec45[0]             = ((fSlow1 * fRec45[1]) + (fSlow2 * fRec44[1]));
+            fVec18[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec45[0]));
+            fRec44[0]             = fVec18[((IOTA - iSlow13) & 8191)];
+            fRec47[0]             = ((fSlow1 * fRec47[1]) + (fSlow2 * fRec46[1]));
+            fVec19[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec47[0]));
+            fRec46[0]             = fVec19[((IOTA - iSlow14) & 8191)];
+            float fTemp7 =
+                ((((((((fRec32[0] + fRec34[0]) + fRec36[0]) + fRec38[0]) + fRec40[0])
+                    + fRec42[0])
+                   + fRec44[0])
+                  + fRec46[0])
+                 + (0.5f * fRec30[1]));
+            fVec20[(IOTA & 2047)] = fTemp7;
+            fRec30[0]             = fVec20[((IOTA - iSlow16) & 2047)];
+            float fRec31          = (0.0f - (0.5f * fTemp7));
+            float fTemp8          = (fRec30[1] + (fRec31 + (0.5f * fRec28[1])));
+            fVec21[(IOTA & 2047)] = fTemp8;
+            fRec28[0]             = fVec21[((IOTA - iSlow17) & 2047)];
+            float fRec29          = (0.0f - (0.5f * fTemp8));
+            float fTemp9          = (fRec28[1] + (fRec29 + (0.5f * fRec26[1])));
+            fVec22[(IOTA & 2047)] = fTemp9;
+            fRec26[0]             = fVec22[((IOTA - iSlow18) & 2047)];
+            float fRec27          = (0.0f - (0.5f * fTemp9));
+            float fTemp10         = (fRec26[1] + (fRec27 + (0.5f * fRec24[1])));
+            fVec23[(IOTA & 2047)] = fTemp10;
+            fRec24[0]             = fVec23[((IOTA - iSlow19) & 2047)];
+            float fRec25          = (0.0f - (0.5f * fTemp10));
+            output1[i] = FAUSTFLOAT(((fRec25 + fRec24[1]) + (fSlow5 * fTemp1)));
+            fRec9[1]   = fRec9[0];
+            IOTA       = (IOTA + 1);
+            fRec8[1]   = fRec8[0];
+            fRec11[1]  = fRec11[0];
+            fRec10[1]  = fRec10[0];
+            fRec13[1]  = fRec13[0];
+            fRec12[1]  = fRec12[0];
+            fRec15[1]  = fRec15[0];
+            fRec14[1]  = fRec14[0];
+            fRec17[1]  = fRec17[0];
+            fRec16[1]  = fRec16[0];
+            fRec19[1]  = fRec19[0];
+            fRec18[1]  = fRec18[0];
+            fRec21[1]  = fRec21[0];
+            fRec20[1]  = fRec20[0];
+            fRec23[1]  = fRec23[0];
+            fRec22[1]  = fRec22[0];
+            fRec6[1]   = fRec6[0];
+            fRec4[1]   = fRec4[0];
+            fRec2[1]   = fRec2[0];
+            fRec0[1]   = fRec0[0];
+            fRec33[1]  = fRec33[0];
+            fRec32[1]  = fRec32[0];
+            fRec35[1]  = fRec35[0];
+            fRec34[1]  = fRec34[0];
+            fRec37[1]  = fRec37[0];
+            fRec36[1]  = fRec36[0];
+            fRec39[1]  = fRec39[0];
+            fRec38[1]  = fRec38[0];
+            fRec41[1]  = fRec41[0];
+            fRec40[1]  = fRec40[0];
+            fRec43[1]  = fRec43[0];
+            fRec42[1]  = fRec42[0];
+            fRec45[1]  = fRec45[0];
+            fRec44[1]  = fRec44[0];
+            fRec47[1]  = fRec47[0];
+            fRec46[1]  = fRec46[0];
+            fRec30[1]  = fRec30[0];
+            fRec28[1]  = fRec28[0];
+            fRec26[1]  = fRec26[0];
+            fRec24[1]  = fRec24[0];
+        }
+    }
 };
 
 #endif
index 5de618ec5591c6a0671d7eb9daf5f3118cb9db3e..5d04d8f538ab2f9cd91c496dd0aa92698d4eb8f9 100644 (file)
@@ -4,8 +4,8 @@ Code generated with Faust 2.28.6 (https://faust.grame.fr)
 Compilation options: -lang cpp -inpl -scal -ftz 0
 ------------------------------------------------------------ */
 
-#ifndef  __freeverbmonodsp_H__
-#define  __freeverbmonodsp_H__
+#ifndef __freeverbmonodsp_H__
+#define __freeverbmonodsp_H__
 
 // NOTE: ANY INCLUDE-GUARD HERE MUST BE DERIVED FROM THE CLASS NAME
 //
@@ -23,15 +23,15 @@ Compilation options: -lang cpp -inpl -scal -ftz 0
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -56,165 +56,177 @@ struct Meta;
  */
 
 struct dsp_memory_manager {
-    
     virtual ~dsp_memory_manager() {}
-    
+
     virtual void* allocate(size_t size) = 0;
-    virtual void destroy(void* ptr) = 0;
-    
+    virtual void destroy(void* ptr)     = 0;
 };
 
 /**
-* Signal processor definition.
-*/
-
-class dsp {
-
-    public:
-
-        dsp() {}
-        virtual ~dsp() {}
-
-        /* Return instance number of audio inputs */
-        virtual int getNumInputs() = 0;
-    
-        /* Return instance number of audio outputs */
-        virtual int getNumOutputs() = 0;
-    
-        /**
-         * Trigger the ui_interface parameter with instance specific calls
-         * to 'openTabBox', 'addButton', 'addVerticalSlider'... in order to build the UI.
-         *
-         * @param ui_interface - the user interface builder
-         */
-        virtual void buildUserInterface(UI* ui_interface) = 0;
-    
-        /* Returns the sample rate currently used by the instance */
-        virtual int getSampleRate() = 0;
-    
-        /**
-         * Global init, calls the following methods:
-         * - static class 'classInit': static tables initialization
-         * - 'instanceInit': constants and instance state initialization
-         *
-         * @param sample_rate - the sampling rate in Hertz
-         */
-        virtual void init(int sample_rate) = 0;
-
-        /**
-         * Init instance state
-         *
-         * @param sample_rate - the sampling rate in Hertz
-         */
-        virtual void instanceInit(int sample_rate) = 0;
-
-        /**
-         * Init instance constant state
-         *
-         * @param sample_rate - the sampling rate in Hertz
-         */
-        virtual void instanceConstants(int sample_rate) = 0;
-    
-        /* Init default control parameters values */
-        virtual void instanceResetUserInterface() = 0;
-    
-        /* Init instance state (delay lines...) */
-        virtual void instanceClear() = 0;
-        /**
-         * Return a clone of the instance.
-         *
-         * @return a copy of the instance on success, otherwise a null pointer.
-         */
-        virtual dsp* clone() = 0;
-    
-        /**
-         * Trigger the Meta* parameter with instance specific calls to 'declare' (key, value) metadata.
-         *
-         * @param m - the Meta* meta user
-         */
-        virtual void metadata(Meta* m) = 0;
-    
-        /**
-         * DSP instance computation, to be called with successive in/out audio buffers.
-         *
-         * @param count - the number of frames to compute
-         * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
-         * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
-         *
-         */
-        virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) = 0;
-    
-        /**
-         * DSP instance computation: alternative method to be used by subclasses.
-         *
-         * @param date_usec - the timestamp in microsec given by audio driver.
-         * @param count - the number of frames to compute
-         * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
-         * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
-         *
-         */
-        virtual void compute(double /*date_usec*/, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { compute(count, inputs, outputs); }
-       
+ * Signal processor definition.
+ */
+
+class dsp
+{
+   public:
+    dsp() {}
+    virtual ~dsp() {}
+
+    /* Return instance number of audio inputs */
+    virtual int getNumInputs() = 0;
+
+    /* Return instance number of audio outputs */
+    virtual int getNumOutputs() = 0;
+
+    /**
+     * Trigger the ui_interface parameter with instance specific calls
+     * to 'openTabBox', 'addButton', 'addVerticalSlider'... in order to build the UI.
+     *
+     * @param ui_interface - the user interface builder
+     */
+    virtual void buildUserInterface(UI* ui_interface) = 0;
+
+    /* Returns the sample rate currently used by the instance */
+    virtual int getSampleRate() = 0;
+
+    /**
+     * Global init, calls the following methods:
+     * - static class 'classInit': static tables initialization
+     * - 'instanceInit': constants and instance state initialization
+     *
+     * @param sample_rate - the sampling rate in Hertz
+     */
+    virtual void init(int sample_rate) = 0;
+
+    /**
+     * Init instance state
+     *
+     * @param sample_rate - the sampling rate in Hertz
+     */
+    virtual void instanceInit(int sample_rate) = 0;
+
+    /**
+     * Init instance constant state
+     *
+     * @param sample_rate - the sampling rate in Hertz
+     */
+    virtual void instanceConstants(int sample_rate) = 0;
+
+    /* Init default control parameters values */
+    virtual void instanceResetUserInterface() = 0;
+
+    /* Init instance state (delay lines...) */
+    virtual void instanceClear() = 0;
+
+    /**
+     * Return a clone of the instance.
+     *
+     * @return a copy of the instance on success, otherwise a null pointer.
+     */
+    virtual dsp* clone() = 0;
+
+    /**
+     * Trigger the Meta* parameter with instance specific calls to 'declare' (key, value)
+     * metadata.
+     *
+     * @param m - the Meta* meta user
+     */
+    virtual void metadata(Meta* m) = 0;
+
+    /**
+     * DSP instance computation, to be called with successive in/out audio buffers.
+     *
+     * @param count - the number of frames to compute
+     * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (eiher float, double or quad)
+     * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (eiher float, double or quad)
+     *
+     */
+    virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) = 0;
+
+    /**
+     * DSP instance computation: alternative method to be used by subclasses.
+     *
+     * @param date_usec - the timestamp in microsec given by audio driver.
+     * @param count - the number of frames to compute
+     * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (either float, double or quad)
+     * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (either float, double or quad)
+     *
+     */
+    virtual void compute(double /*date_usec*/, int count, FAUSTFLOAT** inputs,
+                         FAUSTFLOAT** outputs)
+    {
+        compute(count, inputs, outputs);
+    }
 };
 
 /**
  * Generic DSP decorator.
  */
 
-class decorator_dsp : public dsp {
-
-    protected:
-
-        dsp* fDSP;
-
-    public:
-
-        decorator_dsp(dsp* dsp = nullptr):fDSP(dsp) {}
-        virtual ~decorator_dsp() { delete fDSP; }
-
-        virtual int getNumInputs() { return fDSP->getNumInputs(); }
-        virtual int getNumOutputs() { return fDSP->getNumOutputs(); }
-        virtual void buildUserInterface(UI* ui_interface) { fDSP->buildUserInterface(ui_interface); }
-        virtual int getSampleRate() { return fDSP->getSampleRate(); }
-        virtual void init(int sample_rate) { fDSP->init(sample_rate); }
-        virtual void instanceInit(int sample_rate) { fDSP->instanceInit(sample_rate); }
-        virtual void instanceConstants(int sample_rate) { fDSP->instanceConstants(sample_rate); }
-        virtual void instanceResetUserInterface() { fDSP->instanceResetUserInterface(); }
-        virtual void instanceClear() { fDSP->instanceClear(); }
-        virtual decorator_dsp* clone() { return new decorator_dsp(fDSP->clone()); }
-        virtual void metadata(Meta* m) { fDSP->metadata(m); }
-        // Beware: subclasses usually have to overload the two 'compute' methods
-        virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(count, inputs, outputs); }
-        virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(date_usec, count, inputs, outputs); }
-    
+class decorator_dsp : public dsp
+{
+   protected:
+    dsp* fDSP;
+
+   public:
+    decorator_dsp(dsp* dsp = nullptr) : fDSP(dsp) {}
+    virtual ~decorator_dsp() { delete fDSP; }
+
+    virtual int getNumInputs() { return fDSP->getNumInputs(); }
+    virtual int getNumOutputs() { return fDSP->getNumOutputs(); }
+    virtual void buildUserInterface(UI* ui_interface)
+    {
+        fDSP->buildUserInterface(ui_interface);
+    }
+    virtual int getSampleRate() { return fDSP->getSampleRate(); }
+    virtual void init(int sample_rate) { fDSP->init(sample_rate); }
+    virtual void instanceInit(int sample_rate) { fDSP->instanceInit(sample_rate); }
+    virtual void instanceConstants(int sample_rate)
+    {
+        fDSP->instanceConstants(sample_rate);
+    }
+    virtual void instanceResetUserInterface() { fDSP->instanceResetUserInterface(); }
+    virtual void instanceClear() { fDSP->instanceClear(); }
+    virtual decorator_dsp* clone() { return new decorator_dsp(fDSP->clone()); }
+    virtual void metadata(Meta* m) { fDSP->metadata(m); }
+    // Beware: subclasses usually have to overload the two 'compute' methods
+    virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
+    {
+        fDSP->compute(count, inputs, outputs);
+    }
+    virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs,
+                         FAUSTFLOAT** outputs)
+    {
+        fDSP->compute(date_usec, count, inputs, outputs);
+    }
 };
 
 /**
  * DSP factory class.
  */
 
-class dsp_factory {
-    
-    protected:
-    
-        // So that to force sub-classes to use deleteDSPFactory(dsp_factory* factory);
-        virtual ~dsp_factory() {}
-    
-    public:
-    
-        virtual std::string getName() = 0;
-        virtual std::string getSHAKey() = 0;
-        virtual std::string getDSPCode() = 0;
-        virtual std::string getCompileOptions() = 0;
-        virtual std::vector<std::string> getLibraryList() = 0;
-        virtual std::vector<std::string> getIncludePathnames() = 0;
-    
-        virtual dsp* createDSPInstance() = 0;
-    
-        virtual void setMemoryManager(dsp_memory_manager* manager) = 0;
-        virtual dsp_memory_manager* getMemoryManager() = 0;
-    
+class dsp_factory
+{
+   protected:
+    // So that to force sub-classes to use deleteDSPFactory(dsp_factory* factory);
+    virtual ~dsp_factory() {}
+
+   public:
+    virtual std::string getName()                          = 0;
+    virtual std::string getSHAKey()                        = 0;
+    virtual std::string getDSPCode()                       = 0;
+    virtual std::string getCompileOptions()                = 0;
+    virtual std::vector<std::string> getLibraryList()      = 0;
+    virtual std::vector<std::string> getIncludePathnames() = 0;
+
+    virtual dsp* createDSPInstance() = 0;
+
+    virtual void setMemoryManager(dsp_memory_manager* manager) = 0;
+    virtual dsp_memory_manager* getMemoryManager()             = 0;
 };
 
 /**
@@ -223,14 +235,14 @@ class dsp_factory {
  */
 
 #ifdef __SSE__
-    #include <xmmintrin.h>
-    #ifdef __SSE2__
-        #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
-    #else
-        #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
-    #endif
+#include <xmmintrin.h>
+#ifdef __SSE2__
+#define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
+#else
+#define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
+#endif
 #else
-    #define AVOIDDENORMALS
+#define AVOIDDENORMALS
 #endif
 
 #endif
@@ -245,15 +257,15 @@ class dsp_factory {
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -263,11 +275,11 @@ class dsp_factory {
 #ifndef API_UI_H
 #define API_UI_H
 
+#include <iostream>
+#include <map>
 #include <sstream>
 #include <string>
 #include <vector>
-#include <iostream>
-#include <map>
 
 /************************** BEGIN meta.h **************************/
 /************************************************************************
@@ -278,15 +290,15 @@ class dsp_factory {
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -296,11 +308,9 @@ class dsp_factory {
 #ifndef __meta__
 #define __meta__
 
-struct Meta
-{
-    virtual ~Meta() {};
+struct Meta {
+    virtual ~Meta(){};
     virtual void declare(const char* key, const char* value) = 0;
-    
 };
 
 #endif
@@ -314,15 +324,15 @@ struct Meta
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -345,43 +355,47 @@ struct Meta
 
 struct Soundfile;
 
-template <typename REAL>
-struct UIReal
-{
+template<typename REAL>
+struct UIReal {
     UIReal() {}
     virtual ~UIReal() {}
-    
+
     // -- widget's layouts
-    
-    virtual void openTabBox(const char* label) = 0;
+
+    virtual void openTabBox(const char* label)        = 0;
     virtual void openHorizontalBox(const char* label) = 0;
-    virtual void openVerticalBox(const char* label) = 0;
-    virtual void closeBox() = 0;
-    
+    virtual void openVerticalBox(const char* label)   = 0;
+    virtual void closeBox()                           = 0;
+
     // -- active widgets
-    
-    virtual void addButton(const char* label, REAL* zone) = 0;
+
+    virtual void addButton(const char* label, REAL* zone)      = 0;
     virtual void addCheckButton(const char* label, REAL* zone) = 0;
-    virtual void addVerticalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
-    virtual void addHorizontalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
-    virtual void addNumEntry(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
-    
+    virtual void addVerticalSlider(const char* label, REAL* zone, REAL init, REAL min,
+                                   REAL max, REAL step)        = 0;
+    virtual void addHorizontalSlider(const char* label, REAL* zone, REAL init, REAL min,
+                                     REAL max, REAL step)      = 0;
+    virtual void addNumEntry(const char* label, REAL* zone, REAL init, REAL min, REAL max,
+                             REAL step)                        = 0;
+
     // -- passive widgets
-    
-    virtual void addHorizontalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
-    virtual void addVerticalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
-    
+
+    virtual void addHorizontalBargraph(const char* label, REAL* zone, REAL min,
+                                       REAL max) = 0;
+    virtual void addVerticalBargraph(const char* label, REAL* zone, REAL min,
+                                     REAL max)   = 0;
+
     // -- soundfiles
-    
-    virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) = 0;
-    
+
+    virtual void addSoundfile(const char* label, const char* filename,
+                              Soundfile** sf_zone) = 0;
+
     // -- metadata declarations
-    
+
     virtual void declare(REAL* zone, const char* key, const char* val) {}
 };
 
-struct UI : public UIReal<FAUSTFLOAT>
-{
+struct UI : public UIReal<FAUSTFLOAT> {
     UI() {}
     virtual ~UI() {}
 };
@@ -397,15 +411,15 @@ struct UI : public UIReal<FAUSTFLOAT>
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -415,9 +429,9 @@ struct UI : public UIReal<FAUSTFLOAT>
 #ifndef FAUST_PATHBUILDER_H
 #define FAUST_PATHBUILDER_H
 
-#include <vector>
-#include <string>
 #include <algorithm>
+#include <string>
+#include <vector>
 
 /*******************************************************************************
  * PathBuilder : Faust User Interface
@@ -426,37 +440,33 @@ struct UI : public UIReal<FAUSTFLOAT>
 
 class PathBuilder
 {
-
-    protected:
-    
-        std::vector<std::string> fControlsLevel;
-       
-    public:
-    
-        PathBuilder() {}
-        virtual ~PathBuilder() {}
-    
-        std::string buildPath(const std::string& label) 
-        {
-            std::string res = "/";
-            for (size_t i = 0; i < fControlsLevel.size(); i++) {
-                res += fControlsLevel[i];
-                res += "/";
-            }
-            res += label;
-            std::replace(res.begin(), res.end(), ' ', '_');
-            return res;
-        }
-    
-        std::string buildLabel(std::string label)
-        {
-            std::replace(label.begin(), label.end(), ' ', '_');
-            return label;
+   protected:
+    std::vector<std::string> fControlsLevel;
+
+   public:
+    PathBuilder() {}
+    virtual ~PathBuilder() {}
+
+    std::string buildPath(const std::string& label)
+    {
+        std::string res = "/";
+        for (size_t i = 0; i < fControlsLevel.size(); i++) {
+            res += fControlsLevel[i];
+            res += "/";
         }
-    
-        void pushLabel(const std::string& label) { fControlsLevel.push_back(label); }
-        void popLabel() { fControlsLevel.pop_back(); }
-    
+        res += label;
+        std::replace(res.begin(), res.end(), ' ', '_');
+        return res;
+    }
+
+    std::string buildLabel(std::string label)
+    {
+        std::replace(label.begin(), label.end(), ' ', '_');
+        return label;
+    }
+
+    void pushLabel(const std::string& label) { fControlsLevel.push_back(label); }
+    void popLabel() { fControlsLevel.pop_back(); }
 };
 
 #endif  // FAUST_PATHBUILDER_H
@@ -470,15 +480,15 @@ class PathBuilder
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -489,7 +499,7 @@ class PathBuilder
 #define __ValueConverter__
 
 /***************************************************************************************
-                                                               ValueConverter.h
+                                                                ValueConverter.h
                             (GRAME, Copyright 2015-2019)
 
 Set of conversion objects used to map user interface values (for example a gui slider
@@ -499,8 +509,9 @@ delivering values between 0 and 1) to faust values (for example a vslider betwee
 -- Utilities
 
 Range(lo,hi) : clip a value x between lo and hi
-Interpolator(lo,hi,v1,v2) : Maps a value x between lo and hi to a value y between v1 and v2
-Interpolator3pt(lo,mi,hi,v1,vm,v2) : Map values between lo mid hi to values between v1 vm v2
+Interpolator(lo,hi,v1,v2) : Maps a value x between lo and hi to a value y between v1 and
+v2 Interpolator3pt(lo,mi,hi,v1,vm,v2) : Map values between lo mid hi to values between v1
+vm v2
 
 -- Value Converters
 
@@ -531,11 +542,11 @@ ZoneReader(zone, valueConverter) : a zone with a data converter
 
 ****************************************************************************************/
 
-#include <float.h>
-#include <algorithm>    // std::max
+#include <algorithm>  // std::max
+#include <cassert>
+#include <cfloat>
 #include <cmath>
 #include <vector>
-#include <assert.h>
 
 //--------------------------------------------------------------------------------------
 // Interpolator(lo,hi,v1,v2)
@@ -548,50 +559,49 @@ ZoneReader(zone, valueConverter) : a zone with a data converter
 //--------------------------------------------------------------------------------------
 class Interpolator
 {
-    private:
-
-        //--------------------------------------------------------------------------------------
-        // Range(lo,hi) clip a value between lo and hi
-        //--------------------------------------------------------------------------------------
-        struct Range
-        {
-            double fLo;
-            double fHi;
-
-            Range(double x, double y) : fLo(std::min<double>(x,y)), fHi(std::max<double>(x,y)) {}
-            double operator()(double x) { return (x<fLo) ? fLo : (x>fHi) ? fHi : x; }
-        };
-
-
-        Range fRange;
-        double fCoef;
-        double fOffset;
-
-    public:
-
-        Interpolator(double lo, double hi, double v1, double v2) : fRange(lo,hi)
-        {
-            if (hi != lo) {
-                // regular case
-                fCoef = (v2-v1)/(hi-lo);
-                fOffset = v1 - lo*fCoef;
-            } else {
-                // degenerate case, avoids division by zero
-                fCoef = 0;
-                fOffset = (v1+v2)/2;
-            }
-        }
-        double operator()(double v)
+   private:
+    //--------------------------------------------------------------------------------------
+    // Range(lo,hi) clip a value between lo and hi
+    //--------------------------------------------------------------------------------------
+    struct Range {
+        double fLo;
+        double fHi;
+
+        Range(double x, double y)
+            : fLo(std::min<double>(x, y)), fHi(std::max<double>(x, y))
         {
-            double x = fRange(v);
-            return  fOffset + x*fCoef;
         }
-
-        void getLowHigh(double& amin, double& amax)
-        {
-            amin = fRange.fLo;
-            amax = fRange.fHi;
+        double operator()(double x) { return (x < fLo) ? fLo : (x > fHi) ? fHi : x; }
+    };
+
+    Range fRange;
+    double fCoef;
+    double fOffset;
+
+   public:
+    Interpolator(double lo, double hi, double v1, double v2) : fRange(lo, hi)
+    {
+        if (hi != lo) {
+            // regular case
+            fCoef   = (v2 - v1) / (hi - lo);
+            fOffset = v1 - lo * fCoef;
+        } else {
+            // degenerate case, avoids division by zero
+            fCoef   = 0;
+            fOffset = (v1 + v2) / 2;
         }
+    }
+    double operator()(double v)
+    {
+        double x = fRange(v);
+        return fOffset + x * fCoef;
+    }
+
+    void getLowHigh(double& amin, double& amax)
+    {
+        amin = fRange.fLo;
+        amax = fRange.fHi;
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -600,26 +610,23 @@ class Interpolator
 //--------------------------------------------------------------------------------------
 class Interpolator3pt
 {
-
-    private:
-
-        Interpolator fSegment1;
-        Interpolator fSegment2;
-        double fMid;
-
-    public:
-
-        Interpolator3pt(double lo, double mi, double hi, double v1, double vm, double v2) :
-            fSegment1(lo, mi, v1, vm),
-            fSegment2(mi, hi, vm, v2),
-            fMid(mi) {}
-        double operator()(double x) { return  (x < fMid) ? fSegment1(x) : fSegment2(x); }
-
-        void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fSegment1.getLowHigh(amin, amid);
-            fSegment2.getLowHigh(amid, amax);
-        }
+   private:
+    Interpolator fSegment1;
+    Interpolator fSegment2;
+    double fMid;
+
+   public:
+    Interpolator3pt(double lo, double mi, double hi, double v1, double vm, double v2)
+        : fSegment1(lo, mi, v1, vm), fSegment2(mi, hi, vm, v2), fMid(mi)
+    {
+    }
+    double operator()(double x) { return (x < fMid) ? fSegment1(x) : fSegment2(x); }
+
+    void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fSegment1.getLowHigh(amin, amid);
+        fSegment2.getLowHigh(amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -627,62 +634,51 @@ class Interpolator3pt
 //--------------------------------------------------------------------------------------
 class ValueConverter
 {
-
-    public:
-
-        virtual ~ValueConverter() {}
-        virtual double ui2faust(double x) = 0;
-        virtual double faust2ui(double x) = 0;
+   public:
+    virtual ~ValueConverter() {}
+    virtual double ui2faust(double x) = 0;
+    virtual double faust2ui(double x) = 0;
 };
 
 //--------------------------------------------------------------------------------------
 // A converter than can be updated
 //--------------------------------------------------------------------------------------
 
-class UpdatableValueConverter : public ValueConverter {
-    
-    protected:
-        
-        bool fActive;
-        
-    public:
-        
-        UpdatableValueConverter():fActive(true)
-        {}
-        virtual ~UpdatableValueConverter()
-        {}
-        
-        virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max) = 0;
-        virtual void getMappingValues(double& amin, double& amid, double& amax) = 0;
-        
-        void setActive(bool on_off) { fActive = on_off; }
-        bool getActive() { return fActive; }
-    
-};
+class UpdatableValueConverter : public ValueConverter
+{
+   protected:
+    bool fActive;
 
+   public:
+    UpdatableValueConverter() : fActive(true) {}
+    virtual ~UpdatableValueConverter() {}
+
+    virtual void setMappingValues(double amin, double amid, double amax, double min,
+                                  double init, double max)                  = 0;
+    virtual void getMappingValues(double& amin, double& amid, double& amax) = 0;
+
+    void setActive(bool on_off) { fActive = on_off; }
+    bool getActive() { return fActive; }
+};
 
 //--------------------------------------------------------------------------------------
 // Linear conversion between ui and Faust values
 //--------------------------------------------------------------------------------------
 class LinearValueConverter : public ValueConverter
 {
-    
-    private:
-        
-        Interpolator fUI2F;
-        Interpolator fF2UI;
-        
-    public:
-        
-        LinearValueConverter(double umin, double umax, double fmin, double fmax) :
-            fUI2F(umin,umax,fmin,fmax), fF2UI(fmin,fmax,umin,umax)
-        {}
-        
-        LinearValueConverter() : fUI2F(0.,0.,0.,0.), fF2UI(0.,0.,0.,0.)
-        {}
-        virtual double ui2faust(double x) { return fUI2F(x); }
-        virtual double faust2ui(double x) { return fF2UI(x); }
-    
+   private:
+    Interpolator fUI2F;
+    Interpolator fF2UI;
+
+   public:
+    LinearValueConverter(double umin, double umax, double fmin, double fmax)
+        : fUI2F(umin, umax, fmin, fmax), fF2UI(fmin, fmax, umin, umax)
+    {
+    }
+
+    LinearValueConverter() : fUI2F(0., 0., 0., 0.), fF2UI(0., 0., 0., 0.) {}
+    virtual double ui2faust(double x) { return fUI2F(x); }
+    virtual double faust2ui(double x) { return fF2UI(x); }
 };
 
 //--------------------------------------------------------------------------------------
@@ -690,35 +686,35 @@ class LinearValueConverter : public ValueConverter
 //--------------------------------------------------------------------------------------
 class LinearValueConverter2 : public UpdatableValueConverter
 {
-    
-    private:
-    
-        Interpolator3pt fUI2F;
-        Interpolator3pt fF2UI;
-        
-    public:
-    
-        LinearValueConverter2(double amin, double amid, double amax, double min, double init, double max) :
-            fUI2F(amin, amid, amax, min, init, max), fF2UI(min, init, max, amin, amid, amax)
-        {}
-        
-        LinearValueConverter2() : fUI2F(0.,0.,0.,0.,0.,0.), fF2UI(0.,0.,0.,0.,0.,0.)
-        {}
-    
-        virtual double ui2faust(double x) { return fUI2F(x); }
-        virtual double faust2ui(double x) { return fF2UI(x); }
-    
-        virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max)
-        {
-            fUI2F = Interpolator3pt(amin, amid, amax, min, init, max);
-            fF2UI = Interpolator3pt(min, init, max, amin, amid, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fUI2F.getMappingValues(amin, amid, amax);
-        }
-    
+   private:
+    Interpolator3pt fUI2F;
+    Interpolator3pt fF2UI;
+
+   public:
+    LinearValueConverter2(double amin, double amid, double amax, double min, double init,
+                          double max)
+        : fUI2F(amin, amid, amax, min, init, max), fF2UI(min, init, max, amin, amid, amax)
+    {
+    }
+
+    LinearValueConverter2() : fUI2F(0., 0., 0., 0., 0., 0.), fF2UI(0., 0., 0., 0., 0., 0.)
+    {
+    }
+
+    virtual double ui2faust(double x) { return fUI2F(x); }
+    virtual double faust2ui(double x) { return fF2UI(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double min,
+                                  double init, double max)
+    {
+        fUI2F = Interpolator3pt(amin, amid, amax, min, init, max);
+        fF2UI = Interpolator3pt(min, init, max, amin, amid, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fUI2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -726,16 +722,21 @@ class LinearValueConverter2 : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class LogValueConverter : public LinearValueConverter
 {
-
-    public:
-
-        LogValueConverter(double umin, double umax, double fmin, double fmax) :
-            LinearValueConverter(umin, umax, std::log(std::max<double>(DBL_MIN, fmin)), std::log(std::max<double>(DBL_MIN, fmax)))
-        {}
-
-        virtual double ui2faust(double x) { return std::exp(LinearValueConverter::ui2faust(x)); }
-        virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::log(std::max<double>(x, DBL_MIN))); }
-
+   public:
+    LogValueConverter(double umin, double umax, double fmin, double fmax)
+        : LinearValueConverter(umin, umax, std::log(std::max<double>(DBL_MIN, fmin)),
+                               std::log(std::max<double>(DBL_MIN, fmax)))
+    {
+    }
+
+    virtual double ui2faust(double x)
+    {
+        return std::exp(LinearValueConverter::ui2faust(x));
+    }
+    virtual double faust2ui(double x)
+    {
+        return LinearValueConverter::faust2ui(std::log(std::max<double>(x, DBL_MIN)));
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -743,16 +744,21 @@ class LogValueConverter : public LinearValueConverter
 //--------------------------------------------------------------------------------------
 class ExpValueConverter : public LinearValueConverter
 {
-
-    public:
-
-        ExpValueConverter(double umin, double umax, double fmin, double fmax) :
-            LinearValueConverter(umin, umax, std::min<double>(DBL_MAX, std::exp(fmin)), std::min<double>(DBL_MAX, std::exp(fmax)))
-        {}
-
-        virtual double ui2faust(double x) { return std::log(LinearValueConverter::ui2faust(x)); }
-        virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::min<double>(DBL_MAX, std::exp(x))); }
-
+   public:
+    ExpValueConverter(double umin, double umax, double fmin, double fmax)
+        : LinearValueConverter(umin, umax, std::min<double>(DBL_MAX, std::exp(fmin)),
+                               std::min<double>(DBL_MAX, std::exp(fmax)))
+    {
+    }
+
+    virtual double ui2faust(double x)
+    {
+        return std::log(LinearValueConverter::ui2faust(x));
+    }
+    virtual double faust2ui(double x)
+    {
+        return LinearValueConverter::faust2ui(std::min<double>(DBL_MAX, std::exp(x)));
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -761,34 +767,34 @@ class ExpValueConverter : public LinearValueConverter
 //--------------------------------------------------------------------------------------
 class AccUpConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt fA2F;
-        Interpolator3pt fF2A;
-
-    public:
-
-        AccUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmin,fmid,fmax),
-            fF2A(fmin,fmid,fmax,amin,amid,amax)
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-            //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmin, fmid, fmax);
-            fF2A = Interpolator3pt(fmin, fmid, fmax, amin, amid, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
-
+   private:
+    Interpolator3pt fA2F;
+    Interpolator3pt fF2A;
+
+   public:
+    AccUpConverter(double amin, double amid, double amax, double fmin, double fmid,
+                   double fmax)
+        : fA2F(amin, amid, amax, fmin, fmid, fmax)
+        , fF2A(fmin, fmid, fmax, amin, amid, amax)
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double fmid, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpConverter update %f %f %f
+        //%f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmin, fmid, fmax);
+        fF2A = Interpolator3pt(fmin, fmid, fmax, amin, amid, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -797,33 +803,34 @@ class AccUpConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class AccDownConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt        fA2F;
-        Interpolator3pt        fF2A;
-
-    public:
-
-        AccDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmax,fmid,fmin),
-            fF2A(fmin,fmid,fmax,amax,amid,amin)
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-             //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmax, fmid, fmin);
-            fF2A = Interpolator3pt(fmin, fmid, fmax, amax, amid, amin);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
+   private:
+    Interpolator3pt fA2F;
+    Interpolator3pt fF2A;
+
+   public:
+    AccDownConverter(double amin, double amid, double amax, double fmin, double fmid,
+                     double fmax)
+        : fA2F(amin, amid, amax, fmax, fmid, fmin)
+        , fF2A(fmin, fmid, fmax, amax, amid, amin)
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double fmid, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownConverter update %f %f
+        //%f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmax, fmid, fmin);
+        fF2A = Interpolator3pt(fmin, fmid, fmax, amax, amid, amin);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -832,33 +839,35 @@ class AccDownConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class AccUpDownConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt        fA2F;
-        Interpolator fF2A;
-
-    public:
-
-        AccUpDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmin,fmax,fmin),
-            fF2A(fmin,fmax,amin,amax)                          // Special, pseudo inverse of a non monotonic function
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-            //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmin, fmax, fmin);
-            fF2A = Interpolator(fmin, fmax, amin, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
+   private:
+    Interpolator3pt fA2F;
+    Interpolator fF2A;
+
+   public:
+    AccUpDownConverter(double amin, double amid, double amax, double fmin, double fmid,
+                       double fmax)
+        : fA2F(amin, amid, amax, fmin, fmax, fmin)
+        , fF2A(fmin, fmax, amin,
+               amax)  // Special, pseudo inverse of a non monotonic function
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double fmid, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpDownConverter update %f %f
+        //%f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmin, fmax, fmin);
+        fF2A = Interpolator(fmin, fmax, amin, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -867,33 +876,35 @@ class AccUpDownConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class AccDownUpConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt        fA2F;
-        Interpolator fF2A;
-
-    public:
-
-        AccDownUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmax,fmin,fmax),
-            fF2A(fmin,fmax,amin,amax)                          // Special, pseudo inverse of a non monotonic function
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-            //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmax, fmin, fmax);
-            fF2A = Interpolator(fmin, fmax, amin, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
+   private:
+    Interpolator3pt fA2F;
+    Interpolator fF2A;
+
+   public:
+    AccDownUpConverter(double amin, double amid, double amax, double fmin, double fmid,
+                       double fmax)
+        : fA2F(amin, amid, amax, fmax, fmin, fmax)
+        , fF2A(fmin, fmax, amin,
+               amax)  // Special, pseudo inverse of a non monotonic function
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double fmid, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownUpConverter update %f %f
+        //%f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmax, fmin, fmax);
+        fF2A = Interpolator(fmin, fmax, amin, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -901,28 +912,27 @@ class AccDownUpConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class ZoneControl
 {
+   protected:
+    FAUSTFLOAT* fZone;
 
-    protected:
-
-        FAUSTFLOAT*    fZone;
-
-    public:
-
-        ZoneControl(FAUSTFLOAT* zone) : fZone(zone) {}
-        virtual ~ZoneControl() {}
+   public:
+    ZoneControl(FAUSTFLOAT* zone) : fZone(zone) {}
+    virtual ~ZoneControl() {}
 
-        virtual void update(double v) const {}
+    virtual void update(double v) const {}
 
-        virtual void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max) {}
-        virtual void getMappingValues(double& amin, double& amid, double& amax) {}
+    virtual void setMappingValues(int curve, double amin, double amid, double amax,
+                                  double min, double init, double max)
+    {
+    }
+    virtual void getMappingValues(double& amin, double& amid, double& amax) {}
 
-        FAUSTFLOAT* getZone() { return fZone; }
+    FAUSTFLOAT* getZone() { return fZone; }
 
-        virtual void setActive(bool on_off) {}
-        virtual bool getActive() { return false; }
-
-        virtual int getCurve() { return -1; }
+    virtual void setActive(bool on_off) {}
+    virtual bool getActive() { return false; }
 
+    virtual int getCurve() { return -1; }
 };
 
 //--------------------------------------------------------------------------------------
@@ -930,20 +940,22 @@ class ZoneControl
 //--------------------------------------------------------------------------------------
 class ConverterZoneControl : public ZoneControl
 {
-
-    protected:
-
-        ValueConverter* fValueConverter;
-
-    public:
-
-        ConverterZoneControl(FAUSTFLOAT* zone, ValueConverter* converter) : ZoneControl(zone), fValueConverter(converter) {}
-        virtual ~ConverterZoneControl() { delete fValueConverter; } // Assuming fValueConverter is not kept elsewhere...
-
-        virtual void update(double v) const { *fZone = fValueConverter->ui2faust(v); }
-
-        ValueConverter* getConverter() { return fValueConverter; }
-
+   protected:
+    ValueConverter* fValueConverter;
+
+   public:
+    ConverterZoneControl(FAUSTFLOAT* zone, ValueConverter* converter)
+        : ZoneControl(zone), fValueConverter(converter)
+    {
+    }
+    virtual ~ConverterZoneControl()
+    {
+        delete fValueConverter;
+    }  // Assuming fValueConverter is not kept elsewhere...
+
+    virtual void update(double v) const { *fZone = fValueConverter->ui2faust(v); }
+
+    ValueConverter* getConverter() { return fValueConverter; }
 };
 
 //--------------------------------------------------------------------------------------
@@ -952,592 +964,613 @@ class ConverterZoneControl : public ZoneControl
 //--------------------------------------------------------------------------------------
 class CurveZoneControl : public ZoneControl
 {
-
-    private:
-
-        std::vector<UpdatableValueConverter*> fValueConverters;
-        int fCurve;
-
-    public:
-
-        CurveZoneControl(FAUSTFLOAT* zone, int curve, double amin, double amid, double amax, double min, double init, double max) : ZoneControl(zone), fCurve(0)
-        {
-            assert(curve >= 0 && curve <= 3);
-            fValueConverters.push_back(new AccUpConverter(amin, amid, amax, min, init, max));
-            fValueConverters.push_back(new AccDownConverter(amin, amid, amax, min, init, max));
-            fValueConverters.push_back(new AccUpDownConverter(amin, amid, amax, min, init, max));
-            fValueConverters.push_back(new AccDownUpConverter(amin, amid, amax, min, init, max));
-            fCurve = curve;
-        }
-        virtual ~CurveZoneControl()
-        {
-            std::vector<UpdatableValueConverter*>::iterator it;
-            for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
-                delete(*it);
-            }
-        }
-        void update(double v) const { if (fValueConverters[fCurve]->getActive()) *fZone = fValueConverters[fCurve]->ui2faust(v); }
-
-        void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max)
-        {
-            fValueConverters[curve]->setMappingValues(amin, amid, amax, min, init, max);
-            fCurve = curve;
-        }
-
-        void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fValueConverters[fCurve]->getMappingValues(amin, amid, amax);
+   private:
+    std::vector<UpdatableValueConverter*> fValueConverters;
+    int fCurve;
+
+   public:
+    CurveZoneControl(FAUSTFLOAT* zone, int curve, double amin, double amid, double amax,
+                     double min, double init, double max)
+        : ZoneControl(zone), fCurve(0)
+    {
+        assert(curve >= 0 && curve <= 3);
+        fValueConverters.push_back(new AccUpConverter(amin, amid, amax, min, init, max));
+        fValueConverters.push_back(
+            new AccDownConverter(amin, amid, amax, min, init, max));
+        fValueConverters.push_back(
+            new AccUpDownConverter(amin, amid, amax, min, init, max));
+        fValueConverters.push_back(
+            new AccDownUpConverter(amin, amid, amax, min, init, max));
+        fCurve = curve;
+    }
+    virtual ~CurveZoneControl()
+    {
+        std::vector<UpdatableValueConverter*>::iterator it;
+        for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+            delete (*it);
         }
-
-        void setActive(bool on_off)
-        {
-            std::vector<UpdatableValueConverter*>::iterator it;
-            for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
-                (*it)->setActive(on_off);
-            }
+    }
+    void update(double v) const
+    {
+        if (fValueConverters[fCurve]->getActive())
+            *fZone = fValueConverters[fCurve]->ui2faust(v);
+    }
+
+    void setMappingValues(int curve, double amin, double amid, double amax, double min,
+                          double init, double max)
+    {
+        fValueConverters[curve]->setMappingValues(amin, amid, amax, min, init, max);
+        fCurve = curve;
+    }
+
+    void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fValueConverters[fCurve]->getMappingValues(amin, amid, amax);
+    }
+
+    void setActive(bool on_off)
+    {
+        std::vector<UpdatableValueConverter*>::iterator it;
+        for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+            (*it)->setActive(on_off);
         }
+    }
 
-        int getCurve() { return fCurve; }
+    int getCurve() { return fCurve; }
 };
 
 class ZoneReader
 {
+   private:
+    FAUSTFLOAT* fZone;
+    Interpolator fInterpolator;
 
-    private:
+   public:
+    ZoneReader(FAUSTFLOAT* zone, double lo, double hi)
+        : fZone(zone), fInterpolator(lo, hi, 0, 255)
+    {
+    }
 
-        FAUSTFLOAT* fZone;
-        Interpolator fInterpolator;
-
-    public:
-
-        ZoneReader(FAUSTFLOAT* zone, double lo, double hi) : fZone(zone), fInterpolator(lo, hi, 0, 255) {}
-
-        virtual ~ZoneReader() {}
-
-        int getValue()
-        {
-            return (fZone != nullptr) ? int(fInterpolator(*fZone)) : 127;
-        }
+    virtual ~ZoneReader() {}
 
+    int getValue() { return (fZone != nullptr) ? int(fInterpolator(*fZone)) : 127; }
 };
 
 #endif
 /**************************  END  ValueConverter.h **************************/
 
-class APIUI : public PathBuilder, public Meta, public UI
+class APIUI
+    : public PathBuilder
+    , public Meta
+    , public UI
 {
-    public:
-    
-        enum ItemType { kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph };
-  
-    protected:
-    
-        enum { kLin = 0, kLog = 1, kExp = 2 };
-    
-        int fNumParameters;
-        std::vector<std::string> fPaths;
-        std::vector<std::string> fLabels;
-        std::map<std::string, int> fPathMap;
-        std::map<std::string, int> fLabelMap;
-        std::vector<ValueConverter*> fConversion;
-        std::vector<FAUSTFLOAT*> fZone;
-        std::vector<FAUSTFLOAT> fInit;
-        std::vector<FAUSTFLOAT> fMin;
-        std::vector<FAUSTFLOAT> fMax;
-        std::vector<FAUSTFLOAT> fStep;
-        std::vector<ItemType> fItemType;
-        std::vector<std::map<std::string, std::string> > fMetaData;
-        std::vector<ZoneControl*> fAcc[3];
-        std::vector<ZoneControl*> fGyr[3];
-
-        // Screen color control
-        // "...[screencolor:red]..." etc.
-        bool fHasScreenControl;      // true if control screen color metadata
-        ZoneReader* fRedReader;
-        ZoneReader* fGreenReader;
-        ZoneReader* fBlueReader;
-
-        // Current values controlled by metadata
-        std::string fCurrentUnit;
-        int fCurrentScale;
-        std::string fCurrentAcc;
-        std::string fCurrentGyr;
-        std::string fCurrentColor;
-        std::string fCurrentTooltip;
-        std::map<std::string, std::string> fCurrentMetadata;
-    
-        // Add a generic parameter
-        virtual void addParameter(const char* label,
-                                FAUSTFLOAT* zone,
-                                FAUSTFLOAT init,
-                                FAUSTFLOAT min,
-                                FAUSTFLOAT max,
-                                FAUSTFLOAT step,
-                                ItemType type)
-        {
-            std::string path = buildPath(label);
-            fPathMap[path] = fLabelMap[label] = fNumParameters++;
-            fPaths.push_back(path);
-            fLabels.push_back(label);
-            fZone.push_back(zone);
-            fInit.push_back(init);
-            fMin.push_back(min);
-            fMax.push_back(max);
-            fStep.push_back(step);
-            fItemType.push_back(type);
-            
-            // handle scale metadata
-            switch (fCurrentScale) {
-                case kLin:
-                    fConversion.push_back(new LinearValueConverter(0, 1, min, max));
-                    break;
-                case kLog:
-                    fConversion.push_back(new LogValueConverter(0, 1, min, max));
-                    break;
-                case kExp: fConversion.push_back(new ExpValueConverter(0, 1, min, max));
-                    break;
-            }
-            fCurrentScale = kLin;
-            
-            if (fCurrentAcc.size() > 0 && fCurrentGyr.size() > 0) {
-                std::cerr << "warning : 'acc' and 'gyr' metadata used for the same " << label << " parameter !!\n";
-            }
+   public:
+    enum ItemType {
+        kButton = 0,
+        kCheckButton,
+        kVSlider,
+        kHSlider,
+        kNumEntry,
+        kHBargraph,
+        kVBargraph
+    };
+
+   protected:
+    enum { kLin = 0, kLog = 1, kExp = 2 };
+
+    int fNumParameters;
+    std::vector<std::string> fPaths;
+    std::vector<std::string> fLabels;
+    std::map<std::string, int> fPathMap;
+    std::map<std::string, int> fLabelMap;
+    std::vector<ValueConverter*> fConversion;
+    std::vector<FAUSTFLOAT*> fZone;
+    std::vector<FAUSTFLOAT> fInit;
+    std::vector<FAUSTFLOAT> fMin;
+    std::vector<FAUSTFLOAT> fMax;
+    std::vector<FAUSTFLOAT> fStep;
+    std::vector<ItemType> fItemType;
+    std::vector<std::map<std::string, std::string> > fMetaData;
+    std::vector<ZoneControl*> fAcc[3];
+    std::vector<ZoneControl*> fGyr[3];
+
+    // Screen color control
+    // "...[screencolor:red]..." etc.
+    bool fHasScreenControl;  // true if control screen color metadata
+    ZoneReader* fRedReader;
+    ZoneReader* fGreenReader;
+    ZoneReader* fBlueReader;
+
+    // Current values controlled by metadata
+    std::string fCurrentUnit;
+    int fCurrentScale;
+    std::string fCurrentAcc;
+    std::string fCurrentGyr;
+    std::string fCurrentColor;
+    std::string fCurrentTooltip;
+    std::map<std::string, std::string> fCurrentMetadata;
+
+    // Add a generic parameter
+    virtual void addParameter(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                              FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step,
+                              ItemType type)
+    {
+        std::string path = buildPath(label);
+        fPathMap[path] = fLabelMap[label] = fNumParameters++;
+        fPaths.push_back(path);
+        fLabels.push_back(label);
+        fZone.push_back(zone);
+        fInit.push_back(init);
+        fMin.push_back(min);
+        fMax.push_back(max);
+        fStep.push_back(step);
+        fItemType.push_back(type);
+
+        // handle scale metadata
+        switch (fCurrentScale) {
+        case kLin:
+            fConversion.push_back(new LinearValueConverter(0, 1, min, max));
+            break;
+        case kLog:
+            fConversion.push_back(new LogValueConverter(0, 1, min, max));
+            break;
+        case kExp:
+            fConversion.push_back(new ExpValueConverter(0, 1, min, max));
+            break;
+        }
+        fCurrentScale = kLin;
 
-            // handle acc metadata "...[acc : <axe> <curve> <amin> <amid> <amax>]..."
-            if (fCurrentAcc.size() > 0) {
-                std::istringstream iss(fCurrentAcc);
-                int axe, curve;
-                double amin, amid, amax;
-                iss >> axe >> curve >> amin >> amid >> amax;
-
-                if ((0 <= axe) && (axe < 3) &&
-                    (0 <= curve) && (curve < 4) &&
-                    (amin < amax) && (amin <= amid) && (amid <= amax))
-                {
-                    fAcc[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
-                } else {
-                    std::cerr << "incorrect acc metadata : " << fCurrentAcc << std::endl;
-                }
-                fCurrentAcc = "";
-            }
-       
-            // handle gyr metadata "...[gyr : <axe> <curve> <amin> <amid> <amax>]..."
-            if (fCurrentGyr.size() > 0) {
-                std::istringstream iss(fCurrentGyr);
-                int axe, curve;
-                double amin, amid, amax;
-                iss >> axe >> curve >> amin >> amid >> amax;
-
-                if ((0 <= axe) && (axe < 3) &&
-                    (0 <= curve) && (curve < 4) &&
-                    (amin < amax) && (amin <= amid) && (amid <= amax))
-                {
-                    fGyr[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
-                } else {
-                    std::cerr << "incorrect gyr metadata : " << fCurrentGyr << std::endl;
-                }
-                fCurrentGyr = "";
-            }
-        
-            // handle screencolor metadata "...[screencolor:red|green|blue|white]..."
-            if (fCurrentColor.size() > 0) {
-                if ((fCurrentColor == "red") && (fRedReader == 0)) {
-                    fRedReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else if ((fCurrentColor == "green") && (fGreenReader == 0)) {
-                    fGreenReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else if ((fCurrentColor == "blue") && (fBlueReader == 0)) {
-                    fBlueReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else if ((fCurrentColor == "white") && (fRedReader == 0) && (fGreenReader == 0) && (fBlueReader == 0)) {
-                    fRedReader = new ZoneReader(zone, min, max);
-                    fGreenReader = new ZoneReader(zone, min, max);
-                    fBlueReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else {
-                    std::cerr << "incorrect screencolor metadata : " << fCurrentColor << std::endl;
-                }
-            }
-            fCurrentColor = "";
-            
-            fMetaData.push_back(fCurrentMetadata);
-            fCurrentMetadata.clear();
+        if (fCurrentAcc.size() > 0 && fCurrentGyr.size() > 0) {
+            std::cerr << "warning : 'acc' and 'gyr' metadata used for the same " << label
+                      << " parameter !!\n";
         }
 
-        int getZoneIndex(std::vector<ZoneControl*>* table, int p, int val)
-        {
-            FAUSTFLOAT* zone = fZone[p];
-            for (size_t i = 0; i < table[val].size(); i++) {
-                if (zone == table[val][i]->getZone()) return int(i);
+        // handle acc metadata "...[acc : <axe> <curve> <amin> <amid> <amax>]..."
+        if (fCurrentAcc.size() > 0) {
+            std::istringstream iss(fCurrentAcc);
+            int axe, curve;
+            double amin, amid, amax;
+            iss >> axe >> curve >> amin >> amid >> amax;
+
+            if ((0 <= axe) && (axe < 3) && (0 <= curve) && (curve < 4) && (amin < amax)
+                && (amin <= amid) && (amid <= amax)) {
+                fAcc[axe].push_back(
+                    new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
+            } else {
+                std::cerr << "incorrect acc metadata : " << fCurrentAcc << std::endl;
             }
-            return -1;
+            fCurrentAcc = "";
         }
-    
-        void setConverter(std::vector<ZoneControl*>* table, int p, int val, int curve, double amin, double amid, double amax)
-        {
-            int id1 = getZoneIndex(table, p, 0);
-            int id2 = getZoneIndex(table, p, 1);
-            int id3 = getZoneIndex(table, p, 2);
-            
-            // Deactivates everywhere..
-            if (id1 != -1) table[0][id1]->setActive(false);
-            if (id2 != -1) table[1][id2]->setActive(false);
-            if (id3 != -1) table[2][id3]->setActive(false);
-            
-            if (val == -1) { // Means: no more mapping...
-                // So stay all deactivated...
+
+        // handle gyr metadata "...[gyr : <axe> <curve> <amin> <amid> <amax>]..."
+        if (fCurrentGyr.size() > 0) {
+            std::istringstream iss(fCurrentGyr);
+            int axe, curve;
+            double amin, amid, amax;
+            iss >> axe >> curve >> amin >> amid >> amax;
+
+            if ((0 <= axe) && (axe < 3) && (0 <= curve) && (curve < 4) && (amin < amax)
+                && (amin <= amid) && (amid <= amax)) {
+                fGyr[axe].push_back(
+                    new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
             } else {
-                int id4 = getZoneIndex(table, p, val);
-                if (id4 != -1) {
-                    // Reactivate the one we edit...
-                    table[val][id4]->setMappingValues(curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]);
-                    table[val][id4]->setActive(true);
-                } else {
-                    // Allocate a new CurveZoneControl which is 'active' by default
-                    FAUSTFLOAT* zone = fZone[p];
-                    table[val].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]));
-                }
+                std::cerr << "incorrect gyr metadata : " << fCurrentGyr << std::endl;
             }
+            fCurrentGyr = "";
         }
-    
-        void getConverter(std::vector<ZoneControl*>* table, int p, int& val, int& curve, double& amin, double& amid, double& amax)
-        {
-            int id1 = getZoneIndex(table, p, 0);
-            int id2 = getZoneIndex(table, p, 1);
-            int id3 = getZoneIndex(table, p, 2);
-            
-            if (id1 != -1) {
-                val = 0;
-                curve = table[val][id1]->getCurve();
-                table[val][id1]->getMappingValues(amin, amid, amax);
-            } else if (id2 != -1) {
-                val = 1;
-                curve = table[val][id2]->getCurve();
-                table[val][id2]->getMappingValues(amin, amid, amax);
-            } else if (id3 != -1) {
-                val = 2;
-                curve = table[val][id3]->getCurve();
-                table[val][id3]->getMappingValues(amin, amid, amax);
+
+        // handle screencolor metadata "...[screencolor:red|green|blue|white]..."
+        if (fCurrentColor.size() > 0) {
+            if ((fCurrentColor == "red") && (fRedReader == 0)) {
+                fRedReader        = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
+            } else if ((fCurrentColor == "green") && (fGreenReader == 0)) {
+                fGreenReader      = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
+            } else if ((fCurrentColor == "blue") && (fBlueReader == 0)) {
+                fBlueReader       = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
+            } else if ((fCurrentColor == "white") && (fRedReader == 0)
+                       && (fGreenReader == 0) && (fBlueReader == 0)) {
+                fRedReader        = new ZoneReader(zone, min, max);
+                fGreenReader      = new ZoneReader(zone, min, max);
+                fBlueReader       = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
             } else {
-                val = -1; // No mapping
-                curve = 0;
-                amin = -100.;
-                amid = 0.;
-                amax = 100.;
+                std::cerr << "incorrect screencolor metadata : " << fCurrentColor
+                          << std::endl;
             }
         }
+        fCurrentColor = "";
 
-     public:
-    
-        enum Type { kAcc = 0, kGyr = 1, kNoType };
-   
-        APIUI() : fNumParameters(0), fHasScreenControl(false), fRedReader(0), fGreenReader(0), fBlueReader(0), fCurrentScale(kLin)
-        {}
+        fMetaData.push_back(fCurrentMetadata);
+        fCurrentMetadata.clear();
+    }
 
-        virtual ~APIUI()
-        {
-            for (auto& it : fConversion) delete it;
-            for (int i = 0; i < 3; i++) {
-                for (auto& it : fAcc[i]) delete it;
-                for (auto& it : fGyr[i]) delete it;
+    int getZoneIndex(std::vector<ZoneControl*>* table, int p, int val)
+    {
+        FAUSTFLOAT* zone = fZone[p];
+        for (size_t i = 0; i < table[val].size(); i++) {
+            if (zone == table[val][i]->getZone()) return int(i);
+        }
+        return -1;
+    }
+
+    void setConverter(std::vector<ZoneControl*>* table, int p, int val, int curve,
+                      double amin, double amid, double amax)
+    {
+        int id1 = getZoneIndex(table, p, 0);
+        int id2 = getZoneIndex(table, p, 1);
+        int id3 = getZoneIndex(table, p, 2);
+
+        // Deactivates everywhere..
+        if (id1 != -1) table[0][id1]->setActive(false);
+        if (id2 != -1) table[1][id2]->setActive(false);
+        if (id3 != -1) table[2][id3]->setActive(false);
+
+        if (val == -1) {  // Means: no more mapping...
+            // So stay all deactivated...
+        } else {
+            int id4 = getZoneIndex(table, p, val);
+            if (id4 != -1) {
+                // Reactivate the one we edit...
+                table[val][id4]->setMappingValues(curve, amin, amid, amax, fMin[p],
+                                                  fInit[p], fMax[p]);
+                table[val][id4]->setActive(true);
+            } else {
+                // Allocate a new CurveZoneControl which is 'active' by default
+                FAUSTFLOAT* zone = fZone[p];
+                table[val].push_back(new CurveZoneControl(zone, curve, amin, amid, amax,
+                                                          fMin[p], fInit[p], fMax[p]));
             }
-            delete fRedReader;
-            delete fGreenReader;
-            delete fBlueReader;
         }
-    
-        // -- widget's layouts
-
-        virtual void openTabBox(const char* label) { pushLabel(label); }
-        virtual void openHorizontalBox(const char* label) { pushLabel(label); }
-        virtual void openVerticalBox(const char* label) { pushLabel(label); }
-        virtual void closeBox() { popLabel(); }
-
-        // -- active widgets
-
-        virtual void addButton(const char* label, FAUSTFLOAT* zone)
-        {
-            addParameter(label, zone, 0, 0, 1, 1, kButton);
+    }
+
+    void getConverter(std::vector<ZoneControl*>* table, int p, int& val, int& curve,
+                      double& amin, double& amid, double& amax)
+    {
+        int id1 = getZoneIndex(table, p, 0);
+        int id2 = getZoneIndex(table, p, 1);
+        int id3 = getZoneIndex(table, p, 2);
+
+        if (id1 != -1) {
+            val   = 0;
+            curve = table[val][id1]->getCurve();
+            table[val][id1]->getMappingValues(amin, amid, amax);
+        } else if (id2 != -1) {
+            val   = 1;
+            curve = table[val][id2]->getCurve();
+            table[val][id2]->getMappingValues(amin, amid, amax);
+        } else if (id3 != -1) {
+            val   = 2;
+            curve = table[val][id3]->getCurve();
+            table[val][id3]->getMappingValues(amin, amid, amax);
+        } else {
+            val   = -1;  // No mapping
+            curve = 0;
+            amin  = -100.;
+            amid  = 0.;
+            amax  = 100.;
         }
-
-        virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
-        {
-            addParameter(label, zone, 0, 0, 1, 1, kCheckButton);
+    }
+
+   public:
+    enum Type { kAcc = 0, kGyr = 1, kNoType };
+
+    APIUI()
+        : fNumParameters(0)
+        , fHasScreenControl(false)
+        , fRedReader(0)
+        , fGreenReader(0)
+        , fBlueReader(0)
+        , fCurrentScale(kLin)
+    {
+    }
+
+    virtual ~APIUI()
+    {
+        for (auto& it : fConversion) delete it;
+        for (int i = 0; i < 3; i++) {
+            for (auto& it : fAcc[i]) delete it;
+            for (auto& it : fGyr[i]) delete it;
         }
+        delete fRedReader;
+        delete fGreenReader;
+        delete fBlueReader;
+    }
 
-        virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
-        {
-            addParameter(label, zone, init, min, max, step, kVSlider);
-        }
+    // -- widget's layouts
 
-        virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
-        {
-            addParameter(label, zone, init, min, max, step, kHSlider);
-        }
+    virtual void openTabBox(const char* label) { pushLabel(label); }
+    virtual void openHorizontalBox(const char* label) { pushLabel(label); }
+    virtual void openVerticalBox(const char* label) { pushLabel(label); }
+    virtual void closeBox() { popLabel(); }
 
-        virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
-        {
-            addParameter(label, zone, init, min, max, step, kNumEntry);
-        }
+    // -- active widgets
 
-        // -- passive widgets
+    virtual void addButton(const char* label, FAUSTFLOAT* zone)
+    {
+        addParameter(label, zone, 0, 0, 1, 1, kButton);
+    }
+
+    virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
+    {
+        addParameter(label, zone, 0, 0, 1, 1, kCheckButton);
+    }
+
+    virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                                   FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+    {
+        addParameter(label, zone, init, min, max, step, kVSlider);
+    }
+
+    virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                                     FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+    {
+        addParameter(label, zone, init, min, max, step, kHSlider);
+    }
+
+    virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                             FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+    {
+        addParameter(label, zone, init, min, max, step, kNumEntry);
+    }
 
-        virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
-        {
-            addParameter(label, zone, min, min, max, (max-min)/1000.0, kHBargraph);
-        }
+    // -- passive widgets
 
-        virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
-        {
-            addParameter(label, zone, min, min, max, (max-min)/1000.0, kVBargraph);
-        }
-    
-        // -- soundfiles
-    
-        virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) {}
+    virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone,
+                                       FAUSTFLOAT min, FAUSTFLOAT max)
+    {
+        addParameter(label, zone, min, min, max, (max - min) / 1000.0, kHBargraph);
+    }
 
-        // -- metadata declarations
+    virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min,
+                                     FAUSTFLOAT max)
+    {
+        addParameter(label, zone, min, min, max, (max - min) / 1000.0, kVBargraph);
+    }
 
-        virtual void declare(FAUSTFLOAT* zone, const char* key, const char* val)
-        {
-            // Keep metadata
-            fCurrentMetadata[key] = val;
-            
-            if (strcmp(key, "scale") == 0) {
-                if (strcmp(val, "log") == 0) {
-                    fCurrentScale = kLog;
-                } else if (strcmp(val, "exp") == 0) {
-                    fCurrentScale = kExp;
-                } else {
-                    fCurrentScale = kLin;
-                }
-            } else if (strcmp(key, "unit") == 0) {
-                fCurrentUnit = val;
-            } else if (strcmp(key, "acc") == 0) {
-                fCurrentAcc = val;
-            } else if (strcmp(key, "gyr") == 0) {
-                fCurrentGyr = val;
-            } else if (strcmp(key, "screencolor") == 0) {
-                fCurrentColor = val; // val = "red", "green", "blue" or "white"
-            } else if (strcmp(key, "tooltip") == 0) {
-                fCurrentTooltip = val;
-            }
-        }
+    // -- soundfiles
 
-        virtual void declare(const char* key, const char* val)
-        {}
+    virtual void addSoundfile(const char* label, const char* filename,
+                              Soundfile** sf_zone)
+    {
+    }
 
-               //-------------------------------------------------------------------------------
-               // Simple API part
-               //-------------------------------------------------------------------------------
-               int getParamsCount() { return fNumParameters; }
-        int getParamIndex(const char* path)
-        {
-            if (fPathMap.find(path) != fPathMap.end()) {
-                return fPathMap[path];
-            } else if (fLabelMap.find(path) != fLabelMap.end()) {
-                return fLabelMap[path];
-            } else {
-                return -1;
-            }
-        }
-        const char* getParamAddress(int p) { return fPaths[p].c_str(); }
-        const char* getParamLabel(int p) { return fLabels[p].c_str(); }
-        std::map<const char*, const char*> getMetadata(int p)
-        {
-            std::map<const char*, const char*> res;
-            std::map<std::string, std::string> metadata = fMetaData[p];
-            for (auto it : metadata) {
-                res[it.first.c_str()] = it.second.c_str();
-            }
-            return res;
-        }
+    // -- metadata declarations
 
-        const char* getMetadata(int p, const char* key)
-        {
-            return (fMetaData[p].find(key) != fMetaData[p].end()) ? fMetaData[p][key].c_str() : "";
-        }
-        FAUSTFLOAT getParamMin(int p) { return fMin[p]; }
-        FAUSTFLOAT getParamMax(int p) { return fMax[p]; }
-        FAUSTFLOAT getParamStep(int p) { return fStep[p]; }
-        FAUSTFLOAT getParamInit(int p) { return fInit[p]; }
-
-        FAUSTFLOAT* getParamZone(int p) { return fZone[p]; }
-        FAUSTFLOAT getParamValue(int p) { return *fZone[p]; }
-        void setParamValue(int p, FAUSTFLOAT v) { *fZone[p] = v; }
-
-        double getParamRatio(int p) { return fConversion[p]->faust2ui(*fZone[p]); }
-        void setParamRatio(int p, double r) { *fZone[p] = fConversion[p]->ui2faust(r); }
-
-        double value2ratio(int p, double r)    { return fConversion[p]->faust2ui(r); }
-        double ratio2value(int p, double r)    { return fConversion[p]->ui2faust(r); }
-    
-        /**
-         * Return the control type (kAcc, kGyr, or -1) for a given parameter
-         *
-         * @param p - the UI parameter index
-         *
-         * @return the type
-         */
-        Type getParamType(int p)
-        {
-            if (p >= 0) {
-                if (getZoneIndex(fAcc, p, 0) != -1
-                    || getZoneIndex(fAcc, p, 1) != -1
-                    || getZoneIndex(fAcc, p, 2) != -1) {
-                    return kAcc;
-                } else if (getZoneIndex(fGyr, p, 0) != -1
-                           || getZoneIndex(fGyr, p, 1) != -1
-                           || getZoneIndex(fGyr, p, 2) != -1) {
-                    return kGyr;
-                }
-            }
-            return kNoType;
-        }
-    
-        /**
-         * Return the Item type (kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph) for a given parameter
-         *
-         * @param p - the UI parameter index
-         *
-         * @return the Item type
-         */
-        ItemType getParamItemType(int p)
-        {
-            return fItemType[p];
-        }
-   
-        /**
-         * Set a new value coming from an accelerometer, propagate it to all relevant FAUSTFLOAT* zones.
-         *
-         * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
-         * @param value - the new value
-         *
-         */
-        void propagateAcc(int acc, double value)
-        {
-            for (size_t i = 0; i < fAcc[acc].size(); i++) {
-                fAcc[acc][i]->update(value);
-            }
-        }
-    
-        /**
-         * Used to edit accelerometer curves and mapping. Set curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer (-1 means "no mapping")
-         * @param curve - between 0 and 3
-         * @param amin - mapping 'min' point
-         * @param amid - mapping 'middle' point
-         * @param amax - mapping 'max' point
-         *
-         */
-        void setAccConverter(int p, int acc, int curve, double amin, double amid, double amax)
-        {
-            setConverter(fAcc, p, acc, curve, amin, amid, amax);
-        }
-    
-        /**
-         * Used to edit gyroscope curves and mapping. Set curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param acc - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope (-1 means "no mapping")
-         * @param curve - between 0 and 3
-         * @param amin - mapping 'min' point
-         * @param amid - mapping 'middle' point
-         * @param amax - mapping 'max' point
-         *
-         */
-        void setGyrConverter(int p, int gyr, int curve, double amin, double amid, double amax)
-        {
-             setConverter(fGyr, p, gyr, curve, amin, amid, amax);
-        }
-    
-        /**
-         * Used to edit accelerometer curves and mapping. Get curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param acc - the acc value to be retrieved (-1 means "no mapping")
-         * @param curve - the curve value to be retrieved
-         * @param amin - the amin value to be retrieved
-         * @param amid - the amid value to be retrieved
-         * @param amax - the amax value to be retrieved
-         *
-         */
-        void getAccConverter(int p, int& acc, int& curve, double& amin, double& amid, double& amax)
-        {
-            getConverter(fAcc, p, acc, curve, amin, amid, amax);
-        }
+    virtual void declare(FAUSTFLOAT* zone, const char* key, const char* val)
+    {
+        // Keep metadata
+        fCurrentMetadata[key] = val;
 
-        /**
-         * Used to edit gyroscope curves and mapping. Get curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param gyr - the gyr value to be retrieved (-1 means "no mapping")
-         * @param curve - the curve value to be retrieved
-         * @param amin - the amin value to be retrieved
-         * @param amid - the amid value to be retrieved
-         * @param amax - the amax value to be retrieved
-         *
-         */
-        void getGyrConverter(int p, int& gyr, int& curve, double& amin, double& amid, double& amax)
-        {
-            getConverter(fGyr, p, gyr, curve, amin, amid, amax);
-        }
-    
-        /**
-         * Set a new value coming from an gyroscope, propagate it to all relevant FAUSTFLOAT* zones.
-         *
-         * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
-         * @param value - the new value
-         *
-         */
-        void propagateGyr(int gyr, double value)
-        {
-            for (size_t i = 0; i < fGyr[gyr].size(); i++) {
-                fGyr[gyr][i]->update(value);
+        if (strcmp(key, "scale") == 0) {
+            if (strcmp(val, "log") == 0) {
+                fCurrentScale = kLog;
+            } else if (strcmp(val, "exp") == 0) {
+                fCurrentScale = kExp;
+            } else {
+                fCurrentScale = kLin;
             }
+        } else if (strcmp(key, "unit") == 0) {
+            fCurrentUnit = val;
+        } else if (strcmp(key, "acc") == 0) {
+            fCurrentAcc = val;
+        } else if (strcmp(key, "gyr") == 0) {
+            fCurrentGyr = val;
+        } else if (strcmp(key, "screencolor") == 0) {
+            fCurrentColor = val;  // val = "red", "green", "blue" or "white"
+        } else if (strcmp(key, "tooltip") == 0) {
+            fCurrentTooltip = val;
         }
-    
-        /**
-         * Get the number of FAUSTFLOAT* zones controlled with the accelerometer
-         *
-         * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
-         * @return the number of zones
-         *
-         */
-        int getAccCount(int acc)
-        {
-            return (acc >= 0 && acc < 3) ? int(fAcc[acc].size()) : 0;
-        }
-    
-        /**
-         * Get the number of FAUSTFLOAT* zones controlled with the gyroscope
-         *
-         * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
-         * @param the number of zones
-         *
-         */
-        int getGyrCount(int gyr)
-        {
-            return (gyr >= 0 && gyr < 3) ? int(fGyr[gyr].size()) : 0;
+    }
+
+    virtual void declare(const char* key, const char* val) {}
+
+    //-------------------------------------------------------------------------------
+    // Simple API part
+    //-------------------------------------------------------------------------------
+    int getParamsCount() { return fNumParameters; }
+    int getParamIndex(const char* path)
+    {
+        if (fPathMap.find(path) != fPathMap.end()) {
+            return fPathMap[path];
+        } else if (fLabelMap.find(path) != fLabelMap.end()) {
+            return fLabelMap[path];
+        } else {
+            return -1;
         }
-   
-        // getScreenColor() : -1 means no screen color control (no screencolor metadata found)
-        // otherwise return 0x00RRGGBB a ready to use color
-        int getScreenColor()
-        {
-            if (fHasScreenControl) {
-                int r = (fRedReader) ? fRedReader->getValue() : 0;
-                int g = (fGreenReader) ? fGreenReader->getValue() : 0;
-                int b = (fBlueReader) ? fBlueReader->getValue() : 0;
-                return (r<<16) | (g<<8) | b;
-            } else {
-                return -1;
+    }
+    const char* getParamAddress(int p) { return fPaths[p].c_str(); }
+    const char* getParamLabel(int p) { return fLabels[p].c_str(); }
+    std::map<const char*, const char*> getMetadata(int p)
+    {
+        std::map<const char*, const char*> res;
+        std::map<std::string, std::string> metadata = fMetaData[p];
+        for (auto it : metadata) { res[it.first.c_str()] = it.second.c_str(); }
+        return res;
+    }
+
+    const char* getMetadata(int p, const char* key)
+    {
+        return (fMetaData[p].find(key) != fMetaData[p].end()) ? fMetaData[p][key].c_str()
+                                                              : "";
+    }
+    FAUSTFLOAT getParamMin(int p) { return fMin[p]; }
+    FAUSTFLOAT getParamMax(int p) { return fMax[p]; }
+    FAUSTFLOAT getParamStep(int p) { return fStep[p]; }
+    FAUSTFLOAT getParamInit(int p) { return fInit[p]; }
+
+    FAUSTFLOAT* getParamZone(int p) { return fZone[p]; }
+    FAUSTFLOAT getParamValue(int p) { return *fZone[p]; }
+    void setParamValue(int p, FAUSTFLOAT v) { *fZone[p] = v; }
+
+    double getParamRatio(int p) { return fConversion[p]->faust2ui(*fZone[p]); }
+    void setParamRatio(int p, double r) { *fZone[p] = fConversion[p]->ui2faust(r); }
+
+    double value2ratio(int p, double r) { return fConversion[p]->faust2ui(r); }
+    double ratio2value(int p, double r) { return fConversion[p]->ui2faust(r); }
+
+    /**
+     * Return the control type (kAcc, kGyr, or -1) for a given parameter
+     *
+     * @param p - the UI parameter index
+     *
+     * @return the type
+     */
+    Type getParamType(int p)
+    {
+        if (p >= 0) {
+            if (getZoneIndex(fAcc, p, 0) != -1 || getZoneIndex(fAcc, p, 1) != -1
+                || getZoneIndex(fAcc, p, 2) != -1) {
+                return kAcc;
+            } else if (getZoneIndex(fGyr, p, 0) != -1 || getZoneIndex(fGyr, p, 1) != -1
+                       || getZoneIndex(fGyr, p, 2) != -1) {
+                return kGyr;
             }
         }
+        return kNoType;
+    }
+
+    /**
+     * Return the Item type (kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry,
+     * kHBargraph, kVBargraph) for a given parameter
+     *
+     * @param p - the UI parameter index
+     *
+     * @return the Item type
+     */
+    ItemType getParamItemType(int p) { return fItemType[p]; }
+
+    /**
+     * Set a new value coming from an accelerometer, propagate it to all relevant
+     * FAUSTFLOAT* zones.
+     *
+     * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+     * @param value - the new value
+     *
+     */
+    void propagateAcc(int acc, double value)
+    {
+        for (size_t i = 0; i < fAcc[acc].size(); i++) { fAcc[acc][i]->update(value); }
+    }
+
+    /**
+     * Used to edit accelerometer curves and mapping. Set curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+     * (-1 means "no mapping")
+     * @param curve - between 0 and 3
+     * @param amin - mapping 'min' point
+     * @param amid - mapping 'middle' point
+     * @param amax - mapping 'max' point
+     *
+     */
+    void setAccConverter(int p, int acc, int curve, double amin, double amid, double amax)
+    {
+        setConverter(fAcc, p, acc, curve, amin, amid, amax);
+    }
+
+    /**
+     * Used to edit gyroscope curves and mapping. Set curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param acc - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope (-1 means "no
+     * mapping")
+     * @param curve - between 0 and 3
+     * @param amin - mapping 'min' point
+     * @param amid - mapping 'middle' point
+     * @param amax - mapping 'max' point
+     *
+     */
+    void setGyrConverter(int p, int gyr, int curve, double amin, double amid, double amax)
+    {
+        setConverter(fGyr, p, gyr, curve, amin, amid, amax);
+    }
+
+    /**
+     * Used to edit accelerometer curves and mapping. Get curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param acc - the acc value to be retrieved (-1 means "no mapping")
+     * @param curve - the curve value to be retrieved
+     * @param amin - the amin value to be retrieved
+     * @param amid - the amid value to be retrieved
+     * @param amax - the amax value to be retrieved
+     *
+     */
+    void getAccConverter(int p, int& acc, int& curve, double& amin, double& amid,
+                         double& amax)
+    {
+        getConverter(fAcc, p, acc, curve, amin, amid, amax);
+    }
+
+    /**
+     * Used to edit gyroscope curves and mapping. Get curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param gyr - the gyr value to be retrieved (-1 means "no mapping")
+     * @param curve - the curve value to be retrieved
+     * @param amin - the amin value to be retrieved
+     * @param amid - the amid value to be retrieved
+     * @param amax - the amax value to be retrieved
+     *
+     */
+    void getGyrConverter(int p, int& gyr, int& curve, double& amin, double& amid,
+                         double& amax)
+    {
+        getConverter(fGyr, p, gyr, curve, amin, amid, amax);
+    }
+
+    /**
+     * Set a new value coming from an gyroscope, propagate it to all relevant FAUSTFLOAT*
+     * zones.
+     *
+     * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+     * @param value - the new value
+     *
+     */
+    void propagateGyr(int gyr, double value)
+    {
+        for (size_t i = 0; i < fGyr[gyr].size(); i++) { fGyr[gyr][i]->update(value); }
+    }
+
+    /**
+     * Get the number of FAUSTFLOAT* zones controlled with the accelerometer
+     *
+     * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+     * @return the number of zones
+     *
+     */
+    int getAccCount(int acc) { return (acc >= 0 && acc < 3) ? int(fAcc[acc].size()) : 0; }
+
+    /**
+     * Get the number of FAUSTFLOAT* zones controlled with the gyroscope
+     *
+     * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+     * @param the number of zones
+     *
+     */
+    int getGyrCount(int gyr) { return (gyr >= 0 && gyr < 3) ? int(fGyr[gyr].size()) : 0; }
+
+    // getScreenColor() : -1 means no screen color control (no screencolor metadata found)
+    // otherwise return 0x00RRGGBB a ready to use color
+    int getScreenColor()
+    {
+        if (fHasScreenControl) {
+            int r = (fRedReader) ? fRedReader->getValue() : 0;
+            int g = (fGreenReader) ? fGreenReader->getValue() : 0;
+            int b = (fBlueReader) ? fBlueReader->getValue() : 0;
+            return (r << 16) | (g << 8) | b;
+        } else {
+            return -1;
+        }
+    }
 };
 
 #endif
@@ -1550,605 +1583,498 @@ class APIUI : public PathBuilder, public Meta, public UI
 //  FAUST Generated Code
 //----------------------------------------------------------------------------
 
-
 #ifndef FAUSTFLOAT
 #define FAUSTFLOAT float
-#endif 
+#endif
 
 #include <algorithm>
 #include <cmath>
-#include <math.h>
 
-
-#ifndef FAUSTCLASS 
+#ifndef FAUSTCLASS
 #define FAUSTCLASS freeverbmonodsp
 #endif
 
-#ifdef __APPLE__ 
+#ifdef __APPLE__
 #define exp10f __exp10f
-#define exp10 __exp10
+#define exp10  __exp10
 #endif
 
-class freeverbmonodsp : public dsp {
-       
- private:
-       
-       FAUSTFLOAT fVslider0;
-       int fSampleRate;
-       float fConst0;
-       float fConst1;
-       FAUSTFLOAT fVslider1;
-       float fConst2;
-       FAUSTFLOAT fVslider2;
-       float fRec9[2];
-       int IOTA;
-       float fVec0[8192];
-       int iConst3;
-       float fConst4;
-       FAUSTFLOAT fVslider3;
-       float fRec8[2];
-       float fRec11[2];
-       float fVec1[8192];
-       int iConst5;
-       float fRec10[2];
-       float fRec13[2];
-       float fVec2[8192];
-       int iConst6;
-       float fRec12[2];
-       float fRec15[2];
-       float fVec3[8192];
-       int iConst7;
-       float fRec14[2];
-       float fRec17[2];
-       float fVec4[8192];
-       int iConst8;
-       float fRec16[2];
-       float fRec19[2];
-       float fVec5[8192];
-       int iConst9;
-       float fRec18[2];
-       float fRec21[2];
-       float fVec6[8192];
-       int iConst10;
-       float fRec20[2];
-       float fRec23[2];
-       float fVec7[8192];
-       int iConst11;
-       float fRec22[2];
-       float fVec8[2048];
-       int iConst12;
-       float fRec6[2];
-       float fVec9[2048];
-       int iConst13;
-       float fRec4[2];
-       float fVec10[2048];
-       int iConst14;
-       float fRec2[2];
-       float fVec11[2048];
-       int iConst15;
-       float fRec0[2];
-       float fRec33[2];
-       float fVec12[8192];
-       float fRec32[2];
-       float fRec35[2];
-       float fVec13[8192];
-       float fRec34[2];
-       float fRec37[2];
-       float fVec14[8192];
-       float fRec36[2];
-       float fRec39[2];
-       float fVec15[8192];
-       float fRec38[2];
-       float fRec41[2];
-       float fVec16[8192];
-       float fRec40[2];
-       float fRec43[2];
-       float fVec17[8192];
-       float fRec42[2];
-       float fRec45[2];
-       float fVec18[8192];
-       float fRec44[2];
-       float fRec47[2];
-       float fVec19[8192];
-       float fRec46[2];
-       float fVec20[2048];
-       int iConst16;
-       float fRec30[2];
-       float fVec21[2048];
-       int iConst17;
-       float fRec28[2];
-       float fVec22[2048];
-       int iConst18;
-       float fRec26[2];
-       float fVec23[1024];
-       int iConst19;
-       float fRec24[2];
-       
- public:
-       
-       void metadata(Meta* m) { 
-               m->declare("delays.lib/name", "Faust Delay Library");
-               m->declare("delays.lib/version", "0.1");
-               m->declare("filename", "freeverbmonodsp.dsp");
-               m->declare("filters.lib/allpass_comb:author", "Julius O. Smith III");
-               m->declare("filters.lib/allpass_comb:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
-               m->declare("filters.lib/allpass_comb:license", "MIT-style STK-4.3 license");
-               m->declare("filters.lib/lowpass0_highpass1", "MIT-style STK-4.3 license");
-               m->declare("filters.lib/name", "Faust Filters Library");
-               m->declare("freeverbdsp.dsp/author", "Romain Michon");
-               m->declare("freeverbdsp.dsp/description", "Freeverb implementation in Faust, from the Faust Library's dm.freeverb_demo in demos.lib");
-               m->declare("freeverbdsp.dsp/license", "LGPL");
-               m->declare("freeverbdsp.dsp/name", "freeverb");
-               m->declare("freeverbdsp.dsp/version", "0.0");
-               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.3");
-               m->declare("name", "freeverbmonodsp");
-               m->declare("platform.lib/name", "Generic Platform Library");
-               m->declare("platform.lib/version", "0.1");
-               m->declare("reverbs.lib/name", "Faust Reverb Library");
-               m->declare("reverbs.lib/version", "0.0");
-       }
-
-       virtual int getNumInputs() {
-               return 1;
-       }
-       virtual int getNumOutputs() {
-               return 1;
-       }
-       virtual int getInputRate(int channel) {
-               int rate;
-               switch ((channel)) {
-                       case 0: {
-                               rate = 1;
-                               break;
-                       }
-                       default: {
-                               rate = -1;
-                               break;
-                       }
-               }
-               return rate;
-       }
-       virtual int getOutputRate(int channel) {
-               int rate;
-               switch ((channel)) {
-                       case 0: {
-                               rate = 1;
-                               break;
-                       }
-                       default: {
-                               rate = -1;
-                               break;
-                       }
-               }
-               return rate;
-       }
-       
-       static void classInit(int sample_rate) {
-       }
-       
-       virtual void instanceConstants(int sample_rate) {
-               fSampleRate = sample_rate;
-               fConst0 = std::min<float>(192000.0f, std::max<float>(1.0f, float(fSampleRate)));
-               fConst1 = (12348.0f / fConst0);
-               fConst2 = (17640.0f / fConst0);
-               iConst3 = int((0.0253061224f * fConst0));
-               fConst4 = (0.00104308384f * fConst0);
-               iConst5 = int((0.0269387756f * fConst0));
-               iConst6 = int((0.0289569162f * fConst0));
-               iConst7 = int((0.0307482984f * fConst0));
-               iConst8 = int((0.0322448984f * fConst0));
-               iConst9 = int((0.033809524f * fConst0));
-               iConst10 = int((0.0353061222f * fConst0));
-               iConst11 = int((0.0366666652f * fConst0));
-               iConst12 = int((0.0126077095f * fConst0));
-               iConst13 = int((0.00999999978f * fConst0));
-               iConst14 = int((0.00773242628f * fConst0));
-               iConst15 = int((0.00510204071f * fConst0));
-               iConst16 = std::min<int>(1024, std::max<int>(0, (iConst12 + -1)));
-               iConst17 = std::min<int>(1024, std::max<int>(0, (iConst13 + -1)));
-               iConst18 = std::min<int>(1024, std::max<int>(0, (iConst14 + -1)));
-               iConst19 = std::min<int>(1024, std::max<int>(0, (iConst15 + -1)));
-       }
-       
-       virtual void instanceResetUserInterface() {
-               fVslider0 = FAUSTFLOAT(0.10000000000000001f);
-               fVslider1 = FAUSTFLOAT(0.10000000000000001f);
-               fVslider2 = FAUSTFLOAT(0.5f);
-               fVslider3 = FAUSTFLOAT(0.5f);
-       }
-       
-       virtual void instanceClear() {
-               for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) {
-                       fRec9[l0] = 0.0f;
-               }
-               IOTA = 0;
-               for (int l1 = 0; (l1 < 8192); l1 = (l1 + 1)) {
-                       fVec0[l1] = 0.0f;
-               }
-               for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) {
-                       fRec8[l2] = 0.0f;
-               }
-               for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) {
-                       fRec11[l3] = 0.0f;
-               }
-               for (int l4 = 0; (l4 < 8192); l4 = (l4 + 1)) {
-                       fVec1[l4] = 0.0f;
-               }
-               for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) {
-                       fRec10[l5] = 0.0f;
-               }
-               for (int l6 = 0; (l6 < 2); l6 = (l6 + 1)) {
-                       fRec13[l6] = 0.0f;
-               }
-               for (int l7 = 0; (l7 < 8192); l7 = (l7 + 1)) {
-                       fVec2[l7] = 0.0f;
-               }
-               for (int l8 = 0; (l8 < 2); l8 = (l8 + 1)) {
-                       fRec12[l8] = 0.0f;
-               }
-               for (int l9 = 0; (l9 < 2); l9 = (l9 + 1)) {
-                       fRec15[l9] = 0.0f;
-               }
-               for (int l10 = 0; (l10 < 8192); l10 = (l10 + 1)) {
-                       fVec3[l10] = 0.0f;
-               }
-               for (int l11 = 0; (l11 < 2); l11 = (l11 + 1)) {
-                       fRec14[l11] = 0.0f;
-               }
-               for (int l12 = 0; (l12 < 2); l12 = (l12 + 1)) {
-                       fRec17[l12] = 0.0f;
-               }
-               for (int l13 = 0; (l13 < 8192); l13 = (l13 + 1)) {
-                       fVec4[l13] = 0.0f;
-               }
-               for (int l14 = 0; (l14 < 2); l14 = (l14 + 1)) {
-                       fRec16[l14] = 0.0f;
-               }
-               for (int l15 = 0; (l15 < 2); l15 = (l15 + 1)) {
-                       fRec19[l15] = 0.0f;
-               }
-               for (int l16 = 0; (l16 < 8192); l16 = (l16 + 1)) {
-                       fVec5[l16] = 0.0f;
-               }
-               for (int l17 = 0; (l17 < 2); l17 = (l17 + 1)) {
-                       fRec18[l17] = 0.0f;
-               }
-               for (int l18 = 0; (l18 < 2); l18 = (l18 + 1)) {
-                       fRec21[l18] = 0.0f;
-               }
-               for (int l19 = 0; (l19 < 8192); l19 = (l19 + 1)) {
-                       fVec6[l19] = 0.0f;
-               }
-               for (int l20 = 0; (l20 < 2); l20 = (l20 + 1)) {
-                       fRec20[l20] = 0.0f;
-               }
-               for (int l21 = 0; (l21 < 2); l21 = (l21 + 1)) {
-                       fRec23[l21] = 0.0f;
-               }
-               for (int l22 = 0; (l22 < 8192); l22 = (l22 + 1)) {
-                       fVec7[l22] = 0.0f;
-               }
-               for (int l23 = 0; (l23 < 2); l23 = (l23 + 1)) {
-                       fRec22[l23] = 0.0f;
-               }
-               for (int l24 = 0; (l24 < 2048); l24 = (l24 + 1)) {
-                       fVec8[l24] = 0.0f;
-               }
-               for (int l25 = 0; (l25 < 2); l25 = (l25 + 1)) {
-                       fRec6[l25] = 0.0f;
-               }
-               for (int l26 = 0; (l26 < 2048); l26 = (l26 + 1)) {
-                       fVec9[l26] = 0.0f;
-               }
-               for (int l27 = 0; (l27 < 2); l27 = (l27 + 1)) {
-                       fRec4[l27] = 0.0f;
-               }
-               for (int l28 = 0; (l28 < 2048); l28 = (l28 + 1)) {
-                       fVec10[l28] = 0.0f;
-               }
-               for (int l29 = 0; (l29 < 2); l29 = (l29 + 1)) {
-                       fRec2[l29] = 0.0f;
-               }
-               for (int l30 = 0; (l30 < 2048); l30 = (l30 + 1)) {
-                       fVec11[l30] = 0.0f;
-               }
-               for (int l31 = 0; (l31 < 2); l31 = (l31 + 1)) {
-                       fRec0[l31] = 0.0f;
-               }
-               for (int l32 = 0; (l32 < 2); l32 = (l32 + 1)) {
-                       fRec33[l32] = 0.0f;
-               }
-               for (int l33 = 0; (l33 < 8192); l33 = (l33 + 1)) {
-                       fVec12[l33] = 0.0f;
-               }
-               for (int l34 = 0; (l34 < 2); l34 = (l34 + 1)) {
-                       fRec32[l34] = 0.0f;
-               }
-               for (int l35 = 0; (l35 < 2); l35 = (l35 + 1)) {
-                       fRec35[l35] = 0.0f;
-               }
-               for (int l36 = 0; (l36 < 8192); l36 = (l36 + 1)) {
-                       fVec13[l36] = 0.0f;
-               }
-               for (int l37 = 0; (l37 < 2); l37 = (l37 + 1)) {
-                       fRec34[l37] = 0.0f;
-               }
-               for (int l38 = 0; (l38 < 2); l38 = (l38 + 1)) {
-                       fRec37[l38] = 0.0f;
-               }
-               for (int l39 = 0; (l39 < 8192); l39 = (l39 + 1)) {
-                       fVec14[l39] = 0.0f;
-               }
-               for (int l40 = 0; (l40 < 2); l40 = (l40 + 1)) {
-                       fRec36[l40] = 0.0f;
-               }
-               for (int l41 = 0; (l41 < 2); l41 = (l41 + 1)) {
-                       fRec39[l41] = 0.0f;
-               }
-               for (int l42 = 0; (l42 < 8192); l42 = (l42 + 1)) {
-                       fVec15[l42] = 0.0f;
-               }
-               for (int l43 = 0; (l43 < 2); l43 = (l43 + 1)) {
-                       fRec38[l43] = 0.0f;
-               }
-               for (int l44 = 0; (l44 < 2); l44 = (l44 + 1)) {
-                       fRec41[l44] = 0.0f;
-               }
-               for (int l45 = 0; (l45 < 8192); l45 = (l45 + 1)) {
-                       fVec16[l45] = 0.0f;
-               }
-               for (int l46 = 0; (l46 < 2); l46 = (l46 + 1)) {
-                       fRec40[l46] = 0.0f;
-               }
-               for (int l47 = 0; (l47 < 2); l47 = (l47 + 1)) {
-                       fRec43[l47] = 0.0f;
-               }
-               for (int l48 = 0; (l48 < 8192); l48 = (l48 + 1)) {
-                       fVec17[l48] = 0.0f;
-               }
-               for (int l49 = 0; (l49 < 2); l49 = (l49 + 1)) {
-                       fRec42[l49] = 0.0f;
-               }
-               for (int l50 = 0; (l50 < 2); l50 = (l50 + 1)) {
-                       fRec45[l50] = 0.0f;
-               }
-               for (int l51 = 0; (l51 < 8192); l51 = (l51 + 1)) {
-                       fVec18[l51] = 0.0f;
-               }
-               for (int l52 = 0; (l52 < 2); l52 = (l52 + 1)) {
-                       fRec44[l52] = 0.0f;
-               }
-               for (int l53 = 0; (l53 < 2); l53 = (l53 + 1)) {
-                       fRec47[l53] = 0.0f;
-               }
-               for (int l54 = 0; (l54 < 8192); l54 = (l54 + 1)) {
-                       fVec19[l54] = 0.0f;
-               }
-               for (int l55 = 0; (l55 < 2); l55 = (l55 + 1)) {
-                       fRec46[l55] = 0.0f;
-               }
-               for (int l56 = 0; (l56 < 2048); l56 = (l56 + 1)) {
-                       fVec20[l56] = 0.0f;
-               }
-               for (int l57 = 0; (l57 < 2); l57 = (l57 + 1)) {
-                       fRec30[l57] = 0.0f;
-               }
-               for (int l58 = 0; (l58 < 2048); l58 = (l58 + 1)) {
-                       fVec21[l58] = 0.0f;
-               }
-               for (int l59 = 0; (l59 < 2); l59 = (l59 + 1)) {
-                       fRec28[l59] = 0.0f;
-               }
-               for (int l60 = 0; (l60 < 2048); l60 = (l60 + 1)) {
-                       fVec22[l60] = 0.0f;
-               }
-               for (int l61 = 0; (l61 < 2); l61 = (l61 + 1)) {
-                       fRec26[l61] = 0.0f;
-               }
-               for (int l62 = 0; (l62 < 1024); l62 = (l62 + 1)) {
-                       fVec23[l62] = 0.0f;
-               }
-               for (int l63 = 0; (l63 < 2); l63 = (l63 + 1)) {
-                       fRec24[l63] = 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 freeverbmonodsp* clone() {
-               return new freeverbmonodsp();
-       }
-       
-       virtual int getSampleRate() {
-               return fSampleRate;
-       }
-       
-       virtual void buildUserInterface(UI* ui_interface) {
-               ui_interface->openHorizontalBox("Freeverb");
-               ui_interface->declare(0, "0", "");
-               ui_interface->openVerticalBox("0x00");
-               ui_interface->declare(&fVslider2, "0", "");
-               ui_interface->declare(&fVslider2, "style", "knob");
-               ui_interface->declare(&fVslider2, "tooltip", "Somehow control the   density of the reverb.");
-               ui_interface->addVerticalSlider("Damp", &fVslider2, 0.5f, 0.0f, 1.0f, 0.0250000004f);
-               ui_interface->declare(&fVslider1, "1", "");
-               ui_interface->declare(&fVslider1, "style", "knob");
-               ui_interface->declare(&fVslider1, "tooltip", "The room size   between 0 and 1 with 1 for the largest room.");
-               ui_interface->addVerticalSlider("RoomSize", &fVslider1, 0.100000001f, 0.0f, 1.0f, 0.0250000004f);
-               ui_interface->declare(&fVslider3, "2", "");
-               ui_interface->declare(&fVslider3, "style", "knob");
-               ui_interface->declare(&fVslider3, "tooltip", "Spatial   spread between 0 and 1 with 1 for maximum spread.");
-               ui_interface->addVerticalSlider("Stereo Spread", &fVslider3, 0.5f, 0.0f, 1.0f, 0.00999999978f);
-               ui_interface->closeBox();
-               ui_interface->declare(&fVslider0, "1", "");
-               ui_interface->declare(&fVslider0, "tooltip", "The amount of reverb applied to the signal   between 0 and 1 with 1 for the maximum amount of reverb.");
-               ui_interface->addVerticalSlider("Wet", &fVslider0, 0.100000001f, 0.0f, 1.0f, 0.0250000004f);
-               ui_interface->closeBox();
-       }
-       
-       virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
-               FAUSTFLOAT* input0 = inputs[0];
-               FAUSTFLOAT* output0 = outputs[0];
-               float fSlow0 = float(fVslider0);
-               float fSlow1 = (0.200000003f * fSlow0);
-               float fSlow2 = ((fConst1 * float(fVslider1)) + 0.699999988f);
-               float fSlow3 = (fConst2 * float(fVslider2));
-               float fSlow4 = (1.0f - fSlow3);
-               int iSlow5 = int((fConst4 * float(fVslider3)));
-               int iSlow6 = (iConst3 + iSlow5);
-               int iSlow7 = (iConst5 + iSlow5);
-               int iSlow8 = (iConst6 + iSlow5);
-               int iSlow9 = (iConst7 + iSlow5);
-               int iSlow10 = (iConst8 + iSlow5);
-               int iSlow11 = (iConst9 + iSlow5);
-               int iSlow12 = (iConst10 + iSlow5);
-               int iSlow13 = (iConst11 + iSlow5);
-               int iSlow14 = (iSlow5 + -1);
-               int iSlow15 = std::min<int>(1024, std::max<int>(0, (iConst12 + iSlow14)));
-               int iSlow16 = std::min<int>(1024, std::max<int>(0, (iConst13 + iSlow14)));
-               int iSlow17 = std::min<int>(1024, std::max<int>(0, (iConst14 + iSlow14)));
-               int iSlow18 = std::min<int>(1024, std::max<int>(0, (iConst15 + iSlow14)));
-               float fSlow19 = (2.0f * (1.0f - fSlow0));
-               for (int i = 0; (i < count); i = (i + 1)) {
-                       float fTemp0 = float(input0[i]);
-                       float fTemp1 = (fSlow1 * fTemp0);
-                       fRec9[0] = ((fSlow3 * fRec9[1]) + (fSlow4 * fRec8[1]));
-                       fVec0[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec9[0]));
-                       fRec8[0] = fVec0[((IOTA - iSlow6) & 8191)];
-                       fRec11[0] = ((fSlow3 * fRec11[1]) + (fSlow4 * fRec10[1]));
-                       fVec1[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec11[0]));
-                       fRec10[0] = fVec1[((IOTA - iSlow7) & 8191)];
-                       fRec13[0] = ((fSlow3 * fRec13[1]) + (fSlow4 * fRec12[1]));
-                       fVec2[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec13[0]));
-                       fRec12[0] = fVec2[((IOTA - iSlow8) & 8191)];
-                       fRec15[0] = ((fSlow3 * fRec15[1]) + (fSlow4 * fRec14[1]));
-                       fVec3[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec15[0]));
-                       fRec14[0] = fVec3[((IOTA - iSlow9) & 8191)];
-                       fRec17[0] = ((fSlow3 * fRec17[1]) + (fSlow4 * fRec16[1]));
-                       fVec4[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec17[0]));
-                       fRec16[0] = fVec4[((IOTA - iSlow10) & 8191)];
-                       fRec19[0] = ((fSlow3 * fRec19[1]) + (fSlow4 * fRec18[1]));
-                       fVec5[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec19[0]));
-                       fRec18[0] = fVec5[((IOTA - iSlow11) & 8191)];
-                       fRec21[0] = ((fSlow3 * fRec21[1]) + (fSlow4 * fRec20[1]));
-                       fVec6[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec21[0]));
-                       fRec20[0] = fVec6[((IOTA - iSlow12) & 8191)];
-                       fRec23[0] = ((fSlow3 * fRec23[1]) + (fSlow4 * fRec22[1]));
-                       fVec7[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec23[0]));
-                       fRec22[0] = fVec7[((IOTA - iSlow13) & 8191)];
-                       float fTemp2 = ((((((((fRec8[0] + fRec10[0]) + fRec12[0]) + fRec14[0]) + fRec16[0]) + fRec18[0]) + fRec20[0]) + fRec22[0]) + (0.5f * fRec6[1]));
-                       fVec8[(IOTA & 2047)] = fTemp2;
-                       fRec6[0] = fVec8[((IOTA - iSlow15) & 2047)];
-                       float fRec7 = (0.0f - (0.5f * fTemp2));
-                       float fTemp3 = (fRec6[1] + (fRec7 + (0.5f * fRec4[1])));
-                       fVec9[(IOTA & 2047)] = fTemp3;
-                       fRec4[0] = fVec9[((IOTA - iSlow16) & 2047)];
-                       float fRec5 = (0.0f - (0.5f * fTemp3));
-                       float fTemp4 = (fRec4[1] + (fRec5 + (0.5f * fRec2[1])));
-                       fVec10[(IOTA & 2047)] = fTemp4;
-                       fRec2[0] = fVec10[((IOTA - iSlow17) & 2047)];
-                       float fRec3 = (0.0f - (0.5f * fTemp4));
-                       float fTemp5 = (fRec2[1] + (fRec3 + (0.5f * fRec0[1])));
-                       fVec11[(IOTA & 2047)] = fTemp5;
-                       fRec0[0] = fVec11[((IOTA - iSlow18) & 2047)];
-                       float fRec1 = (0.0f - (0.5f * fTemp5));
-                       fRec33[0] = ((fSlow3 * fRec33[1]) + (fSlow4 * fRec32[1]));
-                       fVec12[(IOTA & 8191)] = ((fSlow2 * fRec33[0]) + fTemp1);
-                       fRec32[0] = fVec12[((IOTA - iConst3) & 8191)];
-                       fRec35[0] = ((fSlow3 * fRec35[1]) + (fSlow4 * fRec34[1]));
-                       fVec13[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec35[0]));
-                       fRec34[0] = fVec13[((IOTA - iConst5) & 8191)];
-                       fRec37[0] = ((fSlow3 * fRec37[1]) + (fSlow4 * fRec36[1]));
-                       fVec14[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec37[0]));
-                       fRec36[0] = fVec14[((IOTA - iConst6) & 8191)];
-                       fRec39[0] = ((fSlow3 * fRec39[1]) + (fSlow4 * fRec38[1]));
-                       fVec15[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec39[0]));
-                       fRec38[0] = fVec15[((IOTA - iConst7) & 8191)];
-                       fRec41[0] = ((fSlow3 * fRec41[1]) + (fSlow4 * fRec40[1]));
-                       fVec16[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec41[0]));
-                       fRec40[0] = fVec16[((IOTA - iConst8) & 8191)];
-                       fRec43[0] = ((fSlow3 * fRec43[1]) + (fSlow4 * fRec42[1]));
-                       fVec17[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec43[0]));
-                       fRec42[0] = fVec17[((IOTA - iConst9) & 8191)];
-                       fRec45[0] = ((fSlow3 * fRec45[1]) + (fSlow4 * fRec44[1]));
-                       fVec18[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec45[0]));
-                       fRec44[0] = fVec18[((IOTA - iConst10) & 8191)];
-                       fRec47[0] = ((fSlow3 * fRec47[1]) + (fSlow4 * fRec46[1]));
-                       fVec19[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec47[0]));
-                       fRec46[0] = fVec19[((IOTA - iConst11) & 8191)];
-                       float fTemp6 = ((((((((fRec32[0] + fRec34[0]) + fRec36[0]) + fRec38[0]) + fRec40[0]) + fRec42[0]) + fRec44[0]) + fRec46[0]) + (0.5f * fRec30[1]));
-                       fVec20[(IOTA & 2047)] = fTemp6;
-                       fRec30[0] = fVec20[((IOTA - iConst16) & 2047)];
-                       float fRec31 = (0.0f - (0.5f * fTemp6));
-                       float fTemp7 = (fRec30[1] + (fRec31 + (0.5f * fRec28[1])));
-                       fVec21[(IOTA & 2047)] = fTemp7;
-                       fRec28[0] = fVec21[((IOTA - iConst17) & 2047)];
-                       float fRec29 = (0.0f - (0.5f * fTemp7));
-                       float fTemp8 = (fRec28[1] + (fRec29 + (0.5f * fRec26[1])));
-                       fVec22[(IOTA & 2047)] = fTemp8;
-                       fRec26[0] = fVec22[((IOTA - iConst18) & 2047)];
-                       float fRec27 = (0.0f - (0.5f * fTemp8));
-                       float fTemp9 = (fRec26[1] + (fRec27 + (0.5f * fRec24[1])));
-                       fVec23[(IOTA & 1023)] = fTemp9;
-                       fRec24[0] = fVec23[((IOTA - iConst19) & 1023)];
-                       float fRec25 = (0.0f - (0.5f * fTemp9));
-                       output0[i] = FAUSTFLOAT((fRec0[1] + ((fRec24[1] + (fRec25 + fRec1)) + (fSlow19 * fTemp0))));
-                       fRec9[1] = fRec9[0];
-                       IOTA = (IOTA + 1);
-                       fRec8[1] = fRec8[0];
-                       fRec11[1] = fRec11[0];
-                       fRec10[1] = fRec10[0];
-                       fRec13[1] = fRec13[0];
-                       fRec12[1] = fRec12[0];
-                       fRec15[1] = fRec15[0];
-                       fRec14[1] = fRec14[0];
-                       fRec17[1] = fRec17[0];
-                       fRec16[1] = fRec16[0];
-                       fRec19[1] = fRec19[0];
-                       fRec18[1] = fRec18[0];
-                       fRec21[1] = fRec21[0];
-                       fRec20[1] = fRec20[0];
-                       fRec23[1] = fRec23[0];
-                       fRec22[1] = fRec22[0];
-                       fRec6[1] = fRec6[0];
-                       fRec4[1] = fRec4[0];
-                       fRec2[1] = fRec2[0];
-                       fRec0[1] = fRec0[0];
-                       fRec33[1] = fRec33[0];
-                       fRec32[1] = fRec32[0];
-                       fRec35[1] = fRec35[0];
-                       fRec34[1] = fRec34[0];
-                       fRec37[1] = fRec37[0];
-                       fRec36[1] = fRec36[0];
-                       fRec39[1] = fRec39[0];
-                       fRec38[1] = fRec38[0];
-                       fRec41[1] = fRec41[0];
-                       fRec40[1] = fRec40[0];
-                       fRec43[1] = fRec43[0];
-                       fRec42[1] = fRec42[0];
-                       fRec45[1] = fRec45[0];
-                       fRec44[1] = fRec44[0];
-                       fRec47[1] = fRec47[0];
-                       fRec46[1] = fRec46[0];
-                       fRec30[1] = fRec30[0];
-                       fRec28[1] = fRec28[0];
-                       fRec26[1] = fRec26[0];
-                       fRec24[1] = fRec24[0];
-               }
-       }
-
+class freeverbmonodsp : public dsp
+{
+   private:
+    FAUSTFLOAT fVslider0;
+    int fSampleRate;
+    float fConst0;
+    float fConst1;
+    FAUSTFLOAT fVslider1;
+    float fConst2;
+    FAUSTFLOAT fVslider2;
+    float fRec9[2];
+    int IOTA;
+    float fVec0[8192];
+    int iConst3;
+    float fConst4;
+    FAUSTFLOAT fVslider3;
+    float fRec8[2];
+    float fRec11[2];
+    float fVec1[8192];
+    int iConst5;
+    float fRec10[2];
+    float fRec13[2];
+    float fVec2[8192];
+    int iConst6;
+    float fRec12[2];
+    float fRec15[2];
+    float fVec3[8192];
+    int iConst7;
+    float fRec14[2];
+    float fRec17[2];
+    float fVec4[8192];
+    int iConst8;
+    float fRec16[2];
+    float fRec19[2];
+    float fVec5[8192];
+    int iConst9;
+    float fRec18[2];
+    float fRec21[2];
+    float fVec6[8192];
+    int iConst10;
+    float fRec20[2];
+    float fRec23[2];
+    float fVec7[8192];
+    int iConst11;
+    float fRec22[2];
+    float fVec8[2048];
+    int iConst12;
+    float fRec6[2];
+    float fVec9[2048];
+    int iConst13;
+    float fRec4[2];
+    float fVec10[2048];
+    int iConst14;
+    float fRec2[2];
+    float fVec11[2048];
+    int iConst15;
+    float fRec0[2];
+    float fRec33[2];
+    float fVec12[8192];
+    float fRec32[2];
+    float fRec35[2];
+    float fVec13[8192];
+    float fRec34[2];
+    float fRec37[2];
+    float fVec14[8192];
+    float fRec36[2];
+    float fRec39[2];
+    float fVec15[8192];
+    float fRec38[2];
+    float fRec41[2];
+    float fVec16[8192];
+    float fRec40[2];
+    float fRec43[2];
+    float fVec17[8192];
+    float fRec42[2];
+    float fRec45[2];
+    float fVec18[8192];
+    float fRec44[2];
+    float fRec47[2];
+    float fVec19[8192];
+    float fRec46[2];
+    float fVec20[2048];
+    int iConst16;
+    float fRec30[2];
+    float fVec21[2048];
+    int iConst17;
+    float fRec28[2];
+    float fVec22[2048];
+    int iConst18;
+    float fRec26[2];
+    float fVec23[1024];
+    int iConst19;
+    float fRec24[2];
+
+   public:
+    void metadata(Meta* m)
+    {
+        m->declare("delays.lib/name", "Faust Delay Library");
+        m->declare("delays.lib/version", "0.1");
+        m->declare("filename", "freeverbmonodsp.dsp");
+        m->declare("filters.lib/allpass_comb:author", "Julius O. Smith III");
+        m->declare(
+            "filters.lib/allpass_comb:copyright",
+            "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+        m->declare("filters.lib/allpass_comb:license", "MIT-style STK-4.3 license");
+        m->declare("filters.lib/lowpass0_highpass1", "MIT-style STK-4.3 license");
+        m->declare("filters.lib/name", "Faust Filters Library");
+        m->declare("freeverbdsp.dsp/author", "Romain Michon");
+        m->declare("freeverbdsp.dsp/description",
+                   "Freeverb implementation in Faust, from the Faust Library's "
+                   "dm.freeverb_demo in demos.lib");
+        m->declare("freeverbdsp.dsp/license", "LGPL");
+        m->declare("freeverbdsp.dsp/name", "freeverb");
+        m->declare("freeverbdsp.dsp/version", "0.0");
+        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.3");
+        m->declare("name", "freeverbmonodsp");
+        m->declare("platform.lib/name", "Generic Platform Library");
+        m->declare("platform.lib/version", "0.1");
+        m->declare("reverbs.lib/name", "Faust Reverb Library");
+        m->declare("reverbs.lib/version", "0.0");
+    }
+
+    virtual int getNumInputs() { return 1; }
+    virtual int getNumOutputs() { return 1; }
+    virtual int getInputRate(int channel)
+    {
+        int rate;
+        switch ((channel)) {
+        case 0: {
+            rate = 1;
+            break;
+        }
+        default: {
+            rate = -1;
+            break;
+        }
+        }
+        return rate;
+    }
+    virtual int getOutputRate(int channel)
+    {
+        int rate;
+        switch ((channel)) {
+        case 0: {
+            rate = 1;
+            break;
+        }
+        default: {
+            rate = -1;
+            break;
+        }
+        }
+        return rate;
+    }
+
+    static void classInit(int /*sample_rate*/) {}
+
+    virtual void instanceConstants(int sample_rate)
+    {
+        fSampleRate = sample_rate;
+        fConst0  = std::min<float>(192000.0f, std::max<float>(1.0f, float(fSampleRate)));
+        fConst1  = (12348.0f / fConst0);
+        fConst2  = (17640.0f / fConst0);
+        iConst3  = int((0.0253061224f * fConst0));
+        fConst4  = (0.00104308384f * fConst0);
+        iConst5  = int((0.0269387756f * fConst0));
+        iConst6  = int((0.0289569162f * fConst0));
+        iConst7  = int((0.0307482984f * fConst0));
+        iConst8  = int((0.0322448984f * fConst0));
+        iConst9  = int((0.033809524f * fConst0));
+        iConst10 = int((0.0353061222f * fConst0));
+        iConst11 = int((0.0366666652f * fConst0));
+        iConst12 = int((0.0126077095f * fConst0));
+        iConst13 = int((0.00999999978f * fConst0));
+        iConst14 = int((0.00773242628f * fConst0));
+        iConst15 = int((0.00510204071f * fConst0));
+        iConst16 = std::min<int>(1024, std::max<int>(0, (iConst12 + -1)));
+        iConst17 = std::min<int>(1024, std::max<int>(0, (iConst13 + -1)));
+        iConst18 = std::min<int>(1024, std::max<int>(0, (iConst14 + -1)));
+        iConst19 = std::min<int>(1024, std::max<int>(0, (iConst15 + -1)));
+    }
+
+    virtual void instanceResetUserInterface()
+    {
+        fVslider0 = FAUSTFLOAT(0.10000000000000001f);
+        fVslider1 = FAUSTFLOAT(0.10000000000000001f);
+        fVslider2 = FAUSTFLOAT(0.5f);
+        fVslider3 = FAUSTFLOAT(0.5f);
+    }
+
+    virtual void instanceClear()
+    {
+        for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec9[l0] = 0.0f; }
+        IOTA = 0;
+        for (int l1 = 0; (l1 < 8192); l1 = (l1 + 1)) { fVec0[l1] = 0.0f; }
+        for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) { fRec8[l2] = 0.0f; }
+        for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) { fRec11[l3] = 0.0f; }
+        for (int l4 = 0; (l4 < 8192); l4 = (l4 + 1)) { fVec1[l4] = 0.0f; }
+        for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) { fRec10[l5] = 0.0f; }
+        for (int l6 = 0; (l6 < 2); l6 = (l6 + 1)) { fRec13[l6] = 0.0f; }
+        for (int l7 = 0; (l7 < 8192); l7 = (l7 + 1)) { fVec2[l7] = 0.0f; }
+        for (int l8 = 0; (l8 < 2); l8 = (l8 + 1)) { fRec12[l8] = 0.0f; }
+        for (int l9 = 0; (l9 < 2); l9 = (l9 + 1)) { fRec15[l9] = 0.0f; }
+        for (int l10 = 0; (l10 < 8192); l10 = (l10 + 1)) { fVec3[l10] = 0.0f; }
+        for (int l11 = 0; (l11 < 2); l11 = (l11 + 1)) { fRec14[l11] = 0.0f; }
+        for (int l12 = 0; (l12 < 2); l12 = (l12 + 1)) { fRec17[l12] = 0.0f; }
+        for (int l13 = 0; (l13 < 8192); l13 = (l13 + 1)) { fVec4[l13] = 0.0f; }
+        for (int l14 = 0; (l14 < 2); l14 = (l14 + 1)) { fRec16[l14] = 0.0f; }
+        for (int l15 = 0; (l15 < 2); l15 = (l15 + 1)) { fRec19[l15] = 0.0f; }
+        for (int l16 = 0; (l16 < 8192); l16 = (l16 + 1)) { fVec5[l16] = 0.0f; }
+        for (int l17 = 0; (l17 < 2); l17 = (l17 + 1)) { fRec18[l17] = 0.0f; }
+        for (int l18 = 0; (l18 < 2); l18 = (l18 + 1)) { fRec21[l18] = 0.0f; }
+        for (int l19 = 0; (l19 < 8192); l19 = (l19 + 1)) { fVec6[l19] = 0.0f; }
+        for (int l20 = 0; (l20 < 2); l20 = (l20 + 1)) { fRec20[l20] = 0.0f; }
+        for (int l21 = 0; (l21 < 2); l21 = (l21 + 1)) { fRec23[l21] = 0.0f; }
+        for (int l22 = 0; (l22 < 8192); l22 = (l22 + 1)) { fVec7[l22] = 0.0f; }
+        for (int l23 = 0; (l23 < 2); l23 = (l23 + 1)) { fRec22[l23] = 0.0f; }
+        for (int l24 = 0; (l24 < 2048); l24 = (l24 + 1)) { fVec8[l24] = 0.0f; }
+        for (int l25 = 0; (l25 < 2); l25 = (l25 + 1)) { fRec6[l25] = 0.0f; }
+        for (int l26 = 0; (l26 < 2048); l26 = (l26 + 1)) { fVec9[l26] = 0.0f; }
+        for (int l27 = 0; (l27 < 2); l27 = (l27 + 1)) { fRec4[l27] = 0.0f; }
+        for (int l28 = 0; (l28 < 2048); l28 = (l28 + 1)) { fVec10[l28] = 0.0f; }
+        for (int l29 = 0; (l29 < 2); l29 = (l29 + 1)) { fRec2[l29] = 0.0f; }
+        for (int l30 = 0; (l30 < 2048); l30 = (l30 + 1)) { fVec11[l30] = 0.0f; }
+        for (int l31 = 0; (l31 < 2); l31 = (l31 + 1)) { fRec0[l31] = 0.0f; }
+        for (int l32 = 0; (l32 < 2); l32 = (l32 + 1)) { fRec33[l32] = 0.0f; }
+        for (int l33 = 0; (l33 < 8192); l33 = (l33 + 1)) { fVec12[l33] = 0.0f; }
+        for (int l34 = 0; (l34 < 2); l34 = (l34 + 1)) { fRec32[l34] = 0.0f; }
+        for (int l35 = 0; (l35 < 2); l35 = (l35 + 1)) { fRec35[l35] = 0.0f; }
+        for (int l36 = 0; (l36 < 8192); l36 = (l36 + 1)) { fVec13[l36] = 0.0f; }
+        for (int l37 = 0; (l37 < 2); l37 = (l37 + 1)) { fRec34[l37] = 0.0f; }
+        for (int l38 = 0; (l38 < 2); l38 = (l38 + 1)) { fRec37[l38] = 0.0f; }
+        for (int l39 = 0; (l39 < 8192); l39 = (l39 + 1)) { fVec14[l39] = 0.0f; }
+        for (int l40 = 0; (l40 < 2); l40 = (l40 + 1)) { fRec36[l40] = 0.0f; }
+        for (int l41 = 0; (l41 < 2); l41 = (l41 + 1)) { fRec39[l41] = 0.0f; }
+        for (int l42 = 0; (l42 < 8192); l42 = (l42 + 1)) { fVec15[l42] = 0.0f; }
+        for (int l43 = 0; (l43 < 2); l43 = (l43 + 1)) { fRec38[l43] = 0.0f; }
+        for (int l44 = 0; (l44 < 2); l44 = (l44 + 1)) { fRec41[l44] = 0.0f; }
+        for (int l45 = 0; (l45 < 8192); l45 = (l45 + 1)) { fVec16[l45] = 0.0f; }
+        for (int l46 = 0; (l46 < 2); l46 = (l46 + 1)) { fRec40[l46] = 0.0f; }
+        for (int l47 = 0; (l47 < 2); l47 = (l47 + 1)) { fRec43[l47] = 0.0f; }
+        for (int l48 = 0; (l48 < 8192); l48 = (l48 + 1)) { fVec17[l48] = 0.0f; }
+        for (int l49 = 0; (l49 < 2); l49 = (l49 + 1)) { fRec42[l49] = 0.0f; }
+        for (int l50 = 0; (l50 < 2); l50 = (l50 + 1)) { fRec45[l50] = 0.0f; }
+        for (int l51 = 0; (l51 < 8192); l51 = (l51 + 1)) { fVec18[l51] = 0.0f; }
+        for (int l52 = 0; (l52 < 2); l52 = (l52 + 1)) { fRec44[l52] = 0.0f; }
+        for (int l53 = 0; (l53 < 2); l53 = (l53 + 1)) { fRec47[l53] = 0.0f; }
+        for (int l54 = 0; (l54 < 8192); l54 = (l54 + 1)) { fVec19[l54] = 0.0f; }
+        for (int l55 = 0; (l55 < 2); l55 = (l55 + 1)) { fRec46[l55] = 0.0f; }
+        for (int l56 = 0; (l56 < 2048); l56 = (l56 + 1)) { fVec20[l56] = 0.0f; }
+        for (int l57 = 0; (l57 < 2); l57 = (l57 + 1)) { fRec30[l57] = 0.0f; }
+        for (int l58 = 0; (l58 < 2048); l58 = (l58 + 1)) { fVec21[l58] = 0.0f; }
+        for (int l59 = 0; (l59 < 2); l59 = (l59 + 1)) { fRec28[l59] = 0.0f; }
+        for (int l60 = 0; (l60 < 2048); l60 = (l60 + 1)) { fVec22[l60] = 0.0f; }
+        for (int l61 = 0; (l61 < 2); l61 = (l61 + 1)) { fRec26[l61] = 0.0f; }
+        for (int l62 = 0; (l62 < 1024); l62 = (l62 + 1)) { fVec23[l62] = 0.0f; }
+        for (int l63 = 0; (l63 < 2); l63 = (l63 + 1)) { fRec24[l63] = 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 freeverbmonodsp* clone() { return new freeverbmonodsp(); }
+
+    virtual int getSampleRate() { return fSampleRate; }
+
+    virtual void buildUserInterface(UI* ui_interface)
+    {
+        ui_interface->openHorizontalBox("Freeverb");
+        ui_interface->declare(0, "0", "");
+        ui_interface->openVerticalBox("0x00");
+        ui_interface->declare(&fVslider2, "0", "");
+        ui_interface->declare(&fVslider2, "style", "knob");
+        ui_interface->declare(&fVslider2, "tooltip",
+                              "Somehow control the   density of the reverb.");
+        ui_interface->addVerticalSlider("Damp", &fVslider2, 0.5f, 0.0f, 1.0f,
+                                        0.0250000004f);
+        ui_interface->declare(&fVslider1, "1", "");
+        ui_interface->declare(&fVslider1, "style", "knob");
+        ui_interface->declare(
+            &fVslider1, "tooltip",
+            "The room size   between 0 and 1 with 1 for the largest room.");
+        ui_interface->addVerticalSlider("RoomSize", &fVslider1, 0.100000001f, 0.0f, 1.0f,
+                                        0.0250000004f);
+        ui_interface->declare(&fVslider3, "2", "");
+        ui_interface->declare(&fVslider3, "style", "knob");
+        ui_interface->declare(
+            &fVslider3, "tooltip",
+            "Spatial   spread between 0 and 1 with 1 for maximum spread.");
+        ui_interface->addVerticalSlider("Stereo Spread", &fVslider3, 0.5f, 0.0f, 1.0f,
+                                        0.00999999978f);
+        ui_interface->closeBox();
+        ui_interface->declare(&fVslider0, "1", "");
+        ui_interface->declare(&fVslider0, "tooltip",
+                              "The amount of reverb applied to the signal   between 0 "
+                              "and 1 with 1 for the maximum amount of reverb.");
+        ui_interface->addVerticalSlider("Wet", &fVslider0, 0.100000001f, 0.0f, 1.0f,
+                                        0.0250000004f);
+        ui_interface->closeBox();
+    }
+
+    virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
+    {
+        FAUSTFLOAT* input0  = inputs[0];
+        FAUSTFLOAT* output0 = outputs[0];
+        float fSlow0        = float(fVslider0);
+        float fSlow1        = (0.200000003f * fSlow0);
+        float fSlow2        = ((fConst1 * float(fVslider1)) + 0.699999988f);
+        float fSlow3        = (fConst2 * float(fVslider2));
+        float fSlow4        = (1.0f - fSlow3);
+        int iSlow5          = int((fConst4 * float(fVslider3)));
+        int iSlow6          = (iConst3 + iSlow5);
+        int iSlow7          = (iConst5 + iSlow5);
+        int iSlow8          = (iConst6 + iSlow5);
+        int iSlow9          = (iConst7 + iSlow5);
+        int iSlow10         = (iConst8 + iSlow5);
+        int iSlow11         = (iConst9 + iSlow5);
+        int iSlow12         = (iConst10 + iSlow5);
+        int iSlow13         = (iConst11 + iSlow5);
+        int iSlow14         = (iSlow5 + -1);
+        int iSlow15         = std::min<int>(1024, std::max<int>(0, (iConst12 + iSlow14)));
+        int iSlow16         = std::min<int>(1024, std::max<int>(0, (iConst13 + iSlow14)));
+        int iSlow17         = std::min<int>(1024, std::max<int>(0, (iConst14 + iSlow14)));
+        int iSlow18         = std::min<int>(1024, std::max<int>(0, (iConst15 + iSlow14)));
+        float fSlow19       = (2.0f * (1.0f - fSlow0));
+        for (int i = 0; (i < count); i = (i + 1)) {
+            float fTemp0         = float(input0[i]);
+            float fTemp1         = (fSlow1 * fTemp0);
+            fRec9[0]             = ((fSlow3 * fRec9[1]) + (fSlow4 * fRec8[1]));
+            fVec0[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec9[0]));
+            fRec8[0]             = fVec0[((IOTA - iSlow6) & 8191)];
+            fRec11[0]            = ((fSlow3 * fRec11[1]) + (fSlow4 * fRec10[1]));
+            fVec1[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec11[0]));
+            fRec10[0]            = fVec1[((IOTA - iSlow7) & 8191)];
+            fRec13[0]            = ((fSlow3 * fRec13[1]) + (fSlow4 * fRec12[1]));
+            fVec2[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec13[0]));
+            fRec12[0]            = fVec2[((IOTA - iSlow8) & 8191)];
+            fRec15[0]            = ((fSlow3 * fRec15[1]) + (fSlow4 * fRec14[1]));
+            fVec3[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec15[0]));
+            fRec14[0]            = fVec3[((IOTA - iSlow9) & 8191)];
+            fRec17[0]            = ((fSlow3 * fRec17[1]) + (fSlow4 * fRec16[1]));
+            fVec4[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec17[0]));
+            fRec16[0]            = fVec4[((IOTA - iSlow10) & 8191)];
+            fRec19[0]            = ((fSlow3 * fRec19[1]) + (fSlow4 * fRec18[1]));
+            fVec5[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec19[0]));
+            fRec18[0]            = fVec5[((IOTA - iSlow11) & 8191)];
+            fRec21[0]            = ((fSlow3 * fRec21[1]) + (fSlow4 * fRec20[1]));
+            fVec6[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec21[0]));
+            fRec20[0]            = fVec6[((IOTA - iSlow12) & 8191)];
+            fRec23[0]            = ((fSlow3 * fRec23[1]) + (fSlow4 * fRec22[1]));
+            fVec7[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec23[0]));
+            fRec22[0]            = fVec7[((IOTA - iSlow13) & 8191)];
+            float fTemp2 =
+                ((((((((fRec8[0] + fRec10[0]) + fRec12[0]) + fRec14[0]) + fRec16[0])
+                    + fRec18[0])
+                   + fRec20[0])
+                  + fRec22[0])
+                 + (0.5f * fRec6[1]));
+            fVec8[(IOTA & 2047)]  = fTemp2;
+            fRec6[0]              = fVec8[((IOTA - iSlow15) & 2047)];
+            float fRec7           = (0.0f - (0.5f * fTemp2));
+            float fTemp3          = (fRec6[1] + (fRec7 + (0.5f * fRec4[1])));
+            fVec9[(IOTA & 2047)]  = fTemp3;
+            fRec4[0]              = fVec9[((IOTA - iSlow16) & 2047)];
+            float fRec5           = (0.0f - (0.5f * fTemp3));
+            float fTemp4          = (fRec4[1] + (fRec5 + (0.5f * fRec2[1])));
+            fVec10[(IOTA & 2047)] = fTemp4;
+            fRec2[0]              = fVec10[((IOTA - iSlow17) & 2047)];
+            float fRec3           = (0.0f - (0.5f * fTemp4));
+            float fTemp5          = (fRec2[1] + (fRec3 + (0.5f * fRec0[1])));
+            fVec11[(IOTA & 2047)] = fTemp5;
+            fRec0[0]              = fVec11[((IOTA - iSlow18) & 2047)];
+            float fRec1           = (0.0f - (0.5f * fTemp5));
+            fRec33[0]             = ((fSlow3 * fRec33[1]) + (fSlow4 * fRec32[1]));
+            fVec12[(IOTA & 8191)] = ((fSlow2 * fRec33[0]) + fTemp1);
+            fRec32[0]             = fVec12[((IOTA - iConst3) & 8191)];
+            fRec35[0]             = ((fSlow3 * fRec35[1]) + (fSlow4 * fRec34[1]));
+            fVec13[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec35[0]));
+            fRec34[0]             = fVec13[((IOTA - iConst5) & 8191)];
+            fRec37[0]             = ((fSlow3 * fRec37[1]) + (fSlow4 * fRec36[1]));
+            fVec14[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec37[0]));
+            fRec36[0]             = fVec14[((IOTA - iConst6) & 8191)];
+            fRec39[0]             = ((fSlow3 * fRec39[1]) + (fSlow4 * fRec38[1]));
+            fVec15[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec39[0]));
+            fRec38[0]             = fVec15[((IOTA - iConst7) & 8191)];
+            fRec41[0]             = ((fSlow3 * fRec41[1]) + (fSlow4 * fRec40[1]));
+            fVec16[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec41[0]));
+            fRec40[0]             = fVec16[((IOTA - iConst8) & 8191)];
+            fRec43[0]             = ((fSlow3 * fRec43[1]) + (fSlow4 * fRec42[1]));
+            fVec17[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec43[0]));
+            fRec42[0]             = fVec17[((IOTA - iConst9) & 8191)];
+            fRec45[0]             = ((fSlow3 * fRec45[1]) + (fSlow4 * fRec44[1]));
+            fVec18[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec45[0]));
+            fRec44[0]             = fVec18[((IOTA - iConst10) & 8191)];
+            fRec47[0]             = ((fSlow3 * fRec47[1]) + (fSlow4 * fRec46[1]));
+            fVec19[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec47[0]));
+            fRec46[0]             = fVec19[((IOTA - iConst11) & 8191)];
+            float fTemp6 =
+                ((((((((fRec32[0] + fRec34[0]) + fRec36[0]) + fRec38[0]) + fRec40[0])
+                    + fRec42[0])
+                   + fRec44[0])
+                  + fRec46[0])
+                 + (0.5f * fRec30[1]));
+            fVec20[(IOTA & 2047)] = fTemp6;
+            fRec30[0]             = fVec20[((IOTA - iConst16) & 2047)];
+            float fRec31          = (0.0f - (0.5f * fTemp6));
+            float fTemp7          = (fRec30[1] + (fRec31 + (0.5f * fRec28[1])));
+            fVec21[(IOTA & 2047)] = fTemp7;
+            fRec28[0]             = fVec21[((IOTA - iConst17) & 2047)];
+            float fRec29          = (0.0f - (0.5f * fTemp7));
+            float fTemp8          = (fRec28[1] + (fRec29 + (0.5f * fRec26[1])));
+            fVec22[(IOTA & 2047)] = fTemp8;
+            fRec26[0]             = fVec22[((IOTA - iConst18) & 2047)];
+            float fRec27          = (0.0f - (0.5f * fTemp8));
+            float fTemp9          = (fRec26[1] + (fRec27 + (0.5f * fRec24[1])));
+            fVec23[(IOTA & 1023)] = fTemp9;
+            fRec24[0]             = fVec23[((IOTA - iConst19) & 1023)];
+            float fRec25          = (0.0f - (0.5f * fTemp9));
+            output0[i]            = FAUSTFLOAT(
+                (fRec0[1] + ((fRec24[1] + (fRec25 + fRec1)) + (fSlow19 * fTemp0))));
+            fRec9[1]  = fRec9[0];
+            IOTA      = (IOTA + 1);
+            fRec8[1]  = fRec8[0];
+            fRec11[1] = fRec11[0];
+            fRec10[1] = fRec10[0];
+            fRec13[1] = fRec13[0];
+            fRec12[1] = fRec12[0];
+            fRec15[1] = fRec15[0];
+            fRec14[1] = fRec14[0];
+            fRec17[1] = fRec17[0];
+            fRec16[1] = fRec16[0];
+            fRec19[1] = fRec19[0];
+            fRec18[1] = fRec18[0];
+            fRec21[1] = fRec21[0];
+            fRec20[1] = fRec20[0];
+            fRec23[1] = fRec23[0];
+            fRec22[1] = fRec22[0];
+            fRec6[1]  = fRec6[0];
+            fRec4[1]  = fRec4[0];
+            fRec2[1]  = fRec2[0];
+            fRec0[1]  = fRec0[0];
+            fRec33[1] = fRec33[0];
+            fRec32[1] = fRec32[0];
+            fRec35[1] = fRec35[0];
+            fRec34[1] = fRec34[0];
+            fRec37[1] = fRec37[0];
+            fRec36[1] = fRec36[0];
+            fRec39[1] = fRec39[0];
+            fRec38[1] = fRec38[0];
+            fRec41[1] = fRec41[0];
+            fRec40[1] = fRec40[0];
+            fRec43[1] = fRec43[0];
+            fRec42[1] = fRec42[0];
+            fRec45[1] = fRec45[0];
+            fRec44[1] = fRec44[0];
+            fRec47[1] = fRec47[0];
+            fRec46[1] = fRec46[0];
+            fRec30[1] = fRec30[0];
+            fRec28[1] = fRec28[0];
+            fRec26[1] = fRec26[0];
+            fRec24[1] = fRec24[0];
+        }
+    }
 };
 
 #endif
diff --git a/src/gui/Jacktrip.ai b/src/gui/Jacktrip.ai
new file mode 100644 (file)
index 0000000..fc14ad6
--- /dev/null
@@ -0,0 +1,1014 @@
+%PDF-1.6\r%âãÏÓ\r
+1 0 obj\r<</Metadata 2 0 R/OCProperties<</D<</ON[21 0 R]/Order 22 0 R/RBGroups[]>>/OCGs[21 0 R]>>/Pages 3 0 R/Type/Catalog>>\rendobj\r2 0 obj\r<</Length 38021/Subtype/XML/Type/Metadata>>stream\r
+<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
+<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 6.0-c002 79.164460, 2020/05/12-16:04:17        ">
+   <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+      <rdf:Description rdf:about=""
+            xmlns:dc="http://purl.org/dc/elements/1.1/"
+            xmlns:xmp="http://ns.adobe.com/xap/1.0/"
+            xmlns:xmpGImg="http://ns.adobe.com/xap/1.0/g/img/"
+            xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
+            xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#"
+            xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#"
+            xmlns:illustrator="http://ns.adobe.com/illustrator/1.0/"
+            xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/"
+            xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#"
+            xmlns:xmpG="http://ns.adobe.com/xap/1.0/g/"
+            xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
+         <dc:format>application/pdf</dc:format>
+         <dc:title>
+            <rdf:Alt>
+               <rdf:li xml:lang="x-default">Jacktrip</rdf:li>
+            </rdf:Alt>
+         </dc:title>
+         <xmp:CreatorTool>Adobe Illustrator 24.2 (Macintosh)</xmp:CreatorTool>
+         <xmp:CreateDate>2020-07-25T23:44:56+10:00</xmp:CreateDate>
+         <xmp:ModifyDate>2020-07-25T23:44:56+10:00</xmp:ModifyDate>
+         <xmp:MetadataDate>2020-07-25T23:44:56+10:00</xmp:MetadataDate>
+         <xmp:Thumbnails>
+            <rdf:Alt>
+               <rdf:li rdf:parseType="Resource">
+                  <xmpGImg:width>136</xmpGImg:width>
+                  <xmpGImg:height>256</xmpGImg:height>
+                  <xmpGImg:format>JPEG</xmpGImg:format>
+                  <xmpGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAACIAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXylrx8yfnZ+ZPmLSbnVrjS/Inli4Nl9Rtm4PPIrPHzYGqsztEzcnB4rQAbk4&#xA;qgNU03X/AMgdX0nzB5d1e7v/ACdd3S2uraNdsGHxAvUBAiciisVcICpFDUNTFX12rKyhlIZWFVYb&#xA;gg9xireKuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV8q+Svrmkf8AOR3nfQ/Lrrd+XbiZ7vVnf/dM&#xA;x/eFYyD9pLid4qdwP8nFUP8A85Atf6j518meXNYK2nkm/vYGnvVBLGYy+lKHNfh9OKT4f9Ynemyr&#xA;6yAAFBsB0GKuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KviGy8h+Q/Nn5p/mV/izWH0n6lrl19S&#xA;4XNvbep6t5depX6wknLj6a/Z6V3xVLPzK/Lf8t/K0GjXflbXH1W7uNQjhuIXurW4CxEFi3GCNGG4&#xA;AqdsVfeOKuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KvhyD8n/+Vi/mn+ZH+5b9F/ovXLr/AI9/&#xA;rHqfWLy5/wCLYePH0fetcVSv8x/yLHkC30jUTrZ1IXl/Ha+kLb6sVqC/IOJpf5fDFX3virsVdirs&#xA;VdirsVdirsVdirsVdirsVdirsVdir4Pu/wApda/MH80/zE/Rl5bWn6M1y89b6z6nxfWLy448eCv0&#xA;9I1riqUedvyS1/yGmlahqOoWtxHeXsdsgtfU5qxq/L94ij9nFX6D4q7FXYq7FXYq7FXYq7FXYq7F&#xA;XYq7FXYq7FXYq+Y/yY/8mn+b/wD23G/6jL7FVH/nJ7/jgeW/+2zF/wAm3xV9RYq7FXYq7FXYq7FX&#xA;Yq7FXYq7FXYq7FXYq7FXYq+Y/wAmP/Jp/m//ANtxv+oy+xVR/wCcnv8AjgeW/wDtsxf8m3xV9RYq&#xA;7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXxR/zkn5l85Qfndf6TpGtX1nFKtjHBbQXU0MQeWCMfZR&#xA;goqzb7YQLNIJp59H5G/MWO4nuY7tkuLpzJdTLdMHlckktIwNWNWJqfHL/wArNh4oW3PkT8w7oILq&#xA;5M4jbmglumcKw/aHImhx/KzXxQyr8ofMnnyH86vLujatr2oXCi+RLm3kvJ5YmBQtRlZyrDfKZRMT&#xA;RZg2+8Mil2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV8Pf8AORP/AK0k3/GXS/8Ak3Fk8X1D3sZciyPN&#xA;u4jsVYV5B/8AWldF/wC2jF/yZzV5/rLlY/pfeeUs3Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXw9/zk&#xA;T/60k3/GXS/+TcWTxfUPexlyLI827iOxVhXkH/1pXRf+2jF/yZzV5/rLlY/pfeeUs3Yq7FXYq7FX&#xA;Yq7FXYq7FXYq7FXYq7FXw9/zkT/60k3/ABl0v/k3Fk8X1D3sZciyPNu4jsVYV5B/9aV0X/toxf8A&#xA;JnNXn+suVj+l955SzdirsVdirsVdirsVdirsVdirsVdirsVfD3/ORP8A60k3/GXS/wDk3Fk8X1D3&#xA;sZciyPNu4jsVYV5B/wDWldF/7aMX/JnNXn+suVj+l955SzdirsVdirsVdirsVdirsVdirsVdirsV&#xA;fD3/ADkT/wCtJN/xl0v/AJNxZPF9Q97GXIsjzbuI7FWFeQf/AFpXRf8Atoxf8mc1ef6y5WP6X3nl&#xA;LN2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV8Pf85E/+tJN/xl0v/k3Fk8X1D3sZciyPNu4jsVYV5B/9&#xA;aV0X/toxf8mc1ef6y5WP6X3nlLN2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV8Tf85WafeaH+d1tr00R&#xA;e0vYbO7t2AorG1pFJHXpyBiBPswyUTRBQRYR1hrWlX9slzaXUcsTioIYVHswO4Psc20ZgiwXEIIV&#xA;LnU9OtYWnuLqKKJBVnZ1A/XhMgOaACxf8j7e481f85C6bf2EbfVbaeS+mkoaJBbxFVZvDm3Ffm2a&#xA;nLLikS5cRQfd+QZOxV2KuxV2KuxV2KuxV2KuxV2KuxV2KsV/Mf8ALTyv+YOgNo+vwkqp52l5FRbi&#xA;3k6c4nIbr0YEEHv2xV+fn5meTU8meetX8sR3RvY9NlVEuWT0y6vGsgqoLUID064qt/LjyafOnnbS&#xA;vLAu/qP6TkaM3ZT1fTCRtITw5Jy2T+YYq+9vyq/J/wAp/lvpMlpo6NPe3NDf6nPxM8xXovwgBI1/&#xA;ZQfTU74qznFXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq/Pb/AJyR/wDJ2+af+M8P/UNFirv+cbv/&#xA;ACdvlb/jPN/1DS4q/QnFXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX57f85I/+Tt80/wDGeH/q&#xA;GixV3/ON3/k7fK3/ABnm/wCoaXFX6E4q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq/Pb/nJH/y&#xA;dvmn/jPD/wBQ0WKu/wCcbv8Aydvlb/jPN/1DS4q/QnFXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq&#xA;7FX57f8AOSP/AJO3zT/xnh/6hosVd/zjd/5O3yt/xnm/6hpcVfoTirsVdirsVdirsVdirsVdirsV&#xA;dirsVdirsVdir89v+ckf/J2+af8AjPD/ANQ0WKu/5xu/8nb5W/4zzf8AUNLir9CcVdirsVdirsVd&#xA;irsVdirsVdirsVdirsVdirsVfnt/zkj/AOTt80/8Z4f+oaLFXf8AON3/AJO3yt/xnm/6hpcVfoTi&#xA;rsVdirsVdirsVdirsVdirsVdirsVdirsVdir89v+ckf/ACdvmn/jPD/1DRYq7/nG7/ydvlb/AIzz&#xA;f9Q0uKv0JxV8q/8AQ8//AH5P/c0/7M8Vd/0PP/35P/c0/wCzPFXf9Dz/APfk/wDc0/7M8VTDy9/z&#xA;ml+l9f03ST5O9AajdQWnr/pLnw9eRY+fH6qtePKtKjFX01irsVdirsVdirsVdirsVdirsVfnt/zk&#xA;j/5O3zT/AMZ4f+oaLFXf843f+Tt8rf8AGeb/AKhpcVfoTir5U17/AJwgZLGWTQfM/q3qgmK3vbfh&#xA;G5/lMsbsU+fA4q+YdW0u/wBJ1S80vUIjBf2E0ltdwkglJYmKOtQSDRh2xVHeT/Kes+bvMlj5d0WN&#xA;ZdS1BykIduCAKpd3duyoilj7DbFX1L5O/wCcMrfR9V0rV9Q80PPd2FxDdvbW9qEjLwusgQSPIzFa&#xA;rSvEfIYq+lsVdirsVdirsVdirsVdirsVdir89f8AnI8k/nb5pqCP9Ii2P/MNF4Yq7/nHAkfnb5Wo&#xA;Cf8ASJdh/wAw0vjir9CsVdir88v+citObT/zp80wlQvqXS3IoAARcwpNXbx9Tf3xV3/OOuqxaX+d&#xA;XlW5kICyXT2m/TldwSWy/wDDSjFX6G4q7FXYq7FXYq7FXYq7FXYq7FXYq/N785dWTVvzW813yNzj&#xA;bU7iOJxuGSBzChG52KoMVZT/AM4q6c95+duiSBeUdlHd3MvsBayRqfoeRcVffGKuxV8Yf85o+WXs&#xA;fP8ApmvolLfWbERu/jcWjcXr/wA8pIsVeB6ZqF1pupWmo2jcLqymjuIH8JImDqfvGKv038r+YLLz&#xA;H5c0zXbI1tdTtormIVrQSKGKn3U7H3xVNMVdirsVdirsVdirsVdirsVY7+YnmyDyj5H1rzHKVB06&#xA;1kkgVujTkcIE/wBnKyrir80JZZJZHllYvJIxZ3Y1JYmpJPvir6X/AOcJPLLy695h8zSJ+6tLaPT4&#xA;HPQvcOJZOPuqwrX/AFsVfXWKuxV5F/zlD5Dk81/lbdzWkXqanoL/AKStVUfE0calbhB33iYtQdSo&#xA;xV8EYq+sP+cN/wA0Yntrn8vdSmpNGXvNCLnZkb4ri3WvdW/eqPd/DFX1JirsVdirsVdirsVdirsV&#xA;dir5F/5zF/NKK/1C28g6XNzg09xda06H4TcFf3UFR/vtWLMPEjuuKvmXFX6G/wDOPnkJ/JX5X6Xp&#xA;9zGYtTvQdQ1NCKMs9wAQjDxjiVEPuMVej4q7FXEBgQRUHYg9CMVfn7/zkN+VEv5f+eJhaQlfLmrM&#xA;9zpEgB4ICayW1d94S1B/klTirzfS9U1DStSttT06d7W/s5FmtriM0ZJENVYfTir78/I387dI/MnQ&#xA;gsrJa+Z7JB+lNOGwPb14ASSYmP0qdj2JVenYq7FXYq7FXYq7FXYq8f8A+cgPz30/8vtHk0zS5Y7j&#xA;zhex0tbfZxaow/3omHan7Cn7R/ya4q+ELq6ubu6mu7qVp7m4dpZ5pCWd5HJZmZjuSxNScVex/wDO&#xA;MP5SyedPOiazqEPLy5oEiT3JYfDPcj4oYB47jm/+SKH7QxV92Yq7FXYq7FWLfmV+Xeh+f/KtzoGr&#xA;LxEn7yzu1AMlvcKDwlSvhWjDuKjFX57+fvIPmPyN5jn0HXoPSuIvihmWpiniJIWWJiByVqfMHY0I&#xA;xVKtF1vVtD1S31bSLuSx1G0bnb3MLcXVun3EGhB2I2OKvrn8pv8AnLvQdWjg0rz2F0nVNkXVkB+p&#xA;zHoDIBUwMe/VO9V6Yq+h7K9s761iu7KeO6tJl5Q3ELrJG6nurqSpHyxVWxV2KuxVC6nqumaVYy3+&#xA;qXcNjZQjlNc3EixRqP8AKdyAMVfNv5t/85gafbRTaT+Xg+t3ZBR9enQiGPtW3icVkYfzOOPswxV8&#xA;oajqN/qV9Pf6hcSXd7cuZLi5mYvI7tuWZmqScVZL+WX5Z+Y/zC8yRaNo0dI1o9/fOD6NtDWhdz4n&#xA;9lerH6SFX6EeR/Jeh+S/LFl5d0WL07OzWhkahklkbd5ZGAFXc7n7hsAMVT7FXYq7FXYq7FWI/mX+&#xA;V/lX8w9COla7AfUjq1jfxUFxbSH9qNjXY0+JTsfnQhV8N/mp+SHnX8ur1/0jbm80Vm42utW6kwOC&#xA;fhEnUwuf5W/2JYb4q89xVP8Ayt5985+VJzN5c1m60wsQzxwyEROR/PEaxv8A7JTir1bRv+cx/wA2&#xA;bGNY76LTdWA+1LcW7RSHbxt5IU/4TFU8f/nN3zkYyI/LunLJQUZnnYVrvsGX9eKsd1v/AJzA/N7U&#xA;UZLNrDSFNQr2ltzcD53LTivvxxV5T5k85ea/M9yLnzBq11qkq19P6zK0ipXqI0J4oPZQMVSbFXqH&#xA;5R/kB5y/MO5juUjbTPLgb9/rE6niwHVbdDQyt8vhHc9sVfcHkH8vvK/kXQY9F8vWvoQD4p53o008&#xA;lKGSZ6Dkx+4dAAMVZJirsVdirsVdirsVdiqldWtrd20lrdwpcW0ylJoJVDo6nYqysCCD4HFXhP5h&#xA;f84geRdfkkvfLU7+W79/iMCL61kx6/3JKtHX/IbiP5cVeB+aP+cWPzi0JneHTI9ZtVr+/wBNlWU0&#xA;7fuX9OY/QhxV5zqflDzZpTFNU0W/sGXqLm2mhp1/nVfA4qlSI8jhEUu7GiqoqSfAAYqneleRPO2r&#xA;sF0vy/qN8W6G3tJpB1puVUgDbqcVek+Vf+cTfzd1tke9s4NCtWoTLfyrzp7Qw+q9fZwuKvfvy+/5&#xA;xK/Lvy28V5rZfzLqUe4+tKI7RT7WwLcv+ejMPbFXt0cccUaxxqEjQBURQAqqBQAAdAMVXYq7FXYq&#xA;7FX/2Q==</xmpGImg:image>
+               </rdf:li>
+            </rdf:Alt>
+         </xmp:Thumbnails>
+         <xmpMM:OriginalDocumentID>uuid:9E3E5C9A8C81DB118734DB58FDDE4BA7</xmpMM:OriginalDocumentID>
+         <xmpMM:DocumentID>xmp.did:49477e0f-276a-4cd3-8c1b-cab8815bed51</xmpMM:DocumentID>
+         <xmpMM:InstanceID>uuid:2e5c36ab-b08f-3840-94fd-90b8522b24ab</xmpMM:InstanceID>
+         <xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass>
+         <xmpMM:DerivedFrom rdf:parseType="Resource">
+            <stRef:instanceID>uuid:dab6724e-c618-4184-9b2e-7d44879e5e5f</stRef:instanceID>
+            <stRef:documentID>xmp.did:008add62-65b7-3547-8416-6472cd533b2c</stRef:documentID>
+            <stRef:originalDocumentID>uuid:9E3E5C9A8C81DB118734DB58FDDE4BA7</stRef:originalDocumentID>
+            <stRef:renditionClass>proof:pdf</stRef:renditionClass>
+         </xmpMM:DerivedFrom>
+         <xmpMM:History>
+            <rdf:Seq>
+               <rdf:li rdf:parseType="Resource">
+                  <stEvt:action>saved</stEvt:action>
+                  <stEvt:instanceID>xmp.iid:49477e0f-276a-4cd3-8c1b-cab8815bed51</stEvt:instanceID>
+                  <stEvt:when>2020-07-25T23:40:45+10:00</stEvt:when>
+                  <stEvt:softwareAgent>Adobe Illustrator 24.2 (Macintosh)</stEvt:softwareAgent>
+                  <stEvt:changed>/</stEvt:changed>
+               </rdf:li>
+            </rdf:Seq>
+         </xmpMM:History>
+         <illustrator:StartupProfile>Basic RGB</illustrator:StartupProfile>
+         <illustrator:Type>Document</illustrator:Type>
+         <illustrator:CreatorSubTool>AIRobin</illustrator:CreatorSubTool>
+         <xmpTPg:NPages>1</xmpTPg:NPages>
+         <xmpTPg:HasVisibleTransparency>False</xmpTPg:HasVisibleTransparency>
+         <xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint>
+         <xmpTPg:MaxPageSize rdf:parseType="Resource">
+            <stDim:w>1024.000000</stDim:w>
+            <stDim:h>1024.000000</stDim:h>
+            <stDim:unit>Pixels</stDim:unit>
+         </xmpTPg:MaxPageSize>
+         <xmpTPg:PlateNames>
+            <rdf:Seq>
+               <rdf:li>Cyan</rdf:li>
+               <rdf:li>Magenta</rdf:li>
+               <rdf:li>Yellow</rdf:li>
+               <rdf:li>Black</rdf:li>
+            </rdf:Seq>
+         </xmpTPg:PlateNames>
+         <xmpTPg:SwatchGroups>
+            <rdf:Seq>
+               <rdf:li rdf:parseType="Resource">
+                  <xmpG:groupName>Default Swatch Group</xmpG:groupName>
+                  <xmpG:groupType>0</xmpG:groupType>
+                  <xmpG:Colorants>
+                     <rdf:Seq>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>White</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>255</xmpG:red>
+                           <xmpG:green>255</xmpG:green>
+                           <xmpG:blue>255</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>Black</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>0</xmpG:red>
+                           <xmpG:green>0</xmpG:green>
+                           <xmpG:blue>0</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>RGB Red</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>255</xmpG:red>
+                           <xmpG:green>0</xmpG:green>
+                           <xmpG:blue>0</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>RGB Yellow</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>255</xmpG:red>
+                           <xmpG:green>255</xmpG:green>
+                           <xmpG:blue>0</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>RGB Green</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>0</xmpG:red>
+                           <xmpG:green>255</xmpG:green>
+                           <xmpG:blue>0</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>RGB Cyan</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>0</xmpG:red>
+                           <xmpG:green>255</xmpG:green>
+                           <xmpG:blue>255</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>RGB Blue</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>0</xmpG:red>
+                           <xmpG:green>0</xmpG:green>
+                           <xmpG:blue>255</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>RGB Magenta</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>255</xmpG:red>
+                           <xmpG:green>0</xmpG:green>
+                           <xmpG:blue>255</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=193 G=39 B=45</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>193</xmpG:red>
+                           <xmpG:green>39</xmpG:green>
+                           <xmpG:blue>45</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=237 G=28 B=36</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>237</xmpG:red>
+                           <xmpG:green>28</xmpG:green>
+                           <xmpG:blue>36</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=241 G=90 B=36</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>241</xmpG:red>
+                           <xmpG:green>90</xmpG:green>
+                           <xmpG:blue>36</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=247 G=147 B=30</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>247</xmpG:red>
+                           <xmpG:green>147</xmpG:green>
+                           <xmpG:blue>30</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=251 G=176 B=59</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>251</xmpG:red>
+                           <xmpG:green>176</xmpG:green>
+                           <xmpG:blue>59</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=252 G=238 B=33</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>252</xmpG:red>
+                           <xmpG:green>238</xmpG:green>
+                           <xmpG:blue>33</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=217 G=224 B=33</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>217</xmpG:red>
+                           <xmpG:green>224</xmpG:green>
+                           <xmpG:blue>33</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=140 G=198 B=63</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>140</xmpG:red>
+                           <xmpG:green>198</xmpG:green>
+                           <xmpG:blue>63</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=57 G=181 B=74</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>57</xmpG:red>
+                           <xmpG:green>181</xmpG:green>
+                           <xmpG:blue>74</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=0 G=146 B=69</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>0</xmpG:red>
+                           <xmpG:green>146</xmpG:green>
+                           <xmpG:blue>69</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=0 G=104 B=55</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>0</xmpG:red>
+                           <xmpG:green>104</xmpG:green>
+                           <xmpG:blue>55</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=34 G=181 B=115</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>34</xmpG:red>
+                           <xmpG:green>181</xmpG:green>
+                           <xmpG:blue>115</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=0 G=169 B=157</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>0</xmpG:red>
+                           <xmpG:green>169</xmpG:green>
+                           <xmpG:blue>157</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=41 G=171 B=226</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>41</xmpG:red>
+                           <xmpG:green>171</xmpG:green>
+                           <xmpG:blue>226</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=0 G=113 B=188</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>0</xmpG:red>
+                           <xmpG:green>113</xmpG:green>
+                           <xmpG:blue>188</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=46 G=49 B=146</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>46</xmpG:red>
+                           <xmpG:green>49</xmpG:green>
+                           <xmpG:blue>146</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=27 G=20 B=100</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>27</xmpG:red>
+                           <xmpG:green>20</xmpG:green>
+                           <xmpG:blue>100</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=102 G=45 B=145</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>102</xmpG:red>
+                           <xmpG:green>45</xmpG:green>
+                           <xmpG:blue>145</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=147 G=39 B=143</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>147</xmpG:red>
+                           <xmpG:green>39</xmpG:green>
+                           <xmpG:blue>143</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=158 G=0 B=93</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>158</xmpG:red>
+                           <xmpG:green>0</xmpG:green>
+                           <xmpG:blue>93</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=212 G=20 B=90</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>212</xmpG:red>
+                           <xmpG:green>20</xmpG:green>
+                           <xmpG:blue>90</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=237 G=30 B=121</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>237</xmpG:red>
+                           <xmpG:green>30</xmpG:green>
+                           <xmpG:blue>121</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=199 G=178 B=153</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>199</xmpG:red>
+                           <xmpG:green>178</xmpG:green>
+                           <xmpG:blue>153</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=153 G=134 B=117</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>153</xmpG:red>
+                           <xmpG:green>134</xmpG:green>
+                           <xmpG:blue>117</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=115 G=99 B=87</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>115</xmpG:red>
+                           <xmpG:green>99</xmpG:green>
+                           <xmpG:blue>87</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=83 G=71 B=65</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>83</xmpG:red>
+                           <xmpG:green>71</xmpG:green>
+                           <xmpG:blue>65</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=198 G=156 B=109</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>198</xmpG:red>
+                           <xmpG:green>156</xmpG:green>
+                           <xmpG:blue>109</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=166 G=124 B=82</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>166</xmpG:red>
+                           <xmpG:green>124</xmpG:green>
+                           <xmpG:blue>82</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=140 G=98 B=57</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>140</xmpG:red>
+                           <xmpG:green>98</xmpG:green>
+                           <xmpG:blue>57</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=117 G=76 B=36</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>117</xmpG:red>
+                           <xmpG:green>76</xmpG:green>
+                           <xmpG:blue>36</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=96 G=56 B=19</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>96</xmpG:red>
+                           <xmpG:green>56</xmpG:green>
+                           <xmpG:blue>19</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=66 G=33 B=11</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>66</xmpG:red>
+                           <xmpG:green>33</xmpG:green>
+                           <xmpG:blue>11</xmpG:blue>
+                        </rdf:li>
+                     </rdf:Seq>
+                  </xmpG:Colorants>
+               </rdf:li>
+               <rdf:li rdf:parseType="Resource">
+                  <xmpG:groupName>Cold</xmpG:groupName>
+                  <xmpG:groupType>1</xmpG:groupType>
+                  <xmpG:Colorants>
+                     <rdf:Seq>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>C=56 M=0 Y=20 K=0</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>101</xmpG:red>
+                           <xmpG:green>200</xmpG:green>
+                           <xmpG:blue>208</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>C=51 M=43 Y=0 K=0</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>131</xmpG:red>
+                           <xmpG:green>139</xmpG:green>
+                           <xmpG:blue>197</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>C=26 M=41 Y=0 K=0</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>186</xmpG:red>
+                           <xmpG:green>155</xmpG:green>
+                           <xmpG:blue>201</xmpG:blue>
+                        </rdf:li>
+                     </rdf:Seq>
+                  </xmpG:Colorants>
+               </rdf:li>
+               <rdf:li rdf:parseType="Resource">
+                  <xmpG:groupName>Grays</xmpG:groupName>
+                  <xmpG:groupType>1</xmpG:groupType>
+                  <xmpG:Colorants>
+                     <rdf:Seq>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=0 G=0 B=0</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>0</xmpG:red>
+                           <xmpG:green>0</xmpG:green>
+                           <xmpG:blue>0</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=26 G=26 B=26</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>26</xmpG:red>
+                           <xmpG:green>26</xmpG:green>
+                           <xmpG:blue>26</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=51 G=51 B=51</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>51</xmpG:red>
+                           <xmpG:green>51</xmpG:green>
+                           <xmpG:blue>51</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=77 G=77 B=77</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>77</xmpG:red>
+                           <xmpG:green>77</xmpG:green>
+                           <xmpG:blue>77</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=102 G=102 B=102</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>102</xmpG:red>
+                           <xmpG:green>102</xmpG:green>
+                           <xmpG:blue>102</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=128 G=128 B=128</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>128</xmpG:red>
+                           <xmpG:green>128</xmpG:green>
+                           <xmpG:blue>128</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=153 G=153 B=153</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>153</xmpG:red>
+                           <xmpG:green>153</xmpG:green>
+                           <xmpG:blue>153</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=179 G=179 B=179</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>179</xmpG:red>
+                           <xmpG:green>179</xmpG:green>
+                           <xmpG:blue>179</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=204 G=204 B=204</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>204</xmpG:red>
+                           <xmpG:green>204</xmpG:green>
+                           <xmpG:blue>204</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=230 G=230 B=230</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>230</xmpG:red>
+                           <xmpG:green>230</xmpG:green>
+                           <xmpG:blue>230</xmpG:blue>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xmpG:swatchName>R=242 G=242 B=242</xmpG:swatchName>
+                           <xmpG:mode>RGB</xmpG:mode>
+                           <xmpG:type>PROCESS</xmpG:type>
+                           <xmpG:red>242</xmpG:red>
+                           <xmpG:green>242</xmpG:green>
+                           <xmpG:blue>242</xmpG:blue>
+                        </rdf:li>
+                     </rdf:Seq>
+                  </xmpG:Colorants>
+               </rdf:li>
+            </rdf:Seq>
+         </xmpTPg:SwatchGroups>
+         <pdf:Producer>Adobe PDF library 15.00</pdf:Producer>
+      </rdf:Description>
+   </rdf:RDF>
+</x:xmpmeta>
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                           
+<?xpacket end="w"?>\rendstream\rendobj\r3 0 obj\r<</Count 1/Kids[5 0 R]/Type/Pages>>\rendobj\r5 0 obj\r<</ArtBox[260.012 83.8406 713.5 947.255]/BleedBox[0.0 0.0 1024.0 1024.0]/Contents 23 0 R/CropBox[0.0 0.0 1024.0 1024.0]/LastModified(D:20200725234456+10'00')/MediaBox[0.0 0.0 1024.0 1024.0]/Parent 3 0 R/PieceInfo<</Illustrator 7 0 R>>/Resources<</ColorSpace<</CS0 24 0 R>>/ExtGState<</GS0 25 0 R>>/Properties<</MC0 21 0 R>>>>/Thumb 26 0 R/TrimBox[0.0 0.0 1024.0 1024.0]/Type/Page>>\rendobj\r23 0 obj\r<</Filter/FlateDecode/Length 572>>stream\r
+H\89ÌTË\8eÛ0\f¼ë+ø\ 3a(R¢¨kÒ¢§m\11äÐ\ f\bú8l\17ØæÐßïÈv¼NÚÞ\8b\0\8aI\9bÃÇ\8c¸ÿt¤ýÓQèðîHi\7f<\v]®$\1cÚîNº^^Òþ\ 3^\7f»&\8fÌÖ3E\ 4w    ÚYfU£ÜY\8aÑÏ/éë\fu<\93L?:\1f?¦¢ô\8bÒ+åÉ\95ɽ\92\ 6\12þHÃ1N­ÊjJÏé\9c\15\9e,Zæc7\9d\0ÿL/\e\14ËÊVZ\ 3Tf¯(c\83·ë\8d\9bQCa¡@hÎ\91\95nÿ«ã2ç[AK4î\8e¼\95et¸BÎx²"LÈ\99\1e\81g<a\e\1f\8eÓ\813\8dq3\ 1u®ÔJù­:Ka\8b\8a1\f#*¦ÜgC\ 5pÑ       M\171Ø£{¼TÔµµ/©\82\93ÞÞ<ÏÉ\91lëiý\ro<ß\12]\12,AÀwðxJÙ\1fhû¿\8b\96¥ô\99\80¿ê8ËèÈéU\88 \b5\1fÂ:L¾°2ùf±->¿÷m¦\ 1źA+\90   K\85Æ×\99ì\9c\ebw\19\9a\984}¸Ó\18p¹B0\14\1d\16\7fDþ+°Vô\82\17]\94÷\8aG`Ñ ÃÌb0­A\94\98\16\9aÁæ\88I7\87vîm|ÎV\9d¬ãnÛ\bÒÚoÖ%iæ\0Èb\8f\v\ f\ 2\96ÈÅZ\81o6ôo¸âh¦+j2à©pFªq:¾\1c\8d-\eb\10£õ^jêÂ\92\15Á`<*HX;\1dj\8bV&²\a\8a>,\17\13ã\9c- 2T\93\8dV34c\83\99`\95\82Í\81yöA0·\9bñ¸\11L¡?Ülmà»·»-\93\v\vè\9aÆ    Z\1d%\8fû±<Ï`sw\86ä&È\83Õ\11¨\ f\94\rÕdcGÚI]ï\9f°\8bOé·\0\ 3\0¼%\16}\rendstream\rendobj\r26 0 obj\r<</BitsPerComponent 8/ColorSpace 27 0 R/Filter[/ASCII85Decode/FlateDecode]/Height 106/Length 325/Width 106>>stream\r
+8;Z]b5n\c'%#*ZsM8NlC%==^R8%K72"G.)t9]nQ^%[548!jiY1;/VUTKn49iTS--H
+:D61!;o5\DU2I]V:<Z%U4eYr\o[Zs%pKfJ>Un69cBV(lgd[ZmSZdHu6Bn3#,lHrg3
+#5(qW)EM(MXs_ImMkkW5OYfjN;Le:;<smU_:`h5aMf9q5OsEV^,Y=0u.&E8$qAjXI
+eLD<cGAro`F-<F,e!$\%cq]5)+^BL6PJXbBaP>'pp*td(FB$EU&31tPed@*(WDI8`
+ni_M!9C%2gd.4%pr\9@8lMBA"D:Vq.SLs+6kaQ^Wo8-bp.#N&;49bf4%(e_~>\rendstream\rendobj\r27 0 obj\r[/Indexed/DeviceRGB 255 28 0 R]\rendobj\r28 0 obj\r<</Filter[/ASCII85Decode/FlateDecode]/Length 428>>stream\r
+8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0
+b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup`
+E1r!/,*0[*9.aFIR2&b-C#s<Xl5FH@[<=!#6V)uDBXnIr.F>oRZ7Dl%MLY\.?d>Mn
+6%Q2oYfNRF$$+ON<+]RUJmC0I<jlL.oXisZ;SYU[/7#<&37rclQKqeJe#,UF7Rgb1
+VNWFKf>nDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j<etJICj7e7nPMb=O6S7UOH<
+PO7r\I.Hu&e0d&E<.')fERr/l+*W,)q^D*ai5<uuLX.7g/>$XKrcYp0n+Xl_nU*O(
+l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~>\rendstream\rendobj\r21 0 obj\r<</Intent 29 0 R/Name(Layer 1)/Type/OCG/Usage 30 0 R>>\rendobj\r29 0 obj\r[/View/Design]\rendobj\r30 0 obj\r<</CreatorInfo<</Creator(Adobe Illustrator 24.2)/Subtype/Artwork>>>>\rendobj\r25 0 obj\r<</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op false>>\rendobj\r24 0 obj\r[/ICCBased 31 0 R]\rendobj\r31 0 obj\r<</Filter/FlateDecode/Length 2574/N 3>>stream\r
+H\89\9c\96yTSw\16Ç\7f\9e\90\95°Ãc\r[\80°\ 6\905la\91\1d\ 4Q\bI\b\ 1\12BHØ\ 5AD\ 5\14ED\84ª\952ÖmtFOE\9d.®c­\ eÖ}êÒ\ 3õ0êè8´\16×\8e\9d\178G\9dNg¦Óï\1fï÷9÷wïïÝß½÷\9dó\0 '¥ªµÕ0\v\0\8dÖ ÏJ\8cÅ\16\15\14b¤    \0\ 3
\ 2\11\02y­.-;!\aà\92ÆK°ZÜ    ü\8b\9e^\a\90i½"LÊÀ0ðÿ\89-×é\r\0@\198\a(\94µr\9c;q®ª7èLö\19\9c\95&\86Q\13ëñ\ 4q¶4±j\9e½ç|æ9ÚÄ
+\8dV\81³)g\9dB£0ñi\9c\19\958#©8wÕ©\95õ8_Å٥ʨQãüÜ\14«QÊj\ 1@é&»A)/ÇÙ\ fgº>'K\82ó\ 2\0ÈtÕ;\ú\ e\e\94\r\ 6Ó¥$ÕºF½ZUnÀÜå\1e\98(4T\8c%)ë«\94\ 6\830C&¯\94é\15\98¤Z£\93i\e\ 1\98¿ó\9c8¦Úbx\91\83E¡ÁÁB\7f\1fÑ;\85ú¯\9b¿P¦ÞÎÓ\93̹\9e\vom?çW=
+\80x\16¯Íú·¶Ò-\0\8c¯\ 4Àòæ[\9bËû\00ñ¾\1d¾øÎ}ø¦y)7\18ta¾¾õõõ>j¥ÜÇTÐ7ú\9f\ e¿@ï¼ÏÇtÜ\9bò`qÊ2\99±Ê\80\99ê&¯®ª6ê±Z\9dL®Ä\84?\1dâ_\1døóyxg)Ë\94\16\8fÈçL­UáíÖ*Ô\ 6\16SkÿS\13\7feØO4?׸¸c¯\ 1¯Ø\a°.ò\0ò·\v\0åÒ\0\rß\81Þô-\95\92\a2ð5ßáÞüÜÏ     ú÷Sá>Ó£V­\9a\8b\93då`r£¾n~ÏôY\ 2\ 2 \ 2\ 1+`\ f\9c\81;\10\ 2\7f\10\ 2ÂA4\88\aÉ \1dä\80\ 2°\14ÈA9Ð\0\a\1dt\81\1e°\1el\ 2Ã`;\18\ 3»Á~p\10\8c\83\8fÁ  ðGp\1e|   ®\81[`\12L\83\87`\ 6<\ 5¯ \b"A\f\88\vYA\ e\90\ 5ùCb(\12\8a\87R¡,¨\0*\81T\90\162B-Ð
\aê\87\86¡\1dÐnè÷ÐQè\ 4t\ eº\ 4}\ 5MA\ f ï \970\ 2Óa\1el\a»Á¾°\18\8e\81\1cx ¬\82kà&¸\13^\a\ fÁ£ð>ø0|\ 2>\ f_\83\87ð,\ 2\10\1aÂG\1c\11!"F$H:R\88\94!z¤\15éF\ 6\91Qd?r\f9\8b\A&\91\v\94\88rQ\f\15¢áh\12\9a\8bÊÑ\1a´\15íE\87Ñ]èaô4z\ 5\9dBgÐ×\ 4\ 6Á\96àE\b#H     \8b\b*B=¡\8b0HØIø\88p\86p\8d0MxJ$\12ùD\ 11\84\98D, V\10\9b\89½Ä­Ä\ 3ÄãÄKÄ»ÄY\12\89dEò"E\90ÒI2\92\81ÔEÚBÚGú\8ct\994MzN¦\91\1dÈþä\ 4r!YKî \ f\92÷\90?%_&ß#¿¢°(®\940J:EAi¤ôQÆ(Ç(\17\94WT6U@\8d æP+¨íÔ!ê~ê\19êmê\13\1a\8dæD\v¥eÒÔ´å´!Úïh\9fÓ¦h/è\1cº']B/¢\eéëè\1fÒ\8fÓ¿¢?a0\18n\8chF!ÃÀXÇØÍ8Åø\9añÜ\8ckæc&5S\98µ\99\8d\98\1d6»lö\98Iaº2c\98K\99MÌAæ!æEæ#\16\85åÆ\92°d¬VÖ\bë(ë\ 6k\96Íe\8bØél\r»\97½\87}\8e}\9fCâ¸qâ9
+N'ç\ 3Î)Î].ÂuæJ¸rî
\18÷\fw\9aGä       xR^\ 5¯\87÷[Þ\ 4\9cc\1eh\9egÞ`>bþ\89ù$\1fá»ñ¥ü*~\1fÿ ÿ:ÿ¥\85\9dE\8c\85Òb\8dÅ~\8bË\16Ï,m,£-\95\96Ý\96\a,¯Y¾´Â¬â­*­6X\8d[ݱF­=­3­ë­·Y\9f±~dó      ·\91ÛtÛ\1c´¹i\vÛzÚfÙ6Û~`{ÁvÖÎÞ.ÑNg·Åî\94Ý#{¾}´}\85ý\80ý§ö\ f\1c¸\ e\91\ ej\87\ 1\87Ï\1cþ\8a\99c1X\156\84\9dÆf\1cm\1d\93\1c\8d\8e;\1c'\1c_9     \9cr\9d:\9c\ e8Ýq¦:\8b\9dË\9c\a\9cO:ϸ8¸¤¹´¸ìu¹éJq\15»\96»nv=ëúÌMà\96ï¶ÊmÜí¾ÀR \154      ö
+n»3Ü£ÜkÜGݯz\10\1e\95\1e[=¾ô\84=\83<Ë=G</zÁ^Á^j¯­^\97¼     Þ¡ÞZïQï\eBº0FX'Ü+\9còáû¤útø\8cû<öuñ-ôÝà{Ö÷µ_\90_\95ß\98ß-\11G\94\10\1d\13}çïé/÷\1fñ¿\1aÀ\bH\bh\v8\12ðm W 2p[à\9f\83¸AiA«\82N\ 6ý#8$X\1f¼?øA\88KHIÈ{!7Ä<q\86¸Wüy(!46´-ôãÐ\17aÁa\86°\83a\7f\ f\17\86W\86ï   ¿¿@°@¹`lÁÝ\b§\b\8e\88ÉH,²$òýÈÉ(Ç(YÔhÔ7ÑÎÑ\8aè\9dÑ÷b<b*böÅ<\8eõ\8bÕÇ~\14ûL\12&Y&9\1e\87Ä%ÆuÇMÄsâsã\87ã¿NpJP%ìM\98I\fJlN<\9eDHJIÚ\90tCj'\95KwKg\92C\92\97%\9fN¡§d§\f§|\93ê\99ªO=\96\ 6§%§mL»½Ðu¡váx:H\97¦oL¿\93!È¨ÉøC&13#s$ó/Y¢¬\96¬³ÙÜìâì=ÙOsbsúrnåºç\1asOæ1ó\8aòvç=Ë\8fËïÏ\9f\ä»hÙ¢ó\ 5Ö\ 5ê\82#\85¤Â¼Â\9d\85³\8bã\17oZ<]\14TÔUt}\89`IÃ\92sK­\97V-ý¤\98Y,+>TB(É/ÙSò\83,]6*\9b-\95\96¾W:#\97È7Ë\1f\15\ 3\8a\aÊ\be¿ò^YDY\7fÙ}U\84j£êAyTù`ù#µD=¬þ¶"©b{ųÊôÊ\ f+\7f¬Ê¯: !kJ4Gµ\1cm¥ötµ}uCõ%\9d\97®K7Y\13V³©fF\9f¢ßY\vÕ.©=bàá?S\17\8cîÆ\95Æ©ºÈº\91ºçõyõ\87\1aØ\rÚ\86\v\8d\9e\8dk\1aï5%4ý¦\19m\967\9flqlio\99Z\16³lG+ÔZÚz²Í¹­³mzyâò]íÔöÊö?uøuôw|¿"\7fűN»Îå\9dwW&®ÜÛe֥ﺱ*|ÕöÕèjõê\895\ 1k¶¬yÝ­èþ¢Ç¯g°ç\87^yï\17kEk\87Öþ¸®lÝD_pß¶õÄõÚõ×7DmØÕÏîoê¿»1mãá\ 1l {àûMÅ\9bÎ\r\ 6\ enßLÝlÜ<9\94úO\0¤\ 1\98¸\99$\99\90\99ü\9ah\9aÕ\9bB\9b¯\9c\1c\9c\89\9c÷\9dd\9dÒ\9e@\9e®\9f\1d\9f\8b\9fú i Ø¡G¡¶¢&¢\96£\ 6£v£æ¤V¤Ç¥8¥©¦\1a¦\8b¦ý§n§à¨R¨Ä©7©©ª\1cª\8f«\ 2«u«é¬\¬Ð­D­¸®-®¡¯\16¯\8b°\0°u°ê±`±Ö²K²Â³8³®´%´\9cµ\13µ\8a\ 1¶y¶ð·h·à¸Y¸Ñ¹J¹Âº;ºµ».»§¼!¼\9b½\15½\8f¾
\84¾ÿ¿z¿õÀpÀìÁgÁãÂ_ÂÛÃXÃÔÄQÄÎÅKÅÈÆFÆÃÇAÇ¿È=ȼÉ:ɹÊ8Ê·Ë6˶Ì5̵Í5͵Î6ζÏ7ϸÐ9кÑ<ѾÒ?ÒÁÓDÓÆÔIÔËÕNÕÑÖUÖØ×\×àØdØèÙlÙñÚvÚûÛ\80Ü\ 5Ü\8aÝ\10Ý\96Þ\1cÞ¢ß)߯à6à½áDáÌâSâÛãcãëäsäüå\84æ\ræ\96ç\1fç©è2è¼éFéÐê[êåëpëûì\86í\11í\9cî(î´ï@ïÌðXðåñrñÿò\8có\19ó§ô4ôÂõPõÞömöû÷\8aø\19ø¨ù8ùÇúWúçûwü\aü\98ý)ýºþKþÜÿmÿÿ\ 2\f\0÷\84óû\rendstream\rendobj\r7 0 obj\r<</LastModified(D:20200725234456+10'00')/Private 16 0 R>>\rendobj\r16 0 obj\r<</AIMetaData 17 0 R/AIPrivateData1 18 0 R/AIPrivateData2 19 0 R/ContainerVersion 12/CreatorVersion 24/NumBlock 2/RoundtripStreamType 2/RoundtripVersion 24>>\rendobj\r17 0 obj\r<</Length 1128>>stream\r
+%!PS-Adobe-3.0 \r%%Creator: Adobe Illustrator(R) 24.0\r%%AI8_CreatorVersion: 24.2.1\r%%For: (Aaron Wyatt) ()\r%%Title: (Jacktrip.ai)\r%%CreationDate: 25/7/20 23:44\r%%Canvassize: 16383\r%%BoundingBox: 260 -941 714 -76\r%%HiResBoundingBox: 260.012435076958 -940.159420289856 713.5 -76.7445203867428\r%%DocumentProcessColors: Cyan Magenta Yellow Black\r%AI5_FileFormat 14.0\r%AI12_BuildNumber: 496\r%AI3_ColorUsage: Color\r%AI7_ImageSettings: 0\r%%RGBProcessColor: 0 0 0 ([Registration])\r%AI3_Cropmarks: 0 -1024 1024 0\r%AI3_TemplateBox: 512.5 -512.5 512.5 -512.5\r%AI3_TileBox: 232.5 -892 791.5 -109\r%AI3_DocumentPreview: None\r%AI5_ArtSize: 14400 14400\r%AI5_RulerUnits: 6\r%AI24_LargeCanvasScale: 1\r%AI9_ColorModel: 1\r%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0\r%AI5_TargetResolution: 800\r%AI5_NumLayers: 1\r%AI9_OpenToView: -379.499237432242 87.568545097045 0.654974427262942 1428 807 18 0 0 6 43 0 0 0 1 1 0 1 1 0 1\r%AI5_OpenViewLayers: 7\r%%PageOrigin:112 -812\r%AI7_GridSettings: 72 8 72 8 1 0 0.800000011920929 0.800000011920929 0.800000011920929 0.899999976158142 0.899999976158142 0.899999976158142\r%AI9_Flatten: 1\r%AI12_CMSettings: 00.MS\r%%EndComments\r\rendstream\rendobj\r18 0 obj\r<</Length 65536>>stream\r
+%AI24_ZStandard_Data(µ/ý\0XÌM\ 5\8eUÆÒ\f'ÐØ°b\ 3\14\13«|<\8b­l\9b¶©k"â\8aM\8aìM;Ë\f\86\rÎ\8cR\ f¸àª\1e\r\10Ñ\vÍ\vRD\1a3\82î-u\92Ï("\1a\13UO\17s¯3\A!U\86zâY¼\9eNs|É~b\99Ï\9c\84åpEejN/ë\86u£*8"\952â+Æj%u+òÃ#\8egY¯!\8d!\8aãePE+6ëuS£dRD\1e\919}:Ã\14CßG7\91\19\9e\19Ga#åÑ+g\83\8aVÃ:¥lÓÑ\89Âá\9a³\8f\94Ã7É\91\8e.%óÎKÓ`ÅuÊG¿ÖÃU6\ fVØÜøèfi¸aè\ 2\b        !¸\0\aDMôýQ\9dX\99\9cµjØDõ|Ç1\8d\9a(\92äúô<Ä\14vSCrªì»hXïÝÅÆKtÆlÝD7w\1eT\82R6cJ\fysF\1dsÓ:s\Óºå>nÈÒ\14]x&Å\92\84½ÐÌø\rIµuâgÜ\14%V}\88u!w\94(N¦]¤\8cÈÌ£&îN\8dÆM\9cèbô«¹ñ\9eÌMô\92ã(cç\ 6\9d¸E¬¬¦?ÎÄðþ\12£°[\8d\96°×w¾ýGYÌÈ\8dH»*þªWgô\9eÙ¨º\8d² mÎÈ,SrFV,Û)Ã,X33zÝðÆj\10\89+\8e+\8a\92>¬Ä\95x\8a\8d\9a\94\8c\9a\18úÔ\1es\14µ\8c2qr\12Ò§ccNAι~þLeÔå]Ý\9dÝpL  ßØÍ/ù\83äJß|Ú\84EÞ*Å#\9e\85s+¯æ\13\8f)afuæ\93jFI\85I;hâuñüá9H*Zw\98       #9Oé´7nÂJnB?ß\86Oa²\8e\9b8_æ>\8f\8a.\8e2a\92¾\88£hXó\85èã¬Djþ\91ÈÔ\8bæß\95ãRçú~ã%|ZÍ]d\88\89âO̯ÙãÂá\10\13C^ÌãRA¿\1a\8cS3\91\94ë|¿:FZ%\14¡[ï\86\9d\82$6|\82\96qRa#3Î\84GÆÈgõ\86Ù\1f\95Oì»ò\9d~C66G3ùtß aMi\93_b\1fÄ\8a:OKhò\8d\97\9bz\  êÉÈ\87Æ\95`\8d\rù½é(V\94|\ 6\9d¨\97\89}¡Í`+\8aj£~æ\92R\14iH'zòá\v;;\91N?\r\9e¢ÆÜ±\98Ы\86\83NºêhD\94«jm\1d\96\85Å8\9d:\92GäÞG]\18\89YÍ.Rß·c\87HÍa\17C³ïwÈ!RQ÷\8d_èU\99áÛøE¥ìÒYw\9c¯¤ä\86>G7z\14¿\14EìæêJ¯\18\8d"ÏæCäÒ\85¤ãÎääCS"׫!\95¨N\86¨ô9\1e½dTºe\8cT¿l\9cH\95HgDzhj­\96o\86\9d\7f¬J·Ï\f;\8aû\87\85bL\92¡\17ù\ 6\1d\85í¡íu7£"4Ýl5xv£oP(ªè%ú±~!rì6õ\15\89\89>U\1ae\14coÅ5[\15ý*4h¥O\194G\ 6\15ÅXõ¬$+Ý»£×\94\8d²ÆìLK/£¢Ón\17\19$\85ËcEíÜi¯åD\97+\ f\11ˬHÌ\9es\95ìéN&6tv<\91JNj§#Ý\88ø\1a,
+\96\19k7\ f\87\90Â*¥£×Îᢨ¯T»\94m\9cPôS9º´8ªÆFÆ>\1c\e%\14e\96\eÝfjTQ\94ülìGdc\84V\14µ\9fl¿2\r\11\8a\12ûèUÒp\15\8d_ÌLU\8d{\11\85ÑÇ/H¼a]h7JwÒö\96M-\13\89Y±N\8aµfb\9b\9cý¬5Ve\91\8bívѨPÜQ\19g\90x,K\99¶[=£b¬\13ÕÜtØÅ¹\83ô\11\1a©ËÐGÑÝ£\17\14b\1d½í\8d)
\9d\8cÔiä0¢ Ý1'\86çÖÉH\9döFª\9fÍÑ\86x\17+\1a\89üª\91×Ì\98\13¾;¶B¥º\9f\1a6w\961'N&¥:QmØPL\11ÇMÔÝÈÔ-\9cQ¦ð\85\83'j´\9e^m\a\8b\17@H`\10V5êD9®Ñ¯Ôñ¢øéq&h4:IQЮ\83L¼\Ôºí8μ\0\aÄÔ\84zT\16â \13UDR\1c4\14ä\92A&æHE2h\86üa\13îI#\83\86\17@HÀ@\ 3\8e\13\9aLÊ,'wâéçªkç¹\1dëÞ\e"\81\ 6A\eÀ\ 5\10\12\10p\ 1\84\ 4\ 2\ 2\11l\90A  >\80ÁÂ\ 5\174@!\0B\ 3\ e8X0\80à\ 5\10\12\ e XÐ\ 1\ 6\ep\90Á\a\1fÈ á\83\ e\14\fp\ 1\84\84\r\1e .\80\90`\ 2q\ 1\84\ 4
+h\0\ 4B:À\ 1\ 1\ 1!\14*\10\14$\10"\1cÀ\ 2\rx  |\ 1\84\ 4\14\\0!!\82\82
+4  ä\ 2\b w\96²_^ÇYAý\88|\10QÐ*S;}j\(\88EÃ,\12\ 4\10!\ 5\19\0â\0¬!Éiä\17ý¨®ºÅj\88\8bhõyª2k·%Ü8ÐA\1c\1e\1a\1c\1a\1a\1a\18\1a\16\1a\14\1aÞp\rÕ@\r       n\98\ 66H\83\ 3C\ 3\ 3\ 3Ã\ 2\83\ 2Ã\19\8c¡\18ÌP\ 6apXhXXXø\82-ÐÂ,páA¡AaAá
+¥`\85*\88\82Ã\19Ê\84S¸">\9c\r
+\r      
+¿zph`XHXPø\15yaa\81\v       \ 2 @\84\ f2\18A\ 6ÈúÆû:ÙLJ\92\9a\eM8DØQ\95\9fk]L\ 5ü5D\98Ë8|#×z\89Ô£\92\98Ó×-Ë]\8a\86tÍæ"ä\f\11c*±\1a\13Y^\r\ f\7fH\90\82Ã\83,$\9c\9cN\ 5.\90\81\r\ 3¥téú*t¡\fm¨C\1f*óà\ 4\85Ûl&\93mqh\98\85Yx9\\90\85\ 4\a\86;\8aÐ\897N¾ák\7f\97Í\9a\f\11C¯!\17gn¥*W\9d]ìåÁá¡á\81áaáAáá\ f÷`\ fõ@\ f~\98\87>ÈÃ\83\83\83C\83\ 3\83Ã\82\83\82Ã\1dÎÁ\1cÊ\81\1c\14D¡á\81ô\820\88\83<\88\90,\87C³h<VUm\86\b\eR\9d\91w\8e4¡Ô¥%#\91ÛkH8\85\85\87\ 4k\18\992ás     \r\r\ 2 ê\10qê¥$\13¢9\1a"ZtGcW\15\86\bÚÕÝ\98ÜÓ©!bJfìZÎø556      7\1f\85\ 61]\8fù|\ 67\90¨È\14\1a\12¤luu\86j(\87JPH¨30$4ÈÔ\1f\14\1e\16\1e\18\1e\1a\1e\1cä\ eÇp       ?;ºa°\9b\19=TC-PM±\1e¨\81¦Á\fVð¹L\ e\93ÐðP\87«Õ\81\r      m`0\12\87'ÌÂT\eLzð\ 3y\9cP3\81\81\f\82$<0|\81á\16îî\12ìªÁ\18nÇP\v¥\90@\ fä°0äà\86:Aa>7f:$,ü*A\16\1e\14\1e\14\1c\14\1c\14\1a\18\16\14\8a\14<lxBÃ\19¾p\ 5>\9cÃ)Ü\9dQ\13\1a\8c¡\84á,å@\r´@
+ttT    m i\18\86Y\98[æa!\81\95\ 6\1c\aa\90\ 5Q0\9b\1f"~ºl­m\88\82$\8féñBÇ\9e\8e\8a\1a\19\1c\1a¤\81n k8\83L)$$ A(\15aèB\15Ìt \ 3\17¨À£I:HB\ 2\12\ 4 \14"\10 \88`\ 2\f6Øà\ 2%DãB®³±\1cIFD|þ\\86B?«!B\12<X ;\88F\86\b¢\96ù¶éb"\14\19½:×Ii\9ax\88¨:O*þ\87.W¤QG5\e"\84Чù±âq\88\98;\93MK"*{ãñßC\84\rÇgR§Ü6D\\87V£¹r%C\ 4\85\15©jÆÛÅ\1a"®Ää\86\8c"d\87$p`êð\863\1cݼ$4üÎç\as0\akX0\ 5³²2ò\98C9\94\839\98Ã9Üá\ e
+\ e
+\ e\v\ e\v\ e\f\ e\r\ e\r\ e\ e\ e\ e\ e\ f\ e      \ f\ eò \ f|àC\1fú0\ fóà\a\ 3=ÔC=Ø\83=ÜÃýAáAa\81¡ÁáAäJ¡\16ª¡\1eJ¬æÛ\82\83ñxst        µàÓ]á
+gxÃ\1dîpQ¨Má
+\f\r
+Gc\91H\1c\96u\10\87\ 4\ 5\93¢P\ 1        B\19\19b0Ã0\94\81\fÂð°à°Ð°À°°° °ð\85\85\ 5/ÌB\17dáAÁA¡A\81AaAAAá
+§`
+¥@
+V\18\85*PA\14\1eîð\84\ 4$\90ÜoH\82\ 2\12\1c\9a\9bÏÂ0\8cÃ<\f]ÛäòYÁ\v\83\85JC¦¢£Ó\ 21\90\ 3=\10«5EUu%\95\a>840,(\9cÇ\84\ 4H\82\ 2\12\1eJ\8cV\e³%\90\95\99\9dÝ\14\18¬Á\1cìÁäx½9\1f]\9dÝÝOá\16\8eá\1aÎá\1eNÎ÷s\9f^·ßÿ\853¼á      \ e\7f¸(P¡
+£`\ 5R(\ 5S8\85+((,(0(4(8(<(È\ 2\17º0\v\85\85\82ÂÂÂ\ 2ÃBÃ\82\ 3\19Ê0\ f\v\ f\v \fd CB\19:\ff0\ 31\10C1\941\1cÃ1\9cá\f
+\f
+\f\v\f\v\f\f\r\f\r\f\ e\f\ e\f\ f\f\ f\fÒÀ\ 66´¡\rÓ0\r   n \ 6\86\ 6»\867¼A¡A¡a¡a¡\81¡\81¡¡Á¡Á¡á¡á¡A\1c\84ã0\ e\ 39\90\ 3É\ay\90\ 4\ai\90\ 6a\10\86\ 5Q\10\85ËÉ\89\89\15y\12JIH@\ 2\13\14\90Ðð\85+ü·×\13èó^þp\ eÇp\v§p?»:º¹\1eOÎÁ\1a\14ìvfFf\e£\89=\94C5ÔB)Ô˪jªÅJx \ 6\ 6R Ó\91\11\91i\88$ô`\a3xÁ
+¾Ïæ²=¦é\87q\18\86a\18\85¹±\99:4!\ 1  
+H¨\ 4\1a\ fyÜép82\1c\99\87>4Á¡\rm(C\19ºÐ\ 5\85÷zÖj\95JuÝv:mËJ¥              °\10\91 \80\ f<@A\83\0\81\ 6\1c,\0\ 4\e84,$x° \84ô`á\ 2\b \15\0\82\10¡\10ª\10B\88è`á\ 2\b      .û\90\84#ýÒô\8eÄnH\ 2ÉÖº"öÓW\95å7rUå\90\ 4I J[êÈ\18\8b\86$p \ 1\ 4\v¢BD\82\0XP\82
+\88\b(Ð`!\0â\0\1fl\10!\ 3\10`ÐÁ\ 26X\10/@\ 1\81Ã\ 5\14!\ 5\19\ 3\10l\10A\83\ 51\82
+\b\ 1D8\ 1\ 6\80\0Á\ 6(àà\ 4\80\a\19  \ 2¢\83\b Ø \83\10\8cà\ 3\f\81\ f"l\80\81\ 6\13ø`\83\f0x@\a\18l\80\81\ 6\13\b\80\10À     8РB
+6p0A\a\1c\84 BC
+2øà\ 3\11NàA\a\11&\10\0!\0\11l\90Á\a0èÀ\ 2"\0B\0\1f\ 2       < \ 1\ 1\82\b-È \ 3\ e>ø@\ 4\f\83\11\9c\0\83\ eD\90\81\ 6\1a\10¡\ 3\f4xø\80 "|à\ 1\v*\10A\83\ fdðA\a\18\ 4\1e\ 1\a\1e0\ 1\v\81\a2xÀ\b\ 1\ 6\80è\80\83\ f2\0\81\83ø \ 3\ 5\ 1\9c \ 3\f\86\ 6\1cp`\81\ f:P\b\80\10\80\10\80\ 6\1cp`\ 11\ 2\ fPÐÁ\82\18Á\a\18L`\ 3   lÐA\84\ f>À`\ 2\ 1Hà \ 4\e\ 4(à \83\ 5l\90\81\bP Á\ 4\b$\88`\83\f>Ø \83\ e\ 1\a\11¸à\ 4(ø B\ 5\81\ 6\1ct0\81\r2\10A\84\ 5\b\10\12<ø`\83\b&0\ 1\a\f ØÀ\ 1\ 2\84\84
+@`\88@\80á\82r\83\b\1f|\80\81\ 6\ f5\8fXö÷Ò\93rãD\r\ 4\19\80ò
+ J\1e`\83\fD\90A\a\12\88 \ 2\f&\0\ 1B\82© B\ 6\18ؠ   $À±¨£09q5EýV­¶ÝTC\ 4YìB¦+\1av¢nÇ6ý=nS\0\fp`\81\r"\9c@\ 2\1et\10\81\ 5\18\ 4(\88À}\80\ 2\r8ð \ 2\ 5>\88 \82\ e\01Ðàá\83\ e\14\r"\80\80\ 3\b¼\ 1
+\10\12(\ e\10A\ 3\f>P\81\b\0\83\a\8a\ 3xðA\ 6\e\83\b\1a \80\ 2"v\ 5>è@!Â\ 6\1cD@\1c@\ 5\112HA\84\v\v hð&ú\9bj\90\81\ 5
+ h\94\14á\ 3\f48\81     "Xà\82\11®°\0\ 1<(A\a\18\98à\ 4\1c\80\ elÀA\ 6\19\88 \ 2\ 58\10\0\11\aXX\0\ 5 @H\10q\0\ fD°A\ 6\1f|\10¡\ 2\11D\80\81  \1ap\815@\ 1B\828@\ 4\11`àÁ\ 5.\98\ 6(@H¨[\1c \83\b\1e0\ 1
+"\0\ 2\r2@ÁÂ\ 5e\ 3\14(>ÀÀ\ 4\1d\10A\83\f\1e\ 6(@H(Á\a0Ð`A¨\80\ 3\r4\88°\ 1\81Á\a\eD\10\ 1\ 6\10\10\e\ 2\ 6q\0\ f:à@\ 3\ e\18<ð Â\a8è`\ 2\1fl\10Á\ 4\0\a\r\10 $\mu#%ÛFY\ 1\ 4\8d¡\89¢ûUê\13\87ø\ 5\10G/\13\1a\972<\88@\81\f\18\0\ 1BBY\ 1\84i\82~\ 1\84\ 1VÀÁ\82\b\0\ 4\e \80\83\ 5\b\10\12æ¦(\ e\10¡\ 5\19\ 1\ 6\0\ 3\ 6\b\10\12ì\ 3L\85Ô\0f\0ª8@\84\ f0hØ\80\83\f\ 4\90\ 1\ 6ã\ 4\19tðA        >\80\81\ 3\ 2 \ e\10A\83\ f\0\ 4\b        \ 2\b\80\10À\a\1f\82\f\88\r\0\ 3\85\0\88\ 3tÀÁ\ 3\ 4\b     \1c\1d®8À\ 6\1cdàA\a\110pÁ5@\ 1\ 2\84\ 4\19®\10\0\ 5\ 2Ð\ 1\a\1f`ÐÁ\a\1e @\ 3\r\1a Ä\ 1:àà\ 3\f"tÀ\0\ 1B\82\901\ 5\88à\ 1\ e@ P\80
+L\0\0\10\ 26Ì3\9e\67JÆJ(¦öQ\95Ë<#öz=Ì'ç=´¹9s\19\91Èk;©¡Í'dÍ\8e6\ fk"¶ÙD¬UËf\93+{ûÜ0©ÑRñ\ 6\1c\ 1\ 6\1fp@\ 1\13 à\ 3\1fPXX\b\80\10Á\ 6\19tðA\ 5\f \ 40'\9ac
+\10\0a47=\11\12$¤É°i\99m¾öJʾ-£%lâ\8dß\12\8fVG\9d\91ÏhL$>\8d§­q5UªñMHÆ´WÓö^ã;Ú>\19\91Í\9eDQÑ­$üÖ\9d?Ìu² 9jé­û\8d\12\91v©«\96\}øÄ\83Ä\86åùþð   »Ä3I}g\92\99\92gF´Ï\96\9e±þ·t\11´ÿLgOÿEb\1f¸ªò}7*2ÊQ\15ÍrTEfrT6³»\92#*J\89Û7sYñ=¯Ht«2\91àÜ\8e\ 6\91hoäè&á(\eYF\8e\88Êñ]Ï;ú\14Yâs\9f%¨Å\12SV×\921$*V;ú\9dÇèʧ\97kL:²ík¥n\1a\ f#\8e\94¥\8a,u3¡Q4%Eìç5Ï$\1cEet$SR35£Ì\e\87Ç \16v-\r\8d9
+#ߨ\11URc\1ar4f¯s\91 ÕØ×LE5\8f¸\fQ\91QLÕè\11U$\15Õ>8f\14w\11*iè\96Êð\95K,½\16\8f\1f)\97×¹èd$Ã'\1e\ f\9fI<ôÚ\1e¾Îuhøî£\9d¡Û\Ã÷Ñ
+\93;C'\97Í+<Ýì\86\8f¾Î\87\8fâC6ª¢èQGQ*òÐ\91\86üZ%D§
\12     Ñ9XÁ\9bë-î0\11£±k\réelHOX©ø\8dYQ\84\1f
+׬£\95+\v+ìħ_FIePåLR«°LÏRA\12dä#È·\93¹\89X\8e°\9a\91}¾¢Ä¯ÇΫ--Rí×­\86´¥¶¶´?í\8eW¼h´¥­U\ro¨ã#ÈÆsì \8bù]ÄA\9c\99øVûùì³ð±&¶M<C&\9eNM<\172±§¥\1aBÂbWE\164Ñn¤$Hì¦Ê\8a\9f¡¸(5\8a\ 4\87H/!9)ÑD|\9az\88\90\8b¦ÈÜ\88)â1\92í\1dϸÀ\0\18hJ\96\11\8c\9c\95¬êÊb{Ì\8a\89ãÁÖÆÔ\15c"Í\92ÌômLÅ\19\15ívp\ 4M5ò\b³#\12\ e\8e¨»"\1a\1dÁ\12±\921ä¸\8a©Þ\94;\8c4bE¾ibI#\9bmvu\e\8c\86Ya»°læ\83*,õÜïKCÄJö"\92ÙXî>\7fÚ\fó¢uG碪ùÝ/ò\8c;i>/ISá\19Q)#é~\9d\8eh\8c0\191ó#éV\1e³1¢\8e¨ã\ 4Q\95b\1f\13òÏäRúQ\98\89\ 6q\90°ÍÆ$'"Ì+2\r\8aÞP\8a.F\93E\91F36,LÌÄè×\12ûxÑf1\19b\94AÂH>,nuVe\91Q\98\18
\84Ê¢Å+ÛÝ\r\90\8cN=\8e«\19aºäd\94µ*F/Iª)Fbs>²\ e±Úô¢²*MD\9aR\15\12©áut\84±}Ñ\10ã\\91\aÙ¹J^˱JF1Ã\1aµ(¹«è¶Ô ÉI}\1c\854ó­7\96L¯±$L7\8aê¯"¾!³A*{Ül\9cÅÑåNn:ç\1eg&>Ó«eã\8c¢¨ÎvL\1fâ\r9
+*\17ÙC\97º\ e\9f\9c¸Ä³Æ-ÈeSºéÙÓ³\8e[Ôâ)ÝqÜw¼\85U>¥»\13£\e¦\ fñ\8d\e1\95\1asv¬\11C5#É9hó\aIxnÐIjH\9asè7ï ;\12Õ*\9bäæÎ"z\9dÕ ön3c64E5!Á«\9b¢\1a\8b^+\8d\9a\10éQ#aÒrÑË\9eQ\13\eBâD.º¼fÔ(%|\e\87Þ3\91¬%çZó-7b\Î}\97k\88ܰÅ˵ù¤Cbn\88Êä\aʪþ\96\8d*Aò*\7f¨Æ§*²s­ê`\15\15ËhT\89O\1d\95I\12æ\93"\9fNf\90È8\8baKdb/\80\90`\82©±²°.\99fGÏ\99vW\9a\19\e½²\93\89\fÑê\9b1ÅD+é\99\8b\1c\8d©!Ú\87¯Q±gN®°»¢yò¼\95W¬´SÕî\92÷\eå\90\8fLÌgRÍf?\9aÓ\98ðèúZÏ&{%´Õ\b]åb\19\9b¹\ÇæR\13¾f~d\8dÐ\95\89µsÜ!5Ó*É!´\9a±/­ÝNdZTlí­Í|\8cf´*èø1Tá#ú\8c\fsO¦n^ïG]q%ÆWkìNT¶Ó\1d\13\13Õ°<f1MsJÕ¯Ælâ\e\9a\97g\83x\92\9f\9c±\88ìÿCcCd±¡ùÑÜ ªÉ\ 6QÅõf85¥
+\92ÔhÚ\9cî\8d³\8dØíj\88ÖA\17&\95Ñ|Æ:,.¾*ùb¨<-\ e_\;fd¼\91á\v¢ù1\17\1d\1aÞ\98\8bK\95ç¶k\1cUnÌËsTQ\91\9a¾æ®\18\12$·Ê°\89ãÇDGä\9f¢"þ3=\9e\r\91Ýæ÷ª*¹1÷\8f\rÑÐüFF#\1eoI\1as1Ò\9bæô¬2xâĤãÛ¼áö.\17ñ\7f\93\8d1aZ^¿ZQõÏ×F?*¿¾\9b6öÚ vLÆÔ\1aUN\*?;\1ftQÄÖxÚ\9f}×Ñ\eé\86I)O>®\19½0\87|esU\e\8d^\98ñ¬|qÕ\10Ö\8eê"\92þ²òOh½è\89­,¬¸Ü\98\bù¶«\92Y¶÷ÎC\84ã¶#27Jh~,]\90\84B\95\999Óò)©\9f\8c\8a\8d»°YÕ>x\17d\9b\8f#ã§TLy>»óW©\98±\98íb\1e·|ldØ\1a^M(î\93ºG±bxD[¥J[yb\87½Jþ"UÝK&\93q)\92\87\94ÞX\91\ eþgï¸PqZ.\7fZ\17É\86\86o\8d¸ÈG$âýw£X÷ø)̽Ö^§\95Cf³Ðl%e\e\1a\15+¥]ê\1fS:«2\13£\13]       \8bµ\15é\86ú\9aØåu\83x\1e3"&F¤ ª£3Z\89½Èè|KQ\15­Ìt¾\8dÕ\18¹Q\89}\848\8ac¤bn\9f\18ñb>ÍØ~òs\9cÒJ¯r\14\19Æ
\91rªêP\98Ýfü\93áp+c¯Á!½:w584ú\88¬\88\7f:«ºÍ<8B¼\9aA\19\9bY£eZ=\1a2\15\9c\r\19\92úÔÏx+ø2­ng\192õgÎqí¸ÄV/E­£J3v\85¯\93®£5\8do¾³¨CJAU¢zP+8\14«_u3¬\15dWDs\8eúbõÄoM\87§¢×¡ø6\9eþ&'<Ö¶hò.gHÌe\15G\11¡2\19\8aÏé\9d­®Bñ=B×ÌV63KZÅ7z\86M\8bT\11\9fB\ f\9b
+\92±]M)È|~^{\r1)|\8bY\8d\9b^çt\9b¾i68\15õ!bÉ~^v\1aâ
+²Ê^/¹\1a'\ 5Ç\8aN\83L"+K©¤ýIé\8aF\86äæV¬uäæWï wê\84\84#rs1ÍÞ<cGcåPÙÜV7²Û¼¥\1aä\9a%«O\15Ù\90Kå|ÜyÝz3X
+\9fÙX²ùT\85Ϫu\96\ eSÅý£HQó££!UÊ\98C\8a³\8d©ú\14\97\9f|Ã:\88¥è\f\8d5Ltf¼Xª\95£E\1a\16S\1e\19\aÉ·¢l"Eã\14\1c\8bÕLÆ\87ÍNÕõ\9bò \8dÂEr\18\ 5Ñ\1d·\8c4.\96\87yL\1a\1aFi\9dï\86\95êè\9aY_2\9c\1fd\8a·<¦BmMýn\95§d^Ë\97\9d\15Û`Ey\99ª¹Á\8a2eªnúøbÖª³÷\98á°
++£]wé\86\98ú©WåFo.£\16,ªr\8b\1e4Âv\1c»\83VA¯\11Õ{ë¨aU\fyÌêÕÚ°òEl~v\83#|¡Ï\ 6[\1e×È\1f÷<%c=\89]»Í¥þcÑç¸\94ñÓ\8eWѱf\9e©]X!v_+CF\1c\99t\84\86\8dèk\8e\86CFtêæêTs\90Ì \11gUG#ß*_ù\9aâ\8c«\8dYæµ3Ñ\f3\9d|\9ca\16f\87zRl\99&råG-î\F;]Ù 9Äâu©ØÍý°3²!¾\v\rZ\14\87¢î\19å9G+ìßT4ÅV\8d\9c\98\f¥ÄQ¨ìzucH¢LO\r\97gAÖËUõJGV÷pªÚa\167"¥GH7\99ÇÕèË\9d]\91ÕïlƵNVW©\96Õ[â¸R\Ñ\86Ytè\7f}ÆlÜ=Nâ<&±{¤Fñe\1a.a\9d\12\8f\96b^\ f!Q£\e\9a\1d}u»R̶k}\1cmq\1fÿu*û8\9a\98\87-*R\7f]\86\1fG\93²¿\8e\14\94q\99\88ØÉµqä\f[\94Ñ\88Ø;¬q$\vû\biæ-ì>ó¸\90ÄåæÚG\94\11«ö\11ñ8á\9dÔÅNÒ\87Ù£¡«\9b\10\r\97¢Nn:u\e\1e9ªÓ\8d\99×(\89\8f-®)¦îã$jÛS\17S\94\18~被Æ\17ªÛ\18OZ§®NhèF\8e¤ºÈɸ!\87\11\8fDró\947\19´1Ê        \17\85n(F:\83JÜZ$\8dg\86Îú\98Ô\10ª\a-LÎoý^5Ê$?i½b2\84(\8c\84ÝȱÎ\9f\83D¶Æ\91¸\9a³á\12~)23\%¬â\1a½\ 4\rõG·9\8d\96\90ò£ûW£·kÕgèÎ\8eê7®ÄÜÌÑG\8b¢tVÖ;ª]\8d+a²¹£\ fýÑ#QöÜéB¿\re\94Å©æ§\9b\9cÆ\91GLïtDÂ\19\1e\88oFòGn\13JëèF¹1#Ã#X®£ó/+IÉÕÑÝ¢1%æð\b\8eNeîÏñ\11çù¦qDA-\1aµ\98£\e©»¼Q,\8d«Ð\10[>)\13Ϥ \11«öañU¯\97/\96¯\9f\8e/\96Dözu\e\1fQñÜ£JQí\84C¥Ø\8d\r\877¥Ý¤Í\94Ø\9búu2u\14Û¤j\e\85åÇìÛD¿-b\9fÞPï1\92ð~5ÿvÇlä\95íÂWxç\9ag\8c\8e.IG£Ú      ç<×*³\12\13ÏKl.²¸Ãî\96ïh'IÒPùäÿöÿÿ_â±ù\84lU?³\9dÔÐÂ
+9d¦9Y¾\18Ç\88׺\9c¿ðÊ\92pÆÎFd:FÂûÍNÎê3\85ö߯×ëÿ}\96s\88\rÖ\91Ù\87Q\19\19\19ñ\86\86\11\r#SëU®*\eFV'\e&[\r\93\11Ñ0\91y\98L\96A4TCªê\ 6\91Ù\19éîséÃl¶\9bhÔ7d3j¬º\8d)\99"r\8d)ZlL\9dÒ\1a¯âÕ ã\rÍ0;+3Ñ2;2;{¯\1e½ÔÎfÛF\93Lèä\17]ëó¡Mh¬\7fcÙ°¿>~\99\9b\11\96h¯ÒDZ´\92}\11\8d4\1a"[ÚÍQzò\89\11Y¹£\93QŪúªªôÉ«*o"q\85\96\89\91\15\1a\e×XfF¦\r\89¦M\91iäï\84S\ fÑnn&ýùGÂ\9f,32t\8ffºÉ\9cZ»¡ólLáçäôÓÑ\89)Õù~¿:\1e©&âc\1e\ e\16\1dÍ\akP\9dÍ\89jTÞ`\rVëÊ8Zm\95\8f£U2¬jg£ªÚ\1abb41Zý2h\83fZ¬ê&³\93ë\9d\1c-Dz²³cÝÃ\8eî\ 2\b     \1f ÑG\99Ý\87«ÊtÇá:\12\19®\91\91á²×\aÕ\98µeEGýðm?v\vmLlõ#ÛÝYÅVÿTȪ\ f\9déµ\12Ê]\vm\15\8ḇ%\93\1ekãå¤^Å:ë&ÊyÊæËè®\e\9eUÕáÑÚ+*Ou¡ë5\855D!i¡XX&ò¤\84u\12s\98h^X&z¨\9dzÍ×\rm\84\86jε%³ÕZ¦\99ä+k\999c
+[gì\91jn\86#-!\9a\95±\89\88ôÊ"-!\16Ñu¢¡WÉPäÌ®ú\92Ccõét¼äÅ\86uÇÎ-uWSÒ÷o"*ó(²d-:Õ*5r\84H\16ë\91!ãGÜ^±$Ë®\14ùÅLÖ\18\15É\94\90î*V<y\ f¹È¦íz¡ÉƯ©³\11»\91rÂÚKj;\91$óù|>\9fKËõ˪6w½ÞÜÍÍ\98ãÿñ\18     -­;½N\1ft:½l3uLh#Iä\8c\87¯ÚDääGEa\8dzFÓ\91§\9c~±$ï?ÒhjbDZk±\9fõ¯\93W-é÷*««\90\8cîüm6®ü\8dÌÇê­\15uh\9fÓÌÙ©Cu3\93\9aLUÃ\1aÒP\9dÅz¨lÈ¡RÙ\90ì®áÛ2×\90?×}öqCsêB\9e\8d\88¦q\9a\v $|\80w6\86|6ÌF£\1eô\87733\9dÑaç:nª\1eâ\1a6\9câèP©Ö\93Auu\88\83:¤Ñù\94\87§&\1f3CòÑñ\87õæf\n*6DÌ\10©{þ\10Ê\9c\8c¹ñö:¤D6r£d\8c\fieH\ 1F\86HuHyÈø-§ãfPÙ\9fÞQÆÚÇ\8dC*µ\f©ÌÇ_\1e\ fé8søÃÒ\1ab65DHC\8cn\86tÈ(\8e\91\92!¬Q\17@Hø\0;\8a3ª4hfFMÕÌ\8d÷h\eïyã¥ßxë\91!#Óºê¨É\99q46hË[þ\83|ßÔa\12\9aa2\99\86©Æ\1a&\93Ô0               \11\11\11\11Yj\ 6QM;\88\86\83¨Cè,$çÒQ}\94èæ£ä\e¥Q*QK£tÒq\9bm\1cäûÝ2Ì£T\1fDDd%¢\ f¢¢êq\14u.t£::6v\15iÐ%£!6\15\rñÔ\10_Õn\88i\8fÅÉeÄâ|ØXGÃtÄwÆ\11ÑÑQ\89Æiê<\dä\1a\89íÆÚ\87ýþúÉ£®\7f\9dG\16¹M\84¦ÐnEÊ&ÿý·»\8c\95ðW-\91\8a¯r³Úo¨.dR\9bMé¸ßX\9d»\8d:^ÜÉ¿Áó<\7fº±a;»\89Ý\ 4\95ÝngBÃlìªh\10±\1e&\9a\8e¡\179tÄë\r"£w\1c\99£\88Ô\13ǹ\1dã\19cs\8cÇW\1fõ\98\9eó \9a3\eg;ã\10ÿ´\9bÍx\89$w¼Æ\8e×e\1dïk´\ f\9b\9b»Q\92"ÕùÆÇõGuØ\eÕ3Ú¨N½F\15\ 5\19Ð\80\10@\0ÄCÀÁ\ 5,8\ 1\a\f\17l\90\ 1\ 6\10è@á\ 2\10\0\83\b'\88@\81\v<h\80 \8b±YI\91L)Ë&Y\8d<KèwC.V;±ã«D\8e\16«\95<\1a«\8aU\17E\16+:±\91\7fA<ªÑ\8f76F§*­=¡½Ä<LVêµ\vÍæFh®\14\99\8c#4ÛQ\8cDB\9b¾(e+ªÕªco±\8aF!zLs¬Õlb\95dVy]\8d]é<'"«kÏtVd×\9bé®ì[IJª2ÓË$4sI\95\95õÌwD¶c\89ÌêX£Ç\13#ÚIrVé\92\ féÿÔ\99ÝYµìî\¼;\9f¤¾UU¤?wîVv­ê\99ÕmÞ§\18º\97\15}¾¡\9b\15ÍÊÞ\'dßøg.éü\r¥\1fû\9d(±ÈMqyä¦t\8aä\14Ú\11ÉMqÕÈM¬r&é­\8aÂ\9b1úiçÏxEÒYGRKº\95ÔßNwåM´n%½\9f\9fÝB\9a\9f 1\9f\9a\9aK*\11\99ôhÌvRC§\ fGÚ*3kî\ 4Í\9d\86æz¢Ì\8aæ8'èeÆaW'=IΩÖ\94n24\1cT;\9a\f\1e\r¹\8f%c¢²3++ÕqLX{\93N§8«\93\15\92Þ\9dF÷å3x\82æî\90î\9ft\15ºÿë\7fÛIê'}^Â:¬(Cª¹ )W\11çâ¡3\13t\8bOT=\95{º^õó÷Tt    ²Ì\9c¤H(§\12\9fÚ\\8ads¢ªÆR£È\1d\86 ÄÏ2ö8áIÕ.*§\18\eÕNÆMµ\93\e\ 5ejhCÞ½Þ©\19'Õäg\83Ãq\154"QM\7f¡zM\1c7\1e«ù8\85\19ûb}¥\19¶µ\8b]è:5X»Tk\17NK¡Ø\89WAU\e\1dÑúõ\8aJ\8b_ìÇ$Vd#)Þà\90ØOî\1c))VJ¬(Vä\98\88\9b\¿s\89ñ®¦\94³\90yõ²Ë¨~Ô\88×\9cb36âFBGu#4\866ä"µCûüìå\88©*­d¤\91×Ù©©\1a\8c¤Êc4½Tª~$F§\1a*\8f©|U*»,ÓÏ\8d «²Kl6Ss5\84¬F¢Ê¤:¢9R¡{«Ì¡·\8a\ 4\8dæ­2I\90\8bE\12\12ý\ 2\b        \f4ÓºoÄÝK\96ù<\95"NÝ\94f°FNÈv"3>ÂçñÄÛËxª\8f8¢ñT¾;\9enDÝL3ÂJÚh\98X=[§\19¦FP¥üÌtD\rï×\11\1e³{Ñ\10³P¬#l\84=®¢dîNç\11*!¢ÙÑ]¿}xÊÆè\89é\84højúM}È\89P>äf\94cúÝÜ\90\8d     kÈ\rOñFMFëbàïD<
+\9f&¼z\8bÂ\88¢Ú\1a\18ÖÆèÆèÊv#5\88¢´\8dnUwVS£\14)\13GgF\1dD\9c\9aY%
+\1aR\0ñ\9fQël\92!5$4\99k­ëLÄÝcS\97MR\17\89\98\9e|ê(ª$5ewlTÔØÌ\14\994HX\8dTëÌ»u¾\a)¦Êæ}\b¡ ã\90ê\8e'Q\93\9f9\9a\1aAr=¢aÑ\91°)\9eê÷\11­\99S\rÅ\9d ¸¬\8aC£ðÑ\98\90KÌq
\13\97\8cäV¿\9f\9bë£J\13Q\99\8fNÒÝjF\9c\11E\8a\ 4Y¥(q#ÍÕ[ºèL«Qã«·c\14#²á3\1aY\8a¡\1dù\88F\ f\8b\91Xµîuòâº2\8dUJdt;\13_6»\ f\15K§OOl\92M\91ZE+éV\z¥\95\15Õ:B\16=D\15\9a\11\1aËS\9c\12\9a´X\16iNMÚ­Xô\9cg;\94\8d\8dÐ\86\8e4féuFµd\9a\9dÖ\87\95\13û\rÉtnÊr\bËhÚÉ]\9fjÝÚ\8dêsZݸê\8dóêsV:íÄDsî\97ªñ\13Æù\91fF]\90\88\8bR©1\v=33Èí\8dݱ\12\1eÍP\7fQæò\ 5éÒÌP\854sþ\9d\9a\8a\15Í\8c\96Pj¦Õ¾JGsÎ\bÙ \89k\8cYÚul\171²ñÅ#U\9còØ\99¡\9aªó\90Í|f.­\1aSU\ f}Rã\8e\9e\8bï!U^øÎFó³\99aÿCN\7fN\96\8eÆÏSs²\98¦ãÚ>ó\9bÝ\r]\9a¨\93¹±ÇLNX\8bè8æ\84Ñ©c÷}î\8boNþçf\\91ÏÍøÓ\9a\eÏYgnì\8aÒ\88§N3ÕQ\13\1c¢i\88¬D\89~6n\9f:xÂF~\1a!\19Rj\86ìÄ\99)5v§¹Xï4wÂ$\9dfdz\9a!:£\9e¸!ÖÌ9\9d)+12\9e\99ºý\1e£·¶ùIéÿ¼%2õ\95d̳¬lÐ\84\8dIõ©T\822\1f°ë\84\1aÝÄ'ö\88\9c¥Njxñë¤.3¶\9e IÄ~M5ØVgÈEM(c»qønZ\1ar¢7Ñ2Xé\9d\1em\8fü\97\18\91Ñ\18\9d\8c\96(\93Ð\ZK\90C\93Ê\98\12.Kó+\9dq¹Q\13&.ËsÂg¥ÆÐ\86ö°\8b\9a±1ÿ¤vñO\8dynÆãĪ\1cóÝ¢qR» \9eÕì¢.êÙ8¢Ñ\97Iv§c\8e\17\9f\91R±waSe2ý®vï«Øº\9aô׫\9dD¬,Uö\7fV³9\96Ï*²\97«Ý:eF§2\85ÆNý\r\v\19\ 5bê<æXS¹V\1fE¯;{Mæ*ßTwÿ­ÊùòÒ\8a~5$D\8aÝýµ\92\91¿BÆúRb­\86^~YÓÓò\86ffLÒL½ÎdÖæ\16\97¶'²\ f\ e\87\1eZUæsj©'&íL¥.ùû\11·\8aRFGqM+®)¹âK+þÝ\97\9aÒP\8ad(\94³ºÚ32\9bô\8arz(71\8aM¡ó¾ÔضÊ\99³\17±Ç\1aû#\85Æ\8fÇãPN3\85Æü\84&\ eѤ\93Î#GOªÍÐÔ¤\9ebTs\8b\94}M}»ÔÎes|éxF²\91Nò­J~\94sj:\8e±ÎÎ\95\9a\9e#ºúèbGvD·áQõd\87\8e>»16dõ\12#ÉêZ=³Õµì³\9eÍÊZ\17"ÕKxRåa\8d·ÌÿÕÕÕU\8ee¿ß²sÑü\18ïÌh謵\8b&\9d\99ÝÔ«ìÈ\8fêJ\99>\8fÔfµõLxURë»\9cfV´2«²²*\9aTËL\12ñ¾\95\91\15\8c\8a­²º;\99\fÿbmX\91¤Ü\19ê\14\992&ÇÍa§Ó:SÜrl¢Ô\10EZe?UÏ/v\96\88«¦=%\16s|¶¾X'!\89Ä£7cTRo\15yT\95\1a«\92²[Õ\8e<³ÖQ¯¨×£Þ8G-Ï\15ÕÆ5W­¹º\8cñ\8a*|G+f$éê\9e®Ö*Ç6³\8b5\92ÔH;\1aK\8aë\84ÿÇúª½N²\8d\14\ e±2U$\1c^©¯³Lc\87\8b\95'Fd¯Î-    ýêì\95{GV×\e»]ý\11rTëb}-gÊ(7jê£e*Ò\1aÛúÊ\9a\99\19·Böæj¬ìÙãimNIùv\fegöT!\9bì³$û\96Ò8k\9f­Ê\9d<ìm69Kõ\9fS7ßf\1f$\95\13\87Y\9b\9d\92É\84ã³ô§»Ïç\19éRuz¨¦\f\8dê·Sù¦ÊìüÈ?\99ê\85.t¡\93X¾Üw\9e\94\85ÌjB¿ÓHkvÍ#µj'§]y£'\8bO\9f?\91ãØ\98\90æ¬+\8bé%ùà±CTÆÛr$ÎI\87\1c©Ó*T'UêlY±Vèc\16\11ï\9b©\92\f3\12íE\9b#C\91cíb#]\91\18ïªÄXVóè%Æ*ãÝ\19I¬xcNºÚX\8fTÆ£\92\8b¦\ö_t,¡\93f\96ÎÉ0©ÑH\9d\8d±¨e.óÏýYhvë-RÒ¹H\ eÉç\9d¦Ûê\85l,Iê0V\8e|zÊ<Ê\882£X¿4\19Ö\ e\8b|;\12_\89jª-³\8c\"eÓ\8dm\9fí\8djrgö\18]q\8e4zÑs­cËä\83ZÿÔ\8fn\9bß¾b+\14\93º§Î£ÌÍ\89Oº    OèrÊÐ\91EÆ£"_õ\9b%º]·ÍÌ\19Õ\b  Å\86®æJ\13j;¨8¬¢ª*\1agh\1c+z\19Å2\942¢Ñr4Å"\11âÔÛkÝwd\99¢\99¢û\11\87<ľUæu<e7\9e\9fø^Icój>{¥hÊ&õÈ\9ezM±±Ë¥:\93«\86Uù\12²ù6ròp(Vb,9ó\10«!C±\97_õ)\12\9f\8bw\9a\97>§)F\9aþÔ¨)VÛý\½}×P®wå¶sÝH²éÞ6C7=\9bD\8aÅÒ\88\ f\91Ìl\14©\1f½÷_Þ\12©+/D6e\8fÈÑ9w£\vÇU$ÓhE®\97Ù\1a©ËØ\19³lר\88î\91º\18\1fÒTµÚ\9bß­¬>V\93ÌnnªÞ³b2\9dW¬®NG\19îQ8ä\96\8b,¯idÇ\90ò²b·ý\86\91ÒÖ¥tí¶Ú\10\12\91Ö¡!\85æb\9e\12¡ÔDx\95éÐpk\9b\1a\935Ä)y4Ô9)d\r±\8c4]4gfø\8eצèhCd3Ç×áÍ<Ý\88Å\9f\1e£ßi!\8e\91Dñ0¢\94½e§\97\89Dr;\9d®½Ó\89Ç{\7ff\99\98ös\8aÌ÷\86x\862\8cxgvqæÈÅú\98\11\8b\8c\88îÒ¥xÿÄn¼X%d&\88Ä\19j\9dN×íusaQÌH³î\12Ç&«ÑØQÆ\11\1e\9dÎF×0¢ydÈdóÙÐh+Ô±Û±¿í¸%wÚ!Ö>§7¤í\95\8aevÄæ\8beJ~µ¦Än?<}NÈÚ.Ù¾ùn\9cµ9Û/©"Év$\9aB6V\8eZeëò9ó\8cêãÒªI>ä²\96ØÈЧ´^\89F\9eZgÛË7Hj¢9\9f<å)Í#åÈ\8d\91²LG$u$u\1eéMî\i[ÞU\8d9rk®Tse\11çb<ªYSº\98    \9d·:¿C\1c#½Ï\1eéGº\86æ(VSº×Ðé«M\9dµ¡9Ò¦c\8e3ÇóQJ?\92Ðýó|\8eÑ é\90\9d¥ÿµ.ß\884wB²Ðë%=\9f¤¼×ÈJÌ7lÇ:\1eó\87\1d2ºù®Vä¢\96jlÒò§þ(\87ä\96k:VW\9c\1aÇ\16iö­}Ù?v®ªÆ\97\9b\8c\93\1d\91+\8db©H¶X\8dï[hü²\9eÉLÝ\fjGÆÔÞ¦Eï\r\92lm\\85\9eé\87Înú;ºöóÈÇ\95\9c|\\8a\fºU¾"~^®\96\9f\9eLM\9d\16\9fÎ7h:BÓ\9cöôÛÚÚ\92Ƶ'\1cöF\88EFçÜçæöÂ_Íß\9f\99÷¹\90K\16úÒ\96Ç´SgÇm[ºÏïj\9fW\99ì\1fã\8c\9bÞÔ4\9d\e·VW+bgµº\9d\8e\8dÛzlWûêVýp}³3i'jÕÇxCÊaÕ¯5F\eÖûüVUë[ª\8b\15\ e\8cÃZ½\9a*}/³Ø\95]\15\95kF!oªÌxFVõ»£Á!¯7c\16ëC34ÕpN,wý(\93¨F\86\99½«!=D&K®eæpj®ñao=s\98\8fÍÆ\87s<W-W\1f»\1a\99²Mù$Òúü3\84\86$uò´£\1f½\8e~\16\1a\91h\86W±T\11\94,sDºq8^¬\9fè6öÄ.B¹««°n¢°ä0±BNÉ\89·bõX$\ f\1eiªh:£ÅÓÏX&:\19m\93\1cmÓØc\e2äIä\88~\1c:\9b+\19$ÚW)#Ö5/\12Ý\8cC¢«³\18ñÎ:Û\9dñèrCã\8cE-]Þ\19g\94±Ñ«,Q\91k\8cyUSïycÌ\11\9b©©1&\99±÷iÝÄ7Τ\b\16©\1fQl<75æËª\8b\99\f\ f]Äú\98!«fx¹\92¯ªFs×\r\8bdDæçÄWWS\ e«=«×¼,?\99»ª\9bðĨW³«:\8b3t3ÖSDz\9fÍR\93E¿ó\96Î/wt¦)×\8cênu¢\9aNÂëå\94\96\8e\1f©$µç\98\a\9dSVÆf\88\92ó\8dçÌb®°Î¦77=\r3ò.&\1e\89\8e'6úÑ\14\15\95¦ÊSÅ)úI?j¤kÑ\18¥­ÒmîF\1dmXãÇ\1d\87Xrez  iÜx\16É7\16M\8fGÒç$Ùo¤\*½GÛ)B%³#ô£\11\12¢3\9a\8c5\19\13\19tÖêÌÅû3\9d£ai/ssIy\17©ûØII«cý\ÊÌ\97;\e%=#_t3.5\9b\94SW\16vNÊ?\96\86ή\97øãÕãØ©9\1fkF6;\95±¹¡\92Q¬Û\9b\16Û"ª#\99\1a\12\1dYÚwH˳:»ÞØÒÞÍöÙ³_v3\8e-¶¼\94\88ïfH\91        Ýi\Úº\öS¾MùVÔQ\1aÎ¥\84èò=%kþÝî®w¾ÙÒЧFLÚk½\9b9ædI¯ó>³¹uì2¤³\1dÒG(Sú\19mÈyb¡Óy\97n\96\8c\19§\9f¡_3¿1&\8fÚ£ö¨iÔuM\9bâ\99nHY\rÒÝ8\9fùq®\8cû.\ eS\8d\95\14\r*±!ö;\1abFb3ªÆÙæ.\80\90Àp2'\7féÏç\9f˯·SÍ7ï\89Ç|n\11\9fð|wwòü\88S\ f:º»\91MYçÈf\90Ù\9d'6ö;\19Wb\17@HøÀÙ\8d;\9eç\aÏ\ fÞL?ÖÞ~\1c\91\8b¨ôQ"³G©DçQ¢ZÇyHP8D8¤N:dL<D\ 6¹2(v£(\88Æcz5É\8cy\906c\86Çö\98ãÔ¨Ú\15Íq2NÆÑɸq$\ef~\ 6\19q\90q\10uPÉî¨ÖU­8ªÚñðLÍøØØÐLÆÍM]fÜüãò\i\90i2î1Ä14\9f\8e¡¡¡sÈ4\1dåagÐãaUè\83EÇb\r\93\90ùÃtk\8d*«ÕlÔj5W\91\87\90Ñ?Cʵ\87\94\94PJêþñ£l÷6>#\1e3õuÌÌÌÌÌ\9c\98lÐÜFÍçÈC|SÓº\1a/o4¬%R£:ª¤\7fT«ÕjuTÇ\94Z\8eÏ\98Î8«Ö¸\13\1a\8c£uÜUI\8d²ñ\19Câº\r\9b«\8d²òd_ä/·Ü\88\9cú;\91ýª½Þ¯ZÒÜUý\88½\93¡\98ysä(f5$±\92açò«¶ÂN±úz\19Oäõ*©${;E®¢¢þäìjªîÄD!^j\98XiûË\14\9d·¸¼²\94ie/)¢ÊKHHL\8e3&D,«\JeºêåYÏê.OH+\19»Üªw(fEu\ eYå¹>¼-§\8dìª\8cÌ\8c\8a\86tV&õ\e\9a\86\1eö\9c\19\13»°ÌÇ\96è³^óèèì»\9dÔtnff\8aÌ3_rÑÍ]ÊDâ\ 5®4¨ÔÏg&Ã"Ç)¥\10Í\8c\ 4\ 1\0\0\93\11\0\08$\ e\ 6\ 3B\ 1±\80\a\14\0\bÀ\96@`\16\84\10K´¥2Î\0\0\0\0\0\0\0\0\0\0\0k\13±\8d\a{\8e%\1eäx\9dd#<$âN¬þ\1d\80>jïP\v\9e\18\83\ e\1e\93\ 5Ï w\98\16\ 2àÉèÛ\ e\1e}$í°\9a\v©A²\83\8c$\ 2vxùÅ.pò;9F«\83Ä\14Û²\ 1£:\ 5¹>\8a`$íþE0Ã\95\7fQ\1fuÐñx%)qwÛt\90\91Ò3Ýj\9f\84(\8eÔáú\9b\88í\84ÛÕ!òïÄ"Jß\89-¤·dÕN²rÄwi;1\86âwb\aã\11\ 5|'v\83t&ú\9d\90+u\88o;9\81G\0¼ðB\92©v²Å\89®I\a5Ú ¯¢C±É\ 5:¨FôÎÁÖ;ivsȤñ\84]e\ e½\90â\85'\98p9Ì$>åàÜ?J\ e\e)\ 2r°û\15Ça\94Üüà\89\9b\17\87\94x\9a8Xø\9d4ípH\10\v\85\83kí¤\93\ 5\874c\15p0ÑNú\8aß\10Ó
+\ e¾ß\e\9d\9ccÞàñ\88¶:a×ÝP\94êÄ\8eº\ 1õì$I4\10\r\f¸á\1cÞ\89ÜÛ\86\8dØÉD®\rvÌJ\eD@\ e\ 3v"ÑdÃ:`\8a\r\8b§\13¥i Øà\ f\9fNÞKu^\83{Q(\ e×°¹pÎ\1a>>öj\98O\8cªA\81Ó\89\K\rKa\ 65\1c}NÄã4\8co9\19ÚK\83£Â;\ fcÒpþ¹£aWÉ¥hPYN\ 4]hX¯\9c\f\8b@\83;IÞ\95o9!\9bÏ\90¨\9cü\81g\88×\93s\86\ 2\9e\92Iª7ÃÉsâÅž\8eQDåd\1e3\83à9i¹¿\8bN'RÃ\f+y\9dÌå2¸0\84eÐÇ\9d¤\982\14\14\9eØ\ 6(OV\9eð¢®è\ 1*îà\89\96'<\16êÉà\9f\92xùÄ\9cá>Ñe\8fª\93Áü~Ò=\ 4@\91¤\90@á6e(1\9dR\ 6Í%(äY\10(ãÕFP^\14mPÌL\19ÔH(       H\19º°Plè5\14\ 3­\fº}(I¥\f¥\10
+{ã8¢\ 4\87²Z0¢|\8bñP,áüJI÷;\r\11\8b(ê]\19&)¢¶à\84\87\1aHm\86²Ì¹to\19t ÎËP\96¼L×\95A'Ü­\fÊ\1dJ_uêP\94FÊðÅáË8\9d:\94A[\19¼Û¡ôͼ\88\94¡Æ\ eQ=\19:\14\ 6ú\1a\8f¦ã\10¢hÜÊ00D9\a\15ú\81\Ð¥ö\88\88b\91¤\fPü`Ê·¥¢%âÊ`ðÏ
+\91[\ 6·Lý2¨9Q2\18\81fËpV\7f$L\14\16®\f]C\14ëR\ 6\942Q:GúÚAB\80\19\97\7fz&J{\92\f=\91\150Xâñ½\94N18ÿ¸1,7y\19\83Ç_.\86Ý*Ê\r\86]\14·S\f\81Ì(Ì\94\18J\13\1eÄ @o\14>\1c\86¬<\8aé/\f\90\ 5)QL\18ê\91Å\ e\ 6`\8b\94\98\14\f\8d\94\947\16\18\93\12_\80¡\8eÑü\ 5\94@A¤¯\94gÑr®F\10\97ÒÏ{!-Êê\ 5\11Á\94®å\85\bÉ\14n\v/TMJ)¼\0I\9b²Cî\82F\9c"\12vax\9d2dºà2=¥¿s!¥\9fÂ\90r¡oP1Y\\80XC%\p¡iQù\83·\10×G%/\89*\8aR\91r¶ =¦ÒÍk!\959\15®ª\85Æ\85*vÆD\88k¨K\15\8c\87\16\ 6S\95£ë,\98ܪ\b\15³°h¬2\96Ê\82g­Ò\91\90\85\1cÅX\bc!\90¯\12\97±\10_Xy{X\88ϱ\12Û`!\10\97\95§½â\82Vbí\15\97Z\99Ó®`\15[i'¹B\12n\85Åm\85\12·\15£¤\15\10ûV\82öÊ
+\9d\19æ\9«°\82Áº"\8dü®Ðå*´\17½òÈÉAâ+k§
+óú\95S:T\ 3\96\ 1\ 6\8b\878\85üÿ \8c
+ô+ÐåW\8a\f*¨4±\b\1eó­½XN\0\1eöÆ2\1fï\7f,\eµd °G\161\88¿\ fe¹n¥ }\96%«I¡QÌbN¤\80n\18¥ø» *\19k\16¦úJ®\8d\9d%F\8aÂvùY¦\81(¸;´t»PH\ 5¤\85\96eß9à\962-S\ 5
+U²ñ'\80\8fZ\ 2Î'ôbµ<©'dik\89\ eOH\ 6\83\9d\10\vÉ\96èÏ     í¥-ß\8c\13RÙ¶%\a?í"·\88¦M\10m·ô©MH½·°^MhÝ¿ÅzÑ\ 4È\83K\90Ì\84¾?u!\13Ð\82±\81\1cTÓ¶üù%¤­\\92xÐ\\92Ò%äz.¦×\12\90\8c.Aa        ©?]þ`%Ä\90u       >gÔò\18»\ 4\1d%D\11l\97\ fÇ\a¡»T®I\80óÌ\92ÐDßÅ|$\ 1£ð\12G#!ïxy\1d\91\90Ìå%\1a!!\11ôòõ\8f\10\92z      l\8f\90Göò¤\1d!Aw/5+¤>ñe\936B§æ\8bu4\ 2\ 4ëK\142Bôûòè\17!\1eôK\90-Bkþòª\15!\19ÿ%ª\14¡B\ 1æ\ 3'B\8c\ 3&ä$Bø\ 2óL\11\10Lì@\84\80
\19\ f\f&E\12\ f\r¡©\b\f\ 1W\13&BYV
++Ì^\15\vc\90      \ 1\ f\r\132\84\90x\1cæÉd\84\1eæö¶F\1eÄ\88\9e $Æ\88yó@ȨÄÄ©@Èyb^1 $Ã)&#¡øÒ¢Ì?(ºÄ¼¿\1f¤\9b0&îü »\8cyà}\10¬\1a\13V}PÇ\eópêÃ\9ccJ\b\1f@\ 4t\95{\0y\8c8ìA .æÇéAÆ\85L\98\9e\a\9d(2\1f+\ fb;2!\18\ fBM2wÇ;Ñ5Kò\92\91­w`È\14w   '\93íì ºPÆÍÊ_ÐÅ¢½\ 5¾ñ,¨ê \96\92é ¤+ã;\\9dT\0V\969aÎ\81\96[F\18æ`ü.³·\1d0ó{r\90\ e\88\99x\ 1ã"3lã?dÍL\85\85\ 3\98ÑL\b\81\83\10kæ)ߠ˵\998\91\iý_}3\10Ï\rú±\ 57\0ÚãL\1c¢J\99<\87\81³ANv\86'\9c\ 1é\89gL\\10h`_\13Ï\14\935\0\84J5(S\9fùþ4\88ôÏdE»Ö\ 3Í~K\83lc\v£\8d\ 6\10\9f\b\rZ04f{\ 6ð\85hbÉ\19\ 4T4Oi\ 6±ïÖÙ\v1£±
+3\0ñ\vˠʣ1üd\0O\91&\88\91AÑIóÌc\90åJ\136c\90ïKó;Å \10\ 21p\8eÓt[\18\84¤§áÈ`\90\1dÔ\98\180\0\ 4ë\17´T©ù\e_\90â©     \88^Ð?Õ¼ú.È:VS\89Æ\96v5Sm\970bÍ\10R"®IÞÚLy/qÁÜEå\8b\v\80ª54¼\ 5ivkÞÍ\16DûibÑ\16\14á¾Z\0ì_¢\ 5ý©f\16hMk\bYÃúæÖT0,°eÙW H\18\ 5þ¬\15<#×\F¦\8f\96ùÚ5Ób\15\98\9c`\1f-õs1*À®      åSÐ(>5\ 50>b)ȯk\8cF
+°L¯\89Ó(¨ôk\1eF\14ä\19lB\11
+\12÷°y\ 1P\10\88±\89µ'\b\ 3Ù|³\13¤4e\93C\93Ùd\1f'\bél\8c´      °<´\89\8b&¨0m\1e"\13äUmB\7f       \12óÚ|
+\9fmL\11à6j$ÊÛðX\ 57\ 3p       |\8b\9bÖÄ(72\8eÎ\r\ fÝæfê\féæ\8b+A\88ë&\81ÿv\93¥&àÍä±òæ­>½1È\85{#Â\ 1©\94À¥|Ó\96Ï}£Mp¿!s\ 2àLq\12H\9eÀé\8a*'¼\82Ö\ fZíàD)fÂ\99?_8\7fr8\1cÓ¯\ 4Ê\828i\8c!\vJ\1ck\10êâ\12l\ 2r%X\95âÈÓÙâPDJ\90Ñâ¼\b.ei\8cÃgaã$\18%è©ãØ2`A\1f'\89!AA!Çë¬\8a7\ 4\1c~ª~;r\8a\1c\12 ^r\82ù\bZ@9ïs\ 4ñ\8dÊiT\8fzÉr¶Ã\b\1cÃX\ 4à}òDP$æ\18\e\11`iæ\84÷\10ä·æü¢!\bð\9b\13¨Õä&:\87a\85 Íx\8e}\b\ 1\8a>' \ 6A\7f óò@\101\86N\8c£¢\93g@Póè\18\8a\95/;éhìgô\ 3:/>¶{ÉÑÏ\v¨\90\v\e±Ù\aZ\17Áj¥\92ùXèA³Í>`ì;p\ 2ÅÀÇÒø@fO\1d\16çóh$áø\0Ýñó'~ ym°ø\80+\8dOq´»\91ø\80ó\19\11\1f\10T\ 4^ܨ\ 5\8cf\ f,Ðr\ e\b±\1fg\10VàÀj\82
+!çã\81à\ 4X\10æãÓ*°\89÷\9fÔ¡¬µ¶\91\a\8c¦ÀÚôU\9d!\ fÄ~d0\9bÓ¥20\90\a^|~¤Ðø¢\82\85<@¼-:\0D\1eà\9a\ 4Ê\9d\81-R\90\aö$\ 2á£\\85¡È\ 3V]0gÞP\ eD\1eÈ\ep\b\10FZ\912\ 3È\ 3\ 6|ã³×Ø$fY\1c\80Á\b¡\10¬´2\8f\a\88X¡3\7f>Û_fÎ>\1eðÂIB9\1eX¤À÷\14v!xØnÕg¨º\14Þ1®@\10¢;»\83j\8dM\8e\b+±ï±yüĶ&Qx{í@}ÖR\15ÀCÑ¢vÀ\1dFU\rA\8a\8a·Ú\ 1s\8fè\95\94ÑÒn¯b\1d(|LOEí@ü\14\ 6ì;`\8b'qDk)¤Sß\81­4Ü£´54E¶\9cbsµ\ 3\93¿ùEÐлÕ\ ep`å\84\94ìO%\ fë@9%±Ñ\81ÂOúrÂ\90\1f¥Is ½Êá,pï+r`¹\8c|Y\96×\1edË"\a8:¶\97"\a6'{\18U7÷R8à½68\ 2N\85ØÂ\ 1ÕQ[ª\9cªP²p\0¤\98G=\9aR\8d\84åï\96FxÅqÀ\ 5/°òu\1cÈ)\81¥ÑâÔ|¢l8\ e` Z0¥1;\ e\84ü\1cØh×Mp\1c8<T\86w\e»\14\ e0nõE\94Ô\17E\ 2ßÀù\15$F!¡Ë²\8fÜ\80\ e^\1cè¬OÝL\e@w/\94U\ 4cï9eÙ=`\ 3:ëº\8bÖ\v\ 6FáXg¥\8dºt5`«6]Lj\83\89Êi\80» çí\81\9bÊ¢\ 1øø\13òB\ 5\9cy]ð\f|µÕdL51/´\ 3µÔ<\ 3\99'\ 2\b5<\ 3\eº\1fî\8a\ 5\10\84Ú¶\v\f\11Q\9d\90\1e\11¤\fì\ 6ï\97\14\fø
+Ûé¼#Å)7~\f\83g@Sr\8c&\vhF\87o1pI/\18)a?ü8\ 5l\18pZ[¶Ü¼\97\102\14\fØ
+<Oº\9f\82~\ 1(9È\81®§:e\0þ##Ò¶\ 3\8e\89Öº@\89_Oý\94Çu\81n8¹\12C\11\17Xýï¬yô/\8e¸²\ 5pf©q\ fÙ·\93\0Z\0%ÿ߯%¦\8d\8e\ 5ÖÎ"A ¯@±H\93ÁZ\ 1\0}ºË\97¬\ 2÷^\9f\ 5o\a×G\ 5¨Í¹%é¦;'\93¤\1c\93\14\85üßH
+èP\rn]\ 2\85¥\14(
+$@\887\966\ 3\ 5P\86\1f1\o%&\eO\0\8b\183®!9¥\ 2+Li\88x\93b\9c\ 6,\9c Ü\12F®©¦`$\8a\80C\ 4ì\ 2Æøeþ¢'\93\80\8f^\8bøÂ~Ê!\ 1IX5i )}ë\b´§:Í\96ñ¹®Ä\b\88\8a\99-k \b(©ÝÍ÷KY\1f\ 2\801úúÉK\9f·\10Àã\8a`ód\97q\1e\19\ 4¨\96d\0\99¡ß\95V\199.¤^oFRú\ 1䣢£ÚQDß@ºeØØU\10\9a\8dÿ\99\84\ 6>\80Â×Ì\17\ fdðy@\7fØYFyá\99\b°\82w\80Ð:7¡\ 5êò\ e\88\0?(\9b×v7T\a\8c[âA\1e\1c` Èï\9f\9e
+\aH"ßH
+"\8eeÒÜ\80\ræ ?¹`ôP5pØ\07eؼÞCGê§\ 1ô=6­ Å'å\19Pyð©×¡Ë{e@>\\ 3\10\81¥\ f\85\9fî\18\ 3øÜÏÀÇ1êä\15YW½þÓû\83\ 1
+&Ý\7f\fÜ\83Õ\vHbæ\9b?\r\88b_°Ç\ 5x³®±ª\95láÐ\ 2æó û\0>¬2¿\ 2N±N©ç\85zZ\ 5\1c\8a\1d\ e;sS\80µ×i*\94í|(@\9f\19:ùÖ    àF\88£ÏÞÿµ­Né*;hñrè¾ùçT   (.bÈ\82\11\10\ f        ØlÈ\17Äõ\r \90\10Sâ¶þ/ #\807»¦b³x>\ 4\14Ççt\94\84\ f\ 1Í\0)L\99e\9f\82Õ `Π \9dI6Õ\9a¼~\80z\11Ehµ7\13H$z\80h9\11ht\1açu\9e\1d \ 3C6\&oç5T\7f\19\831\ e`õÓL¨ü¤Þ¤¥\r\10Å\aÊÈ;\ 2m\80        ×@z\ 4åR!\1a`\ 40>þ\86â4\f\ 5/\1d7\85í?\ 4\9b\81\ 1¸L¸X\ f\Þw\v°ÂU\83¸¢Ê\94®\0·Ôó\96,\8f\16\92\ 2xÖ7X\91Ù\ 4 Ô$Xe\14óo\19\92\0û\82 Äô}×\89\0bÜ­±ðS\1a)\b0/«me\9a¥õò\0r!\8bw\83×uÃ\ 1àË[\13ø¸âng\0[å~"*DÔ¦¡\9f\17Àjº\81uÅ>\b\1aò¾\9b\99*\0H9ÖAM\887\820\ 1èe@²I,®p\b@Â>\8eL\a`ÄÓgkÐ>à\b^\f\80ñùNþ\1eíx¬E\81\19(\0\1a=\0\80|&Õ\7f\08\ 6êC>¤ 
\91§Ë\ 2ÀrIa\9cÆ>\93\ 1\80æ2\8a¦Á;\0 è=r\f¤ô\14\80Dÿ_[\88Bûÿ£ZM\ 4³O°\93ÿk${º;\89\ f\7f®8\0¦ô\95w S¤\86÷Z¼û_²Ùæ\9bÌ®ÿ¢\9ca_ÙÌWsþ\af&äù\8fNñ®\ 6­\88©¸øO\12\ 3Î$¤"Â\9fwÞ?m`^ü\8bÃÝ\87Åì\1f¢ë\84Ü\w\85 QýO÷ÿ¨U\ezOè\7ft×0vùGÎ\88k»g\96é\88ã_\97åço\ 3´Æ=(ü\eã°,\15øþhÖvÓDX\88¶_æþ\fiEö\10
+aTûC\9bÒ\14\88Ò\85\1dìß±\9a\139¯þMñÐ\81-R×\9dþ\995>\f¥\90\ 5\16\1aý\r¸\14MRTôü\95S¥6\9b\9aÿCq]þ6öÀ^,ÿøÐ\83éÈ\85Ì\8eüÁµyùû\13áð\94Æÿo \89vGäùUÄ?4kÕ\ 3Q\11ÿ\aë.\10O{Ä?\82\8f\8f\9cÖ«I\a\7f\1d\ fþ`/¬Ü~%ò{\7fÿ\10|³9ð;V~ºxÅaµ\90\0í½Pl÷Ó{¤#M\aC\81\93û#\90Ýýð\8aÊ\11àA\16DóãÒE_\1ag        \1aç`\14¾\ e\1awãð\10¼$ûuìIÝ7Õ\17Àþgz´Ë\95£QfÙû\94È­?Õ\90cç¥\96Ö®~e¥i2Ûõ\89<1\95ú\85\80ª\8aûS·Ñô*§¿\11;'÷\9fô+\ 4é*>\18]x²Qô\87+\9c\94úáùÙA\ 2èw\88     \ f´\835ªR¡\89áù/\ 1\18\1fãE\94?VJ§\95òäö\99gf~aãr\90â[ù^|\97¿¤*@ù¬dΧòWVY­PùG\e3NåQù\19~Ln\ e\ 5\9d\fçÊ\ò\a:\8f\91D©nüò\85ü\1d<\9e\8b¦.ç\1cäø¿}5º\ 5\89±s;ùâ§\98    AØ\83µÍ:É ëMl\11`âè\ 5îðãêJøÞ\fÀ\89\8b\85\1f\88ï·\1c\147\1aüÔJÀQ\94-+\ 2?ø¡\ 5j)Æa¿ß«ÿ]\ 6nÀõ'ßç\90?P¤÷ýÜ\98ÑóGLÁûUPM\ eeŸë>ä \9e=,\90{îËÌÁ S\81¬\8cûåÊ_r½ýÑq\ 2:¦Yl\7füÐQ<\81/£mj\9cÛSû}
+IÖ\9cë\ 1ç\ f\1aÓ¶\81@X\ eJ\12Ï0û`\8eDG½BR0w\98Ù?íó3BÌÎvwUd\7f\1a1Ù+ö3­ÊMÁG{¸`_¬w\vá\eöíóúI#q&õAÓçNo\eÃõ)öÉ\99#^¤·³¾\8e\15\95(Q4\97Ø¢«\9fi7p\8e{s\9fS\17\80ª_ÌZBÔ@\96\97ú¹hõA   [6\84ú\ 6À\12\0Ò:ýÆÜ°_¦_Û¢ò3ý\r\85      T\80Ï\9d÷G¢ÒoÅ@\1aDzn\fé;\1f'\90\90º@Q \8eÑ'B{²\1dxk²>ô\85ñ\1cVùcÐw\86
+\83óN?\1fSLÛ4Ì®\ e­\9fO\96úñ'B·º¹z~ÆÄ()w\9d\9fRÇÛ¡\14¡â|\\bï7ίCé95:ÖG\8b褥w1\14\18´<°bõ²\ 6{\ f2_»´Î~ù<\82\829n\10w©±å¿­\8c¾îo¼Â°G!jåWþ\01§ÐRÓ´#å\7f\15\19\7f¦=b\rÞäç+X2!d~\95äÿ¬Ó¶h'öÂ\9a\13ùlTï¹B\19zÿ|è\1a\14\90\7f\9eÝ.¹ãw·{/\16È27~'YØC¶M#\1a\95æÒU\19ÿ´hì\11\99=M@E¶\19\9f¡\95vpS¸'f|j°\88\aL"þ#©ò.>ecƨԨøT+¶\9b_äNðCK|1«$*Âñ½Ä7\18«\ f{é p\95'+ñÉ]ºJÃ\88\92\95øòå6¬\0\85\87\12\1f#\92   ÕåÃ"¤Ä×Ìý\99ã\ 3È\85î\95ETd\98@PâÇð&HÆ\80)\80Íl\19¦¢Ä·LT7W;óÅéÞ\8b\ 5îJ%$\10âÈ\84Õ ~¡\î#z\8dø >¿$\ eJSÜ\83\1c8\88\7fûÚrK+º\99\1f}r£c±Fnø78²,0phnø\11\97ø \87\9fþ\15E{Ô  ®\ fg\91ð©\9c®ësð\aÝ$|y4­ô§hý\81>        _Å\b\vRßý\92ðÉ¿\8e)ÊÓÉ\13G-ºÙ³\93ðe\b¯´þÈàãFøÍ\91¡$#|Á{ã¿áÕÞ\ 4\18\93R-\e7)\82Ï4\vZàá\99\83À?\ 5D\b\8f\b\r"ðÕÆâ\ 5\1c\97J\ 4>¶T\10ÞD=¦é\ 4\81\7fÖò\8b;í§¨wÐ\7f\8fT\10\82ݸ®¯~\8f\91ñɵú=\89Ë+QpÐW(\92Æ\9bÒÆ÷²Í\1d[Njï5J´dĺa\9b\aîÐ{é÷&VK¬\1e3áx?\r\89Ì\94þÚã};µ\7f\ 4Ø»\97Ù\80*Úf-Ð\86\7fGËîqøíaOã\aÙýÅÛ´mè\9a\1f
+\b©{ò\12­\94\88\ 5m\82¼áÒ¢\9alÊrÿ\90ƼWMÀ1\14÷I\8f\18\1a\ 2\9b\rà::p?)ï\ 4÷\16\1dÆÐS\11\91·\17'C\93e2ôæ'¸½·s¦h\ 2ñz¶g¾ý"\14âCÕkß\ 6ã>º0£WP©öãÞ.Vàü\8fiß³ñ\11Q\rñ    ¤\84V·Jê4T'SÇþ\89.\97G\16Á`ª    c/X*GÙßI©S¢?ö\1fekwýÏPm±7Z^       Z ï\92X@÷u\ 5\9aíf¤\80ësö9!:VÍ~MS©DB_¤Ó¶»\ 4\98×\1f\82ö\83.Ç­\9a\90\8d\ 1éZêúVðýî\81]Â<*\\7fh\9aSÈW\b;\86­\1fÆé£\12\a¶~Ì\87û`QEÎüYß%KL&½5¿±^:\88õ¹W\1f\0\? Ç÷2«/5ç\18\8e\9fµUõ¢9ÅUÕs\b\8f\91QÍ´+à5T?nâ¤\81©'\81ç²ÌÝ\99GýW½X\906oÙª\15ÒP\8f\93 2éNy9Õ§ßæ¡©ÿÙ¦b:ý«\12òÿÛ)âÖô'Û6ÜCem\f\98øt!\83ç+ÛXÃÒ\1fº\81ݯWTi\8c'}\81\8aòE\80û\1aéña\86\ 2\82u\8f~¼B\8aFϧ\rË(£\91¬è;­=ËîAêDôü#Îõ\93ñN\8b\91¡Ï\83\13\b=þ5M\19\ 3Áâlâ\81¾zÔjFÜØôÏÃã\9f±ñv\ 5\18\18èóÝ\9c\8c'(<úü\9fð&v\16\ 4´\9eß,Ñe\19¯ø\8cx¾¤R
+mÌÓ½ìü (l°\8fÓÆ@çÁð9Ѩ$o¼(\87\95 4è\9b·]ûÙ\19c\95òAÛÕÚü1·µêÞ\95Æ\9açîê\8f\93\ 2¨>\8dæS£ÊË\ 1\8af\81¸ËÍ|X9\8d\7f\8e\8e1ɼ ±\15ÐàÏ\19Hb\1e^<QOfY9\8a\ 2æ\1d ¹¢\9c¾Ë«\11\82\9ednk\80¸å\95TñE÷jôY\96\9f
+\1f\13\17«\97å'Gè\ 4m³Ö\8bl®|/A×õ|\11W>\9eþaýù\11±©|eºÄÓõЬ\94/zV\9bXÔöãÓ\1e\94ß·»\93+$;\8dáä¥Å?\ 4Oe\85æKÞç\b-   s\93\ 6ËMZ_9Ñ\1eùK'âÕ       \ 1¥"\8föu\87W\8fð\eª#C\1e\bÇ×à¡=\90\97®\ 4Sqh\19È·\97\e\88\84I0   Ç3þ oÝ+\83ÇWNÊ\0gñmøø¢ÎñFÖé/H¨t9¨\ráã'J\9bY\86Ï\f\80(\8f\17\1fo\95.\9aü\8e/g6eî\8fkÞñ`[á\e98å;^¥ß$*ò!Y!\80\80¾ãqÂ\ 3\9fª\1f¬\90Ó¨\rAfï\ 2±ª*\18\93äGÐ\ eÌñééÊl6ÇÿEìN¦VÄË)kæxå½Ô\ 6¡9¾:Ï b\96©Ñ\1c?Å­\ f\8e\8a¯½\0æx\17ñ\¢<i9^\9c\89XS\ 5±\1cßëÖ\a\94ã3¹q\86h<"»v\a}9IæÆ7,²ä\a\8dØ¡ÑkË@8k\ 6ð\10±2>\ e\16\0cUê\12XC0~ \«M&\85߸øYO\1f\16]Ø+~Ó\16[ü¿À#Mñ\1d\93\14}J'\9eáR\88è@m\97s\16\83\9a"Ô"¾*ØQÖ\9a   \ 1Cd
+U\10\ f.6\8a<Q '{øÐ\8a¼\ 4Y6yY\ 4Þ2\f\85\9c3mKÃ#$x[^\98û\96½\8b\ 1\86g9ÐØÎ\124aù¼ÂÃ\\85æ9áE°\1c+õßL\8a´w[\13á\85úZ4§N|Ì\13vðà\92÷#«\1cÝ@¯\86(*\99\9bZ\86¹\vb:\88IÁ§4Ñ\1e\rÆCüz \9ac\17XSÖ\v<\92\8aʳ]\17Ê0Í\1e\0Ä\1c\82]\9d·E¶\ 1Þ\87{\9dô>\9eèûï­\ e\91ûyÂ\7fS_\90çï+\90'¯­»{¢mP¿»\8böÈz1\1aÄïmÙùá\19Õâ÷\9c=\9eåÞÜJöýA\f\1eñb) }ç 9/Gõ\84¾SQéQ$ò ÇwÜ\9aA\86\ fxj\8d\91ïÝ\92¿U»À\11yÒÔÞß×Zò\vÖ;\1cJ\r \0\88Þ?\92\90Tiç\j2ï÷4\ fðáá\95gÈ{\9fU¹SEG\98õ« \17\17Î\84Y\81\büî¨\fÁ f,\ª\15uwåºVñ{\1c=&c»\v\89n`kL\80C\8fÝ\91\9cÓFìÃÍé£uÿ$£\8e\83±,3ê>\1f¯Êùëc\8duUV\0énûµß\9f»;ã\88ék| ³NÅ6wj¹\7fzÎIáSÛ\96{\89\83AU¹µLrÇ];\97¡TÄh¹\8d;Lî\1eô\8cU\17&î QS=        \8cÖ°ÂÝòn\9cç\86r     ¸Ë\ 5ú2[U\99\19\9eضðí%é¦\84<?ñ\ 5ôn\17¿V¡\91ZL\9dÛË\98 FªÉ&\86ÅÛ\ eºÀô\ 2Xµ}Õ=¤o\ féäÎlÏÔ\97"DÚbÀ\1e¶_\13b6\80\85°³ØòÎ=,ÖÎ\9a´$Ó¦¯R\vß\9aGµK\98]¨Ü´ùi·Ê®6\8dJx\89ÎÒ\ ek-\98yX\8fz\19G;)=9¦iw5´ã\98\15eí]\96!ÛÏN\1f¤A\86a¨h¸:»Q\v\8c\90\81Í®éX´\8eùÿ\95\99\13³³ú\1f²p\92p\91e§dF7ñÆ­\ 2\11\a¸¯\8doàf£\9f¿"%\1f;4\ 3Íf\e;^Ç¿\89îΰ+µØWÌ&hüë¹ØÙ\vj\ 3Ø«¬ÄN\92x\98e0Èô¯Ãþ(ëMÐPù`\9a\14ö«©vW\9cì\15J\vv\82\17\ eÑ\ 1j\10ò\81B\ 3ìÜË%cR.ÀÎ\95õM\ 3\90Ñ\12\96_ÿ:U»yà±ã\ f_?u\86k2à¨s^·HÂw7\14o-?¾ë\9c¹¦B\95s
+ëú{Î\88F\ 6å\88r.k®cGì\99Äõò\8d è\8aÈ­aÁn=¶\|ȪvëQî)\17\b0q\1f[7ÈÜ4°´Ø­Xj=×TÑ\1f« \ 2\ 5´¾Ì\r\10\90ø#\8b~0ë ¯\9c\13¢3Ó<\88=~\9d°hæäþذ\ e6vçüV~uô×ÄÀ\8duu\96 \12GüKuuÚ¢é\81gOlnÆVgùñkeiaxÆX\1d\90¿²\8e\89ó\94V]\e¸\9dì!#ä&T=È\8b\19\19ßÒ?ª\aYv¬Ø\1d\9fO}\17\e µâ\97ûlê¶\r­³p`\81üÔR\87¶:&sPR\f\9f¤þ\1a ï\8e8碵Qw\13¥!ßl \ 4\89zÛ5¤_\a2\9f\ 6\15w        õÔu\17j\vD_¹\14\97\ 4¹U\92lMÔmrÑàÀ\87 ÐôBAubÂ^NNÇ\89\85÷\17kæÇ!äqÀ­íÊ6·à5\9aL4=,\846\\9db\87\81#Î9\8c\97
+L'¿}\ 1É\87oé½-G>¾#®t\96\0t/\¤Ç\94®\vÓ\87Cw*\f\19%ÊI·:Ñ71Ù\80m\92\8e¢#ëú\f\v\14éh\86MB\8b\88ëéí\ 2éË/ÝC=õ1\9e\8a\9b\1aÑ9\10¿~£s\ 6±;l\83\1ek\93\19Ý\8e
+\9f\13OnÍvÑU\1e\84\ 2±qÝM*º\12ÊÍó\12}Ãñ¹\85è\bîðý\buw\95C\7fáKÃèrÈB0t0ºã¯\v*4/I\93á     ÝQ\18\83¾bÙ\9aCb¿Và}·
+:EÇÄ[\fj®WüĨ!\ 3ý¼}æ\ f(\ 6ú\ 6Ô\13BzF\8d\ 1ú-\82a,\1ci\12\86ýùùA\eÈ2?Çé\1d\8d|!H¯Ï\17\90ï2aÁX|âs©ç¶\9aöÄ\95|çÔ7ä[\9cÔGÏ¡\ 2  ªD\9e\ 3\92\89>\151\ 1ú\9d7_\87øAÑ\80çbc\95?BÉÇ     ?Üy5Üna\15ÅäsìÂ`hoûu.-Ú:.a1\9d÷H\11Zð+âA\ 5¬¦\ 68>\8dq\0\8f&çT³i\88Ϭ\152|-N¥â¼ðl¨XÒE_Ó}ï\ 3çÝÛ[$ñæÙàã²\96oó;\v%0\92$
+âHTܳq\ 2´c>4·rÖ!­\97ü\84cj®1\1d\1195\ f}\9c(ÍM\vÀÞw\88\f}uAs\11:\1a\ 1¹°\13B¶ã»Ò5CØV\f\95nÕ):Q=\99óó\13\95\90zE¶c\9e:ñ,\140\80\8eyÐm¿e\8ay7\12i,ÌI_Ú\ 5æ\8f\92¢\98ý?_îÐϪIþHC\8a]ÞʤsZµ,Ô\ e.Nh¹÷,\14\9e\1eËG\80¿÷Ëþ\8emP\8a$\r\ 2.jåÌ\18*\89Úö}È*ï8\81[\ 4¨À*7U§+\ 6ü-\9d£òÏ T{fI9ÕÕ\94ÿ \16\970\85¢©\87úO\8e<R\8eF.1«(\8f"wÕÎÉ@\8b\81r\8b¢å\88\11ÈÎ34\80\âÉc\10\8e­y\1a\b\8e\93G­%\13Ù/aB\93ßk\17cfRÕÏÖ¨/9½\8aL\9aرT°M%¿I&©ä¡_hÀaq^I\9e\ 6´Eï\92°AòªBÞ¯6þÂ\91#\10§8jdøÝ\86\8b<®ÑFQ2æ3%rú\99¡\a\1d`(ä\90§uÈËäÓJj>\¸\94\14r{JK¬r\97\vr*=\9b³+°\vÈ_\17»\15\124äÇÇ.Ri\9b:@?\90\97"U\ 4âWsçñâDc0Q!ÌïxÇÉ\86"\18ùw9áêøÊÙð«_uHu|{þpS~ç\99ãV\ 2%y*'\rÇAUh=N\93µéÆ¡è=>Ò$3Ù8-Ü3kG_\ 2J\8d\ fÈ\91\84\9b\95\18Ðø\9dËý\ 1®\Æc\18\80\16\14%\1eo\ epòüVa\\81¥Tʨ¡VXøâR\10A|\ e\ fR\9c\14äEÏS¡íXh©Z|Ù\12Wâë\17û\8b\17\ 2b?\8bñ°ø+9m\9f@C¡Ì\15\93@lIú¾,+GM|¸\ 6Î\14Å9csÌ#\15\bH,¢÷ñfâÌÈ*\9a\ 1¡x \97æ\ 3Î\r7ÄQÜ[±B\9f>\1f=\\96ô¿!.R\8a¹PÊ\87q\8dW¬ÎèkÃ|¸\9a\ eíÊbÀ\16\1eNK%\1aÀ\ 1\1e ÐáÔ/ñÜ\e>ïú\8dSy5üõjsÅøy\7f}\19NÀ}±à\8c\97ba0\1cÀ\rzN;\8b¹\85¯\9d£³¢p\18µ\89ºÂ\e"L\ 2Ôg2)|ª4¶     ×Í}óÂX\12>\84¤zZfë\f l*0\8b\ e\80ðu\83íµ\1dmº¤\1d¼3èmc\18°\r\8eU)T\\80X\90\eþ@'\83\91\ 6Mh,m[p\0ºÒ¤`ÁÏO\15-Rð1\aYQ\12<'\9d帽?ÿ\f\ 4\7fÆ\19\v®øk4l*ÒAá\rüŪH.Öoà\885\80\1cþ¥\9fr\81ÏÈ\89A~Í>y\vS\9c\95Í4\9e\86Ñ\ 6\\ f"Oé°\ 4\9c­¢Ö°\13¹"àÐ\Ûâ\85\ e\ 1\10ÿ\bx*>\87\90´³IM<     pï¡ÊH¡%\ 1>\96°íe\ 5\94¡        ð\ 3ö[ÆW(\ 1\87\1e\9d(\92¢¥ê\12ð;¨\86Õ\11Ê1Ï_\ 2n4\10\1119àÑý³\v\aüR°[V´\88\99\80+\ 3q\vÏx<\99\13ð\92´1é\ 4|\1d3F    «¢\9bì\ 4<\19lr½Ð&àü;\86\86t98ýOÀwëZá\99\ 4\1c\81\92 ç\ 4Ü\87þ\16²x \9c\80Ó©³*ä   8[\v\97\9e\80Ë\vp¥G\86A¡(À\91\fÐ\ 6*\12\0?¬©G
+\80#Óc\9fþ\93\80\ 4À/c¥ÀHÌ\9e\17\0¯'\ 6rÔMøo¦¢¼syý\8fïo:ª\11\9e´ÈÏê   Koù»±Ð\8fS\ f÷ûÉAü\ 4\8f9!À5ýÎÝïG5\13å7\16\9dôë=B°à7©*îÌ8\84\9f\a¸o1\vt\a±ï^v}¯\92é\85W»Øô­\8b~i\96)ýà9gu*\r t¾\91\90O\882¹Fùn\1f'G5®\1d\9föºø>]øö\12lp¿à[C\8a\ 3\0\89,².ïÝ4f^\8bäu!\ 5÷\ eÒ \9e\99½OæÐ-Ålx¥c]o\\19Ë\89\eT\1a+\1eS-\84J\9b±ôö̦\8e|¿ôN >±,.\18·Bo¢\f\ eP>}óÖ!\83\9eê.ï&W\164Òá\84\a\e¡Ê®|Ùâx_ìÖdu\17ÂÄÛ@\94\81\17¤ð^\10ÔøÊ}"à\8d\ 1\0\82ãç8|74\10¸£ç\99\11¼[Ù\17\97CÇ×nâ\9c»\13Éi@k\99\9f\1dÖ}µ\9b¹\81\13ÀìFXKf%Ê=Âî6Ån/ã3ÌòH¹nl!\1a÷ÕM\14ͯw\9c^S7FP\1e\9fít;¿3ÞÙ\8f\18\94n\ 2ì3¼\ 2U}ØYtsöN6\e\8bó     ºS{QN9P\bç<÷x¦1©¤ë\86áܦ\7f¥\81m\82tsæö¹ È3wÅ~¨\1a\89ðr\8fb\1e®mQK\ 1Âf\1a\ 6U¹%¬\86æLî/\8c\8diR\13ç!\93Û\9d¢¨\ 3\10\19N&÷à[ZÚ\rø\ eáw\1c]% \86¦9:îD\94¬\14^XMÇ=\88[sA\86     2AÅ9Æ­Æ}\91\93õ¢Ù\9c¸}\9fð}1V?PÇøÃ\e\92Eá¶c\97\8e\1dDÝM¼_\99ÌxÁ]\r\12´Î-¸EÝîÒ o¿\ fº`òW-/û˲\ 57÷é\b\7f¯Ù>\17Ü-Ö§\\91ûÔaÁÝbýØNQµà¶\ 1|«3\89Hãé\vîI|wÕÀ\ 3²à\ 6\9f§ï\90\10ýr\1cåAIzÁ}¶\1dóbÖB\e\96ÝÀñW\83Â\1d\vJ\9e pK\e\ 37/\v\80SJJ¡p[â®ä\9fpßë\ fh\8f\84¤3 Bs\ 5T\v·6\85»á½\ 5¹¨T±Q¸\13TF\95FÌO)è )Üî\9bxt\9b\82\94%ÜMÒdù\8e\8e\8b\r·\96µèóÀ1m¸½¦¨\92'ܱ\89¼C£9ÜÙ¿\17r\11\b8E8ܲ\vçj(Ñ VY×À\86W²ã\1c\ 3°Äb\ e÷]\9eä\ 4\87[¾ã\89Ë\14'\1f\87\80=Í9Üé^¬\8d\10\87Û(\7f\14ÓéÛ­A=\ e÷I\96¸c¦\13×\127sö4¶\91I\0s»:Ö­ÖóÖó\ 1¨Äí\80ª7\WÍ%n~d½H2\15\94¸\81^\ e·Íö0æp3µÖw\89|e\8eÃ\r\1dS @\97yµá&ÜC¢\rzb$Ü¥vP»\ 3éo\9b¿\84»Þæî½áæ\93Ô»ØZm¸·!nÂϳ9    7õ\1a\f¦\84»-©kÃ\r\ f86+\98\86Û\08\1aÊ\1c ©ê\86ûÓ6^Úøßp\17müZ\8dÛ¦sÃ}ìÁܳán*½\85(Þ¾\84»ÇµI±×¤/á\86\ 6½5ñÀ\0«\84;!\f&nFk\17 ÷Nö\14¹\12/.á\86æs³b/Ø\91\95\9bÕÛ \97W\90C\8fÃí+§¦Ä=\ fc\10l%î2&Iw\8bÛM\9b
+âö°V\8a\9b\82a\84Ä=L»ap\12w/£\87þä\ e\849ÜL\9beÙÚ\16B\0Ôp\ ew\ 3\8aAâ¾¢
\84\e_H\b\8c¸N©0(\9eJEpj\0\11\ 6à\96r{?YpC¹>J\8b\10\98òª"÷6e\90\83Ûæ\0F¹Ûä2Ñt;¤Mèz\ 1T¬Ü\ 6\a»rFh\15U:¸í\12\8b\9a\15Ç ypÛ7ÖÖï¯íz\1e×       \15\ 1\9b\ f\9díýágo:Û\1d
+3óYa¨\8a\9b²½B\aÊ\10ô/ê\ 3ìb[ÂX½\81Í®`\e\90\1c\r;\10@yí\0v\93n'\82&\[iÜ        Å\97"#¸³öÑa\17½²\83¿×.\87\83<A\aç\0©jwg\80u\88ßÒÈÔæ\10ú#äm\19gÿ&ñ\84^\91z\88\v\92Ëi\1f\ʦ\9fm}@\11»\81iïO \1aC Ó6\10¢ZØ\97\b2aª\81/\9c´\81ëv4\92¸_£G;}\17\845\97§\17\13\160\1eYh\13ÚR|{7{\14h#\80\ 1\1d\8d¤nä³\87.?ÆbÈAù'\86gÓî9w\8açð\81º9;Þ6\9f^\8akrÎ\9bmàó¤g\1c0\10³U³\ 1\ 2ï \9bS\0ÏÌ.CÃ\ 6_³|~\98Ý\1aµü4\943x\90ê²SnÁ9\95\18ÛcÙØ\7f\1cv\1a\ e\18\95\r¼¬.IU\95\1d\1c¬\9c\1c\8eh\b\8e\1eÙ\10å<\12¾Ü\87!û       ¶¦\1e²ßqUU©^!¾\8fýF#¾\88\8eí6$ì\1eר#\ 1­\ 3¨dìl\98=ºè\93£m\8b\rw\89¶Ë̼¾>5µ´\14\9béÓX\8b\b\83\17@ ~Ð.\fL=\ 4£/ 6\9f¡\ 4ª\11Üæ\ 6
+\87íÍ\809\87-\95®\aùVV\81\12\86}bâÈ\98ºÀ«\7f?aw   \ 4P{\1eí'ì\vP\18 Æ\ 4¢sáÑë¬\82Íë²\84Å\fòÈÀÎi2f¼¯éºd`M¨\88\ 3\9dú\1agÈA\7f\1d\7fb\r¦iÙð\8d\ 1¹!J§ÍsfèëÆ=\b}\9e\7f\8efæH \9e<8\ 1f¾õ\ 1\ 5a«]§®\1dYóº$5~ º±¢|\11¯]\1aos6\9c5Õµî®\93F\16\1e\91\ 4ÄWvÝÒa­^¦®ÕyoàZ\12tý¯\99\15¿¨\81\97ë·éßê\1d»¢S\1d×HFû\94\v\12\9a\93\eªÈùÖ\82\17ñÆ\17±\95\97\85\1eZOê\9fÿt\14`ïµâGÑ\8cB#ÃÖ©\90\96\16OØò\ 2Öú·v6Õ\90Ø\9fÖÐØ¾ßÞ|Ð\ 12Z_Ëæ\16Oæbö¬A\8aÿò­\ 2v\97²4ë\0öob÷\eã\ 6¬¬A;\ 4\9bÔ KCd\1dYòÒ\91uáØ\90\14¨x}äV\9f\1a\ 13E¢\ 1zúX\f±\9eÛÆ\84 Ù~\ e·\aëZ\93\17þê\14\15\8bõj£s"?\8dÉøìêÓ÷\ 2\8c\99ùTh\82\808Gqµö\ 5$\b%\12³Õ°Ð3ñj"Ú³\1a*èô(0[#Ù\15Ë\82Æêüô\8bÀ\81ú»W}ó¶hevhCeµj¦ó[´6(ÚdU{+"¨wP'\f\8fª\rákàü\ 6;Jy\ 4a\9fãÇ}e\83óHuI]¦þ­2B\10Õ\83\8b\95ÜÿS÷\11X¬¨¦\9e3íÔº\ 4ÉÆmjø\92F.IÙAI¦vÂî¸\14ó@5\ 5¶Ôvhë~Ò{±\94\9aN\85}®Âé\18vHêC¯?UL¦é\8f\9a\15á\88\94\ 56j\11E\9a3R\80§\8c\16õ){\9bi\ 41zC¢^\8d${þ\86:ð`k\8c\91à      uê¡`uóp­ ¶\96\1døµ\18\88\ eP+y2K[ØÃñÓ]\90 þÕ"\8dݽ§µ\1d"\ 3;x±yz$z¸¦;ýàb\97®5ºÓ\93 \10²´%'DÕiZ\96\80§R/\83\1e\15\ f\84újü$«±³Ãéâ\90ÆÓ\91nºÃ¤n`lzp9n¬_D\ 5pºÂ\e«5kÙiÃt\15¸ü\b
+ìV\99\1ej\0\12\8a3¦ù\91\aÓØ\96=\ 1³\12¤\97V\14^_\1aÂ\8a*.͵\85ô:Kó\97 N\ f]i\85µ&½\80ëý\12\176ªJwQÛW3*\fß(SºQÒìx(}\ eûd\ fÓI´æ¤\95\1a,Èw0ip¤\1e\9d¤¯V\8c\15\1eé\86Þ\13\8d¾"½ù\1fE\0\86ôüVÚ\b\1aªºA\ 3é|\ fK\91\8b\86>z\9d ÉÌ \99\8dG\876y¯Êxó\1c\1d\9d$C\ f8\93\eí\95\97Q\19¦\14\1cªÑ\7f\9d\9b   3Ú\1c\16®O\9e×FT\12\86ÚÃu\8c¬uÑ\90qÂ?ïá\8a,`ÑÆ
+\86\87\aj\ 49f\7f\8a.\10Ì\ 6{ÓlOô)\84\ 1\0°\95èÑꫯD³¥\eÕ3f»X&î/»\88®iw­Ù\0\84\v3\17ø=\v¢ë\ 1&W\0²        Õ<ô¢]\88)*\0phàôöì\92Á3tZÑ1\95\ 4\96G/´ªé§#\89\0?\14T¡Çif>P\b^\0â\85X\95¼xyXäEè\r\1dçeèOWóåA\ fù\88\ 3\9a-\84\fz´çq\ 1\90ÀÎ%\ 5-»bs       \b\1a\1eE­£A¿³{\81\ eÉN¢\¤\ 1½2ø-5 \v\90^"¨\81\17 ÐLÉ\8aâÅ®ûgÿÜ)\b­BÙ¼ÅJ¶æ 69çO³égKc@÷\9fWf\17øÙê\9e\ 2x}¶\15­¦<Ù\0\80\b%¬ñ|Î\00M@="hUù\1c\ 3\9e.\90\99ÕCï¹u\83\1a\9fg\9c\93öÜ]\10\15\ f2\99Tõ|¹cö¤¼ëQp\17z.±áãVöíQ\ f¿Ëó­ãßW\19\7fïxÞø¤FÂó\9fh\9dÇç\92¼|gzçèÝ\83þ\0y\83"î\±\82`\ 1hg\89\17\9e\87\ 3\18¸¯s\f\1fW\1aÝ0cku®¤iy±é\8crÈëÕÊøyV\ 1\f\82\89ÎÆ\82á\1d´sNÁva\18ÑDæ|ÃÙéÌÙà\8d`ÁØ\8e\8e³Ê9Ó̰ê\94]\9cÓ\90óZ¡ÅËà\9e\90%ó+p\83\19,\93¦ëx\+Ä9ïÓ\86\9f#ÆÁ9\94-üyOÞýÍ\16ãB]¨\94e<½Ù©¤H\9b­\9b\a£=ýâæ7\11@źâ\98bu²ÍM÷\92ÇXÔÊÄ Í\9fÀ\9d­c£\9f\8dÍ\vÅCiÙvnø8½f?þ\8d)\15\13­Ùµâ\ 2ñôÞ¬æÑ©\16\12\9e\r\a½4jV\ 3UiN5Í3\92ÿK\8aG\9aáSih:Õ\18 \9a\8bÈR­ôÛ\1dû3[«O-væ\18Å\15&\ fÿ\8a\97\9b¹B\9fHl\91&¿$rdæÏFæ\1dIÖȸOË\Þ\ 2­\83IµÌ\924ñ!M\949\9c\9cä&\92¹`\ 3t\14ù1\8f©\8bñ\1a/7\f\1e\81?\10É\r¦Åü\jÞ\0\9d£\ 241Ë)\94+MÌ\1c¸¹W\rÆ\13±\98\98%nËVNæ\97Í\14M̶6¥¬\12db>\81ÙÕb\7f\ e\88L$¬±\96\82\1cf^At§\1e ?\87Y\8cÂêb\90q\98µr6     ¾\9c*BÑ8Ì\87ÿw¢/Í\84Ù\ fv\8aU\121\1f\13fÂß\ 5󬯱9avÂÈ |ÅÏ:a¾!\80
+Ö·¦    3£\81B\1cN2}Â<U^z}Ç\1c\8e©\vI¶>×¥\9cU0\8b\91a\86S\85\86\82\99æ\ 5*\15"U¬`îñ6¯H5j\8b\82¹C.¸\19JbÅ\849Du\98Çç3¥v\98ï£\1a½\19\<%;Ì\8d\1d¨LhÈLa´Ã,
+AODf\rÁ&æ¤
+æ¬\0W>\eµ\bváÌÄìg\9d\85\86\9e\ 4\8d \ 2ïß"\98\94\80Ér\98EWèå$Ä\1a ó9¾?\13\ 4\84Ù³r\9665Ô`\ e=Â|\1d»¼ôÌútúî[Q\8b0\e\13±2?æQ_\11f\8cfCh(Ãr2ÿ³17¸Ø\9b¯\1f9ÄLb/{Çê\8a\eèT(vØ ÷Ôð_N<6\99(`\1dÿ$õeáì\98eð\©\97©8\95ÍJÀðò½4ݽ$Ô\ 1N\99À.Û7fÛ\8cLü+«ù\^v\ 6\96\1dC®q\99\96\fRl¡gB\19³zË\r\8b«\a3\1fÚ²}¯\87æj\19F\8aeæã\ f ÑrL_ã\9c\ 6+Ê-\87¬Ìr=Ü'\9f\f\90ãc\19{IÆø6,?Éï\9a¥\1fÊé+\9byl\18\8d\98xf$ºr°4Ñ\95ï]\86ty%ñ¿q\96µrß\0Û\83P'9ëL\å\83>{ul\ 2i©·¹\17\1a\16ÚL[¥½]\9b\9a\17þ´ÎÞ\19tÇpº  ^4\1a\19Ñ\83\19åMË)kÕ¾\99«#&\\14%Á)ô\18Lp2`¼c°á´\81ÖNÜp\ 6fq¦U\1f¸\1f'eJ-ã(gI8¸\91 É\f/æTýÔI\91Îé(\14jëeEt^sQ\9f¦³\95Ì\98\bµ\ 4¬Nr~Ð\85\8aÖLÞuê®\a´\95\9d    .«ÅíÔ@×\7fÛÉ6Ï`;M\86\ 3¯®ß@M°vú³§7ÝÉLhæ\81¾ó\ 4Ãó9&4\r\8f§~Kn\98§Ô:aUè\99B\0\976\r\8aéÌ»´Vû\947\9eY\81\9br^\13ZËýÎ=a¤¸+0i«\8d\8fK!öß\13Äíöp\8fZt\b»ÖÏ\90ëi;ýÉÝË\r|¦üÏÅ®v\ 6¨­æY= °¼\8c>` ÎÊ\92ð\1fh7¯¥QÐ\f\9f\fª%%å1×ÛA{CÃ\84\bÍ~\1e.nB³DÎ\97\15z­Ôó¾P[\v(ACcr¨}\8dCM\ f\95®KÃ\8d7\88úêjFd[æúmÀ^²Â>{¢9¥´ø\14½íd~XTÿo5\93\8b>pÆJ\18M\14#ò¿\8c~\95\ 3ñ4Êì8\ 5áë¶C#årr£ñ®V\95)GíÉmî(D&v\8b_`j¤GÓhþÑ>\82å\91\11\ 6©Úµ©èCúÅ¥õú\8fjdÒNhD÷!\1c3ÜIº:»H\83£\9b\8c\80\89\93J2P}\83ÒS\7f\90tJ©lRã©ô\86ã\9b+\8dÅüeé5Ãõ\vw_ÊìÈ        S°\1f\9fèJ©\ 6¹Ù\ eÓ0\ f\vdJä4÷Ì\94Ý-=6\9c8Wd|ÊÕ´ìÓ;
+a\8a'Úô
+!8tpóµ\eÆi\ 5\8a¡øsjWf°ØéÚMD#\ 6\8b=:<\r'+sÛ,T\ 1ÕÇ\ 2\94¢ P\9b\96\ 6\18â9͸ÕéñG¢-ÔQ85?T\87ÃÑBQõ¹ÂXŨ·0\80\eªÒ7a\87í\ f©§\95\8a
+\93jX\1fj\95zü²J^*\88uÒu¦ö|\8358µ¬Ï²=O\95"¨B\86q:?©'æÒzÁ\4Z%
+Í]Hª·ò*\1c\9ajÔ¡hÓ¹FJ\1e÷AU/ÚZ?ªZ,è8`Uµ\ 1[KÝ\1f-Z=GXe³yçXV½¥\15Õj\15\13\96¨±. \ 6ç1îçªÜ»Xãw\15ì´ØðÕÕCý\ 6\1fÓ\19LÕ¸D\16\10
+«d\1e= Å\8a6u¬\8cí¼h²&\1dªö_Öà\ 5E40qÖi\19\16\15AëW%ác¥u@äz\93j\8dðZk\12     î³Õ@K\v\87\r\eå­ÜkkCpÍô\9c\18\f®Â\1fó\85qE\99]]S¹ª
+UÞs\ 5%EÚ\7fº®ê\1a\1d\8f\ 3°«í«è\80(RåðâàU\82\1fJTy\95¤%{z½\a\19÷Z\16\e6ùÊ£9.í+cí2\84ýÊ?I\ 6ã¿Rìª1\8b¿à"?`çÜ"Í®\8f·;"ý2\80\95Ý=À\b«§÷\96,,_zT\86\0\9eJ\11\82\ f«\9e´\1c\9c\ 6o
+=\93¨}b]\80KP,¶\9aQ\ 4>\1fTÙÁX½¿\8a\92 iìv<  \ 4äØ"õX5\ eø\1dd\ 5%'+\14ÙDÁ\89?É®Ë\1cd\92NVLYï¸>_YP\r®\19\97Å\83\b\85:\98\15£ÌêרÕ4;Ý\9fþ\84\9b\8d\95R\86rÖ?\¹êÎ"\90{6nè«\97+@k?I¶\94Ðö{oJ¢í\97\ 1\84\e-±kùA\926²-­È:äÕ\18<µwØ\f\7fZÓká9©\15%rMò¼]Eª\15Ô\vH»Õ¿ý£\aÔJ¸µ¯l­\8fºV\97\vå¸@º\8e[\11\ 5é×v\9b´\1c\88í#ï@êF¶Ìζ÷ {1m\8b¾\93\1a¯-\8bK1Ámé^Ì\8eàÖ´¼³Y\89N!#\ 1\92\9fna\82ö\19¹[3Ú\80Ä/\QªøíÞ*Ý·A¿1\ 2¸H\85¢ÕaãµH\ 4õ\84ëfó£6ÜTG(`ò,\127?}ùªÅE\81âx5\84\0|\ØHîòÝ:\ 6Y\8drׯ@\80f¹9\90Âêæ\ 5\1a\16s\9d¨ '^sC\99JÈç[\eì\80öN]ÿ\86\fùÊB×\réªLÃÏÌtå\1du\15Ù\1c\8aÕQ\1cz¬®>\ e\82{µ®Âf2_wú±«¯\18\1d´{Å\ 4DÉv»\90     \82¸\9bb\ fTÙÝçÆ#¡zW¯$Jñw\9fz2\ 4ò\fèØÁk\85\8fÈ\84gÚ=âs\94\14í,âÀGÆ\eÑ\1cÂ\9bvJ²¼GeÍËæî\7fÏ­Ó£×Sï\11\ 4õV\95|~òÐw:ÆÓ\16\8a½¹+}.ko\8dgPÒ½6\b\0\ 5úÞ\7f<è75(UÐzáð¾\ 2_ùÎñ%_ ¯Ë\97\8aL\1côm\ 4À§\ 5:<X«ªü\eÐþ\1e\99\11ÄU6ß\v\0\8bI©Ò\1dCþ²oжÀò\87ñ¡Iʾ­g2L\9a¡Â\r*úGp\9a\80ÙU\17©/È¥\ 2\83øÚÑv¨¾?ò}|¸A0/ª¾-Snu8""¡/B\81,\a+¤ýMè»sË]ß\1fôUY«!\ 2÷è\87\8cP\rÐMè|\99\7f:\8c\93_Õù\92WÜá±ê·Y\86Zb\8f`çË\85\9e\85î\1aù\96µ;_»¶©õUÊrâF
+i{À;¾õ}\93çË"¬\93§¯\1aL\ 3@VgÑ\18§¯\0PJ8ùȳ¦/º/   +;óE\9eé\vÄ\9f5ç)/\eÓwmekXÎábú¦\ 2\15\8a\88ÈXD¦ï\9eg8òx\ eK\18\97¶÷η\9aÌêV\9dïEJ\8fÁóÝ!&ö¿4m)\ fð|±¾\1957ö\80ë\1cÏ·p`¦ì\1d©(Ô´gÓÄO\14        0zç\e\848s¹;_â\18ðd=kæ£u¾o-3\a(_¯ü\13\10sƪ|ñÙÇ\88|\ 1bå[Ìá¨äù\82%¬½Å\12åKÕ/s\\9e?c\8e§½¬¥¹ÒtùÓG\10\8a÷æ\9b\1aØ8*_mså17NÔNå\ea\ 3Ùÿû\15\93o5g#´\89ß½\17¿\9e\ 5±&\ 2{->í\ 4bEñ\ 5/\8c\8bç\a\13\9f\ 4EI\bS|õ]¢\b>¢nµâk\8a`\0
+>M¾]Í\91\81ì\98rK\17\rúúOzL}i\v\9cÍ*!9õý\80\97¦ú~Îâ\93Õ\97¬\14`Ðä×<\11­\95H\ 4?¾éïØ­ÃúÖ\1arÊê\9bëàCôýz¦kæK\8fü[\90/\ 4^\116\8aðÃw\ 5»¬\í\0        \10_°r\19\18A!¾x\99Ĥ\9bøºê\1e\8c)\11ß¼\9dö's,\18ñ\95/>¬\81\8e\11_àÂ\1d¡T=\ 4C\11F|#Þ\bÞ\80\11¡\96«\rq`Û0\15Ä·\ 3KÒ©î\88¯^FEa:C|%\0cM!¾á\ 3\1d\ 1\8bøâR.\ f?ñýÛ\9c5ܦ&¾.M>r\85d\16$¾7\e\8e\ 2\9fPN|Í-\91e\88Ô#\1eºâkù×0Ì:ZE\8cjɽ4\81Q\rVU#t$b\87-\a¾\83e\9e\1c\aø\ eK\14f\80o´Ñ:¤Ýµ\87\ e>PI¾½çGyÆiMUÐg\10_.\88à)ÄWÂá¯kä\ 3ñurÒ\9c\ 41iî±zØ\83î\ 5ë%¾\\11ºÊý¤q\7f\17Xs`ò\85Û\94\99É\8atò=ÏE\8cMGM¾\93¯#\ 4Õ±ÔÌÛFô\88\16¸tk\9bÉ\1c\9e\8b\14åÛ\99Ò#E  îʯøF0\94\8aP|×nÒR\18A,Øf=Ú^ÕM*U|õ+Ó\1f²XÅ·ê¼tò­1kpÁ¢ïrzÉä+P/@\88¨R|×}+eòw÷.á¼R@Ià\v+¾M¦\16Ù\8aâ\9bËy@%\85¼°\8aï\99"ÖY\0f\17\98M\895I+¾\ 2¢~\ñÕÓ7\98Ñäû1´Ê*Å\97J4=ðä\8bÝy*¦\9d|ù½@- áq\93¹¸æ:\9c¯\93÷X³}\8cìη\8cÕ-òÎwÛr\95Æ\89\9f¬`
+\ 5ÿ\98mH\ 5Ü\8e\1diÎ×Y\17Û=ÎWÅëVÛ\82\9c/xÅi\892$Éù\1eRf|§ýA\80n\84Éw\94ó\82î/B¯¾\r,+ê<ùB\14\9aèÕKØíìÖ}Ôå\88Îù:nbÐ\85\9cj\9copïíào-¥o¡àwZ_ ù\0   ¤/#\99£Dð\0Æ#      ¥\8fíùhÙ½ÊI\8c­\ 4\1cc¡z5ï¼;Øù\86\ fC\84éÛ2
+\13z}\89$ÌÊ\86ûÒ\1d\8bÁ\82__Í«ªür\86ü£é\97\98¢\93àî÷Nµ\f%\ eÔ×\9aÝ\9a¿e¤âÅ\ 4¤¹_\aó\87\8fa¹ßÇ\10ÁÕ\8aÄöûcð\16Ô¾Iö§\99s]ÆÚ/ùyC^]´§Ú¯\1cÆÆ\87\9c½·_q¹Æ\ f\ 2C\»\95ü\91I¿\17²)\14²\ 3Ü\15~7°r\ 6¾/­¢_QÚ¬§KÑ\aÿÜU\95Êné¼½\15{OÛÚ.\19Ý߯\0\ fùEßçµe÷$Ý\9dAàâ      ùÕ\8b\7fü^åê\ 4 _\98\18\9e\97ñì\17e\82\87Å_z8+àõ÷\7f\88«|\ fâ<îúëÐÄ1ýÛÀdyÛÿf\ e\ 1<yº =Àño3<¼9è8\18°\8c1a
+\81+\bmQ«ÀÙÑÊ`ÏÀ9\ f¼¬Q\85\14Á\12;12\90\85\85QF\80tjÊW°\1fs\f\ 4\83\93\ 2­ÆÌ$\1a|½o\ 4*\ e>:ýÀzðÖ¨Ç\aa*fñlF8TWX©\841\88ÍÏío}\9e5©mnç\1c¶iéÂ\83e\18.Y̰0j82M,ãn8bS­k\18êÆÃ\95`#<?ì1\ egT\10+ó)lu\88\ 5shà­æ¿J\7fÄzRÈ\96w\8b\12\ 5Q\8e\89#\ 3\14_'®\12ÈÝPìð\11l\ 4¦Xú\8fæWÅʶ«\98W\f\9f[\ 2e­Øxõæ,Næ\9c\90.¸xÙ^¬o\vÑ\84ñUý«%\8eq\89ùÉËø\1dh_Ñ\91\82Æ?¥Æç\1d¥Q\95\8d\83Ù\8d\ 5º\bøÄ±²\ 5D\fæ\98\91p?fÝé:1Þ±-EJ\1f\1fÜyÌÓ\87à𱰹Š?ö\92"\14\93\11\1añ\80¬\9c
+ÕÁA\96÷CãBþ\13\8ek(AMJ³d\8aü#úÃÿ\92¶£æ\ e\86\13\9a\10N\8e"'\89®\9d;Sõ!_Vü§Ö Åx\1f2\aô¶XÑ\f\13\ f(\8f,É©×B~rÌ\ fyf$°þð!GL\10ØÖ`I\90Ra\ 6ϧ³\90\11#*\ 3ó!\9bD\915M\v;\19Yh÷ÓéÈ!\97«\9f\1cYqè\95¹UfÊ\91é½\8dtD¾³ãÄ\91½ö\ e:\7fàx\95Ej­;\8eì\0ócâ¢+\12G\1e8\93ºâÈ"\b\8dÂ5ìK\13\0·J´ÉgÁ¾ëðIó 9²2îÎÂ2\9b\a\18
+ÉÏ\9e\92û\8a\0\bÉ+^\1f1ÜÜ\17\92ÓÍæ\8c\vÉé\16\ fù\11E\8a¬j?¿%9\96\14º\19»\ 5,ÉC»§\18a\85xY-{
\ 6Õ²¿\ 5sR\92Inp¨é£9Jrqîyj*\85lqI®\85Q\18X\92uÚ*%Tòå\1d¾X\1fª®\98Ðö5ÙR\88\80ãt\9eI\14n>S\9c\92ϰ'ÒCJîÂËî\ eN\ 4CHÉ\8fíi\1dÁî\89þaL¡×\16»\94\fÏÄiî\\152$%\93Ï&\17^)yDî)\br*))â\ 3l?\1cFx\8b´ö»\90\btJ¾+\83\96Úkèi)Yrh#ø¤äëquù\86ýH(\95\92+-\98Ù\ 2ÉR2\8fÛàqo±ªØRrÆy¡jK¾\8a¶ü\8bÒÅÄ'\12Zg\r\7fF&?Åßj9\99,T5h\8d\9fz®´\90É÷v\b¼;Éäó\ 3ná/I&ã©D´6\99\ 1\97î7\99lr\bh\86+utd²÷\0Òvdrç~Sh\93CÚf¿\93Á\19ID\80òÛmI¢|ø\ 1\94L\99´)[ëÏhIå&
+\8cÐ*gà¥\12ºÍ\14iNj+k©¯¶¥iÕõWF\8biTdù\ 45JEË"\91\92\9f[oàûq\99\ f{MAme;\19\ 3Ò\1e6ê/\9f\99å[\eî\ fÄ\9c4uâÎ\98§ð0´È,\8b\85¼Væð*ħ\99\ 1Ý´EÏ\9cáQù0\9a·\1a\8a?ÍDGs\12kf\aùhP\v:\91ÉE\10ùÓfºàmrs{-`\87_¼»&\83\8f\97\1f\9cS\0\rë\9brΠ\ 2Ñî\9c\ 1¼ýyLç\0YÂ1²B¸3}SÇ\v\82çT@N-|\8aMÏûRÿªWª£)÷¬K/¸ò9õG»ûìü\1a ´\9f]$\r\85ý\9c#\b\bþgM\949\\11è$"hNó¹\93\ 6\1d8m\1d¡±_¼\92\85.\eìù¬¡ó\8f ÅH/~\98#\1dÑyÏ£\85¢µV\ f8gÑ\17Ã\93\7f\16­RËQbôÙù_Ð5\9aNëÅ×h\r@[¬£3SÜS\1d]ª\þ£¿(P"ÍR\81/s\92\9f\8bF\ e©\91M\1aõW9_b~\v\e)}\bÃ\vÏñ<\92Þ÷¤i®ÑS~éÜ¿¤\1f2ýx©Ð75H\12Ц·n\7f\86¤+½a§×\17\85ÿJÔÙÌ\9f\1e.\83ºå½\8f\87\8fbÔiF \f\92\86â\ fþB\10\ 2\81ÃcFGí`ÅÏdRÇVd^^jd(ÃÜK\8dm\ 1\8f\e/5û
+Ãø\ 4\9e\1cºÔ$¾ð\9dB«¥þ@5\89ÚRs\vÇâ¦å\ 1O@©^³IK «\96\9a¿öÄÍ\96Z\90×\90|®Ý8)]\10Æ\ 2Öu}¶Ô|h\\82#0ã\0?\8d\14\\ 1&«Ij:¶,Ø+hIj@DÖ¤·\17|JRÿÀ\875GÿÑ\87¤Î:sá?\ 5Z\99e\8c¤þáÅ&­É0Û\84¤\16Ï©º$u
+ö=æ<i\90ÔtY·Ç5\91æ\v\92Z\9d-n'©µ\85\16ÇÙCw!©wÆË]-µ\12 á\9d¥n¼\82â\12FG\96q¤æVJ=ò      á\8dÔ:G\94LVO$µb\8b©+âº\0\13\92\1a£ÔÂ\8c-µÚ\ 2\88(Ë7KýN\ 3±ç·fI\ 2èËR£ùÔæ\85\96Z\b\1cÁ½¥>Fî.;&%I\9d\9eF÷H­æoNç\9d){\z¤ÞÁ4=;ÆñH=ÉÕ\r@\80«_\97N"µ\97xu¿Ö'XcÔ\92z¿\ 2ZVjpxDf\a宬Ô\16\97'\93¦{[©ÝIuªÓÔôýÛ\13Lm@At\8aéå¥V\98ÓËA\86      \9eï¥~ñ3¨±\1cú±\19o'þÇK\1d\12\82\80%\13%\vd/µ\99[\83l\1a\90-\97\9f\18F\8fV
+m©a\89\ 38\bÒRó\12H&iû²\ 5\8eÔ/\ 5:X:Þ3yè\1aä|\9c\f\8aÔ\12\10?õ7\15\vÜâN'ò\81ì(¹W/p\83ÈìÎr\16©%îRmÍk £vú¡1Ë˨ÿü[\91ßÌ`Ôr\8f\1d°\7f^H\9d\11¥Ö°ËÖ©¥R;Á1\161àG­\9cJû_\92æu<ê\8fÞl´*xÔ>À að¨\832\82µ\13ÕRQw\81!8\9dgÑG¦\f\15u\96\ 4_6TÔO\80\84î>\ 1\18\15õ\12\8cú>\9a=VÔ~ÂV\9a(RQ\87Éjß\81¿®¨¯ßç\8d*\19¦\12ð\ruu>RÙ\eê\9aAy`\ 5V\9f .\9bì»&¨M«Å`\12Ôf@T4aPKP\87~Fí:Ï)Am\13\83ñá34P£B\1e\$¨\aK^\95\17æqIPC1\ 5Î÷P\1e3Pÿ¿zå¼ù\92¡®ó¸q5\19jDÜ{Â\ 4\1f\vø\fuÚy#Æ\9dì½íe¨ÉO
+4¬±\18j\ 5kuW|"á^\9b\ 3u\97üèk \8e\vq\95¡¾ÅÝ\97\8a\1aO\9b\81¶£Þö8;\93\8b\81\7f=\a-¢-L­\8f\15\13pj\ e\88\8f\8eWC\0J\10N\rÈ£¦\ 5b©;c\7f©\1dbdlòRÓ\90YZ\9fó¼h\14/uæÄÈ\96SëVë\81P]¼b\11+Õæí\897\99ªó¹\18ì¹jq\99\97©²øLmeõ/Å»r«#£\0ß»º2ÌÖ)`\1d¦÷eÊ\85k\12°\ e\e¶´Ý\vYL»º`úèý_­\8b$¨H¬ÙË\92r\ f\91¬\8f\ 1\ 1M\9aµù" c´&\95ý\ e¬u¬º v¶\eíøÚº2¬5áµp$:µuZòy2>EF¬5\18\13qÁ©\ 1mýø¥¸Ö
+\83j]¤\\12®fk´\94Þý4[ßà\816·A\85½ÙÚ\1c1\93(ûëö6[³¬Â\94IªõN¬\ 1rX¹&ªõ\19\11Ñ8B\14\ 5ÇP­u`\1f
+\1cZc\8b\ 1I\86Ö\96\99¿L« \1dк\91\18¤\1e\ fÃ\16\94\93d\19´V\9e\0«¦Ö\87ôÛ\95²¦§Ö\80cÅÖWÜ\9fZGX¥Ê;Âh¨µ(Sw\8bõ\ 1ÄÅ¡Ö(Fl\9f83äÇ¢Ö%
+x­Õ`w\91¹Ë2£[`;\aµ¾\8c;ÏZ\86N8ÖPkR\9dü  É\86Z'#@9\1aÛìm¢Ö<]Ì\86aëT\ 1\98ñ\9bäd\v[S¢:ÐÖ9\ 5¶6úà\1a\92Ë©Øú\1cÒ\8aP8þ\87lm\18)1º\19C\97\95ËïrÙºDÖ@¶å\8e\85ÊÖ\16þ!\ 52QV)n¼Û\18oW[ZLfk\ 4ܪ0\e\e6[kÇP\8f·Ö»Äh\ 6}\99îO¢:o\9d®ÚùJ\18\85ç­ëÿ¸àz\ 1BPÞ\1a!\89\98>\98
+ÞÚ¹?ÎÎ\11\8dÁºu\88¤Ã\98qm\r_êÖ¡Î\93¸Á%jl­¯;¤¯[\ f/ZÅÐì£ÐÛò»V-ݺ\15%Ìòñ\11æéX2\?L2k<Dî\8e,\99­èg­}¯{\ 4î\85å:ìfËR×¾] uwÍëzÊîZïÌc<¯IÈtÀ×D-$¬-\19\99!¿Æ0É\1a¿lÁ½èK¶\7fJ«OaÚ-û|)l\19¯©Ãæ%\1fh,#råÌ\81f|±\17í5å\e»\83   ÷~l\92/`íÒ\9f\vq\e\ae/!(5˶ö$)\16\93\87?\9d½4{¶Î\bm­CX\97ýqÄ,míO\9b\8e\99»Ö\0¬JEµrü`m%\14iε#V¸0é\1eìrÈ\9clÛMg@!0¾ÑvëͶ£sB*«Ù\8f TݾÈ|Ó\9c·{Ío+\ 3úº\ 5wÒá\9e\97¶I]ܬÊâù¸í¨yk&·Z{EnÉý4\84\e\96[Z-{hn}\ eÇ
+ÏýÛ¾\18\10Ýæ\ 1\1d\8aMw¦2\ 5\a\1dõ¥Õt|ÝüÍP´\eÙ\ e\ÜM¸\13\10õnö\vÞ(Ð\90ñ\16ë\1c<awmO\ 1uÞv\1cO¥w$³£Zï\7fµ÷WHn\8c\f£_\1eÅàβî:**P\12hu1ë1-\99ì;\91ßXwo3ì·¨\9f\98Ëêo9ÿ»#Å\94~\80Ãàfc\15¼xFà82}A\ 3×R\9dK\82ÃríB¸àüopé\9f½\ e\80puV\12\8e@
+\17Ö|k}ÏmÁô»\f\ 18kÃé\f°­ÃíçÒ¯òYÜ>\94wýûÝù\91M{]ý¶h\bQ<¤SäVq\9c0<ç\96\9c®\ 4#Â8?6`p\8cÓ\9e\88ÆÙáâ«lÚxÓ\14Ç\róÒuüö\9e\9eôy\9cù×vòã­º \9f¿\13ÂÌÍ<¿Èï¨Ú\0H\9e\99çðHɽ2yXÛ`{;y$ÊQ¶uÞ\94\13o\98\ 5Zåx\16\96/¬Ibv5«NÝ\0\1d\80øò¹lC´0oÈ\84\9a\8fùßMè`æ        2\19\81Ð\1cü3WsûI\8bW\ 1^\8d0\9bãènn ÎÕ\91æ¤d@\eC'h\9dËÔ\eÐùÎ\ 5\97²\85\ 6l*欽ãsç±}Y?׫1\b/\ 3úâ\18ô<\15ºêcZïÐ_¼Ìé\83\1e#V\ 4l\18=29úì\90\ eB\96×;\93\9eÐ*\1dD$µÏM}¦ë\87=ôpºåî0\97§\1f\1a\93¯\ 4uãÿ¶ç¢\8e
+       C©\83kûoon;u±W\a\96>\19³\9bêVx   LX\1dò\9e\9c`¹~~1JX\8f%QK/ëØÿ\aß§u ·¾7$xåºX=&r×ñÍu|´×\87\7f½\89\0ëx\84\9dJ#ö\7fýc\86Ò¨\eÙ\13øÝþ\1eá\fé5;\rð\98¨f'é<\9c®>²«S­aÖLRëªDÚ       j\7f»}_åAA\92Ót2¶ë\96\96«ÙvmL\92êvNcÚ5~»ã|à\ 1Äh¸7\1eÇÊÇ=ß>BÀÜ\7fÐ\0±Cw\1eÎÅ\17º\97\82ø\84\1f3©î#ÍîýÁ\ 10ïî[j]¼sQî\13\91!\88øYï6°\15×1²\ f%\vúþð£±ÿáz\ 3rýÝ»ñÏ\1aàiB\8d4\ 3ïNà¿\15\98*4úàm)|÷.Y#Ã\83\82ȯc\87OÑßÞ\ 3UuPÃ]\96Ú\8d\ 5Et\89OdÕ¢\82LO\88\ f8ü!;\8f7\88Ï\94N\88»Ë\aÚ\83xb%\a\8b³´\89Z\ 6ñ\898)\15¢Ø¡TÅü\0*ñòH\a¥\85n4\18\ 4ÝG#R<yd\1d\1cQ\8a\7f        30\8e÷»THj)X³µxÑ\8b\95}
+'>\8b|5\94¡\16\9f\9bÝr\1c²²x²üx
+yM;\²x¼\81¤M -·Ü,þÜ\a6@\8cÏ»\86\86w\8d÷\ 3S\13«ZaõñתþqãÑ\ f\130êÈ_¸äã)\86\ 4ÊÛ_\99\14*ß®e&\1aË7\0hÔº|[\ 3Ôv\98ÿ\18¹üÌ|º\80\92\9fêcØÞ|qô\95ö9¯\82¯SC±óð|H\1e\10<Ù¬R\90,Ð{Ô4b¥'\8f¦\92á¥0¡7ÙycT¢Ï!Ô»\9d£×-é\11\92¡´»ô>\86?\ 5Nßs¡\94&\85 ~$·9©ÔÓPz«©^\8c×Û lá\7f\94\16W¿º_¿¢¬\97\1eßËsëëF\99Ñ\vÞõÿ\ f+
\7fía&(Fûb\7f\88\0 ì¹\1e+vö\8aªCËn\800íåZª¢_{eÌ\93\ 4·\8f¬"á\97k\81ÛKe\ e\84\aÜ¿\15È z\0÷_¯±3¹\1f\12r5È}\90Ä7^í°\7f±èÞü\ 1N¡Ý'\ 4\1d¸ã=Å\ 3Sa½G@\11"1­óûó}\18Çß÷´À_k\aß\10,|A\9açê\81ÿÈTPäݱwmÉø\v¼ã\8bFäãg\90Gmò#ÚÊÇãËWÒßÊÐüIJÙ<Î\87Fôü\ 53è§\8cÑ·\8f*ý(|\0r\b\1eý§q~¨\fìÂ\88ü\82\8d\86\1f¼\9a>\ 5¶ìµ,\1f»b>âfÁÿ\ 5Ó/ûZ\1a\10pÖ¡×\7f¯u\90ë4W²\80\_ß\92\12«3\18&\ 5ɸYc¦ ãº¢Abâ\118\ eÆ)`'N\ f4Pç¢\11ÃWë\9fÚyÆl
+\9b\95\8aÐ\9dÆÉË>ÃöT¸\v\9eX½jÖùª>\82ºzF\7fz\84µ\eÁ´9>®\81i\9aè£õê\89}nF\85\84Éì\86ë3\80f\8d±àÍÚ?§¬p¨\96khY\8fg\a\184\84\9bÿæ©~ñ\9e\17/¥\Âߦò¯~´÷zü\82\83Þ\19º\9bâ\88gYáé\94õ\16@;Ý®\9c1ôí\15\ f\85û]kOýmu\89Zµ\MÎá§uÖ9¹ÓN['ÈzCoõáV\87ìq÷ù\0Ýè2RÅ.±\a\12P½¦õP:\81Ò\ 6Õ»×&BûI¯\80\1eXLÛö\1aL\1c\85\1ccE¨v\83
+Û·"9°\O©S?\f\80Ûà\8fÓ\ e'»'ë\9b\9f\19]¾xß{\12¸å«åÚ\1fkC\9e)\90\8d\ 4¹°¹E\95\19ÿ@Cö½\93L\1fºälÖ\ 6§ä
\ e\11\ 2îÊàÑwv2á\8bG\84\17\9a\86à.çB\8eìBb±a\94Óµ\88n\ 1À\ fR\84\ 1#µëFÂ{ y\1fý\ 6ø\8a\91\83ÿ\b
+9ÓXÔåITßd\rÙ\9eO\10Wà{\ e\9a;\8c\16\90EÍé\9f\1e\1e\84¾&¸ª©¢hê$¤L|$\ 33gboY6\\95ÆÀì§¢xF¤ ,+Ïq$6Â=Ö       é¸\86FëôÌÌ\\17iæÈá\f4+¬YX\ 6K\95ôؤYhO+ê¥sN®\92àÄ"\8dÕÈíØºA\8eÀà\ 3EHu¦xì\13\16\7f>å*k\8a£/Ê£\90psY¥\13\9c^ÖÜ\1d\82uÛ°¨ã\7f±u\ 5¾jÄe7\f!qîZC\0\a\99\b\85\v\9b\19 ¼ñ|DxÒØ\r­¸\ 6\8aÃ#a´xý\19Üa½w\8cÝ\1cSx\viSh¶\1f½lÿ4q\94ŲX¦k\12B+'bLÆSÍ-ù\16æª93ü2ï\ 5|®,\15µ/\9fÅß\vÐ\7f7ç©æ´c\94}\9aðIã\93\1e\16lëm\1a\8aø\eV\90\12õ\145#õ\11Äô§ÜÅJGÓmã¡\ 4ºº5·ß'ßehÔÈ\1eéØÍÅ\ 2\r\7f¢k5\99\8eB×þ­t^Ú\ 6]\fà$Ä#½{8»\7fú´k\97\ 4¥Z4JH5\8b@\9c3ÝRrʳ?âP3\8f @\11\81\ e2\87}ç¼\ 6\18r\1f{eDÓª\89çÕ\99rîÑ$+Ñ¿G\81\98 4Ük\86ÀéÓ\95âÒM \ 1DYDV\88ÜsJvÏÿ\ 5;\ 3<\13é'0\8138hæ(ð\87qh­\18Çl\ùGj\14ºy¹  ¡\99\9b\87ªf;XvfrLɪ¨\81ÏÏËç\1cÀô\1fû?[X\80Á0MC6+çd^Ä\11'\17EÃqÌ\85à®{\8aÜ"   "×ãÓàÉ\81\14cÎs\18\ 3\81T,\ 5²*XóìÐÝëÝ\19ìh§\ f\9b·@ôÞê\19!R\95Ð1t®¨^Í1×\83m\8b4k\82\82À\8aÜ\8e\16è0\8a\19umr-\bå÷FØ«\eX\95\ f\ 1\12êzÆêÁ£z\82\98á¼TRÐý\18qs\90\1d¼â\r`\8cÁ÷Î`Ãé\18¬ßwʰLxm«gç8Ôú\17ÁçØâ*\90\96]\0aw\ 6¿×]%ü{È*TÞ\7f\95\1fëL\e\16m ÜN^ç\98Ê®_êÍ\a§\09¡wÿL:yJ\1ahO­çhiT\ 3­Yj˾\8a¤$½·\e\14ÞL´¹Þ\84\10ÕÄ \7f\93ch\7f°zìY\8a\ 3R\85_\ó¡gA\bEq\92l¨6|+Y¥\82\8aº¦\81ÛÜï òi\18î\a\12¾)(;û±të\¦Ï7g¾á¹\87f=J
\92\7f¡®\ f\99\bÆ\14\82æ\82à±ÐX\8c\83\91º£\11ªBvú\1d'`×)\98\a\9bS\86jû+áQ\11§\92\94fû¹Ñó©ÿee®ç×\91#\84\96\13°æa?t\13\9e\ 5û       æÑö\ f\11<=!8|\13\0ð\15\9doÅO\18óàeS\98×\88Mÿ\0"=ã\95\890DzÆ\82¾®\bÛqò\aKÕ¢[Bmï%\956\8d4\90mâ¸\16\ 2ï\9e\9bØ(¸\1dm\7f¡\94\0\ 4³\1a\au`\r\8f.\eS\8fèâW\82Ò6]Jq \88\9aǦ0ctç\95³²(æü`\94âà´Î\9fÃd§ Z\9d\18\ 2¡÷\93¨\85\a\e[B\80«Q³ìD\96     \0\17䪲u\8f\92\9c\8f\18zwïJ\89W£n\ 5¼rç\19\86Q\er\80²×®çaî5ÝØËSøÍ    ¹\9bX)ñ\avQ1¯Ö\90\e!\7fë§Å~YXñ|DL\ 5      \945\91°ì\8d\1a8\7fC§ûü\98\81\ 2*¹¨a\a\88È\10\8b´Ì\ f\ 5\1fO9¤\99Iu\7f6\96QõSó\90¥,eüçèl?\9cúK     '\8cÆ\1f:\r\82\9e\17±u¿wjÌÔÇ\ 2èÁï\86ÕåÓÇ<Ö\eDH\r9\ 5\ 3;3ZRæ\80ôEágGPy\84$tÔà\9a!\12º\ 6f$vb\anþ|p3Ä\9d\0ÅÞ÷Úo¶2+yC\96º\90\8bÓ\8e§U6\bÃ\11¡\17Ñk\8f¤\1d\17Ç\ 3¸\ 1«Ç\96»ªà\87°ÿǤüºB\98Fô·\94\11¿¼\9a³úo\veÞdg$\86\92¥Ì{ñ\9fÀ[]\ 2\9aåp9Úºb,ݹèó.\ 3n\84\1eËMthÏ*\ e\15\v\13x0lu¼º64˪®9åô\ f\8aÀBºäÈ*EÌ+\84w'FY#U¢TT\95È!É6¿\ 5H\0\93YTvÀA\9e\1dó?¦¡½
+û4®\0ö£V\ e[õÈ\96[\1a\r\8c~#°K«|%Ä5Ã6c# Ð\81õòù\91\ 2X.\7föOä\b\ 3#        9Ic\8cè+\ 4ʼ~wÕ\88ê\e\83Ö|HÎ{×\ 5¹'ù]qQ`ÿûr?IÉ\16eÿ\14\9f¯\91\1cø\87\15<\85\7fF\10ð8P½í²ìm5\86$cü\\93M\99_\0\11ÿx\97\v\85°\85lwQ9S\9fþ¼¨\f¥\ 45ÄZÏ/@¨u\8ehÚÝÜq3\0\ 1â\ 5\ f»\8eÙ¥q\85¼!\12h,ܧô\9b"þhè2¨\14ˬ\12ê\ 2é¾0ÖjK\95<þÂ3Øk\92ð(\97\b\977\8evÊ\\9atZÖ`ö        \ 6ú¾½\82\85>Âaë\99MÞT\ 2\93°é\98r\87\9fÑ2© ¹¥0TÖÄã4\96J\8e\93\9a\1fð¾ÁÍw7ÕWXÕ3[\0
+
+öÙ^Aê\19\eý¢.b\8c2×ÝãåÈ\a%¡×aÈzÍ\91\90\1c\9e\12h\85\ 1q\19E]!áò\ 1¿Áò\ 6\ 6r\8eø\8aQàjrj·\15*u2Æ\8cA.\ea\18*]A*\ 3\18T2\ 6Å9Ôi\91"tC{\80\90\ 1\95Û\ 3w"\84ñ\96ê!¹ô\ 4¥X\10\8c!|\17fVP\18\89N\18°+¿ÏÎÎ\11z×È>A\92ê*^:ük<>³mYü< VÞ\8e§hÔ#+y\1câLáØSwªøka\82=\89\9f\ et\8e\12¾,O\14á\eD\94OÍjCÇ\898qn c|}\9dZu\1f\97Ò@Ã\15ÒA;´\13Öy\0ÖÚÀú9±\1d|\94\12eQ\96!@\ 6\99ö%î½wµÙã\9cY\19;%[²S.»éL0Æq^î\8b¡æ\8c}ÆÌ\96|F(HÏA\11q5´ó\ 4­f\11ṬÂ\83GçSÂ\18Üñ51\88ÞKµ¨ôþÜ\9e;Ü@h\83Wt\86©o±\1c0r±.;}æè\9b¬±ÔÍ\15±\fz±*\85\ft\99@Dîª%\1a]÷Ä\92Ö\98\ 6Òñ\7fÙÎìT:=L\88Gâ=L4n¯á«\92{¶yzªÿ\18\ f\94ð*%\7f\94¥óäÌðº\ f¦9ixô\97üHr\8dJË@Ï|\b£1\89ðR\1dÆA¬I·\ f ´½D&×ãË\96S  Å:­$ÊAÆÄI¨\8f\8eý¬ú°wPÀÅ\1f\ 1«è\fÚ1!wµÃ]¤eH\19H2x±4^"g¤\ fI\9bë#â=±èÍ*vD³\91_Ø<ê¶^þE        \5øSZP\96wͬ`8\7fð\130ÞÁ*$Ü\8aå²Ä5ù¸\10±G\95\9eÃräTþ\1f\91w5#Þ¨\94,M\ 2\1cÕ\8cþ\8b³\8aè³ÆþiéBÅ\96^Nò¹¾cH8±I8Æ\9cw\e\1c rD\11¡\91q\13\92­ÜÅBïsé\17aÁÒê\eXB,*ìyl\11I\84ظâc8x6æ´C²·ËêÌ\96ù\19´\13#\10ÉùB\ eä\e-M&Hb\8df%\98ê@s\89)\82µ\fô]ÜùZJ\9f¾\17Ö!Û\15Üí\ fR\9eçH\ 2\87ÔH\fº=       l\8d\80ÚM\91ÏlC1Ð\80*\823²±£ªÁ1\80AF\9b½bfÃd\øð\90¾\e¬t±ÁC£\892T¿Ë\87t`Á\7f\0\7fq\81»\9f\10\8e  Æ§\ e N²|¤\12\8d\11D0s·\91p4P_ZVÉ\17å*zF6&v\ fÚ\84dÒ¢³IÅE¥?Þ\81v\ 2Ê(Mz\84ó\85l_\f\80ê7\85Éí0\12\9b\89µ\90YÚZ\ 6#d#æy\92\b\98.\90\9c¹&ÌÊÝ.y\81TÌE=²1%ûÈXFX\0éO(uj\85o»XwQs&ï÷QüËëj\98>\83\9bpH8\11ØV©\9eº"ínëÊ\ 6';\b\91«\90Ú%\84úó\0©JÅAs\8e¢e}£«Ñ˨,\90·6QGÑ\ 5\8eÎp\86¯\1aý\8dGÑß\8e\88\1fo\1142A\16Y*´ ù\9aE>5æ¼a\8c\80çʳeèÜ\989\88Í=\80ò&y\10ò\18\92\85\e\9cÃ:\19¤K©¶F/§×\17\vV\ f½órñÜæm\88\13Gò¤±(\8b^\96¬êÎÓ:bV"\88\88\87ÔÞêIF1\1fÎ\18\89|íb\9cÁ\ 5\13´¡¹E¢B0_sVm6÷ª%Dùý\r¸\83\14-['D¯=òB\bî[\84V4½Ý\82øôP·#u\ 6àZ\a×Ðwi§Ü\ e¸\aÖ\9ed`Ä\8b\15äkw{ùÇè\8f#yà\1aæ2×\1da\vä]\ 26H\85Æ #\9a(uD\ 5\82ç\ 3\1f\ 3á\80Øa\14\83\94)\ 3c\9f\1d¸ ±YæóF\ 2%1\ 2^\ eþÃ\8eü\80\v&k\fF£¸Ü/\9aU\11ð¤±/q¤s]T¢#T4\98\92\17\12\8eS\93\13\91,\83ñ\r\9d$1\aÍ\1e\9b
+©$\1eól\8bXÂUÚ8@\v\9e\1c\9e(\13\94\14Û¬A9ÀröiØì´±&\99\r\80\ 3\19ÍÅ"Ç×õ½I\93\ e\bçj\13_KÕe&\1c\86òñuN Ò\1cFÉoIÆ\15ÁL\ 6úWÂ\bã\14ØöÔà\7fHôò\17¤ÔE"è\8bu#Cüþí²ÞÌ¢U\1a\13[a\93M\1aòy\16\86-ª¿\88~\1a®ò²í¢ë\rnG\1aó$ÂJ0²ä\9e`t\8c(âË\15fh4n\ 39­ß\ 59/\82ènz~¸«¢\02.ü\96õ¬\9d*òªÊPÂh\7f\8d\9d\19~t\ 1\11Q\14\17"CuúÇ\ 2\92»u\8b­Û\89\8dII\9aô\8f\1d£Daìs¥\8e\r\81Ùõ\80\11Ý\9deQ徺\98\ 5ÕÞC\98à°Ézx\1a%ìmt\84¸Á@×Í\0ã¦Z+C£d7@\e\Ïâ@«P}¬ûÖ¥\1eS\13\85¾<\9d\\r´\87?\13Ƕ\87\8aÆ÷"\85\ 3<{õ\ e\ve\1e¸ñµ7Y~ü­ì\19Ìë¾¹7À°   \18ýe¹Eä# ÝÜB3ÎÙ\96fpïW\9b\84@àR\9b{Eg#Ó&G\94\10S5\r\ 1\986\aj\1cwWPìØgÈ`\rB|¶"\90µþ\1d\8dæÍ¹Æ@I\88D.ÂT
+R½^1¡\-\bÉ\e\ eºv\ 3¦\93ül\9cÿ/w\fR\1eÁpEB³ \aÊ\94"I¤àA¢õÕ4Ç\9d!\99å}H\8e\91\ 2%\1a!#8\80'1±ø\9f\ 2ý:7/Æ\8fÄVìJWr8\99ÒH\r¾üÞp°¢\¹ÉVÕ\b/ö~\ 3K]AÒßðz\ f a#\87\17Ç$!\80ê\9b\9a=6â\ 1     Î\ 1#\e 2ä# \93J-ñÅ7G\80F$'\82\v\12°r\91!$T{¦òW+dÇ\11ñ;(~Ü$\93¾LÂ\1f!Ƽ\83TÉÅe­\93cR,\86æ\8a\b"us¿­4£Ê
+\13\ 6qùa6Rf¢\0\9eö\7f\92È\84\9aW<ó\8dd\89°À^
+%¼\19\18ãÙ
+\8a"ÂED\88®\ 4¯¬Âaæ\e\98øQ\16¦\9ao\1e%Wä\90\v5¿p\8e\82iBo\r\ eª\9e)\ eg­â\8b'\1d\1fË\v\81\ eb\7f\f\ 3sâ<¼gNß­]n\1e-Öµ\ 4\eµRú\v\12>7»\ 5ÄFêb\9d½\10 µYOÕ\ 1É\9c\18\85Û)ü\0(zydÙµ-ûÀ0\12£\14¡ýФB¾;÷Åôè\ 5Ôå\f÷\93Ê_õÍ%\87ä@\126ÃÊ\9fx*\eèc²\fc\a\81H\14ê,î\1d\ 3¢Ú¹\a òBªf\94ùîÊ\19å\ e\8cÊþÊ/\\ 3\88\86Ré©þ|q\1cÔ°Z\15y\1fRyü\83\90´Ðm\87¿s\12WäÆt0\82\9b\94ìcP\ f\ 6!=
+¢ZǨ7Ð\7f+§Ñë²1(p0Öô\12M\85o¹cª÷-¼\8e)\19¬}N¡\11J=û]d\7fP\ 2\9fOøAÛT\12¤ð+¿Ñ¼Ì*¨\98\98T\vJ\1a\97\84\0gé½;\f\b\ f\81.\9fÀ\ 1F{\b^ïMÏ\92ß\87\83e\fí³1iÛ-¶,¢\ 3Ñ\1fC\91@\13\e?\1aÿn\v¦æiÑY8Ø\19GjØ\11\9b@ZTX\\v/È^W\ 4î\9a\82u\8c=\v×\aŦ'G!K\8eÈÄ.jøn{\14
+c\95\14\7f¢\ 3Òh#\14\97ÙÓ¡Á\14¤Å\ f\8aR\96DèXsdÐ_-;}!:~·ö¯\98±\b\ 1e\88²7b\ 2\84¾\98K³îû=»ï.\84Ì\9d\8eë&#{¨Ñ\ÑAYõ§ñ/·\1c¥:g\99\9fÊû\93\7fa\ 5³\8f\ 4wD\1c\14./G\ 6\9e\9fª\16ýfQ\91ñûJ\r \97Lºû}O\92I,¨Ï4çÊ`Sf\86\ f\b6\92&\83Gg\9f\16ó¦vn\81ùÅeúô\90ú[\9eé_Á¨-\1d\rÄÃû\17:X¯\15p`ë)°6
+Ý@Ôì^eÍÎôw \87þ\84\8f'\r\9d8\ 5\foï_\8f|Óß\96
+n*ð{a²R\14\94ØÊ\8a¸øý¿8øÉ\8e='\ 4\89*}\f"\81qÞYQ³\92¦à\13\88¼r~ô ÷0ÍÑÉ3SÇ\92ÙÃ7
+\1e\18Á2\82\ 4í}ÇN\94ª*kì0Ýï±È 5?0I\9a\ 5
+\89É+Ç*<Ú½,\8a\13\1cT¯l,¿Æí¡vs:â\93ØÃ#zÑ¡ªU'\8c¸´{¤Ö\92\13\1e¦\85\ 1\8c\12×cä\9bêýÀÂ#&\81\80ñ÷RÍ\ 2BÔ¸ì2â«\v\1d\9c©TèÎ(ãRfK\b\ e\99}q?ÎS}\11S-(r\aÁ
\a¿£¼JM\8a?Uie>\87-:ãìéb¶\b7\ 6ÍË\8aCÏ}'\8d\aÁ¶Ì&¹VÝ\16    \81°¼í`\ 4\ 4Æ8ÞB\8bÁ\1dC\ 4}\1dT\92>\13_\ f\ 2\82\ e\9apÇl\1f\99F\90g\0\13ä\11\96zªÎ\9f\8fä\18\80[·0bZ²\1aõú\18­\89äp\98\9e\98¼E.%«×\953]%9\86êé\rI¨8\8d¾5ô).äLuÍü¦³\9c\rX\f­ù7\8fÑÆº©Ì½_ÊÆ&KoydßAµAUJðq\9b©w ¯\ fÁÌ«RN\99ÀÁð­A\88s\82°ºÃ`\8fc\89ü fõp\97y:ÿì\8f\1em
\ 4æ-JDNì$Û7\ 4@\e$\19\ 2\19ÅÃýÂ\89ÂwÁ\92TD­»5Ð\97L?Ú\ e\14\b  v\17Ìé\98\97¶¿ÝFNe+\96Ú¦À\ 59ïàV4\vss«ý¹½\0\9b¦Ïn¢\84;
\93¹-q9yZ¶lÏc\95ì\96\84\94/\ 3\94-ÌfU\85\9a\84§U;\ayp1±m\90j%hÝM\8d\86ðÑ\9dO(\8b\12\86\12\vt\0ØzWýëÿw-.\14âÚy\8b»-qR\93V {\80\ 3$säÌ\92GÄ÷BO.Q\96u<7\7f 1Y\ fü©dUv|×me\9bG\ 5ðÝ?Ü­OÓì-ôbÔV\9f(0Ñ׸i¤Ìe®xÛO\9b̪ÃìG\ 3\17\99±~\g©:\894sÚÍ«\aeV üw\8aGY5!âV\97\ e´\avaS\86~Eô\r\0\99½@\12µÆØ|%\ryÃ÷zPÁêºóéþD6O-eä~\91Ù\ 6¸\e\89^þ­zª¥4õq\e\9el\r\ e!eg\80årß8ÙÉ+\f\1au²®³}k\ 1\9d\17S\15=Ac]·+²5GÏ\86Ô¢RÃÿ2hø\11f\16é\f\Àñ·â¥tpòÕ£èå5Tϵ\18z*û\ 67tÃ\rxÕs0\83»\83LQ]É5\ 4\0\91\15ù\12\ 5I\11îÕm\ 5}\8fáê\8a\ 1Ëv\99ë)\8c³GUðÙ_Q®¥Àd&Ai
+ Õ/ùóF\89¢ª\12.ËL\86:\84¶Æ\12h\8fE·¸ÑZ¸\16\103«Vú\95\ f§ÁX¦#\95\81Ó1[¬h,\83Nh\7fITØÕŸÕ\ 2ç©\84\rÙë7ÑüÜÝNGѶ©Ïvh\rfnâªgæþ`½\92¼þ\95éþBo\80g\11Æn«      b\ 4ª÷*\94\85\97²Ó`XÖv\17\87«J\14\8d¤«þ\1a6FÁG\ 4É9Þ¿\e×H\1a¡Ì\8d8ÀD\95!Õí²úVÂ\90ÍÀ\95RLÌ^VXÍc\fã~\12Û¢\84\93\18\10l\8c4ëp+}nÙÍæ¥§TZå\bå\87¯Äl\v_4\894>¼\96ò<­\98ô\99P\90O©ÃN¹i \98\ 2c¤)É\1fhª0\88>cô|Ú¬z͵\87ºônU©$q\1eH\10cT {ß,É\ 21ôÉ-%ä8\88¡ðbÁ\9440kç"\ 6\83Y\94\17\85Ʋ·»\9aõú'j5½\8eê{\ 6q"r\84Çt0\88}\97õS    \9a X»\83µ\8a\16L\a­\86£N\vO5\93Æ\84\12\9f½/å\13l|­lOX\92Aðt¥¦ã\14>°¶$\9d´õíy\ 1 \10HgÐ\99(ãqç]://y]Y§Ð\18Y\17[\89­¢\8d\8fÕóA\9d\aÿ¢^¬v
\97â­ÃÄé\86d\95øGAæÅ¥ÔË\88¹¬5\89\9e*çÝN4\97´äKÈÜ\ 20{\99\rÆ\13ºªt¬Zâç¬Àa\ 6ºÕ®ÚÝH   XI²¢\92\89×Þ¤Q\e\vû   \85&¬ÔSQQãA\97!½¿Èol¦xðJ9\92\8d\19\1fij&\ 4CT's/a\1a\aj\93Ñ\9eR\9bh\9e\bI-¦3+
+ëà\8dqONQøÿÈrÓí\búå»ÄÀ9\9f\88­éÄî\ 4ô\93S¦ÅÍ\18x;\84x3\19±\99`Þ9W%O,AéÛ)º¹\18\98ml\16)\12ô/\9dßñ\ 2\b\10¢ñ\13µµÎ¯\18Èî\1a!\\ví´­\0V\9eï§\ 5hÕÄtW\1d·\8e:ÂR÷ñI_\rºÔ&\93º\8c\ e¹F« Ù\10F\814t8ÑÚ ªÈ\1f¬àù\9d¬\ 6Fóç@\11fÂ%\85\1f\84V4\10"\fÚdöÆ\9d0b/ª V-§r9¤ ¸[·¹6:®\97\84\88<D\16«ïÌÙ¡¾¦v\8d\11÷k\f]8\ 4ù\90îêǤRæV2O\97åLÉÍ®f\1dê\1cÎCÌlß«\95æ\81\11(ª|ª¢¥hðE«\11T·Ø_êÆ\ 4H\91d\99!\ 3\118÷ÏEÔ\8f^GÜ&öäs:Tu\ 4Ö*ë=t\1dÛ}fÉ\9e\ 4é\86j¾«E!\14rx\ 4ì7e)\988?4´/¿êª¬\80H²Ê\82IÊ÷\82\bb\ 1\80.ù¨å èKØÏº\86\13\89I\80\18\98\91\v\847\ 6Ó\80ðÌ,\ 4d¨JF\rà¯\ 6}+\1aò\90gT*bË*\97qóµ~Oë_\92¡\93\9e§\9f©­þ\15\16&æRnÂ\9a4\84ÅåüÒ¡.G\89l©Ve&\14\90ê°N\0L¬G\7f(\12­úÇfñËyÛ¥p¤Ò³I\ 2vþk\füO²AòÕ\95b\92
+\92u\8bt?1Ë"þ\9fmÊ;`¡ß/\8b°(\ fUâР      ö\v- êÕ\99\7fN\bÏô\12#\95®@âËÀ\a¼\84\ 3 F\98¬oBzåÖ«þ74¸"¶\12ô\88sy¯u\f\9d\r0\8ew\13ø\9d\84*~-ÊÒc\e\87\rN§VZ;EkÀT\8fnIÊ\16ÖÄß\85ÀA%8\17C´H?w\18 +\ 1\ e\16EHÔ\88\9c(\1c\80x\85jëòN]c½øz\ 2 ~Y©\eº%8Â\8a\9bÚéÃ}¨\95\ 2\0Khü\15\ 6í\9bOz\94øiÓ\1a<OgôÎ\8e\8bðû\86Ïg¹\82kã_@\ 4\9dh¥é=\1f\9dù\1f\8aäÖ¹A\15$P2è¹÷@ÓÅ\92*\aÊ¡\8b8\93ÑN IVå\8fS\vâ¶2!^R%KÑÙ   ÆÐæ\82oÖØKدÎ\93\92)Æ~\90\0%\r\0ƹ\82?úbZ\82g\08!¼\18©ëKô®vìbsjd®Ùdé\\aj¡}»ÉNa\1f,\ f\9e·A\9d®O¸-\84jçñ3 \8f\80q\bÜ4-\96f¥×z%gÁAJ¥|>ÙUQw\91Hª°\ 5ToUè~\ 3?fdÝÿÒ7\94\1d@rýÐo©ðË\9a\92ù|v\98´Ñ\82\15O+òÝLÊ·¥oÎ.\90nx*ä\97\19,3FÁ \ 4Ñ\b³ã\12\17à=\eæ£Lé V<µCJSÚC'ÈD3\9c^\94\rþ\9cl2e82Ñ\95n\8c\82\0±EV\10ÈÔ5Þ\b\11U\93{¾è,αvÂl\9f\9bòG'ùÀ´¨$\9d\³ø-_\99q/e'è\82slf?¡\96$\ 5\92\83\ 11ê%5cÕ\84\93Ù\1d\9d®-|ßÉÿ\85ÏêÙ§Þ«ZàÓGhÆqKî\1dN;ù²\87vE       ç\84\8d×    »Þ\1aìÞ\8b,FÖ:E\98D¤:NÜ$A\16\98JDÛRcõ\87ìôf\ e¨oï\16sz°ÀTüÛÌþC]@\8b~÷t
+Ï[Æ\85\1aXU;$²\92Ö\97\91\1a\8e\aM.­ÞåÓ.Ã\98\94­D\a\0è\ 6\17²ÿÑ#\83\b¸»\1eVJq[Sò±w\8fR6\9a4ãLx\ 3\15ûËÄþ\8bo·íô.Þ\17ëcWn\r¢¿ù¾ñPÊ\11\01\11D4\91\9aó0<Øa£59Ê¥`×M:!Q\8e5Ê{\1cÞ&\17ð ã.NÑLùóÅ÷§¤*¥FôÓ&c\b\fë]2\9b·®²G\ e³qÿ­Èe¤?^"bK¡[\ 4\9f\89Boîé\15Øh\92Ù\ 3IÝ0O\8aè8\0f3ÇÑ1oë\1cb5Ä\141°Íÿ4¾b\7fCKkcx*\a6-ü\r½\7fS·HDÒÍ\81È\97p=åv"ãò\b\ 2\f@ï}þ\e\0Ñ\a!Û»\19©ÝÛÀaµn\9c.\6Q{Í\92Ç\8aV\84)\85 \89ÑÚB\a{\92L£¦±gãÞ7©Y\85\rxJ_\ 4Øð\8bô
+\9b
+¤BÑÄ\ 2t\8e\ 4aÖWï\fݲY\ f\94tHñ)\93;\87\11t­úïy~\eO\9aÃý\0gU &ÙÂ%\ 6µì\831´F\ 5!\983ë      \86\85tô^DÎuJRí2\9c¯Î»5íÍN\9dW\89°ëÝ0õÜ\87Åá\r\92Lqe_?ó¡\10·c&?Ç\82Ç\87ÿY\8fЩü»³\93Y\8b\0v\ 5^3ò\85g)#:§4q\8d\1a5È+8\10¡fxA÷\936A\11Hüÿ1¬nH´
+#ù\92-³×¹\16Õ^b16KÐ\87\91G^Ý\80 \9a{\a\11ÓNÕ$5rß    Ìb;\16\ 59\vrÀbF\1c&\12\ 1¡k´      ­+ðz\7f\8b*|ùf\17<Îßoþq\9eé¦\rX\83ï\8aÆ©­\8f¢*#I\±Ê[\ 5õ\e5?\0î\19HBä\8c"I?\14S3ºÚ¿T\80\8e«\90\83\a\1d©â\87TóÎÚnÚ8T7Æ\ví"s\ f½\16¥RùùïÈ\8e\80à\bp\8b&ZêñU\94´v\94¥\v\86\80eXÈ\1d[½"\92T¢Áÿê\83ÑF\1aô\9f\80!E\95ì\ 5ì§ÅÔ\rÃzi\12ý2ûÓ\ e\82\azU£øSG\85\97»æ#È\7f\ 3¬`\e\0;í;5\99\95C-\0Ý\84¶Ô\ fÖÅJ9¤J8       á\8f÷?§\96\96vÒ+ØDµh\92q\9c6\ 1ZÙ}?$Óq'\16ç%\11Q\12\8cH{\92®NXÌCX\16ðáe\8d{&lb\9bø+{\93N\94=\96ú9]µ£\88§À½b"Vøê\8dWoy±ò\9dn8;\13æ§?\1f&y¬x¤þ$ý½\1e-\902Á>\97\80÷\7f´R­\16íÒcJ;ë§\f-\ 2$T\89ìþR=;\9b¥4<­¤M\9a\1fhME,¹\ 52Û2æ\8fE¥þá1|Ê\11lr\17\91&7\7fU\ ez\ f\ 2\13\8a¿\9fÄ!Ê\15\f\80I\97Òcñ!Z³ïÖd\85\13Ç'£$×\9d9\vôÿõD;³>=ò\95É\10ÿ\\9ab¸Ær\9f\91«0©|\95 ¤\ e\e\94x\ e\v¾Q\b\18\82A3üÑe\83\94ä\1f\82Ìóå\8c¨\99#Üf]\a#\8eÁ;0oåÚ@\9f\1d\95\ñ¼\8c¡\12\ 2\1d^\f\1d\rJcú\8fL`h\9a\90¥\82rà¦\rK¼wÄZa\9d\a´\92$µa\1a\8a\0)±nâª=pH¦Ø"Q\15ëûv(Ò0õ\v\92}\9cºSù\93Z<ÿ\e>
+òå#ì7¾ (\88(^ض÷\8bôªzV®\9aøu\12¼\10\86OB+Ù\12áf¾ÅðA\93Ò\88ü~Aõ\ eÈ<Çìxõ\93kýÜ¡ç1Ô_L\84þªPÊ¥u  \8cç\95&¿7'\134Ê÷9\1eE\17\94\ 5t©<©ñÏj/j?ø£þu\ e:^4   ?ØÅ\10sô¼³{;ØDÉý\ 2\ eSU{A\19NÑììÏ×ÙÍ\18Ð~\r\ 1uTõ[\1dÖqeñiR\a.¾¶\1cmt§\89Úé¡\84À9j½ç\ f\10î\89^\92\b¡S\10zWJ\89g#&\9b]ëO\ 2®=ªí¹Ô¦õüÆ\88·\8bX\b-^í\11N5¨]\81_îw¬÷ölè|\11Î÷âö\16`*Ë1ãÉ1AMæ\81ª\16\86æW>¨ÔÞmt\ 1mmzoTã55­\ 5\9d\14õC\9e\16\16\15M\82¨Ó¯Uî\97¬\92\8f²bc\92:\8cÛ\95/¥'¦*Cå\16\18>\12\17[a]öi\94zÕ¦}=\9f9äÛ<#®\rpçífÏ´(«výYî=R¦\1cÌÜX\8f\99\1a÷\9e@ë<\a\84\ 1ÐÄq=ö_
+º¡Àü7¿zä5wo\12\0µÉ\rÖ],\ 4\17Æà2× åÕî\81\9c\81\ 5ÿ\8eÑÁaiSuK\10{Ü,\ 2ppr?%\84\8a²`¾^§uØ\93r{ë\v\88¡%\18\88(Í lAçZ?õ\91e/\12z1$w\90\b1Ä4\9c Û\1eÎ\83_?TưÛoàg'    ¹m\8dÜ\94\99\88g0\89÷¢\19\91j\8dRE\16½èÐ\ 2«Ùß\85ý;K¶@ô\89pzjQ¸i\8e©o½\12áeYWã¤>Ä:ÛM\Ó\83\98+\14\13\0+x\b_ã´ ç \85Ë\91\9fXJ¼Ø³ÒÕCC¸\8f    !HÉLïö\83ôÑ\83Mpg\18êÂ_MM5\7f4\b\8aPëÖiÇMã3\rãL0\v@ÊÂΣ\95¶Ñ\92Ó\ 4Ö0¿hìO©\1f]¹µ\r\90\81åra       `¶·M\r\12ÿÏ\ 4\17s=U'À\13Á~\8e\92\83ûïXÑMÕÓá<KnÖ±R?¿¤3Ò\ f÷7°\ 25q\1fh\9d\84ý\ 1þ\e¥Ë'@1\0\15ÕE\95£\92ª\90\ fûéA\16èé\9b\82ÀIQ&\9cXz\17\96\15\82±­¬\19Z)\87\95¼«\94Å*\1fRE\8dS©ú   Òö\97¿/\90\8fúRS\1ex¾Ðü\87/¿DF\17e\8aì\ 6a}\ 5\11Þ\ 6¢V\11qsÎà HÇ\14§:íÁð\87»\ 2\82Ñ@[|\82
+\fÊüÿ%ñH¹Ñvù¶¤î\84pe\0\v¼ð\ 3î­º)\1d\ e\85J`\8d\82ëN\90ê*H
+x[6ò$U"aê)ñom\ 1\89\14ðòH\9cÅ\9d±¼\1afy¤LKþ\ eS¾u¹M1\82ðÅ\91ry¯\r \9a\ 4\,õ/ùtUí>\16»H\92\84srX¡        ôa\18̯\97\1c.\9d\1e5ñªêµè\94cXë¿\9bC        FöÜ\95ý\8aþ×ÌÇú¨yrÎc¯\15æ¨À\ 2\ 4³\91w\1cÕJ\v´ï@
+\ 6ÑØ9RóvúÏèy\9f\ 3U<\90*\1c\7f\80ëÆÿ6àä\91Ãl"`\97¿SéµÛ\92|\t    ]N¸\9f¨cy­6i¢\ 5\90VÉë\8e¶Ã×Ëżª7\ f\86_zy1×\17ª¯ãH\15ÇUÃ\89®\92\ e¿\85é-¡÷áÐíø\86È\e\86r_(\94Ô>p\17òá1Ü\0Ê\ðá\ 2]ðçöB·Ò\9e+\98ç¾;\93È×\99\85v\96D\9d5%¨Î^W7gy\8c³Î\9b\83b;ÕÜð\12\9dø§²¨=í·b6é\aON~\8a\\8ajùÏÚ­LÅ\eýPß\16{4ùë1!,¶9EEþ\17½®
+\8e¢ÿ}\14\91\95«âw=þpñìˤo\ eZ\85ÐÜÄ}7\94ÓÇ\85Ã>\16Èr^ºE-Éc{ñú\ fÞ3ï\80\90»T#Z¼\88.GüD\92ê$}-\ 5-¦L4Á X`\18­\fð\b\16,\96¾µ?å%\ 4\97\9b?\88\ 1<G;pZ\93\91\9c~\87\8cNæ6\9aë\ 6K>#\9a\9e\7fO±XßöñHÁ¼Ø¢¯B\87v#\95h{F\90´\11þ\ 5¬Õ6\92ó\ 1sÏÂ\7f\81\87­Ü\8d\94Xª¦4u5Ä\82í9v¸rÊ¥\v\8aõ!G\81b*\974¤Q\8bqÐê\8bÙR\92Ã\1eP).tþ\1fLÛ·CÂ\19®uÊ[á_\98ßO3H­?²ÝǦéøÚ7\ 2ª\19\13¼¨Ë\16\19\94¥aÄ\87\ f\11p\86©²?­\92#\95ß©j\8fªý«üæ¡î2iÈo\90\ 5ÑØr!2æ\12e\8dv\f\93\99à\92>+¼\19G\8d°¿\87+\84\15\ 5¥Eðêø¨ÑÄíjã\ 5ÍÔÿ¦\b¢^Ú-¸¤÷ý>Y²\ 3Ëh\ 3    bÊye\rþíϯڬô\98øL§\84\ 5@4ü51¡­[Iµ÷\95Ï\b2\0FTI ÏÆ7¿Tr#éöJO\94*7GÚ\8fð;'k¼\88\a\9aè\8fÆÕÈKR±þ\15]1*°þÿG<Å/2\8a\1f\7f±?\9føßûzF\1e^\9fF\15\7f6?@ô#\11\13\15\1ey¯?©¦`¼»\8f\1cM)W¡YW\ 6\96ª\94¯ÂÒª:¬Ô7ÚW©Z½M FnßÍðÒoø\ºÇ¾;        ëãÿCêö·o\7fÁ"\85\8fõRsÚèw\ fC\ 4ä\92¿ªì`é-S[ÏI\eè\86\92TÅ­°\9eÙJ\95ÐýÁÔ\1a\93g\97Ùåß\9bò.»¶,\ 4\7fG\96\18\9e\90ë\86\84ÜÑ"¡\9632£ø\9a>\18ùõ«áJ\8c¡¹C\ eÿ\a   3d¾\82ìKø¼\7fΩn¾6z\95£L\98\92+Ñ£ñgY\ 6\9d\9aR\98\ fL¤ìL´çu\rí«0íK3ý\ 3\9c\95\7fÚ\83s\8e\86S¦ï\98¶ë®\900R\98t\86×Ã\1a£k"ÙÛïq?    \98ÿ§°zM=\b©\ 6¯ï\80ûn\9aG\ 2þ!ïíüË83\99\97ãå×$YH      ¿tH\ 4ü\17?(&\10\ 2U\ fÑÊ\0Òñ2Ìá\10k~qÖ\83JwIÿþwT¬(\92x¤ãß\90\13\15á)í\ eh\85\17Íÿ÷\1e\8eÇøÆÆ9\b\10\¹òÁqÌ\8ag\rt\82\12Ö\7fò\8d*å@\b\9e
+þjMºW­·ß·\86\ 2òþþ.[²\7f\1eÇ\9aü\12ê?¿ÓÛõÏFÿçÈ;ÿ\ 1tf\ 2J8é,-ð¨f$\ 6\11ªFk¡;¥\84\11¿´]Ï\ 1â\8eq\ efF*Æ( ¤¤$é.¡, Gô0,z&ò\12°\ 2T\ 2g\ 2\87\85v9µ\1f<ZÅÁZÐ)=Í£­5[Ý_¨ô"«ñÇvY\89\86Ä\82\9aÔ|Kc÷$\97\95bÚlKI\9d\8b\8b\93\95\88z\858YTDµ\98Du{\93DNÅ!òÖ(*)N\96ÚM¥aæ\7fÏI¬DC\82Á¾Ñ»ÚÍÝѤRC\1cŲ\8d\9a^¢!±`\9f\86<«¨cÛ\86\g³ãi®eN-Õb¢3qG+¿°\97fÇÞ³ÙÚYM4$\16ènÐk{°\ 6\11÷öi\98FC÷¤Á##\1e7¿©´\93\96zfû3ó\7fèuÎêªg\rqVí{\96í\1a¼   ñvm\9bnÐG\1fæ^q÷\97\8bÎï\a1O\98\9b\83k;v;$»ßÝÒiåÍ~*\1dkÐîæ\8aG¶]Êß®×r\8fhÍZs¹[§·\95¥E7òU]%â«æ*¿ÀD5ª<£9*\9a³´Å?ó÷¤Y&Þlna¥)Õ~\aKG¿8XùÅ`Ý\99Ùà=/\8brÎFf\9fûiÓîª\8cvi¬Òyec\91<Þv^ù»¨Ðð¬ò\8b2û!NåN\9dZÎêÒ\18oSU·\86ª²Rͧ7TI6ÂSJ\9bÉZõ4»«ëºKt\17ÝX\9f_\94\7f×ø÷Úã¼íTÙ/·ÆÅ°`´ÿi(Ò\90X0º\9c¶¥\1eÕñ\85ßóÝåM\95j%!î®ýèTÜÌTó\99\9a®£¾ÓT\99g\r\buÖÈò\8b\86\ 4\ 3C\91Ò(e¥îP-æ$å\17\89\86ÄÂÕo[PÜZÎ*Òò\8a½y\88NzÅ\19\14(ªHñ\1a2óâ\90\ 25«PohtOÝ£Yª)ɺ8\94\12?\19(¿HD\147HúE"\ 2
+\14d\11\89\b\14((±@A    \ 4Ð\ 1"\82¢\80äñ`Q@BY*\15\ 6\ 4\ eÉ\ 2\v4&\f\vÄ\ 1£òp,`\15ÉÒ ,\104\88<\18ÐE\98DPqxðX\fð0\99@2¡\10 \81äÑ Ò°0LX\ eÐ\0by<L\16\1aD\1e\f  \93\85\ 6\11\96\a\84\85\ 2AEÂ@\ 2\8as¨8\1e\vh°@\1e\130\96\b\12PØê\1f¥´Úcfå¤\19¡Úús¬}:ós\ 1CäS¢)O\95\8fÊ\9f²Óå#\9d²mÓø&\9cÛFûÓ\83&2Ú7>\9b®sváøÈÆçSÒ1ÓÙjиåoîÓ£v¦ª\vo\9cÛêêUE¼- \8eú£V³uÖùü¢¦þ¯ÞN=¿¸\95uÇGÚ\1d[Ú)ÿ\9bÿöç\17þ¿\9e"µ§\1aÇnw·\e3\1d;\91ÑÜ\1dUqîé±Ê[\e+4«Á¯ÿÁ§\9d~\f\r¿\93¿é/¿c\87k\1eÅ<}~\91\83¿©,\9bükô¨ó{ö\87®\1fíì\19\8cÌ\8alhoÈÊ6e¿)Ž2\e¡\95úc¶3Ûìæfs»\1c3ßÜæfù\85\99}\fOhE\93h¸ó\9bÆpN8i´iOË/NÕÊ.E_Ëò\v\9a5¯)\96\8c\8ct_óë³s§i\9e_X­Çw·«Ç\10Çw_¢<\9dãÚ·{\8bóÕBÏ­l|ßiìó+×\87¨S\1f\1fy¼zÿÝÎniÇÎÆìÔw?{\fÓ\ 6Ï\90|9y\999V:8\96\93G\9eÓKº:\9b»\1dÛÓ»\1fÍíç\8cpì:v\9eÂ,KLý \92\1ak
+ÍsfS\98\99Ò\11\9a\95±\8cV\13á\1a))ÚÝ\98\99Íáî\1cz\ eí\87÷9ÏQÎáa\12~0¿\18L\9c\9bK?\11\11\80\86\ 4Ãâçºh·1Ë\1d³µ¬zå\9e\91\9aÑ\98͵Ô\9fëë\9f\15ý5çë¾òó¿\91ýz[×í\93È47mÕÜä¹Oïª;3Çõë\13o|½±Ó>N-T\ 3k\8c´²ÆH+ÓH\8d»\8b4§G\89\8b\98«öÚhÖë­ûÎ\117o\88Ô\90\8ej5\9dié6j\8fújól*M×îc\88ç1ÒßoÌg{úÔ©9Þ³åø\96Ôª³Ç\9d=y¯¯ûQïvìh:Fz4\BÄ¢9d¸µEû\90+\87\8c\9b¸\89\18¶M7¾ò}sn:ë\9c\u\e\19ó¦Ê\11OÙdZ·Cúh%¾¬E~º¶lkëã\9fy\191­Õ\18éø\12\10\80DCbAO÷Gæ\1có\96ÉÿmÎ÷¡úÕNùòtê\8e\85õOY1P\14Ú\93\89jå9E3ÅT\Ä\9cc¸»KÕ¼ú\åÙT&ú~c\89zOËL#K³LWÍåÙ©\8ee~q\97ù˳Õ\9cK\1d»´´\9cËËËÌÃ<˳ÌÌLô¤iÖ(ý4­ôò6/ÓH5m\93\94ÖWJ\9a\88s¥ÊPjUªFcM«¹ôôj%B\1d«âÎõ\9a;¿æÕ\94~cµc?3\9dÓÓ£âÜ\93z;GÍÓ\1cÔÕKÿtRóZ£z\1cÕ¯\9a\19ѦÑZí\10êËì¾·XUs·{\87»_8ĵҵmîmÕ»¿Ùe¸\12ÙF:v_\94\13Iï¥VvÄ¡\93ÖÉ\vZ×äæîÐ7¿ØõmQîÜÒm~ak:äµ3ZÓñ\9e\8d7¿X[»ü\82hi\9c6þ=´ùEi\95\96&\1a§ù\ 5j~a§f:§ZGsº:¦tZô,S³\ f\rYÎ5çê\85+*C\95\925¿¨-ÍÌËÌ\1d¬\1dÌDÓ\1cÌ"Ìü"ç2¿¨|êÐ3¿¨¬üP΢!M­\17kÑvQQ1\87²Ôu¸&«94*C;ÔÛG¨F\7f\b\vÑFC$Â\9d=ôî\11î¹ô\16önô2)s2ï\ e\13\vïêSwu\97_hÍ-îU\9a÷hªNu\85Xj4Þ³V\rÕ½.¿¨û­ákͶÔlKugiVcVw\85§Î¹\1dNÝÖL     m?e+[\8d­\8cÊÌSd6%ËE\1d²ííhO\9e%×M{ýRîËöz[\16ÖTÒ  O:\97_¨û\91tïô\ fý¾\87~§¡Ú¡ôe\19ñ;ç³C\9bÌf¾ÕZ×éÌ4uÇhs'¦j\1dU\8eo4vVjÖØ´\ 1å***\88\17Ê]1x0¨\88È£\ 1\f-\b\v\930(\13\ 5ÇBQ¨,\90É\ 3\82ÂäÁÃ!y(,\11\10\a
+\92e¡<P\98°@D44<\1cV +È
+.WÃåp¸ L"\vå\ 1y\80`@\91<\1a\16\87ä¡(E)(\14\88¬ ²Â\95\82¬P\8ar\ 4§ \9bÀ\80@\0Y$< ¨\ 3\9c\r\1a R\16Ç\84²\0\r\184``A¹Ñh4ªÑh4\1aÚ¨FC\17\8dÈCÂ\88\88D4\1a\fÉD\12\99P\1a\1c\a\81<\1a\1a\1ah@\18\rÆ"y@*\ f\87c¡<X\1c\90\ 3\93ʤBaT \16Ê\ 4F\ 4\bÃ\1a(\ 59xP*\8c\88\1f\18\rT$Kdi0 \ f\10\ f\ 6\ e $H\88 ±@\16    \8bDÂpX\98°\80\1c,\1cøÁ\ 42qx LÊ\11\ f\a\832\f\ 6äá¨\92 aa\rX\16\8a\ 2\90Éd¡\1c\13\a\96\a\94¥\ 1W\1e\103ú+¨
+*¨,\11\87Ê\83Âp\ 5\15¸ü@ò\90 \18*\92Ç\ 4\ 2        \12\84Z4 \ 1DäÅ\ 1\8ex ±<@L¨8D\18\0e\ 2\994\16\ f$\8f\8aÃ\83\adi0\1a(\11Ǩ@H&\v\92E2y\90°\0\85\ 1\89h,\ f\10T\ fLp8*\vDCÃÄá°\ 2\12Æ\ 3\ 2"\82Q\80¢D@\1c< ,\f\1c\15\b \12¼°\b\13\aÃA\ 2È\ 2aQ \ 1\ 3\v\fâ1q\0¨4\18\94\ 6SP4,\f\12\80\98<D&\v\96<$\8fÆÃá\81A)ÀÒ DL$X\1e&\92Ç\ 4KCA`T\1a\ fD"$®@" \16\8a\ 3JD\ 5b\81<&\80phT\1e\15    &\92\86d\89`ÀB!À\ 2Ápp4´4$\v\ 1\12!\82\ 4    \13&8\0\80¨\1c\ fÇ£\1a0\1c\1e \v\1a0°@\0
+\85\b\10\ 1a@X\1c\93ÆC\92\80\ 4\14\bL\ eH\b@\81Àò0¡²8&\12'\ 4 @@²P\1c\90\87C\83A¡,H`©D8xP*\15ÆbqL$\90\88\84\ 3\14
+\8b\0C\ 3\14$\90\18\80"\81\ 4e©@\1e\ 4(\80\ 2\82D\1e¹×J\98\94\f\11ÅB\8e\98\84ªWté\8e\9a§ãÍ:kb¥ë¸c\8aªS@¶po4Q}µg\9aÕ¤Ú·Èx\8be\8c  !I, á\0\81¨Ó§*ª­Ô\8c\18&CíÚ\19b\92\8f\f\91\1f"\ 36b\8a\ 6?¢K\84«È3Ò\9b®ö¤K5t»Ó«Âèl«\9e\91%Ñ2ø¤\96\8a\1e3(@J\eR\f)(]K\97\89¤§IT5ô;ûÝmÞF³#zL§»»Û\80ÂpH¡¸\11-MDKG\96äS¼è\1f²Ê[\r%\1eðêaV\96\92Ýhb\96\rO6u\98\ f\v\14Ua@ pH\16H$ Ñ\90X@õ âÝ\92a\12Î}\b\ fÓ4T»Þò é\9e·ô¾·\88Õø<Úí÷\86y½}3 þ\88fãôeÚN§mÅ1ÖØþÙvÙ\98l\a\9a>¨´\95i\92Z*\b\0\0\0     ã\11\b\80@( \vGdRÁDÜ~\14\80\ 4brFÂP$\8e\84¡`P¨\f\81`\84\ 1\14P\0\18\ 2\80\ 1Ä@d\ 6Dn\a\15Ü\83\9e]OÿîO
+Ãy\906\83¦D\10I¼¶\89\ 5\ 1ô«-RùE®¬ðÁ\91£4í_^\e©DO¢    =ZÄ\86&\875@kn¦dÜ:¬\1eêé%6J¯?°ZÈÕueìÌ"F\rÿ©ë\18\8bé\11±®û\14tF_\8f\19ý\ få÷jU\81x\8eÛW\f=PÆ\9fº\9b.ofvÀm^qit\84úM$<»\18\ 6ÅH³øß\fÛÆ]j\Äl\Ä2·\9fÐ\8b¬SØ{~ýé« \18\15'Q¢*t¤_Ç´;ú¡¾\81\96V\81\8e=\1cløÍ(z\88}9\±N\ fDG¿ý-SrÏ\ 1`n .m&>ÜAj\93~,\89Á\92ÊÅ\ f¢\10\95(\997B\87qQÝ õK\9b      ®55\85\ 2V,\11Íü$r.w\1a¨án\89q®» 7 \1eNdð"\10Ô\e­?L8\9e\81kû;ÖIº\19U:\b\1d³ \ 1VÏã\1f\97ëî90+\94×\95\93ë\17Üi\1dÇà}\8aH\87ïί$)5̨\9c\1cWÝÐ\88òvxÊfiQ,DTY\90»\ eºçÔ0XlÕ@\ e½Ù¹\80æ\84ó7'TN\86î´¦ûrÉ\8flp:z¦³8vòVXÔÌOc¿Ñ¤]­·´$\90\12\ f3;`Ì\0\12\e¼
+H\1a     ã-'þéÎlr\v2cvK\8f³\aS\9d©;õ¨ \96\9eÈ3\90t\f\9c¾oºì®\f&ÝÞ;\97\eXüDb§A²\86õ^²B\87\ f\9b\ðaô\ 3Cäë\13Ûë\83\9e\9b\119\7\7fh\13\rµ\89.·8è\10Ý£\14\12]\19ÿ\1f\9d
+Æ9Q­C¦\1d\ f       Þ/+^ ¥¢\f\ 4\Ö÷j)x3ÄÑì±\7fó~\9bJ§»ÙJ\eи&\93¥\9aþX\1d4J¿\18bà]Bµ¹COºIR\1føBÄøû\1eø\1aÿAA§a\89\ f\f'«ge\ 2w\ 2ÁÇæ~RE\a\9dBo\ eø¨@\8c¸±"\16¯\ 3\ 6>\94å£\92APê\97u\8a\12\83\ 2A©g}Ap\b\19¡ ÏÇf\8b[)ßL¹d\80u\ e|wªÃ
+\r>\98\8bôÈYõÇ\9a%\8bÅ\9aK²sB0\e¥\7f2\ fC/¼bf\bó°{+¶ëjAý\f»\ 4\9e\1d=ÞUD¿ÝxX«C\1c?\1f\95\90\88ö»¹\81SÖ²\bûf¬R?b\14\9dêKl#\18\aR\95åâÎf\17bB\8anÃ^ò_ÖK\ 3K\17á\88Ô\14©|\91+V¸<\90óù%¯þ\16ä¥\98ü <Vk¿'\ 2=#¸­yYÕ­\14Òëºi'7<1ÿ£;-\8b³\11Mél\88\10\8bÑ禠      ý\13\91\1e\80¼\9d¿ü=)\1eçÊ\14|³X£Y0J\e,s\bô\87\ 2·8¶\92#\8b²$y\8c\9bæè\ 6\8cã\1f#\84\ f\8eüfpâAZA\16\9dDõMt±x w%«4¯4\0|C\v\aîW\ 6¶î¢\85\92\14¹ÿSwá8\91üàD$£\1e®lf6MÞ}9_]¤m;\v\ 2MßøÂñ\r¦\98ûB\ 5wè8yC0\fzv\f\14Â1\14uæÉðWc§\828ö%¤Ü ¿\0Âh<±Ø\95¾xUbe\12Ó]Â;B+«üj¯<ð°fÎ*S\ 3P\869²¦ÿÈÎvA\9e7ÚH\1fÛ\1fØ\9c¡Â¦\v\93\86M«X\ eG\8bëc\1c\8f\95 Ð`\90Ôå4ùÆÁBq\ 3,B\ 1   ´ß\14¦\8c \8a\ 4e\15S\19\18\ 2\v\97õ½Z
+Þlüpö\16ls¢i1Q¢ooY\81¹g\84\9bGÑûIô\94Oïê\95cZ\ f\97ÖC\16-£Ü_Â\8d\11¥\ 6ñ\8c¼ß){Eü¶Ä_\ 3DUääb\96K\99\9aß`¹\970L|\7frséQtGbV¿÷2û\90¤\9f§ôîÒ\19ÓK«Ò1G<ѬlÆ{\87\88w\eð­%D0\13¨xx\13\88P\999<\81çnÞ©\94F
+"Û!è©kô(f4«\15Xú¾w{E\94QuÅY¼¨\83\9a\83bjOb)Ë\8eîiòÉ\0ÄõÌLÐÞ´¦éª.Ã\15¼Ùx\9f\96¬}×¥<Ž\ 4!è^×\bº\87Á¨ó¢GY$é¿9åbè\87çã\ 6Ëê\96I\9a\8a\9b"\8bü:\18¬í¢èd®m¾Y\18\13\13¦S\7fjA~U\12ü\82\99\ f\99ã³w\11ÖÒ9É\1c|æ¦\8fo=\80;¨sä\9eQ|\80³¨\83\87\fÍ ÿ\85È\89\v\1cô&\99\9d\82ÐeÚËz\92\ 2\ 4Ú03-ö½\13 \8b*¿)ê]¢Otcx¿`2=oË\1f \1f£\8c\ 3KA¶+½ôï°D_bÉtú\1fÀ\7f\ 46*W\a\9a¹c\v´\ eu8]HcvB¨\9e¨SSE\8fg|\9d"\97Ý\ 3\1eþF\97LHA\8e©ËA%Mî^;\8f\99Yûü\11+\7f\8e\18v½©¥] {\11Í.2}¿äb¦HDÇ5\18\9d?+T\ e\88ö®Ë!\9eä»V\10ñs\9b
+´xnéäz\9fqY²ûÉú\86&\1dHñÁ\ 4¾\esÉQrC\ 2Öw7HÚi#gæ50\r\80\14\ 6n°f7í,\13´=³LÕx ¸\9dù_þ¥ã]Â+ûѼ\9d<#EYf÷Q\0,Ñ'˦\99\1dÿv3AÊòô\7f\1afd\1e©zp×\84N\e\91ßÌT¬ÚØ#\90³26\1cÆ:¿\ 6»Ê<¹\7f\89x@T6\91§\90·\7f¿\v\1f?§Jçä{\Z\86Ó\9f®\aÅ\ap\9b8%\13Eê¤Ïâ\9e@1;°Ã/WtÂ\19ñ§³\ fî\8eѼɳ\82\94=\86î/\11¨S´ú¡ôq÷\ea¬H\ f¤\8f \86i¶³TH'Wàþ\9cûb\b\88K\19\99\ 5+Z@ù½þÁ\r\1an\13ò\0\101ëUê¿ö\13 \rÇZºÛÜ\96è\ 3ûÕd\11ù\9a\1eVXC\f\8bû¡[Ä£\87Åûº2\85o\ 6í\9e5*UhtGzU\9cóf\94^\8cc\e\e"¨@4ªìSôÐC§\12\82È$LA\1d¼    s\e\ 2Ô¬­ËQ\11¢\0çß¶\87`6&Ò
+½KÇ\96ÞRè\94K¡ *¶áÎ\12ù̾?\11&w\91¿ñ\80\r\9f\90|auì \aBA\ 4¾Ó|þ¼¤×\0Ðeq~ä4\ 5X\9f[ñÏ0±\10dG\89g\94£àì\85\b\r\81ìgÄÊgÐM¦;cÐQ;§Wþú-<ñ2á\99Q3\81\13\eãC/5\0 \8a\8a¢\10¬q£KÑÂ\ e\9bw\89\91%[\ 1|\ 1\ eêáä®øÌ¹)z\8a}0¼2{x\93î­¨KEðǰTß\17¤°Íð\7fV÷ø\90~4Gï7ôco7VP\8cºØô\91\99'\Ù\89A6Æ^~úÉQëæÀ\88\8b9i5\82pH\92µ R\16\8f\9c\97f\b%¡-0¥\rJ ýp\8e\13Ìþ\90¼$\7fÞ\9c\83Ùÿ¡Xás\ 1ñ\8d\bºæ)8\0\9eº\ 5LIÇÞ\98\9ce\ 5p^£\9c\8aQ\8cï¡\88îáÛh\94ߨÙý'Ðâ¥Ä GXèä[ªä\}f\89kù÷DLß_\8dJÔ¨«\81PúÎÖîêeÇu\94àÂK\9ct@\0Øû\8b\\9dÖ¥(\99;FÕÝ®BÑþ\81T\12áMÙ¾µÆ»à3æ¦\9a²\8f\8c¦×&W&j?©4\18,YÑ\8bZeoöÀ wÞ\11\7fFÒýmÍèÂÃÄT\1e!¸b\12üX#}6*_\18{î¡\81QOÃà\99y\86\86\96Æ\99FPµîÌ\85Ýyc -\ 6]4\9fw¢ú |\80Xä¼\7f¯\ 3mäÑ\8cC\9be&;ÐòñSÇÏ\0ÂÜ,¨óNZ³Ý¾\85\ 3TÊ7>Íâ\9b{X\bò\97\1a)"\98ëØ\eð$ýÅ\10OeqX\bÈ-\16?LlùTBÐDNw¥H\rõ\e-zwL¹Î5\vW\1e\99ë]`"k[ÿ\91©N\9e.PW6V\96\84Ù\9c*Â:©\83e\95\92õ²Jxãm\97\ 5Ä\ f\a¢&MN*áªàúKQ2Ì\ e­Yë\8f\90<z&\13A\1a\9e¹t¦ûà3gf4KuP]\1fæ\8eU¨Ýõ\1a¹lÊ\ f\89j2k^wD\ e\88 sìuø\14ê¯VU\8e\9d\99¿+\8d\1dD77LfÉAàß»\89ªDbqSεÂ\8a\rÜ\e6Û®'*zÊ\89\8e\1e»epýÁ.\9d\19æ5õâ¡7\96\89\85¬åT\86:JâåüýÀT\97´\84¾¢N¬0x\9eq\8c\93e\83`m$Õoäd\9bÈ*Æ+Ê^\8a\91vÞÓ@\83ò%\v\93ÔÆ¥c\bÛ\9c6Éãð\aXz&{Zz¨k\7fçyÂkå©è\19røaÝAûqx`pÀ\9aðL\7f\14\9cúfÞxRãþ|\1c%\aÃß\7fÊ­õ¦ë;Y\86\94Ï2Õ\13\91èu\19A\0#\ÿ\9cëBº<WÞ\9c\82\1erÑ®,ñJq.1µ8\8aæ¤ó'^Èá\ 2p\8a\18\0\1fÈ\92¤ø\1fÓîUÏ\13\ f\9b$\ f÷\11Þ®Ó®7r|ú\93êMoñ   ½AF$\92à\90è0äLâälF\7f\13\1dr\1c\84Utq\9b=#óý#ç\ 5àk\1f¨qZ¹5HÃÙêò;ëAV±åú\19³\10ã\97º÷ßj-Íí\9e\92«!81Öè¶Z\1aÄ¡XtúåÙ\83°ö\94ð0ÄÉU\1a\ 4Q\11@\1f\12\1c\9d\83¸©öçâ|òë ûqÿ/ \18vÓ}õï\8d²u¿¯:>\12N#|ɲª\ 3î\f\189á       û\12\8fþ08Ø< cÈ¢íìÖj\bÅ\98\ 3:Qw@Y¨oGu¯Í¸mº\89Ã\ 5^,4\13\8ffCXCV<?ÂEÄ\99¡$hP¦þtI¦\1a0p² Å«S|Í\92\ 4ìÛ        BÇ\90Ðe$?ó\ 3ü\8f:·Õ)`Ü\bæ4¼(0]¼U<a2,?\86\\ fð\9a\13Ä\19\9dÇ^;Ç\11\86«\rðt\eÎï}n¼{ÎC\ 6|\1e\9f\192B\98Þ}\85='\90±ÞD9%´\98ã\ 4þTì¯\\ 6^@Çð\1e\17\ 6\84ËÃS=¿ÞS\8b\14\ 3\96v¹k\f\9a#·xI\12ÇIÒ¸5    ÊA\a'Ïg!T4¤ðs>ªÊ<Ø\85\80"\ 3>\ 4º4;\1cYÖ¯\ e:'\13\95*½ð¤g2\8dÞ\97d7ÿO\0\95\13\95¥1AÐ]9¨\by\r\14²t¨;§x
+\8a9A\8f\8e\83W0\94«Û\18Â;\r7\7fºnßÍè¡\b\82#J~µÍ\10­y°<Ë:M\ 2î·9i\96K\88\rð\bBU\13À\7f-ÄÆÝªçëê\b\1a!Üiº.ÊÍär|\91];ÀC\1d\1c
+\84ð\9bû\1fRX¢û\1fë2F§\88\99A"UBeäê\14%­`«P\12\87\ 2Wrºôà<S\85\1e(`\v\9a\83\171\9aí\8e\8cϧÐG¢æÕ­\ 3{¥J\ 4Ü'\ f£¾9\11\81FÉD\80\1c\9cË\v\81ï\8b\1e\ 3\98µ}QZ\ 2))\94þ\7f\17ûÝÍ\ 4\aÙ\88§\18¦\1cå\15\93ë\ 1%\ 6®òó \81\v`\87°\83ÂS\e3A0'fsì\\9fè\90ÅË"\935\91íR\9f.Ìï¡éqÿè\87ýï!ßÀI¬ìõ\1eª\90õ7IZ6]\96+8\1d¥1\ e\\9d)\86Ø«\1fV\85Ýø´\84ÌH2j\89}\96\8fûiÔ\0)8ëó[l\84»\89È\8f¸J¼/\86
+9f,Þø\rëM\83cbLt}}º·i\1e\99\10d\84$ÿ
+ß,\ez6Ës7       'Ñ·mT\1f{\11\'\rÙÆkeÝX\ 11Á®¶á\1d\14ÌÕn4Ø\ f%\95¾´Ôn½n\1f}È@Qû\ 2°ÑT×6\9b0°Ò\8aº¢à\10ãú\0+[\9ex\1d"¥À}Á©è\13\10\988ÿêýx\f˾\19þ`R[åkÀpV\1c¢E\86\1a\ 2\ e­\fJ\ e9\eG¬ú«\rÍéH£-\1aà\ 5$ß@zG"XÔ_\86Nßq7\96!"cäìFRÏ\9e¼m*º³\b\83\8d\82\14°ÂتÝ)Q²0"õ"æÅ\1aX|/¯\92èS\17·ðrüh\JF(\14\96on\0\7fÖòh\ e\ 1\1d#>B\fI\1d5\90ÚL\80\8d½§\ 1U\ eYºÅ%Ëáx$j\9cì\94¡Û\18gcã­¦2ò¥Ê\12¨\1e\81\1eã\9b\83b#mi\9fwg\10÷\18\89P0',£«å¬:cÇ\1a\19ì4\ fñL[\9a1Z=Å\1eÏÓj_\1c9ÌL\18ζÆzm¤ó$à\1f¼\96»È\eª_¥ÕzrÀ\12' y8©\86\18\ f\ 5\bÉ5\97ôõð¸é_ÉÂ\1d»,ÝÈ®¦ökO³\123ØNà\10\1e\aH\ 1\94]\8af\fn\94Ïc·\13(g\90ã¸b!¼<Á=\92 º¨\ e'Oº¾ãß\ 6\15{ê°Êå¦5\9e\96!\8a\ 5ó-\85Ùob8nH;Þ­7À\97¿\17 \93\ 5\e \13¨·$,\ f\84\
+\v\97³\999\10\vÅÿîÿ2CU×äñ_ºî\80\82\94¤ ®à!Üì¼¶\1cÍ.L\ f\9ff\85îzíÿ\96\14¬LT<­&\ f7I\82ñ[i·vòe\12£ô\7f\1e\9b\914ãuή÷fíF®\12ÕÂ8`¸.¯ÅuY6¥@\f~²c\826è{¡\89®Á×è\7f6)n\13\92\8cÈ\9fï7C¶?ô\86Æ!\8bí×\81&1Æ\9aB[\99X\86\8b\10\12\r\84\8e?9$\87rÂtÍ=et\8bcÕiõ\12Ë{$¶mGQ³Ë\ e°\91 \ föNî`Uf\89\8eµDËkN\0\\ eÚ^i\b\15^éè\93C Lþ¹­\ f\ 6Q\98\eðø
+AË\0P\92üAd\ 6AÞ±\0ïrŷij)\86%\f`¹(wsW\ 3Çn\ 5\84\b­¼ºz\9f\85&8ó:Í@ü²\ 4²´\80;b\9f\98{­üeÿ:A\87Ïv+\1e\ e+¬"¾t\8d\8bÆ1ô\18\19y>m´=\88\9a\16@\0\15î\ eÏ8kÿI\19Äñð*\9amÙ$ñ\15\93ä¿Æð$\10ë$\8d\18ëô$\8e\ 1\98
+5\81\80LO½s¿=\11¥\9e$\0¿V»ñ\8f=Ãø\ eê\15.¼4âT\ 1\99Ûx!ò\11\13úQGþZpº÷º¥Q7\ 1µ)\18\föî8\9cÏÞ»<Hgy\1cA\98\ 6\19\ 4Ù¢I\9d\10*\ 1\87øUáÏ#Ð\90a\95Iq\862Cäe+» Hë¦Ðx\ 2©¤>c¤$o\93ª\r(3ê\b&\99\9c\133*m\ f|ô>¢^ó¹_ñÈW>"T\19Ä»\10ZGÚ\90)Z\14mB\19\1f (\v\98#3üÙî½õ$\8a1^Aî¡]#\b¨\r\93tüå=hdPp#8[\80\99\83\0¤\14 f\ e/$¶»>Ì-=
+Üf¡C¦¯Q\894F³\«õõ'2\97òñ´\88ò¾.\13\11\b¤Ü\7f ý\8bSRÊk\ZµÛR\ 5¥ÌyÇ#b\8fL\ 1\8bqt­ñ³ý \15gj<¶
+³p\18\87\ 4g$¿ÛD\86H¤Æ\92ÖV5\87W`\11n\82öx\18X³¡\84\ 2}\ eR\99ÄϪÁ\ f\90\80B&\7f\82\ e\8dD»À>\8bV\a_\12\8dþÆ\99y' ò@MÙ[Âëðih·É\15§\93Ú\16zÊ0\90ÿºú15©\ 3TáÚ{\a\8aä90\ 5ݨ\157gS.Mâ3\98Ö;\80\fÄ¡P\ 1\12Þ\ e\ 4JÙ1ø¼§G,\1c\9e:Cña\8f7Ü 1\9c:ó¬        Ô\7f\8an    Ò©ËY$öâ#ìÌ&ð¤\8dhº^¢ÜÖ¦N\9ctsöã÷    Þê\k\96\88Ö_)\9d\87\82\93u\11G\843\880K\ 2ä=\ 6\9a\15\ 5·hU#°ßùér-nÍãYÑ\9d\82aå{?êN>êÛb\8eË\12\1f«"^À\ 5\9eÄ85\ 3\ 5Æ'¹\80\ 4\ 6~¥´\8aj\90\81r_g\1c.\ 1\bÓ@KÚ®Ù\95\1cµº)¨Õ\9b1/,)5$Ù'r\1d\8e¾Ü\88 *IKÈp\84pqê\96}sÑp?M\101e#ºh5é÷pjÁ \7f'¥Æ-Bõ\1fiÕM?·$ÉÁV­µ/ab@âLµ*äu·\9a\175ídB» c\88²§;]¿¡SV_²Â\13¥ë\97e©i\99\93Q.}³ë\13Øç\80\89N-·ø~Ir3s\9c§\8c\9b\94\80«Ë\81ÉÜ$`]/\86Úzü\9f\1c\ 5̰lÑI\8fwFH$\8eE&¥\ 6\96ÌF\1dá\ 1\9aÙOü;^ôY¾a2,Ø\1a
+©æäÿi¸øéY©T¨_xα,Þ,ãÚø\ 3Cê46\95\16k°/²°LÄy£\r+!Ï~j§¦rE\8cy\8bÆõXÓ\1dÂ?ó
+)\8b\81\18×EÀ\0<\97\b\1d\ f\99F\17ND¥|ÜúÐ1\a«e\8aïÃÂ(Ês\8c)%\vêìIg©\9b¼\ 1ý ³\11u\12«v\82¿\12FÜ9;vÙ@\12u_w³-Qºv'\86_¶»- R/\84ú%Ð
+êð ÎÄ\9c¶)\9a\9c¡\9apZéܶQ\0\ 5â47¡a!SäQQ»¢\1cü)\14\12]áwþé¥0é[åMåâÁ®¬W-øÿ\8ay·4\ eþ#\12ùgãC\0æqdȲ\19ä³m©µH¿à-\ 3ÑÑ·nïVÕ0ÿ9\13±Ø\90]¶*üÐ5Ãyòó3RÉ2)a'\9dÀBð1«6\93ÌÌò'\etvhÐ\90$\89_Ës\93j"÷r°aÐ;\92éÊ\128ü)Ú\80j\81Ê\1e\89\ 5Y0$Ä\9bZ%ìFæ\19r\1a0¹ÆO\eøái Nzb­÷.H\99Z\ 5^.\8a\83\7f±\842s¤¿Î\87\ f×\ f\9d¥\99«ËòGçO\82íc6
+\16è\v\ fïçÈL4 ¶\93+i\12÷©\ 4`\8f½õ ¦\ 33A\9a1Õþ!sѧi\ 4úW\98%´Ö\16C\9a\99`µ-.\ 39\9b\ 1VYJõ\ 2f×*ï>\16\\ 5Ä\8d\93M       úQäÅqè\86ð\9a       ¤ÿ\14Þ{¡µ\94x\12:]*%\f¼ ù|q¦\1c£\81\94ñ¬Æa\ e~\ 1\14\14Y\15\r^  l6\90¢8 ¸&_®kU6>+©\86ÝÐÜ\8d¢\18\1eóJÉk\0ÍIª¾\f\97².\97¥\90!Ô?\8a\eð\aĤ¤^=-ã  Ã\ 6Õ a¹M=H       ­\86uD\8dL}®ªÈª¤ï~\12ËUÆ,£²N\vÃ\8ah\ 2¦ïíàÙäî\8d\11íÚñµò¼vò\8dø¦gpË{¿Ì@Ú\1d»a§\12\a\1dPÉ÷H \9eÚ\85]\8d.#\99®5¼ÄÛÊ_\95È© õ5\98\89ãqø<\ eë¥.\85á5aÀ©\168\87^"Ë-\81^\94¥~¡\8d¹Ãéw>À\9f\8c*x2\18\10~\85\ f\8fµ\98¶OfO÷wOI\8eÉ\9f(zD¾{r\82&Aö\ e%Óø]{+@´þÈ^\ 5ÕÃL\b\90òAÁhh/©-\89\8f\0f+ت<¥qøPNä\9e\Hñì\ 3Ðm&s0J\87à\0\ f
+\1a\ 3·b·`bê\81\87\1e\8e\84\94\a\8f¦)#xàMâüWr%q'\ 5a\ 5`Á»\8as¿'\8eChd\19®aeíï\9bîþv]aéÃ\8an¯²H¸`íÍTR\10ô=XM´{Á¶\85r×¶\1dd?,\92úê\1dfÊ9^c\88µ\9cx0lM\1d\9dø£²µ\1f\8a:\17U%\9a©\v\9e\bcúÁû´xÈB¸B6Ý%<¿\81Ùv%ûðI&\9di ß\15-\12\13\ 1{ÑÖZ#íx\89\96\81Âæ.m[eƤMf>jù\9b\8dØYðLÙï\a¿\81b9)Ò\8b¾û-\96¡\9a\8c   \14M\98\86¸x\0p°ÝrÔ\88   ÙÌ´¾ \8có¹\933Ý+¢d_"ï"=(W¨B\ 1#Ô©hD´;â \fKp\ 3Ã\86Üý@´´º¾\84Lr\0¤ç0\16,s\8bT\9c\85\b³çÆ{\8fç0\91\93VÃ8\16X¾1D\8cc\14®\86¢rC¿3\12\%¾PãD\8fxÆ+Ò¶\1fOY\87RUP    \97\95ÝÏó\94dÏx"»IX3-\17­\ eÙ\93ôÞôù=3\81`\1a\10W\ 5%áÒ $â.\91|\87\9eA3\1a0þD\89GHí\90\80\ 3h\rÄ÷i\81\1a#k±bn\ç©Ú¶\8diAÅ\ 2Úê¹f\15\9f\89ýö\0\a\ 5'jÅ\ 5ÅõÅ@sp¡7ºÃ\10Bdw\8d¹r?þ\93ïKäp&9Ù\94Ü¡\82\b^¹ÃW'\8c\8eAké\82ùþô\18¥º\V¾Zl6>ñôT,uM,\1dÍø\88êbzãÆ\ 6oR\8ab\1fU!\96\98[\12\14·\1e7e¡\8dVúõ)T\97\04ãöWÚ\85`ÅsôÙ'\9e \9fNâA\9e\89\ fÊÁ\87\16\fß{YÔ        Çbø\9aHlBÄþ%\14&§¥~Ã\NÝOør\9c1ì`\9f\95­$\84B¿IôoXI\90à©õb{¡\14÷ú÷\rpºHM®HÅ8\U\97\92)#»*\123"´Å\9c·\8a\96\93c}\ 1\85IP\98t¡ì¸¡\ 4\9a\ 4E'ÐY¶ë9×>\ 1Éì\ 4a¿JGy\9cä\1dõ»#Ú\96ä*»\9bX7Ï¿Ä\9e\ 5\14Þ7äj|/wòÛ\83[Ãê\12\92tÿ\85\94#³Î\\99\ fDÃ(=\18Î,ÙÔC-g¼éÉ®\1cÎ
+dÊ3ë|VE\11\rM\9b\10\rw¼Ö<Z\96\9e¥*\ 4Léj1Ö
+)P[?1\10k;ú\8b§¶\84B¾)ϬF31Ïpå\98\ 3ÖkÞ9[\9fb<QuÎLþO£\1föD>~ b\0±V\14~\AI\9cÛ/9\83î:Î\91í\10¾0ì!v\15/"õ#fz\7fz×å±Ú­O¥\ 3\14\ 1\1aPto+¾K\12W=WD°)\85\f7\90/£Á|wØ"=ìL\9b¾\8e!\80³\86\86¥Â'\86äÔ\85´T[6¡ÚðßKßÎ+b\eE¥-­KÞ)5ßw$b:7\8f#\8dé#O¥ý^ÍÉ\ e¯,-{ãe¢\8569\12\88Ûâ¸P(y\96É=­¨Å\80\9b/\8d\81ô\8cúÅjÁ\9c[\r\96\8bû5\19\9b\80\10:\9b\94wvqè\a\95"\8b÷ø"×e\9e>öxð½\98\92+\rLBÓ\8e"húk+\94±è\17\19¹à¹\11ZÁ#¾>\13}Ë«´k\94ö¤T»È\85ò\82>\94\91\93Ê£m\1f³\1c\10½ì\88g\1e\95\eØ-\1c\8fB3NÛ"ݾZ\v}Ìצ0 Ù=\90ÄÒ;ïæ[Ýa\90/ùdÇs±Õ\1dÜ!qñ\82ÎWògÜ#\9a\87G*zÙó³Ó¹ãL\94¾)6Y}\94*dµ\94YÄé[¼ÁØ»9û-û\1dÞ¯5AF\ 4¥\ 1\194G¯qË^XK\87Î\rÂ\80Àjì ;Ða\ 5¶1H0Ö\89áÝÍ9¤R|Ot\89\r\84\8f\vÊè\ 3\8cvÆK¼¹FïcÞ©\9b©ó\15\8d\8eàGjº`Ñf ê\89\ fn\a\9eQ\99ü\1a\16\ f¾=àj[&?%\1e\ fÃÑF,å\8aI;·®¡F°ð.åî+\83\18xEÈ\1e!´C\12\0kd^A3Ä\99Q&E\91Kþ'ýËÜù>tÎ\ e¸X©r\88y>\9cÓ+TÆê\82oK(Éx®ÄÉZ%.7âºÀ¹Y|ô6\86Üç©z\84\82(>áè'\92\80J\84oëUBõÇejG×
+3\80\82íôDûñ¯\7f\89ì¦çø\8cØÓ±\11\eióÅbce\17\1e¢:0¾\f,;(N\vdòGÂ\{\rKÄìl\r_\8d*óÿèÆvÀw,/e\8b\aéÀ¨\190\1a}\8bâYqÜ^ËÔÍ\18?´#qÅî|$\ e®u\18,ýb\19\17ÐÅd\8d\9e\85L­æg:\8dÌl\84AD©7ëc`ÜB¼g\92ʽuÐ[ã¸\ 2d\ 6·V\9b\1d$_&"\17ý\ 5';6I" \92²¥\13IJ^\93ö\87Í,sH<\eÕ\0\ eÀoÔÿ\9d\ 4\1e\v      %?¨HIôc"Æ*ªô°N-Î\89\ 1°D\8fÅ_\ 5çO,\96\95\90ÉJ&Ii·rfi(ÏÚÀGÙ¾iy\eC\eÇ\18·Æ\9b\ 1z\1ax\8cO¢©\98\f¨éDäóÏcE´{f°#U¸%}\93\1e¯\1fÀt\1c×i+xd\921\17y\ 3­ïÏà\98©\14\88 ±Ð\18\1d±À\11ì×\8d\8cJ|-A\rÏè\81­A\87È×rêYÏ\9fâË_¡\98(YÖ\13f|qÕ\9c'c\9e\18ùÄ+n¨\r²
+\96HðlÅhWm\ 2§ë8\aéÍÒ9ü4ÕÐ\13d-k¢Ü\81\0\86¬\8b\8f\ 1¤+\91ó\81\9a/\7fù`\7f\ fv­äÄ.ÿúSA"a\7f+«¹ýµH6ì¢\8a¾\9eê\8b¾­¤¶\ 6\88på®ñ\10wtXM,\8f\8at:\86<³"\14¬÷à\ 1X;l¤%~\a\81½\ 3)\16­töî×\8aÌ1\15(ÕGC8ñ}Ó\ 2|Q\15»G\19ÆWU\7f%FßV\86D\1e½-ZÜ\85\17+\14X\88\99< hí®\8eT±ö*5Þ7x;\89Æðåîb¦Ø#\ 5\15$j\15>D3À\vÛaD¥Zd\9b\8c3² 8n-ÛZ\18s{îíW\93c\9f\16²ØÊ°è\8a\ 1©Õ8z
+(?Ä\83\82\8b\ 1\bdf5±\8fE0¡\ 52D¼ã¸kcKâñ®¤uà\e\ 5\v ß>Âs °\8a\93\8fæ\e¬ÿ)Äæ¦\9cKÂGPôߥ\83Q26\85ÒÔ\8e\81Ë"\85%4³¼\8c?\82\b\12¶l3=¢\v×\r¦¶·óh\ e\a<= \198EBÇ'øgÀ>CØ\18]Ö[à+å\14\8d5{ìû-ð3\12\9b\ 5\86\14xl3väh¢1\12hlö\8f\0\ 1@¿w t°%:úF\98|l6L\9eº\8e@©2®#ñUg\82ÿ\98µîÈ·Î\bê/×ßû\7fq#yÀ\87qàñ ØÂF¥¸J\vð|Π¯\17ÝæÁ¯\98Ç/\11*ïiâ^\ 1\9e7Om\90#ÚaÔ\8eo\87â5\918\e\b\80»ITC\8b\12\9aOê!ò]\ e[y\869\bÛ.¨Ç\19Èȱ\10ì\9e\ 4ËpÞeÛâW6ÝV1\87\8d\ 2k\10\87¶Vû<ªvX\bl2§@v3v\0I\83Ñ\8aÝ\83ê3!s\1eï¼"´/\ 6\88¤=÷ý\83öh\87%àOz®ñNq1n\ 6g\8b$ 5\13ÿþ|¹#É7Â\b\eUþ¥5\9aósû\94÷»YæÇ\88ò. ã\9a2ÐD5\9f\ ey0¾¸Í#Nª\9a$½ÚÄ\83\88ý\8a\1ariÄêè\99\96é\ ef\81Xëãzkû$qì[8\8e®Uþ\9e ï\1c\80Æ}%¾ÙÎ|Îá- mWgPP9¹\17T^7N81£Föy´¹jÿÞg'\14\93øÀ\93,\99\15\1ceCÊ7'X¥7½NRÕ}\97\7f ¸áP\82!Û'aRByh(mk.Ïú\97´h©é­R"¦\96¢\15\1cîÈÏs\f\ 5'\91ÿ\ 3 ^°Uè0Ù$\98\80#\1az:\15\9c\11ç\91\80#¢¯ïX70\16\91\vw\ 3\916\12ð   \9c´znÖîÍhÓ\14ÚÈ?\bµ\82ºº\9c\86\91\8bÏ\81\ 2 Â\10\18¶.ʾ^\8dÆÄY\ 6Â\82`íñ5Ã]c\913×y¸Ú$>}#îKL¯$ÎO<·s\12\rä\0\ 5Ãü´ßT]QX&ér¢ù;\11'*\95ë\1cÌM¨Ü\O\18tÐB¸+Ü7\8ec\92ìúCýÄ%sO\94¾N\88\bÌ\90î«{vX|\ 5\9er*\82%\12Ý.\ edl\1cI¤Æ\97­U\15(QV\1eÎ\·\9cÈkÄ®då\95DM\93\9c\9a¾pä«Þ¢\85åö\19ÿZKGº¸ºq\12~<D\9fpÓÓA\8bóFì\89Q¹Ïe\ fyÉe§;Îýü\ 3\9b\98\esZ\88H.M\ 6\9cÿø#/ñîÔ}s\14\11c´ET\91\7f4zó\¦A¡xUW5Ò÷ÔÏØ"\9bñ\bYñQc"fCê>\18»Òã7Î\116,¹Sg\ 1çO°â\15ÓS7Ó\r\ 6\87èU1­æ\ 5¡\15BlB\1f\8d\ 3\95O^x\856´;áÉ¡àÐñ\bcò¶\88WPÐ\8bÖ\81UP}f\0\r\84è\82\87Ûq\ 4§\9cLoð}\ fW\1cñ\r\ 1[\0e1|\83\1a×»\ 4\80ãO/Ä\bY(¤\93Æ5úav¬ÓA0jò\9c\17æ/¤U\eÙ¿CÝ\89'\1cãzZ\v®I{\8aªÏL\15\89Ìb\96¯lÆ\9c{\ 1ÿÌØYüØø©g\9a0\ 3¿¥h\ 4¦\12;ó1~%ú"Z]Þ\84²\ e+º?³ÜÎuþI8iñ\82\9f\80z\1c\930ÄsË-TÈúØ´\15\ 6¶p\1c\r    Ü ×eº\8c¤ùn ½\ 6ï9ºÃËÊ\18æ\ 5ø)\7fM W;mBßæ\9b\ 3WL0®hE%Lè\ fï\8bdônïBÁ\9e\8bK\f\aè`\84ÎIx|ùp      NÇ\88E\8fFS¦¹ìHh\808.\97Á"o\91\17VW3\ 6Ãaά¶®ÈáôK\82õ\8c½ío\1eÒe'\15ð¾N94F.@\9c\87\8b\18'\ 1¨\87ã¬\12\82[9§Yúßså\ 5\1dÊ\91²3ÌX«\v(åjsê¿\92ߨ.ýð{Åúqî\rΣb\15¡iâÄDyK4 Õÿô`\ 2ª\0z4Òe®\97é3&\ 6\81²±å0§\ 5O\1a1ñã    ø Ìqéu\aàªbÿ
+):\ 4wÞù«_vAêØÈu6\1a\v\17´<\ 5\8eݲCÄNÇxû·¢\12Ø!ý\15ÓfËkllB\0Á\10ÖG\87Éë\rê \88Â#±¥1\16Å®Y|\15\83Ï]ðs,$ç¯D¡3\6\88å!$\9cȪ\ 2\8dïÜ×\rä\ 4âv`S\94\12ùgdûÉ\84Ö#\f®>\90¦«\87%êìÎÐ)é\93Û%\9b\14ÙzÞÓm\e\7fPݾà\8d\15x0
+"/ÿe\94¢\8c6Vu\ fßßÇFj\15Ó=\1e¢j³,Yó\94 \18\f\91\9aÒ`Ê\ 1Ú\18\1aì\b\aÅ\e_½ø0@37òùºH\\85Ó:\18\9d[h\ e°\18\1eü¾Þ¹þîý£G¨¸xÂUH¦k\9dó\1eK       f\88E)|%\94LR!ú\90fSaD=Çn\10©A\86Eê¢L«¯§Ày¡Û\12?
+ÍGYÆc\87<¹ûW\ 4í²«:µCù\1eHw¦\1fÛo\1a%H\9f\87\9cïênÏ¿cËp\$4Ñͺv@,\9d\8d\923«ê\82V\ 3R\8b\88[íJÀ¾}×Õbå*rÅ\80\9a\82\88"eg4¢½Ðd\1e¤áY+ãûÇ  Ädôrå3¢¾àÎU÷(\eæð\9dP±°8Dø¦ÊÂ\84øL   ë"Ý-w]Å\98H×X\19È\8d\8ep'}C04o\1cW|Õ,\81U\8b\88¼õR\1e~'¨Æ\\8bØ\1dS\99G[bLÍ \v\93MKpò       \91:ÀÍ    a\e\17¡\8b+u¬Rc\8d\ fF\9dµ \8e\ 4
+p\eÌßQ\96©LµÌ°_i(\aà\võx@è\97eºrs\11¬Û\bpOAl=qhß
+Àí\rêv×on\90\12K\8c½ Ü\8e\11¬4\9c0\fõoh6¾rÑ©Tm\1dô'\80CZ¦\ 5u|v\ 6\8d\12\94I\ 6øóC\1eÊ\93ÿW²ã\8d\1c\ f\12ã0\13åMÈ»À\82`˳²Lð\8aþT½Z«Err`\16yV\18}xeH¥âh¬\13)\aÃ\ eù\ e\9bË[`Zº\1a\9d\ 3\83bC\8f Ç\ 64®²,        ï\ 50,n­¯\94\19W
+)`ö\ 3þ\97\8c¼e\b\84ÆúÓ×\18\8bÖX{\97\86\1eÊY£LΨÌ\aDr©±7?ÎSnàX<\14ZwÆ\9a\82\85\*\86\ ev\ fö \ e\8eR°ª\8eY`Ò«\ f\fDO\8c«mµ\84n\fÇ\15àà\88¯ï#Ù×c\ÿ `«<¹Ó\85\87Ù´OäÌϺJ/\9fJ¶0§]g¾{ÑèÇ\9c*@Ƽa\8c¸Â%¤M¢ÖfHÇY\1cåaÜïi\ 5\94J1k°Z]3þ\86\1e¼\8f[\19;8\86ó\84v¶µ\8bÁ4WÐ\8dW\aáºÝî/ê¤/\e\ 5\8cË"d\92 ·Éϳ8$Ø\b0ÃZÙ`\v\1a1ÿÂ\1aÒ´\148ïÊûymÕcHO\ 6¿q\83pªìmÑR\ f¡\8b\96®\ e\95)4\85\r/1+h|#M6O\810\14ìu\1e}g,øzÌÜÉY\7fa]=JèÕ\7fy\98\85\ 4çú¬E\952¤ô)Çq(9\ 4ê\7f¸¾¹æÀGì
+\90;\8e:!\9f%J:\81\ 3ø\fqe\8c\ 1h×F¿\8b³æóùo@\ 3åvBl X\83)\ e⿪Ë\b\9bÄV\87¥\1eX\ 6®NCέ&K0K\fX,±Å\12\ 3
+\95û~\19\12êO\9b\96v²Ì\18\80&©qN\91V8¶KÐ\89Ów3Çäp$5\12óëÄÆ\94_¨ÒófÙpw©G˨ØÐ\9a\ f6d\8e|[ä\ 1ë:\16\rê\1f\9f\12Z,'þ¤\1d\84åñÝ\8e\19~ÍøqbKó\9bË\1c\142\1aúÛqX\ eÕrWc¡\9büG \8fJBc\9fC\9d@º"\ f 
+\rÆ¿ÉWOð\7fd¶3Ó\b¸Ñ7fJ\85\87¿\93aXY\8b£/\ 3³ã¥\ 4¯+\19v\90\ 1\ e\11ägG]×ÁE\89\9f@\e:3dªÌ-¾ä\92\8a[\18\98xG\86_[G\7fCµRÀØ2E¹ ò\90³\89¿¼´³ðßSÁ\97ØËl\1fz\89Ô©(\98Ü~\83¯vª¬P\86\8a\8eðYøI\96~
+\f\ 6,\1elÒp~d\16\ 4\ 6Í\8f´\14izËC\8eR\ 4ft;\fÎ\v\0\vâ=\17
+ΤL\85¡Ô¯,íÿæý\v#\11j@âÂ[O\16²z×ï«X\ 6\83B¸Z0çx/Døî²Ï¢ïã\1d\9e\9cA\14T@ð\ 5\a\ e\16ò>G`2ÑÆô¹"©äZÅ\8f\7f\1d|Ûy\11Õôò«â\88A\86×\9de!`g,`\12,þó\83Z\ 3\9f\ 3V\8bO\1aÎ\v®ÔÝÀxUj\a7\ew\15ÁR\9b!ÏÏÊ<(
\bZ¼Í\87\91C¨Ê\9fúÌ\1fÇ ;Y±ªüèÓÊÛß3È'|çh\840G\95\91Z|=0BßÂ\7fØ\9fR2TøòëVC]Ó§C\14VZÖÁô\17\80'\b\ 2\10§¤
+Ú4$Çóå\06\a\7fçBFH\rÆqð\86§P> ÌÈ\83i\f   \9ecʲ\84ö+$\ 6\10ôQHh¾|æ\9cF\arZ\13M4ry¥£HJ¶\ fz\87\ 6Q\f¯²i<ì\a\88¿bZë\87lUЧñìf\ 4È{q\9e\98Y\92ú\80¤º\98«{\89\9bö23pÛ¿G\9bï6Hë§å\85Õ§o0¯â\8e$S\18\b*½­¢\ eÕé"TÝN\15íg±6\9aÌ2qUò\8d\17õC >\80­©\18Ø\9d Kn¹\e\90~Wâ\91êkÇM\17\0)\97\89ü \9e¯èesq\11DiuCØ6vâ@\9c \9aÙø\96Ü?ðW\8ab\8d\ f\84mJkIvrnä\10×\8c7\89\11ªa\1c\e\9cn\85Ã;\12²«À*$.¾F¾U\96ÄG\1dü{£¼¥Çóá\82ô~Dê\11\11¯\10\83\10r\b\19ÉÏ\1dC'ú8Ù\1e\84ý¿'§\86t-r\10(²Óáò\8d\ enkú\1cq»WÇrt\ 2eÓ×´´1µT\ e£ìLëøe\14\9eó>\97\´Ï\81OtÇ\9c\88PlýØHÝ\84i\84q|îá\84½kÓк§Û\1f\13©2ù\87\ 3ª\9f\bfóÁ_ MÝ_ûNI¯\834\få­zÏíÖÆØ\8c\8a]\07¡?\eêØ_bôä~é\pN#Ð\ 25ò©ÎÿJä\8dgt Ì¸\12ñ>ÐSó õÌÖ\8b4V      Ï\96k¿) \1aÒ
+ئ1ä¿G¸þ¤«\89eøcô#}¶\15\85àE\1fµ%(f\85\81ï½Ô\eí$3+©Âhü\1a\8eÃ^ø\9b\10:\9aþ«0NA\81\ 25¥xw\10FÐÏ\163B\rÁÆ¢]ußúë,µ×\15·m¬\12,õ&Ù\8fÍ.}\81\83¡iy
+o*¿AÛd}]2ôÎxM²¨`]B@\94ÛJ÷[樬@gár\7fu\ 6+\87¸ð\87l\0\98ç\94bQ\1cÖ\14Ó\µ\98\9fn\ e´\12(3H\85Äékgf»öÉÝ?½ì\83ñ/\86i6\91\88\8f\18Zz)¼#çÃøq³\19÷\v\8a\8c\fì\r\ 6oï7å\Á
+üM
\84·\13bOÙËXbm¹mV\97­M\17¿î2\87 §X\89\18\17Рé\16G\ e)\91\18°á\86î6f\8c\96aäï!np¼n¨¿\80Ó\96ÌN@Ä\90å\8c\8dísÐ\16\80ã\\95\13waÌ.åçï\ 1BwLtQÑÙJ\99\90b+\86B\99ÿßJ\94\96\8e\93t/_\1d`\ 2Ão\11ã\fù!\6\88Ùö)=¢]ù}\rb\f\9c@¸·Dg\v\91f\7fR\95^³s\rçF\96"eF+\86\10\1d\ 4\91¸ð8t\873ÿ©\8c¹,Z,¸a;\1e\136d+\ 5v\96\96\r
+Ät\88ÖÍ\14P4!\ 4     G)\0P£ùÖ &ÔÚ\ 6áö\ 1}B ÛÝ\1c¾\1e\92Âu\96bNæ¼¶È¥\9a\r\ 6Ez_N¹»\18\12\96ÓÌ\ e\12\0*\8c0,zEU#3ây[éÍfR¡!äÉÌÂáN\17\9a'l\ 2\ 5       Þ\8dï­ÎæAÞô³âÛ\f|}ù\8a=\1e¢ý\8d\ 2¡Së\82£ûP\8c^@-%qqèqÓ[T"\9dÚ_\8fbN\\r\12s[ò\ 1dB\19\8d-#\9aø*Ô«¬ã>AóÚá\8aá\8b¢ì/ã*Êâ    á/?<\9f^Qɬ(k4\vU)Y\fð I\8b£\1c\b¡9Ù\17\1d\ 6M\80;O0\87\87{\ f\99Ð\83o\89\ 4@\9d\Î~JYAt\85¯ïv\7fÓ©\19\86\88ôJ\r\vöá\97\8f²ÝïxqoΡ#\8bÉùêß~Ð\ 3ð\8a¾\19¤/ê\14y³ÕP\12¹ãÒJÐÐmc 0ÝBàñÆ\18*\955t\17\9c\1c\11n²èÃë\10ÅSK\82p\80q\vÖãæÓ@\ 1Ö¹ä­\1d\88Æ\ e\14\85·9.ïäí³<ô\82°Ô?L\97GnsxÌÝ\8bpZ\9a\94gÿ\81r  ø\9bd«ÈÁ\1a Ê\96\r\8e\e5\ f\1e\15NO^7\a¢Û\ 3Ùø"\88jÏ´\94\11\82¤\ 3\12hêê\89~Gá=ïæë\120°Öóp½Üܧ\97S\8b\13Z\196Hcì\82þû±\8aµu^\ 6Lo\P\8a!\84K\87Hc\18\12\17µ±  ôs\96ehDi·|â\9e/
+Ñþ1\10] k1\8dos\ eâO¼'£wí\8dY¹30 Ê>²\11,\98\8dΠRë`v.\ðDÚ\1fæð}ì áu¼URqÆ|)1\88ßðº­\8b\9aÙÀ$C\19\97\r\8e\87\b\81\8fµßa\8c
+9\10¾\1fÃ\14ù̹C\ 1\9bÙ\1dQ§0îö\Ú~â\ f\92~®"ŧÎÀöÍE»e\18ê¸] '\86Érê\86\16\85Ù÷0g%M[pn\88\87x\b*@-¼\92\99\19T\aLáé\87øåiÛxà'¾E+Ã\1a/\8eâ{\82G\99\17\99@\e¥o\90\ 3\8b;\8c\f¡{ðÙ7\83´}\8f\19ÊÐ1åm\ 4#H\vWL¤wët¶÷]?3x\16`\18htq+  ßX        ã+ª·yl\ 1+2Õ\fãdOg8ñ\17¿\9a\81\97\r\87!\ 4½9©ãÉ\92Æ\90EG\ 6\ eícB¼'m\81ôÛ\84ÜR(
+6E\91À\95þ©\b\16Ú\aÕ\10\9aåN0t
+\14\7f<ή6z¥ÇT¢^øÂ%\9cÀß3|]\84\92£jt8\15u\91C.%¼B\87»Ýn \14\ e\92Õç\83Ä\18\ f¸mÁ°bQÁ\vÖ\87\rUnÀ ¾fö¿\98-\e\83\10LOmð­Zß\ 4/Ññ\88Õ\80Ø)+ÇÎAç× ú¦Ù/\vk|\ e¿9±\18ç\9b*F&ã\9axàñÜô-Î\1c\8eí\ 2ø.@êìe"í'À\r!9ªx\14Ìxø\v
+>û\91¯Éú­;WHæ|,öRW5¾\1fP:Kt\8b>\8bùÇ\85ñ\1dBá#4çÔ\8bßÎ\199ÛÄiö5[e\93\19b\0(8\17ÿP*
+äm\7f%\0`ðo\elÑ&ËÃ~K\91±Ý\92\16³& ÿ«12?w\12C\1cä×*3»Þ\1a¢éC Æ»ª®ê#0`ïäû\197\7f2T^A\ 3nÈòÕ\ 2\rÔÔ=²\ f:3Ö½»\a-å{ø0\e\11t\ 1Û¡\83Â*oò       a\84ÒúñDÞ©\9c\87,G<Y\ 6|X\96êg T,)µþÉ\ÛP\87f_|#5mÇnÆå\98¸\968©GH%Y\8a&\ 4âÿ,\80Ê}&÷¸8}7e\91K²ëD&è\lÀK5\97\85ÃÀ\94s(¸e\19#E©±\1aÕ3üTnOKð~­\9d²¿\ 41ªÇ~\92«¼]ÐÙ\84ñ\86V\85ð¼\19\9aE<õÏa\88p`&\1fjkre¾âåKÌ   ¾Ræé\e\9d\ 1\0å>ÍU\ 4Öf§iT< [ò,\ 4½\84
+(ôØÍÅ\8965Ñz¦A¸\11\8f¢\1cT|³àÆÒxJ^\18C\944MXÏ\8e¶@C\95Ü:]U³«\ 4\8f\82ù\961["O\85#ö0£\9b\a\7fÊ1\91\14#\1d,
+)\89Ïê\8bùDì\1fã®áÍH\8bã\9e_ݧ>¤«[ ñYLAw¥:¥¨\83zá}\ fþ$\ 5 8\83\85\83àÄZ\9a}\ fý¹©d\ 2\ 2»\ 3\9a\85%e×ü\18ís\95ølý~|EòÅq\84\87\90ù)g\9dG\9aM\7f¬cðºq\8d\1f+,uçKîj¦\96\94xB¬\82q=Rèf§fúd\aÆ÷S\e®\93)\8e\84«\eWÝÐÿjY [\\160«Wl\9f\0X _!ñ ôIZ\83nÝ¢8\8cI\17Âl¤\e\14BDº¶eAѯhya\82;ÿ\95Q\ 5\16\rà&É\87\ 2G\1a&"@Þ\91q\ahmäû%Óð\8faïw\ 4í(fÿûã³Ï\10P\97\ e\85»ßAðcGéâçý%\10pú¿°¾\90&ö¿"\89ñÿÊå"ä¬\ 2IAýD\10\88\15ä:\91ëÒ
\8ep\10´u"\84ö
+¹Ñ5\12\16Êt"B\8d\85Ú\9aÈä\12\13©X\16Ì,\11*iLÄç³\10\9bQ\v5£Ø\82B©[\90\9dn\8báB\9fÀ\X¹X\17ÌRß\85^KD\ e½ÐÈ\9a\17ÖKï\ 5_ß6hY"2\ 40T\ 3p÷_@-þ\85\8e'\87¼¿ ô\18\18\83A>\12y\84a |DÒ\10C=\12\91«\18*"g\f\13\92Ç\90ô\ eP\1cÃe>\b\ 3\1d\89\ 4\r3\8cû\88\Ã}f#\91\f\ e\8bÈ=\9d!vÞgpV\86\86Ú\88\88䣡K\v\ eÁ4¼\95¡\86r!2\95ª¡s\8d5\84S]\83Q-±¡¾j6P "!Ö\86y!rêÛ\90;\88Ü \e\1a\81ÈÁxCï\87\¤o\88ÿ\81\83+\1fÂd8ØÒC\18+\ e\10æ\1e\aÓË\81\8d\86¬\9f\1c*ßa\ eÁ=ç`;\87\10\13:8r\97{\96\ eL\92êpwCîu\1d*6ä\88e\87x3~·CC\réõîÐ|\86H\0\97!2\11\ fÅc\88ÜÈCi\18¢|<´,Ì\83¶/ä7\9a=ct!\vÄ\83¹\16B\80=øb!\94Ë=\18\11%s\85\ f6T\bIù`;
+a\9c>\18}B\18î\83­&\84QùÁ\19ø/÷C¼+\1a\ 2\ 6\869Bòçb"\84ª|è\15B\1a\19\88\8274\11\84~x³\82ðÌ \91ä§ç  ¹@¤O\8e\87ª\ 6¹aÌ +\e!ú0ÈvùÕ\ 5\99a!\1acAÄ·5\ 3ñPAdÔ\10Í\13DÕ­\ 41ñ9D\17\16\1f"f~ÀX\8d\13\85\93\82 cP\11Í<\906\16Ñgº\b\11\ eäö0\82;\ 3\893#Z/\10ÙjD£\ 2\eÑ\97@êÎ\11M\bD\16\1eÑr@TÊGô0 r\81Du±\9e-$X\ f\90\94\14\89n\8b\85\8c?\10Æ)\aj\94\0ÊçHT1\80\ 4E\92\18\e\0¹+K"]ÿãì\95D"þã"2\89*úÇQÔI4¾?î"\94\1f§^JtÌ\1f¯\95\97øcK\95hy?f]\89\ 6¶Î\12}öã
+.\11U?\8e\92\97È¡\1f7Y`" æ5+&¸1?\ 4L&ê\1f\ 6g¢ú´Ò\843\81e\13q\98&غ\8f\ 6¼&Ò[K¿Ðù\8c\9b\0\82õN\a'À±\8ffW_\ 6Ê£\9c°&\94\13±¬\19úÉ\9dÈ×\91¹y\82dó¡\0\9f(-\1fkç'*ÉG\8d\80¢l|ÈyAQS|H\80(\14uïÁ^¡ \13ø\88ÜCÑ\95ï!ðDQtÌáæ0\8a\1cE9÷xJx{Ì\85\14uµÇ"1f3{ô>¥\88a\8fv\\8aÔõ\bT¦ØX\8f»»)\ 2Õã\1cì\14±|vö§p*=d"**F\ f\19HEÕè!±   =¼e*Â=\8fæ£\8a\94ó\88êXi\1e×U«È\94ÈÛ\ 1\rV\8c0\ fÖc\85»ò   Za8y0³\15N\91\a+\áðx\90TW\983\1eL\93âá\ 5yE\9eüë\ 2¿ð ì+ª\83G#Á"\16x\ 4Â°Øø;N\15\8bJ¾ã\84c\11Ò;NK\16mkõ\85\18\8cåe\11°;Úq\16å¹#\f\83\16ï¸ã^iQ};\8e¦\16¥¶ã\f\\8bfí8W¶H7·\85iõnÑ\8e\0\17½Ì\8e5qQ\83ì¨t\1cvX#¹\bpÛëµ¹øø\96y\9f ý$]ää!Åú|¡u\ 1("öm\17ÿV\87²ßECªC\1aò¢5\9a£\92.\11£\17Â`«ËÛ\và¦Ãy\:ªÈ\17´¤#ÈöÅàè¸\¿(\89\8e+ú/Z¡ã\15\1aÐ1sÀ(ø\1có\10\8câ;G\8d\1a\8c\86\8e0´ô\vÃ0ç\88\8eÃ8»9®A\8c\8e\9aãZ\89\91\979Nv\8a\91\ 6s\9c\91\8b\91p9NUÆè^9®ìÆÈ£rÜpÇ\b}rÜ\ 1d´,9N$\91\11Sm~%\19\17!GU\9b\8cÞãèê¥\8cF\8e#¬VÆ4\8dã\ 6\8cú0\8eã\7f\19\15\8bã\8aÅ÷Ä\91\83fh\ fq\1cÖf0;\1c©~\86#5ΨU8*_g´\15\ e%\7f\84Ã\17=£rp´ÙÏ\88\14\1cá\ 5\8d½Àq\98C#øç\8b\86#ÀA\13i\98ù\e\9c\95\86é}\83\8ak\1a\1eó\rZ\92î\r\1fø4ê©7\82ßQãcÞ8ma\13\1c\12\16o@8«q¼\e\97|vcG¬ÑU7&_k´Ð\8dJºF\aæ\86âר3<l(\8f\e\18ìáFÌâ¾\8d\1c\99\8d\86n£*Ú¨ë6ôecÛ0¡ßØF­¯6Ð\93Z\e~0º¢6\92\91\87´ÑõãF\9b\8c\11C\ 5ÝÀm6b\9dÝ\18*Ì<P¼\ 1O²á]o\94\8d\8d\eMb#¼¿qNØ8gàh\ 1l\9cèÁ\11èÑgó\96¢EA©)\1aÃH3\84¯A/\88#$à \14G£yÊ8\84T\ 4{\ e\bv\0\7f×pÔ\9bkøkÐ\89\1cGº5j§²\9dÈÁµ\1cràeÜq\94 I\16ÌãÐ;\\86Î8J22\8e\11·Æ\rÆ\91\7faç÷Lk´3\1eék_Â\8bã\91¬ñÅ\aÖØ\fã((á\ 19\8eS\1dSY D±ÕHPB"¬ÕÈ\87ã(¬\1a/SF5¶/\8eúé (°NL55\9c0\8e\16R£}"\98\1dj\18yqð~\1a15qL\89ö:\r\93\8cM\ 3ùÄ¡Å4\1eÁ8ÈóY\96FzÐ\93\86\86\89£áÅ\88H\ 3\7fâPîh¼,qPÊhdê(\1a\81&\87F\1drBùB¡\ 1(ZÐ\98s8*¦{²'\e£ò32/q´ýÄ\85e\1c\15ÅPóÞ\19\8cv\1c]P\99åqÌ{¢õ8Þ|Ì`%Aèf8_ð±\19\1eû\86\e5\83È=\ e\97$ù]\1aG\1c`±âø\a˨D\1c\15\1a3z\80\fÇtaF²'1Ëj80ø2³á\98s\19·\848G-#;1,CiÁÊ\bX\9f2J)\8b2|ä Ä\93a\88:\93\81«áP¤\92q¥     É`²ÇÈè;\ f\19Þ\e\8e\90\ 6\19\11øý\18\b\1c\ e\8d\1eã_\9e:\ 6\85  G1\1c£RÂÑac\b\9b®g\8c5¸X\1fÞ7²UR\91ôöb´Å´\18>\18«\18H\r\87JQ\8c\17J&\ 6wÃÑþ²ù\93\19r)7Ä\18ÎíÃØuÐa\98K\1c½Ö0\1akÅ0\80&\ eM\16Æ\9b\18
+\83Ãñ\b£aù`8T5\18 ÆáÐ-\18ÿ\f\12\f\92%\8e\92\r\8cf\1c\8e\ 4\86Î!\ 1Ã\ 4\88\ 3?Hð2ß_\18r8B;6\1cåº_ô¬å\17.\ eGá¾è²Ä\91m8\1cÕô\85¬CùÂ#\96\vK\817T\10Ü\vÖ.\8e¼°\17\8dµ§\17@/\ eÍóâ\8dXyÁ\91M±OÌ]\88ú\ 5/\92\eÝ.\8eâ]\1e\ 4ü\7f\89£+^(X¦Xº»8t\9a\e\87\ex\11àÇ1ÿ·qx[£B"à#\968>\8d\17G\8d\0ÇQ\vwÔí \ad¦ä(¤N94ÞÅ\1d\97\83\8a-s\18î.bçæb¦A(_A7\0\1d\9eã¯ìBsçº0âæ¨§.ú\18J\17à6\87>èâ\19\1fç\82\91ÍÑñrÑí6GÑ\15É=\eP\T sx6\\10\1fs¸       .x\8c}\vg-G/y\8b\81\8b\v"Yp\v\19-Gµó,\a²¶\b\98f\8bkNl±xÍQÛµØè\1c½Ç¦Ð¤Z\98M\ fµÀ÷9TL\8b\13C\a\88ᣣq<o\ 6\141\1d\9eÏ\82±P\87­§ÒY¤«:Ê\9aEݬ£`Ëë\90\88Y\\8a\1dD\96EÔÙÑCY(^;jG\16;a\80çcQ\0îh\1a\8b\8eÒ\1dyÅ"VÞñD,\ e¸\f\8bE}G\rÂb\ext\ e,
+\f\8fÞ¿B±âQ«¯Ðx<:ö
+\81\93G\1f¯P\80y\94#µ+r(\1aDW\18\19z rE`\98\1eó[qnÝ\91\15\87½\1eÙZq7Ì\1e­´âþíQpVÜè=ÚdÅE\83\8fX±âÚñ\11\ 2+Nuùȼ\8aó\80>
+®âDê£Ï*îÆ>Ú«â2¦ªb¢ûè\98*vÃ\8fn¨¢2ó£Õ©\90T?º\98
+\1dïGG©\90Üù£\0©Ð\ 2ÿè0*´´\10\15öä?ÊAE\v\ 2\90\büáõ§ 5@lz
+ÊZ@,l~b\81@Lq
+¾Í¦pb
+$¡)Â\8e\91)02\10ý\97âë\ e\84\ 2\11AÊ[
+QM\90ú+Ŧ\15¤aJÑzAú\9d\14ê\19¤F9\1cDMR<\99\aa\8b\141\82\90&H¡Â"¤\94G1 \8d£è¿\12b¥cÀ\ 4
+q|Q°©\10\9f\15\ 5+\v±WÞ\854M\14ÊÞ\10žº\90\9e\1d
+ɸ\0¿$C!­ªB\91\e\vi\84P\94@\854\18\14*L\10\14α\90Ì>ó\ 3\8a
+*Ä÷\9f`ÄBÌú      B«.Äß\96Ñ\11C¢øÄ\r3$fO\1c¥AO\f·\fi"O\8c\r~'*´\8e®¾do\9dHzH'jS\86\98Í        :%9á5Â`Ò}\8aM8\9b\86\ 4²\9b\88\10\92A\0J\1a\9b \19kMt¸¤&üg\93&p¨!
+hâ¤n\b\ fg"­"\19\8a\&"Ý\90NÉDÍÂ1á\99\e\92tb¢CI\\ f\88  \98\eRñ%j³¿KXÍ!Qæ\12½(O·Dú0$@-qÒ-K,Ú
+K\fOy9®\\89\ 5\13V¯y*Q6\88\91C~ñ\94h(\87ô*%:0\1a%ÀË\17JLnÕ'1²ÓI8²l\12å!\87Ð\98DÈvÈkIüp¢$æ=#%±ÕCJ\12\8e\1f¶k\\90\84\90\10\8f\7fH[\17\89\88\ 3X"\81UsH\fÙCº       \89Eÿ\902\ 5\89"!R\v\90\10/\11),¨¥\8dÈ\1c##\89<\97#*Ò\12 ÜÚ´\1fÁØD8wDÜO¤MGÈ8å\88\95F\8a\b}77Â\14\15\11mhE\1a\ 2\ 51c\91m\1aqyÀwFhÓG\ 5¶PF$m"\8dò¤i\1cFÈ/"\8a\86\8cÌ\99\86if\ 4\89EØ,\1a     ³"úW#é+\92i#ê("¸72\9c2\8ex}"¸ç\88+\1e\82\80\1d1Y"\88\86\91\bêÔ#\1eG\ 4U>âNDPÞ\8fØ\15"¨'\90\18\ e\f\12\9f>\ 4W\85Ä\19\ fAyHì\95\89¤\98C\88û"©Ü\1038\922\rQç I]\ 2À°\92\84\0C\84LIö-Ä \97¤r\85¸Q& _!\8e¤)ÄÈMRvBì½\93t\94\10õ\80\92\b\ 4!\B\94t\1eDûHIÁA\84Ñ\94¬/G%Þ3\b\8eUâò\82 j%¦*\b"_\89\9d  \82ú±ÄËì\11\15Zâî@PÎ\96Ø2\10\14q\89+\ 5\82"A \­K²\v\88\18½äq\808H\19@ÌÛ/iù\1f\96\1fZ\a\13W\7fË\88Iu{oL\826³¢*M
+\a \14ÄíÃ\96óCò]R\15?\L\r0Áp8f3ñ\r\1fÄ\82\9b\9f\ f\831\ù0F\9a\98\8b\ f¤¨\89!øÀW­\89§÷À>£p\ f\89Óg\ f|-\13Óõ@å7ñS\ f\f\87\13\93ô@(äÄ\ 1=P`N|\9b\av\0»åÁ<q\9de\ ewv\ 2\ 2ú#+\9c,\90\0À´\a\0Ð}¿uk\18\84\81¾ÐÑaà\87\9a\8b¤Ã\88þV\92ÝäMrT\1cKÍ"\0\0\0\ 1\0\0@\9f\b:        \94
+\1dÚwÆ\1dç\9b¯Þû~k³·vóþ³¶\17ÿû3çºó\8aGý¿\95\ eµúÞ^½µVï\9dïµùwnûå×Zk·Æ÷ÚÍÿ¾ÿî\8c;ÞÝû[sÆ\95\ eÅùWK5Çx{8ã\9b¯þ»âQÞïö¿âÎ\7fç\98ó½q·¿oÍw¶¹âÑ®¯þxçj\7fí×ZooÇØrÿ«¥ÿb»«µ\17[k«ý\95\ e½:W»õÝýân1¾\1c\7f_íýþvËïÿ\9dç\8aG=®thϸ²3¾\17gl·÷Öv\8fïÎ\19ÿÛ\7fµvwÞ}µØn»uÅ£?W:4ÿ[!=ª¥;{\8c?îØw¼;æ½_­5§<÷û=¿|\7fÞ¹å·s̯Æ\97ÛÛ18\13½ïoÖ<ÿm±õÝgï¿\02\9aßë³í\e_\8fóþÞú»e Xv0þ÷úÍ1¯\r¸o¬w×6×Ï\7fï{ï\8fýå¶²@\12õ:¤\87ö¡¼¶]ç\f[}¢÷Ð>Ôj¤i\ 3\11x\9e ø\8dX²Mê\7f0ÜÅ\90¬HÆÂRÄ)ξ\16¨yÀö$é¦\0\18Å\ e-Ás&ºÞW^¿å\19{¾­¿¾sÛ½ö_oﯶ9W\92F|Üý¥ÜæL-íºÞ\8eÚ\aj©¨ÔI\81\ 1Â\ 3Xù±À\0\91\1e¨4\ 2ÍÙ\80r|õ\8f\1c\1fT\\99\1fJ\13MX2Qµµ\ 1
+Y\95æÊ,Á\13\ 5˱\ 5z\94%ûH\ 1\eÊ/9\96\1aJ\8e¥ÆblW \80ÍD\9b\88bÈa\89d`\80\rh.XQ\f9g8cÉÆÌY~£    Õ\bh\0\8f\92F/¥LBSö\19 ¥HÄgh\9a´Z\e1äL(\84\f¿ú¸\14\84\8dåYZ\85æçÁVßY\12\19\9e&ôj\ 3tBe!\85\0á¹\ 2c_Â\84B4
+\95\ 1`\94!L4óÛLóÖô¡A.µÔÒKédb©¥\13:¡ø¡A\1e\1aä\94ÍD/õÐ:\9aÂ\96îR&\15@ù©B\10(\9efXz©\ f\86fzéî»WK5µ\ f\ròРø¾L»/Ý\97ÒL³ø\ 5\10Y{é}h\90\87V)dR\82\ 1İD'"I\86g\89U\82¯ó\ 39´£â7®Êï\95y\99¯Õl4\89_\0\11­'I³½tòÐ:
+\99°d³\91DëIÒL'\14R\82¬RDKÐõɾ\10}\99³Ró\98jL±ç\9cÛ{ïµ3Rö¹\9fþO¹íÛZl\82:P§Å|×\0@57A\1d¨öîwÆ è¥8W»¹Ç?w\9boþÞ{ëýŤ\ f,1§\0Ðdï­ûn\8bµåYç|¯¾Úîëý\8b¯¿\9dwÏuõ\7fëÎñÕuw¿w\fõuå\9dwÚsö¼wyß\7f¿ßÞÞ|\7fí>û\9ewÍ9×Kóýuo\8có¥Øj|ëïô¾9_þ3ßõ~Þ)î\16ë_óö¼Öýw»½Í\e\7fË1Æ\99k1\14½þâÞiç¹ß\9f{æÝfmûÕ{W~;Í;ï8wößϵ½½âýñÆÝ_\8fy½¹^ì1õýöÌõõ]×ûÿÚñ{»\8aïÆÕ^mÅñ¥øã_/÷6güëö¼S|óöVÞÅÿwªùß\9b[\9dq¯ßß\8eíßWÛ¿±ý?[\7fsÕ¸÷\?çÝoÞsß~Û}kÎ\9dÍ\16ï®ûý|ÿNõÞ5ón÷ì5í¹»üÞÎ×{»\8b;»ñõ\9d\7fL/îþ½\9eßî^Ü«¾Ú\8a~ÜÝmµÕÇ^wÜi+|»ÏwÖuwÚ\8aWÜÑk;ÚQ~;ʹͺj\9e?¶¶n¾;º;\9a¯Ç\98wßóÜíÎk+þõÕbùþ\8bi\8aKq)nã\185WÔZ\9dõµxëî«õÜóh¿;óëoÏ\9dÞίþ\1e÷¯³ÏZ\fE7ö\9ewÜÿ÷_Wÿùõ8÷¯o¶ÝæÌ{Ö\98s̳­º~ÝQëkî(D\83>×@üg:ݼ£¹ÓÛ;õ\9dv¯¡v\865\95\16óèÅ\9eß}·æ\9bßz;ï\9dþ\9com¯Ïþç¬w·¶ZPÆ\7f\r¤eîÖ¶£\k\99Îo\8fkï(ßZFwÿâ«e2å¼×Lï×2ùæ\8f=ß¶Ú\8a;-ã+î(ïwï\9a»Ý\7fÕ\9dí·î®ëÎß\ e{-f½¼/ƶóÛQ¼;ï;\8a\9fú­eèÝ[ßú©¿6×\8bµ\f½:ß®ÃXËhÜåK7îîÝøz\¿\16Û¸Óµk.j1$j»6\8bÈF\19æA¯&ÛÙV\7f\7fÍ÷Þ_Å\14§­R\9c\16ó)\8e\85Z\0alëï4Ю½z\9a;ê)ÿ[k¼kö9o®o§;Æ\9d\ 6Âõ_\8f¿ý\9d\83\1d®1|¯ÆÑ2·ÃÙÞÍ÷θ£ûf_­¯\19ãNËôνç\9agÜ;Ý5\ 6]ýoŽêmë§\19g~Õ\9fWÝѼµî¼Wý;Ê=¯¿Ë\9dr\8a¯Ï9gû­÷Øö\9f?Ö¹ZÌûõÜ{Üï÷Ù_\ùç½ë2î[çìíÕ\\1eµ¶£\90}3]þ Ü3¼~úéåÝãª;Z?ý¸ÓV¿zÿ¯æÕÓ¬;º½ç¹z\9a9θj\7f7í¸£\98jÛ}Ý3¯¿ÓVù×ßí\8a鶸zª/½\19Ûj¯Õ¹bÌëÎ\97ö¼qÕ¸«üV\8d3æ>ãúogë¿]¯þúÛá«\91\1c³PôR\9b\ 2Å\0ÎÿÁ¤\bR\9c6\10\96©óÁdX «\1cW é\1c\13&4æÑþy¶Û請\9c\9dsûïÖ\9cîÞ/®\95¿<\95§­l¿ôïU×ýN[Y®\89^«ò\ 3KýR\v\12)¦»Z-F¿Þ¹Z\8e9®öoìýýw_½ïö\9f{þ¹öúb^-Þ\98cOïí´\fí»Òê\7f÷»{o¿¶âÛwݵó«ñÏP{»]ÿ®\7f×O­çöv\1a(Fy\17Q;\130z£*6fXá¬\ 3\8aªOv\96#)`Ã
\8eK\16\86bé§8\8dúK-§:Å\99òý\9cãÛ3îèý\9ewÊ9卑wEííDj/ÈcпÚBDó<jµ\96çÜ[ytß¾qGq\fEíç½£ÚzÞQ\8c;z«Õ\\1e½¿£\96^Måi \fµ·Ó@Ôv\9d½\1díøæîþ_?Å}óú­½ö~ìéÍZ\8cvz³¦¡¶¥eè½\9d\ 6¢½£8k\19ê?½\97n\ f¢\1ewôÒk)Î\14ãú;\8as×i \8f;º­æ¢V\13Qk¯l<Ï\99÷ÐÄQ\15\v@_\96l\93²÷\83á0dlÌ´LÙW\9aN\19(ónÇÒ^ñJ6ã\9cð\ 3\97\ 4[(26fê5\953Ñ#cc¦\13       \10p\ 3øÊ\8e½2\19¾Øæ{3&\1eG\91C     à\fW\1f9R\ 2Øê\13U¬q\14[#\8b%@ÀíöýJ\17k\1c\19tµû\14 àV»Ú«ïô\9e\v\10°o\97/¾ø\ 6\10\0\v,1¦\ 10o\82Cx\9d\bjll*0\8bF"Qáª\ fN\e0@3&\e¯qa\910$\87\ 6¯sk\ 2\97\92\82×I\1fǶ¥DÛ¶\11P\16!lÛ6    \ 4Ƕ\95\a\ 2Û6\80ÓR\92mÛD\vƶåRÀ\ 1\16i-@¶mÀ\80\ 1\ 3\ 6p\9aÄ\12{M¼nÛ`\87\86ÎÄ]á\ 1ç\ 6¥\0Ù\180\80tO\13\96ò  Á¡ü\rendstream\rendobj\r19 0 obj\r<</Length 32300>>stream\r
+ÑàׯÀH8-Kä\19\82\86ó8Z\9a\a\8a\80j\13ñ\10Q\fpÄÛp8³Â\84\19u\13/G. \13M\ 1gaMªÍ\8bä\ e|@%¢\95áÄ67\19ì_ª^ØÛ\7fÛ¶ïQa\99Øt\v\15%\98áln·m\9bÙ\91ªf\97\13\93\19f6Û¶m \ 3Û¶å\ 4\18×!-¶m##Û¶\r`ª£Ãi¦
+dÛ¶\16ÅÈc
+\16Û¶-\1eÛ¶\91YÁcV\94\95\83É@t!ðÙ#8ø¬&6\ eǶm\90\8a\88\93ÁÞ¶m{5: \81×ñ\8b\14¸mÛDWDÇ\98¶mÛJ\81mÛîG¡4ÀÛ¶m\ 3D\eÐö\9c¶8xlÛÂ\11Ù6Í\ 4\ 6\f\18@\82:\rÎkÖ ò\ 3 B\9cð\9f\ 6"\8a\ 1É£\e\9be(·-\81 \83\18¡VÉ«\94ÜÇ!ø\1eÑD\93-\96\86\1d\8cþl³m\e§\rP\905®@Íö\9f\84\99P
+\r üd¡71ÝK?\18Ê­G'¥Ñ\86D\ 5\80"\19\8a\19ó\vE\f\rO\19\86~0\94ß\ f\86b*\vé(£\7fß\ f\ 6\14Éð\14g!0ÀWú`B\ f\0Æ\17\10Da²\ f½wUOS\84ÉB+ûHò\93\952'G3zP\82\8cCòËlî
+\14ÅqE\1f\1e°ò\v\95`øÉT±ÙË\ 4\9e_   ÊÀÎ5]14\81æB\0_Ù±ú\ 6ð\95\1dP\fM\eÏÄ\95ìÓ:e\9fóS\8då
+\ 3ÆÆòµ\1aecHc\\82a+<e ë\13ÀWvdcxù\19"ÜQ\85\91\ 1\8c²1´5\ 3®!K6fdái\82\9a\0\1e°r\ 4ÀYbbcÉY\85â8
\e38\16\96¦±%û\80®oD\8e&Xù\85\ é\92.\19\96+\13Ôà*\ 3À(\83ÉfÔ\f[#\ 5Í\19\15?\99Ì\15\9a Fö¡æG_«\99¹
+E\92üè9\e\ 3øDúQYHÏ\90Òñ¤,\10\94ÑÙ\18@9Ò\81\90ÊÂÏå\92\85\ 2©l¤²O$él\f\0\ 5Z9\9a\91ì£æGA1lQÙG]²0ÀgR\19ø\ 2\05)\8b\82¯\93\82åGA\13|\99\1e\0\0Ã\93
+d8Í\8f\ 3\93\85 k\96\9fwIò+M«Q£[ è²Ê\8f%ûÎR\8a£\19áûÁL&å\a\92$F\14g\1c°\14\0\b+A\8b] ù:?2å\92\85\ 1Æ\10\0¾R\ 3\8aá\8b\81üd¥    % Ç\11\ 5]ßÌ%û@ç\8c<g"ú?\98\97    \86èÿ`.=K\90Ò{?\1146\vY`èáñ\81%\86\1cËL\8a\váîk>\v\v¶{\90\e\9a#i4\89   c~.9\9aX (zâ\8c\ 4Iâ§\1aÅÎþ`²ÏüÒS\0h\1aÑ{ï\rMZ\82äGÒÿÁ¨J\8a=Öx»è¥\94U~£ê,?úAQEÁó\13G34)+,]4\80\95\f,?Ò\94}åIÿ\aã¢çl\84­F\19\8cÒK¢ã9ÃÐ\ fæ#yNqãê\1cI3\14¿\1a\92¬\ e3¿\98y\82¦\89\ 1EÕ79W¡æA    Ê\0áù\89 iwÔ\8e¡\v\0P$Cq%~*\1a +ÁÓüÊ\9eµ\1f)\18 \ 4M°$ÇðüHæ)\e9'hªf%{o'GÓïã
+,\89"\98á÷÷Ó,C\8e\0\90%û¸dáË\f\89ÞÎýY:[ ¨û­[ ¨\ 5\82.æ-\10t\86²\85Sk¿rÉB\0\80áI\9f<\16\b\8a^érð\14°9[ È¿Vá\8b!6f@1l\8då\88\ 5ªb\e1T\85çGÆÆ\fG32Kð\ 4c_ù\8d>\18\18(ºd\18põqÎ\97+$\9d#YJáûÁ\b\0O\v\ e\b\b\17\8a\1f\rOÙÇÏ\92(Î8\1f\fÌV[õ}\84\1aPT}&0ö%\88ßj\ 4\99\9aO  \9e²ÏjÔ\9c\9fG\ 4K\ fJ`RP\16\8açl¤%Ø¢V\ 4\ 3\80 \1aÀ\19\8aßL\81ºd!ý¢Ù\98\11E0seã\80°\1c=\98\ 5\92Êq\149\1e+,;þû\1d\96d    \ 6\10\f_\fÔ4Á\92$g%Úï\0\8bñ¿óc}'\18\ 3@˼6ã¯ùîZ\80\80\0\ 2øÿ{}uÍÜ\9f-\10\14\eÏsT­BѼ\0h\99÷\ 4K'XúÎO\ 3\8adì3)\ 1nl<ÍÙ*\0\85å\17à\82°Õ(\ e\9c`©ü\ 2ÜPe¦8\ 2³ü\ 2¤LYã\91âRÜ$Åißùi>>Í\10ä\8d°Æ\1aë_-õùÿm=æ\1a[«ÿ¿úwÛ³­¸âQk«÷ûîíïö\98ó\8dû¶\97Ûû»¾»ãÿµ·^\87j\8b¿Î|ßn³¿\1eÿ~í¾ÚþËõ¿¿ÿþûæöwîÿî½o˽¿\1aû­ûïÚîÏmÎ\9bo\7f}Ö>÷«»î\ek|ñÝÕ~ëï½]ïn·ÖÝ⬽ÇÞbî·å¿cÌïÆØ^m{ηoë¯Ï¾w¿õ½·÷¿{¯x´÷J\87öþýæ\99Û\8c=ßöZ¿{þ×úݱç}ó]ñèÝ\15\8fr\8c·ÎØ÷\8a\7fÿÿc\8d÷Çÿöíýõ\9cs\8c-öÜÿÏ-ÇÝ£\96Þ«+!Êq%£1ÆûÚþ1Æ\99ãJ\ 3ͺ\12¢\97oü»¾¿sÛ³íöÞ]A \16W\1a¨­\84\95L®Ö~üq×þÿ\7f¹ÿøj®\11½\14Â\12ÇÌ\83¤\11«\91F±¦òòîY_Ï1·Ø÷}{î:wίÍ]W:\94\7f\9c±ÎvûÞ·ÍXßÜyç·ï«ë½¸Ú­sÎWã½±å\1eç\7f±öÛf{³å\1cãíqþ?{«»Õ\9ckÌ3ö·Ò¡\9cß\9f­æ¼{{­íß\7f[í·|g½íÕ½Zoy·ùëûußßz~óçûV:Ôÿ¾uµ4sþíõyóÌ«í\97û¬¹å¼âÑÛ+\1d\9a=ÎÕz\9b¯Æ_oÜóö\9ck­-Ï\7fç\8d\96w_ñèÿ\95\ eÝ·ë\½Õ\9bcËsþþgÜmÞÕÒßí¾·âQ\9do¥Có¾{[Ï­ßÚî\8d·¶7\7f\8fuµ|oÿsöÿsî1÷\1a_\8cõþ?W\9b»÷ßþ\9f;®vóî±ÆÞc|q¶y_ì·Ï\16W\9byÞ}{oûÿøzk/çÿúj)ï|ÿ\7f\7fÅ£¶Ò¡~soõÍÝçl½íùs|/ö\97S­ý½voíuÖ·ï½o¾\9e[\9fõÅùZ­½ç\98ëËñÿÕónuηâÑ­+\1d\8aíý¹Z]-Åý{ï1ιoß÷Öþ\7fmõÞº[{+\1eµ¸BzTKy¿×Ú\7fµÆ\1cç͵®t(×ûöûµÝVçûuç¸Û\8bõõý÷¼5ÿÕfïoÅ£ù^\9b³×\96s¼«åöëÎ1®xôöËoÍßzï\7fïúnÍû¾\15\8f~Î;Õ7Ûß¹öwã¾uµøú|mîöÛ\9b÷½Úß«³çØâ¯{ý\1dgÌûÞ\15\8fjk­®\96v¬wÿVk˱ÆÜï\9f±½Þê\9c·õÚfïq¶ÿs}±ïys{\7fÆôr¯qÎÙ[Ìq·\9a{Ý+\1e½þV\ 2.rl\95¤Èª§¬\ 5\9e²°ÆVXT}2pÆ"ÇJ
+\18W+Ù¬\15\8a.RÀ\95É>R@5¿ð\94}\95\14`\82²ó\13['h\9aäX\96\95\14`VR\06KVyÊÆU        ²¾\97YM2¶\82\ 5\10\92¬±\8a»ÌæC½\ eÉ|¬®XMòs\81²j\92ªj\92ä'\96`\80S¶Z\99\95U®Dre\ 6\0Åoe\ 6xUWe\95+2\14[20,ÇÊ*GÒ<Wµ\14\14\91"v\86*óS©F
+VU\8d\14/\0¬\ 2\84¥\86\ 6 ¢,P\16¶@ÍCu­/û>Å
+º¾XxkI\92¾\96$ùwI\92%I²H\11d\8d1\16YÅÓ¬âi\964\14ß\ fæA   R\9cf     Àoq\10³Ó#©ò\14Q\rJ°æ­\|\1f\86\8am\99ð\15\9cv°IFr"U\1a\91\f\91Åd\81\1a\19²ç`<k\1f\18+v²\92A\ÇFæø\ f\87ì\80\83%b±R\81\12C-bà\9d5\88^aS ~$\85        ë\18Í     Æ\12\e\1fVù¸H\8a\98\ 4¢DñY\8d8\ 5§9@   ²ð\81² \10\12@ tX\960ñu\8aMF/\ 2\99B~m£       s¥\1a%\91ë\93qve\83\16¬5C1\88
+On\91\b2"è9TFà¶\a\1a\84<\9cb¬Ò®\14X\14®\ 1Îú>\bãêá\9a¥\15§\9dÎ\ 4¿"©"¥jtb\9d\11\89@¥0ú̾ÒÈÀác8\19\>\bÕGà[\9d\ f\12\13°+ËLÌ>\1a2!y¡V©~\1f\9fÔfa¡¦\16"=\94h9l"     \ 6ÿ´D\17Mc\ 4¨¤°\10¡¢$\10DpZ£Fl\11\16R\ 5\ 1á\10r\19\88mU\81@XT\12¬\a       WFx\88\98­û\0\82lb\ e#eÀäp\ 1½(\ e­ðÛ\1c<~\88hP-Dh\1aºÀ\84¤a\15\82¹P\ 4\ f\89\bE\11áá¨\8d¥U2,8ïÀ°Ðra\188M\97<\b\ 3ŦÑ:\85,¯ÐéV$ö     F`*\17\14\fJ\ e\v\14\84\ao\81qZE\16T­Óe\12=(#SÁÅäM\12\88Åf"!"\89\92\8a\94\16\1aà¤t°\90\10#]&þDê\14ùB²£É\83\ 4á\92\96\ 2§q\8f/RX\8c\1c¯0kEl
+§Ä\99\1aÍ .\9f\11ã{á\91\ 3¶©\10\rÌ\16\ f"l%4"\ 2\8a4\10\ 5±\84\ 4ÆfHxØpLÂËÕ%        \e\81G\11Âá\82)\94ñBKè´]H\88âáô\ 2E0\8e\12\88Ó<\9cª\80\1aJÿ\0\9d¡À\vá\7f       á$áPA0\1fD\ f\ 4\vxz\1dD¼L¥\ 3     \ 3´\1c\19ä ì|\8aOfõ°ð¡\80@0\1f\v\82iàã\12#1\8feóBy`åHãÉ |ë)!\92\8aNhÅEt8M\92\0ùt$|·;\15\b\98§HÅY\80\81        \9cÿ\9a\10pL
+\ 6\a§!\16  7\98\rba\ 3\89xo\13Z\1a\93M)4Aj0/\86\bM­¢\ 3\8d\99 ê\1aÖ\f% 9uT­ÌÁy\962\16\10Ædr$¡f8M²*I\8fÑñ$¼Ò\92\b^l¦ð=
+X\81Ã{}\ e
+L\8bÁÅ\80q5°6\98ðáË\18X\84Ä\86!a1\96ÁÆ=J\ 6\8eÜ1\ 6\93\8ehbð?²¼h\ 68ße\ 4"E\97\882Ár\81eºîÒ CÒÂi=ä\90²|"\b  \96\b\95¦b)\11:\ 3\96¼\ fÈ
+\82À)UY½¾\84
+\84\15±T2\r\97®2áЪ(\80@ø¯à³z\8d
+B\8a\8cAÁf<l\ 1\83ýN\ 2Ç\ 1\ 3\8b\0\14¡1\11\98\ e\8d\86\80ÓÉh\82QD\10 à4MÅ\14\17Ø@é\\16\a\94mÁ¡P\14\1aÂ\be À\93?B\0\9cø\ 5¯\8dÂ'O\rï\8f\10@ü±\81\88ñ)\f\10B\9f@`qðÚË xÒã)ð\f¢Pç1*\96Ù#cÉê0l9u\14\82D§s\1a\87\ 5ù\9dk\88Ho4ü
+.>D\15O\95H&^\9ax\1cî\99¸\9e_¼H\84÷È@Ŷ®nµ!¢ÉÂæ2\99Î^t\86¿Ï\bL²M\81ljS \ 1Ô§@\ 4¥\17\92\86\ 3Ýè\ 5\15\9c\13ÍiVİÐÞ\ 5¢È\ 6\ 2?"\1fx}\94\17&v&O@4ϲ\92\ 6\92\1d\fP\ 5î%\90\85;5\82Â\r\12\19\ 4,nF\v\968*\18
+\ e\9fF\1eÙ\1d3Wuq\1f\17nÈ~\9fû\82\94*w\ 2\97Ó@\8f\ fwa]HfwVPY\ 6\8dëd\19£óÀr¾}±0ÆB¶\ 5\98Çê$F\15\93í\10hM$\ e\16\1c&ù¤\88&\12\9eYf²\19,?Q\91Hݤ \1f,&¢ì@¬\9e\ 5\84¯
+\14\80N\95áqB¨\9cÖÉ\97A\15U\r^C\ f\9e¤Z\a׬{\91\v1@Lt\19b\9fº±%"t\f\15   \98\ eÓQz'±p]\a\16\1d\ 3L\15\eØä\89Õ@\1eE4\f\95h ä\98\9b\81\87±+\18Høpð\80ÇH=\ 6\93\16§¤ú\10\85\843\17\9f¤D\85\18$¢f AÒ²\13\1a\89já!\90¤F\8f%\11.\b\90\1aÏÈCD\b\8b@|¢*"\ 1\8e\r\91ol(D@\81ì\89À´ç\12©ÐDð\bã¡Q#\92
+\r\17Ù^¬\80pÚÅd     !\bÛ8\ 1\1c  ,X\1dALME\aRM\89\vÄ\ 2\ 2uÈH\92\99@V ç\80,\10¼óÁ­'>@ä\ 1ë±ú  \1e\8d\92Ìô°h$¡\a\8a\80³y\9c\9e¢ò ðÏ\1f¨ßª\8f­bq<8íb\0;\1d©\ f\90\96\9aI8ÈGÈà¸X F\ eVIôqè\11Ás@\10(\108jÄI;P\13°st\ffÃÁ\0éf\8dÊ \915\1e6èjèÐ~\rUGÁ¡Q\19h\98\1a2\18*Ô@8ñN\83Ó\1e\98РñpG\94\ 6Á¢ë\ 6\19\86\ 2\væhè\8fµ5b«\16É\8d&R\14\1c\ f)X\\ 5L\94àPç¢\813¨½ÄA*\b!î¥ðêp¥\96õ8K#¡\80\93`NÎɾ\84ËA8f\12\ e\94\80jp\9cV\99\11l\í\9c¤ÀÌ\9c\80     ¼\10B-\81\a\ 6å\13\18\9d&\10\ 2\1dJe\10¨\98\ 3$\81Í                t\98ì\11p\MF`#\11,\ 2\15)\88/\10[ض\0\ 5\ 2\81\15xu$$\ 2®Ì\80C u\11-\ 4\\98\86ÉxeH2\ 6§Q `
+F¬ä\ 2\19å7ú\18\vòG0\1c\10F\ 3£«P\98\18Z\ 1bĨÀ\18@\f\8e-y\18¢\83\ 4\rÃ\81\82dÀh\11L\140Ì/æ\19\92ÜØ\fß\90/ÃÃK\1d\83A\15B\18¯\8bn0\ 4ÊÒ\82Á\17\1cç\82Ó>~D."HFlQѰ\10\87 µðà\98j\91ÚJ©ÅBÄ@,\b>Û°0\9dÎ\85\85LA$-t\88%Z\88<\10 \85ø\89ø,4\82\ 4gQ"½2\8b\8a\86Ò`Qð9,\v\b\19\85`ñp$øÅ\ 1\85b/8-\16ºyAð\85ìb\82\85½d$\8b\ 5Ôë±h0¼Æ"ä\91\8cÅìûl\v\ f\1e
+\86UÅÖ©¢q«h Ä6\8fmÀ¶ó\e_\eÈÂjm\ 2$\8aµ\95H'Õ6°M\13\e\84¨ ±õ\ 5\14ÄÆi¯JÊaÛ\f\8c¨mA1;m\v(»°éЧ´\85\18\95Âöá\8dÑ\ 6\91\\12\14÷\816̬CØ\18¤è³A\90\9cg3¨\18q6\81²±ÙR\8c\87̦\89P¼Mre\ 6\9b«rºl¢\ 3\8b\f\8dÊÆiçjE°Il\v\94Í£9\7fË!\ 3¿\95©Û7      Æ\0ß\ e
+\1a\v³¼ \9c\8c¼\81ݼ\9bÂ(f·Jè\9al\90NU7\8a\r\9d$N\ 3\9b·P\90l\95\0\8d¥\rd{\10/\8f­c)\8e\8dÓ¶¨ÒضWç6\95\ 4\vl  \9a\ 1ÆF\89h,¶Æ¶m\e×mÛ6À» ¦\81\18ø\0ëÇ\a\87±mÛ\16ñØ\ 6,¶-ò)\91­\ 2\95\0Ù\16\11\11ÈbÛ¶í<¸l[¦Ül\9bfÐl\e\85\87µØb«      cë.\84±\r\18`        \85<M\86èZ\9aEí<FåÈ\18Hºòb:-¼ñ$¯mVÂ\8c \81\12æ@a±m\ 3\ 6D|\98ä~V%&·ÌIï*n\8b^\16\rD\8fÓ\1c\1fÖGó ð;OBQa´\18\r\b\98Ù\80UmD\1eóC\10\ f±®%-\84  \8c"\81bàqZ\ e\9b~1AMµ@Ä:§\9d,W\98\91\19\f\940\94\ 3Y/O\8bdC8\80M\ 6\f\ 42Oà\806\92¾ºT\18\Ph#¡x*aæ´Bà\ôá\14pf®1\86©\805X\9c&\1a0`\80\176T\18\f°(\ 1\17\89\89õ -Ü\89òpf\ 1Cy8Ó 1U\1d\8b)\81òp×\80ò°ãò2u\1f\942\959\8d¡\ 2¢\ 2¢s:\9dN¨Î·8Z\15\ e[áh\91\rd\ 6b\13±\10`"7³\80j\940\91\8ba&\b3A;\81\99ã©CÁDn\ 6²1\91ë\98p&\13Ê\84\82\84Ç\ eD\1e\90      \8fÍÄF\1dK  \85À)P2\ 299\88\1dTüÙÁ½\1cÄ\1e\9a"\90óAìàA\11È\a±Èìà^Î
+§}pHrj\1e\971ô¡\8046\8fË\87bÀñùP\9c.3\ 2\97\9aÇE§P\1eæ´\14ê\ 4R\80\96Ó<®Æåä.§\ 5{\\17{\\ 3\19ß\13LsêN\15\aæ~\a¬8pD¢âÀ§\87á\ e«30ª8phñq\9a\ 1g\91Z|w\86U\15 ÅwG¬ÚHh 67\93\ 3\r\e\89\ 6\ 3\ 2bs7\12\9b\8d\ 49Ð0VN#;C\835æèI*\1a#²ãÇØ\18Yd\12\ 3qƱp\10\1eA4\bB\13\ 1
+C!E\90e\ 2\1eßyHØ \14\12<Èz\81 \ 6\83\9bL#ÇâØC\83\86\98ñ
+\ 6)FP ©wbV>8\8d\0ôBiSB1Ëßu\16æÄ\17
+E\1c\83+x&\8e\9d°8\vs³@\8d[\ 1\17\90hE0¢(ø\87­ÀãE\8e,m\8bD\820ñ2\99Uõ2\1c{N\fjÁÆAcjà8h\1aúÅÄÉ8Î\89Áfd1q$\f\ 4>g3c14©ï$v^"KYVø­e;¤DË"$øÒ\84Ó\1e¯pÁÀ#ñÁ\98\19E\13b(@\12\ f¼À\ 2
+\ 6±WÁØÉBÛ2\86R\r5\85òzÍ´@\b\ 4\ 2ÙTuLUÇTuj\86Óf,\94\87'5Óêj¦uª8p}PZeª\ 3B¸(\14Jòð\ 6r\99ê<(­2Õ±H\14ÊT\ 5\ 4î\16·Õ-n«[ÜV\ 5\ 4\ 3\8a\81\ 1e\92\16ßÍt\8bÛ\92,nË\92"]\86\e:'Ôv\82ØÜS\ 4±¹\99
+GËf²¡C6t,\92ÉÃÃ\9c&\81\99\12\98)\81\99ã©cYX@- \f0\91\9b\91ÀL\bÌ\8c\80\14 ­¸Á²\99L\83e3\95\ 6Ëf\1e\ 3\r\96up\9aæq\b|\19\92úÀ\1c\eu,%T  UBÕ     \8fÍp\1a\816óà`YGê\ 3-\ 2)É%½¹\85\14(\bd\ 3\ 1¢@A0GOÂ9úÂ%s
+\94\v¦@¹Ì\fx\9e\1dÜ\86ÅmÙ\83\18®ø\ 2\ eîE\12R \òAìq\80p/\a \13Ø\17È\1f\8aη@òË\8cÀ¸cFl.§\9d\9aÇ\85\ 1f\82öCÁi\8e\ fé\8cà4ÆæqÉpÚgÛ<.\9b­c\91|ÌÑ«*3\ 2+d\1ej¦e=®Î·H4lZN\8b\84Ó<¦Ek,\1a@\b÷"á4\8f@\ 5Ê[\Îí\85ò°Ç\1c=Ór\96}\82,S\r\1dY©c\91ÄF\9cLàÃ:,\92èàrZ$\1dsô$\9c6\86\ 6\87'«,\92ÎùPq`ÓÃp\87%\99,\9c 50U\1dKç\|\97Ó\14D\9c\8fk l\1e\17        çá.\fÜ\81»0p\193Ôâ»\1eéS\10È\9c/r!YU\91\8c¯    §y¤Ïc=\ e\81ï\92\ 3\r\16   §iP\9fÇ6 \13¨
+GË\8e§\8eE²iÔ\11h5\89\86\14é2\92\ 6B'd:]2§5@lº\86\81Í\80E2°É\e\89η(\904àkÒ(?\10\9b«å\8d\ 4äà;xxl8<(-Ëi\8c
+\88NGÀ¡ð"w\1c\17R\1fh#\9cÆX\946\a·± x³\bü±\17\a\1e\bU\1cØ1K}>\8cAU     '\9cÆqûÀ6F\16\89\82Bd\96òX®1á±£\85ηtº\ 6\8bD#â4àkâa²\82\89\\8fôy\1e]\83E2\86\ 6¸\8dÅ"Q\bI&ùs°¬æ¡ó-\ fN3±\1e¤e\80Â\b'\ 6¥\ 6Ëf"]FRÎ8\16\89Bì1\81\81ÀD®G\1aЯ-Bm$*\18\\16\9bIÄX\ e\19È\a}h\ 2Ó\98º\b\83\8dÁ-\vfÉi\ e
+^ý\ 1:\18\9cÓN\13\ 3\1dmr\16fD\83\16;\128F\12à4\ 6\9fcqebV6@4§\89\9d\87\98@\85Åã3        |1LF£Á*y        Þ\14(iÖ*up\e¥\84\16Ç^
+ÎÂä4\87\ 6ý \92\v\f\ 6Wpá\ 2É¢ìêĬÜ,0\91\vQU #TÐ\ 2åÚX\14\94å\fU\99X\87Ì\87&\9f\82\17ÚãÍIud\86\85»fÙ\8d*\ eÌi\8b2%v¶Eà\83re i\ 6\fI3°q`\16ÉV)^\ 3\9b\89â5°5ü\83nËÀ,\92MàÄ\90\85\85\96%·<²\10Ð$t9\8d \93\f©\93\f&¯;ÖU\bs\90\91}0É"p\80\17È\83\8a\84Ox¤O\16Ú\16      Y\0!-\8d\10©¤'\964 M­\10ÓX¼\99*\98%$°\95©\9d\914¶ÔH6(\ 4\94
\1d³%ájý½»Ðª\95ûu'}-\16\82\12.        \94~H\88\1e°\bÉÃvм<\ f\b.0\12`\98e\§
+\88\8a¾p"\e\ eðÀY\8aF\92ÉÛ¼Jÿ\9fJ\96\ 26\13U\ 1í\12·Ðj\82\952\91@öôà1\0ÙRg\80U°±ec$\8e\15\8b¤û¬ò\16\euZ\9f\8f·Ø¨c\91H6eYn\a\r\96\8d\14hP\14\10ùämIOìêÌà\8dÓd'\ 6\81\16.Ùt`Zx:\84{aè&\15É\8cÓ`Ù\86þ\0\1d\e71+9­r\166\e«p@9#°*%`9\8f\97\NK&lL\83\ 6Ë\92\88ã´\89\ f\91"\19A<\ f\8b\ 3\97±\9eª`ðÈ\87\9ddwÆi\15\94\ 6Ë®
+üBb\80E^\ 2\eqÊrÛ
+&\11\89\86\ 5§=Py\82\8a\90\v\89Hc$$ì\ 5âÀ!R`\f\1eZ¨"\1e\91ÕF\ 1~\12$*\ 3\ e6|`\10<0\f\8dSÇpIØ\1e\aY\1c\12'ûyÐ\9cö\9a$\80¦ð´§þÐ\ 1\95Î\19§AJ\1f\93Õ\ f\1aAw@=\87JåX+\82\83\ 3aÁi%\91\12*\89\83­\18Èr\9a¾xºWÀ<\91ü? kqàÀ 6¤\12¬b3ø£kÈ©\8eÃä4²7X¶t\9aÀ8Ë\90à\1d\18
+\1d\vv@Q¨Áà\9cv\10\8e\1c« IÐÜ\8fq\16æ¨\0\81c\1f\1atw\98U0\18Ü\9cTNã\90\b
+$\11\ f\97\a\84»\13³²lt\87ùX\14pÚØð0jO\8eÀ\98\99;d|Å\81\94ôÄ\9e¸\86\99\ 4eÉiçB$nN\81Ĩ\e,+É\84*ú¡r\1a\0G\94\r&ÁF\85\89\\96x\12d\87cÄ?
+\bTU}\1c\ 6]garÚ\82\ 3£c'0\98Ò\88cp\r\83\89c9-\ 1\ 2\9cÅY\84"\96cQ\r:¤/\ 2\91×.Ð+\ 2    §\1d<d(\16GEaÔpb\98\ f[\81ÃD%2<\9c6rà\12\96\8c\89\95\8a(%d%Ò¨9-dbS7¶\8eE2ó \\r"\99\88òÅI\15Ñm°ìã¡`\90Q\Ç[&D\17ý(é\89Eð"Dy2 ÊÒ\ 4q\9a¦¡Á²bg[$\12\1eÆ\ 5w<\85\80ç[4\v\8b\ 3k\1c\11\9b\99\ 1S\1eÛ\80\8d\12X\ 1\83^÷<+\8d¬ÑH\90&&\87\84FN(}:\ 6\13ó@ðåª$\97Aa¥ðµÄd\1d§qóa\13ÌÑ\93`\8aB\81Ö\r\95\89%3£        \8f\8d\1dl\8b¤[I.\9a\81\8b\ 1B/á\84       ïá%¹h8Êö`<\9b㠩بÄÍi3½\0í\ 3bid\86\ 3\12  3NjÂ\84Ä ·\ 1Et\82ö\0\7f\11âB\98\11\98kb2\81ljNS\80d¶-ë\98Èý$\13\ f\e\8dø\89È\94\1a1\88Wý½\10¼.\1a\aÍ\ f\8d"(\ 5.sb@\ 2=\86M¥c\9aø\9emN*L³-\92ËÁ\84Ç.\842\17\ 6RQ\92\ 6\9bW\10\r@¶'LP\16®`\80@a `Ài\a>\16Ã$p+m`í\rÝNf\8f\1d7\1fÖZ\1alKóUH\f\ f¬ó[\1aï4]2\81B¦(\14h\1c\92Ll>_\17É$$\99Ø\89êt\91ô\89m\91ÜûÁL´S\0hº÷\83!  k\fQ*\vA,ÙGOó\ 3é\9bÇ\96ì£\1a\ f®(\8e«ª\1a)FÐ,Á\0`YU#\ 5èúDñ»\9f¨"C\98\89¡ 9«ª\91Â\8aÕ$_ç¨\9a\99õ\94µl\0Õª\9a¤=ÃS5R\84 ë#AY(¶@VY®T­ÖÈ\ 2AQÕj\8d\15\16\v\94\99¨4R\88\94¹(E\9dR
+\91È\0\0\0\90\0c\12\00((\18\91\92\91$\84\98í\ 1\14\0\ 4vV&D:>.&\10Gc¡@\18\12\85\81\14Ia\14\83Q\10\ 3a\fc\f1¤Ìé \0\e\fû8Âô[¾\12£\ eû]Þæx&SuÙôLOé+(và ]®\82&Á¥òal1\ 5\9e\94=KmpÞh3q?\91ó\16­\85\ 6\879ÄM\99hk(Å
+êÝYÐØ\99Z\ eEÃC¸\13g\1aúf]\17\92\ 3ôÄ$ú\96-»í\9f\r\0ù.\9dP÷£¾u\19<QÇ\1aØUs¿VÑ}5x\ f\91\ 5·¿\8c¼\10º9\19\ 2\14@iÂD1\1a¥É\12\9e\1e<|FP¥}Öc+Fõ\81\89\97¢+С\14ç\r{ÈÕHO\19]vʯè\86[]º\11øG\17yLÏ\96Pùè"\8aU"o\14bÒëT\88Ð\1c]\f$\88òèÚìû\90ñ*#P]£[\1an\1d0Y¤Md9º\b¾L;\14ÝÚ\v\9b\16\16¬\8a\ 3<ݮĢúNèÂA\8a\92\eþÑM=rY\ 6\1f÷&¡\ 4ÎèYZìQÅ\11¡\128Ù9\88¯Ý5QÜ2̳Ç\92+ò-¦ø³\9cü>\8aéÃxRÌ\e½\81\91d\aÏ\r\ 4p\rçcÆ\83\960?ÖH^\91û/nX\98\87\8a;ôÖ\0Ä¥{*Â\ eS,Qò\8ef'W\9f\88\eÊ`GÅ\8b\b1.ó\1aB.L\ 6\80×E>ÓP\8f4\81þpöt\9a5\ 4\85V\7f&\1f¾PÙÄcj\10¤\1fG\ 33C\94a*¾\À÷(%å"+IÐIJgÉ6©VÑ*â$«<¤ü 1\ 1Ç(\9bkgh\89§\erË©\ 5©¦\10üß\84\16]w\b}r}1\16à-\16\v)ù=¥>\v\ fæ¼\1cÄ\86À\11Öíoy³\97\93\ 6û\88ËÁþ\89mfÞ6ß¡¼(kü¸Dp@\93ö\ 5ÕCV\11,ÖöÆ\83,̸Êkê!\94­p:2\f±M2Ý\94\9fá\83ü_YsH\ 5\8d{é4\9c¬?\9d\83G\13å\a\a)~\1a1¸ð\a\ 5ñä¢lX\98¿rØ\\81Z\15Ú\ e\9e¡\aV\85\19«\1fÙ\12\B\9cñ^\9a\ 25¿          \98TÜâ-\83\88è\0\1f\ 4öâYb}ÃÚÆÿf\97Úfº\92ç}¥;µ`ºÛ.hà»t tE\8e\9dseÅ\9b\12ßÈ\98Ç©\sLéÂx®ð2Ý[8rÍ\85ê\8f$ø`ºï\ 2UöO×^¼\19û\89eºß\9b\91®\8fÆ\ 6\97ß\99®àq+Cp\1c\e\e\98®Þ{vx!\0so9H¹òÌt\8dfmC 3ëÈ\85ÂLÈ*\9f°*t\8cúòJ¥q^ "\18ý¡Ì\0¥X\98\1f\19bST\86F§Zß]dV\ 6Ê=\9e\92\96X\rª\93\8eäÍqÔ+Ca\a-=·Ê×Xe´!Q\1a6\ 3ѧ¥ã¹:q¨\1f\ eÀ\8e[ätú\1fW\80\a\90\ 3Û\UÃÒ¿Ôìt\ 3ª\8c\92KtÆÍëÞp¿q\ 5OYeÄaÁV\98 ^Æ(¥Qr9\ 6\96\1c\ 4ìt3\97\a\19*ÊÂ\v\98:\1eëK=õ\ 4{K96\1a\8a»²v%\9f\19xáÄ\83[]¾K±¤r.5k\ 6·\93\97\1f8\v\b|2åóÙ£Ñ\9f¬_Òäã#\12ã.ò'ÀÿR\16\ 3\0[W\1e:e~\80ð\18,\9fZ\92\98-w\90¤ñ$\91ªÍÌúq\vÑ>\94þM\824\82\ÿ\86ÐÇ\94\9d\ f:\8c­Ø\8c\8cI!\91Ý\92R<\ 4\8e\18Á¬é¬ÁOÑ\9cË¥\v¯ÂpqWf8v\890û³i}\15ðer\e\88Öé\87\ 1È%¦Ñ¡\8c\19\85\fÏHp\9bré\11ðQUí\1eÓ)Â^\88\91tt,~\14\1c½¤\18\81aïÌ÷Û«éZ§À!%¸éhóÒheôl\13\10§\1a°.B¨7|7Mó\9bÏ\b\84TQ\15·æ(Ã\9bà_|_«~\90¯j4ͧ\82Ü^ì¦\9f°ã'\80Å(\eNc^t\ 1Í\8c\19\91ú\ 1@\85xÖ¿À\8aÜFÒÝä~¬EY_\95\a\84\83ãÒÒ\8bµ]Úe!\19¾T\fò_\18±\1aÅ
\19ÑS%Pøe)pÇa\85þ¦\80Lc\ 1x\r\11H\8a\18Ü\v>.\95ë\8e)\10\eò®h±Ç\ eÜ\8fA\ 1dYX¹aN\963\a\97­#Bxqâ\ fÀ#$( .E\8b\a\89ûU\bÔ#í\80\8b\13úÁ\vGÓMá¹Ë]Q?ü«jh\ f±\90þmi¦!ëQƸǠ    y%õ\9e\9cbl¿.,\9fobÒ \7fßîf\8e÷1Öt\8f.\11\9a¥¦è\80ºD\92\8d;ÿ¶2Þ)ÕqpuÏ\19¤CÓ\9c\7fº\fJÃÿûõ´®°xö>òmX\9e\90\98  I@«dá:\1eø~\8b\f(\9ccÚ±EdNÊ+uÜiù£TM5F\80\90\ 5â/¨Odº\8bÄøW¡\8b8bS\9eú·Ãó\9f0coÈO\1d\ 2úR\9e 5#\84\1da\90ß»rU·PBÞ\8d£\1d×9áäè\1atf\1cì#¡670#\92Ý&Í\9d\ f0\8d¥V\ 4ÞOI`\80E=ófÊo\õ\95ÊËL«¯Ibø\f\17ývÿì·Ã\16\83¼ÖwØ÷\8c®\10q_n 8D±µo\18\f\1fø0\90&ÙøãÈ×jP7\83\ 3äTSÌÖÿ\99Í\r¢\93\ 3\ 5\97¶6\a»y}\92\eááÑ ðÁ\98icxÄÑ\12§ÐÈ\9a[·6ÝEPÒíT³*d¯Û<\09\18ï#ÿlT\ 2»A4\1e\8d      _þg·\14\82\16\83éßZ\98\17Èp!9HG\e\eÁn\8fÈÉ\96\9fn»L\8dsÝ¢
+JAë.Üô\18\16¢Á.\92×\8cÝO\13;Í)ô\9a?\8b\;\16X ¨Ä`ÍúÙe\15È_\85!\17³íBJ\87å\82_
+J\88<'ÄC\934³©\ 3-\ 1\85K\ 2¢
+jDÅ%QÊq,l,=Q½ÛöQÉ\9b\96õ\9b>\17·\90ä\14\80Ãhc«ì\7f   Ç\80ÅÐ$ ã,\1f\\84     ÞkzáPC-\83-\ 3l³_^\7f{=Á+\ 6:î·Â}\17Æ¥Ë
+S\16(í<\94XA\11ù\99®¾]\ 5u\9e,\16\98&\15}ëÆªf,³¼Ø¹øè[x! \e\ fs\0\1c\1a\9bQÂÃ\1d´ï\92\80\97\16øÎ\b\1a\9e2/B"°µ\16\ 1Û\87Â\8bgI\ f\9a\8a\ 1{ ¢[Ä\87ù»g±èP8w6\8f\98@Xä\86\0\98\1f>|\ 4ßrÄ×-#á\ f\93Wô~2¾¼ùqH\ 6AB\18\8fOoá§>PÄ    \ 1¨·ù\9aÉ"æa6²n\1cÇw¯\16\89X&\95\87§¯e\87¯\8f¯_4=¬ÑÆìúJ/|I«Dv||Ò÷Àæ`Ë\9f}´ÝÏ­\8a«\1c\89§ã#\97+Äs-iÜÏ*Õ§Q\9c·\ 6¡V\vi\18´\95\82:ï¹sQ\83\1dg]\86^\83Mþò\0ݤð\bQ\1fÿ\9fö?Ðí\ 1\81
+p\97JqJ´\90T-ÒÒ_x\19\93\bZ¾N!\92ý\8aPzWøï\94³\13\8ej\11ó~\1cØÃ\ 6M¤b-× ðHñ\98\ f\93/\aär¡§ÕS\82ü\0ûi\1fèr\9aËPTX5\9aä\eû×|ia¯gqy\85{ëH(HZ5\16²ÿ\11\90\1að·$aÊ5ÕHaHÚ\14í«Éöð@Í\0\96l\8c\9c»×º¹\1cÛú\86 Âã»r\13Ê\9bäª&Ðèa~!Z\83Ó\16¤\ 3·õ½©æ7eFÖ\16\9cÁTG'´+\1a£6\eÜ\82Ñ\94Þ3PîKv`NCVãªT\8d\83\9e\1aéa)a\97Éeß/\92ö%ï\82¬I>Cu\15ÇpùDøÖñ\14ÇÂ
+\9d±\94\1af\93³`P\99ÜÎê\fø\86\1c·\9aM\9dgëiI.»o£bW\97­úx\19\1c\ 1\ 2xËÍ\95Æ\99x\8a+/\99+{â={ÞÀäY\97ár¼: \ 2If
+\93\88½¢ò\9eñì*÷¶Ýµß\8e¡À#Í\9f?ð!o\9e]ôaÃsq7\1dÕ3\88\87\839»}5(aÂÑíÌ8¼<{WL\80ï[\8aõóLu\93û¢\8f$\ 4|\93E[\81e\9bÑke\1döÌdîMR(,\\86¯?RAÎ\ 5\88 E½l:\ 4\16<\ 5¡\96bkØçeH[!c&J%¿\8a­\f6\ 5YÌ!)OqQ\12í\88ÛR;\8dÄ6(¶\13í\9a\81\9cý\11\19¿\96W\1fã,lÇ\9c\1f¹È\98·\eßø~\14ß\ f\ 3\8c¨!§<¤ÿÌ\15\879a(4¯\19ä [&@\ 3X^»{Jä4UyÜ¥?PÒè^ïrâ×ÅkäÏDQÞ\98Éfdå[Vû>\81\8584´×ä\92zG\8ec\84Þ®\92\88y
+vÖ¤\9e\11\ f\98ziægPFS«özò.\16¬\86ùp\96â]\8bvWQ\11äl}]~\9e\9f0hÌ\ 1ß\19\19X²4\90ñõ\82ZB­°ÙçåUD¨
+\15Þ\16Ì xnykQ\95ç\98â\8b\80ùË![\86ÕÁDD"nhí^ò\1f\90ñÜqe\b\ 1\13Õx`ÿêºÉ\96\15Ï\15bµÏ\ fÝz(\98ä   !Æ\1aÜõ1ìÂ\ 6\11\ fA
+\9d6ùÃ\97\ 6\a\12>gyÞ\15Lå·ñÃ\95­`ð¨\7f\84\8c\7f\18ª\93\80b\1dN\1cÒw1Y¨æeP\86G5\1a\84\9bÉM\ e\915\ fè/Û\8eæ\17-d¤\1fýõ¹\10þ\93ò-\ 5¿j\96úF\94Ì9³n&×Ñ\93\8d\ e
+\16\97     \8ar¶÷BH\ e®\1fõi\bßËJRcJd°\19jÚ-°\8e\88ÝÁ+¼þ\14\83Bmz5(:Ú\9f¢¶#¨q\87M\ 5\81L\8d+Èráø¤\ 6yCF¥³Ð%\80!\94Íþ~§$\81´%aÐÅé\93aWE-ÎÁý\18 \1fÅ\ 5}=?\90M\81   ¼L\1f¨3ÞN¤ÖYÑè\0\97¦Ö\896?`\85¶9u\10k+ãc \9aW\18ª\822?Ô©(6Ç\89³\8eW\7fA\82¿\15\91\88¬\8a}ÃZÌ))"rc²Ëù\11+/8\9c\e[v[Ó?\1c\1aIÌ,\1d½N4r:eZtJüA\89\1fX÷&G\80U.M\rùJ\ e\92á[\83Áo0Úâ\ 3Ebïg\97®ë¯¶ï\aD3Öí\95¯\}\9db  )[¤\95*íÛÓ\91×b±|Àà\90Á\1cú!ÆK" ±*ï%2\15\1fG\87Ù¨£\89=ÿô$Óvo«\9c\ 1\10Ô8VÒLx\96¦\91\ 1fÛÞÓ qðix]B£-ë4\8a±\8c\ 3y\90Y å$oþ\1d\19É¡#÷    YÁN\99Ñ)ô\eÊfö\892ÌQ#Ù\v\b\ e|\ 4µ\97\8aû!âÀÑ\9b\18àöA M\97\vü\ fCõ H_\83.#ó\9e¬»'$]ø9ùµå|÷®g#\ 2­5Ì\vä\19\f©ú\14^\f\10Î\839\9b\95²*n\82ý\9c\87éq0\ 5\1d\ fðËåp£Øá-Åü\86tìAù©Éºç8\91â\97Çþ¾:Þ\86Z*vÉ\ 3\8cl\w\8b70ß\11\8bÔH\89Ú{ \88\ 2!\84Ä)Ýà,ä7\88À̹\91\9b\85\a\99\9f\ e\86µÇ\1f\0\86¸\99{\81Úh|h\89ó\16ù[H<7©P¸%Ui$[C\ 1ù~^d(S\b\v\8d*\19t?ªo@ûÁ\96ï3µt@e\bÈ\1e*F÷WÖýl#_¢ÿ\9a\18\99YU×h\ 3\93&\ 3D±7É\18Å9\bnÛo}b\85¿ãkö\86\9fì\ e\9cåd¤ÿ·NfT\1a\1d>\8b\ f   ø\91ÌzÓüß²X#(\17~åô)\8f\ 6Ä\ 3§aý~ò^|~«¦PÖ\96\82     °ê×\91x×ÛÀËo¤gi\eÙr\1fµó,M\87or\98צ®Ör\ f$&I>\rø¸¬¢­pRS
+\f\9e\8añ\93 ¯Oºê±ø>b&×T\8fIuö\föh\0\98\9a\12\a\90`0ø×\8b¬       ¡ÅszÂw$VRÍ\9aàF\ fÿ\ 3\11Ã\1a6Ëì\0cæ>ô\1e\v+\(qvLh\9c\7f\86}D"Ð7#Ry!u\b\16\9c\84$\93\80\9e\a="Ø\85ׯ\9f\10H5i\92Ìõã¶¾<;Ú\8c\øt¬W¯­\91põê³þ\ 6¡ð8Éó6YòêQx¶e\v\8fxQåÈté£\18¤zíìU¼,\14h\9eÖ²Þ   <~\16Ù\9d\94\14ín³Õ\19%-´G~\9c"\87\9c\0¿V4\13ÂõÓêic9X\8e\96\ 1éL\95\ 4Ùp\9fôZN`l\8fì¨N5Ã\1f\8b\83K\16»ÔcÞ+}fûF\9f\97\ 5í\81ª1¨fè÷ýÌ2+'G\v\18\96b\É|\ 4\bµÙiKW-p:¦ëÉV   $âÛ/\8e\ e¢Á³þ\ÆÑ<:\1f\13ûS5\8bQ\9fþÓ\ 48\ 1\81î{.®ÓÄ\8a§\99^³/>ÍÃz¨Î>c\97\87÷
+þ¼]\90Éê&\87êàø5Y\86÷îsce÷Í\r]ãË×õ>£\ 4Ìl\e+"!`Hù\fä¡\1e\18\8a¾|¦\97\bê&GÏÎ\1fC\97}'üË2·×\\99Ðàlë6\15Û\1av·C¾VÆ!\1aô,Qx½ôD+N\ e¬d´\8fbçë\14¦c\8aÜ=2\0dF\17´¥\f\7f78ÚW\ 3I5Bê#ö\821W/vÌó\87Dr\81=¡u¿\15K{©+gíU\8bÐ&éG1c\83d©å)\12n\ 1p\13 \8fãÃÖ\12tN~oro÷×ë37*¶<FJÆ\aÓ-w\8a\Ûõ=\b\bðd\10Ò?\11Fu\99ª\85\rZ\ 6¢\96ÏÁÛ\1d\8aÊ×Í?ÄþÓVp\ 1l\9eb¶ÀÞMC\ 3ý¿-nhÞ<\vk\14*%\80\b\8d6\ 5\ 3ew×\\920·       Æ%\93~(Hx%â{V\8fÒF\e\1f\9btubwâ)r"\99HǼÕMÞ\86þ\98Ò\ 5ÏÅ^¹&*C3\8f\vQÅU\8a\0&\1fTÐÀìÝ2\8c"\9dà\ 27:\8að*\b|Y\1e\97mÐË\8fø\83\1c\11X°Ó\ 5-Ð\ã'(iz(3\9dº\8a\1a\8f;û¼Ëï1ÔØ.ï\ 1\e\ 6ê z¦_'\9aþ íàÙO\13Á¡æ,Èû$ßz}ý:\ 4»\8aäN\ fC\8cÃx\86\9cê\e¥\90\ 3\15]8ÑðTËi µ'zÿq;º8]\96d;.\85\8e\9eü#¨\13¤«Q\1aT\eu«c´ÛÑ?°\9d§\9a\ 41à9\87ý5\11Ç\ 3&ô°\86\96ëà«¿®n\97\98Ç\8b\97ÍxÔí\13É\1fcdí¶\1ah\vuDÖn\10Ð\90k\9fEé¥\83ZL!!G¤XU(íðýê5ö\8f\84\ 5Á\12ô\1c\8b¯cF5Ë3iÈ~5Ö\8fÈèn\867~¤\93\83õ\ 2\83\95Üü°mdÚüÃFsuu+ò\ 4\99(pã`ds\ fWàP\9a­7\8d\8dêZ<:o¯îi;÷e ½°«\12\10\89 g\92ê¿\96L~º©\ 1\96ù\93E(.\ eì\9c\92ò¬\94\16^\86\90X-¼!U!\8b)\1cF"@§YGD¦îiBøÏUµ×2-\ 6Wæ?C<¦    p\9e\80: g£erIwiÕE-\85*\b¯\15\0\vHU[àUW4ðv\89\11ùa°ÝAKaì)|#øþ\12Ì@\9bÓ\17O.
+B[y\ 5R\ 3E=n±n-Zè[0(ýÄÌ\8f\95\0ÚÏK\14D0!¦³é9ÎO¯.6\9c\12Lú÷!Ò\b\952æfúþ\ 3)Îï1AZ\ 3 \9aºÙïÛ\1e¿t?ñJÏ1'\86ÑSf;x÷ÎÑKã`«uâöüç\9c:=¾ê:\96óùCØÔ:ðýF\9eæÇ\92-\ 2Üy+ÑL÷åî\bbì~Ç\82ºÑì\7ftB[ÂZ 0Å\9b×9øä\99\ 1O¨¸JÛ\b\81\ fàSõ³[\18\ e\83(A\1c\88\8f`ÇÐ\1fá¯o\10jr=¡\1aLeï\85É\81åÇùíªDe´\bÞ0ø¿VÒ¿\8dÿÖàú\ 2\ 1\85?\v\8a¯&ÌícG?\81TÍ4*\aàú\ e\10nÀ)h²^\r\88Ôû^\15¹õC±\1c\ 3´  _!xõ\91U­&\1fC"fK\10\99¿\83¿ð°¬íQñsn\95#\16|°¼ñè;º\8f\15\13°UÀ\7f×y\9b0\92\84È\8c\8aÔàõt?Y\ 6¯\17¤\12zâ^QH+Àn\ 1Àߪ\0ùu8\ 2éFDÆ\9bHûiu\8dæ\8b\87¼V\94h=ÆR\10\ 4s\95MåCʬ\ 4Ú\vþù\ 6pkén©»A\82\ 3é¼Ö\f¥Ð\99\83\ 1\81Á<¶¶-1!ü\9f\8eZD»ã}\fÓ\1c
+g\90f\ 2\84\1fÀ¶ <ÊÅ\r­ éD\99¿J\189\91\fw\v\86Z\9a8JìîÇé%ifm\9c×ÿ?&2D±ð/ò,\98/Â4¢¡\895İ}\8c\bV\1e\84\14ð\14\vù°.\12\1aán.ÄL ]\vÂî,@MÿÐ/m²ôÑ·4\16\91      `Å6?uÅq~ç²\98³\ 2w\85Ãä\99o\86A@|¢Äð\91\1cK)=¿¨·Z¤¸´VÊï\85û\f\1eùª¶ÙmÑ´\ f\8c>FSpiÝ\19Ñ\9còRuS&Kø\95\ 1VcC)ÛD@\ 3»¨F \96\11ï\91\10ÁÅ@\ e`$¨e)³®DLK\r\8béåëÜ?\ 6Á\8a\8a
+PIc¦³´ºì(ií\ 1\80\91\9a\f,N\eçKñ\b\179ãûQþ?'þ&õTanÜÂܯ7\193]\ eÄ­dÜl\96©s½+\84údp8Â\ 6
+\8d)òR\8e\b\ f\88²x\86+\99¡ñ©ÔjÎ\81?\8c\18Ò=n\96#
\93\9b\9bZ®?x÷©L8öI!f\973íB¹\99U\8e\r\8f\85×Z\83ÊLNº\ 4ÊÜjÛ\8f§T\ f\9a\85¯¾Îií\81K8#E\1câ³\b¸bÜ\adcµ¸\18D;\15\b\9dÑ\89º\86T¾n´ðe\ 4\86bmV\94J¯Ø&ý\ f)"µ(ݰ_K\14µþ_\ f\91Óz©Ùoe\96-\ f¸éD\15Ñå3u7@X\10íÅ*Õ\bÞÔ!;ãhEÝy\bìõ\11\ 3¨\18\ 6\0\16ôÁ\98Y\95Ñ@ÛÀåÊØ?\rÈf&]\e¥o«;\15}R\v²³é\ 2bL\8f\7f4ÄYÞÑ&N\19\1a.§ÔÄ^ z\1c\11ð\95:p\1af\88\82ó·2Â\ 2R\90²&âM¸É{U\19ud\98\80\19º\ 2HêT\16ý7\90ÌR ó¤þê\8c\88q£0ß-á\8a^f\8c\7fÃ\98ÔQÞA+\88cNÂR\945âµìÖÔ·\9aȲd\86oèðtÇÑk\800!' ISM2ýs\ e\82üna\ 6_\92¯ÑRÑ\1a°Ç³¿\19§er\88t\11í\10\9cQ\81¥\84á\ 1ý\80Ì                à\96ä\8b\9e1"l\9d\8els\18\88!´ÈÃ\1a\b´9[\87ª\8eË\15åqó0Áº\9fo&vr騫p\1cÑ\en0ëÌ\14P¾HòFÇ1P \ fi\90\14Þ\15{\1eàk\92Ô\9c>ó£þ"\§ÛÚÌu\86!\13\92\1f\15\95\88\8c"\1a\8c\14°¶Çn¸5ûóK&pJ´\9dB\83ë\ 5Æ9\8f\17F\89u\bÚÂ\87Ü\95ÞOS7?·\16OÓ]\9fs\90*\ 3/\1e\91Rç(á)\97µ\13Õ.\f\e\13\8f¹|¹OqôÒr\80u'\f¹{~e\99ä[]"¬Ä\1d½ê2JöC\b¼VÉ\8e£¤øáÏ#nìvCTL%Óv\9c¯ëªDç\15Z\9b# ­»\1a·\80\1fîw\ 2±<8ZÝ\91(¾TÏqør{u÷¹µ\94\ 2Cc\9d\90\86\9fW\85,Ö2l\86Ñ\16úú=\0ÂÐ"ëÔN2Üý?gÿI#\1e\14Âåi\vp\96Vçé,ôöÃ\ fMéd\F \14\9c\9b\ 6\18<éz\ 5\17ÊU5Ux\83Û\1c=\1eê«é¶(â³B\12¨Ë¬\e\97¤Ý®ëä\19û\9ek£p6\ 1Áï0B\9cÂgÏf\9b¶QGF*<2c\85
+¿åC4S
+FEN\10\15\84õ$PK\9d¦/rxû\82-SÆ75\1a\1d\b\ f\8fjGx\89¿       Æùæ\9e\88,\vîy«\1e£\11»$îä/ \80\95\8c\9fbu%;\88  @é\ 4=
+ÁÐ\ 5*\8cÃû'©®ûõÅ\17\0ãÿüOãê J\9bð\14²f\ 5f:˧\1c+Dp\17_\9bî\8e°­ä.Lñ¦\96ñ\13\98L\vR¥Ý¸Q»è\v<lb\8b®¸Ä¿ú\v\13fF\17\93ñ\11\149N\8f
+xO\9c\17%\r\ 5o\97\f\90\8e\14\13é\a{\16í\9e\8aجÝY@½;Mn.%N\v\8cÁ\80½fðɪCcÿ\91Ò¬W\a[OV@PúfæÈÚ\13D\97\9e_\85\1e¼©a
+õ³N\89\1aÜÕ±×A\10\ 4l\10¨ Ë\9f§\11X\17óá¼j! :án\12­\ 6FôÖ\8ddË¢      ôÈ(k\89»=\85\9a\8apI\91¨ìÛ-ÃD{:\86\ 3\89áÁ0ybóTܪ\8b×-\aèèqwÕ3\92'\81w+E[ï\ 6+G;7\1c\81\ 3y=QsH\9c\894>*2¦ór\90 \ 6çu.¿\ 3Îv'Ã\e\9aU\80¿\9c¬A×þËä<%\87Û%N§¿Çg\9aa´U.@\ 1²ÉBßû0Ö$M\ 5=㮬~îõ\92§aÁhò\99\1ajGÀ\ 1¤õ©÷X¬È³B\10\9d\ 3ÑÐ>\86̤\8cTªI\ 5D\94ñ\8a AnZ\91'\11·\1e,Mxcö\80\83Ì\8a\9c\8d¿ã&TÎ-ig¶`á¾C27»\99}ºL\18St\rì,U*ÿÀ\1d\802|Ée¿#v\96Ð\9aÿhGñ;\aó\81Pu¿4X\14Ð\94\1e;~Ï#C\10\1a¶0À¼ë\A\7f\18KÃ&\ 5ÙÇ [ Ò\1cT\98\88$K²Ì7Ë|Åï |\90u\8dO\8e¯KÞã\10\98,\99`iE\1a×MCZ÷\9cT^§µþó»÷¸C\92\18Ú\13ë\87=¨CZû·gF©É3q\ 4\8cKL\8c«\13\ 2\11\99à?:ô!²²/ú\8cAüi\b0VR\96lB\9e\1a~U:"II\0\8eX¥G*õ-0½_>\90\88c\15°{©\92U\9e\18ç\14>h$\87ÑRÃG×ç<      ºÌ¼Í{Öpü¦WÙ\95\80\10\ e?\1f q\1cê¤\ 6Ë\1eIô×}Ò\8d)í¢']\ 1â\10\8e\91yÙmQ5O\99\16C\1d\bÇeWÐu\8aûg\8f¬u×ýÃ\1cûG\18Í÷Ë"\86/ÐtKòF\ 1%ª´å\8f\1a!rÃ_ÿ×\82D¦èÑ´\e\86\ 6\91ÝÌ\8f\r\1c\84û \ 4$\1f<\ 6¡\8a\89?\855Vñ\ e¯ò%Íà5ZdÆØPý\9e3\83{é*ÁTÜ#\18?b\8cÉ_M\92\15âQ\xJfZqñ\92ìi:äë\84BÍþ\85*ûVåöÐûIà7/ùºw±L\89!4Å\17µeL·GsR,äã!\94dCà_\87\10\ e´í>ªpX¢MPÔ\8c÷¹\9ej½nþB©\97RYÞ4Y\ eöÚX§ !± ) ÆÇ\95«\89R|F9<Ppóa9\16\16\ 1É\98\v>2qÅìéþÉ\13 -*ûí\83\¡Ú_¶a\84Y\e#¢%ò~}ð*hZÉscó\ f\12\91-\fð\r\9b\9eòê        !¼^AxGÜ*1\8a8\85E!¹~/# l¨\93\81
+¥h\1a\8dº\aó>"Õ\97ØÁ.\1c+\r÷(§<\84\1cµ\f\1fr\14é\86.%\1fF\16\12\vt\r\84ä\13+ºéÎÆ\1c\8eàü\9a\8fGj?½³ò"\a{\9e\8e\8b3j\93"\89\10äO'5\f\1fS>¸zR´:\f\88\ 1!T¦\ 6pFÑ\ 5ë¶q#þ\1fq\91\85#¶aøÑZK¥%1\17\8c\1cÔv\10j\v\7f
+\88\96o¬.\ 5 P\85T\aòF\r\90v\1f2\18¬Á7¸GC>fS4½\97Z70_!fÆààþ¨>Ò\92§-ü$\92\12¾\v\91F\ 3¦ír\19\19ã\r¢Ý¤Û
\97o\85øÄNE¢»\93fj(Î\84\ 2èd\ 4'WYÊ£ÇD\ 6¾Óèqu?K²+ü\0\ 5X\18\ 6ìf«ÁC®a¹:í{hÍ2M>\89:\96Ü)\97\7f
+o9\8e/\9f\99\\fÆÆ(þ«\98\ e\ f\v\ e\18׸ÐË0´´XUKþìmvÝXÀÎbâÂÒÞ¿\80\e\94\1f\f{âL`¼(\eß½jf[püòLJT\ 3Y\9a!\ 6v¶¯ì$ì\vÍ\r\10Ç\10êD{£÷ï»ÌFÀ\85ÑrÇKî\898l`\87¨,3O\rAISó\r\90³óÇ\ f\7f¹\85Éëb¤xÛ»9®\13#L¦\eµ\13¯;\ f¥L\82\12þ²m\16_¼5BÖ\v\1d\84OLl \ 3îwõ½õ\ 6C.ö\93(a\8cƪ7\163£S\92¯Vëâ^\9b-\9b\a\ 6þ{Ð+q\b\80ûÒÝ\109OBf¨Ô\a!\8e\92ÛÈ\95z\9d-\ 2©\9eFE\16åáÅG0ì¼\9b°\80e4'\94\12.\13É|\8c5\89{«­µW\eT$\18?ÒLôØÐÁ\ 3\94ÎñÖ®\8c\1f6\98\16èµ\vðå¥Dw\992ôeÃik\1e\10e\r'\13ç\90\Dj¸ïI\94Øl5¯ÛþbÝ9,z^éôáúê}ó\ 3\88£\ 5Ù¯«Gbø9¾ô\16f\8f#^s\8dúJü|.CN\ 2\8bæZ    \ 5G\92\1aê\88Öʵ¤\15\14d\eÿr°¿ÉMz>\13\86 ï?\11\ fæÂ\ fÛjϹËðµq{V¦\ 5\90\ e\83\99\1a\80\1a\e%@¬\99Q)\82\bzu×\81{VÄ\9bÌ\13¡Üá@xRÁqlÉò`\ro\1aa\17üá\eZ\9cn%'\83Õùå\a\f¦m\86,Þ±:}ä\8cØUR\9dq\0Wkq\9d\8d\96ìi\12¢\92\9aâvÇ}"l¸\8dð׿_¶µÑÊy!@\ 6¹\17q¿&!¼1Û\99#¹°Û_\8f©Ýýéñ\ 6\16ëà<\8c\v/j\92\88\9c;RÞ\8eI\8d\10µÜ³Ñ Õ&\ 3JºÇÈ\87Æÿ
+ÿJâm\1eer&
\89\8bìzA¡Èr8\f(\ f\ 5ò=a² H"änT?\11Òq|%^;\1f\a$ÙØÚlÒ\15¡\ 3ò7\ 6\85H7\ 5õ©\1a.T\12\116Ña"\18Z%\86zZ\ 5\ 4É\19\ 2»\8b\97\8b]r\b=d\84Êõ\91H\t\9e\95­'V\965¬ÐÆ\81v\1e®iåK\10\88E\bË©B\96®²\9cÎÙuf\ e¨¡pàÖ$\86Y©²"¥Ç\7f
+Ò|m(À\ 2r\9dfÈT\80/ëklxÛùî<=\1am{\19\8c{N\80\væ\ eäü\r¯E¶dè\93¨G\8a\85Ó ¿»G¸«\ eËÛÐG´ý´ël\14\150\9d°#oÑ\ 4xb\17\85\ 6ëêrWkKE\83\ 5V\9a\ 5Õ|\9eI=H\9f
\88\9eã\f\930\90SÕÈZº%O<\1fÃÞ\ 3!|,²\1e2§I3Ç\90\8bSC8\8e\12\98HáV\96uþK\92,\97\84\10Ê\14-\\1cÔ\12æ5\8f\8cÙ\ eßÍF*\15)\9bx\82ø\9dÿ\0eaXÄr\8b\9b¢\1f\95ÂØ©Ñ\ 5îÊÜí\8eOI\\aÈ\86\8f\17Màò\91u0 FS/ \ 5oݱ©\95\8cP\ f÷ÇOß2JÑ>ZÉ\89\13>n>ýQ\ 4\99z`\9dG\17£¥\15åå?ãYQð
+ï+dò=¢U\ 2F\140L(ÉððM\ eùR\15¢nþ3\8eI)~KQS%\ 2p\v#8Oë\7fÚ\eIÊ8\15¯\0Y\95ºq\9bÓä\97\91ó¤Ë\83çN\ 3jÒ¥®$4¸×\v\8aïù\f\ 4¡V\85ý\16\87\82\ 5¬­\85GßZ\ 1¡¿+h&ð¯¡c\9b33øC3Q­²»Û\87Cî!Æ\15_97~\99á;\9añW¯¡\9dÄ\80Ùcç\94\9eeåíAßï¨Ú«*\86[èª-¤]y©á\9eÄj)ÖÚ\1a1RXÂôSâ"­¥\9c®{ZDÉ\88\18I=\8d}0\1f±\8d\1d+ù/\1dIhX\ 2ù\19Ö©á¥E\82QhÆBÉe\f\1a«ð¨!\rZ$Wë\r&*ûýÌs\f~ùà\80\888ýPN\0\9aì+j ¡\9f\ f¬nbÆ\88\1f\7fq\13~\18\8c\13Ð;X»¿\94ÐF\ f ëaܽÍY\ 1¢Ì\akÉÛÒ\ 2Ú<p,/\vb¡]ÜåÐFȨ\92\8açj\90³nâÃð[L/Þ-b¾ü­\8f/\1dðsL²Ì\12#óI\83 \95\1e4P\95\8dcº°\85þ<·\8a¯ +r\8ei\13\93o÷H\1aú³Û\ e\8cÑãT\fUz¸\r4V­$x]\839ô8À \aÃÇ)dpÕ\8e/\13\94\87\95«´1\10¾\18\9f\11Çôä·rP\8aü«Ã\12jÃݲ\e5\ 6\86ýl';ØCÁó\ 5*ÃnÒy1FEîÿ\85.\8d^=\8fy\99\97\ 6\8dKÂ~ï¿n(®Ì\0ñ\81\82"?×q\ 4 ({\8aDa@gjìwwO§   \8bÁÌ]\9d\1e7\91)^\16H\a­ôÙÀ ïLzüë°\8d©÷\92_H{ýyäǦVÊ*?Å\0\13ÐÕ;Ø7CÛ^Xõ?\9cl\8b\ 2h#\1dS-Z\b\10Ð\ 5ð©»\90\11~âEr¹\ 2\9a\8a\1cÚÇç)JW©åKg­\13\86ì\95\8bb»Û-$\9c\ e\83áV\83û\91\8d\b®\ 6\1e)HZê'À³îì(=4I8¿m.\ 1(Ö c B»\r©¶z\97ü«#]\87H°Ìãv\8e©Î\9aª^ØAC%\9d\e\9a3Ï«\a\1c©ZìB¼\\§
+\17L0\f `ÐC\91³Ï'\82¢íW\99{Úørïøö\90ä´\87¸t\10ú\9aH?0\9eb=QgüüµlÖ¾\ 4\1dð\99\10
+\ fÑÏ\11¿#é6 Tä·»\84j\9a&]*ãëS\12\97\1c\87\8f\1eCÙWì`ßi¦\89\17Xz\9a\94ÿ¹û\ 6\85â%¢s\1d\ 2ôHãø]°\12¾\9b\88\99µî\15ÆÁ¸\82üçÜÑÕ\9ez\ 2\ 6m\85&-\99öÙΩøàÒØ]Àj\9ed\97¥^4*Bk'+\88|:\ e*ɼs®Í1Sg\1c\1e\asçÇßýB8\8c±â\88ø\1d\8e±ÿa.\1c\14°1\ 1ZRÀÝ9Ò¨Í2³Jr*\ìÏ\ e\1eö\arC\80Ce8zø#¨öÂÊþ`ðµwÀ\19\atu}/-$e\9aÜú\8b\a\ 6¥)\19«SÓ\91Û1XÛ\99\9aë\8b´\ 3¢*Ͻ\1fÄÓ\ 6\0Å×ðµ\85%k\1d66==ÒD\8a\13\86n¥p\8b±à\99*7\ e9\ 3\0\92²\ 1\fwPñÁ0UZ8Z¡\ 6\8eA>±'«F-\84Sð7       \v       hÄ5`] 6¼q¿¨±\18H6F\9bË\16ÜàS×\8dñ'\17Z=¬ÀZ{KØ9\ f\94\8dúÕQëCZÖ\80\8c\ 6j}Ö ú¾í(\ eø"<Ò:\88±®\ f«\1a\1c\8b/\8e\15h¶¤\0úq`\a\vÚ
+b\ 4}\8f+Oßì_è\e\1a\18r,Óè}ýýrYÕhÓ¯×o\1ð\85u/c!\89edíxu},
\83,\14\12:à[l¸§ã\98q\8dJ\14\1awòC\9fyªBø\8bQÆüu8\10\9b\87\1e½Áb\8eeL\ f_\9dÔ\84    +ÞBê\8cx¨o?ÖT\14`\1cÍÖ¹X$bzVv8\açD³\97uÄàXxÝ+ÅÜ\15\87\8eb\94P8e¼\87êr¡AÞë\87î\13\94C\88,\amå¨ß    \1dé\8ca³RZý¿\89óØ1&Røms§\ fF\87Þ¹}U\1f{>îr\9b[\86h\vºW3eë\rÕߣh\vÐæ\12¤m\f\1c\88äàã\86\84ÎB\13tåx\97kóÝ\10\9f"×˦b"/TÜ\90/\9fü¹\ 2zïf\1c~7¹ÔôÛ¤\88Á¥Ê2Ðú\r_*µë\90\9c\fñ\rKËôM\96µÂÅEZ\95\8ej,ÿâ>\ 3\94)ÑN¶óFKøµÔ²Í¿\14ïîhGôE>¼<RÝü\ fò\95è 0\92O'\e$\99\fG lÔÛ7cÔ«ôgGDEP,-\14fXÞÖýØ_\ fóG\a\89\eXPWA\¹¯g\0ò/¬C¦z\r("p\10ã
+P\b\1c\ 2\8dO=Oª[¹\97\88+^ø_öë®C7\9c\0\1cPuw5\89Ò?\97Ï\80<ÏL%÷¬
+:\88ð[Ç\ fðÓÌ.)¹   \9b:\8a:mYX=\ 4²\920±«\87æÉ]q<ð\87VÍ\ÃJÿ"\92.$w\1f{>d\82°b²î Óü\95\1dØ,Ôõmª\r\11db\ 2ù\ fê&\89t\9bSÀê\½i ¹Â\82aÚ£äÜ\1f\95)\b\9c'%ÑÆÐ¦ªÝYV4\89X\ f&i\12,´mæ6Uj\15Ãð<âÀ\8d.P"\9aÚ¢ÃqÉ(W\92É)v\1d\9bqq
+\ 1,@\8e\ 2\17³\ fé7\ 1\1cL|ëú\84j\14;2@\84\8aøB[÷C¯îÅlé¾¶EöD{W½U\112¥<\ 3ð\ 6;\1cè\ f\11\987ø¨/&<\1dò\14_^q|A        \95D\8a?ÀfÔh;\1en\ 4÷\112!\85\88\937Hõë\87Ok\84©ÏneÁä%à}0Ö¬mj\e\e J\80Ý\b½#á)D$ab\83½58À\11\84;\ 5r\12\80ùTLá'yϯ¨Ô.þ'ú¡ÿF\ 5\9b\ e\82t\86\14u\99
+\94}-\98TãÆE\91\17*\fiÙ³\88\81\84[Iò×â\a#\9eÈVN\ 6ð9¿\ 1G¡TÚÇFßw]Ð\16jæ¢Kâ]ü®Öø\ 4nt|\16ßÁWc²VI n~ÙoJäÔ\ fp´6»\86¼\ eclL@z~I\18|­'\r£B\94ë ü7ôä\ ez\11\9dô?©´oEu~6\9c~¾(\1d°?wÏyY\8ey\9d\98â\ 1\ 3\v\17}þNëº]\81º¢sÞ\ 1MC\9dî×òmaØÛ³\8eÔÍ\18M\18GHÈ
+               \94R\14ÃiÚgg\94\0\14æ&4P\8cïWã\9f±¢ÌÌ\13\1eñ\17\ 6\18°w&iU2È\9cÌÂñ\93d\86ì!Û90;akW½î¬\8a¯\8a·»h\8dJÎIò?Ö_^èÞ\9aÇæy¹\93g¯2J{\85\91~>¼8ü¼o\98hN\7fÁ0\9c#ïÖ^%Áo\9d\1f%2p÷\ 20Ù`ïñUE\12\89X:\83\91aù¥\[Õ\93bÛ¬uj2F´\ 2Jeywk\83\82\82)\99I6UX¨\9a#D!¶NxÞ+2K.\90\17³ÅQ\1a¯t¿°WÔKÎ\9aýUí©\82ÀÂþC#\17\90~¹ !W²#x\96\8c\b/ZØzXȦ\91\8bñ\ 1Þæ\ 5´\7fJV½\13®P\81 \14®¿\9czûúz«Ñ\vfëm8\94\ f\19Nk\82áÖIÏav\nB\81ËF\fdWTQ§\96\ 6\97\ 6\13\81\18_É ÅG÷\0Ã>¼\9f\9d\9b$Óó³«:ö¹'×W ³9&\13¦oº(lE÷Ë\92é\85w\93\ 1áÆà¤ÄÊ.ó\11\81\r\9fÏ\95½_èk²\9a^.¨ï>`ÈÃB?çN/É\ 2\88RîþÒ\8bPU¢\13%¿ñG¦\97W\9bû7*(h\85Ç)L\90\ 4\12\vp\ e\82\81SgÎ\ 4\96%Ô      \12®Þó²Ów\19+æCÛ\9b\8d\97@ïã\82\9c\89\8b\1aV&±Ö²êØ=6nÏÀ\8e\18Ü.QÆ\ 3ÎãÞ\ 4*\88\8aÚÇ%÷¯
+Ûß\80¶¢\9b"\8a#9c;\147\80Û\14¡¥×÷Ý[Ó.N*`¡\98ó\18t2Çú\\82ç+\815\86\båüÐ\9eY\13^ h|Pv{\1f\12\98\99­.ýR ü\b;0\ 1\9dóHC~¥Ì\82 #0CS£"gts¡\1csc£)26Á\91\8d\9c}:£     B\1cà@\89`ØK\10\ 1¡C\9byÔ'\fÌÕ¥\8b4\ 2>]õ=Óz\1eiBºQ\8cG$=¸,Ç\89\ 5áv\1f\92fª¦\18Ý\913tpNÐ7À\1dQå8~/H\97nýºÜ\17eíT\8b`\14\ 4¡\ 3QlLÃ'wVÅ\95^ :l)ÐæAYí\8dÕZÁL\86ͧ$\0ì\17è´\ 3ñÂ\9dÑ\806Í£ÅA.ZÑ·!Ø?Ë\1e<Vc\12/Wÿ\bç\18\9fð~\85ME~s'¤?\ 6|\12\10\ 5¼ª\99õ\94\84VuåfT¡È²:Íl\ 1\9fØ)ã14Ìî\86ÑÇ\0Ä[á\14\búM\bâéÍ3
+`EìD\8f%~\ 4\94Ç\81\a\1f¤+¢\8bTe\10Þ·¹Ñ\aIN´\9fϯù{¨?3«w\ 6£þ?8\91ò§\9a\ 1Ïj5\0þ×ÔL\9e&<4\82\8d\83ðM\98¡\81\eêâ,_hs××\f\ 66\94\aõ\1d|^ôëu\8dèé>Ã=­­ï¤ôVÂ\9f;¡{­ñ\9c´\90\94äû`    ©öQ\1fû\ 1/¬Ù\9e\10NYû¡Î\8d0\85ãø\1cåâ\apV\99TëA\19î)ÒÎ$,³¶e{\ f\84\13\1d8îõ¿k¨ß|8)@Ðv\8c\vD\88\92ºÿ\f\16\84/ò¤§rCëÉNÜ"Ä=\8eë§\11§°\11©<ô\9fø\13\1dNÓdÌGýªõn   \9b\1f³\\94ã«`iÕ?D\88\15\1f\9b\81«qns\9f\9d\a$R_`\1d\93\8cç\17ïÚ¿ð¹êè\95\80\10°VÑy\84\ 3\13iLqá@Ì¢<«\97ËD¿"Ä]üËÈ\ e\19à!ÒÄoyWj\85®x³\ 15\83\88+\18¹xu-X.7\ 5Áy\1a\98kB:KßFô3»-,ZP,Ô\fdÙLîߺÿH\10:¢ê·¥«~ÏËså\15þÚ¸¨\96b1ù´b&o9p\17ßzÊf¥ôÆ Y¾\1e'J\bÃÚ×\94r\16\17ÿ\8b\f[å´Æ>æi]]è¥d\f»þ\9aÇ\9a\86£\0ÎóÒ|µãý#4\87A¿ø¸å\80AD¾O«÷\8cbÚ«8JR«lÍÇ¡·¸k}ñÌ\12¹m\eÖT\89¦úLX¹µyÞ>OäüøÕi\9e\16(\ 5\ 2bh0ÇKö\8cçk£ÐÇ_\ 2\8bA[\ e®\ eÇU/\96\91ÍGSäÔ°[\9dÙE:\ 3\HJdtÅÛ\8cÑ\96\11\10\83§´vë/¸\8f{òg\1fÐþ\82\85ÝÀ-C\94ßT¤¨×*MøiÞV\8dî\ 6x}\11\9bO É\e\ 6\a\ 5d^(\95\19_Ð2\a\98Pe`Þ'ø     Ù¥®m¼9(\93\a\r1¨r¿E\8bÇ\82hU¾\r':s\19´\921ûBHZÒhõ\15W\17\eÝB\15ôò\9d¹\14*y(¤\11\15yéWhæs0ät¨¦¿[¤hÂD\16Súxà8L1­\7fT\81oð¸êÑ\9b\ 6Ó?\9d×X´þYÃ\17\¢å¦&\ 5Î\12bpþiQ0f3%sy¯\8eM\95\1ewM\15¡3ÕáîÍ1\15#`d­\8bÈ\87\1c       \81\15m¯|\85Çka\16z\8fýaNb¤ôÕ\18é\87\80\88ó½\83ê¢\95óK¡\a\9bã¶oY\9d\90\ 2Á¿çüçµ-³as\ fÛ9\v½ú6\9bÁ)ë<¼\90ÌBJ|«r´oEï\98Il\11        ­?Ôì7\10C.\9aò\8cØ?\e\85^T«¹ªQÕ£·¼sâ\89\94V¦É\ 6ðªi*[OözI\f\0h|Qg\ 1\ e      \1c\ 2\9e\bíI'\80À|nûVÅ\90ï¬àuÄë\98(Oè¸\ 6o_X\89Ò\85õZ\88ÕD\85è}\1aîn\ 1¿ú=¢\85â|öæ?\15\ e6 ¤¨æBÓâ+ûF\93\9c( Á\81ÐB}\14<\81KÉñÝQ´Qù\9c\15l4cu^¤P\9c\9a>\ 6w@¦-¸5\8c\96\85¬Ñ(æ\97\19Î\ 2ZVËJ/ìu-OEç
+vJ{äF¸(\19\ 3Ý­ËÁ\12ýµ\82tFÒ\v\995\ 5P(á¥[ÿ7\ e¯\85j\12î6¥^f\88¨\90sYÙè©\ 3\92ë\v\ 4\8agsÝbÃ\18E9\96S=\91»k;{N\1c\1eà\8aJ\9aU»ÒO\93ÿ·Ì?\17¯e\17/\83S7\ 4z¯ådæÚõ¥mºâ}\9c\86ú\8cÐï    §1\ 1¤·#\8b\91
\91
+M«X\85&Ú~ѹ\vm|ÍWòÏT\15æK\14Cá±»¾A\1f:\8bÒçhe\16\9b=\8dÒR\99\1d¶ñç\8e!\8e³Ôºí
+·;µJ\þ\81íx¾\r@\89í¿1      \1a\10:aGê¯D´,{Í3ï15Ð\ eÎX¼`-ËÓ\aîóê-\b\96\94\92f¨ÂE\851ît\\97ú\8bã'\99Ý4Öu\18$ý!9\16¬¬P'\rYl,g1e-ó\ 3:\10\90\18+M\aò\IéewVÄ\95[TS\1aÀ/ÓK£è;\19\9c\88\8aX\97³ÄbHµê9\9e\1f¤\19ðå\8a\v
+î¡M\8a¿½¾Ü¥+´úòG\1f\93\9e6¡QÝ\97w\91\93ÔE\1aâù¿Ä¥\ ezª{8ü\17¼Hzáþkû#Ï\ 23°(*^\95¢\98ï\ 2R\9a\8c{q?Ì\14ó°Ñ°o½C2°\8fhîU±\13/Múö\99ê\91#2¯Ù\a\rX?ÚÃÁ¾f\ f~[¤],ßP\10¬3\r\93l¢ÝuÍv»\18\11h\8fã¿NzÇ\9bW\1fÆkAø\982kµT\9a\83hk±\ e\83\84H\90zF^Wþt3z\9a½\9b\1f\1av\15ê¸t)#\88+\eÌ;ï\93¸3½K:8    çN%\936\/jÄ\19òÑ\1cïO\ 6\94\98ÞÃ÷\98@ëJO\10EoP\ 6z\ 4'F\9a\ 2±ë¹ ï\18O\19ÖÅ\89Dr4«Ü©«\ f-1l\8c\8d>\13æ¶\ 30\1cc\8b\1dô\94²1ÓÛD\83\ 4å\a¤blϰ\9fð4uXI¥ÀÀå¨.`\16{¦º\14ì&_Í ®ªì´¾p\e\88Ø'Ó\84,\81Y\11\9cõò/§\fD\ 1ÛÔ9Ú5Ñy\95æx=-&¥ATåì\8c\97wu`ÑÎÌþ=\13Æ^>&\ 4k\aß\80½!\7f$6Ë'\7f}\80e\9aШq\eY>ú\\röt8\9b\82À\84¹eÏßþMéñ2Ý/V0Ê­\14-ÀÚíIþ3\18Y\17óH£È/GGî.ØØ6\8aF5×a\95(z \9a\89}\1c§\1e\91jfÙZAé\15Ö\1c£+¥¿\ f\ e®\bÙü2\88\94r<\11PnD¨â\92$b7wÜd\92©ô\ f\9cW\801IÉ:\92\ 44Ò¤\7fú\90\8c"½Ä±ñô5äìÞ6{\1a-Ô·\ 4Aÿh5\18øý!ëÁ\1dÅ\8d\b\96\97³\ e:E§Þ\bþJkN\1d:c#XÓÔæ\81QâVt×4eöi©fï5ئf\7fX7ÐZ3Ò\8f>¦§\98£\83låý\92\82\ 3½a\15í·\15\81\97\88?_Ç\92-`\ 1^t\9d\ 2½¨
+\18Òû\võox\82í?¥\90\ 6¤\98\92ôÌH\91,¹H\ 5ÚìÒ\\12\95Ý\92Ö¸\0\9eç:.§\r\89wFFå(Án×I\1f\1arC\12Ä.Ñ\84Ñ\97óò¼dÕ\99R\85Ï@\b\úb³h\82
+îj#­ÛE\9dÁEîehAþG\89²\9f'?\84¶kM¯\e\8b\96ä§^k8ë[@
+'\85²\16\1a±\1f\ 5O\90\9b\86\80q\1c\18\1d\1c2µ÷0à\84tÔ,S\14©\91\ 40\f\86¹µ¤­\94\ 4üÓýã&¦I>iÍÊDP\9aúÇjL!ZÕ¤4j\ 2ÕÙùg<9\19\1aîtÒ§6zz Ìb\15j\vwÌÝ¿)õµ¼ 2\83@
+  h:CÏÞú"w¥*Þx*\8f×7¸\1c-bØ%À\ 6 \ eܯúK\ 2\ 1ôq\99Ý\9f\9fá¿Û\16¡úÀ}÷\b4\19\rÙ\89·OQ\84@,à®øI\102\83\b\9f|ÝÁ[°5\ eå'@®\8c£\eWãýÃ\8f*8älM«®uóÞ«)>Í+N«Ý\8f×2\82\ e\vÂÂPèK%\82Ò\18ÚøÀb±µ×"a\ 4]\e|XcÙï\1dÄ[2\96¥°Êx\84×ò\10·Ô5\8bLO&\f\94Å2Ǭ\93ót{\877Þt#\93º\8ab5\15¢°\1eÚrå\86à2ÓÌæ©¼Çn\91 R\16H½(̧R@Ô\e¸èâº0\¦Dd²L%]|ñâõhl2Çä\ e\85R\ 1Ê5Ý<) \0`X\aÜ¿Ë3\ 2\94\ 4×uÅuG]·zÝì°'ef¦dÖ5\83¡À{j\9e\b^\8b¯\vô\ 3ã\ 3Û\ 3 \8e«pµÅ\ 3f#   $4f\19\10\81\ 1\81\92ÃÈ\b\11\83-D8Í\81\11\18\8cöfàõ\bÍ@\92UN5ú[ËLI²lNW.5/(Íp\1a\84ël\12jÀ©AÈj\87\17ëômÉ\ ew\0½\bG¦Z     N¢\b\82\11útT\ 2\18¬8ß
+\æW[Øò\82à\14\88\1fÆ \aºVC\b6&\vÎ\9d\95ô\116Ô 2 ¥\1c\13ôVÚ­õ\9dS\98bNGÄ\\91u*¯H\91q\88{eóh4ÜÜ\ 4p5±\9c*/) ¥\1dµ\10Ð\9bäZ墱ªRÒÌ¡¸àÁÀ¡¸\93\96CA«*\r9\14\18\8d\100\ 3ë'\86\8faÃÇp§\14\9dà\14±\11§\88á[I\14\8a&Ø&J`\91(EÅÚ\0\f\ 1fa\b\80!À,Í\93Ò<4O\8a\ e\90t\8e\95j'`®±Rí$¯T;Q±`v\80´à`èñ}\1a\ fïVJÁÐ\ 3ãïÓÈ|\1a\ fÑ\96\96ù4\1e\1f\18z`\9d§ñ\0=\f®#0Þaþ\81¡ap\1d\81¿\81À\99\7f`\fÍÐ@`̽è(÷¢£,\1e
+Qw0àr¨Ë½ ¨H\92«"IT\99JU\9fä90\9fäyèP\1dèáP]zH\17¹s\86\8a \87A¯R\eK¡Î)kb\96R\10`PxPÑ\13a¼BáIx(\ 5´\84\87\86\ 1gªÝú9:\ 6Ø¡óÚqNòCã\eV\95\9a¸X\fã'\10Ú\87ÓwÀÈrkæ¬\96È\9c\81*Êb­ÌbÈ\95JùÆ\18A\18\ 6\9a\13J\b\10A\90Ï\89ú\ 4Ô\13\97Ö4Õ_\9a*\1dvgK,\96LY\f§0Ï@\88ÖÂ@Û\10Öô\9c\8bO`fs |F2-èiUÆóR\8dß\8e\100>\82\97\ 6R¢ñ\e\81(ã÷\ 1\19Ƨ³ ×'0\97\13\10,øð\87Z\ 4\19D 9\13\88UEÉ1¿TÇ\82I\b\ 6Ì5\15              \ 6=Re¹\95v9\89Ùr\82ËIÌ\96@\8fDZ,H$î4:´\f¬W\19X?1|Ì\8e\8f,åT1)§Ê\84rªüD\11³·\12¾\95n%\11N\11³\f\9c"f¯Y\ 60¼YÎ&²\89Ò\10        ô\ 6h\1e\9a'³ÁÐ\ 3gn\190ôÀ\8dÐ\ 3+>\8d\968\88¡\aÎX\1dÁ\ 3ch\98\8cë\88\1dæ14Ì"ó\98DÙ@ 2ÿÀ`\f­\84¥¨xAuê\ 5=ÄCG0¢â\13¨2U¦ÊR\8b\98\1aX·±t\eKh%U¡\9c*\8foc©b K¸\92ª\8c%Ы\8d%ÔF¡\[ÂCÑ$<ë\84òxBRD\1a\8c\95½v\82w+è]ÓÁØ­$âZB\95\8a\15e8'¨d:|Ò\8dH\rª\15\85\93ÁÃ.Y\16\ 3*Ì    \ 5\8fEh ¯ö\9c¹ð\13\90\95­\8b"d:¤øf1äN¥¼® \87
+A\1cqØßXíVRX*\984Põ\ 4=8g\ eô\14\87\95j_\96\13É\93\8a\ fÊ\16W6\aÁ\80ø \f``\aÊ\bcJ&?£\108T\8eÔZÑHt&d@d1Q@\8fÇ
+b\Õ\93Xç?B2\12X=\99:V­]\8få¸P\1fÑ%p\e\93aAk\11\fª²º\9e\17O\80\88\9b\1cê\ 6äZ%Q\94\1aø²´\88\9aË\94\91\85îË\9c®DîêT\ 5ñqÄ\95j\19\87\95jo("\v@àð°R­í¤¦µ6\ 1\fÅ\84 ÔçhT,³,åhTìÈ>\ 2ù\\84Ò?¹ææòfÕyä°\91Jn¢\a~Ef«\89*â¨h30\9e\1aßR3$Hf­\1cê.&¨io\17\ 3ëE\a\1a\8f0@/äh赸¡\19\8eè\811\95\0\ 4\16\eãA©#\1d\98\17\81\1dê\8e¨\ f¢¸¶\12*\8a8EÌ\86ªFE\11\86\0S¨:\95FÅr¡3í"{`v-iT$q¬Û\80fDN\95EÉaöÒ%~§O\8düÐ\84\83ð#x\84ã§6vâ\87Q\98ä·0qÂ\8f\8c_%%\1a?\12\82Áø\81ÞÎ\822Àf\18;¨"\ 6!\ 5\94»[Õ.7³Þn\10\b\v\13ËÈ1¿L"¼\1f\e\8c"\ 1o\ eÔ´\e-\98Õ4\9diOѦb±\84§H\99\94D+Ë'£²ls\1f¥Qq1*¡¢EiT´\9d0\81K\94F\11"\e\0I\85\80\ 3      ×\9e\88p\9b\f1£`ÓAê®ÞdM¦É¥2iTÜ´\80JÆ#\8d\8a\91þ\91\10ÕBE;Ò¨92'\1fÊ%G.þ d\ 2\8d\8açæV,8U\82¤v¨»z\ 2\8d\8aÖó2U\ e\10»\81\88ì4¡R\18£ӠçÐ|Â+\11°¨á\95\80\93\81ï\92¡hb.O\84!+\13\0È#¼$\81FE2\93áE¬âa¥Ú\83À\ 1\15ñG£"\ e}\\1f\8d\8açåázZÂ\83\8aæG£â;H×K6#Úà\b×\8f\1f\8d\8a¥(k}4è¡þs4*b\v©¾\85 Ô/_Y6rZ\8bPÊàhTdà$)èýä6¾
+\7f©Ò\82j\1e\8a;BÐ\9cÆF\8b0\1a(è5\16\8b\97E\8dF\99\88J\12UÄEF£âúi\ 2 2H*f3\ 5¡Ê²\12\10\11\96C\91\10mZ\1cÈ¡¸bC\9bÖ\ 69U>ÌÚ´\8aCi\b=pyX©\964È¡.\82\ 230I\1cË´ãKU]rF2mÇÍ\\95\1a¬cÚ7Y\a\13\81Fªò\97\8bº°ìÀ\91".\ e+Õ.F)Z\11K\92«9`P\93\17\bÑ-\ f\87î"gµÕ\b\87 \14\83`6\92Q\ 5¢Þ\8aÄlå.R\18:\13"ÂIF\95|m\89\86\82?tâébÃ\10\93\89\eÈ|E\97`Ыµº\86Ø\14«æ?\a\87Md$rY0\8d£:Úb5Â:¦UqQÅ~Jy]?\95Å´\ 5\9cÓ!Vph\80øu\r.i\9c\ e)Ìëª\ 3\9dªÝ
+z"ÉY×0%°²¸\9d\15ÙÜø¤Vs`³XÊ'c±\r\12¡b%\8d\84\01\97$ä§A0\18¿\nÑÑÄ,\88\1aÅ,襹Gxm\96Eú AÊ11\ 2\ 5®_Ku\13¹áô\aÒ\89e\8f%áÌ¡kp\19`;åV\13¡R±\86\ ez\ 4\9e\82\96εvê\90»\8cÎܺè«u\ 5%vj1®\98ÅJ2\12\8b\85\80(ÂÉî\aI\89å'\1a \b¡\rØÉ\96\v\ e\ 6»ðr)\88\81;]`\84âÁ\19} ÇÙ5È\1a©ï vr{dZÚ\9a\17\14ôÊ\8c\9aöCJ;j/Ú´è\90ÔI;J\8e\ emZ±\80¤\\86ªQq\9cå`v¡jT,U,\98eUF\ fг:ÂøqÀ¡¸\fX§¶Ñ    Sï\9bÎ4\10ÐÜ\\1eAÈVEq"\0E\\86\ 4\8a\ 5E0éDh"\8cbQ\12¸  \81sè&°\89\82]v N$&ßhÕÊ&\84WÀê\9a
+´S]M\82êÚn\v\15K\93\12bR]=Ò¨¨e·rU¬°rS\ 5»\eJ \ÝqQîÅD¹#\8d\8a¥C¥ÜÑìµ\vïê\16\94¾\ 1Sx\17/\14\8fpr\bÝk@H\14È\1dÌ·&\81W\124vx  4*âÙÀÆ\14-¥/0¹:ªëí\9dlWùA\90\1f\8d\8aäßZâ\aLµ.G£âÕlõ-\87£QÑ6n)§L¥\1c\83\90cpA\90\90\8dåëCc\ 6\9c\8cÏȬjv|Ð\ 3½×l\15ôr\8aÃJ\ 5½\9d\ 5Åøt'Áå,/ÈrÌl\88;\bA\12ì\81æ3ûcÜ\87£%¾í\80Û\98\8b\80Òêz\ eoð7\a
+zÖô²ÉÍ$]¢Fdéz\98\ 1=\95\81b|kZÊ\896íZ@\92\ÅèÐ\f®M»xE©ÍD9&xPQUÛ¤J\ eÓ*øLü\ 5N¤Q±õm5\ 2z'\92(!Ek\1aS@
+CF\15ÏìÐ-\ 1¯\9c     Á\bèL\88á5ál\12(EMH0\8b\89²\9b\80\eUsßAäSWé\e´z#)®$°íÀH\7f·»mÌ\ 4È0³ \973XÇßp\ eZ_nº\ 6uR'\94\8f\0ÔׯHä³YIZ\b¢\84´ÆB×\15ô&0U\ 6\aT{]\91f\81ÝZkL\80èÒ\88ê¦\13ÛÆT\8c\ 42V\8d\80@\11]êÇ'mr¨\9bË\15\ 1K\88 Õ\89|§46YKö?Ô!¾\ 2RàzqÀ`\ 6IA#ÇDL\10¢ñAoÅé\ fä;0Dp\86\ 4Õÿf\ f\1d\f¶Zl¯Z(À\e\v\1e\1a\0[BsA\ fô@\ fô\ 4,*è\81\95\13       Ñ\87\8eAM4)kG!©Ä\a%»>ò\¼\96¤\12"$\17\ 4dzh>áE-jx\1d\90Gx\e\ 1\99l\94\88ðJ
+L\91Ð\aÒQ\1f\97\87Ë\9clW&\94¬\ eÒõ\1cá\1aÿö&º\8a¢¬Å\0\17\b\95º¬¾\89®\17ô\0½×lõ­\85T!\bµqK\1fô²,ý±L¥\8bPú3
+àIAÏtÈÆ/yJÔ\8c\1fÖìÂ@a!©\98ýF\995!N\92âðZÀ\0½Ã\96¨©!÷\17\ 4ùåÛÉmüó\13
+0G\80\ 5NÆgèúh6Bã¢\11³3\8ahxУÔ@²üF\bÁP¢T\9d      %¤DA.\7fß\ e¤s\90 £6k<D3¯>\ 1\10Cnç\f5}d7uû\95\9af\ 3ëO\ 5%ɺ\82^Å´}$\ 3¬cÚßÝY\87cгy4j\11O\95gQjà¡\83h\ 1\ 2§\ 40#Ö:\aæZÂ\89ÐÆx`VBè\81I+\13/+ù\94dyS\92pQ\10\12ðÃ¥¾¸\eRÀæX×\9e¥S\ 1A\10ô`2Ö-\80Í W\80­6]\ e¶Ê
+0\19ë\ 6Ó±
\0X9\99·Â\12\ eX+\ 1Ij¶îwg]îË÷©±Åz\7f>3æü¼»Äß/>1ïX\83{Æ·ÿî¸s\9eOËíÝûįõ\9fXküÛêÿ³ìún|w¶\99\97ù?\9f¶ìøZüü´\9cVèç¾Úfί%Ïþ\9cÿãò^¬1ïùr\9d?k~ZÝOþúí÷2\9f\18ãû\16ç·ö$\vÝö·¸ë\13ÿ\97Øb/@áÞ~ÿnû¥|\92.×¹w¾ñÖvc~9é\ 5\8b3¾Ûâ¿Ö\96\9bïÎyɵ}ýý{þ]Þs\178Ͻã\8cÿÞû\97\9f\9d÷\9c]vã½ÿ´åÞ»ð'YÈ\9a?¿9ëî¹xÇoõ[ûûsÞ\8fÏ·\96ÿk[ê¼\vXgÝ1YÀ\16?þ³ìüæû¿qçøË\7f|Þ­1Ö§µÿûæüÖfι¶\9fy?uïÛ>æeçÛ£å|ÚÞñµûä¯Ë}nÛ¯í\8fϳ\9fùËóK\97ßl?óç÷î\9cï÷\8bË,ñ4\ 5ÝOÎÉ}÷c}\96:ë¼ÿ¼¸_Ýû¦\15\19\93\ 5|ïÅ\sÌs.ïß\8dñÞ\\9f{Ûþ6ãKÒ\9d¿&ïK\16ö¹½\0\ 5û-\8d\96\9fV\9f{{\9aÞ9ßÞä÷Û\8bí-³Þ\85ÜOû]ÿw{\96ç\99ÉBþ?»íùñ.à^n®ûåÿ;¿þÝ5ÖçYÚ\13Ó
+ºÜüÞí\ 5(ì÷X¤ÿ\8bo>Ï­o\7f[ÚÂÞûÌ\7f\9fcls¿\9c\9f[kÍïî'ß\7ffÞïYv|\92\85\8d3\7fÎ˼7î]{´Âi{y~'\v=ç?ó$\9f¹\7f'ùÍ\wû\97Û|\92\ 5}\92\ 5»ïɱ\97\8b\14îB#«Á4»ë[Òy¿ÍçYî~ORÎøl4`µ\ 3\rÞ\9d[®Ë\1fð4\85Þµí\99VÈy{\ 1
+7ßVX«ÆR\e\rX\0\a\9a\80Þûí=ónñ½åãÇ\97Ä;¿ú>î\9c\97\13\97V\98®\ 6ÃýOίµ\16_Yí\80ëÇ\ f»\ 1\80 \81\15@í²°\8d\ 6h\85ÕVÛA\80\99Ë\960a­/Öî\93À:Ð\1dÔ.\8d\ 6,AVcé\0P£qÀ\8aáý\1a\8e7çûK«÷¶§-5~~\7f\9f¶ãòÏÍmaw{?óÜûÅúÚ|­Íwk\8bµí^G\ 5z\ 1\1aQÙBøªB£@¹\844\e\92Y\89\14Þ«i
\17\16^KS°\ 5«\v¶P°\85\7fÕ* è½j\15Õ¿\87\ 6 Ç\80xL»ûB\ f\fJM\v3\e·ôIN*}\91£Q\11E@¨Ïp¤\ 1\8aW¨T4\16ºl\13:\84\10\89\0\8c\0\ 1\fÃ\12H08(\14\8f\bäRòª\97ó\14\0\ 3X8&@@>88(\93Ë¢\910$
+\ 6\ 4r\18\85a\1c\ 4A\18È1å\90dH1Èù~#°~ßjm|EÁ\95`®j\b0¥?7=,¢Í`+«B\8ap\7fòÓÒ&\ 1ç\82\96Áº\88²\eI
+Û·c\96|Að\ fÜ\9aª\92*  n\16\17ý¾6\83¹\94\12ÑN\92=\99\90o\17]\94»\12ÂM\b\92\rÁ¶¼L¶ÏÀmî>lÂ34¡)Oip\80\vº®4ÐçW\7f
+@î4Lj9·ÿí\81\12m\9cE+ÓëÑÚ\ f8áºým2yþþ1¸Ô\99§¢d­\aM\vú;À¤ky\9ex\8cȲC1Pf8
+Áe\94\97\16\89Ã\8eSorÜ\ 6²\84\8eY\ 4?lºGP¡ª~xûÑ\b¾\8b\82Z<TUqºéRJ\ 5\91Þ¿ÿ\18z\ 2'LÈ#]\ e~­ü ºd6
+\89\9fï\87OÂù\ 39\15Ñ\8c\90\vp\ e\1eôg\9fçuµ\80h\13T3\88ï\1ck\90G\92N\ 47ÀAç)ÞLa\7fÊù\86T¥e«\9bä·\ 5 \9f#\ 1\ 2Ç\13à\13­»Nu\91\1f\ 6ðöYqHqá¨/\87\8c\19\18ÒÍ\89rézæS};ÖlMï2\91}XN\8c\95`1ö\f.\8bàÚH.\10ÉÙM>\9cÕ\8e®W°\9c\8dyOÛh\ 6þù*E\15\ 1ãz¡ô,Dõ?\ 5bµ+\16ÁÂÌ=ë\10ͱ\ 2\ 3üR©ûÓ\88\e\93åñ;ª\1a4
\98}¨@äÃz)=´yBK`è1ír\9f\eõ7?dô\85\83Q\vm\93©\9f¯^\8fÑyôÂkD^²\891Âê2B\95ZQC\16 \10ùrKdì\19Ã\ 2'BßíXº\99z%ÂлKÉÖ¢Ý-M7D\9a4_\9fø2¬ \99w\10 ðÈ";à\1fPIê!ñ\9f6p\13IJ\12òµe\b\88¶P£»ëf\bê5½\84ü\16ý¤\99\81\88¡c\85ЬëÎu\0u]\89nrÖ\h\9f½\vÔW\8b\87Rh\14¡Úö©<\84X"A´Þ»é¥Nñ\87¶Ôã\87ãÅïÕ\eý\9e\13O\93\90gé4\99I\1e* ×V3\0©û\v\90\94%H\12öª\80\98rmä\80\ 6\18\15¥ªb\89GíÌÐ\9bk¶:ýõ¦\ eðÉ~ÞÄÒß\16O\v¬NxÜ\ 1¤a\92ò7\7f\19r8=Ñ㩦\95­nÚ2F`e,ìp\82¨<öItõ¾D\8a«+\11R"\91÷\1cÊj\1f}\ 34¡(¦\88\e\ 2\9a\89û\14\7f7\13Î\83è´]\rvL\91é\13\1f\7f\9cyùÿÎT6\90à\89÷\17¢ºè½=¹Ci\85åM««HË\93I{Í,­\8b³\15Ò°\97\98é7oªª\81\7f©¹ô\8c%©Ã\17­Yfg\8eª>\rP@Q\ 6¯¶Kª\19ê°\9eÙ:%ô´/Q×/¸v^ËN£\88Ú3U0Ó\8a\87²À´\97ÓQ`|k\1fVrï\82\14äç:<ís\ 69w¢od7\8b·\8c¢ö\1e\ 3ÁäºcßYãíÊ\ 3#ê4¤\96\17\13¨\ 5ÝÙ\88D¸\19\99¡]ÊG|§\ 3\rÚ²áI¢s¢ù´xiê\84¯.Q9:r"n\v\96\r>S.Ê]ªØëÏC¬am¿yºÈÃÉ2z°Ö¢\87JªRWÏá\87ï÷$\84&Ó¹÷t|®û\9cÆ*p(®\1c\0\9bÐ7`¬â
+GáF\ 3»v:x©^\95\8c\9c1Ãùì¼\12#\ac¾~# ¦\80á϶1^Ej"\14÷8-\8aù\f\86 Ô\93¤C2úS\ fFúq¢Î²\11,7\10âÓá)ÅL] dp\99±\9cæÀ\rÛ6Ù­5º\13\ 1-\87¬ÆM\8f%\ 2\8bÆ\14\85%)¼\10o\1fàñÁjÜy@\1fɱqÙÙÓgæ\7fW
+\88Ë\90é\90\ fíw\ 6Ák\rÍ\14´\133°Ð\98\10b8/L\90õ\16æ\9eæy\91LL@÷Îx\92\1e\rÀ\88\99I?îÝ,\96\81\88\92ÿ\86ÑZøZO\84dOçf(¢t\8d\96CãíüѲò\94\v&j\85hRf¢\9bsæ~\89\88\93ÉþÝ1¹r\9a\va\9b\8a"(¢Ö\9ai\85\fùÃS;Ðñ\1c{\87iÔô\9b+J\99%z\95+ÔѪ\ 5\13±ù-ÈÒÍ\12l\ 4ä\ f2\7f\b!+#¾`px\r±.\ê\89`A\8dkWÙÛöºjuE\13$2³jL®
+Ït\9fè\97­\9d¤'\84|¿QL\ fÑ\8d0wo~¼º\88D\16¼Ú\11\92X"\99ñ1íf\95\e\1f.u5Ö£:N\91ð÷Î\ 3øfr´é)¥\9f7\97\89Äu¼\ 5(ï3o\1dýcá8îÛS¶å¿»/ÒáWÞ\89çdÓ\0!y°V&êL\82÷Í\ 3\f\19>$>7 \81ï<¬\13ª"{\93¯\16\a|úÕÈ,©7Ý»$;='+\84O\9e\8dÞ)½Søp\98X¯4Ø\94\ 2ç\80N¯é\9eöÅy ii<v"\8b;|²ñTV   Ö\8f{8ÊÌg±Èlh8òÄ3Ë2\91K£Hs¬ý\92ä"\8a¤v¶æ¨e\8aÜoG,Ýå\88is\85\9eµ\9f6egJBD
+BÕp&/à7j§
+G/Q£$x\8cÁCÂ.ñaW«2%«à\ 1È¡`L\81\ 4Î)´]£\r9cÌ4Ý{¥Ð\1ev\8a\1c\10=\1dm\ 6\846    \8fE\8aL\1eÓ\80Ä®=N\81î8'\93¿7¦`Ë\8eG{\1c
+\12¤ú\8egï¶ÃU>\85:\1d\10$¸²\1dï½Ê+ô\ 2s\98&¶²rÇý=\92BÄþ
+\12\14ë\8e3(\91\93\1a\nDZ¦Î]B\9e\88yôçÌ\1eì¸T@#ÿéñØN.L\9eA«ìx¤ÇÁ\915\ e½\1dÏ\12éñ©?\ 2\7fÇ#ü \95\92\99\1eÚÅtÛì¸)Q\1a23³ãOfuòYãá\8eÐã¶F*ýÝq\ 4U&ú£ÞdÇ\e=>©\9b\80Oðèñ\b~Çõ\81èÌ®ô§Ë;n  ô \11Iùì\8eû:`ºcÜmË\8eGz\1c\185\ ev\1c\8f|\1c§£ß¬\8f\82VTâ\8e»Ì0¯Çû7«ê\1d\7f\9a\96ÝãE\82A`;\9eL¿Çz¼\0={é\8e\86s\9d_\ 1w7Úñ\99\1egz¢(¢ßã:É\8e\8fôx½\14\88ì8B\8f£Êã\0tÇ÷\19ÀëñÎ\99dDÙñ\9b\96ÍZ*Cw\9cÞÿ\07¼Ö\85;n{\e#kd\fb\ frc\f    dظÇ%q\8c!?ÎGHc.Üÿ\18Ã\162bz|]Cë1Æ\1e2À{¼\8d\90\9d\92\8aX2ÖMR\8e1\8eCƾÇ{éÛÆ\18BÈ0ïñD!Lå\1d\8f¹¹K×\9cð"\ 2|ð¸;#\13\0\9dæd]#Ø{\vÉ£óÚm\ 5\ 4¡ÌX\86ê
+\1d\9fë¡h\84Ôr`£Æ#   íù\89\98ÑÞrÄ?\ 6FÜ»ý(d\8a\10kLï0`\ 5R\92ÀP\92\86(\16\81\92+ðUZÖ\96öÐÙ\17"¹n?QÆ\87@ɰæÉ·oÅ\ 1ÛúÎþ¦¡·Gíp\8e\98\1d\8e\16^:O\bE\87¡ºKÑÏcÀ\183è7¼Òk\ 4s¶+\92\86W\89}\ 5=\93ÂË\7fÁ«Çm±àÕq-\12¼RlWëxU¹\ 2\85ýõM0)\e>^ÑÍîù[Á«ÐvÕóðjË`xÛU\8d\81Wd\1d«\9b?2»ªíxµYÚmWö\1e¯@\8b±µ«Ê0#\1dÆÜ\1dvQ2Pwç#*ÑÜ»b½½¼Ò\15Abd\86\17\8a)\7f\89ÿøö\87¿åÁX$´X½`eZ¡Ü'LE£\ 2qÀìD­<î\e\83e{L¤Ùó?4Hº\8d\92\93É;©à._.SåFóº:<:\81:.¯ÔFe2&9NW @\8b¹H³6\80\82ŵ]ÿz\86\81¡\ 4"0J\98lçÐ'RH©5Ó¶\97QBÒØ\17ÎS¾:3Æå­yðX\85ðâ*/g8Ð\ 6\84uÀQöûüâ7¥ÊR\1aZ\ 5\1dÐá:íð\82!'grÆUI\9c¦a\84ìÿÿëÜߦÚÎqiæ\ 2_Õè4\16#4%ó\14\9e\1a}¡,/
+þJt¤|D\8d\9cuò$×ò^â¼ÌãåE\ e\f\7fcÕ¢©VÀjÈÀØ!2¥*Qþ¢;è\82«A²#\ 1ú~;XõåÄÈ\19\9dhÙ/I>SL¢\ 5g\b´½v4¿\80"\0Ð\f¸iº!\10©â?ku\14 @¿øc1¸k\19\92g¸Ö2x\1c\bZ\8d\18Y1\90T\10X\12]àÈøµ\ 1\16\ 4N{õ>¦iºé\932P\1e\bùpE³êPq¢­\0ª\97à"o\9cçx\17×§\86rh\rÃii j»\87U\1eyy     î\88\0Ü\ 3ôZYfª!\8c\19:3æ§_\ 3\84\15/JÃ\15\8f\87¯ãÐ2\aò%õS\8c'\ 4KPvºA\ 2\99GRé³íããÛF+½vÑiþPMD\18\ 22\18TM]\82ºaKW\89¤        9ï·õ\9b\1a3\82ÀNî\f±\8fò¶Ø-*'\ eï\8eb\95Q\12^\11þ\92\97XÁâEø\94\93\8eÚê\88ËÏIL\13\d\1e\9bvq\ 3\a\13Û'ò\16j5±\98\1aïRâqõº·\927o,ÀÆØùj\1a\83u\0bôhK\96°ieAÈ\94^\8a\855>ÿº4¥\r ü^Ò\97Ðiý\1aöMlKöì\152\99\80Ȥ;\18\83åwå¨\85]\92c`Ë#\81¡\ 6Ë\9dT$tÐ_\85A\9a~\82ú\ 5ÿ!L9­o\8d\e«\1f\89ÑO-@EÀì±í?¬\10ÅË-{·|Â\1aÏþ¾ò\14\8a\ 6ë8ßñ\9c\95\11`GB\99Î\ 2ƲÌþ#v£5*\83Íyê\9eÌf:&\f\8fOX¥\1cj\83Þo\0~o°Ê±\1a¨q6ìéâ\95$\1dÊ\1e]â³ñG´ÃGi¯8ðϯ.f@\aCôxêe<9=Ö;\9a«è\9fM{ñ\8d\eÈÜ\10*5\85ª\ 46ELzY\14õ\7f\98!k[\ 5wôÒv\a\87N}¿òj²Là\vF{Ø%¿üGÌ~\94ù\14\9f\1e^õ7ä\b\19\86èp\f¦\81\ eÏ\99± {\98.&Z¼\92â§\1c\10K\9f\1ap\ 3ÍB¤Ã{µ±=\1eµ\14»\11\17s<÷A;wE
+#Ð4    \83õ\86\v×Ê£ÉéÁ;\ f\8e_å2lV\eæg\99ÞÏâ:è\12\9d±\rË\83\17\1a8\1dvÇúÌÐu/K3.E̸£\v6Á0\10»ôCÎ\11\9cæ\89Y\13üdK\90Õï~\8aR¢R+\83ã\9cJf\0\10\18-ÿ\e\97\94
+wÆ\18>e!òÓü¢ÌÞÞa.§c±\8e\9c÷XÀ\84_¾÷%y\157\11\8d»°­â]\9f÷H6K¡\8bàùi\ e!Éê>~\ 3¢.Ïu\0\15Oe\11IæAü¶÷î\8a§lO\9aø>5\19ñ\ 4®9î\1d¯W\7f\8eÈY\9e\1aÇ \9e´+\84L\ f£¡xÚ\7f\1cAïÌ\83x¿\16¤\9d\9d0\14O\0\8eÏ\92o\8a\93u«¹#mZ\8ex\12\9dÌ7Í\9a\1fR<Å\9fo\8cG+a--\86\8e\ 2ÙW¶\9bo^\15°¹¶ÑZ    \13óM\12?+àÖrÁÖU\17ó\12m\ 2\9e\8a9í ö\87\9b{ý­\83?­àsD\86Í.}ä2OHÞÇb\7f\8f8¤Í\83Ì\90±B{µöM1Çä^})\80£BAm\v\81h=«LR@dFqSÛÄUø®°\8e|6;&\16c\1a\b\b;{/äyÈRÝwLâE\9c\8fè\88;;\8eù±øì¹L\16ìB/FÃw\1dó/ü\8aH\8eÔRîÂE:ùD\0\\8f\96\ 6Ì\13_tm7\8eÛj5¤-ôûT\18\8d\92\87DMrf\16Ì\ 6ª&ÎUG{x?ä\ 2éä\15\98\90³¥Tô\85\fa'(&O\7f\99}\14ïD\8c¥_­.ÜÚp%NË\9d\12\1az5% Ó­¾WüZ\ 3\0\ e\a`\vq\82Ñd]¬½A      8-¡\ 2£[\19ÌW\8eâ{è \97þ        ¥C)\9d\13D^/\89\1c\97ØÁ@y=ÜóÙä\91\93Zß·¢8{vÉð\ 5+X=\9bÙðè\1aE k}Ëh\8d\99M\9d7\17¸Î\8b\9f\131m\89\1a\8aÃG\19\ 64Dîw\b\13ûaH6uj\86\b\8d§Ç(\16"¶ô`\ e\84æ¨Uu\eýÅÍ\8a\90} øg~<E¼p\8d§\97ò\9dU\89Æù\1a]\95Ä\82ÿ&¶Ë§Ì\11 \0^
+Òæ6<ÛóxBPñDb\9d(Ãó\88Ëüú\87\8b-oRÙµ\88ìã\14bûx²í   \vE4\9eþ\1c\84\96¬aòö    /ÕxZÄ~ ÜÓw-ã´\87\94%O6T\8dPXÅ\98Lؼu\ 2ªØì\7fª­_\1f\1a\9a\83Ð)¸5Ä\1ckÿ[ð\98U®Ö^\ 2\9eÜÕÙ\e\92ø\ exPí\85¹nB_\10-1ÁÌü×HÆ\82Q
+FR\13ÅØ\85I\83ü`?¸\ 1
+\9b¾\vILÀñöZc\8cÌ\95\18;\1a\12wÐxÙ  k\10çCÀ\1aª>3Ê¥´4\8d\r¶~\9dc\ 2]\876E\f\95gAì½aĬÎÍp-u\ 1\92Ý\15\8c\18\ 3\87/\eÕ,ø
+,Ê\bKïùës\85U®4h\91L׸Q\97/áEcì\18§Ú+ît\93t\1dNp®ÄÛ(|Êð\9c©G)ñÿå\18G\9a
+¯mÁ\\96\9c\10\84¶LÌ7W²ÏFþºã\86\84ë\90.k¹
+\eó}n¿¨¼\81\98\86\11\12õ\b\ 5Q×A)\0e³sÑÂ\19bÕ[q"x\ 1\0\94Ì9ç\ 3³\8e\1e\14Q\8b÷\1dÿ\97\92\90q\1c\95!\ 6ÿ\9e\1e]EíS\8fJDÐI=z\f\94\ 1\18\85¦\87Ït
+o{+\9c*¯°TÝðÌ-È\9bh\108L\97@sçÞÎ\98k~ï{í\85# SH{Þé\8fÃ\91tͼ+Pà\8fLk)O®\v\99îzúN\13Øq\99.ÓBA,. @\eF·DG\92áw\7fVcSb&¹ \84\80ë¿ ÃFa?cõ|íÊ\12\17\ 1ãg
+ñ¾[ö\f\90çB£YO}4\bÖÉeyP¯e¢Rb¦ÆW\14º6m\9dú\1d\a%q~Ï\91^§Ãæ\ 3öLïß¹Þ\1fQÿ3¹;\15Û5tÔf?@ð½'ÞZvÚv\17ÙMw%áMÕ j_«\ 5\82\812\Û²ÍÉ'5è\96¨ªÚª\16W¢rõÑ\\7f\7fCìú°»¶\98Uö B\89²*b²éÍr"N»â§W®³o#9u\14ëj)"\14VX\1c¿Ô\ 5;H\1a\9a)\a6\8d ÝFL¨ý\12­\1f\81ã\b\a±\a%ïe\ 6\80RMËíJ'\86ö\9bÜ¡¶f)§~÷$æ\11½\1d\10ö)4ï\10å\87E¨­T]ÁøÍÈn\ 4Ö9\86\93\87HcX¶oÿÛ\18>Þr³Ë\87\7f\1aw\ 6¡d\a±\ 5)](oÜØ\1aÛôÓ\19òð\94\18ì´pQ¥n\9fE`\ 5\12Í.\8e\98!?g¨Jt\8e\19õ¯ØÏ\97\87\9d¬¹IïOQ\rßУç;\8be^Mm\7fþ¿LnÒ¸\11wÌÀ\15\80Ã*ýË\9b\80@ògãÀô\15\98\9b\14\r\11ʳ iüûe¶IÊ\14Û\92\ 68Òh»Ï\84¥ÅÞl\15,ý«k2\81(\19¨\7fo
\85\83\9dk*ï\10À¿\81\82¸\f÷
+óy\8f\9aéß_£\9f"öÿKÿªñ\8c\b\f\ fö\86\rE%\0sH¬¼\9b2xøWç²BÃÚ\91Õ¿AK\v?ý¢äÕÕÒæñîp-A\fÿR\19¡p¦\7fé\9e2v\85\7fINe\82d\1f¨®µ\f\11ð/^Üù\9bB£¬Ñ\94\9fÜA]\91\81ô/Óõ\9d\91\91Ü®,Wø÷\85\8a&Kê¿~ètuÂ\ 5\95ËúÁ\94\8c\8cûÛ\1c\ e1éà\8fW@EujQMa\ eA\ 6Êm%´\1c\133\9d\87B\11°Ac[¡Ë.cS©©f®Æ\91îÊÞ£eu\f\1dÔwJ\16\v\9c\94\8eë\87Vp \10Aå8\f\ f[ºbY\80h¹¡KÀ\1d×\19´\9dF~aï,Ö\9eÖ4xjæ×ò\13\98@c¤Dá    \98\85mì"U`\8f\9dB\8cÕnE]f>Û.úÂ\fl(G|Ä+é¨am~PYêÌ8U\9e\14m¡@ȤDWàæ\13\13H[Ñ\1e\8bõS\90ßkö\86\91\9aÕ@°}ú\98¥\ 2aZ¹t^_Wêf$¸tÚå¹\7f\17yÁå~»\82wk§LMu\81\12k\8a\ f\98|{^\8aòÜ\90ÚÍ1Õ\88óÔP5\ 6&\1dÜÿ\a\16²6´¡zª\10\96a7Xn\aô°êÕº4à\7f\92<ëMÈÌB\9bÚnÒ\9c餣¶\85Ú*D%\94*\ e¤Á\96\e¦Ûè\93¥\88õ`\86¤,®ÞeZBø`\9c©\82\88\fª\1aiµÀ\ 1      ¡\82\12/\87\1a»D\94\8eyßR:8,\10Ç\11wø1fß\ 6\7f\9d½\ fz{Ó\ 2RÙ9G»\9eïR¯\\K\88"\aßn\az{g\ e\83ôJà\10
+\1eX¯¤^\9fÊÿ\8cåSlR/ì^Yw\91P\84\98x\b\13\ 2ê½ÿ\96õ'\r\9aý\17J|&Ñ5\97HKo\10õ\89¹Ù5é#Þÿc\1cêµf\17\8b\e$ÐM\8d Þ8qªÝ\1cC~R/h²6©6 Z°q\ 3S@)M¤=\9c\94z5®7YW\1dÇ\11Sm¸\9cU15wAÚ\r&\98×hs\8a\86\19\ 2î¤qd}Ñ6\91\94M:¨r'Ó\8b´ejª>gÁî\9f¹\12rWR¸\96\8f\82\13ï·\18\82\9bëE>\8aÅn\19`þt¯\17=\9aþa$vY\1fZ¹ÉÂ5¸øI6Ð"Ú°}\19iB\89\8cÃ\16~]%É\eÕ)2FÉè`çâ\92$eL\91\8a&\84Söw(?ÞxÅf]\8c&ÄÔ\8e%SL¿â\950v,L¨\17\ 20¹8Àj\94\ 5õ>\82\9a%%}Uä´@\rHÇ   ½3^á?áxÌs\11w\8c\13Å,¥<JQIv\11âIP¬(ï{\ 6ìñ\ f\v±ì¸3Åæ+\82ï¥8¥­ ©\ 5\8dò6D~\ac\ e¾ë¨mV\9d¢$Û\92m/_$ùʺ¸\195X\809T\ f\1c'¹D\91Ç8AXv)\v-\8c^ªn\ 6Ĥ\16\12?j\ f¦\83\ 1\12µý\ 2Uú?        ÕNZ\9dJ\fñ\18\7f·%dG\8f\bü£§ÇIC÷mE\03|w­ÿì\ 6Ìv'³&U½è½t\8b\ 5\8cmdÜ}õ:iGD\9cæ\b¾S\90Þ\82\81\7f\870Qõ.Û\88Â\9f4\0W½`ÝÄ_Ы1íjÕ{+4ê\99\93ÎÒ\94'hl\99\1e\9cÃ\15Få¯û$´1h¯òò2\ el?ÀÀª7År}÷O¸|õj0\8cöÖ\99ãªÞ\ egW\b¼zA\8b\83$à&¤A£#VT½\90>×öª»W'¬(»¼CÚÍb\8c'¨ù¿\87Æ\bÛ_q\16\8cZuBã½ov¾\92\10³\86\81       ò\v\8f°G\ 1ì'öðH!\84Îí\96Ñs'95áÐÅ\11aGÄR¹|\81\97CÅxÁ\e\12ô0m\83\99\br)ðv¾I÷)b\16ard\877t4x\88wSIüZEÇü¼ÄÀ0\ 4\ 4H=^\8a\80ØJFø\8f¾òý\8dÊ+æ\19Þ'É3Eû¼mÒ\97ø\91\b\8b\fõþº3µnìDíúÜêi+\8a¬ÈúÊèÕ\12·\18`\8f\86Ã\97ïx\ 3#8\ f\84p\94²\85IAm°\97Ô×\88q\ 3   ¦@°\178ò;g\ 4\81+\90ú\ f#åEXî\ 4\86许|¡\85å|ÃF}\1aÍ.þ\94ÙÝ\19}Ë|| ®À Ëè9`¬\f&§ð
+{cÀ¹\8cmI\9bo?£Tåaý½\1cøÇ|/\ 1¬\8dc\b¢\9d\13\9f{áî^:â\97\1eî\87ywq\8d\95\8aûÍ¡3(v$8«Fb\bí\18ÅvúEOF\ f\ 6Ä\8f¿AÓøR'$¤ë¬³¢\84,)\94¦\94\9fGG\12\7f½~l\1aÞ]Ò\1aµ\99,{Ï|~w\8bý¤÷j\186-Þ­s\86Â/ð°ï®\ 2\7fã\ 5\7f1KÒóÇuêÝ%Ï\11ðµÝfpä\13Ç\97=^ýëÕÃCIº*¶ùü©     \8cðFrÇéÝ\8d´lóìÅ\eèݵÿÝ¡\ 3T:äÒÆ\87GÝÞÝ=³ÀoÀ´c²DÅ»ü/+ß$a\16ù¢\9ex7¨®Ú_æbzw\15D\9b\17\88uÝ|\8d\ f\ 5\19kªô4$ùé2g   N\92o\10\8e2\80Ý\8bø= o²â¨\80!Å«_´\88\83ÅÔ[<[à®Ç\94\ e\13è}&î> \7f[d\12\1c\82\13\88KEm)\0-R~kGÍ\96ÉÜò\86\8bk\19º¢5qQ9ñ\1dsÌÏ\ 5Ôý\12R\9a\99\8a&IM¬I§\19\ fÏ\83v\80 ß¨\8ag\19ú\96öÿñ\a|VÉ\8c\13-kÌ¥99ÂFp\a6âÃ\95ï\88äf\98\ eI\ 6Óê¨mª?&\8b\81\ 6®î\14\f\17Ãu)Î\8aëÝ(üwÒ Ê8ð¡\a\b\82¹*o,ì\87©\805\86Z\8fÁöÌ ´l-\96Â\¢µ\0FYL§\9c\1e½®ÑMXöY÷h³Ñ¡Û¤\19\v\b\8eó\0?ÿ<³¦\e\99KoyÂ\9dÈÒ7'ÚæÇ,s\ 6\18í\19\86S¸¬\8cÕúd\0\88\92A.KiJ\9a@À¡i\96eÎ$k³ß\98k~\8aGs\0´y¾±\9fÂU¡|û\1aëSï\99¶3xNð\94ö©r¼'¯\ 3<\9dr$\:õºÚÕÕ¬Êëh}tÂ=\89­jål&þ#n$¥\89óÎfn\99\9dXÂ{Gö»\85ÜÝéÙÄáeùyõÞ/RÚ\95h¢VtXy\15¶ÜÆã´üé \81Ý¥Þ9¨s\85\9e%j~\14ø\87\92ûØõ\rĶb\búé±\ 2\90îAîî«ø\14\19¿¼\94
+\7fLA5NRh\86È\174    ñzÛ²$ \14q&þS\ f\19¼\ 1fÇÐJ\ f®\r  \ 3\0\ 2®\ 4\rendstream\rendobj\r22 0 obj\r[21 0 R]\rendobj\r32 0 obj\r<</CreationDate(D:20200725234456+10'00')/Creator(Adobe Illustrator 24.2 \(Macintosh\))/ModDate(D:20200725234456+10'00')/Producer(Adobe PDF library 15.00)/Title(Jacktrip)>>\rendobj\rxref\r
+0 33\r
+0000000004 65535 f\r
+0000000016 00000 n\r
+0000000147 00000 n\r
+0000038245 00000 n\r
+0000000000 00000 f\r
+0000038296 00000 n\r
+0000000000 00000 f\r
+0000043346 00000 n\r
+0000000000 00000 f\r
+0000000000 00000 f\r
+0000000000 00000 f\r
+0000000000 00000 f\r
+0000000000 00000 f\r
+0000000000 00000 f\r
+0000000000 00000 f\r
+0000000000 00000 f\r
+0000043419 00000 n\r
+0000043593 00000 n\r
+0000044772 00000 n\r
+0000110360 00000 n\r
+0000000000 00000 f\r
+0000040363 00000 n\r
+0000142712 00000 n\r
+0000038693 00000 n\r
+0000040663 00000 n\r
+0000040550 00000 n\r
+0000039334 00000 n\r
+0000039802 00000 n\r
+0000039850 00000 n\r
+0000040434 00000 n\r
+0000040465 00000 n\r
+0000040698 00000 n\r
+0000142737 00000 n\r
+trailer\r<</Size 33/Root 1 0 R/Info 32 0 R/ID[<0736C03EA6374B77AEB4921C0FCAF2A6><B3D402B8E9994E6585EF6BDAA695FC42>]>>\rstartxref\r142925\r%%EOF\r
\ No newline at end of file
diff --git a/src/gui/NoNap.h b/src/gui/NoNap.h
new file mode 100644 (file)
index 0000000..0fe3eda
--- /dev/null
@@ -0,0 +1,45 @@
+//*****************************************************************
+/*
+  QJackTrip: Bringing a graphical user interface to JackTrip, a
+  system for high quality audio network performance over the
+  internet.
+
+  Copyright (c) 2020 Aaron Wyatt.
+
+  This file is part of QJackTrip.
+
+  QJackTrip is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  QJackTrip is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with QJackTrip.  If not, see <https://www.gnu.org/licenses/>.
+*/
+//*****************************************************************
+
+#ifndef __NONAP_H__
+#define __NONAP_H__
+
+#include <objc/objc.h>
+
+class NoNap
+{
+   public:
+    NoNap();
+    ~NoNap();
+
+    void disableNap();
+    void enableNap();
+
+   private:
+    id m_activity;
+    bool m_preventNap;
+};
+
+#endif  // __NONAP_H__
diff --git a/src/gui/NoNap.mm b/src/gui/NoNap.mm
new file mode 100644 (file)
index 0000000..cb2edb2
--- /dev/null
@@ -0,0 +1,58 @@
+//*****************************************************************
+/*
+  QJackTrip: Bringing a graphical user interface to JackTrip, a
+  system for high quality audio network performance over the
+  internet.
+
+  Copyright (c) 2020 Aaron Wyatt.
+  
+  This file is part of QJackTrip.
+
+  QJackTrip is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  QJackTrip is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with QJackTrip.  If not, see <https://www.gnu.org/licenses/>.
+*/
+//*****************************************************************
+
+#include "NoNap.h"
+#include <Foundation/Foundation.h>
+
+NoNap::NoNap() :
+    m_preventNap(false)
+{}
+
+void NoNap::disableNap()
+{
+    if (m_preventNap) {
+        return;
+    }
+    m_preventNap = true;
+    m_activity = [[NSProcessInfo processInfo] beginActivityWithOptions:NSActivityLatencyCritical | NSActivityUserInitiated reason:@"Disable App Nap"];
+    [m_activity retain];
+}
+
+void NoNap::enableNap()
+{
+    if (!m_preventNap) {
+        return;
+    }
+    m_preventNap = false;
+    [[NSProcessInfo processInfo] endActivity:m_activity];
+    [m_activity release];
+}
+
+NoNap::~NoNap()
+{
+    if (m_preventNap) {
+        enableNap();
+    }
+}
diff --git a/src/gui/about.cpp b/src/gui/about.cpp
new file mode 100644 (file)
index 0000000..a61d4c2
--- /dev/null
@@ -0,0 +1,84 @@
+//*****************************************************************
+/*
+  QJackTrip: Bringing a graphical user interface to JackTrip, a
+  system for high quality audio network performance over the
+  internet.
+
+  Copyright (c) 2020 Aaron Wyatt.
+
+  This file is part of QJackTrip.
+
+  QJackTrip is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  QJackTrip is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with QJackTrip.  If not, see <https://www.gnu.org/licenses/>.
+*/
+//*****************************************************************
+
+#include "about.h"
+
+#include "../jacktrip_globals.h"
+#include "ui_about.h"
+
+#ifndef BUILD_TYPE
+#define BUILD_TYPE "";
+#endif
+#ifndef BUILD_ID
+#define BUILD_ID "";
+#endif
+
+const QString About::s_buildType = BUILD_TYPE;
+const QString About::s_buildID   = BUILD_ID;
+
+About::About(QWidget* parent) : QDialog(parent), m_ui(new Ui::About)
+{
+    m_ui->setupUi(this);
+    connect(m_ui->closeButton, &QPushButton::clicked, this, [=]() { this->done(0); });
+
+    m_ui->aboutLabel->setText(m_ui->aboutLabel->text().replace("%VERSION%", gVersion));
+#ifdef QT_OPENSOURCE
+    m_ui->aboutLabel->setText(
+        m_ui->aboutLabel->text().replace("%LICENSE%", "This build of JackTrip is subject to LGPL license. "));
+#else
+    m_ui->aboutLabel->setText(m_ui->aboutLabel->text().replace("%LICENSE%", ""));
+#endif
+    if (!s_buildType.isEmpty() || !s_buildID.isEmpty()) {
+        QString buildString = "<br/>(";
+        if (!s_buildType.isEmpty()) {
+            buildString.append(s_buildType);
+            if (!s_buildID.isEmpty()) {
+                buildString.append(QString(", build %1").arg(s_buildID));
+            }
+        } else {
+            buildString.append(QString("Build %1").arg(s_buildID));
+        }
+        buildString.append(")");
+        m_ui->aboutLabel->setText(
+            m_ui->aboutLabel->text().replace("%BUILD%", buildString));
+    } else {
+        m_ui->aboutLabel->setText(m_ui->aboutLabel->text().replace("%BUILD%", ""));
+    }
+#ifdef __MAC_OSX__
+    m_ui->aboutImage->setPixmap(QPixmap(":/qjacktrip/about@2x.png"));
+#endif
+
+    aboutText.setHtml(m_ui->aboutLabel->text());
+    aboutText.setDefaultFont(m_ui->aboutLabel->font());
+}
+
+void About::resizeEvent(QResizeEvent* event)
+{
+    QDialog::resizeEvent(event);
+    aboutText.setTextWidth(m_ui->textLayout->geometry().width());
+    m_ui->aboutLabel->setMinimumHeight(aboutText.size().height());
+}
+
+About::~About() = default;
diff --git a/src/gui/about.h b/src/gui/about.h
new file mode 100644 (file)
index 0000000..28766b7
--- /dev/null
@@ -0,0 +1,56 @@
+//*****************************************************************
+/*
+  QJackTrip: Bringing a graphical user interface to JackTrip, a
+  system for high quality audio network performance over the
+  internet.
+
+  Copyright (c) 2020 Aaron Wyatt.
+
+  This file is part of QJackTrip.
+
+  QJackTrip is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  QJackTrip is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with QJackTrip.  If not, see <https://www.gnu.org/licenses/>.
+*/
+//*****************************************************************
+
+#ifndef ABOUT_H
+#define ABOUT_H
+
+#include <QDialog>
+#include <QScopedPointer>
+#include <QTextDocument>
+
+namespace Ui
+{
+class About;
+}
+
+class About : public QDialog
+{
+    Q_OBJECT
+
+   public:
+    explicit About(QWidget* parent = nullptr);
+    ~About() override;
+
+    void resizeEvent(QResizeEvent* event) override;
+
+    static const QString s_buildType;
+    static const QString s_buildID;
+
+   private:
+    QScopedPointer<Ui::About> m_ui;
+    QTextDocument aboutText;
+};
+
+#endif  // ABOUT_H
diff --git a/src/gui/about.png b/src/gui/about.png
new file mode 100644 (file)
index 0000000..0f877b9
Binary files /dev/null and b/src/gui/about.png differ
diff --git a/src/gui/about.ui b/src/gui/about.ui
new file mode 100644 (file)
index 0000000..afff2b3
--- /dev/null
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>About</class>
+ <widget class="QDialog" name="About">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>524</width>
+    <height>310</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>About</string>
+  </property>
+  <layout class="QHBoxLayout" name="horizontalLayout">
+   <item>
+    <layout class="QVBoxLayout" name="imageLayout">
+     <item>
+      <widget class="QLabel" name="aboutImage">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="autoFillBackground">
+        <bool>false</bool>
+       </property>
+       <property name="styleSheet">
+        <string notr="true">background-color: rgb(255,255,255);
+border: 4px solid black; </string>
+       </property>
+       <property name="frameShape">
+        <enum>QFrame::Box</enum>
+       </property>
+       <property name="lineWidth">
+        <number>3</number>
+       </property>
+       <property name="text">
+        <string/>
+       </property>
+       <property name="pixmap">
+        <pixmap resource="qjacktrip.qrc">:/qjacktrip/about.png</pixmap>
+       </property>
+       <property name="scaledContents">
+        <bool>true</bool>
+       </property>
+       <property name="margin">
+        <number>0</number>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="imageVerticalSpacer">
+       <property name="orientation">
+        <enum>Qt::Vertical</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>20</width>
+         <height>40</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <layout class="QVBoxLayout" name="textLayout">
+     <property name="sizeConstraint">
+      <enum>QLayout::SetMinimumSize</enum>
+     </property>
+     <item>
+      <widget class="QLabel" name="titleLabel">
+       <property name="styleSheet">
+        <string notr="true">font: 24pt;</string>
+       </property>
+       <property name="text">
+        <string>JackTrip</string>
+       </property>
+       <property name="margin">
+        <number>3</number>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLabel" name="aboutLabel">
+       <property name="minimumSize">
+        <size>
+         <width>366</width>
+         <height>191</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A system for high quality audio network performance over the internet.&lt;/p&gt;&lt;p&gt;Version %VERSION%%BUILD%&lt;/p&gt;&lt;p&gt;Copyright © 2008-2020 Juan-Pablo Caceres, Chris Chafe, et al. SoundWIRE group at CCRMA, Stanford University.&lt;/p&gt;&lt;p&gt;Graphical user interface component originally released as QJackTrip, Copyright © 2020 Aaron Wyatt.&lt;p&gt;%LICENSE%JackTrip source code is released under MIT and GPL licenses. See LICENSE.md file for more information.&lt;/p&gt;This is free software and is provided &amp;quot;as is&amp;quot;, without warranty of any kind.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+       </property>
+       <property name="wordWrap">
+        <bool>true</bool>
+       </property>
+       <property name="margin">
+        <number>3</number>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="textVerticalSpacer">
+       <property name="orientation">
+        <enum>Qt::Vertical</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>20</width>
+         <height>40</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <layout class="QHBoxLayout" name="buttonLayout">
+       <item>
+        <spacer name="buttonHorizontalSpacer">
+         <property name="orientation">
+          <enum>Qt::Horizontal</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>40</width>
+           <height>20</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item>
+        <widget class="QPushButton" name="closeButton">
+         <property name="text">
+          <string>Close</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="qjacktrip.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/src/gui/about@2x.png b/src/gui/about@2x.png
new file mode 100644 (file)
index 0000000..f51508b
Binary files /dev/null and b/src/gui/about@2x.png differ
diff --git a/src/gui/icon.png b/src/gui/icon.png
new file mode 100644 (file)
index 0000000..9344dff
Binary files /dev/null and b/src/gui/icon.png differ
diff --git a/src/gui/messageDialog.cpp b/src/gui/messageDialog.cpp
new file mode 100644 (file)
index 0000000..35c70a7
--- /dev/null
@@ -0,0 +1,57 @@
+//*****************************************************************
+/*
+  QJackTrip: Bringing a graphical user interface to JackTrip, a
+  system for high quality audio network performance over the
+  internet.
+
+  Copyright (c) 2020 Aaron Wyatt.
+
+  This file is part of QJackTrip.
+
+  QJackTrip is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  QJackTrip is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with QJackTrip.  If not, see <https://www.gnu.org/licenses/>.
+*/
+//*****************************************************************
+
+#include "messageDialog.h"
+
+#include "ui_messageDialog.h"
+
+MessageDialog::MessageDialog(QWidget* parent)
+    : QDialog(parent), m_ui(new Ui::MessageDialog), m_ioTimer(new QTimer(this))
+{
+    m_ui->setupUi(this);
+    connect(&m_ioTimer, &QTimer::timeout, this, &MessageDialog::writeOutput);
+    m_ioTimer.setInterval(1000);
+}
+
+void MessageDialog::setStatsFile(QSharedPointer<QTemporaryFile> statsFile)
+{
+    m_ui->messagesTextEdit->clear();
+    m_ioStatsFile = statsFile;
+}
+
+void MessageDialog::startMonitoring() { m_ioTimer.start(); }
+
+void MessageDialog::stopMonitoring() { m_ioTimer.stop(); }
+
+void MessageDialog::writeOutput()
+{
+    while (!m_ioStatsFile->atEnd()) {
+        m_ui->messagesTextEdit->moveCursor(QTextCursor::End);
+        m_ui->messagesTextEdit->insertPlainText(m_ioStatsFile->readLine());
+        (m_ioStatsFile->readLine());
+    }
+}
+
+MessageDialog::~MessageDialog() = default;
diff --git a/src/gui/messageDialog.h b/src/gui/messageDialog.h
new file mode 100644 (file)
index 0000000..ccb0bcd
--- /dev/null
@@ -0,0 +1,61 @@
+//*****************************************************************
+/*
+  QJackTrip: Bringing a graphical user interface to JackTrip, a
+  system for high quality audio network performance over the
+  internet.
+
+  Copyright (c) 2020 Aaron Wyatt.
+
+  This file is part of QJackTrip.
+
+  QJackTrip is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  QJackTrip is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with QJackTrip.  If not, see <https://www.gnu.org/licenses/>.
+*/
+//*****************************************************************
+
+#ifndef MESSAGEDIALOG_H
+#define MESSAGEDIALOG_H
+
+#include <QDialog>
+#include <QScopedPointer>
+#include <QTemporaryFile>
+#include <QTimer>
+
+namespace Ui
+{
+class MessageDialog;
+}
+
+class MessageDialog : public QDialog
+{
+    Q_OBJECT
+
+   public:
+    explicit MessageDialog(QWidget* parent = nullptr);
+    ~MessageDialog() override;
+
+    void setStatsFile(QSharedPointer<QTemporaryFile> statsFile);
+    void startMonitoring();
+    void stopMonitoring();
+
+   private slots:
+    void writeOutput();
+
+   private:
+    QScopedPointer<Ui::MessageDialog> m_ui;
+    QSharedPointer<QTemporaryFile> m_ioStatsFile;
+    // Using a QFileSystem watcher didn't work on OS X, so use a timer instead.
+    QTimer m_ioTimer;
+};
+
+#endif  // MESSAGEDIALOG_H
diff --git a/src/gui/messageDialog.ui b/src/gui/messageDialog.ui
new file mode 100644 (file)
index 0000000..9b140ba
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MessageDialog</class>
+ <widget class="QDialog" name="MessageDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>567</width>
+    <height>321</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Stats</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
+    <widget class="QPlainTextEdit" name="messagesTextEdit">
+     <property name="readOnly">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/gui/qjacktrip.cpp b/src/gui/qjacktrip.cpp
new file mode 100644 (file)
index 0000000..1ed8793
--- /dev/null
@@ -0,0 +1,1449 @@
+//*****************************************************************
+/*
+  QJackTrip: Bringing a graphical user interface to JackTrip, a
+  system for high quality audio network performance over the
+  internet.
+
+  Copyright (c) 2020 Aaron Wyatt.
+
+  This file is part of QJackTrip.
+
+  QJackTrip is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  QJackTrip is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with QJackTrip.  If not, see <https://www.gnu.org/licenses/>.
+*/
+//*****************************************************************
+
+#include "qjacktrip.h"
+
+#include <QFileDialog>
+#include <QHostAddress>
+#include <QMessageBox>
+#include <QSettings>
+#include <QVector>
+#include <cstdlib>
+#include <ctime>
+
+#include "about.h"
+#include "ui_qjacktrip.h"
+#ifdef USE_WEAK_JACK
+#include "weak_libjack.h"
+#endif
+
+#ifdef __RT_AUDIO__
+#include "RtAudio.h"
+#endif
+
+#include "../Compressor.h"
+#include "../CompressorPresets.h"
+#include "../Limiter.h"
+#include "../Reverb.h"
+
+QJackTrip::QJackTrip(QWidget* parent)
+    : QMainWindow(parent)
+    , m_ui(new Ui::QJackTrip)
+    , m_netManager(new QNetworkAccessManager(this))
+    , m_messageDialog(new MessageDialog(this))
+    , m_jackTripRunning(false)
+    , m_isExiting(false)
+    , m_hasIPv4Reply(false)
+    , m_argc(1)
+    , m_hideWarning(false)
+{
+    m_ui->setupUi(this);
+
+    QCoreApplication::setOrganizationName("jacktrip");
+    QCoreApplication::setOrganizationDomain("jacktrip.org");
+    QCoreApplication::setApplicationName("JackTrip");
+
+    // Create all our UI connections.
+    connect(m_ui->typeComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
+            &QJackTrip::chooseRunType);
+    connect(m_ui->addressComboBox, &QComboBox::currentTextChanged, this,
+            &QJackTrip::addressChanged);
+    connect(m_ui->connectButton, &QPushButton::clicked, this, &QJackTrip::start);
+    connect(m_ui->disconnectButton, &QPushButton::clicked, this, &QJackTrip::stop);
+    connect(m_ui->exitButton, &QPushButton::clicked, this, &QJackTrip::exit);
+    connect(m_ui->certBrowse, &QPushButton::clicked, this, &QJackTrip::browseForFile);
+    connect(m_ui->keyBrowse, &QPushButton::clicked, this, &QJackTrip::browseForFile);
+    connect(m_ui->credsBrowse, &QPushButton::clicked, this, &QJackTrip::browseForFile);
+    connect(m_ui->commandLineButton, &QPushButton::clicked, this,
+            &QJackTrip::showCommandLineMessageBox);
+    connect(m_ui->useDefaultsButton, &QPushButton::clicked, this,
+            &QJackTrip::resetOptions);
+    connect(m_ui->usernameEdit, &QLineEdit::textChanged, this,
+            &QJackTrip::credentialsChanged);
+    connect(m_ui->passwordEdit, &QLineEdit::textChanged, this,
+            &QJackTrip::credentialsChanged);
+    connect(m_ui->certEdit, &QLineEdit::textChanged, this, &QJackTrip::authFilesChanged);
+    connect(m_ui->keyEdit, &QLineEdit::textChanged, this, &QJackTrip::authFilesChanged);
+    connect(m_ui->credsEdit, &QLineEdit::textChanged, this, &QJackTrip::authFilesChanged);
+    connect(m_ui->aboutButton, &QPushButton::clicked, this, [=]() {
+        About about(this);
+        about.exec();
+    });
+    connect(m_ui->authCheckBox, &QCheckBox::stateChanged, this, [=]() {
+        m_ui->usernameLabel->setEnabled(m_ui->authCheckBox->isChecked());
+        m_ui->usernameEdit->setEnabled(m_ui->authCheckBox->isChecked());
+        m_ui->passwordLabel->setEnabled(m_ui->authCheckBox->isChecked());
+        m_ui->passwordEdit->setEnabled(m_ui->authCheckBox->isChecked());
+        credentialsChanged();
+    });
+    connect(m_ui->requireAuthCheckBox, &QCheckBox::stateChanged, this, [=]() {
+        m_ui->certLabel->setEnabled(m_ui->requireAuthCheckBox->isChecked());
+        m_ui->certEdit->setEnabled(m_ui->requireAuthCheckBox->isChecked());
+        m_ui->certBrowse->setEnabled(m_ui->requireAuthCheckBox->isChecked());
+        m_ui->keyLabel->setEnabled(m_ui->requireAuthCheckBox->isChecked());
+        m_ui->keyEdit->setEnabled(m_ui->requireAuthCheckBox->isChecked());
+        m_ui->keyBrowse->setEnabled(m_ui->requireAuthCheckBox->isChecked());
+        m_ui->credsLabel->setEnabled(m_ui->requireAuthCheckBox->isChecked());
+        m_ui->credsEdit->setEnabled(m_ui->requireAuthCheckBox->isChecked());
+        m_ui->credsBrowse->setEnabled(m_ui->requireAuthCheckBox->isChecked());
+        authFilesChanged();
+    });
+    connect(m_ui->ioStatsCheckBox, &QCheckBox::stateChanged, this, [=]() {
+        m_ui->ioStatsLabel->setEnabled(m_ui->ioStatsCheckBox->isChecked());
+        m_ui->ioStatsSpinBox->setEnabled(m_ui->ioStatsCheckBox->isChecked());
+    });
+    connect(m_ui->jitterCheckBox, &QCheckBox::stateChanged, this, [=]() {
+        m_ui->broadcastCheckBox->setEnabled(m_ui->jitterCheckBox->isChecked());
+        m_ui->broadcastQueueLabel->setEnabled(m_ui->jitterCheckBox->isChecked()
+                                              && m_ui->broadcastCheckBox->isChecked());
+        m_ui->broadcastQueueSpinBox->setEnabled(m_ui->jitterCheckBox->isChecked()
+                                                && m_ui->broadcastCheckBox->isChecked());
+        m_ui->bufferStrategyLabel->setEnabled(m_ui->jitterCheckBox->isChecked());
+        m_ui->bufferStrategyComboBox->setEnabled(m_ui->jitterCheckBox->isChecked());
+        // m_ui->strategyExplanationLabel->setEnabled(m_ui->jitterCheckBox->isChecked());
+        m_ui->bufferLine->setEnabled(m_ui->jitterCheckBox->isChecked());
+        m_ui->autoQueueCheckBox->setEnabled(m_ui->jitterCheckBox->isChecked());
+        m_ui->autoQueueLabel->setEnabled(m_ui->jitterCheckBox->isChecked()
+                                         && m_ui->autoQueueCheckBox->isChecked());
+        m_ui->autoQueueSpinBox->setEnabled(m_ui->jitterCheckBox->isChecked()
+                                           && m_ui->autoQueueCheckBox->isChecked());
+        m_ui->packetsLabel->setEnabled(m_ui->jitterCheckBox->isChecked()
+                                       && m_ui->autoQueueCheckBox->isChecked());
+        m_ui->autoQueueExplanationLabel->setEnabled(
+            m_ui->jitterCheckBox->isChecked() && m_ui->autoQueueCheckBox->isChecked());
+        if (m_ui->jitterCheckBox->isChecked() && m_ui->autoQueueCheckBox->isChecked()) {
+            m_autoQueueIndicator.setText("Auto queue: enabled");
+        } else {
+            m_autoQueueIndicator.setText("Auto queue: disabled");
+        }
+    });
+    connect(m_ui->broadcastCheckBox, &QCheckBox::stateChanged, this, [=]() {
+        m_ui->broadcastQueueLabel->setEnabled(m_ui->jitterCheckBox->isChecked()
+                                              && m_ui->broadcastCheckBox->isChecked());
+        m_ui->broadcastQueueSpinBox->setEnabled(m_ui->jitterCheckBox->isChecked()
+                                                && m_ui->broadcastCheckBox->isChecked());
+    });
+    connect(m_ui->autoQueueCheckBox, &QCheckBox::stateChanged, this, [=]() {
+        m_ui->autoQueueLabel->setEnabled(m_ui->jitterCheckBox->isChecked()
+                                         && m_ui->autoQueueCheckBox->isChecked());
+        m_ui->autoQueueSpinBox->setEnabled(m_ui->jitterCheckBox->isChecked()
+                                           && m_ui->autoQueueCheckBox->isChecked());
+        m_ui->packetsLabel->setEnabled(m_ui->jitterCheckBox->isChecked()
+                                       && m_ui->autoQueueCheckBox->isChecked());
+        m_ui->autoQueueExplanationLabel->setEnabled(
+            m_ui->jitterCheckBox->isChecked() && m_ui->autoQueueCheckBox->isChecked());
+        if (m_ui->jitterCheckBox->isChecked() && m_ui->autoQueueCheckBox->isChecked()) {
+            m_autoQueueIndicator.setText("Auto queue: enabled");
+        } else {
+            m_autoQueueIndicator.setText("Auto queue: disabled");
+        }
+    });
+
+    connect(m_ui->inFreeverbCheckBox, &QCheckBox::stateChanged, this, [=]() {
+        m_ui->inFreeverbLabel->setEnabled(m_ui->inFreeverbCheckBox->isChecked());
+        m_ui->inFreeverbWetnessSlider->setEnabled(m_ui->inFreeverbCheckBox->isChecked());
+    });
+    connect(m_ui->inZitarevCheckBox, &QCheckBox::stateChanged, this, [=]() {
+        m_ui->inZitarevLabel->setEnabled(m_ui->inZitarevCheckBox->isChecked());
+        m_ui->inZitarevWetnessSlider->setEnabled(m_ui->inZitarevCheckBox->isChecked());
+    });
+
+    connect(m_ui->outFreeverbCheckBox, &QCheckBox::stateChanged, this, [=]() {
+        m_ui->outFreeverbLabel->setEnabled(m_ui->outFreeverbCheckBox->isChecked());
+        m_ui->outFreeverbWetnessSlider->setEnabled(
+            m_ui->outFreeverbCheckBox->isChecked());
+    });
+    connect(m_ui->outZitarevCheckBox, &QCheckBox::stateChanged, this, [=]() {
+        m_ui->outZitarevLabel->setEnabled(m_ui->outZitarevCheckBox->isChecked());
+        m_ui->outZitarevWetnessSlider->setEnabled(m_ui->outZitarevCheckBox->isChecked());
+    });
+    connect(m_ui->outLimiterCheckBox, &QCheckBox::stateChanged, this, [=]() {
+        m_ui->outLimiterLabel->setEnabled(m_ui->outLimiterCheckBox->isChecked());
+        m_ui->outClientsSpinBox->setEnabled(m_ui->outLimiterCheckBox->isChecked());
+    });
+    m_ui->autoPatchComboBox->setVisible(false);
+    m_ui->autoPatchLabel->setVisible(false);
+
+    connect(m_netManager.data(), &QNetworkAccessManager::finished, this,
+            &QJackTrip::receivedIP);
+    // Use the ipify API to find our external IP address.
+    m_netManager->get(QNetworkRequest(QUrl("https://api.ipify.org")));
+    m_netManager->get(QNetworkRequest(QUrl("https://api6.ipify.org")));
+    m_ui->statusBar->showMessage(QString("JackTrip version ").append(gVersion));
+
+    // Set up our interface for the default Client run mode.
+    //(loadSettings will take care of the UI in all other cases.)
+    m_ui->remoteNameLabel->setVisible(false);
+    m_ui->remoteNameEdit->setVisible(false);
+    m_ui->basePortLabel->setVisible(false);
+    m_ui->basePortSpinBox->setVisible(false);
+    m_ui->requireAuthGroupBox->setVisible(false);
+    m_ui->authGroupBox->setVisible(false);
+
+#ifdef __RT_AUDIO__
+    connect(m_ui->backendComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
+            this, [=](int index) {
+                if (index == 1) {
+                    m_ui->sampleRateComboBox->setEnabled(true);
+                    m_ui->sampleRateLabel->setEnabled(true);
+                    m_ui->bufferSizeComboBox->setEnabled(true);
+                    m_ui->bufferSizeLabel->setEnabled(true);
+                    m_ui->inputDeviceComboBox->setEnabled(true);
+                    m_ui->inputDeviceLabel->setEnabled(true);
+                    m_ui->outputDeviceComboBox->setEnabled(true);
+                    m_ui->outputDeviceLabel->setEnabled(true);
+                    m_ui->refreshDevicesButton->setEnabled(true);
+                    populateDeviceMenu(m_ui->inputDeviceComboBox, true);
+                    populateDeviceMenu(m_ui->outputDeviceComboBox, false);
+                } else {
+                    m_ui->sampleRateComboBox->setEnabled(false);
+                    m_ui->sampleRateLabel->setEnabled(false);
+                    m_ui->bufferSizeComboBox->setEnabled(false);
+                    m_ui->bufferSizeLabel->setEnabled(false);
+                    m_ui->inputDeviceComboBox->setEnabled(false);
+                    m_ui->inputDeviceLabel->setEnabled(false);
+                    m_ui->outputDeviceComboBox->setEnabled(false);
+                    m_ui->outputDeviceLabel->setEnabled(false);
+                    m_ui->refreshDevicesButton->setEnabled(false);
+                }
+            });
+    connect(m_ui->refreshDevicesButton, &QPushButton::clicked, this, [=]() {
+        populateDeviceMenu(m_ui->inputDeviceComboBox, true);
+        populateDeviceMenu(m_ui->outputDeviceComboBox, false);
+    });
+#else
+    int tabIndex = findTab("Audio Backend");
+    if (tabIndex != -1) {
+        m_ui->optionsTabWidget->removeTab(tabIndex);
+    }
+#endif
+
+    migrateSettings();
+    loadSettings();
+
+    QVector<QLabel*> labels;
+    labels << m_ui->inFreeverbLabel << m_ui->inZitarevLabel << m_ui->outFreeverbLabel;
+    std::srand(std::time(nullptr));
+    int index = std::rand() % 4;
+    if (index < 3) {
+        labels.at(index)->setToolTip(m_ui->outZitarevLabel->toolTip());
+        m_ui->outZitarevLabel->setToolTip("");
+    }
+
+    // Add an autoqueue indicator to the status bar.
+    m_ui->statusBar->addPermanentWidget(&m_autoQueueIndicator);
+    if (m_ui->jitterCheckBox->isChecked() && m_ui->autoQueueCheckBox->isChecked()) {
+        m_autoQueueIndicator.setText("Auto queue: enabled");
+    } else {
+        m_autoQueueIndicator.setText("Auto queue: disabled");
+    }
+
+#ifdef USE_WEAK_JACK
+    // Check if Jack is actually available
+    if (have_libjack() != 0) {
+#ifdef __RT_AUDIO__
+        m_ui->backendComboBox->setCurrentIndex(1);
+        m_ui->backendComboBox->setEnabled(false);
+        m_ui->backendLabel->setEnabled(false);
+
+        // If we're in Hub Server mode, switch us back to P2P server mode.
+        if (m_ui->typeComboBox->currentIndex() == HUB_SERVER) {
+            m_ui->typeComboBox->setCurrentIndex(P2P_SERVER);
+        }
+        m_ui->typeComboBox->removeItem(HUB_SERVER);
+
+        QSettings settings;
+        settings.beginGroup("Audio");
+        if (!settings.value("HideJackWarning", false).toBool()) {
+            QCheckBox* dontBugMe = new QCheckBox("Don't show this warning again");
+            QMessageBox msgBox;
+            msgBox.setText(
+                "An installation of JACK was not found. Only the RtAudio\nbackend will "
+                "be available. (Hub Server mode is not\ncurrently supported in this "
+                "configuration.");
+            msgBox.setWindowTitle("JACK Not Available");
+            msgBox.setCheckBox(dontBugMe);
+            QObject::connect(dontBugMe, &QCheckBox::stateChanged, this,
+                             [=]() { m_hideWarning = dontBugMe->isChecked(); });
+            msgBox.exec();
+            if (m_hideWarning) { settings.setValue("HideJackWarning", true); }
+        }
+        settings.endGroup();
+#else
+        QMessageBox msgBox;
+        msgBox.setText(
+            "An installation of JACK was not found, and no other audio\nbackends are "
+            "available. JackTrip will not be able to start.\n(Please install JACK to fix "
+            "this.)");
+        msgBox.setWindowTitle("JACK Not Available");
+        msgBox.exec();
+#endif  // __RT_AUDIO__
+    }
+#endif  // USE_WEAK_JACK
+
+    m_ui->optionsTabWidget->setCurrentIndex(0);
+}
+
+void QJackTrip::closeEvent(QCloseEvent* event)
+{
+    // Ignore the close event so that we can override the handling of it.
+    event->ignore();
+    exit();
+}
+
+void QJackTrip::resizeEvent(QResizeEvent* event)
+{
+    QMainWindow::resizeEvent(event);
+    // We need to fix the layout of our word wrapped labels.
+    // The font should be the same for all of them so we can reuse the one QFontMetrics
+    // object
+    QFontMetrics metrics(m_ui->autoQueueExplanationLabel->font());
+    // This seems like a convoluted way to get what is effectively our layout geometry,
+    // but until we look at the jitter tab, the layout geometry is unset.
+    int width = m_ui->JitterTab->contentsRect().width()
+                - m_ui->JitterTab->contentsMargins().left()
+                - m_ui->JitterTab->contentsMargins().right()
+                - m_ui->JitterTab->layout()->contentsMargins().left()
+                - m_ui->JitterTab->layout()->contentsMargins().right();
+
+    /*QRect rect = metrics.boundingRect(0, 0, width, 0, Qt::TextWordWrap,
+    m_ui->strategyExplanationLabel->text());
+    m_ui->strategyExplanationLabel->setMinimumHeight(rect.height());*/
+    QRect rect = metrics.boundingRect(0, 0, width, 0, Qt::TextWordWrap,
+                                      m_ui->autoQueueExplanationLabel->text());
+    m_ui->autoQueueExplanationLabel->setMinimumHeight(rect.height());
+
+    width = m_ui->requireAuthGroupBox->contentsRect().width()
+            - m_ui->requireAuthGroupBox->contentsMargins().left()
+            - m_ui->requireAuthGroupBox->contentsMargins().right()
+            - m_ui->requireAuthGroupBox->layout()->contentsMargins().left()
+            - m_ui->requireAuthGroupBox->contentsMargins().right();
+    rect = metrics.boundingRect(0, 0, width, 0, Qt::TextWordWrap,
+                                m_ui->authDisclaimerLabel->text());
+    m_ui->authDisclaimerLabel->setMinimumHeight(rect.height());
+}
+
+void QJackTrip::showEvent(QShowEvent* event)
+{
+    QMainWindow::showEvent(event);
+
+    // One of our arguments will always be --gui, so if that's the only one
+    // then we don't need to show the warning message.
+    if (m_argc > 2) {
+        QMessageBox msgBox;
+        msgBox.setText(
+            "The GUI version of JackTrip currently\nignores any command line "
+            "options.\n\nThis may change in future.");
+        msgBox.setWindowTitle("Command line options");
+        msgBox.exec();
+    }
+}
+
+void QJackTrip::setArgc(int argc) { m_argc = argc; }
+
+void QJackTrip::processFinished()
+{
+    if (!m_jackTripRunning) {
+        // Don't execute this if our process isn't actually running.
+        return;
+    }
+    m_jackTripRunning = false;
+#ifdef __MAC_OSX__
+    m_noNap.enableNap();
+#endif
+    if (m_ui->ioStatsCheckBox->isChecked()) { m_messageDialog->stopMonitoring(); }
+    m_ui->disconnectButton->setEnabled(false);
+    if (m_ui->typeComboBox->currentIndex() == HUB_SERVER) {
+        m_udpHub.reset();
+    } else {
+        m_jackTrip.reset();
+    }
+    if (m_isExiting) {
+        emit signalExit();
+    } else {
+        enableUi(true);
+        m_ui->connectButton->setEnabled(true);
+        m_ui->statusBar->showMessage("JackTrip Processes Stopped", 2000);
+    }
+}
+
+void QJackTrip::processError(const QString& errorMessage)
+{
+    QMessageBox msgBox;
+    if (errorMessage == "Peer Stopped") {
+        // Report the other end quitting as a regular occurance rather than an error.
+        msgBox.setText(errorMessage);
+        msgBox.setWindowTitle("Disconnected");
+    } else {
+        msgBox.setText(QString("Error: ").append(errorMessage));
+        msgBox.setWindowTitle("Doh!");
+    }
+    msgBox.exec();
+    processFinished();
+}
+
+void QJackTrip::receivedConnectionFromPeer()
+{
+    m_ui->statusBar->showMessage("Received Connection from Peer!");
+}
+
+void QJackTrip::queueLengthChanged(int queueLength)
+{
+    m_autoQueueIndicator.setText(QString("Auto queue: %1").arg(queueLength));
+}
+
+void QJackTrip::udpWaitingTooLong()
+{
+    m_ui->statusBar->showMessage("UDP waiting too long (more than 30ms)", 1000);
+}
+
+void QJackTrip::chooseRunType(int index)
+{
+    // Update ui to reflect choice of run mode.
+    if (index == HUB_CLIENT || index == P2P_CLIENT) {
+        m_ui->addressComboBox->setEnabled(true);
+        m_ui->addressLabel->setEnabled(true);
+        if (index == HUB_CLIENT) {
+            credentialsChanged();
+        } else {
+            m_ui->connectButton->setEnabled(
+                !m_ui->addressComboBox->currentText().isEmpty());
+        }
+        m_ui->remotePortSpinBox->setVisible(true);
+        m_ui->remotePortLabel->setVisible(true);
+        m_ui->connectButton->setText("Connect");
+        m_ui->disconnectButton->setText("Disconnect");
+    } else {
+        m_ui->addressComboBox->setEnabled(false);
+        m_ui->addressLabel->setEnabled(false);
+        m_ui->remotePortSpinBox->setVisible(false);
+        m_ui->remotePortLabel->setVisible(false);
+        m_ui->connectButton->setText("Start");
+        m_ui->disconnectButton->setText("Stop");
+        m_ui->connectButton->setEnabled(true);
+    }
+
+    if (index == HUB_SERVER) {
+        m_ui->channelGroupBox->setVisible(false);
+        m_ui->timeoutCheckBox->setVisible(false);
+        m_ui->autoPatchComboBox->setVisible(true);
+        m_ui->autoPatchLabel->setVisible(true);
+        m_ui->requireAuthGroupBox->setVisible(true);
+        advancedOptionsForHubServer(true);
+        int index = findTab("Plugins");
+        if (index != -1) {
+            m_ui->optionsTabWidget->removeTab(index);
+        }
+        authFilesChanged();
+#ifdef __RT_AUDIO__
+        index = findTab("Audio Backend");
+        if (index != -1) {
+            m_ui->optionsTabWidget->removeTab(index);
+        }
+#endif
+    } else {
+        m_ui->autoPatchComboBox->setVisible(false);
+        m_ui->autoPatchLabel->setVisible(false);
+        m_ui->requireAuthGroupBox->setVisible(false);
+        m_ui->channelGroupBox->setVisible(true);
+        m_ui->timeoutCheckBox->setVisible(true);
+        advancedOptionsForHubServer(false);
+        if (findTab("Plugins") == -1) {
+            m_ui->optionsTabWidget->addTab(m_ui->pluginsTab, "Plugins");
+        }
+#ifdef __RT_AUDIO__
+        if (findTab("Audio Backend") == -1) {
+            m_ui->optionsTabWidget->insertTab(2, m_ui->backendTab, "Audio Backend");
+        }
+#endif
+    }
+
+    if (index == HUB_CLIENT) {
+        m_ui->remoteNameEdit->setVisible(true);
+        m_ui->remoteNameLabel->setVisible(true);
+        m_ui->authGroupBox->setVisible(true);
+    } else {
+        m_ui->remoteNameEdit->setVisible(false);
+        m_ui->remoteNameLabel->setVisible(false);
+        m_ui->authGroupBox->setVisible(false);
+    }
+}
+
+void QJackTrip::addressChanged(const QString& address)
+{
+    // Make sure we check that JackTrip isn't running.
+    //(This also gets called when we save our recent address list on connecting to a
+    //server.)
+    if (m_jackTripRunning) { return; }
+    if (m_ui->typeComboBox->currentIndex() == P2P_CLIENT) {
+        m_ui->connectButton->setEnabled(!address.isEmpty());
+    } else if (m_ui->typeComboBox->currentIndex() == HUB_CLIENT) {
+        credentialsChanged();
+    }
+}
+
+void QJackTrip::authFilesChanged()
+{
+    if (m_ui->typeComboBox->currentIndex() != HUB_SERVER) { return; }
+
+    if (m_ui->requireAuthCheckBox->isChecked()
+        && (m_ui->certEdit->text().isEmpty() || m_ui->keyEdit->text().isEmpty()
+            || m_ui->credsEdit->text().isEmpty())) {
+        m_ui->connectButton->setEnabled(false);
+    } else {
+        m_ui->connectButton->setEnabled(true);
+    }
+}
+
+void QJackTrip::credentialsChanged()
+{
+    if (m_ui->typeComboBox->currentIndex() != HUB_CLIENT) { return; }
+
+    if (m_ui->authCheckBox->isChecked()
+        && (m_ui->usernameEdit->text().isEmpty()
+            || m_ui->passwordEdit->text().isEmpty())) {
+        m_ui->connectButton->setEnabled(false);
+    } else {
+        m_ui->connectButton->setEnabled(!m_ui->addressComboBox->currentText().isEmpty());
+    }
+}
+
+void QJackTrip::browseForFile()
+{
+    QPushButton* sender = static_cast<QPushButton*>(QObject::sender());
+    QString fileType;
+    QLineEdit* fileEdit;
+    if (sender == m_ui->certBrowse) {
+        fileType = "Certificates (*.crt *.pem)";
+        fileEdit = m_ui->certEdit;
+    } else if (sender == m_ui->keyBrowse) {
+        fileType = "Keys (*.key *.pem)";
+        fileEdit = m_ui->keyEdit;
+    } else {
+        fileType = "";
+        fileEdit = m_ui->credsEdit;
+    }
+    QString fileName =
+        QFileDialog::getOpenFileName(this, "Open File", m_lastPath, fileType);
+    if (!fileName.isEmpty()) {
+        fileEdit->setText(fileName);
+        fileEdit->setFocus(Qt::OtherFocusReason);
+        m_lastPath = QFileInfo(fileName).canonicalPath();
+    }
+}
+
+void QJackTrip::receivedIP(QNetworkReply* reply)
+{
+    QMutexLocker locker(&m_requestMutex);
+    // Check whether we're dealing with our IPv4 or IPv6 request.
+    if (reply->url().host().startsWith("api6")) {
+        if (reply->error() == QNetworkReply::NoError) {
+            m_IPv6Address = QString(reply->readAll());
+            // Make sure this isn't just a repeat of our IPv4 address.
+            if (QHostAddress(m_IPv6Address).protocol() != QAbstractSocket::IPv6Protocol) {
+                m_IPv6Address.clear();
+                reply->deleteLater();
+                return;
+            }
+            if (m_hasIPv4Reply) {
+                m_ui->ipLabel->setText(m_ui->ipLabel->text().append(
+                    QString("\n(IPv6: %1)").arg(m_IPv6Address)));
+            }
+            m_ui->ipLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
+        }
+    } else {
+        if (reply->error() != QNetworkReply::NoError) {
+            m_ui->ipLabel->setText("Unable to determine external IP address.");
+        } else {
+            QByteArray address = reply->readAll();
+            m_ui->ipLabel->setText(QString("External IP address: ").append(address));
+            m_ui->ipLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
+        }
+        if (!m_IPv6Address.isEmpty()) {
+            m_ui->ipLabel->setText(
+                m_ui->ipLabel->text().append(QString("\n(IPv6: %1)").arg(m_IPv6Address)));
+        }
+        m_hasIPv4Reply = true;
+    }
+    reply->deleteLater();
+}
+
+void QJackTrip::resetOptions()
+{
+    // Reset our basic options
+    /*m_ui->channelSpinBox->setValue(2);
+    m_ui->autoPatchComboBox->setCurrentIndex(0);
+    m_ui->zeroCheckBox->setChecked(false);
+    m_ui->timeoutCheckBox->setChecked(false);*/
+
+    // Then advanced options
+    m_ui->clientNameEdit->setText("");
+    m_ui->remoteNameEdit->setText("");
+    m_ui->localPortSpinBox->setValue(gDefaultPort);
+    m_ui->remotePortSpinBox->setValue(gDefaultPort);
+    m_ui->basePortSpinBox->setValue(61002);
+    m_ui->queueLengthSpinBox->setValue(gDefaultQueueLength);
+    m_ui->redundancySpinBox->setValue(gDefaultRedundancy);
+    m_ui->resolutionComboBox->setCurrentIndex(1);
+    m_ui->connectAudioCheckBox->setChecked(true);
+    m_ui->realTimeCheckBox->setChecked(true);
+    m_ui->ioStatsCheckBox->setChecked(false);
+    m_ui->ioStatsSpinBox->setValue(1);
+
+    saveSettings();
+}
+
+void QJackTrip::start()
+{
+    m_ui->connectButton->setEnabled(false);
+    enableUi(false);
+    m_jackTripRunning = true;
+
+    // Start the appropriate JackTrip process.
+    try {
+        if (m_ui->typeComboBox->currentIndex() == HUB_SERVER) {
+            m_udpHub.reset(new UdpHubListener(m_ui->localPortSpinBox->value(),
+                                              m_ui->basePortSpinBox->value()));
+            int hubConnectionMode = m_ui->autoPatchComboBox->currentIndex();
+            if (hubConnectionMode > 2) {
+                // Adjust for the RESERVEDMATRIX gap.
+                hubConnectionMode++;
+            }
+
+            m_udpHub->setHubPatch(hubConnectionMode);
+
+            if (m_ui->zeroCheckBox->isChecked()) {
+                // Set buffers to zero when underrun
+                m_udpHub->setUnderRunMode(JackTrip::ZEROS);
+            }
+
+            if (!m_ui->jitterCheckBox->isChecked()) {
+                m_udpHub->setBufferStrategy(-1);
+                m_udpHub->setBufferQueueLength(m_ui->queueLengthSpinBox->value());
+            } else {
+                m_udpHub->setBufferStrategy(m_ui->bufferStrategyComboBox->currentIndex()
+                                            + 1);
+                if (m_ui->broadcastCheckBox->isChecked()) {
+                    m_udpHub->setBroadcast(m_ui->broadcastQueueSpinBox->value());
+                }
+                if (m_ui->autoQueueCheckBox->isChecked()) {
+                    m_udpHub->setBufferQueueLength(-(m_ui->autoQueueSpinBox->value()));
+                    m_autoQueueIndicator.setText("Auto queue: enabled");
+                } else {
+                    m_udpHub->setBufferQueueLength(m_ui->queueLengthSpinBox->value());
+                }
+            }
+            m_udpHub->setUseRtUdpPriority(m_ui->realTimeCheckBox->isChecked());
+
+            // Enable authentication if needed
+            if (m_ui->requireAuthCheckBox->isChecked()) {
+                m_udpHub->setRequireAuth(true);
+                m_udpHub->setCertFile(m_ui->certEdit->text());
+                m_udpHub->setKeyFile(m_ui->keyEdit->text());
+                m_udpHub->setCredsFile(m_ui->credsEdit->text());
+            }
+
+            // Open our stats window if needed
+            if (m_ui->ioStatsCheckBox->isChecked()) {
+                setupStatsWindow();
+                m_udpHub->setIOStatTimeout(m_ui->ioStatsSpinBox->value());
+                m_udpHub->setIOStatStream(QSharedPointer<std::ofstream>(
+                    new std::ofstream(m_ioStatsOutput->fileName().toUtf8().constData())));
+            }
+
+            QObject::connect(m_udpHub.data(), &UdpHubListener::signalStopped, this,
+                             &QJackTrip::processFinished, Qt::QueuedConnection);
+            QObject::connect(m_udpHub.data(), &UdpHubListener::signalError, this,
+                             &QJackTrip::processError, Qt::QueuedConnection);
+            m_ui->disconnectButton->setEnabled(true);
+            m_udpHub->start();
+            m_ui->statusBar->showMessage("Hub Server Started");
+        } else {
+            JackTrip::jacktripModeT jackTripMode;
+            if (m_ui->typeComboBox->currentIndex() == P2P_CLIENT) {
+                jackTripMode = JackTrip::CLIENT;
+            } else if (m_ui->typeComboBox->currentIndex() == P2P_SERVER) {
+                jackTripMode = JackTrip::SERVER;
+            } else {
+                jackTripMode = JackTrip::CLIENTTOPINGSERVER;
+            }
+
+            AudioInterface::audioBitResolutionT resolution;
+            if (m_ui->resolutionComboBox->currentIndex() == 0) {
+                resolution = AudioInterface::BIT8;
+            } else if (m_ui->resolutionComboBox->currentIndex() == 1) {
+                resolution = AudioInterface::BIT16;
+            } else if (m_ui->resolutionComboBox->currentIndex() == 2) {
+                resolution = AudioInterface::BIT24;
+            } else {
+                resolution = AudioInterface::BIT32;
+            }
+
+            m_jackTrip.reset(new JackTrip(jackTripMode, JackTrip::UDP,
+                                          m_ui->channelSendSpinBox->value(),
+                                          m_ui->channelRecvSpinBox->value(),
+#ifdef WAIR  // wair
+                                          0,
+#endif  // endwhere
+                                          m_ui->queueLengthSpinBox->value(),
+                                          m_ui->redundancySpinBox->value(), resolution));
+            m_jackTrip->setConnectDefaultAudioPorts(
+                m_ui->connectAudioCheckBox->isChecked());
+            if (m_ui->zeroCheckBox->isChecked()) {
+                // Set buffers to zero when underrun
+                m_jackTrip->setUnderRunMode(JackTrip::ZEROS);
+            }
+
+#ifdef __RT_AUDIO__
+            if (m_ui->backendComboBox->currentIndex() == 1) {
+                m_jackTrip->setAudiointerfaceMode(JackTrip::RTAUDIO);
+                m_jackTrip->setSampleRate(
+                    m_ui->sampleRateComboBox->currentText().toInt());
+                m_jackTrip->setAudioBufferSizeInSamples(
+                    m_ui->bufferSizeComboBox->currentText().toInt());
+                // we assume that first entry is "(default)"
+                if(m_ui->inputDeviceComboBox->currentIndex() == 0) {
+                    m_jackTrip->setInputDevice("");
+                } else {
+                    m_jackTrip->setInputDevice(
+                      m_ui->inputDeviceComboBox->currentText().toStdString());
+                }
+                if(m_ui->outputDeviceComboBox->currentIndex() == 0) {
+                    m_jackTrip->setOutputDevice("");
+                } else {
+                    m_jackTrip->setOutputDevice(
+                      m_ui->outputDeviceComboBox->currentText().toStdString());
+                }
+            }
+#endif
+
+            if (m_ui->timeoutCheckBox->isChecked()) {
+                m_jackTrip->setStopOnTimeout(true);
+            }
+
+            if (m_ui->jitterCheckBox->isChecked()) {
+                m_jackTrip->setBufferStrategy(m_ui->bufferStrategyComboBox->currentIndex()
+                                              + 1);
+                if (m_ui->broadcastCheckBox->isChecked()) {
+                    m_jackTrip->setBroadcast(m_ui->broadcastQueueSpinBox->value());
+                }
+                if (m_ui->autoQueueCheckBox->isChecked()) {
+                    m_jackTrip->setBufferQueueLength(-(m_ui->autoQueueSpinBox->value()));
+                    m_autoQueueIndicator.setText("Auto queue: enabled");
+                }
+            } else {
+                m_jackTrip->setBufferStrategy(-1);
+            }
+            m_jackTrip->setUseRtUdpPriority(m_ui->realTimeCheckBox->isChecked());
+
+            // Set peer address in client mode
+            if (jackTripMode == JackTrip::CLIENT
+                || jackTripMode == JackTrip::CLIENTTOPINGSERVER) {
+                m_jackTrip->setPeerAddress(m_ui->addressComboBox->currentText().trimmed());
+                if (jackTripMode == JackTrip::CLIENTTOPINGSERVER
+                    && !m_ui->remoteNameEdit->text().isEmpty()) {
+                    m_jackTrip->setRemoteClientName(m_ui->remoteNameEdit->text());
+                }
+            }
+
+            m_jackTrip->setBindPorts(m_ui->localPortSpinBox->value());
+            m_jackTrip->setPeerPorts(m_ui->remotePortSpinBox->value());
+            m_jackTrip->setPeerHandshakePort(m_ui->remotePortSpinBox->value());
+
+            if (!m_ui->clientNameEdit->text().isEmpty()) {
+                m_jackTrip->setClientName(m_ui->clientNameEdit->text());
+            }
+
+            // Set credentials if we're using authentication
+            if (m_ui->authCheckBox->isChecked()) {
+                m_jackTrip->setUseAuth(true);
+                m_jackTrip->setUsername(m_ui->usernameEdit->text());
+                m_jackTrip->setPassword(m_ui->passwordEdit->text());
+            }
+
+            // Open our stats window if needed
+            if (m_ui->ioStatsCheckBox->isChecked()) {
+                setupStatsWindow();
+                m_jackTrip->setIOStatTimeout(m_ui->ioStatsSpinBox->value());
+                m_jackTrip->setIOStatStream(QSharedPointer<std::ofstream>(
+                    new std::ofstream(m_ioStatsOutput->fileName().toUtf8().constData())));
+            }
+
+            // Append any plugins
+            appendPlugins(m_jackTrip.data(), m_ui->channelSendSpinBox->value(),
+                          m_ui->channelRecvSpinBox->value());
+
+            QObject::connect(m_jackTrip.data(), &JackTrip::signalProcessesStopped, this,
+                             &QJackTrip::processFinished, Qt::QueuedConnection);
+            QObject::connect(m_jackTrip.data(), &JackTrip::signalError, this,
+                             &QJackTrip::processError, Qt::QueuedConnection);
+            QObject::connect(
+                m_jackTrip.data(), &JackTrip::signalReceivedConnectionFromPeer, this,
+                &QJackTrip::receivedConnectionFromPeer, Qt::QueuedConnection);
+            QObject::connect(m_jackTrip.data(), &JackTrip::signalUdpWaitingTooLong, this,
+                             &QJackTrip::udpWaitingTooLong, Qt::QueuedConnection);
+            QObject::connect(m_jackTrip.data(), &JackTrip::signalQueueLengthChanged, this,
+                             &QJackTrip::queueLengthChanged, Qt::QueuedConnection);
+            m_ui->statusBar->showMessage("Waiting for Peer...");
+            m_ui->disconnectButton->setEnabled(true);
+#ifdef WAIRTOHUB  // WAIR
+            m_jackTrip->startProcess(
+                0);  // for WAIR compatibility, ID in jack client name
+#else
+            m_jackTrip->startProcess();
+#endif  // endwhere
+        }
+    } catch (const std::exception& e) {
+        // Let the user know what our exception was.
+        QMessageBox msgBox;
+        msgBox.setText(QString("Error: ").append(e.what()));
+        msgBox.setWindowTitle("Doh!");
+        msgBox.exec();
+
+        m_jackTripRunning = false;
+        enableUi(true);
+        m_ui->connectButton->setEnabled(true);
+        m_ui->disconnectButton->setEnabled(false);
+        m_ui->statusBar->clearMessage();
+
+        return;
+    }
+
+    // Add the address to our server history.
+    QString serverAddress = m_ui->addressComboBox->currentText().trimmed();
+    int serverIndex       = m_ui->addressComboBox->findText(serverAddress);
+    if (serverIndex != -1) { m_ui->addressComboBox->removeItem(serverIndex); }
+    m_ui->addressComboBox->insertItem(0, serverAddress);
+    m_ui->addressComboBox->setCurrentIndex(0);
+
+#ifdef __MAC_OSX__
+    m_noNap.disableNap();
+#endif
+}
+
+void QJackTrip::stop()
+{
+    m_ui->disconnectButton->setEnabled(false);
+    if (m_ui->typeComboBox->currentIndex() == HUB_SERVER) {
+        m_udpHub->stop();
+    } else {
+        m_jackTrip->stop();
+    }
+}
+
+void QJackTrip::exit()
+{
+    // Only run this once.
+    if (m_isExiting) { return; }
+    m_isExiting = true;
+    m_ui->exitButton->setEnabled(false);
+    saveSettings();
+    if (m_jackTripRunning) {
+        stop();
+    } else {
+        emit signalExit();
+    }
+}
+
+int QJackTrip::findTab(const QString& tabName)
+{
+    for (int i = 0; i < m_ui->optionsTabWidget->count(); i++) {
+        if (m_ui->optionsTabWidget->tabText(i) == tabName) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+void QJackTrip::enableUi(bool enabled)
+{
+    m_ui->optionsTabWidget->setEnabled(enabled);
+    m_ui->typeLabel->setEnabled(enabled);
+    m_ui->typeComboBox->setEnabled(enabled);
+    m_ui->addressLabel->setEnabled(
+        enabled
+        && (m_ui->typeComboBox->currentIndex() == P2P_CLIENT
+            || m_ui->typeComboBox->currentIndex() == HUB_CLIENT));
+    m_ui->addressComboBox->setEnabled(
+        enabled
+        && (m_ui->typeComboBox->currentIndex() == P2P_CLIENT
+            || m_ui->typeComboBox->currentIndex() == HUB_CLIENT));
+}
+
+void QJackTrip::advancedOptionsForHubServer(bool isHubServer)
+{
+    m_ui->clientNameLabel->setVisible(!isHubServer);
+    m_ui->clientNameEdit->setVisible(!isHubServer);
+    m_ui->redundancyLabel->setVisible(!isHubServer);
+    m_ui->redundancySpinBox->setVisible(!isHubServer);
+    m_ui->resolutionLabel->setVisible(!isHubServer);
+    m_ui->resolutionComboBox->setVisible(!isHubServer);
+    m_ui->connectAudioCheckBox->setVisible(!isHubServer);
+    m_ui->basePortLabel->setVisible(isHubServer);
+    m_ui->basePortSpinBox->setVisible(isHubServer);
+    if (isHubServer) {
+        m_ui->localPortSpinBox->setToolTip(
+            "Set the local TCP port to use for the initial handshake connection. The "
+            "default is 4464.");
+    } else {
+        m_ui->localPortSpinBox->setToolTip(
+            "Set the local port to use for the connection. The default is 4464.\n(Useful "
+            "for running multiple hub clients behind the same router.)");
+    }
+}
+
+void QJackTrip::migrateSettings()
+{
+    // Function to migrate settings for users who previously had QJackTrip installed.
+    QSettings settings;
+    if (settings.value("Migrated", false).toBool()) { return; }
+#ifdef __MAC_OSX__
+    QSettings oldSettings("psi-borg.org", "QJackTrip");
+#else
+    QSettings oldSettings("psi-borg", "QJackTrip");
+#endif
+    QStringList keys = oldSettings.allKeys();
+    for (int i = 0; i < keys.size(); i++) {
+        settings.setValue(keys.at(i), oldSettings.value(keys.at(i), QVariant()));
+    }
+    settings.setValue("Migrated", true);
+}
+
+void QJackTrip::loadSettings()
+{
+    QSettings settings;
+    m_ui->typeComboBox->setCurrentIndex(settings.value("RunMode", 2).toInt());
+
+    // Migrate to separate send and receive channel numbers.
+    int oldChannelSetting = settings.value("Channels", -1).toInt();
+    if (oldChannelSetting != -1) {
+        m_ui->channelSendSpinBox->setValue(oldChannelSetting);
+        m_ui->channelRecvSpinBox->setValue(oldChannelSetting);
+        settings.remove("Channels");
+    } else {
+        m_ui->channelSendSpinBox->setValue(
+            settings.value("ChannelsSend", gDefaultNumInChannels).toInt());
+        m_ui->channelRecvSpinBox->setValue(
+            settings.value("ChannelsRecv", gDefaultNumOutChannels).toInt());
+    }
+
+    m_ui->autoPatchComboBox->setCurrentIndex(settings.value("AutoPatchMode", 0).toInt());
+    m_ui->zeroCheckBox->setChecked(settings.value("ZeroUnderrun", false).toBool());
+    m_ui->timeoutCheckBox->setChecked(settings.value("Timeout", false).toBool());
+    m_ui->clientNameEdit->setText(settings.value("ClientName", "").toString());
+    m_ui->remoteNameEdit->setText(settings.value("RemoteName", "").toString());
+    m_ui->localPortSpinBox->setValue(settings.value("LocalPort", gDefaultPort).toInt());
+    m_ui->remotePortSpinBox->setValue(settings.value("RemotePort", gDefaultPort).toInt());
+    m_ui->basePortSpinBox->setValue(settings.value("BasePort", 61002).toInt());
+    m_ui->queueLengthSpinBox->setValue(
+        settings.value("QueueLength", gDefaultQueueLength).toInt());
+    m_ui->redundancySpinBox->setValue(
+        settings.value("Redundancy", gDefaultRedundancy).toInt());
+    m_ui->resolutionComboBox->setCurrentIndex(settings.value("Resolution", 1).toInt());
+    m_ui->connectAudioCheckBox->setChecked(settings.value("ConnectAudio", true).toBool());
+    m_ui->realTimeCheckBox->setChecked(settings.value("RTNetworking", true).toBool());
+    m_lastPath = settings.value("LastPath", QDir::homePath()).toString();
+
+    settings.beginGroup("RecentServers");
+    for (int i = 1; i <= 5; i++) {
+        QString address = settings.value(QString("Server%1").arg(i), "").toString();
+        if (!address.isEmpty()) { m_ui->addressComboBox->addItem(address); }
+    }
+    settings.endGroup();
+    // Need to get this here so it isn't overwritten by the previous section.
+    m_ui->addressComboBox->setCurrentText(settings.value("LastAddress", "").toString());
+
+#ifdef __RT_AUDIO__
+    settings.beginGroup("Audio");
+    m_ui->backendComboBox->setCurrentIndex(settings.value("Backend", 0).toInt());
+    m_ui->sampleRateComboBox->setCurrentText(
+        settings.value("SampleRate", "48000").toString());
+    m_ui->bufferSizeComboBox->setCurrentText(
+        settings.value("BufferSize", "128").toString());
+    // update device list and set the device
+    populateDeviceMenu(m_ui->inputDeviceComboBox, true);
+    auto inDevice = settings.value("InputDevice").toString();
+    if(!inDevice.isEmpty()) {
+        m_ui->inputDeviceComboBox->setCurrentText(inDevice);
+    }
+    populateDeviceMenu(m_ui->outputDeviceComboBox, false);
+    auto outDevice = settings.value("OutputDevice").toString();
+    if(!outDevice.isEmpty()) {
+        m_ui->outputDeviceComboBox->setCurrentText(outDevice);
+    }
+    settings.endGroup();
+#endif
+
+    settings.beginGroup("Auth");
+    m_ui->requireAuthCheckBox->setChecked(settings.value("Require", false).toBool());
+    m_ui->certEdit->setText(settings.value("CertFile", "").toString());
+    m_ui->keyEdit->setText(settings.value("KeyFile", "").toString());
+    m_ui->credsEdit->setText(settings.value("CredsFile", "").toString());
+    m_ui->authCheckBox->setChecked(settings.value("Use", false).toBool());
+    m_ui->usernameEdit->setText(settings.value("Username", "").toString());
+    settings.endGroup();
+
+    settings.beginGroup("IOStats");
+    m_ui->ioStatsCheckBox->setChecked(settings.value("Display", false).toBool());
+    m_ui->ioStatsSpinBox->setValue(settings.value("ReportingInterval", 1).toInt());
+    settings.endGroup();
+
+    settings.beginGroup("JitterBuffer");
+    bool jitterAnnounce = settings.value("JitterAnnounce", false).toBool();
+    if (!jitterAnnounce && !settings.value("Enabled", true).toBool()) {
+        QMessageBox msgBox;
+        msgBox.setText(
+            "From this build onwards, the new jitter buffer is being enabled by default. "
+            "You can turn it off in the Jitter Buffer settings tab.");
+        msgBox.setWindowTitle("Jitter Buffer");
+        msgBox.exec();
+        settings.setValue("Enabled", true);
+    }
+    settings.setValue("JitterAnnounce", true);
+    m_ui->jitterCheckBox->setChecked(settings.value("Enabled", true).toBool());
+    m_ui->broadcastCheckBox->setChecked(settings.value("Broadcast", false).toBool());
+    m_ui->broadcastQueueSpinBox->setValue(
+        settings.value("BroadcastLength", gDefaultQueueLength * 2).toInt());
+    m_ui->bufferStrategyComboBox->setCurrentIndex(settings.value("Strategy", 1).toInt()
+                                                  - 1);
+    m_ui->autoQueueCheckBox->setChecked(settings.value("AutoQueue", true).toBool());
+    m_ui->autoQueueSpinBox->setValue(settings.value("TuningParameter", 500).toInt());
+    settings.endGroup();
+
+    settings.beginGroup("InPlugins");
+    m_ui->inFreeverbCheckBox->setChecked(settings.value("Freeverb", false).toBool());
+    m_ui->inFreeverbWetnessSlider->setValue(settings.value("FreeverbWetness", 0).toInt());
+    m_ui->inZitarevCheckBox->setChecked(settings.value("Zitarev", false).toBool());
+    m_ui->inZitarevWetnessSlider->setValue(settings.value("ZitarevWetness", 0).toInt());
+    m_ui->inCompressorCheckBox->setChecked(settings.value("Compressor", false).toBool());
+    m_ui->inLimiterCheckBox->setChecked(settings.value("Limiter", false).toBool());
+    settings.endGroup();
+
+    settings.beginGroup("OutPlugins");
+    m_ui->outFreeverbCheckBox->setChecked(settings.value("Freeverb", false).toBool());
+    m_ui->outFreeverbWetnessSlider->setValue(
+        settings.value("FreeverbWetness", 0).toInt());
+    m_ui->outZitarevCheckBox->setChecked(settings.value("Zitarev", false).toBool());
+    m_ui->outZitarevWetnessSlider->setValue(settings.value("ZitarevWetness", 0).toInt());
+    m_ui->outCompressorCheckBox->setChecked(settings.value("Compressor", false).toBool());
+    m_ui->outLimiterCheckBox->setChecked(settings.value("Limiter", false).toBool());
+    m_ui->outClientsSpinBox->setValue(settings.value("Clients", 1).toInt());
+    settings.endGroup();
+
+    settings.beginGroup("Window");
+    QByteArray geometry = settings.value("Geometry").toByteArray();
+    if (geometry.size() > 0) {
+        restoreGeometry(settings.value("Geometry").toByteArray());
+    } else {
+        // Because of hidden elements in our dialog window, it's vertical size in the
+        // creator is getting rediculous. Set it to something sensible by default if this
+        // is our first load.
+        this->resize(QSize(this->size().width(), 600));
+    }
+    settings.endGroup();
+}
+
+void QJackTrip::saveSettings()
+{
+    QSettings settings;
+    settings.setValue("RunMode", m_ui->typeComboBox->currentIndex());
+    settings.setValue("LastAddress", m_ui->addressComboBox->currentText());
+    settings.setValue("ChannelsSend", m_ui->channelSendSpinBox->value());
+    settings.setValue("ChannelsRecv", m_ui->channelRecvSpinBox->value());
+    settings.setValue("AutoPatchMode", m_ui->autoPatchComboBox->currentIndex());
+    settings.setValue("ZeroUnderrun", m_ui->zeroCheckBox->isChecked());
+    settings.setValue("Timeout", m_ui->timeoutCheckBox->isChecked());
+    settings.setValue("ClientName", m_ui->clientNameEdit->text());
+    settings.setValue("RemoteName", m_ui->remoteNameEdit->text());
+    settings.setValue("LocalPort", m_ui->localPortSpinBox->value());
+    settings.setValue("RemotePort", m_ui->remotePortSpinBox->value());
+    settings.setValue("BasePort", m_ui->basePortSpinBox->value());
+    settings.setValue("QueueLength", m_ui->queueLengthSpinBox->value());
+    settings.setValue("Redundancy", m_ui->redundancySpinBox->value());
+    settings.setValue("Resolution", m_ui->resolutionComboBox->currentIndex());
+    settings.setValue("ConnectAudio", m_ui->connectAudioCheckBox->isChecked());
+    settings.setValue("RTNetworking", m_ui->realTimeCheckBox->isChecked());
+    settings.setValue("LastPath", m_lastPath);
+
+    settings.beginGroup("RecentServers");
+    for (int i = 0; i < m_ui->addressComboBox->count(); i++) {
+        settings.setValue(QString("Server%1").arg(i + 1),
+                          m_ui->addressComboBox->itemText(i));
+    }
+    settings.endGroup();
+
+#ifdef __RT_AUDIO__
+    settings.beginGroup("Audio");
+    settings.setValue("Backend", m_ui->backendComboBox->currentIndex());
+    settings.setValue("SampleRate", m_ui->sampleRateComboBox->currentText());
+    settings.setValue("BufferSize", m_ui->bufferSizeComboBox->currentText());
+    settings.setValue("InputDevice", m_ui->inputDeviceComboBox->currentText());
+    settings.setValue("OutputDevice", m_ui->outputDeviceComboBox->currentText());
+    settings.endGroup();
+#endif
+
+    settings.beginGroup("Auth");
+    settings.setValue("Require", m_ui->requireAuthCheckBox->isChecked());
+    settings.setValue("CertFile", m_ui->certEdit->text());
+    settings.setValue("KeyFile", m_ui->keyEdit->text());
+    settings.setValue("CredsFile", m_ui->credsEdit->text());
+    settings.setValue("Use", m_ui->authCheckBox->isChecked());
+    settings.setValue("Username", m_ui->usernameEdit->text());
+    settings.endGroup();
+
+    settings.beginGroup("IOStats");
+    settings.setValue("Display", m_ui->ioStatsCheckBox->isChecked());
+    settings.setValue("ReportingInterval", m_ui->ioStatsSpinBox->value());
+    settings.endGroup();
+
+    settings.beginGroup("JitterBuffer");
+    settings.setValue("Enabled", m_ui->jitterCheckBox->isChecked());
+    settings.setValue("Broadcast", m_ui->broadcastCheckBox->isChecked());
+    settings.setValue("BroadcastLength", m_ui->broadcastQueueSpinBox->value());
+    settings.setValue("Strategy", m_ui->bufferStrategyComboBox->currentIndex() + 1);
+    settings.setValue("AutoQueue", m_ui->autoQueueCheckBox->isChecked());
+    settings.setValue("TuningParameter", m_ui->autoQueueSpinBox->value());
+    settings.endGroup();
+
+    settings.beginGroup("InPlugins");
+    settings.setValue("Freeverb", m_ui->inFreeverbCheckBox->isChecked());
+    settings.setValue("FreeverbWetness", m_ui->inFreeverbWetnessSlider->value());
+    settings.setValue("Zitarev", m_ui->inZitarevCheckBox->isChecked());
+    settings.setValue("ZitarevWetness", m_ui->inZitarevWetnessSlider->value());
+    settings.setValue("Compressor", m_ui->inCompressorCheckBox->isChecked());
+    settings.setValue("Limiter", m_ui->inLimiterCheckBox->isChecked());
+    settings.endGroup();
+
+    settings.beginGroup("OutPlugins");
+    settings.setValue("Freeverb", m_ui->outFreeverbCheckBox->isChecked());
+    settings.setValue("FreeverbWetness", m_ui->outFreeverbWetnessSlider->value());
+    settings.setValue("Zitarev", m_ui->outZitarevCheckBox->isChecked());
+    settings.setValue("ZitarevWetness", m_ui->outZitarevWetnessSlider->value());
+    settings.setValue("Compressor", m_ui->outCompressorCheckBox->isChecked());
+    settings.setValue("Limiter", m_ui->outLimiterCheckBox->isChecked());
+    settings.setValue("Clients", m_ui->outClientsSpinBox->value());
+    settings.endGroup();
+
+    settings.beginGroup("Window");
+    settings.setValue("Geometry", saveGeometry());
+    settings.endGroup();
+}
+
+void QJackTrip::setupStatsWindow()
+{
+    m_ioStatsOutput.reset(new QTemporaryFile());
+    m_ioStatsOutput->open();
+    m_messageDialog->setStatsFile(m_ioStatsOutput);
+    m_messageDialog->show();
+    m_messageDialog->startMonitoring();
+}
+
+void QJackTrip::appendPlugins(JackTrip* jackTrip, int numSendChannels,
+                              int numRecvChannels)
+{
+    if (!jackTrip) { return; }
+
+    // These effects are currently deleted by the AudioInterface of jacktrip.
+    // May need to change this code if we move to smart pointers.
+    if (m_ui->outCompressorCheckBox->isChecked()) {
+        jackTrip->appendProcessPluginToNetwork(
+            new Compressor(numSendChannels, false, CompressorPresets::voice));
+    }
+    if (m_ui->inCompressorCheckBox->isChecked()) {
+        jackTrip->appendProcessPluginFromNetwork(
+            new Compressor(numRecvChannels, false, CompressorPresets::voice));
+    }
+
+    if (m_ui->outZitarevCheckBox->isChecked()) {
+        qreal wetness = m_ui->outZitarevWetnessSlider->value() / 100.0;
+        jackTrip->appendProcessPluginToNetwork(
+            new Reverb(numSendChannels, numSendChannels, 1.0 + wetness));
+    }
+    if (m_ui->inZitarevCheckBox->isChecked()) {
+        qreal wetness = m_ui->inZitarevWetnessSlider->value() / 100.0;
+        jackTrip->appendProcessPluginFromNetwork(
+            new Reverb(numRecvChannels, numRecvChannels, 1.0 + wetness));
+    }
+
+    if (m_ui->outFreeverbCheckBox->isChecked()) {
+        qreal wetness = m_ui->outFreeverbWetnessSlider->value() / 100.0;
+        jackTrip->appendProcessPluginToNetwork(
+            new Reverb(numSendChannels, numSendChannels, wetness));
+    }
+    if (m_ui->inFreeverbCheckBox->isChecked()) {
+        qreal wetness = m_ui->inFreeverbWetnessSlider->value() / 100.0;
+        jackTrip->appendProcessPluginFromNetwork(
+            new Reverb(numRecvChannels, numRecvChannels, wetness));
+    }
+
+    // Limiters go last in the plugin sequence.
+    if (m_ui->inLimiterCheckBox->isChecked()) {
+        jackTrip->appendProcessPluginFromNetwork(new Limiter(numSendChannels, 1));
+    }
+    if (m_ui->outLimiterCheckBox->isChecked()) {
+        jackTrip->appendProcessPluginToNetwork(
+            new Limiter(numRecvChannels, m_ui->outClientsSpinBox->value()));
+    }
+}
+
+QString QJackTrip::commandLineFromCurrentOptions()
+{
+    QString commandLine = "jacktrip";
+
+    if (m_ui->typeComboBox->currentIndex() == P2P_CLIENT) {
+        commandLine.append(" -c ").append(m_ui->addressComboBox->currentText());
+    } else if (m_ui->typeComboBox->currentIndex() == P2P_SERVER) {
+        commandLine.append(" -s");
+    } else if (m_ui->typeComboBox->currentIndex() == HUB_CLIENT) {
+        commandLine.append(" -C ").append(m_ui->addressComboBox->currentText());
+    } else {
+        commandLine.append(" -S");
+    }
+
+    if (m_ui->zeroCheckBox->isChecked()) { commandLine.append(" -z"); }
+
+    if (m_ui->typeComboBox->currentIndex() == HUB_SERVER) {
+        int hubConnectionMode = m_ui->autoPatchComboBox->currentIndex();
+        if (hubConnectionMode > 2) {
+            // Adjust for the RESERVEDMATRIX gap.
+            hubConnectionMode++;
+        }
+        if (hubConnectionMode > 0) {
+            commandLine.append(QString(" -p %1").arg(hubConnectionMode));
+        }
+    } else {
+        if (m_ui->channelSendSpinBox->value() != gDefaultNumInChannels
+            || m_ui->channelRecvSpinBox->value() != gDefaultNumOutChannels) {
+            if (m_ui->channelSendSpinBox->value() == m_ui->channelRecvSpinBox->value()) {
+                commandLine.append(
+                    QString(" -n %1").arg(m_ui->channelRecvSpinBox->value()));
+            } else {
+                commandLine.append(QString(" --receivechannels %1 --sendchannels %2")
+                                       .arg(m_ui->channelRecvSpinBox->value())
+                                       .arg(m_ui->channelSendSpinBox->value()));
+            }
+        }
+        if (m_ui->timeoutCheckBox->isChecked()) { commandLine.append(" -t"); }
+    }
+
+    int bufStrategy = -1;
+    if (m_ui->jitterCheckBox->isChecked()) {
+        bufStrategy = m_ui->bufferStrategyComboBox->currentIndex() + 1;
+    }
+    if (bufStrategy != 1) {
+        commandLine.append(QString(" --bufstrategy %1").arg(bufStrategy));
+    }
+
+    if (m_ui->jitterCheckBox->isChecked() && m_ui->autoQueueCheckBox->isChecked()) {
+        if (m_ui->autoQueueSpinBox->value() == 500) {
+            commandLine.append(QString(" -q auto"));
+        } else {
+            commandLine.append(
+                QString(" -q auto%1").arg(m_ui->autoQueueSpinBox->value()));
+        }
+    } else if (m_ui->queueLengthSpinBox->value() != gDefaultQueueLength) {
+        commandLine.append(QString(" -q %1").arg(m_ui->queueLengthSpinBox->value()));
+    }
+
+    if (m_ui->jitterCheckBox->isChecked() && m_ui->broadcastCheckBox->isChecked()) {
+        commandLine.append(
+            QString(" --broadcast %1").arg(m_ui->broadcastQueueSpinBox->value()));
+    }
+
+    // Port settings
+    if (m_ui->localPortSpinBox->value() != gDefaultPort) {
+        commandLine.append(QString(" -B %1").arg(m_ui->localPortSpinBox->value()));
+    }
+    if (m_ui->typeComboBox->currentIndex() == HUB_CLIENT
+        || m_ui->typeComboBox->currentIndex() == P2P_CLIENT) {
+        if (m_ui->remotePortSpinBox->value() != gDefaultPort) {
+            commandLine.append(QString(" -P %1").arg(m_ui->remotePortSpinBox->value()));
+        }
+    }
+
+    // Auth settings
+    if (m_ui->typeComboBox->currentIndex() == HUB_SERVER) {
+        if (m_ui->requireAuthCheckBox->isChecked()) {
+            commandLine.append(QString(" -A"));
+            if (!m_ui->certEdit->text().isEmpty()) {
+                commandLine.append(" --certfile ").append(m_ui->certEdit->text());
+            }
+            if (!m_ui->keyEdit->text().isEmpty()) {
+                commandLine.append(" --keyfile ").append(m_ui->keyEdit->text());
+            }
+            if (!m_ui->credsEdit->text().isEmpty()) {
+                commandLine.append(" --credsfile ").append(m_ui->credsEdit->text());
+            }
+        }
+    } else if (m_ui->typeComboBox->currentIndex() == HUB_CLIENT) {
+        if (m_ui->authCheckBox->isChecked()) {
+            commandLine.append(QString(" -A"));
+            if (!m_ui->usernameEdit->text().isEmpty()) {
+                commandLine.append(" --username ").append(m_ui->usernameEdit->text());
+            }
+            /*if (!m_ui->passwordEdit->text().isEmpty()) {
+                commandLine.append(" --password <password>");
+            }*/
+        }
+    }
+
+    if (m_ui->typeComboBox->currentIndex() == HUB_SERVER) {
+        int offset = m_ui->localPortSpinBox->value() - gDefaultPort;
+        if (m_ui->basePortSpinBox->value() != 61002 + offset) {
+            commandLine.append(QString(" -U %1").arg(m_ui->basePortSpinBox->value()));
+        }
+    } else {
+        if (!m_ui->clientNameEdit->text().isEmpty()) {
+            commandLine.append(QString(" -J \"%1\"").arg(m_ui->clientNameEdit->text()));
+        }
+        if (m_ui->typeComboBox->currentIndex() == HUB_CLIENT
+            && !m_ui->remoteNameEdit->text().isEmpty()) {
+            commandLine.append(QString(" -K \"%1\"").arg(m_ui->remoteNameEdit->text()));
+        }
+        if (m_ui->redundancySpinBox->value() > 1) {
+            commandLine.append(QString(" -r %1").arg(m_ui->redundancySpinBox->value()));
+        }
+        if (m_ui->resolutionComboBox->currentText() != "16") {
+            commandLine.append(" -b ").append(m_ui->resolutionComboBox->currentText());
+        }
+        if (!m_ui->connectAudioCheckBox->isChecked()) { commandLine.append(" -D"); }
+
+        if (m_ui->inLimiterCheckBox->isChecked()
+            || m_ui->outLimiterCheckBox->isChecked()) {
+            commandLine.append(" -O ");
+            if (m_ui->inLimiterCheckBox->isChecked()) { commandLine.append("i"); }
+            if (m_ui->outLimiterCheckBox->isChecked()) {
+                commandLine.append("o");
+                if (m_ui->outClientsSpinBox->value() != 2) {
+                    commandLine.append(
+                        QString(" -a %1").arg(m_ui->outClientsSpinBox->value()));
+                }
+            }
+        }
+
+        bool inEffects = m_ui->inFreeverbCheckBox->isChecked()
+                         || m_ui->inZitarevCheckBox->isChecked()
+                         || m_ui->inCompressorCheckBox->isChecked();
+        bool outEffects = m_ui->outFreeverbCheckBox->isChecked()
+                          || m_ui->outZitarevCheckBox->isChecked()
+                          || m_ui->outCompressorCheckBox->isChecked();
+        if (inEffects || outEffects) {
+            commandLine.append(" -f \"");
+            if (inEffects) {
+                commandLine.append("i:");
+                if (m_ui->inCompressorCheckBox->isChecked()) { commandLine.append("c"); }
+                if (m_ui->inFreeverbCheckBox->isChecked()) {
+                    commandLine.append(QString("f(%1)").arg(
+                        m_ui->inFreeverbWetnessSlider->value() / 100.0));
+                }
+                if (m_ui->inZitarevCheckBox->isChecked()) {
+                    commandLine.append(QString("f(%1)").arg(
+                        m_ui->inZitarevWetnessSlider->value() / 100.0));
+                }
+                if (outEffects) { commandLine.append(", "); }
+            }
+            if (outEffects) {
+                commandLine.append("o:");
+                if (m_ui->outCompressorCheckBox->isChecked()) { commandLine.append("c"); }
+                if (m_ui->outFreeverbCheckBox->isChecked()) {
+                    commandLine.append(QString("f(%1)").arg(
+                        m_ui->outFreeverbWetnessSlider->value() / 100.0));
+                }
+                if (m_ui->outZitarevCheckBox->isChecked()) {
+                    commandLine.append(QString("f(%1)").arg(
+                        m_ui->outZitarevWetnessSlider->value() / 100.0));
+                }
+            }
+            commandLine.append("\"");
+        }
+    }
+    if (m_ui->ioStatsCheckBox->isChecked()) {
+        commandLine.append(QString(" -I %1").arg(m_ui->ioStatsSpinBox->value()));
+    }
+
+    if (m_ui->realTimeCheckBox->isChecked()) { commandLine.append(" --udprt"); }
+
+#ifdef __RT_AUDIO__
+    if (m_ui->typeComboBox->currentIndex() != HUB_SERVER
+        && m_ui->backendComboBox->currentIndex() == 1) {
+        commandLine.append(" --rtaudio");
+        commandLine.append(
+            QString(" --srate %1").arg(m_ui->sampleRateComboBox->currentText()));
+        commandLine.append(
+            QString(" --bufsize %1").arg(m_ui->bufferSizeComboBox->currentText()));
+        QString inDevice;
+        if(m_ui->inputDeviceComboBox->currentIndex() > 0) {
+            inDevice = m_ui->inputDeviceComboBox->currentText();
+        }
+        QString outDevice;
+        if(m_ui->outputDeviceComboBox->currentIndex() > 0) {
+            outDevice = m_ui->outputDeviceComboBox->currentText();
+        }
+        commandLine.append(
+            QString(" --audiodevice \"%1\",\"%2\"").arg(inDevice, outDevice));
+    }
+#endif
+
+    return commandLine;
+}
+
+#ifdef __RT_AUDIO__
+void QJackTrip::populateDeviceMenu(QComboBox* menu, bool isInput)
+{
+    RtAudio audio;
+    QString previousString = menu->currentText();
+    menu->clear();
+    // std::cout << "previousString: " << previousString.toStdString() << std::endl;
+    menu->addItem("(default)");
+    unsigned int devices = audio.getDeviceCount();
+    RtAudio::DeviceInfo info;
+    for (unsigned int i=0; i<devices; i++) {
+        info = audio.getDeviceInfo(i);
+        if (info.probed == true) {
+            if (isInput && info.inputChannels > 0) {
+                menu->addItem(QString::fromStdString(info.name));
+            } else if (!isInput && info.outputChannels > 0) {
+                menu->addItem(QString::fromStdString(info.name));
+            }
+        }
+    }
+    // set the previous value
+    menu->setCurrentText(previousString);
+}
+#endif
+
+void QJackTrip::showCommandLineMessageBox()
+{
+    QMessageBox msgBox;
+    QString messageText =
+        QString("The equivalent command line for the current options is:\n\n%1")
+            .arg(commandLineFromCurrentOptions());
+    msgBox.setText(messageText);
+    msgBox.setWindowTitle("Command Line");
+    msgBox.setTextInteractionFlags(Qt::TextSelectableByMouse);
+    msgBox.exec();
+}
+
+QJackTrip::~QJackTrip() = default;
diff --git a/src/gui/qjacktrip.h b/src/gui/qjacktrip.h
new file mode 100644 (file)
index 0000000..6d57080
--- /dev/null
@@ -0,0 +1,134 @@
+//*****************************************************************
+/*
+  QJackTrip: Bringing a graphical user interface to JackTrip, a
+  system for high quality audio network performance over the
+  internet.
+
+  Copyright (c) 2020 Aaron Wyatt.
+
+  This file is part of QJackTrip.
+
+  QJackTrip is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  QJackTrip is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with QJackTrip.  If not, see <https://www.gnu.org/licenses/>.
+*/
+//*****************************************************************
+
+#ifndef QJACKTRIP_H
+#define QJACKTRIP_H
+
+#include <QByteArray>
+#include <QCloseEvent>
+#include <QLabel>
+#include <QMainWindow>
+#include <QMutex>
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
+#include <QScopedPointer>
+#include <QString>
+#include <QTemporaryFile>
+
+#include "../JackTrip.h"
+#include "../UdpHubListener.h"
+#include "messageDialog.h"
+
+#ifdef __MAC_OSX__
+#include "NoNap.h"
+#endif
+
+#ifdef __RT_AUDIO__
+#include <QComboBox>
+#endif
+
+namespace Ui
+{
+class QJackTrip;
+}
+
+class QJackTrip : public QMainWindow
+{
+    Q_OBJECT
+
+   public:
+    explicit QJackTrip(QWidget* parent = nullptr);
+    ~QJackTrip() override;
+
+    void closeEvent(QCloseEvent* event) override;
+    void resizeEvent(QResizeEvent* event) override;
+    void showEvent(QShowEvent* event) override;
+
+    void setArgc(int argc);
+
+   signals:
+    void signalExit();
+
+   private slots:
+    void processFinished();
+    void processError(const QString& errorMessage);
+    void receivedConnectionFromPeer();
+    void udpWaitingTooLong();
+    void queueLengthChanged(int queueLength);
+    void chooseRunType(int index);
+    void addressChanged(const QString& address);
+    void authFilesChanged();
+    void credentialsChanged();
+    void browseForFile();
+    void receivedIP(QNetworkReply* reply);
+    void resetOptions();
+    void start();
+    void stop();
+    void exit();
+
+   private:
+    enum runTypeT { P2P_CLIENT, P2P_SERVER, HUB_CLIENT, HUB_SERVER };
+
+    int findTab(const QString& tabName);
+    void enableUi(bool enabled);
+    void advancedOptionsForHubServer(bool isHubServer);
+    void migrateSettings();
+    void loadSettings();
+    void saveSettings();
+
+#ifdef __RT_AUDIO__
+    void populateDeviceMenu(QComboBox* menu, bool isInput);
+#endif
+
+    void setupStatsWindow();
+    void appendPlugins(JackTrip* jackTrip, int numSendChannels, int numRecvChannels);
+
+    QString commandLineFromCurrentOptions();
+    void showCommandLineMessageBox();
+
+    QScopedPointer<Ui::QJackTrip> m_ui;
+    QScopedPointer<UdpHubListener> m_udpHub;
+    QScopedPointer<JackTrip> m_jackTrip;
+    QScopedPointer<QNetworkAccessManager> m_netManager;
+    QScopedPointer<MessageDialog> m_messageDialog;
+    QSharedPointer<QTemporaryFile> m_ioStatsOutput;
+    bool m_jackTripRunning;
+    bool m_isExiting;
+
+    QMutex m_requestMutex;
+    QString m_IPv6Address;
+    bool m_hasIPv4Reply;
+    QString m_lastPath;
+
+    QLabel m_autoQueueIndicator;
+    int m_argc;
+    bool m_hideWarning;
+
+#ifdef __MAC_OSX__
+    NoNap m_noNap;
+#endif
+};
+
+#endif  // QJACKTRIP_H
diff --git a/src/gui/qjacktrip.qrc b/src/gui/qjacktrip.qrc
new file mode 100644 (file)
index 0000000..179c85a
--- /dev/null
@@ -0,0 +1,7 @@
+<RCC>
+  <qresource prefix="qjacktrip">
+    <file>about@2x.png</file>
+    <file>about.png</file>
+    <file>icon.png</file>
+  </qresource>
+</RCC>
diff --git a/src/gui/qjacktrip.ui b/src/gui/qjacktrip.ui
new file mode 100644 (file)
index 0000000..5387103
--- /dev/null
@@ -0,0 +1,1801 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QJackTrip</class>
+ <widget class="QMainWindow" name="QJackTrip">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>409</width>
+    <height>817</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>JackTrip</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="qjacktrip.qrc">
+    <normaloff>:/qjacktrip/icon.png</normaloff>:/qjacktrip/icon.png</iconset>
+  </property>
+  <widget class="QWidget" name="centralWidget">
+   <layout class="QGridLayout" name="gridLayout">
+    <item row="0" column="1">
+     <widget class="QComboBox" name="typeComboBox">
+      <property name="toolTip">
+       <string>To connect to a p2p (peer to peer) server you need to run as a p2p client.
+To connect to a hub server you need to run as a hub client.</string>
+      </property>
+      <item>
+       <property name="text">
+        <string>P2P Client</string>
+       </property>
+      </item>
+      <item>
+       <property name="text">
+        <string>P2P Server</string>
+       </property>
+      </item>
+      <item>
+       <property name="text">
+        <string>Hub Client</string>
+       </property>
+      </item>
+      <item>
+       <property name="text">
+        <string>Hub Server</string>
+       </property>
+      </item>
+     </widget>
+    </item>
+    <item row="6" column="0" colspan="2">
+     <layout class="QHBoxLayout" name="buttonLayout">
+      <item>
+       <widget class="QPushButton" name="connectButton">
+        <property name="enabled">
+         <bool>false</bool>
+        </property>
+        <property name="text">
+         <string>Connect</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="disconnectButton">
+        <property name="enabled">
+         <bool>false</bool>
+        </property>
+        <property name="text">
+         <string>Disconnect</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="exitButton">
+        <property name="text">
+         <string>Exit</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </item>
+    <item row="3" column="1">
+     <widget class="QLabel" name="ipLabel">
+      <property name="toolTip">
+       <string>If running as a server, this is the address you should supply to the other clients.
+(You will need to enable any port forwarding on your router manually.)</string>
+      </property>
+      <property name="text">
+       <string>Looking up external IP address...</string>
+      </property>
+     </widget>
+    </item>
+    <item row="1" column="1">
+     <widget class="QComboBox" name="addressComboBox">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <property name="toolTip">
+       <string>Enter the IP address or the hostname of the server you want to connect to.</string>
+      </property>
+      <property name="editable">
+       <bool>true</bool>
+      </property>
+      <property name="maxCount">
+       <number>5</number>
+      </property>
+      <property name="insertPolicy">
+       <enum>QComboBox::NoInsert</enum>
+      </property>
+     </widget>
+    </item>
+    <item row="1" column="0">
+     <widget class="QLabel" name="addressLabel">
+      <property name="enabled">
+       <bool>true</bool>
+      </property>
+      <property name="text">
+       <string>&amp;Address of server</string>
+      </property>
+      <property name="buddy">
+       <cstring>addressComboBox</cstring>
+      </property>
+     </widget>
+    </item>
+    <item row="0" column="0">
+     <widget class="QLabel" name="typeLabel">
+      <property name="text">
+       <string>&amp;Run JackTrip as</string>
+      </property>
+      <property name="buddy">
+       <cstring>typeComboBox</cstring>
+      </property>
+     </widget>
+    </item>
+    <item row="5" column="0" colspan="2">
+     <widget class="QTabWidget" name="optionsTabWidget">
+      <property name="enabled">
+       <bool>true</bool>
+      </property>
+      <property name="minimumSize">
+       <size>
+        <width>391</width>
+        <height>0</height>
+       </size>
+      </property>
+      <property name="currentIndex">
+       <number>0</number>
+      </property>
+      <property name="tabsClosable">
+       <bool>false</bool>
+      </property>
+      <property name="movable">
+       <bool>false</bool>
+      </property>
+      <widget class="QWidget" name="basicTab">
+       <property name="enabled">
+        <bool>true</bool>
+       </property>
+       <attribute name="title">
+        <string>Basic options</string>
+       </attribute>
+       <layout class="QGridLayout" name="gridLayout_3">
+        <item row="2" column="0" colspan="3">
+         <widget class="QGroupBox" name="channelGroupBox">
+          <layout class="QGridLayout" name="gridLayout_9">
+           <item row="3" column="0">
+            <widget class="QLabel" name="channelRecvLabel">
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
+             </property>
+             <property name="text">
+              <string>&amp;Received from network:</string>
+             </property>
+             <property name="buddy">
+              <cstring>channelRecvSpinBox</cstring>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="1">
+            <widget class="QSpinBox" name="channelRecvSpinBox">
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
+             </property>
+             <property name="toolTip">
+              <string>Number of audio channels toaccept from the network.</string>
+             </property>
+             <property name="minimum">
+              <number>1</number>
+             </property>
+             <property name="value">
+              <number>2</number>
+             </property>
+            </widget>
+           </item>
+           <item row="4" column="1">
+            <widget class="QSpinBox" name="channelSendSpinBox">
+             <property name="toolTip">
+              <string>Number of audio channels to send to the network.</string>
+             </property>
+             <property name="minimum">
+              <number>1</number>
+             </property>
+             <property name="value">
+              <number>2</number>
+             </property>
+            </widget>
+           </item>
+           <item row="4" column="0">
+            <widget class="QLabel" name="channelSendLabel">
+             <property name="text">
+              <string>&amp;Sent to network:</string>
+             </property>
+             <property name="buddy">
+              <cstring>channelSendSpinBox</cstring>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="0" colspan="2">
+            <widget class="QLabel" name="channelLabel">
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
+             </property>
+             <property name="text">
+              <string>&amp;Number of channels</string>
+             </property>
+             <property name="buddy">
+              <cstring>channelRecvSpinBox</cstring>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+        <item row="3" column="1" colspan="2">
+         <widget class="QComboBox" name="autoPatchComboBox">
+          <property name="toolTip">
+           <string>Select how you want audio to be routed by the hub server.</string>
+          </property>
+          <property name="currentIndex">
+           <number>0</number>
+          </property>
+          <item>
+           <property name="text">
+            <string>Server to clients</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>Client loopback</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>Client fan out/in but no loopback</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>Full Mix</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>No auto patching</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+        <item row="11" column="0" colspan="3">
+         <layout class="QHBoxLayout" name="aboutLayout">
+          <item>
+           <spacer name="aboutSpacer">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QPushButton" name="aboutButton">
+            <property name="text">
+             <string>About</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item row="7" column="0" colspan="3">
+         <widget class="QGroupBox" name="requireAuthGroupBox">
+          <property name="title">
+           <string/>
+          </property>
+          <layout class="QGridLayout" name="gridLayout_7">
+           <item row="3" column="2">
+            <widget class="QPushButton" name="keyBrowse">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>Browse</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="0" colspan="3">
+            <widget class="QLabel" name="authDisclaimerLabel">
+             <property name="text">
+              <string>(This is a work in progress and needs to be manually configured outside of the app. Only use if you know what you're doing.)</string>
+             </property>
+             <property name="wordWrap">
+              <bool>true</bool>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="0">
+            <widget class="QLabel" name="certLabel">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>&amp;Certificate File</string>
+             </property>
+             <property name="buddy">
+              <cstring>certEdit</cstring>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="0">
+            <widget class="QLabel" name="keyLabel">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>&amp;Key File</string>
+             </property>
+             <property name="buddy">
+              <cstring>keyEdit</cstring>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="1">
+            <widget class="QLineEdit" name="keyEdit">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="toolTip">
+              <string>Choose the private key that the server should use for the SSL connection.</string>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="1">
+            <widget class="QLineEdit" name="certEdit">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="toolTip">
+              <string>Choose the certificate file that the server should use to establish an initial SSL connection.</string>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="2">
+            <widget class="QPushButton" name="certBrowse">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>Browse</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="0" colspan="2">
+            <widget class="QCheckBox" name="requireAuthCheckBox">
+             <property name="toolTip">
+              <string>Require clients to connect with a username and password.</string>
+             </property>
+             <property name="text">
+              <string>&amp;Require Authentication</string>
+             </property>
+            </widget>
+           </item>
+           <item row="4" column="0">
+            <widget class="QLabel" name="credsLabel">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>&amp;Credentials File</string>
+             </property>
+             <property name="buddy">
+              <cstring>credsEdit</cstring>
+             </property>
+            </widget>
+           </item>
+           <item row="4" column="1">
+            <widget class="QLineEdit" name="credsEdit">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="toolTip">
+              <string>Choose the file containing the list of usernames and passwords.</string>
+             </property>
+            </widget>
+           </item>
+           <item row="4" column="2">
+            <widget class="QPushButton" name="credsBrowse">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>Browse</string>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+        <item row="6" column="0" colspan="3">
+         <widget class="QCheckBox" name="timeoutCheckBox">
+          <property name="toolTip">
+           <string>Stop JackTrip if no network traffic has been received for 10 seconds.</string>
+          </property>
+          <property name="text">
+           <string>&amp;Disconnect after 10 seconds of no network activity</string>
+          </property>
+         </widget>
+        </item>
+        <item row="9" column="0">
+         <spacer name="basicVerticalSpacer">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeType">
+           <enum>QSizePolicy::Expanding</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>40</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+        <item row="5" column="0" colspan="3">
+         <widget class="QCheckBox" name="zeroCheckBox">
+          <property name="toolTip">
+           <string>Silence the audio when there's a buffer underrun.</string>
+          </property>
+          <property name="text">
+           <string>Set buffer to &amp;zero when underrun occurs</string>
+          </property>
+         </widget>
+        </item>
+        <item row="3" column="0">
+         <widget class="QLabel" name="autoPatchLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>Hub auto&amp;patch mode</string>
+          </property>
+          <property name="buddy">
+           <cstring>autoPatchComboBox</cstring>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+      <widget class="QWidget" name="advancedTab">
+       <property name="enabled">
+        <bool>true</bool>
+       </property>
+       <attribute name="title">
+        <string>Advanced options</string>
+       </attribute>
+       <layout class="QGridLayout" name="gridLayout_4">
+        <item row="2" column="0">
+         <widget class="QLabel" name="localPortLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>&amp;Local Port</string>
+          </property>
+          <property name="buddy">
+           <cstring>localPortSpinBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="11" column="0">
+         <widget class="QCheckBox" name="ioStatsCheckBox">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="toolTip">
+           <string>Display IO stats in another window.</string>
+          </property>
+          <property name="text">
+           <string>Display &amp;IO Stats</string>
+          </property>
+         </widget>
+        </item>
+        <item row="12" column="0" colspan="3">
+         <widget class="QGroupBox" name="authGroupBox">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="title">
+           <string/>
+          </property>
+          <layout class="QGridLayout" name="gridLayout_6">
+           <item row="0" column="0" colspan="2">
+            <widget class="QCheckBox" name="authCheckBox">
+             <property name="toolTip">
+              <string>Supply a username and password to connect to the server.</string>
+             </property>
+             <property name="text">
+              <string>&amp;Use Authentication</string>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="1">
+            <widget class="QLineEdit" name="passwordEdit">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="toolTip">
+              <string>Enter your password. (This will not be shown or saved.)</string>
+             </property>
+             <property name="echoMode">
+              <enum>QLineEdit::Password</enum>
+             </property>
+             <property name="cursorPosition">
+              <number>0</number>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="1">
+            <widget class="QLineEdit" name="usernameEdit">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="toolTip">
+              <string>Enter your username for the server.</string>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="0">
+            <widget class="QLabel" name="passwordLabel">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>&amp;Password</string>
+             </property>
+             <property name="buddy">
+              <cstring>passwordEdit</cstring>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="0">
+            <widget class="QLabel" name="usernameLabel">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>&amp;Username</string>
+             </property>
+             <property name="buddy">
+              <cstring>usernameEdit</cstring>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+        <item row="1" column="0">
+         <widget class="QLabel" name="remoteNameLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>Remote Client &amp;Name</string>
+          </property>
+          <property name="buddy">
+           <cstring>remoteNameEdit</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="12" column="0">
+         <spacer name="advancedVerticalSpacer">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>40</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+        <item row="8" column="0" colspan="3">
+         <widget class="QCheckBox" name="connectAudioCheckBox">
+          <property name="toolTip">
+           <string>Connect the Jack client to the default system audio ports.</string>
+          </property>
+          <property name="text">
+           <string>&amp;Connect default audio ports</string>
+          </property>
+          <property name="checked">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="1" colspan="2">
+         <widget class="QSpinBox" name="localPortSpinBox">
+          <property name="toolTip">
+           <string>Set the local port to use for the connection. The default is 4464.
+(Useful for running multiple hub clients behind the same router.)</string>
+          </property>
+          <property name="minimum">
+           <number>1024</number>
+          </property>
+          <property name="maximum">
+           <number>65535</number>
+          </property>
+          <property name="value">
+           <number>4464</number>
+          </property>
+         </widget>
+        </item>
+        <item row="11" column="2">
+         <widget class="QLabel" name="ioStatsLabel">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>Reporting &amp;Interval (s)</string>
+          </property>
+          <property name="buddy">
+           <cstring>ioStatsSpinBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="3" column="0">
+         <widget class="QLabel" name="remotePortLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>Remote &amp;Port</string>
+          </property>
+          <property name="buddy">
+           <cstring>remotePortSpinBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="7" column="0">
+         <widget class="QLabel" name="resolutionLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>Audio &amp;Bit Resolution</string>
+          </property>
+          <property name="buddy">
+           <cstring>resolutionComboBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="1" colspan="2">
+         <widget class="QLineEdit" name="clientNameEdit">
+          <property name="toolTip">
+           <string>Set the name of the Jack client.</string>
+          </property>
+          <property name="maxLength">
+           <number>64</number>
+          </property>
+          <property name="placeholderText">
+           <string>JackTrip</string>
+          </property>
+         </widget>
+        </item>
+        <item row="6" column="0">
+         <widget class="QLabel" name="redundancyLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>&amp;Redundancy</string>
+          </property>
+          <property name="buddy">
+           <cstring>redundancySpinBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="5" column="0">
+         <widget class="QLabel" name="queueLengthLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>&amp;Queue Buffer Length</string>
+          </property>
+          <property name="buddy">
+           <cstring>queueLengthSpinBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="1" colspan="2">
+         <widget class="QLineEdit" name="remoteNameEdit">
+          <property name="toolTip">
+           <string>Set the name of the Jack client as it will appear on the hub server.</string>
+          </property>
+          <property name="maxLength">
+           <number>64</number>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="0">
+         <widget class="QLabel" name="clientNameLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>Custom Client &amp;Name</string>
+          </property>
+          <property name="buddy">
+           <cstring>clientNameEdit</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="11" column="1">
+         <widget class="QSpinBox" name="ioStatsSpinBox">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="toolTip">
+           <string>Choose how often stats should be reported.</string>
+          </property>
+          <property name="minimum">
+           <number>1</number>
+          </property>
+          <property name="maximum">
+           <number>120</number>
+          </property>
+         </widget>
+        </item>
+        <item row="7" column="1" colspan="2">
+         <widget class="QComboBox" name="resolutionComboBox">
+          <property name="toolTip">
+           <string>Select the audio bit resolution.</string>
+          </property>
+          <property name="currentIndex">
+           <number>1</number>
+          </property>
+          <item>
+           <property name="text">
+            <string>8</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>16</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>24</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>32</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+        <item row="6" column="1" colspan="2">
+         <widget class="QSpinBox" name="redundancySpinBox">
+          <property name="toolTip">
+           <string>Number of redundant packets to be sent to avoid glitches related to packet loss.</string>
+          </property>
+          <property name="minimum">
+           <number>1</number>
+          </property>
+          <property name="value">
+           <number>1</number>
+          </property>
+         </widget>
+        </item>
+        <item row="5" column="1" colspan="2">
+         <widget class="QSpinBox" name="queueLengthSpinBox">
+          <property name="toolTip">
+           <string>Set the queue buffer length, in packet size.</string>
+          </property>
+          <property name="minimum">
+           <number>2</number>
+          </property>
+          <property name="value">
+           <number>4</number>
+          </property>
+         </widget>
+        </item>
+        <item row="3" column="1" colspan="2">
+         <widget class="QSpinBox" name="remotePortSpinBox">
+          <property name="toolTip">
+           <string>Set the remote port to use for the connection. The default is 4464.</string>
+          </property>
+          <property name="minimum">
+           <number>1024</number>
+          </property>
+          <property name="maximum">
+           <number>65535</number>
+          </property>
+          <property name="value">
+           <number>4464</number>
+          </property>
+         </widget>
+        </item>
+        <item row="13" column="0" colspan="3">
+         <layout class="QHBoxLayout" name="useDefaultsLayout">
+          <item>
+           <spacer name="useDefaultsSpacer">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QPushButton" name="commandLineButton">
+            <property name="toolTip">
+             <string>Show the equivalent command line for the current settings.</string>
+            </property>
+            <property name="text">
+             <string>Get Command &amp;Line</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QPushButton" name="useDefaultsButton">
+            <property name="text">
+             <string>Use &amp;Defaults</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item row="4" column="0">
+         <widget class="QLabel" name="basePortLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>&amp;UDP Base Port</string>
+          </property>
+          <property name="buddy">
+           <cstring>basePortSpinBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="4" column="1" colspan="2">
+         <widget class="QSpinBox" name="basePortSpinBox">
+          <property name="toolTip">
+           <string>Set the base UDP port to be used by connecting hub clients. The default is 61002.
+(You should manually set this if running multiple hub servers on the same machine.)</string>
+          </property>
+          <property name="minimum">
+           <number>1024</number>
+          </property>
+          <property name="maximum">
+           <number>65535</number>
+          </property>
+          <property name="value">
+           <number>61002</number>
+          </property>
+         </widget>
+        </item>
+        <item row="9" column="0" colspan="3">
+         <widget class="QCheckBox" name="realTimeCheckBox">
+          <property name="toolTip">
+           <string>Use real time priority for the networking threads.</string>
+          </property>
+          <property name="text">
+           <string>Enable real&amp;time priority for networking threads</string>
+          </property>
+          <property name="checked">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+      <widget class="QWidget" name="backendTab">
+       <attribute name="title">
+        <string>Audio Backend</string>
+       </attribute>
+       <layout class="QGridLayout" name="gridLayout_11">
+        <item row="0" column="0">
+         <widget class="QLabel" name="backendLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>Audio &amp;Backend:</string>
+          </property>
+          <property name="buddy">
+           <cstring>backendComboBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="1">
+         <widget class="QComboBox" name="backendComboBox">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Choose the audio backend to use. JACK is the default and is well tested, but requires the JACK audio server to be installed.&lt;/p&gt;&lt;p&gt;RtAudio is still a work in progress, but it works with your operating system's native audio drivers and requires no additional software.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <item>
+           <property name="text">
+            <string>JACK</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>RtAudio</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+        <item row="1" column="0">
+         <widget class="QLabel" name="sampleRateLabel">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>&amp;Sampling Rate:</string>
+          </property>
+          <property name="buddy">
+           <cstring>sampleRateComboBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="1">
+         <widget class="QComboBox" name="sampleRateComboBox">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Set the audio sample rate to use with the RtAudio backend. This setting should be the same on both ends of the connection.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="currentText">
+           <string>48000</string>
+          </property>
+          <property name="currentIndex">
+           <number>3</number>
+          </property>
+          <item>
+           <property name="text">
+            <string>22050</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>32000</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>44100</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>48000</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>88200</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>96000</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>192000</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+        <item row="2" column="0">
+         <widget class="QLabel" name="bufferSizeLabel">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>&amp;Buffer Size:</string>
+          </property>
+          <property name="buddy">
+           <cstring>bufferSizeComboBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="1">
+         <widget class="QComboBox" name="bufferSizeComboBox">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Set the driver's buffer size to use with the RtAudio backend.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="currentIndex">
+           <number>3</number>
+          </property>
+          <item>
+           <property name="text">
+            <string>16</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>32</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>64</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>128</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>256</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>512</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>1024</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+        <item row="3" column="0">
+         <widget class="QLabel" name="inputDeviceLabel">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>&amp;Input Device:</string>
+          </property>
+          <property name="buddy">
+           <cstring>inputDeviceComboBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="3" column="1">
+         <widget class="QComboBox" name="inputDeviceComboBox">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="4" column="0">
+         <widget class="QLabel" name="outputDeviceLabel">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>&amp;Output Device:</string>
+          </property>
+          <property name="buddy">
+           <cstring>outputDeviceComboBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="4" column="1">
+         <widget class="QComboBox" name="outputDeviceComboBox">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="5" column="1">
+         <spacer name="backendSpacer">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>444</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+        <item row="8" column="0" colspan="2">
+          <layout class="QHBoxLayout" name="deviceManagementLayout">
+           <item>
+            <spacer name="backendTabSpacer">
+             <property name="orientation">
+              <enum>Qt::Horizontal</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>40</width>
+               <height>20</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+           <item row="8" column="2">
+            <widget class="QPushButton" name="refreshDevicesButton">
+             <property name="text">
+              <string>&amp;Refresh Device List</string>
+             </property>
+            </widget>
+           </item>
+          </layout>
+        </item>
+       </layout>
+      </widget>
+      <widget class="QWidget" name="JitterTab">
+       <attribute name="title">
+        <string>Jitter Buffer</string>
+       </attribute>
+       <layout class="QGridLayout" name="gridLayout_8">
+        <item row="10" column="2">
+         <widget class="QLabel" name="packetsLabel">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>Packets</string>
+          </property>
+         </widget>
+        </item>
+        <item row="8" column="0" colspan="3">
+         <widget class="QCheckBox" name="autoQueueCheckBox">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="text">
+           <string>Automatically set the &amp;queue length</string>
+          </property>
+         </widget>
+        </item>
+        <item row="9" column="0" colspan="2">
+         <widget class="QLabel" name="autoQueueLabel">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>Aim to &amp;drop no more than one in every</string>
+          </property>
+          <property name="buddy">
+           <cstring>autoQueueSpinBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="5" column="0" colspan="3">
+         <widget class="Line" name="bufferLine">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+         </widget>
+        </item>
+        <item row="9" column="2">
+         <widget class="QSpinBox" name="autoQueueSpinBox">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="maximum">
+           <number>1000000</number>
+          </property>
+          <property name="singleStep">
+           <number>100</number>
+          </property>
+          <property name="value">
+           <number>500</number>
+          </property>
+         </widget>
+        </item>
+        <item row="3" column="0" colspan="3">
+         <widget class="QCheckBox" name="broadcastCheckBox">
+          <property name="toolTip">
+           <string>Enable a second, broadcast output with a higher queue length
+for better quality at the expense of latency.</string>
+          </property>
+          <property name="text">
+           <string>Enable &amp;Broadcast Output</string>
+          </property>
+         </widget>
+        </item>
+        <item row="12" column="0">
+         <spacer name="verticalSpacer">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>40</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+        <item row="11" column="0" colspan="3">
+         <widget class="QLabel" name="autoQueueExplanationLabel">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>This will override the queue buffer length entered in the advanced options tab. (The default value is 500.)</string>
+          </property>
+          <property name="wordWrap">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="0" colspan="2">
+         <widget class="QCheckBox" name="jitterCheckBox">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="toolTip">
+           <string>Enable the new jitter buffer. This is now the default.</string>
+          </property>
+          <property name="text">
+           <string>Enable &amp;Jitter Buffer</string>
+          </property>
+          <property name="checked">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="1" colspan="2">
+         <widget class="QComboBox" name="bufferStrategyComboBox">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Buffer strategy 1 attempts to drop as little audio data as possible without exceeding the maximum queue length. It operates very similarly to the original buffer implementation with a few fixes to drop even less audio.&lt;/p&gt;&lt;p&gt;Buffer strategy 2 is optimized to keep the latency stable, so that the delay experienced over the connection doesn't fluctuate and is as predictable as possible. The trade off is that more audio might be dropped, but the difference should be negligible with the right queue length.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="currentIndex">
+           <number>0</number>
+          </property>
+          <item>
+           <property name="text">
+            <string>1</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>2</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>3 (experimental)</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+        <item row="2" column="0">
+         <widget class="QLabel" name="bufferStrategyLabel">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>Use buffer &amp;strategy</string>
+          </property>
+          <property name="buddy">
+           <cstring>bufferStrategyComboBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="4" column="0">
+         <widget class="QLabel" name="broadcastQueueLabel">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>Broadcast &amp;Queue Length</string>
+          </property>
+          <property name="buddy">
+           <cstring>broadcastQueueSpinBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="4" column="1" colspan="2">
+         <widget class="QSpinBox" name="broadcastQueueSpinBox">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="toolTip">
+           <string>Set the broadcast queue buffer length, in packet size.</string>
+          </property>
+          <property name="value">
+           <number>8</number>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+      <widget class="QWidget" name="pluginsTab">
+       <attribute name="title">
+        <string>Plugins</string>
+       </attribute>
+       <layout class="QVBoxLayout" name="verticalLayout">
+        <item>
+         <widget class="QGroupBox" name="incomingGroupBox">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="title">
+           <string>Incoming</string>
+          </property>
+          <layout class="QGridLayout" name="gridLayout_5">
+           <item row="1" column="1">
+            <widget class="QSlider" name="inZitarevWetnessSlider">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="toolTip">
+              <string>Set the wet/dry mix.</string>
+             </property>
+             <property name="maximum">
+              <number>100</number>
+             </property>
+             <property name="orientation">
+              <enum>Qt::Horizontal</enum>
+             </property>
+             <property name="tickPosition">
+              <enum>QSlider::TicksBelow</enum>
+             </property>
+             <property name="tickInterval">
+              <number>20</number>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="2">
+            <widget class="QLabel" name="inFreeverbLabel">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>Wetness</string>
+             </property>
+            </widget>
+           </item>
+           <item row="4" column="0">
+            <widget class="QCheckBox" name="inLimiterCheckBox">
+             <property name="toolTip">
+              <string>Enable the limiter on incoming audio.</string>
+             </property>
+             <property name="text">
+              <string>&amp;Limiter</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="0">
+            <widget class="QCheckBox" name="inFreeverbCheckBox">
+             <property name="toolTip">
+              <string>Enable the freeverb plugin on incoming audio.</string>
+             </property>
+             <property name="text">
+              <string>&amp;Freeverb</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="2" alignment="Qt::AlignHCenter">
+            <widget class="QLabel" name="inZitarevLabel">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>Wetness</string>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="0">
+            <widget class="QCheckBox" name="inCompressorCheckBox">
+             <property name="toolTip">
+              <string>Enable the compressor plugin on incoming audio.</string>
+             </property>
+             <property name="text">
+              <string>&amp;Compressor</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="0">
+            <widget class="QCheckBox" name="inZitarevCheckBox">
+             <property name="toolTip">
+              <string>Enable the zitarev reverb plugin on incoming audio.</string>
+             </property>
+             <property name="text">
+              <string>&amp;Zitarev</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="1">
+            <widget class="QSlider" name="inFreeverbWetnessSlider">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="toolTip">
+              <string>Set the wet/dry mix.</string>
+             </property>
+             <property name="maximum">
+              <number>100</number>
+             </property>
+             <property name="singleStep">
+              <number>1</number>
+             </property>
+             <property name="orientation">
+              <enum>Qt::Horizontal</enum>
+             </property>
+             <property name="invertedAppearance">
+              <bool>false</bool>
+             </property>
+             <property name="tickPosition">
+              <enum>QSlider::TicksBelow</enum>
+             </property>
+             <property name="tickInterval">
+              <number>20</number>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+        <item>
+         <widget class="QGroupBox" name="outgoingGroupBox">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="title">
+           <string>Outgoing</string>
+          </property>
+          <layout class="QGridLayout" name="gridLayout_2">
+           <item row="0" column="0">
+            <widget class="QCheckBox" name="outFreeverbCheckBox">
+             <property name="toolTip">
+              <string>Enable the freeverb plugin on outgoing audio.</string>
+             </property>
+             <property name="text">
+              <string>Free&amp;verb</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="1">
+            <widget class="QSlider" name="outFreeverbWetnessSlider">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="toolTip">
+              <string>Set the wet/dry mix.</string>
+             </property>
+             <property name="maximum">
+              <number>100</number>
+             </property>
+             <property name="singleStep">
+              <number>1</number>
+             </property>
+             <property name="orientation">
+              <enum>Qt::Horizontal</enum>
+             </property>
+             <property name="invertedAppearance">
+              <bool>false</bool>
+             </property>
+             <property name="tickPosition">
+              <enum>QSlider::TicksBelow</enum>
+             </property>
+             <property name="tickInterval">
+              <number>20</number>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="2">
+            <widget class="QLabel" name="outFreeverbLabel">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>Wetness</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="0">
+            <widget class="QCheckBox" name="outZitarevCheckBox">
+             <property name="toolTip">
+              <string>Enable the zitarev reverb plugin on outgoing audio.</string>
+             </property>
+             <property name="text">
+              <string>Zi&amp;tarev</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="1">
+            <widget class="QSlider" name="outZitarevWetnessSlider">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="toolTip">
+              <string>Set the wet/dry mix.</string>
+             </property>
+             <property name="maximum">
+              <number>100</number>
+             </property>
+             <property name="orientation">
+              <enum>Qt::Horizontal</enum>
+             </property>
+             <property name="tickPosition">
+              <enum>QSlider::TicksBelow</enum>
+             </property>
+             <property name="tickInterval">
+              <number>20</number>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="2">
+            <widget class="QLabel" name="outZitarevLabel">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="toolTip">
+              <string>Moisture is the essence of wetness,
+and wetness is the essence of beauty.</string>
+             </property>
+             <property name="text">
+              <string>Wetness</string>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="0">
+            <widget class="QCheckBox" name="outCompressorCheckBox">
+             <property name="toolTip">
+              <string>Enable the compressor plugin on outgoing audio.</string>
+             </property>
+             <property name="text">
+              <string>Com&amp;pressor</string>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="0">
+            <widget class="QCheckBox" name="outLimiterCheckBox">
+             <property name="toolTip">
+              <string>Enable the limiter on outgoing audio.</string>
+             </property>
+             <property name="text">
+              <string>Li&amp;miter</string>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="1">
+            <widget class="QSpinBox" name="outClientsSpinBox">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="toolTip">
+              <string>Enter the anticipated number of clients that will be connected to the server.</string>
+             </property>
+             <property name="minimum">
+              <number>1</number>
+             </property>
+             <property name="maximum">
+              <number>100</number>
+             </property>
+             <property name="value">
+              <number>2</number>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="2">
+            <widget class="QLabel" name="outLimiterLabel">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>Clients</string>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+        <item>
+         <spacer name="pluginsVerticalSpacer">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>40</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </widget>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menuBar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>409</width>
+     <height>30</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QStatusBar" name="statusBar"/>
+ </widget>
+ <tabstops>
+  <tabstop>typeComboBox</tabstop>
+  <tabstop>addressComboBox</tabstop>
+  <tabstop>connectButton</tabstop>
+  <tabstop>disconnectButton</tabstop>
+  <tabstop>exitButton</tabstop>
+  <tabstop>optionsTabWidget</tabstop>
+  <tabstop>channelRecvSpinBox</tabstop>
+  <tabstop>channelSendSpinBox</tabstop>
+  <tabstop>autoPatchComboBox</tabstop>
+  <tabstop>zeroCheckBox</tabstop>
+  <tabstop>timeoutCheckBox</tabstop>
+  <tabstop>requireAuthCheckBox</tabstop>
+  <tabstop>certEdit</tabstop>
+  <tabstop>certBrowse</tabstop>
+  <tabstop>keyEdit</tabstop>
+  <tabstop>keyBrowse</tabstop>
+  <tabstop>credsEdit</tabstop>
+  <tabstop>credsBrowse</tabstop>
+  <tabstop>authCheckBox</tabstop>
+  <tabstop>usernameEdit</tabstop>
+  <tabstop>passwordEdit</tabstop>
+  <tabstop>aboutButton</tabstop>
+  <tabstop>clientNameEdit</tabstop>
+  <tabstop>remoteNameEdit</tabstop>
+  <tabstop>localPortSpinBox</tabstop>
+  <tabstop>remotePortSpinBox</tabstop>
+  <tabstop>basePortSpinBox</tabstop>
+  <tabstop>queueLengthSpinBox</tabstop>
+  <tabstop>redundancySpinBox</tabstop>
+  <tabstop>resolutionComboBox</tabstop>
+  <tabstop>connectAudioCheckBox</tabstop>
+  <tabstop>realTimeCheckBox</tabstop>
+  <tabstop>ioStatsCheckBox</tabstop>
+  <tabstop>ioStatsSpinBox</tabstop>
+  <tabstop>commandLineButton</tabstop>
+  <tabstop>useDefaultsButton</tabstop>
+  <tabstop>backendComboBox</tabstop>
+  <tabstop>sampleRateComboBox</tabstop>
+  <tabstop>bufferSizeComboBox</tabstop>
+  <tabstop>inputDeviceComboBox</tabstop>
+  <tabstop>outputDeviceComboBox</tabstop>
+  <tabstop>refreshDevicesButton</tabstop>
+  <tabstop>jitterCheckBox</tabstop>
+  <tabstop>bufferStrategyComboBox</tabstop>
+  <tabstop>broadcastCheckBox</tabstop>
+  <tabstop>broadcastQueueSpinBox</tabstop>
+  <tabstop>autoQueueCheckBox</tabstop>
+  <tabstop>autoQueueSpinBox</tabstop>
+  <tabstop>inFreeverbCheckBox</tabstop>
+  <tabstop>inFreeverbWetnessSlider</tabstop>
+  <tabstop>inZitarevCheckBox</tabstop>
+  <tabstop>inZitarevWetnessSlider</tabstop>
+  <tabstop>inCompressorCheckBox</tabstop>
+  <tabstop>inLimiterCheckBox</tabstop>
+  <tabstop>outFreeverbCheckBox</tabstop>
+  <tabstop>outFreeverbWetnessSlider</tabstop>
+  <tabstop>outZitarevCheckBox</tabstop>
+  <tabstop>outZitarevWetnessSlider</tabstop>
+  <tabstop>outCompressorCheckBox</tabstop>
+  <tabstop>outLimiterCheckBox</tabstop>
+  <tabstop>outClientsSpinBox</tabstop>
+ </tabstops>
+ <resources>
+  <include location="qjacktrip.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/src/jacktrip.pro b/src/jacktrip.pro
deleted file mode 100644 (file)
index 0157e90..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-#******************************
-# Created by Juan-Pablo Caceres
-#******************************
-
-CONFIG += c++11 console
-CONFIG -= app_bundle
-
-CONFIG += qt thread debug_and_release build_all
-CONFIG(debug, debug|release) {
-  TARGET = jacktrip_debug
-  } else {
-  TARGET = jacktrip
-  }
-
-QT -= gui
-QT += network
-
-# rc.1.2 switch enables experimental wair build, merge some of it with WAIRTOHUB
-# DEFINES += WAIR
-DEFINES += WAIRTOHUB
-
-# http://wiki.qtcentre.org/index.php?title=Undocumented_qmake#Custom_tools
-#cc DEFINES += __RT_AUDIO__
-# Configuration without Jack
-nojack {
-  DEFINES += __NO_JACK__
-}
-
-# for plugins
-INCLUDEPATH += ../faust-src-lair/stk
-
-!win32 {
-  INCLUDEPATH+=/usr/local/include
-# wair needs stk, can be had from linux this way
-# INCLUDEPATH+=/usr/include/stk
-# LIBS += -L/usr/local/lib -ljack -lstk -lm
-  LIBS += -L/usr/local/lib -ljack -lm
-  nojack {
-    message(Building NONJACK)
-    LIBS -= -ljack
-  }
-}
-
-macx {
-  message(Building on MAC OS X)
-  QMAKE_CXXFLAGS += -D__MACOSX_CORE__ #-D__UNIX_JACK__ #RtAudio Flags
-  QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.9
-  #QMAKE_MAC_SDK = macosx10.9
-  CONFIG -= app_bundle
-  #CONFIG += x86 #ppc #### If you have both libraries installed, you
-  # can change between 32bits (x86) or 64bits(x86_64) Change this to go back to 32 bits (x86)
-  LIBS += -framework CoreAudio -framework CoreFoundation
-  DEFINES += __MAC_OSX__
-  }
-
-linux-g++ | linux-g++-64 {
-#   LIBS += -lasound -lrtaudio
-  QMAKE_CXXFLAGS += -D__LINUX_ALSA__ #-D__LINUX_OSS__ #RtAudio Flags
-
-FEDORA = $$system(cat /proc/version | grep -o fc)
-
-contains( FEDORA, fc): {
-  message(building on fedora)
-}
-
-UBUNTU = $$system(cat /proc/version | grep -o Ubuntu)
-
-contains( UBUNTU, Ubuntu): {
-  message(building on  Ubuntu)
-
-# workaround for Qt bug under ubuntu 18.04
-# gcc version 7.3.0 (Ubuntu 7.3.0-16ubuntu3)
-# QMake version 3.1
-# Using Qt version 5.9.5 in /usr/lib/x86_64-linux-gnu
-  INCLUDEPATH += /usr/include/x86_64-linux-gnu/c++/7
-
-# sets differences from original fedora version
-  DEFINES += __UBUNTU__
-}
-
-  QMAKE_CXXFLAGS += -g -O2
-  DEFINES += __LINUX__
-  }
-
-linux-g++ {
-  message(Linux)
-  QMAKE_CXXFLAGS += -D__LINUX_ALSA__ #-D__LINUX_OSS__ #RtAudio Flags
-  }
-
-linux-g++-64 {
-  message(Linux 64bit)
-  QMAKE_CXXFLAGS += -fPIC -D__LINUX_ALSA__ #-D__LINUX_OSS__ #RtAudio Flags
-  }
-
-
-win32 {
-  message(Building on win32)
-#cc  CONFIG += x86 console
-  CONFIG += c++11 console
-  INCLUDEPATH += "C:\Program Files (x86)\Jack\includes"
-  LIBS += "C:\Program Files (x86)\Jack\lib\libjack64.lib"
-  LIBS += "C:\Program Files (x86)\Jack\lib\libjackserver64.lib"
-#cc  QMAKE_CXXFLAGS += -D__WINDOWS_ASIO__ #-D__UNIX_JACK__ #RtAudio Flags
-  #QMAKE_LFLAGS += -static -static-libgcc -static-libstdc++ -lpthread
-  LIBS += -lWs2_32 #cc -lOle32 #needed by rtaudio/asio
-  DEFINES += __WIN_32__
-  DEFINES += _WIN32_WINNT=0x0600 #needed for inet_pton
-#cc    DEFINES -= UNICODE #RtAudio for Qt
-}
-
-DESTDIR = .
-QMAKE_CLEAN += -r ./jacktrip ./jacktrip_debug ./release ./debug
-
-# isEmpty(PREFIX) will allow path to be changed during the command line
-# call to qmake, e.g. qmake PREFIX=/usr
-isEmpty(PREFIX) {
- PREFIX = /usr/local
-}
-target.path = $$PREFIX/bin/
-INSTALLS += target
-
-# for plugins
-INCLUDEPATH += ../faust-src-lair
-
-# Input
-HEADERS += DataProtocol.h \
-           JMess.h \
-           JackTrip.h \
-           Effects.h \
-           Compressor.h \
-           CompressorPresets.h \
-           Limiter.h \
-           Reverb.h \
-           AudioTester.h \
-           jacktrip_globals.h \
-           jacktrip_types.h \
-           JackTripThread.h \
-           JackTripWorker.h \
-           JackTripWorkerMessages.h \
-           JitterBuffer.h \
-           LoopBack.h \
-           NetKS.h \
-           PacketHeader.h \
-           ProcessPlugin.h \
-           RingBuffer.h \
-           RingBufferWavetable.h \
-           Settings.h \
-           TestRingBuffer.h \
-           ThreadPoolTest.h \
-           UdpDataProtocol.h \
-           UdpHubListener.h \
-           AudioInterface.h \
-           compressordsp.h \
-           limiterdsp.h \
-           freeverbdsp.h
-
-!nojack {
-HEADERS += JackAudioInterface.h
-}
-SOURCES += DataProtocol.cpp \
-           JMess.cpp \
-           JackTrip.cpp \
-           Compressor.cpp \
-           Limiter.cpp \
-           Reverb.cpp \
-           AudioTester.cpp \
-           jacktrip_globals.cpp \
-           jacktrip_main.cpp \
-           jacktrip_tests.cpp \
-           JackTripThread.cpp \
-           JackTripWorker.cpp \
-           JitterBuffer.cpp \
-           LoopBack.cpp \
-           PacketHeader.cpp \
-           ProcessPlugin.cpp \
-           RingBuffer.cpp \
-           Settings.cpp \
-           UdpDataProtocol.cpp \
-           UdpHubListener.cpp \
-           AudioInterface.cpp
-
-!nojack {
-SOURCES += JackAudioInterface.cpp
-}
-
-# RtAudio Input
-win32 {
-  INCLUDEPATH += ../externals/rtaudio-4.1.1/include
-  DEPENDPATH += ../externals/rtaudio-4.1.1/include
-}
-macx | win32 {
-INCLUDEPATH += ../externals/rtaudio-4.1.1/
-DEPENDPATH += ../externals/rtaudio-4.1.1/
-HEADERS +=
-SOURCES +=
-}
index 7e75994bb1a74a5865c46c56047546bc09ad1faa..977c712639165594d27ab105fb250f3dedb85524 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
 
 #include <iostream>
 
-#if defined ( __LINUX__ )
-    #include <sched.h>
-    #include <unistd.h>
-    #include <sys/types.h>
-#endif //__LINUX__
-
-#if defined ( __MAC_OSX__ )
-    #include <mach/mach.h>
-    #include <mach/mach_time.h>
-    #include <mach/thread_policy.h>
-#endif //__MAC_OSX__
-
+#if defined(__LINUX__)
+#include <sched.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif  //__LINUX__
+
+#if defined(__MAC_OSX__)
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <mach/thread_policy.h>
+#include <sys/qos.h>
+#endif  //__MAC_OSX__
+
+#if defined(__WIN_32__)
+// Windows libraries that rely on the ordering of includes…
+// clang-format off
+#include <windows.h>
+#include <processthreadsapi.h>
+// clang-format on
+#endif
 #include "jacktrip_globals.h"
 
-
-#if defined ( __MAC_OSX__ )
+#if defined(__MAC_OSX__)
 
 // The following function is taken from the chromium source code
 // https://github.com/chromium/chromium/blob/master/base/threading/platform_thread_mac.mm
-// For the following macOS implementation of the function setRealtimeProcessPriority() only: Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// For the following macOS implementation of the function setRealtimeProcessPriority()
+// only: Copyright (c) 2012 The Chromium Authors. All rights reserved.
 
 // Enables time-contraint policy and priority suitable for low-latency,
 // glitch-resistant audio.
-void setRealtimeProcessPriority() {
+void setRealtimeProcessPriority(int bufferSize, int sampleRate)
+{
+    // Set thread QoS to allow maximum performance.
+    pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0);
+
     // Increase thread priority to real-time.
 
     // Please note that the thread_policy_set() calls may fail in
@@ -72,22 +84,19 @@ void setRealtimeProcessPriority() {
 
     // Make thread fixed priority.
     thread_extended_policy_data_t policy;
-    policy.timeshare = 0;  // Set to 1 for a non-fixed thread.
-    kern_return_t result =
-            thread_policy_set(mach_thread_id,
-                              THREAD_EXTENDED_POLICY,
-                              reinterpret_cast<thread_policy_t>(&policy),
-                              THREAD_EXTENDED_POLICY_COUNT);
+    policy.timeshare     = 0;  // Set to 1 for a non-fixed thread.
+    kern_return_t result = thread_policy_set(mach_thread_id, THREAD_EXTENDED_POLICY,
+                                             reinterpret_cast<thread_policy_t>(&policy),
+                                             THREAD_EXTENDED_POLICY_COUNT);
     if (result != KERN_SUCCESS) {
         std::cerr << "Failed to make thread fixed priority. " << result << std::endl;
         return;
     }
 
-    // Set to relatively high priority.
+    // Set to relatively high priority. (BASEPRI_FOREGROUND = 47)
     thread_precedence_policy_data_t precedence;
-    precedence.importance = 63;
-    result = thread_policy_set(mach_thread_id,
-                               THREAD_PRECEDENCE_POLICY,
+    precedence.importance = 52;
+    result                = thread_policy_set(mach_thread_id, THREAD_PRECEDENCE_POLICY,
                                reinterpret_cast<thread_policy_t>(&precedence),
                                THREAD_PRECEDENCE_POLICY_COUNT);
     if (result != KERN_SUCCESS) {
@@ -102,14 +111,15 @@ void setRealtimeProcessPriority() {
     // means the scheduler would give half the time to the thread.
     // These values have empirically been found to yield good behavior.
     // Good means that audio performance is high and other threads won't starve.
-    const double kGuaranteedAudioDutyCycle = 0.75;
-    const double kMaxAudioDutyCycle = 0.85;
+    // const double kGuaranteedAudioDutyCycle = 0.75;
+    const double kGuaranteedAudioDutyCycle = 0.5;
+    const double kMaxAudioDutyCycle        = 0.85;
 
     // Define constants determining how much time the audio thread can
     // use in a given time quantum.  All times are in milliseconds.
 
-    // About 128 frames @44.1KHz
-    const double kTimeQuantum = 2.9;
+    // Work out how many milliseconds we have in each buffer cycle
+    const double kTimeQuantum = 1000 * (double)bufferSize / (double)sampleRate;
 
     // Time guaranteed each quantum.
     const double kAudioTimeNeeded = kGuaranteedAudioDutyCycle * kTimeQuantum;
@@ -122,16 +132,15 @@ void setRealtimeProcessPriority() {
     mach_timebase_info_data_t tb_info;
     mach_timebase_info(&tb_info);
     double ms_to_abs_time =
-            (static_cast<double>(tb_info.denom) / tb_info.numer) * 1000000;
+        (static_cast<double>(tb_info.denom) / tb_info.numer) * 1000000;
 
     thread_time_constraint_policy_data_t time_constraints;
-    time_constraints.period = kTimeQuantum * ms_to_abs_time;
+    time_constraints.period      = kTimeQuantum * ms_to_abs_time;
     time_constraints.computation = kAudioTimeNeeded * ms_to_abs_time;
-    time_constraints.constraint = kMaxTimeAllowed * ms_to_abs_time;
+    time_constraints.constraint  = kMaxTimeAllowed * ms_to_abs_time;
     time_constraints.preemptible = 0;
 
-    result = thread_policy_set(mach_thread_id,
-                               THREAD_TIME_CONSTRAINT_POLICY,
+    result = thread_policy_set(mach_thread_id, THREAD_TIME_CONSTRAINT_POLICY,
                                reinterpret_cast<thread_policy_t>(&time_constraints),
                                THREAD_TIME_CONSTRAINT_POLICY_COUNT);
     if (result != KERN_SUCCESS)
@@ -140,38 +149,35 @@ void setRealtimeProcessPriority() {
     return;
 }
 
-#endif //__MAC_OSX__
+#endif  //__MAC_OSX__
 
-
-#if defined ( __LINUX__ )
+#if defined(__LINUX__)
 //*******************************************************************************
 void setRealtimeProcessPriority()
 {
-    int priority = sched_get_priority_max(SCHED_FIFO); // 99 is the highest possible
+    int priority = sched_get_priority_max(SCHED_FIFO);  // 99 is the highest possible
 #ifdef __UBUNTU__
-    priority = 95; // anything higher is silently ignored by Ubuntu 18.04
+    priority = 95;  // anything higher is silently ignored by Ubuntu 18.04
 #endif
     priority = 3;
 
-    struct sched_param sp = { .sched_priority = priority };
+    struct sched_param sp = {.sched_priority = priority};
 
     if (sched_setscheduler(0, SCHED_FIFO, &sp) == -1) {
-        std::cerr << "Failed to set the scheduler policy and priority." << std::endl;;
+        std::cerr << "Failed to set the scheduler policy and priority." << std::endl;
+        ;
     }
 }
-#endif //__LINUX__
-
+#endif  //__LINUX__
 
-#if defined ( __WIN_32__ )
+#if defined(__WIN_32__)
 void setRealtimeProcessPriority()
 {
-    if (SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS) == 0)
-    {
+    if (SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS) == 0) {
         std::cerr << "Failed to set process priority class." << std::endl;
     }
-    if (SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL) == 0)
-    {
+    if (SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL) == 0) {
         std::cerr << "Failed to set thread priority." << std::endl;
     }
 }
-#endif //__WIN_32__
+#endif  //__WIN_32__
index ab66d2ba0144f7b2b5105f894fbbb66463b1f311..25580457463cdd5b4c7f94683d7c33fe05b7fd94 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
 //#include "JackAudioInterface.h"
 
 /// \todo Add this namespace
-//namespace JackTrip
+// namespace JackTrip
 
-const char* const gVersion = "1.3.0"; ///< JackTrip version
+constexpr const char* const gVersion = "1.4.1";  ///< JackTrip version
 
 //*******************************************************************************
 /// \name Default Values
 //@{
-const int gDefaultNumInChannels = 2;
-const int gDefaultNumOutChannels = 2;
+constexpr int gDefaultNumInChannels  = 2;
+constexpr int gDefaultNumOutChannels = 2;
 
-#define PROTOCOL_STACK QHostAddress::AnyIPv4 // as opposed to Any
+#define PROTOCOL_STACK QHostAddress::AnyIPv4  // as opposed to Any
 // #define WAIR_AUDIO_NAME "JackTrip" // for jack connection
-const QString WAIR_AUDIO_NAME = QString("JackTrip"); // keep legacy for WAIR
-const int gMAX_WAIRS = 128; // FIXME, should agree with maxThreadCount
+constexpr const char* WAIR_AUDIO_NAME = "JackTrip";  // keep legacy for WAIR
+constexpr int gMAX_WAIRS              = 128;  // FIXME, should agree with maxThreadCount
 // jmess revision needed for string parse if > 1 digit
 
 // hubpatch = 3 for TUB ensemble patching
 ///////////////////////////////
 // test NUC as server
-//const QString gDOMAIN_TRIPLE = QString("130.149.23"); // for TUB multiclient hub
-//const int gMIN_TUB = 245; // lowest client address
-//const int gMAX_TUB = 245; // highest client address
+// const QString gDOMAIN_TRIPLE = QString("130.149.23"); // for TUB multiclient hub
+// const int gMIN_TUB = 245; // lowest client address
+// const int gMAX_TUB = 245; // highest client address
 ///////////////////////////////
 // test Riviera as server
- const QString gDOMAIN_TRIPLE = QString("192.168.0"); // for TUB multiclient hub
- const int gMIN_TUB = 11; // lowest client address
- const int gMAX_TUB = 20; // highest client address
+constexpr const char* gDOMAIN_TRIPLE = "192.168.0";  // for TUB multiclient hub
+constexpr int gMIN_TUB               = 11;           // lowest client address
+constexpr int gMAX_TUB               = 20;           // highest client address
 
-#ifdef WAIR // wair
+#ifdef WAIR  // wair
 // uses hub mode
 // hard wire the number of netrev (comb filter) channels
-  #define NUMNETREVCHANSbecauseNOTINRECEIVEDheader 16 // for jacktripworker, jmess
-  const int gDefaultNumNetRevChannels = NUMNETREVCHANSbecauseNOTINRECEIVEDheader;
-  const int gDefaultAddCombFilterLength = 0;
-  const int gDefaultCombFilterFeedback = 0;
-#endif // endwhere
+#define NUMNETREVCHANSbecauseNOTINRECEIVEDheader 16  // for jacktripworker, jmess
+constexpr int gDefaultNumNetRevChannels   = NUMNETREVCHANSbecauseNOTINRECEIVEDheader;
+constexpr int gDefaultAddCombFilterLength = 0;
+constexpr int gDefaultCombFilterFeedback  = 0;
+#endif  // endwhere
 
-//const JackAudioInterface::audioBitResolutionT gDefaultBitResolutionMode =
+// const JackAudioInterface::audioBitResolutionT gDefaultBitResolutionMode =
 //    JackAudioInterface::BIT16;
-const AudioInterface::audioBitResolutionT gDefaultBitResolutionMode =
-        AudioInterface::BIT16;
-const int gDefaultQueueLength = 4;
-const int gDefaultOutputQueueLength = 4;
-const uint32_t gDefaultSampleRate = 48000;
-const uint32_t gDefaultDeviceID = 0;
-const uint32_t gDefaultBufferSizeInSamples = 128;
-const QString gDefaultLocalAddress = QString();
-const int gDefaultRedundancy = 1;
-const int gTimeOutMultiThreadedServer = 10000; // seconds
-const int gWaitCounter = 60;
+constexpr AudioInterface::audioBitResolutionT gDefaultBitResolutionMode =
+    AudioInterface::BIT16;
+constexpr int gDefaultQueueLength              = 4;
+constexpr int gDefaultOutputQueueLength        = 4;
+constexpr uint32_t gDefaultSampleRate          = 48000;
+constexpr int gDefaultDeviceID                 = -1;
+constexpr uint32_t gDefaultBufferSizeInSamples = 128;
+constexpr const char* gDefaultLocalAddress     = "";
+constexpr int gDefaultRedundancy               = 1;
+constexpr int gTimeOutMultiThreadedServer      = 10000;  // seconds
+constexpr int gWaitCounter                     = 60;
 //@}
 
-
 //*******************************************************************************
 /// \name Network related ports
 //@{
-const int gDefaultPort = 4464; ///< Default JackTrip Port
-const int gBindPortLow = 3464; ///< lowest Bindport
-const int gBindPortHigh = 5464; ///< highest Bindport
-//const int gInputPort_0 = 4464; ///< Input base port
-//const int gOutputPort_0 = 4465; ///< Output base port
-//const int gDefaultSendPort = 4464; ///< Default for to use to send packet
+constexpr int gDefaultPort  = 4464;  ///< Default JackTrip Port
+constexpr int gBindPortLow  = 3464;  ///< lowest Bindport
+constexpr int gBindPortHigh = 5464;  ///< highest Bindport
+// const int gInputPort_0 = 4464; ///< Input base port
+// const int gOutputPort_0 = 4465; ///< Output base port
+// const int gDefaultSendPort = 4464; ///< Default for to use to send packet
 //@}
 
-
 //*******************************************************************************
 /// \name Separator for terminal printing
 //@{
-const char* const gPrintSeparator = "---------------------------------------------------------";
+constexpr const char* const gPrintSeparator =
+    "---------------------------------------------------------";
 //@}
 
-
 //*******************************************************************************
 /// \name Global flags
 //@{
-extern int gVerboseFlag; ///< Verbose mode flag declaration
+extern int gVerboseFlag;  ///< Verbose mode flag declaration
 //@}
 
-
 //*******************************************************************************
 /// \name JackAudio
 //@{
-const int gJackBitResolution = 32; ///< Audio Bit Resolution of the Jack Server
-const QString gJackDefaultClientName = "JackTrip";
-const int gMaxRemoteNameLength = 64;
+constexpr int gJackBitResolution = 32;  ///< Audio Bit Resolution of the Jack Server
+constexpr const char* gJackDefaultClientName = "JackTrip";
+constexpr int gMaxRemoteNameLength           = 64;
 //@}
 
-
 //*******************************************************************************
 /// \name Global Functions
 
+#ifdef __MAC_OSX__
+void setRealtimeProcessPriority(int bufferSize, int sampleRate);
+#else
 void setRealtimeProcessPriority();
-
+#endif
 
 //*******************************************************************************
 /// \name JackTrip Server parameters
 //@{
 /// Maximum Threads that can be run at the same time
-const int gMaxThreads = 1024;
+constexpr int gMaxThreads = 1024;
 
 /// Public well-known UDP port to where the clients will connect
-const int gServerUdpPort = 4464;
+constexpr int gServerUdpPort = 4464;
 //@}
 
-
 #endif
diff --git a/src/jacktrip_main.cpp b/src/jacktrip_main.cpp
deleted file mode 100644 (file)
index bd4ed14..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-//*****************************************************************
-/*
-  JackTrip: A System for High-Quality Audio Network Performance
-  over the Internet
-
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
-  SoundWIRE group at CCRMA, Stanford University.
-
-  Permission is hereby granted, free of charge, to any person
-  obtaining a copy of this software and associated documentation
-  files (the "Software"), to deal in the Software without
-  restriction, including without limitation the rights to use,
-  copy, modify, merge, publish, distribute, sublicense, and/or sell
-  copies of the Software, and to permit persons to whom the
-  Software is furnished to do so, subject to the following
-  conditions:
-
-  The above copyright notice and this permission notice shall be
-  included in all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-  OTHER DEALINGS IN THE SOFTWARE.
-*/
-//*****************************************************************
-
-/**
- * \file main.cpp
- * \author Juan-Pablo Caceres
- * \date June 2008
- */
-
-#include <iostream>
-
-#include <QCoreApplication>
-#include <QScopedPointer>
-#include <iostream>
-#include <signal.h>
-#include "jacktrip_globals.h"
-#include "Settings.h"
-#include "UdpHubListener.h"
-#include <QLoggingCategory>
-
-void qtMessageHandler(__attribute__((unused)) QtMsgType type, __attribute__((unused)) const QMessageLogContext &context, const QString &msg)
-{
-    std::cerr << msg.toStdString() << std::endl;
-}
-
-#if defined (__LINUX__) || (__MAC_OSX__)
-static int setupUnixSignalHandler(void (*handler)(int))
-{
-    //Setup our SIGINT handler.
-    struct sigaction sigInt;
-    sigInt.sa_handler = handler;
-    sigemptyset(&sigInt.sa_mask);
-    sigInt.sa_flags = 0;
-    sigInt.sa_flags |= SA_RESTART;
-
-    int result = 0;
-    if (sigaction(SIGINT, &sigInt, 0)) {
-        std::cout << "Unable to register SIGINT handler" << std::endl;
-        result |= 1;
-    }
-    if (sigaction(SIGTERM, &sigInt, 0)) {
-        std::cout << "Unable to register SIGTERM handler" << std::endl;
-        result |= 2;
-    }
-    return result;
-}
-#else
-bool isHubServer = false;
-
-BOOL WINAPI windowsCtrlHandler(DWORD fdwCtrlType)
-{
-    switch (fdwCtrlType) {
-        case CTRL_C_EVENT:
-            if (isHubServer) {
-                UdpHubListener::sigIntHandler(0);
-            } else {
-                JackTrip::sigIntHandler(0);
-            }
-            return true;
-        default:
-            return false;
-    }
-}
-#endif
-
-int main(int argc, char *argv[])
-{
-    QCoreApplication app(argc, argv);
-    QScopedPointer<JackTrip> jackTrip;
-    QScopedPointer<UdpHubListener> udpHub;
-    
-    QLoggingCategory::setFilterRules(QStringLiteral("*.debug=true"));
-    qInstallMessageHandler(qtMessageHandler);
-
-    try {
-        Settings settings;
-        settings.parseInput(argc, argv);
-        
-        //Either start our hub server or our jacktrip process as appropriate.
-        if (settings.isHubServer()) {
-            udpHub.reset(settings.getConfiguredHubServer());
-            if (gVerboseFlag) std::cout << "Settings:startJackTrip before udphub->start" << std::endl;
-            QObject::connect(udpHub.data(), &UdpHubListener::signalStopped, &app,
-                             &QCoreApplication::quit, Qt::QueuedConnection);
-            QObject::connect(udpHub.data(), &UdpHubListener::signalError, &app,
-                             &QCoreApplication::quit, Qt::QueuedConnection);
-#if defined (__LINUX__) || (__MAC_OSX__)
-            setupUnixSignalHandler(UdpHubListener::sigIntHandler);
-#else
-            isHubServer = true;
-            SetConsoleCtrlHandler(windowsCtrlHandler, true);
-#endif
-            udpHub->start();
-        } else {
-            jackTrip.reset(settings.getConfiguredJackTrip());
-            if (gVerboseFlag) std::cout << "Settings:startJackTrip before mJackTrip->startProcess" << std::endl;
-            QObject::connect(jackTrip.data(), &JackTrip::signalProcessesStopped, &app,
-                             &QCoreApplication::quit, Qt::QueuedConnection);
-            QObject::connect(jackTrip.data(), &JackTrip::signalError, &app,
-                             &QCoreApplication::quit, Qt::QueuedConnection);
-#if defined (__LINUX__) || (__MAC_OSX__)
-            setupUnixSignalHandler(JackTrip::sigIntHandler);
-#else
-            std::cout << SetConsoleCtrlHandler(windowsCtrlHandler, true) << std::endl;
-#endif
-#ifdef WAIRTOHUB // WAIR
-            jackTrip->startProcess(0); // for WAIR compatibility, ID in jack client name
-#else
-            jackTrip->startProcess();
-#endif // endwhere
-        }
-        
-        if (gVerboseFlag) std::cout << "step 6" << std::endl;
-        if (gVerboseFlag) std::cout << "jmain before app->exec()" << std::endl;
-    } catch (const std::exception &e) {
-        std::cerr << "ERROR:" << std::endl;
-        std::cerr << e.what() << std::endl;
-        std::cerr << "Exiting JackTrip..." << std::endl;
-        std::cerr << gPrintSeparator << std::endl;
-        return -1;
-    }
-    
-    return app.exec();
-}
diff --git a/src/jacktrip_tests.cpp b/src/jacktrip_tests.cpp
deleted file mode 100644 (file)
index e4c3d8f..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-//*****************************************************************
-/*
-  JackTrip: A System for High-Quality Audio Network Performance
-  over the Internet
-
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
-  SoundWIRE group at CCRMA, Stanford University.
-
-  Permission is hereby granted, free of charge, to any person
-  obtaining a copy of this software and associated documentation
-  files (the "Software"), to deal in the Software without
-  restriction, including without limitation the rights to use,
-  copy, modify, merge, publish, distribute, sublicense, and/or sell
-  copies of the Software, and to permit persons to whom the
-  Software is furnished to do so, subject to the following
-  conditions:
-
-  The above copyright notice and this permission notice shall be
-  included in all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-  OTHER DEALINGS IN THE SOFTWARE.
-*/
-//*****************************************************************
-
-/**
- * \file jacktrip_tests.cpp
- * \author Juan-Pablo Caceres
- * \date September 2008
- */
-
-#include <iostream>
-
-#include <QVector>
-
-#include "JackTripThread.h"
-
-using std::cout; using std::endl;
-
-const int num_jacktrips = 5;
-const int base_port = 4464;
-
-
-void main_tests(int argc, char** argv);
-void test_threads_server();
-void test_threads_client(const char* peer_address);
-
-
-void main_tests(int /*argc*/, char** argv)
-{
-    if (argv[1][0] == 's' )
-    {
-        test_threads_server();
-    }
-    else if (argv[1][0] == 'c' )
-    {
-        test_threads_client("171.64.197.209");
-    }
-}
-
-
-// Test many servers running at the same time
-void test_threads_server()
-{
-    QVector<JackTripThread*> jacktrips;
-    jacktrips.resize(num_jacktrips);
-    int port_num;
-    for (int i = 0; i < num_jacktrips; i++)
-    {
-        port_num = base_port + i*10;
-        cout << "Port Number: " << port_num << endl;
-        jacktrips[i] = new JackTripThread(JackTrip::SERVER);
-        jacktrips[i]->setPort(port_num);
-        jacktrips[i]->start(QThread::NormalPriority);
-        //sleep(1);
-    }
-}
-
-
-// Test many servers running at the same time
-void test_threads_client(const char* peer_address)
-{
-    QVector<JackTripThread*> jacktrips;
-    jacktrips.resize(num_jacktrips);
-    int port_num;
-    for (int i = 0; i < num_jacktrips; i++)
-    {
-        port_num = base_port + i*10;
-        cout << "Port Number: " << port_num << endl;
-        jacktrips[i] = new JackTripThread(JackTrip::CLIENT);
-        jacktrips[i]->setPort(port_num);
-        jacktrips[i]->setPeerAddress(peer_address);
-        //sleep(1);
-        jacktrips[i]->start(QThread::NormalPriority);
-        //sleep(1);
-    }
-}
index 31a6a6346322fa66cbfb28c34619b94181f623fb..0a8c49473f65bc8981a9e0328c7444bccb784eba 100644 (file)
@@ -3,7 +3,7 @@
   JackTrip: A System for High-Quality Audio Network Performance
   over the Internet
 
-  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
   SoundWIRE group at CCRMA, Stanford University.
 
   Permission is hereby granted, free of charge, to any person
  * \date June 2008
  */
 
-
 #ifndef __JACKTRIP_TYPES_H__
 #define __JACKTRIP_TYPES_H__
 
 //#include <jack/types.h>
-#include <QtGlobal> //For QT4 types
+#include <QtGlobal>  //For QT4 types
 
-//namespace JackTripNamespace
+// namespace JackTripNamespace
 //{
 
-  //-------------------------------------------------------------------------------
-  /** \name Audio typedefs
+//-------------------------------------------------------------------------------
+/** \name Audio typedefs
  *
  */
-  //-------------------------------------------------------------------------------
-  //@{
-  /// Audio sample type
-  //typedef jack_default_audio_sample_t sample_t;
-  typedef float sample_t;
-  //@}
-
+//-------------------------------------------------------------------------------
+//@{
+/// Audio sample type
+// typedef jack_default_audio_sample_t sample_t;
+typedef float sample_t;
+//@}
 
-  //-------------------------------------------------------------------------------
-  /** \name Typedefs that guaranty some specific bit length
+//-------------------------------------------------------------------------------
+/** \name Typedefs that guaranty some specific bit length
  *
  * It uses the QT4 types. This can be changed in the future, keeping
  * compatibility for the rest of the code.
  */
-  //-------------------------------------------------------------------------------
-  //@{
-  /// Typedef for <tt>unsigned char</tt>. This type is guaranteed to be 8-bit.
-  typedef quint8 uint8_t;
-  /// Typedef for <tt>unsigned short</tt>. This type is guaranteed to be 16-bit.
-  typedef quint16 uint16_t;
-  /// Typedef for <tt>unsigned int</tt>. This type is guaranteed to be 32-bit.
-  typedef quint32 uint32_t;
-  /// \brief Typedef for <tt>unsigned long long int</tt>. This type is guaranteed to
-  /// be 64-bit.
-  //typedef quint64 uint64_t;
-  /// Typedef for <tt>signed char</tt>. This type is guaranteed to be 8-bit.
-  typedef qint8 int8_t;
-  /// Typedef for <tt>signed short</tt>. This type is guaranteed to be 16-bit.
-  typedef qint16 int16_t;
-  /// Typedef for <tt>signed int</tt>. This type is guaranteed to be 32-bit.
-  typedef qint32 int32_t;
-  /// \brief Typedef for <tt>long long int</tt>. This type is guaranteed to
-  /// be 64-bit.
-  //typedef qint64 int64_t;
-  //@}
+//-------------------------------------------------------------------------------
+//@{
+/// Typedef for <tt>unsigned char</tt>. This type is guaranteed to be 8-bit.
+typedef quint8 uint8_t;
+/// Typedef for <tt>unsigned short</tt>. This type is guaranteed to be 16-bit.
+typedef quint16 uint16_t;
+/// Typedef for <tt>unsigned int</tt>. This type is guaranteed to be 32-bit.
+typedef quint32 uint32_t;
+/// \brief Typedef for <tt>unsigned long long int</tt>. This type is guaranteed to
+/// be 64-bit.
+// typedef quint64 uint64_t;
+/// Typedef for <tt>signed char</tt>. This type is guaranteed to be 8-bit.
+typedef qint8 int8_t;
+/// Typedef for <tt>signed short</tt>. This type is guaranteed to be 16-bit.
+typedef qint16 int16_t;
+/// Typedef for <tt>signed int</tt>. This type is guaranteed to be 32-bit.
+typedef qint32 int32_t;
+/// \brief Typedef for <tt>long long int</tt>. This type is guaranteed to
+/// be 64-bit.
+// typedef qint64 int64_t;
+//@}
 //} // end of namespace JackTripNamespace
 
 #endif
diff --git a/src/jacktrip_types_alt.h b/src/jacktrip_types_alt.h
deleted file mode 100644 (file)
index 2ce854b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-typedef float sample_t;
-typedef unsigned char uint8_t;
-typedef unsigned short int uint16_t;
-typedef unsigned int uint32_t;
-typedef signed char int8_t;
-typedef short int int16_t;
-typedef int int32_t;
index 21ab62140d18ae6f94d80545e601b219b9efa598..927b5e4dc08e8d11fe6cb6b5e1ec039d4e906196 100644 (file)
@@ -4,8 +4,8 @@ Code generated with Faust 2.28.6 (https://faust.grame.fr)
 Compilation options: -lang cpp -inpl -scal -ftz 0
 ------------------------------------------------------------ */
 
-#ifndef  __limiterdsp_H__
-#define  __limiterdsp_H__
+#ifndef __limiterdsp_H__
+#define __limiterdsp_H__
 
 // NOTE: ANY INCLUDE-GUARD HERE MUST BE DERIVED FROM THE CLASS NAME
 //
@@ -23,15 +23,15 @@ Compilation options: -lang cpp -inpl -scal -ftz 0
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -56,165 +56,177 @@ struct Meta;
  */
 
 struct dsp_memory_manager {
-    
     virtual ~dsp_memory_manager() {}
-    
+
     virtual void* allocate(size_t size) = 0;
-    virtual void destroy(void* ptr) = 0;
-    
+    virtual void destroy(void* ptr)     = 0;
 };
 
 /**
-* Signal processor definition.
-*/
-
-class dsp {
-
-    public:
-
-        dsp() {}
-        virtual ~dsp() {}
-
-        /* Return instance number of audio inputs */
-        virtual int getNumInputs() = 0;
-    
-        /* Return instance number of audio outputs */
-        virtual int getNumOutputs() = 0;
-    
-        /**
-         * Trigger the ui_interface parameter with instance specific calls
-         * to 'openTabBox', 'addButton', 'addVerticalSlider'... in order to build the UI.
-         *
-         * @param ui_interface - the user interface builder
-         */
-        virtual void buildUserInterface(UI* ui_interface) = 0;
-    
-        /* Returns the sample rate currently used by the instance */
-        virtual int getSampleRate() = 0;
-    
-        /**
-         * Global init, calls the following methods:
-         * - static class 'classInit': static tables initialization
-         * - 'instanceInit': constants and instance state initialization
-         *
-         * @param sample_rate - the sampling rate in Hertz
-         */
-        virtual void init(int sample_rate) = 0;
-
-        /**
-         * Init instance state
-         *
-         * @param sample_rate - the sampling rate in Hertz
-         */
-        virtual void instanceInit(int sample_rate) = 0;
-
-        /**
-         * Init instance constant state
-         *
-         * @param sample_rate - the sampling rate in Hertz
-         */
-        virtual void instanceConstants(int sample_rate) = 0;
-    
-        /* Init default control parameters values */
-        virtual void instanceResetUserInterface() = 0;
-    
-        /* Init instance state (delay lines...) */
-        virtual void instanceClear() = 0;
-        /**
-         * Return a clone of the instance.
-         *
-         * @return a copy of the instance on success, otherwise a null pointer.
-         */
-        virtual dsp* clone() = 0;
-    
-        /**
-         * Trigger the Meta* parameter with instance specific calls to 'declare' (key, value) metadata.
-         *
-         * @param m - the Meta* meta user
-         */
-        virtual void metadata(Meta* m) = 0;
-    
-        /**
-         * DSP instance computation, to be called with successive in/out audio buffers.
-         *
-         * @param count - the number of frames to compute
-         * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
-         * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
-         *
-         */
-        virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) = 0;
-    
-        /**
-         * DSP instance computation: alternative method to be used by subclasses.
-         *
-         * @param date_usec - the timestamp in microsec given by audio driver.
-         * @param count - the number of frames to compute
-         * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
-         * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
-         *
-         */
-        virtual void compute(double /*date_usec*/, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { compute(count, inputs, outputs); }
-       
+ * Signal processor definition.
+ */
+
+class dsp
+{
+   public:
+    dsp() {}
+    virtual ~dsp() {}
+
+    /* Return instance number of audio inputs */
+    virtual int getNumInputs() = 0;
+
+    /* Return instance number of audio outputs */
+    virtual int getNumOutputs() = 0;
+
+    /**
+     * Trigger the ui_interface parameter with instance specific calls
+     * to 'openTabBox', 'addButton', 'addVerticalSlider'... in order to build the UI.
+     *
+     * @param ui_interface - the user interface builder
+     */
+    virtual void buildUserInterface(UI* ui_interface) = 0;
+
+    /* Returns the sample rate currently used by the instance */
+    virtual int getSampleRate() = 0;
+
+    /**
+     * Global init, calls the following methods:
+     * - static class 'classInit': static tables initialization
+     * - 'instanceInit': constants and instance state initialization
+     *
+     * @param sample_rate - the sampling rate in Hertz
+     */
+    virtual void init(int sample_rate) = 0;
+
+    /**
+     * Init instance state
+     *
+     * @param sample_rate - the sampling rate in Hertz
+     */
+    virtual void instanceInit(int sample_rate) = 0;
+
+    /**
+     * Init instance constant state
+     *
+     * @param sample_rate - the sampling rate in Hertz
+     */
+    virtual void instanceConstants(int sample_rate) = 0;
+
+    /* Init default control parameters values */
+    virtual void instanceResetUserInterface() = 0;
+
+    /* Init instance state (delay lines...) */
+    virtual void instanceClear() = 0;
+
+    /**
+     * Return a clone of the instance.
+     *
+     * @return a copy of the instance on success, otherwise a null pointer.
+     */
+    virtual dsp* clone() = 0;
+
+    /**
+     * Trigger the Meta* parameter with instance specific calls to 'declare' (key, value)
+     * metadata.
+     *
+     * @param m - the Meta* meta user
+     */
+    virtual void metadata(Meta* m) = 0;
+
+    /**
+     * DSP instance computation, to be called with successive in/out audio buffers.
+     *
+     * @param count - the number of frames to compute
+     * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (eiher float, double or quad)
+     * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (eiher float, double or quad)
+     *
+     */
+    virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) = 0;
+
+    /**
+     * DSP instance computation: alternative method to be used by subclasses.
+     *
+     * @param date_usec - the timestamp in microsec given by audio driver.
+     * @param count - the number of frames to compute
+     * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (either float, double or quad)
+     * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (either float, double or quad)
+     *
+     */
+    virtual void compute(double /*date_usec*/, int count, FAUSTFLOAT** inputs,
+                         FAUSTFLOAT** outputs)
+    {
+        compute(count, inputs, outputs);
+    }
 };
 
 /**
  * Generic DSP decorator.
  */
 
-class decorator_dsp : public dsp {
-
-    protected:
-
-        dsp* fDSP;
-
-    public:
-
-        decorator_dsp(dsp* dsp = nullptr):fDSP(dsp) {}
-        virtual ~decorator_dsp() { delete fDSP; }
-
-        virtual int getNumInputs() { return fDSP->getNumInputs(); }
-        virtual int getNumOutputs() { return fDSP->getNumOutputs(); }
-        virtual void buildUserInterface(UI* ui_interface) { fDSP->buildUserInterface(ui_interface); }
-        virtual int getSampleRate() { return fDSP->getSampleRate(); }
-        virtual void init(int sample_rate) { fDSP->init(sample_rate); }
-        virtual void instanceInit(int sample_rate) { fDSP->instanceInit(sample_rate); }
-        virtual void instanceConstants(int sample_rate) { fDSP->instanceConstants(sample_rate); }
-        virtual void instanceResetUserInterface() { fDSP->instanceResetUserInterface(); }
-        virtual void instanceClear() { fDSP->instanceClear(); }
-        virtual decorator_dsp* clone() { return new decorator_dsp(fDSP->clone()); }
-        virtual void metadata(Meta* m) { fDSP->metadata(m); }
-        // Beware: subclasses usually have to overload the two 'compute' methods
-        virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(count, inputs, outputs); }
-        virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(date_usec, count, inputs, outputs); }
-    
+class decorator_dsp : public dsp
+{
+   protected:
+    dsp* fDSP;
+
+   public:
+    decorator_dsp(dsp* dsp = nullptr) : fDSP(dsp) {}
+    virtual ~decorator_dsp() { delete fDSP; }
+
+    virtual int getNumInputs() { return fDSP->getNumInputs(); }
+    virtual int getNumOutputs() { return fDSP->getNumOutputs(); }
+    virtual void buildUserInterface(UI* ui_interface)
+    {
+        fDSP->buildUserInterface(ui_interface);
+    }
+    virtual int getSampleRate() { return fDSP->getSampleRate(); }
+    virtual void init(int sample_rate) { fDSP->init(sample_rate); }
+    virtual void instanceInit(int sample_rate) { fDSP->instanceInit(sample_rate); }
+    virtual void instanceConstants(int sample_rate)
+    {
+        fDSP->instanceConstants(sample_rate);
+    }
+    virtual void instanceResetUserInterface() { fDSP->instanceResetUserInterface(); }
+    virtual void instanceClear() { fDSP->instanceClear(); }
+    virtual decorator_dsp* clone() { return new decorator_dsp(fDSP->clone()); }
+    virtual void metadata(Meta* m) { fDSP->metadata(m); }
+    // Beware: subclasses usually have to overload the two 'compute' methods
+    virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
+    {
+        fDSP->compute(count, inputs, outputs);
+    }
+    virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs,
+                         FAUSTFLOAT** outputs)
+    {
+        fDSP->compute(date_usec, count, inputs, outputs);
+    }
 };
 
 /**
  * DSP factory class.
  */
 
-class dsp_factory {
-    
-    protected:
-    
-        // So that to force sub-classes to use deleteDSPFactory(dsp_factory* factory);
-        virtual ~dsp_factory() {}
-    
-    public:
-    
-        virtual std::string getName() = 0;
-        virtual std::string getSHAKey() = 0;
-        virtual std::string getDSPCode() = 0;
-        virtual std::string getCompileOptions() = 0;
-        virtual std::vector<std::string> getLibraryList() = 0;
-        virtual std::vector<std::string> getIncludePathnames() = 0;
-    
-        virtual dsp* createDSPInstance() = 0;
-    
-        virtual void setMemoryManager(dsp_memory_manager* manager) = 0;
-        virtual dsp_memory_manager* getMemoryManager() = 0;
-    
+class dsp_factory
+{
+   protected:
+    // So that to force sub-classes to use deleteDSPFactory(dsp_factory* factory);
+    virtual ~dsp_factory() {}
+
+   public:
+    virtual std::string getName()                          = 0;
+    virtual std::string getSHAKey()                        = 0;
+    virtual std::string getDSPCode()                       = 0;
+    virtual std::string getCompileOptions()                = 0;
+    virtual std::vector<std::string> getLibraryList()      = 0;
+    virtual std::vector<std::string> getIncludePathnames() = 0;
+
+    virtual dsp* createDSPInstance() = 0;
+
+    virtual void setMemoryManager(dsp_memory_manager* manager) = 0;
+    virtual dsp_memory_manager* getMemoryManager()             = 0;
 };
 
 /**
@@ -223,14 +235,14 @@ class dsp_factory {
  */
 
 #ifdef __SSE__
-    #include <xmmintrin.h>
-    #ifdef __SSE2__
-        #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
-    #else
-        #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
-    #endif
+#include <xmmintrin.h>
+#ifdef __SSE2__
+#define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
+#else
+#define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
+#endif
 #else
-    #define AVOIDDENORMALS
+#define AVOIDDENORMALS
 #endif
 
 #endif
@@ -245,15 +257,15 @@ class dsp_factory {
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -263,11 +275,11 @@ class dsp_factory {
 #ifndef API_UI_H
 #define API_UI_H
 
+#include <iostream>
+#include <map>
 #include <sstream>
 #include <string>
 #include <vector>
-#include <iostream>
-#include <map>
 
 /************************** BEGIN meta.h **************************/
 /************************************************************************
@@ -278,15 +290,15 @@ class dsp_factory {
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -296,11 +308,9 @@ class dsp_factory {
 #ifndef __meta__
 #define __meta__
 
-struct Meta
-{
-    virtual ~Meta() {};
+struct Meta {
+    virtual ~Meta(){};
     virtual void declare(const char* key, const char* value) = 0;
-    
 };
 
 #endif
@@ -314,15 +324,15 @@ struct Meta
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -345,43 +355,47 @@ struct Meta
 
 struct Soundfile;
 
-template <typename REAL>
-struct UIReal
-{
+template<typename REAL>
+struct UIReal {
     UIReal() {}
     virtual ~UIReal() {}
-    
+
     // -- widget's layouts
-    
-    virtual void openTabBox(const char* label) = 0;
+
+    virtual void openTabBox(const char* label)        = 0;
     virtual void openHorizontalBox(const char* label) = 0;
-    virtual void openVerticalBox(const char* label) = 0;
-    virtual void closeBox() = 0;
-    
+    virtual void openVerticalBox(const char* label)   = 0;
+    virtual void closeBox()                           = 0;
+
     // -- active widgets
-    
-    virtual void addButton(const char* label, REAL* zone) = 0;
+
+    virtual void addButton(const char* label, REAL* zone)      = 0;
     virtual void addCheckButton(const char* label, REAL* zone) = 0;
-    virtual void addVerticalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
-    virtual void addHorizontalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
-    virtual void addNumEntry(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
-    
+    virtual void addVerticalSlider(const char* label, REAL* zone, REAL init, REAL min,
+                                   REAL max, REAL step)        = 0;
+    virtual void addHorizontalSlider(const char* label, REAL* zone, REAL init, REAL min,
+                                     REAL max, REAL step)      = 0;
+    virtual void addNumEntry(const char* label, REAL* zone, REAL init, REAL min, REAL max,
+                             REAL step)                        = 0;
+
     // -- passive widgets
-    
-    virtual void addHorizontalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
-    virtual void addVerticalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
-    
+
+    virtual void addHorizontalBargraph(const char* label, REAL* zone, REAL min,
+                                       REAL max) = 0;
+    virtual void addVerticalBargraph(const char* label, REAL* zone, REAL min,
+                                     REAL max)   = 0;
+
     // -- soundfiles
-    
-    virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) = 0;
-    
+
+    virtual void addSoundfile(const char* label, const char* filename,
+                              Soundfile** sf_zone) = 0;
+
     // -- metadata declarations
-    
-    virtual void declare(REAL* zone, const char* key, const char* val) {}
+
+    virtual void declare(REAL* /*zone*/, const char* /*key*/, const char* /*val*/) {}
 };
 
-struct UI : public UIReal<FAUSTFLOAT>
-{
+struct UI : public UIReal<FAUSTFLOAT> {
     UI() {}
     virtual ~UI() {}
 };
@@ -397,15 +411,15 @@ struct UI : public UIReal<FAUSTFLOAT>
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -415,9 +429,9 @@ struct UI : public UIReal<FAUSTFLOAT>
 #ifndef FAUST_PATHBUILDER_H
 #define FAUST_PATHBUILDER_H
 
-#include <vector>
-#include <string>
 #include <algorithm>
+#include <string>
+#include <vector>
 
 /*******************************************************************************
  * PathBuilder : Faust User Interface
@@ -426,37 +440,33 @@ struct UI : public UIReal<FAUSTFLOAT>
 
 class PathBuilder
 {
-
-    protected:
-    
-        std::vector<std::string> fControlsLevel;
-       
-    public:
-    
-        PathBuilder() {}
-        virtual ~PathBuilder() {}
-    
-        std::string buildPath(const std::string& label) 
-        {
-            std::string res = "/";
-            for (size_t i = 0; i < fControlsLevel.size(); i++) {
-                res += fControlsLevel[i];
-                res += "/";
-            }
-            res += label;
-            std::replace(res.begin(), res.end(), ' ', '_');
-            return res;
-        }
-    
-        std::string buildLabel(std::string label)
-        {
-            std::replace(label.begin(), label.end(), ' ', '_');
-            return label;
+   protected:
+    std::vector<std::string> fControlsLevel;
+
+   public:
+    PathBuilder() {}
+    virtual ~PathBuilder() {}
+
+    std::string buildPath(const std::string& label)
+    {
+        std::string res = "/";
+        for (size_t i = 0; i < fControlsLevel.size(); i++) {
+            res += fControlsLevel[i];
+            res += "/";
         }
-    
-        void pushLabel(const std::string& label) { fControlsLevel.push_back(label); }
-        void popLabel() { fControlsLevel.pop_back(); }
-    
+        res += label;
+        std::replace(res.begin(), res.end(), ' ', '_');
+        return res;
+    }
+
+    std::string buildLabel(std::string label)
+    {
+        std::replace(label.begin(), label.end(), ' ', '_');
+        return label;
+    }
+
+    void pushLabel(const std::string& label) { fControlsLevel.push_back(label); }
+    void popLabel() { fControlsLevel.pop_back(); }
 };
 
 #endif  // FAUST_PATHBUILDER_H
@@ -470,15 +480,15 @@ class PathBuilder
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -489,7 +499,7 @@ class PathBuilder
 #define __ValueConverter__
 
 /***************************************************************************************
-                                                               ValueConverter.h
+                                                                ValueConverter.h
                             (GRAME, Copyright 2015-2019)
 
 Set of conversion objects used to map user interface values (for example a gui slider
@@ -499,8 +509,9 @@ delivering values between 0 and 1) to faust values (for example a vslider betwee
 -- Utilities
 
 Range(lo,hi) : clip a value x between lo and hi
-Interpolator(lo,hi,v1,v2) : Maps a value x between lo and hi to a value y between v1 and v2
-Interpolator3pt(lo,mi,hi,v1,vm,v2) : Map values between lo mid hi to values between v1 vm v2
+Interpolator(lo,hi,v1,v2) : Maps a value x between lo and hi to a value y between v1 and
+v2 Interpolator3pt(lo,mi,hi,v1,vm,v2) : Map values between lo mid hi to values between v1
+vm v2
 
 -- Value Converters
 
@@ -531,11 +542,11 @@ ZoneReader(zone, valueConverter) : a zone with a data converter
 
 ****************************************************************************************/
 
-#include <float.h>
-#include <algorithm>    // std::max
+#include <algorithm>  // std::max
+#include <cassert>
+#include <cfloat>
 #include <cmath>
 #include <vector>
-#include <assert.h>
 
 //--------------------------------------------------------------------------------------
 // Interpolator(lo,hi,v1,v2)
@@ -548,50 +559,49 @@ ZoneReader(zone, valueConverter) : a zone with a data converter
 //--------------------------------------------------------------------------------------
 class Interpolator
 {
-    private:
-
-        //--------------------------------------------------------------------------------------
-        // Range(lo,hi) clip a value between lo and hi
-        //--------------------------------------------------------------------------------------
-        struct Range
-        {
-            double fLo;
-            double fHi;
-
-            Range(double x, double y) : fLo(std::min<double>(x,y)), fHi(std::max<double>(x,y)) {}
-            double operator()(double x) { return (x<fLo) ? fLo : (x>fHi) ? fHi : x; }
-        };
-
-
-        Range fRange;
-        double fCoef;
-        double fOffset;
-
-    public:
-
-        Interpolator(double lo, double hi, double v1, double v2) : fRange(lo,hi)
-        {
-            if (hi != lo) {
-                // regular case
-                fCoef = (v2-v1)/(hi-lo);
-                fOffset = v1 - lo*fCoef;
-            } else {
-                // degenerate case, avoids division by zero
-                fCoef = 0;
-                fOffset = (v1+v2)/2;
-            }
-        }
-        double operator()(double v)
+   private:
+    //--------------------------------------------------------------------------------------
+    // Range(lo,hi) clip a value between lo and hi
+    //--------------------------------------------------------------------------------------
+    struct Range {
+        double fLo;
+        double fHi;
+
+        Range(double x, double y)
+            : fLo(std::min<double>(x, y)), fHi(std::max<double>(x, y))
         {
-            double x = fRange(v);
-            return  fOffset + x*fCoef;
         }
-
-        void getLowHigh(double& amin, double& amax)
-        {
-            amin = fRange.fLo;
-            amax = fRange.fHi;
+        double operator()(double x) { return (x < fLo) ? fLo : (x > fHi) ? fHi : x; }
+    };
+
+    Range fRange;
+    double fCoef;
+    double fOffset;
+
+   public:
+    Interpolator(double lo, double hi, double v1, double v2) : fRange(lo, hi)
+    {
+        if (hi != lo) {
+            // regular case
+            fCoef   = (v2 - v1) / (hi - lo);
+            fOffset = v1 - lo * fCoef;
+        } else {
+            // degenerate case, avoids division by zero
+            fCoef   = 0;
+            fOffset = (v1 + v2) / 2;
         }
+    }
+    double operator()(double v)
+    {
+        double x = fRange(v);
+        return fOffset + x * fCoef;
+    }
+
+    void getLowHigh(double& amin, double& amax)
+    {
+        amin = fRange.fLo;
+        amax = fRange.fHi;
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -600,26 +610,23 @@ class Interpolator
 //--------------------------------------------------------------------------------------
 class Interpolator3pt
 {
-
-    private:
-
-        Interpolator fSegment1;
-        Interpolator fSegment2;
-        double fMid;
-
-    public:
-
-        Interpolator3pt(double lo, double mi, double hi, double v1, double vm, double v2) :
-            fSegment1(lo, mi, v1, vm),
-            fSegment2(mi, hi, vm, v2),
-            fMid(mi) {}
-        double operator()(double x) { return  (x < fMid) ? fSegment1(x) : fSegment2(x); }
-
-        void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fSegment1.getLowHigh(amin, amid);
-            fSegment2.getLowHigh(amid, amax);
-        }
+   private:
+    Interpolator fSegment1;
+    Interpolator fSegment2;
+    double fMid;
+
+   public:
+    Interpolator3pt(double lo, double mi, double hi, double v1, double vm, double v2)
+        : fSegment1(lo, mi, v1, vm), fSegment2(mi, hi, vm, v2), fMid(mi)
+    {
+    }
+    double operator()(double x) { return (x < fMid) ? fSegment1(x) : fSegment2(x); }
+
+    void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fSegment1.getLowHigh(amin, amid);
+        fSegment2.getLowHigh(amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -627,62 +634,51 @@ class Interpolator3pt
 //--------------------------------------------------------------------------------------
 class ValueConverter
 {
-
-    public:
-
-        virtual ~ValueConverter() {}
-        virtual double ui2faust(double x) = 0;
-        virtual double faust2ui(double x) = 0;
+   public:
+    virtual ~ValueConverter() {}
+    virtual double ui2faust(double x) = 0;
+    virtual double faust2ui(double x) = 0;
 };
 
 //--------------------------------------------------------------------------------------
 // A converter than can be updated
 //--------------------------------------------------------------------------------------
 
-class UpdatableValueConverter : public ValueConverter {
-    
-    protected:
-        
-        bool fActive;
-        
-    public:
-        
-        UpdatableValueConverter():fActive(true)
-        {}
-        virtual ~UpdatableValueConverter()
-        {}
-        
-        virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max) = 0;
-        virtual void getMappingValues(double& amin, double& amid, double& amax) = 0;
-        
-        void setActive(bool on_off) { fActive = on_off; }
-        bool getActive() { return fActive; }
-    
-};
+class UpdatableValueConverter : public ValueConverter
+{
+   protected:
+    bool fActive;
 
+   public:
+    UpdatableValueConverter() : fActive(true) {}
+    virtual ~UpdatableValueConverter() {}
+
+    virtual void setMappingValues(double amin, double amid, double amax, double min,
+                                  double init, double max)                  = 0;
+    virtual void getMappingValues(double& amin, double& amid, double& amax) = 0;
+
+    void setActive(bool on_off) { fActive = on_off; }
+    bool getActive() { return fActive; }
+};
 
 //--------------------------------------------------------------------------------------
 // Linear conversion between ui and Faust values
 //--------------------------------------------------------------------------------------
 class LinearValueConverter : public ValueConverter
 {
-    
-    private:
-        
-        Interpolator fUI2F;
-        Interpolator fF2UI;
-        
-    public:
-        
-        LinearValueConverter(double umin, double umax, double fmin, double fmax) :
-            fUI2F(umin,umax,fmin,fmax), fF2UI(fmin,fmax,umin,umax)
-        {}
-        
-        LinearValueConverter() : fUI2F(0.,0.,0.,0.), fF2UI(0.,0.,0.,0.)
-        {}
-        virtual double ui2faust(double x) { return fUI2F(x); }
-        virtual double faust2ui(double x) { return fF2UI(x); }
-    
+   private:
+    Interpolator fUI2F;
+    Interpolator fF2UI;
+
+   public:
+    LinearValueConverter(double umin, double umax, double fmin, double fmax)
+        : fUI2F(umin, umax, fmin, fmax), fF2UI(fmin, fmax, umin, umax)
+    {
+    }
+
+    LinearValueConverter() : fUI2F(0., 0., 0., 0.), fF2UI(0., 0., 0., 0.) {}
+    virtual double ui2faust(double x) { return fUI2F(x); }
+    virtual double faust2ui(double x) { return fF2UI(x); }
 };
 
 //--------------------------------------------------------------------------------------
@@ -690,35 +686,35 @@ class LinearValueConverter : public ValueConverter
 //--------------------------------------------------------------------------------------
 class LinearValueConverter2 : public UpdatableValueConverter
 {
-    
-    private:
-    
-        Interpolator3pt fUI2F;
-        Interpolator3pt fF2UI;
-        
-    public:
-    
-        LinearValueConverter2(double amin, double amid, double amax, double min, double init, double max) :
-            fUI2F(amin, amid, amax, min, init, max), fF2UI(min, init, max, amin, amid, amax)
-        {}
-        
-        LinearValueConverter2() : fUI2F(0.,0.,0.,0.,0.,0.), fF2UI(0.,0.,0.,0.,0.,0.)
-        {}
-    
-        virtual double ui2faust(double x) { return fUI2F(x); }
-        virtual double faust2ui(double x) { return fF2UI(x); }
-    
-        virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max)
-        {
-            fUI2F = Interpolator3pt(amin, amid, amax, min, init, max);
-            fF2UI = Interpolator3pt(min, init, max, amin, amid, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fUI2F.getMappingValues(amin, amid, amax);
-        }
-    
+   private:
+    Interpolator3pt fUI2F;
+    Interpolator3pt fF2UI;
+
+   public:
+    LinearValueConverter2(double amin, double amid, double amax, double min, double init,
+                          double max)
+        : fUI2F(amin, amid, amax, min, init, max), fF2UI(min, init, max, amin, amid, amax)
+    {
+    }
+
+    LinearValueConverter2() : fUI2F(0., 0., 0., 0., 0., 0.), fF2UI(0., 0., 0., 0., 0., 0.)
+    {
+    }
+
+    virtual double ui2faust(double x) { return fUI2F(x); }
+    virtual double faust2ui(double x) { return fF2UI(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double min,
+                                  double init, double max)
+    {
+        fUI2F = Interpolator3pt(amin, amid, amax, min, init, max);
+        fF2UI = Interpolator3pt(min, init, max, amin, amid, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fUI2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -726,16 +722,21 @@ class LinearValueConverter2 : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class LogValueConverter : public LinearValueConverter
 {
-
-    public:
-
-        LogValueConverter(double umin, double umax, double fmin, double fmax) :
-            LinearValueConverter(umin, umax, std::log(std::max<double>(DBL_MIN, fmin)), std::log(std::max<double>(DBL_MIN, fmax)))
-        {}
-
-        virtual double ui2faust(double x) { return std::exp(LinearValueConverter::ui2faust(x)); }
-        virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::log(std::max<double>(x, DBL_MIN))); }
-
+   public:
+    LogValueConverter(double umin, double umax, double fmin, double fmax)
+        : LinearValueConverter(umin, umax, std::log(std::max<double>(DBL_MIN, fmin)),
+                               std::log(std::max<double>(DBL_MIN, fmax)))
+    {
+    }
+
+    virtual double ui2faust(double x)
+    {
+        return std::exp(LinearValueConverter::ui2faust(x));
+    }
+    virtual double faust2ui(double x)
+    {
+        return LinearValueConverter::faust2ui(std::log(std::max<double>(x, DBL_MIN)));
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -743,16 +744,21 @@ class LogValueConverter : public LinearValueConverter
 //--------------------------------------------------------------------------------------
 class ExpValueConverter : public LinearValueConverter
 {
-
-    public:
-
-        ExpValueConverter(double umin, double umax, double fmin, double fmax) :
-            LinearValueConverter(umin, umax, std::min<double>(DBL_MAX, std::exp(fmin)), std::min<double>(DBL_MAX, std::exp(fmax)))
-        {}
-
-        virtual double ui2faust(double x) { return std::log(LinearValueConverter::ui2faust(x)); }
-        virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::min<double>(DBL_MAX, std::exp(x))); }
-
+   public:
+    ExpValueConverter(double umin, double umax, double fmin, double fmax)
+        : LinearValueConverter(umin, umax, std::min<double>(DBL_MAX, std::exp(fmin)),
+                               std::min<double>(DBL_MAX, std::exp(fmax)))
+    {
+    }
+
+    virtual double ui2faust(double x)
+    {
+        return std::log(LinearValueConverter::ui2faust(x));
+    }
+    virtual double faust2ui(double x)
+    {
+        return LinearValueConverter::faust2ui(std::min<double>(DBL_MAX, std::exp(x)));
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -761,34 +767,34 @@ class ExpValueConverter : public LinearValueConverter
 //--------------------------------------------------------------------------------------
 class AccUpConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt fA2F;
-        Interpolator3pt fF2A;
-
-    public:
-
-        AccUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmin,fmid,fmax),
-            fF2A(fmin,fmid,fmax,amin,amid,amax)
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-            //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmin, fmid, fmax);
-            fF2A = Interpolator3pt(fmin, fmid, fmax, amin, amid, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
-
+   private:
+    Interpolator3pt fA2F;
+    Interpolator3pt fF2A;
+
+   public:
+    AccUpConverter(double amin, double amid, double amax, double fmin, double fmid,
+                   double fmax)
+        : fA2F(amin, amid, amax, fmin, fmid, fmax)
+        , fF2A(fmin, fmid, fmax, amin, amid, amax)
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double fmid, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpConverter update %f %f %f
+        //%f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmin, fmid, fmax);
+        fF2A = Interpolator3pt(fmin, fmid, fmax, amin, amid, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -797,33 +803,34 @@ class AccUpConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class AccDownConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt        fA2F;
-        Interpolator3pt        fF2A;
-
-    public:
-
-        AccDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmax,fmid,fmin),
-            fF2A(fmin,fmid,fmax,amax,amid,amin)
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-             //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmax, fmid, fmin);
-            fF2A = Interpolator3pt(fmin, fmid, fmax, amax, amid, amin);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
+   private:
+    Interpolator3pt fA2F;
+    Interpolator3pt fF2A;
+
+   public:
+    AccDownConverter(double amin, double amid, double amax, double fmin, double fmid,
+                     double fmax)
+        : fA2F(amin, amid, amax, fmax, fmid, fmin)
+        , fF2A(fmin, fmid, fmax, amax, amid, amin)
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double fmid, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownConverter update %f %f
+        //%f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmax, fmid, fmin);
+        fF2A = Interpolator3pt(fmin, fmid, fmax, amax, amid, amin);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -832,33 +839,35 @@ class AccDownConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class AccUpDownConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt        fA2F;
-        Interpolator fF2A;
-
-    public:
-
-        AccUpDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmin,fmax,fmin),
-            fF2A(fmin,fmax,amin,amax)                          // Special, pseudo inverse of a non monotonic function
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-            //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmin, fmax, fmin);
-            fF2A = Interpolator(fmin, fmax, amin, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
+   private:
+    Interpolator3pt fA2F;
+    Interpolator fF2A;
+
+   public:
+    AccUpDownConverter(double amin, double amid, double amax, double fmin,
+                       double /*fmid*/, double fmax)
+        : fA2F(amin, amid, amax, fmin, fmax, fmin)
+        , fF2A(fmin, fmax, amin,
+               amax)  // Special, pseudo inverse of a non monotonic function
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double /*fmid*/, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpDownConverter update %f %f
+        //%f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmin, fmax, fmin);
+        fF2A = Interpolator(fmin, fmax, amin, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -867,33 +876,35 @@ class AccUpDownConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class AccDownUpConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt        fA2F;
-        Interpolator fF2A;
-
-    public:
-
-        AccDownUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmax,fmin,fmax),
-            fF2A(fmin,fmax,amin,amax)                          // Special, pseudo inverse of a non monotonic function
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-            //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmax, fmin, fmax);
-            fF2A = Interpolator(fmin, fmax, amin, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
+   private:
+    Interpolator3pt fA2F;
+    Interpolator fF2A;
+
+   public:
+    AccDownUpConverter(double amin, double amid, double amax, double fmin,
+                       double /*fmid*/, double fmax)
+        : fA2F(amin, amid, amax, fmax, fmin, fmax)
+        , fF2A(fmin, fmax, amin,
+               amax)  // Special, pseudo inverse of a non monotonic function
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double /*fmid*/, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownUpConverter update %f %f
+        //%f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmax, fmin, fmax);
+        fF2A = Interpolator(fmin, fmax, amin, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -901,28 +912,28 @@ class AccDownUpConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class ZoneControl
 {
+   protected:
+    FAUSTFLOAT* fZone;
 
-    protected:
-
-        FAUSTFLOAT*    fZone;
-
-    public:
-
-        ZoneControl(FAUSTFLOAT* zone) : fZone(zone) {}
-        virtual ~ZoneControl() {}
+   public:
+    ZoneControl(FAUSTFLOAT* zone) : fZone(zone) {}
+    virtual ~ZoneControl() {}
 
-        virtual void update(double v) const {}
+    virtual void update(double /*v*/) const {}
 
-        virtual void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max) {}
-        virtual void getMappingValues(double& amin, double& amid, double& amax) {}
+    virtual void setMappingValues(int /*curve*/, double /*amin*/, double /*amid*/,
+                                  double /*amax*/, double /*min*/, double /*init*/,
+                                  double /*max*/)
+    {
+    }
+    virtual void getMappingValues(double& /*amin*/, double& /*amid*/, double& /*amax*/) {}
 
-        FAUSTFLOAT* getZone() { return fZone; }
+    FAUSTFLOAT* getZone() { return fZone; }
 
-        virtual void setActive(bool on_off) {}
-        virtual bool getActive() { return false; }
-
-        virtual int getCurve() { return -1; }
+    virtual void setActive(bool /*on_off*/) {}
+    virtual bool getActive() { return false; }
 
+    virtual int getCurve() { return -1; }
 };
 
 //--------------------------------------------------------------------------------------
@@ -930,20 +941,22 @@ class ZoneControl
 //--------------------------------------------------------------------------------------
 class ConverterZoneControl : public ZoneControl
 {
-
-    protected:
-
-        ValueConverter* fValueConverter;
-
-    public:
-
-        ConverterZoneControl(FAUSTFLOAT* zone, ValueConverter* converter) : ZoneControl(zone), fValueConverter(converter) {}
-        virtual ~ConverterZoneControl() { delete fValueConverter; } // Assuming fValueConverter is not kept elsewhere...
-
-        virtual void update(double v) const { *fZone = fValueConverter->ui2faust(v); }
-
-        ValueConverter* getConverter() { return fValueConverter; }
-
+   protected:
+    ValueConverter* fValueConverter;
+
+   public:
+    ConverterZoneControl(FAUSTFLOAT* zone, ValueConverter* converter)
+        : ZoneControl(zone), fValueConverter(converter)
+    {
+    }
+    virtual ~ConverterZoneControl()
+    {
+        delete fValueConverter;
+    }  // Assuming fValueConverter is not kept elsewhere...
+
+    virtual void update(double v) const { *fZone = fValueConverter->ui2faust(v); }
+
+    ValueConverter* getConverter() { return fValueConverter; }
 };
 
 //--------------------------------------------------------------------------------------
@@ -952,592 +965,613 @@ class ConverterZoneControl : public ZoneControl
 //--------------------------------------------------------------------------------------
 class CurveZoneControl : public ZoneControl
 {
-
-    private:
-
-        std::vector<UpdatableValueConverter*> fValueConverters;
-        int fCurve;
-
-    public:
-
-        CurveZoneControl(FAUSTFLOAT* zone, int curve, double amin, double amid, double amax, double min, double init, double max) : ZoneControl(zone), fCurve(0)
-        {
-            assert(curve >= 0 && curve <= 3);
-            fValueConverters.push_back(new AccUpConverter(amin, amid, amax, min, init, max));
-            fValueConverters.push_back(new AccDownConverter(amin, amid, amax, min, init, max));
-            fValueConverters.push_back(new AccUpDownConverter(amin, amid, amax, min, init, max));
-            fValueConverters.push_back(new AccDownUpConverter(amin, amid, amax, min, init, max));
-            fCurve = curve;
-        }
-        virtual ~CurveZoneControl()
-        {
-            std::vector<UpdatableValueConverter*>::iterator it;
-            for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
-                delete(*it);
-            }
-        }
-        void update(double v) const { if (fValueConverters[fCurve]->getActive()) *fZone = fValueConverters[fCurve]->ui2faust(v); }
-
-        void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max)
-        {
-            fValueConverters[curve]->setMappingValues(amin, amid, amax, min, init, max);
-            fCurve = curve;
-        }
-
-        void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fValueConverters[fCurve]->getMappingValues(amin, amid, amax);
+   private:
+    std::vector<UpdatableValueConverter*> fValueConverters;
+    int fCurve;
+
+   public:
+    CurveZoneControl(FAUSTFLOAT* zone, int curve, double amin, double amid, double amax,
+                     double min, double init, double max)
+        : ZoneControl(zone), fCurve(0)
+    {
+        assert(curve >= 0 && curve <= 3);
+        fValueConverters.push_back(new AccUpConverter(amin, amid, amax, min, init, max));
+        fValueConverters.push_back(
+            new AccDownConverter(amin, amid, amax, min, init, max));
+        fValueConverters.push_back(
+            new AccUpDownConverter(amin, amid, amax, min, init, max));
+        fValueConverters.push_back(
+            new AccDownUpConverter(amin, amid, amax, min, init, max));
+        fCurve = curve;
+    }
+    virtual ~CurveZoneControl()
+    {
+        std::vector<UpdatableValueConverter*>::iterator it;
+        for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+            delete (*it);
         }
-
-        void setActive(bool on_off)
-        {
-            std::vector<UpdatableValueConverter*>::iterator it;
-            for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
-                (*it)->setActive(on_off);
-            }
+    }
+    void update(double v) const
+    {
+        if (fValueConverters[fCurve]->getActive())
+            *fZone = fValueConverters[fCurve]->ui2faust(v);
+    }
+
+    void setMappingValues(int curve, double amin, double amid, double amax, double min,
+                          double init, double max)
+    {
+        fValueConverters[curve]->setMappingValues(amin, amid, amax, min, init, max);
+        fCurve = curve;
+    }
+
+    void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fValueConverters[fCurve]->getMappingValues(amin, amid, amax);
+    }
+
+    void setActive(bool on_off)
+    {
+        std::vector<UpdatableValueConverter*>::iterator it;
+        for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+            (*it)->setActive(on_off);
         }
+    }
 
-        int getCurve() { return fCurve; }
+    int getCurve() { return fCurve; }
 };
 
 class ZoneReader
 {
+   private:
+    FAUSTFLOAT* fZone;
+    Interpolator fInterpolator;
 
-    private:
+   public:
+    ZoneReader(FAUSTFLOAT* zone, double lo, double hi)
+        : fZone(zone), fInterpolator(lo, hi, 0, 255)
+    {
+    }
 
-        FAUSTFLOAT* fZone;
-        Interpolator fInterpolator;
-
-    public:
-
-        ZoneReader(FAUSTFLOAT* zone, double lo, double hi) : fZone(zone), fInterpolator(lo, hi, 0, 255) {}
-
-        virtual ~ZoneReader() {}
-
-        int getValue()
-        {
-            return (fZone != nullptr) ? int(fInterpolator(*fZone)) : 127;
-        }
+    virtual ~ZoneReader() {}
 
+    int getValue() { return (fZone != nullptr) ? int(fInterpolator(*fZone)) : 127; }
 };
 
 #endif
 /**************************  END  ValueConverter.h **************************/
 
-class APIUI : public PathBuilder, public Meta, public UI
+class APIUI
+    : public PathBuilder
+    , public Meta
+    , public UI
 {
-    public:
-    
-        enum ItemType { kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph };
-  
-    protected:
-    
-        enum { kLin = 0, kLog = 1, kExp = 2 };
-    
-        int fNumParameters;
-        std::vector<std::string> fPaths;
-        std::vector<std::string> fLabels;
-        std::map<std::string, int> fPathMap;
-        std::map<std::string, int> fLabelMap;
-        std::vector<ValueConverter*> fConversion;
-        std::vector<FAUSTFLOAT*> fZone;
-        std::vector<FAUSTFLOAT> fInit;
-        std::vector<FAUSTFLOAT> fMin;
-        std::vector<FAUSTFLOAT> fMax;
-        std::vector<FAUSTFLOAT> fStep;
-        std::vector<ItemType> fItemType;
-        std::vector<std::map<std::string, std::string> > fMetaData;
-        std::vector<ZoneControl*> fAcc[3];
-        std::vector<ZoneControl*> fGyr[3];
-
-        // Screen color control
-        // "...[screencolor:red]..." etc.
-        bool fHasScreenControl;      // true if control screen color metadata
-        ZoneReader* fRedReader;
-        ZoneReader* fGreenReader;
-        ZoneReader* fBlueReader;
-
-        // Current values controlled by metadata
-        std::string fCurrentUnit;
-        int fCurrentScale;
-        std::string fCurrentAcc;
-        std::string fCurrentGyr;
-        std::string fCurrentColor;
-        std::string fCurrentTooltip;
-        std::map<std::string, std::string> fCurrentMetadata;
-    
-        // Add a generic parameter
-        virtual void addParameter(const char* label,
-                                FAUSTFLOAT* zone,
-                                FAUSTFLOAT init,
-                                FAUSTFLOAT min,
-                                FAUSTFLOAT max,
-                                FAUSTFLOAT step,
-                                ItemType type)
-        {
-            std::string path = buildPath(label);
-            fPathMap[path] = fLabelMap[label] = fNumParameters++;
-            fPaths.push_back(path);
-            fLabels.push_back(label);
-            fZone.push_back(zone);
-            fInit.push_back(init);
-            fMin.push_back(min);
-            fMax.push_back(max);
-            fStep.push_back(step);
-            fItemType.push_back(type);
-            
-            // handle scale metadata
-            switch (fCurrentScale) {
-                case kLin:
-                    fConversion.push_back(new LinearValueConverter(0, 1, min, max));
-                    break;
-                case kLog:
-                    fConversion.push_back(new LogValueConverter(0, 1, min, max));
-                    break;
-                case kExp: fConversion.push_back(new ExpValueConverter(0, 1, min, max));
-                    break;
-            }
-            fCurrentScale = kLin;
-            
-            if (fCurrentAcc.size() > 0 && fCurrentGyr.size() > 0) {
-                std::cerr << "warning : 'acc' and 'gyr' metadata used for the same " << label << " parameter !!\n";
-            }
+   public:
+    enum ItemType {
+        kButton = 0,
+        kCheckButton,
+        kVSlider,
+        kHSlider,
+        kNumEntry,
+        kHBargraph,
+        kVBargraph
+    };
+
+   protected:
+    enum { kLin = 0, kLog = 1, kExp = 2 };
+
+    int fNumParameters;
+    std::vector<std::string> fPaths;
+    std::vector<std::string> fLabels;
+    std::map<std::string, int> fPathMap;
+    std::map<std::string, int> fLabelMap;
+    std::vector<ValueConverter*> fConversion;
+    std::vector<FAUSTFLOAT*> fZone;
+    std::vector<FAUSTFLOAT> fInit;
+    std::vector<FAUSTFLOAT> fMin;
+    std::vector<FAUSTFLOAT> fMax;
+    std::vector<FAUSTFLOAT> fStep;
+    std::vector<ItemType> fItemType;
+    std::vector<std::map<std::string, std::string> > fMetaData;
+    std::vector<ZoneControl*> fAcc[3];
+    std::vector<ZoneControl*> fGyr[3];
+
+    // Screen color control
+    // "...[screencolor:red]..." etc.
+    bool fHasScreenControl;  // true if control screen color metadata
+    ZoneReader* fRedReader;
+    ZoneReader* fGreenReader;
+    ZoneReader* fBlueReader;
+
+    // Current values controlled by metadata
+    std::string fCurrentUnit;
+    int fCurrentScale;
+    std::string fCurrentAcc;
+    std::string fCurrentGyr;
+    std::string fCurrentColor;
+    std::string fCurrentTooltip;
+    std::map<std::string, std::string> fCurrentMetadata;
+
+    // Add a generic parameter
+    virtual void addParameter(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                              FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step,
+                              ItemType type)
+    {
+        std::string path = buildPath(label);
+        fPathMap[path] = fLabelMap[label] = fNumParameters++;
+        fPaths.push_back(path);
+        fLabels.push_back(label);
+        fZone.push_back(zone);
+        fInit.push_back(init);
+        fMin.push_back(min);
+        fMax.push_back(max);
+        fStep.push_back(step);
+        fItemType.push_back(type);
+
+        // handle scale metadata
+        switch (fCurrentScale) {
+        case kLin:
+            fConversion.push_back(new LinearValueConverter(0, 1, min, max));
+            break;
+        case kLog:
+            fConversion.push_back(new LogValueConverter(0, 1, min, max));
+            break;
+        case kExp:
+            fConversion.push_back(new ExpValueConverter(0, 1, min, max));
+            break;
+        }
+        fCurrentScale = kLin;
 
-            // handle acc metadata "...[acc : <axe> <curve> <amin> <amid> <amax>]..."
-            if (fCurrentAcc.size() > 0) {
-                std::istringstream iss(fCurrentAcc);
-                int axe, curve;
-                double amin, amid, amax;
-                iss >> axe >> curve >> amin >> amid >> amax;
-
-                if ((0 <= axe) && (axe < 3) &&
-                    (0 <= curve) && (curve < 4) &&
-                    (amin < amax) && (amin <= amid) && (amid <= amax))
-                {
-                    fAcc[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
-                } else {
-                    std::cerr << "incorrect acc metadata : " << fCurrentAcc << std::endl;
-                }
-                fCurrentAcc = "";
-            }
-       
-            // handle gyr metadata "...[gyr : <axe> <curve> <amin> <amid> <amax>]..."
-            if (fCurrentGyr.size() > 0) {
-                std::istringstream iss(fCurrentGyr);
-                int axe, curve;
-                double amin, amid, amax;
-                iss >> axe >> curve >> amin >> amid >> amax;
-
-                if ((0 <= axe) && (axe < 3) &&
-                    (0 <= curve) && (curve < 4) &&
-                    (amin < amax) && (amin <= amid) && (amid <= amax))
-                {
-                    fGyr[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
-                } else {
-                    std::cerr << "incorrect gyr metadata : " << fCurrentGyr << std::endl;
-                }
-                fCurrentGyr = "";
-            }
-        
-            // handle screencolor metadata "...[screencolor:red|green|blue|white]..."
-            if (fCurrentColor.size() > 0) {
-                if ((fCurrentColor == "red") && (fRedReader == 0)) {
-                    fRedReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else if ((fCurrentColor == "green") && (fGreenReader == 0)) {
-                    fGreenReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else if ((fCurrentColor == "blue") && (fBlueReader == 0)) {
-                    fBlueReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else if ((fCurrentColor == "white") && (fRedReader == 0) && (fGreenReader == 0) && (fBlueReader == 0)) {
-                    fRedReader = new ZoneReader(zone, min, max);
-                    fGreenReader = new ZoneReader(zone, min, max);
-                    fBlueReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else {
-                    std::cerr << "incorrect screencolor metadata : " << fCurrentColor << std::endl;
-                }
-            }
-            fCurrentColor = "";
-            
-            fMetaData.push_back(fCurrentMetadata);
-            fCurrentMetadata.clear();
+        if (fCurrentAcc.size() > 0 && fCurrentGyr.size() > 0) {
+            std::cerr << "warning : 'acc' and 'gyr' metadata used for the same " << label
+                      << " parameter !!\n";
         }
 
-        int getZoneIndex(std::vector<ZoneControl*>* table, int p, int val)
-        {
-            FAUSTFLOAT* zone = fZone[p];
-            for (size_t i = 0; i < table[val].size(); i++) {
-                if (zone == table[val][i]->getZone()) return int(i);
+        // handle acc metadata "...[acc : <axe> <curve> <amin> <amid> <amax>]..."
+        if (fCurrentAcc.size() > 0) {
+            std::istringstream iss(fCurrentAcc);
+            int axe, curve;
+            double amin, amid, amax;
+            iss >> axe >> curve >> amin >> amid >> amax;
+
+            if ((0 <= axe) && (axe < 3) && (0 <= curve) && (curve < 4) && (amin < amax)
+                && (amin <= amid) && (amid <= amax)) {
+                fAcc[axe].push_back(
+                    new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
+            } else {
+                std::cerr << "incorrect acc metadata : " << fCurrentAcc << std::endl;
             }
-            return -1;
+            fCurrentAcc = "";
         }
-    
-        void setConverter(std::vector<ZoneControl*>* table, int p, int val, int curve, double amin, double amid, double amax)
-        {
-            int id1 = getZoneIndex(table, p, 0);
-            int id2 = getZoneIndex(table, p, 1);
-            int id3 = getZoneIndex(table, p, 2);
-            
-            // Deactivates everywhere..
-            if (id1 != -1) table[0][id1]->setActive(false);
-            if (id2 != -1) table[1][id2]->setActive(false);
-            if (id3 != -1) table[2][id3]->setActive(false);
-            
-            if (val == -1) { // Means: no more mapping...
-                // So stay all deactivated...
+
+        // handle gyr metadata "...[gyr : <axe> <curve> <amin> <amid> <amax>]..."
+        if (fCurrentGyr.size() > 0) {
+            std::istringstream iss(fCurrentGyr);
+            int axe, curve;
+            double amin, amid, amax;
+            iss >> axe >> curve >> amin >> amid >> amax;
+
+            if ((0 <= axe) && (axe < 3) && (0 <= curve) && (curve < 4) && (amin < amax)
+                && (amin <= amid) && (amid <= amax)) {
+                fGyr[axe].push_back(
+                    new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
             } else {
-                int id4 = getZoneIndex(table, p, val);
-                if (id4 != -1) {
-                    // Reactivate the one we edit...
-                    table[val][id4]->setMappingValues(curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]);
-                    table[val][id4]->setActive(true);
-                } else {
-                    // Allocate a new CurveZoneControl which is 'active' by default
-                    FAUSTFLOAT* zone = fZone[p];
-                    table[val].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]));
-                }
+                std::cerr << "incorrect gyr metadata : " << fCurrentGyr << std::endl;
             }
+            fCurrentGyr = "";
         }
-    
-        void getConverter(std::vector<ZoneControl*>* table, int p, int& val, int& curve, double& amin, double& amid, double& amax)
-        {
-            int id1 = getZoneIndex(table, p, 0);
-            int id2 = getZoneIndex(table, p, 1);
-            int id3 = getZoneIndex(table, p, 2);
-            
-            if (id1 != -1) {
-                val = 0;
-                curve = table[val][id1]->getCurve();
-                table[val][id1]->getMappingValues(amin, amid, amax);
-            } else if (id2 != -1) {
-                val = 1;
-                curve = table[val][id2]->getCurve();
-                table[val][id2]->getMappingValues(amin, amid, amax);
-            } else if (id3 != -1) {
-                val = 2;
-                curve = table[val][id3]->getCurve();
-                table[val][id3]->getMappingValues(amin, amid, amax);
+
+        // handle screencolor metadata "...[screencolor:red|green|blue|white]..."
+        if (fCurrentColor.size() > 0) {
+            if ((fCurrentColor == "red") && (fRedReader == 0)) {
+                fRedReader        = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
+            } else if ((fCurrentColor == "green") && (fGreenReader == 0)) {
+                fGreenReader      = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
+            } else if ((fCurrentColor == "blue") && (fBlueReader == 0)) {
+                fBlueReader       = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
+            } else if ((fCurrentColor == "white") && (fRedReader == 0)
+                       && (fGreenReader == 0) && (fBlueReader == 0)) {
+                fRedReader        = new ZoneReader(zone, min, max);
+                fGreenReader      = new ZoneReader(zone, min, max);
+                fBlueReader       = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
             } else {
-                val = -1; // No mapping
-                curve = 0;
-                amin = -100.;
-                amid = 0.;
-                amax = 100.;
+                std::cerr << "incorrect screencolor metadata : " << fCurrentColor
+                          << std::endl;
             }
         }
+        fCurrentColor = "";
 
-     public:
-    
-        enum Type { kAcc = 0, kGyr = 1, kNoType };
-   
-        APIUI() : fNumParameters(0), fHasScreenControl(false), fRedReader(0), fGreenReader(0), fBlueReader(0), fCurrentScale(kLin)
-        {}
+        fMetaData.push_back(fCurrentMetadata);
+        fCurrentMetadata.clear();
+    }
 
-        virtual ~APIUI()
-        {
-            for (auto& it : fConversion) delete it;
-            for (int i = 0; i < 3; i++) {
-                for (auto& it : fAcc[i]) delete it;
-                for (auto& it : fGyr[i]) delete it;
+    int getZoneIndex(std::vector<ZoneControl*>* table, int p, int val)
+    {
+        FAUSTFLOAT* zone = fZone[p];
+        for (size_t i = 0; i < table[val].size(); i++) {
+            if (zone == table[val][i]->getZone()) return int(i);
+        }
+        return -1;
+    }
+
+    void setConverter(std::vector<ZoneControl*>* table, int p, int val, int curve,
+                      double amin, double amid, double amax)
+    {
+        int id1 = getZoneIndex(table, p, 0);
+        int id2 = getZoneIndex(table, p, 1);
+        int id3 = getZoneIndex(table, p, 2);
+
+        // Deactivates everywhere..
+        if (id1 != -1) table[0][id1]->setActive(false);
+        if (id2 != -1) table[1][id2]->setActive(false);
+        if (id3 != -1) table[2][id3]->setActive(false);
+
+        if (val == -1) {  // Means: no more mapping...
+            // So stay all deactivated...
+        } else {
+            int id4 = getZoneIndex(table, p, val);
+            if (id4 != -1) {
+                // Reactivate the one we edit...
+                table[val][id4]->setMappingValues(curve, amin, amid, amax, fMin[p],
+                                                  fInit[p], fMax[p]);
+                table[val][id4]->setActive(true);
+            } else {
+                // Allocate a new CurveZoneControl which is 'active' by default
+                FAUSTFLOAT* zone = fZone[p];
+                table[val].push_back(new CurveZoneControl(zone, curve, amin, amid, amax,
+                                                          fMin[p], fInit[p], fMax[p]));
             }
-            delete fRedReader;
-            delete fGreenReader;
-            delete fBlueReader;
         }
-    
-        // -- widget's layouts
-
-        virtual void openTabBox(const char* label) { pushLabel(label); }
-        virtual void openHorizontalBox(const char* label) { pushLabel(label); }
-        virtual void openVerticalBox(const char* label) { pushLabel(label); }
-        virtual void closeBox() { popLabel(); }
-
-        // -- active widgets
-
-        virtual void addButton(const char* label, FAUSTFLOAT* zone)
-        {
-            addParameter(label, zone, 0, 0, 1, 1, kButton);
+    }
+
+    void getConverter(std::vector<ZoneControl*>* table, int p, int& val, int& curve,
+                      double& amin, double& amid, double& amax)
+    {
+        int id1 = getZoneIndex(table, p, 0);
+        int id2 = getZoneIndex(table, p, 1);
+        int id3 = getZoneIndex(table, p, 2);
+
+        if (id1 != -1) {
+            val   = 0;
+            curve = table[val][id1]->getCurve();
+            table[val][id1]->getMappingValues(amin, amid, amax);
+        } else if (id2 != -1) {
+            val   = 1;
+            curve = table[val][id2]->getCurve();
+            table[val][id2]->getMappingValues(amin, amid, amax);
+        } else if (id3 != -1) {
+            val   = 2;
+            curve = table[val][id3]->getCurve();
+            table[val][id3]->getMappingValues(amin, amid, amax);
+        } else {
+            val   = -1;  // No mapping
+            curve = 0;
+            amin  = -100.;
+            amid  = 0.;
+            amax  = 100.;
         }
-
-        virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
-        {
-            addParameter(label, zone, 0, 0, 1, 1, kCheckButton);
+    }
+
+   public:
+    enum Type { kAcc = 0, kGyr = 1, kNoType };
+
+    APIUI()
+        : fNumParameters(0)
+        , fHasScreenControl(false)
+        , fRedReader(0)
+        , fGreenReader(0)
+        , fBlueReader(0)
+        , fCurrentScale(kLin)
+    {
+    }
+
+    virtual ~APIUI()
+    {
+        for (auto& it : fConversion) delete it;
+        for (int i = 0; i < 3; i++) {
+            for (auto& it : fAcc[i]) delete it;
+            for (auto& it : fGyr[i]) delete it;
         }
+        delete fRedReader;
+        delete fGreenReader;
+        delete fBlueReader;
+    }
 
-        virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
-        {
-            addParameter(label, zone, init, min, max, step, kVSlider);
-        }
+    // -- widget's layouts
 
-        virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
-        {
-            addParameter(label, zone, init, min, max, step, kHSlider);
-        }
+    virtual void openTabBox(const char* label) { pushLabel(label); }
+    virtual void openHorizontalBox(const char* label) { pushLabel(label); }
+    virtual void openVerticalBox(const char* label) { pushLabel(label); }
+    virtual void closeBox() { popLabel(); }
 
-        virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
-        {
-            addParameter(label, zone, init, min, max, step, kNumEntry);
-        }
+    // -- active widgets
 
-        // -- passive widgets
+    virtual void addButton(const char* label, FAUSTFLOAT* zone)
+    {
+        addParameter(label, zone, 0, 0, 1, 1, kButton);
+    }
+
+    virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
+    {
+        addParameter(label, zone, 0, 0, 1, 1, kCheckButton);
+    }
+
+    virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                                   FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+    {
+        addParameter(label, zone, init, min, max, step, kVSlider);
+    }
+
+    virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                                     FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+    {
+        addParameter(label, zone, init, min, max, step, kHSlider);
+    }
+
+    virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                             FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+    {
+        addParameter(label, zone, init, min, max, step, kNumEntry);
+    }
 
-        virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
-        {
-            addParameter(label, zone, min, min, max, (max-min)/1000.0, kHBargraph);
-        }
+    // -- passive widgets
 
-        virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
-        {
-            addParameter(label, zone, min, min, max, (max-min)/1000.0, kVBargraph);
-        }
-    
-        // -- soundfiles
-    
-        virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) {}
+    virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone,
+                                       FAUSTFLOAT min, FAUSTFLOAT max)
+    {
+        addParameter(label, zone, min, min, max, (max - min) / 1000.0, kHBargraph);
+    }
 
-        // -- metadata declarations
+    virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min,
+                                     FAUSTFLOAT max)
+    {
+        addParameter(label, zone, min, min, max, (max - min) / 1000.0, kVBargraph);
+    }
 
-        virtual void declare(FAUSTFLOAT* zone, const char* key, const char* val)
-        {
-            // Keep metadata
-            fCurrentMetadata[key] = val;
-            
-            if (strcmp(key, "scale") == 0) {
-                if (strcmp(val, "log") == 0) {
-                    fCurrentScale = kLog;
-                } else if (strcmp(val, "exp") == 0) {
-                    fCurrentScale = kExp;
-                } else {
-                    fCurrentScale = kLin;
-                }
-            } else if (strcmp(key, "unit") == 0) {
-                fCurrentUnit = val;
-            } else if (strcmp(key, "acc") == 0) {
-                fCurrentAcc = val;
-            } else if (strcmp(key, "gyr") == 0) {
-                fCurrentGyr = val;
-            } else if (strcmp(key, "screencolor") == 0) {
-                fCurrentColor = val; // val = "red", "green", "blue" or "white"
-            } else if (strcmp(key, "tooltip") == 0) {
-                fCurrentTooltip = val;
-            }
-        }
+    // -- soundfiles
 
-        virtual void declare(const char* key, const char* val)
-        {}
+    virtual void addSoundfile(const char* /*label*/, const char* /*filename*/,
+                              Soundfile** /*sf_zone*/)
+    {
+    }
 
-               //-------------------------------------------------------------------------------
-               // Simple API part
-               //-------------------------------------------------------------------------------
-               int getParamsCount() { return fNumParameters; }
-        int getParamIndex(const char* path)
-        {
-            if (fPathMap.find(path) != fPathMap.end()) {
-                return fPathMap[path];
-            } else if (fLabelMap.find(path) != fLabelMap.end()) {
-                return fLabelMap[path];
-            } else {
-                return -1;
-            }
-        }
-        const char* getParamAddress(int p) { return fPaths[p].c_str(); }
-        const char* getParamLabel(int p) { return fLabels[p].c_str(); }
-        std::map<const char*, const char*> getMetadata(int p)
-        {
-            std::map<const char*, const char*> res;
-            std::map<std::string, std::string> metadata = fMetaData[p];
-            for (auto it : metadata) {
-                res[it.first.c_str()] = it.second.c_str();
-            }
-            return res;
-        }
+    // -- metadata declarations
 
-        const char* getMetadata(int p, const char* key)
-        {
-            return (fMetaData[p].find(key) != fMetaData[p].end()) ? fMetaData[p][key].c_str() : "";
-        }
-        FAUSTFLOAT getParamMin(int p) { return fMin[p]; }
-        FAUSTFLOAT getParamMax(int p) { return fMax[p]; }
-        FAUSTFLOAT getParamStep(int p) { return fStep[p]; }
-        FAUSTFLOAT getParamInit(int p) { return fInit[p]; }
-
-        FAUSTFLOAT* getParamZone(int p) { return fZone[p]; }
-        FAUSTFLOAT getParamValue(int p) { return *fZone[p]; }
-        void setParamValue(int p, FAUSTFLOAT v) { *fZone[p] = v; }
-
-        double getParamRatio(int p) { return fConversion[p]->faust2ui(*fZone[p]); }
-        void setParamRatio(int p, double r) { *fZone[p] = fConversion[p]->ui2faust(r); }
-
-        double value2ratio(int p, double r)    { return fConversion[p]->faust2ui(r); }
-        double ratio2value(int p, double r)    { return fConversion[p]->ui2faust(r); }
-    
-        /**
-         * Return the control type (kAcc, kGyr, or -1) for a given parameter
-         *
-         * @param p - the UI parameter index
-         *
-         * @return the type
-         */
-        Type getParamType(int p)
-        {
-            if (p >= 0) {
-                if (getZoneIndex(fAcc, p, 0) != -1
-                    || getZoneIndex(fAcc, p, 1) != -1
-                    || getZoneIndex(fAcc, p, 2) != -1) {
-                    return kAcc;
-                } else if (getZoneIndex(fGyr, p, 0) != -1
-                           || getZoneIndex(fGyr, p, 1) != -1
-                           || getZoneIndex(fGyr, p, 2) != -1) {
-                    return kGyr;
-                }
-            }
-            return kNoType;
-        }
-    
-        /**
-         * Return the Item type (kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph) for a given parameter
-         *
-         * @param p - the UI parameter index
-         *
-         * @return the Item type
-         */
-        ItemType getParamItemType(int p)
-        {
-            return fItemType[p];
-        }
-   
-        /**
-         * Set a new value coming from an accelerometer, propagate it to all relevant FAUSTFLOAT* zones.
-         *
-         * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
-         * @param value - the new value
-         *
-         */
-        void propagateAcc(int acc, double value)
-        {
-            for (size_t i = 0; i < fAcc[acc].size(); i++) {
-                fAcc[acc][i]->update(value);
-            }
-        }
-    
-        /**
-         * Used to edit accelerometer curves and mapping. Set curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer (-1 means "no mapping")
-         * @param curve - between 0 and 3
-         * @param amin - mapping 'min' point
-         * @param amid - mapping 'middle' point
-         * @param amax - mapping 'max' point
-         *
-         */
-        void setAccConverter(int p, int acc, int curve, double amin, double amid, double amax)
-        {
-            setConverter(fAcc, p, acc, curve, amin, amid, amax);
-        }
-    
-        /**
-         * Used to edit gyroscope curves and mapping. Set curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param acc - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope (-1 means "no mapping")
-         * @param curve - between 0 and 3
-         * @param amin - mapping 'min' point
-         * @param amid - mapping 'middle' point
-         * @param amax - mapping 'max' point
-         *
-         */
-        void setGyrConverter(int p, int gyr, int curve, double amin, double amid, double amax)
-        {
-             setConverter(fGyr, p, gyr, curve, amin, amid, amax);
-        }
-    
-        /**
-         * Used to edit accelerometer curves and mapping. Get curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param acc - the acc value to be retrieved (-1 means "no mapping")
-         * @param curve - the curve value to be retrieved
-         * @param amin - the amin value to be retrieved
-         * @param amid - the amid value to be retrieved
-         * @param amax - the amax value to be retrieved
-         *
-         */
-        void getAccConverter(int p, int& acc, int& curve, double& amin, double& amid, double& amax)
-        {
-            getConverter(fAcc, p, acc, curve, amin, amid, amax);
-        }
+    virtual void declare(FAUSTFLOAT* /*zone*/, const char* key, const char* val)
+    {
+        // Keep metadata
+        fCurrentMetadata[key] = val;
 
-        /**
-         * Used to edit gyroscope curves and mapping. Get curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param gyr - the gyr value to be retrieved (-1 means "no mapping")
-         * @param curve - the curve value to be retrieved
-         * @param amin - the amin value to be retrieved
-         * @param amid - the amid value to be retrieved
-         * @param amax - the amax value to be retrieved
-         *
-         */
-        void getGyrConverter(int p, int& gyr, int& curve, double& amin, double& amid, double& amax)
-        {
-            getConverter(fGyr, p, gyr, curve, amin, amid, amax);
-        }
-    
-        /**
-         * Set a new value coming from an gyroscope, propagate it to all relevant FAUSTFLOAT* zones.
-         *
-         * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
-         * @param value - the new value
-         *
-         */
-        void propagateGyr(int gyr, double value)
-        {
-            for (size_t i = 0; i < fGyr[gyr].size(); i++) {
-                fGyr[gyr][i]->update(value);
+        if (strcmp(key, "scale") == 0) {
+            if (strcmp(val, "log") == 0) {
+                fCurrentScale = kLog;
+            } else if (strcmp(val, "exp") == 0) {
+                fCurrentScale = kExp;
+            } else {
+                fCurrentScale = kLin;
             }
+        } else if (strcmp(key, "unit") == 0) {
+            fCurrentUnit = val;
+        } else if (strcmp(key, "acc") == 0) {
+            fCurrentAcc = val;
+        } else if (strcmp(key, "gyr") == 0) {
+            fCurrentGyr = val;
+        } else if (strcmp(key, "screencolor") == 0) {
+            fCurrentColor = val;  // val = "red", "green", "blue" or "white"
+        } else if (strcmp(key, "tooltip") == 0) {
+            fCurrentTooltip = val;
         }
-    
-        /**
-         * Get the number of FAUSTFLOAT* zones controlled with the accelerometer
-         *
-         * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
-         * @return the number of zones
-         *
-         */
-        int getAccCount(int acc)
-        {
-            return (acc >= 0 && acc < 3) ? int(fAcc[acc].size()) : 0;
-        }
-    
-        /**
-         * Get the number of FAUSTFLOAT* zones controlled with the gyroscope
-         *
-         * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
-         * @param the number of zones
-         *
-         */
-        int getGyrCount(int gyr)
-        {
-            return (gyr >= 0 && gyr < 3) ? int(fGyr[gyr].size()) : 0;
+    }
+
+    virtual void declare(const char* /*key*/, const char* /*val*/) {}
+
+    //-------------------------------------------------------------------------------
+    // Simple API part
+    //-------------------------------------------------------------------------------
+    int getParamsCount() { return fNumParameters; }
+    int getParamIndex(const char* path)
+    {
+        if (fPathMap.find(path) != fPathMap.end()) {
+            return fPathMap[path];
+        } else if (fLabelMap.find(path) != fLabelMap.end()) {
+            return fLabelMap[path];
+        } else {
+            return -1;
         }
-   
-        // getScreenColor() : -1 means no screen color control (no screencolor metadata found)
-        // otherwise return 0x00RRGGBB a ready to use color
-        int getScreenColor()
-        {
-            if (fHasScreenControl) {
-                int r = (fRedReader) ? fRedReader->getValue() : 0;
-                int g = (fGreenReader) ? fGreenReader->getValue() : 0;
-                int b = (fBlueReader) ? fBlueReader->getValue() : 0;
-                return (r<<16) | (g<<8) | b;
-            } else {
-                return -1;
+    }
+    const char* getParamAddress(int p) { return fPaths[p].c_str(); }
+    const char* getParamLabel(int p) { return fLabels[p].c_str(); }
+    std::map<const char*, const char*> getMetadata(int p)
+    {
+        std::map<const char*, const char*> res;
+        std::map<std::string, std::string> metadata = fMetaData[p];
+        for (const auto& it : metadata) { res[it.first.c_str()] = it.second.c_str(); }
+        return res;
+    }
+
+    const char* getMetadata(int p, const char* key)
+    {
+        return (fMetaData[p].find(key) != fMetaData[p].end()) ? fMetaData[p][key].c_str()
+                                                              : "";
+    }
+    FAUSTFLOAT getParamMin(int p) { return fMin[p]; }
+    FAUSTFLOAT getParamMax(int p) { return fMax[p]; }
+    FAUSTFLOAT getParamStep(int p) { return fStep[p]; }
+    FAUSTFLOAT getParamInit(int p) { return fInit[p]; }
+
+    FAUSTFLOAT* getParamZone(int p) { return fZone[p]; }
+    FAUSTFLOAT getParamValue(int p) { return *fZone[p]; }
+    void setParamValue(int p, FAUSTFLOAT v) { *fZone[p] = v; }
+
+    double getParamRatio(int p) { return fConversion[p]->faust2ui(*fZone[p]); }
+    void setParamRatio(int p, double r) { *fZone[p] = fConversion[p]->ui2faust(r); }
+
+    double value2ratio(int p, double r) { return fConversion[p]->faust2ui(r); }
+    double ratio2value(int p, double r) { return fConversion[p]->ui2faust(r); }
+
+    /**
+     * Return the control type (kAcc, kGyr, or -1) for a given parameter
+     *
+     * @param p - the UI parameter index
+     *
+     * @return the type
+     */
+    Type getParamType(int p)
+    {
+        if (p >= 0) {
+            if (getZoneIndex(fAcc, p, 0) != -1 || getZoneIndex(fAcc, p, 1) != -1
+                || getZoneIndex(fAcc, p, 2) != -1) {
+                return kAcc;
+            } else if (getZoneIndex(fGyr, p, 0) != -1 || getZoneIndex(fGyr, p, 1) != -1
+                       || getZoneIndex(fGyr, p, 2) != -1) {
+                return kGyr;
             }
         }
+        return kNoType;
+    }
+
+    /**
+     * Return the Item type (kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry,
+     * kHBargraph, kVBargraph) for a given parameter
+     *
+     * @param p - the UI parameter index
+     *
+     * @return the Item type
+     */
+    ItemType getParamItemType(int p) { return fItemType[p]; }
+
+    /**
+     * Set a new value coming from an accelerometer, propagate it to all relevant
+     * FAUSTFLOAT* zones.
+     *
+     * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+     * @param value - the new value
+     *
+     */
+    void propagateAcc(int acc, double value)
+    {
+        for (size_t i = 0; i < fAcc[acc].size(); i++) { fAcc[acc][i]->update(value); }
+    }
+
+    /**
+     * Used to edit accelerometer curves and mapping. Set curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+     * (-1 means "no mapping")
+     * @param curve - between 0 and 3
+     * @param amin - mapping 'min' point
+     * @param amid - mapping 'middle' point
+     * @param amax - mapping 'max' point
+     *
+     */
+    void setAccConverter(int p, int acc, int curve, double amin, double amid, double amax)
+    {
+        setConverter(fAcc, p, acc, curve, amin, amid, amax);
+    }
+
+    /**
+     * Used to edit gyroscope curves and mapping. Set curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param acc - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope (-1 means "no
+     * mapping")
+     * @param curve - between 0 and 3
+     * @param amin - mapping 'min' point
+     * @param amid - mapping 'middle' point
+     * @param amax - mapping 'max' point
+     *
+     */
+    void setGyrConverter(int p, int gyr, int curve, double amin, double amid, double amax)
+    {
+        setConverter(fGyr, p, gyr, curve, amin, amid, amax);
+    }
+
+    /**
+     * Used to edit accelerometer curves and mapping. Get curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param acc - the acc value to be retrieved (-1 means "no mapping")
+     * @param curve - the curve value to be retrieved
+     * @param amin - the amin value to be retrieved
+     * @param amid - the amid value to be retrieved
+     * @param amax - the amax value to be retrieved
+     *
+     */
+    void getAccConverter(int p, int& acc, int& curve, double& amin, double& amid,
+                         double& amax)
+    {
+        getConverter(fAcc, p, acc, curve, amin, amid, amax);
+    }
+
+    /**
+     * Used to edit gyroscope curves and mapping. Get curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param gyr - the gyr value to be retrieved (-1 means "no mapping")
+     * @param curve - the curve value to be retrieved
+     * @param amin - the amin value to be retrieved
+     * @param amid - the amid value to be retrieved
+     * @param amax - the amax value to be retrieved
+     *
+     */
+    void getGyrConverter(int p, int& gyr, int& curve, double& amin, double& amid,
+                         double& amax)
+    {
+        getConverter(fGyr, p, gyr, curve, amin, amid, amax);
+    }
+
+    /**
+     * Set a new value coming from an gyroscope, propagate it to all relevant FAUSTFLOAT*
+     * zones.
+     *
+     * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+     * @param value - the new value
+     *
+     */
+    void propagateGyr(int gyr, double value)
+    {
+        for (size_t i = 0; i < fGyr[gyr].size(); i++) { fGyr[gyr][i]->update(value); }
+    }
+
+    /**
+     * Get the number of FAUSTFLOAT* zones controlled with the accelerometer
+     *
+     * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+     * @return the number of zones
+     *
+     */
+    int getAccCount(int acc) { return (acc >= 0 && acc < 3) ? int(fAcc[acc].size()) : 0; }
+
+    /**
+     * Get the number of FAUSTFLOAT* zones controlled with the gyroscope
+     *
+     * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+     * @param the number of zones
+     *
+     */
+    int getGyrCount(int gyr) { return (gyr >= 0 && gyr < 3) ? int(fGyr[gyr].size()) : 0; }
+
+    // getScreenColor() : -1 means no screen color control (no screencolor metadata found)
+    // otherwise return 0x00RRGGBB a ready to use color
+    int getScreenColor()
+    {
+        if (fHasScreenControl) {
+            int r = (fRedReader) ? fRedReader->getValue() : 0;
+            int g = (fGreenReader) ? fGreenReader->getValue() : 0;
+            int b = (fBlueReader) ? fBlueReader->getValue() : 0;
+            return (r << 16) | (g << 8) | b;
+        } else {
+            return -1;
+        }
+    }
 };
 
 #endif
@@ -1550,202 +1584,191 @@ class APIUI : public PathBuilder, public Meta, public UI
 //  FAUST Generated Code
 //----------------------------------------------------------------------------
 
-
 #ifndef FAUSTFLOAT
 #define FAUSTFLOAT float
-#endif 
+#endif
 
 #include <algorithm>
 #include <cmath>
-#include <math.h>
 
-
-#ifndef FAUSTCLASS 
+#ifndef FAUSTCLASS
 #define FAUSTCLASS limiterdsp
 #endif
 
-#ifdef __APPLE__ 
+#ifdef __APPLE__
 #define exp10f __exp10f
-#define exp10 __exp10
+#define exp10  __exp10
 #endif
 
-class limiterdsp : public dsp {
-       
- private:
-       
-       int fSampleRate;
-       float fConst0;
-       float fConst1;
-       float fConst2;
-       float fConst3;
-       int iRec5[2];
-       FAUSTFLOAT fHslider0;
-       int IOTA;
-       float fVec0[32];
-       float fRec4[2];
-       int iRec2[2];
-       float fRec1[2];
-       float fConst4;
-       float fConst5;
-       float fRec0[2];
-       int iConst6;
-       
- public:
-       
-       void metadata(Meta* m) { 
-               m->declare("analyzers.lib/name", "Faust Analyzer Library");
-               m->declare("analyzers.lib/version", "0.1");
-               m->declare("basics.lib/name", "Faust Basic Element Library");
-               m->declare("basics.lib/version", "0.1");
-               m->declare("compressors.lib/limiter_lad_N:author", "Dario Sanfilippo");
-               m->declare("compressors.lib/limiter_lad_N:copyright", "Copyright (C) 2020 Dario Sanfilippo       <sanfilippo.dario@gmail.com>");
-               m->declare("compressors.lib/limiter_lad_N:license", "GPLv3 license");
-               m->declare("compressors.lib/limiter_lad_mono:author", "Dario Sanfilippo");
-               m->declare("compressors.lib/limiter_lad_mono:copyright", "Copyright (C) 2020 Dario Sanfilippo       <sanfilippo.dario@gmail.com>");
-               m->declare("compressors.lib/limiter_lad_mono:license", "GPLv3 license");
-               m->declare("compressors.lib/name", "Faust Compressor Effect Library");
-               m->declare("compressors.lib/version", "0.0");
-               m->declare("filename", "limiterdsp.dsp");
-               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.3");
-               m->declare("name", "limiterdsp");
-               m->declare("platform.lib/name", "Generic Platform Library");
-               m->declare("platform.lib/version", "0.1");
-               m->declare("routes.lib/name", "Faust Signal Routing Library");
-               m->declare("routes.lib/version", "0.2");
-               m->declare("signals.lib/name", "Faust Signal Routing Library");
-               m->declare("signals.lib/version", "0.0");
-       }
-
-       virtual int getNumInputs() {
-               return 1;
-       }
-       virtual int getNumOutputs() {
-               return 1;
-       }
-       virtual int getInputRate(int channel) {
-               int rate;
-               switch ((channel)) {
-                       case 0: {
-                               rate = 1;
-                               break;
-                       }
-                       default: {
-                               rate = -1;
-                               break;
-                       }
-               }
-               return rate;
-       }
-       virtual int getOutputRate(int channel) {
-               int rate;
-               switch ((channel)) {
-                       case 0: {
-                               rate = 1;
-                               break;
-                       }
-                       default: {
-                               rate = -1;
-                               break;
-                       }
-               }
-               return rate;
-       }
-       
-       static void classInit(int sample_rate) {
-       }
-       
-       virtual void instanceConstants(int sample_rate) {
-               fSampleRate = sample_rate;
-               fConst0 = std::min<float>(192000.0f, std::max<float>(1.0f, float(fSampleRate)));
-               fConst1 = std::exp((0.0f - (100000.0f / fConst0)));
-               fConst2 = (1.0f - fConst1);
-               fConst3 = (0.100000001f * fConst0);
-               fConst4 = std::exp((0.0f - (4.0f / fConst0)));
-               fConst5 = (1.0f - fConst4);
-               iConst6 = int((9.99999975e-05f * fConst0));
-       }
-       
-       virtual void instanceResetUserInterface() {
-               fHslider0 = FAUSTFLOAT(2.0f);
-       }
-       
-       virtual void instanceClear() {
-               for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) {
-                       iRec5[l0] = 0;
-               }
-               IOTA = 0;
-               for (int l1 = 0; (l1 < 32); l1 = (l1 + 1)) {
-                       fVec0[l1] = 0.0f;
-               }
-               for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) {
-                       fRec4[l2] = 0.0f;
-               }
-               for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) {
-                       iRec2[l3] = 0;
-               }
-               for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) {
-                       fRec1[l4] = 0.0f;
-               }
-               for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) {
-                       fRec0[l5] = 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 limiterdsp* clone() {
-               return new limiterdsp();
-       }
-       
-       virtual int getSampleRate() {
-               return fSampleRate;
-       }
-       
-       virtual void buildUserInterface(UI* ui_interface) {
-               ui_interface->openVerticalBox("limiterdsp");
-               ui_interface->declare(&fHslider0, "0", "");
-               ui_interface->addHorizontalSlider("NumClientsAssumed", &fHslider0, 2.0f, 1.0f, 64.0f, 1.0f);
-               ui_interface->closeBox();
-       }
-       
-       virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
-               FAUSTFLOAT* input0 = inputs[0];
-               FAUSTFLOAT* output0 = outputs[0];
-               float fSlow0 = (1.0f / std::sqrt(float(fHslider0)));
-               for (int i = 0; (i < count); i = (i + 1)) {
-                       float fTemp0 = float(input0[i]);
-                       iRec5[0] = ((iRec5[1] + 1) % int(std::max<float>(1.0f, (fConst3 * float(iRec2[1])))));
-                       float fTemp1 = (fSlow0 * fTemp0);
-                       fVec0[(IOTA & 31)] = fTemp1;
-                       float fTemp2 = std::fabs(fTemp1);
-                       fRec4[0] = std::max<float>((float((iRec5[0] > 0)) * fRec4[1]), fTemp2);
-                       iRec2[0] = (fRec4[0] >= fTemp2);
-                       float fRec3 = fRec4[0];
-                       fRec1[0] = ((fConst1 * fRec1[1]) + (fConst2 * fRec3));
-                       float fTemp3 = std::fabs(fRec1[0]);
-                       fRec0[0] = std::max<float>(fTemp3, ((fConst4 * fRec0[1]) + (fConst5 * fTemp3)));
-                       output0[i] = FAUSTFLOAT((std::min<float>(1.0f, (0.5f / std::max<float>(fRec0[0], 1.1920929e-07f))) * fVec0[((IOTA - iConst6) & 31)]));
-                       iRec5[1] = iRec5[0];
-                       IOTA = (IOTA + 1);
-                       fRec4[1] = fRec4[0];
-                       iRec2[1] = iRec2[0];
-                       fRec1[1] = fRec1[0];
-                       fRec0[1] = fRec0[0];
-               }
-       }
-
+class limiterdsp : public dsp
+{
+   private:
+    int fSampleRate;
+    float fConst0;
+    float fConst1;
+    float fConst2;
+    float fConst3;
+    int iRec5[2];
+    FAUSTFLOAT fHslider0;
+    int IOTA;
+    float fVec0[32];
+    float fRec4[2];
+    int iRec2[2];
+    float fRec1[2];
+    float fConst4;
+    float fConst5;
+    float fRec0[2];
+    int iConst6;
+
+   public:
+    void metadata(Meta* m)
+    {
+        m->declare("analyzers.lib/name", "Faust Analyzer Library");
+        m->declare("analyzers.lib/version", "0.1");
+        m->declare("basics.lib/name", "Faust Basic Element Library");
+        m->declare("basics.lib/version", "0.1");
+        m->declare("compressors.lib/limiter_lad_N:author", "Dario Sanfilippo");
+        m->declare(
+            "compressors.lib/limiter_lad_N:copyright",
+            "Copyright (C) 2020 Dario Sanfilippo       <sanfilippo.dario@gmail.com>");
+        m->declare("compressors.lib/limiter_lad_N:license", "GPLv3 license");
+        m->declare("compressors.lib/limiter_lad_mono:author", "Dario Sanfilippo");
+        m->declare(
+            "compressors.lib/limiter_lad_mono:copyright",
+            "Copyright (C) 2020 Dario Sanfilippo       <sanfilippo.dario@gmail.com>");
+        m->declare("compressors.lib/limiter_lad_mono:license", "GPLv3 license");
+        m->declare("compressors.lib/name", "Faust Compressor Effect Library");
+        m->declare("compressors.lib/version", "0.0");
+        m->declare("filename", "limiterdsp.dsp");
+        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.3");
+        m->declare("name", "limiterdsp");
+        m->declare("platform.lib/name", "Generic Platform Library");
+        m->declare("platform.lib/version", "0.1");
+        m->declare("routes.lib/name", "Faust Signal Routing Library");
+        m->declare("routes.lib/version", "0.2");
+        m->declare("signals.lib/name", "Faust Signal Routing Library");
+        m->declare("signals.lib/version", "0.0");
+    }
+
+    virtual int getNumInputs() { return 1; }
+    virtual int getNumOutputs() { return 1; }
+    virtual int getInputRate(int channel)
+    {
+        int rate;
+        switch ((channel)) {
+        case 0: {
+            rate = 1;
+            break;
+        }
+        default: {
+            rate = -1;
+            break;
+        }
+        }
+        return rate;
+    }
+    virtual int getOutputRate(int channel)
+    {
+        int rate;
+        switch ((channel)) {
+        case 0: {
+            rate = 1;
+            break;
+        }
+        default: {
+            rate = -1;
+            break;
+        }
+        }
+        return rate;
+    }
+
+    static void classInit(int /*sample_rate*/) {}
+
+    virtual void instanceConstants(int sample_rate)
+    {
+        fSampleRate = sample_rate;
+        fConst0 = std::min<float>(192000.0f, std::max<float>(1.0f, float(fSampleRate)));
+        fConst1 = std::exp((0.0f - (100000.0f / fConst0)));
+        fConst2 = (1.0f - fConst1);
+        fConst3 = (0.100000001f * fConst0);
+        fConst4 = std::exp((0.0f - (4.0f / fConst0)));
+        fConst5 = (1.0f - fConst4);
+        iConst6 = int((9.99999975e-05f * fConst0));
+    }
+
+    virtual void instanceResetUserInterface() { fHslider0 = FAUSTFLOAT(2.0f); }
+
+    virtual void instanceClear()
+    {
+        for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { iRec5[l0] = 0; }
+        IOTA = 0;
+        for (int l1 = 0; (l1 < 32); l1 = (l1 + 1)) { fVec0[l1] = 0.0f; }
+        for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) { fRec4[l2] = 0.0f; }
+        for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) { iRec2[l3] = 0; }
+        for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) { fRec1[l4] = 0.0f; }
+        for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) { fRec0[l5] = 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 limiterdsp* clone() { return new limiterdsp(); }
+
+    virtual int getSampleRate() { return fSampleRate; }
+
+    virtual void buildUserInterface(UI* ui_interface)
+    {
+        ui_interface->openVerticalBox("limiterdsp");
+        ui_interface->declare(&fHslider0, "0", "");
+        ui_interface->addHorizontalSlider("NumClientsAssumed", &fHslider0, 2.0f, 1.0f,
+                                          64.0f, 1.0f);
+        ui_interface->closeBox();
+    }
+
+    virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
+    {
+        FAUSTFLOAT* input0  = inputs[0];
+        FAUSTFLOAT* output0 = outputs[0];
+        float fSlow0        = (1.0f / std::sqrt(float(fHslider0)));
+        for (int i = 0; (i < count); i = (i + 1)) {
+            float fTemp0       = float(input0[i]);
+            iRec5[0]           = ((iRec5[1] + 1)
+                        % int(std::max<float>(1.0f, (fConst3 * float(iRec2[1])))));
+            float fTemp1       = (fSlow0 * fTemp0);
+            fVec0[(IOTA & 31)] = fTemp1;
+            float fTemp2       = std::fabs(fTemp1);
+            fRec4[0]     = std::max<float>((float((iRec5[0] > 0)) * fRec4[1]), fTemp2);
+            iRec2[0]     = (fRec4[0] >= fTemp2);
+            float fRec3  = fRec4[0];
+            fRec1[0]     = ((fConst1 * fRec1[1]) + (fConst2 * fRec3));
+            float fTemp3 = std::fabs(fRec1[0]);
+            fRec0[0] =
+                std::max<float>(fTemp3, ((fConst4 * fRec0[1]) + (fConst5 * fTemp3)));
+            output0[i] = FAUSTFLOAT(
+                (std::min<float>(1.0f, (0.5f / std::max<float>(fRec0[0], 1.1920929e-07f)))
+                 * fVec0[((IOTA - iConst6) & 31)]));
+            iRec5[1] = iRec5[0];
+            IOTA     = (IOTA + 1);
+            fRec4[1] = fRec4[0];
+            iRec2[1] = iRec2[0];
+            fRec1[1] = fRec1[0];
+            fRec0[1] = fRec0[0];
+        }
+    }
 };
 
 #endif
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644 (file)
index 0000000..9939ca3
--- /dev/null
@@ -0,0 +1,242 @@
+//*****************************************************************
+/*
+  JackTrip: A System for High-Quality Audio Network Performance
+  over the Internet
+
+  Copyright (c) 2008-2021 Juan-Pablo Caceres, Chris Chafe.
+  SoundWIRE group at CCRMA, Stanford University.
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation
+  files (the "Software"), to deal in the Software without
+  restriction, including without limitation the rights to use,
+  copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the
+  Software is furnished to do so, subject to the following
+  conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+  OTHER DEALINGS IN THE SOFTWARE.
+*/
+//*****************************************************************
+
+/**
+ * \file main.cpp
+ * \author Aaron Wyatt, based on jacktrip_main by Juan-Pablo Caceres
+ * \date July 2020
+ */
+
+#ifndef NO_GUI
+#include <QApplication>
+
+#include "gui/qjacktrip.h"
+#else
+#include <QCoreApplication>
+#endif
+#include <QLoggingCategory>
+#include <QScopedPointer>
+#include <csignal>
+#include <iostream>
+
+#include "Settings.h"
+#include "UdpHubListener.h"
+#include "jacktrip_globals.h"
+
+QCoreApplication* createApplication(int& argc, char* argv[])
+{
+    // Check for some specific, GUI related command line options.
+    bool forceGui = false;
+    for (int i = 1; i < argc; i++) {
+        if (strcmp(argv[i], "--gui") == 0) {
+            forceGui = true;
+        } else if (strcmp(argv[i], "--test-gui") == 0) {
+            // Command line option to test if the binary has been built with GUI support.
+            // Exits immediately. Exits with an error if GUI support has not been built
+            // in.
+#ifdef NO_GUI
+            std::cout << "This version of JackTrip has been built without GUI support."
+                      << std::endl;
+            std::cout << "(To run JackTrip normally, please omit the --test-gui option.)"
+                      << std::endl;
+            std::exit(1);
+#else
+            std::cout << "This version of JackTrip has been built with GUI support."
+                      << std::endl;
+            std::cout << "(To run JackTrip normally, please omit the --test-gui option.)"
+                      << std::endl;
+            std::exit(0);
+#endif
+        }
+    }
+
+    // If we have command line arguments and aren't forcing the GUI run on the command
+    // line.
+    if (argc == 1 || forceGui) {
+#ifdef NO_GUI
+        if (forceGui) {
+            std::cout << "This version of jacktrip has not been built with GUI support."
+                      << std::endl;
+            std::exit(1);
+        } else {
+            return new QCoreApplication(argc, argv);
+        }
+#else
+#ifdef __LINUX__
+        // Check if X or Wayland environment variables are set.
+        if (std::getenv("WAYLAND_DISPLAY") == nullptr
+            && std::getenv("DISPLAY") == nullptr) {
+            std::cout << "ERROR: Display not found. Make sure X or Wayland is running or "
+                         "try running jacktrip in command line mode."
+                      << std::endl;
+            std::cout << "(To display a list of command line options run \"jacktrip -h\")"
+                      << std::endl;
+            std::exit(1);
+        }
+#endif  // __LINUX__
+        return new QApplication(argc, argv);
+#endif  // NO_GUI
+    } else {
+        return new QCoreApplication(argc, argv);
+    }
+}
+
+void qtMessageHandler([[maybe_unused]] QtMsgType type,
+                      [[maybe_unused]] const QMessageLogContext& context,
+                      const QString& msg)
+{
+    std::cerr << msg.toStdString() << std::endl;
+}
+
+#if defined(__LINUX__) || defined(__MAC_OSX__)
+static int setupUnixSignalHandler(void (*handler)(int))
+{
+    // Setup our SIGINT handler.
+    struct sigaction sigInt;
+    sigInt.sa_handler = handler;
+    sigemptyset(&sigInt.sa_mask);
+    sigInt.sa_flags = 0;
+    sigInt.sa_flags |= SA_RESTART;
+
+    int result = 0;
+    if (sigaction(SIGINT, &sigInt, 0)) {
+        std::cout << "Unable to register SIGINT handler" << std::endl;
+        result |= 1;
+    }
+    if (sigaction(SIGTERM, &sigInt, 0)) {
+        std::cout << "Unable to register SIGTERM handler" << std::endl;
+        result |= 2;
+    }
+    return result;
+}
+#else
+bool isHubServer = false;
+
+BOOL WINAPI windowsCtrlHandler(DWORD fdwCtrlType)
+{
+    switch (fdwCtrlType) {
+    case CTRL_C_EVENT:
+        if (isHubServer) {
+            UdpHubListener::sigIntHandler(0);
+        } else {
+            JackTrip::sigIntHandler(0);
+        }
+        return true;
+    default:
+        return false;
+    }
+}
+#endif
+
+int main(int argc, char* argv[])
+{
+    QScopedPointer<QCoreApplication> app(createApplication(argc, argv));
+    QScopedPointer<JackTrip> jackTrip;
+    QScopedPointer<UdpHubListener> udpHub;
+#ifndef NO_GUI
+    QScopedPointer<QJackTrip> window;
+    if (qobject_cast<QApplication*>(app.data())) {
+        // Start the GUI if there are no command line options.
+#ifdef __WIN_32__
+        // Remove the console that appears if we're in windows.
+        FreeConsole();
+#endif  // __WIN_32__
+        app->setApplicationName("QJackTrip");
+        window.reset(new QJackTrip);
+        window->setArgc(argc);
+        QObject::connect(window.data(), &QJackTrip::signalExit, app.data(),
+                         &QCoreApplication::quit, Qt::QueuedConnection);
+        window->show();
+    } else {
+#endif  // NO_GUI
+        // Otherwise use the non-GUI version, and parse our command line.
+        QLoggingCategory::setFilterRules(QStringLiteral("*.debug=true"));
+        qInstallMessageHandler(qtMessageHandler);
+        try {
+            Settings settings;
+            settings.parseInput(argc, argv);
+
+            // Either start our hub server or our jacktrip process as appropriate.
+            if (settings.isHubServer()) {
+                udpHub.reset(settings.getConfiguredHubServer());
+                if (gVerboseFlag)
+                    std::cout << "Settings:startJackTrip before udphub->start"
+                              << std::endl;
+                QObject::connect(udpHub.data(), &UdpHubListener::signalStopped,
+                                 app.data(), &QCoreApplication::quit,
+                                 Qt::QueuedConnection);
+                QObject::connect(udpHub.data(), &UdpHubListener::signalError, app.data(),
+                                 &QCoreApplication::quit, Qt::QueuedConnection);
+#if defined(__LINUX__) || defined(__MAC_OSX__)
+                setupUnixSignalHandler(UdpHubListener::sigIntHandler);
+#else
+            isHubServer = true;
+            SetConsoleCtrlHandler(windowsCtrlHandler, true);
+#endif
+                udpHub->start();
+            } else {
+                jackTrip.reset(settings.getConfiguredJackTrip());
+                if (gVerboseFlag)
+                    std::cout << "Settings:startJackTrip before mJackTrip->startProcess"
+                              << std::endl;
+                QObject::connect(jackTrip.data(), &JackTrip::signalProcessesStopped,
+                                 app.data(), &QCoreApplication::quit,
+                                 Qt::QueuedConnection);
+                QObject::connect(jackTrip.data(), &JackTrip::signalError, app.data(),
+                                 &QCoreApplication::quit, Qt::QueuedConnection);
+#if defined(__LINUX__) || defined(__MAC_OSX__)
+                setupUnixSignalHandler(JackTrip::sigIntHandler);
+#else
+            std::cout << SetConsoleCtrlHandler(windowsCtrlHandler, true) << std::endl;
+#endif
+#ifdef WAIRTOHUB  // WAIR
+                jackTrip->startProcess(
+                    0);  // for WAIR compatibility, ID in jack client name
+#else
+            jackTrip->startProcess();
+#endif  // endwhere
+            }
+
+            if (gVerboseFlag) std::cout << "step 6" << std::endl;
+            if (gVerboseFlag) std::cout << "jmain before app->exec()" << std::endl;
+        } catch (const std::exception& e) {
+            std::cerr << "ERROR:" << std::endl;
+            std::cerr << e.what() << std::endl;
+            std::cerr << "Exiting JackTrip..." << std::endl;
+            std::cerr << gPrintSeparator << std::endl;
+            return -1;
+        }
+#ifndef NO_GUI
+    }
+#endif  // NO_GUI
+
+    return app->exec();
+}
index c1dcf3171068fd099008e0e5d2d46a84657a4730..461de41d2dca821e5f36eead95fab0f9ee300bfd 100755 (executable)
@@ -1 +1 @@
-qmake -spec macx-xcode jacktrip.pro
+qmake -spec macx-xcode ../jacktrip.pro
index 96067d423d3ba7991ec2f7c562af74c072d8a3cf..47a648e3cb8259af401898c7b994fbad12ad5525 100644 (file)
@@ -4,8 +4,8 @@ Code generated with Faust 2.28.6 (https://faust.grame.fr)
 Compilation options: -lang cpp -inpl -scal -ftz 0
 ------------------------------------------------------------ */
 
-#ifndef  __zitarevdsp_H__
-#define  __zitarevdsp_H__
+#ifndef __zitarevdsp_H__
+#define __zitarevdsp_H__
 
 // NOTE: ANY INCLUDE-GUARD HERE MUST BE DERIVED FROM THE CLASS NAME
 //
@@ -23,15 +23,15 @@ Compilation options: -lang cpp -inpl -scal -ftz 0
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -56,165 +56,177 @@ struct Meta;
  */
 
 struct dsp_memory_manager {
-    
     virtual ~dsp_memory_manager() {}
-    
+
     virtual void* allocate(size_t size) = 0;
-    virtual void destroy(void* ptr) = 0;
-    
+    virtual void destroy(void* ptr)     = 0;
 };
 
 /**
-* Signal processor definition.
-*/
-
-class dsp {
-
-    public:
-
-        dsp() {}
-        virtual ~dsp() {}
-
-        /* Return instance number of audio inputs */
-        virtual int getNumInputs() = 0;
-    
-        /* Return instance number of audio outputs */
-        virtual int getNumOutputs() = 0;
-    
-        /**
-         * Trigger the ui_interface parameter with instance specific calls
-         * to 'openTabBox', 'addButton', 'addVerticalSlider'... in order to build the UI.
-         *
-         * @param ui_interface - the user interface builder
-         */
-        virtual void buildUserInterface(UI* ui_interface) = 0;
-    
-        /* Returns the sample rate currently used by the instance */
-        virtual int getSampleRate() = 0;
-    
-        /**
-         * Global init, calls the following methods:
-         * - static class 'classInit': static tables initialization
-         * - 'instanceInit': constants and instance state initialization
-         *
-         * @param sample_rate - the sampling rate in Hertz
-         */
-        virtual void init(int sample_rate) = 0;
-
-        /**
-         * Init instance state
-         *
-         * @param sample_rate - the sampling rate in Hertz
-         */
-        virtual void instanceInit(int sample_rate) = 0;
-
-        /**
-         * Init instance constant state
-         *
-         * @param sample_rate - the sampling rate in Hertz
-         */
-        virtual void instanceConstants(int sample_rate) = 0;
-    
-        /* Init default control parameters values */
-        virtual void instanceResetUserInterface() = 0;
-    
-        /* Init instance state (delay lines...) */
-        virtual void instanceClear() = 0;
-        /**
-         * Return a clone of the instance.
-         *
-         * @return a copy of the instance on success, otherwise a null pointer.
-         */
-        virtual dsp* clone() = 0;
-    
-        /**
-         * Trigger the Meta* parameter with instance specific calls to 'declare' (key, value) metadata.
-         *
-         * @param m - the Meta* meta user
-         */
-        virtual void metadata(Meta* m) = 0;
-    
-        /**
-         * DSP instance computation, to be called with successive in/out audio buffers.
-         *
-         * @param count - the number of frames to compute
-         * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
-         * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
-         *
-         */
-        virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) = 0;
-    
-        /**
-         * DSP instance computation: alternative method to be used by subclasses.
-         *
-         * @param date_usec - the timestamp in microsec given by audio driver.
-         * @param count - the number of frames to compute
-         * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
-         * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
-         *
-         */
-        virtual void compute(double /*date_usec*/, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { compute(count, inputs, outputs); }
-       
+ * Signal processor definition.
+ */
+
+class dsp
+{
+   public:
+    dsp() {}
+    virtual ~dsp() {}
+
+    /* Return instance number of audio inputs */
+    virtual int getNumInputs() = 0;
+
+    /* Return instance number of audio outputs */
+    virtual int getNumOutputs() = 0;
+
+    /**
+     * Trigger the ui_interface parameter with instance specific calls
+     * to 'openTabBox', 'addButton', 'addVerticalSlider'... in order to build the UI.
+     *
+     * @param ui_interface - the user interface builder
+     */
+    virtual void buildUserInterface(UI* ui_interface) = 0;
+
+    /* Returns the sample rate currently used by the instance */
+    virtual int getSampleRate() = 0;
+
+    /**
+     * Global init, calls the following methods:
+     * - static class 'classInit': static tables initialization
+     * - 'instanceInit': constants and instance state initialization
+     *
+     * @param sample_rate - the sampling rate in Hertz
+     */
+    virtual void init(int sample_rate) = 0;
+
+    /**
+     * Init instance state
+     *
+     * @param sample_rate - the sampling rate in Hertz
+     */
+    virtual void instanceInit(int sample_rate) = 0;
+
+    /**
+     * Init instance constant state
+     *
+     * @param sample_rate - the sampling rate in Hertz
+     */
+    virtual void instanceConstants(int sample_rate) = 0;
+
+    /* Init default control parameters values */
+    virtual void instanceResetUserInterface() = 0;
+
+    /* Init instance state (delay lines...) */
+    virtual void instanceClear() = 0;
+
+    /**
+     * Return a clone of the instance.
+     *
+     * @return a copy of the instance on success, otherwise a null pointer.
+     */
+    virtual dsp* clone() = 0;
+
+    /**
+     * Trigger the Meta* parameter with instance specific calls to 'declare' (key, value)
+     * metadata.
+     *
+     * @param m - the Meta* meta user
+     */
+    virtual void metadata(Meta* m) = 0;
+
+    /**
+     * DSP instance computation, to be called with successive in/out audio buffers.
+     *
+     * @param count - the number of frames to compute
+     * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (eiher float, double or quad)
+     * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (eiher float, double or quad)
+     *
+     */
+    virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) = 0;
+
+    /**
+     * DSP instance computation: alternative method to be used by subclasses.
+     *
+     * @param date_usec - the timestamp in microsec given by audio driver.
+     * @param count - the number of frames to compute
+     * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (either float, double or quad)
+     * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (either float, double or quad)
+     *
+     */
+    virtual void compute(double /*date_usec*/, int count, FAUSTFLOAT** inputs,
+                         FAUSTFLOAT** outputs)
+    {
+        compute(count, inputs, outputs);
+    }
 };
 
 /**
  * Generic DSP decorator.
  */
 
-class decorator_dsp : public dsp {
-
-    protected:
-
-        dsp* fDSP;
-
-    public:
-
-        decorator_dsp(dsp* dsp = nullptr):fDSP(dsp) {}
-        virtual ~decorator_dsp() { delete fDSP; }
-
-        virtual int getNumInputs() { return fDSP->getNumInputs(); }
-        virtual int getNumOutputs() { return fDSP->getNumOutputs(); }
-        virtual void buildUserInterface(UI* ui_interface) { fDSP->buildUserInterface(ui_interface); }
-        virtual int getSampleRate() { return fDSP->getSampleRate(); }
-        virtual void init(int sample_rate) { fDSP->init(sample_rate); }
-        virtual void instanceInit(int sample_rate) { fDSP->instanceInit(sample_rate); }
-        virtual void instanceConstants(int sample_rate) { fDSP->instanceConstants(sample_rate); }
-        virtual void instanceResetUserInterface() { fDSP->instanceResetUserInterface(); }
-        virtual void instanceClear() { fDSP->instanceClear(); }
-        virtual decorator_dsp* clone() { return new decorator_dsp(fDSP->clone()); }
-        virtual void metadata(Meta* m) { fDSP->metadata(m); }
-        // Beware: subclasses usually have to overload the two 'compute' methods
-        virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(count, inputs, outputs); }
-        virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(date_usec, count, inputs, outputs); }
-    
+class decorator_dsp : public dsp
+{
+   protected:
+    dsp* fDSP;
+
+   public:
+    decorator_dsp(dsp* dsp = nullptr) : fDSP(dsp) {}
+    virtual ~decorator_dsp() { delete fDSP; }
+
+    virtual int getNumInputs() { return fDSP->getNumInputs(); }
+    virtual int getNumOutputs() { return fDSP->getNumOutputs(); }
+    virtual void buildUserInterface(UI* ui_interface)
+    {
+        fDSP->buildUserInterface(ui_interface);
+    }
+    virtual int getSampleRate() { return fDSP->getSampleRate(); }
+    virtual void init(int sample_rate) { fDSP->init(sample_rate); }
+    virtual void instanceInit(int sample_rate) { fDSP->instanceInit(sample_rate); }
+    virtual void instanceConstants(int sample_rate)
+    {
+        fDSP->instanceConstants(sample_rate);
+    }
+    virtual void instanceResetUserInterface() { fDSP->instanceResetUserInterface(); }
+    virtual void instanceClear() { fDSP->instanceClear(); }
+    virtual decorator_dsp* clone() { return new decorator_dsp(fDSP->clone()); }
+    virtual void metadata(Meta* m) { fDSP->metadata(m); }
+    // Beware: subclasses usually have to overload the two 'compute' methods
+    virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
+    {
+        fDSP->compute(count, inputs, outputs);
+    }
+    virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs,
+                         FAUSTFLOAT** outputs)
+    {
+        fDSP->compute(date_usec, count, inputs, outputs);
+    }
 };
 
 /**
  * DSP factory class.
  */
 
-class dsp_factory {
-    
-    protected:
-    
-        // So that to force sub-classes to use deleteDSPFactory(dsp_factory* factory);
-        virtual ~dsp_factory() {}
-    
-    public:
-    
-        virtual std::string getName() = 0;
-        virtual std::string getSHAKey() = 0;
-        virtual std::string getDSPCode() = 0;
-        virtual std::string getCompileOptions() = 0;
-        virtual std::vector<std::string> getLibraryList() = 0;
-        virtual std::vector<std::string> getIncludePathnames() = 0;
-    
-        virtual dsp* createDSPInstance() = 0;
-    
-        virtual void setMemoryManager(dsp_memory_manager* manager) = 0;
-        virtual dsp_memory_manager* getMemoryManager() = 0;
-    
+class dsp_factory
+{
+   protected:
+    // So that to force sub-classes to use deleteDSPFactory(dsp_factory* factory);
+    virtual ~dsp_factory() {}
+
+   public:
+    virtual std::string getName()                          = 0;
+    virtual std::string getSHAKey()                        = 0;
+    virtual std::string getDSPCode()                       = 0;
+    virtual std::string getCompileOptions()                = 0;
+    virtual std::vector<std::string> getLibraryList()      = 0;
+    virtual std::vector<std::string> getIncludePathnames() = 0;
+
+    virtual dsp* createDSPInstance() = 0;
+
+    virtual void setMemoryManager(dsp_memory_manager* manager) = 0;
+    virtual dsp_memory_manager* getMemoryManager()             = 0;
 };
 
 /**
@@ -223,14 +235,14 @@ class dsp_factory {
  */
 
 #ifdef __SSE__
-    #include <xmmintrin.h>
-    #ifdef __SSE2__
-        #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
-    #else
-        #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
-    #endif
+#include <xmmintrin.h>
+#ifdef __SSE2__
+#define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
+#else
+#define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
+#endif
 #else
-    #define AVOIDDENORMALS
+#define AVOIDDENORMALS
 #endif
 
 #endif
@@ -245,15 +257,15 @@ class dsp_factory {
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -263,11 +275,11 @@ class dsp_factory {
 #ifndef API_UI_H
 #define API_UI_H
 
+#include <iostream>
+#include <map>
 #include <sstream>
 #include <string>
 #include <vector>
-#include <iostream>
-#include <map>
 
 /************************** BEGIN meta.h **************************/
 /************************************************************************
@@ -278,15 +290,15 @@ class dsp_factory {
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -296,11 +308,9 @@ class dsp_factory {
 #ifndef __meta__
 #define __meta__
 
-struct Meta
-{
-    virtual ~Meta() {};
+struct Meta {
+    virtual ~Meta(){};
     virtual void declare(const char* key, const char* value) = 0;
-    
 };
 
 #endif
@@ -314,15 +324,15 @@ struct Meta
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -345,43 +355,47 @@ struct Meta
 
 struct Soundfile;
 
-template <typename REAL>
-struct UIReal
-{
+template<typename REAL>
+struct UIReal {
     UIReal() {}
     virtual ~UIReal() {}
-    
+
     // -- widget's layouts
-    
-    virtual void openTabBox(const char* label) = 0;
+
+    virtual void openTabBox(const char* label)        = 0;
     virtual void openHorizontalBox(const char* label) = 0;
-    virtual void openVerticalBox(const char* label) = 0;
-    virtual void closeBox() = 0;
-    
+    virtual void openVerticalBox(const char* label)   = 0;
+    virtual void closeBox()                           = 0;
+
     // -- active widgets
-    
-    virtual void addButton(const char* label, REAL* zone) = 0;
+
+    virtual void addButton(const char* label, REAL* zone)      = 0;
     virtual void addCheckButton(const char* label, REAL* zone) = 0;
-    virtual void addVerticalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
-    virtual void addHorizontalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
-    virtual void addNumEntry(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
-    
+    virtual void addVerticalSlider(const char* label, REAL* zone, REAL init, REAL min,
+                                   REAL max, REAL step)        = 0;
+    virtual void addHorizontalSlider(const char* label, REAL* zone, REAL init, REAL min,
+                                     REAL max, REAL step)      = 0;
+    virtual void addNumEntry(const char* label, REAL* zone, REAL init, REAL min, REAL max,
+                             REAL step)                        = 0;
+
     // -- passive widgets
-    
-    virtual void addHorizontalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
-    virtual void addVerticalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
-    
+
+    virtual void addHorizontalBargraph(const char* label, REAL* zone, REAL min,
+                                       REAL max) = 0;
+    virtual void addVerticalBargraph(const char* label, REAL* zone, REAL min,
+                                     REAL max)   = 0;
+
     // -- soundfiles
-    
-    virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) = 0;
-    
+
+    virtual void addSoundfile(const char* label, const char* filename,
+                              Soundfile** sf_zone) = 0;
+
     // -- metadata declarations
-    
+
     virtual void declare(REAL* zone, const char* key, const char* val) {}
 };
 
-struct UI : public UIReal<FAUSTFLOAT>
-{
+struct UI : public UIReal<FAUSTFLOAT> {
     UI() {}
     virtual ~UI() {}
 };
@@ -397,15 +411,15 @@ struct UI : public UIReal<FAUSTFLOAT>
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -415,9 +429,9 @@ struct UI : public UIReal<FAUSTFLOAT>
 #ifndef FAUST_PATHBUILDER_H
 #define FAUST_PATHBUILDER_H
 
-#include <vector>
-#include <string>
 #include <algorithm>
+#include <string>
+#include <vector>
 
 /*******************************************************************************
  * PathBuilder : Faust User Interface
@@ -426,37 +440,33 @@ struct UI : public UIReal<FAUSTFLOAT>
 
 class PathBuilder
 {
-
-    protected:
-    
-        std::vector<std::string> fControlsLevel;
-       
-    public:
-    
-        PathBuilder() {}
-        virtual ~PathBuilder() {}
-    
-        std::string buildPath(const std::string& label) 
-        {
-            std::string res = "/";
-            for (size_t i = 0; i < fControlsLevel.size(); i++) {
-                res += fControlsLevel[i];
-                res += "/";
-            }
-            res += label;
-            std::replace(res.begin(), res.end(), ' ', '_');
-            return res;
-        }
-    
-        std::string buildLabel(std::string label)
-        {
-            std::replace(label.begin(), label.end(), ' ', '_');
-            return label;
+   protected:
+    std::vector<std::string> fControlsLevel;
+
+   public:
+    PathBuilder() {}
+    virtual ~PathBuilder() {}
+
+    std::string buildPath(const std::string& label)
+    {
+        std::string res = "/";
+        for (size_t i = 0; i < fControlsLevel.size(); i++) {
+            res += fControlsLevel[i];
+            res += "/";
         }
-    
-        void pushLabel(const std::string& label) { fControlsLevel.push_back(label); }
-        void popLabel() { fControlsLevel.pop_back(); }
-    
+        res += label;
+        std::replace(res.begin(), res.end(), ' ', '_');
+        return res;
+    }
+
+    std::string buildLabel(std::string label)
+    {
+        std::replace(label.begin(), label.end(), ' ', '_');
+        return label;
+    }
+
+    void pushLabel(const std::string& label) { fControlsLevel.push_back(label); }
+    void popLabel() { fControlsLevel.pop_back(); }
 };
 
 #endif  // FAUST_PATHBUILDER_H
@@ -470,15 +480,15 @@ class PathBuilder
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -489,7 +499,7 @@ class PathBuilder
 #define __ValueConverter__
 
 /***************************************************************************************
-                                                               ValueConverter.h
+                                                                ValueConverter.h
                             (GRAME, Copyright 2015-2019)
 
 Set of conversion objects used to map user interface values (for example a gui slider
@@ -499,8 +509,9 @@ delivering values between 0 and 1) to faust values (for example a vslider betwee
 -- Utilities
 
 Range(lo,hi) : clip a value x between lo and hi
-Interpolator(lo,hi,v1,v2) : Maps a value x between lo and hi to a value y between v1 and v2
-Interpolator3pt(lo,mi,hi,v1,vm,v2) : Map values between lo mid hi to values between v1 vm v2
+Interpolator(lo,hi,v1,v2) : Maps a value x between lo and hi to a value y between v1 and
+v2 Interpolator3pt(lo,mi,hi,v1,vm,v2) : Map values between lo mid hi to values between v1
+vm v2
 
 -- Value Converters
 
@@ -531,11 +542,11 @@ ZoneReader(zone, valueConverter) : a zone with a data converter
 
 ****************************************************************************************/
 
-#include <float.h>
-#include <algorithm>    // std::max
+#include <algorithm>  // std::max
+#include <cassert>
+#include <cfloat>
 #include <cmath>
 #include <vector>
-#include <assert.h>
 
 //--------------------------------------------------------------------------------------
 // Interpolator(lo,hi,v1,v2)
@@ -548,50 +559,49 @@ ZoneReader(zone, valueConverter) : a zone with a data converter
 //--------------------------------------------------------------------------------------
 class Interpolator
 {
-    private:
-
-        //--------------------------------------------------------------------------------------
-        // Range(lo,hi) clip a value between lo and hi
-        //--------------------------------------------------------------------------------------
-        struct Range
-        {
-            double fLo;
-            double fHi;
-
-            Range(double x, double y) : fLo(std::min<double>(x,y)), fHi(std::max<double>(x,y)) {}
-            double operator()(double x) { return (x<fLo) ? fLo : (x>fHi) ? fHi : x; }
-        };
-
-
-        Range fRange;
-        double fCoef;
-        double fOffset;
-
-    public:
-
-        Interpolator(double lo, double hi, double v1, double v2) : fRange(lo,hi)
+   private:
+    //--------------------------------------------------------------------------------------
+    // Range(lo,hi) clip a value between lo and hi
+    //--------------------------------------------------------------------------------------
+    struct Range {
+        double fLo;
+        double fHi;
+
+        Range(double x, double y)
+            : fLo(std::min<double>(x, y)), fHi(std::max<double>(x, y))
         {
-            if (hi != lo) {
-                // regular case
-                fCoef = (v2-v1)/(hi-lo);
-                fOffset = v1 - lo*fCoef;
-            } else {
-                // degenerate case, avoids division by zero
-                fCoef = 0;
-                fOffset = (v1+v2)/2;
-            }
         }
-        double operator()(double v)
-        {
-            double x = fRange(v);
-            return  fOffset + x*fCoef;
-        }
-
-        void getLowHigh(double& amin, double& amax)
-        {
-            amin = fRange.fLo;
-            amax = fRange.fHi;
+        double operator()(double x) { return (x < fLo) ? fLo : (x > fHi) ? fHi : x; }
+    };
+
+    Range fRange;
+    double fCoef;
+    double fOffset;
+
+   public:
+    Interpolator(double lo, double hi, double v1, double v2) : fRange(lo, hi)
+    {
+        if (hi != lo) {
+            // regular case
+            fCoef   = (v2 - v1) / (hi - lo);
+            fOffset = v1 - lo * fCoef;
+        } else {
+            // degenerate case, avoids division by zero
+            fCoef   = 0;
+            fOffset = (v1 + v2) / 2;
         }
+    }
+    double operator()(double v)
+    {
+        double x = fRange(v);
+        return fOffset + x * fCoef;
+    }
+
+    void getLowHigh(double& amin, double& amax)
+    {
+        amin = fRange.fLo;
+        amax = fRange.fHi;
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -600,26 +610,23 @@ class Interpolator
 //--------------------------------------------------------------------------------------
 class Interpolator3pt
 {
-
-    private:
-
-        Interpolator fSegment1;
-        Interpolator fSegment2;
-        double fMid;
-
-    public:
-
-        Interpolator3pt(double lo, double mi, double hi, double v1, double vm, double v2) :
-            fSegment1(lo, mi, v1, vm),
-            fSegment2(mi, hi, vm, v2),
-            fMid(mi) {}
-        double operator()(double x) { return  (x < fMid) ? fSegment1(x) : fSegment2(x); }
-
-        void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fSegment1.getLowHigh(amin, amid);
-            fSegment2.getLowHigh(amid, amax);
-        }
+   private:
+    Interpolator fSegment1;
+    Interpolator fSegment2;
+    double fMid;
+
+   public:
+    Interpolator3pt(double lo, double mi, double hi, double v1, double vm, double v2)
+        : fSegment1(lo, mi, v1, vm), fSegment2(mi, hi, vm, v2), fMid(mi)
+    {
+    }
+    double operator()(double x) { return (x < fMid) ? fSegment1(x) : fSegment2(x); }
+
+    void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fSegment1.getLowHigh(amin, amid);
+        fSegment2.getLowHigh(amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -627,62 +634,51 @@ class Interpolator3pt
 //--------------------------------------------------------------------------------------
 class ValueConverter
 {
-
-    public:
-
-        virtual ~ValueConverter() {}
-        virtual double ui2faust(double x) = 0;
-        virtual double faust2ui(double x) = 0;
+   public:
+    virtual ~ValueConverter() {}
+    virtual double ui2faust(double x) = 0;
+    virtual double faust2ui(double x) = 0;
 };
 
 //--------------------------------------------------------------------------------------
 // A converter than can be updated
 //--------------------------------------------------------------------------------------
 
-class UpdatableValueConverter : public ValueConverter {
-    
-    protected:
-        
-        bool fActive;
-        
-    public:
-        
-        UpdatableValueConverter():fActive(true)
-        {}
-        virtual ~UpdatableValueConverter()
-        {}
-        
-        virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max) = 0;
-        virtual void getMappingValues(double& amin, double& amid, double& amax) = 0;
-        
-        void setActive(bool on_off) { fActive = on_off; }
-        bool getActive() { return fActive; }
-    
-};
+class UpdatableValueConverter : public ValueConverter
+{
+   protected:
+    bool fActive;
+
+   public:
+    UpdatableValueConverter() : fActive(true) {}
+    virtual ~UpdatableValueConverter() {}
 
+    virtual void setMappingValues(double amin, double amid, double amax, double min,
+                                  double init, double max)                  = 0;
+    virtual void getMappingValues(double& amin, double& amid, double& amax) = 0;
+
+    void setActive(bool on_off) { fActive = on_off; }
+    bool getActive() { return fActive; }
+};
 
 //--------------------------------------------------------------------------------------
 // Linear conversion between ui and Faust values
 //--------------------------------------------------------------------------------------
 class LinearValueConverter : public ValueConverter
 {
-    
-    private:
-        
-        Interpolator fUI2F;
-        Interpolator fF2UI;
-        
-    public:
-        
-        LinearValueConverter(double umin, double umax, double fmin, double fmax) :
-            fUI2F(umin,umax,fmin,fmax), fF2UI(fmin,fmax,umin,umax)
-        {}
-        
-        LinearValueConverter() : fUI2F(0.,0.,0.,0.), fF2UI(0.,0.,0.,0.)
-        {}
-        virtual double ui2faust(double x) { return fUI2F(x); }
-        virtual double faust2ui(double x) { return fF2UI(x); }
-    
+   private:
+    Interpolator fUI2F;
+    Interpolator fF2UI;
+
+   public:
+    LinearValueConverter(double umin, double umax, double fmin, double fmax)
+        : fUI2F(umin, umax, fmin, fmax), fF2UI(fmin, fmax, umin, umax)
+    {
+    }
+
+    LinearValueConverter() : fUI2F(0., 0., 0., 0.), fF2UI(0., 0., 0., 0.) {}
+    virtual double ui2faust(double x) { return fUI2F(x); }
+    virtual double faust2ui(double x) { return fF2UI(x); }
 };
 
 //--------------------------------------------------------------------------------------
@@ -690,35 +686,35 @@ class LinearValueConverter : public ValueConverter
 //--------------------------------------------------------------------------------------
 class LinearValueConverter2 : public UpdatableValueConverter
 {
-    
-    private:
-    
-        Interpolator3pt fUI2F;
-        Interpolator3pt fF2UI;
-        
-    public:
-    
-        LinearValueConverter2(double amin, double amid, double amax, double min, double init, double max) :
-            fUI2F(amin, amid, amax, min, init, max), fF2UI(min, init, max, amin, amid, amax)
-        {}
-        
-        LinearValueConverter2() : fUI2F(0.,0.,0.,0.,0.,0.), fF2UI(0.,0.,0.,0.,0.,0.)
-        {}
-    
-        virtual double ui2faust(double x) { return fUI2F(x); }
-        virtual double faust2ui(double x) { return fF2UI(x); }
-    
-        virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max)
-        {
-            fUI2F = Interpolator3pt(amin, amid, amax, min, init, max);
-            fF2UI = Interpolator3pt(min, init, max, amin, amid, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fUI2F.getMappingValues(amin, amid, amax);
-        }
-    
+   private:
+    Interpolator3pt fUI2F;
+    Interpolator3pt fF2UI;
+
+   public:
+    LinearValueConverter2(double amin, double amid, double amax, double min, double init,
+                          double max)
+        : fUI2F(amin, amid, amax, min, init, max), fF2UI(min, init, max, amin, amid, amax)
+    {
+    }
+
+    LinearValueConverter2() : fUI2F(0., 0., 0., 0., 0., 0.), fF2UI(0., 0., 0., 0., 0., 0.)
+    {
+    }
+
+    virtual double ui2faust(double x) { return fUI2F(x); }
+    virtual double faust2ui(double x) { return fF2UI(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double min,
+                                  double init, double max)
+    {
+        fUI2F = Interpolator3pt(amin, amid, amax, min, init, max);
+        fF2UI = Interpolator3pt(min, init, max, amin, amid, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fUI2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -726,16 +722,21 @@ class LinearValueConverter2 : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class LogValueConverter : public LinearValueConverter
 {
-
-    public:
-
-        LogValueConverter(double umin, double umax, double fmin, double fmax) :
-            LinearValueConverter(umin, umax, std::log(std::max<double>(DBL_MIN, fmin)), std::log(std::max<double>(DBL_MIN, fmax)))
-        {}
-
-        virtual double ui2faust(double x) { return std::exp(LinearValueConverter::ui2faust(x)); }
-        virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::log(std::max<double>(x, DBL_MIN))); }
-
+   public:
+    LogValueConverter(double umin, double umax, double fmin, double fmax)
+        : LinearValueConverter(umin, umax, std::log(std::max<double>(DBL_MIN, fmin)),
+                               std::log(std::max<double>(DBL_MIN, fmax)))
+    {
+    }
+
+    virtual double ui2faust(double x)
+    {
+        return std::exp(LinearValueConverter::ui2faust(x));
+    }
+    virtual double faust2ui(double x)
+    {
+        return LinearValueConverter::faust2ui(std::log(std::max<double>(x, DBL_MIN)));
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -743,16 +744,21 @@ class LogValueConverter : public LinearValueConverter
 //--------------------------------------------------------------------------------------
 class ExpValueConverter : public LinearValueConverter
 {
-
-    public:
-
-        ExpValueConverter(double umin, double umax, double fmin, double fmax) :
-            LinearValueConverter(umin, umax, std::min<double>(DBL_MAX, std::exp(fmin)), std::min<double>(DBL_MAX, std::exp(fmax)))
-        {}
-
-        virtual double ui2faust(double x) { return std::log(LinearValueConverter::ui2faust(x)); }
-        virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::min<double>(DBL_MAX, std::exp(x))); }
-
+   public:
+    ExpValueConverter(double umin, double umax, double fmin, double fmax)
+        : LinearValueConverter(umin, umax, std::min<double>(DBL_MAX, std::exp(fmin)),
+                               std::min<double>(DBL_MAX, std::exp(fmax)))
+    {
+    }
+
+    virtual double ui2faust(double x)
+    {
+        return std::log(LinearValueConverter::ui2faust(x));
+    }
+    virtual double faust2ui(double x)
+    {
+        return LinearValueConverter::faust2ui(std::min<double>(DBL_MAX, std::exp(x)));
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -761,34 +767,34 @@ class ExpValueConverter : public LinearValueConverter
 //--------------------------------------------------------------------------------------
 class AccUpConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt fA2F;
-        Interpolator3pt fF2A;
-
-    public:
-
-        AccUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmin,fmid,fmax),
-            fF2A(fmin,fmid,fmax,amin,amid,amax)
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-            //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmin, fmid, fmax);
-            fF2A = Interpolator3pt(fmin, fmid, fmax, amin, amid, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
-
+   private:
+    Interpolator3pt fA2F;
+    Interpolator3pt fF2A;
+
+   public:
+    AccUpConverter(double amin, double amid, double amax, double fmin, double fmid,
+                   double fmax)
+        : fA2F(amin, amid, amax, fmin, fmid, fmax)
+        , fF2A(fmin, fmid, fmax, amin, amid, amax)
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double fmid, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpConverter update %f %f %f
+        //%f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmin, fmid, fmax);
+        fF2A = Interpolator3pt(fmin, fmid, fmax, amin, amid, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -797,33 +803,34 @@ class AccUpConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class AccDownConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt        fA2F;
-        Interpolator3pt        fF2A;
-
-    public:
-
-        AccDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmax,fmid,fmin),
-            fF2A(fmin,fmid,fmax,amax,amid,amin)
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-             //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmax, fmid, fmin);
-            fF2A = Interpolator3pt(fmin, fmid, fmax, amax, amid, amin);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
+   private:
+    Interpolator3pt fA2F;
+    Interpolator3pt fF2A;
+
+   public:
+    AccDownConverter(double amin, double amid, double amax, double fmin, double fmid,
+                     double fmax)
+        : fA2F(amin, amid, amax, fmax, fmid, fmin)
+        , fF2A(fmin, fmid, fmax, amax, amid, amin)
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double fmid, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownConverter update %f %f
+        //%f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmax, fmid, fmin);
+        fF2A = Interpolator3pt(fmin, fmid, fmax, amax, amid, amin);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -832,33 +839,35 @@ class AccDownConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class AccUpDownConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt        fA2F;
-        Interpolator fF2A;
-
-    public:
-
-        AccUpDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmin,fmax,fmin),
-            fF2A(fmin,fmax,amin,amax)                          // Special, pseudo inverse of a non monotonic function
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-            //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmin, fmax, fmin);
-            fF2A = Interpolator(fmin, fmax, amin, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
+   private:
+    Interpolator3pt fA2F;
+    Interpolator fF2A;
+
+   public:
+    AccUpDownConverter(double amin, double amid, double amax, double fmin, double fmid,
+                       double fmax)
+        : fA2F(amin, amid, amax, fmin, fmax, fmin)
+        , fF2A(fmin, fmax, amin,
+               amax)  // Special, pseudo inverse of a non monotonic function
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double fmid, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpDownConverter update %f %f
+        //%f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmin, fmax, fmin);
+        fF2A = Interpolator(fmin, fmax, amin, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -867,33 +876,35 @@ class AccUpDownConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class AccDownUpConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt        fA2F;
-        Interpolator fF2A;
-
-    public:
-
-        AccDownUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmax,fmin,fmax),
-            fF2A(fmin,fmax,amin,amax)                          // Special, pseudo inverse of a non monotonic function
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-            //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmax, fmin, fmax);
-            fF2A = Interpolator(fmin, fmax, amin, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
+   private:
+    Interpolator3pt fA2F;
+    Interpolator fF2A;
+
+   public:
+    AccDownUpConverter(double amin, double amid, double amax, double fmin, double fmid,
+                       double fmax)
+        : fA2F(amin, amid, amax, fmax, fmin, fmax)
+        , fF2A(fmin, fmax, amin,
+               amax)  // Special, pseudo inverse of a non monotonic function
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double fmid, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownUpConverter update %f %f
+        //%f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmax, fmin, fmax);
+        fF2A = Interpolator(fmin, fmax, amin, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -901,28 +912,27 @@ class AccDownUpConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class ZoneControl
 {
+   protected:
+    FAUSTFLOAT* fZone;
 
-    protected:
+   public:
+    ZoneControl(FAUSTFLOAT* zone) : fZone(zone) {}
+    virtual ~ZoneControl() {}
 
-        FAUSTFLOAT*    fZone;
+    virtual void update(double v) const {}
 
-    public:
+    virtual void setMappingValues(int curve, double amin, double amid, double amax,
+                                  double min, double init, double max)
+    {
+    }
+    virtual void getMappingValues(double& amin, double& amid, double& amax) {}
 
-        ZoneControl(FAUSTFLOAT* zone) : fZone(zone) {}
-        virtual ~ZoneControl() {}
+    FAUSTFLOAT* getZone() { return fZone; }
 
-        virtual void update(double v) const {}
-
-        virtual void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max) {}
-        virtual void getMappingValues(double& amin, double& amid, double& amax) {}
-
-        FAUSTFLOAT* getZone() { return fZone; }
-
-        virtual void setActive(bool on_off) {}
-        virtual bool getActive() { return false; }
-
-        virtual int getCurve() { return -1; }
+    virtual void setActive(bool on_off) {}
+    virtual bool getActive() { return false; }
 
+    virtual int getCurve() { return -1; }
 };
 
 //--------------------------------------------------------------------------------------
@@ -930,20 +940,22 @@ class ZoneControl
 //--------------------------------------------------------------------------------------
 class ConverterZoneControl : public ZoneControl
 {
-
-    protected:
-
-        ValueConverter* fValueConverter;
-
-    public:
-
-        ConverterZoneControl(FAUSTFLOAT* zone, ValueConverter* converter) : ZoneControl(zone), fValueConverter(converter) {}
-        virtual ~ConverterZoneControl() { delete fValueConverter; } // Assuming fValueConverter is not kept elsewhere...
-
-        virtual void update(double v) const { *fZone = fValueConverter->ui2faust(v); }
-
-        ValueConverter* getConverter() { return fValueConverter; }
-
+   protected:
+    ValueConverter* fValueConverter;
+
+   public:
+    ConverterZoneControl(FAUSTFLOAT* zone, ValueConverter* converter)
+        : ZoneControl(zone), fValueConverter(converter)
+    {
+    }
+    virtual ~ConverterZoneControl()
+    {
+        delete fValueConverter;
+    }  // Assuming fValueConverter is not kept elsewhere...
+
+    virtual void update(double v) const { *fZone = fValueConverter->ui2faust(v); }
+
+    ValueConverter* getConverter() { return fValueConverter; }
 };
 
 //--------------------------------------------------------------------------------------
@@ -952,592 +964,613 @@ class ConverterZoneControl : public ZoneControl
 //--------------------------------------------------------------------------------------
 class CurveZoneControl : public ZoneControl
 {
-
-    private:
-
-        std::vector<UpdatableValueConverter*> fValueConverters;
-        int fCurve;
-
-    public:
-
-        CurveZoneControl(FAUSTFLOAT* zone, int curve, double amin, double amid, double amax, double min, double init, double max) : ZoneControl(zone), fCurve(0)
-        {
-            assert(curve >= 0 && curve <= 3);
-            fValueConverters.push_back(new AccUpConverter(amin, amid, amax, min, init, max));
-            fValueConverters.push_back(new AccDownConverter(amin, amid, amax, min, init, max));
-            fValueConverters.push_back(new AccUpDownConverter(amin, amid, amax, min, init, max));
-            fValueConverters.push_back(new AccDownUpConverter(amin, amid, amax, min, init, max));
-            fCurve = curve;
-        }
-        virtual ~CurveZoneControl()
-        {
-            std::vector<UpdatableValueConverter*>::iterator it;
-            for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
-                delete(*it);
-            }
-        }
-        void update(double v) const { if (fValueConverters[fCurve]->getActive()) *fZone = fValueConverters[fCurve]->ui2faust(v); }
-
-        void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max)
-        {
-            fValueConverters[curve]->setMappingValues(amin, amid, amax, min, init, max);
-            fCurve = curve;
-        }
-
-        void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fValueConverters[fCurve]->getMappingValues(amin, amid, amax);
+   private:
+    std::vector<UpdatableValueConverter*> fValueConverters;
+    int fCurve;
+
+   public:
+    CurveZoneControl(FAUSTFLOAT* zone, int curve, double amin, double amid, double amax,
+                     double min, double init, double max)
+        : ZoneControl(zone), fCurve(0)
+    {
+        assert(curve >= 0 && curve <= 3);
+        fValueConverters.push_back(new AccUpConverter(amin, amid, amax, min, init, max));
+        fValueConverters.push_back(
+            new AccDownConverter(amin, amid, amax, min, init, max));
+        fValueConverters.push_back(
+            new AccUpDownConverter(amin, amid, amax, min, init, max));
+        fValueConverters.push_back(
+            new AccDownUpConverter(amin, amid, amax, min, init, max));
+        fCurve = curve;
+    }
+    virtual ~CurveZoneControl()
+    {
+        std::vector<UpdatableValueConverter*>::iterator it;
+        for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+            delete (*it);
         }
-
-        void setActive(bool on_off)
-        {
-            std::vector<UpdatableValueConverter*>::iterator it;
-            for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
-                (*it)->setActive(on_off);
-            }
+    }
+    void update(double v) const
+    {
+        if (fValueConverters[fCurve]->getActive())
+            *fZone = fValueConverters[fCurve]->ui2faust(v);
+    }
+
+    void setMappingValues(int curve, double amin, double amid, double amax, double min,
+                          double init, double max)
+    {
+        fValueConverters[curve]->setMappingValues(amin, amid, amax, min, init, max);
+        fCurve = curve;
+    }
+
+    void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fValueConverters[fCurve]->getMappingValues(amin, amid, amax);
+    }
+
+    void setActive(bool on_off)
+    {
+        std::vector<UpdatableValueConverter*>::iterator it;
+        for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+            (*it)->setActive(on_off);
         }
+    }
 
-        int getCurve() { return fCurve; }
+    int getCurve() { return fCurve; }
 };
 
 class ZoneReader
 {
+   private:
+    FAUSTFLOAT* fZone;
+    Interpolator fInterpolator;
 
-    private:
-
-        FAUSTFLOAT* fZone;
-        Interpolator fInterpolator;
+   public:
+    ZoneReader(FAUSTFLOAT* zone, double lo, double hi)
+        : fZone(zone), fInterpolator(lo, hi, 0, 255)
+    {
+    }
 
-    public:
-
-        ZoneReader(FAUSTFLOAT* zone, double lo, double hi) : fZone(zone), fInterpolator(lo, hi, 0, 255) {}
-
-        virtual ~ZoneReader() {}
-
-        int getValue()
-        {
-            return (fZone != nullptr) ? int(fInterpolator(*fZone)) : 127;
-        }
+    virtual ~ZoneReader() {}
 
+    int getValue() { return (fZone != nullptr) ? int(fInterpolator(*fZone)) : 127; }
 };
 
 #endif
 /**************************  END  ValueConverter.h **************************/
 
-class APIUI : public PathBuilder, public Meta, public UI
+class APIUI
+    : public PathBuilder
+    , public Meta
+    , public UI
 {
-    public:
-    
-        enum ItemType { kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph };
-  
-    protected:
-    
-        enum { kLin = 0, kLog = 1, kExp = 2 };
-    
-        int fNumParameters;
-        std::vector<std::string> fPaths;
-        std::vector<std::string> fLabels;
-        std::map<std::string, int> fPathMap;
-        std::map<std::string, int> fLabelMap;
-        std::vector<ValueConverter*> fConversion;
-        std::vector<FAUSTFLOAT*> fZone;
-        std::vector<FAUSTFLOAT> fInit;
-        std::vector<FAUSTFLOAT> fMin;
-        std::vector<FAUSTFLOAT> fMax;
-        std::vector<FAUSTFLOAT> fStep;
-        std::vector<ItemType> fItemType;
-        std::vector<std::map<std::string, std::string> > fMetaData;
-        std::vector<ZoneControl*> fAcc[3];
-        std::vector<ZoneControl*> fGyr[3];
-
-        // Screen color control
-        // "...[screencolor:red]..." etc.
-        bool fHasScreenControl;      // true if control screen color metadata
-        ZoneReader* fRedReader;
-        ZoneReader* fGreenReader;
-        ZoneReader* fBlueReader;
-
-        // Current values controlled by metadata
-        std::string fCurrentUnit;
-        int fCurrentScale;
-        std::string fCurrentAcc;
-        std::string fCurrentGyr;
-        std::string fCurrentColor;
-        std::string fCurrentTooltip;
-        std::map<std::string, std::string> fCurrentMetadata;
-    
-        // Add a generic parameter
-        virtual void addParameter(const char* label,
-                                FAUSTFLOAT* zone,
-                                FAUSTFLOAT init,
-                                FAUSTFLOAT min,
-                                FAUSTFLOAT max,
-                                FAUSTFLOAT step,
-                                ItemType type)
-        {
-            std::string path = buildPath(label);
-            fPathMap[path] = fLabelMap[label] = fNumParameters++;
-            fPaths.push_back(path);
-            fLabels.push_back(label);
-            fZone.push_back(zone);
-            fInit.push_back(init);
-            fMin.push_back(min);
-            fMax.push_back(max);
-            fStep.push_back(step);
-            fItemType.push_back(type);
-            
-            // handle scale metadata
-            switch (fCurrentScale) {
-                case kLin:
-                    fConversion.push_back(new LinearValueConverter(0, 1, min, max));
-                    break;
-                case kLog:
-                    fConversion.push_back(new LogValueConverter(0, 1, min, max));
-                    break;
-                case kExp: fConversion.push_back(new ExpValueConverter(0, 1, min, max));
-                    break;
-            }
-            fCurrentScale = kLin;
-            
-            if (fCurrentAcc.size() > 0 && fCurrentGyr.size() > 0) {
-                std::cerr << "warning : 'acc' and 'gyr' metadata used for the same " << label << " parameter !!\n";
-            }
+   public:
+    enum ItemType {
+        kButton = 0,
+        kCheckButton,
+        kVSlider,
+        kHSlider,
+        kNumEntry,
+        kHBargraph,
+        kVBargraph
+    };
+
+   protected:
+    enum { kLin = 0, kLog = 1, kExp = 2 };
+
+    int fNumParameters;
+    std::vector<std::string> fPaths;
+    std::vector<std::string> fLabels;
+    std::map<std::string, int> fPathMap;
+    std::map<std::string, int> fLabelMap;
+    std::vector<ValueConverter*> fConversion;
+    std::vector<FAUSTFLOAT*> fZone;
+    std::vector<FAUSTFLOAT> fInit;
+    std::vector<FAUSTFLOAT> fMin;
+    std::vector<FAUSTFLOAT> fMax;
+    std::vector<FAUSTFLOAT> fStep;
+    std::vector<ItemType> fItemType;
+    std::vector<std::map<std::string, std::string> > fMetaData;
+    std::vector<ZoneControl*> fAcc[3];
+    std::vector<ZoneControl*> fGyr[3];
+
+    // Screen color control
+    // "...[screencolor:red]..." etc.
+    bool fHasScreenControl;  // true if control screen color metadata
+    ZoneReader* fRedReader;
+    ZoneReader* fGreenReader;
+    ZoneReader* fBlueReader;
+
+    // Current values controlled by metadata
+    std::string fCurrentUnit;
+    int fCurrentScale;
+    std::string fCurrentAcc;
+    std::string fCurrentGyr;
+    std::string fCurrentColor;
+    std::string fCurrentTooltip;
+    std::map<std::string, std::string> fCurrentMetadata;
+
+    // Add a generic parameter
+    virtual void addParameter(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                              FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step,
+                              ItemType type)
+    {
+        std::string path = buildPath(label);
+        fPathMap[path] = fLabelMap[label] = fNumParameters++;
+        fPaths.push_back(path);
+        fLabels.push_back(label);
+        fZone.push_back(zone);
+        fInit.push_back(init);
+        fMin.push_back(min);
+        fMax.push_back(max);
+        fStep.push_back(step);
+        fItemType.push_back(type);
+
+        // handle scale metadata
+        switch (fCurrentScale) {
+        case kLin:
+            fConversion.push_back(new LinearValueConverter(0, 1, min, max));
+            break;
+        case kLog:
+            fConversion.push_back(new LogValueConverter(0, 1, min, max));
+            break;
+        case kExp:
+            fConversion.push_back(new ExpValueConverter(0, 1, min, max));
+            break;
+        }
+        fCurrentScale = kLin;
 
-            // handle acc metadata "...[acc : <axe> <curve> <amin> <amid> <amax>]..."
-            if (fCurrentAcc.size() > 0) {
-                std::istringstream iss(fCurrentAcc);
-                int axe, curve;
-                double amin, amid, amax;
-                iss >> axe >> curve >> amin >> amid >> amax;
-
-                if ((0 <= axe) && (axe < 3) &&
-                    (0 <= curve) && (curve < 4) &&
-                    (amin < amax) && (amin <= amid) && (amid <= amax))
-                {
-                    fAcc[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
-                } else {
-                    std::cerr << "incorrect acc metadata : " << fCurrentAcc << std::endl;
-                }
-                fCurrentAcc = "";
-            }
-       
-            // handle gyr metadata "...[gyr : <axe> <curve> <amin> <amid> <amax>]..."
-            if (fCurrentGyr.size() > 0) {
-                std::istringstream iss(fCurrentGyr);
-                int axe, curve;
-                double amin, amid, amax;
-                iss >> axe >> curve >> amin >> amid >> amax;
-
-                if ((0 <= axe) && (axe < 3) &&
-                    (0 <= curve) && (curve < 4) &&
-                    (amin < amax) && (amin <= amid) && (amid <= amax))
-                {
-                    fGyr[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
-                } else {
-                    std::cerr << "incorrect gyr metadata : " << fCurrentGyr << std::endl;
-                }
-                fCurrentGyr = "";
-            }
-        
-            // handle screencolor metadata "...[screencolor:red|green|blue|white]..."
-            if (fCurrentColor.size() > 0) {
-                if ((fCurrentColor == "red") && (fRedReader == 0)) {
-                    fRedReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else if ((fCurrentColor == "green") && (fGreenReader == 0)) {
-                    fGreenReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else if ((fCurrentColor == "blue") && (fBlueReader == 0)) {
-                    fBlueReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else if ((fCurrentColor == "white") && (fRedReader == 0) && (fGreenReader == 0) && (fBlueReader == 0)) {
-                    fRedReader = new ZoneReader(zone, min, max);
-                    fGreenReader = new ZoneReader(zone, min, max);
-                    fBlueReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else {
-                    std::cerr << "incorrect screencolor metadata : " << fCurrentColor << std::endl;
-                }
-            }
-            fCurrentColor = "";
-            
-            fMetaData.push_back(fCurrentMetadata);
-            fCurrentMetadata.clear();
+        if (fCurrentAcc.size() > 0 && fCurrentGyr.size() > 0) {
+            std::cerr << "warning : 'acc' and 'gyr' metadata used for the same " << label
+                      << " parameter !!\n";
         }
 
-        int getZoneIndex(std::vector<ZoneControl*>* table, int p, int val)
-        {
-            FAUSTFLOAT* zone = fZone[p];
-            for (size_t i = 0; i < table[val].size(); i++) {
-                if (zone == table[val][i]->getZone()) return int(i);
+        // handle acc metadata "...[acc : <axe> <curve> <amin> <amid> <amax>]..."
+        if (fCurrentAcc.size() > 0) {
+            std::istringstream iss(fCurrentAcc);
+            int axe, curve;
+            double amin, amid, amax;
+            iss >> axe >> curve >> amin >> amid >> amax;
+
+            if ((0 <= axe) && (axe < 3) && (0 <= curve) && (curve < 4) && (amin < amax)
+                && (amin <= amid) && (amid <= amax)) {
+                fAcc[axe].push_back(
+                    new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
+            } else {
+                std::cerr << "incorrect acc metadata : " << fCurrentAcc << std::endl;
             }
-            return -1;
+            fCurrentAcc = "";
         }
-    
-        void setConverter(std::vector<ZoneControl*>* table, int p, int val, int curve, double amin, double amid, double amax)
-        {
-            int id1 = getZoneIndex(table, p, 0);
-            int id2 = getZoneIndex(table, p, 1);
-            int id3 = getZoneIndex(table, p, 2);
-            
-            // Deactivates everywhere..
-            if (id1 != -1) table[0][id1]->setActive(false);
-            if (id2 != -1) table[1][id2]->setActive(false);
-            if (id3 != -1) table[2][id3]->setActive(false);
-            
-            if (val == -1) { // Means: no more mapping...
-                // So stay all deactivated...
+
+        // handle gyr metadata "...[gyr : <axe> <curve> <amin> <amid> <amax>]..."
+        if (fCurrentGyr.size() > 0) {
+            std::istringstream iss(fCurrentGyr);
+            int axe, curve;
+            double amin, amid, amax;
+            iss >> axe >> curve >> amin >> amid >> amax;
+
+            if ((0 <= axe) && (axe < 3) && (0 <= curve) && (curve < 4) && (amin < amax)
+                && (amin <= amid) && (amid <= amax)) {
+                fGyr[axe].push_back(
+                    new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
             } else {
-                int id4 = getZoneIndex(table, p, val);
-                if (id4 != -1) {
-                    // Reactivate the one we edit...
-                    table[val][id4]->setMappingValues(curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]);
-                    table[val][id4]->setActive(true);
-                } else {
-                    // Allocate a new CurveZoneControl which is 'active' by default
-                    FAUSTFLOAT* zone = fZone[p];
-                    table[val].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]));
-                }
+                std::cerr << "incorrect gyr metadata : " << fCurrentGyr << std::endl;
             }
+            fCurrentGyr = "";
         }
-    
-        void getConverter(std::vector<ZoneControl*>* table, int p, int& val, int& curve, double& amin, double& amid, double& amax)
-        {
-            int id1 = getZoneIndex(table, p, 0);
-            int id2 = getZoneIndex(table, p, 1);
-            int id3 = getZoneIndex(table, p, 2);
-            
-            if (id1 != -1) {
-                val = 0;
-                curve = table[val][id1]->getCurve();
-                table[val][id1]->getMappingValues(amin, amid, amax);
-            } else if (id2 != -1) {
-                val = 1;
-                curve = table[val][id2]->getCurve();
-                table[val][id2]->getMappingValues(amin, amid, amax);
-            } else if (id3 != -1) {
-                val = 2;
-                curve = table[val][id3]->getCurve();
-                table[val][id3]->getMappingValues(amin, amid, amax);
+
+        // handle screencolor metadata "...[screencolor:red|green|blue|white]..."
+        if (fCurrentColor.size() > 0) {
+            if ((fCurrentColor == "red") && (fRedReader == 0)) {
+                fRedReader        = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
+            } else if ((fCurrentColor == "green") && (fGreenReader == 0)) {
+                fGreenReader      = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
+            } else if ((fCurrentColor == "blue") && (fBlueReader == 0)) {
+                fBlueReader       = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
+            } else if ((fCurrentColor == "white") && (fRedReader == 0)
+                       && (fGreenReader == 0) && (fBlueReader == 0)) {
+                fRedReader        = new ZoneReader(zone, min, max);
+                fGreenReader      = new ZoneReader(zone, min, max);
+                fBlueReader       = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
             } else {
-                val = -1; // No mapping
-                curve = 0;
-                amin = -100.;
-                amid = 0.;
-                amax = 100.;
+                std::cerr << "incorrect screencolor metadata : " << fCurrentColor
+                          << std::endl;
             }
         }
+        fCurrentColor = "";
 
-     public:
-    
-        enum Type { kAcc = 0, kGyr = 1, kNoType };
-   
-        APIUI() : fNumParameters(0), fHasScreenControl(false), fRedReader(0), fGreenReader(0), fBlueReader(0), fCurrentScale(kLin)
-        {}
+        fMetaData.push_back(fCurrentMetadata);
+        fCurrentMetadata.clear();
+    }
 
-        virtual ~APIUI()
-        {
-            for (auto& it : fConversion) delete it;
-            for (int i = 0; i < 3; i++) {
-                for (auto& it : fAcc[i]) delete it;
-                for (auto& it : fGyr[i]) delete it;
+    int getZoneIndex(std::vector<ZoneControl*>* table, int p, int val)
+    {
+        FAUSTFLOAT* zone = fZone[p];
+        for (size_t i = 0; i < table[val].size(); i++) {
+            if (zone == table[val][i]->getZone()) return int(i);
+        }
+        return -1;
+    }
+
+    void setConverter(std::vector<ZoneControl*>* table, int p, int val, int curve,
+                      double amin, double amid, double amax)
+    {
+        int id1 = getZoneIndex(table, p, 0);
+        int id2 = getZoneIndex(table, p, 1);
+        int id3 = getZoneIndex(table, p, 2);
+
+        // Deactivates everywhere..
+        if (id1 != -1) table[0][id1]->setActive(false);
+        if (id2 != -1) table[1][id2]->setActive(false);
+        if (id3 != -1) table[2][id3]->setActive(false);
+
+        if (val == -1) {  // Means: no more mapping...
+            // So stay all deactivated...
+        } else {
+            int id4 = getZoneIndex(table, p, val);
+            if (id4 != -1) {
+                // Reactivate the one we edit...
+                table[val][id4]->setMappingValues(curve, amin, amid, amax, fMin[p],
+                                                  fInit[p], fMax[p]);
+                table[val][id4]->setActive(true);
+            } else {
+                // Allocate a new CurveZoneControl which is 'active' by default
+                FAUSTFLOAT* zone = fZone[p];
+                table[val].push_back(new CurveZoneControl(zone, curve, amin, amid, amax,
+                                                          fMin[p], fInit[p], fMax[p]));
             }
-            delete fRedReader;
-            delete fGreenReader;
-            delete fBlueReader;
         }
-    
-        // -- widget's layouts
-
-        virtual void openTabBox(const char* label) { pushLabel(label); }
-        virtual void openHorizontalBox(const char* label) { pushLabel(label); }
-        virtual void openVerticalBox(const char* label) { pushLabel(label); }
-        virtual void closeBox() { popLabel(); }
-
-        // -- active widgets
-
-        virtual void addButton(const char* label, FAUSTFLOAT* zone)
-        {
-            addParameter(label, zone, 0, 0, 1, 1, kButton);
+    }
+
+    void getConverter(std::vector<ZoneControl*>* table, int p, int& val, int& curve,
+                      double& amin, double& amid, double& amax)
+    {
+        int id1 = getZoneIndex(table, p, 0);
+        int id2 = getZoneIndex(table, p, 1);
+        int id3 = getZoneIndex(table, p, 2);
+
+        if (id1 != -1) {
+            val   = 0;
+            curve = table[val][id1]->getCurve();
+            table[val][id1]->getMappingValues(amin, amid, amax);
+        } else if (id2 != -1) {
+            val   = 1;
+            curve = table[val][id2]->getCurve();
+            table[val][id2]->getMappingValues(amin, amid, amax);
+        } else if (id3 != -1) {
+            val   = 2;
+            curve = table[val][id3]->getCurve();
+            table[val][id3]->getMappingValues(amin, amid, amax);
+        } else {
+            val   = -1;  // No mapping
+            curve = 0;
+            amin  = -100.;
+            amid  = 0.;
+            amax  = 100.;
         }
-
-        virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
-        {
-            addParameter(label, zone, 0, 0, 1, 1, kCheckButton);
+    }
+
+   public:
+    enum Type { kAcc = 0, kGyr = 1, kNoType };
+
+    APIUI()
+        : fNumParameters(0)
+        , fHasScreenControl(false)
+        , fRedReader(0)
+        , fGreenReader(0)
+        , fBlueReader(0)
+        , fCurrentScale(kLin)
+    {
+    }
+
+    virtual ~APIUI()
+    {
+        for (auto& it : fConversion) delete it;
+        for (int i = 0; i < 3; i++) {
+            for (auto& it : fAcc[i]) delete it;
+            for (auto& it : fGyr[i]) delete it;
         }
+        delete fRedReader;
+        delete fGreenReader;
+        delete fBlueReader;
+    }
 
-        virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
-        {
-            addParameter(label, zone, init, min, max, step, kVSlider);
-        }
+    // -- widget's layouts
 
-        virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
-        {
-            addParameter(label, zone, init, min, max, step, kHSlider);
-        }
+    virtual void openTabBox(const char* label) { pushLabel(label); }
+    virtual void openHorizontalBox(const char* label) { pushLabel(label); }
+    virtual void openVerticalBox(const char* label) { pushLabel(label); }
+    virtual void closeBox() { popLabel(); }
 
-        virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
-        {
-            addParameter(label, zone, init, min, max, step, kNumEntry);
-        }
+    // -- active widgets
 
-        // -- passive widgets
+    virtual void addButton(const char* label, FAUSTFLOAT* zone)
+    {
+        addParameter(label, zone, 0, 0, 1, 1, kButton);
+    }
+
+    virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
+    {
+        addParameter(label, zone, 0, 0, 1, 1, kCheckButton);
+    }
+
+    virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                                   FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+    {
+        addParameter(label, zone, init, min, max, step, kVSlider);
+    }
+
+    virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                                     FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+    {
+        addParameter(label, zone, init, min, max, step, kHSlider);
+    }
+
+    virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                             FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+    {
+        addParameter(label, zone, init, min, max, step, kNumEntry);
+    }
 
-        virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
-        {
-            addParameter(label, zone, min, min, max, (max-min)/1000.0, kHBargraph);
-        }
+    // -- passive widgets
 
-        virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
-        {
-            addParameter(label, zone, min, min, max, (max-min)/1000.0, kVBargraph);
-        }
-    
-        // -- soundfiles
-    
-        virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) {}
+    virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone,
+                                       FAUSTFLOAT min, FAUSTFLOAT max)
+    {
+        addParameter(label, zone, min, min, max, (max - min) / 1000.0, kHBargraph);
+    }
 
-        // -- metadata declarations
+    virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min,
+                                     FAUSTFLOAT max)
+    {
+        addParameter(label, zone, min, min, max, (max - min) / 1000.0, kVBargraph);
+    }
 
-        virtual void declare(FAUSTFLOAT* zone, const char* key, const char* val)
-        {
-            // Keep metadata
-            fCurrentMetadata[key] = val;
-            
-            if (strcmp(key, "scale") == 0) {
-                if (strcmp(val, "log") == 0) {
-                    fCurrentScale = kLog;
-                } else if (strcmp(val, "exp") == 0) {
-                    fCurrentScale = kExp;
-                } else {
-                    fCurrentScale = kLin;
-                }
-            } else if (strcmp(key, "unit") == 0) {
-                fCurrentUnit = val;
-            } else if (strcmp(key, "acc") == 0) {
-                fCurrentAcc = val;
-            } else if (strcmp(key, "gyr") == 0) {
-                fCurrentGyr = val;
-            } else if (strcmp(key, "screencolor") == 0) {
-                fCurrentColor = val; // val = "red", "green", "blue" or "white"
-            } else if (strcmp(key, "tooltip") == 0) {
-                fCurrentTooltip = val;
-            }
-        }
+    // -- soundfiles
 
-        virtual void declare(const char* key, const char* val)
-        {}
+    virtual void addSoundfile(const char* label, const char* filename,
+                              Soundfile** sf_zone)
+    {
+    }
 
-               //-------------------------------------------------------------------------------
-               // Simple API part
-               //-------------------------------------------------------------------------------
-               int getParamsCount() { return fNumParameters; }
-        int getParamIndex(const char* path)
-        {
-            if (fPathMap.find(path) != fPathMap.end()) {
-                return fPathMap[path];
-            } else if (fLabelMap.find(path) != fLabelMap.end()) {
-                return fLabelMap[path];
-            } else {
-                return -1;
-            }
-        }
-        const char* getParamAddress(int p) { return fPaths[p].c_str(); }
-        const char* getParamLabel(int p) { return fLabels[p].c_str(); }
-        std::map<const char*, const char*> getMetadata(int p)
-        {
-            std::map<const char*, const char*> res;
-            std::map<std::string, std::string> metadata = fMetaData[p];
-            for (auto it : metadata) {
-                res[it.first.c_str()] = it.second.c_str();
-            }
-            return res;
-        }
+    // -- metadata declarations
 
-        const char* getMetadata(int p, const char* key)
-        {
-            return (fMetaData[p].find(key) != fMetaData[p].end()) ? fMetaData[p][key].c_str() : "";
-        }
-        FAUSTFLOAT getParamMin(int p) { return fMin[p]; }
-        FAUSTFLOAT getParamMax(int p) { return fMax[p]; }
-        FAUSTFLOAT getParamStep(int p) { return fStep[p]; }
-        FAUSTFLOAT getParamInit(int p) { return fInit[p]; }
-
-        FAUSTFLOAT* getParamZone(int p) { return fZone[p]; }
-        FAUSTFLOAT getParamValue(int p) { return *fZone[p]; }
-        void setParamValue(int p, FAUSTFLOAT v) { *fZone[p] = v; }
-
-        double getParamRatio(int p) { return fConversion[p]->faust2ui(*fZone[p]); }
-        void setParamRatio(int p, double r) { *fZone[p] = fConversion[p]->ui2faust(r); }
-
-        double value2ratio(int p, double r)    { return fConversion[p]->faust2ui(r); }
-        double ratio2value(int p, double r)    { return fConversion[p]->ui2faust(r); }
-    
-        /**
-         * Return the control type (kAcc, kGyr, or -1) for a given parameter
-         *
-         * @param p - the UI parameter index
-         *
-         * @return the type
-         */
-        Type getParamType(int p)
-        {
-            if (p >= 0) {
-                if (getZoneIndex(fAcc, p, 0) != -1
-                    || getZoneIndex(fAcc, p, 1) != -1
-                    || getZoneIndex(fAcc, p, 2) != -1) {
-                    return kAcc;
-                } else if (getZoneIndex(fGyr, p, 0) != -1
-                           || getZoneIndex(fGyr, p, 1) != -1
-                           || getZoneIndex(fGyr, p, 2) != -1) {
-                    return kGyr;
-                }
-            }
-            return kNoType;
-        }
-    
-        /**
-         * Return the Item type (kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph) for a given parameter
-         *
-         * @param p - the UI parameter index
-         *
-         * @return the Item type
-         */
-        ItemType getParamItemType(int p)
-        {
-            return fItemType[p];
-        }
-   
-        /**
-         * Set a new value coming from an accelerometer, propagate it to all relevant FAUSTFLOAT* zones.
-         *
-         * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
-         * @param value - the new value
-         *
-         */
-        void propagateAcc(int acc, double value)
-        {
-            for (size_t i = 0; i < fAcc[acc].size(); i++) {
-                fAcc[acc][i]->update(value);
-            }
-        }
-    
-        /**
-         * Used to edit accelerometer curves and mapping. Set curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer (-1 means "no mapping")
-         * @param curve - between 0 and 3
-         * @param amin - mapping 'min' point
-         * @param amid - mapping 'middle' point
-         * @param amax - mapping 'max' point
-         *
-         */
-        void setAccConverter(int p, int acc, int curve, double amin, double amid, double amax)
-        {
-            setConverter(fAcc, p, acc, curve, amin, amid, amax);
-        }
-    
-        /**
-         * Used to edit gyroscope curves and mapping. Set curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param acc - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope (-1 means "no mapping")
-         * @param curve - between 0 and 3
-         * @param amin - mapping 'min' point
-         * @param amid - mapping 'middle' point
-         * @param amax - mapping 'max' point
-         *
-         */
-        void setGyrConverter(int p, int gyr, int curve, double amin, double amid, double amax)
-        {
-             setConverter(fGyr, p, gyr, curve, amin, amid, amax);
-        }
-    
-        /**
-         * Used to edit accelerometer curves and mapping. Get curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param acc - the acc value to be retrieved (-1 means "no mapping")
-         * @param curve - the curve value to be retrieved
-         * @param amin - the amin value to be retrieved
-         * @param amid - the amid value to be retrieved
-         * @param amax - the amax value to be retrieved
-         *
-         */
-        void getAccConverter(int p, int& acc, int& curve, double& amin, double& amid, double& amax)
-        {
-            getConverter(fAcc, p, acc, curve, amin, amid, amax);
-        }
+    virtual void declare(FAUSTFLOAT* zone, const char* key, const char* val)
+    {
+        // Keep metadata
+        fCurrentMetadata[key] = val;
 
-        /**
-         * Used to edit gyroscope curves and mapping. Get curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param gyr - the gyr value to be retrieved (-1 means "no mapping")
-         * @param curve - the curve value to be retrieved
-         * @param amin - the amin value to be retrieved
-         * @param amid - the amid value to be retrieved
-         * @param amax - the amax value to be retrieved
-         *
-         */
-        void getGyrConverter(int p, int& gyr, int& curve, double& amin, double& amid, double& amax)
-        {
-            getConverter(fGyr, p, gyr, curve, amin, amid, amax);
-        }
-    
-        /**
-         * Set a new value coming from an gyroscope, propagate it to all relevant FAUSTFLOAT* zones.
-         *
-         * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
-         * @param value - the new value
-         *
-         */
-        void propagateGyr(int gyr, double value)
-        {
-            for (size_t i = 0; i < fGyr[gyr].size(); i++) {
-                fGyr[gyr][i]->update(value);
+        if (strcmp(key, "scale") == 0) {
+            if (strcmp(val, "log") == 0) {
+                fCurrentScale = kLog;
+            } else if (strcmp(val, "exp") == 0) {
+                fCurrentScale = kExp;
+            } else {
+                fCurrentScale = kLin;
             }
+        } else if (strcmp(key, "unit") == 0) {
+            fCurrentUnit = val;
+        } else if (strcmp(key, "acc") == 0) {
+            fCurrentAcc = val;
+        } else if (strcmp(key, "gyr") == 0) {
+            fCurrentGyr = val;
+        } else if (strcmp(key, "screencolor") == 0) {
+            fCurrentColor = val;  // val = "red", "green", "blue" or "white"
+        } else if (strcmp(key, "tooltip") == 0) {
+            fCurrentTooltip = val;
         }
-    
-        /**
-         * Get the number of FAUSTFLOAT* zones controlled with the accelerometer
-         *
-         * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
-         * @return the number of zones
-         *
-         */
-        int getAccCount(int acc)
-        {
-            return (acc >= 0 && acc < 3) ? int(fAcc[acc].size()) : 0;
-        }
-    
-        /**
-         * Get the number of FAUSTFLOAT* zones controlled with the gyroscope
-         *
-         * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
-         * @param the number of zones
-         *
-         */
-        int getGyrCount(int gyr)
-        {
-            return (gyr >= 0 && gyr < 3) ? int(fGyr[gyr].size()) : 0;
+    }
+
+    virtual void declare(const char* key, const char* val) {}
+
+    //-------------------------------------------------------------------------------
+    // Simple API part
+    //-------------------------------------------------------------------------------
+    int getParamsCount() { return fNumParameters; }
+    int getParamIndex(const char* path)
+    {
+        if (fPathMap.find(path) != fPathMap.end()) {
+            return fPathMap[path];
+        } else if (fLabelMap.find(path) != fLabelMap.end()) {
+            return fLabelMap[path];
+        } else {
+            return -1;
         }
-   
-        // getScreenColor() : -1 means no screen color control (no screencolor metadata found)
-        // otherwise return 0x00RRGGBB a ready to use color
-        int getScreenColor()
-        {
-            if (fHasScreenControl) {
-                int r = (fRedReader) ? fRedReader->getValue() : 0;
-                int g = (fGreenReader) ? fGreenReader->getValue() : 0;
-                int b = (fBlueReader) ? fBlueReader->getValue() : 0;
-                return (r<<16) | (g<<8) | b;
-            } else {
-                return -1;
+    }
+    const char* getParamAddress(int p) { return fPaths[p].c_str(); }
+    const char* getParamLabel(int p) { return fLabels[p].c_str(); }
+    std::map<const char*, const char*> getMetadata(int p)
+    {
+        std::map<const char*, const char*> res;
+        std::map<std::string, std::string> metadata = fMetaData[p];
+        for (auto it : metadata) { res[it.first.c_str()] = it.second.c_str(); }
+        return res;
+    }
+
+    const char* getMetadata(int p, const char* key)
+    {
+        return (fMetaData[p].find(key) != fMetaData[p].end()) ? fMetaData[p][key].c_str()
+                                                              : "";
+    }
+    FAUSTFLOAT getParamMin(int p) { return fMin[p]; }
+    FAUSTFLOAT getParamMax(int p) { return fMax[p]; }
+    FAUSTFLOAT getParamStep(int p) { return fStep[p]; }
+    FAUSTFLOAT getParamInit(int p) { return fInit[p]; }
+
+    FAUSTFLOAT* getParamZone(int p) { return fZone[p]; }
+    FAUSTFLOAT getParamValue(int p) { return *fZone[p]; }
+    void setParamValue(int p, FAUSTFLOAT v) { *fZone[p] = v; }
+
+    double getParamRatio(int p) { return fConversion[p]->faust2ui(*fZone[p]); }
+    void setParamRatio(int p, double r) { *fZone[p] = fConversion[p]->ui2faust(r); }
+
+    double value2ratio(int p, double r) { return fConversion[p]->faust2ui(r); }
+    double ratio2value(int p, double r) { return fConversion[p]->ui2faust(r); }
+
+    /**
+     * Return the control type (kAcc, kGyr, or -1) for a given parameter
+     *
+     * @param p - the UI parameter index
+     *
+     * @return the type
+     */
+    Type getParamType(int p)
+    {
+        if (p >= 0) {
+            if (getZoneIndex(fAcc, p, 0) != -1 || getZoneIndex(fAcc, p, 1) != -1
+                || getZoneIndex(fAcc, p, 2) != -1) {
+                return kAcc;
+            } else if (getZoneIndex(fGyr, p, 0) != -1 || getZoneIndex(fGyr, p, 1) != -1
+                       || getZoneIndex(fGyr, p, 2) != -1) {
+                return kGyr;
             }
         }
+        return kNoType;
+    }
+
+    /**
+     * Return the Item type (kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry,
+     * kHBargraph, kVBargraph) for a given parameter
+     *
+     * @param p - the UI parameter index
+     *
+     * @return the Item type
+     */
+    ItemType getParamItemType(int p) { return fItemType[p]; }
+
+    /**
+     * Set a new value coming from an accelerometer, propagate it to all relevant
+     * FAUSTFLOAT* zones.
+     *
+     * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+     * @param value - the new value
+     *
+     */
+    void propagateAcc(int acc, double value)
+    {
+        for (size_t i = 0; i < fAcc[acc].size(); i++) { fAcc[acc][i]->update(value); }
+    }
+
+    /**
+     * Used to edit accelerometer curves and mapping. Set curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+     * (-1 means "no mapping")
+     * @param curve - between 0 and 3
+     * @param amin - mapping 'min' point
+     * @param amid - mapping 'middle' point
+     * @param amax - mapping 'max' point
+     *
+     */
+    void setAccConverter(int p, int acc, int curve, double amin, double amid, double amax)
+    {
+        setConverter(fAcc, p, acc, curve, amin, amid, amax);
+    }
+
+    /**
+     * Used to edit gyroscope curves and mapping. Set curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param acc - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope (-1 means "no
+     * mapping")
+     * @param curve - between 0 and 3
+     * @param amin - mapping 'min' point
+     * @param amid - mapping 'middle' point
+     * @param amax - mapping 'max' point
+     *
+     */
+    void setGyrConverter(int p, int gyr, int curve, double amin, double amid, double amax)
+    {
+        setConverter(fGyr, p, gyr, curve, amin, amid, amax);
+    }
+
+    /**
+     * Used to edit accelerometer curves and mapping. Get curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param acc - the acc value to be retrieved (-1 means "no mapping")
+     * @param curve - the curve value to be retrieved
+     * @param amin - the amin value to be retrieved
+     * @param amid - the amid value to be retrieved
+     * @param amax - the amax value to be retrieved
+     *
+     */
+    void getAccConverter(int p, int& acc, int& curve, double& amin, double& amid,
+                         double& amax)
+    {
+        getConverter(fAcc, p, acc, curve, amin, amid, amax);
+    }
+
+    /**
+     * Used to edit gyroscope curves and mapping. Get curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param gyr - the gyr value to be retrieved (-1 means "no mapping")
+     * @param curve - the curve value to be retrieved
+     * @param amin - the amin value to be retrieved
+     * @param amid - the amid value to be retrieved
+     * @param amax - the amax value to be retrieved
+     *
+     */
+    void getGyrConverter(int p, int& gyr, int& curve, double& amin, double& amid,
+                         double& amax)
+    {
+        getConverter(fGyr, p, gyr, curve, amin, amid, amax);
+    }
+
+    /**
+     * Set a new value coming from an gyroscope, propagate it to all relevant FAUSTFLOAT*
+     * zones.
+     *
+     * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+     * @param value - the new value
+     *
+     */
+    void propagateGyr(int gyr, double value)
+    {
+        for (size_t i = 0; i < fGyr[gyr].size(); i++) { fGyr[gyr][i]->update(value); }
+    }
+
+    /**
+     * Get the number of FAUSTFLOAT* zones controlled with the accelerometer
+     *
+     * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+     * @return the number of zones
+     *
+     */
+    int getAccCount(int acc) { return (acc >= 0 && acc < 3) ? int(fAcc[acc].size()) : 0; }
+
+    /**
+     * Get the number of FAUSTFLOAT* zones controlled with the gyroscope
+     *
+     * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+     * @param the number of zones
+     *
+     */
+    int getGyrCount(int gyr) { return (gyr >= 0 && gyr < 3) ? int(fGyr[gyr].size()) : 0; }
+
+    // getScreenColor() : -1 means no screen color control (no screencolor metadata found)
+    // otherwise return 0x00RRGGBB a ready to use color
+    int getScreenColor()
+    {
+        if (fHasScreenControl) {
+            int r = (fRedReader) ? fRedReader->getValue() : 0;
+            int g = (fGreenReader) ? fGreenReader->getValue() : 0;
+            int b = (fBlueReader) ? fBlueReader->getValue() : 0;
+            return (r << 16) | (g << 8) | b;
+        } else {
+            return -1;
+        }
+    }
 };
 
 #endif
@@ -1550,826 +1583,883 @@ class APIUI : public PathBuilder, public Meta, public UI
 //  FAUST Generated Code
 //----------------------------------------------------------------------------
 
-
 #ifndef FAUSTFLOAT
 #define FAUSTFLOAT float
-#endif 
+#endif
 
 #include <algorithm>
 #include <cmath>
-#include <math.h>
 
-static float zitarevdsp_faustpower2_f(float value) {
-       return (value * value);
-}
+static float zitarevdsp_faustpower2_f(float value) { return (value * value); }
 
-#ifndef FAUSTCLASS 
+#ifndef FAUSTCLASS
 #define FAUSTCLASS zitarevdsp
 #endif
 
-#ifdef __APPLE__ 
+#ifdef __APPLE__
 #define exp10f __exp10f
-#define exp10 __exp10
+#define exp10  __exp10
 #endif
 
-class zitarevdsp : public dsp {
-       
- private:
-       
-       int IOTA;
-       float fVec0[16384];
-       float fVec1[16384];
-       FAUSTFLOAT fVslider0;
-       float fRec0[2];
-       FAUSTFLOAT fVslider1;
-       float fRec1[2];
-       int fSampleRate;
-       float fConst0;
-       float fConst1;
-       FAUSTFLOAT fVslider2;
-       FAUSTFLOAT fVslider3;
-       FAUSTFLOAT fVslider4;
-       FAUSTFLOAT fVslider5;
-       float fConst2;
-       float fConst3;
-       FAUSTFLOAT fVslider6;
-       FAUSTFLOAT fVslider7;
-       FAUSTFLOAT fVslider8;
-       float fConst4;
-       FAUSTFLOAT fVslider9;
-       float fRec15[2];
-       float fRec14[2];
-       float fVec2[32768];
-       float fConst5;
-       int iConst6;
-       float fConst7;
-       FAUSTFLOAT fVslider10;
-       float fVec3[2048];
-       int iConst8;
-       float fRec12[2];
-       float fConst9;
-       float fConst10;
-       float fRec19[2];
-       float fRec18[2];
-       float fVec4[32768];
-       float fConst11;
-       int iConst12;
-       float fVec5[4096];
-       int iConst13;
-       float fRec16[2];
-       float fConst14;
-       float fConst15;
-       float fRec23[2];
-       float fRec22[2];
-       float fVec6[16384];
-       float fConst16;
-       int iConst17;
-       float fVec7[4096];
-       int iConst18;
-       float fRec20[2];
-       float fConst19;
-       float fConst20;
-       float fRec27[2];
-       float fRec26[2];
-       float fVec8[32768];
-       float fConst21;
-       int iConst22;
-       float fVec9[4096];
-       int iConst23;
-       float fRec24[2];
-       float fConst24;
-       float fConst25;
-       float fRec31[2];
-       float fRec30[2];
-       float fVec10[16384];
-       float fConst26;
-       int iConst27;
-       float fVec11[2048];
-       int iConst28;
-       float fRec28[2];
-       float fConst29;
-       float fConst30;
-       float fRec35[2];
-       float fRec34[2];
-       float fVec12[16384];
-       float fConst31;
-       int iConst32;
-       float fVec13[4096];
-       int iConst33;
-       float fRec32[2];
-       float fConst34;
-       float fConst35;
-       float fRec39[2];
-       float fRec38[2];
-       float fVec14[16384];
-       float fConst36;
-       int iConst37;
-       float fVec15[4096];
-       int iConst38;
-       float fRec36[2];
-       float fConst39;
-       float fConst40;
-       float fRec43[2];
-       float fRec42[2];
-       float fVec16[16384];
-       float fConst41;
-       int iConst42;
-       float fVec17[2048];
-       int iConst43;
-       float fRec40[2];
-       float fRec4[3];
-       float fRec5[3];
-       float fRec6[3];
-       float fRec7[3];
-       float fRec8[3];
-       float fRec9[3];
-       float fRec10[3];
-       float fRec11[3];
-       float fRec3[3];
-       float fRec2[3];
-       float fRec45[3];
-       float fRec44[3];
-       
- public:
-       
-       void metadata(Meta* m) { 
-               m->declare("basics.lib/name", "Faust Basic Element Library");
-               m->declare("basics.lib/version", "0.1");
-               m->declare("delays.lib/name", "Faust Delay Library");
-               m->declare("delays.lib/version", "0.1");
-               m->declare("filename", "zitarevdsp.dsp");
-               m->declare("filters.lib/allpass_comb:author", "Julius O. Smith III");
-               m->declare("filters.lib/allpass_comb:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
-               m->declare("filters.lib/allpass_comb:license", "MIT-style STK-4.3 license");
-               m->declare("filters.lib/fir:author", "Julius O. Smith III");
-               m->declare("filters.lib/fir:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
-               m->declare("filters.lib/fir:license", "MIT-style STK-4.3 license");
-               m->declare("filters.lib/iir:author", "Julius O. Smith III");
-               m->declare("filters.lib/iir:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
-               m->declare("filters.lib/iir:license", "MIT-style STK-4.3 license");
-               m->declare("filters.lib/lowpass0_highpass1", "MIT-style STK-4.3 license");
-               m->declare("filters.lib/lowpass0_highpass1:author", "Julius O. Smith III");
-               m->declare("filters.lib/lowpass:author", "Julius O. Smith III");
-               m->declare("filters.lib/lowpass:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
-               m->declare("filters.lib/lowpass:license", "MIT-style STK-4.3 license");
-               m->declare("filters.lib/name", "Faust Filters Library");
-               m->declare("filters.lib/peak_eq_rm:author", "Julius O. Smith III");
-               m->declare("filters.lib/peak_eq_rm:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
-               m->declare("filters.lib/peak_eq_rm:license", "MIT-style STK-4.3 license");
-               m->declare("filters.lib/tf1:author", "Julius O. Smith III");
-               m->declare("filters.lib/tf1:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
-               m->declare("filters.lib/tf1:license", "MIT-style STK-4.3 license");
-               m->declare("filters.lib/tf1s:author", "Julius O. Smith III");
-               m->declare("filters.lib/tf1s:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
-               m->declare("filters.lib/tf1s:license", "MIT-style STK-4.3 license");
-               m->declare("filters.lib/tf2:author", "Julius O. Smith III");
-               m->declare("filters.lib/tf2:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
-               m->declare("filters.lib/tf2:license", "MIT-style STK-4.3 license");
-               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.3");
-               m->declare("name", "zitarevdsp");
-               m->declare("platform.lib/name", "Generic Platform Library");
-               m->declare("platform.lib/version", "0.1");
-               m->declare("reverbs.lib/name", "Faust Reverb Library");
-               m->declare("reverbs.lib/version", "0.0");
-               m->declare("routes.lib/name", "Faust Signal Routing Library");
-               m->declare("routes.lib/version", "0.2");
-               m->declare("signals.lib/name", "Faust Signal Routing Library");
-               m->declare("signals.lib/version", "0.0");
-       }
-
-       virtual int getNumInputs() {
-               return 2;
-       }
-       virtual int getNumOutputs() {
-               return 2;
-       }
-       virtual int getInputRate(int channel) {
-               int rate;
-               switch ((channel)) {
-                       case 0: {
-                               rate = 1;
-                               break;
-                       }
-                       case 1: {
-                               rate = 1;
-                               break;
-                       }
-                       default: {
-                               rate = -1;
-                               break;
-                       }
-               }
-               return rate;
-       }
-       virtual int getOutputRate(int channel) {
-               int rate;
-               switch ((channel)) {
-                       case 0: {
-                               rate = 1;
-                               break;
-                       }
-                       case 1: {
-                               rate = 1;
-                               break;
-                       }
-                       default: {
-                               rate = -1;
-                               break;
-                       }
-               }
-               return rate;
-       }
-       
-       static void classInit(int sample_rate) {
-       }
-       
-       virtual void instanceConstants(int sample_rate) {
-               fSampleRate = sample_rate;
-               fConst0 = std::min<float>(192000.0f, std::max<float>(1.0f, float(fSampleRate)));
-               fConst1 = (6.28318548f / fConst0);
-               fConst2 = std::floor(((0.219990999f * fConst0) + 0.5f));
-               fConst3 = ((0.0f - (6.90775537f * fConst2)) / fConst0);
-               fConst4 = (3.14159274f / fConst0);
-               fConst5 = std::floor(((0.0191229992f * fConst0) + 0.5f));
-               iConst6 = int(std::min<float>(16384.0f, std::max<float>(0.0f, (fConst2 - fConst5))));
-               fConst7 = (0.00100000005f * fConst0);
-               iConst8 = int(std::min<float>(1024.0f, std::max<float>(0.0f, (fConst5 + -1.0f))));
-               fConst9 = std::floor(((0.256891012f * fConst0) + 0.5f));
-               fConst10 = ((0.0f - (6.90775537f * fConst9)) / fConst0);
-               fConst11 = std::floor(((0.0273330007f * fConst0) + 0.5f));
-               iConst12 = int(std::min<float>(16384.0f, std::max<float>(0.0f, (fConst9 - fConst11))));
-               iConst13 = int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst11 + -1.0f))));
-               fConst14 = std::floor(((0.192303002f * fConst0) + 0.5f));
-               fConst15 = ((0.0f - (6.90775537f * fConst14)) / fConst0);
-               fConst16 = std::floor(((0.0292910002f * fConst0) + 0.5f));
-               iConst17 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst14 - fConst16))));
-               iConst18 = int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst16 + -1.0f))));
-               fConst19 = std::floor(((0.210389003f * fConst0) + 0.5f));
-               fConst20 = ((0.0f - (6.90775537f * fConst19)) / fConst0);
-               fConst21 = std::floor(((0.0244210009f * fConst0) + 0.5f));
-               iConst22 = int(std::min<float>(16384.0f, std::max<float>(0.0f, (fConst19 - fConst21))));
-               iConst23 = int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst21 + -1.0f))));
-               fConst24 = std::floor(((0.125f * fConst0) + 0.5f));
-               fConst25 = ((0.0f - (6.90775537f * fConst24)) / fConst0);
-               fConst26 = std::floor(((0.0134579996f * fConst0) + 0.5f));
-               iConst27 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst24 - fConst26))));
-               iConst28 = int(std::min<float>(1024.0f, std::max<float>(0.0f, (fConst26 + -1.0f))));
-               fConst29 = std::floor(((0.127837002f * fConst0) + 0.5f));
-               fConst30 = ((0.0f - (6.90775537f * fConst29)) / fConst0);
-               fConst31 = std::floor(((0.0316039994f * fConst0) + 0.5f));
-               iConst32 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst29 - fConst31))));
-               iConst33 = int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst31 + -1.0f))));
-               fConst34 = std::floor(((0.174713001f * fConst0) + 0.5f));
-               fConst35 = ((0.0f - (6.90775537f * fConst34)) / fConst0);
-               fConst36 = std::floor(((0.0229039993f * fConst0) + 0.5f));
-               iConst37 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst34 - fConst36))));
-               iConst38 = int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst36 + -1.0f))));
-               fConst39 = std::floor(((0.153128996f * fConst0) + 0.5f));
-               fConst40 = ((0.0f - (6.90775537f * fConst39)) / fConst0);
-               fConst41 = std::floor(((0.0203460008f * fConst0) + 0.5f));
-               iConst42 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst39 - fConst41))));
-               iConst43 = int(std::min<float>(1024.0f, std::max<float>(0.0f, (fConst41 + -1.0f))));
-       }
-       
-       virtual void instanceResetUserInterface() {
-               fVslider0 = FAUSTFLOAT(-3.0f);
-               fVslider1 = FAUSTFLOAT(0.0f);
-               fVslider2 = FAUSTFLOAT(1500.0f);
-               fVslider3 = FAUSTFLOAT(0.0f);
-               fVslider4 = FAUSTFLOAT(315.0f);
-               fVslider5 = FAUSTFLOAT(0.0f);
-               fVslider6 = FAUSTFLOAT(2.0f);
-               fVslider7 = FAUSTFLOAT(6000.0f);
-               fVslider8 = FAUSTFLOAT(3.0f);
-               fVslider9 = FAUSTFLOAT(200.0f);
-               fVslider10 = FAUSTFLOAT(60.0f);
-       }
-       
-       virtual void instanceClear() {
-               IOTA = 0;
-               for (int l0 = 0; (l0 < 16384); l0 = (l0 + 1)) {
-                       fVec0[l0] = 0.0f;
-               }
-               for (int l1 = 0; (l1 < 16384); l1 = (l1 + 1)) {
-                       fVec1[l1] = 0.0f;
-               }
-               for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) {
-                       fRec0[l2] = 0.0f;
-               }
-               for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) {
-                       fRec1[l3] = 0.0f;
-               }
-               for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) {
-                       fRec15[l4] = 0.0f;
-               }
-               for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) {
-                       fRec14[l5] = 0.0f;
-               }
-               for (int l6 = 0; (l6 < 32768); l6 = (l6 + 1)) {
-                       fVec2[l6] = 0.0f;
-               }
-               for (int l7 = 0; (l7 < 2048); l7 = (l7 + 1)) {
-                       fVec3[l7] = 0.0f;
-               }
-               for (int l8 = 0; (l8 < 2); l8 = (l8 + 1)) {
-                       fRec12[l8] = 0.0f;
-               }
-               for (int l9 = 0; (l9 < 2); l9 = (l9 + 1)) {
-                       fRec19[l9] = 0.0f;
-               }
-               for (int l10 = 0; (l10 < 2); l10 = (l10 + 1)) {
-                       fRec18[l10] = 0.0f;
-               }
-               for (int l11 = 0; (l11 < 32768); l11 = (l11 + 1)) {
-                       fVec4[l11] = 0.0f;
-               }
-               for (int l12 = 0; (l12 < 4096); l12 = (l12 + 1)) {
-                       fVec5[l12] = 0.0f;
-               }
-               for (int l13 = 0; (l13 < 2); l13 = (l13 + 1)) {
-                       fRec16[l13] = 0.0f;
-               }
-               for (int l14 = 0; (l14 < 2); l14 = (l14 + 1)) {
-                       fRec23[l14] = 0.0f;
-               }
-               for (int l15 = 0; (l15 < 2); l15 = (l15 + 1)) {
-                       fRec22[l15] = 0.0f;
-               }
-               for (int l16 = 0; (l16 < 16384); l16 = (l16 + 1)) {
-                       fVec6[l16] = 0.0f;
-               }
-               for (int l17 = 0; (l17 < 4096); l17 = (l17 + 1)) {
-                       fVec7[l17] = 0.0f;
-               }
-               for (int l18 = 0; (l18 < 2); l18 = (l18 + 1)) {
-                       fRec20[l18] = 0.0f;
-               }
-               for (int l19 = 0; (l19 < 2); l19 = (l19 + 1)) {
-                       fRec27[l19] = 0.0f;
-               }
-               for (int l20 = 0; (l20 < 2); l20 = (l20 + 1)) {
-                       fRec26[l20] = 0.0f;
-               }
-               for (int l21 = 0; (l21 < 32768); l21 = (l21 + 1)) {
-                       fVec8[l21] = 0.0f;
-               }
-               for (int l22 = 0; (l22 < 4096); l22 = (l22 + 1)) {
-                       fVec9[l22] = 0.0f;
-               }
-               for (int l23 = 0; (l23 < 2); l23 = (l23 + 1)) {
-                       fRec24[l23] = 0.0f;
-               }
-               for (int l24 = 0; (l24 < 2); l24 = (l24 + 1)) {
-                       fRec31[l24] = 0.0f;
-               }
-               for (int l25 = 0; (l25 < 2); l25 = (l25 + 1)) {
-                       fRec30[l25] = 0.0f;
-               }
-               for (int l26 = 0; (l26 < 16384); l26 = (l26 + 1)) {
-                       fVec10[l26] = 0.0f;
-               }
-               for (int l27 = 0; (l27 < 2048); l27 = (l27 + 1)) {
-                       fVec11[l27] = 0.0f;
-               }
-               for (int l28 = 0; (l28 < 2); l28 = (l28 + 1)) {
-                       fRec28[l28] = 0.0f;
-               }
-               for (int l29 = 0; (l29 < 2); l29 = (l29 + 1)) {
-                       fRec35[l29] = 0.0f;
-               }
-               for (int l30 = 0; (l30 < 2); l30 = (l30 + 1)) {
-                       fRec34[l30] = 0.0f;
-               }
-               for (int l31 = 0; (l31 < 16384); l31 = (l31 + 1)) {
-                       fVec12[l31] = 0.0f;
-               }
-               for (int l32 = 0; (l32 < 4096); l32 = (l32 + 1)) {
-                       fVec13[l32] = 0.0f;
-               }
-               for (int l33 = 0; (l33 < 2); l33 = (l33 + 1)) {
-                       fRec32[l33] = 0.0f;
-               }
-               for (int l34 = 0; (l34 < 2); l34 = (l34 + 1)) {
-                       fRec39[l34] = 0.0f;
-               }
-               for (int l35 = 0; (l35 < 2); l35 = (l35 + 1)) {
-                       fRec38[l35] = 0.0f;
-               }
-               for (int l36 = 0; (l36 < 16384); l36 = (l36 + 1)) {
-                       fVec14[l36] = 0.0f;
-               }
-               for (int l37 = 0; (l37 < 4096); l37 = (l37 + 1)) {
-                       fVec15[l37] = 0.0f;
-               }
-               for (int l38 = 0; (l38 < 2); l38 = (l38 + 1)) {
-                       fRec36[l38] = 0.0f;
-               }
-               for (int l39 = 0; (l39 < 2); l39 = (l39 + 1)) {
-                       fRec43[l39] = 0.0f;
-               }
-               for (int l40 = 0; (l40 < 2); l40 = (l40 + 1)) {
-                       fRec42[l40] = 0.0f;
-               }
-               for (int l41 = 0; (l41 < 16384); l41 = (l41 + 1)) {
-                       fVec16[l41] = 0.0f;
-               }
-               for (int l42 = 0; (l42 < 2048); l42 = (l42 + 1)) {
-                       fVec17[l42] = 0.0f;
-               }
-               for (int l43 = 0; (l43 < 2); l43 = (l43 + 1)) {
-                       fRec40[l43] = 0.0f;
-               }
-               for (int l44 = 0; (l44 < 3); l44 = (l44 + 1)) {
-                       fRec4[l44] = 0.0f;
-               }
-               for (int l45 = 0; (l45 < 3); l45 = (l45 + 1)) {
-                       fRec5[l45] = 0.0f;
-               }
-               for (int l46 = 0; (l46 < 3); l46 = (l46 + 1)) {
-                       fRec6[l46] = 0.0f;
-               }
-               for (int l47 = 0; (l47 < 3); l47 = (l47 + 1)) {
-                       fRec7[l47] = 0.0f;
-               }
-               for (int l48 = 0; (l48 < 3); l48 = (l48 + 1)) {
-                       fRec8[l48] = 0.0f;
-               }
-               for (int l49 = 0; (l49 < 3); l49 = (l49 + 1)) {
-                       fRec9[l49] = 0.0f;
-               }
-               for (int l50 = 0; (l50 < 3); l50 = (l50 + 1)) {
-                       fRec10[l50] = 0.0f;
-               }
-               for (int l51 = 0; (l51 < 3); l51 = (l51 + 1)) {
-                       fRec11[l51] = 0.0f;
-               }
-               for (int l52 = 0; (l52 < 3); l52 = (l52 + 1)) {
-                       fRec3[l52] = 0.0f;
-               }
-               for (int l53 = 0; (l53 < 3); l53 = (l53 + 1)) {
-                       fRec2[l53] = 0.0f;
-               }
-               for (int l54 = 0; (l54 < 3); l54 = (l54 + 1)) {
-                       fRec45[l54] = 0.0f;
-               }
-               for (int l55 = 0; (l55 < 3); l55 = (l55 + 1)) {
-                       fRec44[l55] = 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 zitarevdsp* clone() {
-               return new zitarevdsp();
-       }
-       
-       virtual int getSampleRate() {
-               return fSampleRate;
-       }
-       
-       virtual void buildUserInterface(UI* ui_interface) {
-               ui_interface->declare(0, "0", "");
-               ui_interface->declare(0, "tooltip", "~ ZITA REV1 FEEDBACK DELAY NETWORK (FDN) & SCHROEDER  ALLPASS-COMB REVERBERATOR (8x8). See Faust's reverbs.lib for documentation and  references");
-               ui_interface->openHorizontalBox("Zita_Rev1");
-               ui_interface->declare(0, "1", "");
-               ui_interface->openHorizontalBox("Input");
-               ui_interface->declare(&fVslider10, "1", "");
-               ui_interface->declare(&fVslider10, "style", "knob");
-               ui_interface->declare(&fVslider10, "tooltip", "Delay in ms   before reverberation begins");
-               ui_interface->declare(&fVslider10, "unit", "ms");
-               ui_interface->addVerticalSlider("In Delay", &fVslider10, 60.0f, 20.0f, 100.0f, 1.0f);
-               ui_interface->closeBox();
-               ui_interface->declare(0, "2", "");
-               ui_interface->openHorizontalBox("Decay Times in Bands (see tooltips)");
-               ui_interface->declare(&fVslider9, "1", "");
-               ui_interface->declare(&fVslider9, "scale", "log");
-               ui_interface->declare(&fVslider9, "style", "knob");
-               ui_interface->declare(&fVslider9, "tooltip", "Crossover frequency (Hz) separating low and middle frequencies");
-               ui_interface->declare(&fVslider9, "unit", "Hz");
-               ui_interface->addVerticalSlider("LF X", &fVslider9, 200.0f, 50.0f, 1000.0f, 1.0f);
-               ui_interface->declare(&fVslider8, "2", "");
-               ui_interface->declare(&fVslider8, "scale", "log");
-               ui_interface->declare(&fVslider8, "style", "knob");
-               ui_interface->declare(&fVslider8, "tooltip", "T60 = time (in seconds) to decay 60dB in low-frequency band");
-               ui_interface->declare(&fVslider8, "unit", "s");
-               ui_interface->addVerticalSlider("Low RT60", &fVslider8, 3.0f, 1.0f, 8.0f, 0.100000001f);
-               ui_interface->declare(&fVslider6, "3", "");
-               ui_interface->declare(&fVslider6, "scale", "log");
-               ui_interface->declare(&fVslider6, "style", "knob");
-               ui_interface->declare(&fVslider6, "tooltip", "T60 = time (in seconds) to decay 60dB in middle band");
-               ui_interface->declare(&fVslider6, "unit", "s");
-               ui_interface->addVerticalSlider("Mid RT60", &fVslider6, 2.0f, 1.0f, 8.0f, 0.100000001f);
-               ui_interface->declare(&fVslider7, "4", "");
-               ui_interface->declare(&fVslider7, "scale", "log");
-               ui_interface->declare(&fVslider7, "style", "knob");
-               ui_interface->declare(&fVslider7, "tooltip", "Frequency (Hz) at which the high-frequency T60 is half the middle-band's T60");
-               ui_interface->declare(&fVslider7, "unit", "Hz");
-               ui_interface->addVerticalSlider("HF Damping", &fVslider7, 6000.0f, 1500.0f, 23520.0f, 1.0f);
-               ui_interface->closeBox();
-               ui_interface->declare(0, "3", "");
-               ui_interface->openHorizontalBox("RM Peaking Equalizer 1");
-               ui_interface->declare(&fVslider4, "1", "");
-               ui_interface->declare(&fVslider4, "scale", "log");
-               ui_interface->declare(&fVslider4, "style", "knob");
-               ui_interface->declare(&fVslider4, "tooltip", "Center-frequency of second-order Regalia-Mitra peaking equalizer section 1");
-               ui_interface->declare(&fVslider4, "unit", "Hz");
-               ui_interface->addVerticalSlider("Eq1 Freq", &fVslider4, 315.0f, 40.0f, 2500.0f, 1.0f);
-               ui_interface->declare(&fVslider5, "2", "");
-               ui_interface->declare(&fVslider5, "style", "knob");
-               ui_interface->declare(&fVslider5, "tooltip", "Peak level   in dB of second-order Regalia-Mitra peaking equalizer section 1");
-               ui_interface->declare(&fVslider5, "unit", "dB");
-               ui_interface->addVerticalSlider("Eq1 Level", &fVslider5, 0.0f, -15.0f, 15.0f, 0.100000001f);
-               ui_interface->closeBox();
-               ui_interface->declare(0, "4", "");
-               ui_interface->openHorizontalBox("RM Peaking Equalizer 2");
-               ui_interface->declare(&fVslider2, "1", "");
-               ui_interface->declare(&fVslider2, "scale", "log");
-               ui_interface->declare(&fVslider2, "style", "knob");
-               ui_interface->declare(&fVslider2, "tooltip", "Center-frequency of second-order Regalia-Mitra peaking equalizer section 2");
-               ui_interface->declare(&fVslider2, "unit", "Hz");
-               ui_interface->addVerticalSlider("Eq2 Freq", &fVslider2, 1500.0f, 160.0f, 10000.0f, 1.0f);
-               ui_interface->declare(&fVslider3, "2", "");
-               ui_interface->declare(&fVslider3, "style", "knob");
-               ui_interface->declare(&fVslider3, "tooltip", "Peak level   in dB of second-order Regalia-Mitra peaking equalizer section 2");
-               ui_interface->declare(&fVslider3, "unit", "dB");
-               ui_interface->addVerticalSlider("Eq2 Level", &fVslider3, 0.0f, -15.0f, 15.0f, 0.100000001f);
-               ui_interface->closeBox();
-               ui_interface->declare(0, "5", "");
-               ui_interface->openHorizontalBox("Output");
-               ui_interface->declare(&fVslider1, "1", "");
-               ui_interface->declare(&fVslider1, "style", "knob");
-               ui_interface->declare(&fVslider1, "tooltip", "Dry/Wet Mix: 0 = dry, 1 = wet");
-               ui_interface->addVerticalSlider("Wet", &fVslider1, 0.0f, 0.0f, 1.0f, 0.00999999978f);
-               ui_interface->declare(&fVslider0, "2", "");
-               ui_interface->declare(&fVslider0, "style", "knob");
-               ui_interface->declare(&fVslider0, "tooltip", "Output scale   factor");
-               ui_interface->declare(&fVslider0, "unit", "dB");
-               ui_interface->addVerticalSlider("Level", &fVslider0, -3.0f, -70.0f, 20.0f, 0.100000001f);
-               ui_interface->closeBox();
-               ui_interface->closeBox();
-       }
-       
-       virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
-               FAUSTFLOAT* input0 = inputs[0];
-               FAUSTFLOAT* input1 = inputs[1];
-               FAUSTFLOAT* output0 = outputs[0];
-               FAUSTFLOAT* output1 = outputs[1];
-               float fSlow0 = (0.00100000005f * std::pow(10.0f, (0.0500000007f * float(fVslider0))));
-               float fSlow1 = (0.00100000005f * float(fVslider1));
-               float fSlow2 = float(fVslider2);
-               float fSlow3 = std::pow(10.0f, (0.0500000007f * float(fVslider3)));
-               float fSlow4 = (fConst1 * (fSlow2 / std::sqrt(std::max<float>(0.0f, fSlow3))));
-               float fSlow5 = ((1.0f - fSlow4) / (fSlow4 + 1.0f));
-               float fSlow6 = float(fVslider4);
-               float fSlow7 = std::pow(10.0f, (0.0500000007f * float(fVslider5)));
-               float fSlow8 = (fConst1 * (fSlow6 / std::sqrt(std::max<float>(0.0f, fSlow7))));
-               float fSlow9 = ((1.0f - fSlow8) / (fSlow8 + 1.0f));
-               float fSlow10 = float(fVslider6);
-               float fSlow11 = std::exp((fConst3 / fSlow10));
-               float fSlow12 = zitarevdsp_faustpower2_f(fSlow11);
-               float fSlow13 = std::cos((fConst1 * float(fVslider7)));
-               float fSlow14 = (1.0f - (fSlow12 * fSlow13));
-               float fSlow15 = (1.0f - fSlow12);
-               float fSlow16 = (fSlow14 / fSlow15);
-               float fSlow17 = std::sqrt(std::max<float>(0.0f, ((zitarevdsp_faustpower2_f(fSlow14) / zitarevdsp_faustpower2_f(fSlow15)) + -1.0f)));
-               float fSlow18 = (fSlow16 - fSlow17);
-               float fSlow19 = (fSlow11 * (fSlow17 + (1.0f - fSlow16)));
-               float fSlow20 = float(fVslider8);
-               float fSlow21 = ((std::exp((fConst3 / fSlow20)) / fSlow11) + -1.0f);
-               float fSlow22 = (1.0f / std::tan((fConst4 * float(fVslider9))));
-               float fSlow23 = (1.0f / (fSlow22 + 1.0f));
-               float fSlow24 = (1.0f - fSlow22);
-               int iSlow25 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst7 * float(fVslider10)))));
-               float fSlow26 = std::exp((fConst10 / fSlow10));
-               float fSlow27 = zitarevdsp_faustpower2_f(fSlow26);
-               float fSlow28 = (1.0f - (fSlow27 * fSlow13));
-               float fSlow29 = (1.0f - fSlow27);
-               float fSlow30 = (fSlow28 / fSlow29);
-               float fSlow31 = std::sqrt(std::max<float>(0.0f, ((zitarevdsp_faustpower2_f(fSlow28) / zitarevdsp_faustpower2_f(fSlow29)) + -1.0f)));
-               float fSlow32 = (fSlow30 - fSlow31);
-               float fSlow33 = (fSlow26 * (fSlow31 + (1.0f - fSlow30)));
-               float fSlow34 = ((std::exp((fConst10 / fSlow20)) / fSlow26) + -1.0f);
-               float fSlow35 = std::exp((fConst15 / fSlow10));
-               float fSlow36 = zitarevdsp_faustpower2_f(fSlow35);
-               float fSlow37 = (1.0f - (fSlow36 * fSlow13));
-               float fSlow38 = (1.0f - fSlow36);
-               float fSlow39 = (fSlow37 / fSlow38);
-               float fSlow40 = std::sqrt(std::max<float>(0.0f, ((zitarevdsp_faustpower2_f(fSlow37) / zitarevdsp_faustpower2_f(fSlow38)) + -1.0f)));
-               float fSlow41 = (fSlow39 - fSlow40);
-               float fSlow42 = (fSlow35 * (fSlow40 + (1.0f - fSlow39)));
-               float fSlow43 = ((std::exp((fConst15 / fSlow20)) / fSlow35) + -1.0f);
-               float fSlow44 = std::exp((fConst20 / fSlow10));
-               float fSlow45 = zitarevdsp_faustpower2_f(fSlow44);
-               float fSlow46 = (1.0f - (fSlow45 * fSlow13));
-               float fSlow47 = (1.0f - fSlow45);
-               float fSlow48 = (fSlow46 / fSlow47);
-               float fSlow49 = std::sqrt(std::max<float>(0.0f, ((zitarevdsp_faustpower2_f(fSlow46) / zitarevdsp_faustpower2_f(fSlow47)) + -1.0f)));
-               float fSlow50 = (fSlow48 - fSlow49);
-               float fSlow51 = (fSlow44 * (fSlow49 + (1.0f - fSlow48)));
-               float fSlow52 = ((std::exp((fConst20 / fSlow20)) / fSlow44) + -1.0f);
-               float fSlow53 = std::exp((fConst25 / fSlow10));
-               float fSlow54 = zitarevdsp_faustpower2_f(fSlow53);
-               float fSlow55 = (1.0f - (fSlow54 * fSlow13));
-               float fSlow56 = (1.0f - fSlow54);
-               float fSlow57 = (fSlow55 / fSlow56);
-               float fSlow58 = std::sqrt(std::max<float>(0.0f, ((zitarevdsp_faustpower2_f(fSlow55) / zitarevdsp_faustpower2_f(fSlow56)) + -1.0f)));
-               float fSlow59 = (fSlow57 - fSlow58);
-               float fSlow60 = (fSlow53 * (fSlow58 + (1.0f - fSlow57)));
-               float fSlow61 = ((std::exp((fConst25 / fSlow20)) / fSlow53) + -1.0f);
-               float fSlow62 = std::exp((fConst30 / fSlow10));
-               float fSlow63 = zitarevdsp_faustpower2_f(fSlow62);
-               float fSlow64 = (1.0f - (fSlow63 * fSlow13));
-               float fSlow65 = (1.0f - fSlow63);
-               float fSlow66 = (fSlow64 / fSlow65);
-               float fSlow67 = std::sqrt(std::max<float>(0.0f, ((zitarevdsp_faustpower2_f(fSlow64) / zitarevdsp_faustpower2_f(fSlow65)) + -1.0f)));
-               float fSlow68 = (fSlow66 - fSlow67);
-               float fSlow69 = (fSlow62 * (fSlow67 + (1.0f - fSlow66)));
-               float fSlow70 = ((std::exp((fConst30 / fSlow20)) / fSlow62) + -1.0f);
-               float fSlow71 = std::exp((fConst35 / fSlow10));
-               float fSlow72 = zitarevdsp_faustpower2_f(fSlow71);
-               float fSlow73 = (1.0f - (fSlow72 * fSlow13));
-               float fSlow74 = (1.0f - fSlow72);
-               float fSlow75 = (fSlow73 / fSlow74);
-               float fSlow76 = std::sqrt(std::max<float>(0.0f, ((zitarevdsp_faustpower2_f(fSlow73) / zitarevdsp_faustpower2_f(fSlow74)) + -1.0f)));
-               float fSlow77 = (fSlow75 - fSlow76);
-               float fSlow78 = (fSlow71 * (fSlow76 + (1.0f - fSlow75)));
-               float fSlow79 = ((std::exp((fConst35 / fSlow20)) / fSlow71) + -1.0f);
-               float fSlow80 = std::exp((fConst40 / fSlow10));
-               float fSlow81 = zitarevdsp_faustpower2_f(fSlow80);
-               float fSlow82 = (1.0f - (fSlow81 * fSlow13));
-               float fSlow83 = (1.0f - fSlow81);
-               float fSlow84 = (fSlow82 / fSlow83);
-               float fSlow85 = std::sqrt(std::max<float>(0.0f, ((zitarevdsp_faustpower2_f(fSlow82) / zitarevdsp_faustpower2_f(fSlow83)) + -1.0f)));
-               float fSlow86 = (fSlow84 - fSlow85);
-               float fSlow87 = (fSlow80 * (fSlow85 + (1.0f - fSlow84)));
-               float fSlow88 = ((std::exp((fConst40 / fSlow20)) / fSlow80) + -1.0f);
-               float fSlow89 = (0.0f - (std::cos((fConst1 * fSlow6)) * (fSlow9 + 1.0f)));
-               float fSlow90 = (0.0f - (std::cos((fConst1 * fSlow2)) * (fSlow5 + 1.0f)));
-               for (int i = 0; (i < count); i = (i + 1)) {
-                       float fTemp0 = float(input0[i]);
-                       fVec0[(IOTA & 16383)] = fTemp0;
-                       float fTemp1 = float(input1[i]);
-                       fVec1[(IOTA & 16383)] = fTemp1;
-                       fRec0[0] = (fSlow0 + (0.999000013f * fRec0[1]));
-                       fRec1[0] = (fSlow1 + (0.999000013f * fRec1[1]));
-                       fRec15[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec15[1]) - (fRec11[1] + fRec11[2]))));
-                       fRec14[0] = ((fSlow18 * fRec14[1]) + (fSlow19 * (fRec11[1] + (fSlow21 * fRec15[0]))));
-                       fVec2[(IOTA & 32767)] = ((0.353553385f * fRec14[0]) + 9.99999968e-21f);
-                       float fTemp2 = (0.300000012f * fVec1[((IOTA - iSlow25) & 16383)]);
-                       float fTemp3 = (((0.600000024f * fRec12[1]) + fVec2[((IOTA - iConst6) & 32767)]) - fTemp2);
-                       fVec3[(IOTA & 2047)] = fTemp3;
-                       fRec12[0] = fVec3[((IOTA - iConst8) & 2047)];
-                       float fRec13 = (0.0f - (0.600000024f * fTemp3));
-                       fRec19[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec19[1]) - (fRec7[1] + fRec7[2]))));
-                       fRec18[0] = ((fSlow32 * fRec18[1]) + (fSlow33 * (fRec7[1] + (fSlow34 * fRec19[0]))));
-                       fVec4[(IOTA & 32767)] = ((0.353553385f * fRec18[0]) + 9.99999968e-21f);
-                       float fTemp4 = (((0.600000024f * fRec16[1]) + fVec4[((IOTA - iConst12) & 32767)]) - fTemp2);
-                       fVec5[(IOTA & 4095)] = fTemp4;
-                       fRec16[0] = fVec5[((IOTA - iConst13) & 4095)];
-                       float fRec17 = (0.0f - (0.600000024f * fTemp4));
-                       fRec23[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec23[1]) - (fRec9[1] + fRec9[2]))));
-                       fRec22[0] = ((fSlow41 * fRec22[1]) + (fSlow42 * (fRec9[1] + (fSlow43 * fRec23[0]))));
-                       fVec6[(IOTA & 16383)] = ((0.353553385f * fRec22[0]) + 9.99999968e-21f);
-                       float fTemp5 = (fVec6[((IOTA - iConst17) & 16383)] + (fTemp2 + (0.600000024f * fRec20[1])));
-                       fVec7[(IOTA & 4095)] = fTemp5;
-                       fRec20[0] = fVec7[((IOTA - iConst18) & 4095)];
-                       float fRec21 = (0.0f - (0.600000024f * fTemp5));
-                       fRec27[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec27[1]) - (fRec5[1] + fRec5[2]))));
-                       fRec26[0] = ((fSlow50 * fRec26[1]) + (fSlow51 * (fRec5[1] + (fSlow52 * fRec27[0]))));
-                       fVec8[(IOTA & 32767)] = ((0.353553385f * fRec26[0]) + 9.99999968e-21f);
-                       float fTemp6 = (fTemp2 + ((0.600000024f * fRec24[1]) + fVec8[((IOTA - iConst22) & 32767)]));
-                       fVec9[(IOTA & 4095)] = fTemp6;
-                       fRec24[0] = fVec9[((IOTA - iConst23) & 4095)];
-                       float fRec25 = (0.0f - (0.600000024f * fTemp6));
-                       fRec31[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec31[1]) - (fRec10[1] + fRec10[2]))));
-                       fRec30[0] = ((fSlow59 * fRec30[1]) + (fSlow60 * (fRec10[1] + (fSlow61 * fRec31[0]))));
-                       fVec10[(IOTA & 16383)] = ((0.353553385f * fRec30[0]) + 9.99999968e-21f);
-                       float fTemp7 = (0.300000012f * fVec0[((IOTA - iSlow25) & 16383)]);
-                       float fTemp8 = (fVec10[((IOTA - iConst27) & 16383)] - (fTemp7 + (0.600000024f * fRec28[1])));
-                       fVec11[(IOTA & 2047)] = fTemp8;
-                       fRec28[0] = fVec11[((IOTA - iConst28) & 2047)];
-                       float fRec29 = (0.600000024f * fTemp8);
-                       fRec35[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec35[1]) - (fRec6[1] + fRec6[2]))));
-                       fRec34[0] = ((fSlow68 * fRec34[1]) + (fSlow69 * (fRec6[1] + (fSlow70 * fRec35[0]))));
-                       fVec12[(IOTA & 16383)] = ((0.353553385f * fRec34[0]) + 9.99999968e-21f);
-                       float fTemp9 = (fVec12[((IOTA - iConst32) & 16383)] - (fTemp7 + (0.600000024f * fRec32[1])));
-                       fVec13[(IOTA & 4095)] = fTemp9;
-                       fRec32[0] = fVec13[((IOTA - iConst33) & 4095)];
-                       float fRec33 = (0.600000024f * fTemp9);
-                       fRec39[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec39[1]) - (fRec8[1] + fRec8[2]))));
-                       fRec38[0] = ((fSlow77 * fRec38[1]) + (fSlow78 * (fRec8[1] + (fSlow79 * fRec39[0]))));
-                       fVec14[(IOTA & 16383)] = ((0.353553385f * fRec38[0]) + 9.99999968e-21f);
-                       float fTemp10 = ((fTemp7 + fVec14[((IOTA - iConst37) & 16383)]) - (0.600000024f * fRec36[1]));
-                       fVec15[(IOTA & 4095)] = fTemp10;
-                       fRec36[0] = fVec15[((IOTA - iConst38) & 4095)];
-                       float fRec37 = (0.600000024f * fTemp10);
-                       fRec43[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec43[1]) - (fRec4[1] + fRec4[2]))));
-                       fRec42[0] = ((fSlow86 * fRec42[1]) + (fSlow87 * (fRec4[1] + (fSlow88 * fRec43[0]))));
-                       fVec16[(IOTA & 16383)] = ((0.353553385f * fRec42[0]) + 9.99999968e-21f);
-                       float fTemp11 = ((fVec16[((IOTA - iConst42) & 16383)] + fTemp7) - (0.600000024f * fRec40[1]));
-                       fVec17[(IOTA & 2047)] = fTemp11;
-                       fRec40[0] = fVec17[((IOTA - iConst43) & 2047)];
-                       float fRec41 = (0.600000024f * fTemp11);
-                       float fTemp12 = (fRec41 + fRec37);
-                       float fTemp13 = (fRec29 + (fRec33 + fTemp12));
-                       fRec4[0] = (fRec12[1] + (fRec16[1] + (fRec20[1] + (fRec24[1] + (fRec28[1] + (fRec32[1] + (fRec36[1] + (fRec40[1] + (fRec13 + (fRec17 + (fRec21 + (fRec25 + fTemp13))))))))))));
-                       fRec5[0] = ((fRec28[1] + (fRec32[1] + (fRec36[1] + (fRec40[1] + fTemp13)))) - (fRec12[1] + (fRec16[1] + (fRec20[1] + (fRec24[1] + (fRec13 + (fRec17 + (fRec25 + fRec21))))))));
-                       float fTemp14 = (fRec33 + fRec29);
-                       fRec6[0] = ((fRec20[1] + (fRec24[1] + (fRec36[1] + (fRec40[1] + (fRec21 + (fRec25 + fTemp12)))))) - (fRec12[1] + (fRec16[1] + (fRec28[1] + (fRec32[1] + (fRec13 + (fRec17 + fTemp14)))))));
-                       fRec7[0] = ((fRec12[1] + (fRec16[1] + (fRec36[1] + (fRec40[1] + (fRec13 + (fRec17 + fTemp12)))))) - (fRec20[1] + (fRec24[1] + (fRec28[1] + (fRec32[1] + (fRec21 + (fRec25 + fTemp14)))))));
-                       float fTemp15 = (fRec41 + fRec33);
-                       float fTemp16 = (fRec37 + fRec29);
-                       fRec8[0] = ((fRec16[1] + (fRec24[1] + (fRec32[1] + (fRec40[1] + (fRec17 + (fRec25 + fTemp15)))))) - (fRec12[1] + (fRec20[1] + (fRec28[1] + (fRec36[1] + (fRec13 + (fRec21 + fTemp16)))))));
-                       fRec9[0] = ((fRec12[1] + (fRec20[1] + (fRec32[1] + (fRec40[1] + (fRec13 + (fRec21 + fTemp15)))))) - (fRec16[1] + (fRec24[1] + (fRec28[1] + (fRec36[1] + (fRec17 + (fRec25 + fTemp16)))))));
-                       float fTemp17 = (fRec41 + fRec29);
-                       float fTemp18 = (fRec37 + fRec33);
-                       fRec10[0] = ((fRec12[1] + (fRec24[1] + (fRec28[1] + (fRec40[1] + (fRec13 + (fRec25 + fTemp17)))))) - (fRec16[1] + (fRec20[1] + (fRec32[1] + (fRec36[1] + (fRec17 + (fRec21 + fTemp18)))))));
-                       fRec11[0] = ((fRec16[1] + (fRec20[1] + (fRec28[1] + (fRec40[1] + (fRec17 + (fRec21 + fTemp17)))))) - (fRec12[1] + (fRec24[1] + (fRec32[1] + (fRec36[1] + (fRec13 + (fRec25 + fTemp18)))))));
-                       float fTemp19 = (0.370000005f * (fRec5[0] + fRec6[0]));
-                       float fTemp20 = (fSlow89 * fRec3[1]);
-                       fRec3[0] = (fTemp19 - (fTemp20 + (fSlow9 * fRec3[2])));
-                       float fTemp21 = (fSlow9 * fRec3[0]);
-                       float fTemp22 = (0.5f * ((fTemp21 + (fRec3[2] + (fTemp19 + fTemp20))) + (fSlow7 * ((fTemp21 + (fTemp20 + fRec3[2])) - fTemp19))));
-                       float fTemp23 = (fSlow90 * fRec2[1]);
-                       fRec2[0] = (fTemp22 - (fTemp23 + (fSlow5 * fRec2[2])));
-                       float fTemp24 = (fSlow5 * fRec2[0]);
-                       float fTemp25 = (1.0f - fRec1[0]);
-                       output0[i] = FAUSTFLOAT((fRec0[0] * ((0.5f * (fRec1[0] * ((fTemp24 + (fRec2[2] + (fTemp22 + fTemp23))) + (fSlow3 * ((fTemp24 + (fTemp23 + fRec2[2])) - fTemp22))))) + (fTemp0 * fTemp25))));
-                       float fTemp26 = (0.370000005f * (fRec5[0] - fRec6[0]));
-                       float fTemp27 = (fSlow89 * fRec45[1]);
-                       fRec45[0] = (fTemp26 - (fTemp27 + (fSlow9 * fRec45[2])));
-                       float fTemp28 = (fSlow9 * fRec45[0]);
-                       float fTemp29 = (0.5f * ((fTemp28 + (fRec45[2] + (fTemp26 + fTemp27))) + (fSlow7 * ((fTemp28 + (fTemp27 + fRec45[2])) - fTemp26))));
-                       float fTemp30 = (fSlow90 * fRec44[1]);
-                       fRec44[0] = (fTemp29 - (fTemp30 + (fSlow5 * fRec44[2])));
-                       float fTemp31 = (fSlow5 * fRec44[0]);
-                       output1[i] = FAUSTFLOAT((fRec0[0] * ((0.5f * (fRec1[0] * ((fTemp31 + (fRec44[2] + (fTemp29 + fTemp30))) + (fSlow3 * ((fTemp31 + (fTemp30 + fRec44[2])) - fTemp29))))) + (fTemp1 * fTemp25))));
-                       IOTA = (IOTA + 1);
-                       fRec0[1] = fRec0[0];
-                       fRec1[1] = fRec1[0];
-                       fRec15[1] = fRec15[0];
-                       fRec14[1] = fRec14[0];
-                       fRec12[1] = fRec12[0];
-                       fRec19[1] = fRec19[0];
-                       fRec18[1] = fRec18[0];
-                       fRec16[1] = fRec16[0];
-                       fRec23[1] = fRec23[0];
-                       fRec22[1] = fRec22[0];
-                       fRec20[1] = fRec20[0];
-                       fRec27[1] = fRec27[0];
-                       fRec26[1] = fRec26[0];
-                       fRec24[1] = fRec24[0];
-                       fRec31[1] = fRec31[0];
-                       fRec30[1] = fRec30[0];
-                       fRec28[1] = fRec28[0];
-                       fRec35[1] = fRec35[0];
-                       fRec34[1] = fRec34[0];
-                       fRec32[1] = fRec32[0];
-                       fRec39[1] = fRec39[0];
-                       fRec38[1] = fRec38[0];
-                       fRec36[1] = fRec36[0];
-                       fRec43[1] = fRec43[0];
-                       fRec42[1] = fRec42[0];
-                       fRec40[1] = fRec40[0];
-                       fRec4[2] = fRec4[1];
-                       fRec4[1] = fRec4[0];
-                       fRec5[2] = fRec5[1];
-                       fRec5[1] = fRec5[0];
-                       fRec6[2] = fRec6[1];
-                       fRec6[1] = fRec6[0];
-                       fRec7[2] = fRec7[1];
-                       fRec7[1] = fRec7[0];
-                       fRec8[2] = fRec8[1];
-                       fRec8[1] = fRec8[0];
-                       fRec9[2] = fRec9[1];
-                       fRec9[1] = fRec9[0];
-                       fRec10[2] = fRec10[1];
-                       fRec10[1] = fRec10[0];
-                       fRec11[2] = fRec11[1];
-                       fRec11[1] = fRec11[0];
-                       fRec3[2] = fRec3[1];
-                       fRec3[1] = fRec3[0];
-                       fRec2[2] = fRec2[1];
-                       fRec2[1] = fRec2[0];
-                       fRec45[2] = fRec45[1];
-                       fRec45[1] = fRec45[0];
-                       fRec44[2] = fRec44[1];
-                       fRec44[1] = fRec44[0];
-               }
-       }
-
+class zitarevdsp : public dsp
+{
+   private:
+    int IOTA;
+    float fVec0[16384];
+    float fVec1[16384];
+    FAUSTFLOAT fVslider0;
+    float fRec0[2];
+    FAUSTFLOAT fVslider1;
+    float fRec1[2];
+    int fSampleRate;
+    float fConst0;
+    float fConst1;
+    FAUSTFLOAT fVslider2;
+    FAUSTFLOAT fVslider3;
+    FAUSTFLOAT fVslider4;
+    FAUSTFLOAT fVslider5;
+    float fConst2;
+    float fConst3;
+    FAUSTFLOAT fVslider6;
+    FAUSTFLOAT fVslider7;
+    FAUSTFLOAT fVslider8;
+    float fConst4;
+    FAUSTFLOAT fVslider9;
+    float fRec15[2];
+    float fRec14[2];
+    float fVec2[32768];
+    float fConst5;
+    int iConst6;
+    float fConst7;
+    FAUSTFLOAT fVslider10;
+    float fVec3[2048];
+    int iConst8;
+    float fRec12[2];
+    float fConst9;
+    float fConst10;
+    float fRec19[2];
+    float fRec18[2];
+    float fVec4[32768];
+    float fConst11;
+    int iConst12;
+    float fVec5[4096];
+    int iConst13;
+    float fRec16[2];
+    float fConst14;
+    float fConst15;
+    float fRec23[2];
+    float fRec22[2];
+    float fVec6[16384];
+    float fConst16;
+    int iConst17;
+    float fVec7[4096];
+    int iConst18;
+    float fRec20[2];
+    float fConst19;
+    float fConst20;
+    float fRec27[2];
+    float fRec26[2];
+    float fVec8[32768];
+    float fConst21;
+    int iConst22;
+    float fVec9[4096];
+    int iConst23;
+    float fRec24[2];
+    float fConst24;
+    float fConst25;
+    float fRec31[2];
+    float fRec30[2];
+    float fVec10[16384];
+    float fConst26;
+    int iConst27;
+    float fVec11[2048];
+    int iConst28;
+    float fRec28[2];
+    float fConst29;
+    float fConst30;
+    float fRec35[2];
+    float fRec34[2];
+    float fVec12[16384];
+    float fConst31;
+    int iConst32;
+    float fVec13[4096];
+    int iConst33;
+    float fRec32[2];
+    float fConst34;
+    float fConst35;
+    float fRec39[2];
+    float fRec38[2];
+    float fVec14[16384];
+    float fConst36;
+    int iConst37;
+    float fVec15[4096];
+    int iConst38;
+    float fRec36[2];
+    float fConst39;
+    float fConst40;
+    float fRec43[2];
+    float fRec42[2];
+    float fVec16[16384];
+    float fConst41;
+    int iConst42;
+    float fVec17[2048];
+    int iConst43;
+    float fRec40[2];
+    float fRec4[3];
+    float fRec5[3];
+    float fRec6[3];
+    float fRec7[3];
+    float fRec8[3];
+    float fRec9[3];
+    float fRec10[3];
+    float fRec11[3];
+    float fRec3[3];
+    float fRec2[3];
+    float fRec45[3];
+    float fRec44[3];
+
+   public:
+    void metadata(Meta* m)
+    {
+        m->declare("basics.lib/name", "Faust Basic Element Library");
+        m->declare("basics.lib/version", "0.1");
+        m->declare("delays.lib/name", "Faust Delay Library");
+        m->declare("delays.lib/version", "0.1");
+        m->declare("filename", "zitarevdsp.dsp");
+        m->declare("filters.lib/allpass_comb:author", "Julius O. Smith III");
+        m->declare(
+            "filters.lib/allpass_comb:copyright",
+            "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+        m->declare("filters.lib/allpass_comb:license", "MIT-style STK-4.3 license");
+        m->declare("filters.lib/fir:author", "Julius O. Smith III");
+        m->declare(
+            "filters.lib/fir:copyright",
+            "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+        m->declare("filters.lib/fir:license", "MIT-style STK-4.3 license");
+        m->declare("filters.lib/iir:author", "Julius O. Smith III");
+        m->declare(
+            "filters.lib/iir:copyright",
+            "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+        m->declare("filters.lib/iir:license", "MIT-style STK-4.3 license");
+        m->declare("filters.lib/lowpass0_highpass1", "MIT-style STK-4.3 license");
+        m->declare("filters.lib/lowpass0_highpass1:author", "Julius O. Smith III");
+        m->declare("filters.lib/lowpass:author", "Julius O. Smith III");
+        m->declare(
+            "filters.lib/lowpass:copyright",
+            "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+        m->declare("filters.lib/lowpass:license", "MIT-style STK-4.3 license");
+        m->declare("filters.lib/name", "Faust Filters Library");
+        m->declare("filters.lib/peak_eq_rm:author", "Julius O. Smith III");
+        m->declare(
+            "filters.lib/peak_eq_rm:copyright",
+            "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+        m->declare("filters.lib/peak_eq_rm:license", "MIT-style STK-4.3 license");
+        m->declare("filters.lib/tf1:author", "Julius O. Smith III");
+        m->declare(
+            "filters.lib/tf1:copyright",
+            "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+        m->declare("filters.lib/tf1:license", "MIT-style STK-4.3 license");
+        m->declare("filters.lib/tf1s:author", "Julius O. Smith III");
+        m->declare(
+            "filters.lib/tf1s:copyright",
+            "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+        m->declare("filters.lib/tf1s:license", "MIT-style STK-4.3 license");
+        m->declare("filters.lib/tf2:author", "Julius O. Smith III");
+        m->declare(
+            "filters.lib/tf2:copyright",
+            "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+        m->declare("filters.lib/tf2:license", "MIT-style STK-4.3 license");
+        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.3");
+        m->declare("name", "zitarevdsp");
+        m->declare("platform.lib/name", "Generic Platform Library");
+        m->declare("platform.lib/version", "0.1");
+        m->declare("reverbs.lib/name", "Faust Reverb Library");
+        m->declare("reverbs.lib/version", "0.0");
+        m->declare("routes.lib/name", "Faust Signal Routing Library");
+        m->declare("routes.lib/version", "0.2");
+        m->declare("signals.lib/name", "Faust Signal Routing Library");
+        m->declare("signals.lib/version", "0.0");
+    }
+
+    virtual int getNumInputs() { return 2; }
+    virtual int getNumOutputs() { return 2; }
+    virtual int getInputRate(int channel)
+    {
+        int rate;
+        switch ((channel)) {
+        case 0: {
+            rate = 1;
+            break;
+        }
+        case 1: {
+            rate = 1;
+            break;
+        }
+        default: {
+            rate = -1;
+            break;
+        }
+        }
+        return rate;
+    }
+    virtual int getOutputRate(int channel)
+    {
+        int rate;
+        switch ((channel)) {
+        case 0: {
+            rate = 1;
+            break;
+        }
+        case 1: {
+            rate = 1;
+            break;
+        }
+        default: {
+            rate = -1;
+            break;
+        }
+        }
+        return rate;
+    }
+
+    static void classInit(int /*sample_rate*/) {}
+
+    virtual void instanceConstants(int sample_rate)
+    {
+        fSampleRate = sample_rate;
+        fConst0 = std::min<float>(192000.0f, std::max<float>(1.0f, float(fSampleRate)));
+        fConst1 = (6.28318548f / fConst0);
+        fConst2 = std::floor(((0.219990999f * fConst0) + 0.5f));
+        fConst3 = ((0.0f - (6.90775537f * fConst2)) / fConst0);
+        fConst4 = (3.14159274f / fConst0);
+        fConst5 = std::floor(((0.0191229992f * fConst0) + 0.5f));
+        iConst6 =
+            int(std::min<float>(16384.0f, std::max<float>(0.0f, (fConst2 - fConst5))));
+        fConst7 = (0.00100000005f * fConst0);
+        iConst8 = int(std::min<float>(1024.0f, std::max<float>(0.0f, (fConst5 + -1.0f))));
+        fConst9 = std::floor(((0.256891012f * fConst0) + 0.5f));
+        fConst10 = ((0.0f - (6.90775537f * fConst9)) / fConst0);
+        fConst11 = std::floor(((0.0273330007f * fConst0) + 0.5f));
+        iConst12 =
+            int(std::min<float>(16384.0f, std::max<float>(0.0f, (fConst9 - fConst11))));
+        iConst13 =
+            int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst11 + -1.0f))));
+        fConst14 = std::floor(((0.192303002f * fConst0) + 0.5f));
+        fConst15 = ((0.0f - (6.90775537f * fConst14)) / fConst0);
+        fConst16 = std::floor(((0.0292910002f * fConst0) + 0.5f));
+        iConst17 =
+            int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst14 - fConst16))));
+        iConst18 =
+            int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst16 + -1.0f))));
+        fConst19 = std::floor(((0.210389003f * fConst0) + 0.5f));
+        fConst20 = ((0.0f - (6.90775537f * fConst19)) / fConst0);
+        fConst21 = std::floor(((0.0244210009f * fConst0) + 0.5f));
+        iConst22 =
+            int(std::min<float>(16384.0f, std::max<float>(0.0f, (fConst19 - fConst21))));
+        iConst23 =
+            int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst21 + -1.0f))));
+        fConst24 = std::floor(((0.125f * fConst0) + 0.5f));
+        fConst25 = ((0.0f - (6.90775537f * fConst24)) / fConst0);
+        fConst26 = std::floor(((0.0134579996f * fConst0) + 0.5f));
+        iConst27 =
+            int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst24 - fConst26))));
+        iConst28 =
+            int(std::min<float>(1024.0f, std::max<float>(0.0f, (fConst26 + -1.0f))));
+        fConst29 = std::floor(((0.127837002f * fConst0) + 0.5f));
+        fConst30 = ((0.0f - (6.90775537f * fConst29)) / fConst0);
+        fConst31 = std::floor(((0.0316039994f * fConst0) + 0.5f));
+        iConst32 =
+            int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst29 - fConst31))));
+        iConst33 =
+            int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst31 + -1.0f))));
+        fConst34 = std::floor(((0.174713001f * fConst0) + 0.5f));
+        fConst35 = ((0.0f - (6.90775537f * fConst34)) / fConst0);
+        fConst36 = std::floor(((0.0229039993f * fConst0) + 0.5f));
+        iConst37 =
+            int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst34 - fConst36))));
+        iConst38 =
+            int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst36 + -1.0f))));
+        fConst39 = std::floor(((0.153128996f * fConst0) + 0.5f));
+        fConst40 = ((0.0f - (6.90775537f * fConst39)) / fConst0);
+        fConst41 = std::floor(((0.0203460008f * fConst0) + 0.5f));
+        iConst42 =
+            int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst39 - fConst41))));
+        iConst43 =
+            int(std::min<float>(1024.0f, std::max<float>(0.0f, (fConst41 + -1.0f))));
+    }
+
+    virtual void instanceResetUserInterface()
+    {
+        fVslider0  = FAUSTFLOAT(-3.0f);
+        fVslider1  = FAUSTFLOAT(0.0f);
+        fVslider2  = FAUSTFLOAT(1500.0f);
+        fVslider3  = FAUSTFLOAT(0.0f);
+        fVslider4  = FAUSTFLOAT(315.0f);
+        fVslider5  = FAUSTFLOAT(0.0f);
+        fVslider6  = FAUSTFLOAT(2.0f);
+        fVslider7  = FAUSTFLOAT(6000.0f);
+        fVslider8  = FAUSTFLOAT(3.0f);
+        fVslider9  = FAUSTFLOAT(200.0f);
+        fVslider10 = FAUSTFLOAT(60.0f);
+    }
+
+    virtual void instanceClear()
+    {
+        IOTA = 0;
+        for (int l0 = 0; (l0 < 16384); l0 = (l0 + 1)) { fVec0[l0] = 0.0f; }
+        for (int l1 = 0; (l1 < 16384); l1 = (l1 + 1)) { fVec1[l1] = 0.0f; }
+        for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) { fRec0[l2] = 0.0f; }
+        for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) { fRec1[l3] = 0.0f; }
+        for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) { fRec15[l4] = 0.0f; }
+        for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) { fRec14[l5] = 0.0f; }
+        for (int l6 = 0; (l6 < 32768); l6 = (l6 + 1)) { fVec2[l6] = 0.0f; }
+        for (int l7 = 0; (l7 < 2048); l7 = (l7 + 1)) { fVec3[l7] = 0.0f; }
+        for (int l8 = 0; (l8 < 2); l8 = (l8 + 1)) { fRec12[l8] = 0.0f; }
+        for (int l9 = 0; (l9 < 2); l9 = (l9 + 1)) { fRec19[l9] = 0.0f; }
+        for (int l10 = 0; (l10 < 2); l10 = (l10 + 1)) { fRec18[l10] = 0.0f; }
+        for (int l11 = 0; (l11 < 32768); l11 = (l11 + 1)) { fVec4[l11] = 0.0f; }
+        for (int l12 = 0; (l12 < 4096); l12 = (l12 + 1)) { fVec5[l12] = 0.0f; }
+        for (int l13 = 0; (l13 < 2); l13 = (l13 + 1)) { fRec16[l13] = 0.0f; }
+        for (int l14 = 0; (l14 < 2); l14 = (l14 + 1)) { fRec23[l14] = 0.0f; }
+        for (int l15 = 0; (l15 < 2); l15 = (l15 + 1)) { fRec22[l15] = 0.0f; }
+        for (int l16 = 0; (l16 < 16384); l16 = (l16 + 1)) { fVec6[l16] = 0.0f; }
+        for (int l17 = 0; (l17 < 4096); l17 = (l17 + 1)) { fVec7[l17] = 0.0f; }
+        for (int l18 = 0; (l18 < 2); l18 = (l18 + 1)) { fRec20[l18] = 0.0f; }
+        for (int l19 = 0; (l19 < 2); l19 = (l19 + 1)) { fRec27[l19] = 0.0f; }
+        for (int l20 = 0; (l20 < 2); l20 = (l20 + 1)) { fRec26[l20] = 0.0f; }
+        for (int l21 = 0; (l21 < 32768); l21 = (l21 + 1)) { fVec8[l21] = 0.0f; }
+        for (int l22 = 0; (l22 < 4096); l22 = (l22 + 1)) { fVec9[l22] = 0.0f; }
+        for (int l23 = 0; (l23 < 2); l23 = (l23 + 1)) { fRec24[l23] = 0.0f; }
+        for (int l24 = 0; (l24 < 2); l24 = (l24 + 1)) { fRec31[l24] = 0.0f; }
+        for (int l25 = 0; (l25 < 2); l25 = (l25 + 1)) { fRec30[l25] = 0.0f; }
+        for (int l26 = 0; (l26 < 16384); l26 = (l26 + 1)) { fVec10[l26] = 0.0f; }
+        for (int l27 = 0; (l27 < 2048); l27 = (l27 + 1)) { fVec11[l27] = 0.0f; }
+        for (int l28 = 0; (l28 < 2); l28 = (l28 + 1)) { fRec28[l28] = 0.0f; }
+        for (int l29 = 0; (l29 < 2); l29 = (l29 + 1)) { fRec35[l29] = 0.0f; }
+        for (int l30 = 0; (l30 < 2); l30 = (l30 + 1)) { fRec34[l30] = 0.0f; }
+        for (int l31 = 0; (l31 < 16384); l31 = (l31 + 1)) { fVec12[l31] = 0.0f; }
+        for (int l32 = 0; (l32 < 4096); l32 = (l32 + 1)) { fVec13[l32] = 0.0f; }
+        for (int l33 = 0; (l33 < 2); l33 = (l33 + 1)) { fRec32[l33] = 0.0f; }
+        for (int l34 = 0; (l34 < 2); l34 = (l34 + 1)) { fRec39[l34] = 0.0f; }
+        for (int l35 = 0; (l35 < 2); l35 = (l35 + 1)) { fRec38[l35] = 0.0f; }
+        for (int l36 = 0; (l36 < 16384); l36 = (l36 + 1)) { fVec14[l36] = 0.0f; }
+        for (int l37 = 0; (l37 < 4096); l37 = (l37 + 1)) { fVec15[l37] = 0.0f; }
+        for (int l38 = 0; (l38 < 2); l38 = (l38 + 1)) { fRec36[l38] = 0.0f; }
+        for (int l39 = 0; (l39 < 2); l39 = (l39 + 1)) { fRec43[l39] = 0.0f; }
+        for (int l40 = 0; (l40 < 2); l40 = (l40 + 1)) { fRec42[l40] = 0.0f; }
+        for (int l41 = 0; (l41 < 16384); l41 = (l41 + 1)) { fVec16[l41] = 0.0f; }
+        for (int l42 = 0; (l42 < 2048); l42 = (l42 + 1)) { fVec17[l42] = 0.0f; }
+        for (int l43 = 0; (l43 < 2); l43 = (l43 + 1)) { fRec40[l43] = 0.0f; }
+        for (int l44 = 0; (l44 < 3); l44 = (l44 + 1)) { fRec4[l44] = 0.0f; }
+        for (int l45 = 0; (l45 < 3); l45 = (l45 + 1)) { fRec5[l45] = 0.0f; }
+        for (int l46 = 0; (l46 < 3); l46 = (l46 + 1)) { fRec6[l46] = 0.0f; }
+        for (int l47 = 0; (l47 < 3); l47 = (l47 + 1)) { fRec7[l47] = 0.0f; }
+        for (int l48 = 0; (l48 < 3); l48 = (l48 + 1)) { fRec8[l48] = 0.0f; }
+        for (int l49 = 0; (l49 < 3); l49 = (l49 + 1)) { fRec9[l49] = 0.0f; }
+        for (int l50 = 0; (l50 < 3); l50 = (l50 + 1)) { fRec10[l50] = 0.0f; }
+        for (int l51 = 0; (l51 < 3); l51 = (l51 + 1)) { fRec11[l51] = 0.0f; }
+        for (int l52 = 0; (l52 < 3); l52 = (l52 + 1)) { fRec3[l52] = 0.0f; }
+        for (int l53 = 0; (l53 < 3); l53 = (l53 + 1)) { fRec2[l53] = 0.0f; }
+        for (int l54 = 0; (l54 < 3); l54 = (l54 + 1)) { fRec45[l54] = 0.0f; }
+        for (int l55 = 0; (l55 < 3); l55 = (l55 + 1)) { fRec44[l55] = 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 zitarevdsp* clone() { return new zitarevdsp(); }
+
+    virtual int getSampleRate() { return fSampleRate; }
+
+    virtual void buildUserInterface(UI* ui_interface)
+    {
+        ui_interface->declare(0, "0", "");
+        ui_interface->declare(0, "tooltip",
+                              "~ ZITA REV1 FEEDBACK DELAY NETWORK (FDN) & SCHROEDER  "
+                              "ALLPASS-COMB REVERBERATOR (8x8). See Faust's reverbs.lib "
+                              "for documentation and  references");
+        ui_interface->openHorizontalBox("Zita_Rev1");
+        ui_interface->declare(0, "1", "");
+        ui_interface->openHorizontalBox("Input");
+        ui_interface->declare(&fVslider10, "1", "");
+        ui_interface->declare(&fVslider10, "style", "knob");
+        ui_interface->declare(&fVslider10, "tooltip",
+                              "Delay in ms   before reverberation begins");
+        ui_interface->declare(&fVslider10, "unit", "ms");
+        ui_interface->addVerticalSlider("In Delay", &fVslider10, 60.0f, 20.0f, 100.0f,
+                                        1.0f);
+        ui_interface->closeBox();
+        ui_interface->declare(0, "2", "");
+        ui_interface->openHorizontalBox("Decay Times in Bands (see tooltips)");
+        ui_interface->declare(&fVslider9, "1", "");
+        ui_interface->declare(&fVslider9, "scale", "log");
+        ui_interface->declare(&fVslider9, "style", "knob");
+        ui_interface->declare(
+            &fVslider9, "tooltip",
+            "Crossover frequency (Hz) separating low and middle frequencies");
+        ui_interface->declare(&fVslider9, "unit", "Hz");
+        ui_interface->addVerticalSlider("LF X", &fVslider9, 200.0f, 50.0f, 1000.0f, 1.0f);
+        ui_interface->declare(&fVslider8, "2", "");
+        ui_interface->declare(&fVslider8, "scale", "log");
+        ui_interface->declare(&fVslider8, "style", "knob");
+        ui_interface->declare(
+            &fVslider8, "tooltip",
+            "T60 = time (in seconds) to decay 60dB in low-frequency band");
+        ui_interface->declare(&fVslider8, "unit", "s");
+        ui_interface->addVerticalSlider("Low RT60", &fVslider8, 3.0f, 1.0f, 8.0f,
+                                        0.100000001f);
+        ui_interface->declare(&fVslider6, "3", "");
+        ui_interface->declare(&fVslider6, "scale", "log");
+        ui_interface->declare(&fVslider6, "style", "knob");
+        ui_interface->declare(&fVslider6, "tooltip",
+                              "T60 = time (in seconds) to decay 60dB in middle band");
+        ui_interface->declare(&fVslider6, "unit", "s");
+        ui_interface->addVerticalSlider("Mid RT60", &fVslider6, 2.0f, 1.0f, 8.0f,
+                                        0.100000001f);
+        ui_interface->declare(&fVslider7, "4", "");
+        ui_interface->declare(&fVslider7, "scale", "log");
+        ui_interface->declare(&fVslider7, "style", "knob");
+        ui_interface->declare(&fVslider7, "tooltip",
+                              "Frequency (Hz) at which the high-frequency T60 is half "
+                              "the middle-band's T60");
+        ui_interface->declare(&fVslider7, "unit", "Hz");
+        ui_interface->addVerticalSlider("HF Damping", &fVslider7, 6000.0f, 1500.0f,
+                                        23520.0f, 1.0f);
+        ui_interface->closeBox();
+        ui_interface->declare(0, "3", "");
+        ui_interface->openHorizontalBox("RM Peaking Equalizer 1");
+        ui_interface->declare(&fVslider4, "1", "");
+        ui_interface->declare(&fVslider4, "scale", "log");
+        ui_interface->declare(&fVslider4, "style", "knob");
+        ui_interface->declare(
+            &fVslider4, "tooltip",
+            "Center-frequency of second-order Regalia-Mitra peaking equalizer section 1");
+        ui_interface->declare(&fVslider4, "unit", "Hz");
+        ui_interface->addVerticalSlider("Eq1 Freq", &fVslider4, 315.0f, 40.0f, 2500.0f,
+                                        1.0f);
+        ui_interface->declare(&fVslider5, "2", "");
+        ui_interface->declare(&fVslider5, "style", "knob");
+        ui_interface->declare(&fVslider5, "tooltip",
+                              "Peak level   in dB of second-order Regalia-Mitra peaking "
+                              "equalizer section 1");
+        ui_interface->declare(&fVslider5, "unit", "dB");
+        ui_interface->addVerticalSlider("Eq1 Level", &fVslider5, 0.0f, -15.0f, 15.0f,
+                                        0.100000001f);
+        ui_interface->closeBox();
+        ui_interface->declare(0, "4", "");
+        ui_interface->openHorizontalBox("RM Peaking Equalizer 2");
+        ui_interface->declare(&fVslider2, "1", "");
+        ui_interface->declare(&fVslider2, "scale", "log");
+        ui_interface->declare(&fVslider2, "style", "knob");
+        ui_interface->declare(
+            &fVslider2, "tooltip",
+            "Center-frequency of second-order Regalia-Mitra peaking equalizer section 2");
+        ui_interface->declare(&fVslider2, "unit", "Hz");
+        ui_interface->addVerticalSlider("Eq2 Freq", &fVslider2, 1500.0f, 160.0f, 10000.0f,
+                                        1.0f);
+        ui_interface->declare(&fVslider3, "2", "");
+        ui_interface->declare(&fVslider3, "style", "knob");
+        ui_interface->declare(&fVslider3, "tooltip",
+                              "Peak level   in dB of second-order Regalia-Mitra peaking "
+                              "equalizer section 2");
+        ui_interface->declare(&fVslider3, "unit", "dB");
+        ui_interface->addVerticalSlider("Eq2 Level", &fVslider3, 0.0f, -15.0f, 15.0f,
+                                        0.100000001f);
+        ui_interface->closeBox();
+        ui_interface->declare(0, "5", "");
+        ui_interface->openHorizontalBox("Output");
+        ui_interface->declare(&fVslider1, "1", "");
+        ui_interface->declare(&fVslider1, "style", "knob");
+        ui_interface->declare(&fVslider1, "tooltip", "Dry/Wet Mix: 0 = dry, 1 = wet");
+        ui_interface->addVerticalSlider("Wet", &fVslider1, 0.0f, 0.0f, 1.0f,
+                                        0.00999999978f);
+        ui_interface->declare(&fVslider0, "2", "");
+        ui_interface->declare(&fVslider0, "style", "knob");
+        ui_interface->declare(&fVslider0, "tooltip", "Output scale   factor");
+        ui_interface->declare(&fVslider0, "unit", "dB");
+        ui_interface->addVerticalSlider("Level", &fVslider0, -3.0f, -70.0f, 20.0f,
+                                        0.100000001f);
+        ui_interface->closeBox();
+        ui_interface->closeBox();
+    }
+
+    virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
+    {
+        FAUSTFLOAT* input0  = inputs[0];
+        FAUSTFLOAT* input1  = inputs[1];
+        FAUSTFLOAT* output0 = outputs[0];
+        FAUSTFLOAT* output1 = outputs[1];
+        float fSlow0 =
+            (0.00100000005f * std::pow(10.0f, (0.0500000007f * float(fVslider0))));
+        float fSlow1  = (0.00100000005f * float(fVslider1));
+        float fSlow2  = float(fVslider2);
+        float fSlow3  = std::pow(10.0f, (0.0500000007f * float(fVslider3)));
+        float fSlow4  = (fConst1 * (fSlow2 / std::sqrt(std::max<float>(0.0f, fSlow3))));
+        float fSlow5  = ((1.0f - fSlow4) / (fSlow4 + 1.0f));
+        float fSlow6  = float(fVslider4);
+        float fSlow7  = std::pow(10.0f, (0.0500000007f * float(fVslider5)));
+        float fSlow8  = (fConst1 * (fSlow6 / std::sqrt(std::max<float>(0.0f, fSlow7))));
+        float fSlow9  = ((1.0f - fSlow8) / (fSlow8 + 1.0f));
+        float fSlow10 = float(fVslider6);
+        float fSlow11 = std::exp((fConst3 / fSlow10));
+        float fSlow12 = zitarevdsp_faustpower2_f(fSlow11);
+        float fSlow13 = std::cos((fConst1 * float(fVslider7)));
+        float fSlow14 = (1.0f - (fSlow12 * fSlow13));
+        float fSlow15 = (1.0f - fSlow12);
+        float fSlow16 = (fSlow14 / fSlow15);
+        float fSlow17 = std::sqrt(std::max<float>(
+            0.0f, ((zitarevdsp_faustpower2_f(fSlow14) / zitarevdsp_faustpower2_f(fSlow15))
+                   + -1.0f)));
+        float fSlow18 = (fSlow16 - fSlow17);
+        float fSlow19 = (fSlow11 * (fSlow17 + (1.0f - fSlow16)));
+        float fSlow20 = float(fVslider8);
+        float fSlow21 = ((std::exp((fConst3 / fSlow20)) / fSlow11) + -1.0f);
+        float fSlow22 = (1.0f / std::tan((fConst4 * float(fVslider9))));
+        float fSlow23 = (1.0f / (fSlow22 + 1.0f));
+        float fSlow24 = (1.0f - fSlow22);
+        int iSlow25   = int(std::min<float>(
+            8192.0f, std::max<float>(0.0f, (fConst7 * float(fVslider10)))));
+        float fSlow26 = std::exp((fConst10 / fSlow10));
+        float fSlow27 = zitarevdsp_faustpower2_f(fSlow26);
+        float fSlow28 = (1.0f - (fSlow27 * fSlow13));
+        float fSlow29 = (1.0f - fSlow27);
+        float fSlow30 = (fSlow28 / fSlow29);
+        float fSlow31 = std::sqrt(std::max<float>(
+            0.0f, ((zitarevdsp_faustpower2_f(fSlow28) / zitarevdsp_faustpower2_f(fSlow29))
+                   + -1.0f)));
+        float fSlow32 = (fSlow30 - fSlow31);
+        float fSlow33 = (fSlow26 * (fSlow31 + (1.0f - fSlow30)));
+        float fSlow34 = ((std::exp((fConst10 / fSlow20)) / fSlow26) + -1.0f);
+        float fSlow35 = std::exp((fConst15 / fSlow10));
+        float fSlow36 = zitarevdsp_faustpower2_f(fSlow35);
+        float fSlow37 = (1.0f - (fSlow36 * fSlow13));
+        float fSlow38 = (1.0f - fSlow36);
+        float fSlow39 = (fSlow37 / fSlow38);
+        float fSlow40 = std::sqrt(std::max<float>(
+            0.0f, ((zitarevdsp_faustpower2_f(fSlow37) / zitarevdsp_faustpower2_f(fSlow38))
+                   + -1.0f)));
+        float fSlow41 = (fSlow39 - fSlow40);
+        float fSlow42 = (fSlow35 * (fSlow40 + (1.0f - fSlow39)));
+        float fSlow43 = ((std::exp((fConst15 / fSlow20)) / fSlow35) + -1.0f);
+        float fSlow44 = std::exp((fConst20 / fSlow10));
+        float fSlow45 = zitarevdsp_faustpower2_f(fSlow44);
+        float fSlow46 = (1.0f - (fSlow45 * fSlow13));
+        float fSlow47 = (1.0f - fSlow45);
+        float fSlow48 = (fSlow46 / fSlow47);
+        float fSlow49 = std::sqrt(std::max<float>(
+            0.0f, ((zitarevdsp_faustpower2_f(fSlow46) / zitarevdsp_faustpower2_f(fSlow47))
+                   + -1.0f)));
+        float fSlow50 = (fSlow48 - fSlow49);
+        float fSlow51 = (fSlow44 * (fSlow49 + (1.0f - fSlow48)));
+        float fSlow52 = ((std::exp((fConst20 / fSlow20)) / fSlow44) + -1.0f);
+        float fSlow53 = std::exp((fConst25 / fSlow10));
+        float fSlow54 = zitarevdsp_faustpower2_f(fSlow53);
+        float fSlow55 = (1.0f - (fSlow54 * fSlow13));
+        float fSlow56 = (1.0f - fSlow54);
+        float fSlow57 = (fSlow55 / fSlow56);
+        float fSlow58 = std::sqrt(std::max<float>(
+            0.0f, ((zitarevdsp_faustpower2_f(fSlow55) / zitarevdsp_faustpower2_f(fSlow56))
+                   + -1.0f)));
+        float fSlow59 = (fSlow57 - fSlow58);
+        float fSlow60 = (fSlow53 * (fSlow58 + (1.0f - fSlow57)));
+        float fSlow61 = ((std::exp((fConst25 / fSlow20)) / fSlow53) + -1.0f);
+        float fSlow62 = std::exp((fConst30 / fSlow10));
+        float fSlow63 = zitarevdsp_faustpower2_f(fSlow62);
+        float fSlow64 = (1.0f - (fSlow63 * fSlow13));
+        float fSlow65 = (1.0f - fSlow63);
+        float fSlow66 = (fSlow64 / fSlow65);
+        float fSlow67 = std::sqrt(std::max<float>(
+            0.0f, ((zitarevdsp_faustpower2_f(fSlow64) / zitarevdsp_faustpower2_f(fSlow65))
+                   + -1.0f)));
+        float fSlow68 = (fSlow66 - fSlow67);
+        float fSlow69 = (fSlow62 * (fSlow67 + (1.0f - fSlow66)));
+        float fSlow70 = ((std::exp((fConst30 / fSlow20)) / fSlow62) + -1.0f);
+        float fSlow71 = std::exp((fConst35 / fSlow10));
+        float fSlow72 = zitarevdsp_faustpower2_f(fSlow71);
+        float fSlow73 = (1.0f - (fSlow72 * fSlow13));
+        float fSlow74 = (1.0f - fSlow72);
+        float fSlow75 = (fSlow73 / fSlow74);
+        float fSlow76 = std::sqrt(std::max<float>(
+            0.0f, ((zitarevdsp_faustpower2_f(fSlow73) / zitarevdsp_faustpower2_f(fSlow74))
+                   + -1.0f)));
+        float fSlow77 = (fSlow75 - fSlow76);
+        float fSlow78 = (fSlow71 * (fSlow76 + (1.0f - fSlow75)));
+        float fSlow79 = ((std::exp((fConst35 / fSlow20)) / fSlow71) + -1.0f);
+        float fSlow80 = std::exp((fConst40 / fSlow10));
+        float fSlow81 = zitarevdsp_faustpower2_f(fSlow80);
+        float fSlow82 = (1.0f - (fSlow81 * fSlow13));
+        float fSlow83 = (1.0f - fSlow81);
+        float fSlow84 = (fSlow82 / fSlow83);
+        float fSlow85 = std::sqrt(std::max<float>(
+            0.0f, ((zitarevdsp_faustpower2_f(fSlow82) / zitarevdsp_faustpower2_f(fSlow83))
+                   + -1.0f)));
+        float fSlow86 = (fSlow84 - fSlow85);
+        float fSlow87 = (fSlow80 * (fSlow85 + (1.0f - fSlow84)));
+        float fSlow88 = ((std::exp((fConst40 / fSlow20)) / fSlow80) + -1.0f);
+        float fSlow89 = (0.0f - (std::cos((fConst1 * fSlow6)) * (fSlow9 + 1.0f)));
+        float fSlow90 = (0.0f - (std::cos((fConst1 * fSlow2)) * (fSlow5 + 1.0f)));
+        for (int i = 0; (i < count); i = (i + 1)) {
+            float fTemp0          = float(input0[i]);
+            fVec0[(IOTA & 16383)] = fTemp0;
+            float fTemp1          = float(input1[i]);
+            fVec1[(IOTA & 16383)] = fTemp1;
+            fRec0[0]              = (fSlow0 + (0.999000013f * fRec0[1]));
+            fRec1[0]              = (fSlow1 + (0.999000013f * fRec1[1]));
+            fRec15[0] =
+                (0.0f - (fSlow23 * ((fSlow24 * fRec15[1]) - (fRec11[1] + fRec11[2]))));
+            fRec14[0] =
+                ((fSlow18 * fRec14[1]) + (fSlow19 * (fRec11[1] + (fSlow21 * fRec15[0]))));
+            fVec2[(IOTA & 32767)] = ((0.353553385f * fRec14[0]) + 9.99999968e-21f);
+            float fTemp2          = (0.300000012f * fVec1[((IOTA - iSlow25) & 16383)]);
+            float fTemp3 =
+                (((0.600000024f * fRec12[1]) + fVec2[((IOTA - iConst6) & 32767)])
+                 - fTemp2);
+            fVec3[(IOTA & 2047)] = fTemp3;
+            fRec12[0]            = fVec3[((IOTA - iConst8) & 2047)];
+            float fRec13         = (0.0f - (0.600000024f * fTemp3));
+            fRec19[0] =
+                (0.0f - (fSlow23 * ((fSlow24 * fRec19[1]) - (fRec7[1] + fRec7[2]))));
+            fRec18[0] =
+                ((fSlow32 * fRec18[1]) + (fSlow33 * (fRec7[1] + (fSlow34 * fRec19[0]))));
+            fVec4[(IOTA & 32767)] = ((0.353553385f * fRec18[0]) + 9.99999968e-21f);
+            float fTemp4 =
+                (((0.600000024f * fRec16[1]) + fVec4[((IOTA - iConst12) & 32767)])
+                 - fTemp2);
+            fVec5[(IOTA & 4095)] = fTemp4;
+            fRec16[0]            = fVec5[((IOTA - iConst13) & 4095)];
+            float fRec17         = (0.0f - (0.600000024f * fTemp4));
+            fRec23[0] =
+                (0.0f - (fSlow23 * ((fSlow24 * fRec23[1]) - (fRec9[1] + fRec9[2]))));
+            fRec22[0] =
+                ((fSlow41 * fRec22[1]) + (fSlow42 * (fRec9[1] + (fSlow43 * fRec23[0]))));
+            fVec6[(IOTA & 16383)] = ((0.353553385f * fRec22[0]) + 9.99999968e-21f);
+            float fTemp5          = (fVec6[((IOTA - iConst17) & 16383)]
+                            + (fTemp2 + (0.600000024f * fRec20[1])));
+            fVec7[(IOTA & 4095)]  = fTemp5;
+            fRec20[0]             = fVec7[((IOTA - iConst18) & 4095)];
+            float fRec21          = (0.0f - (0.600000024f * fTemp5));
+            fRec27[0] =
+                (0.0f - (fSlow23 * ((fSlow24 * fRec27[1]) - (fRec5[1] + fRec5[2]))));
+            fRec26[0] =
+                ((fSlow50 * fRec26[1]) + (fSlow51 * (fRec5[1] + (fSlow52 * fRec27[0]))));
+            fVec8[(IOTA & 32767)] = ((0.353553385f * fRec26[0]) + 9.99999968e-21f);
+            float fTemp6 =
+                (fTemp2
+                 + ((0.600000024f * fRec24[1]) + fVec8[((IOTA - iConst22) & 32767)]));
+            fVec9[(IOTA & 4095)] = fTemp6;
+            fRec24[0]            = fVec9[((IOTA - iConst23) & 4095)];
+            float fRec25         = (0.0f - (0.600000024f * fTemp6));
+            fRec31[0] =
+                (0.0f - (fSlow23 * ((fSlow24 * fRec31[1]) - (fRec10[1] + fRec10[2]))));
+            fRec30[0] =
+                ((fSlow59 * fRec30[1]) + (fSlow60 * (fRec10[1] + (fSlow61 * fRec31[0]))));
+            fVec10[(IOTA & 16383)] = ((0.353553385f * fRec30[0]) + 9.99999968e-21f);
+            float fTemp7           = (0.300000012f * fVec0[((IOTA - iSlow25) & 16383)]);
+            float fTemp8           = (fVec10[((IOTA - iConst27) & 16383)]
+                            - (fTemp7 + (0.600000024f * fRec28[1])));
+            fVec11[(IOTA & 2047)]  = fTemp8;
+            fRec28[0]              = fVec11[((IOTA - iConst28) & 2047)];
+            float fRec29           = (0.600000024f * fTemp8);
+            fRec35[0] =
+                (0.0f - (fSlow23 * ((fSlow24 * fRec35[1]) - (fRec6[1] + fRec6[2]))));
+            fRec34[0] =
+                ((fSlow68 * fRec34[1]) + (fSlow69 * (fRec6[1] + (fSlow70 * fRec35[0]))));
+            fVec12[(IOTA & 16383)] = ((0.353553385f * fRec34[0]) + 9.99999968e-21f);
+            float fTemp9           = (fVec12[((IOTA - iConst32) & 16383)]
+                            - (fTemp7 + (0.600000024f * fRec32[1])));
+            fVec13[(IOTA & 4095)]  = fTemp9;
+            fRec32[0]              = fVec13[((IOTA - iConst33) & 4095)];
+            float fRec33           = (0.600000024f * fTemp9);
+            fRec39[0] =
+                (0.0f - (fSlow23 * ((fSlow24 * fRec39[1]) - (fRec8[1] + fRec8[2]))));
+            fRec38[0] =
+                ((fSlow77 * fRec38[1]) + (fSlow78 * (fRec8[1] + (fSlow79 * fRec39[0]))));
+            fVec14[(IOTA & 16383)] = ((0.353553385f * fRec38[0]) + 9.99999968e-21f);
+            float fTemp10          = ((fTemp7 + fVec14[((IOTA - iConst37) & 16383)])
+                             - (0.600000024f * fRec36[1]));
+            fVec15[(IOTA & 4095)]  = fTemp10;
+            fRec36[0]              = fVec15[((IOTA - iConst38) & 4095)];
+            float fRec37           = (0.600000024f * fTemp10);
+            fRec43[0] =
+                (0.0f - (fSlow23 * ((fSlow24 * fRec43[1]) - (fRec4[1] + fRec4[2]))));
+            fRec42[0] =
+                ((fSlow86 * fRec42[1]) + (fSlow87 * (fRec4[1] + (fSlow88 * fRec43[0]))));
+            fVec16[(IOTA & 16383)] = ((0.353553385f * fRec42[0]) + 9.99999968e-21f);
+            float fTemp11          = ((fVec16[((IOTA - iConst42) & 16383)] + fTemp7)
+                             - (0.600000024f * fRec40[1]));
+            fVec17[(IOTA & 2047)]  = fTemp11;
+            fRec40[0]              = fVec17[((IOTA - iConst43) & 2047)];
+            float fRec41           = (0.600000024f * fTemp11);
+            float fTemp12          = (fRec41 + fRec37);
+            float fTemp13          = (fRec29 + (fRec33 + fTemp12));
+            fRec4[0] =
+                (fRec12[1]
+                 + (fRec16[1]
+                    + (fRec20[1]
+                       + (fRec24[1]
+                          + (fRec28[1]
+                             + (fRec32[1]
+                                + (fRec36[1]
+                                   + (fRec40[1]
+                                      + (fRec13
+                                         + (fRec17
+                                            + (fRec21 + (fRec25 + fTemp13))))))))))));
+            fRec5[0] =
+                ((fRec28[1] + (fRec32[1] + (fRec36[1] + (fRec40[1] + fTemp13))))
+                 - (fRec12[1]
+                    + (fRec16[1]
+                       + (fRec20[1]
+                          + (fRec24[1] + (fRec13 + (fRec17 + (fRec25 + fRec21))))))));
+            float fTemp14 = (fRec33 + fRec29);
+            fRec6[0] =
+                ((fRec20[1]
+                  + (fRec24[1]
+                     + (fRec36[1] + (fRec40[1] + (fRec21 + (fRec25 + fTemp12))))))
+                 - (fRec12[1]
+                    + (fRec16[1]
+                       + (fRec28[1] + (fRec32[1] + (fRec13 + (fRec17 + fTemp14)))))));
+            fRec7[0] =
+                ((fRec12[1]
+                  + (fRec16[1]
+                     + (fRec36[1] + (fRec40[1] + (fRec13 + (fRec17 + fTemp12))))))
+                 - (fRec20[1]
+                    + (fRec24[1]
+                       + (fRec28[1] + (fRec32[1] + (fRec21 + (fRec25 + fTemp14)))))));
+            float fTemp15 = (fRec41 + fRec33);
+            float fTemp16 = (fRec37 + fRec29);
+            fRec8[0] =
+                ((fRec16[1]
+                  + (fRec24[1]
+                     + (fRec32[1] + (fRec40[1] + (fRec17 + (fRec25 + fTemp15))))))
+                 - (fRec12[1]
+                    + (fRec20[1]
+                       + (fRec28[1] + (fRec36[1] + (fRec13 + (fRec21 + fTemp16)))))));
+            fRec9[0] =
+                ((fRec12[1]
+                  + (fRec20[1]
+                     + (fRec32[1] + (fRec40[1] + (fRec13 + (fRec21 + fTemp15))))))
+                 - (fRec16[1]
+                    + (fRec24[1]
+                       + (fRec28[1] + (fRec36[1] + (fRec17 + (fRec25 + fTemp16)))))));
+            float fTemp17 = (fRec41 + fRec29);
+            float fTemp18 = (fRec37 + fRec33);
+            fRec10[0] =
+                ((fRec12[1]
+                  + (fRec24[1]
+                     + (fRec28[1] + (fRec40[1] + (fRec13 + (fRec25 + fTemp17))))))
+                 - (fRec16[1]
+                    + (fRec20[1]
+                       + (fRec32[1] + (fRec36[1] + (fRec17 + (fRec21 + fTemp18)))))));
+            fRec11[0] =
+                ((fRec16[1]
+                  + (fRec20[1]
+                     + (fRec28[1] + (fRec40[1] + (fRec17 + (fRec21 + fTemp17))))))
+                 - (fRec12[1]
+                    + (fRec24[1]
+                       + (fRec32[1] + (fRec36[1] + (fRec13 + (fRec25 + fTemp18)))))));
+            float fTemp19 = (0.370000005f * (fRec5[0] + fRec6[0]));
+            float fTemp20 = (fSlow89 * fRec3[1]);
+            fRec3[0]      = (fTemp19 - (fTemp20 + (fSlow9 * fRec3[2])));
+            float fTemp21 = (fSlow9 * fRec3[0]);
+            float fTemp22 =
+                (0.5f
+                 * ((fTemp21 + (fRec3[2] + (fTemp19 + fTemp20)))
+                    + (fSlow7 * ((fTemp21 + (fTemp20 + fRec3[2])) - fTemp19))));
+            float fTemp23 = (fSlow90 * fRec2[1]);
+            fRec2[0]      = (fTemp22 - (fTemp23 + (fSlow5 * fRec2[2])));
+            float fTemp24 = (fSlow5 * fRec2[0]);
+            float fTemp25 = (1.0f - fRec1[0]);
+            output0[i]    = FAUSTFLOAT(
+                (fRec0[0]
+                 * ((0.5f
+                     * (fRec1[0]
+                        * ((fTemp24 + (fRec2[2] + (fTemp22 + fTemp23)))
+                           + (fSlow3 * ((fTemp24 + (fTemp23 + fRec2[2])) - fTemp22)))))
+                    + (fTemp0 * fTemp25))));
+            float fTemp26 = (0.370000005f * (fRec5[0] - fRec6[0]));
+            float fTemp27 = (fSlow89 * fRec45[1]);
+            fRec45[0]     = (fTemp26 - (fTemp27 + (fSlow9 * fRec45[2])));
+            float fTemp28 = (fSlow9 * fRec45[0]);
+            float fTemp29 =
+                (0.5f
+                 * ((fTemp28 + (fRec45[2] + (fTemp26 + fTemp27)))
+                    + (fSlow7 * ((fTemp28 + (fTemp27 + fRec45[2])) - fTemp26))));
+            float fTemp30 = (fSlow90 * fRec44[1]);
+            fRec44[0]     = (fTemp29 - (fTemp30 + (fSlow5 * fRec44[2])));
+            float fTemp31 = (fSlow5 * fRec44[0]);
+            output1[i]    = FAUSTFLOAT(
+                (fRec0[0]
+                 * ((0.5f
+                     * (fRec1[0]
+                        * ((fTemp31 + (fRec44[2] + (fTemp29 + fTemp30)))
+                           + (fSlow3 * ((fTemp31 + (fTemp30 + fRec44[2])) - fTemp29)))))
+                    + (fTemp1 * fTemp25))));
+            IOTA      = (IOTA + 1);
+            fRec0[1]  = fRec0[0];
+            fRec1[1]  = fRec1[0];
+            fRec15[1] = fRec15[0];
+            fRec14[1] = fRec14[0];
+            fRec12[1] = fRec12[0];
+            fRec19[1] = fRec19[0];
+            fRec18[1] = fRec18[0];
+            fRec16[1] = fRec16[0];
+            fRec23[1] = fRec23[0];
+            fRec22[1] = fRec22[0];
+            fRec20[1] = fRec20[0];
+            fRec27[1] = fRec27[0];
+            fRec26[1] = fRec26[0];
+            fRec24[1] = fRec24[0];
+            fRec31[1] = fRec31[0];
+            fRec30[1] = fRec30[0];
+            fRec28[1] = fRec28[0];
+            fRec35[1] = fRec35[0];
+            fRec34[1] = fRec34[0];
+            fRec32[1] = fRec32[0];
+            fRec39[1] = fRec39[0];
+            fRec38[1] = fRec38[0];
+            fRec36[1] = fRec36[0];
+            fRec43[1] = fRec43[0];
+            fRec42[1] = fRec42[0];
+            fRec40[1] = fRec40[0];
+            fRec4[2]  = fRec4[1];
+            fRec4[1]  = fRec4[0];
+            fRec5[2]  = fRec5[1];
+            fRec5[1]  = fRec5[0];
+            fRec6[2]  = fRec6[1];
+            fRec6[1]  = fRec6[0];
+            fRec7[2]  = fRec7[1];
+            fRec7[1]  = fRec7[0];
+            fRec8[2]  = fRec8[1];
+            fRec8[1]  = fRec8[0];
+            fRec9[2]  = fRec9[1];
+            fRec9[1]  = fRec9[0];
+            fRec10[2] = fRec10[1];
+            fRec10[1] = fRec10[0];
+            fRec11[2] = fRec11[1];
+            fRec11[1] = fRec11[0];
+            fRec3[2]  = fRec3[1];
+            fRec3[1]  = fRec3[0];
+            fRec2[2]  = fRec2[1];
+            fRec2[1]  = fRec2[0];
+            fRec45[2] = fRec45[1];
+            fRec45[1] = fRec45[0];
+            fRec44[2] = fRec44[1];
+            fRec44[1] = fRec44[0];
+        }
+    }
 };
 
 #endif
index 190453a10c8cbfef1f5dbf202ba6ba06d4c01270..6ee0590405682d676072c172ad82664056992820 100644 (file)
@@ -4,8 +4,8 @@ Code generated with Faust 2.28.6 (https://faust.grame.fr)
 Compilation options: -lang cpp -inpl -scal -ftz 0
 ------------------------------------------------------------ */
 
-#ifndef  __zitarevmonodsp_H__
-#define  __zitarevmonodsp_H__
+#ifndef __zitarevmonodsp_H__
+#define __zitarevmonodsp_H__
 
 // NOTE: ANY INCLUDE-GUARD HERE MUST BE DERIVED FROM THE CLASS NAME
 //
@@ -23,15 +23,15 @@ Compilation options: -lang cpp -inpl -scal -ftz 0
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -56,165 +56,177 @@ struct Meta;
  */
 
 struct dsp_memory_manager {
-    
     virtual ~dsp_memory_manager() {}
-    
+
     virtual void* allocate(size_t size) = 0;
-    virtual void destroy(void* ptr) = 0;
-    
+    virtual void destroy(void* ptr)     = 0;
 };
 
 /**
-* Signal processor definition.
-*/
-
-class dsp {
-
-    public:
-
-        dsp() {}
-        virtual ~dsp() {}
-
-        /* Return instance number of audio inputs */
-        virtual int getNumInputs() = 0;
-    
-        /* Return instance number of audio outputs */
-        virtual int getNumOutputs() = 0;
-    
-        /**
-         * Trigger the ui_interface parameter with instance specific calls
-         * to 'openTabBox', 'addButton', 'addVerticalSlider'... in order to build the UI.
-         *
-         * @param ui_interface - the user interface builder
-         */
-        virtual void buildUserInterface(UI* ui_interface) = 0;
-    
-        /* Returns the sample rate currently used by the instance */
-        virtual int getSampleRate() = 0;
-    
-        /**
-         * Global init, calls the following methods:
-         * - static class 'classInit': static tables initialization
-         * - 'instanceInit': constants and instance state initialization
-         *
-         * @param sample_rate - the sampling rate in Hertz
-         */
-        virtual void init(int sample_rate) = 0;
-
-        /**
-         * Init instance state
-         *
-         * @param sample_rate - the sampling rate in Hertz
-         */
-        virtual void instanceInit(int sample_rate) = 0;
-
-        /**
-         * Init instance constant state
-         *
-         * @param sample_rate - the sampling rate in Hertz
-         */
-        virtual void instanceConstants(int sample_rate) = 0;
-    
-        /* Init default control parameters values */
-        virtual void instanceResetUserInterface() = 0;
-    
-        /* Init instance state (delay lines...) */
-        virtual void instanceClear() = 0;
-        /**
-         * Return a clone of the instance.
-         *
-         * @return a copy of the instance on success, otherwise a null pointer.
-         */
-        virtual dsp* clone() = 0;
-    
-        /**
-         * Trigger the Meta* parameter with instance specific calls to 'declare' (key, value) metadata.
-         *
-         * @param m - the Meta* meta user
-         */
-        virtual void metadata(Meta* m) = 0;
-    
-        /**
-         * DSP instance computation, to be called with successive in/out audio buffers.
-         *
-         * @param count - the number of frames to compute
-         * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
-         * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
-         *
-         */
-        virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) = 0;
-    
-        /**
-         * DSP instance computation: alternative method to be used by subclasses.
-         *
-         * @param date_usec - the timestamp in microsec given by audio driver.
-         * @param count - the number of frames to compute
-         * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
-         * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
-         *
-         */
-        virtual void compute(double /*date_usec*/, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { compute(count, inputs, outputs); }
-       
+ * Signal processor definition.
+ */
+
+class dsp
+{
+   public:
+    dsp() {}
+    virtual ~dsp() {}
+
+    /* Return instance number of audio inputs */
+    virtual int getNumInputs() = 0;
+
+    /* Return instance number of audio outputs */
+    virtual int getNumOutputs() = 0;
+
+    /**
+     * Trigger the ui_interface parameter with instance specific calls
+     * to 'openTabBox', 'addButton', 'addVerticalSlider'... in order to build the UI.
+     *
+     * @param ui_interface - the user interface builder
+     */
+    virtual void buildUserInterface(UI* ui_interface) = 0;
+
+    /* Returns the sample rate currently used by the instance */
+    virtual int getSampleRate() = 0;
+
+    /**
+     * Global init, calls the following methods:
+     * - static class 'classInit': static tables initialization
+     * - 'instanceInit': constants and instance state initialization
+     *
+     * @param sample_rate - the sampling rate in Hertz
+     */
+    virtual void init(int sample_rate) = 0;
+
+    /**
+     * Init instance state
+     *
+     * @param sample_rate - the sampling rate in Hertz
+     */
+    virtual void instanceInit(int sample_rate) = 0;
+
+    /**
+     * Init instance constant state
+     *
+     * @param sample_rate - the sampling rate in Hertz
+     */
+    virtual void instanceConstants(int sample_rate) = 0;
+
+    /* Init default control parameters values */
+    virtual void instanceResetUserInterface() = 0;
+
+    /* Init instance state (delay lines...) */
+    virtual void instanceClear() = 0;
+
+    /**
+     * Return a clone of the instance.
+     *
+     * @return a copy of the instance on success, otherwise a null pointer.
+     */
+    virtual dsp* clone() = 0;
+
+    /**
+     * Trigger the Meta* parameter with instance specific calls to 'declare' (key, value)
+     * metadata.
+     *
+     * @param m - the Meta* meta user
+     */
+    virtual void metadata(Meta* m) = 0;
+
+    /**
+     * DSP instance computation, to be called with successive in/out audio buffers.
+     *
+     * @param count - the number of frames to compute
+     * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (eiher float, double or quad)
+     * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (eiher float, double or quad)
+     *
+     */
+    virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) = 0;
+
+    /**
+     * DSP instance computation: alternative method to be used by subclasses.
+     *
+     * @param date_usec - the timestamp in microsec given by audio driver.
+     * @param count - the number of frames to compute
+     * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (either float, double or quad)
+     * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT
+     * samples (either float, double or quad)
+     *
+     */
+    virtual void compute(double /*date_usec*/, int count, FAUSTFLOAT** inputs,
+                         FAUSTFLOAT** outputs)
+    {
+        compute(count, inputs, outputs);
+    }
 };
 
 /**
  * Generic DSP decorator.
  */
 
-class decorator_dsp : public dsp {
-
-    protected:
-
-        dsp* fDSP;
-
-    public:
-
-        decorator_dsp(dsp* dsp = nullptr):fDSP(dsp) {}
-        virtual ~decorator_dsp() { delete fDSP; }
-
-        virtual int getNumInputs() { return fDSP->getNumInputs(); }
-        virtual int getNumOutputs() { return fDSP->getNumOutputs(); }
-        virtual void buildUserInterface(UI* ui_interface) { fDSP->buildUserInterface(ui_interface); }
-        virtual int getSampleRate() { return fDSP->getSampleRate(); }
-        virtual void init(int sample_rate) { fDSP->init(sample_rate); }
-        virtual void instanceInit(int sample_rate) { fDSP->instanceInit(sample_rate); }
-        virtual void instanceConstants(int sample_rate) { fDSP->instanceConstants(sample_rate); }
-        virtual void instanceResetUserInterface() { fDSP->instanceResetUserInterface(); }
-        virtual void instanceClear() { fDSP->instanceClear(); }
-        virtual decorator_dsp* clone() { return new decorator_dsp(fDSP->clone()); }
-        virtual void metadata(Meta* m) { fDSP->metadata(m); }
-        // Beware: subclasses usually have to overload the two 'compute' methods
-        virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(count, inputs, outputs); }
-        virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(date_usec, count, inputs, outputs); }
-    
+class decorator_dsp : public dsp
+{
+   protected:
+    dsp* fDSP;
+
+   public:
+    decorator_dsp(dsp* dsp = nullptr) : fDSP(dsp) {}
+    virtual ~decorator_dsp() { delete fDSP; }
+
+    virtual int getNumInputs() { return fDSP->getNumInputs(); }
+    virtual int getNumOutputs() { return fDSP->getNumOutputs(); }
+    virtual void buildUserInterface(UI* ui_interface)
+    {
+        fDSP->buildUserInterface(ui_interface);
+    }
+    virtual int getSampleRate() { return fDSP->getSampleRate(); }
+    virtual void init(int sample_rate) { fDSP->init(sample_rate); }
+    virtual void instanceInit(int sample_rate) { fDSP->instanceInit(sample_rate); }
+    virtual void instanceConstants(int sample_rate)
+    {
+        fDSP->instanceConstants(sample_rate);
+    }
+    virtual void instanceResetUserInterface() { fDSP->instanceResetUserInterface(); }
+    virtual void instanceClear() { fDSP->instanceClear(); }
+    virtual decorator_dsp* clone() { return new decorator_dsp(fDSP->clone()); }
+    virtual void metadata(Meta* m) { fDSP->metadata(m); }
+    // Beware: subclasses usually have to overload the two 'compute' methods
+    virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
+    {
+        fDSP->compute(count, inputs, outputs);
+    }
+    virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs,
+                         FAUSTFLOAT** outputs)
+    {
+        fDSP->compute(date_usec, count, inputs, outputs);
+    }
 };
 
 /**
  * DSP factory class.
  */
 
-class dsp_factory {
-    
-    protected:
-    
-        // So that to force sub-classes to use deleteDSPFactory(dsp_factory* factory);
-        virtual ~dsp_factory() {}
-    
-    public:
-    
-        virtual std::string getName() = 0;
-        virtual std::string getSHAKey() = 0;
-        virtual std::string getDSPCode() = 0;
-        virtual std::string getCompileOptions() = 0;
-        virtual std::vector<std::string> getLibraryList() = 0;
-        virtual std::vector<std::string> getIncludePathnames() = 0;
-    
-        virtual dsp* createDSPInstance() = 0;
-    
-        virtual void setMemoryManager(dsp_memory_manager* manager) = 0;
-        virtual dsp_memory_manager* getMemoryManager() = 0;
-    
+class dsp_factory
+{
+   protected:
+    // So that to force sub-classes to use deleteDSPFactory(dsp_factory* factory);
+    virtual ~dsp_factory() {}
+
+   public:
+    virtual std::string getName()                          = 0;
+    virtual std::string getSHAKey()                        = 0;
+    virtual std::string getDSPCode()                       = 0;
+    virtual std::string getCompileOptions()                = 0;
+    virtual std::vector<std::string> getLibraryList()      = 0;
+    virtual std::vector<std::string> getIncludePathnames() = 0;
+
+    virtual dsp* createDSPInstance() = 0;
+
+    virtual void setMemoryManager(dsp_memory_manager* manager) = 0;
+    virtual dsp_memory_manager* getMemoryManager()             = 0;
 };
 
 /**
@@ -223,14 +235,14 @@ class dsp_factory {
  */
 
 #ifdef __SSE__
-    #include <xmmintrin.h>
-    #ifdef __SSE2__
-        #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
-    #else
-        #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
-    #endif
+#include <xmmintrin.h>
+#ifdef __SSE2__
+#define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
+#else
+#define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
+#endif
 #else
-    #define AVOIDDENORMALS
+#define AVOIDDENORMALS
 #endif
 
 #endif
@@ -245,15 +257,15 @@ class dsp_factory {
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -263,11 +275,11 @@ class dsp_factory {
 #ifndef API_UI_H
 #define API_UI_H
 
+#include <iostream>
+#include <map>
 #include <sstream>
 #include <string>
 #include <vector>
-#include <iostream>
-#include <map>
 
 /************************** BEGIN meta.h **************************/
 /************************************************************************
@@ -278,15 +290,15 @@ class dsp_factory {
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -296,11 +308,9 @@ class dsp_factory {
 #ifndef __meta__
 #define __meta__
 
-struct Meta
-{
-    virtual ~Meta() {};
+struct Meta {
+    virtual ~Meta(){};
     virtual void declare(const char* key, const char* value) = 0;
-    
 };
 
 #endif
@@ -314,15 +324,15 @@ struct Meta
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -345,43 +355,47 @@ struct Meta
 
 struct Soundfile;
 
-template <typename REAL>
-struct UIReal
-{
+template<typename REAL>
+struct UIReal {
     UIReal() {}
     virtual ~UIReal() {}
-    
+
     // -- widget's layouts
-    
-    virtual void openTabBox(const char* label) = 0;
+
+    virtual void openTabBox(const char* label)        = 0;
     virtual void openHorizontalBox(const char* label) = 0;
-    virtual void openVerticalBox(const char* label) = 0;
-    virtual void closeBox() = 0;
-    
+    virtual void openVerticalBox(const char* label)   = 0;
+    virtual void closeBox()                           = 0;
+
     // -- active widgets
-    
-    virtual void addButton(const char* label, REAL* zone) = 0;
+
+    virtual void addButton(const char* label, REAL* zone)      = 0;
     virtual void addCheckButton(const char* label, REAL* zone) = 0;
-    virtual void addVerticalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
-    virtual void addHorizontalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
-    virtual void addNumEntry(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
-    
+    virtual void addVerticalSlider(const char* label, REAL* zone, REAL init, REAL min,
+                                   REAL max, REAL step)        = 0;
+    virtual void addHorizontalSlider(const char* label, REAL* zone, REAL init, REAL min,
+                                     REAL max, REAL step)      = 0;
+    virtual void addNumEntry(const char* label, REAL* zone, REAL init, REAL min, REAL max,
+                             REAL step)                        = 0;
+
     // -- passive widgets
-    
-    virtual void addHorizontalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
-    virtual void addVerticalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
-    
+
+    virtual void addHorizontalBargraph(const char* label, REAL* zone, REAL min,
+                                       REAL max) = 0;
+    virtual void addVerticalBargraph(const char* label, REAL* zone, REAL min,
+                                     REAL max)   = 0;
+
     // -- soundfiles
-    
-    virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) = 0;
-    
+
+    virtual void addSoundfile(const char* label, const char* filename,
+                              Soundfile** sf_zone) = 0;
+
     // -- metadata declarations
-    
+
     virtual void declare(REAL* zone, const char* key, const char* val) {}
 };
 
-struct UI : public UIReal<FAUSTFLOAT>
-{
+struct UI : public UIReal<FAUSTFLOAT> {
     UI() {}
     virtual ~UI() {}
 };
@@ -397,15 +411,15 @@ struct UI : public UIReal<FAUSTFLOAT>
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -415,9 +429,9 @@ struct UI : public UIReal<FAUSTFLOAT>
 #ifndef FAUST_PATHBUILDER_H
 #define FAUST_PATHBUILDER_H
 
-#include <vector>
-#include <string>
 #include <algorithm>
+#include <string>
+#include <vector>
 
 /*******************************************************************************
  * PathBuilder : Faust User Interface
@@ -426,37 +440,33 @@ struct UI : public UIReal<FAUSTFLOAT>
 
 class PathBuilder
 {
-
-    protected:
-    
-        std::vector<std::string> fControlsLevel;
-       
-    public:
-    
-        PathBuilder() {}
-        virtual ~PathBuilder() {}
-    
-        std::string buildPath(const std::string& label) 
-        {
-            std::string res = "/";
-            for (size_t i = 0; i < fControlsLevel.size(); i++) {
-                res += fControlsLevel[i];
-                res += "/";
-            }
-            res += label;
-            std::replace(res.begin(), res.end(), ' ', '_');
-            return res;
-        }
-    
-        std::string buildLabel(std::string label)
-        {
-            std::replace(label.begin(), label.end(), ' ', '_');
-            return label;
+   protected:
+    std::vector<std::string> fControlsLevel;
+
+   public:
+    PathBuilder() {}
+    virtual ~PathBuilder() {}
+
+    std::string buildPath(const std::string& label)
+    {
+        std::string res = "/";
+        for (size_t i = 0; i < fControlsLevel.size(); i++) {
+            res += fControlsLevel[i];
+            res += "/";
         }
-    
-        void pushLabel(const std::string& label) { fControlsLevel.push_back(label); }
-        void popLabel() { fControlsLevel.pop_back(); }
-    
+        res += label;
+        std::replace(res.begin(), res.end(), ' ', '_');
+        return res;
+    }
+
+    std::string buildLabel(std::string label)
+    {
+        std::replace(label.begin(), label.end(), ' ', '_');
+        return label;
+    }
+
+    void pushLabel(const std::string& label) { fControlsLevel.push_back(label); }
+    void popLabel() { fControlsLevel.pop_back(); }
 };
 
 #endif  // FAUST_PATHBUILDER_H
@@ -470,15 +480,15 @@ class PathBuilder
  and/or modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
+
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
+
  You should have received a copy of the GNU General Public License
  along with this program; If not, see <http://www.gnu.org/licenses/>.
+
  EXCEPTION : As a special exception, you may create a larger work
  that contains this FAUST architecture section and distribute
  that work under terms of your choice, so long as this FAUST
@@ -489,7 +499,7 @@ class PathBuilder
 #define __ValueConverter__
 
 /***************************************************************************************
-                                                               ValueConverter.h
+                                                                ValueConverter.h
                             (GRAME, Copyright 2015-2019)
 
 Set of conversion objects used to map user interface values (for example a gui slider
@@ -499,8 +509,9 @@ delivering values between 0 and 1) to faust values (for example a vslider betwee
 -- Utilities
 
 Range(lo,hi) : clip a value x between lo and hi
-Interpolator(lo,hi,v1,v2) : Maps a value x between lo and hi to a value y between v1 and v2
-Interpolator3pt(lo,mi,hi,v1,vm,v2) : Map values between lo mid hi to values between v1 vm v2
+Interpolator(lo,hi,v1,v2) : Maps a value x between lo and hi to a value y between v1 and
+v2 Interpolator3pt(lo,mi,hi,v1,vm,v2) : Map values between lo mid hi to values between v1
+vm v2
 
 -- Value Converters
 
@@ -531,11 +542,11 @@ ZoneReader(zone, valueConverter) : a zone with a data converter
 
 ****************************************************************************************/
 
-#include <float.h>
-#include <algorithm>    // std::max
+#include <algorithm>  // std::max
+#include <cassert>
+#include <cfloat>
 #include <cmath>
 #include <vector>
-#include <assert.h>
 
 //--------------------------------------------------------------------------------------
 // Interpolator(lo,hi,v1,v2)
@@ -548,50 +559,49 @@ ZoneReader(zone, valueConverter) : a zone with a data converter
 //--------------------------------------------------------------------------------------
 class Interpolator
 {
-    private:
-
-        //--------------------------------------------------------------------------------------
-        // Range(lo,hi) clip a value between lo and hi
-        //--------------------------------------------------------------------------------------
-        struct Range
-        {
-            double fLo;
-            double fHi;
-
-            Range(double x, double y) : fLo(std::min<double>(x,y)), fHi(std::max<double>(x,y)) {}
-            double operator()(double x) { return (x<fLo) ? fLo : (x>fHi) ? fHi : x; }
-        };
-
-
-        Range fRange;
-        double fCoef;
-        double fOffset;
-
-    public:
-
-        Interpolator(double lo, double hi, double v1, double v2) : fRange(lo,hi)
-        {
-            if (hi != lo) {
-                // regular case
-                fCoef = (v2-v1)/(hi-lo);
-                fOffset = v1 - lo*fCoef;
-            } else {
-                // degenerate case, avoids division by zero
-                fCoef = 0;
-                fOffset = (v1+v2)/2;
-            }
-        }
-        double operator()(double v)
+   private:
+    //--------------------------------------------------------------------------------------
+    // Range(lo,hi) clip a value between lo and hi
+    //--------------------------------------------------------------------------------------
+    struct Range {
+        double fLo;
+        double fHi;
+
+        Range(double x, double y)
+            : fLo(std::min<double>(x, y)), fHi(std::max<double>(x, y))
         {
-            double x = fRange(v);
-            return  fOffset + x*fCoef;
         }
-
-        void getLowHigh(double& amin, double& amax)
-        {
-            amin = fRange.fLo;
-            amax = fRange.fHi;
+        double operator()(double x) { return (x < fLo) ? fLo : (x > fHi) ? fHi : x; }
+    };
+
+    Range fRange;
+    double fCoef;
+    double fOffset;
+
+   public:
+    Interpolator(double lo, double hi, double v1, double v2) : fRange(lo, hi)
+    {
+        if (hi != lo) {
+            // regular case
+            fCoef   = (v2 - v1) / (hi - lo);
+            fOffset = v1 - lo * fCoef;
+        } else {
+            // degenerate case, avoids division by zero
+            fCoef   = 0;
+            fOffset = (v1 + v2) / 2;
         }
+    }
+    double operator()(double v)
+    {
+        double x = fRange(v);
+        return fOffset + x * fCoef;
+    }
+
+    void getLowHigh(double& amin, double& amax)
+    {
+        amin = fRange.fLo;
+        amax = fRange.fHi;
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -600,26 +610,23 @@ class Interpolator
 //--------------------------------------------------------------------------------------
 class Interpolator3pt
 {
-
-    private:
-
-        Interpolator fSegment1;
-        Interpolator fSegment2;
-        double fMid;
-
-    public:
-
-        Interpolator3pt(double lo, double mi, double hi, double v1, double vm, double v2) :
-            fSegment1(lo, mi, v1, vm),
-            fSegment2(mi, hi, vm, v2),
-            fMid(mi) {}
-        double operator()(double x) { return  (x < fMid) ? fSegment1(x) : fSegment2(x); }
-
-        void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fSegment1.getLowHigh(amin, amid);
-            fSegment2.getLowHigh(amid, amax);
-        }
+   private:
+    Interpolator fSegment1;
+    Interpolator fSegment2;
+    double fMid;
+
+   public:
+    Interpolator3pt(double lo, double mi, double hi, double v1, double vm, double v2)
+        : fSegment1(lo, mi, v1, vm), fSegment2(mi, hi, vm, v2), fMid(mi)
+    {
+    }
+    double operator()(double x) { return (x < fMid) ? fSegment1(x) : fSegment2(x); }
+
+    void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fSegment1.getLowHigh(amin, amid);
+        fSegment2.getLowHigh(amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -627,62 +634,51 @@ class Interpolator3pt
 //--------------------------------------------------------------------------------------
 class ValueConverter
 {
-
-    public:
-
-        virtual ~ValueConverter() {}
-        virtual double ui2faust(double x) = 0;
-        virtual double faust2ui(double x) = 0;
+   public:
+    virtual ~ValueConverter() {}
+    virtual double ui2faust(double x) = 0;
+    virtual double faust2ui(double x) = 0;
 };
 
 //--------------------------------------------------------------------------------------
 // A converter than can be updated
 //--------------------------------------------------------------------------------------
 
-class UpdatableValueConverter : public ValueConverter {
-    
-    protected:
-        
-        bool fActive;
-        
-    public:
-        
-        UpdatableValueConverter():fActive(true)
-        {}
-        virtual ~UpdatableValueConverter()
-        {}
-        
-        virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max) = 0;
-        virtual void getMappingValues(double& amin, double& amid, double& amax) = 0;
-        
-        void setActive(bool on_off) { fActive = on_off; }
-        bool getActive() { return fActive; }
-    
-};
+class UpdatableValueConverter : public ValueConverter
+{
+   protected:
+    bool fActive;
 
+   public:
+    UpdatableValueConverter() : fActive(true) {}
+    virtual ~UpdatableValueConverter() {}
+
+    virtual void setMappingValues(double amin, double amid, double amax, double min,
+                                  double init, double max)                  = 0;
+    virtual void getMappingValues(double& amin, double& amid, double& amax) = 0;
+
+    void setActive(bool on_off) { fActive = on_off; }
+    bool getActive() { return fActive; }
+};
 
 //--------------------------------------------------------------------------------------
 // Linear conversion between ui and Faust values
 //--------------------------------------------------------------------------------------
 class LinearValueConverter : public ValueConverter
 {
-    
-    private:
-        
-        Interpolator fUI2F;
-        Interpolator fF2UI;
-        
-    public:
-        
-        LinearValueConverter(double umin, double umax, double fmin, double fmax) :
-            fUI2F(umin,umax,fmin,fmax), fF2UI(fmin,fmax,umin,umax)
-        {}
-        
-        LinearValueConverter() : fUI2F(0.,0.,0.,0.), fF2UI(0.,0.,0.,0.)
-        {}
-        virtual double ui2faust(double x) { return fUI2F(x); }
-        virtual double faust2ui(double x) { return fF2UI(x); }
-    
+   private:
+    Interpolator fUI2F;
+    Interpolator fF2UI;
+
+   public:
+    LinearValueConverter(double umin, double umax, double fmin, double fmax)
+        : fUI2F(umin, umax, fmin, fmax), fF2UI(fmin, fmax, umin, umax)
+    {
+    }
+
+    LinearValueConverter() : fUI2F(0., 0., 0., 0.), fF2UI(0., 0., 0., 0.) {}
+    virtual double ui2faust(double x) { return fUI2F(x); }
+    virtual double faust2ui(double x) { return fF2UI(x); }
 };
 
 //--------------------------------------------------------------------------------------
@@ -690,35 +686,35 @@ class LinearValueConverter : public ValueConverter
 //--------------------------------------------------------------------------------------
 class LinearValueConverter2 : public UpdatableValueConverter
 {
-    
-    private:
-    
-        Interpolator3pt fUI2F;
-        Interpolator3pt fF2UI;
-        
-    public:
-    
-        LinearValueConverter2(double amin, double amid, double amax, double min, double init, double max) :
-            fUI2F(amin, amid, amax, min, init, max), fF2UI(min, init, max, amin, amid, amax)
-        {}
-        
-        LinearValueConverter2() : fUI2F(0.,0.,0.,0.,0.,0.), fF2UI(0.,0.,0.,0.,0.,0.)
-        {}
-    
-        virtual double ui2faust(double x) { return fUI2F(x); }
-        virtual double faust2ui(double x) { return fF2UI(x); }
-    
-        virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max)
-        {
-            fUI2F = Interpolator3pt(amin, amid, amax, min, init, max);
-            fF2UI = Interpolator3pt(min, init, max, amin, amid, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fUI2F.getMappingValues(amin, amid, amax);
-        }
-    
+   private:
+    Interpolator3pt fUI2F;
+    Interpolator3pt fF2UI;
+
+   public:
+    LinearValueConverter2(double amin, double amid, double amax, double min, double init,
+                          double max)
+        : fUI2F(amin, amid, amax, min, init, max), fF2UI(min, init, max, amin, amid, amax)
+    {
+    }
+
+    LinearValueConverter2() : fUI2F(0., 0., 0., 0., 0., 0.), fF2UI(0., 0., 0., 0., 0., 0.)
+    {
+    }
+
+    virtual double ui2faust(double x) { return fUI2F(x); }
+    virtual double faust2ui(double x) { return fF2UI(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double min,
+                                  double init, double max)
+    {
+        fUI2F = Interpolator3pt(amin, amid, amax, min, init, max);
+        fF2UI = Interpolator3pt(min, init, max, amin, amid, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fUI2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -726,16 +722,21 @@ class LinearValueConverter2 : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class LogValueConverter : public LinearValueConverter
 {
-
-    public:
-
-        LogValueConverter(double umin, double umax, double fmin, double fmax) :
-            LinearValueConverter(umin, umax, std::log(std::max<double>(DBL_MIN, fmin)), std::log(std::max<double>(DBL_MIN, fmax)))
-        {}
-
-        virtual double ui2faust(double x) { return std::exp(LinearValueConverter::ui2faust(x)); }
-        virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::log(std::max<double>(x, DBL_MIN))); }
-
+   public:
+    LogValueConverter(double umin, double umax, double fmin, double fmax)
+        : LinearValueConverter(umin, umax, std::log(std::max<double>(DBL_MIN, fmin)),
+                               std::log(std::max<double>(DBL_MIN, fmax)))
+    {
+    }
+
+    virtual double ui2faust(double x)
+    {
+        return std::exp(LinearValueConverter::ui2faust(x));
+    }
+    virtual double faust2ui(double x)
+    {
+        return LinearValueConverter::faust2ui(std::log(std::max<double>(x, DBL_MIN)));
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -743,16 +744,21 @@ class LogValueConverter : public LinearValueConverter
 //--------------------------------------------------------------------------------------
 class ExpValueConverter : public LinearValueConverter
 {
-
-    public:
-
-        ExpValueConverter(double umin, double umax, double fmin, double fmax) :
-            LinearValueConverter(umin, umax, std::min<double>(DBL_MAX, std::exp(fmin)), std::min<double>(DBL_MAX, std::exp(fmax)))
-        {}
-
-        virtual double ui2faust(double x) { return std::log(LinearValueConverter::ui2faust(x)); }
-        virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::min<double>(DBL_MAX, std::exp(x))); }
-
+   public:
+    ExpValueConverter(double umin, double umax, double fmin, double fmax)
+        : LinearValueConverter(umin, umax, std::min<double>(DBL_MAX, std::exp(fmin)),
+                               std::min<double>(DBL_MAX, std::exp(fmax)))
+    {
+    }
+
+    virtual double ui2faust(double x)
+    {
+        return std::log(LinearValueConverter::ui2faust(x));
+    }
+    virtual double faust2ui(double x)
+    {
+        return LinearValueConverter::faust2ui(std::min<double>(DBL_MAX, std::exp(x)));
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -761,34 +767,34 @@ class ExpValueConverter : public LinearValueConverter
 //--------------------------------------------------------------------------------------
 class AccUpConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt fA2F;
-        Interpolator3pt fF2A;
-
-    public:
-
-        AccUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmin,fmid,fmax),
-            fF2A(fmin,fmid,fmax,amin,amid,amax)
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-            //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmin, fmid, fmax);
-            fF2A = Interpolator3pt(fmin, fmid, fmax, amin, amid, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
-
+   private:
+    Interpolator3pt fA2F;
+    Interpolator3pt fF2A;
+
+   public:
+    AccUpConverter(double amin, double amid, double amax, double fmin, double fmid,
+                   double fmax)
+        : fA2F(amin, amid, amax, fmin, fmid, fmax)
+        , fF2A(fmin, fmid, fmax, amin, amid, amax)
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double fmid, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpConverter update %f %f %f
+        //%f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmin, fmid, fmax);
+        fF2A = Interpolator3pt(fmin, fmid, fmax, amin, amid, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -797,33 +803,34 @@ class AccUpConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class AccDownConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt        fA2F;
-        Interpolator3pt        fF2A;
-
-    public:
-
-        AccDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmax,fmid,fmin),
-            fF2A(fmin,fmid,fmax,amax,amid,amin)
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-             //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmax, fmid, fmin);
-            fF2A = Interpolator3pt(fmin, fmid, fmax, amax, amid, amin);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
+   private:
+    Interpolator3pt fA2F;
+    Interpolator3pt fF2A;
+
+   public:
+    AccDownConverter(double amin, double amid, double amax, double fmin, double fmid,
+                     double fmax)
+        : fA2F(amin, amid, amax, fmax, fmid, fmin)
+        , fF2A(fmin, fmid, fmax, amax, amid, amin)
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double fmid, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownConverter update %f %f
+        //%f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmax, fmid, fmin);
+        fF2A = Interpolator3pt(fmin, fmid, fmax, amax, amid, amin);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -832,33 +839,35 @@ class AccDownConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class AccUpDownConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt        fA2F;
-        Interpolator fF2A;
-
-    public:
-
-        AccUpDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmin,fmax,fmin),
-            fF2A(fmin,fmax,amin,amax)                          // Special, pseudo inverse of a non monotonic function
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-            //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmin, fmax, fmin);
-            fF2A = Interpolator(fmin, fmax, amin, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
+   private:
+    Interpolator3pt fA2F;
+    Interpolator fF2A;
+
+   public:
+    AccUpDownConverter(double amin, double amid, double amax, double fmin, double fmid,
+                       double fmax)
+        : fA2F(amin, amid, amax, fmin, fmax, fmin)
+        , fF2A(fmin, fmax, amin,
+               amax)  // Special, pseudo inverse of a non monotonic function
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double fmid, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpDownConverter update %f %f
+        //%f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmin, fmax, fmin);
+        fF2A = Interpolator(fmin, fmax, amin, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -867,33 +876,35 @@ class AccUpDownConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class AccDownUpConverter : public UpdatableValueConverter
 {
-
-    private:
-
-        Interpolator3pt        fA2F;
-        Interpolator fF2A;
-
-    public:
-
-        AccDownUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
-            fA2F(amin,amid,amax,fmax,fmin,fmax),
-            fF2A(fmin,fmax,amin,amax)                          // Special, pseudo inverse of a non monotonic function
-        {}
-
-        virtual double ui2faust(double x) { return fA2F(x); }
-        virtual double faust2ui(double x) { return fF2A(x); }
-
-        virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
-        {
-            //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
-            fA2F = Interpolator3pt(amin, amid, amax, fmax, fmin, fmax);
-            fF2A = Interpolator(fmin, fmax, amin, amax);
-        }
-
-        virtual void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fA2F.getMappingValues(amin, amid, amax);
-        }
+   private:
+    Interpolator3pt fA2F;
+    Interpolator fF2A;
+
+   public:
+    AccDownUpConverter(double amin, double amid, double amax, double fmin, double fmid,
+                       double fmax)
+        : fA2F(amin, amid, amax, fmax, fmin, fmax)
+        , fF2A(fmin, fmax, amin,
+               amax)  // Special, pseudo inverse of a non monotonic function
+    {
+    }
+
+    virtual double ui2faust(double x) { return fA2F(x); }
+    virtual double faust2ui(double x) { return fF2A(x); }
+
+    virtual void setMappingValues(double amin, double amid, double amax, double fmin,
+                                  double fmid, double fmax)
+    {
+        //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownUpConverter update %f %f
+        //%f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+        fA2F = Interpolator3pt(amin, amid, amax, fmax, fmin, fmax);
+        fF2A = Interpolator(fmin, fmax, amin, amax);
+    }
+
+    virtual void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fA2F.getMappingValues(amin, amid, amax);
+    }
 };
 
 //--------------------------------------------------------------------------------------
@@ -901,28 +912,27 @@ class AccDownUpConverter : public UpdatableValueConverter
 //--------------------------------------------------------------------------------------
 class ZoneControl
 {
+   protected:
+    FAUSTFLOAT* fZone;
 
-    protected:
-
-        FAUSTFLOAT*    fZone;
-
-    public:
-
-        ZoneControl(FAUSTFLOAT* zone) : fZone(zone) {}
-        virtual ~ZoneControl() {}
+   public:
+    ZoneControl(FAUSTFLOAT* zone) : fZone(zone) {}
+    virtual ~ZoneControl() {}
 
-        virtual void update(double v) const {}
+    virtual void update(double v) const {}
 
-        virtual void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max) {}
-        virtual void getMappingValues(double& amin, double& amid, double& amax) {}
+    virtual void setMappingValues(int curve, double amin, double amid, double amax,
+                                  double min, double init, double max)
+    {
+    }
+    virtual void getMappingValues(double& amin, double& amid, double& amax) {}
 
-        FAUSTFLOAT* getZone() { return fZone; }
+    FAUSTFLOAT* getZone() { return fZone; }
 
-        virtual void setActive(bool on_off) {}
-        virtual bool getActive() { return false; }
-
-        virtual int getCurve() { return -1; }
+    virtual void setActive(bool on_off) {}
+    virtual bool getActive() { return false; }
 
+    virtual int getCurve() { return -1; }
 };
 
 //--------------------------------------------------------------------------------------
@@ -930,20 +940,22 @@ class ZoneControl
 //--------------------------------------------------------------------------------------
 class ConverterZoneControl : public ZoneControl
 {
-
-    protected:
-
-        ValueConverter* fValueConverter;
-
-    public:
-
-        ConverterZoneControl(FAUSTFLOAT* zone, ValueConverter* converter) : ZoneControl(zone), fValueConverter(converter) {}
-        virtual ~ConverterZoneControl() { delete fValueConverter; } // Assuming fValueConverter is not kept elsewhere...
-
-        virtual void update(double v) const { *fZone = fValueConverter->ui2faust(v); }
-
-        ValueConverter* getConverter() { return fValueConverter; }
-
+   protected:
+    ValueConverter* fValueConverter;
+
+   public:
+    ConverterZoneControl(FAUSTFLOAT* zone, ValueConverter* converter)
+        : ZoneControl(zone), fValueConverter(converter)
+    {
+    }
+    virtual ~ConverterZoneControl()
+    {
+        delete fValueConverter;
+    }  // Assuming fValueConverter is not kept elsewhere...
+
+    virtual void update(double v) const { *fZone = fValueConverter->ui2faust(v); }
+
+    ValueConverter* getConverter() { return fValueConverter; }
 };
 
 //--------------------------------------------------------------------------------------
@@ -952,592 +964,613 @@ class ConverterZoneControl : public ZoneControl
 //--------------------------------------------------------------------------------------
 class CurveZoneControl : public ZoneControl
 {
-
-    private:
-
-        std::vector<UpdatableValueConverter*> fValueConverters;
-        int fCurve;
-
-    public:
-
-        CurveZoneControl(FAUSTFLOAT* zone, int curve, double amin, double amid, double amax, double min, double init, double max) : ZoneControl(zone), fCurve(0)
-        {
-            assert(curve >= 0 && curve <= 3);
-            fValueConverters.push_back(new AccUpConverter(amin, amid, amax, min, init, max));
-            fValueConverters.push_back(new AccDownConverter(amin, amid, amax, min, init, max));
-            fValueConverters.push_back(new AccUpDownConverter(amin, amid, amax, min, init, max));
-            fValueConverters.push_back(new AccDownUpConverter(amin, amid, amax, min, init, max));
-            fCurve = curve;
-        }
-        virtual ~CurveZoneControl()
-        {
-            std::vector<UpdatableValueConverter*>::iterator it;
-            for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
-                delete(*it);
-            }
-        }
-        void update(double v) const { if (fValueConverters[fCurve]->getActive()) *fZone = fValueConverters[fCurve]->ui2faust(v); }
-
-        void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max)
-        {
-            fValueConverters[curve]->setMappingValues(amin, amid, amax, min, init, max);
-            fCurve = curve;
-        }
-
-        void getMappingValues(double& amin, double& amid, double& amax)
-        {
-            fValueConverters[fCurve]->getMappingValues(amin, amid, amax);
+   private:
+    std::vector<UpdatableValueConverter*> fValueConverters;
+    int fCurve;
+
+   public:
+    CurveZoneControl(FAUSTFLOAT* zone, int curve, double amin, double amid, double amax,
+                     double min, double init, double max)
+        : ZoneControl(zone), fCurve(0)
+    {
+        assert(curve >= 0 && curve <= 3);
+        fValueConverters.push_back(new AccUpConverter(amin, amid, amax, min, init, max));
+        fValueConverters.push_back(
+            new AccDownConverter(amin, amid, amax, min, init, max));
+        fValueConverters.push_back(
+            new AccUpDownConverter(amin, amid, amax, min, init, max));
+        fValueConverters.push_back(
+            new AccDownUpConverter(amin, amid, amax, min, init, max));
+        fCurve = curve;
+    }
+    virtual ~CurveZoneControl()
+    {
+        std::vector<UpdatableValueConverter*>::iterator it;
+        for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+            delete (*it);
         }
-
-        void setActive(bool on_off)
-        {
-            std::vector<UpdatableValueConverter*>::iterator it;
-            for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
-                (*it)->setActive(on_off);
-            }
+    }
+    void update(double v) const
+    {
+        if (fValueConverters[fCurve]->getActive())
+            *fZone = fValueConverters[fCurve]->ui2faust(v);
+    }
+
+    void setMappingValues(int curve, double amin, double amid, double amax, double min,
+                          double init, double max)
+    {
+        fValueConverters[curve]->setMappingValues(amin, amid, amax, min, init, max);
+        fCurve = curve;
+    }
+
+    void getMappingValues(double& amin, double& amid, double& amax)
+    {
+        fValueConverters[fCurve]->getMappingValues(amin, amid, amax);
+    }
+
+    void setActive(bool on_off)
+    {
+        std::vector<UpdatableValueConverter*>::iterator it;
+        for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+            (*it)->setActive(on_off);
         }
+    }
 
-        int getCurve() { return fCurve; }
+    int getCurve() { return fCurve; }
 };
 
 class ZoneReader
 {
+   private:
+    FAUSTFLOAT* fZone;
+    Interpolator fInterpolator;
 
-    private:
+   public:
+    ZoneReader(FAUSTFLOAT* zone, double lo, double hi)
+        : fZone(zone), fInterpolator(lo, hi, 0, 255)
+    {
+    }
 
-        FAUSTFLOAT* fZone;
-        Interpolator fInterpolator;
-
-    public:
-
-        ZoneReader(FAUSTFLOAT* zone, double lo, double hi) : fZone(zone), fInterpolator(lo, hi, 0, 255) {}
-
-        virtual ~ZoneReader() {}
-
-        int getValue()
-        {
-            return (fZone != nullptr) ? int(fInterpolator(*fZone)) : 127;
-        }
+    virtual ~ZoneReader() {}
 
+    int getValue() { return (fZone != nullptr) ? int(fInterpolator(*fZone)) : 127; }
 };
 
 #endif
 /**************************  END  ValueConverter.h **************************/
 
-class APIUI : public PathBuilder, public Meta, public UI
+class APIUI
+    : public PathBuilder
+    , public Meta
+    , public UI
 {
-    public:
-    
-        enum ItemType { kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph };
-  
-    protected:
-    
-        enum { kLin = 0, kLog = 1, kExp = 2 };
-    
-        int fNumParameters;
-        std::vector<std::string> fPaths;
-        std::vector<std::string> fLabels;
-        std::map<std::string, int> fPathMap;
-        std::map<std::string, int> fLabelMap;
-        std::vector<ValueConverter*> fConversion;
-        std::vector<FAUSTFLOAT*> fZone;
-        std::vector<FAUSTFLOAT> fInit;
-        std::vector<FAUSTFLOAT> fMin;
-        std::vector<FAUSTFLOAT> fMax;
-        std::vector<FAUSTFLOAT> fStep;
-        std::vector<ItemType> fItemType;
-        std::vector<std::map<std::string, std::string> > fMetaData;
-        std::vector<ZoneControl*> fAcc[3];
-        std::vector<ZoneControl*> fGyr[3];
-
-        // Screen color control
-        // "...[screencolor:red]..." etc.
-        bool fHasScreenControl;      // true if control screen color metadata
-        ZoneReader* fRedReader;
-        ZoneReader* fGreenReader;
-        ZoneReader* fBlueReader;
-
-        // Current values controlled by metadata
-        std::string fCurrentUnit;
-        int fCurrentScale;
-        std::string fCurrentAcc;
-        std::string fCurrentGyr;
-        std::string fCurrentColor;
-        std::string fCurrentTooltip;
-        std::map<std::string, std::string> fCurrentMetadata;
-    
-        // Add a generic parameter
-        virtual void addParameter(const char* label,
-                                FAUSTFLOAT* zone,
-                                FAUSTFLOAT init,
-                                FAUSTFLOAT min,
-                                FAUSTFLOAT max,
-                                FAUSTFLOAT step,
-                                ItemType type)
-        {
-            std::string path = buildPath(label);
-            fPathMap[path] = fLabelMap[label] = fNumParameters++;
-            fPaths.push_back(path);
-            fLabels.push_back(label);
-            fZone.push_back(zone);
-            fInit.push_back(init);
-            fMin.push_back(min);
-            fMax.push_back(max);
-            fStep.push_back(step);
-            fItemType.push_back(type);
-            
-            // handle scale metadata
-            switch (fCurrentScale) {
-                case kLin:
-                    fConversion.push_back(new LinearValueConverter(0, 1, min, max));
-                    break;
-                case kLog:
-                    fConversion.push_back(new LogValueConverter(0, 1, min, max));
-                    break;
-                case kExp: fConversion.push_back(new ExpValueConverter(0, 1, min, max));
-                    break;
-            }
-            fCurrentScale = kLin;
-            
-            if (fCurrentAcc.size() > 0 && fCurrentGyr.size() > 0) {
-                std::cerr << "warning : 'acc' and 'gyr' metadata used for the same " << label << " parameter !!\n";
-            }
+   public:
+    enum ItemType {
+        kButton = 0,
+        kCheckButton,
+        kVSlider,
+        kHSlider,
+        kNumEntry,
+        kHBargraph,
+        kVBargraph
+    };
+
+   protected:
+    enum { kLin = 0, kLog = 1, kExp = 2 };
+
+    int fNumParameters;
+    std::vector<std::string> fPaths;
+    std::vector<std::string> fLabels;
+    std::map<std::string, int> fPathMap;
+    std::map<std::string, int> fLabelMap;
+    std::vector<ValueConverter*> fConversion;
+    std::vector<FAUSTFLOAT*> fZone;
+    std::vector<FAUSTFLOAT> fInit;
+    std::vector<FAUSTFLOAT> fMin;
+    std::vector<FAUSTFLOAT> fMax;
+    std::vector<FAUSTFLOAT> fStep;
+    std::vector<ItemType> fItemType;
+    std::vector<std::map<std::string, std::string> > fMetaData;
+    std::vector<ZoneControl*> fAcc[3];
+    std::vector<ZoneControl*> fGyr[3];
+
+    // Screen color control
+    // "...[screencolor:red]..." etc.
+    bool fHasScreenControl;  // true if control screen color metadata
+    ZoneReader* fRedReader;
+    ZoneReader* fGreenReader;
+    ZoneReader* fBlueReader;
+
+    // Current values controlled by metadata
+    std::string fCurrentUnit;
+    int fCurrentScale;
+    std::string fCurrentAcc;
+    std::string fCurrentGyr;
+    std::string fCurrentColor;
+    std::string fCurrentTooltip;
+    std::map<std::string, std::string> fCurrentMetadata;
+
+    // Add a generic parameter
+    virtual void addParameter(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                              FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step,
+                              ItemType type)
+    {
+        std::string path = buildPath(label);
+        fPathMap[path] = fLabelMap[label] = fNumParameters++;
+        fPaths.push_back(path);
+        fLabels.push_back(label);
+        fZone.push_back(zone);
+        fInit.push_back(init);
+        fMin.push_back(min);
+        fMax.push_back(max);
+        fStep.push_back(step);
+        fItemType.push_back(type);
+
+        // handle scale metadata
+        switch (fCurrentScale) {
+        case kLin:
+            fConversion.push_back(new LinearValueConverter(0, 1, min, max));
+            break;
+        case kLog:
+            fConversion.push_back(new LogValueConverter(0, 1, min, max));
+            break;
+        case kExp:
+            fConversion.push_back(new ExpValueConverter(0, 1, min, max));
+            break;
+        }
+        fCurrentScale = kLin;
 
-            // handle acc metadata "...[acc : <axe> <curve> <amin> <amid> <amax>]..."
-            if (fCurrentAcc.size() > 0) {
-                std::istringstream iss(fCurrentAcc);
-                int axe, curve;
-                double amin, amid, amax;
-                iss >> axe >> curve >> amin >> amid >> amax;
-
-                if ((0 <= axe) && (axe < 3) &&
-                    (0 <= curve) && (curve < 4) &&
-                    (amin < amax) && (amin <= amid) && (amid <= amax))
-                {
-                    fAcc[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
-                } else {
-                    std::cerr << "incorrect acc metadata : " << fCurrentAcc << std::endl;
-                }
-                fCurrentAcc = "";
-            }
-       
-            // handle gyr metadata "...[gyr : <axe> <curve> <amin> <amid> <amax>]..."
-            if (fCurrentGyr.size() > 0) {
-                std::istringstream iss(fCurrentGyr);
-                int axe, curve;
-                double amin, amid, amax;
-                iss >> axe >> curve >> amin >> amid >> amax;
-
-                if ((0 <= axe) && (axe < 3) &&
-                    (0 <= curve) && (curve < 4) &&
-                    (amin < amax) && (amin <= amid) && (amid <= amax))
-                {
-                    fGyr[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
-                } else {
-                    std::cerr << "incorrect gyr metadata : " << fCurrentGyr << std::endl;
-                }
-                fCurrentGyr = "";
-            }
-        
-            // handle screencolor metadata "...[screencolor:red|green|blue|white]..."
-            if (fCurrentColor.size() > 0) {
-                if ((fCurrentColor == "red") && (fRedReader == 0)) {
-                    fRedReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else if ((fCurrentColor == "green") && (fGreenReader == 0)) {
-                    fGreenReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else if ((fCurrentColor == "blue") && (fBlueReader == 0)) {
-                    fBlueReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else if ((fCurrentColor == "white") && (fRedReader == 0) && (fGreenReader == 0) && (fBlueReader == 0)) {
-                    fRedReader = new ZoneReader(zone, min, max);
-                    fGreenReader = new ZoneReader(zone, min, max);
-                    fBlueReader = new ZoneReader(zone, min, max);
-                    fHasScreenControl = true;
-                } else {
-                    std::cerr << "incorrect screencolor metadata : " << fCurrentColor << std::endl;
-                }
-            }
-            fCurrentColor = "";
-            
-            fMetaData.push_back(fCurrentMetadata);
-            fCurrentMetadata.clear();
+        if (fCurrentAcc.size() > 0 && fCurrentGyr.size() > 0) {
+            std::cerr << "warning : 'acc' and 'gyr' metadata used for the same " << label
+                      << " parameter !!\n";
         }
 
-        int getZoneIndex(std::vector<ZoneControl*>* table, int p, int val)
-        {
-            FAUSTFLOAT* zone = fZone[p];
-            for (size_t i = 0; i < table[val].size(); i++) {
-                if (zone == table[val][i]->getZone()) return int(i);
+        // handle acc metadata "...[acc : <axe> <curve> <amin> <amid> <amax>]..."
+        if (fCurrentAcc.size() > 0) {
+            std::istringstream iss(fCurrentAcc);
+            int axe, curve;
+            double amin, amid, amax;
+            iss >> axe >> curve >> amin >> amid >> amax;
+
+            if ((0 <= axe) && (axe < 3) && (0 <= curve) && (curve < 4) && (amin < amax)
+                && (amin <= amid) && (amid <= amax)) {
+                fAcc[axe].push_back(
+                    new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
+            } else {
+                std::cerr << "incorrect acc metadata : " << fCurrentAcc << std::endl;
             }
-            return -1;
+            fCurrentAcc = "";
         }
-    
-        void setConverter(std::vector<ZoneControl*>* table, int p, int val, int curve, double amin, double amid, double amax)
-        {
-            int id1 = getZoneIndex(table, p, 0);
-            int id2 = getZoneIndex(table, p, 1);
-            int id3 = getZoneIndex(table, p, 2);
-            
-            // Deactivates everywhere..
-            if (id1 != -1) table[0][id1]->setActive(false);
-            if (id2 != -1) table[1][id2]->setActive(false);
-            if (id3 != -1) table[2][id3]->setActive(false);
-            
-            if (val == -1) { // Means: no more mapping...
-                // So stay all deactivated...
+
+        // handle gyr metadata "...[gyr : <axe> <curve> <amin> <amid> <amax>]..."
+        if (fCurrentGyr.size() > 0) {
+            std::istringstream iss(fCurrentGyr);
+            int axe, curve;
+            double amin, amid, amax;
+            iss >> axe >> curve >> amin >> amid >> amax;
+
+            if ((0 <= axe) && (axe < 3) && (0 <= curve) && (curve < 4) && (amin < amax)
+                && (amin <= amid) && (amid <= amax)) {
+                fGyr[axe].push_back(
+                    new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
             } else {
-                int id4 = getZoneIndex(table, p, val);
-                if (id4 != -1) {
-                    // Reactivate the one we edit...
-                    table[val][id4]->setMappingValues(curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]);
-                    table[val][id4]->setActive(true);
-                } else {
-                    // Allocate a new CurveZoneControl which is 'active' by default
-                    FAUSTFLOAT* zone = fZone[p];
-                    table[val].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]));
-                }
+                std::cerr << "incorrect gyr metadata : " << fCurrentGyr << std::endl;
             }
+            fCurrentGyr = "";
         }
-    
-        void getConverter(std::vector<ZoneControl*>* table, int p, int& val, int& curve, double& amin, double& amid, double& amax)
-        {
-            int id1 = getZoneIndex(table, p, 0);
-            int id2 = getZoneIndex(table, p, 1);
-            int id3 = getZoneIndex(table, p, 2);
-            
-            if (id1 != -1) {
-                val = 0;
-                curve = table[val][id1]->getCurve();
-                table[val][id1]->getMappingValues(amin, amid, amax);
-            } else if (id2 != -1) {
-                val = 1;
-                curve = table[val][id2]->getCurve();
-                table[val][id2]->getMappingValues(amin, amid, amax);
-            } else if (id3 != -1) {
-                val = 2;
-                curve = table[val][id3]->getCurve();
-                table[val][id3]->getMappingValues(amin, amid, amax);
+
+        // handle screencolor metadata "...[screencolor:red|green|blue|white]..."
+        if (fCurrentColor.size() > 0) {
+            if ((fCurrentColor == "red") && (fRedReader == 0)) {
+                fRedReader        = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
+            } else if ((fCurrentColor == "green") && (fGreenReader == 0)) {
+                fGreenReader      = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
+            } else if ((fCurrentColor == "blue") && (fBlueReader == 0)) {
+                fBlueReader       = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
+            } else if ((fCurrentColor == "white") && (fRedReader == 0)
+                       && (fGreenReader == 0) && (fBlueReader == 0)) {
+                fRedReader        = new ZoneReader(zone, min, max);
+                fGreenReader      = new ZoneReader(zone, min, max);
+                fBlueReader       = new ZoneReader(zone, min, max);
+                fHasScreenControl = true;
             } else {
-                val = -1; // No mapping
-                curve = 0;
-                amin = -100.;
-                amid = 0.;
-                amax = 100.;
+                std::cerr << "incorrect screencolor metadata : " << fCurrentColor
+                          << std::endl;
             }
         }
+        fCurrentColor = "";
 
-     public:
-    
-        enum Type { kAcc = 0, kGyr = 1, kNoType };
-   
-        APIUI() : fNumParameters(0), fHasScreenControl(false), fRedReader(0), fGreenReader(0), fBlueReader(0), fCurrentScale(kLin)
-        {}
+        fMetaData.push_back(fCurrentMetadata);
+        fCurrentMetadata.clear();
+    }
 
-        virtual ~APIUI()
-        {
-            for (auto& it : fConversion) delete it;
-            for (int i = 0; i < 3; i++) {
-                for (auto& it : fAcc[i]) delete it;
-                for (auto& it : fGyr[i]) delete it;
+    int getZoneIndex(std::vector<ZoneControl*>* table, int p, int val)
+    {
+        FAUSTFLOAT* zone = fZone[p];
+        for (size_t i = 0; i < table[val].size(); i++) {
+            if (zone == table[val][i]->getZone()) return int(i);
+        }
+        return -1;
+    }
+
+    void setConverter(std::vector<ZoneControl*>* table, int p, int val, int curve,
+                      double amin, double amid, double amax)
+    {
+        int id1 = getZoneIndex(table, p, 0);
+        int id2 = getZoneIndex(table, p, 1);
+        int id3 = getZoneIndex(table, p, 2);
+
+        // Deactivates everywhere..
+        if (id1 != -1) table[0][id1]->setActive(false);
+        if (id2 != -1) table[1][id2]->setActive(false);
+        if (id3 != -1) table[2][id3]->setActive(false);
+
+        if (val == -1) {  // Means: no more mapping...
+            // So stay all deactivated...
+        } else {
+            int id4 = getZoneIndex(table, p, val);
+            if (id4 != -1) {
+                // Reactivate the one we edit...
+                table[val][id4]->setMappingValues(curve, amin, amid, amax, fMin[p],
+                                                  fInit[p], fMax[p]);
+                table[val][id4]->setActive(true);
+            } else {
+                // Allocate a new CurveZoneControl which is 'active' by default
+                FAUSTFLOAT* zone = fZone[p];
+                table[val].push_back(new CurveZoneControl(zone, curve, amin, amid, amax,
+                                                          fMin[p], fInit[p], fMax[p]));
             }
-            delete fRedReader;
-            delete fGreenReader;
-            delete fBlueReader;
         }
-    
-        // -- widget's layouts
-
-        virtual void openTabBox(const char* label) { pushLabel(label); }
-        virtual void openHorizontalBox(const char* label) { pushLabel(label); }
-        virtual void openVerticalBox(const char* label) { pushLabel(label); }
-        virtual void closeBox() { popLabel(); }
-
-        // -- active widgets
-
-        virtual void addButton(const char* label, FAUSTFLOAT* zone)
-        {
-            addParameter(label, zone, 0, 0, 1, 1, kButton);
+    }
+
+    void getConverter(std::vector<ZoneControl*>* table, int p, int& val, int& curve,
+                      double& amin, double& amid, double& amax)
+    {
+        int id1 = getZoneIndex(table, p, 0);
+        int id2 = getZoneIndex(table, p, 1);
+        int id3 = getZoneIndex(table, p, 2);
+
+        if (id1 != -1) {
+            val   = 0;
+            curve = table[val][id1]->getCurve();
+            table[val][id1]->getMappingValues(amin, amid, amax);
+        } else if (id2 != -1) {
+            val   = 1;
+            curve = table[val][id2]->getCurve();
+            table[val][id2]->getMappingValues(amin, amid, amax);
+        } else if (id3 != -1) {
+            val   = 2;
+            curve = table[val][id3]->getCurve();
+            table[val][id3]->getMappingValues(amin, amid, amax);
+        } else {
+            val   = -1;  // No mapping
+            curve = 0;
+            amin  = -100.;
+            amid  = 0.;
+            amax  = 100.;
         }
-
-        virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
-        {
-            addParameter(label, zone, 0, 0, 1, 1, kCheckButton);
+    }
+
+   public:
+    enum Type { kAcc = 0, kGyr = 1, kNoType };
+
+    APIUI()
+        : fNumParameters(0)
+        , fHasScreenControl(false)
+        , fRedReader(0)
+        , fGreenReader(0)
+        , fBlueReader(0)
+        , fCurrentScale(kLin)
+    {
+    }
+
+    virtual ~APIUI()
+    {
+        for (auto& it : fConversion) delete it;
+        for (int i = 0; i < 3; i++) {
+            for (auto& it : fAcc[i]) delete it;
+            for (auto& it : fGyr[i]) delete it;
         }
+        delete fRedReader;
+        delete fGreenReader;
+        delete fBlueReader;
+    }
 
-        virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
-        {
-            addParameter(label, zone, init, min, max, step, kVSlider);
-        }
+    // -- widget's layouts
 
-        virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
-        {
-            addParameter(label, zone, init, min, max, step, kHSlider);
-        }
+    virtual void openTabBox(const char* label) { pushLabel(label); }
+    virtual void openHorizontalBox(const char* label) { pushLabel(label); }
+    virtual void openVerticalBox(const char* label) { pushLabel(label); }
+    virtual void closeBox() { popLabel(); }
 
-        virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
-        {
-            addParameter(label, zone, init, min, max, step, kNumEntry);
-        }
+    // -- active widgets
 
-        // -- passive widgets
+    virtual void addButton(const char* label, FAUSTFLOAT* zone)
+    {
+        addParameter(label, zone, 0, 0, 1, 1, kButton);
+    }
+
+    virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
+    {
+        addParameter(label, zone, 0, 0, 1, 1, kCheckButton);
+    }
+
+    virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                                   FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+    {
+        addParameter(label, zone, init, min, max, step, kVSlider);
+    }
+
+    virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                                     FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+    {
+        addParameter(label, zone, init, min, max, step, kHSlider);
+    }
+
+    virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init,
+                             FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+    {
+        addParameter(label, zone, init, min, max, step, kNumEntry);
+    }
 
-        virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
-        {
-            addParameter(label, zone, min, min, max, (max-min)/1000.0, kHBargraph);
-        }
+    // -- passive widgets
 
-        virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
-        {
-            addParameter(label, zone, min, min, max, (max-min)/1000.0, kVBargraph);
-        }
-    
-        // -- soundfiles
-    
-        virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) {}
+    virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone,
+                                       FAUSTFLOAT min, FAUSTFLOAT max)
+    {
+        addParameter(label, zone, min, min, max, (max - min) / 1000.0, kHBargraph);
+    }
 
-        // -- metadata declarations
+    virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min,
+                                     FAUSTFLOAT max)
+    {
+        addParameter(label, zone, min, min, max, (max - min) / 1000.0, kVBargraph);
+    }
 
-        virtual void declare(FAUSTFLOAT* zone, const char* key, const char* val)
-        {
-            // Keep metadata
-            fCurrentMetadata[key] = val;
-            
-            if (strcmp(key, "scale") == 0) {
-                if (strcmp(val, "log") == 0) {
-                    fCurrentScale = kLog;
-                } else if (strcmp(val, "exp") == 0) {
-                    fCurrentScale = kExp;
-                } else {
-                    fCurrentScale = kLin;
-                }
-            } else if (strcmp(key, "unit") == 0) {
-                fCurrentUnit = val;
-            } else if (strcmp(key, "acc") == 0) {
-                fCurrentAcc = val;
-            } else if (strcmp(key, "gyr") == 0) {
-                fCurrentGyr = val;
-            } else if (strcmp(key, "screencolor") == 0) {
-                fCurrentColor = val; // val = "red", "green", "blue" or "white"
-            } else if (strcmp(key, "tooltip") == 0) {
-                fCurrentTooltip = val;
-            }
-        }
+    // -- soundfiles
 
-        virtual void declare(const char* key, const char* val)
-        {}
+    virtual void addSoundfile(const char* label, const char* filename,
+                              Soundfile** sf_zone)
+    {
+    }
 
-               //-------------------------------------------------------------------------------
-               // Simple API part
-               //-------------------------------------------------------------------------------
-               int getParamsCount() { return fNumParameters; }
-        int getParamIndex(const char* path)
-        {
-            if (fPathMap.find(path) != fPathMap.end()) {
-                return fPathMap[path];
-            } else if (fLabelMap.find(path) != fLabelMap.end()) {
-                return fLabelMap[path];
-            } else {
-                return -1;
-            }
-        }
-        const char* getParamAddress(int p) { return fPaths[p].c_str(); }
-        const char* getParamLabel(int p) { return fLabels[p].c_str(); }
-        std::map<const char*, const char*> getMetadata(int p)
-        {
-            std::map<const char*, const char*> res;
-            std::map<std::string, std::string> metadata = fMetaData[p];
-            for (auto it : metadata) {
-                res[it.first.c_str()] = it.second.c_str();
-            }
-            return res;
-        }
+    // -- metadata declarations
 
-        const char* getMetadata(int p, const char* key)
-        {
-            return (fMetaData[p].find(key) != fMetaData[p].end()) ? fMetaData[p][key].c_str() : "";
-        }
-        FAUSTFLOAT getParamMin(int p) { return fMin[p]; }
-        FAUSTFLOAT getParamMax(int p) { return fMax[p]; }
-        FAUSTFLOAT getParamStep(int p) { return fStep[p]; }
-        FAUSTFLOAT getParamInit(int p) { return fInit[p]; }
-
-        FAUSTFLOAT* getParamZone(int p) { return fZone[p]; }
-        FAUSTFLOAT getParamValue(int p) { return *fZone[p]; }
-        void setParamValue(int p, FAUSTFLOAT v) { *fZone[p] = v; }
-
-        double getParamRatio(int p) { return fConversion[p]->faust2ui(*fZone[p]); }
-        void setParamRatio(int p, double r) { *fZone[p] = fConversion[p]->ui2faust(r); }
-
-        double value2ratio(int p, double r)    { return fConversion[p]->faust2ui(r); }
-        double ratio2value(int p, double r)    { return fConversion[p]->ui2faust(r); }
-    
-        /**
-         * Return the control type (kAcc, kGyr, or -1) for a given parameter
-         *
-         * @param p - the UI parameter index
-         *
-         * @return the type
-         */
-        Type getParamType(int p)
-        {
-            if (p >= 0) {
-                if (getZoneIndex(fAcc, p, 0) != -1
-                    || getZoneIndex(fAcc, p, 1) != -1
-                    || getZoneIndex(fAcc, p, 2) != -1) {
-                    return kAcc;
-                } else if (getZoneIndex(fGyr, p, 0) != -1
-                           || getZoneIndex(fGyr, p, 1) != -1
-                           || getZoneIndex(fGyr, p, 2) != -1) {
-                    return kGyr;
-                }
-            }
-            return kNoType;
-        }
-    
-        /**
-         * Return the Item type (kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph) for a given parameter
-         *
-         * @param p - the UI parameter index
-         *
-         * @return the Item type
-         */
-        ItemType getParamItemType(int p)
-        {
-            return fItemType[p];
-        }
-   
-        /**
-         * Set a new value coming from an accelerometer, propagate it to all relevant FAUSTFLOAT* zones.
-         *
-         * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
-         * @param value - the new value
-         *
-         */
-        void propagateAcc(int acc, double value)
-        {
-            for (size_t i = 0; i < fAcc[acc].size(); i++) {
-                fAcc[acc][i]->update(value);
-            }
-        }
-    
-        /**
-         * Used to edit accelerometer curves and mapping. Set curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer (-1 means "no mapping")
-         * @param curve - between 0 and 3
-         * @param amin - mapping 'min' point
-         * @param amid - mapping 'middle' point
-         * @param amax - mapping 'max' point
-         *
-         */
-        void setAccConverter(int p, int acc, int curve, double amin, double amid, double amax)
-        {
-            setConverter(fAcc, p, acc, curve, amin, amid, amax);
-        }
-    
-        /**
-         * Used to edit gyroscope curves and mapping. Set curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param acc - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope (-1 means "no mapping")
-         * @param curve - between 0 and 3
-         * @param amin - mapping 'min' point
-         * @param amid - mapping 'middle' point
-         * @param amax - mapping 'max' point
-         *
-         */
-        void setGyrConverter(int p, int gyr, int curve, double amin, double amid, double amax)
-        {
-             setConverter(fGyr, p, gyr, curve, amin, amid, amax);
-        }
-    
-        /**
-         * Used to edit accelerometer curves and mapping. Get curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param acc - the acc value to be retrieved (-1 means "no mapping")
-         * @param curve - the curve value to be retrieved
-         * @param amin - the amin value to be retrieved
-         * @param amid - the amid value to be retrieved
-         * @param amax - the amax value to be retrieved
-         *
-         */
-        void getAccConverter(int p, int& acc, int& curve, double& amin, double& amid, double& amax)
-        {
-            getConverter(fAcc, p, acc, curve, amin, amid, amax);
-        }
+    virtual void declare(FAUSTFLOAT* zone, const char* key, const char* val)
+    {
+        // Keep metadata
+        fCurrentMetadata[key] = val;
 
-        /**
-         * Used to edit gyroscope curves and mapping. Get curve and related mapping for a given UI parameter.
-         *
-         * @param p - the UI parameter index
-         * @param gyr - the gyr value to be retrieved (-1 means "no mapping")
-         * @param curve - the curve value to be retrieved
-         * @param amin - the amin value to be retrieved
-         * @param amid - the amid value to be retrieved
-         * @param amax - the amax value to be retrieved
-         *
-         */
-        void getGyrConverter(int p, int& gyr, int& curve, double& amin, double& amid, double& amax)
-        {
-            getConverter(fGyr, p, gyr, curve, amin, amid, amax);
-        }
-    
-        /**
-         * Set a new value coming from an gyroscope, propagate it to all relevant FAUSTFLOAT* zones.
-         *
-         * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
-         * @param value - the new value
-         *
-         */
-        void propagateGyr(int gyr, double value)
-        {
-            for (size_t i = 0; i < fGyr[gyr].size(); i++) {
-                fGyr[gyr][i]->update(value);
+        if (strcmp(key, "scale") == 0) {
+            if (strcmp(val, "log") == 0) {
+                fCurrentScale = kLog;
+            } else if (strcmp(val, "exp") == 0) {
+                fCurrentScale = kExp;
+            } else {
+                fCurrentScale = kLin;
             }
+        } else if (strcmp(key, "unit") == 0) {
+            fCurrentUnit = val;
+        } else if (strcmp(key, "acc") == 0) {
+            fCurrentAcc = val;
+        } else if (strcmp(key, "gyr") == 0) {
+            fCurrentGyr = val;
+        } else if (strcmp(key, "screencolor") == 0) {
+            fCurrentColor = val;  // val = "red", "green", "blue" or "white"
+        } else if (strcmp(key, "tooltip") == 0) {
+            fCurrentTooltip = val;
         }
-    
-        /**
-         * Get the number of FAUSTFLOAT* zones controlled with the accelerometer
-         *
-         * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
-         * @return the number of zones
-         *
-         */
-        int getAccCount(int acc)
-        {
-            return (acc >= 0 && acc < 3) ? int(fAcc[acc].size()) : 0;
-        }
-    
-        /**
-         * Get the number of FAUSTFLOAT* zones controlled with the gyroscope
-         *
-         * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
-         * @param the number of zones
-         *
-         */
-        int getGyrCount(int gyr)
-        {
-            return (gyr >= 0 && gyr < 3) ? int(fGyr[gyr].size()) : 0;
+    }
+
+    virtual void declare(const char* key, const char* val) {}
+
+    //-------------------------------------------------------------------------------
+    // Simple API part
+    //-------------------------------------------------------------------------------
+    int getParamsCount() { return fNumParameters; }
+    int getParamIndex(const char* path)
+    {
+        if (fPathMap.find(path) != fPathMap.end()) {
+            return fPathMap[path];
+        } else if (fLabelMap.find(path) != fLabelMap.end()) {
+            return fLabelMap[path];
+        } else {
+            return -1;
         }
-   
-        // getScreenColor() : -1 means no screen color control (no screencolor metadata found)
-        // otherwise return 0x00RRGGBB a ready to use color
-        int getScreenColor()
-        {
-            if (fHasScreenControl) {
-                int r = (fRedReader) ? fRedReader->getValue() : 0;
-                int g = (fGreenReader) ? fGreenReader->getValue() : 0;
-                int b = (fBlueReader) ? fBlueReader->getValue() : 0;
-                return (r<<16) | (g<<8) | b;
-            } else {
-                return -1;
+    }
+    const char* getParamAddress(int p) { return fPaths[p].c_str(); }
+    const char* getParamLabel(int p) { return fLabels[p].c_str(); }
+    std::map<const char*, const char*> getMetadata(int p)
+    {
+        std::map<const char*, const char*> res;
+        std::map<std::string, std::string> metadata = fMetaData[p];
+        for (auto it : metadata) { res[it.first.c_str()] = it.second.c_str(); }
+        return res;
+    }
+
+    const char* getMetadata(int p, const char* key)
+    {
+        return (fMetaData[p].find(key) != fMetaData[p].end()) ? fMetaData[p][key].c_str()
+                                                              : "";
+    }
+    FAUSTFLOAT getParamMin(int p) { return fMin[p]; }
+    FAUSTFLOAT getParamMax(int p) { return fMax[p]; }
+    FAUSTFLOAT getParamStep(int p) { return fStep[p]; }
+    FAUSTFLOAT getParamInit(int p) { return fInit[p]; }
+
+    FAUSTFLOAT* getParamZone(int p) { return fZone[p]; }
+    FAUSTFLOAT getParamValue(int p) { return *fZone[p]; }
+    void setParamValue(int p, FAUSTFLOAT v) { *fZone[p] = v; }
+
+    double getParamRatio(int p) { return fConversion[p]->faust2ui(*fZone[p]); }
+    void setParamRatio(int p, double r) { *fZone[p] = fConversion[p]->ui2faust(r); }
+
+    double value2ratio(int p, double r) { return fConversion[p]->faust2ui(r); }
+    double ratio2value(int p, double r) { return fConversion[p]->ui2faust(r); }
+
+    /**
+     * Return the control type (kAcc, kGyr, or -1) for a given parameter
+     *
+     * @param p - the UI parameter index
+     *
+     * @return the type
+     */
+    Type getParamType(int p)
+    {
+        if (p >= 0) {
+            if (getZoneIndex(fAcc, p, 0) != -1 || getZoneIndex(fAcc, p, 1) != -1
+                || getZoneIndex(fAcc, p, 2) != -1) {
+                return kAcc;
+            } else if (getZoneIndex(fGyr, p, 0) != -1 || getZoneIndex(fGyr, p, 1) != -1
+                       || getZoneIndex(fGyr, p, 2) != -1) {
+                return kGyr;
             }
         }
+        return kNoType;
+    }
+
+    /**
+     * Return the Item type (kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry,
+     * kHBargraph, kVBargraph) for a given parameter
+     *
+     * @param p - the UI parameter index
+     *
+     * @return the Item type
+     */
+    ItemType getParamItemType(int p) { return fItemType[p]; }
+
+    /**
+     * Set a new value coming from an accelerometer, propagate it to all relevant
+     * FAUSTFLOAT* zones.
+     *
+     * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+     * @param value - the new value
+     *
+     */
+    void propagateAcc(int acc, double value)
+    {
+        for (size_t i = 0; i < fAcc[acc].size(); i++) { fAcc[acc][i]->update(value); }
+    }
+
+    /**
+     * Used to edit accelerometer curves and mapping. Set curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+     * (-1 means "no mapping")
+     * @param curve - between 0 and 3
+     * @param amin - mapping 'min' point
+     * @param amid - mapping 'middle' point
+     * @param amax - mapping 'max' point
+     *
+     */
+    void setAccConverter(int p, int acc, int curve, double amin, double amid, double amax)
+    {
+        setConverter(fAcc, p, acc, curve, amin, amid, amax);
+    }
+
+    /**
+     * Used to edit gyroscope curves and mapping. Set curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param acc - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope (-1 means "no
+     * mapping")
+     * @param curve - between 0 and 3
+     * @param amin - mapping 'min' point
+     * @param amid - mapping 'middle' point
+     * @param amax - mapping 'max' point
+     *
+     */
+    void setGyrConverter(int p, int gyr, int curve, double amin, double amid, double amax)
+    {
+        setConverter(fGyr, p, gyr, curve, amin, amid, amax);
+    }
+
+    /**
+     * Used to edit accelerometer curves and mapping. Get curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param acc - the acc value to be retrieved (-1 means "no mapping")
+     * @param curve - the curve value to be retrieved
+     * @param amin - the amin value to be retrieved
+     * @param amid - the amid value to be retrieved
+     * @param amax - the amax value to be retrieved
+     *
+     */
+    void getAccConverter(int p, int& acc, int& curve, double& amin, double& amid,
+                         double& amax)
+    {
+        getConverter(fAcc, p, acc, curve, amin, amid, amax);
+    }
+
+    /**
+     * Used to edit gyroscope curves and mapping. Get curve and related mapping for a
+     * given UI parameter.
+     *
+     * @param p - the UI parameter index
+     * @param gyr - the gyr value to be retrieved (-1 means "no mapping")
+     * @param curve - the curve value to be retrieved
+     * @param amin - the amin value to be retrieved
+     * @param amid - the amid value to be retrieved
+     * @param amax - the amax value to be retrieved
+     *
+     */
+    void getGyrConverter(int p, int& gyr, int& curve, double& amin, double& amid,
+                         double& amax)
+    {
+        getConverter(fGyr, p, gyr, curve, amin, amid, amax);
+    }
+
+    /**
+     * Set a new value coming from an gyroscope, propagate it to all relevant FAUSTFLOAT*
+     * zones.
+     *
+     * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+     * @param value - the new value
+     *
+     */
+    void propagateGyr(int gyr, double value)
+    {
+        for (size_t i = 0; i < fGyr[gyr].size(); i++) { fGyr[gyr][i]->update(value); }
+    }
+
+    /**
+     * Get the number of FAUSTFLOAT* zones controlled with the accelerometer
+     *
+     * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+     * @return the number of zones
+     *
+     */
+    int getAccCount(int acc) { return (acc >= 0 && acc < 3) ? int(fAcc[acc].size()) : 0; }
+
+    /**
+     * Get the number of FAUSTFLOAT* zones controlled with the gyroscope
+     *
+     * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+     * @param the number of zones
+     *
+     */
+    int getGyrCount(int gyr) { return (gyr >= 0 && gyr < 3) ? int(fGyr[gyr].size()) : 0; }
+
+    // getScreenColor() : -1 means no screen color control (no screencolor metadata found)
+    // otherwise return 0x00RRGGBB a ready to use color
+    int getScreenColor()
+    {
+        if (fHasScreenControl) {
+            int r = (fRedReader) ? fRedReader->getValue() : 0;
+            int g = (fGreenReader) ? fGreenReader->getValue() : 0;
+            int b = (fBlueReader) ? fBlueReader->getValue() : 0;
+            return (r << 16) | (g << 8) | b;
+        } else {
+            return -1;
+        }
+    }
 };
 
 #endif
@@ -1550,808 +1583,874 @@ class APIUI : public PathBuilder, public Meta, public UI
 //  FAUST Generated Code
 //----------------------------------------------------------------------------
 
-
 #ifndef FAUSTFLOAT
 #define FAUSTFLOAT float
-#endif 
+#endif
 
 #include <algorithm>
 #include <cmath>
-#include <math.h>
 
-static float zitarevmonodsp_faustpower2_f(float value) {
-       return (value * value);
-}
+static float zitarevmonodsp_faustpower2_f(float value) { return (value * value); }
 
-#ifndef FAUSTCLASS 
+#ifndef FAUSTCLASS
 #define FAUSTCLASS zitarevmonodsp
 #endif
 
-#ifdef __APPLE__ 
+#ifdef __APPLE__
 #define exp10f __exp10f
-#define exp10 __exp10
+#define exp10  __exp10
 #endif
 
-class zitarevmonodsp : public dsp {
-       
- private:
-       
-       int IOTA;
-       float fVec0[16384];
-       FAUSTFLOAT fVslider0;
-       float fRec0[2];
-       FAUSTFLOAT fVslider1;
-       float fRec1[2];
-       int fSampleRate;
-       float fConst0;
-       float fConst1;
-       FAUSTFLOAT fVslider2;
-       FAUSTFLOAT fVslider3;
-       FAUSTFLOAT fVslider4;
-       FAUSTFLOAT fVslider5;
-       float fConst2;
-       float fConst3;
-       FAUSTFLOAT fVslider6;
-       FAUSTFLOAT fVslider7;
-       FAUSTFLOAT fVslider8;
-       float fConst4;
-       FAUSTFLOAT fVslider9;
-       float fRec15[2];
-       float fRec14[2];
-       float fVec1[32768];
-       float fConst5;
-       int iConst6;
-       float fConst7;
-       FAUSTFLOAT fVslider10;
-       float fVec2[2048];
-       int iConst8;
-       float fRec12[2];
-       float fConst9;
-       float fConst10;
-       float fRec19[2];
-       float fRec18[2];
-       float fVec3[32768];
-       float fConst11;
-       int iConst12;
-       float fVec4[4096];
-       int iConst13;
-       float fRec16[2];
-       float fConst14;
-       float fConst15;
-       float fRec23[2];
-       float fRec22[2];
-       float fVec5[16384];
-       float fConst16;
-       int iConst17;
-       float fVec6[4096];
-       int iConst18;
-       float fRec20[2];
-       float fConst19;
-       float fConst20;
-       float fRec27[2];
-       float fRec26[2];
-       float fVec7[32768];
-       float fConst21;
-       int iConst22;
-       float fVec8[4096];
-       int iConst23;
-       float fRec24[2];
-       float fConst24;
-       float fConst25;
-       float fRec31[2];
-       float fRec30[2];
-       float fVec9[16384];
-       float fConst26;
-       int iConst27;
-       float fVec10[2048];
-       int iConst28;
-       float fRec28[2];
-       float fConst29;
-       float fConst30;
-       float fRec35[2];
-       float fRec34[2];
-       float fVec11[16384];
-       float fConst31;
-       int iConst32;
-       float fVec12[4096];
-       int iConst33;
-       float fRec32[2];
-       float fConst34;
-       float fConst35;
-       float fRec39[2];
-       float fRec38[2];
-       float fVec13[16384];
-       float fConst36;
-       int iConst37;
-       float fVec14[4096];
-       int iConst38;
-       float fRec36[2];
-       float fConst39;
-       float fConst40;
-       float fRec43[2];
-       float fRec42[2];
-       float fVec15[16384];
-       float fConst41;
-       int iConst42;
-       float fVec16[2048];
-       int iConst43;
-       float fRec40[2];
-       float fRec4[3];
-       float fRec5[3];
-       float fRec6[3];
-       float fRec7[3];
-       float fRec8[3];
-       float fRec9[3];
-       float fRec10[3];
-       float fRec11[3];
-       float fRec3[3];
-       float fRec2[3];
-       float fRec45[3];
-       float fRec44[3];
-       
- public:
-       
-       void metadata(Meta* m) { 
-               m->declare("basics.lib/name", "Faust Basic Element Library");
-               m->declare("basics.lib/version", "0.1");
-               m->declare("delays.lib/name", "Faust Delay Library");
-               m->declare("delays.lib/version", "0.1");
-               m->declare("filename", "zitarevmonodsp.dsp");
-               m->declare("filters.lib/allpass_comb:author", "Julius O. Smith III");
-               m->declare("filters.lib/allpass_comb:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
-               m->declare("filters.lib/allpass_comb:license", "MIT-style STK-4.3 license");
-               m->declare("filters.lib/fir:author", "Julius O. Smith III");
-               m->declare("filters.lib/fir:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
-               m->declare("filters.lib/fir:license", "MIT-style STK-4.3 license");
-               m->declare("filters.lib/iir:author", "Julius O. Smith III");
-               m->declare("filters.lib/iir:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
-               m->declare("filters.lib/iir:license", "MIT-style STK-4.3 license");
-               m->declare("filters.lib/lowpass0_highpass1", "MIT-style STK-4.3 license");
-               m->declare("filters.lib/lowpass0_highpass1:author", "Julius O. Smith III");
-               m->declare("filters.lib/lowpass:author", "Julius O. Smith III");
-               m->declare("filters.lib/lowpass:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
-               m->declare("filters.lib/lowpass:license", "MIT-style STK-4.3 license");
-               m->declare("filters.lib/name", "Faust Filters Library");
-               m->declare("filters.lib/peak_eq_rm:author", "Julius O. Smith III");
-               m->declare("filters.lib/peak_eq_rm:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
-               m->declare("filters.lib/peak_eq_rm:license", "MIT-style STK-4.3 license");
-               m->declare("filters.lib/tf1:author", "Julius O. Smith III");
-               m->declare("filters.lib/tf1:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
-               m->declare("filters.lib/tf1:license", "MIT-style STK-4.3 license");
-               m->declare("filters.lib/tf1s:author", "Julius O. Smith III");
-               m->declare("filters.lib/tf1s:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
-               m->declare("filters.lib/tf1s:license", "MIT-style STK-4.3 license");
-               m->declare("filters.lib/tf2:author", "Julius O. Smith III");
-               m->declare("filters.lib/tf2:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
-               m->declare("filters.lib/tf2:license", "MIT-style STK-4.3 license");
-               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.3");
-               m->declare("name", "zitarevmonodsp");
-               m->declare("platform.lib/name", "Generic Platform Library");
-               m->declare("platform.lib/version", "0.1");
-               m->declare("reverbs.lib/name", "Faust Reverb Library");
-               m->declare("reverbs.lib/version", "0.0");
-               m->declare("routes.lib/name", "Faust Signal Routing Library");
-               m->declare("routes.lib/version", "0.2");
-               m->declare("signals.lib/name", "Faust Signal Routing Library");
-               m->declare("signals.lib/version", "0.0");
-       }
-
-       virtual int getNumInputs() {
-               return 1;
-       }
-       virtual int getNumOutputs() {
-               return 1;
-       }
-       virtual int getInputRate(int channel) {
-               int rate;
-               switch ((channel)) {
-                       case 0: {
-                               rate = 1;
-                               break;
-                       }
-                       default: {
-                               rate = -1;
-                               break;
-                       }
-               }
-               return rate;
-       }
-       virtual int getOutputRate(int channel) {
-               int rate;
-               switch ((channel)) {
-                       case 0: {
-                               rate = 1;
-                               break;
-                       }
-                       default: {
-                               rate = -1;
-                               break;
-                       }
-               }
-               return rate;
-       }
-       
-       static void classInit(int sample_rate) {
-       }
-       
-       virtual void instanceConstants(int sample_rate) {
-               fSampleRate = sample_rate;
-               fConst0 = std::min<float>(192000.0f, std::max<float>(1.0f, float(fSampleRate)));
-               fConst1 = (6.28318548f / fConst0);
-               fConst2 = std::floor(((0.219990999f * fConst0) + 0.5f));
-               fConst3 = ((0.0f - (6.90775537f * fConst2)) / fConst0);
-               fConst4 = (3.14159274f / fConst0);
-               fConst5 = std::floor(((0.0191229992f * fConst0) + 0.5f));
-               iConst6 = int(std::min<float>(16384.0f, std::max<float>(0.0f, (fConst2 - fConst5))));
-               fConst7 = (0.00100000005f * fConst0);
-               iConst8 = int(std::min<float>(1024.0f, std::max<float>(0.0f, (fConst5 + -1.0f))));
-               fConst9 = std::floor(((0.256891012f * fConst0) + 0.5f));
-               fConst10 = ((0.0f - (6.90775537f * fConst9)) / fConst0);
-               fConst11 = std::floor(((0.0273330007f * fConst0) + 0.5f));
-               iConst12 = int(std::min<float>(16384.0f, std::max<float>(0.0f, (fConst9 - fConst11))));
-               iConst13 = int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst11 + -1.0f))));
-               fConst14 = std::floor(((0.192303002f * fConst0) + 0.5f));
-               fConst15 = ((0.0f - (6.90775537f * fConst14)) / fConst0);
-               fConst16 = std::floor(((0.0292910002f * fConst0) + 0.5f));
-               iConst17 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst14 - fConst16))));
-               iConst18 = int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst16 + -1.0f))));
-               fConst19 = std::floor(((0.210389003f * fConst0) + 0.5f));
-               fConst20 = ((0.0f - (6.90775537f * fConst19)) / fConst0);
-               fConst21 = std::floor(((0.0244210009f * fConst0) + 0.5f));
-               iConst22 = int(std::min<float>(16384.0f, std::max<float>(0.0f, (fConst19 - fConst21))));
-               iConst23 = int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst21 + -1.0f))));
-               fConst24 = std::floor(((0.125f * fConst0) + 0.5f));
-               fConst25 = ((0.0f - (6.90775537f * fConst24)) / fConst0);
-               fConst26 = std::floor(((0.0134579996f * fConst0) + 0.5f));
-               iConst27 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst24 - fConst26))));
-               iConst28 = int(std::min<float>(1024.0f, std::max<float>(0.0f, (fConst26 + -1.0f))));
-               fConst29 = std::floor(((0.127837002f * fConst0) + 0.5f));
-               fConst30 = ((0.0f - (6.90775537f * fConst29)) / fConst0);
-               fConst31 = std::floor(((0.0316039994f * fConst0) + 0.5f));
-               iConst32 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst29 - fConst31))));
-               iConst33 = int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst31 + -1.0f))));
-               fConst34 = std::floor(((0.174713001f * fConst0) + 0.5f));
-               fConst35 = ((0.0f - (6.90775537f * fConst34)) / fConst0);
-               fConst36 = std::floor(((0.0229039993f * fConst0) + 0.5f));
-               iConst37 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst34 - fConst36))));
-               iConst38 = int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst36 + -1.0f))));
-               fConst39 = std::floor(((0.153128996f * fConst0) + 0.5f));
-               fConst40 = ((0.0f - (6.90775537f * fConst39)) / fConst0);
-               fConst41 = std::floor(((0.0203460008f * fConst0) + 0.5f));
-               iConst42 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst39 - fConst41))));
-               iConst43 = int(std::min<float>(1024.0f, std::max<float>(0.0f, (fConst41 + -1.0f))));
-       }
-       
-       virtual void instanceResetUserInterface() {
-               fVslider0 = FAUSTFLOAT(-3.0f);
-               fVslider1 = FAUSTFLOAT(0.0f);
-               fVslider2 = FAUSTFLOAT(1500.0f);
-               fVslider3 = FAUSTFLOAT(0.0f);
-               fVslider4 = FAUSTFLOAT(315.0f);
-               fVslider5 = FAUSTFLOAT(0.0f);
-               fVslider6 = FAUSTFLOAT(2.0f);
-               fVslider7 = FAUSTFLOAT(6000.0f);
-               fVslider8 = FAUSTFLOAT(3.0f);
-               fVslider9 = FAUSTFLOAT(200.0f);
-               fVslider10 = FAUSTFLOAT(60.0f);
-       }
-       
-       virtual void instanceClear() {
-               IOTA = 0;
-               for (int l0 = 0; (l0 < 16384); l0 = (l0 + 1)) {
-                       fVec0[l0] = 0.0f;
-               }
-               for (int l1 = 0; (l1 < 2); l1 = (l1 + 1)) {
-                       fRec0[l1] = 0.0f;
-               }
-               for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) {
-                       fRec1[l2] = 0.0f;
-               }
-               for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) {
-                       fRec15[l3] = 0.0f;
-               }
-               for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) {
-                       fRec14[l4] = 0.0f;
-               }
-               for (int l5 = 0; (l5 < 32768); l5 = (l5 + 1)) {
-                       fVec1[l5] = 0.0f;
-               }
-               for (int l6 = 0; (l6 < 2048); l6 = (l6 + 1)) {
-                       fVec2[l6] = 0.0f;
-               }
-               for (int l7 = 0; (l7 < 2); l7 = (l7 + 1)) {
-                       fRec12[l7] = 0.0f;
-               }
-               for (int l8 = 0; (l8 < 2); l8 = (l8 + 1)) {
-                       fRec19[l8] = 0.0f;
-               }
-               for (int l9 = 0; (l9 < 2); l9 = (l9 + 1)) {
-                       fRec18[l9] = 0.0f;
-               }
-               for (int l10 = 0; (l10 < 32768); l10 = (l10 + 1)) {
-                       fVec3[l10] = 0.0f;
-               }
-               for (int l11 = 0; (l11 < 4096); l11 = (l11 + 1)) {
-                       fVec4[l11] = 0.0f;
-               }
-               for (int l12 = 0; (l12 < 2); l12 = (l12 + 1)) {
-                       fRec16[l12] = 0.0f;
-               }
-               for (int l13 = 0; (l13 < 2); l13 = (l13 + 1)) {
-                       fRec23[l13] = 0.0f;
-               }
-               for (int l14 = 0; (l14 < 2); l14 = (l14 + 1)) {
-                       fRec22[l14] = 0.0f;
-               }
-               for (int l15 = 0; (l15 < 16384); l15 = (l15 + 1)) {
-                       fVec5[l15] = 0.0f;
-               }
-               for (int l16 = 0; (l16 < 4096); l16 = (l16 + 1)) {
-                       fVec6[l16] = 0.0f;
-               }
-               for (int l17 = 0; (l17 < 2); l17 = (l17 + 1)) {
-                       fRec20[l17] = 0.0f;
-               }
-               for (int l18 = 0; (l18 < 2); l18 = (l18 + 1)) {
-                       fRec27[l18] = 0.0f;
-               }
-               for (int l19 = 0; (l19 < 2); l19 = (l19 + 1)) {
-                       fRec26[l19] = 0.0f;
-               }
-               for (int l20 = 0; (l20 < 32768); l20 = (l20 + 1)) {
-                       fVec7[l20] = 0.0f;
-               }
-               for (int l21 = 0; (l21 < 4096); l21 = (l21 + 1)) {
-                       fVec8[l21] = 0.0f;
-               }
-               for (int l22 = 0; (l22 < 2); l22 = (l22 + 1)) {
-                       fRec24[l22] = 0.0f;
-               }
-               for (int l23 = 0; (l23 < 2); l23 = (l23 + 1)) {
-                       fRec31[l23] = 0.0f;
-               }
-               for (int l24 = 0; (l24 < 2); l24 = (l24 + 1)) {
-                       fRec30[l24] = 0.0f;
-               }
-               for (int l25 = 0; (l25 < 16384); l25 = (l25 + 1)) {
-                       fVec9[l25] = 0.0f;
-               }
-               for (int l26 = 0; (l26 < 2048); l26 = (l26 + 1)) {
-                       fVec10[l26] = 0.0f;
-               }
-               for (int l27 = 0; (l27 < 2); l27 = (l27 + 1)) {
-                       fRec28[l27] = 0.0f;
-               }
-               for (int l28 = 0; (l28 < 2); l28 = (l28 + 1)) {
-                       fRec35[l28] = 0.0f;
-               }
-               for (int l29 = 0; (l29 < 2); l29 = (l29 + 1)) {
-                       fRec34[l29] = 0.0f;
-               }
-               for (int l30 = 0; (l30 < 16384); l30 = (l30 + 1)) {
-                       fVec11[l30] = 0.0f;
-               }
-               for (int l31 = 0; (l31 < 4096); l31 = (l31 + 1)) {
-                       fVec12[l31] = 0.0f;
-               }
-               for (int l32 = 0; (l32 < 2); l32 = (l32 + 1)) {
-                       fRec32[l32] = 0.0f;
-               }
-               for (int l33 = 0; (l33 < 2); l33 = (l33 + 1)) {
-                       fRec39[l33] = 0.0f;
-               }
-               for (int l34 = 0; (l34 < 2); l34 = (l34 + 1)) {
-                       fRec38[l34] = 0.0f;
-               }
-               for (int l35 = 0; (l35 < 16384); l35 = (l35 + 1)) {
-                       fVec13[l35] = 0.0f;
-               }
-               for (int l36 = 0; (l36 < 4096); l36 = (l36 + 1)) {
-                       fVec14[l36] = 0.0f;
-               }
-               for (int l37 = 0; (l37 < 2); l37 = (l37 + 1)) {
-                       fRec36[l37] = 0.0f;
-               }
-               for (int l38 = 0; (l38 < 2); l38 = (l38 + 1)) {
-                       fRec43[l38] = 0.0f;
-               }
-               for (int l39 = 0; (l39 < 2); l39 = (l39 + 1)) {
-                       fRec42[l39] = 0.0f;
-               }
-               for (int l40 = 0; (l40 < 16384); l40 = (l40 + 1)) {
-                       fVec15[l40] = 0.0f;
-               }
-               for (int l41 = 0; (l41 < 2048); l41 = (l41 + 1)) {
-                       fVec16[l41] = 0.0f;
-               }
-               for (int l42 = 0; (l42 < 2); l42 = (l42 + 1)) {
-                       fRec40[l42] = 0.0f;
-               }
-               for (int l43 = 0; (l43 < 3); l43 = (l43 + 1)) {
-                       fRec4[l43] = 0.0f;
-               }
-               for (int l44 = 0; (l44 < 3); l44 = (l44 + 1)) {
-                       fRec5[l44] = 0.0f;
-               }
-               for (int l45 = 0; (l45 < 3); l45 = (l45 + 1)) {
-                       fRec6[l45] = 0.0f;
-               }
-               for (int l46 = 0; (l46 < 3); l46 = (l46 + 1)) {
-                       fRec7[l46] = 0.0f;
-               }
-               for (int l47 = 0; (l47 < 3); l47 = (l47 + 1)) {
-                       fRec8[l47] = 0.0f;
-               }
-               for (int l48 = 0; (l48 < 3); l48 = (l48 + 1)) {
-                       fRec9[l48] = 0.0f;
-               }
-               for (int l49 = 0; (l49 < 3); l49 = (l49 + 1)) {
-                       fRec10[l49] = 0.0f;
-               }
-               for (int l50 = 0; (l50 < 3); l50 = (l50 + 1)) {
-                       fRec11[l50] = 0.0f;
-               }
-               for (int l51 = 0; (l51 < 3); l51 = (l51 + 1)) {
-                       fRec3[l51] = 0.0f;
-               }
-               for (int l52 = 0; (l52 < 3); l52 = (l52 + 1)) {
-                       fRec2[l52] = 0.0f;
-               }
-               for (int l53 = 0; (l53 < 3); l53 = (l53 + 1)) {
-                       fRec45[l53] = 0.0f;
-               }
-               for (int l54 = 0; (l54 < 3); l54 = (l54 + 1)) {
-                       fRec44[l54] = 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 zitarevmonodsp* clone() {
-               return new zitarevmonodsp();
-       }
-       
-       virtual int getSampleRate() {
-               return fSampleRate;
-       }
-       
-       virtual void buildUserInterface(UI* ui_interface) {
-               ui_interface->declare(0, "0", "");
-               ui_interface->declare(0, "tooltip", "~ ZITA REV1 FEEDBACK DELAY NETWORK (FDN) & SCHROEDER  ALLPASS-COMB REVERBERATOR (8x8). See Faust's reverbs.lib for documentation and  references");
-               ui_interface->openHorizontalBox("Zita_Rev1");
-               ui_interface->declare(0, "1", "");
-               ui_interface->openHorizontalBox("Input");
-               ui_interface->declare(&fVslider10, "1", "");
-               ui_interface->declare(&fVslider10, "style", "knob");
-               ui_interface->declare(&fVslider10, "tooltip", "Delay in ms   before reverberation begins");
-               ui_interface->declare(&fVslider10, "unit", "ms");
-               ui_interface->addVerticalSlider("In Delay", &fVslider10, 60.0f, 20.0f, 100.0f, 1.0f);
-               ui_interface->closeBox();
-               ui_interface->declare(0, "2", "");
-               ui_interface->openHorizontalBox("Decay Times in Bands (see tooltips)");
-               ui_interface->declare(&fVslider9, "1", "");
-               ui_interface->declare(&fVslider9, "scale", "log");
-               ui_interface->declare(&fVslider9, "style", "knob");
-               ui_interface->declare(&fVslider9, "tooltip", "Crossover frequency (Hz) separating low and middle frequencies");
-               ui_interface->declare(&fVslider9, "unit", "Hz");
-               ui_interface->addVerticalSlider("LF X", &fVslider9, 200.0f, 50.0f, 1000.0f, 1.0f);
-               ui_interface->declare(&fVslider8, "2", "");
-               ui_interface->declare(&fVslider8, "scale", "log");
-               ui_interface->declare(&fVslider8, "style", "knob");
-               ui_interface->declare(&fVslider8, "tooltip", "T60 = time (in seconds) to decay 60dB in low-frequency band");
-               ui_interface->declare(&fVslider8, "unit", "s");
-               ui_interface->addVerticalSlider("Low RT60", &fVslider8, 3.0f, 1.0f, 8.0f, 0.100000001f);
-               ui_interface->declare(&fVslider6, "3", "");
-               ui_interface->declare(&fVslider6, "scale", "log");
-               ui_interface->declare(&fVslider6, "style", "knob");
-               ui_interface->declare(&fVslider6, "tooltip", "T60 = time (in seconds) to decay 60dB in middle band");
-               ui_interface->declare(&fVslider6, "unit", "s");
-               ui_interface->addVerticalSlider("Mid RT60", &fVslider6, 2.0f, 1.0f, 8.0f, 0.100000001f);
-               ui_interface->declare(&fVslider7, "4", "");
-               ui_interface->declare(&fVslider7, "scale", "log");
-               ui_interface->declare(&fVslider7, "style", "knob");
-               ui_interface->declare(&fVslider7, "tooltip", "Frequency (Hz) at which the high-frequency T60 is half the middle-band's T60");
-               ui_interface->declare(&fVslider7, "unit", "Hz");
-               ui_interface->addVerticalSlider("HF Damping", &fVslider7, 6000.0f, 1500.0f, 23520.0f, 1.0f);
-               ui_interface->closeBox();
-               ui_interface->declare(0, "3", "");
-               ui_interface->openHorizontalBox("RM Peaking Equalizer 1");
-               ui_interface->declare(&fVslider4, "1", "");
-               ui_interface->declare(&fVslider4, "scale", "log");
-               ui_interface->declare(&fVslider4, "style", "knob");
-               ui_interface->declare(&fVslider4, "tooltip", "Center-frequency of second-order Regalia-Mitra peaking equalizer section 1");
-               ui_interface->declare(&fVslider4, "unit", "Hz");
-               ui_interface->addVerticalSlider("Eq1 Freq", &fVslider4, 315.0f, 40.0f, 2500.0f, 1.0f);
-               ui_interface->declare(&fVslider5, "2", "");
-               ui_interface->declare(&fVslider5, "style", "knob");
-               ui_interface->declare(&fVslider5, "tooltip", "Peak level   in dB of second-order Regalia-Mitra peaking equalizer section 1");
-               ui_interface->declare(&fVslider5, "unit", "dB");
-               ui_interface->addVerticalSlider("Eq1 Level", &fVslider5, 0.0f, -15.0f, 15.0f, 0.100000001f);
-               ui_interface->closeBox();
-               ui_interface->declare(0, "4", "");
-               ui_interface->openHorizontalBox("RM Peaking Equalizer 2");
-               ui_interface->declare(&fVslider2, "1", "");
-               ui_interface->declare(&fVslider2, "scale", "log");
-               ui_interface->declare(&fVslider2, "style", "knob");
-               ui_interface->declare(&fVslider2, "tooltip", "Center-frequency of second-order Regalia-Mitra peaking equalizer section 2");
-               ui_interface->declare(&fVslider2, "unit", "Hz");
-               ui_interface->addVerticalSlider("Eq2 Freq", &fVslider2, 1500.0f, 160.0f, 10000.0f, 1.0f);
-               ui_interface->declare(&fVslider3, "2", "");
-               ui_interface->declare(&fVslider3, "style", "knob");
-               ui_interface->declare(&fVslider3, "tooltip", "Peak level   in dB of second-order Regalia-Mitra peaking equalizer section 2");
-               ui_interface->declare(&fVslider3, "unit", "dB");
-               ui_interface->addVerticalSlider("Eq2 Level", &fVslider3, 0.0f, -15.0f, 15.0f, 0.100000001f);
-               ui_interface->closeBox();
-               ui_interface->declare(0, "5", "");
-               ui_interface->openHorizontalBox("Output");
-               ui_interface->declare(&fVslider1, "1", "");
-               ui_interface->declare(&fVslider1, "style", "knob");
-               ui_interface->declare(&fVslider1, "tooltip", "Dry/Wet Mix: 0 = dry, 1 = wet");
-               ui_interface->addVerticalSlider("Wet", &fVslider1, 0.0f, 0.0f, 1.0f, 0.00999999978f);
-               ui_interface->declare(&fVslider0, "2", "");
-               ui_interface->declare(&fVslider0, "style", "knob");
-               ui_interface->declare(&fVslider0, "tooltip", "Output scale   factor");
-               ui_interface->declare(&fVslider0, "unit", "dB");
-               ui_interface->addVerticalSlider("Level", &fVslider0, -3.0f, -70.0f, 20.0f, 0.100000001f);
-               ui_interface->closeBox();
-               ui_interface->closeBox();
-       }
-       
-       virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
-               FAUSTFLOAT* input0 = inputs[0];
-               FAUSTFLOAT* output0 = outputs[0];
-               float fSlow0 = (0.00100000005f * std::pow(10.0f, (0.0500000007f * float(fVslider0))));
-               float fSlow1 = (0.00100000005f * float(fVslider1));
-               float fSlow2 = float(fVslider2);
-               float fSlow3 = std::pow(10.0f, (0.0500000007f * float(fVslider3)));
-               float fSlow4 = (fConst1 * (fSlow2 / std::sqrt(std::max<float>(0.0f, fSlow3))));
-               float fSlow5 = ((1.0f - fSlow4) / (fSlow4 + 1.0f));
-               float fSlow6 = float(fVslider4);
-               float fSlow7 = std::pow(10.0f, (0.0500000007f * float(fVslider5)));
-               float fSlow8 = (fConst1 * (fSlow6 / std::sqrt(std::max<float>(0.0f, fSlow7))));
-               float fSlow9 = ((1.0f - fSlow8) / (fSlow8 + 1.0f));
-               float fSlow10 = float(fVslider6);
-               float fSlow11 = std::exp((fConst3 / fSlow10));
-               float fSlow12 = zitarevmonodsp_faustpower2_f(fSlow11);
-               float fSlow13 = std::cos((fConst1 * float(fVslider7)));
-               float fSlow14 = (1.0f - (fSlow12 * fSlow13));
-               float fSlow15 = (1.0f - fSlow12);
-               float fSlow16 = (fSlow14 / fSlow15);
-               float fSlow17 = std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow14) / zitarevmonodsp_faustpower2_f(fSlow15)) + -1.0f)));
-               float fSlow18 = (fSlow16 - fSlow17);
-               float fSlow19 = (fSlow11 * (fSlow17 + (1.0f - fSlow16)));
-               float fSlow20 = float(fVslider8);
-               float fSlow21 = ((std::exp((fConst3 / fSlow20)) / fSlow11) + -1.0f);
-               float fSlow22 = (1.0f / std::tan((fConst4 * float(fVslider9))));
-               float fSlow23 = (1.0f / (fSlow22 + 1.0f));
-               float fSlow24 = (1.0f - fSlow22);
-               int iSlow25 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst7 * float(fVslider10)))));
-               float fSlow26 = std::exp((fConst10 / fSlow10));
-               float fSlow27 = zitarevmonodsp_faustpower2_f(fSlow26);
-               float fSlow28 = (1.0f - (fSlow27 * fSlow13));
-               float fSlow29 = (1.0f - fSlow27);
-               float fSlow30 = (fSlow28 / fSlow29);
-               float fSlow31 = std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow28) / zitarevmonodsp_faustpower2_f(fSlow29)) + -1.0f)));
-               float fSlow32 = (fSlow30 - fSlow31);
-               float fSlow33 = (fSlow26 * (fSlow31 + (1.0f - fSlow30)));
-               float fSlow34 = ((std::exp((fConst10 / fSlow20)) / fSlow26) + -1.0f);
-               float fSlow35 = std::exp((fConst15 / fSlow10));
-               float fSlow36 = zitarevmonodsp_faustpower2_f(fSlow35);
-               float fSlow37 = (1.0f - (fSlow36 * fSlow13));
-               float fSlow38 = (1.0f - fSlow36);
-               float fSlow39 = (fSlow37 / fSlow38);
-               float fSlow40 = std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow37) / zitarevmonodsp_faustpower2_f(fSlow38)) + -1.0f)));
-               float fSlow41 = (fSlow39 - fSlow40);
-               float fSlow42 = (fSlow35 * (fSlow40 + (1.0f - fSlow39)));
-               float fSlow43 = ((std::exp((fConst15 / fSlow20)) / fSlow35) + -1.0f);
-               float fSlow44 = std::exp((fConst20 / fSlow10));
-               float fSlow45 = zitarevmonodsp_faustpower2_f(fSlow44);
-               float fSlow46 = (1.0f - (fSlow45 * fSlow13));
-               float fSlow47 = (1.0f - fSlow45);
-               float fSlow48 = (fSlow46 / fSlow47);
-               float fSlow49 = std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow46) / zitarevmonodsp_faustpower2_f(fSlow47)) + -1.0f)));
-               float fSlow50 = (fSlow48 - fSlow49);
-               float fSlow51 = (fSlow44 * (fSlow49 + (1.0f - fSlow48)));
-               float fSlow52 = ((std::exp((fConst20 / fSlow20)) / fSlow44) + -1.0f);
-               float fSlow53 = std::exp((fConst25 / fSlow10));
-               float fSlow54 = zitarevmonodsp_faustpower2_f(fSlow53);
-               float fSlow55 = (1.0f - (fSlow54 * fSlow13));
-               float fSlow56 = (1.0f - fSlow54);
-               float fSlow57 = (fSlow55 / fSlow56);
-               float fSlow58 = std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow55) / zitarevmonodsp_faustpower2_f(fSlow56)) + -1.0f)));
-               float fSlow59 = (fSlow57 - fSlow58);
-               float fSlow60 = (fSlow53 * (fSlow58 + (1.0f - fSlow57)));
-               float fSlow61 = ((std::exp((fConst25 / fSlow20)) / fSlow53) + -1.0f);
-               float fSlow62 = std::exp((fConst30 / fSlow10));
-               float fSlow63 = zitarevmonodsp_faustpower2_f(fSlow62);
-               float fSlow64 = (1.0f - (fSlow63 * fSlow13));
-               float fSlow65 = (1.0f - fSlow63);
-               float fSlow66 = (fSlow64 / fSlow65);
-               float fSlow67 = std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow64) / zitarevmonodsp_faustpower2_f(fSlow65)) + -1.0f)));
-               float fSlow68 = (fSlow66 - fSlow67);
-               float fSlow69 = (fSlow62 * (fSlow67 + (1.0f - fSlow66)));
-               float fSlow70 = ((std::exp((fConst30 / fSlow20)) / fSlow62) + -1.0f);
-               float fSlow71 = std::exp((fConst35 / fSlow10));
-               float fSlow72 = zitarevmonodsp_faustpower2_f(fSlow71);
-               float fSlow73 = (1.0f - (fSlow72 * fSlow13));
-               float fSlow74 = (1.0f - fSlow72);
-               float fSlow75 = (fSlow73 / fSlow74);
-               float fSlow76 = std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow73) / zitarevmonodsp_faustpower2_f(fSlow74)) + -1.0f)));
-               float fSlow77 = (fSlow75 - fSlow76);
-               float fSlow78 = (fSlow71 * (fSlow76 + (1.0f - fSlow75)));
-               float fSlow79 = ((std::exp((fConst35 / fSlow20)) / fSlow71) + -1.0f);
-               float fSlow80 = std::exp((fConst40 / fSlow10));
-               float fSlow81 = zitarevmonodsp_faustpower2_f(fSlow80);
-               float fSlow82 = (1.0f - (fSlow81 * fSlow13));
-               float fSlow83 = (1.0f - fSlow81);
-               float fSlow84 = (fSlow82 / fSlow83);
-               float fSlow85 = std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow82) / zitarevmonodsp_faustpower2_f(fSlow83)) + -1.0f)));
-               float fSlow86 = (fSlow84 - fSlow85);
-               float fSlow87 = (fSlow80 * (fSlow85 + (1.0f - fSlow84)));
-               float fSlow88 = ((std::exp((fConst40 / fSlow20)) / fSlow80) + -1.0f);
-               float fSlow89 = (0.0f - (std::cos((fConst1 * fSlow6)) * (fSlow9 + 1.0f)));
-               float fSlow90 = (0.0f - (std::cos((fConst1 * fSlow2)) * (fSlow5 + 1.0f)));
-               for (int i = 0; (i < count); i = (i + 1)) {
-                       float fTemp0 = float(input0[i]);
-                       fVec0[(IOTA & 16383)] = fTemp0;
-                       fRec0[0] = (fSlow0 + (0.999000013f * fRec0[1]));
-                       fRec1[0] = (fSlow1 + (0.999000013f * fRec1[1]));
-                       fRec15[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec15[1]) - (fRec11[1] + fRec11[2]))));
-                       fRec14[0] = ((fSlow18 * fRec14[1]) + (fSlow19 * (fRec11[1] + (fSlow21 * fRec15[0]))));
-                       fVec1[(IOTA & 32767)] = ((0.353553385f * fRec14[0]) + 9.99999968e-21f);
-                       float fTemp1 = (0.300000012f * fVec0[((IOTA - iSlow25) & 16383)]);
-                       float fTemp2 = (((0.600000024f * fRec12[1]) + fVec1[((IOTA - iConst6) & 32767)]) - fTemp1);
-                       fVec2[(IOTA & 2047)] = fTemp2;
-                       fRec12[0] = fVec2[((IOTA - iConst8) & 2047)];
-                       float fRec13 = (0.0f - (0.600000024f * fTemp2));
-                       fRec19[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec19[1]) - (fRec7[1] + fRec7[2]))));
-                       fRec18[0] = ((fSlow32 * fRec18[1]) + (fSlow33 * (fRec7[1] + (fSlow34 * fRec19[0]))));
-                       fVec3[(IOTA & 32767)] = ((0.353553385f * fRec18[0]) + 9.99999968e-21f);
-                       float fTemp3 = (((0.600000024f * fRec16[1]) + fVec3[((IOTA - iConst12) & 32767)]) - fTemp1);
-                       fVec4[(IOTA & 4095)] = fTemp3;
-                       fRec16[0] = fVec4[((IOTA - iConst13) & 4095)];
-                       float fRec17 = (0.0f - (0.600000024f * fTemp3));
-                       fRec23[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec23[1]) - (fRec9[1] + fRec9[2]))));
-                       fRec22[0] = ((fSlow41 * fRec22[1]) + (fSlow42 * (fRec9[1] + (fSlow43 * fRec23[0]))));
-                       fVec5[(IOTA & 16383)] = ((0.353553385f * fRec22[0]) + 9.99999968e-21f);
-                       float fTemp4 = (fVec5[((IOTA - iConst17) & 16383)] + (fTemp1 + (0.600000024f * fRec20[1])));
-                       fVec6[(IOTA & 4095)] = fTemp4;
-                       fRec20[0] = fVec6[((IOTA - iConst18) & 4095)];
-                       float fRec21 = (0.0f - (0.600000024f * fTemp4));
-                       fRec27[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec27[1]) - (fRec5[1] + fRec5[2]))));
-                       fRec26[0] = ((fSlow50 * fRec26[1]) + (fSlow51 * (fRec5[1] + (fSlow52 * fRec27[0]))));
-                       fVec7[(IOTA & 32767)] = ((0.353553385f * fRec26[0]) + 9.99999968e-21f);
-                       float fTemp5 = (fVec7[((IOTA - iConst22) & 32767)] + (fTemp1 + (0.600000024f * fRec24[1])));
-                       fVec8[(IOTA & 4095)] = fTemp5;
-                       fRec24[0] = fVec8[((IOTA - iConst23) & 4095)];
-                       float fRec25 = (0.0f - (0.600000024f * fTemp5));
-                       fRec31[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec31[1]) - (fRec10[1] + fRec10[2]))));
-                       fRec30[0] = ((fSlow59 * fRec30[1]) + (fSlow60 * (fRec10[1] + (fSlow61 * fRec31[0]))));
-                       fVec9[(IOTA & 16383)] = ((0.353553385f * fRec30[0]) + 9.99999968e-21f);
-                       float fTemp6 = (fVec9[((IOTA - iConst27) & 16383)] - (fTemp1 + (0.600000024f * fRec28[1])));
-                       fVec10[(IOTA & 2047)] = fTemp6;
-                       fRec28[0] = fVec10[((IOTA - iConst28) & 2047)];
-                       float fRec29 = (0.600000024f * fTemp6);
-                       fRec35[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec35[1]) - (fRec6[1] + fRec6[2]))));
-                       fRec34[0] = ((fSlow68 * fRec34[1]) + (fSlow69 * (fRec6[1] + (fSlow70 * fRec35[0]))));
-                       fVec11[(IOTA & 16383)] = ((0.353553385f * fRec34[0]) + 9.99999968e-21f);
-                       float fTemp7 = (fVec11[((IOTA - iConst32) & 16383)] - (fTemp1 + (0.600000024f * fRec32[1])));
-                       fVec12[(IOTA & 4095)] = fTemp7;
-                       fRec32[0] = fVec12[((IOTA - iConst33) & 4095)];
-                       float fRec33 = (0.600000024f * fTemp7);
-                       fRec39[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec39[1]) - (fRec8[1] + fRec8[2]))));
-                       fRec38[0] = ((fSlow77 * fRec38[1]) + (fSlow78 * (fRec8[1] + (fSlow79 * fRec39[0]))));
-                       fVec13[(IOTA & 16383)] = ((0.353553385f * fRec38[0]) + 9.99999968e-21f);
-                       float fTemp8 = ((fTemp1 + fVec13[((IOTA - iConst37) & 16383)]) - (0.600000024f * fRec36[1]));
-                       fVec14[(IOTA & 4095)] = fTemp8;
-                       fRec36[0] = fVec14[((IOTA - iConst38) & 4095)];
-                       float fRec37 = (0.600000024f * fTemp8);
-                       fRec43[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec43[1]) - (fRec4[1] + fRec4[2]))));
-                       fRec42[0] = ((fSlow86 * fRec42[1]) + (fSlow87 * (fRec4[1] + (fSlow88 * fRec43[0]))));
-                       fVec15[(IOTA & 16383)] = ((0.353553385f * fRec42[0]) + 9.99999968e-21f);
-                       float fTemp9 = ((fVec15[((IOTA - iConst42) & 16383)] + fTemp1) - (0.600000024f * fRec40[1]));
-                       fVec16[(IOTA & 2047)] = fTemp9;
-                       fRec40[0] = fVec16[((IOTA - iConst43) & 2047)];
-                       float fRec41 = (0.600000024f * fTemp9);
-                       float fTemp10 = (fRec41 + fRec37);
-                       float fTemp11 = (fRec29 + (fRec33 + fTemp10));
-                       fRec4[0] = (fRec12[1] + (fRec16[1] + (fRec20[1] + (fRec24[1] + (fRec28[1] + (fRec32[1] + (fRec36[1] + (fRec40[1] + (fRec13 + (fRec17 + (fRec21 + (fRec25 + fTemp11))))))))))));
-                       fRec5[0] = ((fRec28[1] + (fRec32[1] + (fRec36[1] + (fRec40[1] + fTemp11)))) - (fRec12[1] + (fRec16[1] + (fRec20[1] + (fRec24[1] + (fRec13 + (fRec17 + (fRec25 + fRec21))))))));
-                       float fTemp12 = (fRec33 + fRec29);
-                       fRec6[0] = ((fRec20[1] + (fRec24[1] + (fRec36[1] + (fRec40[1] + (fRec21 + (fRec25 + fTemp10)))))) - (fRec12[1] + (fRec16[1] + (fRec28[1] + (fRec32[1] + (fRec13 + (fRec17 + fTemp12)))))));
-                       fRec7[0] = ((fRec12[1] + (fRec16[1] + (fRec36[1] + (fRec40[1] + (fRec13 + (fRec17 + fTemp10)))))) - (fRec20[1] + (fRec24[1] + (fRec28[1] + (fRec32[1] + (fRec21 + (fRec25 + fTemp12)))))));
-                       float fTemp13 = (fRec41 + fRec33);
-                       float fTemp14 = (fRec37 + fRec29);
-                       fRec8[0] = ((fRec16[1] + (fRec24[1] + (fRec32[1] + (fRec40[1] + (fRec17 + (fRec25 + fTemp13)))))) - (fRec12[1] + (fRec20[1] + (fRec28[1] + (fRec36[1] + (fRec13 + (fRec21 + fTemp14)))))));
-                       fRec9[0] = ((fRec12[1] + (fRec20[1] + (fRec32[1] + (fRec40[1] + (fRec13 + (fRec21 + fTemp13)))))) - (fRec16[1] + (fRec24[1] + (fRec28[1] + (fRec36[1] + (fRec17 + (fRec25 + fTemp14)))))));
-                       float fTemp15 = (fRec41 + fRec29);
-                       float fTemp16 = (fRec37 + fRec33);
-                       fRec10[0] = ((fRec12[1] + (fRec24[1] + (fRec28[1] + (fRec40[1] + (fRec13 + (fRec25 + fTemp15)))))) - (fRec16[1] + (fRec20[1] + (fRec32[1] + (fRec36[1] + (fRec17 + (fRec21 + fTemp16)))))));
-                       fRec11[0] = ((fRec16[1] + (fRec20[1] + (fRec28[1] + (fRec40[1] + (fRec17 + (fRec21 + fTemp15)))))) - (fRec12[1] + (fRec24[1] + (fRec32[1] + (fRec36[1] + (fRec13 + (fRec25 + fTemp16)))))));
-                       float fTemp17 = (0.370000005f * (fRec5[0] + fRec6[0]));
-                       float fTemp18 = (fSlow89 * fRec3[1]);
-                       fRec3[0] = (fTemp17 - (fTemp18 + (fSlow9 * fRec3[2])));
-                       float fTemp19 = (fSlow9 * fRec3[0]);
-                       float fTemp20 = (0.5f * ((fTemp19 + (fRec3[2] + (fTemp17 + fTemp18))) + (fSlow7 * ((fTemp19 + (fTemp18 + fRec3[2])) - fTemp17))));
-                       float fTemp21 = (fSlow90 * fRec2[1]);
-                       fRec2[0] = (fTemp20 - (fTemp21 + (fSlow5 * fRec2[2])));
-                       float fTemp22 = (fSlow5 * fRec2[0]);
-                       float fTemp23 = (fTemp0 * (1.0f - fRec1[0]));
-                       float fTemp24 = (0.370000005f * (fRec5[0] - fRec6[0]));
-                       float fTemp25 = (fSlow89 * fRec45[1]);
-                       fRec45[0] = (fTemp24 - (fTemp25 + (fSlow9 * fRec45[2])));
-                       float fTemp26 = (fSlow9 * fRec45[0]);
-                       float fTemp27 = (0.5f * ((fTemp26 + (fRec45[2] + (fTemp24 + fTemp25))) + (fSlow7 * ((fTemp26 + (fTemp25 + fRec45[2])) - fTemp24))));
-                       float fTemp28 = (fSlow90 * fRec44[1]);
-                       fRec44[0] = (fTemp27 - (fTemp28 + (fSlow5 * fRec44[2])));
-                       float fTemp29 = (fSlow5 * fRec44[0]);
-                       output0[i] = FAUSTFLOAT((fRec0[0] * (((0.5f * (fRec1[0] * ((fTemp22 + (fRec2[2] + (fTemp20 + fTemp21))) + (fSlow3 * ((fTemp22 + (fTemp21 + fRec2[2])) - fTemp20))))) + fTemp23) + (fTemp23 + (0.5f * (fRec1[0] * ((fTemp29 + (fRec44[2] + (fTemp27 + fTemp28))) + (fSlow3 * ((fTemp29 + (fTemp28 + fRec44[2])) - fTemp27)))))))));
-                       IOTA = (IOTA + 1);
-                       fRec0[1] = fRec0[0];
-                       fRec1[1] = fRec1[0];
-                       fRec15[1] = fRec15[0];
-                       fRec14[1] = fRec14[0];
-                       fRec12[1] = fRec12[0];
-                       fRec19[1] = fRec19[0];
-                       fRec18[1] = fRec18[0];
-                       fRec16[1] = fRec16[0];
-                       fRec23[1] = fRec23[0];
-                       fRec22[1] = fRec22[0];
-                       fRec20[1] = fRec20[0];
-                       fRec27[1] = fRec27[0];
-                       fRec26[1] = fRec26[0];
-                       fRec24[1] = fRec24[0];
-                       fRec31[1] = fRec31[0];
-                       fRec30[1] = fRec30[0];
-                       fRec28[1] = fRec28[0];
-                       fRec35[1] = fRec35[0];
-                       fRec34[1] = fRec34[0];
-                       fRec32[1] = fRec32[0];
-                       fRec39[1] = fRec39[0];
-                       fRec38[1] = fRec38[0];
-                       fRec36[1] = fRec36[0];
-                       fRec43[1] = fRec43[0];
-                       fRec42[1] = fRec42[0];
-                       fRec40[1] = fRec40[0];
-                       fRec4[2] = fRec4[1];
-                       fRec4[1] = fRec4[0];
-                       fRec5[2] = fRec5[1];
-                       fRec5[1] = fRec5[0];
-                       fRec6[2] = fRec6[1];
-                       fRec6[1] = fRec6[0];
-                       fRec7[2] = fRec7[1];
-                       fRec7[1] = fRec7[0];
-                       fRec8[2] = fRec8[1];
-                       fRec8[1] = fRec8[0];
-                       fRec9[2] = fRec9[1];
-                       fRec9[1] = fRec9[0];
-                       fRec10[2] = fRec10[1];
-                       fRec10[1] = fRec10[0];
-                       fRec11[2] = fRec11[1];
-                       fRec11[1] = fRec11[0];
-                       fRec3[2] = fRec3[1];
-                       fRec3[1] = fRec3[0];
-                       fRec2[2] = fRec2[1];
-                       fRec2[1] = fRec2[0];
-                       fRec45[2] = fRec45[1];
-                       fRec45[1] = fRec45[0];
-                       fRec44[2] = fRec44[1];
-                       fRec44[1] = fRec44[0];
-               }
-       }
-
+class zitarevmonodsp : public dsp
+{
+   private:
+    int IOTA;
+    float fVec0[16384];
+    FAUSTFLOAT fVslider0;
+    float fRec0[2];
+    FAUSTFLOAT fVslider1;
+    float fRec1[2];
+    int fSampleRate;
+    float fConst0;
+    float fConst1;
+    FAUSTFLOAT fVslider2;
+    FAUSTFLOAT fVslider3;
+    FAUSTFLOAT fVslider4;
+    FAUSTFLOAT fVslider5;
+    float fConst2;
+    float fConst3;
+    FAUSTFLOAT fVslider6;
+    FAUSTFLOAT fVslider7;
+    FAUSTFLOAT fVslider8;
+    float fConst4;
+    FAUSTFLOAT fVslider9;
+    float fRec15[2];
+    float fRec14[2];
+    float fVec1[32768];
+    float fConst5;
+    int iConst6;
+    float fConst7;
+    FAUSTFLOAT fVslider10;
+    float fVec2[2048];
+    int iConst8;
+    float fRec12[2];
+    float fConst9;
+    float fConst10;
+    float fRec19[2];
+    float fRec18[2];
+    float fVec3[32768];
+    float fConst11;
+    int iConst12;
+    float fVec4[4096];
+    int iConst13;
+    float fRec16[2];
+    float fConst14;
+    float fConst15;
+    float fRec23[2];
+    float fRec22[2];
+    float fVec5[16384];
+    float fConst16;
+    int iConst17;
+    float fVec6[4096];
+    int iConst18;
+    float fRec20[2];
+    float fConst19;
+    float fConst20;
+    float fRec27[2];
+    float fRec26[2];
+    float fVec7[32768];
+    float fConst21;
+    int iConst22;
+    float fVec8[4096];
+    int iConst23;
+    float fRec24[2];
+    float fConst24;
+    float fConst25;
+    float fRec31[2];
+    float fRec30[2];
+    float fVec9[16384];
+    float fConst26;
+    int iConst27;
+    float fVec10[2048];
+    int iConst28;
+    float fRec28[2];
+    float fConst29;
+    float fConst30;
+    float fRec35[2];
+    float fRec34[2];
+    float fVec11[16384];
+    float fConst31;
+    int iConst32;
+    float fVec12[4096];
+    int iConst33;
+    float fRec32[2];
+    float fConst34;
+    float fConst35;
+    float fRec39[2];
+    float fRec38[2];
+    float fVec13[16384];
+    float fConst36;
+    int iConst37;
+    float fVec14[4096];
+    int iConst38;
+    float fRec36[2];
+    float fConst39;
+    float fConst40;
+    float fRec43[2];
+    float fRec42[2];
+    float fVec15[16384];
+    float fConst41;
+    int iConst42;
+    float fVec16[2048];
+    int iConst43;
+    float fRec40[2];
+    float fRec4[3];
+    float fRec5[3];
+    float fRec6[3];
+    float fRec7[3];
+    float fRec8[3];
+    float fRec9[3];
+    float fRec10[3];
+    float fRec11[3];
+    float fRec3[3];
+    float fRec2[3];
+    float fRec45[3];
+    float fRec44[3];
+
+   public:
+    void metadata(Meta* m)
+    {
+        m->declare("basics.lib/name", "Faust Basic Element Library");
+        m->declare("basics.lib/version", "0.1");
+        m->declare("delays.lib/name", "Faust Delay Library");
+        m->declare("delays.lib/version", "0.1");
+        m->declare("filename", "zitarevmonodsp.dsp");
+        m->declare("filters.lib/allpass_comb:author", "Julius O. Smith III");
+        m->declare(
+            "filters.lib/allpass_comb:copyright",
+            "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+        m->declare("filters.lib/allpass_comb:license", "MIT-style STK-4.3 license");
+        m->declare("filters.lib/fir:author", "Julius O. Smith III");
+        m->declare(
+            "filters.lib/fir:copyright",
+            "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+        m->declare("filters.lib/fir:license", "MIT-style STK-4.3 license");
+        m->declare("filters.lib/iir:author", "Julius O. Smith III");
+        m->declare(
+            "filters.lib/iir:copyright",
+            "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+        m->declare("filters.lib/iir:license", "MIT-style STK-4.3 license");
+        m->declare("filters.lib/lowpass0_highpass1", "MIT-style STK-4.3 license");
+        m->declare("filters.lib/lowpass0_highpass1:author", "Julius O. Smith III");
+        m->declare("filters.lib/lowpass:author", "Julius O. Smith III");
+        m->declare(
+            "filters.lib/lowpass:copyright",
+            "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+        m->declare("filters.lib/lowpass:license", "MIT-style STK-4.3 license");
+        m->declare("filters.lib/name", "Faust Filters Library");
+        m->declare("filters.lib/peak_eq_rm:author", "Julius O. Smith III");
+        m->declare(
+            "filters.lib/peak_eq_rm:copyright",
+            "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+        m->declare("filters.lib/peak_eq_rm:license", "MIT-style STK-4.3 license");
+        m->declare("filters.lib/tf1:author", "Julius O. Smith III");
+        m->declare(
+            "filters.lib/tf1:copyright",
+            "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+        m->declare("filters.lib/tf1:license", "MIT-style STK-4.3 license");
+        m->declare("filters.lib/tf1s:author", "Julius O. Smith III");
+        m->declare(
+            "filters.lib/tf1s:copyright",
+            "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+        m->declare("filters.lib/tf1s:license", "MIT-style STK-4.3 license");
+        m->declare("filters.lib/tf2:author", "Julius O. Smith III");
+        m->declare(
+            "filters.lib/tf2:copyright",
+            "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+        m->declare("filters.lib/tf2:license", "MIT-style STK-4.3 license");
+        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.3");
+        m->declare("name", "zitarevmonodsp");
+        m->declare("platform.lib/name", "Generic Platform Library");
+        m->declare("platform.lib/version", "0.1");
+        m->declare("reverbs.lib/name", "Faust Reverb Library");
+        m->declare("reverbs.lib/version", "0.0");
+        m->declare("routes.lib/name", "Faust Signal Routing Library");
+        m->declare("routes.lib/version", "0.2");
+        m->declare("signals.lib/name", "Faust Signal Routing Library");
+        m->declare("signals.lib/version", "0.0");
+    }
+
+    virtual int getNumInputs() { return 1; }
+    virtual int getNumOutputs() { return 1; }
+    virtual int getInputRate(int channel)
+    {
+        int rate;
+        switch ((channel)) {
+        case 0: {
+            rate = 1;
+            break;
+        }
+        default: {
+            rate = -1;
+            break;
+        }
+        }
+        return rate;
+    }
+    virtual int getOutputRate(int channel)
+    {
+        int rate;
+        switch ((channel)) {
+        case 0: {
+            rate = 1;
+            break;
+        }
+        default: {
+            rate = -1;
+            break;
+        }
+        }
+        return rate;
+    }
+
+    static void classInit(int /*sample_rate*/) {}
+
+    virtual void instanceConstants(int sample_rate)
+    {
+        fSampleRate = sample_rate;
+        fConst0 = std::min<float>(192000.0f, std::max<float>(1.0f, float(fSampleRate)));
+        fConst1 = (6.28318548f / fConst0);
+        fConst2 = std::floor(((0.219990999f * fConst0) + 0.5f));
+        fConst3 = ((0.0f - (6.90775537f * fConst2)) / fConst0);
+        fConst4 = (3.14159274f / fConst0);
+        fConst5 = std::floor(((0.0191229992f * fConst0) + 0.5f));
+        iConst6 =
+            int(std::min<float>(16384.0f, std::max<float>(0.0f, (fConst2 - fConst5))));
+        fConst7 = (0.00100000005f * fConst0);
+        iConst8 = int(std::min<float>(1024.0f, std::max<float>(0.0f, (fConst5 + -1.0f))));
+        fConst9 = std::floor(((0.256891012f * fConst0) + 0.5f));
+        fConst10 = ((0.0f - (6.90775537f * fConst9)) / fConst0);
+        fConst11 = std::floor(((0.0273330007f * fConst0) + 0.5f));
+        iConst12 =
+            int(std::min<float>(16384.0f, std::max<float>(0.0f, (fConst9 - fConst11))));
+        iConst13 =
+            int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst11 + -1.0f))));
+        fConst14 = std::floor(((0.192303002f * fConst0) + 0.5f));
+        fConst15 = ((0.0f - (6.90775537f * fConst14)) / fConst0);
+        fConst16 = std::floor(((0.0292910002f * fConst0) + 0.5f));
+        iConst17 =
+            int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst14 - fConst16))));
+        iConst18 =
+            int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst16 + -1.0f))));
+        fConst19 = std::floor(((0.210389003f * fConst0) + 0.5f));
+        fConst20 = ((0.0f - (6.90775537f * fConst19)) / fConst0);
+        fConst21 = std::floor(((0.0244210009f * fConst0) + 0.5f));
+        iConst22 =
+            int(std::min<float>(16384.0f, std::max<float>(0.0f, (fConst19 - fConst21))));
+        iConst23 =
+            int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst21 + -1.0f))));
+        fConst24 = std::floor(((0.125f * fConst0) + 0.5f));
+        fConst25 = ((0.0f - (6.90775537f * fConst24)) / fConst0);
+        fConst26 = std::floor(((0.0134579996f * fConst0) + 0.5f));
+        iConst27 =
+            int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst24 - fConst26))));
+        iConst28 =
+            int(std::min<float>(1024.0f, std::max<float>(0.0f, (fConst26 + -1.0f))));
+        fConst29 = std::floor(((0.127837002f * fConst0) + 0.5f));
+        fConst30 = ((0.0f - (6.90775537f * fConst29)) / fConst0);
+        fConst31 = std::floor(((0.0316039994f * fConst0) + 0.5f));
+        iConst32 =
+            int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst29 - fConst31))));
+        iConst33 =
+            int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst31 + -1.0f))));
+        fConst34 = std::floor(((0.174713001f * fConst0) + 0.5f));
+        fConst35 = ((0.0f - (6.90775537f * fConst34)) / fConst0);
+        fConst36 = std::floor(((0.0229039993f * fConst0) + 0.5f));
+        iConst37 =
+            int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst34 - fConst36))));
+        iConst38 =
+            int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst36 + -1.0f))));
+        fConst39 = std::floor(((0.153128996f * fConst0) + 0.5f));
+        fConst40 = ((0.0f - (6.90775537f * fConst39)) / fConst0);
+        fConst41 = std::floor(((0.0203460008f * fConst0) + 0.5f));
+        iConst42 =
+            int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst39 - fConst41))));
+        iConst43 =
+            int(std::min<float>(1024.0f, std::max<float>(0.0f, (fConst41 + -1.0f))));
+    }
+
+    virtual void instanceResetUserInterface()
+    {
+        fVslider0  = FAUSTFLOAT(-3.0f);
+        fVslider1  = FAUSTFLOAT(0.0f);
+        fVslider2  = FAUSTFLOAT(1500.0f);
+        fVslider3  = FAUSTFLOAT(0.0f);
+        fVslider4  = FAUSTFLOAT(315.0f);
+        fVslider5  = FAUSTFLOAT(0.0f);
+        fVslider6  = FAUSTFLOAT(2.0f);
+        fVslider7  = FAUSTFLOAT(6000.0f);
+        fVslider8  = FAUSTFLOAT(3.0f);
+        fVslider9  = FAUSTFLOAT(200.0f);
+        fVslider10 = FAUSTFLOAT(60.0f);
+    }
+
+    virtual void instanceClear()
+    {
+        IOTA = 0;
+        for (int l0 = 0; (l0 < 16384); l0 = (l0 + 1)) { fVec0[l0] = 0.0f; }
+        for (int l1 = 0; (l1 < 2); l1 = (l1 + 1)) { fRec0[l1] = 0.0f; }
+        for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) { fRec1[l2] = 0.0f; }
+        for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) { fRec15[l3] = 0.0f; }
+        for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) { fRec14[l4] = 0.0f; }
+        for (int l5 = 0; (l5 < 32768); l5 = (l5 + 1)) { fVec1[l5] = 0.0f; }
+        for (int l6 = 0; (l6 < 2048); l6 = (l6 + 1)) { fVec2[l6] = 0.0f; }
+        for (int l7 = 0; (l7 < 2); l7 = (l7 + 1)) { fRec12[l7] = 0.0f; }
+        for (int l8 = 0; (l8 < 2); l8 = (l8 + 1)) { fRec19[l8] = 0.0f; }
+        for (int l9 = 0; (l9 < 2); l9 = (l9 + 1)) { fRec18[l9] = 0.0f; }
+        for (int l10 = 0; (l10 < 32768); l10 = (l10 + 1)) { fVec3[l10] = 0.0f; }
+        for (int l11 = 0; (l11 < 4096); l11 = (l11 + 1)) { fVec4[l11] = 0.0f; }
+        for (int l12 = 0; (l12 < 2); l12 = (l12 + 1)) { fRec16[l12] = 0.0f; }
+        for (int l13 = 0; (l13 < 2); l13 = (l13 + 1)) { fRec23[l13] = 0.0f; }
+        for (int l14 = 0; (l14 < 2); l14 = (l14 + 1)) { fRec22[l14] = 0.0f; }
+        for (int l15 = 0; (l15 < 16384); l15 = (l15 + 1)) { fVec5[l15] = 0.0f; }
+        for (int l16 = 0; (l16 < 4096); l16 = (l16 + 1)) { fVec6[l16] = 0.0f; }
+        for (int l17 = 0; (l17 < 2); l17 = (l17 + 1)) { fRec20[l17] = 0.0f; }
+        for (int l18 = 0; (l18 < 2); l18 = (l18 + 1)) { fRec27[l18] = 0.0f; }
+        for (int l19 = 0; (l19 < 2); l19 = (l19 + 1)) { fRec26[l19] = 0.0f; }
+        for (int l20 = 0; (l20 < 32768); l20 = (l20 + 1)) { fVec7[l20] = 0.0f; }
+        for (int l21 = 0; (l21 < 4096); l21 = (l21 + 1)) { fVec8[l21] = 0.0f; }
+        for (int l22 = 0; (l22 < 2); l22 = (l22 + 1)) { fRec24[l22] = 0.0f; }
+        for (int l23 = 0; (l23 < 2); l23 = (l23 + 1)) { fRec31[l23] = 0.0f; }
+        for (int l24 = 0; (l24 < 2); l24 = (l24 + 1)) { fRec30[l24] = 0.0f; }
+        for (int l25 = 0; (l25 < 16384); l25 = (l25 + 1)) { fVec9[l25] = 0.0f; }
+        for (int l26 = 0; (l26 < 2048); l26 = (l26 + 1)) { fVec10[l26] = 0.0f; }
+        for (int l27 = 0; (l27 < 2); l27 = (l27 + 1)) { fRec28[l27] = 0.0f; }
+        for (int l28 = 0; (l28 < 2); l28 = (l28 + 1)) { fRec35[l28] = 0.0f; }
+        for (int l29 = 0; (l29 < 2); l29 = (l29 + 1)) { fRec34[l29] = 0.0f; }
+        for (int l30 = 0; (l30 < 16384); l30 = (l30 + 1)) { fVec11[l30] = 0.0f; }
+        for (int l31 = 0; (l31 < 4096); l31 = (l31 + 1)) { fVec12[l31] = 0.0f; }
+        for (int l32 = 0; (l32 < 2); l32 = (l32 + 1)) { fRec32[l32] = 0.0f; }
+        for (int l33 = 0; (l33 < 2); l33 = (l33 + 1)) { fRec39[l33] = 0.0f; }
+        for (int l34 = 0; (l34 < 2); l34 = (l34 + 1)) { fRec38[l34] = 0.0f; }
+        for (int l35 = 0; (l35 < 16384); l35 = (l35 + 1)) { fVec13[l35] = 0.0f; }
+        for (int l36 = 0; (l36 < 4096); l36 = (l36 + 1)) { fVec14[l36] = 0.0f; }
+        for (int l37 = 0; (l37 < 2); l37 = (l37 + 1)) { fRec36[l37] = 0.0f; }
+        for (int l38 = 0; (l38 < 2); l38 = (l38 + 1)) { fRec43[l38] = 0.0f; }
+        for (int l39 = 0; (l39 < 2); l39 = (l39 + 1)) { fRec42[l39] = 0.0f; }
+        for (int l40 = 0; (l40 < 16384); l40 = (l40 + 1)) { fVec15[l40] = 0.0f; }
+        for (int l41 = 0; (l41 < 2048); l41 = (l41 + 1)) { fVec16[l41] = 0.0f; }
+        for (int l42 = 0; (l42 < 2); l42 = (l42 + 1)) { fRec40[l42] = 0.0f; }
+        for (int l43 = 0; (l43 < 3); l43 = (l43 + 1)) { fRec4[l43] = 0.0f; }
+        for (int l44 = 0; (l44 < 3); l44 = (l44 + 1)) { fRec5[l44] = 0.0f; }
+        for (int l45 = 0; (l45 < 3); l45 = (l45 + 1)) { fRec6[l45] = 0.0f; }
+        for (int l46 = 0; (l46 < 3); l46 = (l46 + 1)) { fRec7[l46] = 0.0f; }
+        for (int l47 = 0; (l47 < 3); l47 = (l47 + 1)) { fRec8[l47] = 0.0f; }
+        for (int l48 = 0; (l48 < 3); l48 = (l48 + 1)) { fRec9[l48] = 0.0f; }
+        for (int l49 = 0; (l49 < 3); l49 = (l49 + 1)) { fRec10[l49] = 0.0f; }
+        for (int l50 = 0; (l50 < 3); l50 = (l50 + 1)) { fRec11[l50] = 0.0f; }
+        for (int l51 = 0; (l51 < 3); l51 = (l51 + 1)) { fRec3[l51] = 0.0f; }
+        for (int l52 = 0; (l52 < 3); l52 = (l52 + 1)) { fRec2[l52] = 0.0f; }
+        for (int l53 = 0; (l53 < 3); l53 = (l53 + 1)) { fRec45[l53] = 0.0f; }
+        for (int l54 = 0; (l54 < 3); l54 = (l54 + 1)) { fRec44[l54] = 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 zitarevmonodsp* clone() { return new zitarevmonodsp(); }
+
+    virtual int getSampleRate() { return fSampleRate; }
+
+    virtual void buildUserInterface(UI* ui_interface)
+    {
+        ui_interface->declare(0, "0", "");
+        ui_interface->declare(0, "tooltip",
+                              "~ ZITA REV1 FEEDBACK DELAY NETWORK (FDN) & SCHROEDER  "
+                              "ALLPASS-COMB REVERBERATOR (8x8). See Faust's reverbs.lib "
+                              "for documentation and  references");
+        ui_interface->openHorizontalBox("Zita_Rev1");
+        ui_interface->declare(0, "1", "");
+        ui_interface->openHorizontalBox("Input");
+        ui_interface->declare(&fVslider10, "1", "");
+        ui_interface->declare(&fVslider10, "style", "knob");
+        ui_interface->declare(&fVslider10, "tooltip",
+                              "Delay in ms   before reverberation begins");
+        ui_interface->declare(&fVslider10, "unit", "ms");
+        ui_interface->addVerticalSlider("In Delay", &fVslider10, 60.0f, 20.0f, 100.0f,
+                                        1.0f);
+        ui_interface->closeBox();
+        ui_interface->declare(0, "2", "");
+        ui_interface->openHorizontalBox("Decay Times in Bands (see tooltips)");
+        ui_interface->declare(&fVslider9, "1", "");
+        ui_interface->declare(&fVslider9, "scale", "log");
+        ui_interface->declare(&fVslider9, "style", "knob");
+        ui_interface->declare(
+            &fVslider9, "tooltip",
+            "Crossover frequency (Hz) separating low and middle frequencies");
+        ui_interface->declare(&fVslider9, "unit", "Hz");
+        ui_interface->addVerticalSlider("LF X", &fVslider9, 200.0f, 50.0f, 1000.0f, 1.0f);
+        ui_interface->declare(&fVslider8, "2", "");
+        ui_interface->declare(&fVslider8, "scale", "log");
+        ui_interface->declare(&fVslider8, "style", "knob");
+        ui_interface->declare(
+            &fVslider8, "tooltip",
+            "T60 = time (in seconds) to decay 60dB in low-frequency band");
+        ui_interface->declare(&fVslider8, "unit", "s");
+        ui_interface->addVerticalSlider("Low RT60", &fVslider8, 3.0f, 1.0f, 8.0f,
+                                        0.100000001f);
+        ui_interface->declare(&fVslider6, "3", "");
+        ui_interface->declare(&fVslider6, "scale", "log");
+        ui_interface->declare(&fVslider6, "style", "knob");
+        ui_interface->declare(&fVslider6, "tooltip",
+                              "T60 = time (in seconds) to decay 60dB in middle band");
+        ui_interface->declare(&fVslider6, "unit", "s");
+        ui_interface->addVerticalSlider("Mid RT60", &fVslider6, 2.0f, 1.0f, 8.0f,
+                                        0.100000001f);
+        ui_interface->declare(&fVslider7, "4", "");
+        ui_interface->declare(&fVslider7, "scale", "log");
+        ui_interface->declare(&fVslider7, "style", "knob");
+        ui_interface->declare(&fVslider7, "tooltip",
+                              "Frequency (Hz) at which the high-frequency T60 is half "
+                              "the middle-band's T60");
+        ui_interface->declare(&fVslider7, "unit", "Hz");
+        ui_interface->addVerticalSlider("HF Damping", &fVslider7, 6000.0f, 1500.0f,
+                                        23520.0f, 1.0f);
+        ui_interface->closeBox();
+        ui_interface->declare(0, "3", "");
+        ui_interface->openHorizontalBox("RM Peaking Equalizer 1");
+        ui_interface->declare(&fVslider4, "1", "");
+        ui_interface->declare(&fVslider4, "scale", "log");
+        ui_interface->declare(&fVslider4, "style", "knob");
+        ui_interface->declare(
+            &fVslider4, "tooltip",
+            "Center-frequency of second-order Regalia-Mitra peaking equalizer section 1");
+        ui_interface->declare(&fVslider4, "unit", "Hz");
+        ui_interface->addVerticalSlider("Eq1 Freq", &fVslider4, 315.0f, 40.0f, 2500.0f,
+                                        1.0f);
+        ui_interface->declare(&fVslider5, "2", "");
+        ui_interface->declare(&fVslider5, "style", "knob");
+        ui_interface->declare(&fVslider5, "tooltip",
+                              "Peak level   in dB of second-order Regalia-Mitra peaking "
+                              "equalizer section 1");
+        ui_interface->declare(&fVslider5, "unit", "dB");
+        ui_interface->addVerticalSlider("Eq1 Level", &fVslider5, 0.0f, -15.0f, 15.0f,
+                                        0.100000001f);
+        ui_interface->closeBox();
+        ui_interface->declare(0, "4", "");
+        ui_interface->openHorizontalBox("RM Peaking Equalizer 2");
+        ui_interface->declare(&fVslider2, "1", "");
+        ui_interface->declare(&fVslider2, "scale", "log");
+        ui_interface->declare(&fVslider2, "style", "knob");
+        ui_interface->declare(
+            &fVslider2, "tooltip",
+            "Center-frequency of second-order Regalia-Mitra peaking equalizer section 2");
+        ui_interface->declare(&fVslider2, "unit", "Hz");
+        ui_interface->addVerticalSlider("Eq2 Freq", &fVslider2, 1500.0f, 160.0f, 10000.0f,
+                                        1.0f);
+        ui_interface->declare(&fVslider3, "2", "");
+        ui_interface->declare(&fVslider3, "style", "knob");
+        ui_interface->declare(&fVslider3, "tooltip",
+                              "Peak level   in dB of second-order Regalia-Mitra peaking "
+                              "equalizer section 2");
+        ui_interface->declare(&fVslider3, "unit", "dB");
+        ui_interface->addVerticalSlider("Eq2 Level", &fVslider3, 0.0f, -15.0f, 15.0f,
+                                        0.100000001f);
+        ui_interface->closeBox();
+        ui_interface->declare(0, "5", "");
+        ui_interface->openHorizontalBox("Output");
+        ui_interface->declare(&fVslider1, "1", "");
+        ui_interface->declare(&fVslider1, "style", "knob");
+        ui_interface->declare(&fVslider1, "tooltip", "Dry/Wet Mix: 0 = dry, 1 = wet");
+        ui_interface->addVerticalSlider("Wet", &fVslider1, 0.0f, 0.0f, 1.0f,
+                                        0.00999999978f);
+        ui_interface->declare(&fVslider0, "2", "");
+        ui_interface->declare(&fVslider0, "style", "knob");
+        ui_interface->declare(&fVslider0, "tooltip", "Output scale   factor");
+        ui_interface->declare(&fVslider0, "unit", "dB");
+        ui_interface->addVerticalSlider("Level", &fVslider0, -3.0f, -70.0f, 20.0f,
+                                        0.100000001f);
+        ui_interface->closeBox();
+        ui_interface->closeBox();
+    }
+
+    virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
+    {
+        FAUSTFLOAT* input0  = inputs[0];
+        FAUSTFLOAT* output0 = outputs[0];
+        float fSlow0 =
+            (0.00100000005f * std::pow(10.0f, (0.0500000007f * float(fVslider0))));
+        float fSlow1  = (0.00100000005f * float(fVslider1));
+        float fSlow2  = float(fVslider2);
+        float fSlow3  = std::pow(10.0f, (0.0500000007f * float(fVslider3)));
+        float fSlow4  = (fConst1 * (fSlow2 / std::sqrt(std::max<float>(0.0f, fSlow3))));
+        float fSlow5  = ((1.0f - fSlow4) / (fSlow4 + 1.0f));
+        float fSlow6  = float(fVslider4);
+        float fSlow7  = std::pow(10.0f, (0.0500000007f * float(fVslider5)));
+        float fSlow8  = (fConst1 * (fSlow6 / std::sqrt(std::max<float>(0.0f, fSlow7))));
+        float fSlow9  = ((1.0f - fSlow8) / (fSlow8 + 1.0f));
+        float fSlow10 = float(fVslider6);
+        float fSlow11 = std::exp((fConst3 / fSlow10));
+        float fSlow12 = zitarevmonodsp_faustpower2_f(fSlow11);
+        float fSlow13 = std::cos((fConst1 * float(fVslider7)));
+        float fSlow14 = (1.0f - (fSlow12 * fSlow13));
+        float fSlow15 = (1.0f - fSlow12);
+        float fSlow16 = (fSlow14 / fSlow15);
+        float fSlow17 =
+            std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow14)
+                                              / zitarevmonodsp_faustpower2_f(fSlow15))
+                                             + -1.0f)));
+        float fSlow18 = (fSlow16 - fSlow17);
+        float fSlow19 = (fSlow11 * (fSlow17 + (1.0f - fSlow16)));
+        float fSlow20 = float(fVslider8);
+        float fSlow21 = ((std::exp((fConst3 / fSlow20)) / fSlow11) + -1.0f);
+        float fSlow22 = (1.0f / std::tan((fConst4 * float(fVslider9))));
+        float fSlow23 = (1.0f / (fSlow22 + 1.0f));
+        float fSlow24 = (1.0f - fSlow22);
+        int iSlow25   = int(std::min<float>(
+            8192.0f, std::max<float>(0.0f, (fConst7 * float(fVslider10)))));
+        float fSlow26 = std::exp((fConst10 / fSlow10));
+        float fSlow27 = zitarevmonodsp_faustpower2_f(fSlow26);
+        float fSlow28 = (1.0f - (fSlow27 * fSlow13));
+        float fSlow29 = (1.0f - fSlow27);
+        float fSlow30 = (fSlow28 / fSlow29);
+        float fSlow31 =
+            std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow28)
+                                              / zitarevmonodsp_faustpower2_f(fSlow29))
+                                             + -1.0f)));
+        float fSlow32 = (fSlow30 - fSlow31);
+        float fSlow33 = (fSlow26 * (fSlow31 + (1.0f - fSlow30)));
+        float fSlow34 = ((std::exp((fConst10 / fSlow20)) / fSlow26) + -1.0f);
+        float fSlow35 = std::exp((fConst15 / fSlow10));
+        float fSlow36 = zitarevmonodsp_faustpower2_f(fSlow35);
+        float fSlow37 = (1.0f - (fSlow36 * fSlow13));
+        float fSlow38 = (1.0f - fSlow36);
+        float fSlow39 = (fSlow37 / fSlow38);
+        float fSlow40 =
+            std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow37)
+                                              / zitarevmonodsp_faustpower2_f(fSlow38))
+                                             + -1.0f)));
+        float fSlow41 = (fSlow39 - fSlow40);
+        float fSlow42 = (fSlow35 * (fSlow40 + (1.0f - fSlow39)));
+        float fSlow43 = ((std::exp((fConst15 / fSlow20)) / fSlow35) + -1.0f);
+        float fSlow44 = std::exp((fConst20 / fSlow10));
+        float fSlow45 = zitarevmonodsp_faustpower2_f(fSlow44);
+        float fSlow46 = (1.0f - (fSlow45 * fSlow13));
+        float fSlow47 = (1.0f - fSlow45);
+        float fSlow48 = (fSlow46 / fSlow47);
+        float fSlow49 =
+            std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow46)
+                                              / zitarevmonodsp_faustpower2_f(fSlow47))
+                                             + -1.0f)));
+        float fSlow50 = (fSlow48 - fSlow49);
+        float fSlow51 = (fSlow44 * (fSlow49 + (1.0f - fSlow48)));
+        float fSlow52 = ((std::exp((fConst20 / fSlow20)) / fSlow44) + -1.0f);
+        float fSlow53 = std::exp((fConst25 / fSlow10));
+        float fSlow54 = zitarevmonodsp_faustpower2_f(fSlow53);
+        float fSlow55 = (1.0f - (fSlow54 * fSlow13));
+        float fSlow56 = (1.0f - fSlow54);
+        float fSlow57 = (fSlow55 / fSlow56);
+        float fSlow58 =
+            std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow55)
+                                              / zitarevmonodsp_faustpower2_f(fSlow56))
+                                             + -1.0f)));
+        float fSlow59 = (fSlow57 - fSlow58);
+        float fSlow60 = (fSlow53 * (fSlow58 + (1.0f - fSlow57)));
+        float fSlow61 = ((std::exp((fConst25 / fSlow20)) / fSlow53) + -1.0f);
+        float fSlow62 = std::exp((fConst30 / fSlow10));
+        float fSlow63 = zitarevmonodsp_faustpower2_f(fSlow62);
+        float fSlow64 = (1.0f - (fSlow63 * fSlow13));
+        float fSlow65 = (1.0f - fSlow63);
+        float fSlow66 = (fSlow64 / fSlow65);
+        float fSlow67 =
+            std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow64)
+                                              / zitarevmonodsp_faustpower2_f(fSlow65))
+                                             + -1.0f)));
+        float fSlow68 = (fSlow66 - fSlow67);
+        float fSlow69 = (fSlow62 * (fSlow67 + (1.0f - fSlow66)));
+        float fSlow70 = ((std::exp((fConst30 / fSlow20)) / fSlow62) + -1.0f);
+        float fSlow71 = std::exp((fConst35 / fSlow10));
+        float fSlow72 = zitarevmonodsp_faustpower2_f(fSlow71);
+        float fSlow73 = (1.0f - (fSlow72 * fSlow13));
+        float fSlow74 = (1.0f - fSlow72);
+        float fSlow75 = (fSlow73 / fSlow74);
+        float fSlow76 =
+            std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow73)
+                                              / zitarevmonodsp_faustpower2_f(fSlow74))
+                                             + -1.0f)));
+        float fSlow77 = (fSlow75 - fSlow76);
+        float fSlow78 = (fSlow71 * (fSlow76 + (1.0f - fSlow75)));
+        float fSlow79 = ((std::exp((fConst35 / fSlow20)) / fSlow71) + -1.0f);
+        float fSlow80 = std::exp((fConst40 / fSlow10));
+        float fSlow81 = zitarevmonodsp_faustpower2_f(fSlow80);
+        float fSlow82 = (1.0f - (fSlow81 * fSlow13));
+        float fSlow83 = (1.0f - fSlow81);
+        float fSlow84 = (fSlow82 / fSlow83);
+        float fSlow85 =
+            std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow82)
+                                              / zitarevmonodsp_faustpower2_f(fSlow83))
+                                             + -1.0f)));
+        float fSlow86 = (fSlow84 - fSlow85);
+        float fSlow87 = (fSlow80 * (fSlow85 + (1.0f - fSlow84)));
+        float fSlow88 = ((std::exp((fConst40 / fSlow20)) / fSlow80) + -1.0f);
+        float fSlow89 = (0.0f - (std::cos((fConst1 * fSlow6)) * (fSlow9 + 1.0f)));
+        float fSlow90 = (0.0f - (std::cos((fConst1 * fSlow2)) * (fSlow5 + 1.0f)));
+        for (int i = 0; (i < count); i = (i + 1)) {
+            float fTemp0          = float(input0[i]);
+            fVec0[(IOTA & 16383)] = fTemp0;
+            fRec0[0]              = (fSlow0 + (0.999000013f * fRec0[1]));
+            fRec1[0]              = (fSlow1 + (0.999000013f * fRec1[1]));
+            fRec15[0] =
+                (0.0f - (fSlow23 * ((fSlow24 * fRec15[1]) - (fRec11[1] + fRec11[2]))));
+            fRec14[0] =
+                ((fSlow18 * fRec14[1]) + (fSlow19 * (fRec11[1] + (fSlow21 * fRec15[0]))));
+            fVec1[(IOTA & 32767)] = ((0.353553385f * fRec14[0]) + 9.99999968e-21f);
+            float fTemp1          = (0.300000012f * fVec0[((IOTA - iSlow25) & 16383)]);
+            float fTemp2 =
+                (((0.600000024f * fRec12[1]) + fVec1[((IOTA - iConst6) & 32767)])
+                 - fTemp1);
+            fVec2[(IOTA & 2047)] = fTemp2;
+            fRec12[0]            = fVec2[((IOTA - iConst8) & 2047)];
+            float fRec13         = (0.0f - (0.600000024f * fTemp2));
+            fRec19[0] =
+                (0.0f - (fSlow23 * ((fSlow24 * fRec19[1]) - (fRec7[1] + fRec7[2]))));
+            fRec18[0] =
+                ((fSlow32 * fRec18[1]) + (fSlow33 * (fRec7[1] + (fSlow34 * fRec19[0]))));
+            fVec3[(IOTA & 32767)] = ((0.353553385f * fRec18[0]) + 9.99999968e-21f);
+            float fTemp3 =
+                (((0.600000024f * fRec16[1]) + fVec3[((IOTA - iConst12) & 32767)])
+                 - fTemp1);
+            fVec4[(IOTA & 4095)] = fTemp3;
+            fRec16[0]            = fVec4[((IOTA - iConst13) & 4095)];
+            float fRec17         = (0.0f - (0.600000024f * fTemp3));
+            fRec23[0] =
+                (0.0f - (fSlow23 * ((fSlow24 * fRec23[1]) - (fRec9[1] + fRec9[2]))));
+            fRec22[0] =
+                ((fSlow41 * fRec22[1]) + (fSlow42 * (fRec9[1] + (fSlow43 * fRec23[0]))));
+            fVec5[(IOTA & 16383)] = ((0.353553385f * fRec22[0]) + 9.99999968e-21f);
+            float fTemp4          = (fVec5[((IOTA - iConst17) & 16383)]
+                            + (fTemp1 + (0.600000024f * fRec20[1])));
+            fVec6[(IOTA & 4095)]  = fTemp4;
+            fRec20[0]             = fVec6[((IOTA - iConst18) & 4095)];
+            float fRec21          = (0.0f - (0.600000024f * fTemp4));
+            fRec27[0] =
+                (0.0f - (fSlow23 * ((fSlow24 * fRec27[1]) - (fRec5[1] + fRec5[2]))));
+            fRec26[0] =
+                ((fSlow50 * fRec26[1]) + (fSlow51 * (fRec5[1] + (fSlow52 * fRec27[0]))));
+            fVec7[(IOTA & 32767)] = ((0.353553385f * fRec26[0]) + 9.99999968e-21f);
+            float fTemp5          = (fVec7[((IOTA - iConst22) & 32767)]
+                            + (fTemp1 + (0.600000024f * fRec24[1])));
+            fVec8[(IOTA & 4095)]  = fTemp5;
+            fRec24[0]             = fVec8[((IOTA - iConst23) & 4095)];
+            float fRec25          = (0.0f - (0.600000024f * fTemp5));
+            fRec31[0] =
+                (0.0f - (fSlow23 * ((fSlow24 * fRec31[1]) - (fRec10[1] + fRec10[2]))));
+            fRec30[0] =
+                ((fSlow59 * fRec30[1]) + (fSlow60 * (fRec10[1] + (fSlow61 * fRec31[0]))));
+            fVec9[(IOTA & 16383)] = ((0.353553385f * fRec30[0]) + 9.99999968e-21f);
+            float fTemp6          = (fVec9[((IOTA - iConst27) & 16383)]
+                            - (fTemp1 + (0.600000024f * fRec28[1])));
+            fVec10[(IOTA & 2047)] = fTemp6;
+            fRec28[0]             = fVec10[((IOTA - iConst28) & 2047)];
+            float fRec29          = (0.600000024f * fTemp6);
+            fRec35[0] =
+                (0.0f - (fSlow23 * ((fSlow24 * fRec35[1]) - (fRec6[1] + fRec6[2]))));
+            fRec34[0] =
+                ((fSlow68 * fRec34[1]) + (fSlow69 * (fRec6[1] + (fSlow70 * fRec35[0]))));
+            fVec11[(IOTA & 16383)] = ((0.353553385f * fRec34[0]) + 9.99999968e-21f);
+            float fTemp7           = (fVec11[((IOTA - iConst32) & 16383)]
+                            - (fTemp1 + (0.600000024f * fRec32[1])));
+            fVec12[(IOTA & 4095)]  = fTemp7;
+            fRec32[0]              = fVec12[((IOTA - iConst33) & 4095)];
+            float fRec33           = (0.600000024f * fTemp7);
+            fRec39[0] =
+                (0.0f - (fSlow23 * ((fSlow24 * fRec39[1]) - (fRec8[1] + fRec8[2]))));
+            fRec38[0] =
+                ((fSlow77 * fRec38[1]) + (fSlow78 * (fRec8[1] + (fSlow79 * fRec39[0]))));
+            fVec13[(IOTA & 16383)] = ((0.353553385f * fRec38[0]) + 9.99999968e-21f);
+            float fTemp8           = ((fTemp1 + fVec13[((IOTA - iConst37) & 16383)])
+                            - (0.600000024f * fRec36[1]));
+            fVec14[(IOTA & 4095)]  = fTemp8;
+            fRec36[0]              = fVec14[((IOTA - iConst38) & 4095)];
+            float fRec37           = (0.600000024f * fTemp8);
+            fRec43[0] =
+                (0.0f - (fSlow23 * ((fSlow24 * fRec43[1]) - (fRec4[1] + fRec4[2]))));
+            fRec42[0] =
+                ((fSlow86 * fRec42[1]) + (fSlow87 * (fRec4[1] + (fSlow88 * fRec43[0]))));
+            fVec15[(IOTA & 16383)] = ((0.353553385f * fRec42[0]) + 9.99999968e-21f);
+            float fTemp9           = ((fVec15[((IOTA - iConst42) & 16383)] + fTemp1)
+                            - (0.600000024f * fRec40[1]));
+            fVec16[(IOTA & 2047)]  = fTemp9;
+            fRec40[0]              = fVec16[((IOTA - iConst43) & 2047)];
+            float fRec41           = (0.600000024f * fTemp9);
+            float fTemp10          = (fRec41 + fRec37);
+            float fTemp11          = (fRec29 + (fRec33 + fTemp10));
+            fRec4[0] =
+                (fRec12[1]
+                 + (fRec16[1]
+                    + (fRec20[1]
+                       + (fRec24[1]
+                          + (fRec28[1]
+                             + (fRec32[1]
+                                + (fRec36[1]
+                                   + (fRec40[1]
+                                      + (fRec13
+                                         + (fRec17
+                                            + (fRec21 + (fRec25 + fTemp11))))))))))));
+            fRec5[0] =
+                ((fRec28[1] + (fRec32[1] + (fRec36[1] + (fRec40[1] + fTemp11))))
+                 - (fRec12[1]
+                    + (fRec16[1]
+                       + (fRec20[1]
+                          + (fRec24[1] + (fRec13 + (fRec17 + (fRec25 + fRec21))))))));
+            float fTemp12 = (fRec33 + fRec29);
+            fRec6[0] =
+                ((fRec20[1]
+                  + (fRec24[1]
+                     + (fRec36[1] + (fRec40[1] + (fRec21 + (fRec25 + fTemp10))))))
+                 - (fRec12[1]
+                    + (fRec16[1]
+                       + (fRec28[1] + (fRec32[1] + (fRec13 + (fRec17 + fTemp12)))))));
+            fRec7[0] =
+                ((fRec12[1]
+                  + (fRec16[1]
+                     + (fRec36[1] + (fRec40[1] + (fRec13 + (fRec17 + fTemp10))))))
+                 - (fRec20[1]
+                    + (fRec24[1]
+                       + (fRec28[1] + (fRec32[1] + (fRec21 + (fRec25 + fTemp12)))))));
+            float fTemp13 = (fRec41 + fRec33);
+            float fTemp14 = (fRec37 + fRec29);
+            fRec8[0] =
+                ((fRec16[1]
+                  + (fRec24[1]
+                     + (fRec32[1] + (fRec40[1] + (fRec17 + (fRec25 + fTemp13))))))
+                 - (fRec12[1]
+                    + (fRec20[1]
+                       + (fRec28[1] + (fRec36[1] + (fRec13 + (fRec21 + fTemp14)))))));
+            fRec9[0] =
+                ((fRec12[1]
+                  + (fRec20[1]
+                     + (fRec32[1] + (fRec40[1] + (fRec13 + (fRec21 + fTemp13))))))
+                 - (fRec16[1]
+                    + (fRec24[1]
+                       + (fRec28[1] + (fRec36[1] + (fRec17 + (fRec25 + fTemp14)))))));
+            float fTemp15 = (fRec41 + fRec29);
+            float fTemp16 = (fRec37 + fRec33);
+            fRec10[0] =
+                ((fRec12[1]
+                  + (fRec24[1]
+                     + (fRec28[1] + (fRec40[1] + (fRec13 + (fRec25 + fTemp15))))))
+                 - (fRec16[1]
+                    + (fRec20[1]
+                       + (fRec32[1] + (fRec36[1] + (fRec17 + (fRec21 + fTemp16)))))));
+            fRec11[0] =
+                ((fRec16[1]
+                  + (fRec20[1]
+                     + (fRec28[1] + (fRec40[1] + (fRec17 + (fRec21 + fTemp15))))))
+                 - (fRec12[1]
+                    + (fRec24[1]
+                       + (fRec32[1] + (fRec36[1] + (fRec13 + (fRec25 + fTemp16)))))));
+            float fTemp17 = (0.370000005f * (fRec5[0] + fRec6[0]));
+            float fTemp18 = (fSlow89 * fRec3[1]);
+            fRec3[0]      = (fTemp17 - (fTemp18 + (fSlow9 * fRec3[2])));
+            float fTemp19 = (fSlow9 * fRec3[0]);
+            float fTemp20 =
+                (0.5f
+                 * ((fTemp19 + (fRec3[2] + (fTemp17 + fTemp18)))
+                    + (fSlow7 * ((fTemp19 + (fTemp18 + fRec3[2])) - fTemp17))));
+            float fTemp21 = (fSlow90 * fRec2[1]);
+            fRec2[0]      = (fTemp20 - (fTemp21 + (fSlow5 * fRec2[2])));
+            float fTemp22 = (fSlow5 * fRec2[0]);
+            float fTemp23 = (fTemp0 * (1.0f - fRec1[0]));
+            float fTemp24 = (0.370000005f * (fRec5[0] - fRec6[0]));
+            float fTemp25 = (fSlow89 * fRec45[1]);
+            fRec45[0]     = (fTemp24 - (fTemp25 + (fSlow9 * fRec45[2])));
+            float fTemp26 = (fSlow9 * fRec45[0]);
+            float fTemp27 =
+                (0.5f
+                 * ((fTemp26 + (fRec45[2] + (fTemp24 + fTemp25)))
+                    + (fSlow7 * ((fTemp26 + (fTemp25 + fRec45[2])) - fTemp24))));
+            float fTemp28 = (fSlow90 * fRec44[1]);
+            fRec44[0]     = (fTemp27 - (fTemp28 + (fSlow5 * fRec44[2])));
+            float fTemp29 = (fSlow5 * fRec44[0]);
+            output0[i]    = FAUSTFLOAT((
+                fRec0[0]
+                * (((0.5f
+                     * (fRec1[0]
+                        * ((fTemp22 + (fRec2[2] + (fTemp20 + fTemp21)))
+                           + (fSlow3 * ((fTemp22 + (fTemp21 + fRec2[2])) - fTemp20)))))
+                    + fTemp23)
+                   + (fTemp23
+                      + (0.5f
+                         * (fRec1[0]
+                            * ((fTemp29 + (fRec44[2] + (fTemp27 + fTemp28)))
+                               + (fSlow3
+                                  * ((fTemp29 + (fTemp28 + fRec44[2])) - fTemp27)))))))));
+            IOTA          = (IOTA + 1);
+            fRec0[1]      = fRec0[0];
+            fRec1[1]      = fRec1[0];
+            fRec15[1]     = fRec15[0];
+            fRec14[1]     = fRec14[0];
+            fRec12[1]     = fRec12[0];
+            fRec19[1]     = fRec19[0];
+            fRec18[1]     = fRec18[0];
+            fRec16[1]     = fRec16[0];
+            fRec23[1]     = fRec23[0];
+            fRec22[1]     = fRec22[0];
+            fRec20[1]     = fRec20[0];
+            fRec27[1]     = fRec27[0];
+            fRec26[1]     = fRec26[0];
+            fRec24[1]     = fRec24[0];
+            fRec31[1]     = fRec31[0];
+            fRec30[1]     = fRec30[0];
+            fRec28[1]     = fRec28[0];
+            fRec35[1]     = fRec35[0];
+            fRec34[1]     = fRec34[0];
+            fRec32[1]     = fRec32[0];
+            fRec39[1]     = fRec39[0];
+            fRec38[1]     = fRec38[0];
+            fRec36[1]     = fRec36[0];
+            fRec43[1]     = fRec43[0];
+            fRec42[1]     = fRec42[0];
+            fRec40[1]     = fRec40[0];
+            fRec4[2]      = fRec4[1];
+            fRec4[1]      = fRec4[0];
+            fRec5[2]      = fRec5[1];
+            fRec5[1]      = fRec5[0];
+            fRec6[2]      = fRec6[1];
+            fRec6[1]      = fRec6[0];
+            fRec7[2]      = fRec7[1];
+            fRec7[1]      = fRec7[0];
+            fRec8[2]      = fRec8[1];
+            fRec8[1]      = fRec8[0];
+            fRec9[2]      = fRec9[1];
+            fRec9[1]      = fRec9[0];
+            fRec10[2]     = fRec10[1];
+            fRec10[1]     = fRec10[0];
+            fRec11[2]     = fRec11[1];
+            fRec11[1]     = fRec11[0];
+            fRec3[2]      = fRec3[1];
+            fRec3[1]      = fRec3[0];
+            fRec2[2]      = fRec2[1];
+            fRec2[1]      = fRec2[0];
+            fRec45[2]     = fRec45[1];
+            fRec45[1]     = fRec45[0];
+            fRec44[2]     = fRec44[1];
+            fRec44[1]     = fRec44[0];
+        }
+    }
 };
 
 #endif
diff --git a/subprojects/rtaudio.wrap b/subprojects/rtaudio.wrap
new file mode 100644 (file)
index 0000000..cdb4fb2
--- /dev/null
@@ -0,0 +1,6 @@
+[wrap-git]
+url=https://github.com/thestk/rtaudio.git
+revision=head
+
+[provide]
+dependency_names = rtaudio
diff --git a/subprojects/wingetopt.wrap b/subprojects/wingetopt.wrap
new file mode 100644 (file)
index 0000000..dcc94c1
--- /dev/null
@@ -0,0 +1,6 @@
+[wrap-git]
+url=https://github.com/alex85k/wingetopt.git
+revision=head
+
+[provide]
+dependency_names = wingetopt
diff --git a/tests/jacktrip_tests.cpp b/tests/jacktrip_tests.cpp
new file mode 100644 (file)
index 0000000..d0eb2f4
--- /dev/null
@@ -0,0 +1,94 @@
+//*****************************************************************
+/*
+  JackTrip: A System for High-Quality Audio Network Performance
+  over the Internet
+
+  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
+  SoundWIRE group at CCRMA, Stanford University.
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation
+  files (the "Software"), to deal in the Software without
+  restriction, including without limitation the rights to use,
+  copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the
+  Software is furnished to do so, subject to the following
+  conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+  OTHER DEALINGS IN THE SOFTWARE.
+*/
+//*****************************************************************
+
+/**
+ * \file jacktrip_tests.cpp
+ * \author Juan-Pablo Caceres
+ * \date September 2008
+ */
+
+#include <QVector>
+#include <iostream>
+
+#include "JackTripThread.h"
+
+using std::cout;
+using std::endl;
+
+const int num_jacktrips = 5;
+const int base_port     = 4464;
+
+void main_tests(int argc, char** argv);
+void test_threads_server();
+void test_threads_client(const char* peer_address);
+
+void main_tests(int /*argc*/, char** argv)
+{
+    if (argv[1][0] == 's') {
+        test_threads_server();
+    } else if (argv[1][0] == 'c') {
+        test_threads_client("171.64.197.209");
+    }
+}
+
+// Test many servers running at the same time
+void test_threads_server()
+{
+    QVector<JackTripThread*> jacktrips;
+    jacktrips.resize(num_jacktrips);
+    int port_num;
+    for (int i = 0; i < num_jacktrips; i++) {
+        port_num = base_port + i * 10;
+        cout << "Port Number: " << port_num << endl;
+        jacktrips[i] = new JackTripThread(JackTrip::SERVER);
+        jacktrips[i]->setPort(port_num);
+        jacktrips[i]->start(QThread::NormalPriority);
+        // sleep(1);
+    }
+}
+
+// Test many servers running at the same time
+void test_threads_client(const char* peer_address)
+{
+    QVector<JackTripThread*> jacktrips;
+    jacktrips.resize(num_jacktrips);
+    int port_num;
+    for (int i = 0; i < num_jacktrips; i++) {
+        port_num = base_port + i * 10;
+        cout << "Port Number: " << port_num << endl;
+        jacktrips[i] = new JackTripThread(JackTrip::CLIENT);
+        jacktrips[i]->setPort(port_num);
+        jacktrips[i]->setPeerAddress(peer_address);
+        // sleep(1);
+        jacktrips[i]->start(QThread::NormalPriority);
+        // sleep(1);
+    }
+}
diff --git a/win/build_installer.bat b/win/build_installer.bat
new file mode 100755 (executable)
index 0000000..80f5a14
--- /dev/null
@@ -0,0 +1,75 @@
+@echo off\r
+setlocal EnableDelayedExpansion\r
+\r
+if not defined QTBINPATH (\r
+       for /f "delims=" %%a in ('dir /b C:\Qt\5*') do set QTVERSION=%%a\r
+       for /f "delims=" %%a in ('dir /b C:\Qt\!QTVERSION!\min*') do set QTBINPATH=%%a\r
+       set QTBINPATH=C:\Qt\!QTVERSION!\!QTBINPATH!\bin\r
+)\r
+if not defined QTLIBPATH (\r
+       for /f "delims=" %%a in ('dir /b C:\Qt\Tools\min*') do set QTLIBPATH=%%a\r
+       set QTLIBPATH=C:\Qt\Tools\!QTLIBPATH!\bin\r
+)\r
+if not defined WIXPATH (\r
+       for /f "delims=" %%a in ('dir /b "C:\Program Files (x86)\Wix Toolset*"') do set WIXPATH=%%a\r
+       set WIXPATH=C:\Program Files ^(x86^)\!WIXPATH!\bin\r
+)\r
+if not defined SSLPATH (set SSLPATH=C:\Qt\Tools\OpenSSL\Win_x64\bin)\r
+if not defined RTAUDIOLIB (set RTAUDIOLIB="C:\Program Files (x86)\RtAudio\bin\librtaudio.dll")\r
+\r
+set PATH=%PATH%;%WIXPATH%\r
+del deploy /s /q\r
+rmdir deploy /s /q\r
+mkdir deploy\r
+\r
+copy ..\LICENSE.md deploy\\r
+xcopy ..\LICENSES deploy\LICENSES\\r
+\r
+REM create RTF file with licenses' text\r
+set LICENSEPATH=deploy\license.rtf\r
+echo {\rtf1\ansi\deff0 {\fonttbl {\f0 Calibri;}} \f0\fs22>%LICENSEPATH%\r
+for %%f in (..\LICENSE.md ..\LICENSES\MIT.txt ..\LICENSES\GPL-3.0.txt ..\LICENSES\LGPL-3.0-only.txt) do (\r
+  for /f "delims=" %%x in ('type %%f') do (\r
+    echo %%x\line>>%LICENSEPATH%\r
+  )\r
+  echo \par >>%LICENSEPATH%\r
+)\r
+echo }>>%LICENSEPATH%\r
+\r
+copy dialog.bmp deploy\\r
+if exist ..\builddir\release\jacktrip.exe (set JACKTRIP=..\builddir\release\jacktrip.exe) else (set JACKTRIP=..\builddir\jacktrip.exe)\r
+copy %JACKTRIP% deploy\\r
+cd deploy\r
+set "WIXDEFINES="\r
+for /f "tokens=*" %%a in ('%QTLIBPATH%\objdump -p jacktrip.exe ^| findstr Qt5Core.dll') do set DYNAMIC_QT=%%a\r
+if defined DYNAMIC_QT (\r
+       echo Including Qt Files\r
+       %QTBINPATH%\windeployqt jacktrip.exe\r
+       copy "%QTLIBPATH%\libgcc_s_seh-1.dll" .\\r
+       copy "%QTLIBPATH%\libstdc++-6.dll" .\\r
+       copy "%QTLIBPATH%\libwinpthread-1.dll" .\\r
+       copy "%SSLPATH%\libcrypto-1_1-x64.dll" .\\r
+       copy "%SSLPATH%\libssl-1_1-x64.dll" .\\r
+       set WIXDEFINES=%WIXDEFINES% -ddynamic\r
+)\r
+for /f "tokens=*" %%a in ('%QTLIBPATH%\objdump -p jacktrip.exe ^| findstr librtaudio.dll') do set RTAUDIO=%%a\r
+if defined RTAUDIO (\r
+       echo Including librtaudio\r
+       copy %RTAUDIOLIB% .\\r
+       set WIXDEFINES=%WIXDEFINES% -drtaudio\r
+)\r
+\r
+copy ..\jacktrip.wxs .\\r
+copy ..\files.wxs .\\r
+.\jacktrip --test-gui\r
+if %ERRORLEVEL% NEQ 0 (\r
+       echo You need to build jacktrip with gui support to build the installer.\r
+       exit /b 1\r
+)\r
+rem Get our version number\r
+for /f "tokens=*" %%a in ('.\jacktrip -v ^| findstr VERSION') do for %%b in (%%~a) do set VERSION=%%b\r
+for /f "tokens=1 delims=-" %%a in ("%VERSION%") do set VERSION=%%a\r
+echo Version=%VERSION%\r
+candle.exe -dVersion=%VERSION%%WIXDEFINES% jacktrip.wxs files.wxs\r
+light.exe -ext WixUIExtension -o JackTrip.msi jacktrip.wixobj files.wixobj\r
+endlocal\r
diff --git a/win/dialog.bmp b/win/dialog.bmp
new file mode 100644 (file)
index 0000000..f751877
Binary files /dev/null and b/win/dialog.bmp differ
diff --git a/win/files.wxs b/win/files.wxs
new file mode 100644 (file)
index 0000000..94c3a3c
--- /dev/null
@@ -0,0 +1,255 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">\r
+    <Fragment>\r
+        <DirectoryRef Id="INSTALLDIR">\r
+            <Component Id="cmpE6579DC78E167F46AB23E0BE3EAA58CE" Guid="27BFCC7D-F4A8-4F71-8A2B-00A8BC74B106">\r
+                <File Id="fil5E6E1243EAE085FE802B6D64690357B0" KeyPath="yes" Source="SourceDir\jacktrip.exe" />\r
+                <Shortcut Id="startmenuJackTrip" Directory="ProgramMenuDir" Name="JackTrip"\r
+                    WorkingDirectory="INSTALLDIR" Icon="jacktrip.exe" IconIndex="0" Advertise="yes" />\r
+            </Component>\r
+            <Component Id="cmp52FE9CFF214054652C281C37201305EC" Guid="{158D5247-525B-417F-B12B-48F13CD7E414}">\r
+                <File Id="fil8AF433A253A49035CB32EA6F957BF7D4" KeyPath="yes" Source="SourceDir\LICENSE.md" />\r
+            </Component>\r
+            <Directory Id="LICENSESDIR" Name="LICENSES">\r
+                <Component Id="cmpA07F2DC814BECD1E5F3FC36DC47718E5" Guid="{36E317A7-BA26-4E2B-99CD-0728CD8779DD}">\r
+                    <File Id="fil39657C9CD79E70F8B3033F0CF1D035A1" KeyPath="yes" Source="SourceDir\LICENSES\LGPL-3.0-only.txt" />\r
+                </Component>\r
+                <Component Id="cmpBF7FA1E27DF091A3CCFA1CD7B7CD94BA" Guid="{2D555037-9C09-4042-8F0C-C6EBAB80681A}">\r
+                    <File Id="fil496C76DCE2246C589E09AC68BCFDFB32" KeyPath="yes" Source="SourceDir\LICENSES\MIT.txt" />\r
+                </Component>\r
+                <Component Id="cmpF915A8D749EFFA98CD8DD582A7C82614" Guid="{A3C72CE1-0570-497B-A84F-F21C53771ABC}">\r
+                    <File Id="filCCF13ED800A4C7B438EC52A50C3A6755" KeyPath="yes" Source="SourceDir\LICENSES\GPL-3.0.txt" />\r
+                </Component>\r
+              </Directory>\r
+<?ifdef rtaudio?>\r
+            <Component Id="cmpD683260746BC875AE3BDED667AA8F954" Guid="20A867E8-36B6-49E3-A1DA-76CFCE967908">\r
+                <File Id="filA7BCB2CDD7D00C9DFB32AEB94F294425" KeyPath="yes" Source="SourceDir\librtaudio.dll" />\r
+            </Component>\r
+<?endif?>\r
+<?ifdef dynamic?>\r
+            <Component Id="cmpF83098612A5B11C5398DBA3894ED590A" Guid="6A0A67A9-3318-4CFB-BC07-5AF3FF7B7E87">\r
+                <File Id="fil526FA994C1850220CFA7BD7FCD995C32" KeyPath="yes" Source="SourceDir\D3Dcompiler_47.dll" />\r
+            </Component>\r
+            <Component Id="cmpB60B52D038613C3F20F84A0E1C83D4D4" Guid="62E3CBE5-9787-4A5C-B6CD-B867781773EE">\r
+                <File Id="fil09D765981E2E493119D2DBD2DA179B9D" KeyPath="yes" Source="SourceDir\libcrypto-1_1-x64.dll" />\r
+            </Component>\r
+            <Component Id="cmp5DDCF0CE56D406D1B8B1F93E988AED6B" Guid="4346C308-2912-4CAF-B01B-1FB85781DAD0">\r
+                <File Id="fil0F4CD3729AF07C1C460E292E0F081D0A" KeyPath="yes" Source="SourceDir\libEGL.dll" />\r
+            </Component>\r
+            <Component Id="cmpDEFDDDBEBEA7255D07EE4400F2CDA2FF" Guid="904EB309-B381-443D-A064-4C2669E8E66E">\r
+                <File Id="fil2ECEB8B8BE6121A2C5659BA0F64D92FC" KeyPath="yes" Source="SourceDir\libgcc_s_seh-1.dll" />\r
+            </Component>\r
+            <Component Id="cmpB0CFEB9FF932521D6A75B6BE6F8D644F" Guid="73A8C873-FBDB-4BC5-BB74-2F82619DC3EC">\r
+                <File Id="fil736048FE57EC840EA5DCE88625C38E8D" KeyPath="yes" Source="SourceDir\libGLESv2.dll" />\r
+            </Component>\r
+            <Component Id="cmp809509D62BD9EA848EF243F03D83758F" Guid="FE4AFCE9-7DE1-4A82-A96E-42C8B93E04C7">\r
+                <File Id="filCE00A8B273087E758109FEC2AC699195" KeyPath="yes" Source="SourceDir\libssl-1_1-x64.dll" />\r
+            </Component>\r
+            <Component Id="cmp57DDA83E372188A5B760684B961DE685" Guid="96741680-04B3-4A4A-8D55-08C48D6B2201">\r
+                <File Id="filF57E66845C852C7C1EFFE6996027BE3C" KeyPath="yes" Source="SourceDir\libstdc++-6.dll" />\r
+            </Component>\r
+            <Component Id="cmpF76D0CD1138260DB167395B86D0011CF" Guid="88B4D808-2CD2-40E0-9BC4-51093AFD3D61">\r
+                <File Id="fil8C56E6114C3ACED0DF58456A08DC0437" KeyPath="yes" Source="SourceDir\libwinpthread-1.dll" />\r
+            </Component>\r
+            <Component Id="cmpEA16414E09FD1D5068139520966B49EB" Guid="9B14A007-CA41-4C45-BE9E-0B1067DD5311">\r
+                <File Id="filFC8C908E3AD35E8090AFF39C9B0FB744" KeyPath="yes" Source="SourceDir\opengl32sw.dll" />\r
+            </Component>\r
+            <Component Id="cmp01229088A6F1DEA1BE391E6E7CC3D3EE" Guid="9A610B9C-6322-4045-9C4B-910FFBA38502">\r
+                <File Id="filAD80F4724AAE3D8B0682F5982CC2548D" KeyPath="yes" Source="SourceDir\Qt5Core.dll" />\r
+            </Component>\r
+            <Component Id="cmp1658AEC83DA2CDD0D93D5BAAABBEAD46" Guid="9D7923EE-3849-4FCE-A0C4-A2254AD769D3">\r
+                <File Id="fil7E727B350B33C4EEEFE406E27624E057" KeyPath="yes" Source="SourceDir\Qt5Gui.dll" />\r
+            </Component>\r
+            <Component Id="cmp2DE804C107C75B0C71470A93647D09B5" Guid="F8E604E4-A6B2-444D-9F1F-2D86230D5585">\r
+                <File Id="filD86C7802D20EDF450E8B03BC177BA71F" KeyPath="yes" Source="SourceDir\Qt5Network.dll" />\r
+            </Component>\r
+            <Component Id="cmp82912105030EA0D2D7550CF8AC5677F6" Guid="17A8DAEB-44BD-451C-BEEE-C3C2EF883516">\r
+                <File Id="fil6DA129DEAE11F969B17E1886F9AF9AA0" KeyPath="yes" Source="SourceDir\Qt5Svg.dll" />\r
+            </Component>\r
+            <Component Id="cmp975651B71289ACA70B3EB154C08A27F0" Guid="FD612706-4DF7-439B-B82B-57EFA2657F84">\r
+                <File Id="filE89B28CF105C7A7691C046E6516D540E" KeyPath="yes" Source="SourceDir\Qt5Widgets.dll" />\r
+            </Component>\r
+            <Directory Id="dirFF9CCFA394406B344C7FF767066C0809" Name="bearer">\r
+                <Component Id="cmp3CE5AF7CB2F8B2689D2096769883BC56" Guid="FD4AB5B8-4F89-4C08-819B-58A7E8F6360A">\r
+                    <File Id="fil94C33B546082B4DF43813FFB7569FBF6" KeyPath="yes" Source="SourceDir\bearer\qgenericbearer.dll" />\r
+                </Component>\r
+            </Directory>\r
+            <Directory Id="dirB4D909CA5877E8EBEB32B83B2D15F595" Name="iconengines">\r
+                <Component Id="cmp1AAFF160C8E04AD945D74CA884667ABC" Guid="F9CAC368-2789-40F4-ADB8-0EDF377306DF">\r
+                    <File Id="filB4B2363760DE489E24EBDBD0BC837FDE" KeyPath="yes" Source="SourceDir\iconengines\qsvgicon.dll" />\r
+                </Component>\r
+            </Directory>\r
+            <Directory Id="dir60B76952C227590F998DC42F548339BE" Name="imageformats">\r
+                <Component Id="cmp02252B1C1976959CFEE7FA11B6E36C4C" Guid="67FB3C37-C4EB-404B-84E0-2B85288C9A46">\r
+                    <File Id="fil646F5D906D2B2A321C0C481D1D22C9C7" KeyPath="yes" Source="SourceDir\imageformats\qgif.dll" />\r
+                </Component>\r
+                <Component Id="cmp62CBFF830BF239A4E376FAE29937AFAB" Guid="FCFFB090-6600-4F92-9F71-A9EFDA3F5F05">\r
+                    <File Id="fil2132CC3E0278FB6088A48B8A3C120D44" KeyPath="yes" Source="SourceDir\imageformats\qicns.dll" />\r
+                </Component>\r
+                <Component Id="cmpD9DF9496C7453F1AA6C20CD4A1C94ED7" Guid="6EAE06EC-8FC6-4075-8B7D-2E5E2ECDBC1D">\r
+                    <File Id="fil0A4C8F6CF0C62302928ED23A10F88E84" KeyPath="yes" Source="SourceDir\imageformats\qico.dll" />\r
+                </Component>\r
+                <Component Id="cmp0E8940C551429DC79C890130F6D10B6D" Guid="4E9F8DE6-5789-421B-8299-04C8F95F6804">\r
+                    <File Id="fil080B2419A3875B7348050418715B59D5" KeyPath="yes" Source="SourceDir\imageformats\qjpeg.dll" />\r
+                </Component>\r
+                <Component Id="cmpC6FCE143A8E5EAFEA6119E94128459C6" Guid="E22AD241-DA8F-4016-A34B-3DA0ABB77AE9">\r
+                    <File Id="filE6DE80FB6D1ADCBBC8D5665DCF3A4674" KeyPath="yes" Source="SourceDir\imageformats\qsvg.dll" />\r
+                </Component>\r
+                <Component Id="cmpFCC4763BEDEA49F63E8D8E3A18E86329" Guid="D3ABC0A1-CE5F-4ABB-8B15-E630FCF1C9B1">\r
+                    <File Id="filAABDE938CE7225264D2AD6E5B85F0F35" KeyPath="yes" Source="SourceDir\imageformats\qtga.dll" />\r
+                </Component>\r
+                <Component Id="cmpF278C1175D7FB53021C0126B8F155FC2" Guid="24C00F19-08E6-40E6-913E-AD54EFB81AB7">\r
+                    <File Id="fil102CCD3441784435E39937C763D95F2F" KeyPath="yes" Source="SourceDir\imageformats\qtiff.dll" />\r
+                </Component>\r
+                <Component Id="cmp608F60C2BD04F2C37AB51C3211ABF615" Guid="8A88549A-3B1F-4A94-B721-7ED99998CA95">\r
+                    <File Id="fil8698D33404DE182991C30D32BA39A5EC" KeyPath="yes" Source="SourceDir\imageformats\qwbmp.dll" />\r
+                </Component>\r
+                <Component Id="cmpE6323C810986405043F219CECD6B6C10" Guid="7194531B-2B4C-4DB0-8BED-B89929695F17">\r
+                    <File Id="filB9C6E81C6DBC26365A8C44CD0A36C49F" KeyPath="yes" Source="SourceDir\imageformats\qwebp.dll" />\r
+                </Component>\r
+            </Directory>\r
+            <Directory Id="dir623D6610C7C3C018A72040463AD22773" Name="platforms">\r
+                <Component Id="cmp9132FD413972F732967B8BC075BC2781" Guid="0DAA1BEB-EA44-4EEC-BCC8-22CE871FC519">\r
+                    <File Id="fil835F5A10B680242272F647CE0A82B16C" KeyPath="yes" Source="SourceDir\platforms\qwindows.dll" />\r
+                </Component>\r
+            </Directory>\r
+            <Directory Id="dirF1334AF64D097D9920D6F285D2DE292C" Name="styles">\r
+                <Component Id="cmp52840D209B2AC1DC45A29A6BA5A75FF8" Guid="3FA00436-A967-45AB-8871-A6DA384044CE">\r
+                    <File Id="fil84E6446D9ECFA487C5A2EC4752E07F04" KeyPath="yes" Source="SourceDir\styles\qwindowsvistastyle.dll" />\r
+                </Component>\r
+            </Directory>\r
+            <Directory Id="dirF1C5FA08924D46D2A43D5134DF70C0A8" Name="translations">\r
+                <Component Id="cmpBCDC6995284E75B9A24E4646E6117744" Guid="51A3610B-4AE8-4020-926E-80B77B650E52">\r
+                    <File Id="fil694FD3DFB9C088844BF9929014423509" KeyPath="yes" Source="SourceDir\translations\qt_ar.qm" />\r
+                </Component>\r
+                <Component Id="cmp3B3D2ADEE08668758CB9FDB1D243AA11" Guid="E84288C8-80B5-43C0-ABC1-13720B58F806">\r
+                    <File Id="fil0877F2432B761D0289C5DB92EC1E528E" KeyPath="yes" Source="SourceDir\translations\qt_bg.qm" />\r
+                </Component>\r
+                <Component Id="cmpDAE87E8CC29C30A200A5D17D81DF1DE7" Guid="BC72F77D-4D7F-4AFD-BC4F-0F9E337182A9">\r
+                    <File Id="fil36E8A56D7DAEC62D31CEA91730D42174" KeyPath="yes" Source="SourceDir\translations\qt_ca.qm" />\r
+                </Component>\r
+                <Component Id="cmp719D62CCB63A2C08F22335557CBAB533" Guid="084DAFF0-3499-4D2E-9685-D0F7573A0723">\r
+                    <File Id="fil5ECAF3F9F1940369AA594EE12825D0FB" KeyPath="yes" Source="SourceDir\translations\qt_cs.qm" />\r
+                </Component>\r
+                <Component Id="cmp8BDD412901C153FC8A2BF7335835AC78" Guid="ED469E4F-52A1-4BDC-83EA-304D779025ED">\r
+                    <File Id="fil035B9FC36AE44B63202E6201D2A9608E" KeyPath="yes" Source="SourceDir\translations\qt_da.qm" />\r
+                </Component>\r
+                <Component Id="cmp56040A1BBEBE8A547F7D6672326FF4EE" Guid="F0F32818-EB50-415C-8302-B3BCFA3D1A5F">\r
+                    <File Id="fil0AA794E087CE581F4CA99D75C295092D" KeyPath="yes" Source="SourceDir\translations\qt_de.qm" />\r
+                </Component>\r
+                <Component Id="cmp42D4B2D8A4C91F9ED463DA42F3895E27" Guid="1444EE4B-AD59-4C33-9B17-3B21B132DAA9">\r
+                    <File Id="filAD08CEBCD34B84E90701D6248FDB5FA9" KeyPath="yes" Source="SourceDir\translations\qt_en.qm" />\r
+                </Component>\r
+                <Component Id="cmpB92DA15530102518B1B98DBF1DAC135D" Guid="10E7AA9E-7DC7-45E5-A52C-9B33DD7CD157">\r
+                    <File Id="filB05A80E55C2FCBFE9999B66E309F0312" KeyPath="yes" Source="SourceDir\translations\qt_es.qm" />\r
+                </Component>\r
+                <Component Id="cmp7210C3ACD533D6A934BD5977AB16AF71" Guid="8D242F4F-56C4-4BBD-82EF-7EC103AB4445">\r
+                    <File Id="fil4B803C16DFCB1C5EA4D308AFD35049E3" KeyPath="yes" Source="SourceDir\translations\qt_fi.qm" />\r
+                </Component>\r
+                <Component Id="cmp0643210AD0A541FA765CE55469F22FBB" Guid="3DAD67C2-7EBC-4FE2-9375-ED04F44B95C2">\r
+                    <File Id="fil65E050731B55F3764817B70B50D1F483" KeyPath="yes" Source="SourceDir\translations\qt_fr.qm" />\r
+                </Component>\r
+                <Component Id="cmpBB98B3096730FFFE87E708A6291ED47C" Guid="4FC0CA17-91C9-4207-B18F-0D3676A4EAA8">\r
+                    <File Id="fil38E65580D7E2598A2AB22B21A55AE808" KeyPath="yes" Source="SourceDir\translations\qt_gd.qm" />\r
+                </Component>\r
+                <Component Id="cmp3666ECDFA614EA095AF7310AECCD44B7" Guid="A4ADC90F-ED1F-49EC-9595-226C90767318">\r
+                    <File Id="filD812B4BB739798D5C3BF25BEFBFBA938" KeyPath="yes" Source="SourceDir\translations\qt_he.qm" />\r
+                </Component>\r
+                <Component Id="cmpC4FA2671255E7459BD46070D88B76FF1" Guid="427500F9-DE40-499D-AA91-34944AD8AD45">\r
+                    <File Id="fil750345F0F25CC28174362BF42A332BFA" KeyPath="yes" Source="SourceDir\translations\qt_hu.qm" />\r
+                </Component>\r
+                <Component Id="cmp8D644C0D5E80E34EBCB6FC3643C879AF" Guid="FA35CBD4-A861-494E-AABC-76262872F717">\r
+                    <File Id="filF6634E490610EB73E2D852D47B43255E" KeyPath="yes" Source="SourceDir\translations\qt_it.qm" />\r
+                </Component>\r
+                <Component Id="cmpA8DDE2BD9E1AB00C9631DE447CBAA11D" Guid="15D64C1E-B407-4531-9684-A785DAF53421">\r
+                    <File Id="fil493967A00B1FFB8D251F7A844D53A64A" KeyPath="yes" Source="SourceDir\translations\qt_ja.qm" />\r
+                </Component>\r
+                <Component Id="cmp23B3657EE14B0ED7D00B271AFF81187C" Guid="6FC090EB-D1CC-423E-9527-DBDF4E7A4B8F">\r
+                    <File Id="fil5A7EE1B788293556A515EAFFC95747DB" KeyPath="yes" Source="SourceDir\translations\qt_ko.qm" />\r
+                </Component>\r
+                <Component Id="cmp2D105F39980CF93A40405E25755346BB" Guid="79E81F16-F627-4CD1-BB41-5C52A141BE5F">\r
+                    <File Id="fil17B2A1B774381BBA3BF85AF1FFB636AA" KeyPath="yes" Source="SourceDir\translations\qt_lv.qm" />\r
+                </Component>\r
+                <Component Id="cmpC3CB042567F53DD612D309E9CA2E10A6" Guid="CED83F6F-60ED-4321-94B6-7917D1DB232C">\r
+                    <File Id="filC674EE989D2B9719C388F537FC8EFFCF" KeyPath="yes" Source="SourceDir\translations\qt_pl.qm" />\r
+                </Component>\r
+                <Component Id="cmp43D57F897A909679308EFC03849D7E2E" Guid="8E42022B-B599-4ABD-8D30-F5E378FE60FE">\r
+                    <File Id="filADA551AF628F8CBA7E3D06EF76F2713A" KeyPath="yes" Source="SourceDir\translations\qt_ru.qm" />\r
+                </Component>\r
+                <Component Id="cmpF5EA7E37332E95C614BD2D7EAA933E5D" Guid="6516FDA0-5035-420D-AADF-41D1E3735EDA">\r
+                    <File Id="fil49E3CA421049811064612E40502A6147" KeyPath="yes" Source="SourceDir\translations\qt_sk.qm" />\r
+                </Component>\r
+                <Component Id="cmpA214B663A372012F5DCBA6A5CDAE421D" Guid="790AF12A-1970-4B96-BFAD-925734F604EB">\r
+                    <File Id="fil1380C741E2DBC1F60AA4DC32D66B1E6C" KeyPath="yes" Source="SourceDir\translations\qt_uk.qm" />\r
+                </Component>\r
+                <Component Id="cmpFDB70117D8E46EB188997470A3793B5D" Guid="EA2F54B9-EE49-4426-A2EF-EDDF3CAC83FD">\r
+                    <File Id="fil9085627E4E33630ABCDB62A5CC05B794" KeyPath="yes" Source="SourceDir\translations\qt_zh_TW.qm" />\r
+                </Component>\r
+            </Directory>\r
+<?endif?>\r
+        </DirectoryRef>\r
+    </Fragment>\r
+    <Fragment>\r
+        <ComponentGroup Id="jacktrip">\r
+            <ComponentRef Id="cmpE6579DC78E167F46AB23E0BE3EAA58CE" />\r
+            <ComponentRef Id="cmp52FE9CFF214054652C281C37201305EC" />\r
+            <ComponentRef Id="cmpA07F2DC814BECD1E5F3FC36DC47718E5" />\r
+            <ComponentRef Id="cmpBF7FA1E27DF091A3CCFA1CD7B7CD94BA" />\r
+            <ComponentRef Id="cmpF915A8D749EFFA98CD8DD582A7C82614" />\r
+<?ifdef rtaudio?>\r
+            <ComponentRef Id="cmpD683260746BC875AE3BDED667AA8F954" />\r
+<?endif?>\r
+<?ifdef dynamic?>\r
+            <ComponentRef Id="cmpF83098612A5B11C5398DBA3894ED590A" />\r
+            <ComponentRef Id="cmpB60B52D038613C3F20F84A0E1C83D4D4" />\r
+            <ComponentRef Id="cmp5DDCF0CE56D406D1B8B1F93E988AED6B" />\r
+            <ComponentRef Id="cmpDEFDDDBEBEA7255D07EE4400F2CDA2FF" />\r
+            <ComponentRef Id="cmpB0CFEB9FF932521D6A75B6BE6F8D644F" />\r
+            <ComponentRef Id="cmp809509D62BD9EA848EF243F03D83758F" />\r
+            <ComponentRef Id="cmp57DDA83E372188A5B760684B961DE685" />\r
+            <ComponentRef Id="cmpF76D0CD1138260DB167395B86D0011CF" />\r
+            <ComponentRef Id="cmpEA16414E09FD1D5068139520966B49EB" />\r
+            <ComponentRef Id="cmp01229088A6F1DEA1BE391E6E7CC3D3EE" />\r
+            <ComponentRef Id="cmp1658AEC83DA2CDD0D93D5BAAABBEAD46" />\r
+            <ComponentRef Id="cmp2DE804C107C75B0C71470A93647D09B5" />\r
+            <ComponentRef Id="cmp82912105030EA0D2D7550CF8AC5677F6" />\r
+            <ComponentRef Id="cmp975651B71289ACA70B3EB154C08A27F0" />\r
+            <ComponentRef Id="cmp3CE5AF7CB2F8B2689D2096769883BC56" />\r
+            <ComponentRef Id="cmp1AAFF160C8E04AD945D74CA884667ABC" />\r
+            <ComponentRef Id="cmp02252B1C1976959CFEE7FA11B6E36C4C" />\r
+            <ComponentRef Id="cmp62CBFF830BF239A4E376FAE29937AFAB" />\r
+            <ComponentRef Id="cmpD9DF9496C7453F1AA6C20CD4A1C94ED7" />\r
+            <ComponentRef Id="cmp0E8940C551429DC79C890130F6D10B6D" />\r
+            <ComponentRef Id="cmpC6FCE143A8E5EAFEA6119E94128459C6" />\r
+            <ComponentRef Id="cmpFCC4763BEDEA49F63E8D8E3A18E86329" />\r
+            <ComponentRef Id="cmpF278C1175D7FB53021C0126B8F155FC2" />\r
+            <ComponentRef Id="cmp608F60C2BD04F2C37AB51C3211ABF615" />\r
+            <ComponentRef Id="cmpE6323C810986405043F219CECD6B6C10" />\r
+            <ComponentRef Id="cmp9132FD413972F732967B8BC075BC2781" />\r
+            <ComponentRef Id="cmp52840D209B2AC1DC45A29A6BA5A75FF8" />\r
+            <ComponentRef Id="cmpBCDC6995284E75B9A24E4646E6117744" />\r
+            <ComponentRef Id="cmp3B3D2ADEE08668758CB9FDB1D243AA11" />\r
+            <ComponentRef Id="cmpDAE87E8CC29C30A200A5D17D81DF1DE7" />\r
+            <ComponentRef Id="cmp719D62CCB63A2C08F22335557CBAB533" />\r
+            <ComponentRef Id="cmp8BDD412901C153FC8A2BF7335835AC78" />\r
+            <ComponentRef Id="cmp56040A1BBEBE8A547F7D6672326FF4EE" />\r
+            <ComponentRef Id="cmp42D4B2D8A4C91F9ED463DA42F3895E27" />\r
+            <ComponentRef Id="cmpB92DA15530102518B1B98DBF1DAC135D" />\r
+            <ComponentRef Id="cmp7210C3ACD533D6A934BD5977AB16AF71" />\r
+            <ComponentRef Id="cmp0643210AD0A541FA765CE55469F22FBB" />\r
+            <ComponentRef Id="cmpBB98B3096730FFFE87E708A6291ED47C" />\r
+            <ComponentRef Id="cmp3666ECDFA614EA095AF7310AECCD44B7" />\r
+            <ComponentRef Id="cmpC4FA2671255E7459BD46070D88B76FF1" />\r
+            <ComponentRef Id="cmp8D644C0D5E80E34EBCB6FC3643C879AF" />\r
+            <ComponentRef Id="cmpA8DDE2BD9E1AB00C9631DE447CBAA11D" />\r
+            <ComponentRef Id="cmp23B3657EE14B0ED7D00B271AFF81187C" />\r
+            <ComponentRef Id="cmp2D105F39980CF93A40405E25755346BB" />\r
+            <ComponentRef Id="cmpC3CB042567F53DD612D309E9CA2E10A6" />\r
+            <ComponentRef Id="cmp43D57F897A909679308EFC03849D7E2E" />\r
+            <ComponentRef Id="cmpF5EA7E37332E95C614BD2D7EAA933E5D" />\r
+            <ComponentRef Id="cmpA214B663A372012F5DCBA6A5CDAE421D" />\r
+            <ComponentRef Id="cmpFDB70117D8E46EB188997470A3793B5D" />\r
+<?endif?>\r
+        </ComponentGroup>\r
+    </Fragment>\r
+</Wix>\r
diff --git a/win/jacktrip.ico b/win/jacktrip.ico
new file mode 100644 (file)
index 0000000..6774f3b
Binary files /dev/null and b/win/jacktrip.ico differ
diff --git a/win/jacktrip.wxs b/win/jacktrip.wxs
new file mode 100644 (file)
index 0000000..f34dab9
--- /dev/null
@@ -0,0 +1,43 @@
+<?xml version='1.0' encoding='windows-1252'?>\r
+<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>\r
+    <Product Name='JackTrip' Manufacturer='JackTrip'\r
+        Id='*'\r
+        UpgradeCode='70450e42-8a91-4c28-8f00-52c6b8e86e37'\r
+        Language='1033' Codepage='1252' Version='$(var.Version)'>\r
+\r
+        <Package Id='*' Keywords='Installer' Description='JackTrip Installer'\r
+            Comments='Developed by SoundWIRE Group at CCRMA, Stanford' Manufacturer='JackTrip'\r
+            InstallerVersion='100' Languages='1033' Compressed='yes' SummaryCodepage='1252' />\r
+        <Media Id='1' Cabinet='JackTrip.cab' EmbedCab='yes' DiskPrompt='Disk 1' />\r
+        <Property Id='DiskPrompt' Value='JackTrip Installer File' />\r
+        <MajorUpgrade AllowDowngrades="no" DowngradeErrorMessage="A newer version is already installed."\r
+            AllowSameVersionUpgrades="no" />\r
+\r
+        <Directory Id='TARGETDIR' Name='SourceDir'>\r
+            <Directory Id='ProgramFilesFolder' Name='PFiles'>\r
+                <Directory Id='INSTALLDIR' Name='JackTrip'>\r
+                </Directory>\r
+            </Directory>\r
+            <Directory Id='ProgramMenuFolder' Name='Programs'>\r
+                <Directory Id='ProgramMenuDir' Name='JackTrip'>\r
+                    <Component Id="ProgramMenuDir" Guid="2f25e96a-47a5-4eca-b367-a78ce536d9b9">\r
+                        <RemoveFolder Id='ProgramMenuDir' On='uninstall' />\r
+                        <RegistryValue Root='HKCU' Key='Software\[Manufacturer]\[ProductName]' Type='string' Value='' KeyPath='yes' />\r
+                    </Component>\r
+                </Directory>\r
+            </Directory>\r
+        </Directory>\r
+\r
+        <Feature Id='NormalInstall' Title='JackTrip' Description='Standard Install'\r
+            Level='1' ConfigurableDirectory='INSTALLDIR'>\r
+            <ComponentGroupRef Id='jacktrip' />\r
+            <ComponentRef Id='ProgramMenuDir' />\r
+        </Feature>\r
+\r
+        <WixVariable Id='WixUIDialogBmp' Value='dialog.bmp' />\r
+        <WixVariable Id='WixUILicenseRtf' Value='license.rtf' />\r
+        <Property Id='WIXUI_INSTALLDIR' Value='INSTALLDIR' />\r
+        <UIRef Id='WixUI_InstallDir' />\r
+        <Icon Id='jacktrip.exe' SourceFile='jacktrip.exe' />\r
+    </Product>\r
+</Wix>\r
diff --git a/win/qjacktrip.rc b/win/qjacktrip.rc
new file mode 100644 (file)
index 0000000..9516335
--- /dev/null
@@ -0,0 +1 @@
+IDI_ICON1 ICON "jacktrip.ico"