svcore  1.9
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 float
24  float centsOffset,
25  float concertA)
26 {
27  if (concertA <= 0.0) {
29  }
30  float p = float(midiPitch) + (centsOffset / 100);
31  return concertA * powf(2.0, (p - 69.0) / 12.0);
32 }
33 
34 int
36  float *centsOffsetReturn,
37  float concertA)
38 {
39  if (concertA <= 0.0) {
41  }
42  float p = 12.0 * (log(frequency / (concertA / 2.0)) / log(2.0)) + 57.0;
43 
44  int midiPitch = int(p + 0.00001);
45  float centsOffset = (p - midiPitch) * 100.0;
46 
47  if (centsOffset >= 50.0) {
48  midiPitch = midiPitch + 1;
49  centsOffset = -(100.0 - centsOffset);
50  }
51 
52  if (centsOffsetReturn) *centsOffsetReturn = centsOffset;
53  return midiPitch;
54 }
55 
56 int
58  float frequencyB,
59  float *centsOffsetReturn,
60  float concertA)
61 {
62  if (concertA <= 0.0) {
64  }
65 
66  if (frequencyA > frequencyB) {
67  std::swap(frequencyA, frequencyB);
68  }
69 
70  float pA = 12.0 * (log(frequencyA / (concertA / 2.0)) / log(2.0)) + 57.0;
71  float pB = 12.0 * (log(frequencyB / (concertA / 2.0)) / log(2.0)) + 57.0;
72 
73  float p = pB - pA;
74 
75  int midiPitch = int(p + 0.00001);
76  float centsOffset = (p - midiPitch) * 100.0;
77 
78  if (centsOffset >= 50.0) {
79  midiPitch = midiPitch + 1;
80  centsOffset = -(100.0 - centsOffset);
81  }
82 
83  if (centsOffsetReturn) *centsOffsetReturn = centsOffset;
84  return midiPitch;
85 }
86 
87 static QString notes[] = {
88  "C%1", "C#%1", "D%1", "D#%1",
89  "E%1", "F%1", "F#%1", "G%1",
90  "G#%1", "A%1", "A#%1", "B%1"
91 };
92 
93 static QString flatNotes[] = {
94  "C%1", "Db%1", "D%1", "Eb%1",
95  "E%1", "F%1", "Gb%1", "G%1",
96  "Ab%1", "A%1", "Bb%1", "B%1"
97 };
98 
99 QString
100 Pitch::getPitchLabel(int midiPitch,
101  float centsOffset,
102  bool useFlats)
103 {
105  int octave = baseOctave;
106 
107  // Note, this only gets the right octave number at octave
108  // boundaries because Cb is enharmonic with B (not B#) and B# is
109  // enharmonic with C (not Cb). So neither B# nor Cb will be
110  // spelled from a MIDI pitch + flats flag in isolation.
111 
112  if (midiPitch < 0) {
113  while (midiPitch < 0) {
114  midiPitch += 12;
115  --octave;
116  }
117  } else {
118  octave = midiPitch / 12 + baseOctave;
119  }
120 
121  QString plain = (useFlats ? flatNotes : notes)[midiPitch % 12].arg(octave);
122 
123  int ic = lrintf(centsOffset);
124  if (ic == 0) return plain;
125  else if (ic > 0) return QString("%1+%2c").arg(plain).arg(ic);
126  else return QString("%1%2c").arg(plain).arg(ic);
127 }
128 
129 QString
131  float concertA,
132  bool useFlats)
133 {
134  if (concertA <= 0.0) {
136  }
137  float centsOffset = 0.0;
138  int midiPitch = getPitchForFrequency(frequency, &centsOffset, concertA);
139  return getPitchLabel(midiPitch, centsOffset, useFlats);
140 }
141 
142 QString
143 Pitch::getLabelForPitchRange(int semis, float cents)
144 {
145  if (semis > 0) {
146  while (cents < 0.f) {
147  --semis;
148  cents += 100.f;
149  }
150  }
151  if (semis < 0) {
152  while (cents > 0.f) {
153  ++semis;
154  cents -= 100.f;
155  }
156  }
157 
158  int ic = lrintf(cents);
159 
160  if (ic == 0) {
161  if (semis >= 12) {
162  return QString("%1'%2").arg(semis/12).arg(semis - 12*(semis/12));
163  } else {
164  return QString("%1").arg(semis);
165  }
166  } else {
167  if (ic > 0) {
168  if (semis >= 12) {
169  return QString("%1'%2+%3c").arg(semis/12).arg(semis - 12*(semis/12)).arg(ic);
170  } else {
171  return QString("%1+%3c").arg(semis).arg(ic);
172  }
173  } else {
174  if (semis >= 12) {
175  return QString("%1'%2%3c").arg(semis/12).arg(semis - 12*(semis/12)).arg(ic);
176  } else {
177  return QString("%1%3c").arg(semis).arg(ic);
178  }
179  }
180  }
181 }
182 
183 bool
185  float concertA)
186 {
187  float centsOffset = 0.0;
188  int midiPitch = getPitchForFrequency(frequency, &centsOffset, concertA);
189  return (midiPitch >= 0 && midiPitch < 128);
190 }
191 
float getTuningFrequency() const
Definition: Preferences.h:52
static QString getPitchLabelForFrequency(float frequency, float concertA=0.0, bool useFlats=false)
Return a string describing the nearest MIDI pitch to the given frequency, with cents offset.
Definition: Pitch.cpp:130
static Preferences * getInstance()
Definition: Preferences.cpp:31
static QString getPitchLabel(int midiPitch, float centsOffset=0, bool useFlats=false)
Return a string describing the given MIDI pitch, with optional cents offset.
Definition: Pitch.cpp:100
static int getPitchForFrequency(float frequency, float *centsOffsetReturn=0, float concertA=0.0)
Return the nearest MIDI pitch to the given frequency.
Definition: Pitch.cpp:35
static QString flatNotes[]
Definition: Pitch.cpp:93
static QString notes[]
Definition: Pitch.cpp:87
static int getPitchForFrequencyDifference(float frequencyA, float frequencyB, float *centsOffsetReturn=0, float concertA=0.0)
Return the nearest MIDI pitch range to the given frequency range, that is, the difference in MIDI pit...
Definition: Pitch.cpp:57
static QString getLabelForPitchRange(int semis, float cents=0)
Return a string describing the given pitch range in octaves, semitones and cents.
Definition: Pitch.cpp:143
static float getFrequencyForPitch(int midiPitch, float centsOffset=0, float concertA=0.0)
Return the frequency at the given MIDI pitch plus centsOffset cents (1/100ths of a semitone).
Definition: Pitch.cpp:23
static bool isFrequencyInMidiRange(float frequency, float 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:184
int getOctaveOfLowestMIDINote() const
Definition: Preferences.h:100