Mercurial > hg > svcore
changeset 1025:88b54a185a0a
Use double instead of float for frequencies in Pitch, just for confidence
author | Chris Cannam |
---|---|
date | Mon, 08 Dec 2014 15:37:12 +0000 |
parents | d1ce7a4a920b |
children | 01a90c025eaa ce1077bd663a abe13fe10ed6 d74ebd2d2c49 |
files | base/Pitch.cpp base/Pitch.h base/test/TestPitch.h |
diffstat | 3 files changed, 96 insertions(+), 53 deletions(-) [+] |
line wrap: on
line diff
--- a/base/Pitch.cpp Tue Dec 02 17:53:17 2014 +0000 +++ b/base/Pitch.cpp Mon Dec 08 15:37:12 2014 +0000 @@ -19,45 +19,49 @@ #include <cmath> -float +double Pitch::getFrequencyForPitch(int midiPitch, - float centsOffset, - float concertA) + double centsOffset, + double concertA) { if (concertA <= 0.0) { concertA = Preferences::getInstance()->getTuningFrequency(); } - float p = float(midiPitch) + (centsOffset / 100); - return concertA * powf(2.0, (p - 69.0) / 12.0); + double p = double(midiPitch) + (centsOffset / 100); + return concertA * pow(2.0, (p - 69.0) / 12.0); } int -Pitch::getPitchForFrequency(float frequency, - float *centsOffsetReturn, - float concertA) +Pitch::getPitchForFrequency(double frequency, + double *centsOffsetReturn, + double concertA) { if (concertA <= 0.0) { concertA = Preferences::getInstance()->getTuningFrequency(); } - float p = 12.0 * (log(frequency / (concertA / 2.0)) / log(2.0)) + 57.0; + double p = 12.0 * (log(frequency / (concertA / 2.0)) / log(2.0)) + 57.0; - int midiPitch = int(p + 0.00001); - float centsOffset = (p - midiPitch) * 100.0; + int midiPitch = int(round(p)); + double centsOffset = (p - midiPitch) * 100.0; if (centsOffset >= 50.0) { midiPitch = midiPitch + 1; centsOffset = -(100.0 - centsOffset); } + if (centsOffset < -50.0) { + midiPitch = midiPitch - 1; + centsOffset = (100.0 + centsOffset); + } if (centsOffsetReturn) *centsOffsetReturn = centsOffset; return midiPitch; } int -Pitch::getPitchForFrequencyDifference(float frequencyA, - float frequencyB, - float *centsOffsetReturn, - float concertA) +Pitch::getPitchForFrequencyDifference(double frequencyA, + double frequencyB, + double *centsOffsetReturn, + double concertA) { if (concertA <= 0.0) { concertA = Preferences::getInstance()->getTuningFrequency(); @@ -67,13 +71,13 @@ std::swap(frequencyA, frequencyB); } - float pA = 12.0 * (log(frequencyA / (concertA / 2.0)) / log(2.0)) + 57.0; - float pB = 12.0 * (log(frequencyB / (concertA / 2.0)) / log(2.0)) + 57.0; + double pA = 12.0 * (log(frequencyA / (concertA / 2.0)) / log(2.0)) + 57.0; + double pB = 12.0 * (log(frequencyB / (concertA / 2.0)) / log(2.0)) + 57.0; - float p = pB - pA; + double p = pB - pA; int midiPitch = int(p + 0.00001); - float centsOffset = (p - midiPitch) * 100.0; + double centsOffset = (p - midiPitch) * 100.0; if (centsOffset >= 50.0) { midiPitch = midiPitch + 1; @@ -129,7 +133,7 @@ QString Pitch::getPitchLabel(int midiPitch, - float centsOffset, + double centsOffset, bool useFlats) { int note, octave; @@ -137,42 +141,42 @@ QString plain = (useFlats ? flatNotes : notes)[note].arg(octave); - int ic = lrintf(centsOffset); + int ic = lrint(centsOffset); if (ic == 0) return plain; else if (ic > 0) return QString("%1+%2c").arg(plain).arg(ic); else return QString("%1%2c").arg(plain).arg(ic); } QString -Pitch::getPitchLabelForFrequency(float frequency, - float concertA, +Pitch::getPitchLabelForFrequency(double frequency, + double concertA, bool useFlats) { if (concertA <= 0.0) { concertA = Preferences::getInstance()->getTuningFrequency(); } - float centsOffset = 0.0; + double centsOffset = 0.0; int midiPitch = getPitchForFrequency(frequency, ¢sOffset, concertA); return getPitchLabel(midiPitch, centsOffset, useFlats); } QString -Pitch::getLabelForPitchRange(int semis, float cents) +Pitch::getLabelForPitchRange(int semis, double cents) { if (semis > 0) { - while (cents < 0.f) { + while (cents < 0.0) { --semis; - cents += 100.f; + cents += 100.0; } } if (semis < 0) { - while (cents > 0.f) { + while (cents > 0.0) { ++semis; - cents -= 100.f; + cents -= 100.0; } } - int ic = lrintf(cents); + int ic = lrint(cents); if (ic == 0) { if (semis >= 12) { @@ -198,10 +202,10 @@ } bool -Pitch::isFrequencyInMidiRange(float frequency, - float concertA) +Pitch::isFrequencyInMidiRange(double frequency, + double concertA) { - float centsOffset = 0.0; + double centsOffset = 0.0; int midiPitch = getPitchForFrequency(frequency, ¢sOffset, concertA); return (midiPitch >= 0 && midiPitch < 128); }
--- a/base/Pitch.h Tue Dec 02 17:53:17 2014 +0000 +++ b/base/Pitch.h Mon Dec 08 15:37:12 2014 +0000 @@ -30,9 +30,9 @@ * for the A at MIDI pitch 69; otherwise use the tuning frequency * specified in the application preferences (default 440Hz). */ - static float getFrequencyForPitch(int midiPitch, - float centsOffset = 0, - float concertA = 0.0); + static double getFrequencyForPitch(int midiPitch, + double centsOffset = 0, + double concertA = 0.0); /** * Return the nearest MIDI pitch to the given frequency. @@ -46,9 +46,22 @@ * for the A at MIDI pitch 69; otherwise use the tuning frequency * specified in the application preferences (default 440Hz). */ - static int getPitchForFrequency(float frequency, - float *centsOffsetReturn = 0, - float concertA = 0.0); + static int getPitchForFrequency(double frequency, + double *centsOffsetReturn = 0, + double concertA = 0.0); + + /** + * Compatibility version of getPitchForFrequency accepting float + * pointer argument. + */ + static int getPitchForFrequency(double frequency, + float *centsOffsetReturn, + double concertA = 0.0) { + double c; + int p = getPitchForFrequency(frequency, &c, concertA); + if (centsOffsetReturn) *centsOffsetReturn = float(c); + return p; + } /** * Return the nearest MIDI pitch range to the given frequency @@ -64,12 +77,27 @@ * for the A at MIDI pitch 69; otherwise use the tuning frequency * specified in the application preferences (default 440Hz). */ - static int getPitchForFrequencyDifference(float frequencyA, - float frequencyB, - float *centsOffsetReturn = 0, - float concertA = 0.0); + static int getPitchForFrequencyDifference(double frequencyA, + double frequencyB, + double *centsOffsetReturn = 0, + double concertA = 0.0); /** + * Compatibility version of getPitchForFrequencyDifference + * accepting float pointer argument. + */ + static int getPitchForFrequencyDifference(double frequencyA, + double frequencyB, + float *centsOffsetReturn, + double concertA = 0.0) { + double c; + int p = getPitchForFrequencyDifference(frequencyA, frequencyB, + &c, concertA); + if (centsOffsetReturn) *centsOffsetReturn = float(c); + return p; + } + + /** * Return the MIDI pitch for the given note number (0-12 where 0 * is C) and octave number. The octave numbering system is based * on the application preferences (default is C4 = middle C, @@ -99,7 +127,7 @@ * e.g. Bb3 instead of A#3. */ static QString getPitchLabel(int midiPitch, - float centsOffset = 0, + double centsOffset = 0, bool useFlats = false); /** @@ -113,15 +141,15 @@ * If useFlats is true, spell notes with flats instead of sharps, * e.g. Bb3 instead of A#3. */ - static QString getPitchLabelForFrequency(float frequency, - float concertA = 0.0, + static QString getPitchLabelForFrequency(double frequency, + double concertA = 0.0, bool useFlats = false); /** * Return a string describing the given pitch range in octaves, * semitones and cents. This is in the form e.g. "1'2+4c". */ - static QString getLabelForPitchRange(int semis, float cents = 0); + static QString getLabelForPitchRange(int semis, double cents = 0); /** * Return true if the given frequency falls within the range of @@ -134,8 +162,8 @@ * for the A at MIDI pitch 69; otherwise use the tuning frequency * specified in the application preferences (default 440Hz). */ - static bool isFrequencyInMidiRange(float frequency, - float concertA = 0.0); + static bool isFrequencyInMidiRange(double frequency, + double concertA = 0.0); };
--- a/base/test/TestPitch.h Tue Dec 02 17:53:17 2014 +0000 +++ b/base/test/TestPitch.h Mon Dec 08 15:37:12 2014 +0000 @@ -72,18 +72,29 @@ QCOMPARE(Pitch::getPitchLabelForFrequency(261.63, 440, false), QString("C4")); } -#define MIDDLE_C 261.6255653f +#define MIDDLE_C 261.6255653005986 void frequencyForPitch() { QCOMPARE(Pitch::getFrequencyForPitch(60, 0), MIDDLE_C); - QCOMPARE(Pitch::getFrequencyForPitch(69, 0), 440.f); - QCOMPARE(Pitch::getFrequencyForPitch(60, 0, 220), MIDDLE_C / 2.f); - QCOMPARE(Pitch::getFrequencyForPitch(69, 0, 220), 220.f); + QCOMPARE(Pitch::getFrequencyForPitch(69, 0), 440.0); + QCOMPARE(Pitch::getFrequencyForPitch(60, 0, 220), MIDDLE_C / 2.0); + QCOMPARE(Pitch::getFrequencyForPitch(69, 0, 220), 220.0); } void pitchForFrequency() { + double centsOffset = 0.0; + QCOMPARE(Pitch::getPitchForFrequency(MIDDLE_C, ¢sOffset), 60); + QCOMPARE(centsOffset, 0.0); + QCOMPARE(Pitch::getPitchForFrequency(261.0, ¢sOffset), 60); + QCOMPARE(int(centsOffset), -4); + QCOMPARE(Pitch::getPitchForFrequency(440.0, ¢sOffset), 69); + QCOMPARE(centsOffset, 0.0); + } + + void pitchForFrequencyF() + { float centsOffset = 0.f; QCOMPARE(Pitch::getPitchForFrequency(MIDDLE_C, ¢sOffset), 60); QCOMPARE(centsOffset, 0.f);