001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030/** 031 * 032 */ 033package org.openimaj.audio.util; 034 035import java.util.Arrays; 036 037/** 038 * Represents a note in a standard equal-tempered Western scale. There 039 * are various static methods for creating notes from names, note numbers, 040 * and frequencies. 041 * 042 * @author David Dupplaw (dpd@ecs.soton.ac.uk) 043 * @see "http://www.musicdsp.org/showone.php?id=125" 044 * @created 27 Nov 2011 045 */ 046public class WesternScaleNote 047{ 048 /** The MIDI note number of the note */ 049 public int noteNumber; 050 051 /** The note name; e.g. C, D, F#, etc. */ 052 public String noteName; 053 054 /** The octave number. Note C4 is middle C */ 055 public int octaveNumber; 056 057 /** The frequency of the note */ 058 public float frequency; 059 060 /** 061 * {@inheritDoc} 062 * @see java.lang.Object#toString() 063 */ 064 @Override 065 public String toString() 066 { 067 return this.noteName + this.octaveNumber + 068 " ("+this.frequency+"Hz, "+this.noteNumber+")"; 069// return this.noteName+this.octaveNumber; 070 } 071 072 // ---------------------- Static stuff below here ------------------------ // 073 /** The standing tuning is A=440Hz. Can change that here. */ 074 public static float tuningOfA = 440.0f; 075 076 /** The twelfth root of 2 */ 077 public static final double twelfthRootOfTwo = 1.059463094359; 078 079 /** The names of the notes in the Western scale */ 080 public static final String[] noteNames = new String[] 081 {"C","C#","D","D#","E","F","F#","G","G#","A","A#","B" }; 082 083 /** 084 * Returns the number of half-steps between the two given notes. 085 * 086 * @param note1 The first note of the interval 087 * @param note2 The second note of the interval 088 * @return The number of half-steps between the two notes. 089 */ 090 public final static int nStepsBetween( final WesternScaleNote note1, 091 final WesternScaleNote note2 ) 092 { 093 return note1.noteNumber - note2.noteNumber; 094 } 095 096 /** 097 * Converts a MIDI note number to a frequency. 098 * @param noteNumber The note number 099 * @return The frequency 100 */ 101 public final static float noteToFrequency( final int noteNumber ) 102 { 103 return (float)(WesternScaleNote.tuningOfA * 104 Math.pow( 2, (noteNumber-69)/12d )); 105 } 106 107 /** 108 * Converts a frequency to the nearest note number 109 * @param frequency The frequency 110 * @return The note number 111 */ 112 public final static int frequencyToNote( final float frequency ) 113 { 114 return (int)Math.round( 12 * Math.log( 115 frequency/WesternScaleNote.tuningOfA )/Math.log(2) ) 116 +69; 117 } 118 119 /** 120 * Given a note string, returns a new {@link WesternScaleNote} from 121 * which other information can be garnered. A note string is the note name 122 * followed by the octave; e.g. "D3" or "A#5". 123 * @param noteString The note string 124 * @return A {@link WesternScaleNote} or null if the note string is invalid 125 */ 126 public final static WesternScaleNote createNote( final String noteString ) 127 { 128 // Options we have are nO, nAO, nOO, nAOO. 129 130 // Find the longest matching start to the string 131 String startNoteName = null; 132 int length = 0; 133 for( String noteName: noteNames ) 134 { 135 if( noteString.startsWith( noteName ) && noteName.length() > length ) 136 { 137 startNoteName = noteName; 138 length = noteName.length(); 139 } 140 } 141 142 if( startNoteName == null ) return null; 143 144 // Parse the octave value 145 int octave = Integer.parseInt( noteString.substring( 146 startNoteName.length() ) ); 147 148 // Create a new note 149 return WesternScaleNote.createNote( startNoteName, octave ); 150 } 151 152 /** 153 * Given a note name and octave, returns a {@link WesternScaleNote} from 154 * which other information can be garnered. 155 * 156 * @param noteName The name of the note 157 * @param octaveNumber The octave of the note. 158 * @return A new WesternScaleNote 159 */ 160 public final static WesternScaleNote createNote( final String noteName, 161 final int octaveNumber ) 162 { 163 final WesternScaleNote n = new WesternScaleNote(); 164 n.noteName = noteName; 165 n.octaveNumber = octaveNumber; 166 n.noteNumber = Arrays.asList( WesternScaleNote.noteNames ).indexOf( noteName ) + 167 (octaveNumber+1)*12; 168 n.frequency = WesternScaleNote.noteToFrequency( n.noteNumber ); 169 170 return n; 171 } 172 173 /** 174 * Create a {@link WesternScaleNote} given a frequency. It does this by 175 * converting the frequency in to a MIDI note number and using 176 * {@link WesternScaleNote#createNote(int)} which returns the note. For 177 * this reason, the value of the member {@link #frequency} in the returned 178 * note may not be the same as the given frequency. 179 * 180 * @param frequency The frequency to convert to a note. 181 * @return A {@link WesternScaleNote} 182 */ 183 public final static WesternScaleNote createNote( final float frequency ) 184 { 185 final int noteNum = WesternScaleNote.frequencyToNote( frequency ); 186 return WesternScaleNote.createNote( noteNum ); 187 } 188 189 /** 190 * Given a note number, returns a {@link WesternScaleNote} from which other 191 * information can be garnered. 192 * 193 * @param noteNumber A note number 194 * @return A {@link WesternScaleNote} 195 */ 196 public final static WesternScaleNote createNote( final int noteNumber ) 197 { 198 final WesternScaleNote n = new WesternScaleNote(); 199 n.noteNumber = noteNumber; 200 n.octaveNumber = noteNumber/12 -1; 201 n.noteName = WesternScaleNote.noteNames[ noteNumber%12 ]; 202 n.frequency = WesternScaleNote.noteToFrequency( noteNumber ); 203 204 return n; 205 } 206 207}