Merge branch 'master' into panning
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "libs/oboe"]
|
||||
path = libs/oboe
|
||||
url = https://github.com/google/oboe.git
|
101
ChangeLog
|
@ -1,12 +1,43 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
3.5.3git
|
||||
|
||||
TODO improve input channel mapping and introduce input/output gains with overrange to amplification (separate dialog, replace Pan, etc.)
|
||||
- correct unregister of headless server and RPP file creation on
|
||||
SIGINT/SIGTERM, coded by pljones (Tickets #130, #168)
|
||||
|
||||
TODO support internationalization
|
||||
- for CoreAudio and 4 channel input, support mixing channels 1&2 with 3&4
|
||||
|
||||
TODO sometimes I cannot see the central server in the server list
|
||||
- added bassoon/oboe/harp instrument icons created by dszgit;
|
||||
congas/bongo created by bspeer (Ticket #131)
|
||||
|
||||
- link to docs from application Help menu (Ticket #90)
|
||||
|
||||
- support Mac CoreAudio aggregated devices (Ticket #138)
|
||||
|
||||
- added translations: french by trebmuh, portuguese by Snayler, spanish by ignotus666 (Ticket #77)
|
||||
|
||||
- new design for the About dialog (Ticket #189)
|
||||
|
||||
- new command line option -d to disconnect all clients on shutdown of the server (Ticket #161)
|
||||
|
||||
- bug fix: for mono capture jack audio interface Jamulus complains it
|
||||
cannot make connections (Ticket #137)
|
||||
|
||||
- bug fix: fixed that Jamulus segfaults when jackd is restarted (Ticket #122, #127)
|
||||
|
||||
- bug fix: better handling of disconnect message in the client
|
||||
|
||||
|
||||
TODO check if Tickets #130, #168 are really solved by code from pljones
|
||||
|
||||
TODO WIP support internationalization
|
||||
|
||||
TODO implement panning for channels (Ticket #52, #145)
|
||||
|
||||
TODO show mute state of others
|
||||
|
||||
|
||||
|
||||
|
@ -15,73 +46,73 @@ TODO sometimes I cannot see the central server in the server list
|
|||
|
||||
3.5.2 (2020-04-24)
|
||||
|
||||
* use audio level meter bars for normal skin
|
||||
- use audio level meter bars for normal skin
|
||||
|
||||
* store Show All Musicians setting in the ini-file
|
||||
- store Show All Musicians setting in the ini-file
|
||||
|
||||
* improved Mac installer, coded by doloopuntil
|
||||
- improved Mac installer, coded by doloopuntil
|
||||
|
||||
* support to open ASIO driver setup(s) if startup failed due to incorrect driver settings (Ticket #117)
|
||||
- support to open ASIO driver setup(s) if startup failed due to incorrect driver settings (Ticket #117)
|
||||
|
||||
* added -v/--version command line argument to output version information (Ticket #121)
|
||||
- added -v/--version command line argument to output version information (Ticket #121)
|
||||
|
||||
* added bodhran and other instrument icons, bodhran created by bomm (Ticket #131)
|
||||
- added bodhran and other instrument icons, bodhran created by bomm (Ticket #131)
|
||||
|
||||
* bug fix: if small network buffers are used we get much better audio quality when drop outs occur
|
||||
- bug fix: if small network buffers are used we get much better audio quality when drop outs occur
|
||||
|
||||
* bug fix: if names given with the -o option were too long, the server registration failed (Ticket #91)
|
||||
- bug fix: if names given with the -o option were too long, the server registration failed (Ticket #91)
|
||||
|
||||
* bug fix: audio level changes if Buffer Delay is changed (Ticket #106)
|
||||
- bug fix: audio level changes if Buffer Delay is changed (Ticket #106)
|
||||
|
||||
* bug fix: do not reset fader level meters if number of clients change
|
||||
- bug fix: do not reset fader level meters if number of clients change
|
||||
|
||||
* bug fix: fixed a crash with JackRouter 64 bit ASIO driver (Ticket #93, thanks to elliotclee)
|
||||
- bug fix: fixed a crash with JackRouter 64 bit ASIO driver (Ticket #93, thanks to elliotclee)
|
||||
|
||||
|
||||
3.5.1 (2020-04-18)
|
||||
|
||||
* added a Mute Stream button to hear your signal and the signal of the other clients but
|
||||
do not transmit your signal to the server so that the other clients cannot hear you
|
||||
- added a Mute Stream button to hear your signal and the signal of the other clients but
|
||||
do not transmit your signal to the server so that the other clients cannot hear you
|
||||
|
||||
* added Enable Small Network Buffers switch to enable small sound card buffers in
|
||||
combination with legacy OPUS packets since OPUS packets with 64 samples enable low
|
||||
latency but can increase audio drop outs
|
||||
- added Enable Small Network Buffers switch to enable small sound card buffers in
|
||||
combination with legacy OPUS packets since OPUS packets with 64 samples enable low
|
||||
latency but can increase audio drop outs
|
||||
|
||||
* upgrade OPUS codec library to v1.3.1 by doloopuntil
|
||||
- upgrade OPUS codec library to v1.3.1 by doloopuntil
|
||||
|
||||
* server list registration status indicator added to the server GUI, coded by pljones
|
||||
- server list registration status indicator added to the server GUI, coded by pljones
|
||||
|
||||
* improved auto jitter buffer for 64 samples frame size
|
||||
- improved auto jitter buffer for 64 samples frame size
|
||||
|
||||
* the ping times in the server list are now more stable
|
||||
- the ping times in the server list are now more stable
|
||||
|
||||
|
||||
3.5.0 (2020-04-15)
|
||||
|
||||
* added support for 64 samples OPUS packets in the client (if a sound card buffer size
|
||||
larger or equal than 128 samples is chosen, the legacy 128 samples OPUS packets are used)
|
||||
- added support for 64 samples OPUS packets in the client (if a sound card buffer size
|
||||
larger or equal than 128 samples is chosen, the legacy 128 samples OPUS packets are used)
|
||||
|
||||
* added a filter for the server list to, e.g., filter a specific country or search for a musician
|
||||
- added a filter for the server list to, e.g., filter a specific country or search for a musician
|
||||
|
||||
* refresh server list if the Central Server address type is changed
|
||||
- refresh server list if the Central Server address type is changed
|
||||
|
||||
* the unit of the mixer faders is now dB using the range -50 dB to 0 dB
|
||||
- the unit of the mixer faders is now dB using the range -50 dB to 0 dB
|
||||
|
||||
* increased LED luminance (Ticket #71)
|
||||
- increased LED luminance (Ticket #71)
|
||||
|
||||
* bug fix: the server welcome message may appear twice if the server list was double clicked
|
||||
- bug fix: the server welcome message may appear twice if the server list was double clicked
|
||||
|
||||
|
||||
3.4.7 (2020-04-11)
|
||||
|
||||
* added support for alternative Central Servers to solve the 200 server registration limit (Ticket #50)
|
||||
- added support for alternative Central Servers to solve the 200 server registration limit (Ticket #50)
|
||||
|
||||
* added support for 64 samples frame size in the server (if server runs in 64 or 128 samples
|
||||
mode it is still compatible to both, 64 and 128 samples frame size clients)
|
||||
- added support for 64 samples frame size in the server (if server runs in 64 or 128 samples
|
||||
mode it is still compatible to both, 64 and 128 samples frame size clients)
|
||||
|
||||
* added multichannel CoreAudio support, coded by emlynmac (#44)
|
||||
- added multichannel CoreAudio support, coded by emlynmac (#44)
|
||||
|
||||
* fixed server not visible if in same local network, coded by pljones (Ticket #27)
|
||||
- fixed server not visible if in same local network, coded by pljones (Ticket #27)
|
||||
|
||||
|
||||
3.4.6 (2020-04-09)
|
||||
|
|
172
Jamulus.pro
|
@ -8,16 +8,17 @@ contains(CONFIG, "noupcasename") {
|
|||
|
||||
CONFIG += qt \
|
||||
thread \
|
||||
debug
|
||||
|
||||
CONFIG(debug, debug|release) { CONFIG += qt warn_on rtti exceptions }
|
||||
release \
|
||||
lrelease
|
||||
|
||||
QT += widgets \
|
||||
network \
|
||||
xml
|
||||
|
||||
#TRANSLATIONS = src/res/translation_de_DE.ts \
|
||||
# src/res/translation_fr_FR.ts
|
||||
TRANSLATIONS = src/res/translation/translation_de_DE.ts \
|
||||
src/res/translation/translation_fr_FR.ts \
|
||||
src/res/translation/translation_pt_PT.ts \
|
||||
src/res/translation/translation_es_ES.ts
|
||||
|
||||
INCLUDEPATH += src
|
||||
|
||||
|
@ -127,11 +128,138 @@ win32 {
|
|||
LIBS += /usr/local/lib/libjack.dylib
|
||||
}
|
||||
} else:android {
|
||||
# we want to compile with C++14
|
||||
CONFIG += c++14
|
||||
|
||||
QT += androidextras
|
||||
|
||||
# enabled only for debugging on android devices
|
||||
DEFINES += ANDROIDDEBUG
|
||||
|
||||
target.path = /tmp/your_executable # path on device
|
||||
INSTALLS += target
|
||||
|
||||
HEADERS += android/sound.h
|
||||
SOURCES += android/sound.cpp
|
||||
SOURCES += android/sound.cpp \
|
||||
android/androiddebug.cpp
|
||||
|
||||
LIBS += -lOpenSLES
|
||||
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
|
||||
OTHER_FILES += android/AndroidManifest.xml
|
||||
|
||||
# if compiling for android you need to use Oboe library which is included as a git submodule
|
||||
# make sure you git pull with submodules to pull the latest Oboe library
|
||||
OBOE_SOURCES = libs/oboe/src/aaudio/AAudioLoader.cpp \
|
||||
libs/oboe/src/aaudio/AudioStreamAAudio.cpp \
|
||||
libs/oboe/src/common/AudioSourceCaller.cpp \
|
||||
libs/oboe/src/common/AudioStream.cpp \
|
||||
libs/oboe/src/common/AudioStreamBuilder.cpp \
|
||||
libs/oboe/src/common/DataConversionFlowGraph.cpp \
|
||||
libs/oboe/src/common/FilterAudioStream.cpp \
|
||||
libs/oboe/src/common/FixedBlockAdapter.cpp \
|
||||
libs/oboe/src/common/FixedBlockReader.cpp \
|
||||
libs/oboe/src/common/FixedBlockWriter.cpp \
|
||||
libs/oboe/src/common/LatencyTuner.cpp \
|
||||
libs/oboe/src/common/QuirksManager.cpp \
|
||||
libs/oboe/src/common/SourceFloatCaller.cpp \
|
||||
libs/oboe/src/common/SourceI16Caller.cpp \
|
||||
libs/oboe/src/common/StabilizedCallback.cpp \
|
||||
libs/oboe/src/common/Trace.cpp \
|
||||
libs/oboe/src/common/Utilities.cpp \
|
||||
libs/oboe/src/common/Version.cpp \
|
||||
libs/oboe/src/fifo/FifoBuffer.cpp \
|
||||
libs/oboe/src/fifo/FifoController.cpp \
|
||||
libs/oboe/src/fifo/FifoControllerBase.cpp \
|
||||
libs/oboe/src/fifo/FifoControllerIndirect.cpp \
|
||||
libs/oboe/src/flowgraph/ClipToRange.cpp \
|
||||
libs/oboe/src/flowgraph/FlowGraphNode.cpp \
|
||||
libs/oboe/src/flowgraph/ManyToMultiConverter.cpp \
|
||||
libs/oboe/src/flowgraph/MonoToMultiConverter.cpp \
|
||||
libs/oboe/src/flowgraph/RampLinear.cpp \
|
||||
libs/oboe/src/flowgraph/SampleRateConverter.cpp \
|
||||
libs/oboe/src/flowgraph/SinkFloat.cpp \
|
||||
libs/oboe/src/flowgraph/SinkI16.cpp \
|
||||
libs/oboe/src/flowgraph/SinkI24.cpp \
|
||||
libs/oboe/src/flowgraph/SourceFloat.cpp \
|
||||
libs/oboe/src/flowgraph/SourceI16.cpp \
|
||||
libs/oboe/src/flowgraph/SourceI24.cpp \
|
||||
libs/oboe/src/flowgraph/resampler/IntegerRatio.cpp \
|
||||
libs/oboe/src/flowgraph/resampler/LinearResampler.cpp \
|
||||
libs/oboe/src/flowgraph/resampler/MultiChannelResampler.cpp \
|
||||
libs/oboe/src/flowgraph/resampler/PolyphaseResampler.cpp \
|
||||
libs/oboe/src/flowgraph/resampler/PolyphaseResamplerMono.cpp \
|
||||
libs/oboe/src/flowgraph/resampler/PolyphaseResamplerStereo.cpp \
|
||||
libs/oboe/src/flowgraph/resampler/SincResampler.cpp \
|
||||
libs/oboe/src/flowgraph/resampler/SincResamplerStereo.cpp \
|
||||
libs/oboe/src/opensles/AudioInputStreamOpenSLES.cpp \
|
||||
libs/oboe/src/opensles/AudioOutputStreamOpenSLES.cpp \
|
||||
libs/oboe/src/opensles/AudioStreamBuffered.cpp \
|
||||
libs/oboe/src/opensles/AudioStreamOpenSLES.cpp \
|
||||
libs/oboe/src/opensles/EngineOpenSLES.cpp \
|
||||
libs/oboe/src/opensles/OpenSLESUtilities.cpp \
|
||||
libs/oboe/src/opensles/OutputMixerOpenSLES.cpp
|
||||
|
||||
OBOE_HEADERS = libs/oboe/src/aaudio/AAudioLoader.h \
|
||||
libs/oboe/src/aaudio/AudioStreamAAudio.h \
|
||||
libs/oboe/src/common/AudioClock.h \
|
||||
libs/oboe/src/common/AudioSourceCaller.h \
|
||||
libs/oboe/src/common/DataConversionFlowGraph.h \
|
||||
libs/oboe/src/common/FilterAudioStream.h \
|
||||
libs/oboe/src/common/FixedBlockAdapter.h \
|
||||
libs/oboe/src/common/FixedBlockReader.h \
|
||||
libs/oboe/src/common/FixedBlockWriter.h \
|
||||
libs/oboe/src/common/MonotonicCounter.h \
|
||||
libs/oboe/src/common/OboeDebug.h \
|
||||
libs/oboe/src/common/QuirksManager.h \
|
||||
libs/oboe/src/common/SourceFloatCaller.h \
|
||||
libs/oboe/src/common/SourceI16Caller.h \
|
||||
libs/oboe/src/common/Trace.h \
|
||||
libs/oboe/src/fifo/FifoBuffer.h \
|
||||
libs/oboe/src/fifo/FifoController.h \
|
||||
libs/oboe/src/fifo/FifoControllerBase.h \
|
||||
libs/oboe/src/fifo/FifoControllerIndirect.h \
|
||||
libs/oboe/src/flowgraph/ClipToRange.h \
|
||||
libs/oboe/src/flowgraph/FlowGraphNode.h \
|
||||
libs/oboe/src/flowgraph/ManyToMultiConverter.h \
|
||||
libs/oboe/src/flowgraph/MonoToMultiConverter.h \
|
||||
libs/oboe/src/flowgraph/RampLinear.h \
|
||||
libs/oboe/src/flowgraph/SampleRateConverter.h \
|
||||
libs/oboe/src/flowgraph/SinkFloat.h \
|
||||
libs/oboe/src/flowgraph/SinkI16.h \
|
||||
libs/oboe/src/flowgraph/SinkI24.h \
|
||||
libs/oboe/src/flowgraph/SourceFloat.h \
|
||||
libs/oboe/src/flowgraph/SourceI16.h \
|
||||
libs/oboe/src/flowgraph/SourceI24.h \
|
||||
libs/oboe/src/flowgraph/resampler/HyperbolicCosineWindow.h \
|
||||
libs/oboe/src/flowgraph/resampler/IntegerRatio.h \
|
||||
libs/oboe/src/flowgraph/resampler/LinearResampler.h \
|
||||
libs/oboe/src/flowgraph/resampler/MultiChannelResampler.h \
|
||||
libs/oboe/src/flowgraph/resampler/PolyphaseResampler.h \
|
||||
libs/oboe/src/flowgraph/resampler/PolyphaseResamplerMono.h \
|
||||
libs/oboe/src/flowgraph/resampler/PolyphaseResamplerStereo.h \
|
||||
libs/oboe/src/flowgraph/resampler/SincResampler.h \
|
||||
libs/oboe/src/flowgraph/resampler/SincResamplerStereo.h \
|
||||
libs/oboe/src/opensles/AudioInputStreamOpenSLES.h \
|
||||
libs/oboe/src/opensles/AudioOutputStreamOpenSLES.h \
|
||||
libs/oboe/src/opensles/AudioStreamBuffered.h \
|
||||
libs/oboe/src/opensles/AudioStreamOpenSLES.h \
|
||||
libs/oboe/src/opensles/EngineOpenSLES.h \
|
||||
libs/oboe/src/opensles/OpenSLESUtilities.h \
|
||||
libs/oboe/src/opensles/OutputMixerOpenSLES.h
|
||||
|
||||
INCLUDEPATH_OBOE = libs/oboe/include/ \
|
||||
libs/oboe/src/
|
||||
|
||||
DISTFILES_OBOE += libs/oboe/AUTHORS \
|
||||
libs/oboe/CONTRIBUTING \
|
||||
libs/oboe/LICENSE \
|
||||
libs/oboe/README
|
||||
|
||||
INCLUDEPATH += $$INCLUDEPATH_OBOE
|
||||
HEADERS += $$OBOE_HEADERS
|
||||
SOURCES += $$OBOE_SOURCES
|
||||
DISTFILES += $$DISTFILES_OBOE
|
||||
|
||||
} else:unix {
|
||||
# we want to compile with C++11
|
||||
QMAKE_CXXFLAGS += -std=c++11
|
||||
|
@ -147,8 +275,14 @@ win32 {
|
|||
nosoundoption = $$find(CONFIG, "nosound")
|
||||
count(nosoundoption, 0) {
|
||||
message(Jack Audio Interface Enabled.)
|
||||
CONFIG += link_pkgconfig
|
||||
PKGCONFIG += jack
|
||||
|
||||
contains(CONFIG, "raspijamulus") {
|
||||
message(Using Jack Audio in raspijamulus.sh mode.)
|
||||
LIBS += -ljack
|
||||
} else {
|
||||
CONFIG += link_pkgconfig
|
||||
PKGCONFIG += jack
|
||||
}
|
||||
|
||||
HEADERS += linux/sound.h
|
||||
SOURCES += linux/sound.cpp
|
||||
|
@ -203,7 +337,8 @@ HEADERS += src/audiomixerboard.h \
|
|||
src/recorder/jamrecorder.h \
|
||||
src/recorder/creaperproject.h \
|
||||
src/recorder/cwavestream.h \
|
||||
src/historygraph.h
|
||||
src/historygraph.h \
|
||||
src/signalhandler.h
|
||||
|
||||
HEADERS_OPUS = libs/opus/celt/arch.h \
|
||||
libs/opus/celt/bands.h \
|
||||
|
@ -317,6 +452,7 @@ SOURCES += src/audiomixerboard.cpp \
|
|||
src/serverlist.cpp \
|
||||
src/serverlogging.cpp \
|
||||
src/settings.cpp \
|
||||
src/signalhandler.cpp \
|
||||
src/socket.cpp \
|
||||
src/soundbase.cpp \
|
||||
src/util.cpp \
|
||||
|
@ -485,6 +621,12 @@ DISTFILES += ChangeLog \
|
|||
COPYING \
|
||||
INSTALL.md \
|
||||
README.md \
|
||||
android/build.gradle \
|
||||
android/gradle/wrapper/gradle-wrapper.jar \
|
||||
android/gradle/wrapper/gradle-wrapper.properties \
|
||||
android/gradlew \
|
||||
android/gradlew.bat \
|
||||
android/res/values/libs.xml \
|
||||
src/res/CLEDBlack.png \
|
||||
src/res/CLEDBlackSmall.png \
|
||||
src/res/CLEDDisabledSmall.png \
|
||||
|
@ -512,7 +654,6 @@ DISTFILES += ChangeLog \
|
|||
src/res/ledbuttonnotpressed.png \
|
||||
src/res/ledbuttonpressed.png \
|
||||
src/res/fronticon.png \
|
||||
src/res/logopicture.png \
|
||||
src/res/mainicon.png \
|
||||
src/res/mixerboardbackground.png \
|
||||
src/res/VLEDBlack.png \
|
||||
|
@ -566,6 +707,17 @@ DISTFILES += ChangeLog \
|
|||
src/res/instruments/instrkeyboardvocal.png \
|
||||
src/res/instruments/bodhran.svg \
|
||||
src/res/instruments/bodhran.png \
|
||||
src/res/instruments/bassoon.svg \
|
||||
src/res/instruments/bassoon.png \
|
||||
src/res/instruments/oboe.svg \
|
||||
src/res/instruments/oboe.png \
|
||||
src/res/instruments/harp.svg \
|
||||
src/res/instruments/harp.png \
|
||||
src/res/instruments/viola.png \
|
||||
src/res/instruments/congas.svg \
|
||||
src/res/instruments/congas.png \
|
||||
src/res/instruments/bongo.svg \
|
||||
src/res/instruments/bongo.png \
|
||||
src/res/flags/flagnone.png \
|
||||
src/res/flags/ad.png \
|
||||
src/res/flags/ae.png \
|
||||
|
|
|
@ -1,41 +1,94 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<manifest android:versionName="1.0" android:installLocation="auto" package="org.qtproject.jamulus" android:versionCode="1" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application android:label="Jamulus" android:name="org.qtproject.qt5.android.bindings.QtApplication">
|
||||
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|locale|fontScale|keyboard|keyboardHidden|navigation" android:label="@string/app_name" android:screenOrientation="landscape" android:name="org.qtproject.qt5.android.bindings.QtActivity">
|
||||
<?xml version="1.0"?>
|
||||
<manifest package="org.qtproject.jamulus" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" android:versionCode="1" android:installLocation="auto">
|
||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/>
|
||||
|
||||
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
|
||||
Remove the comment if you do not require these default permissions. -->
|
||||
<!-- %%INSERT_PERMISSIONS -->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
|
||||
|
||||
<!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
|
||||
Remove the comment if you do not require these default features. -->
|
||||
<!-- %%INSERT_FEATURES -->
|
||||
<uses-feature android:name="android.hardware.microphone" android:required="true"/>
|
||||
<uses-feature android:name="android.hardware.audio.output" android:required="true"/>
|
||||
|
||||
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
|
||||
|
||||
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="Jamulus" android:extractNativeLibs="true">
|
||||
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="@string/app_name" android:screenOrientation="landscape" android:launchMode="singleTop">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
<meta-data android:value="Jamulus" android:name="android.app.lib_name"/>
|
||||
<meta-data android:resource="@array/qt_sources" android:name="android.app.qt_sources_resource_id"/>
|
||||
<meta-data android:value="default" android:name="android.app.repository"/>
|
||||
<meta-data android:resource="@array/qt_libs" android:name="android.app.qt_libs_resource_id"/>
|
||||
<meta-data android:resource="@array/bundled_libs" android:name="android.app.bundled_libs_resource_id"/>
|
||||
|
||||
<!-- Application arguments -->
|
||||
<!-- meta-data android:name="android.app.arguments" android:value="arg1 arg2 arg3"/ -->
|
||||
<!-- Application arguments -->
|
||||
|
||||
<meta-data android:name="android.app.lib_name" android:value="Jamulus"/>
|
||||
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
|
||||
<meta-data android:name="android.app.repository" android:value="default"/>
|
||||
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
|
||||
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
|
||||
<!-- Deploy Qt libs as part of package -->
|
||||
<meta-data android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --" android:name="android.app.bundle_local_qt_libs"/>
|
||||
<meta-data android:resource="@array/bundled_in_lib" android:name="android.app.bundled_in_lib_resource_id"/>
|
||||
<meta-data android:resource="@array/bundled_in_assets" android:name="android.app.bundled_in_assets_resource_id"/>
|
||||
<meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
|
||||
|
||||
<!-- Run with local libs -->
|
||||
<meta-data android:value="-- %%USE_LOCAL_QT_LIBS%% --" android:name="android.app.use_local_qt_libs"/>
|
||||
<meta-data android:value="/data/local/tmp/qt/" android:name="android.app.libs_prefix"/>
|
||||
<meta-data android:value="-- %%INSERT_LOCAL_LIBS%% --" android:name="android.app.load_local_libs"/>
|
||||
<meta-data android:value="-- %%INSERT_LOCAL_JARS%% --" android:name="android.app.load_local_jars"/>
|
||||
<meta-data android:value="-- %%INSERT_INIT_CLASSES%% --" android:name="android.app.static_init_classes"/>
|
||||
<meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
|
||||
<meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
|
||||
<meta-data android:name="android.app.load_local_libs_resource_id" android:resource="@array/load_local_libs"/>
|
||||
<meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
|
||||
<meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
|
||||
<!-- Used to specify custom system library path to run with local system libs -->
|
||||
<!-- <meta-data android:name="android.app.system_libs_prefix" android:value="/system/lib/"/> -->
|
||||
<!-- Messages maps -->
|
||||
<meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
|
||||
<meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
|
||||
<meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
|
||||
<meta-data android:value="@string/unsupported_android_version" android:name="android.app.unsupported_android_version"/>
|
||||
<!-- Messages maps -->
|
||||
|
||||
<!-- Splash screen -->
|
||||
<meta-data android:resource="@layout/splash" android:name="android.app.splash_screen"/>
|
||||
<!-- Orientation-specific (portrait/landscape) data is checked first. If not available for current orientation,
|
||||
then android.app.splash_screen_drawable. For best results, use together with splash_screen_sticky and
|
||||
use hideSplashScreen() with a fade-out animation from Qt Android Extras to hide the splash screen when you
|
||||
are done populating your window with content. -->
|
||||
<!-- meta-data android:name="android.app.splash_screen_drawable_portrait" android:resource="@drawable/logo_portrait" / -->
|
||||
<!-- meta-data android:name="android.app.splash_screen_drawable_landscape" android:resource="@drawable/logo_landscape" / -->
|
||||
<!-- meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/ -->
|
||||
<!-- meta-data android:name="android.app.splash_screen_sticky" android:value="true"/ -->
|
||||
<!-- Splash screen -->
|
||||
</activity>
|
||||
|
||||
<!-- Background running -->
|
||||
<!-- Warning: changing this value to true may cause unexpected crashes if the
|
||||
application still try to draw after
|
||||
"applicationStateChanged(Qt::ApplicationSuspended)"
|
||||
signal is sent! -->
|
||||
<meta-data android:name="android.app.background_running" android:value="false"/>
|
||||
<!-- Background running -->
|
||||
|
||||
<!-- auto screen scale factor -->
|
||||
<meta-data android:name="android.app.auto_screen_scale_factor" android:value="false"/>
|
||||
<!-- auto screen scale factor -->
|
||||
|
||||
<!-- extract android style -->
|
||||
<!-- available android:values :
|
||||
* default - In most cases this will be the same as "full", but it can also be something else if needed, e.g., for compatibility reasons
|
||||
* full - useful QWidget & Quick Controls 1 apps
|
||||
* minimal - useful for Quick Controls 2 apps, it is much faster than "full"
|
||||
* none - useful for apps that don't use any of the above Qt modules
|
||||
-->
|
||||
<meta-data android:name="android.app.extract_android_style" android:value="default"/>
|
||||
<!-- extract android style -->
|
||||
</activity>
|
||||
|
||||
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
|
||||
|
||||
</application>
|
||||
<uses-sdk android:targetSdkVersion="19" android:minSdkVersion="17"/>
|
||||
<supports-screens android:normalScreens="true" android:smallScreens="true" android:largeScreens="true" android:anyDensity="true"/>
|
||||
<!-- %%INSERT_PERMISSIONS -->
|
||||
<!-- %%INSERT_FEATURES -->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
|
||||
</manifest>
|
||||
|
|
45
android/androiddebug.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
const char*const applicationName="Jamulus";
|
||||
|
||||
#ifdef ANDROIDDEBUG // Set in my myapp.pro file for android builds
|
||||
#include <android/log.h>
|
||||
#include <QString>
|
||||
#include <QEvent>
|
||||
#include <QDebug>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string>
|
||||
|
||||
void myMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg)
|
||||
{
|
||||
QString report=msg;
|
||||
if (context.file && !QString(context.file).isEmpty()) {
|
||||
report+=" in file ";
|
||||
report+=QString(context.file);
|
||||
report+=" line ";
|
||||
report+=QString::number(context.line);
|
||||
}
|
||||
if (context.function && !QString(context.function).isEmpty()) {
|
||||
report+=+" function ";
|
||||
report+=QString(context.function);
|
||||
}
|
||||
const char*const local=report.toLocal8Bit().constData();
|
||||
switch (type) {
|
||||
case QtDebugMsg:
|
||||
__android_log_write(ANDROID_LOG_DEBUG,applicationName,local);
|
||||
break;
|
||||
case QtInfoMsg:
|
||||
__android_log_write(ANDROID_LOG_INFO,applicationName,local);
|
||||
break;
|
||||
case QtWarningMsg:
|
||||
__android_log_write(ANDROID_LOG_WARN,applicationName,local);
|
||||
break;
|
||||
case QtCriticalMsg:
|
||||
__android_log_write(ANDROID_LOG_ERROR,applicationName,local);
|
||||
break;
|
||||
case QtFatalMsg:
|
||||
default:
|
||||
__android_log_write(ANDROID_LOG_FATAL,applicationName,local);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -2,7 +2,7 @@
|
|||
* Copyright (c) 2004-2020
|
||||
*
|
||||
* Author(s):
|
||||
* Volker Fischer
|
||||
* Simon Tomlinson
|
||||
*
|
||||
******************************************************************************
|
||||
*
|
||||
|
@ -23,255 +23,157 @@
|
|||
\******************************************************************************/
|
||||
|
||||
#include "sound.h"
|
||||
|
||||
#include "androiddebug.cpp"
|
||||
|
||||
/* Implementation *************************************************************/
|
||||
CSound::CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, void* arg ),
|
||||
void* arg,
|
||||
const int iCtrlMIDIChannel,
|
||||
const bool bNoAutoJackConnect ) :
|
||||
CSoundBase ( "OpenSL", true, fpNewProcessCallback, arg, iCtrlMIDIChannel, bNoAutoJackConnect )
|
||||
|
||||
CSound::CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, void* arg ),
|
||||
void* arg,
|
||||
const int iCtrlMIDIChannel,
|
||||
const bool ,
|
||||
const QString& ) :
|
||||
CSoundBase ( "OpenSL", true, fpNewProcessCallback, arg, iCtrlMIDIChannel )
|
||||
|
||||
{
|
||||
pSound = this;
|
||||
#ifdef ANDROIDDEBUG
|
||||
qInstallMessageHandler(myMessageHandler);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CSound::setupCommonStreamParams(oboe::AudioStreamBuilder *builder)
|
||||
{
|
||||
// We request EXCLUSIVE mode since this will give us the lowest possible
|
||||
// latency. If EXCLUSIVE mode isn't available the builder will fall back to SHARED mode
|
||||
builder->setCallback(this)
|
||||
->setFormat(oboe::AudioFormat::Float)
|
||||
->setSharingMode(oboe::SharingMode::Shared)
|
||||
->setChannelCount(oboe::ChannelCount::Mono)
|
||||
// ->setSampleRate(48000)
|
||||
// ->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::Medium)
|
||||
->setPerformanceMode(oboe::PerformanceMode::None);
|
||||
return;
|
||||
}
|
||||
|
||||
void CSound::openStreams()
|
||||
{
|
||||
// Create callback
|
||||
mCallback = this;
|
||||
|
||||
//Setup output stream
|
||||
oboe::AudioStreamBuilder inBuilder, outBuilder;
|
||||
outBuilder.setDirection(oboe::Direction::Output);
|
||||
setupCommonStreamParams(&outBuilder);
|
||||
oboe::Result result = outBuilder.openManagedStream(mPlayStream);
|
||||
if (result != oboe::Result::OK) {
|
||||
return;
|
||||
}
|
||||
mPlayStream->setBufferSizeInFrames(pSound->iOpenSLBufferSizeStereo);
|
||||
|
||||
warnIfNotLowLatency(mPlayStream, "PlayStream");
|
||||
printStreamDetails(mPlayStream);
|
||||
|
||||
//Setup input stream
|
||||
inBuilder.setDirection(oboe::Direction::Input);
|
||||
setupCommonStreamParams(&inBuilder);
|
||||
result = inBuilder.openManagedStream(mRecordingStream);
|
||||
if (result != oboe::Result::OK) {
|
||||
closeStream(mPlayStream);
|
||||
return;
|
||||
}
|
||||
mRecordingStream->setBufferSizeInFrames(pSound->iOpenSLBufferSizeStereo);
|
||||
|
||||
warnIfNotLowLatency(mRecordingStream, "RecordStream");
|
||||
printStreamDetails(mRecordingStream);
|
||||
}
|
||||
|
||||
void CSound::printStreamDetails(oboe::ManagedStream &stream)
|
||||
{
|
||||
|
||||
QString sDirection = (stream->getDirection()==oboe::Direction::Input?"Input":"Output");
|
||||
QString sFramesPerBurst = QString::number(stream->getFramesPerBurst());
|
||||
QString sBufferSizeInFrames = QString::number(stream->getBufferSizeInFrames());
|
||||
QString sBytesPerFrame = QString::number(stream->getBytesPerFrame());
|
||||
QString sBytesPerSample = QString::number(stream->getBytesPerSample());
|
||||
QString sBufferCapacityInFrames = QString::number(stream->getBufferCapacityInFrames());
|
||||
QString sPerformanceMode = (stream->getPerformanceMode()==oboe::PerformanceMode::LowLatency?"LowLatency":"NotLowLatency");
|
||||
QString sSharingMode = (stream->getSharingMode() == oboe::SharingMode::Exclusive?"Exclusive":"Shared");
|
||||
QString sDeviceID = QString::number(stream->getDeviceId());
|
||||
QString sSampleRate = QString::number(stream->getSampleRate());
|
||||
QString sAudioFormat = (stream->getFormat()==oboe::AudioFormat::I16?"I16":"Float");
|
||||
|
||||
QString sFramesPerCallback = QString::number(stream->getFramesPerCallback());
|
||||
//QString sSampleRateConversionQuality = (stream.getSampleRateConversionQuality()==oboe::SampleRateConversionQuality::
|
||||
|
||||
qInfo() << "Stream details: [sDirection: " << sDirection <<
|
||||
", FramesPerBurst: " << sFramesPerBurst <<
|
||||
", BufferSizeInFrames: " << sBufferSizeInFrames <<
|
||||
", BytesPerFrame: " << sBytesPerFrame <<
|
||||
", BytesPerSample: " << sBytesPerSample <<
|
||||
", BufferCapacityInFrames: " << sBufferCapacityInFrames <<
|
||||
", PerformanceMode: " << sPerformanceMode <<
|
||||
", SharingMode: " << sSharingMode <<
|
||||
", DeviceID: " << sDeviceID <<
|
||||
", SampleRate: " << sSampleRate <<
|
||||
", AudioFormat: " << sAudioFormat <<
|
||||
", FramesPerCallback: " << sFramesPerCallback << "]";
|
||||
|
||||
}
|
||||
|
||||
void CSound::InitializeOpenSL()
|
||||
{
|
||||
// set up stream formats for input and output
|
||||
SLDataFormat_PCM inStreamFormat;
|
||||
inStreamFormat.formatType = SL_DATAFORMAT_PCM;
|
||||
inStreamFormat.numChannels = 1;
|
||||
inStreamFormat.samplesPerSec = SL_SAMPLINGRATE_16;
|
||||
inStreamFormat.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
|
||||
inStreamFormat.containerSize = 16;
|
||||
inStreamFormat.channelMask = SL_SPEAKER_FRONT_CENTER;
|
||||
inStreamFormat.endianness = SL_BYTEORDER_LITTLEENDIAN;
|
||||
|
||||
SLDataFormat_PCM outStreamFormat;
|
||||
outStreamFormat.formatType = SL_DATAFORMAT_PCM;
|
||||
outStreamFormat.numChannels = 2;
|
||||
outStreamFormat.samplesPerSec = SYSTEM_SAMPLE_RATE_HZ * 1000; // unit is mHz
|
||||
outStreamFormat.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
|
||||
outStreamFormat.containerSize = 16;
|
||||
outStreamFormat.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
|
||||
outStreamFormat.endianness = SL_BYTEORDER_LITTLEENDIAN;
|
||||
|
||||
// create the OpenSL root engine object
|
||||
slCreateEngine ( &engineObject,
|
||||
0,
|
||||
nullptr,
|
||||
0,
|
||||
nullptr,
|
||||
nullptr );
|
||||
|
||||
// realize the engine
|
||||
(*engineObject)->Realize ( engineObject,
|
||||
SL_BOOLEAN_FALSE );
|
||||
|
||||
// get the engine interface (required to create other objects)
|
||||
(*engineObject)->GetInterface ( engineObject,
|
||||
SL_IID_ENGINE,
|
||||
&engine );
|
||||
|
||||
// create the main output mix
|
||||
(*engine)->CreateOutputMix ( engine,
|
||||
&outputMixObject,
|
||||
0,
|
||||
nullptr,
|
||||
nullptr );
|
||||
|
||||
// realize the output mix
|
||||
(*outputMixObject)->Realize ( outputMixObject,
|
||||
SL_BOOLEAN_FALSE );
|
||||
|
||||
// configure the audio (data) source for input
|
||||
SLDataLocator_IODevice micLocator;
|
||||
micLocator.locatorType = SL_DATALOCATOR_IODEVICE;
|
||||
micLocator.deviceType = SL_IODEVICE_AUDIOINPUT;
|
||||
micLocator.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
|
||||
micLocator.device = nullptr;
|
||||
|
||||
SLDataSource inDataSource;
|
||||
inDataSource.pLocator = &micLocator;
|
||||
inDataSource.pFormat = nullptr;
|
||||
|
||||
// configure the input buffer queue
|
||||
SLDataLocator_AndroidSimpleBufferQueue inBufferQueue;
|
||||
inBufferQueue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
|
||||
inBufferQueue.numBuffers = 2; // max number of buffers in queue
|
||||
|
||||
// configure the audio (data) sink for input
|
||||
SLDataSink inDataSink;
|
||||
inDataSink.pLocator = &inBufferQueue;
|
||||
inDataSink.pFormat = &inStreamFormat;
|
||||
|
||||
// create the audio recorder
|
||||
const SLInterfaceID recorderIds[] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
|
||||
const SLboolean recorderReq[] = { SL_BOOLEAN_TRUE };
|
||||
|
||||
(*engine)->CreateAudioRecorder ( engine,
|
||||
&recorderObject,
|
||||
&inDataSource,
|
||||
&inDataSink,
|
||||
1,
|
||||
recorderIds,
|
||||
recorderReq );
|
||||
|
||||
// realize the audio recorder
|
||||
(*recorderObject)->Realize ( recorderObject,
|
||||
SL_BOOLEAN_FALSE );
|
||||
|
||||
// get the audio recorder interface
|
||||
(*recorderObject)->GetInterface ( recorderObject,
|
||||
SL_IID_RECORD,
|
||||
&recorder );
|
||||
|
||||
// get the audio recorder simple buffer queue interface
|
||||
(*recorderObject)->GetInterface ( recorderObject,
|
||||
SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
|
||||
&recorderSimpleBufQueue );
|
||||
|
||||
// register the audio input callback
|
||||
(*recorderSimpleBufQueue)->RegisterCallback ( recorderSimpleBufQueue,
|
||||
processInput,
|
||||
this );
|
||||
|
||||
// configure the output buffer queue
|
||||
SLDataLocator_AndroidSimpleBufferQueue outBufferQueue;
|
||||
outBufferQueue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
|
||||
outBufferQueue.numBuffers = 2; // max number of buffers in queue
|
||||
|
||||
// configure the audio (data) source for output
|
||||
SLDataSource outDataSource;
|
||||
outDataSource.pLocator = &outBufferQueue;
|
||||
outDataSource.pFormat = &outStreamFormat;
|
||||
|
||||
// configure the output mix
|
||||
SLDataLocator_OutputMix outputMix;
|
||||
outputMix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
|
||||
outputMix.outputMix = outputMixObject;
|
||||
|
||||
// configure the audio (data) sink for output
|
||||
SLDataSink outDataSink;
|
||||
outDataSink.pLocator = &outputMix;
|
||||
outDataSink.pFormat = nullptr;
|
||||
|
||||
// create the audio player
|
||||
const SLInterfaceID playerIds[] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
|
||||
const SLboolean playerReq[] = { SL_BOOLEAN_TRUE };
|
||||
|
||||
(*engine)->CreateAudioPlayer ( engine,
|
||||
&playerObject,
|
||||
&outDataSource,
|
||||
&outDataSink,
|
||||
1,
|
||||
playerIds,
|
||||
playerReq );
|
||||
|
||||
// realize the audio player
|
||||
(*playerObject)->Realize ( playerObject,
|
||||
SL_BOOLEAN_FALSE );
|
||||
|
||||
// get the audio player interface
|
||||
(*playerObject)->GetInterface ( playerObject,
|
||||
SL_IID_PLAY,
|
||||
&player );
|
||||
|
||||
// get the audio player simple buffer queue interface
|
||||
(*playerObject)->GetInterface ( playerObject,
|
||||
SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
|
||||
&playerSimpleBufQueue );
|
||||
|
||||
// register the audio output callback
|
||||
(*playerSimpleBufQueue)->RegisterCallback ( playerSimpleBufQueue,
|
||||
processOutput,
|
||||
this );
|
||||
void CSound::warnIfNotLowLatency(oboe::ManagedStream &stream, QString streamName) {
|
||||
if (stream->getPerformanceMode() != oboe::PerformanceMode::LowLatency) {
|
||||
QString latencyMode = (stream->getPerformanceMode()==oboe::PerformanceMode::None ? "None" : "Power Saving");
|
||||
// throw CGenErr ( tr ( "Stream is NOT low latency."
|
||||
// "Check your requested format, sample rate and channel count." ) );
|
||||
}
|
||||
}
|
||||
|
||||
void CSound::CloseOpenSL()
|
||||
void CSound::closeStream(oboe::ManagedStream &stream)
|
||||
{
|
||||
if (stream) {
|
||||
oboe::Result requestStopRes = stream->requestStop();
|
||||
oboe::Result result = stream->close();
|
||||
if (result != oboe::Result::OK) {
|
||||
throw CGenErr ( tr ( "Error closing stream: $s",
|
||||
oboe::convertToText(result) ) );
|
||||
}
|
||||
stream.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void CSound::closeStreams()
|
||||
{
|
||||
// clean up
|
||||
(*recorderObject)->Destroy ( recorderObject );
|
||||
(*playerObject)->Destroy ( playerObject );
|
||||
(*outputMixObject)->Destroy ( outputMixObject );
|
||||
(*engineObject)->Destroy ( engineObject );
|
||||
closeStream(mRecordingStream);
|
||||
closeStream(mPlayStream);
|
||||
}
|
||||
|
||||
void CSound::Start()
|
||||
{
|
||||
InitializeOpenSL();
|
||||
|
||||
// TEST We have to supply the interface with initial buffers, otherwise
|
||||
// the rendering will not start.
|
||||
// Note that the number of buffers enqueued here must match the maximum
|
||||
// numbers of buffers configured in the constructor of this class.
|
||||
vecsTmpAudioSndCrdStereo.Reset ( 0 );
|
||||
|
||||
// enqueue initial buffers for record
|
||||
(*recorderSimpleBufQueue)->Enqueue ( recorderSimpleBufQueue,
|
||||
&vecsTmpAudioSndCrdStereo[0],
|
||||
iOpenSLBufferSizeStereo * 2 /* 2 bytes */ );
|
||||
|
||||
(*recorderSimpleBufQueue)->Enqueue ( recorderSimpleBufQueue,
|
||||
&vecsTmpAudioSndCrdStereo[0],
|
||||
iOpenSLBufferSizeStereo * 2 /* 2 bytes */ );
|
||||
|
||||
// enqueue initial buffers for playback
|
||||
(*playerSimpleBufQueue)->Enqueue ( playerSimpleBufQueue,
|
||||
&vecsTmpAudioSndCrdStereo[0],
|
||||
iOpenSLBufferSizeStereo * 2 /* 2 bytes */ );
|
||||
|
||||
(*playerSimpleBufQueue)->Enqueue ( playerSimpleBufQueue,
|
||||
&vecsTmpAudioSndCrdStereo[0],
|
||||
iOpenSLBufferSizeStereo * 2 /* 2 bytes */ );
|
||||
|
||||
// start the rendering
|
||||
(*recorder)->SetRecordState ( recorder, SL_RECORDSTATE_RECORDING );
|
||||
(*player)->SetPlayState ( player, SL_PLAYSTATE_PLAYING );
|
||||
openStreams();
|
||||
|
||||
// call base class
|
||||
CSoundBase::Start();
|
||||
|
||||
// finally start the streams so the callback begins, start with inputstream first.
|
||||
mRecordingStream->requestStart();
|
||||
mPlayStream->requestStart();
|
||||
|
||||
}
|
||||
|
||||
void CSound::Stop()
|
||||
{
|
||||
// stop the audio stream
|
||||
(*recorder)->SetRecordState ( recorder, SL_RECORDSTATE_STOPPED );
|
||||
(*player)->SetPlayState ( player, SL_PLAYSTATE_STOPPED );
|
||||
|
||||
// clear the buffers
|
||||
(*recorderSimpleBufQueue)->Clear ( recorderSimpleBufQueue );
|
||||
(*playerSimpleBufQueue)->Clear ( playerSimpleBufQueue );
|
||||
closeStreams();
|
||||
|
||||
// call base class
|
||||
CSoundBase::Stop();
|
||||
|
||||
CloseOpenSL();
|
||||
}
|
||||
|
||||
int CSound::Init ( const int iNewPrefMonoBufferSize )
|
||||
{
|
||||
|
||||
|
||||
// TODO make use of the following:
|
||||
// String sampleRate = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE));
|
||||
// String framesPerBuffer = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER));
|
||||
/*
|
||||
// get the Audio IO DEVICE CAPABILITIES interface
|
||||
SLAudioIODeviceCapabilitiesItf audioCapabilities;
|
||||
|
||||
(*engineObject)->GetInterface ( engineObject,
|
||||
SL_IID_AUDIOIODEVICECAPABILITIES,
|
||||
&audioCapabilities );
|
||||
|
||||
(*audioCapabilities)->QueryAudioInputCapabilities ( audioCapabilities,
|
||||
inputDeviceIDs[i],
|
||||
&audioInputDescriptor );
|
||||
*/
|
||||
|
||||
|
||||
// store buffer size
|
||||
iOpenSLBufferSizeMono = iNewPrefMonoBufferSize;
|
||||
iOpenSLBufferSizeMono = 512 ;
|
||||
//iNewPrefMonoBufferSize;
|
||||
|
||||
// init base class
|
||||
CSoundBase::Init ( iOpenSLBufferSizeMono );
|
||||
|
@ -282,7 +184,6 @@ SLAudioIODeviceCapabilitiesItf audioCapabilities;
|
|||
// create memory for intermediate audio buffer
|
||||
vecsTmpAudioSndCrdStereo.Init ( iOpenSLBufferSizeStereo );
|
||||
|
||||
|
||||
// TEST
|
||||
#if ( SYSTEM_SAMPLE_RATE_HZ != 48000 )
|
||||
# error "Only a system sample rate of 48 kHz is supported by this module"
|
||||
|
@ -295,57 +196,105 @@ SLAudioIODeviceCapabilitiesItf audioCapabilities;
|
|||
iModifiedInBufSize = iOpenSLBufferSizeMono / 3;
|
||||
vecsTmpAudioInSndCrd.Init ( iModifiedInBufSize );
|
||||
|
||||
|
||||
return iOpenSLBufferSizeMono;
|
||||
}
|
||||
|
||||
void CSound::processInput ( SLAndroidSimpleBufferQueueItf bufferQueue,
|
||||
void* instance )
|
||||
// This is the main callback method for when an audio stream is ready to publish data to an output stream
|
||||
// or has received data on an input stream. As per manual much be very careful not to do anything in this back that
|
||||
// can cause delays such as sleeping, file processing, allocate memory, etc
|
||||
oboe::DataCallbackResult CSound::onAudioReady(oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames)
|
||||
{
|
||||
CSound* pSound = static_cast<CSound*> ( instance );
|
||||
// only process if we are running
|
||||
if ( ! pSound->bRun )
|
||||
{
|
||||
return oboe::DataCallbackResult::Continue;
|
||||
}
|
||||
|
||||
// only process if we are running
|
||||
if ( !pSound->bRun )
|
||||
// Need to modify the size of the buffer based on the numFrames requested in this callback.
|
||||
// Buffer size can change regularly by android devices
|
||||
int& iBufferSizeMono = pSound->iOpenSLBufferSizeMono;
|
||||
|
||||
// perform the processing for input and output
|
||||
// QMutexLocker locker ( &pSound->Mutex );
|
||||
// locker.mutex();
|
||||
|
||||
//This can be called from both input and output at different times
|
||||
if (oboeStream == pSound->mPlayStream.get() && audioData)
|
||||
{
|
||||
return;
|
||||
float *floatData = static_cast<float *>(audioData);
|
||||
|
||||
// Zero out the incoming container array
|
||||
memset(audioData, 0, sizeof(float) * numFrames * oboeStream->getChannelCount());
|
||||
|
||||
// Only copy data if we have data to copy, otherwise fill with silence
|
||||
if (!pSound->vecsTmpAudioSndCrdStereo.empty())
|
||||
{
|
||||
for (int frmNum = 0; frmNum < numFrames; ++frmNum)
|
||||
{
|
||||
for (int channelNum = 0; channelNum < oboeStream->getChannelCount(); channelNum++)
|
||||
{
|
||||
// copy sample received from server into output buffer
|
||||
|
||||
|
||||
// convert to 32 bit
|
||||
const int32_t iCurSam = static_cast<int32_t> (
|
||||
pSound->vecsTmpAudioSndCrdStereo [frmNum * oboeStream->getChannelCount() + channelNum] );
|
||||
floatData[frmNum * oboeStream->getChannelCount() + channelNum] = (float) iCurSam/ _MAXSHORT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// prime output stream buffer with silence
|
||||
memset(static_cast<float*>(audioData) + numFrames * oboeStream->getChannelCount(), 0,
|
||||
(numFrames) * oboeStream->getBytesPerFrame());
|
||||
}
|
||||
}
|
||||
|
||||
QMutexLocker locker ( &pSound->Mutex );
|
||||
|
||||
// enqueue the buffer for record
|
||||
(*bufferQueue)->Enqueue ( bufferQueue,
|
||||
&pSound->vecsTmpAudioInSndCrd[0],
|
||||
pSound->iModifiedInBufSize * 2 /* 2 bytes */ );
|
||||
|
||||
// upsampling (without filtering) and channel management
|
||||
pSound->vecsTmpAudioSndCrdStereo.Reset ( 0 );
|
||||
for ( int i = 0; i < pSound->iModifiedInBufSize; i++ )
|
||||
{
|
||||
pSound->vecsTmpAudioSndCrdStereo[6 * i] =
|
||||
pSound->vecsTmpAudioSndCrdStereo[6 * i + 1] =
|
||||
pSound->vecsTmpAudioInSndCrd[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CSound::processOutput ( SLAndroidSimpleBufferQueueItf bufferQueue,
|
||||
void* instance )
|
||||
{
|
||||
CSound* pSound = static_cast<CSound*> ( instance );
|
||||
|
||||
// only process if we are running
|
||||
if ( !pSound->bRun )
|
||||
else if (oboeStream == pSound->mRecordingStream.get() && audioData)
|
||||
{
|
||||
return;
|
||||
// First things first, we need to discard the input queue a little for 500ms or so
|
||||
if (pSound->mCountCallbacksToDrain > 0)
|
||||
{
|
||||
// discard the input buffer
|
||||
int32_t numBytes = numFrames * oboeStream->getBytesPerFrame();
|
||||
memset(audioData, 0 /* value */, numBytes);
|
||||
pSound->mCountCallbacksToDrain--;
|
||||
}
|
||||
|
||||
// We're good to start recording now
|
||||
// Take the data from the recording device ouput buffer and move
|
||||
// it to the vector ready to send up to the server
|
||||
|
||||
float *floatData = static_cast<float *>(audioData);
|
||||
|
||||
// Copy recording data to internal vector
|
||||
for (int frmNum = 0; frmNum < numFrames; ++frmNum)
|
||||
{
|
||||
for (int channelNum = 0; channelNum < oboeStream->getChannelCount(); channelNum++)
|
||||
{
|
||||
pSound->vecsTmpAudioSndCrdStereo [frmNum * oboeStream->getChannelCount() + channelNum] =
|
||||
(short) floatData[frmNum * oboeStream->getChannelCount() + channelNum] * _MAXSHORT;
|
||||
}
|
||||
}
|
||||
|
||||
// Tell parent class that we've put some data ready to send to the server
|
||||
pSound->ProcessCallback ( pSound->vecsTmpAudioSndCrdStereo );
|
||||
}
|
||||
|
||||
QMutexLocker locker ( &pSound->Mutex );
|
||||
|
||||
// call processing callback function
|
||||
pSound->ProcessCallback ( pSound->vecsTmpAudioSndCrdStereo );
|
||||
|
||||
// enqueue the buffer for playback
|
||||
(*bufferQueue)->Enqueue ( bufferQueue,
|
||||
&pSound->vecsTmpAudioSndCrdStereo[0],
|
||||
pSound->iOpenSLBufferSizeStereo * 2 /* 2 bytes */ );
|
||||
// locker.unlock();
|
||||
return oboe::DataCallbackResult::Continue;
|
||||
}
|
||||
|
||||
//TODO better handling of stream closing errors
|
||||
void CSound::onErrorAfterClose(oboe::AudioStream *oboeStream, oboe::Result result)
|
||||
{
|
||||
qDebug() << "CSound::onErrorAfterClose";
|
||||
}
|
||||
|
||||
//TODO better handling of stream closing errors
|
||||
void CSound::onErrorBeforeClose(oboe::AudioStream *oboeStream, oboe::Result result)
|
||||
{
|
||||
qDebug() << "CSound::onErrorBeforeClose";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* Copyright (c) 2004-2020
|
||||
*
|
||||
* Author(s):
|
||||
* Volker Fischer
|
||||
* Simon Tomlinson
|
||||
*
|
||||
******************************************************************************
|
||||
*
|
||||
|
@ -24,31 +24,55 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <SLES/OpenSLES.h>
|
||||
#include <SLES/OpenSLES_Android.h>
|
||||
/* Deprecated, moving to OBOE
|
||||
* #include <SLES/OpenSLES.h>
|
||||
* #include <SLES/OpenSLES_Android.h> */
|
||||
#include <oboe/Oboe.h>
|
||||
#include <QMutex>
|
||||
#include "soundbase.h"
|
||||
#include "global.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <android/log.h>
|
||||
|
||||
/* Classes ********************************************************************/
|
||||
class CSound : public CSoundBase
|
||||
class CSound : public CSoundBase, public oboe::AudioStreamCallback//, public IRenderableAudio, public IRestartable
|
||||
{
|
||||
public:
|
||||
CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, void* arg ),
|
||||
void* arg,
|
||||
const int iCtrlMIDIChannel,
|
||||
const bool bNoAutoJackConnect );
|
||||
CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, void* arg ),
|
||||
void* arg,
|
||||
const int iCtrlMIDIChannel,
|
||||
const bool ,
|
||||
const QString& );
|
||||
virtual ~CSound() {}
|
||||
|
||||
virtual int Init ( const int iNewPrefMonoBufferSize );
|
||||
virtual void Start();
|
||||
virtual void Stop();
|
||||
|
||||
// Call backs for Oboe
|
||||
virtual oboe::DataCallbackResult onAudioReady(oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames);
|
||||
virtual void onErrorAfterClose(oboe::AudioStream *oboeStream, oboe::Result result);
|
||||
virtual void onErrorBeforeClose(oboe::AudioStream *oboeStream, oboe::Result result);
|
||||
|
||||
// these variables should be protected but cannot since we want
|
||||
// to access them from the callback function
|
||||
CVector<short> vecsTmpAudioSndCrdStereo;
|
||||
|
||||
static void android_message_handler(QtMsgType type,
|
||||
const QMessageLogContext &context,
|
||||
const QString &message)
|
||||
{
|
||||
android_LogPriority priority = ANDROID_LOG_DEBUG;
|
||||
switch (type) {
|
||||
case QtDebugMsg: priority = ANDROID_LOG_DEBUG; break;
|
||||
case QtWarningMsg: priority = ANDROID_LOG_WARN; break;
|
||||
case QtCriticalMsg: priority = ANDROID_LOG_ERROR; break;
|
||||
case QtFatalMsg: priority = ANDROID_LOG_FATAL; break;
|
||||
};
|
||||
|
||||
__android_log_print(priority, "Qt", "%s", qPrintable(message));
|
||||
};
|
||||
|
||||
// TEST
|
||||
CVector<short> vecsTmpAudioInSndCrd;
|
||||
int iModifiedInBufSize;
|
||||
|
@ -56,27 +80,25 @@ int iModifiedInBufSize;
|
|||
int iOpenSLBufferSizeMono;
|
||||
int iOpenSLBufferSizeStereo;
|
||||
|
||||
protected:
|
||||
private:
|
||||
void setupCommonStreamParams(oboe::AudioStreamBuilder *builder);
|
||||
void printStreamDetails(oboe::ManagedStream &stream);
|
||||
void openStreams();
|
||||
void closeStreams();
|
||||
void warnIfNotLowLatency(oboe::ManagedStream &stream, QString streamName);
|
||||
void closeStream(oboe::ManagedStream &stream);
|
||||
|
||||
void InitializeOpenSL();
|
||||
void CloseOpenSL();
|
||||
oboe::ManagedStream mRecordingStream;
|
||||
oboe::ManagedStream mPlayStream;
|
||||
AudioStreamCallback *mCallback;
|
||||
|
||||
// callbacks
|
||||
static void processInput ( SLAndroidSimpleBufferQueueItf bufferQueue,
|
||||
void* instance );
|
||||
// used to reach a state where the input buffer is
|
||||
// empty and the garbage in the first 500ms or so is discarded
|
||||
static constexpr int32_t kNumCallbacksToDrain = 10;
|
||||
int32_t mCountCallbacksToDrain = kNumCallbacksToDrain;
|
||||
|
||||
static void processOutput ( SLAndroidSimpleBufferQueueItf bufferQueue,
|
||||
void* instance );
|
||||
|
||||
SLObjectItf engineObject;
|
||||
SLEngineItf engine;
|
||||
SLObjectItf recorderObject;
|
||||
SLRecordItf recorder;
|
||||
SLAndroidSimpleBufferQueueItf recorderSimpleBufQueue;
|
||||
SLObjectItf outputMixObject;
|
||||
SLObjectItf playerObject;
|
||||
SLPlayItf player;
|
||||
SLAndroidSimpleBufferQueueItf playerSimpleBufQueue;
|
||||
// Used to reference this instance of class from within the static callback
|
||||
CSound *pSound;
|
||||
|
||||
QMutex Mutex;
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ Build-Depends:
|
|||
make,
|
||||
qt5-default,
|
||||
qtdeclarative5-dev,
|
||||
qttools5-dev-tools,
|
||||
Standards-Version: 3.9.5
|
||||
Homepage: http://llcon.sourceforge.net/
|
||||
Vcs-Git: git://github.com/corrados/jamulus.git
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
override_dh_auto_configure:
|
||||
qmake CONFIG+=noupcasename Jamulus.pro
|
||||
|
||||
override_dh_auto_build:
|
||||
cd src/res/translation && lrelease *.ts
|
||||
dh_auto_build
|
||||
|
||||
override_dh_usrlocal:
|
||||
echo $$(pwd)
|
||||
mkdir -p $$(pwd)/debian/jamulus/usr/bin/
|
||||
|
|
|
@ -75,7 +75,7 @@ fi
|
|||
|
||||
# compile Jamulus with external Opus library
|
||||
cd ..
|
||||
qmake "CONFIG+=opus_shared_lib" "INCLUDEPATH+=distributions/${OPUS}/include" "QMAKE_LIBDIR+=distributions/${OPUS}/.libs" "INCLUDEPATH+=distributions/jack2/common" "QMAKE_LIBDIR+=distributions/jack2/build/common" Jamulus.pro
|
||||
qmake "CONFIG+=opus_shared_lib" "CONFIG+=raspijamulus" "INCLUDEPATH+=distributions/${OPUS}/include" "QMAKE_LIBDIR+=distributions/${OPUS}/.libs" "INCLUDEPATH+=distributions/jack2/common" "QMAKE_LIBDIR+=distributions/jack2/build/common" Jamulus.pro
|
||||
make -j${NCORES}
|
||||
|
||||
# get first USB audio sound card device
|
||||
|
|
1
libs/oboe
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 55d878a4e85e1994f2b5883366079b991500a25f
|
100
linux/sound.cpp
|
@ -27,14 +27,15 @@
|
|||
#include "sound.h"
|
||||
|
||||
#ifdef WITH_SOUND
|
||||
void CSound::OpenJack()
|
||||
void CSound::OpenJack ( const bool bNoAutoJackConnect,
|
||||
const char* jackClientName )
|
||||
{
|
||||
jack_status_t JackStatus;
|
||||
|
||||
// try to become a client of the JACK server
|
||||
pJackClient = jack_client_open ( APP_NAME, JackNullOption, &JackStatus );
|
||||
pJackClient = jack_client_open ( jackClientName, JackNullOption, &JackStatus );
|
||||
|
||||
if ( pJackClient == NULL )
|
||||
if ( pJackClient == nullptr )
|
||||
{
|
||||
throw CGenErr ( tr ( "The Jack server is not running. This software "
|
||||
"requires a Jack server to run. Normally if the Jack server is "
|
||||
|
@ -57,13 +58,13 @@ void CSound::OpenJack()
|
|||
if ( jack_get_sample_rate ( pJackClient ) != SYSTEM_SAMPLE_RATE_HZ )
|
||||
{
|
||||
throw CGenErr ( tr ( "The Jack server sample rate is different from "
|
||||
"the required one. The required sample rate is: <b>" ) +
|
||||
QString().setNum ( SYSTEM_SAMPLE_RATE_HZ ) + tr ( " Hz</b>. You can "
|
||||
"the required one. The required sample rate is:" ) + " <b>" +
|
||||
QString().setNum ( SYSTEM_SAMPLE_RATE_HZ ) + " Hz</b>. " + tr ( "You can "
|
||||
"use a tool like <i><a href=""http://qjackctl.sourceforge.net"">QJackCtl</a></i> "
|
||||
"to adjust the Jack server sample rate.<br>Make sure to set the "
|
||||
"<b>Frames/Period</b> to a low value like <b>" ) +
|
||||
"to adjust the Jack server sample rate." ) + "<br>" + tr ( "Make sure to set the "
|
||||
"Frames/Period to a low value like " ) +
|
||||
QString().setNum ( DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES ) +
|
||||
tr ( "</b> to achieve a low delay." ) );
|
||||
tr ( " to achieve a low delay." ) );
|
||||
}
|
||||
|
||||
// create four ports (two for input, two for output -> stereo)
|
||||
|
@ -79,10 +80,10 @@ void CSound::OpenJack()
|
|||
output_port_right = jack_port_register ( pJackClient, "output right",
|
||||
JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 );
|
||||
|
||||
if ( ( input_port_left == NULL ) ||
|
||||
( input_port_right == NULL ) ||
|
||||
( output_port_left == NULL ) ||
|
||||
( output_port_right == NULL ) )
|
||||
if ( ( input_port_left == nullptr ) ||
|
||||
( input_port_right == nullptr ) ||
|
||||
( output_port_left == nullptr ) ||
|
||||
( output_port_right == nullptr ) )
|
||||
{
|
||||
throw CGenErr ( tr ( "The Jack port registering failed." ) );
|
||||
}
|
||||
|
@ -93,14 +94,14 @@ void CSound::OpenJack()
|
|||
input_port_midi = jack_port_register ( pJackClient, "input midi",
|
||||
JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0 );
|
||||
|
||||
if ( input_port_midi == NULL )
|
||||
if ( input_port_midi == nullptr )
|
||||
{
|
||||
throw CGenErr ( tr ( "The Jack port registering failed." ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
input_port_midi = NULL;
|
||||
input_port_midi = nullptr;
|
||||
}
|
||||
|
||||
// tell the JACK server that we are ready to roll
|
||||
|
@ -119,23 +120,16 @@ void CSound::OpenJack()
|
|||
|
||||
// try to connect physical input ports
|
||||
if ( ( ports = jack_get_ports ( pJackClient,
|
||||
NULL,
|
||||
NULL,
|
||||
JackPortIsPhysical | JackPortIsOutput ) ) != NULL )
|
||||
nullptr,
|
||||
nullptr,
|
||||
JackPortIsPhysical | JackPortIsOutput ) ) != nullptr )
|
||||
{
|
||||
if ( jack_connect ( pJackClient, ports[0], jack_port_name ( input_port_left ) ) )
|
||||
{
|
||||
throw CGenErr ( tr ( "Cannot connect the Jack input ports" ) );
|
||||
}
|
||||
jack_connect ( pJackClient, ports[0], jack_port_name ( input_port_left ) );
|
||||
|
||||
// before connecting the second stereo channel, check if the input is not
|
||||
// mono
|
||||
// before connecting the second stereo channel, check if the input is not mono
|
||||
if ( ports[1] )
|
||||
{
|
||||
if ( jack_connect ( pJackClient, ports[1], jack_port_name ( input_port_right ) ) )
|
||||
{
|
||||
throw CGenErr ( tr ( "Cannot connect the Jack input ports" ) );
|
||||
}
|
||||
jack_connect ( pJackClient, ports[1], jack_port_name ( input_port_right ) );
|
||||
}
|
||||
|
||||
jack_free ( ports );
|
||||
|
@ -143,23 +137,16 @@ void CSound::OpenJack()
|
|||
|
||||
// try to connect physical output ports
|
||||
if ( ( ports = jack_get_ports ( pJackClient,
|
||||
NULL,
|
||||
NULL,
|
||||
JackPortIsPhysical | JackPortIsInput ) ) != NULL )
|
||||
nullptr,
|
||||
nullptr,
|
||||
JackPortIsPhysical | JackPortIsInput ) ) != nullptr )
|
||||
{
|
||||
if ( jack_connect ( pJackClient, jack_port_name ( output_port_left ), ports[0] ) )
|
||||
{
|
||||
throw CGenErr ( tr ( "Cannot connect the Jack output ports." ) );
|
||||
}
|
||||
jack_connect ( pJackClient, jack_port_name ( output_port_left ), ports[0] );
|
||||
|
||||
// before connecting the second stereo channel, check if the output is not
|
||||
// mono
|
||||
// before connecting the second stereo channel, check if the output is not mono
|
||||
if ( ports[1] )
|
||||
{
|
||||
if ( jack_connect ( pJackClient, jack_port_name ( output_port_right ), ports[1] ) )
|
||||
{
|
||||
throw CGenErr ( tr ( "Cannot connect the Jack output ports." ) );
|
||||
}
|
||||
jack_connect ( pJackClient, jack_port_name ( output_port_right ), ports[1] );
|
||||
}
|
||||
|
||||
jack_free ( ports );
|
||||
|
@ -197,16 +184,20 @@ void CSound::Stop()
|
|||
int CSound::Init ( const int /* iNewPrefMonoBufferSize */ )
|
||||
{
|
||||
|
||||
|
||||
// try setting buffer size
|
||||
// TODO seems not to work! -> no audio after this operation!
|
||||
|
||||
// Doesn't this give an infinite loop? The set buffer size function will call our
|
||||
// registerd callback which calls "EmitReinitRequestSignal()". In that function
|
||||
// this CSound::Init() function is called...
|
||||
|
||||
//jack_set_buffer_size ( pJackClient, iNewPrefMonoBufferSize );
|
||||
|
||||
// without a Jack server, Jamulus makes no sense to run, throw an error message
|
||||
if ( bJackWasShutDown )
|
||||
{
|
||||
throw CGenErr ( tr ( "The Jack server was shut down. This software "
|
||||
"requires a Jack server to run. Try to restart the software to "
|
||||
"solve the issue." ) );
|
||||
}
|
||||
|
||||
// get actual buffer size
|
||||
iJACKBufferSizeMono = jack_get_buffer_size ( pJackClient );
|
||||
|
@ -230,7 +221,7 @@ int CSound::process ( jack_nframes_t nframes, void* arg )
|
|||
CSound* pSound = static_cast<CSound*> ( arg );
|
||||
int i;
|
||||
|
||||
if ( pSound->IsRunning() )
|
||||
if ( pSound->IsRunning() && ( nframes == static_cast<jack_nframes_t> ( pSound->iJACKBufferSizeMono ) ) )
|
||||
{
|
||||
// get input data pointer
|
||||
jack_default_audio_sample_t* in_left =
|
||||
|
@ -242,7 +233,7 @@ int CSound::process ( jack_nframes_t nframes, void* arg )
|
|||
pSound->input_port_right, nframes );
|
||||
|
||||
// copy input audio data
|
||||
if ( in_left != 0 && in_right != 0 )
|
||||
if ( ( in_left != nullptr ) && ( in_right != nullptr ) )
|
||||
{
|
||||
for ( i = 0; i < pSound->iJACKBufferSizeMono; i++ )
|
||||
{
|
||||
|
@ -267,7 +258,7 @@ int CSound::process ( jack_nframes_t nframes, void* arg )
|
|||
pSound->output_port_right, nframes );
|
||||
|
||||
// copy output data
|
||||
if ( out_left != 0 && out_right != 0 )
|
||||
if ( ( out_left != nullptr ) && ( out_right != nullptr ) )
|
||||
{
|
||||
for ( i = 0; i < pSound->iJACKBufferSizeMono; i++ )
|
||||
{
|
||||
|
@ -291,7 +282,7 @@ int CSound::process ( jack_nframes_t nframes, void* arg )
|
|||
pSound->output_port_right, nframes );
|
||||
|
||||
// clear output data
|
||||
if ( out_left != 0 && out_right != 0 )
|
||||
if ( ( out_left != nullptr ) && ( out_right != nullptr ) )
|
||||
{
|
||||
memset ( out_left,
|
||||
0,
|
||||
|
@ -304,7 +295,7 @@ int CSound::process ( jack_nframes_t nframes, void* arg )
|
|||
}
|
||||
|
||||
// akt on MIDI data if MIDI is enabled
|
||||
if ( pSound->input_port_midi != NULL )
|
||||
if ( pSound->input_port_midi != nullptr )
|
||||
{
|
||||
void* in_midi = jack_port_get_buffer ( pSound->input_port_midi, nframes );
|
||||
|
||||
|
@ -334,7 +325,7 @@ int CSound::process ( jack_nframes_t nframes, void* arg )
|
|||
return 0; // zero on success, non-zero on error
|
||||
}
|
||||
|
||||
int CSound::bufferSizeCallback ( jack_nframes_t, void *arg )
|
||||
int CSound::bufferSizeCallback ( jack_nframes_t, void* arg )
|
||||
{
|
||||
CSound* pSound = static_cast<CSound*> ( arg );
|
||||
|
||||
|
@ -343,12 +334,11 @@ int CSound::bufferSizeCallback ( jack_nframes_t, void *arg )
|
|||
return 0; // zero on success, non-zero on error
|
||||
}
|
||||
|
||||
void CSound::shutdownCallback ( void* )
|
||||
void CSound::shutdownCallback ( void* arg )
|
||||
{
|
||||
// without a Jack server, our software makes no sense to run, throw
|
||||
// error message
|
||||
throw CGenErr ( tr ( "The Jack server was shut down. This software "
|
||||
"requires a Jack server to run. Try to restart the software to "
|
||||
"solve the issue." ) );
|
||||
CSound* pSound = static_cast<CSound*> ( arg );
|
||||
|
||||
pSound->bJackWasShutDown = true;
|
||||
pSound->EmitReinitRequestSignal ( RS_ONLY_RESTART_AND_INIT );
|
||||
}
|
||||
#endif // WITH_SOUND
|
||||
|
|
|
@ -60,12 +60,14 @@
|
|||
class CSound : public CSoundBase
|
||||
{
|
||||
public:
|
||||
CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, void* arg ),
|
||||
void* arg,
|
||||
const int iCtrlMIDIChannel,
|
||||
const bool bNoAutoJackConnect ) :
|
||||
CSoundBase ( "Jack", true, fpNewProcessCallback, arg, iCtrlMIDIChannel, bNoAutoJackConnect ), iJACKBufferSizeMono ( 0 ),
|
||||
iJACKBufferSizeStero ( 0 ) { OpenJack(); }
|
||||
CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, void* arg ),
|
||||
void* arg,
|
||||
const int iCtrlMIDIChannel,
|
||||
const bool bNoAutoJackConnect,
|
||||
const QString& strJackClientName ) :
|
||||
CSoundBase ( "Jack", true, fpNewProcessCallback, arg, iCtrlMIDIChannel ),
|
||||
iJACKBufferSizeMono ( 0 ), bJackWasShutDown ( false ) { OpenJack ( bNoAutoJackConnect, strJackClientName.toLocal8Bit().data() ); }
|
||||
|
||||
virtual ~CSound() { CloseJack(); }
|
||||
|
||||
virtual int Init ( const int iNewPrefMonoBufferSize );
|
||||
|
@ -77,6 +79,7 @@ public:
|
|||
CVector<short> vecsTmpAudioSndCrdStereo;
|
||||
int iJACKBufferSizeMono;
|
||||
int iJACKBufferSizeStero;
|
||||
bool bJackWasShutDown;
|
||||
|
||||
jack_port_t* input_port_left;
|
||||
jack_port_t* input_port_right;
|
||||
|
@ -85,7 +88,9 @@ public:
|
|||
jack_port_t* input_port_midi;
|
||||
|
||||
protected:
|
||||
void OpenJack();
|
||||
void OpenJack ( const bool bNoAutoJackConnect,
|
||||
const char* jackClientName );
|
||||
|
||||
void CloseJack();
|
||||
|
||||
// callbacks
|
||||
|
@ -99,11 +104,12 @@ protected:
|
|||
class CSound : public CSoundBase
|
||||
{
|
||||
public:
|
||||
CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, void* pParg ),
|
||||
void* pParg,
|
||||
const int iCtrlMIDIChannel,
|
||||
const bool bNoAutoJackConnect ) :
|
||||
CSoundBase ( "nosound", false, fpNewProcessCallback, pParg, iCtrlMIDIChannel, bNoAutoJackConnect ) {}
|
||||
CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, void* pParg ),
|
||||
void* pParg,
|
||||
const int iCtrlMIDIChannel,
|
||||
const bool ,
|
||||
const QString& ) :
|
||||
CSoundBase ( "nosound", false, fpNewProcessCallback, pParg, iCtrlMIDIChannel ) {}
|
||||
virtual ~CSound() {}
|
||||
};
|
||||
#endif // WITH_SOUND
|
||||
|
|
346
mac/sound.cpp
|
@ -26,11 +26,12 @@
|
|||
|
||||
|
||||
/* Implementation *************************************************************/
|
||||
CSound::CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, void* arg ),
|
||||
void* arg,
|
||||
const int iCtrlMIDIChannel,
|
||||
const bool bNoAutoJackConnect ) :
|
||||
CSoundBase ( "CoreAudio", true, fpNewProcessCallback, arg, iCtrlMIDIChannel, bNoAutoJackConnect ),
|
||||
CSound::CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, void* arg ),
|
||||
void* arg,
|
||||
const int iCtrlMIDIChannel,
|
||||
const bool ,
|
||||
const QString& ) :
|
||||
CSoundBase ( "CoreAudio", true, fpNewProcessCallback, arg, iCtrlMIDIChannel ),
|
||||
midiInPortRef ( static_cast<MIDIPortRef> ( NULL ) )
|
||||
{
|
||||
// Apple Mailing Lists: Subject: GUI Apps should set kAudioHardwarePropertyRunLoop
|
||||
|
@ -166,6 +167,7 @@ CSound::CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, vo
|
|||
CurrentAudioInputDeviceID = 0;
|
||||
CurrentAudioOutputDeviceID = 0;
|
||||
iNumInChan = 0;
|
||||
iNumInChanPlusAddChan = 0;
|
||||
iNumOutChan = 0;
|
||||
iSelInputLeftChannel = 0;
|
||||
iSelInputRightChannel = 0;
|
||||
|
@ -255,47 +257,55 @@ void CSound::GetAudioDeviceInfos ( const AudioDeviceID DeviceID,
|
|||
}
|
||||
|
||||
int CSound::CountChannels ( AudioDeviceID devID,
|
||||
const int iNumChanPerFrame,
|
||||
bool isInput )
|
||||
{
|
||||
OSStatus err;
|
||||
UInt32 propSize;
|
||||
int result = 0;
|
||||
|
||||
// check for the case the we have interleaved format, in that case we assume
|
||||
// that only the very first buffer contains all our channels
|
||||
if ( iNumChanPerFrame > 1 )
|
||||
if ( isInput )
|
||||
{
|
||||
result = iNumChanPerFrame;
|
||||
vecNumInBufChan.Init ( 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
// it seems we have multiple buffers where each buffer has only one channel,
|
||||
// in that case we assume that each input channel has its own buffer
|
||||
AudioObjectPropertyScope theScope = isInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
|
||||
vecNumOutBufChan.Init ( 0 );
|
||||
}
|
||||
|
||||
AudioObjectPropertyAddress theAddress = { kAudioDevicePropertyStreamConfiguration,
|
||||
theScope,
|
||||
0 };
|
||||
// it seems we have multiple buffers where each buffer has only one channel,
|
||||
// in that case we assume that each input channel has its own buffer
|
||||
AudioObjectPropertyScope theScope = isInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
|
||||
|
||||
AudioObjectGetPropertyDataSize ( devID, &theAddress, 0, NULL, &propSize );
|
||||
AudioObjectPropertyAddress theAddress = { kAudioDevicePropertyStreamConfiguration,
|
||||
theScope,
|
||||
0 };
|
||||
|
||||
AudioBufferList *buflist = (AudioBufferList*) malloc ( propSize );
|
||||
AudioObjectGetPropertyDataSize ( devID, &theAddress, 0, NULL, &propSize );
|
||||
|
||||
err = AudioObjectGetPropertyData ( devID, &theAddress, 0, NULL, &propSize, buflist );
|
||||
AudioBufferList *buflist = (AudioBufferList*) malloc ( propSize );
|
||||
|
||||
if ( !err )
|
||||
err = AudioObjectGetPropertyData ( devID, &theAddress, 0, NULL, &propSize, buflist );
|
||||
|
||||
if ( !err )
|
||||
{
|
||||
for ( UInt32 i = 0; i < buflist->mNumberBuffers; ++i )
|
||||
{
|
||||
for ( UInt32 i = 0; i < buflist->mNumberBuffers; ++i )
|
||||
// The correct value mNumberChannels for an AudioBuffer can be derived from the mChannelsPerFrame
|
||||
// and the interleaved flag. For non interleaved formats, mNumberChannels is always 1.
|
||||
// For interleaved formats, mNumberChannels is equal to mChannelsPerFrame.
|
||||
result += buflist->mBuffers[i].mNumberChannels;
|
||||
|
||||
if ( isInput )
|
||||
{
|
||||
// The correct value mNumberChannels for an AudioBuffer can be derived from the mChannelsPerFrame
|
||||
// and the interleaved flag. For non interleaved formats, mNumberChannels is always 1.
|
||||
// For interleaved formats, mNumberChannels is equal to mChannelsPerFrame.
|
||||
result += buflist->mBuffers[i].mNumberChannels;
|
||||
vecNumInBufChan.Add ( buflist->mBuffers[i].mNumberChannels );
|
||||
}
|
||||
else
|
||||
{
|
||||
vecNumOutBufChan.Add ( buflist->mBuffers[i].mNumberChannels );
|
||||
}
|
||||
}
|
||||
free ( buflist );
|
||||
}
|
||||
free ( buflist );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -315,10 +325,10 @@ QString CSound::LoadAndInitializeDriver ( int iDriverIdx, bool )
|
|||
|
||||
// the device has changed, per definition we reset the channel
|
||||
// mapping to the defaults (first two available channels)
|
||||
iSelInputLeftChannel = 0;
|
||||
iSelInputRightChannel = min ( iNumInChan - 1, 1 );
|
||||
iSelOutputLeftChannel = 0;
|
||||
iSelOutputRightChannel = min ( iNumOutChan - 1, 1 );
|
||||
SetLeftInputChannel ( 0 );
|
||||
SetRightInputChannel ( 1 );
|
||||
SetLeftOutputChannel ( 0 );
|
||||
SetRightOutputChannel ( 1 );
|
||||
}
|
||||
|
||||
return strStat;
|
||||
|
@ -461,9 +471,6 @@ QString CSound::CheckDeviceCapabilities ( const int iDriverIdx )
|
|||
"not compatible with this software." );
|
||||
}
|
||||
|
||||
// store the input number of channels per frame for this stream
|
||||
const int iNumInChanPerFrame = CurDevStreamFormat.mChannelsPerFrame;
|
||||
|
||||
// check the output
|
||||
AudioObjectGetPropertyData ( outputStreamID,
|
||||
&stPropertyAddress,
|
||||
|
@ -482,12 +489,9 @@ QString CSound::CheckDeviceCapabilities ( const int iDriverIdx )
|
|||
"not compatible with this software." );
|
||||
}
|
||||
|
||||
// store the output number of channels per frame for this stream
|
||||
const int iNumOutChanPerFrame = CurDevStreamFormat.mChannelsPerFrame;
|
||||
|
||||
// store the input and out number of channels for this device
|
||||
iNumInChan = CountChannels ( audioInputDevice[iDriverIdx], iNumInChanPerFrame, true );
|
||||
iNumOutChan = CountChannels ( audioOutputDevice[iDriverIdx], iNumOutChanPerFrame, false );
|
||||
iNumInChan = CountChannels ( audioInputDevice[iDriverIdx], true );
|
||||
iNumOutChan = CountChannels ( audioOutputDevice[iDriverIdx], false );
|
||||
|
||||
// clip the number of input/output channels to our allowed maximum
|
||||
if ( iNumInChan > MAX_NUM_IN_OUT_CHANNELS )
|
||||
|
@ -567,25 +571,129 @@ QString CSound::CheckDeviceCapabilities ( const int iDriverIdx )
|
|||
}
|
||||
}
|
||||
|
||||
// special case with 4 input channels: support adding channels
|
||||
if ( iNumInChan == 4 )
|
||||
{
|
||||
// add four mixed channels (i.e. 4 normal, 4 mixed channels)
|
||||
iNumInChanPlusAddChan = 8;
|
||||
|
||||
for ( int iCh = 0; iCh < iNumInChanPlusAddChan; iCh++ )
|
||||
{
|
||||
int iSelCH, iSelAddCH;
|
||||
|
||||
GetSelCHAndAddCH ( iCh, iNumInChan, iSelCH, iSelAddCH );
|
||||
|
||||
if ( iSelAddCH >= 0 )
|
||||
{
|
||||
// for mixed channels, show both audio channel names to be mixed
|
||||
sChannelNamesInput[iCh] =
|
||||
sChannelNamesInput[iSelCH] + " + " + sChannelNamesInput[iSelAddCH];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// regular case: no mixing input channels used
|
||||
iNumInChanPlusAddChan = iNumInChan;
|
||||
}
|
||||
|
||||
// everything is ok, return empty string for "no error" case
|
||||
return "";
|
||||
}
|
||||
|
||||
void CSound::UpdateChSelection()
|
||||
{
|
||||
// calculate the selected input/output buffer and the selected interleaved
|
||||
// channel index in the buffer, note that each buffer can have a different
|
||||
// number of interleaved channels
|
||||
int iChCnt;
|
||||
int iSelCHLeft, iSelAddCHLeft;
|
||||
int iSelCHRight, iSelAddCHRight;
|
||||
|
||||
// initialize all buffer indexes with an invalid value
|
||||
iSelInBufferLeft = -1;
|
||||
iSelInBufferRight = -1;
|
||||
iSelAddInBufferLeft = -1; // if no additional channel used, this will stay on the invalid value
|
||||
iSelAddInBufferRight = -1; // if no additional channel used, this will stay on the invalid value
|
||||
iSelOutBufferLeft = -1;
|
||||
iSelOutBufferRight = -1;
|
||||
|
||||
// input
|
||||
GetSelCHAndAddCH ( iSelInputLeftChannel, iNumInChan, iSelCHLeft, iSelAddCHLeft );
|
||||
GetSelCHAndAddCH ( iSelInputRightChannel, iNumInChan, iSelCHRight, iSelAddCHRight );
|
||||
|
||||
iChCnt = 0;
|
||||
|
||||
for ( int iBuf = 0; iBuf < vecNumInBufChan.Size(); iBuf++ )
|
||||
{
|
||||
iChCnt += vecNumInBufChan[iBuf];
|
||||
|
||||
if ( ( iSelInBufferLeft < 0 ) && ( iChCnt > iSelCHLeft ) )
|
||||
{
|
||||
iSelInBufferLeft = iBuf;
|
||||
iSelInInterlChLeft = iSelCHLeft - iChCnt + vecNumInBufChan[iBuf];
|
||||
}
|
||||
|
||||
if ( ( iSelInBufferRight < 0 ) && ( iChCnt > iSelCHRight ) )
|
||||
{
|
||||
iSelInBufferRight = iBuf;
|
||||
iSelInInterlChRight = iSelCHRight - iChCnt + vecNumInBufChan[iBuf];
|
||||
}
|
||||
|
||||
if ( ( iSelAddCHLeft >= 0 ) && ( iSelAddInBufferLeft < 0 ) && ( iChCnt > iSelAddCHLeft ) )
|
||||
{
|
||||
iSelAddInBufferLeft = iBuf;
|
||||
iSelAddInInterlChLeft = iSelAddCHLeft - iChCnt + vecNumInBufChan[iBuf];
|
||||
}
|
||||
|
||||
if ( ( iSelAddCHRight >= 0 ) && ( iSelAddInBufferRight < 0 ) && ( iChCnt > iSelAddCHRight ) )
|
||||
{
|
||||
iSelAddInBufferRight = iBuf;
|
||||
iSelAddInInterlChRight = iSelAddCHRight - iChCnt + vecNumInBufChan[iBuf];
|
||||
}
|
||||
}
|
||||
|
||||
// output
|
||||
GetSelCHAndAddCH ( iSelOutputLeftChannel, iNumOutChan, iSelCHLeft, iSelAddCHLeft );
|
||||
GetSelCHAndAddCH ( iSelOutputRightChannel, iNumOutChan, iSelCHRight, iSelAddCHRight );
|
||||
|
||||
iChCnt = 0;
|
||||
|
||||
for ( int iBuf = 0; iBuf < vecNumOutBufChan.Size(); iBuf++ )
|
||||
{
|
||||
iChCnt += vecNumOutBufChan[iBuf];
|
||||
|
||||
if ( ( iSelOutBufferLeft < 0 ) && ( iChCnt > iSelCHLeft ) )
|
||||
{
|
||||
iSelOutBufferLeft = iBuf;
|
||||
iSelOutInterlChLeft = iSelCHLeft - iChCnt + vecNumOutBufChan[iBuf];
|
||||
}
|
||||
|
||||
if ( ( iSelOutBufferRight < 0 ) && ( iChCnt > iSelCHRight ) )
|
||||
{
|
||||
iSelOutBufferRight = iBuf;
|
||||
iSelOutInterlChRight = iSelCHRight - iChCnt + vecNumOutBufChan[iBuf];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSound::SetLeftInputChannel ( const int iNewChan )
|
||||
{
|
||||
// apply parameter after input parameter check
|
||||
if ( ( iNewChan >= 0 ) && ( iNewChan < iNumInChan ) )
|
||||
if ( ( iNewChan >= 0 ) && ( iNewChan < iNumInChanPlusAddChan ) )
|
||||
{
|
||||
iSelInputLeftChannel = iNewChan;
|
||||
UpdateChSelection();
|
||||
}
|
||||
}
|
||||
|
||||
void CSound::SetRightInputChannel ( const int iNewChan )
|
||||
{
|
||||
// apply parameter after input parameter check
|
||||
if ( ( iNewChan >= 0 ) && ( iNewChan < iNumInChan ) )
|
||||
if ( ( iNewChan >= 0 ) && ( iNewChan < iNumInChanPlusAddChan ) )
|
||||
{
|
||||
iSelInputRightChannel = iNewChan;
|
||||
UpdateChSelection();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -595,6 +703,7 @@ void CSound::SetLeftOutputChannel ( const int iNewChan )
|
|||
if ( ( iNewChan >= 0 ) && ( iNewChan < iNumOutChan ) )
|
||||
{
|
||||
iSelOutputLeftChannel = iNewChan;
|
||||
UpdateChSelection();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -604,6 +713,7 @@ void CSound::SetRightOutputChannel ( const int iNewChan )
|
|||
if ( ( iNewChan >= 0 ) && ( iNewChan < iNumOutChan ) )
|
||||
{
|
||||
iSelOutputRightChannel = iNewChan;
|
||||
UpdateChSelection();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -823,68 +933,70 @@ OSStatus CSound::callbackIO ( AudioDeviceID inDevice,
|
|||
// both, the input and output device use the same callback function
|
||||
QMutexLocker locker ( &pSound->Mutex );
|
||||
|
||||
const int iCoreAudioBufferSizeMono = pSound->iCoreAudioBufferSizeMono;
|
||||
const int iNumInChan = pSound->iNumInChan;
|
||||
const int iNumOutChan = pSound->iNumOutChan;
|
||||
const int iSelInputLeftChannel = pSound->iSelInputLeftChannel;
|
||||
const int iSelInputRightChannel = pSound->iSelInputRightChannel;
|
||||
const int iSelOutputLeftChannel = pSound->iSelOutputLeftChannel;
|
||||
const int iSelOutputRightChannel = pSound->iSelOutputRightChannel;
|
||||
const int iCoreAudioBufferSizeMono = pSound->iCoreAudioBufferSizeMono;
|
||||
const int iSelInBufferLeft = pSound->iSelInBufferLeft;
|
||||
const int iSelInBufferRight = pSound->iSelInBufferRight;
|
||||
const int iSelInInterlChLeft = pSound->iSelInInterlChLeft;
|
||||
const int iSelInInterlChRight = pSound->iSelInInterlChRight;
|
||||
const int iSelAddInBufferLeft = pSound->iSelAddInBufferLeft;
|
||||
const int iSelAddInBufferRight = pSound->iSelAddInBufferRight;
|
||||
const int iSelAddInInterlChLeft = pSound->iSelAddInInterlChLeft;
|
||||
const int iSelAddInInterlChRight = pSound->iSelAddInInterlChRight;
|
||||
const int iSelOutBufferLeft = pSound->iSelOutBufferLeft;
|
||||
const int iSelOutBufferRight = pSound->iSelOutBufferRight;
|
||||
const int iSelOutInterlChLeft = pSound->iSelOutInterlChLeft;
|
||||
const int iSelOutInterlChRight = pSound->iSelOutInterlChRight;
|
||||
const CVector<int>& vecNumInBufChan = pSound->vecNumInBufChan;
|
||||
const CVector<int>& vecNumOutBufChan = pSound->vecNumOutBufChan;
|
||||
|
||||
if ( ( inDevice == pSound->CurrentAudioInputDeviceID ) && inInputData )
|
||||
{
|
||||
// check size (float32 has four bytes)
|
||||
if ( inInputData->mBuffers[0].mDataByteSize ==
|
||||
static_cast<UInt32> ( iCoreAudioBufferSizeMono * iNumInChan * 4 ) )
|
||||
// check sizes (note that float32 has four bytes)
|
||||
if ( ( iSelInBufferLeft >= 0 ) &&
|
||||
( iSelInBufferLeft < static_cast<int> ( inInputData->mNumberBuffers ) ) &&
|
||||
( iSelInBufferRight >= 0 ) &&
|
||||
( iSelInBufferRight < static_cast<int> ( inInputData->mNumberBuffers ) ) &&
|
||||
( iSelAddInBufferLeft < static_cast<int> ( inInputData->mNumberBuffers ) ) &&
|
||||
( iSelAddInBufferRight < static_cast<int> ( inInputData->mNumberBuffers ) ) &&
|
||||
( inInputData->mBuffers[iSelInBufferLeft].mDataByteSize == static_cast<UInt32> ( vecNumInBufChan[iSelInBufferLeft] * iCoreAudioBufferSizeMono * 4 ) ) &&
|
||||
( inInputData->mBuffers[iSelInBufferRight].mDataByteSize == static_cast<UInt32> ( vecNumInBufChan[iSelInBufferRight] * iCoreAudioBufferSizeMono * 4 ) ) )
|
||||
{
|
||||
// one buffer with all the channels in interleaved format:
|
||||
// get a pointer to the input data of the correct type
|
||||
Float32* pInData = static_cast<Float32*> ( inInputData->mBuffers[0].mData );
|
||||
Float32* pLeftData = static_cast<Float32*> ( inInputData->mBuffers[iSelInBufferLeft].mData );
|
||||
Float32* pRightData = static_cast<Float32*> ( inInputData->mBuffers[iSelInBufferRight].mData );
|
||||
int iNumChanPerFrameLeft = vecNumInBufChan[iSelInBufferLeft];
|
||||
int iNumChanPerFrameRight = vecNumInBufChan[iSelInBufferRight];
|
||||
|
||||
// copy input data
|
||||
for ( int i = 0; i < iCoreAudioBufferSizeMono; i++ )
|
||||
{
|
||||
// left
|
||||
pSound->vecsTmpAudioSndCrdStereo[2 * i] =
|
||||
(short) ( pInData[iNumInChan * i + iSelInputLeftChannel] * _MAXSHORT );
|
||||
|
||||
// right
|
||||
pSound->vecsTmpAudioSndCrdStereo[2 * i + 1] =
|
||||
(short) ( pInData[iNumInChan * i + iSelInputRightChannel] * _MAXSHORT );
|
||||
|
||||
/*
|
||||
// TEST mix channel with micro to the stereo output
|
||||
if ( iNumInChan == 4 )
|
||||
{
|
||||
// add mic input on input channel 4 to both stereo channels
|
||||
pSound->vecsTmpAudioSndCrdStereo[2 * i] =
|
||||
Double2Short ( (double) ( pInData[iNumInChan * i + 3] * _MAXSHORT ) +
|
||||
(double) pSound->vecsTmpAudioSndCrdStereo[2 * i] );
|
||||
pSound->vecsTmpAudioSndCrdStereo[2 * i + 1] =
|
||||
Double2Short ( (double) ( pInData[iNumInChan * i + 3] * _MAXSHORT ) +
|
||||
(double) pSound->vecsTmpAudioSndCrdStereo[2 * i + 1] );
|
||||
}
|
||||
*/
|
||||
|
||||
// copy left and right channels separately
|
||||
pSound->vecsTmpAudioSndCrdStereo[2 * i] = (short) ( pLeftData[iNumChanPerFrameLeft * i + iSelInInterlChLeft] * _MAXSHORT );
|
||||
pSound->vecsTmpAudioSndCrdStereo[2 * i + 1] = (short) ( pRightData[iNumChanPerFrameRight * i + iSelInInterlChRight] * _MAXSHORT );
|
||||
}
|
||||
}
|
||||
else if ( inInputData->mNumberBuffers == (UInt32) iNumInChan && // we should have a matching number of buffers to channels
|
||||
inInputData->mBuffers[0].mDataByteSize == static_cast<UInt32> ( iCoreAudioBufferSizeMono * 4 ) )
|
||||
{
|
||||
// one buffer per channel mode:
|
||||
AudioBuffer left = inInputData->mBuffers[iSelInputLeftChannel];
|
||||
Float32* pLeftData = static_cast<Float32*> ( left.mData );
|
||||
AudioBuffer right = inInputData->mBuffers[iSelInputRightChannel];
|
||||
Float32* pRightData = static_cast<Float32*> ( right.mData );
|
||||
|
||||
// copy input data
|
||||
for ( int i = 0; i < iCoreAudioBufferSizeMono; i++ )
|
||||
// add an additional optional channel
|
||||
if ( iSelAddInBufferLeft >= 0 )
|
||||
{
|
||||
// left
|
||||
pSound->vecsTmpAudioSndCrdStereo[2 * i] = (short) ( pLeftData[i] * _MAXSHORT );
|
||||
pLeftData = static_cast<Float32*> ( inInputData->mBuffers[iSelAddInBufferLeft].mData );
|
||||
iNumChanPerFrameLeft = vecNumInBufChan[iSelAddInBufferLeft];
|
||||
|
||||
// right
|
||||
pSound->vecsTmpAudioSndCrdStereo[2 * i + 1] = (short) ( pRightData[i] * _MAXSHORT );
|
||||
for ( int i = 0; i < iCoreAudioBufferSizeMono; i++ )
|
||||
{
|
||||
pSound->vecsTmpAudioSndCrdStereo[2 * i] = Double2Short (
|
||||
pSound->vecsTmpAudioSndCrdStereo[2 * i] + pLeftData[iNumChanPerFrameLeft * i + iSelAddInInterlChLeft] * _MAXSHORT );
|
||||
}
|
||||
}
|
||||
|
||||
if ( iSelAddInBufferRight >= 0 )
|
||||
{
|
||||
pRightData = static_cast<Float32*> ( inInputData->mBuffers[iSelAddInBufferRight].mData );
|
||||
iNumChanPerFrameRight = vecNumInBufChan[iSelAddInBufferRight];
|
||||
|
||||
for ( int i = 0; i < iCoreAudioBufferSizeMono; i++ )
|
||||
{
|
||||
pSound->vecsTmpAudioSndCrdStereo[2 * i + 1] = Double2Short (
|
||||
pSound->vecsTmpAudioSndCrdStereo[2 * i + 1] + pRightData[iNumChanPerFrameRight * i + iSelAddInInterlChRight] * _MAXSHORT );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -899,42 +1011,26 @@ if ( iNumInChan == 4 )
|
|||
|
||||
if ( ( inDevice == pSound->CurrentAudioOutputDeviceID ) && outOutputData )
|
||||
{
|
||||
// check size (float32 has four bytes)
|
||||
if ( outOutputData->mBuffers[0].mDataByteSize ==
|
||||
static_cast<UInt32> ( iCoreAudioBufferSizeMono * iNumOutChan * 4 ) )
|
||||
{
|
||||
// one buffer with all the channels in interleaved format:
|
||||
// get a pointer to the input data of the correct type
|
||||
Float32* pOutData = static_cast<Float32*> ( outOutputData->mBuffers[0].mData );
|
||||
// check sizes (note that float32 has four bytes)
|
||||
if ( ( iSelOutBufferLeft >= 0 ) &&
|
||||
( iSelOutBufferLeft < static_cast<int> ( outOutputData->mNumberBuffers ) ) &&
|
||||
( iSelOutBufferRight >= 0 ) &&
|
||||
( iSelOutBufferRight < static_cast<int> ( outOutputData->mNumberBuffers ) ) &&
|
||||
( outOutputData->mBuffers[iSelOutBufferLeft].mDataByteSize == static_cast<UInt32> ( vecNumOutBufChan[iSelOutBufferLeft] * iCoreAudioBufferSizeMono * 4 ) ) &&
|
||||
( outOutputData->mBuffers[iSelOutBufferRight].mDataByteSize == static_cast<UInt32> ( vecNumOutBufChan[iSelOutBufferRight] * iCoreAudioBufferSizeMono * 4 ) ) )
|
||||
{
|
||||
Float32* pLeftData = static_cast<Float32*> ( outOutputData->mBuffers[iSelOutBufferLeft].mData );
|
||||
Float32* pRightData = static_cast<Float32*> ( outOutputData->mBuffers[iSelOutBufferRight].mData );
|
||||
int iNumChanPerFrameLeft = vecNumOutBufChan[iSelOutBufferLeft];
|
||||
int iNumChanPerFrameRight = vecNumOutBufChan[iSelOutBufferRight];
|
||||
|
||||
// copy output data
|
||||
for ( int i = 0; i < iCoreAudioBufferSizeMono; i++ )
|
||||
{
|
||||
// left
|
||||
pOutData[iNumOutChan * i + iSelOutputLeftChannel] =
|
||||
(Float32) pSound->vecsTmpAudioSndCrdStereo[2 * i] / _MAXSHORT;
|
||||
|
||||
// right
|
||||
pOutData[iNumOutChan * i + iSelOutputRightChannel] =
|
||||
(Float32) pSound->vecsTmpAudioSndCrdStereo[2 * i + 1] / _MAXSHORT;
|
||||
}
|
||||
}
|
||||
else if ( outOutputData->mNumberBuffers == (UInt32) iNumOutChan && // we should have a matching number of buffers to channels
|
||||
outOutputData->mBuffers[0].mDataByteSize == static_cast<UInt32> ( iCoreAudioBufferSizeMono * 4 ) )
|
||||
{
|
||||
// Outputs are to individual buffers too, rather than using channels
|
||||
Float32* pLeftOutData = static_cast<Float32*> ( outOutputData->mBuffers[iSelOutputLeftChannel].mData );
|
||||
Float32* pRightOutData = static_cast<Float32*> ( outOutputData->mBuffers[iSelOutputRightChannel].mData );
|
||||
|
||||
// copy output data
|
||||
for ( int i = 0; i < iCoreAudioBufferSizeMono; i++ )
|
||||
{
|
||||
// left
|
||||
pLeftOutData[i] = (Float32) pSound->vecsTmpAudioSndCrdStereo[2 * i] / _MAXSHORT;
|
||||
|
||||
// right
|
||||
pRightOutData[i] = (Float32) pSound->vecsTmpAudioSndCrdStereo[2 * i + 1] / _MAXSHORT;
|
||||
}
|
||||
// copy output data
|
||||
for ( int i = 0; i < iCoreAudioBufferSizeMono; i++ )
|
||||
{
|
||||
// copy left and right channels separately
|
||||
pLeftData[iNumChanPerFrameLeft * i + iSelOutInterlChLeft] = (Float32) pSound->vecsTmpAudioSndCrdStereo[2 * i] / _MAXSHORT;
|
||||
pRightData[iNumChanPerFrameRight * i + iSelOutInterlChRight] = (Float32) pSound->vecsTmpAudioSndCrdStereo[2 * i + 1] / _MAXSHORT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
31
mac/sound.h
|
@ -36,17 +36,18 @@
|
|||
class CSound : public CSoundBase
|
||||
{
|
||||
public:
|
||||
CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, void* arg ),
|
||||
void* arg,
|
||||
const int iCtrlMIDIChannel,
|
||||
const bool bNoAutoJackConnect );
|
||||
CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, void* arg ),
|
||||
void* arg,
|
||||
const int iCtrlMIDIChannel,
|
||||
const bool ,
|
||||
const QString& );
|
||||
|
||||
virtual int Init ( const int iNewPrefMonoBufferSize );
|
||||
virtual void Start();
|
||||
virtual void Stop();
|
||||
|
||||
// channel selection
|
||||
virtual int GetNumInputChannels() { return iNumInChan; }
|
||||
virtual int GetNumInputChannels() { return iNumInChanPlusAddChan; }
|
||||
virtual QString GetInputChannelName ( const int iDiD ) { return sChannelNamesInput[iDiD]; }
|
||||
virtual void SetLeftInputChannel ( const int iNewChan );
|
||||
virtual void SetRightInputChannel ( const int iNewChan );
|
||||
|
@ -68,18 +69,34 @@ public:
|
|||
AudioDeviceID CurrentAudioInputDeviceID;
|
||||
AudioDeviceID CurrentAudioOutputDeviceID;
|
||||
int iNumInChan;
|
||||
int iNumInChanPlusAddChan; // includes additional "added" channels
|
||||
int iNumOutChan;
|
||||
int iSelInputLeftChannel;
|
||||
int iSelInputRightChannel;
|
||||
int iSelOutputLeftChannel;
|
||||
int iSelOutputRightChannel;
|
||||
int iSelInBufferLeft;
|
||||
int iSelInBufferRight;
|
||||
int iSelInInterlChLeft;
|
||||
int iSelInInterlChRight;
|
||||
int iSelAddInBufferLeft;
|
||||
int iSelAddInBufferRight;
|
||||
int iSelAddInInterlChLeft;
|
||||
int iSelAddInInterlChRight;
|
||||
int iSelOutBufferLeft;
|
||||
int iSelOutBufferRight;
|
||||
int iSelOutInterlChLeft;
|
||||
int iSelOutInterlChRight;
|
||||
CVector<int> vecNumInBufChan;
|
||||
CVector<int> vecNumOutBufChan;
|
||||
|
||||
protected:
|
||||
virtual QString LoadAndInitializeDriver ( int iIdx, bool );
|
||||
|
||||
QString CheckDeviceCapabilities ( const int iDriverIdx );
|
||||
QString CheckDeviceCapabilities ( const int iDriverIdx );
|
||||
void UpdateChSelection();
|
||||
|
||||
int CountChannels ( AudioDeviceID devID,
|
||||
const int iNumChanPerFrame,
|
||||
bool isInput );
|
||||
|
||||
UInt32 SetBufferSize ( AudioDeviceID& audioDeviceID,
|
||||
|
|
|
@ -30,174 +30,134 @@
|
|||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="PixmapLabelDreamLogo">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap/>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblVersion">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabelVersion</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblAuthorNames">
|
||||
<property name="text">
|
||||
<string>Author: Volker Fischer</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblCopyright">
|
||||
<property name="text">
|
||||
<string>Copyright (C) 2005-2020</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
<widget class="QLabel" name="pxlLogo">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="resources.qrc">:/png/main/res/fronticon.png</pixmap>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="pxlGigPicture">
|
||||
<widget class="QLabel" name="lblVersion">
|
||||
<property name="text">
|
||||
<string/>
|
||||
<string>TextLabelVersion</string>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="resources.qrc">:/png/main/res/logopicture.png</pixmap>
|
||||
<property name="wordWrap">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<widget class="QLabel" name="lblCopyright">
|
||||
<property name="text">
|
||||
<string>Copyright (C) 2005-2020 Volker Fischer and others</string>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Minimum</enum>
|
||||
<property name="wordWrap">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>1</height>
|
||||
</size>
|
||||
<property name="margin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</spacer>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="txvCredits"/>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>A&bout</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="txvAbout">
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>&Libraries</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="txvLibraries">
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_3">
|
||||
<attribute name="title">
|
||||
<string>&Contributors</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="txvContributors">
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_4">
|
||||
<attribute name="title">
|
||||
<string>&Translation</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="txvTranslation">
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
|
@ -251,7 +211,6 @@
|
|||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>buttonOk</tabstop>
|
||||
<tabstop>txvCredits</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="resources.qrc"/>
|
||||
|
|
|
@ -43,11 +43,11 @@ CChannelFader::CChannelFader ( QWidget* pNW,
|
|||
pPan = new QSlider (Qt::Horizontal, pLevelsBox);
|
||||
|
||||
pMuteSoloBox = new QWidget ( pFrame );
|
||||
pcbMute = new QCheckBox ( "Mute", pMuteSoloBox );
|
||||
pcbSolo = new QCheckBox ( "Solo", pMuteSoloBox );
|
||||
pcbMute = new QCheckBox ( tr ( "Mute" ), pMuteSoloBox );
|
||||
pcbSolo = new QCheckBox ( tr ( "Solo" ), pMuteSoloBox );
|
||||
|
||||
pLabelInstBox = new QGroupBox ( pFrame );
|
||||
plblLabel = new QLabel ( "", pFrame );
|
||||
plblLabel = new QLabel ( "", pFrame );
|
||||
plblInstrument = new QLabel ( pFrame );
|
||||
plblCountryFlag = new QLabel ( pFrame );
|
||||
|
||||
|
@ -116,15 +116,15 @@ CChannelFader::CChannelFader ( QWidget* pNW,
|
|||
Reset();
|
||||
|
||||
// add help text to controls
|
||||
plbrChannelLevel->setWhatsThis ( tr ( "<b>Channel Level:</b> Displays the "
|
||||
"pre-fader audio level of this channel. All connected clients at the "
|
||||
plbrChannelLevel->setWhatsThis ( "<b>" + tr ( "Channel Level" ) + ":</b> " +
|
||||
tr ( "Displays the pre-fader audio level of this channel. All connected clients at the "
|
||||
"server will be assigned an audio level, the same value for each client." ) );
|
||||
plbrChannelLevel->setAccessibleName ( tr ( "Input level of the current audio "
|
||||
"channel at the server" ) );
|
||||
|
||||
pFader->setWhatsThis ( tr ( "<b>Mixer Fader:</b> Adjusts the audio level of "
|
||||
"this channel. All connected clients at the server will be assigned "
|
||||
"an audio fader at each client, adjusting the local mix." ) );
|
||||
pFader->setWhatsThis ( "<b>" + tr ( "Mixer Fader" ) + ":</b> " + tr (
|
||||
"Adjusts the audio level of this channel. All connected clients at the server "
|
||||
"will be assigned an audio fader at each client, adjusting the local mix." ) );
|
||||
pFader->setAccessibleName ( tr ( "Local mix level setting of the current audio "
|
||||
"channel at the server" ) );
|
||||
|
||||
|
@ -132,17 +132,17 @@ CChannelFader::CChannelFader ( QWidget* pNW,
|
|||
" Works only in stero or preferably mono in/stereo out mode." ) );
|
||||
pPan->setAccessibleName ( tr ( "Local panning position of the current audio channel at the server" ) );
|
||||
|
||||
pcbMute->setWhatsThis ( tr ( "<b>Mute:</b> With the Mute checkbox, the "
|
||||
"audio channel can be muted." ) );
|
||||
pcbMute->setWhatsThis ( "<b>" + tr ( "Mute" ) + ":</b> " + tr (
|
||||
"With the Mute checkbox, the audio channel can be muted." ) );
|
||||
pcbMute->setAccessibleName ( tr ( "Mute button" ) );
|
||||
|
||||
pcbSolo->setWhatsThis ( tr ( "<b>Solo:</b> With the Solo checkbox, the "
|
||||
pcbSolo->setWhatsThis ( "<b>" + tr ( "Solo" ) + ":</b> " + tr ( "With the Solo checkbox, the "
|
||||
"audio channel can be set to solo which means that all other channels "
|
||||
"except of the current channel are muted. It is possible to set more than "
|
||||
"one channel to solo." ) );
|
||||
pcbSolo->setAccessibleName ( tr ( "Solo button" ) );
|
||||
|
||||
QString strFaderText = tr ( "<b>Fader Tag:</b> The fader tag "
|
||||
QString strFaderText = "<b>" + tr ( "Fader Tag" ) + ":</b> " + tr ( "The fader tag "
|
||||
"identifies the connected client. The tag name, the picture of your "
|
||||
"instrument and a flag of your country can be set in the main window." );
|
||||
|
||||
|
@ -474,13 +474,13 @@ void CChannelFader::SetChannelInfos ( const CChannelInfo& cChanInfo )
|
|||
// alias/name
|
||||
if ( !strReceivedName.isEmpty() )
|
||||
{
|
||||
strToolTip += "<h4>Alias/Name</h4>" + strReceivedName;
|
||||
strToolTip += "<h4>" + tr ( "Alias/Name" ) + "</h4>" + strReceivedName;
|
||||
}
|
||||
|
||||
// instrument
|
||||
if ( !CInstPictures::IsNotUsedInstrument ( iTTInstrument ) )
|
||||
{
|
||||
strToolTip += "<h4>Instrument</h4>" +
|
||||
strToolTip += "<h4>" + tr ( "Instrument" ) + "</h4>" +
|
||||
CInstPictures::GetName ( iTTInstrument );
|
||||
}
|
||||
|
||||
|
@ -488,7 +488,7 @@ void CChannelFader::SetChannelInfos ( const CChannelInfo& cChanInfo )
|
|||
if ( ( eTTCountry != QLocale::AnyCountry ) ||
|
||||
( !cChanInfo.strCity.isEmpty() ) )
|
||||
{
|
||||
strToolTip += "<h4>Location</h4>";
|
||||
strToolTip += "<h4>" + tr ( "Location" ) + "</h4>";
|
||||
|
||||
if ( !cChanInfo.strCity.isEmpty() )
|
||||
{
|
||||
|
@ -510,15 +510,15 @@ void CChannelFader::SetChannelInfos ( const CChannelInfo& cChanInfo )
|
|||
switch ( cChanInfo.eSkillLevel )
|
||||
{
|
||||
case SL_BEGINNER:
|
||||
strToolTip += "<h4>Skill Level</h4>Beginner";
|
||||
strToolTip += "<h4>" + tr ( "Skill Level" ) + "</h4>" + tr ( "Beginner" );
|
||||
break;
|
||||
|
||||
case SL_INTERMEDIATE:
|
||||
strToolTip += "<h4>Skill Level</h4>Intermediate";
|
||||
strToolTip += "<h4>" + tr ( "Skill Level" ) + "</h4>" + tr ( "Intermediate" );
|
||||
break;
|
||||
|
||||
case SL_PROFESSIONAL:
|
||||
strToolTip += "<h4>Skill Level</h4>Expert";
|
||||
strToolTip += "<h4>" + tr ( "Skill Level" ) + "</h4>" + tr ( "Expert" );
|
||||
break;
|
||||
|
||||
case SL_NOT_SET:
|
||||
|
@ -529,7 +529,7 @@ void CChannelFader::SetChannelInfos ( const CChannelInfo& cChanInfo )
|
|||
// if no information is given, leave the tool tip empty, otherwise add header
|
||||
if ( !strToolTip.isEmpty() )
|
||||
{
|
||||
strToolTip.prepend ( "<h3>Musician Profile</h3>" );
|
||||
strToolTip.prepend ( "<h3>" + tr ( "Musician Profile" ) + "</h3>" );
|
||||
}
|
||||
|
||||
plblCountryFlag->setToolTip ( strToolTip );
|
||||
|
@ -746,7 +746,7 @@ void CAudioMixerBoard::SetServerName ( const QString& strNewServerName )
|
|||
if ( strServerName.isEmpty() )
|
||||
{
|
||||
// no connection or connection was reset: show default title
|
||||
pGroupBox->setTitle ( "Server" );
|
||||
pGroupBox->setTitle ( tr ( "Server" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -755,13 +755,7 @@ void CAudioMixerBoard::SetServerName ( const QString& strNewServerName )
|
|||
// list was received, the connection was successful and the title is updated
|
||||
// with the correct server name. Make sure to choose a "try to connect" title
|
||||
// which is most striking (we use filled blocks and upper case letters).
|
||||
QByteArray baBlock;
|
||||
baBlock.append ( 0xE2 );
|
||||
baBlock.append ( 0x96 );
|
||||
baBlock.append ( 0x88 );
|
||||
QString sBlocks = QString().fromUtf8 ( baBlock ).repeated ( 5 );
|
||||
|
||||
pGroupBox->setTitle ( sBlocks + " T R Y I N G T O C O N N E C T " + sBlocks );
|
||||
pGroupBox->setTitle ( u8"\u2588\u2588\u2588\u2588\u2588 " + tr ( "T R Y I N G T O C O N N E C T" ) + u8" \u2588\u2588\u2588\u2588\u2588" );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ public:
|
|||
void SetChannelInfos ( const CChannelInfo& cChanInfo );
|
||||
void Show() { pFrame->show(); }
|
||||
void Hide() { pFrame->hide(); }
|
||||
bool IsVisible() { return plblLabel->isVisible(); }
|
||||
bool IsVisible() { return !pFrame->isHidden(); }
|
||||
bool IsSolo() { return pcbSolo->isChecked(); }
|
||||
bool IsMute() { return pcbMute->isChecked(); }
|
||||
void SetGUIDesign ( const EGUIDesign eNewDesign );
|
||||
|
|
|
@ -34,14 +34,14 @@ CChatDlg::CChatDlg ( QWidget* parent, Qt::WindowFlags f ) :
|
|||
|
||||
// Add help text to controls -----------------------------------------------
|
||||
// chat window
|
||||
txvChatWindow->setWhatsThis ( tr ( "<b>Chat Window:</b> The chat window "
|
||||
"shows a history of all chat messages." ) );
|
||||
txvChatWindow->setWhatsThis ( "<b>" + tr ( "Chat Window" ) + ":</b> " + tr (
|
||||
"The chat window shows a history of all chat messages." ) );
|
||||
|
||||
txvChatWindow->setAccessibleName ( tr ( "Chat history" ) );
|
||||
|
||||
// input message text
|
||||
edtLocalInputText->setWhatsThis ( tr ( "<b>Input Message Text:</b> Enter "
|
||||
"the chat message text in the edit box and press enter to send the "
|
||||
edtLocalInputText->setWhatsThis ( "<b>" + tr ( "Input Message Text" ) + ":</b> " + tr (
|
||||
"Enter the chat message text in the edit box and press enter to send the "
|
||||
"message to the server which distributes the message to all connected "
|
||||
"clients. Your message will then show up in the chat window." ) );
|
||||
|
||||
|
|
|
@ -29,7 +29,8 @@
|
|||
CClient::CClient ( const quint16 iPortNumber,
|
||||
const QString& strConnOnStartupAddress,
|
||||
const int iCtrlMIDIChannel,
|
||||
const bool bNoAutoJackConnect ) :
|
||||
const bool bNoAutoJackConnect,
|
||||
const QString& strNClientName ) :
|
||||
vstrIPAddress ( MAX_NUM_SERVER_ADDR_ITEMS, "" ),
|
||||
ChannelInfo (),
|
||||
vecStoredFaderTags ( MAX_NUM_STORED_FADER_SETTINGS, "" ),
|
||||
|
@ -38,6 +39,7 @@ CClient::CClient ( const quint16 iPortNumber,
|
|||
vecStoredFaderIsMute ( MAX_NUM_STORED_FADER_SETTINGS, false ),
|
||||
iNewClientFaderLevel ( 100 ),
|
||||
bConnectDlgShowAllMusicians ( true ),
|
||||
strClientName ( strNClientName ),
|
||||
vecWindowPosMain (), // empty array
|
||||
vecWindowPosSettings (), // empty array
|
||||
vecWindowPosChat (), // empty array
|
||||
|
@ -59,7 +61,7 @@ CClient::CClient ( const quint16 iPortNumber,
|
|||
bIsInitializationPhase ( true ),
|
||||
bMuteOutStream ( false ),
|
||||
Socket ( &Channel, iPortNumber ),
|
||||
Sound ( AudioCallback, this, iCtrlMIDIChannel, bNoAutoJackConnect ),
|
||||
Sound ( AudioCallback, this, iCtrlMIDIChannel, bNoAutoJackConnect, strNClientName ),
|
||||
iAudioInFader ( AUD_FADER_IN_MIDDLE ),
|
||||
bReverbOnLeftChan ( false ),
|
||||
iReverbLevel ( 0 ),
|
||||
|
@ -945,7 +947,7 @@ vecsMultChanAudioSndCrd = vecsStereoSndCrdTMP; // TEST just copy the stereo data
|
|||
|
||||
void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
|
||||
{
|
||||
int i, j;
|
||||
int i, j, iUnused;
|
||||
unsigned char* pCurCodedData;
|
||||
|
||||
|
||||
|
@ -957,7 +959,7 @@ void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
|
|||
if ( iReverbLevel != 0 )
|
||||
{
|
||||
// calculate attenuation amplification factor
|
||||
const double dRevLev = static_cast<double> ( iReverbLevel ) / AUD_REVERB_MAX / 2;
|
||||
const double dRevLev = static_cast<double> ( iReverbLevel ) / AUD_REVERB_MAX / 4;
|
||||
|
||||
if ( eAudioChannelConf == CC_STEREO )
|
||||
{
|
||||
|
@ -1094,19 +1096,19 @@ void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
|
|||
{
|
||||
if ( bMuteOutStream )
|
||||
{
|
||||
opus_custom_encode ( CurOpusEncoder,
|
||||
&vecZeros[i * iNumAudioChannels * iOPUSFrameSizeSamples],
|
||||
iOPUSFrameSizeSamples,
|
||||
&vecCeltData[0],
|
||||
iCeltNumCodedBytes );
|
||||
iUnused = opus_custom_encode ( CurOpusEncoder,
|
||||
&vecZeros[i * iNumAudioChannels * iOPUSFrameSizeSamples],
|
||||
iOPUSFrameSizeSamples,
|
||||
&vecCeltData[0],
|
||||
iCeltNumCodedBytes );
|
||||
}
|
||||
else
|
||||
{
|
||||
opus_custom_encode ( CurOpusEncoder,
|
||||
&vecsStereoSndCrd[i * iNumAudioChannels * iOPUSFrameSizeSamples],
|
||||
iOPUSFrameSizeSamples,
|
||||
&vecCeltData[0],
|
||||
iCeltNumCodedBytes );
|
||||
iUnused = opus_custom_encode ( CurOpusEncoder,
|
||||
&vecsStereoSndCrd[i * iNumAudioChannels * iOPUSFrameSizeSamples],
|
||||
iOPUSFrameSizeSamples,
|
||||
&vecCeltData[0],
|
||||
iCeltNumCodedBytes );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1150,11 +1152,11 @@ void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
|
|||
// OPUS decoding
|
||||
if ( CurOpusDecoder != nullptr )
|
||||
{
|
||||
opus_custom_decode ( CurOpusDecoder,
|
||||
pCurCodedData,
|
||||
iCeltNumCodedBytes,
|
||||
&vecsStereoSndCrd[i * iNumAudioChannels * iOPUSFrameSizeSamples],
|
||||
iOPUSFrameSizeSamples );
|
||||
iUnused = opus_custom_decode ( CurOpusDecoder,
|
||||
pCurCodedData,
|
||||
iCeltNumCodedBytes,
|
||||
&vecsStereoSndCrd[i * iNumAudioChannels * iOPUSFrameSizeSamples],
|
||||
iOPUSFrameSizeSamples );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1204,6 +1206,8 @@ fflush(pFileDelay);
|
|||
|
||||
// update socket buffer size
|
||||
Channel.UpdateSocketBufferSize();
|
||||
|
||||
Q_UNUSED ( iUnused )
|
||||
}
|
||||
|
||||
int CClient::EstimatedOverallDelay ( const int iPingTimeMs )
|
||||
|
|
|
@ -107,7 +107,8 @@ public:
|
|||
CClient ( const quint16 iPortNumber,
|
||||
const QString& strConnOnStartupAddress,
|
||||
const int iCtrlMIDIChannel,
|
||||
const bool bNoAutoJackConnect );
|
||||
const bool bNoAutoJackConnect,
|
||||
const QString& strNClientName );
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
|
@ -285,6 +286,7 @@ public:
|
|||
CVector<int> vecStoredFaderIsMute;
|
||||
int iNewClientFaderLevel;
|
||||
bool bConnectDlgShowAllMusicians;
|
||||
QString strClientName;
|
||||
|
||||
// window position/state settings
|
||||
QByteArray vecWindowPosMain;
|
||||
|
@ -399,7 +401,7 @@ public slots:
|
|||
void OnJittBufSizeChanged ( int iNewJitBufSize );
|
||||
void OnReqChanInfo() { Channel.SetRemoteInfo ( ChannelInfo ); }
|
||||
void OnNewConnection();
|
||||
void OnCLDisconnection ( CHostAddress InetAddr ) { if ( InetAddr == Channel.GetAddress() ) { Stop(); } }
|
||||
void OnCLDisconnection ( CHostAddress InetAddr ) { if ( InetAddr == Channel.GetAddress() ) { emit Disconnected(); } }
|
||||
void OnCLPingReceived ( CHostAddress InetAddr,
|
||||
int iMs );
|
||||
|
||||
|
|
|
@ -48,10 +48,10 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
|
|||
|
||||
// Add help text to controls -----------------------------------------------
|
||||
// input level meter
|
||||
QString strInpLevH = tr ( "<b>Input Level Meter:</b> The input level "
|
||||
QString strInpLevH = "<b>" + tr ( "Input Level Meter" ) + ":</b> " + tr ( "The input level "
|
||||
"indicators show the input level of the two stereo channels "
|
||||
"of the current selected audio input.<br>"
|
||||
"Make sure not to clip the input signal to avoid distortions of the "
|
||||
"of the current selected audio input." ) + "<br>" +
|
||||
tr ( "Make sure not to clip the input signal to avoid distortions of the "
|
||||
"audio signal." );
|
||||
|
||||
QString strInpLevHTT = tr ( "If the " ) + APP_NAME +
|
||||
|
@ -60,13 +60,13 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
|
|||
"meter should flicker. If this is not the case, you have "
|
||||
"probably selected the wrong input channel (e.g. line in instead "
|
||||
"of the microphone input) or set the input gain too low in the "
|
||||
"(Windows) audio mixer.<br>For a proper usage of the " ) + APP_NAME +
|
||||
tr ( " software, "
|
||||
"(Windows) audio mixer." ) + "<br>" + tr ( "For a proper usage of the " ) +
|
||||
APP_NAME + tr ( " software, "
|
||||
"you should not hear your singing/instrument in the loudspeaker or "
|
||||
"your headphone when the " ) + APP_NAME +
|
||||
tr ( " software is not connected. This can "
|
||||
"be achieved by muting your input audio channel in the Playback "
|
||||
"mixer (<b>not</b> the Recording mixer!)." ) + TOOLTIP_COM_END_TEXT;
|
||||
"mixer (not the Recording mixer!)." ) + TOOLTIP_COM_END_TEXT;
|
||||
|
||||
QString strInpLevHAccText = tr ( "Input level meter" );
|
||||
QString strInpLevHAccDescr = tr ( "Simulates an analog LED level meter." );
|
||||
|
@ -84,8 +84,8 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
|
|||
lbrInputLevelR->setToolTip ( strInpLevHTT );
|
||||
|
||||
// connect/disconnect button
|
||||
butConnect->setWhatsThis ( tr ( "<b>Connect / Disconnect Button:"
|
||||
"</b> Push this button to connect a server. A dialog where you can "
|
||||
butConnect->setWhatsThis ( "<b>" + tr ( "Connect/Disconnect Button" ) + ":</b> " +
|
||||
tr ( "Push this button to connect a server. A dialog where you can "
|
||||
"select a server will open. If you are connected, pressing this "
|
||||
"button will end the session." ) );
|
||||
|
||||
|
@ -98,14 +98,15 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
|
|||
"and disconnecting the " ) + APP_NAME + tr ( " software." ) );
|
||||
|
||||
// local audio input fader
|
||||
QString strAudFader = tr ( "<b>Local Audio Input Fader:</b> With the "
|
||||
"audio fader, the relative levels of the left and right local audio "
|
||||
QString strAudFader = "<b>" + tr ( "Local Audio Input Fader" ) + ":</b> " +
|
||||
tr ( "With the audio fader, the relative levels of the left and right local audio "
|
||||
"channels can be changed. For a mono signal it acts like a panning "
|
||||
"between the two channels. If, e.g., a microphone is connected to "
|
||||
"the right input channel and an instrument is connected to the left "
|
||||
"input channel which is much louder than the microphone, move the "
|
||||
"audio fader in a direction where the label above the fader shows "
|
||||
"<i>L -x</i>, where <i>x</i> is the current attenuation indicator." );
|
||||
"audio fader in a direction where the label above the fader shows " ) +
|
||||
"<i>" + tr ( "L" ) + " -x</i>" + tr ( ", where" ) + " <i>x</i> " +
|
||||
tr ( "is the current attenuation indicator." );
|
||||
|
||||
lblAudioPan->setWhatsThis ( strAudFader );
|
||||
lblAudioPanValue->setWhatsThis ( strAudFader );
|
||||
|
@ -114,14 +115,14 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
|
|||
sldAudioPan->setAccessibleName ( tr ( "Local audio input fader (left/right)" ) );
|
||||
|
||||
// reverberation level
|
||||
QString strAudReverb = tr ( "<b>Reverberation Level:</b> A reverberation "
|
||||
"effect can be applied to one local mono audio channel or to both "
|
||||
"channels in stereo mode. The mone channel selection and the "
|
||||
QString strAudReverb = "<b>" + tr ( "Reverberation Level" ) + ":</b> " +
|
||||
tr ( "A reverberation effect can be applied to one local mono audio channel or to both "
|
||||
"channels in stereo mode. The mono channel selection and the "
|
||||
"reverberation level can be modified. If, e.g., "
|
||||
"the microphone signal is fed into the right audio channel of the "
|
||||
"sound card and a reverberation effect shall be applied, set the "
|
||||
"channel selector to right and move the fader upwards until the "
|
||||
"desired reverberation level is reached.<br>"
|
||||
"desired reverberation level is reached." ) + "<br>" + tr (
|
||||
"The reverberation effect requires significant CPU so that it should "
|
||||
"only be used on fast PCs. If the reverberation level fader is set to "
|
||||
"minimum (which is the default setting), the reverberation effect is "
|
||||
|
@ -133,8 +134,8 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
|
|||
sldAudioReverb->setAccessibleName ( tr ( "Reverberation effect level setting" ) );
|
||||
|
||||
// reverberation channel selection
|
||||
QString strRevChanSel = tr ( "<b>Reverberation Channel Selection:</b> "
|
||||
"With these radio buttons the audio input channel on which the "
|
||||
QString strRevChanSel = "<b>" + tr ( "Reverberation Channel Selection" ) + ":</b> " +
|
||||
tr ( "With these radio buttons the audio input channel on which the "
|
||||
"reverberation effect is applied can be chosen. Either the left "
|
||||
"or right input channel can be selected." );
|
||||
|
||||
|
@ -144,8 +145,8 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
|
|||
rbtReverbSelR->setAccessibleName ( tr ( "Right channel selection for reverberation" ) );
|
||||
|
||||
// delay LED
|
||||
QString strLEDDelay = tr ( "<b>Delay Status LED:</b> "
|
||||
"The delay status LED indicator shows the current audio delay "
|
||||
QString strLEDDelay = "<b>" + tr ( "Delay Status LED" ) + ":</b> " +
|
||||
tr ( "The delay status LED indicator shows the current audio delay "
|
||||
"status. If the light is green, the delay is perfect for a jam "
|
||||
"session. If the light is yellow, a session is still possible but "
|
||||
"it may be harder to play. If the light is red, the delay is too "
|
||||
|
@ -160,20 +161,20 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
|
|||
ledDelay->setAccessibleName ( tr ( "Delay status LED indicator" ) );
|
||||
|
||||
// buffers LED
|
||||
QString strLEDBuffers = tr ( "<b>Buffers Status LED:</b> "
|
||||
"The buffers status LED indicator shows the current audio/streaming "
|
||||
QString strLEDBuffers = "<b>" + tr ( "Buffers Status LED" ) + ":</b> " +
|
||||
tr ( "The buffers status LED indicator shows the current audio/streaming "
|
||||
"status. If the light is green, there are no buffer overruns/underruns "
|
||||
"and the audio stream is not interrupted. If the light is red, the "
|
||||
"audio stream is interrupted caused by one of the following problems:"
|
||||
"audio stream is interrupted caused by one of the following problems:" ) +
|
||||
"<ul>"
|
||||
"<li>The network jitter buffer is not large enough for the current "
|
||||
"network/audio interface jitter.</li>"
|
||||
"<li>The sound card buffer delay (buffer size) is set to a too small "
|
||||
"value.</li>"
|
||||
"<li>The upload or download stream rate is too high for the current "
|
||||
"available internet bandwidth.</li>"
|
||||
"<li>The CPU of the client or server is at 100%.</li>"
|
||||
"</ul>" );
|
||||
"<li>" + tr ( "The network jitter buffer is not large enough for the current "
|
||||
"network/audio interface jitter." ) + "</li>"
|
||||
"<li>" + tr ( "The sound card buffer delay (buffer size) is set to a too small "
|
||||
"value." ) + "</li>"
|
||||
"<li>" + tr ( "The upload or download stream rate is too high for the current "
|
||||
"available internet bandwidth." ) + "</li>"
|
||||
"<li>" + tr ( "The CPU of the client or server is at 100%." ) + "</li>"
|
||||
"</ul>";
|
||||
|
||||
lblBuffers->setWhatsThis ( strLEDBuffers );
|
||||
ledBuffers->setWhatsThis ( strLEDBuffers );
|
||||
|
@ -200,7 +201,7 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
|
|||
OnTimerStatus();
|
||||
|
||||
// init connection button text
|
||||
butConnect->setText ( CON_BUT_CONNECTTEXT );
|
||||
butConnect->setText ( tr ( "C&onnect" ) );
|
||||
|
||||
// init input level meter bars
|
||||
lbrInputLevelL->setValue ( 0 );
|
||||
|
@ -252,7 +253,7 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
|
|||
|
||||
|
||||
// View menu --------------------------------------------------------------
|
||||
pViewMenu = new QMenu ( "&View", this );
|
||||
pViewMenu = new QMenu ( tr ( "&View" ), this );
|
||||
|
||||
pViewMenu->addAction ( tr ( "&Connection Setup..." ), this,
|
||||
SLOT ( OnOpenConnectionSetupDialog() ) );
|
||||
|
@ -283,7 +284,7 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
|
|||
pMenu = new QMenuBar ( this );
|
||||
|
||||
pMenu->addMenu ( pViewMenu );
|
||||
pMenu->addMenu ( new CHelpMenu ( this ) );
|
||||
pMenu->addMenu ( new CHelpMenu ( true, this ) );
|
||||
|
||||
// Now tell the layout about the menu
|
||||
layout()->setMenuBar ( pMenu );
|
||||
|
@ -323,7 +324,7 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
|
|||
{
|
||||
// default icon and name for no flag selected
|
||||
CurFlagIcon.addFile ( ":/png/flags/res/flags/flagnone.png" );
|
||||
sCurCountryName = "None";
|
||||
sCurCountryName = tr ( "None" );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -606,20 +607,20 @@ void CClientDlg::UpdateAudioFaderSlider()
|
|||
// attenuated
|
||||
if ( iCurAudInFader == AUD_FADER_IN_MIDDLE )
|
||||
{
|
||||
lblAudioPanValue->setText ( "Center" );
|
||||
lblAudioPanValue->setText ( tr ( "Center" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( iCurAudInFader > AUD_FADER_IN_MIDDLE )
|
||||
{
|
||||
// attenuation on right channel
|
||||
lblAudioPanValue->setText ( "R -" +
|
||||
lblAudioPanValue->setText ( tr ( "R" ) + " -" +
|
||||
QString().setNum ( iCurAudInFader - AUD_FADER_IN_MIDDLE ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// attenuation on left channel
|
||||
lblAudioPanValue->setText ( "L -" +
|
||||
lblAudioPanValue->setText ( tr ( "L" ) + " -" +
|
||||
QString().setNum ( AUD_FADER_IN_MIDDLE - iCurAudInFader ) );
|
||||
}
|
||||
}
|
||||
|
@ -734,16 +735,6 @@ void CClientDlg::OnConnectDisconBut()
|
|||
}
|
||||
}
|
||||
|
||||
void CClientDlg::OnDisconnected()
|
||||
{
|
||||
// channel is now disconnected, clear mixer board (remove all faders) and
|
||||
// reset the delay LED (since this is only updated on an active connection)
|
||||
MainMixerBoard->HideAll();
|
||||
ledDelay->Reset();
|
||||
|
||||
UpdateDisplay();
|
||||
}
|
||||
|
||||
void CClientDlg::OnCentralServerAddressTypeChanged()
|
||||
{
|
||||
// if the server list is shown and the server type was changed, update the list
|
||||
|
@ -812,18 +803,18 @@ void CClientDlg::SetMyWindowTitle ( const int iNumClients )
|
|||
if ( iNumClients == 0 )
|
||||
{
|
||||
// only application name
|
||||
setWindowTitle ( APP_NAME );
|
||||
setWindowTitle ( pClient->strClientName );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( iNumClients == 1 )
|
||||
{
|
||||
setWindowTitle ( QString ( APP_NAME ) + " (1 user)" );
|
||||
setWindowTitle ( QString ( pClient->strClientName ) + " (1 " + tr ( "user" ) + ")" );
|
||||
}
|
||||
else
|
||||
{
|
||||
setWindowTitle ( QString ( APP_NAME ) +
|
||||
QString ( " (%1 users)" ).arg ( iNumClients ) );
|
||||
setWindowTitle ( QString ( pClient->strClientName ) +
|
||||
QString ( " (%1 " + tr ( "users" ) + ")" ).arg ( iNumClients ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1060,7 +1051,7 @@ void CClientDlg::Connect ( const QString& strSelectedAddress,
|
|||
}
|
||||
|
||||
// change connect button text to "disconnect"
|
||||
butConnect->setText ( CON_BUT_DISCONNECTTEXT );
|
||||
butConnect->setText ( tr ( "D&isconnect" ) );
|
||||
|
||||
// set server name in audio mixer group box title
|
||||
MainMixerBoard->SetServerName ( strMixerBoardLabel );
|
||||
|
@ -1084,7 +1075,7 @@ void CClientDlg::Disconnect()
|
|||
}
|
||||
|
||||
// change connect button text to "connect"
|
||||
butConnect->setText ( CON_BUT_CONNECTTEXT );
|
||||
butConnect->setText ( tr ( "C&onnect" ) );
|
||||
|
||||
// reset server name in audio mixer group box title
|
||||
MainMixerBoard->SetServerName ( "" );
|
||||
|
|
|
@ -51,10 +51,6 @@
|
|||
|
||||
|
||||
/* Definitions ****************************************************************/
|
||||
// text strings for connection button for connect and disconnect
|
||||
#define CON_BUT_CONNECTTEXT "C&onnect"
|
||||
#define CON_BUT_DISCONNECTTEXT "D&isconnect"
|
||||
|
||||
// update time for GUI controls
|
||||
#define LEVELMETER_UPDATE_TIME_MS 100 // ms
|
||||
#define BUFFER_LED_UPDATE_TIME_MS 300 // ms
|
||||
|
@ -102,7 +98,7 @@ protected:
|
|||
QTimer TimerStatus;
|
||||
QTimer TimerPing;
|
||||
|
||||
virtual void closeEvent ( QCloseEvent* Event );
|
||||
virtual void closeEvent ( QCloseEvent* Event );
|
||||
void UpdateDisplay();
|
||||
|
||||
QMenu* pViewMenu;
|
||||
|
@ -201,7 +197,7 @@ public slots:
|
|||
{ MainMixerBoard->SetChannelLevels ( vecLevelList ); }
|
||||
|
||||
void OnConnectDlgAccepted();
|
||||
void OnDisconnected();
|
||||
void OnDisconnected() { Disconnect(); }
|
||||
void OnCentralServerAddressTypeChanged();
|
||||
|
||||
void OnGUIDesignChanged()
|
||||
|
|
|
@ -249,7 +249,7 @@
|
|||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>16</width>
|
||||
<width>19</width>
|
||||
<height>88</height>
|
||||
</size>
|
||||
</property>
|
||||
|
@ -265,7 +265,7 @@
|
|||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>16</width>
|
||||
<width>19</width>
|
||||
<height>88</height>
|
||||
</size>
|
||||
</property>
|
||||
|
@ -548,43 +548,13 @@
|
|||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="MixerBoardPages">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
<widget class="CAudioMixerBoard" name="MainMixerBoard" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="ServerMixer">
|
||||
<layout class="QHBoxLayout" name="horizontalLayoutMainMixer">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="CAudioMixerBoard" name="MainMixerBoard" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="InputLeftMixer"/>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
|
@ -34,34 +34,34 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
|
|||
|
||||
// Add help text to controls -----------------------------------------------
|
||||
// jitter buffer
|
||||
QString strJitterBufferSize = tr ( "<b>Jitter Buffer Size:</b> The jitter "
|
||||
"buffer compensates for network and sound card timing jitters. The "
|
||||
QString strJitterBufferSize = "<b>" + tr ( "Jitter Buffer Size" ) + ":</b> " + tr (
|
||||
"The jitter buffer compensates for network and sound card timing jitters. The "
|
||||
"size of this jitter buffer has therefore influence on the quality of "
|
||||
"the audio stream (how many dropouts occur) and the overall delay "
|
||||
"(the longer the buffer, the higher the delay).<br>"
|
||||
"(the longer the buffer, the higher the delay)." ) + "<br>" + tr (
|
||||
"The jitter buffer size can be manually chosen for the local client "
|
||||
"and the remote server. For the local jitter buffer, dropouts in the "
|
||||
"audio stream are indicated by the light on the bottom "
|
||||
"of the jitter buffer size faders. If the light turns to red, a buffer "
|
||||
"overrun/underrun took place and the audio stream is interrupted.<br>"
|
||||
"overrun/underrun took place and the audio stream is interrupted." ) + "<br>" + tr (
|
||||
"The jitter buffer setting is therefore a trade-off between audio "
|
||||
"quality and overall delay.<br>"
|
||||
"quality and overall delay." ) + "<br>" + tr (
|
||||
"An auto setting of the jitter buffer size setting is available. If "
|
||||
"the check Auto is enabled, the jitter buffers of the local client and "
|
||||
"the remote server are set automatically "
|
||||
"based on measurements of the network and sound card timing jitter. If "
|
||||
"the <i>Auto</i> check is enabled, the jitter buffer size faders are "
|
||||
"the Auto check is enabled, the jitter buffer size faders are "
|
||||
"disabled (they cannot be moved with the mouse)." );
|
||||
|
||||
QString strJitterBufferSizeTT = tr ( "In case the auto setting of the "
|
||||
"jitter buffer is enabled, the network buffers of the local client and "
|
||||
"the remote server are set to a conservative "
|
||||
"value to minimize the audio dropout probability. To <b>tweak the "
|
||||
"audio delay/latency</b> it is recommended to disable the auto setting "
|
||||
"functionality and to <b>lower the jitter buffer size manually</b> by "
|
||||
"value to minimize the audio dropout probability. To tweak the "
|
||||
"audio delay/latency it is recommended to disable the auto setting "
|
||||
"functionality and to lower the jitter buffer size manually by "
|
||||
"using the sliders until your personal acceptable limit of the amount "
|
||||
"of dropouts is reached. The LED indicator will visualize the audio "
|
||||
"dropouts of the local jitter buffer by a red light" ) +
|
||||
"dropouts of the local jitter buffer by a red light." ) +
|
||||
TOOLTIP_COM_END_TEXT;
|
||||
|
||||
lblNetBuf->setWhatsThis ( strJitterBufferSize );
|
||||
|
@ -80,11 +80,11 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
|
|||
ledNetw->setToolTip ( strJitterBufferSizeTT );
|
||||
|
||||
// sound card device
|
||||
cbxSoundcard->setWhatsThis ( tr ( "<b>Sound Card Device:</b> The ASIO "
|
||||
"driver (sound card) can be selected using " ) + APP_NAME +
|
||||
cbxSoundcard->setWhatsThis ( "<b>" + tr ( "Sound Card Device" ) + ":</b> " +
|
||||
tr ( "The ASIO driver (sound card) can be selected using " ) + APP_NAME +
|
||||
tr ( " under the Windows operating system. Under MacOS/Linux, no sound "
|
||||
"card selection is possible. If the selected ASIO driver is not valid "
|
||||
"an error message is shown and the previous valid driver is selected.<br>"
|
||||
"an error message is shown and the previous valid driver is selected." ) + "<br>" + tr (
|
||||
"If the driver is selected during an active connection, the connection "
|
||||
"is stopped, the driver is changed and the connection is started again "
|
||||
"automatically." ) );
|
||||
|
@ -93,19 +93,19 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
|
|||
|
||||
#ifdef _WIN32
|
||||
// set Windows specific tool tip
|
||||
cbxSoundcard->setToolTip ( tr ( "In case the <b>ASIO4ALL</b> driver is used, "
|
||||
cbxSoundcard->setToolTip ( tr ( "In case the ASIO4ALL driver is used, "
|
||||
"please note that this driver usually introduces approx. 10-30 ms of "
|
||||
"additional audio delay. Using a sound card with a native ASIO driver "
|
||||
"is therefore recommended.<br>If you are using the <b>kX ASIO</b> "
|
||||
"is therefore recommended." ) + "<br>" + tr ( "If you are using the kX ASIO "
|
||||
"driver, make sure to connect the ASIO inputs in the kX DSP settings "
|
||||
"panel." ) + TOOLTIP_COM_END_TEXT );
|
||||
#endif
|
||||
|
||||
// sound card input/output channel mapping
|
||||
QString strSndCrdChanMapp = tr ( "<b>Sound Card Channel Mapping:</b> "
|
||||
"In case the selected sound card device offers more than one "
|
||||
QString strSndCrdChanMapp = "<b>" + tr ( "Sound Card Channel Mapping" ) + ":</b> " +
|
||||
tr ( "In case the selected sound card device offers more than one "
|
||||
"input or output channel, the Input Channel Mapping and Output "
|
||||
"Channel Mapping settings are visible.<br>"
|
||||
"Channel Mapping settings are visible." ) + "<br>" + tr (
|
||||
"For each " ) + APP_NAME + tr ( " input/output channel (Left and "
|
||||
"Right channel) a different actual sound card channel can be "
|
||||
"selected." );
|
||||
|
@ -122,8 +122,8 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
|
|||
cbxROutChan->setAccessibleName ( tr ( "Right output channel selection combo box" ) );
|
||||
|
||||
// enable OPUS64
|
||||
chbEnableOPUS64->setWhatsThis ( tr ( "<b>Enable Small Network Buffers:</b> If enabled, "
|
||||
"the support for very small network audio packets is activated. Very small "
|
||||
chbEnableOPUS64->setWhatsThis ( "<b>" + tr ( "Enable Small Network Buffers" ) + ":</b> " + tr (
|
||||
"If enabled, the support for very small network audio packets is activated. Very small "
|
||||
"network packets are only actually used if the sound card buffer delay is smaller than " ) +
|
||||
QString().setNum ( DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES ) + tr ( " samples. The "
|
||||
"smaller the network buffers, the smaller the audio latency. But at the same time "
|
||||
|
@ -132,35 +132,35 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
|
|||
chbEnableOPUS64->setAccessibleName ( tr ( "Enable small network buffers check box" ) );
|
||||
|
||||
// sound card buffer delay
|
||||
QString strSndCrdBufDelay = tr ( "<b>Sound Card Buffer Delay:</b> The "
|
||||
"buffer delay setting is a fundamental setting of the " ) +
|
||||
QString strSndCrdBufDelay = "<b>" + tr ( "Sound Card Buffer Delay" ) + ":</b> " +
|
||||
tr ( "The buffer delay setting is a fundamental setting of the " ) +
|
||||
APP_NAME + tr ( " software. This setting has influence on many "
|
||||
"connection properties.<br>"
|
||||
"Three buffer sizes are supported:"
|
||||
"<ul>"
|
||||
"<li>64 samples: This is the preferred setting since it gives lowest "
|
||||
"latency but does not work with all sound cards.</li>"
|
||||
"<li>128 samples: This setting should work on most of the available "
|
||||
"sound cards.</li>"
|
||||
"<li>256 samples: This setting should only be used if only a very slow "
|
||||
"computer or a slow internet connection is available.</li>"
|
||||
"</ul>"
|
||||
"connection properties." ) + "<br>" + tr (
|
||||
"Three buffer sizes are supported" ) +
|
||||
":<ul>"
|
||||
"<li>" + tr ( "64 samples: This is the preferred setting since it gives lowest "
|
||||
"latency but does not work with all sound cards." ) + "</li>"
|
||||
"<li>" + tr ( "128 samples: This setting should work on most of the available "
|
||||
"sound cards." ) + "</li>"
|
||||
"<li>" + tr ( "256 samples: This setting should only be used if only a very slow "
|
||||
"computer or a slow internet connection is available." ) + "</li>"
|
||||
"</ul>" + tr (
|
||||
"Some sound card driver do not allow the buffer delay to be changed "
|
||||
"from within the " ) + APP_NAME +
|
||||
tr ( " software. In this case the buffer delay setting "
|
||||
"is disabled. To change the actual buffer delay, this "
|
||||
"setting has to be changed in the sound card driver. On Windows, press "
|
||||
"the ASIO Setup button to open the driver settings panel. On Linux, "
|
||||
"use the Jack configuration tool to change the buffer size.<br>"
|
||||
"use the Jack configuration tool to change the buffer size." ) + "<br>" + tr (
|
||||
"If no buffer size is selected and all settings are disabled, an "
|
||||
"unsupported buffer size is used by the driver. The " ) + APP_NAME +
|
||||
tr ( " software will still work with this setting but with restricted "
|
||||
"performannce.<br>"
|
||||
"performance." ) + "<br>" + tr (
|
||||
"The actual buffer delay has influence on the connection status, the "
|
||||
"current upload rate and the overall delay. The lower the buffer size, "
|
||||
"the higher the probability of red light in the status indicator (drop "
|
||||
"outs) and the higher the upload rate and the lower the overall "
|
||||
"delay.<br>"
|
||||
"delay." ) + "<br>" + tr (
|
||||
"The buffer setting is therefore a trade-off between audio "
|
||||
"quality and overall delay." );
|
||||
|
||||
|
@ -185,19 +185,19 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
|
|||
butDriverSetup->setToolTip ( strSndCrdBufDelayTT );
|
||||
|
||||
// fancy skin
|
||||
chbGUIDesignFancy->setWhatsThis ( tr ( "<b>Fancy Skin:</b> If enabled, "
|
||||
"a fancy skin will be applied to the main window." ) );
|
||||
chbGUIDesignFancy->setWhatsThis ( "<b>" + tr ( "Fancy Skin" ) + ":</b> " + tr (
|
||||
"If enabled, a fancy skin will be applied to the main window." ) );
|
||||
|
||||
chbGUIDesignFancy->setAccessibleName ( tr ( "Fancy skin check box" ) );
|
||||
|
||||
// display channel levels
|
||||
chbDisplayChannelLevels->setWhatsThis ( tr ( "<b>Display Channel Levels:</b> "
|
||||
"If enabled, each client channel will display a pre-fader level bar." ) );
|
||||
chbDisplayChannelLevels->setWhatsThis ( "<b>" + tr ( "Display Channel Levels" ) + ":</b> " +
|
||||
tr ( "If enabled, each client channel will display a pre-fader level bar." ) );
|
||||
|
||||
chbDisplayChannelLevels->setAccessibleName ( tr ( "Display channel levels check box" ) );
|
||||
|
||||
// audio channels
|
||||
QString strAudioChannels = tr ( "<b>Audio Channels:</b> "
|
||||
QString strAudioChannels = "<b>" + tr ( "Audio Channels" ) + ":</b> " + tr (
|
||||
"Select the number of audio channels to be used. There are three "
|
||||
"modes available. The mono and stereo modes use one and two "
|
||||
"audio channels respectively. In the mono-in/stereo-out mode "
|
||||
|
@ -206,10 +206,10 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
|
|||
"sound card puts the instrument on one input channel and the "
|
||||
"microphone on the other channel. In that case the two input signals "
|
||||
"can be mixed to one mono channel but the server mix can be heard in "
|
||||
"stereo.<br>"
|
||||
"stereo." ) + "<br>" + tr (
|
||||
"Enabling the stereo streaming mode will increase the "
|
||||
"stream data rate. Make sure that the current upload rate does not "
|
||||
"exceed the available bandwidth of your internet connection.<br>"
|
||||
"exceed the available bandwidth of your internet connection." ) + "<br>" + tr (
|
||||
"In case of the stereo streaming mode, no audio channel selection "
|
||||
"for the reverberation effect will be available on the main window "
|
||||
"since the effect is applied on both channels in this case." );
|
||||
|
@ -219,7 +219,7 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
|
|||
cbxAudioChannels->setAccessibleName ( tr ( "Audio channels combo box" ) );
|
||||
|
||||
// audio quality
|
||||
QString strAudioQuality = tr ( "<b>Audio Quality:</b> "
|
||||
QString strAudioQuality = "<b>" + tr ( "Audio Quality" ) + ":</b> " + tr (
|
||||
"Select the desired audio quality. A low, normal or high audio "
|
||||
"quality can be selected. The higher the audio quality, the higher "
|
||||
"the audio stream data rate. Make sure that the current "
|
||||
|
@ -231,8 +231,8 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
|
|||
cbxAudioQuality->setAccessibleName ( tr ( "Audio quality combo box" ) );
|
||||
|
||||
// new client fader level
|
||||
QString strNewClientLevel = tr ( "<b>New Client Level:</b> The "
|
||||
"new client level setting defines the fader level of a new "
|
||||
QString strNewClientLevel = "<b>" + tr ( "New Client Level" ) + ":</b> " +
|
||||
tr ( "The new client level setting defines the fader level of a new "
|
||||
"connected client in percent. I.e. if a new client connects "
|
||||
"to the current server, it will get the specified initial "
|
||||
"fader level if no other fader level of a previous connection "
|
||||
|
@ -243,8 +243,8 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
|
|||
edtNewClientLevel->setAccessibleName ( tr ( "New client level edit box" ) );
|
||||
|
||||
// central server address
|
||||
QString strCentrServAddr = tr ( "<b>Central Server Address:</b> The "
|
||||
"central server address is the IP address or URL of the central server "
|
||||
QString strCentrServAddr = "<b>" + tr ( "Central Server Address" ) + ":</b> " +
|
||||
tr ( "The central server address is the IP address or URL of the central server "
|
||||
"at which the server list of the connection dialog is managed. With the "
|
||||
"central server address type either the local region can be selected of "
|
||||
"the default central servers or a manual address can be specified." );
|
||||
|
@ -257,15 +257,15 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
|
|||
edtCentralServerAddress->setAccessibleName ( tr ( "Central server address line edit" ) );
|
||||
|
||||
// current connection status parameter
|
||||
QString strConnStats = tr ( "<b>Current Connection Status "
|
||||
"Parameter:</b> The ping time is the time required for the audio "
|
||||
QString strConnStats = "<b>" + tr ( "Current Connection Status "
|
||||
"Parameter" ) + ":</b> " + tr ( "The ping time is the time required for the audio "
|
||||
"stream to travel from the client to the server and backwards. This "
|
||||
"delay is introduced by the network. This delay should be as low as "
|
||||
"20-30 ms. If this delay is higher (e.g., 50-60 ms), your distance to "
|
||||
"the server is too large or your internet connection is not "
|
||||
"sufficient.<br>"
|
||||
"sufficient." ) + "<br>" + tr (
|
||||
"The overall delay is calculated from the current ping time and the "
|
||||
"delay which is introduced by the current buffer settings.<br>"
|
||||
"delay which is introduced by the current buffer settings." ) + "<br>" + tr (
|
||||
"The upstream rate depends on the current audio packet size and the "
|
||||
"audio compression setting. Make sure that the upstream rate is not "
|
||||
"higher than the available rate (check the upstream capabilities of "
|
||||
|
@ -285,7 +285,7 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
|
|||
|
||||
// init driver button
|
||||
#ifdef _WIN32
|
||||
butDriverSetup->setText ( "ASIO Setup" );
|
||||
butDriverSetup->setText ( tr ( "ASIO Setup" ) );
|
||||
#else
|
||||
// no use for this button for MacOS/Linux right now -> hide it
|
||||
butDriverSetup->hide();
|
||||
|
@ -332,23 +332,23 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
|
|||
|
||||
// "Audio Channels" combo box
|
||||
cbxAudioChannels->clear();
|
||||
cbxAudioChannels->addItem ( "Mono" ); // CC_MONO
|
||||
cbxAudioChannels->addItem ( "Mono-in/Stereo-out" ); // CC_MONO_IN_STEREO_OUT
|
||||
cbxAudioChannels->addItem ( "Stereo" ); // CC_STEREO
|
||||
cbxAudioChannels->addItem ( tr ( "Mono" ) ); // CC_MONO
|
||||
cbxAudioChannels->addItem ( tr ( "Mono-in/Stereo-out" ) ); // CC_MONO_IN_STEREO_OUT
|
||||
cbxAudioChannels->addItem ( tr ( "Stereo" ) ); // CC_STEREO
|
||||
cbxAudioChannels->setCurrentIndex ( static_cast<int> ( pClient->GetAudioChannels() ) );
|
||||
|
||||
// "Audio Quality" combo box
|
||||
cbxAudioQuality->clear();
|
||||
cbxAudioQuality->addItem ( "Low" ); // AQ_LOW
|
||||
cbxAudioQuality->addItem ( "Normal" ); // AQ_NORMAL
|
||||
cbxAudioQuality->addItem ( "High" ); // AQ_HIGH
|
||||
cbxAudioQuality->addItem ( tr ( "Low" ) ); // AQ_LOW
|
||||
cbxAudioQuality->addItem ( tr ( "Normal" ) ); // AQ_NORMAL
|
||||
cbxAudioQuality->addItem ( tr ( "High" ) ); // AQ_HIGH
|
||||
cbxAudioQuality->setCurrentIndex ( static_cast<int> ( pClient->GetAudioQuality() ) );
|
||||
|
||||
// central server address type combo box
|
||||
cbxCentServAddrType->clear();
|
||||
cbxCentServAddrType->addItem ( "Manual" ); // AT_MANUAL
|
||||
cbxCentServAddrType->addItem ( "Default" ); // AT_DEFAULT
|
||||
cbxCentServAddrType->addItem ( "Default (North America)" ); // AT_NORTH_AMERICA
|
||||
cbxCentServAddrType->addItem ( tr ( "Manual" ) ); // AT_MANUAL
|
||||
cbxCentServAddrType->addItem ( tr ( "Default" ) ); // AT_DEFAULT
|
||||
cbxCentServAddrType->addItem ( tr ( "Default (North America)" ) ); // AT_NORTH_AMERICA
|
||||
cbxCentServAddrType->setCurrentIndex ( static_cast<int> ( pClient->GetCentralServerAddressType() ) );
|
||||
UpdateCentralServerDependency();
|
||||
|
||||
|
@ -364,7 +364,7 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
|
|||
|
||||
rbtBufferDelayDefault->setText ( GenSndCrdBufferDelayString (
|
||||
FRAME_SIZE_FACTOR_DEFAULT * SYSTEM_FRAME_SIZE_SAMPLES,
|
||||
", preferred" ) );
|
||||
", " + tr ( "preferred" ) ) );
|
||||
|
||||
rbtBufferDelaySafe->setText ( GenSndCrdBufferDelayString (
|
||||
FRAME_SIZE_FACTOR_SAFE * SYSTEM_FRAME_SIZE_SAMPLES ) );
|
||||
|
@ -454,11 +454,11 @@ void CClientSettingsDlg::UpdateJitterBufferFrame()
|
|||
// update slider value and text
|
||||
const int iCurNumNetBuf = pClient->GetSockBufNumFrames();
|
||||
sldNetBuf->setValue ( iCurNumNetBuf );
|
||||
lblNetBuf->setText ( "Size: " + QString().setNum ( iCurNumNetBuf ) );
|
||||
lblNetBuf->setText ( tr ( "Size: " ) + QString().setNum ( iCurNumNetBuf ) );
|
||||
|
||||
const int iCurNumNetBufServer = pClient->GetServerSockBufNumFrames();
|
||||
sldNetBufServer->setValue ( iCurNumNetBufServer );
|
||||
lblNetBufServer->setText ( "Size: " + QString().setNum ( iCurNumNetBufServer ) );
|
||||
lblNetBufServer->setText ( tr ( "Size: " ) + QString().setNum ( iCurNumNetBufServer ) );
|
||||
|
||||
// if auto setting is enabled, disable slider control
|
||||
const bool bIsAutoSockBufSize = pClient->GetDoAutoSockBufSize();
|
||||
|
@ -515,12 +515,12 @@ void CClientSettingsDlg::UpdateSoundCardFrame()
|
|||
if ( bPreferredChecked || bDefaultChecked || bSafeChecked )
|
||||
{
|
||||
// default title text
|
||||
grbSoundCrdBufDelay->setTitle ( "Buffer Delay" );
|
||||
grbSoundCrdBufDelay->setTitle ( tr ( "Buffer Delay" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// special title text with buffer size information added
|
||||
grbSoundCrdBufDelay->setTitle ( "Buffer Delay: " +
|
||||
grbSoundCrdBufDelay->setTitle ( tr ( "Buffer Delay: " ) +
|
||||
GenSndCrdBufferDelayString ( iCurActualBufSize ) );
|
||||
}
|
||||
}
|
||||
|
@ -633,7 +633,7 @@ void CClientSettingsDlg::OnSoundcardActivated ( int iSndDevIdx )
|
|||
QString ( tr ( "The selected audio device could not be used "
|
||||
"because of the following error: " ) ) + strError +
|
||||
QString ( tr ( " The previous driver will be selected." ) ),
|
||||
"Ok", nullptr );
|
||||
tr ( "Ok" ), nullptr );
|
||||
|
||||
// recover old selection
|
||||
cbxSoundcard->setCurrentIndex ( pClient->GetSndCrdDev() );
|
||||
|
|
|
@ -44,13 +44,13 @@ CConnectDlg::CConnectDlg ( const bool bNewShowCompleteRegList,
|
|||
|
||||
// Add help text to controls -----------------------------------------------
|
||||
// server list
|
||||
lvwServers->setWhatsThis ( tr ( "<b>Server List:</b> The server list shows "
|
||||
"a list of available servers which are registered at the central "
|
||||
"server. Select a server from the list and press the connect button to "
|
||||
lvwServers->setWhatsThis ( "<b>" + tr ( "Server List" ) + ":</b> " + tr (
|
||||
"The server list shows a list of available servers which are registered at the "
|
||||
"central server. Select a server from the list and press the connect button to "
|
||||
"connect to this server. Alternatively, double click a server from "
|
||||
"the list to connect to it. If a server is occupied, a list of the "
|
||||
"connected musicians is available by expanding the list item. "
|
||||
"Permanent servers are shown in bold font.<br>"
|
||||
"Permanent servers are shown in bold font." ) + "<br>" + tr (
|
||||
"Note that it may take some time to retrieve the server list from the "
|
||||
"central server. If no valid central server address is specified in "
|
||||
"the settings, no server list will be available." ) );
|
||||
|
@ -58,12 +58,12 @@ CConnectDlg::CConnectDlg ( const bool bNewShowCompleteRegList,
|
|||
lvwServers->setAccessibleName ( tr ( "Server list view" ) );
|
||||
|
||||
// server address
|
||||
QString strServAddrH = tr ( "<b>Server Address:</b> The IP address or URL "
|
||||
"of the server running the " ) + APP_NAME + tr ( " server software "
|
||||
"must be set here. An optional port number can be added after the IP "
|
||||
"address or URL using a comma as a separator, e.g, <i>"
|
||||
QString strServAddrH = "<b>" + tr ( "Server Address" ) + ":</b> " + tr (
|
||||
"The IP address or URL of the server running the " ) + APP_NAME + tr (
|
||||
" server software must be set here. An optional port number can be added after the IP "
|
||||
"address or URL using a colon as a separator, e.g, "
|
||||
"example.org:" ) +
|
||||
QString().setNum ( LLCON_DEFAULT_PORT_NUMBER ) + tr ( "</i>. A list of "
|
||||
QString().setNum ( LLCON_DEFAULT_PORT_NUMBER ) + tr ( ". A list of "
|
||||
"the most recent used server IP addresses or URLs is available for "
|
||||
"selection." );
|
||||
|
||||
|
@ -75,13 +75,13 @@ CConnectDlg::CConnectDlg ( const bool bNewShowCompleteRegList,
|
|||
"IP address or URL. It also stores old URLs in the combo box list." ) );
|
||||
|
||||
// filter
|
||||
edtFilter->setWhatsThis ( tr ( "<b>Filter:</b> The server list is filered "
|
||||
"by the given text. Note that the filter is case insensitive." ) );
|
||||
edtFilter->setWhatsThis ( "<b>" + tr ( "Filter" ) + ":</b> " + tr ( "The server "
|
||||
"list is filered by the given text. Note that the filter is case insensitive." ) );
|
||||
edtFilter->setAccessibleName ( tr ( "Filter edit box" ) );
|
||||
|
||||
// show all mucisians
|
||||
chbExpandAll->setWhatsThis ( tr ( "<b>Show All Musicians:</b> If you check "
|
||||
"this check box, the musicians of all servers are shown. If you "
|
||||
chbExpandAll->setWhatsThis ( "<b>" + tr ( "Show All Musicians" ) + ":</b> " + tr (
|
||||
"If you check this check box, the musicians of all servers are shown. If you "
|
||||
"uncheck the check box, all list view items are collapsed.") );
|
||||
chbExpandAll->setAccessibleName ( tr ( "Show all musicians check box" ) );
|
||||
|
||||
|
|
15
src/global.h
|
@ -105,8 +105,10 @@ LED bar: lbr
|
|||
#define DEFAULT_SERVER_ADDRESS "jamulus.fischvolk.de"
|
||||
#define DEFAULT_SERVER_NAME "Central Server"
|
||||
|
||||
// download URL
|
||||
#define SOFTWARE_DOWNLOAD_URL "http://sourceforge.net/projects/llcon/files"
|
||||
// getting started and software manual URL
|
||||
#define CLIENT_GETTING_STARTED_URL "https://github.com/corrados/jamulus/wiki/Software-Manual"
|
||||
#define SERVER_GETTING_STARTED_URL "https://github.com/corrados/jamulus/wiki/Running-a-Server"
|
||||
#define SOFTWARE_MANUAL_URL "https://github.com/corrados/jamulus/blob/master/src/res/homepage/manual.md"
|
||||
|
||||
// determining server internal address uses well-known host and port
|
||||
// (Google DNS, or something else reliable)
|
||||
|
@ -218,15 +220,12 @@ LED bar: lbr
|
|||
#define SERVLIST_TIME_PERMSERV_MINUTES 1440 // minutes, 1440 = 60 min * 24 h
|
||||
|
||||
// registration response timeout
|
||||
#define REGISTER_SERVER_TIME_OUT_MS 500 // ms
|
||||
#define REGISTER_SERVER_TIME_OUT_MS 500 // ms
|
||||
|
||||
// defines the maximum number of times to retry server registration
|
||||
// when no response is received within the timeout (before reverting
|
||||
// to SERVLIST_REGIST_INTERV_MINUTES)
|
||||
#define REGISTER_SERVER_RETRY_LIMIT 5 // count
|
||||
|
||||
// length of the moving average buffer for response time measurement
|
||||
#define TIME_MOV_AV_RESPONSE_SECONDS 30 // seconds
|
||||
#define REGISTER_SERVER_RETRY_LIMIT 5 // count
|
||||
|
||||
|
||||
// Maximum length of fader tag and text message strings (Since for chat messages
|
||||
|
@ -264,6 +263,8 @@ typedef unsigned __int64 uint64_t;
|
|||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
#elif defined ( ANDROID )
|
||||
// don't redfine types for android as these ones below don't work
|
||||
#else
|
||||
typedef long long int64_t;
|
||||
typedef int int32_t;
|
||||
|
|
223
src/main.cpp
|
@ -33,49 +33,54 @@
|
|||
#include "settings.h"
|
||||
#include "testbench.h"
|
||||
#include "util.h"
|
||||
#ifdef ANDROID
|
||||
# include <QtAndroidExtras/QtAndroid>
|
||||
#endif
|
||||
|
||||
|
||||
// Implementation **************************************************************
|
||||
|
||||
int main ( int argc, char** argv )
|
||||
{
|
||||
|
||||
QTextStream& tsConsole = *( ( new ConsoleWriterFactory() )->get() );
|
||||
QString strArgument;
|
||||
double rDbleArgument;
|
||||
|
||||
// initialize all flags and string which might be changed by command line
|
||||
// arguments
|
||||
|
||||
#if defined( SERVER_BUNDLE ) && ( defined( __APPLE__ ) || defined( __MACOSX ) )
|
||||
// if we are on MacOS and we are building a server bundle, starts Jamulus in server mode
|
||||
bool bIsClient = false;
|
||||
bool bIsClient = false;
|
||||
#else
|
||||
bool bIsClient = true;
|
||||
bool bIsClient = true;
|
||||
#endif
|
||||
|
||||
bool bUseGUI = true;
|
||||
bool bStartMinimized = false;
|
||||
bool bShowComplRegConnList = false;
|
||||
bool bDisconnectAllClients = false;
|
||||
bool bUseDoubleSystemFrameSize = true; // default is 128 samples frame size
|
||||
bool bShowAnalyzerConsole = false;
|
||||
bool bCentServPingServerInList = false;
|
||||
bool bNoAutoJackConnect = false;
|
||||
int iNumServerChannels = DEFAULT_USED_NUM_CHANNELS;
|
||||
int iMaxDaysHistory = DEFAULT_DAYS_HISTORY;
|
||||
int iCtrlMIDIChannel = INVALID_MIDI_CH;
|
||||
quint16 iPortNumber = LLCON_DEFAULT_PORT_NUMBER;
|
||||
ELicenceType eLicenceType = LT_NO_LICENCE;
|
||||
QString strConnOnStartupAddress = "";
|
||||
QString strIniFileName = "";
|
||||
QString strHTMLStatusFileName = "";
|
||||
QString strServerName = "";
|
||||
QString strLoggingFileName = "";
|
||||
QString strHistoryFileName = "";
|
||||
QString strRecordingDirName = "";
|
||||
QString strCentralServer = "";
|
||||
QString strServerInfo = "";
|
||||
QString strWelcomeMessage = "";
|
||||
bool bUseGUI = true;
|
||||
bool bStartMinimized = false;
|
||||
bool bShowComplRegConnList = false;
|
||||
bool bDisconnectAllClientsOnQuit = false;
|
||||
bool bUseDoubleSystemFrameSize = true; // default is 128 samples frame size
|
||||
bool bShowAnalyzerConsole = false;
|
||||
bool bCentServPingServerInList = false;
|
||||
bool bNoAutoJackConnect = false;
|
||||
bool bUseTranslation = true;
|
||||
bool bCustomPortNumberGiven = false;
|
||||
int iNumServerChannels = DEFAULT_USED_NUM_CHANNELS;
|
||||
int iMaxDaysHistory = DEFAULT_DAYS_HISTORY;
|
||||
int iCtrlMIDIChannel = INVALID_MIDI_CH;
|
||||
quint16 iPortNumber = LLCON_DEFAULT_PORT_NUMBER;
|
||||
ELicenceType eLicenceType = LT_NO_LICENCE;
|
||||
QString strConnOnStartupAddress = "";
|
||||
QString strIniFileName = "";
|
||||
QString strHTMLStatusFileName = "";
|
||||
QString strServerName = "";
|
||||
QString strLoggingFileName = "";
|
||||
QString strHistoryFileName = "";
|
||||
QString strRecordingDirName = "";
|
||||
QString strCentralServer = "";
|
||||
QString strServerInfo = "";
|
||||
QString strWelcomeMessage = "";
|
||||
QString strClientName = APP_NAME;
|
||||
|
||||
// QT docu: argv()[0] is the program name, argv()[1] is the first
|
||||
// argument and argv()[argc()-1] is the last argument.
|
||||
|
@ -195,6 +200,18 @@ int main ( int argc, char** argv )
|
|||
}
|
||||
|
||||
|
||||
// Disconnect all clients on quit --------------------------------------
|
||||
if ( GetFlagArgument ( argv,
|
||||
i,
|
||||
"-d",
|
||||
"--discononquit" ) )
|
||||
{
|
||||
bDisconnectAllClientsOnQuit = true;
|
||||
tsConsole << "- disconnect all clients on quit" << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Disabling auto Jack connections -------------------------------------
|
||||
if ( GetFlagArgument ( argv,
|
||||
i,
|
||||
|
@ -207,6 +224,18 @@ int main ( int argc, char** argv )
|
|||
}
|
||||
|
||||
|
||||
// Disable translations ------------------------------------------------
|
||||
if ( GetFlagArgument ( argv,
|
||||
i,
|
||||
"-t",
|
||||
"--notranslation" ) )
|
||||
{
|
||||
bUseTranslation = false;
|
||||
tsConsole << "- translations disabled" << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Show all registered servers in the server list ----------------------
|
||||
// Undocumented debugging command line argument: Show all registered
|
||||
// servers in the server list regardless if a ping to the server is
|
||||
|
@ -222,20 +251,6 @@ int main ( int argc, char** argv )
|
|||
}
|
||||
|
||||
|
||||
// Disconnect all clients (emergency mode) -----------------------------
|
||||
// Undocumented debugging command line argument: Needed to disconnect
|
||||
// an unwanted client.
|
||||
if ( GetFlagArgument ( argv,
|
||||
i,
|
||||
"--disconnectall", // no short form
|
||||
"--disconnectall" ) )
|
||||
{
|
||||
bDisconnectAllClients = true;
|
||||
tsConsole << "- disconnect all clients" << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Show analyzer console -----------------------------------------------
|
||||
// Undocumented debugging command line argument: Show the analyzer
|
||||
// console to debug network buffer properties.
|
||||
|
@ -293,7 +308,8 @@ int main ( int argc, char** argv )
|
|||
65535,
|
||||
rDbleArgument ) )
|
||||
{
|
||||
iPortNumber = static_cast<quint16> ( rDbleArgument );
|
||||
iPortNumber = static_cast<quint16> ( rDbleArgument );
|
||||
bCustomPortNumberGiven = true;
|
||||
tsConsole << "- selected port number: " << iPortNumber << endl;
|
||||
continue;
|
||||
}
|
||||
|
@ -327,7 +343,22 @@ int main ( int argc, char** argv )
|
|||
}
|
||||
|
||||
|
||||
// HTML status file ----------------------------------------------------
|
||||
// Client Name ---------------------------------------------------------
|
||||
if ( GetStringArgument ( tsConsole,
|
||||
argc,
|
||||
argv,
|
||||
i,
|
||||
"--clientname",
|
||||
"--clientname",
|
||||
strArgument ) )
|
||||
{
|
||||
strClientName = QString ( APP_NAME ) + " " + strArgument;
|
||||
tsConsole << "- client name: " << strClientName << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Server history file name --------------------------------------------
|
||||
if ( GetStringArgument ( tsConsole,
|
||||
argc,
|
||||
argv,
|
||||
|
@ -473,17 +504,41 @@ int main ( int argc, char** argv )
|
|||
strCentralServer = DEFAULT_SERVER_ADDRESS;
|
||||
}
|
||||
|
||||
// adjust default port number for client: use different default port than the server since
|
||||
// if the client is started before the server, the server would get a socket bind error
|
||||
if ( bIsClient && !bCustomPortNumberGiven )
|
||||
{
|
||||
iPortNumber += 10; // increment by 10
|
||||
}
|
||||
|
||||
// Application/GUI setup ---------------------------------------------------
|
||||
// Application object
|
||||
if ( !bUseGUI && !strHistoryFileName.isEmpty() )
|
||||
// display a warning if in server no GUI mode and a history file is requested
|
||||
if ( !bIsClient && !bUseGUI && !strHistoryFileName.isEmpty() )
|
||||
{
|
||||
tsConsole << "Qt5 requires a windowing system to paint a JPEG image; image will use SVG" << endl;
|
||||
}
|
||||
|
||||
|
||||
// Application/GUI setup ---------------------------------------------------
|
||||
// Application object
|
||||
QCoreApplication* pApp = bUseGUI
|
||||
? new QApplication ( argc, argv )
|
||||
: new QCoreApplication ( argc, argv );
|
||||
|
||||
#ifdef ANDROID
|
||||
// special Android coded needed for record audio permission handling
|
||||
auto result = QtAndroid::checkPermission ( QString ( "android.permission.RECORD_AUDIO" ) );
|
||||
|
||||
if ( result == QtAndroid::PermissionResult::Denied )
|
||||
{
|
||||
QtAndroid::PermissionResultMap resultHash = QtAndroid::requestPermissionsSync ( QStringList ( { "android.permission.RECORD_AUDIO" } ) );
|
||||
|
||||
if ( resultHash["android.permission.RECORD_AUDIO"] == QtAndroid::PermissionResult::Denied )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
// set application priority class -> high priority
|
||||
SetPriorityClass ( GetCurrentProcess(), HIGH_PRIORITY_CLASS );
|
||||
|
@ -498,16 +553,16 @@ int main ( int argc, char** argv )
|
|||
// init resources
|
||||
Q_INIT_RESOURCE(resources);
|
||||
|
||||
// load translations
|
||||
QTranslator myappTranslator;
|
||||
|
||||
// TODO translation loading does not yet work
|
||||
// // load translations
|
||||
// if ( bUseGUI )
|
||||
// {
|
||||
// QTranslator myappTranslator;
|
||||
// bool ret = myappTranslator.load ( "src/res/translation_" + QLocale::system().name() );
|
||||
//qDebug() << "translation successfully loaded: " << ret << " " << "src/res/translation_" + QLocale::system().name();
|
||||
// pApp->installTranslator ( &myappTranslator );
|
||||
// }
|
||||
if ( bUseGUI && bUseTranslation )
|
||||
{
|
||||
if ( myappTranslator.load ( ":/translations/translation.qm" ) )
|
||||
{
|
||||
pApp->installTranslator ( &myappTranslator );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TEST -> activate the following line to activate the test bench,
|
||||
|
@ -523,7 +578,8 @@ int main ( int argc, char** argv )
|
|||
CClient Client ( iPortNumber,
|
||||
strConnOnStartupAddress,
|
||||
iCtrlMIDIChannel,
|
||||
bNoAutoJackConnect );
|
||||
bNoAutoJackConnect,
|
||||
strClientName );
|
||||
|
||||
// load settings from init-file
|
||||
CSettings Settings ( &Client, strIniFileName );
|
||||
|
@ -568,7 +624,7 @@ int main ( int argc, char** argv )
|
|||
strWelcomeMessage,
|
||||
strRecordingDirName,
|
||||
bCentServPingServerInList,
|
||||
bDisconnectAllClients,
|
||||
bDisconnectAllClientsOnQuit,
|
||||
bUseDoubleSystemFrameSize,
|
||||
eLicenceType );
|
||||
if ( bUseGUI )
|
||||
|
@ -636,44 +692,45 @@ int main ( int argc, char** argv )
|
|||
QString UsageArguments ( char **argv )
|
||||
{
|
||||
return
|
||||
"Usage: " + QString ( argv[0] ) + " [option] [argument]\n"
|
||||
"Usage: " + QString ( argv[0] ) + " [option] [optional argument]\n"
|
||||
"\nRecognized options:\n"
|
||||
" -a, --servername server name, required for HTML status (server\n"
|
||||
" only)\n"
|
||||
" -c, --connect connect to given server address on startup\n"
|
||||
" (client only)\n"
|
||||
" -e, --centralserver address of the central server (server only)\n"
|
||||
" -F, --fastupdate use 64 samples frame size mode (server only)\n"
|
||||
" -g, --pingservers ping servers in list to keep NAT port open\n"
|
||||
" (central server only)\n"
|
||||
" -h, -?, --help display this help text and exit\n"
|
||||
" -i, --inifile initialization file name\n"
|
||||
" -j, --nojackconnect disable auto Jack connections (client only)\n"
|
||||
" -n, --nogui disable GUI\n"
|
||||
" -p, --port set your local port number\n"
|
||||
" -t, --notranslation disable translation (use englisch language)\n"
|
||||
" -v, --version output version information and exit\n"
|
||||
"\nServer only:\n"
|
||||
" -a, --servername server name, required for HTML status\n"
|
||||
" -d, --discononquit disconnect all clients on quit\n"
|
||||
" -D, --histdays number of days of history to display\n"
|
||||
" -e, --centralserver address of the central server\n"
|
||||
" -F, --fastupdate use 64 samples frame size mode\n"
|
||||
" -g, --pingservers ping servers in list to keep NAT port open\n"
|
||||
" (central server only)\n"
|
||||
" -l, --log enable logging, set file name\n"
|
||||
" -L, --licence a licence must be accepted on a new\n"
|
||||
" connection (server only)\n"
|
||||
" -m, --htmlstatus enable HTML status file, set file name (server\n"
|
||||
" only)\n"
|
||||
" -n, --nogui disable GUI\n"
|
||||
" connection\n"
|
||||
" -m, --htmlstatus enable HTML status file, set file name\n"
|
||||
" -o, --serverinfo infos of the server(s) in the format:\n"
|
||||
" [name];[city];[country as QLocale ID]; ...\n"
|
||||
" [server1 address];[server1 name]; ...\n"
|
||||
" [server1 city]; ...\n"
|
||||
" [server1 country as QLocale ID]; ...\n"
|
||||
" [server2 address]; ... (server only)\n"
|
||||
" -p, --port local port number (server only)\n"
|
||||
" [server2 address]; ...\n"
|
||||
" -R, --recording enables recording and sets directory to contain\n"
|
||||
" recorded jams (server only)\n"
|
||||
" recorded jams\n"
|
||||
" -s, --server start server\n"
|
||||
" -u, --numchannels maximum number of channels (server only)\n"
|
||||
" -v, --version output version information and exit\n"
|
||||
" -w, --welcomemessage welcome message on connect (server only)\n"
|
||||
" -y, --history enable connection history and set file\n"
|
||||
" name (server only)\n"
|
||||
" -D, --histdays number of days of history to display (server only)\n"
|
||||
" -z, --startminimized start minimizied (server only)\n"
|
||||
" --ctrlmidich MIDI controller channel to listen (client only)"
|
||||
"\nExample: " + QString ( argv[0] ) + " -l -inifile myinifile.ini\n";
|
||||
" -u, --numchannels maximum number of channels\n"
|
||||
" -w, --welcomemessage welcome message on connect\n"
|
||||
" -y, --history enable connection history and set file name\n"
|
||||
" -z, --startminimized start minimizied\n"
|
||||
"\nClient only:\n"
|
||||
" -c, --connect connect to given server address on startup\n"
|
||||
" -j, --nojackconnect disable auto Jack connections\n"
|
||||
" --ctrlmidich MIDI controller channel to listen\n"
|
||||
" --clientname client name (window title and jack client name)\n"
|
||||
"\nExample: " + QString ( argv[0] ) + " -s -inifile myinifile.ini\n";
|
||||
}
|
||||
|
||||
bool GetFlagArgument ( char** argv,
|
||||
|
|
|
@ -48,8 +48,7 @@ CMultiColorLEDBar::CMultiColorLEDBar ( QWidget* parent, Qt::WindowFlags f ) :
|
|||
// create LED object
|
||||
vecpLEDs[iLEDIdx] = new cLED ( parent );
|
||||
|
||||
// add LED to layout with spacer (do not add spacer on the bottom of the
|
||||
// first LED)
|
||||
// add LED to layout with spacer (do not add spacer on the bottom of the first LED)
|
||||
if ( iLEDIdx < NUM_STEPS_LED_BAR - 1 )
|
||||
{
|
||||
pLEDLayout->addStretch();
|
||||
|
@ -77,7 +76,7 @@ CMultiColorLEDBar::CMultiColorLEDBar ( QWidget* parent, Qt::WindowFlags f ) :
|
|||
// according to QScrollArea description: "When using a scroll area to display the
|
||||
// contents of a custom widget, it is important to ensure that the size hint of
|
||||
// the child widget is set to a suitable value."
|
||||
pProgressBar->setMinimumSize ( QSize ( 1, 1 ) );
|
||||
pProgressBar->setMinimumSize ( QSize ( 19, 1 ) ); // 15px + 2 * 1px + 2 * 1px = 19px
|
||||
pLEDMeter->setMinimumSize ( QSize ( 1, 1 ) );
|
||||
|
||||
// update the meter type (using the default value of the meter type)
|
||||
|
|
|
@ -314,22 +314,31 @@ void CJamRecorder::Init( const CServer* server,
|
|||
throw std::runtime_error( (recordBaseDir.absolutePath() + " is a directory but cannot be written to").toStdString() );
|
||||
}
|
||||
|
||||
QObject::connect((const QObject *)server, SIGNAL ( Stopped() ),
|
||||
this, SLOT( OnEnd() ),
|
||||
Qt::ConnectionType::QueuedConnection);
|
||||
QObject::connect( (const QObject *)server, SIGNAL ( Stopped() ),
|
||||
this, SLOT( OnEnd() ),
|
||||
Qt::ConnectionType::QueuedConnection );
|
||||
|
||||
QObject::connect((const QObject *)server, SIGNAL ( ClientDisconnected(int) ),
|
||||
this, SLOT( OnDisconnected(int) ),
|
||||
Qt::ConnectionType::QueuedConnection);
|
||||
QObject::connect( (const QObject *)server, SIGNAL ( ClientDisconnected ( int ) ),
|
||||
this, SLOT( OnDisconnected ( int ) ),
|
||||
Qt::ConnectionType::QueuedConnection );
|
||||
|
||||
qRegisterMetaType<CVector<int16_t>>();
|
||||
QObject::connect((const QObject *)server, SIGNAL ( AudioFrame(const int, const QString, const CHostAddress, const int, const CVector<int16_t>) ),
|
||||
this, SLOT( OnFrame(const int, const QString, const CHostAddress, const int, const CVector<int16_t>) ),
|
||||
Qt::ConnectionType::QueuedConnection);
|
||||
QObject::connect( (const QObject *)server, SIGNAL ( AudioFrame( const int, const QString, const CHostAddress, const int, const CVector<int16_t> ) ),
|
||||
this, SLOT( OnFrame (const int, const QString, const CHostAddress, const int, const CVector<int16_t> ) ),
|
||||
Qt::ConnectionType::QueuedConnection );
|
||||
|
||||
QObject::connect( QCoreApplication::instance(),
|
||||
SIGNAL ( aboutToQuit() ),
|
||||
this, SLOT( OnAboutToQuit() ) );
|
||||
|
||||
iServerFrameSizeSamples = _iServerFrameSizeSamples;
|
||||
|
||||
thisThread = new QThread();
|
||||
moveToThread ( thisThread );
|
||||
thisThread->start();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief CJamRecorder::OnStart Start up tasks when the first client connects
|
||||
*/
|
||||
|
@ -337,7 +346,7 @@ void CJamRecorder::OnStart() {
|
|||
// Ensure any previous cleaning up has been done.
|
||||
OnEnd();
|
||||
|
||||
currentSession = new CJamSession(recordBaseDir);
|
||||
currentSession = new CJamSession( recordBaseDir );
|
||||
isRecording = true;
|
||||
}
|
||||
|
||||
|
@ -346,7 +355,7 @@ void CJamRecorder::OnStart() {
|
|||
*/
|
||||
void CJamRecorder::OnEnd()
|
||||
{
|
||||
if (isRecording)
|
||||
if ( isRecording )
|
||||
{
|
||||
isRecording = false;
|
||||
currentSession->End();
|
||||
|
@ -372,6 +381,13 @@ void CJamRecorder::OnEnd()
|
|||
}
|
||||
}
|
||||
|
||||
void CJamRecorder::OnAboutToQuit()
|
||||
{
|
||||
OnEnd();
|
||||
|
||||
thisThread->exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CJamRecorder::SessionDirToReaper Replica of CJamRecorder::OnEnd() but using the directory contents to construct the CReaperProject object
|
||||
* @param strSessionDirName
|
||||
|
@ -409,11 +425,11 @@ void CJamRecorder::SessionDirToReaper(QString& strSessionDirName, int serverFram
|
|||
*/
|
||||
void CJamRecorder::OnDisconnected(int iChID)
|
||||
{
|
||||
if (!isRecording)
|
||||
if ( !isRecording )
|
||||
{
|
||||
qWarning() << "CJamRecorder::OnDisconnected: channel" << iChID << "disconnected but not recording";
|
||||
}
|
||||
if (currentSession == nullptr)
|
||||
if ( currentSession == nullptr )
|
||||
{
|
||||
qWarning() << "CJamRecorder::OnDisconnected: channel" << iChID << "disconnected but no currentSession";
|
||||
return;
|
||||
|
@ -434,7 +450,7 @@ void CJamRecorder::OnDisconnected(int iChID)
|
|||
void CJamRecorder::OnFrame(const int iChID, const QString name, const CHostAddress address, const int numAudioChannels, const CVector<int16_t> data)
|
||||
{
|
||||
// Make sure we are ready
|
||||
if (!isRecording)
|
||||
if ( !isRecording )
|
||||
{
|
||||
OnStart();
|
||||
}
|
||||
|
|
|
@ -132,13 +132,16 @@ private:
|
|||
QList<CJamClientConnection*> jamClientConnections;
|
||||
};
|
||||
|
||||
class CJamRecorder : public QThread
|
||||
class CJamRecorder : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CJamRecorder(const QString recordingDirName) :
|
||||
recordBaseDir (recordingDirName), isRecording (false) {}
|
||||
CJamRecorder ( const QString recordingDirName ) :
|
||||
recordBaseDir ( recordingDirName ),
|
||||
isRecording ( false )
|
||||
{
|
||||
}
|
||||
|
||||
void Init( const CServer* server, const int _iServerFrameSizeSamples );
|
||||
|
||||
|
@ -155,16 +158,21 @@ public slots:
|
|||
*/
|
||||
void OnEnd();
|
||||
|
||||
/**
|
||||
* @brief Raised when application is stopping
|
||||
*/
|
||||
void OnAboutToQuit();
|
||||
|
||||
/**
|
||||
* @brief Raised when an existing client leaves the server.
|
||||
* @param iChID channel number of client
|
||||
*/
|
||||
void OnDisconnected(int iChID);
|
||||
void OnDisconnected ( int iChID );
|
||||
|
||||
/**
|
||||
* @brief Raised when a frame of data fis available to process
|
||||
* @brief Raised when a frame of data is available to process
|
||||
*/
|
||||
void OnFrame(const int iChID, const QString name, const CHostAddress address, const int numAudioChannels, const CVector<int16_t> data);
|
||||
void OnFrame ( const int iChID, const QString name, const CHostAddress address, const int numAudioChannels, const CVector<int16_t> data );
|
||||
|
||||
private:
|
||||
QDir recordBaseDir;
|
||||
|
@ -172,6 +180,8 @@ private:
|
|||
bool isRecording;
|
||||
CJamSession* currentSession;
|
||||
int iServerFrameSizeSamples;
|
||||
|
||||
QThread* thisThread;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
BIN
src/res/instruments/bassoon.png
Normal file
After Width: | Height: | Size: 910 B |
227
src/res/instruments/bassoon.svg
Normal file
|
@ -0,0 +1,227 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="11in"
|
||||
height="8.5in"
|
||||
viewBox="0 0 279.4 215.9"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
|
||||
sodipodi:docname="bassoon.svg"
|
||||
inkscape:export-filename="/home/david/Music/Instruments/bassoon.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.70710678"
|
||||
inkscape:cx="297.27202"
|
||||
inkscape:cy="623.34622"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
showguides="false"
|
||||
inkscape:snap-global="false"
|
||||
units="in"
|
||||
showborder="false"
|
||||
inkscape:window-width="1366"
|
||||
inkscape:window-height="749"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid10" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-81.1)">
|
||||
<g
|
||||
id="g4796"
|
||||
transform="rotate(-29.01229,73.046042,121.22491)">
|
||||
<path
|
||||
sodipodi:nodetypes="cssccssccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path12"
|
||||
d="m 46.367866,43.314518 c 0,0 1.58921,3.69544 0,8.60447 -1.83477,5.66754 -0.701362,12.20664 -0.0767,16.8528 1.21491,9.03635 0.0767,88.764332 0.0767,131.881532 h 8.070518 c 0,-46.46672 -1.75839,-123.432682 -0.0927,-131.850152 0.99457,-5.026 1.68155,-9.92635 0.0927,-16.77595 -1.16203,-5.00954 0,-5.85039 0,-9.51137 h -8.070518 z"
|
||||
style="opacity:1;vector-effect:none;fill:#803300;fill-opacity:1;stroke:#000000;stroke-width:0.85982138;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<ellipse
|
||||
ry="2.2148652"
|
||||
rx="9.4134111"
|
||||
cy="42.129814"
|
||||
cx="50.668777"
|
||||
id="path14"
|
||||
style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#333333;stroke-width:1.15859199;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
transform="rotate(-90)"
|
||||
y="54.915047"
|
||||
x="-201.91927"
|
||||
height="3.3675961"
|
||||
width="95.415215"
|
||||
id="rect3725"
|
||||
style="opacity:1;vector-effect:none;fill:#aa4400;fill-opacity:1;stroke:#000000;stroke-width:0.70599997;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
transform="rotate(-90)"
|
||||
y="45.518219"
|
||||
x="-202.79692"
|
||||
height="13.548525"
|
||||
width="11.935585"
|
||||
id="rect3729"
|
||||
style="opacity:1;vector-effect:none;fill:#b3b3b3;fill-opacity:1;stroke:#333333;stroke-width:0.63450718;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="csssssc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3731"
|
||||
d="m 56.613851,106.16137 c 0,0 -0.24168,-6.398058 1.02098,-9.693309 0.78131,-2.039027 2.42033,-4.09041 4.49792,-4.7625 1.79385,-0.5803 3.09877,-0.51589 4.76513,0.36611 2.53543,1.34199 2.27053,2.97449 4.53263,6.216388 1.36878,1.961631 3.71629,3.306381 6.03967,3.875121 7.39159,1.80937 18.94588,1.58749 16.02175,1.58749"
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#8080ff;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4544"
|
||||
d="m 94.703667,102.81387 c 3.262067,1.23276 10.142893,-0.35753 10.142893,-0.35753 l -2.96326,4.31989 c 0,0 -3.909421,-2.97182 -7.476951,-2.05203 z"
|
||||
style="opacity:1;vector-effect:none;fill:#ffcc00;fill-opacity:1;stroke:#ffcc00;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
y="81.27993"
|
||||
x="47.143467"
|
||||
height="6.2547331"
|
||||
width="6.2547321"
|
||||
id="rect4550"
|
||||
style="opacity:1;vector-effect:none;fill:#b3b3b3;fill-opacity:1;stroke:#b3b3b3;stroke-width:1.83068395;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
style="opacity:1;vector-effect:none;fill:#b3b3b3;fill-opacity:1;stroke:#b3b3b3;stroke-width:2.27667642;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect4552"
|
||||
width="10.416251"
|
||||
height="5.8087401"
|
||||
x="47.101879"
|
||||
y="145.00291" />
|
||||
<rect
|
||||
y="106.55724"
|
||||
x="55.002777"
|
||||
height="2.5712204"
|
||||
width="3.1803987"
|
||||
id="rect4554"
|
||||
style="opacity:1;vector-effect:none;fill:#b3b3b3;fill-opacity:1;stroke:#b3b3b3;stroke-width:0.83697993;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<circle
|
||||
r="1.7972932"
|
||||
cy="69.529976"
|
||||
cx="50.709747"
|
||||
id="path4556"
|
||||
style="opacity:1;vector-effect:none;fill:#d5e5ff;fill-opacity:1;stroke:#d5e5ff;stroke-width:0.60041487;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<circle
|
||||
r="1.4766704"
|
||||
style="opacity:1;vector-effect:none;fill:#d5e5ff;fill-opacity:1;stroke:#d5e5ff;stroke-width:0.49330565;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="circle4580"
|
||||
cx="49.806404"
|
||||
cy="185.79163" />
|
||||
<circle
|
||||
r="1.1560477"
|
||||
cy="175.58247"
|
||||
cx="51.01973"
|
||||
id="circle4582"
|
||||
style="opacity:1;vector-effect:none;fill:#d5e5ff;fill-opacity:1;stroke:#d5e5ff;stroke-width:0.38619646;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<circle
|
||||
style="opacity:1;vector-effect:none;fill:#d5e5ff;fill-opacity:1;stroke:#d5e5ff;stroke-width:0.46652839;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="circle4584"
|
||||
cx="50.177826"
|
||||
cy="171.44269"
|
||||
r="1.3965148" />
|
||||
<ellipse
|
||||
transform="matrix(-0.9676937,-0.25212875,-0.2886886,-0.95742305,0,0)"
|
||||
ry="0.56005347"
|
||||
rx="1.2347096"
|
||||
cy="-137.54945"
|
||||
cx="-11.971257"
|
||||
id="path4586"
|
||||
style="opacity:1;vector-effect:none;fill:#d5e5ff;fill-opacity:1;stroke:#d5e5ff;stroke-width:0.33503741;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<ellipse
|
||||
inkscape:transform-center-y="0.49806172"
|
||||
inkscape:transform-center-x="-0.77738863"
|
||||
transform="matrix(-0.98472888,-0.17409487,0.17196262,-0.98510348,0,0)"
|
||||
ry="0.62549603"
|
||||
rx="1.8658425"
|
||||
cy="-121.87131"
|
||||
cx="-73.939224"
|
||||
id="path4588"
|
||||
style="opacity:1;vector-effect:none;fill:#d5e5ff;fill-opacity:1;stroke:#d5e5ff;stroke-width:0.4565016;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<ellipse
|
||||
style="opacity:1;vector-effect:none;fill:#d5e5ff;fill-opacity:1;stroke:#d5e5ff;stroke-width:0.32630903;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="ellipse4592"
|
||||
cx="105.17155"
|
||||
cy="-179.23906"
|
||||
rx="1.2218931"
|
||||
ry="0.536825"
|
||||
transform="matrix(-0.94648072,0.32276035,-0.84098337,-0.54106097,0,0)" />
|
||||
<ellipse
|
||||
style="opacity:1;vector-effect:none;fill:#d5e5ff;fill-opacity:1;stroke:#d5e5ff;stroke-width:0.24506681;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="ellipse4594"
|
||||
cx="-34.641891"
|
||||
cy="-123.9094"
|
||||
rx="0.93775296"
|
||||
ry="0.39453751"
|
||||
transform="matrix(-0.92026936,-0.39128546,-0.14973615,-0.98872599,0,0)" />
|
||||
<ellipse
|
||||
transform="matrix(-0.76478399,0.64428677,-0.94974484,-0.31302514,0,0)"
|
||||
ry="0.39453751"
|
||||
rx="0.93775296"
|
||||
cy="-154.59048"
|
||||
cx="125.81667"
|
||||
id="ellipse4596"
|
||||
style="opacity:1;vector-effect:none;fill:#d5e5ff;fill-opacity:1;stroke:#d5e5ff;stroke-width:0.24506681;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4598"
|
||||
d="M 50.207146,125.41978 50.962303,71.546673"
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#aaaaff;stroke-width:0.57336599;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#aaaaff;stroke-width:0.57336599;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m 49.002555,185.15586 0.755157,-53.87311"
|
||||
id="path4600"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4602"
|
||||
d="m 48.334921,170.75003 0.755157,-53.8731"
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#aaaaff;stroke-width:0.57336599;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#aaaaff;stroke-width:0.39104879;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m 47.585808,166.63427 0.543936,-34.79044"
|
||||
id="path4604"
|
||||
inkscape:connector-curvature="0" />
|
||||
<ellipse
|
||||
ry="1.2653216"
|
||||
rx="0.89114428"
|
||||
style="opacity:1;vector-effect:none;fill:#d5e5ff;fill-opacity:1;stroke:#d5e5ff;stroke-width:0.3547374;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="circle4608"
|
||||
cx="48.125366"
|
||||
cy="117.46767" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 12 KiB |
BIN
src/res/instruments/bongo.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
142
src/res/instruments/bongo.svg
Normal file
|
@ -0,0 +1,142 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 360.9 244.9" style="enable-background:new 0 0 360.9 244.9;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{display:none;}
|
||||
.st1{fill:url(#SVGID_1_);}
|
||||
.st2{fill:url(#SVGID_2_);}
|
||||
.st3{fill:none;stroke:#E6E6E6;stroke-width:1.0844;stroke-miterlimit:10;}
|
||||
.st4{fill:#D8BD8D;stroke:#000000;stroke-width:0.1213;stroke-miterlimit:10;}
|
||||
.st5{fill:none;stroke:#E6E6E6;stroke-width:1.0817;stroke-miterlimit:10;}
|
||||
.st6{stroke:#000000;stroke-width:0.1213;stroke-miterlimit:10;}
|
||||
.st7{fill:#D8BD8D;stroke:#000000;stroke-width:0.1188;stroke-miterlimit:10;}
|
||||
.st8{fill:none;stroke:#000000;stroke-width:1.0817;stroke-miterlimit:10;}
|
||||
.st9{fill:none;}
|
||||
.st10{stroke:#000000;stroke-width:0.1456;stroke-miterlimit:10;}
|
||||
.st11{stroke:#000000;stroke-width:0.1335;stroke-miterlimit:10;}
|
||||
.st12{stroke:#000000;stroke-width:0.1165;stroke-miterlimit:10;}
|
||||
.st13{fill:url(#SVGID_3_);stroke:#000000;stroke-width:0.1213;stroke-miterlimit:10;}
|
||||
.st14{fill:url(#SVGID_4_);stroke:#000000;stroke-width:0.1896;stroke-miterlimit:10;}
|
||||
</style>
|
||||
<g id="Layer_1_copy" class="st0">
|
||||
|
||||
<image style="display:inline;overflow:visible;" width="2912" height="1976" xlink:href="bongobase.jpg" transform="matrix(0.1239 0 0 0.1239 0 0)">
|
||||
</image>
|
||||
</g>
|
||||
<g id="Layer_1" class="st0">
|
||||
|
||||
<image style="display:inline;overflow:visible;" width="2912" height="1976" xlink:href="bongobase.jpg" transform="matrix(0.1239 0 0 0.1239 0 0)">
|
||||
</image>
|
||||
</g>
|
||||
<g id="Layer_10">
|
||||
</g>
|
||||
<g id="Layer_6">
|
||||
</g>
|
||||
<g id="Layer_7">
|
||||
</g>
|
||||
<g id="Layer_4">
|
||||
</g>
|
||||
<g id="Layer_9">
|
||||
</g>
|
||||
<g id="Layer_8">
|
||||
</g>
|
||||
<g id="Layer_2_copy">
|
||||
</g>
|
||||
<g id="Layer_2">
|
||||
<g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="134.371" y1="104.3634" x2="157.2497" y2="90.1605">
|
||||
<stop offset="0.1132" style="stop-color:#BF6F00"/>
|
||||
<stop offset="0.2222" style="stop-color:#FF7300"/>
|
||||
<stop offset="0.2734" style="stop-color:#FC7C00"/>
|
||||
<stop offset="0.3585" style="stop-color:#F49600"/>
|
||||
<stop offset="0.4664" style="stop-color:#E7BF00"/>
|
||||
<stop offset="0.4807" style="stop-color:#E5C500"/>
|
||||
<stop offset="0.6614" style="stop-color:#FF7300"/>
|
||||
<stop offset="0.7093" style="stop-color:#F97C01"/>
|
||||
<stop offset="0.7888" style="stop-color:#EA9602"/>
|
||||
<stop offset="0.8109" style="stop-color:#E59E03"/>
|
||||
<stop offset="0.9573" style="stop-color:#BF6F00"/>
|
||||
</linearGradient>
|
||||
<path class="st1" d="M129.8,95l10.6,11.2c0,0,7.8,1.7,10.8,0s5.4-4.6,5.5-4.5c0.1,0.1-3.3-4.5-2.8-7.6c0.4-3.1,1.6-6.9,1.6-6.9
|
||||
s-7,5.9-12.4,7.2c-5.4,1.4-8.8,1.5-10.4,1.1C131.1,95.2,129.8,95,129.8,95z"/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="161.3593" y1="113.4498" x2="194.464" y2="110.1142">
|
||||
<stop offset="0.1132" style="stop-color:#BF6F00"/>
|
||||
<stop offset="0.2222" style="stop-color:#FF7300"/>
|
||||
<stop offset="0.2734" style="stop-color:#FC7C00"/>
|
||||
<stop offset="0.3585" style="stop-color:#F49600"/>
|
||||
<stop offset="0.4664" style="stop-color:#E7BF00"/>
|
||||
<stop offset="0.4807" style="stop-color:#E5C500"/>
|
||||
<stop offset="0.6614" style="stop-color:#FF7300"/>
|
||||
<stop offset="0.7093" style="stop-color:#F97C01"/>
|
||||
<stop offset="0.7888" style="stop-color:#EA9602"/>
|
||||
<stop offset="0.8109" style="stop-color:#E59E03"/>
|
||||
<stop offset="0.9573" style="stop-color:#BF6F00"/>
|
||||
</linearGradient>
|
||||
<path class="st2" d="M161.1,105c0,0,10.2,3.3,15.8,3.1s8.1-1.1,11.4-2.3c3.3-1.2,7.3-4.3,7.3-4.3l-4.8,12.5c0,0-2.8,5.2-6.5,5.6
|
||||
s-10,0.4-12.6-0.6s-5.6-3.1-6.4-5S161.1,105,161.1,105L161.1,105"/>
|
||||
|
||||
<ellipse transform="matrix(0.9359 -0.3524 0.3524 0.9359 -20.9237 55.2979)" class="st3" cx="141.4" cy="85.1" rx="16.6" ry="8.8"/>
|
||||
<path class="st4" d="M127,83.3c0,0-2.1,5.5,8.3,5.1c10.4-0.4,16.3-7.1,16.3-7.1s2.1-3.5,1.9-4.4c-0.2-0.9-2.5-2.4-2.5-2.4l3.4,1
|
||||
c1.5,0.4,2.6,1.7,2.9,3.3l0.1,0.8l-1.5,2.9l-1,2.6l-2.8,2.4l-5.6,3.4l-10.1,2.8l-7-1.6l-4.2-2.7l1-3L127,83.3z"/>
|
||||
<path class="st5" d="M201.3,89.7c1,9.8-8.5,16.4-21.5,18.1c-13.1,1.7-24.6-3.5-25.6-11.7c-1.1-8.2,8.7-16.2,21.8-17.9
|
||||
S200.5,81.5,201.3,89.7z"/>
|
||||
<path class="st6" d="M148.5,73.5l2.6,0.9c0.7,0.3-0.9,0.1,1.3,0.3l3.1,2.6c0.8,0.7,1.2,1.5-0.7,4.5c-2.9,4.5-10.5,8.8-18.9,9.5
|
||||
c-6.7,0.5-9.4-2.5-9.4-2.5L126,87v-1.8c0,0,1-3,4.6-5.6c3.6-2.6,5.2-3.2,5.2-3.2s4.2-1.7,4.7-1.9
|
||||
C142.3,73.8,146.3,73.5,148.5,73.5c-2.3-0.1-4.5,0.1-5.9,0.3c-11.5,2-15.7,8.1-17.3,10.8c-1.6,2.7,0,5.3,0,5.3l1.3,1.9
|
||||
c0,0,5.7,5.9,17.5,0.8s14.4-10.2,13.1-14.8C156.5,75.4,150.1,73.7,148.5,73.5z"/>
|
||||
<path class="st7" d="M165.7,78.3c0,0-5.5,1.8-7.1,5.8c-1.6,4-2.6,10,4.2,12.6c6.7,2.6,15.6,3.2,24-0.8c8.4-4,11.3-10.8,9.1-15.6
|
||||
l5.3,5.9c0,0-0.2,5.3-2.1,8.5s-1.9,3.3-1.9,3.3s-8.4,8.3-21.2,8.1c-12.8-0.2-18-4.4-20.1-6.9c-2-2.4-1.8-3.9-2.3-4.9
|
||||
c-0.5-0.9-0.3-3.4,0-4.8c0.3-1.4,5.4-7.4,5.4-7.4L165.7,78.3z"/>
|
||||
<g>
|
||||
<path class="st8" d="M155.7,98.5c0,0-1.3,0.5-2.3,1c-0.5,0.3-0.7,1-0.3,1.4c1.6,1.8,5.5,6,5.9,6.5c0,0,0,0.1,0.1,0.1l5.9,12.3"/>
|
||||
<path class="st8" d="M153.4,93l-1.1,0.7c-0.1,0.1-0.2,0.2-0.1,0.3l1.9,5.3c0.1,0.3,0.5,0.2,0.5-0.1v0c0-0.1,0.1-0.2,0.2-0.2
|
||||
l1-0.5"/>
|
||||
<path class="st8" d="M146.1,90.2l1.4,1.8c0.1,0.1,0.1,0.2,0,0.3l-2.6,4.4c-0.1,0.1-0.2,0.2-0.3,0.1l-4.7-1.6
|
||||
c-0.1,0-0.2-0.1-0.2-0.2l-0.4-2.4"/>
|
||||
<path class="st8" d="M143.3,95.3c0,0,0.8-1.1,1.7-0.6c0.9,0.5,1.8,0.8,1.1,2.2c-0.7,1.3,0.2,4.7,0.3,5c0,0,0,0,0,0.1l4.7,8.6"/>
|
||||
<path class="st8" d="M138.8,106.9l-9.1-10.8l-5.5-4.8c-0.1-0.1-0.1-0.4,0.1-0.5l0.8-0.3"/>
|
||||
<path class="st8" d="M181.4,105.5l1.4,2.8c0,0.1,0.1,0.1,0.2,0.1l3.8,1.4c0.1,0,0.2,0,0.3-0.1l4.6-4.8c0.1-0.1,0.1-0.2,0-0.3
|
||||
l-1.2-1.8"/>
|
||||
<path class="st8" d="M185.2,108c0,0,1.1-0.7,1.9,0c0.9,0.7,1.6,2.4,0.8,4c-0.8,1.5-2.4,3.8-2.6,4.2c0,0,0,0.1,0,0.2v9.5"/>
|
||||
</g>
|
||||
<path d="M163.7,110.6c0,0,2.6,5.3,8.4,7.2s11.5,1,15-1.2s4.1-3.8,4.3-4.4c0.3-0.5,0.3-0.5,0.3-0.5l0.5-1.8c0,0-0.3,5.5-3.2,7.7
|
||||
c-2.9,2.2-8,4.8-15.1,3.1c-7.2-1.7-9-5.6-9.4-6.7S163.7,110.6,163.7,110.6z"/>
|
||||
<path class="st8" d="M183,119.5L183,119.5c-0.6,0-1,0.8-0.6,1.3l1.1,1.4c0.1,0.1,0.1,0.2,0.1,0.3c0.1,0.3,0.4,0.8,1.6,0.3l0.8-0.3
|
||||
c0.4-0.2,0.6-0.7,0.4-1.1L185,119"/>
|
||||
<path class="st8" d="M166.4,115.6l-2.7,1.8c0,0-1.1,0.4-1.8-0.2c-0.6-0.6,0.4-1.6,0.4-1.6l2.7-1.5"/>
|
||||
<line class="st9" x1="185.2" y1="123.7" x2="185.2" y2="126.5"/>
|
||||
<path d="M137.2,102c0,0,1.2,3.2,7.1,4c5.9,0.8,12-4,12-4l1.8,1.7c0,0-2.5,1.7-4,2.6c-3.5,2.1-7.7,2.5-11.4,1.8
|
||||
c0,0-2.4-1.2-3.9-3.2C138,104,137.2,102,137.2,102z"/>
|
||||
<path class="st8" d="M138,103.8l-1.1,1c0,0-1.3,0.3-1.4,1.2c-0.1,1,1.7,0,1.7,0l1.5-1.1"/>
|
||||
<path class="st6" d="M136.3,104.5l1.8-0.8l1,0.7l1.3,2c0,0,0.4,0.5,0,0.6c-0.4,0.1-1.4,1.3-1.4,1.3h-1.6l-1.6-2.3L136.3,104.5z"/>
|
||||
<path class="st6" d="M148.2,107.7l1.8-0.8l1,0.7l1.3,2c0,0,0.4,0.5,0,0.6c-0.4,0.1-1.4,1.3-1.4,1.3h-1.6l-1.6-2.3L148.2,107.7z"/>
|
||||
<path class="st10" d="M183.7,121.3l2.3-0.3l0.9,1.1l0.8,2.8c0,0,0.3,0.8-0.2,0.7c-0.5,0-2,1-2,1l-1.8-0.5l-1.1-3.2L183.7,121.3z"
|
||||
/>
|
||||
<path class="st11" d="M162,116.4l1.9-0.9l1.1,0.8l1.4,2.3c0,0,0.5,0.6,0,0.7c-0.5,0.1-1.5,1.4-1.5,1.4h-1.7l-1.8-2.6L162,116.4z"
|
||||
/>
|
||||
<path class="st6" d="M179.6,95l1.8-0.8l1,0.7l1.3,2c0,0,0.4,0.5,0,0.6c-0.4,0.1-1.4,1.3-1.4,1.3h-1.6l-1.6-2.3L179.6,95z"/>
|
||||
<path class="st12" d="M201.4,86.4c-0.3-3.1-4.6-6.8-8.2-9c-3.6-2.3-12.1-3-12.9-2.9c-8.1,0.4-14.2,2.9-14.2,2.9
|
||||
c-5.6,2.4-11,7.4-12.3,11.3c-1.3,3.9,0.8,10.3,4.5,13.9c3.8,3.6,14.6,5.9,22.9,4.6c8.3-1.3,15.1-6,17.1-9S201.7,89.5,201.4,86.4z
|
||||
M191.8,100.8c-9.9,4.8-18.3,4.9-27.5,2.2c-9.2-2.7-9.8-8.4-9.8-8.4s0.1-2.2,0-3.6c-0.1-1.4,0.6-1.9,1-3.1
|
||||
c0.3-1.2,1.2-2.5,2.5-3.7s2.2-2.3,2.2-2.3s1,0.5,3.1-1.4c2.2-1.9,10.8-4.3,10.8-4.3s4.1-0.5,6.8-0.7c2.7-0.1,7,0.8,10.8,2.2
|
||||
c3.8,1.4,6.6,5.1,7.4,7.1c0.9,2,0.4,0.7,1,2.7C200.5,89.7,201.7,96,191.8,100.8z"/>
|
||||
<g>
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="125.5923" y1="81.5875" x2="153.9333" y2="81.5875">
|
||||
<stop offset="5.076142e-03" style="stop-color:#FFE794"/>
|
||||
<stop offset="1" style="stop-color:#ECDEFF"/>
|
||||
</linearGradient>
|
||||
<path class="st13" d="M125.8,85.8c-1.2-3.9,4.1-9,11.9-11.3c7.7-2.3,15-1.1,16.1,2.8c1.2,3.9-4.1,9-11.9,11.3
|
||||
C134.2,91,126.9,89.7,125.8,85.8z"/>
|
||||
</g>
|
||||
<g>
|
||||
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="156.165" y1="88.117" x2="197.6382" y2="88.117">
|
||||
<stop offset="5.076142e-03" style="stop-color:#FFE794"/>
|
||||
<stop offset="1" style="stop-color:#ECDEFF"/>
|
||||
</linearGradient>
|
||||
<path class="st14" d="M156.3,91.8c-1.2-6.8,7-14,18.4-16.1c11.4-2,21.6,1.9,22.8,8.7c1.2,6.8-7,14-18.4,16.1
|
||||
C167.7,102.5,157.5,98.6,156.3,91.8z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 8.7 KiB |
BIN
src/res/instruments/congas.png
Normal file
After Width: | Height: | Size: 2 KiB |
139
src/res/instruments/congas.svg
Normal file
|
@ -0,0 +1,139 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 29 21.9" style="enable-background:new 0 0 29 21.9;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{display:none;fill:#DDD6CE;}
|
||||
.st1{fill:url(#SVGID_1_);}
|
||||
.st2{fill:url(#SVGID_2_);}
|
||||
.st3{fill:none;stroke:#898989;stroke-width:0.4152;stroke-linecap:round;stroke-miterlimit:10;}
|
||||
.st4{fill:url(#SVGID_3_);}
|
||||
.st5{fill:url(#SVGID_4_);}
|
||||
.st6{fill:url(#SVGID_5_);}
|
||||
.st7{fill:url(#SVGID_6_);}
|
||||
.st8{fill:#231F20;}
|
||||
.st9{fill:#9B7550;}
|
||||
.st10{fill:#C1AC97;}
|
||||
.st11{stroke:#000000;stroke-width:0.4152;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
|
||||
</style>
|
||||
<path class="st0" d="M6.2,47.6"/>
|
||||
<g>
|
||||
<g id="Layer_2_1_">
|
||||
<g>
|
||||
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-6.7753" y1="181.6339" x2="-2.3834" y2="181.6339" gradientTransform="matrix(0.9952 -9.790000e-02 -9.790000e-02 -0.9952 34.2217 190.0392)">
|
||||
<stop offset="0" style="stop-color:#A5161B"/>
|
||||
<stop offset="0.2559" style="stop-color:#AB1F23"/>
|
||||
<stop offset="0.6801" style="stop-color:#BA3939"/>
|
||||
<stop offset="0.8934" style="stop-color:#C34846"/>
|
||||
</linearGradient>
|
||||
<path class="st1" d="M9.7,3.2l3.4-0.7c0.1,0,0.3,0.1,0.3,0.2l1.3,13.5c0,0.1-0.1,0.2-0.2,0.3c-0.2,0.1-0.6,0.2-1.1,0.1
|
||||
c-0.6-0.1-1-0.6-1.1-0.7c0,0,0,0,0-0.1c-2.2-5.3-1.6-3.5-2.2-5.3c-0.6-1.7-0.8-5-0.8-5.4c0,0,0-0.4,0-0.4l0.1-1.2
|
||||
C9.4,3.4,9.5,3.3,9.7,3.2z"/>
|
||||
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="-63.7946" y1="181.6438" x2="-59.2975" y2="181.6438" gradientTransform="matrix(-0.9952 9.790000e-02 -9.790000e-02 -0.9952 -27.5088 196.0988)">
|
||||
<stop offset="0" style="stop-color:#A5161B"/>
|
||||
<stop offset="0.2559" style="stop-color:#AB1F23"/>
|
||||
<stop offset="0.6801" style="stop-color:#BA3939"/>
|
||||
<stop offset="0.8934" style="stop-color:#C34846"/>
|
||||
</linearGradient>
|
||||
<path class="st2" d="M17,2.4l-3.7,0.1l1.1,14c0,0,0.6,0.2,1.3-0.2c0.7-0.3,1-1,1-1c1.3-5.7,1-3.8,1.3-5.7s-0.3-5.3-0.3-5.3
|
||||
l-0.3-1.6C17.3,2.5,17.2,2.4,17,2.4z"/>
|
||||
</g>
|
||||
</g>
|
||||
<path class="st3" d="M10.6,8.5c0-0.2,0.2-0.8,0.1-0.9l-0.6-2.4"/>
|
||||
<g>
|
||||
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="-32.4531" y1="177.8433" x2="-27.3982" y2="177.8433" gradientTransform="matrix(0.9815 -0.1915 -0.1915 -0.9815 67.819 182.7466)">
|
||||
<stop offset="0" style="stop-color:#FF7300"/>
|
||||
<stop offset="0.1217" style="stop-color:#F97C01"/>
|
||||
<stop offset="0.3234" style="stop-color:#EA9602"/>
|
||||
<stop offset="0.3795" style="stop-color:#E59E03"/>
|
||||
<stop offset="0.8652" style="stop-color:#E5C500"/>
|
||||
</linearGradient>
|
||||
<path class="st4" d="M1.1,6.4L5,5.2c0.2-0.1,0.3,0.1,0.4,0.2l3,15.9c0,0.1,0,0.3-0.2,0.3c-0.3,0.1-0.7,0.3-1.2,0.2
|
||||
c-0.7-0.1-1.2-0.6-1.3-0.7c0,0,0,0,0-0.1c-3.2-6-2.3-4-3.2-6c-0.9-2-1.5-5.9-1.5-6.3c0,0,0-0.5,0-0.5l0-1.4
|
||||
C0.8,6.6,0.9,6.5,1.1,6.4z"/>
|
||||
|
||||
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="-39.4058" y1="177.8697" x2="-34.2269" y2="177.8697" gradientTransform="matrix(-0.9815 0.1915 -0.1915 -0.9815 6.937 194.6229)">
|
||||
<stop offset="0" style="stop-color:#FF7300"/>
|
||||
<stop offset="0.1217" style="stop-color:#F97C01"/>
|
||||
<stop offset="0.3234" style="stop-color:#EA9602"/>
|
||||
<stop offset="0.3795" style="stop-color:#E59E03"/>
|
||||
<stop offset="0.8652" style="stop-color:#E5C500"/>
|
||||
</linearGradient>
|
||||
<path class="st5" d="M9.4,4.7L5.2,5.2l2.9,16.5c0,0,0.7,0.1,1.5-0.3s1-1.2,1-1.2c0.8-6.9,0.7-4.6,0.8-6.9c0.1-2.3-1-6.3-1-6.3
|
||||
L9.8,5C9.8,4.8,9.6,4.7,9.4,4.7z"/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
|
||||
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="34.4733" y1="159.7419" x2="39.6473" y2="159.7419" gradientTransform="matrix(0.996 8.950000e-02 8.950000e-02 -0.996 -30.5432 168.0219)">
|
||||
<stop offset="0" style="stop-color:#FF7300"/>
|
||||
<stop offset="0.1217" style="stop-color:#F97C01"/>
|
||||
<stop offset="0.3234" style="stop-color:#EA9602"/>
|
||||
<stop offset="0.3795" style="stop-color:#E59E03"/>
|
||||
<stop offset="0.8652" style="stop-color:#E5C500"/>
|
||||
</linearGradient>
|
||||
<path class="st6" d="M19.3,4l4.2,0c0.2,0,0.3,0.2,0.3,0.3l-1.3,16.3c0,0.1-0.1,0.3-0.3,0.3c-0.3,0-0.8,0-1.3-0.2
|
||||
c-0.7-0.3-1.1-0.9-1.1-1.1c0,0,0,0,0-0.1c-1.5-6.8-1.2-4.5-1.5-6.8c-0.3-2.2,0.6-6.6,0.7-7.1c0,0,0,0,0-0.1l0-1.3
|
||||
C19,4.1,19.1,4,19.3,4z"/>
|
||||
|
||||
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="-106.4789" y1="159.7513" x2="-101.3623" y2="159.7513" gradientTransform="matrix(-0.996 -8.950000e-02 8.950000e-02 -0.996 -92.3257 162.4685)">
|
||||
<stop offset="0" style="stop-color:#FF7300"/>
|
||||
<stop offset="0.1217" style="stop-color:#F97C01"/>
|
||||
<stop offset="0.3234" style="stop-color:#EA9602"/>
|
||||
<stop offset="0.3795" style="stop-color:#E59E03"/>
|
||||
<stop offset="0.8652" style="stop-color:#E5C500"/>
|
||||
</linearGradient>
|
||||
<path class="st7" d="M28.2,4.8L23.8,4l-1.6,16.8c0,0,0.7,0.3,1.6,0.1c0.9-0.2,1.3-0.9,1.3-0.9c2.7-6.4,2-4.2,2.7-6.4
|
||||
c0.7-2.2,0.5-7.1,0.5-7.1l0.2-1.3C28.5,5,28.4,4.8,28.2,4.8z"/>
|
||||
</g>
|
||||
<path class="st8" d="M19.6,19.2c0,0,1.1,1.1,2.3,1.2c1.2,0.1,2,0,2.6-0.4c0.6-0.3,1-0.7,1-0.7l-0.2,1c0,0-0.8,1-2.7,0.9
|
||||
c-2-0.1-2.7-1.1-2.7-1.1L19.6,19.2z"/>
|
||||
</g>
|
||||
<path class="st8" d="M5.3,20.7c0,0,1,0.7,2.5,0.4c1.6-0.3,1.8-0.6,2.3-1.1c0.5-0.5,0.5-0.7,0.5-0.7V20c0,0.2-0.2,0.4-0.3,0.6
|
||||
c-0.4,0.8-1.2,1-2.2,1.2c-0.7,0.1-1.3,0.1-1.9,0c-0.4-0.1-0.7-0.2-0.9-0.5L5.3,20.7z"/>
|
||||
<path class="st9" d="M1.1,5.1l8-0.9c0.2,0,0,0,0.4,0l0.3,0.2C9.5,4.3,9.7,4.5,9.7,4.6c0,0.1,0.1,0.2,0.1,0.2l0,0
|
||||
c0.1,0,0.1,0.4,0.2,0.5c0,0.1,0,0-0.1,0.1C9.5,5.9,8,7.1,5.9,7.5C3.6,8,2.8,7.8,1.7,7.6C1,7.5,0.7,7,0.6,6.7C0.5,6.4,0.3,6.3,0.4,6
|
||||
l0.2-0.6C0.7,5.2,0.9,5.1,1.1,5.1z"/>
|
||||
<path class="st9" d="M19.5,3l9.1,1.1c0,0,0,0.1,0.1,0.1l0.2,0.3c0,0.1-0.2,0.3-0.1,0.3l0-0.1c0.1,0,0.1,0.4,0.1,0.5
|
||||
c0.1,0.4-0.1,0.5-0.2,0.6c-0.3,0.7-2.1,0.9-4,0.7c-3-0.3-2.7-0.4-3.8-0.8c-0.6-0.2-1.1-0.5-1.5-0.7c-0.3-0.2-0.7-0.8-0.5-1.1
|
||||
L19.5,3C19.4,3.1,19.5,3,19.5,3z"/>
|
||||
<path class="st9" d="M9.5,1.8L9.3,2.6c0,0,0.4,0.8,2.7,1s4.9-1.4,4.9-1.4c0.2-0.1,0.1-0.3,0.2-0.4c0,0,0.1-0.1,0-0.2l-0.6-0.8"/>
|
||||
<ellipse transform="matrix(0.9875 -0.1577 0.1577 0.9875 -0.7287 0.8601)" class="st10" cx="5.1" cy="5" rx="4.6" ry="1.7"/>
|
||||
|
||||
<ellipse transform="matrix(0.9945 -0.1051 0.1051 0.9945 -7.567539e-02 1.3796)" class="st10" cx="13.1" cy="1.4" rx="3.5" ry="1.4"/>
|
||||
<ellipse transform="matrix(0.1216 -0.9926 0.9926 0.1216 17.2543 27.095)" class="st10" cx="23.9" cy="3.8" rx="1.7" ry="4.6"/>
|
||||
<path class="st8" d="M0.4,5.7c0,0-0.4,0.5-0.4,0.8s0.4,1.9,0.4,1.9l0.3,0.3l0.5-0.3c0,0,0.6,0.2,1.7,0.3s1.7,0,1.7,0l1,1.5l0.6-0.1
|
||||
l0.6-1.8c0,0,1-0.3,1.7-0.8s1.5-1.1,1.5-1.1l0.4,0.9L10.7,7l-0.6-2.5L9.6,4.3l0.3,1c0,0-0.2,0.7-1.9,1.5C6.6,7.4,5.3,7.7,5.3,7.7
|
||||
S4,7.8,2.8,7.7C0.6,7.5,0.4,6.6,0.4,6.6V5.7z"/>
|
||||
<path class="st3" d="M0.3,8c0,0.3-0.1,1-0.1,1.3L0.8,10L1,11.7"/>
|
||||
<polygon class="st8" points="0.6,10.6 1.2,10.6 1.3,11.3 0.7,11.5 "/>
|
||||
<polygon class="st11" points="4.9,11.1 6.2,11.5 7.3,10.6 6.6,13.3 "/>
|
||||
<line class="st3" x1="5.9" y1="9.3" x2="6.3" y2="12.2"/>
|
||||
<path class="st8" d="M9.5,1.7c0,0-0.5,0.4-0.6,0.6c0,0.2,0.2,1.5,0.2,1.5L9.4,4l0.4-0.2c0,0,0.5,0.3,1.4,0.4
|
||||
c0.9,0.1,1.4,0.1,1.4,0.1l0.8,1.1L14,5.3l0.6-1.3c0,0,0.9-0.2,1.5-0.5c0.6-0.3,1.3-0.8,1.3-0.8l0.2,0.8l0.3-0.3l-0.3-1.8
|
||||
c0-0.1-0.1-0.2-0.2-0.3l-0.5-0.2l0.4,0.6c0,0-0.1,0.6-1.5,1.2c-1.1,0.4-2.3,0.6-2.3,0.6s-1.1,0.1-2.1,0c-1.9-0.3-1.9-1-1.9-1
|
||||
L9.5,1.7z"/>
|
||||
<g>
|
||||
<polygon class="st11" points="12.7,6.5 13.9,6.9 15,6.2 14.1,8.6 "/>
|
||||
<line class="st3" x1="13.6" y1="4.8" x2="13.9" y2="7.6"/>
|
||||
</g>
|
||||
<path class="st8" d="M14.5,15.7c-1.7,0-2.4-0.4-2.4-0.4l0.2,0.6c0,0,0.4,0.7,2.2,0.6c1.8-0.1,2.2-0.9,2.2-0.9v-0.7
|
||||
c0,0-0.2,0.3-0.9,0.6C15.1,15.8,14.5,15.7,14.5,15.7z"/>
|
||||
<path class="st8" d="M24.2,7.4c1.4,0,1.6,0.2,3-0.2c0.6-0.2,1.1-0.4,1.1-0.4l0.4-0.4l0.2-0.5l0-1.1c0-0.2-0.1-0.4-0.2-0.5l-0.1-0.1
|
||||
l0.1,0.9c0,0,0,0.7-1.9,1c-1.5,0.2-2.9,0.1-2.9,0.1S22.4,6,21.3,5.6c-2.3-0.8-2.2-1.8-2.2-1.8L19.4,3c0,0-0.5,0.3-0.6,0.5
|
||||
c-0.1,0.2-0.1,1.4-0.1,1.4l0.3,0.4l0,0c0,0,1.3,1.5,3,1.8l0,0L24.2,7.4z"/>
|
||||
<polygon class="st8" points="21.5,6.6 20.7,7.6 20,7.3 19.9,6 "/>
|
||||
<path class="st8" d="M25.7,7l1.7-0.3l-0.2,1.4c0-0.2,0-0.2,0-0.2l-0.9,0.2L25.7,7z"/>
|
||||
<g>
|
||||
<polygon class="st11" points="25.7,9.4 26.9,9.7 28,8.8 27.3,11.7 "/>
|
||||
<line class="st3" x1="26.6" y1="7.3" x2="27" y2="10.6"/>
|
||||
</g>
|
||||
<g>
|
||||
<polygon class="st11" points="18.9,7.8 19.8,8.8 21.1,8.7 19.4,10.7 "/>
|
||||
<line class="st3" x1="20.5" y1="6.7" x2="19.6" y2="9.6"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 8.6 KiB |
BIN
src/res/instruments/harp.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
465
src/res/instruments/harp.svg
Normal file
After Width: | Height: | Size: 91 KiB |
BIN
src/res/instruments/oboe.png
Normal file
After Width: | Height: | Size: 840 B |
282
src/res/instruments/oboe.svg
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
src/res/instruments/viola.png
Normal file
After Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 30 KiB |
BIN
src/res/translation/translation_de_DE.qm
Normal file
2334
src/res/translation/translation_de_DE.ts
Normal file
BIN
src/res/translation/translation_es_ES.qm
Normal file
2338
src/res/translation/translation_es_ES.ts
Normal file
BIN
src/res/translation/translation_fr_FR.qm
Normal file
2346
src/res/translation/translation_fr_FR.ts
Normal file
BIN
src/res/translation/translation_pt_PT.qm
Normal file
2346
src/res/translation/translation_pt_PT.ts
Normal file
|
@ -1,4 +1,16 @@
|
|||
<RCC>
|
||||
<qresource prefix="/translations" lang="de">
|
||||
<file alias="translation.qm">res/translation/translation_de_DE.qm</file>
|
||||
</qresource>
|
||||
<qresource prefix="/translations" lang="fr">
|
||||
<file alias="translation.qm">res/translation/translation_fr_FR.qm</file>
|
||||
</qresource>
|
||||
<qresource prefix="/translations" lang="pt">
|
||||
<file alias="translation.qm">res/translation/translation_pt_PT.qm</file>
|
||||
</qresource>
|
||||
<qresource prefix="/translations" lang="es">
|
||||
<file alias="translation.qm">res/translation/translation_es_ES.qm</file>
|
||||
</qresource>
|
||||
<qresource prefix="/png/LEDs">
|
||||
<file>res/CLEDDisabledSmall.png</file>
|
||||
<file>res/CLEDGreenArrow.png</file>
|
||||
|
@ -50,10 +62,15 @@
|
|||
<file>res/instruments/instrguitarvocal.png</file>
|
||||
<file>res/instruments/instrkeyboardvocal.png</file>
|
||||
<file>res/instruments/bodhran.png</file>
|
||||
<file>res/instruments/bassoon.png</file>
|
||||
<file>res/instruments/oboe.png</file>
|
||||
<file>res/instruments/harp.png</file>
|
||||
<file>res/instruments/viola.png</file>
|
||||
<file>res/instruments/congas.png</file>
|
||||
<file>res/instruments/bongo.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="/png/main">
|
||||
<file>res/fronticon.png</file>
|
||||
<file>res/logopicture.png</file>
|
||||
<file>res/mainicon.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="/png/flags">
|
||||
|
|
115
src/server.cpp
|
@ -231,27 +231,28 @@ CServer::CServer ( const int iNewMaxNumChan,
|
|||
const QString& strNewWelcomeMessage,
|
||||
const QString& strRecordingDirName,
|
||||
const bool bNCentServPingServerInList,
|
||||
const bool bNDisconnectAllClients,
|
||||
const bool bNDisconnectAllClientsOnQuit,
|
||||
const bool bNUseDoubleSystemFrameSize,
|
||||
const ELicenceType eNLicenceType ) :
|
||||
bUseDoubleSystemFrameSize ( bNUseDoubleSystemFrameSize ),
|
||||
iMaxNumChannels ( iNewMaxNumChan ),
|
||||
Socket ( this, iPortNumber ),
|
||||
Logging ( iMaxDaysHistory ),
|
||||
JamRecorder ( strRecordingDirName ),
|
||||
bEnableRecording ( !strRecordingDirName.isEmpty() ),
|
||||
bWriteStatusHTMLFile ( false ),
|
||||
HighPrecisionTimer ( bNUseDoubleSystemFrameSize ),
|
||||
ServerListManager ( iPortNumber,
|
||||
strCentralServer,
|
||||
strServerInfo,
|
||||
iNewMaxNumChan,
|
||||
bNCentServPingServerInList,
|
||||
&ConnLessProtocol ),
|
||||
bAutoRunMinimized ( false ),
|
||||
strWelcomeMessage ( strNewWelcomeMessage ),
|
||||
eLicenceType ( eNLicenceType ),
|
||||
bDisconnectAllClients ( bNDisconnectAllClients )
|
||||
bUseDoubleSystemFrameSize ( bNUseDoubleSystemFrameSize ),
|
||||
iMaxNumChannels ( iNewMaxNumChan ),
|
||||
Socket ( this, iPortNumber ),
|
||||
Logging ( iMaxDaysHistory ),
|
||||
JamRecorder ( strRecordingDirName ),
|
||||
bEnableRecording ( !strRecordingDirName.isEmpty() ),
|
||||
bWriteStatusHTMLFile ( false ),
|
||||
HighPrecisionTimer ( bNUseDoubleSystemFrameSize ),
|
||||
ServerListManager ( iPortNumber,
|
||||
strCentralServer,
|
||||
strServerInfo,
|
||||
iNewMaxNumChan,
|
||||
bNCentServPingServerInList,
|
||||
&ConnLessProtocol ),
|
||||
bAutoRunMinimized ( false ),
|
||||
strWelcomeMessage ( strNewWelcomeMessage ),
|
||||
eLicenceType ( eNLicenceType ),
|
||||
bDisconnectAllClientsOnQuit ( bNDisconnectAllClientsOnQuit ),
|
||||
pSignalHandler ( CSignalHandler::getSingletonP() )
|
||||
{
|
||||
int iOpusError;
|
||||
int i;
|
||||
|
@ -400,11 +401,10 @@ CServer::CServer ( const int iNewMaxNumChan,
|
|||
QString().number( static_cast<int> ( iPortNumber ) ) );
|
||||
}
|
||||
|
||||
// Enable jam recording (if requested)
|
||||
// Enable jam recording (if requested) - kicks off the thread
|
||||
if ( bEnableRecording )
|
||||
{
|
||||
JamRecorder.Init ( this, iServerFrameSizeSamples );
|
||||
JamRecorder.start();
|
||||
}
|
||||
|
||||
// enable all channels (for the server all channel must be enabled the
|
||||
|
@ -468,6 +468,14 @@ CServer::CServer ( const int iNewMaxNumChan,
|
|||
SIGNAL ( SvrRegStatusChanged() ),
|
||||
this, SLOT ( OnSvrRegStatusChanged() ) );
|
||||
|
||||
QObject::connect ( QCoreApplication::instance(),
|
||||
SIGNAL ( aboutToQuit() ),
|
||||
this, SLOT ( OnAboutToQuit() ) );
|
||||
|
||||
QObject::connect ( pSignalHandler,
|
||||
SIGNAL ( ShutdownSignal ( int ) ),
|
||||
this, SLOT ( OnShutdown ( int ) ) );
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
connectChannelSignalsToServerSlots<MAX_NUM_CHANNELS>();
|
||||
|
||||
|
@ -804,14 +812,6 @@ void CServer::SendProtMessage ( int iChID, CVector<uint8_t> vecMessage )
|
|||
void CServer::OnNewConnection ( int iChID,
|
||||
CHostAddress RecHostAddr )
|
||||
{
|
||||
// in the special case that all clients shall be disconnected, just send the
|
||||
// disconnect message and leave this function
|
||||
if ( bDisconnectAllClients )
|
||||
{
|
||||
ConnLessProtocol.CreateCLDisconnection ( RecHostAddr );
|
||||
return;
|
||||
}
|
||||
|
||||
// on a new connection we query the network transport properties for the
|
||||
// audio packets (to use the correct network block size and audio
|
||||
// compression properties, etc.)
|
||||
|
@ -910,6 +910,39 @@ void CServer::OnCLDisconnection ( CHostAddress InetAddr )
|
|||
}
|
||||
}
|
||||
|
||||
void CServer::OnAboutToQuit()
|
||||
{
|
||||
// if enabled, disconnect all clients on quit
|
||||
if ( bDisconnectAllClientsOnQuit )
|
||||
{
|
||||
Mutex.lock();
|
||||
{
|
||||
for ( int i = 0; i < iMaxNumChannels; i++ )
|
||||
{
|
||||
if ( vecChannels[i].IsConnected() )
|
||||
{
|
||||
ConnLessProtocol.CreateCLDisconnection ( vecChannels[i].GetAddress() );
|
||||
}
|
||||
}
|
||||
}
|
||||
Mutex.unlock(); // release mutex
|
||||
}
|
||||
|
||||
Stop();
|
||||
|
||||
// if server was registered at the central server, unregister on shutdown
|
||||
if ( GetServerListEnabled() )
|
||||
{
|
||||
UnregisterSlaveServer();
|
||||
}
|
||||
}
|
||||
|
||||
void CServer::OnShutdown ( int )
|
||||
{
|
||||
// This should trigger OnAboutToQuit
|
||||
QCoreApplication::instance()->exit();
|
||||
}
|
||||
|
||||
void CServer::Start()
|
||||
{
|
||||
// only start if not already running
|
||||
|
@ -944,7 +977,7 @@ void CServer::Stop()
|
|||
|
||||
void CServer::OnTimer()
|
||||
{
|
||||
int i, j;
|
||||
int i, j, iUnused;
|
||||
int iClientFrameSizeSamples;
|
||||
OpusCustomDecoder* CurOpusDecoder;
|
||||
OpusCustomEncoder* CurOpusEncoder;
|
||||
|
@ -1099,11 +1132,11 @@ JitterMeas.Measure();
|
|||
// OPUS decode received data stream
|
||||
if ( CurOpusDecoder != nullptr )
|
||||
{
|
||||
opus_custom_decode ( CurOpusDecoder,
|
||||
pCurCodedData,
|
||||
iCeltNumCodedBytes,
|
||||
&vecvecsData[i][iB * SYSTEM_FRAME_SIZE_SAMPLES * vecNumAudioChannels[i]],
|
||||
iClientFrameSizeSamples );
|
||||
iUnused = opus_custom_decode ( CurOpusDecoder,
|
||||
pCurCodedData,
|
||||
iCeltNumCodedBytes,
|
||||
&vecvecsData[i][iB * SYSTEM_FRAME_SIZE_SAMPLES * vecNumAudioChannels[i]],
|
||||
iClientFrameSizeSamples );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1247,11 +1280,11 @@ JitterMeas.Measure();
|
|||
opus_custom_encoder_ctl ( CurOpusEncoder,
|
||||
OPUS_SET_BITRATE ( CalcBitRateBitsPerSecFromCodedBytes ( iCeltNumCodedBytes, iClientFrameSizeSamples ) ) );
|
||||
|
||||
opus_custom_encode ( CurOpusEncoder,
|
||||
&vecsSendData[iB * SYSTEM_FRAME_SIZE_SAMPLES * vecNumAudioChannels[i]],
|
||||
iClientFrameSizeSamples,
|
||||
&vecbyCodedData[0],
|
||||
iCeltNumCodedBytes );
|
||||
iUnused = opus_custom_encode ( CurOpusEncoder,
|
||||
&vecsSendData[iB * SYSTEM_FRAME_SIZE_SAMPLES * vecNumAudioChannels[i]],
|
||||
iClientFrameSizeSamples,
|
||||
&vecbyCodedData[0],
|
||||
iCeltNumCodedBytes );
|
||||
}
|
||||
|
||||
// send separate mix to current clients
|
||||
|
@ -1277,6 +1310,8 @@ opus_custom_encoder_ctl ( CurOpusEncoder,
|
|||
// does not consume any significant CPU when no client is connected.
|
||||
Stop();
|
||||
}
|
||||
|
||||
Q_UNUSED ( iUnused )
|
||||
}
|
||||
|
||||
/// @brief Mix all audio data from all clients together.
|
||||
|
|
11
src/server.h
|
@ -36,6 +36,7 @@
|
|||
#endif
|
||||
#include "global.h"
|
||||
#include "buffer.h"
|
||||
#include "signalhandler.h"
|
||||
#include "socket.h"
|
||||
#include "channel.h"
|
||||
#include "util.h"
|
||||
|
@ -177,7 +178,7 @@ public:
|
|||
const QString& strNewWelcomeMessage,
|
||||
const QString& strRecordingDirName,
|
||||
const bool bNCentServPingServerInList,
|
||||
const bool bNDisconnectAllClients,
|
||||
const bool bNDisconnectAllClientsOnQuit,
|
||||
const bool bNUseDoubleSystemFrameSize,
|
||||
const ELicenceType eNLicenceType );
|
||||
|
||||
|
@ -370,7 +371,9 @@ protected:
|
|||
// messaging
|
||||
QString strWelcomeMessage;
|
||||
ELicenceType eLicenceType;
|
||||
bool bDisconnectAllClients;
|
||||
bool bDisconnectAllClientsOnQuit;
|
||||
|
||||
CSignalHandler* pSignalHandler;
|
||||
|
||||
signals:
|
||||
void Started();
|
||||
|
@ -457,6 +460,10 @@ public slots:
|
|||
|
||||
void OnCLDisconnection ( CHostAddress InetAddr );
|
||||
|
||||
void OnAboutToQuit();
|
||||
|
||||
void OnShutdown ( int );
|
||||
|
||||
#if QT_VERSION < 0x50000 // MOC does not expand macros in Qt 4, so we cannot use QT_VERSION_CHECK(5, 0, 0)
|
||||
// CODE TAG: MAX_NUM_CHANNELS_TAG
|
||||
// make sure we have MAX_NUM_CHANNELS connections!!!
|
||||
|
|
|
@ -42,28 +42,28 @@ CServerDlg::CServerDlg ( CServer* pNServP,
|
|||
|
||||
// Add help text to controls -----------------------------------------------
|
||||
// client list
|
||||
lvwClients->setWhatsThis ( tr ( "<b>Client List:</b> The client list "
|
||||
"shows all clients which are currently connected to this server. Some "
|
||||
"information about the clients like the IP address and name are given "
|
||||
"for each connected client." ) );
|
||||
lvwClients->setWhatsThis ( "<b>" + tr ( "Client List" ) + ":</b> " + tr (
|
||||
"The client list shows all clients which are currently connected to this "
|
||||
"server. Some information about the clients like the IP address and name "
|
||||
"are given for each connected client." ) );
|
||||
|
||||
lvwClients->setAccessibleName ( tr ( "Connected clients list view" ) );
|
||||
|
||||
// start minimized on operating system start
|
||||
chbStartOnOSStart->setWhatsThis ( tr ( "<b>Start Minimized on Operating "
|
||||
"System Start:</b> If the start minimized on operating system start "
|
||||
chbStartOnOSStart->setWhatsThis ( "<b>" + tr ( "Start Minimized on Operating "
|
||||
"System Start" ) + ":</b> " + tr ( "If the start minimized on operating system start "
|
||||
"check box is checked, the " ) + APP_NAME + tr ( " server will be "
|
||||
"started when the operating system starts up and is automatically "
|
||||
"minimized to a system task bar icon." ) );
|
||||
|
||||
// CC licence dialog switch
|
||||
chbUseCCLicence->setWhatsThis ( tr ( "<b>Show Creative Commons Licence "
|
||||
"Dialog:</b> If enabled, a Creative Commons BY-NC-SA 4.0 Licence "
|
||||
chbUseCCLicence->setWhatsThis ( "<b>" + tr ( "Show Creative Commons Licence "
|
||||
"Dialog" ) + ":</b> " + tr ( "If enabled, a Creative Commons BY-NC-SA 4.0 Licence "
|
||||
"dialog is shown each time a new user connects the server." ) );
|
||||
|
||||
// Make My Server Public flag
|
||||
chbRegisterServer->setWhatsThis ( tr ( "<b>Make My Server Public:</b> If "
|
||||
"the Make My Server Public check box is checked, this server registers "
|
||||
chbRegisterServer->setWhatsThis ( "<b>" + tr ( "Make My Server Public" ) + ":</b> " +
|
||||
tr ( "If the Make My Server Public check box is checked, this server registers "
|
||||
"itself at the central server so that all " ) + APP_NAME +
|
||||
tr ( " users can see the server in the connect dialog server list and "
|
||||
"connect to it. The registering of the server is renewed periodically "
|
||||
|
@ -71,13 +71,13 @@ CServerDlg::CServerDlg ( CServer* pNServP,
|
|||
"actually available." ) );
|
||||
|
||||
// register server status label
|
||||
lblRegSvrStatus->setWhatsThis ( tr ( "<b>Register Server Status:</b> If "
|
||||
"the Make My Server Public check box is checked, this will show "
|
||||
lblRegSvrStatus->setWhatsThis ( "<b>" + tr ( "Register Server Status" ) + ":</b> " +
|
||||
tr ( "If the Make My Server Public check box is checked, this will show "
|
||||
"the success of registration with the central server." ) );
|
||||
|
||||
// central server address
|
||||
QString strCentrServAddr = tr ( "<b>Central Server Address:</b> The "
|
||||
"Central server address is the IP address or URL of the central server "
|
||||
QString strCentrServAddr = "<b>" + tr ( "Central Server Address" ) + ":</b> " +
|
||||
tr ( "The Central server address is the IP address or URL of the central server "
|
||||
"at which this server is registered. With the central server address "
|
||||
"type either the local region can be selected of the default central "
|
||||
"servers or a manual address can be specified." );
|
||||
|
@ -90,7 +90,7 @@ CServerDlg::CServerDlg ( CServer* pNServP,
|
|||
edtCentralServerAddress->setAccessibleName ( tr ( "Central server address line edit" ) );
|
||||
|
||||
// server name
|
||||
QString strServName = tr ( "<b>Server Name:</b> The server name identifies "
|
||||
QString strServName = "<b>" + tr ( "Server Name" ) + ":</b> " + tr ( "The server name identifies "
|
||||
"your server in the connect dialog server list at the clients. If no "
|
||||
"name is given, the IP address is shown instead." );
|
||||
|
||||
|
@ -100,18 +100,17 @@ CServerDlg::CServerDlg ( CServer* pNServP,
|
|||
edtServerName->setAccessibleName ( tr ( "Server name line edit" ) );
|
||||
|
||||
// location city
|
||||
QString strLocCity = tr ( "<b>Location City:</b> The city in which this "
|
||||
QString strLocCity = "<b>" + tr ( "Location City" ) + ":</b> " + tr ( "The city in which this "
|
||||
"server is located can be set here. If a city name is entered, it "
|
||||
"will be shown in the connect dialog server list at the clients." );
|
||||
|
||||
lblLocationCity->setWhatsThis ( strLocCity );
|
||||
edtLocationCity->setWhatsThis ( strLocCity );
|
||||
|
||||
edtLocationCity->setAccessibleName ( tr (
|
||||
"City where the server is located line edit" ) );
|
||||
edtLocationCity->setAccessibleName ( tr ( "City where the server is located line edit" ) );
|
||||
|
||||
// location country
|
||||
QString strLocCountry = tr ( "<b>Location country:</b> The country in "
|
||||
QString strLocCountry = "<b>" + tr ( "Location country" ) + ":</b> " + tr ( "The country in "
|
||||
"which this server is located can be set here. If a country is "
|
||||
"entered, it will be shown in the connect dialog server list at the "
|
||||
"clients." );
|
||||
|
@ -189,9 +188,9 @@ lvwClients->setMinimumHeight ( 140 );
|
|||
|
||||
// central server address type combo box
|
||||
cbxCentServAddrType->clear();
|
||||
cbxCentServAddrType->addItem ( "Manual" ); // AT_MANUAL
|
||||
cbxCentServAddrType->addItem ( "Default" ); // AT_DEFAULT
|
||||
cbxCentServAddrType->addItem ( "Default (North America)" ); // AT_NORTH_AMERICA
|
||||
cbxCentServAddrType->addItem ( tr ( "Manual" ) ); // AT_MANUAL
|
||||
cbxCentServAddrType->addItem ( tr ( "Default" ) ); // AT_DEFAULT
|
||||
cbxCentServAddrType->addItem ( tr ( "Default (North America)" ) ); // AT_NORTH_AMERICA
|
||||
cbxCentServAddrType->setCurrentIndex ( static_cast<int> ( pServer->GetCentralServerAddressType() ) );
|
||||
|
||||
// update server name line edit
|
||||
|
@ -273,7 +272,7 @@ lvwClients->setMinimumHeight ( 140 );
|
|||
|
||||
|
||||
// View menu --------------------------------------------------------------
|
||||
QMenu* pViewMenu = new QMenu ( "&Window", this );
|
||||
QMenu* pViewMenu = new QMenu ( tr ( "&Window" ), this );
|
||||
|
||||
pViewMenu->addAction ( tr ( "E&xit" ), this,
|
||||
SLOT ( close() ), QKeySequence ( Qt::CTRL + Qt::Key_Q ) );
|
||||
|
@ -283,7 +282,7 @@ lvwClients->setMinimumHeight ( 140 );
|
|||
pMenu = new QMenuBar ( this );
|
||||
|
||||
pMenu->addMenu ( pViewMenu );
|
||||
pMenu->addMenu ( new CHelpMenu ( this ) );
|
||||
pMenu->addMenu ( new CHelpMenu ( false, this ) );
|
||||
|
||||
// Now tell the layout about the menu
|
||||
layout()->setMenuBar ( pMenu );
|
||||
|
@ -343,18 +342,6 @@ lvwClients->setMinimumHeight ( 140 );
|
|||
Timer.start ( GUI_CONTRL_UPDATE_TIME );
|
||||
}
|
||||
|
||||
void CServerDlg::closeEvent ( QCloseEvent* Event )
|
||||
{
|
||||
// if server was registered at the central server, unregister on shutdown
|
||||
if ( pServer->GetServerListEnabled() )
|
||||
{
|
||||
pServer->UnregisterSlaveServer();
|
||||
}
|
||||
|
||||
// default implementation of this event handler routine
|
||||
Event->accept();
|
||||
}
|
||||
|
||||
void CServerDlg::OnStartOnOSStartStateChanged ( int value )
|
||||
{
|
||||
const bool bCurAutoStartMinState = ( value == Qt::Checked );
|
||||
|
@ -447,6 +434,12 @@ void CServerDlg::OnLocationCountryActivated ( int iCntryListItem )
|
|||
|
||||
void CServerDlg::OnCentServAddrTypeActivated ( int iTypeIdx )
|
||||
{
|
||||
// if server was registered, unregister first
|
||||
if ( pServer->GetServerListEnabled() )
|
||||
{
|
||||
pServer->UnregisterSlaveServer();
|
||||
}
|
||||
|
||||
// apply new setting to the server and update it
|
||||
pServer->SetCentralServerAddressType ( static_cast<ECSAddType> ( iTypeIdx ) );
|
||||
pServer->UpdateServerList();
|
||||
|
|
|
@ -58,7 +58,6 @@ public:
|
|||
|
||||
protected:
|
||||
virtual void changeEvent ( QEvent* pEvent );
|
||||
virtual void closeEvent ( QCloseEvent* Event );
|
||||
|
||||
void UpdateGUIDependencies();
|
||||
void UpdateSystemTrayIcon ( const bool bIsActive );
|
||||
|
|
|
@ -31,7 +31,8 @@ CServerListManager::CServerListManager ( const quint16 iNPortNum,
|
|||
const int iNumChannels,
|
||||
const bool bNCentServPingServerInList,
|
||||
CProtocol* pNConLProt )
|
||||
: iNumPredefinedServers ( 0 ),
|
||||
: tsConsoleStream ( *( ( new ConsoleWriterFactory() )->get() ) ),
|
||||
iNumPredefinedServers ( 0 ),
|
||||
eCentralServerAddressType ( AT_MANUAL ), // must be AT_MANUAL for the "no GUI" case
|
||||
bCentServPingServerInList ( bNCentServPingServerInList ),
|
||||
pConnLessProtocol ( pNConLProt ),
|
||||
|
@ -307,6 +308,8 @@ void CServerListManager::OnTimerPingServerInList()
|
|||
|
||||
void CServerListManager::OnTimerPollList()
|
||||
{
|
||||
CVector<CHostAddress> vecRemovedHostAddr;
|
||||
|
||||
QMutexLocker locker ( &Mutex );
|
||||
|
||||
// Check all list entries except of the very first one (which is the central
|
||||
|
@ -319,6 +322,7 @@ void CServerListManager::OnTimerPollList()
|
|||
if ( ServerList[iIdx].RegisterTime.elapsed() > ( SERVLIST_TIME_OUT_MINUTES * 60000 ) )
|
||||
{
|
||||
// remove this list entry
|
||||
vecRemovedHostAddr.Add ( ServerList[iIdx].HostAddr );
|
||||
ServerList.removeAt ( iIdx );
|
||||
}
|
||||
else
|
||||
|
@ -327,16 +331,27 @@ void CServerListManager::OnTimerPollList()
|
|||
iIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
locker.unlock();
|
||||
|
||||
foreach ( const CHostAddress HostAddr, vecRemovedHostAddr )
|
||||
{
|
||||
tsConsoleStream << "Expired entry for " << HostAddr.toString() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void CServerListManager::CentralServerRegisterServer ( const CHostAddress& InetAddr,
|
||||
const CHostAddress& LInetAddr,
|
||||
const CServerCoreInfo& ServerInfo )
|
||||
{
|
||||
QMutexLocker locker ( &Mutex );
|
||||
|
||||
if ( bIsCentralServer && bEnabled )
|
||||
{
|
||||
tsConsoleStream << "Requested to register entry for "
|
||||
<< InetAddr.toString() << " (" << LInetAddr.toString() << ")"
|
||||
<< ": " << ServerInfo.strName << endl;
|
||||
|
||||
QMutexLocker locker ( &Mutex );
|
||||
|
||||
const int iCurServerListSize = ServerList.size();
|
||||
|
||||
// define invalid index used as a flag
|
||||
|
@ -394,10 +409,13 @@ void CServerListManager::CentralServerRegisterServer ( const CHostAddress& In
|
|||
|
||||
void CServerListManager::CentralServerUnregisterServer ( const CHostAddress& InetAddr )
|
||||
{
|
||||
QMutexLocker locker ( &Mutex );
|
||||
|
||||
if ( bIsCentralServer && bEnabled )
|
||||
{
|
||||
tsConsoleStream << "Requested to unregister entry for "
|
||||
<< InetAddr.toString() << endl;
|
||||
|
||||
QMutexLocker locker ( &Mutex );
|
||||
|
||||
const int iCurServerListSize = ServerList.size();
|
||||
|
||||
// Find the server to unregister in the list. The very first list entry
|
||||
|
@ -587,7 +605,6 @@ void CServerListManager::SlaveServerRegisterServer ( const bool bIsRegister )
|
|||
void CServerListManager::SetSvrRegStatus ( ESvrRegStatus eNSvrRegStatus )
|
||||
{
|
||||
// output regirstation result/update on the console
|
||||
QTextStream& tsConsoleStream = *( ( new ConsoleWriterFactory() )->get() );
|
||||
tsConsoleStream << "Server Registration Status update: " << svrRegStatusToString ( eNSvrRegStatus ) << endl;
|
||||
|
||||
// store the state and inform the GUI about the new status
|
||||
|
|
|
@ -186,6 +186,7 @@ protected:
|
|||
QTimer TimerCLRegisterServerResp;
|
||||
|
||||
QMutex Mutex;
|
||||
QTextStream& tsConsoleStream;
|
||||
|
||||
QList<CServerListEntry> ServerList;
|
||||
|
||||
|
|
183
src/signalhandler.cpp
Executable file
|
@ -0,0 +1,183 @@
|
|||
/******************************************************************************\
|
||||
* Copyright (c) 2020
|
||||
*
|
||||
* Author(s):
|
||||
* Peter L Jones
|
||||
*
|
||||
******************************************************************************
|
||||
*
|
||||
* 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
|
||||
*
|
||||
******************************************************************************
|
||||
*
|
||||
* This code contains some ideas derived from QCtrlSignals
|
||||
* https://github.com/Skycoder42/QCtrlSignals.git
|
||||
* - mostly the singleton and emitSignal code, plus some of the structure
|
||||
* - virtually everything else is common knowledge across SourceForge answers
|
||||
*
|
||||
* BSD 3-Clause License
|
||||
*
|
||||
* Copyright (c) 2016, Felix Barz
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
\******************************************************************************/
|
||||
|
||||
#include "signalhandler.h"
|
||||
|
||||
class CSignalHandlerSingleton : public CSignalHandler {
|
||||
public:
|
||||
inline CSignalHandlerSingleton() : CSignalHandler() {}
|
||||
};
|
||||
Q_GLOBAL_STATIC ( CSignalHandlerSingleton, singleton )
|
||||
|
||||
CSignalHandler::CSignalHandler() : pSignalBase ( CSignalBase::withSignalHandler ( this ) ) {}
|
||||
|
||||
CSignalHandler::~CSignalHandler() = default;
|
||||
|
||||
CSignalHandler* CSignalHandler::getSingletonP() { return singleton; }
|
||||
|
||||
bool CSignalHandler::emitSignal ( int sigNum )
|
||||
{
|
||||
return QMetaObject::invokeMethod( singleton, "ShutdownSignal", Qt::QueuedConnection, Q_ARG( int, sigNum ) );
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
void CSignalHandler::OnSocketNotify( int socket )
|
||||
{
|
||||
int sigNum;
|
||||
if ( ::read ( socket, &sigNum, sizeof ( int ) ) == sizeof ( int ) )
|
||||
{
|
||||
emitSignal ( sigNum );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------
|
||||
|
||||
CSignalBase::CSignalBase ( CSignalHandler* pSignalHandler ) :
|
||||
pSignalHandler ( pSignalHandler )
|
||||
{
|
||||
}
|
||||
|
||||
CSignalBase::~CSignalBase() = default;
|
||||
|
||||
CSignalBase* CSignalBase::withSignalHandler ( CSignalHandler* pSignalHandler )
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return new CSignalWin ( pSignalHandler );
|
||||
#else
|
||||
return new CSignalUnix ( pSignalHandler );
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
CSignalWin::CSignalWin ( CSignalHandler* nPSignalHandler ) :
|
||||
CSignalBase ( nPSignalHandler ),
|
||||
lock ( QReadWriteLock::Recursive )
|
||||
{
|
||||
SetConsoleCtrlHandler ( signalHandler, true );
|
||||
}
|
||||
|
||||
CSignalWin::~CSignalWin() {
|
||||
SetConsoleCtrlHandler ( signalHandler, false );
|
||||
}
|
||||
|
||||
QReadWriteLock* CSignalWin::getLock() const
|
||||
{
|
||||
return &lock;
|
||||
}
|
||||
|
||||
BOOL WINAPI CSignalWin::signalHandler ( _In_ DWORD sigNum )
|
||||
{
|
||||
auto self = getSelf<CSignalWin>();
|
||||
QReadLocker lock ( self->getLock() );
|
||||
return self->pSignalHandler->emitSignal ( static_cast<int>( sigNum ) );
|
||||
}
|
||||
|
||||
#else
|
||||
int CSignalUnix::socketPair[2];
|
||||
|
||||
CSignalUnix::CSignalUnix ( CSignalHandler* nPSignalHandler ) :
|
||||
CSignalBase ( nPSignalHandler )
|
||||
{
|
||||
if ( ::socketpair ( AF_UNIX, SOCK_STREAM, 0, socketPair ) == 0 )
|
||||
{
|
||||
socketNotifier = new QSocketNotifier ( socketPair[ 1 ], QSocketNotifier::Read );
|
||||
|
||||
QObject::connect ( socketNotifier, &QSocketNotifier::activated, nPSignalHandler, &CSignalHandler::OnSocketNotify );
|
||||
|
||||
socketNotifier->setEnabled ( true );
|
||||
|
||||
setSignalHandled ( SIGINT, true );
|
||||
setSignalHandled ( SIGTERM, true );
|
||||
}
|
||||
}
|
||||
|
||||
CSignalUnix::~CSignalUnix() {
|
||||
setSignalHandled ( SIGINT, false );
|
||||
setSignalHandled ( SIGTERM, false );
|
||||
}
|
||||
|
||||
QReadWriteLock* CSignalUnix::getLock() const { return nullptr; }
|
||||
|
||||
bool CSignalUnix::setSignalHandled ( int sigNum, bool state )
|
||||
{
|
||||
struct sigaction sa;
|
||||
sigemptyset ( &sa.sa_mask );
|
||||
|
||||
if ( state )
|
||||
{
|
||||
sa.sa_handler = CSignalUnix::signalHandler;
|
||||
sa.sa_flags |= SA_RESTART;
|
||||
}
|
||||
else
|
||||
{
|
||||
sa.sa_handler = SIG_DFL;
|
||||
}
|
||||
|
||||
return ::sigaction ( sigNum, &sa, nullptr ) == 0;
|
||||
}
|
||||
|
||||
void CSignalUnix::signalHandler ( int sigNum )
|
||||
{
|
||||
const auto res = ::write ( socketPair[ 0 ], &sigNum, sizeof ( int ) );
|
||||
Q_UNUSED ( res );
|
||||
}
|
||||
#endif
|
177
src/signalhandler.h
Executable file
|
@ -0,0 +1,177 @@
|
|||
/******************************************************************************\
|
||||
* Copyright (c) 2020
|
||||
*
|
||||
* Author(s):
|
||||
* Peter L Jones
|
||||
*
|
||||
******************************************************************************
|
||||
*
|
||||
* 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
|
||||
*
|
||||
******************************************************************************
|
||||
*
|
||||
* This code contains some ideas derived from QCtrlSignals
|
||||
* https://github.com/Skycoder42/QCtrlSignals.git
|
||||
* - mostly the singleton and emitSignal code, plus some of the structure
|
||||
* - virtually everything else is common knowledge across SourceForge answers
|
||||
*
|
||||
* BSD 3-Clause License
|
||||
*
|
||||
* Copyright (c) 2016, Felix Barz
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QScopedPointer>
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QReadWriteLock>
|
||||
#include <QtCore/QSet>
|
||||
#include <QGlobalStatic>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <qt_windows.h>
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QSemaphore>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QDebug>
|
||||
#else
|
||||
#include <QSocketNotifier>
|
||||
#include <QObject>
|
||||
#include <QCoreApplication>
|
||||
#include <csignal>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
class CSignalBase;
|
||||
|
||||
class CSignalHandler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class CSignalBase;
|
||||
friend class CSignalHandlerSingleton;
|
||||
|
||||
public:
|
||||
static CSignalHandler* getSingletonP();
|
||||
|
||||
bool emitSignal ( int );
|
||||
|
||||
#ifndef _WIN32
|
||||
public slots:
|
||||
void OnSocketNotify ( int socket );
|
||||
#endif
|
||||
|
||||
signals:
|
||||
void ShutdownSignal ( int sigNum );
|
||||
|
||||
private:
|
||||
QScopedPointer<CSignalBase> pSignalBase;
|
||||
|
||||
explicit CSignalHandler();
|
||||
~CSignalHandler() override;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------
|
||||
|
||||
class CSignalBase
|
||||
{
|
||||
Q_DISABLE_COPY ( CSignalBase )
|
||||
|
||||
public:
|
||||
static CSignalBase* withSignalHandler ( CSignalHandler* );
|
||||
virtual ~CSignalBase();
|
||||
|
||||
virtual QReadWriteLock* getLock() const = 0;
|
||||
|
||||
QSet<int> sHandledSigNums;
|
||||
|
||||
protected:
|
||||
CSignalBase ( CSignalHandler* );
|
||||
|
||||
CSignalHandler* pSignalHandler;
|
||||
|
||||
template <typename T>
|
||||
static T *getSelf()
|
||||
{
|
||||
return static_cast<T*>( CSignalHandler::getSingletonP()->pSignalBase.data() );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
class CSignalWin : public CSignalBase
|
||||
{
|
||||
public:
|
||||
CSignalWin ( CSignalHandler* );
|
||||
~CSignalWin() override;
|
||||
|
||||
virtual QReadWriteLock* getLock() const override;
|
||||
|
||||
private:
|
||||
mutable QReadWriteLock lock;
|
||||
|
||||
static BOOL WINAPI signalHandler ( _In_ DWORD sigNum );
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class CSignalUnix : public CSignalBase
|
||||
{
|
||||
public:
|
||||
CSignalUnix ( CSignalHandler* );
|
||||
~CSignalUnix() override;
|
||||
|
||||
virtual QReadWriteLock* getLock() const override;
|
||||
|
||||
private:
|
||||
QSocketNotifier* socketNotifier = nullptr;
|
||||
bool setSignalHandled ( int sigNum, bool state );
|
||||
|
||||
static int socketPair[2];
|
||||
static void signalHandler ( int sigNum );
|
||||
};
|
||||
|
||||
#endif
|
|
@ -65,11 +65,9 @@ void CSocket::Init ( const quint16 iPortNumber )
|
|||
}
|
||||
else
|
||||
{
|
||||
// Per definition use the port number plus ten for the client to make
|
||||
// it possible to run server and client on the same computer. If the
|
||||
// port is not available, try "NUM_SOCKET_PORTS_TO_TRY" times with
|
||||
// incremented port numbers.
|
||||
quint16 iClientPortIncrement = 10; // start value: port nubmer plus ten
|
||||
// if the port is not available, try "NUM_SOCKET_PORTS_TO_TRY" times
|
||||
// with incremented port numbers
|
||||
quint16 iClientPortIncrement = 0;
|
||||
bSuccess = false; // initialization for while loop
|
||||
|
||||
while ( !bSuccess && ( iClientPortIncrement <= NUM_SOCKET_PORTS_TO_TRY ) )
|
||||
|
|
|
@ -30,14 +30,12 @@ CSoundBase::CSoundBase ( const QString& strNewSystemDriverTechniqueName,
|
|||
const bool bNewIsCallbackAudioInterface,
|
||||
void (*fpNewProcessCallback) ( CVector<int16_t>& psData, void* pParg ),
|
||||
void* pParg,
|
||||
const int iNewCtrlMIDIChannel,
|
||||
const bool bNewNoAutoJackConnect ) :
|
||||
fpProcessCallback ( fpNewProcessCallback ),
|
||||
pProcessCallbackArg ( pParg ), bRun ( false ),
|
||||
bIsCallbackAudioInterface ( bNewIsCallbackAudioInterface ),
|
||||
const int iNewCtrlMIDIChannel ) :
|
||||
fpProcessCallback ( fpNewProcessCallback ),
|
||||
pProcessCallbackArg ( pParg ), bRun ( false ),
|
||||
bIsCallbackAudioInterface ( bNewIsCallbackAudioInterface ),
|
||||
strSystemDriverTechniqueName ( strNewSystemDriverTechniqueName ),
|
||||
iCtrlMIDIChannel ( iNewCtrlMIDIChannel ),
|
||||
bNoAutoJackConnect ( bNewNoAutoJackConnect )
|
||||
iCtrlMIDIChannel ( iNewCtrlMIDIChannel )
|
||||
{
|
||||
// initializations for the sound card names (default)
|
||||
lNumDevs = 1;
|
||||
|
@ -143,10 +141,10 @@ QString CSoundBase::SetDev ( const int iNewDev )
|
|||
nullptr, APP_NAME, QString ( tr ( "The audio driver properties "
|
||||
"have changed to a state which is incompatible to this "
|
||||
"software. The selected audio device could not be used "
|
||||
"because of the following error: <b>" ) ) +
|
||||
"because of the following error:" ) + " <b>" ) +
|
||||
strErrorMessage +
|
||||
QString ( tr ( "</b><br><br>Please restart the software." ) ),
|
||||
"Close", nullptr );
|
||||
QString ( "</b><br><br>" + tr ( "Please restart the software." ) ),
|
||||
tr ( "Close" ), nullptr );
|
||||
|
||||
_exit ( 0 );
|
||||
}
|
||||
|
@ -188,11 +186,11 @@ QString CSoundBase::SetDev ( const int iNewDev )
|
|||
if ( !vsErrorList.isEmpty() )
|
||||
{
|
||||
// create error message with all details
|
||||
QString sErrorMessage = tr ( "<b>No usable " ) +
|
||||
QString sErrorMessage = "<b>" + tr ( "No usable " ) +
|
||||
strSystemDriverTechniqueName + tr ( " audio device "
|
||||
"(driver) found.</b><br><br>"
|
||||
"(driver) found." ) + "</b><br><br>" + tr (
|
||||
"In the following there is a list of all available drivers "
|
||||
"with the associated error message:<ul>" );
|
||||
"with the associated error message:" ) + "<ul>";
|
||||
|
||||
for ( int i = 0; i < lNumDevs; i++ )
|
||||
{
|
||||
|
@ -204,7 +202,7 @@ QString CSoundBase::SetDev ( const int iNewDev )
|
|||
// to be able to access the ASIO driver setup for changing, e.g., the sample rate, we
|
||||
// offer the user under Windows that we open the driver setups of all registered
|
||||
// ASIO drivers
|
||||
sErrorMessage = sErrorMessage + tr ( "<br/>Do you want to open the ASIO driver setups?" );
|
||||
sErrorMessage = sErrorMessage + "<br/>" + tr ( "Do you want to open the ASIO driver setups?" );
|
||||
|
||||
if ( QMessageBox::Yes == QMessageBox::information ( nullptr, APP_NAME, sErrorMessage, QMessageBox::Yes|QMessageBox::No ) )
|
||||
{
|
||||
|
|
|
@ -51,8 +51,7 @@ public:
|
|||
const bool bNewIsCallbackAudioInterface,
|
||||
void (*fpNewProcessCallback) ( CVector<int16_t>& psData, void* pParg ),
|
||||
void* pParg,
|
||||
const int iNewCtrlMIDIChannel,
|
||||
const bool bNewNoAutoJackConnect );
|
||||
const int iNewCtrlMIDIChannel );
|
||||
|
||||
virtual int Init ( const int iNewPrefMonoBufferSize );
|
||||
virtual void Start();
|
||||
|
@ -98,6 +97,27 @@ protected:
|
|||
virtual void UnloadCurrentDriver() {}
|
||||
QVector<QString> LoadAndInitializeFirstValidDriver ( const bool bOpenDriverSetup = false );
|
||||
|
||||
static void GetSelCHAndAddCH ( const int iSelCH, const int iNumInChan,
|
||||
int& iSelCHOut, int& iSelAddCHOut )
|
||||
{
|
||||
// we have a mixed channel setup, definitions:
|
||||
// - mixed channel setup only for 4 physical inputs:
|
||||
// SelCH == 4: Ch 0 + Ch 2
|
||||
// SelCh == 5: Ch 0 + Ch 3
|
||||
// SelCh == 6: Ch 1 + Ch 2
|
||||
// SelCh == 7: Ch 1 + Ch 3
|
||||
if ( iSelCH >= iNumInChan )
|
||||
{
|
||||
iSelAddCHOut = ( ( iSelCH - iNumInChan ) % 2 ) + 2;
|
||||
iSelCHOut = ( iSelCH - iNumInChan ) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
iSelAddCHOut = -1; // set it to an invalid number
|
||||
iSelCHOut = iSelCH;
|
||||
}
|
||||
}
|
||||
|
||||
// function pointer to callback function
|
||||
void (*fpProcessCallback) ( CVector<int16_t>& psData, void* arg );
|
||||
void* pProcessCallbackArg;
|
||||
|
@ -121,7 +141,6 @@ protected:
|
|||
bool bIsCallbackAudioInterface;
|
||||
QString strSystemDriverTechniqueName;
|
||||
int iCtrlMIDIChannel;
|
||||
bool bNoAutoJackConnect;
|
||||
|
||||
CVector<int16_t> vecsAudioSndCrdStereo;
|
||||
|
||||
|
|
258
src/util.cpp
|
@ -348,16 +348,14 @@ CAboutDlg::CAboutDlg ( QWidget* parent ) : QDialog ( parent )
|
|||
{
|
||||
setupUi ( this );
|
||||
|
||||
// set the text for the about dialog html text control
|
||||
txvCredits->setOpenExternalLinks ( true );
|
||||
txvCredits->setText (
|
||||
"<p>" // general description of software
|
||||
"<big>" + tr ( "The " ) + APP_NAME +
|
||||
// general description of software
|
||||
txvAbout->setText (
|
||||
"<p>" + tr ( "The " ) + APP_NAME +
|
||||
tr ( " software enables musicians to perform real-time jam sessions "
|
||||
"over the internet. There is a " ) + APP_NAME + tr ( " "
|
||||
"over the internet." ) + "<br>" + tr ( "There is a " ) + APP_NAME + tr ( " "
|
||||
"server which collects the audio data from each " ) +
|
||||
APP_NAME + tr ( " client, mixes the audio data and sends the mix back "
|
||||
"to each client." ) + "</big></p><br>"
|
||||
"to each client." ) + "</p>"
|
||||
"<p><font face=\"courier\">" // GPL header text
|
||||
"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 "
|
||||
|
@ -370,27 +368,48 @@ CAboutDlg::CAboutDlg ( QWidget* parent ) : QDialog ( parent )
|
|||
"License along with his program; if not, write to the Free Software "
|
||||
"Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 "
|
||||
"USA"
|
||||
"</font></p><br>"
|
||||
"<p><b>" + APP_NAME + // libraries used by this compilation
|
||||
"</font></p>" );
|
||||
|
||||
// libraries used by this compilation
|
||||
txvLibraries->setText ( APP_NAME +
|
||||
tr ( " uses the following libraries, resources or code snippets:" ) +
|
||||
"</b></p>"
|
||||
"<ul>"
|
||||
"<li>Qt cross-platform application framework: "
|
||||
"<i><a href=""http://www.qt.io"">http://www.qt.io</a></i></li>"
|
||||
"<li>Opus Interactive Audio Codec: "
|
||||
"<i><a href=""http://www.opus-codec.org"">http://www.opus-codec.org</a></i></li>"
|
||||
"<li>Audio reverberation code: by Perry R. Cook and Gary P. Scavone, "
|
||||
"1995 - 2004 (taken from "
|
||||
"<i><a href=""http://ccrma.stanford.edu/software/stk"">"
|
||||
"The Synthesis ToolKit in C++ (STK)</a></i>)</li>"
|
||||
"<li>Some pixmaps are from the Open Clip Art Library (OCAL): "
|
||||
"<i><a href=""http://openclipart.org"">http://openclipart.org</a></i></li>"
|
||||
"<li>Country flag icons from Mark James: "
|
||||
"<i><a href=""http://www.famfamfam.com"">http://www.famfamfam.com</a></i></li>"
|
||||
"</ul>"
|
||||
"We would like to acknowledge the contributors listed in the "
|
||||
"<a href=""https://github.com/corrados/jamulus/graphs/contributors"">Github Contributors list</a>"
|
||||
"</center><br>");
|
||||
"<br><p>" + tr ( "Qt cross-platform application framework" ) +
|
||||
", <i><a href=""http://www.qt.io"">http://www.qt.io</a></i></p>"
|
||||
"<p>Opus Interactive Audio Codec"
|
||||
", <i><a href=""http://www.opus-codec.org"">http://www.opus-codec.org</a></i></p>"
|
||||
"<p>" + tr ( "Audio reverberation code by Perry R. Cook and Gary P. Scavone" ) +
|
||||
", 1995 - 2004, <i><a href=""http://ccrma.stanford.edu/software/stk"">"
|
||||
"The Synthesis ToolKit in C++ (STK)</a></i></p>"
|
||||
"<p>" + tr ( "Some pixmaps are from the" ) + " Open Clip Art Library (OCAL), "
|
||||
"<i><a href=""http://openclipart.org"">http://openclipart.org</a></i></p>"
|
||||
"<p>" + tr ( "Country flag icons from Mark James" ) +
|
||||
", <i><a href=""http://www.famfamfam.com"">http://www.famfamfam.com</a></i></p>" );
|
||||
|
||||
// contributors list
|
||||
txvContributors->setText (
|
||||
"<p>Peter L. Jones (<a href=""https://github.com/pljones"">pljones</a>)</p>"
|
||||
"<p>Jonathan Baker-Bates (<a href=""https://github.com/gilgongo"">gilgongo</a>)</p>"
|
||||
"<p>Daniele Masato (<a href=""https://github.com/doloopuntil"">doloopuntil</a>)</p>"
|
||||
"<p>Simon Tomlinson (<a href=""https://github.com/sthenos"">sthenos</a>)</p>"
|
||||
"<p>Marc jr. Landolt (<a href=""https://github.com/braindef"">braindef</a>)</p>"
|
||||
"<p>Olivier Humbert (<a href=""https://github.com/trebmuh"">trebmuh</a>)</p>"
|
||||
"<p>mirabilos (<a href=""https://github.com/mirabilos"">mirabilos</a>)</p>"
|
||||
"<p>newlaurent62 (<a href=""https://github.com/newlaurent62"">newlaurent62</a>)</p>"
|
||||
"<p>Emlyn Bolton (<a href=""https://github.com/emlynmac"">emlynmac</a>)</p>"
|
||||
"<p>Jos van den Oever (<a href=""https://github.com/vandenoever"">vandenoever</a>)</p>"
|
||||
"<p>Tormod Volden (<a href=""https://github.com/tormodvolden"">tormodvolden</a>)</p>"
|
||||
"<p>Stanislas Michalak (<a href=""https://github.com/stanislas-m"">stanislas-m</a>)</p>"
|
||||
"<br>" + tr ( "For details on the contributions check out the " ) +
|
||||
"<a href=""https://github.com/corrados/jamulus/graphs/contributors"">" + tr ( "Github Contributors list" ) + "</a>." );
|
||||
|
||||
// translators
|
||||
txvTranslation->setText (
|
||||
"<p><b>Spanish</b></p>"
|
||||
"<p>Daryl Hanlon (<a href=""https://github.com/ignotus666"">ignotus666</a>)</p>"
|
||||
"<p><b>French</b></p>"
|
||||
"<p>Olivier Humbert (<a href=""https://github.com/trebmuh"">trebmuh</a>)</p>"
|
||||
"<p><b>Portuguese</b></p>"
|
||||
"<p>Miguel de Matos (<a href=""https://github.com/Snayler"">Snayler</a>)</p>" );
|
||||
|
||||
// set version number in about dialog
|
||||
lblVersion->setText ( GetVersionAndNameStr() );
|
||||
|
@ -406,7 +425,7 @@ QString CAboutDlg::GetVersionAndNameStr ( const bool bWithHtml )
|
|||
// name, short description and GPL hint
|
||||
if ( bWithHtml )
|
||||
{
|
||||
strVersionText += "<center><b>";
|
||||
strVersionText += "<b>";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -424,24 +443,14 @@ QString CAboutDlg::GetVersionAndNameStr ( const bool bWithHtml )
|
|||
strVersionText += "\n *** ";
|
||||
}
|
||||
|
||||
strVersionText += tr ( "Internet Jam Session Software" );
|
||||
|
||||
if ( bWithHtml )
|
||||
{
|
||||
strVersionText += "<br>";
|
||||
}
|
||||
else
|
||||
if ( !bWithHtml )
|
||||
{
|
||||
strVersionText += tr ( "Internet Jam Session Software" );
|
||||
strVersionText += "\n *** ";
|
||||
}
|
||||
|
||||
strVersionText += tr ( "Under the GNU General Public License (GPL)" );
|
||||
|
||||
if ( bWithHtml )
|
||||
{
|
||||
strVersionText += "</center>";
|
||||
}
|
||||
|
||||
return strVersionText;
|
||||
}
|
||||
|
||||
|
@ -462,9 +471,9 @@ CLicenceDlg::CLicenceDlg ( QWidget* parent ) : QDialog ( parent )
|
|||
QVBoxLayout* pLayout = new QVBoxLayout ( this );
|
||||
QHBoxLayout* pSubLayout = new QHBoxLayout;
|
||||
QTextBrowser* txvLicence = new QTextBrowser ( this );
|
||||
QCheckBox* chbAgree = new QCheckBox ( "I &agree to the above licence terms", this );
|
||||
butAccept = new QPushButton ( "Accept", this );
|
||||
QPushButton* butDecline = new QPushButton ( "Decline", this );
|
||||
QCheckBox* chbAgree = new QCheckBox ( tr ( "I &agree to the above licence terms" ), this );
|
||||
butAccept = new QPushButton ( tr ( "Accept" ), this );
|
||||
QPushButton* butDecline = new QPushButton ( tr ( "Decline" ), this );
|
||||
|
||||
pSubLayout->addStretch();
|
||||
pSubLayout->addWidget ( chbAgree );
|
||||
|
@ -486,10 +495,10 @@ CLicenceDlg::CLicenceDlg ( QWidget* parent ) : QDialog ( parent )
|
|||
"You agree that all data, sounds, or other works transmitted to this server "
|
||||
"are owned and created by you or your licensors, and that you are making these "
|
||||
"data, sounds or other works available via the following Creative Commons "
|
||||
"License (for more information on this license, see "
|
||||
"License (for more information on this license, see " ) +
|
||||
"<i><a href=""http://creativecommons.org/licenses/by-nc-sa/4.0"">"
|
||||
"http://creativecommons.org/licenses/by-nc-sa/4.0</a></i>):" ) + "</big></p>" +
|
||||
"<h3>Attribution-NonCommercial-ShareAlike 4.0</h3>" +
|
||||
"http://creativecommons.org/licenses/by-nc-sa/4.0</a></i>):</big></p>"
|
||||
"<h3>Attribution-NonCommercial-ShareAlike 4.0</h3>"
|
||||
"<p>" + tr ( "You are free to:" ) +
|
||||
"<ul>"
|
||||
"<li><b>" + tr ( "Share" ) + "</b> - " +
|
||||
|
@ -539,22 +548,22 @@ CMusProfDlg::CMusProfDlg ( CClient* pNCliP,
|
|||
- label with combo box for skill level
|
||||
- OK button
|
||||
*/
|
||||
setWindowTitle ( "Musician Profile" );
|
||||
setWindowTitle ( tr ( "Musician Profile" ) );
|
||||
setWindowIcon ( QIcon ( QString::fromUtf8 ( ":/png/main/res/fronticon.png" ) ) );
|
||||
|
||||
QVBoxLayout* pLayout = new QVBoxLayout ( this );
|
||||
QHBoxLayout* pButSubLayout = new QHBoxLayout;
|
||||
QLabel* plblAlias = new QLabel ( "Alias/Name", this );
|
||||
QLabel* plblAlias = new QLabel ( tr ( "Alias/Name" ), this );
|
||||
pedtAlias = new QLineEdit ( this );
|
||||
QLabel* plblInstrument = new QLabel ( "Instrument", this );
|
||||
QLabel* plblInstrument = new QLabel ( tr ( "Instrument" ), this );
|
||||
pcbxInstrument = new QComboBox ( this );
|
||||
QLabel* plblCountry = new QLabel ( "Country", this );
|
||||
QLabel* plblCountry = new QLabel ( tr ( "Country" ), this );
|
||||
pcbxCountry = new QComboBox ( this );
|
||||
QLabel* plblCity = new QLabel ( "City", this );
|
||||
QLabel* plblCity = new QLabel ( tr ( "City" ), this );
|
||||
pedtCity = new QLineEdit ( this );
|
||||
QLabel* plblSkill = new QLabel ( "Skill", this );
|
||||
QLabel* plblSkill = new QLabel ( tr ( "Skill" ), this );
|
||||
pcbxSkill = new QComboBox ( this );
|
||||
QPushButton* butClose = new QPushButton ( "&Close", this );
|
||||
QPushButton* butClose = new QPushButton ( tr ( "&Close" ), this );
|
||||
|
||||
QGridLayout* pGridLayout = new QGridLayout;
|
||||
plblAlias->setSizePolicy ( QSizePolicy::Minimum, QSizePolicy::Expanding );
|
||||
|
@ -592,13 +601,31 @@ CMusProfDlg::CMusProfDlg ( CClient* pNCliP,
|
|||
// add an entry for all known instruments
|
||||
for ( int iCurInst = 0; iCurInst < CInstPictures::GetNumAvailableInst(); iCurInst++ )
|
||||
{
|
||||
// create a combo box item with text and image
|
||||
pcbxInstrument->addItem (
|
||||
QIcon ( CInstPictures::GetResourceReference ( iCurInst ) ),
|
||||
CInstPictures::GetName ( iCurInst ),
|
||||
iCurInst );
|
||||
// create a combo box item with text, image and background color
|
||||
QColor InstrColor;
|
||||
|
||||
pcbxInstrument->addItem ( QIcon ( CInstPictures::GetResourceReference ( iCurInst ) ),
|
||||
CInstPictures::GetName ( iCurInst ),
|
||||
iCurInst );
|
||||
|
||||
switch ( CInstPictures::GetCategory ( iCurInst ) )
|
||||
{
|
||||
case CInstPictures::IC_OTHER_INSTRUMENT: InstrColor = QColor ( Qt::blue ); break;
|
||||
case CInstPictures::IC_WIND_INSTRUMENT: InstrColor = QColor ( Qt::green ); break;
|
||||
case CInstPictures::IC_STRING_INSTRUMENT: InstrColor = QColor ( Qt::red ); break;
|
||||
case CInstPictures::IC_PLUCKING_INSTRUMENT: InstrColor = QColor ( Qt::cyan ); break;
|
||||
case CInstPictures::IC_PERCUSSION_INSTRUMENT: InstrColor = QColor ( Qt::white ); break;
|
||||
case CInstPictures::IC_KEYBOARD_INSTRUMENT: InstrColor = QColor ( Qt::yellow ); break;
|
||||
case CInstPictures::IC_MULTIPLE_INSTRUMENT: InstrColor = QColor ( Qt::black ); break;
|
||||
}
|
||||
|
||||
InstrColor.setAlpha ( 10 );
|
||||
pcbxInstrument->setItemData ( iCurInst, InstrColor, Qt::BackgroundRole );
|
||||
}
|
||||
|
||||
// sort the items in alphabetical order
|
||||
pcbxInstrument->model()->sort ( 0 );
|
||||
|
||||
|
||||
// Country flag icons combo box --------------------------------------------
|
||||
// add an entry for all known country flags
|
||||
|
@ -609,8 +636,7 @@ CMusProfDlg::CMusProfDlg ( CClient* pNCliP,
|
|||
if ( static_cast<QLocale::Country> ( iCurCntry ) != QLocale::AnyCountry )
|
||||
{
|
||||
// get current country enum
|
||||
QLocale::Country eCountry =
|
||||
static_cast<QLocale::Country> ( iCurCntry );
|
||||
QLocale::Country eCountry = static_cast<QLocale::Country> ( iCurCntry );
|
||||
|
||||
// try to load icon from resource file name
|
||||
QIcon CurFlagIcon;
|
||||
|
@ -635,7 +661,7 @@ CMusProfDlg::CMusProfDlg ( CClient* pNCliP,
|
|||
FlagNoneIcon.addFile ( ":/png/flags/res/flags/flagnone.png" );
|
||||
pcbxCountry->insertItem ( 0,
|
||||
FlagNoneIcon,
|
||||
"None",
|
||||
tr ( "None" ),
|
||||
static_cast<int> ( QLocale::AnyCountry ) );
|
||||
|
||||
|
||||
|
@ -647,35 +673,35 @@ CMusProfDlg::CMusProfDlg ( CClient* pNCliP,
|
|||
RGBCOL_G_SL_NOT_SET,
|
||||
RGBCOL_B_SL_NOT_SET ) );
|
||||
|
||||
pcbxSkill->addItem ( QIcon ( SLPixmap ), "None", SL_NOT_SET );
|
||||
pcbxSkill->addItem ( QIcon ( SLPixmap ), tr ( "None" ), SL_NOT_SET );
|
||||
|
||||
SLPixmap.fill ( QColor::fromRgb ( RGBCOL_R_SL_BEGINNER,
|
||||
RGBCOL_G_SL_BEGINNER,
|
||||
RGBCOL_B_SL_BEGINNER ) );
|
||||
|
||||
pcbxSkill->addItem ( QIcon ( SLPixmap ), "Beginner", SL_BEGINNER );
|
||||
pcbxSkill->addItem ( QIcon ( SLPixmap ), tr ( "Beginner" ), SL_BEGINNER );
|
||||
|
||||
SLPixmap.fill ( QColor::fromRgb ( RGBCOL_R_SL_INTERMEDIATE,
|
||||
RGBCOL_G_SL_INTERMEDIATE,
|
||||
RGBCOL_B_SL_INTERMEDIATE ) );
|
||||
|
||||
pcbxSkill->addItem ( QIcon ( SLPixmap ), "Intermediate", SL_INTERMEDIATE );
|
||||
pcbxSkill->addItem ( QIcon ( SLPixmap ), tr ( "Intermediate" ), SL_INTERMEDIATE );
|
||||
|
||||
SLPixmap.fill ( QColor::fromRgb ( RGBCOL_R_SL_SL_PROFESSIONAL,
|
||||
RGBCOL_G_SL_SL_PROFESSIONAL,
|
||||
RGBCOL_B_SL_SL_PROFESSIONAL ) );
|
||||
|
||||
pcbxSkill->addItem ( QIcon ( SLPixmap ), "Expert", SL_PROFESSIONAL );
|
||||
pcbxSkill->addItem ( QIcon ( SLPixmap ), tr ( "Expert" ), SL_PROFESSIONAL );
|
||||
|
||||
|
||||
// Add help text to controls -----------------------------------------------
|
||||
// fader tag
|
||||
QString strFaderTag = tr ( "<b>Musician Profile:</b> Set your name "
|
||||
"or an alias here so that the other musicians you want to play with "
|
||||
QString strFaderTag = "<b>" + tr ( "Musician Profile" ) + ":</b> " + tr (
|
||||
"Set your name or an alias here so that the other musicians you want to play with "
|
||||
"know who you are. Additionally you may set an instrument picture of "
|
||||
"the instrument you play and a flag of the country you are living. "
|
||||
"The city you live in and the skill level of playing your instrument "
|
||||
"may also be added.\n"
|
||||
"may also be added." ) + "<br>" + tr (
|
||||
"What you set here will appear at your fader on the mixer board when "
|
||||
"you are connected to a " ) + APP_NAME + tr ( " server. This tag will "
|
||||
"also show up at each client which is connected to the same server as "
|
||||
|
@ -806,16 +832,20 @@ void CMusProfDlg::OnSkillActivated ( int iCntryListItem )
|
|||
|
||||
|
||||
// Help menu -------------------------------------------------------------------
|
||||
CHelpMenu::CHelpMenu ( QWidget* parent ) : QMenu ( "&?", parent )
|
||||
CHelpMenu::CHelpMenu ( const bool bIsClient, QWidget* parent ) : QMenu ( tr ( "&Help" ), parent )
|
||||
{
|
||||
// standard help menu consists of about and what's this help
|
||||
addAction ( tr ( "What's &This" ), this,
|
||||
SLOT ( OnHelpWhatsThis() ), QKeySequence ( Qt::SHIFT + Qt::Key_F1 ) );
|
||||
|
||||
if ( bIsClient )
|
||||
{
|
||||
addAction ( tr ( "Getting &Started..." ), this, SLOT ( OnHelpClientGetStarted() ) );
|
||||
addAction ( tr ( "Software &Manual..." ), this, SLOT ( OnHelpSoftwareMan() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
addAction ( tr ( "Getting &Started..." ), this, SLOT ( OnHelpServerGetStarted() ) );
|
||||
}
|
||||
addSeparator();
|
||||
addAction ( tr ( "&Download Link..." ), this,
|
||||
SLOT ( OnHelpDownloadLink() ) );
|
||||
|
||||
addAction ( tr ( "What's &This" ), this, SLOT ( OnHelpWhatsThis() ), QKeySequence ( Qt::SHIFT + Qt::Key_F1 ) );
|
||||
addSeparator();
|
||||
addAction ( tr ( "&About..." ), this, SLOT ( OnHelpAbout() ) );
|
||||
}
|
||||
|
@ -935,35 +965,41 @@ CVector<CInstPictures::CInstPictProps>& CInstPictures::GetTable()
|
|||
// instrument picture data base initialization
|
||||
// NOTE: Do not change the order of any instrument in the future!
|
||||
// NOTE: The very first entry is the "not used" element per definition.
|
||||
vecDataBase.Add ( CInstPictProps ( "None", ":/png/instr/res/instruments/instrnone.png", IC_OTHER_INSTRUMENT ) ); // special first element
|
||||
vecDataBase.Add ( CInstPictProps ( "Drum Set", ":/png/instr/res/instruments/instrdrumset.png", IC_PERCUSSION_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Djembe", ":/png/instr/res/instruments/instrdjembe.png", IC_PERCUSSION_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Electric Guitar", ":/png/instr/res/instruments/instreguitar.png", IC_PLUCKING_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Acoustic Guitar", ":/png/instr/res/instruments/instraguitar.png", IC_PLUCKING_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Bass Guitar", ":/png/instr/res/instruments/instrbassguitar.png", IC_PLUCKING_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Keyboard", ":/png/instr/res/instruments/instrkeyboard.png", IC_KEYBOARD_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Synthesizer", ":/png/instr/res/instruments/instrsynthesizer.png", IC_KEYBOARD_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Grand Piano", ":/png/instr/res/instruments/instrgrandpiano.png", IC_KEYBOARD_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Accordion", ":/png/instr/res/instruments/instraccordeon.png", IC_KEYBOARD_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Vocal", ":/png/instr/res/instruments/instrvocal.png", IC_OTHER_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Microphone", ":/png/instr/res/instruments/instrmicrophone.png", IC_OTHER_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Harmonica", ":/png/instr/res/instruments/instrharmonica.png", IC_WIND_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Trumpet", ":/png/instr/res/instruments/instrtrumpet.png", IC_WIND_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Trombone", ":/png/instr/res/instruments/instrtrombone.png", IC_WIND_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "French Horn", ":/png/instr/res/instruments/instrfrenchhorn.png", IC_WIND_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Tuba", ":/png/instr/res/instruments/instrtuba.png", IC_WIND_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Saxophone", ":/png/instr/res/instruments/instrsaxophone.png", IC_WIND_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Clarinet", ":/png/instr/res/instruments/instrclarinet.png", IC_WIND_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Flute", ":/png/instr/res/instruments/instrflute.png", IC_WIND_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Violin", ":/png/instr/res/instruments/instrviolin.png", IC_STRING_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Cello", ":/png/instr/res/instruments/instrcello.png", IC_STRING_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Double Bass", ":/png/instr/res/instruments/instrdoublebass.png", IC_STRING_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Recorder", ":/png/instr/res/instruments/instrrecorder.png", IC_OTHER_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Streamer", ":/png/instr/res/instruments/instrstreamer.png", IC_OTHER_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Listener", ":/png/instr/res/instruments/instrlistener.png", IC_OTHER_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Guitar+Vocal", ":/png/instr/res/instruments/instrguitarvocal.png", IC_MULTIPLE_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Keyboard+Vocal", ":/png/instr/res/instruments/instrkeyboardvocal.png", IC_MULTIPLE_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( "Bodhran", ":/png/instr/res/instruments/bodhran.png", IC_PERCUSSION_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "None" ), ":/png/instr/res/instruments/instrnone.png", IC_OTHER_INSTRUMENT ) ); // special first element
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Drum Set" ), ":/png/instr/res/instruments/instrdrumset.png", IC_PERCUSSION_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Djembe" ), ":/png/instr/res/instruments/instrdjembe.png", IC_PERCUSSION_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Electric Guitar" ), ":/png/instr/res/instruments/instreguitar.png", IC_PLUCKING_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Acoustic Guitar" ), ":/png/instr/res/instruments/instraguitar.png", IC_PLUCKING_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Bass Guitar" ), ":/png/instr/res/instruments/instrbassguitar.png", IC_PLUCKING_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Keyboard" ), ":/png/instr/res/instruments/instrkeyboard.png", IC_KEYBOARD_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Synthesizer" ), ":/png/instr/res/instruments/instrsynthesizer.png", IC_KEYBOARD_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Grand Piano" ), ":/png/instr/res/instruments/instrgrandpiano.png", IC_KEYBOARD_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Accordion" ), ":/png/instr/res/instruments/instraccordeon.png", IC_KEYBOARD_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Vocal" ), ":/png/instr/res/instruments/instrvocal.png", IC_OTHER_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Microphone" ), ":/png/instr/res/instruments/instrmicrophone.png", IC_OTHER_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Harmonica" ), ":/png/instr/res/instruments/instrharmonica.png", IC_WIND_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Trumpet" ), ":/png/instr/res/instruments/instrtrumpet.png", IC_WIND_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Trombone" ), ":/png/instr/res/instruments/instrtrombone.png", IC_WIND_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "French Horn" ), ":/png/instr/res/instruments/instrfrenchhorn.png", IC_WIND_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Tuba" ), ":/png/instr/res/instruments/instrtuba.png", IC_WIND_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Saxophone" ), ":/png/instr/res/instruments/instrsaxophone.png", IC_WIND_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Clarinet" ), ":/png/instr/res/instruments/instrclarinet.png", IC_WIND_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Flute" ), ":/png/instr/res/instruments/instrflute.png", IC_WIND_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Violin" ), ":/png/instr/res/instruments/instrviolin.png", IC_STRING_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Cello" ), ":/png/instr/res/instruments/instrcello.png", IC_STRING_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Double Bass" ), ":/png/instr/res/instruments/instrdoublebass.png", IC_STRING_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Recorder" ), ":/png/instr/res/instruments/instrrecorder.png", IC_OTHER_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Streamer" ), ":/png/instr/res/instruments/instrstreamer.png", IC_OTHER_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Listener" ), ":/png/instr/res/instruments/instrlistener.png", IC_OTHER_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Guitar+Vocal" ), ":/png/instr/res/instruments/instrguitarvocal.png", IC_MULTIPLE_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Keyboard+Vocal" ), ":/png/instr/res/instruments/instrkeyboardvocal.png", IC_MULTIPLE_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Bodhran" ), ":/png/instr/res/instruments/bodhran.png", IC_PERCUSSION_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Bassoon" ), ":/png/instr/res/instruments/bassoon.png", IC_WIND_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Oboe" ), ":/png/instr/res/instruments/oboe.png", IC_WIND_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Harp" ), ":/png/instr/res/instruments/harp.png", IC_STRING_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Viola" ), ":/png/instr/res/instruments/viola.png", IC_STRING_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Congas" ), ":/png/instr/res/instruments/congas.png", IC_PERCUSSION_INSTRUMENT ) );
|
||||
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Bongo" ), ":/png/instr/res/instruments/bongo.png", IC_PERCUSSION_INSTRUMENT ) );
|
||||
|
||||
// now the table is initialized
|
||||
TableIsInitialized = true;
|
||||
|
@ -1006,6 +1042,20 @@ QString CInstPictures::GetName ( const int iInstrument )
|
|||
}
|
||||
}
|
||||
|
||||
CInstPictures::EInstCategory CInstPictures::GetCategory ( const int iInstrument )
|
||||
{
|
||||
// range check
|
||||
if ( IsInstIndexInRange ( iInstrument ) )
|
||||
{
|
||||
// return the name of the instrument
|
||||
return GetTable()[iInstrument].eInstCategory;
|
||||
}
|
||||
else
|
||||
{
|
||||
return IC_OTHER_INSTRUMENT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Locale management class -----------------------------------------------------
|
||||
QString CLocale::GetCountryFlagIconsResourceReference ( const QLocale::Country eCountry )
|
||||
|
|
36
src/util.h
|
@ -473,16 +473,17 @@ class CHelpMenu : public QMenu
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CHelpMenu ( QWidget* parent = nullptr );
|
||||
CHelpMenu ( const bool bIsClient, QWidget* parent = nullptr );
|
||||
|
||||
protected:
|
||||
CAboutDlg AboutDlg;
|
||||
|
||||
public slots:
|
||||
void OnHelpWhatsThis() { QWhatsThis::enterWhatsThisMode(); }
|
||||
void OnHelpAbout() { AboutDlg.exec(); }
|
||||
void OnHelpDownloadLink()
|
||||
{ QDesktopServices::openUrl ( QUrl ( SOFTWARE_DOWNLOAD_URL ) ); }
|
||||
void OnHelpWhatsThis() { QWhatsThis::enterWhatsThisMode(); }
|
||||
void OnHelpAbout() { AboutDlg.exec(); }
|
||||
void OnHelpClientGetStarted() { QDesktopServices::openUrl ( QUrl ( CLIENT_GETTING_STARTED_URL ) ); }
|
||||
void OnHelpServerGetStarted() { QDesktopServices::openUrl ( QUrl ( SERVER_GETTING_STARTED_URL ) ); }
|
||||
void OnHelpSoftwareMan() { QDesktopServices::openUrl ( QUrl ( SOFTWARE_MANUAL_URL ) ); }
|
||||
};
|
||||
|
||||
|
||||
|
@ -589,28 +590,28 @@ inline QString svrRegStatusToString ( ESvrRegStatus eSvrRegStatus )
|
|||
switch ( eSvrRegStatus )
|
||||
{
|
||||
case SRS_UNREGISTERED:
|
||||
return "Unregistered";
|
||||
return QCoreApplication::translate ( "CServerDlg", "Unregistered" );
|
||||
|
||||
case SRS_BAD_ADDRESS:
|
||||
return "Bad address";
|
||||
return QCoreApplication::translate ( "CServerDlg", "Bad address" );
|
||||
|
||||
case SRS_REQUESTED:
|
||||
return "Registration requested";
|
||||
return QCoreApplication::translate ( "CServerDlg", "Registration requested" );
|
||||
|
||||
case SRS_TIME_OUT:
|
||||
return "Registration failed";
|
||||
return QCoreApplication::translate ( "CServerDlg", "Registration failed" );
|
||||
|
||||
case SRS_UNKNOWN_RESP:
|
||||
return "Check server version";
|
||||
return QCoreApplication::translate ( "CServerDlg", "Check server version" );
|
||||
|
||||
case SRS_REGISTERED:
|
||||
return "Registered";
|
||||
return QCoreApplication::translate ( "CServerDlg", "Registered" );
|
||||
|
||||
case SRS_CENTRAL_SVR_FULL:
|
||||
return "Central Server full";
|
||||
return QCoreApplication::translate ( "CServerDlg", "Central Server full" );
|
||||
}
|
||||
|
||||
return QString ( "Unknown value " ).append ( eSvrRegStatus );
|
||||
return QString ( QCoreApplication::translate ( "CServerDlg", "Unknown value " ) ).append ( eSvrRegStatus );
|
||||
}
|
||||
|
||||
|
||||
|
@ -657,7 +658,7 @@ public:
|
|||
void Update ( const CVector<short>& vecsAudio );
|
||||
double MicLeveldBLeft() { return CalcLogResult ( dCurLevelL ); }
|
||||
double MicLeveldBRight() { return CalcLogResult ( dCurLevelR ); }
|
||||
static double CalcLogResult ( const double& dLinearLevel );
|
||||
static double CalcLogResult ( const double& dLinearLevel );
|
||||
|
||||
void Reset()
|
||||
{
|
||||
|
@ -761,9 +762,10 @@ public:
|
|||
static int GetNotUsedInstrument() { return 0; }
|
||||
static bool IsNotUsedInstrument ( const int iInstrument ) { return iInstrument == 0; }
|
||||
|
||||
static int GetNumAvailableInst() { return GetTable().Size(); }
|
||||
static QString GetResourceReference ( const int iInstrument );
|
||||
static QString GetName ( const int iInstrument );
|
||||
static int GetNumAvailableInst() { return GetTable().Size(); }
|
||||
static QString GetResourceReference ( const int iInstrument );
|
||||
static QString GetName ( const int iInstrument );
|
||||
static EInstCategory GetCategory ( const int iInstrument );
|
||||
|
||||
// TODO make use of instrument category (not yet implemented)
|
||||
|
||||
|
|
|
@ -483,11 +483,12 @@ void CSound::Stop()
|
|||
}
|
||||
}
|
||||
|
||||
CSound::CSound ( void (*fpNewCallback) ( CVector<int16_t>& psData, void* arg ),
|
||||
void* arg,
|
||||
const int iCtrlMIDIChannel,
|
||||
const bool bNoAutoJackConnect) :
|
||||
CSoundBase ( "ASIO", true, fpNewCallback, arg, iCtrlMIDIChannel, bNoAutoJackConnect ),
|
||||
CSound::CSound ( void (*fpNewCallback) ( CVector<int16_t>& psData, void* arg ),
|
||||
void* arg,
|
||||
const int iCtrlMIDIChannel,
|
||||
const bool ,
|
||||
const QString& ) :
|
||||
CSoundBase ( "ASIO", true, fpNewCallback, arg, iCtrlMIDIChannel ),
|
||||
lNumInChan ( 0 ),
|
||||
lNumInChanPlusAddChan ( 0 ),
|
||||
lNumOutChan ( 0 ),
|
||||
|
@ -514,9 +515,9 @@ CSound::CSound ( void (*fpNewCallback) ( CVector<int16_t>& psData, void* a
|
|||
// in case we do not have a driver available, throw error
|
||||
if ( lNumDevs == 0 )
|
||||
{
|
||||
throw CGenErr ( tr ( "<b>No ASIO audio device (driver) found.</b><br><br>"
|
||||
"The " ) + APP_NAME + tr ( " software requires the low latency audio "
|
||||
"interface <b>ASIO</b> to work properly. This is no standard "
|
||||
throw CGenErr ( "<b>" + tr ( "No ASIO audio device (driver) found." ) + "</b><br><br>" +
|
||||
tr ( "The " ) + APP_NAME + tr ( " software requires the low latency audio "
|
||||
"interface ASIO to work properly. This is no standard "
|
||||
"Windows audio interface and therefore a special audio driver is "
|
||||
"required. Either your sound card has a native ASIO driver (which "
|
||||
"is recommended) or you might want to use alternative drivers like "
|
||||
|
|
|
@ -46,10 +46,12 @@
|
|||
class CSound : public CSoundBase
|
||||
{
|
||||
public:
|
||||
CSound ( void (*fpNewCallback) ( CVector<int16_t>& psData, void* arg ),
|
||||
void* arg,
|
||||
const int iCtrlMIDIChannel,
|
||||
const bool bNoAutoJackConnect );
|
||||
CSound ( void (*fpNewCallback) ( CVector<int16_t>& psData, void* arg ),
|
||||
void* arg,
|
||||
const int iCtrlMIDIChannel,
|
||||
const bool ,
|
||||
const QString& );
|
||||
|
||||
virtual ~CSound() { UnloadCurrentDriver(); }
|
||||
|
||||
virtual int Init ( const int iNewPrefMonoBufferSize );
|
||||
|
@ -85,28 +87,6 @@ protected:
|
|||
bool CheckSampleTypeSupportedForCHMixing ( const ASIOSampleType SamType );
|
||||
void ResetChannelMapping();
|
||||
|
||||
static void GetSelCHAndAddCH ( const int iSelCH, const int iNumInChan,
|
||||
int& iSelCHOut, int& iSelAddCHOut )
|
||||
{
|
||||
// we have a mixed channel setup
|
||||
// definitions:
|
||||
// - mixed channel setup only for 4 physical inputs:
|
||||
// SelCH == 4: Ch 0 + Ch 2
|
||||
// SelCh == 5: Ch 0 + Ch 3
|
||||
// SelCh == 6: Ch 1 + Ch 2
|
||||
// SelCh == 7: Ch 1 + Ch 3
|
||||
if ( iSelCH >= iNumInChan )
|
||||
{
|
||||
iSelAddCHOut = ( ( iSelCH - iNumInChan ) % 2 ) + 2;
|
||||
iSelCHOut = ( iSelCH - iNumInChan ) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
iSelAddCHOut = -1;
|
||||
iSelCHOut = iSelCH;
|
||||
}
|
||||
}
|
||||
|
||||
int iASIOBufferSizeMono;
|
||||
int iASIOBufferSizeStereo;
|
||||
|
||||
|
|