UNPKG

xen-dev-utils

Version:

Utility functions used by the Scale Workshop ecosystem

199 lines 6.89 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.natsToSemitones = exports.semitonesToNats = exports.natsToCents = exports.centsToNats = exports.mtsBytesToHex = exports.mtsBytesToFrequency = exports.mtsBytesToMts = exports.frequencyToMtsBytes = exports.mtsToMtsBytes = exports.ftom = exports.ftomts = exports.mtof = exports.centOffsetToFrequency = exports.frequencyToCentOffset = exports.centsToValue = exports.valueToCents = void 0; /** * Convert floating point ratio to cents. * ```ts * valueToCents(3/2) // 701.9550008653874 * ``` * @param value Musical interval in multiplicative representation. * @returns Musical interval in additive representation measured in cents. */ function valueToCents(value) { return 1200 * Math.log2(value); } exports.valueToCents = valueToCents; /** * Convert cents to floating point ratio. * ```ts * centsToValue(1200) // 2.0 * ``` * @param cents Musical interval in additive representation measured in cents. * @returns Musical interval in multiplicative representation. */ function centsToValue(cents) { return Math.pow(2, cents / 1200); } exports.centsToValue = centsToValue; /** * Convert musical frequency to pitch in cents by comparing it to a reference frequency. * ```ts * frequencyToCentOffset(220) // -1200.0 * ``` * @param frequency Musical frequency. * @param baseFrequency Reference frequency. * @returns Musical pitch in additive representation as a cents offset from reference. */ function frequencyToCentOffset(frequency, baseFrequency = 440) { return valueToCents(frequency / baseFrequency); } exports.frequencyToCentOffset = frequencyToCentOffset; /** * Convert pitch as cents offset from reference to frequency. * ```ts * centOffsetToFrequency(1200) // 880.0 * ``` * @param offset Musical pitch in additive representation as a cents offset from reference. * @param baseFrequency Reference frequency. * @returns Musical frequency. */ function centOffsetToFrequency(offset, baseFrequency = 440) { return centsToValue(offset) * baseFrequency; } exports.centOffsetToFrequency = centOffsetToFrequency; const MIDI_NOTE_NUMBER_OF_A4 = 69; /** * Convert MIDI note number to frequency. * @param index MIDI note number or MTS value. * @returns Frequency in Hertz. */ function mtof(index) { return 440 * Math.pow(2, (index - MIDI_NOTE_NUMBER_OF_A4) / 12); } exports.mtof = mtof; /** * Convert frequency to MTS number (semitones with A440=69). * @param frequency Frequency in Hertz. * @returns MTS value */ function ftomts(frequency, ignoreLimit = false) { if (frequency <= 0) return 0; if (frequency > 13289.656616 && !ignoreLimit) return 127.999878; // Highest possible MTS value, corresponding to 7F 7F 7E const mts = MIDI_NOTE_NUMBER_OF_A4 + 12 * Math.log2(frequency / 440); return Math.round(mts * 1000000) / 1000000; } exports.ftomts = ftomts; /** * Convert frequency to MIDI note number and pitch offset measured in cents. * @param frequency Frequency in Hertz. * @returns [MIDI note number, pitch offset in cents] */ function ftom(frequency) { const semitones = MIDI_NOTE_NUMBER_OF_A4 + 12 * Math.log2(frequency / 440); const midiNoteNumber = Math.round(semitones); const centsOffset = (semitones - midiNoteNumber) * 100; return [midiNoteNumber, centsOffset]; } exports.ftom = ftom; /** * Convert MTS pitch value to 3-byte representation * @param mtsValue MTS pitch value * @returns Uint8Array 3-byte of 7-bit MTS data */ function mtsToMtsBytes(mtsValue) { if (mtsValue <= 0) return new Uint8Array([0, 0, 0]); if (mtsValue > 127.999878) return new Uint8Array([127, 127, 126]); const noteNumber = Math.trunc(mtsValue); const fine = Math.round(0x4000 * (mtsValue - noteNumber)); const data = new Uint8Array(3); data[0] = noteNumber; data[1] = (fine >> 7) & 0x7f; data[2] = fine & 0x7f; return data; } exports.mtsToMtsBytes = mtsToMtsBytes; /** * Convert frequency to 3-byte MTS value * @param frequency Frequency in Hertz. * @returns Uint8Array of length 3 */ function frequencyToMtsBytes(frequency) { const mtsValue = ftomts(frequency); return mtsToMtsBytes(mtsValue); } exports.frequencyToMtsBytes = frequencyToMtsBytes; /** * Convert 3-byte MTS value to frequency * @param mtsBytes Uint8Array of 3-bytes of 7-bit MTS values * @returns frequency Frequency in Hertz */ function mtsBytesToMts(mtsBytes) { const msb = mtsBytes[1] > 0x7f ? 0x7f : mtsBytes[1]; let lsb = mtsBytes[2]; const noteNumber = mtsBytes[0] > 0x7f ? 0x7f : mtsBytes[0]; if (noteNumber === 0x7f) { if (lsb >= 0x7f) lsb = 0x7e; } else if (lsb > 0x7f) lsb = 0x7f; const fine = ((msb << 7) + lsb) / 0x4000; return noteNumber + fine; } exports.mtsBytesToMts = mtsBytesToMts; /** * Convert 3-byte MTS value to frequency * @param mtsBytes Uint8Array of 3-bytes of 7-bit MTS values * @returns frequency Frequency in Hertz */ function mtsBytesToFrequency(mtsBytes) { const mts = mtsBytesToMts(mtsBytes); const frequency = mtof(mts); return Math.round(frequency * 1000000) / 1000000; } exports.mtsBytesToFrequency = mtsBytesToFrequency; /** Convert MTS Data value into readable hex string * @param mtsBytes Uint8Array of 3-bytes of 7-bit MTS values * @returns String representation of MTS value in hexadecimal * can be used in MIDI messages */ function mtsBytesToHex(mtsBytes) { const noteNumber = mtsBytes[0] > 0x7f ? 0x7f : mtsBytes[0]; const msb = mtsBytes[1] > 0x7f ? 0x7f : mtsBytes[1]; const lsb = mtsBytes[2] > 0x7f ? 0x7f : mtsBytes[2]; return (noteNumber.toString(16).padStart(2, '0') + msb.toString(16).padStart(2, '0') + lsb.toString(16).padStart(2, '0')); } exports.mtsBytesToHex = mtsBytesToHex; /** * Convert cents to natural units. * @param cents Musical interval in cents. * @returns Musical interval in natural units. */ function centsToNats(cents) { return (cents / 1200) * Math.LN2; } exports.centsToNats = centsToNats; /** * Convert natural units to cents. * @param nats Musical interval in natural units. * @returns Musical interval in cents. */ function natsToCents(nats) { return (nats / Math.LN2) * 1200; } exports.natsToCents = natsToCents; /** * Convert semitones to natural units. * @param semitones Musical interval in semitones. * @returns Musical interval in natural units. */ function semitonesToNats(semitones) { return (semitones / 12) * Math.LN2; } exports.semitonesToNats = semitonesToNats; /** * Convert natural units to cents. * @param nats Musical interval in natural units. * @returns Musical interval in semitones. */ function natsToSemitones(nats) { return (nats / Math.LN2) * 12; } exports.natsToSemitones = natsToSemitones; //# sourceMappingURL=conversion.js.map