text: /**********************************************************************
  
     AudMonkey: 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 "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);
  }
  
  
  TranslatableString PitchName(const double dMIDInote, const PitchNameChoice choice)
  {
     static const TranslatableString 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 TranslatableString 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 TranslatableString 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 TranslatableString *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)];
  }
  
  TranslatableString PitchName_Absolute(const double dMIDInote, const PitchNameChoice choice)
  {
     // The format string is not localized.  Should it be?
     return Verbatim( wxT("%s%d") )
        .Format( 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));
  }
  