{"version":3,"sources":["../index.ts"],"sourcesContent":["import { all, ChordType } from \"@tonaljs/chord-type\";\nimport { modes } from \"@tonaljs/pcset\";\nimport { note } from \"@tonaljs/pitch-note\";\n\ninterface FoundChord {\n  readonly weight: number;\n  readonly name: string;\n}\n\nconst namedSet = (notes: string[]) => {\n  const pcToName = notes.reduce<Record<number, string>>((record, n) => {\n    const chroma = note(n).chroma;\n    if (chroma !== undefined) {\n      record[chroma] = record[chroma] || note(n).name;\n    }\n    return record;\n  }, {});\n\n  return (chroma: number) => pcToName[chroma];\n};\n\ntype DetectOptions = {\n  assumePerfectFifth: boolean;\n};\nexport function detect(\n  source: string[],\n  options: Partial<DetectOptions> = {},\n): string[] {\n  const notes = source.map((n) => note(n).pc).filter((x) => x);\n  if (note.length === 0) {\n    return [];\n  }\n\n  const found: FoundChord[] = findMatches(notes, 1, options);\n\n  return found\n    .filter((chord) => chord.weight)\n    .sort((a, b) => b.weight - a.weight)\n    .map((chord) => chord.name);\n}\n\n/* tslint:disable:no-bitwise */\nconst BITMASK = {\n  // 3m 000100000000\n  // 3M 000010000000\n  anyThirds: 384,\n  // 5P 000000010000\n  perfectFifth: 16,\n  // 5d 000000100000\n  // 5A 000000001000\n  nonPerfectFifths: 40,\n  anySeventh: 3,\n};\n\nconst testChromaNumber = (bitmask: number) => (chromaNumber: number) =>\n  Boolean(chromaNumber & bitmask);\nconst hasAnyThird = testChromaNumber(BITMASK.anyThirds);\nconst hasPerfectFifth = testChromaNumber(BITMASK.perfectFifth);\nconst hasAnySeventh = testChromaNumber(BITMASK.anySeventh);\nconst hasNonPerfectFifth = testChromaNumber(BITMASK.nonPerfectFifths);\n\nfunction hasAnyThirdAndPerfectFifthAndAnySeventh(chordType: ChordType) {\n  const chromaNumber = parseInt(chordType.chroma, 2);\n  return (\n    hasAnyThird(chromaNumber) &&\n    hasPerfectFifth(chromaNumber) &&\n    hasAnySeventh(chromaNumber)\n  );\n}\n\nfunction withPerfectFifth(chroma: string): string {\n  const chromaNumber = parseInt(chroma, 2);\n  return hasNonPerfectFifth(chromaNumber)\n    ? chroma\n    : (chromaNumber | 16).toString(2);\n}\n\n/* tslint:enable:no-bitwise */\n\ntype FindMatchesOptions = {\n  assumePerfectFifth: boolean;\n};\nfunction findMatches(\n  notes: string[],\n  weight: number,\n  options: Partial<FindMatchesOptions>,\n): FoundChord[] {\n  const tonic = notes[0];\n  const tonicChroma = note(tonic).chroma;\n  const noteName = namedSet(notes);\n  // we need to test all chromas to get the correct baseNote\n  const allModes = modes(notes, false);\n\n  const found: FoundChord[] = [];\n  allModes.forEach((mode, index) => {\n    const modeWithPerfectFifth =\n      options.assumePerfectFifth && withPerfectFifth(mode);\n    // some chords could have the same chroma but different interval spelling\n    const chordTypes = all().filter((chordType) => {\n      if (\n        options.assumePerfectFifth &&\n        hasAnyThirdAndPerfectFifthAndAnySeventh(chordType)\n      ) {\n        return chordType.chroma === modeWithPerfectFifth;\n      }\n      return chordType.chroma === mode;\n    });\n\n    chordTypes.forEach((chordType) => {\n      const chordName = chordType.aliases[0];\n      const baseNote = noteName(index);\n      const isInversion = index !== tonicChroma;\n      if (isInversion) {\n        found.push({\n          weight: 0.5 * weight,\n          name: `${baseNote}${chordName}/${tonic}`,\n        });\n      } else {\n        found.push({ weight: 1 * weight, name: `${baseNote}${chordName}` });\n      }\n    });\n  });\n\n  return found;\n}\n\n/** @deprecated */\nexport default { detect };\n"],"mappings":";AAAA,SAAS,WAAsB;AAC/B,SAAS,aAAa;AACtB,SAAS,YAAY;AAOrB,IAAM,WAAW,CAAC,UAAoB;AACpC,QAAM,WAAW,MAAM,OAA+B,CAAC,QAAQ,MAAM;AACnE,UAAM,SAAS,KAAK,CAAC,EAAE;AACvB,QAAI,WAAW,QAAW;AACxB,aAAO,MAAM,IAAI,OAAO,MAAM,KAAK,KAAK,CAAC,EAAE;AAAA,IAC7C;AACA,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AAEL,SAAO,CAAC,WAAmB,SAAS,MAAM;AAC5C;AAKO,SAAS,OACd,QACA,UAAkC,CAAC,GACzB;AACV,QAAM,QAAQ,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC;AAC3D,MAAI,KAAK,WAAW,GAAG;AACrB,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,QAAsB,YAAY,OAAO,GAAG,OAAO;AAEzD,SAAO,MACJ,OAAO,CAAC,UAAU,MAAM,MAAM,EAC9B,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM,EAClC,IAAI,CAAC,UAAU,MAAM,IAAI;AAC9B;AAGA,IAAM,UAAU;AAAA;AAAA;AAAA,EAGd,WAAW;AAAA;AAAA,EAEX,cAAc;AAAA;AAAA;AAAA,EAGd,kBAAkB;AAAA,EAClB,YAAY;AACd;AAEA,IAAM,mBAAmB,CAAC,YAAoB,CAAC,iBAC7C,QAAQ,eAAe,OAAO;AAChC,IAAM,cAAc,iBAAiB,QAAQ,SAAS;AACtD,IAAM,kBAAkB,iBAAiB,QAAQ,YAAY;AAC7D,IAAM,gBAAgB,iBAAiB,QAAQ,UAAU;AACzD,IAAM,qBAAqB,iBAAiB,QAAQ,gBAAgB;AAEpE,SAAS,wCAAwC,WAAsB;AACrE,QAAM,eAAe,SAAS,UAAU,QAAQ,CAAC;AACjD,SACE,YAAY,YAAY,KACxB,gBAAgB,YAAY,KAC5B,cAAc,YAAY;AAE9B;AAEA,SAAS,iBAAiB,QAAwB;AAChD,QAAM,eAAe,SAAS,QAAQ,CAAC;AACvC,SAAO,mBAAmB,YAAY,IAClC,UACC,eAAe,IAAI,SAAS,CAAC;AACpC;AAOA,SAAS,YACP,OACA,QACA,SACc;AACd,QAAM,QAAQ,MAAM,CAAC;AACrB,QAAM,cAAc,KAAK,KAAK,EAAE;AAChC,QAAM,WAAW,SAAS,KAAK;AAE/B,QAAM,WAAW,MAAM,OAAO,KAAK;AAEnC,QAAM,QAAsB,CAAC;AAC7B,WAAS,QAAQ,CAAC,MAAM,UAAU;AAChC,UAAM,uBACJ,QAAQ,sBAAsB,iBAAiB,IAAI;AAErD,UAAM,aAAa,IAAI,EAAE,OAAO,CAAC,cAAc;AAC7C,UACE,QAAQ,sBACR,wCAAwC,SAAS,GACjD;AACA,eAAO,UAAU,WAAW;AAAA,MAC9B;AACA,aAAO,UAAU,WAAW;AAAA,IAC9B,CAAC;AAED,eAAW,QAAQ,CAAC,cAAc;AAChC,YAAM,YAAY,UAAU,QAAQ,CAAC;AACrC,YAAM,WAAW,SAAS,KAAK;AAC/B,YAAM,cAAc,UAAU;AAC9B,UAAI,aAAa;AACf,cAAM,KAAK;AAAA,UACT,QAAQ,MAAM;AAAA,UACd,MAAM,GAAG,QAAQ,GAAG,SAAS,IAAI,KAAK;AAAA,QACxC,CAAC;AAAA,MACH,OAAO;AACL,cAAM,KAAK,EAAE,QAAQ,IAAI,QAAQ,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,CAAC;AAAA,MACpE;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAED,SAAO;AACT;AAGA,IAAO,uBAAQ,EAAE,OAAO;","names":[]}