Skip to content

Commit 6df0f54

Browse files
committed
Release 0.5.3
* Added normalization of output sample.
2 parents 5d6cab4 + b8089b9 commit 6df0f54

File tree

10 files changed

+166
-1
lines changed

10 files changed

+166
-1
lines changed

CHANGELOG

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
* RECENT CHANGES
33
*******************************************************************************
44

5+
=== 0.5.3 ===
6+
* Added normalization of output sample.
7+
58
=== 0.5.2 ===
69

710
* Fixed command-line parsing.

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ The available option list will be the following:
2020
-g, --gain Gain (in dB) of the sine sweep
2121
-h, --help Output this help message
2222
-i, --in-file Input audio file
23+
-n, --normalize Set normalization mode
24+
-ng, --norm-gain Set normalization peak gain (in dB)
2325
-o, --out-file Output audio file
2426
-r, --reference Reference audio file
2527
-s, --sweep Produce sine sweep signal
@@ -110,6 +112,13 @@ For more information, see `room-raider --help`.
110112

111113
The file `response.wav` will have the same number of channels as `room-outputs.wav` and will contain the electroacoustic impulse responses from soundcard output to each of the test microphones.
112114

115+
Additionally, the output sample can be normalized with options ```-n``` and ```-ng```. While ```-ng``` option sets the maximum peak level (in dB) of the output sample,
116+
the ```-n``` option allows to specify the normalization algorithm:
117+
* **none** - do not use normalization (default);
118+
* **above** - normalize the file if the maximum signal peak is above the specified peak level;
119+
* **below** - normalize the file if the maximum signal peak is below the specified peak level;
120+
* **always** - always normalize output files to match the maximum signal peak to specified peak level.
121+
113122
Requirements
114123
======
115124

include/private/config.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ namespace room_raider
3636
M_DECONVOLVE
3737
};
3838

39+
enum normalize_t
40+
{
41+
NORM_NONE, // No normalization
42+
NORM_ABOVE, // When the maximum peak is above the threshold
43+
NORM_BELOW, // When the maximum peak is below the threshold
44+
NORM_ALWAYS // Always normalize
45+
};
46+
3947
/**
4048
* Overall configuration
4149
*/
@@ -54,6 +62,8 @@ namespace room_raider
5462
LSPString sInFile; // Source file
5563
LSPString sOutFile; // Destination file
5664
LSPString sReference; // Reference file
65+
ssize_t nNormalize; // Normalization method
66+
float fNormGain; // Normalization gain
5767

5868
public:
5969
explicit config_t();

include/private/dsp.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,17 @@
2828
namespace room_raider
2929
{
3030
status_t synth_test_sweep(const config_t *cfg, dspu::Sample &out);
31+
3132
status_t deconvolve(const config_t *cfg, const dspu::Sample &in, const dspu::Sample &ref, dspu::Sample &out);
33+
34+
/**
35+
* Normalize sample to the specified gain
36+
* @param dst sample to normalize
37+
* @param gain the maximum peak gain
38+
* @param mode the normalization mode
39+
* @return status of operation
40+
*/
41+
status_t normalize(dspu::Sample *dst, float gain, size_t mode);
3242
}
3343

3444
#endif

project.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
ARTIFACT_ID = ROOM_RAIDER
2323
ARTIFACT_NAME = room-raider
2424
ARTIFACT_DESC = Room-Raider - a tool for performing off-line impulse response capture of the room
25-
ARTIFACT_VERSION = 0.5.2
25+
ARTIFACT_VERSION = 0.5.3
2626

2727
#------------------------------------------------------------------------------
2828
# Plugin dependencies

src/main/cmdline.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,21 @@ namespace room_raider
4040
const char *s_desc;
4141
} option_t;
4242

