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