1 /**********************************************************************
2
3 Audacity: A Digital Audio Editor
4 Audacity(R) is copyright (c) 1999-2012 Audacity Team.
5 License: GPL v2. See License.txt.
6
7 PitchName.cpp
8 Vaughan Johnson and Dominic Mazzoni.
9
10 ******************************************************************//**
11
12 \file PitchName.cpp
13 \brief Utilities for converting from frequency to pitch
14 and from pitch to absolute (e.g., C4 for middle C)
15 or nominal (A through G#) pitch name.
16
17 *//*******************************************************************/
18
19
20
21 #include "PitchName.h"
22
23 #include <math.h>
24 #include <stdio.h>
25
26 #include "Internat.h"
27
28
FreqToMIDInote(const double freq)29 double FreqToMIDInote(const double freq)
30 {
31 // Make the calculation relative to A440 (A4), note number 69.
32 return (69.0 + (12.0 * (log(freq / 440.0) / log(2.0))));
33 }
34
MIDInoteToFreq(const double dMIDInote)35 double MIDInoteToFreq(const double dMIDInote)
36 {
37 return (440.0 * pow(2.0, (dMIDInote - 69.0) / 12.0));
38 }
39
PitchIndex(const double dMIDInote)40 unsigned int PitchIndex(const double dMIDInote)
41 {
42 // MIDI numbers can be negative. Round in the right direction.
43 double dRound = (dMIDInote < 0.0) ? -0.5 : 0.5;
44 int nPitchIndex = ((int)(dMIDInote + dRound) % 12);
45
46 // Because of the modulo, we know we're within 12 of positive, if dMIDInote is negative.
47 if (nPitchIndex < 0)
48 nPitchIndex += 12;
49
50 return nPitchIndex;
51 }
52
PitchOctave(const double dMIDInote)53 int PitchOctave(const double dMIDInote)
54 {
55 double dRound = (dMIDInote < 0.0) ? -0.5 : 0.5;
56 return ((int)((dMIDInote + dRound) / 12.0) - 1);
57 }
58
59
PitchName(const double dMIDInote,const PitchNameChoice choice)60 TranslatableString PitchName(const double dMIDInote, const PitchNameChoice choice)
61 {
62 static const TranslatableString sharpnames[12] = {
63 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
64 XO("C"),
65 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
66 XO("C\u266f"),
67 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
68 XO("D"),
69 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
70 XO("D\u266f"),
71 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
72 XO("E"),
73 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
74 XO("F"),
75 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
76 XO("F\u266f"),
77 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
78 XO("G"),
79 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
80 XO("G\u266f"),
81 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
82 XO("A"),
83 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
84 XO("A\u266f"),
85 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
86 XO("B"),
87 };
88
89 static const TranslatableString flatnames[12] = {
90 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
91 XO("C"),
92 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
93 XO("D\u266d"),
94 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
95 XO("D"),
96 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
97 XO("E\u266d"),
98 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
99 XO("E"),
100 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
101 XO("F"),
102 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
103 XO("G\u266d"),
104 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
105 XO("G"),
106 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
107 XO("A\u266d"),
108 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
109 XO("A"),
110 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
111 XO("B\u266d"),
112 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
113 XO("B"),
114 };
115
116 static const TranslatableString bothnames[12] = {
117 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
118 XO("C"),
119 /* i18n-hint: Two, alternate names of a musical note in the 12-tone chromatic scale */
120 XO("C\u266f/D\u266d"),
121 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
122 XO("D"),
123 /* i18n-hint: Two, alternate names of a musical note in the 12-tone chromatic scale */
124 XO("D\u266f/E\u266d"),
125 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
126 XO("E"),
127 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
128 XO("F"),
129 /* i18n-hint: Two, alternate names of a musical note in the 12-tone chromatic scale */
130 XO("F\u266f/G\u266d"),
131 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
132 XO("G"),
133 /* i18n-hint: Two, alternate names of a musical note in the 12-tone chromatic scale */
134 XO("G\u266f/A\u266d"),
135 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
136 XO("A"),
137 /* i18n-hint: Two, alternate names of a musical note in the 12-tone chromatic scale */
138 XO("A\u266f/B\u266d"),
139 /* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
140 XO("B"),
141 };
142
143 const TranslatableString *table = nullptr;
144 switch ( choice ) {
145 case PitchNameChoice::Sharps: table = sharpnames; break;
146 case PitchNameChoice::Flats: table = flatnames; break;
147 case PitchNameChoice::Both: table = bothnames; break;
148 default: wxASSERT(false); break;
149 }
150
151 return table[PitchIndex(dMIDInote)];
152 }
153
PitchName_Absolute(const double dMIDInote,const PitchNameChoice choice)154 TranslatableString PitchName_Absolute(const double dMIDInote, const PitchNameChoice choice)
155 {
156 // The format string is not localized. Should it be?
157 return Verbatim( wxT("%s%d") )
158 .Format( PitchName(dMIDInote, choice), PitchOctave(dMIDInote) );
159 }
160
PitchToMIDInote(const unsigned int nPitchIndex,const int nPitchOctave)161 double PitchToMIDInote(const unsigned int nPitchIndex, const int nPitchOctave)
162 {
163 return ((double)nPitchIndex + (((double)nPitchOctave + 1.0) * 12.0));
164 }
165
PitchToFreq(const unsigned int nPitchIndex,const int nPitchOctave)166 double PitchToFreq(const unsigned int nPitchIndex, const int nPitchOctave)
167 {
168 return MIDInoteToFreq(PitchToMIDInote(nPitchIndex, nPitchOctave));
169 }
170