Pitch.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7  This file copyright 2006 Chris Cannam.
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2 of the
12  License, or (at your option) any later version. See the file
13  COPYING included with this distribution for more information.
14 */
15 
16 #include "Pitch.h"
17 #include "Preferences.h"
18 #include "system/System.h"
19 
20 #include <cmath>
21 
22 double
24  double centsOffset,
25  double concertA)
26 {
27  if (concertA <= 0.0) {
29  }
30  double p = double(midiPitch) + (centsOffset / 100);
31  return concertA * pow(2.0, (p - 69.0) / 12.0);
32 }
33 
34 int
35 Pitch::getPitchForFrequency(double frequency,
36  double *centsOffsetReturn,
37  double concertA)
38 {
39  if (concertA <= 0.0) {
41  }
42  double p = 12.0 * (log(frequency / (concertA / 2.0)) / log(2.0)) + 57.0;
43 
44  int midiPitch = int(round(p));
45  double centsOffset = (p - midiPitch) * 100.0;
46 
47  if (centsOffset >= 50.0) {
48  midiPitch = midiPitch + 1;
49  centsOffset = -(100.0 - centsOffset);
50  }
51  if (centsOffset < -50.0) {
52  midiPitch = midiPitch - 1;
53  centsOffset = (100.0 + centsOffset);
54  }
55 
56  if (centsOffsetReturn) *centsOffsetReturn = centsOffset;
57  return midiPitch;
58 }
59 
60 int
62  double frequencyB,
63  double *centsOffsetReturn,
64  double concertA)
65 {
66  if (concertA <= 0.0) {
68  }
69 
70  if (frequencyA > frequencyB) {
71  std::swap(frequencyA, frequencyB);
72  }
73 
74  double pA = 12.0 * (log(frequencyA / (concertA / 2.0)) / log(2.0)) + 57.0;
75  double pB = 12.0 * (log(frequencyB / (concertA / 2.0)) / log(2.0)) + 57.0;
76 
77  double p = pB - pA;
78 
79  int midiPitch = int(p + 0.00001);
80  double centsOffset = (p - midiPitch) * 100.0;
81 
82  if (centsOffset >= 50.0) {
83  midiPitch = midiPitch + 1;
84  centsOffset = -(100.0 - centsOffset);
85  }
86 
87  if (centsOffsetReturn) *centsOffsetReturn = centsOffset;
88  return midiPitch;
89 }
90 
91 static QString notes[] = {
92  "C%1", "C#%1", "D%1", "D#%1",
93  "E%1", "F%1", "F#%1", "G%1",
94  "G#%1", "A%1", "A#%1", "B%1"
95 };
96 
97 static QString flatNotes[] = {
98  "C%1", "Db%1", "D%1", "Eb%1",
99  "E%1", "F%1", "Gb%1", "G%1",
100  "Ab%1", "A%1", "Bb%1", "B%1"
101 };
102 
103 int
104 Pitch::getPitchForNoteAndOctave(int note, int octave)
105 {
107  return (octave - baseOctave) * 12 + note;
108 }
109 
110 void
111 Pitch::getNoteAndOctaveForPitch(int midiPitch, int &note, int &octave)
112 {
114 
115  octave = baseOctave;
116 
117  // Note, this only gets the right octave number at octave
118  // boundaries because Cb is enharmonic with B (not B#) and B# is
119  // enharmonic with C (not Cb). So neither B# nor Cb will be
120  // spelled from a MIDI pitch + flats flag in isolation.
121 
122  if (midiPitch < 0) {
123  while (midiPitch < 0) {
124  midiPitch += 12;
125  --octave;
126  }
127  } else {
128  octave = midiPitch / 12 + baseOctave;
129  }
130 
131  note = midiPitch % 12;
132 }
133 
134 QString
135 Pitch::getPitchLabel(int midiPitch,
136  double centsOffset,
137  bool useFlats)
138 {
139  int note, octave;
140  getNoteAndOctaveForPitch(midiPitch, note, octave);
141 
142  QString plain = (useFlats ? flatNotes : notes)[note].arg(octave);
143 
144  long ic = lrint(centsOffset);
145  if (ic == 0) return plain;
146  else if (ic > 0) return QString("%1+%2c").arg(plain).arg(ic);
147  else return QString("%1%2c").arg(plain).arg(ic);
148 }
149 
150 QString
152  double concertA,
153  bool useFlats)
154 {
155  if (concertA <= 0.0) {
157  }
158  double centsOffset = 0.0;
159  int midiPitch = getPitchForFrequency(frequency, &centsOffset, concertA);
160  return getPitchLabel(midiPitch, centsOffset, useFlats);
161 }
162 
163 QString
164 Pitch::getLabelForPitchRange(int semis, double cents)
165 {
166  if (semis > 0) {
167  while (cents < 0.0) {
168  --semis;
169  cents += 100.0;
170  }
171  }
172  if (semis < 0) {
173  while (cents > 0.0) {
174  ++semis;
175  cents -= 100.0;
176  }
177  }
178 
179  long ic = lrint(cents);
180 
181  if (ic == 0) {
182  if (semis >= 12) {
183  return QString("%1'%2").arg(semis/12).arg(semis - 12*(semis/12));
184  } else {
185  return QString("%1").arg(semis);
186  }
187  } else {
188  if (ic > 0) {
189  if (semis >= 12) {
190  return QString("%1'%2+%3c").arg(semis/12).arg(semis - 12*(semis/12)).arg(ic);
191  } else {
192  return QString("%1+%3c").arg(semis).arg(ic);
193  }
194  } else {
195  if (semis >= 12) {
196  return QString("%1'%2%3c").arg(semis/12).arg(semis - 12*(semis/12)).arg(ic);
197  } else {
198  return QString("%1%3c").arg(semis).arg(ic);
199  }
200  }
201  }
202 }
203 
204 bool
206  double concertA)
207 {
208  double centsOffset = 0.0;
209  int midiPitch = getPitchForFrequency(frequency, &centsOffset, concertA);
210  return (midiPitch >= 0 && midiPitch < 128);
211 }
212 
static int getPitchForNoteAndOctave(int note, int octave)
Return the MIDI pitch for the given note number (0-12 where 0 is C) and octave number.
Definition: Pitch.cpp:104
static double getFrequencyForPitch(int midiPitch, double centsOffset=0, double concertA=0.0)
Return the frequency at the given MIDI pitch plus centsOffset cents (1/100ths of a semitone)...
Definition: Pitch.cpp:23
int getOctaveOfLowestMIDINote() const
Definition: Preferences.h:108
static QString getLabelForPitchRange(int semis, double cents=0)
Return a string describing the given pitch range in octaves, semitones and cents. ...
Definition: Pitch.cpp:164
static Preferences * getInstance()
Definition: Preferences.cpp:31
static QString getPitchLabelForFrequency(double frequency, double concertA=0.0, bool useFlats=false)
Return a string describing the nearest MIDI pitch to the given frequency, with cents offset...
Definition: Pitch.cpp:151
static QString flatNotes[]
Definition: Pitch.cpp:97
static QString notes[]
Definition: Pitch.cpp:91
static void getNoteAndOctaveForPitch(int midiPitch, int &note, int &octave)
Return the note number (0-12 where 0 is C) and octave number for the given MIDI pitch.
Definition: Pitch.cpp:111
static bool isFrequencyInMidiRange(double frequency, double concertA=0.0)
Return true if the given frequency falls within the range of MIDI note pitches, plus or minus half a ...
Definition: Pitch.cpp:205
static int getPitchForFrequencyDifference(double frequencyA, double frequencyB, double *centsOffsetReturn=0, double concertA=0.0)
Return the nearest MIDI pitch range to the given frequency range, that is, the difference in MIDI pit...
Definition: Pitch.cpp:61
double getTuningFrequency() const
Definition: Preferences.h:50
static int getPitchForFrequency(double frequency, double *centsOffsetReturn=0, double concertA=0.0)
Return the nearest MIDI pitch to the given frequency.
Definition: Pitch.cpp:35
static QString getPitchLabel(int midiPitch, double centsOffset=0, bool useFlats=false)
Return a string describing the given MIDI pitch, with optional cents offset.
Definition: Pitch.cpp:135