qsampler-1.0.0/PaxHeaders/CMakeLists.txt0000644000000000000000000000013214634065603015161 xustar0030 mtime=1718643587.390448566 30 atime=1718643587.390448566 30 ctime=1718643587.390448566 qsampler-1.0.0/CMakeLists.txt0000644000175000001440000002171314634065603015155 0ustar00rncbcuserscmake_minimum_required (VERSION 3.13) project (Qsampler VERSION 1.0.0 DESCRIPTION "A LinuxSampler Qt GUI Interface" HOMEPAGE_URL "https://qsampler.sourceforge.io" LANGUAGES C CXX) set (PROJECT_TITLE "${PROJECT_NAME}") string (TOLOWER "${PROJECT_TITLE}" PROJECT_NAME) set (PROJECT_COPYRIGHT "Copyright (C) 2004-2024, rncbc aka Rui Nuno Capela. All rights reserved.") set (PROJECT_COPYRIGHT2 "Copyright (C) 2007-2019, Christian Schoenebeck") set (PROJECT_DOMAIN "linuxsampler.org") execute_process ( COMMAND git describe --tags --dirty --abbrev=6 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_DESCRIBE_OUTPUT RESULT_VARIABLE GIT_DESCRIBE_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE) if (GIT_DESCRIBE_RESULT EQUAL 0) set (GIT_VERSION "${GIT_DESCRIBE_OUTPUT}") string (REGEX REPLACE "^[^0-9]+" "" GIT_VERSION "${GIT_VERSION}") string (REGEX REPLACE "^1_" "" GIT_VERSION "${GIT_VERSION}") string (REGEX REPLACE "^[_vV]+" "" GIT_VERSION "${GIT_VERSION}") string (REGEX REPLACE "-g" "git." GIT_VERSION "${GIT_VERSION}") string (REGEX REPLACE "[_|-]" "." GIT_VERSION "${GIT_VERSION}") execute_process ( COMMAND git rev-parse --abbrev-ref HEAD WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_REVPARSE_OUTPUT RESULT_VARIABLE GIT_REVPARSE_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE) if (GIT_REVPARSE_RESULT EQUAL 0 AND NOT GIT_REVPARSE_OUTPUT STREQUAL "main") set (GIT_VERSION "${GIT_VERSION} [${GIT_REVPARSE_OUTPUT}]") endif () set (PROJECT_VERSION "${GIT_VERSION}") endif () if (CMAKE_BUILD_TYPE MATCHES "Debug") set (CONFIG_DEBUG 1) set (CONFIG_BUILD_TYPE "debug") else () set (CONFIG_DEBUG 0) set (CONFIG_BUILD_TYPE "release") set (CMAKE_BUILD_TYPE "Release") endif () set (CONFIG_PREFIX "${CMAKE_INSTALL_PREFIX}") include (GNUInstallDirs) set (CONFIG_BINDIR "${CONFIG_PREFIX}/${CMAKE_INSTALL_BINDIR}") set (CONFIG_LIBDIR "${CONFIG_PREFIX}/${CMAKE_INSTALL_LIBDIR}") set (CONFIG_DATADIR "${CONFIG_PREFIX}/${CMAKE_INSTALL_DATADIR}") set (CONFIG_MANDIR "${CONFIG_PREFIX}/${CMAKE_INSTALL_MANDIR}") # Enable libgig availability. option (CONFIG_LIBGIG "Enable libgig interface (default=yes)" 1) # Enable unique/single instance. option (CONFIG_XUNIQUE "Enable unique/single instance (default=yes)" 1) # Enable debugger stack-trace option (assumes --enable-debug). option (CONFIG_STACKTRACE "Enable debugger stack-trace (default=no)" 0) # Enable Wayland support option. option (CONFIG_WAYLAND "Enable Wayland support (EXPERIMENTAL) (default=no)" 0) # Enable Qt6 build preference. option (CONFIG_QT6 "Enable Qt6 build (default=yes)" 1) # Fix for new CMAKE_REQUIRED_LIBRARIES policy. if (POLICY CMP0075) cmake_policy (SET CMP0075 NEW) endif () # Check for Qt... if (CONFIG_QT6) find_package (Qt6 QUIET) if (NOT Qt6_FOUND) set (CONFIG_QT6 0) endif () endif () if (CONFIG_QT6) find_package (QT QUIET NAMES Qt6) else () find_package (QT QUIET NAMES Qt5) endif () find_package (Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Gui Widgets Svg) if (CONFIG_XUNIQUE) find_package (Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Network) endif () find_package (Qt${QT_VERSION_MAJOR}LinguistTools) include (CheckIncludeFile) include (CheckIncludeFiles) include (CheckIncludeFileCXX) include (CheckFunctionExists) include (CheckLibraryExists) # Checks for libraries. if (WIN32) check_function_exists (lroundf CONFIG_ROUND) else () find_library (MATH_LIBRARY m) # Check for round math function. if (MATH_LIBRARY) set (CMAKE_REQUIRED_LIBRARIES "${MATH_LIBRARY};${CMAKE_REQUIRED_LIBRARIES}") check_function_exists (lroundf CONFIG_ROUND) else () message (FATAL_ERROR "*** math library not found.") endif () endif () # Checks for header files. if (UNIX AND NOT APPLE) check_include_files ("fcntl.h;unistd.h;signal.h" HAVE_SIGNAL_H) endif () # Find package modules include (FindPkgConfig) # Check for LSCP libraries. pkg_check_modules (LSCP REQUIRED IMPORTED_TARGET lscp) if (LSCP_FOUND) find_library(LSCP_LIBRARY NAMES ${LSCP_LIBRARIES} HINTS ${LSCP_LIBDIR}) endif () if (LSCP_LIBRARY) set (CONFIG_LIBLSCP 1) set (CMAKE_REQUIRED_LIBRARIES "${LSCP_LIBRARY};${CMAKE_REQUIRED_LIBRARIES}") # Check for for instrument_name in lscp_channel_info_t. check_include_file (lscp/client.h HAVE_LSCP_CLIENT_H) if (NOT HAVE_LSCP_CLIENT_H) set (CONFIG_INSTRUMENT_NAME 0) else () set (CONFIG_INSTRUMENT_NAME 1) endif () # Check for mute/solo in lscp_channel_info_t. if (NOT HAVE_LSCP_CLIENT_H) set (CONFIG_MUTE_SOLO 0) else () set (CONFIG_MUTE_SOLO 1) endif () if (CONFIG_MUTE_SOLO) check_function_exists (lscp_set_channel_mute CONFIG_MUTE_SOLO) endif () if (CONFIG_MUTE_SOLO) check_function_exists (lscp_set_channel_solo CONFIG_MUTE_SOLO) endif () # Check if MIDI instrument mapping is available. check_function_exists (lscp_map_midi_instrument CONFIG_MIDI_INSTRUMENT) # Check if FX sends is available. check_function_exists (lscp_create_fxsend CONFIG_FXSEND) # Check for FX send level in lscp_fxsend_info_t if (CONFIG_FXSEND) if (NOT HAVE_LSCP_CLIENT_H) set (CONFIG_FXSEND_LEVEL 0) else () set (CONFIG_FXSEND_LEVEL 1) endif () endif () # Check if FX send rename is available. if (CONFIG_FXSEND) check_function_exists (lscp_set_fxsend_name CONFIG_FXSEND_RENAME) endif () # Check for audio_routing array type if (NOT HAVE_LSCP_CLIENT_H) set (CONFIG_AUDIO_ROUTING 0) else () set (CONFIG_AUDIO_ROUTING 1) endif () # Check if global volume is available. check_function_exists (lscp_set_volume CONFIG_VOLUME) # Check if instrument editing is available. check_function_exists (lscp_edit_channel_instrument CONFIG_EDIT_INSTRUMENT) # Check for CHANNEL_MIDI LSCP event support in liblscp], check_include_file (lscp/event.h HAVE_LSCP_EVENT_H) if (NOT HAVE_LSCP_EVENT_H) set (CONFIG_EVENT_CHANNEL_MIDI 0) else () set (CONFIG_EVENT_CHANNEL_MIDI 1) endif () # Check for DEVICE_MIDI LSCP event support in liblscp], if (NOT HAVE_LSCP_EVENT_H) set (CONFIG_EVENT_DEVICE_MIDI 0) else () set (CONFIG_EVENT_DEVICE_MIDI 1) endif () # Check if max. voices / streams is available. check_function_exists (lscp_get_voices CONFIG_MAX_VOICES) else () message (FATAL_ERROR "*** LSCP library not found.") set (CONFIG_LIBLSCP 0) endif () # Check for GIG libraries. if (CONFIG_LIBGIG) pkg_check_modules (GIG IMPORTED_TARGET gig>=3.3.0) if (GIG_FOUND) find_library(GIG_LIBRARY NAMES ${GIG_LIBRARIES} HINTS ${GIG_LIBDIR}) endif () if (GIG_LIBRARY) set (CONFIG_LIBGIG 1) #set (CMAKE_REQUIRED_LIBRARIES "${GIG_LIBRARY};${CMAKE_REQUIRED_LIBRARIES}") # liggig supports fast information retrieval. set (CONFIG_LIBGIG_SETAUTOLOAD 1) # Check if libgig/SF.h is available. check_include_file_cxx (libgig/SF.h HAVE_LIBGIG_SF_H) if (NOT HAVE_LIBGIG_SF_H) set (CONFIG_LIBGIG_SF2 0) else () set (CONFIG_LIBGIG_SF2 1) endif () else () message (WARNING "*** GIG library not found.") set (CONFIG_LIBGIG 0) endif () endif () add_subdirectory (src) # Configuration status macro (SHOW_OPTION text value) if (${value}) message ("${text}: yes") else () message ("${text}: no") endif () endmacro () message ("\n ${PROJECT_TITLE} ${PROJECT_VERSION} (Qt ${QT_VERSION})") message ("\n Build target . . . . . . . . . . . . . . . . . . .: ${CONFIG_BUILD_TYPE}\n") show_option (" LSCP instrument name support . . . . . . . . . . ." CONFIG_INSTRUMENT_NAME) show_option (" LSCP mute/solo support . . . . . . . . . . . . . ." CONFIG_MUTE_SOLO) show_option (" LSCP MIDI instrument support . . . . . . . . . . ." CONFIG_MIDI_INSTRUMENT) show_option (" LSCP FX send support . . . . . . . . . . . . . . ." CONFIG_FXSEND) show_option (" LSCP FX send level support . . . . . . . . . . . ." CONFIG_FXSEND_LEVEL) show_option (" LSCP FX send rename support . . . . . . . . . . ." CONFIG_FXSEND_RENAME) show_option (" LSCP audio routing support . . . . . . . . . . . ." CONFIG_AUDIO_ROUTING) show_option (" LSCP volume support . . . . . . . . . . . . . . ." CONFIG_VOLUME) show_option (" LSCP edit instrument support . . . . . . . . . . ." CONFIG_EDIT_INSTRUMENT) show_option (" GigaSampler instrument file support (libgig) . . ." CONFIG_LIBGIG) if (CONFIG_LIBGIG) show_option (" libgig supports fast information retrieval . . . ." CONFIG_LIBGIG_SETAUTOLOAD) show_option (" libgig supports SoundFont2 instruments files . . ." CONFIG_LIBGIG_SF2) endif () show_option (" LSCP channel MIDI event support . . . . . . . . ." CONFIG_EVENT_CHANNEL_MIDI) show_option (" LSCP device MIDI event support . . . . . . . . . ." CONFIG_EVENT_DEVICE_MIDI) show_option (" LSCP runtime max. voices / disk streams support ." CONFIG_MAX_VOICES) message ("") show_option (" Unique/Single instance support . . . . . . . . . ." CONFIG_XUNIQUE) show_option (" Debugger stack-trace (gdb) . . . . . . . . . . . ." CONFIG_STACKTRACE) message ("\n Install prefix . . . . . . . . . . . . . . . . . .: ${CONFIG_PREFIX}\n") qsampler-1.0.0/PaxHeaders/ChangeLog0000644000000000000000000000013214634065603014173 xustar0030 mtime=1718643587.390448566 30 atime=1718643587.390448566 30 ctime=1718643587.390448566 qsampler-1.0.0/ChangeLog0000644000175000001440000005616014634065603014173 0ustar00rncbcusersQsampler - A LinuxSampler Qt GUI Interface ------------------------------------------ ChangeLog 1.0.0 2024-06-19 An Unthinkable Release. - Making up the unthinkable (aka. v1.0.0) 0.9.91 2024-05-01 A Spring'24 Release Candidate 2. - Prepping the unthinkable (aka. v1.0.0-rc2) - Updated to latest framework level (Qt >= 6.7) 0.9.90 2024-04-10 A Spring'24 Release Candidate. - Prepping the unthinkable (aka. v1.0.0-rc1) - Custom color themes are now file based (*.conf); legacy still preserved ntl. 0.9.12 2024-01-24 A Winter'24 Release. - Updated copyright headers into the New Year (2024). 0.9.11 2023-09-09 An End-of-Summer'23 Release. - Preppings to next development cycle (Qt >= 6.6) 0.9.10 2023-06-01 A Spring'23 Release. - Prepping into the next development cycle (with Qt >= 6.5). 0.9.9 2023-03-23 An Early-Spring'23 Release. - Bumping copyright headers to the brand new year. 0.9.8 2022-12-28 An End-of-Year'22 Release. - Just bumping into the next develop cycle/season. 0.9.7 2022-10-03 An Early-Autumn'22 Release. - Add current system user-name to the singleton/unique application instance identifier. 0.9.6 2022-04-02 A Spring'22 Release. - Main application icon is now presented in scalable format (SVG). - Migrated command line parsing to QCommandLineParser/Option (Qt >= 5.2) - Fixed translations path to be relative to application runtime. 0.9.5 2022-01-09 A Winter'22 Release. - Dropped autotools (autoconf, automake, etc.) build system. - Fixed for Qt6 plugins path eg. widget theme or styles. 0.9.4 2021-07-03 An Early-Summer'21 Release. - All builds default to Qt6 (Qt >= 6.1) where available. - CMake is now the official build system. 0.9.3 2021-05-11 A Spring'21 Release. - All packaging builds switching to CMake. 0.9.2 2021-03-14 An End-of-Winter'21 Release. - Bumped version micro/dot number into the next develop cycle. 0.9.1 2021-02-07 A Winter'21 Release. - Early preparations for the New Year develop(ment) cycle. 0.9.0 2020-12-17 A Winter'20 Release. - Early fixing to build for Qt >= 6.0.0 and comply with C++17 standard. 0.6.3 2020-07-31 A Summer'20 Release. - Early fixing to build for Qt >= 5.15.0. 0.6.2 2020-03-24 A Spring'20 Release. - Make man page compression reproducible (after request by Jelle van der Waa, while on the Vee-Ones, thanks). - Ditching deprecated QTime methods for QElapsedTimer's (in compliance to Qt >= 5.14.0). - If connection to server aborted, try to automatically reconnect (if server was not started by QSampler). - Fixed crash when a device disappeared on server side (caused by iterator invalidation). - Bumped copyright headers into the New Year (2020). 0.6.1 2019-12-22 The Winter'19 Release. - Custom color (palette) theme editor introduced; color (palette) theme changes are now effective immediately, except on default. - Second attempt to fix the yet non-official though CMake build configuration. - When using autotools and ./configure --with-qt=..., it is also necessary to adjust the PKG_CONFIG_PATH environment variable (after a merge request by plcl aka. Pedro López-Cabanillas, while on qmidinet). 0.6.0 2019-10-17 An Autumn'19 Release. - Added alternate yet non-official CMake build option. - Fix HiDPI display screen effective support (Qt >= 5.6). - Make sure compiler flags comply to c++11 as standard. 0.5.6 2019-07-12 A Summer'19 Release. - Updated for the newer Qt5 translation tools (>= 5.13). - Configure updated to check for qtchooser availability. - Minor update to Debian packaging control file. 0.5.5 2019-04-11 A Spring-Break'19 Release. - Re-defined all main application UNIX signal handling. 0.5.4 2019-03-11 Pre-LAC2019 Release Frenzy. - Refactored all singleton/unique application instance setup logic away from X11/Xcb hackery. - HiDPI display screen support (Qt >= 5.6). - Bumped copyright headers into the New Year (2019). 0.5.3 2018-12-06 An End of Autumn'18 Release. - Avoid saving plug-in sampler channels and related devices to regular LSCP (*.lscp) session files. - Fixed MIDI and Audio device selection on the common sampler channel settings dialog. - Old deprecated Qt4 build support is no more. - AppStream metadata updated to be the most compliant with latest freedesktop.org specification and recommendation. 0.5.2 2018-07-22 A Summer'18 Release. - AppData/AppStream metadata is now settled under an all permisssive license (FSFAP). 0.5.1 2018-05-21 Pre-LAC2018 release frenzy. - Disable singleton/unique application instance setup logic when the display server platform is not X11. - Fixed device management dialog not responding to user changes. - A little hardening on the configure (autoconf) macro side. - Fixed minor memory leak in device management dialog. - Fixed unnecessary latency when closing app. 0.5.0 2017-12-12 An Autumn'17 release. - French (fr) translation added by Olivier Humbert (qsampler_fr.ts). - Desktop entry specification file is now finally independent from build/configure template chains. - Updated target path for freedesktop.org's AppStream metainfo file (formerly AppData). 0.4.3 2017-04-27 Pre-LAC2017 release frenzy. - Added French man page (by Olivier Humbert, thanks). - Make builds reproducible byte for byte, by getting rid of the configure build date and time stamps. 0.4.2 2016-11-14 A Fall'16 release. - Fixed a potential crash on the singleton/unique application instance setup. - Almost complete overhaul on the configure script command line options, wrt. installation directories specification, eg. --prefix, --bindir, --libdir, --datadir and --mandir. 0.4.1 2016-09-14 End of Summer'16 release. - Fixed a race condition on creating sampler channels that ended in duplicate channel strips; also fixed channel auto-arrange. - Dropped the --enable-qt5 from configure as found redundant given that's the build default anyway (suggestion by Guido Scholz, while for Qtractor, thanks). - Automake: set environment variable GCC_COLORS=auto to allow GCC to auto detect whether it (sh/c)ould output its messages in color. 0.4.0 2016-04-05 Spring'16 release frenzy. - Added application keywords to freedesktop.org's AppData. - Prevent x11extras module from use on non-X11/Unix plaforms. - Messages standard output capture has been improved again, now in both ways a non-blocking pipe may get. - Single/unique application instance control adapted to Qt5/X11. 0.3.1 2015-07-19 Summer'15 release frenzy. - Fixed configure script's Qt include directory lookup for some 64bit Linux flavours. - Prefer Qt5 over Qt4 by default with configure script. - A new top-level widget window geometry state save and restore sub-routine is now in effect. - Fixed for some strict tests for Qt4 vs. Qt5 configure builds. 0.3.0 2015-03-25 Pre-LAC2015 release frenzy. - Added application description as freedesktop.org's AppData. - Added this "Don't ask/show this again" option to some if not most of the nagging warning/error message boxes. - Mac OS X: Fixed default path of linuxsampler binary. - When closing qsampler and showing the user the dialog whether to stop the LinuxSampler backend, set the default selection to "Yes". - Master volume slider now getting proper layout when changing its main toolbar orientation. - Messages standard output capture has been slightly improved as for non-blocking i/o, whenever available. - Adjusted configure check for libgig to detect the new --includedir. - A man page has beed added (making up Matt Flax's work on debian, thanks). - Translations install directory change. - Added support for SF2 instrument names/preset enumeration. - Added instrument list popup on channel strip which shows up when the instrument name is clicked. Allows faster switching among instruments of the same file. - Adjusted configure check for libgig to detect its new --libdir (impolitely forcing the user now to have at least libgig 3.3.0). 0.2.3 2013-12-31 A fifth of a Jubilee. - Allow the build system to include an user specified LDFLAGS. - More preparations for Qt5 configure build. - Standard scalable format (SVG) and MIME type icons support for session files (*.lscp) is now being added. - Preparations for Qt5 migration. - Added include to shut up gcc 4.7 build failures. - Make(ing) -jN parallel builds now available for the masses. - Fixed Makefile.in handling of installation directories to the configure script eg. --datadir, --localedir. - Made lookup of translation files work inside a Mac OS X bundle. - Minor Mac OS X compilation error fix. - Debugging stacktrace now applies to all working threads. - Made lookup of translation files more robust on Windows. - Fixes for cross compiling and building for Windows with configure and make. - libX11 is now being added explicitly to the build link phase, as seen necessary on some bleeding-edge distros eg. Fedora 13, Debian 6. - Moving from old deprecated Qt3'ish custom event post handling into regular asynchronous signal/slot strategy. - Sampler channel and instrument file requester support for other than GIG engine instrument files (*gig; *.dls) has been added, making roads for the newer SFZ and SF2 engines instrument files (*.sfz; *.sf2). - General standard dialog buttons layout is now in place. - Initial widget geometry and visibility persistence logic has been slightly revised as much to avoid crash failures due to wrong main widget hidden state. - General source tree layout and build configuration change. - Automatic crash-dump reports, debugger stack-traces (gdb), back- traces, whatever, are being introduced as a brand new configure option (--enable-stacktrace) and default enabled on debug build targets (--enable-debug). - Attempt to fix broken instrument list model/view on Qt >= 4.6. - Device parameter spin-box default maximum has been set higher: now at a magic 24-bit limit (16777216) instead of older 16-bit (65536), possibly fixing bug #136. - LADISH Level 1 support has been added: SIGUSR1 signal trap just makes it a shortcut to File/Save. - MIDI Device Status menu is disabled when no MIDI device exists; a menu separator has been added. - Window manager's close button was found missing from the Devices and Instruments widgets when on Qt >= 4.5, now fixed. - MIDI activity indicator on channel strips and MIDI device status widgets is now implemented as a flashing green LED, instead of a lame green solid background :). - Global configuration state is now explicitly saved/committed to disk when View/Options... dialog changes are accepted and applied. - Czech (cs) translation added (by Pavel Fric). 0.2.2 2009-08-01 New release cycle. - Russian (qsampler_ru.ts by Alexandre Prokoudine) makes it as brand first translation delivered. Thanks and welcomes whom ever may follow ;) - Converted obsolete QMessageBox forms to standard buttons. - Added support for runtime max. voices / disk streams setting (accessible from the "Options..." dialog). Those fine tuning settings will be saved in case the user modified them and automatically restored to the sampler when reconnecting to a sampler the next time. - Grayed/disabled palette color group fix for dark color themes. - Fait-divers: desktop menu file touched to openSUSE conventions. - Due to some trouble with newer Qt >= 4.4 applications regarding font size configuration, a new global user option is now available to the rescue: View/Options... /Display/Other/Base font size (default none). - Attempt to load Qt's own translation support and get rid of the ever warning startup message, unless built in debug mode. (transaction by Guido Scholz, while on qsynth-devel, thanks). - Only one application instance is now allowed to be up and running, with immediate but graceful termination upon startup iif an already running instance is detected, which will see its main widget shown up automatically (Qt/X11 platform only). - Messages file logging makes its first long overdue appearance, with user configurable settings in View/Options.../Server/Logging. - Bugfix in sampler channel dialog, driver combo boxes' content were screwed. - Automatically add & remove channel strips as they were removed e.g. by other frontends. - Refresh device management dialog when device informations changed, e.g. on changes caused by other frontends (fixes segfault on device changes) - Implemented MIDI device activity windows, selectable from the "View" main menu. - Implemented MIDI activity indicator on channel strips. - Added FX Sends Dialog to Channel Strips. - Color pallete fix for the instrument name display in channel strip, particularly notorious on Mac OS X builds. - Added dialog when the application exits which lets the user decide whether to keep the LinuxSampler running or not. 0.2.1 2007-12-06 Qt4 migration was complete. - Added recent new support of libgig for retrieving instrument names in avery fast way. If libgig provides this feature, then the respective name retrieval setting in qsampler is enabled by default. - The current selected/activated channel-strip is now visually evident while in the application workspace (highlighting). - Make View/Menubar and Toolbar shortcuts accessible even though the main menu and toobar are not visible. - Audio routing table is initially hidden in the dialog, when creating a new sampler channel. - README requirements and configuration notes update. - Disable OK button in sampler channel form and MIDI instrument form if no valid engine is selected (to avoid bothering newbie users with confusing LSCP syntax errors when using the UI the first time). - Fixed creation of devices (don't try to set device parameters which the user did not touch in the device creation dialog). - Added Windows file path support. - Fixed win32/qmakefile and win32/config.h so that it compiles under win32. - Qt4 port of the application. 0.1.5 2007-10-15 Five months later a fifth is heard. - Added support for LSCP escape sequences to allow loading and mapping instrument files with special characters in their filename, as well as special characters for instrument names and instrument map names (requires LSCP v1.2 on sampler side). - Added new button "Edit" to the channel strips, which probably does exactly what you think it does: it opens an appropriate instrument editor application; the channel instrument editor tool is also accessible from the main menu and toolbar. - Application icon is now installed to ${prefix}/share/pixmaps; application desktop entry file is now included in installation; spec file (RPM) is now a bit more openSUSE compliant. - Crash fix on double-clicking on a empty instrument list. 0.1.4 2007-05-04 Almost another year has gone by. - Channel button colors have changed: yellow for mute and cyan for solo is now the rule, but note that this color highlighting is only rendered on some widget styles. - Master sampler volume slider/spinbox combo is now featured. - Initial support for sampler channel FX sends, while saving the session state, only at code-level. - Sampler channel setup dialog does not mandate for valid nor existing instrument file name. - Revised error verbosity in general and on session load/save; hour-glass wait cursor is now displayed on session load/save; keyboard shortcuts changed on MIDI instruments view context; improved channel strip arrangement on session open/load; instrument map entry removal confirmation (as optional); corrected some tooltip text strings. - Most top-level widgets were missing the normal-widget flag, which were causing some sticky size behavior while on some window managers. - Added preliminary MIDI instrument mapping support; now with an instrument list widget and editing capabilities; MIDI instrumeent map program numbers are now displayed in the range 1-128, instead of the internal 0-127. - GPL address update. 0.1.3 2006-06-01 Its been a long year isn't it? - Changed deprecated copyright attribute to license, on qsampler.spec (RPM). - Added configure support for x86_64 libraries (UNTESTED). - Optional specification of alternate liblscp and libgig installation paths have been added to configure command arguments (--with-liblscp, --with-libgig). - Whenever the listing of actual instrument names is not an option (e.g. due to lack of libgig support), the whole number of selectable instrument items is now being graciously increased from just the bare 8 (eight) right up through 100 (one hundred), on the sampler channel setup dialog. - The selection buttons, on the right of the Instrument, Audio and MIDI devices combo-boxes, on the sampler channel dialog, are now expected to be a little better looking than it was before, at least for those Mac OS X eyes. - Minor fixing on the initial messages dock-window height. - Audio output channel routing configuration finally hits the sampler channel dialog, at last! - All widget captions changed to include proper application title name prefix. - Attempt to bring those aging autoconf templates to date; sample SPEC file for RPM build is now being included and generated at configure time. - Set to use QApplication::setMainWidget() instead of registering the traditional lastWindowClosed() signal to quit() slot, just to let the -geometry command line argument have some effect on X11. - Added MUTE/SOLO buttons to individual channel strips. - Fixed compilation error which occured when Qt was compiled with -no-stl. 0.1.2 2005-06-23 Even minor workings needs a rest. - Fixed output disability when messages limit option is turned off (thanks to Wolfgang Woehl for spotting this one, while on qjackctl). - Added CHANNEL_INFO event feedback notification handling; minor stream/voice usage auto-refresh cycle optimization. 0.1.1 2005-06-12 The mantra of bugfixes. - New improved and full-featured application icon, thanks to Christian Schoenebeck design. - Fixed refresh cycle of channel strips that are found in an error state, which was preventing correct channel info updates. - Device configuration now accessible on toolbar. Added buddy text label to device port/channel combobox on the device dialog. - Include libgig version info on command line request (-v). - Minor configure and Makefile install fixes, as Debian and Mac OS X specialties. Also, install does the right thing with target file modes (thanks to Matt Flax and Ebrahim Mayat, for pointing these out). 0.1.0 2005-05-23 Device configuration breakthrough. - Device configuration is now complete. - [bug #9] Fixed for a LSCP command syntax convention consistency, regarding the enumeration of available sampler engines, Audio and MIDI drivers. - [bug #13] Update instrument names list when a new instrument file is select on the channel setup dialog. - Show appropriate message in channel strip while loading an instrument. - Show libgig version in About box (in case libgig is used). 0.0.5 2005-03-04 Fifth alpha-release. - Fixed device driver type channel information gathering, which was severely flawed, dropping all channel session configurations to the default audio driver type (which is ALSA) unexpectedly. - Channels are now properly renumbered when saving to a session LSCP script, assuming that it should be always loaded from scratch (i.e. zero channels). - Disabled MIDI port setting on channel dialog, and on session file save, as its use is still troublesome. - Added new menu and toolbar option: Reset All Channels. - Channel setup changes are now properly filtered, as for only those settings that are actually changed gets applied; change information are now also posted to messages window. - Drag-and-drop of either session files (LSCP scripts) or instrument files (GIG) are now supported. Multiple files drop is allowed, but it only makes sense for instrument files, each one prompting to create a new sampler channel. - Drag-and-drop to an existing channel strip is now also featured, allowing the in-place change of the channel sampler instrument file. - Actual instrument names are now optionally retrieved from the instrument file, even though libgig is available, avoiding excessively annoying load times while on the channel dialog, when huge instrument files are selected. - Set to ignore the SIGPIPE ("Broken pipe") signal, where available, as the default handler is usually fatal when a JACK client is zombified abruptly. - Messages window limit is now enforced only when the line count exceeds in one third the user configured line count maximum; if Qt 3.2.0+ is in use, the QTextView widget is otherwise set to the optimized Qt::LogText format. 0.0.4 2004-11-19 Fourth alpha-release. - Instrument index selection now made via combo box widget; actual instrument names are now properly retrieved from the instrument file, provided if libgig is available. - Sampler channels strips are just created if, and only if, the respective channel setup dialog is actually accepted, following common user-interface guidelines. - Almost complete rewrite of sampler channel strips internal control structures. - Sampler reset command action added to menu and toolbar. - MIDI channel selection is now a dropdown list, allowing the explicit selection for "All" channels input per sampler channel (omni mode). - Channel strip display glass effect has changed background color to black (was green), being now an user option. - Minor configure fixes. 0.0.3 2004-07-06 Third alpha-release. - Mon-modal intrument file loading and status support. - Effective MIDI input port setting on channel dialog, and on session file save. - Channel dialog gets sensible engine and driver defaults on create time. - Implied channel reset on successful instrument load. 0.0.2 2004-06-15 Pre-revolutionary release. - The channel context menu is also accessible by right-clicking over the empty workspace area. - Added small wait event loop on qsamplerMainForm::stopServer(), so let local server terminate gracefully and stabilize, and avoiding a probable segfault on exit, which was preventing the correct salvage of settings and configuration. - Maximum channel volume percent setting is now a global option, provided to override the default (which is 100%). - Client/server transaction timeout option upper limit has been increased from 5000 to 60000 milliseconds. - A channel context menu is now featured, by right-clicking over each sampler channel strip. - Commented SET CHANNEL MIDI_INPUT_PORT command from qsamplerMainForm::saveSessionFile(), it has no effect. - Insert a n #include on qsamplerMessages.cpp, between a #if !defined(WIN32) clause. - An initial non zero value (0.8) is now set for volume of every new sampler channel strip. - The order to load/save and setup channel settings is now as suggested in the following lines: SET CHANNEL AUDIO_OUTPUT_TYPE ... SET CHANNEL MIDI_INPUT_TYPE ... SET CHANNEL MIDI_INPUT_CHANNEL ... LOAD ENGINE ... LOAD INSTRUMENT ... SET CHANNEL VOLUME ... 0.0.1 2004-06-05 Primordial alpha release. qsampler-1.0.0/PaxHeaders/LICENSE0000644000000000000000000000013214634065603013426 xustar0030 mtime=1718643587.390448566 30 atime=1718643587.390448566 30 ctime=1718643587.390448566 qsampler-1.0.0/LICENSE0000644000175000001440000004310314634065603013417 0ustar00rncbcusers GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. qsampler-1.0.0/PaxHeaders/README0000644000000000000000000000013214634065603013301 xustar0030 mtime=1718643587.390448566 30 atime=1718643587.390448566 30 ctime=1718643587.390448566 qsampler-1.0.0/README0000644000175000001440000000476114634065603013301 0ustar00rncbcusersQsampler - A LinuxSampler Qt GUI Interface ------------------------------------------ Qsampler is a LinuxSampler GUI front-end application written in C++ around the Qt framework using Qt Designer. At the moment it just wraps as a client reference interface for the LinuxSampler Control Protocol (LSCP). LinuxSampler is a work in progress. The goal is to produce a free, open source pure software audio sampler with professional grade features, comparable to both hardware and commercial Windows/Mac software samplers. The initial platform will be Linux because it is one of the most promising open source multimedia operating systems. Thanks to various kernel patches and the Jack Audio Connection Kit, Linux is currently able to deliver rock solid sub-5 millisecond MIDI-to-Audio response. Homepage: https://qsampler.sourceforge.io http://qsampler.sourceforge.net See also: https://www.linuxsampler.org License: GNU General Public License (GPL) Requirements ------------ The software requirements for build and runtime are listed as follows: Mandatory: - Qt framework, C++ class library and tools for cross-platform application and UI development https://qt.io/ - liblscp, C library for LinuxSampler control protocol API. https://www.linuxsampler.org/ Optional (opted-in at build time): - libgig, C++ library for loading and modifying Gigasampler and DLS files. https://www.linuxsampler.org/libgig/ Installation ------------ Unpack the tarball and in the extracted source directory: cmake [-DCMAKE_INSTALL_PREFIX=] -B build cmake --build build [--parallel ] and optionally, as root: [sudo] cmake --install build Note that the default installation path () is /usr/local . Configuration ------------- Qsampler holds its settings and configuration state per user, in a file located as $HOME/.config/linuxsampler.org/Qsampler.conf . Normally, there's no need to edit this file, as it is recreated and rewritten everytime qsampler is run. Bugs ---- Plenty as this is still alpha software. Bug reports should be posted on LinuxSampler bug tracker (https://bugs.linuxsampler.org). Support ------- Qsampler is open source free software. For bug reports, feature requests, discussion forums, mailling lists, or any other matter related to the development of this piece of software, please use the LinuxSampler project site (https://www.linuxsampler.org). Enjoy. rncbc aka Rui Nuno Capela rncbc at rncbc dot org https://www.rncbc.org qsampler-1.0.0/PaxHeaders/TRANSLATORS0000644000000000000000000000013214634065603014160 xustar0030 mtime=1718643587.390448566 30 atime=1718643587.390448566 30 ctime=1718643587.390448566 qsampler-1.0.0/TRANSLATORS0000644000175000001440000000025014634065603014145 0ustar00rncbcusersCzech (cs) Pavel Fric French (fr) Olivier Humbert Russian (ru) Alexandre Prokoudine qsampler-1.0.0/PaxHeaders/src0000644000000000000000000000013214634065603013133 xustar0030 mtime=1718643587.395448566 30 atime=1718643587.391448566 30 ctime=1718643587.395448566 qsampler-1.0.0/src/0000755000175000001440000000000014634065603013200 5ustar00rncbcusersqsampler-1.0.0/src/PaxHeaders/mimetypes0000644000000000000000000000013214634065603015147 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/mimetypes/0000755000175000001440000000000014634065603015214 5ustar00rncbcusersqsampler-1.0.0/src/mimetypes/PaxHeaders/org.rncbc.qsampler.application-x-qsampler-session.png0000644000000000000000000000013214634065603027504 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/mimetypes/org.rncbc.qsampler.application-x-qsampler-session.png0000644000175000001440000000335414634065603027501 0ustar00rncbcusersPNG  IHDR szz pHYsodtEXtSoftwarewww.inkscape.org<yIDATX[l\W}xf_8q6$CDQBAHh"* $HJyy3n*]עovۚ6|cyKV~W?p?(2Glwku-V8_޽TcWo?+Iq|iC^y{es}W~"eeeD'LLN(qN445m?vt"cXPW~T ~ַnCnNjܱ+Jg_rP<@)EEUvwJNhs O䩫+>Ͷm[)%$1RqCvelذ굘ɷǩ^2YO/6'\{ O=8;v| #05$ M/q;0Fii~wIc4e/ J%7Nt^CJ3B4d(@ ^zQ+|%ʕ CDi"Fg rpw3#e=LTJ=&"eWbp`WػQՕsphD$$c 'Y$Hej[[)h Ez`Uq:>sO3]ݣ &H,[βAPdoFC7;%#'Rg ZcЎù,*RbO-<_^䘊;d2˭!C#`S (1& Bi"睳 eش)@r Yzē.e$>'3/K TjjĢI$ 5g"Gr&v4 (Y 2ZRj.,R`XLMJ060UU>ϓ{xg:ggiT@=Cz,Ev㫩%,Qåi|)TwvmTrNx`0YpjGh11ikx_ݾյKkJUL3)]~?lrM?çDAg7< WCռc&ygyMd*\@yRb&%_:sߗo Aw0M93Mrz~ = 7/,m?S@r>3:?Ҡ<`_Hs9h8Nx=cbC& lbW ijE$T5j/p.P?#9|9FARy?sǩ\fC[[m 93 Qsampler session (LSCP) qsampler-1.0.0/src/mimetypes/PaxHeaders/org.rncbc.qsampler.application-x-qsampler-session.svg0000644000000000000000000000013214634065603027517 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/mimetypes/org.rncbc.qsampler.application-x-qsampler-session.svg0000644000175000001440000001752314634065603027517 0ustar00rncbcusers qsampler-1.0.0/src/PaxHeaders/qsamplerFxSend.cpp0000644000000000000000000000013214634065603016650 xustar0030 mtime=1718643587.393448566 30 atime=1718643587.393448566 30 ctime=1718643587.393448566 qsampler-1.0.0/src/qsamplerFxSend.cpp0000644000175000001440000001516514634065603016650 0ustar00rncbcusers// qsamplerFxSend.cpp // /**************************************************************************** Copyright (C) 2004-2019, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2008, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #include "qsamplerAbout.h" #include "qsamplerFxSend.h" #include "qsamplerUtilities.h" #include "qsamplerOptions.h" #include "qsamplerMainForm.h" namespace QSampler { // marks FxSend objects which don't exist on sampler side yet #define NEW_FX_SEND -1 FxSend::FxSend(int SamplerChannelID, int FxSendID) : m_iSamplerChannelID(SamplerChannelID), m_iFxSendID(FxSendID), m_bDelete(false), m_bModified(false) { m_MidiCtrl = 91; m_Depth = 0.0f; } FxSend::FxSend(int SamplerChannelID) : m_iSamplerChannelID(SamplerChannelID), m_iFxSendID(NEW_FX_SEND), m_bDelete(false), m_bModified(true) { m_MidiCtrl = 91; m_Depth = 0.0f; } FxSend::~FxSend() { } int FxSend::id() const { return m_iFxSendID; } bool FxSend::isNew() const { return m_iFxSendID == NEW_FX_SEND; } void FxSend::setDeletion(bool bDelete) { m_bDelete = bDelete; m_bModified = true; } bool FxSend::deletion() const { return m_bDelete; } void FxSend::setName(const QString& sName) { m_FxSendName = sName; m_bModified = true; } bool FxSend::isModified() const { return m_bModified; } const QString& FxSend::name() const { return m_FxSendName; } void FxSend::setSendDepthMidiCtrl(int iMidiController) { m_MidiCtrl = iMidiController; m_bModified = true; } int FxSend::sendDepthMidiCtrl() const { return m_MidiCtrl; } void FxSend::setCurrentDepth(float depth) { m_Depth = depth; m_bModified = true; } float FxSend::currentDepth() const { return m_Depth; } int FxSend::audioChannel(int iAudioSrc) const { if (iAudioSrc < 0 || iAudioSrc >= m_AudioRouting.size()) return -1; return m_AudioRouting[iAudioSrc]; } bool FxSend::setAudioChannel(int iAudioSrc, int iAudioDst) { if (iAudioSrc < 0 || iAudioSrc >= m_AudioRouting.size()) return false; m_AudioRouting[iAudioSrc] = iAudioDst; m_bModified = true; return true; } const FxSendRoutingMap& FxSend::audioRouting() const { return m_AudioRouting; } bool FxSend::getFromSampler() { #if CONFIG_FXSEND m_bModified = false; // in case this is a new, actually not yet existing FX send, ignore update if (isNew()) return true; MainForm *pMainForm = MainForm::getInstance(); if (!pMainForm || !pMainForm->client()) return false; lscp_fxsend_info_t* pFxSendInfo = ::lscp_get_fxsend_info( pMainForm->client(), m_iSamplerChannelID, m_iFxSendID); if (!pFxSendInfo) { pMainForm->appendMessagesClient("lscp_get_fxsend_info"); return false; } m_FxSendName = qsamplerUtilities::lscpEscapedTextToRaw(pFxSendInfo->name); m_MidiCtrl = pFxSendInfo->midi_controller; m_Depth = pFxSendInfo->level; m_AudioRouting.clear(); if (pFxSendInfo->audio_routing) for (int i = 0; pFxSendInfo->audio_routing[i] != -1; ++i) m_AudioRouting[i] = pFxSendInfo->audio_routing[i]; return true; #else // CONFIG_FXSEND return false; #endif // CONFIG_FXSEND } bool FxSend::applyToSampler() { #if CONFIG_FXSEND MainForm *pMainForm = MainForm::getInstance(); if (!pMainForm || !pMainForm->client()) return false; // in case FX send doesn't exist on sampler side yet, create it if (isNew()) { // doesn't exist and scheduled for deletion? nothing to do if (deletion()) { m_bModified = false; return true; } int result = ::lscp_create_fxsend( pMainForm->client(), m_iSamplerChannelID, m_MidiCtrl, nullptr ); if (result == -1) { pMainForm->appendMessagesClient("lscp_create_fxsend"); return false; } m_iFxSendID = result; } lscp_status_t result; // delete FX send on sampler side if (deletion()) { result = ::lscp_destroy_fxsend( pMainForm->client(), m_iSamplerChannelID, m_iFxSendID ); if (result != LSCP_OK) { pMainForm->appendMessagesClient("lscp_destroy_fxsend"); return false; } m_bModified = false; return true; } // set FX send depth MIDI controller result = ::lscp_set_fxsend_midi_controller( pMainForm->client(), m_iSamplerChannelID, m_iFxSendID, m_MidiCtrl ); if (result != LSCP_OK) { pMainForm->appendMessagesClient("lscp_set_fxsend_midi_controller"); return false; } #if CONFIG_FXSEND_RENAME // set FX send's name result = ::lscp_set_fxsend_name( pMainForm->client(), m_iSamplerChannelID, m_iFxSendID, qsamplerUtilities::lscpEscapeText( m_FxSendName ).constData() ); if (result != LSCP_OK) { pMainForm->appendMessagesClient("lscp_set_fxsend_name"); return false; } #endif // CONFIG_FXSEND_RENAME // set FX send current send level result = ::lscp_set_fxsend_level( pMainForm->client(), m_iSamplerChannelID, m_iFxSendID, m_Depth ); if (result != LSCP_OK) { pMainForm->appendMessagesClient("lscp_set_fxsend_level"); return false; } // set FX send's audio routing for (int i = 0; i < m_AudioRouting.size(); ++i) { result = ::lscp_set_fxsend_audio_channel( pMainForm->client(), m_iSamplerChannelID, m_iFxSendID, i, /*audio source*/ m_AudioRouting[i] /*audio destination*/ ); if (result != LSCP_OK) { pMainForm->appendMessagesClient("lscp_set_fxsend_audio_channel"); return false; } } m_bModified = false; return true; #else // CONFIG_FXSEND return false; #endif // CONFIG_FXSEND } QList FxSend::allFxSendsOfSamplerChannel(int samplerChannelID) { QList sends; MainForm *pMainForm = MainForm::getInstance(); if (!pMainForm || !pMainForm->client()) return sends; #ifdef CONFIG_FXSEND int *piSends = ::lscp_list_fxsends(pMainForm->client(), samplerChannelID); if (!piSends) { if (::lscp_client_get_errno(pMainForm->client())) pMainForm->appendMessagesClient("lscp_list_fxsends"); } else { for (int iSend = 0; piSends[iSend] >= 0; ++iSend) sends.append(piSends[iSend]); } #endif // CONFIG_FXSEND return sends; } } // namespace QSampler // end of qsamplerFxSend.cpp qsampler-1.0.0/src/PaxHeaders/qsamplerOptionsForm.cpp0000644000000000000000000000013214634065603017740 xustar0030 mtime=1718643587.394448566 30 atime=1718643587.394448566 30 ctime=1718643587.394448566 qsampler-1.0.0/src/qsamplerOptionsForm.cpp0000644000175000001440000004552114634065603017737 0ustar00rncbcusers// qsamplerOptionsForm.cpp // /**************************************************************************** Copyright (C) 2004-2022, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #include "qsamplerOptionsForm.h" #include "qsamplerAbout.h" #include "qsamplerOptions.h" #include "qsamplerPaletteForm.h" #include #include #include #include // Default (empty/blank) name. static const char *g_pszDefName = QT_TRANSLATE_NOOP("qsamplerOptionsForm", "(default)"); namespace QSampler { //------------------------------------------------------------------------- // QSampler::OptionsForm -- Options form implementation. // OptionsForm::OptionsForm ( QWidget* pParent ) : QDialog(pParent) { m_ui.setupUi(this); #if QT_VERSION < QT_VERSION_CHECK(6, 1, 0) QDialog::setWindowIcon(QIcon(":/images/qsampler.png")); #endif // No settings descriptor initially (the caller will set it). m_pOptions = nullptr; // Initialize dirty control state. m_iDirtySetup = 0; m_iDirtyCount = 0; // Set dialog validators... m_ui.ServerPortComboBox->setValidator( new QIntValidator(m_ui.ServerPortComboBox)); // Try to restore old window positioning. adjustSize(); QObject::connect(m_ui.ServerHostComboBox, SIGNAL(editTextChanged(const QString&)), SLOT(optionsChanged())); QObject::connect(m_ui.ServerPortComboBox, SIGNAL(editTextChanged(const QString&)), SLOT(optionsChanged())); QObject::connect(m_ui.ServerTimeoutSpinBox, SIGNAL(valueChanged(int)), SLOT(optionsChanged())); QObject::connect(m_ui.ServerStartCheckBox, SIGNAL(stateChanged(int)), SLOT(optionsChanged())); QObject::connect(m_ui.ServerCmdLineComboBox, SIGNAL(editTextChanged(const QString&)), SLOT(optionsChanged())); QObject::connect(m_ui.StartDelaySpinBox, SIGNAL(valueChanged(int)), SLOT(optionsChanged())); QObject::connect(m_ui.MessagesLogCheckBox, SIGNAL(stateChanged(int)), SLOT(optionsChanged())); QObject::connect(m_ui.MessagesLogPathComboBox, SIGNAL(editTextChanged(const QString&)), SLOT(optionsChanged())); QObject::connect(m_ui.MessagesLogPathToolButton, SIGNAL(clicked()), SLOT(browseMessagesLogPath())); QObject::connect(m_ui.DisplayFontPushButton, SIGNAL(clicked()), SLOT(chooseDisplayFont())); QObject::connect(m_ui.DisplayEffectCheckBox, SIGNAL(toggled(bool)), SLOT(toggleDisplayEffect(bool))); QObject::connect(m_ui.AutoRefreshCheckBox, SIGNAL(stateChanged(int)), SLOT(optionsChanged())); QObject::connect(m_ui.AutoRefreshTimeSpinBox, SIGNAL(valueChanged(int)), SLOT(optionsChanged())); QObject::connect(m_ui.MaxVolumeSpinBox, SIGNAL(valueChanged(int)), SLOT(optionsChanged())); QObject::connect(m_ui.MessagesFontPushButton, SIGNAL(clicked()), SLOT(chooseMessagesFont())); QObject::connect(m_ui.MessagesLimitCheckBox, SIGNAL(stateChanged(int)), SLOT(optionsChanged())); QObject::connect(m_ui.MessagesLimitLinesSpinBox, SIGNAL(valueChanged(int)), SLOT(optionsChanged())); QObject::connect(m_ui.ConfirmRemoveCheckBox, SIGNAL(stateChanged(int)), SLOT(optionsChanged())); QObject::connect(m_ui.ConfirmResetCheckBox, SIGNAL(stateChanged(int)), SLOT(optionsChanged())); QObject::connect(m_ui.ConfirmRestartCheckBox, SIGNAL(stateChanged(int)), SLOT(optionsChanged())); QObject::connect(m_ui.ConfirmErrorCheckBox, SIGNAL(stateChanged(int)), SLOT(optionsChanged())); QObject::connect(m_ui.KeepOnTopCheckBox, SIGNAL(stateChanged(int)), SLOT(optionsChanged())); QObject::connect(m_ui.StdoutCaptureCheckBox, SIGNAL(stateChanged(int)), SLOT(optionsChanged())); QObject::connect(m_ui.MaxRecentFilesSpinBox, SIGNAL(valueChanged(int)), SLOT(optionsChanged())); QObject::connect(m_ui.CompletePathCheckBox, SIGNAL(stateChanged(int)), SLOT(optionsChanged())); QObject::connect(m_ui.InstrumentNamesCheckBox, SIGNAL(stateChanged(int)), SLOT(optionsChanged())); QObject::connect(m_ui.CustomColorThemeComboBox, SIGNAL(activated(int)), SLOT(optionsChanged())); QObject::connect(m_ui.CustomColorThemeToolButton, SIGNAL(clicked()), SLOT(editCustomColorThemes())); QObject::connect(m_ui.CustomStyleThemeComboBox, SIGNAL(activated(int)), SLOT(optionsChanged())); QObject::connect(m_ui.BaseFontSizeComboBox, SIGNAL(editTextChanged(const QString&)), SLOT(optionsChanged())); QObject::connect(m_ui.MaxVoicesSpinBox, SIGNAL(valueChanged(int)), SLOT(maxVoicesChanged(int))); QObject::connect(m_ui.MaxStreamsSpinBox, SIGNAL(valueChanged(int)), SLOT(maxStreamsChanged(int))); QObject::connect(m_ui.DialogButtonBox, SIGNAL(accepted()), SLOT(accept())); QObject::connect(m_ui.DialogButtonBox, SIGNAL(rejected()), SLOT(reject())); } OptionsForm::~OptionsForm() { } // Populate (setup) dialog controls from settings descriptors. void OptionsForm::setup ( Options *pOptions ) { // Set reference descriptor. m_pOptions = pOptions; // Start clean. m_iDirtyCount = 0; // Avoid nested changes. m_iDirtySetup++; // Load combo box history... m_pOptions->loadComboBoxHistory(m_ui.ServerHostComboBox); m_pOptions->loadComboBoxHistory(m_ui.ServerPortComboBox); m_pOptions->loadComboBoxHistory(m_ui.ServerCmdLineComboBox); m_pOptions->loadComboBoxHistory(m_ui.MessagesLogPathComboBox); // Load Server settings... m_ui.ServerHostComboBox->setEditText(m_pOptions->sServerHost); m_ui.ServerPortComboBox->setEditText(QString::number(m_pOptions->iServerPort)); m_ui.ServerTimeoutSpinBox->setValue(m_pOptions->iServerTimeout); m_ui.ServerStartCheckBox->setChecked(m_pOptions->bServerStart); m_ui.ServerCmdLineComboBox->setEditText(m_pOptions->sServerCmdLine); m_ui.StartDelaySpinBox->setValue(m_pOptions->iStartDelay); // Logging options... m_ui.MessagesLogCheckBox->setChecked(m_pOptions->bMessagesLog); m_ui.MessagesLogPathComboBox->setEditText(m_pOptions->sMessagesLogPath); // Load Display options... QFont font; QPalette pal; // Display font. if (m_pOptions->sDisplayFont.isEmpty() || !font.fromString(m_pOptions->sDisplayFont)) font = QFont("Sans Serif", 8); m_ui.DisplayFontTextLabel->setFont(font); m_ui.DisplayFontTextLabel->setText(font.family() + ' ' + QString::number(font.pointSize())); // Display effect. m_ui.DisplayEffectCheckBox->setChecked(m_pOptions->bDisplayEffect); toggleDisplayEffect(m_pOptions->bDisplayEffect); // Auto-refresh and maximum volume options. m_ui.AutoRefreshCheckBox->setChecked(m_pOptions->bAutoRefresh); m_ui.AutoRefreshTimeSpinBox->setValue(m_pOptions->iAutoRefreshTime); m_ui.MaxVolumeSpinBox->setValue(m_pOptions->iMaxVolume); // Messages font. if (m_pOptions->sMessagesFont.isEmpty() || !font.fromString(m_pOptions->sMessagesFont)) font = QFont("Monospace", 8); pal = m_ui.MessagesFontTextLabel->palette(); pal.setColor(QPalette::Window, pal.base().color()); m_ui.MessagesFontTextLabel->setPalette(pal); m_ui.MessagesFontTextLabel->setFont(font); m_ui.MessagesFontTextLabel->setText(font.family() + ' ' + QString::number(font.pointSize())); // Messages limit option. m_ui.MessagesLimitCheckBox->setChecked(m_pOptions->bMessagesLimit); m_ui.MessagesLimitLinesSpinBox->setValue(m_pOptions->iMessagesLimitLines); // Other options finally. m_ui.ConfirmRemoveCheckBox->setChecked(m_pOptions->bConfirmRemove); m_ui.ConfirmRestartCheckBox->setChecked(m_pOptions->bConfirmRestart); m_ui.ConfirmResetCheckBox->setChecked(m_pOptions->bConfirmReset); m_ui.ConfirmErrorCheckBox->setChecked(m_pOptions->bConfirmError); m_ui.KeepOnTopCheckBox->setChecked(m_pOptions->bKeepOnTop); m_ui.StdoutCaptureCheckBox->setChecked(m_pOptions->bStdoutCapture); m_ui.CompletePathCheckBox->setChecked(m_pOptions->bCompletePath); m_ui.InstrumentNamesCheckBox->setChecked(m_pOptions->bInstrumentNames); m_ui.MaxRecentFilesSpinBox->setValue(m_pOptions->iMaxRecentFiles); if (m_pOptions->iBaseFontSize > 0) m_ui.BaseFontSizeComboBox->setEditText(QString::number(m_pOptions->iBaseFontSize)); else m_ui.BaseFontSizeComboBox->setCurrentIndex(0); #ifndef CONFIG_LIBGIG m_ui.InstrumentNamesCheckBox->setEnabled(false); #endif bMaxVoicesModified = bMaxStreamsModified = false; #ifdef CONFIG_MAX_VOICES const bool bMaxVoicesSupported = m_pOptions->getEffectiveMaxVoices() >= 0; const bool bMaxStreamsSupported = m_pOptions->getEffectiveMaxStreams() >= 0; m_ui.MaxVoicesSpinBox->setEnabled(bMaxVoicesSupported); m_ui.MaxVoicesSpinBox->setValue(m_pOptions->getMaxVoices()); if (!bMaxVoicesSupported) m_ui.MaxVoicesSpinBox->setToolTip( tr("This parameter is not supported by the current sampler " "version in use.") ); else m_ui.MaxVoicesSpinBox->setToolTip( tr("The max. amount of voices the sampler shall process " "simultaneously.") ); m_ui.MaxStreamsSpinBox->setEnabled(bMaxStreamsSupported); m_ui.MaxStreamsSpinBox->setValue(m_pOptions->getMaxStreams()); if (!bMaxStreamsSupported) m_ui.MaxStreamsSpinBox->setToolTip( tr("This parameter is not supported by the current sampler " "version in use.") ); else m_ui.MaxStreamsSpinBox->setToolTip( tr("The max. amount of disk streams the sampler shall process " "simultaneously.") ); #else m_ui.MaxVoicesSpinBox->setEnabled(false); m_ui.MaxStreamsSpinBox->setEnabled(false); m_ui.MaxVoicesSpinBox->setToolTip( tr("QSampler was built without support for this parameter.") ); m_ui.MaxStreamsSpinBox->setToolTip( tr("QSampler was built without support for this parameter.") ); #endif // CONFIG_MAX_VOICES // Custom display options... resetCustomColorThemes(m_pOptions->sCustomColorTheme); resetCustomStyleThemes(m_pOptions->sCustomStyleTheme); // Done. m_iDirtySetup--; stabilizeForm(); } // Accept settings (OK button slot). void OptionsForm::accept (void) { // Save options... if (m_iDirtyCount > 0) { // Server settings.... m_pOptions->sServerHost = m_ui.ServerHostComboBox->currentText().trimmed(); m_pOptions->iServerPort = m_ui.ServerPortComboBox->currentText().toInt(); m_pOptions->iServerTimeout = m_ui.ServerTimeoutSpinBox->value(); m_pOptions->bServerStart = m_ui.ServerStartCheckBox->isChecked(); m_pOptions->sServerCmdLine = m_ui.ServerCmdLineComboBox->currentText().trimmed(); m_pOptions->iStartDelay = m_ui.StartDelaySpinBox->value(); // Logging options... m_pOptions->bMessagesLog = m_ui.MessagesLogCheckBox->isChecked(); m_pOptions->sMessagesLogPath = m_ui.MessagesLogPathComboBox->currentText(); // Channels options... m_pOptions->sDisplayFont = m_ui.DisplayFontTextLabel->font().toString(); m_pOptions->bDisplayEffect = m_ui.DisplayEffectCheckBox->isChecked(); m_pOptions->bAutoRefresh = m_ui.AutoRefreshCheckBox->isChecked(); m_pOptions->iAutoRefreshTime = m_ui.AutoRefreshTimeSpinBox->value(); m_pOptions->iMaxVolume = m_ui.MaxVolumeSpinBox->value(); // Messages options... m_pOptions->sMessagesFont = m_ui.MessagesFontTextLabel->font().toString(); m_pOptions->bMessagesLimit = m_ui.MessagesLimitCheckBox->isChecked(); m_pOptions->iMessagesLimitLines = m_ui.MessagesLimitLinesSpinBox->value(); // Other options... m_pOptions->bConfirmRemove = m_ui.ConfirmRemoveCheckBox->isChecked(); m_pOptions->bConfirmRestart = m_ui.ConfirmRestartCheckBox->isChecked(); m_pOptions->bConfirmReset = m_ui.ConfirmResetCheckBox->isChecked(); m_pOptions->bConfirmError = m_ui.ConfirmErrorCheckBox->isChecked(); m_pOptions->bKeepOnTop = m_ui.KeepOnTopCheckBox->isChecked(); m_pOptions->bStdoutCapture = m_ui.StdoutCaptureCheckBox->isChecked(); m_pOptions->bCompletePath = m_ui.CompletePathCheckBox->isChecked(); m_pOptions->bInstrumentNames = m_ui.InstrumentNamesCheckBox->isChecked(); m_pOptions->iMaxRecentFiles = m_ui.MaxRecentFilesSpinBox->value(); m_pOptions->iBaseFontSize = m_ui.BaseFontSizeComboBox->currentText().toInt(); // Custom color/style theme options... if (m_ui.CustomStyleThemeComboBox->currentIndex() > 0) m_pOptions->sCustomStyleTheme = m_ui.CustomStyleThemeComboBox->currentText(); else m_pOptions->sCustomStyleTheme.clear(); if (m_ui.CustomColorThemeComboBox->currentIndex() > 0) m_pOptions->sCustomColorTheme = m_ui.CustomColorThemeComboBox->currentText(); else m_pOptions->sCustomColorTheme.clear(); // Reset dirty flag. m_iDirtyCount = 0; } // If the user modified the limits, apply them to the sampler // (and store it later in qsampler's configuration) if (bMaxVoicesModified && m_ui.MaxVoicesSpinBox->isEnabled()) m_pOptions->setMaxVoices(m_ui.MaxVoicesSpinBox->value()); if (bMaxStreamsModified && m_ui.MaxStreamsSpinBox->isEnabled()) m_pOptions->setMaxStreams(m_ui.MaxStreamsSpinBox->value()); // Save combobox history... m_pOptions->saveComboBoxHistory(m_ui.ServerHostComboBox); m_pOptions->saveComboBoxHistory(m_ui.ServerPortComboBox); m_pOptions->saveComboBoxHistory(m_ui.ServerCmdLineComboBox); m_pOptions->saveComboBoxHistory(m_ui.MessagesLogPathComboBox); // Save/commit to disk. m_pOptions->saveOptions(); // Just go with dialog acceptance. QDialog::accept(); } // Reject settings (Cancel button slot). void OptionsForm::reject (void) { bool bReject = true; // Check if there's any pending changes... if (m_iDirtyCount > 0) { switch (QMessageBox::warning(this, tr("Warning"), tr("Some settings have been changed.\n\n" "Do you want to apply the changes?"), QMessageBox::Apply | QMessageBox::Discard | QMessageBox::Cancel)) { case QMessageBox::Apply: accept(); return; case QMessageBox::Discard: break; default: // Cancel. bReject = false; } } if (bReject) QDialog::reject(); } // Dirty up settings. void OptionsForm::optionsChanged (void) { if (m_iDirtySetup > 0) return; m_iDirtyCount++; stabilizeForm(); } // Stabilize current form state. void OptionsForm::stabilizeForm (void) { bool bValid = (m_iDirtyCount > 0); bool bEnabled = m_ui.ServerStartCheckBox->isChecked(); m_ui.ServerCmdLineTextLabel->setEnabled(bEnabled); m_ui.ServerCmdLineComboBox->setEnabled(bEnabled); m_ui.StartDelayTextLabel->setEnabled(bEnabled); m_ui.StartDelaySpinBox->setEnabled(bEnabled); bEnabled = m_ui.MessagesLogCheckBox->isChecked(); m_ui.MessagesLogPathComboBox->setEnabled(bEnabled); m_ui.MessagesLogPathToolButton->setEnabled(bEnabled); if (bEnabled && bValid) { const QString& sPath = m_ui.MessagesLogPathComboBox->currentText(); bValid = !sPath.isEmpty(); } m_ui.AutoRefreshTimeSpinBox->setEnabled( m_ui.AutoRefreshCheckBox->isChecked()); m_ui.MessagesLimitLinesSpinBox->setEnabled( m_ui.MessagesLimitCheckBox->isChecked()); m_ui.DialogButtonBox->button(QDialogButtonBox::Ok)->setEnabled(bValid); } // Messages log path browse slot. void OptionsForm::browseMessagesLogPath (void) { QString sFileName = QFileDialog::getSaveFileName( this, // Parent. tr("Messages Log"), // Caption. m_ui.MessagesLogPathComboBox->currentText(), // Start here. tr("Log files") + " (*.log)" // Filter (log files) ); if (!sFileName.isEmpty()) { m_ui.MessagesLogPathComboBox->setEditText(sFileName); m_ui.MessagesLogPathComboBox->setFocus(); optionsChanged(); } } // The channel display font selection dialog. void OptionsForm::chooseDisplayFont (void) { bool bOk = false; QFont font = QFontDialog::getFont(&bOk, m_ui.DisplayFontTextLabel->font(), this); if (bOk) { m_ui.DisplayFontTextLabel->setFont(font); m_ui.DisplayFontTextLabel->setText(font.family() + ' ' + QString::number(font.pointSize())); optionsChanged(); } } // The messages font selection dialog. void OptionsForm::chooseMessagesFont (void) { bool bOk = false; QFont font = QFontDialog::getFont(&bOk, m_ui.MessagesFontTextLabel->font(), this); if (bOk) { m_ui.MessagesFontTextLabel->setFont(font); m_ui.MessagesFontTextLabel->setText(font.family() + ' ' + QString::number(font.pointSize())); optionsChanged(); } } // The channel display effect demo changer. void OptionsForm::toggleDisplayEffect ( bool bOn ) { QPalette pal; pal.setColor(QPalette::WindowText, Qt::green); if (bOn) { QPixmap pm(":/images/displaybg1.png"); pal.setBrush(QPalette::Window, QBrush(pm)); } else { pal.setColor(QPalette::Window, Qt::black); } m_ui.DisplayFontTextLabel->setPalette(pal); optionsChanged(); } void OptionsForm::maxVoicesChanged(int /*iMaxVoices*/) { bMaxVoicesModified = true; optionsChanged(); } void OptionsForm::maxStreamsChanged(int /*iMaxStreams*/) { bMaxStreamsModified = true; optionsChanged(); } // Custom color palette theme manager. void OptionsForm::editCustomColorThemes (void) { PaletteForm form(this); form.setSettings(&m_pOptions->settings()); QString sCustomColorTheme; int iDirtyCustomColorTheme = 0; const int iCustomColorTheme = m_ui.CustomColorThemeComboBox->currentIndex(); if (iCustomColorTheme > 0) { sCustomColorTheme = m_ui.CustomColorThemeComboBox->itemText( iCustomColorTheme); form.setPaletteName(sCustomColorTheme); } if (form.exec() == QDialog::Accepted) { sCustomColorTheme = form.paletteName(); ++iDirtyCustomColorTheme; } if (iDirtyCustomColorTheme > 0 || form.isDirty()) { resetCustomColorThemes(sCustomColorTheme); optionsChanged(); } } // Custom color palette themes settler. void OptionsForm::resetCustomColorThemes ( const QString& sCustomColorTheme ) { m_ui.CustomColorThemeComboBox->clear(); m_ui.CustomColorThemeComboBox->addItem( tr(g_pszDefName)); m_ui.CustomColorThemeComboBox->addItems( PaletteForm::namedPaletteList(&m_pOptions->settings())); int iCustomColorTheme = 0; if (!sCustomColorTheme.isEmpty()) { iCustomColorTheme = m_ui.CustomColorThemeComboBox->findText( sCustomColorTheme); if (iCustomColorTheme < 0) iCustomColorTheme = 0; } m_ui.CustomColorThemeComboBox->setCurrentIndex(iCustomColorTheme); } // Custom widget style themes settler. void OptionsForm::resetCustomStyleThemes ( const QString& sCustomStyleTheme ) { m_ui.CustomStyleThemeComboBox->clear(); m_ui.CustomStyleThemeComboBox->addItem( tr(g_pszDefName)); m_ui.CustomStyleThemeComboBox->addItems(QStyleFactory::keys()); int iCustomStyleTheme = 0; if (!sCustomStyleTheme.isEmpty()) { iCustomStyleTheme = m_ui.CustomStyleThemeComboBox->findText( sCustomStyleTheme); if (iCustomStyleTheme < 0) iCustomStyleTheme = 0; } m_ui.CustomStyleThemeComboBox->setCurrentIndex(iCustomStyleTheme); } } // namespace QSampler // end of qsamplerOptionsForm.cpp qsampler-1.0.0/src/PaxHeaders/qsamplerFxSendsModel.h0000644000000000000000000000013214634065603017461 xustar0030 mtime=1718643587.393448566 30 atime=1718643587.393448566 30 ctime=1718643587.393448566 qsampler-1.0.0/src/qsamplerFxSendsModel.h0000644000175000001440000000432714634065603017457 0ustar00rncbcusers// qsamplerFxSendList.h // /**************************************************************************** Copyright (C) 2010-2019, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2008, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *****************************************************************************/ #ifndef __qsamplerFxSendList_h #define __qsamplerFxSendList_h #include "qsamplerFxSend.h" #include #include namespace QSampler { class FxSendsModel : public QAbstractListModel { Q_OBJECT public: FxSendsModel(int iChannelID, QObject *pParent = nullptr); // Overridden methods from subclass(es) int rowCount(const QModelIndex& parent) const; QVariant data(const QModelIndex& index, int role) const; bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole); QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; Qt::ItemFlags flags(const QModelIndex& index) const; // Own methods FxSend *addFxSend(); FxSend *fxSend(const QModelIndex& index); void removeFxSend(const QModelIndex& index); signals: void fxSendsDirtyChanged(bool); public slots: void cleanRefresh(); void applyToSampler(); // not pretty, but more efficient than wiring connections for each element void onExternalModifiication(const QModelIndex& index); private: typedef QList FxSendsList; int m_iChannelID; FxSendsList m_fxSends; }; } // namespace QSampler #endif // __qsamplerFxSendList_h // end of qsamplerFxSendList.h qsampler-1.0.0/src/PaxHeaders/qsampler.cpp0000644000000000000000000000013214634065603015540 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/qsampler.cpp0000644000175000001440000004307314634065603015537 0ustar00rncbcusers// qsampler.cpp // /**************************************************************************** Copyright (C) 2004-2024, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007,2008,2015,2019 Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #include "qsampler.h" #include "qsamplerOptions.h" #include "qsamplerMainForm.h" #include "qsamplerPaletteForm.h" #include #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) #include #ifdef CONFIG_LIBGIG #if defined(Q_CC_GNU) || defined(Q_CC_MINGW) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif #include #if defined(Q_CC_GNU) || defined(Q_CC_MINGW) #pragma GCC diagnostic pop #endif #endif #endif #if defined(__APPLE__) // Toshi Nagata 20080105 #include #endif #ifndef CONFIG_PREFIX #define CONFIG_PREFIX "/usr/local" #endif #ifndef CONFIG_BINDIR #define CONFIG_BINDIR CONFIG_PREFIX "/bin" #endif #ifndef CONFIG_DATADIR #define CONFIG_DATADIR CONFIG_PREFIX "/share" #endif #ifndef CONFIG_LIBDIR #if defined(__x86_64__) #define CONFIG_LIBDIR CONFIG_PREFIX "/lib64" #else #define CONFIG_LIBDIR CONFIG_PREFIX "/lib" #endif #endif #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #define CONFIG_PLUGINSDIR CONFIG_LIBDIR "/qt4/plugins" #elif QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #define CONFIG_PLUGINSDIR CONFIG_LIBDIR "/qt5/plugins" #else #define CONFIG_PLUGINSDIR CONFIG_LIBDIR "/qt6/plugins" #endif #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) #define RELATIVE_LOCALE_DIR "/share/locale" #elif defined(__APPLE__) #define RELATIVE_LOCALE_DIR "/../Resources" #endif //------------------------------------------------------------------------- // Singleton application instance stuff (Qt/X11 only atm.) // #ifdef CONFIG_XUNIQUE #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #ifdef CONFIG_X11 #define QSAMPLER_XUNIQUE "qsamplerApplication" #include /* for gethostname() */ #include #include #endif // CONFIG_X11 #else #include #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) #include #endif #include #include #include #endif #endif // CONFIG_XUNIQUE // Constructor. qsamplerApplication::qsamplerApplication ( int& argc, char **argv ) : QApplication(argc, argv), m_pQtTranslator(nullptr), m_pMyTranslator(nullptr), m_pWidget(nullptr) #ifdef CONFIG_XUNIQUE #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #ifdef CONFIG_X11 , m_pDisplay(nullptr) , m_aUnique(0) , m_wOwner(0) #endif // CONFIG_X11 #else , m_pMemory(nullptr) , m_pServer(nullptr) #endif #endif // CONFIG_XUNIQUE { #if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) QApplication::setApplicationName(QSAMPLER_TITLE); QApplication::setApplicationDisplayName(QSAMPLER_TITLE); // QSAMPLER_TITLE " - " + QObject::tr(QSAMPLER_SUBTITLE)); #if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) QApplication::setDesktopFileName( QString("org.rncbc.%1").arg(PROJECT_NAME)); #endif QString sVersion(PROJECT_VERSION); sVersion += '\n'; sVersion += QString("Qt: %1").arg(qVersion()); #if defined(QT_STATIC) sVersion += "-static"; #endif sVersion += '\n'; #ifdef CONFIG_LIBGIG sVersion += QString("%1: %2") .arg(gig::libraryName().c_str()) .arg(gig::libraryVersion().c_str()); sVersion += '\n'; #endif sVersion += QString("%1: %2") .arg(::lscp_client_package()) .arg(::lscp_client_version()); QApplication::setApplicationVersion(sVersion); #endif // Load translation support. QLocale loc; if (loc.language() != QLocale::C) { // Try own Qt translation... m_pQtTranslator = new QTranslator(this); QString sLocName = "qt_" + loc.name(); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QString sLocPath = QLibraryInfo::path(QLibraryInfo::TranslationsPath); #else QString sLocPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath); #endif if (m_pQtTranslator->load(sLocName, sLocPath)) { QApplication::installTranslator(m_pQtTranslator); } else { sLocPath = QApplication::applicationDirPath(); #ifdef RELATIVE_LOCALE_DIR sLocPath.append(RELATIVE_LOCALE_DIR); #else sLocPath.remove(CONFIG_BINDIR); sLocPath.append(CONFIG_DATADIR "/qsampler/translations"); #endif if (m_pQtTranslator->load(sLocName, sLocPath)) { QApplication::installTranslator(m_pQtTranslator); } else { delete m_pQtTranslator; m_pQtTranslator = nullptr; #ifdef CONFIG_DEBUG qWarning("Warning: no translation found for '%s' locale: %s/%s.qm", loc.name().toUtf8().constData(), sLocPath.toUtf8().constData(), sLocName.toUtf8().constData()); #endif } } // Try own application translation... m_pMyTranslator = new QTranslator(this); sLocName = "qsampler_" + loc.name(); if (m_pMyTranslator->load(sLocName, sLocPath)) { QApplication::installTranslator(m_pMyTranslator); } else { #ifdef RELATIVE_LOCALE_DIR sLocPath = QApplication::applicationDirPath() + RELATIVE_LOCALE_DIR; #else sLocPath = CONFIG_DATADIR "/qsampler/translations"; #endif if (m_pMyTranslator->load(sLocName, sLocPath)) { QApplication::installTranslator(m_pMyTranslator); } else { delete m_pMyTranslator; m_pMyTranslator = nullptr; #ifdef CONFIG_DEBUG qWarning("Warning: no translation found for '%s' locale: %s/%s.qm", loc.name().toUtf8().constData(), sLocPath.toUtf8().constData(), sLocName.toUtf8().constData()); #endif } } } } // Destructor. qsamplerApplication::~qsamplerApplication (void) { #ifdef CONFIG_XUNIQUE #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) clearServer(); #endif #endif // CONFIG_XUNIQUE if (m_pMyTranslator) delete m_pMyTranslator; if (m_pQtTranslator) delete m_pQtTranslator; } // Main application widget accessors. void qsamplerApplication::setMainWidget ( QWidget *pWidget ) { m_pWidget = pWidget; #ifdef CONFIG_XUNIQUE #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #ifdef CONFIG_X11 m_wOwner = m_pWidget->winId(); if (m_pDisplay && m_wOwner) { XGrabServer(m_pDisplay); XSetSelectionOwner(m_pDisplay, m_aUnique, m_wOwner, CurrentTime); XUngrabServer(m_pDisplay); } #endif // CONFIG_X11 #endif #endif // CONFIG_XUNIQUE } // Check if another instance is running, // and raise its proper main widget... bool qsamplerApplication::setup (void) { #ifdef CONFIG_XUNIQUE #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #ifdef CONFIG_X11 m_pDisplay = QX11Info::display(); if (m_pDisplay) { QString sUnique = QSAMPLER_XUNIQUE; QString sUserName = QString::fromUtf8(::getenv("USER")); if (sUserName.isEmpty()) sUserName = QString::fromUtf8(::getenv("USERNAME")); if (!sUserName.isEmpty()) { sUnique += ':'; sUnique += sUserName; } char szHostName[255]; if (::gethostname(szHostName, sizeof(szHostName)) == 0) { sUnique += '@'; sUnique += QString::fromUtf8(szHostName); } m_aUnique = XInternAtom(m_pDisplay, sUnique.toUtf8().constData(), false); XGrabServer(m_pDisplay); m_wOwner = XGetSelectionOwner(m_pDisplay, m_aUnique); XUngrabServer(m_pDisplay); if (m_wOwner != None) { // First, notify any freedesktop.org WM // that we're about to show the main widget... Screen *pScreen = XDefaultScreenOfDisplay(m_pDisplay); int iScreen = XScreenNumberOfScreen(pScreen); XEvent ev; memset(&ev, 0, sizeof(ev)); ev.xclient.type = ClientMessage; ev.xclient.display = m_pDisplay; ev.xclient.window = m_wOwner; ev.xclient.message_type = XInternAtom(m_pDisplay, "_NET_ACTIVE_WINDOW", false); ev.xclient.format = 32; ev.xclient.data.l[0] = 0; // Source indication. ev.xclient.data.l[1] = 0; // Timestamp. ev.xclient.data.l[2] = 0; // Requestor's currently active window (none) ev.xclient.data.l[3] = 0; ev.xclient.data.l[4] = 0; XSelectInput(m_pDisplay, m_wOwner, StructureNotifyMask); XSendEvent(m_pDisplay, RootWindow(m_pDisplay, iScreen), false, (SubstructureNotifyMask | SubstructureRedirectMask), &ev); XSync(m_pDisplay, false); XRaiseWindow(m_pDisplay, m_wOwner); // And then, let it get caught on destination // by QApplication::native/x11EventFilter... const QByteArray value = QSAMPLER_XUNIQUE; XChangeProperty( m_pDisplay, m_wOwner, m_aUnique, m_aUnique, 8, PropModeReplace, (unsigned char *) value.data(), value.length()); // Done. return true; } } #endif // CONFIG_X11 return false; #else return setupServer(); #endif #else return false; #endif // !CONFIG_XUNIQUE } #ifdef CONFIG_XUNIQUE #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #ifdef CONFIG_X11 void qsamplerApplication::x11PropertyNotify ( Window w ) { if (m_pDisplay && m_pWidget && m_wOwner == w) { // Always check whether our property-flag is still around... Atom aType; int iFormat = 0; unsigned long iItems = 0; unsigned long iAfter = 0; unsigned char *pData = 0; if (XGetWindowProperty( m_pDisplay, m_wOwner, m_aUnique, 0, 1024, false, m_aUnique, &aType, &iFormat, &iItems, &iAfter, &pData) == Success && aType == m_aUnique && iItems > 0 && iAfter == 0) { // Avoid repeating it-self... XDeleteProperty(m_pDisplay, m_wOwner, m_aUnique); // Just make it always shows up fine... m_pWidget->showNormal(); m_pWidget->raise(); m_pWidget->activateWindow(); // FIXME: Do our best speciality, although it should be // done iif configuration says so, we'll do it anyway! qsamplerMainForm *pMainForm = qsamplerMainForm::getInstance(); if (pMainForm) pMainForm->startAllEngines(); } // Free any left-overs... if (iItems > 0 && pData) XFree(pData); } } bool qsamplerApplication::x11EventFilter ( XEvent *pEv ) { if (pEv->type == PropertyNotify && pEv->xproperty.state == PropertyNewValue) x11PropertyNotify(pEv->xproperty.window); return QApplication::x11EventFilter(pEv); } #endif // CONFIG_X11 #else // Local server/shmem setup. bool qsamplerApplication::setupServer (void) { clearServer(); m_sUnique = QCoreApplication::applicationName(); QString sUserName = QString::fromUtf8(::getenv("USER")); if (sUserName.isEmpty()) sUserName = QString::fromUtf8(::getenv("USERNAME")); if (!sUserName.isEmpty()) { m_sUnique += ':'; m_sUnique += sUserName; } m_sUnique += '@'; m_sUnique += QHostInfo::localHostName(); #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) const QNativeIpcKey nativeKey = QSharedMemory::legacyNativeKey(m_sUnique); #if defined(Q_OS_UNIX) m_pMemory = new QSharedMemory(nativeKey); m_pMemory->attach(); delete m_pMemory; #endif m_pMemory = new QSharedMemory(nativeKey); #else #if defined(Q_OS_UNIX) m_pMemory = new QSharedMemory(m_sUnique); m_pMemory->attach(); delete m_pMemory; #endif m_pMemory = new QSharedMemory(m_sUnique); #endif bool bServer = false; const qint64 pid = QCoreApplication::applicationPid(); struct Data { qint64 pid; }; if (m_pMemory->create(sizeof(Data))) { m_pMemory->lock(); Data *pData = static_cast (m_pMemory->data()); if (pData) { pData->pid = pid; bServer = true; } m_pMemory->unlock(); } else if (m_pMemory->attach()) { m_pMemory->lock(); // maybe not necessary? Data *pData = static_cast (m_pMemory->data()); if (pData) bServer = (pData->pid == pid); m_pMemory->unlock(); } if (bServer) { QLocalServer::removeServer(m_sUnique); m_pServer = new QLocalServer(); m_pServer->setSocketOptions(QLocalServer::UserAccessOption); m_pServer->listen(m_sUnique); QObject::connect(m_pServer, SIGNAL(newConnection()), SLOT(newConnectionSlot())); } else { QLocalSocket socket; socket.connectToServer(m_sUnique); if (socket.state() == QLocalSocket::ConnectingState) socket.waitForConnected(200); if (socket.state() == QLocalSocket::ConnectedState) { socket.write(QCoreApplication::arguments().join(' ').toUtf8()); socket.flush(); socket.waitForBytesWritten(200); } } return !bServer; } // Local server/shmem cleanup. void qsamplerApplication::clearServer (void) { if (m_pServer) { m_pServer->close(); delete m_pServer; m_pServer = nullptr; } if (m_pMemory) { delete m_pMemory; m_pMemory = nullptr; } m_sUnique.clear(); } // Local server conection slot. void qsamplerApplication::newConnectionSlot (void) { QLocalSocket *pSocket = m_pServer->nextPendingConnection(); QObject::connect(pSocket, SIGNAL(readyRead()), SLOT(readyReadSlot())); } // Local server data-ready slot. void qsamplerApplication::readyReadSlot (void) { QLocalSocket *pSocket = qobject_cast (sender()); if (pSocket) { const qint64 nread = pSocket->bytesAvailable(); if (nread > 0) { const QByteArray data = pSocket->read(nread); // Just make it always shows up fine... if (m_pWidget) { m_pWidget->showNormal(); m_pWidget->raise(); m_pWidget->activateWindow(); } // Reset the server... setupServer(); } } } #endif #endif // CONFIG_XUNIQUE //------------------------------------------------------------------------- // stacktrace - Signal crash handler. // #ifdef CONFIG_STACKTRACE #if defined(__GNUC__) && defined(Q_OS_LINUX) #include #include #include #include #include void stacktrace ( int signo ) { pid_t pid; int rc; int status = 0; char cmd[80]; // Reinstall default handler; prevent race conditions... ::signal(signo, SIG_DFL); static const char *shell = "/bin/sh"; static const char *format = "gdb -q --batch --pid=%d" " --eval-command='thread apply all bt'"; snprintf(cmd, sizeof(cmd), format, (int) getpid()); pid = fork(); // Fork failure! if (pid < 0) return; // Fork child... if (pid == 0) { execl(shell, shell, "-c", cmd, nullptr); _exit(1); return; } // Parent here: wait for child to terminate... do { rc = waitpid(pid, &status, 0); } while ((rc < 0) && (errno == EINTR)); // Dispatch any logging, if any... QApplication::processEvents(QEventLoop::AllEvents, 3000); // Make sure everyone terminates... kill(pid, SIGTERM); _exit(1); } #endif #endif //------------------------------------------------------------------------- // main - The main program trunk. // int main ( int argc, char **argv ) { Q_INIT_RESOURCE(qsampler); #ifdef CONFIG_STACKTRACE #if defined(__GNUC__) && defined(Q_OS_LINUX) ::signal(SIGILL, stacktrace); ::signal(SIGFPE, stacktrace); ::signal(SIGSEGV, stacktrace); ::signal(SIGABRT, stacktrace); ::signal(SIGBUS, stacktrace); #endif #endif #if defined(Q_OS_LINUX) && !defined(CONFIG_WAYLAND) ::setenv("QT_QPA_PLATFORM", "xcb", 0); #endif #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif #endif qsamplerApplication app(argc, argv); #if defined(__APPLE__) // Toshi Nagata 20080105 { // Set the plugin path to @exetutable_path/../plugins QDir dir(QApplication::applicationDirPath()); dir.cdUp(); // "Contents" directory QApplication::setLibraryPaths(QStringList(dir.absolutePath() + "/plugins")); // Set the PATH environment variable to include @executable_path/../../.. dir.cdUp(); dir.cdUp(); QString path(getenv("PATH")); path = dir.absolutePath() + ":" + path; setenv("PATH", path.toUtf8().constData(), 1); } #endif // Construct default settings; override with command line arguments. QSampler::Options options; if (!options.parse_args(app.arguments())) { app.quit(); return 1; } // Have another instance running? if (app.setup()) { app.quit(); return 2; } // Special custom styles... if (QDir(CONFIG_PLUGINSDIR).exists()) app.addLibraryPath(CONFIG_PLUGINSDIR); if (!options.sCustomStyleTheme.isEmpty()) app.setStyle(QStyleFactory::create(options.sCustomStyleTheme)); // Custom color theme (eg. "KXStudio")... const QChar sep = QDir::separator(); QString sPalettePath = QApplication::applicationDirPath(); sPalettePath.remove(CONFIG_BINDIR); sPalettePath.append(CONFIG_DATADIR); sPalettePath.append(sep); sPalettePath.append(PROJECT_NAME); sPalettePath.append(sep); sPalettePath.append("palette"); if (QDir(sPalettePath).exists()) { QStringList names; names.append("KXStudio"); names.append("Wonton Soup"); QStringListIterator name_iter(names); while (name_iter.hasNext()) { const QString& name = name_iter.next(); const QFileInfo fi(sPalettePath, name + ".conf"); if (fi.isReadable()) { QSampler::PaletteForm::addNamedPaletteConf( &options.settings(), name, fi.absoluteFilePath()); } } } QPalette pal(app.palette()); if (QSampler::PaletteForm::namedPalette( &options.settings(), options.sCustomColorTheme, pal)) app.setPalette(pal); // Set default base font... if (options.iBaseFontSize > 0) app.setFont(QFont(app.font().family(), options.iBaseFontSize)); // Construct, setup and show the main form. QSampler::MainForm w; w.setup(&options); w.show(); // Settle this one as application main widget... app.setMainWidget(&w); // Register the quit signal/slot. // app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit())); return app.exec(); } // end of qsampler.cpp qsampler-1.0.0/src/PaxHeaders/images0000644000000000000000000000013214634065603014400 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/0000755000175000001440000000000014634065603014445 5ustar00rncbcusersqsampler-1.0.0/src/images/PaxHeaders/formAccept.png0000644000000000000000000000013214634065603017246 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/formAccept.png0000644000175000001440000000027314634065603017240 0ustar00rncbcusersPNG  IHDRasRGBuIDAT8 D#u]Ùt&U04J?{ ;/~BLD0@hd l dpxJ)R03~YI99}ײWs3zN{lż:IENDB`qsampler-1.0.0/src/images/PaxHeaders/qsamplerInstrument.png0000644000000000000000000000013214634065603021100 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/qsamplerInstrument.png0000644000175000001440000000045214634065603021071 0ustar00rncbcusersPNG  IHDRĴl;sRGBbKGD pHYs  tIME 6gb|IDAT8A 0?kYX~uJZ51K?BgPEUe !bFUif$I\55qzz?Z $sg@D|#=?v<%y2^C3V |7|g?TqxxüJs[VIENDB`qsampler-1.0.0/src/images/PaxHeaders/deviceDelete.png0000644000000000000000000000013214634065603017545 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/deviceDelete.png0000644000175000001440000000062714634065603017542 0ustar00rncbcusersPNG  IHDRasRGBbKGD pHYs  tIMEIDAT8˵m0 ]"shgg Q! wq y ( AQw<$?bFP7=VJєݖ0boB_/ޫsADp"|mʶb MxP8s@OdH-"RV23bLy5r"U@!* 3H~}n"tO&l8oCFHP }/]ŷķz+n%u3*gf91> f:@IENDB`qsampler-1.0.0/src/images/PaxHeaders/qsampler.svg0000644000000000000000000000013214634065603017022 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/qsampler.svg0000644000175000001440000001056614634065603017022 0ustar00rncbcusers qsampler-1.0.0/src/images/PaxHeaders/editResetAllChannels.png0000644000000000000000000000013214634065603021220 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/editResetAllChannels.png0000644000175000001440000000051714634065603021213 0ustar00rncbcusersPNG  IHDRĴl;IDATxݕ E?S&1gdap4&&6mB?Cu^/mNp]Wsx>c#" =Woy P; y~/ضPMNE{0As̪(lBtYʸts٤t96g~%OSHzZ<{[xk(!1hٞD# ~ D"~S+W(DkN&K^ktuuS޾ϝuuu?Y [ZkN4hs/n_rz)޾a)x<DCCCtI <b1_p7𸣓 I/"ǐ{,Kb+g$wx + cO&"sϗ' Q W@)a+< A-ݏ5Ҥm XP!103r-4qRvACD9r_SS35$Ta1T%)\٥[5랞9skoo6 оOPk(0 P'>|ukV6˟$i)leaX.B`.-}(\e.wИIS9Rg_KfWb'c `UۢS,B@ww<}v9?~@LjIENDB`qsampler-1.0.0/src/images/PaxHeaders/fileSave.png0000644000000000000000000000013214634065603016721 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/fileSave.png0000644000175000001440000000031514634065603016710 0ustar00rncbcusersPNG  IHDRĴl;sRGBIDAT8 0 FҝrJOJEAA/ih>lnB0RT;1Lo>G}P]/ŵ7Hi|v*$U?"ܰ3,'c&IENDB`qsampler-1.0.0/src/images/PaxHeaders/midi2.png0000644000000000000000000000013214634065603016167 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/midi2.png0000644000175000001440000000035714634065603016164 0ustar00rncbcusersPNG  IHDRaIDAT8œ 0 D_9333G,WU[(H+>;9/c:%=Z. $$3y{fv 7;f$"INf "0"bHuQ2S֐tzm13i|ܷIWGSx*(kXw_ӗ_<, EIENDB`qsampler-1.0.0/src/images/PaxHeaders/ledon1.png0000644000000000000000000000013214634065603016345 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/ledon1.png0000644000175000001440000000125014634065603016333 0ustar00rncbcusersPNG  IHDRabKGD pHYs  tIME&k;>5IDATx͒MkQ{g26 jlJSB#tD(n+Kw A]P]ٸ&&I?&ׅTk=s}x:ȟJ2fP K[d(6j_777EZ->'XXGgVM8V҅;N޻_b[٩z9^fۨ+DQvC'֯WLw-疲 E$@s^f8[q;j|[ƶT>%5!' óCu $JZ~=4Tv( %.XFLbԇ/;HR.8HD@a'R]bWā|>}Zq@]j6f)O4.EK @ M)˙K9k 5"ZFxl6_8m; |[ R|\pMmLwh<,__\.OW@ ,a8Eݶ?[u*~^IENDB`qsampler-1.0.0/src/images/PaxHeaders/fileRestart.png0000644000000000000000000000013214634065603017447 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/fileRestart.png0000644000175000001440000000111714634065603017437 0ustar00rncbcusersPNG  IHDRĴl;IDATxOhqw~63(9spX98I)rpܔ?)vp1L(R!3ofc~~v~C^zFAI;~Q # |iC9)R8}0u}g.ۖgt]޾{=?/qgvWgG2/\-ֵgrr hl~S<ݹSg .2qz4[oxl3E0ahΏ{=} Xm]D<*&B ѩ,8?ԏ+ӏwi»VI74M U W2soώ_ x8WjP @JR B!pؘ3] Lr)( @4)+* 0v}H)BHuZF-("l!i"ulM0 o#_ LlCi&n:NJ-3ޫ{~:ҽs6x0 !mם}|h4φc .DY'Pn.\u%S.:\e/z'~t4gVq8493݃c 핺}|: 4@Aq0 ,..=gEGA3XR(%0+>\\Uw۝|fqz[7Mi}me!RT3|uqfg(\;Rf"Ppo--U6Af{uM,[͚@£E0E|oؤEIENDB`qsampler-1.0.0/src/images/PaxHeaders/audio2.png0000644000000000000000000000013214634065603016346 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/audio2.png0000644000175000001440000000034114634065603016334 0ustar00rncbcusersPNG  IHDRaIDAT8˕SQ ^7fYd Y׭07胄IJK$/4IKmYtYbGmAoR{ Cdܺv2eQƅ$DtgSDRwY*6MҜȉQxU )5''@iL&˜ՅIENDB`qsampler-1.0.0/src/images/PaxHeaders/deviceCreate.png0000644000000000000000000000013214634065603017546 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/deviceCreate.png0000644000175000001440000000063014634065603017535 0ustar00rncbcusersPNG  IHDRasRGBbKGD pHYs  tIME6`IDAT8˵u! D?ynۆ p6P цS@ 62Gff-ߙ֩,qZ 4!e0@wg9*9am,N(^sXmܣB++ZI @Jge!<2 DU FE Hk&qmȒϤ L)7Ek;^JMdQJO_Ƿ,IENDB`qsampler-1.0.0/src/images/PaxHeaders/itemFile.png0000644000000000000000000000013214634065603016721 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/itemFile.png0000644000175000001440000000060414634065603016711 0ustar00rncbcusersPNG  IHDRaKIDAT8ˍJ@ ^,4P]H *ϣc>Mׂ}xAjf.EM60|󟙉b>tށ6@2m;[Br B  NSјYV Ew qA'P̧ZLA`C%pQ,GLCQZ;/K[hLAuLjW]$$QӴKVR1 1XIENDB`qsampler-1.0.0/src/images/PaxHeaders/editSetupChannel.png0000644000000000000000000000013214634065603020422 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/editSetupChannel.png0000644000175000001440000000047414634065603020417 0ustar00rncbcusersPNG  IHDRĴl;sRGBbKGD pHYs  tIMEIDAT8 E0TFa,=XC%K`Ë?"ר"yY "Fe-g4МׂOPٴO:[]Њ!9I;??/`g/AX Ƙok瓯Cc4+1:? 9dfKhfxw+2M!یι};!oft5c(9>mL)agvBDx]i{*P*( R^ 32ﭷ9-{HIENDB`qsampler-1.0.0/src/images/PaxHeaders/editResetChannel.png0000644000000000000000000000013214634065603020404 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/editResetChannel.png0000644000175000001440000000040414634065603020372 0ustar00rncbcusersPNG  IHDRĴl;IDATxQ DG&^o=\d9B5ڟvv@3bE΁J@σKfz<Ǒi:8p#NFc IU-t1Ƣ0(s)UE"e˽\DR1D!Pkmk9BINX(I C +^׊1yom}|c5{z/ü_l\[ IENDB`qsampler-1.0.0/src/images/PaxHeaders/formSave.png0000644000000000000000000000013214634065603016745 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/formSave.png0000644000175000001440000000111014634065603016726 0ustar00rncbcusersPNG  IHDRasBIT|d pHYsu85tEXtSoftwarewww.inkscape.org<IDAT8ZA}19nCr@$`iHPWRQه̞qoIˬ`Γ,vh` mbѲ,8^ppRh4t/{T*rn3Nz= BRtxpIENDB`qsampler-1.0.0/src/images/PaxHeaders/qsampler.png0000644000000000000000000000013214634065603017007 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/qsampler.png0000644000175000001440000000443314634065603017003 0ustar00rncbcusersPNG  IHDR szz pHYsyytEXtSoftwarewww.inkscape.org<IDATX[l\}3ό=\ !&-Q KQ@ڇ*!HU*\R[ԇRD+@E! !$!;qlljg3sݻg4‘ΑfZknB@+tA6!TG9Eu妜M[@7䞆ǡ}Y!`̌ ZkuCˀB{!)4ח!QyUFG%F'`P{]k!`_;h6}Vv۷5ضGbۑ U=oȤ _kOӅG4J`.Ćuf LiX| o?Z>&6)M"<f)ضOb^^r %ִ󶵜}(*@H;T.-B4A=]]]ƫ>KS"2|jQTժO-g.ϕY,VY)+̚][9'P4t? Sk4CO@̳;p"ђGch,LM\`+"+RcI@[`D.66lN*)7'=(נTZM ݳ֞Nq0-02 \<=O@h2&lhf`퓐0Wcgfh#aA672LL$2NJi@k oшP)TC!8`m֋Dպ"X= (;\Vj5 %ɑoΙ Z5,҄`7-7r6\E7|9|r]M Lp gnަ-!K1]5À# m xΩ1nQZAgX.{}J|y|84g3@Dx9DiQ|DD(,s(k{ )30V?K-5! IENDB`qsampler-1.0.0/src/images/PaxHeaders/itemReset.png0000644000000000000000000000013214634065603017124 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/itemReset.png0000644000175000001440000000110314634065603017107 0ustar00rncbcusersPNG  IHDRasBIT|d pHYsbb8ztEXtSoftwarewww.inkscape.org<IDAT8R`__] NHMP ]ڥCS'(tS7%O24bHi/5{clt{s? D$(M/Lr)˲|i .y'aE1'mq("( ԡ}eYf)q mE1;͒l6re}u=" ѨZUBl[c $۶ziVs !Kv;cEp΁R R4M$~;9?5 s~Z!g~Q20J)AG"H7Bay?m4J1LRT.v$"!`8(ur|V*c}q%N~3υri6MZ.:GixUs IENDB`qsampler-1.0.0/src/images/PaxHeaders/itemGroupOpen.png0000644000000000000000000000013214634065603017760 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/itemGroupOpen.png0000644000175000001440000000156214634065603017754 0ustar00rncbcusersPNG  IHDRa9IDAT8˅hu_{vtSk#Z R !psXʒ fհIDm퇮nλ_mgw=L{o|t]/JIII]MM񦦦/W˫=JͧN/Y4m}mmGl6[FWF"a!Dv?q;*-4Y[z )7 m0?vtaWN}|Y#)6R -*Y5ճl%ףe?T5y@.y2,kEB! ⲏ.^fJ5q -^g/1Tl e7^-NyS1fNwھzL2lc=tjUr.IENDB`qsampler-1.0.0/src/images/PaxHeaders/formReject.png0000644000000000000000000000013214634065603017263 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/formReject.png0000644000175000001440000000033014634065603017247 0ustar00rncbcusersPNG  IHDRasRGBIDAT8RA +|?3gM 3U77u-[@<0X}&+^G-ةTEȟAG[v ,29kw';saE浶Dn7b rs>'`65IENDB`qsampler-1.0.0/src/images/PaxHeaders/formOpen.png0000644000000000000000000000013214634065603016750 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/formOpen.png0000644000175000001440000000105214634065603016736 0ustar00rncbcusersPNG  IHDRasBIT|d pHYsu85tEXtSoftwarewww.inkscape.org<IDAT8?AGW# M!8V%} I!)m *hw,bac"ץHHsn&wy/!3B]Pǀ π@~_0 ʴ 4X;'xK( ÀzmO$иjfH Qg+a&_H`a i jsBZ@A H ΐ^GhJ@aGr"~ͣs[fPXփYUHB~b&@T=T Rxȥ#8|ǩ M@[2UW$XU{k~*j+`i7ꃨ18rS g!.Cr_5~ \6;wѹ0ͤ> pS S^wPUŬb v&Dc9݁"b+ d|= U,d4;s-oJfIENDB`qsampler-1.0.0/src/images/PaxHeaders/itemNew.png0000644000000000000000000000013214634065603016573 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/itemNew.png0000644000175000001440000000100314634065603016555 0ustar00rncbcusersPNG  IHDRabKGD pHYs  tIME #!leIDATxڕOkA,{ZD؅,$D:G/U^H`5kY?Ib2I9{t]ΞkQ0nă,s0EM!7A(9u_fs_4_%P{bN|. +UJIŸ ?¯%#E蜇|k(j̿a 10E?IENDB`qsampler-1.0.0/src/images/PaxHeaders/editEditChannel.png0000644000000000000000000000013214634065603020207 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/editEditChannel.png0000644000175000001440000000064214634065603020201 0ustar00rncbcusersPNG  IHDRĴl;sRGBbKGD pHYs  tIME+ 4# "IDAT81J@"X V9I9MǘvsI=@oj 73{<_oR p| J0Fc]9Yھ$ɲ,)C[Z ߀ޜ ɫO}~0pʩ1ftND+;v(zfR@$9zGVDQW4|p۶UPJC< hkpwB Ir7*{[cL[SHDFῨWY;c IENDB`qsampler-1.0.0/src/images/PaxHeaders/fileNew.png0000644000000000000000000000013214634065603016554 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/fileNew.png0000644000175000001440000000031014634065603016536 0ustar00rncbcusersPNG  IHDRĴl;sRGBIDAT8풱 ˝PDԱu|=rN6<؉%F"8`IZ!IםFҮd @5| 9{IɗǸC{-qgcc<SbFֹҿ˓!6l@GBpIENDB`qsampler-1.0.0/src/images/PaxHeaders/displaybg1.png0000644000000000000000000000013214634065603017222 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/images/displaybg1.png0000644000175000001440000001762014634065603017220 0ustar00rncbcusersPNG  IHDR@@kWIDATx]]qpV䯰%_I!)$@] }興t"+*+ug8N ib ##H$@@uKM>*} 6n;z~P(^)Tf~ >[p |zCk=kH@^ ?t_?o?Oşg\^?y8c&)Hj$#O@ J&{%2oW2L~+=(Z7>#q}Ɨ{'c9 Ѝ!y o q΃z˃+j`P(>buKH<yfx:;_}3}"^_&Nn8pApAA>s0H F,`lSR֢ȸ/Ĕ }C҂pxm]l+iƃ "C1ȞVd}Tb?|BzY(ނ{f5khT[!ԁ`]?k=ELO>:J8b"%Fb2 \Lͮ5:\+ `,o)l4n:$yY!ƈi"ia "wq. cבK1Mt>{c&Dc"P1MYI?wK`NW=JRɚ=Kh,'{ W9n`y{+gi(e2S;`OOi{e?K<ж? DS62c蘀pžՙaHM>\?5rzyifb9`$sKy~̦ȔÀPIT"O˰g&ePIC=ƮdD:1dGZ!p3>%,u<`D˿e`\2LXH53K""!@+TLbC`סv%@_HWʸ`'x,K=숞[,;C d_Z 7 eM P(CLW\ovɕV%BgC#2;K OۮJq4#V'0܁1._ɔ&!*"a>urAMY$7,P9: bp|PuQ=[aa-hu6]]4ۻ8}5~%IJGp8w}YmH) 6H9uFdƒ]Kr#MpDݍ[Xic@ %W'JVR$}1xoqA:2@'&W .M'c9n*F5u%ISb4S Hf(.vtzRp8,}nD%“xo<Ϙir[F - h>@H/MDQ$@m(ۺ[bPjݫe!by2ͧl B:EzXwdqBJ1!zU,Aezٰy<}!9fsp?#p^n 8'`foj_i7aa Oe5~)Jbc6gJrl664Cua~{;Yfҫ;;ʫhM=7]̣[T/mi‡'*w ; ŴYL^ȞpT ]>Ǵs&g|,ieVHlj3͊10\<ٸ Cf_ lbzd:{0P+uݬIK׈y_W|u{HMZ=3FQ"@_zI Huktd55MeuPr`F\[pUx_2t`34XVck@ocS!:8a L\."_^t 8Dw}[qrҨX`~e*!&)V.ZYYVmJ-&hg՘s iQ+IA)-Y*K(5Gη県2֬]b-!j# `ju1se' yA)0>DHL7!P5zBd>-)c{rvbEw3sj|ZS\B~OHM>=&pCt[==OOq`C?@hF $V L t, &Wqժ7+\.3X0,>,q6n+1'h:QH_C`z?ח/o^8/zsEasLACRH>{eٌQ,k!uy!YB8i1#YQ͛8X,xLn2ƝP?Q;^P/= Zuu?c 21/ Ox~麄 YS%.QP*fD!n,S APYpfQ/h͙+n1&k3àÐNG`#} 5vͻ"i5/Os;f~è2r|{$>oW0θ\gp7GI=;DX,+XEBTj5+,EbadK ]aW`P]5swlji4m7IJ T̽PJ $8_ x{y˴$>y3ABtgVX~b, mpiK2@LUdyjQBijW ifg5m.v3)*X w9ֻ@ҟE+屰Yxh6-g YےItP/GIJW8@̓cϗ;]FS3@4ay^2IaH7P) 7ۑDgW%gUJ=:̵Fd7xVBSlz Xii{cOR舑) hv x>HK:,S3Ds8py59Wq0]'Dkca7]5T0,|_*YK2̆g@{Bb|;d.D%}Hx,Gz =+܋ްҺ`Ԡr0cy4;utE`ث% =/%1qZ +7(fL=25 LY>.P2@ .,=:;,z 0 p-| 4Jm{FNaxf`u&Huf\tְ}l |U1Uח[ YR XN4d(Pn.1: qfZX2;Q0V:68E[Zbby_ʎ\F_ivxa9+$wmI]"Q5V-Mx˅UF9O8ҕ!#wJs˳zݮ海7rt* 8aR48U~!FMENt@%6P3AdH-G\"3O W,T5Lnh,[D6 RZB+J9Vt>9nʢ}v/e8>&y Ig [ Kb\^(~OQ\K+ف0=%J T[i9(~~V&l9L "~ꅮi C:bXk;2x(DzH I;яG~TQGgճkHfPEВJ6dfQ4g{iϥzr)M:e7TyGeP7'ܽc7{w2e{Ƕ&AVy;]냴ՔxeoMQSԡi[Z&:t.sUu='7a588 EckW8^6B#ًAҾ,p #V5doܒT#EYg"bh /2gZiA0[ wv*Vt`Cs/z!]FGzvW~Y`s\*p^n4cD=(L !aBԺd6 ) 5v1STYefZ2)4:MjA!Ye[ߞ?י8<;`@88q/2qe}P S$/M"Ok~R2Kˬ) 5/1px3; M6вF'deѕǸȗAª/~0XJREY޶ $vVz9!\W,Qs珒KXJl5PA,U[!(zVy;wk3c;&Fa+&f-"!!i|^Gaoϼzb&2 Y[Xp✑Pj Dq@CtZna! >CO>@; oϧtk\"Mh=OXV{aaIuB.0cV]^p`uXJ^9ٍoT-XkW" j `[ )Bxw^X,Đ#h{ u^b0aѬyk[٣2VhT\Ŋ닝UF.za]1cy'hǗJٗؾ_!Ά屆 -1j"[?i"g+JgZV (PB-M]f,iLuf;#]ןMA zƖQ`gSd';uZ&%ߛf +.EvH Xxy461`'4H-m.לe|4t`m2-e6cOP-h>#Iƙ!1Qe}j+:ٷ5wR2u-JQ+cż#jgiyr954+Pa+3 z l Yΰj9SYkY &ДڭZC,io݄@IGl XPY9wC$6T\ai <;uLTAx@v*DˁJzk+k}/C`waTkzUǧ)[n0*c+"I)23MLE]%ˁ,1 m_tYbb8*{ciG[KfF%X6edo4As`v:wfp\V[Ga9d|F$t=`jy1wyQ'[ jeMfaJzP"e-IM`GwzZZEt}OY~G#~4 =j&Ycn2>bQߧC]Z (\bX>b"P?e-3jsx=X؜'Q -f~fw^G}vEf|v͑d\{lI9Tmy:e(81j$JZYDcD+k=֭&tjN횾N~FVX _9+$ah[BkHS"+]J[ŮR>ǖ)A[/&YI#lI<$3Ώ4Q@&-˓J iKr=P{l !{y[K̝pViSUI52@(r/ϣs2 f5!0 InrfjAgbJQr]CaQP,𳆢udяDc U dY xZa>/76*$փIcf>s;&ce_ۏa^n dhZbMAUqH2RBV[ڬ6.B{IENDB`qsampler-1.0.0/src/PaxHeaders/qsamplerChannelForm.h0000644000000000000000000000013214634065603017322 xustar0030 mtime=1718643587.392448566 30 atime=1718643587.392448566 30 ctime=1718643587.392448566 qsampler-1.0.0/src/qsamplerChannelForm.h0000644000175000001440000000532614634065603017320 0ustar00rncbcusers// qsamplerChannelForm.h // /**************************************************************************** Copyright (C) 2004-2020, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #ifndef __qsamplerChannelForm_h #define __qsamplerChannelForm_h #include "ui_qsamplerChannelForm.h" #include "qsamplerDevice.h" #include "qsamplerChannel.h" #include "qsamplerDeviceForm.h" #include namespace QSampler { //------------------------------------------------------------------------- // QSampler::Channelform -- Channel form interface. // class ChannelForm : public QDialog { Q_OBJECT public: ChannelForm(QWidget* pParent = nullptr); ~ChannelForm(); void setup(Channel* pChannel); void setupDevice(Device* pDevice, Device::DeviceType deviceTypeMode, const QString& sDriverName); void selectMidiDriverItem(const QString& sMidiDriver); void selectMidiDeviceItem(int iMidiItem); void selectAudioDriverItem(const QString& sAudioDriver); void selectAudioDeviceItem(int iAudioItem); protected slots: void accept(); void reject(); void openInstrumentFile(); void updateInstrumentName(); void selectMidiDriver(const QString& sMidiDriver); void selectMidiDevice(int iMidiItem); void setupMidiDevice(); void selectAudioDriver(const QString& sAudioDriver); void selectAudioDevice(int iAudioItem); void setupAudioDevice(); void updateDevices(); void optionsChanged(); void stabilizeForm(); void updateTableCellRenderers(); void updateTableCellRenderers( const QModelIndex& topLeft, const QModelIndex& bottomRight); private: Ui::qsamplerChannelForm m_ui; Channel* m_pChannel; int m_iDirtySetup; int m_iDirtyCount; QHash m_audioDevices; QHash m_midiDevices; DeviceForm* m_pDeviceForm; ChannelRoutingModel m_routingModel; ChannelRoutingDelegate m_routingDelegate; }; } // namespace QSampler #endif // __qsamplerChannelForm_h // end of qsamplerChannelForm.h qsampler-1.0.0/src/PaxHeaders/qsamplerInstrumentList.cpp0000644000000000000000000000013214634065603020465 xustar0030 mtime=1718643587.393448566 30 atime=1718643587.393448566 30 ctime=1718643587.393448566 qsampler-1.0.0/src/qsamplerInstrumentList.cpp0000644000175000001440000002502114634065603020455 0ustar00rncbcusers// qsamplerInstrumentList.cpp // /**************************************************************************** Copyright (C) 2003-2019, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *****************************************************************************/ #include "qsamplerAbout.h" #include "qsamplerInstrumentList.h" #include "qsamplerInstrument.h" #include "qsamplerOptions.h" #include "qsamplerMainForm.h" #include #include #include namespace QSampler { //------------------------------------------------------------------------- // QSampler::InstrumentListModel - data model for MIDI prog mappings // InstrumentListModel::InstrumentListModel ( QObject *pParent ) : QAbstractItemModel(pParent), m_iMidiMap(LSCP_MIDI_MAP_ALL) { // QAbstractItemModel::reset(); } InstrumentListModel::~InstrumentListModel (void) { clear(); } int InstrumentListModel::rowCount ( const QModelIndex& /*parent*/) const { int nrows = 0; if (m_iMidiMap == LSCP_MIDI_MAP_ALL) { InstrumentMap::const_iterator itMap = m_instruments.constBegin(); for ( ; itMap != m_instruments.constEnd(); ++itMap) nrows += (*itMap).size(); } else { InstrumentMap::const_iterator itMap = m_instruments.find(m_iMidiMap); if (itMap != m_instruments.constEnd()) nrows += (*itMap).size(); } return nrows; } int InstrumentListModel::columnCount ( const QModelIndex& /*parent*/) const { return 9; } QVariant InstrumentListModel::data ( const QModelIndex &index, int role ) const { if (!index.isValid()) return QVariant(); const Instrument *pInstr = static_cast (index.internalPointer()); if (pInstr && role == Qt::DisplayRole) { switch (index.column()) { case 0: return pInstr->name(); case 1: return QVariant::fromValue(pInstr->map()); case 2: return QVariant::fromValue(pInstr->bank()); case 3: return QVariant::fromValue(pInstr->prog() + 1); case 4: return pInstr->engineName(); case 5: return pInstr->instrumentFile(); case 6: return QVariant::fromValue(pInstr->instrumentNr()); case 7: return QString::number(pInstr->volume() * 100.0) + " %"; case 8: { switch (pInstr->loadMode()) { case 3: return tr("Persistent"); case 2: return tr("On Demand Hold"); case 1: return tr("On Demand"); } } default: break; } } return QVariant(); } QModelIndex InstrumentListModel::index ( int row, int col, const QModelIndex& /*parent*/ ) const { const Instrument *pInstr = nullptr; if (m_iMidiMap == LSCP_MIDI_MAP_ALL) { int nrows = 0; InstrumentMap::const_iterator itMap = m_instruments.constBegin(); for ( ; itMap != m_instruments.constEnd(); ++itMap) { const InstrumentList& list = *itMap; nrows += list.size(); if (row < nrows) { pInstr = list.at(row + list.size() - nrows); break; } } } else { // Resolve MIDI instrument map... InstrumentMap::const_iterator itMap = m_instruments.find(m_iMidiMap); if (itMap != m_instruments.constEnd()) { const InstrumentList& list = *itMap; if (row < list.size()) pInstr = list.at(row); } } if (pInstr) return createIndex(row, col, (void *) pInstr); else return QModelIndex(); } QModelIndex InstrumentListModel::parent ( const QModelIndex& /*child*/ ) const { return QModelIndex(); } QVariant InstrumentListModel::headerData ( int section, Qt::Orientation orientation, int role ) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case 0: return tr("Name"); case 1: return tr("Map"); case 2: return tr("Bank"); case 3: return tr("Prog"); case 4: return tr("Engine"); case 5: return tr("File"); case 6: return tr("Nr"); case 7: return tr("Vol"); case 8: return tr("Mode"); } } return QAbstractItemModel::headerData(section, orientation, role); } void InstrumentListModel::setMidiMap ( int iMidiMap ) { if (iMidiMap < 0) iMidiMap = LSCP_MIDI_MAP_ALL; m_iMidiMap = iMidiMap; } int InstrumentListModel::midiMap (void) const { return m_iMidiMap; } const Instrument *InstrumentListModel::addInstrument ( int iMap, int iBank, int iProg ) { // Check it there's already one instrument item // with the very same key (bank, program); // if yes, just remove it without prejudice... InstrumentList& list = m_instruments[iMap]; int i = 0; for ( ; i < list.size(); ++i) { const Instrument *pInstr = list.at(i); if (pInstr->bank() == iBank && pInstr->prog() == iProg) { delete pInstr; list.removeAt(i); break; } } // Resolve the appropriate place, we keep the list sorted that way... for (i = 0; i < list.size(); ++i) { const Instrument *pInstr = list.at(i); if (iBank < pInstr->bank() || (iBank == pInstr->bank() && iProg < pInstr->prog())) { break; } } Instrument *pInstr = new Instrument(iMap, iBank, iProg); if (pInstr->getInstrument()) { list.insert(i, pInstr); } else { delete pInstr; pInstr = nullptr; } return pInstr; } void InstrumentListModel::removeInstrument ( Instrument *pInstrument ) { const int iMap = pInstrument->map(); if (m_instruments.contains(iMap)) { InstrumentList& list = m_instruments[iMap]; for (int i = 0; i < list.size(); ++i) { if (pInstrument == list.at(i)) { delete pInstrument; list.removeAt(i); break; } } } } void InstrumentListModel::updateInstrument ( Instrument *pInstrument ) { pInstrument->getInstrument(); } // Reposition the instrument in the model (called when map/bank/prg changed) void InstrumentListModel::resortInstrument ( Instrument *pInstrument ) { const int iMap = pInstrument->map(); const int iBank = pInstrument->bank(); const int iProg = pInstrument->prog(); // Remove given instrument from its current list... removeInstrument(pInstrument); // Re-add the instrument... addInstrument(iMap, iBank, iProg); } void InstrumentListModel::refresh (void) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; if (pMainForm->client() == nullptr) return; QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); clear(); // Load the whole bunch of instrument items... lscp_midi_instrument_t *pInstrs = ::lscp_list_midi_instruments(pMainForm->client(), m_iMidiMap); for (int iInstr = 0; pInstrs && pInstrs[iInstr].map >= 0; ++iInstr) { const int iMap = pInstrs[iInstr].map; const int iBank = pInstrs[iInstr].bank; const int iProg = pInstrs[iInstr].prog; addInstrument(iMap, iBank, iProg); // Try to keep it snappy :) QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } QApplication::restoreOverrideCursor(); if (pInstrs == nullptr && ::lscp_client_get_errno(pMainForm->client())) { pMainForm->appendMessagesClient("lscp_list_midi_instruments"); pMainForm->appendMessagesError( tr("Could not get current list of MIDI instrument mappings.\n\nSorry.")); } } void InstrumentListModel::beginReset (void) { #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) QAbstractItemModel::beginResetModel(); #endif } void InstrumentListModel::endReset (void) { #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) QAbstractItemModel::endResetModel(); #else QAbstractItemModel::reset(); #endif } // Map clear. void InstrumentListModel::clear (void) { InstrumentMap::iterator itMap = m_instruments.begin(); for ( ; itMap != m_instruments.end(); ++itMap) { InstrumentList& list = itMap.value(); qDeleteAll(list); list.clear(); } m_instruments.clear(); } //------------------------------------------------------------------------- // QSampler::InstrumentListView - list view for MIDI prog mappings // // Constructor. InstrumentListView::InstrumentListView ( QWidget *pParent ) : QTreeView(pParent) { m_pListModel = new InstrumentListModel(this); QTreeView::setModel(m_pListModel); QTreeView::setRootIsDecorated(false); QTreeView::setUniformRowHeights(true); QTreeView::setAlternatingRowColors(true); QTreeView::setSelectionBehavior(QAbstractItemView::SelectRows); QTreeView::setSelectionMode(QAbstractItemView::SingleSelection); QTreeView::setItemsExpandable(false); QHeaderView *pHeader = QTreeView::header(); pHeader->setDefaultAlignment(Qt::AlignLeft); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) pHeader->setMovable(false); #endif pHeader->setStretchLastSection(true); pHeader->resizeSection(0, 120); // Name QTreeView::resizeColumnToContents(1); // Map QTreeView::resizeColumnToContents(2); // Bank QTreeView::resizeColumnToContents(3); // Prog QTreeView::resizeColumnToContents(4); // Engine pHeader->resizeSection(5, 240); // File QTreeView::resizeColumnToContents(6); // Nr pHeader->resizeSection(7, 60); // Vol } // Destructor. InstrumentListView::~InstrumentListView (void) { delete m_pListModel; } void InstrumentListView::setMidiMap ( int iMidiMap ) { m_pListModel->setMidiMap(iMidiMap); } int InstrumentListView::midiMap (void) const { return m_pListModel->midiMap(); } const Instrument *InstrumentListView::addInstrument ( int iMap, int iBank, int iProg ) { m_pListModel->beginReset(); const Instrument *pInstrument = m_pListModel->addInstrument(iMap, iBank, iProg); m_pListModel->endReset(); return pInstrument; } void InstrumentListView::removeInstrument ( Instrument *pInstrument ) { m_pListModel->beginReset(); m_pListModel->removeInstrument(pInstrument); m_pListModel->endReset(); } void InstrumentListView::updateInstrument ( Instrument *pInstrument ) { m_pListModel->beginReset(); m_pListModel->updateInstrument(pInstrument); m_pListModel->endReset(); } // Reposition the instrument in the model (called when map/bank/prg changed) void InstrumentListView::resortInstrument ( Instrument *pInstrument ) { m_pListModel->beginReset(); m_pListModel->resortInstrument(pInstrument); m_pListModel->endReset(); } // Refreshener. void InstrumentListView::refresh (void) { m_pListModel->beginReset(); m_pListModel->refresh(); m_pListModel->endReset(); } } // namespace QSampler // end of qsamplerInstrumentList.cpp qsampler-1.0.0/src/PaxHeaders/qsamplerInstrumentListForm.ui0000644000000000000000000000013214634065603021144 xustar0030 mtime=1718643587.393448566 30 atime=1718643587.393448566 30 ctime=1718643587.393448566 qsampler-1.0.0/src/qsamplerInstrumentListForm.ui0000644000175000001440000000660214634065603021140 0ustar00rncbcusers rncbc aka Rui Nuno Capela qsampler - A LinuxSampler Qt GUI Interface. Copyright (C) 2004-2020, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. qsamplerInstrumentListForm 0 0 720 340 Instruments :/images/qsamplerInstrument.png Qt::Horizontal TopToolBarArea false :/images/itemNew.png New &Instrument... New Ins :/images/formEdit.png &Edit... Edit Enter :/images/formRemove.png &Delete Delete Del :/images/formRefresh.png &Refresh Refresh F5 qsampler-1.0.0/src/PaxHeaders/qsamplerFxSendsModel.cpp0000644000000000000000000000013214634065603020014 xustar0030 mtime=1718643587.393448566 30 atime=1718643587.393448566 30 ctime=1718643587.393448566 qsampler-1.0.0/src/qsamplerFxSendsModel.cpp0000644000175000001440000001232614634065603020010 0ustar00rncbcusers// qsamplerFxSendList.cpp // /**************************************************************************** Copyright (C) 2010-2019, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2008, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *****************************************************************************/ #include "qsamplerAbout.h" #include "qsamplerFxSendsModel.h" #include "qsamplerFxSend.h" #include #include #include namespace QSampler { FxSendsModel::FxSendsModel ( int iChannelID, QObject* pParent ) : QAbstractListModel(pParent) { m_iChannelID = iChannelID; cleanRefresh(); } int FxSendsModel::rowCount ( const QModelIndex& /*parent*/ ) const { return m_fxSends.size(); } QVariant FxSendsModel::data ( const QModelIndex& index, int role ) const { if (!index.isValid()) return QVariant(); switch (role) { case Qt::DisplayRole: return m_fxSends[index.row()].name(); break; case Qt::ToolTipRole: if (m_fxSends[index.row()].deletion()) return QString( "Scheduled for deletion. Click on 'Apply' to actually " "destroy FX Send." ); return (m_fxSends[index.row()].isNew()) ? QString( "New FX send. Click on 'Apply' to actually " "perform creation." ) : QString("FX Send ID ") + QString::number(m_fxSends.at(index.row()).id()); break; case Qt::ForegroundRole: if (m_fxSends.at(index.row()).deletion()) return QBrush(Qt::red); if (m_fxSends.at(index.row()).isNew()) return QBrush(Qt::green); break; case Qt::DecorationRole: if (m_fxSends.at(index.row()).deletion()) return QIcon(":/images/formRemove.png"); if (m_fxSends.at(index.row()).isNew()) return QIcon(":/images/itemNew.png"); if (m_fxSends.at(index.row()).isModified()) return QIcon(":/images/formEdit.png"); return QIcon(":/images/itemFile.png"); case Qt::FontRole: { if (m_fxSends.at(index.row()).isModified()) { QFont font; font.setBold(true); return font; } break; } default: return QVariant(); } return QVariant(); } bool FxSendsModel::setData ( const QModelIndex& index, const QVariant& value, int /*role*/ ) { if (!index.isValid()) return false; m_fxSends[index.row()].setName(value.toString()); emit dataChanged(index, index); emit fxSendsDirtyChanged(true); return true; } QVariant FxSendsModel::headerData ( int section, Qt::Orientation /*orientation*/, int role ) const { if (role == Qt::DisplayRole && section == 0) return QString("FX Send Name"); else return QVariant(); } Qt::ItemFlags FxSendsModel::flags ( const QModelIndex& /*index*/) const { return Qt::ItemIsEditable | Qt::ItemIsEnabled; } FxSend *FxSendsModel::addFxSend (void) { #if CONFIG_FXSEND FxSend fxSend(m_iChannelID); fxSend.setName("New FX Send"); m_fxSends.push_back(fxSend); createIndex(m_fxSends.size() - 1, 0); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) QAbstractListModel::reset(); #else QAbstractListModel::beginResetModel(); QAbstractListModel::endResetModel(); #endif emit fxSendsDirtyChanged(true); return &m_fxSends.last(); #else return nullptr; #endif // CONFIG_FXSEND } FxSend *FxSendsModel::fxSend ( const QModelIndex& index ) { if (!index.isValid()) return nullptr; return &m_fxSends[index.row()]; } void FxSendsModel::removeFxSend ( const QModelIndex& index ) { FxSend *pFxSend = fxSend(index); if (!pFxSend) return; pFxSend->setDeletion(true); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) QAbstractListModel::reset(); #else QAbstractListModel::beginResetModel(); QAbstractListModel::endResetModel(); #endif emit fxSendsDirtyChanged(true); } void FxSendsModel::cleanRefresh (void) { m_fxSends.clear(); const QList& sends = FxSend::allFxSendsOfSamplerChannel(m_iChannelID); for (int i = 0; i < sends.size(); ++i) { const int iFxSendId = sends.at(i); FxSend fxSend(m_iChannelID, iFxSendId); fxSend.getFromSampler(); m_fxSends.push_back(fxSend); } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) QAbstractListModel::reset(); #else QAbstractListModel::beginResetModel(); QAbstractListModel::endResetModel(); #endif emit fxSendsDirtyChanged(false); } void FxSendsModel::onExternalModifiication ( const QModelIndex& index ) { if (!index.isValid()) return; emit dataChanged(index, index); emit fxSendsDirtyChanged(true); } void FxSendsModel::applyToSampler (void) { for (int i = 0; i < m_fxSends.size(); ++i) m_fxSends[i].applyToSampler(); // make a clean refresh // (throws out all FxSend objects marked for deletion) cleanRefresh(); } } // namespace QSampler // end of qsamplerFxSendList.cpp qsampler-1.0.0/src/PaxHeaders/palette0000644000000000000000000000013214634065603014571 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/palette/0000755000175000001440000000000014634065603014636 5ustar00rncbcusersqsampler-1.0.0/src/palette/PaxHeaders/KXStudio.conf0000644000000000000000000000013214634065603017227 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/palette/KXStudio.conf0000644000175000001440000000165514634065603017226 0ustar00rncbcusers[ColorThemes] KXStudio\AlternateBase=#0e0e0e, #0e0e0e, #0c0c0c KXStudio\Base=#070707, #070707, #060606 KXStudio\BrightText=#ffffff, #ffffff, #ffffff KXStudio\Button=#1c1c1c, #1c1c1c, #181818 KXStudio\ButtonText=#f0f0f0, #f0f0f0, #5a5a5a KXStudio\Dark=#818181, #818181, #818181 KXStudio\Highlight=#3c3c3c, #222222, #0e0e0e KXStudio\HighlightedText=#ffffff, #f0f0f0, #535353 KXStudio\Light=#bfbfbf, #bfbfbf, #bfbfbf KXStudio\Link=#6464e6, #6464e6, #22224a KXStudio\LinkVisited=#e664e6, #e664e6, #4a224a KXStudio\Mid=#5e5e5e, #5e5e5e, #5e5e5e KXStudio\Midlight=#9b9b9b, #9b9b9b, #9b9b9b KXStudio\NoRole=#000000, #000000, #000000 KXStudio\PlaceholderText=#000000, #000000, #000000 KXStudio\Shadow=#9b9b9b, #9b9b9b, #9b9b9b KXStudio\Text=#e6e6e6, #e6e6e6, #4a4a4a KXStudio\ToolTipBase=#040404, #040404, #040404 KXStudio\ToolTipText=#e6e6e6, #e6e6e6, #e6e6e6 KXStudio\Window=#111111, #111111, #0e0e0e KXStudio\WindowText=#f0f0f0, #f0f0f0, #535353 qsampler-1.0.0/src/palette/PaxHeaders/Wonton Soup.conf0000644000000000000000000000013214634065603017710 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/palette/Wonton Soup.conf0000644000175000001440000000202614634065603017700 0ustar00rncbcusers[ColorThemes] Wonton%20Soup\AlternateBase=#434750, #434750, #3b3e46 Wonton%20Soup\Base=#3c4048, #3c4048, #34383f Wonton%20Soup\BrightText=#ffffff, #ffffff, #ffffff Wonton%20Soup\Button=#525863, #525863, #484d57 Wonton%20Soup\ButtonText=#d2def0, #d2def0, #6f7682 Wonton%20Soup\Dark=#282b31, #282b31, #23262b Wonton%20Soup\Highlight=#78889c, #515a67, #40444d Wonton%20Soup\HighlightedText=#d1e1f4, #b6c1d0, #616872 Wonton%20Soup\Light=#5f6572, #5f6572, #565c68 Wonton%20Soup\Link=#9cd4ff, #9cd4ff, #526677 Wonton%20Soup\LinkVisited=#4080ff, #4080ff, #364c77 Wonton%20Soup\Mid=#3f444c, #3f444c, #383b43 Wonton%20Soup\Midlight=#545a65, #545a65, #4b515b Wonton%20Soup\NoRole=#000000, #000000, #000000 Wonton%20Soup\PlaceholderText=#000000, #000000, #000000 Wonton%20Soup\Shadow=#1d1f23, #1d1f23, #191b1e Wonton%20Soup\Text=#d2def0, #d2def0, #636973 Wonton%20Soup\ToolTipBase=#b6c1d0, #b6c1d0, #b6c1d0 Wonton%20Soup\ToolTipText=#2a2c30, #2a2c30, #2a2c30 Wonton%20Soup\Window=#494e58, #494e58, #40444d Wonton%20Soup\WindowText=#b6c1d0, #b6c1d0, #616872 qsampler-1.0.0/src/PaxHeaders/appdata0000644000000000000000000000013214634065603014545 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/appdata/0000755000175000001440000000000014634065603014612 5ustar00rncbcusersqsampler-1.0.0/src/appdata/PaxHeaders/org.rncbc.qsampler.desktop0000644000000000000000000000013214634065603021715 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/appdata/org.rncbc.qsampler.desktop0000644000175000001440000000110614634065603021703 0ustar00rncbcusers[Desktop Entry] Name=Qsampler Version=1.0 GenericName=LinuxSampler GUI GenericName[fr]=Interface graphique pour LinuxSampler Comment=Qsampler is a LinuxSampler Qt GUI Interface Comment[fr]=Qsampler est une interface graphique Qt pour LinuxSampler Exec=qsampler %f Icon=org.rncbc.qsampler Categories=Audio;AudioVideo;Midi;X-Alsa;X-Jack;Qt; MimeType=application/x-qsampler-session; Keywords=Audio;MIDI;ALSA;JACK;LinuxSampler;GigaSampler;SoundFont;Synthesizer;Sampler;GIG;SF2;SFZ;Qt; Terminal=false Type=Application StartupWMClass=qsampler X-Window-Icon=qsampler X-SuSE-translate=true qsampler-1.0.0/src/appdata/PaxHeaders/org.rncbc.qsampler.metainfo.xml0000644000000000000000000000013214634065603022645 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/appdata/org.rncbc.qsampler.metainfo.xml0000644000175000001440000000324714634065603022643 0ustar00rncbcusers org.rncbc.qsampler FSFAP GPL-2.0+ Qsampler A LinuxSampler Qt GUI interface

QSampler is a LinuxSampler GUI front-end application written in C++ around the Qt framework using Qt Designer. For the moment it just wraps the client interface of LinuxSampler Control Protocol (LSCP) (http\://www.linuxsampler.org).

https://qsampler.sourceforge.io/image/qsampler-screenshot1.png The main window showing the application in action org.rncbc.qsampler.desktop qsampler Audio MIDI ALSA JACK LinuxSampler GigaSampler SoundFont Synthesizer Sampler GIG SF2 SFZ Qt https://qsampler.sourceforge.io linuxsampler.org rncbc aka. Rui Nuno Capela rncbc@rncbc.org
qsampler-1.0.0/src/PaxHeaders/qsamplerOptions.cpp0000644000000000000000000000013214634065603017114 xustar0030 mtime=1718643587.394448566 30 atime=1718643587.394448566 30 ctime=1718643587.394448566 qsampler-1.0.0/src/qsamplerOptions.cpp0000644000175000001440000005137514634065603017117 0ustar00rncbcusers// qsamplerOptions.cpp // /**************************************************************************** Copyright (C) 2004-2024, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007,2008,2015 Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #include "qsamplerAbout.h" #include "qsamplerOptions.h" #include "qsamplerMainForm.h" #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) #include #include #if defined(Q_OS_WINDOWS) #include #endif #endif #include #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #include #endif namespace QSampler { //------------------------------------------------------------------------- // QSampler::Options - Prototype settings structure. // // Constructor. Options::Options (void) : m_settings(QSAMPLER_DOMAIN, QSAMPLER_TITLE) { loadOptions(); } // Default Destructor. Options::~Options (void) { saveOptions(); } // Explicit load method. void Options::loadOptions (void) { // Begin into general options group. m_settings.beginGroup("/Options"); // Load server options... m_settings.beginGroup("/Server"); sServerHost = m_settings.value("/ServerHost", "localhost").toString(); iServerPort = m_settings.value("/ServerPort", 8888).toInt(); #if defined(__APPLE__) // Toshi Nagata 20080105 // TODO: Should this be a configure option? iServerTimeout = m_settings.value("/ServerTimeout", 10000).toInt(); #else iServerTimeout = m_settings.value("/ServerTimeout", 1000).toInt(); #endif bServerStart = m_settings.value("/ServerStart", true).toBool(); #if defined(__APPLE__) sServerCmdLine = m_settings.value("/ServerCmdLine", "/usr/local/bin/linuxsampler").toString(); #else sServerCmdLine = m_settings.value("/ServerCmdLine", "linuxsampler").toString(); #endif iStartDelay = m_settings.value("/StartDelay", 3).toInt(); m_settings.endGroup(); // Load logging options... m_settings.beginGroup("/Logging"); bMessagesLog = m_settings.value("/MessagesLog", false).toBool(); sMessagesLogPath = m_settings.value("/MessagesLogPath", "qsampler.log").toString(); m_settings.endGroup(); // Load display options... m_settings.beginGroup("/Display"); sDisplayFont = m_settings.value("/DisplayFont").toString(); bDisplayEffect = m_settings.value("/DisplayEffect", true).toBool(); bAutoRefresh = m_settings.value("/AutoRefresh", true).toBool(); iAutoRefreshTime = m_settings.value("/AutoRefreshTime", 1000).toInt(); iMaxVolume = m_settings.value("/MaxVolume", 100).toInt(); sMessagesFont = m_settings.value("/MessagesFont").toString(); bMessagesLimit = m_settings.value("/MessagesLimit", true).toBool(); iMessagesLimitLines = m_settings.value("/MessagesLimitLines", 1000).toInt(); bConfirmRemove = m_settings.value("/ConfirmRemove", true).toBool(); bConfirmReset = m_settings.value("/ConfirmReset", true).toBool(); bConfirmRestart = m_settings.value("/ConfirmRestart", true).toBool(); bConfirmError = m_settings.value("/ConfirmError", true).toBool(); bKeepOnTop = m_settings.value("/KeepOnTop", true).toBool(); bStdoutCapture = m_settings.value("/StdoutCapture", true).toBool(); bCompletePath = m_settings.value("/CompletePath", true).toBool(); iMaxRecentFiles = m_settings.value("/MaxRecentFiles", 5).toInt(); iBaseFontSize = m_settings.value("/BaseFontSize", 0).toInt(); // if libgig provides a fast way to retrieve instrument names even for large // .gig files, then we enable this feature by default #ifdef CONFIG_LIBGIG_SETAUTOLOAD bInstrumentNames = m_settings.value("/InstrumentNames", true).toBool(); #else bInstrumentNames = m_settings.value("/InstrumentNames", false).toBool(); #endif m_settings.endGroup(); // Load custom options... m_settings.beginGroup("/Custom"); sCustomColorTheme = m_settings.value("/ColorTheme").toString(); sCustomStyleTheme = m_settings.value("/StyleTheme").toString(); m_settings.endGroup(); // And go into view options group. m_settings.beginGroup("/View"); bMenubar = m_settings.value("/Menubar", true).toBool(); bToolbar = m_settings.value("/Toolbar", true).toBool(); bStatusbar = m_settings.value("/Statusbar", true).toBool(); bAutoArrange = m_settings.value("/AutoArrange", true).toBool(); m_settings.endGroup(); m_settings.endGroup(); // Options group. // Recent file list. recentFiles.clear(); m_settings.beginGroup("/RecentFiles"); for (int iFile = 0; iFile < iMaxRecentFiles; iFile++) { QString sFilename = m_settings.value( "/File" + QString::number(iFile + 1)).toString(); if (!sFilename.isEmpty()) recentFiles.append(sFilename); } m_settings.endGroup(); // Sampler fine tuning settings. m_settings.beginGroup("/Tuning"); iMaxVoices = m_settings.value("/MaxVoices", -1).toInt(); iMaxStreams = m_settings.value("/MaxStreams", -1).toInt(); m_settings.endGroup(); // Last but not least, get the default directories. m_settings.beginGroup("/Default"); sSessionDir = m_settings.value("/SessionDir").toString(); sInstrumentDir = m_settings.value("/InstrumentDir").toString(); sEngineName = m_settings.value("/EngineName").toString(); sAudioDriver = m_settings.value("/AudioDriver").toString(); sMidiDriver = m_settings.value("/MidiDriver").toString(); iMidiMap = m_settings.value("/MidiMap", 0).toInt(); iMidiBank = m_settings.value("/MidiBank", 0).toInt(); iMidiProg = m_settings.value("/MidiProg", 0).toInt(); iVolume = m_settings.value("/Volume", 100).toInt(); iLoadMode = m_settings.value("/Loadmode", 0).toInt(); m_settings.endGroup(); } // Explicit save method. void Options::saveOptions (void) { // Make program version available in the future. m_settings.beginGroup("/Program"); m_settings.setValue("/Version", PROJECT_VERSION); m_settings.endGroup(); // And go into general options group. m_settings.beginGroup("/Options"); // Save server options. m_settings.beginGroup("/Server"); m_settings.setValue("/ServerHost", sServerHost); m_settings.setValue("/ServerPort", iServerPort); m_settings.setValue("/ServerTimeout", iServerTimeout); m_settings.setValue("/ServerStart", bServerStart); m_settings.setValue("/ServerCmdLine", sServerCmdLine); m_settings.setValue("/StartDelay", iStartDelay); m_settings.endGroup(); // Save logging options... m_settings.beginGroup("/Logging"); m_settings.setValue("/MessagesLog", bMessagesLog); m_settings.setValue("/MessagesLogPath", sMessagesLogPath); m_settings.endGroup(); // Save display options. m_settings.beginGroup("/Display"); m_settings.setValue("/DisplayFont", sDisplayFont); m_settings.setValue("/DisplayEffect", bDisplayEffect); m_settings.setValue("/AutoRefresh", bAutoRefresh); m_settings.setValue("/AutoRefreshTime", iAutoRefreshTime); m_settings.setValue("/MaxVolume", iMaxVolume); m_settings.setValue("/MessagesFont", sMessagesFont); m_settings.setValue("/MessagesLimit", bMessagesLimit); m_settings.setValue("/MessagesLimitLines", iMessagesLimitLines); m_settings.setValue("/ConfirmRemove", bConfirmRemove); m_settings.setValue("/ConfirmReset", bConfirmReset); m_settings.setValue("/ConfirmRestart", bConfirmRestart); m_settings.setValue("/ConfirmError", bConfirmError); m_settings.setValue("/KeepOnTop", bKeepOnTop); m_settings.setValue("/StdoutCapture", bStdoutCapture); m_settings.setValue("/CompletePath", bCompletePath); m_settings.setValue("/MaxRecentFiles", iMaxRecentFiles); m_settings.setValue("/BaseFontSize", iBaseFontSize); m_settings.setValue("/InstrumentNames", bInstrumentNames); m_settings.endGroup(); // Save custom options... m_settings.beginGroup("/Custom"); m_settings.setValue("/ColorTheme", sCustomColorTheme); m_settings.setValue("/StyleTheme", sCustomStyleTheme); m_settings.endGroup(); // View options group. m_settings.beginGroup("/View"); m_settings.setValue("/Menubar", bMenubar); m_settings.setValue("/Toolbar", bToolbar); m_settings.setValue("/Statusbar", bStatusbar); m_settings.setValue("/AutoArrange", bAutoArrange); m_settings.endGroup(); m_settings.endGroup(); // Options group. // Recent file list. int iFile = 0; m_settings.beginGroup("/RecentFiles"); QStringListIterator iter(recentFiles); while (iter.hasNext()) m_settings.setValue("/File" + QString::number(++iFile), iter.next()); m_settings.endGroup(); // Sampler fine tuning settings. m_settings.beginGroup("/Tuning"); if (iMaxVoices > 0) m_settings.setValue("/MaxVoices", iMaxVoices); if (iMaxStreams >= 0) m_settings.setValue("/MaxStreams", iMaxStreams); m_settings.endGroup(); // Default directories. m_settings.beginGroup("/Default"); m_settings.setValue("/SessionDir", sSessionDir); m_settings.setValue("/InstrumentDir", sInstrumentDir); m_settings.setValue("/EngineName", sEngineName); m_settings.setValue("/AudioDriver", sAudioDriver); m_settings.setValue("/MidiDriver", sMidiDriver); m_settings.setValue("/MidiMap", iMidiMap); m_settings.setValue("/MidiBank", iMidiBank); m_settings.setValue("/MidiProg", iMidiProg); m_settings.setValue("/Volume", iVolume); m_settings.setValue("/Loadmode", iLoadMode); m_settings.endGroup(); // Save/commit to disk. m_settings.sync(); } //------------------------------------------------------------------------- // Settings accessor. // QSettings& Options::settings (void) { return m_settings; } //------------------------------------------------------------------------- // Command-line argument stuff. // #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) void Options::show_error( const QString& msg ) { #if defined(Q_OS_WINDOWS) QMessageBox::information(nullptr, QApplication::applicationName(), msg); #else const QByteArray tmp = msg.toUtf8() + '\n'; ::fputs(tmp.constData(), stderr); #endif } #else // Help about command line options. void Options::print_usage ( const QString& arg0 ) { QTextStream out(stderr); const QString sEot = "\n\t"; const QString sEol = "\n\n"; out << QObject::tr("Usage: %1 [options] [session-file]").arg(arg0) + sEol; out << QSAMPLER_TITLE " - " + QObject::tr(QSAMPLER_SUBTITLE) + sEol; out << QObject::tr("Options:") + sEol; out << " -s, --start" + sEot + QObject::tr("Start linuxsampler server locally.") + sEol; out << " -n, --hostname" + sEot + QObject::tr("Specify linuxsampler server hostname (default = localhost)") + sEol; out << " -p, --port" + sEot + QObject::tr("Specify linuxsampler server port number (default = 8888)") + sEol; out << " -h, --help" + sEot + QObject::tr("Show help about command line options.") + sEol; out << " -v, --version" + sEot + QObject::tr("Show version information") + sEol; } #endif // Parse command line arguments into m_settings. bool Options::parse_args ( const QStringList& args ) { #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) QCommandLineParser parser; parser.setApplicationDescription( QSAMPLER_TITLE " - " + QObject::tr(QSAMPLER_SUBTITLE)); parser.addOption({{"s", "start"}, QObject::tr("Start linuxsampler server locally.")}); parser.addOption({{"n", "hostname"}, QObject::tr("Specify linuxsampler server hostname (default = localhost)"), "name"}); parser.addOption({{"p", "port"}, QObject::tr("Specify linuxsampler server port number (default = 8888)"), "num"}); parser.addHelpOption(); parser.addVersionOption(); parser.addPositionalArgument("session-file", QObject::tr("Session file (.lscp)"), QObject::tr("[session-file]")); parser.process(args); if (parser.isSet("start")) { bServerStart = true; } if (parser.isSet("hostname")) { const QString& sVal = parser.value("hostname"); if (sVal.isEmpty()) { show_error(QObject::tr("Option -n requires an argument (hostname).")); return false; } sServerHost = sVal; } if (parser.isSet("port")) { bool bOK = false; const int iVal = parser.value("port").toInt(&bOK); if (!bOK) { show_error(QObject::tr("Option -p requires an argument (port).")); return false; } iServerPort = iVal; } foreach (const QString& sArg, parser.positionalArguments()) { sessionFiles.append(QFileInfo(sArg).absoluteFilePath()); } #else int iCmdArgs = 0; QTextStream out(stderr); const QString sEol = "\n\n"; const int argc = args.count(); for (int i = 1; i < argc; ++i) { QString sArg = args.at(i); if (iCmdArgs > 0) { sessionFiles.append(QFileInfo(sArg).absoluteFilePath()); ++iCmdArgs; continue; } QString sVal; const int iEqual = sArg.indexOf("="); if (iEqual >= 0) { sVal = sArg.right(sArg.length() - iEqual - 1); sArg = sArg.left(iEqual); } else if (i < argc - 1) { sVal = args.at(i + 1); if (sVal[0] == '-') sVal.clear(); } if (sArg == "-s" || sArg == "--start") { bServerStart = true; } else if (sArg == "-n" || sArg == "--hostname") { if (sVal.isNull()) { out << QObject::tr("Option -n requires an argument (hostname).") + sEol; return false; } sServerHost = sVal; if (iEqual < 0) ++i; } else if (sArg == "-p" || sArg == "--port") { if (sVal.isNull()) { out << QObject::tr("Option -p requires an argument (port).") + sEol; return false; } iServerPort = sVal.toInt(); if (iEqual < 0) ++i; } else if (sArg == "-h" || sArg == "--help") { print_usage(args.at(0)); return false; } else if (sArg == "-v" || sArg == "--version") { out << QString("Qt: %1").arg(qVersion()); #if defined(QT_STATIC) out << "-static"; #endif out << '\n'; #ifdef CONFIG_LIBGIG out << QString("%1: %2\n") .arg(gig::libraryName().c_str()) .arg(gig::libraryVersion().c_str()); #endif out << QString("%1: %2\n") .arg(::lscp_client_package()) .arg(::lscp_client_version()); out << QString("%1: %2\n") .arg(QSAMPLER_TITLE) .arg(PROJECT_VERSION); return false; } else { // If we don't have one by now, // this will be the startup sesion file... sessionFiles.append(QFileInfo(sArg).absoluteFilePath()); ++iCmdArgs; } } #endif // Alright with argument parsing. return true; } //--------------------------------------------------------------------------- // Widget geometry persistence helper methods. void Options::loadWidgetGeometry ( QWidget *pWidget, bool bVisible ) { // Try to restore old form window positioning. if (pWidget) { // if (bVisible) pWidget->show(); -- force initial exposure? m_settings.beginGroup("/Geometry/" + pWidget->objectName()); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) const QByteArray& geometry = m_settings.value("/geometry").toByteArray(); if (geometry.isEmpty()) { QWidget *pParent = pWidget->parentWidget(); if (pParent) pParent = pParent->window(); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) if (pParent == nullptr) pParent = QApplication::desktop(); #endif if (pParent) { QRect wrect(pWidget->geometry()); wrect.moveCenter(pParent->geometry().center()); pWidget->move(wrect.topLeft()); } } else { pWidget->restoreGeometry(geometry); } #else//--LOAD_OLD_GEOMETRY QPoint wpos; QSize wsize; wpos.setX(m_settings.value("/x", -1).toInt()); wpos.setY(m_settings.value("/y", -1).toInt()); wsize.setWidth(m_settings.value("/width", -1).toInt()); wsize.setHeight(m_settings.value("/height", -1).toInt()); if (wpos.x() > 0 && wpos.y() > 0) pWidget->move(wpos); if (wsize.width() > 0 && wsize.height() > 0) pWidget->resize(wsize); #endif // else // pWidget->adjustSize(); if (!bVisible) bVisible = m_settings.value("/visible", false).toBool(); if (bVisible) pWidget->show(); else pWidget->hide(); m_settings.endGroup(); } } void Options::saveWidgetGeometry ( QWidget *pWidget, bool bVisible ) { // Try to save form window position... // (due to X11 window managers ideossincrasies, we better // only save the form geometry while its up and visible) if (pWidget) { m_settings.beginGroup("/Geometry/" + pWidget->objectName()); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) m_settings.setValue("/geometry", pWidget->saveGeometry()); #else//--SAVE_OLD_GEOMETRY const QPoint& wpos = pWidget->pos(); const QSize& wsize = pWidget->size(); m_settings.setValue("/x", wpos.x()); m_settings.setValue("/y", wpos.y()); m_settings.setValue("/width", wsize.width()); m_settings.setValue("/height", wsize.height()); #endif if (!bVisible) bVisible = pWidget->isVisible(); m_settings.setValue("/visible", bVisible); m_settings.endGroup(); } } //--------------------------------------------------------------------------- // Combo box history persistence helper implementation. void Options::loadComboBoxHistory ( QComboBox *pComboBox, int iLimit ) { const bool bBlockSignals = pComboBox->blockSignals(true); // Load combobox list from configuration settings file... m_settings.beginGroup("/History/" + pComboBox->objectName()); if (m_settings.childKeys().count() > 0) { pComboBox->setUpdatesEnabled(false); pComboBox->setDuplicatesEnabled(false); pComboBox->clear(); for (int i = 0; i < iLimit; ++i) { const QString& sText = m_settings.value( "/Item" + QString::number(i + 1)).toString(); if (sText.isEmpty()) break; pComboBox->addItem(sText); } pComboBox->setUpdatesEnabled(true); } m_settings.endGroup(); pComboBox->blockSignals(bBlockSignals); } void Options::saveComboBoxHistory ( QComboBox *pComboBox, int iLimit ) { const bool bBlockSignals = pComboBox->blockSignals(true); int iCount = pComboBox->count(); // Add current text as latest item (if not blank)... const QString& sCurrentText = pComboBox->currentText(); if (!sCurrentText.isEmpty()) { for (int i = 0; i < iCount; ++i) { const QString& sText = pComboBox->itemText(i); if (sText == sCurrentText) { pComboBox->removeItem(i); --iCount; break; } } pComboBox->insertItem(0, sCurrentText); pComboBox->setCurrentIndex(0); ++iCount; } while (iCount >= iLimit) pComboBox->removeItem(--iCount); // Save combobox list to configuration settings file... m_settings.beginGroup("/History/" + pComboBox->objectName()); for (int i = 0; i < iCount; ++i) { const QString& sText = pComboBox->itemText(i); if (sText.isEmpty()) break; m_settings.setValue("/Item" + QString::number(i + 1), sText); } m_settings.endGroup(); pComboBox->blockSignals(bBlockSignals); } int Options::getMaxVoices() { #ifndef CONFIG_MAX_VOICES return -1; #else if (iMaxVoices > 0) return iMaxVoices; return getEffectiveMaxVoices(); #endif // CONFIG_MAX_VOICES } int Options::getEffectiveMaxVoices() { #ifndef CONFIG_MAX_VOICES return -1; #else MainForm *pMainForm = MainForm::getInstance(); if (!pMainForm || !pMainForm->client()) return -1; return ::lscp_get_voices(pMainForm->client()); #endif // CONFIG_MAX_VOICES } void Options::setMaxVoices(int iMaxVoices) { #ifdef CONFIG_MAX_VOICES if (iMaxVoices < 1) return; MainForm *pMainForm = MainForm::getInstance(); if (!pMainForm || !pMainForm->client()) return; lscp_status_t result = ::lscp_set_voices(pMainForm->client(), iMaxVoices); if (result != LSCP_OK) { pMainForm->appendMessagesClient("lscp_set_voices"); return; } this->iMaxVoices = iMaxVoices; #endif // CONFIG_MAX_VOICES } int Options::getMaxStreams() { #ifndef CONFIG_MAX_VOICES return -1; #else if (iMaxStreams > 0) return iMaxStreams; return getEffectiveMaxStreams(); #endif // CONFIG_MAX_VOICES } int Options::getEffectiveMaxStreams() { #ifndef CONFIG_MAX_VOICES return -1; #else MainForm *pMainForm = MainForm::getInstance(); if (!pMainForm || !pMainForm->client()) return -1; return ::lscp_get_streams(pMainForm->client()); #endif // CONFIG_MAX_VOICES } void Options::setMaxStreams(int iMaxStreams) { #ifdef CONFIG_MAX_VOICES if (iMaxStreams < 0) return; MainForm *pMainForm = MainForm::getInstance(); if (!pMainForm || !pMainForm->client()) return; lscp_status_t result = ::lscp_set_streams(pMainForm->client(), iMaxStreams); if (result != LSCP_OK) { pMainForm->appendMessagesClient("lscp_set_streams"); return; } this->iMaxStreams = iMaxStreams; #endif // CONFIG_MAX_VOICES } void Options::sendFineTuningSettings() { setMaxVoices(iMaxVoices); setMaxStreams(iMaxStreams); MainForm *pMainForm = MainForm::getInstance(); if (!pMainForm || !pMainForm->client()) return; pMainForm->appendMessages(QObject::tr("Sent fine tuning settings.")); } } // namespace QSampler // end of qsamplerOptions.cpp qsampler-1.0.0/src/PaxHeaders/qsamplerInstrumentListForm.h0000644000000000000000000000013214634065603020756 xustar0030 mtime=1718643587.393448566 30 atime=1718643587.393448566 30 ctime=1718643587.393448566 qsampler-1.0.0/src/qsamplerInstrumentListForm.h0000644000175000001440000000417414634065603020754 0ustar00rncbcusers// qsamplerInstrumentListForm.h // /**************************************************************************** Copyright (C) 2003-2020, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *****************************************************************************/ #ifndef __qsamplerInstrumentListForm_h #define __qsamplerInstrumentListForm_h #include "ui_qsamplerInstrumentListForm.h" class QModelIndex; class QComboBox; namespace QSampler { class InstrumentListView; //------------------------------------------------------------------------- // QSampler::InstrumentListForm -- Instrument map list form interface. // class InstrumentListForm : public QMainWindow { Q_OBJECT public: InstrumentListForm(QWidget *pParent = nullptr, Qt::WindowFlags wflags = Qt::WindowFlags()); ~InstrumentListForm(); public slots: void newInstrument(); void editInstrument(); void editInstrument(const QModelIndex& index); void deleteInstrument(); void refreshInstruments(); void activateMap(int); void stabilizeForm(); protected: void showEvent(QShowEvent *); void hideEvent(QHideEvent *); void closeEvent(QCloseEvent *); void contextMenuEvent(QContextMenuEvent *); private: Ui::qsamplerInstrumentListForm m_ui; QComboBox *m_pMapComboBox; InstrumentListView *m_pInstrumentListView; }; } // namespace QSampler #endif // __qsamplerInstrumentListForm_h // end of qsamplerInstrumentListForm.h qsampler-1.0.0/src/PaxHeaders/qsamplerInstrument.cpp0000644000000000000000000000013214634065603017631 xustar0030 mtime=1718643587.393448566 30 atime=1718643587.393448566 30 ctime=1718643587.393448566 qsampler-1.0.0/src/qsamplerInstrument.cpp0000644000175000001440000001671214634065603017630 0ustar00rncbcusers// qsamplerInstrument.cpp // /**************************************************************************** Copyright (C) 2004-2019, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #include "qsamplerAbout.h" #include "qsamplerInstrument.h" #include "qsamplerUtilities.h" #include "qsamplerOptions.h" #include "qsamplerMainForm.h" namespace QSampler { //------------------------------------------------------------------------- // QSampler::Instrument - MIDI instrument map structure. // // Constructor. Instrument::Instrument ( int iMap, int iBank, int iProg ) { m_iMap = iMap; m_iBank = iBank; m_iProg = iProg; m_iInstrumentNr = 0; m_fVolume = 1.0f; m_iLoadMode = 0; } // Default destructor. Instrument::~Instrument (void) { } // Instrument accessors. void Instrument::setMap ( int iMap ) { m_iMap = iMap; } int Instrument::map (void) const { return m_iMap; } void Instrument::setBank ( int iBank ) { m_iBank = iBank; } int Instrument::bank (void) const { return m_iBank; } void Instrument::setProg ( int iProg ) { m_iProg = iProg; } int Instrument::prog (void) const { return m_iProg; } void Instrument::setName ( const QString& sName ) { m_sName = sName; } const QString& Instrument::name (void) const { return m_sName; } void Instrument::setEngineName ( const QString& sEngineName ) { m_sEngineName = sEngineName; } const QString& Instrument::engineName (void) const { return m_sEngineName; } void Instrument::setInstrumentFile ( const QString& sInstrumentFile ) { m_sInstrumentFile = sInstrumentFile; } const QString& Instrument::instrumentFile (void) const { return m_sInstrumentFile; } const QString& Instrument::instrumentName (void) const { return m_sInstrumentName; } void Instrument::setInstrumentNr ( int iInstrumentNr ) { m_iInstrumentNr = iInstrumentNr; } int Instrument::instrumentNr (void) const { return m_iInstrumentNr; } void Instrument::setVolume ( float fVolume ) { m_fVolume = fVolume; } float Instrument::volume (void) const { return m_fVolume; } void Instrument::setLoadMode ( int iLoadMode ) { m_iLoadMode = iLoadMode; } int Instrument::loadMode (void) const { return m_iLoadMode; } // Sync methods. bool Instrument::mapInstrument (void) { #ifdef CONFIG_MIDI_INSTRUMENT MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr) return false; if (m_iMap < 0 || m_iBank < 0 || m_iProg < 0) return false; lscp_midi_instrument_t instr; instr.map = m_iMap; instr.bank = (m_iBank & 0x0fff); instr.prog = (m_iProg & 0x7f); lscp_load_mode_t load_mode; switch (m_iLoadMode) { case 3: load_mode = LSCP_LOAD_PERSISTENT; break; case 2: load_mode = LSCP_LOAD_ON_DEMAND_HOLD; break; case 1: load_mode = LSCP_LOAD_ON_DEMAND; break; case 0: default: load_mode = LSCP_LOAD_DEFAULT; break; } if (::lscp_map_midi_instrument(pMainForm->client(), &instr, m_sEngineName.toUtf8().constData(), qsamplerUtilities::lscpEscapePath( m_sInstrumentFile).constData(), m_iInstrumentNr, m_fVolume, load_mode, m_sName.toUtf8().constData()) != LSCP_OK) { pMainForm->appendMessagesClient("lscp_map_midi_instrument"); return false; } return true; #else return false; #endif } bool Instrument::unmapInstrument (void) { #ifdef CONFIG_MIDI_INSTRUMENT if (m_iMap < 0 || m_iBank < 0 || m_iProg < 0) return false; MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr) return false; lscp_midi_instrument_t instr; instr.map = m_iMap; instr.bank = (m_iBank & 0x0fff); instr.prog = (m_iProg & 0x7f); if (::lscp_unmap_midi_instrument(pMainForm->client(), &instr) != LSCP_OK) { pMainForm->appendMessagesClient("lscp_unmap_midi_instrument"); return false; } return true; #else return false; #endif } bool Instrument::getInstrument (void) { #ifdef CONFIG_MIDI_INSTRUMENT if (m_iMap < 0 || m_iBank < 0 || m_iProg < 0) return false; MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr) return false; lscp_midi_instrument_t instr; instr.map = m_iMap; instr.bank = (m_iBank & 0x0fff); instr.prog = (m_iProg & 0x7f); lscp_midi_instrument_info_t *pInstrInfo = ::lscp_get_midi_instrument_info(pMainForm->client(), &instr); if (pInstrInfo == nullptr) { pMainForm->appendMessagesClient("lscp_get_midi_instrument_info"); return false; } m_sName = qsamplerUtilities::lscpEscapedTextToRaw(pInstrInfo->name); m_sEngineName = pInstrInfo->engine_name; m_sInstrumentName = qsamplerUtilities::lscpEscapedTextToRaw( pInstrInfo->instrument_name); m_sInstrumentFile = qsamplerUtilities::lscpEscapedPathToPosix( pInstrInfo->instrument_file); m_iInstrumentNr = pInstrInfo->instrument_nr; m_fVolume = pInstrInfo->volume; switch (pInstrInfo->load_mode) { case LSCP_LOAD_PERSISTENT: m_iLoadMode = 3; break; case LSCP_LOAD_ON_DEMAND_HOLD: m_iLoadMode = 2; break; case LSCP_LOAD_ON_DEMAND: m_iLoadMode = 1; break; case LSCP_LOAD_DEFAULT: default: m_iLoadMode = 0; break; } // Fix something. if (m_sName.isEmpty()) m_sName = m_sInstrumentName; return true; #else return false; #endif } // Instrument map name enumerator. QStringList Instrument::getMapNames (void) { QStringList maps; MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return maps; if (pMainForm->client() == nullptr) return maps; #ifdef CONFIG_MIDI_INSTRUMENT int *piMaps = ::lscp_list_midi_instrument_maps(pMainForm->client()); if (piMaps == nullptr) { if (::lscp_client_get_errno(pMainForm->client())) pMainForm->appendMessagesClient("lscp_list_midi_instruments"); } else { for (int iMap = 0; piMaps[iMap] >= 0; iMap++) { const QString& sMapName = getMapName(piMaps[iMap]); if (!sMapName.isEmpty()) maps.append(sMapName); } } #endif return maps; } // Instrument map name enumerator. QString Instrument::getMapName ( int iMidiMap ) { QString sMapName; MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return sMapName; if (pMainForm->client() == nullptr) return sMapName; #ifdef CONFIG_MIDI_INSTRUMENT const char *pszMapName = ::lscp_get_midi_instrument_map_name(pMainForm->client(), iMidiMap); if (pszMapName == nullptr) { pszMapName = " -"; if (::lscp_client_get_errno(pMainForm->client())) pMainForm->appendMessagesClient("lscp_get_midi_instrument_name"); } sMapName = QString("%1 - %2").arg(iMidiMap) .arg(qsamplerUtilities::lscpEscapedTextToRaw(pszMapName)); #endif return sMapName; } } // namespace QSampler // end of qsamplerInstrument.cpp qsampler-1.0.0/src/PaxHeaders/qsamplerChannelFxForm.h0000644000000000000000000000013214634065603017620 xustar0030 mtime=1718643587.392448566 30 atime=1718643587.392448566 30 ctime=1718643587.392448566 qsampler-1.0.0/src/qsamplerChannelFxForm.h0000644000175000001440000000374414634065603017620 0ustar00rncbcusers// qsamplerChannelFxForm.h // /**************************************************************************** Copyright (C) 2010-2021, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2008, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #ifndef __qsamplerChannelFxForm_h #define __qsamplerChannelFxForm_h #include "ui_qsamplerChannelFxForm.h" #include "qsamplerChannel.h" #include "qsamplerDevice.h" #include namespace QSampler { class ChannelFxForm : public QDialog { Q_OBJECT public: ChannelFxForm(Channel *pSamplerChannel, QWidget *pParent = nullptr); ~ChannelFxForm(); protected slots: void onFxSendSelection(const QModelIndex& index); void onButtonClicked(QAbstractButton* button); void onCreateFxSend(); void onDestroyFxSend(); void onDepthCtrlChanged(int iMidiCtrl); void onCurrentSendDepthChanged(int depthPercent); void onRoutingTableChanged(); void updateTableCellRenderers(); void updateTableCellRenderers(const QModelIndex& topLeft, const QModelIndex& bottomRight); private: Ui::qsamplerChannelFxForm m_ui; Channel* m_pSamplerChannel; //int m_SamplerChannelID; Device* m_pAudioDevice; }; } // namespace QSampler #endif // __qsamplerChannelFxForm_h // end of qsamplerChannelFxForm.h qsampler-1.0.0/src/PaxHeaders/qsamplerOptionsForm.h0000644000000000000000000000013214634065603017405 xustar0030 mtime=1718643587.394448566 30 atime=1718643587.394448566 30 ctime=1718643587.394448566 qsampler-1.0.0/src/qsamplerOptionsForm.h0000644000175000001440000000427314634065603017403 0ustar00rncbcusers// qsamplerOptionsForm.h // /**************************************************************************** Copyright (C) 2004-2022, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #ifndef __qsamplerOptionsForm_h #define __qsamplerOptionsForm_h #include "ui_qsamplerOptionsForm.h" #include "qsamplerOptions.h" namespace QSampler { //------------------------------------------------------------------------- // QSampler::OptionsForm -- Options form interface. // class OptionsForm : public QDialog { Q_OBJECT public: OptionsForm(QWidget *pParent = nullptr); ~OptionsForm(); void setup(Options* pOptions); protected slots: void accept(); void reject(); void optionsChanged(); void browseMessagesLogPath(); void chooseDisplayFont(); void chooseMessagesFont(); void toggleDisplayEffect(bool bOn); void editCustomColorThemes(); void maxVoicesChanged(int iMaxVoices); void maxStreamsChanged(int iMaxStreams); protected: // Custom color/style themes settlers. void resetCustomColorThemes(const QString& sCustomColorTheme); void resetCustomStyleThemes(const QString& sCustomStyleTheme); void stabilizeForm(); private: Ui::qsamplerOptionsForm m_ui; Options* m_pOptions; int m_iDirtySetup; int m_iDirtyCount; bool bMaxVoicesModified; bool bMaxStreamsModified; }; } // namespace QSampler #endif // __qsamplerOptionsForm_h // end of qsamplerOptionsForm.h qsampler-1.0.0/src/PaxHeaders/qsamplerDevice.h0000644000000000000000000000013214634065603016325 xustar0030 mtime=1718643587.393448566 30 atime=1718643587.393448566 30 ctime=1718643587.393448566 qsampler-1.0.0/src/qsamplerDevice.h0000644000175000001440000002207014634065603016316 0ustar00rncbcusers// qsamplerDevice.h // /**************************************************************************** Copyright (C) 2004-2020, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, 2008 Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #ifndef __qsamplerDevice_h #define __qsamplerDevice_h #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "qsamplerOptions.h" namespace QSampler { class DevicePort; // Special QListViewItem::rtti() unique return value. #define QSAMPLER_DEVICE_ITEM 1001 //------------------------------------------------------------------------- // QSampler::DeviceParam - MIDI/Audio Device parameter structure. // class DeviceParam { public: // Constructor. DeviceParam(lscp_param_info_t *pParamInfo = nullptr, const char *pszValue = nullptr); // Initializer. void setParam(lscp_param_info_t *pParamInfo, const char *pszValue = nullptr); // Info structure field members. lscp_type_t type; QString description; bool mandatory; bool fix; bool multiplicity; QStringList depends; QString defaultv; QString range_min; QString range_max; QStringList possibilities; // The current parameter value. QString value; }; // Typedef'd parameter QMap. typedef QMap DeviceParamMap; // Typedef'd device port/channels QList. typedef QList DevicePortList; //------------------------------------------------------------------------- // QSampler::Device - MIDI/Audio Device structure. // class Device { public: // We use the same class for MIDI and audio device management enum DeviceType { None, Midi, Audio }; // Constructor. Device(DeviceType deviceType, int iDeviceID = -1); // Copy constructor. Device(const Device& device); // Default destructor. ~Device(); // Initializer. void setDevice(DeviceType deviceType, int iDeviceID = -1); // Driver name initializer. void setDriver(const QString& sDriverName); // Device property accessors. int deviceID() const; DeviceType deviceType() const; const QString& deviceTypeName() const; const QString& driverName() const; // Special device name formatter. QString deviceName() const; // Set the proper device parameter value. bool setParam (const QString& sParam, const QString& sValue); // Device parameters accessor. const DeviceParamMap& params() const; // Device port/channel list accessor. DevicePortList& ports(); // Device parameter dependency list refreshner. int refreshParams(); // Device port/channel list refreshner. int refreshPorts(); // Refresh/set dependencies given that some parameter has changed. int refreshDepends(const QString& sParam); // Create/destroy device methods. bool createDevice(); bool deleteDevice(); // Message logging methods (brainlessly mapped to main form's). void appendMessages (const QString& s) const; void appendMessagesColor (const QString& s, const QColor& rgb) const; void appendMessagesText (const QString& s) const; void appendMessagesError (const QString& s) const; void appendMessagesClient (const QString& s) const; // Device ids enumerator. static int *getDevices(lscp_client_t *pClient, DeviceType deviceType); static std::set getDeviceIDs(lscp_client_t *pClient, DeviceType deviceType); // Driver names enumerator. static QStringList getDrivers(lscp_client_t *pClient, DeviceType deviceType); private: // Refresh/set given parameter based on driver supplied dependencies. int refreshParam(const QString& sParam); // Instance variables. int m_iDeviceID; DeviceType m_deviceType; QString m_sDeviceType; QString m_sDriverName; QString m_sDeviceName; // Device parameter list. DeviceParamMap m_params; // Device port/channel list. DevicePortList m_ports; }; //------------------------------------------------------------------------- // QSampler::DevicePort - MIDI/Audio Device port/channel structure. // class DevicePort { public: // Constructor. DevicePort(Device& device, int iPortID); // Default destructor. ~DevicePort(); // Initializer. void setDevicePort(int iPortID); // Device port property accessors. int portID() const; const QString& portName() const; // Device port parameters accessor. const DeviceParamMap& params() const; // Set the proper device port/channel parameter value. bool setParam (const QString& sParam, const QString& sValue); private: // Device reference. Device& m_device; // Instance variables. int m_iPortID; QString m_sPortName; // Device port parameter list. DeviceParamMap m_params; }; //------------------------------------------------------------------------- // QSampler::DeviceItem - QTreeWidget device item. // class DeviceItem : public QTreeWidgetItem { public: // Constructors. DeviceItem(QTreeWidget *pTreeWidget, Device::DeviceType deviceType); DeviceItem(QTreeWidgetItem *pItem, Device::DeviceType deviceType, int iDeviceID); // Default destructor. ~DeviceItem(); // Instance accessors. Device& device(); private: // Instance variables. Device m_device; }; struct DeviceParameterRow { QString name; DeviceParam param; bool alive; // whether these params refer to an existing device // or for a device that is yet to be created }; //------------------------------------------------------------------------- // QSampler::AbstractDeviceParamModel - data model base class for device parameters // class AbstractDeviceParamModel : public QAbstractTableModel { Q_OBJECT public: AbstractDeviceParamModel(QObject *pParent = nullptr); // Overridden methods from subclass(es) int rowCount(const QModelIndex& parent = QModelIndex()) const; int columnCount(const QModelIndex& parent = QModelIndex() ) const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; Qt::ItemFlags flags(const QModelIndex& index) const; virtual void clear(); void refresh(const DeviceParamMap* params, bool bEditable); protected: const DeviceParamMap *m_pParams; bool m_bEditable; }; //------------------------------------------------------------------------- // QSampler::DeviceParamModel - data model for device parameters // (used for QTableView) class DeviceParamModel : public AbstractDeviceParamModel { Q_OBJECT public: DeviceParamModel(QObject *pParent = nullptr); // Overridden methods from subclass(es) QVariant data(const QModelIndex &index, int role) const; bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole); void clear(); public slots: void refresh(Device* pDevice, bool bEditable); private: Device *m_pDevice; }; //------------------------------------------------------------------------- // QSampler::PortParamModel - data model for port parameters // (used for QTableView) class PortParamModel : public AbstractDeviceParamModel { Q_OBJECT public: PortParamModel(QObject *pParent = 0); // overridden methods from subclass(es) QVariant data(const QModelIndex &index, int role) const; bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole); void clear(); public slots: void refresh(DevicePort* pPort, bool bEditable); private: DevicePort* m_pPort; }; //------------------------------------------------------------------------- // QSampler::DeviceParamDelegate - table cell renderer for device/port parameters // class DeviceParamDelegate : public QItemDelegate { Q_OBJECT public: DeviceParamDelegate(QObject *pParent = nullptr); QWidget* createEditor(QWidget *pParent, const QStyleOptionViewItem& option, const QModelIndex& index) const; void setEditorData(QWidget *pEditor, const QModelIndex& index) const; void setModelData(QWidget *pEditor, QAbstractItemModel *pModel, const QModelIndex& index) const; void updateEditorGeometry(QWidget* pEditor, const QStyleOptionViewItem& option, const QModelIndex& index) const; }; } // namespace QSampler // so we can use it i.e. through QVariant Q_DECLARE_METATYPE(QSampler::DeviceParameterRow) #endif // __qsamplerDevice_h // end of qsamplerDevice.h qsampler-1.0.0/src/PaxHeaders/qsamplerChannel.cpp0000644000000000000000000000013214634065603017031 xustar0030 mtime=1718643587.392448566 30 atime=1718643587.391448566 30 ctime=1718643587.392448566 qsampler-1.0.0/src/qsamplerChannel.cpp0000644000175000001440000007150414634065603017030 0ustar00rncbcusers// qsamplerChannel.cpp // /**************************************************************************** Copyright (C) 2004-2023, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, 2008 Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #include "qsamplerAbout.h" #include "qsamplerChannel.h" #include "qsamplerUtilities.h" #include "qsamplerMainForm.h" #include "qsamplerChannelForm.h" #include #include #ifdef CONFIG_LIBGIG #if defined(Q_CC_GNU) || defined(Q_CC_MINGW) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif #include "gig.h" #ifdef CONFIG_LIBGIG_SF2 #pragma GCC diagnostic ignored "-Wunused-variable" #include "SF.h" #endif #if defined(Q_CC_GNU) || defined(Q_CC_MINGW) #pragma GCC diagnostic pop #endif #endif namespace QSampler { #define QSAMPLER_INSTRUMENT_MAX 128 #define UNICODE_RIGHT_ARROW QChar(char(0x92), char(0x21)) //------------------------------------------------------------------------- // QSampler::Channel - Sampler channel structure. // // Constructor. Channel::Channel ( int iChannelID ) { m_iChannelID = iChannelID; // m_sEngineName = noEngineName(); // m_sInstrumentName = noInstrumentName(); // m_sInstrumentFile = m_sInstrumentName; m_iInstrumentNr = -1; m_iInstrumentStatus = -1; m_sMidiDriver = "ALSA"; m_iMidiDevice = -1; m_iMidiPort = -1; m_iMidiChannel = -1; m_iMidiMap = -1; m_sAudioDriver = "ALSA"; m_iAudioDevice = -1; m_fVolume = 0.0f; m_bMute = false; m_bSolo = false; } // Default destructor. Channel::~Channel (void) { } // Create a new sampler channel, if not already. bool Channel::addChannel (void) { MainForm* pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr) return false; // Are we a new channel? if (m_iChannelID < 0) { m_iChannelID = ::lscp_add_channel(pMainForm->client()); if (m_iChannelID < 0) { appendMessagesClient("lscp_add_channel"); appendMessagesError( QObject::tr("Could not add channel.\n\nSorry.")); } // Otherwise it's created... else appendMessages(QObject::tr("added.")); } // Return whether we're a valid channel... return (m_iChannelID >= 0); } // Remove sampler channel. bool Channel::removeChannel (void) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr) return false; // Are we an existing channel? if (m_iChannelID >= 0) { if (::lscp_remove_channel(pMainForm->client(), m_iChannelID) != LSCP_OK) { appendMessagesClient("lscp_remove_channel"); appendMessagesError(QObject::tr("Could not remove channel.\n\nSorry.")); } else { // Otherwise it's removed. appendMessages(QObject::tr("removed.")); m_iChannelID = -1; } } // Return whether we've removed the channel... return (m_iChannelID < 0); } // Channel-ID (aka Sammpler-Channel) accessors. int Channel::channelID (void) const { return m_iChannelID; } void Channel::setChannelID ( int iChannelID ) { m_iChannelID = iChannelID; } // Readable channel name. QString Channel::channelName (void) const { return (m_iChannelID < 0 ? QObject::tr("New Channel") : QObject::tr("Channel %1").arg(m_iChannelID)); } // Engine name accessors. const QString& Channel::engineName (void) const { return m_sEngineName; } bool Channel::loadEngine ( const QString& sEngineName ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr || m_iChannelID < 0) return false; if (m_iInstrumentStatus == 100 && m_sEngineName == sEngineName) return true; if (::lscp_load_engine(pMainForm->client(), sEngineName.toUtf8().constData(), m_iChannelID) != LSCP_OK) { appendMessagesClient("lscp_load_engine"); return false; } appendMessages(QObject::tr("Engine: %1.").arg(sEngineName)); m_sEngineName = sEngineName; return true; } // Instrument filename accessor. const QString& Channel::instrumentFile (void) const { return m_sInstrumentFile; } // Instrument index accessor. int Channel::instrumentNr (void) const { return m_iInstrumentNr; } // Instrument name accessor. const QString& Channel::instrumentName (void) const { return m_sInstrumentName; } // Instrument status accessor. int Channel::instrumentStatus (void) const { return m_iInstrumentStatus; } // Instrument file loader. bool Channel::loadInstrument ( const QString& sInstrumentFile, int iInstrumentNr ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr || m_iChannelID < 0) return false; if (!QFileInfo(sInstrumentFile).exists()) return false; if (m_iInstrumentStatus == 100 && m_sInstrumentFile == sInstrumentFile && m_iInstrumentNr == iInstrumentNr) return true; if (::lscp_load_instrument_non_modal( pMainForm->client(), qsamplerUtilities::lscpEscapePath( sInstrumentFile).constData(), iInstrumentNr, m_iChannelID ) != LSCP_OK) { appendMessagesClient("lscp_load_instrument"); return false; } appendMessages(QObject::tr("Instrument: \"%1\" (%2).") .arg(sInstrumentFile).arg(iInstrumentNr)); return setInstrument(sInstrumentFile, iInstrumentNr); } // Special instrument file/name/number settler. bool Channel::setInstrument ( const QString& sInstrumentFile, int iInstrumentNr ) { m_sInstrumentFile = sInstrumentFile; m_iInstrumentNr = iInstrumentNr; #ifdef CONFIG_INSTRUMENT_NAME m_sInstrumentName.clear(); // We'll get it, maybe later, on channel_info... #else m_sInstrumentName = getInstrumentName(sInstrumentFile, iInstrumentNr, true); #endif m_iInstrumentStatus = 0; return true; } // MIDI driver type accessors (DEPRECATED). const QString& Channel::midiDriver (void) const { return m_sMidiDriver; } bool Channel::setMidiDriver ( const QString& sMidiDriver ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr || m_iChannelID < 0) return false; if (m_iInstrumentStatus == 100 && m_sMidiDriver == sMidiDriver) return true; if (::lscp_set_channel_midi_type(pMainForm->client(), m_iChannelID, sMidiDriver.toUtf8().constData()) != LSCP_OK) { appendMessagesClient("lscp_set_channel_midi_type"); return false; } appendMessages(QObject::tr("MIDI driver: %1.").arg(sMidiDriver)); m_sMidiDriver = sMidiDriver; return true; } // MIDI device accessors. int Channel::midiDevice (void) const { return m_iMidiDevice; } bool Channel::setMidiDevice ( int iMidiDevice ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr || m_iChannelID < 0) return false; if (m_iInstrumentStatus == 100 && m_iMidiDevice == iMidiDevice) return true; if (::lscp_set_channel_midi_device(pMainForm->client(), m_iChannelID, iMidiDevice) != LSCP_OK) { appendMessagesClient("lscp_set_channel_midi_device"); return false; } appendMessages(QObject::tr("MIDI device: %1.").arg(iMidiDevice)); m_iMidiDevice = iMidiDevice; return true; } // MIDI port number accessor. int Channel::midiPort (void) const { return m_iMidiPort; } bool Channel::setMidiPort ( int iMidiPort ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr || m_iChannelID < 0) return false; if (m_iInstrumentStatus == 100 && m_iMidiPort == iMidiPort) return true; if (::lscp_set_channel_midi_port(pMainForm->client(), m_iChannelID, iMidiPort) != LSCP_OK) { appendMessagesClient("lscp_set_channel_midi_port"); return false; } appendMessages(QObject::tr("MIDI port: %1.").arg(iMidiPort)); m_iMidiPort = iMidiPort; return true; } // MIDI channel accessor. int Channel::midiChannel (void) const { return m_iMidiChannel; } bool Channel::setMidiChannel ( int iMidiChannel ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr || m_iChannelID < 0) return false; if (m_iInstrumentStatus == 100 && m_iMidiChannel == iMidiChannel) return true; if (::lscp_set_channel_midi_channel(pMainForm->client(), m_iChannelID, iMidiChannel) != LSCP_OK) { appendMessagesClient("lscp_set_channel_midi_channel"); return false; } appendMessages(QObject::tr("MIDI channel: %1.").arg(iMidiChannel)); m_iMidiChannel = iMidiChannel; return true; } // MIDI instrument map accessor. int Channel::midiMap (void) const { return m_iMidiMap; } bool Channel::setMidiMap ( int iMidiMap ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr || m_iChannelID < 0) return false; if (m_iInstrumentStatus == 100 && m_iMidiMap == iMidiMap) return true; #ifdef CONFIG_MIDI_INSTRUMENT if (::lscp_set_channel_midi_map(pMainForm->client(), m_iChannelID, iMidiMap) != LSCP_OK) { appendMessagesClient("lscp_set_channel_midi_map"); return false; } #endif appendMessages(QObject::tr("MIDI map: %1.").arg(iMidiMap)); m_iMidiMap = iMidiMap; return true; } // Audio device accessor. int Channel::audioDevice (void) const { return m_iAudioDevice; } bool Channel::setAudioDevice ( int iAudioDevice ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr || m_iChannelID < 0) return false; if (m_iInstrumentStatus == 100 && m_iAudioDevice == iAudioDevice) return true; if (::lscp_set_channel_audio_device(pMainForm->client(), m_iChannelID, iAudioDevice) != LSCP_OK) { appendMessagesClient("lscp_set_channel_audio_device"); return false; } appendMessages(QObject::tr("Audio device: %1.").arg(iAudioDevice)); m_iAudioDevice = iAudioDevice; return true; } // Audio driver type accessors (DEPRECATED). const QString& Channel::audioDriver (void) const { return m_sAudioDriver; } bool Channel::setAudioDriver ( const QString& sAudioDriver ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr || m_iChannelID < 0) return false; if (m_iInstrumentStatus == 100 && m_sAudioDriver == sAudioDriver) return true; if (::lscp_set_channel_audio_type(pMainForm->client(), m_iChannelID, sAudioDriver.toUtf8().constData()) != LSCP_OK) { appendMessagesClient("lscp_set_channel_audio_type"); return false; } appendMessages(QObject::tr("Audio driver: %1.").arg(sAudioDriver)); m_sAudioDriver = sAudioDriver; return true; } // Channel volume accessors. float Channel::volume (void) const { return m_fVolume; } bool Channel::setVolume ( float fVolume ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr || m_iChannelID < 0) return false; if (m_iInstrumentStatus == 100 && m_fVolume == fVolume) return true; if (::lscp_set_channel_volume(pMainForm->client(), m_iChannelID, fVolume) != LSCP_OK) { appendMessagesClient("lscp_set_channel_volume"); return false; } appendMessages(QObject::tr("Volume: %1.").arg(fVolume)); m_fVolume = fVolume; return true; } // Sampler channel mute state. bool Channel::channelMute (void) const { return m_bMute; } bool Channel::setChannelMute ( bool bMute ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr || m_iChannelID < 0) return false; if (m_iInstrumentStatus == 100 && ((m_bMute && bMute) || (!m_bMute && !bMute))) return true; #ifdef CONFIG_MUTE_SOLO if (::lscp_set_channel_mute(pMainForm->client(), m_iChannelID, bMute) != LSCP_OK) { appendMessagesClient("lscp_set_channel_mute"); return false; } appendMessages(QObject::tr("Mute: %1.").arg((int) bMute)); m_bMute = bMute; return true; #else return false; #endif } // Sampler channel solo state. bool Channel::channelSolo (void) const { return m_bSolo; } bool Channel::setChannelSolo ( bool bSolo ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr || m_iChannelID < 0) return false; if (m_iInstrumentStatus == 100 && ((m_bSolo && bSolo) || (!m_bSolo && !bSolo))) return true; #ifdef CONFIG_MUTE_SOLO if (::lscp_set_channel_solo(pMainForm->client(), m_iChannelID, bSolo) != LSCP_OK) { appendMessagesClient("lscp_set_channel_solo"); return false; } appendMessages(QObject::tr("Solo: %1.").arg((int) bSolo)); m_bSolo = bSolo; return true; #else return false; #endif } // Audio routing accessors. int Channel::audioChannel ( int iAudioOut ) const { return m_audioRouting[iAudioOut]; } bool Channel::setAudioChannel ( int iAudioOut, int iAudioIn ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr || m_iChannelID < 0) return false; if (m_iInstrumentStatus == 100 && m_audioRouting[iAudioOut] == iAudioIn) return true; if (::lscp_set_channel_audio_channel(pMainForm->client(), m_iChannelID, iAudioOut, iAudioIn) != LSCP_OK) { appendMessagesClient("lscp_set_channel_audio_channel"); return false; } appendMessages(QObject::tr("Audio Channel: %1 -> %2.") .arg(iAudioOut).arg(iAudioIn)); m_audioRouting[iAudioOut] = iAudioIn; return true; } // The audio routing map itself. const ChannelRoutingMap& Channel::audioRouting (void) const { return m_audioRouting; } // Istrument name remapper. void Channel::updateInstrumentName (void) { #ifndef CONFIG_INSTRUMENT_NAME Options *pOptions = nullptr; MainForm *pMainForm = MainForm::getInstance(); if (pMainForm) pOptions = pMainForm->options(); m_sInstrumentName = getInstrumentName(m_sInstrumentFile, m_iInstrumentNr, (pOptions && pOptions->bInstrumentNames)); #endif } // Update whole channel info state. bool Channel::updateChannelInfo (void) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr || m_iChannelID < 0) return false; // Read channel information. lscp_channel_info_t *pChannelInfo = ::lscp_get_channel_info(pMainForm->client(), m_iChannelID); if (pChannelInfo == nullptr) { appendMessagesClient("lscp_get_channel_info"); appendMessagesError(QObject::tr("Could not get channel information.\n\nSorry.")); return false; } #ifdef CONFIG_INSTRUMENT_NAME // We got all actual instrument datum... m_sInstrumentFile = qsamplerUtilities::lscpEscapedPathToPosix(pChannelInfo->instrument_file); m_iInstrumentNr = pChannelInfo->instrument_nr; m_sInstrumentName = qsamplerUtilities::lscpEscapedTextToRaw(pChannelInfo->instrument_name); #else // First, check if intrument name has changed, // taking care that instrument name lookup might be expensive, // so we better make it only once and when really needed... if ((m_sInstrumentFile != pChannelInfo->instrument_file) || (m_iInstrumentNr != pChannelInfo->instrument_nr)) { m_sInstrumentFile = pChannelInfo->instrument_file; m_iInstrumentNr = pChannelInfo->instrument_nr; updateInstrumentName(); } #endif // Cache in other channel information. m_sEngineName = pChannelInfo->engine_name; m_iInstrumentStatus = pChannelInfo->instrument_status; m_iMidiDevice = pChannelInfo->midi_device; m_iMidiPort = pChannelInfo->midi_port; m_iMidiChannel = pChannelInfo->midi_channel; #ifdef CONFIG_MIDI_INSTRUMENT m_iMidiMap = pChannelInfo->midi_map; #endif m_iAudioDevice = pChannelInfo->audio_device; m_fVolume = pChannelInfo->volume; #ifdef CONFIG_MUTE_SOLO m_bMute = pChannelInfo->mute; m_bSolo = pChannelInfo->solo; #endif // Some sanity checks. if (m_sEngineName == "NONE" || m_sEngineName.isEmpty()) m_sEngineName.clear(); if (m_sInstrumentFile == "NONE" || m_sInstrumentFile.isEmpty()) { m_sInstrumentFile.clear(); m_sInstrumentName.clear(); } // Time for device info grabbing... lscp_device_info_t *pDeviceInfo; const QString sNone = QObject::tr("(none)"); // Audio device driver type. pDeviceInfo = ::lscp_get_audio_device_info(pMainForm->client(), m_iAudioDevice); if (pDeviceInfo == nullptr) { appendMessagesClient("lscp_get_audio_device_info"); m_sAudioDriver = sNone; } else { m_sAudioDriver = pDeviceInfo->driver; } // MIDI device driver type. pDeviceInfo = ::lscp_get_midi_device_info(pMainForm->client(), m_iMidiDevice); if (pDeviceInfo == nullptr) { appendMessagesClient("lscp_get_midi_device_info"); m_sMidiDriver = sNone; } else { m_sMidiDriver = pDeviceInfo->driver; } // Set the audio routing map. m_audioRouting.clear(); #ifdef CONFIG_AUDIO_ROUTING int *piAudioRouting = pChannelInfo->audio_routing; for (int i = 0; piAudioRouting && piAudioRouting[i] >= 0; i++) m_audioRouting[i] = piAudioRouting[i]; #else char **ppszAudioRouting = pChannelInfo->audio_routing; for (int i = 0; ppszAudioRouting && ppszAudioRouting[i]; i++) m_audioRouting[i] = ::atoi(ppszAudioRouting[i]); #endif return true; } // Reset channel method. bool Channel::channelReset (void) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr || m_iChannelID < 0) return false; if (::lscp_reset_channel(pMainForm->client(), m_iChannelID) != LSCP_OK) { appendMessagesClient("lscp_reset_channel"); return false; } appendMessages(QObject::tr("reset.")); return true; } // Spawn instrument editor method. bool Channel::editChannel (void) { #ifdef CONFIG_EDIT_INSTRUMENT MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr || m_iChannelID < 0) return false; if (::lscp_edit_channel_instrument(pMainForm->client(), m_iChannelID) != LSCP_OK) { appendMessagesClient("lscp_edit_channel_instrument"); appendMessagesError(QObject::tr( "Could not launch an appropriate instrument editor " "for the given instrument!\n\n" "Make sure you have an appropriate " "instrument editor like 'gigedit' installed " "and that it placed its mandatory DLL file " "into the sampler's plugin directory.") ); return false; } appendMessages(QObject::tr("edit instrument.")); return true; #else appendMessagesError(QObject::tr( "Sorry, QSampler was compiled for a version of liblscp " "which lacks this feature.\n\n" "You may want to update liblscp and recompile QSampler afterwards.") ); return false; #endif } // Channel setup dialog form. bool Channel::channelSetup ( QWidget *pParent ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; bool bResult = false; appendMessages(QObject::tr("setup...")); ChannelForm *pChannelForm = new ChannelForm(pParent); if (pChannelForm) { pChannelForm->setup(this); bResult = pChannelForm->exec(); delete pChannelForm; } return bResult; } // Redirected messages output methods. void Channel::appendMessages ( const QString& sText ) const { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm) pMainForm->appendMessages(channelName() + ' ' + sText); } void Channel::appendMessagesColor ( const QString& sText, const QColor& rgb ) const { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm) pMainForm->appendMessagesColor(channelName() + ' ' + sText, rgb); } void Channel::appendMessagesText ( const QString& sText ) const { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm) pMainForm->appendMessagesText(channelName() + ' ' + sText); } void Channel::appendMessagesError ( const QString& sText ) const { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm) pMainForm->appendMessagesError(channelName() + "\n\n" + sText); } void Channel::appendMessagesClient ( const QString& sText ) const { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm) pMainForm->appendMessagesClient(channelName() + ' ' + sText); } // Context menu event handler. void Channel::contextMenuEvent ( QContextMenuEvent *pEvent ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm) pMainForm->contextMenuEvent(pEvent); } // FIXME: Check whether a given file is an instrument file (DLS only). bool Channel::isDlsInstrumentFile ( const QString& sInstrumentFile ) { bool bResult = false; QFile file(sInstrumentFile); if (file.open(QIODevice::ReadOnly)) { char achHeader[16]; if (file.read(achHeader, 16) > 0) { bResult = (::memcmp(&achHeader[0], "RIFF", 4) == 0 && ::memcmp(&achHeader[8], "DLS LIST", 8) == 0); } file.close(); } return bResult; } // FIXME: Check whether a given file is an instrument file (SF2 only). bool Channel::isSf2InstrumentFile ( const QString& sInstrumentFile ) { bool bResult = false; QFile file(sInstrumentFile); if (file.open(QIODevice::ReadOnly)) { char achHeader[12]; if (file.read(achHeader, 12) > 0) { bResult = (::memcmp(&achHeader[0], "RIFF", 4) == 0 && ::memcmp(&achHeader[8], "sfbk", 4) == 0); } file.close(); } return bResult; } // Retrieve the instrument list of a instrument file (.gig). QStringList Channel::getInstrumentList ( const QString& sInstrumentFile, bool bInstrumentNames ) { QStringList instlist; const QFileInfo fi(sInstrumentFile); if (!fi.exists()) { instlist.append(noInstrumentName()); return instlist; } #ifdef CONFIG_LIBGIG if (bInstrumentNames) { if (isDlsInstrumentFile(sInstrumentFile)) { RIFF::File *pRiff = new RIFF::File(sInstrumentFile.toUtf8().constData()); gig::File *pGig = new gig::File(pRiff); #ifdef CONFIG_LIBGIG_SETAUTOLOAD // prevent sleepy response time on large .gig files pGig->SetAutoLoad(false); #endif int iIndex = 0; gig::Instrument *pInstrument = pGig->GetInstrument(iIndex); while (pInstrument) { instlist.append((pInstrument->pInfo)->Name.c_str()); pInstrument = pGig->GetInstrument(++iIndex); } delete pGig; delete pRiff; } #ifdef CONFIG_LIBGIG_SF2 else if (isSf2InstrumentFile(sInstrumentFile)) { RIFF::File *pRiff = new RIFF::File(sInstrumentFile.toUtf8().constData()); sf2::File *pSf2 = new sf2::File(pRiff); const int iPresetCount = pSf2->GetPresetCount(); for (int iIndex = 0; iIndex < iPresetCount; ++iIndex) { sf2::Preset *pPreset = pSf2->GetPreset(iIndex); if (pPreset) { instlist.append(pPreset->Name.c_str()); } else { instlist.append(fi.fileName() + " [" + QString::number(iIndex) + "]"); } } delete pSf2; delete pRiff; } #endif } #endif if (instlist.isEmpty()) { for (int iIndex = 0; iIndex < QSAMPLER_INSTRUMENT_MAX; ++iIndex) { instlist.append(fi.fileName() + " [" + QString::number(iIndex) + "]"); } } return instlist; } // Retrieve the spacific instrument name of a instrument file (.gig), given its index. QString Channel::getInstrumentName ( const QString& sInstrumentFile, int iInstrumentNr, bool bInstrumentNames ) { const QFileInfo fi(sInstrumentFile); if (!fi.exists()) return noInstrumentName(); QString sInstrumentName; #ifdef CONFIG_LIBGIG if (bInstrumentNames) { if (isDlsInstrumentFile(sInstrumentFile)) { RIFF::File *pRiff = new RIFF::File(sInstrumentFile.toUtf8().constData()); gig::File *pGig = new gig::File(pRiff); #ifdef CONFIG_LIBGIG_SETAUTOLOAD // prevent sleepy response time on large .gig files pGig->SetAutoLoad(false); #endif int iIndex = 0; gig::Instrument *pInstrument = pGig->GetInstrument(iIndex); while (pInstrument) { if (iIndex == iInstrumentNr) { sInstrumentName = (pInstrument->pInfo)->Name.c_str(); break; } pInstrument = pGig->GetInstrument(++iIndex); } delete pGig; delete pRiff; } #ifdef CONFIG_LIBGIG_SF2 else if (isSf2InstrumentFile(sInstrumentFile)) { RIFF::File *pRiff = new RIFF::File(sInstrumentFile.toUtf8().constData()); sf2::File *pSf2 = new sf2::File(pRiff); sf2::Preset *pPreset = pSf2->GetPreset(iInstrumentNr); if (pPreset) sInstrumentName = pPreset->Name.c_str(); delete pSf2; delete pRiff; } #endif } #endif if (sInstrumentName.isEmpty()) { sInstrumentName = fi.fileName(); sInstrumentName += " [" + QString::number(iInstrumentNr) + "]"; } return sInstrumentName; } // Common invalid name-helpers. QString Channel::noEngineName (void) { return QObject::tr("(No engine)"); } QString Channel::noInstrumentName (void) { return QObject::tr("(No instrument)"); } QString Channel::loadingInstrument (void) { return QObject::tr("(Loading instrument...)"); } //------------------------------------------------------------------------- // QSampler::ChannelRoutingModel - data model for audio routing // (used for QTableView) ChannelRoutingModel::ChannelRoutingModel ( QObject *pParent ) : QAbstractTableModel(pParent), m_pDevice(nullptr) { } int ChannelRoutingModel::rowCount ( const QModelIndex& /*parent*/) const { return (m_pDevice) ? m_routing.size() : 0; } int ChannelRoutingModel::columnCount ( const QModelIndex& /*parent*/) const { return 1; } Qt::ItemFlags ChannelRoutingModel::flags ( const QModelIndex& /*index*/) const { return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled; } bool ChannelRoutingModel::setData ( const QModelIndex& index, const QVariant& value, int /*role*/) { if (!index.isValid()) return false; m_routing[index.row()] = value.toInt(); emit dataChanged(index, index); return true; } QVariant ChannelRoutingModel::data ( const QModelIndex &index, int role ) const { if (!index.isValid()) return QVariant(); if (role != Qt::DisplayRole) return QVariant(); if (index.column() != 0) return QVariant(); ChannelRoutingItem item; // The common device port item list. DevicePortList& ports = m_pDevice->ports(); QListIterator iter(ports); while (iter.hasNext()) { DevicePort *pPort = iter.next(); item.options.append( m_pDevice->deviceTypeName() + ' ' + m_pDevice->driverName() + ' ' + pPort->portName() ); } item.selection = m_routing[index.row()]; return QVariant::fromValue(item); } QVariant ChannelRoutingModel::headerData ( int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) return QVariant(); switch (orientation) { case Qt::Horizontal: return UNICODE_RIGHT_ARROW + QObject::tr(" Device Channel"); case Qt::Vertical: return QObject::tr("Audio Channel ") + QString::number(section) + " " + UNICODE_RIGHT_ARROW; default: return QVariant(); } } void ChannelRoutingModel::refresh ( Device *pDevice, const ChannelRoutingMap& routing ) { m_pDevice = pDevice; m_routing = routing; // inform the outer world (QTableView) that our data changed #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) QAbstractTableModel::reset(); #else QAbstractTableModel::beginResetModel(); QAbstractTableModel::endResetModel(); #endif } //------------------------------------------------------------------------- // QSampler::ChannelRoutingDelegate - table cell renderer for audio routing // ChannelRoutingDelegate::ChannelRoutingDelegate ( QObject *pParent ) : QItemDelegate(pParent) { } QWidget* ChannelRoutingDelegate::createEditor ( QWidget *pParent, const QStyleOptionViewItem & option, const QModelIndex& index ) const { if (!index.isValid()) return nullptr; if (index.column() != 0) return nullptr; ChannelRoutingItem item = index.model()->data(index, Qt::DisplayRole).value(); QComboBox* pComboBox = new QComboBox(pParent); pComboBox->addItems(item.options); pComboBox->setCurrentIndex(item.selection); pComboBox->setEnabled(true); pComboBox->setEditable(true); pComboBox->setGeometry(option.rect); return pComboBox; } void ChannelRoutingDelegate::setEditorData ( QWidget *pEditor, const QModelIndex &index) const { ChannelRoutingItem item = index.model()->data(index, Qt::DisplayRole).value (); QComboBox* pComboBox = static_cast (pEditor); pComboBox->setCurrentIndex(item.selection); } void ChannelRoutingDelegate::setModelData ( QWidget* pEditor, QAbstractItemModel *pModel, const QModelIndex& index ) const { QComboBox *pComboBox = static_cast (pEditor); pModel->setData(index, pComboBox->currentIndex()); } void ChannelRoutingDelegate::updateEditorGeometry ( QWidget *pEditor, const QStyleOptionViewItem& option, const QModelIndex &/* index */) const { pEditor->setGeometry(option.rect); } } // namespace QSampler // end of qsamplerChannel.cpp qsampler-1.0.0/src/PaxHeaders/qsamplerPaletteForm.ui0000644000000000000000000000013214634065603017536 xustar0030 mtime=1718643587.395448566 30 atime=1718643587.394448566 30 ctime=1718643587.395448566 qsampler-1.0.0/src/qsamplerPaletteForm.ui0000644000175000001440000001731014634065603017530 0ustar00rncbcusers rncbc aka Rui Nuno Capela qsampler - A LinuxSampler Qt GUI Interface. Copyright (C) 2005-2024, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. qsamplerPaletteForm 0 0 534 640 0 0 Color Themes Name 0 0 320 0 Current color palette name true QComboBox::NoInsert Save current color palette name Save :/images/formSave.png Delete current color palette name Delete :/images/formRemove.png Palette 280 360 Current color palette true Generate: 0 0 Qt::StrongFocus Base color to generate palette Reset all current palette colors Reset :/images/itemReset.png Qt::Horizontal 8 20 Import a custom color theme (palette) from file Import... :/images/formOpen.png Export a custom color theme (palette) to file Export... :/images/formSave.png Qt::Horizontal 8 20 Show Details Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok QSampler::PaletteForm::ColorButton nameCombo saveButton deleteButton paletteView generateButton resetButton importButton exportButton detailsCheck dialogButtons qsampler-1.0.0/src/PaxHeaders/qsamplerMessages.h0000644000000000000000000000013214634065603016675 xustar0030 mtime=1718643587.394448566 30 atime=1718643587.394448566 30 ctime=1718643587.394448566 qsampler-1.0.0/src/qsamplerMessages.h0000644000175000001440000000570514634065603016674 0ustar00rncbcusers// qsamplerMessages.h // /**************************************************************************** Copyright (C) 2004-2021, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #ifndef __qsamplerMessages_h #define __qsamplerMessages_h #include class QSocketNotifier; class QTextBrowser; class QFile; namespace QSampler { //------------------------------------------------------------------------- // QSampler::Messages - Messages log dockable window. // class Messages : public QDockWidget { Q_OBJECT public: // Constructor. Messages(QWidget *pParent); // Destructor. ~Messages(); // Stdout/stderr capture accessors. bool isCaptureEnabled(); void setCaptureEnabled(bool bCapture); // Message font accessors. QFont messagesFont(); void setMessagesFont(const QFont& font); // Maximum number of message lines accessors. int messagesLimit(); void setMessagesLimit(int iMessagesLimit); // Logging settings. bool isLogging() const; void setLogging(bool bEnabled, const QString& sFilename = QString()); // The main utility methods. void appendMessages(const QString& s); void appendMessagesColor(const QString& s, const QColor& rgb); void appendMessagesText(const QString& s); // Stdout capture functions. void appendStdoutBuffer(const QString& s); void flushStdoutBuffer(); // History reset. void clear(); protected: // Message executives. void appendMessagesLine(const QString& s); void appendMessagesLog(const QString& s); // Set stdout/stderr blocking mode. bool stdoutBlock(int fd, bool bBlock) const; // Split stdout/stderr into separate lines... void processStdoutBuffer(); protected slots: // Stdout capture slot. void stdoutNotify(int fd); private: // The maximum number of message lines. int m_iMessagesLines; int m_iMessagesLimit; int m_iMessagesHigh; // The textview main widget. QTextBrowser *m_pMessagesTextView; // Stdout capture variables. QSocketNotifier *m_pStdoutNotifier; QString m_sStdoutBuffer; int m_fdStdout[2]; // Logging stuff. QFile *m_pMessagesLog; }; } // namespace QSampler #endif // __qsamplerMessages_h // end of qsamplerMessages.h qsampler-1.0.0/src/PaxHeaders/qsamplerMessages.cpp0000644000000000000000000000013214634065603017230 xustar0030 mtime=1718643587.394448566 30 atime=1718643587.394448566 30 ctime=1718643587.394448566 qsampler-1.0.0/src/qsamplerMessages.cpp0000644000175000001440000002306114634065603017222 0ustar00rncbcusers// qsamplerMessages.cpp // /**************************************************************************** Copyright (C) 2004-2021, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #include "qsamplerAbout.h" #include "qsamplerMessages.h" #include #include #include #include #include #include #include #include #if !defined(__WIN32__) && !defined(_WIN32) && !defined(WIN32) #include #include #endif // Deprecated QTextStreamFunctions/Qt namespaces workaround. #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) #define endl Qt::endl #endif namespace QSampler { // The default maximum number of message lines. #define QSAMPLER_MESSAGES_MAXLINES 1000 // Notification pipe descriptors #define QSAMPLER_MESSAGES_FDNIL -1 #define QSAMPLER_MESSAGES_FDREAD 0 #define QSAMPLER_MESSAGES_FDWRITE 1 //------------------------------------------------------------------------- // QSampler::Messages - Messages log dockable window. // // Constructor. Messages::Messages ( QWidget *pParent ) : QDockWidget(pParent) { // Surely a name is crucial (e.g.for storing geometry settings) QDockWidget::setObjectName("qsamplerMessages"); // Intialize stdout capture stuff. m_pStdoutNotifier = nullptr; m_fdStdout[QSAMPLER_MESSAGES_FDREAD] = QSAMPLER_MESSAGES_FDNIL; m_fdStdout[QSAMPLER_MESSAGES_FDWRITE] = QSAMPLER_MESSAGES_FDNIL; // Create local text view widget. m_pMessagesTextView = new QTextBrowser(this); // QFont font(m_pMessagesTextView->font()); // font.setFamily("Fixed"); // m_pMessagesTextView->setFont(font); m_pMessagesTextView->setLineWrapMode(QTextEdit::NoWrap); // m_pMessagesTextView->setReadOnly(true); // m_pMessagesTextView->setUndoRedoEnabled(false); // m_pMessagesTextView->setTextFormat(Qt::LogText); // Initialize default message limit. m_iMessagesLines = 0; setMessagesLimit(QSAMPLER_MESSAGES_MAXLINES); m_pMessagesLog = nullptr; // Prepare the dockable window stuff. QDockWidget::setWidget(m_pMessagesTextView); // QDockWidget::setFeatures(QDockWidget::AllDockWidgetFeatures); QDockWidget::setAllowedAreas( Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea); // Some specialties to this kind of dock window... QDockWidget::setMinimumHeight(120); // Finally set the default caption and tooltip. const QString& sCaption = tr("Messages"); QDockWidget::setWindowTitle(sCaption); // QDockWidget::setWindowIcon(QIcon(":/icons/qsamplerMessages.png")); QDockWidget::setToolTip(sCaption); } // Destructor. Messages::~Messages (void) { // Turn off and close logging. setLogging(false); // No more notifications. if (m_pStdoutNotifier) delete m_pStdoutNotifier; // No need to delete child widgets, Qt does it all for us. } #if defined(Q_CC_GNU) || defined(Q_CC_MINGW) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif // Set stdout/stderr blocking mode. bool Messages::stdoutBlock ( int fd, bool bBlock ) const { #if !defined(__WIN32__) && !defined(_WIN32) && !defined(WIN32) const int iFlags = ::fcntl(fd, F_GETFL, 0); const bool bNonBlock = bool(iFlags & O_NONBLOCK); if (bBlock && bNonBlock) bBlock = (::fcntl(fd, F_SETFL, iFlags & ~O_NONBLOCK) == 0); else if (!bBlock && !bNonBlock) bBlock = (::fcntl(fd, F_SETFL, iFlags | O_NONBLOCK) != 0); #endif return bBlock; } // Own stdout/stderr socket notifier slot. void Messages::stdoutNotify ( int fd ) { #if !defined(__WIN32__) && !defined(_WIN32) && !defined(WIN32) // Set non-blocking reads, if not already... const bool bBlock = stdoutBlock(fd, false); // Read as much as is available... QString sTemp; char achBuffer[1024]; const int cchBuffer = sizeof(achBuffer) - 1; int cchRead = ::read(fd, achBuffer, cchBuffer); while (cchRead > 0) { achBuffer[cchRead] = (char) 0; sTemp.append(achBuffer); cchRead = (bBlock ? 0 : ::read(fd, achBuffer, cchBuffer)); } // Needs to be non-empty... if (!sTemp.isEmpty()) appendStdoutBuffer(sTemp); #endif } #if defined(Q_CC_GNU) || defined(Q_CC_MINGW) #pragma GCC diagnostic pop #endif // Stdout buffer handler -- now splitted by complete new-lines... void Messages::appendStdoutBuffer ( const QString& s ) { m_sStdoutBuffer.append(s); processStdoutBuffer(); } void Messages::processStdoutBuffer (void) { const int iLength = m_sStdoutBuffer.lastIndexOf('\n'); if (iLength > 0) { QStringListIterator iter(m_sStdoutBuffer.left(iLength).split('\n')); while (iter.hasNext()) { const QString& sTemp = iter.next(); if (!sTemp.isEmpty()) #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) appendMessagesText(sTemp.trimmed()); #else appendMessagesText(sTemp); #endif } m_sStdoutBuffer.remove(0, iLength + 1); } } // Stdout flusher -- show up any unfinished line... void Messages::flushStdoutBuffer (void) { processStdoutBuffer(); if (!m_sStdoutBuffer.isEmpty()) { #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) appendMessagesText(m_sStdoutBuffer.trimmed()); #else appendMessagesText(m_sStdoutBuffer); #endif m_sStdoutBuffer.clear(); } } // Stdout capture accessors. bool Messages::isCaptureEnabled (void) { return (m_pStdoutNotifier != nullptr); } void Messages::setCaptureEnabled ( bool bCapture ) { // Flush current buffer. flushStdoutBuffer(); #if !defined(__WIN32__) && !defined(_WIN32) && !defined(WIN32) // Destroy if already enabled. if (!bCapture && m_pStdoutNotifier) { delete m_pStdoutNotifier; m_pStdoutNotifier = nullptr; // Close the notification pipes. if (m_fdStdout[QSAMPLER_MESSAGES_FDREAD] != QSAMPLER_MESSAGES_FDNIL) { ::close(m_fdStdout[QSAMPLER_MESSAGES_FDREAD]); m_fdStdout[QSAMPLER_MESSAGES_FDREAD] = QSAMPLER_MESSAGES_FDNIL; } } // Are we going to make up the capture? if (bCapture && m_pStdoutNotifier == nullptr && ::pipe(m_fdStdout) == 0) { ::dup2(m_fdStdout[QSAMPLER_MESSAGES_FDWRITE], STDOUT_FILENO); ::dup2(m_fdStdout[QSAMPLER_MESSAGES_FDWRITE], STDERR_FILENO); m_pStdoutNotifier = new QSocketNotifier( m_fdStdout[QSAMPLER_MESSAGES_FDREAD], QSocketNotifier::Read, this); QObject::connect(m_pStdoutNotifier, SIGNAL(activated(int)), SLOT(stdoutNotify(int))); } #endif } // Message font accessors. QFont Messages::messagesFont (void) { return m_pMessagesTextView->font(); } void Messages::setMessagesFont ( const QFont& font ) { m_pMessagesTextView->setFont(font); } // Maximum number of message lines accessors. int Messages::messagesLimit (void) { return m_iMessagesLimit; } void Messages::setMessagesLimit ( int iMessagesLimit ) { m_iMessagesLimit = iMessagesLimit; m_iMessagesHigh = iMessagesLimit + (iMessagesLimit / 3); } // Messages logging stuff. bool Messages::isLogging (void) const { return (m_pMessagesLog != nullptr); } void Messages::setLogging ( bool bEnabled, const QString& sFilename ) { if (m_pMessagesLog) { appendMessages(tr("Logging stopped --- %1 ---") .arg(QDateTime::currentDateTime().toString())); m_pMessagesLog->close(); delete m_pMessagesLog; m_pMessagesLog = nullptr; } if (bEnabled) { m_pMessagesLog = new QFile(sFilename); if (m_pMessagesLog->open(QIODevice::Text | QIODevice::Append)) { appendMessages(tr("Logging started --- %1 ---") .arg(QDateTime::currentDateTime().toString())); } else { delete m_pMessagesLog; m_pMessagesLog = nullptr; } } } // Messages log output method. void Messages::appendMessagesLog ( const QString& s ) { if (m_pMessagesLog) { QTextStream(m_pMessagesLog) << QTime::currentTime().toString("hh:mm:ss.zzz") << ' ' << s << endl; m_pMessagesLog->flush(); } } // Messages widget output method. void Messages::appendMessagesLine ( const QString& s ) { // Check for message line limit... if (m_iMessagesLines > m_iMessagesHigh) { m_pMessagesTextView->setUpdatesEnabled(false); QTextCursor textCursor(m_pMessagesTextView->document()->begin()); while (m_iMessagesLines > m_iMessagesLimit) { // Move cursor extending selection // from start to next line-block... textCursor.movePosition( QTextCursor::NextBlock, QTextCursor::KeepAnchor); m_iMessagesLines--; } // Remove the excessive line-blocks... textCursor.removeSelectedText(); m_pMessagesTextView->setUpdatesEnabled(true); } m_pMessagesTextView->append(s); m_iMessagesLines++; } // The main utility methods. void Messages::appendMessages ( const QString& s ) { appendMessagesColor(s, Qt::gray); } void Messages::appendMessagesColor ( const QString& s, const QColor& rgb ) { appendMessagesLine("" + s + ""); appendMessagesLog(s); } void Messages::appendMessagesText ( const QString& s ) { appendMessagesLine(s); appendMessagesLog(s); } // History reset. void Messages::clear (void) { m_iMessagesLines = 0; m_pMessagesTextView->clear(); } } // namespace QSampler // end of qsamplerMessages.cpp qsampler-1.0.0/src/PaxHeaders/translations0000644000000000000000000000013214634065603015654 xustar0030 mtime=1718643587.395448566 30 atime=1718643587.395448566 30 ctime=1718643587.395448566 qsampler-1.0.0/src/translations/0000755000175000001440000000000014634065603015721 5ustar00rncbcusersqsampler-1.0.0/src/translations/PaxHeaders/qsampler_ru.ts0000644000000000000000000000013214634065603020633 xustar0030 mtime=1718643587.395448566 30 atime=1718643587.395448566 30 ctime=1718643587.395448566 qsampler-1.0.0/src/translations/qsampler_ru.ts0000644000175000001440000036461014634065603020635 0ustar00rncbcusers QObject Could not add channel. Sorry. Не удалось добавить канал. Извините. added. добавлен. Could not remove channel. Sorry. Не удалось удалить канал. Извините. removed. удален. New Channel Новый канал Channel %1 Канал %1 Engine: %1. Движок: %1. Instrument: "%1" (%2). Инструмент: "%1" (%2). MIDI driver: %1. Драйвер MIDI: %1. MIDI device: %1. Устройство MIDI: %1. MIDI port: %1. Порт MIDI: %1. MIDI channel: %1. Канал MIDI: %1. MIDI map: %1. Карта MIDI: %1. Audio device: %1. Звуковое устройство: %1. Audio driver: %1. Звуковой драйвер: %1. Volume: %1. Громкость: %1. Mute: %1. Приглушение: %1. Solo: %1. Солирование: %1. Audio Channel: %1 -> %2. Звуковой канал: %1 -> %2. Could not get channel information. Sorry. Не удалось получить информацию о канале. Извините. (none) (нет) reset. Could not launch an appropriate instrument editor for the given instrument! Make sure you have an appropriate instrument editor like 'gigedit' installed and that it placed its mandatory DLL file into the sampler's plugin directory. Не удалось запустить подходящий редактор для этого инструмента! Убедитесь, что в системе установлен необходимый редактор вроде gigedit, и что его файл DLL размещен в папке с расширениями сэмплера. edit instrument. Sorry, QSampler was compiled for a version of liblscp which lacks this feature. You may want to update liblscp and recompile QSampler afterwards. Извините, но QSampler был собран с версией liblscp, где эта функция не реализована. Вероятно вам стоит обновить версию liblscp и пересобрать QSampler. setup... (No engine) (нет движка) (No instrument) (нет инструмента) (Loading instrument...) (загружается инструмент...) Device Channel Канал устройства Audio Channel Звуковой канал channel fx sends... Audio Звук MIDI MIDI New %1 device Новое устройство %1 Device %1 Устройство %1 Could not set device parameter value. Sorry. Не удалось установить значение параметра. Извините. created. создано. Could not create device. Sorry. Не удалось создать устройство Извините. deleted. удалено Could not delete device. Sorry. Не удалось удалить устройство Извините. Could not set %1 parameter value. Sorry. Не удалось установить значение параметра %1. Извините. Audio Devices Звуковые устройства MIDI Devices Устройства MIDI Usage: %1 [options] [session-file] Options: Start linuxsampler server locally. Specify linuxsampler server hostname (default = localhost) Specify linuxsampler server port number (default = 8888) Show help about command line options. Show version information Session file (.lscp) [session-file] Option -n requires an argument (hostname). Option -p requires an argument (port). Ключу -p нужен аргумент (номер порта). Sent fine tuning settings. QSampler::AbstractDeviceParamModel Parameter Параметр Value Значение Description Описание QSampler::ChannelForm Select an instrument of the file You might want to enable instrument name retrieval in the settings dialog Some channel settings could not be set. Sorry. Не удалось задать некоторые параметры канала. Извините. Warning Предупреждение Some channel settings have been changed. Do you want to apply the changes? Некоторые параметры канала изменились. Вы хотите применить эти изменения? GIG Instrument files SFZ Instrument files SF2 Instrument files All files Instrument files Файлы инструментов (New MIDI %1 device) (Новое устройство MIDI %1) (New Audio %1 device) (Новое звуковое устройство %1) QSampler::ChannelStrip Unavailable Недоступно Sorry, QSampler was built without FX send support! (Make sure you have a recent liblscp when recompiling QSampler) Извините, но QSampler был собран без поддержки посыла эффектов! Убедитесь, что в системе установлена достаточно новая версия liblscp. Instruments Инструменты All Все ERR%1 ERR%1 QSampler::DeviceForm Warning Предупреждение About to delete device: %1 Are you sure? Будет удалено устройство: %1 Вы уверены? Don't ask this again Ch&annel: &Канал: P&ort: &Порт: &Create device &Создать устройство &Delete device &Удалить устройство &Refresh О&бновить QSampler::DeviceParamDelegate (none) (нет) QSampler::DeviceStatusForm %1 Status QSampler::InstrumentForm GIG Instrument files SFZ Instrument files SF2 Instrument files Instrument files Файлы инструментов Warning Предупреждение Some channel settings have been changed. Do you want to apply the changes? Некоторые параметры канала изменились. Вы хотите учесть эти изменения? QSampler::InstrumentListForm Instrument Map Карта инструментов (All) (Все) Warning Предупреждение About to delete instrument map entry: %1 Are you sure? Элемент карты инструментов будет удален: %1 Вы уверены? Don't ask this again QSampler::InstrumentListModel Persistent Непрерывно On Demand Hold On Demand По требованию Name Название Map Карта Bank Банк Prog Программа Engine Движок File Файл Nr Vol Громкость Mode Режим Could not get current list of MIDI instrument mappings. Sorry. Не удалось получить актуальный список привязок инструментов MIDI. Извините. QSampler::MainForm Master volume Общая громкость Connected Установлено соединение с MOD Ready Готов Untitled Без названия New session: "%1". Новый сеанс: "%1". Open Session Открыть сеанс LSCP Session files Файлы сеансов LSCP Save Session Сохранить сеанс Warning Предупреждение The file already exists: "%1" Do you want to replace it? Такой файл уже существует: "%1" Заменить его? The current session has been changed: "%1" Do you want to save the changes? Текущий сеанс изменился: "%1" Вы хотите сохранить эти изменения? Could not open "%1" session file. Sorry. Не удалось открыть файл сеанса "%1". Извините. Session loaded with errors from "%1". Sorry. Сеанс загружен с ошибками из "%1". Извините. Open session: "%1". Открыть сеанс: "%1". Version Версия File Файл Date Дата Device Устройство MIDI instrument map Карта инструментов MIDI Channel Канал Global volume level Общий уровень громкости Some settings could not be saved to "%1" session file. Sorry. Некоторые параметры не удалось сохранить в файл сеанса "%1". Извините. Save session: "%1". Сохранить сеанс: "%1". Resetting the sampler instance will close all device and channel configurations. Please note that this operation may cause temporary MIDI and Audio disruption. Do you want to reset the sampler engine now? Перезагрузка движка сэмплера приведет к закрытию всех устройств и каналов. Это может привести к временному разрыву в воспроизведении MIDI и звука. Вы хотите перезапустить движок сэмплера? Could not reset sampler instance. Sorry. Не удалось перезапустить движок сэмплера. Извините. Sampler reset. Перезагрузка сэмплера. New settings will be effective after restarting the client/server connection. Please note that this operation may cause temporary MIDI and Audio disruption. Do you want to restart the connection now? Новые параметры возымеют эффект после перезапуска соединения клиента с сервером. Это может привести к временному разрыву в воспроизведении MIDI и звука. Вы хотите заново установить соединение клиента и сервера? About to remove channel: %1 Are you sure? Будет удален канал: %1 Вы уверены? Using: Qt %1 LSCP Event: %1 data: %2 Don't ask this again Information Справка Some settings may be only effective next time you start this program. Некоторые новые параметры возымеют силу только при следующем запуске программы. Debugging option enabled. Функция отладки включена. GIG (libgig) file support disabled. Поддержка сэмплов GIG (libgig) отключена. LSCP (liblscp) instrument_name support disabled. Поддержка функции instrument_name в LSCP (liblscp) отключена. Sampler channel Mute/Solo support disabled. Поддержка приглушения/солирования канала отключена. LSCP (liblscp) audio_routing support disabled. Поддержка функции audio_routing в LSCP (liblscp) отключена. Sampler channel Effect Sends support disabled. Поддержка поканального посыла эффектов отключена. Global volume support disabled. Поддержка общего регулятора громкости отключена. MIDI instrument mapping support disabled. Поддержка свызывания инструментов MIDI отключена. Instrument editing support disabled. Функция редактирования инструментов отключена. Channel MIDI event support disabled. Device MIDI event support disabled. Runtime max. voices / disk streams support disabled. Поддержка ограничения числа голосов/дисковых потоков отключена. Website Сайт This program is free software; you can redistribute it and/or modify it Эта программа является свободной; вы можете распространять и/или under the terms of the GNU General Public License version 2 or later. изменять ее на условиях GNU GPL версии 2 или новее. About О программе Chromatic Хроматическая Drum Kits Перкуссия Could not get current list of channels. Sorry. Не удалось получить актуальный список каналов. Извините. Error Ошибка Don't show this again Could not start the LinuxSampler server. Maybe it is already started. Не удалось запустить сервер LinuxSampler. Возможно, он уже запущен. Server is starting... Запускается сервер... Could not start server. Sorry. Не удалось запустить сервер. Извините. Server was started with PID=%1. Сервер запущен с PID=%1. The backend's fate ... Что делать с движком Server is stopping... Останавливается сервер... Server is being forced... Server was stopped with exit status %1. Сервер был остановлен со статусом выхода %1. Client connecting... Устанавливается соединения клиента... Could not connect to server as client. Sorry. Не удалось соединиться с сервером в качестве клиента. Извините. Client receive timeout is set to %1 msec. Client connected. Клиент соединился. Client disconnecting... Выполняется отсоединение клиента... Client disconnected. Клиент отсоединен. Trying to reconnect... You have the option to keep the sampler backend (LinuxSampler) running in the background. The sampler would continue to work according to your current sampler session and you could alter the sampler session at any time by relaunching QSampler. Do you want LinuxSampler to stop? QSampler::Messages Messages Сообщения Logging stopped --- %1 --- Ведение журнала остановлено --- %1 --- Logging started --- %1 --- Ведение журнала начато --- %1 --- QSampler::OptionsForm This parameter is not supported by the current sampler version in use. Этот параметр не поддерживается используемой версией сэмплера. The max. amount of voices the sampler shall process simultaneously. The max. amount of disk streams the sampler shall process simultaneously. QSampler was built without support for this parameter. QSampler был собран без поддержки этого параметра. Warning Предупреждение Some settings have been changed. Do you want to apply the changes? Некоторые параметры были изменены. Вы хотите применить изменения? Messages Log Журнал сообщений Log files Файлы журналов QSampler::PaletteForm Import File - %1 Palette files (*.%1) Save Palette - %1 All files (*.*) Warning - %1 Could not import from file: %1 Sorry. Export File - %1 Some settings have been changed. Do you want to discard the changes? Some settings have been changed: "%1". Do you want to save the changes? QSampler::PaletteForm::PaletteModel Color Role Active Inactive Disabled qsamplerChannelForm Browse for instrument filename Указать файл инструмента Instrument name Название инструмента &Engine: &Движок: Engine name Название движка &Instrument: &Инструмент: Instrument filename Имя файла инструмента MIDI / Input MIDI / вход MIDI input device Устройство MIDI для входа MIDI input device setup Настроить устройство MIDI для входа &Map: &Карта: Instrument map Карта инструментов MIDI input driver type Тип драйвера MIDI для входа De&vice: T&ype: Channel Канал Filena&me: &Port: &Порт: MIDI input port number Номер порта MIDI для входа &Channel: &Канал: MIDI input channel Канал MIDI для входа 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 All Все Audio / Output Звук / выход Audio output device Устройство вывода звука Audio output device setup Настроить устройство вывода звука Audio output driver type Тип устройства вывода звука Audio routing table Таблица маршрутизации звука qsamplerChannelFxForm Channel Effects Эффекты канала FX Send Selection Выбор посыла эффектов Creates a new FX Send. You have to select 'Apply' afterwards to actually create it on sampler side. Создать новый посыл. Для действительного назначения посыла на стороне сэмплера надо будет нажать кнопку «Применить». Create Создать Schedules the selected FX send for deletion. You have to select 'Apply' afterwards to actually destroy it on sampler side. Добавить выбранный посыл эффектов в очередь на удаление Для действительного удаления посыла на стороне сэмплера надо будет нажать кнопку «Применить» Destroy Разрушить FX Send's Parameters Параметры посыла эффектов Send Depth MIDI Controller: Отправлять MIDI-контроллер Depth: Current Depth: Текущая глубина: % % Audio Routing Маршрутизация звука qsamplerChannelStrip Channel setup Настроить канал &Channel &Канал -- -- Instrument name Название инструмента MIDI port / channel Порт/канал MIDI Channel Канал -- / -- -- / -- Instrument load status Статус загрузки инструмента MIDI activity Channel mute Приглушить канал &Mute &Тихо Channel solo Солирование канала &Solo &Соло Channel volume Громкость канала % % Edit Channel's Effect Settings Изменить эффекты канала &FX &Эффекты Edit channel's instrument Изменить инструмент канала &Edit &Изменить Least buffer fill stream usage (%) Stream / Voice count Счетчик потоков/голосов --/-- --/-- qsamplerDeviceForm Device list Список устройств Devices Устройства Device name Название устройства Dri&ver: &Драйвер: Driver type name Название типа драйвера Channel: Канал: Device port/channel Порт/канал устройства Refresh device list view Обновить список устройств &Refresh О&бновить Create device Создать устройство &Create &Создать Delete device Удалить устройство &Delete &Удалить Close this dialog Закрыть этот диалог Close &Закрыть qsamplerInstrumentForm Instrument Engine name Название движка &Engine: &Движок: &Prog: &Программа: Program (0-127) Программа (0-127) Vol&ume: &Громкость: &Map: &Карта: &Bank: &Банк: Bank (0-16383) Банк (0-16383) Instrument filename Имя файла инструмента M&ode: &Режим: &Filename: Имя &файла: &Name: И&мя Instrument map Карта инструментов &Instrument: &Инструмент: Instrument name Название инструмента Volume (%) Громкость (%) % % Name Название Load mode Режим загрузки Default По умолчанию On Demand По требованию On Demand Hold Persistent Непрерывно Browse for instrument filename Указать файл инструмента qsamplerInstrumentListForm Instruments Инструменты New &Instrument... &Создать инструмент... New Создать Ins &Edit... &Изменить... Edit Изменить Enter Enter &Delete &Удалить Delete Удалить Del &Refresh О&бновить Refresh Обновить F5 F5 qsamplerMainForm &Edit &Правка &View &Вид MIDI Device Status Статус устройства MIDI &Channels &Каналы &Help &Справка &File &Файл Open &Recent Открыть &недавние &New &Создать New Создать New session Создать сеанс New sampler session Создать новый сеанс работы с сэмплером Ctrl+N Ctrl+N &Open... &Открыть... Open Открыть Open session Открыть сеанс Open sampler session Открыть сеанс работы с сэмплером Ctrl+O Ctrl+O &Save Со&хранить Save Сохранить Save session Сохранить сеанс Save sampler session Сохранить сеанс работы с сэмплером Ctrl+S Ctrl+S Save &As... Сохранить &как... Save As Сохранить как Save current sampler session with another name Сохранить активный сеанс под другим именем Rese&t С&бросить Reset Сбросить Reset instance Reset sampler instance Ctrl+R Ctrl+R &Restart &Перезагрузить Restart Перезагрузить Restart instance Перезагрузить движок Restart sampler instance Перезагрузить движок сэмплера Ctrl+Shift+R Ctrl+Shift+R E&xit В&ыход Exit Выйти Exit this application program Завершить работу с программой &Add Channel &Добавить канал Add Добавить Add channel Добавить канал Add a new sampler channel Добавить новый канал сэмплера Ctrl+A Ctrl+A &Remove Channel &Удалить канал Remove Удалить Remove channel Удалить канал Remove current sampler channel Удалить активный канал сэмплера Ctrl+X Ctrl+X Re&set Channel С&бросить канал Reset channel Сбросить канал Reset current sampler channel Сбросить активный канал сэмплера R&eset All Channels Сбросить &все каналы Reset All Сбросить все Reset all channels Сбросить все каналы Reset all sampler channels Сбросить все каналы сэмплера &Setup Channel... &Настроить канал... Setup Настроить Setup channel Настроить канал Setup current sampler channel Настроить активный канал сэмплера F2 F2 Ed&it Channel... &Изменить канал... Edit Изменить Edit channel Изменить канал Edit current sampler channel Изменить активный канал сэмплера F9 F9 &Menubar Строка &меню Menubar Строка меню Show/hide menubar Показать или скрыть строку меню Show/hide the main program window menubar Показать или скрыть строку меню основного окна программы Ctrl+M Ctrl+M &Toolbar &Панель инструментов Toolbar Панель инструментов Show/hide toolbar Показать или скрыть панель инструментов Show/hide main program window toolbars Показать или скрыть панель инструментов основного окна программы Ctrl+T Ctrl+T &Statusbar &Строка состояния Statusbar Строка состояния Show/hide statusbar Показать или скрыть строку состояния Show/hide the main program window statusbar Показать или скрыть строку состояния основного окна программы M&essages Соо&бщения Messages Сообщения Show/hide messages Показать или скрыть диалог сообщений Show/hide the messages window Показать или скрыть окно диалога сообщений &Instruments &Инструменты Instruments Инструменты MIDI instruments configuration Настройка инструментов MIDI Show/hide the MIDI instruments configuration window Показать или скрыть окно настройки инструментов MIDI F10 F10 &Devices &Устройства Devices Устройства Device configuration Настройка устройств Show/hide the device configuration window Показать или скрыть окно настройки устройств F11 F11 &Options... &Параметры... Options Параметры General options Общие параметры Change general application program options Общие параметры работы программы F12 F12 &Arrange &Расставить Arrange Расставить Arrange channels Расставить каналы Line up all channel strips Расставить блоки каналов по вертикали F5 F5 A&uto Arrange &Автоматически расставлять Auto Arrange Автоматически расставлять Auto-arrange channels Автоматически расставлять каналы Auto-arrange channel strips Автоматически расставлять блоки каналов &About... &О программе... About О программе Show information about this application program Показать информацию о программе About &Qt... О &Qt... About Qt О Qt Show information about the Qt toolkit Показать информацию об инструментарии Qt qsamplerOptionsForm &Server &Сервер Settings Параметры &Host: &Хост: LinuxSampler server listener port number Номер порта для LinuxSampler 8888 8888 &Port: &Порт: LinuxSampler server host name or address Название или адрес узла LinuxSampler localhost localhost &Command line: &Командная строка: Whether to start the LinuxSampler server on local machine Запускать ли сервер LinuxSampler на локальной машине &Start server locally &Запускать сервер локально Command line to start LinuxSampler server locally Команда локального запуска LinuxSampler linuxsampler linuxsampler Start &delay: З&адержка старта: Delay time in seconds after server startup Задержка в секундах перед стартом сервера secs с Receive timeout in milliseconds Время ожидания в миллисекундах msec мс &Timeout: &Время ожидания: Logging Ведение журнала Messages log file Файл с журналом сообщений LinuxSampler Browse for the messages log file location Указать расположение файла журнала ... ... Whether to activate a messages logging to file. Включать ли функцию ведения журнала в файле &Messages log file: &Файл с журналом: Whether to ask for session reset &Confirm session reset Whether to ask for session restart &Confirm session restart Whether to show session errors &Confirm session errors &Tuning &Настройка Options Параметры Limits Пределы Maximum number of voices Максимальное число голосов Maximum number of disk streams Максимальное число дисковых потоков &Display &Интерфейс Channels Каналы Sample channel display font display Пример отображения шрифта в канале Select font for the channel display Выберите шрифт для отображения канала &Font... &Шрифт... Whether to refresh the channels view automatically Обновлять ли втоматически вид каналов &Auto refresh: &Автообновление: Maximum &volume: Макс. &громкость: Time in milliseconds between each auto-refresh cycle Время между циклами автообновления в миллисекундах Upper limit for the sampler channel volume setting Верхний предел громкости каждого канала % % Whether to enable a shiny glass light effect on the channel display Показывать ли отблеск на «стекле» с индикаторами канала Display shiny glass light &effect Показывать отблеск на &дисплее канала Messages Сообщения &General Sample messages text font display Пример использования выбранного шрифта для сообщений Select font for the messages text display Выберите шрифт для вывода сообщений Whether to keep a maximum number of lines in the messages window Устанавливать ли максимальный предел строк в панели сообщений &Messages limit: П&редел строк сообщений: The maximum number of message lines to keep in view Максимальное количество видимых в панели сообщений lines строк Other Прочее Whether to ask for confirmation on removals Спрашивать подтверждение при удалении каналов &Confirm removals &Подтверждать удаление &Number of recent files: &Запоминаемых сеансов: The maximum number of recent files to keep in menu Максимальное число сеансов, перечисляемых как недавно открывавшихся Whether to keep all child windows on top of the main window Показывать ли все окна прграммы всегда над основным ее окном &Keep child windows always on top Окна &всегда наверху Whether to capture standard output (stdout/stderr) into messages window Захватывать ли стандартные потоки (stdout/stderr) в панель сообщений Capture standard &output Захватывать &системные потоки сообщений Whether to show the complete directory path of loaded session files Показывать ли расположение загруженного файла сеанса в файловой системе Show complete &path of session files По&казывать полный путь к файлам сеансов Whether to show the actual instrument names as read from instrument file (using libgig) Показывать ли названия инструментов, считанные из метаданных файлов (при помощи libgig) Show actual &instrument names Показывать названия инс&трументов Custom &Color palette theme: Custom color palette theme Wonton Soup DO NOT TRANSLATE KXStudio DO NOT TRANSLATE Manage custom color palette themes &Widget style theme: Custom widget style theme Defaults &Base font size: К&егль шрифта в GUI: Base application font size (pt.) Кегль шрифта в интерфейсе (в пунктах) Maximum &number of voices: Maximum number of disk &streams: (default) (по умолчанию) 6 6 7 7 8 8 9 9 10 10 11 11 12 12 qsamplerPaletteForm Color Themes Name Название Current color palette name Save current color palette name Save Сохранить Delete current color palette name Delete Удалить Palette Current color palette Generate: Base color to generate palette Reset all current palette colors Reset Import a custom color theme (palette) from file Import... Export a custom color theme (palette) to file Export... Show Details qsampler-1.0.0/src/translations/PaxHeaders/qsampler_fr.ts0000644000000000000000000000013214634065603020614 xustar0030 mtime=1718643587.395448566 30 atime=1718643587.395448566 30 ctime=1718643587.395448566 qsampler-1.0.0/src/translations/qsampler_fr.ts0000644000175000001440000035504314634065603020616 0ustar00rncbcusers QObject Could not add channel. Sorry. Impossible d'ajouter un canal. Navré. added. ajouté. Could not remove channel. Sorry. Impossible de retirer un canal. Navré. removed. retiré. New Channel Nouveau canal Channel %1 Canal %1 Engine: %1. Moteur : %1. Instrument: "%1" (%2). Instrument : "%1" (%2). MIDI driver: %1. Pilote MIDI : %1. MIDI device: %1. Périphérique MIDI : %1. MIDI port: %1. Port MIDI : %1. MIDI channel: %1. Canal MIDI : %1. MIDI map: %1. Cartographie MIDI : %1. Audio device: %1. Périphérique audio : %1. Audio driver: %1. Pilote audio : %1. Volume: %1. Volume : %1. Mute: %1. Muet : %1. Solo: %1. Solo : %1. Audio Channel: %1 -> %2. Canal audio : %1 -> %2. Could not get channel information. Sorry. Impossible d'acquérir les informations à propos du canal. Navré. (none) (aucun) reset. réinitialiser. Could not launch an appropriate instrument editor for the given instrument! Make sure you have an appropriate instrument editor like 'gigedit' installed and that it placed its mandatory DLL file into the sampler's plugin directory. Impossible de lancer un éditeur d'instrument approprié pour l'instrument donné ! Assurez-vous que vous avez un éditeur d'instrument approprié installé comme 'gigedit' et qu'il ait placé son fichier DLL nécessaire dans le répertoire de greffon de l'échantillonneur. edit instrument. éditer l'instrument. Sorry, QSampler was compiled for a version of liblscp which lacks this feature. You may want to update liblscp and recompile QSampler afterwards. Navré, QSampler a été compilé pour une version de liblscp pour laquelle cette fonctionnalité est manquante. Vous pourriez vouloir mettre à jour liblscp et recompiler QSampler ensuite. setup... paramètre... (No engine) (pas de moteur) (No instrument) (pas d'instrument) (Loading instrument...) (chargement de l'instrument...) Device Channel Canal de périphérique Audio Channel Canal Audio channel fx sends... envois d'effet de canal... Audio Audio MIDI MIDI New %1 device Nouveau périphérique %1 Device %1 Périphérique %1 Could not set device parameter value. Sorry. Impossible de régler la valeur de paramètre du péripérique. Navré. created. créé. Could not create device. Sorry. Impossible de créer le périphérique. Navré. deleted. effacé. Could not delete device. Sorry. Impossible de supprimer le périphérique. Navré. Could not set %1 parameter value. Sorry. Impossible de régler la valeur de paramètre %1. Navré. Audio Devices Périphériques audio MIDI Devices Périphériques MIDI Usage: %1 [options] [session-file] Utilisation : %1 [options] [fichier-de-session] Options: Options : Start linuxsampler server locally. Démarrez le serveur linuxsampler localement. Specify linuxsampler server hostname (default = localhost) Spécifier le nom d'hôte du serveur linuxsampler (par défaut = localhost) Specify linuxsampler server port number (default = 8888) Spécifier le numéro de port du serveur linuxsampler (par défaut = 8888) Show help about command line options. Afficher l'aide à propos des options en ligne de commande. Show version information Afficher les informations de version Session file (.lscp) Fichier de session .(lscp) [session-file] [fichier-de-session] Option -n requires an argument (hostname). L'option -n nécessite un argument (nom d'hôte). Option -p requires an argument (port). L'option -p requiert un argument (le port). Sent fine tuning settings. Envoyer les paramètres d'accordage fin. QSampler::AbstractDeviceParamModel Parameter Paramètre Value Valeur Description Description QSampler::ChannelForm Select an instrument of the file Sélectionnez un instrument du fichier You might want to enable instrument name retrieval in the settings dialog Vous pourriez souhaiter activer la récupération du nom d'instrument dans le dialogue des paramètres Some channel settings could not be set. Sorry. Certains paramètres de canal n'ont pas pu être réglés. Navré. Warning Attention Some channel settings have been changed. Do you want to apply the changes? Certains paramètres de canal ont été modifiés. Souhaitez-vous appliquer les modifications ? GIG Instrument files Fichiers instrument GIG SFZ Instrument files Fichiers instrument SFZ SF2 Instrument files Fichiers instrument SF2 All files Tous les fichiers Instrument files Fichiers instruments (New MIDI %1 device) (Nouveau périphérique MIDI %1) (New Audio %1 device) (Nouveau périphérique audio %1) QSampler::ChannelStrip Unavailable Indisponible Sorry, QSampler was built without FX send support! (Make sure you have a recent liblscp when recompiling QSampler) Navré, QSampler a été construit sans le support de l'envoi d'effet ! (Assurez-vous d'avoir un liblscp récent lors de la recompilation de Qsampler) Instruments Instruments All Tout ERR%1 ERR%1 QSampler::DeviceForm Warning Attention About to delete device: %1 Are you sure? Sur le point de supprimer le périphérique: %1 Êtes-vous sûr(e) ? Don't ask this again Ne pas redemander Ch&annel: C&аnal : P&ort: P&ort : &Create device &Créer un périphérique &Delete device &Supprimer un périphérique &Refresh &Rafraîchir QSampler::DeviceParamDelegate (none) (aucun) QSampler::DeviceStatusForm %1 Status Status %1 QSampler::InstrumentForm GIG Instrument files Fichiers instrument GIG SFZ Instrument files Fichiers instrument SFZ SF2 Instrument files Fichiers instrument SF2 Instrument files Fichiers instrument Warning Attention Some channel settings have been changed. Do you want to apply the changes? Certains paramètre de canal ont été modifiés. Souhaitez-vous appliquer les changements ? QSampler::InstrumentListForm Instrument Map Cartographie d'instrument (All) (Tous) Warning Attention About to delete instrument map entry: %1 Are you sure? Sur le point d'effacer l'entrée de cartographie d'instrument : %1 Êtes-vous sûr(e) ? Don't ask this again Ne pas redemander QSampler::InstrumentListModel Persistent Persistant On Demand Hold Maintien à la demande On Demand À la demande Name Nom Map Cartograpie Bank Banque Prog Prog Engine Moteur File Fichier Nr N. Vol Vol Mode Mode Could not get current list of MIDI instrument mappings. Sorry. Impossible d'obtenir la liste actuelle des cartographies d'instrument MIDI. Navré. QSampler::MainForm Master volume Volume général Connected Connecté MOD MOD Ready Prêt Untitled Sans titre New session: "%1". Nouvelle session : "%1". Open Session Ouvrir une session LSCP Session files Fichiers de session LSCP Save Session Sauvegarder la session Warning Attention The file already exists: "%1" Do you want to replace it? Le fichier existe déjà : "%1" Souhaitez-vous le remplacer ? The current session has been changed: "%1" Do you want to save the changes? La session actuelle a été modifiée : "%1" Souhaitez-vous sauvegarder les changements ? Could not open "%1" session file. Sorry. Impossible d'ouvrir le fichier-session "%1". Navré. Session loaded with errors from "%1". Sorry. Session chargée avec des erreurs depuis "%1". Navré. Open session: "%1". Ouvrir la session : "%1". Version Version File Fichier Date Date Device Périphérique MIDI instrument map Cartographie d'instrument MIDI Channel Canal Global volume level Niveau de volume global Some settings could not be saved to "%1" session file. Sorry. Certaines paramètres n'ont pas pu être sauvegardés dans le fichier-session "%1". Navré. Save session: "%1". Sauvegarder la session : "%1". Resetting the sampler instance will close all device and channel configurations. Please note that this operation may cause temporary MIDI and Audio disruption. Do you want to reset the sampler engine now? Réinitialiser l'instance de l'échantillonneur fermera tous les périphériques et configurations de canal. Veuillez noter que cette opération pourrait engendrer une interruption temporaire MIDI et audio. Souhaitez-vous réinitialiser le moteur de l'échantillonneur maintenant ? Could not reset sampler instance. Sorry. Impossible de réinitialiser l'instance de l'échantillonneur. Navré. Sampler reset. Réinitialisation de l'échantillonneur. New settings will be effective after restarting the client/server connection. Please note that this operation may cause temporary MIDI and Audio disruption. Do you want to restart the connection now? Les nouveaux paramètres seront effectifs après le redémarrage de la connexion client/serveur. Veuillez noter que cette opération pourrait engendrer une interruption temporaire MIDI et audio. Souhaitez-vous redémarrer la connexion maintenant ? About to remove channel: %1 Are you sure? Sur le point de retirer un canal : %1 Êtes-vous sûr(e) ? Using: Qt %1 Utilisant : Qt %1 LSCP Event: %1 data: %2 Événement LSCP : donnée %1 : %2 Don't ask this again Ne pas redemander Information Information Some settings may be only effective next time you start this program. Certains parapètres pourraient n'être effectif que lors du prochain démarrage de ce programme. Debugging option enabled. Option de débogage activée. GIG (libgig) file support disabled. Support de fichier GIG (libgig) désactivé. LSCP (liblscp) instrument_name support disabled. Support de l'instrument_name LSCP (liblscp) désactivé. Sampler channel Mute/Solo support disabled. Support du muet/solo de canal de l'échantillonneur désactivé. LSCP (liblscp) audio_routing support disabled. Support de l'audio_routing LSCP (liblscp) désactivé. Sampler channel Effect Sends support disabled. Support des envois d'effet de canal désactivé. Global volume support disabled. Support du volume global désactivé. MIDI instrument mapping support disabled. Support de la cartographie d'instrument MIDI désactivé. Instrument editing support disabled. Support de l'édition d'instrument désactivé. Channel MIDI event support disabled. Support d'événement MIDI de canal désactivé. Device MIDI event support disabled. Support d'événement MIDI de périphérique désactivé. Runtime max. voices / disk streams support disabled. Support des flux de disque / voix maximum d'exécution désactivé. Website Site ouèbe This program is free software; you can redistribute it and/or modify it Ce programme est un logiciel libre; vous pouvez le redistribuer et/ou le under the terms of the GNU General Public License version 2 or later. modifier en accord avec les termes de la licence GNU GPL version 2 ou ultérieure. About À propos Chromatic Chromatique Drum Kits Kits de batterie Could not get current list of channels. Sorry. Impossible d'obtenir la liste actuelle des canaux Navré. Error Erreur Don't show this again Ne plus afficher Could not start the LinuxSampler server. Maybe it is already started. Impossible de démarrer le serveur LinuxSampler. Peut être est-il déjà démarré. Server is starting... Le serveur démarre... Could not start server. Sorry. Impossible de démarrer le serveur. Navré. Server was started with PID=%1. Le serveur a été démarré avec PID=%1. The backend's fate ... Le décès de l'arrière-plan... Server is stopping... Le serveur s'arrête... Server is being forced... Le serveur est en train d'être forcé... Server was stopped with exit status %1. Le serveur a été arrêté avec un status de sortie %1. Client connecting... Connexion du client... Could not connect to server as client. Sorry. Impossible de se connecter au serveur en tant que client. Navré. Client receive timeout is set to %1 msec. La réception de l'expiration du client est réglée à %1 msec. Client connected. Client connecté. Client disconnecting... Déconnexion du client... Client disconnected. Client déconnecté. Trying to reconnect... Tentative de reconnection... You have the option to keep the sampler backend (LinuxSampler) running in the background. The sampler would continue to work according to your current sampler session and you could alter the sampler session at any time by relaunching QSampler. Do you want LinuxSampler to stop? Vous avez la possiblité de conserver l'échantillonneur (LinuxSampler) en arrière-plan. L'échantillonneur continuerait à fonctionner en fonction de votre session d'échantillonnage actuelle, et vous pourrez modifier la session d'échantillonnage à tout moment en relançant QSampler. Souhaitez-vous que LinuxSampler s'arrête ? QSampler::Messages Messages Messages Logging stopped --- %1 --- Identification arrêtée --- %1 --- Logging started --- %1 --- Identification démarrée --- %1 --- QSampler::OptionsForm This parameter is not supported by the current sampler version in use. Ce paramètre n'est pas supporté par la version de l'échantillonneur actuel en utilisation. The max. amount of voices the sampler shall process simultaneously. La quantité maximum de voix que l'échantillonneur peut traiter simultanément. The max. amount of disk streams the sampler shall process simultaneously. La quantité maximum de flux de disque que l'échantillonneur peut traiter simultanément. QSampler was built without support for this parameter. QSampler a été construit sans le support pour ce paramètre. Warning Attention Some settings have been changed. Do you want to apply the changes? Certains paramètres ont été modifiés. Souhaitez-vous appliquer les modifications ? Messages Log Journal de messages Log files Fichiers de journaux QSampler::PaletteForm Import File - %1 Importer le fichier - %1 Palette files (*.%1) Fichiers de palette (*.%1) Save Palette - %1 Sauvegarder la palette - %1 All files (*.*) Tous les fichiers (*.*) Warning - %1 Attention - %1 Could not import from file: %1 Sorry. Impossible d'importer depuis le fichier : %1 Navré. Export File - %1 Exporter le fichier - %1 Some settings have been changed. Do you want to discard the changes? Certains paramètres ont été modifié. Souhaitez-vous abandonner les modifications ? Some settings have been changed: "%1". Do you want to save the changes? Certains paramètres ont été modifié. "%1". Souhaitez-vous sauvegarder les modifications ? QSampler::PaletteForm::PaletteModel Color Role Role de couleur Active Actif Inactive Inactif Disabled Désactivé qsamplerChannelForm Browse for instrument filename Naviguer vers un nom de fichier d'instrument Instrument name Nome d'instrument &Engine: Mot&eur : Engine name Nom du moteur &Instrument: &Instrument : Instrument filename Nom de fichier d'instrument MIDI / Input MIDI / entrée MIDI input device Périphérique d'entrée MIDI MIDI input device setup Paramétrage de périphérique d'entrée MIDI &Map: &Cartographie : Instrument map Cartographie d'instrument MIDI input driver type Type de pilote d'entrée MIDI De&vice: &Périphérique : T&ype: T&ype : Channel Canal Filena&me: No&m de fichier &Port: &Port : MIDI input port number Numéro de port d'entrée MIDI &Channel: &Canal : MIDI input channel Canal d'entrée MIDI 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 All Tous Audio / Output Audio / sortie Audio output device Périphérique de sortie audio Audio output device setup Paramétrage de périphérique de sortie audio Audio output driver type Type de pilote de sortie audio Audio routing table Table de routage audio qsamplerChannelFxForm Channel Effects Canal d'effets FX Send Selection Sélection d'envoi d'effet Creates a new FX Send. You have to select 'Apply' afterwards to actually create it on sampler side. Crée un nouvel envoi d'effet. Vous devez sélectionner 'Appliquer' à la suite pour réellement le créer du côté de l'échantillonneur. Create Créer Schedules the selected FX send for deletion. You have to select 'Apply' afterwards to actually destroy it on sampler side. Prépare l'envoi de l'effet sélectionné pour suppression. Vous devez sélectionner 'Appliquer' à la suite pour réellement le détruire du côté de l'échantillonneur. Destroy Détruire FX Send's Parameters Paramètres d'envoi d'effet Send Depth MIDI Controller: Envoyer la profondeur Contrôleur MIDI : Current Depth: Profondeur actuelle : % % Audio Routing Routage audio qsamplerChannelStrip Channel setup Paramétrage de canal &Channel &Canal -- -- Instrument name Nom d'instrument MIDI port / channel Port/canal MIDI Channel Canal -- / -- -- / -- Instrument load status Status du chargement d'instrument MIDI activity Activité MIDI Channel mute Silencer le canal &Mute &Muet Channel solo Mettre le canal en solo &Solo &Solo Channel volume Volume du canal % % Edit Channel's Effect Settings Éditer les paramètres d'effet du canal &FX E&ffet Edit channel's instrument Éditer l'instrument de canal &Edit Édit&er Least buffer fill stream usage (%) Tampon minimal d'utilisation du remplissage de flux (%) Stream / Voice count Flux / comptage de voix --/-- --/-- qsamplerDeviceForm Device list Liste de périphérique Devices Périphériques Device name Nom de périphérique Dri&ver: &Pilote : Driver type name Nom du type de pilote Channel: Canal : Device port/channel Port/canal de périphérique Refresh device list view Rafraîchir l'affichage de la liste de périphériques &Refresh &Rafraîchir Create device Créer le périphérique &Create &Créer Delete device Supprimer le périphérique &Delete &Supprimer Close this dialog Fermer ce dialogue Close Fermer qsamplerInstrumentForm Instrument Instrument Engine name Nom du moteur &Engine: &Moteur : &Prog: &Prog : Program (0-127) Programme (0-127) Vol&ume: Vol&ume : &Map: &Cartographie : &Bank: &Banque : Bank (0-16383) Banque (0-16383) Instrument filename Nom de fichier d'instrument M&ode: M&ode : &Filename: Nom de &fichier : &Name: &Nom : Instrument map Cartographie d'instrument &Instrument: &Instrument : Instrument name Nom d'instrument Volume (%) Volume (%) % % Name Nom Load mode Mode de chargement Default Défaut On Demand À la demande On Demand Hold Maintien à la demande Persistent Persistant Browse for instrument filename Naviguer vers un nom de fichier d'instrument qsamplerInstrumentListForm Instruments Instruments New &Instrument... Nouvel &instrument... New Nouveau Ins Ins &Edit... Édit&er... Edit Éditer Enter Entrer &Delete &Effacer Delete Effacer Del Eff &Refresh &Rafraîchir Refresh Rafraîchir F5 F5 qsamplerMainForm &Edit &Éditer &View &Affichage MIDI Device Status Status du périphérique MIDI &Channels &Canaux &Help &Aide &File &Fichier Open &Recent Ouvrir &récent &New &Nouveau New Nouveau New session Nouvelle session New sampler session Nouvelle session d'échantillonneur Ctrl+N Ctrl+N &Open... &Ouvrir... Open Ouvrir Open session Ouvrir une session Open sampler session Ouvrir une session d'échantillonneur Ctrl+O Ctrl+O &Save &Sauvegarder Save Sauvegarder Save session Sauvegarder la session Save sampler session Sauvegarder la session d'échantillonneur Ctrl+S Ctrl+S Save &As... Sauvegarder &sous... Save As Sauvegarder sous Save current sampler session with another name Sauvegarder la session actuelle de l'échantillonneur avec un autre nom Rese&t Réini&tialiser Reset Réinitialiser Reset instance Réinitialiser Reset sampler instance Réinitialiser l'instance de l'échantillonneur Ctrl+R Ctrl+R &Restart &Redémarrer Restart Redémarrer Restart instance Redémarrer l'instance Restart sampler instance Redémarrer l'instance de l'échantillonneur Ctrl+Shift+R Ctrl+Shift+R E&xit &Quitter Exit Quitter Exit this application program Quitter ce programme d'application &Add Channel &Ajouter un canal Add Ajouter Add channel Ajouter un canal Add a new sampler channel Ajouter un nouveau canal d'échantillonneur Ctrl+A Ctrl+A &Remove Channel &Retirer le canal Remove Retirer Remove channel Retirer le canal Remove current sampler channel Retirer le canal d'échantillonneur actuel Ctrl+X Ctrl+X Re&set Channel Réinitiali&ser le canal Reset channel Réinitialiser le canal Reset current sampler channel Réinitialiser le canal de l'échantillonneur actuel R&eset All Channels Réinitialis&er tous les canaux Reset All Tout réinitialisé Reset all channels Réinitialiser tous les canaux Reset all sampler channels Réinitialiser tous les canaux de l'échantillonneur &Setup Channel... &Paramétrage du canal... Setup Paramétrage Setup channel Paramétrage du canal Setup current sampler channel Paramétrage du canal actuel de l'échantillonneur F2 F2 Ed&it Channel... Éd&iter le canal... Edit Éditer Edit channel Éditer le canal Edit current sampler channel Éditer le canal actuel de l'échantillonneur F9 F9 &Menubar Barre de &menu Menubar Barre de menu Show/hide menubar Afficher/cacher la barre de menu Show/hide the main program window menubar Afficher/cacher la barre de menu de la fenêtre principale du programme Ctrl+M Ctrl+M &Toolbar Barre d'ou&tils Toolbar Barre d'outils Show/hide toolbar Afficher/cacher la barre d'outils Show/hide main program window toolbars Afficher/cacher la barre d'outils de la fenêtre principale du programme Ctrl+T Ctrl+T &Statusbar Barre de &status Statusbar Barre de status Show/hide statusbar Afficher/cacher la barre de status Show/hide the main program window statusbar Afficher/cacher la barre de status de la fenêtre principale du programme M&essages M&essages Messages Messages Show/hide messages Afficher/cacher les messages Show/hide the messages window Afficher/cacher la fenêtre des messages &Instruments &Instruments Instruments Instruments MIDI instruments configuration Configuration des instruments MIDI Show/hide the MIDI instruments configuration window Afficher/cacher la fenêtre de configuration des instruments MIDI F10 F10 &Devices &Périphériques Devices Périphériques Device configuration Configuration du périphérique Show/hide the device configuration window Afficher/cacher la fenêtre de configuration du périphérique F11 F11 &Options... &Options... Options Options General options Options générales Change general application program options Modifier les options générales du programme d'application F12 F12 &Arrange &Arranger Arrange Arranger Arrange channels Arranger les canaux Line up all channel strips Aligner toutes les tranches de canal F5 F5 A&uto Arrange Arrangerment &automatique Auto Arrange Arrangement automatique Auto-arrange channels Arranger automatiquement les canaux Auto-arrange channel strips Arranger automatiquement les tranches de canal &About... À &propos... About À propos Show information about this application program Afficher des informations à propos de ce programme d'application About &Qt... À propos de &Qt... About Qt À propos de Qt Show information about the Qt toolkit Afficher des informations à propos de la boîte à outils Qt qsamplerOptionsForm &Server &Serveur Settings Paramétrages &Host: &Hôte : LinuxSampler server listener port number Numéro de port d'écoute du serveur LinuxSampler 8888 8888 &Port: &Port : LinuxSampler server host name or address Adresse ou nom de l'hôte du serveur LinuxSampler localhost localhost &Command line: Ligne de &commande : Whether to start the LinuxSampler server on local machine Si l'on doit démarrer le serveur LinuxSampler sur la machine locale &Start server locally &Démarrer le serveur localement Command line to start LinuxSampler server locally Ligne de commande pour démarrer le serveur localement linuxsampler linuxsampler Start &delay: &Délai de démarrage : Delay time in seconds after server startup Temps de délai en seconde après que le serveur démarre secs secs Receive timeout in milliseconds Délai d'expiration en millisecondes msec msec &Timeout: Expira&tion : Logging Journalisation Messages log file Fichier du journal de messages Browse for the messages log file location Navigatuer vers l'emplacement du fichier de journalisation des messages ... ... Whether to activate a messages logging to file. Si l'on doit activer la journalisation des messages dans un fichier. &Messages log file: Fichier de journalisation des &messages : Whether to ask for session reset Si l'on doit demander avant de réinitialiser une session. &Confirm session reset &Confirmation de réinitialiser de session. Whether to ask for session restart Si l'on doit demander avant de redémarrer une session. &Confirm session restart &Confirmation le redémarrage d'une session. Whether to show session errors Si l'on doit afficher les erreurs de session. &Confirm session errors &Confirmation des erreurs de session. &Tuning &Accordage Options Options Limits Limites Maximum number of voices Nombre maximum de voix Maximum number of disk streams Nombre maximum de flux de disque &Display &Affichage Channels Canaux Sample channel display font display Police d'affichage de l'affichage de canal d'échantillon Select font for the channel display Sélectionner une police pour l'affichage de canal &Font... &Police... Whether to refresh the channels view automatically Si l'on doit rafraîchir l'affichage des canaux automatiquement &Auto refresh: Rafraîchissement &automatique : Maximum &volume: &Volume maximum : Time in milliseconds between each auto-refresh cycle Temps en millisecondes entre chaque cycle de rafraîchissement automatique Upper limit for the sampler channel volume setting Limite haute pour le paramètrage du volume de canal de l'échantillonneur % % Whether to enable a shiny glass light effect on the channel display Si l'on doit activer un effet de reflet lumineux brillant sur l'affichage de canal Display shiny glass light &effect Affichage de l'&effet lumineux brillant Messages Messages &General Général Sample messages text font display Affichage de police de texte des messages d'échantillon Select font for the messages text display Sélectionner la police pour l'affichage des messages de texte Whether to keep a maximum number of lines in the messages window Si l'on doit garder un nombre maximum de lignes dans la fenêtre des messages &Messages limit: Limite des &messages : The maximum number of message lines to keep in view Nombre maximum de lignes de message à conserver affichées lines lignes Other Autre Whether to ask for confirmation on removals Si l'on doit demander une confirmation lors des suppressions &Confirm removals &Confirmer les suppressions &Number of recent files: &Nombre de fichiers récents : The maximum number of recent files to keep in menu Le nombre maximum de fichiers récents à conserver dans le menu Whether to keep all child windows on top of the main window Si l'on doit conserver toutes les fenêtres-enfant au dessus de la fenêtre principale &Keep child windows always on top &Toujours conserver les fenêtres-enfant au dessus Whether to capture standard output (stdout/stderr) into messages window Si l'on doit capturer la sortie standard (stdout/stderr) dans la fenêtre de messages Capture standard &output Capturer la s&ortie standard Whether to show the complete directory path of loaded session files Si l'on montre le chemin complet du répertoire des fichiers-session chargés Show complete &path of session files Afficher le chemin com&plet des fichiers de session Whether to show the actual instrument names as read from instrument file (using libgig) Si on montre les noms des instruments courants en les lisant depuis le fichier d'instrument (en utilisant libgig) Show actual &instrument names Montrer les noms des &instruments courants Custom Personnalisé &Color palette theme: Thème de palette de &couleur : Custom color palette theme Theme de palette de couleur personnalisé Wonton Soup DO NOT TRANSLATE KXStudio DO NOT TRANSLATE Manage custom color palette themes Gérer les thèmes de palette de couleur personnalisés &Widget style theme: Thème de style de &widget : Custom widget style theme Thème de style de widget personnalisé : Defaults Défaut &Base font size: Taille de police de &base : Base application font size (pt.) Taille de police de base (pt.) pour l'application Maximum &number of voices: &Nombre maximum de voix : Maximum number of disk &streams: Nombre maximum de flux de di&sques : (default) (défaut) 6 6 7 7 8 8 9 9 10 10 11 11 12 12 qsamplerPaletteForm Color Themes Thèmes de couleur Name Nom Current color palette name Nom de la palette de couleur actuelle Save current color palette name Sauvegarder le nom de la palette de couleur actuelle Save Sauvegarder Delete current color palette name Effacer le nom de la palette de couleur actuelle Delete Effacer Palette Palette Current color palette Palette de couleur actuelle Generate: Générer : Base color to generate palette Couleur de base pour générer la palette Reset all current palette colors Réinitialiser toutes les couleurs de la palette actuelle Reset Réinitialiser Import a custom color theme (palette) from file Importer un thème (palette) de couleur personnalisé depuis un fichier Import... Importer... Export a custom color theme (palette) to file Exporter un thème (palette) de couleur personnalisé vers un fichier Export... Exporter... Show Details Afficher les détails qsampler-1.0.0/src/translations/PaxHeaders/qsampler_cs.ts0000644000000000000000000000013214634065603020612 xustar0030 mtime=1718643587.395448566 30 atime=1718643587.395448566 30 ctime=1718643587.395448566 qsampler-1.0.0/src/translations/qsampler_cs.ts0000644000175000001440000035023014634065603020605 0ustar00rncbcusers QObject Could not add channel. Sorry. Nepodařilo se přidat kanál. Promiňte. added. přidán. Could not remove channel. Sorry. Nepodařilo se odstranit kanál. Promiňte. removed. odstraněn. New Channel Nový kanál Channel %1 Kanál %1 Engine: %1. Stroj: %1. Instrument: "%1" (%2). Nástroj: "%1" (%2). MIDI driver: %1. Ovladač MIDI: %1. MIDI device: %1. Zařízení MIDI: %1. MIDI port: %1. Přípojka MIDI: %1. MIDI channel: %1. Kanál MIDI: %1. MIDI map: %1. Přiřazení MIDI: %1. Audio device: %1. Zvukové zařízení: %1. Audio driver: %1. Zvukový ovladač: %1. Volume: %1. Hlasitost: %1. Mute: %1. Ztlumení: %1. Solo: %1. Sólo: %1. Audio Channel: %1 -> %2. Zvukový kanál: %1 -> %2. Could not get channel information. Sorry. Nepodařilo se získat informaci o kanále. Promiňte. (none) (žádná) reset. znovu nastaven. Could not launch an appropriate instrument editor for the given instrument! Make sure you have an appropriate instrument editor like 'gigedit' installed and that it placed its mandatory DLL file into the sampler's plugin directory. Pro zadaný nástroj se nepodařilo spustit příslušný nástrojový editor! Ujistěte se, že máte nainstalován vhodný editor nástrojů, jakým je 'gigedit', a že tento umístil svůj povinný soubor DLL do adresáře sampleru, ve kterém jsou přídavné moduly. edit instrument. upravit nástroj. Sorry, QSampler was compiled for a version of liblscp which lacks this feature. You may want to update liblscp and recompile QSampler afterwards. Promiňte, ale QSampler byl sestaven pro verzi liblscp, která postrádá tuto funkci. Můžete chtít povýšit liblscp a sestavit QSampler později znovu. setup... nastavit... (No engine) (Není stroj) (No instrument) (Není nástroj) (Loading instrument...) (Nahrává se nástroj...) Device Channel Kanál zařízení Audio Channel Zvukový kanál channel fx sends... kanál fx posílá... Audio Zvuk MIDI MIDI New %1 device Nové zařízení %1 Device %1 Zařízení %1 Could not set device parameter value. Sorry. Nepodařilo se nastavit hodnotu parametru pro zařízení. Promiňte. created. vytvořeno. Could not create device. Sorry. Nepodařilo se vytvořit zařízení Promiňte. deleted. smazáno. Could not delete device. Sorry. Nepodařilo se smazat zařízení. Promiňte. Could not set %1 parameter value. Sorry. Nepodařilo se nastavit %1 hodnotu parametru. Promiňte. Audio Devices Zvuková zařízení MIDI Devices Zařízení MIDI Usage: %1 [options] [session-file] Použití: %1 [volby] [soubor se sezením] Options: Volby: Start linuxsampler server locally. Spustit server LinuxSampler místně. Specify linuxsampler server hostname (default = localhost) Zadat název serveru LinuxSampler (výchozí = localhost) Specify linuxsampler server port number (default = 8888) Zadat číslo přípojky serveru LinuxSampler (výchozí = 8888) Show help about command line options. Ukázat nápovědu k volbám příkazového řádku. Show version information Ukázat informace o verzi Session file (.lscp) Soubor se sezením (.lscp) [session-file] [soubor se sezením] Option -n requires an argument (hostname). Volba -n vyžaduje argument (název serveru). Option -p requires an argument (port). Volba -p vyžaduje argument (název přípojky - brány; port). Sent fine tuning settings. Poslána nastavení pěkného ladění. QSampler::AbstractDeviceParamModel Parameter Parametr Value Hodnota Description Popis QSampler::ChannelForm Select an instrument of the file Vybrat nástroj souboru You might want to enable instrument name retrieval in the settings dialog Získání názvu nástroje povolíte v dialogu nastavení Some channel settings could not be set. Sorry. Některá nastavení kanálu se nepodařilo nastavit. Promiňte. Warning Varování Some channel settings have been changed. Do you want to apply the changes? Některá nastavení kanálu byla změněna. Chcete použít změny? GIG Instrument files Soubory s nástroji GIG SFZ Instrument files Soubory s nástroji SFZ SF2 Instrument files Soubory s nástroji SF2 All files Všechny soubory Instrument files Soubory s nástroji (New MIDI %1 device) (Nové zařízení MIDI %1) (New Audio %1 device) (Nové zvukové zařízení %1) QSampler::ChannelStrip Unavailable Nedostupné Sorry, QSampler was built without FX send support! (Make sure you have a recent liblscp when recompiling QSampler) Promiňte, ale QSampler byl sestaven bez podpory pro poslání FX. (Ujistěte se, že když sestavujete QSampler, máte poslední liblscp) Instruments Nástroje All Vše ERR%1 ERR%1 QSampler::DeviceForm Warning Varování About to delete device: %1 Are you sure? Chystáte se smazat zařízení: %1 Jste si jistý? Don't ask this again Neptat se znovu Ch&annel: &Каnál: P&ort: &Přípojka: &Create device &Vytvořit zařízení &Delete device &Smazat zařízení &Refresh &Obnovit QSampler::DeviceParamDelegate (none) (žádný) QSampler::DeviceStatusForm %1 Status %1 Stav QSampler::InstrumentForm GIG Instrument files Soubory s nástroji GIG SFZ Instrument files Soubory s nástroji SFZ SF2 Instrument files Soubory s nástroji SF2 Instrument files Soubory s nástroji Warning Varování Some channel settings have been changed. Do you want to apply the changes? Některá nastavení kanálu byla změněna. Chcete použít změny? QSampler::InstrumentListForm Instrument Map Zobrazení nástrojů (All) (Vše) Warning Varování About to delete instrument map entry: %1 Are you sure? Chystáte se smazat položku v zobrazení nástrojů: %1 Jste si jistý? Don't ask this again Neptat se znovu QSampler::InstrumentListModel Persistent Trvalý On Demand Hold Držení na požádání On Demand Na požádání Name Název Map Přiřazení Bank Banka Prog Program Engine Stroj File Soubor Nr Číslo Vol Hlasitost Mode Režim Could not get current list of MIDI instrument mappings. Sorry. Nepodařilo se získat nynější seznam přiřazení MIDI nástrojů. Promiňte. QSampler::MainForm Master volume Hlavní hlasitost Connected Spojeno MOD MOD Ready Připraven Untitled Bez názvu New session: "%1". Nové sezení: "%1". Open Session Otevřít sezení LSCP Session files Soubory se sezením LSCP Save Session Uložit sezení Warning Varování The file already exists: "%1" Do you want to replace it? Soubor již existuje: "%1" Chcete jej nahradit? The current session has been changed: "%1" Do you want to save the changes? Nynější sezení bylo změněno: "%1" Chcete uložit změny? Could not open "%1" session file. Sorry. Nepodařilo se otevřít soubor se sezením "%1". Promiňte. Session loaded with errors from "%1". Sorry. Sezení nahráno s chybami z "%1". Promiňte. Open session: "%1". Otevřít sezení: "%1". Version Verze File Soubor Date Datum Device Zařízení MIDI instrument map Zobrazení nástrojů MIDI Channel Kanál Global volume level Úroveň celkové hlasitosti Some settings could not be saved to "%1" session file. Sorry. Některá nastavení se nepodařilo uložit. do souboru se sezením "%1". Promiňte. Save session: "%1". Uložit sezení: "%1". Resetting the sampler instance will close all device and channel configurations. Please note that this operation may cause temporary MIDI and Audio disruption. Do you want to reset the sampler engine now? Přenastavení řízení sampleru uzavře všechna nastavení zařízení a kanálů. Uvědomte si, prosím, že tato operace může způsobit dočasné rušení MIDI a zvuku. Chcete přenastavit stroj sampleru nyní? Could not reset sampler instance. Sorry. Nepodařilo se přenastavit řízení sampleru. Promiňte. Sampler reset. Přenastavení sampleru. New settings will be effective after restarting the client/server connection. Please note that this operation may cause temporary MIDI and Audio disruption. Do you want to restart the connection now? Nová nastavení se projeví po znovuspuštění spojení klient/server. Uvědomte si, prosím, že tato operace může způsobit dočasné rušení MIDI a zvuku. Chcete spojení spustit znovu nyní? About to remove channel: %1 Are you sure? Chystáte se odstranit kanál: %1 Jste si jistý? Using: Qt %1 Používající: Qt %1 LSCP Event: %1 data: %2 Událost LSCP: %1 data: %2 Don't ask this again Neptat se znovu Information Informace Some settings may be only effective next time you start this program. Některá nastavení se projeví až tehdy, když příště spustíte tento program. Debugging option enabled. Povolena volba ladění. GIG (libgig) file support disabled. Zakázána podpora pro soubor GIG (libgig). LSCP (liblscp) instrument_name support disabled. Zakázána podpora pro instrument_name v LSCP (liblscp). Sampler channel Mute/Solo support disabled. Zakázána podpora pro Ztlumení/Sólo kanálu sampleru. LSCP (liblscp) audio_routing support disabled. Zakázána podpora pro audio_routing v LSCP (liblscp). Sampler channel Effect Sends support disabled. Zakázána podpora pro poslání efektu kanálu sampleru. Global volume support disabled. Zakázána podpora pro celkovou hlasitost. MIDI instrument mapping support disabled. Zakázána podpora pro zobrazení nástrojů MIDI. Instrument editing support disabled. Zakázána podpora pro úpravy nástrojů. Channel MIDI event support disabled. Zakázána podpora pro události kanálů MIDI. Device MIDI event support disabled. Zakázána podpora pro události zařízení MIDI. Runtime max. voices / disk streams support disabled. Zakázána podpora pro největší množství hlasů/diskových proudy běžících současně. Website Stránky This program is free software; you can redistribute it and/or modify it Tento program je svobodným programem. Můžete jej šířit a/nebo upravit under the terms of the GNU General Public License version 2 or later. za podmínek GNU General Public License ve verzi 2 nebo pozdější. About O programu Chromatic Chromatický Drum Kits Bicí Could not get current list of channels. Sorry. Nepodařilo se získat nynější seznam kanálů. Promiňte. Error Chyba Don't show this again Neukazovat znovu Could not start the LinuxSampler server. Maybe it is already started. Nepodařilo se spustit server LinuxSampler. Možná je už spuštěn. Server is starting... Spouští se server... Could not start server. Sorry. Nepodařilo se spustit server. Promiňte. Server was started with PID=%1. Server byl spuštěn s PID=%1. The backend's fate ... Osud zadní části programu... Server is stopping... Zastavuje se server... Server is being forced... Server je nucen... Server was stopped with exit status %1. Server byl zastaven se stavem ukončení %1. Client connecting... Připojuje se klient... Could not connect to server as client. Sorry. Nepodařilo se připojit k serveru jako klient. Promiňte. Client receive timeout is set to %1 msec. Přerušení přijetí klienta je nastavena na %1 msec. Client connected. Klient připojen. Client disconnecting... Odpojuje se klient... Client disconnected. Klient odpojen. Trying to reconnect... Pokouší se o znovupřipojení... You have the option to keep the sampler backend (LinuxSampler) running in the background. The sampler would continue to work according to your current sampler session and you could alter the sampler session at any time by relaunching QSampler. Do you want LinuxSampler to stop? Máte volbu, kterou zadní část programu (LinuxSampler) udržujete běžící na pozadí. Sampler bude pokračovat v práci podle vašeho nynějšího sezení sampleru a vy můžete změnit sezení sampleru kdykoli novým spuštěním QSampleru. Chcete zastavit LinuxSampler? QSampler::Messages Messages Hlášení Logging stopped --- %1 --- Vedení zápisu zastaveno --- %1 --- Logging started --- %1 --- Vedení zápisu spuštěno --- %1 --- QSampler::OptionsForm This parameter is not supported by the current sampler version in use. Tento parametr není podporován současnou používanou verzí sampleru. The max. amount of voices the sampler shall process simultaneously. Největší počet hlasů, které vzorkovač (sampler) má souběžně zpracovat. The max. amount of disk streams the sampler shall process simultaneously. Největší počet diskových proudů, které vzorkovač (sampler) má souběžně zpracovat. QSampler was built without support for this parameter. QSampler byl sestaven bez podpory pro tento parametr. Warning Varování Some settings have been changed. Do you want to apply the changes? Některá nastavení byla změněna. Chcete použít změny? Messages Log Zápis hlášení Log files Soubory s hlášeními QSampler::PaletteForm Import File - %1 Zavést soubor - %1 Palette files (*.%1) Soubory s paletami (*.%1) Save Palette - %1 Uložit paletu - %1 All files (*.*) Všechny soubory (*.*) Warning - %1 Varování - %1 Could not import from file: %1 Sorry. Nepodařilo se zavést ze souboru. %1 Promiňte. Export File - %1 Vyvést soubor - %1 Some settings have been changed. Do you want to discard the changes? Některá nastavení byla změněna. Chcete zahodit změny? Some settings have been changed: "%1". Do you want to save the changes? Některá nastavení byla změněna: "%1" Chcete uložit změny? QSampler::PaletteForm::PaletteModel Color Role Barevná role Active Činný Inactive Nečinný Disabled Zakázáno qsamplerChannelForm Browse for instrument filename Procházet názvy souborů s nástroji Instrument name Název nástroje &Engine: &Stroj: Engine name Název stroje &Instrument: &Nástroj: Instrument filename Název souboru s nástrojem MIDI / Input MIDI/Vstup MIDI input device Vstupní zařízení pro MIDI MIDI input device setup Nastavení vstupního zařízení pro MIDI &Map: &Zobrazení: Instrument map Zobrazení nástrojů MIDI input driver type Typ ovladače pro vstup MIDI De&vice: &Zařízení: T&ype: &Typ: Channel Kanál Filena&me: &Název souboru: &Port: &Přípojka: MIDI input port number Číslo přípojky pro vstup MIDI &Channel: &Каnál: MIDI input channel Vstupní kanál MIDI 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 All Vše Audio / Output Zvuk/Výstup Audio output device Zvukové výstupní zařízení Audio output device setup Nastavení zvukového výstupního zařízení Audio output driver type Typ ovladače pro výstup zvuku Audio routing table Tabulka vedení zvuku qsamplerChannelFxForm Channel Effects Efekty pro kanál FX Send Selection Výběr poslání efektů (FX) Creates a new FX Send. You have to select 'Apply' afterwards to actually create it on sampler side. Vytvoří nové poslání efektů (FX). Poté musíte vybrat "Použít", abyste je skutečně vytvořil na straně sampleru. Create Vytvořit Schedules the selected FX send for deletion. You have to select 'Apply' afterwards to actually destroy it on sampler side. Rozvrhne vybrané poslání efektů (FX) pro smazání. Poté musíte vybrat "Použít", abyste je skutečně odstranil na straně sampleru. Destroy Odstranit FX Send's Parameters Parametry pro poslání efektů (FX) Send Depth MIDI Controller: Poslat ovladač hloubky MIDI: Current Depth: Nynější hloubka: % % Audio Routing Vedení zvuku qsamplerChannelStrip Channel setup Nastavení kanálu &Channel &Каnál -- -- Instrument name Název nástroje MIDI port / channel Přípojka/kanál MIDI Channel Kanál -- / -- -- / -- Instrument load status Stav nahrání nástroje MIDI activity Činnost MIDI Channel mute Ztlumení kanálu &Mute &Ztlumení Channel solo Sólo kanálu &Solo &Sólo Channel volume Hlasitost kanálu % % Edit Channel's Effect Settings Upravit nastavení efektů kanálu &FX &Efekty (FX) Edit channel's instrument Upravit nástroj kanálu &Edit &Upravit Least buffer fill stream usage (%) Použití proudu posledního naplnění vyrovnávací paměti (%) Stream / Voice count Počet proudů/hlasů --/-- --/-- qsamplerDeviceForm Device list Seznam zařízení Devices Zařízení Device name Název zařízení Dri&ver: &Ovladač: Driver type name Název pro typ ovladače Channel: Kanál: Device port/channel Přípojka/kanál zařízení Refresh device list view Obnovit pohled na seznam zařízení &Refresh &Obnovit Create device Vytvořit zařízení &Create &Vytvořit Delete device Smazat zařízení &Delete &Smazat Close this dialog Zavřít tento dialog Close Zavřít qsamplerInstrumentForm Instrument Nástroj Engine name Název stroje &Engine: &Stroj: &Prog: &Program: Program (0-127) Program (0-127) Vol&ume: &Hlasitost: &Map: &Zobrazení: &Bank: &Banka: Bank (0-16383) Banka (0-16383) Instrument filename Název souboru s nástrojem M&ode: &Režim: &Filename: &Název souboru: &Name: &Název: Instrument map Zobrazení nástrojů &Instrument: &Nástroj: Instrument name Název nástroje Volume (%) Hlasitost (%) % % Name Název Load mode Nahrát režim Default Výchozí On Demand Na požádání On Demand Hold Držení na požádání Persistent Trvalý Browse for instrument filename Procházet názvy souborů s nástroji qsamplerInstrumentListForm Instruments Nástroje New &Instrument... &Nový nástroj... New Nový Ins Nástroj &Edit... &Upravit... Edit Upravit Enter Enter &Delete &Smazat Delete Smazat Del Del &Refresh &Obnovit Refresh Obnovit F5 F5 qsamplerMainForm &Edit &Úpravy &View &Pohled MIDI Device Status Stav zařízení MIDI &Channels &Kanály &Help &Nápověda &File &Soubor Open &Recent Otevřít &nedávný &New &Nový New Nový New session Nové sezení New sampler session Nové sezení sampleru Ctrl+N Ctrl+N &Open... &Otevřít... Open Otevřít Open session Otevřít sezení Open sampler session Otevřít sezení sampleru Ctrl+O Ctrl+O &Save &Uložit Save Uložit Save session Uložit sezení Save sampler session Uložit sezení sampleru Ctrl+S Ctrl+S Save &As... Uložit &jako... Save As Uložit jako Save current sampler session with another name Uložit nynější sezení sampleru pod jiným názvem Rese&t Nastavit &znovu Reset Nastavit znovu Reset instance Nastavit znovu řízení Reset sampler instance Nastavit znovu řízení sampleru Ctrl+R Ctrl+R &Restart &Spustit znovu Restart Spustit znovu Restart instance Spustit znovu řízení Restart sampler instance Spustit znovu řízení sampleru Ctrl+Shift+R Ctrl+Shift+R E&xit &Ukončit Exit Ukončit Exit this application program Ukončit program této aplikace &Add Channel &Přidat kanál Add Přidat Add channel Přidat kanál Add a new sampler channel Přidat nový kanál do sampleru Ctrl+A Ctrl+A &Remove Channel &Odstranit kanál Remove Odstranit Remove channel Odstranit kanál Remove current sampler channel Odstranit nynější kanál ze sampleru Ctrl+X Ctrl+X Re&set Channel &Nastavit znovu kanál Reset channel Nastavit znovu kanál Reset current sampler channel Na&stavit znovu nynější kanál v sampleru R&eset All Channels Na&stavit znovu všechny kanály Reset All Nastavit znovu vše Reset all channels Nastavit znovu všechny kanály Reset all sampler channels Nastavit znovu všechny kanály v sampleru &Setup Channel... &Nastavit kanál... Setup Nastavit Setup channel Nastavit kanál Setup current sampler channel Nastavit nynější kanál v sampleru F2 F2 Ed&it Channel... &Upravit kanál... Edit Upravit Edit channel Upravit kanál Edit current sampler channel Upravit nynější kanál v sampleru F9 F9 &Menubar &Pruh s nabídkami Menubar Pruh s nabídkami Show/hide menubar Ukázat/skrýt pruh s nabídkami Show/hide the main program window menubar Ukázat/skrýt pruh s nabídkami v hlavním programovém okně Ctrl+M Ctrl+M &Toolbar &Pruh s nástroji Toolbar Pruh s nástroji Show/hide toolbar Ukázat/skrýt pruh s nástroji Show/hide main program window toolbars Ukázat/skrýt pruhy s nástroji v hlavním programovém okně Ctrl+T Ctrl+T &Statusbar &Stavový řádek Statusbar Stavový řádek Show/hide statusbar Ukázat/skrýt stavový řádek Show/hide the main program window statusbar Ukázat/skrýt stavový řádek v hlavním programovém okně M&essages &Hlášení Messages Hlášení Show/hide messages Ukázat/skrýt hlášení Show/hide the messages window Ukázat/skrýt okno s hlášeními &Instruments &Nástroje Instruments Nástroje MIDI instruments configuration Nastavení nástrojů MIDI Show/hide the MIDI instruments configuration window Ukázat/skrýt okno s nastavením pro nástroje F10 F10 &Devices &Zařízení Devices Zařízení Device configuration Nastavení zařízení Show/hide the device configuration window Ukázat/skrýt okno s nastavením pro zařízení F11 F11 &Options... &Volby... Options Volby General options Obecné volby Change general application program options Změnit obecné volby pro použití programu F12 F12 &Arrange &Uspořádat Arrange Uspořádat Arrange channels Uspořádat kanály Line up all channel strips Seřadit všechny proužky kanálů F5 F5 A&uto Arrange &Uspořádat automaticky Auto Arrange Uspořádat automaticky Auto-arrange channels Uspořádat automaticky kanály Auto-arrange channel strips Uspořádat automaticky proužky kanálů &About... &O programu... About O programu Show information about this application program Ukázat informace o tomto programu About &Qt... О &Qt... About Qt O Qt Show information about the Qt toolkit Ukázat informace o sadě nástrojů Qt qsamplerOptionsForm &Server &Server Settings Nastavení &Host: &Hostitel: LinuxSampler server listener port number Číslo naslouchací přípojky pro server LinuxSampler 8888 8888 &Port: &Přípojka: LinuxSampler server host name or address Název hostitele nebo adresa pro server LinuxSampler localhost localhost &Command line: &Příkazový řádek: Whether to start the LinuxSampler server on local machine Spustit server LinuxSampler na místním stroji &Start server locally &Spustit server místně Command line to start LinuxSampler server locally Příkazový řádek pro místní spuštění serveru LinuxSampler linuxsampler linuxsampler Start &delay: &Zpoždění spuštění: Delay time in seconds after server startup Čas zpoždění v sekundách po rozběhnutí serveru secs s Receive timeout in milliseconds Přijmout přerušení v ms msec ms &Timeout: &Přerušení: Logging Vedení zápisů Messages log file Soubor se zápisy hlášení LinuxSampleru Browse for the messages log file location Procházet umístění souboru se zápisem hlášení ... ... Whether to activate a messages logging to file. Spustit zápis hlášení do souboru. &Messages log file: Soubor se &zápisem hlášení: Whether to ask for session reset Žádat o potvrzení při vynulování sezení &Confirm session reset &Potvrdit vynulování sezení Whether to ask for session restart Žádat o potvrzení při restartování sezení &Confirm session restart &Potvrdit restartování sezení Whether to show session errors Ukázat chyby sezení &Confirm session errors &Potvrdit ukázání chyb sezení &Tuning &Ladění Options Volby Limits Mezní hodnoty Maximum number of voices Nejvyšší počet hlasů Maximum number of disk streams Nejvyšší počet diskových proudů &Display &Zobrazení Channels Kanály Sample channel display font display Zobrazení písma při zobrazení kanálu s ukázkou Select font for the channel display Vybrat písmo pro zobrazení kanálu &Font... &Písmo... Whether to refresh the channels view automatically Obnovit pohled na kanály automaticky &Auto refresh: &Automatické obnovení: Maximum &volume: Nejvyšší &hlasitost: Time in milliseconds between each auto-refresh cycle Čas v milisekundách mezi každým kolem automatického obnovení Upper limit for the sampler channel volume setting Horní mez pro nastavení hlasitosti kanálů v zařízení pro míchání hudby % % Whether to enable a shiny glass light effect on the channel display Povolit lesklý skelný světelný efekt při zobrazení kanálu Display shiny glass light &effect Zobrazit lesklý skelný světelný &efekt Messages Hlášení &General &Obecné Sample messages text font display Zobrazení písma textu hlášení o ukázkách Select font for the messages text display Vybrat písmo pro zobrazení textu hlášení Whether to keep a maximum number of lines in the messages window Zachovat nejvyšší počet řádků v okně s hlášeními &Messages limit: Mezní hodnota pro hlášení: The maximum number of message lines to keep in view Nejvyšší počet řádků s hlášením, který se bude uchovávat v okně lines řádky Other Jiné Whether to ask for confirmation on removals Žádat o potvrzení při odstranění &Confirm removals &Potvrdit odstranění &Number of recent files: &Počet nedávných souborů: The maximum number of recent files to keep in menu Nejvyšší počet nedávných souborů, který se bude uchovávat v nabídce Whether to keep all child windows on top of the main window Uchovávat všechna další okna nahoře nad hlavním oknem &Keep child windows always on top &Uchovávat další okna vždy nahoře Whether to capture standard output (stdout/stderr) into messages window Zachytit obvyklý výstup (stdout/stderr) do okna s hlášeními Capture standard &output Zachytit obvyklý &výstup Whether to show the complete directory path of loaded session files Ukázat úplnou cestu k adresáři s nahranými soubory se sezeními Show complete &path of session files Ukázat úplnou &cestu k souborům se sezeními Whether to show the actual instrument names as read from instrument file (using libgig) Ukázat skutečné názvy nástrojů, jak jsou přečteny ze souborů s nástroji (pomocí libgig) Show actual &instrument names Ukázat skutečné názvy &nástrojů Custom Vlastní &Color palette theme: &Motiv palety barev: Custom color palette theme Vlastní motiv palety barev Wonton Soup DO NOT TRANSLATE KXStudio DO NOT TRANSLATE Manage custom color palette themes Spravovat vlastní motivy palety barev &Widget style theme: Motiv stylu &prvku: Custom widget style theme Vlastní motiv stylu prvku Defaults Výchozí &Base font size: &Velikost písma uživatelského rozhraní: Base application font size (pt.) Základní velikost písma v programu (v bodech) Maximum &number of voices: Nejvyšší &počet hlasů: Maximum number of disk &streams: Nejvyšší počet diskových &proudů: (default) (výchozí) 6 6 7 7 8 8 9 9 10 10 11 11 12 12 qsamplerPaletteForm Color Themes Barevné motivy Name Název Current color palette name Název nynější palety barev Save current color palette name Uložit název nynější palety barev Save Uložit Delete current color palette name Smazat název nynější palety barev Delete Smazat Palette Paleta Current color palette Nynější paleta barev Generate: Vytvořit: Base color to generate palette Základní barva pro vytvoření palety Reset all current palette colors Nastavit všechny barvy palety barev na výchozí Reset Obnovit výchozí Import a custom color theme (palette) from file Zavést vlastní barevný motiv (paleta) ze souboru Import... Zavést... Export a custom color theme (palette) to file Vyvést vlastní barevný motiv (paleta) do souboru Export... Vyvést... Show Details Ukázat podrobnosti qsampler-1.0.0/src/PaxHeaders/qsamplerDeviceStatusForm.h0000644000000000000000000000013214634065603020355 xustar0030 mtime=1718643587.393448566 30 atime=1718643587.393448566 30 ctime=1718643587.393448566 qsampler-1.0.0/src/qsamplerDeviceStatusForm.h0000644000175000001440000000500614634065603020346 0ustar00rncbcusers// qsamplerDeviceStatusForm.h // /**************************************************************************** Copyright (C) 2010-2020, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2008,2019 Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #ifndef __qsamplerDeviceStatusForm_h #define __qsamplerDeviceStatusForm_h #include "qsamplerDevice.h" #include #include #include #include #include #include namespace QSampler { class MidiActivityLED : public QLabel { Q_OBJECT public: MidiActivityLED(QString sText = QString(), QWidget *pParent = nullptr); ~MidiActivityLED(); void midiActivityLedOn(); protected slots: void midiActivityLedOff(); private: QTimer m_timer; // MIDI activity pixmap common resources. static int g_iMidiActivityRefCount; static QPixmap *g_pMidiActivityLedOn; static QPixmap *g_pMidiActivityLedOff; }; class DeviceStatusForm : public QWidget { Q_OBJECT public: DeviceStatusForm(int DeviceID, QWidget *pParent = nullptr, Qt::WindowFlags wflags = Qt::WindowFlags()); ~DeviceStatusForm(); QAction *visibleAction(); void midiArrived(int iPort); static DeviceStatusForm *getInstance(int iDeviceID); static const std::map& getInstances(); static void onDevicesChanged(); static void onDeviceChanged(int iDeviceID); static void deleteAllInstances(); protected: void closeEvent(QCloseEvent *pCloseEvent); void updateGUIPorts(); private: int m_DeviceID; Device *m_pDevice; QAction *m_pVisibleAction; std::vector m_midiActivityLEDs; static std::map g_instances; }; } // namespace QSampler #endif // __qsamplerDeviceStatusForm_h // end of qsamplerDeviceStatusForm.h qsampler-1.0.0/src/PaxHeaders/qsamplerPaletteForm.cpp0000644000000000000000000000013214634065603017703 xustar0030 mtime=1718643587.394448566 30 atime=1718643587.394448566 30 ctime=1718643587.394448566 qsampler-1.0.0/src/qsamplerPaletteForm.cpp0000644000175000001440000010001314634065603017666 0ustar00rncbcusers// qsamplerPaletteForm.cpp // /**************************************************************************** Copyright (C) 2004-2024, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #include "qsamplerAbout.h" #include "qsamplerPaletteForm.h" #include "ui_qsamplerPaletteForm.h" #include #include #include #include #include #include #include #include #include #include #include namespace QSampler { // Local static consts. static const char *ColorThemesGroup = "/ColorThemes/"; static const char *PaletteEditorGroup = "/PaletteEditor/"; static const char *DefaultDirKey = "DefaultDir"; static const char *ShowDetailsKey = "ShowDetails"; static const char *DefaultSuffix = "conf"; static struct { const char *key; QPalette::ColorRole value; } g_colorRoles[] = { { "Window", QPalette::Window }, { "WindowText", QPalette::WindowText }, { "Button", QPalette::Button }, { "ButtonText", QPalette::ButtonText }, { "Light", QPalette::Light }, { "Midlight", QPalette::Midlight }, { "Dark", QPalette::Dark }, { "Mid", QPalette::Mid }, { "Text", QPalette::Text }, { "BrightText", QPalette::BrightText }, { "Base", QPalette::Base }, { "AlternateBase", QPalette::AlternateBase }, { "Shadow", QPalette::Shadow }, { "Highlight", QPalette::Highlight }, { "HighlightedText", QPalette::HighlightedText }, { "Link", QPalette::Link }, { "LinkVisited", QPalette::LinkVisited }, { "ToolTipBase", QPalette::ToolTipBase }, { "ToolTipText", QPalette::ToolTipText }, #if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) { "PlaceholderText", QPalette::PlaceholderText }, #endif { "NoRole", QPalette::NoRole }, { nullptr, QPalette::NoRole } }; //------------------------------------------------------------------------- // Qsampler::PaletteForm PaletteForm::PaletteForm ( QWidget *parent, const QPalette& pal ) : QDialog(parent), p_ui(new Ui::qsamplerPaletteForm), m_ui(*p_ui) { m_ui.setupUi(this); m_settings = nullptr; m_owner = false; m_modelUpdated = false; m_paletteUpdated = false; m_dirtyCount = 0; m_dirtyTotal = 0; updateGenerateButton(); m_paletteModel = new PaletteModel(this); m_ui.paletteView->setModel(m_paletteModel); ColorDelegate *delegate = new ColorDelegate(this); m_ui.paletteView->setItemDelegate(delegate); m_ui.paletteView->setEditTriggers(QAbstractItemView::AllEditTriggers); // m_ui.paletteView->setAlternatingRowColors(true); m_ui.paletteView->setSelectionBehavior(QAbstractItemView::SelectRows); m_ui.paletteView->setDragEnabled(true); m_ui.paletteView->setDropIndicatorShown(true); m_ui.paletteView->setRootIsDecorated(false); m_ui.paletteView->setColumnHidden(2, true); m_ui.paletteView->setColumnHidden(3, true); QObject::connect(m_ui.nameCombo, SIGNAL(editTextChanged(const QString&)), SLOT(nameComboChanged(const QString&))); QObject::connect(m_ui.saveButton, SIGNAL(clicked()), SLOT(saveButtonClicked())); QObject::connect(m_ui.deleteButton, SIGNAL(clicked()), SLOT(deleteButtonClicked())); QObject::connect(m_ui.generateButton, SIGNAL(changed()), SLOT(generateButtonChanged())); QObject::connect(m_ui.resetButton, SIGNAL(clicked()), SLOT(resetButtonClicked())); QObject::connect(m_ui.detailsCheck, SIGNAL(clicked()), SLOT(detailsCheckClicked())); QObject::connect(m_ui.importButton, SIGNAL(clicked()), SLOT(importButtonClicked())); QObject::connect(m_ui.exportButton, SIGNAL(clicked()), SLOT(exportButtonClicked())); QObject::connect(m_paletteModel, SIGNAL(paletteChanged(const QPalette&)), SLOT(paletteChanged(const QPalette&))); QObject::connect(m_ui.dialogButtons, SIGNAL(accepted()), SLOT(accept())); QObject::connect(m_ui.dialogButtons, SIGNAL(rejected()), SLOT(reject())); setPalette(pal, pal); QDialog::adjustSize(); } PaletteForm::~PaletteForm (void) { setSettings(nullptr); } void PaletteForm::setPalette ( const QPalette& pal ) { m_palette = pal; #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) const uint mask = pal.resolveMask(); #else const uint mask = pal.resolve(); #endif for (int i = 0; g_colorRoles[i].key; ++i) { if ((mask & (1 << i)) == 0) { const QPalette::ColorRole cr = g_colorRoles[i].value; m_palette.setBrush(QPalette::Active, cr, m_parentPalette.brush(QPalette::Active, cr)); m_palette.setBrush(QPalette::Inactive, cr, m_parentPalette.brush(QPalette::Inactive, cr)); m_palette.setBrush(QPalette::Disabled, cr, m_parentPalette.brush(QPalette::Disabled, cr)); } } #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) m_palette.setResolveMask(mask); #else m_palette.resolve(mask); #endif updateGenerateButton(); m_paletteUpdated = true; if (!m_modelUpdated) m_paletteModel->setPalette(m_palette, m_parentPalette); m_paletteUpdated = false; } void PaletteForm::setPalette ( const QPalette& pal, const QPalette& parentPal ) { m_parentPalette = parentPal; setPalette(pal); } const QPalette& PaletteForm::palette (void) const { return m_palette; } void PaletteForm::setSettings ( QSettings *settings, bool owner ) { if (m_settings && m_owner) delete m_settings; m_settings = settings; m_owner = owner; m_ui.detailsCheck->setChecked(isShowDetails()); updateNamedPaletteList(); updateDialogButtons(); } QSettings *PaletteForm::settings (void) const { return m_settings; } void PaletteForm::nameComboChanged ( const QString& name ) { if (m_dirtyCount > 0 && m_ui.nameCombo->findText(name) < 0) { updateDialogButtons(); } else { resetButtonClicked(); setPaletteName(name); ++m_dirtyTotal; } } void PaletteForm::saveButtonClicked (void) { const QString& name = m_ui.nameCombo->currentText(); if (name.isEmpty()) return; QString filename = namedPaletteConf(name); if (filename.isEmpty() || !QFileInfo(filename).isWritable()) { const QString& title = tr("Save Palette - %1").arg(QDialog::windowTitle()); QStringList filters; filters.append(tr("Palette files (*.%1)").arg(DefaultSuffix)); filters.append(tr("All files (*.*)")); QString dirname = defaultDir(); if (!dirname.isEmpty()) dirname.append(QDir::separator()); dirname.append(paletteName() + '.' + DefaultSuffix); filename = QFileDialog::getSaveFileName(this, title, dirname, filters.join(";;")); } if (!filename.isEmpty() && saveNamedPaletteConf(name, filename, m_palette)) { addNamedPaletteConf(name, filename); setPalette(m_palette, m_palette); updateNamedPaletteList(); resetButtonClicked(); } } void PaletteForm::deleteButtonClicked (void) { const QString& name = m_ui.nameCombo->currentText(); if (m_ui.nameCombo->findText(name) >= 0) { deleteNamedPaletteConf(name); updateNamedPaletteList(); updateDialogButtons(); } } void PaletteForm::generateButtonChanged (void) { const QColor& color = m_ui.generateButton->brush().color(); const QPalette& pal = QPalette(color); setPalette(pal); ++m_dirtyCount; updateDialogButtons(); } void PaletteForm::resetButtonClicked (void) { const bool blocked = blockSignals(true); for (int i = 0; g_colorRoles[i].key; ++i) { const QPalette::ColorRole cr = g_colorRoles[i].value; const QModelIndex& index = m_paletteModel->index(cr, 0); m_paletteModel->setData(index, false, Qt::EditRole); } m_dirtyCount = 0; updateDialogButtons(); blockSignals(blocked); } void PaletteForm::detailsCheckClicked (void) { const int cw = (m_ui.paletteView->viewport()->width() >> 2); QHeaderView *header = m_ui.paletteView->header(); header->resizeSection(0, cw); if (m_ui.detailsCheck->isChecked()) { m_ui.paletteView->setColumnHidden(2, false); m_ui.paletteView->setColumnHidden(3, false); header->resizeSection(1, cw); header->resizeSection(2, cw); header->resizeSection(3, cw); m_paletteModel->setGenerate(false); } else { m_ui.paletteView->setColumnHidden(2, true); m_ui.paletteView->setColumnHidden(3, true); header->resizeSection(1, cw * 3); m_paletteModel->setGenerate(true); } } void PaletteForm::importButtonClicked (void) { const QString& title = tr("Import File - %1").arg(QDialog::windowTitle()); QStringList filters; filters.append(tr("Palette files (*.%1)").arg(DefaultSuffix)); filters.append(tr("All files (*.*)")); const QString& filename = QFileDialog::getOpenFileName(this, title, defaultDir(), filters.join(";;")); if (filename.isEmpty()) return; QSettings conf(filename, QSettings::IniFormat); conf.beginGroup(ColorThemesGroup); const QStringList names = conf.childGroups(); conf.endGroup(); int imported = 0; QStringListIterator name_iter(names); while (name_iter.hasNext()) { const QString& name = name_iter.next(); if (!name.isEmpty()) { addNamedPaletteConf(name, filename); setPaletteName(name); ++imported; } } if (imported > 0) { updateNamedPaletteList(); resetButtonClicked(); setDefaultDir(QFileInfo(filename).absolutePath()); } else { QMessageBox::warning(this, tr("Warning - %1").arg(QDialog::windowTitle()), tr("Could not import from file:\n\n" "%1\n\nSorry.").arg(filename)); } } void PaletteForm::exportButtonClicked (void) { const QString& title = tr("Export File - %1").arg(QDialog::windowTitle()); QStringList filters; filters.append(tr("Palette files (*.%1)").arg(DefaultSuffix)); filters.append(tr("All files (*.*)")); QString dirname = defaultDir(); if (!dirname.isEmpty()) dirname.append(QDir::separator()); dirname.append(paletteName() + '.' + DefaultSuffix); const QString& filename = QFileDialog::getSaveFileName(this, title, dirname, filters.join(";;")); if (filename.isEmpty()) return; const QFileInfo fi(filename); const QString& name = fi.baseName(); if (saveNamedPaletteConf(name, filename, m_palette)) { // addNamedPaletteConf(name, filename); setDefaultDir(fi.absolutePath()); } } void PaletteForm::paletteChanged ( const QPalette& pal ) { m_modelUpdated = true; if (!m_paletteUpdated) setPalette(pal); m_modelUpdated = false; ++m_dirtyCount; updateDialogButtons(); } void PaletteForm::setPaletteName ( const QString& name ) { const bool blocked = m_ui.nameCombo->blockSignals(true); m_ui.nameCombo->setEditText(name); QPalette pal; if (namedPalette(m_settings, name, pal, true)) setPalette(pal, pal); m_dirtyCount = 0; updateDialogButtons(); m_ui.nameCombo->blockSignals(blocked); } QString PaletteForm::paletteName (void) const { return m_ui.nameCombo->currentText(); } void PaletteForm::updateNamedPaletteList (void) { const bool blocked = m_ui.nameCombo->blockSignals(true); const QString old_name = m_ui.nameCombo->currentText(); m_ui.nameCombo->clear(); m_ui.nameCombo->insertItems(0, namedPaletteList()); // m_ui.nameCombo->model()->sort(0); const int i = m_ui.nameCombo->findText(old_name); if (i >= 0) m_ui.nameCombo->setCurrentIndex(i); else m_ui.nameCombo->setEditText(old_name); m_ui.nameCombo->blockSignals(blocked); } void PaletteForm::updateGenerateButton (void) { m_ui.generateButton->setBrush( m_palette.brush(QPalette::Active, QPalette::Button)); } void PaletteForm::updateDialogButtons (void) { const QString& name = m_ui.nameCombo->currentText(); const QString& filename = namedPaletteConf(name); const int i = m_ui.nameCombo->findText(name); m_ui.saveButton->setEnabled(!name.isEmpty() && (m_dirtyCount > 0 || i < 0)); m_ui.deleteButton->setEnabled(i >= 0); m_ui.resetButton->setEnabled(m_dirtyCount > 0); m_ui.exportButton->setEnabled(!name.isEmpty() || i >= 0); m_ui.dialogButtons->button(QDialogButtonBox::Ok)->setEnabled(i >= 0); } bool PaletteForm::namedPalette ( const QString& name, QPalette& pal ) const { return namedPalette(m_settings, name, pal); } bool PaletteForm::namedPalette ( QSettings *settings, const QString& name, QPalette& pal, bool fixup ) { int result = 0; if (!name.isEmpty() && loadNamedPalette(settings, name, pal)) { ++result; } else { const QString& filename = namedPaletteConf(settings, name); if (!filename.isEmpty() && QFileInfo(filename).isReadable() && loadNamedPaletteConf(name, filename, pal)) { ++result; } } // Dark themes grayed/disabled color group fix... if (!fixup && pal.base().color().value() < 0x7f) { const QColor& color = pal.window().color(); const int groups = int(QPalette::Active | QPalette::Inactive) + 1; for (int i = 0; i < groups; ++i) { const QPalette::ColorGroup cg = QPalette::ColorGroup(i); pal.setBrush(cg, QPalette::Light, color.lighter(140)); pal.setBrush(cg, QPalette::Midlight, color.lighter(100)); pal.setBrush(cg, QPalette::Mid, color.lighter(90)); pal.setBrush(cg, QPalette::Dark, color.darker(160)); pal.setBrush(cg, QPalette::Shadow, color.darker(180)); } pal.setColorGroup(QPalette::Disabled, pal.windowText().color().darker(), pal.button(), pal.light(), pal.dark(), pal.mid(), pal.text().color().darker(), pal.text().color().lighter(), pal.base(), pal.window()); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) pal.setColor(QPalette::Disabled, QPalette::Highlight, pal.mid().color()); pal.setColor(QPalette::Disabled, QPalette::ButtonText, pal.mid().color()); #endif ++result; } return (result > 0); } QStringList PaletteForm::namedPaletteList (void) const { return namedPaletteList(m_settings); } QStringList PaletteForm::namedPaletteList ( QSettings *settings ) { QStringList list; if (settings) { settings->beginGroup(ColorThemesGroup); list.append(settings->childKeys()); list.append(settings->childGroups()); // legacy... settings->endGroup(); } return list; } QString PaletteForm::namedPaletteConf ( const QString& name ) const { return namedPaletteConf(m_settings, name); } QString PaletteForm::namedPaletteConf ( QSettings *settings, const QString& name ) { QString ret; if (settings && !name.isEmpty()) { settings->beginGroup(ColorThemesGroup); ret = settings->value(name).toString(); settings->endGroup(); } return ret; } void PaletteForm::addNamedPaletteConf ( const QString& name, const QString& filename ) { addNamedPaletteConf(m_settings, name, filename); ++m_dirtyTotal; } void PaletteForm::addNamedPaletteConf ( QSettings *settings, const QString& name, const QString& filename ) { if (settings) { settings->beginGroup(ColorThemesGroup); settings->remove(name); // remove legacy keys! settings->setValue(name, filename); settings->endGroup(); } } void PaletteForm::deleteNamedPaletteConf ( const QString& name ) { if (m_settings) { m_settings->beginGroup(ColorThemesGroup); m_settings->remove(name); m_settings->endGroup(); ++m_dirtyTotal; } } bool PaletteForm::loadNamedPaletteConf ( const QString& name, const QString& filename, QPalette& pal ) { QSettings conf(filename, QSettings::IniFormat); return loadNamedPalette(&conf, name, pal); } bool PaletteForm::saveNamedPaletteConf ( const QString& name, const QString& filename, const QPalette& pal ) { QSettings conf(filename, QSettings::IniFormat); return saveNamedPalette(&conf, name, pal); } bool PaletteForm::loadNamedPalette ( QSettings *settings, const QString& name, QPalette& pal ) { if (settings == nullptr) return false; int result = 0; settings->beginGroup(ColorThemesGroup); QStringListIterator name_iter(settings->childGroups()); while (name_iter.hasNext() && !result) { const QString& name2 = name_iter.next(); if (name2 == name) { #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) uint mask = pal.resolve(); #endif settings->beginGroup(name + '/'); QStringListIterator iter(settings->childKeys()); while (iter.hasNext()) { const QString& key = iter.next(); const QPalette::ColorRole cr = PaletteForm::colorRole(key); const QStringList& clist = settings->value(key).toStringList(); if (clist.count() == 3) { pal.setColor(QPalette::Active, cr, QColor(clist.at(0))); pal.setColor(QPalette::Inactive, cr, QColor(clist.at(1))); pal.setColor(QPalette::Disabled, cr, QColor(clist.at(2))); #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) mask &= ~(1 << int(cr)); #endif ++result; } } #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) pal.resolve(mask); #endif settings->endGroup(); } } settings->endGroup(); return (result > 0); } bool PaletteForm::saveNamedPalette ( QSettings *settings, const QString& name, const QPalette& pal ) { if (settings == nullptr) return false; settings->beginGroup(ColorThemesGroup); settings->beginGroup(name + '/'); for (int i = 0; g_colorRoles[i].key; ++i) { const QString& key = QString::fromLatin1(g_colorRoles[i].key); const QPalette::ColorRole cr = g_colorRoles[i].value; QStringList clist; clist.append(pal.color(QPalette::Active, cr).name()); clist.append(pal.color(QPalette::Inactive, cr).name()); clist.append(pal.color(QPalette::Disabled, cr).name()); settings->setValue(key, clist); } settings->endGroup(); settings->endGroup(); return true; } QPalette::ColorRole PaletteForm::colorRole ( const QString& name ) { static QHash s_colorRoles; if (s_colorRoles.isEmpty()) { for (int i = 0; g_colorRoles[i].key; ++i) { const QString& key = QString::fromLatin1(g_colorRoles[i].key); const QPalette::ColorRole value = g_colorRoles[i].value; s_colorRoles.insert(key, value); } } return s_colorRoles.value(name, QPalette::NoRole); } bool PaletteForm::isDirty (void) const { return (m_dirtyTotal > 0); } void PaletteForm::accept (void) { setShowDetails(m_ui.detailsCheck->isChecked()); if (m_dirtyCount > 0) saveButtonClicked(); QDialog::accept(); } void PaletteForm::reject (void) { if (m_dirtyCount > 0) { const QString& name = paletteName(); if (name.isEmpty()) { if (QMessageBox::warning(this, tr("Warning - %1").arg(QDialog::windowTitle()), tr("Some settings have been changed.\n\n" "Do you want to discard the changes?"), QMessageBox::Discard | QMessageBox::Cancel) == QMessageBox::Cancel) return; } else { switch (QMessageBox::warning(this, tr("Warning - %1").arg(QDialog::windowTitle()), tr("Some settings have been changed:\n\n" "\"%1\".\n\nDo you want to save the changes?") .arg(name), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel)) { case QMessageBox::Save: saveButtonClicked(); // Fall thru... case QMessageBox::Discard: break; default: // Cancel... return; } } } QDialog::reject(); } void PaletteForm::setDefaultDir ( const QString& dir ) { if (m_settings) { m_settings->beginGroup(PaletteEditorGroup); m_settings->setValue(DefaultDirKey, dir); m_settings->endGroup(); } } QString PaletteForm::defaultDir (void) const { QString dir; if (m_settings) { m_settings->beginGroup(PaletteEditorGroup); dir = m_settings->value(DefaultDirKey).toString(); m_settings->endGroup(); } return dir; } void PaletteForm::setShowDetails ( bool on ) { if (m_settings) { m_settings->beginGroup(PaletteEditorGroup); m_settings->setValue(ShowDetailsKey, on); m_settings->endGroup(); } } bool PaletteForm::isShowDetails (void) const { bool on = false; if (m_settings) { m_settings->beginGroup(PaletteEditorGroup); on = m_settings->value(ShowDetailsKey).toBool(); m_settings->endGroup(); } return on; } void PaletteForm::showEvent ( QShowEvent *event ) { QDialog::showEvent(event); detailsCheckClicked(); } void PaletteForm::resizeEvent ( QResizeEvent *event ) { QDialog::resizeEvent(event); detailsCheckClicked(); } //------------------------------------------------------------------------- // PaletteForm::PaletteModel PaletteForm::PaletteModel::PaletteModel ( QObject *parent ) : QAbstractTableModel(parent) { for (m_nrows = 0; g_colorRoles[m_nrows].key; ++m_nrows) { const QPalette::ColorRole value = g_colorRoles[m_nrows].value; const QString& key = QString::fromLatin1(g_colorRoles[m_nrows].key); m_roleNames.insert(value, key); } m_generate = true; } int PaletteForm::PaletteModel::rowCount ( const QModelIndex& ) const { return m_nrows; } int PaletteForm::PaletteModel::columnCount ( const QModelIndex& ) const { return 4; } QVariant PaletteForm::PaletteModel::data ( const QModelIndex& index, int role ) const { if (!index.isValid()) return QVariant(); if (index.row() < 0 || index.row() >= m_nrows) return QVariant(); if (index.column() < 0 || index.column() >= 4) return QVariant(); if (index.column() == 0) { if (role == Qt::DisplayRole) return m_roleNames.value(QPalette::ColorRole(index.row())); if (role == Qt::EditRole) { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) const uint mask = m_palette.resolveMask(); #else const uint mask = m_palette.resolve(); #endif return bool(mask & (1 << index.row())); } } else if (role == Qt::BackgroundRole) { return m_palette.color( columnToGroup(index.column()), QPalette::ColorRole(index.row())); } return QVariant(); } bool PaletteForm::PaletteModel::setData ( const QModelIndex& index, const QVariant& value, int role ) { if (!index.isValid()) return false; if (index.column() != 0 && role == Qt::BackgroundRole) { const QColor& color = value.value(); const QPalette::ColorRole cr = QPalette::ColorRole(index.row()); const QPalette::ColorGroup cg = columnToGroup(index.column()); m_palette.setBrush(cg, cr, color); QModelIndex index_begin = PaletteModel::index(cr, 0); QModelIndex index_end = PaletteModel::index(cr, 3); if (m_generate) { m_palette.setBrush(QPalette::Inactive, cr, color); switch (cr) { case QPalette::WindowText: case QPalette::Text: case QPalette::ButtonText: case QPalette::Base: break; case QPalette::Dark: m_palette.setBrush(QPalette::Disabled, QPalette::WindowText, color); m_palette.setBrush(QPalette::Disabled, QPalette::Dark, color); m_palette.setBrush(QPalette::Disabled, QPalette::Text, color); m_palette.setBrush(QPalette::Disabled, QPalette::ButtonText, color); index_begin = PaletteModel::index(0, 0); index_end = PaletteModel::index(m_nrows - 1, 3); break; case QPalette::Window: m_palette.setBrush(QPalette::Disabled, QPalette::Base, color); m_palette.setBrush(QPalette::Disabled, QPalette::Window, color); index_begin = PaletteModel::index(QPalette::Base, 0); break; case QPalette::Highlight: m_palette.setBrush(QPalette::Disabled, QPalette::Highlight, color.darker(120)); break; default: m_palette.setBrush(QPalette::Disabled, cr, color); break; } } emit paletteChanged(m_palette); emit dataChanged(index_begin, index_end); return true; } if (index.column() == 0 && role == Qt::EditRole) { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) uint mask = m_palette.resolveMask(); #else uint mask = m_palette.resolve(); #endif const bool masked = value.value(); const int i = index.row(); if (masked) { mask |= (1 << i); } else { const QPalette::ColorRole cr = QPalette::ColorRole(i); m_palette.setBrush(QPalette::Active, cr, m_parentPalette.brush(QPalette::Active, cr)); m_palette.setBrush(QPalette::Inactive, cr, m_parentPalette.brush(QPalette::Inactive, cr)); m_palette.setBrush(QPalette::Disabled, cr, m_parentPalette.brush(QPalette::Disabled, cr)); mask &= ~(1 << i); } #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) m_palette.setResolveMask(mask); #else m_palette.resolve(mask); #endif emit paletteChanged(m_palette); const QModelIndex& index_end = PaletteModel::index(i, 3); emit dataChanged(index, index_end); return true; } return false; } Qt::ItemFlags PaletteForm::PaletteModel::flags ( const QModelIndex& index ) const { if (!index.isValid()) return Qt::ItemIsEnabled; else return Qt::ItemIsEditable | Qt::ItemIsEnabled; } QVariant PaletteForm::PaletteModel::headerData ( int section, Qt::Orientation orientation, int role ) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { if (section == 0) return tr("Color Role"); else if (section == groupToColumn(QPalette::Active)) return tr("Active"); else if (section == groupToColumn(QPalette::Inactive)) return tr("Inactive"); else if (section == groupToColumn(QPalette::Disabled)) return tr("Disabled"); } return QVariant(); } const QPalette& PaletteForm::PaletteModel::palette(void) const { return m_palette; } void PaletteForm::PaletteModel::setPalette ( const QPalette& palette, const QPalette& parentPalette ) { m_palette = palette; m_parentPalette = parentPalette; const QModelIndex& index_begin = index(0, 0); const QModelIndex& index_end = index(m_nrows - 1, 3); emit dataChanged(index_begin, index_end); } QPalette::ColorGroup PaletteForm::PaletteModel::columnToGroup ( int index ) const { if (index == 1) return QPalette::Active; else if (index == 2) return QPalette::Inactive; return QPalette::Disabled; } int PaletteForm::PaletteModel::groupToColumn ( QPalette::ColorGroup group ) const { if (group == QPalette::Active) return 1; else if (group == QPalette::Inactive) return 2; return 3; } //------------------------------------------------------------------------- // QSampler::PaletteForm::ColorDelegate QWidget *PaletteForm::ColorDelegate::createEditor ( QWidget *parent, const QStyleOptionViewItem&, const QModelIndex& index ) const { QWidget *editor = nullptr; if (index.column() == 0) { RoleEditor *ed = new RoleEditor(parent); QObject::connect(ed, SIGNAL(changed(QWidget *)), SIGNAL(commitData(QWidget *))); // ed->setFocusPolicy(Qt::NoFocus); // ed->installEventFilter(const_cast(this)); editor = ed; } else { ColorEditor *ed = new ColorEditor(parent); QObject::connect(ed, SIGNAL(changed(QWidget *)), SIGNAL(commitData(QWidget *))); ed->setFocusPolicy(Qt::NoFocus); ed->installEventFilter(const_cast(this)); editor = ed; } return editor; } void PaletteForm::ColorDelegate::setEditorData ( QWidget *editor, const QModelIndex& index ) const { if (index.column() == 0) { const bool masked = index.model()->data(index, Qt::EditRole).value(); RoleEditor *ed = static_cast(editor); ed->setEdited(masked); const QString& colorName = index.model()->data(index, Qt::DisplayRole).value(); ed->setLabel(colorName); } else { const QColor& color = index.model()->data(index, Qt::BackgroundRole).value(); ColorEditor *ed = static_cast(editor); ed->setColor(color); } } void PaletteForm::ColorDelegate::setModelData ( QWidget *editor, QAbstractItemModel *model, const QModelIndex& index ) const { if (index.column() == 0) { RoleEditor *ed = static_cast(editor); const bool masked = ed->edited(); model->setData(index, masked, Qt::EditRole); } else { ColorEditor *ed = static_cast(editor); if (ed->changed()) { const QColor& color = ed->color(); model->setData(index, color, Qt::BackgroundRole); } } } void PaletteForm::ColorDelegate::updateEditorGeometry ( QWidget *editor, const QStyleOptionViewItem& option, const QModelIndex& index ) const { QItemDelegate::updateEditorGeometry(editor, option, index); editor->setGeometry(editor->geometry().adjusted(0, 0, -1, -1)); } void PaletteForm::ColorDelegate::paint ( QPainter *painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const { QStyleOptionViewItem opt = option; const bool masked = index.model()->data(index, Qt::EditRole).value(); if (index.column() == 0 && masked) opt.font.setBold(true); QItemDelegate::paint(painter, opt, index); // painter->setPen(opt.palette.midlight().color()); painter->setPen(Qt::darkGray); painter->drawLine(opt.rect.right(), opt.rect.y(), opt.rect.right(), opt.rect.bottom()); painter->drawLine(opt.rect.x(), opt.rect.bottom(), opt.rect.right(), opt.rect.bottom()); } QSize PaletteForm::ColorDelegate::sizeHint ( const QStyleOptionViewItem& option, const QModelIndex &index) const { return QItemDelegate::sizeHint(option, index) + QSize(4, 4); } //------------------------------------------------------------------------- // QSampler::PaletteForm::ColorButton PaletteForm::ColorButton::ColorButton ( QWidget *parent ) : QPushButton(parent), m_brush(Qt::darkGray) { QPushButton::setMinimumWidth(48); QObject::connect(this, SIGNAL(clicked()), SLOT(chooseColor())); } const QBrush& PaletteForm::ColorButton::brush (void) const { return m_brush; } void PaletteForm::ColorButton::setBrush ( const QBrush& brush ) { m_brush = brush; update(); } void PaletteForm::ColorButton::paintEvent ( QPaintEvent *event ) { QPushButton::paintEvent(event); QStyleOptionButton opt; opt.initFrom(this); const QRect& rect = style()->subElementRect(QStyle::SE_PushButtonContents, &opt, this); QPainter paint(this); paint.setBrush(QBrush(m_brush.color())); paint.drawRect(rect.adjusted(+1, +1, -2, -2)); } void PaletteForm::ColorButton::chooseColor (void) { const QColor color = QColorDialog::getColor(m_brush.color(), this); if (color.isValid()) { m_brush.setColor(color); emit changed(); } } //------------------------------------------------------------------------- // QSampler::PaletteForm::ColorEditor PaletteForm::ColorEditor::ColorEditor ( QWidget *parent ) : QWidget(parent) { QLayout *layout = new QHBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); m_button = new PaletteForm::ColorButton(this); layout->addWidget(m_button); QObject::connect(m_button, SIGNAL(changed()), SLOT(colorChanged())); setFocusProxy(m_button); m_changed = false; } void PaletteForm::ColorEditor::setColor ( const QColor& color ) { m_button->setBrush(color); m_changed = false; } QColor PaletteForm::ColorEditor::color (void) const { return m_button->brush().color(); } void PaletteForm::ColorEditor::colorChanged (void) { m_changed = true; emit changed(this); } bool PaletteForm::ColorEditor::changed (void) const { return m_changed; } //------------------------------------------------------------------------- // QSampler::PaletteForm::RoleEditor PaletteForm::RoleEditor::RoleEditor ( QWidget *parent ) : QWidget(parent) { m_edited = false; QHBoxLayout *layout = new QHBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(0); m_label = new QLabel(this); layout->addWidget(m_label); m_label->setAutoFillBackground(true); m_label->setIndent(3); // HACK: it should have the same value of textMargin in QItemDelegate setFocusProxy(m_label); m_button = new QToolButton(this); m_button->setToolButtonStyle(Qt::ToolButtonIconOnly); m_button->setIcon(QPixmap(":/images/itemReset.png")); m_button->setIconSize(QSize(8, 8)); m_button->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding)); layout->addWidget(m_button); QObject::connect(m_button, SIGNAL(clicked()), SLOT(resetProperty())); } void PaletteForm::RoleEditor::setLabel ( const QString& label ) { m_label->setText(label); } void PaletteForm::RoleEditor::setEdited ( bool on ) { QFont font; if (on) font.setBold(on); m_label->setFont(font); m_button->setEnabled(on); m_edited = on; } bool PaletteForm::RoleEditor::edited (void) const { return m_edited; } void PaletteForm::RoleEditor::resetProperty (void) { setEdited(false); emit changed(this); } } // namespace QSampler // end of qsamplerPaletteForm.cpp qsampler-1.0.0/src/PaxHeaders/qsamplerOptionsForm.ui0000644000000000000000000000013214634065603017573 xustar0030 mtime=1718643587.394448566 30 atime=1718643587.394448566 30 ctime=1718643587.394448566 qsampler-1.0.0/src/qsamplerOptionsForm.ui0000644000175000001440000015161414634065603017573 0ustar00rncbcusers rncbc aka Rui Nuno Capela qsampler - A LinuxSampler Qt GUI Interface. Copyright (C) 2005-2022, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. qsamplerOptionsForm 0 0 520 320 Options :/images/qsampler.svg true 4 4 false 0 &General 4 8 75 true Messages true 4 4 0 0 180 0 180 32767 50 false Sample messages text font display true QFrame::StyledPanel QFrame::Sunken Qt::AlignCenter false 50 false Select font for the messages text display &Font... false Qt::Horizontal QSizePolicy::Expanding 20 8 50 false Whether to keep a maximum number of lines in the messages window &Messages limit: 50 false The maximum number of message lines to keep in view lines 100 10000 100 1000 75 true Other true 50 false Whether to ask for confirmation on removals &Confirm removals Qt::Horizontal QSizePolicy::Expanding 20 8 50 false &Number of recent files: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false MaxRecentFilesSpinBox 50 false The maximum number of recent files to keep in menu 0 20 5 50 false Whether to keep all child windows on top of the main window &Keep child windows always on top 50 false Whether to capture standard output (stdout/stderr) into messages window Capture standard &output 50 false Whether to ask for session reset &Confirm session reset 50 false Whether to show the complete directory path of loaded session files Show complete &path of session files 50 false Whether to ask for session restart &Confirm session restart 50 false Whether to show the actual instrument names as read from instrument file (using libgig) Show actual &instrument names 50 false Whether to show session errors &Confirm session errors Qt::Vertical QSizePolicy::Expanding 8 20 &Display 4 8 75 true Channels true 4 4 0 0 180 0 180 32767 50 false Sample channel display font display true QFrame::StyledPanel QFrame::Sunken 1 Qt::AlignCenter false 50 false Select font for the channel display &Font... false Qt::Horizontal QSizePolicy::Expanding 20 8 50 false Whether to refresh the channels view automatically &Auto refresh: 0 0 50 false Time in milliseconds between each auto-refresh cycle msec 200 20000 100 1000 50 false Whether to enable a shiny glass light effect on the channel display Display shiny glass light &effect 75 true Custom true 8 4 50 false &Color palette theme: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter CustomColorThemeComboBox 50 false Custom color palette theme false (default) Wonton Soup KXStudio 22 22 24 24 50 false Qt::TabFocus Manage custom color palette themes ... Qt::Horizontal 20 20 50 false &Widget style theme: CustomStyleThemeComboBox 50 false Custom widget style theme false (default) Qt::Vertical QSizePolicy::Expanding 8 20 75 true Defaults true Qt::Horizontal QSizePolicy::Expanding 20 8 50 false &Base font size: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter BaseFontSizeComboBox 50 false Base application font size (pt.) true (default) 6 7 8 9 10 11 12 &Server 4 8 75 true Settings true 4 4 4 4 4 50 false &Host: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false ServerHostComboBox 60 32767 50 false LinuxSampler server listener port number true 8888 60 32767 50 false &Port: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false ServerPortComboBox 0 0 50 false LinuxSampler server host name or address true localhost 50 false &Command line: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false ServerCmdLineComboBox 50 false Whether to start the LinuxSampler server on local machine &Start server locally 0 0 50 false Command line to start LinuxSampler server locally true linuxsampler 50 false Start &delay: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false StartDelaySpinBox 0 0 40 0 50 false Delay time in seconds after server startup secs 1 100 3 Qt::Horizontal QSizePolicy::Expanding 20 8 Qt::Vertical QSizePolicy::Expanding 20 8 Qt::Horizontal QSizePolicy::Expanding 20 8 0 0 40 0 50 false Receive timeout in milliseconds msec 100 60000 100 1000 50 false &Timeout: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false ServerTimeoutSpinBox Qt::Vertical QSizePolicy::Expanding 8 20 75 true Logging true 8 8 8 8 4 0 0 50 false Messages log file true 22 22 24 24 50 false Qt::TabFocus Browse for the messages log file location ... 50 false Whether to activate a messages logging to file. &Messages log file: &Tuning 4 8 75 true Limits true 50 false Maximum &volume: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false MaxVolumeSpinBox 0 0 50 false Upper limit for the sampler channel volume setting % 1000 10 100 Qt::Horizontal 20 8 Qt::Vertical 20 8 50 false Maximum &number of voices: MaxVoicesSpinBox 60 0 50 false Maximum number of voices 999999999 Qt::Horizontal 20 8 50 false Maximum number of disk &streams: MaxStreamsSpinBox 60 0 50 false Maximum number of disk streams 999999999 Qt::Vertical 20 20 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok DialogButtonBox OptionsTabWidget OptionsTabWidget MessagesFontPushButton MessagesLimitCheckBox MessagesLimitLinesSpinBox ConfirmRemoveCheckBox MaxRecentFilesSpinBox KeepOnTopCheckBox StdoutCaptureCheckBox ConfirmResetCheckBox CompletePathCheckBox ConfirmRestartCheckBox InstrumentNamesCheckBox ConfirmErrorCheckBox DisplayFontPushButton AutoRefreshCheckBox AutoRefreshTimeSpinBox DisplayEffectCheckBox CustomColorThemeComboBox CustomColorThemeToolButton CustomStyleThemeComboBox BaseFontSizeComboBox ServerPortComboBox ServerHostComboBox ServerStartCheckBox ServerCmdLineComboBox StartDelaySpinBox ServerTimeoutSpinBox MessagesLogPathComboBox MessagesLogPathToolButton MessagesLogCheckBox MaxVolumeSpinBox MaxVoicesSpinBox MaxStreamsSpinBox DialogButtonBox qsampler-1.0.0/src/PaxHeaders/qsamplerOptions.h0000644000000000000000000000013214634065603016561 xustar0030 mtime=1718643587.394448566 30 atime=1718643587.394448566 30 ctime=1718643587.394448566 qsampler-1.0.0/src/qsamplerOptions.h0000644000175000001440000000730714634065603016560 0ustar00rncbcusers// qsamplerOptions.h // /**************************************************************************** Copyright (C) 2004-2024, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007,2008,2015 Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #ifndef __qsamplerOptions_h #define __qsamplerOptions_h #include #include class QWidget; class QComboBox; namespace QSampler { //------------------------------------------------------------------------- // QSampler::Options - Prototype settings class. // class Options { public: // Constructor. Options(); // Default destructor. ~Options(); // The settings object accessor. QSettings& settings(); // explicit I/O methods. void loadOptions(); void saveOptions(); // Command line arguments parser. bool parse_args(const QStringList& args); #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) void show_error(const QString& msg); #else // Command line usage helper. void print_usage(const QString& arg0); #endif // Startup supplied session file(s). QStringList sessionFiles; // Server options... QString sServerHost; int iServerPort; int iServerTimeout; bool bServerStart; QString sServerCmdLine; int iStartDelay; // Logging options... bool bMessagesLog; QString sMessagesLogPath; // Display options... QString sDisplayFont; bool bDisplayEffect; bool bAutoRefresh; int iAutoRefreshTime; int iMaxVolume; QString sMessagesFont; bool bMessagesLimit; int iMessagesLimitLines; bool bConfirmRemove; bool bConfirmReset; bool bConfirmRestart; bool bConfirmError; bool bKeepOnTop; bool bStdoutCapture; bool bCompletePath; bool bInstrumentNames; int iBaseFontSize; QString sCustomColorTheme; QString sCustomStyleTheme; // View options... bool bMenubar; bool bToolbar; bool bStatusbar; bool bAutoArrange; // Default options... QString sSessionDir; QString sInstrumentDir; QString sEngineName; QString sAudioDriver; QString sMidiDriver; int iMidiMap; int iMidiBank; int iMidiProg; int iVolume; int iLoadMode; // Recent file list. int iMaxRecentFiles; QStringList recentFiles; // Widget geometry persistence helper prototypes. void saveWidgetGeometry(QWidget *pWidget, bool bVisible = false); void loadWidgetGeometry(QWidget *pWidget, bool bVisible = false); // Combo box history persistence helper prototypes. void loadComboBoxHistory(QComboBox *pComboBox, int iLimit = 8); void saveComboBoxHistory(QComboBox *pComboBox, int iLimit = 8); int getMaxVoices(); int getEffectiveMaxVoices(); void setMaxVoices(int iMaxVoices); int getMaxStreams(); int getEffectiveMaxStreams(); void setMaxStreams(int iMaxStreams); void sendFineTuningSettings(); private: // Settings member variables. QSettings m_settings; // Tuning int iMaxVoices; int iMaxStreams; }; } // namespace QSampler #endif // __qsamplerOptions_h // end of qsamplerOptions.h qsampler-1.0.0/src/PaxHeaders/qsamplerUtilities.cpp0000644000000000000000000000013214634065603017434 xustar0030 mtime=1718643587.395448566 30 atime=1718643587.395448566 30 ctime=1718643587.395448566 qsampler-1.0.0/src/qsamplerUtilities.cpp0000644000175000001440000001553114634065603017431 0ustar00rncbcusers// qsamplerUtilities.cpp // /**************************************************************************** Copyright (C) 2004-2020, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, 2008 Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #include "qsamplerUtilities.h" #include "qsamplerOptions.h" #include "qsamplerMainForm.h" #include using namespace QSampler; namespace qsamplerUtilities { static int _hexToNumber ( char hex_digit ) { switch (hex_digit) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'a': return 10; case 'b': return 11; case 'c': return 12; case 'd': return 13; case 'e': return 14; case 'f': return 15; case 'A': return 10; case 'B': return 11; case 'C': return 12; case 'D': return 13; case 'E': return 14; case 'F': return 15; default: return 0; } } static int _hexsToNumber ( char hex0, char hex1 ) { return _hexToNumber(hex1) * 16 + _hexToNumber(hex0); } static bool _isHex ( char hex_digit ) { return _hexToNumber ( hex_digit ) || hex_digit == '0'; } // returns true if the connected LSCP server supports escape sequences static bool _remoteSupportsEscapeSequences (void) { const lscpVersion_t version = getRemoteLscpVersion(); // LSCP v1.2 or younger required return (version.major > 1 || (version.major == 1 && version.minor >= 2)); } // converts the given file path into a path as expected by LSCP 1.2 QByteArray lscpEscapePath ( const QString& sPath ) { QByteArray path = sPath.toUtf8(); if (!_remoteSupportsEscapeSequences()) return path; const char pathSeparator = '/'; int path_len = path.length(); char buf[5]; // Trying single pass to avoid redundant checks on extra run for ( int i = 0; i < path_len; i++ ) { // translate POSIX escape sequences if (path[i] == '%') { // replace POSIX path escape sequences (%HH) by LSCP escape sequences (\xHH) // TODO: missing code for other systems like Windows if (_isHex(path[i+1]) && _isHex(path[i+2])) { path.replace (i, 1, "\\x"); path_len++; i += 3; continue; } // replace POSIX path escape sequence (%%) by its raw character if (path[i+1] == '%') { path.remove (i, 1); path_len--; continue; } continue; } // replace all non-basic characters by LSCP escape sequences // // match all non-alphanumerics // (we could exclude much more characters here, but that way // we're sure it just works^TM) const char c = path[i]; if ( !(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) !(c == ':') && #endif !(c == pathSeparator) ) { // convertion ::snprintf(buf, sizeof(buf), "\\x%02x", static_cast(c)); path = path.replace(i, 1, buf); path_len += 3; i += 3; } } return path; } // converts a path returned by a LSCP command (and may contain escape // sequences) into the appropriate POSIX path QString lscpEscapedPathToPosix ( const char* sPath ) { if (!_remoteSupportsEscapeSequences()) return QString(sPath); QByteArray path(sPath); int path_len = path.length(); char cAscii[2] = "\0"; for ( int i = 0; i < path_len; i++) { // first escape all percent ('%') characters for POSIX if (path[i] == '%') { path.insert(i, '%'); path_len++; i++; continue; } // resolve LSCP hex escape sequences (\xHH) if (path[i] == '\\' && path[i+1] == 'x' && _isHex(path[i+2]) && _isHex(path[i+3])) { const QByteArray sHex = path.mid(i + 2, 2).toLower(); // the slash has to be escaped for POSIX as well if (sHex == "2f") { path.replace(i, 4, "%2f"); // all other characters we simply decode } else { cAscii[0] = _hexsToNumber(sHex[1], sHex[0]); path.replace(i, 4, cAscii); } path_len -= 3; continue; } } return QString(path); } // converts the given text as expected by LSCP 1.2 // (that is by encoding special characters with LSCP escape sequences) QByteArray lscpEscapeText ( const QString& sText ) { QByteArray text = sText.toUtf8(); if (!_remoteSupportsEscapeSequences()) return text; int text_len = text.length(); char buf[5]; // replace all non-basic characters by LSCP escape sequences for (int i = 0; i < text_len; ++i) { // match all non-alphanumerics // (we could exclude much more characters here, but that way // we're sure it just works^TM) const char c = text[i]; if ( !(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') ) { // convert the non-basic character into a LSCP escape sequence ::snprintf(buf, sizeof(buf), "\\x%02x", static_cast(c)); text.replace(i, 1, buf); text_len += 3; i += 3; } } return text; } // converts a text returned by a LSCP command and may contain escape // sequences) into raw text, that is with all escape sequences decoded QString lscpEscapedTextToRaw ( const char* sText ) { if (!_remoteSupportsEscapeSequences()) return QString(sText); QByteArray text(sText); int text_len = text.length(); char sHex[2], cAscii[2] = "\0"; // resolve LSCP hex escape sequences (\xHH) for (int i = 0; i < text_len; i++) { if (text[i] != '\\' || text[i+1] != 'x') continue; sHex[0] = text[i+2], sHex[1] = text[i+3]; if (_isHex(sHex[0]) && _isHex(sHex[1])) { cAscii[0] = _hexsToNumber(sHex[1], sHex[0]); text.replace(i, 4, cAscii); text_len -= 3; } } return QString(text); } lscpVersion_t getRemoteLscpVersion (void) { lscpVersion_t result = { 0, 0 }; MainForm* pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return result; if (pMainForm->client() == nullptr) return result; lscp_server_info_t* pServerInfo = ::lscp_get_server_info(pMainForm->client()); if (pServerInfo && pServerInfo->protocol_version) ::sscanf(pServerInfo->protocol_version, "%d.%d", &result.major, &result.minor); return result; } } // namespace qsamplerUtilities // end of qsamplerUtilities.cpp qsampler-1.0.0/src/PaxHeaders/qsamplerFxSend.h0000644000000000000000000000013214634065603016315 xustar0030 mtime=1718643587.393448566 30 atime=1718643587.393448566 30 ctime=1718643587.393448566 qsampler-1.0.0/src/qsamplerFxSend.h0000644000175000001440000000453514634065603016314 0ustar00rncbcusers// qsamplerFxSend.h // /**************************************************************************** Copyright (C) 2004-2019, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2008, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #ifndef __qsamplerFxSend_h #define __qsamplerFxSend_h #include #include #include namespace QSampler { // Typedef'd QMap. typedef QMap FxSendRoutingMap; class FxSend { public: // retrieve existing FX send FxSend(int SamplerChannelID, int FxSendID); // create a new FX send FxSend(int SamplerChannelID); ~FxSend(); int id() const; // whether FX send exists on sampler side yet bool isNew() const; // whether scheduled for deletion bool deletion() const; void setDeletion(bool bDelete); bool isModified() const; void setName(const QString& sName); const QString& name() const; void setSendDepthMidiCtrl(int iMidiController); int sendDepthMidiCtrl() const; void setCurrentDepth(float depth); float currentDepth() const; // Audio routing accessors. int audioChannel(int iAudioSrc) const; bool setAudioChannel(int iAudioSrc, int iAudioDst); // The audio routing map itself. const FxSendRoutingMap& audioRouting() const; bool getFromSampler(); bool applyToSampler(); static QList allFxSendsOfSamplerChannel(int samplerChannelID); private: int m_iSamplerChannelID; int m_iFxSendID; bool m_bDelete; bool m_bModified; QString m_FxSendName; int m_MidiCtrl; float m_Depth; FxSendRoutingMap m_AudioRouting; }; } // namespace QSampler #endif // __qsamplerFxSend_h // end of __qsamplerFxSend.h qsampler-1.0.0/src/PaxHeaders/qsamplerMainForm.h0000644000000000000000000000013214634065603016636 xustar0030 mtime=1718643587.394448566 30 atime=1718643587.394448566 30 ctime=1718643587.394448566 qsampler-1.0.0/src/qsamplerMainForm.h0000644000175000001440000001244114634065603016630 0ustar00rncbcusers// qsamplerMainForm.h // /**************************************************************************** Copyright (C) 2004-2024, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007-2019 Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #ifndef __qsamplerMainForm_h #define __qsamplerMainForm_h #include "ui_qsamplerMainForm.h" #include class QProcess; class QMdiSubWindow; class QSocketNotifier; class QSpinBox; class QSlider; class QLabel; namespace QSampler { class Workspace; class Options; class Messages; class Channel; class ChannelStrip; class DeviceForm; class InstrumentListForm; //------------------------------------------------------------------------- // QSampler::MainForm -- Main window form implementation. // class MainForm : public QMainWindow { Q_OBJECT public: MainForm(QWidget *pParent = nullptr); ~MainForm(); void setup(Options *pOptions); Options *options() const; lscp_client_t *client() const; QString sessionName(const QString& sFilename); void appendMessages(const QString& s); void appendMessagesColor(const QString& s, const QColor& rgb); void appendMessagesText(const QString& s); void appendMessagesError(const QString& s); void appendMessagesClient(const QString& s); ChannelStrip *createChannelStrip(Channel *pChannel); void destroyChannelStrip(ChannelStrip *pChannelStrip); ChannelStrip *activeChannelStrip(); ChannelStrip *channelStripAt(int iChannel); ChannelStrip *channelStrip(int iChannelID); void channelsArrangeAuto(); void contextMenuEvent(QContextMenuEvent *pEvent); void sessionDirty(); static MainForm *getInstance(); public slots: void fileNew(); void fileOpen(); void fileOpenRecent(); void fileSave(); void fileSaveAs(); void fileReset(); void fileRestart(); void fileExit(); void editAddChannel(); void editRemoveChannel(); void editSetupChannel(); void editEditChannel(); void editResetChannel(); void editResetAllChannels(); void viewMenubar(bool bOn); void viewToolbar(bool bOn); void viewStatusbar(bool bOn); void viewMessages(bool bOn); void viewInstruments(); void viewDevices(); void viewOptions(); void channelsArrange(); void channelsAutoArrange(bool bOn); void helpAboutQt(); void helpAbout(); void stabilizeForm(); protected slots: void updateRecentFilesMenu(); void volumeChanged(int iVolume); void channelStripChanged(ChannelStrip *pChannelStrip); void channelsMenuAboutToShow(); void channelsMenuActivated(); void timerSlot(); void readServerStdout(); void processServerExit(); void autoReconnectClient(); void handle_sigusr1(); void handle_sigterm(); // Channel strip activation/selection. void activateStrip(QMdiSubWindow *pMdiSubWindow); // Channel toolbar orientation change. void channelsToolbarOrientation(Qt::Orientation orientation); protected: void addChannelStrip(); void removeChannelStrip(); bool queryClose(); void closeEvent(QCloseEvent* pCloseEvent); void dragEnterEvent(QDragEnterEvent *pDragEnterEvent); void dropEvent(QDropEvent *pDropEvent); void customEvent(QEvent *pCustomEvent); bool newSession(); bool openSession(); bool saveSession(bool bPrompt); bool closeSession(bool bForce); bool loadSessionFile(const QString& sFilename); bool saveSessionFile(const QString& sFilename); void updateSession(); void updateRecentFiles(const QString& sFilename); void updateInstrumentNames(); void updateDisplayFont(); void updateDisplayEffect(); void updateMaxVolume(); void updateMessagesFont(); void updateMessagesLimit(); void updateMessagesCapture(); void updateViewMidiDeviceStatusMenu(); void updateAllChannelStrips(bool bRemoveDeadStrips); void startSchedule(int iStartDelay); void stopSchedule(); void startServer(); void stopServer(bool bInteractive = false); bool startClient(bool bReconnectOnly = false); void stopClient(); void startAutoReconnectClient(); private: Ui::qsamplerMainForm m_ui; Options *m_pOptions; Messages *m_pMessages; Workspace *m_pWorkspace; QSocketNotifier *m_pSigusr1Notifier; QSocketNotifier *m_pSigtermNotifier; QString m_sFilename; int m_iUntitled; int m_iDirtySetup; int m_iDirtyCount; lscp_client_t *m_pClient; QProcess *m_pServer; bool m_bForceServerStop; int m_iStartDelay; int m_iTimerDelay; int m_iTimerSlot; QLabel *m_statusItem[5]; QList m_changedStrips; InstrumentListForm *m_pInstrumentListForm; DeviceForm *m_pDeviceForm; static MainForm *g_pMainForm; QSlider *m_pVolumeSlider; QSpinBox *m_pVolumeSpinBox; int m_iVolumeChanging; }; } // namespace QSampler #endif // __qsamplerMainForm_h // end of qsamplerMainForm.h qsampler-1.0.0/src/PaxHeaders/qsamplerInstrumentForm.cpp0000644000000000000000000000013214634065603020455 xustar0030 mtime=1718643587.393448566 30 atime=1718643587.393448566 30 ctime=1718643587.393448566 qsampler-1.0.0/src/qsamplerInstrumentForm.cpp0000644000175000001440000002656714634065603020465 0ustar00rncbcusers// qsamplerInstrumentForm.cpp // /**************************************************************************** Copyright (C) 2003-2021, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *****************************************************************************/ #include "qsamplerAbout.h" #include "qsamplerInstrumentForm.h" #include "qsamplerOptions.h" #include "qsamplerChannel.h" #include "qsamplerMainForm.h" #include #include #include // Needed for lroundf() #ifdef CONFIG_ROUND #include #else static inline long lroundf ( float x ) { if (x >= 0.0f) return long(x + 0.5f); else return long(x - 0.5f); } #endif namespace QSampler { //------------------------------------------------------------------------- // QSampler::InstrumentForm -- Instrument map item form implementation. // InstrumentForm::InstrumentForm ( QWidget *pParent ) : QDialog(pParent) { m_ui.setupUi(this); // Initialize locals. m_pInstrument = nullptr; m_iDirtySetup = 0; m_iDirtyCount = 0; m_iDirtyName = 0; // Try to restore normal window positioning. adjustSize(); QObject::connect(m_ui.MapComboBox, SIGNAL(activated(int)), SLOT(changed())); QObject::connect(m_ui.BankSpinBox, SIGNAL(valueChanged(int)), SLOT(changed())); QObject::connect(m_ui.ProgSpinBox, SIGNAL(valueChanged(int)), SLOT(changed())); QObject::connect(m_ui.NameLineEdit, SIGNAL(textChanged(const QString&)), SLOT(nameChanged(const QString&))); QObject::connect(m_ui.EngineNameComboBox, SIGNAL(activated(int)), SLOT(changed())); QObject::connect(m_ui.InstrumentFileComboBox, SIGNAL(activated(const QString&)), SLOT(updateInstrumentName())); QObject::connect(m_ui.InstrumentFileToolButton, SIGNAL(clicked()), SLOT(openInstrumentFile())); QObject::connect(m_ui.InstrumentNrComboBox, SIGNAL(activated(int)), SLOT(instrumentNrChanged())); QObject::connect(m_ui.VolumeSpinBox, SIGNAL(valueChanged(int)), SLOT(changed())); QObject::connect(m_ui.LoadModeComboBox, SIGNAL(activated(int)), SLOT(changed())); QObject::connect(m_ui.DialogButtonBox, SIGNAL(accepted()), SLOT(accept())); QObject::connect(m_ui.DialogButtonBox, SIGNAL(rejected()), SLOT(reject())); } InstrumentForm::~InstrumentForm (void) { } // Channel dialog setup formal initializer. void InstrumentForm::setup ( Instrument *pInstrument ) { m_pInstrument = pInstrument; m_iDirtySetup = 0; m_iDirtyCount = 0; m_iDirtyName = 0; if (m_pInstrument == nullptr) return; // Check if we're up and connected. MainForm* pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; if (pMainForm->client() == nullptr) return; Options *pOptions = pMainForm->options(); if (pOptions == nullptr) return; // It can be a brand new channel, remember? bool bNew = (m_pInstrument->bank() < 0 || m_pInstrument->prog() < 0); if (!bNew) { m_pInstrument->getInstrument(); m_iDirtyName++; } // Avoid nested changes. m_iDirtySetup++; // Load combo box history... pOptions->loadComboBoxHistory(m_ui.InstrumentFileComboBox); // Populate maps list. m_ui.MapComboBox->clear(); m_ui.MapComboBox->insertItems(0, Instrument::getMapNames()); // Populate Engines list. const char **ppszEngines = ::lscp_list_available_engines(pMainForm->client()); if (ppszEngines) { m_ui.EngineNameComboBox->clear(); for (int iEngine = 0; ppszEngines[iEngine]; iEngine++) m_ui.EngineNameComboBox->addItem(ppszEngines[iEngine]); } else pMainForm->appendMessagesClient("lscp_list_available_engines"); // Read proper instrument information, // and populate the instrument form fields. // Instrument map name... int iMap = (bNew ? pOptions->iMidiMap : m_pInstrument->map()); if (iMap < 0) iMap = 0; const QString& sMapName = Instrument::getMapName(iMap); if (!sMapName.isEmpty()) { m_ui.MapComboBox->setCurrentIndex( m_ui.MapComboBox->findText(sMapName, Qt::MatchExactly | Qt::MatchCaseSensitive)); } // It might be no maps around... bool bMapEnabled = (m_ui.MapComboBox->count() > 0); m_ui.MapTextLabel->setEnabled(bMapEnabled); m_ui.MapComboBox->setEnabled(bMapEnabled); // Instrument bank/program... int iBank = (bNew ? pOptions->iMidiBank : m_pInstrument->bank()); int iProg = (bNew ? pOptions->iMidiProg : m_pInstrument->prog()) + 1; if (bNew && iProg > 128) { iProg = 1; iBank++; } m_ui.BankSpinBox->setValue(iBank); m_ui.ProgSpinBox->setValue(iProg); // Instrument name... m_ui.NameLineEdit->setText(m_pInstrument->name()); // Engine name... QString sEngineName = m_pInstrument->engineName(); if (sEngineName.isEmpty() || bNew) sEngineName = pOptions->sEngineName; if (sEngineName.isEmpty()) sEngineName = Channel::noEngineName(); if (m_ui.EngineNameComboBox->findText(sEngineName, Qt::MatchExactly | Qt::MatchCaseSensitive) < 0) { m_ui.EngineNameComboBox->addItem(sEngineName); } m_ui.EngineNameComboBox->setCurrentIndex( m_ui.EngineNameComboBox->findText(sEngineName, Qt::MatchExactly | Qt::MatchCaseSensitive)); // Instrument filename and index... QString sInstrumentFile = m_pInstrument->instrumentFile(); if (sInstrumentFile.isEmpty()) sInstrumentFile = Channel::noInstrumentName(); m_ui.InstrumentFileComboBox->setEditText(sInstrumentFile); m_ui.InstrumentNrComboBox->clear(); m_ui.InstrumentNrComboBox->insertItems(0, Channel::getInstrumentList(sInstrumentFile, pOptions->bInstrumentNames)); m_ui.InstrumentNrComboBox->setCurrentIndex(m_pInstrument->instrumentNr()); // Instrument volume.... int iVolume = (bNew ? pOptions->iVolume : ::lroundf(100.0f * m_pInstrument->volume())); m_ui.VolumeSpinBox->setValue(iVolume); // Instrument load mode... int iLoadMode = (bNew ? pOptions->iLoadMode : m_pInstrument->loadMode()); m_ui.LoadModeComboBox->setCurrentIndex(iLoadMode); // Done. m_iDirtySetup--; stabilizeForm(); } // Special case for name change, void InstrumentForm::nameChanged ( const QString& /* sName */ ) { if (m_iDirtySetup > 0) return; m_iDirtyName++; changed(); } // Browse and open an instrument file. void InstrumentForm::openInstrumentFile (void) { MainForm* pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; Options *pOptions = pMainForm->options(); if (pOptions == nullptr) return; // FIXME: the instrument file filters should be restricted, // depending on the current engine. const QString& sEngineName = m_ui.EngineNameComboBox->currentText().toUpper(); QStringList filters; if (sEngineName.contains("GIG")) filters << tr("GIG Instrument files") + " (*.gig *.dls)"; if (sEngineName.contains("SFZ")) filters << tr("SFZ Instrument files") + " (*.sfz)"; if (sEngineName.contains("SF2")) filters << tr("SF2 Instrument files") + " (*.sf2)"; const QString& filter = filters.join(";;"); QString sInstrumentFile = QFileDialog::getOpenFileName(this, tr("Instrument files"), // Caption. pOptions->sInstrumentDir, // Start here. filter // File filter. ); if (sInstrumentFile.isEmpty()) return; m_ui.InstrumentFileComboBox->setEditText(sInstrumentFile); updateInstrumentName(); } // Refresh the actual instrument name. void InstrumentForm::updateInstrumentName (void) { MainForm* pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; Options *pOptions = pMainForm->options(); if (pOptions == nullptr) return; // TODO: this better idea would be to use libgig // to retrieve the REAL instrument names. m_ui.InstrumentNrComboBox->clear(); m_ui.InstrumentNrComboBox->insertItems(0, Channel::getInstrumentList( m_ui.InstrumentFileComboBox->currentText(), pOptions->bInstrumentNames) ); instrumentNrChanged(); } // Special case for instrumnet index change, void InstrumentForm::instrumentNrChanged (void) { if (m_iDirtySetup > 0) return; if (m_ui.NameLineEdit->text().isEmpty() || m_iDirtyName == 0) { m_ui.NameLineEdit->setText(m_ui.InstrumentNrComboBox->currentText()); m_iDirtyName = 0; } changed(); } // Accept settings (OK button slot). void InstrumentForm::accept (void) { if (m_pInstrument == nullptr) return; MainForm* pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; if (pMainForm->client() == nullptr) return; Options *pOptions = pMainForm->options(); if (pOptions == nullptr) return; if (m_iDirtyCount > 0) { m_pInstrument->setMap(m_ui.MapComboBox->currentIndex()); m_pInstrument->setBank(m_ui.BankSpinBox->value()); m_pInstrument->setProg(m_ui.ProgSpinBox->value() - 1); m_pInstrument->setName(m_ui.NameLineEdit->text()); m_pInstrument->setEngineName(m_ui.EngineNameComboBox->currentText()); m_pInstrument->setInstrumentFile(m_ui.InstrumentFileComboBox->currentText()); m_pInstrument->setInstrumentNr(m_ui.InstrumentNrComboBox->currentIndex()); m_pInstrument->setVolume(0.01f * float(m_ui.VolumeSpinBox->value())); m_pInstrument->setLoadMode(m_ui.LoadModeComboBox->currentIndex()); } // Save default engine name, instrument directory and history... pOptions->sInstrumentDir = QFileInfo( m_ui.InstrumentFileComboBox->currentText()).dir().absolutePath(); pOptions->sEngineName = m_ui.EngineNameComboBox->currentText(); pOptions->iMidiMap = m_ui.MapComboBox->currentIndex(); pOptions->iMidiBank = m_ui.BankSpinBox->value(); pOptions->iMidiProg = m_ui.ProgSpinBox->value(); pOptions->iVolume = m_ui.VolumeSpinBox->value(); pOptions->iLoadMode = m_ui.LoadModeComboBox->currentIndex(); pOptions->saveComboBoxHistory(m_ui.InstrumentFileComboBox); // Just go with dialog acceptance. QDialog::accept(); } // Reject settings (Cancel button slot). void InstrumentForm::reject (void) { bool bReject = true; // Check if there's any pending changes... if (m_iDirtyCount > 0) { switch (QMessageBox::warning(this, tr("Warning"), tr("Some channel settings have been changed.\n\n" "Do you want to apply the changes?"), QMessageBox::Apply | QMessageBox::Discard | QMessageBox::Cancel)) { case QMessageBox::Apply: accept(); return; case QMessageBox::Discard: break; default: // Cancel. bReject = false; break; } } if (bReject) QDialog::reject(); } // Dirty up settings. void InstrumentForm::changed (void) { if (m_iDirtySetup > 0) return; m_iDirtyCount++; stabilizeForm(); } // Stabilize current form state. void InstrumentForm::stabilizeForm (void) { bool bValid = !m_ui.NameLineEdit->text().isEmpty() && m_ui.EngineNameComboBox->currentIndex() >= 0 && m_ui.EngineNameComboBox->currentText() != Channel::noEngineName(); const QString& sPath = m_ui.InstrumentFileComboBox->currentText(); bValid = bValid && !sPath.isEmpty() && QFileInfo(sPath).exists(); m_ui.DialogButtonBox->button( QDialogButtonBox::Ok)->setEnabled(m_iDirtyCount > 0 && bValid); } } // namespace QSampler // end of qsamplerInstrumentForm.cpp qsampler-1.0.0/src/PaxHeaders/CMakeLists.txt0000644000000000000000000000013214634065603015750 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/CMakeLists.txt0000644000175000001440000001257014634065603015745 0ustar00rncbcusers# project (qsampler) set (CMAKE_INCLUDE_CURRENT_DIR ON) set (CMAKE_AUTOUIC ON) set (CMAKE_AUTOMOC ON) set (CMAKE_AUTORCC ON) if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/config.h) file (REMOVE ${CMAKE_CURRENT_SOURCE_DIR}/config.h) endif () configure_file (config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) set (HEADERS qsampler.h qsamplerAbout.h qsamplerOptions.h qsamplerChannel.h qsamplerMessages.h qsamplerInstrument.h qsamplerInstrumentList.h qsamplerDevice.h qsamplerFxSend.h qsamplerFxSendsModel.h qsamplerUtilities.h qsamplerInstrumentForm.h qsamplerInstrumentListForm.h qsamplerDeviceForm.h qsamplerDeviceStatusForm.h qsamplerChannelStrip.h qsamplerChannelForm.h qsamplerChannelFxForm.h qsamplerOptionsForm.h qsamplerPaletteForm.h qsamplerMainForm.h ) set (SOURCES qsampler.cpp qsamplerOptions.cpp qsamplerChannel.cpp qsamplerMessages.cpp qsamplerInstrument.cpp qsamplerInstrumentList.cpp qsamplerDevice.cpp qsamplerFxSend.cpp qsamplerFxSendsModel.cpp qsamplerUtilities.cpp qsamplerInstrumentForm.cpp qsamplerInstrumentListForm.cpp qsamplerDeviceForm.cpp qsamplerDeviceStatusForm.cpp qsamplerChannelStrip.cpp qsamplerChannelForm.cpp qsamplerChannelFxForm.cpp qsamplerOptionsForm.cpp qsamplerPaletteForm.cpp qsamplerMainForm.cpp ) set (FORMS qsamplerInstrumentForm.ui qsamplerInstrumentListForm.ui qsamplerDeviceForm.ui qsamplerChannelStrip.ui qsamplerChannelForm.ui qsamplerChannelFxForm.ui qsamplerOptionsForm.ui qsamplerPaletteForm.ui qsamplerMainForm.ui ) set (RESOURCES qsampler.qrc ) set (TRANSLATIONS translations/qsampler_cs.ts translations/qsampler_fr.ts translations/qsampler_ru.ts ) if (QT_VERSION VERSION_LESS 5.15.0) qt5_add_translation (QM_FILES ${TRANSLATIONS}) else () qt_add_translation (QM_FILES ${TRANSLATIONS}) endif () add_custom_target (translations ALL DEPENDS ${QM_FILES}) if (WIN32) set (RC_FILE ${CMAKE_CURRENT_SOURCE_DIR}/win32/${PROJECT_NAME}.rc) set (RES_FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.res.obj) find_program (WINDRES_EXECUTABLE NAMES windres mingw32-windres i686-mingw32-windres) if (MINGW) exec_program (${WINDRES_EXECUTABLE} ARGS "-i ${RC_FILE} -o ${RES_FILE} --include-dir=${CMAKE_CURRENT_SOURCE_DIR}/images") list (APPEND SOURCES ${RES_FILE}) else () list (APPEND SOURCES ${RC_FILE}) endif () endif () if (APPLE) set (ICON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/images/${PROJECT_NAME}.icns) list (APPEND SOURCES ${ICON_FILE}) set (MACOSX_BUNDLE_ICON_FILE ${PROJECT_NAME}.icns) set_source_files_properties (${ICON_FILE} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) endif () add_executable (${PROJECT_NAME} ${HEADERS} ${SOURCES} ${FORMS} ${RESOURCES} ) # Add some debugger flags. if (CONFIG_DEBUG AND UNIX AND NOT APPLE) set (CONFIG_DEBUG_OPTIONS -g -fsanitize=address -fno-omit-frame-pointer) target_compile_options (${PROJECT_NAME} PRIVATE ${CONFIG_DEBUG_OPTIONS}) target_link_options (${PROJECT_NAME} PRIVATE ${CONFIG_DEBUG_OPTIONS}) endif () set_target_properties (${PROJECT_NAME} PROPERTIES CXX_STANDARD 17) if (WIN32) set_target_properties (${PROJECT_NAME} PROPERTIES WIN32_EXECUTABLE true) endif () if (APPLE) set_target_properties (${PROJECT_NAME} PROPERTIES MACOSX_BUNDLE true) endif () target_link_libraries (${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Svg) if (CONFIG_XUNIQUE) target_link_libraries (${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Network) endif () if (CONFIG_LIBLSCP) target_link_libraries (${PROJECT_NAME} PRIVATE PkgConfig::LSCP) endif () if (CONFIG_LIBGIG) target_link_libraries (${PROJECT_NAME} PRIVATE PkgConfig::GIG) endif () if (UNIX AND NOT APPLE) install (TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install (FILES ${QM_FILES} DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/translations) install (FILES images/${PROJECT_NAME}.png RENAME org.rncbc.${PROJECT_NAME}.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/32x32/apps) install (FILES images/${PROJECT_NAME}.svg RENAME org.rncbc.${PROJECT_NAME}.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps) install (FILES appdata/org.rncbc.${PROJECT_NAME}.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) install (FILES appdata/org.rncbc.${PROJECT_NAME}.metainfo.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/metainfo) install (FILES mimetypes/org.rncbc.${PROJECT_NAME}.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/mime/packages) install (FILES mimetypes/org.rncbc.${PROJECT_NAME}.application-x-${PROJECT_NAME}-session.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/32x32/mimetypes) install (FILES mimetypes/org.rncbc.${PROJECT_NAME}.application-x-${PROJECT_NAME}-session.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/mimetypes) install (FILES man1/${PROJECT_NAME}.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) install (FILES man1/${PROJECT_NAME}.fr.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/fr/man1 RENAME ${PROJECT_NAME}.1) install (FILES palette/KXStudio.conf palette/Wonton\ Soup.conf DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/palette) endif () if (WIN32) install (TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) install (FILES ${QM_FILES} DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/translations) endif () qsampler-1.0.0/src/PaxHeaders/qsamplerPaletteForm.h0000644000000000000000000000013214634065603017350 xustar0030 mtime=1718643587.394448566 30 atime=1718643587.394448566 30 ctime=1718643587.394448566 qsampler-1.0.0/src/qsamplerPaletteForm.h0000644000175000001440000001710614634065603017345 0ustar00rncbcusers// qsamplerPaletteForm.h // /**************************************************************************** Copyright (C) 2004-2024, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #ifndef __qsamplerPaletteForm_h #define __qsamplerPaletteForm_h #include #include #include #include #include #include // Forward decls. class QListView; class QLabel; class QToolButton; namespace Ui { class qsamplerPaletteForm; } namespace QSampler { //------------------------------------------------------------------------- // QSampler::PaletteForm class PaletteForm: public QDialog { Q_OBJECT public: PaletteForm(QWidget *parent = nullptr, const QPalette& pal = QPalette()); virtual ~PaletteForm(); void setPalette(const QPalette& pal); const QPalette& palette() const; void setSettings(QSettings *settings, bool owner = false); QSettings *settings() const; void setPaletteName(const QString& name); QString paletteName() const; bool isDirty() const; static bool namedPalette(QSettings *settings, const QString& name, QPalette& pal, bool fixup = false); static QStringList namedPaletteList(QSettings *settings); static QString namedPaletteConf( QSettings *settings, const QString& name); static void addNamedPaletteConf( QSettings *settings, const QString& name, const QString& filename); static QPalette::ColorRole colorRole(const QString& name); class PaletteModel; class ColorDelegate; class ColorButton; class ColorEditor; class RoleEditor; protected slots: void nameComboChanged(const QString& name); void saveButtonClicked(); void deleteButtonClicked(); void generateButtonChanged(); void resetButtonClicked(); void detailsCheckClicked(); void importButtonClicked(); void exportButtonClicked(); void paletteChanged(const QPalette& pal); void accept(); void reject(); protected: void setPalette(const QPalette& pal, const QPalette& parentPal); bool namedPalette(const QString& name, QPalette& pal) const; QStringList namedPaletteList() const; QString namedPaletteConf(const QString& name) const; void addNamedPaletteConf(const QString& name, const QString& filename); void deleteNamedPaletteConf(const QString& name); static bool loadNamedPaletteConf( const QString& name, const QString& filename, QPalette& pal); static bool saveNamedPaletteConf( const QString& name, const QString& filename, const QPalette& pal); static bool loadNamedPalette( QSettings *settings, const QString& name, QPalette& pal); static bool saveNamedPalette( QSettings *settings, const QString& name, const QPalette& pal); void updateNamedPaletteList(); void updateGenerateButton(); void updateDialogButtons(); void setDefaultDir(const QString& dir); QString defaultDir() const; void setShowDetails(bool on); bool isShowDetails() const; void showEvent(QShowEvent *event); void resizeEvent(QResizeEvent *event); private: Ui::qsamplerPaletteForm *p_ui; Ui::qsamplerPaletteForm& m_ui; QSettings *m_settings; bool m_owner; QPalette m_palette; QPalette m_parentPalette; PaletteModel *m_paletteModel; bool m_modelUpdated; bool m_paletteUpdated; int m_dirtyCount; int m_dirtyTotal; }; //------------------------------------------------------------------------- // QSampler::PaletteForm::PaletteModel class PaletteForm::PaletteModel : public QAbstractTableModel { Q_OBJECT Q_PROPERTY(QPalette::ColorRole colorRole READ colorRole) public: PaletteModel(QObject *parent = nullptr); int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role) const; bool setData(const QModelIndex &index, const QVariant &value, int role); Qt::ItemFlags flags(const QModelIndex &index) const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; void setPalette(const QPalette &palette, const QPalette &parentPalette); const QPalette& palette() const; void setGenerate(bool on) { m_generate = on; } QPalette::ColorRole colorRole() const { return QPalette::NoRole; } signals: void paletteChanged(const QPalette &palette); protected: QPalette::ColorGroup columnToGroup(int index) const; int groupToColumn(QPalette::ColorGroup group) const; private: QPalette m_palette; QPalette m_parentPalette; QMap m_roleNames; int m_nrows; bool m_generate; }; //------------------------------------------------------------------------- // QSampler::PaletteForm::ColorDelegate class PaletteForm::ColorDelegate : public QItemDelegate { public: ColorDelegate(QObject *parent = nullptr) : QItemDelegate(parent) {} QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem& option, const QModelIndex& index) const; void setEditorData(QWidget *editor, const QModelIndex& index) const; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem& option, const QModelIndex &index) const; virtual void paint(QPainter *painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; }; //------------------------------------------------------------------------- // QSampler::PaletteForm::ColorButton class PaletteForm::ColorButton : public QPushButton { Q_OBJECT Q_PROPERTY(QBrush brush READ brush WRITE setBrush) public: ColorButton (QWidget *parent = nullptr); const QBrush& brush() const; void setBrush(const QBrush& b); signals: void changed(); protected slots: void chooseColor(); protected: void paintEvent(QPaintEvent *event); private: QBrush m_brush; }; //------------------------------------------------------------------------- // QSampler::PaleteEditor::ColorEditor class PaletteForm::ColorEditor : public QWidget { Q_OBJECT public: ColorEditor(QWidget *parent = nullptr); void setColor(const QColor &color); QColor color() const; bool changed() const; signals: void changed(QWidget *widget); protected slots: void colorChanged(); private: PaletteForm::ColorButton *m_button; bool m_changed; }; //------------------------------------------------------------------------- // QSampler::PaleteEditor::RoleEditor class PaletteForm::RoleEditor : public QWidget { Q_OBJECT public: RoleEditor(QWidget *parent = nullptr); void setLabel(const QString &label); void setEdited(bool on); bool edited() const; signals: void changed(QWidget *widget); protected slots: void resetProperty(); private: QLabel *m_label; QToolButton *m_button; bool m_edited; }; } // namespace QSampler #endif // __qsamplerPaletteForm_h // end of qsamplerPaletteForm.h qsampler-1.0.0/src/PaxHeaders/qsamplerChannelStrip.cpp0000644000000000000000000000013214634065603020053 xustar0030 mtime=1718643587.392448566 30 atime=1718643587.392448566 30 ctime=1718643587.392448566 qsampler-1.0.0/src/qsamplerChannelStrip.cpp0000644000175000001440000004261314634065603020051 0ustar00rncbcusers// qsamplerChannelStrip.cpp // /**************************************************************************** Copyright (C) 2004-2021, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, 2008, 2014 Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #include "qsamplerAbout.h" #include "qsamplerChannelStrip.h" #include "qsamplerMainForm.h" #include "qsamplerChannelFxForm.h" #include #include #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) #include #endif // Channel status/usage usage limit control. #define QSAMPLER_ERROR_LIMIT 3 // Needed for lroundf() #ifdef CONFIG_ROUND #include #else static inline long lroundf ( float x ) { if (x >= 0.0f) return long(x + 0.5f); else return long(x - 0.5f); } #endif namespace QSampler { //------------------------------------------------------------------------- // QSampler::ChannelStrip -- Channel strip form implementation. // // MIDI activity pixmap common resources. int ChannelStrip::g_iMidiActivityRefCount = 0; QPixmap *ChannelStrip::g_pMidiActivityLedOn = nullptr; QPixmap *ChannelStrip::g_pMidiActivityLedOff = nullptr; // Channel strip activation/selection. ChannelStrip *ChannelStrip::g_pSelectedStrip = nullptr; ChannelStrip::ChannelStrip ( QWidget* pParent, Qt::WindowFlags wflags ) : QWidget(pParent, wflags) { m_ui.setupUi(this); // Initialize locals. m_pChannel = nullptr; m_iDirtyChange = 0; m_iErrorCount = 0; m_instrumentListPopupMenu = nullptr; if (++g_iMidiActivityRefCount == 1) { g_pMidiActivityLedOn = new QPixmap(":/images/ledon1.png"); g_pMidiActivityLedOff = new QPixmap(":/images/ledoff1.png"); } m_ui.MidiActivityLabel->setPixmap(*g_pMidiActivityLedOff); #ifndef CONFIG_EVENT_CHANNEL_MIDI m_ui.MidiActivityLabel->setToolTip("MIDI activity (disabled)"); #endif m_pMidiActivityTimer = new QTimer(this); m_pMidiActivityTimer->setSingleShot(true); QObject::connect(m_pMidiActivityTimer, SIGNAL(timeout()), SLOT(midiActivityLedOff()) ); // Try to restore normal window positioning. adjustSize(); QObject::connect(m_ui.ChannelSetupPushButton, SIGNAL(clicked()), SLOT(channelSetup())); QObject::connect(m_ui.ChannelMutePushButton, SIGNAL(toggled(bool)), SLOT(channelMute(bool))); QObject::connect(m_ui.ChannelSoloPushButton, SIGNAL(toggled(bool)), SLOT(channelSolo(bool))); QObject::connect(m_ui.ChannelVolumeSlider, SIGNAL(valueChanged(int)), SLOT(volumeChanged(int))); QObject::connect(m_ui.ChannelVolumeSpinBox, SIGNAL(valueChanged(int)), SLOT(volumeChanged(int))); QObject::connect(m_ui.ChannelEditPushButton, SIGNAL(clicked()), SLOT(channelEdit())); QObject::connect(m_ui.ChannelFxPushButton, SIGNAL(clicked()), SLOT(channelFxEdit())); setSelected(false); } ChannelStrip::~ChannelStrip (void) { setSelected(false); // Destroy existing channel descriptor. if (m_pChannel) delete m_pChannel; m_pChannel = nullptr; if (--g_iMidiActivityRefCount == 0) { if (g_pMidiActivityLedOn) delete g_pMidiActivityLedOn; g_pMidiActivityLedOn = nullptr; if (g_pMidiActivityLedOff) delete g_pMidiActivityLedOff; g_pMidiActivityLedOff = nullptr; } } // Window drag-n-drop event handlers. void ChannelStrip::dragEnterEvent ( QDragEnterEvent* pDragEnterEvent ) { if (m_pChannel == nullptr) return; bool bAccept = false; if (pDragEnterEvent->source() == nullptr) { const QMimeData *pMimeData = pDragEnterEvent->mimeData(); if (pMimeData && pMimeData->hasUrls()) { QListIterator iter(pMimeData->urls()); while (iter.hasNext()) { const QString& sFilename = iter.next().toLocalFile(); if (!sFilename.isEmpty()) { // bAccept = Channel::isDlsInstrumentFile(sFilename); bAccept = QFileInfo(sFilename).exists(); break; } } } } if (bAccept) pDragEnterEvent->accept(); else pDragEnterEvent->ignore(); } void ChannelStrip::dropEvent ( QDropEvent* pDropEvent ) { if (m_pChannel == nullptr) return; if (pDropEvent->source()) return; const QMimeData *pMimeData = pDropEvent->mimeData(); if (pMimeData && pMimeData->hasUrls()) { QStringList files; QListIterator iter(pMimeData->urls()); while (iter.hasNext()) { const QString& sFilename = iter.next().toLocalFile(); if (!sFilename.isEmpty()) { // Go and set the dropped instrument filename... m_pChannel->setInstrument(sFilename, 0); // Open up the channel dialog. channelSetup(); break; } } } } // Channel strip setup formal initializer. void ChannelStrip::setup ( Channel *pChannel ) { // Destroy any previous channel descriptor; // (remember that once setup we own it!) if (m_pChannel) delete m_pChannel; // Set the new one... m_pChannel = pChannel; // Stabilize this around. updateChannelInfo(); // We'll accept drops from now on... if (m_pChannel) setAcceptDrops(true); } // Channel secriptor accessor. Channel *ChannelStrip::channel (void) const { return m_pChannel; } // Messages view font accessors. QFont ChannelStrip::displayFont (void) const { return m_ui.EngineNameTextLabel->font(); } void ChannelStrip::setDisplayFont ( const QFont & font ) { m_ui.EngineNameTextLabel->setFont(font); m_ui.MidiPortChannelTextLabel->setFont(font); m_ui.InstrumentNamePushButton->setFont(font); m_ui.InstrumentStatusTextLabel->setFont(font); } // Channel display background effect. void ChannelStrip::setDisplayEffect ( bool bDisplayEffect ) { QPalette pal; pal.setColor(QPalette::WindowText, Qt::yellow); pal.setColor(QPalette::ButtonText, Qt::yellow); m_ui.EngineNameTextLabel->setPalette(pal); m_ui.MidiPortChannelTextLabel->setPalette(pal); pal.setColor(QPalette::WindowText, Qt::green); pal.setColor(QPalette::ButtonText, Qt::green); if (bDisplayEffect) { QPixmap pm(":/images/displaybg1.png"); pal.setBrush(QPalette::Window, QBrush(pm)); } else { pal.setColor(QPalette::Window, Qt::black); } m_ui.ChannelInfoFrame->setPalette(pal); m_ui.InstrumentNamePushButton->setPalette(pal); m_ui.StreamVoiceCountTextLabel->setPalette(pal); } // Maximum volume slider accessors. void ChannelStrip::setMaxVolume ( int iMaxVolume ) { m_iDirtyChange++; m_ui.ChannelVolumeSlider->setRange(0, iMaxVolume); m_ui.ChannelVolumeSpinBox->setRange(0, iMaxVolume); m_iDirtyChange--; } // Channel setup dialog slot. bool ChannelStrip::channelSetup (void) { if (m_pChannel == nullptr) return false; // Invoke the channel setup dialog. const bool bResult = m_pChannel->channelSetup(this); // Notify that this channel has changed. if (bResult) emit channelChanged(this); return bResult; } // Channel mute slot. bool ChannelStrip::channelMute ( bool bMute ) { if (m_pChannel == nullptr) return false; // Invoke the channel mute method. const bool bResult = m_pChannel->setChannelMute(bMute); // Notify that this channel has changed. if (bResult) emit channelChanged(this); return bResult; } // Channel solo slot. bool ChannelStrip::channelSolo ( bool bSolo ) { if (m_pChannel == nullptr) return false; // Invoke the channel solo method. const bool bResult = m_pChannel->setChannelSolo(bSolo); // Notify that this channel has changed. if (bResult) emit channelChanged(this); return bResult; } // Channel edit slot. void ChannelStrip::channelEdit (void) { if (m_pChannel == nullptr) return; m_pChannel->editChannel(); } bool ChannelStrip::channelFxEdit (void) { MainForm *pMainForm = MainForm::getInstance(); if (!pMainForm || !channel()) return false; pMainForm->appendMessages(QObject::tr("channel fx sends...")); bool bResult = false; #if CONFIG_FXSEND ChannelFxForm *pChannelFxForm = new ChannelFxForm(channel(), parentWidget()); if (pChannelFxForm) { //pChannelForm->setup(this); bResult = pChannelFxForm->exec(); delete pChannelFxForm; } #else // CONFIG_FXSEND QMessageBox::critical(this, tr("Unavailable"), tr("Sorry, QSampler was built without FX send support!\n\n" "(Make sure you have a recent liblscp when recompiling QSampler)")); #endif // CONFIG_FXSEND return bResult; } // Channel reset slot. bool ChannelStrip::channelReset (void) { if (m_pChannel == nullptr) return false; // Invoke the channel reset method. const bool bResult = m_pChannel->channelReset(); // Notify that this channel has changed. if (bResult) emit channelChanged(this); return bResult; } // Update the channel instrument name. bool ChannelStrip::updateInstrumentName ( bool bForce ) { if (m_pChannel == nullptr) return false; // Do we refresh the actual name? if (bForce) m_pChannel->updateInstrumentName(); // Instrument name... if (m_pChannel->instrumentName().isEmpty()) { if (m_pChannel->instrumentStatus() >= 0) { m_ui.InstrumentNamePushButton->setText( ' ' + Channel::loadingInstrument()); } else { m_ui.InstrumentNamePushButton->setText( ' ' + Channel::noInstrumentName()); } } else { m_ui.InstrumentNamePushButton->setText( ' ' + m_pChannel->instrumentName()); } bool bShowInstrumentPopup = false; // Instrument list popup (for fast switching among sounds of the same file) if (!m_pChannel->instrumentFile().isEmpty()) { const QStringList instruments = Channel::getInstrumentList(m_pChannel->instrumentFile(), true); if (!instruments.isEmpty()) { bShowInstrumentPopup = true; if (!m_instrumentListPopupMenu) { m_instrumentListPopupMenu = new QMenu(m_ui.InstrumentNamePushButton); m_instrumentListPopupMenu->setTitle(tr("Instruments")); // for cosmetical reasons, should have at least // the width of the instrument name label... m_instrumentListPopupMenu->setMinimumWidth(120); m_ui.InstrumentNamePushButton->setMenu(m_instrumentListPopupMenu); QObject::connect(m_instrumentListPopupMenu, SIGNAL(triggered(QAction*)), SLOT(instrumentListPopupItemClicked(QAction *))); } else { m_instrumentListPopupMenu->clear(); } QAction *action; for (int i = 0; i < instruments.size(); ++i) { action = m_instrumentListPopupMenu->addAction(instruments.at(i)); action->setData(i); action->setCheckable(true); action->setChecked(i == m_pChannel->instrumentNr()); } } } if (!bShowInstrumentPopup && m_instrumentListPopupMenu) { delete m_instrumentListPopupMenu; m_instrumentListPopupMenu = nullptr; } return true; } void ChannelStrip::instrumentListPopupItemClicked ( QAction *action ) { if (!action) return; QVariant data = action->data(); if (data.isValid() && !m_pChannel->instrumentFile().isEmpty()) { m_pChannel->loadInstrument(m_pChannel->instrumentFile(), data.toInt()); emit channelChanged(this); } } // Do the dirty volume change. bool ChannelStrip::updateChannelVolume (void) { if (m_pChannel == nullptr) return false; // Convert... int iVolume = ::lroundf(100.0f * m_pChannel->volume()); // And clip... if (iVolume < 0) iVolume = 0; // Flag it here, to avoid infinite recursion. m_iDirtyChange++; m_ui.ChannelVolumeSlider->setValue(iVolume); m_ui.ChannelVolumeSpinBox->setValue(iVolume); m_iDirtyChange--; return true; } // Update whole channel info state. bool ChannelStrip::updateChannelInfo (void) { if (m_pChannel == nullptr) return false; // Check for error limit/recycle... if (m_iErrorCount > QSAMPLER_ERROR_LIMIT) return true; // Update strip caption. const QString& sText = m_pChannel->channelName(); setWindowTitle(sText); m_ui.ChannelSetupPushButton->setText('&' + sText); // Check if we're up and connected. MainForm *pMainForm = MainForm::getInstance(); if (pMainForm->client() == nullptr) return false; // Read actual channel information. m_pChannel->updateChannelInfo(); // Engine name... if (m_pChannel->engineName().isEmpty()) { m_ui.EngineNameTextLabel->setText( ' ' + Channel::noEngineName()); } else { m_ui.EngineNameTextLabel->setText( ' ' + m_pChannel->engineName()); } // Instrument name... updateInstrumentName(false); // MIDI Port/Channel... QString sMidiPortChannel = QString::number(m_pChannel->midiPort()) + " / "; if (m_pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL) sMidiPortChannel += tr("All"); else sMidiPortChannel += QString::number(m_pChannel->midiChannel() + 1); m_ui.MidiPortChannelTextLabel->setText(sMidiPortChannel); // Common palette... QPalette pal; const QColor& rgbFore = pal.color(QPalette::WindowText); // Instrument status... const int iInstrumentStatus = m_pChannel->instrumentStatus(); if (iInstrumentStatus < 0) { pal.setColor(QPalette::WindowText, Qt::red); m_ui.InstrumentStatusTextLabel->setPalette(pal); m_ui.InstrumentStatusTextLabel->setText( tr("ERR%1").arg(iInstrumentStatus)); m_iErrorCount++; return false; } // All seems normal... pal.setColor(QPalette::WindowText, iInstrumentStatus < 100 ? Qt::yellow : Qt::green); m_ui.InstrumentStatusTextLabel->setPalette(pal); m_ui.InstrumentStatusTextLabel->setText( QString::number(iInstrumentStatus) + '%'); m_iErrorCount = 0; #ifdef CONFIG_MUTE_SOLO // Mute/Solo button state coloring... const bool bMute = m_pChannel->channelMute(); const QColor& rgbButton = pal.color(QPalette::Button); const QColor& rgbButtonText = pal.color(QPalette::ButtonText); pal.setColor(QPalette::WindowText, rgbFore); pal.setColor(QPalette::Button, bMute ? Qt::yellow : rgbButton); pal.setColor(QPalette::ButtonText, bMute ? Qt::darkYellow : rgbButtonText); m_ui.ChannelMutePushButton->setPalette(pal); m_ui.ChannelMutePushButton->setDown(bMute); const bool bSolo = m_pChannel->channelSolo(); pal.setColor(QPalette::Button, bSolo ? Qt::cyan : rgbButton); pal.setColor(QPalette::ButtonText, bSolo ? Qt::darkCyan : rgbButtonText); m_ui.ChannelSoloPushButton->setPalette(pal); m_ui.ChannelSoloPushButton->setDown(bSolo); #else m_ui.ChannelMutePushButton->setEnabled(false); m_ui.ChannelSoloPushButton->setEnabled(false); #endif // And update the both GUI volume elements; // return success if, and only if, intrument is fully loaded... return updateChannelVolume() && (iInstrumentStatus == 100); } // Update whole channel usage state. bool ChannelStrip::updateChannelUsage (void) { if (m_pChannel == nullptr) return false; MainForm *pMainForm = MainForm::getInstance(); if (pMainForm->client() == nullptr) return false; // This only makes sense on fully loaded channels... if (m_pChannel->instrumentStatus() < 100) return false; // Get current channel voice count. const int iVoiceCount = ::lscp_get_channel_voice_count( pMainForm->client(), m_pChannel->channelID()); // Get current stream count. const int iStreamCount = ::lscp_get_channel_stream_count( pMainForm->client(), m_pChannel->channelID()); // Get current channel buffer fill usage. // As benno has suggested this is the percentage usage // of the least filled buffer stream... const int iStreamUsage = ::lscp_get_channel_stream_usage( pMainForm->client(), m_pChannel->channelID()); // Update the GUI elements... m_ui.StreamUsageProgressBar->setValue(iStreamUsage); m_ui.StreamVoiceCountTextLabel->setText( QString("%1 / %2").arg(iStreamCount).arg(iVoiceCount)); // We're clean. return true; } // Volume change slot. void ChannelStrip::volumeChanged ( int iVolume ) { if (m_pChannel == nullptr) return; // Avoid recursion. if (m_iDirtyChange > 0) return; // Convert and clip. float fVolume = (float) iVolume / 100.0f; if (fVolume < 0.001f) fVolume = 0.0f; // Update the GUI elements. if (m_pChannel->setVolume(fVolume)) { updateChannelVolume(); emit channelChanged(this); } } // Context menu event handler. void ChannelStrip::contextMenuEvent( QContextMenuEvent *pEvent ) { if (m_pChannel == nullptr) return; // We'll just show up the main form's edit menu (thru qsamplerChannel). m_pChannel->contextMenuEvent(pEvent); } void ChannelStrip::midiActivityLedOn (void) { m_ui.MidiActivityLabel->setPixmap(*g_pMidiActivityLedOn); m_pMidiActivityTimer->start(100); } void ChannelStrip::midiActivityLedOff (void) { m_ui.MidiActivityLabel->setPixmap(*g_pMidiActivityLedOff); } // Error count hackish accessors. void ChannelStrip::resetErrorCount (void) { m_iErrorCount = 0; } // Channel strip activation/selection. void ChannelStrip::setSelected ( bool bSelected ) { if (bSelected) { if (g_pSelectedStrip == this) return; if (g_pSelectedStrip) g_pSelectedStrip->setSelected(false); g_pSelectedStrip = this; } else { if (g_pSelectedStrip == this) g_pSelectedStrip = nullptr; } QPalette pal; if (bSelected) { const QColor& color = pal.midlight().color(); pal.setColor(QPalette::Window, color.darker(150)); pal.setColor(QPalette::WindowText, color.lighter(150)); } QWidget *pParentWidget = QWidget::parentWidget(); if (pParentWidget) pParentWidget->setPalette(pal); } bool ChannelStrip::isSelected (void) const { return (this == g_pSelectedStrip); } } // namespace QSampler // end of qsamplerChannelStrip.cpp qsampler-1.0.0/src/PaxHeaders/qsamplerInstrumentForm.h0000644000000000000000000000013214634065603020122 xustar0030 mtime=1718643587.393448566 30 atime=1718643587.393448566 30 ctime=1718643587.393448566 qsampler-1.0.0/src/qsamplerInstrumentForm.h0000644000175000001440000000364114634065603020116 0ustar00rncbcusers// qsamplerInstrumentForm.h // /**************************************************************************** Copyright (C) 2003-2021, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *****************************************************************************/ #ifndef __qsamplerInstrumentForm_h #define __qsamplerInstrumentForm_h #include "ui_qsamplerInstrumentForm.h" #include "qsamplerInstrument.h" namespace QSampler { //------------------------------------------------------------------------- // QSampler::InstrumentForm -- Instrument map item form interface. // class InstrumentForm : public QDialog { Q_OBJECT public: InstrumentForm(QWidget *pParent = nullptr); ~InstrumentForm(); void setup(Instrument* pInstrument); public slots: void nameChanged(const QString& sName); void openInstrumentFile(); void updateInstrumentName(); void instrumentNrChanged(); void accept(); void reject(); void changed(); void stabilizeForm(); private: Ui::qsamplerInstrumentForm m_ui; Instrument *m_pInstrument; int m_iDirtySetup; int m_iDirtyCount; int m_iDirtyName; }; } // namespace QSampler #endif // __qsamplerInstrumentForm_h // end of qsamplerInstrumentForm.h qsampler-1.0.0/src/PaxHeaders/qsampler.h0000644000000000000000000000013214634065603015205 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/qsampler.h0000644000175000001440000000575314634065603015207 0ustar00rncbcusers// qsampler.h // /**************************************************************************** Copyright (C) 2003-2024, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007,2008,2015,2019 Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #ifndef __qsampler_h #define __qsampler_h #include "qsamplerAbout.h" #include #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #if defined(Q_WS_X11) #define CONFIG_X11 #endif #endif // Forward decls. class QWidget; class QTranslator; #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #ifdef CONFIG_XUNIQUE #ifdef CONFIG_X11 #include typedef unsigned long Window; typedef unsigned long Atom; #endif // CONFIG_X11 #endif // CONFIG_XUNIQUE #else #ifdef CONFIG_XUNIQUE class QSharedMemory; class QLocalServer; #endif // CONFIG_XUNIQUE #endif //------------------------------------------------------------------------- // Singleton application instance stuff (Qt/X11 only atm.) // class qsamplerApplication : public QApplication { Q_OBJECT public: // Constructor. qsamplerApplication(int& argc, char **argv); // Destructor. ~qsamplerApplication(); // Main application widget accessors. void setMainWidget(QWidget *pWidget); QWidget *mainWidget() const { return m_pWidget; } // Check if another instance is running, // and raise its proper main widget... bool setup(); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #ifdef CONFIG_XUNIQUE #ifdef CONFIG_X11 void x11PropertyNotify(Window w); bool x11EventFilter(XEvent *pEv) #endif // CONFIG_X11 #endif // CONFIG_XUNIQUE #else #ifdef CONFIG_XUNIQUE protected slots: // Local server slots. void newConnectionSlot(); void readyReadSlot(); protected: // Local server/shmem setup/cleanup. bool setupServer(); void clearServer(); #endif // CONFIG_XUNIQUE #endif private: // Translation support. QTranslator *m_pQtTranslator; QTranslator *m_pMyTranslator; // Instance variables. QWidget *m_pWidget; #ifdef CONFIG_XUNIQUE #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #ifdef CONFIG_X11 Display *m_pDisplay; Atom m_aUnique; Window m_wOwner; #endif // CONFIG_X11 #else QString m_sUnique; QSharedMemory *m_pMemory; QLocalServer *m_pServer; #endif #endif // CONFIG_XUNIQUE }; #endif // __qsampler_h // end of qsampler.h qsampler-1.0.0/src/PaxHeaders/qsamplerMainForm.cpp0000644000000000000000000000013214634065603017171 xustar0030 mtime=1718643587.394448566 30 atime=1718643587.394448566 30 ctime=1718643587.394448566 qsampler-1.0.0/src/qsamplerMainForm.cpp0000644000175000001440000026337314634065603017177 0ustar00rncbcusers// qsamplerMainForm.cpp // /**************************************************************************** Copyright (C) 2004-2024, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007-2019 Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #include "qsamplerAbout.h" #include "qsamplerMainForm.h" #include "qsamplerOptions.h" #include "qsamplerChannel.h" #include "qsamplerMessages.h" #include "qsamplerChannelStrip.h" #include "qsamplerInstrumentList.h" #include "qsamplerInstrumentListForm.h" #include "qsamplerDeviceForm.h" #include "qsamplerOptionsForm.h" #include "qsamplerDeviceStatusForm.h" #include "qsamplerPaletteForm.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) #include #endif #if QT_VERSION < QT_VERSION_CHECK(4, 5, 0) namespace Qt { const WindowFlags WindowCloseButtonHint = WindowFlags(0x08000000); } #endif #ifdef CONFIG_LIBGIG #if defined(Q_CC_GNU) || defined(Q_CC_MINGW) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif #include #if defined(Q_CC_GNU) || defined(Q_CC_MINGW) #pragma GCC diagnostic pop #endif #endif // Deprecated QTextStreamFunctions/Qt namespaces workaround. #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) #define endl Qt::endl #endif // Needed for lroundf() #ifdef CONFIG_ROUND #include #else static inline long lroundf ( float x ) { if (x >= 0.0f) return long(x + 0.5f); else return long(x - 0.5f); } #endif // All winsock apps needs this. #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) static WSADATA _wsaData; #undef HAVE_SIGNAL_H #endif //------------------------------------------------------------------------- // LADISH Level 1 support stuff. #if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H) #include #include #include #include #include // File descriptor for SIGUSR1 notifier. static int g_fdSigusr1[2] = { -1, -1 }; // Unix SIGUSR1 signal handler. static void qsampler_sigusr1_handler ( int /* signo */ ) { char c = 1; (void) (::write(g_fdSigusr1[0], &c, sizeof(c)) > 0); } // File descriptor for SIGTERM notifier. static int g_fdSigterm[2] = { -1, -1 }; // Unix SIGTERM signal handler. static void qsampler_sigterm_handler ( int /* signo */ ) { char c = 1; (void) (::write(g_fdSigterm[0], &c, sizeof(c)) > 0); } #endif // HAVE_SIGNAL_H //------------------------------------------------------------------------- // QSampler -- namespace namespace QSampler { // Timer constant stuff. #define QSAMPLER_TIMER_MSECS 200 // Status bar item indexes #define QSAMPLER_STATUS_CLIENT 0 // Client connection state. #define QSAMPLER_STATUS_SERVER 1 // Currenr server address (host:port) #define QSAMPLER_STATUS_CHANNEL 2 // Active channel caption. #define QSAMPLER_STATUS_SESSION 3 // Current session modification state. // Specialties for thread-callback comunication. #define QSAMPLER_LSCP_EVENT QEvent::Type(QEvent::User + 1) //------------------------------------------------------------------------- // QSampler::LscpEvent -- specialty for LSCP callback comunication. class LscpEvent : public QEvent { public: // Constructor. LscpEvent(lscp_event_t event, const char *pchData, int cchData) : QEvent(QSAMPLER_LSCP_EVENT) { m_event = event; m_data = QString::fromUtf8(pchData, cchData); } // Accessors. lscp_event_t event() { return m_event; } const QString& data() { return m_data; } private: // The proper event type. lscp_event_t m_event; // The event data as a string. QString m_data; }; //------------------------------------------------------------------------- // QSampler::Workspace -- Main window workspace (MDI Area) decl. class Workspace : public QMdiArea { public: Workspace(MainForm *pMainForm) : QMdiArea(pMainForm) {} protected: void resizeEvent(QResizeEvent *) { MainForm *pMainForm = static_cast (parentWidget()); if (pMainForm) pMainForm->channelsArrangeAuto(); } }; //------------------------------------------------------------------------- // QSampler::MainForm -- Main window form implementation. // Kind of singleton reference. MainForm *MainForm::g_pMainForm = nullptr; MainForm::MainForm ( QWidget *pParent ) : QMainWindow(pParent) { m_ui.setupUi(this); #if QT_VERSION < QT_VERSION_CHECK(6, 1, 0) QMainWindow::setWindowIcon(QIcon(":/images/qsampler.png")); #endif // Pseudo-singleton reference setup. g_pMainForm = this; // Initialize some pointer references. m_pOptions = nullptr; // All child forms are to be created later, not earlier than setup. m_pMessages = nullptr; m_pInstrumentListForm = nullptr; m_pDeviceForm = nullptr; // We'll start clean. m_iUntitled = 0; m_iDirtySetup = 0; m_iDirtyCount = 0; m_pServer = nullptr; m_pClient = nullptr; m_iStartDelay = 0; m_iTimerDelay = 0; m_iTimerSlot = 0; #if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H) // Set to ignore any fatal "Broken pipe" signals. ::signal(SIGPIPE, SIG_IGN); // LADISH Level 1 suport. // Initialize file descriptors for SIGUSR1 socket notifier. ::socketpair(AF_UNIX, SOCK_STREAM, 0, g_fdSigusr1); m_pSigusr1Notifier = new QSocketNotifier(g_fdSigusr1[1], QSocketNotifier::Read, this); QObject::connect(m_pSigusr1Notifier, SIGNAL(activated(int)), SLOT(handle_sigusr1())); // Install SIGUSR1 signal handler. struct sigaction sigusr1; sigusr1.sa_handler = qsampler_sigusr1_handler; sigemptyset(&sigusr1.sa_mask); sigusr1.sa_flags = 0; sigusr1.sa_flags |= SA_RESTART; ::sigaction(SIGUSR1, &sigusr1, nullptr); // Initialize file descriptors for SIGTERM socket notifier. ::socketpair(AF_UNIX, SOCK_STREAM, 0, g_fdSigterm); m_pSigtermNotifier = new QSocketNotifier(g_fdSigterm[1], QSocketNotifier::Read, this); QObject::connect(m_pSigtermNotifier, SIGNAL(activated(int)), SLOT(handle_sigterm())); // Install SIGTERM signal handler. struct sigaction sigterm; sigterm.sa_handler = qsampler_sigterm_handler; sigemptyset(&sigterm.sa_mask); sigterm.sa_flags = 0; sigterm.sa_flags |= SA_RESTART; ::sigaction(SIGTERM, &sigterm, nullptr); ::sigaction(SIGQUIT, &sigterm, nullptr); // Ignore SIGHUP/SIGINT signals. ::signal(SIGHUP, SIG_IGN); ::signal(SIGINT, SIG_IGN); #else // HAVE_SIGNAL_H m_pSigusr1Notifier = nullptr; m_pSigtermNotifier = nullptr; #endif // !HAVE_SIGNAL_H #ifdef CONFIG_VOLUME // Make some extras into the toolbar... const QString& sVolumeText = tr("Master volume"); m_iVolumeChanging = 0; // Volume slider... m_ui.channelsToolbar->addSeparator(); m_pVolumeSlider = new QSlider(Qt::Horizontal, m_ui.channelsToolbar); m_pVolumeSlider->setTickPosition(QSlider::TicksBothSides); m_pVolumeSlider->setTickInterval(10); m_pVolumeSlider->setPageStep(10); m_pVolumeSlider->setSingleStep(10); m_pVolumeSlider->setMinimum(0); m_pVolumeSlider->setMaximum(100); m_pVolumeSlider->setMaximumHeight(26); m_pVolumeSlider->setMinimumWidth(160); m_pVolumeSlider->setToolTip(sVolumeText); QObject::connect(m_pVolumeSlider, SIGNAL(valueChanged(int)), SLOT(volumeChanged(int))); m_ui.channelsToolbar->addWidget(m_pVolumeSlider); // Volume spin-box m_ui.channelsToolbar->addSeparator(); m_pVolumeSpinBox = new QSpinBox(m_ui.channelsToolbar); m_pVolumeSpinBox->setSuffix(" %"); m_pVolumeSpinBox->setMinimum(0); m_pVolumeSpinBox->setMaximum(100); m_pVolumeSpinBox->setToolTip(sVolumeText); QObject::connect(m_pVolumeSpinBox, SIGNAL(valueChanged(int)), SLOT(volumeChanged(int))); m_ui.channelsToolbar->addWidget(m_pVolumeSpinBox); #endif // Make it an MDI workspace. m_pWorkspace = new Workspace(this); m_pWorkspace->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); m_pWorkspace->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); // Set the activation connection. QObject::connect(m_pWorkspace, SIGNAL(subWindowActivated(QMdiSubWindow *)), SLOT(activateStrip(QMdiSubWindow *))); // Make it shine :-) setCentralWidget(m_pWorkspace); // Create some statusbar labels... QLabel *pLabel; // Client status. pLabel = new QLabel(tr("Connected"), this); pLabel->setAlignment(Qt::AlignLeft); pLabel->setMinimumSize(pLabel->sizeHint()); m_statusItem[QSAMPLER_STATUS_CLIENT] = pLabel; statusBar()->addWidget(pLabel); // Server address. pLabel = new QLabel(this); pLabel->setAlignment(Qt::AlignLeft); m_statusItem[QSAMPLER_STATUS_SERVER] = pLabel; statusBar()->addWidget(pLabel, 1); // Channel title. pLabel = new QLabel(this); pLabel->setAlignment(Qt::AlignLeft); m_statusItem[QSAMPLER_STATUS_CHANNEL] = pLabel; statusBar()->addWidget(pLabel, 2); // Session modification status. pLabel = new QLabel(tr("MOD"), this); pLabel->setAlignment(Qt::AlignHCenter); pLabel->setMinimumSize(pLabel->sizeHint()); m_statusItem[QSAMPLER_STATUS_SESSION] = pLabel; statusBar()->addWidget(pLabel); #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) WSAStartup(MAKEWORD(1, 1), &_wsaData); #endif // Some actions surely need those // shortcuts firmly attached... addAction(m_ui.viewMenubarAction); addAction(m_ui.viewToolbarAction); QObject::connect(m_ui.fileNewAction, SIGNAL(triggered()), SLOT(fileNew())); QObject::connect(m_ui.fileOpenAction, SIGNAL(triggered()), SLOT(fileOpen())); QObject::connect(m_ui.fileSaveAction, SIGNAL(triggered()), SLOT(fileSave())); QObject::connect(m_ui.fileSaveAsAction, SIGNAL(triggered()), SLOT(fileSaveAs())); QObject::connect(m_ui.fileResetAction, SIGNAL(triggered()), SLOT(fileReset())); QObject::connect(m_ui.fileRestartAction, SIGNAL(triggered()), SLOT(fileRestart())); QObject::connect(m_ui.fileExitAction, SIGNAL(triggered()), SLOT(fileExit())); QObject::connect(m_ui.editAddChannelAction, SIGNAL(triggered()), SLOT(editAddChannel())); QObject::connect(m_ui.editRemoveChannelAction, SIGNAL(triggered()), SLOT(editRemoveChannel())); QObject::connect(m_ui.editSetupChannelAction, SIGNAL(triggered()), SLOT(editSetupChannel())); QObject::connect(m_ui.editEditChannelAction, SIGNAL(triggered()), SLOT(editEditChannel())); QObject::connect(m_ui.editResetChannelAction, SIGNAL(triggered()), SLOT(editResetChannel())); QObject::connect(m_ui.editResetAllChannelsAction, SIGNAL(triggered()), SLOT(editResetAllChannels())); QObject::connect(m_ui.viewMenubarAction, SIGNAL(toggled(bool)), SLOT(viewMenubar(bool))); QObject::connect(m_ui.viewToolbarAction, SIGNAL(toggled(bool)), SLOT(viewToolbar(bool))); QObject::connect(m_ui.viewStatusbarAction, SIGNAL(toggled(bool)), SLOT(viewStatusbar(bool))); QObject::connect(m_ui.viewMessagesAction, SIGNAL(toggled(bool)), SLOT(viewMessages(bool))); QObject::connect(m_ui.viewInstrumentsAction, SIGNAL(triggered()), SLOT(viewInstruments())); QObject::connect(m_ui.viewDevicesAction, SIGNAL(triggered()), SLOT(viewDevices())); QObject::connect(m_ui.viewOptionsAction, SIGNAL(triggered()), SLOT(viewOptions())); QObject::connect(m_ui.channelsArrangeAction, SIGNAL(triggered()), SLOT(channelsArrange())); QObject::connect(m_ui.channelsAutoArrangeAction, SIGNAL(toggled(bool)), SLOT(channelsAutoArrange(bool))); QObject::connect(m_ui.helpAboutAction, SIGNAL(triggered()), SLOT(helpAbout())); QObject::connect(m_ui.helpAboutQtAction, SIGNAL(triggered()), SLOT(helpAboutQt())); QObject::connect(m_ui.fileMenu, SIGNAL(aboutToShow()), SLOT(updateRecentFilesMenu())); QObject::connect(m_ui.channelsMenu, SIGNAL(aboutToShow()), SLOT(channelsMenuAboutToShow())); #ifdef CONFIG_VOLUME QObject::connect(m_ui.channelsToolbar, SIGNAL(orientationChanged(Qt::Orientation)), SLOT(channelsToolbarOrientation(Qt::Orientation))); #endif } // Destructor. MainForm::~MainForm() { // Do final processing anyway. processServerExit(); #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) WSACleanup(); #endif #if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H) if (m_pSigusr1Notifier) delete m_pSigusr1Notifier; if (m_pSigtermNotifier) delete m_pSigtermNotifier; #endif // Finally drop any widgets around... if (m_pDeviceForm) delete m_pDeviceForm; if (m_pInstrumentListForm) delete m_pInstrumentListForm; if (m_pMessages) delete m_pMessages; if (m_pWorkspace) delete m_pWorkspace; // Delete status item labels one by one. if (m_statusItem[QSAMPLER_STATUS_CLIENT]) delete m_statusItem[QSAMPLER_STATUS_CLIENT]; if (m_statusItem[QSAMPLER_STATUS_SERVER]) delete m_statusItem[QSAMPLER_STATUS_SERVER]; if (m_statusItem[QSAMPLER_STATUS_CHANNEL]) delete m_statusItem[QSAMPLER_STATUS_CHANNEL]; if (m_statusItem[QSAMPLER_STATUS_SESSION]) delete m_statusItem[QSAMPLER_STATUS_SESSION]; #ifdef CONFIG_VOLUME delete m_pVolumeSpinBox; delete m_pVolumeSlider; #endif // Pseudo-singleton reference shut-down. g_pMainForm = nullptr; } // Make and set a proper setup options step. void MainForm::setup ( Options *pOptions ) { // We got options? m_pOptions = pOptions; // What style do we create these forms? Qt::WindowFlags wflags = Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint; if (m_pOptions->bKeepOnTop) wflags |= Qt::Tool; // Some child forms are to be created right now. m_pMessages = new Messages(this); m_pDeviceForm = new DeviceForm(this, wflags); #ifdef CONFIG_MIDI_INSTRUMENT m_pInstrumentListForm = new InstrumentListForm(this, wflags); #else m_ui.viewInstrumentsAction->setEnabled(false); #endif // Setup messages logging appropriately... m_pMessages->setLogging( m_pOptions->bMessagesLog, m_pOptions->sMessagesLogPath); // Set message defaults... updateMessagesFont(); updateMessagesLimit(); updateMessagesCapture(); // Set the visibility signal. QObject::connect(m_pMessages, SIGNAL(visibilityChanged(bool)), SLOT(stabilizeForm())); // Initial decorations toggle state. m_ui.viewMenubarAction->setChecked(m_pOptions->bMenubar); m_ui.viewToolbarAction->setChecked(m_pOptions->bToolbar); m_ui.viewStatusbarAction->setChecked(m_pOptions->bStatusbar); m_ui.channelsAutoArrangeAction->setChecked(m_pOptions->bAutoArrange); // Initial decorations visibility state. viewMenubar(m_pOptions->bMenubar); viewToolbar(m_pOptions->bToolbar); viewStatusbar(m_pOptions->bStatusbar); addDockWidget(Qt::BottomDockWidgetArea, m_pMessages); // Restore whole dock windows state. QByteArray aDockables = m_pOptions->settings().value( "/Layout/DockWindows").toByteArray(); if (!aDockables.isEmpty()) { restoreState(aDockables); } // Try to restore old window positioning and initial visibility. m_pOptions->loadWidgetGeometry(this, true); m_pOptions->loadWidgetGeometry(m_pInstrumentListForm); m_pOptions->loadWidgetGeometry(m_pDeviceForm); // Final startup stabilization... updateMaxVolume(); updateRecentFilesMenu(); stabilizeForm(); // Make it ready :-) statusBar()->showMessage(tr("Ready"), 3000); // We'll try to start immediately... startSchedule(0); // Register the first timer slot. QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot())); } // Window close event handlers. bool MainForm::queryClose (void) { bool bQueryClose = closeSession(false); // Try to save current general state... if (m_pOptions) { // Some windows default fonts is here on demand too. if (bQueryClose && m_pMessages) m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString(); // Try to save current positioning. if (bQueryClose) { // Save decorations state. m_pOptions->bMenubar = m_ui.MenuBar->isVisible(); m_pOptions->bToolbar = (m_ui.fileToolbar->isVisible() || m_ui.editToolbar->isVisible() || m_ui.channelsToolbar->isVisible()); m_pOptions->bStatusbar = statusBar()->isVisible(); // Save the dock windows state. m_pOptions->settings().setValue("/Layout/DockWindows", saveState()); // And the children, and the main windows state,. m_pOptions->saveWidgetGeometry(m_pDeviceForm); m_pOptions->saveWidgetGeometry(m_pInstrumentListForm); m_pOptions->saveWidgetGeometry(this, true); // Close popup widgets. if (m_pInstrumentListForm) m_pInstrumentListForm->close(); if (m_pDeviceForm) m_pDeviceForm->close(); // Stop client and/or server, gracefully. stopServer(true /*interactive*/); } } return bQueryClose; } void MainForm::closeEvent ( QCloseEvent *pCloseEvent ) { if (queryClose()) { DeviceStatusForm::deleteAllInstances(); pCloseEvent->accept(); } else pCloseEvent->ignore(); } // Window drag-n-drop event handlers. void MainForm::dragEnterEvent ( QDragEnterEvent* pDragEnterEvent ) { // Accept external drags only... if (pDragEnterEvent->source() == nullptr && pDragEnterEvent->mimeData()->hasUrls()) { pDragEnterEvent->accept(); } else { pDragEnterEvent->ignore(); } } void MainForm::dropEvent ( QDropEvent *pDropEvent ) { // Accept externally originated drops only... if (pDropEvent->source()) return; const QMimeData *pMimeData = pDropEvent->mimeData(); if (pMimeData->hasUrls()) { QListIterator iter(pMimeData->urls()); while (iter.hasNext()) { const QString& sPath = iter.next().toLocalFile(); // if (Channel::isDlsInstrumentFile(sPath)) { if (QFileInfo(sPath).exists()) { // Try to create a new channel from instrument file... Channel *pChannel = new Channel(); if (pChannel == nullptr) return; // Start setting the instrument filename... pChannel->setInstrument(sPath, 0); // Before we show it up, may be we'll // better ask for some initial values? if (!pChannel->channelSetup(this)) { delete pChannel; return; } // Finally, give it to a new channel strip... if (!createChannelStrip(pChannel)) { delete pChannel; return; } // Make that an overall update. m_iDirtyCount++; stabilizeForm(); } // Otherwise, load an usual session file (LSCP script)... else if (closeSession(true)) { loadSessionFile(sPath); break; } } // Make it look responsive...:) QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } } // Custome event handler. void MainForm::customEvent ( QEvent* pEvent ) { // For the time being, just pump it to messages. if (pEvent->type() == QSAMPLER_LSCP_EVENT) { LscpEvent *pLscpEvent = static_cast (pEvent); switch (pLscpEvent->event()) { case LSCP_EVENT_CHANNEL_COUNT: updateAllChannelStrips(true); break; case LSCP_EVENT_CHANNEL_INFO: { const int iChannelID = pLscpEvent->data().toInt(); ChannelStrip *pChannelStrip = channelStrip(iChannelID); if (pChannelStrip) channelStripChanged(pChannelStrip); break; } case LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT: if (m_pDeviceForm) m_pDeviceForm->refreshDevices(); DeviceStatusForm::onDevicesChanged(); updateViewMidiDeviceStatusMenu(); break; case LSCP_EVENT_MIDI_INPUT_DEVICE_INFO: { if (m_pDeviceForm) m_pDeviceForm->refreshDevices(); const int iDeviceID = pLscpEvent->data().section(' ', 0, 0).toInt(); DeviceStatusForm::onDeviceChanged(iDeviceID); break; } case LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT: if (m_pDeviceForm) m_pDeviceForm->refreshDevices(); break; case LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO: if (m_pDeviceForm) m_pDeviceForm->refreshDevices(); break; #if CONFIG_EVENT_CHANNEL_MIDI case LSCP_EVENT_CHANNEL_MIDI: { const int iChannelID = pLscpEvent->data().section(' ', 0, 0).toInt(); ChannelStrip *pChannelStrip = channelStrip(iChannelID); if (pChannelStrip) pChannelStrip->midiActivityLedOn(); break; } #endif #if CONFIG_EVENT_DEVICE_MIDI case LSCP_EVENT_DEVICE_MIDI: { const int iDeviceID = pLscpEvent->data().section(' ', 0, 0).toInt(); const int iPortID = pLscpEvent->data().section(' ', 1, 1).toInt(); DeviceStatusForm *pDeviceStatusForm = DeviceStatusForm::getInstance(iDeviceID); if (pDeviceStatusForm) pDeviceStatusForm->midiArrived(iPortID); break; } #endif default: appendMessagesColor(tr("LSCP Event: %1 data: %2") .arg(::lscp_event_to_text(pLscpEvent->event())) .arg(pLscpEvent->data()), "#996699"); } } } // LADISH Level 1 -- SIGUSR1 signal handler. void MainForm::handle_sigusr1 (void) { #if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H) char c; if (::read(g_fdSigusr1[1], &c, sizeof(c)) > 0) saveSession(false); #endif } void MainForm::handle_sigterm (void) { #if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H) char c; if (::read(g_fdSigterm[1], &c, sizeof(c)) > 0) close(); #endif } void MainForm::updateViewMidiDeviceStatusMenu (void) { m_ui.viewMidiDeviceStatusMenu->clear(); const std::map statusForms = DeviceStatusForm::getInstances(); std::map::const_iterator iter = statusForms.begin(); for ( ; iter != statusForms.end(); ++iter) { DeviceStatusForm *pStatusForm = iter->second; m_ui.viewMidiDeviceStatusMenu->addAction( pStatusForm->visibleAction()); } } // Context menu event handler. void MainForm::contextMenuEvent( QContextMenuEvent *pEvent ) { stabilizeForm(); m_ui.editMenu->exec(pEvent->globalPos()); } //------------------------------------------------------------------------- // QSampler::MainForm -- Brainless public property accessors. // The global options settings property. Options *MainForm::options (void) const { return m_pOptions; } // The LSCP client descriptor property. lscp_client_t *MainForm::client (void) const { return m_pClient; } // The pseudo-singleton instance accessor. MainForm *MainForm::getInstance (void) { return g_pMainForm; } //------------------------------------------------------------------------- // QSampler::MainForm -- Session file stuff. // Format the displayable session filename. QString MainForm::sessionName ( const QString& sFilename ) { const bool bCompletePath = (m_pOptions && m_pOptions->bCompletePath); QString sSessionName = sFilename; if (sSessionName.isEmpty()) sSessionName = tr("Untitled") + QString::number(m_iUntitled); else if (!bCompletePath) sSessionName = QFileInfo(sSessionName).fileName(); return sSessionName; } // Create a new session file from scratch. bool MainForm::newSession (void) { // Check if we can do it. if (!closeSession(true)) return false; // Give us what the server has, right now... updateSession(); // Ok increment untitled count. m_iUntitled++; // Stabilize form. m_sFilename = QString(); m_iDirtyCount = 0; appendMessages(tr("New session: \"%1\".").arg(sessionName(m_sFilename))); stabilizeForm(); return true; } // Open an existing sampler session. bool MainForm::openSession (void) { if (m_pOptions == nullptr) return false; // Ask for the filename to open... QString sFilename = QFileDialog::getOpenFileName(this, tr("Open Session"), // Caption. m_pOptions->sSessionDir, // Start here. tr("LSCP Session files") + " (*.lscp)" // Filter (LSCP files) ); // Have we cancelled? if (sFilename.isEmpty()) return false; // Check if we're going to discard safely the current one... if (!closeSession(true)) return false; // Load it right away. return loadSessionFile(sFilename); } // Save current sampler session with another name. bool MainForm::saveSession ( bool bPrompt ) { if (m_pOptions == nullptr) return false; QString sFilename = m_sFilename; // Ask for the file to save, if there's none... if (bPrompt || sFilename.isEmpty()) { // If none is given, assume default directory. if (sFilename.isEmpty()) sFilename = m_pOptions->sSessionDir; // Prompt the guy... sFilename = QFileDialog::getSaveFileName(this, tr("Save Session"), // Caption. sFilename, // Start here. tr("LSCP Session files") + " (*.lscp)" // Filter (LSCP files) ); // Have we cancelled it? if (sFilename.isEmpty()) return false; // Enforce .lscp extension... if (QFileInfo(sFilename).suffix().isEmpty()) sFilename += ".lscp"; #if 0 // Check if already exists... if (sFilename != m_sFilename && QFileInfo(sFilename).exists()) { if (QMessageBox::warning(this, tr("Warning"), tr("The file already exists:\n\n" "\"%1\"\n\n" "Do you want to replace it?") .arg(sFilename), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) return false; } #endif } // Save it right away. return saveSessionFile(sFilename); } // Close current session. bool MainForm::closeSession ( bool bForce ) { bool bClose = true; // Are we dirty enough to prompt it? if (m_iDirtyCount > 0) { switch (QMessageBox::warning(this, tr("Warning"), tr("The current session has been changed:\n\n" "\"%1\"\n\n" "Do you want to save the changes?") .arg(sessionName(m_sFilename)), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel)) { case QMessageBox::Save: bClose = saveSession(false); // Fall thru.... case QMessageBox::Discard: break; default: // Cancel. bClose = false; break; } } // If we may close it, dot it. if (bClose) { // Remove all channel strips from sight... m_pWorkspace->setUpdatesEnabled(false); const QList& wlist = m_pWorkspace->subWindowList(); foreach (QMdiSubWindow *pMdiSubWindow, wlist) { ChannelStrip *pChannelStrip = static_cast (pMdiSubWindow->widget()); if (pChannelStrip) { Channel *pChannel = pChannelStrip->channel(); if (bForce && pChannel) pChannel->removeChannel(); delete pChannelStrip; } delete pMdiSubWindow; } m_pWorkspace->setUpdatesEnabled(true); // We're now clean, for sure. m_iDirtyCount = 0; } return bClose; } // Load a session from specific file path. bool MainForm::loadSessionFile ( const QString& sFilename ) { if (m_pClient == nullptr) return false; // Open and read from real file. QFile file(sFilename); if (!file.open(QIODevice::ReadOnly)) { appendMessagesError( tr("Could not open \"%1\" session file.\n\nSorry.") .arg(sFilename)); return false; } // Tell the world we'll take some time... QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // Read the file. int iLine = 0; int iErrors = 0; QTextStream ts(&file); while (!ts.atEnd()) { // Read the line. QString sCommand = ts.readLine().trimmed(); iLine++; // If not empty, nor a comment, call the server... if (!sCommand.isEmpty() && sCommand[0] != '#') { // Remember that, no matter what, // all LSCP commands are CR/LF terminated. sCommand += "\r\n"; if (::lscp_client_query(m_pClient, sCommand.toUtf8().constData()) != LSCP_OK) { appendMessagesColor(QString("%1(%2): %3") .arg(QFileInfo(sFilename).fileName()).arg(iLine) .arg(sCommand.simplified()), "#996633"); appendMessagesClient("lscp_client_query"); iErrors++; } } // Try to make it snappy :) QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } // Ok. we've read it. file.close(); // Now we'll try to create (update) the whole GUI session. updateSession(); // We're fornerly done. QApplication::restoreOverrideCursor(); // Have we any errors? if (iErrors > 0) { appendMessagesError( tr("Session loaded with errors\nfrom \"%1\".\n\nSorry.") .arg(sFilename)); } // Save as default session directory. if (m_pOptions) m_pOptions->sSessionDir = QFileInfo(sFilename).dir().absolutePath(); // We're not dirty anymore, if loaded without errors, m_iDirtyCount = iErrors; // Stabilize form... m_sFilename = sFilename; updateRecentFiles(sFilename); appendMessages(tr("Open session: \"%1\".").arg(sessionName(m_sFilename))); // Make that an overall update. stabilizeForm(); return true; } // Save current session to specific file path. bool MainForm::saveSessionFile ( const QString& sFilename ) { if (m_pClient == nullptr) return false; // Check whether server is apparently OK... if (::lscp_get_channels(m_pClient) < 0) { appendMessagesClient("lscp_get_channels"); return false; } // Open and write into real file. QFile file(sFilename); if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { appendMessagesError( tr("Could not open \"%1\" session file.\n\nSorry.") .arg(sFilename)); return false; } // Tell the world we'll take some time... QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // Write the file. int iErrors = 0; QTextStream ts(&file); ts << "# " << QSAMPLER_TITLE " - " << tr(QSAMPLER_SUBTITLE) << endl; ts << "# " << tr("Version") << ": " PROJECT_VERSION << endl; // ts << "# " << tr("Build") << ": " CONFIG_BUILD_DATE << endl; ts << "#" << endl; ts << "# " << tr("File") << ": " << QFileInfo(sFilename).fileName() << endl; ts << "# " << tr("Date") << ": " << QDate::currentDate().toString("MMM dd yyyy") << " " << QTime::currentTime().toString("hh:mm:ss") << endl; ts << "#" << endl; ts << endl; // It is assumed that this new kind of device+session file // will be loaded from a complete initialized server... int *piDeviceIDs; int i, iDevice; ts << "RESET" << endl; // Audio device mapping. QMap audioDeviceMap; iDevice = 0; piDeviceIDs = Device::getDevices(m_pClient, Device::Audio); for (i = 0; piDeviceIDs && piDeviceIDs[i] >= 0; ++i) { Device device(Device::Audio, piDeviceIDs[i]); // Avoid plug-in driver devices... if (device.driverName().toUpper() == "PLUGIN") continue; // Audio device specification... ts << endl; ts << "# " << device.deviceTypeName() << " " << device.driverName() << " " << tr("Device") << " " << iDevice << endl; ts << "CREATE AUDIO_OUTPUT_DEVICE " << device.driverName(); DeviceParamMap::ConstIterator deviceParam; for (deviceParam = device.params().begin(); deviceParam != device.params().end(); ++deviceParam) { const DeviceParam& param = deviceParam.value(); if (param.value.isEmpty()) ts << "# "; ts << " " << deviceParam.key() << "='" << param.value << "'"; } ts << endl; // Audio channel parameters... int iPort = 0; QListIterator iter(device.ports()); while (iter.hasNext()) { DevicePort *pPort = iter.next(); DeviceParamMap::ConstIterator portParam; for (portParam = pPort->params().begin(); portParam != pPort->params().end(); ++portParam) { const DeviceParam& param = portParam.value(); if (param.fix || param.value.isEmpty()) ts << "# "; ts << "SET AUDIO_OUTPUT_CHANNEL_PARAMETER " << iDevice << " " << iPort << " " << portParam.key() << "='" << param.value << "'" << endl; } iPort++; } // Audio device index/id mapping. audioDeviceMap.insert(device.deviceID(), iDevice++); // Try to keep it snappy :) QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } // MIDI device mapping. QMap midiDeviceMap; iDevice = 0; piDeviceIDs = Device::getDevices(m_pClient, Device::Midi); for (i = 0; piDeviceIDs && piDeviceIDs[i] >= 0; ++i) { Device device(Device::Midi, piDeviceIDs[i]); // Avoid plug-in driver devices... if (device.driverName().toUpper() == "PLUGIN") continue; // MIDI device specification... ts << endl; ts << "# " << device.deviceTypeName() << " " << device.driverName() << " " << tr("Device") << " " << iDevice << endl; ts << "CREATE MIDI_INPUT_DEVICE " << device.driverName(); DeviceParamMap::ConstIterator deviceParam; for (deviceParam = device.params().begin(); deviceParam != device.params().end(); ++deviceParam) { const DeviceParam& param = deviceParam.value(); if (param.value.isEmpty()) ts << "# "; ts << " " << deviceParam.key() << "='" << param.value << "'"; } ts << endl; // MIDI port parameters... int iPort = 0; QListIterator iter(device.ports()); while (iter.hasNext()) { DevicePort *pPort = iter.next(); DeviceParamMap::ConstIterator portParam; for (portParam = pPort->params().begin(); portParam != pPort->params().end(); ++portParam) { const DeviceParam& param = portParam.value(); if (param.fix || param.value.isEmpty()) ts << "# "; ts << "SET MIDI_INPUT_PORT_PARAMETER " << iDevice << " " << iPort << " " << portParam.key() << "='" << param.value << "'" << endl; } iPort++; } // MIDI device index/id mapping. midiDeviceMap.insert(device.deviceID(), iDevice++); // Try to keep it snappy :) QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } ts << endl; #ifdef CONFIG_MIDI_INSTRUMENT // MIDI instrument mapping... QMap midiInstrumentMap; int *piMaps = ::lscp_list_midi_instrument_maps(m_pClient); for (int iMap = 0; piMaps && piMaps[iMap] >= 0; iMap++) { const int iMidiMap = piMaps[iMap]; const char *pszMapName = ::lscp_get_midi_instrument_map_name(m_pClient, iMidiMap); ts << "# " << tr("MIDI instrument map") << " " << iMap; if (pszMapName) ts << " - " << pszMapName; ts << endl; ts << "ADD MIDI_INSTRUMENT_MAP"; if (pszMapName) ts << " '" << pszMapName << "'"; ts << endl; // MIDI instrument mapping... lscp_midi_instrument_t *pInstrs = ::lscp_list_midi_instruments(m_pClient, iMidiMap); for (int iInstr = 0; pInstrs && pInstrs[iInstr].map >= 0; iInstr++) { lscp_midi_instrument_info_t *pInstrInfo = ::lscp_get_midi_instrument_info(m_pClient, &pInstrs[iInstr]); if (pInstrInfo) { ts << "MAP MIDI_INSTRUMENT " << iMap << " " << pInstrs[iInstr].bank << " " << pInstrs[iInstr].prog << " " << pInstrInfo->engine_name << " '" << pInstrInfo->instrument_file << "' " << pInstrInfo->instrument_nr << " " << pInstrInfo->volume << " "; switch (pInstrInfo->load_mode) { case LSCP_LOAD_PERSISTENT: ts << "PERSISTENT"; break; case LSCP_LOAD_ON_DEMAND_HOLD: ts << "ON_DEMAND_HOLD"; break; case LSCP_LOAD_ON_DEMAND: case LSCP_LOAD_DEFAULT: default: ts << "ON_DEMAND"; break; } if (pInstrInfo->name) ts << " '" << pInstrInfo->name << "'"; ts << endl; } // Check for errors... else if (::lscp_client_get_errno(m_pClient)) { appendMessagesClient("lscp_get_midi_instrument_info"); iErrors++; } // Try to keep it snappy :) QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } ts << endl; // Check for errors... if (pInstrs == nullptr && ::lscp_client_get_errno(m_pClient)) { appendMessagesClient("lscp_list_midi_instruments"); iErrors++; } // MIDI strument index/id mapping. midiInstrumentMap.insert(iMidiMap, iMap); } // Check for errors... if (piMaps == nullptr && ::lscp_client_get_errno(m_pClient)) { appendMessagesClient("lscp_list_midi_instrument_maps"); iErrors++; } #endif // CONFIG_MIDI_INSTRUMENT // Sampler channel mapping... int iChannelID = 0; const QList& wlist = m_pWorkspace->subWindowList(); foreach (QMdiSubWindow *pMdiSubWindow, wlist) { ChannelStrip *pChannelStrip = static_cast (pMdiSubWindow->widget()); if (pChannelStrip) { Channel *pChannel = pChannelStrip->channel(); if (pChannel) { // Avoid "artifial" plug-in devices... const int iAudioDevice = pChannel->audioDevice(); if (!audioDeviceMap.contains(iAudioDevice)) continue; const int iMidiDevice = pChannel->midiDevice(); if (!midiDeviceMap.contains(iMidiDevice)) continue; // Go for regular, canonical devices... ts << "# " << tr("Channel") << " " << iChannelID << endl; ts << "ADD CHANNEL" << endl; if (audioDeviceMap.isEmpty()) { ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannelID << " " << pChannel->audioDriver() << endl; } else { ts << "SET CHANNEL AUDIO_OUTPUT_DEVICE " << iChannelID << " " << audioDeviceMap.value(iAudioDevice) << endl; } if (midiDeviceMap.isEmpty()) { ts << "SET CHANNEL MIDI_INPUT_TYPE " << iChannelID << " " << pChannel->midiDriver() << endl; } else { ts << "SET CHANNEL MIDI_INPUT_DEVICE " << iChannelID << " " << midiDeviceMap.value(iMidiDevice) << endl; } ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannelID << " " << pChannel->midiPort() << endl; ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannelID << " "; if (pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL) ts << "ALL"; else ts << pChannel->midiChannel(); ts << endl; ts << "LOAD ENGINE " << pChannel->engineName() << " " << iChannelID << endl; if (pChannel->instrumentStatus() < 100) ts << "# "; ts << "LOAD INSTRUMENT NON_MODAL '" << pChannel->instrumentFile() << "' " << pChannel->instrumentNr() << " " << iChannelID << endl; ChannelRoutingMap::ConstIterator audioRoute; for (audioRoute = pChannel->audioRouting().begin(); audioRoute != pChannel->audioRouting().end(); ++audioRoute) { ts << "SET CHANNEL AUDIO_OUTPUT_CHANNEL " << iChannelID << " " << audioRoute.key() << " " << audioRoute.value() << endl; } ts << "SET CHANNEL VOLUME " << iChannelID << " " << pChannel->volume() << endl; if (pChannel->channelMute()) ts << "SET CHANNEL MUTE " << iChannelID << " 1" << endl; if (pChannel->channelSolo()) ts << "SET CHANNEL SOLO " << iChannelID << " 1" << endl; #ifdef CONFIG_MIDI_INSTRUMENT const int iMidiMap = pChannel->midiMap(); if (midiInstrumentMap.contains(iMidiMap)) { ts << "SET CHANNEL MIDI_INSTRUMENT_MAP " << iChannelID << " " << midiInstrumentMap.value(iMidiMap) << endl; } #endif #ifdef CONFIG_FXSEND int *piFxSends = ::lscp_list_fxsends(m_pClient, iChannelID); for (int iFxSend = 0; piFxSends && piFxSends[iFxSend] >= 0; iFxSend++) { lscp_fxsend_info_t *pFxSendInfo = ::lscp_get_fxsend_info( m_pClient, iChannelID, piFxSends[iFxSend]); if (pFxSendInfo) { ts << "CREATE FX_SEND " << iChannelID << " " << pFxSendInfo->midi_controller; if (pFxSendInfo->name) ts << " '" << pFxSendInfo->name << "'"; ts << endl; int *piRouting = pFxSendInfo->audio_routing; for (int iAudioSrc = 0; piRouting && piRouting[iAudioSrc] >= 0; iAudioSrc++) { ts << "SET FX_SEND AUDIO_OUTPUT_CHANNEL " << iChannelID << " " << iFxSend << " " << iAudioSrc << " " << piRouting[iAudioSrc] << endl; } #ifdef CONFIG_FXSEND_LEVEL ts << "SET FX_SEND LEVEL " << iChannelID << " " << iFxSend << " " << pFxSendInfo->level << endl; #endif } // Check for errors... else if (::lscp_client_get_errno(m_pClient)) { appendMessagesClient("lscp_get_fxsend_info"); iErrors++; } } #endif ts << endl; // Go for next channel... ++iChannelID; } } // Try to keep it snappy :) QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } #ifdef CONFIG_VOLUME ts << "# " << tr("Global volume level") << endl; ts << "SET VOLUME " << ::lscp_get_volume(m_pClient) << endl; ts << endl; #endif // Ok. we've wrote it. file.close(); // We're fornerly done. QApplication::restoreOverrideCursor(); // Have we any errors? if (iErrors > 0) { appendMessagesError( tr("Some settings could not be saved\n" "to \"%1\" session file.\n\nSorry.") .arg(sFilename)); } // Save as default session directory. if (m_pOptions) m_pOptions->sSessionDir = QFileInfo(sFilename).dir().absolutePath(); // We're not dirty anymore. m_iDirtyCount = 0; // Stabilize form... m_sFilename = sFilename; updateRecentFiles(sFilename); appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename))); stabilizeForm(); return true; } // Session change receiver slot. void MainForm::sessionDirty (void) { // Just mark the dirty form. m_iDirtyCount++; // and update the form status... stabilizeForm(); } //------------------------------------------------------------------------- // QSampler::MainForm -- File Action slots. // Create a new sampler session. void MainForm::fileNew (void) { // Of course we'll start clean new. newSession(); } // Open an existing sampler session. void MainForm::fileOpen (void) { // Open it right away. openSession(); } // Open a recent file session. void MainForm::fileOpenRecent (void) { // Retrive filename index from action data... QAction *pAction = qobject_cast (sender()); if (pAction && m_pOptions) { const int iIndex = pAction->data().toInt(); if (iIndex >= 0 && iIndex < m_pOptions->recentFiles.count()) { QString sFilename = m_pOptions->recentFiles[iIndex]; // Check if we can safely close the current session... if (!sFilename.isEmpty() && closeSession(true)) loadSessionFile(sFilename); } } } // Save current sampler session. void MainForm::fileSave (void) { // Save it right away. saveSession(false); } // Save current sampler session with another name. void MainForm::fileSaveAs (void) { // Save it right away, maybe with another name. saveSession(true); } // Reset the sampler instance. void MainForm::fileReset (void) { if (m_pClient == nullptr) return; // Ask user whether he/she want's an internal sampler reset... if (m_pOptions && m_pOptions->bConfirmReset) { const QString& sTitle = tr("Warning"); const QString& sText = tr( "Resetting the sampler instance will close\n" "all device and channel configurations.\n\n" "Please note that this operation may cause\n" "temporary MIDI and Audio disruption.\n\n" "Do you want to reset the sampler engine now?"); #if 0 if (QMessageBox::warning(this, sTitle, sText, QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) return; #else QMessageBox mbox(this); mbox.setIcon(QMessageBox::Warning); mbox.setWindowTitle(sTitle); mbox.setText(sText); mbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); QCheckBox cbox(tr("Don't ask this again")); cbox.setChecked(false); cbox.blockSignals(true); mbox.addButton(&cbox, QMessageBox::ActionRole); if (mbox.exec() == QMessageBox::Cancel) return; if (cbox.isChecked()) m_pOptions->bConfirmReset = false; #endif } // Trye closing the current session, first... if (!closeSession(true)) return; // Just do the reset, after closing down current session... // Do the actual sampler reset... if (::lscp_reset_sampler(m_pClient) != LSCP_OK) { appendMessagesClient("lscp_reset_sampler"); appendMessagesError(tr("Could not reset sampler instance.\n\nSorry.")); return; } // Log this. appendMessages(tr("Sampler reset.")); // Make it a new session... newSession(); } // Restart the client/server instance. void MainForm::fileRestart (void) { if (m_pOptions == nullptr) return; bool bRestart = true; // Ask user whether he/she want's a complete restart... // (if we're currently up and running) if (m_pOptions && m_pOptions->bConfirmRestart) { const QString& sTitle = tr("Warning"); const QString& sText = tr( "New settings will be effective after\n" "restarting the client/server connection.\n\n" "Please note that this operation may cause\n" "temporary MIDI and Audio disruption.\n\n" "Do you want to restart the connection now?"); #if 0 if (QMessageBox::warning(this, sTitle, sText, QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) bRestart = false; #else QMessageBox mbox(this); mbox.setIcon(QMessageBox::Warning); mbox.setWindowTitle(sTitle); mbox.setText(sText); mbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); QCheckBox cbox(tr("Don't ask this again")); cbox.setChecked(false); cbox.blockSignals(true); mbox.addButton(&cbox, QMessageBox::ActionRole); if (mbox.exec() == QMessageBox::Cancel) bRestart = false; else if (cbox.isChecked()) m_pOptions->bConfirmRestart = false; #endif } // Are we still for it? if (bRestart && closeSession(true)) { // Stop server, it will force the client too. stopServer(); // Reschedule a restart... startSchedule(m_pOptions->iStartDelay); } } // Exit application program. void MainForm::fileExit (void) { // Go for close the whole thing. close(); } //------------------------------------------------------------------------- // QSampler::MainForm -- Edit Action slots. // Add a new sampler channel. void MainForm::editAddChannel (void) { ++m_iDirtySetup; addChannelStrip(); --m_iDirtySetup; } void MainForm::addChannelStrip (void) { if (m_pClient == nullptr) return; // Just create the channel instance... Channel *pChannel = new Channel(); if (pChannel == nullptr) return; // Before we show it up, may be we'll // better ask for some initial values? if (!pChannel->channelSetup(this)) { delete pChannel; return; } // And give it to the strip... // (will own the channel instance, if successful). if (!createChannelStrip(pChannel)) { delete pChannel; return; } // Do we auto-arrange? channelsArrangeAuto(); // Make that an overall update. m_iDirtyCount++; stabilizeForm(); } // Remove current sampler channel. void MainForm::editRemoveChannel (void) { ++m_iDirtySetup; removeChannelStrip(); --m_iDirtySetup; } void MainForm::removeChannelStrip (void) { if (m_pClient == nullptr) return; ChannelStrip *pChannelStrip = activeChannelStrip(); if (pChannelStrip == nullptr) return; Channel *pChannel = pChannelStrip->channel(); if (pChannel == nullptr) return; // Prompt user if he/she's sure about this... if (m_pOptions && m_pOptions->bConfirmRemove) { const QString& sTitle = tr("Warning"); const QString& sText = tr( "About to remove channel:\n\n" "%1\n\n" "Are you sure?") .arg(pChannelStrip->windowTitle()); #if 0 if (QMessageBox::warning(this, sTitle, sText, QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) return; #else QMessageBox mbox(this); mbox.setIcon(QMessageBox::Warning); mbox.setWindowTitle(sTitle); mbox.setText(sText); mbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); QCheckBox cbox(tr("Don't ask this again")); cbox.setChecked(false); cbox.blockSignals(true); mbox.addButton(&cbox, QMessageBox::ActionRole); if (mbox.exec() == QMessageBox::Cancel) return; if (cbox.isChecked()) m_pOptions->bConfirmRemove = false; #endif } // Remove the existing sampler channel. if (!pChannel->removeChannel()) return; // Just delete the channel strip. destroyChannelStrip(pChannelStrip); // We'll be dirty, for sure... m_iDirtyCount++; stabilizeForm(); } // Setup current sampler channel. void MainForm::editSetupChannel (void) { if (m_pClient == nullptr) return; ChannelStrip *pChannelStrip = activeChannelStrip(); if (pChannelStrip == nullptr) return; // Just invoque the channel strip procedure. pChannelStrip->channelSetup(); } // Edit current sampler channel. void MainForm::editEditChannel (void) { if (m_pClient == nullptr) return; ChannelStrip *pChannelStrip = activeChannelStrip(); if (pChannelStrip == nullptr) return; // Just invoque the channel strip procedure. pChannelStrip->channelEdit(); } // Reset current sampler channel. void MainForm::editResetChannel (void) { if (m_pClient == nullptr) return; ChannelStrip *pChannelStrip = activeChannelStrip(); if (pChannelStrip == nullptr) return; // Just invoque the channel strip procedure. pChannelStrip->channelReset(); } // Reset all sampler channels. void MainForm::editResetAllChannels (void) { if (m_pClient == nullptr) return; // Invoque the channel strip procedure, // for all channels out there... m_pWorkspace->setUpdatesEnabled(false); const QList& wlist = m_pWorkspace->subWindowList(); foreach (QMdiSubWindow *pMdiSubWindow, wlist) { ChannelStrip *pChannelStrip = static_cast (pMdiSubWindow->widget()); if (pChannelStrip) pChannelStrip->channelReset(); } m_pWorkspace->setUpdatesEnabled(true); } //------------------------------------------------------------------------- // QSampler::MainForm -- View Action slots. // Show/hide the main program window menubar. void MainForm::viewMenubar ( bool bOn ) { if (bOn) m_ui.MenuBar->show(); else m_ui.MenuBar->hide(); } // Show/hide the main program window toolbar. void MainForm::viewToolbar ( bool bOn ) { if (bOn) { m_ui.fileToolbar->show(); m_ui.editToolbar->show(); m_ui.channelsToolbar->show(); } else { m_ui.fileToolbar->hide(); m_ui.editToolbar->hide(); m_ui.channelsToolbar->hide(); } } // Show/hide the main program window statusbar. void MainForm::viewStatusbar ( bool bOn ) { if (bOn) statusBar()->show(); else statusBar()->hide(); } // Show/hide the messages window logger. void MainForm::viewMessages ( bool bOn ) { if (bOn) m_pMessages->show(); else m_pMessages->hide(); } // Show/hide the MIDI instrument list-view form. void MainForm::viewInstruments (void) { if (m_pOptions == nullptr) return; if (m_pInstrumentListForm) { m_pOptions->saveWidgetGeometry(m_pInstrumentListForm); if (m_pInstrumentListForm->isVisible()) { m_pInstrumentListForm->hide(); } else { m_pInstrumentListForm->show(); m_pInstrumentListForm->raise(); m_pInstrumentListForm->activateWindow(); } } } // Show/hide the device configurator form. void MainForm::viewDevices (void) { if (m_pOptions == nullptr) return; if (m_pDeviceForm) { m_pOptions->saveWidgetGeometry(m_pDeviceForm); if (m_pDeviceForm->isVisible()) { m_pDeviceForm->hide(); } else { m_pDeviceForm->show(); m_pDeviceForm->raise(); m_pDeviceForm->activateWindow(); } } } // Show options dialog. void MainForm::viewOptions (void) { if (m_pOptions == nullptr) return; OptionsForm* pOptionsForm = new OptionsForm(this); if (pOptionsForm) { // Check out some initial nullities(tm)... ChannelStrip *pChannelStrip = activeChannelStrip(); if (m_pOptions->sDisplayFont.isEmpty() && pChannelStrip) m_pOptions->sDisplayFont = pChannelStrip->displayFont().toString(); if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages) m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString(); // To track down deferred or immediate changes. const QString sOldServerHost = m_pOptions->sServerHost; const int iOldServerPort = m_pOptions->iServerPort; const int iOldServerTimeout = m_pOptions->iServerTimeout; const bool bOldServerStart = m_pOptions->bServerStart; const QString sOldServerCmdLine = m_pOptions->sServerCmdLine; const bool bOldMessagesLog = m_pOptions->bMessagesLog; const QString sOldMessagesLogPath = m_pOptions->sMessagesLogPath; const QString sOldDisplayFont = m_pOptions->sDisplayFont; const bool bOldDisplayEffect = m_pOptions->bDisplayEffect; const int iOldMaxVolume = m_pOptions->iMaxVolume; const QString sOldMessagesFont = m_pOptions->sMessagesFont; const bool bOldKeepOnTop = m_pOptions->bKeepOnTop; const bool bOldStdoutCapture = m_pOptions->bStdoutCapture; const int bOldMessagesLimit = m_pOptions->bMessagesLimit; const int iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines; const bool bOldCompletePath = m_pOptions->bCompletePath; const bool bOldInstrumentNames = m_pOptions->bInstrumentNames; const int iOldMaxRecentFiles = m_pOptions->iMaxRecentFiles; const int iOldBaseFontSize = m_pOptions->iBaseFontSize; const QString sOldCustomStyleTheme = m_pOptions->sCustomStyleTheme; const QString sOldCustomColorTheme = m_pOptions->sCustomColorTheme; // Load the current setup settings. pOptionsForm->setup(m_pOptions); // Show the setup dialog... if (pOptionsForm->exec()) { // Warn if something will be only effective on next run. int iNeedRestart = 0; if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) || (!bOldStdoutCapture && m_pOptions->bStdoutCapture)) { updateMessagesCapture(); ++iNeedRestart; } if (( bOldKeepOnTop && !m_pOptions->bKeepOnTop) || (!bOldKeepOnTop && m_pOptions->bKeepOnTop) || (iOldBaseFontSize != m_pOptions->iBaseFontSize)) { ++iNeedRestart; } // Check whether restart is needed or whether // custom options maybe set up immediately... if (m_pOptions->sCustomStyleTheme != sOldCustomStyleTheme) { if (m_pOptions->sCustomStyleTheme.isEmpty()) { ++iNeedRestart; } else { QApplication::setStyle( QStyleFactory::create(m_pOptions->sCustomStyleTheme)); } } if (m_pOptions->sCustomColorTheme != sOldCustomColorTheme) { if (m_pOptions->sCustomColorTheme.isEmpty()) { ++iNeedRestart; } else { QPalette pal; if (PaletteForm::namedPalette( &m_pOptions->settings(), m_pOptions->sCustomColorTheme, pal)) QApplication::setPalette(pal); } } // Check wheather something immediate has changed. if (( bOldMessagesLog && !m_pOptions->bMessagesLog) || (!bOldMessagesLog && m_pOptions->bMessagesLog) || (sOldMessagesLogPath != m_pOptions->sMessagesLogPath)) m_pMessages->setLogging( m_pOptions->bMessagesLog, m_pOptions->sMessagesLogPath); if (( bOldCompletePath && !m_pOptions->bCompletePath) || (!bOldCompletePath && m_pOptions->bCompletePath) || (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles)) updateRecentFilesMenu(); if (( bOldInstrumentNames && !m_pOptions->bInstrumentNames) || (!bOldInstrumentNames && m_pOptions->bInstrumentNames)) updateInstrumentNames(); if (( bOldDisplayEffect && !m_pOptions->bDisplayEffect) || (!bOldDisplayEffect && m_pOptions->bDisplayEffect)) updateDisplayEffect(); if (sOldDisplayFont != m_pOptions->sDisplayFont) updateDisplayFont(); if (iOldMaxVolume != m_pOptions->iMaxVolume) updateMaxVolume(); if (sOldMessagesFont != m_pOptions->sMessagesFont) updateMessagesFont(); if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) || (!bOldMessagesLimit && m_pOptions->bMessagesLimit) || (iOldMessagesLimitLines != m_pOptions->iMessagesLimitLines)) updateMessagesLimit(); // Show restart needed message... if (iNeedRestart > 0) { QMessageBox::information(this, tr("Information"), tr("Some settings may be only effective\n" "next time you start this program.")); } // And now the main thing, whether we'll do client/server recycling? if ((sOldServerHost != m_pOptions->sServerHost) || (iOldServerPort != m_pOptions->iServerPort) || (iOldServerTimeout != m_pOptions->iServerTimeout) || ( bOldServerStart && !m_pOptions->bServerStart) || (!bOldServerStart && m_pOptions->bServerStart) || (sOldServerCmdLine != m_pOptions->sServerCmdLine && m_pOptions->bServerStart)) fileRestart(); } // Done. delete pOptionsForm; } // This makes it. stabilizeForm(); } //------------------------------------------------------------------------- // QSampler::MainForm -- Channels action slots. // Arrange channel strips. void MainForm::channelsArrange (void) { // Full width vertical tiling const QList& wlist = m_pWorkspace->subWindowList(); if (wlist.isEmpty()) return; m_pWorkspace->setUpdatesEnabled(false); int y = 0; foreach (QMdiSubWindow *pMdiSubWindow, wlist) { pMdiSubWindow->adjustSize(); const QRect& frameRect = pMdiSubWindow->frameGeometry(); int w = m_pWorkspace->width(); if (w < frameRect.width()) w = frameRect.width(); const int h = frameRect.height(); pMdiSubWindow->setGeometry(0, y, w, h); y += h; } m_pWorkspace->setUpdatesEnabled(true); stabilizeForm(); } // Auto-arrange channel strips. void MainForm::channelsAutoArrange ( bool bOn ) { if (m_pOptions == nullptr) return; // Toggle the auto-arrange flag. m_pOptions->bAutoArrange = bOn; // If on, update whole workspace... channelsArrangeAuto(); } void MainForm::channelsArrangeAuto (void) { if (m_pOptions && m_pOptions->bAutoArrange) channelsArrange(); } //------------------------------------------------------------------------- // QSampler::MainForm -- Help Action slots. // Show information about the Qt toolkit. void MainForm::helpAboutQt (void) { QMessageBox::aboutQt(this); } // Show information about application program. void MainForm::helpAbout (void) { QStringList list; #ifdef CONFIG_DEBUG list << tr("Debugging option enabled."); #endif #ifndef CONFIG_LIBGIG list << tr("GIG (libgig) file support disabled."); #endif #ifndef CONFIG_INSTRUMENT_NAME list << tr("LSCP (liblscp) instrument_name support disabled."); #endif #ifndef CONFIG_MUTE_SOLO list << tr("Sampler channel Mute/Solo support disabled."); #endif #ifndef CONFIG_AUDIO_ROUTING list << tr("LSCP (liblscp) audio_routing support disabled."); #endif #ifndef CONFIG_FXSEND list << tr("Sampler channel Effect Sends support disabled."); #endif #ifndef CONFIG_VOLUME list << tr("Global volume support disabled."); #endif #ifndef CONFIG_MIDI_INSTRUMENT list << tr("MIDI instrument mapping support disabled."); #endif #ifndef CONFIG_EDIT_INSTRUMENT list << tr("Instrument editing support disabled."); #endif #ifndef CONFIG_EVENT_CHANNEL_MIDI list << tr("Channel MIDI event support disabled."); #endif #ifndef CONFIG_EVENT_DEVICE_MIDI list << tr("Device MIDI event support disabled."); #endif #ifndef CONFIG_MAX_VOICES list << tr("Runtime max. voices / disk streams support disabled."); #endif // Stuff the about box text... QString sText = "

" QSAMPLER_TITLE "

\n"; sText += "

" + tr(QSAMPLER_SUBTITLE) + "
\n"; sText += "
\n"; sText += tr("Version") + ": " PROJECT_VERSION "
\n"; // sText += "" + tr("Build") + ": " CONFIG_BUILD_DATE "
\n"; if (!list.isEmpty()) { sText += ""; sText += list.join("
\n"); sText += "
"; } sText += "
\n"; sText += tr("Using: Qt %1").arg(qVersion()); #if defined(QT_STATIC) sText += "-static"; #endif sText += ", "; sText += ::lscp_client_package(); sText += " "; sText += ::lscp_client_version(); #ifdef CONFIG_LIBGIG sText += ", "; sText += gig::libraryName().c_str(); sText += " "; sText += gig::libraryVersion().c_str(); #endif sText += "
\n"; sText += "
\n"; sText += tr("Website") + ": " QSAMPLER_WEBSITE "
\n"; sText += "
\n"; sText += ""; sText += QSAMPLER_COPYRIGHT "
\n"; sText += QSAMPLER_COPYRIGHT2 "
\n"; sText += "
\n"; sText += tr("This program is free software; you can redistribute it and/or modify it") + "
\n"; sText += tr("under the terms of the GNU General Public License version 2 or later."); sText += "
"; sText += "
\n"; sText += "

\n"; QMessageBox::about(this, tr("About"), sText); } //------------------------------------------------------------------------- // QSampler::MainForm -- Main window stabilization. void MainForm::stabilizeForm (void) { // Update the main application caption... QString sSessionName = sessionName(m_sFilename); if (m_iDirtyCount > 0) sSessionName += " *"; setWindowTitle(sSessionName); // Update the main menu state... ChannelStrip *pChannelStrip = activeChannelStrip(); const QList& wlist = m_pWorkspace->subWindowList(); const bool bHasClient = (m_pOptions != nullptr && m_pClient != nullptr); const bool bHasChannel = (bHasClient && pChannelStrip != nullptr); const bool bHasChannels = (bHasClient && wlist.count() > 0); m_ui.fileNewAction->setEnabled(bHasClient); m_ui.fileOpenAction->setEnabled(bHasClient); m_ui.fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0); m_ui.fileSaveAsAction->setEnabled(bHasClient); m_ui.fileResetAction->setEnabled(bHasClient); m_ui.fileRestartAction->setEnabled(bHasClient || m_pServer == nullptr); m_ui.editAddChannelAction->setEnabled(bHasClient); m_ui.editRemoveChannelAction->setEnabled(bHasChannel); m_ui.editSetupChannelAction->setEnabled(bHasChannel); #ifdef CONFIG_EDIT_INSTRUMENT m_ui.editEditChannelAction->setEnabled(bHasChannel); #else m_ui.editEditChannelAction->setEnabled(false); #endif m_ui.editResetChannelAction->setEnabled(bHasChannel); m_ui.editResetAllChannelsAction->setEnabled(bHasChannels); m_ui.viewMessagesAction->setChecked(m_pMessages && m_pMessages->isVisible()); #ifdef CONFIG_MIDI_INSTRUMENT m_ui.viewInstrumentsAction->setChecked(m_pInstrumentListForm && m_pInstrumentListForm->isVisible()); m_ui.viewInstrumentsAction->setEnabled(bHasClient); #else m_ui.viewInstrumentsAction->setEnabled(false); #endif m_ui.viewDevicesAction->setChecked(m_pDeviceForm && m_pDeviceForm->isVisible()); m_ui.viewDevicesAction->setEnabled(bHasClient); m_ui.viewMidiDeviceStatusMenu->setEnabled( DeviceStatusForm::getInstances().size() > 0); m_ui.channelsArrangeAction->setEnabled(bHasChannels); #ifdef CONFIG_VOLUME // Toolbar widgets are also affected... m_pVolumeSlider->setEnabled(bHasClient); m_pVolumeSpinBox->setEnabled(bHasClient); #endif // Client/Server status... if (bHasClient) { m_statusItem[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected")); m_statusItem[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost + ':' + QString::number(m_pOptions->iServerPort)); } else { m_statusItem[QSAMPLER_STATUS_CLIENT]->clear(); m_statusItem[QSAMPLER_STATUS_SERVER]->clear(); } // Channel status... if (bHasChannel) m_statusItem[QSAMPLER_STATUS_CHANNEL]->setText(pChannelStrip->windowTitle()); else m_statusItem[QSAMPLER_STATUS_CHANNEL]->clear(); // Session status... if (m_iDirtyCount > 0) m_statusItem[QSAMPLER_STATUS_SESSION]->setText(tr("MOD")); else m_statusItem[QSAMPLER_STATUS_SESSION]->clear(); // Recent files menu. m_ui.fileOpenRecentMenu->setEnabled(m_pOptions->recentFiles.count() > 0); } // Global volume change receiver slot. void MainForm::volumeChanged ( int iVolume ) { #ifdef CONFIG_VOLUME if (m_iVolumeChanging > 0) return; m_iVolumeChanging++; // Update the toolbar widgets... if (m_pVolumeSlider->value() != iVolume) m_pVolumeSlider->setValue(iVolume); if (m_pVolumeSpinBox->value() != iVolume) m_pVolumeSpinBox->setValue(iVolume); // Do it as commanded... const float fVolume = 0.01f * float(iVolume); if (::lscp_set_volume(m_pClient, fVolume) == LSCP_OK) appendMessages(QObject::tr("Volume: %1.").arg(fVolume)); else appendMessagesClient("lscp_set_volume"); m_iVolumeChanging--; m_iDirtyCount++; stabilizeForm(); #endif } // Channel change receiver slot. void MainForm::channelStripChanged ( ChannelStrip *pChannelStrip ) { // Add this strip to the changed list... if (!m_changedStrips.contains(pChannelStrip)) { m_changedStrips.append(pChannelStrip); pChannelStrip->resetErrorCount(); } // Just mark the dirty form. m_iDirtyCount++; // and update the form status... stabilizeForm(); } // Grab and restore current sampler channels session. void MainForm::updateSession (void) { #ifdef CONFIG_VOLUME const int iVolume = ::lroundf(100.0f * ::lscp_get_volume(m_pClient)); m_iVolumeChanging++; m_pVolumeSlider->setValue(iVolume); m_pVolumeSpinBox->setValue(iVolume); m_iVolumeChanging--; #endif #ifdef CONFIG_MIDI_INSTRUMENT // FIXME: Make some room for default instrument maps... const int iMaps = ::lscp_get_midi_instrument_maps(m_pClient); if (iMaps < 0) appendMessagesClient("lscp_get_midi_instrument_maps"); else if (iMaps < 1) { ::lscp_add_midi_instrument_map(m_pClient, tr("Chromatic").toUtf8().constData()); ::lscp_add_midi_instrument_map(m_pClient, tr("Drum Kits").toUtf8().constData()); } #endif updateAllChannelStrips(false); // Do we auto-arrange? channelsArrangeAuto(); // Remember to refresh devices and instruments... if (m_pInstrumentListForm) m_pInstrumentListForm->refreshInstruments(); if (m_pDeviceForm) m_pDeviceForm->refreshDevices(); } void MainForm::updateAllChannelStrips ( bool bRemoveDeadStrips ) { // Skip if setting up a new channel strip... if (m_iDirtySetup > 0) return; // Retrieve the current channel list. int *piChannelIDs = ::lscp_list_channels(m_pClient); if (piChannelIDs == nullptr) { if (::lscp_client_get_errno(m_pClient)) { appendMessagesClient("lscp_list_channels"); appendMessagesError( tr("Could not get current list of channels.\n\nSorry.")); } } else { // Try to (re)create each channel. m_pWorkspace->setUpdatesEnabled(false); for (int iChannel = 0; piChannelIDs[iChannel] >= 0; ++iChannel) { // Check if theres already a channel strip for this one... if (!channelStrip(piChannelIDs[iChannel])) createChannelStrip(new Channel(piChannelIDs[iChannel])); } // Do we auto-arrange? channelsArrangeAuto(); // remove dead channel strips if (bRemoveDeadStrips) { const QList& wlist = m_pWorkspace->subWindowList(); foreach (QMdiSubWindow *pMdiSubWindow, wlist) { ChannelStrip *pChannelStrip = static_cast (pMdiSubWindow->widget()); if (pChannelStrip) { bool bExists = false; for (int iChannel = 0; piChannelIDs[iChannel] >= 0; ++iChannel) { Channel *pChannel = pChannelStrip->channel(); if (pChannel == nullptr) break; if (piChannelIDs[iChannel] == pChannel->channelID()) { // strip exists, don't touch it bExists = true; break; } } if (!bExists) destroyChannelStrip(pChannelStrip); } } } m_pWorkspace->setUpdatesEnabled(true); } stabilizeForm(); } // Update the recent files list and menu. void MainForm::updateRecentFiles ( const QString& sFilename ) { if (m_pOptions == nullptr) return; // Remove from list if already there (avoid duplicates) const int iIndex = m_pOptions->recentFiles.indexOf(sFilename); if (iIndex >= 0) m_pOptions->recentFiles.removeAt(iIndex); // Put it to front... m_pOptions->recentFiles.push_front(sFilename); } // Update the recent files list and menu. void MainForm::updateRecentFilesMenu (void) { if (m_pOptions == nullptr) return; // Time to keep the list under limits. int iRecentFiles = m_pOptions->recentFiles.count(); while (iRecentFiles > m_pOptions->iMaxRecentFiles) { m_pOptions->recentFiles.pop_back(); iRecentFiles--; } // Rebuild the recent files menu... m_ui.fileOpenRecentMenu->clear(); for (int i = 0; i < iRecentFiles; i++) { const QString& sFilename = m_pOptions->recentFiles[i]; if (QFileInfo(sFilename).exists()) { QAction *pAction = m_ui.fileOpenRecentMenu->addAction( QString("&%1 %2").arg(i + 1).arg(sessionName(sFilename)), this, SLOT(fileOpenRecent())); pAction->setData(i); } } } // Force update of the channels instrument names mode. void MainForm::updateInstrumentNames (void) { // Full channel list update... const QList& wlist = m_pWorkspace->subWindowList(); if (wlist.isEmpty()) return; m_pWorkspace->setUpdatesEnabled(false); foreach (QMdiSubWindow *pMdiSubWindow, wlist) { ChannelStrip *pChannelStrip = static_cast (pMdiSubWindow->widget()); if (pChannelStrip) pChannelStrip->updateInstrumentName(true); } m_pWorkspace->setUpdatesEnabled(true); } // Force update of the channels display font. void MainForm::updateDisplayFont (void) { if (m_pOptions == nullptr) return; // Check if display font is legal. if (m_pOptions->sDisplayFont.isEmpty()) return; // Realize it. QFont font; if (!font.fromString(m_pOptions->sDisplayFont)) return; // Full channel list update... const QList& wlist = m_pWorkspace->subWindowList(); if (wlist.isEmpty()) return; m_pWorkspace->setUpdatesEnabled(false); foreach (QMdiSubWindow *pMdiSubWindow, wlist) { ChannelStrip *pChannelStrip = static_cast (pMdiSubWindow->widget()); if (pChannelStrip) pChannelStrip->setDisplayFont(font); } m_pWorkspace->setUpdatesEnabled(true); } // Update channel strips background effect. void MainForm::updateDisplayEffect (void) { // Full channel list update... const QList& wlist = m_pWorkspace->subWindowList(); if (wlist.isEmpty()) return; m_pWorkspace->setUpdatesEnabled(false); foreach (QMdiSubWindow *pMdiSubWindow, wlist) { ChannelStrip *pChannelStrip = static_cast (pMdiSubWindow->widget()); if (pChannelStrip) pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect); } m_pWorkspace->setUpdatesEnabled(true); } // Force update of the channels maximum volume setting. void MainForm::updateMaxVolume (void) { if (m_pOptions == nullptr) return; #ifdef CONFIG_VOLUME m_iVolumeChanging++; m_pVolumeSlider->setMaximum(m_pOptions->iMaxVolume); m_pVolumeSpinBox->setMaximum(m_pOptions->iMaxVolume); m_iVolumeChanging--; #endif // Full channel list update... const QList& wlist = m_pWorkspace->subWindowList(); if (wlist.isEmpty()) return; m_pWorkspace->setUpdatesEnabled(false); foreach (QMdiSubWindow *pMdiSubWindow, wlist) { ChannelStrip *pChannelStrip = static_cast (pMdiSubWindow->widget()); if (pChannelStrip) pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume); } m_pWorkspace->setUpdatesEnabled(true); } //------------------------------------------------------------------------- // QSampler::MainForm -- Messages window form handlers. // Messages output methods. void MainForm::appendMessages ( const QString& s ) { if (m_pMessages) m_pMessages->appendMessages(s); statusBar()->showMessage(s, 3000); } void MainForm::appendMessagesColor ( const QString& s, const QColor& rgb ) { if (m_pMessages) m_pMessages->appendMessagesColor(s, rgb); statusBar()->showMessage(s, 3000); } void MainForm::appendMessagesText ( const QString& s ) { if (m_pMessages) m_pMessages->appendMessagesText(s); } void MainForm::appendMessagesError ( const QString& s ) { if (m_pMessages) m_pMessages->show(); appendMessagesColor(s.simplified(), Qt::red); // Make it look responsive...:) QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); if (m_pOptions && m_pOptions->bConfirmError) { const QString& sTitle = tr("Error"); #if 0 QMessageBox::critical(this, sTitle, sText, QMessageBox::Cancel); #else QMessageBox mbox(this); mbox.setIcon(QMessageBox::Critical); mbox.setWindowTitle(sTitle); mbox.setText(s); mbox.setStandardButtons(QMessageBox::Cancel); QCheckBox cbox(tr("Don't show this again")); cbox.setChecked(false); cbox.blockSignals(true); mbox.addButton(&cbox, QMessageBox::ActionRole); if (mbox.exec() && cbox.isChecked()) m_pOptions->bConfirmError = false; #endif } } // This is a special message format, just for client results. void MainForm::appendMessagesClient( const QString& s ) { if (m_pClient == nullptr) return; appendMessagesColor(s + QString(": %1 (errno=%2)") .arg(::lscp_client_get_result(m_pClient)) .arg(::lscp_client_get_errno(m_pClient)), "#996666"); // Make it look responsive...:) QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } // Force update of the messages font. void MainForm::updateMessagesFont (void) { if (m_pOptions == nullptr) return; if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) { QFont font; if (font.fromString(m_pOptions->sMessagesFont)) m_pMessages->setMessagesFont(font); } } // Update messages window line limit. void MainForm::updateMessagesLimit (void) { if (m_pOptions == nullptr) return; if (m_pMessages) { if (m_pOptions->bMessagesLimit) m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines); else m_pMessages->setMessagesLimit(-1); } } // Enablement of the messages capture feature. void MainForm::updateMessagesCapture (void) { if (m_pOptions == nullptr) return; if (m_pMessages) m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture); } //------------------------------------------------------------------------- // QSampler::MainForm -- MDI channel strip management. // The channel strip creation executive. ChannelStrip *MainForm::createChannelStrip ( Channel *pChannel ) { if (m_pClient == nullptr || pChannel == nullptr) return nullptr; // Add a new channel itema... ChannelStrip *pChannelStrip = new ChannelStrip(); if (pChannelStrip == nullptr) return nullptr; // Set some initial channel strip options... if (m_pOptions) { // Background display effect... pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect); // We'll need a display font. QFont font; if (!m_pOptions->sDisplayFont.isEmpty() && font.fromString(m_pOptions->sDisplayFont)) pChannelStrip->setDisplayFont(font); // Maximum allowed volume setting. pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume); } // Add it to workspace... QMdiSubWindow *pMdiSubWindow = m_pWorkspace->addSubWindow(pChannelStrip, Qt::SubWindow | Qt::FramelessWindowHint); pMdiSubWindow->setAttribute(Qt::WA_DeleteOnClose); // Actual channel strip setup... pChannelStrip->setup(pChannel); QObject::connect(pChannelStrip, SIGNAL(channelChanged(ChannelStrip *)), SLOT(channelStripChanged(ChannelStrip *))); // Now we show up us to the world. pChannelStrip->show(); // This is pretty new, so we'll watch for it closely. channelStripChanged(pChannelStrip); // Return our successful reference... return pChannelStrip; } void MainForm::destroyChannelStrip ( ChannelStrip *pChannelStrip ) { QMdiSubWindow *pMdiSubWindow = static_cast (pChannelStrip->parentWidget()); if (pMdiSubWindow == nullptr) return; // Just delete the channel strip. delete pChannelStrip; delete pMdiSubWindow; // Do we auto-arrange? channelsArrangeAuto(); } // Retrieve the active channel strip. ChannelStrip *MainForm::activeChannelStrip (void) { QMdiSubWindow *pMdiSubWindow = m_pWorkspace->activeSubWindow(); if (pMdiSubWindow) return static_cast (pMdiSubWindow->widget()); else return nullptr; } // Retrieve a channel strip by index. ChannelStrip *MainForm::channelStripAt ( int iStrip ) { if (!m_pWorkspace) return nullptr; const QList& wlist = m_pWorkspace->subWindowList(); if (wlist.isEmpty()) return nullptr; if (iStrip < 0 || iStrip >= wlist.count()) return nullptr; QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip); if (pMdiSubWindow) return static_cast (pMdiSubWindow->widget()); else return nullptr; } // Retrieve a channel strip by sampler channel id. ChannelStrip *MainForm::channelStrip ( int iChannelID ) { const QList& wlist = m_pWorkspace->subWindowList(); if (wlist.isEmpty()) return nullptr; foreach (QMdiSubWindow *pMdiSubWindow, wlist) { ChannelStrip *pChannelStrip = static_cast (pMdiSubWindow->widget()); if (pChannelStrip) { Channel *pChannel = pChannelStrip->channel(); if (pChannel && pChannel->channelID() == iChannelID) return pChannelStrip; } } // Not found. return nullptr; } // Construct the windows menu. void MainForm::channelsMenuAboutToShow (void) { m_ui.channelsMenu->clear(); m_ui.channelsMenu->addAction(m_ui.channelsArrangeAction); m_ui.channelsMenu->addAction(m_ui.channelsAutoArrangeAction); const QList& wlist = m_pWorkspace->subWindowList(); if (!wlist.isEmpty()) { m_ui.channelsMenu->addSeparator(); int iStrip = 0; foreach (QMdiSubWindow *pMdiSubWindow, wlist) { ChannelStrip *pChannelStrip = static_cast (pMdiSubWindow->widget()); if (pChannelStrip) { QAction *pAction = m_ui.channelsMenu->addAction( pChannelStrip->windowTitle(), this, SLOT(channelsMenuActivated())); pAction->setCheckable(true); pAction->setChecked(activeChannelStrip() == pChannelStrip); pAction->setData(iStrip); } ++iStrip; } } } // Windows menu activation slot void MainForm::channelsMenuActivated (void) { // Retrive channel index from action data... QAction *pAction = qobject_cast (sender()); if (pAction == nullptr) return; ChannelStrip *pChannelStrip = channelStripAt(pAction->data().toInt()); if (pChannelStrip) { pChannelStrip->showNormal(); pChannelStrip->setFocus(); } } //------------------------------------------------------------------------- // QSampler::MainForm -- Timer stuff. // Set the pseudo-timer delay schedule. void MainForm::startSchedule ( int iStartDelay ) { m_iStartDelay = 1 + (iStartDelay * 1000); m_iTimerDelay = 0; } // Suspend the pseudo-timer delay schedule. void MainForm::stopSchedule (void) { m_iStartDelay = 0; m_iTimerDelay = 0; } // Timer slot funtion. void MainForm::timerSlot (void) { if (m_pOptions == nullptr) return; // Is it the first shot on server start after a few delay? if (m_iTimerDelay < m_iStartDelay) { m_iTimerDelay += QSAMPLER_TIMER_MSECS; if (m_iTimerDelay >= m_iStartDelay) { // If we cannot start it now, maybe a lil'mo'later ;) if (!startClient()) { m_iStartDelay += m_iTimerDelay; m_iTimerDelay = 0; } } } if (m_pClient) { // Update the channel information for each pending strip... QListIterator iter(m_changedStrips); while (iter.hasNext()) { ChannelStrip *pChannelStrip = iter.next(); // If successfull, remove from pending list... if (pChannelStrip->updateChannelInfo()) { const int iChannelStrip = m_changedStrips.indexOf(pChannelStrip); if (iChannelStrip >= 0) m_changedStrips.removeAt(iChannelStrip); } } // Refresh each channel usage, on each period... if (m_pOptions->bAutoRefresh) { m_iTimerSlot += QSAMPLER_TIMER_MSECS; if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime) { m_iTimerSlot = 0; // Update the channel stream usage for each strip... const QList& wlist = m_pWorkspace->subWindowList(); foreach (QMdiSubWindow *pMdiSubWindow, wlist) { ChannelStrip *pChannelStrip = static_cast (pMdiSubWindow->widget()); if (pChannelStrip && pChannelStrip->isVisible()) pChannelStrip->updateChannelUsage(); } } } #if CONFIG_LSCP_CLIENT_CONNECTION_LOST // If we lost connection to server: Try to automatically reconnect if we // did not start the server. // // TODO: If we started the server, then we might inform the user that // the server probably crashed and asking user ONCE whether we should // restart the server. if (lscp_client_connection_lost(m_pClient) && !m_pServer) startAutoReconnectClient(); #endif // CONFIG_LSCP_CLIENT_CONNECTION_LOST } // Register the next timer slot. QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot())); } //------------------------------------------------------------------------- // QSampler::MainForm -- Server stuff. // Start linuxsampler server... void MainForm::startServer (void) { if (m_pOptions == nullptr) return; // Aren't already a client, are we? if (!m_pOptions->bServerStart || m_pClient) return; // Is the server process instance still here? if (m_pServer) { if (QMessageBox::warning(this, tr("Warning"), tr("Could not start the LinuxSampler server.\n\n" "Maybe it is already started."), QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { m_pServer->terminate(); m_pServer->kill(); } return; } // Reset our timer counters... stopSchedule(); // Verify we have something to start with... if (m_pOptions->sServerCmdLine.isEmpty()) return; // OK. Let's build the startup process... m_pServer = new QProcess(); m_bForceServerStop = true; // Setup stdout/stderr capture... m_pServer->setProcessChannelMode(QProcess::ForwardedChannels); QObject::connect(m_pServer, SIGNAL(readyReadStandardOutput()), SLOT(readServerStdout())); QObject::connect(m_pServer, SIGNAL(readyReadStandardError()), SLOT(readServerStdout())); // The unforgiveable signal communication... QObject::connect(m_pServer, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(processServerExit())); // Build process arguments... QStringList args = m_pOptions->sServerCmdLine.split(' '); QString sCommand = args[0]; args.removeAt(0); appendMessages(tr("Server is starting...")); appendMessagesColor(m_pOptions->sServerCmdLine, "#990099"); // Go linuxsampler, go... m_pServer->start(sCommand, args); if (!m_pServer->waitForStarted()) { appendMessagesError(tr("Could not start server.\n\nSorry.")); processServerExit(); return; } // Show startup results... appendMessages( tr("Server was started with PID=%1.") #if QT_VERSION < QT_VERSION_CHECK(5, 3, 0) .arg(quint64(m_pServer->pid()))); #else .arg(quint64(m_pServer->processId()))); #endif // Reset (yet again) the timer counters, // but this time is deferred as the user opted. startSchedule(m_pOptions->iStartDelay); stabilizeForm(); } // Stop linuxsampler server... void MainForm::stopServer ( bool bInteractive ) { // Stop client code. stopClient(); if (m_pServer && bInteractive) { if (QMessageBox::question(this, tr("The backend's fate ..."), tr("You have the option to keep the sampler backend (LinuxSampler)\n" "running in the background. The sampler would continue to work\n" "according to your current sampler session and you could alter the\n" "sampler session at any time by relaunching QSampler.\n\n" "Do you want LinuxSampler to stop?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::No) { m_bForceServerStop = false; } } bool bGraceWait = true; // And try to stop server. if (m_pServer && m_bForceServerStop) { appendMessages(tr("Server is stopping...")); if (m_pServer->state() == QProcess::Running) { #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) // Try harder... m_pServer->kill(); #else // Try softly... m_pServer->terminate(); bool bFinished = m_pServer->waitForFinished(QSAMPLER_TIMER_MSECS * 1000); if (bFinished) bGraceWait = false; #endif } } // Do final processing anyway. else processServerExit(); // Give it some time to terminate gracefully and stabilize... if (bGraceWait) { QElapsedTimer timer; timer.start(); while (timer.elapsed() < QSAMPLER_TIMER_MSECS) QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } } // Stdout handler... void MainForm::readServerStdout (void) { if (m_pMessages) m_pMessages->appendStdoutBuffer(m_pServer->readAllStandardOutput()); } // Linuxsampler server cleanup. void MainForm::processServerExit (void) { // Force client code cleanup. stopClient(); // Flush anything that maybe pending... if (m_pMessages) m_pMessages->flushStdoutBuffer(); if (m_pServer && m_bForceServerStop) { if (m_pServer->state() != QProcess::NotRunning) { appendMessages(tr("Server is being forced...")); // Force final server shutdown... m_pServer->kill(); // Give it some time to terminate gracefully and stabilize... QElapsedTimer timer; timer.start(); while (timer.elapsed() < QSAMPLER_TIMER_MSECS) QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } // Force final server shutdown... appendMessages( tr("Server was stopped with exit status %1.") .arg(m_pServer->exitStatus())); delete m_pServer; m_pServer = nullptr; } // Again, make status visible stable. stabilizeForm(); } //------------------------------------------------------------------------- // QSampler::MainForm -- Client stuff. // The LSCP client callback procedure. lscp_status_t qsampler_client_callback ( lscp_client_t */*pClient*/, lscp_event_t event, const char *pchData, int cchData, void *pvData ) { MainForm* pMainForm = (MainForm *) pvData; if (pMainForm == nullptr) return LSCP_FAILED; // ATTN: DO NOT EVER call any GUI code here, // as this is run under some other thread context. // A custom event must be posted here... QApplication::postEvent(pMainForm, new LscpEvent(event, pchData, cchData)); return LSCP_OK; } // Start our almighty client... bool MainForm::startClient (bool bReconnectOnly) { // Have it a setup? if (m_pOptions == nullptr) return false; // Aren't we already started, are we? if (m_pClient) return true; // Log prepare here. appendMessages(tr("Client connecting...")); // Create the client handle... m_pClient = ::lscp_client_create( m_pOptions->sServerHost.toUtf8().constData(), m_pOptions->iServerPort, qsampler_client_callback, this); if (m_pClient == nullptr) { // Is this the first try? // maybe we need to start a local server... if ((m_pServer && m_pServer->state() == QProcess::Running) || !m_pOptions->bServerStart || bReconnectOnly) { // if this method is called from autoReconnectClient() // then don't bother user with an error message... if (!bReconnectOnly) { appendMessagesError( tr("Could not connect to server as client.\n\nSorry.") ); } } else { startServer(); } // This is always a failure. stabilizeForm(); return false; } // Just set receive timeout value, blindly. ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout); appendMessages( tr("Client receive timeout is set to %1 msec.") .arg(::lscp_client_get_timeout(m_pClient))); // Subscribe to channel info change notifications... if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_COUNT) != LSCP_OK) appendMessagesClient("lscp_client_subscribe(CHANNEL_COUNT)"); if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO) != LSCP_OK) appendMessagesClient("lscp_client_subscribe(CHANNEL_INFO)"); DeviceStatusForm::onDevicesChanged(); // initialize updateViewMidiDeviceStatusMenu(); if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT) != LSCP_OK) appendMessagesClient("lscp_client_subscribe(MIDI_INPUT_DEVICE_COUNT)"); if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_INFO) != LSCP_OK) appendMessagesClient("lscp_client_subscribe(MIDI_INPUT_DEVICE_INFO)"); if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT) != LSCP_OK) appendMessagesClient("lscp_client_subscribe(AUDIO_OUTPUT_DEVICE_COUNT)"); if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO) != LSCP_OK) appendMessagesClient("lscp_client_subscribe(AUDIO_OUTPUT_DEVICE_INFO)"); #if CONFIG_EVENT_CHANNEL_MIDI // Subscribe to channel MIDI data notifications... if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_MIDI) != LSCP_OK) appendMessagesClient("lscp_client_subscribe(CHANNEL_MIDI)"); #endif #if CONFIG_EVENT_DEVICE_MIDI // Subscribe to channel MIDI data notifications... if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_DEVICE_MIDI) != LSCP_OK) appendMessagesClient("lscp_client_subscribe(DEVICE_MIDI)"); #endif // We may stop scheduling around. stopSchedule(); // We'll accept drops from now on... setAcceptDrops(true); // Log success here. appendMessages(tr("Client connected.")); // Hard-notify instrumnet and device configuration forms, // if visible, that we're ready... if (m_pInstrumentListForm) m_pInstrumentListForm->refreshInstruments(); if (m_pDeviceForm) m_pDeviceForm->refreshDevices(); // Is any session pending to be loaded? if (!m_pOptions->sessionFiles.isEmpty()) { // Just load the prabably startup session... if (loadSessionFile(m_pOptions->sessionFiles.first())) { m_pOptions->sessionFiles.clear(); return true; } } // send the current / loaded fine tuning settings to the sampler m_pOptions->sendFineTuningSettings(); // Make a new session return newSession(); } // Stop client... void MainForm::stopClient (void) { if (m_pClient == nullptr) return; // Log prepare here. appendMessages(tr("Client disconnecting...")); // Clear timer counters... stopSchedule(); // We'll reject drops from now on... setAcceptDrops(false); // Force any channel strips around, but // but avoid removing the corresponding // channels from the back-end server. m_iDirtyCount = 0; closeSession(false); // Close us as a client... #if CONFIG_EVENT_DEVICE_MIDI ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_DEVICE_MIDI); #endif #if CONFIG_EVENT_CHANNEL_MIDI ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_MIDI); #endif ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO); ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT); ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_INFO); ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT); ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO); ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_COUNT); ::lscp_client_destroy(m_pClient); m_pClient = nullptr; // Hard-notify instrumnet and device configuration forms, // if visible, that we're running out... if (m_pInstrumentListForm) m_pInstrumentListForm->refreshInstruments(); if (m_pDeviceForm) m_pDeviceForm->refreshDevices(); // Log final here. appendMessages(tr("Client disconnected.")); // Make visible status. stabilizeForm(); } void MainForm::startAutoReconnectClient (void) { stopClient(); appendMessages(tr("Trying to reconnect...")); QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(autoReconnectClient())); } void MainForm::autoReconnectClient (void) { const bool bSuccess = startClient(true); if (!bSuccess) QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(autoReconnectClient())); } // Channel strip activation/selection. void MainForm::activateStrip ( QMdiSubWindow *pMdiSubWindow ) { ChannelStrip *pChannelStrip = nullptr; if (pMdiSubWindow) pChannelStrip = static_cast (pMdiSubWindow->widget()); if (pChannelStrip) pChannelStrip->setSelected(true); stabilizeForm(); } // Channel toolbar orientation change. void MainForm::channelsToolbarOrientation ( Qt::Orientation orientation ) { #ifdef CONFIG_VOLUME m_pVolumeSlider->setOrientation(orientation); if (orientation == Qt::Horizontal) { m_pVolumeSlider->setMinimumHeight(24); m_pVolumeSlider->setMaximumHeight(32); m_pVolumeSlider->setMinimumWidth(120); m_pVolumeSlider->setMaximumWidth(640); m_pVolumeSpinBox->setMaximumWidth(64); m_pVolumeSpinBox->setButtonSymbols(QSpinBox::UpDownArrows); } else { m_pVolumeSlider->setMinimumHeight(120); m_pVolumeSlider->setMaximumHeight(480); m_pVolumeSlider->setMinimumWidth(24); m_pVolumeSlider->setMaximumWidth(32); m_pVolumeSpinBox->setMaximumWidth(32); m_pVolumeSpinBox->setButtonSymbols(QSpinBox::NoButtons); } #endif } } // namespace QSampler // end of qsamplerMainForm.cpp qsampler-1.0.0/src/PaxHeaders/qsamplerDeviceForm.h0000644000000000000000000000013214634065603017151 xustar0030 mtime=1718643587.393448566 30 atime=1718643587.393448566 30 ctime=1718643587.393448566 qsampler-1.0.0/src/qsamplerDeviceForm.h0000644000175000001440000000544314634065603017147 0ustar00rncbcusers// qsamplerDeviceForm.h // /**************************************************************************** Copyright (C) 2004-2020, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #ifndef __qsamplerDeviceForm_h #define __qsamplerDeviceForm_h #include "ui_qsamplerDeviceForm.h" #include "qsamplerDevice.h" namespace QSampler { //------------------------------------------------------------------------- // QSampler::DeviceForm -- Device form interface. // class DeviceForm : public QDialog { Q_OBJECT public: DeviceForm(QWidget *pParent = nullptr, Qt::WindowFlags wflags = Qt::WindowFlags()); ~DeviceForm(); void setDeviceTypeMode(Device::DeviceType deviceType); void setDriverName(const QString& sDriverName); void setDevice(Device *pDevice); public slots: void createDevice(); void deleteDevice(); void refreshDevices(); void selectDriver(int iDriver); void selectDevice(); void selectDevicePort(int iPort); void changeDeviceParam(int iRow, int iCol); void changeDevicePortParam(int iRow, int iCol); void deviceListViewContextMenu(const QPoint& pos); void stabilizeForm(); void updateCellRenderers(); void updateCellRenderers( const QModelIndex& topLeft, const QModelIndex& bottomRight); void updatePortCellRenderers(); void updatePortCellRenderers( const QModelIndex& topLeft, const QModelIndex& bottomRight); signals: void devicesChanged(); protected: void showEvent(QShowEvent* pShowEvent); void hideEvent(QHideEvent* pHideEvent); private: Ui::qsamplerDeviceForm m_ui; DeviceParamModel m_deviceParamModel; DeviceParamDelegate m_deviceParamDelegate; PortParamModel m_devicePortParamModel; DeviceParamDelegate m_devicePortParamDelegate; lscp_client_t *m_pClient; int m_iDirtySetup; int m_iDirtyCount; bool m_bNewDevice; Device::DeviceType m_deviceType; Device::DeviceType m_deviceTypeMode; DeviceItem *m_pAudioItems; DeviceItem *m_pMidiItems; }; } // namespace QSampler #endif // __qsamplerDeviceForm_h // end of qsamplerDeviceForm.h qsampler-1.0.0/src/PaxHeaders/qsamplerDevice.cpp0000644000000000000000000000013214634065603016660 xustar0030 mtime=1718643587.393448566 30 atime=1718643587.392448566 30 ctime=1718643587.393448566 qsampler-1.0.0/src/qsamplerDevice.cpp0000644000175000001440000010240014634065603016645 0ustar00rncbcusers// qsamplerDevice.cpp // /**************************************************************************** Copyright (C) 2004-2020, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, 2008 Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #include "qsamplerAbout.h" #include "qsamplerDevice.h" #include "qsamplerMainForm.h" #include "qsamplerDeviceForm.h" #include #include #include namespace QSampler { //------------------------------------------------------------------------- // QSampler::DeviceParam - MIDI/Audio Device parameter structure. // // Constructors. DeviceParam::DeviceParam ( lscp_param_info_t *pParamInfo, const char *pszValue ) { setParam(pParamInfo, pszValue); } // Initializer. void DeviceParam::setParam ( lscp_param_info_t *pParamInfo, const char *pszValue ) { if (pParamInfo == nullptr) return; // Info structure field members. type = pParamInfo->type; if (pParamInfo->description) description = pParamInfo->description; else description.clear(); mandatory = bool(pParamInfo->mandatory); fix = bool(pParamInfo->fix); multiplicity = bool(pParamInfo->multiplicity); depends.clear(); for (int i = 0; pParamInfo->depends && pParamInfo->depends[i]; i++) depends.append(pParamInfo->depends[i]); if (pParamInfo->defaultv) defaultv = pParamInfo->defaultv; else defaultv.clear(); if (pParamInfo->range_min) range_min = pParamInfo->range_min; else range_min.clear(); if (pParamInfo->range_max) range_max = pParamInfo->range_max; else range_max.clear(); possibilities.clear(); for (int i = 0; pParamInfo->possibilities && pParamInfo->possibilities[i]; i++) possibilities.append(pParamInfo->possibilities[i]); // The current parameter value. if (pszValue) value = pszValue; else value.clear(); } //------------------------------------------------------------------------- // QSampler::Device - MIDI/Audio Device structure. // // Constructor. Device::Device ( DeviceType deviceType, int iDeviceID ) { // m_ports.setAutoDelete(true); setDevice(deviceType, iDeviceID); } // Default destructor. Device::~Device (void) { qDeleteAll(m_ports); m_ports.clear(); } // Copy constructor. Device::Device ( const Device& device ) : m_params(device.m_params), m_ports(device.m_ports) { m_iDeviceID = device.m_iDeviceID; m_deviceType = device.m_deviceType; m_sDeviceType = device.m_sDeviceType; m_sDriverName = device.m_sDriverName; m_sDeviceName = device.m_sDeviceName; } // Initializer. void Device::setDevice ( DeviceType deviceType, int iDeviceID ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; if (pMainForm->client() == nullptr) return; // Device id and type should be always set. m_iDeviceID = iDeviceID; m_deviceType = deviceType; // Reset device parameters and ports anyway. m_params.clear(); qDeleteAll(m_ports); m_ports.clear(); // Retrieve device info, if any. lscp_device_info_t *pDeviceInfo = nullptr; switch (deviceType) { case Device::Audio: m_sDeviceType = QObject::tr("Audio"); if (m_iDeviceID >= 0 && (pDeviceInfo = ::lscp_get_audio_device_info( pMainForm->client(), m_iDeviceID)) == nullptr) appendMessagesClient("lscp_get_audio_device_info"); break; case Device::Midi: m_sDeviceType = QObject::tr("MIDI"); if (m_iDeviceID >= 0 && (pDeviceInfo = ::lscp_get_midi_device_info( pMainForm->client(), m_iDeviceID)) == nullptr) appendMessagesClient("lscp_get_midi_device_info"); break; case Device::None: m_sDeviceType.clear(); break; } // If we're bogus, bail out... if (pDeviceInfo == nullptr) { m_sDriverName.clear(); m_sDeviceName = QObject::tr("New %1 device").arg(m_sDeviceType); return; } // Other device properties... m_sDriverName = pDeviceInfo->driver; m_sDeviceName = m_sDriverName + ' ' + QObject::tr("Device %1").arg(m_iDeviceID); // Grab device parameters... for (int i = 0; pDeviceInfo->params && pDeviceInfo->params[i].key; i++) { const QString sParam = pDeviceInfo->params[i].key; lscp_param_info_t *pParamInfo = nullptr; switch (deviceType) { case Device::Audio: if ((pParamInfo = ::lscp_get_audio_driver_param_info( pMainForm->client(), m_sDriverName.toUtf8().constData(), sParam.toUtf8().constData(), nullptr)) == nullptr) appendMessagesClient("lscp_get_audio_driver_param_info"); break; case Device::Midi: if ((pParamInfo = ::lscp_get_midi_driver_param_info( pMainForm->client(), m_sDriverName.toUtf8().constData(), sParam.toUtf8().constData(), nullptr)) == nullptr) appendMessagesClient("lscp_get_midi_driver_param_info"); break; case Device::None: break; } if (pParamInfo) { m_params[sParam.toUpper()] = DeviceParam(pParamInfo, pDeviceInfo->params[i].value); } } // Refresh parameter dependencies... refreshParams(); // Set port/channel list... refreshPorts(); } // Driver name initializer/settler. void Device::setDriver ( const QString& sDriverName ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; if (pMainForm->client() == nullptr) return; // Valid only for scratch devices. if (m_sDriverName == sDriverName) return; // Reset device parameters and ports anyway. m_params.clear(); qDeleteAll(m_ports); m_ports.clear(); // Retrieve driver info, if any. lscp_driver_info_t *pDriverInfo = nullptr; switch (m_deviceType) { case Device::Audio: if ((pDriverInfo = ::lscp_get_audio_driver_info(pMainForm->client(), sDriverName.toUtf8().constData())) == nullptr) appendMessagesClient("lscp_get_audio_driver_info"); break; case Device::Midi: if ((pDriverInfo = ::lscp_get_midi_driver_info(pMainForm->client(), sDriverName.toUtf8().constData())) == nullptr) appendMessagesClient("lscp_get_midi_driver_info"); break; case Device::None: break; } // If we're bogus, bail out... if (pDriverInfo == nullptr) return; // Remember device parameters... m_sDriverName = sDriverName; // Grab driver parameters... for (int i = 0; pDriverInfo->parameters && pDriverInfo->parameters[i]; i++) { const QString sParam = pDriverInfo->parameters[i]; lscp_param_info_t *pParamInfo = nullptr; switch (m_deviceType) { case Device::Audio: if ((pParamInfo = ::lscp_get_audio_driver_param_info( pMainForm->client(), sDriverName.toUtf8().constData(), sParam.toUtf8().constData(), nullptr)) == nullptr) appendMessagesClient("lscp_get_audio_driver_param_info"); break; case Device::Midi: if ((pParamInfo = ::lscp_get_midi_driver_param_info( pMainForm->client(), sDriverName.toUtf8().constData(), sParam.toUtf8().constData(), nullptr)) == nullptr) appendMessagesClient("lscp_get_midi_driver_param_info"); break; case Device::None: break; } if (pParamInfo) { m_params[sParam.toUpper()] = DeviceParam(pParamInfo, pParamInfo->defaultv); } } // Refresh parameter dependencies... refreshParams(); // Set port/channel list... refreshPorts(); } // Device property accessors. int Device::deviceID (void) const { return m_iDeviceID; } Device::DeviceType Device::deviceType (void) const { return m_deviceType; } const QString& Device::deviceTypeName (void) const { return m_sDeviceType; } const QString& Device::driverName (void) const { return m_sDriverName; } // Special device name formatter. QString Device::deviceName (void) const { QString sPrefix; if (m_iDeviceID >= 0) sPrefix += m_sDeviceType + ' '; return sPrefix + m_sDeviceName; } // Set the proper device parameter value. bool Device::setParam ( const QString& sParam, const QString& sValue ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr) return false; // Set proper device parameter. m_params[sParam.toUpper()].value = sValue; // If the device already exists, things get immediate... int iRefresh = 0; if (m_iDeviceID >= 0 && !sValue.isEmpty()) { // we need temporary byte arrrays with the final strings, because // i.e. QString::toUtf8() only returns a temporary object and the // C-style char* pointers for liblscp would immediately be invalidated QByteArray finalParamKey = sParam.toUtf8(); QByteArray finalParamVal = sValue.toUtf8(); // Prepare parameter struct. lscp_param_t param; param.key = (char *) finalParamKey.constData(); param.value = (char *) finalParamVal.constData(); // Now it depends on the device type... lscp_status_t ret = LSCP_FAILED; switch (m_deviceType) { case Device::Audio: if (sParam == "CHANNELS") iRefresh++; if ((ret = ::lscp_set_audio_device_param(pMainForm->client(), m_iDeviceID, ¶m)) != LSCP_OK) appendMessagesClient("lscp_set_audio_device_param"); break; case Device::Midi: if (sParam == "PORTS") iRefresh++; if ((ret = ::lscp_set_midi_device_param(pMainForm->client(), m_iDeviceID, ¶m)) != LSCP_OK) appendMessagesClient("lscp_set_midi_device_param"); break; case Device::None: break; } // Show result. if (ret == LSCP_OK) { appendMessages(QString("%1: %2.").arg(sParam).arg(sValue)); // Special care for specific parameter changes... if (iRefresh > 0) iRefresh += refreshPorts(); iRefresh += refreshDepends(sParam); } else { // Oops... appendMessagesError( QObject::tr("Could not set device parameter value.\n\nSorry.")); } } // Return whether we're need a view refresh. return (iRefresh > 0); } // Device parameter accessor. const DeviceParamMap& Device::params (void) const { return m_params; } // Device port/channel list accessor. DevicePortList& Device::ports (void) { return m_ports; } // Create a new device, as a copy of this current one. bool Device::createDevice (void) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr) return false; // we need temporary lists with the final strings, because i.e. // QString::toUtf8() only returns a temporary object and the // C-style char* pointers for liblscp would immediately be invalidated QList finalKeys; QList finalVals; DeviceParamMap::ConstIterator iter; for (iter = m_params.begin(); iter != m_params.end(); ++iter) { if (iter.value().value.isEmpty()) continue; finalKeys.push_back(iter.key().toUtf8()); finalVals.push_back(iter.value().value.toUtf8()); } // yeah, we DO HAVE to do the two loops separately ! // Build the parameter list... lscp_param_t *pParams = new lscp_param_t [finalKeys.count() + 1]; int iParam; for (iParam = 0; iParam < finalKeys.count(); iParam++) { pParams[iParam].key = (char *) finalKeys[iParam].constData(); pParams[iParam].value = (char *) finalVals[iParam].constData(); } // Null terminated. pParams[iParam].key = nullptr; pParams[iParam].value = nullptr; // Now it depends on the device type... switch (m_deviceType) { case Device::Audio: if ((m_iDeviceID = ::lscp_create_audio_device(pMainForm->client(), m_sDriverName.toUtf8().constData(), pParams)) < 0) appendMessagesClient("lscp_create_audio_device"); break; case Device::Midi: if ((m_iDeviceID = ::lscp_create_midi_device(pMainForm->client(), m_sDriverName.toUtf8().constData(), pParams)) < 0) appendMessagesClient("lscp_create_midi_device"); break; case Device::None: break; } // Free used parameter array. delete[] pParams; // Show result. if (m_iDeviceID >= 0) { // Refresh our own stuff... setDevice(m_deviceType, m_iDeviceID); appendMessages(QObject::tr("created.")); } else { appendMessagesError(QObject::tr("Could not create device.\n\nSorry.")); } // Return whether we're a valid device... return (m_iDeviceID >= 0); } // Destroy existing device. bool Device::deleteDevice (void) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr) return false; // Now it depends on the device type... lscp_status_t ret = LSCP_FAILED; switch (m_deviceType) { case Device::Audio: if ((ret = ::lscp_destroy_audio_device(pMainForm->client(), m_iDeviceID)) != LSCP_OK) appendMessagesClient("lscp_destroy_audio_device"); break; case Device::Midi: if ((ret = ::lscp_destroy_midi_device(pMainForm->client(), m_iDeviceID)) != LSCP_OK) appendMessagesClient("lscp_destroy_midi_device"); break; case Device::None: break; } // Show result. if (ret == LSCP_OK) { appendMessages(QObject::tr("deleted.")); m_iDeviceID = -1; } else { appendMessagesError(QObject::tr("Could not delete device.\n\nSorry.")); } // Return whether we've done it.. return (ret == LSCP_OK); } // Device parameter dependencies refreshner. int Device::refreshParams (void) { // This should only make sense for scratch devices... if (m_iDeviceID >= 0) return 0; // Refresh all parameters that have dependencies... int iParams = 0; DeviceParamMap::ConstIterator iter; for (iter = m_params.begin(); iter != m_params.end(); ++iter) iParams += refreshParam(iter.key()); // Return how many parameters have been refreshed... return iParams; } // Device port/channel list refreshner. int Device::refreshPorts (void) { // This should only make sense for actual devices... if (m_iDeviceID < 0) return 0; // Port/channel count determination... int iPorts = 0; switch (m_deviceType) { case Device::Audio: iPorts = m_params["CHANNELS"].value.toInt(); break; case Device::Midi: iPorts = m_params["PORTS"].value.toInt(); break; case Device::None: break; } // Retrieve port/channel information... qDeleteAll(m_ports); m_ports.clear(); for (int iPort = 0; iPort < iPorts; iPort++) m_ports.append(new DevicePort(*this, iPort)); // Return how many ports have been refreshed... return iPorts; } // Refresh/set dependencies given that some parameter has changed. int Device::refreshDepends ( const QString& sParam ) { // This should only make sense for scratch devices... if (m_iDeviceID >= 0) return 0; // Refresh all parameters that depend on this one... int iDepends = 0; DeviceParamMap::ConstIterator iter; for (iter = m_params.begin(); iter != m_params.end(); ++iter) { const QStringList& depends = iter.value().depends; if (depends.indexOf(sParam) >= 0) iDepends += refreshParam(iter.key()); } // Return how many dependencies have been refreshed... return iDepends; } // Refresh/set given parameter based on driver supplied dependencies. int Device::refreshParam ( const QString& sParam ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return 0; if (pMainForm->client() == nullptr) return 0; // Check if we have dependencies... DeviceParam& param = m_params[sParam.toUpper()]; if (param.depends.isEmpty()) return 0; int iRefresh = 0; // Build dependency list... lscp_param_t *pDepends = new lscp_param_t [param.depends.count() + 1]; int iDepend = 0; // we need temporary lists with the final strings, because i.e. // QString::toUtf8() only returns a temporary object and the // C-style char* pointers for liblscp would immediately be invalidated QList finalKeys; QList finalVals; for (int i = 0; i < param.depends.count(); i++) { const QString& sDepend = param.depends[i]; finalKeys.push_back(sDepend.toUtf8()); finalVals.push_back(m_params[sDepend.toUpper()].value.toUtf8()); } // yeah, we DO HAVE to do those two loops separately ! for (int i = 0; i < param.depends.count(); i++) { pDepends[iDepend].key = (char *) finalKeys[i].constData(); pDepends[iDepend].value = (char *) finalVals[i].constData(); ++iDepend; } // Null terminated. pDepends[iDepend].key = nullptr; pDepends[iDepend].value = nullptr; // FIXME: Some parameter dependencies (e.g.ALSA CARD) // are blocking for no reason, causing potential timeout-crashes. // hopefully this gets mitigated if this dependency hell is only // carried out for scratch devices... // Retrieve some modern parameters... lscp_param_info_t *pParamInfo = nullptr; switch (m_deviceType) { case Device::Audio: if ((pParamInfo = ::lscp_get_audio_driver_param_info( pMainForm->client(), m_sDriverName.toUtf8().constData(), sParam.toUtf8().constData(), pDepends)) == nullptr) appendMessagesClient("lscp_get_audio_driver_param_info"); break; case Device::Midi: if ((pParamInfo = ::lscp_get_midi_driver_param_info( pMainForm->client(), m_sDriverName.toUtf8().constData(), sParam.toUtf8().constData(), pDepends)) == nullptr) appendMessagesClient("lscp_get_midi_driver_param_info"); break; case Device::None: break; } if (pParamInfo) { param = DeviceParam(pParamInfo, param.value.isEmpty() ? nullptr : param.value.toUtf8().constData()); iRefresh++; } // Free used parameter array. delete[] pDepends; // Return whether the parameters has been changed... return iRefresh; } // Redirected messages output methods. void Device::appendMessages( const QString& s ) const { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm) pMainForm->appendMessages(deviceName() + ' ' + s); } void Device::appendMessagesColor( const QString& s, const QColor& rgb ) const { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm) pMainForm->appendMessagesColor(deviceName() + ' ' + s, rgb); } void Device::appendMessagesText( const QString& s ) const { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm) pMainForm->appendMessagesText(deviceName() + ' ' + s); } void Device::appendMessagesError( const QString& s ) const { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm) pMainForm->appendMessagesError(deviceName() + "\n\n" + s); } void Device::appendMessagesClient( const QString& s ) const { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm) pMainForm->appendMessagesClient(deviceName() + ' ' + s); } // Device ids enumerator. int *Device::getDevices ( lscp_client_t *pClient, DeviceType deviceType ) { int *piDeviceIDs = nullptr; switch (deviceType) { case Device::Audio: piDeviceIDs = ::lscp_list_audio_devices(pClient); break; case Device::Midi: piDeviceIDs = ::lscp_list_midi_devices(pClient); break; case Device::None: break; } return piDeviceIDs; } std::set Device::getDeviceIDs(lscp_client_t *pClient, DeviceType deviceType) { std::set result; int* piDeviceIDs = getDevices(pClient, deviceType); if (!piDeviceIDs) return result; for (int i = 0; piDeviceIDs[i] != -1; ++i) result.insert(piDeviceIDs[i]); return result; } // Driver names enumerator. QStringList Device::getDrivers ( lscp_client_t *pClient, DeviceType deviceType ) { QStringList drivers; const char **ppszDrivers = nullptr; switch (deviceType) { case Device::Audio: ppszDrivers = ::lscp_list_available_audio_drivers(pClient); break; case Device::Midi: ppszDrivers = ::lscp_list_available_midi_drivers(pClient); break; case Device::None: break; } for (int iDriver = 0; ppszDrivers && ppszDrivers[iDriver]; iDriver++) drivers.append(ppszDrivers[iDriver]); return drivers; } //------------------------------------------------------------------------- // QSampler::DevicePort - MIDI/Audio Device port/channel structure. // // Constructor. DevicePort::DevicePort ( Device& device, int iPortID ) : m_device(device) { setDevicePort(iPortID); } // Default destructor. DevicePort::~DevicePort (void) { } // Initializer. void DevicePort::setDevicePort ( int iPortID ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; if (pMainForm->client() == nullptr) return; // Device port id should be always set. m_iPortID = iPortID; // Reset port parameters anyway. m_params.clear(); // Retrieve device port/channel info, if any. lscp_device_port_info_t *pPortInfo = nullptr; switch (m_device.deviceType()) { case Device::Audio: if ((pPortInfo = ::lscp_get_audio_channel_info(pMainForm->client(), m_device.deviceID(), m_iPortID)) == nullptr) m_device.appendMessagesClient("lscp_get_audio_channel_info"); break; case Device::Midi: if ((pPortInfo = ::lscp_get_midi_port_info(pMainForm->client(), m_device.deviceID(), m_iPortID)) == nullptr) m_device.appendMessagesClient("lscp_get_midi_port_info"); break; case Device::None: break; } // If we're bogus, bail out... if (pPortInfo == nullptr) { m_sPortName.clear(); return; } // Set device port/channel properties... m_sPortName = pPortInfo->name; // Grab device port/channel parameters... m_params.clear(); for (int i = 0; pPortInfo->params && pPortInfo->params[i].key; i++) { const QString sParam = pPortInfo->params[i].key; lscp_param_info_t *pParamInfo = nullptr; switch (m_device.deviceType()) { case Device::Audio: if ((pParamInfo = ::lscp_get_audio_channel_param_info( pMainForm->client(), m_device.deviceID(), m_iPortID, sParam.toUtf8().constData())) == nullptr) m_device.appendMessagesClient("lscp_get_audio_channel_param_info"); break; case Device::Midi: if ((pParamInfo = ::lscp_get_midi_port_param_info( pMainForm->client(), m_device.deviceID(), m_iPortID, sParam.toUtf8().constData())) == nullptr) m_device.appendMessagesClient("lscp_get_midi_port_param_info"); break; case Device::None: break; } if (pParamInfo) { m_params[sParam.toUpper()] = DeviceParam(pParamInfo, pPortInfo->params[i].value); } } } // Device port/channel property accessors. int DevicePort::portID (void) const { return m_iPortID; } const QString& DevicePort::portName (void) const { return m_sPortName; } // Device port/channel parameter accessor. const DeviceParamMap& DevicePort::params (void) const { return m_params; } // Set the proper device port/channel parameter value. bool DevicePort::setParam ( const QString& sParam, const QString& sValue ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return false; if (pMainForm->client() == nullptr) return false; // Set proper port/channel parameter. m_params[sParam.toUpper()].value = sValue; // If the device already exists, things get immediate... int iRefresh = 0; if (m_device.deviceID() >= 0 && m_iPortID >= 0) { // we need temporary byte arrrays with the final strings, because // i.e. QString::toUtf8() only returns a temporary object and the // C-style char* pointers for liblscp would immediately be invalidated QByteArray finalParamKey = sParam.toUtf8(); QByteArray finalParamVal = sValue.toUtf8(); // Prepare parameter struct. lscp_param_t param; param.key = (char *) finalParamKey.constData(); param.value = (char *) finalParamVal.constData(); // Now it depends on the device type... lscp_status_t ret = LSCP_FAILED; switch (m_device.deviceType()) { case Device::Audio: if ((ret = ::lscp_set_audio_channel_param(pMainForm->client(), m_device.deviceID(), m_iPortID, ¶m)) != LSCP_OK) m_device.appendMessagesClient("lscp_set_audio_channel_param"); break; case Device::Midi: if ((ret = ::lscp_set_midi_port_param(pMainForm->client(), m_device.deviceID(), m_iPortID, ¶m)) != LSCP_OK) m_device.appendMessagesClient("lscp_set_midi_port_param"); break; case Device::None: break; } // Show result. if (ret == LSCP_OK) { m_device.appendMessages(m_sPortName + ' ' + QString("%1: %2.").arg(sParam).arg(sValue)); iRefresh++; } else { m_device.appendMessagesError( QObject::tr("Could not set %1 parameter value.\n\n" "Sorry.").arg(m_sPortName)); } } // Return whether we're need a view refresh. return (iRefresh > 0); } //------------------------------------------------------------------------- // QSampler::DeviceItem - QTreeWidget device item. // // Constructors. DeviceItem::DeviceItem ( QTreeWidget* pTreeWidget, Device::DeviceType deviceType ) : QTreeWidgetItem(pTreeWidget, QSAMPLER_DEVICE_ITEM), m_device(deviceType) { switch(m_device.deviceType()) { case Device::Audio: setIcon(0, QPixmap(":/images/audio1.png")); setText(0, QObject::tr("Audio Devices")); break; case Device::Midi: setIcon(0, QPixmap(":/images/midi1.png")); setText(0, QObject::tr("MIDI Devices")); break; case Device::None: break; } // Root items are not selectable... setFlags(flags() & ~Qt::ItemIsSelectable); } DeviceItem::DeviceItem ( QTreeWidgetItem* pItem, Device::DeviceType deviceType, int iDeviceID ) : QTreeWidgetItem(pItem, QSAMPLER_DEVICE_ITEM), m_device(deviceType, iDeviceID) { switch(m_device.deviceType()) { case Device::Audio: setIcon(0, QPixmap(":/images/audio2.png")); break; case Device::Midi: setIcon(0, QPixmap(":/images/midi2.png")); break; case Device::None: break; } setText(0, m_device.deviceName()); } // Default destructor. DeviceItem::~DeviceItem () { } // Instance accessors. Device& DeviceItem::device () { return m_device; } //------------------------------------------------------------------------- // QSampler::AbstractDeviceParamModel - data model base class for device parameters // AbstractDeviceParamModel::AbstractDeviceParamModel ( QObject* pParent ) : QAbstractTableModel(pParent), m_bEditable(false) { m_pParams = nullptr; } int AbstractDeviceParamModel::rowCount ( const QModelIndex& /*parent*/) const { //std::cout << "model size=" << params.size() << "\n" << std::flush; return (m_pParams ? m_pParams->size() : 0); } int AbstractDeviceParamModel::columnCount ( const QModelIndex& /*parent*/) const { return 3; } Qt::ItemFlags AbstractDeviceParamModel::flags ( const QModelIndex& /*index*/) const { return Qt::ItemIsEditable | Qt::ItemIsEnabled; } QVariant AbstractDeviceParamModel::headerData ( int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) return QVariant(); if (orientation == Qt::Horizontal) { switch (section) { case 0: return tr("Parameter"); case 1: return tr("Value"); case 2: return tr("Description"); default: return QVariant(); } } return QVariant(); } void AbstractDeviceParamModel::refresh ( const DeviceParamMap* pParams, bool bEditable ) { m_pParams = pParams; m_bEditable = bEditable; // inform the outer world (QTableView) that our data changed #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) QAbstractTableModel::reset(); #else QAbstractTableModel::beginResetModel(); QAbstractTableModel::endResetModel(); #endif } void AbstractDeviceParamModel::clear (void) { m_pParams = nullptr; // inform the outer world (QTableView) that our data changed #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) QAbstractTableModel::reset(); #else QAbstractTableModel::beginResetModel(); QAbstractTableModel::endResetModel(); #endif } //------------------------------------------------------------------------- // QSampler::DeviceParamModel - data model for device parameters // (used for QTableView) DeviceParamModel::DeviceParamModel ( QObject *pParent ) : AbstractDeviceParamModel(pParent) { m_pDevice = nullptr; } QVariant DeviceParamModel::data ( const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (role != Qt::DisplayRole) return QVariant(); DeviceParameterRow item; item.name = m_pParams->keys()[index.row()]; item.param = (*m_pParams)[item.name]; item.alive = (m_pDevice && m_pDevice->deviceID() >= 0); return QVariant::fromValue(item); } bool DeviceParamModel::setData ( const QModelIndex& index, const QVariant& value, int /*role*/) { if (!index.isValid()) return false; QString key = m_pParams->keys()[index.row()]; //m_pParams[key].value = value.toString(); m_pDevice->setParam(key, value.toString()); emit dataChanged(index, index); return true; } void DeviceParamModel::refresh ( Device* pDevice, bool bEditable ) { m_pDevice = pDevice; AbstractDeviceParamModel::refresh(&pDevice->params(), bEditable); } void DeviceParamModel::clear (void) { AbstractDeviceParamModel::clear(); m_pDevice = nullptr; } //------------------------------------------------------------------------- // QSampler::PortParamModel - data model for port parameters // (used for QTableView) PortParamModel::PortParamModel ( QObject *pParent) : AbstractDeviceParamModel(pParent) { m_pPort = nullptr; } QVariant PortParamModel::data ( const QModelIndex &index, int role ) const { if (!index.isValid()) return QVariant(); if (role != Qt::DisplayRole) return QVariant(); DeviceParameterRow item; item.name = m_pParams->keys()[index.row()]; item.param = (*m_pParams)[item.name]; item.alive = (m_pPort && m_pPort->portID() >= 0); return QVariant::fromValue(item); } bool PortParamModel::setData ( const QModelIndex& index, const QVariant& value, int /*role*/) { if (!index.isValid()) return false; QString key = m_pParams->keys()[index.row()]; //params[key].value = value.toString(); m_pPort->setParam(key, value.toString()); emit dataChanged(index, index); return true; } void PortParamModel::refresh ( DevicePort* pPort, bool bEditable ) { m_pPort = pPort; AbstractDeviceParamModel::refresh(&pPort->params(), bEditable); } void PortParamModel::clear (void) { AbstractDeviceParamModel::clear(); m_pPort = nullptr; } //------------------------------------------------------------------------- // QSampler::DeviceParamDelegate - table cell renderer for device/port parameters // DeviceParamDelegate::DeviceParamDelegate ( QObject *pParent) : QItemDelegate(pParent) { } QWidget* DeviceParamDelegate::createEditor ( QWidget *pParent, const QStyleOptionViewItem& /* option */, const QModelIndex& index ) const { if (!index.isValid()) return nullptr; DeviceParameterRow r = index.model()->data(index, Qt::DisplayRole).value(); const bool bEnabled = (r.alive) ? !r.param.fix : true; const bool bFix = r.param.fix; QString val = (r.alive) ? r.param.value : r.param.defaultv; switch (index.column()) { case 0: return new QLabel(r.name, pParent); case 1: { if (r.param.type == LSCP_TYPE_BOOL) { QCheckBox *pCheckBox = new QCheckBox(pParent); if (!val.isEmpty()) pCheckBox->setChecked(val.toLower() == "true"); pCheckBox->setEnabled(bEnabled); pCheckBox->setCheckable(!bFix); return pCheckBox; } else if (r.param.possibilities.count() > 0) { QStringList opts = r.param.possibilities; if (r.param.multiplicity) opts.prepend(tr("(none)")); QComboBox *pComboBox = new QComboBox(pParent); pComboBox->addItems(opts); if (r.param.value.isEmpty()) pComboBox->setCurrentIndex(0); else pComboBox->setCurrentIndex(pComboBox->findText(val)); pComboBox->setEnabled(bEnabled); pComboBox->setEditable(!bFix); return pComboBox; } else if (r.param.type == LSCP_TYPE_INT && bEnabled) { QSpinBox *pSpinBox = new QSpinBox(pParent); pSpinBox->setMinimum( (!r.param.range_min.isEmpty()) ? r.param.range_min.toInt() : 0 // or better a negative default min value ? ); pSpinBox->setMaximum( (!r.param.range_max.isEmpty()) ? r.param.range_max.toInt() : (1 << 24) // or better a higher default max value ? ); pSpinBox->setValue(val.toInt()); pSpinBox->setReadOnly(bFix); return pSpinBox; } else if (bEnabled) { QLineEdit *pLineEdit = new QLineEdit(val, pParent); pLineEdit->setReadOnly(bFix); return pLineEdit; } else { QLabel *pLabel = new QLabel(val, pParent); return pLabel; } } case 2: return new QLabel(r.param.description, pParent); default: return nullptr; } } void DeviceParamDelegate::setEditorData ( QWidget* /*pEditor*/, const QModelIndex& /*index*/) const { // Unused, since we set the editor data already in createEditor() } void DeviceParamDelegate::setModelData ( QWidget *pEditor, QAbstractItemModel *pModel, const QModelIndex& index ) const { if (index.column() == 1) { DeviceParameterRow r = index.model()->data(index, Qt::DisplayRole).value (); if (pEditor->metaObject()->className() == QString("QCheckBox")) { QCheckBox *pCheckBox = static_cast (pEditor); pModel->setData(index, QVariant(pCheckBox->checkState() == Qt::Checked)); } else if (pEditor->metaObject()->className() == QString("QComboBox")) { QComboBox *pComboBox = static_cast (pEditor); pModel->setData(index, pComboBox->currentText()); } else if (pEditor->metaObject()->className() == QString("QSpinBox")) { QSpinBox *pSpinBox = static_cast (pEditor); pModel->setData(index, pSpinBox->value()); } else if (pEditor->metaObject()->className() == QString("QLineEdit")) { QLineEdit *pLineEdit = static_cast (pEditor); pModel->setData(index, pLineEdit->text()); } else if (pEditor->metaObject()->className() == QString("QLabel")) { QLabel *pLabel = static_cast (pEditor); pModel->setData(index, pLabel->text()); } } } void DeviceParamDelegate::updateEditorGeometry ( QWidget *pEditor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { if (pEditor) pEditor->setGeometry(option.rect); } } // namespace QSampler // end of qsamplerDevice.cpp qsampler-1.0.0/src/PaxHeaders/qsamplerInstrumentListForm.cpp0000644000000000000000000000013214634065603021311 xustar0030 mtime=1718643587.393448566 30 atime=1718643587.393448566 30 ctime=1718643587.393448566 qsampler-1.0.0/src/qsamplerInstrumentListForm.cpp0000644000175000001440000002166414634065603021312 0ustar00rncbcusers// qsamplerInstrumentListForm.cpp // /**************************************************************************** Copyright (C) 2003-2020, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *****************************************************************************/ #include "qsamplerAbout.h" #include "qsamplerInstrumentListForm.h" #include "qsamplerInstrumentList.h" #include "qsamplerInstrumentForm.h" #include "qsamplerOptions.h" #include "qsamplerInstrument.h" #include "qsamplerMainForm.h" #include #include #include #include namespace QSampler { //------------------------------------------------------------------------- // QSampler::InstrumentListForm -- Instrument map list form implementation. // InstrumentListForm::InstrumentListForm ( QWidget *pParent, Qt::WindowFlags wflags ) : QMainWindow(pParent, wflags) { m_ui.setupUi(this); m_pInstrumentListView = new InstrumentListView(this); QMainWindow::setCentralWidget(m_pInstrumentListView); // Setup toolbar widgets. m_pMapComboBox = new QComboBox(m_ui.instrumentToolbar); m_pMapComboBox->setMinimumWidth(120); m_pMapComboBox->setEnabled(false); m_pMapComboBox->setToolTip(tr("Instrument Map")); m_ui.instrumentToolbar->addWidget(m_pMapComboBox); m_ui.instrumentToolbar->addSeparator(); m_ui.instrumentToolbar->addAction(m_ui.newInstrumentAction); m_ui.instrumentToolbar->addAction(m_ui.editInstrumentAction); m_ui.instrumentToolbar->addAction(m_ui.deleteInstrumentAction); m_ui.instrumentToolbar->addSeparator(); m_ui.instrumentToolbar->addAction(m_ui.refreshInstrumentsAction); QObject::connect(m_pMapComboBox, SIGNAL(activated(int)), SLOT(activateMap(int))); QObject::connect(m_pInstrumentListView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex&,const QModelIndex&)), SLOT(stabilizeForm())); QObject::connect( m_pInstrumentListView, SIGNAL(activated(const QModelIndex&)), SLOT(editInstrument(const QModelIndex&))); QObject::connect( m_ui.newInstrumentAction, SIGNAL(triggered()), SLOT(newInstrument())); QObject::connect( m_ui.deleteInstrumentAction, SIGNAL(triggered()), SLOT(deleteInstrument())); QObject::connect( m_ui.editInstrumentAction, SIGNAL(triggered()), SLOT(editInstrument())); QObject::connect( m_ui.refreshInstrumentsAction, SIGNAL(triggered()), SLOT(refreshInstruments())); // Things must be stable from the start. stabilizeForm(); } InstrumentListForm::~InstrumentListForm (void) { delete m_pMapComboBox; delete m_pInstrumentListView; } // Notify our parent that we're emerging. void InstrumentListForm::showEvent ( QShowEvent *pShowEvent ) { MainForm* pMainForm = MainForm::getInstance(); if (pMainForm) pMainForm->stabilizeForm(); QWidget::showEvent(pShowEvent); } // Notify our parent that we're closing. void InstrumentListForm::hideEvent ( QHideEvent *pHideEvent ) { QWidget::hideEvent(pHideEvent); MainForm* pMainForm = MainForm::getInstance(); if (pMainForm) pMainForm->stabilizeForm(); } // Just about to notify main-window that we're closing. void InstrumentListForm::closeEvent ( QCloseEvent * /*pCloseEvent*/ ) { QWidget::hide(); MainForm *pMainForm = MainForm::getInstance(); if (pMainForm) pMainForm->stabilizeForm(); } // Refresh all instrument list and views. void InstrumentListForm::refreshInstruments (void) { MainForm* pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; Options *pOptions = pMainForm->options(); if (pOptions == nullptr) return; // Get/save current map selection... int iMap = m_pMapComboBox->currentIndex(); if (iMap < 0 || m_pMapComboBox->count() < 2) iMap = pOptions->iMidiMap + 1; // Populate maps list. m_pMapComboBox->clear(); m_pMapComboBox->addItem(tr("(All)")); m_pMapComboBox->insertItems(1, Instrument::getMapNames()); // Adjust to saved selection... if (iMap < 0 || iMap >= m_pMapComboBox->count()) iMap = 0; m_pMapComboBox->setCurrentIndex(iMap); m_pMapComboBox->setEnabled(m_pMapComboBox->count() > 1); activateMap(iMap); } // Refresh instrument maps selector. void InstrumentListForm::activateMap ( int iMap ) { MainForm* pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; Options *pOptions = pMainForm->options(); if (pOptions == nullptr) return; int iMidiMap = iMap - 1; if (iMidiMap >= 0) pOptions->iMidiMap = iMidiMap; m_pInstrumentListView->setMidiMap(iMidiMap); m_pInstrumentListView->refresh(); stabilizeForm(); } void InstrumentListForm::newInstrument (void) { Instrument instrument; InstrumentForm form(this); form.setup(&instrument); if (!form.exec()) return; // Commit... instrument.mapInstrument(); // add new item to the table model m_pInstrumentListView->addInstrument( instrument.map(), instrument.bank(), instrument.prog()); stabilizeForm(); } void InstrumentListForm::editInstrument (void) { editInstrument(m_pInstrumentListView->currentIndex()); } void InstrumentListForm::editInstrument ( const QModelIndex& index ) { if (!index.isValid()) return; Instrument *pInstrument = static_cast (index.internalPointer()); if (pInstrument == nullptr) return; // Save current key values... int iMap = pInstrument->map(); int iBank = pInstrument->bank(); int iProg = pInstrument->prog(); Instrument instrument(iMap, iBank, iProg); // Do the edit dance... InstrumentForm form(this); form.setup(pInstrument); if (!form.exec()) return; // Commit... pInstrument->mapInstrument(); // Check whether we changed instrument key... if (pInstrument->map() == iMap && pInstrument->bank() == iBank && pInstrument->prog() == iProg) { // Just update tree item... m_pInstrumentListView->updateInstrument(pInstrument); } else { // Unmap old instance... instrument.unmapInstrument(); // Correct the position of the instrument in the model m_pInstrumentListView->resortInstrument(pInstrument); } stabilizeForm(); } void InstrumentListForm::deleteInstrument (void) { const QModelIndex& index = m_pInstrumentListView->currentIndex(); if (!index.isValid()) return; Instrument *pInstrument = static_cast (index.internalPointer()); if (pInstrument == nullptr) return; MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; // Prompt user if this is for real... Options *pOptions = pMainForm->options(); if (pOptions && pOptions->bConfirmRemove) { const QString& sTitle = tr("Warning"); const QString& sText = tr( "About to delete instrument map entry:\n\n" "%1\n\n" "Are you sure?") .arg(pInstrument->name()); #if 0 if (QMessageBox::warning(this, sTitle, sText, QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) return; #else QMessageBox mbox(this); mbox.setIcon(QMessageBox::Warning); mbox.setWindowTitle(sTitle); mbox.setText(sText); mbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); QCheckBox cbox(tr("Don't ask this again")); cbox.setChecked(false); cbox.blockSignals(true); mbox.addButton(&cbox, QMessageBox::ActionRole); if (mbox.exec() == QMessageBox::Cancel) return; if (cbox.isChecked()) pOptions->bConfirmRemove = false; #endif } pInstrument->unmapInstrument(); // Let the instrument vanish from the table model... m_pInstrumentListView->removeInstrument(pInstrument); stabilizeForm(); } // Update form actions enablement... void InstrumentListForm::stabilizeForm (void) { MainForm *pMainForm = MainForm::getInstance(); bool bEnabled = (pMainForm && pMainForm->client()); m_ui.newInstrumentAction->setEnabled(bEnabled); const QModelIndex& index = m_pInstrumentListView->currentIndex(); bEnabled = (bEnabled && index.isValid()); m_ui.editInstrumentAction->setEnabled(bEnabled); m_ui.deleteInstrumentAction->setEnabled(bEnabled); } // Context menu request. void InstrumentListForm::contextMenuEvent ( QContextMenuEvent *pContextMenuEvent ) { QMenu menu(this); menu.addAction(m_ui.newInstrumentAction); menu.addSeparator(); menu.addAction(m_ui.editInstrumentAction); menu.addAction(m_ui.deleteInstrumentAction); menu.addSeparator(); menu.addAction(m_ui.refreshInstrumentsAction); menu.exec(pContextMenuEvent->globalPos()); } } // namespace QSampler // end of qsamplerInstrumentListForm.cpp qsampler-1.0.0/src/PaxHeaders/qsamplerAbout.h0000644000000000000000000000013214634065603016200 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/qsamplerAbout.h0000644000175000001440000000254514634065603016176 0ustar00rncbcusers// qsamplerAbout.h // /**************************************************************************** Copyright (C) 2004-2024, rncbc aka Rui Nuno Capela. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #ifndef __qsamplerAbout_h #define __qsamplerAbout_h #include "config.h" #define QSAMPLER_TITLE PROJECT_TITLE #define QSAMPLER_SUBTITLE PROJECT_DESCRIPTION #define QSAMPLER_WEBSITE PROJECT_HOMEPAGE_URL #define QSAMPLER_COPYRIGHT PROJECT_COPYRIGHT #define QSAMPLER_COPYRIGHT2 PROJECT_COPYRIGHT2 #define QSAMPLER_DOMAIN PROJECT_DOMAIN #endif // __qsamplerAbout_h // end of qsamplerAbout.h qsampler-1.0.0/src/PaxHeaders/qsamplerInstrument.h0000644000000000000000000000013214634065603017276 xustar0030 mtime=1718643587.393448566 30 atime=1718643587.393448566 30 ctime=1718643587.393448566 qsampler-1.0.0/src/qsamplerInstrument.h0000644000175000001440000000506614634065603017275 0ustar00rncbcusers// qsamplerInstrument.h // /**************************************************************************** Copyright (C) 2004-2019, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #ifndef __qsamplerInstrument_h #define __qsamplerInstrument_h #include namespace QSampler { //------------------------------------------------------------------------- // QSampler::Instrument - MIDI instrument map structure. // class Instrument { public: // Constructor. Instrument(int iMap = 0, int iBank = -1, int iProg = -1); // Default destructor. ~Instrument(); // Instrument accessors. void setMap(int iMap); int map() const; void setBank(int iBank); int bank() const; void setProg(int iProg); int prog() const; void setName(const QString& sName); const QString& name() const; void setEngineName(const QString& sEngineName); const QString& engineName() const; void setInstrumentFile(const QString& sInstrumentFile); const QString& instrumentFile() const; const QString& instrumentName() const; void setInstrumentNr(int InstrumentNr); int instrumentNr() const; void setVolume(float fVolume); float volume() const; void setLoadMode(int iLoadMode); int loadMode() const; // Sync methods. bool getInstrument(); bool mapInstrument(); bool unmapInstrument(); // Instrument map names initialization... static QStringList getMapNames(); static QString getMapName(int iMidiMap); private: // Instance variables. int m_iMap; int m_iBank; int m_iProg; QString m_sName; QString m_sEngineName; QString m_sInstrumentFile; QString m_sInstrumentName; int m_iInstrumentNr; float m_fVolume; int m_iLoadMode; }; } // namespace QSampler #endif // __qsamplerInstrument_h // end of qsamplerInstrument.h qsampler-1.0.0/src/PaxHeaders/qsamplerUtilities.h0000644000000000000000000000013214634065603017101 xustar0030 mtime=1718643587.395448566 30 atime=1718643587.395448566 30 ctime=1718643587.395448566 qsampler-1.0.0/src/qsamplerUtilities.h0000644000175000001440000000272714634065603017101 0ustar00rncbcusers// qsamplerUtilities.h // /**************************************************************************** Copyright (C) 2004-2020, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, 2008 Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #ifndef __qsamplerUtilities_h #define __qsamplerUtilities_h #include namespace qsamplerUtilities { struct lscpVersion_t { int major; int minor; }; QByteArray lscpEscapePath(const QString& sPath); QString lscpEscapedPathToPosix(const char* sPath); QByteArray lscpEscapeText(const QString& sText); QString lscpEscapedTextToRaw(const char* sText); lscpVersion_t getRemoteLscpVersion(); } // namespace qsamplerUtilities #endif // __qsamplerUtilities_h qsampler-1.0.0/src/PaxHeaders/qsamplerDeviceStatusForm.cpp0000644000000000000000000000013214634065603020710 xustar0030 mtime=1718643587.393448566 30 atime=1718643587.393448566 30 ctime=1718643587.393448566 qsampler-1.0.0/src/qsamplerDeviceStatusForm.cpp0000644000175000001440000001567314634065603020714 0ustar00rncbcusers// qsamplerDeviceStatusForm.cpp // /**************************************************************************** Copyright (C) 2010-2020, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2008,2019 Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #include "qsamplerAbout.h" #include "qsamplerDeviceStatusForm.h" #include "qsamplerMainForm.h" #include #if QT_VERSION < QT_VERSION_CHECK(4, 5, 0) namespace Qt { const WindowFlags WindowCloseButtonHint = WindowFlags(0x08000000); } #endif namespace QSampler { //------------------------------------------------------------------------- // QSampler::MidiActivityLED -- Graphical indicator for MIDI activity. // // MIDI activity pixmap common resources. int MidiActivityLED::g_iMidiActivityRefCount = 0; QPixmap *MidiActivityLED::g_pMidiActivityLedOn = nullptr; QPixmap *MidiActivityLED::g_pMidiActivityLedOff = nullptr; MidiActivityLED::MidiActivityLED ( QString sText, QWidget *pParent ) : QLabel(sText, pParent) { if (++g_iMidiActivityRefCount == 1) { g_pMidiActivityLedOn = new QPixmap(":/images/ledon1.png"); g_pMidiActivityLedOff = new QPixmap(":/images/ledoff1.png"); } setPixmap(*g_pMidiActivityLedOff); #ifndef CONFIG_EVENT_DEVICE_MIDI setToolTip("MIDI Activity disabled"); #endif m_timer.setSingleShot(true); QObject::connect(&m_timer, SIGNAL(timeout()), SLOT(midiActivityLedOff()) ); } MidiActivityLED::~MidiActivityLED (void) { if (--g_iMidiActivityRefCount == 0) { if (g_pMidiActivityLedOn) delete g_pMidiActivityLedOn; g_pMidiActivityLedOn = nullptr; if (g_pMidiActivityLedOff) delete g_pMidiActivityLedOff; g_pMidiActivityLedOff = nullptr; } } void MidiActivityLED::midiActivityLedOn (void) { setPixmap(*g_pMidiActivityLedOn); m_timer.start(100); } void MidiActivityLED::midiActivityLedOff (void) { setPixmap(*g_pMidiActivityLedOff); } //------------------------------------------------------------------------- // QSampler::DeviceStatusForm -- Device status informations window. // std::map DeviceStatusForm::g_instances; DeviceStatusForm::DeviceStatusForm ( int DeviceID, QWidget *pParent, Qt::WindowFlags wflags ) : QWidget(pParent, wflags) { m_pDevice = new Device(Device::Midi, DeviceID); setLayout(new QGridLayout(/*this*/)); updateGUIPorts(); // build the GUI m_pVisibleAction = new QAction(this); m_pVisibleAction->setCheckable(true); m_pVisibleAction->setChecked(false); m_pVisibleAction->setText(m_pDevice->deviceName()); m_pVisibleAction->setToolTip( QString("MIDI Device ID: ") + QString::number(m_pDevice->deviceID()) ); QObject::connect(m_pVisibleAction, SIGNAL(toggled(bool)), SLOT(setVisible(bool)) ); setWindowTitle(tr("%1 Status").arg(m_pDevice->deviceName())); } void DeviceStatusForm::updateGUIPorts (void) { // refresh device informations m_pDevice->setDevice(m_pDevice->deviceType(), m_pDevice->deviceID()); DevicePortList ports = m_pDevice->ports(); // clear the GUI QGridLayout *pLayout = static_cast (layout()); for (int i = pLayout->count() - 1; i >= 0; --i) { QLayoutItem *pItem = pLayout->itemAt(i); if (pItem) { pLayout->removeItem(pItem); if (pItem->widget()) delete pItem->widget(); delete pItem; } } m_midiActivityLEDs.clear(); // rebuild the GUI for (int i = 0; i < ports.size(); ++i) { MidiActivityLED *pLED = new MidiActivityLED(); m_midiActivityLEDs.push_back(pLED); pLayout->addWidget(pLED, i, 0); QLabel *pLabel = new QLabel( m_pDevice->deviceTypeName() + ' ' + m_pDevice->driverName() + ' ' + ports[i]->portName()); pLayout->addWidget(pLabel, i, 1, Qt::AlignLeft); } } DeviceStatusForm::~DeviceStatusForm (void) { if (m_pDevice) delete m_pDevice; } QAction* DeviceStatusForm::visibleAction (void) { return m_pVisibleAction; } void DeviceStatusForm::closeEvent ( QCloseEvent *pCloseEvent ) { m_pVisibleAction->setChecked(false); pCloseEvent->accept(); } void DeviceStatusForm::midiArrived ( int iPort ) { if (uint(iPort) >= m_midiActivityLEDs.size()) return; m_midiActivityLEDs[iPort]->midiActivityLedOn(); } DeviceStatusForm *DeviceStatusForm::getInstance ( int iDeviceID ) { std::map::iterator iter = g_instances.find(iDeviceID); return ((iter != g_instances.end()) ? iter->second : nullptr); } const std::map& DeviceStatusForm::getInstances (void) { return g_instances; } void DeviceStatusForm::deleteAllInstances (void) { std::map::iterator iter = g_instances.begin(); for ( ; iter != g_instances.end(); ++iter) { iter->second->hide(); delete iter->second; } g_instances.clear(); } void DeviceStatusForm::onDevicesChanged (void) { MainForm* pMainForm = MainForm::getInstance(); if (pMainForm && pMainForm->client()) { std::set deviceIDs = Device::getDeviceIDs(pMainForm->client(), Device::Midi); // hide and delete status forms whose device has been destroyed std::map::iterator iter = g_instances.begin(); while (iter != g_instances.end()) { if (deviceIDs.find(iter->first) == deviceIDs.end()) { iter->second->hide(); delete iter->second; // postfix increment here to avoid iterator invalidation (crash) g_instances.erase(iter++); } else ++iter; } // create status forms for new devices std::set::iterator it = deviceIDs.begin(); for ( ; it != deviceIDs.end(); ++it) { if (g_instances.find(*it) == g_instances.end()) { // What style do we create these forms? Qt::WindowFlags wflags = Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint; Options *pOptions = pMainForm->options(); if (pOptions && pOptions->bKeepOnTop) wflags |= Qt::Tool; // Create the form, giving it the device id. DeviceStatusForm *pStatusForm = new DeviceStatusForm(*it, nullptr, wflags); g_instances[*it] = pStatusForm; } } } } void DeviceStatusForm::onDeviceChanged ( int iDeviceID ) { DeviceStatusForm *pStatusForm = DeviceStatusForm::getInstance(iDeviceID); if (pStatusForm) pStatusForm->updateGUIPorts(); } } // namespace QSampler // end of qsamplerDeviceStatusForm.cpp qsampler-1.0.0/src/PaxHeaders/config.h.cmake0000644000000000000000000000013214634065603015705 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/config.h.cmake0000644000175000001440000000646014634065603015703 0ustar00rncbcusers#ifndef CONFIG_H #define CONFIG_H /* Define to the title of this package. */ #cmakedefine PROJECT_TITLE "@PROJECT_TITLE@" /* Define to the name of this package. */ #cmakedefine PROJECT_NAME "@PROJECT_NAME@" /* Define to the version of this package. */ #cmakedefine PROJECT_VERSION "@PROJECT_VERSION@" /* Define to the description of this package. */ #cmakedefine PROJECT_DESCRIPTION "@PROJECT_DESCRIPTION@" /* Define to the homepage of this package. */ #cmakedefine PROJECT_HOMEPAGE_URL "@PROJECT_HOMEPAGE_URL@" /* Define to the copyright of this package. */ #cmakedefine PROJECT_COPYRIGHT "@PROJECT_COPYRIGHT@" #cmakedefine PROJECT_COPYRIGHT2 "@PROJECT_COPYRIGHT2@" /* Define to the domain of this package. */ #cmakedefine PROJECT_DOMAIN "@PROJECT_DOMAIN@" /* Default installation prefix. */ #cmakedefine CONFIG_PREFIX "@CONFIG_PREFIX@" /* Define to target installation dirs. */ #cmakedefine CONFIG_BINDIR "@CONFIG_BINDIR@" #cmakedefine CONFIG_LIBDIR "@CONFIG_LIBDIR@" #cmakedefine CONFIG_DATADIR "@CONFIG_DATADIR@" #cmakedefine CONFIG_MANDIR "@CONFIG_MANDIR@" /* Define if debugging is enabled. */ #cmakedefine CONFIG_DEBUG @CONFIG_DEBUG@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SIGNAL_H @HAVE_SIGNAL_H@ /* Define if round is available. */ #cmakedefine CONFIG_ROUND @CONFIG_ROUND@ /* Define if liblscp is available. */ #cmakedefine CONFIG_LIBLSCP @CONFIG_LIBLSCP@ /* Define if instrument_name is available. */ #cmakedefine CONFIG_INSTRUMENT_NAME @CONFIG_INSTRUMENT_NAME@ /* Define if mute/solo is available. */ #cmakedefine CONFIG_MUTE_SOLO @CONFIG_MUTE_SOLO@ /* Define if MIDI instrument mapping is available. */ #cmakedefine CONFIG_MIDI_INSTRUMENT @CONFIG_MIDI_INSTRUMENT@ /* Define if FX sends is available. */ #cmakedefine CONFIG_FXSEND @CONFIG_FXSEND@ /* Define if FX send level is available. */ #cmakedefine CONFIG_FXSEND_LEVEL @CONFIG_FXSEND_LEVEL@ /* Define if FX send rename is available. */ #cmakedefine CONFIG_FXSEND_RENAME @CONFIG_FXSEND_RENAME@ /* Define if audio_routing is an integer array. */ #cmakedefine CONFIG_AUDIO_ROUTING @CONFIG_AUDIO_ROUTING@ /* Define if global volume is available. */ #cmakedefine CONFIG_VOLUME @CONFIG_VOLUME@ /* Define if instrument editing is available. */ #cmakedefine CONFIG_EDIT_INSTRUMENT @CONFIG_EDIT_INSTRUMENT@ /* Define if LSCP CHANNEL_MIDI event support is available. */ #cmakedefine CONFIG_EVENT_CHANNEL_MIDI @CONFIG_EVENT_CHANNEL_MIDI@ /* Define if LSCP DEVICE_MIDI event support is available. */ #cmakedefine CONFIG_EVENT_DEVICE_MIDI @CONFIG_EVENT_DEVICE_MIDI@ /* Define if max. voices / streams is available. */ #cmakedefine CONFIG_MAX_VOICES @CONFIG_MAX_VOICES@ /* Define if libgig is available. */ #cmakedefine CONFIG_LIBGIG @CONFIG_LIBGIG@ /* Define if libgig provides gig::File::SetAutoLoad() method. */ #cmakedefine CONFIG_LIBGIG_SETAUTOLOAD @CONFIG_LIBGIG_SETAUTOLOAD@ /* Define if round is available. */ #cmakedefine CONFIG_ROUND @CONFIG_ROUND@ /* Define if libgig/SF.h is available. */ #cmakedefine CONFIG_LIBGIG_SF2 @CONFIG_LIBGIG_SF2@ /* Define if unique/single instance is enabled. */ #cmakedefine CONFIG_XUNIQUE @CONFIG_XUNIQUE@ /* Define if debugger stack-trace is enabled. */ #cmakedefine CONFIG_STACKTRACE @CONFIG_STACKTRACE@ /* Define if Wayland is supported */ #cmakedefine CONFIG_WAYLAND @CONFIG_WAYLAND@ #endif /* CONFIG_H */ qsampler-1.0.0/src/PaxHeaders/qsamplerInstrumentList.h0000644000000000000000000000013214634065603020132 xustar0030 mtime=1718643587.393448566 30 atime=1718643587.393448566 30 ctime=1718643587.393448566 qsampler-1.0.0/src/qsamplerInstrumentList.h0000644000175000001440000000651214634065603020126 0ustar00rncbcusers// qsamplerInstrumentList.h // /**************************************************************************** Copyright (C) 2003-2019, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *****************************************************************************/ #ifndef __qsamplerInstrumentList_h #define __qsamplerInstrumentList_h #include namespace QSampler { class Instrument; //------------------------------------------------------------------------- // QSampler:InstrumentListModel - data model for MIDI prog mappings // class InstrumentListModel : public QAbstractItemModel { Q_OBJECT public: // Constructor. InstrumentListModel(QObject *pParent = nullptr); // Destructor. ~InstrumentListModel(); // Overridden methods from subclass(es) int rowCount(const QModelIndex& parent) const; int columnCount(const QModelIndex& parent) const; QVariant data(const QModelIndex& index, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; // Map selector. void setMidiMap(int iMidiMap); int midiMap() const; // Own methods const Instrument *addInstrument(int iMap, int iBank, int iProg); void removeInstrument(Instrument *pInstrument); void updateInstrument(Instrument *pInstrument); void resortInstrument(Instrument *pInstrument); // General reloader. void refresh(); // Make the following method public void beginReset(); void endReset(); // Map clear. void clear(); protected: QModelIndex index(int row, int col, const QModelIndex& parent) const; QModelIndex parent(const QModelIndex& child) const; private: typedef QList InstrumentList; typedef QMap InstrumentMap; InstrumentMap m_instruments; // Current map selection. int m_iMidiMap; }; //------------------------------------------------------------------------- // QSampler::InstrumentListView - list view for MIDI prog mappings // class InstrumentListView : public QTreeView { Q_OBJECT public: // Constructor. InstrumentListView(QWidget *pParent = nullptr); // Destructor. ~InstrumentListView(); // Map selector. void setMidiMap(int iMidiMap); int midiMap() const; // Own methods const Instrument *addInstrument(int iMap, int iBank, int iProg); void removeInstrument(Instrument *pInstrument); void updateInstrument(Instrument *pInstrument); void resortInstrument(Instrument *pInstrument); // General reloader. void refresh(); private: // Instance variables. InstrumentListModel *m_pListModel; }; } // namespace QSampler #endif // __qsamplerInstrumentList_h // end of qsamplerInstrumentList.h qsampler-1.0.0/src/PaxHeaders/qsamplerInstrumentForm.ui0000644000000000000000000000013214634065603020310 xustar0030 mtime=1718643587.393448566 30 atime=1718643587.393448566 30 ctime=1718643587.393448566 qsampler-1.0.0/src/qsamplerInstrumentForm.ui0000644000175000001440000002674314634065603020314 0ustar00rncbcusers rncbc aka Rui Nuno Capela qsampler - A LinuxSampler Qt GUI Interface. Copyright (C) 2004-2021, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. qsamplerInstrumentForm 0 0 452 226 Qt::StrongFocus Instrument :/images/qsamplerInstrument.png 4 4 0 4 Engine name &Engine: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false EngineNameComboBox &Prog: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false ProgSpinBox Program (0-127) 128 1 Vol&ume: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false VolumeSpinBox &Map: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false MapComboBox &Bank: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false BankSpinBox Bank (0-16383) 16383 320 0 Instrument filename true M&ode: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false LoadModeComboBox Qt::Horizontal QSizePolicy::Expanding 119 8 &Filename: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false InstrumentFileComboBox &Name: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false NameLineEdit Instrument map &Instrument: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false InstrumentNrComboBox 320 0 Instrument name Volume (%) % 100 Name Load mode Default On Demand On Demand Hold Persistent 24 24 26 26 Qt::TabFocus Browse for instrument filename :/images/fileOpen.png Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok MapComboBox BankSpinBox ProgSpinBox NameLineEdit EngineNameComboBox InstrumentFileComboBox InstrumentFileToolButton InstrumentNrComboBox VolumeSpinBox LoadModeComboBox DialogButtonBox qsampler-1.0.0/src/PaxHeaders/qsamplerChannelStrip.ui0000644000000000000000000000013214634065603017706 xustar0030 mtime=1718643587.392448566 30 atime=1718643587.392448566 30 ctime=1718643587.392448566 qsampler-1.0.0/src/qsamplerChannelStrip.ui0000644000175000001440000003035014634065603017677 0ustar00rncbcusers rncbc aka Rui Nuno Capela qsampler - A LinuxSampler Qt GUI Interface. Copyright (C) 2004-2021, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, 2008, 2014 Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. qsamplerChannelStrip 0 0 640 64 0 0 Qt::StrongFocus Channel :/images/qsamplerChannel.png 100 22 120 32 Channel setup &Channel :/images/qsamplerChannel.png 0 0 240 48 320 64 true QFrame::StyledPanel QFrame::Sunken 2 0 -- 0 0 20 0 MIDI port / channel -- / -- Qt::AlignCenter false 20 0 Instrument load status -- Qt::AlignCenter false 0 0 16 16 16 16 16 16 MIDI activity QFrame::NoFrame QFrame::Plain Qt::AlignCenter Instrument name text-align: left; margin: 0px; -- true 48 32 Channel mute &Mute true 48 32 Channel solo &Solo true 100 0 Channel volume 100 Qt::Horizontal QSlider::TicksBothSides 10 60 0 120 24 Channel volume % 100 48 32 Edit Channel's Effect Settings &FX 48 32 Edit channel's instrument &Edit Qt::Horizontal QSizePolicy::Preferred 8 22 0 0 64 22 Least buffer fill stream usage (%) Qt::Horizontal 48 22 64 32 Stream / Voice count true QFrame::StyledPanel QFrame::Sunken --/-- Qt::AlignCenter false Qt::Horizontal QSizePolicy::Preferred 8 22 ChannelSetupPushButton ChannelMutePushButton ChannelSoloPushButton ChannelVolumeSlider ChannelVolumeSpinBox ChannelFxPushButton ChannelEditPushButton qsampler-1.0.0/src/PaxHeaders/qsamplerChannelFxForm.ui0000644000000000000000000000013214634065603020006 xustar0030 mtime=1718643587.392448566 30 atime=1718643587.392448566 30 ctime=1718643587.392448566 qsampler-1.0.0/src/qsamplerChannelFxForm.ui0000644000175000001440000001552314634065603020004 0ustar00rncbcusers Christian Schoenebeck Copyright (C) 2010-2021, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2008, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. qsamplerChannelFxForm 0 0 518 370 Channel Effects FX Send Selection 0 0 true Qt::Horizontal 40 20 Creates a new FX Send. You have to select 'Apply' afterwards to actually create it on sampler side. Create :/images/itemNew.png Schedules the selected FX send for deletion. You have to select 'Apply' afterwards to actually destroy it on sampler side. Destroy :/images/formRemove.png 0 0 FX Send's Parameters Send Depth MIDI Controller: Current Depth: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter % 300 0 0 Audio Routing Qt::Horizontal QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok|QDialogButtonBox::Reset buttonBox accepted() qsamplerChannelFxForm accept() 248 254 157 274 buttonBox rejected() qsamplerChannelFxForm reject() 316 260 286 274 qsampler-1.0.0/src/PaxHeaders/qsamplerChannelStrip.h0000644000000000000000000000013214634065603017520 xustar0030 mtime=1718643587.392448566 30 atime=1718643587.392448566 30 ctime=1718643587.392448566 qsampler-1.0.0/src/qsamplerChannelStrip.h0000644000175000001440000000600114634065603017505 0ustar00rncbcusers// qsamplerChannelStrip.h // /**************************************************************************** Copyright (C) 2004-2021, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, 2008, 2014 Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #ifndef __qsamplerChannelStrip_h #define __qsamplerChannelStrip_h #include "ui_qsamplerChannelStrip.h" #include "qsamplerChannel.h" class QDragEnterEvent; class QTimer; class QMenu; namespace QSampler { //------------------------------------------------------------------------- // QSampler::ChannelStrip -- Channel strip form interface. // class ChannelStrip : public QWidget { Q_OBJECT public: ChannelStrip( QWidget *pParent = nullptr, Qt::WindowFlags wflags = Qt::WindowFlags()); ~ChannelStrip(); void setup(Channel *pChannel); Channel *channel() const; void setDisplayFont(const QFont& font); QFont displayFont() const; void setDisplayEffect(bool bDisplayEffect); void setMaxVolume(int iMaxVolume); bool updateInstrumentName(bool bForce); bool updateChannelVolume(); bool updateChannelInfo(); bool updateChannelUsage(); void resetErrorCount(); // Channel strip activation/selection. void setSelected(bool bSelected); bool isSelected() const; signals: void channelChanged(ChannelStrip*); public slots: bool channelSetup(); bool channelMute(bool bMute); bool channelSolo(bool bSolo); void channelEdit(); bool channelFxEdit(); bool channelReset(); void volumeChanged(int iVolume); void midiActivityLedOn(); protected: void dragEnterEvent(QDragEnterEvent* pDragEnterEvent); void dropEvent(QDropEvent* pDropEvent); void contextMenuEvent(QContextMenuEvent* pEvent); protected slots: void midiActivityLedOff(); void instrumentListPopupItemClicked(QAction* action); private: Ui::qsamplerChannelStrip m_ui; Channel *m_pChannel; int m_iDirtyChange; int m_iErrorCount; QMenu* m_instrumentListPopupMenu; QTimer *m_pMidiActivityTimer; // MIDI activity pixmap common resources. static int g_iMidiActivityRefCount; static QPixmap *g_pMidiActivityLedOn; static QPixmap *g_pMidiActivityLedOff; // Channel strip activation/selection. static ChannelStrip *g_pSelectedStrip; }; } // namespace QSampler #endif // __qsamplerChannelStrip_h // end of qsamplerChannelStrip.h qsampler-1.0.0/src/PaxHeaders/qsamplerDeviceForm.cpp0000644000000000000000000000013214634065603017504 xustar0030 mtime=1718643587.393448566 30 atime=1718643587.393448566 30 ctime=1718643587.393448566 qsampler-1.0.0/src/qsamplerDeviceForm.cpp0000644000175000001440000005013314634065603017476 0ustar00rncbcusers// qsamplerDeviceForm.cpp // /**************************************************************************** Copyright (C) 2004-2020, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, 2008 Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #include "qsamplerDeviceForm.h" #include "qsamplerAbout.h" #include "qsamplerMainForm.h" #include #include #include namespace QSampler { //------------------------------------------------------------------------- // QSampler::DeviceForm -- Device form implementation. // DeviceForm::DeviceForm ( QWidget *pParent, Qt::WindowFlags wflags ) : QDialog(pParent, wflags) { m_ui.setupUi(this); // Initialize locals. m_iDirtySetup = 0; m_iDirtyCount = 0; m_bNewDevice = false; m_deviceType = Device::None; m_pAudioItems = nullptr; m_pMidiItems = nullptr; // No exclusive mode as default. m_deviceTypeMode = Device::None; m_ui.DeviceListView->header()->hide(); int iRowHeight = m_ui.DeviceParamTable->fontMetrics().height() + 4; m_ui.DeviceParamTable->verticalHeader()->setDefaultSectionSize(iRowHeight); m_ui.DevicePortParamTable->verticalHeader()->setDefaultSectionSize(iRowHeight); m_ui.DeviceParamTable->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft); m_ui.DevicePortParamTable->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft); m_ui.DeviceParamTable->setModel(&m_deviceParamModel); m_ui.DeviceParamTable->setItemDelegate(&m_deviceParamDelegate); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) m_ui.DeviceParamTable->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch); #else m_ui.DeviceParamTable->horizontalHeader()->setResizeMode(2, QHeaderView::Stretch); #endif m_ui.DeviceParamTable->verticalHeader()->hide(); m_ui.DevicePortParamTable->setModel(&m_devicePortParamModel); m_ui.DevicePortParamTable->setItemDelegate(&m_devicePortParamDelegate); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) m_ui.DevicePortParamTable->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch); #else m_ui.DevicePortParamTable->horizontalHeader()->setResizeMode(2, QHeaderView::Stretch); #endif m_ui.DevicePortParamTable->verticalHeader()->hide(); // Initial contents. refreshDevices(); // Try to restore normal window positioning. adjustSize(); QObject::connect(m_ui.DeviceListView, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(selectDevice())); QObject::connect(m_ui.DeviceListView, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(deviceListViewContextMenu(const QPoint&))); QObject::connect(m_ui.RefreshDevicesPushButton, SIGNAL(clicked()), SLOT(refreshDevices())); QObject::connect(m_ui.DriverNameComboBox, SIGNAL(activated(int)), SLOT(selectDriver(int))); QObject::connect(m_ui.DevicePortComboBox, SIGNAL(activated(int)), SLOT(selectDevicePort(int))); QObject::connect(m_ui.CreateDevicePushButton, SIGNAL(clicked()), SLOT(createDevice())); QObject::connect(m_ui.DeleteDevicePushButton, SIGNAL(clicked()), SLOT(deleteDevice())); QObject::connect(m_ui.ClosePushButton, SIGNAL(clicked()), SLOT(close())); QObject::connect(&m_deviceParamModel, SIGNAL(modelReset()), SLOT(updateCellRenderers())); QObject::connect(&m_deviceParamModel, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), SLOT(updateCellRenderers(const QModelIndex&, const QModelIndex&))); QObject::connect(&m_devicePortParamModel, SIGNAL(modelReset()), SLOT(updatePortCellRenderers())); QObject::connect(&m_devicePortParamModel, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), SLOT(updatePortCellRenderers(const QModelIndex&, const QModelIndex&))); } DeviceForm::~DeviceForm (void) { } // Notify our parent that we're emerging. void DeviceForm::showEvent ( QShowEvent *pShowEvent ) { MainForm* pMainForm = MainForm::getInstance(); if (pMainForm) pMainForm->stabilizeForm(); QWidget::showEvent(pShowEvent); refreshDevices(); } // Notify our parent that we're closing. void DeviceForm::hideEvent ( QHideEvent *pHideEvent ) { QWidget::hideEvent(pHideEvent); MainForm *pMainForm = MainForm::getInstance(); if (pMainForm) pMainForm->stabilizeForm(); // Signal special whether we changed the device set. if (m_iDirtyCount > 0) { m_iDirtyCount = 0; emit devicesChanged(); } } // Set device type spacial exclusive mode. void DeviceForm::setDeviceTypeMode ( Device::DeviceType deviceTypeMode ) { // If it has not changed, do nothing. if (m_deviceTypeMode == deviceTypeMode) return; m_deviceTypeMode = deviceTypeMode; // OK. Do a whole refresh around. refreshDevices(); } // Device driver name setup formal initializer. void DeviceForm::setDriverName ( const QString& sDriverName ) { if (m_ui.DriverNameComboBox->findText(sDriverName) < 0) m_ui.DriverNameComboBox->insertItem(0, sDriverName); m_ui.DriverNameComboBox->setItemText( m_ui.DriverNameComboBox->currentIndex(), sDriverName); } // Set current selected device by type and id. void DeviceForm::setDevice ( Device *pDevice ) { // In case no device is given... Device::DeviceType deviceType = m_deviceTypeMode; if (pDevice) deviceType = pDevice->deviceType(); // Get the device view root item... DeviceItem *pRootItem = nullptr; switch (deviceType) { case Device::Audio: pRootItem = m_pAudioItems; break; case Device::Midi: pRootItem = m_pMidiItems; break; case Device::None: break; } // Is the root present? if (pRootItem == nullptr) return; // So there's no device huh? if (pDevice == nullptr) { m_ui.DeviceListView->setCurrentItem(pRootItem); return; } // For each child, test for identity... for (int i = 0; i < pRootItem->childCount(); i++) { DeviceItem* pDeviceItem = (DeviceItem*) pRootItem->child(i); // If identities match, select as current device item. if (pDeviceItem->device().deviceID() == pDevice->deviceID()) { pDeviceItem->setSelected(true); break; } } } // Create a new device from current table view. void DeviceForm::createDevice (void) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; QTreeWidgetItem *pItem = m_ui.DeviceListView->currentItem(); if (pItem == nullptr || pItem->type() != QSAMPLER_DEVICE_ITEM) return; // About a brand new device instance... Device device(((DeviceItem *) pItem)->device()); if (device.createDevice()) { // Now it depends on the device type... DeviceItem *pRootItem = nullptr; switch (device.deviceType()) { case Device::Audio: pRootItem = m_pAudioItems; break; case Device::Midi: pRootItem = m_pMidiItems; break; case Device::None: break; } // Append the new device item. DeviceItem *pDeviceItem = new DeviceItem(pRootItem, device.deviceType(), device.deviceID()); // Just make it the new selection... pDeviceItem->setSelected(true); // Main session should be marked dirty. pMainForm->sessionDirty(); m_iDirtyCount++; } } // Delete current device in table view. void DeviceForm::deleteDevice (void) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; QTreeWidgetItem* pItem = m_ui.DeviceListView->currentItem(); if (pItem == nullptr || pItem->type() != QSAMPLER_DEVICE_ITEM) return; Device& device = ((DeviceItem *) pItem)->device(); // Prompt user if this is for real... Options *pOptions = pMainForm->options(); if (pOptions && pOptions->bConfirmRemove) { const QString& sTitle = tr("Warning"); const QString& sText = tr( "About to delete device:\n\n" "%1\n\n" "Are you sure?") .arg(device.deviceName()); #if 0 if (QMessageBox::warning(this, sTitle, sText, QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) return; #else QMessageBox mbox(this); mbox.setIcon(QMessageBox::Warning); mbox.setWindowTitle(sTitle); mbox.setText(sText); mbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); QCheckBox cbox(tr("Don't ask this again")); cbox.setChecked(false); cbox.blockSignals(true); mbox.addButton(&cbox, QMessageBox::ActionRole); if (mbox.exec() == QMessageBox::Cancel) return; if (cbox.isChecked()) pOptions->bConfirmRemove = false; #endif } // Go and destroy... if (device.deleteDevice()) { // Remove it from the device view... delete pItem; // Main session should be marked dirty. pMainForm->sessionDirty(); m_iDirtyCount++; } } // Refresh all device list and views. void DeviceForm::refreshDevices (void) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; // Avoid nested changes. m_iDirtySetup++; // // (Re)Load complete device configuration data ... // m_pAudioItems = nullptr; m_pMidiItems = nullptr; m_ui.DeviceListView->clear(); if (pMainForm->client()) { int *piDeviceIDs; // Grab and pop Audio devices... if (m_deviceTypeMode == Device::None || m_deviceTypeMode == Device::Audio) { m_pAudioItems = new DeviceItem(m_ui.DeviceListView, Device::Audio); } if (m_pAudioItems) { piDeviceIDs = Device::getDevices(pMainForm->client(), Device::Audio); for (int i = 0; piDeviceIDs && piDeviceIDs[i] >= 0; i++) { new DeviceItem(m_pAudioItems, Device::Audio, piDeviceIDs[i]); } m_pAudioItems->setExpanded(true); } // Grab and pop MIDI devices... if (m_deviceTypeMode == Device::None || m_deviceTypeMode == Device::Midi) { m_pMidiItems = new DeviceItem(m_ui.DeviceListView, Device::Midi); } if (m_pMidiItems) { piDeviceIDs = Device::getDevices(pMainForm->client(), Device::Midi); for (int i = 0; piDeviceIDs && piDeviceIDs[i] >= 0; i++) { new DeviceItem(m_pMidiItems, Device::Midi, piDeviceIDs[i]); } m_pMidiItems->setExpanded(true); } } // Done. m_iDirtySetup--; // Show something. selectDevice(); } // Driver selection slot. void DeviceForm::selectDriver ( int iDriver ) { if (m_iDirtySetup > 0) return; // // Driver name has changed for a new device... // const QString& sDriverName = m_ui.DriverNameComboBox->itemText(iDriver); if (sDriverName.isEmpty()) return; QTreeWidgetItem* pItem = m_ui.DeviceListView->currentItem(); if (pItem == nullptr || pItem->type() != QSAMPLER_DEVICE_ITEM) return; Device& device = ((DeviceItem *) pItem)->device(); // Driver change is only valid for scratch devices... if (m_bNewDevice) { m_iDirtySetup++; device.setDriver(sDriverName); m_deviceParamModel.refresh(&device, m_bNewDevice); m_iDirtySetup--; // Done. stabilizeForm(); } } // Device selection slot. void DeviceForm::selectDevice () { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; if (m_iDirtySetup > 0) return; // // Device selection has changed... // QTreeWidgetItem* pItem = m_ui.DeviceListView->currentItem(); if (pItem == nullptr || pItem->type() != QSAMPLER_DEVICE_ITEM) { m_deviceType = Device::None; m_ui.DeviceNameTextLabel->setText(QString()); m_deviceParamModel.clear(); m_ui.DevicePortComboBox->clear(); m_devicePortParamModel.clear(); m_ui.DevicePortTextLabel->setEnabled(false); m_ui.DevicePortComboBox->setEnabled(false); m_ui.DevicePortParamTable->setEnabled(false); stabilizeForm(); return; } Device& device = ((DeviceItem *) pItem)->device(); m_iDirtySetup++; // Flag whether this is a new device. m_bNewDevice = (device.deviceID() < 0); // Fill the device/driver heading... m_ui.DeviceNameTextLabel->setText(device.deviceName()); // The driver combobox is only rebuilt if device type has changed... if (device.deviceType() != m_deviceType) { m_ui.DriverNameComboBox->clear(); m_ui.DriverNameComboBox->insertItems(0, Device::getDrivers(pMainForm->client(), device.deviceType())); m_deviceType = device.deviceType(); } // Do we need a driver name? if (m_bNewDevice || device.driverName().isEmpty()) device.setDriver(m_ui.DriverNameComboBox->currentText()); setDriverName(device.driverName()); m_ui.DriverNameTextLabel->setEnabled(m_bNewDevice); m_ui.DriverNameComboBox->setEnabled(m_bNewDevice); // Fill the device parameter table... m_deviceParamModel.refresh(&device, m_bNewDevice); // And now the device port/channel parameter table... switch (device.deviceType()) { case Device::Audio: m_ui.DevicePortTextLabel->setText(tr("Ch&annel:")); break; case Device::Midi: m_ui.DevicePortTextLabel->setText(tr("P&ort:")); break; case Device::None: break; } m_ui.DevicePortComboBox->clear(); m_devicePortParamModel.clear(); if (m_bNewDevice) { m_ui.DevicePortTextLabel->setEnabled(false); m_ui.DevicePortComboBox->setEnabled(false); m_ui.DevicePortParamTable->setEnabled(false); } else { QPixmap pixmap; switch (device.deviceType()) { case Device::Audio: pixmap = QPixmap(":/images/audio2.png"); break; case Device::Midi: pixmap = QPixmap(":/images/midi2.png"); break; case Device::None: break; } DevicePortList& ports = device.ports(); QListIterator iter(ports); while (iter.hasNext()) { DevicePort *pPort = iter.next(); m_ui.DevicePortComboBox->addItem(pixmap, device.deviceTypeName() + ' ' + device.driverName() + ' ' + pPort->portName()); } bool bEnabled = (ports.count() > 0); m_ui.DevicePortTextLabel->setEnabled(bEnabled); m_ui.DevicePortComboBox->setEnabled(bEnabled); m_ui.DevicePortParamTable->setEnabled(bEnabled); } // Done. m_iDirtySetup--; // Make the device port/channel selection effective. selectDevicePort(m_ui.DevicePortComboBox->currentIndex()); } // Device port/channel selection slot. void DeviceForm::selectDevicePort ( int iPort ) { if (m_iDirtySetup > 0) return; // // Device port/channel selection has changed... // QTreeWidgetItem* pItem = m_ui.DeviceListView->currentItem(); if (pItem == nullptr || pItem->type() != QSAMPLER_DEVICE_ITEM) return; Device& device = ((DeviceItem *) pItem)->device(); DevicePort *pPort = nullptr; if (iPort >= 0 && iPort < device.ports().count()) pPort = device.ports().at(iPort); if (pPort) { m_iDirtySetup++; m_devicePortParamModel.refresh(pPort, false); m_iDirtySetup--; } // Done. stabilizeForm(); } // Device parameter value change slot. void DeviceForm::changeDeviceParam ( int iRow, int iCol ) { if (m_iDirtySetup > 0) return; if (iRow < 0 || iCol < 0) return; // // Device parameter change... // /* we do that in the model class now ... QTreeWidgetItem* pItem = m_ui.DeviceListView->currentItem(); if (pItem == nullptr || pItem->type() != QSAMPLER_DEVICE_ITEM) return; Device& device = ((DeviceItem *) pItem)->device(); // Table 1st column has the parameter name; //const QString sParam = m_ui.DeviceParamTable->text(iRow, 0); //const QString sValue = m_ui.DeviceParamTable->text(iRow, iCol); const QString sParam = m_deviceParamModel.data(m_deviceParamModel.index(iRow, 0), Qt::DisplayRole).value().name; const QString sValue = m_deviceParamModel.data(m_deviceParamModel.index(iRow, iCol), Qt::DisplayRole).value().param.value; // Set the local device parameter value. if (device.setParam(sParam, sValue)) { selectDevice(); } else { stabilizeForm(); } */ // Main session should be dirtier... MainForm *pMainForm = MainForm::getInstance(); if (pMainForm) pMainForm->sessionDirty(); } // Device port/channel parameter value change slot. void DeviceForm::changeDevicePortParam ( int iRow, int iCol ) { if (m_iDirtySetup > 0) return; if (iRow < 0 || iCol < 0) return; // // Device port/channel parameter change... // /* we do that in the model class now ... QTreeWidgetItem* pItem = m_ui.DeviceListView->currentItem(); if (pItem == nullptr || pItem->type() != QSAMPLER_DEVICE_ITEM) return; Device& device = ((DeviceItem *) pItem)->device(); int iPort = m_ui.DevicePortComboBox->currentIndex(); DevicePort *pPort = nullptr; if (iPort >= 0 && iPort < device.ports().count()) pPort = device.ports().at(iPort); if (pPort == nullptr) return; // Table 1st column has the parameter name; //const QString sParam = m_ui.DevicePortParamTable->text(iRow, 0); //const QString sValue = m_ui.DevicePortParamTable->text(iRow, iCol); const QString sParam = m_devicePortParamModel.data(m_devicePortParamModel.index(iRow, 0), Qt::DisplayRole).value().name; const QString sValue = m_devicePortParamModel.data(m_devicePortParamModel.index(iRow, iCol), Qt::DisplayRole).value().param.value; // Set the local device port/channel parameter value. pPort->setParam(sParam, sValue); */ // Done. stabilizeForm(); // Main session should be dirtier... MainForm* pMainForm = MainForm::getInstance(); if (pMainForm) pMainForm->sessionDirty(); } // Device list view context menu handler. void DeviceForm::deviceListViewContextMenu ( const QPoint& pos ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; QTreeWidgetItem* pItem = m_ui.DeviceListView->itemAt(pos); if (pItem == nullptr) return; // Build the device context menu... QMenu menu(this); QAction *pAction; bool bClient = (pMainForm->client() != nullptr); bool bEnabled = (pItem != nullptr); pAction = menu.addAction( QIcon(":/images/deviceCreate.png"), tr("&Create device"), this, SLOT(createDevice())); pAction->setEnabled(bEnabled || (bClient && m_bNewDevice)); pAction = menu.addAction( QIcon(":/images/deviceDelete.png"), tr("&Delete device"), this, SLOT(deleteDevice())); pAction->setEnabled(bEnabled && !m_bNewDevice); menu.addSeparator(); pAction = menu.addAction( QIcon(":/images/formRefresh.png"), tr("&Refresh"), this, SLOT(refreshDevices())); pAction->setEnabled(bClient); menu.exec(pos); } // Stabilize current form state. void DeviceForm::stabilizeForm (void) { MainForm* pMainForm = MainForm::getInstance(); QTreeWidgetItem* pItem = m_ui.DeviceListView->currentItem(); bool bClient = (pMainForm && pMainForm->client() != nullptr); bool bEnabled = (pItem != nullptr); m_ui.DeviceNameTextLabel->setEnabled(bEnabled && !m_bNewDevice); m_ui.DriverNameTextLabel->setEnabled(bEnabled && m_bNewDevice); m_ui.DriverNameComboBox->setEnabled(bEnabled && m_bNewDevice); m_ui.DeviceParamTable->setEnabled(bEnabled); m_ui.RefreshDevicesPushButton->setEnabled(bClient); m_ui.CreateDevicePushButton->setEnabled(bEnabled || (bClient && m_bNewDevice)); m_ui.DeleteDevicePushButton->setEnabled(bEnabled && !m_bNewDevice); } void DeviceForm::updateCellRenderers (void) { const int rows = m_deviceParamModel.rowCount(); const int cols = m_deviceParamModel.columnCount(); updateCellRenderers( m_deviceParamModel.index(0, 0), m_deviceParamModel.index(rows - 1, cols - 1)); } void DeviceForm::updateCellRenderers ( const QModelIndex& topLeft, const QModelIndex& bottomRight ) { for (int r = topLeft.row(); r <= bottomRight.row(); r++) { for (int c = topLeft.column(); c <= bottomRight.column(); c++) { const QModelIndex index = m_deviceParamModel.index(r, c); m_ui.DeviceParamTable->openPersistentEditor(index); } } } void DeviceForm::updatePortCellRenderers (void) { const int rows = m_devicePortParamModel.rowCount(); const int cols = m_devicePortParamModel.columnCount(); updatePortCellRenderers( m_devicePortParamModel.index(0, 0), m_devicePortParamModel.index(rows - 1, cols - 1)); } void DeviceForm::updatePortCellRenderers ( const QModelIndex& topLeft, const QModelIndex& bottomRight ) { for (int r = topLeft.row(); r <= bottomRight.row(); r++) { for (int c = topLeft.column(); c <= bottomRight.column(); c++) { const QModelIndex index = m_devicePortParamModel.index(r, c); m_ui.DevicePortParamTable->openPersistentEditor(index); } } } } // namespace QSampler // end of qsamplerDeviceForm.cpp qsampler-1.0.0/src/PaxHeaders/qsamplerChannelFxForm.cpp0000644000000000000000000000013214634065603020153 xustar0030 mtime=1718643587.392448566 30 atime=1718643587.392448566 30 ctime=1718643587.392448566 qsampler-1.0.0/src/qsamplerChannelFxForm.cpp0000644000175000001440000002674714634065603020163 0ustar00rncbcusers// qsamplerChannelFxForm.cpp // /**************************************************************************** Copyright (C) 2010-2021, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2008, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #include "qsamplerAbout.h" #include "qsamplerChannelFxForm.h" #include "qsamplerFxSendsModel.h" // let's not reinvent the wheel for audio routing #include "qsamplerChannel.h" #include #include #include #include #include namespace { // private namespace static const char* _midiControllerName(int iMidiCtrl) { switch (iMidiCtrl) { case 0: return "Bank select MSB"; case 1: return "Modulation MSB"; case 2: return "Breath Controller"; case 4: return "Foot Controller MSB"; case 5: return "Portamento Time MSB"; case 6: return "(N)RPN Data Byte"; case 7: return "Main Volume"; case 8: return "Balance"; case 10: return "Panorama"; case 11: return "Expression"; case 12: return "Effect Control 1"; case 13: return "Effect Control 2"; case 16: return "General Purpose Controller 1"; case 17: return "General Purpose Controller 2"; case 18: return "General Purpose Controller 3"; case 19: return "General Purpose Controller 4"; case 32: return "Bank select LSB"; case 63: return "LSB for Controllers 0?31"; case 64: return "Hold 1"; case 65: return "Portamento"; case 66: return "Sostenuto"; case 67: return "Soft Pedal"; case 68: return "Legato Footswitch"; case 69: return "Hold 2"; case 70: return "Sound Controller 1 (Sound Variation)"; case 71: return "Sound Controller 2 (Harmonic Content)"; case 72: return "Sound Controller 3 (Release Time)"; case 73: return "Sound Controller 4 (Attack Time)"; case 74: return "Sound Controller 5 (Brightness)"; case 75: return "Sound Controller 6"; case 76: return "Sound Controller 7"; case 77: return "Sound Controller 8"; case 78: return "Sound Controller 9"; case 79: return "Sound Controller 10"; case 80: return "General Purpose 5"; case 81: return "General Purpose 6"; case 82: return "General Purpose 7"; case 83: return "General Purpose 8"; case 84: return "Portamento Control"; case 91: return "Effects 1 Depth"; case 92: return "Effects 2 Depth"; case 93: return "Effects 3 Depth"; case 94: return "Effects 4 Depth"; case 95: return "Effects 5 Depth"; case 96: return "Data Increment (N)RPN"; case 97: return "Data Decrement (N)RPN"; case 98: return "NRPN LSB"; case 99: return "NRPN MSB"; case 100: return "RPN LSB"; case 101: return "RPN MSB"; case 120: return "All Sounds Off"; case 121: return "Controller Reset"; case 122: return "Local Control on/off"; case 123: return "All Notes Off"; case 124: return "Omni Off"; case 125: return "Omni On"; case 126: return "Mono On / Poly Off"; case 127: return "Poly On / Mono Off"; default: return ""; } } } // private namespace namespace QSampler { ChannelFxForm::ChannelFxForm ( Channel *pSamplerChannel, QWidget *pParent ) : QDialog(pParent) { m_ui.setupUi(this); m_pSamplerChannel = pSamplerChannel; m_pAudioDevice = nullptr; FxSendsModel* pModel = new FxSendsModel(m_pSamplerChannel->channelID(), m_ui.SendsListView); m_ui.SendsListView->setModel(pModel); m_ui.SendsListView->setSelectionRectVisible(true); const int iRowHeight = m_ui.audioRoutingTable->fontMetrics().height() + 4; m_ui.audioRoutingTable->verticalHeader()->setDefaultSectionSize(iRowHeight); m_ui.audioRoutingTable->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft); ChannelRoutingModel* pRoutingModel = new ChannelRoutingModel(m_ui.audioRoutingTable); m_ui.audioRoutingTable->setModel(pRoutingModel); ChannelRoutingDelegate* pRoutingDelegate = new ChannelRoutingDelegate(m_ui.audioRoutingTable); m_ui.audioRoutingTable->setItemDelegate(pRoutingDelegate); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) m_ui.audioRoutingTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); #else m_ui.audioRoutingTable->horizontalHeader()->setResizeMode(0, QHeaderView::Stretch); #endif // m_ui.audioRoutingTable->verticalHeader()->hide(); QAbstractButton* pApplyButton = m_ui.buttonBox->button(QDialogButtonBox::Apply); pApplyButton->setEnabled(false); pApplyButton->setIcon(QIcon(":/images/formEdit.png")); QAbstractButton* pCancelButton = m_ui.buttonBox->button(QDialogButtonBox::Cancel); pCancelButton->setIcon(QIcon(":/images/formRemove.png")); QAbstractButton* pOkButton = m_ui.buttonBox->button(QDialogButtonBox::Ok); pOkButton->setIcon(QIcon(":/images/formAccept.png")); QAbstractButton* pResetButton = m_ui.buttonBox->button(QDialogButtonBox::Reset); pResetButton->setEnabled(false); pResetButton->setToolTip("Revert all changes."); m_ui.destroyPushButton->setEnabled(false); m_ui.mainParametersGroupBox->setEnabled(false); m_ui.audioRoutingGroupBox->setEnabled(false); for (int i = 0; i < 128; ++i) { m_ui.depthCtrlComboBox->addItem( QString("[") + QString::number(i) + "] " + _midiControllerName(i) ); } connect( m_ui.buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(onButtonClicked(QAbstractButton*)) ); connect( m_ui.createPushButton, SIGNAL(clicked()), this, SLOT(onCreateFxSend()) ); connect( m_ui.destroyPushButton, SIGNAL(clicked()), this, SLOT(onDestroyFxSend()) ); connect( pModel, SIGNAL(fxSendsDirtyChanged(bool)), pApplyButton, SLOT(setEnabled(bool)) ); connect( pModel, SIGNAL(fxSendsDirtyChanged(bool)), pResetButton, SLOT(setEnabled(bool)) ); connect( m_ui.SendsListView, SIGNAL(clicked(const QModelIndex&)), this, SLOT(onFxSendSelection(const QModelIndex&)) ); connect( m_ui.depthCtrlComboBox, SIGNAL(activated(int)), this, SLOT(onDepthCtrlChanged(int)) ); connect( m_ui.depthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(onCurrentSendDepthChanged(int)) ); connect( pRoutingModel, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(updateTableCellRenderers(const QModelIndex&, const QModelIndex&)) ); connect( pRoutingModel, SIGNAL(modelReset()), this, SLOT(updateTableCellRenderers()) ); connect( pRoutingModel, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(onRoutingTableChanged()) ); } ChannelFxForm::~ChannelFxForm() { if (m_pAudioDevice) delete m_pAudioDevice; } void ChannelFxForm::onButtonClicked(QAbstractButton* button) { FxSendsModel* pModel = (FxSendsModel*) m_ui.SendsListView->model(); switch (m_ui.buttonBox->buttonRole(button)) { case QDialogButtonBox::AcceptRole: case QDialogButtonBox::ApplyRole: pModel->applyToSampler(); // force a refresh of the parameter control elements onFxSendSelection(m_ui.SendsListView->currentIndex()); break; case QDialogButtonBox::ResetRole: pModel->cleanRefresh(); // force a refresh of the parameter control elements onFxSendSelection(m_ui.SendsListView->currentIndex()); break; default: // to avoid gcc warnings break; } } void ChannelFxForm::onFxSendSelection(const QModelIndex& index) { const bool bValid = index.isValid(); m_ui.destroyPushButton->setEnabled(bValid); m_ui.mainParametersGroupBox->setEnabled(bValid); m_ui.audioRoutingGroupBox->setEnabled(bValid); FxSendsModel* pModel = (FxSendsModel*) m_ui.SendsListView->model(); FxSend* pFxSend = pModel->fxSend(index); // clear routing model ChannelRoutingModel* pRoutingModel = (ChannelRoutingModel*) m_ui.audioRoutingTable->model(); pRoutingModel->refresh(nullptr, ChannelRoutingMap()); pRoutingModel->routingMap().clear(); // Reset routing change map. if (m_pAudioDevice) { delete m_pAudioDevice; m_pAudioDevice = nullptr; } if (!pFxSend) return; // update routing model if (m_pSamplerChannel->audioDevice() >= 0) { m_pAudioDevice = new Device(Device::Audio, m_pSamplerChannel->audioDevice()); pRoutingModel->refresh(m_pAudioDevice, pFxSend->audioRouting()); } m_ui.depthCtrlComboBox->setCurrentIndex(pFxSend->sendDepthMidiCtrl()); m_ui.depthSpinBox->setValue( int(::round(pFxSend->currentDepth() * 100.0)) ); } void ChannelFxForm::onCreateFxSend() { FxSendsModel* pModel = (FxSendsModel*) m_ui.SendsListView->model(); pModel->addFxSend(); } void ChannelFxForm::onDestroyFxSend() { FxSendsModel* pModel = (FxSendsModel*) m_ui.SendsListView->model(); pModel->removeFxSend(m_ui.SendsListView->currentIndex()); } void ChannelFxForm::onDepthCtrlChanged(int iMidiCtrl) { FxSendsModel* pModel = (FxSendsModel*) m_ui.SendsListView->model(); const QModelIndex index = m_ui.SendsListView->currentIndex(); FxSend* pFxSend = pModel->fxSend(index); if (!pFxSend) return; pFxSend->setSendDepthMidiCtrl(iMidiCtrl); pModel->onExternalModifiication(index); } void ChannelFxForm::onCurrentSendDepthChanged(int depthPercent) { FxSendsModel* pModel = (FxSendsModel*) m_ui.SendsListView->model(); const QModelIndex index = m_ui.SendsListView->currentIndex(); FxSend* pFxSend = pModel->fxSend(index); if (!pFxSend) return; if (depthPercent == int( ::round(pFxSend->currentDepth() * 100.0) )) return; // nothing changed actually pFxSend->setCurrentDepth(double(depthPercent) / 100.0); pModel->onExternalModifiication(index); } void ChannelFxForm::onRoutingTableChanged() { ChannelRoutingModel* pRoutingModel = (ChannelRoutingModel*) m_ui.audioRoutingTable->model(); if (pRoutingModel->routingMap().size() <= 0) return; // no changes FxSendsModel* pModel = (FxSendsModel*) m_ui.SendsListView->model(); const QModelIndex index = m_ui.SendsListView->currentIndex(); FxSend* pFxSend = pModel->fxSend(index); if (!pFxSend) { pRoutingModel->routingMap().clear(); // reset routing change map return; } ChannelRoutingMap routingMap = pRoutingModel->routingMap(); for ( ChannelRoutingMap::iterator iter = routingMap.begin(); iter != routingMap.end(); ++iter ) pFxSend->setAudioChannel(iter.key(), iter.value()); pRoutingModel->routingMap().clear(); // reset routing change map pModel->onExternalModifiication(index); } void ChannelFxForm::updateTableCellRenderers() { ChannelRoutingModel* pRoutingModel = (ChannelRoutingModel*) m_ui.audioRoutingTable->model(); const int rows = pRoutingModel->rowCount(); const int cols = pRoutingModel->columnCount(); updateTableCellRenderers( pRoutingModel->index(0, 0), pRoutingModel->index(rows - 1, cols - 1) ); } void ChannelFxForm::updateTableCellRenderers ( const QModelIndex& topLeft, const QModelIndex& bottomRight ) { ChannelRoutingModel* pRoutingModel = (ChannelRoutingModel*) m_ui.audioRoutingTable->model(); for (int r = topLeft.row(); r <= bottomRight.row(); r++) { for (int c = topLeft.column(); c <= bottomRight.column(); c++) { const QModelIndex index = pRoutingModel->index(r, c); m_ui.audioRoutingTable->openPersistentEditor(index); } } } } // namespace QSampler // end of qsamplerChannelFxForm.cpp qsampler-1.0.0/src/PaxHeaders/man10000644000000000000000000000013214634065603013767 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/man1/0000755000175000001440000000000014634065603014034 5ustar00rncbcusersqsampler-1.0.0/src/man1/PaxHeaders/qsampler.10000644000000000000000000000013214634065603015752 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/man1/qsampler.10000644000175000001440000000321114634065603015737 0ustar00rncbcusers.TH QSAMPLER 1 "June 17, 2014" .SH NAME Qsampler \- A LinuxSampler Qt GUI Interface .SH SYNOPSIS .B qsampler [\fIoptions\fR] [\fIsession-file\fR] .SH DESCRIPTION This manual page documents briefly the .B qsampler command. .PP \fBQsampler\fP is a LinuxSampler GUI front-end application written in C++ around the Qt framework using Qt Designer. At the moment it just wraps as a client reference interface for the LinuxSampler Control Protocol (LSCP). .PP \fBLinuxSampler\fP is a work in progress. The goal is to produce a free, open source pure software audio sampler with professional grade features, comparable to both hardware and commercial Windows/Mac software samplers. .PP The initial platform will be Linux because it is one of the most promising open source multimedia operating systems. Thanks to various kernel patches and the Jack Audio Connection Kit, Linux is currently able to deliver rock solid sub-5 millisecond MIDI-to-Audio response. .SH OPTIONS .HP \fB\-s, \fB\-\-start\fR .IP Start linuxsampler server locally .HP \fB\-h, \fB\-\-hostname\fR=[\fIhost\fR] .IP Specify linuxsampler server hostname (default = localhost) .HP \fB\-p, \fB\-\-port\fR=[\fIport\fR] .IP Specify linuxsampler server port number (default = 8888) .HP \fB\-?, \fB\-\-help\fR .IP Show help about command line options .HP \fB\-v, \fB\-\-version\fR .IP Show version information .SH FILES Configuration settings are stored in ~/.config/rncbc.org/Qsampler.conf .SH SEE ALSO .BR linuxsampler (1) .SH AUTHOR Qsampler was written by Rui Nuno Capela, Christian Schoenebeck. .PP This manual page was written by Matt Flax , for the Debian project (but may be used by others). qsampler-1.0.0/src/man1/PaxHeaders/qsampler.fr.10000644000000000000000000000013214634065603016360 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/man1/qsampler.fr.10000644000175000001440000000411714634065603016353 0ustar00rncbcusers.TH QSAMPLER 1 "Juin 17, 2014" .SH NOM Qsampler \- une interface graphique Qt pour LinuxSampler .SH SYNOPSIS .B qsampler [\fIoptions\fR] [\fIfichier-session\fR] .SH DESCRIPTION Cette page de manuel documente rapidement la commande .B qsampler . .PP \fBQsampler\fP est une interface graphique pour LinuxSampler, écrite en C++ autour des outils Qt, en utilisant Qt Designer. Pour le moment, c'est simplement un emballage en tant que client de référence pour le protocole de contrôle de LinuxSampler (LSCP). .PP \fBLinuxSampler\fP est un travail en cours. Le but est de produire un échantillonneur audio logiciel pur à source ouverte et gratuit avec des fonctionnalités de niveau professionnel, comparable aux échantillonneurs matériels et aux logiciels d'échantillonnage commerciaux pour Windows/Mac. .PP La plateforme initiale sera Linux car elle est l'un système d'exploitation multimédia à source ouverte des plus prometteurs. Grâce aux rustines du noyau et au kit de connexion Jack, Linux est actuellement capable de fournir une réponse MIDI-vers-audio en dessous de 5 millisecondes, à toute épreuve. .SH OPTIONS .HP \fB\-s, \fB\-\-start\fR .IP Démarre le serveur linuxsampler localement .HP \fB\-h, \fB\-\-hostname\fR=[\fIhôte\fR] .IP Spécifie le nom d'hôte du serveur linuxsampler (par défaut = localhost) .HP \fB\-p, \fB\-\-port\fR=[\fIport\fR] .IP Spécifie le numéro de port du serveur linuxsampler (par défaut = 8888) .HP \fB\-?, \fB\-\-help\fR .IP Affiche de l'aide à propos des options de ligne de commande .HP \fB\-v, \fB\-\-version\fR .IP Affiche des informations de version .SH FICHIERS Les paramètres de configuration sont stockés dans ~/.config/rncbc.org/Qsampler.conf .SH VOIR ÉGALEMENT .BR linuxsampler (1) .SH AUTEUR Qsampler a été écrit par Rui Nuno Capela et Christian Schoenebeck. .PP Cette page de manuel a été écrite par Matt Flax , pour le projet Debian (mais peut être utilisée par d'autres). .PP La version française a été traduite par Olivier Humbert , pour le projet LibraZiK (mais peut être utilisée par d'autres). qsampler-1.0.0/src/PaxHeaders/qsamplerChannel.h0000644000000000000000000000013214634065603016476 xustar0030 mtime=1718643587.392448566 30 atime=1718643587.392448566 30 ctime=1718643587.392448566 qsampler-1.0.0/src/qsamplerChannel.h0000644000175000001440000001653414634065603016477 0ustar00rncbcusers// qsamplerChannel.h // /**************************************************************************** Copyright (C) 2004-2023, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #ifndef __qsamplerChannel_h #define __qsamplerChannel_h #include #include #include #include #include "qsamplerOptions.h" namespace QSampler { class Device; // Typedef'd QMap. typedef QMap ChannelRoutingMap; //------------------------------------------------------------------------- // QSampler::Channel - Sampler channel structure. // class Channel { public: // Constructor. Channel(int iChannelID = -1); // Default destructor. ~Channel(); // Add/remove sampler channel methods. bool addChannel(); bool removeChannel(); // Sampler channel ID accessors. int channelID() const; void setChannelID(int iChannelID); // Readable channel name. QString channelName() const; // Engine name property. const QString& engineName() const; bool loadEngine(const QString& sEngineName); // Instrument file and index. const QString& instrumentFile() const; int instrumentNr() const; const QString& instrumentName() const; int instrumentStatus() const; // Instrument file loader. bool loadInstrument(const QString& sInstrumentFile, int iInstrumentNr); // Special instrument file/name/number settler. bool setInstrument(const QString& sInstrumentFile, int iInstrumentNr); // MIDI input driver (DEPRECATED). const QString& midiDriver() const; bool setMidiDriver(const QString& sMidiDriver); // MIDI input device. int midiDevice() const; bool setMidiDevice(int iMidiDevice); // MIDI input port. int midiPort() const; bool setMidiPort(int iMidiPort); // MIDI input channel. int midiChannel() const; bool setMidiChannel(int iMidiChannel); // MIDI instrument map. int midiMap() const; bool setMidiMap(int iMidiMap); // Audio output driver (DEPRECATED). const QString& audioDriver() const; bool setAudioDriver(const QString& sAudioDriver); // Audio output device. int audioDevice() const; bool setAudioDevice(int iAudioDevice); // Sampler channel volume. float volume() const; bool setVolume(float fVolume); // Sampler channel mute state. bool channelMute() const; bool setChannelMute(bool bMute); // Sampler channel solo state. bool channelSolo() const; bool setChannelSolo(bool bSolo); // Audio routing accessors. int audioChannel(int iAudioOut) const; bool setAudioChannel(int iAudioOut, int iAudioIn); // The audio routing map itself. const ChannelRoutingMap& audioRouting() const; // Istrument name remapper. void updateInstrumentName(); // Channel info structure map executive. bool updateChannelInfo(); // Channel setup dialog form. bool channelSetup(QWidget *pParent); // Reset channel method. bool channelReset(); // Spawn instrument editor method. bool editChannel(); // Message logging methods (brainlessly mapped to main form's). void appendMessages (const QString & s) const; void appendMessagesColor (const QString & s, const QColor& rgb) const; void appendMessagesText (const QString & s) const; void appendMessagesError (const QString & s) const; void appendMessagesClient (const QString & s) const; // Context menu event handler. void contextMenuEvent(QContextMenuEvent *pEvent); // Common (invalid) name-helpers. static QString noEngineName(); static QString noInstrumentName(); static QString loadingInstrument(); // Check whether a given file is an instrument file. static bool isDlsInstrumentFile (const QString& sInstrumentFile); static bool isSf2InstrumentFile (const QString& sInstrumentFile); // Retrieve the available instrument name(s) of an instrument file (.gig). static QString getInstrumentName (const QString& sInstrumentFile, int iInstrumentNr, bool bInstrumentNames); static QStringList getInstrumentList (const QString& sInstrumentFile, bool bInstrumentNames); private: // Unique channel identifier. int m_iChannelID; // Sampler channel info map. QString m_sEngineName; QString m_sInstrumentName; QString m_sInstrumentFile; int m_iInstrumentNr; int m_iInstrumentStatus; QString m_sMidiDriver; int m_iMidiDevice; int m_iMidiPort; int m_iMidiChannel; int m_iMidiMap; QString m_sAudioDriver; int m_iAudioDevice; float m_fVolume; bool m_bMute; bool m_bSolo; // The audio routing mapping. ChannelRoutingMap m_audioRouting; }; //------------------------------------------------------------------------- // QSampler::ChannelRoutingModel - data model for audio routing // (used for QTableView) // struct ChannelRoutingItem { QStringList options; int selection; }; class ChannelRoutingModel : public QAbstractTableModel { Q_OBJECT public: ChannelRoutingModel(QObject* pParent = nullptr); // overridden methods from subclass(es) int rowCount(const QModelIndex& parent = QModelIndex()) const; int columnCount(const QModelIndex& parent = QModelIndex()) const; Qt::ItemFlags flags(const QModelIndex& index) const; bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole); QVariant data(const QModelIndex &index, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; // own methods ChannelRoutingMap routingMap() const { return m_routing; } void clear() { m_routing.clear(); } public slots: void refresh(Device *pDevice, const ChannelRoutingMap& routing); private: Device *m_pDevice; ChannelRoutingMap m_routing; }; //------------------------------------------------------------------------- // QSampler::ChannelRoutingDelegate - table cell renderer for audio routing // class ChannelRoutingDelegate : public QItemDelegate { Q_OBJECT public: ChannelRoutingDelegate(QObject* pParent = nullptr); QWidget* createEditor(QWidget *pParent, const QStyleOptionViewItem& option, const QModelIndex& index) const; void setEditorData(QWidget *pEditor, const QModelIndex& index) const; void setModelData(QWidget *pEditor, QAbstractItemModel* model, const QModelIndex& index) const; void updateEditorGeometry(QWidget *pEditor, const QStyleOptionViewItem& option, const QModelIndex& index) const; }; } // namespace QSampler // So we can use it i.e. through QVariant Q_DECLARE_METATYPE(QSampler::ChannelRoutingItem) #endif // __qsamplerChannel_h // end of qsamplerChannel.h qsampler-1.0.0/src/PaxHeaders/qsamplerChannelForm.ui0000644000000000000000000000013214634065603017510 xustar0030 mtime=1718643587.392448566 30 atime=1718643587.392448566 30 ctime=1718643587.392448566 qsampler-1.0.0/src/qsamplerChannelForm.ui0000644000175000001440000005176014634065603017511 0ustar00rncbcusers rncbc aka Rui Nuno Capela qsampler - A LinuxSampler Qt GUI Interface. Copyright (C) 2005-2020, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. qsamplerChannelForm 0 0 480 460 Qt::StrongFocus Channel :/images/qsamplerChannel.png 8 62 0 62 16777215 &Engine: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false EngineNameComboBox 0 0 Engine name Qt::Horizontal QSizePolicy::Expanding 20 20 Filena&me: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false InstrumentFileComboBox 0 0 320 0 Instrument filename true 0 0 24 24 26 26 Qt::TabFocus Browse for instrument filename :/images/fileOpen.png &Instrument: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false InstrumentNrComboBox 0 0 320 0 Instrument name MIDI / Input 62 0 62 16777215 T&ype: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false MidiDriverComboBox 0 0 92 0 92 16777215 MIDI input driver type Qt::Horizontal QSizePolicy::Expanding 20 20 &Port: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false MidiPortSpinBox MIDI input port number &Channel: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false MidiChannelComboBox MIDI input channel 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 All Qt::Horizontal QSizePolicy::Expanding 20 20 De&vice: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false MidiDeviceComboBox 0 0 MIDI input device 0 0 24 24 26 26 Qt::TabFocus MIDI input device setup :/images/midi1.png &Map: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false MidiMapComboBox 0 0 Instrument map Qt::Horizontal QSizePolicy::Expanding 20 20 Audio / Output 62 0 62 16777215 T&ype: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false AudioDriverComboBox 0 0 92 0 92 16777215 Audio output driver type Qt::Horizontal QSizePolicy::Expanding 20 20 De&vice: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false AudioDeviceComboBox 0 0 Audio output device 0 0 24 24 26 26 Qt::TabFocus Audio output device setup :/images/audio1.png 0 0 320 80 Audio routing table Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok EngineNameComboBox InstrumentFileComboBox InstrumentFileToolButton InstrumentNrComboBox DialogButtonBox qsampler-1.0.0/src/PaxHeaders/qsamplerDeviceForm.ui0000644000000000000000000000013214634065603017337 xustar0030 mtime=1718643587.393448566 30 atime=1718643587.393448566 30 ctime=1718643587.393448566 qsampler-1.0.0/src/qsamplerDeviceForm.ui0000644000175000001440000002435614634065603017341 0ustar00rncbcusers rncbc aka Rui Nuno Capela qsampler - A LinuxSampler Qt GUI Interface. Copyright (C) 2004-2020, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. qsamplerDeviceForm 0 0 601 378 Qt::StrongFocus Devices :/images/qsamplerDevice.png 9 6 7 7 0 0 Qt::Horizontal 4 120 0 Device list false true Devices 7 7 0 0 Qt::Vertical 4 0 6 0 6 75 true Device name false 4 Dri&ver: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false DriverNameComboBox Driver type name true QAbstractItemView::NoSelection false 0 6 0 6 Channel: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false DevicePortComboBox 7 0 0 0 120 0 Device port/channel true QAbstractItemView::NoSelection false 0 4 Refresh device list view &Refresh :/images/formRefresh.png Qt::Horizontal QSizePolicy::Expanding 180 20 Create device &Create :/images/deviceCreate.png Delete device &Delete :/images/deviceDelete.png Close this dialog Close :/images/formReject.png DeviceListView RefreshDevicesPushButton DriverNameComboBox DevicePortComboBox CreateDevicePushButton DeleteDevicePushButton ClosePushButton qsampler-1.0.0/src/PaxHeaders/qsamplerMainForm.ui0000644000000000000000000000013214634065603017024 xustar0030 mtime=1718643587.394448566 30 atime=1718643587.394448566 30 ctime=1718643587.394448566 qsampler-1.0.0/src/qsamplerMainForm.ui0000644000175000001440000004415514634065603017025 0ustar00rncbcusers rncbc aka Rui Nuno Capela qsampler - A LinuxSampler Qt GUI Interface. Copyright (C) 2004-2024, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007-2019 Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. qsamplerMainForm 0 0 800 600 :/images/qsampler.svg Qt::Horizontal 4 Qt::Horizontal 4 Qt::Horizontal 4 0 0 800 31 &Edit &View MIDI Device Status &Channels &Help &File Open &Recent :/images/fileNew.png &New New New session New sampler session Ctrl+N :/images/fileOpen.png &Open... Open Open session Open sampler session Ctrl+O :/images/fileSave.png &Save Save Save session Save sampler session Ctrl+S Save &As... Save As Save current sampler session with another name :/images/fileReset.png Rese&t Reset Reset instance Reset sampler instance Ctrl+R :/images/fileRestart.png &Restart Restart Restart instance Restart sampler instance Ctrl+Shift+R E&xit Exit Exit this application program :/images/editAddChannel.png &Add Channel Add Add channel Add a new sampler channel Ctrl+A :/images/editRemoveChannel.png &Remove Channel Remove Remove channel Remove current sampler channel Ctrl+X :/images/editResetChannel.png Re&set Channel Reset Reset channel Reset current sampler channel :/images/editResetAllChannels.png R&eset All Channels Reset All Reset all channels Reset all sampler channels :/images/editSetupChannel.png &Setup Channel... Setup Setup channel Setup current sampler channel F2 :/images/editEditChannel.png Ed&it Channel... Edit Edit channel Edit current sampler channel F9 true &Menubar Menubar Show/hide menubar Show/hide the main program window menubar Ctrl+M true &Toolbar Toolbar Show/hide toolbar Show/hide main program window toolbars Ctrl+T true &Statusbar Statusbar Show/hide statusbar Show/hide the main program window statusbar true M&essages Messages Show/hide messages Show/hide the messages window true :/images/qsamplerInstrument.png &Instruments Instruments MIDI instruments configuration Show/hide the MIDI instruments configuration window F10 true :/images/qsamplerDevice.png &Devices Devices Device configuration Show/hide the device configuration window F11 &Options... Options General options Change general application program options F12 false :/images/channelsArrange.png &Arrange Arrange Arrange channels Line up all channel strips F5 true A&uto Arrange Auto Arrange Auto-arrange channels Auto-arrange channel strips &About... About Show information about this application program About &Qt... About Qt Show information about the Qt toolkit qsampler-1.0.0/src/PaxHeaders/qsampler.qrc0000644000000000000000000000013214634065603015543 xustar0030 mtime=1718643587.391448566 30 atime=1718643587.391448566 30 ctime=1718643587.391448566 qsampler-1.0.0/src/qsampler.qrc0000644000175000001440000000333614634065603015540 0ustar00rncbcusers images/qsampler.png images/qsampler.svg images/audio1.png images/audio2.png images/channelsArrange.png images/deviceCreate.png images/deviceDelete.png images/displaybg1.png images/editAddChannel.png images/editEditChannel.png images/editRemoveChannel.png images/editResetAllChannels.png images/editResetChannel.png images/editSetupChannel.png images/fileNew.png images/fileOpen.png images/fileReset.png images/fileRestart.png images/fileSave.png images/formAccept.png images/formEdit.png images/formOpen.png images/formRefresh.png images/formReject.png images/formRemove.png images/formSave.png images/itemFile.png images/itemGroup.png images/itemGroupNew.png images/itemGroupOpen.png images/itemNew.png images/itemReset.png images/ledoff1.png images/ledon1.png images/midi1.png images/midi2.png images/qsamplerChannel.png images/qsamplerDevice.png images/qsamplerInstrument.png qsampler-1.0.0/src/PaxHeaders/qsamplerChannelForm.cpp0000644000000000000000000000013214634065603017655 xustar0030 mtime=1718643587.392448566 30 atime=1718643587.392448566 30 ctime=1718643587.392448566 qsampler-1.0.0/src/qsamplerChannelForm.cpp0000644000175000001440000006173114634065603017655 0ustar00rncbcusers// qsamplerChannelForm.cpp // /**************************************************************************** Copyright (C) 2004-2020, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007, 2008 Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *****************************************************************************/ #include "qsamplerChannelForm.h" #include "qsamplerAbout.h" #include "qsamplerDeviceForm.h" #include "qsamplerMainForm.h" #include "qsamplerInstrument.h" #include #include #include #include #include namespace QSampler { //------------------------------------------------------------------------- // QSampler::Channelform -- Channel form implementation. // ChannelForm::ChannelForm ( QWidget* pParent ) : QDialog(pParent) { m_ui.setupUi(this); // Initialize locals. m_pChannel = nullptr; m_iDirtySetup = 0; m_iDirtyCount = 0; // m_midiDevices.setAutoDelete(true); // m_audioDevices.setAutoDelete(true); m_pDeviceForm = nullptr; const int iRowHeight = m_ui.AudioRoutingTable->fontMetrics().height() + 4; m_ui.AudioRoutingTable->verticalHeader()->setDefaultSectionSize(iRowHeight); m_ui.AudioRoutingTable->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft); m_ui.AudioRoutingTable->setModel(&m_routingModel); m_ui.AudioRoutingTable->setItemDelegate(&m_routingDelegate); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) m_ui.AudioRoutingTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); #else m_ui.AudioRoutingTable->horizontalHeader()->setResizeMode(0, QHeaderView::Stretch); #endif // m_ui.AudioRoutingTable->verticalHeader()->hide(); // This goes initially hidden, and will be shown // on setup() for currently existing channels... m_ui.AudioRoutingTable->hide(); // Try to restore normal window positioning. adjustSize(); QObject::connect(m_ui.EngineNameComboBox, SIGNAL(activated(int)), SLOT(optionsChanged())); QObject::connect(m_ui.InstrumentFileComboBox, SIGNAL(editTextChanged(const QString&)), SLOT(updateInstrumentName())); QObject::connect(m_ui.InstrumentFileComboBox, SIGNAL(activated(const QString&)), SLOT(updateInstrumentName())); QObject::connect(m_ui.InstrumentFileToolButton, SIGNAL(clicked()), SLOT(openInstrumentFile())); QObject::connect(m_ui.InstrumentNrComboBox, SIGNAL(activated(int)), SLOT(optionsChanged())); QObject::connect(m_ui.MidiDriverComboBox, SIGNAL(activated(const QString&)), SLOT(selectMidiDriver(const QString&))); QObject::connect(m_ui.MidiDeviceComboBox, SIGNAL(activated(int)), SLOT(selectMidiDevice(int))); QObject::connect(m_ui.MidiPortSpinBox, SIGNAL(valueChanged(int)), SLOT(optionsChanged())); QObject::connect(m_ui.MidiChannelComboBox, SIGNAL(activated(int)), SLOT(optionsChanged())); QObject::connect(m_ui.MidiMapComboBox, SIGNAL(activated(int)), SLOT(optionsChanged())); QObject::connect(m_ui.AudioDriverComboBox, SIGNAL(activated(const QString&)), SLOT(selectAudioDriver(const QString&))); QObject::connect(m_ui.AudioDeviceComboBox, SIGNAL(activated(int)), SLOT(selectAudioDevice(int))); QObject::connect(m_ui.DialogButtonBox, SIGNAL(accepted()), SLOT(accept())); QObject::connect(m_ui.DialogButtonBox, SIGNAL(rejected()), SLOT(reject())); QObject::connect(m_ui.MidiDeviceToolButton, SIGNAL(clicked()), SLOT(setupMidiDevice())); QObject::connect(m_ui.AudioDeviceToolButton, SIGNAL(clicked()), SLOT(setupAudioDevice())); QObject::connect(&m_routingModel, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), SLOT(optionsChanged())); QObject::connect(&m_routingModel, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), SLOT(updateTableCellRenderers(const QModelIndex&, const QModelIndex&))); QObject::connect(&m_routingModel, SIGNAL(modelReset()), SLOT(updateTableCellRenderers())); } ChannelForm::~ChannelForm() { if (m_pDeviceForm) delete m_pDeviceForm; m_pDeviceForm = nullptr; qDeleteAll(m_midiDevices); m_midiDevices.clear(); qDeleteAll(m_audioDevices); m_audioDevices.clear(); } // Channel dialog setup formal initializer. void ChannelForm::setup ( Channel *pChannel ) { m_pChannel = pChannel; m_iDirtySetup = 0; m_iDirtyCount = 0; if (m_pChannel == nullptr) return; // It can be a brand new channel, remember? const bool bNew = (m_pChannel->channelID() < 0); setWindowTitle(m_pChannel->channelName()); // Check if we're up and connected. MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; if (pMainForm->client() == nullptr) return; Options *pOptions = pMainForm->options(); if (pOptions == nullptr) return; // Avoid nested changes. m_iDirtySetup++; // Load combo box history... pOptions->loadComboBoxHistory(m_ui.InstrumentFileComboBox); // Remove non-existant instrument file-paths... int i = m_ui.InstrumentFileComboBox->count() - 1; while (i >= 0) { const QString& sInstrumentFile = m_ui.InstrumentFileComboBox->itemText(i); if (sInstrumentFile.isEmpty() || !QFileInfo(sInstrumentFile).exists()) m_ui.InstrumentFileComboBox->removeItem(i); --i; } // Populate Engines list. const char **ppszEngines = ::lscp_list_available_engines(pMainForm->client()); if (ppszEngines) { m_ui.EngineNameComboBox->clear(); for (int iEngine = 0; ppszEngines[iEngine]; iEngine++) m_ui.EngineNameComboBox->addItem(QString(ppszEngines[iEngine])); } else m_pChannel->appendMessagesClient("lscp_list_available_engines"); // Populate Audio output type list. m_ui.AudioDriverComboBox->clear(); m_ui.AudioDriverComboBox->insertItems(0, Device::getDrivers(pMainForm->client(), Device::Audio)); // Populate MIDI input type list. m_ui.MidiDriverComboBox->clear(); m_ui.MidiDriverComboBox->insertItems(0, Device::getDrivers(pMainForm->client(), Device::Midi)); // Populate Maps list. m_ui.MidiMapComboBox->clear(); m_ui.MidiMapComboBox->insertItems(0, Instrument::getMapNames()); // Read proper channel information, // and populate the channel form fields. // Engine name... QString sEngineName = pChannel->engineName(); if (sEngineName.isEmpty() || bNew) sEngineName = pOptions->sEngineName; if (sEngineName.isEmpty()) sEngineName = Channel::noEngineName(); if (m_ui.EngineNameComboBox->findText(sEngineName, Qt::MatchExactly | Qt::MatchCaseSensitive) < 0) { m_ui.EngineNameComboBox->addItem(sEngineName); } m_ui.EngineNameComboBox->setCurrentIndex( m_ui.EngineNameComboBox->findText(sEngineName, Qt::MatchExactly | Qt::MatchCaseSensitive)); // Instrument filename and index... QString sInstrumentFile = pChannel->instrumentFile(); if (sInstrumentFile.isEmpty()) sInstrumentFile = Channel::noInstrumentName(); m_ui.InstrumentFileComboBox->setEditText(sInstrumentFile); m_ui.InstrumentNrComboBox->clear(); m_ui.InstrumentNrComboBox->insertItems(0, Channel::getInstrumentList(sInstrumentFile, pOptions->bInstrumentNames)); int iInstrumentNr = pChannel->instrumentNr(); if (iInstrumentNr < 0) iInstrumentNr = 0; m_ui.InstrumentNrComboBox->setCurrentIndex(iInstrumentNr); // MIDI input device... const Device midiDevice(Device::Midi, m_pChannel->midiDevice()); // MIDI input driver... QString sMidiDriver = midiDevice.driverName(); if (sMidiDriver.isEmpty() || bNew) sMidiDriver = pOptions->sMidiDriver.toUpper(); if (!sMidiDriver.isEmpty()) { if (m_ui.MidiDriverComboBox->findText(sMidiDriver, Qt::MatchExactly | Qt::MatchCaseSensitive) < 0) { m_ui.MidiDriverComboBox->insertItem(0, sMidiDriver); } m_ui.MidiDriverComboBox->setCurrentIndex( m_ui.MidiDriverComboBox->findText(sMidiDriver, Qt::MatchExactly | Qt::MatchCaseSensitive) ); } selectMidiDriverItem(sMidiDriver); if (!bNew) { m_ui.MidiDeviceComboBox->setCurrentIndex( m_ui.MidiDeviceComboBox->findData(midiDevice.deviceID())); } selectMidiDeviceItem(m_ui.MidiDeviceComboBox->currentIndex()); // MIDI input port... m_ui.MidiPortSpinBox->setValue(pChannel->midiPort()); // MIDI input channel... int iMidiChannel = pChannel->midiChannel(); // When new, try to suggest a sensible MIDI channel... if (iMidiChannel < 0) iMidiChannel = (::lscp_get_channels(pMainForm->client()) % 16); m_ui.MidiChannelComboBox->setCurrentIndex(iMidiChannel); // MIDI instrument map... int iMidiMap = (bNew ? pOptions->iMidiMap : pChannel->midiMap()); // When new, try to suggest a sensible MIDI map... if (iMidiMap < 0) iMidiMap = 0; const QString& sMapName = Instrument::getMapName(iMidiMap); if (!sMapName.isEmpty()) { m_ui.MidiMapComboBox->setItemText( m_ui.MidiMapComboBox->currentIndex(), sMapName); } // It might be no maps around... const bool bMidiMapEnabled = (m_ui.MidiMapComboBox->count() > 0); m_ui.MidiMapTextLabel->setEnabled(bMidiMapEnabled); m_ui.MidiMapComboBox->setEnabled(bMidiMapEnabled); // Audio output device... const Device audioDevice(Device::Audio, m_pChannel->audioDevice()); // Audio output driver... QString sAudioDriver = audioDevice.driverName(); if (sAudioDriver.isEmpty() || bNew) sAudioDriver = pOptions->sAudioDriver.toUpper(); if (!sAudioDriver.isEmpty()) { if (m_ui.AudioDriverComboBox->findText(sAudioDriver, Qt::MatchExactly | Qt::MatchCaseSensitive) < 0) { m_ui.AudioDriverComboBox->insertItem(0, sAudioDriver); } m_ui.AudioDriverComboBox->setCurrentIndex( m_ui.AudioDriverComboBox->findText(sAudioDriver, Qt::MatchExactly | Qt::MatchCaseSensitive) ); } selectAudioDriverItem(sAudioDriver); if (!bNew) { m_ui.AudioDeviceComboBox->setCurrentIndex( m_ui.AudioDeviceComboBox->findData(audioDevice.deviceID())); } selectAudioDeviceItem(m_ui.AudioDeviceComboBox->currentIndex()); // Let the audio routing table see the light, // if we're editing an existing sampler channel... m_ui.AudioRoutingTable->setVisible(!bNew); const QString sInstrumentNrToolTip = (pOptions->bInstrumentNames) ? tr("Select an instrument of the file") : tr("You might want to enable instrument name retrieval in the " "settings dialog"); m_ui.InstrumentNrComboBox->setToolTip( QObject::tr(sInstrumentNrToolTip.toUtf8().data()) ); #if 0 // As convenient, make it ready on stabilizeForm() for // prompt acceptance, if we got the minimum required... if (sEngineName != Channel::noEngineName() && sInstrumentFile != Channel::noInstrumentName()) m_iDirtyCount++; #endif // Done. m_iDirtySetup--; stabilizeForm(); } // Accept settings (OK button slot). void ChannelForm::accept (void) { if (m_pChannel == nullptr) return; MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; if (pMainForm->client() == nullptr) return; Options *pOptions = pMainForm->options(); if (pOptions == nullptr) return; // Flush any pending editing... //m_ui.AudioRoutingTable->flush(); // We'll go for it! if (m_iDirtyCount > 0) { int iErrors = 0; // Are we a new channel? if (!m_pChannel->addChannel()) iErrors++; // Accept Audio driver or device selection... if (m_audioDevices.isEmpty()) { if (!m_pChannel->setAudioDriver(m_ui.AudioDriverComboBox->currentText())) iErrors++; } else { Device *pDevice = nullptr; const int iAudioItem = m_ui.AudioDeviceComboBox->currentIndex(); if (iAudioItem >= 0) { const int iAudioDevice = m_ui.AudioDeviceComboBox->itemData(iAudioItem).toInt(); pDevice = m_audioDevices.value(iAudioDevice, nullptr); } ChannelRoutingMap routingMap = m_routingModel.routingMap(); if (pDevice == nullptr) iErrors++; else if (!m_pChannel->setAudioDevice(pDevice->deviceID())) iErrors++; else if (!routingMap.isEmpty()) { // Set the audio route changes... ChannelRoutingMap::ConstIterator iter; for (iter = routingMap.begin(); iter != routingMap.end(); ++iter) { if (!m_pChannel->setAudioChannel(iter.key(), iter.value())) iErrors++; } } } // Accept MIDI driver or device selection... if (m_midiDevices.isEmpty()) { if (!m_pChannel->setMidiDriver(m_ui.MidiDriverComboBox->currentText())) iErrors++; } else { Device *pDevice = nullptr; const int iMidiItem = m_ui.MidiDeviceComboBox->currentIndex(); if (iMidiItem >= 0) { const int iMidiDevice = m_ui.MidiDeviceComboBox->itemData(iMidiItem).toInt(); pDevice = m_midiDevices.value(iMidiDevice, nullptr); } if (pDevice == nullptr) iErrors++; else if (!m_pChannel->setMidiDevice(pDevice->deviceID())) iErrors++; } // MIDI input port number... if (!m_pChannel->setMidiPort(m_ui.MidiPortSpinBox->value())) iErrors++; // MIDI input channel... if (!m_pChannel->setMidiChannel(m_ui.MidiChannelComboBox->currentIndex())) iErrors++; // Engine name... if (!m_pChannel->loadEngine(m_ui.EngineNameComboBox->currentText())) iErrors++; // Instrument file and index... const QString& sPath = m_ui.InstrumentFileComboBox->currentText(); if (!sPath.isEmpty() && QFileInfo(sPath).exists()) { if (!m_pChannel->loadInstrument(sPath, m_ui.InstrumentNrComboBox->currentIndex())) iErrors++; } // MIDI intrument map... if (!m_pChannel->setMidiMap(m_ui.MidiMapComboBox->currentIndex())) iErrors++; // Show error messages? if (iErrors > 0) { m_pChannel->appendMessagesError( tr("Some channel settings could not be set.\n\nSorry.")); } } // Save default engine name, instrument directory and history... pOptions->sInstrumentDir = QFileInfo( m_ui.InstrumentFileComboBox->currentText()).dir().absolutePath(); pOptions->sEngineName = m_ui.EngineNameComboBox->currentText(); pOptions->sAudioDriver = m_ui.AudioDriverComboBox->currentText(); pOptions->sMidiDriver = m_ui.MidiDriverComboBox->currentText(); pOptions->iMidiMap = m_ui.MidiMapComboBox->currentIndex(); pOptions->saveComboBoxHistory(m_ui.InstrumentFileComboBox); // Just go with dialog acceptance. QDialog::accept(); } // Reject settings (Cancel button slot). void ChannelForm::reject (void) { bool bReject = true; // Check if there's any pending changes... if (m_iDirtyCount > 0) { switch (QMessageBox::warning(this, tr("Warning"), tr("Some channel settings have been changed.\n\n" "Do you want to apply the changes?"), QMessageBox::Apply | QMessageBox::Discard | QMessageBox::Cancel)) { case QMessageBox::Apply: accept(); return; case QMessageBox::Discard: break; default: // Cancel. bReject = false; break; } } if (bReject) QDialog::reject(); } // Browse and open an instrument file. void ChannelForm::openInstrumentFile (void) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; if (pMainForm->client() == nullptr) return; Options *pOptions = pMainForm->options(); if (pOptions == nullptr) return; // FIXME: the instrument file filters should be restricted, // depending on the current engine. QStringList filters; const QString& sEngineName = m_ui.EngineNameComboBox->currentText().toUpper(); if (sEngineName.contains("GIG")) filters << tr("GIG Instrument files") + " (*.gig *.dls)"; if (sEngineName.contains("SFZ")) filters << tr("SFZ Instrument files") + " (*.sfz)"; if (sEngineName.contains("SF2")) filters << tr("SF2 Instrument files") + " (*.sf2)"; filters << tr("All files") + " (*.*)"; const QString& filter = filters.join(";;"); QString sInstrumentFile = QFileDialog::getOpenFileName(this, tr("Instrument files"), // Caption. pOptions->sInstrumentDir, // Start here. filter // File filter. ); if (sInstrumentFile.isEmpty()) return; m_ui.InstrumentFileComboBox->setEditText(sInstrumentFile); updateInstrumentName(); } // Refresh the actual instrument name. void ChannelForm::updateInstrumentName (void) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; if (pMainForm->client() == nullptr) return; Options *pOptions = pMainForm->options(); if (pOptions == nullptr) return; // Finally this better idea would be to use libgig // to retrieve the REAL instrument names. m_ui.InstrumentNrComboBox->clear(); m_ui.InstrumentNrComboBox->insertItems(0, Channel::getInstrumentList( m_ui.InstrumentFileComboBox->currentText(), pOptions->bInstrumentNames) ); optionsChanged(); } // Show device options dialog. void ChannelForm::setupDevice ( Device *pDevice, Device::DeviceType deviceTypeMode, const QString& sDriverName ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; if (pMainForm->client() == nullptr) return; // Create the device form if not already... if (m_pDeviceForm == nullptr) { m_pDeviceForm = new DeviceForm(this); m_pDeviceForm->setAttribute(Qt::WA_ShowModal); QObject::connect(m_pDeviceForm, SIGNAL(devicesChanged()), this, SLOT(updateDevices())); } // Refresh the device form with selected data. if (m_pDeviceForm) { m_pDeviceForm->setDeviceTypeMode(deviceTypeMode); m_pDeviceForm->refreshDevices(); m_pDeviceForm->setDevice(pDevice); m_pDeviceForm->setDriverName(sDriverName); m_pDeviceForm->show(); } } // Refresh MIDI driver item devices. void ChannelForm::selectMidiDriverItem ( const QString& sMidiDriver ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; if (pMainForm->client() == nullptr) return; const QString sDriverName = sMidiDriver.toUpper(); // Save current device id. int iDeviceID = 0; int iMidiItem = m_ui.MidiDeviceComboBox->currentIndex(); if (iMidiItem >= 0) iDeviceID = m_ui.MidiDeviceComboBox->itemData(iMidiItem).toInt(); // Clean maplist. m_ui.MidiDeviceComboBox->clear(); qDeleteAll(m_midiDevices); m_midiDevices.clear(); // Populate with the current ones... Device *pDevice = nullptr; const QPixmap midiPixmap(":/images/midi2.png"); int *piDeviceIDs = Device::getDevices(pMainForm->client(), Device::Midi); for (int i = 0; piDeviceIDs && piDeviceIDs[i] >= 0; ++i) { pDevice = new Device(Device::Midi, piDeviceIDs[i]); if (pDevice->driverName().toUpper() == sDriverName) { const int iMidiDevice = pDevice->deviceID(); m_ui.MidiDeviceComboBox->addItem( midiPixmap, pDevice->deviceName()); m_ui.MidiDeviceComboBox->setItemData(i, iMidiDevice); m_midiDevices.insert(iMidiDevice, pDevice); if (iMidiDevice == iDeviceID) iMidiItem = i; } else { delete pDevice; } } // Do proper enabling... const bool bEnabled = !m_midiDevices.isEmpty(); if (bEnabled) { // Select the previous current device... m_ui.MidiDeviceComboBox->setCurrentIndex(iMidiItem); selectMidiDeviceItem(iMidiItem); } else { m_ui.MidiDeviceComboBox->insertItem(0, tr("(New MIDI %1 device)").arg(sMidiDriver)); m_ui.MidiDeviceComboBox->setItemData(0, -1); } // m_ui.MidiDeviceTextLabel->setEnabled(bEnabled); // m_ui.MidiDeviceComboBox->setEnabled(bEnabled); } // Refresh MIDI device options slot. void ChannelForm::selectMidiDriver ( const QString& sMidiDriver ) { if (m_iDirtySetup > 0) return; selectMidiDriverItem(sMidiDriver); optionsChanged(); } // Select MIDI device item. void ChannelForm::selectMidiDeviceItem ( int iMidiItem ) { Device *pDevice = nullptr; if (iMidiItem >= 0) { const int iMidiDevice = m_ui.MidiDeviceComboBox->itemData(iMidiItem).toInt(); pDevice = m_midiDevices.value(iMidiDevice, nullptr); } if (pDevice) { const DeviceParamMap& params = pDevice->params(); const int iPorts = params["PORTS"].value.toInt(); m_ui.MidiPortTextLabel->setEnabled(iPorts > 0); m_ui.MidiPortSpinBox->setEnabled(iPorts > 0); if (iPorts > 0) m_ui.MidiPortSpinBox->setMaximum(iPorts - 1); } } // Select MIDI device options slot. void ChannelForm::selectMidiDevice ( int iMidiItem ) { if (m_iDirtySetup > 0) return; selectMidiDeviceItem(iMidiItem); optionsChanged(); } // MIDI device options. void ChannelForm::setupMidiDevice (void) { Device *pDevice = nullptr; const int iMidiItem = m_ui.MidiDeviceComboBox->currentIndex(); if (iMidiItem >= 0) { const int iMidiDevice = m_ui.MidiDeviceComboBox->itemData(iMidiItem).toInt(); pDevice = m_midiDevices.value(iMidiDevice, nullptr); } setupDevice(pDevice, Device::Midi, m_ui.MidiDriverComboBox->currentText()); } // Refresh Audio driver item devices. void ChannelForm::selectAudioDriverItem ( const QString& sAudioDriver ) { MainForm *pMainForm = MainForm::getInstance(); if (pMainForm == nullptr) return; if (pMainForm->client() == nullptr) return; const QString sDriverName = sAudioDriver.toUpper(); // Save current device id. int iDeviceID = 0; int iAudioItem = m_ui.AudioDeviceComboBox->currentIndex(); if (iAudioItem >= 0) iDeviceID = m_ui.AudioDeviceComboBox->itemData(iAudioItem).toInt(); // Clean maplist. m_ui.AudioDeviceComboBox->clear(); qDeleteAll(m_audioDevices); m_audioDevices.clear(); // Populate with the current ones... Device *pDevice = nullptr; const QPixmap audioPixmap(":/images/audio2.png"); int *piDeviceIDs = Device::getDevices(pMainForm->client(), Device::Audio); for (int i = 0; piDeviceIDs && piDeviceIDs[i] >= 0; ++i) { pDevice = new Device(Device::Audio, piDeviceIDs[i]); if (pDevice->driverName().toUpper() == sDriverName) { const int iAudioDevice = pDevice->deviceID(); m_ui.AudioDeviceComboBox->addItem( audioPixmap, pDevice->deviceName()); m_ui.AudioDeviceComboBox->setItemData(i, iAudioDevice); m_audioDevices.insert(iAudioDevice, pDevice); if (iAudioDevice == iDeviceID) iAudioItem = i; } else { delete pDevice; } } // Do proper enabling... const bool bEnabled = !m_audioDevices.isEmpty(); if (bEnabled) { // Select the previous current device... m_ui.AudioDeviceComboBox->setCurrentIndex(iAudioItem); selectAudioDeviceItem(iAudioItem); } else { m_ui.AudioDeviceComboBox->insertItem(0, tr("(New Audio %1 device)").arg(sAudioDriver)); m_ui.AudioDeviceComboBox->setItemData(0, -1); } // m_ui.AudioDeviceTextLabel->setEnabled(bEnabled); // m_ui.AudioDeviceComboBox->setEnabled(bEnabled); m_ui.AudioRoutingTable->setEnabled(bEnabled); } // Refresh Audio device options slot. void ChannelForm::selectAudioDriver ( const QString& sAudioDriver ) { if (m_iDirtySetup > 0) return; selectAudioDriverItem(sAudioDriver); optionsChanged(); } // Select Audio device item. void ChannelForm::selectAudioDeviceItem ( int iAudioItem ) { Device *pDevice = nullptr; if (iAudioItem >= 0) { const int iAudioDevice = m_ui.AudioDeviceComboBox->itemData(iAudioItem).toInt(); pDevice = m_audioDevices.value(iAudioDevice, nullptr); } if (pDevice) { // Refresh the audio routing table. m_routingModel.refresh(pDevice, m_pChannel->audioRouting()); // Reset routing change map. m_routingModel.clear(); } } // Select Audio device options slot. void ChannelForm::selectAudioDevice ( int iAudioItem ) { if (m_iDirtySetup > 0) return; selectAudioDeviceItem(iAudioItem); optionsChanged(); } // Audio device options. void ChannelForm::setupAudioDevice (void) { Device *pDevice = nullptr; const int iAudioItem = m_ui.AudioDeviceComboBox->currentIndex(); if (iAudioItem >= 0) { const int iAudioDevice = m_ui.AudioDeviceComboBox->itemData(iAudioItem).toInt(); pDevice = m_audioDevices.value(iAudioDevice, nullptr); } setupDevice(pDevice, Device::Audio, m_ui.AudioDriverComboBox->currentText()); } // UPdate all device lists slot. void ChannelForm::updateDevices (void) { if (m_iDirtySetup > 0) return; selectMidiDriverItem(m_ui.MidiDriverComboBox->currentText()); selectAudioDriverItem(m_ui.AudioDriverComboBox->currentText()); optionsChanged(); } // Dirty up settings. void ChannelForm::optionsChanged (void) { if (m_iDirtySetup > 0) return; m_iDirtyCount++; stabilizeForm(); } // Stabilize current form state. void ChannelForm::stabilizeForm (void) { bool bValid = m_ui.EngineNameComboBox->currentIndex() >= 0 && m_ui.EngineNameComboBox->currentText() != Channel::noEngineName(); const QString& sPath = m_ui.InstrumentFileComboBox->currentText(); bValid = bValid && !sPath.isEmpty() && QFileInfo(sPath).exists(); m_ui.DialogButtonBox->button( QDialogButtonBox::Ok)->setEnabled(m_iDirtyCount > 0 && bValid); } void ChannelForm::updateTableCellRenderers (void) { const int rows = m_routingModel.rowCount(); const int cols = m_routingModel.columnCount(); updateTableCellRenderers( m_routingModel.index(0, 0), m_routingModel.index(rows - 1, cols - 1)); } void ChannelForm::updateTableCellRenderers ( const QModelIndex& topLeft, const QModelIndex& bottomRight ) { for (int r = topLeft.row(); r <= bottomRight.row(); r++) { for (int c = topLeft.column(); c <= bottomRight.column(); c++) { const QModelIndex index = m_routingModel.index(r, c); m_ui.AudioRoutingTable->openPersistentEditor(index); } } } } // namespace QSampler // end of qsamplerChannelForm.cpp