Skip to content

Commit

Permalink
unitSum normalization; better param names in HPCP
Browse files Browse the repository at this point in the history
Add unitSum normalization (closes #348). Print warning when trying to
apply unitSum together with band preset (this combination was not tested).

Some code cleanup.

Rename 'splitFrequency' parameter to 'bandSplitFrequency'. This way it
is easier to see in documentation that it is related to bandPreset. Update
extractors using this parameter.

Better description for non-linear post processing in the doc.
  • Loading branch information
dbogdanov committed Dec 23, 2016
1 parent a1a8ecc commit 1ed6d72
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 27 deletions.
4 changes: 2 additions & 2 deletions src/algorithms/extractor/tonalextractor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ void TonalExtractor::configure() {
_hpcpChord->configure("referenceFrequency", tuningFrequency,
"minFrequency", 40.0,
"nonLinear", true,
"splitFrequency", 500.0,
"bandSplitFrequency", 500.0,
"maxFrequency", 5000.0,
"bandPreset", true,
"windowSize", 0.5,
Expand All @@ -139,7 +139,7 @@ void TonalExtractor::configure() {
_hpcpTuning->configure("referenceFrequency", tuningFrequency,
"minFrequency", 40.0,
"nonLinear", true,
"splitFrequency", 500.0,
"bandSplitFrequency", 500.0,
"maxFrequency", 5000.0,
"bandPreset", true,
"windowSize", 0.5,
Expand Down
47 changes: 31 additions & 16 deletions src/algorithms/spectral/hpcp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const char* HPCP::name = "HPCP";
const char* HPCP::category = "Tonal";
const char* HPCP::description = DOC("Computes a Harmonic Pitch Class Profile (HPCP) from the spectral peaks of a signal. HPCP is a k*12 dimensional vector which represents the intensities of the twelve (k==1) semitone pitch classes (corresponsing to notes from A to G#), or subdivisions of these (k>1).\n"
"\n"
"Exceptions are thrown if \"minFrequency\", \"splitFrequency\" and \"maxFrequency\" are not separated by at least 200Hz from each other, requiring that \"maxFrequency\" be greater than \"splitFrequency\" and \"splitFrequency\" be greater than \"minFrequency\". Other exceptions are thrown if input vectors have different size, if parameter \"size\" is not a positive non-zero multiple of 12 or if \"windowSize\" is less than one hpcp bin (12/size).\n"
"Exceptions are thrown if \"minFrequency\", \"bandSplitFrequency\" and \"maxFrequency\" are not separated by at least 200Hz from each other, requiring that \"maxFrequency\" be greater than \"bandSplitFrequency\" and \"bandSplitFrequency\" be greater than \"minFrequency\". Other exceptions are thrown if input vectors have different size, if parameter \"size\" is not a positive non-zero multiple of 12 or if \"windowSize\" is less than one hpcp bin (12/size).\n"
"\n"
"References:\n"
" [1] T. Fujishima, \"Realtime Chord Recognition of Musical Sound: A System\n"
Expand Down Expand Up @@ -66,7 +66,7 @@ void HPCP::configure() {
throw EssentiaException("HPCP: Minimum and maximum frequencies are too close");
}

_splitFrequency = parameter("splitFrequency").toReal();
_splitFrequency = parameter("bandSplitFrequency").toReal();
_bandPreset = parameter("bandPreset").toBool();

if (_bandPreset) {
Expand All @@ -86,10 +86,15 @@ void HPCP::configure() {

_nonLinear = parameter("nonLinear").toBool();
_maxShifted = parameter("maxShifted").toBool();
_normalized = parameter("normalized").toBool();

string normalized = toLower(parameter("normalized").toString());
if (normalized == "none") _normalized = N_NONE;
if (normalized == "unitsum") _normalized = N_UNIT_SUM;
if (normalized == "unitmax") _normalized = N_UNIT_MAX;

if (_nonLinear && !_normalized) {
throw EssentiaException("HPCP: Cannot apply non-linear filter when HPCP vector is not normalized");

if (_nonLinear && _normalized != N_UNIT_MAX) {
throw EssentiaException("HPCP: Cannot apply non-linear filter when HPCP vector is not normalized to unit max.");
}

initHarmonicContributionTable();
Expand Down Expand Up @@ -254,24 +259,34 @@ void HPCP::compute() {
}

// Normalize the HPCP vector
if (_normalized) {
if (_bandPreset) {

if (_bandPreset) {
if (_normalized == N_UNIT_MAX) {
normalize(hpcp_LO);
normalize(hpcp_HI);
for (int i=0; i<(int)hpcp.size(); i++) {
hpcp[i] = hpcp_LO[i] + hpcp_HI[i];
}
}
normalize(hpcp);
} else {
if (_bandPreset) {
for (int i=0; i<(int)hpcp.size(); i++) {
hpcp[i] = hpcp_LO[i] + hpcp_HI[i];
}
else if (_normalized == N_UNIT_SUM) {
// TODO does it makes sense to apply band preset together with unit sum normalization?
E_WARNING("HPCP: applying band preset together with unit sum normalization was not tested.");
normalizeSum(hpcp_LO);
normalizeSum(hpcp_HI);
}

for (int i=0; i<(int)hpcp.size(); i++) {
hpcp[i] = hpcp_LO[i] + hpcp_HI[i];
}
}

if (_normalized == N_UNIT_MAX) {
normalize(hpcp);
}
else if (_normalized == N_UNIT_SUM) {
normalizeSum(hpcp);
}

// Perform the Jordi non-linear post-processing step
// This makes small values (below 0.6) even smaller
// while boosting further values close to 1.
if (_nonLinear) {
for (int i=0; i<(int)hpcp.size(); i++) {
hpcp[i] = sin(hpcp[i] * M_PI * 0.5);
Expand Down
13 changes: 9 additions & 4 deletions src/algorithms/spectral/hpcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ class HPCP : public Algorithm {
declareParameter("referenceFrequency", "the reference frequency for semitone index calculation, corresponding to A3 [Hz]", "(0,inf)", 440.0);
declareParameter("harmonics", "number of harmonics for frequency contribution, 0 indicates exclusive fundamental frequency contribution", "[0,inf)", 0); // 8 for chord estimation
declareParameter("bandPreset", "enables whether to use a band preset", "{true,false}", true);
declareParameter("bandSplitFrequency", "the split frequency for low and high bands, not used if bandPreset is false [Hz]", "(0,inf)", 500.0);
declareParameter("minFrequency", "the minimum frequency that contributes to the HPCP [Hz] (the difference between the min and split frequencies must not be less than 200.0 Hz)", "(0,inf)", 40.0);
declareParameter("maxFrequency", "the maximum frequency that contributes to the HPCP [Hz] (the difference between the max and split frequencies must not be less than 200.0 Hz)", "(0,inf)", 5000.0);
declareParameter("splitFrequency", "the split frequency for low and high bands, not used if bandPreset is false [Hz]", "(0,inf)", 500.0);
declareParameter("weightType", "type of weighting function for determining frequency contribution", "{none,cosine,squaredCosine}", "squaredCosine");
declareParameter("nonLinear", "enables whether to apply a Jordi non-linear post-processing function to the output", "{true,false}", false);
declareParameter("nonLinear", "apply non-linear post-processing to the output (use with normalized='unitMax'). Boosts values close to 1, decreases values close to 0.", "{true,false}", false);
declareParameter("windowSize", "the size, in semitones, of the window used for the weighting", "(0,12]", 1.0);
declareParameter("sampleRate", "the sampling rate of the audio signal [Hz]", "(0,inf)", 44100.);
declareParameter("maxShifted", "whether to shift the HPCP vector so that the maximum peak is at index 0", "{true,false}", false);
declareParameter("normalized", "whether to normalize the HPCP vector", "{true,false}", true);
declareParameter("normalized", "whether to normalize the HPCP vector", "{none,unitSum,unitMax}", "unitMax");
}

void configure();
Expand Down Expand Up @@ -90,9 +90,14 @@ class HPCP : public Algorithm {
NONE, COSINE, SQUARED_COSINE
};
WeightType _weightType;

enum NormalizeType {
N_NONE, N_UNIT_MAX, N_UNIT_SUM
};
NormalizeType _normalized;

bool _nonLinear;
bool _maxShifted;
bool _normalized;

std::vector<HarmonicPeak> _harmonicPeaks;
};
Expand Down
4 changes: 2 additions & 2 deletions src/examples/extractor_music/MusicTonalDescriptors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ void MusicTonalDescriptors::createNetwork(SourceBase& source, Pool& pool){
"bandPreset", true,
"minFrequency", 40.0,
"maxFrequency", 5000.0,
"splitFrequency", 500.0,
"bandSplitFrequency", 500.0,
"weightType", "cosine",
"nonLinear", true,
"windowSize", 0.5);
Expand Down Expand Up @@ -160,7 +160,7 @@ void MusicTonalDescriptors::createNetwork(SourceBase& source, Pool& pool){
"bandPreset", true,
"minFrequency", 40.0,
"maxFrequency", 5000.0,
"splitFrequency", 500.0,
"bandSplitFrequency", 500.0,
"weightType", "cosine",
"nonLinear", true,
"windowSize", 0.5);
Expand Down
2 changes: 1 addition & 1 deletion src/examples/freesound/FreesoundTonalDescriptors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ void FreesoundTonalDescriptors ::createTuningFrequencyNetwork(SourceBase& source
"bandPreset", true,
"minFrequency", 40.0,
"maxFrequency", 5000.0,
"splitFrequency", 500.0,
"bandSplitFrequency", 500.0,
"weightType", "cosine",
"nonLinear", true,
"windowSize", 0.5);
Expand Down
4 changes: 2 additions & 2 deletions src/examples/outdated/streaming_extractortonal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ void TonalDescriptors(SourceBase& input, Pool& pool, const Pool& options, const
"bandPreset", true,
"minFrequency", 40.0,
"maxFrequency", 5000.0,
"splitFrequency", 500.0,
"bandSplitFrequency", 500.0,
"weightType", "cosine",
"nonLinear", true,
"windowSize", 0.5);
Expand Down Expand Up @@ -238,7 +238,7 @@ void TonalDescriptors(SourceBase& input, Pool& pool, const Pool& options, const
"bandPreset", true,
"minFrequency", 40.0,
"maxFrequency", 5000.0,
"splitFrequency", 500.0,
"bandSplitFrequency", 500.0,
"weightType", "cosine",
"nonLinear", true,
"windowSize", 0.5);
Expand Down

0 comments on commit 1ed6d72

Please sign in to comment.