43+
typedef struct cfg_flag_t
44+
{
45+
const char *name;
46+
ssize_t value;
47+
} cfg_flag_t;
48+
4349
static const option_t options[] =
4450
{
4551
{ "-d", "--deconvolve", true, "Deconvolve the captured signal" },
4652
{ "-ef", "--end-freq", false, "End frequency of the sine sweep" },
4753
{ "-g", "--gain", false, "Gain (in dB) of the sine sweep" },
4854
{ "-h", "--help", true, "Output this help message" },
4955
{ "-i", "--in-file", false, "Input audio file" },
56+
{ "-n", "--normalize", false, "Set normalization mode" },
57+
{ "-ng", "--norm-gain", false, "Set normalization peak gain (in dB)" },
5058
{ "-o", "--out-file", false, "Output audio file" },
5159
{ "-r", "--reference", false, "Reference audio file" },
5260
{ "-s", "--sweep", true, "Produce sine sweep signal" },
@@ -56,6 +64,15 @@ namespace room_raider
5664
{ NULL, NULL, false, NULL }
5765
};
5866

67+
const cfg_flag_t normalize_flags[] =
68+
{
69+
{ "none", NORM_NONE },
70+
{ "above", NORM_ABOVE },
71+
{ "below", NORM_BELOW },
72+
{ "always", NORM_ALWAYS },
73+
{ NULL, 0 }
74+
};
75+
5976
status_t print_usage(const char *name, bool fail)
6077
{
6178
LSPString buf, fmt;
@@ -143,6 +160,55 @@ namespace room_raider
143160
return STATUS_OK;
144161
}
145162

163+
const cfg_flag_t *find_config_flag(const LSPString *s, const cfg_flag_t *flags)
164+
{
165+
for (size_t i=0; (flags != NULL) && (flags->name != NULL); ++i, ++flags)
166+
{
167+
if (s->equals_ascii_nocase(flags->name))
168+
return flags;
169+
}
170+
return NULL;
171+
}
172+
173+
status_t parse_cmdline_enum(ssize_t *dst, const char *parameter, const char *val, const cfg_flag_t *flags)
174+
{
175+
LSPString in;
176+
if (!in.set_native(val))
177+
{
178+
fprintf(stderr, "Out of memory\n");
179+
return STATUS_NO_MEM;
180+
}
181+
182+
io::InStringSequence is(&in);
183+
expr::Tokenizer t(&is);
184+
const cfg_flag_t *flag = NULL;
185+
186+
switch (t.get_token(expr::TF_GET | expr::TF_XKEYWORDS))
187+
{
188+
case expr::TT_BAREWORD:
189+
if ((flag = find_config_flag(t.text_value(), flags)) == NULL)
190+
{
191+
fprintf(stderr, "Bad '%s' value\n", parameter);
192+
return STATUS_BAD_FORMAT;
193+
}
194+
break;
195+
196+
default:
197+
fprintf(stderr, "Bad '%s' value\n", parameter);
198+
return STATUS_BAD_FORMAT;
199+
}
200+
201+
if (t.get_token(expr::TF_GET) != expr::TT_EOF)
202+
{
203+
fprintf(stderr, "Bad '%s' value\n", parameter);
204+
return STATUS_INVALID_VALUE;
205+
}
206+
207+
*dst = flag->value;
208+
209+
return STATUS_OK;
210+
}
211+
146212
status_t parse_cmdline(config_t *cfg, int argc, const char **argv)
147213
{
148214
const char *cmd = argv[0], *val;
@@ -262,6 +328,16 @@ namespace room_raider
262328
if ((res = parse_cmdline_float(&cfg->fSweepLength, val, "sweep length")) != STATUS_OK)
263329
return res;
264330
}
331+
if ((val = options.get("--norm-gain")) != NULL)
332+
{
333+
if ((res = parse_cmdline_float(&cfg->fNormGain, val, "norm-gain")) != STATUS_OK)
334+
return res;
335+
}
336+
if ((val = options.get("--normalize")) != NULL)
337+
{
338+
if ((res = parse_cmdline_enum(&cfg->nNormalize, "normalize", val, normalize_flags)) != STATUS_OK)
339+
return res;
340+
}
265341

266342
return STATUS_OK;
267343
}

src/main/config.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ namespace room_raider
3434
fEndFreq = 20000.0f;
3535
fGain = 0.0f;
3636
fSweepLength = 20.0f;
37+
38+
nNormalize = NORM_NONE; // No normalization by default
39+
fNormGain = 0.0f; // 0 dB gain by default
3740
}
3841

