Seanitzel/Note-Art

View on GitHub
src/utilities/ScientificFunctions.ts

Summary

Maintainability
A
2 hrs
Test Coverage
import { Note, PitchClass, RawFlatPitchClass } from 'types';
import { FLAT_CLASS_NOTES, NUMBER_OF_PITCH_CLASSES, PITCH_STANDARD, SEMITONE } from '../Constants.js';
import { getPitchClassIndex, noteToObject } from './PureMusicUtils.js';

/**
 * Calculate the frequency of a note by its octave and index out of all notes(c, c#, etc...).
 * @param {String} note
 * @returns {Number}
 */
export function freqFromPitch(note: Note): number {
  const { pitchClass, octave } = noteToObject(note);
  const oct = octave - PITCH_STANDARD.octave; // calculate octave difference
  const pitchClassIndex = getPitchClassIndex(pitchClass as PitchClass);
  return Math.pow(
    SEMITONE,
    pitchClassIndex - FLAT_CLASS_NOTES.indexOf(PITCH_STANDARD.pitchClass as RawFlatPitchClass) + oct * NUMBER_OF_PITCH_CLASSES,
  ) * PITCH_STANDARD.frequency;
}

export function freqToPitch(frequency: number): Note {
  const midi = freqToMidi(frequency);
  const pitchClass = midi % NUMBER_OF_PITCH_CLASSES;
  const octave = Math.floor(midi / NUMBER_OF_PITCH_CLASSES) - 1;
  const note = `${FLAT_CLASS_NOTES[pitchClass]}${octave}`;
  return note as Note;
}

/**
 * Turns a midi value to frequency.
 * @param {Number} midi
 * @returns {number}
 */
export function freqFromMidi(midi: number): number {
  return PITCH_STANDARD.frequency * Math.pow(2, (midi - PITCH_STANDARD.midi) / NUMBER_OF_PITCH_CLASSES);
}

/**
 * Turns a frequency value to midi note.
 * @param frequency
 * @returns {number}
 */
export function freqToFloatMidi(frequency: number): number {
  return PITCH_STANDARD.midi + NUMBER_OF_PITCH_CLASSES * Math.log2(frequency / PITCH_STANDARD.frequency);
}

/**
 * Turns frequency value to a ABSOLUTE midi note.
 * @param {Number} frequency
 * @returns {number}
 */
export function freqToMidi(frequency: number): number {
  return Math.round(freqToFloatMidi(frequency));
}

/**
 * Returns how much cents off a frequency is from an absolute note.
 * @param {Number} frequency
 * @param {Number} midi
 * @returns {number}
 */
export function centsOffFromFreq(frequency: number, midi: number): number {
  return Math.floor(1200 * Math.log(frequency / freqFromMidi(midi)) / Math.log(2));
}

/**
 * Generate frequency from real number.
 * @param realNumber
 * @returns {Number}
 */
export function midiToFreq(realNumber: number): number {
  return PITCH_STANDARD.frequency * (Math.pow(2, (realNumber - PITCH_STANDARD.midi) / NUMBER_OF_PITCH_CLASSES));
}

/**
 * Convert MIDI value to pitch.
 * @param {Number} midi
 * @returns {Note}
 */
export function midiToPitch(midi: number): Note {
  const freq = freqFromMidi(midi);
  return freqToPitch(freq);
}

/**
 * Convert pitch to MIDI value.
 * @param {Note} pitch
 * @returns {number}
 */
export function pitchToMidi(note: Note): number {
  const freq = freqFromPitch(note);
  return freqToMidi(freq);
}