Merge pull request #4 from corrados/master

update fork
This commit is contained in:
ignotus 2020-05-12 09:53:48 +02:00 committed by GitHub
commit ebe4867b2c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 1127 additions and 710 deletions

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "libs/oboe"]
path = libs/oboe
url = https://github.com/google/oboe.git

View file

@ -7,7 +7,7 @@
- for CoreAudio and 4 channel input, support mixing channels 1&2 with 3&4 - for CoreAudio and 4 channel input, support mixing channels 1&2 with 3&4
- added bassoon/oboe/harp instrument icons created by dszgit; congas created by bspeer (Ticket #131) - 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) - link to docs from application Help menu (Ticket #90)
@ -24,6 +24,8 @@
TODO WIP support internationalization TODO WIP support internationalization
TODO improve disconnect message behaviour on client
TODO implement panning for channels (Ticket #52, #145) TODO implement panning for channels (Ticket #52, #145)
TODO show mute state of others TODO show mute state of others

View file

@ -128,11 +128,138 @@ win32 {
LIBS += /usr/local/lib/libjack.dylib LIBS += /usr/local/lib/libjack.dylib
} }
} else:android { } 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 HEADERS += android/sound.h
SOURCES += android/sound.cpp SOURCES += android/sound.cpp \
android/androiddebug.cpp
LIBS += -lOpenSLES LIBS += -lOpenSLES
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
OTHER_FILES += android/AndroidManifest.xml 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 { } else:unix {
# we want to compile with C++11 # we want to compile with C++11
QMAKE_CXXFLAGS += -std=c++11 QMAKE_CXXFLAGS += -std=c++11
@ -492,6 +619,12 @@ DISTFILES += ChangeLog \
COPYING \ COPYING \
INSTALL.md \ INSTALL.md \
README.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/CLEDBlack.png \
src/res/CLEDBlackSmall.png \ src/res/CLEDBlackSmall.png \
src/res/CLEDDisabledSmall.png \ src/res/CLEDDisabledSmall.png \
@ -581,6 +714,8 @@ DISTFILES += ChangeLog \
src/res/instruments/viola.png \ src/res/instruments/viola.png \
src/res/instruments/congas.svg \ src/res/instruments/congas.svg \
src/res/instruments/congas.png \ src/res/instruments/congas.png \
src/res/instruments/bongo.svg \
src/res/instruments/bongo.png \
src/res/flags/flagnone.png \ src/res/flags/flagnone.png \
src/res/flags/ad.png \ src/res/flags/ad.png \
src/res/flags/ae.png \ src/res/flags/ae.png \

View file

@ -1,41 +1,94 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version="1.0"?>
<manifest android:versionName="1.0" android:installLocation="auto" package="org.qtproject.jamulus" android:versionCode="1" xmlns:android="http://schemas.android.com/apk/res/android"> <manifest package="org.qtproject.jamulus" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" android:versionCode="1" android:installLocation="auto">
<application android:label="Jamulus" android:name="org.qtproject.qt5.android.bindings.QtApplication"> <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/>
<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">
<!-- 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> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter> </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"/> <!-- Application arguments -->
<meta-data android:value="default" android:name="android.app.repository"/> <!-- meta-data android:name="android.app.arguments" android:value="arg1 arg2 arg3"/ -->
<meta-data android:resource="@array/qt_libs" android:name="android.app.qt_libs_resource_id"/> <!-- Application arguments -->
<meta-data android:resource="@array/bundled_libs" android:name="android.app.bundled_libs_resource_id"/>
<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 --> <!-- 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:name="android.app.bundle_local_qt_libs" android:value="-- %%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"/>
<!-- Run with local libs --> <!-- Run with local libs -->
<meta-data android:value="-- %%USE_LOCAL_QT_LIBS%% --" android:name="android.app.use_local_qt_libs"/> <meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
<meta-data android:value="/data/local/tmp/qt/" android:name="android.app.libs_prefix"/> <meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
<meta-data android:value="-- %%INSERT_LOCAL_LIBS%% --" android:name="android.app.load_local_libs"/> <meta-data android:name="android.app.load_local_libs_resource_id" android:resource="@array/load_local_libs"/>
<meta-data android:value="-- %%INSERT_LOCAL_JARS%% --" android:name="android.app.load_local_jars"/> <meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
<meta-data android:value="-- %%INSERT_INIT_CLASSES%% --" android:name="android.app.static_init_classes"/> <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 --> <!-- 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_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/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/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 --> <!-- Messages maps -->
<!-- Splash screen --> <!-- 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 --> <!-- 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> </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> </manifest>

45
android/androiddebug.cpp Normal file
View 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

View file

@ -2,7 +2,7 @@
* Copyright (c) 2004-2020 * Copyright (c) 2004-2020
* *
* Author(s): * Author(s):
* Volker Fischer * Simon Tomlinson
* *
****************************************************************************** ******************************************************************************
* *
@ -23,256 +23,157 @@
\******************************************************************************/ \******************************************************************************/
#include "sound.h" #include "sound.h"
#include "androiddebug.cpp"
/* Implementation *************************************************************/ /* Implementation *************************************************************/
CSound::CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, void* arg ), CSound::CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, void* arg ),
void* arg, void* arg,
const int iCtrlMIDIChannel, const int iCtrlMIDIChannel,
const bool , const bool ,
const QString& ) : const QString& ) :
CSoundBase ( "OpenSL", true, fpNewProcessCallback, arg, iCtrlMIDIChannel ) 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() void CSound::warnIfNotLowLatency(oboe::ManagedStream &stream, QString streamName) {
{ if (stream->getPerformanceMode() != oboe::PerformanceMode::LowLatency) {
// set up stream formats for input and output QString latencyMode = (stream->getPerformanceMode()==oboe::PerformanceMode::None ? "None" : "Power Saving");
SLDataFormat_PCM inStreamFormat; // throw CGenErr ( tr ( "Stream is NOT low latency."
inStreamFormat.formatType = SL_DATAFORMAT_PCM; // "Check your requested format, sample rate and channel count." ) );
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::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 // clean up
(*recorderObject)->Destroy ( recorderObject ); closeStream(mRecordingStream);
(*playerObject)->Destroy ( playerObject ); closeStream(mPlayStream);
(*outputMixObject)->Destroy ( outputMixObject );
(*engineObject)->Destroy ( engineObject );
} }
void CSound::Start() void CSound::Start()
{ {
InitializeOpenSL(); openStreams();
// 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 );
// call base class // call base class
CSoundBase::Start(); CSoundBase::Start();
// finally start the streams so the callback begins, start with inputstream first.
mRecordingStream->requestStart();
mPlayStream->requestStart();
} }
void CSound::Stop() void CSound::Stop()
{ {
// stop the audio stream closeStreams();
(*recorder)->SetRecordState ( recorder, SL_RECORDSTATE_STOPPED );
(*player)->SetPlayState ( player, SL_PLAYSTATE_STOPPED );
// clear the buffers
(*recorderSimpleBufQueue)->Clear ( recorderSimpleBufQueue );
(*playerSimpleBufQueue)->Clear ( playerSimpleBufQueue );
// call base class // call base class
CSoundBase::Stop(); CSoundBase::Stop();
CloseOpenSL();
} }
int CSound::Init ( const int iNewPrefMonoBufferSize ) 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 // store buffer size
iOpenSLBufferSizeMono = iNewPrefMonoBufferSize; iOpenSLBufferSizeMono = 512 ;
//iNewPrefMonoBufferSize;
// init base class // init base class
CSoundBase::Init ( iOpenSLBufferSizeMono ); CSoundBase::Init ( iOpenSLBufferSizeMono );
@ -283,7 +184,6 @@ SLAudioIODeviceCapabilitiesItf audioCapabilities;
// create memory for intermediate audio buffer // create memory for intermediate audio buffer
vecsTmpAudioSndCrdStereo.Init ( iOpenSLBufferSizeStereo ); vecsTmpAudioSndCrdStereo.Init ( iOpenSLBufferSizeStereo );
// TEST // TEST
#if ( SYSTEM_SAMPLE_RATE_HZ != 48000 ) #if ( SYSTEM_SAMPLE_RATE_HZ != 48000 )
# error "Only a system sample rate of 48 kHz is supported by this module" # error "Only a system sample rate of 48 kHz is supported by this module"
@ -296,57 +196,105 @@ SLAudioIODeviceCapabilitiesItf audioCapabilities;
iModifiedInBufSize = iOpenSLBufferSizeMono / 3; iModifiedInBufSize = iOpenSLBufferSizeMono / 3;
vecsTmpAudioInSndCrd.Init ( iModifiedInBufSize ); vecsTmpAudioInSndCrd.Init ( iModifiedInBufSize );
return iOpenSLBufferSizeMono; return iOpenSLBufferSizeMono;
} }
void CSound::processInput ( SLAndroidSimpleBufferQueueItf bufferQueue, // This is the main callback method for when an audio stream is ready to publish data to an output stream
void* instance ) // 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 // Need to modify the size of the buffer based on the numFrames requested in this callback.
if ( !pSound->bRun ) // 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());
}
} }
else if (oboeStream == pSound->mRecordingStream.get() && audioData)
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 )
{ {
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 );
} }
// locker.unlock();
QMutexLocker locker ( &pSound->Mutex ); return oboe::DataCallbackResult::Continue;
// call processing callback function
pSound->ProcessCallback ( pSound->vecsTmpAudioSndCrdStereo );
// enqueue the buffer for playback
(*bufferQueue)->Enqueue ( bufferQueue,
&pSound->vecsTmpAudioSndCrdStereo[0],
pSound->iOpenSLBufferSizeStereo * 2 /* 2 bytes */ );
} }
//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";
}

