plectrum

Plectrum: instrument tuner for Android
Log | Files | Refs | README | LICENSE

PitchConverter.java (6787B)


      1 /*
      2 *      _______                       _____   _____ _____  
      3 *     |__   __|                     |  __ \ / ____|  __ \ 
      4 *        | | __ _ _ __ ___  ___  ___| |  | | (___ | |__) |
      5 *        | |/ _` | '__/ __|/ _ \/ __| |  | |\___ \|  ___/ 
      6 *        | | (_| | |  \__ \ (_) \__ \ |__| |____) | |     
      7 *        |_|\__,_|_|  |___/\___/|___/_____/|_____/|_|     
      8 *                                                         
      9 * -------------------------------------------------------------
     10 *
     11 * TarsosDSP is developed by Joren Six at IPEM, University Ghent
     12 *  
     13 * -------------------------------------------------------------
     14 *
     15 *  Info: http://0110.be/tag/TarsosDSP
     16 *  Github: https://github.com/JorenSix/TarsosDSP
     17 *  Releases: http://0110.be/releases/TarsosDSP/
     18 *  
     19 *  TarsosDSP includes modified source code by various authors,
     20 *  for credits and info, see README.
     21 * 
     22 */
     23 
     24 
     25 package be.tarsos.dsp.util;
     26 
     27 
     28 /**
     29  * Converts pitch from one unit to another (and back (and back (and back ...))).
     30  * 
     31  * @author Joren Six
     32  */
     33 public final class PitchConverter {
     34 
     35 	/**
     36 	 * Hide the default constructor.
     37 	 */
     38 	private PitchConverter() {
     39 	}
     40 
     41 	/**
     42 	 * C-1 = 16.35 / 2 Hz.
     43 	 */
     44 	private static final double REF_FREQ = 8.17579892;
     45 
     46 	/**
     47 	 * Cache LOG 2 calculation.
     48 	 */
     49 	private static final double LOG_TWO = Math.log(2.0);
     50 
     51 	/**
     52 	 * A MIDI key is an integer between 0 and 127, inclusive. Within a certain
     53 	 * range every pitch is mapped to a MIDI key. If a value outside the range
     54 	 * is given an IllegalArugmentException is thrown.
     55 	 * 
     56 	 * @param hertzValue
     57 	 *            The pitch in Hertz.
     58 	 * @return An integer representing the closest midi key.
     59 	 * @exception IllegalArgumentException
     60 	 *                if the hertzValue does not fall within the range of valid
     61 	 *                MIDI key frequencies.
     62 	 */
     63 	public static int hertzToMidiKey(final Double hertzValue) {
     64 		final int midiKey = (int) Math.round(hertzToMidiCent(hertzValue));
     65 		if (midiKey < 0 || midiKey > 127) {
     66 			// TODO
     67 			// LOG.warning("MIDI is only defined between [" + midiKeyToHertz(0)
     68 			// + ","
     69 			// + midiKeyToHertz(127) + "] " + hertzValue +
     70 			// "does not map to a MIDI key.");
     71 		}
     72 		return midiKey;
     73 	}
     74 
     75 	/**
     76 	 * Calculates the frequency (Hz) for a MIDI key.
     77 	 * 
     78 	 * @param midiKey
     79 	 *            The MIDI key. A MIDI key is an integer between 0 and 127,
     80 	 *            inclusive.
     81 	 * @return A frequency in Hz corresponding to the MIDI key.
     82 	 * @exception IllegalArgumentException
     83 	 *                If midiKey is not in the valid range between 0 and 127,
     84 	 *                inclusive.
     85 	 */
     86 	public static double midiKeyToHertz(final int midiKey) {
     87 		if (midiKey < 0 || midiKey > 127) {
     88 			throw new IllegalArgumentException("MIDI keys are values from 0 to 127, inclusive " + midiKey
     89 					+ " is invalid.");
     90 		}
     91 		return midiCentToHertz(midiKey);
     92 	}
     93 
     94 	/**
     95 	 * Converts a Hertz value to relative cents. E.g. 440Hz is converted to 900
     96 	 * if the reference is a C.
     97 	 * 
     98 	 * @param hertzValue
     99 	 *            A value in hertz.
    100 	 * @return A value in relative cents.
    101 	 */
    102 	public static double hertzToRelativeCent(final double hertzValue) {
    103 		double absoluteCentValue = hertzToAbsoluteCent(hertzValue);
    104 		// make absoluteCentValue positive. E.g. -2410 => 1210
    105 		if (absoluteCentValue < 0) {
    106 			absoluteCentValue = Math.abs(1200 + absoluteCentValue);
    107 		}
    108 		// so it can be folded to one octave. E.g. 1210 => 10
    109 		return absoluteCentValue % 1200.0;
    110 	}
    111 
    112 	/**
    113 	 * This method is not really practical. Maybe I will need it someday.
    114 	 * 
    115 	 * @param relativeCent
    116 	 * @return public static double relativeCentToHertz(double relativeCent){ if
    117 	 *         (relativeCent < 0 || relativeCent >= 1200) throw new
    118 	 *         IllegalArgumentException
    119 	 *         ("Relative cent values are values from 0 to 1199, inclusive " +
    120 	 *         relativeCent + " is invalid."); int defaultOctave = 5; int offset
    121 	 *         = defaultOctave * 1200; return absoluteCentToHertz(relativeCent +
    122 	 *         offset); }
    123 	 */
    124 
    125 	/**
    126 	 * The reference frequency is configured. The default reference frequency is
    127 	 * 16.35Hz. This is C0 on a piano keyboard with A4 tuned to 440 Hz. This
    128 	 * means that 0 cents is C0; 1200 is C1; 2400 is C2; ... also -1200 cents is
    129 	 * C-1
    130 	 * 
    131 	 * @param hertzValue
    132 	 *            The pitch in Hertz.
    133 	 * @return The value in absolute cents using the configured reference
    134 	 *         frequency
    135 	 */
    136 	public static double hertzToAbsoluteCent(final double hertzValue) {
    137 		double pitchInAbsCent = 0.0;
    138 		if (hertzValue > 0) {
    139 			pitchInAbsCent = 1200 * Math.log(hertzValue / REF_FREQ) / LOG_TWO;
    140 		} else {
    141 			throw new IllegalArgumentException("Pitch in Hz schould be greater than zero, is " + hertzValue);
    142 		}
    143 		return pitchInAbsCent;
    144 	}
    145 
    146 	/**
    147 	 * Returns the frequency (Hz) of an absolute cent value. This calculation
    148 	 * uses a configured reference frequency.
    149 	 * 
    150 	 * @param absoluteCent
    151 	 *            The pitch in absolute cent.
    152 	 * @return A pitch in Hz.
    153 	 */
    154 	public static double absoluteCentToHertz(final double absoluteCent) {
    155 		return REF_FREQ * Math.pow(2, absoluteCent / 1200.0);
    156 	}
    157 
    158 	/**
    159 	 * Converts a frequency in Hz to a MIDI CENT value using
    160 	 * <code>(12 * log2 (f / 440)) + 69</code> <br>
    161 	 * E.g.<br>
    162 	 * <code>69.168 MIDI CENTS = MIDI NOTE 69  + 16,8 cents</code><br>
    163 	 * <code>69.168 MIDI CENTS = 440Hz + x Hz</code>
    164 	 * 
    165 	 * @param hertzValue
    166 	 *            The pitch in Hertz.
    167 	 * @return The pitch in MIDI cent.
    168 	 */
    169 	public static double hertzToMidiCent(final double hertzValue) {
    170 		double pitchInMidiCent = 0.0;
    171 		if (hertzValue != 0) {
    172 			pitchInMidiCent = 12 * Math.log(hertzValue / 440) / LOG_TWO + 69;
    173 		}
    174 		return pitchInMidiCent;
    175 	}
    176 
    177 	/**
    178 	 * Converts a MIDI CENT frequency to a frequency in Hz.
    179 	 * 
    180 	 * @param midiCent
    181 	 *            The pitch in MIDI CENT.
    182 	 * @return The pitch in Hertz.
    183 	 */
    184 	public static double midiCentToHertz(final double midiCent) {
    185 		return 440 * Math.pow(2, (midiCent - 69) / 12d);
    186 	}
    187 
    188 	/**
    189 	 * Converts cent values to ratios. See
    190 	 * "Ratios Make Cents: Conversions from ratios to cents and back again" in
    191 	 * the book "Tuning Timbre Spectrum Scale" William A. Sethares.
    192 	 * 
    193 	 * @param cent
    194 	 *            A cent value
    195 	 * @return A ratio containing the same information.
    196 	 */
    197 	public static double centToRatio(final double cent) {
    198 		final double ratio;
    199 		ratio = Math.pow(10, Math.log10(2) * cent / 1200.0);
    200 		return ratio;
    201 	}
    202 
    203 	/**
    204 	 * Converts a ratio to cents.
    205 	 * "Ratios Make Cents: Conversions from ratios to cents and back again" in
    206 	 * the book "Tuning Timbre Spectrum Scale" William A. Sethares
    207 	 * 
    208 	 * @param ratio
    209 	 *            A cent value
    210 	 * @return A ratio containing the same information.
    211 	 */
    212 	public static double ratioToCent(final double ratio) {
    213 		final double cent;
    214 		cent = 1200 / Math.log10(2) * Math.log10(ratio);
    215 		return cent;
    216 	}
    217 }