{"version":3,"sources":["../index.ts"],"sourcesContent":["import {\n  coordinates,\n  isNamedPitch,\n  isPitch,\n  NamedPitch,\n  Pitch,\n  pitch,\n  PitchCoordinates,\n} from \"@tonaljs/pitch\";\n\nconst fillStr = (s: string, n: number) => Array(Math.abs(n) + 1).join(s);\n\nexport type NoteWithOctave = string;\nexport type PcName = string;\nexport type NoteName = NoteWithOctave | PcName;\nexport type NoteLiteral = NoteName | Pitch | NamedPitch;\n\nexport interface Note extends Pitch, NamedPitch {\n  readonly empty: boolean;\n  readonly name: NoteName;\n  readonly letter: string;\n  readonly acc: string;\n  readonly pc: PcName;\n  readonly chroma: number;\n  readonly height: number;\n  readonly coord: PitchCoordinates;\n  readonly midi: number | null;\n  readonly freq: number | null;\n}\n\nexport type NoteType = Note;\n\nconst NoNote: Note = Object.freeze({\n  empty: true,\n  name: \"\",\n  letter: \"\",\n  acc: \"\",\n  pc: \"\",\n  step: NaN,\n  alt: NaN,\n  chroma: NaN,\n  height: NaN,\n  coord: [] as unknown as PitchCoordinates,\n  midi: null,\n  freq: null,\n});\n\nconst cache: Map<NoteLiteral | undefined, Note> = new Map();\n\nexport const stepToLetter = (step: number) => \"CDEFGAB\".charAt(step);\nexport const altToAcc = (alt: number): string =>\n  alt < 0 ? fillStr(\"b\", -alt) : fillStr(\"#\", alt);\nexport const accToAlt = (acc: string): number =>\n  acc[0] === \"b\" ? -acc.length : acc.length;\n\n/**\n * Given a note literal (a note name or a note object), returns the Note object\n * @example\n * note('Bb4') // => { name: \"Bb4\", midi: 70, chroma: 10, ... }\n */\nexport function note(src: NoteLiteral): Note {\n  const stringSrc = JSON.stringify(src);\n\n  const cached = cache.get(stringSrc);\n  if (cached) {\n    return cached;\n  }\n\n  const value =\n    typeof src === \"string\"\n      ? parse(src)\n      : isPitch(src)\n        ? note(pitchName(src))\n        : isNamedPitch(src)\n          ? note(src.name)\n          : NoNote;\n  cache.set(stringSrc, value);\n  return value;\n}\n\ntype NoteTokens = [string, string, string, string];\n\nconst REGEX = /^([a-gA-G]?)(#{1,}|b{1,}|x{1,}|)(-?\\d*)\\s*(.*)$/;\n\n/**\n * @private\n */\nexport function tokenizeNote(str: string): NoteTokens {\n  const m = REGEX.exec(str) as string[];\n  return m\n    ? [m[1].toUpperCase(), m[2].replace(/x/g, \"##\"), m[3], m[4]]\n    : [\"\", \"\", \"\", \"\"];\n}\n\n/**\n * @private\n */\nexport function coordToNote(noteCoord: PitchCoordinates): Note {\n  return note(pitch(noteCoord)) as Note;\n}\n\nconst mod = (n: number, m: number) => ((n % m) + m) % m;\n\nconst SEMI = [0, 2, 4, 5, 7, 9, 11];\nfunction parse(noteName: NoteName): Note {\n  const tokens = tokenizeNote(noteName);\n  if (tokens[0] === \"\" || tokens[3] !== \"\") {\n    return NoNote;\n  }\n\n  const letter = tokens[0];\n  const acc = tokens[1];\n  const octStr = tokens[2];\n\n  const step = (letter.charCodeAt(0) + 3) % 7;\n  const alt = accToAlt(acc);\n  const oct = octStr.length ? +octStr : undefined;\n  const coord = coordinates({ step, alt, oct });\n\n  const name = letter + acc + octStr;\n  const pc = letter + acc;\n  const chroma = (SEMI[step] + alt + 120) % 12;\n  const height =\n    oct === undefined\n      ? mod(SEMI[step] + alt, 12) - 12 * 99\n      : SEMI[step] + alt + 12 * (oct + 1);\n  const midi = height >= 0 && height <= 127 ? height : null;\n  const freq = oct === undefined ? null : Math.pow(2, (height - 69) / 12) * 440;\n\n  return {\n    empty: false,\n    acc,\n    alt,\n    chroma,\n    coord,\n    freq,\n    height,\n    letter,\n    midi,\n    name,\n    oct,\n    pc,\n    step,\n  };\n}\n\nfunction pitchName(props: Pitch): NoteName {\n  const { step, alt, oct } = props;\n  const letter = stepToLetter(step);\n  if (!letter) {\n    return \"\";\n  }\n\n  const pc = letter + altToAcc(alt);\n  return oct || oct === 0 ? pc + oct : pc;\n}\n"],"mappings":"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","names":[]}