Skip to content
← Public packages

@kentcdodds/pocket-piano

A pocket piano for choir practice: your singing part's range on your phone, installable and offline.

FollowForkOpen app

src/index.ts

36 lines · 1.3 KB · TypeScript
Raw
import { midiToFrequency, midiToName } from './notes.ts'

/**
 * Look up the name and frequency of a MIDI note number.
 * Use when an agent needs the same note naming the Pocket Piano app shows
 * (for example to tell Kent which key to press for a starting pitch).
 *
 * @param input - `{ midi }` where midi is an integer from 0 to 127 (60 is middle C, C4)
 * @returns `{ midi, name, frequency }` with frequency in Hz (A4 = 440)
 *
 * @example
 * import noteInfo from 'kody:@kentcdodds/pocket-piano'
 *
 * const info = await noteInfo({ midi: 60 }) // { midi: 60, name: 'C4', frequency: 261.63 }
 */
export default async function noteInfo(input: unknown) {
	if (!input || typeof input !== 'object') {
		throw new Error('Expected an object like { midi: 60 }.')
	}
	const keys = Object.keys(input)
	const unknown = keys.filter((key) => key !== 'midi')
	if (unknown.length > 0) {
		throw new Error(
			'Unknown key(s): ' + unknown.join(', ') + '. Accepted shape: { midi: number }.',
		)
	}
	const midi = (input as { midi?: unknown }).midi
	if (typeof midi !== 'number' || !Number.isInteger(midi) || midi < 0 || midi > 127) {
		throw new Error('midi must be an integer from 0 to 127 (60 is middle C).')
	}
	return {
		midi,
		name: midiToName(midi),
		frequency: Math.round(midiToFrequency(midi) * 100) / 100,
	}
}