From 92481baa2f428b372be71c2de98ae7d883be36bf Mon Sep 17 00:00:00 2001
From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com>
Date: Fri, 17 Jul 2026 15:14:31 +0200
Subject: [PATCH 1/4] Use MVerb by Martin Eastwood for reverberation
Add reverb preset selection to advanced settings dialogue
make "Stadium" the default reverb preset
Make reverb buffers protected members
Add reverb presets
---
.gitmodules | 3 +
Jamulus.pro | 5 +-
libs/mverb | 1 +
src/client.cpp | 2 +-
src/client.h | 8 +-
src/clientsettingsdlg.cpp | 27 +++++
src/clientsettingsdlg.h | 1 +
src/clientsettingsdlgbase.ui | 197 ++++++++++++++++----------------
src/plugins/audioreverb.cpp | 211 ++++++-----------------------------
src/plugins/audioreverb.h | 91 +++++++++------
src/settings.cpp | 9 ++
11 files changed, 237 insertions(+), 318 deletions(-)
create mode 160000 libs/mverb
diff --git a/.gitmodules b/.gitmodules
index 819ad73047..f61a791095 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,6 @@
[submodule "libs/oboe"]
path = libs/oboe
url = ../../google/oboe.git
+[submodule "libs/mverb"]
+ path = libs/mverb
+ url = https://github.com/martineastwood/mverb.git
diff --git a/Jamulus.pro b/Jamulus.pro
index 575c329732..aff8433f42 100644
--- a/Jamulus.pro
+++ b/Jamulus.pro
@@ -90,6 +90,8 @@ DEFINES += APP_VERSION=\\\"$$VERSION\\\" \
DEFINES += QT_NO_DEPRECATED_WARNINGS
win32 {
+ # fixes error C7525: inline variables require at least '/std:c++17'
+ CONFIG += c++17
DEFINES -= UNICODE # fixes issue with ASIO SDK (asiolist.cpp is not unicode compatible)
DEFINES += NOMINMAX # solves a compiler error in qdatetime.h (Qt5)
RC_FILE = src/res/win-mainicon.rc
@@ -403,7 +405,8 @@ HEADERS += src/plugins/audioreverb.h \
src/recorder/jamrecorder.h \
src/recorder/creaperproject.h \
src/recorder/cwavestream.h \
- src/signalhandler.h
+ src/signalhandler.h \
+ libs/mverb/MVerb.h
!contains(CONFIG, "serveronly") {
HEADERS += src/client.h \
diff --git a/libs/mverb b/libs/mverb
new file mode 160000
index 0000000000..9f9512e9d9
--- /dev/null
+++ b/libs/mverb
@@ -0,0 +1 @@
+Subproject commit 9f9512e9d990fcf265e00fc7c2ee47ad20c8019f
diff --git a/src/client.cpp b/src/client.cpp
index 6ee048a863..3cde8158bb 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -1369,7 +1369,7 @@ void CClient::Init()
Channel.SetAudioStreamProperties ( eAudioCompressionType, iCeltNumCodedBytes, iSndCrdFrameSizeFactor, iNumAudioChannels );
// init reverberation
- AudioReverb.Init ( eAudioChannelConf, iStereoBlockSizeSam, SYSTEM_SAMPLE_RATE_HZ );
+ AudioReverb.Init ( eAudioChannelConf, iStereoBlockSizeSam );
// init the sound card conversion buffers
if ( bSndCrdConversionBufferRequired )
diff --git a/src/client.h b/src/client.h
index b56e5c42d1..ebfebae545 100644
--- a/src/client.h
+++ b/src/client.h
@@ -190,14 +190,12 @@ class CClient : public QObject
void SetAudioInFader ( const int iNV ) { iAudioInFader = iNV; }
int GetReverbLevel() const { return iReverbLevel; }
+ int GetReverbPreset() const { return AudioReverb.getPreset(); }
void SetReverbLevel ( const int iNL ) { iReverbLevel = iNL; }
+ void SetReverbPreset ( const int iNP ) { AudioReverb.setPreset ( iNP ); }
bool IsReverbOnLeftChan() const { return bReverbOnLeftChan; }
- void SetReverbOnLeftChan ( const bool bIL )
- {
- bReverbOnLeftChan = bIL;
- AudioReverb.Clear();
- }
+ void SetReverbOnLeftChan ( const bool bIL ) { bReverbOnLeftChan = bIL; }
void SetDoAutoSockBufSize ( const bool bValue );
bool GetDoAutoSockBufSize() const { return Channel.GetDoAutoSockBufSize(); }
diff --git a/src/clientsettingsdlg.cpp b/src/clientsettingsdlg.cpp
index ad92a0f8e1..9932023a42 100644
--- a/src/clientsettingsdlg.cpp
+++ b/src/clientsettingsdlg.cpp
@@ -380,6 +380,15 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, CClientSettings* pNSet
cbxInputBoost->setWhatsThis ( strInputBoost );
cbxInputBoost->setAccessibleName ( tr ( "Input Boost combo box" ) );
+ // reverb preset
+ QString strReverbPreset = "" + tr ( "Reverb Preset" ) + ": " +
+ tr ( "Jamulus uses MVerb by Martin Eastwood for reverberation. "
+ "MVerb comes with a set of presets you can select here. "
+ "Available Presets: Subtle, Stadium, Cupboard, Dark, Halves " );
+ lblInputBoost->setWhatsThis ( strReverbPreset );
+ cbxInputBoost->setWhatsThis ( strReverbPreset );
+ cbxInputBoost->setAccessibleName ( tr ( "Reverb Preset combo box" ) );
+
// custom directories
QString strCustomDirectories = "" + tr ( "Custom Directories" ) + ": " +
tr ( "If you need to add additional directories to the Connect dialog Directory drop down, "
@@ -555,6 +564,17 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, CClientSettings* pNSet
// factor is 1-based while index is 0-based:
cbxInputBoost->setCurrentIndex ( pSettings->iInputBoost - 1 );
+ // Rever Preset combo box
+ cbxReverbPreset->clear();
+ cbxReverbPreset->addItem ( "Subtle" );
+ cbxReverbPreset->addItem ( "Stadium" );
+ cbxReverbPreset->addItem ( "Cupboard" );
+ cbxReverbPreset->addItem ( "Dark" );
+ cbxReverbPreset->addItem ( "Halves" );
+ cbxReverbPreset->addItem ( "Drum Room" );
+ cbxReverbPreset->addItem ( "Club" );
+ cbxReverbPreset->setCurrentIndex ( pClient->GetReverbPreset() );
+
// init number of mixer rows
spnMixerRows->setValue ( pSettings->iNumMixerPanelRows );
@@ -786,6 +806,11 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, CClientSettings* pNSet
this,
&CClientSettingsDlg::OnInputBoostChanged );
+ QObject::connect ( cbxReverbPreset,
+ static_cast ( &QComboBox::activated ),
+ this,
+ &CClientSettingsDlg::OnReverbPresetChanged );
+
// buttons
#if defined( _WIN32 ) && !defined( WITH_JACK )
// Driver Setup button is only available for Windows when JACK is not used
@@ -1389,6 +1414,8 @@ void CClientSettingsDlg::OnInputBoostChanged()
pClient->SetInputBoost ( pSettings->iInputBoost );
}
+void CClientSettingsDlg::OnReverbPresetChanged() { pClient->SetReverbPreset ( cbxReverbPreset->currentIndex() ); }
+
void CClientSettingsDlg::OnAliasTextChanged ( const QString& strNewName )
{
// check length
diff --git a/src/clientsettingsdlg.h b/src/clientsettingsdlg.h
index 7844f64117..6564e21ca9 100644
--- a/src/clientsettingsdlg.h
+++ b/src/clientsettingsdlg.h
@@ -109,6 +109,7 @@ public slots:
void OnCustomDirectoriesChanged ( bool bDelete );
void OnNewClientLevelEditingFinished() { pSettings->iNewClientFaderLevel = edtNewClientLevel->text().toInt(); }
void OnInputBoostChanged();
+ void OnReverbPresetChanged();
void OnSndCrdBufferDelayButtonGroupClicked ( QAbstractButton* button );
void OnSoundcardActivated ( int iSndDevIdx );
void OnLInChanActivated ( int iChanIdx );
diff --git a/src/clientsettingsdlgbase.ui b/src/clientsettingsdlgbase.ui
index 842ab9220c..8e15b59077 100644
--- a/src/clientsettingsdlgbase.ui
+++ b/src/clientsettingsdlgbase.ui
@@ -7,7 +7,7 @@
0
0
534
- 591
+ 652
@@ -30,7 +30,7 @@
- 3
+ 2
true
@@ -45,7 +45,7 @@
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
@@ -60,10 +60,10 @@
-
- Qt::Vertical
+ Qt::Orientation::Vertical
- QSizePolicy::Preferred
+ QSizePolicy::Policy::Preferred
@@ -209,7 +209,7 @@
-
- Qt::Vertical
+ Qt::Orientation::Vertical
@@ -305,7 +305,7 @@
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+ Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter
1
@@ -332,7 +332,7 @@
-
- Qt::Vertical
+ Qt::Orientation::Vertical
@@ -347,7 +347,7 @@
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
@@ -399,10 +399,10 @@
-
- Qt::Vertical
+ Qt::Orientation::Vertical
- QSizePolicy::Expanding
+ QSizePolicy::Policy::Expanding
@@ -431,7 +431,7 @@
-
- Qt::Vertical
+ Qt::Orientation::Vertical
@@ -450,10 +450,10 @@
- QFrame::NoFrame
+ QFrame::Shape::NoFrame
- QFrame::Plain
+ QFrame::Shadow::Plain
@@ -600,10 +600,10 @@
-
- Qt::Vertical
+ Qt::Orientation::Vertical
- QSizePolicy::Expanding
+ QSizePolicy::Policy::Expanding
@@ -654,7 +654,7 @@
-
- Qt::Vertical
+ Qt::Orientation::Vertical
@@ -717,10 +717,10 @@
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
- QSizePolicy::MinimumExpanding
+ QSizePolicy::Policy::MinimumExpanding
@@ -759,7 +759,7 @@
Local
- Qt::AlignCenter
+ Qt::AlignmentFlag::AlignCenter
false
@@ -772,7 +772,7 @@
Server
- Qt::AlignCenter
+ Qt::AlignmentFlag::AlignCenter
false
@@ -789,7 +789,7 @@
Size
- Qt::AlignCenter
+ Qt::AlignmentFlag::AlignCenter
false
@@ -802,7 +802,7 @@
Size
- Qt::AlignCenter
+ Qt::AlignmentFlag::AlignCenter
false
@@ -816,10 +816,10 @@
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
- QSizePolicy::Minimum
+ QSizePolicy::Policy::Minimum
@@ -841,20 +841,20 @@
1
- Qt::Vertical
+ Qt::Orientation::Vertical
- QSlider::TicksBothSides
+ QSlider::TickPosition::TicksBothSides
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
- QSizePolicy::Minimum
+ QSizePolicy::Policy::Minimum
@@ -876,10 +876,10 @@
1
- Qt::Vertical
+ Qt::Orientation::Vertical
- QSlider::TicksBothSides
+ QSlider::TickPosition::TicksBothSides
@@ -915,7 +915,7 @@
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
@@ -931,7 +931,7 @@
kbps
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+ Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter
@@ -941,7 +941,7 @@
val
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+ Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter
2
@@ -951,7 +951,7 @@
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
@@ -971,10 +971,10 @@
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
- QSizePolicy::Minimum
+ QSizePolicy::Policy::Minimum
@@ -1000,7 +1000,7 @@
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
@@ -1015,10 +1015,10 @@
-
- Qt::Vertical
+ Qt::Orientation::Vertical
- QSizePolicy::MinimumExpanding
+ QSizePolicy::Policy::MinimumExpanding
@@ -1055,7 +1055,7 @@
-
- Qt::Vertical
+ Qt::Orientation::Vertical
@@ -1092,7 +1092,7 @@
-
- Qt::Vertical
+ Qt::Orientation::Vertical
@@ -1115,10 +1115,33 @@
-
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Reverb Preset
+
+
+
+ -
+
+
-
- Qt::Vertical
+ Qt::Orientation::Vertical
@@ -1144,7 +1167,7 @@
-
- Qt::Vertical
+ Qt::Orientation::Vertical
@@ -1159,7 +1182,7 @@
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
@@ -1176,10 +1199,10 @@
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
- QSizePolicy::Preferred
+ QSizePolicy::Policy::Preferred
@@ -1206,7 +1229,7 @@
Pan
- Qt::AlignCenter
+ Qt::AlignmentFlag::AlignCenter
sldAudioPan
@@ -1218,10 +1241,10 @@
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
- QSizePolicy::Minimum
+ QSizePolicy::Policy::Minimum
@@ -1252,20 +1275,20 @@
1
- Qt::Horizontal
+ Qt::Orientation::Horizontal
- QSlider::TicksBothSides
+ QSlider::TickPosition::TicksBothSides
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
- QSizePolicy::Minimum
+ QSizePolicy::Policy::Minimum
@@ -1289,7 +1312,7 @@
Center
- Qt::AlignCenter
+ Qt::AlignmentFlag::AlignCenter
false
@@ -1304,10 +1327,10 @@
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
- QSizePolicy::Preferred
+ QSizePolicy::Policy::Preferred
@@ -1324,7 +1347,7 @@
-
- Qt::Vertical
+ Qt::Orientation::Vertical
@@ -1383,7 +1406,6 @@
- 50
false
@@ -1408,7 +1430,6 @@
- 50
false
@@ -1502,7 +1523,7 @@
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
@@ -1522,7 +1543,7 @@
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
@@ -1538,7 +1559,6 @@
- 50
false
@@ -1561,7 +1581,6 @@
- 50
false
@@ -1580,7 +1599,6 @@
- 50
false
@@ -1596,7 +1614,6 @@
- 50
false
@@ -1611,7 +1628,7 @@
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
@@ -1629,7 +1646,7 @@
-
- Qt::Vertical
+ Qt::Orientation::Vertical
@@ -1642,7 +1659,7 @@
-
- Qt::Vertical
+ Qt::Orientation::Vertical
@@ -1657,7 +1674,7 @@
-
- Qt::Vertical
+ Qt::Orientation::Vertical
@@ -1671,7 +1688,6 @@
- 50
false
@@ -1694,7 +1710,6 @@
- 50
false
@@ -1713,7 +1728,6 @@
- 50
false
@@ -1726,7 +1740,6 @@
- 50
false
@@ -1741,7 +1754,7 @@
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
@@ -1755,7 +1768,6 @@
- 50
false
@@ -1774,7 +1786,6 @@
- 50
false
@@ -1795,7 +1806,6 @@
- 50
false
@@ -1818,7 +1828,6 @@
- 50
false
@@ -1837,7 +1846,6 @@
- 50
false
@@ -1850,7 +1858,6 @@
- 50
false
@@ -1865,7 +1872,7 @@
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
@@ -1879,7 +1886,6 @@
- 50
false
@@ -1898,7 +1904,6 @@
- 50
false
@@ -1918,7 +1923,7 @@
-
- Qt::Vertical
+ Qt::Orientation::Vertical
@@ -1932,7 +1937,6 @@
- 50
false
@@ -1955,7 +1959,6 @@
- 50
false
@@ -1974,7 +1977,6 @@
- 50
false
@@ -1987,7 +1989,6 @@
- 50
false
@@ -2002,7 +2003,7 @@
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
@@ -2016,7 +2017,6 @@
- 50
false
@@ -2035,7 +2035,6 @@
- 50
false
@@ -2056,7 +2055,6 @@
- 50
false
@@ -2079,7 +2077,6 @@
- 50
false
@@ -2098,7 +2095,6 @@
- 50
false
@@ -2111,7 +2107,6 @@
- 50
false
@@ -2126,7 +2121,7 @@
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
@@ -2140,7 +2135,6 @@
- 50
false
@@ -2159,7 +2153,6 @@
- 50
false
@@ -2179,7 +2172,7 @@
-
- Qt::Vertical
+ Qt::Orientation::Vertical
@@ -2213,7 +2206,7 @@
-
- Qt::Horizontal
+ Qt::Orientation::Horizontal
@@ -2228,7 +2221,7 @@
-
- Qt::Vertical
+ Qt::Orientation::Vertical
diff --git a/src/plugins/audioreverb.cpp b/src/plugins/audioreverb.cpp
index a10c415bb8..2e0a9885bb 100644
--- a/src/plugins/audioreverb.cpp
+++ b/src/plugins/audioreverb.cpp
@@ -2,206 +2,69 @@
* Audio Reverberation *
\******************************************************************************/
/*
- The following code is based on "JCRev: John Chowning's reverberator class"
- by Perry R. Cook and Gary P. Scavone, 1995 - 2004
- which is in "The Synthesis ToolKit in C++ (STK)"
- http://ccrma.stanford.edu/software/stk
-
- Original description:
- This class is derived from the CLM JCRev function, which is based on the use
- of networks of simple allpass and comb delay filters. This class implements
- three series allpass units, followed by four parallel comb filters, and two
- decorrelation delay lines in parallel at the output.
+ The following code calls MVerb for reverberation.
+ MVerb was written by Martin Eastwood.
+ https://github.com/martineastwood/mverb
*/
#include "audioreverb.h"
-void CAudioReverb::Init ( const EAudChanConf eNAudioChannelConf, const int iNStereoBlockSizeSam, const int iSampleRate, const float fT60 )
+void CAudioReverb::Init ( const EAudChanConf eNAudioChannelConf, const int iNStereoBlockSizeSam )
{
- // store parameters
eAudioChannelConf = eNAudioChannelConf;
iStereoBlockSizeSam = iNStereoBlockSizeSam;
- // delay lengths for 44100 Hz sample rate
- int lengths[9] = { 1116, 1356, 1422, 1617, 225, 341, 441, 211, 179 };
- const float scaler = static_cast ( iSampleRate ) / 44100.0f;
-
- if ( scaler != 1.0f )
- {
- for ( int i = 0; i < 9; i++ )
- {
- int delay = static_cast ( floorf ( scaler * lengths[i] ) );
+ // Jamulus uses interleaved stereo, mverb operates on a 2-dimensional array instead
+ // Calculate the number of frames for each channel ( iStereoBlockSizeSam / 2 )
+ numFrames = iStereoBlockSizeSam >> 1;
- if ( ( delay & 1 ) == 0 )
- {
- delay++;
- }
+ // These buffers get filled with dry signal and are then passed to mverb
+ // They need to be vectors as the windows builds fail when arrays are used
+ bufL.resize ( numFrames );
+ bufR.resize ( numFrames );
- while ( !isPrime ( delay ) )
- {
- delay += 2;
- }
-
- lengths[i] = delay;
- }
- }
-
- for ( int i = 0; i < 3; i++ )
- {
- allpassDelays[i].Init ( lengths[i + 4] );
- }
+ mverb->setSampleRate ( static_cast ( SYSTEM_SAMPLE_RATE_HZ ) );
+ loadPreset();
+}
- for ( int i = 0; i < 4; i++ )
+void CAudioReverb::loadPreset()
+{
+ for ( int i = 0; i < MVerb::NUM_PARAMS; i++ )
{
- combDelays[i].Init ( lengths[i] );
- combFilters[i].setPole ( 0.2f );
+ mverb->setParameter ( i, presets[iPreset][i] );
}
-
- setT60 ( fT60, iSampleRate );
- outLeftDelay.Init ( lengths[7] );
- outRightDelay.Init ( lengths[8] );
- allpassCoefficient = 0.7f;
- Clear();
}
-bool CAudioReverb::isPrime ( const int number )
+void CAudioReverb::Process ( CVector& vecsStereoInOut, const bool bReverbOnLeftChan, const float fReverbGain )
{
- /*
- Returns true if argument value is prime. Taken from "class Effect" in
- "STK abstract effects parent class".
- */
- if ( number == 2 )
- {
- return true;
- }
- if ( number & 1 )
+ // One buffer to pass to mverb's process function
+ float* fInput[2] = { bufL.data(), bufR.data() };
+
+ if ( eAudioChannelConf == CC_STEREO )
{
- for ( int i = 3; i < static_cast ( sqrtf ( static_cast ( number ) ) ) + 1; i += 2 )
+ for ( int i = 0, j = 0; j < numFrames; i += 2, j++ )
{
- if ( ( number % i ) == 0 )
- {
- return false;
- }
+ // True stereo reverb
+ bufL[j] = static_cast ( vecsStereoInOut[i] ) / fMaxShort;
+ bufR[j] = static_cast ( vecsStereoInOut[i + 1] ) / fMaxShort;
}
-
- return true; // prime
}
else
{
- return false; // even
+ for ( int i = 0, j = 0; j < numFrames; i += 2, j++ )
+ {
+ // For Mono and Mono-in/Stereo-out only one channel is selected and copied into both fInput channels
+ bufR[j] = bufL[j] = static_cast ( vecsStereoInOut[i + !bReverbOnLeftChan] ) / fMaxShort;
+ }
}
-}
-void CAudioReverb::Clear()
-{
- // reset and clear all internal state
- allpassDelays[0].Reset ( 0 );
- allpassDelays[1].Reset ( 0 );
- allpassDelays[2].Reset ( 0 );
- combDelays[0].Reset ( 0 );
- combDelays[1].Reset ( 0 );
- combDelays[2].Reset ( 0 );
- combDelays[3].Reset ( 0 );
- combFilters[0].Reset();
- combFilters[1].Reset();
- combFilters[2].Reset();
- combFilters[3].Reset();
- outRightDelay.Reset ( 0 );
- outLeftDelay.Reset ( 0 );
-}
+ mverb->process ( fInput, fInput, numFrames );
-void CAudioReverb::setT60 ( const float fT60, const int iSampleRate )
-{
- // set the reverberation T60 decay time
- for ( int i = 0; i < 4; i++ )
+ for ( int i = 0, j = 0; j < numFrames; i += 2, j++ )
{
- combCoefficient[i] = powf ( 10.0f, static_cast ( -3.0f * combDelays[i].Size() / ( fT60 * iSampleRate ) ) );
+ // Mix wet and dry signal
+ vecsStereoInOut[i] = Float2Short ( vecsStereoInOut[i] + bufL[j] * fMaxShort * fReverbGain );
+ vecsStereoInOut[i + 1] = Float2Short ( vecsStereoInOut[i + 1] + bufR[j] * fMaxShort * fReverbGain );
}
}
-
-void CAudioReverb::COnePole::setPole ( const float fPole )
-{
- // calculate IIR filter coefficients based on the pole value
- fA = -fPole;
- fB = 1.0f - fPole;
-}
-
-float CAudioReverb::COnePole::Calc ( const float fIn )
-{
- // calculate IIR filter
- fLastSample = fB * fIn - fA * fLastSample;
-
- return fLastSample;
-}
-
-void CAudioReverb::Process ( CVector& vecsStereoInOut, const bool bReverbOnLeftChan, const float fAttenuation )
-{
- float fMixedInput, temp, temp0, temp1, temp2;
-
- for ( int i = 0; i < iStereoBlockSizeSam; i += 2 )
- {
- // we sum up the stereo input channels (in case mono input is used, a zero
- // shall be input for the right channel)
- if ( eAudioChannelConf == CC_STEREO )
- {
- fMixedInput = 0.5f * ( vecsStereoInOut[i] + vecsStereoInOut[i + 1] );
- }
- else
- {
- if ( bReverbOnLeftChan )
- {
- fMixedInput = vecsStereoInOut[i];
- }
- else
- {
- fMixedInput = vecsStereoInOut[i + 1];
- }
- }
-
- temp = allpassDelays[0].Get();
- temp0 = allpassCoefficient * temp;
- temp0 += fMixedInput;
- allpassDelays[0].Add ( temp0 );
- temp0 = -( allpassCoefficient * temp0 ) + temp;
-
- temp = allpassDelays[1].Get();
- temp1 = allpassCoefficient * temp;
- temp1 += temp0;
- allpassDelays[1].Add ( temp1 );
- temp1 = -( allpassCoefficient * temp1 ) + temp;
-
- temp = allpassDelays[2].Get();
- temp2 = allpassCoefficient * temp;
- temp2 += temp1;
- allpassDelays[2].Add ( temp2 );
- temp2 = -( allpassCoefficient * temp2 ) + temp;
-
- const float temp3 = temp2 + combFilters[0].Calc ( combCoefficient[0] * combDelays[0].Get() );
- const float temp4 = temp2 + combFilters[1].Calc ( combCoefficient[1] * combDelays[1].Get() );
- const float temp5 = temp2 + combFilters[2].Calc ( combCoefficient[2] * combDelays[2].Get() );
- const float temp6 = temp2 + combFilters[3].Calc ( combCoefficient[3] * combDelays[3].Get() );
-
- combDelays[0].Add ( temp3 );
- combDelays[1].Add ( temp4 );
- combDelays[2].Add ( temp5 );
- combDelays[3].Add ( temp6 );
-
- const float filtout = temp3 + temp4 + temp5 + temp6;
-
- outLeftDelay.Add ( filtout );
- outRightDelay.Add ( filtout );
-
- // inplace apply the attenuated reverb signal (for stereo always apply
- // reverberation effect on both channels)
- if ( ( eAudioChannelConf == CC_STEREO ) || bReverbOnLeftChan )
- {
- vecsStereoInOut[i] = Float2Short ( ( 1.0f - fAttenuation ) * vecsStereoInOut[i] + 0.5f * fAttenuation * outLeftDelay.Get() );
- }
-
- if ( ( eAudioChannelConf == CC_STEREO ) || !bReverbOnLeftChan )
- {
- vecsStereoInOut[i + 1] = Float2Short ( ( 1.0f - fAttenuation ) * vecsStereoInOut[i + 1] + 0.5f * fAttenuation * outRightDelay.Get() );
- }
- }
-}
\ No newline at end of file
diff --git a/src/plugins/audioreverb.h b/src/plugins/audioreverb.h
index a5da6fac61..20ab6ad34b 100644
--- a/src/plugins/audioreverb.h
+++ b/src/plugins/audioreverb.h
@@ -2,56 +2,77 @@
* Audio Reverberation *
\******************************************************************************/
/*
- The following code is based on "JCRev: John Chowning's reverberator class"
- by Perry R. Cook and Gary P. Scavone, 1995 - 2004
- which is in "The Synthesis ToolKit in C++ (STK)"
- http://ccrma.stanford.edu/software/stk
-
- Original description:
- This class is derived from the CLM JCRev function, which is based on the use
- of networks of simple allpass and comb delay filters. This class implements
- three series allpass units, followed by four parallel comb filters, and two
- decorrelation delay lines in parallel at the output.
+ The following code calls MVerb for reverberation.
+ MVerb was written by Martin Eastwood.
+ https://github.com/martineastwood/mverb
*/
#pragma once
#include "util.h"
+#include "libs/mverb/MVerb.h"
class CAudioReverb
{
public:
- CAudioReverb() {}
+ CAudioReverb()
+ {
+ fMaxShort = static_cast ( _MAXSHORT );
+ iPreset = STADIUM;
+
+ // Create MVerb on the heap
+ mverb = std::unique_ptr> ( new MVerb() );
+ mverb->setSampleRate ( SYSTEM_SAMPLE_RATE_HZ );
+ loadPreset();
+ }
- void Init ( const EAudChanConf eNAudioChannelConf, const int iNStereoBlockSizeSam, const int iSampleRate, const float fT60 = 1.1f );
+ void Init ( const EAudChanConf eNAudioChannelConf, const int iNStereoBlockSizeSam );
void Clear();
- void Process ( CVector& vecsStereoInOut, const bool bReverbOnLeftChan, const float fAttenuation );
+ void Process ( CVector& vecsStereoInOut, const bool bReverbOnLeftChan, const float fReverbGain );
+ void setPreset ( const int iNPreset )
+ {
+ // silently fail if preset doesn't exist
+ if ( MathUtils::InRange ( iNPreset, 0, NUM_REV_PRESETS ) )
+ {
+ iPreset = iNPreset;
+ loadPreset();
+ }
+ };
+ int getPreset() const { return iPreset; };
protected:
- void setT60 ( const float fT60, const int iSampleRate );
- bool isPrime ( const int number );
+ std::unique_ptr> mverb;
- class COnePole
+ void loadPreset();
+ EAudChanConf eAudioChannelConf;
+ int iStereoBlockSizeSam;
+ float fMaxShort;
+ int iPreset;
+
+ int numFrames;
+ std::vector bufL;
+ std::vector bufR;
+
+ enum
{
- public:
- COnePole() : fA ( 0 ), fB ( 0 ) { Reset(); }
- void setPole ( const float fPole );
- float Calc ( const float fIn );
- void Reset() { fLastSample = 0; }
-
- protected:
- float fA;
- float fB;
- float fLastSample;
+ SUBTLE = 0,
+ STADIUM,
+ CUPBOARD,
+ DARK,
+ HALVES,
+ DRUMROOM,
+ CLUB,
+ NUM_REV_PRESETS
};
- EAudChanConf eAudioChannelConf;
- int iStereoBlockSizeSam;
- CFIFO allpassDelays[3];
- CFIFO combDelays[4];
- COnePole combFilters[4];
- CFIFO outLeftDelay;
- CFIFO outRightDelay;
- float allpassCoefficient;
- float combCoefficient[4];
+ // Parameters are set iteratively by enum. See MVerb.h for reference.
+ // NOTE: parameters "GAIN" and "MIX" must be "1."
+ constexpr static inline float const presets[NUM_REV_PRESETS][MVerb::NUM_PARAMS] = { { 0., .5, 1., .5, 0., .5, 1., 1., .75 },
+ { 0., .5, 1., .5, 0., 1., 1., 1., .75 },
+ { 0., .5, 1., .5, 0., .25, 1., 1., .75 },
+ { .9, .5, .1, .5, 0., .5, 1., 1., .75 },
+ { .5, .5, .5, .5, .5, .75, 1., 1., .5 },
+ { .2, .4, .4, .6, .1, .05, 1., 1., .4 },
+ { .4, .2, .3, .6, .2, .2, 1., 1., .5 }
+ };
};
diff --git a/src/settings.cpp b/src/settings.cpp
index bdc453913e..4d8fec898b 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -508,6 +508,12 @@ void CClientSettings::ReadSettingsFromXML ( const QDomDocument& IniXMLDocument,
pClient->SetReverbOnLeftChan ( bValue );
}
+ // reverb preset
+ if ( GetNumericIniSet ( IniXMLDocument, "client", "revpreset", 0, 4, iValue ) )
+ {
+ pClient->SetReverbPreset ( iValue );
+ }
+
// sound card selection
const QString strError = pClient->SetSndCrdDev ( FromBase64ToString ( GetIniSetting ( IniXMLDocument, "client", "auddev_base64", "" ) ) );
@@ -951,6 +957,9 @@ void CClientSettings::WriteSettingsToXML ( QDomDocument& IniXMLDocument, bool is
// reverberation channel assignment
SetFlagIniSet ( IniXMLDocument, "client", "reverblchan", pClient->IsReverbOnLeftChan() );
+ // reverb preset
+ SetNumericIniSet ( IniXMLDocument, "client", "revpreset", pClient->GetReverbPreset() );
+
// sound card selection
PutIniSetting ( IniXMLDocument, "client", "auddev_base64", ToBase64 ( pClient->GetSndCrdDev() ) );
From 82b5a5a803c88c08d12460caa13180d0111e0cfc Mon Sep 17 00:00:00 2001
From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com>
Date: Sun, 9 Aug 2026 22:32:54 +0200
Subject: [PATCH 2/4] Introduce "noreverb" as a qmake config option. Optionally
build without the reverb plugin and hide all related UI elements
---
COMPILING.md | 1 +
Jamulus.pro | 33 ++++++++++++++++++++++++++-------
src/client.cpp | 10 ++++++----
src/client.h | 20 ++++++++++++--------
src/clientdlg.cpp | 34 ++++++++++++++++++++++------------
src/clientdlg.h | 13 ++++++++++---
src/clientsettingsdlg.cpp | 27 ++++++++++++++++-----------
src/clientsettingsdlg.h | 2 ++
src/plugins/audioreverb.h | 3 +--
src/settings.cpp | 8 ++++----
10 files changed, 100 insertions(+), 51 deletions(-)
diff --git a/COMPILING.md b/COMPILING.md
index d4a10c3bb5..e9d9a0c94b 100644
--- a/COMPILING.md
+++ b/COMPILING.md
@@ -205,3 +205,4 @@ During compile time some CONFIG arguments can be given to enable or disable spec
| `disable_version_check` | Skip checks for version updates |
| `noupcasename` | Compile Jamulus binary as lower case "jamulus" instead of "Jamulus" |
| `raspijamulus` | Use raspijamulus.sh specific enhancements for build on Raspberry Pi |
+| `noreverb` | Don't build the internal reverb and disable all related GUI elements |
diff --git a/Jamulus.pro b/Jamulus.pro
index aff8433f42..dbc7ee41ed 100644
--- a/Jamulus.pro
+++ b/Jamulus.pro
@@ -42,6 +42,21 @@ contains(CONFIG, "nosound") {
warning("\"nosound\" is deprecated: please use \"serveronly\" for a server-only build.")
}
+!contains(CONFIG, "serveronly") {
+ !contains(CONFIG, "noreverb"):!exists($$PWD/libs/mverb/MVerb.h) {
+ !system("git -C $$PWD submodule update --init --force libs/mverb") {
+ message("MVerb not found and could not be cloned.")
+ CONFIG += noreverb
+ }
+ }
+ contains(CONFIG, "noreverb") {
+ message("building without reverb plugin")
+ DEFINES += NO_REVERB
+ } else {
+ message("building with MVerb")
+ }
+}
+
contains(CONFIG, "headless") {
message(Headless mode activated.)
QT -= gui
@@ -389,8 +404,7 @@ FORMS_GUI = src/aboutdlgbase.ui \
src/connectdlgbase.ui
}
-HEADERS += src/plugins/audioreverb.h \
- src/buffer.h \
+HEADERS += src/buffer.h \
src/channel.h \
src/global.h \
src/protocol.h \
@@ -405,13 +419,16 @@ HEADERS += src/plugins/audioreverb.h \
src/recorder/jamrecorder.h \
src/recorder/creaperproject.h \
src/recorder/cwavestream.h \
- src/signalhandler.h \
- libs/mverb/MVerb.h
+ src/signalhandler.h
!contains(CONFIG, "serveronly") {
HEADERS += src/client.h \
src/sound/soundbase.h \
src/testbench.h
+ !contains(CONFIG, noreverb) {
+ HEADERS += src/plugins/audioreverb.h \
+ libs/mverb/MVerb.h
+ }
}
HEADERS_GUI = src/serverdlg.h
@@ -498,8 +515,7 @@ HEADERS_OPUS_X86 = libs/opus/celt/x86/celt_lpc_sse.h \
libs/opus/celt/x86/x86cpu.h \
$$files(libs/opus/silk/x86/*.h)
-SOURCES += src/plugins/audioreverb.cpp \
- src/buffer.cpp \
+SOURCES += src/buffer.cpp \
src/channel.cpp \
src/main.cpp \
src/protocol.cpp \
@@ -517,7 +533,10 @@ SOURCES += src/plugins/audioreverb.cpp \
!contains(CONFIG, "serveronly") {
SOURCES += src/client.cpp \
- src/sound/soundbase.cpp \
+ src/sound/soundbase.cpp
+ !contains(CONFIG, "noreverb") {
+ SOURCES += src/plugins/audioreverb.cpp
+ }
}
SOURCES_GUI = src/serverdlg.cpp
diff --git a/src/client.cpp b/src/client.cpp
index 3cde8158bb..bfe2c499f4 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -75,8 +75,10 @@ CClient::CClient ( const quint16 iPortNumber,
Socket ( &Channel, iPortNumber, iQosNumber, "", "", bNDisableIPv6, bIPv6Available ),
Sound ( AudioCallback, this, bNoAutoJackConnect, strNClientName ),
iAudioInFader ( AUD_FADER_IN_MIDDLE ),
+#ifndef NO_REVERB
bReverbOnLeftChan ( false ),
iReverbLevel ( 0 ),
+#endif
iInputBoost ( 1 ),
iSndCrdPrefFrameSizeFactor ( FRAME_SIZE_FACTOR_DEFAULT ),
iSndCrdFrameSizeFactor ( FRAME_SIZE_FACTOR_DEFAULT ),
@@ -1367,10 +1369,10 @@ void CClient::Init()
// set the channel network properties
Channel.SetAudioStreamProperties ( eAudioCompressionType, iCeltNumCodedBytes, iSndCrdFrameSizeFactor, iNumAudioChannels );
-
+#ifndef NO_REVERB
// init reverberation
AudioReverb.Init ( eAudioChannelConf, iStereoBlockSizeSam );
-
+#endif
// init the sound card conversion buffers
if ( bSndCrdConversionBufferRequired )
{
@@ -1462,13 +1464,13 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd )
#ifndef HEADLESS
SignalLevelMeter.Update ( vecsStereoSndCrd, iMonoBlockSizeSam, true );
#endif
-
+#ifndef NO_REVERB
// add reverberation effect if activated
if ( iReverbLevel != 0 )
{
AudioReverb.Process ( vecsStereoSndCrd, bReverbOnLeftChan, static_cast ( iReverbLevel ) / AUD_REVERB_MAX / 4 );
}
-
+#endif
// apply pan (audio fader) and mix mono signals
if ( !( ( iAudioInFader == AUD_FADER_IN_MIDDLE ) && ( eAudioChannelConf == CC_STEREO ) ) )
{
diff --git a/src/client.h b/src/client.h
index ebfebae545..f566fabc62 100644
--- a/src/client.h
+++ b/src/client.h
@@ -61,7 +61,9 @@
#include "socket.h"
#include "channel.h"
#include "util.h"
-#include "plugins/audioreverb.h"
+#ifndef NO_REVERB
+# include "plugins/audioreverb.h"
+#endif
#include "buffer.h"
#include "signalhandler.h"
@@ -188,7 +190,7 @@ class CClient : public QObject
int GetAudioInFader() const { return iAudioInFader; }
void SetAudioInFader ( const int iNV ) { iAudioInFader = iNV; }
-
+#ifndef NO_REVERB
int GetReverbLevel() const { return iReverbLevel; }
int GetReverbPreset() const { return AudioReverb.getPreset(); }
void SetReverbLevel ( const int iNL ) { iReverbLevel = iNL; }
@@ -196,7 +198,7 @@ class CClient : public QObject
bool IsReverbOnLeftChan() const { return bReverbOnLeftChan; }
void SetReverbOnLeftChan ( const bool bIL ) { bReverbOnLeftChan = bIL; }
-
+#endif
void SetDoAutoSockBufSize ( const bool bValue );
bool GetDoAutoSockBufSize() const { return Channel.GetDoAutoSockBufSize(); }
@@ -401,11 +403,13 @@ class CClient : public QObject
CVector vecbyNetwData;
- std::atomic iAudioInFader;
- std::atomic bReverbOnLeftChan;
- std::atomic iReverbLevel;
- CAudioReverb AudioReverb;
- std::atomic iInputBoost;
+ int iAudioInFader;
+#ifndef NO_REVERB
+ bool bReverbOnLeftChan;
+ int iReverbLevel;
+ CAudioReverb AudioReverb;
+#endif
+ int iInputBoost;
int iSndCrdPrefFrameSizeFactor;
int iSndCrdFrameSizeFactor;
diff --git a/src/clientdlg.cpp b/src/clientdlg.cpp
index d939b54aa2..7f24b2124b 100644
--- a/src/clientdlg.cpp
+++ b/src/clientdlg.cpp
@@ -117,7 +117,7 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
"If you are connected, pressing this button will end the session." ) );
butConnect->setAccessibleName ( tr ( "Connect and disconnect toggle button" ) );
-
+#ifndef NO_REVERB
// reverberation level
QString strAudReverb = "" + tr ( "Reverb effect" ) + ": " +
tr ( "Reverb can be applied to one local mono audio channel or to both "
@@ -143,7 +143,13 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
rbtReverbSelL->setAccessibleName ( tr ( "Left channel selection for reverb" ) );
rbtReverbSelR->setWhatsThis ( strRevChanSel );
rbtReverbSelR->setAccessibleName ( tr ( "Right channel selection for reverb" ) );
-
+#endif
+#ifdef NO_REVERB
+ lblAudioReverb->setVisible ( false );
+ sldAudioReverb->setVisible ( false );
+ rbtReverbSelL->setVisible ( false );
+ rbtReverbSelR->setVisible ( false );
+#endif
// delay LED
QString strLEDDelay = "" + tr ( "Delay Status LED" ) + ": " + tr ( "Shows the current audio delay status:" ) +
"
"
@@ -257,18 +263,18 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
// init status LEDs
ledBuffers->Reset();
ledDelay->Reset();
-
+#ifndef NO_REVERB
// init audio reverberation
sldAudioReverb->setRange ( 0, AUD_REVERB_MAX );
const int iCurAudReverb = pClient->GetReverbLevel();
sldAudioReverb->setValue ( iCurAudReverb );
sldAudioReverb->setTickInterval ( AUD_REVERB_MAX / 5 );
- // init input boost
- pClient->SetInputBoost ( pSettings->iInputBoost );
-
// init reverb channel
UpdateRevSelection();
+#endif
+ // init input boost
+ pClient->SetInputBoost ( pSettings->iInputBoost );
// init connect dialog
ConnectDlg.SetShowAllMusicians ( pSettings->bConnectDlgShowAllMusicians );
@@ -496,14 +502,14 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
QObject::connect ( &TimerCheckAudioDeviceOk, &QTimer::timeout, this, &CClientDlg::OnTimerCheckAudioDeviceOk );
QObject::connect ( &TimerDetectFeedback, &QTimer::timeout, this, &CClientDlg::OnTimerDetectFeedback );
-
+#ifndef NO_REVERB
QObject::connect ( sldAudioReverb, &QSlider::valueChanged, this, &CClientDlg::OnAudioReverbValueChanged );
// radio buttons
QObject::connect ( rbtReverbSelL, &QRadioButton::clicked, this, &CClientDlg::OnReverbSelLClicked );
QObject::connect ( rbtReverbSelR, &QRadioButton::clicked, this, &CClientDlg::OnReverbSelRClicked );
-
+#endif
// other
QObject::connect ( pClient, &CClient::ConClientListMesReceived, this, &CClientDlg::OnConClientListMesReceived );
@@ -690,7 +696,7 @@ void CClientDlg::ManageDragNDrop ( QDropEvent* Event, const bool bCheckAccept )
}
}
}
-
+#ifndef NO_REVERB
void CClientDlg::UpdateRevSelection()
{
if ( pClient->GetAudioChannels() == CC_STEREO )
@@ -720,7 +726,7 @@ void CClientDlg::UpdateRevSelection()
// update visibility of the pan controls in the audio mixer board (pan is not supported for mono)
MainMixerBoard->SetDisplayPans ( pClient->GetAudioChannels() != CC_MONO );
}
-
+#endif
void CClientDlg::OnConnectDlgAccepted()
{
// We had an issue that the accepted signal was emit twice if a list item was double
@@ -1402,7 +1408,8 @@ void CClientDlg::SetGUIDesign ( const EGUIDesign eNewDesign )
" image: url(:/png/fader/res/ledbuttonpressed.png); }"
"QCheckBox { color: rgb(220, 220, 220);"
" font: bold; }" );
-#ifdef _WIN32
+#ifndef NO_REVERB
+# ifdef _WIN32
// Workaround QT-Windows problem: This should not be necessary since in the
// background frame the style sheet for QRadioButton was already set. But it
// seems that it is only applied if the style was set to default and then back
@@ -1411,6 +1418,7 @@ void CClientDlg::SetGUIDesign ( const EGUIDesign eNewDesign )
"font: bold;" );
rbtReverbSelR->setStyleSheet ( "color: rgb(220, 220, 220);"
"font: bold;" );
+# endif
#endif
ledBuffers->SetType ( CMultiColorLED::MT_LED );
@@ -1421,10 +1429,12 @@ void CClientDlg::SetGUIDesign ( const EGUIDesign eNewDesign )
// reset style sheet and set original parameters
backgroundFrame->setStyleSheet ( "" );
-#ifdef _WIN32
+#ifndef NO_REVERB
+# ifdef _WIN32
// Workaround QT-Windows problem: See above description
rbtReverbSelL->setStyleSheet ( "" );
rbtReverbSelR->setStyleSheet ( "" );
+# endif
#endif
ledBuffers->SetType ( CMultiColorLED::MT_INDICATOR );
diff --git a/src/clientdlg.h b/src/clientdlg.h
index 6a34cc66f0..856d04a74d 100644
--- a/src/clientdlg.h
+++ b/src/clientdlg.h
@@ -115,7 +115,9 @@ class CClientDlg : public CBaseDlg, private Ui_CClientDlgBase
void ShowChatWindow ( const bool bForceRaise = true );
void ShowAnalyzerConsole();
void UpdateAudioFaderSlider();
+#ifndef NO_REVERB
void UpdateRevSelection();
+#endif
void Connect ( const QString& strSelectedAddress, const QString& strMixerBoardLabel );
void Disconnect();
void ManageDragNDrop ( QDropEvent* Event, const bool bCheckAccept );
@@ -201,13 +203,13 @@ public slots:
void OnSettingsStateChanged ( int value );
void OnChatStateChanged ( int value );
void OnLocalMuteStateChanged ( int value );
-
+#ifndef NO_REVERB
void OnAudioReverbValueChanged ( int value ) { pClient->SetReverbLevel ( value ); }
void OnReverbSelLClicked() { pClient->SetReverbOnLeftChan ( true ); }
void OnReverbSelRClicked() { pClient->SetReverbOnLeftChan ( false ); }
-
+#endif
void OnFeedbackDetectionChanged ( int state ) { ClientSettingsDlg.SetEnableFeedbackDetection ( state == Qt::Checked ); }
void OnConClientListMesReceived ( CVector vecChanInfo );
@@ -259,7 +261,12 @@ public slots:
void OnMeterStyleChanged();
void OnRecorderStateReceived ( ERecorderState eRecorderState );
void SetMixerBoardDeco ( const ERecorderState newRecorderState, const EGUIDesign eNewDesign );
- void OnAudioChannelsChanged() { UpdateRevSelection(); }
+ void OnAudioChannelsChanged()
+ {
+#ifndef NO_REVERB
+ UpdateRevSelection();
+#endif
+ }
void OnNumClientsChanged ( int iNewNumClients );
void accept() { close(); } // introduced by pljones
diff --git a/src/clientsettingsdlg.cpp b/src/clientsettingsdlg.cpp
index 9932023a42..1c44f134d7 100644
--- a/src/clientsettingsdlg.cpp
+++ b/src/clientsettingsdlg.cpp
@@ -379,16 +379,21 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, CClientSettings* pNSet
lblInputBoost->setWhatsThis ( strInputBoost );
cbxInputBoost->setWhatsThis ( strInputBoost );
cbxInputBoost->setAccessibleName ( tr ( "Input Boost combo box" ) );
-
+#ifndef NO_REVERB
// reverb preset
QString strReverbPreset = "" + tr ( "Reverb Preset" ) + ": " +
tr ( "Jamulus uses MVerb by Martin Eastwood for reverberation. "
"MVerb comes with a set of presets you can select here. "
"Available Presets: Subtle, Stadium, Cupboard, Dark, Halves " );
- lblInputBoost->setWhatsThis ( strReverbPreset );
- cbxInputBoost->setWhatsThis ( strReverbPreset );
- cbxInputBoost->setAccessibleName ( tr ( "Reverb Preset combo box" ) );
-
+ lblReverbPreset->setWhatsThis ( strReverbPreset );
+ cbxReverbPreset->setWhatsThis ( strReverbPreset );
+ cbxReverbPreset->setAccessibleName ( tr ( "Reverb Preset combo box" ) );
+#endif
+#ifdef NO_REVERB
+ lblReverbPreset->setVisible ( false );
+ cbxReverbPreset->setVisible ( false );
+ verticalSpacer_13->changeSize ( 0, 0 );
+#endif
// custom directories
QString strCustomDirectories = "" + tr ( "Custom Directories" ) + ": " +
tr ( "If you need to add additional directories to the Connect dialog Directory drop down, "
@@ -563,7 +568,7 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, CClientSettings* pNSet
}
// factor is 1-based while index is 0-based:
cbxInputBoost->setCurrentIndex ( pSettings->iInputBoost - 1 );
-
+#ifndef NO_REVERB
// Rever Preset combo box
cbxReverbPreset->clear();
cbxReverbPreset->addItem ( "Subtle" );
@@ -574,7 +579,7 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, CClientSettings* pNSet
cbxReverbPreset->addItem ( "Drum Room" );
cbxReverbPreset->addItem ( "Club" );
cbxReverbPreset->setCurrentIndex ( pClient->GetReverbPreset() );
-
+#endif
// init number of mixer rows
spnMixerRows->setValue ( pSettings->iNumMixerPanelRows );
@@ -805,12 +810,12 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, CClientSettings* pNSet
static_cast ( &QComboBox::activated ),
this,
&CClientSettingsDlg::OnInputBoostChanged );
-
+#ifndef NO_REVERB
QObject::connect ( cbxReverbPreset,
static_cast ( &QComboBox::activated ),
this,
&CClientSettingsDlg::OnReverbPresetChanged );
-
+#endif
// buttons
#if defined( _WIN32 ) && !defined( WITH_JACK )
// Driver Setup button is only available for Windows when JACK is not used
@@ -1413,9 +1418,9 @@ void CClientSettingsDlg::OnInputBoostChanged()
pSettings->iInputBoost = cbxInputBoost->currentIndex() + 1;
pClient->SetInputBoost ( pSettings->iInputBoost );
}
-
+#ifndef NO_REVERB
void CClientSettingsDlg::OnReverbPresetChanged() { pClient->SetReverbPreset ( cbxReverbPreset->currentIndex() ); }
-
+#endif
void CClientSettingsDlg::OnAliasTextChanged ( const QString& strNewName )
{
// check length
diff --git a/src/clientsettingsdlg.h b/src/clientsettingsdlg.h
index 6564e21ca9..f6ade362b2 100644
--- a/src/clientsettingsdlg.h
+++ b/src/clientsettingsdlg.h
@@ -109,7 +109,9 @@ public slots:
void OnCustomDirectoriesChanged ( bool bDelete );
void OnNewClientLevelEditingFinished() { pSettings->iNewClientFaderLevel = edtNewClientLevel->text().toInt(); }
void OnInputBoostChanged();
+#ifndef NO_REVERB
void OnReverbPresetChanged();
+#endif
void OnSndCrdBufferDelayButtonGroupClicked ( QAbstractButton* button );
void OnSoundcardActivated ( int iSndDevIdx );
void OnLInChanActivated ( int iChanIdx );
diff --git a/src/plugins/audioreverb.h b/src/plugins/audioreverb.h
index 20ab6ad34b..df5704e224 100644
--- a/src/plugins/audioreverb.h
+++ b/src/plugins/audioreverb.h
@@ -73,6 +73,5 @@ class CAudioReverb
{ .9, .5, .1, .5, 0., .5, 1., 1., .75 },
{ .5, .5, .5, .5, .5, .75, 1., 1., .5 },
{ .2, .4, .4, .6, .1, .05, 1., 1., .4 },
- { .4, .2, .3, .6, .2, .2, 1., 1., .5 }
- };
+ { .4, .2, .3, .6, .2, .2, 1., 1., .5 } };
};
diff --git a/src/settings.cpp b/src/settings.cpp
index 4d8fec898b..aaa643f3da 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -495,7 +495,7 @@ void CClientSettings::ReadSettingsFromXML ( const QDomDocument& IniXMLDocument,
{
pClient->SetAudioInFader ( iValue );
}
-
+# ifndef NO_REVERB
// reverberation level
if ( GetNumericIniSet ( IniXMLDocument, "client", "revlev", 0, AUD_REVERB_MAX, iValue ) )
{
@@ -513,7 +513,7 @@ void CClientSettings::ReadSettingsFromXML ( const QDomDocument& IniXMLDocument,
{
pClient->SetReverbPreset ( iValue );
}
-
+# endif
// sound card selection
const QString strError = pClient->SetSndCrdDev ( FromBase64ToString ( GetIniSetting ( IniXMLDocument, "client", "auddev_base64", "" ) ) );
@@ -950,7 +950,7 @@ void CClientSettings::WriteSettingsToXML ( QDomDocument& IniXMLDocument, bool is
// audio fader
SetNumericIniSet ( IniXMLDocument, "client", "audfad", pClient->GetAudioInFader() );
-
+# ifndef NO_REVERB
// reverberation level
SetNumericIniSet ( IniXMLDocument, "client", "revlev", pClient->GetReverbLevel() );
@@ -959,7 +959,7 @@ void CClientSettings::WriteSettingsToXML ( QDomDocument& IniXMLDocument, bool is
// reverb preset
SetNumericIniSet ( IniXMLDocument, "client", "revpreset", pClient->GetReverbPreset() );
-
+# endif
// sound card selection
PutIniSetting ( IniXMLDocument, "client", "auddev_base64", ToBase64 ( pClient->GetSndCrdDev() ) );
From 6d1f8496413621a1a7ae3e28dbe9cf3d13ad09ea Mon Sep 17 00:00:00 2001
From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com>
Date: Mon, 10 Aug 2026 06:33:19 +0200
Subject: [PATCH 3/4] Update preset names
---
src/clientsettingsdlg.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/clientsettingsdlg.cpp b/src/clientsettingsdlg.cpp
index 1c44f134d7..b0582362e3 100644
--- a/src/clientsettingsdlg.cpp
+++ b/src/clientsettingsdlg.cpp
@@ -384,7 +384,7 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, CClientSettings* pNSet
QString strReverbPreset = "" + tr ( "Reverb Preset" ) + ": " +
tr ( "Jamulus uses MVerb by Martin Eastwood for reverberation. "
"MVerb comes with a set of presets you can select here. "
- "Available Presets: Subtle, Stadium, Cupboard, Dark, Halves " );
+ "Available Presets: Subtle, Stadium, Cupboard, Dark, Halves, Drum Room, Club " );
lblReverbPreset->setWhatsThis ( strReverbPreset );
cbxReverbPreset->setWhatsThis ( strReverbPreset );
cbxReverbPreset->setAccessibleName ( tr ( "Reverb Preset combo box" ) );
From c4ac37b1d93125b7a69620ceb77868199f753c0d Mon Sep 17 00:00:00 2001
From: Nils Brederlow <62596379+dingodoppelt@users.noreply.github.com>
Date: Mon, 10 Aug 2026 19:55:12 +0200
Subject: [PATCH 4/4] Throw an error and exit QMake when MVerb could not be
cloned as a submodule although requested
---
Jamulus.pro | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/Jamulus.pro b/Jamulus.pro
index dbc7ee41ed..6817659296 100644
--- a/Jamulus.pro
+++ b/Jamulus.pro
@@ -45,15 +45,15 @@ contains(CONFIG, "nosound") {
!contains(CONFIG, "serveronly") {
!contains(CONFIG, "noreverb"):!exists($$PWD/libs/mverb/MVerb.h) {
!system("git -C $$PWD submodule update --init --force libs/mverb") {
- message("MVerb not found and could not be cloned.")
- CONFIG += noreverb
+ error('MVerb not found and could not be cloned as a submodule.$$escape_expand(\n) \
+ Try cloning MVerb manually with: \'git submodule update --init --force libs/mverb\'$$escape_expand(\n) \
+ To disable the reverb plugin call QMake with \"CONFIG+=noreverb\"$$escape_expand(\\n)Exiting...')
+ } else {
+ message("building with MVerb")
}
- }
- contains(CONFIG, "noreverb") {
+ } else {
message("building without reverb plugin")
DEFINES += NO_REVERB
- } else {
- message("building with MVerb")
}
}