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
- 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)
@ -24,6 +24,8 @@
TODO WIP support internationalization
TODO improve disconnect message behaviour on client
TODO implement panning for channels (Ticket #52, #145)
TODO show mute state of others

View File

@ -128,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
@ -492,6 +619,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 \
@ -581,6 +714,8 @@ DISTFILES += ChangeLog \
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 \

View File

@ -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
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
*
* Author(s):
* Volker Fischer
* Simon Tomlinson
*
******************************************************************************
*
@ -23,256 +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 ,
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 );
@ -283,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"
@ -296,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";
}

View File

@ -2,7 +2,7 @@
* Copyright (c) 2004-2020
*
* Author(s):
* Volker Fischer
* Simon Tomlinson
*
******************************************************************************
*
@ -24,15 +24,18 @@
#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 ),
@ -46,10 +49,30 @@ public:
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;
@ -57,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;

1
libs/oboe Submodule

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

View File

@ -117,7 +117,7 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
// reverberation level
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 mone channel selection and the "
"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 "

View File

@ -258,6 +258,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;

View File

@ -33,12 +33,16 @@
#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;
@ -60,6 +64,7 @@ int main ( int argc, char** argv )
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;
@ -77,13 +82,6 @@ int main ( int argc, char** argv )
QString strWelcomeMessage = "";
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
// argument and argv()[argc()-1] is the last argument.
// Start with first argument, therefore "i = 1"
@ -312,7 +310,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;
}
@ -507,17 +506,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 );

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>
<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>
</message>
<message>
@ -1856,6 +1856,11 @@
<source>Congas</source>
<translation>Congas</translation>
</message>
<message>
<location filename="../../util.cpp" line="1002"/>
<source>Bongo</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<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>
<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>
<location filename="../../../android/sound.cpp" line="137"/>
<source>Error closing stream: $s</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>CSoundBase</name>

File diff suppressed because it is too large Load Diff

View File

@ -562,7 +562,7 @@
</message>
<message>
<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>
</message>
<message>
@ -1864,6 +1864,11 @@
<source>Congas</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../util.cpp" line="1002"/>
<source>Bongo</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<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>
<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>
<location filename="../../../android/sound.cpp" line="137"/>
<source>Error closing stream: $s</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>CSoundBase</name>

View File

@ -67,6 +67,7 @@
<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>

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", "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;