00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "Pitch.h"
00017 #include "Preferences.h"
00018
00019 #include <cmath>
00020
00021 float
00022 Pitch::getFrequencyForPitch(int midiPitch,
00023 float centsOffset,
00024 float concertA)
00025 {
00026 if (concertA <= 0.0) {
00027 concertA = Preferences::getInstance()->getTuningFrequency();
00028 }
00029 float p = float(midiPitch) + (centsOffset / 100);
00030 return concertA * powf(2.0, (p - 69.0) / 12.0);
00031 }
00032
00033 int
00034 Pitch::getPitchForFrequency(float frequency,
00035 float *centsOffsetReturn,
00036 float concertA)
00037 {
00038 if (concertA <= 0.0) {
00039 concertA = Preferences::getInstance()->getTuningFrequency();
00040 }
00041 float p = 12.0 * (log(frequency / (concertA / 2.0)) / log(2.0)) + 57.0;
00042
00043 int midiPitch = int(p + 0.00001);
00044 float centsOffset = (p - midiPitch) * 100.0;
00045
00046 if (centsOffset >= 50.0) {
00047 midiPitch = midiPitch + 1;
00048 centsOffset = -(100.0 - centsOffset);
00049 }
00050
00051 if (centsOffsetReturn) *centsOffsetReturn = centsOffset;
00052 return midiPitch;
00053 }
00054
00055 int
00056 Pitch::getPitchForFrequencyDifference(float frequencyA,
00057 float frequencyB,
00058 float *centsOffsetReturn,
00059 float concertA)
00060 {
00061 if (concertA <= 0.0) {
00062 concertA = Preferences::getInstance()->getTuningFrequency();
00063 }
00064
00065 if (frequencyA > frequencyB) {
00066 std::swap(frequencyA, frequencyB);
00067 }
00068
00069 float pA = 12.0 * (log(frequencyA / (concertA / 2.0)) / log(2.0)) + 57.0;
00070 float pB = 12.0 * (log(frequencyB / (concertA / 2.0)) / log(2.0)) + 57.0;
00071
00072 float p = pB - pA;
00073
00074 int midiPitch = int(p + 0.00001);
00075 float centsOffset = (p - midiPitch) * 100.0;
00076
00077 if (centsOffset >= 50.0) {
00078 midiPitch = midiPitch + 1;
00079 centsOffset = -(100.0 - centsOffset);
00080 }
00081
00082 if (centsOffsetReturn) *centsOffsetReturn = centsOffset;
00083 return midiPitch;
00084 }
00085
00086 static QString notes[] = {
00087 "C%1", "C#%1", "D%1", "D#%1",
00088 "E%1", "F%1", "F#%1", "G%1",
00089 "G#%1", "A%1", "A#%1", "B%1"
00090 };
00091
00092 static QString flatNotes[] = {
00093 "C%1", "Db%1", "D%1", "Eb%1",
00094 "E%1", "F%1", "Gb%1", "G%1",
00095 "Ab%1", "A%1", "Bb%1", "B%1"
00096 };
00097
00098 QString
00099 Pitch::getPitchLabel(int midiPitch,
00100 float centsOffset,
00101 bool useFlats)
00102 {
00103 int octave = -2;
00104
00105 if (midiPitch < 0) {
00106 while (midiPitch < 0) {
00107 midiPitch += 12;
00108 --octave;
00109 }
00110 } else {
00111 octave = midiPitch / 12 - 2;
00112 }
00113
00114 QString plain = (useFlats ? flatNotes : notes)[midiPitch % 12].arg(octave);
00115
00116 int ic = lrintf(centsOffset);
00117 if (ic == 0) return plain;
00118 else if (ic > 0) return QString("%1+%2c").arg(plain).arg(ic);
00119 else return QString("%1%2c").arg(plain).arg(ic);
00120 }
00121
00122 QString
00123 Pitch::getPitchLabelForFrequency(float frequency,
00124 float concertA,
00125 bool useFlats)
00126 {
00127 if (concertA <= 0.0) {
00128 concertA = Preferences::getInstance()->getTuningFrequency();
00129 }
00130 float centsOffset = 0.0;
00131 int midiPitch = getPitchForFrequency(frequency, ¢sOffset, concertA);
00132 return getPitchLabel(midiPitch, centsOffset, useFlats);
00133 }
00134
00135 QString
00136 Pitch::getLabelForPitchRange(int semis, float cents)
00137 {
00138 int ic = lrintf(cents);
00139
00140 if (ic == 0) {
00141 if (semis >= 12) {
00142 return QString("%1'%2").arg(semis/12).arg(semis - 12*(semis/12));
00143 } else {
00144 return QString("%1").arg(semis);
00145 }
00146 } else {
00147 if (ic > 0) {
00148 if (semis >= 12) {
00149 return QString("%1'%2+%3c").arg(semis/12).arg(semis - 12*(semis/12)).arg(ic);
00150 } else {
00151 return QString("%1+%3c").arg(semis).arg(ic);
00152 }
00153 } else {
00154 if (semis >= 12) {
00155 return QString("%1'%2%3c").arg(semis/12).arg(semis - 12*(semis/12)).arg(ic);
00156 } else {
00157 return QString("%1%3c").arg(semis).arg(ic);
00158 }
00159 }
00160 }
00161 }
00162
00163 bool
00164 Pitch::isFrequencyInMidiRange(float frequency,
00165 float concertA)
00166 {
00167 float centsOffset = 0.0;
00168 int midiPitch = getPitchForFrequency(frequency, ¢sOffset, concertA);
00169 return (midiPitch >= 0 && midiPitch < 128);
00170 }
00171