set(rtaudio TRUE)
set(weakjack TRUE)
set(novs FALSE)
+set(vsftux FALSE)
set(noupdater FALSE)
set(psi FALSE)
set(QtVersion "5")
set(QRC_FILE "src/gui/qjacktrip.qrc")
endif ()
+if (vsftux)
+ add_compile_definitions(VS_FTUX)
+endif ()
+
if (noupdater)
add_compile_definitions(NO_UPDATER)
endif ()
src/gui/vsWebSocket.cpp
src/gui/vsPermissions.cpp
src/gui/qjacktrip.qrc
+ src/Monitor.cpp
src/Volume.cpp
src/Tone.cpp
# Need to include this for AUTOMOC to do its thing
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.
Further information and instructions are available on https://jacktrip.github.io/jacktrip/.
+
+Please report any security concerns to vulnerabilities@jacktrip.org
# Parse command line options
clean=1
install=0
+jobs=1
CONFIG="DEFINES+=JACKTRIP_BUILD_INFO=\\\"$(git describe --tags)-$(git rev-parse --short HEAD)\\\""
-UNKNOWN_OPTIONS=
+UNKNOWN_OPTIONS=()
BUILD_RTAUDIO=0
RTAUDIO=0
NO_SYSTEM_RTAUDIO=0
PRO_FILE="../jacktrip.pro"
HELP_STR="usage:\n
-./build [noclean nojack rtaudio nogui novs static install [-config static]]\n\n
+./build [noclean nojack rtaudio nogui novs vsftux static install [-config static]]\n\n
options:\n
noclean - do not run \"make clean\" first\n
nojack - build without jack\n
no-system-rtaudio - use bundled RtAudio library even if it's available in the system\n
nogui - build without the gui\n
novs - build without Virtual Studio support\n
+vsftux - build with Virtual Studio first launch experience\n
noupdater - build without auto-update support\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
+ if [[ ${#UNKNOWN_OPTIONS[@]} -eq 0 ]]; then
case $1 in
noclean) clean=0 ;;
nojack)
echo "Building without Virtual Studio support"
CONFIG="-config novs $CONFIG"
;;
+ vsftux)
+ echo "Building with Virtual Studio first launch experience"
+ CONFIG="-config vsftux $CONFIG"
+ ;;
noupdater)
echo "Building without auto-update support"
CONFIG="-config noupdater $CONFIG"
echo "Will install JackTrip in system location"
install=1
;;
+ -j*)
+ jobs=$(echo $1 |sed 's,-j0*\([0-9]*\),\1,')
+ if [[ $jobs -le 1 ]]; then
+ jobs=1
+ fi
+ echo "Will build using $jobs make jobs"
+ ;;
-h|--help)
echo -e $HELP_STR; exit
;;
- *) UNKNOWN_OPTIONS="$UNKNOWN_OPTIONS $1" ;;
+ *) UNKNOWN_OPTIONS+=("$1") ;;
esac
shift
else
case $1 in
- *) UNKNOWN_OPTIONS="$UNKNOWN_OPTIONS $1" ;;
+ *) UNKNOWN_OPTIONS+=("$1") ;;
esac
shift
fi
set -e
# Build
-QCMDARGS=(-spec $QSPEC $CONFIG "$UNKNOWN_OPTIONS" $PRO_FILE)
echo "qmake command:"
-echo $QCMD ${QCMDARGS[@]}
+echo $QCMD -spec $QSPEC $CONFIG "${UNKNOWN_OPTIONS[@]}" $PRO_FILE
+$QCMD -spec $QSPEC $CONFIG "${UNKNOWN_OPTIONS[@]}" $PRO_FILE
if [[ $clean == 1 ]]; then
- $QCMD ${QCMDARGS[@]}
$MCMD clean
fi
-$QCMD ${QCMDARGS[@]}
-$MCMD release
+$MCMD -j$jobs release
if [[ "$install" == 1 ]]; then
echo "*** Installing JackTrip ***"
echo "We need elevated privileges to install JackTrip in the system location"
+- Version: "1.9.0"
+ Date: 2023-05-05
+ Description:
+ - (added) buffer strategy 4 to run PLC in audio callback
+ - (added) VS Mode - change audio devices while connected
+ - (added) universal binary for macOS
+ - (added) tooltips, sliders, and positioning of connected interface
+ - (added) emails for vulnerability reporting
+ - (added) local monitoring
+ - (added) VS mode - Error message when single studio limit reached
+ - (updated) regulator thread uses real-time priority
+ - (updated) VS mode - use buffer strategy 4
+ - (updated) VS mode - Default to PLC
+ - (updated) VS Mode - PLC auto queue has 5ms headroom
+ - (updated) Enforcing using the same ASIO device on Windows
+ - (updated) VS Mode - JTL builds hide the yes/no screen on first launch
+ - (updated) GHA - wait for static Qt builds rather than failing
+ - (updated) VS Mode - "all devices" is now "high latency"
+ - (updated) VS Mode - Warning text for non-ASIO Windows devices
+ - (updated) Faust-generate code moved out of headers
+ - (fixed) PLC bugs
+ - (fixed) VS Mode - changing devices while connected refreshes device lists
+ - (fixed) play test tone on Linux
+ - (fixed) static openssl on Linux
- Version: "1.8.1"
Date: 2023-03-29
Description:
--- /dev/null
+declare name "monitor";
+declare version "1.0";
+declare author "Dominick Hing, adapted from 'Volume Control' by Matt Horton";
+declare license "MIT Style STK-4.2";
+declare description "Volume Control Faust Plugin for JackTrip, based on Faust examples";
+
+
+import("stdfaust.lib");
+mute = checkbox("[1] Mute");
+gain(v) = v : ba.db2linear : si.smoo : _;
+gainVMute(v) = _ * gain(v), 0 : select2(mute) : _;
+zeroCutoff(v) = _ , 0 : select2(v == -40) : _;
+volume = hslider("[0] Volume", 0, -40, 0, 0.1);
+
+process = _,_ <: vgroup("Monitor", _ : gainVMute(volume) : zeroCutoff(volume)), _ : +;
QT += quickcontrols2
QT += svg
QT += websockets
+ vsftux {
+ DEFINES += VS_FTUX
+ }
}
noupdater|linux-g++|linux-g++-64 {
DEFINES += NO_UPDATER
# INCLUDEPATH+=/usr/include/stk
# LIBS += -L/usr/local/lib -ljack -lstk -lm
LIBS += -L/usr/local/lib -lm
+ QMAKE_CXXFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden
weakjack {
message(Building with weak linking of JACK)
INCLUDEPATH += externals/weakjack
src/Regulator.h \
src/Reverb.h \
src/Meter.h \
+ src/Monitor.h \
src/Volume.h \
src/Tone.h \
src/StereoToMono.h \
src/Regulator.cpp \
src/Reverb.cpp \
src/Meter.cpp \
+ src/Monitor.cpp \
src/StereoToMono.cpp \
src/Volume.cpp \
src/Tone.cpp \
--- /dev/null
+# JackTrip is a multi-machine audio system used for network music performance over the Internet.
+
+See LICENSE.md for license information.
+
+To install JackTrip as a Linux desktop application:
+
+```
+sudo cp jacktrip /usr/local/bin
+mkdir -p $HOME/.local/share/applications $HOME/.local/share/icons/hicolor/scalable/apps $HOME/.local/share/icons/hicolor/48x48/apps
+cp org.jacktrip.JackTrip.svg $HOME/.local/share/icons/hicolor/scalable/apps/
+cp org.jacktrip.JackTrip.png $HOME/.local/share/icons/hicolor/48x48/apps/
+desktop-file-install --dir=$HOME/.local/share/applications org.jacktrip.JackTrip.desktop
+update-desktop-database $HOME/.local/share/applications
+```
+
+Further information and instructions are available on https://jacktrip.github.io/jacktrip/.
+
+Please report any security concerns to vulnerabilities@jacktrip.org
--- /dev/null
+diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h
+index 43b5bf6..7160825 100644
+--- a/src/network/ssl/qsslsocket_openssl_symbols_p.h
++++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h
+@@ -237,7 +237,6 @@
+ EVP_PKEY_CTX *q_EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e);
+ void q_EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx);
+ int q_EVP_PKEY_param_check(EVP_PKEY_CTX *ctx);
+-int q_EVP_PKEY_base_id(EVP_PKEY *a);
+ int q_RSA_bits(RSA *a);
+ Q_AUTOTEST_EXPORT int q_OPENSSL_sk_num(OPENSSL_STACK *a);
+ Q_AUTOTEST_EXPORT void q_OPENSSL_sk_pop_free(OPENSSL_STACK *a, void (*b)(void *));
+@@ -383,6 +382,17 @@
+ int q_EC_GROUP_get_degree(const EC_GROUP* g);
+ #endif // OPENSSL_NO_EC
+
++// Here we have the ones that make difference between OpenSSL pre/post v3:
++#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
++X509 *q_SSL_get1_peer_certificate(SSL *a);
++#define q_SSL_get_peer_certificate q_SSL_get1_peer_certificate
++int q_EVP_PKEY_get_base_id(const EVP_PKEY *pkey);
++#define q_EVP_PKEY_base_id q_EVP_PKEY_get_base_id
++#else
++X509 *q_SSL_get_peer_certificate(SSL *a);
++int q_EVP_PKEY_base_id(EVP_PKEY *a);
++#endif // OPENSSL_VERSION_MAJOR >= 3
++
+ DSA *q_DSA_new();
+ void q_DSA_free(DSA *a);
+ X509 *q_d2i_X509(X509 **a, const unsigned char **b, long c);
+@@ -510,7 +520,6 @@
+ int q_SSL_version(const SSL *a);
+ int q_SSL_get_error(SSL *a, int b);
+ STACK_OF(X509) *q_SSL_get_peer_cert_chain(SSL *a);
+-X509 *q_SSL_get_peer_certificate(SSL *a);
+ long q_SSL_get_verify_result(const SSL *a);
+ SSL *q_SSL_new(SSL_CTX *a);
+ SSL_CTX *q_SSL_get_SSL_CTX(SSL *a);
--- /dev/null
+--- configure.json 2023-04-22 13:05:35
++++ configure.json.new 2023-04-22 13:05:35
+@@ -1258,7 +1258,6 @@
+ },
+ "neon": {
+ "label": "NEON",
+- "condition": "(arch.arm || arch.arm64) && subarch.neon",
+ "output": [
+ "privateConfig",
+ { "type": "define", "name": "QT_COMPILER_SUPPORTS_NEON", "value": 1 }
+@@ -1614,8 +1613,7 @@
+ },
+ {
+ "type": "feature",
+- "args": "neon",
+- "condition": "arch.arm || arch.arm64"
++ "args": "neon"
+ },
+ {
+ "type": "feature",
'src/Compressor.cpp',
'src/Limiter.cpp',
'src/Meter.cpp',
+ 'src/Monitor.cpp',
'src/Volume.cpp',
'src/Tone.cpp',
'src/StereoToMono.cpp',
'src/JackTrip.h',
'src/ProcessPlugin.h',
'src/Meter.h',
+ 'src/Monitor.h',
'src/StereoToMono.h',
'src/Volume.h',
'src/Tone.h',
qres = ['src/gui/qjacktrip.qrc']
endif
+ if get_option('vsftux') == true
+ defines += '-DVS_FTUX'
+ endif
+
if get_option('noupdater') == true or host_machine.system() == 'linux'
defines += '-DNO_UPDATER'
else
option('weakjack', type : 'boolean', value : 'false', description: 'Weak link JACK library')
option('nogui', type : 'boolean', value : 'false', description: 'Build without graphical user interface')
option('novs', type : 'boolean', value : 'false', description: 'Build without Virtual Studio support')
+option('vsftux', type : 'boolean', value : 'false', description: 'Build with Virtual Studio first launch experience')
option('noupdater', type : 'boolean', value : 'false', description: 'Build without auto-update support')
option('profile', type: 'combo', choices: ['default', 'development'], value: 'default', description: 'Choose build profile / Sets desktop id accordingly')
option('qtversion', type : 'combo', choices: ['5', '6'], description: 'Choose to build with either Qt5 or Qt6')
\ No newline at end of file
{
- "app_name": "JackTrip",
- "releases": [
- {
- "version": "1.8.0",
- "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.8.0",
- "download": {
- "date": "2023-03-18T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.8.0-macOS-x64-signed-installer.pkg",
- "downloadSize": "11771203",
- "sha256": "dfee21d5e91a35baaf3b58891188f72f2cb894b2bf796ac70350a2ef9d3fb68c"
- }
- },
- {
- "version": "1.8.0-beta1",
- "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.8.0-beta1",
- "download": {
- "date": "2023-03-01T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.8.0-beta1-macOS-x64-installer.pkg",
- "downloadSize": 11761503,
- "sha256": "3159d5625d42db7925867949880eceef581f4991959f85bf4203c2ae15fc623f"
- }
- },
- {
- "version": "1.7.1",
- "changelog": "Video button, bug fixes, Linux build fixes, and Qt upgrades: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.1",
- "download": {
- "date": "2023-02-10T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.7.1-macOS-x64-installer.pkg",
- "downloadSize": 11679783,
- "sha256": "027d1d3aeb4aaca79b21824371a0bfb915b8c43afe924a8ec2be92df719a431f"
- }
- },
- {
- "version": "1.7.1-beta1",
- "changelog": "Video button, bug fixes, and Qt upgrades: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.1-beta1",
- "download": {
- "date": "2023-02-03T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.7.1-beta1/JackTrip-v1.7.1-beta1-macOS-x64-installer.pkg",
- "downloadSize": 11678822,
- "sha256": "1dcc8b54dd67741137582638ce04359404848d5f258c9fae7ab1946730e9381d"
- }
- },
- {
- "version": "1.7.0",
- "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.0",
- "download": {
- "date": "2023-01-24T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.7.0-macOS-x64-installer.pkg",
- "downloadSize": 11530594,
- "sha256": "0e5731c2ad71aa4bd28ccf9311e312f2386c42b02abbca142777dfb06ea1b427"
- }
- },
- {
- "version": "1.7.0-rc1",
- "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.0-rc1",
- "download": {
- "date": "2023-01-20T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.7.0-rc1/JackTrip-v1.7.0-rc1-macOS-x64-installer.pkg",
- "downloadSize": 11530680,
- "sha256": "406134ee2017bcb762f968f893bc28463149d7567dd33b92f963ca9e09608636"
- }
- },
- {
- "version": "1.6.9-beta3",
- "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.9-beta3",
- "download": {
- "date": "2023-01-18T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.9-beta3/JackTrip-v1.6.9-beta3-macOS-x64-installer.pkg",
- "downloadSize": 11528836,
- "sha256": "30689d83641377c1594e1db44d8e6cf75a45780969381d02c11ede81a175561f"
- }
- },
- {
- "version": "1.6.9-beta2",
- "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.9-beta2",
- "download": {
- "date": "2023-01-10T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.9-beta2/JackTrip-v1.6.9-beta2-macOS-x64-installer.pkg",
- "downloadSize": 11528427,
- "sha256": "884e5c0cf3ea5bc82b348a739df3ba11238074a9552dcb1d1f250f484be89b77"
- }
- },
- {
- "version": "1.6.9-beta1",
- "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.9-beta1",
- "download": {
- "date": "2022-12-16T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.9-beta1-macOS-x64-installer.pkg",
- "downloadSize": 11527211,
- "sha256": "636055dee6fb84286cc73a95c887dd39c4a6d14780c451504db87860738b2278"
- }
- },
- {
- "version": "1.6.8",
- "changelog": "Critical bug fix: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.8",
- "download": {
- "date": "2022-12-05T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.8-macOS-x64-installer.pkg",
- "downloadSize": 11517093,
- "sha256": "5c040b2caa1e7dea97d7f48fd888f532a1c30da7385535b2d4a2805551bc5f71"
- }
- },
- {
- "version": "1.6.7",
- "changelog": "Updated Windows networking, enabling all audio devices on Windows, new default device behavior, and fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.7",
- "download": {
- "date": "2022-12-02T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.7-macOS-x64-installer.pkg",
- "downloadSize": 11517151,
- "sha256": "38c25788895ec404bdb4b6148114cad8af31b65e5189ca08819d1e954e2ef4e7"
- }
- },
- {
- "version": "1.6.7-rc.2",
- "changelog": "Virtual Studio first time UI, Non-ASIO devices on Windows, Windows can't connect fix: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.7-rc.2",
- "download": {
- "date": "2022-11-29T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.7-rc.2/JackTrip-v1.6.7-rc.2-macOS-x64-installer.pkg",
- "downloadSize": 11516784,
- "sha256": "4fe2e4dbd67986926b6f738cd4d8a22b801fd3cd50aeebee13d2e1de0310b160"
- }
- },
- {
- "version": "1.6.7-rc.1",
- "changelog": "New networking code on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.7-rc.1",
- "download": {
- "date": "2022-11-07T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.7-rc.1-macOS-x64-installer.pkg",
- "downloadSize": 11481444,
- "sha256": "aa07023d130129684dc8d1e395d04eabea9709db32459e203c4fb7cf9759976e"
- }
- },
- {
- "version": "1.6.6",
- "changelog": "Adding volume controls in Virtual Studio, preliminary QT6 support, classic mode GUI updates, and fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.6",
- "download": {
- "date": "2022-11-02T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.6-macOS-x64-installer.pkg",
- "downloadSize": 11481324,
- "sha256": "e99149ea9bbfb94a2000cfd3848013e44bb8d23e783198005681c2038bcbd313"
- }
- },
- {
- "version": "1.6.5-rc.1",
- "changelog": "Adding volume controls, mute, early Qt6 support, and bug fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.5-rc1",
- "download": {
- "date": "2022-10-21T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.5-rc1/JackTrip-v1.6.5-rc1-macOS-x64-installer.pkg",
- "downloadSize": 11481049,
- "sha256": "cea18dd189d84eb9ca3be115819c597900e7bba7771185b61308518aa0e3d716"
- }
- },
- {
- "version": "1.6.4",
- "changelog": "Adding volume meters, bugfixes around Windows hanging, device disconnects, and PLC: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.4",
- "download": {
- "date": "2022-09-16T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.4-macOS-x64-installer.pkg",
- "downloadSize": 11554866,
- "sha256": "e5898f3ff57fc2d734590decb4f82a28ad9208a33cad97152f119716cdcea1a9"
- }
- },
- {
- "version": "1.6.4-rc.2",
- "changelog": "Adding volume meters, bugfixes around Windows hanging, device disconnects, and PLC: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.4-rc2",
- "download": {
- "date": "2022-09-08T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.4-rc2/JackTrip-v1.6.4-rc2-macOS-x64-installer.pkg",
- "downloadSize": 11554117,
- "sha256": "c849c22583883027f94141b3878cebc85295c0a617640449d4f66862982f75c0"
- }
- },
- {
- "version": "1.6.4-rc.1",
- "changelog": "Adding volume meters, bugfixes around Windows hanging, device disconnects, and PLC: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.4-rc1",
- "download": {
- "date": "2022-09-01T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.4-rc1/JackTrip-v1.6.4-rc1-macOS-x64-installer.pkg",
- "downloadSize": 11548759,
- "sha256": "6e8af76766b164e40e7a44842a14e640cb3c0fac7b9b7067f9c75048d3354496"
- }
- },
- {
- "version": "1.6.3",
- "changelog": "Fixes around Linux desktop file and hub server mode: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.3",
- "download": {
- "date": "2022-08-23T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.3-macOS-x64-installer.pkg",
- "downloadSize": 11533023,
- "sha256": "0b597c62544e9813949f859cc7b7c13bef893f6896f96b34a19889faf4855116"
- }
- },
- {
- "version": "1.6.2",
- "changelog": "Ability to open app via URL schemes, displaying latency stats, and Virtual Studio device support. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.2",
- "download": {
- "date": "2022-08-17T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.2-macOS-x64-installer.pkg",
- "downloadSize": 11536442,
- "sha256": "450222f4db1922275e07286d0be6ea2df2873a8a39c3b23096bcfbce342b7b3c"
- }
- },
- {
- "version": "1.6.2-rc.3",
- "changelog": "Ability to open app via URL schemes, displaying latency stats, and Virtual Studio device support. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.2-rc3",
- "download": {
- "date": "2022-08-15T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.2-rc3/JackTrip-v1.6.2-rc3-macOS-x64-installer.pkg",
- "downloadSize": 11536485,
- "sha256": "accf625c8c797c13bde01fb50fe5bbb87fe4eefd0ae8ef06b74034e1cde6f22b"
- }
- },
- {
- "version": "1.6.2-rc.2",
- "changelog": "Ability to open app via URL schemes, displaying latency stats, and Virtual Studio device support. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.2-rc2",
- "download": {
- "date": "2022-08-09T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.2-rc2/JackTrip-v1.6.2-rc2-macOS-x64-installer.pkg",
- "downloadSize": 11531462,
- "sha256": "a8b5418992045a5d08bfce1e7a412a1ad8414f9d7ea770564f2bba0caa83297b"
- }
- },
- {
- "version": "1.6.2-rc.1",
- "changelog": "Ability to open app via URL schemes, displaying latency stats, and Virtual Studio device support. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.2-rc1",
- "download": {
- "date": "2022-08-06T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.2-rc1/JackTrip-v1.6.2-rc1-macOS-x64-installer.pkg",
- "downloadSize": 11534071,
- "sha256": "9a2200d157c4bb308b0b5ba5854ee5af17ae74991f7aa94fa5a0da19282cc571"
- }
- },
- {
- "version": "1.6.1",
- "changelog": "Bugfixes around UDP timeout and 'Logging In' screen navigation. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.1",
- "download": {
- "date": "2022-06-21T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.1-macOS-x64-installer.pkg",
- "downloadSize": 11476305,
- "sha256": "eaf05c842d6b3ae799208a40b37da1cdb13e3700dcbbd97443c80cad81f4d2ac"
- }
- },
- {
- "version": "1.6.0",
- "changelog": "Full integration with JackTrip Virtual Studio. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.0",
- "download": {
- "date": "2022-06-01T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.0-macOS-x64-installer.pkg",
- "downloadSize": 11474299,
- "sha256": "27259600ecd879106ebbf97754d72d6236075a049eafa0de6271d33f753f13e4"
- }
- },
- {
- "version": "1.6.0-rc.5",
- "changelog": "Release candidate 5 for 1.6.0",
- "download": {
- "date": "2022-05-30T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.0-rc.5/JackTrip-v1.6.0-rc.5-macOS-x64-installer.pkg",
- "downloadSize": 11474262,
- "sha256": "8289530a8e6ef1f772776c7078679e2dac146f366cfc4e8c09e0ad16865fe274"
- }
- },
- {
- "version": "1.6.0-rc.4",
- "changelog": "Release candidate 4 for 1.6.0",
- "download": {
- "date": "2022-05-29T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.0-rc.4/JackTrip-v1.6.0-rc.4-macOS-x64-installer.pkg",
- "downloadSize": 11460550,
- "sha256": "38d817f3e8cc61b707392ce74cee8ab46da9c8eb2086ea2b3f0c79496caf70a8"
- }
- },
- {
- "version": "1.6.0-rc.3",
- "changelog": "Release candidate 3 for 1.6.0",
- "download": {
- "date": "2022-05-27T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.0-rc.3-macOS-x64-installer.pkg",
- "downloadSize": 11460230,
- "sha256": "c9614964974d61c062d905f01c7d30ab04a697562ecfba6264392aebe7161051"
- }
- },
- {
- "version": "1.6.0-rc.2",
- "changelog": "Release candidate 2 for 1.6.0",
- "download": {
- "date": "2022-05-26T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.0-rc.2-macOS-x64-signed-installer.pkg",
- "downloadSize": 11460155,
- "sha256": "ad508680115f73036da3a5328ddf0841b86620406406e0ffaa4b982e24a27771"
- }
- },
- {
- "version": "1.6.0-rc.1",
- "changelog": "Release candidate 1 for 1.6.0",
- "download": {
- "date": "2022-05-23T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.0-rc.1/JackTrip-v1.6.0-rc.1-macOS-x64-installer.pkg",
- "downloadSize": 11076221,
- "sha256": "071cda0ce59361e474a04db00beec41e92d2d823dab71e3fab179faf89f6fd7e"
- }
- }
- ]
+ "app_name": "JackTrip",
+ "releases": [
+ {
+ "version": "1.9.0-beta3",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.9.0-beta3",
+ "download": {
+ "date": "2023-05-05T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.9.0-beta3-macOS-x64-signed-installer.pkg",
+ "downloadSize": "22811032",
+ "sha256": "0d6d0f34c4c99fb03810ea86360a8ac93874121db897b2ba23132acf9fdefc50"
+ }
+ },
+ {
+ "version": "1.9.0-beta2",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.9.0-beta2",
+ "download": {
+ "date": "2023-04-25T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.9.0-beta2-macOS-x64-signed-installer.pkg",
+ "downloadSize": "22776100",
+ "sha256": "99ea878f0fbd5913516cfd73e2403c61d181b03c7e4f251e8075b01fbd78ecd7"
+ }
+ },
+ {
+ "version": "1.9.0-beta1",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.9.0-beta1",
+ "download": {
+ "date": "2023-04-18T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.9.0-beta1-macOS-x64-signed-installer.pkg",
+ "downloadSize": "11768911",
+ "sha256": "a2f38e04cd03c3b8e549e7e82644df11dd1d59c03aa00806a02aa6ff7c76c1b0"
+ }
+ },
+ {
+ "version": "1.8.1",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.8.1",
+ "download": {
+ "date": "2023-04-03T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.8.1-macOS-x64-signed-installer.pkg",
+ "downloadSize": "11754694",
+ "sha256": "d073ff5f2b90b5dd86ccd07c5d30d61d7be776c5e3c0083e6f665f78fea48298"
+ }
+ },
+ {
+ "version": "1.8.0",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.8.0",
+ "download": {
+ "date": "2023-03-18T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.8.0-macOS-x64-signed-installer.pkg",
+ "downloadSize": "11771203",
+ "sha256": "dfee21d5e91a35baaf3b58891188f72f2cb894b2bf796ac70350a2ef9d3fb68c"
+ }
+ },
+ {
+ "version": "1.8.0-beta2",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.8.0-beta2",
+ "download": {
+ "date": "2023-03-10T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.8.0-beta2-macOS-x64-signed-installer.pkg",
+ "downloadSize": "11769049",
+ "sha256": "9ffbf4c2c7b9419cd7e5000efe1441ca3eb0e44dfcdecd0347c561e7eecc4e36"
+ }
+ },
+ {
+ "version": "1.8.0-beta1",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.8.0-beta1",
+ "download": {
+ "date": "2023-03-01T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.8.0-beta1-macOS-x64-installer.pkg",
+ "downloadSize": 11761503,
+ "sha256": "3159d5625d42db7925867949880eceef581f4991959f85bf4203c2ae15fc623f"
+ }
+ },
+ {
+ "version": "1.7.1",
+ "changelog": "Video button, bug fixes, Linux build fixes, and Qt upgrades: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.1",
+ "download": {
+ "date": "2023-02-10T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.7.1-macOS-x64-installer.pkg",
+ "downloadSize": 11679783,
+ "sha256": "027d1d3aeb4aaca79b21824371a0bfb915b8c43afe924a8ec2be92df719a431f"
+ }
+ },
+ {
+ "version": "1.7.1-beta1",
+ "changelog": "Video button, bug fixes, and Qt upgrades: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.1-beta1",
+ "download": {
+ "date": "2023-02-03T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.7.1-beta1/JackTrip-v1.7.1-beta1-macOS-x64-installer.pkg",
+ "downloadSize": 11678822,
+ "sha256": "1dcc8b54dd67741137582638ce04359404848d5f258c9fae7ab1946730e9381d"
+ }
+ },
+ {
+ "version": "1.7.0",
+ "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.0",
+ "download": {
+ "date": "2023-01-24T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.7.0-macOS-x64-installer.pkg",
+ "downloadSize": 11530594,
+ "sha256": "0e5731c2ad71aa4bd28ccf9311e312f2386c42b02abbca142777dfb06ea1b427"
+ }
+ },
+ {
+ "version": "1.7.0-rc1",
+ "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.0-rc1",
+ "download": {
+ "date": "2023-01-20T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.7.0-rc1/JackTrip-v1.7.0-rc1-macOS-x64-installer.pkg",
+ "downloadSize": 11530680,
+ "sha256": "406134ee2017bcb762f968f893bc28463149d7567dd33b92f963ca9e09608636"
+ }
+ },
+ {
+ "version": "1.6.9-beta3",
+ "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.9-beta3",
+ "download": {
+ "date": "2023-01-18T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.9-beta3/JackTrip-v1.6.9-beta3-macOS-x64-installer.pkg",
+ "downloadSize": 11528836,
+ "sha256": "30689d83641377c1594e1db44d8e6cf75a45780969381d02c11ede81a175561f"
+ }
+ },
+ {
+ "version": "1.6.9-beta2",
+ "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.9-beta2",
+ "download": {
+ "date": "2023-01-10T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.9-beta2/JackTrip-v1.6.9-beta2-macOS-x64-installer.pkg",
+ "downloadSize": 11528427,
+ "sha256": "884e5c0cf3ea5bc82b348a739df3ba11238074a9552dcb1d1f250f484be89b77"
+ }
+ },
+ {
+ "version": "1.6.9-beta1",
+ "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.9-beta1",
+ "download": {
+ "date": "2022-12-16T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.9-beta1-macOS-x64-installer.pkg",
+ "downloadSize": 11527211,
+ "sha256": "636055dee6fb84286cc73a95c887dd39c4a6d14780c451504db87860738b2278"
+ }
+ },
+ {
+ "version": "1.6.8",
+ "changelog": "Critical bug fix: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.8",
+ "download": {
+ "date": "2022-12-05T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.8-macOS-x64-installer.pkg",
+ "downloadSize": 11517093,
+ "sha256": "5c040b2caa1e7dea97d7f48fd888f532a1c30da7385535b2d4a2805551bc5f71"
+ }
+ },
+ {
+ "version": "1.6.7",
+ "changelog": "Updated Windows networking, enabling all audio devices on Windows, new default device behavior, and fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.7",
+ "download": {
+ "date": "2022-12-02T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.7-macOS-x64-installer.pkg",
+ "downloadSize": 11517151,
+ "sha256": "38c25788895ec404bdb4b6148114cad8af31b65e5189ca08819d1e954e2ef4e7"
+ }
+ },
+ {
+ "version": "1.6.7-rc.2",
+ "changelog": "Virtual Studio first time UI, Non-ASIO devices on Windows, Windows can't connect fix: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.7-rc.2",
+ "download": {
+ "date": "2022-11-29T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.7-rc.2/JackTrip-v1.6.7-rc.2-macOS-x64-installer.pkg",
+ "downloadSize": 11516784,
+ "sha256": "4fe2e4dbd67986926b6f738cd4d8a22b801fd3cd50aeebee13d2e1de0310b160"
+ }
+ },
+ {
+ "version": "1.6.7-rc.1",
+ "changelog": "New networking code on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.7-rc.1",
+ "download": {
+ "date": "2022-11-07T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.7-rc.1-macOS-x64-installer.pkg",
+ "downloadSize": 11481444,
+ "sha256": "aa07023d130129684dc8d1e395d04eabea9709db32459e203c4fb7cf9759976e"
+ }
+ },
+ {
+ "version": "1.6.6",
+ "changelog": "Adding volume controls in Virtual Studio, preliminary QT6 support, classic mode GUI updates, and fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.6",
+ "download": {
+ "date": "2022-11-02T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.6-macOS-x64-installer.pkg",
+ "downloadSize": 11481324,
+ "sha256": "e99149ea9bbfb94a2000cfd3848013e44bb8d23e783198005681c2038bcbd313"
+ }
+ },
+ {
+ "version": "1.6.5-rc.1",
+ "changelog": "Adding volume controls, mute, early Qt6 support, and bug fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.5-rc1",
+ "download": {
+ "date": "2022-10-21T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.5-rc1/JackTrip-v1.6.5-rc1-macOS-x64-installer.pkg",
+ "downloadSize": 11481049,
+ "sha256": "cea18dd189d84eb9ca3be115819c597900e7bba7771185b61308518aa0e3d716"
+ }
+ },
+ {
+ "version": "1.6.4",
+ "changelog": "Adding volume meters, bugfixes around Windows hanging, device disconnects, and PLC: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.4",
+ "download": {
+ "date": "2022-09-16T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.4-macOS-x64-installer.pkg",
+ "downloadSize": 11554866,
+ "sha256": "e5898f3ff57fc2d734590decb4f82a28ad9208a33cad97152f119716cdcea1a9"
+ }
+ },
+ {
+ "version": "1.6.4-rc.2",
+ "changelog": "Adding volume meters, bugfixes around Windows hanging, device disconnects, and PLC: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.4-rc2",
+ "download": {
+ "date": "2022-09-08T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.4-rc2/JackTrip-v1.6.4-rc2-macOS-x64-installer.pkg",
+ "downloadSize": 11554117,
+ "sha256": "c849c22583883027f94141b3878cebc85295c0a617640449d4f66862982f75c0"
+ }
+ },
+ {
+ "version": "1.6.4-rc.1",
+ "changelog": "Adding volume meters, bugfixes around Windows hanging, device disconnects, and PLC: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.4-rc1",
+ "download": {
+ "date": "2022-09-01T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.4-rc1/JackTrip-v1.6.4-rc1-macOS-x64-installer.pkg",
+ "downloadSize": 11548759,
+ "sha256": "6e8af76766b164e40e7a44842a14e640cb3c0fac7b9b7067f9c75048d3354496"
+ }
+ },
+ {
+ "version": "1.6.3",
+ "changelog": "Fixes around Linux desktop file and hub server mode: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.3",
+ "download": {
+ "date": "2022-08-23T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.3-macOS-x64-installer.pkg",
+ "downloadSize": 11533023,
+ "sha256": "0b597c62544e9813949f859cc7b7c13bef893f6896f96b34a19889faf4855116"
+ }
+ },
+ {
+ "version": "1.6.2",
+ "changelog": "Ability to open app via URL schemes, displaying latency stats, and Virtual Studio device support. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.2",
+ "download": {
+ "date": "2022-08-17T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.2-macOS-x64-installer.pkg",
+ "downloadSize": 11536442,
+ "sha256": "450222f4db1922275e07286d0be6ea2df2873a8a39c3b23096bcfbce342b7b3c"
+ }
+ },
+ {
+ "version": "1.6.2-rc.3",
+ "changelog": "Ability to open app via URL schemes, displaying latency stats, and Virtual Studio device support. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.2-rc3",
+ "download": {
+ "date": "2022-08-15T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.2-rc3/JackTrip-v1.6.2-rc3-macOS-x64-installer.pkg",
+ "downloadSize": 11536485,
+ "sha256": "accf625c8c797c13bde01fb50fe5bbb87fe4eefd0ae8ef06b74034e1cde6f22b"
+ }
+ },
+ {
+ "version": "1.6.2-rc.2",
+ "changelog": "Ability to open app via URL schemes, displaying latency stats, and Virtual Studio device support. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.2-rc2",
+ "download": {
+ "date": "2022-08-09T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.2-rc2/JackTrip-v1.6.2-rc2-macOS-x64-installer.pkg",
+ "downloadSize": 11531462,
+ "sha256": "a8b5418992045a5d08bfce1e7a412a1ad8414f9d7ea770564f2bba0caa83297b"
+ }
+ },
+ {
+ "version": "1.6.2-rc.1",
+ "changelog": "Ability to open app via URL schemes, displaying latency stats, and Virtual Studio device support. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.2-rc1",
+ "download": {
+ "date": "2022-08-06T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.2-rc1/JackTrip-v1.6.2-rc1-macOS-x64-installer.pkg",
+ "downloadSize": 11534071,
+ "sha256": "9a2200d157c4bb308b0b5ba5854ee5af17ae74991f7aa94fa5a0da19282cc571"
+ }
+ },
+ {
+ "version": "1.6.1",
+ "changelog": "Bugfixes around UDP timeout and 'Logging In' screen navigation. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.1",
+ "download": {
+ "date": "2022-06-21T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.1-macOS-x64-installer.pkg",
+ "downloadSize": 11476305,
+ "sha256": "eaf05c842d6b3ae799208a40b37da1cdb13e3700dcbbd97443c80cad81f4d2ac"
+ }
+ },
+ {
+ "version": "1.6.0",
+ "changelog": "Full integration with JackTrip Virtual Studio. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.0",
+ "download": {
+ "date": "2022-06-01T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.0-macOS-x64-installer.pkg",
+ "downloadSize": 11474299,
+ "sha256": "27259600ecd879106ebbf97754d72d6236075a049eafa0de6271d33f753f13e4"
+ }
+ },
+ {
+ "version": "1.6.0-rc.5",
+ "changelog": "Release candidate 5 for 1.6.0",
+ "download": {
+ "date": "2022-05-30T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.0-rc.5/JackTrip-v1.6.0-rc.5-macOS-x64-installer.pkg",
+ "downloadSize": 11474262,
+ "sha256": "8289530a8e6ef1f772776c7078679e2dac146f366cfc4e8c09e0ad16865fe274"
+ }
+ },
+ {
+ "version": "1.6.0-rc.4",
+ "changelog": "Release candidate 4 for 1.6.0",
+ "download": {
+ "date": "2022-05-29T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.0-rc.4/JackTrip-v1.6.0-rc.4-macOS-x64-installer.pkg",
+ "downloadSize": 11460550,
+ "sha256": "38d817f3e8cc61b707392ce74cee8ab46da9c8eb2086ea2b3f0c79496caf70a8"
+ }
+ },
+ {
+ "version": "1.6.0-rc.3",
+ "changelog": "Release candidate 3 for 1.6.0",
+ "download": {
+ "date": "2022-05-27T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.0-rc.3-macOS-x64-installer.pkg",
+ "downloadSize": 11460230,
+ "sha256": "c9614964974d61c062d905f01c7d30ab04a697562ecfba6264392aebe7161051"
+ }
+ },
+ {
+ "version": "1.6.0-rc.2",
+ "changelog": "Release candidate 2 for 1.6.0",
+ "download": {
+ "date": "2022-05-26T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.0-rc.2-macOS-x64-signed-installer.pkg",
+ "downloadSize": 11460155,
+ "sha256": "ad508680115f73036da3a5328ddf0841b86620406406e0ffaa4b982e24a27771"
+ }
+ },
+ {
+ "version": "1.6.0-rc.1",
+ "changelog": "Release candidate 1 for 1.6.0",
+ "download": {
+ "date": "2022-05-23T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.0-rc.1/JackTrip-v1.6.0-rc.1-macOS-x64-installer.pkg",
+ "downloadSize": 11076221,
+ "sha256": "071cda0ce59361e474a04db00beec41e92d2d823dab71e3fab179faf89f6fd7e"
+ }
+ }
+ ]
}
{
- "app_name": "JackTrip",
- "releases": [
- {
- "version": "1.8.0",
- "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.8.0",
- "download": {
- "date": "2023-03-18T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.8.0-Windows-x64-signed-installer.msi",
- "downloadSize": "45699072",
- "sha256": "4b6705a2e8af7f9a516fefaf119d5e6cadf93e8f40964cd52b635ced5745b267"
- }
- },
- {
- "version": "1.8.0-beta1",
- "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.8.0-beta1",
- "download": {
- "date": "2023-03-01T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.8.0-beta1-Windows-x64-installer.msi",
- "downloadSize": 45568000,
- "sha256": "61641b72fe27389ab755580d5b94fa2de993ad42967af0c5c765743ca8b30602"
- }
- },
- {
- "version": "1.7.1",
- "changelog": "Video button, bug fixes, Linux build fixes, and Qt upgrades: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.1",
- "download": {
- "date": "2023-02-10T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.7.1-Windows-x64-installer.msi",
- "downloadSize": 45330432,
- "sha256": "fb5d756afcd471ca8ae45b05b411235026f23f2178893d85ac12f39c3f66a01a"
- }
- },
- {
- "version": "1.7.1-beta1",
- "changelog": "Video button, bug fixes, and Qt upgrades: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.1-beta1",
- "download": {
- "date": "2023-02-03T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.7.1-beta1/JackTrip-v1.7.1-beta1-Windows-x64-installer.msi",
- "downloadSize": 45326336,
- "sha256": "eeb16bc11957413fb74da852b9e0fa3cb8c84cb2945d5c992a40f3e9b526c294"
- }
- },
- {
- "version": "1.7.0",
- "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.0",
- "download": {
- "date": "2023-01-24T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.7.0-Windows-x64-installer.msi",
- "downloadSize": 44572672,
- "sha256": "a1890fe10de484f423a17118031d898abacc9b9eb2ccd35bdb4351e9411ff866"
- }
- },
- {
- "version": "1.7.0-rc1",
- "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.0-rc1",
- "download": {
- "date": "2023-01-20T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.7.0-rc1/JackTrip-v1.7.0-rc1-Windows-x64-installer.msi",
- "downloadSize": 44556288,
- "sha256": "edba383791a598954d129d39024e87f3c062985d10f47dbea43f3d226ee37c6c"
- }
- },
- {
- "version": "1.6.9-beta3",
- "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.9-beta3",
- "download": {
- "date": "2023-01-10T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.9-beta3/JackTrip-v1.6.9-beta3-Windows-x64-installer.msi",
- "downloadSize": 44552192,
- "sha256": "f0d8157d99da5ecfa3fb21e6bb039ea48052fc0792b114ca4f40ae0a554a4852"
- }
- },
- {
- "version": "1.6.9-beta2",
- "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.9-beta2",
- "download": {
- "date": "2023-01-10T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.9-beta2/JackTrip-v1.6.9-beta2-Windows-x64-installer.msi",
- "downloadSize": 44548096,
- "sha256": "a8e7c9b353d953df894a827e2856baa71f89dc8fa835a5f3eb8422a94ffff5b5"
- }
- },
- {
- "version": "1.6.9-beta1",
- "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.9-beta1",
- "download": {
- "date": "2022-12-16T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.9-beta1-Windows-x64-installer.msi",
- "downloadSize": 44548096,
- "sha256": "c5cfbfc1c7650d685489974b69f005671ceb44a1301006d33ceeda45fc00f7c7"
- }
- },
- {
- "version": "1.6.8",
- "changelog": "Critical bug fix: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.8",
- "download": {
- "date": "2022-12-05T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.8-Windows-x64-installer.msi",
- "downloadSize": 44539904,
- "sha256": "e4ac16e7a66b4d656eea4e88f703fe156d656aedc16ad7f63ec570d82c27ed54"
- }
- },
- {
- "version": "1.6.7",
- "changelog": "Updated Windows networking, enabling all audio devices on Windows, new default device behavior, and fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.7",
- "download": {
- "date": "2022-12-02T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.7-Windows-x64-installer.msi",
- "downloadSize": 44535808,
- "sha256": "75464575311da5521e011da8d2f2b5aff1379edb4dee9dcb90e1750dcc97f2f9"
- }
- },
- {
- "version": "1.6.7-rc.2",
- "changelog": "Virtual Studio first time UI, Non-ASIO devices on Windows, Windows can't connect fix: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.7-rc.2",
- "download": {
- "date": "2022-11-29T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.7-rc.2/JackTrip-v1.6.7-rc.2-Windows-x64-installer.msi",
- "downloadSize": 44531712,
- "sha256": "656716e1e665187474bda00c89348a405018a69830557b4722e382187ee367e1"
- }
- },
- {
- "version": "1.6.7-rc.1",
- "changelog": "New networking code on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.7-rc.1",
- "download": {
- "date": "2022-11-07T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.7-rc.1-Windows-x64-installer.msi",
- "downloadSize": 44412928,
- "sha256": "a0485d45c615c435fc4d6b0840d0bf8a74f990001eeacfe26a74d61afbd72dfd"
- }
- },
- {
- "version": "1.6.6",
- "changelog": "Adding volume controls in Virtual Studio, preliminary QT6 support, classic mode GUI updates, and fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.6",
- "download": {
- "date": "2022-11-02T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.6-Windows-x64-installer.msi",
- "downloadSize": 44408832,
- "sha256": "828a1f43254db187a33601cc809551617db83e60a51dad3e992c30270967de0c"
- }
- },
- {
- "version": "1.6.5-rc.1",
- "changelog": "Adding volume controls, mute, early Qt6 support, and bug fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.5-rc1",
- "download": {
- "date": "2022-10-21T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.5-rc1/JackTrip-v1.6.5-rc1-Windows-x64-installer.msi",
- "downloadSize": 44408832,
- "sha256": "99404fa7bf1a07df76a1b1048c7a0e64a0d5f552e2ca5dfb12e7cbaac0c6fb24"
- }
- },
- {
- "version": "1.6.4",
- "changelog": "Adding volume meters, bugfixes around Windows hanging, device disconnects, and PLC: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.4",
- "download": {
- "date": "2022-09-16T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.4-Windows-x64-installer.msi",
- "downloadSize": 43663360,
- "sha256": "58dcbba584e1cc82373b8aa159800ad360eec7933ce9462e413ca347f09f3c26"
- }
- },
- {
- "version": "1.6.4-rc.2",
- "changelog": "Adding volume meters, bugfixes around Windows hanging, device disconnects, and PLC: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.4-rc2",
- "download": {
- "date": "2022-09-08T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.4-rc2/JackTrip-v1.6.4-rc2-Windows-x64-installer.msi",
- "downloadSize": 43663360,
- "sha256": "fc782f0f9547ff096eb99891745e5d80056090b05a179f0209bd7785b1b808a6"
- }
- },
- {
- "version": "1.6.4-rc.1",
- "changelog": "Adding volume meters, bugfixes around Windows hanging, device disconnects, and PLC: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.4-rc1",
- "download": {
- "date": "2022-09-01T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.4-rc1/JackTrip-v1.6.4-rc1-Windows-x64-installer.msi",
- "downloadSize": 43651072,
- "sha256": "fbe0f883429119b4c878e0dff4bb2c79f2ac0d995b9c947f7eb8cc70fa59bc67"
- }
- },
- {
- "version": "1.6.3",
- "changelog": "Fixes around Linux desktop file and hub server mode: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.3",
- "download": {
- "date": "2022-08-23T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.3-Windows-x64-installer.msi",
- "downloadSize": 43606016,
- "sha256": "83a4def2a8c8fde24d147d39e70f60ee144e9425828f34eda2340c23ce72b1da"
- }
- },
- {
- "version": "1.6.2",
- "changelog": "Ability to open app via URL schemes, displaying latency stats, and Virtual Studio device support. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.2",
- "download": {
- "date": "2022-08-17T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.2-Windows-x64-installer.msi",
- "downloadSize": 43606016,
- "sha256": "2bb06fe3624df447d56da0d72fef1f4328346fd92c6dffccf66ba37253ec5e62"
- }
- },
- {
- "version": "1.6.2-rc.3",
- "changelog": "Ability to open app via URL schemes, displaying latency stats, and Virtual Studio device support. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.2-rc3",
- "download": {
- "date": "2022-08-15T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.2-rc3/JackTrip-v1.6.2-rc3-Windows-x64-installer.msi",
- "downloadSize": 43606016,
- "sha256": "62771ca5efbf2e91fa4cd347214e6e517b76c032a8895ca80bcbc2fa765ab81a"
- }
- },
- {
- "version": "1.6.2-rc.2",
- "changelog": "Ability to open app via URL schemes, displaying latency stats, and Virtual Studio device support. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.2-rc2",
- "download": {
- "date": "2022-08-09T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.2-rc2/JackTrip-v1.6.2-rc2-Windows-x64-installer.msi",
- "downloadSize": 43606016,
- "sha256": "ff88acd1804362589478366a620d12be302071dba9781ea38ed6a8343c94c16d"
- }
- },
- {
- "version": "1.6.2-rc.1",
- "changelog": "Ability to open app via URL schemes, displaying latency stats, and Virtual Studio device support. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.2-rc1",
- "download": {
- "date": "2022-08-06T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.2-rc1/JackTrip-v1.6.2-rc1-Windows-x64-installer.msi",
- "downloadSize": 43601920,
- "sha256": "f1412de0b13ff7599353a10aec8f2b69e9831a37103187f8fa68334c8f8f09de"
- }
- },
- {
- "version": "1.6.1",
- "changelog": "Bugfixes around UDP timeout and 'Logging In' screen navigation. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.1",
- "download": {
- "date": "2022-06-21T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.1-Windows-x64-installer.msi",
- "downloadSize": 43368448,
- "sha256": "8eac390617488d849c0356e3305c96a59bbe46a8174d02b0321bb1dc86774b87"
- }
- },
- {
- "version": "1.6.0",
- "changelog": "Full integration with JackTrip Virtual Studio. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.0",
- "download": {
- "date": "2022-06-01T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.0-Windows-x64-installer.msi",
- "downloadSize": 43364352,
- "sha256": "9562ab654202bfc432e05caa3bd2bf1d0b52c50581b0a567f0546983fe46c078"
- }
- },
- {
- "version": "1.6.0-rc.5",
- "changelog": "Release candidate 5 for 1.6.0",
- "download": {
- "date": "2022-05-30T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.0-rc.5/JackTrip-v1.6.0-rc.5-Windows-x64-installer.msi",
- "downloadSize": 43364352,
- "sha256": "d84e6e5d21cf31f5dd48e9dcc0c1a44fe7a37d977f94b6ff63d5e381745e5a44"
- }
- },
- {
- "version": "1.6.0-rc.4",
- "changelog": "Release candidate 4 for 1.6.0",
- "download": {
- "date": "2022-05-29T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.0-rc.4/JackTrip-v1.6.0-rc.4-Windows-x64-installer.msi",
- "downloadSize": 43126784,
- "sha256": "cdb0ef906cf0d6047289838bf013b31a626cdd74dd4f75d6c1c4c3adbc9cd41d"
- }
- },
- {
- "version": "1.6.0-rc.3",
- "changelog": "Release candidate 3 for 1.6.0",
- "download": {
- "date": "2022-05-27T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.0-rc.3-Windows-x64-installer.msi",
- "downloadSize": 43118592,
- "sha256": "dceaf670a67cf1541007db82c5ce937b25370a7140e48192b94470f575fc4988"
- }
- },
- {
- "version": "1.6.0-rc.2",
- "changelog": "Release candidate 2 for 1.6.0",
- "download": {
- "date": "2022-05-26T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.0-rc.2-Windows-x64-signed-installer.msi",
- "downloadSize": 43114496,
- "sha256": "b1a7adc8dc0fb47f59515790e8531dd10838d799bacb4b5653192ed621bca208"
- }
- },
- {
- "version": "1.6.0-rc.1",
- "changelog": "Release candidate 1 for 1.6.0",
- "download": {
- "date": "2022-05-23T00:00:00Z",
- "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.0-rc.1/JackTrip-v1.6.0-rc.1-Windows-x64-installer.msi",
- "downloadSize": 43081728,
- "sha256": "240f8b495ec5057228be922da80829a3718b474bafc2ba2d77750643abd1005c"
- }
- }
- ]
-}
\ No newline at end of file
+ "app_name": "JackTrip",
+ "releases": [
+ {
+ "version": "1.9.0-beta3",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.9.0-beta3",
+ "download": {
+ "date": "2023-05-05T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.9.0-beta3-Windows-x64-signed-installer.msi",
+ "downloadSize": "46383104",
+ "sha256": "7db404d0fe9d062409d9f1ebe3382ab99aa9638f82c9951cbc442dab91e42f21"
+ }
+ },
+ {
+ "version": "1.9.0-beta2",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.9.0-beta2",
+ "download": {
+ "date": "2023-04-25T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.9.0-beta2-Windows-x64-signed-installer.msi",
+ "downloadSize": "46546944",
+ "sha256": "ee75aa4bb3e617f055b9a5b64c2bf98006d774845a4f1cdc247add7dfc1ba9fc"
+ }
+ },
+ {
+ "version": "1.9.0-beta1",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.9.0-beta1",
+ "download": {
+ "date": "2023-04-18T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.9.0-beta1-Windows-x64-signed-installer.msi",
+ "downloadSize": "46530560",
+ "sha256": "80fac822af3e826743c501715681430fdecda9799dd6e8cf478e8b87f0d0d9c5"
+ }
+ },
+ {
+ "version": "1.8.1",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.8.1",
+ "download": {
+ "date": "2023-04-03T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.8.1-Windows-x64-signed-installer.msi",
+ "downloadSize": "46456832",
+ "sha256": "55da405ea55a3567a672eef0f5f3699c264f456e13dd04d2a55d90bd3d1a2f55"
+ }
+ },
+ {
+ "version": "1.8.0",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.8.0",
+ "download": {
+ "date": "2023-03-18T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.8.0-Windows-x64-signed-installer.msi",
+ "downloadSize": "45699072",
+ "sha256": "4b6705a2e8af7f9a516fefaf119d5e6cadf93e8f40964cd52b635ced5745b267"
+ }
+ },
+ {
+ "version": "1.8.0-beta2",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.8.0-beta2",
+ "download": {
+ "date": "2023-03-10T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.8.0-beta2-Windows-x64-signed-installer.msi",
+ "downloadSize": "45694976",
+ "sha256": "8d080a009b5583fc4360dfefb2efaa74966c2d76d9a982bba36c42c8a0e536fd"
+ }
+ },
+ {
+ "version": "1.8.0-beta1",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.8.0-beta1",
+ "download": {
+ "date": "2023-03-01T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.8.0-beta1-Windows-x64-installer.msi",
+ "downloadSize": 45568000,
+ "sha256": "61641b72fe27389ab755580d5b94fa2de993ad42967af0c5c765743ca8b30602"
+ }
+ },
+ {
+ "version": "1.7.1",
+ "changelog": "Video button, bug fixes, Linux build fixes, and Qt upgrades: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.1",
+ "download": {
+ "date": "2023-02-10T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.7.1-Windows-x64-installer.msi",
+ "downloadSize": 45330432,
+ "sha256": "fb5d756afcd471ca8ae45b05b411235026f23f2178893d85ac12f39c3f66a01a"
+ }
+ },
+ {
+ "version": "1.7.1-beta1",
+ "changelog": "Video button, bug fixes, and Qt upgrades: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.1-beta1",
+ "download": {
+ "date": "2023-02-03T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.7.1-beta1/JackTrip-v1.7.1-beta1-Windows-x64-installer.msi",
+ "downloadSize": 45326336,
+ "sha256": "eeb16bc11957413fb74da852b9e0fa3cb8c84cb2945d5c992a40f3e9b526c294"
+ }
+ },
+ {
+ "version": "1.7.0",
+ "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.0",
+ "download": {
+ "date": "2023-01-24T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.7.0-Windows-x64-installer.msi",
+ "downloadSize": 44572672,
+ "sha256": "a1890fe10de484f423a17118031d898abacc9b9eb2ccd35bdb4351e9411ff866"
+ }
+ },
+ {
+ "version": "1.7.0-rc1",
+ "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.0-rc1",
+ "download": {
+ "date": "2023-01-20T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.7.0-rc1/JackTrip-v1.7.0-rc1-Windows-x64-installer.msi",
+ "downloadSize": 44556288,
+ "sha256": "edba383791a598954d129d39024e87f3c062985d10f47dbea43f3d226ee37c6c"
+ }
+ },
+ {
+ "version": "1.6.9-beta3",
+ "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.9-beta3",
+ "download": {
+ "date": "2023-01-10T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.9-beta3/JackTrip-v1.6.9-beta3-Windows-x64-installer.msi",
+ "downloadSize": 44552192,
+ "sha256": "f0d8157d99da5ecfa3fb21e6bb039ea48052fc0792b114ca4f40ae0a554a4852"
+ }
+ },
+ {
+ "version": "1.6.9-beta2",
+ "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.9-beta2",
+ "download": {
+ "date": "2023-01-10T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.9-beta2/JackTrip-v1.6.9-beta2-Windows-x64-installer.msi",
+ "downloadSize": 44548096,
+ "sha256": "a8e7c9b353d953df894a827e2856baa71f89dc8fa835a5f3eb8422a94ffff5b5"
+ }
+ },
+ {
+ "version": "1.6.9-beta1",
+ "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.9-beta1",
+ "download": {
+ "date": "2022-12-16T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.9-beta1-Windows-x64-installer.msi",
+ "downloadSize": 44548096,
+ "sha256": "c5cfbfc1c7650d685489974b69f005671ceb44a1301006d33ceeda45fc00f7c7"
+ }
+ },
+ {
+ "version": "1.6.8",
+ "changelog": "Critical bug fix: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.8",
+ "download": {
+ "date": "2022-12-05T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.8-Windows-x64-installer.msi",
+ "downloadSize": 44539904,
+ "sha256": "e4ac16e7a66b4d656eea4e88f703fe156d656aedc16ad7f63ec570d82c27ed54"
+ }
+ },
+ {
+ "version": "1.6.7",
+ "changelog": "Updated Windows networking, enabling all audio devices on Windows, new default device behavior, and fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.7",
+ "download": {
+ "date": "2022-12-02T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.7-Windows-x64-installer.msi",
+ "downloadSize": 44535808,
+ "sha256": "75464575311da5521e011da8d2f2b5aff1379edb4dee9dcb90e1750dcc97f2f9"
+ }
+ },
+ {
+ "version": "1.6.7-rc.2",
+ "changelog": "Virtual Studio first time UI, Non-ASIO devices on Windows, Windows can't connect fix: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.7-rc.2",
+ "download": {
+ "date": "2022-11-29T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.7-rc.2/JackTrip-v1.6.7-rc.2-Windows-x64-installer.msi",
+ "downloadSize": 44531712,
+ "sha256": "656716e1e665187474bda00c89348a405018a69830557b4722e382187ee367e1"
+ }
+ },
+ {
+ "version": "1.6.7-rc.1",
+ "changelog": "New networking code on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.7-rc.1",
+ "download": {
+ "date": "2022-11-07T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.7-rc.1-Windows-x64-installer.msi",
+ "downloadSize": 44412928,
+ "sha256": "a0485d45c615c435fc4d6b0840d0bf8a74f990001eeacfe26a74d61afbd72dfd"
+ }
+ },
+ {
+ "version": "1.6.6",
+ "changelog": "Adding volume controls in Virtual Studio, preliminary QT6 support, classic mode GUI updates, and fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.6",
+ "download": {
+ "date": "2022-11-02T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.6-Windows-x64-installer.msi",
+ "downloadSize": 44408832,
+ "sha256": "828a1f43254db187a33601cc809551617db83e60a51dad3e992c30270967de0c"
+ }
+ },
+ {
+ "version": "1.6.5-rc.1",
+ "changelog": "Adding volume controls, mute, early Qt6 support, and bug fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.5-rc1",
+ "download": {
+ "date": "2022-10-21T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.5-rc1/JackTrip-v1.6.5-rc1-Windows-x64-installer.msi",
+ "downloadSize": 44408832,
+ "sha256": "99404fa7bf1a07df76a1b1048c7a0e64a0d5f552e2ca5dfb12e7cbaac0c6fb24"
+ }
+ },
+ {
+ "version": "1.6.4",
+ "changelog": "Adding volume meters, bugfixes around Windows hanging, device disconnects, and PLC: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.4",
+ "download": {
+ "date": "2022-09-16T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.4-Windows-x64-installer.msi",
+ "downloadSize": 43663360,
+ "sha256": "58dcbba584e1cc82373b8aa159800ad360eec7933ce9462e413ca347f09f3c26"
+ }
+ },
+ {
+ "version": "1.6.4-rc.2",
+ "changelog": "Adding volume meters, bugfixes around Windows hanging, device disconnects, and PLC: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.4-rc2",
+ "download": {
+ "date": "2022-09-08T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.4-rc2/JackTrip-v1.6.4-rc2-Windows-x64-installer.msi",
+ "downloadSize": 43663360,
+ "sha256": "fc782f0f9547ff096eb99891745e5d80056090b05a179f0209bd7785b1b808a6"
+ }
+ },
+ {
+ "version": "1.6.4-rc.1",
+ "changelog": "Adding volume meters, bugfixes around Windows hanging, device disconnects, and PLC: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.4-rc1",
+ "download": {
+ "date": "2022-09-01T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.4-rc1/JackTrip-v1.6.4-rc1-Windows-x64-installer.msi",
+ "downloadSize": 43651072,
+ "sha256": "fbe0f883429119b4c878e0dff4bb2c79f2ac0d995b9c947f7eb8cc70fa59bc67"
+ }
+ },
+ {
+ "version": "1.6.3",
+ "changelog": "Fixes around Linux desktop file and hub server mode: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.3",
+ "download": {
+ "date": "2022-08-23T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.3-Windows-x64-installer.msi",
+ "downloadSize": 43606016,
+ "sha256": "83a4def2a8c8fde24d147d39e70f60ee144e9425828f34eda2340c23ce72b1da"
+ }
+ },
+ {
+ "version": "1.6.2",
+ "changelog": "Ability to open app via URL schemes, displaying latency stats, and Virtual Studio device support. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.2",
+ "download": {
+ "date": "2022-08-17T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.2-Windows-x64-installer.msi",
+ "downloadSize": 43606016,
+ "sha256": "2bb06fe3624df447d56da0d72fef1f4328346fd92c6dffccf66ba37253ec5e62"
+ }
+ },
+ {
+ "version": "1.6.2-rc.3",
+ "changelog": "Ability to open app via URL schemes, displaying latency stats, and Virtual Studio device support. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.2-rc3",
+ "download": {
+ "date": "2022-08-15T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.2-rc3/JackTrip-v1.6.2-rc3-Windows-x64-installer.msi",
+ "downloadSize": 43606016,
+ "sha256": "62771ca5efbf2e91fa4cd347214e6e517b76c032a8895ca80bcbc2fa765ab81a"
+ }
+ },
+ {
+ "version": "1.6.2-rc.2",
+ "changelog": "Ability to open app via URL schemes, displaying latency stats, and Virtual Studio device support. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.2-rc2",
+ "download": {
+ "date": "2022-08-09T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.2-rc2/JackTrip-v1.6.2-rc2-Windows-x64-installer.msi",
+ "downloadSize": 43606016,
+ "sha256": "ff88acd1804362589478366a620d12be302071dba9781ea38ed6a8343c94c16d"
+ }
+ },
+ {
+ "version": "1.6.2-rc.1",
+ "changelog": "Ability to open app via URL schemes, displaying latency stats, and Virtual Studio device support. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.2-rc1",
+ "download": {
+ "date": "2022-08-06T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.2-rc1/JackTrip-v1.6.2-rc1-Windows-x64-installer.msi",
+ "downloadSize": 43601920,
+ "sha256": "f1412de0b13ff7599353a10aec8f2b69e9831a37103187f8fa68334c8f8f09de"
+ }
+ },
+ {
+ "version": "1.6.1",
+ "changelog": "Bugfixes around UDP timeout and 'Logging In' screen navigation. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.1",
+ "download": {
+ "date": "2022-06-21T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.1-Windows-x64-installer.msi",
+ "downloadSize": 43368448,
+ "sha256": "8eac390617488d849c0356e3305c96a59bbe46a8174d02b0321bb1dc86774b87"
+ }
+ },
+ {
+ "version": "1.6.0",
+ "changelog": "Full integration with JackTrip Virtual Studio. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.0",
+ "download": {
+ "date": "2022-06-01T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.0-Windows-x64-installer.msi",
+ "downloadSize": 43364352,
+ "sha256": "9562ab654202bfc432e05caa3bd2bf1d0b52c50581b0a567f0546983fe46c078"
+ }
+ },
+ {
+ "version": "1.6.0-rc.5",
+ "changelog": "Release candidate 5 for 1.6.0",
+ "download": {
+ "date": "2022-05-30T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.0-rc.5/JackTrip-v1.6.0-rc.5-Windows-x64-installer.msi",
+ "downloadSize": 43364352,
+ "sha256": "d84e6e5d21cf31f5dd48e9dcc0c1a44fe7a37d977f94b6ff63d5e381745e5a44"
+ }
+ },
+ {
+ "version": "1.6.0-rc.4",
+ "changelog": "Release candidate 4 for 1.6.0",
+ "download": {
+ "date": "2022-05-29T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.0-rc.4/JackTrip-v1.6.0-rc.4-Windows-x64-installer.msi",
+ "downloadSize": 43126784,
+ "sha256": "cdb0ef906cf0d6047289838bf013b31a626cdd74dd4f75d6c1c4c3adbc9cd41d"
+ }
+ },
+ {
+ "version": "1.6.0-rc.3",
+ "changelog": "Release candidate 3 for 1.6.0",
+ "download": {
+ "date": "2022-05-27T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.0-rc.3-Windows-x64-installer.msi",
+ "downloadSize": 43118592,
+ "sha256": "dceaf670a67cf1541007db82c5ce937b25370a7140e48192b94470f575fc4988"
+ }
+ },
+ {
+ "version": "1.6.0-rc.2",
+ "changelog": "Release candidate 2 for 1.6.0",
+ "download": {
+ "date": "2022-05-26T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.0-rc.2-Windows-x64-signed-installer.msi",
+ "downloadSize": 43114496,
+ "sha256": "b1a7adc8dc0fb47f59515790e8531dd10838d799bacb4b5653192ed621bca208"
+ }
+ },
+ {
+ "version": "1.6.0-rc.1",
+ "changelog": "Release candidate 1 for 1.6.0",
+ "download": {
+ "date": "2022-05-23T00:00:00Z",
+ "url": "https://github.com/jacktrip/jacktrip/releases/download/v1.6.0-rc.1/JackTrip-v1.6.0-rc.1-Windows-x64-installer.msi",
+ "downloadSize": 43081728,
+ "sha256": "240f8b495ec5057228be922da80829a3718b474bafc2ba2d77750643abd1005c"
+ }
+ }
+ ]
+}
{
- "app_name": "JackTrip",
- "releases": [
- {
- "version": "1.8.0",
- "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.8.0",
- "download": {
- "date": "2023-03-18T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.8.0-Linux-x64-binary.zip",
- "downloadSize": "36167636",
- "sha256": "6f14273ffd5526d576a184f4559adb4124def8760d0b9ba60c43b0fa75b2d1a5"
- }
- },
- {
- "version": "1.7.1",
- "changelog": "Video button, bug fixes, Linux build fixes, and Qt upgrades: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.1",
- "download": {
- "date": "2023-02-10T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.7.1-Linux-x64-binary.zip",
- "downloadSize": 34338503,
- "sha256": "4298e1edd561815630e3c6573660eeea15b199a12742ab1b90d43a6e3522b632"
- }
- },
- {
- "version": "1.7.0",
- "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.0",
- "download": {
- "date": "2023-01-24T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.7.0-Linux-x64-binary.zip",
- "downloadSize": 32554865,
- "sha256": "13b3781f6dca0713eb135c9352c23cf0f40094603357ee5d5a940868597e8bb8"
- }
- },
- {
- "version": "1.6.8",
- "changelog": "Critical bug fix: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.8",
- "download": {
- "date": "2022-12-05T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.8-Linux-x64-binary.zip",
- "downloadSize": 30496801,
- "sha256": "c2fcbf86f8ad4db862431f9ccf6b52b275b3cf5fc3bc2f7eea7ac803ee7ca590"
- }
- },
- {
- "version": "1.6.7",
- "changelog": "Updated Windows networking, enabling all audio devices on Windows, new default device behavior, and fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.7",
- "download": {
- "date": "2022-12-02T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.7-Linux-x64-binary.zip",
- "downloadSize": 30495373,
- "sha256": "09421562aeeefe40bb15945bf1e8e03b3f905ea383ce0a9ddd1f93f099141cfd"
- }
- },
- {
- "version": "1.6.6",
- "changelog": "Adding volume controls in Virtual Studio, preliminary QT6 support, classic mode GUI updates, and fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.6",
- "download": {
- "date": "2022-11-02T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.6-Linux-x64-binary.zip",
- "downloadSize": 29837298,
- "sha256": "25b15f3208521530b18e2096de722fefe5318149aa296610f8c5eec147586e0a"
- }
- },
- {
- "version": "1.6.4",
- "changelog": "Adding volume meters, bugfixes around Windows hanging, device disconnects, and PLC: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.4",
- "download": {
- "date": "2022-09-16T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.4-Linux-x64-binary.zip",
- "downloadSize": 22233485,
- "sha256": "f1b9585e4eb72c07c735ee6f4dc94ad1d1a4c70474799eb1111bb5a39a99e295"
- }
- }
- ]
+ "app_name": "JackTrip",
+ "releases": [
+ {
+ "version": "1.8.1",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.8.1",
+ "download": {
+ "date": "2023-04-03T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.8.1-Linux-x64-binary.zip",
+ "downloadSize": "36128967",
+ "sha256": "c0c082942ae2010553ba01c51c23b4ba01d8e5d4f69d3d2d2e56e183156d6f07"
+ }
+ },
+ {
+ "version": "1.8.0",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.8.0",
+ "download": {
+ "date": "2023-03-18T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.8.0-Linux-x64-binary.zip",
+ "downloadSize": "36167636",
+ "sha256": "6f14273ffd5526d576a184f4559adb4124def8760d0b9ba60c43b0fa75b2d1a5"
+ }
+ },
+ {
+ "version": "1.7.1",
+ "changelog": "Video button, bug fixes, Linux build fixes, and Qt upgrades: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.1",
+ "download": {
+ "date": "2023-02-10T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.7.1-Linux-x64-binary.zip",
+ "downloadSize": 34338503,
+ "sha256": "4298e1edd561815630e3c6573660eeea15b199a12742ab1b90d43a6e3522b632"
+ }
+ },
+ {
+ "version": "1.7.0",
+ "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.0",
+ "download": {
+ "date": "2023-01-24T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.7.0-Linux-x64-binary.zip",
+ "downloadSize": 32554865,
+ "sha256": "13b3781f6dca0713eb135c9352c23cf0f40094603357ee5d5a940868597e8bb8"
+ }
+ },
+ {
+ "version": "1.6.8",
+ "changelog": "Critical bug fix: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.8",
+ "download": {
+ "date": "2022-12-05T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.8-Linux-x64-binary.zip",
+ "downloadSize": 30496801,
+ "sha256": "c2fcbf86f8ad4db862431f9ccf6b52b275b3cf5fc3bc2f7eea7ac803ee7ca590"
+ }
+ },
+ {
+ "version": "1.6.7",
+ "changelog": "Updated Windows networking, enabling all audio devices on Windows, new default device behavior, and fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.7",
+ "download": {
+ "date": "2022-12-02T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.7-Linux-x64-binary.zip",
+ "downloadSize": 30495373,
+ "sha256": "09421562aeeefe40bb15945bf1e8e03b3f905ea383ce0a9ddd1f93f099141cfd"
+ }
+ },
+ {
+ "version": "1.6.6",
+ "changelog": "Adding volume controls in Virtual Studio, preliminary QT6 support, classic mode GUI updates, and fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.6",
+ "download": {
+ "date": "2022-11-02T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.6-Linux-x64-binary.zip",
+ "downloadSize": 29837298,
+ "sha256": "25b15f3208521530b18e2096de722fefe5318149aa296610f8c5eec147586e0a"
+ }
+ },
+ {
+ "version": "1.6.4",
+ "changelog": "Adding volume meters, bugfixes around Windows hanging, device disconnects, and PLC: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.4",
+ "download": {
+ "date": "2022-09-16T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.4-Linux-x64-binary.zip",
+ "downloadSize": 22233485,
+ "sha256": "f1b9585e4eb72c07c735ee6f4dc94ad1d1a4c70474799eb1111bb5a39a99e295"
+ }
+ }
+ ]
}
{
- "app_name": "JackTrip",
- "releases": [
- {
- "version": "1.8.0",
- "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.8.0",
- "download": {
- "date": "2023-03-18T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.8.0-macOS-x64-signed-installer.pkg",
- "downloadSize": "11771203",
- "sha256": "dfee21d5e91a35baaf3b58891188f72f2cb894b2bf796ac70350a2ef9d3fb68c"
- }
- },
- {
- "version": "1.7.1",
- "changelog": "Video button, bug fixes, Linux build fixes, and Qt upgrades: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.1",
- "download": {
- "date": "2023-02-10T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.7.1-macOS-x64-installer.pkg",
- "downloadSize": 11679783,
- "sha256": "027d1d3aeb4aaca79b21824371a0bfb915b8c43afe924a8ec2be92df719a431f"
- }
- },
- {
- "version": "1.7.0",
- "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.0",
- "download": {
- "date": "2023-01-24T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.7.0-macOS-x64-installer.pkg",
- "downloadSize": 11530594,
- "sha256": "0e5731c2ad71aa4bd28ccf9311e312f2386c42b02abbca142777dfb06ea1b427"
- }
- },
- {
- "version": "1.6.8",
- "changelog": "Critical bug fix: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.8",
- "download": {
- "date": "2022-12-05T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.8-macOS-x64-installer.pkg",
- "downloadSize": 11517093,
- "sha256": "5c040b2caa1e7dea97d7f48fd888f532a1c30da7385535b2d4a2805551bc5f71"
- }
- },
- {
- "version": "1.6.7",
- "changelog": "Updated Windows networking, enabling all audio devices on Windows, new default device behavior, and fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.7",
- "download": {
- "date": "2022-12-02T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.7-macOS-x64-installer.pkg",
- "downloadSize": 11517151,
- "sha256": "38c25788895ec404bdb4b6148114cad8af31b65e5189ca08819d1e954e2ef4e7"
- }
- },
- {
- "version": "1.6.6",
- "changelog": "Adding volume controls in Virtual Studio, preliminary QT6 support, classic mode GUI updates, and fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.6",
- "download": {
- "date": "2022-11-02T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.6-macOS-x64-installer.pkg",
- "downloadSize": 11481324,
- "sha256": "e99149ea9bbfb94a2000cfd3848013e44bb8d23e783198005681c2038bcbd313"
- }
- },
- {
- "version": "1.6.4",
- "changelog": "Adding volume meters, bugfixes around Windows hanging, device disconnects, and PLC: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.4",
- "download": {
- "date": "2022-09-16T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.4-macOS-x64-installer.pkg",
- "downloadSize": 11554866,
- "sha256": "e5898f3ff57fc2d734590decb4f82a28ad9208a33cad97152f119716cdcea1a9"
- }
- },
- {
- "version": "1.6.3",
- "changelog": "Fixes around Linux desktop file and hub server mode: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.3",
- "download": {
- "date": "2022-08-23T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.3-macOS-x64-installer.pkg",
- "downloadSize": 11533023,
- "sha256": "0b597c62544e9813949f859cc7b7c13bef893f6896f96b34a19889faf4855116"
- }
- },
- {
- "version": "1.6.2",
- "changelog": "Ability to open app via URL schemes, displaying latency stats, and Virtual Studio device support. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.2",
- "download": {
- "date": "2022-08-17T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.2-macOS-x64-installer.pkg",
- "downloadSize": 11536442,
- "sha256": "450222f4db1922275e07286d0be6ea2df2873a8a39c3b23096bcfbce342b7b3c"
- }
- },
- {
- "version": "1.6.1",
- "changelog": "Bugfixes around UDP timeout and 'Logging In' screen navigation. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.1",
- "download": {
- "date": "2022-06-21T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.1-macOS-x64-installer.pkg",
- "downloadSize": 11476305,
- "sha256": "eaf05c842d6b3ae799208a40b37da1cdb13e3700dcbbd97443c80cad81f4d2ac"
- }
- },
- {
- "version": "1.6.0",
- "changelog": "Full integration with JackTrip Virtual Studio. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.0",
- "download": {
- "date": "2022-06-01T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.0-macOS-x64-installer.pkg",
- "downloadSize": 11474299,
- "sha256": "27259600ecd879106ebbf97754d72d6236075a049eafa0de6271d33f753f13e4"
- }
- }
- ]
-}
\ No newline at end of file
+ "app_name": "JackTrip",
+ "releases": [
+ {
+ "version": "1.8.1",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.8.1",
+ "download": {
+ "date": "2023-04-03T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.8.1-macOS-x64-signed-installer.pkg",
+ "downloadSize": "11754694",
+ "sha256": "d073ff5f2b90b5dd86ccd07c5d30d61d7be776c5e3c0083e6f665f78fea48298"
+ }
+ },
+ {
+ "version": "1.8.0",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.8.0",
+ "download": {
+ "date": "2023-03-18T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.8.0-macOS-x64-signed-installer.pkg",
+ "downloadSize": "11771203",
+ "sha256": "dfee21d5e91a35baaf3b58891188f72f2cb894b2bf796ac70350a2ef9d3fb68c"
+ }
+ },
+ {
+ "version": "1.7.1",
+ "changelog": "Video button, bug fixes, Linux build fixes, and Qt upgrades: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.1",
+ "download": {
+ "date": "2023-02-10T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.7.1-macOS-x64-installer.pkg",
+ "downloadSize": 11679783,
+ "sha256": "027d1d3aeb4aaca79b21824371a0bfb915b8c43afe924a8ec2be92df719a431f"
+ }
+ },
+ {
+ "version": "1.7.0",
+ "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.0",
+ "download": {
+ "date": "2023-01-24T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.7.0-macOS-x64-installer.pkg",
+ "downloadSize": 11530594,
+ "sha256": "0e5731c2ad71aa4bd28ccf9311e312f2386c42b02abbca142777dfb06ea1b427"
+ }
+ },
+ {
+ "version": "1.6.8",
+ "changelog": "Critical bug fix: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.8",
+ "download": {
+ "date": "2022-12-05T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.8-macOS-x64-installer.pkg",
+ "downloadSize": 11517093,
+ "sha256": "5c040b2caa1e7dea97d7f48fd888f532a1c30da7385535b2d4a2805551bc5f71"
+ }
+ },
+ {
+ "version": "1.6.7",
+ "changelog": "Updated Windows networking, enabling all audio devices on Windows, new default device behavior, and fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.7",
+ "download": {
+ "date": "2022-12-02T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.7-macOS-x64-installer.pkg",
+ "downloadSize": 11517151,
+ "sha256": "38c25788895ec404bdb4b6148114cad8af31b65e5189ca08819d1e954e2ef4e7"
+ }
+ },
+ {
+ "version": "1.6.6",
+ "changelog": "Adding volume controls in Virtual Studio, preliminary QT6 support, classic mode GUI updates, and fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.6",
+ "download": {
+ "date": "2022-11-02T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.6-macOS-x64-installer.pkg",
+ "downloadSize": 11481324,
+ "sha256": "e99149ea9bbfb94a2000cfd3848013e44bb8d23e783198005681c2038bcbd313"
+ }
+ },
+ {
+ "version": "1.6.4",
+ "changelog": "Adding volume meters, bugfixes around Windows hanging, device disconnects, and PLC: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.4",
+ "download": {
+ "date": "2022-09-16T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.4-macOS-x64-installer.pkg",
+ "downloadSize": 11554866,
+ "sha256": "e5898f3ff57fc2d734590decb4f82a28ad9208a33cad97152f119716cdcea1a9"
+ }
+ },
+ {
+ "version": "1.6.3",
+ "changelog": "Fixes around Linux desktop file and hub server mode: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.3",
+ "download": {
+ "date": "2022-08-23T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.3-macOS-x64-installer.pkg",
+ "downloadSize": 11533023,
+ "sha256": "0b597c62544e9813949f859cc7b7c13bef893f6896f96b34a19889faf4855116"
+ }
+ },
+ {
+ "version": "1.6.2",
+ "changelog": "Ability to open app via URL schemes, displaying latency stats, and Virtual Studio device support. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.2",
+ "download": {
+ "date": "2022-08-17T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.2-macOS-x64-installer.pkg",
+ "downloadSize": 11536442,
+ "sha256": "450222f4db1922275e07286d0be6ea2df2873a8a39c3b23096bcfbce342b7b3c"
+ }
+ },
+ {
+ "version": "1.6.1",
+ "changelog": "Bugfixes around UDP timeout and 'Logging In' screen navigation. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.1",
+ "download": {
+ "date": "2022-06-21T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.1-macOS-x64-installer.pkg",
+ "downloadSize": 11476305,
+ "sha256": "eaf05c842d6b3ae799208a40b37da1cdb13e3700dcbbd97443c80cad81f4d2ac"
+ }
+ },
+ {
+ "version": "1.6.0",
+ "changelog": "Full integration with JackTrip Virtual Studio. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.0",
+ "download": {
+ "date": "2022-06-01T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.0-macOS-x64-installer.pkg",
+ "downloadSize": 11474299,
+ "sha256": "27259600ecd879106ebbf97754d72d6236075a049eafa0de6271d33f753f13e4"
+ }
+ }
+ ]
+}
{
- "app_name": "JackTrip",
- "releases": [
- {
- "version": "1.8.0",
- "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.8.0",
- "download": {
- "date": "2023-03-18T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.8.0-Windows-x64-signed-installer.msi",
- "downloadSize": "45699072",
- "sha256": "4b6705a2e8af7f9a516fefaf119d5e6cadf93e8f40964cd52b635ced5745b267"
- }
- },
- {
- "version": "1.7.1",
- "changelog": "Video button, bug fixes, Linux build fixes, and Qt upgrades: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.1",
- "download": {
- "date": "2023-02-10T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.7.1-Windows-x64-installer.msi",
- "downloadSize": 45330432,
- "sha256": "fb5d756afcd471ca8ae45b05b411235026f23f2178893d85ac12f39c3f66a01a"
- }
- },
- {
- "version": "1.7.0",
- "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.0",
- "download": {
- "date": "2023-01-24T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.7.0-Windows-x64-installer.msi",
- "downloadSize": 44572672,
- "sha256": "a1890fe10de484f423a17118031d898abacc9b9eb2ccd35bdb4351e9411ff866"
- }
- },
- {
- "version": "1.6.8",
- "changelog": "Critical bug fix: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.8",
- "download": {
- "date": "2022-12-05T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.8-Windows-x64-installer.msi",
- "downloadSize": 44539904,
- "sha256": "e4ac16e7a66b4d656eea4e88f703fe156d656aedc16ad7f63ec570d82c27ed54"
- }
- },
- {
- "version": "1.6.7",
- "changelog": "Updated Windows networking, enabling all audio devices on Windows, new default device behavior, and fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.7",
- "download": {
- "date": "2022-12-02T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.7-Windows-x64-installer.msi",
- "downloadSize": 44535808,
- "sha256": "75464575311da5521e011da8d2f2b5aff1379edb4dee9dcb90e1750dcc97f2f9"
- }
- },
- {
- "version": "1.6.6",
- "changelog": "Adding volume controls in Virtual Studio, preliminary QT6 support, classic mode GUI updates, and fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.6",
- "download": {
- "date": "2022-11-02T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.6-Windows-x64-installer.msi",
- "downloadSize": 44408832,
- "sha256": "828a1f43254db187a33601cc809551617db83e60a51dad3e992c30270967de0c"
- }
- },
- {
- "version": "1.6.4",
- "changelog": "Adding volume meters, bugfixes around Windows hanging, device disconnects, and PLC: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.4",
- "download": {
- "date": "2022-09-16T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.4-Windows-x64-installer.msi",
- "downloadSize": 43663360,
- "sha256": "58dcbba584e1cc82373b8aa159800ad360eec7933ce9462e413ca347f09f3c26"
- }
- },
- {
- "version": "1.6.3",
- "changelog": "Fixes around Linux desktop file and hub server mode: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.3",
- "download": {
- "date": "2022-08-23T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.3-Windows-x64-installer.msi",
- "downloadSize": 43606016,
- "sha256": "83a4def2a8c8fde24d147d39e70f60ee144e9425828f34eda2340c23ce72b1da"
- }
- },
- {
- "version": "1.6.2",
- "changelog": "Ability to open app via URL schemes, displaying latency stats, and Virtual Studio device support. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.2",
- "download": {
- "date": "2022-08-17T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.2-Windows-x64-installer.msi",
- "downloadSize": 43606016,
- "sha256": "2bb06fe3624df447d56da0d72fef1f4328346fd92c6dffccf66ba37253ec5e62"
- }
- },
- {
- "version": "1.6.1",
- "changelog": "Bugfixes around UDP timeout and 'Logging In' screen navigation. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.1",
- "download": {
- "date": "2022-06-21T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.1-Windows-x64-installer.msi",
- "downloadSize": 43368448,
- "sha256": "8eac390617488d849c0356e3305c96a59bbe46a8174d02b0321bb1dc86774b87"
- }
- },
- {
- "version": "1.6.0",
- "changelog": "Full integration with JackTrip Virtual Studio. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.0",
- "download": {
- "date": "2022-06-01T00:00:00Z",
- "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.0-Windows-x64-installer.msi",
- "downloadSize": 43364352,
- "sha256": "9562ab654202bfc432e05caa3bd2bf1d0b52c50581b0a567f0546983fe46c078"
- }
- }
- ]
-}
\ No newline at end of file
+ "app_name": "JackTrip",
+ "releases": [
+ {
+ "version": "1.8.1",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.8.1",
+ "download": {
+ "date": "2023-04-03T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.8.1-Windows-x64-signed-installer.msi",
+ "downloadSize": "46456832",
+ "sha256": "55da405ea55a3567a672eef0f5f3699c264f456e13dd04d2a55d90bd3d1a2f55"
+ }
+ },
+ {
+ "version": "1.8.0",
+ "changelog": "Full changelog at https://github.com/jacktrip/jacktrip/releases/tag/v1.8.0",
+ "download": {
+ "date": "2023-03-18T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.8.0-Windows-x64-signed-installer.msi",
+ "downloadSize": "45699072",
+ "sha256": "4b6705a2e8af7f9a516fefaf119d5e6cadf93e8f40964cd52b635ced5745b267"
+ }
+ },
+ {
+ "version": "1.7.1",
+ "changelog": "Video button, bug fixes, Linux build fixes, and Qt upgrades: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.1",
+ "download": {
+ "date": "2023-02-10T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.7.1-Windows-x64-installer.msi",
+ "downloadSize": 45330432,
+ "sha256": "fb5d756afcd471ca8ae45b05b411235026f23f2178893d85ac12f39c3f66a01a"
+ }
+ },
+ {
+ "version": "1.7.0",
+ "changelog": "Start/join inactive studios, fix crashes and hanging UI on Windows: https://github.com/jacktrip/jacktrip/releases/tag/v1.7.0",
+ "download": {
+ "date": "2023-01-24T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.7.0-Windows-x64-installer.msi",
+ "downloadSize": 44572672,
+ "sha256": "a1890fe10de484f423a17118031d898abacc9b9eb2ccd35bdb4351e9411ff866"
+ }
+ },
+ {
+ "version": "1.6.8",
+ "changelog": "Critical bug fix: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.8",
+ "download": {
+ "date": "2022-12-05T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.8-Windows-x64-installer.msi",
+ "downloadSize": 44539904,
+ "sha256": "e4ac16e7a66b4d656eea4e88f703fe156d656aedc16ad7f63ec570d82c27ed54"
+ }
+ },
+ {
+ "version": "1.6.7",
+ "changelog": "Updated Windows networking, enabling all audio devices on Windows, new default device behavior, and fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.7",
+ "download": {
+ "date": "2022-12-02T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.7-Windows-x64-installer.msi",
+ "downloadSize": 44535808,
+ "sha256": "75464575311da5521e011da8d2f2b5aff1379edb4dee9dcb90e1750dcc97f2f9"
+ }
+ },
+ {
+ "version": "1.6.6",
+ "changelog": "Adding volume controls in Virtual Studio, preliminary QT6 support, classic mode GUI updates, and fixes: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.6",
+ "download": {
+ "date": "2022-11-02T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.6-Windows-x64-installer.msi",
+ "downloadSize": 44408832,
+ "sha256": "828a1f43254db187a33601cc809551617db83e60a51dad3e992c30270967de0c"
+ }
+ },
+ {
+ "version": "1.6.4",
+ "changelog": "Adding volume meters, bugfixes around Windows hanging, device disconnects, and PLC: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.4",
+ "download": {
+ "date": "2022-09-16T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.4-Windows-x64-installer.msi",
+ "downloadSize": 43663360,
+ "sha256": "58dcbba584e1cc82373b8aa159800ad360eec7933ce9462e413ca347f09f3c26"
+ }
+ },
+ {
+ "version": "1.6.3",
+ "changelog": "Fixes around Linux desktop file and hub server mode: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.3",
+ "download": {
+ "date": "2022-08-23T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.3-Windows-x64-installer.msi",
+ "downloadSize": 43606016,
+ "sha256": "83a4def2a8c8fde24d147d39e70f60ee144e9425828f34eda2340c23ce72b1da"
+ }
+ },
+ {
+ "version": "1.6.2",
+ "changelog": "Ability to open app via URL schemes, displaying latency stats, and Virtual Studio device support. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.2",
+ "download": {
+ "date": "2022-08-17T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.2-Windows-x64-installer.msi",
+ "downloadSize": 43606016,
+ "sha256": "2bb06fe3624df447d56da0d72fef1f4328346fd92c6dffccf66ba37253ec5e62"
+ }
+ },
+ {
+ "version": "1.6.1",
+ "changelog": "Bugfixes around UDP timeout and 'Logging In' screen navigation. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.1",
+ "download": {
+ "date": "2022-06-21T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.1-Windows-x64-installer.msi",
+ "downloadSize": 43368448,
+ "sha256": "8eac390617488d849c0356e3305c96a59bbe46a8174d02b0321bb1dc86774b87"
+ }
+ },
+ {
+ "version": "1.6.0",
+ "changelog": "Full integration with JackTrip Virtual Studio. Learn more here: https://github.com/jacktrip/jacktrip/releases/tag/v1.6.0",
+ "download": {
+ "date": "2022-06-01T00:00:00Z",
+ "url": "https://files.jacktrip.org/app-builds/JackTrip-v1.6.0-Windows-x64-installer.msi",
+ "downloadSize": 43364352,
+ "sha256": "9562ab654202bfc432e05caa3bd2bf1d0b52c50581b0a567f0546983fe46c078"
+ }
+ }
+ ]
+}
--- /dev/null
+#!/bin/bash
+
+EDGE_PLATFORMS="mac win"
+STABLE_PLATFORMS="$EDGE_PLATFORMS linux"
+
+function update_manifest {
+ NAME="$1/$2-manifests.json"
+ echo "Updating $NAME"
+ curl -s -o "releases/$NAME" "https://files.jacktrip.org/app-releases/$NAME"
+}
+
+for x in $EDGE_PLATFORMS
+do
+ update_manifest edge $x
+done
+
+for y in $STABLE_PLATFORMS
+do
+ update_manifest stable $y
+done
#ifndef WAIR
// cc
// Initialize and assign memory for ProcessPlugins Buffers
+ int monitorChans = std::min(mInputChans.size(), mOutputChans.size());
mInProcessBuffer.resize(mInputChans.size());
mOutProcessBuffer.resize(mOutputChans.size());
+ mMonProcessBuffer.resize(monitorChans);
// Set pointer to NULL
for (int i = 0; i < mInProcessBuffer.size(); i++) {
mInProcessBuffer[i] = NULL;
for (int i = 0; i < mOutProcessBuffer.size(); i++) {
mOutProcessBuffer[i] = NULL;
}
+ for (int i = 0; i < monitorChans; i++) {
+ mMonProcessBuffer[i] = NULL;
+ }
#else // WAIR
int iCnt =
(mInputChans.size() > mNumNetRevChans) ? mInputChans.size() : mNumNetRevChans;
int oCnt =
(mOutputChans.size() > mNumNetRevChans) ? mOutputChans.size() : mNumNetRevChans;
int aCnt = (mNumNetRevChans) ? mInputChans.size() : 0;
+ int mCnt = std::min(iCnt, oCnt);
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 < mCnt; i++) {
+ mMonProcessBuffer[i] = NULL;
+ }
for (int i = 0; i < aCnt; i++) {
mAPInBuffer[i] = NULL;
}
new sample_t[MAX_AUDIO_BUFFER_SIZE]; // required for processing audio input
}
+ // Not used in this class but may be needed by subclasses
mNumInChans = mInputChans.size();
mNumOutChans = mOutputChans.size();
}
for (int i = 0; i < mOutProcessBuffer.size(); i++) {
delete[] mOutProcessBuffer[i];
}
+ for (int i = 0; i < mMonProcessBuffer.size(); i++) {
+ delete[] mMonProcessBuffer[i];
+ }
#else // WAIR
for (int i = 0; i < mInProcessBuffer.size(); i++) {
delete[] mInProcessBuffer[i];
for (int i = 0; i < mOutProcessBuffer.size(); i++) {
delete[] mOutProcessBuffer[i];
}
+ for (int i = 0; i < mMonProcessBuffer.size(); i++) {
+ delete[] mMonProcessBuffer[i];
+ }
for (int i = 0; i < mAPInBuffer.size(); i++) {
delete[] mAPInBuffer[i];
}
for (auto* i : qAsConst(mProcessPluginsToNetwork)) {
delete i;
}
+ for (auto* i : qAsConst(mProcessPluginsToMonitor)) {
+ delete i;
+ }
for (int i = 0; i < mInBufCopy.size(); i++) {
delete[] mInBufCopy[i];
}
//*******************************************************************************
void AudioInterface::setup(bool /*verbose*/)
{
- int nChansIn = mInputChans.size();
- int nChansOut = mOutputChans.size();
+ int nChansIn = mInputChans.size();
+ int nChansOut = mOutputChans.size();
+ int nChansMon =
+ std::min(nChansIn, nChansOut); // Note: Should be 2 when mixing stereo-to-mono
inputMixModeT inputMixMode = mInputMixMode;
if (inputMixMode == MIXTOMONO) {
nChansIn = 1;
}
-
+ if (inputMixMode == MONO) {
+ nChansMon = nChansOut;
+ }
// Allocate buffer memory to read and write
mSizeInBytesPerChannel = getSizeInBytesPerChannel();
if (mNumNetRevChans) {
mInProcessBuffer.resize(mNumNetRevChans);
mOutProcessBuffer.resize(mNumNetRevChans);
+ mMonProcessBuffer.resize(mNumNetRevChans);
mAPInBuffer.resize(nChansIn);
mNetInBuffer.resize(mNumNetRevChans);
} else // don't change sizes
{
mInProcessBuffer.resize(nChansIn);
mOutProcessBuffer.resize(nChansOut);
+ mMonProcessBuffer.resize(nChansMon);
}
int nframes = getBufferSizeInSamples();
// set memory to 0
std::memset(mOutProcessBuffer[i], 0, sizeof(sample_t) * nframes);
}
+ for (int i = 0; i < nChansMon; i++) {
+ mMonProcessBuffer[i] = new sample_t[nframes];
+ // set memory to 0
+ std::memset(mMonProcessBuffer[i], 0, sizeof(sample_t) * nframes);
+ }
#else // WAIR
for (int i = 0; i < ((mNumNetRevChans) ? mNumNetRevChans : nChansIn); i++) {
mInProcessBuffer[i] = new sample_t[nframes];
// set memory to 0
std::memset(mOutProcessBuffer[i], 0, sizeof(sample_t) * nframes);
}
+ for (int i = 0; i < ((mNumNetRevChans) ? mNumNetRevChans : nChansMon); i++) {
+ mMonProcessBuffer[i] = new sample_t[nframes];
+ // set memory to 0
+ std::memset(mMonitorProcess[i], 0, sizeof(sample_t) * nframes);
+ }
for (int i = 0; i < ((mNumNetRevChans) ? nChansIn : 0); i++) {
mAPInBuffer[i] = new sample_t[nframes];
// set memory to 0
QVarLengthArray<sample_t*>& out_buffer,
unsigned int n_frames)
{
- int nChansIn = mInputChans.size();
+ int nChansIn = mInputChans.size();
+ int nChansOut = mOutputChans.size();
+ int nChansMon =
+ std::min(nChansIn, nChansOut); // Note: Should be 2 when mixing stereo-to-mono
inputMixModeT inputMixMode = mInputMixMode;
if (inputMixMode == MIXTOMONO) {
nChansIn = 1;
}
+ if (inputMixMode == MONO) {
+ nChansMon = nChansOut;
+ }
// Allocate the Process Callback
//-------------------------------------------------------------------
// 1) First, process incoming packets
// 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
+ if (nop > 0 || audioTesting
+ || mProcessPluginsToMonitor.size()
+ > 0) { // cannot modify in_buffer, so make a copy
// in_buffer is "in" from local audio hardware via JACK
if (mInBufCopy.size() < nChansIn) { // created in constructor above
std::cerr << "*** AudioInterface.cpp: Number of Input Channels changed - "
p->compute(n_frames, mInBufCopy.data(), mInBufCopy.data());
}
}
+
+ for (int i = 0; i < nChansMon; i++) {
+ if ((mInputChans.size() == 2 && mInputMixMode == AudioInterface::MIXTOMONO)
+ || (mInputMixMode == AudioInterface::MONO)) {
+ // if using mix-to-mono, in_buffer[0] should already contain the mixed
+ // audio, so copy it to the monitor buffer. See RtAudioInterface.cpp
+
+ // likewise if using mono, we simply copy the input to every monitor
+ // channel
+ std::memcpy(mMonProcessBuffer[i], in_buffer[0],
+ sizeof(sample_t) * n_frames);
+ } else {
+ // otherwise, copy each channel individually
+ std::memcpy(mMonProcessBuffer[i], in_buffer[i],
+ sizeof(sample_t) * n_frames);
+ }
+ }
+ for (int i = 0; i < mProcessPluginsToMonitor.size(); i++) {
+ ProcessPlugin* p = mProcessPluginsToMonitor[i];
+ if (p->getInited()) {
+ // note: for monitor plugins, the output is out_buffer (to the speakers)
+ p->compute(n_frames, mMonProcessBuffer.data(), out_buffer.data());
+ }
+ }
+
if (audioTesting) {
mAudioTesterP->writeImpulse(
mInBufCopy,
mProcessPluginsFromNetwork.append(plugin);
}
-void AudioInterface::initPlugins(bool verbose)
+void AudioInterface::appendProcessPluginToMonitor(ProcessPlugin* plugin)
{
- int nChansIn = mInputChans.size();
- int nChansOut = mOutputChans.size();
+ if (not plugin) {
+ return;
+ }
+ int nChansIn = mInputChans.size();
+ int nChansOut = mOutputChans.size();
+ int nChansMon =
+ std::min(nChansIn, nChansOut); // Note: Should be 2 when mixing stereo-to-mono
inputMixModeT inputMixMode = mInputMixMode;
if (inputMixMode == MIXTOMONO) {
nChansIn = 1;
}
+ if (inputMixMode == MONO) {
+ nChansMon = nChansOut;
+ }
+ if (plugin->getNumInputs() > nChansMon) {
+ std::cerr
+ << "*** AudioInterface.cpp: appendProcessPluginToMonitor: ProcessPlugin "
+ << typeid(plugin).name() << " REJECTED due to having "
+ << plugin->getNumInputs()
+ << " inputs, while the monitor audio input requires " << nChansMon
+ << " outputs\n";
+ return;
+ }
- int nPlugins = mProcessPluginsFromNetwork.size() + mProcessPluginsToNetwork.size();
+ if (plugin->getNumOutputs() > nChansMon) {
+ std::cerr
+ << "*** AudioInterface.cpp: appendProcessPluginToMonitor: ProcessPlugin "
+ << typeid(plugin).name() << " REJECTED due to having "
+ << plugin->getNumOutputs()
+ << " inputs, while the monitor audio output requires " << nChansMon
+ << " outputs\n";
+ return;
+ }
+
+ mProcessPluginsToMonitor.append(plugin);
+}
+
+void AudioInterface::initPlugins(bool verbose)
+{
+ int nChansIn = mInputChans.size();
+ int nChansOut = mOutputChans.size();
+ int nChansMon =
+ std::min(nChansIn, nChansOut); // Note: Should be 2 when mixing stereo-to-mono
+ inputMixModeT inputMixMode = mInputMixMode;
+ if (inputMixMode == MIXTOMONO) {
+ nChansIn = 1;
+ }
+ if (inputMixMode == MONO) {
+ nChansMon = nChansOut;
+ }
+ int nPlugins = mProcessPluginsFromNetwork.size() + mProcessPluginsToNetwork.size()
+ + mProcessPluginsToMonitor.size();
if (nPlugins > 0) {
if (verbose) {
std::cout << "Initializing Faust plugins (have " << nPlugins
plugin->updateNumChannels(nChansIn, nChansOut);
plugin->init(mSampleRate);
}
+ for (ProcessPlugin* plugin : qAsConst(mProcessPluginsToMonitor)) {
+ plugin->setOutgoingToNetwork(false);
+ plugin->updateNumChannels(nChansMon, nChansMon);
+ plugin->init(mSampleRate);
+ }
}
}
switch (msg) {
case DEVICE_WARN_LATENCY:
mWarningMsg =
- "The currently selected devices don't support low latency. You can use them, "
- "but you "
- "may experience audio delay. Make sure you have up to date drivers from the "
- "manufacturer!";
+ "The selected Input and Output devices are Non-ASIO and may cause high "
+ "latency or audio delay. Installing ASIO drivers and using ASIO Input and "
+ "Output devices will lower audio delays for a 'same room experience'.";
#ifdef _WIN32
mWarningHelpUrl = "https://help.jacktrip.org/hc/en-us/articles/4409919243155";
#else
mErrorMsg = "JackTrip couldn't find any audio devices!";
mErrorHelpUrl = "";
break;
+#ifdef _WIN32
+ case DEVICE_ERR_SAME_ASIO:
+ mErrorMsg =
+ "When using ASIO, please select the same device for your input and output.";
+ mErrorHelpUrl = "https://help.jacktrip.org/hc/en-us/articles/4409919243155";
+ break;
+#endif
default:
mErrorMsg = "";
mErrorHelpUrl = "";
DEVICE_ERR_INCOMPATIBLE,
DEVICE_ERR_NO_INPUTS,
DEVICE_ERR_NO_OUTPUTS,
- DEVICE_ERR_NO_DEVICES
+ DEVICE_ERR_NO_DEVICES,
+#ifdef _WIN32
+ DEVICE_ERR_SAME_ASIO
+#endif
};
enum inputMixModeT : int {
* Initialize all ProcessPlugin modules.
* The audio sampling rate (mSampleRate) must be set at this time.
*/
+ virtual void appendProcessPluginToMonitor(ProcessPlugin* plugin);
+ /** \brief appendProcessPluginFromNetwork():
+ * Appends plugins used for local monitoring
+ */
void initPlugins(bool verbose = true);
virtual void connectDefaultPorts() = 0;
/** \brief Convert a 32bit number (sample_t) into one of the bit resolution
mProcessPluginsFromNetwork; ///< Vector of ProcessPlugin<EM>s</EM>
QVector<ProcessPlugin*>
mProcessPluginsToNetwork; ///< Vector of ProcessPlugin<EM>s</EM>
+ QVector<ProcessPlugin*>
+ mProcessPluginsToMonitor; ///< 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
+ mOutProcessBuffer; ///< Vector of Output buffers/channel for ProcessPlugin
+ QVarLengthArray<sample_t*>
+ mMonProcessBuffer; ///< Vector of Monitor 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
#include "Compressor.h"
+#include "compressordsp.h"
+
+//*******************************************************************************
+Compressor::Compressor(int numchans, // xtor
+ bool verboseIn, float ratioIn, float thresholdDBIn,
+ float attackMSIn, float releaseMSIn, float makeUpGainDBIn)
+ : 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++) {
+ compressordsp* dsp_ptr = new compressordsp;
+ APIUI* ui_ptr = new APIUI;
+ compressorP.push_back(dsp_ptr);
+ compressorUIP.push_back(ui_ptr); // #included in compressordsp.h
+ dsp_ptr->buildUserInterface(ui_ptr);
+ }
+}
+
+//*******************************************************************************
+Compressor::~Compressor()
+{
+ for (int i = 0; i < mNumChannels; i++) {
+ delete static_cast<compressordsp*>(compressorP[i]);
+ delete static_cast<APIUI*>(compressorUIP[i]);
+ }
+ compressorP.clear();
+ compressorUIP.clear();
+}
+
+//*******************************************************************************
+void Compressor::setParamAllChannels(const char pName[], float p)
+{
+ for (int i = 0; i < mNumChannels; i++) {
+ APIUI* ui_ptr = static_cast<APIUI*>(compressorUIP[i]);
+ int ndx = ui_ptr->getParamIndex(pName);
+ if (ndx >= 0) {
+ ui_ptr->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";
+ }
+ }
+}
+
+//*******************************************************************************
+void Compressor::init(int samplingRate)
+{
+ 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++) {
+ static_cast<compressordsp*>(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;
+}
+
//*******************************************************************************
void Compressor::compute(int nframes, float** inputs, float** outputs)
{
init(fSamplingFreq);
}
for (int i = 0; i < mNumChannels; i++) {
- compressorP[i]->compute(nframes, &inputs[i], &outputs[i]);
+ static_cast<compressordsp*>(compressorP[i])
+ ->compute(nframes, &inputs[i], &outputs[i]);
}
}
#include "CompressorPresets.h"
#include "ProcessPlugin.h"
-#include "compressordsp.h"
/** \brief A Compressor reduces the output dynamic range when the
* signal level exceeds the threshold.
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]);
- }
- }
+ float makeUpGainDBIn = 2.0f);
Compressor(int numchans, // xtor
bool verboseIn = false, CompressorPreset preset = CompressorPresets::voice)
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();
- }
+ virtual ~Compressor();
// 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";
- }
- }
- }
-
- 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;
- }
+ void setParamAllChannels(const char pName[], float p);
+ void init(int samplingRate) override;
int getNumInputs() override { return (mNumChannels); }
int getNumOutputs() override { return (mNumChannels); }
void compute(int nframes, float** inputs, float** outputs) override;
private:
float fs;
int mNumChannels;
- std::vector<compressordsp*> compressorP;
- std::vector<APIUI*> compressorUIP;
+ std::vector<void*> compressorP;
+ std::vector<void*> compressorUIP;
float ratio;
float thresholdDB;
float attackMS;
, mStopOnTimeout(false)
, mSendRingBuffer(NULL)
, mReceiveRingBuffer(NULL)
- , mRegulatorThreadPtr(NULL)
- , mRegulatorWorkerPtr(NULL)
, mReceiverBindPort(receiver_bind_port)
, mSenderPeerPort(sender_peer_port)
, mSenderBindPort(sender_bind_port)
JackTrip::~JackTrip()
{
// wait();
+ stop();
delete mDataProtocolSender;
delete mDataProtocolReceiver;
delete mAudioInterface;
delete mPacketHeader;
- delete mRegulatorWorkerPtr;
- delete mRegulatorThreadPtr;
delete mSendRingBuffer;
delete mReceiveRingBuffer;
}
mReceiveRingBuffer =
new RingBuffer(audio_output_slot_size, mBufferQueueLength);
mPacketHeader->setBufferRequiresSameSettings(true);
- } else if (mBufferStrategy == 3) {
+ } else if ((mBufferStrategy == 3) || (mBufferStrategy == 4)) {
+ bool use_worker_thread = (mBufferStrategy == 3);
cout << "Using experimental buffer strategy " << mBufferStrategy
- << "-- Regulator with PLC" << endl;
-
- mReceiveRingBuffer =
- new Regulator(mNumAudioChansOut, mAudioBitResolution, mAudioBufferSize,
- mBufferQueueLength, mBroadcastQueueLength);
- // bufStrategy 3, mBufferQueueLength is in integer msec not packets
+ << "-- Regulator with PLC (worker="
+ << (use_worker_thread ? "true" : "false") << ")" << endl;
+ mReceiveRingBuffer = new Regulator(mNumAudioChansOut, mAudioBitResolution,
+ mAudioBufferSize, mBufferQueueLength,
+ use_worker_thread, mBroadcastQueueLength);
+ // bufStrategy 3 or 4, mBufferQueueLength is in integer msec not packets
mPacketHeader->setBufferRequiresSameSettings(false); // = asym is default
}
}
+//*******************************************************************************
+void JackTrip::appendProcessPluginToMonitor(ProcessPlugin* plugin)
+{
+ if (plugin) {
+ mProcessPluginsToMonitor.append(plugin); // ownership transferred
+ // mAudioInterface->appendProcessPluginFromNetwork(plugin);
+ }
+}
+
//*******************************************************************************
void JackTrip::startProcess(
#ifdef WAIRTOHUB // WAIR
#endif // endwhere
);
- if (mAudioInterface->getDevicesErrorMsg() != "") {
- stop();
+ QString audioInterfaceError =
+ QString::fromStdString(mAudioInterface->getDevicesErrorMsg());
+ if (audioInterfaceError != "") {
+ stop(audioInterfaceError);
return;
}
mAudioInterface->appendProcessPluginToNetwork(i);
}
- if (mBufferStrategy == 3) {
- mRegulatorThreadPtr = new QThread();
- mRegulatorThreadPtr->setObjectName("RegulatorThread");
- Regulator* regulatorPtr = reinterpret_cast<Regulator*>(mReceiveRingBuffer);
- RegulatorWorker* workerPtr = new RegulatorWorker(regulatorPtr);
- workerPtr->moveToThread(mRegulatorThreadPtr);
- QObject::connect(this, &JackTrip::signalReceivedNetworkPacket, workerPtr,
- &RegulatorWorker::pullPacket, Qt::QueuedConnection);
- mRegulatorThreadPtr->start();
- mRegulatorWorkerPtr = workerPtr;
+ for (auto& i : mProcessPluginsToMonitor) {
+ mAudioInterface->appendProcessPluginToMonitor(i);
}
mAudioInterface->initPlugins(true); // mSampleRate known now, which plugins require
serverHostAddress = info.addresses().constFirst();
}
}
- mTcpClient.connectToHost(serverHostAddress, mTcpServerPort);
+
+ if (mTcpClient.state() == QAbstractSocket::UnconnectedState) {
+ mTcpClient.connectToHost(serverHostAddress, mTcpServerPort);
+ }
mRetryTimer.start();
}
mHasShutdown = true;
std::cout << "Stopping JackTrip..." << std::endl;
- if (mRegulatorThreadPtr != nullptr) {
- // Stop the Regulator thread
- mRegulatorThreadPtr->quit();
- mRegulatorThreadPtr->wait();
- }
-
if (mDataProtocolSender != nullptr) {
// Stop The Sender
mDataProtocolSender->stop();
{
mDataProtocolSender->wait();
mDataProtocolReceiver->wait();
- if (mRegulatorThreadPtr != nullptr) {
- mRegulatorThreadPtr->wait();
- }
}
//*******************************************************************************
mRetryTimer.start();
}
- mTcpClient.connectToHost(serverHostAddress, mTcpServerPort);
+ if (mTcpClient.state() == QAbstractSocket::UnconnectedState) {
+ mTcpClient.connectToHost(serverHostAddress, mTcpServerPort);
+ }
if (gVerboseFlag)
cout << "Connecting to TCP Server at "
#ifndef __JACKTRIP_H__
#define __JACKTRIP_H__
-//#include <tr1/memory> //for shared_ptr
+// #include <tr1/memory> //for shared_ptr
#include <QObject>
#include <QSharedPointer>
#include <QSslSocket>
#include "PacketHeader.h"
#include "RingBuffer.h"
-//#include <signal.h>
+// #include <signal.h>
/** \brief Main class to creates a SERVER (to listen) or a CLIENT (to connect
* to a listening server) to send audio streams in the network.
*
// void appendProcessPlugin(const std::tr1::shared_ptr<ProcessPlugin> plugin);
virtual void appendProcessPluginToNetwork(ProcessPlugin* plugin);
virtual void appendProcessPluginFromNetwork(ProcessPlugin* plugin);
+ virtual void appendProcessPluginToMonitor(ProcessPlugin* plugin);
/// \brief Start the processing threads
virtual void startProcess(
virtual void receiveNetworkPacket(int8_t* ptrToReadSlot)
{
mReceiveRingBuffer->readSlotNonBlocking(ptrToReadSlot);
- if (mBufferStrategy == 3) {
- // trigger next packet using RegulatorThread
- emit signalReceivedNetworkPacket();
- }
}
virtual void readAudioBuffer(int8_t* ptrToReadSlot)
{
void signalUdpWaitingTooLong();
void signalQueueLengthChanged(int queueLength);
void signalAudioStarted();
- void signalReceivedNetworkPacket();
public:
/// \brief Set the AudioInteface object
RingBuffer* mSendRingBuffer;
/// Pointer for the Receive RingBuffer
RingBuffer* mReceiveRingBuffer;
- /// thread used to pull packets from Regulator (if mBufferStrategy==3)
- QThread* mRegulatorThreadPtr;
- /// worker used to pull packets from Regulator (if mBufferStrategy==3)
- QObject* mRegulatorWorkerPtr;
int mReceiverBindPort; ///< Incoming (receiving) port for local machine
int mSenderPeerPort; ///< Incoming (receiving) port for peer machine
mProcessPluginsFromNetwork; ///< Vector of ProcessPlugin<EM>s</EM>
QVector<ProcessPlugin*>
mProcessPluginsToNetwork; ///< Vector of ProcessPlugin<EM>s</EM>
-
+ QVector<ProcessPlugin*>
+ mProcessPluginsToMonitor; ///< Vector of ProcessPlugin<EM>s</EM>
QTimer mTimeoutTimer;
QTimer mRetryTimer;
int mRetries;
#include "Limiter.h"
#include "jacktrip_types.h"
+#include "limiterdsp.h"
+
+//*******************************************************************************
+Limiter::Limiter(int numchans, int numclients, bool verboseFlag)
+ : mNumChannels(numchans)
+ , mNumClients(numclients)
+ , warningAmp(0.0)
+ , warnCount(0)
+ , peakMagnitude(0.0)
+ , nextWarning(1)
+{
+ setVerbose(verboseFlag);
+ for (int i = 0; i < mNumChannels; i++) {
+ limiterdsp* dsp_ptr = new limiterdsp;
+ APIUI* ui_ptr = new APIUI;
+ limiterP.push_back(dsp_ptr);
+ limiterUIP.push_back(ui_ptr); // #included in limiterdsp.h
+ dsp_ptr->buildUserInterface(ui_ptr);
+#ifdef SINE_TEST
+ limitertest* test_ptr = new limitertest;
+ ui_ptr = new APIUI;
+ limiterTestP.push_back(test_ptr);
+ limiterTestUIP.push_back(ui_ptr); // #included in limitertest.h
+ test_ptr->buildUserInterface(ui_ptr);
+#endif
+ }
+ // std::cout << "Limiter: constructed for "
+ // << mNumChannels << " channels and "
+ // << mNumClients << " assumed clients\n";
+}
+
+//*******************************************************************************
+Limiter::~Limiter()
+{
+ for (int i = 0; i < mNumChannels; i++) {
+ delete static_cast<limiterdsp*>(limiterP[i]);
+ delete static_cast<APIUI*>(limiterUIP[i]);
+ }
+ limiterP.clear();
+ limiterUIP.clear();
+}
+
+//*******************************************************************************
+void Limiter::init(int samplingRate)
+{
+ 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++) {
+ static_cast<limiterdsp*>(limiterP[i])
+ ->init(fs); // compression filter parameters depend on sampling rate
+ APIUI* ui_ptr = static_cast<APIUI*>(limiterUIP[i]);
+ int ndx = ui_ptr->getParamIndex("NumClientsAssumed");
+ ui_ptr->setParamValue(ndx, mNumClients);
+#ifdef SINE_TEST
+ static_cast<limitertest*>(limiterTestP[i])
+ ->init(fs); // oscillator parameters depend on sampling rate
+ ui_ptr = static_cast<APIUI*>(limiterTestUIP[i]);
+ ndx = ui_ptr->getParamIndex("Amp");
+ ui_ptr->setParamValue(ndx, 0.2);
+ ndx = ui_ptr->getParamIndex("Freq");
+ float sineFreq =
+ 110.0 * pow(1.5, double(i))
+ * (mNumClients > 1 ? 1.25 : 1.0); // Maj 7 chord for stereo in & out
+ ui_ptr->setParamValue(ndx, sineFreq);
+#endif
+ }
+ inited = true;
+}
//*******************************************************************************
void Limiter::compute(int nframes, float** inputs, float** outputs)
checkAmplitudes(nframes,
inputs[i]); // we presently do one check across all channels
}
- limiterP[i]->compute(nframes, &inputs[i], &outputs[i]);
+ static_cast<limiterdsp*>(limiterP[i])->compute(nframes, &inputs[i], &outputs[i]);
#ifdef SINE_TEST
- limiterTestP[i]->compute(nframes, faustSigs, faustSigs);
+ static_cast<limitertest*>(limiterTestP[i])
+ ->compute(nframes, faustSigs, faustSigs);
for (int n = 0; n < nframes; n++) {
outputs[i][n] = outputs[i][n] + sineTestOut[n];
}
#endif
#include <cassert>
+#include <cmath>
#include <iostream>
#include <vector>
#include "ProcessPlugin.h"
-#include "limiterdsp.h"
/** \brief The Limiter class confines the output dynamic range to a
* "dynamic range lane" determined by the assumed number of clients.
{
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]);
-#endif
- }
- // std::cout << "Limiter: constructed for "
- // << mNumChannels << " channels and "
- // << mNumClients << " assumed clients\n";
- }
+ Limiter(int numchans, int numclients, bool verboseFlag = false);
/// \brief The class destructor
- virtual ~Limiter()
- {
- for (int i = 0; i < mNumChannels; i++) {
- delete limiterP[i];
- delete limiterUIP[i];
- }
- limiterP.clear();
- limiterUIP.clear();
- }
+ virtual ~Limiter();
- 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);
-#endif
- }
- inited = true;
- }
+ void init(int samplingRate) override;
int getNumInputs() override { return (mNumChannels); }
int getNumOutputs() override { return (mNumChannels); }
void compute(int nframes, float** inputs, float** outputs) override;
float fs;
int mNumChannels;
int mNumClients;
- std::vector<limiterdsp*> limiterP;
- std::vector<APIUI*> limiterUIP;
+ std::vector<void*> limiterP;
+ std::vector<void*> limiterUIP;
#ifdef SINE_TEST
- std::vector<limitertest*> limiterTestP;
- std::vector<APIUI*> limiterTestUIP;
+ std::vector<void*> limiterTestP;
+ std::vector<void*> limiterTestUIP;
#endif
double warningAmp;
uint32_t warnCount;
#include "Meter.h"
+#include <iostream>
+
#include "jacktrip_types.h"
+#include "meterdsp.h"
+
+//*******************************************************************************
+Meter::Meter(int numchans, bool verboseFlag) : mNumChannels(numchans)
+{
+ setVerbose(verboseFlag);
+ for (int i = 0; i < mNumChannels; i++) {
+ meterP.push_back(new meterdsp);
+ }
+}
+
+//*******************************************************************************
+Meter::~Meter()
+{
+ for (int i = 0; i < mNumChannels; i++) {
+ delete static_cast<meterdsp*>(meterP[i]);
+ }
+ meterP.clear();
+ if (mValues) {
+ delete mValues;
+ }
+ if (mOutValues) {
+ delete mOutValues;
+ }
+ if (mBuffer) {
+ delete mBuffer;
+ }
+}
//*******************************************************************************
void Meter::init(int samplingRate)
fs = float(fSamplingFreq);
for (int i = 0; i < mNumChannels; i++) {
- meterP[i]->init(fs);
+ static_cast<meterdsp*>(meterP[i])->init(fs);
}
/* Set meter values to the default floor */
}
//*******************************************************************************
-void Meter::compute(int nframes, float** inputs, float** /*_*/)
+void Meter::compute(int nframes, float** inputs, float** outputs)
{
- // Note that the second parameter is unused. This is because all of the ProcessPlugins
- // require the same function signature for the compute() function and is normally used
- // for the faust plugin output. However, this plugin is not supposed to modify the
- // signal itself like the other plugins (e.g. Limiter) do, so we don't want to write
- // to this buffer. We just need to report the VU meter output
-
if (not inited) {
std::cerr << "*** Meter " << this << ": init never called! Doing it now.\n";
if (fSamplingFreq <= 0) {
init(fSamplingFreq);
}
+ // Will measure inputs by default unless mMeasureOutputBuffer = true,
+ // in which case the plugin will measure from the outputs. This is useful when
+ // measuring with a monitor, since AudioInterface.cpp expects monitoring plugins
+ // to behave differently than input and output chain plugins
+ float** measuringBuffer = inputs;
+ if (mIsMonitoringMeter) {
+ measuringBuffer = outputs;
+ }
+
if (mBufSize < nframes) {
if (mBuffer) {
delete mBuffer;
for (int i = 0; i < mNumChannels; i++) {
/* Run the signal through Faust */
- meterP[i]->compute(nframes, &inputs[i], &mBuffer);
+ static_cast<meterdsp*>(meterP[i])->compute(nframes, &measuringBuffer[i],
+ &mBuffer);
/* Use the existing value of mValues[i] as
the threshold - this will be reset to the default floor of -80dB
#include <QObject>
#include <QTimer>
-#include <iostream>
#include <vector>
#include "ProcessPlugin.h"
-#include "meterdsp.h"
/** \brief The Meter class measures the live audio loudness level
*/
public:
/// \brief The class constructor sets the number of channels to measure
- Meter(int numchans, bool verboseFlag = false) : mNumChannels(numchans)
- {
- setVerbose(verboseFlag);
- for (int i = 0; i < mNumChannels; i++) {
- meterP.push_back(new meterdsp);
- // meterUIP.push_back(new APIUI);
- // meterP[i]->buildUserInterface(meterUIP[i]);
- }
- }
+ Meter(int numchans, bool verboseFlag = false);
/// \brief The class destructor
- virtual ~Meter()
- {
- for (int i = 0; i < mNumChannels; i++) {
- delete meterP[i];
- }
- meterP.clear();
- if (mValues) {
- delete mValues;
- }
- if (mOutValues) {
- delete mOutValues;
- }
- if (mBuffer) {
- delete mBuffer;
- }
- }
+ virtual ~Meter();
void init(int samplingRate) override;
int getNumInputs() override { return (mNumChannels); }
void updateNumChannels(int nChansIn, int nChansOut) override;
+ void setIsMonitoringMeter(bool isMonitoringMeter)
+ {
+ mIsMonitoringMeter = isMonitoringMeter;
+ };
+ bool getIsMonitoringMeter() { return mIsMonitoringMeter; };
+
private:
void setupValues();
float fs;
+ bool mIsMonitoringMeter = false;
+
int mNumChannels;
float threshold = -80.0;
- std::vector<meterdsp*> meterP;
+ std::vector<void*> meterP;
bool hasProcessedAudio = false;
QTimer mTimer;
--- /dev/null
+//*****************************************************************
+/*
+ JackTrip: A System for High-Quality Audio Network Performance
+ over the Internet
+
+ Copyright (c) 2020 Julius Smith, 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 Monitor.cpp
+ * \author Dominick Hing
+ * \date May 2023
+ * \license MIT
+ */
+
+#include "Monitor.h"
+
+#include <iostream>
+
+#include "jacktrip_types.h"
+#include "monitordsp.h"
+
+//*******************************************************************************
+Monitor::Monitor(int numchans, bool verboseFlag) : mNumChannels(numchans)
+{
+ setVerbose(verboseFlag);
+ for (int i = 0; i < mNumChannels; i++) {
+ monitordsp* dsp_ptr = new monitordsp;
+ APIUI* ui_ptr = new APIUI;
+ monitorP.push_back(dsp_ptr);
+ monitorUIP.push_back(ui_ptr); // #included in monitordsp.h
+ dsp_ptr->buildUserInterface(ui_ptr);
+ }
+}
+
+//*******************************************************************************
+Monitor::~Monitor()
+{
+ for (int i = 0; i < mNumChannels; i++) {
+ delete static_cast<monitordsp*>(monitorP[i]);
+ delete static_cast<APIUI*>(monitorUIP[i]);
+ }
+ monitorP.clear();
+ monitorUIP.clear();
+}
+
+//*******************************************************************************
+void Monitor::init(int samplingRate)
+{
+ 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++) {
+ static_cast<monitordsp*>(monitorP[i])
+ ->init(fs); // compression filter parameters depend on sampling rate
+ APIUI* ui_ptr = static_cast<APIUI*>(monitorUIP[i]);
+ int ndx = ui_ptr->getParamIndex("Volume");
+ ui_ptr->setParamValue(ndx, mVolMultiplier);
+ ndx = ui_ptr->getParamIndex("Mute");
+ ui_ptr->setParamValue(ndx, 0);
+ }
+ inited = true;
+}
+
+//*******************************************************************************
+void Monitor::compute(int nframes, float** inputs, float** outputs)
+{
+ if (not inited) {
+ std::cerr << "*** Monitor " << this << ": init never called! Doing it now.\n";
+ if (fSamplingFreq <= 0) {
+ fSamplingFreq = 48000;
+ std::cout << "Monitor " << this
+ << ": *** HAD TO GUESS the sampling rate (chose 48000 Hz) ***\n";
+ }
+ init(fSamplingFreq);
+ }
+
+ if (mBufSize < nframes) {
+ if (mOutBufferInput) {
+ delete mOutBufferInput;
+ }
+
+ if (mInBufferInput) {
+ delete mInBufferInput;
+ }
+
+ mBufSize = nframes;
+ mOutBufferInput = new float[mBufSize];
+ mInBufferInput = new float[mBufSize];
+ }
+
+ std::vector<float*> buffer{mInBufferInput, mOutBufferInput};
+ for (int i = 0; i < mNumChannels; i++) {
+ // copy inputs and outputs into a separate memory buffer
+ memcpy(mInBufferInput, inputs[i], nframes * sizeof(float));
+ memcpy(mOutBufferInput, outputs[i], nframes * sizeof(float));
+
+ /* Run the signal through Faust */
+ static_cast<monitordsp*>(monitorP[i])
+ ->compute(nframes, buffer.data(), &outputs[i]);
+ }
+}
+
+//*******************************************************************************
+void Monitor::updateNumChannels(int nChansIn, int nChansOut)
+{
+ if (outgoingPluginToNetwork) {
+ mNumChannels = nChansIn;
+ } else {
+ mNumChannels = nChansOut;
+ }
+}
+
+//*******************************************************************************
+void Monitor::volumeUpdated(float multiplier)
+{
+ // maps 0.0-1.0 to a -40 dB to 0 dB range
+ // update if volumedsp.dsp and/or volumedsp.h
+ // change their ranges
+ mVolMultiplier = 40.0 * multiplier - 40.0;
+ for (int i = 0; i < mNumChannels; i++) {
+ APIUI* ui_ptr = static_cast<APIUI*>(monitorUIP[i]);
+ int ndx = ui_ptr->getParamIndex("Volume");
+ ui_ptr->setParamValue(ndx, mVolMultiplier);
+ }
+}
\ No newline at end of file
--- /dev/null
+//*****************************************************************
+/*
+ JackTrip: A System for High-Quality Audio Network Performance
+ over the Internet
+
+ Copyright (c) 2020 Julius Smith, 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 Monitor.h
+ * \author Dominick Hing
+ * \date May 2023
+ * \license MIT
+ */
+
+#ifndef __MONITOR_H__
+#define __MONITOR_H__
+
+#include <QObject>
+#include <vector>
+
+#include "ProcessPlugin.h"
+
+/** \brief The Monitor plugin adds a portion of the input signal multiplied by a
+ * constant factor to the output signal
+ */
+class Monitor : public ProcessPlugin
+{
+ Q_OBJECT;
+
+ public:
+ /// \brief The class constructor sets the number of channels to use
+ Monitor(int numchans, bool verboseFlag = false);
+
+ /// \brief The class destructor
+ virtual ~Monitor();
+
+ void init(int samplingRate) 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 "Monitor"; };
+
+ void updateNumChannels(int nChansIn, int nChansOut) override;
+
+ public slots:
+ void volumeUpdated(float multiplier);
+
+ private:
+ std::vector<void*> monitorP;
+ std::vector<void*> monitorUIP;
+ float fs;
+ int mNumChannels;
+ float mVolMultiplier = 0.0;
+
+ float* mOutBufferInput = nullptr;
+ float* mInBufferInput = nullptr;
+ int mBufSize = 0;
+};
+
+#endif
\ No newline at end of file
constexpr int WindowDivisor = 8; // for faster auto tracking
constexpr int MaxFPP = 1024; // tested up to this FPP
//*******************************************************************************
-Regulator::Regulator(int rcvChannels, int bit_res, int FPP, int qLen, int bqLen)
+Regulator::Regulator(int rcvChannels, int bit_res, int FPP, int qLen,
+ bool use_worker_thread, int bqLen)
: RingBuffer(0, 0)
, mNumChannels(rcvChannels)
, mAudioBitRes(bit_res)
, mFPP(FPP)
, mMsecTolerance((double)qLen) // handle non-auto mode, expects positive qLen
, mAuto(false)
+ , mUseWorkerThread(use_worker_thread)
, m_b_BroadcastQueueLength(bqLen)
+ , mRegulatorThreadPtr(NULL)
+ , mRegulatorWorkerPtr(NULL)
{
// catch settings that are compute bound using long HIST
// hub client rcvChannels is set from client's settings parameters
if (gVerboseFlag)
cout << "mHist = " << mHist << " at " << mFPP << "\n";
- mBytes = mFPP * mNumChannels * mBitResolutionMode;
- mPullQueue = new int8_t[mBytes * 2];
- mXfrBuffer = mPullQueue;
- mPacketCnt = 0; // burg initialization
- mNextPacket.store(mPullQueue + mBytes, std::memory_order_release);
+ mBytes = mFPP * mNumChannels * mBitResolutionMode;
+ mPullQueue = new int8_t[mBytes * 2];
+ mXfrBuffer = mPullQueue;
+ mPacketCnt = 0; // burg initialization
+ mLastPacket = nullptr;
+ mNextPacket.store(mLastPacket, std::memory_order_release);
+ mWorkerUnderruns = 0;
mFadeUp.resize(mFPP, 0.0);
mFadeDown.resize(mFPP, 0.0);
for (int i = 0; i < mFPP; i++) {
<< m_b_BroadcastQueueLength;
// have not implemented the mJackTrip->queueLengthChanged functionality
}
+ if (mUseWorkerThread) {
+ mRegulatorThreadPtr = new QThread();
+ mRegulatorThreadPtr->setObjectName("RegulatorThread");
+ RegulatorWorker* workerPtr = new RegulatorWorker(this);
+ workerPtr->moveToThread(mRegulatorThreadPtr);
+ mRegulatorThreadPtr->start();
+ mRegulatorWorkerPtr = workerPtr;
+ }
}
void Regulator::changeGlobal(double x)
};
if (m_b_BroadcastQueueLength)
delete m_b_BroadcastRingBuffer;
+ if (mRegulatorWorkerPtr != nullptr)
+ delete mRegulatorWorkerPtr;
+ if (mRegulatorThreadPtr != nullptr) {
+ // Stop the Regulator thread
+ mRegulatorThreadPtr->quit();
+ mRegulatorThreadPtr->wait();
+ delete mRegulatorThreadPtr;
+ }
}
void Regulator::setFPPratio()
//*******************************************************************************
void Regulator::pushPacket(const int8_t* buf, int seq_num)
{
+ if (m_b_BroadcastQueueLength)
+ m_b_BroadcastRingBuffer->insertSlotNonBlocking(buf, mBytes, 0, seq_num);
QMutexLocker locker(&mMutex);
seq_num %= mModSeqNum;
// if (seq_num==0) return; // impose regular loss
memcpy(mSlots[mLastSeqNumIn % mNumSlots], buf, mBytes);
};
+//*******************************************************************************
+void Regulator::pullPacket(int8_t* buf)
+{ // only for mBufferStrategy == 4, not using workerThread
+ pullPacket();
+ memcpy(buf, mXfrBuffer, mBytes);
+}
+
//*******************************************************************************
void Regulator::pullPacket()
{
}
}
+void Regulator::readSlotNonBlocking(int8_t* ptrToReadSlot)
+{
+ if (mUseWorkerThread) {
+ // use separate worker thread for PLC
+ const void* ptrToPacket = mNextPacket.load(std::memory_order_acquire);
+ if (ptrToPacket == mLastPacket) {
+ mWorkerUnderruns++;
+ ::memset(ptrToReadSlot, 0, mBytes);
+ if (ptrToPacket == nullptr) {
+ // first time run
+ mRegulatorWorkerPtr->startPullingNextPacket();
+ }
+ } else {
+ ::memcpy(ptrToReadSlot, ptrToPacket, mBytes);
+ mLastPacket = ptrToPacket;
+ mRegulatorWorkerPtr->startPullingNextPacket();
+ }
+ } else {
+ // use jack callback thread to perform PLC
+ pullPacket(ptrToReadSlot);
+ }
+}
+
//*******************************************************************************
bool Regulator::getStats(RingBuffer::IOStat* stat, bool reset)
{
mBroadcastSkew = 0;
}
+ if (mUseWorkerThread) {
+ cout << "PLC worker underruns: " << mWorkerUnderruns << endl;
+ mWorkerUnderruns = 0;
+ }
+
// hijack of struct IOStat {
stat->underruns = pullStat->lastPlcUnderruns + pullStat->lastPlcOverruns;
#define FLOATFACTOR 1000.0
#include "AudioInterface.h"
#include "RingBuffer.h"
+#include "jacktrip_globals.h"
+
+// forward declaration
+class RegulatorWorker;
class BurgAlgorithm
{
class Regulator : public RingBuffer
{
public:
- Regulator(int rcvChannels, int bit_res, int FPP, int qLen, int bqLen);
+ Regulator(int rcvChannels, int bit_res, int FPP, int qLen, bool use_worker_thread,
+ int bqLen);
virtual ~Regulator();
void shimFPP(const int8_t* buf, int len, int seq_num);
// if (!mJackTrip->writeAudioBuffer(src, host_buf_size, last_seq_num))
// instead of
// if (!mJackTrip->writeAudioBuffer(src, host_buf_size, gap_size))
- virtual bool insertSlotNonBlocking(const int8_t* ptrToSlot, int len, int lostLen,
- int seq_num)
+ virtual bool insertSlotNonBlocking(const int8_t* ptrToSlot, int len,
+ [[maybe_unused]] int lostLen, int seq_num)
{
shimFPP(ptrToSlot, len, seq_num);
- if (m_b_BroadcastQueueLength)
- m_b_BroadcastRingBuffer->insertSlotNonBlocking(ptrToSlot, len, lostLen,
- seq_num);
return (true);
}
- // called by RegulatorWorker after each audio callback, to prep next packet
+ void pullPacket(int8_t* buf);
+
void pullPacket();
- virtual void readSlotNonBlocking(int8_t* ptrToReadSlot)
- {
- ::memcpy(ptrToReadSlot, mNextPacket.load(std::memory_order_acquire), mBytes);
- }
+ virtual void readSlotNonBlocking(int8_t* ptrToReadSlot);
virtual void readBroadcastSlot(int8_t* ptrToReadSlot)
{
int mBytesPeerPacket;
int8_t* mPullQueue;
int8_t* mXfrBuffer;
+ const void* mLastPacket;
+ int mWorkerUnderruns;
std::atomic<const void*> mNextPacket;
int8_t* mAssembledPacket;
int mPacketCnt;
double mAutoHeadroom;
double mFPPdurMsec;
double mPeerFPPdurMsec;
+ bool mUseWorkerThread;
void changeGlobal(double);
void changeGlobal_2(int);
void changeGlobal_3(int);
/// Pointer for the Broadcast RingBuffer
RingBuffer* m_b_BroadcastRingBuffer;
int m_b_BroadcastQueueLength;
+
+ /// thread used to pull packets from Regulator (if mBufferStrategy==3)
+ QThread* mRegulatorThreadPtr;
+ /// worker used to pull packets from Regulator (if mBufferStrategy==3)
+ RegulatorWorker* mRegulatorWorkerPtr;
};
class RegulatorWorker : public QObject
Q_OBJECT;
public:
- RegulatorWorker(Regulator* rPtr) : mRegulatorPtr(rPtr) {}
+ RegulatorWorker(Regulator* rPtr) : mRegulatorPtr(rPtr)
+ {
+ QObject::connect(this, &RegulatorWorker::startup, this,
+ &RegulatorWorker::setRealtimePriority, Qt::QueuedConnection);
+ QObject::connect(this, &RegulatorWorker::signalPullPacket, this,
+ &RegulatorWorker::pullPacket, Qt::QueuedConnection);
+ emit startup();
+ }
virtual ~RegulatorWorker() {}
+ void startPullingNextPacket() { emit signalPullPacket(); }
+
+ signals:
+ void signalPullPacket();
+ void startup();
public slots:
void pullPacket()
mRegulatorPtr->pullPacket();
}
}
+ void setRealtimePriority() { setRealtimeProcessPriority(); }
private:
Regulator* mRegulatorPtr;
#include "Reverb.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 "jacktrip_types.h"
+#include "zitarevdsp.h" // stereo in and out
+#include "zitarevmonodsp.h" // mono in and out
+
+//*******************************************************************************
+Reverb::Reverb(int numInChans, int numOutChans, float reverbLevel, bool verboseFlag)
+ : 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 "
+ << mNumOutChannels << " output channels with reverb level = "
+ << 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;
+ static_cast<freeverbdsp*>(freeverbStereoP)
+ ->buildUserInterface(static_cast<APIUI*>(freeverbStereoUIP));
+ static_cast<freeverbmonodsp*>(freeverbMonoP)
+ ->buildUserInterface(static_cast<APIUI*>(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;
+ static_cast<zitarevdsp*>(zitarevStereoP)
+ ->buildUserInterface(static_cast<APIUI*>(zitarevStereoUIP));
+ static_cast<zitarevmonodsp*>(zitarevMonoP)
+ ->buildUserInterface(static_cast<APIUI*>(zitarevMonoUIP));
+ // std::cout << "Using zitarev\n";
+ }
+}
+
+//*******************************************************************************
+Reverb::~Reverb()
+{
+ if (mReverbLevel <= 1.0) { // freeverb:
+ delete static_cast<freeverbdsp*>(freeverbStereoP);
+ delete static_cast<freeverbmonodsp*>(freeverbMonoP);
+ delete static_cast<APIUI*>(freeverbStereoUIP);
+ delete static_cast<APIUI*>(freeverbMonoUIP);
+ } else {
+ delete static_cast<zitarevdsp*>(zitarevStereoP);
+ delete static_cast<zitarevmonodsp*>(zitarevMonoP);
+ delete static_cast<APIUI*>(zitarevStereoUIP);
+ delete static_cast<APIUI*>(zitarevMonoUIP);
+ }
+}
+
+//*******************************************************************************
+void Reverb::init(int samplingRate)
+{
+ 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:
+ static_cast<freeverbdsp*>(freeverbStereoP)
+ ->init(fs); // compression filter parameters depend on sampling rate
+ static_cast<freeverbmonodsp*>(freeverbMonoP)
+ ->init(fs); // compression filter parameters depend on sampling rate
+ int ndx = static_cast<APIUI*>(freeverbStereoUIP)->getParamIndex("Wet");
+ static_cast<APIUI*>(freeverbStereoUIP)->setParamValue(ndx, mReverbLevel);
+ static_cast<APIUI*>(freeverbMonoUIP)->setParamValue(ndx, mReverbLevel);
+ } else { // zitarev:
+ static_cast<zitarevdsp*>(zitarevStereoP)
+ ->init(fs); // compression filter parameters depend on sampling rate
+ static_cast<zitarevmonodsp*>(zitarevMonoP)
+ ->init(fs); // compression filter parameters depend on sampling rate
+ int ndx = static_cast<APIUI*>(zitarevStereoUIP)->getParamIndex("Wet");
+ float zitaLevel =
+ mReverbLevel - 1.0f; // range within zitarev is 0 to 1 (our version only)
+ static_cast<APIUI*>(zitarevStereoUIP)->setParamValue(ndx, zitaLevel);
+ static_cast<APIUI*>(zitarevMonoUIP)->setParamValue(ndx, zitaLevel);
+ }
+ inited = true;
+}
//*******************************************************************************
void Reverb::compute(int nframes, float** inputs, float** outputs)
}
if (mReverbLevel <= 1.0) {
if (mNumInChannels == 1) {
- freeverbMonoP->compute(nframes, inputs, outputs);
+ static_cast<freeverbmonodsp*>(freeverbMonoP)
+ ->compute(nframes, inputs, outputs);
} else {
assert(mNumInChannels == 2);
- freeverbStereoP->compute(nframes, inputs, outputs);
+ static_cast<freeverbdsp*>(freeverbStereoP)->compute(nframes, inputs, outputs);
}
} else {
if (mNumInChannels == 1) {
- zitarevMonoP->compute(nframes, inputs, outputs);
+ static_cast<zitarevmonodsp*>(zitarevMonoP)->compute(nframes, inputs, outputs);
} else {
assert(mNumInChannels == 2);
- zitarevStereoP->compute(nframes, inputs, outputs);
+ static_cast<zitarevdsp*>(zitarevStereoP)->compute(nframes, inputs, outputs);
}
}
}
#include <iostream>
-//#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
/** \brief A Reverb is an echo-based delay effect,
* providing a virtual acoustic listening space.
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 "
- << mNumOutChannels << " output channels with reverb level = "
- << 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";
- }
- }
+ bool verboseFlag = false);
/// \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);
- }
- inited = true;
- }
+ virtual ~Reverb();
+
+ void init(int samplingRate) override;
int getNumInputs() override { return (mNumInChannels); }
int getNumOutputs() override { return (mNumOutChannels); }
void compute(int nframes, float** inputs, float** outputs) override;
float mReverbLevel;
- freeverbdsp* freeverbStereoP;
- freeverbmonodsp* freeverbMonoP;
- APIUI* freeverbStereoUIP;
- APIUI* freeverbMonoUIP;
+ void* freeverbStereoP;
+ void* freeverbMonoP;
+ void* freeverbStereoUIP;
+ void* freeverbMonoUIP;
- zitarevdsp* zitarevStereoP;
- zitarevmonodsp* zitarevMonoP;
- APIUI* zitarevStereoUIP;
- APIUI* zitarevMonoUIP;
+ void* zitarevStereoP;
+ void* zitarevMonoP;
+ void* zitarevStereoUIP;
+ void* zitarevMonoUIP;
};
#endif
if (api_in != "asio") {
AudioInterface::setDevicesWarningMsg(AudioInterface::DEVICE_WARN_LATENCY);
AudioInterface::setDevicesErrorMsg(AudioInterface::DEVICE_ERR_NONE);
+ } else if (api_in == "asio" && index_in != index_out) {
+ AudioInterface::setDevicesWarningMsg(AudioInterface::DEVICE_WARN_NONE);
+ AudioInterface::setDevicesErrorMsg(AudioInterface::DEVICE_ERR_SAME_ASIO);
}
#endif
} else {
categories->append(QStringLiteral("Low-Latency (ASIO)"));
break;
case RtAudio::WINDOWS_WASAPI:
- categories->append(QStringLiteral("All Devices (Non-ASIO)"));
+ categories->append(QStringLiteral("High-Latency (Non-ASIO)"));
break;
case RtAudio::WINDOWS_DS:
- categories->append(QStringLiteral("All Devices (Non-ASIO)"));
+ categories->append(QStringLiteral("High-Latency (Non-ASIO)"));
break;
default:
categories->append(QStringLiteral(""));
categories->append("Low-Latency (ASIO)");
break;
case RtAudio::WINDOWS_WASAPI:
- categories->append("All Devices (Non-ASIO)");
+ categories->append("High-Latency (Non-ASIO)");
break;
case RtAudio::WINDOWS_DS:
- categories->append("All Devices (Non-ASIO)");
+ categories->append("High-Latency (Non-ASIO)");
break;
default:
categories->append("");
break;
case OPT_BUFSTRATEGY: // Buf strategy
mBufferStrategy = atoi(optarg);
- if (-1 > mBufferStrategy || 3 < mBufferStrategy) {
+ if (-1 > mBufferStrategy || 4 < mBufferStrategy) {
std::cerr << "Unsupported buffer strategy " << optarg << endl;
printUsage();
std::exit(1);
cout << " -D, --nojackportsconnect Don't connect default audio ports "
"in jack"
<< endl;
- cout << " --bufstrategy # (0, 1, 2) Use alternative jitter buffer"
+ cout << " --bufstrategy # (0, 1, 2, 3, 4) 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";
#include "StereoToMono.h"
-#include <QVector>
+#include <iostream>
#include "jacktrip_types.h"
+#include "stereotomonodsp.h"
+
+//*******************************************************************************
+StereoToMono::StereoToMono(bool verboseFlag)
+{
+ setVerbose(verboseFlag);
+ stereoToMonoP = new stereotomonodsp;
+}
+
+//*******************************************************************************
+StereoToMono::~StereoToMono()
+{
+ delete static_cast<stereotomonodsp*>(stereoToMonoP);
+}
//*******************************************************************************
void StereoToMono::init(int samplingRate)
}
fs = float(fSamplingFreq);
- stereoToMonoP->init(fs);
+ static_cast<stereotomonodsp*>(stereoToMonoP)->init(fs);
inited = true;
}
}
init(fSamplingFreq);
}
- stereoToMonoP->compute(nframes, inputs, outputs);
+ static_cast<stereotomonodsp*>(stereoToMonoP)->compute(nframes, inputs, outputs);
}
\ No newline at end of file
#define __STEREOTOMONO_H__
#include <QObject>
-#include <QVector>
-#include <iostream>
-#include <vector>
#include "ProcessPlugin.h"
-#include "stereotomonodsp.h"
/** \brief The Meter class measures the live audio loudness level
*/
public:
/// \brief The class constructor sets the number of channels to measure
- StereoToMono(bool verboseFlag = false)
- {
- setVerbose(verboseFlag);
- stereoToMonoP = new stereotomonodsp;
- }
+ StereoToMono(bool verboseFlag = false);
/// \brief The class destructor
- virtual ~StereoToMono() { delete stereoToMonoP; }
+ virtual ~StereoToMono();
void init(int samplingRate) override;
int getNumInputs() override { return 2; }
private:
float fs;
- // int mNumChannels;
- stereotomonodsp* stereoToMonoP;
- // bool hasProcessedAudio = false;
+ void* stereoToMonoP;
};
#endif
\ No newline at end of file
#include "Tone.h"
+#include <iostream>
+
#include "jacktrip_types.h"
+#include "tonedsp.h"
+
+//*******************************************************************************
+Tone::Tone(int numchans, bool verboseFlag) : mNumChannels(numchans)
+{
+ setVerbose(verboseFlag);
+ for (int i = 0; i < mNumChannels; i++) {
+ tonedsp* dsp_ptr = new tonedsp;
+ APIUI* ui_ptr = new APIUI;
+ toneP.push_back(dsp_ptr);
+ toneUIP.push_back(ui_ptr);
+ dsp_ptr->buildUserInterface(ui_ptr);
+ }
+}
+
+//*******************************************************************************
+Tone::~Tone()
+{
+ for (int i = 0; i < mNumChannels; i++) {
+ delete static_cast<tonedsp*>(toneP[i]);
+ delete static_cast<APIUI*>(toneUIP[i]);
+ }
+ toneP.clear();
+ toneUIP.clear();
+}
//*******************************************************************************
void Tone::init(int samplingRate)
fs = float(fSamplingFreq);
for (int i = 0; i < mNumChannels; i++) {
- toneP[i]->init(fs); // compression filter parameters depend on sampling rate
+ static_cast<tonedsp*>(toneP[i])->init(
+ fs); // compression filter parameters depend on sampling rate
}
inited = true;
}
for (int i = 0; i < mNumChannels; i++) {
/* Run the signal through Faust */
- toneP[i]->compute(nframes, &inputs[i], &outputs[i]);
+ static_cast<tonedsp*>(toneP[i])->compute(nframes, &inputs[i], &outputs[i]);
}
}
void Tone::triggerPlayback()
{
for (int i = 0; i < mNumChannels; i++) {
- int ndx = toneUIP[i]->getParamIndex("gate");
- int v = toneUIP[i]->getParamValue(ndx);
- toneUIP[i]->setParamValue(ndx, v + 1);
+ APIUI* ui_ptr = static_cast<APIUI*>(toneUIP[i]);
+ int ndx = ui_ptr->getParamIndex("gate");
+ int v = ui_ptr->getParamValue(ndx);
+ ui_ptr->setParamValue(ndx, v + 1);
}
}
#define __TONE_H__
#include <QObject>
-#include <iostream>
#include <vector>
#include "ProcessPlugin.h"
-#include "tonedsp.h"
/** \brief The Tone plugin plays some arbitrary sample audio
*/
public:
/// \brief The class constructor sets the number of channels to measure
- Tone(int numchans, bool verboseFlag = false) : mNumChannels(numchans)
- {
- setVerbose(verboseFlag);
- for (int i = 0; i < mNumChannels; i++) {
- toneP.push_back(new tonedsp);
- toneUIP.push_back(new APIUI); // #included in tonedsp.h
- toneP[i]->buildUserInterface(toneUIP[i]);
- }
- }
+ Tone(int numchans, bool verboseFlag = false);
/// \brief The class destructor
- virtual ~Tone()
- {
- for (int i = 0; i < mNumChannels; i++) {
- delete toneP[i];
- delete toneUIP[i];
- }
- toneP.clear();
- toneUIP.clear();
- }
+ virtual ~Tone();
void init(int samplingRate) override;
int getNumInputs() override { return (mNumChannels); }
void triggerPlayback();
private:
- std::vector<tonedsp*> toneP;
- std::vector<APIUI*> toneUIP;
+ std::vector<void*> toneP;
+ std::vector<void*> toneUIP;
float fs;
int mNumChannels;
};
#include "Volume.h"
-#include <QVector>
+#include <iostream>
#include "jacktrip_types.h"
+#include "volumedsp.h"
+
+//*******************************************************************************
+Volume::Volume(int numchans, bool verboseFlag) : mNumChannels(numchans)
+{
+ setVerbose(verboseFlag);
+ for (int i = 0; i < mNumChannels; i++) {
+ volumedsp* dsp_ptr = new volumedsp;
+ APIUI* ui_ptr = new APIUI;
+ volumeP.push_back(dsp_ptr);
+ volumeUIP.push_back(ui_ptr); // #included in volumedsp.h
+ dsp_ptr->buildUserInterface(ui_ptr);
+ }
+}
+
+//*******************************************************************************
+Volume::~Volume()
+{
+ for (int i = 0; i < mNumChannels; i++) {
+ delete static_cast<volumedsp*>(volumeP[i]);
+ delete static_cast<APIUI*>(volumeUIP[i]);
+ }
+ volumeP.clear();
+ volumeUIP.clear();
+}
//*******************************************************************************
void Volume::init(int samplingRate)
fs = float(fSamplingFreq);
for (int i = 0; i < mNumChannels; i++) {
- volumeP[i]->init(fs); // compression filter parameters depend on sampling rate
- int ndx = volumeUIP[i]->getParamIndex("Volume");
- volumeUIP[i]->setParamValue(ndx, mVolMultiplier);
- ndx = volumeUIP[i]->getParamIndex("Mute");
- volumeUIP[i]->setParamValue(ndx, isMuted ? 1 : 0);
+ static_cast<volumedsp*>(volumeP[i])
+ ->init(fs); // compression filter parameters depend on sampling rate
+ APIUI* ui_ptr = static_cast<APIUI*>(volumeUIP[i]);
+ int ndx = ui_ptr->getParamIndex("Volume");
+ ui_ptr->setParamValue(ndx, mVolMultiplier);
+ ndx = ui_ptr->getParamIndex("Mute");
+ ui_ptr->setParamValue(ndx, isMuted ? 1 : 0);
}
inited = true;
}
for (int i = 0; i < mNumChannels; i++) {
/* Run the signal through Faust */
- volumeP[i]->compute(nframes, &inputs[i], &outputs[i]);
+ static_cast<volumedsp*>(volumeP[i])->compute(nframes, &inputs[i], &outputs[i]);
}
}
// change their ranges
mVolMultiplier = 40.0 * multiplier - 40.0;
for (int i = 0; i < mNumChannels; i++) {
- int ndx = volumeUIP[i]->getParamIndex("Volume");
- volumeUIP[i]->setParamValue(ndx, mVolMultiplier);
+ APIUI* ui_ptr = static_cast<APIUI*>(volumeUIP[i]);
+ int ndx = ui_ptr->getParamIndex("Volume");
+ ui_ptr->setParamValue(ndx, mVolMultiplier);
}
}
{
isMuted = muted;
for (int i = 0; i < mNumChannels; i++) {
- int ndx = volumeUIP[i]->getParamIndex("Mute");
- volumeUIP[i]->setParamValue(ndx, isMuted ? 1 : 0);
+ APIUI* ui_ptr = static_cast<APIUI*>(volumeUIP[i]);
+ int ndx = ui_ptr->getParamIndex("Mute");
+ ui_ptr->setParamValue(ndx, isMuted ? 1 : 0);
}
}
\ No newline at end of file
#define __VOLUME_H__
#include <QObject>
-#include <QTimer>
-#include <QVector>
-#include <iostream>
#include <vector>
#include "ProcessPlugin.h"
-#include "volumedsp.h"
/** \brief The Volume plugin adjusts the level of the signal via multiplication
*/
public:
/// \brief The class constructor sets the number of channels to measure
- Volume(int numchans, bool verboseFlag = false) : mNumChannels(numchans)
- {
- setVerbose(verboseFlag);
- for (int i = 0; i < mNumChannels; i++) {
- volumeP.push_back(new volumedsp);
- volumeUIP.push_back(new APIUI); // #included in volumedsp.h
- volumeP[i]->buildUserInterface(volumeUIP[i]);
- }
- }
+ Volume(int numchans, bool verboseFlag = false);
/// \brief The class destructor
- virtual ~Volume()
- {
- for (int i = 0; i < mNumChannels; i++) {
- delete volumeP[i];
- delete volumeUIP[i];
- }
- volumeP.clear();
- volumeUIP.clear();
- }
+ virtual ~Volume();
void init(int samplingRate) override;
int getNumInputs() override { return (mNumChannels); }
void muteUpdated(bool muted);
private:
- std::vector<volumedsp*> volumeP;
- std::vector<APIUI*> volumeUIP;
+ std::vector<void*> volumeP;
+ std::vector<void*> volumeUIP;
float fs;
int mNumChannels;
float mVolMultiplier = 0.0;
outputCombo.currentIndex = index
outputCombo.popup.close()
virtualstudio.outputDevice = modelData.text
+ if (modelData.category === "Low-Latency (ASIO)") {
+ let inputComboIdx = inputCombo.model.findIndex(it => it.category === "Low-Latency (ASIO)" && it.text === modelData.text);
+ if (inputComboIdx !== null && inputComboIdx !== undefined) {
+ inputCombo.currentIndex = inputComboIdx;
+ virtualstudio.inputDevice = modelData.text
+ }
+ }
+ virtualstudio.restartAudio()
virtualstudio.validateDevicesState()
}
}
anchors.right: outputCombo.horizontalCenter
anchors.rightMargin: 8 * virtualstudio.uiScale
anchors.top: outputChannelsLabel.bottom
- anchors.topMargin: 12 * virtualstudio.uiScale
+ anchors.topMargin: 4 * virtualstudio.uiScale
model: outputChannelsComboModel
currentIndex: (() => {
let idx = outputChannelsComboModel.findIndex(elem => elem.baseChannel === virtualstudio.baseOutputChannel
Text {
anchors.centerIn: parent
font { family: "Poppins"; pixelSize: fontExtraSmall * virtualstudio.fontScale * virtualstudio.uiScale}
- text: qsTr("Send audio to the studio (microphone, instrument, mixer, etc.)")
+ text: qsTr("Audio sent to the studio (microphone, instrument, mixer, etc.)")
color: toolTipTextColour
}
}
inputCombo.currentIndex = index
inputCombo.popup.close()
virtualstudio.inputDevice = modelData.text
+ if (modelData.category === "Low-Latency (ASIO)") {
+ let outputComboIdx = outputCombo.model.findIndex(it => it.category === "Low-Latency (ASIO)" && it.text === modelData.text);
+ if (outputComboIdx !== null && outputComboIdx !== undefined) {
+ outputCombo.currentIndex = outputComboIdx;
+ virtualstudio.outputDevice = modelData.text
+ }
+ }
+ virtualstudio.restartAudio()
virtualstudio.validateDevicesState()
}
}
anchors.right: inputCombo.horizontalCenter
anchors.rightMargin: 8 * virtualstudio.uiScale
anchors.top: inputChannelsLabel.bottom
- anchors.topMargin: 12 * virtualstudio.uiScale
+ anchors.topMargin: 4 * virtualstudio.uiScale
model: inputChannelsComboModel
currentIndex: (() => {
let idx = inputChannelsComboModel.findIndex(elem => elem.baseChannel === virtualstudio.baseInputChannel
anchors.right: inputCombo.right
anchors.rightMargin: 8 * virtualstudio.uiScale
anchors.top: inputMixModeLabel.bottom
- anchors.topMargin: 12 * virtualstudio.uiScale
+ anchors.topMargin: 4 * virtualstudio.uiScale
model: inputMixModeComboModel
currentIndex: (() => {
let idx = inputMixModeComboModel.findIndex(elem => elem.value === virtualstudio.inputMixMode);
property int fontTiny: 8
property int bodyMargin: 60
+ property int rightMargin: 16
property int bottomToolTipMargin: 8
property int rightToolTipMargin: 4
property string browserButtonStroke: virtualstudio.darkMode ? "#80827D7D" : "#40979797"
property string browserButtonHoverStroke: virtualstudio.darkMode ? "#7B7777" : "#BABCBC"
property string browserButtonPressedStroke: virtualstudio.darkMode ? "#827D7D" : "#BABCBC"
+ property string saveButtonBackgroundColour: "#F2F3F3"
+ property string saveButtonPressedColour: "#E7E8E8"
+ property string saveButtonStroke: "#EAEBEB"
+ property string saveButtonPressedStroke: "#B0B5B5"
+ property string saveButtonText: "#DB0A0A"
property string muteButtonMutedColor: "#FCB6B6"
property string textColour: virtualstudio.darkMode ? "#FAFBFB" : "#0F0D0D"
property string meterYellow: "#F5BF4F"
property string meterRed: "#F21B1B"
+ property bool isUsingRtAudio: virtualstudio.audioBackend == "RtAudio"
+
+ function getCurrentInputDeviceIndex () {
+ if (virtualstudio.inputDevice === "") {
+ return inputComboModel.findIndex(elem => elem.type === "element");
+ }
+
+ let idx = inputComboModel.findIndex(elem => elem.type === "element" && elem.text === virtualstudio.inputDevice);
+ if (idx < 0) {
+ idx = inputComboModel.findIndex(elem => elem.type === "element");
+ }
+
+ return idx;
+ }
+
+ function getCurrentOutputDeviceIndex() {
+ if (virtualstudio.outputDevice === "") {
+ return outputComboModel.findIndex(elem => elem.type === "element");
+ }
+
+ let idx = outputComboModel.findIndex(elem => elem.type === "element" && elem.text === virtualstudio.outputDevice);
+ if (idx < 0) {
+ idx = outputComboModel.findIndex(elem => elem.type === "element");
+ }
+
+ return idx;
+ }
+
function getNetworkStatsText (networkStats) {
let minRtt = networkStats.minRtt;
let maxRtt = networkStats.maxRtt;
return texts;
}
+ Connections {
+ target: virtualstudio
+ function onInputDeviceChanged() {
+ inputCombo.currentIndex = getCurrentInputDeviceIndex();
+ }
+ function onOutputDeviceChanged() {
+ outputCombo.currentIndex = getCurrentOutputDeviceIndex();
+ }
+ }
+
Image {
id: jtlogo
x: parent.width - (49 * virtualstudio.uiScale); y: 16 * virtualstudio.uiScale
inviteKeyString: virtualstudio.currentStudio >= 0 ? serverModel[virtualstudio.currentStudio].inviteKey : ""
}
+ Item {
+ id: deviceSettings
+ visible: showReadyScreen && isUsingRtAudio
+ x: bodyMargin * virtualstudio.uiScale; y: 192 * virtualstudio.uiScale
+ width: parent.width - (2 * x)
+ height: 384 * virtualstudio.uiScale
+ clip: true
+
+ Button {
+ id: deviceSettingsButton
+ background: Rectangle {
+ radius: 6 * virtualstudio.uiScale
+ color: deviceSettingsButton.down ? browserButtonPressedColour : (deviceSettingsButton.hovered ? browserButtonHoverColour : browserButtonColour)
+ }
+ onClicked: popup.open()
+ anchors.right: parent.right
+ width: 144 * virtualstudio.uiScale; height: 24 * virtualstudio.uiScale
+
+ Text {
+ text: "Change Device Settings"
+ font { family: "Poppins"; pixelSize: fontTiny * virtualstudio.fontScale * virtualstudio.uiScale}
+ anchors { horizontalCenter: parent.horizontalCenter; verticalCenter: parent.verticalCenter }
+ color: textColour
+ }
+ }
+
+ Popup {
+ id: popup
+ padding: 1
+ width: parent.width
+ height: parent.height
+ anchors.centerIn: parent
+ modal: true
+ focus: true
+ closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
+ onClosed: {
+ virtualstudio.applySettings()
+ }
+
+ background: Rectangle {
+ anchors.fill: parent
+ color: "transparent"
+ radius: 6 * virtualstudio.uiScale
+ border.width: 1
+ border.color: buttonStroke
+ clip: true
+ }
+
+ contentItem: Rectangle {
+ width: parent.width
+ height: parent.height
+ color: backgroundColour
+ radius: 6 * virtualstudio.uiScale
+
+ Item {
+ id: usingRtAudio
+ anchors.top: parent.top
+ anchors.topMargin: 24 * virtualstudio.uiScale
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ anchors.leftMargin: 24 * virtualstudio.uiScale
+ anchors.right: parent.right
+
+ visible: isUsingRtAudio
+
+ Rectangle {
+ id: leftSpacer
+ x: 0; y: 0
+ width: 144 * virtualstudio.uiScale
+ height: 0
+ color: "transparent"
+ }
+
+ Text {
+ id: outputLabel
+ x: 0; y: 0
+ text: "Output Device"
+ font { family: "Poppins"; pixelSize: fontSmall * virtualstudio.fontScale * virtualstudio.uiScale }
+ color: textColour
+ }
+
+ Image {
+ id: outputHelpIcon
+ anchors.left: outputLabel.right
+ anchors.bottom: outputLabel.top
+ anchors.bottomMargin: -8 * virtualstudio.uiScale
+ source: "help.svg"
+ sourceSize: Qt.size(12 * virtualstudio.uiScale, 12 * virtualstudio.uiScale)
+ fillMode: Image.PreserveAspectFit
+ smooth: true
+
+ property bool showToolTip: false
+
+ Colorize {
+ anchors.fill: parent
+ source: parent
+ hue: 0
+ saturation: 0
+ lightness: virtualstudio.darkMode ? 0.8 : 0.2
+ }
+
+ MouseArea {
+ id: outputMouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+ onEntered: outputHelpIcon.showToolTip = true
+ onExited: outputHelpIcon.showToolTip = false
+ }
+
+ ToolTip {
+ visible: outputHelpIcon.showToolTip
+ contentItem: Rectangle {
+ color: toolTipBackgroundColour
+ radius: 3
+ anchors.fill: parent
+ anchors.bottomMargin: bottomToolTipMargin * virtualstudio.uiScale
+ anchors.rightMargin: rightToolTipMargin * virtualstudio.uiScale
+ layer.enabled: true
+ border.width: 1
+ border.color: buttonStroke
+
+ Text {
+ anchors.centerIn: parent
+ font { family: "Poppins"; pixelSize: fontSmall * virtualstudio.fontScale * virtualstudio.uiScale}
+ text: qsTr("How you'll hear the studio audio")
+ color: toolTipTextColour
+ }
+ }
+ background: Rectangle {
+ color: "transparent"
+ }
+ }
+ }
+
+ Image {
+ id: headphonesIcon
+ anchors.left: outputLabel.left
+ anchors.top: outputLabel.bottom
+ anchors.topMargin: bottomToolTipMargin * virtualstudio.uiScale
+ source: "headphones.svg"
+ sourceSize: Qt.size(28 * virtualstudio.uiScale, 28 * virtualstudio.uiScale)
+ fillMode: Image.PreserveAspectFit
+ smooth: true
+
+ Colorize {
+ anchors.fill: parent
+ source: parent
+ hue: 0
+ saturation: 0
+ lightness: virtualstudio.darkMode ? 1 : 0
+ }
+ }
+
+ ComboBox {
+ id: outputCombo
+ anchors.left: leftSpacer.right
+ anchors.verticalCenter: outputLabel.verticalCenter
+ anchors.rightMargin: rightMargin * virtualstudio.uiScale
+ width: parent.width - leftSpacer.width - rightMargin * virtualstudio.uiScale
+ enabled: virtualstudio.connectionState == "Connected"
+ model: outputComboModel
+ currentIndex: getCurrentOutputDeviceIndex()
+ delegate: ItemDelegate {
+ required property var modelData
+ required property int index
+
+ leftPadding: 0
+
+ width: parent.width
+ contentItem: Text {
+ leftPadding: modelData.type === "element" && outputCombo.model.filter(it => it.type === "header").length > 0 ? 24 : 12
+ text: modelData.text
+ font.bold: modelData.type === "header"
+ }
+ highlighted: outputCombo.highlightedIndex === index
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ if (modelData.type == "element") {
+ outputCombo.currentIndex = index
+ outputCombo.popup.close()
+ virtualstudio.outputDevice = modelData.text
+ if (modelData.category === "Low-Latency (ASIO)") {
+ let inputComboIdx = inputCombo.model.findIndex(it => it.category === "Low-Latency (ASIO)" && it.text === modelData.text);
+ if (inputComboIdx !== null && inputComboIdx !== undefined) {
+ inputCombo.currentIndex = inputComboIdx;
+ virtualstudio.inputDevice = modelData.text
+ }
+ }
+ virtualstudio.validateDevicesState()
+ }
+ }
+ }
+ }
+ contentItem: Text {
+ leftPadding: 12
+ font: outputCombo.font
+ horizontalAlignment: Text.AlignHLeft
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ text: outputCombo.model[outputCombo.currentIndex].text ? outputCombo.model[outputCombo.currentIndex].text : ""
+ }
+ }
+
+ Text {
+ id: outputChannelsLabel
+ anchors.left: outputCombo.left
+ anchors.right: outputCombo.horizontalCenter
+ anchors.top: outputCombo.bottom
+ anchors.topMargin: 12 * virtualstudio.uiScale
+ textFormat: Text.RichText
+ text: "Output Channel(s)"
+ font { family: "Poppins"; pixelSize: fontTiny * virtualstudio.fontScale * virtualstudio.uiScale }
+ color: textColour
+ }
+
+ ComboBox {
+ id: outputChannelsCombo
+ anchors.left: outputCombo.left
+ anchors.right: outputCombo.horizontalCenter
+ anchors.rightMargin: 8 * virtualstudio.uiScale
+ anchors.top: outputChannelsLabel.bottom
+ anchors.topMargin: 4 * virtualstudio.uiScale
+ enabled: virtualstudio.connectionState == "Connected"
+ model: outputChannelsComboModel
+ currentIndex: (() => {
+ let idx = outputChannelsComboModel.findIndex(elem => elem.baseChannel === virtualstudio.baseOutputChannel
+ && elem.numChannels === virtualstudio.numOutputChannels);
+ if (idx < 0) {
+ idx = 0;
+ }
+ return idx;
+ })()
+ delegate: ItemDelegate {
+ required property var modelData
+ required property int index
+ width: parent.width
+ contentItem: Text {
+ text: modelData.label
+ }
+ highlighted: outputChannelsCombo.highlightedIndex === index
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ outputChannelsCombo.currentIndex = index
+ outputChannelsCombo.popup.close()
+ virtualstudio.baseOutputChannel = modelData.baseChannel
+ virtualstudio.numOutputChannels = modelData.numChannels
+ virtualstudio.validateDevicesState()
+ }
+ }
+ }
+ contentItem: Text {
+ leftPadding: 12
+ font: inputCombo.font
+ horizontalAlignment: Text.AlignHLeft
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ text: outputChannelsCombo.model[outputChannelsCombo.currentIndex].label || ""
+ }
+ }
+
+ Text {
+ id: inputLabel
+ anchors.left: outputLabel.left
+ anchors.top: outputChannelsCombo.bottom
+ anchors.topMargin: 32 * virtualstudio.uiScale
+ text: "Input Device"
+ font { family: "Poppins"; pixelSize: fontSmall * virtualstudio.fontScale * virtualstudio.uiScale }
+ color: textColour
+ }
+
+ Image {
+ id: inputHelpIcon
+ anchors.left: inputLabel.right
+ anchors.bottom: inputLabel.top
+ anchors.bottomMargin: -8 * virtualstudio.uiScale
+ source: "help.svg"
+ sourceSize: Qt.size(12 * virtualstudio.uiScale, 12 * virtualstudio.uiScale)
+ fillMode: Image.PreserveAspectFit
+ smooth: true
+
+ property bool showToolTip: false
+
+ Colorize {
+ anchors.fill: parent
+ source: parent
+ hue: 0
+ saturation: 0
+ lightness: virtualstudio.darkMode ? 0.8 : 0.2
+ }
+
+ MouseArea {
+ id: inputMouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+ onEntered: inputHelpIcon.showToolTip = true
+ onExited: inputHelpIcon.showToolTip = false
+ }
+
+ ToolTip {
+ visible: inputHelpIcon.showToolTip
+ contentItem: Rectangle {
+ color: toolTipBackgroundColour
+ radius: 3
+ anchors.fill: parent
+ anchors.bottomMargin: bottomToolTipMargin * virtualstudio.uiScale
+ anchors.rightMargin: rightToolTipMargin * virtualstudio.uiScale
+ layer.enabled: true
+ border.width: 1
+ border.color: buttonStroke
+
+ Text {
+ anchors.centerIn: parent
+ font { family: "Poppins"; pixelSize: fontTiny * virtualstudio.fontScale * virtualstudio.uiScale}
+ text: qsTr("Audio sent to the studio (microphone, instrument, mixer, etc.)")
+ color: toolTipTextColour
+ }
+ }
+ background: Rectangle {
+ color: "transparent"
+ }
+ }
+ }
+
+ Image {
+ id: microphoneIcon
+ anchors.left: inputLabel.left
+ anchors.top: inputLabel.bottom
+ anchors.topMargin: bottomToolTipMargin * virtualstudio.uiScale
+ source: "mic.svg"
+ sourceSize: Qt.size(32 * virtualstudio.uiScale, 32 * virtualstudio.uiScale)
+ fillMode: Image.PreserveAspectFit
+ smooth: true
+
+ Colorize {
+ anchors.fill: parent
+ source: parent
+ hue: 0
+ saturation: 0
+ lightness: virtualstudio.darkMode ? 1 : 0
+ }
+ }
+
+ ComboBox {
+ id: inputCombo
+ model: inputComboModel
+ currentIndex: getCurrentInputDeviceIndex()
+ anchors.left: outputCombo.left
+ anchors.right: outputCombo.right
+ anchors.verticalCenter: inputLabel.verticalCenter
+ enabled: virtualstudio.connectionState == "Connected"
+ delegate: ItemDelegate {
+ required property var modelData
+ required property int index
+
+ leftPadding: 0
+
+ width: parent.width
+ contentItem: Text {
+ leftPadding: modelData.type === "element" && inputCombo.model.filter(it => it.type === "header").length > 0 ? 24 : 12
+ text: modelData.text
+ font.bold: modelData.type === "header"
+ }
+ highlighted: inputCombo.highlightedIndex === index
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ if (modelData.type == "element") {
+ inputCombo.currentIndex = index
+ inputCombo.popup.close()
+ virtualstudio.inputDevice = modelData.text
+ if (modelData.category === "Low-Latency (ASIO)") {
+ let outputComboIdx = outputCombo.model.findIndex(it => it.category === "Low-Latency (ASIO)" && it.text === modelData.text);
+ if (outputComboIdx !== null && outputComboIdx !== undefined) {
+ outputCombo.currentIndex = outputComboIdx;
+ virtualstudio.outputDevice = modelData.text
+ }
+ }
+ virtualstudio.validateDevicesState()
+ }
+ }
+ }
+ }
+ contentItem: Text {
+ leftPadding: 12
+ font: inputCombo.font
+ horizontalAlignment: Text.AlignHLeft
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ text: inputCombo.model[inputCombo.currentIndex].text ? inputCombo.model[inputCombo.currentIndex].text : ""
+ }
+ }
+
+ Text {
+ id: inputChannelsLabel
+ anchors.left: inputCombo.left
+ anchors.right: inputCombo.horizontalCenter
+ anchors.top: inputCombo.bottom
+ anchors.topMargin: 12 * virtualstudio.uiScale
+ textFormat: Text.RichText
+ text: "Input Channel(s)"
+ font { family: "Poppins"; pixelSize: fontTiny * virtualstudio.fontScale * virtualstudio.uiScale }
+ color: textColour
+ }
+
+ ComboBox {
+ id: inputChannelsCombo
+ anchors.left: inputCombo.left
+ anchors.right: inputCombo.horizontalCenter
+ anchors.rightMargin: 8 * virtualstudio.uiScale
+ anchors.top: inputChannelsLabel.bottom
+ anchors.topMargin: 4 * virtualstudio.uiScale
+ enabled: virtualstudio.connectionState == "Connected"
+ model: inputChannelsComboModel
+ currentIndex: (() => {
+ let idx = inputChannelsComboModel.findIndex(elem => elem.baseChannel === virtualstudio.baseInputChannel
+ && elem.numChannels === virtualstudio.numInputChannels);
+ if (idx < 0) {
+ idx = 0;
+ }
+ return idx;
+ })()
+ delegate: ItemDelegate {
+ required property var modelData
+ required property int index
+ width: parent.width
+ contentItem: Text {
+ text: modelData.label
+ }
+ highlighted: inputChannelsCombo.highlightedIndex === index
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ inputChannelsCombo.currentIndex = index
+ inputChannelsCombo.popup.close()
+ virtualstudio.baseInputChannel = modelData.baseChannel
+ virtualstudio.numInputChannels = modelData.numChannels
+ virtualstudio.validateDevicesState()
+ }
+ }
+ }
+ contentItem: Text {
+ leftPadding: 12
+ font: inputCombo.font
+ horizontalAlignment: Text.AlignHLeft
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ text: inputChannelsCombo.model[inputChannelsCombo.currentIndex].label || ""
+ }
+ }
+
+ Text {
+ id: inputMixModeLabel
+ anchors.left: inputCombo.horizontalCenter
+ anchors.right: inputCombo.right
+ anchors.rightMargin: 8 * virtualstudio.uiScale
+ anchors.top: inputCombo.bottom
+ anchors.topMargin: 12 * virtualstudio.uiScale
+ textFormat: Text.RichText
+ text: "Mono / Stereo"
+ font { family: "Poppins"; pixelSize: fontTiny * virtualstudio.fontScale * virtualstudio.uiScale }
+ color: textColour
+ }
+
+ ComboBox {
+ id: inputMixModeCombo
+ anchors.left: inputCombo.horizontalCenter
+ anchors.right: inputCombo.right
+ anchors.rightMargin: 8 * virtualstudio.uiScale
+ anchors.top: inputMixModeLabel.bottom
+ anchors.topMargin: 4 * virtualstudio.uiScale
+ enabled: virtualstudio.connectionState == "Connected"
+ model: inputMixModeComboModel
+ currentIndex: (() => {
+ let idx = inputMixModeComboModel.findIndex(elem => elem.value === virtualstudio.inputMixMode);
+ if (idx < 0) {
+ idx = 0;
+ }
+ return idx;
+ })()
+ delegate: ItemDelegate {
+ required property var modelData
+ required property int index
+ width: parent.width
+ contentItem: Text {
+ text: modelData.label
+ }
+ highlighted: inputMixModeCombo.highlightedIndex === index
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ inputMixModeCombo.currentIndex = index
+ inputMixModeCombo.popup.close()
+ virtualstudio.inputMixMode = inputMixModeComboModel[index].value
+ virtualstudio.validateDevicesState()
+ }
+ }
+ }
+ contentItem: Text {
+ leftPadding: 12
+ font: inputCombo.font
+ horizontalAlignment: Text.AlignHLeft
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ text: inputMixModeCombo.model[inputMixModeCombo.currentIndex].label || ""
+ }
+ }
+
+ Text {
+ id: inputChannelHelpMessage
+ anchors.left: inputChannelsCombo.left
+ anchors.leftMargin: 2 * virtualstudio.uiScale
+ anchors.right: inputChannelsCombo.right
+ anchors.top: inputChannelsCombo.bottom
+ anchors.topMargin: 8 * virtualstudio.uiScale
+ textFormat: Text.RichText
+ wrapMode: Text.WordWrap
+ text: "Choose up to 2 channels"
+ font { family: "Poppins"; pixelSize: fontTiny * virtualstudio.fontScale * virtualstudio.uiScale }
+ color: textColour
+ }
+
+ Text {
+ id: inputMixModeHelpMessage
+ anchors.left: inputMixModeCombo.left
+ anchors.leftMargin: 2 * virtualstudio.uiScale
+ anchors.right: inputMixModeCombo.right
+ anchors.top: inputMixModeCombo.bottom
+ anchors.topMargin: 8 * virtualstudio.uiScale
+ textFormat: Text.RichText
+ wrapMode: Text.WordWrap
+ text: (() => {
+ if (virtualstudio.inputMixMode === 2) {
+ return "Treat the channels as Left and Right signals, coming through each speaker separately.";
+ } else if (virtualstudio.inputMixMode === 3) {
+ return "Combine the channels into one central channel coming through both speakers.";
+ } else if (virtualstudio.inputMixMode === 1) {
+ return "Send a single channel of audio";
+ } else {
+ return "";
+ }
+ })()
+ font { family: "Poppins"; pixelSize: fontTiny * virtualstudio.fontScale * virtualstudio.uiScale }
+ color: textColour
+ }
+
+ Button {
+ id: closePopupButton
+ anchors.right: parent.right
+ anchors.rightMargin: rightMargin * virtualstudio.uiScale
+ anchors.bottomMargin: rightMargin * virtualstudio.uiScale
+ anchors.bottom: parent.bottom
+ width: 150 * virtualstudio.uiScale; height: 30 * virtualstudio.uiScale
+ onClicked: popup.close()
+
+ background: Rectangle {
+ radius: 6 * virtualstudio.uiScale
+ color: closePopupButton.down ? browserButtonPressedColour : (closePopupButton.hovered ? browserButtonHoverColour : browserButtonColour)
+ border.width: 1
+ border.color: closePopupButton.down ? browserButtonPressedStroke : (closePopupButton.hovered ? browserButtonHoverStroke : browserButtonStroke)
+ }
+
+ Text {
+ text: "Close"
+ font.family: "Poppins"
+ font.pixelSize: fontSmall * virtualstudio.fontScale * virtualstudio.uiScale
+ font.weight: Font.Bold
+ color: !Boolean(virtualstudio.devicesError) && virtualstudio.backendAvailable ? saveButtonText : disabledButtonText
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ }
+
+ Button {
+ id: refreshButton
+ text: "Refresh Devices"
+ anchors.right: closePopupButton.left
+ anchors.rightMargin: 8 * virtualstudio.uiScale
+ anchors.bottomMargin: rightMargin * virtualstudio.uiScale
+ anchors.bottom: parent.bottom
+ width: 150 * virtualstudio.uiScale; height: 30 * virtualstudio.uiScale
+ enabled: virtualstudio.connectionState == "Connected"
+
+ palette.buttonText: textColour
+ background: Rectangle {
+ radius: 6 * virtualstudio.uiScale
+ color: refreshButton.down ? browserButtonPressedColour : (refreshButton.hovered ? browserButtonHoverColour : browserButtonColour)
+ border.width: 1
+ border.color: refreshButton.down ? browserButtonPressedStroke : (refreshButton.hovered ? browserButtonHoverStroke : browserButtonStroke)
+ }
+
+ icon {
+ source: "refresh.svg";
+ color: textColour;
+ }
+ display: AbstractButton.TextBesideIcon
+ onClicked: {
+ virtualstudio.validateDevicesState();
+ }
+
+ font {
+ family: "Poppins"
+ pixelSize: fontSmall * virtualstudio.fontScale * virtualstudio.uiScale
+ }
+ }
+ }
+ }
+ }
+ }
+
Item {
id: inputDevice
visible: showReadyScreen
- x: bodyMargin * virtualstudio.uiScale; y: 230 * virtualstudio.uiScale
+ x: bodyMargin * virtualstudio.uiScale; y: 240 * virtualstudio.uiScale
width: Math.min(parent.width / 2, 320 * virtualstudio.uiScale) - x
height: 100 * virtualstudio.uiScale
clip: true
visible: showReadyScreen
x: bodyMargin * virtualstudio.uiScale; y: 320 * virtualstudio.uiScale
width: Math.min(parent.width / 2, 320 * virtualstudio.uiScale) - x
- height: 100 * virtualstudio.uiScale
+ height: 124 * virtualstudio.uiScale
clip: true
+ anchors.top: inputDevice.bottom
Image {
id: headphones
Item {
id: inputControls
visible: showReadyScreen
- x: inputDevice.x + inputDevice.width; y: 230 * virtualstudio.uiScale
+ x: inputDevice.x + inputDevice.width; y: 240 * virtualstudio.uiScale
width: parent.width - inputDevice.width - 2 * bodyMargin * virtualstudio.uiScale
Meter {
padding: 0
y: inputDeviceMeters.y + 36 * virtualstudio.uiScale
anchors.left: inputMute.right
+ anchors.right: inputStudioText.left
anchors.leftMargin: 8 * virtualstudio.uiScale
- anchors.right: inputDeviceMeters.right
+ anchors.rightMargin: 16 * virtualstudio.uiScale
opacity: virtualstudio.inputMuted ? 0.3 : 1
background: Rectangle {
}
}
}
+
+ Text {
+ id: inputStudioText
+ width: 40 * virtualstudio.uiScale
+ height: 24
+ horizontalAlignment: Text.AlignRight
+ anchors.right: inputDeviceMeters.right
+ anchors.verticalCenter: inputSlider.verticalCenter
+ topPadding: 4 * virtualstudio.uiScale
+ rightPadding: 4 * virtualstudio.uiScale
+ text: "Send"
+ font {family: "Poppins"; pixelSize: fontTiny * virtualstudio.fontScale * virtualstudio.uiScale; bold: true }
+ color: textColour
+ }
+
+ Image {
+ id: inputStudioHelpIcon
+ anchors.left: inputStudioText.right
+ anchors.verticalCenter: inputStudioText.verticalCenter
+ anchors.bottomMargin: -8 * virtualstudio.uiScale
+ source: "help.svg"
+ sourceSize: Qt.size(12 * virtualstudio.uiScale, 12 * virtualstudio.uiScale)
+ fillMode: Image.PreserveAspectFit
+ smooth: true
+
+ property bool showToolTip: false
+
+ Colorize {
+ anchors.fill: parent
+ source: parent
+ hue: 0
+ saturation: 0
+ lightness: virtualstudio.darkMode ? 0.8 : 0.2
+ }
+
+ MouseArea {
+ id: inputStudioMouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+ onEntered: inputStudioHelpIcon.showToolTip = true
+ onExited: inputStudioHelpIcon.showToolTip = false
+ }
+
+ ToolTip {
+ visible: inputStudioHelpIcon.showToolTip
+ contentItem: Rectangle {
+ color: toolTipBackgroundColour
+ radius: 3
+ anchors.fill: parent
+ anchors.bottomMargin: bottomToolTipMargin * virtualstudio.uiScale
+ anchors.rightMargin: rightToolTipMargin * virtualstudio.uiScale
+ layer.enabled: true
+ border.width: 1
+ border.color: buttonStroke
+
+ Text {
+ anchors.centerIn: parent
+ font { family: "Poppins"; pixelSize: fontSmall * virtualstudio.fontScale * virtualstudio.uiScale}
+ text: qsTr("How loudly other participants hear you")
+ color: toolTipTextColour
+ }
+ }
+ background: Rectangle {
+ color: "transparent"
+ }
+ }
+ }
}
Item {
visible: showReadyScreen
x: outputDevice.x + outputDevice.width; y: 320 * virtualstudio.uiScale
width: parent.width - inputDevice.width - 2 * bodyMargin * virtualstudio.uiScale
+ anchors.top: inputDevice.bottom
Meter {
id: outputDeviceMeters
padding: 0
y: outputDeviceMeters.y + 36 * virtualstudio.uiScale
anchors.left: outputDeviceMeters.left
- anchors.right: outputDeviceMeters.right
+ anchors.right: outputStudioText.left
+ anchors.rightMargin: 16 * virtualstudio.uiScale
background: Rectangle {
x: outputSlider.leftPadding
border.color: buttonStroke
}
}
+
+ Slider {
+ id: monitorSlider
+ from: 0.0
+ value: virtualstudio ? virtualstudio.monitorVolume : 0.5
+ onMoved: { virtualstudio.monitorVolume = value }
+ to: 1.0
+ padding: 0
+ y: outputSlider.y + 36 * virtualstudio.uiScale
+ anchors.left: outputDeviceMeters.left
+ anchors.right: outputMonText.left
+ anchors.rightMargin: 16 * virtualstudio.uiScale
+
+ background: Rectangle {
+ x: monitorSlider.leftPadding
+ y: monitorSlider.topPadding + monitorSlider.availableHeight / 2 - height / 2
+ implicitWidth: parent.width
+ implicitHeight: 6
+ width: monitorSlider.availableWidth
+ height: implicitHeight
+ radius: 4
+ color: sliderTrackColour
+
+ Rectangle {
+ width: monitorSlider.visualPosition * parent.width
+ height: parent.height
+ color: sliderActiveTrackColour
+ radius: 4
+ }
+ }
+
+ handle: Rectangle {
+ x: monitorSlider.leftPadding + monitorSlider.visualPosition * (monitorSlider.availableWidth - width)
+ y: monitorSlider.topPadding + monitorSlider.availableHeight / 2 - height / 2
+ implicitWidth: 26 * virtualstudio.uiScale
+ implicitHeight: 26 * virtualstudio.uiScale
+ radius: 13 * virtualstudio.uiScale
+ color: monitorSlider.pressed ? sliderPressedColour : sliderColour
+ border.color: buttonStroke
+ }
+ }
+
+ Text {
+ id: outputStudioText
+ width: 40 * virtualstudio.uiScale
+ height: 24
+ horizontalAlignment: Text.AlignRight
+ anchors.right: outputDeviceMeters.right
+ anchors.verticalCenter: outputSlider.verticalCenter
+ topPadding: 4 * virtualstudio.uiScale
+ rightPadding: 4 * virtualstudio.uiScale
+ text: "Studio"
+ font {family: "Poppins"; pixelSize: fontTiny * virtualstudio.fontScale * virtualstudio.uiScale; bold: true }
+ color: textColour
+ }
+
+ Image {
+ id: outputStudioHelpIcon
+ anchors.left: outputStudioText.right
+ anchors.verticalCenter: outputStudioText.verticalCenter
+ anchors.bottomMargin: -8 * virtualstudio.uiScale
+ source: "help.svg"
+ sourceSize: Qt.size(12 * virtualstudio.uiScale, 12 * virtualstudio.uiScale)
+ fillMode: Image.PreserveAspectFit
+ smooth: true
+
+ property bool showToolTip: false
+
+ Colorize {
+ anchors.fill: parent
+ source: parent
+ hue: 0
+ saturation: 0
+ lightness: virtualstudio.darkMode ? 0.8 : 0.2
+ }
+
+ MouseArea {
+ id: outputStudioMouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+ onEntered: outputStudioHelpIcon.showToolTip = true
+ onExited: outputStudioHelpIcon.showToolTip = false
+ }
+
+ ToolTip {
+ visible: outputStudioHelpIcon.showToolTip
+ contentItem: Rectangle {
+ color: toolTipBackgroundColour
+ radius: 3
+ anchors.fill: parent
+ anchors.bottomMargin: bottomToolTipMargin * virtualstudio.uiScale
+ anchors.rightMargin: rightToolTipMargin * virtualstudio.uiScale
+ layer.enabled: true
+ border.width: 1
+ border.color: buttonStroke
+
+ Text {
+ anchors.centerIn: parent
+ font { family: "Poppins"; pixelSize: fontSmall * virtualstudio.fontScale * virtualstudio.uiScale}
+ text: qsTr("How loudly you hear other participants")
+ color: toolTipTextColour
+ }
+ }
+ background: Rectangle {
+ color: "transparent"
+ }
+ }
+ }
+
+ Text {
+ id: outputMonText
+ width: 40 * virtualstudio.uiScale
+ height: 24
+ horizontalAlignment: Text.AlignRight
+ anchors.right: outputDeviceMeters.right
+ anchors.verticalCenter: monitorSlider.verticalCenter
+ topPadding: 4 * virtualstudio.uiScale
+ rightPadding: 4 * virtualstudio.uiScale
+ text: "Monitor"
+ font {family: "Poppins"; pixelSize: fontTiny * virtualstudio.fontScale * virtualstudio.uiScale; bold: true }
+ color: textColour
+ }
+
+ Image {
+ id: outputMonHelpIcon
+ anchors.left: outputMonText.right
+ anchors.verticalCenter: outputMonText.verticalCenter
+ anchors.bottomMargin: -8 * virtualstudio.uiScale
+ source: "help.svg"
+ sourceSize: Qt.size(12 * virtualstudio.uiScale, 12 * virtualstudio.uiScale)
+ fillMode: Image.PreserveAspectFit
+ smooth: true
+
+ property bool showToolTip: false
+
+ Colorize {
+ anchors.fill: parent
+ source: parent
+ hue: 0
+ saturation: 0
+ lightness: virtualstudio.darkMode ? 0.8 : 0.2
+ }
+
+ MouseArea {
+ id: outputMonMouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+ onEntered: outputMonHelpIcon.showToolTip = true
+ onExited: outputMonHelpIcon.showToolTip = false
+ }
+
+ ToolTip {
+ visible: outputMonHelpIcon.showToolTip
+ contentItem: Rectangle {
+ color: toolTipBackgroundColour
+ radius: 3
+ anchors.fill: parent
+ anchors.bottomMargin: bottomToolTipMargin * virtualstudio.uiScale
+ anchors.rightMargin: rightToolTipMargin * virtualstudio.uiScale
+ layer.enabled: true
+ border.width: 1
+ border.color: buttonStroke
+
+ Text {
+ anchors.centerIn: parent
+ font { family: "Poppins"; pixelSize: fontSmall * virtualstudio.fontScale * virtualstudio.uiScale}
+ text: qsTr("How loudly you hear yourself")
+ color: toolTipTextColour
+ }
+ }
+ background: Rectangle {
+ color: "transparent"
+ }
+ }
+ }
}
Item {
id: networkStatsHeader
visible: showReadyScreen
- x: bodyMargin * virtualstudio.uiScale; y: 410 * virtualstudio.uiScale
+ x: bodyMargin * virtualstudio.uiScale; y: 450 * virtualstudio.uiScale
width: Math.min(parent.width / 2, 320 * virtualstudio.uiScale) - x
height: 128 * virtualstudio.uiScale
+ anchors.top: outputDevice.bottom
Image {
id: network
Item {
id: networkStatsText
visible: showReadyScreen
- x: networkStatsHeader.x + networkStatsHeader.width; y: 410 * virtualstudio.uiScale
+ x: networkStatsHeader.x + networkStatsHeader.width; y: 450 * virtualstudio.uiScale
width: parent.width - networkStatsHeader.width - 2 * bodyMargin * virtualstudio.uiScale
height: 72 * virtualstudio.uiScale
+ anchors.top: outputDevice.bottom
Text {
id: netstat0
text: "You will be automatically connected to the studio when it is ready."
wrapMode: Text.WordWrap
}
+
+ Text {
+ id: connectedErrorMessage1
+ x: 0
+ width: parent.width
+ color: warningTextColour
+ anchors.top: waitingText1.bottom
+ anchors.topMargin: 16 * virtualstudio.uiScale
+ anchors.bottomMargin: 16 * virtualstudio.uiScale
+ visible: parent.isAdmin && Boolean(virtualstudio.connectedErrorMsg)
+ textFormat: Text.RichText
+ text: virtualstudio.connectedErrorMsg == "one-studio-limit-reached"
+ ? `Your current plan allows you to use 1 studio at a time. <a style="color: ${linkText}; cursor: pointer" href="https://help.jacktrip.org/hc/en-us/requests/new">Contact us</a> to use multiple studios at a time.`
+ : ""
+ onLinkActivated: link => {
+ virtualstudio.openLink(link)
+ }
+ font {family: "Poppins"; pixelSize: fontSmall * virtualstudio.fontScale * virtualstudio.uiScale }
+ wrapMode: Text.WordWrap
+ }
}
Item {
}
property bool failTextVisible: false
+ property bool showBackButton: true
property string backgroundColour: virtualstudio.darkMode ? "#272525" : "#FAFBFB"
property string textColour: virtualstudio.darkMode ? "#FAFBFB" : "#0F0D0D"
border.color: loginButton.down ? buttonPressedStroke : (loginButton.hovered ? buttonHoverStroke : buttonStroke)
layer.enabled: !loginButton.down
}
- onClicked: { failTextVisible = false; virtualstudio.login() }
+ onClicked: { virtualstudio.showFirstRun = false; failTextVisible = false; virtualstudio.login() }
anchors.horizontalCenter: parent.horizontalCenter
- y: 321 * virtualstudio.uiScale
+ y: showBackButton ? 321 * virtualstudio.uiScale : 371 * virtualstudio.uiScale
width: 263 * virtualstudio.uiScale; height: 64 * virtualstudio.uiScale
Text {
text: "Sign In"
Button {
id: backButton
+ visible: showBackButton
background: Rectangle {
radius: 6 * virtualstudio.uiScale
color: backButton.down ? buttonPressedColour : (backButton.hovered ? buttonHoverColour : buttonColour)
anchors.verticalCenter: parent.verticalCenter
color: backButton.down ? buttonTextPressed : (backButton.hovered ? buttonTextHover : buttonTextColour)
}
- visible: true
+ }
+
+
+ Button {
+ id: classicModeButton
+ visible: !showBackButton && virtualstudio.showFirstRun && virtualstudio.vsFtux
+ background: Rectangle {
+ radius: 6 * virtualstudio.uiScale
+ color: classicModeButton.down ? buttonPressedColour : (classicModeButton.hovered ? buttonHoverColour : backgroundColour)
+ border.width: 0
+ layer.enabled: !classicModeButton.down
+ }
+ onClicked: { virtualstudio.windowState = "login"; virtualstudio.toStandard(); }
+ anchors.horizontalCenter: parent.horizontalCenter
+ y: 600 * virtualstudio.uiScale
+ width: 160 * virtualstudio.uiScale; height: 32 * virtualstudio.uiScale
+ Text {
+ text: "Use Classic Mode"
+ font.family: "Poppins"
+ font.pixelSize: 9 * virtualstudio.fontScale * virtualstudio.uiScale
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ color: classicModeButton.down ? buttonTextPressed : (classicModeButton.hovered ? buttonTextHover : textColour)
+ }
}
}
property string sliderPressedColour: virtualstudio.darkMode ? "#ACAFAF" : "#DEE0E0"
property string sliderTrackColour: virtualstudio.darkMode ? "#5B5858" : "light gray"
property string sliderActiveTrackColour: virtualstudio.darkMode ? "light gray" : "black"
- property string saveButtonShadow: "#80A1A1A1"
property string saveButtonBackgroundColour: "#F2F3F3"
property string saveButtonPressedColour: "#E7E8E8"
property string saveButtonStroke: "#EAEBEB"
</qresource>
<qresource prefix="vs">
<file>vs.qml</file>
+ <file>vsftux.qml</file>
<file>FirstLaunch.qml</file>
<file>Login.qml</file>
<file>Studio.qml</file>
</item>
<item>
<property name="text">
- <string>3 (experimental)</string>
+ <string>3 (experimental - in own thread) </string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>4 (experimental - in callback)</string>
</property>
</item>
</widget>
QVariantList() << QVariant(QJsonValue(outputChannelsComboElement)))));
#endif
- m_bufferStrategy = settings.value(QStringLiteral("BufferStrategy"), 0).toInt();
+ m_bufferStrategy = settings.value(QStringLiteral("BufferStrategy"), 2).toInt();
settings.endGroup();
#ifdef USE_WEAK_JACK
QStringLiteral("backendComboModel"),
QVariant::fromValue(QStringList()
<< QStringLiteral("JACK") << QStringLiteral("RtAudio")));
+#ifdef VS_FTUX
+ m_view.setSource(QUrl(QStringLiteral("qrc:/vs/vsftux.qml")));
+#else
m_view.setSource(QUrl(QStringLiteral("qrc:/vs/vs.qml")));
+#endif // VS_FTUX
m_view.setMinimumSize(QSize(594, 519));
// m_view.setMaximumSize(QSize(696, 577));
m_view.setResizeMode(QQuickView::SizeRootObjectToView);
#ifdef RT_AUDIO
m_inputDevice = device;
emit inputDeviceChanged(m_inputDevice, false);
- emit inputDeviceSelected(m_inputDevice);
#endif
}
#ifdef RT_AUDIO
m_outputDevice = device;
emit outputDeviceChanged(m_outputDevice, false);
- emit outputDeviceSelected(m_outputDevice);
#endif
}
return m_devicesErrorHelpUrl;
}
+QString VirtualStudio::connectedErrorMsg()
+{
+ return m_connectedErrorMsg;
+}
+
+void VirtualStudio::setConnectedErrorMsg(const QString& msg)
+{
+ m_connectedErrorMsg = msg;
+ emit connectedErrorMsgChanged();
+}
+
float VirtualStudio::inputVolume()
{
return m_inMultiplier;
return m_outMultiplier;
}
+float VirtualStudio::monitorVolume()
+{
+ return m_monMultiplier;
+}
+
bool VirtualStudio::inputMuted()
{
return m_inMuted;
return m_outMuted;
}
+bool VirtualStudio::monitorMuted()
+{
+ return m_monMuted;
+}
+
bool VirtualStudio::audioActivated()
{
return m_audioActivated;
emit updatedOutputVolume(multiplier);
}
+void VirtualStudio::setMonitorVolume(float multiplier)
+{
+ m_monMultiplier = multiplier;
+ QSettings settings;
+ settings.beginGroup(QStringLiteral("Audio"));
+ settings.setValue(QStringLiteral("MonMultiplier"), m_monMultiplier);
+ settings.endGroup();
+ emit updatedMonitorVolume(multiplier);
+}
+
void VirtualStudio::setInputMuted(bool muted)
{
m_inMuted = muted;
emit updatedOutputMuted(muted);
}
+void VirtualStudio::setMonitorMuted(bool muted)
+{
+ m_monMuted = muted;
+ QSettings settings;
+ settings.beginGroup(QStringLiteral("Audio"));
+ settings.setValue(QStringLiteral("MonMuted"), m_monMuted ? 1 : 0);
+ settings.endGroup();
+ emit updatedMonitorMuted(muted);
+}
+
int VirtualStudio::bufferSize()
{
#ifdef RT_AUDIO
emit apiHostChanged();
}
+bool VirtualStudio::vsFtux()
+{
+ return m_vsFtux;
+}
+
bool VirtualStudio::showWarnings()
{
return m_showWarnings;
setAudioReady(false);
}
+ refreshRtAudioDevices();
+ validateDevicesState();
+ if (!m_vsAudioInterface.isNull()) {
+ restartAudio();
+ }
+#endif
+}
+
+void VirtualStudio::refreshRtAudioDevices()
+{
+ if (!m_useRtAudio) {
+ return;
+ }
+#ifdef RT_AUDIO
RtAudioInterface::getDeviceList(&m_inputDeviceList, &m_inputDeviceCategories,
&m_inputDeviceChannels, true);
RtAudioInterface::getDeviceList(&m_outputDeviceList, &m_outputDeviceCategories,
inputComboModel);
m_view.engine()->rootContext()->setContextProperty(QStringLiteral("outputComboModel"),
outputComboModel);
- validateDevicesState();
- if (!m_vsAudioInterface.isNull()) {
- restartAudio();
- }
#endif
}
{
validateInputDevicesState();
validateOutputDevicesState();
+ if (m_useRtAudio && m_connectionState == "Connected") {
+ triggerReconnect();
+ }
}
void VirtualStudio::validateInputDevicesState()
if (m_inputDevice == QStringLiteral("")
|| m_inputDeviceList.indexOf(m_inputDevice) == -1) {
m_inputDevice = m_inputDeviceList[0];
- emit inputDeviceChanged(m_inputDevice, false);
}
+ emit inputDeviceChanged(m_inputDevice, false);
// Given the currently selected input device, reset the available input channel
// options
if (m_outputDevice == QStringLiteral("")
|| m_outputDeviceList.indexOf(m_outputDevice) == -1) {
m_outputDevice = m_outputDeviceList[0];
- emit outputDeviceChanged(m_outputDevice, false);
}
+ emit outputDeviceChanged(m_outputDevice, false);
// Given the currently selected output device, reset the available output channel
// options
} else {
completeConnection();
}
+
+ if (m_device != nullptr) {
+ m_device->setReconnect(false);
+ }
}
void VirtualStudio::completeConnection()
m_connectionState = QStringLiteral("Preparing audio...");
emit connectionStateChanged();
try {
- std::string input = "";
- std::string output = "";
- int buffer_size = 0;
+ std::string input = "";
+ std::string output = "";
+ int buffer_size = 0;
+ int inputMixMode = -1;
+ int baseInputChannel = 0;
+ int numInputChannels = 2;
+ int baseOutputChannel = 0;
+ int numOutputChannels = 2;
#ifdef RT_AUDIO
if (m_useRtAudio) {
- input = m_inputDevice.toStdString();
- output = m_outputDevice.toStdString();
- buffer_size = m_bufferSize;
+ input = m_inputDevice.toStdString();
+ output = m_outputDevice.toStdString();
+ buffer_size = m_bufferSize;
+ inputMixMode = m_inputMixMode;
+ baseInputChannel = m_baseInputChannel;
+ numInputChannels = m_numInputChannels;
+ baseOutputChannel = m_baseOutputChannel;
+ numOutputChannels = m_numOutputChannels;
}
- int inputMixMode = m_inputMixMode;
-#else
- int inputMixMode = -1;
-#endif
- JackTrip* jackTrip = m_device->initJackTrip(
- m_useRtAudio, input, output,
-#ifdef RT_AUDIO
- m_baseInputChannel, m_numInputChannels, m_baseOutputChannel,
- m_numOutputChannels,
-#else
- 0, 2, 0, 2, // default to 2 channels for input and 2 channels for output
- // starting at channel 0
#endif
- inputMixMode, buffer_size, m_bufferStrategy, studioInfo);
+ int bufferStrategy = m_bufferStrategy;
+ if (bufferStrategy == 2) {
+ bufferStrategy = 3;
+ }
+ JackTrip* jackTrip =
+ m_device->initJackTrip(m_useRtAudio, input, output, baseInputChannel,
+ numInputChannels, baseOutputChannel, numOutputChannels,
+ inputMixMode, buffer_size, bufferStrategy, studioInfo);
if (jackTrip == 0) {
processError("Could not bind port");
return;
connect(this, &VirtualStudio::updatedInputMuted, m_inputVolumePlugin,
&Volume::muteUpdated);
- // Setup output meter
- m_outputMeter = new Meter(jackTrip->getNumOutputChannels());
- jackTrip->appendProcessPluginFromNetwork(m_outputMeter);
- connect(m_outputMeter, &Meter::onComputedVolumeMeasurements, this,
- &VirtualStudio::updatedOutputVuMeasurements);
-
// Setup input meter
m_inputMeter = new Meter(jackTrip->getNumInputChannels());
jackTrip->appendProcessPluginToNetwork(m_inputMeter);
connect(m_inputMeter, &Meter::onComputedVolumeMeasurements, this,
&VirtualStudio::updatedInputVuMeasurements);
+ // Setup monitor
+ // Note: Constructor determines how many internal monitor buffers to allocate
+ m_monitor = new Monitor(
+ std::max(jackTrip->getNumInputChannels(), jackTrip->getNumOutputChannels()));
+ jackTrip->appendProcessPluginToMonitor(m_monitor);
+ connect(this, &VirtualStudio::updatedMonitorVolume, m_monitor,
+ &Monitor::volumeUpdated);
+
+ // Setup output meter
+ // Note: Add this to monitor process to include self-volume
+ m_outputMeter = new Meter(jackTrip->getNumOutputChannels());
+ m_outputMeter->setIsMonitoringMeter(true);
+ jackTrip->appendProcessPluginToMonitor(m_outputMeter);
+ connect(m_outputMeter, &Meter::onComputedVolumeMeasurements, this,
+ &VirtualStudio::updatedOutputVuMeasurements);
+
// Grab previous levels
QSettings settings;
settings.beginGroup(QStringLiteral("Audio"));
m_inMultiplier = settings.value(QStringLiteral("InMultiplier"), 1).toFloat();
m_outMultiplier = settings.value(QStringLiteral("OutMultiplier"), 1).toFloat();
+ m_monMultiplier = settings.value(QStringLiteral("MonMultiplier"), 0).toFloat();
m_inMuted = settings.value(QStringLiteral("InMuted"), false).toBool();
m_outMuted = settings.value(QStringLiteral("OutMuted"), false).toBool();
+ m_monMuted = settings.value(QStringLiteral("MonMuted"), false).toBool();
+
emit updatedInputVolume(m_inMultiplier);
emit updatedOutputVolume(m_outMultiplier);
+ emit updatedMonitorVolume(m_monMultiplier);
emit updatedInputMuted(m_inMuted);
emit updatedOutputMuted(m_outMuted);
#endif
}
+void VirtualStudio::triggerReconnect()
+{
+ if (m_jackTripRunning) {
+ m_connectionState = QStringLiteral("Reconnecting...");
+ emit connectionStateChanged();
+ m_retryPeriodTimer.stop();
+ m_retryPeriod = false;
+ if (m_device != nullptr) {
+ m_device->setReconnect(true);
+ }
+ }
+}
+
void VirtualStudio::disconnect()
{
m_connectionState = QStringLiteral("Disconnecting...");
emit connectionStateChanged();
+ setConnectedErrorMsg("");
m_retryPeriodTimer.stop();
m_retryPeriod = false;
emit connectionStateChanged();
// cleanup
+ m_monitor = nullptr;
m_inputMeter = nullptr;
m_outputMeter = nullptr;
m_inputVolumePlugin = nullptr;
request.toJson());
connect(reply, &QNetworkReply::finished, this, [&, reply]() {
if (reply->error() != QNetworkReply::NoError) {
- m_connectionState = QStringLiteral("Unable to Start Studio");
+ m_connectionState = QStringLiteral("Unable to Start Studio");
+ QJsonDocument errorDoc = QJsonDocument::fromJson(reply->readAll());
+ if (!errorDoc.isNull()) {
+ QJsonObject errorObj = errorDoc.object();
+ if (errorObj.contains("error")) {
+ QString errorMessage = errorObj.value("error").toString();
+ if (errorMessage.contains(
+ "Only one studio may be running at a time")) {
+ setConnectedErrorMsg("one-studio-limit-reached");
+ }
+ }
+ }
emit connectionStateChanged();
} else {
+ setConnectedErrorMsg("");
QByteArray response = reply->readAll();
QJsonDocument serverState = QJsonDocument::fromJson(response);
if (serverState.object()[QStringLiteral("status")].toString()
&VirtualStudio::setOutputVolume);
connect(m_device, &VsDevice::updatedPlaybackMuteFromServer, this,
&VirtualStudio::setOutputMuted);
+ connect(m_device, &VsDevice::updatedMonitorVolume, this,
+ &VirtualStudio::setMonitorVolume);
connect(this, &VirtualStudio::updatedInputVolume, m_device,
&VsDevice::updateCaptureVolume);
connect(this, &VirtualStudio::updatedInputMuted, m_device,
&VsDevice::updatePlaybackVolume);
connect(this, &VirtualStudio::updatedOutputMuted, m_device,
&VsDevice::updatePlaybackMute);
+ connect(this, &VirtualStudio::updatedMonitorVolume, m_device,
+ &VsDevice::updateMonitorVolume);
}
void VirtualStudio::slotAuthFailed()
void VirtualStudio::processFinished()
{
+ if (m_device != nullptr && m_device->reconnect()) {
+ if (m_device != nullptr && m_device->hasTerminated()) {
+ if (m_useRtAudio) {
+ refreshRtAudioDevices();
+ validateInputDevicesState();
+ validateOutputDevicesState();
+ }
+ connectToStudio(m_currentStudio);
+ }
+ return;
+ }
// use disconnect function to handle reset of all internal flags and timers
disconnect();
connect(this, &VirtualStudio::inputDeviceChanged, m_vsAudioInterface.data(),
&VsAudioInterface::setInputDevice);
- connect(this, &VirtualStudio::inputDeviceSelected, m_vsAudioInterface.data(),
- &VsAudioInterface::setInputDevice);
connect(this, &VirtualStudio::outputDeviceChanged, m_vsAudioInterface.data(),
&VsAudioInterface::setOutputDevice);
- connect(this, &VirtualStudio::outputDeviceSelected, m_vsAudioInterface.data(),
- &VsAudioInterface::setOutputDevice);
+
#ifdef RT_AUDIO
connect(this, &VirtualStudio::baseInputChannelChanged, m_vsAudioInterface.data(),
&VsAudioInterface::setBaseInputChannel);
if (containsCategories) {
QJsonObject header = QJsonObject();
- header.insert(QString::fromStdString("text"), uniqueCategories.at(i));
+ header.insert(QString::fromStdString("text"), category);
header.insert(QString::fromStdString("type"),
QString::fromStdString("header"));
+ header.insert(QString::fromStdString("category"), category);
items.push_back(QVariant(QJsonValue(header)));
}
element.insert(QString::fromStdString("type"),
QString::fromStdString("element"));
element.insert(QString::fromStdString("channels"), channels.at(j));
+ element.insert(QString::fromStdString("category"), category);
items.push_back(QVariant(QJsonValue(element)));
}
}
delete m_servers.at(i);
}
+ delete m_monitor;
delete m_inputMeter;
delete m_outputMeter;
delete m_outputVolumePlugin;
#include "../JackTrip.h"
#include "../Meter.h"
+#include "../Monitor.h"
#include "../Volume.h"
#include "vsAudioInterface.h"
#include "vsConstants.h"
devicesWarningHelpUrlChanged)
Q_PROPERTY(QString devicesErrorHelpUrl READ devicesErrorHelpUrl NOTIFY
devicesErrorHelpUrlChanged)
+ Q_PROPERTY(
+ QString connectedErrorMsg READ connectedErrorMsg NOTIFY connectedErrorMsgChanged)
Q_PROPERTY(
int bufferSize READ bufferSize WRITE setBufferSize NOTIFY bufferSizeChanged)
float inputVolume READ inputVolume WRITE setInputVolume NOTIFY updatedInputVolume)
Q_PROPERTY(float outputVolume READ outputVolume WRITE setOutputVolume NOTIFY
updatedOutputVolume)
+ Q_PROPERTY(float monitorVolume READ monitorVolume WRITE setMonitorVolume NOTIFY
+ updatedMonitorVolume)
Q_PROPERTY(
bool inputMuted READ inputMuted WRITE setInputMuted NOTIFY updatedInputMuted)
Q_PROPERTY(bool audioActivated READ audioActivated WRITE setAudioActivated NOTIFY
Q_PROPERTY(QString windowState READ windowState WRITE setWindowState NOTIFY
windowStateUpdated)
Q_PROPERTY(QString apiHost READ apiHost WRITE setApiHost NOTIFY apiHostChanged)
+ Q_PROPERTY(bool vsFtux READ vsFtux CONSTANT)
public:
explicit VirtualStudio(bool firstRun = false, QObject* parent = nullptr);
QString devicesError();
QString devicesWarningHelpUrl();
QString devicesErrorHelpUrl();
+ QString connectedErrorMsg();
+ void setConnectedErrorMsg(const QString& msg);
int bufferSize();
void setBufferSize(int index);
int bufferStrategy();
QString failedMessage();
float inputVolume();
float outputVolume();
+ float monitorVolume();
bool inputMuted();
bool outputMuted();
+ bool monitorMuted();
Q_INVOKABLE void restartAudio();
bool audioActivated();
bool audioReady();
QString windowState();
QString apiHost();
void setApiHost(QString host);
+ bool vsFtux();
public slots:
void toStandard();
void logout();
void refreshStudios(int index, bool signalRefresh = false);
void refreshDevices();
+ void refreshRtAudioDevices();
void validateDevicesState();
void validateInputDevicesState();
void validateOutputDevicesState();
void applySettings();
void connectToStudio(int studioIndex);
void completeConnection();
+ void triggerReconnect();
void disconnect();
void manageStudio(int studioIndex, bool start = false);
void launchVideo(int studioIndex);
void updatedOutputVuMeasurements(const float* valuesInDecibels, int numChannels);
void setInputVolume(float multiplier);
void setOutputVolume(float multiplier);
+ void setMonitorVolume(float multiplier);
void setInputMuted(bool muted);
void setOutputMuted(bool muted);
+ void setMonitorMuted(bool muted);
void setAudioActivated(bool activated);
void setAudioReady(bool ready);
void setWindowState(QString state);
void numInputChannelsChanged(int numChannels, bool shouldRestart = true);
void inputMixModeChanged(int mode, bool shouldRestart = true);
void outputDeviceChanged(QString device, bool shouldRestart = true);
- void inputDeviceSelected(QString device, bool shouldRestart = true);
- void outputDeviceSelected(QString device, bool shouldRestart = true);
void baseOutputChannelChanged(int baseChannel, bool shouldRestart = true);
void numOutputChannelsChanged(int numChannels, bool shouldRestart = true);
void previousInputChanged();
void devicesErrorChanged();
void devicesWarningHelpUrlChanged();
void devicesErrorHelpUrlChanged();
+ void connectedErrorMsgChanged();
void triggerPlayOutputAudio();
void bufferSizeChanged();
void bufferStrategyChanged();
void studioToJoinChanged();
void updatedInputVolume(float multiplier);
void updatedOutputVolume(float multiplier);
+ void updatedMonitorVolume(float multiplier);
void updatedInputMuted(bool muted);
void updatedOutputMuted(bool muted);
+ void updatedMonitorMuted(bool muted);
void audioActivatedChanged();
void audioReadyChanged();
void windowStateUpdated();
Meter* m_inputTestMeter;
Volume* m_inputVolumePlugin;
Volume* m_outputVolumePlugin;
+ Monitor* m_monitor;
QTimer m_inputClipTimer;
QTimer m_outputClipTimer;
QString m_devicesWarningHelpUrl = QStringLiteral("");
QString m_devicesErrorHelpUrl = QStringLiteral("");
QString m_windowState = QStringLiteral("login");
+ QString m_connectedErrorMsg = QStringLiteral("");
float m_meterMax = 0.0;
float m_meterMin = -64.0;
float m_inMultiplier = 1.0;
float m_outMultiplier = 1.0;
+ float m_monMultiplier = 1.0;
bool m_inMuted = false;
bool m_outMuted = false;
+ bool m_monMuted = false;
QSharedPointer<VsAudioInterface> m_vsAudioInterface;
+#ifdef VS_FTUX
+ bool m_vsFtux = true;
+#else
+ bool m_vsFtux = false;
+#endif
+
#ifdef RT_AUDIO
QStringList m_inputDeviceList;
QStringList m_outputDeviceList;
m_audioInterface->appendProcessPluginFromNetwork(plugin);
}
+void VsAudioInterface::addMonitorPlugin(ProcessPlugin* plugin)
+{
+ m_audioInterface->appendProcessPluginToMonitor(plugin);
+}
+
void VsAudioInterface::setInputDevice(QString deviceName, bool shouldRestart)
{
m_inputDeviceName = deviceName.toStdString();
void startProcess();
void addInputPlugin(ProcessPlugin* plugin);
void addOutputPlugin(ProcessPlugin* plugin);
+ void addMonitorPlugin(ProcessPlugin* plugin);
int getNumInputChannels();
int getNumOutputChannels();
void setupPlugins();
m_playbackVolume =
(float)settings.value(QStringLiteral("OutMultiplier"), 1.0).toDouble();
m_playbackMute = settings.value(QStringLiteral("OutMuted"), false).toBool();
+ m_monitorVolume =
+ (float)settings.value(QStringLiteral("MonMultiplier"), 0).toDouble();
settings.endGroup();
m_sendVolumeTimer = new QTimer(this);
{QLatin1String("captureMute"), m_captureMute},
{QLatin1String("playbackVolume"), (int)(m_playbackVolume * 100.0)},
{QLatin1String("playbackMute"), m_playbackMute},
- };
+ {QLatin1String("monitorVolume"), (int)(m_monitorVolume * 100.0)}};
QJsonDocument request = QJsonDocument(json);
QNetworkReply* reply = m_authenticator->put(
deviceState.object()[QStringLiteral("playbackMute")].toBool();
emit updatedPlaybackVolumeFromServer(m_playbackVolume);
emit updatedPlaybackMuteFromServer(m_playbackMute);
+
+ // monitor volume
+ m_monitorVolume =
+ (float)(deviceState.object()[QStringLiteral("monitorVolume")].toDouble()
+ / 100.0);
+ emit updatedMonitorVolume(m_monitorVolume);
}
QSettings settings;
settings.setValue(QStringLiteral("InMuted"), m_captureMute);
settings.setValue(QStringLiteral("OutMultiplier"), m_playbackVolume);
settings.setValue(QStringLiteral("OutMuted"), m_playbackMute);
+ settings.setValue(QStringLiteral("MonMultiplier"), m_monitorVolume);
settings.endGroup();
reply->deleteLater();
}
}
+bool VsDevice::reconnect()
+{
+ return m_reconnect;
+}
+
+void VsDevice::setReconnect(bool reconnect)
+{
+ m_reconnect = reconnect;
+ if (reconnect) {
+ stopPinger();
+ if (m_webSocket != nullptr && m_webSocket->isValid()) {
+ m_webSocket->closeSocket();
+ }
+ if (!m_jackTrip.isNull()) {
+ m_jackTrip->stop();
+ m_jackTrip.reset();
+ }
+ }
+}
+
+bool VsDevice::hasTerminated()
+{
+ return m_jackTrip.isNull();
+}
+
// setServerId updates the emulated device with the provided serverId
void VsDevice::setServerId(QString serverId)
{
reply->deleteLater();
return;
}
+ m_deviceAgentConfig.insert("serverId", serverId);
reply->deleteLater();
});
}
{QLatin1String("captureMute"), m_captureMute},
{QLatin1String("playbackVolume"), (int)(m_playbackVolume * 100.0)},
{QLatin1String("playbackMute"), m_playbackMute},
- };
+ {QLatin1String("monitorVolume"), (int)(m_monitorVolume * 100.0)}};
QJsonDocument request = QJsonDocument(json);
QNetworkReply* reply = m_authenticator->put(
QStringLiteral("https://%1/api/devices/%2").arg(m_apiHost, m_appID),
m_jackTrip->setRemoteClientName(m_appID);
// increment m_bufferStrategy by 1 for array-index mapping
m_jackTrip->setBufferStrategy(bufferStrategy + 1);
- if (bufferStrategy == 2) {
+ if (bufferStrategy == 2 || bufferStrategy == 3) {
// use -q auto3 for loss concealment
- m_jackTrip->setBufferQueueLength(-3);
+ m_jackTrip->setBufferQueueLength(-5);
} else {
// use -q auto
m_jackTrip->setBufferQueueLength(-500);
void VsDevice::stopJackTrip()
{
if (!m_jackTrip.isNull()) {
+ if (m_webSocket != nullptr && m_webSocket->isValid()) {
+ m_webSocket->closeSocket();
+ }
setServerId("");
m_jackTrip->stop();
+ m_jackTrip.reset();
}
}
}
}
+// updateMonitorVolume sets VsDevice's monitor to the provided float
+void VsDevice::updateMonitorVolume(float multiplier)
+{
+ if (multiplier == m_monitorVolume) {
+ return;
+ }
+
+ m_monitorVolume = multiplier;
+
+ if (m_sendVolumeTimer) {
+ m_sendVolumeTimer->start(200);
+ }
+}
+
// terminateJackTrip is a slot intended to be triggered on jacktrip process signals
void VsDevice::terminateJackTrip()
{
if (!enabled()) {
setServerId("");
}
- m_jackTrip.reset();
+ if (!m_jackTrip.isNull()) {
+ m_jackTrip.reset();
+ }
}
// onTextMessageReceived is a slot intended to be triggered by new incoming WSS messages
emit updatedPlaybackMuteFromServer(m_playbackMute);
}
+ // monitor volume
+ newVolume = (float)(newState["monitorVolume"].toDouble() / 100.0);
+ if (newVolume != m_monitorVolume) {
+ m_monitorVolume = newVolume;
+ emit updatedMonitorVolume(m_monitorVolume);
+ }
+
reconcileAgentConfig(newState);
}
void registerApp();
void removeApp();
void sendHeartbeat();
+ bool reconnect();
+ void setReconnect(bool reconnect);
+ bool hasTerminated();
void setServerId(QString studioID);
JackTrip* initJackTrip(bool useRtAudio, std::string input, std::string output,
int baseInputChannel, int numChannelsIn, int baseOutputChannel,
void updatedCaptureMuteFromServer(bool muted);
void updatedPlaybackVolumeFromServer(float multiplier);
void updatedPlaybackMuteFromServer(bool muted);
+ void updatedMonitorVolume(float multiplier);
public slots:
void updateCaptureVolume(float multiplier);
void updateCaptureMute(bool muted);
void updatePlaybackVolume(float multiplier);
void updatePlaybackMute(bool muted);
+ void updateMonitorVolume(float multiplier);
private slots:
void terminateJackTrip();
bool m_captureMute = false;
float m_playbackVolume = 1.0;
bool m_playbackMute = false;
+ float m_monitorVolume = 0;
QTimer* m_sendVolumeTimer;
+ bool m_reconnect = false;
};
#endif // VSDEVICE_H
--- /dev/null
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+
+Rectangle {
+ property string backgroundColour: virtualstudio.darkMode ? "#272525" : "#FAFBFB"
+ property string textColour: virtualstudio.darkMode ? "#FAFBFB" : "#0F0D0D"
+
+ width: 696
+ height: 577
+ color: backgroundColour
+ state: virtualstudio.windowState
+ anchors.fill: parent
+
+ id: window
+ states: [
+ State {
+ name: "login"
+ PropertyChanges { target: loginScreen; x: 0; failTextVisible: false }
+ PropertyChanges { target: setupScreen; x: window.width }
+ PropertyChanges { target: browseScreen; x: window.width }
+ PropertyChanges { target: settingsScreen; x: window.width }
+ PropertyChanges { target: connectedScreen; x: window.width }
+ PropertyChanges { target: failedScreen; x: window.width }
+ },
+
+ State {
+ name: "setup"
+ PropertyChanges { target: loginScreen; x: -loginScreen.width }
+ PropertyChanges { target: setupScreen; x: 0 }
+ PropertyChanges { target: browseScreen; x: window.width }
+ PropertyChanges { target: settingsScreen; x: window.width }
+ PropertyChanges { target: connectedScreen; x: window.width }
+ PropertyChanges { target: failedScreen; x: window.width }
+ },
+
+ State {
+ name: "browse"
+ PropertyChanges { target: loginScreen; x: -loginScreen.width }
+ PropertyChanges { target: setupScreen; x: -setupScreen.width }
+ PropertyChanges { target: browseScreen; x: 0 }
+ PropertyChanges { target: settingsScreen; x: window.width }
+ PropertyChanges { target: connectedScreen; x: window.width }
+ PropertyChanges { target: failedScreen; x: window.width }
+ },
+
+ State {
+ name: "settings"
+ PropertyChanges { target: loginScreen; x: -loginScreen.width }
+ PropertyChanges { target: setupScreen; x: -setupScreen.width }
+ PropertyChanges { target: browseScreen; x: -browseScreen.width }
+ PropertyChanges { target: settingsScreen; x: 0 }
+ PropertyChanges { target: connectedScreen; x: window.width }
+ PropertyChanges { target: failedScreen; x: window.width }
+ },
+
+ State {
+ name: "connected"
+ PropertyChanges { target: loginScreen; x: -loginScreen.width }
+ PropertyChanges { target: setupScreen; x: -setupScreen.width }
+ PropertyChanges { target: browseScreen; x: -browseScreen.width }
+ PropertyChanges { target: settingsScreen; x: window.width }
+ PropertyChanges { target: connectedScreen; x: 0 }
+ PropertyChanges { target: failedScreen; x: window.width }
+ },
+
+ State {
+ name: "failed"
+ PropertyChanges { target: loginScreen; x: -loginScreen.width }
+ PropertyChanges { target: setupScreen; x: -setupScreen.width }
+ PropertyChanges { target: browseScreen; x: -browseScreen.width }
+ PropertyChanges { target: settingsScreen; x: window.width }
+ PropertyChanges { target: connectedScreen; x: window.width }
+ PropertyChanges { target: failedScreen; x: 0 }
+ }
+ ]
+
+ transitions: Transition {
+ NumberAnimation { properties: "x"; duration: 800; easing.type: Easing.InOutQuad }
+ }
+
+ Setup {
+ id: setupScreen
+ }
+
+ Browse {
+ id: browseScreen
+ }
+
+ Login {
+ id: loginScreen
+ showBackButton: false
+ }
+
+ Settings {
+ id: settingsScreen
+ }
+
+ Connected {
+ id: connectedScreen
+ }
+
+ Failed {
+ id: failedScreen
+ }
+
+ Connections {
+ target: virtualstudio
+ function onAuthSucceeded() {
+ if (virtualstudio.showDeviceSetup) {
+ virtualstudio.windowState = "setup";
+ } else {
+ virtualstudio.windowState = "browse";
+ }
+ }
+ function onAuthFailed() {
+ loginScreen.failTextVisible = true;
+ }
+ function onConnected() {
+ virtualstudio.windowState = "connected";
+ }
+ function onFailed() {
+ virtualstudio.windowState = "failed";
+ }
+ function onDisconnected() {
+ virtualstudio.windowState = "browse";
+ }
+ }
+}
#include "AudioInterface.h"
-constexpr const char* const gVersion = "1.8.1"; ///< JackTrip version
+constexpr const char* const gVersion = "1.9.0"; ///< JackTrip version
//*******************************************************************************
/// \name Default Values
/// \name Global Functions
#ifdef __APPLE__
-void setRealtimeProcessPriority(int bufferSize, int sampleRate);
+void setRealtimeProcessPriority(int bufferSize = gDefaultBufferSizeInSamples,
+ int sampleRate = gDefaultSampleRate);
#else
void setRealtimeProcessPriority();
#endif
--- /dev/null
+/* ------------------------------------------------------------
+author: "Dominick Hing, adapted from 'Volume Control' by Matt Horton"
+license: "MIT Style STK-4.2"
+name: "monitor"
+version: "1.0"
+Code generated with Faust 2.54.9 (https://faust.grame.fr)
+Compilation options: -a faust2header.cpp -lang cpp -i -inpl -cn monitordsp -es 1 -mcd 16 -single -ftz 0
+------------------------------------------------------------ */
+
+#ifndef __monitordsp_H__
+#define __monitordsp_H__
+
+// NOTE: ANY INCLUDE-GUARD HERE MUST BE DERIVED FROM THE CLASS NAME
+//
+// faust2header.cpp - FAUST Architecture File
+// This is a simple variation of matlabplot.cpp in the Faust distribution
+// aimed at creating a simple C++ header file (.h) containing a Faust DSP.
+// See the Makefile for how to use it.
+
+/************************** BEGIN dsp.h ********************************
+ FAUST Architecture File
+ Copyright (C) 2003-2022 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ 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
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __dsp__
+#define __dsp__
+
+#include <string>
+#include <vector>
+
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2022 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ 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
+ architecture section is not modified.
+ ***************************************************************************/
+
+#ifndef __export__
+#define __export__
+
+#define FAUSTVERSION "2.54.9"
+
+// Use FAUST_API for code that is part of the external API but is also compiled in faust and libfaust
+// Use LIBFAUST_API for code that is compiled in faust and libfaust
+
+#ifdef _WIN32
+ #pragma warning (disable: 4251)
+ #ifdef FAUST_EXE
+ #define FAUST_API
+ #define LIBFAUST_API
+ #elif FAUST_LIB
+ #define FAUST_API __declspec(dllexport)
+ #define LIBFAUST_API __declspec(dllexport)
+ #else
+ #define FAUST_API
+ #define LIBFAUST_API
+ #endif
+#else
+ #ifdef FAUST_EXE
+ #define FAUST_API
+ #define LIBFAUST_API
+ #else
+ #define FAUST_API __attribute__((visibility("default")))
+ #define LIBFAUST_API __attribute__((visibility("default")))
+ #endif
+#endif
+
+#endif
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+struct FAUST_API UI;
+struct FAUST_API Meta;
+
+/**
+ * DSP memory manager.
+ */
+
+struct FAUST_API dsp_memory_manager {
+
+ virtual ~dsp_memory_manager() {}
+
+ /**
+ * Inform the Memory Manager with the number of expected memory zones.
+ * @param count - the number of expected memory zones
+ */
+ virtual void begin(size_t /*count*/) {}
+
+ /**
+ * Give the Memory Manager information on a given memory zone.
+ * @param size - the size in bytes of the memory zone
+ * @param reads - the number of Read access to the zone used to compute one frame
+ * @param writes - the number of Write access to the zone used to compute one frame
+ */
+ virtual void info(size_t /*size*/, size_t /*reads*/, size_t /*writes*/) {}
+
+ /**
+ * Inform the Memory Manager that all memory zones have been described,
+ * to possibly start a 'compute the best allocation strategy' step.
+ */
+ virtual void end() {}
+
+ /**
+ * Allocate a memory zone.
+ * @param size - the memory zone size in bytes
+ */
+ virtual void* allocate(size_t size) = 0;
+
+ /**
+ * Destroy a memory zone.
+ * @param ptr - the memory zone pointer to be deallocated
+ */
+ virtual void destroy(void* ptr) = 0;
+
+};
+
+/**
+* Signal processor definition.
+*/
+
+class FAUST_API 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;
+
+ /* Return 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 Hz
+ */
+ virtual void init(int sample_rate) = 0;
+
+ /**
+ * Init instance state
+ *
+ * @param sample_rate - the sampling rate in Hz
+ */
+ virtual void instanceInit(int sample_rate) = 0;
+
+ /**
+ * Init instance constant state
+ *
+ * @param sample_rate - the sampling rate in Hz
+ */
+ virtual void instanceConstants(int sample_rate) = 0;
+
+ /* Init default control parameters values */
+ virtual void instanceResetUserInterface() = 0;
+
+ /* Init instance state (like delay lines...) but keep the control parameter values */
+ 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 FAUST_API 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, used with LLVM and Interpreter backends
+ * to create DSP instances from a compiled DSP program.
+ */
+
+class FAUST_API 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 std::vector<std::string> getWarningMessages() = 0;
+
+ virtual dsp* createDSPInstance() = 0;
+
+ virtual void setMemoryManager(dsp_memory_manager* manager) = 0;
+ virtual dsp_memory_manager* getMemoryManager() = 0;
+
+};
+
+// Denormal handling
+
+#if defined (__SSE__)
+#include <xmmintrin.h>
+#endif
+
+class FAUST_API ScopedNoDenormals {
+
+ private:
+
+ intptr_t fpsr = 0;
+
+ void setFpStatusRegister(intptr_t fpsr_aux) noexcept
+ {
+ #if defined (__arm64__) || defined (__aarch64__)
+ asm volatile("msr fpcr, %0" : : "ri" (fpsr_aux));
+ #elif defined (__SSE__)
+ // The volatile keyword here is needed to workaround a bug in AppleClang 13.0
+ // which aggressively optimises away the variable otherwise
+ volatile uint32_t fpsr_w = static_cast<uint32_t>(fpsr_aux);
+ _mm_setcsr(fpsr_w);
+ #endif
+ }
+
+ void getFpStatusRegister() noexcept
+ {
+ #if defined (__arm64__) || defined (__aarch64__)
+ asm volatile("mrs %0, fpcr" : "=r" (fpsr));
+ #elif defined (__SSE__)
+ fpsr = static_cast<intptr_t>(_mm_getcsr());
+ #endif
+ }
+
+ public:
+
+ ScopedNoDenormals() noexcept
+ {
+ #if defined (__arm64__) || defined (__aarch64__)
+ intptr_t mask = (1 << 24 /* FZ */);
+ #elif defined (__SSE__)
+ #if defined (__SSE2__)
+ intptr_t mask = 0x8040;
+ #else
+ intptr_t mask = 0x8000;
+ #endif
+ #else
+ intptr_t mask = 0x0000;
+ #endif
+ getFpStatusRegister();
+ setFpStatusRegister(fpsr | mask);
+ }
+
+ ~ScopedNoDenormals() noexcept
+ {
+ setFpStatusRegister(fpsr);
+ }
+
+};
+
+#define AVOIDDENORMALS ScopedNoDenormals ftz_scope;
+
+#endif
+
+/************************** END dsp.h **************************/
+/************************** BEGIN APIUI.h *****************************
+FAUST Architecture File
+Copyright (C) 2003-2022 GRAME, Centre National de Creation Musicale
+---------------------------------------------------------------------
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+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
+architecture section is not modified.
+************************************************************************/
+
+#ifndef API_UI_H
+#define API_UI_H
+
+#include <sstream>
+#include <string>
+#include <vector>
+#include <stdio.h>
+#include <map>
+
+/************************** BEGIN meta.h *******************************
+ FAUST Architecture File
+ Copyright (C) 2003-2022 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ 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
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __meta__
+#define __meta__
+
+
+/**
+ The base class of Meta handler to be used in dsp::metadata(Meta* m) method to retrieve (key, value) metadata.
+ */
+struct FAUST_API Meta {
+ virtual ~Meta() {}
+ virtual void declare(const char* key, const char* value) = 0;
+};
+
+#endif
+/************************** END meta.h **************************/
+/************************** BEGIN UI.h *****************************
+ FAUST Architecture File
+ Copyright (C) 2003-2022 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ 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
+ architecture section is not modified.
+ ********************************************************************/
+
+#ifndef __UI_H__
+#define __UI_H__
+
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+/*******************************************************************************
+ * UI : Faust DSP User Interface
+ * User Interface as expected by the buildUserInterface() method of a DSP.
+ * This abstract class contains only the method that the Faust compiler can
+ * generate to describe a DSP user interface.
+ ******************************************************************************/
+
+struct Soundfile;
+
+template <typename REAL>
+struct FAUST_API UIReal {
+
+ UIReal() {}
+ virtual ~UIReal() {}
+
+ // -- widget's layouts
+
+ 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;
+
+ // -- active widgets
+
+ 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;
+
+ // -- 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;
+
+ // -- soundfiles
+
+ 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*/) {}
+
+ // To be used by LLVM client
+ virtual int sizeOfFAUSTFLOAT() { return sizeof(FAUSTFLOAT); }
+};
+
+struct FAUST_API UI : public UIReal<FAUSTFLOAT> {
+ UI() {}
+ virtual ~UI() {}
+};
+
+#endif
+/************************** END UI.h **************************/
+/************************** BEGIN PathBuilder.h **************************
+ FAUST Architecture File
+ Copyright (C) 2003-2022 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ 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
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __PathBuilder__
+#define __PathBuilder__
+
+#include <vector>
+#include <set>
+#include <map>
+#include <string>
+#include <algorithm>
+#include <regex>
+
+
+/*******************************************************************************
+ * PathBuilder : Faust User Interface
+ * Helper class to build complete hierarchical path for UI items.
+ ******************************************************************************/
+
+class FAUST_API PathBuilder {
+
+ protected:
+
+ std::vector<std::string> fControlsLevel;
+ std::vector<std::string> fFullPaths;
+ std::map<std::string, std::string> fFull2Short; // filled by computeShortNames()
+
+ /**
+ * @brief check if a character is acceptable for an ID
+ *
+ * @param c
+ * @return true is the character is acceptable for an ID
+ */
+ bool isIDChar(char c) const
+ {
+ return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || ((c >= '0') && (c <= '9'));
+ }
+
+ /**
+ * @brief remove all "/0x00" parts
+ *
+ * @param src
+ * @return modified string
+ */
+ std::string remove0x00(const std::string& src) const
+ {
+ return std::regex_replace(src, std::regex("/0x00"), "");
+ }
+
+ /**
+ * @brief replace all non ID char with '_' (one '_' may replace several non ID char)
+ *
+ * @param src
+ * @return modified string
+ */
+ std::string str2ID(const std::string& src) const
+ {
+ std::string dst;
+ bool need_underscore = false;
+ for (char c : src) {
+ if (isIDChar(c) || (c == '/')) {
+ if (need_underscore) {
+ dst.push_back('_');
+ need_underscore = false;
+ }
+ dst.push_back(c);
+ } else {
+ need_underscore = true;
+ }
+ }
+ return dst;
+ }
+
+ /**
+ * @brief Keep only the last n slash-parts
+ *
+ * @param src
+ * @param n : 1 indicates the last slash-part
+ * @return modified string
+ */
+ std::string cut(const std::string& src, int n) const
+ {
+ std::string rdst;
+ for (int i = int(src.length())-1; i >= 0; i--) {
+ char c = src[i];
+ if (c != '/') {
+ rdst.push_back(c);
+ } else if (n == 1) {
+ std::string dst;
+ for (int j = int(rdst.length())-1; j >= 0; j--) {
+ dst.push_back(rdst[j]);
+ }
+ return dst;
+ } else {
+ n--;
+ rdst.push_back(c);
+ }
+ }
+ return src;
+ }
+
+ void addFullPath(const std::string& label) { fFullPaths.push_back(buildPath(label)); }
+
+ /**
+ * @brief Compute the mapping between full path and short names
+ */
+ void computeShortNames()
+ {
+ std::vector<std::string> uniquePaths; // all full paths transformed but made unique with a prefix
+ std::map<std::string, std::string> unique2full; // all full paths transformed but made unique with a prefix
+ char num_buffer[16];
+ int pnum = 0;
+
+ for (const auto& s : fFullPaths) {
+ sprintf(num_buffer, "%d", pnum++);
+ std::string u = "/P" + std::string(num_buffer) + str2ID(remove0x00(s));
+ uniquePaths.push_back(u);
+ unique2full[u] = s; // remember the full path associated to a unique path
+ }
+
+ std::map<std::string, int> uniquePath2level; // map path to level
+ for (const auto& s : uniquePaths) uniquePath2level[s] = 1; // we init all levels to 1
+ bool have_collisions = true;
+
+ while (have_collisions) {
+ // compute collision list
+ std::set<std::string> collisionSet;
+ std::map<std::string, std::string> short2full;
+ have_collisions = false;
+ for (const auto& it : uniquePath2level) {
+ std::string u = it.first;
+ int n = it.second;
+ std::string shortName = cut(u, n);
+ auto p = short2full.find(shortName);
+ if (p == short2full.end()) {
+ // no collision
+ short2full[shortName] = u;
+ } else {
+ // we have a collision, add the two paths to the collision set
+ have_collisions = true;
+ collisionSet.insert(u);
+ collisionSet.insert(p->second);
+ }
+ }
+ for (const auto& s : collisionSet) uniquePath2level[s]++; // increase level of colliding path
+ }
+
+ for (const auto& it : uniquePath2level) {
+ std::string u = it.first;
+ int n = it.second;
+ std::string shortName = replaceCharList(cut(u, n), {'/'}, '_');
+ fFull2Short[unique2full[u]] = shortName;
+ }
+ }
+
+ std::string replaceCharList(const std::string& str, const std::vector<char>& ch1, char ch2)
+ {
+ auto beg = ch1.begin();
+ auto end = ch1.end();
+ std::string res = str;
+ for (size_t i = 0; i < str.length(); ++i) {
+ if (std::find(beg, end, str[i]) != end) res[i] = ch2;
+ }
+ return res;
+ }
+
+ public:
+
+ PathBuilder() {}
+ virtual ~PathBuilder() {}
+
+ // Return true for the first level of groups
+ bool pushLabel(const std::string& label) { fControlsLevel.push_back(label); return fControlsLevel.size() == 1;}
+
+ // Return true for the last level of groups
+ bool popLabel() { fControlsLevel.pop_back(); return fControlsLevel.size() == 0; }
+
+ std::string buildPath(const std::string& label)
+ {
+ std::string res = "/";
+ for (size_t i = 0; i < fControlsLevel.size(); i++) {
+ res = res + fControlsLevel[i] + "/";
+ }
+ res += label;
+ return replaceCharList(res, {' ', '#', '*', ',', '?', '[', ']', '{', '}', '(', ')'}, '_');
+ }
+
+};
+
+#endif // __PathBuilder__
+/************************** END PathBuilder.h **************************/
+/************************** BEGIN ValueConverter.h ********************
+ FAUST Architecture File
+ Copyright (C) 2003-2022 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ 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
+ architecture section is not modified.
+ ********************************************************************/
+
+#ifndef __ValueConverter__
+#define __ValueConverter__
+
+/***************************************************************************************
+ ValueConverter.h
+ (GRAME, Copyright 2015-2019)
+
+ Set of conversion objects used to map user interface values (for example a gui slider
+ delivering values between 0 and 1) to faust values (for example a vslider between
+ 20 and 20000) using a log scale.
+
+ -- 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
+
+ -- Value Converters
+
+ ValueConverter::ui2faust(x)
+ ValueConverter::faust2ui(x)
+
+ -- ValueConverters used for sliders depending of the scale
+
+ LinearValueConverter(umin, umax, fmin, fmax)
+ LinearValueConverter2(lo, mi, hi, v1, vm, v2) using 2 segments
+ LogValueConverter(umin, umax, fmin, fmax)
+ ExpValueConverter(umin, umax, fmin, fmax)
+
+ -- ValueConverters used for accelerometers based on 3 points
+
+ AccUpConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 0
+ AccDownConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 1
+ AccUpDownConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 2
+ AccDownUpConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 3
+
+ -- lists of ZoneControl are used to implement accelerometers metadata for each axes
+
+ ZoneControl(zone, valueConverter) : a zone with an accelerometer data converter
+
+ -- ZoneReader are used to implement screencolor metadata
+
+ ZoneReader(zone, valueConverter) : a zone with a data converter
+
+****************************************************************************************/
+
+#include <float.h>
+#include <algorithm> // std::max
+#include <cmath>
+#include <vector>
+#include <assert.h>
+
+
+//--------------------------------------------------------------------------------------
+// Interpolator(lo,hi,v1,v2)
+// Maps a value x between lo and hi to a value y between v1 and v2
+// y = v1 + (x-lo)/(hi-lo)*(v2-v1)
+// y = v1 + (x-lo) * coef with coef = (v2-v1)/(hi-lo)
+// y = v1 + x*coef - lo*coef
+// y = v1 - lo*coef + x*coef
+// y = offset + x*coef with offset = v1 - lo*coef
+//--------------------------------------------------------------------------------------
+class FAUST_API 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)
+ {
+ double x = fRange(v);
+ return fOffset + x*fCoef;
+ }
+
+ void getLowHigh(double& amin, double& amax)
+ {
+ amin = fRange.fLo;
+ amax = fRange.fHi;
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Interpolator3pt(lo,mi,hi,v1,vm,v2)
+// Map values between lo mid hi to values between v1 vm v2
+//--------------------------------------------------------------------------------------
+class FAUST_API 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);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Abstract ValueConverter class. Converts values between UI and Faust representations
+//--------------------------------------------------------------------------------------
+class FAUST_API ValueConverter {
+
+ public:
+
+ virtual ~ValueConverter() {}
+ virtual double ui2faust(double x) { return x; };
+ virtual double faust2ui(double x) { return x; };
+};
+
+//--------------------------------------------------------------------------------------
+// A converter than can be updated
+//--------------------------------------------------------------------------------------
+
+class FAUST_API 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 FAUST_API 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); }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Two segments linear conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class FAUST_API 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);
+ }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Logarithmic conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class FAUST_API 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))); }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Exponential conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class FAUST_API 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))); }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using an Up curve (curve 0)
+//--------------------------------------------------------------------------------------
+class FAUST_API 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);
+ }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using a Down curve (curve 1)
+//--------------------------------------------------------------------------------------
+class FAUST_API 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);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using an Up-Down curve (curve 2)
+//--------------------------------------------------------------------------------------
+class FAUST_API 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);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using a Down-Up curve (curve 3)
+//--------------------------------------------------------------------------------------
+class FAUST_API 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);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Base class for ZoneControl
+//--------------------------------------------------------------------------------------
+class FAUST_API ZoneControl {
+
+ protected:
+
+ FAUSTFLOAT* fZone;
+
+ public:
+
+ ZoneControl(FAUSTFLOAT* zone) : fZone(zone) {}
+ virtual ~ZoneControl() {}
+
+ 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; }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Useful to implement accelerometers metadata as a list of ZoneControl for each axes
+//--------------------------------------------------------------------------------------
+class FAUST_API 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 = FAUSTFLOAT(fValueConverter->ui2faust(v)); }
+
+ ValueConverter* getConverter() { return fValueConverter; }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Association of a zone and a four value converter, each one for each possible curve.
+// Useful to implement accelerometers metadata as a list of ZoneControl for each axes
+//--------------------------------------------------------------------------------------
+class FAUST_API 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()
+ {
+ for (const auto& it : fValueConverters) { delete it; }
+ }
+ void update(double v) const { if (fValueConverters[fCurve]->getActive()) *fZone = FAUSTFLOAT(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)
+ {
+ for (const auto& it : fValueConverters) { it->setActive(on_off); }
+ }
+
+ int getCurve() { return fCurve; }
+};
+
+class FAUST_API ZoneReader {
+
+ private:
+
+ 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;
+ }
+
+};
+
+#endif
+/************************** END ValueConverter.h **************************/
+
+typedef unsigned int uint;
+
+class APIUI : public PathBuilder, public Meta, public UI
+{
+ public:
+ enum ItemType { kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph };
+ enum Type { kAcc = 0, kGyr = 1, kNoType };
+
+ protected:
+
+ enum Mapping { kLin = 0, kLog = 1, kExp = 2 };
+
+ struct Item {
+ std::string fLabel;
+ std::string fShortname;
+ std::string fPath;
+ ValueConverter* fConversion;
+ FAUSTFLOAT* fZone;
+ FAUSTFLOAT fInit;
+ FAUSTFLOAT fMin;
+ FAUSTFLOAT fMax;
+ FAUSTFLOAT fStep;
+ ItemType fItemType;
+
+ Item(const std::string& label,
+ const std::string& short_name,
+ const std::string& path,
+ ValueConverter* conversion,
+ FAUSTFLOAT* zone,
+ FAUSTFLOAT init,
+ FAUSTFLOAT min,
+ FAUSTFLOAT max,
+ FAUSTFLOAT step,
+ ItemType item_type)
+ :fLabel(label), fShortname(short_name), fPath(path), fConversion(conversion),
+ fZone(zone), fInit(init), fMin(min), fMax(max), fStep(step), fItemType(item_type)
+ {}
+ };
+ std::vector<Item> fItems;
+
+ 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);
+ fFullPaths.push_back(path);
+
+ // handle scale metadata
+ ValueConverter* converter = nullptr;
+ switch (fCurrentScale) {
+ case kLin:
+ converter = new LinearValueConverter(0, 1, min, max);
+ break;
+ case kLog:
+ converter = new LogValueConverter(0, 1, min, max);
+ break;
+ case kExp:
+ converter = new ExpValueConverter(0, 1, min, max);
+ break;
+ }
+ fCurrentScale = kLin;
+
+ fItems.push_back(Item(label, "", path, converter, zone, init, min, max, step, type));
+
+ if (fCurrentAcc.size() > 0 && fCurrentGyr.size() > 0) {
+ fprintf(stderr, "warning : 'acc' and 'gyr' metadata used for the same %s parameter !!\n", label);
+ }
+
+ // 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 {
+ fprintf(stderr, "incorrect acc metadata : %s \n", fCurrentAcc.c_str());
+ }
+ 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 {
+ fprintf(stderr, "incorrect gyr metadata : %s \n", fCurrentGyr.c_str());
+ }
+ fCurrentGyr = "";
+ }
+
+ // handle screencolor metadata "...[screencolor:red|green|blue|white]..."
+ if (fCurrentColor.size() > 0) {
+ if ((fCurrentColor == "red") && (fRedReader == nullptr)) {
+ fRedReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else if ((fCurrentColor == "green") && (fGreenReader == nullptr)) {
+ fGreenReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else if ((fCurrentColor == "blue") && (fBlueReader == nullptr)) {
+ fBlueReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else if ((fCurrentColor == "white") && (fRedReader == nullptr) && (fGreenReader == nullptr) && (fBlueReader == nullptr)) {
+ fRedReader = new ZoneReader(zone, min, max);
+ fGreenReader = new ZoneReader(zone, min, max);
+ fBlueReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else {
+ fprintf(stderr, "incorrect screencolor metadata : %s \n", fCurrentColor.c_str());
+ }
+ }
+ fCurrentColor = "";
+
+ fMetaData.push_back(fCurrentMetadata);
+ fCurrentMetadata.clear();
+ }
+
+ int getZoneIndex(std::vector<ZoneControl*>* table, int p, int val)
+ {
+ FAUSTFLOAT* zone = fItems[uint(p)].fZone;
+ 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][uint(id1)]->setActive(false);
+ if (id2 != -1) table[1][uint(id2)]->setActive(false);
+ if (id3 != -1) table[2][uint(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][uint(id4)]->setMappingValues(curve, amin, amid, amax, fItems[uint(p)].fMin, fItems[uint(p)].fInit, fItems[uint(p)].fMax);
+ table[val][uint(id4)]->setActive(true);
+ } else {
+ // Allocate a new CurveZoneControl which is 'active' by default
+ FAUSTFLOAT* zone = fItems[uint(p)].fZone;
+ table[val].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, fItems[uint(p)].fMin, fItems[uint(p)].fInit, fItems[uint(p)].fMax));
+ }
+ }
+ }
+
+ 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][uint(id1)]->getCurve();
+ table[val][uint(id1)]->getMappingValues(amin, amid, amax);
+ } else if (id2 != -1) {
+ val = 1;
+ curve = table[val][uint(id2)]->getCurve();
+ table[val][uint(id2)]->getMappingValues(amin, amid, amax);
+ } else if (id3 != -1) {
+ val = 2;
+ curve = table[val][uint(id3)]->getCurve();
+ table[val][uint(id3)]->getMappingValues(amin, amid, amax);
+ } else {
+ val = -1; // No mapping
+ curve = 0;
+ amin = -100.;
+ amid = 0.;
+ amax = 100.;
+ }
+ }
+
+ public:
+
+ APIUI() : fHasScreenControl(false), fRedReader(nullptr), fGreenReader(nullptr), fBlueReader(nullptr), fCurrentScale(kLin)
+ {}
+
+ virtual ~APIUI()
+ {
+ for (const auto& it : fItems) delete it.fConversion;
+ for (int i = 0; i < 3; i++) {
+ for (const auto& it : fAcc[i]) delete it;
+ for (const auto& it : fGyr[i]) delete it;
+ }
+ 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()
+ {
+ if (popLabel()) {
+ // Shortnames can be computed when all fullnames are known
+ computeShortNames();
+ // Fill 'shortname' field for each item
+ for (const auto& it : fFull2Short) {
+ int index = getParamIndex(it.first.c_str());
+ fItems[index].fShortname = it.second;
+ }
+ }
+ }
+
+ // -- active 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);
+ }
+
+ // -- passive widgets
+
+ virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
+ {
+ addParameter(label, zone, min, min, max, (max-min)/1000.0f, kHBargraph);
+ }
+
+ virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
+ {
+ addParameter(label, zone, min, min, max, (max-min)/1000.0f, kVBargraph);
+ }
+
+ // -- soundfiles
+
+ virtual void addSoundfile(const char* /*label*/, const char* /*filename*/, Soundfile** /*sf_zone*/) {}
+
+ // -- metadata declarations
+
+ 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;
+ }
+ }
+
+ virtual void declare(const char* /*key*/, const char* /*val*/)
+ {}
+
+ //-------------------------------------------------------------------------------
+ // Simple API part
+ //-------------------------------------------------------------------------------
+
+ /**
+ * Return the number of parameters in the UI.
+ *
+ * @return the number of parameters
+ */
+ int getParamsCount() { return int(fItems.size()); }
+
+ /**
+ * Return the param index.
+ *
+ * @param str - the UI parameter label/shortname/path
+ *
+ * @return the param index
+ */
+ int getParamIndex(const char* str)
+ {
+ std::string path = std::string(str);
+ auto it = find_if(fItems.begin(), fItems.end(),
+ [=](const Item& it) { return (it.fLabel == path) || (it.fShortname == path) || (it.fPath == path); });
+ return (it != fItems.end()) ? int(it - fItems.begin()) : -1;
+ }
+
+ /**
+ * Return the param label.
+ *
+ * @param p - the UI parameter index
+ *
+ * @return the param label
+ */
+ const char* getParamLabel(int p) { return fItems[uint(p)].fLabel.c_str(); }
+
+ /**
+ * Return the param shortname.
+ *
+ * @param p - the UI parameter index
+ *
+ * @return the param shortname
+ */
+ const char* getParamShortname(int p) { return fItems[uint(p)].fShortname.c_str(); }
+
+ /**
+ * Return the param path.
+ *
+ * @param p - the UI parameter index
+ *
+ * @return the param path
+ */
+ const char* getParamAddress(int p) { return fItems[uint(p)].fPath.c_str(); }
+
+ /**
+ * Return the param metadata.
+ *
+ * @param p - the UI parameter index
+ *
+ * @return the param metadata as a map<key, value>
+ */
+ std::map<const char*, const char*> getMetadata(int p)
+ {
+ std::map<const char*, const char*> res;
+ std::map<std::string, std::string> metadata = fMetaData[uint(p)];
+ for (const auto& it : metadata) {
+ res[it.first.c_str()] = it.second.c_str();
+ }
+ return res;
+ }
+
+ /**
+ * Return the param metadata value.
+ *
+ * @param p - the UI parameter index
+ * @param key - the UI parameter index
+ *
+ * @return the param metadata value associate to the key
+ */
+ const char* getMetadata(int p, const char* key)
+ {
+ return (fMetaData[uint(p)].find(key) != fMetaData[uint(p)].end()) ? fMetaData[uint(p)][key].c_str() : "";
+ }
+
+ /**
+ * Return the param minimum value.
+ *
+ * @param p - the UI parameter index
+ *
+ * @return the param minimum value
+ */
+ FAUSTFLOAT getParamMin(int p) { return fItems[uint(p)].fMin; }
+
+ /**
+ * Return the param maximum value.
+ *
+ * @param p - the UI parameter index
+ *
+ * @return the param maximum value
+ */
+ FAUSTFLOAT getParamMax(int p) { return fItems[uint(p)].fMax; }
+
+ /**
+ * Return the param step value.
+ *
+ * @param p - the UI parameter index
+ *
+ * @return the param step value
+ */
+ FAUSTFLOAT getParamStep(int p) { return fItems[uint(p)].fStep; }
+
+ /**
+ * Return the param init value.
+ *
+ * @param p - the UI parameter index
+ *
+ * @return the param init value
+ */
+ FAUSTFLOAT getParamInit(int p) { return fItems[uint(p)].fInit; }
+
+ /**
+ * Return the param memory zone.
+ *
+ * @param p - the UI parameter index
+ *
+ * @return the param memory zone.
+ */
+ FAUSTFLOAT* getParamZone(int p) { return fItems[uint(p)].fZone; }
+
+ /**
+ * Return the param value.
+ *
+ * @param p - the UI parameter index
+ *
+ * @return the param value.
+ */
+ FAUSTFLOAT getParamValue(int p) { return *fItems[uint(p)].fZone; }
+
+ /**
+ * Return the param value.
+ *
+ * @param str - the UI parameter label/shortname/path
+ *
+ * @return the param value.
+ */
+ FAUSTFLOAT getParamValue(const char* str)
+ {
+ int index = getParamIndex(str);
+ if (index >= 0) {
+ return getParamValue(index);
+ } else {
+ fprintf(stderr, "getParamValue : '%s' not found\n", (str == nullptr ? "NULL" : str));
+ return FAUSTFLOAT(0);
+ }
+ }
+
+ /**
+ * Set the param value.
+ *
+ * @param p - the UI parameter index
+ * @param v - the UI parameter value
+ *
+ */
+ void setParamValue(int p, FAUSTFLOAT v) { *fItems[uint(p)].fZone = v; }
+
+ /**
+ * Set the param value.
+ *
+ * @param p - the UI parameter label/shortname/path
+ * @param v - the UI parameter value
+ *
+ */
+ void setParamValue(const char* path, FAUSTFLOAT v)
+ {
+ int index = getParamIndex(path);
+ if (index >= 0) {
+ setParamValue(index, v);
+ } else {
+ fprintf(stderr, "setParamValue : '%s' not found\n", (path == nullptr ? "NULL" : path));
+ }
+ }
+
+ double getParamRatio(int p) { return fItems[uint(p)].fConversion->faust2ui(*fItems[uint(p)].fZone); }
+ void setParamRatio(int p, double r) { *fItems[uint(p)].fZone = FAUSTFLOAT(fItems[uint(p)].fConversion->ui2faust(r)); }
+
+ double value2ratio(int p, double r) { return fItems[uint(p)].fConversion->faust2ui(r); }
+ double ratio2value(int p, double r) { return fItems[uint(p)].fConversion->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 fItems[uint(p)].fItemType;
+ }
+
+ /**
+ * 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 (0: up, 1: down, 2: up and down, 2: down and up)
+ * @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 gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope (-1 means "no mapping")
+ * @param curve - between 0 and 3 (0: up, 1: down, 2: up and down, 2: down and up)
+ * @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 (between 0 and 3)
+ * @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 (between 0 and 3)
+ * @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;
+ }
+
+ /**
+ * Get the requested screen color.
+ *
+ * -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
+/************************** END APIUI.h **************************/
+
+// NOTE: "faust -scn name" changes the last line above to
+// #include <faust/name/name.h>
+
+//----------------------------------------------------------------------------
+// FAUST Generated Code
+//----------------------------------------------------------------------------
+
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+#include <algorithm>
+#include <cmath>
+#include <cstdint>
+#include <math.h>
+
+#ifndef FAUSTCLASS
+#define FAUSTCLASS monitordsp
+#endif
+
+#ifdef __APPLE__
+#define exp10f __exp10f
+#define exp10 __exp10
+#endif
+
+#if defined(_WIN32)
+#define RESTRICT __restrict
+#else
+#define RESTRICT __restrict__
+#endif
+
+
+class monitordsp : public dsp {
+
+ private:
+
+ FAUSTFLOAT fHslider0;
+ FAUSTFLOAT fCheckbox0;
+ int fSampleRate;
+ float fConst0;
+ float fConst1;
+ float fRec0[2];
+
+ public:
+
+ void metadata(Meta* m) {
+ m->declare("author", "Dominick Hing, adapted from 'Volume Control' by Matt Horton");
+ m->declare("basics.lib/name", "Faust Basic Element Library");
+ m->declare("basics.lib/version", "0.9");
+ m->declare("compile_options", "-a faust2header.cpp -lang cpp -i -inpl -cn monitordsp -es 1 -mcd 16 -single -ftz 0");
+ m->declare("description", "Volume Control Faust Plugin for JackTrip, based on Faust examples");
+ m->declare("filename", "monitordsp.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.5");
+ m->declare("name", "monitor");
+ m->declare("platform.lib/name", "Generic Platform Library");
+ m->declare("platform.lib/version", "0.3");
+ m->declare("signals.lib/name", "Faust Signal Routing Library");
+ m->declare("signals.lib/version", "0.3");
+ m->declare("version", "1.0");
+ }
+
+ virtual int getNumInputs() {
+ return 2;
+ }
+ virtual int getNumOutputs() {
+ return 1;
+ }
+
+ static void classInit(int /*sample_rate*/) {
+ }
+
+ virtual void instanceConstants(int sample_rate) {
+ fSampleRate = sample_rate;
+ fConst0 = 44.1f / std::min<float>(1.92e+05f, std::max<float>(1.0f, float(fSampleRate)));
+ fConst1 = 1.0f - fConst0;
+ }
+
+ virtual void instanceResetUserInterface() {
+ fHslider0 = FAUSTFLOAT(0.0f);
+ fCheckbox0 = FAUSTFLOAT(0.0f);
+ }
+
+ virtual void instanceClear() {
+ for (int l0 = 0; l0 < 2; l0 = l0 + 1) {
+ fRec0[l0] = 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 monitordsp* clone() {
+ return new monitordsp();
+ }
+
+ virtual int getSampleRate() {
+ return fSampleRate;
+ }
+
+ virtual void buildUserInterface(UI* ui_interface) {
+ ui_interface->openVerticalBox("Monitor");
+ ui_interface->declare(&fHslider0, "0", "");
+ ui_interface->addHorizontalSlider("Volume", &fHslider0, FAUSTFLOAT(0.0f), FAUSTFLOAT(-4e+01f), FAUSTFLOAT(0.0f), FAUSTFLOAT(0.1f));
+ ui_interface->declare(&fCheckbox0, "1", "");
+ ui_interface->addCheckButton("Mute", &fCheckbox0);
+ ui_interface->closeBox();
+ }
+
+ virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
+ FAUSTFLOAT* input0 = inputs[0];
+ FAUSTFLOAT* input1 = inputs[1];
+ FAUSTFLOAT* output0 = outputs[0];
+ float fSlow0 = float(fHslider0);
+ int iSlow1 = fSlow0 == -4e+01f;
+ int iSlow2 = int(float(fCheckbox0));
+ float fSlow3 = fConst0 * std::pow(1e+01f, 0.05f * fSlow0);
+ for (int i0 = 0; i0 < count; i0 = i0 + 1) {
+ float fTemp0 = float(input1[i0]);
+ float fTemp1 = float(input0[i0]);
+ fRec0[0] = fSlow3 + fConst1 * fRec0[1];
+ output0[i0] = FAUSTFLOAT(fTemp0 + ((iSlow1) ? 0.0f : ((iSlow2) ? 0.0f : fTemp1 * fRec0[0])));
+ fRec0[1] = fRec0[0];
+ }
+ }
+
+};
+
+
+#endif