3942
config_t::~config_t()
@@ -51,6 +54,9 @@ namespace room_raider
5154
fGain = 0.0f;
5255
fSweepLength = 20.0f;
5356

57+
nNormalize = NORM_NONE;
58+
fNormGain = 0.0f;
59+
5460
sInFile.clear();
5561
sOutFile.clear();
5662
sReference.clear();

src/main/dsp.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,10 @@ namespace room_raider
170170
// Even though we always use the same impulse response,
171171
// we initialise at every iteration to make sure the internal state of the convolver is re-initialisated.
172172
if (!sConvolver.init(vKernel, nBufferSize, 16, 0))
173+
{
174+
free_aligned(pData);
173175
return STATUS_NO_MEM;
176+
}
174177

175178
dsp::fill_zero(vInput, nIRSize);
176179
dsp::copy(vInput, in.getBuffer(ch), in.length());
@@ -198,4 +201,42 @@ namespace room_raider
198201
// Done.
199202
return STATUS_OK;
200203
}
204+
205+
status_t normalize(dspu::Sample *dst, float gain, size_t mode)
206+
{
207+
if (mode == NORM_NONE)
208+
return STATUS_OK;
209+
210+
float peak = 0.0f;
211+
for (size_t i=0, n=dst->channels(); i<n; ++i)
212+
{
213+
float cpeak = dsp::abs_max(dst->channel(i), dst->length());
214+
peak = lsp_max(peak, cpeak);
215+
}
216+
217+
// No peak detected?
218+
if (peak < 1e-6)
219+
return STATUS_OK;
220+
221+
switch (mode)
222+
{
223+
case NORM_BELOW:
224+
if (peak >= gain)
225+
return STATUS_OK;
226+
break;
227+
case NORM_ABOVE:
228+
if (peak <= gain)
229+
return STATUS_OK;
230+
break;
231+
default:
232+
break;
233+
}
234+
235+
// Adjust gain
236+
float k = gain / peak;
237+
for (size_t i=0, n=dst->channels(); i<n; ++i)
238+
dsp::mul_k2(dst->channel(i), k, dst->length());
239+
240+
return STATUS_OK;
241+
}
201242
}

src/main/tool.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
#define MIN_SAMPLE_RATE 8000
3434
#define MAX_SAMPLE_RATE 192000
3535

36+
#define MIN_GAIN -200.0f
37+
3638
namespace room_raider
3739
{
3840
using namespace lsp;
@@ -163,6 +165,10 @@ namespace room_raider
163165
// deconvolution
164166
deconvolve(cfg, in, ref, out);
165167

168+
// normalization
169+
float norm_gain = (cfg->fNormGain >= MIN_GAIN) ? dspu::db_to_gain(cfg->fNormGain) : 0.0f;
170+
normalize(&out, norm_gain, cfg->nNormalize);
171+
166172
// Save the sample to output
167173
if (out.save(&cfg->sOutFile) < 0)
168174
{

src/test/utest/cmdline.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ UTEST_BEGIN("room_raider", cmdline)
4444
UTEST_ASSERT(cfg->sOutFile.equals_ascii("output-file.wav"));
4545
UTEST_ASSERT(cfg->sReference.equals_ascii("reference-file.wav"));
4646
UTEST_ASSERT(cfg->nSampleRate == 88200);
47+
UTEST_ASSERT(float_equals_absolute(cfg->fNormGain, -3.0f));
48+
UTEST_ASSERT(cfg->nNormalize == room_raider::NORM_ALWAYS);
4749
}
4850

4951
void parse_cmdline(room_raider::config_t *cfg)
@@ -59,6 +61,8 @@ UTEST_BEGIN("room_raider", cmdline)
5961
"-o", "output-file.wav",
6062
"-r", "reference-file.wav",
6163
"-sr", "88200",
64+
"-ng", "-3.0",
65+
"-n", "ALWAYS",
6266
NULL
6367
};
6468

0 commit comments

Comments
 (0)