commit 88df3977083e244f55fbd3de8618a1eaa7dc18fb
parent 9c5efe26ab297211f56a3641fa23faa9440877a3
Author: Johannes Lorenz <j.git@lorenz-ho.me>
Date: Sat, 6 Oct 2018 14:27:38 +0200
Add bash completion
Details:
* Add bash completion
* Add parameters `list-inputs` and `list-outputs`
* Choose the preferred spelling `preferred` for `prefered`
Diffstat:
7 files changed, 497 insertions(+), 48 deletions(-)
diff --git a/cmake/BashCompletion.cmake b/cmake/BashCompletion.cmake
@@ -0,0 +1,92 @@
+# A wrapper around pkg-config-provided and cmake-provided bash completion that
+# will have dynamic behavior at INSTALL() time to allow both root-level
+# INSTALL() as well as user-level INSTALL().
+#
+# See also https://github.com/scop/bash-completion
+#
+# Copyright (c) 2018, Tres Finocchiaro, <tres.finocchiaro@gmail.com>
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+#
+# Usage:
+# INCLUDE(BashCompletion)
+# BASHCOMP_INSTALL(foo)
+# ... where "foo" is a shell script adjacent to the CMakeLists.txt
+#
+# How it determines BASHCOMP_PKG_PATH, in order:
+# 1. Uses BASHCOMP_PKG_PATH if already set (e.g. -DBASHCOMP_PKG_PATH=...)
+# a. If not, uses pkg-config's PKG_CHECK_MODULES to determine path
+# b. Fallback to cmake's FIND_PACKAGE(bash-completion) path
+# c. Fallback to hard-coded /usr/share/bash-completion/completions
+# 2. Final fallback to ${CMAKE_INSTALL_PREFIX}/share/bash-completion/completions if
+# detected path is unwritable.
+
+# - Windows does not support bash completion
+# - macOS support should eventually be added for Homebrew (TODO)
+IF(WIN32)
+ MESSAGE(STATUS "Bash competion is not supported on this platform.")
+ELSEIF(APPLE)
+ MESSAGE(STATUS "Bash completion is not yet implemented for this platform.")
+ELSE()
+ INCLUDE(FindUnixCommands)
+ # Honor manual override if provided
+ IF(NOT BASHCOMP_PKG_PATH)
+ # First, use pkg-config, which is the most reliable
+ FIND_PACKAGE(PkgConfig QUIET)
+ IF(PKGCONFIG_FOUND)
+ PKG_CHECK_MODULES(BASH_COMPLETION bash-completion)
+ PKG_GET_VARIABLE(BASHCOMP_PKG_PATH bash-completion completionsdir)
+ ELSE()
+ # Second, use cmake (preferred but less common)
+ FIND_PACKAGE(bash-completion QUIET)
+ IF(BASH_COMPLETION_FOUND)
+ SET(BASHCOMP_PKG_PATH "${BASH_COMPLETION_COMPLETIONSDIR}")
+ ENDIF()
+ ENDIF()
+
+ # Third, use a hard-coded fallback value
+ IF("${BASHCOMP_PKG_PATH}" STREQUAL "")
+ SET(BASHCOMP_PKG_PATH "/usr/share/bash-completion/completions")
+ ENDIF()
+ ENDIF()
+
+ # Always provide a fallback for non-root INSTALL()
+ SET(BASHCOMP_USER_PATH "${CMAKE_INSTALL_PREFIX}/share/bash-completion/completions")
+
+ # Cmake doesn't allow easy use of conditional logic at INSTALL() time
+ # this is a problem because ${BASHCOMP_PKG_PATH} may not be writable and we
+ # need sane fallback behavior for bundled INSTALL() (e.g. .AppImage, etc).
+ #
+ # The reason this can't be detected by cmake is that it's fairly common to
+ # run "cmake" as a one user (i.e. non-root) and "make install" as another user
+ # (i.e. root).
+ #
+ # - Creates a script called "install_${SCRIPT_NAME}_completion.sh" into the
+ # working binary directory and invokes this script at install.
+ # - Script handles INSTALL()-time conditional logic for sane ballback behavior
+ # when ${BASHCOMP_PKG_PATH} is unwritable (i.e. non-root); Something cmake
+ # can't handle on its own at INSTALL() time)
+ MACRO(BASHCOMP_INSTALL SCRIPT_NAME)
+ # A shell script for wrapping conditionl logic
+ SET(BASHCOMP_SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/install_${SCRIPT_NAME}_completion.sh")
+
+ FILE(WRITE ${BASHCOMP_SCRIPT} "\
+#!${BASH}\n\
+set -e\n\
+BASHCOMP_PKG_PATH=\"${BASHCOMP_USER_PATH}\"\n\
+if [ -w \"${BASHCOMP_PKG_PATH}\" ]; then\n\
+ BASHCOMP_PKG_PATH=\"${BASHCOMP_PKG_PATH}\"\n\
+fi\n\
+echo -e \"\\nInstalling bash completion...\\n\"\n\
+mkdir -p \"\$BASHCOMP_PKG_PATH\"\n\
+cp \"${CMAKE_CURRENT_SOURCE_DIR}/${SCRIPT_NAME}\" \"\$BASHCOMP_PKG_PATH\"\n\
+chmod a+r \"\$BASHCOMP_PKG_PATH/${SCRIPT_NAME}\"\n\
+echo -e \"Bash completion for ${SCRIPT_NAME} has been installed to \$BASHCOMP_PKG_PATH/${SCRIPT_NAME}\"\n\
+")
+ INSTALL(CODE "EXECUTE_PROCESS(COMMAND chmod u+x \"install_${SCRIPT_NAME}_completion.sh\" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} )")
+ INSTALL(CODE "EXECUTE_PROCESS(COMMAND \"./install_${SCRIPT_NAME}_completion.sh\" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} )")
+
+ MESSAGE(STATUS "Bash completion script for ${SCRIPT_NAME} will be installed to ${BASHCOMP_PKG_PATH} or fallback to ${BASHCOMP_USER_PATH} if unwritable.")
+ ENDMACRO()
+ENDIF()
+
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
@@ -13,3 +13,6 @@ if(DOXYGEN_FOUND)
COMMENT "Generating API documentation with Doxygen" VERBATIM)
add_custom_target(doc DEPENDS html)
endif()
+
+add_subdirectory(bash-completion)
+
diff --git a/doc/bash-completion/CMakeLists.txt b/doc/bash-completion/CMakeLists.txt
@@ -0,0 +1,6 @@
+INCLUDE(BashCompletion)
+IF(COMMAND BASHCOMP_INSTALL)
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/zynaddsubfx.in
+ ${CMAKE_CURRENT_BINARY_DIR}/zynaddsubfx @ONLY)
+ BASHCOMP_INSTALL(zynaddsubfx)
+ENDIF()
diff --git a/doc/bash-completion/zynaddsubfx.in b/doc/bash-completion/zynaddsubfx.in
@@ -0,0 +1,296 @@
+# zynaddsubfx(1) completion -*- shell-script -*-
+
+_zynaddsubfx_array_contains ()
+{
+ local e match="$1"
+ shift
+ for e; do [[ "$e" == "$match" ]] && return 0; done
+ return 1
+}
+
+_zynaddsubfx_long_param_of()
+{
+ case "$1" in
+ -l)
+ echo "load"
+ ;;
+ -L)
+ echo "load-instrument"
+ ;;
+ -M)
+ echo "midi-learn"
+ ;;
+ -r)
+ echo "sample-rate"
+ ;;
+ -b)
+ echo "buffer-size"
+ ;;
+ -o)
+ echo "oscil-size"
+ ;;
+ -S)
+ echo "swap"
+ ;;
+ -U)
+ echo "no-gui"
+ ;;
+ -N)
+ echo "named"
+ ;;
+ -a)
+ echo "auto-connect"
+ ;;
+ -A)
+ echo "auto-save"
+ ;;
+ -p)
+ echo "pid-in-client"
+ ;;
+ -P)
+ echo "preferred-port"
+ ;;
+ -O)
+ echo "output"
+ ;;
+ -I)
+ echo "input"
+ ;;
+ -e)
+ echo "exec-after-init"
+ ;;
+ -d)
+ echo "dump-oscdoc"
+ ;;
+ -D)
+ echo "dump-json-schema"
+ ;;
+ *)
+ echo ""
+ ;;
+ esac
+}
+
+_zynaddsubfx()
+{
+ local cword=$COMP_CWORD
+ local cur="${COMP_WORDS[COMP_CWORD]}"
+ local params filetypes pars shortargs
+
+ # call routine provided by bash-completion
+ _init_completion || return
+
+ # pars without args
+ pars=(--help --version --auto-connect --no-gui --swap)
+ pars+=(--pid-in-client-name)
+ # pars with args
+ pars+=(--load --load-instrument --midi-learn)
+ pars+=(--sample-rate --buffer-size --oscil-size)
+ pars+=(--named --auto-save)
+ pars+=(--preferred-port --output --input)
+ pars+=(--exec-after-init --dump-oscdoc --dump-json-schema)
+
+ shortargs=(-h -v -l -L -M -r -b -o -S -U -N -a -A -p -P -O -I -e -d -D)
+
+ local prev=
+ if [ "$cword" -gt 1 ]
+ then
+ prev=${COMP_WORDS[cword-1]}
+ fi
+
+ # don't show shortargs, but complete them when entered
+ if [[ $cur =~ ^-[^-]$ ]]
+ then
+ if _zynaddsubfx_array_contains "$cur" "${shortargs[@]}"
+ then
+ COMPREPLY=( "$cur" )
+ fi
+ return
+ fi
+
+
+ local filemode
+
+ #
+ # please keep those in order like def_pars_args above
+ #
+ case $prev in
+ --load|-l)
+ filetypes=xmz
+ filemode=existing_files
+ ;;
+ --load-instrument|-L)
+ filetypes=xiz
+ filemode=existing_files
+ ;;
+ --midi-learn|-M)
+ filetypes=xlz
+ filemode=existing_files
+ ;;
+ --sample-rate|-r)
+ params="8000 16000 44100 48000 96000 192000"
+ ;;
+ --buffer-size|-b)
+ # less than 32 sounds insane, more than 4096 observed buggy
+ params="32 64 128 256 512 1024 2048 4096"
+ ;;
+ --oscil-size|-o)
+ params="128 256 512 1024 2048 4096"
+ ;;
+ --named|-N)
+ ;;
+ --auto-save|-A)
+ params="30 60 120 180 300 450 600 900 1200 1800 2400 3600 "
+ params+="5400 7200 10800 14400 21600 43200 86400"
+ ;;
+ --preferred-port|-P)
+ params=
+ ;;
+ --input|--output|-I|-O)
+ local jack_enable_cmake=@JackEnable@
+ local pa_enable_cmake=@PaEnable@
+ local alsa_enable_cmake=@AlsaEnable@
+ local oss_enable_cmake=@OssEnable@
+
+ local jack_enable pa_enable alsa_enable oss_enable
+ [[ $jack_enable_cmake =~ FALSE|0|OFF|^$ ]] || jack_enable=1
+ [[ $pa_enable_cmake =~ FALSE|0|OFF|^$ ]] || pa_enable=1
+ [[ $alsa_enable_cmake =~ FALSE|0|OFF|^$ ]] || alsa_enable=1
+ [[ $oss_enable_cmake =~ FALSE|0|OFF|^$ ]] || oss_enable=1
+
+ params="null"
+ [ "$jack_enable" ] && params+=" jack"
+ [ "$pa_enable" ] && params+=" pa"
+ [ "$alsa_enable" ] && params+=" alsa"
+ [ "$oss_enable" ] && params+=" oss"
+ if [[ $prev =~ --output|-O ]]
+ then
+ [ "$jack_enable" ] && params+=" jack-multi"
+ [ "$oss_enable" ] && params+=" oss-multi"
+ fi
+
+ if [[ $prev =~ --output|-O ]]
+ then
+ for i in "${COMPREPLY[@]}"
+ do
+ if [ "$i" == '-a' ] || [ "$i" == '--autoconnect' ]
+ then
+ params="jack jack-multi"
+ break;
+ fi
+ done
+ fi
+ ;;
+ --exec-after-init|-e)
+ filemode=executables
+ ;;
+ --dump-oscdoc|-d)
+ filemode=files
+ filetypes=xml
+ ;;
+ --dump-json-schema|-D)
+ filemode=files
+ filetypes=json
+ ;;
+ *)
+ if [[ $prev =~ --help|-h|-version|-v ]]
+ then
+ # the -e flag (from --import) and help/version
+ # always mark the end of arguments
+ return
+ fi
+
+ # add pars to params, but also check the history of comp words
+ local param
+ for param in "${pars[@]}"
+ do
+ local do_append=1
+ for i in "${!COMP_WORDS[@]}"
+ do
+ if [ "$i" -ne 0 ] && [ "$i" -ne "$cword" ]
+ then
+ # disallow double long parameters
+ if [ "${COMP_WORDS[$i]}" == "$param" ]
+ then
+ do_append=
+ # disallow double short parameters
+ elif [ "${COMP_WORDS[$i]:0:1}" == '-' ] && ! [ "${COMP_WORDS[$i]:1:2}" == '-' ] &&
+ [ "--$(_zynaddsubfx_long_param_of "${COMP_WORDS[$i]}")" == "$param" ]
+ then
+ do_append=
+ # --help or --version must be the first parameters
+ elif [ "$cword" -gt 1 ] && [[ $param =~ --help|--version ]]
+ then
+ do_append=
+ fi
+ fi
+ done
+ if [ "$do_append" ]
+ then
+ params+="$param "
+ fi
+ done
+
+ ;;
+ esac
+
+
+ case $filemode in
+
+ # use completion routine provided by bash-completion
+ # to fill $COMPREPLY
+
+ existing_files)
+ _filedir "@($filetypes)"
+ ;;
+
+ existing_directories)
+ _filedir -d
+ ;;
+
+ executables)
+
+ _filedir
+ local tmp=("${COMPREPLY[@]}")
+ COMPREPLY=( )
+ for i in "${!tmp[@]}"
+ do
+ if [ -f "${tmp[i]}" ] && ! [ -x "${tmp[i]}" ]
+ then
+ # if it's a file that can't be executed, omit from completion
+ true
+ else
+ COMPREPLY+=( "${tmp[i]}" )
+ fi
+ done
+ ;;
+
+ files)
+
+ # non existing files complete like directories...
+ _filedir -d
+
+ # ...except for non-completing files with the right file type
+ if [ ${#COMPREPLY[@]} -eq 0 ]
+ then
+ if ! [[ "$cur" =~ /$ ]] && [ "$filetypes" ] && [[ "$cur" =~ \.($filetypes)$ ]]
+ then
+ # file ending fits, we seem to be done
+ COMPREPLY=( "$cur" )
+ fi
+ fi
+ ;;
+
+ esac
+
+ if [ "$params" ]
+ then
+ # none of our parameters contain spaces, so deactivate shellcheck's warning
+ # shellcheck disable=SC2207
+ COMPREPLY+=( $(compgen -W "${params}" -- "${cur}") )
+ fi
+
+}
+
+
+complete -F _zynaddsubfx zynaddsubfx
diff --git a/src/Nio/Nio.cpp b/src/Nio/Nio.cpp
@@ -134,7 +134,7 @@ string Nio::getSink()
#if JACK
#include <jack/jack.h>
-void Nio::preferedSampleRate(unsigned &rate)
+void Nio::preferredSampleRate(unsigned &rate)
{
#if __linux__
//avoid checking in with jack if it's off
@@ -157,7 +157,7 @@ void Nio::preferedSampleRate(unsigned &rate)
}
}
#else
-void Nio::preferedSampleRate(unsigned &)
+void Nio::preferredSampleRate(unsigned &)
{}
#endif
diff --git a/src/Nio/Nio.h b/src/Nio/Nio.h
@@ -45,8 +45,8 @@ namespace Nio
std::string getSource(void);
std::string getSink(void);
- //Get the prefered sample rate from jack (if running)
- void preferedSampleRate(unsigned &rate);
+ //Get the preferred sample rate from jack (if running)
+ void preferredSampleRate(unsigned &rate);
//Complete Master Swaps to ONLY BE CALLED FROM RT CONTEXT
void masterSwap(Master *master);
diff --git a/src/main.cpp b/src/main.cpp
@@ -103,9 +103,9 @@ void sigterm_exit(int /*sig*/)
/*
* Program initialisation
*/
-void initprogram(SYNTH_T synth, Config* config, int prefered_port)
+void initprogram(SYNTH_T synth, Config* config, int preferred_port)
{
- middleware = new MiddleWare(std::move(synth), config, prefered_port);
+ middleware = new MiddleWare(std::move(synth), config, preferred_port);
master = middleware->spawnMaster();
master->swaplr = swaplr;
@@ -241,14 +241,19 @@ int main(int argc, char *argv[])
synth.oscilsize = config.cfg.OscilSize;
swaplr = config.cfg.SwapStereo;
- Nio::preferedSampleRate(synth.samplerate);
+ Nio::preferredSampleRate(synth.samplerate);
synth.alias(); //build aliases
sprng(time(NULL));
+ // for option entrys with the 3rd member (flag) pointing here,
+ // getopt_long*() will return 0 and set this flag to the 4th member (val)
+ int getopt_flag;
+
/* Parse command-line options */
struct option opts[] = {
+ // options with single char equivalents
{
"load", 2, NULL, 'l'
},
@@ -295,7 +300,7 @@ int main(int argc, char *argv[])
"pid-in-client-name", 0, NULL, 'p'
},
{
- "prefered-port", 1, NULL, 'P',
+ "preferred-port", 1, NULL, 'P',
},
{
"output", 1, NULL, 'O'
@@ -312,15 +317,31 @@ int main(int argc, char *argv[])
{
"dump-json-schema", 2, NULL, 'D'
},
+ // options without single char equivalents ("getopt_flag" compulsory)
+ {
+ "list-inputs", no_argument, &getopt_flag, 'i'
+ },
+ {
+ "list-outputs", no_argument, &getopt_flag, 'o'
+ },
{
0, 0, 0, 0
}
};
opterr = 0;
- int option_index = 0, opt, exitwithhelp = 0, exitwithversion = 0;
- int prefered_port = -1;
+ int option_index = 0, opt;
+ enum class exit_with_t
+ {
+ dont_exit,
+ help,
+ version,
+ list_inputs,
+ list_outputs
+ };
+ exit_with_t exit_with = exit_with_t::dont_exit;
+ int preferred_port = -1;
int auto_save_interval = 0;
-int wmidi = -1;
+ int wmidi = -1;
string loadfile, loadinstrument, execAfterInit, loadmidilearn;
@@ -346,10 +367,10 @@ int wmidi = -1;
switch(opt) {
case 'h':
- exitwithhelp = 1;
+ exit_with = exit_with_t::help;
break;
case 'v':
- exitwithversion = 1;
+ exit_with = exit_with_t::version;
break;
case 'Y': /* this command a dummy command (has NO effect)
and is used because I need for NSIS installer
@@ -422,7 +443,7 @@ int wmidi = -1;
break;
case 'P':
if(optarguments)
- prefered_port = atoi(optarguments);
+ preferred_port = atoi(optarguments);
break;
case 'A':
if(optarguments)
@@ -456,49 +477,80 @@ int wmidi = -1;
if(optarguments)
wmidi = atoi(optarguments);
break;
+ case 0: // catch options without single char equivalent
+ switch(getopt_flag)
+ {
+ case 'i':
+ exit_with = exit_with_t::list_inputs;
+ break;
+ case 'o':
+ exit_with = exit_with_t::list_outputs;
+ break;
+ }
+ break;
case '?':
cerr << "ERROR:Bad option or parameter.\n" << endl;
- exitwithhelp = 1;
+ exit_with = exit_with_t::help;
break;
}
}
synth.alias();
- if(exitwithversion) {
- cout << "Version: " << version << endl;
- return 0;
+ switch (exit_with)
+ {
+ case exit_with_t::version:
+ cout << "Version: " << version << endl;
+ break;
+ case exit_with_t::help:
+ cout << "Usage: zynaddsubfx [OPTION]\n\n"
+ << " -h , --help \t\t\t\t Display command-line help and exit\n"
+ << " -v , --version \t\t\t Display version and exit\n"
+ << " -l file, --load=FILE\t\t\t Loads a .xmz file\n"
+ << " -L file, --load-instrument=FILE\t Loads a .xiz file\n"
+ << " -M file, --midi-learn=FILE\t\t Loads a .xlz file\n"
+ << " -r SR, --sample-rate=SR\t\t Set the sample rate SR\n"
+ <<
+ " -b BS, --buffer-size=SR\t\t Set the buffer size (granularity)\n"
+ << " -o OS, --oscil-size=OS\t\t Set the ADsynth oscil. size\n"
+ << " -S , --swap\t\t\t\t Swap Left <--> Right\n"
+ <<
+ " -U , --no-gui\t\t\t\t Run ZynAddSubFX without user interface\n"
+ << " -N , --named\t\t\t\t Postfix IO Name when possible\n"
+ << " -a , --auto-connect\t\t\t AutoConnect when using JACK\n"
+ << " -A , --auto-save=INTERVAL\t\t Automatically save at interval\n"
+ << "\t\t\t\t\t (disabled with 0 interval)\n"
+ << " -p , --pid-in-client-name\t\t Append PID to (JACK) "
+ "client name\n"
+ << " -P , --preferred-port\t\t\t Preferred OSC Port\n"
+ << " -O , --output\t\t\t\t Set Output Engine\n"
+ << " -I , --input\t\t\t\t Set Input Engine\n"
+ << " -e , --exec-after-init\t\t Run post-initialization script\n"
+ << " -d , --dump-oscdoc=FILE\t\t Dump oscdoc xml to file\n"
+ << " -D , --dump-json-schema=FILE\t\t Dump osc schema (.json) to file\n"
+ << endl;
+ break;
+ case exit_with_t::list_inputs:
+ case exit_with_t::list_outputs:
+ {
+ Nio::init(synth, config.cfg.oss_devs, nullptr);
+ auto get_func = (getopt_flag == 'i')
+ ? &Nio::getSources
+ : &Nio::getSinks;
+ std::set<std::string> engines = (*get_func)();
+ for(std::string engine : engines)
+ {
+ std::transform(engine.begin(), engine.end(), engine.begin(),
+ ::tolower);
+ cout << engine << endl;
+ }
+ break;
+ }
+ default:
+ break;
}
- if(exitwithhelp != 0) {
- cout << "Usage: zynaddsubfx [OPTION]\n\n"
- << " -h , --help \t\t\t\t Display command-line help and exit\n"
- << " -v , --version \t\t\t Display version and exit\n"
- << " -l file, --load=FILE\t\t\t Loads a .xmz file\n"
- << " -L file, --load-instrument=FILE\t Loads a .xiz file\n"
- << " -M file, --midi-learn=FILE\t\t Loads a .xlz file\n"
- << " -r SR, --sample-rate=SR\t\t Set the sample rate SR\n"
- <<
- " -b BS, --buffer-size=SR\t\t Set the buffer size (granularity)\n"
- << " -o OS, --oscil-size=OS\t\t Set the ADsynth oscil. size\n"
- << " -S , --swap\t\t\t\t Swap Left <--> Right\n"
- <<
- " -U , --no-gui\t\t\t\t Run ZynAddSubFX without user interface\n"
- << " -N , --named\t\t\t\t Postfix IO Name when possible\n"
- << " -a , --auto-connect\t\t\t AutoConnect when using JACK\n"
- << " -A , --auto-save=INTERVAL\t\t Automatically save at interval\n"
- << "\t\t\t\t\t (disabled with 0 interval)\n"
- << " -p , --pid-in-client-name\t\t Append PID to (JACK) "
- "client name\n"
- << " -P , --preferred-port\t\t\t Preferred OSC Port\n"
- << " -O , --output\t\t\t\t Set Output Engine\n"
- << " -I , --input\t\t\t\t Set Input Engine\n"
- << " -e , --exec-after-init\t\t Run post-initialization script\n"
- << " -d , --dump-oscdoc=FILE\t\t Dump oscdoc xml to file\n"
- << " -D , --dump-json-schema=FILE\t\t Dump osc schema (.json) to file\n"
- << endl;
-
+ if(exit_with != exit_with_t::dont_exit)
return 0;
- }
cerr.precision(1);
cerr << std::fixed;
@@ -507,7 +559,7 @@ int wmidi = -1;
cerr << "Internal latency = \t" << synth.dt() * 1000.0f << " ms" << endl;
cerr << "ADsynth Oscil.Size = \t" << synth.oscilsize << " samples" << endl;
- initprogram(std::move(synth), &config, prefered_port);
+ initprogram(std::move(synth), &config, preferred_port);
bool altered_master = false;
if(!loadfile.empty()) {