Skip to content

Commit a50be14

Browse files
committed
Add limiter support (with limiter from signalsmith-audio-basics)
This adds limiter support by using Signalsmith Audio Basics C++ header-only library (see https://signalsmith-audio.co.uk/code/ and https://github.com/Signalsmith-Audio/basics) Path to Signalsmith basics lib have to be supplied to cmake in the environment variable SIGNALSMITH_AUDIO_BASICS_PATH The limiter is applied in fluid_rvoice_mixer_process_fx after chorus and reverb effects. In the audio drivers that mix effects and dry audio in one buffer, the limiting will be applied to the resulting buffer. In audio drivers that do this separately (for example, Jack driver), the limiting will be applied only to the dry buffer
1 parent 4d2550c commit a50be14

File tree

12 files changed

+409
-0
lines changed

12 files changed

+409
-0
lines changed

CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ option ( enable-threads "enable multi-threading support (such as parallel voice
102102
option ( enable-openmp "enable OpenMP support (parallelization of soundfont decoding, vectorization of voice mixing, etc.)" on )
103103
option ( enable-unicode "enable UNICODE build for Windows" on )
104104
option ( enable-native-dls "compile native DLS support (requires C++17)" on )
105+
option ( enable-limiter "compile Limiter support (requires signalsmith-audio)" off )
105106

106107
set ( osal "glib" CACHE STRING "OS abstraction to use, provided by src/utils/fluid_sys_${osal}.*" )
107108

@@ -799,6 +800,16 @@ if ( enable-libinstpatch )
799800
endif ()
800801
endif ( enable-libinstpatch )
801802

803+
unset ( LIMITER_SUPPORT CACHE )
804+
if ( enable-limiter )
805+
find_path ( SIGNALSMITH_AUDIO_BASICS include/signalsmith-basics/limiter.h
806+
HINTS ENV SIGNALSMITH_AUDIO_BASICS_PATH NO_CACHE )
807+
if ( SIGNALSMITH_AUDIO_BASICS )
808+
set ( LIMITER_SUPPORT 1 )
809+
set ( LIMITER 1 )
810+
endif ( SIGNALSMITH_AUDIO_BASICS )
811+
endif ( enable-limiter )
812+
802813
# manipulate some variables to setup a proper test env
803814
set(TEST_SOUNDFONT "${FluidSynth_SOURCE_DIR}/sf2/VintageDreamsWaves-v2.sf2")
804815
set(TEST_SOUNDFONT_UTF8_1 "${FluidSynth_SOURCE_DIR}/sf2/\\xE2\\x96\\xA0VintageDreamsWaves-v2\\xE2\\x96\\xA0.sf2")

cmake_admin/report.cmake

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,16 @@ endif ( LIBSNDFILE_SUPPORT )
158158

159159
set ( MISC_REPORT "\nMiscellaneous support:\n" )
160160

161+
if ( LIMITER_SUPPORT )
162+
set ( MISC_REPORT "${MISC_REPORT} Limiter: yes\n" )
163+
else ( LIMITER_SUPPORT )
164+
if ( SIGNALSMITH_AUDIO_BASICS STREQUAL SIGNALSMITH_AUDIO_BASICS-NOTFOUND )
165+
set ( MISC_REPORT "${MISC_REPORT} Limiter: no (signalsmith-audio/basics not found)\n" )
166+
else ( SIGNALSMITH_AUDIO_BASICS STREQUAL SIGNALSMITH_AUDIO_BASICS-NOTFOUND )
167+
set ( MISC_REPORT "${MISC_REPORT} Limiter: no\n" )
168+
endif ( SIGNALSMITH_AUDIO_BASICS STREQUAL SIGNALSMITH_AUDIO_BASICS-NOTFOUND )
169+
endif ( LIMITER_SUPPORT )
170+
161171
if ( DBUS_SUPPORT )
162172
set ( MISC_REPORT "${MISC_REPORT} D-Bus: yes\n" )
163173
else ( DBUS_SUPPORT )

src/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,16 @@ set ( libfluidsynth_SOURCES
195195
bindings/fluid_ladspa.h
196196
)
197197

198+
if ( LIMITER_SUPPORT )
199+
set ( fulid_limiter_SOURCES
200+
rvoice/fluid_limiter.c
201+
rvoice/fluid_limiter.h
202+
rvoice/fluid_limiter_impl.cpp
203+
rvoice/fluid_limiter_impl.h
204+
)
205+
set_source_files_properties(rvoice/fluid_limiter_impl.cpp PROPERTIES COMPILE_FLAGS "-I${SIGNALSMITH_AUDIO_BASICS}/include -std=c++11")
206+
endif ( LIMITER_SUPPORT )
207+
198208
set ( fluid_osal_SOURCES utils/fluid_sys_${osal}.h )
199209
if ( osal STREQUAL "cpp11" )
200210
set ( fluid_osal_SOURCES ${fluid_osal_SOURCES} utils/fluid_sys_${osal}.cpp )
@@ -281,6 +291,7 @@ add_library ( libfluidsynth-OBJ OBJECT
281291
${public_HEADERS}
282292
${public_main_HEADER}
283293
${VersionFilesOutputVariable}
294+
${fulid_limiter_SOURCES}
284295
)
285296

286297
target_include_directories ( libfluidsynth-OBJ PRIVATE

src/config.cmake

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@
136136
/* Include the LADSPA Fx unit */
137137
#cmakedefine LADSPA @LADSPA_SUPPORT@
138138

139+
/* Include the LIMITER */
140+
#cmakedefine LIMITER @LIMITER_SUPPORT@
141+
139142
/* Define to enable IPV6 support */
140143
#cmakedefine IPV6_SUPPORT @IPV6_SUPPORT@
141144

src/rvoice/fluid_limiter.c

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/******************************************************************************
2+
* FluidSynth - A Software Synthesizer
3+
*
4+
* Copyright (C) 2025 Neoharp development team
5+
*
6+
* This library is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU Lesser General Public License
8+
* as published by the Free Software Foundation; either version 2.1 of
9+
* the License, or (at your option) any later version.
10+
*
11+
* This library is distributed in the hope that it will be useful, but
12+
* WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public
17+
* License along with this library; if not, see
18+
* <https://www.gnu.org/licenses/>.
19+
*
20+
*/
21+
22+
#include "fluidsynth_priv.h"
23+
24+
#ifdef LIMITER
25+
26+
#include "fluid_limiter.h"
27+
#include "fluid_limiter_impl.h"
28+
#include "fluid_sys.h"
29+
30+
/*----------------------------------------------------------------------------
31+
Limiter API
32+
-----------------------------------------------------------------------------*/
33+
/*
34+
* Creates a limiter with default parameters
35+
*
36+
* @param sample_rate actual sample rate needed in Hz.
37+
* @return pointer on the new limiter or NULL if memory error.
38+
* Limiter API.
39+
*/
40+
fluid_limiter_t*
41+
new_fluid_limiter(fluid_real_t sample_rate, fluid_limiter_settings_t* settings)
42+
{
43+
fluid_limiter_t* lim;
44+
45+
if(sample_rate <= 0)
46+
{
47+
return NULL;
48+
}
49+
50+
lim = fluid_limiter_impl_new(sample_rate, settings);
51+
52+
if(lim == NULL)
53+
{
54+
return NULL;
55+
}
56+
57+
return lim;
58+
}
59+
60+
/*
61+
* free the limiter.
62+
* @param lim pointer on limiter to free.
63+
* Limiter API.
64+
*/
65+
void
66+
delete_fluid_limiter(fluid_limiter_t *lim)
67+
{
68+
fluid_return_if_fail(lim != NULL);
69+
fluid_limiter_impl_delete(lim);
70+
}
71+
72+
/*
73+
* Applies a sample rate change on the limiter.
74+
*
75+
* @param lim the limiter.
76+
* @param sample_rate new sample rate value
77+
* @return FLUID_OK if success, FLUID_FAILED if lim is NULL
78+
* Limiter API.
79+
*/
80+
int
81+
fluid_limiter_samplerate_change(fluid_limiter_t *lim, fluid_real_t sample_rate)
82+
{
83+
int status = FLUID_OK;
84+
85+
fluid_return_val_if_fail(lim != NULL, FLUID_FAILED);
86+
87+
fluid_limiter_impl_set_sample_rate(lim, sample_rate);
88+
89+
return status;
90+
}
91+
92+
/*-----------------------------------------------------------------------------
93+
* Run the limiter
94+
* @param lim pointer on limiter.
95+
* @param buf_l left buffer to process (will be modified in-place)
96+
* @param buf_r right buffer to process (will be modified in-place)
97+
* Limiter API.
98+
-----------------------------------------------------------------------------*/
99+
void
100+
fluid_limiter_run(fluid_limiter_t *lim, fluid_real_t *buf_l, fluid_real_t *buf_r, int block_count)
101+
{
102+
int i;
103+
fluid_real_t* bufs[FLUID_LIMITER_NUM_CHANNELS_AT_ONCE];
104+
105+
for (i = 0; i < block_count; i++)
106+
{
107+
#if FLUID_LIMITER_NUM_CHANNELS_AT_ONCE < 2
108+
#error "expected FLUID_LIMITER_NUM_CHANNELS_AT_ONCE >= 2"
109+
#endif
110+
bufs[0] = buf_l + i*FLUID_BUFSIZE;
111+
bufs[1] = buf_r + i*FLUID_BUFSIZE;
112+
113+
fluid_limiter_impl_process_buffers(lim, bufs);
114+
}
115+
}
116+
117+
#endif /* LIMITER */

src/rvoice/fluid_limiter.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/* FluidSynth - A Software Synthesizer
2+
*
3+
* Copyright (C) 2003 Peter Hanappe and others.
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public License
7+
* as published by the Free Software Foundation; either version 2.1 of
8+
* the License, or (at your option) any later version.
9+
*
10+
* This library is distributed in the hope that it will be useful, but
11+
* WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this library; if not, see
17+
* <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
21+
#ifndef _FLUID_LIMITER_H
22+
#define _FLUID_LIMITER_H
23+
24+
#ifdef LIMITER
25+
26+
// how many channel buffers to process at once
27+
// maybe if we want to parallelize, we might set this to 1
28+
#define FLUID_LIMITER_NUM_CHANNELS_AT_ONCE 2
29+
30+
typedef struct {
31+
fluid_real_t input_gain;
32+
fluid_real_t output_limit;
33+
fluid_real_t attack_ms;
34+
fluid_real_t hold_ms;
35+
fluid_real_t release_ms;
36+
int smoothing_stages;
37+
fluid_real_t link_channels;
38+
} fluid_limiter_settings_t;
39+
40+
typedef void fluid_limiter_t;
41+
42+
fluid_limiter_t*
43+
new_fluid_limiter(fluid_real_t sample_rate, fluid_limiter_settings_t* settings);
44+
45+
void delete_fluid_limiter(fluid_limiter_t* lim);
46+
47+
int fluid_limiter_samplerate_change(fluid_limiter_t* lim, fluid_real_t sample_rate);
48+
49+
void
50+
fluid_limiter_run(fluid_limiter_t *lim, fluid_real_t *buf_l, fluid_real_t *buf_r, int block_count);
51+
52+
#endif /* LIMITER */
53+
54+
#endif /* _FLUID_LIMITER_H */

src/rvoice/fluid_limiter_impl.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/* FluidSynth - A Software Synthesizer
2+
*
3+
* Copyright (C) 2003 Peter Hanappe and others.
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public License
7+
* as published by the Free Software Foundation; either version 2.1 of
8+
* the License, or (at your option) any later version.
9+
*
10+
* This library is distributed in the hope that it will be useful, but
11+
* WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this library; if not, see
17+
* <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
#include "fluidsynth_priv.h"
21+
22+
#ifdef LIMITER
23+
24+
#include "fluid_limiter.h"
25+
#include "fluid_limiter_impl.h"
26+
#include "signalsmith-basics/limiter.h"
27+
28+
#ifdef WITH_FLOAT
29+
using Limiter = signalsmith::basics::LimiterFloat;
30+
#else
31+
using Limiter = signalsmith::basics::LimiterDouble;
32+
#endif
33+
34+
extern "C" void fluid_limiter_impl_set_sample_rate(fluid_limiter_t* lim, fluid_real_t sample_rate)
35+
{
36+
((Limiter*)lim)->configure(sample_rate, FLUID_BUFSIZE, FLUID_LIMITER_NUM_CHANNELS_AT_ONCE);
37+
}
38+
39+
extern "C" fluid_limiter_t* fluid_limiter_impl_new(fluid_real_t sample_rate, fluid_limiter_settings_t* settings)
40+
{
41+
auto lim = new Limiter(settings->attack_ms + settings->hold_ms);
42+
43+
lim->inputGain = settings->input_gain;
44+
lim->outputLimit = settings->output_limit;
45+
lim->attackMs = settings->attack_ms;
46+
lim->holdMs = settings->hold_ms;
47+
lim->releaseMs = settings->release_ms;
48+
lim->smoothingStages = settings->smoothing_stages;
49+
lim->linkChannels = settings->link_channels;
50+
51+
if (! lim->configure(sample_rate, FLUID_BUFSIZE,
52+
FLUID_LIMITER_NUM_CHANNELS_AT_ONCE,
53+
FLUID_LIMITER_NUM_CHANNELS_AT_ONCE) )
54+
{
55+
FLUID_LOG(FLUID_WARN, "limiter parameters was not accepted");
56+
}
57+
58+
return lim;
59+
}
60+
61+
extern "C" void fluid_limiter_impl_delete(fluid_limiter_t* lim)
62+
{
63+
delete (Limiter*)lim;
64+
}
65+
66+
extern "C" void fluid_limiter_impl_process_buffers(
67+
fluid_limiter_t* lim,
68+
fluid_real_t* bufs[FLUID_LIMITER_NUM_CHANNELS_AT_ONCE])
69+
{
70+
((Limiter*)lim)->process(bufs, FLUID_BUFSIZE);
71+
}
72+
73+
#endif /* LIMITER */

src/rvoice/fluid_limiter_impl.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/******************************************************************************
2+
* FluidSynth - A Software Synthesizer
3+
*
4+
* Copyright (C) 2025 Neoharp development team
5+
*
6+
* This library is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU Lesser General Public License
8+
* as published by the Free Software Foundation; either version 2.1 of
9+
* the License, or (at your option) any later version.
10+
*
11+
* This library is distributed in the hope that it will be useful, but
12+
* WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public
17+
* License along with this library; if not, see
18+
* <https://www.gnu.org/licenses/>.
19+
*
20+
*/
21+
22+
#ifndef _FLUID_LIMITER_IMPL_H
23+
#define _FLUID_LIMITER_IMPL_H
24+
25+
#ifdef __cplusplus
26+
extern "C" {
27+
#endif
28+
29+
void fluid_limiter_impl_set_sample_rate(fluid_limiter_t*lim, fluid_real_t sample_rate);
30+
fluid_limiter_t* fluid_limiter_impl_new(fluid_real_t sample_rate, fluid_limiter_settings_t* settings);
31+
void fluid_limiter_impl_delete(fluid_limiter_t* lim);
32+
void fluid_limiter_impl_process_buffers(fluid_limiter_t* lim, fluid_real_t* bufs[FLUID_LIMITER_NUM_CHANNELS_AT_ONCE]);
33+
34+
#ifdef __cplusplus
35+
}
36+
#endif
37+
38+
#endif /* _FLUID_LIMITER_IMPL_H */

0 commit comments

Comments
 (0)