{"version":3,"sources":["../src/browser-index.ts","../src/arp.ts","../src/utils.ts","../src/channel/instrument-factory.ts","../src/channel/sequence-builder.ts","../src/clip-utils.ts","../src/browser-clip.ts","../src/midi.ts","../src/progression.ts","../src/channel/effects-chain.ts","../src/channel.ts","../src/session.ts"],"sourcesContent":["import { chord, chords, scale, scales } from 'harmonics';\nimport { arp } from './arp';\nimport { clip } from './browser-clip';\nimport { midi } from './midi';\nimport {\n  getChordDegrees,\n  getChordsByProgression,\n  progression,\n} from './progression';\nimport { Session } from './session';\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  Session,\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 { ChannelParams, SynthParams } from '../types';\nimport { errorHasMessage } from '../utils';\n\n/**\n * Check Tone.js object loaded state and either invoke `resolve` right away, or attach to and wait using Tone onload cb.\n * It's an ugly hack that reaches into Tone's internal ._buffers or ._buffer to insert itself into .onload() callback.\n * Tone has different ways to pull the onload callback from within to the API, so this implementation is very brittle.\n * The sole reason for its existence is to handle async loaded state of Tone instruments that we allow to pass in from outside.\n * If that option is eliminated, then this hacky function can be killed (or re-implemented via public onload API)\n * @param toneObject Tone.js object (will work with non-Tone objects that have same loaded/onload properties)\n * @param resolve onload callback\n */\nexport function checkToneObjLoaded(\n  toneObject: ToneLoadable,\n  resolve: () => void\n): void {\n  const skipRecursion = toneObject instanceof Tone.Sampler; // Sampler has a Map of ToneAudioBuffer, and our method to find inner .onload() does not work since there is no single one.\n\n  if ('loaded' in toneObject) {\n    if (toneObject.loaded) {\n      resolve();\n      return;\n    }\n    if (skipRecursion) {\n      return;\n    }\n    // Try Recursion into inner objects:\n    let handled = false;\n    ['buffer', '_buffer', '_buffers'].forEach(key => {\n      if (key in toneObject) {\n        checkToneObjLoaded(toneObject[key] as ToneLoadable, resolve);\n        handled = true;\n      }\n    });\n    if (handled) {\n      return;\n    }\n  }\n\n  // Check object type if it has load/onload (and _buffers or _buffer), then call resolve()\n  // The list was created for Tone@14.8.0 by grepping and reviewing the source code.\n  // Known objecs to have:\n  const hasOnload =\n    toneObject instanceof Tone.ToneAudioBuffer ||\n    toneObject instanceof Tone.ToneBufferSource ||\n    // Falback for \"future\" objects\n    ('loaded' in toneObject && 'onload' in toneObject);\n\n  if (!hasOnload) {\n    // This is not a good assumption. E.g. it does not work for Tone.ToneAudioBuffers\n    resolve();\n  } else {\n    const oldOnLoad = toneObject.onload;\n    toneObject.onload = () => {\n      if (oldOnLoad && typeof oldOnLoad === 'function') {\n        toneObject.onload = oldOnLoad;\n        oldOnLoad();\n      }\n      resolve();\n    };\n  }\n}\n\n/** Clone a Tone instrument into a different audio context, waiting for it to load. */\nexport function recreateToneObjectInContext(\n  toneObject: ToneInstrument,\n  context: ToneAudioContext\n): Promise<ToneInstrument> {\n  context = context || Tone.getContext();\n\n  return new Promise<ToneInstrument>((resolve, _reject) => {\n    if (toneObject instanceof Tone.PolySynth) {\n      const newObj = new (Tone as unknown as ToneDynamic)[\n        toneObject._dummyVoice.name\n      ]({\n        ...toneObject.get(),\n        context,\n      });\n      checkToneObjLoaded(newObj as ToneLoadable, () => resolve(newObj));\n    } else if (toneObject instanceof Tone.Player) {\n      const newObj = new Tone.Player({\n        url: toneObject._buffer,\n        context,\n        onload: () =>\n          checkToneObjLoaded(newObj as ToneLoadable, () => resolve(newObj)),\n      } as Record<string, unknown>);\n    } else if (toneObject instanceof Tone.Sampler) {\n      const { attack, curve, release, volume } = toneObject.get();\n      const paramsFromSampler = {\n        attack,\n        curve,\n        release,\n        volume,\n      };\n      const paramsFromBuffers = {\n        baseUrl: toneObject._buffers.baseUrl,\n        urls: Object.fromEntries(toneObject._buffers._buffers.entries()),\n      };\n      const newObj = new Tone.Sampler({\n        ...paramsFromSampler,\n        ...paramsFromBuffers,\n        context,\n        onload: () =>\n          checkToneObjLoaded(newObj as unknown as ToneLoadable, () =>\n            resolve(newObj)\n          ),\n      } as Record<string, unknown>);\n    } else {\n      const newObj = new (Tone as unknown as ToneDynamic)[toneObject.name]({\n        ...toneObject.get(),\n        context,\n        onload: () =>\n          checkToneObjLoaded(newObj as ToneLoadable, () => resolve(newObj)),\n      });\n      checkToneObjLoaded(newObj as ToneLoadable, () => resolve(newObj));\n    }\n  });\n}\n\nexport interface InstrumentResult {\n  instrument: ToneInstrument;\n  external?: ExternalOutput;\n}\n\n/**\n * Create an instrument from channel params. The instrument is available\n * synchronously on the returned object; `initPromise` resolves once the\n * instrument is fully loaded, recreated in the correct context, and\n * volume-adjusted.\n */\nexport function createInstrument(\n  context: ToneAudioContext,\n  params: ChannelParams,\n  channelMeta: { idx: number | string; name: string }\n): {\n  instrument: ToneInstrument;\n  external?: ExternalOutput;\n  initPromise: Promise<ToneInstrument>;\n} {\n  let instrument!: ToneInstrument;\n  let external: ExternalOutput | undefined;\n\n  context = context || Tone.getContext();\n\n  const loadPromise = new Promise<void>((resolve, reject) => {\n    /*\n     *  1. The params object can be used to pass a sample (sound source) OR a synth(Synth/FMSynth/AMSynth etc) or samples.\n     *  Scribbletune will then create a Tone.js Player or Tone.js Instrument or Tone.js Sampler respectively\n     *  2. It can also be used to pass a Tone.js Player object or instrument that was created elsewhere\n     *  (mostly by Scribbletune itself in the channel creation method)\n     **/\n\n    if (params.synth) {\n      if (params.instrument) {\n        throw new Error(\n          'Either synth or instrument can be provided, but not both.'\n        );\n      }\n      if ((params.synth as SynthParams).synth) {\n        const synthName = (params.synth as SynthParams).synth;\n        const preset = (params.synth as SynthParams).preset || {};\n        instrument = new (Tone as unknown as ToneDynamic)[synthName]({\n          ...preset,\n          context,\n          // Use onload for cases when synthName calls out Tone.Sample/Player/Sampler.\n          // It could be a universal way to load Tone.js instruments.\n          onload: () => checkToneObjLoaded(instrument, resolve),\n          // This onload is ignored in all synths. Therefore we call checkToneObjLoaded() again below.\n          // It is safe to call resolve() multiple times for Promise<void>\n        });\n        checkToneObjLoaded(instrument, resolve);\n      } else {\n        instrument = params.synth as unknown as ToneInstrument; // TODO: This is dangerous by-reference assignment.\n        console.warn(\n          'The \"synth\" parameter with instrument will be deprecated in the future. Please use the \"instrument\" parameter instead.'\n        );\n        // params.synth describing the Tone[params.synth.synth] is allowed.\n        checkToneObjLoaded(instrument, resolve);\n      }\n    } else if (typeof params.instrument === 'string') {\n      instrument = new (Tone as unknown as ToneDynamic)[\n        params.instrument as string\n      ]({ context });\n      checkToneObjLoaded(instrument, resolve);\n    } else if (params.instrument) {\n      instrument = params.instrument; // TODO: This is dangerous by-reference assignment.\n      checkToneObjLoaded(instrument, resolve);\n    } else if (params.sample || params.buffer) {\n      instrument = new Tone.Player({\n        url: params.sample || params.buffer,\n        context,\n        onload: () => checkToneObjLoaded(instrument, resolve),\n      });\n    } else if (params.samples) {\n      instrument = new Tone.Sampler({\n        urls: params.samples,\n        context,\n        onload: () => checkToneObjLoaded(instrument, resolve),\n      });\n    } else if (params.sampler) {\n      instrument = params.sampler; // TODO: This is dangerous by-reference assignment.\n      checkToneObjLoaded(instrument, resolve);\n    } else if (params.player) {\n      instrument = params.player; // TODO: This is dangerous by-reference assignment.\n      checkToneObjLoaded(instrument, resolve);\n    } else if (params.external) {\n      external = { ...params.external }; // Sanitize object by shallow clone\n      instrument = {\n        context,\n        volume: { value: 0 },\n      } as unknown as ToneInstrument;\n      // Do not call! checkToneObjLoaded(instrument, resolve);\n\n      if (params.external.init) {\n        return params.external\n          .init(context.rawContext)\n          .then(() => {\n            resolve();\n          })\n          .catch((e: unknown) => {\n            reject(\n              new Error(\n                `${errorHasMessage(e) ? e.message : e} loading external output module of channel idx ${\n                  channelMeta.idx\n                }, ${channelMeta.name ?? '(no name)'}`\n              )\n            );\n          });\n      } else {\n        resolve();\n      }\n    } else {\n      throw new Error(\n        'One of required synth|instrument|sample|sampler|samples|buffer|player|external is not provided!'\n      );\n    }\n\n    if (!instrument) {\n      throw new Error('Failed instantiating instrument from given params.');\n    }\n  });\n\n  const initPromise = loadPromise\n    .then(() => {\n      // Recreate instrument in the target context if needed\n      if (!external && instrument?.context !== context) {\n        return recreateToneObjectInContext(instrument, context).then(newObj => {\n          instrument = newObj;\n        });\n      }\n    })\n    .then(() => {\n      // Adjust volume\n      if (params.volume) {\n        instrument.volume.value = params.volume;\n        external?.setVolume?.(params.volume);\n      }\n      return instrument;\n    });\n\n  return { instrument, external, initPromise };\n}\n","import { getDuration, getNote } from '../browser-clip';\nimport type { ClipParams, SeqFn } from '../types';\n\n/** Subset of Channel properties needed by the sequence callback. */\nexport interface SequenceHost {\n  instrument: ToneInstrument;\n  external?: ExternalOutput;\n  hasLoaded: boolean;\n  clipNoteCount: number;\n}\n\n/**\n * Build the callback function for a Tone.Sequence based on the instrument type.\n * Returns a function that triggers notes/samples at each step of the sequence.\n */\nexport function buildSequenceCallback(\n  params: ClipParams,\n  host: SequenceHost,\n  playerCb: (params: Record<string, unknown>) => void,\n  eventCb: (event: string, params: Record<string, unknown>) => void\n): SeqFn {\n  if (host.external) {\n    const ext = host.external;\n    return (time: string, el: string) => {\n      if (el === 'x' || el === 'R') {\n        const counter = host.clipNoteCount;\n        if (host.hasLoaded) {\n          const note = getNote(el, params, counter)[0] as string;\n          const duration = getDuration(params, counter);\n          const durSeconds = Tone.Time(duration).toSeconds();\n          playerCb({ note, duration, time, counter });\n          try {\n            ext.triggerAttackRelease?.(note, durSeconds, time);\n          } catch (e) {\n            eventCb('error', { e }); // Report play errors.\n          }\n        }\n        host.clipNoteCount++;\n      }\n    };\n  }\n\n  if (host.instrument instanceof Tone.Player) {\n    return (time: string, el: string) => {\n      if (el === 'x' || el === 'R') {\n        const counter = host.clipNoteCount;\n        if (host.hasLoaded) {\n          playerCb({ note: '', duration: '', time, counter });\n          try {\n            host.instrument.start(time);\n          } catch (e) {\n            eventCb('error', { e }); // Report play errors.\n          }\n        }\n        host.clipNoteCount++;\n      }\n    };\n  }\n\n  if (\n    host.instrument instanceof Tone.PolySynth ||\n    host.instrument instanceof Tone.Sampler\n  ) {\n    return (time: string, el: string) => {\n      if (el === 'x' || el === 'R') {\n        const counter = host.clipNoteCount;\n        if (host.hasLoaded) {\n          const note = getNote(el, params, counter) as string | string[];\n          const duration = getDuration(params, counter);\n          playerCb({ note, duration, time, counter });\n          try {\n            host.instrument.triggerAttackRelease(note, duration, time);\n          } catch (e) {\n            eventCb('error', { e }); // Report play errors.\n          }\n        }\n        host.clipNoteCount++;\n      }\n    };\n  }\n\n  if (host.instrument instanceof Tone.NoiseSynth) {\n    return (time: string, el: string) => {\n      if (el === 'x' || el === 'R') {\n        const counter = host.clipNoteCount;\n        if (host.hasLoaded) {\n          const duration = getDuration(params, counter);\n          playerCb({ note: '', duration, time, counter });\n          try {\n            (host.instrument as Tone.NoiseSynth).triggerAttackRelease(\n              duration,\n              time\n            );\n          } catch (e) {\n            eventCb('error', { e }); // Report play errors.\n          }\n        }\n        host.clipNoteCount++;\n      }\n    };\n  }\n\n  return (time: string, el: string) => {\n    if (el === 'x' || el === 'R') {\n      const counter = host.clipNoteCount;\n      if (host.hasLoaded) {\n        const note = getNote(el, params, counter)[0] as string;\n        const duration = getDuration(params, counter);\n        playerCb({ note, duration, time, counter });\n        try {\n          host.instrument.triggerAttackRelease(note, duration, time);\n        } catch (e) {\n          eventCb('error', { e }); // Report play errors.\n        }\n      }\n      host.clipNoteCount++;\n    }\n  };\n}\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 type { Channel } from './channel';\nimport { checkToneObjLoaded } from './channel/instrument-factory';\nimport {\n  buildSequenceCallback,\n  type SequenceHost,\n} from './channel/sequence-builder';\nimport { preprocessClipParams } from './clip-utils';\nimport type { ClipParams, PatternElement, SeqFn } from './types';\nimport { expandStr, randomInt } from './utils';\n\nconst defaultSubdiv = '4n';\nconst defaultDur = '8n';\n\n/** Get the note(s) for the current step, cycling through the notes array. */\nexport const getNote = (\n  el: string,\n  params: ClipParams,\n  counter: number\n): string | (string | string[])[] => {\n  if (el === 'R' && params.randomNotes && params.randomNotes.length > 0) {\n    return params.randomNotes[randomInt(params.randomNotes.length - 1)];\n  }\n  if (params.notes) {\n    return params.notes[counter % (params.notes.length || 1)];\n  }\n  return '';\n};\n\n/** Get the duration for the current step, cycling through the durations array. */\nexport const getDuration = (\n  params: ClipParams,\n  counter: number\n): string | number => {\n  return params.durations\n    ? params.durations[counter % params.durations.length]\n    : params.dur || params.subdiv || defaultDur;\n};\n\n/**\n * Walk a nested pattern array and compute a flat list of note durations (in seconds).\n * Underscores (`_`) extend the previous note's duration.\n */\nexport const recursivelyApplyPatternToDurations = (\n  patternArr: PatternElement[],\n  length: number,\n  durations: number[] = []\n): number[] => {\n  patternArr.forEach(char => {\n    if (typeof char === 'string') {\n      if (char === 'x' || char === 'R') {\n        durations.push(length);\n      }\n      if (char === '_' && durations.length) {\n        durations[durations.length - 1] += length;\n      }\n    }\n    if (Array.isArray(char)) {\n      recursivelyApplyPatternToDurations(char, length / char.length, durations);\n    }\n  });\n  return durations;\n};\n\n/**\n * Create a Tone.Sequence from clip parameters for live browser playback.\n * When a Channel is provided, uses its instrument. When omitted, creates a\n * standalone Tone.Player from `params.sample`.\n */\nconst generateSequence = (\n  params: ClipParams,\n  channel?: Channel,\n  context?: ToneAudioContext\n): ToneSequence => {\n  context = context || Tone.getContext();\n\n  if (!params.pattern) {\n    throw new Error('No pattern provided!');\n  }\n\n  if (!params.durations && !params.dur) {\n    params.durations = recursivelyApplyPatternToDurations(\n      expandStr(params.pattern),\n      Tone.Ticks(params.subdiv || defaultSubdiv).toSeconds()\n    );\n  }\n\n  let callback: SeqFn;\n\n  if (channel) {\n    // Channel-based path (existing behavior)\n    callback = channel.getSeqFn(params);\n  } else if (params.sample) {\n    // Standalone sample-based path\n    const player = new Tone.Player({ url: params.sample, context });\n    player.toDestination();\n    player.sync();\n\n    const host: SequenceHost = {\n      instrument: player,\n      hasLoaded: false,\n      clipNoteCount: 0,\n    };\n\n    checkToneObjLoaded(player as ToneLoadable, () => {\n      host.hasLoaded = true;\n    });\n\n    const noop = () => {};\n    callback = buildSequenceCallback(params, host, noop, noop);\n  } else {\n    throw new Error(\n      'Either a Channel or a sample URL must be provided to create a clip.'\n    );\n  }\n\n  return new Tone.Sequence({\n    callback,\n    events: expandStr(params.pattern),\n    subdivision: params.subdiv || defaultSubdiv,\n    context,\n  });\n};\n\n/** Calculate total duration (in seconds) of a pattern at the given subdivision. */\nexport const totalPatternDuration = (\n  pattern: string,\n  subdivOrLength: string | number\n): number => {\n  return typeof subdivOrLength === 'number'\n    ? subdivOrLength * expandStr(pattern).length\n    : Tone.Ticks(subdivOrLength).toSeconds() * expandStr(pattern).length;\n};\n\n/** Compute the least common multiple of two positive integers. */\nconst leastCommonMultiple = (n1: number, n2: number): number => {\n  const [smallest, largest] = n1 < n2 ? [n1, n2] : [n2, n1];\n  let i = largest;\n  while (i % smallest !== 0) {\n    i += largest;\n  }\n  return i;\n};\n\n/**\n * Calculate the minimum duration (in seconds) needed to offline-render a clip\n * so that all notes cycle through completely.\n */\nexport const renderingDuration = (\n  pattern: string,\n  subdivOrLength: string | number,\n  notes: string | (string | string[])[],\n  randomNotes: undefined | null | string | (string | string[])[]\n): number => {\n  const patternRegularNotesCount = pattern.split('').filter(c => {\n    return c === 'x';\n  }).length;\n  const patternRandomNotesCount = pattern.split('').filter(c => {\n    return c === 'R';\n  }).length;\n  const patternNotesCount = randomNotes?.length\n    ? patternRegularNotesCount\n    : patternRegularNotesCount + patternRandomNotesCount;\n  const notesCount = notes.length || 1;\n  return (\n    (totalPatternDuration(pattern, subdivOrLength) / patternNotesCount) *\n    leastCommonMultiple(notesCount, patternNotesCount)\n  );\n};\n\nlet ongoingRenderingCounter = 0;\nlet originalContext: ToneAudioContext | undefined;\n\n/** Render a clip offline into a Tone.Player buffer for later playback. */\nconst offlineRenderClip = (params: ClipParams, duration: number) => {\n  if (!originalContext) {\n    originalContext = Tone.getContext();\n  }\n  ongoingRenderingCounter++;\n  const player = new Tone.Player({ context: originalContext, loop: true });\n  Tone.Offline(async (context: ToneAudioContext): Promise<void> => {\n    const sequence = generateSequence(params, context as unknown as Channel);\n    await Tone.loaded();\n    sequence.start();\n    context.transport.start();\n  }, duration).then((buffer: ToneLoadable) => {\n    player.buffer = buffer;\n    ongoingRenderingCounter--;\n    if (ongoingRenderingCounter === 0) {\n      if (originalContext) {\n        Tone.setContext(originalContext);\n      }\n      params.offlineRenderingCallback?.();\n    }\n  });\n  player.toDestination();\n  player.sync();\n  return player;\n};\n\n/**\n * @param  {Object}\n * @return {Tone.js Sequence Object}\n * Take a object literal that may have a Tone.js player OR instrument\n * or simply a sample or synth with a pattern and return a Tone.js sequence\n */\nexport const clip = (\n  params: ClipParams,\n  channel?: Channel\n): ToneSequence | ToneInstrument => {\n  params = preprocessClipParams(params, { align: '1m', alignOffset: '0' });\n\n  if (params.offlineRendering) {\n    return offlineRenderClip(\n      params,\n      renderingDuration(\n        params.pattern,\n        params.subdiv || defaultSubdiv,\n        params.notes || [],\n        params.randomNotes\n      )\n    );\n  }\n  return generateSequence(params, channel, originalContext);\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","import type { ChannelParams } from '../types';\nimport { recreateToneObjectInContext } from './instrument-factory';\n\n/** Create effects from channel params and chain them onto the instrument. */\nexport function initEffects(\n  instrument: ToneInstrument,\n  context: ToneAudioContext,\n  params: ChannelParams\n): Promise<void> {\n  context = context || Tone.getContext();\n\n  const createEffect = (effect: string | ToneNode): Promise<ToneNode> => {\n    return new Promise<ToneNode>((resolve, _reject) => {\n      if (typeof effect === 'string') {\n        resolve(\n          new (Tone as unknown as ToneDynamic)[effect]({\n            context,\n          }) as unknown as ToneNode\n        );\n      } else if (effect.context !== context) {\n        return recreateToneObjectInContext(\n          effect as unknown as ToneInstrument,\n          context\n        );\n      } else {\n        resolve(effect);\n      }\n    }).then(effectOut => {\n      return effectOut.toDestination();\n    });\n  };\n\n  const startEffect = (eff: ToneNode) => {\n    return typeof eff.start === 'function' ? eff.start() : eff;\n  };\n\n  const toArray = <T>(someVal: T | T[] | undefined): T[] => {\n    if (!someVal) {\n      return [];\n    }\n    if (Array.isArray(someVal)) {\n      return someVal;\n    }\n    return [someVal];\n  };\n\n  const effectsIn = toArray(params.effects);\n  if (params.external) {\n    if (effectsIn.length !== 0) {\n      throw new Error('Effects cannot be used with external output');\n    }\n    return Promise.resolve();\n  }\n\n  return Promise.all(effectsIn.map(createEffect))\n    .then(results => results.map(startEffect))\n    .then(effects => {\n      instrument.chain(...effects).toDestination();\n    });\n}\n","import { clip } from './browser-clip';\nimport { initEffects } from './channel/effects-chain';\nimport { createInstrument } from './channel/instrument-factory';\nimport { buildSequenceCallback } from './channel/sequence-builder';\nimport type {\n  ChannelParams,\n  ClipParams,\n  EventFn,\n  PlayerObserverFn,\n  SeqFn,\n} from './types';\nimport { errorHasMessage } from './utils';\n\n/**\n * Get the next logical position to play in the session\n * Tone has a build-in method `Tone.Transport.nextSubdivision('4n')`\n * but I think it s better to round off as follows for live performance\n */\nconst getNextPos = (\n  clip: null | { align?: string; alignOffset?: string }\n): number | ToneTicksValue => {\n  const transportPosTicks = Tone.Transport.ticks;\n  // If we are still in the first beat (bar 0, beat 0), start immediately\n  if (transportPosTicks < Tone.Ticks('4n').toTicks()) {\n    return 0;\n  }\n\n  // Else set it to the next aligned position\n  const align = clip?.align || '1m';\n  const alignOffset = clip?.alignOffset || '0';\n  const alignTicks: number = Tone.Ticks(align).toTicks();\n  const alignOffsetTicks: number = Tone.Ticks(alignOffset).toTicks();\n  const nextPosTicks = Tone.Ticks(\n    Math.floor(transportPosTicks / alignTicks + 1) * alignTicks +\n      alignOffsetTicks\n  );\n  return nextPosTicks;\n};\n\n/**\n * Channel\n * A channel is made up of a Tone.js Player/Instrument, one or more\n * Tone.js sequences (known as clips in Scribbletune)\n * & optionally a set of effects (with or without presets)\n *\n * API:\n * clips -> Get all clips for this channel\n * addClip -> Add a new clip to the channel\n * startClip -> Start a clip at the provided index\n * stopClip -> Stop a clip at the provided index\n * activeClipIdx -> Get the clip that is currently playing\n */\nexport class Channel {\n  idx: number | string;\n  name: string;\n  activePatternIdx: number;\n  channelClips: (ToneSequence | null)[];\n  clipNoteCount: number;\n  counterResetTask: number | undefined;\n  instrument!: ToneInstrument;\n  external: ExternalOutput | undefined;\n  initializerTask: Promise<void>;\n  hasLoaded: boolean;\n  hasFailed: boolean | Error;\n  private eventCbFn: EventFn | undefined;\n  private playerCbFn: PlayerObserverFn | undefined;\n  constructor(params: ChannelParams) {\n    this.idx = params.idx || 0;\n    this.name = params.name || `ch ${params.idx}`;\n    this.activePatternIdx = -1;\n    this.channelClips = [];\n    this.clipNoteCount = 0;\n\n    // Filter out unrequired params and create clip params object\n\n    const { clips, samples, sample, synth, ...params1 } = params;\n\n    const { external, sampler, buffer, ...params2 } = params1;\n\n    const { player, instrument, volume, ...params3 } = params2;\n\n    const { eventCb, playerCb, effects, ...params4 } = params3;\n    const { context = Tone.getContext(), ...originalParamsFiltered } = params4;\n\n    this.eventCbFn = eventCb;\n    this.playerCbFn = playerCb;\n\n    // Async section\n    this.hasLoaded = false;\n    this.hasFailed = false;\n    const result = createInstrument(context, params, {\n      idx: this.idx,\n      name: this.name,\n    });\n    this.instrument = result.instrument;\n    this.external = result.external;\n    this.initializerTask = result.initPromise.then(finalInstrument => {\n      this.instrument = finalInstrument;\n      return initEffects(this.instrument, context, params);\n    });\n    // End Async section\n\n    // Sync section\n    let clipsFailed: { message: string } | false = false;\n    try {\n      (params.clips ?? []).forEach((c: ClipParams, i: number) => {\n        try {\n          this.addClip({\n            ...c,\n            ...originalParamsFiltered,\n          });\n        } catch (e) {\n          // Annotate the error with Clip info\n          throw new Error(\n            `${errorHasMessage(e) ? e.message : e} in clip ${i + 1}`\n          );\n        }\n      }, this);\n    } catch (e) {\n      clipsFailed = e as { message: string }; // Stash the error\n    }\n    // End Sync section\n\n    // Reconcile sync section with async section\n    this.initializerTask\n      .then(() => {\n        if (clipsFailed) {\n          throw clipsFailed;\n        }\n        this.hasLoaded = true;\n        this.eventCb('loaded', {}); // Report async load completion.\n      })\n      .catch(e => {\n        this.hasFailed = e;\n        this.eventCb('error', { e }); // Report async errors.\n      });\n  }\n\n  /** Set the global transport tempo in BPM. */\n  static setTransportTempo(valueBpm: number): void {\n    Tone.Transport.bpm.value = valueBpm;\n  }\n\n  /** Resume the audio context and start the global transport. */\n  static startTransport(): void {\n    Tone.start();\n    Tone.Transport.start();\n  }\n\n  /**\n   * Stop the global transport.\n   * @param deleteEvents - If true (default), cancels all scheduled transport events.\n   */\n  static stopTransport(deleteEvents = true): void {\n    Tone.Transport.stop();\n    if (deleteEvents) {\n      // Delete all events in the Tone.Transport\n      Tone.Transport.cancel();\n    }\n  }\n\n  /** Set the volume (in dB) of this channel's instrument and external output. */\n  setVolume(volume: number): void {\n    if (this.instrument) {\n      this.instrument.volume.value = volume;\n    }\n\n    if (this.external) {\n      this.external.setVolume?.(volume);\n    }\n  }\n\n  /**\n   * Start the clip at the given index, stopping any other active clip first.\n   * @param idx - Clip index in this channel\n   * @param position - Transport time to start at; defaults to the next aligned position\n   */\n  startClip(idx: number, position?: number | string | ToneTicksValue): void {\n    const clip = this.channelClips[idx];\n    position = position || (position === 0 ? 0 : getNextPos(clip));\n    // Stop any other currently running clip\n    if (this.activePatternIdx > -1 && this.activePatternIdx !== idx) {\n      this.stopClip(this.activePatternIdx, position);\n    }\n\n    if (clip && clip.state !== 'started') {\n      // We need to schedule that for just before when clip?.start(position) events start coming.\n      this.counterResetTask = Tone.Transport.scheduleOnce(\n        (/* time: Tone.Seconds */) => {\n          this.clipNoteCount = 0;\n        },\n        position\n      );\n\n      this.activePatternIdx = idx;\n      clip?.start(position);\n    }\n  }\n\n  /**\n   * Stop the clip at the given index.\n   * @param idx - Clip index in this channel\n   * @param position - Transport time to stop at; defaults to the next aligned position\n   */\n  stopClip(idx: number, position?: number | string | ToneTicksValue): void {\n    const clip = this.channelClips[idx];\n    position = position || (position === 0 ? 0 : getNextPos(clip));\n    clip?.stop(position);\n    if (idx === this.activePatternIdx) {\n      this.activePatternIdx = -1;\n    }\n  }\n\n  /**\n   * Add a clip to this channel. If the clip has a pattern, a Tone.Sequence is\n   * created; otherwise an empty (null) slot is reserved.\n   * @param clipParams - Clip configuration\n   * @param idx - Slot index; defaults to the next available position\n   */\n  addClip(clipParams: ClipParams, idx?: number): void {\n    idx = idx || this.channelClips.length;\n    if (clipParams.pattern) {\n      this.channelClips[idx as number] = clip(\n        {\n          ...clipParams,\n        },\n        this\n      ) as ToneSequence;\n      // Pass certain clipParams into getNextPos()\n      const seq = this.channelClips[idx as number];\n      if (seq && clipParams.align) seq.align = clipParams.align;\n      if (seq && clipParams.alignOffset)\n        seq.alignOffset = clipParams.alignOffset;\n    } else {\n      // Allow creation of empty clips\n      this.channelClips[idx as number] = null;\n    }\n  }\n\n  /**\n   * @param  {Object} ClipParams clip parameters\n   * @return {Function} function that can be used as the callback in Tone.Sequence https://tonejs.github.io/docs/Sequence\n   */\n  getSeqFn(params: ClipParams): SeqFn {\n    return buildSequenceCallback(\n      params,\n      this,\n      p => this.playerCb(p),\n      (e, p) => this.eventCb(e, p)\n    );\n  }\n\n  /** Invoke the user-provided event callback, if set. */\n  private eventCb(event: string, params: Record<string, unknown>): void {\n    if (typeof this.eventCbFn === 'function') {\n      params.channel = this;\n      this.eventCbFn(event, params);\n    }\n  }\n\n  /** Invoke the user-provided player observer callback, if set. */\n  private playerCb(params: Record<string, unknown>): void {\n    if (typeof this.playerCbFn === 'function') {\n      params.channel = this;\n      this.playerCbFn(params);\n    }\n  }\n\n  /** All clips (sequences) belonging to this channel. */\n  get clips(): (ToneSequence | null)[] {\n    return this.channelClips;\n  }\n\n  /** Index of the currently playing clip, or -1 if none. */\n  get activeClipIdx(): number {\n    return this.activePatternIdx;\n  }\n}\n","import { Channel } from './channel';\nimport type { ChannelParams, ChannelPattern, PlayParams } from './types';\n\n/**\n * A Session manages multiple Channels and coordinates clip playback\n * across them, similar to a scene/row in a DAW.\n */\nexport class Session {\n  sessionChannels: Channel[];\n\n  /** Create a session, optionally pre-populated with channels. */\n  constructor(arr: ChannelParams[]) {\n    arr = arr || [];\n    this.sessionChannels = arr.map((ch: ChannelParams, i: number) => {\n      // Make sure ch.idx is not empty and unique in this.sessionChannels\n      ch.idx = ch.idx || i;\n      ch.idx = this.uniqueIdx(this.sessionChannels, ch.idx);\n      return new Channel(ch);\n    });\n  }\n\n  /** Return a unique channel index, generating a new one if `idx` is taken or missing. */\n  uniqueIdx(channels: Channel[], idx?: string | number): string | number {\n    if (!channels) {\n      return idx || 0;\n    }\n    // Channel idx's\n    const idxs = channels.reduce((acc: (string | number)[], c) => {\n      return (!acc.find(i => i === c.idx) && acc.concat(c.idx)) || acc;\n    }, []);\n\n    if (!idx || idxs.find(i => i === idx)) {\n      let newIdx = channels.length;\n      while (idxs.find(i => i === newIdx)) {\n        newIdx = newIdx + 1;\n      }\n      return newIdx;\n    }\n\n    return idx;\n  }\n\n  /** Create a new channel with a unique index and add it to the session. */\n  createChannel(ch: ChannelParams): Channel {\n    // Make sure ch.idx is unique in this.sessionChannels\n    ch.idx = this.uniqueIdx(this.sessionChannels, ch.idx);\n    const newChannel = new Channel(ch);\n    this.sessionChannels.push(newChannel);\n    return newChannel;\n  }\n\n  /** All channels in this session. */\n  get channels(): Channel[] {\n    return this.sessionChannels;\n  }\n\n  /** Set the global transport tempo in BPM. */\n  setTransportTempo(valueBpm: number): void {\n    Channel.setTransportTempo(valueBpm);\n  }\n\n  /** Resume the audio context and start the global transport. */\n  startTransport(): void {\n    Channel.startTransport();\n  }\n\n  /**\n   * Stop the global transport.\n   * @param deleteEvents - If true (default), cancels all scheduled transport events.\n   */\n  stopTransport(deleteEvents = true): void {\n    Channel.stopTransport(deleteEvents);\n  }\n\n  /** Start the clip at the given index across all channels simultaneously. */\n  startRow(idx: number): void {\n    this.sessionChannels.forEach((ch: Channel) => {\n      ch.startClip(idx);\n    });\n  }\n\n  /**\n   * Schedule clip playback across channels using a song-structure pattern.\n   * Each channel pattern is a string where each character is a clip index\n   * (or `-` for silence, `_` to sustain the previous clip).\n   */\n  play(params: PlayParams): void {\n    const channelPatterns = params.channelPatterns;\n    const clipDuration = params.clipDuration || '4:0:0';\n    const clipDurationInSeconds: number = Tone.Time(clipDuration).toSeconds();\n\n    const stopClips = (clips: ToneSequence[], time: number) => {\n      clips.forEach(c => {\n        c.stop(time);\n      });\n    };\n\n    const startClips = (\n      channelIdx: string | number,\n      clipIdx: string,\n      time: number\n    ): ToneSequence[] => {\n      if (clipIdx === '-') return [];\n      const clips = this.channels\n        .filter(c => c.idx === channelIdx)\n        .map(c => c.clips[Number(clipIdx)])\n        .filter((c): c is ToneSequence => c != null);\n      for (const c of clips) c.start(time);\n      return clips;\n    };\n\n    channelPatterns.forEach(({ channelIdx, pattern }: ChannelPattern) => {\n      let clips: ToneSequence[] = [];\n      let time = 0;\n      let prevClipIdx = '-';\n      pattern.split('').forEach((clipIdx: string) => {\n        if (clipIdx !== prevClipIdx && clipIdx !== '_') {\n          stopClips(clips, time);\n          clips = startClips(channelIdx, clipIdx, time);\n        }\n        prevClipIdx = clipIdx;\n        time += clipDurationInSeconds;\n      });\n      stopClips(clips, time);\n    });\n  }\n}\n"],"mappings":"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","names":["import_harmonics","import_harmonics","fs","import_harmonics","chords","clip"]}