xen-dev-utils
Version:
Utility functions used by the Scale Workshop ecosystem
199 lines • 6.89 kB
JavaScript
;
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