audacia/src/PitchName.cpp
Paul Licameli 5e7d41ec07 Each .cpp/.mm file includes corresponding header before any other...
... except Audacity.h

This forces us to make each header contain all forward declarations or nested
headers that it requires, rather than depend on context.
2019-03-17 22:54:52 -04:00

170 lines
6.0 KiB
C++

/**********************************************************************
Audacity: A Digital Audio Editor
Audacity(R) is copyright (c) 1999-2012 Audacity Team.
License: GPL v2. See License.txt.
PitchName.cpp
Vaughan Johnson and Dominic Mazzoni.
******************************************************************//**
\file PitchName.cpp
\brief Utilities for converting from frequency to pitch
and from pitch to absolute (e.g., C4 for middle C)
or nominal (A through G#) pitch name.
*//*******************************************************************/
#include "Audacity.h"
#include "PitchName.h"
#include <math.h>
#include <stdio.h>
#include "Internat.h"
double FreqToMIDInote(const double freq)
{
// Make the calculation relative to A440 (A4), note number 69.
return (69.0 + (12.0 * (log(freq / 440.0) / log(2.0))));
}
double MIDInoteToFreq(const double dMIDInote)
{
return (440.0 * pow(2.0, (dMIDInote - 69.0) / 12.0));
}
unsigned int PitchIndex(const double dMIDInote)
{
// MIDI numbers can be negative. Round in the right direction.
double dRound = (dMIDInote < 0.0) ? -0.5 : 0.5;
int nPitchIndex = ((int)(dMIDInote + dRound) % 12);
// Because of the modulo, we know we're within 12 of positive, if dMIDInote is negative.
if (nPitchIndex < 0)
nPitchIndex += 12;
return nPitchIndex;
}
int PitchOctave(const double dMIDInote)
{
double dRound = (dMIDInote < 0.0) ? -0.5 : 0.5;
return ((int)((dMIDInote + dRound) / 12.0) - 1);
}
wxString PitchName(const double dMIDInote, const PitchNameChoice choice)
{
static const wxString sharpnames[12] = {
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("C"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("C\u266f"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("D"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("D\u266f"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("E"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("F"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("F\u266f"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("G"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("G\u266f"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("A"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("A\u266f"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("B"),
};
static const wxString flatnames[12] = {
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("C"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("D\u266d"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("D"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("E\u266d"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("E"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("F"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("G\u266d"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("G"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("A\u266d"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("A"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("B\u266d"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("B"),
};
static const wxString bothnames[12] = {
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("C"),
/* i18n-hint: Two, alternate names of a musical note in the 12-tone chromatic scale */
XO("C\u266f/D\u266d"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("D"),
/* i18n-hint: Two, alternate names of a musical note in the 12-tone chromatic scale */
XO("D\u266f/E\u266d"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("E"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("F"),
/* i18n-hint: Two, alternate names of a musical note in the 12-tone chromatic scale */
XO("F\u266f/G\u266d"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("G"),
/* i18n-hint: Two, alternate names of a musical note in the 12-tone chromatic scale */
XO("G\u266f/A\u266d"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("A"),
/* i18n-hint: Two, alternate names of a musical note in the 12-tone chromatic scale */
XO("A\u266f/B\u266d"),
/* i18n-hint: Name of a musical note in the 12-tone chromatic scale */
XO("B"),
};
const wxString *table = nullptr;
switch ( choice ) {
case PitchNameChoice::Sharps: table = sharpnames; break;
case PitchNameChoice::Flats: table = flatnames; break;
case PitchNameChoice::Both: table = bothnames; break;
default: wxASSERT(false); break;
}
return table[PitchIndex(dMIDInote)];
}
wxString PitchName_Absolute(const double dMIDInote, const PitchNameChoice choice)
{
// The format string is not localized. Should it be?
return wxString::Format(
wxT("%s%d"), PitchName(dMIDInote, choice), PitchOctave(dMIDInote) );
}
double PitchToMIDInote(const unsigned int nPitchIndex, const int nPitchOctave)
{
return ((double)nPitchIndex + (((double)nPitchOctave + 1.0) * 12.0));
}
double PitchToFreq(const unsigned int nPitchIndex, const int nPitchOctave)
{
return MIDInoteToFreq(PitchToMIDInote(nPitchIndex, nPitchOctave));
}