Note Frequency
Closed this issue · 7 comments
I know A4 can be customized, but I couldn't find where. I see in the tunings files that the frequency for each note is set manually; this can be error prone, and I think it could be either calculated (I don't know how, or if it's even possible; I only recently started studying music), or automatically set (for example, from a Map<String, List<Double>>
).
I wanted to ask what you think about the second idea; something like this:
import static java.util.Map.entry;
public class NoteFrequency {
private static final Map<String, List<Double>> freqs = Map.ofEntries(
entry("C", List.of(16.35, 32.70, 65.41, 130.81, 261.63, 523.25, 1046.50, 2093.00, 4186.01)),
/* Either the sharps or the flats may be omitted, depending on needs */
entry("C#", List.of(/*...*/)),
entry("Db", List.of(/*...*/)),
entry("D", List.of(/*...*/)),
/*...*/
);
public static Double getFrequency (String note, int octave) {
return NoteFrequency.freqs.get(note)[octave];
}
}
This way, on the tunings files, the enum alternatives could get the frequency themselves, and be used like E1(E, 1)
instead of E1(E, 1, 41.204f)
, which makes it easier and less error prone to create new tunings.
Again, frequencies taken from https://pages.mtu.edu/~suits/notefreqs.html
That's a very good point! There is indeed also a formula for calculating the frequency: https://pages.mtu.edu/~suits/NoteFreqCalcs.html. We would only have to know the reference frequency:
import java.util.Arrays;
import java.util.List;
public class NoteFrequency {
private static List<String> notes =
Arrays.asList("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B");
public static double getFrequency(String note, int octave) {
int semitonesPerOctave = 12;
int referenceOctave = 4;
double distance = semitonesPerOctave * (octave - referenceOctave);
distance += notes.indexOf(note) - notes.indexOf("A");
float referenceFrequency = 440;
return referenceFrequency * Math.pow(2, distance / 12);
}
}
Nice! Even better! Although there may be some loss in precision calculating these programatically, it should be negligible given the loss of precision of a phone's microphone (just speculation).
You're right. I think it makes sense to have a unit test comparing the computed values against the frequencies listed in https://pages.mtu.edu/~suits/notefreqs.html to see if the deviation is too large.
The hard-coded frequencies have been removed. The changes are part of the new version v3.3 which also includes the Drop C bass tuning and should be published on F-Droid in a couple of days.
Thank you very much for your suggestion!
Awesome work! I was taking a look at the commits, and wanted to ask/comment on a couple of things, if that's ok?
- I noticed you removed the
PitchAdjuster
, but I couldn't see how that functionality is implemented now; so the question is: is it still possible to change the reference pitch (A4
)? I don't personally use it, but I think it would be a bad move to remove it. - My initial idea was to calculate the frequency in the
Enum
constructor and save it in thefrequency
field, as the values are static. Not sure I misunderstood how the code works/used to work, but there shouldn't be a need to recalculate the frequency everytime it's needed; how does it actually work?
Sure!
- The NoteFrequencyCalculator class accepts the reference pitch as a constructor argument and uses it in the calculation of the note frequency.
- If it weren't for the reference pitch, the frequencies could be calculated statically once when the application starts. Perhaps they could be recalculated when the reference pitch changes. Or the calculations could be carried out for all configurable reference pitches, although this would make for a rather big lookup table. But I don't think recalculating the frequencies has a noticeable performance impact.
Alright, got it! Thanks!