View file

@ -2,7 +2,7 @@
* Copyright (c) 2004-2020 * Copyright (c) 2004-2020
* *
* Author(s): * Author(s):
* Volker Fischer * Simon Tomlinson
* *
****************************************************************************** ******************************************************************************
* *
@ -24,15 +24,18 @@
#pragma once #pragma once
#include <SLES/OpenSLES.h> /* Deprecated, moving to OBOE
#include <SLES/OpenSLES_Android.h> * #include <SLES/OpenSLES.h>
* #include <SLES/OpenSLES_Android.h> */
#include <oboe/Oboe.h>
#include <QMutex> #include <QMutex>
#include "soundbase.h" #include "soundbase.h"
#include "global.h" #include "global.h"
#include <QDebug>
#include <android/log.h>
/* Classes ********************************************************************/ /* Classes ********************************************************************/
class CSound : public CSoundBase class CSound : public CSoundBase, public oboe::AudioStreamCallback//, public IRenderableAudio, public IRestartable
{ {
public: public:
CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, void* arg ), CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, void* arg ),
@ -46,10 +49,30 @@ public:
virtual void Start(); virtual void Start();
virtual void Stop(); 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 // these variables should be protected but cannot since we want
// to access them from the callback function // to access them from the callback function
CVector<short> vecsTmpAudioSndCrdStereo; 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 // TEST
CVector<short> vecsTmpAudioInSndCrd; CVector<short> vecsTmpAudioInSndCrd;
int iModifiedInBufSize; int iModifiedInBufSize;
@ -57,27 +80,25 @@ int iModifiedInBufSize;
int iOpenSLBufferSizeMono; int iOpenSLBufferSizeMono;
int iOpenSLBufferSizeStereo; 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(); oboe::ManagedStream mRecordingStream;
void CloseOpenSL(); oboe::ManagedStream mPlayStream;
AudioStreamCallback *mCallback;
// callbacks // used to reach a state where the input buffer is
static void processInput ( SLAndroidSimpleBufferQueueItf bufferQueue, // empty and the garbage in the first 500ms or so is discarded
void* instance ); static constexpr int32_t kNumCallbacksToDrain = 10;
int32_t mCountCallbacksToDrain = kNumCallbacksToDrain;
static void processOutput ( SLAndroidSimpleBufferQueueItf bufferQueue, // Used to reference this instance of class from within the static callback
void* instance ); CSound *pSound;
SLObjectItf engineObject;
SLEngineItf engine;
SLObjectItf recorderObject;
SLRecordItf recorder;
SLAndroidSimpleBufferQueueItf recorderSimpleBufQueue;
SLObjectItf outputMixObject;
SLObjectItf playerObject;
SLPlayItf player;
SLAndroidSimpleBufferQueueItf playerSimpleBufQueue;
QMutex Mutex; QMutex Mutex;

