{"version":3,"sources":["../src/index.ts","../src/arp.ts","../src/utils.ts","../src/clip-utils.ts","../src/clip.ts","../src/midi.ts","../src/progression.ts"],"sourcesContent":["import { chord, chords, scale, scales } from 'harmonics';\nimport { arp } from './arp';\nimport { clip } from './clip';\nimport { midi } from './midi';\nimport {\n  getChordDegrees,\n  getChordsByProgression,\n  progression,\n} from './progression';\nimport { sizzleMap } from './utils';\n\nexport * from './types';\nexport {\n  scale,\n  scale as mode,\n  scales,\n  scales as modes,\n  chord,\n  chords,\n  clip,\n  getChordDegrees,\n  getChordsByProgression,\n  progression,\n  arp,\n  midi,\n  sizzleMap,\n};\n","import { inlineChord } from 'harmonics';\nimport type { ArpParams } from './types';\nimport { errorHasMessage } from './utils';\n\nconst DEFAULT_OCTAVE = 4;\n\n/**\n * Take an array and fill it with it s own elements in the next octave till it s of the specified `len`\n * @param  {Array} arr e.g. ['a4', 'b4']\n * @param  {Number} e.g. len 4\n * @return {Array} e.g. ['a4', 'b4', 'a5', 'b5']\n */\nconst fillArr = (arr: string[], len: number): string[] => {\n  const bumpOctave = (el: string): string => {\n    if (!el) {\n      throw new Error('Empty element');\n    }\n    const note = el.replace(/\\d/, '');\n    const oct = el.replace(/\\D/g, '') || DEFAULT_OCTAVE;\n    if (!note) {\n      throw new Error('Incorrect note');\n    }\n    return note + (+oct + 1);\n  };\n\n  // Create a couple of chord arrays with bumped octaves\n  // so that something like [c3, e3, g4] turns into [c4, e4, g5] and [c5, e5, g6]\n  const arr1 = arr.map(bumpOctave);\n  const arr2 = arr1.map(bumpOctave);\n  const finalArr = [...arr, ...arr1, ...arr2];\n\n  // Slice and return only as much as required\n  return finalArr.slice(0, len);\n};\n\n/**\n *\n * @param chordsOrParams a string that denotes space (comma?) separated chords to be used or an object with additional properties\n * By default, if this is a string, the count of notes generated is 8 and the order is ascending.\n * For instance arp('CM FM') will result in an array of notes [C4, E4, G4, F4, A4, C4, C5, E5]\n * You can even provide Params as an object.\n * For e.g. arp({count: 8, order: '10325476', chords: 'FM_4 Gm7b5_4 AbM_4 Bbm_4 Cm_5 DbM_5 EbM_5})\n */\nexport const arp = (chordsOrParams: string | ArpParams): string[] => {\n  let finalArr: string[] = [];\n  const params: ArpParams = {\n    count: 4,\n    order: '0123',\n    chords: '',\n  };\n\n  if (typeof chordsOrParams === 'string') {\n    params.chords = chordsOrParams;\n  } else {\n    if (chordsOrParams.order?.match(/\\D/g)) {\n      throw new TypeError('Invalid value for order');\n    }\n\n    if (chordsOrParams.count > 8 || chordsOrParams.count < 2) {\n      throw new TypeError('Invalid value for count');\n    }\n\n    // Provision a order for the notes in case only count was provided\n    if (chordsOrParams.count && !chordsOrParams.order) {\n      params.order = Array.from(Array(chordsOrParams.count).keys()).join('');\n    }\n    Object.assign(params, chordsOrParams);\n  }\n\n  // Chords can be passed as a string, e.g. 'CM_4 FM_4'\n  // or as an array of notes arrays e.g. [['C3', 'E3', 'G3', 'B3'], ['F3', 'A3', 'C4', 'E4']]\n  if (typeof params.chords === 'string') {\n    const chordsArr: string[] = params.chords.split(' ');\n    chordsArr.forEach((c, i) => {\n      try {\n        const filledArr = fillArr(inlineChord(c), params.count);\n        // reorder the filledArr as per params.order\n        const reorderedArr = (params.order as string)\n          .split('')\n          .map((idx: string) => filledArr[Number(idx)]);\n        finalArr = [...finalArr, ...reorderedArr];\n      } catch (_e) {\n        throw new Error(\n          `Cannot decode chord ${i + 1} \"${c}\" in given \"${params.chords}\"`\n        );\n      }\n    });\n  } else if (Array.isArray(params.chords)) {\n    params.chords.forEach((c, i) => {\n      try {\n        const filledArr = fillArr(c as string[], params.count);\n        // reorder the filledArr as per params.order\n        const reorderedArr = (params.order as string)\n          .split('')\n          .map((idx: string) => filledArr[Number(idx)]);\n        finalArr = [...finalArr, ...reorderedArr];\n      } catch (e) {\n        throw new Error(\n          `${errorHasMessage(e) ? e.message : e} in chord ${i + 1} \"${c}\"`\n        );\n      }\n    });\n  } else {\n    throw new TypeError('Invalid value for chords');\n  }\n\n  return finalArr;\n};\n","import { chord, inlineChord } from 'harmonics';\nimport type { PatternElement } from './types';\n\n/**\n * Take a string input and check if it s a note name or not\n * @param  {String} str Note name e.g. c4\n * @return {Boolean} Return true for c4 or return false for something like CM\n */\nexport const isNote = (str: string): boolean =>\n  /^[a-gA-G](?:#|b)?\\d$/.test(str);\n\n/**\n * Take a String input such as xxx[xx[xx]]\n * and return an Array as ['x', 'x', 'x', ['x', 'x', ['x', 'x']]]\n * @param  {String} str\n * @return {Array}\n */\nexport const expandStr = (str: string): PatternElement[] => {\n  str = JSON.stringify(str.split(''));\n  str = str.replace(/,\"\\[\",/g, ', [');\n  str = str.replace(/\"\\[\",/g, '[');\n  str = str.replace(/,\"\\]\"/g, ']');\n  return JSON.parse(str);\n};\n\n/**\n * Basic Array randomizer\n * @param  {Array} arr\n * @param  {boolean} fullShuffle Ensure no elements remain in old place\n * @return {Array}\n */\nexport const shuffle = <T>(arr: T[], fullShuffle = true): T[] => {\n  const lastIndex: number = arr.length - 1;\n\n  // Shuffle algorithm by Richard Durstenfeld (Donald E. Knuth), also Ronald Fisher and Frank Yates.\n  // \"Full Shuffle\" Modification to ensure no elements remain in their original place (by taking each element once\n  // and swapping with any remaining elements)\n  arr.forEach((el, idx: number) => {\n    if (idx >= lastIndex) {\n      // No shuffling last element\n      // One before last is always swapped with last at the end of the loop\n      // Since previous swaps can move last element into other places, there is still a random shuffle of last element\n      return;\n    }\n    // Swap el with one of the higher elements randomly\n    const rnd = fullShuffle\n      ? // Pick random number from idx+1 to lastIndex (Modified algorithm, (N-1)! combinations)\n        // Math.random -> [0, 1) -> [0, lastIndex-idx ) --floor-> [0, lastIndex-idx-1]\n        // rnd = [0, lastIndex-idx-1] + 1 + idx = [1 + idx, lastIndex]\n        // (Original algorithm would pick rnd = [idx, lastIndex], thus any element could arrive back into its slot)\n        Math.floor(Math.random() * (lastIndex - idx)) + 1 + idx\n      : // Pick random number from idx to lastIndex (Unmodified Richard Durstenfeld, N! combinations)\n        Math.floor(Math.random() * (lastIndex + 1 - idx)) + idx;\n    arr[idx] = arr[rnd];\n    arr[rnd] = el;\n  });\n\n  return arr;\n};\n\n/**\n * Return an array of numbers relative to maxLevel (default 127) ordered in a Sine wave format.\n * Used by the `sizzle` param of `clip` to add rudimentary variation to the accent of each note.\n * @param maxLevel A number not exceeding 127\n * @return Example: [63, 90, 110, 127, 110, 90, 63, 0, 63, 90, 110, 127, 110, 90, 63, 0]\n */\nexport const sizzleMap = (maxLevel = 127): number[] => {\n  const pi = Math.PI;\n  const piArr: number[] = [\n    pi / 6,\n    pi / 4,\n    pi / 3,\n    pi / 2,\n    (2 * pi) / 3,\n    (3 * pi) / 4,\n    (5 * pi) / 6,\n    pi,\n  ];\n  const piArrRev: number[] = [\n    0,\n    pi / 6,\n    pi / 4,\n    pi / 3,\n    pi / 2,\n    (2 * pi) / 3,\n    (3 * pi) / 4,\n    (5 * pi) / 6,\n  ];\n  piArrRev.reverse();\n  const arr: number[] = piArr.concat(piArrRev);\n  return arr.map(element => Math.round(Math.sin(element) * maxLevel));\n};\n\n/**\n * Pick one item randomly from an array and return it\n * @param arr\n */\nexport const pickOne = <T = unknown>(arr: T[]): T =>\n  arr[Math.floor(Math.random() * arr.length)];\n\n/**\n * Boolean generator\n */\nexport const dice = (): boolean => !!Math.round(Math.random());\n\n/** Type guard: check if a caught value has a string `message` property. */\nexport const errorHasMessage = (x: unknown): x is { message: string } => {\n  return (\n    typeof x === 'object' &&\n    x !== null &&\n    'message' in x &&\n    typeof (x as { message: unknown }).message === 'string'\n  );\n};\n\n/**\n *  'el' could be an inlineChord() e.g. Cmaj7 or Dbsus2_5\n *  or a chord() e.g. 'C3 M'\n */\nexport const convertChordToNotes = (el: string): string[] => {\n  // Try both inlineChord() and chord()\n  let c1: string[] | undefined;\n  let c2: string[] | undefined;\n  let e1: unknown;\n  let e2: unknown;\n  try {\n    c1 = inlineChord(el);\n  } catch (e) {\n    e1 = e;\n  }\n  try {\n    c2 = chord(el.replace(/_/g, ' ')); // chord() is not friendly to underscores\n  } catch (e) {\n    e2 = e;\n  }\n\n  if (!e1 && !e2 && c1 && c2) {\n    // Both inlineChord() and chord() have result\n    if (c1.toString() !== c2.toString()) {\n      throw new Error(`Chord ${el} cannot decode, guessing ${c1} or ${c2}`);\n    }\n    return c1;\n  } // else\n  if (!e1 && c1) {\n    return c1;\n  } // else\n  if (!e2 && c2) {\n    return c2;\n  } // else\n\n  // Give up, last try:\n  return chord(el);\n};\n\n/**\n * Normalize a note, chord name, or array of notes into a string array.\n * Single notes become `['C4']`, chord names are expanded via harmonics.\n */\nexport const convertChordsToNotes = (\n  el: string | (string | string[])[]\n): string[] => {\n  if (typeof el === 'string' && isNote(el as string)) {\n    // A note needs to be an array so that it can accomodate chords or single notes with a single interface\n    return [el];\n  }\n\n  if (Array.isArray(el)) {\n    // This could be a chord provided as an array or an array of arrays\n    el.forEach(n => {\n      // This could be a chord provided as an array\n      if (Array.isArray(n)) {\n        // TODO: Can we convert it to something useful?\n        // make sure it uses valid notes\n        n.forEach(n1 => {\n          if (typeof n1 !== 'string' || !isNote(n1)) {\n            throw new TypeError('array of arrays must comprise valid notes');\n          }\n        });\n        // throw new TypeError('cannot decode array of arrays');\n      } else if (typeof n !== 'string' || !isNote(n)) {\n        // make sure it uses valid notes\n        throw new TypeError('array must comprise valid notes');\n      }\n    });\n\n    return el as string[];\n    // ? return el as (string | string[])[];\n  }\n\n  if (!Array.isArray(el)) {\n    const c = convertChordToNotes(el);\n    if (c?.length) {\n      return c;\n    }\n  }\n\n  throw new Error(`Chord ${el} not found`);\n};\n\n/** Return a random integer from 0 to `num` (inclusive). */\nexport const randomInt = (num = 1): number => Math.round(Math.random() * num);\n","import type { ClipParams } from './types';\nimport { convertChordsToNotes, shuffle } from './utils';\n\nconst defaultParams: ClipParams = {\n  notes: ['C4'],\n  pattern: 'x',\n  shuffle: false,\n  sizzle: false,\n  sizzleReps: 1,\n  arpegiate: false,\n  subdiv: '4n',\n  amp: 100,\n  accentLow: 70,\n  randomNotes: null,\n  offlineRendering: false,\n};\n\n/** Throw if the pattern string contains characters outside `x - _ [ ] R`. */\nexport const validatePattern = (pattern: string): void => {\n  if (/[^x\\-_[\\]R]/.test(pattern)) {\n    throw new TypeError(\n      `pattern can only comprise x - _ [ ] R, found ${pattern}`\n    );\n  }\n};\n\n/**\n * Merge defaults into clip params, normalize notes/randomNotes from strings\n * to arrays, validate the pattern, and optionally shuffle notes.\n */\nexport const preprocessClipParams = (\n  params: ClipParams,\n  extraDefaults?: Partial<ClipParams>\n): ClipParams => {\n  params = { ...defaultParams, ...extraDefaults, ...(params || {}) };\n\n  // Notes: string → array\n  if (typeof params.notes === 'string') {\n    params.notes = params.notes.replace(/\\s{2,}/g, ' ').split(' ');\n  }\n  params.notes = params.notes ? params.notes.map(convertChordsToNotes) : [];\n\n  // Pattern validation\n  validatePattern(params.pattern);\n\n  // Shuffle\n  if (params.shuffle) {\n    params.notes = shuffle(params.notes);\n  }\n\n  // Random notes preprocessing\n  if (params.randomNotes && typeof params.randomNotes === 'string') {\n    params.randomNotes = params.randomNotes.replace(/\\s{2,}/g, ' ').split(/\\s/);\n  }\n  if (params.randomNotes) {\n    params.randomNotes = (params.randomNotes as string[]).map(\n      convertChordsToNotes\n    );\n  }\n\n  return params;\n};\n","import { preprocessClipParams } from './clip-utils';\nimport type {\n  ClipParams,\n  NoteObject,\n  NVP,\n  PatternElement,\n  SizzleStyle,\n} from './types';\nimport { expandStr, randomInt } from './utils';\n\n/**\n * HDR speed is denoted by the number of ticks per note\n * By default this is set to a quarter note (4n) to be in line with Tone.js' default subdivision\n * Technically a bar is 512 ticks long. So it's HDR speed is 512\n * @type {Object}\n */\nconst hdr: NVP<number> = {\n  '1m': 2048,\n  '2m': 4096,\n  '3m': 6144,\n  '4m': 8192,\n  '1n': 512,\n  '2n': 256,\n  '4n': 128,\n  '8n': 64,\n  '16n': 32,\n};\n\n/**\n * Generate an array of note objects from clip parameters (for MIDI export).\n * Applies the pattern to notes, then optionally adds sizzle and accent dynamics.\n */\nexport const clip = (params: ClipParams): NoteObject[] => {\n  params = preprocessClipParams(params);\n\n  const clipNotes: NoteObject[] = [];\n  let step = 0;\n  /**\n   * Recursively apply pattern to notes\n   *\n   * Pass in a pattern array such as ['x', '-', 'x', 'x'] with a length for each element\n   * The length is the HDR speed or tick length (obtained from the hdr object in this script)\n   * If the element of this array is also a (pattern) array, then divide the length by\n   * the length of the inner array and then call the recursive function on that inner array\n   */\n  const recursivelyApplyPatternToNotes = (\n    patternArr: PatternElement[],\n    length: number,\n    parentNoteLength: number | boolean\n  ) => {\n    let totalLength = 0;\n    patternArr.forEach((char, idx) => {\n      if (typeof char === 'string') {\n        let note: string[] | null = null;\n\n        if (char === '-') {\n          // note = null;\n        } else if (\n          char === 'R' &&\n          randomInt() && // Use 1/2 probability for R to pick from param.notes\n          params.randomNotes &&\n          params.randomNotes.length > 0\n        ) {\n          note = params.randomNotes[\n            randomInt(params.randomNotes.length - 1)\n          ] as string[];\n        } else if (params.notes) {\n          note = params.notes[step] as string[];\n        }\n\n        if (char === 'x' || char === 'R') {\n          step++;\n        }\n\n        // Push only note on OR off messages to the clip notes array\n        if (char === 'x' || char === '-' || char === 'R') {\n          clipNotes.push({\n            note,\n            length,\n            level:\n              char === 'R' && !params.randomNotes\n                ? (params.accentLow as number)\n                : (params.amp as number),\n          });\n          totalLength += length;\n        }\n\n        // In case of an underscore, simply extend the previous note's length\n        if (char === '_' && clipNotes.length) {\n          clipNotes[clipNotes.length - 1].length += length;\n          totalLength += length;\n        }\n\n        // if there were triplets in this iteration then ajust length of the last note\n        if (\n          parentNoteLength &&\n          totalLength !== parentNoteLength &&\n          idx === patternArr.length - 1\n        ) {\n          const diff: number = Math.abs(\n            (parentNoteLength as number) - totalLength\n          );\n          const lastClipNote = clipNotes[clipNotes.length - 1];\n          if (lastClipNote.length > diff) {\n            lastClipNote.length = lastClipNote.length - diff;\n          } else {\n            lastClipNote.length = lastClipNote.length + diff;\n          }\n        }\n\n        // If the pattern is longer than the notes, then repeat notes\n        if (step === params.notes?.length) {\n          step = 0;\n        }\n      }\n      // Note: The following condition is not in a else if simply because\n      // we do need to increment the totalLength in order to support triplets\n      if (Array.isArray(char)) {\n        let isTriplet = false;\n        // either this is a triplet or not\n        if (char.length % 2 !== 0 || length % 2 !== 0) {\n          isTriplet = true;\n        }\n        recursivelyApplyPatternToNotes(\n          char,\n          Math.round(length / char.length),\n          isTriplet && length\n        );\n        // Increment total length to support subsequent operations\n        // once we are out of the recursion\n        totalLength += length;\n      }\n    });\n  };\n\n  recursivelyApplyPatternToNotes(\n    expandStr(params.pattern),\n    hdr[params.subdiv as string] || hdr['4n'],\n    false\n  );\n\n  // Many thanks to @R1G for the following functionality\n  if (params.sizzle) {\n    const volArr = [];\n    const style: SizzleStyle = params.sizzle === true ? 'sin' : params.sizzle;\n    const beats: number = clipNotes.length;\n    const amp: number = params.amp as number;\n    const sizzleReps = params.sizzleReps as number;\n    const stepLevel = amp / (beats / sizzleReps);\n    if (style === 'sin' || style === 'cos') {\n      for (let i = 0; i < beats; i++) {\n        const level = Math[style]((i * Math.PI) / (beats / sizzleReps)) * amp;\n        volArr.push(Math.round(Math.abs(level)));\n      }\n    }\n\n    if (style === 'rampUp') {\n      let level = 0;\n      for (let i = 0; i < beats; i++) {\n        if (i % (beats / sizzleReps) === 0) {\n          level = 0;\n        } else {\n          level = level + stepLevel;\n        }\n        volArr.push(Math.round(Math.abs(level)));\n      }\n    }\n\n    if (style === 'rampDown') {\n      let level = amp;\n      for (let i = 0; i < beats; i++) {\n        if (i % (beats / sizzleReps) === 0) {\n          level = amp;\n        } else {\n          level = level - stepLevel;\n        }\n        volArr.push(Math.round(Math.abs(level)));\n      }\n    }\n\n    for (let i = 0; i < volArr.length; i++) {\n      clipNotes[i].level = volArr[i] ? volArr[i] : 1; // Cannot allow 0 value on level\n    }\n  }\n\n  if (params.accent) {\n    // TODO: Eslint barks at \\- as useless, need to verify that JS handles - without \\ properly.\n    if (/[^x-]/.test(params.accent)) {\n      throw new TypeError('Accent can only have x and - characters');\n    }\n\n    let a = 0;\n    for (const clipNote of clipNotes) {\n      let level =\n        params.accent[a] === 'x'\n          ? (params.amp as number)\n          : (params.accentLow as number);\n\n      if (params.sizzle) {\n        level = (clipNote.level + level) / 2;\n      }\n\n      clipNote.level = Math.round(level);\n\n      // Step to the next character in the accent\n      a = a + 1;\n\n      // Reset `a` so that it can loop over the accent\n      if (a === params.accent.length) {\n        a = 0;\n      }\n    }\n  }\n\n  return clipNotes;\n};\n","import fs from 'node:fs';\nimport { File, Track } from '@scribbletune/midi';\nimport type { NoteObject } from './types';\n\n/**\n * Take an array of note objects to generate a MIDI file in the same location as this method is called\n * @param  {NoteObject[]} notes    Notes are in the format: {note: ['c3'], level: 127, length: 64}\n * @param  {String | null} fileName If a filename is not provided, then `music.mid` is used by default\n * If `null` is passed for `fileName`, bytes are returned instead of creating a file\n * If this method is called from a browser then it will return a HTML link that you can append in your page\n * This link will enable the generated MIDI as a downloadable file.\n * @param {Number | null} bpm If a value is provided, the generated midi file will be set to this bpm value.\n */\nexport const midi = (\n  notes: NoteObject[],\n  fileName: string | null = 'music.mid',\n  bpm?: number\n): string | HTMLAnchorElement | undefined => {\n  const file = createFileFromNotes(notes, bpm);\n  const bytes = file.toBytes();\n\n  if (fileName === null) {\n    return bytes;\n  }\n\n  if (!fileName.endsWith('.mid')) {\n    fileName = `${fileName}.mid`;\n  }\n\n  if (\n    typeof window !== 'undefined' &&\n    window.URL &&\n    typeof window.URL.createObjectURL === 'function'\n  ) {\n    return createDownloadLink(bytes, fileName);\n  }\n\n  fs.writeFileSync(fileName, bytes, 'binary');\n  console.log(`MIDI file generated: ${fileName}.`);\n};\n\n/**\n * Create a downloadable link\n * @param b\n */\nconst createDownloadLink = (b: string, fileName: string): HTMLAnchorElement => {\n  // Convert bytes to array buffer\n  // Accepted answer on https://stackoverflow.com/questions/35038884/download-file-from-bytes-in-javascript\n  const bytes = new Uint8Array(b.length);\n  for (let i = 0; i < b.length; i++) {\n    const ascii = b.charCodeAt(i);\n    bytes[i] = ascii;\n  }\n\n  // Create a Blob so that we can set it up with the type of file we want (for eg MIDI)\n  const blob = new Blob([bytes], { type: 'audio/midi' });\n\n  // Create a link element to be used (you can use an existing link on the page as well)\n  const link = document.createElement('a');\n  link.href =\n    (typeof window !== 'undefined' &&\n      typeof window.URL !== 'undefined' &&\n      typeof window.URL.createObjectURL !== 'undefined' &&\n      window.URL.createObjectURL(blob)) ||\n    '';\n\n  // Give the downloadable file a name\n  link.download = fileName;\n  link.innerText = 'Download MIDI file';\n\n  return link;\n};\n\n/** Build a MIDI File with a single track from the given note objects. */\nconst createFileFromNotes = (notes: NoteObject[], bpm?: number) => {\n  const file = new File();\n  const track = new Track();\n\n  // set the track's bpm if it is provided\n  if (typeof bpm === 'number') {\n    track.setTempo(bpm);\n  }\n\n  file.addTrack(track);\n\n  for (const noteObj of notes) {\n    const level = noteObj.level || 127;\n    // While writing chords (multiple notes per tick)\n    // only the first noteOn (or noteOff) needs the complete arity of the function call\n    // subsequent calls need only the first 2 args (channel and note)\n    if (noteObj.note) {\n      if (typeof noteObj.note === 'string') {\n        track.noteOn(0, noteObj.note, noteObj.length, level); // channel, pitch(note), length, velocity\n        track.noteOff(0, noteObj.note, noteObj.length, level);\n      } else {\n        track.addChord(0, noteObj.note, noteObj.length, level);\n      }\n    } else {\n      track.noteOff(0, '', noteObj.length);\n    }\n  }\n\n  return file;\n};\n","import { scale } from 'harmonics';\nimport type { NVP, ProgressionScale, TPD } from './types';\nimport { dice, pickOne } from './utils';\n\n/**\n * Get the chords that go with a given scale/mode\n * This is useful only in case you want to check what chords work with a scale/mode\n * so that you can come up with chord progressions\n * @param  {String} mode e.g. major\n * @return {Array} e.g.['I', 'ii', 'iii', 'IV', 'V', 'vi', 'vii°']\n */\nexport const getChordDegrees = (mode: string): string[] => {\n  const theRomans: NVP<string[]> = {\n    ionian: ['I', 'ii', 'iii', 'IV', 'V', 'vi', 'vii°'],\n    dorian: ['i', 'ii', 'III', 'IV', 'v', 'vi°', 'VII'],\n    phrygian: ['i', 'II', 'III', 'iv', 'v°', 'VI', 'vii'],\n    lydian: ['I', 'II', 'iii', 'iv°', 'V', 'vi', 'vii'],\n    mixolydian: ['I', 'ii', 'iii°', 'IV', 'v', 'vi', 'VII'],\n    aeolian: ['i', 'ii°', 'III', 'iv', 'v', 'VI', 'VII'],\n    locrian: ['i°', 'II', 'iii', 'iv', 'V', 'VI', 'vii'],\n    'melodic minor': ['i', 'ii', 'III+', 'IV', 'V', 'vi°', 'vii°'],\n    'harmonic minor': ['i', 'ii°', 'III+', 'iv', 'V', 'VI', 'vii°'],\n  };\n  theRomans.major = theRomans.ionian;\n  theRomans.minor = theRomans.aeolian;\n\n  return theRomans[mode] || [];\n};\n\nconst idxByDegree: NVP<number> = {\n  i: 0,\n  ii: 1,\n  iii: 2,\n  iv: 3,\n  v: 4,\n  vi: 5,\n  vii: 6,\n};\n\n/**\n * Get a chord name from degree\n * @param  {String} roman e.g. ii OR ii° OR V7\n * @return {String} e.g. m OR m7b5 OR Maj7\n */\nconst getChordName = (roman: string): string => {\n  // remove any non character\n  const str = roman.replace(/\\W/g, '');\n  let prefix = 'M';\n  // check if it s lowercase\n  if (str.toLowerCase() === str) {\n    prefix = 'm';\n  }\n  if (roman.indexOf('°') > -1) {\n    return `${prefix}7b5`;\n  }\n  if (roman.indexOf('+') > -1) {\n    return `${prefix}#5`;\n  }\n\n  if (roman.indexOf('7') > -1) {\n    return prefix === 'M' ? 'maj7' : 'm7';\n  }\n\n  return prefix;\n};\n\n/**\n * Take the specified scale and degrees and return the chord names for them\n * These can be used as the value for the `notes` param of the `clip` method\n * @param {String} noteOctaveScale e.g. 'C4 major'\n * @param  {String} chordDegress e.g. 'I IV V IV'\n * @return {String} e.g. 'CM FM GM FM'\n */\nexport const getChordsByProgression = (\n  noteOctaveScale: string,\n  chordDegress: string\n): string => {\n  // Set the octave if missing\n  // For example if the method was called with `C major` instead of `C4 major`, then add the 4\n  const noteOctaveScaleArr = noteOctaveScale.split(' ');\n  if (!noteOctaveScaleArr[0].match(/\\d/)) {\n    noteOctaveScaleArr[0] += '4';\n    noteOctaveScale = noteOctaveScaleArr.join(' ');\n  }\n\n  // Get the scale from the given note and scale/mode combination\n  const mode = scale(noteOctaveScale);\n  const chordDegreesArr = chordDegress.replace(/\\s*,+\\s*/g, ' ').split(' ');\n  // Now we have something like ['i', 'ii', 'IV']\n  // Convert it to a chord family such as ['Cm', 'Dm', 'FM']\n  const chordFamily = chordDegreesArr.map(roman => {\n    const chordName = getChordName(roman); // e.g. m\n    // get the index to be used by removing any digit or non alphabet character\n    const scaleId = idxByDegree[roman.replace(/\\W|\\d/g, '').toLowerCase()]; // e.g. 0\n    // get the note itself\n    const note = mode[scaleId]; // e.g. C\n    // get the octave of the note;\n    const oct = note.replace(/\\D+/, ''); // e.g. 4\n    // now get the chord\n    return `${note.replace(/\\d/, '') + chordName}_${oct}`;\n  });\n\n  return chordFamily.toString().replace(/,/g, ' ');\n};\n\n/** Create a progression generator that follows tonic -> predominant -> dominant flow. */\nconst getProgFactory = ({ T, P, D }: TPD) => {\n  return (count = 4) => {\n    const chords = [];\n\n    // Push root/tonic\n    chords.push(pickOne(T));\n\n    let i = 1;\n\n    // Pick a predominant\n    if (i < count - 1) {\n      chords.push(pickOne(P));\n      i++;\n    }\n\n    // Try another predominant\n    if (i < count - 1 && dice()) {\n      chords.push(pickOne(P));\n      i++;\n    }\n\n    // /////// 4 or more//////////\n    if (i < count - 1) {\n      // Pick a dominant\n      chords.push(pickOne(D));\n      i++;\n    }\n\n    if (i < count - 1) {\n      // Pick a predominant\n      chords.push(pickOne(P));\n      i++;\n    }\n\n    if (i < count - 1) {\n      // Pick a dominant\n      chords.push(pickOne(D));\n      i++;\n    }\n\n    // Pick a predominant if possible\n    if (i < count - 1 && dice()) {\n      chords.push(pickOne(P));\n      i++;\n    }\n    // //////////////////////////\n\n    // Fill the rest with dominant\n    while (i < count) {\n      chords.push(pickOne(D));\n      i++;\n    }\n\n    return chords;\n  };\n};\n\nconst M = getProgFactory({ T: ['I', 'vi'], P: ['ii', 'IV'], D: ['V'] });\nconst m = getProgFactory({ T: ['i', 'VI'], P: ['ii', 'iv'], D: ['V'] });\n\n/**\n * Generate a chord progression based on basic music theory\n * where we follow tonic to optionally predominant and then dominant\n * and then randomly to predominant and continue this till we reach `count`\n * @param scaleType e.g. M (for major chord progression), m (for minor chord progression)\n * @param count e.g. 4\n */\nexport const progression = (\n  scaleType: ProgressionScale,\n  count = 4\n): string[] => {\n  if (scaleType === 'major' || scaleType === 'M') {\n    return M(count);\n  }\n\n  if (scaleType === 'minor' || scaleType === 'm') {\n    return m(count);\n  }\n\n  return [];\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,oBAA6C;;;ACA7C,IAAAC,oBAA4B;;;ACA5B,uBAAmC;AAQ5B,IAAM,SAAS,CAAC,QACrB,uBAAuB,KAAK,GAAG;AAQ1B,IAAM,YAAY,CAAC,QAAkC;AAC1D,QAAM,KAAK,UAAU,IAAI,MAAM,EAAE,CAAC;AAClC,QAAM,IAAI,QAAQ,WAAW,KAAK;AAClC,QAAM,IAAI,QAAQ,UAAU,GAAG;AAC/B,QAAM,IAAI,QAAQ,UAAU,GAAG;AAC/B,SAAO,KAAK,MAAM,GAAG;AACvB;AAQO,IAAM,UAAU,CAAI,KAAU,cAAc,SAAc;AAC/D,QAAM,YAAoB,IAAI,SAAS;AAKvC,MAAI,QAAQ,CAAC,IAAI,QAAgB;AAC/B,QAAI,OAAO,WAAW;AAIpB;AAAA,IACF;AAEA,UAAM,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,MAKR,KAAK,MAAM,KAAK,OAAO,KAAK,YAAY,IAAI,IAAI,IAAI;AAAA;AAAA;AAAA,MAEpD,KAAK,MAAM,KAAK,OAAO,KAAK,YAAY,IAAI,IAAI,IAAI;AAAA;AACxD,QAAI,GAAG,IAAI,IAAI,GAAG;AAClB,QAAI,GAAG,IAAI;AAAA,EACb,CAAC;AAED,SAAO;AACT;AAQO,IAAM,YAAY,CAAC,WAAW,QAAkB;AACrD,QAAM,KAAK,KAAK;AAChB,QAAM,QAAkB;AAAA,IACtB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACJ,IAAI,KAAM;AAAA,IACV,IAAI,KAAM;AAAA,IACV,IAAI,KAAM;AAAA,IACX;AAAA,EACF;AACA,QAAM,WAAqB;AAAA,IACzB;AAAA,IACA,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACJ,IAAI,KAAM;AAAA,IACV,IAAI,KAAM;AAAA,IACV,IAAI,KAAM;AAAA,EACb;AACA,WAAS,QAAQ;AACjB,QAAM,MAAgB,MAAM,OAAO,QAAQ;AAC3C,SAAO,IAAI,IAAI,aAAW,KAAK,MAAM,KAAK,IAAI,OAAO,IAAI,QAAQ,CAAC;AACpE;AAMO,IAAM,UAAU,CAAc,QACnC,IAAI,KAAK,MAAM,KAAK,OAAO,IAAI,IAAI,MAAM,CAAC;AAKrC,IAAM,OAAO,MAAe,CAAC,CAAC,KAAK,MAAM,KAAK,OAAO,CAAC;AAGtD,IAAM,kBAAkB,CAAC,MAAyC;AACvE,SACE,OAAO,MAAM,YACb,MAAM,QACN,aAAa,KACb,OAAQ,EAA2B,YAAY;AAEnD;AAMO,IAAM,sBAAsB,CAAC,OAAyB;AAE3D,MAAI;AACJ,MAAI;AACJ,MAAI;AACJ,MAAI;AACJ,MAAI;AACF,aAAK,8BAAY,EAAE;AAAA,EACrB,SAAS,GAAG;AACV,SAAK;AAAA,EACP;AACA,MAAI;AACF,aAAK,wBAAM,GAAG,QAAQ,MAAM,GAAG,CAAC;AAAA,EAClC,SAAS,GAAG;AACV,SAAK;AAAA,EACP;AAEA,MAAI,CAAC,MAAM,CAAC,MAAM,MAAM,IAAI;AAE1B,QAAI,GAAG,SAAS,MAAM,GAAG,SAAS,GAAG;AACnC,YAAM,IAAI,MAAM,SAAS,EAAE,4BAA4B,EAAE,OAAO,EAAE,EAAE;AAAA,IACtE;AACA,WAAO;AAAA,EACT;AACA,MAAI,CAAC,MAAM,IAAI;AACb,WAAO;AAAA,EACT;AACA,MAAI,CAAC,MAAM,IAAI;AACb,WAAO;AAAA,EACT;AAGA,aAAO,wBAAM,EAAE;AACjB;AAMO,IAAM,uBAAuB,CAClC,OACa;AACb,MAAI,OAAO,OAAO,YAAY,OAAO,EAAY,GAAG;AAElD,WAAO,CAAC,EAAE;AAAA,EACZ;AAEA,MAAI,MAAM,QAAQ,EAAE,GAAG;AAErB,OAAG,QAAQ,OAAK;AAEd,UAAI,MAAM,QAAQ,CAAC,GAAG;AAGpB,UAAE,QAAQ,QAAM;AACd,cAAI,OAAO,OAAO,YAAY,CAAC,OAAO,EAAE,GAAG;AACzC,kBAAM,IAAI,UAAU,2CAA2C;AAAA,UACjE;AAAA,QACF,CAAC;AAAA,MAEH,WAAW,OAAO,MAAM,YAAY,CAAC,OAAO,CAAC,GAAG;AAE9C,cAAM,IAAI,UAAU,iCAAiC;AAAA,MACvD;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EAET;AAEA,MAAI,CAAC,MAAM,QAAQ,EAAE,GAAG;AACtB,UAAM,IAAI,oBAAoB,EAAE;AAChC,QAAI,GAAG,QAAQ;AACb,aAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,SAAS,EAAE,YAAY;AACzC;AAGO,IAAM,YAAY,CAAC,MAAM,MAAc,KAAK,MAAM,KAAK,OAAO,IAAI,GAAG;;;ADpM5E,IAAM,iBAAiB;AAQvB,IAAM,UAAU,CAAC,KAAe,QAA0B;AACxD,QAAM,aAAa,CAAC,OAAuB;AACzC,QAAI,CAAC,IAAI;AACP,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AACA,UAAM,OAAO,GAAG,QAAQ,MAAM,EAAE;AAChC,UAAM,MAAM,GAAG,QAAQ,OAAO,EAAE,KAAK;AACrC,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,gBAAgB;AAAA,IAClC;AACA,WAAO,QAAQ,CAAC,MAAM;AAAA,EACxB;AAIA,QAAM,OAAO,IAAI,IAAI,UAAU;AAC/B,QAAM,OAAO,KAAK,IAAI,UAAU;AAChC,QAAM,WAAW,CAAC,GAAG,KAAK,GAAG,MAAM,GAAG,IAAI;AAG1C,SAAO,SAAS,MAAM,GAAG,GAAG;AAC9B;AAUO,IAAM,MAAM,CAAC,mBAAiD;AACnE,MAAI,WAAqB,CAAC;AAC1B,QAAM,SAAoB;AAAA,IACxB,OAAO;AAAA,IACP,OAAO;AAAA,IACP,QAAQ;AAAA,EACV;AAEA,MAAI,OAAO,mBAAmB,UAAU;AACtC,WAAO,SAAS;AAAA,EAClB,OAAO;AACL,QAAI,eAAe,OAAO,MAAM,KAAK,GAAG;AACtC,YAAM,IAAI,UAAU,yBAAyB;AAAA,IAC/C;AAEA,QAAI,eAAe,QAAQ,KAAK,eAAe,QAAQ,GAAG;AACxD,YAAM,IAAI,UAAU,yBAAyB;AAAA,IAC/C;AAGA,QAAI,eAAe,SAAS,CAAC,eAAe,OAAO;AACjD,aAAO,QAAQ,MAAM,KAAK,MAAM,eAAe,KAAK,EAAE,KAAK,CAAC,EAAE,KAAK,EAAE;AAAA,IACvE;AACA,WAAO,OAAO,QAAQ,cAAc;AAAA,EACtC;AAIA,MAAI,OAAO,OAAO,WAAW,UAAU;AACrC,UAAM,YAAsB,OAAO,OAAO,MAAM,GAAG;AACnD,cAAU,QAAQ,CAAC,GAAG,MAAM;AAC1B,UAAI;AACF,cAAM,YAAY,YAAQ,+BAAY,CAAC,GAAG,OAAO,KAAK;AAEtD,cAAM,eAAgB,OAAO,MAC1B,MAAM,EAAE,EACR,IAAI,CAAC,QAAgB,UAAU,OAAO,GAAG,CAAC,CAAC;AAC9C,mBAAW,CAAC,GAAG,UAAU,GAAG,YAAY;AAAA,MAC1C,SAAS,IAAI;AACX,cAAM,IAAI;AAAA,UACR,uBAAuB,IAAI,CAAC,KAAK,CAAC,eAAe,OAAO,MAAM;AAAA,QAChE;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH,WAAW,MAAM,QAAQ,OAAO,MAAM,GAAG;AACvC,WAAO,OAAO,QAAQ,CAAC,GAAG,MAAM;AAC9B,UAAI;AACF,cAAM,YAAY,QAAQ,GAAe,OAAO,KAAK;AAErD,cAAM,eAAgB,OAAO,MAC1B,MAAM,EAAE,EACR,IAAI,CAAC,QAAgB,UAAU,OAAO,GAAG,CAAC,CAAC;AAC9C,mBAAW,CAAC,GAAG,UAAU,GAAG,YAAY;AAAA,MAC1C,SAAS,GAAG;AACV,cAAM,IAAI;AAAA,UACR,GAAG,gBAAgB,CAAC,IAAI,EAAE,UAAU,CAAC,aAAa,IAAI,CAAC,KAAK,CAAC;AAAA,QAC/D;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH,OAAO;AACL,UAAM,IAAI,UAAU,0BAA0B;AAAA,EAChD;AAEA,SAAO;AACT;;;AExGA,IAAM,gBAA4B;AAAA,EAChC,OAAO,CAAC,IAAI;AAAA,EACZ,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,WAAW;AAAA,EACX,aAAa;AAAA,EACb,kBAAkB;AACpB;AAGO,IAAM,kBAAkB,CAAC,YAA0B;AACxD,MAAI,cAAc,KAAK,OAAO,GAAG;AAC/B,UAAM,IAAI;AAAA,MACR,gDAAgD,OAAO;AAAA,IACzD;AAAA,EACF;AACF;AAMO,IAAM,uBAAuB,CAClC,QACA,kBACe;AACf,WAAS,EAAE,GAAG,eAAe,GAAG,eAAe,GAAI,UAAU,CAAC,EAAG;AAGjE,MAAI,OAAO,OAAO,UAAU,UAAU;AACpC,WAAO,QAAQ,OAAO,MAAM,QAAQ,WAAW,GAAG,EAAE,MAAM,GAAG;AAAA,EAC/D;AACA,SAAO,QAAQ,OAAO,QAAQ,OAAO,MAAM,IAAI,oBAAoB,IAAI,CAAC;AAGxE,kBAAgB,OAAO,OAAO;AAG9B,MAAI,OAAO,SAAS;AAClB,WAAO,QAAQ,QAAQ,OAAO,KAAK;AAAA,EACrC;AAGA,MAAI,OAAO,eAAe,OAAO,OAAO,gBAAgB,UAAU;AAChE,WAAO,cAAc,OAAO,YAAY,QAAQ,WAAW,GAAG,EAAE,MAAM,IAAI;AAAA,EAC5E;AACA,MAAI,OAAO,aAAa;AACtB,WAAO,cAAe,OAAO,YAAyB;AAAA,MACpD;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;AC7CA,IAAM,MAAmB;AAAA,EACvB,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AACT;AAMO,IAAM,OAAO,CAAC,WAAqC;AACxD,WAAS,qBAAqB,MAAM;AAEpC,QAAM,YAA0B,CAAC;AACjC,MAAI,OAAO;AASX,QAAM,iCAAiC,CACrC,YACA,QACA,qBACG;AACH,QAAI,cAAc;AAClB,eAAW,QAAQ,CAAC,MAAM,QAAQ;AAChC,UAAI,OAAO,SAAS,UAAU;AAC5B,YAAI,OAAwB;AAE5B,YAAI,SAAS,KAAK;AAAA,QAElB,WACE,SAAS,OACT,UAAU;AAAA,QACV,OAAO,eACP,OAAO,YAAY,SAAS,GAC5B;AACA,iBAAO,OAAO,YACZ,UAAU,OAAO,YAAY,SAAS,CAAC,CACzC;AAAA,QACF,WAAW,OAAO,OAAO;AACvB,iBAAO,OAAO,MAAM,IAAI;AAAA,QAC1B;AAEA,YAAI,SAAS,OAAO,SAAS,KAAK;AAChC;AAAA,QACF;AAGA,YAAI,SAAS,OAAO,SAAS,OAAO,SAAS,KAAK;AAChD,oBAAU,KAAK;AAAA,YACb;AAAA,YACA;AAAA,YACA,OACE,SAAS,OAAO,CAAC,OAAO,cACnB,OAAO,YACP,OAAO;AAAA,UAChB,CAAC;AACD,yBAAe;AAAA,QACjB;AAGA,YAAI,SAAS,OAAO,UAAU,QAAQ;AACpC,oBAAU,UAAU,SAAS,CAAC,EAAE,UAAU;AAC1C,yBAAe;AAAA,QACjB;AAGA,YACE,oBACA,gBAAgB,oBAChB,QAAQ,WAAW,SAAS,GAC5B;AACA,gBAAM,OAAe,KAAK;AAAA,YACvB,mBAA8B;AAAA,UACjC;AACA,gBAAM,eAAe,UAAU,UAAU,SAAS,CAAC;AACnD,cAAI,aAAa,SAAS,MAAM;AAC9B,yBAAa,SAAS,aAAa,SAAS;AAAA,UAC9C,OAAO;AACL,yBAAa,SAAS,aAAa,SAAS;AAAA,UAC9C;AAAA,QACF;AAGA,YAAI,SAAS,OAAO,OAAO,QAAQ;AACjC,iBAAO;AAAA,QACT;AAAA,MACF;AAGA,UAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,YAAI,YAAY;AAEhB,YAAI,KAAK,SAAS,MAAM,KAAK,SAAS,MAAM,GAAG;AAC7C,sBAAY;AAAA,QACd;AACA;AAAA,UACE;AAAA,UACA,KAAK,MAAM,SAAS,KAAK,MAAM;AAAA,UAC/B,aAAa;AAAA,QACf;AAGA,uBAAe;AAAA,MACjB;AAAA,IACF,CAAC;AAAA,EACH;AAEA;AAAA,IACE,UAAU,OAAO,OAAO;AAAA,IACxB,IAAI,OAAO,MAAgB,KAAK,IAAI,IAAI;AAAA,IACxC;AAAA,EACF;AAGA,MAAI,OAAO,QAAQ;AACjB,UAAM,SAAS,CAAC;AAChB,UAAM,QAAqB,OAAO,WAAW,OAAO,QAAQ,OAAO;AACnE,UAAM,QAAgB,UAAU;AAChC,UAAM,MAAc,OAAO;AAC3B,UAAM,aAAa,OAAO;AAC1B,UAAM,YAAY,OAAO,QAAQ;AACjC,QAAI,UAAU,SAAS,UAAU,OAAO;AACtC,eAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,cAAM,QAAQ,KAAK,KAAK,EAAG,IAAI,KAAK,MAAO,QAAQ,WAAW,IAAI;AAClE,eAAO,KAAK,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,CAAC;AAAA,MACzC;AAAA,IACF;AAEA,QAAI,UAAU,UAAU;AACtB,UAAI,QAAQ;AACZ,eAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,YAAI,KAAK,QAAQ,gBAAgB,GAAG;AAClC,kBAAQ;AAAA,QACV,OAAO;AACL,kBAAQ,QAAQ;AAAA,QAClB;AACA,eAAO,KAAK,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,CAAC;AAAA,MACzC;AAAA,IACF;AAEA,QAAI,UAAU,YAAY;AACxB,UAAI,QAAQ;AACZ,eAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,YAAI,KAAK,QAAQ,gBAAgB,GAAG;AAClC,kBAAQ;AAAA,QACV,OAAO;AACL,kBAAQ,QAAQ;AAAA,QAClB;AACA,eAAO,KAAK,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,CAAC;AAAA,MACzC;AAAA,IACF;AAEA,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,gBAAU,CAAC,EAAE,QAAQ,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI;AAAA,IAC/C;AAAA,EACF;AAEA,MAAI,OAAO,QAAQ;AAEjB,QAAI,QAAQ,KAAK,OAAO,MAAM,GAAG;AAC/B,YAAM,IAAI,UAAU,yCAAyC;AAAA,IAC/D;AAEA,QAAI,IAAI;AACR,eAAW,YAAY,WAAW;AAChC,UAAI,QACF,OAAO,OAAO,CAAC,MAAM,MAChB,OAAO,MACP,OAAO;AAEd,UAAI,OAAO,QAAQ;AACjB,iBAAS,SAAS,QAAQ,SAAS;AAAA,MACrC;AAEA,eAAS,QAAQ,KAAK,MAAM,KAAK;AAGjC,UAAI,IAAI;AAGR,UAAI,MAAM,OAAO,OAAO,QAAQ;AAC9B,YAAI;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;ACvNA,qBAAe;AACf,kBAA4B;AAYrB,IAAM,OAAO,CAClB,OACA,WAA0B,aAC1B,QAC2C;AAC3C,QAAM,OAAO,oBAAoB,OAAO,GAAG;AAC3C,QAAM,QAAQ,KAAK,QAAQ;AAE3B,MAAI,aAAa,MAAM;AACrB,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,SAAS,SAAS,MAAM,GAAG;AAC9B,eAAW,GAAG,QAAQ;AAAA,EACxB;AAEA,MACE,OAAO,WAAW,eAClB,OAAO,OACP,OAAO,OAAO,IAAI,oBAAoB,YACtC;AACA,WAAO,mBAAmB,OAAO,QAAQ;AAAA,EAC3C;AAEA,iBAAAC,QAAG,cAAc,UAAU,OAAO,QAAQ;AAC1C,UAAQ,IAAI,wBAAwB,QAAQ,GAAG;AACjD;AAMA,IAAM,qBAAqB,CAAC,GAAW,aAAwC;AAG7E,QAAM,QAAQ,IAAI,WAAW,EAAE,MAAM;AACrC,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;AACjC,UAAM,QAAQ,EAAE,WAAW,CAAC;AAC5B,UAAM,CAAC,IAAI;AAAA,EACb;AAGA,QAAM,OAAO,IAAI,KAAK,CAAC,KAAK,GAAG,EAAE,MAAM,aAAa,CAAC;AAGrD,QAAM,OAAO,SAAS,cAAc,GAAG;AACvC,OAAK,OACF,OAAO,WAAW,eACjB,OAAO,OAAO,QAAQ,eACtB,OAAO,OAAO,IAAI,oBAAoB,eACtC,OAAO,IAAI,gBAAgB,IAAI,KACjC;AAGF,OAAK,WAAW;AAChB,OAAK,YAAY;AAEjB,SAAO;AACT;AAGA,IAAM,sBAAsB,CAAC,OAAqB,QAAiB;AACjE,QAAM,OAAO,IAAI,iBAAK;AACtB,QAAM,QAAQ,IAAI,kBAAM;AAGxB,MAAI,OAAO,QAAQ,UAAU;AAC3B,UAAM,SAAS,GAAG;AAAA,EACpB;AAEA,OAAK,SAAS,KAAK;AAEnB,aAAW,WAAW,OAAO;AAC3B,UAAM,QAAQ,QAAQ,SAAS;AAI/B,QAAI,QAAQ,MAAM;AAChB,UAAI,OAAO,QAAQ,SAAS,UAAU;AACpC,cAAM,OAAO,GAAG,QAAQ,MAAM,QAAQ,QAAQ,KAAK;AACnD,cAAM,QAAQ,GAAG,QAAQ,MAAM,QAAQ,QAAQ,KAAK;AAAA,MACtD,OAAO;AACL,cAAM,SAAS,GAAG,QAAQ,MAAM,QAAQ,QAAQ,KAAK;AAAA,MACvD;AAAA,IACF,OAAO;AACL,YAAM,QAAQ,GAAG,IAAI,QAAQ,MAAM;AAAA,IACrC;AAAA,EACF;AAEA,SAAO;AACT;;;ACvGA,IAAAC,oBAAsB;AAWf,IAAM,kBAAkB,CAAC,SAA2B;AACzD,QAAM,YAA2B;AAAA,IAC/B,QAAQ,CAAC,KAAK,MAAM,OAAO,MAAM,KAAK,MAAM,SAAM;AAAA,IAClD,QAAQ,CAAC,KAAK,MAAM,OAAO,MAAM,KAAK,UAAO,KAAK;AAAA,IAClD,UAAU,CAAC,KAAK,MAAM,OAAO,MAAM,SAAM,MAAM,KAAK;AAAA,IACpD,QAAQ,CAAC,KAAK,MAAM,OAAO,UAAO,KAAK,MAAM,KAAK;AAAA,IAClD,YAAY,CAAC,KAAK,MAAM,WAAQ,MAAM,KAAK,MAAM,KAAK;AAAA,IACtD,SAAS,CAAC,KAAK,UAAO,OAAO,MAAM,KAAK,MAAM,KAAK;AAAA,IACnD,SAAS,CAAC,SAAM,MAAM,OAAO,MAAM,KAAK,MAAM,KAAK;AAAA,IACnD,iBAAiB,CAAC,KAAK,MAAM,QAAQ,MAAM,KAAK,UAAO,SAAM;AAAA,IAC7D,kBAAkB,CAAC,KAAK,UAAO,QAAQ,MAAM,KAAK,MAAM,SAAM;AAAA,EAChE;AACA,YAAU,QAAQ,UAAU;AAC5B,YAAU,QAAQ,UAAU;AAE5B,SAAO,UAAU,IAAI,KAAK,CAAC;AAC7B;AAEA,IAAM,cAA2B;AAAA,EAC/B,GAAG;AAAA,EACH,IAAI;AAAA,EACJ,KAAK;AAAA,EACL,IAAI;AAAA,EACJ,GAAG;AAAA,EACH,IAAI;AAAA,EACJ,KAAK;AACP;AAOA,IAAM,eAAe,CAAC,UAA0B;AAE9C,QAAM,MAAM,MAAM,QAAQ,OAAO,EAAE;AACnC,MAAI,SAAS;AAEb,MAAI,IAAI,YAAY,MAAM,KAAK;AAC7B,aAAS;AAAA,EACX;AACA,MAAI,MAAM,QAAQ,MAAG,IAAI,IAAI;AAC3B,WAAO,GAAG,MAAM;AAAA,EAClB;AACA,MAAI,MAAM,QAAQ,GAAG,IAAI,IAAI;AAC3B,WAAO,GAAG,MAAM;AAAA,EAClB;AAEA,MAAI,MAAM,QAAQ,GAAG,IAAI,IAAI;AAC3B,WAAO,WAAW,MAAM,SAAS;AAAA,EACnC;AAEA,SAAO;AACT;AASO,IAAM,yBAAyB,CACpC,iBACA,iBACW;AAGX,QAAM,qBAAqB,gBAAgB,MAAM,GAAG;AACpD,MAAI,CAAC,mBAAmB,CAAC,EAAE,MAAM,IAAI,GAAG;AACtC,uBAAmB,CAAC,KAAK;AACzB,sBAAkB,mBAAmB,KAAK,GAAG;AAAA,EAC/C;AAGA,QAAM,WAAO,yBAAM,eAAe;AAClC,QAAM,kBAAkB,aAAa,QAAQ,aAAa,GAAG,EAAE,MAAM,GAAG;AAGxE,QAAM,cAAc,gBAAgB,IAAI,WAAS;AAC/C,UAAM,YAAY,aAAa,KAAK;AAEpC,UAAM,UAAU,YAAY,MAAM,QAAQ,UAAU,EAAE,EAAE,YAAY,CAAC;AAErE,UAAM,OAAO,KAAK,OAAO;AAEzB,UAAM,MAAM,KAAK,QAAQ,OAAO,EAAE;AAElC,WAAO,GAAG,KAAK,QAAQ,MAAM,EAAE,IAAI,SAAS,IAAI,GAAG;AAAA,EACrD,CAAC;AAED,SAAO,YAAY,SAAS,EAAE,QAAQ,MAAM,GAAG;AACjD;AAGA,IAAM,iBAAiB,CAAC,EAAE,GAAG,GAAG,EAAE,MAAW;AAC3C,SAAO,CAAC,QAAQ,MAAM;AACpB,UAAMC,UAAS,CAAC;AAGhB,IAAAA,QAAO,KAAK,QAAQ,CAAC,CAAC;AAEtB,QAAI,IAAI;AAGR,QAAI,IAAI,QAAQ,GAAG;AACjB,MAAAA,QAAO,KAAK,QAAQ,CAAC,CAAC;AACtB;AAAA,IACF;AAGA,QAAI,IAAI,QAAQ,KAAK,KAAK,GAAG;AAC3B,MAAAA,QAAO,KAAK,QAAQ,CAAC,CAAC;AACtB;AAAA,IACF;AAGA,QAAI,IAAI,QAAQ,GAAG;AAEjB,MAAAA,QAAO,KAAK,QAAQ,CAAC,CAAC;AACtB;AAAA,IACF;AAEA,QAAI,IAAI,QAAQ,GAAG;AAEjB,MAAAA,QAAO,KAAK,QAAQ,CAAC,CAAC;AACtB;AAAA,IACF;AAEA,QAAI,IAAI,QAAQ,GAAG;AAEjB,MAAAA,QAAO,KAAK,QAAQ,CAAC,CAAC;AACtB;AAAA,IACF;AAGA,QAAI,IAAI,QAAQ,KAAK,KAAK,GAAG;AAC3B,MAAAA,QAAO,KAAK,QAAQ,CAAC,CAAC;AACtB;AAAA,IACF;AAIA,WAAO,IAAI,OAAO;AAChB,MAAAA,QAAO,KAAK,QAAQ,CAAC,CAAC;AACtB;AAAA,IACF;AAEA,WAAOA;AAAA,EACT;AACF;AAEA,IAAM,IAAI,eAAe,EAAE,GAAG,CAAC,KAAK,IAAI,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,EAAE,CAAC;AACtE,IAAM,IAAI,eAAe,EAAE,GAAG,CAAC,KAAK,IAAI,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,EAAE,CAAC;AAS/D,IAAM,cAAc,CACzB,WACA,QAAQ,MACK;AACb,MAAI,cAAc,WAAW,cAAc,KAAK;AAC9C,WAAO,EAAE,KAAK;AAAA,EAChB;AAEA,MAAI,cAAc,WAAW,cAAc,KAAK;AAC9C,WAAO,EAAE,KAAK;AAAA,EAChB;AAEA,SAAO,CAAC;AACV;","names":["import_harmonics","import_harmonics","fs","import_harmonics","chords"]}