Fix roundtrip in f32_hz_then_khz_with_note_names
This commit is contained in:
parent
b647f24121
commit
18b4403a3b
|
@ -180,17 +180,18 @@ pub fn s2v_f32_hz_then_khz() -> Arc<dyn Fn(&str) -> Option<f32> + Send + Sync> {
|
|||
Arc::new(move |string| {
|
||||
let string = string.trim();
|
||||
|
||||
// If the user inputs a note representation, then we'll use that
|
||||
if let Some(midi_note_number) = note_formatter(string) {
|
||||
return Some(util::f32_midi_note_to_freq(midi_note_number as f32));
|
||||
}
|
||||
// The input can contain a frequency in Hz or kHz, a note name, a note name and cents, or
|
||||
// one of those two combined with a frequency. In the last case we'll ignore the frequency.
|
||||
// If the string cannot be parsed as a note name, we'll try parsing it as a frequency
|
||||
// instead. This is needed for the formatting roundtrip to work correctly. The input will
|
||||
// consists of 1 to three segments, so we'll try to unpack them like this so we can pattern
|
||||
// match on them
|
||||
let mut segments = string.split(',');
|
||||
let segments = (segments.next(), segments.next(), segments.next());
|
||||
|
||||
// This can also contain semitones. If we cannot parse this as a note name, we'll try
|
||||
// parsing it as a frequency instead. We'll also `XXX Hz, C3` where `XXX Hz` does not match
|
||||
// C3 since the user may just edit that of the text input box while leaving the note name
|
||||
// untouched.
|
||||
let string = if let Some((midi_note_number_str, cents_str)) = string.split_once(',') {
|
||||
// If it contains a comma we'll also try parsing cents
|
||||
if let (_, Some(midi_note_number_str), Some(cents_str))
|
||||
| (Some(midi_note_number_str), Some(cents_str), None) = segments
|
||||
{
|
||||
let cents_str = cents_str
|
||||
.trim_start_matches([' ', '+'])
|
||||
.trim_end_matches([' ', 'C', 'c', 'E', 'e', 'N', 'n', 'T', 't', 'S', 's', '.']);
|
||||
|
@ -203,22 +204,23 @@ pub fn s2v_f32_hz_then_khz() -> Arc<dyn Fn(&str) -> Option<f32> + Send + Sync> {
|
|||
let cents_multiplier = 2.0f32.powf(cents as f32 / 100.0 / 12.0);
|
||||
return Some(plain_note_freq * cents_multiplier);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: As mentioned above, if the input contained a `,` we'll try parsing the part
|
||||
// before the comma as a frequency string if we could not parse the right hand
|
||||
// side has a note string. This can happen if the user edits the output of
|
||||
// `v2s_f32_hz_then_khz_with_note_name()`.
|
||||
midi_note_number_str
|
||||
} else {
|
||||
string
|
||||
};
|
||||
if let (_, Some(midi_note_number_str), _) | (Some(midi_note_number_str), None, None) =
|
||||
segments
|
||||
{
|
||||
if let Some(midi_note_number) = note_formatter(midi_note_number_str) {
|
||||
return Some(util::f32_midi_note_to_freq(midi_note_number as f32));
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise we'll accept values in either Hz (with or without unit) or kHz
|
||||
let cleaned_string = string
|
||||
let frequency_segment = segments.0?;
|
||||
let cleaned_string = frequency_segment
|
||||
.trim_end_matches([' ', 'k', 'K', 'h', 'H', 'z', 'Z'])
|
||||
.parse()
|
||||
.ok();
|
||||
match string.get(string.len().saturating_sub(3)..) {
|
||||
match frequency_segment.get(frequency_segment.len().saturating_sub(3)..) {
|
||||
Some(unit) if unit.eq_ignore_ascii_case("khz") => cleaned_string.map(|x| x * 1000.0),
|
||||
// Even if there's no unit at all, just assume the input is in Hertz
|
||||
_ => cleaned_string,
|
||||
|
|
Loading…
Reference in a new issue