1
libs/oboe Submodule

@ -0,0 +1 @@
Subproject commit 55d878a4e85e1994f2b5883366079b991500a25f

View file

@ -117,7 +117,7 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
// reverberation level // reverberation level
QString strAudReverb = "<b>" + tr ( "Reverberation Level" ) + ":</b> " + QString strAudReverb = "<b>" + tr ( "Reverberation Level" ) + ":</b> " +
tr ( "A reverberation effect can be applied to one local mono audio channel or to both " tr ( "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 " "channels in stereo mode. The mono channel selection and the "
"reverberation level can be modified. If, e.g., " "reverberation level can be modified. If, e.g., "
"the microphone signal is fed into the right audio channel of the " "the microphone signal is fed into the right audio channel of the "
"sound card and a reverberation effect shall be applied, set the " "sound card and a reverberation effect shall be applied, set the "

View file

@ -258,6 +258,8 @@ typedef unsigned __int64 uint64_t;
typedef unsigned __int32 uint32_t; typedef unsigned __int32 uint32_t;
typedef unsigned __int16 uint16_t; typedef unsigned __int16 uint16_t;
typedef unsigned __int8 uint8_t; typedef unsigned __int8 uint8_t;
#elif defined ( ANDROID )
// don't redfine types for android as these ones below don't work
#else #else
typedef long long int64_t; typedef long long int64_t;
typedef int int32_t; typedef int int32_t;

View file

@ -33,12 +33,16 @@
#include "settings.h" #include "settings.h"
#include "testbench.h" #include "testbench.h"
#include "util.h" #include "util.h"
#ifdef ANDROID
# include <QtAndroidExtras/QtAndroid>
#endif
// Implementation ************************************************************** // Implementation **************************************************************
int main ( int argc, char** argv ) int main ( int argc, char** argv )
{ {
QTextStream& tsConsole = *( ( new ConsoleWriterFactory() )->get() ); QTextStream& tsConsole = *( ( new ConsoleWriterFactory() )->get() );
QString strArgument; QString strArgument;
double rDbleArgument; double rDbleArgument;
@ -60,6 +64,7 @@ int main ( int argc, char** argv )
bool bCentServPingServerInList = false; bool bCentServPingServerInList = false;
bool bNoAutoJackConnect = false; bool bNoAutoJackConnect = false;
bool bUseTranslation = true; bool bUseTranslation = true;
bool bCustomPortNumberGiven = false;
int iNumServerChannels = DEFAULT_USED_NUM_CHANNELS; int iNumServerChannels = DEFAULT_USED_NUM_CHANNELS;
int iMaxDaysHistory = DEFAULT_DAYS_HISTORY; int iMaxDaysHistory = DEFAULT_DAYS_HISTORY;
int iCtrlMIDIChannel = INVALID_MIDI_CH; int iCtrlMIDIChannel = INVALID_MIDI_CH;
@ -77,13 +82,6 @@ int main ( int argc, char** argv )
QString strWelcomeMessage = ""; QString strWelcomeMessage = "";
QString strClientName = APP_NAME; QString strClientName = APP_NAME;
// 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 )
{
iPortNumber += 10; // increment by 10
}
// QT docu: argv()[0] is the program name, argv()[1] is the first // QT docu: argv()[0] is the program name, argv()[1] is the first
// argument and argv()[argc()-1] is the last argument. // argument and argv()[argc()-1] is the last argument.
// Start with first argument, therefore "i = 1" // Start with first argument, therefore "i = 1"
@ -312,7 +310,8 @@ int main ( int argc, char** argv )
65535, 65535,
rDbleArgument ) ) rDbleArgument ) )
{ {
iPortNumber = static_cast<quint16> ( rDbleArgument ); iPortNumber = static_cast<quint16> ( rDbleArgument );
bCustomPortNumberGiven = true;
tsConsole << "- selected port number: " << iPortNumber << endl; tsConsole << "- selected port number: " << iPortNumber << endl;
continue; continue;
} }
@ -507,17 +506,41 @@ int main ( int argc, char** argv )
strCentralServer = DEFAULT_SERVER_ADDRESS; 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 --------------------------------------------------- // display a warning if in server no GUI mode and a history file is requested
// Application object if ( !bIsClient && !bUseGUI && !strHistoryFileName.isEmpty() )
if ( !bUseGUI && !strHistoryFileName.isEmpty() )
{ {
tsConsole << "Qt5 requires a windowing system to paint a JPEG image; image will use SVG" << endl; tsConsole << "Qt5 requires a windowing system to paint a JPEG image; image will use SVG" << endl;
} }
// Application/GUI setup ---------------------------------------------------
// Application object
QCoreApplication* pApp = bUseGUI QCoreApplication* pApp = bUseGUI
? new QApplication ( argc, argv ) ? new QApplication ( argc, argv )
: new QCoreApplication ( 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 #ifdef _WIN32
// set application priority class -> high priority // set application priority class -> high priority
SetPriorityClass ( GetCurrentProcess(), HIGH_PRIORITY_CLASS ); SetPriorityClass ( GetCurrentProcess(), HIGH_PRIORITY_CLASS );

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View 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

File diff suppressed because it is too large Load diff

View file

@ -554,7 +554,7 @@
</message> </message>
<message> <message>
<location filename="../../clientdlg.cpp" line="119"/> <location filename="../../clientdlg.cpp" line="119"/>
<source>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 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.</source> <source>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.</source>
<translation>Se puede aplicar un efecto de reverberación a un canal local de audio mono o a ambos canales en modo estéreo. Se puede modificar la selección de canales en modo mono y el nivel de reverberación. Por ej., si la señal del micrófono va por el canal derecho de la tarjeta de sonido y se desea aplicar reverberación, cambia el selector de canal a derecho y sube el fader hasta alcanzar el nivel de reverberación deseado.</translation> <translation>Se puede aplicar un efecto de reverberación a un canal local de audio mono o a ambos canales en modo estéreo. Se puede modificar la selección de canales en modo mono y el nivel de reverberación. Por ej., si la señal del micrófono va por el canal derecho de la tarjeta de sonido y se desea aplicar reverberación, cambia el selector de canal a derecho y sube el fader hasta alcanzar el nivel de reverberación deseado.</translation>
</message> </message>
<message> <message>
@ -1856,6 +1856,11 @@
<source>Congas</source> <source>Congas</source>
<translation>Congas</translation> <translation>Congas</translation>
</message> </message>
<message>
<location filename="../../util.cpp" line="1002"/>
<source>Bongo</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>CServerDlg</name> <name>CServerDlg</name>
@ -2276,6 +2281,11 @@
<source> 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 the ASIO4All driver.</source> <source> 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 the ASIO4All driver.</source>
<translation> requiere la interfaz de audio de baja latencia ASIO para funcionar correctamente. No es una interfaz estándar de Windows y por tanto se requiere un driver de audio especial. Tu tarjeta de audio podría tener un driver ASIO nativo (lo recomendado) o quizá quieras probar un driver alternativo como ASIO4All.</translation> <translation> requiere la interfaz de audio de baja latencia ASIO para funcionar correctamente. No es una interfaz estándar de Windows y por tanto se requiere un driver de audio especial. Tu tarjeta de audio podría tener un driver ASIO nativo (lo recomendado) o quizá quieras probar un driver alternativo como ASIO4All.</translation>
</message> </message>
<message>
<location filename="../../../android/sound.cpp" line="137"/>
<source>Error closing stream: $s</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>CSoundBase</name> <name>CSoundBase</name>

File diff suppressed because it is too large Load diff

View file

@ -562,7 +562,7 @@
</message> </message>
<message> <message>
<location filename="../../clientdlg.cpp" line="119"/> <location filename="../../clientdlg.cpp" line="119"/>
<source>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 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.</source> <source>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.</source>
<translation>Um efeito de reverberação pode ser aplicado a um canal local de áudio mono ou a ambos os canais no modo estéreo. A seleção do canal mono e o nível de reverberação podem ser modificados. Se, por exemplo, o sinal do microfone for alimentado no canal de áudio direito da placa de som, e for aplicado um efeito de reverberação, ajuste o seletor de canal para a direita e mova o fader para cima até que o nível de reverberação desejado seja atingido.</translation> <translation>Um efeito de reverberação pode ser aplicado a um canal local de áudio mono ou a ambos os canais no modo estéreo. A seleção do canal mono e o nível de reverberação podem ser modificados. Se, por exemplo, o sinal do microfone for alimentado no canal de áudio direito da placa de som, e for aplicado um efeito de reverberação, ajuste o seletor de canal para a direita e mova o fader para cima até que o nível de reverberação desejado seja atingido.</translation>
</message> </message>
<message> <message>
@ -1864,6 +1864,11 @@
<source>Congas</source> <source>Congas</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<location filename="../../util.cpp" line="1002"/>
<source>Bongo</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>CServerDlg</name> <name>CServerDlg</name>
@ -2284,6 +2289,11 @@
<source> 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 the ASIO4All driver.</source> <source> 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 the ASIO4All driver.</source>
<translation> requer que a interface de áudio de baixa latência ASIO funcione corretamente. Esta não é uma interface de áudio padrão do Windows e, portanto, é necessário um driver de áudio especial. Ou a sua placa de som possui um driver ASIO nativo (recomendado), ou pode usar drivers alternativos, como o driver ASIO4All.</translation> <translation> requer que a interface de áudio de baixa latência ASIO funcione corretamente. Esta não é uma interface de áudio padrão do Windows e, portanto, é necessário um driver de áudio especial. Ou a sua placa de som possui um driver ASIO nativo (recomendado), ou pode usar drivers alternativos, como o driver ASIO4All.</translation>
</message> </message>
<message>
<location filename="../../../android/sound.cpp" line="137"/>
<source>Error closing stream: $s</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>CSoundBase</name> <name>CSoundBase</name>

View file

@ -67,6 +67,7 @@
<file>res/instruments/harp.png</file> <file>res/instruments/harp.png</file>
<file>res/instruments/viola.png</file> <file>res/instruments/viola.png</file>
<file>res/instruments/congas.png</file> <file>res/instruments/congas.png</file>
<file>res/instruments/bongo.png</file>
</qresource> </qresource>
<qresource prefix="/png/main"> <qresource prefix="/png/main">
<file>res/fronticon.png</file> <file>res/fronticon.png</file>

View file

@ -999,6 +999,7 @@ CVector<CInstPictures::CInstPictProps>& CInstPictures::GetTable()
vecDataBase.Add ( CInstPictProps ( QCoreApplication::translate ( "CMusProfDlg", "Harp" ), ":/png/instr/res/instruments/harp.png", IC_STRING_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", "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", "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 // now the table is initialized
TableIsInitialized = true; TableIsInitialized = true;