pepperscore 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/LICENSE +26 -12
  3. package/README.md +127 -9
  4. package/dist/THIRD_PARTY_NOTICES.txt +1222 -0
  5. package/dist/assets/{import.worker-D0XfuAHu.js → import.worker-Rop-z7az.js} +2 -2
  6. package/dist/assets/verovio.worker-DQm-ikdG.js +7 -0
  7. package/dist/audio.d.ts +24 -0
  8. package/dist/audio.js +198 -0
  9. package/dist/audio.js.map +1 -0
  10. package/dist/components/InstrumentChooser.d.ts +17 -0
  11. package/dist/components/OctaveTool.d.ts +21 -0
  12. package/dist/components/PepperScore.d.ts +96 -1
  13. package/dist/index.d.ts +3 -2
  14. package/dist/index.js +3738 -3382
  15. package/dist/index.js.map +1 -1
  16. package/dist/instruments.d.ts +2 -0
  17. package/dist/instruments.js +2 -0
  18. package/dist/lib/chrome.d.ts +10 -2
  19. package/dist/lib/file-state.d.ts +45 -5
  20. package/dist/lib/header-controls.d.ts +7 -3
  21. package/dist/lib/hit-test.d.ts +18 -0
  22. package/dist/lib/instrument-model.d.ts +80 -0
  23. package/dist/lib/instrument-switch-state.d.ts +169 -0
  24. package/dist/lib/instrument-view.d.ts +92 -0
  25. package/dist/lib/instruments.d.ts +82 -0
  26. package/dist/lib/metronome.d.ts +33 -0
  27. package/dist/lib/notation/document.d.ts +11 -1
  28. package/dist/lib/notation/mei-spelling.d.ts +9 -1
  29. package/dist/lib/notation/mei-tab.d.ts +58 -0
  30. package/dist/lib/notation/mei-view.d.ts +8 -0
  31. package/dist/lib/playback/timeline.d.ts +4 -1
  32. package/dist/lib/prefs.d.ts +67 -0
  33. package/dist/lib/range-fit-core.d.ts +26 -0
  34. package/dist/lib/render.d.ts +36 -1
  35. package/dist/lib/score.d.ts +23 -1
  36. package/dist/lib/sound-players.d.ts +9 -1
  37. package/dist/lib/tab/fret-assign.d.ts +53 -0
  38. package/dist/lib/tab/tab-parts.d.ts +64 -0
  39. package/dist/lib/transpose.d.ts +3 -2
  40. package/dist/lib/verovio-protocol.d.ts +15 -0
  41. package/dist/lib/verovio-runtime.d.ts +9 -1
  42. package/dist/range-fit-core-B1rMWdI4.js +468 -0
  43. package/dist/range-fit-core-B1rMWdI4.js.map +1 -0
  44. package/dist/runtime-files.d.ts +15 -0
  45. package/dist/{sf2-player-CRlOJDhD.js → sf2-player-oWC6yrUH.js} +28 -6
  46. package/dist/sf2-player-oWC6yrUH.js.map +1 -0
  47. package/dist/sound-players-DdLBBZaR.js +1172 -0
  48. package/dist/sound-players-DdLBBZaR.js.map +1 -0
  49. package/dist/style.css +1 -1
  50. package/dist/verovio/LICENSE +858 -0
  51. package/dist/verovio/verovio-module.mjs +0 -0
  52. package/dist/verovio/verovio.mjs +397 -0
  53. package/package.json +14 -2
  54. package/dist/assets/verovio.worker-DkHQmOsT.js +0 -19034
  55. package/dist/sf2-player-CRlOJDhD.js.map +0 -1
@@ -0,0 +1,7 @@
1
+ const e=/<(?:!--[\s\S]*?--|\?[\s\S]*?\?|!\[CDATA\[[\s\S]*?\]\]|!DOCTYPE[^>]*|(\/?)([A-Za-z_][\w.:-]*)((?:\s+[^\s=/>]+(?:\s*=\s*(?:"[^"]*"|'[^']*'))?)*)\s*(\/?))>/g,t=/* @__PURE__ */ new Map;function n(e){let n=t.get(e);return n||(n=RegExp(`\\s${e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}\\s*=\\s*(?:"([^"]*)"|'([^']*)')`),t.set(e,n)),n}function r(e,t){if(!e.includes(t))return null;let r=n(t).exec(e);return r?r[1]??r[2]??``:null}function i(e,t){return e.replace(n(t),``)}function a(e,t,r){return e.replace(n(t),` ${t}="${r}"`)}const o=e=>e.slice(e.indexOf(`:`)+1),s=e=>r(e,`xml:id`)||``,c=e=>(e||``).split(/\s+/).filter(Boolean),l=e=>e.replace(/^#/,``);function u(t,n){e.lastIndex=0;for(let r=e.exec(t);r;r=e.exec(t))if(r[2]&&n({closing:r[1]===`/`,name:o(r[2]),attributes:r[3]||``,selfClosing:r[4]===`/`,index:r.index,length:r[0].length}))return}function d(e){let t=[],n=[],i=[],a=[],o=[],c=-1,l=!1,d=!1,f=0,p=/* @__PURE__ */ new Set,m=0;return u(e,({closing:e,name:u,attributes:h,selfClosing:g})=>{if(e){a.pop(),u===`staff`&&d?(d=!1,f&&(m=Math.max(m,Math.ceil(f/p.size)))):c>=0&&(u===`staffGrp`&&o.pop(),u===`scoreDef`&&a.length===c&&(c=-1,l=!0));return}if(u===`measure`)t.push(s(h));else if(u===`staff`&&!g)d=!0,f=0,p=/* @__PURE__ */ new Set;else if(u===`verse`&&d)f++,p.add(r(h,`n`)||`1`);else if(u===`scoreDef`&&!l&&c<0)g?l=!0:c=a.length;else if(c>=0){if(u===`staffGrp`)i.push({id:s(h),staves:[]}),g||o.push(i.length-1);else if(u===`staffDef`){let e={n:r(h,`n`)||``,id:s(h)};n.push(e),a.at(-1)===`staffGrp`&&o.length&&i[o.at(-1)].staves.push(e)}}g||a.push(u)}),{measureIds:t,lyricDensity:m,staffDefs:n,groups:i}}const f=/* @__PURE__ */ new Set([`meiHead`,`label`,`labelAbbr`,`sb`,`pb`,`pgHead`,`pgFoot`]);function p(e,t){let n=/* @__PURE__ */ new Set,i=[],a=[],o=0;return u(e,({closing:e,name:l,attributes:u,selfClosing:d})=>{if(e){o?o--:l===`staffGrp`&&a.pop();return}let f=l===`staffGrp`?i.push(0)-1:-1;if(o){let e=s(u);e&&n.add(e),d||o++;return}let p=(l===`staffDef`||l===`staff`)&&t.has(r(u,`n`)||``);if(!p){let e=c(r(u,`staff`));p=e.length>0&&e.every(e=>t.has(e))}if(p){let e=s(u);e&&n.add(e),d||(o=1);return}if(l===`staffDef`)for(let e of a)i[e]++;f>=0&&!d&&a.push(f)}),{removed:n,emptyGroups:new Set(i.flatMap((e,t)=>e?[]:[t]))}}function m(e,t,n=1/0,o=0){let d=new Set(t.hiddenStaves),{removed:m,emptyGroups:h}=d.size?p(e,d):{removed:/* @__PURE__ */ new Set,emptyGroups:/* @__PURE__ */ new Set},g=e=>m.size>0&&c(e).some(e=>m.has(l(e))),_=[],v=[],y=0,b=0,x=0,S=0,C=0,w=-1,T=-1,E=()=>++C>=n,D=t.chordSymbols&&t.harmSize&&t.harmSize!==100?Math.round(t.harmSize):0,O=0;if(u(e,({closing:n,name:u,attributes:p,selfClosing:C,index:k,length:A})=>{b||_.push(e.slice(y,k)),y=k+A;let j=e.slice(k,k+A);if(n){if(b){b--;return}return u===`harm`&&O&&v.at(-1)===`rend`&&(v.pop(),O--,_.push(`</rend>`)),v.pop(),T=-1,_.push(j),u===`measure`&&E()?(w=y,!0):void 0}let M=u===`staffGrp`?x++:-1;if(b){if(d.size){let e=s(p);e&&m.add(e)}C||b++;return}let N=f.has(u)||u===`harm`&&!t.chordSymbols,P=j;if(!N&&d.size){let e=c(r(p,`staff`)),t=e.filter(e=>!d.has(e));N=(u===`staffDef`||u===`staff`)&&d.has(r(p,`n`)||``)||M>=0&&h.has(M)||e.length>0&&!t.length||g(r(p,`startid`))||g(r(p,`endid`)),!N&&t.length!==e.length&&(P=a(P,`staff`,t.join(` `)));let n=r(p,`plist`);if(!N&&n&&g(n)){let e=c(n).filter(e=>!m.has(l(e)));e.length?P=a(P,`plist`,e.join(` `)):N=!0}}if(N){if(d.size){let e=s(p);e&&m.add(e)}C||(b=1);return}if((u===`staffDef`||u===`staffGrp`)&&(P=i(i(P,`label`),`label.abbr`)),u===`measure`&&(t.breakEvery>0&&S>0&&(S+o)%t.breakEvery===0&&(T>=0?_.splice(T,0,`<pb/>`):_.push(`<pb/>`)),S++),(u===`ending`||u===`section`)&&!C?T<0&&(T=_.length):T=-1,_.push(P),!C)v.push(/^<([^\s/>]+)/.exec(j)[1]);else if(u===`measure`&&E())return w=y,!0;if(D&&u===`harm`&&!C){let t=e.indexOf(`</harm>`,y);(t>=0?e.slice(y,t).includes(`<fb`):e.includes(`<fb`,y))||(_.push(`<rend fontsize="${D}%">`),v.push(`rend`),O++)}}),w<0)return _.push(e.slice(y)),_.join(``);for(let e=v.length-1;e>=0;e--)_.push(`</${v[e]}>`);return _.join(``)}const h=[`C`,`D`,`E`,`F`,`G`,`A`,`B`],g={C:0,D:2,E:4,F:5,G:7,A:9,B:11},_=[`Cb`,`Gb`,`Db`,`Ab`,`Eb`,`Bb`,`F`,`C`,`G`,`D`,`A`,`E`,`B`,`F#`,`C#`],v=[`Ab`,`Eb`,`Bb`,`F`,`C`,`G`,`D`,`A`,`E`,`B`,`F#`,`C#`,`G#`,`D#`,`A#`],y=[0,-5,2,-3,4,-1,6,1,-4,3,-2,5],b=[0,7,2,-3,4,-1,6,1,-4,3,-2,5],x=(e,t)=>(e%t+t)%t,S=e=>e>0?`#`.repeat(e):`b`.repeat(-e);function C(e){let t=0;for(let n of e)t+=n===`#`||n===`♯`?1:n===`x`||n===`𝄪`?2:n===`𝄫`?-2:-1;return t}function w(e,t){let n=(t>0?`FCGDAEB`:`BEADGCF`).indexOf(e),r=n<Math.abs(t)?Math.floor((Math.abs(t)-1-n)/7)+1:0;return t>0?r:-r}function T(e,t=`major`){let n=(t===`minor`?v:_)[e+7];if(!n)throw Error(`No key with ${e} fifths`);return{tonic:n,mode:t,fifths:e,scale:h.map(t=>({step:t,alter:w(t,e)}))}}function E(e){let t=e.fifths>0?e.fifths-12:e.fifths<0?e.fifths+12:null;return t===null||Math.abs(t)>7?null:T(t,e.mode)}function D(e,t=`major`,n={}){let r=x(e+(t===`minor`?3:0),12),i=T((n.family===`sharp`?b:y)[r],t);return n.flip?E(i)??i:i}function O(e,t){return{...t,octave:Math.round((e-g[t.step]-t.alter)/12)-1}}const k=(e,t)=>x(g[t.step]+t.alter,12)===x(e,12),A=e=>h.indexOf(e);function j(e,t){let n=x(A(t.step)-A(e),7);return n===1?1:n===6?-1:0}function M(e,t,n={}){let r=x(e,12),i=n.source&&k(r,n.source)?n.source:void 0;if(i&&Math.abs(i.alter)===2&&!n.transposed)return O(e,i);let a=t.scale.find(e=>k(r,e));if(a)return O(e,a);let o=e=>Math.abs(e.alter)<=1&&![`E1`,`B1`,`F-1`,`C-1`].includes(e.step+e.alter);if(t.mode===`minor`){let n=A(t.tonic.charAt(0));for(let i of[5,6]){let a=t.scale[(n+i)%7],o={step:a.step,alter:a.alter+1};if(k(r,o)&&Math.abs(o.alter)<=1)return O(e,o)}}if(i&&o(i)&&n.next!==void 0&&n.next-e>=1&&n.next-e<=2)return O(e,i);let s=Object.entries(g).find(([,e])=>e===r)?.[0];if(s){let r={step:h[(A(s)+1)%7],alter:-1};if((s===`E`||s===`B`)&&t.fifths<=-6&&n.prev!==void 0&&n.next!==void 0){let i=M(n.prev,t),a=M(n.next,t),o=[j(r.step,i),j(r.step,a)];if(o.includes(1)&&o.includes(-1))return O(e,r)}return O(e,{step:s,alter:0})}let c={step:h.find(e=>g[e]===r-1),alter:1},l={step:h.find(e=>g[e]===r+1),alter:-1};return t.fifths>0?O(e,c):t.fifths<0?O(e,l):O(e,r===6?c:l)}function N(e,t){let n=/^([A-G])([#♯b♭x𝄪𝄫]*)(.*)$/s.exec(e);if(!n)return e;let r=/[♯♭]/.test(e),i=(e,n)=>{let i=M(60+g[e]+C(n),t),a=S(i.alter);return i.step+(r?a.replace(/#/g,`♯`).replace(/b/g,`♭`):a)},a=n[3].replace(/\/([A-G])([#♯b♭x𝄪𝄫]*)/g,(e,t,n)=>`/${i(t,n)}`);return i(n[1],n[2])+a}new TextEncoder,new TextDecoder;const P=e=>{if(!e.startsWith(`n_`))return null;let t=e.replace(/(?:_c\d+)?(?:_s\d+)?$/,``);return t===e?null:t},F=[`C`,`D`,`E`,`F`,`G`,`A`,`B`],I=[0,2,4,5,7,9,11],L=(e,t)=>(e%t+t)%t;function ee(e){let t=/^([+-]?)(dd|d|m|M|P|A|AA)(\d+)$/.exec(e.trim());if(!t)return{diatonic:0,chromatic:0};let n=Number(t[3])-1,r=n%7,i=I[r]+12*Math.floor(n/7),a=(r===0||r===3||r===4?{dd:-2,d:-1,P:0,A:1,AA:2}:{dd:-3,d:-2,m:-1,M:0,A:1,AA:2})[t[2]]??0,o=t[1]===`-`?-1:1;return{diatonic:o*n,chromatic:o*(i+a)}}const te=({diatonic:e,chromatic:t})=>7*t-12*e;function ne(e,t){if(!t.diatonic&&!t.chromatic)return e;let n=F.indexOf(e.step)+t.diatonic,r=F[L(n,7)],i=e.octave+Math.floor(n/7);return{step:r,octave:i,alter:R(e)+t.chromatic-R({step:r,octave:i,alter:0})}}const R=e=>(e.octave+1)*12+I[F.indexOf(e.step)]+e.alter;function re(e){if(e==null)return null;let t=/^\s*(\d+)\s*([sf]?)\s*$/.exec(e);if(!t)return null;let n=Number(t[1]);return t[2]===`f`?-n:n}const z=e=>e>0?`${e}s`:e<0?`${-e}f`:`0`,ie=e=>{let t=e;for(;t>7;)t-=12;for(;t<-7;)t+=12;return t};function ae(e,t,n,r,i){if(t===0){let t=T(ie(e),n);return i?E(t)??t:t}let a=L(7*(e+7*t),12);return D(L(a-(n===`minor`?3:0),12),n,{family:r.profile,flip:i})}function oe(e){let t=[];return e.forEach((n,r)=>{if(n.tiedFrom!==void 0&&t[n.tiedFrom]&&R(t[n.tiedFrom])===n.midi){t.push(t[n.tiedFrom]);return}let i=e=>e&&!e.chord&&!n.chord?e.midi:void 0;t.push(M(n.midi,n.key,{source:n.source,prev:i(e[r-1]),next:i(e[r+1]),transposed:!0}))}),t}const se=(e,t)=>e.scale[F.indexOf(t)]?.alter??0;function ce(e){let t=Array(e.length).fill(!1),n=e.map((e,t)=>t).sort((t,n)=>e[t].onset-e[n].onset||t-n),r=/* @__PURE__ */ new Map;for(let i=0;i<n.length;){let a=i;for(;a<n.length&&Math.abs(e[n[a]].onset-e[n[i]].onset)<1e-6;)a++;let o=[];for(let s of n.slice(i,a)){let{pitch:n,key:i,tieEnd:a,cautionary:c}=e[s],l=`${n.step}${n.octave}`,u=r.get(l)??se(i,n.step);a||(n.alter!==u||c)&&(t[s]=!0,o.push([l,n.alter]))}for(let[e,t]of o)r.set(e,t);i=a}return t}const le=/^([A-G])([#♯b♭x𝄪𝄫]*)/,ue=e=>[...e].reduce((e,t)=>e+(t===`#`||t===`♯`?1:t===`x`||t===`𝄪`?2:t===`𝄫`?-2:-1),0);function de(e,t){let n=(e,n)=>{let r=t.reduce((e,t)=>ne(e,t),{step:e,alter:ue(n),octave:4});return r.step+(r.alter>0?`#`.repeat(r.alter):`b`.repeat(-r.alter))},r=le.exec(e);if(!r)return e;let i=e.slice(r[0].length).replace(/\/([A-G])([#♯b♭x𝄪𝄫]*)/g,(e,t,r)=>`/${n(t,r)}`);return n(r[1],r[2])+i}const fe={treble:[`G`,`2`],bass:[`F`,`4`],alto:[`C`,`3`],tenor:[`C`,`4`],treble8vb:[`G`,`2`,`8`]},pe=[`clef.shape`,`clef.line`,`clef.dis`,`clef.dis.place`];function me(e,t){let[n,r,i]=fe[e];return`<clef${t?` xml:id="${t}"`:``} shape="${n}" line="${r}"${i?` dis="${i}" dis.place="below"`:``}/>`}function he(e,t){if(!/\sclef\.shape\s*=/.test(e))return e;let n=pe.reduce(Se,e);if(!t||!fe[t])return n;let[r,i,a]=fe[t];return n=H(H(n,`clef.shape`,r),`clef.line`,i),a?H(H(n,`clef.dis`,a),`clef.dis.place`,`below`):n}const ge=`CDEFGAB`,_e=[0,2,4,5,7,9,11],B={s:1,f:-1,n:0,x:2,ss:2,ff:-2,ts:3,tf:-3,xs:3,sx:3,nf:-1,ns:1,su:1,sd:1,fu:-1,fd:-1,nu:0,nd:0},ve=e=>({1:`s`,[-1]:`f`,0:`n`,2:`x`,[-2]:`ff`})[e]??`n`,ye=e=>({1:`s`,[-1]:`f`,0:`n`,2:`ss`,[-2]:`ff`})[e]??`n`;function be(e,t){let n=(t>0?`FCGDAEB`:`BEADGCF`).indexOf(e),r=n<Math.abs(t)?Math.floor((Math.abs(t)-1-n)/7)+1:0;return t>0?r:-r}const V={maxima:32,long:16,breve:8,1:4,2:2,4:1,8:.5,16:.25,32:.125,64:.0625,128:.03125,256:.015625};function xe(e){return r(e,`grace`)===null?(V[r(e,`dur`)||``]??0)*(2-1/2**(Number(r(e,`dots`))||0)):0}function H(e,t,n){let r=RegExp(`\\s${t.replace(`.`,`\\.`)}\\s*=\\s*(?:"[^"]*"|'[^']*')`);return r.test(e)?e.replace(r,` ${t}="${n}"`):e.replace(/\s*(\/?)>$/,` ${t}="${n}"$1>`)}function Se(e,t){return e.replace(RegExp(`\\s${t.replace(`.`,`\\.`)}\\s*=\\s*(?:"[^"]*"|'[^']*')`),``)}const Ce=[`keysig`,`key.sig`,`key.mode`,`key.pname`,`key.accid`,`key.sig.mixed`],we=e=>Ce.reduce(Se,e),Te=e=>e.replace(/\s*\/>$/,`>`),Ee=e=>`<keySig sig="${z(e.fifths)}"${e.mode===`minor`?` mode="minor"`:``}/>`,De=e=>e===`minor`?`minor`:e===`major`?`major`:null,Oe=/^(?:\s+(?:n|xml:id|keysig|key\.[\w.]+)\s*=\s*(?:"[^"]*"|'[^']*'))*\s*$/;function ke(e,t){return t?!!t.interval||t.concert||t.flip||t.semitones!==0||/\b(?:clef\.)?shape="perc"/.test(e)||Object.values(t.staves).some(e=>e.percussion||(e.keys?.length??0)>1||!!e.clef||!!e.shift?.[1]||!!e.shift?.[0]||Object.keys(e.octaves??{}).length>0):!1}async function U(e,t,n,r=0){return!t||!ke(e,t)?e:Ae(t.interval?await n(e,{transpose:t.interval,transposeToSoundingPitch:!1}):e,t,r)}function Ae(e,t,n=0){if(!ke(e,t))return e;let i=te(ee(t.interval)),a=/* @__PURE__ */ new Map;u(e,({closing:e,name:t,attributes:n})=>{if(e||t!==`tie`)return;let i=r(n,`startid`)?.replace(/^#/,``),o=r(n,`endid`)?.replace(/^#/,``);i&&o&&a.set(o,i)});let o=[],s=[],c=[],l=[],d=[],f=[],p=new Set(Object.entries(t.staves).filter(([,e])=>e.percussion).map(([e])=>e)),m=e=>t.staves[e]??{profile:`neutral`,moved:t.semitones!==0},h=e=>{let t=m(e).shift;return t&&(t[0]||t[1])?{diatonic:t[0],chromatic:t[1]}:void 0},g=e=>!p.has(e)&&(m(e).moved||t.semitones!==0||t.flip||!!t.interval||!!h(e)),_=(e,t)=>{let n=p.has(e)?void 0:m(e).octaves;if(!n)return 0;let r=n[t]===void 0?P(t):null;return(n[t]??(r?n[r]:void 0)??0)/12},v=e=>!p.has(e)&&Object.keys(m(e).octaves??{}).length>0,y=e=>{let t=p.has(e)?void 0:m(e).clef;return t&&fe[t]?t:void 0},b=[],x=[],S=[],C,w,E,D=0,O=-1,k=``,A=``,j=0,M=[],F=-1,I=0,L=0,R,z,ie=()=>M.reduce((e,t)=>e*t,1),se=(e,t,n)=>{let i=re(r(e,t))??(t===`key.sig`?re(r(e,`keysig`)):null);return i===null?null:{fifths:i,mode:De(r(e,n))??`major`}};u(e,({closing:t,name:n,attributes:i,selfClosing:u,index:m,length:h})=>{let _=e.slice(m,m+h);if(t){if(S.pop(),E){--D===0&&(E.end=m+h,E=void 0);return}n===`staffDef`&&w?(w.end=m+h,w=void 0):n===`scoreDef`&&C?(C.end=m+h,C=void 0):n===`note`&&R?(R.end=m+h,R=void 0):n===`chord`?(I--,j+=L*ie()):n===`tuplet`?M.pop():n===`harm`&&z?(z.textEnd=m,z=void 0):n===`layer`?A=``:n===`staff`&&(k=``);return}if(u||S.push(n),E){u||D++;return}if(z&&(z.nested=!0),n===`scoreDef`){let e={start:m,end:m+h,initial:!o.length,measure:O+1,content:!1,keyRanges:[],tagEdits:[],keys:/* @__PURE__ */ new Map},t=se(i,`key.sig`,`key.mode`);t&&e.keys.set(`*`,t);let n=we(_);n!==_&&e.tagEdits.push({start:m,end:m+h,text:n}),/\s(?!xml:id)[\w.:-]+\s*=/.test(n.replace(/^<[\w:]+/,``).replace(/\sxml:id\s*=\s*"[^"]*"/,``))&&(e.content=!0),o.push(e),u||(C=e);return}if(C&&n===`staffGrp`){if(C.initial)return;Oe.test(i)||(C.content=!0);return}if(n===`staffDef`){let e=r(i,`n`)||``,t={start:m,end:m+h,n:e,tag:_,selfClosing:u};if(r(i,`clef.shape`)===`perc`&&p.add(e),C){let n=se(i,`key.sig`,`key.mode`);n&&C.keys.set(e,n);let r=y(e)?he(we(_),C.initial?y(e):void 0):we(_);r!==_&&C.tagEdits.push({start:m,end:m+h,text:r}),Oe.test(i)||(C.content=!0),C.initial&&(s.push(t),e&&!x.includes(e)&&x.push(e))}u||(w=t);return}if(n===`clef`&&w){r(i,`shape`)===`perc`&&p.add(w.n),u&&(w.clefEnd=m+h,w.clef={start:m,end:m+h,id:r(i,`xml:id`)}),C&&(C.content=!0),u&&C&&!C.initial&&y(w.n)&&b.push({start:m,end:m+h,text:``});return}if(n===`keySig`){let e={start:m,end:m+h};u||(E=e,D=1);let t=se(i,`sig`,`mode`);C?(C.keyRanges.push(e),t&&C.keys.set(w?w.n:`*`,t)):k&&f.push(Object.assign(e,{staff:k,measure:O,key:t}));return}if(C){C.content=!0;return}if(n===`measure`){O++,c.push(m);return}if(n===`staff`){k=r(i,`n`)||``;return}if(n===`layer`){A=r(i,`n`)||`1`,j=0,M.length=0,I=0;return}if(!k||!A){n===`harm`&&!u&&(z={textStart:m+h,textEnd:m+h,staff:(r(i,`staff`)||``).split(/\s+/)[0],measure:O,nested:!1},d.push(z));return}if(n===`clef`){y(k)&&u&&b.push({start:m,end:m+h,text:``});return}if(n===`tuplet`){let e=Number(r(i,`num`))||1,t=Number(r(i,`numbase`))||1;u||M.push(t/e);return}if(n===`chord`){F=j,L=xe(i),u?j+=L*ie():I++;return}if(n===`note`){let e=I>0,t=e?F:j;e||(j+=xe(i)*ie());let n=(r(i,`pname`)||``).toUpperCase(),o=Number(r(i,`oct`));if(!n||!ge.includes(n)||!Number.isFinite(o)||!(g(k)||v(k)))return;let s=r(i,`xml:id`)||``,c=r(i,`tie`),d=r(i,`accid`),f=r(i,`accid.ges`);R={start:m,end:m+h,tag:_,selfClosing:u,id:s,staff:k,layer:A,measure:O,onset:t,chord:e,pname:n,oct:o,written:d===null?null:B[d]??null,gestural:f===null?null:B[f]??null,accids:[],tieEnd:a.has(s)||c===`t`||c===`m`,cautionary:!1},l.push(R),u&&(R=void 0);return}if(n===`accid`&&R){let e=r(i,`accid`),t=r(i,`accid.ges`);e!==null&&B[e]!==void 0&&(R.written=B[e]),t!==null&&B[t]!==void 0&&(R.gestural=B[t]),(r(i,`func`)!==null||r(i,`enclose`)!==null)&&(R.cautionary=e!==null),R.accids.push({start:m,end:m+h,attributes:i});return}[`rest`,`space`,`mRest`,`mSpace`,`multiRest`].includes(n)&&I===0&&(j+=(n.startsWith(`m`)?1e3:xe(i))*ie())});for(let e of p)x.includes(e)||x.push(e);let le=c.length,ue=/* @__PURE__ */ new Map;for(let e of x){if(p.has(e))continue;let t=Array(Math.max(1,le)).fill(void 0),r=m(e).keys;if(r?.length)for(let e=0;e<t.length;e++){let i=[...r].reverse().find(([t])=>t<=e+n)??r[0];t[e]={fifths:i[1],mode:i[2]}}else{let n={fifths:0,mode:`major`},r=/* @__PURE__ */ new Map;for(let n of o){let a=n.keys.get(e)??n.keys.get(`*`);a&&r.set(Math.min(n.measure,t.length-1),{fifths:a.fifths-i,mode:a.mode})}for(let n of f)n.staff===e&&n.key&&r.set(Math.min(n.measure+1,t.length-1),{fifths:n.key.fifths-i,mode:n.key.mode});for(let e=0;e<t.length;e++)n=r.get(e)??n,t[e]=n}ue.set(e,t)}let pe=/* @__PURE__ */ new Map,V=(e,n)=>{let r=ue.get(e)?.[Math.max(0,Math.min(n,le-1))]??{fifths:0,mode:`major`},i=`${e}|${r.fifths}|${r.mode}`,a=pe.get(i);return a||(a=ae(r.fifths,t.semitones,r.mode,m(e),t.flip),pe.set(i,a)),a},Ce=(e,t)=>{let n=h(e);return(ue.get(e)?.[Math.max(0,Math.min(t,le-1))]?.fifths??0)+i-(n?te(n):0)},U=/* @__PURE__ */ new Map;for(let e of l){let t=`${e.staff}|${e.measure}`;(U.get(t)??U.set(t,[]).get(t)).push(e)}let Ae=/* @__PURE__ */ new Map;for(let e of U.values()){let t=/* @__PURE__ */ new Map;for(let n of[...e].sort((e,t)=>e.onset-t.onset)){let e=`${n.pname}${n.oct}`;Ae.set(n,n.written??n.gestural??t.get(e)??be(n.pname,Ce(n.staff,n.measure))),n.written!==null&&t.set(e,n.written)}}let je=/* @__PURE__ */ new Map;for(let e of l){let t=`${e.staff}|${e.layer}`;(je.get(t)??je.set(t,[]).get(t)).push(e)}let W=/* @__PURE__ */ new Map,G=e=>(e.octave+1)*12+_e[ge.indexOf(e.step)]+e.alter;for(let e of je.values()){let t=new Map(e.map((e,t)=>[e.id,t])),n=e.map(e=>{let n=h(e.staff),r={step:e.pname,octave:e.oct,alter:Ae.get(e)??0},i=n?ne(r,n):r,o={...i,octave:i.octave+_(e.staff,e.id)},s=a.get(e.id);return{midi:G(o),source:o,key:V(e.staff,e.measure),chord:e.chord,tiedFrom:s===void 0?void 0:t.get(s)}});if(!g(e[0].staff)){n.forEach((t,n)=>W.set(e[n],t.source));continue}oe(n).forEach((t,n)=>W.set(e[n],t))}let Me=new Map(l.map(e=>[e.id,e]));for(let e of l){let t=Me.get(a.get(e.id)||``);t&&W.has(t)&&G(W.get(t))===G(W.get(e))&&W.set(e,W.get(t))}let Ne=/* @__PURE__ */ new Set,Pe=(e,t)=>({...T(0),scale:ge.split(``).map(n=>({step:n,alter:be(n,Ce(e,t))}))});for(let e of U.values()){let t=e[0].staff;if(!y(t)&&!v(t))continue;let n=ce(e.map(e=>({pitch:{step:e.pname,octave:e.oct,alter:Ae.get(e)??0},onset:e.onset,key:Pe(e.staff,e.measure),tieEnd:e.tieEnd})));e.forEach((e,t)=>{e.written!==null&&!e.tieEnd&&!n[t]&&Ne.add(e)})}let Fe=/* @__PURE__ */ new Map;for(let e of U.values()){let t=ce(e.map(e=>({pitch:W.get(e),onset:e.onset,key:V(e.staff,e.measure),tieEnd:e.tieEnd,cautionary:e.cautionary||Ne.has(e)})));e.forEach((e,n)=>Fe.set(e,t[n]))}let K=[];for(let e of l){let t=W.get(e),n=Fe.get(e),i=Se(Se(e.tag,`accid`),`accid.ges`);i=H(H(i,`pname`,t.step.toLowerCase()),`oct`,String(t.octave));let a=Number(r(e.tag,`oct.ges`)??NaN);Number.isFinite(a)&&t.octave!==e.oct&&(i=H(i,`oct.ges`,String(a+t.octave-e.oct))),n||(i=H(i,`accid.ges`,ye(t.alter)));let o=e.accids.find(e=>r(e.attributes,`accid`)!==null)??e.accids[0],s=o?r(o.attributes,`xml:id`):null,c=o&&n?[`func`,`enclose`,`place`].map(e=>[e,r(o.attributes,e)]).filter(([,e])=>e!==null).map(([e,t])=>` ${e}="${t}"`).join(``):``,l=n?`<accid${s?` xml:id="${s}"`:``} accid="${ve(t.alter)}"${c}/>`:``;if(e.selfClosing)K.push({start:e.start,end:e.end,text:l?`${Te(i)}${l}</note>`:i});else{K.push({start:e.start,end:e.start+e.tag.length,text:i+l});for(let t of e.accids)K.push({start:t.start,end:t.end,text:``})}}for(let t of d){if(!g(t.staff)||t.nested||t.textEnd<=t.textStart)continue;let n=e.slice(t.textStart,t.textEnd),[,r,i,a]=/^(\s*)([\s\S]*?)(\s*)$/.exec(n),o=h(t.staff),s=N(o?de(i,[o]):i,V(t.staff,Math.max(0,t.measure)));s!==i&&K.push({start:t.textStart,end:t.textEnd,text:r+s+a})}for(let e of f)K.push({start:e.start,end:e.end,text:``});for(let e of o){if(!e.initial&&!e.content){K.push({start:e.start,end:e.end,text:``});continue}K.push(...e.tagEdits);for(let t of e.keyRanges)K.push({start:t.start,end:t.end,text:``})}let Ie=x.filter(e=>!p.has(e));K.push(...b);for(let e of s){if(p.has(e.n)||!Ie.includes(e.n))continue;let t=Ee(V(e.n,0)),n=y(e.n),r=n?he(we(e.tag),n):we(e.tag),i=n&&!e.clef&&!/\sclef\.shape\s*=/.test(e.tag)?me(n,null):``;if(n&&e.clef&&K.push({start:e.clef.start,end:e.clef.end,text:me(n,e.clef.id)}),e.selfClosing){let n=K.findIndex(t=>t.start===e.start&&t.end===e.end);n>=0&&K.splice(n,1),K.push({start:e.start,end:e.end,text:`${Te(r)}${i}${t}</staffDef>`})}else{let n=e.clefEnd??e.start+e.tag.length;K.push({start:n,end:n,text:i+t})}}for(let e=1;e<le;e++){let t=Ie.filter(t=>{let n=V(t,e-1),r=V(t,e);return n.fifths!==r.fifths||n.mode!==r.mode});if(!t.length)continue;let n=c[e];K.push({start:n,end:n,text:`<scoreDef><staffGrp>${t.map(t=>`<staffDef n="${t}">${Ee(V(t,e))}</staffDef>`).join(``)}</staffGrp></scoreDef>`})}if(!K.length)return e;K.sort((e,t)=>e.start-t.start||e.end-t.end);let Le=[],Re=0;for(let t of K)t.start<Re||(Le.push(e.slice(Re,t.start),t.text),Re=t.end);return Le.push(e.slice(Re)),Le.join(``)}const je=[40,45,50,55,59,64],W=.08,G=1e-9;function Me(e,t={}){let n=t.tuning&&t.tuning.length?t.tuning:je,r=Math.max(0,Math.floor(t.capo??0)),i=Math.floor(t.maxFret??22),a=t.octaveFold??!0,o=Math.min(n.length,31),s=Math.max(0,i-r),c=new Int32Array(o);for(let e=0;e<o;e++)c[e]=n[n.length-1-e]+r;let l=Math.max(1,s),u=l+1,d=e=>{for(let t=0;t<o;t++)if(e>=c[t]&&e<=c[t]+s)return!0;return!1},f=e=>{if(Number.isFinite(e)){if(d(e))return 0;if(a)for(let t=1;t<=10;t++){if(d(e+12*t))return 12*t;if(d(e-12*t))return-12*t}}};function p(e,t,n,r){let i=e.length,a=[];if(i===0||i>o)return a;let l=new Int8Array(i),u=new Int8Array(i),d=()=>{let e=99,t=-1,n=0,r=0;for(let a=0;a<i;a++){let i=u[a];r+=l[a],i===0?n++:(i<e&&(e=i),i>t&&(t=i))}let o=t<0,s=1,c=1,d=0;o||(d=t-e,s=Math.max(1,t-3),c=Math.max(1,e),s>c&&(s=c=Math.max(1,e)));let f=i>1?l[i-1]-l[0]+1-i:0,p=-.3*n+.3*Math.max(0,t-12)**2+1*d**1.5+.5*f+.05*r,m=p+W*s;if(a.length===24&&m>=a[23].rank)return;let h={str:l.slice(),fret:u.slice(),open:o,posLo:s,posHi:c,cost:p,rank:m},g=a.length;for(;g>0&&a[g-1].rank>m;)g--;a.splice(g,0,h),a.length>24&&a.pop()},f=(a,p,m,h)=>{if(a===i){d();return}let g=e[a],_=o-(i-a);for(let e=p;e<=_;e++){if(t[a]>=0&&e!==t[a]||r&1<<e)continue;let i=g-c[e];if(i<0||i>s||n[a]>=0&&i!==n[a])continue;let o=m,d=h;i>0&&(i<o&&(o=i),i>d&&(d=i),d-o>(o>=7?5:4))||(l[a]=e,u[a]=i,f(a+1,e+1,o,d))}};return f(0,0,99,-1),a}let m=/* @__PURE__ */ new Map;function h(e,t){let n=String(t);for(let t of e)n+=`,${t.pitch}:${t.fixedT}:${t.fixedFret}`;let r=m.get(n);if(r)return r;let i=e.map((e,t)=>t),a={shapes:[],kept:[]};for(;i.length;){if(i.length<=o){let n=i.map(t=>e[t].pitch),r=i.map(t=>e[t].fixedT),o=i.map(t=>e[t].fixedFret),s=r.some(e=>e>=0),c=i.map(()=>-1),l=[];s&&(l.push([r,o,t]),t&&l.push([r,o,0])),l.push([c,c,t]),t&&l.push([c,c,0]);let u=[];for(let[e,t,r]of l)if(u=p(n,e,t,r),u.length)break;if(u.length){a={shapes:u,kept:i};break}}i=g(e,i)}return m.set(n,a),a}function g(e,t){let n=t.length,r=e=>t.filter((t,n)=>n!==e),i=t=>{let i=t[0],a=1/0;if(t.length>1&&n-1<=o){let o=Array(n-1).fill(-1);for(let n of t){let t=p(r(n).map(t=>e[t].pitch),o,o,0),s=t.length?t[0].rank:1/0;s<a&&(a=s,i=n)}}return r(i)},a=[];for(let r=1;r<n;r++)e[t[r]].pitch===e[t[r-1]].pitch&&a.push(r);if(a.length)return i(a);if(n>2){let r=t.map(t=>(e[t].pitch%12+12)%12),a=[],o=[];for(let e=1;e<n-1;e++)a.push(e),r.some((t,n)=>n!==e&&t===r[e])&&o.push(e);return i(o.length?o:a)}return r(n-1)}let _=e.map(e=>(e.pitches??[]).map(()=>({unplayable:!0}))),v=e.map(e=>{let t=[];return(e.pitches??[]).forEach((n,r)=>{let i=f(n);if(i===void 0)return;let a=n+i,l=-1,u=-1,d=e.fixed?.[r];if(d){let e=Math.floor(d.string)-1,t=d.fret!==void 0&&d.fret!==null&&Number.isFinite(d.fret),n=t?Math.floor(d.fret):a-(c[e]??NaN);e>=0&&e<o&&n>=0&&n<=s&&c[e]+n===a&&(l=e,u=t?n:-1)}t.push({pitch:a,orig:r,shifted:i,fixedT:l,fixedFret:u})}),t.sort((e,t)=>t.pitch-e.pitch||e.orig-t.orig),t.length?t:void 0}),y=new Float64Array(e.length*u),b=new Int32Array(e.length*u),x=new Int32Array(e.length*u),S=new Float64Array(u),C=new Int32Array(u),w=[],T=-1/0,E=0,D=e=>{let t=-1,n=1/0;for(let r=1,i=e*u+1;r<u;r++,i++)y[i]<n&&(n=y[i],t=r);return t},O=t=>{let n=0,r=w.length?D(w.length-1):-1;for(let i=w.length-1;i>=0&&r>=0;i--){let a=w[i];if(a.reach<=t+G)break;if(a.end<=t+G){r=x[i*u+r];continue}let o=a.plan.shapes[b[i*u+r]],s=e[a.event].durations??[];for(let e=0;e<a.plan.kept.length;e++)a.onset+(s[a.notes[a.plan.kept[e]].orig]??0)>t+G&&(n|=1<<o.str[e]);r=x[i*u+r]}return n},k=()=>{if(!w.length)return;let e=D(w.length-1);for(let t=w.length-1;t>=0&&e>=0;t--){let n=w[t],r=n.plan.shapes[b[t*u+e]],i=_[n.event];for(let e=0;e<n.plan.kept.length;e++){let t=n.notes[n.plan.kept[e]],a={string:r.str[e]+1,fret:r.fret[e]};t.shifted&&(a.shifted=t.shifted),i[t.orig]=a}e=x[t*u+e]}w=[]};for(let t=0;t<e.length;t++){let n=v[t];if(!n)continue;let r=e[t],i=Number.isFinite(r.onset)?r.onset:E,a=Math.max(0,i-T);a>=2&&k();let o=h(n,O(i));if(!o.shapes.length)continue;let s=w.length,c=s*u,d=c-u;if(s>0){let e=1+.5*a,t=1.5/e,n=2/e,r=1/0,i=-1;for(let e=1;e<u;e++){S[e]=r,C[e]=i;let t=y[d+e];r+=n,t+n<r&&(r=t+n,i=e)}r=1/0,i=-1;for(let e=u-1;e>=1;e--){let a=S[e],o=C[e];r<a&&(a=r,o=i);let s=y[d+e];r+=n,s+n<r&&(r=s+n,i=e),a+=t,s<=a?(S[e]=s,C[e]=s<1/0?e:-1):(S[e]=a,C[e]=o)}}y.fill(1/0,c,c+u),b.fill(-1,c,c+u),x.fill(-1,c,c+u);let f=o.shapes;for(let e=0;e<f.length;e++){let t=f[e],n=t.open?1:t.posLo,r=t.open?l:t.posHi;for(let i=n;i<=r;i++){let n=t.cost+W*i,r=-1;s>0&&(t.open?(n+=y[d+i],r=i):(n+=S[i],r=C[i])),n<y[c+i]&&(y[c+i]=n,b[c+i]=e,x[c+i]=r)}}let p=r.durations??[],m=0;for(let e of n)m=Math.max(m,p[e.orig]??0);w.push({event:t,plan:o,notes:n,onset:i,end:i+m,reach:Math.max(i+m,w.at(-1)?.reach??-1/0)}),E=i,T=i+m}return k(),_}function Ne(e,t={}){let n=e.map(()=>({continuation:!1})),r=e.map((e,t)=>t).filter(t=>{let n=e[t];return n.pitch!==null&&Number.isFinite(n.pitch)&&Number.isFinite(n.onset)}).sort((t,n)=>e[t].onset-e[n].onset||t-n),i=/* @__PURE__ */ new Map,a=/* @__PURE__ */ new Map,o=[],s=[],c=e=>e.onset+(Number.isFinite(e.duration)?Math.max(0,e.duration):0);for(let t=0;t<r.length;){let l=e[r[t]].onset,u=t;for(;u<r.length&&Math.abs(e[r[u]].onset-l)<1e-6;)u++;let d=r.slice(t,u);t=u;let f=[];for(let t of d){let r=e[t],o=r.tieStop?a.get(r.pitch):void 0;o&&(i.set(t,o),n[t].continuation=!0,f.push(t),s[o[0]][o[1]]=Math.max(s[o[0]][o[1]],c(r)))}for(let t of f)e[t].tieStart||a.delete(e[t].pitch);for(let t of f)e[t].tieStart&&a.set(e[t].pitch,i.get(t));let p,m=/* @__PURE__ */ new Map;for(let t of d){if(n[t].continuation)continue;let r=e[t],u=r.pitch;p||(p={onset:l,durations:[],pitches:[],fixed:[]},o.push(p),s.push([]));let d=o.length-1,f=m.get(u);f===void 0?(f=p.pitches.length,m.set(u,f),p.pitches.push(u),p.fixed.push(r.fixed),s[d].push(c(r))):(s[d][f]=Math.max(s[d][f],c(r)),p.fixed[f]||(p.fixed[f]=r.fixed)),i.set(t,[d,f]),r.tieStart&&a.set(u,[d,f])}}o.forEach((e,t)=>{e.durations=s[t].map(t=>t-e.onset)});let l=Me(o,t);for(let[e,[t,r]]of i)n[e].result=l[t][r];return n}const Pe={c:0,d:2,e:4,f:5,g:7,a:9,b:11},Fe={s:1,f:-1,n:0,x:2,ss:2,ff:-2,ts:3,tf:-3,xs:3,sx:3,nf:-1,ns:1,su:1,sd:1,fu:-1,fd:-1,nu:0,nd:0},K={maxima:32,long:16,breve:8,1:4,2:2,4:1,8:.5,16:.25,32:.125,64:.0625,128:.03125,256:.015625},Ie=/* @__PURE__ */ new Set([`rest`,`space`,`mRest`,`mSpace`,`multiRest`]),Le=/* @__PURE__ */ new Set([`beam`,`tuplet`]),Re=/* @__PURE__ */ new Set([`bTrem`,`fTrem`,`ligature`,`choice`,`orig`,`reg`,`sic`,`corr`,`supplied`,`add`,`subst`]),ze=/* @__PURE__ */ new Set([`harm`,`tempo`,`dir`,`repeatMark`,`fermata`]),Be=/* @__PURE__ */ new Set([`mRpt`,`mRpt2`,`multiRpt`]),Ve=/* @__PURE__ */ new Set([...Be,`beatRpt`,`halfmRpt`]),He=[[`c`],[`c`,`s`],[`d`],[`e`,`f`],[`e`],[`f`],[`f`,`s`],[`g`],[`a`,`f`],[`a`],[`b`,`f`],[`b`]],Ue=e=>e.replace(/[&<>"]/g,``),q=(e,t)=>e?` xml:id="${Ue(e)}${t}"`:``;function We(e,t,n){let i=Number(r(e,`dur.ppq`));if(t&&Number.isFinite(i)&&r(e,`dur.ppq`)!==null)return i/t;let a=K[r(e,`dur`)||``];return a===void 0?0:a*(2-1/2**(Number(r(e,`dots`))||0))*n.reduce((e,t)=>e*t,1)}const Ge=(e,t,n)=>{let i=(r(e,`pname`)||``).toLowerCase(),a=Number(r(e,`oct`));if(!(i in Pe)||!Number.isFinite(a)||r(e,`oct`)===null)return null;let o=r(e,`accid.ges`)??t.gestural??r(e,`accid`)??t.written??``;return 12*(a+1)+Pe[i]+(Fe[o]??0)+n},Ke=e=>typeof e==`number`&&Number.isFinite(e)?Math.max(0,Math.min(24,Math.round(e))):0,qe=e=>Array.isArray(e)&&e.length>=1&&e.length<=31&&e.every(e=>Number.isInteger(e)&&e>=0&&e<=127)?e:je,Je=e=>{if(!e.size)return null;let t=Math.max(...e.keys()),n=Array.from({length:t},(n,r)=>e.get(t-r));return n.every(e=>e!==void 0)?n:null};function Ye(e,t){return`<tuning>${[...e].reverse().map((e,n)=>{let r=e+t,[i,a]=He[(r%12+12)%12];return`<course n="${n+1}" pname="${i}" oct="${Math.floor(r/12)-1}"${a?` accid="${a}"`:``}/>`}).join(``)}</tuning>`}function Xe(e,t){let n=new Set(t.generate),i=t.refret??{},a=new Set(t.sounding??[]),o=t.switched??{},s=/* @__PURE__ */ new Set([...n,...Object.keys(i)]),c=new Map([...s].map(e=>[e,[]])),l=/* @__PURE__ */ new Map,d=/* @__PURE__ */ new Set,f=/* @__PURE__ */ new Set,p=/* @__PURE__ */ new Set,m=4,h=4,g=4,_=(e,t)=>{let n=Number(r(e,`${t}count`)),i=Number(r(e,`${t}unit`));n>0&&(h=n),i>0&&(g=i),m=h*4/g},v=0,y=0,b=!1,x=!1,S=null,C=0,w=null,T=0,E=[],D=null,O=!1,k=null,A=0,j=()=>{if(!k)return;let e=l.get(S);if(S in i){let t=Number(r(k.attributes,`tab.course`)),n=Number(r(k.attributes,`tab.fret`)),a=e?.courses?.get(t);k.rec.midi=a!==void 0&&Number.isInteger(n)&&n>=0&&r(k.attributes,`tab.fret`)!==null?a+n+i[S]:null}else k.rec.midi=Ge(k.attributes,k,e?.semi??0);k=null};return u(e,({closing:e,name:u,attributes:h,selfClosing:M})=>{if(e){if(u===`staffDef`){w?.courses.size&&(w.entry.courses=w.courses),w=null;return}if(u===`measure`){x=!1,v+=y>0&&!b?y:Math.max(y,m);return}if(!S)return;if(A){A--;return}u===`note`?j():u===`chord`||u===`tabGrp`?(D&&!O&&(T+=D.dur),D=null):u===`tuplet`?E.pop():u===`layer`?y=Math.max(y,T):u===`staff`&&--C===0&&(S=null);return}if(u===`scoreDef`){_(h,`meter.`);return}if(u===`meterSig`){_(h,``);return}if(u===`staffDef`){_(h,`meter.`);let e=r(h,`n`)||``;if(s.has(e)){let t=l.get(e),n=Number(r(h,`ppq`)),s=r(h,`trans.semi`),c={ppq:n>0?n:t?.ppq,semi:e in o?o[e]:a.has(e)?0:s===null?t?.semi??0:Number(s)||0,courses:t?.courses};l.set(e,c),e in i&&!M&&(w={entry:c,courses:/* @__PURE__ */ new Map})}return}if(u===`course`&&w){let e=Number(r(h,`n`)),t=Ge(h,{},0);e>=1&&t!==null&&w.courses.set(e,t);return}if(u===`measure`){x=!0,y=0,b=!1;return}if(u===`tie`&&x){let e=(r(h,`startid`)||``).replace(/^#/,``),t=(r(h,`endid`)||``).replace(/^#/,``);e&&t&&(d.add(e),f.add(t));return}if(u===`staff`&&!S){let e=r(h,`n`)||``;s.has(e)&&!M&&(S=e,C=1);return}if(!S)return;if(A){M||A++;return}if(!M&&u===`staff`){C++;return}let N=c.get(S),P=l.get(S)?.ppq;if(u===`layer`){T=0;return}if(u===`graceGrp`){M||(A=1);return}if(u===`tuplet`){let e=Number(r(h,`num`))||1,t=Number(r(h,`numbase`))||1;M||E.push(t/e);return}if(u===`chord`||u===`tabGrp`){if(O=r(h,`grace`)!==null,O){M||(A=1);return}D={onset:v+T,dur:We(h,P,E),notes:[]},N.push(D);let e=r(h,`xml:id`);e&&n.has(S)&&p.add(e),M&&(T+=D.dur,D=null);return}if(u===`note`){if(!D&&r(h,`grace`)!==null){M||(A=1);return}let e=D;e||(e={onset:v+T,dur:We(h,P,E),notes:[]},N.push(e),T+=e.dur);let i=r(h,`xml:id`)||``;i&&n.has(S)&&p.add(i);let a=r(h,`tie`)||``,o=Number(r(h,`tab.course`)),s=Number(r(h,`tab.fret`)),c=Number.isInteger(s)&&r(h,`tab.fret`)!==null,l={id:i,midi:null,fixed:t.fixed&&n.has(S)&&!t.unfixed?.includes(S)&&Number.isInteger(o)&&o>=1?c?{string:o,fret:s}:{string:o}:void 0,continuation:/[mt]/.test(a),tieStart:/[im]/.test(a),dur:e.dur};e.notes.push(l),k={rec:l,attributes:h,event:e,inChord:!!D},M&&j();return}if(u===`accid`&&k){let e=r(h,`accid`),t=r(h,`accid.ges`);e!==null&&(k.written=e),t!==null&&(k.gestural=t);return}(Ie.has(u)||Ve.has(u))&&(u===`mRest`||u===`mSpace`||u===`multiRest`||Be.has(u)?b=!0:T+=u===`halfmRpt`?m/2:u===`beatRpt`?4/g:We(h,P,E))}),{staves:c,tieStarts:d,tieEnds:f,info:l,ids:p}}function Ze(e,t,n,r,i,a){let o=/* @__PURE__ */ new Map,s=qe(i.tuning),c=Ke(i.capo);for(let[l,u]of e){let e=[],d=[];for(let r of u)for(let i of r.notes)e.push(i),d.push({onset:r.onset,duration:i.dur,pitch:i.midi,tieStart:i.tieStart||t.has(i.id),tieStop:i.continuation||n.has(i.id),fixed:a?.get(i.id)??i.fixed});let f=l in(i.refret??{})&&r.get(l)?.courses?Je(r.get(l).courses):null;Ne(d,f?{tuning:f,capo:0}:{tuning:s,capo:c}).forEach(({result:t,continuation:n},r)=>{let i=e[r];if(i.continuation=n,t){if(n){i.held=t;return}o.set(i.id,t),a&&i.id&&`string`in t&&!a.has(i.id)&&a.set(i.id,{string:t.string,fret:t.fret})}})}return o}const Qe=e=>[`dur`,`dots`,`dur.ppq`].map(t=>{let n=r(e,t);return n===null?``:` ${t}="${n}"`}).join(``),$e=(e,t)=>t&&`string`in t?`<note${q(e,``)} tab.course="${t.string}" tab.fret="${t.fret}"/>`:``,et=e=>e&&`string`in e?`<note tab.course="${e.string}" tab.fret="${e.fret}" visible="false"/>`:``,tt=(e,t,n)=>{let r=RegExp(`(\\s${t.replace(`.`,`\\.`)}\\s*=\\s*)(?:"[^"]*"|'[^']*')`);return r.test(e)?e.replace(r,`$1"${n}"`):e.replace(/\s*(\/?)>$/,` ${t}="${n}"$1>`)};function nt(e,t,n){let i=new Set(t.generate),a=t.refret??{},o=t.retarget,s=Object.keys(o).length>0;if(!i.size&&!s&&!Object.keys(a).length)return e;let c=i.size||Object.keys(a).length,{staves:l,tieStarts:d,tieEnds:f,info:p,ids:m}=c?Xe(e,t):{staves:/* @__PURE__ */ new Map,tieStarts:/* @__PURE__ */ new Set,tieEnds:/* @__PURE__ */ new Set,info:/* @__PURE__ */ new Map,ids:/* @__PURE__ */ new Set},h=c?Ze(l,d,f,p,t,n):/* @__PURE__ */ new Map,g=/* @__PURE__ */ new Map;for(let e of l.values())for(let t of e)for(let e of t.notes)e.continuation&&g.set(e.id,e.held);let _=qe(t.tuning),v=Ye(_,Ke(t.capo)),y=new Set([...i].map(e=>String(100+Number(e)))),b=[],x=0,S=-1,C=!1,w=0,T=null,E=null,D=0,O=0,k=null,A=-1,j=(e,t,n)=>{let r=p.get(e)?.ppq;return`<staffDef${q(t,`-tab`)} n="${100+Number(e)}" lines="${_.length}" notationtype="tab.guitar" keysig="0"${r?` ppq="${r}"`:``}><clef shape="TAB" line="${_.length-1}"/>${v}${n}</staffDef>`};return u(e,({closing:t,name:n,attributes:c,selfClosing:l,index:u,length:d})=>{b.push(e.slice(x,u)),x=u+d;let f=e.slice(u,u+d);if(t?w--:l||w++,!t&&ze.has(n)&&s){let e=r(c,`staff`);if(e!==null){let t=e.split(/\s+/).filter(Boolean).map(e=>o[e]??e).join(` `);if(t!==e){f=tt(f,`staff`,t);let e=r(c,`startid`)?.replace(/^#/,``)??``;e&&m.has(e)&&t.split(` `).every(e=>y.has(e))&&(f=tt(f,`startid`,`#${e}-tab`))}}}if(A<0&&n===`staff`&&!t&&!l&&(r(c,`n`)||``)in a)A=w;else if(A>=0&&t&&n===`staff`&&w===A-1)A=-1;else if(A>=0&&n===`note`&&!t){let e=r(c,`xml:id`)||``,t=g.has(e)?g.get(e):h.get(e);t&&`string`in t?f=tt(tt(f,`tab.course`,String(t.string)),`tab.fret`,String(t.fret)):t&&(f=tt(f,`visible`,`false`))}if(b.push(f),n===`scoreDef`&&!t&&!C&&S<0){l?C=!0:S=w;return}if(n===`scoreDef`&&t&&S>=0&&w===S-1){S=-1,C=!0;return}if(S>=0){if(n===`staffDef`&&!t){let e=r(c,`n`)||``;if(!i.has(e))return;let t=r(c,`xml:id`)||``;if(l){b.push(j(e,t,``));return}T={n:e,id:t,meterSig:``,depth:w};return}if(T&&n===`meterSig`&&!t){T.meterSig=f.replace(/\sxml:id\s*=\s*"[^"]*"/,``).replace(/\s*\/?>$/,`/>`);return}T&&n===`staffDef`&&t&&w===T.depth-1&&(b.push(j(T.n,T.id,T.meterSig)),T=null);return}if(!E){if(n===`staff`&&!t&&!l&&i.has(r(c,`n`)||``)){let e=r(c,`n`);E=[`<staff${q(r(c,`xml:id`)||``,`-tab`)} n="${100+Number(e)}">`],D=w,O=0,k=null}return}if(t&&n===`staff`&&w===D-1){E.push(`</staff>`),b.push(E.join(``)),E=null;return}if(O){t?O--:l||O++;return}let p=r(c,`xml:id`)||``;if(t){n===`layer`||Le.has(n)?E.push(`</${n}>`):n===`chord`&&k&&(k.frets||E.push(et(k.held)),E.push(`</tabGrp>`),k=null);return}if(n===`layer`||Le.has(n)){let e=[`n`,`num`,`numbase`,`num.visible`,`bracket.visible`,`num.format`,`bracket.place`,`num.place`].map(e=>{let t=r(c,e);return t===null?``:` ${e}="${t}"`}).join(``);E.push(`<${n}${q(p,`-tab`)}${e}${l?`/>`:`>`}`);return}if(!Re.has(n)){if(n===`chord`){if(r(c,`grace`)!==null){l||(O=1);return}E.push(`<tabGrp${q(p,`-tab`)}${Qe(c)}><tabDurSym/>`),l?E.push(`</tabGrp>`):k={frets:0};return}if(n===`note`){if(l||(O=1),k){if(g.has(p)){k.held||(k.held=g.get(p));return}let e=$e(p?`${p}-tab`:``,h.get(p));e&&k.frets++,E.push(e);return}if(r(c,`grace`)!==null)return;E.push(`<tabGrp${q(p,`-tab`)}${Qe(c)}><tabDurSym/>${g.has(p)?et(g.get(p)):$e(p?`${p}-tabn`:``,h.get(p))}</tabGrp>`);return}if(Ie.has(n)||Ve.has(n)){l||(O=1);let e=Ve.has(n)?c.replace(/\s+xml:id\s*=\s*(?:"[^"]*"|'[^']*')/,``).trimEnd():Qe(c);E.push(`<${n}${q(p,`-tab`)}${e}/>`);return}l||(O=1)}}),b.push(e.slice(x)),b.join(``)}const rt=e=>`reader-m${e+1}`,it=`(?:[^>"']|"[^"]*"|'[^']*')*`,J=RegExp(`<!--[\\s\\S]*?-->|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>|<\\?[\\s\\S]*?\\?>|<(/?)(part|measure|attributes|lyric|slur|wedge|octave-shift|pedal|bracket|dashes|tuplet|glissando|slide|ending|beam)(?=[\\s/>])(${it})>`,`g`),at=/* @__PURE__ */ new Map;function ot(e,t){if(!e.includes(t))return;let n=at.get(t);n||at.set(t,n=RegExp(`\\s${t}\\s*=\\s*(?:"([^"]*)"|'([^']*)')`));let r=n.exec(e);return r?r[1]??r[2]:void 0}const st=/* @__PURE__ */ new Set([`start`,`up`,`down`,`crescendo`,`diminuendo`]);function ct(e){let t=/<score-partwise[\s>]/.exec(e),n=e.indexOf(`</part-list>`);if(!t||n<0)return;let r=[],i=[],a=/* @__PURE__ */ new Map,o=``,s,c=-1,l=-1,u=0,d=/* @__PURE__ */ new Set,f=0,p=-1;J.lastIndex=n;for(let t=J.exec(e);t;t=J.exec(e)){let n=t[2];if(!n)continue;let m=t[1]===`/`,h=t[3]||``,g=h.endsWith(`/`);if(n===`part`){if(m){if(!s||c>=0)return;s=void 0,p=t.index+t[0].length}else{if(s||g)return;r.length||(o=e.slice(0,t.index)),s={open:t[0],measures:[],attributes:[]},r.push(s),l=-1}continue}if(!s)continue;if(n===`measure`){if(m){if(c<0)return;s.measures.push(c,t.index+t[0].length),c=-1,u&&(f=Math.max(f,Math.ceil(u/Math.max(1,d.size))))}else{if(c>=0)return;l++,u=0,d=/* @__PURE__ */ new Set,g?s.measures.push(t.index,t.index+t[0].length):c=t.index}continue}if(c<0||m)continue;if(n===`attributes`){if(g)continue;let n=e.indexOf(`</attributes>`,t.index);if(n<0)return;let r=n+13;s.attributes.push({measure:l,block:e.slice(t.index,r),leading:!/<note(?=[\s/>])/.test(e.slice(c,t.index))}),J.lastIndex=r;continue}if(n===`lyric`){u++,d.add(ot(h,`number`)||`1`);continue}let _;if(n===`beam`){let t=/^\s*(begin|end)\b/.exec(e.slice(J.lastIndex,J.lastIndex+16))?.[1];_=t===`begin`?`open`:t===`end`?`close`:void 0}else{let e=ot(h,`type`)||``;_=st.has(e)?`open`:e===`stop`||n===`ending`&&e===`discontinue`?`close`:void 0}if(!_)continue;let v=`${r.length}:${n}:${n===`ending`?``:ot(h,`number`)||`1`}`;if(_===`open`)a.set(v,l);else{let e=a.get(v);e!==void 0&&(a.delete(v),l>e&&i.push({start:e,end:l}))}}if(!r.length||s||c>=0)return;let m=r[0].measures.length/2;if(m)return i.sort((e,t)=>e.start-t.start),{text:e,head:o,tail:e.slice(p),parts:r,measureCount:m,lyricDensity:f,spans:i}}const lt=[`divisions`,`key`,`time`,`staves`,`part-symbol`,`instruments`,`clef`,`staff-details`,`transpose`,`for-part`],Y=RegExp(`<(${lt.join(`|`)})(?=[\\s/>])(${it})>`,`g`);function ut(e,t){let n=/* @__PURE__ */ new Map;for(let{measure:r,block:i}of e.attributes){if(r>=t)break;Y.lastIndex=0;for(let e=Y.exec(i);e;e=Y.exec(i)){let[t,r,a]=e,o=t;if(!a.endsWith(`/`)){let t=i.indexOf(`</${r}>`,Y.lastIndex);if(t<0)continue;o=i.slice(e.index,t+r.length+3),Y.lastIndex=t+r.length+3}let s=ot(a,`number`)??(r===`clef`?`1`:void 0);if(s===void 0)for(let e of[...n.keys()])e.startsWith(`${r}#`)&&n.delete(e);n.set(`${r}#${s??``}`,o)}}for(let{measure:r,block:i,leading:a}of e.attributes)if(r===t&&a)for(let[,e]of i.matchAll(/<key(?=[\s/>])((?:[^>"']|"[^"]*"|'[^']*')*)>/g)){let t=ot(e,`number`);for(let e of[...n.keys()])e.startsWith(`key#`)&&(t===void 0||e===`key#${t}`||e===`key#`)&&n.delete(e)}if(!n.size)return``;let r=[];for(let e of lt)for(let[t,i]of n)t.startsWith(`${e}#`)&&r.push(e===`time`?i.replace(/^<time\b((?:[^>"']|"[^"]*"|'[^']*')*)/,(e,t)=>`<time print-object="no"${t.replace(/\sprint-object\s*=\s*(?:"[^"]*"|'[^']*')/,``)}`):i);return`<attributes>${r.join(``)}</attributes>`}function dt(e,t,n,r){let i=t.measures[n*2],a=t.measures[n*2+1],o=e.text.slice(i,a),s=/^<measure\b(?:[^>"']|"[^"]*"|'[^']*')*>/.exec(o)[0].length,c=o.slice(0,s),l=` id="${rt(n)}"`;return c=/\sid\s*=\s*(?:"[^"]*"|'[^']*')/.test(c)?c.replace(/\sid\s*=\s*(?:"[^"]*"|'[^']*')/,l):c.replace(/\s*(\/?)>$/,`${l}$1>`),c.endsWith(`/>`)?r?`${c.slice(0,-2)}>${r}</measure>`:c:c+r+o.slice(s)}function ft(e,t,n){let r=[t>0?e.head.replace(/<credit\b[\s\S]*?<\/credit>/g,``):e.head];for(let i of e.parts){r.push(i.open);let a=Math.min(n,i.measures.length/2);for(let n=t;n<a;n++)r.push(dt(e,i,n,n===t&&t>0?ut(i,t):``));r.push(`</part>`)}return r.push(e.tail),r.join(``)}function pt(e,t){let n=t-1;for(let r of e.spans){if(r.start>=t)break;r.end>=t&&(n=Math.min(n,r.start))}return Math.max(0,Math.min(t,16,t-n))}function mt(e,t){let n=t;for(let r of e.spans){if(r.start>=t)break;r.end>=t&&(n=Math.max(n,r.end))}return Math.max(0,Math.min(e.measureCount-t,16,n-t+1))}function ht(e,t,n,r,i){let a=e.measureCount;if(n<=0)return{from:0,to:a,firstSystem:0,endSystem:1,firstPage:1};let o=Math.ceil(a/n),s=Math.max(1,Math.floor(i/Math.max(1,r*n))),c=Math.floor(Math.max(0,Math.min(o-1,t))/s)*s,l=Math.min(o,c+s),u=c*n,d=Math.min(a,l*n),f=pt(e,u),p=d<a?mt(e,d):0,m=u-f,h=f?Math.ceil(u/n)-Math.floor(m/n)+1:1;return{from:m,to:d+p,firstSystem:c,endSystem:l,firstPage:h}}const gt=[`breaks`,`transpose`,`transposeToSoundingPitch`,`xmlIdChecksum`];let _t,vt,yt;function bt(){return vt??=(async()=>{if(!_t)throw Error(`The notation renderer was not told where to load Verovio from.`);let{module:e,toolkit:t}=_t;try{let[n,r]=await Promise.all([import(
2
+ /* @vite-ignore */
3
+ e),import(
4
+ /* @vite-ignore */
5
+ t)]);if(typeof n.default!=`function`||typeof r.VerovioToolkit!=`function`||typeof r.enableLogToBuffer!=`function`)throw Error(`not a compatible Verovio build`);return yt={createModule:n.default,Toolkit:r.VerovioToolkit,enableLogToBuffer:r.enableLogToBuffer}}catch(n){throw vt=void 0,new Dt(`Could not load Verovio from ${e} and ${t}: ${n instanceof Error?n.message:String(n)}`,void 0)}})()}let X,xt;function St(){if(X)return X;let e=bt().then(e=>e.createModule()).then(e=>(yt.enableLogToBuffer(1,e),xt=e,e)).catch(t=>{throw X===e&&(X=void 0),t});return X=e}const Ct=async()=>{let e=await St();return new yt.Toolkit(e)};let wt,Tt,Z;const Q=/* @__PURE__ */ new Map,Et=[];var Dt=class extends Error{code;constructor(e,t){super(e),this.code=t}};function Ot(e){for(let e of[wt,Tt])try{e?.destroy()}catch{}wt=Tt=void 0,Z=void 0,e&&(X=void 0,xt=void 0)}async function kt(e){return e===`main`?wt??=await Ct():Tt??=await Ct()}function At(){let e=xt;return e?.HEAPU8?.length??e?.wasmMemory?.buffer.byteLength}function jt(e){let t=Q.get(e);if(!t)throw new Dt(`The score is no longer loaded in the renderer.`,`missing`);return Q.delete(e),Q.set(e,t),t}function $(e,t,n){if(e.resetOptions(),e.setOptions(n),!e.loadData(t))throw Error(`Verovio could not import this score.`)}const Mt={breaks:`none`,inputFrom:`auto`,xmlIdChecksum:!0};async function Nt(e){let t=await Ct();try{return $(t,e,Mt),t.getMEI()}finally{try{Et.push(t.getLog()||``)}catch{}try{t.destroy()}catch{}}}async function Pt(e,t,n){let r=`${t}-${n}`,i=e.meis.get(r);if(i!==void 0)return e.meis.delete(r),e.meis.set(r,i),i;for(i=await Nt(ft(e.index,t,n)),e.meis.set(r,i);e.meis.size>8;)e.meis.delete(e.meis.keys().next().value);return i}async function Ft(e,t){let n=await Ct();try{return $(n,e,{breaks:`none`,xmlIdChecksum:!0,...t}),n.getMEI()}finally{try{Et.push(n.getLog()||``)}catch{}try{n.destroy()}catch{}}}const It=(e,t,n=0)=>U(e,t,Ft,n);async function Lt(e,t){if(!t)return e.mei;let n=JSON.stringify(t);return e.spelled?.key!==n&&(e.spelled={key:n,mei:await It(e.mei,t)}),e.spelled.mei}async function Rt(e,t){let n=await Lt(e,t.spelling);if(!t.tab)return n;let r=JSON.stringify([t.spelling??null,t.tab]);return e.tabbed?.key!==r&&(e.tabbed={key:r,mei:nt(n,t.tab)}),e.tabbed.mei}async function zt(e,t,n,r){let i=await Bt(e,t,n,r.spelling);if(!r.tab)return i;let a=JSON.stringify([r.spelling??null,r.tab]),o=e.frets.get(a);if(!o)for(o=/* @__PURE__ */ new Map,e.frets.set(a,o);e.frets.size>4;)e.frets.delete(e.frets.keys().next().value);return nt(i,r.tab,o)}async function Bt(e,t,n,r){let i=await Pt(e,t,n);if(!r||!ke(i,r))return i;let a=`${t}-${n}|${JSON.stringify(r)}`,o=e.spelled.get(a);if(o!==void 0)return e.spelled.delete(a),e.spelled.set(a,o),o;for(o=await It(i,r,t),e.spelled.set(a,o);e.spelled.size>8;)e.spelled.delete(e.spelled.keys().next().value);return o}const Vt=(e,t)=>Object.fromEntries(t.map(t=>[t,e[t]??null]));async function Ht(e,t,n,r){let i=JSON.stringify([...e,t,Vt(n,gt)]),a=JSON.stringify(n),o=await kt(`main`);return Z?.loadKey===i?Z.optionsKey!==a&&(Z=void 0,o.resetOptions(),o.setOptions(n),o.redoLayout(),Z={loadKey:i,optionsKey:a}):(Z=void 0,$(o,await r(),n),Z={loadKey:i,optionsKey:a}),o}function Ut(e,t,n){return Math.min(n,Math.max(t*2,qt(e,t,t*4)+1))}const Wt=/\s(?:endid|tstamp2)\s*=\s*"([^"]*)"/g,Gt=/\sxml:id\s*=\s*"([^"]*)"/,Kt=/<measure\b/g;function qt(e,t,n){let r=[];Kt.lastIndex=0;for(let t=Kt.exec(e);t&&r.length<=n;t=Kt.exec(e))r.push(t.index);let i=/* @__PURE__ */ new Set,a=0;for(let n=0;n+1<r.length;n++){let o=e.slice(r[n],r[n+1]);if(n<t)for(let[,e]of o.matchAll(Wt)){let t=/^(\d+)m\+/.exec(e);t?a=Math.max(a,n+Number(t[1])):i.add(e.replace(/^#/,``))}else if(i.size)for(let e of o.match(/<[^>]*\sxml:id\s*=\s*"[^"]*"[^>]*>/g)||[]){let t=Gt.exec(e)?.[1];t&&i.delete(t)&&(a=Math.max(a,n))}if(n>=t&&!i.size)break}return Math.min(n-1,a)}async function Jt(e,t,n){let r=new TextDecoder().decode(t),i=ct(r),a;if(i&&(n||i.parts.length*i.measureCount>=2400)){let{staffDefs:e,groups:t}=d(await Nt(ft(i,0,1)));a={kind:`chunked`,index:i,info:{measureIds:Array.from({length:i.measureCount},(e,t)=>rt(t)),lyricDensity:i.lyricDensity,staffDefs:e,groups:t,chunked:!0},meis:/* @__PURE__ */ new Map,spelled:/* @__PURE__ */ new Map,frets:/* @__PURE__ */ new Map}}else{let e=await kt(`main`);Z=void 0,$(e,r,Mt);let t=e.getMEI();a={kind:`whole`,mei:t,info:d(t)}}for(Q.delete(e),Q.set(e,a);Q.size>12;)Q.delete(Q.keys().next().value);return a.info}function Yt(e,t,n){let r=e.renderToSVG(t),i=/<svg\b[^>]*?\sid="([^"]+)"/.exec(r)?.[1];return!i||!/^[\w-]+$/.test(i)?r:r.replace(RegExp(`(?<=[#"-])${i}(?![\\w-])`,`g`),`${i}-c${n}`)}const Xt=(e,t)=>{let n=new Set(t.hiddenStaves);return Math.max(1,e.staffDefs.filter(e=>!n.has(e.n)).length+(t.tab?.generate.length??0))};async function Zt(e){if(e.kind===`import`)return Jt(e.revision,e.bytes,!!e.chunking?.force);if(e.kind===`release`)return Q.delete(e.revision),null;if(e.simulateOom)throw await new Promise(e=>setTimeout(e,300)),RangeError(`Cannot enlarge memory arrays (simulated).`);let t=jt(e.revision);if(e.kind===`probe`){let n=await kt(`probe`);if(t.kind===`chunked`){let r=t.index.measureCount,i=Math.min(r,e.measures*2),a=e.measures>=r?r:i+mt(t.index,i);return $(n,m(await zt(t,0,a,e.view),e.view),e.options),{svg:Yt(n,1,e.channel),pageCount:n.getPageCount(),measures:a}}let{info:r}=t,i=await Rt(t,e.view),a=e.measures>=r.measureIds.length?r.measureIds.length:Ut(i,e.measures,r.measureIds.length);return $(n,m(i,e.view,a),e.options),{svg:Yt(n,1,e.channel),pageCount:n.getPageCount(),measures:a}}if(t.kind===`whole`){let n=await Ht([e.revision],e.view,e.options,async()=>m(await Rt(t,e.view),e.view)),r=n.getPageCount();return{pageCount:r,pages:e.pages.filter(e=>e>=1&&e<=r).map(t=>({page:t,svg:Yt(n,t,e.channel)}))}}let n=e.view.breakEvery,r=n>0?Math.ceil(t.index.measureCount/n):1,i=/* @__PURE__ */ new Map;for(let a of e.pages){if(a<1||a>r)continue;let o=ht(t.index,a-1,n,Xt(t.info,e.view),e.chunkBudget),s=`${o.from}-${o.to}`;(i.get(s)??i.set(s,{plan:o,pages:[]}).get(s)).pages.push(a)}let a=[];for(let{plan:n,pages:r}of i.values()){let i=await Ht([e.revision,n.from,n.to],e.view,e.options,async()=>m(await zt(t,n.from,n.to,e.view),e.view,1/0,n.from)),o=i.getPageCount();for(let t of r){let r=n.firstPage+(t-1-n.firstSystem);if(r>o)throw Error(`A score chunk laid out ${o} pages where ${r} were expected.`);a.push({page:t,svg:Yt(i,r,e.channel)})}}return{pageCount:r,pages:a}}function Qt(e){if(e instanceof Dt)return{message:e.message,code:e.code};let t=e instanceof Error?`${e.name}: ${e.message}`:String(e),n=globalThis.WebAssembly?.Exception;return n&&e instanceof n||/out of memory|OOM|Cannot enlarge memory|allocation failed|RangeError/i.test(t)?{message:`This score is too large for the notation renderer on this device (it ran out of memory).`,code:`oom`}:{message:e instanceof Error?e.message:String(e)}}function $t(e){let t=Et.splice(0).join(``);try{t+=(wt??Tt)?.getLog()||``}catch{}if(!t)return;let n=t.split(`
6
+ `).filter(Boolean),r=n.filter(e=>e.startsWith(`[Error]`)).length;console.warn(`Verovio ${e}: ${n.length} log message${n.length===1?``:`s`} (${r} error${r===1?``:`s`})${n.length>12?`, first 12`:``}:\n${n.slice(0,12).join(`
7
+ `)}`)}const en=[],tn=/* @__PURE__ */ new Map;let nn=!1;const rn=e=>self.postMessage(e);async function an(){let e=en.shift();if(!e){nn=!1;return}if(e.kind!==`import`&&e.kind!==`release`&&e.ticket<(tn.get(e.channel)??0))rn({id:e.id,error:`Superseded score render.`,code:`superseded`});else try{let t=await Zt(e);$t(e.kind),rn({id:e.id,value:t,heap:At()})}catch(t){$t(e.kind);let{message:n,code:r}=Qt(t);r!==`missing`&&Ot(r===`oom`||!(t instanceof Error&&t.message===`Verovio could not import this score.`)),rn({id:e.id,error:n,code:r,heap:At()})}setTimeout(()=>void an(),0)}self.onmessage=e=>{let t=e.data;if(t.kind===`configure`){_t=t.files;return}(t.kind===`probe`||t.kind===`render`)&&tn.set(t.channel,Math.max(tn.get(t.channel)??0,t.ticket)),en.push(t),nn||(nn=!0,setTimeout(()=>void an(),0))};
@@ -0,0 +1,24 @@
1
+ /**
2
+ * pepperscore/audio: the reader's audio engine as a small, framework-free API (no React), so other apps on the page
3
+ * (a piano visualiser, a practice tool) share one AudioContext, one "who is playing" slot and the same sounds.
4
+ *
5
+ * - getSharedAudio(): the page's AudioContext and master compressor (null without Web Audio). resumeAudio(context)
6
+ * resumes it with a bounded wait (call it from a user gesture).
7
+ * - claimPlayback(owner) / releasePlayback(owner): one player at a time. Claiming stops the previous owner (a
8
+ * PepperScore reader, or your own `{ stop() }`); PepperScore claims it when it starts playing.
9
+ * - loadInstrument(program | name | 'drums', options) / loadDrumKit(options): an AudioPlayer through pepperscore's sound
10
+ * resolution (soundSources, the pack's FluidR3 sound, TimGM6mb.sf2; drums from Perfect Drums plus TimGM6mb's kit).
11
+ * - createMetronome({ voice: 'woodblock' | 'drum-machine' | 'click', gain }).
12
+ *
13
+ * Everything not exported here is internal.
14
+ */
15
+ export { getSharedAudio, resumeAudio, claimPlayback, releasePlayback } from './lib/audio-engine';
16
+ export type { SharedAudio, PlaybackOwner } from './lib/audio-engine';
17
+ export { loadInstrument, loadDrumKit, createMetronome } from './lib/instruments';
18
+ export type { Instrument, InstrumentName, InstrumentPlan, InstrumentOptions, Metronome, MetronomeOptions } from './lib/instruments';
19
+ export { METRONOME_VOICES } from './lib/metronome';
20
+ export type { MetronomeVoice } from './lib/metronome';
21
+ export type { AudioPlayer } from './lib/sound-players';
22
+ export type { SoundSource, SoundPlan } from './lib/sounds';
23
+ export type { SoundPackName } from './lib/assets';
24
+ export { SOUNDS_VERSION, defaultAssetBaseUrl } from './lib/assets';
package/dist/audio.js ADDED
@@ -0,0 +1,198 @@
1
+ import { a as e, c as t, d as n, f as r, g as i, l as a, m as o, n as s, o as c, p as l, r as u, s as d, t as f } from "./sound-players-DdLBBZaR.js";
2
+ //#region src/lib/metronome.ts
3
+ var p = [
4
+ "woodblock",
5
+ "drum-machine",
6
+ "click"
7
+ ], m = 112, h = 78, g = (e) => e === "woodblock" ? [76, 77] : e === "drum-machine" ? [36, 42] : [];
8
+ function _(e, t, { accent: n = t === 0, covers: r } = {}) {
9
+ let i = n ? m : h;
10
+ if (e === "woodblock") {
11
+ let e = n ? 76 : 77;
12
+ return r?.(e) ? [{
13
+ kind: "note",
14
+ note: e,
15
+ velocity: i
16
+ }] : [{
17
+ kind: "knock",
18
+ accent: n
19
+ }];
20
+ }
21
+ if (e === "drum-machine") {
22
+ let e = n ? 36 : 42;
23
+ return r?.(e) ? [{
24
+ kind: "note",
25
+ note: e,
26
+ velocity: i
27
+ }] : [{
28
+ kind: "tick",
29
+ accent: n
30
+ }];
31
+ }
32
+ return [{
33
+ kind: "tick",
34
+ accent: n
35
+ }];
36
+ }
37
+ //#endregion
38
+ //#region src/lib/instruments.ts
39
+ var v = Array.from({ length: 88 }, (e, t) => 21 + t), y = () => typeof document < "u" && document.baseURI || "http://localhost/";
40
+ function b(e) {
41
+ if (e === "drums" || e === "drum-kit") return { drums: !0 };
42
+ let t = typeof e == "number" ? Number.isInteger(e) ? i[e - 1] : void 0 : i.find((t) => t.soundfont === e);
43
+ if (!t) throw Error(`pepperscore/audio: unknown instrument ${JSON.stringify(e)} (use a GM program 1-128, a FluidR3 name or 'drums').`);
44
+ return {
45
+ drums: !1,
46
+ program: t.program,
47
+ name: t.soundfont
48
+ };
49
+ }
50
+ function x(e) {
51
+ if (e.context) return {
52
+ context: e.context,
53
+ destination: e.destination ?? e.context.destination
54
+ };
55
+ let t = r();
56
+ if (!t) throw Error("pepperscore/audio: Web Audio is not available on this device.");
57
+ return {
58
+ context: t.context,
59
+ destination: e.destination ?? t.master
60
+ };
61
+ }
62
+ async function S(n, r = {}) {
63
+ let i = b(n), { context: o, destination: c } = x(r), l = a(r.assetBaseUrl, r.soundPack ?? "core"), d = await t(l), p = e(i, {
64
+ sources: r.sources,
65
+ fluidr3: d.fluidr3,
66
+ base: l,
67
+ page: y()
68
+ }), m = o.createGain();
69
+ m.connect(c);
70
+ let h;
71
+ try {
72
+ h = await s(o, p, m);
73
+ } catch (e) {
74
+ throw m.disconnect(), e;
75
+ }
76
+ let g = !1, _ = Promise.resolve(), S = async (e) => {
77
+ if (await Promise.all(h.map((t) => t.loadNotes?.(e))), p.kind === "note-files" && p.drums) {
78
+ let t = _.then(async () => {
79
+ if (g) return;
80
+ let t = h, n = t.length;
81
+ await f(o, t, e, u(l), m), g && t.slice(n).forEach((e) => e.dispose());
82
+ });
83
+ _ = t.catch(() => {}), await t;
84
+ }
85
+ }, C = {
86
+ context: o,
87
+ output: m,
88
+ plan: {
89
+ kind: p.kind,
90
+ sourceId: p.sourceId
91
+ },
92
+ loadNotes: S,
93
+ covers: (e) => h.some((t) => t.covers?.(e) ?? !0),
94
+ start: (e) => {
95
+ let t = [];
96
+ for (let n of h) try {
97
+ t.push(n.start({
98
+ ...e,
99
+ destination: e.destination ?? m
100
+ }));
101
+ } catch {}
102
+ return () => t.forEach((e) => e());
103
+ },
104
+ stop: () => h.forEach((e) => e.stop()),
105
+ dispose: () => {
106
+ g = !0, h.forEach((e) => e.dispose()), h = [], m.disconnect();
107
+ }
108
+ };
109
+ try {
110
+ await S(r.notes ?? (i.drums ? [] : v));
111
+ } catch (e) {
112
+ throw C.dispose(), e;
113
+ }
114
+ return C;
115
+ }
116
+ var C = (e = {}) => S("drums", e), w = 1e4, T = {
117
+ knock: {
118
+ frequency: [740, 1040],
119
+ drop: .6,
120
+ decay: .07,
121
+ level: [.5, .7],
122
+ type: "triangle"
123
+ },
124
+ tick: {
125
+ frequency: [1800, 2400],
126
+ drop: 1,
127
+ decay: .025,
128
+ level: [.18, .28],
129
+ type: "sine"
130
+ }
131
+ };
132
+ async function E(e = {}) {
133
+ let { context: t, destination: n } = x(e), r = t.createGain();
134
+ r.gain.value = Math.max(0, Math.min(1, e.gain ?? .5)), r.connect(n);
135
+ let i = e.voice ?? "woodblock", a = null, o = null, s = !1, c = -Infinity, l = /* @__PURE__ */ new Set(), u = /* @__PURE__ */ new Set(), d = () => o ??= C({
136
+ ...e,
137
+ context: t,
138
+ destination: r
139
+ }).then((e) => {
140
+ if (s) throw e.dispose(), Error("the metronome was disposed");
141
+ return a = e, e;
142
+ }, (e) => {
143
+ throw o = null, e;
144
+ }), f = async (e) => {
145
+ i = e;
146
+ let t = g(e);
147
+ if (!(!t.length || s || l.has(e))) try {
148
+ await (await d()).loadNotes(t), s || l.add(e);
149
+ } catch (e) {
150
+ if (s) return;
151
+ c = Date.now(), console.warn(`pepperscore/audio: the metronome's drum sounds could not load (${e instanceof Error ? e.message : String(e)}); using synthesized sounds.`);
152
+ }
153
+ }, p = f(i), m = (e, n, i) => {
154
+ let a = T[e], o = +!!n, s = t.createOscillator(), c = t.createGain();
155
+ return s.type = a.type, s.frequency.setValueAtTime(a.frequency[o], i), s.frequency.exponentialRampToValueAtTime(a.frequency[o] * a.drop, i + a.decay), c.gain.setValueAtTime(0, i), c.gain.linearRampToValueAtTime(a.level[o], i + .002), c.gain.exponentialRampToValueAtTime(1e-4, i + a.decay), s.connect(c).connect(r), s.onended = () => {
156
+ u.delete(s), s.disconnect(), c.disconnect();
157
+ }, u.add(s), s.start(i), s.stop(i + a.decay + .01), () => {
158
+ if (u.has(s)) try {
159
+ s.stop();
160
+ } catch {}
161
+ };
162
+ }, h = () => {
163
+ a?.stop();
164
+ for (let e of [...u]) try {
165
+ e.stop();
166
+ } catch {}
167
+ };
168
+ return {
169
+ get voice() {
170
+ return i;
171
+ },
172
+ output: r,
173
+ ready: p,
174
+ setVoice: f,
175
+ tick: ({ time: e, beat: n, accent: r }) => {
176
+ let u = Math.max(e, t.currentTime);
177
+ !s && !o && !l.has(i) && g(i).length && Date.now() - c > w && f(i);
178
+ let d = a && l.has(i) ? a : null, p = _(i, n, {
179
+ accent: r,
180
+ covers: d ? (e) => d.covers(e) : void 0
181
+ }).map((e) => e.kind === "note" ? d.start({
182
+ note: e.note,
183
+ time: u,
184
+ duration: .5,
185
+ velocity: e.velocity
186
+ }) : m(e.kind, e.accent, u));
187
+ return () => p.forEach((e) => e());
188
+ },
189
+ stop: h,
190
+ dispose: () => {
191
+ s = !0, h(), a?.dispose(), a = null, o = null, r.disconnect();
192
+ }
193
+ };
194
+ }
195
+ //#endregion
196
+ export { p as METRONOME_VOICES, c as SOUNDS_VERSION, n as claimPlayback, E as createMetronome, d as defaultAssetBaseUrl, r as getSharedAudio, C as loadDrumKit, S as loadInstrument, l as releasePlayback, o as resumeAudio };
197
+
198
+ //# sourceMappingURL=audio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio.js","names":["planSound","loadPackInfo","claimPlayback","getSharedAudio","programs","resolveAssetBase","resumeAudio","loadPlayers","SOUNDS_VERSION","releasePlayback","fallbackSf2Url","defaultAssetBaseUrl","addDrumFallback","METRONOME_VOICES","ACCENT_VELOCITY","BEAT_VELOCITY","metronomeNotes","voice","metronomeHits","beat","velocity","accent","note","covers","PIANO_RANGE","i","pageBase","instrumentRequest","sound","entry","item","audioTarget","options","shared","loadInstrument","request","base","pack","plan","output","context","destination","players","error","disposed","fallbackQueue","loadNotes","player","notes","step","current","before","instrument","stops","stop","loadDrumKit","RETRY_AFTER_MS","SYNTH","createMetronome","kit","kitLoad","failedAt","loaded","synths","ensureKit","loadedKit","setVoice","next","ready","synth","spec","kind","osc","env","time","at","drums","hit"],"sources":["../src/lib/metronome.ts","../src/lib/instruments.ts"],"sourcesContent":["/**\n * What a metronome beat sounds like, per voice (public through pepperscore/audio's createMetronome). Pure: no Web Audio\n * and no runtime imports (validation/audio-api.mjs runs it in Node).\n * - woodblock: GM hi wood block (76) on beat 1, low wood block (77) on the others, when the drum kit has them; else a\n * soft synthesized knock.\n * - drum-machine: kick (36) on beat 1, closed hi-hat (42) on the others, from the drum kit.\n * - click: a soft, short synthesized tick.\n * Beat 1 (`beat` 0) is accented: a louder note, or a higher, louder synth sound.\n */\nexport type MetronomeVoice = 'woodblock' | 'drum-machine' | 'click';\nexport const METRONOME_VOICES: readonly MetronomeVoice[] = ['woodblock', 'drum-machine', 'click'];\n\nexport type MetronomeHit =\n | { kind: 'note'; note: number; velocity: number }\n | { kind: 'knock' | 'tick'; accent: boolean };\n\nexport const WOODBLOCK_HIGH = 76;\nexport const WOODBLOCK_LOW = 77;\nexport const KICK = 36;\nexport const CLOSED_HAT = 42;\nconst ACCENT_VELOCITY = 112;\nconst BEAT_VELOCITY = 78;\n\n/** Drum notes a voice plays (loaded up front); the synthesized click needs none. */\nexport const metronomeNotes = (voice: MetronomeVoice): number[] =>\n voice === 'woodblock' ? [WOODBLOCK_HIGH, WOODBLOCK_LOW] : voice === 'drum-machine' ? [KICK, CLOSED_HAT] : [];\n\n/**\n * The hits for one beat. `beat` counts from 0 (beat 1 of the bar) and `accent` defaults to `beat === 0`. `kit` says\n * whether the drum kit loaded and which notes it plays; without it, sample voices fall back to synthesized sounds.\n */\nexport function metronomeHits(voice: MetronomeVoice, beat: number, { accent = beat === 0, covers }: { accent?: boolean; covers?: (note: number) => boolean } = {}): MetronomeHit[] {\n const velocity = accent ? ACCENT_VELOCITY : BEAT_VELOCITY;\n if (voice === 'woodblock') {\n const note = accent ? WOODBLOCK_HIGH : WOODBLOCK_LOW;\n return covers?.(note) ? [{ kind: 'note', note, velocity }] : [{ kind: 'knock', accent }];\n }\n if (voice === 'drum-machine') {\n const note = accent ? KICK : CLOSED_HAT;\n return covers?.(note) ? [{ kind: 'note', note, velocity }] : [{ kind: 'tick', accent }];\n }\n return [{ kind: 'tick', accent }];\n}\n","/**\n * Instruments and the metronome for pepperscore/audio (src/audio.ts). Built on the reader's own sound code: the same\n * shared AudioContext (audio-engine), sound resolution (sounds.ts planSound: soundSources, then the pack's FluidR3\n * sound, then TimGM6mb.sf2; drums from Perfect Drums with TimGM6mb's kit for missing notes) and players. Every built-in\n * file is fetched from the asset base, so a page that self-hosts the sounds talks to no other host.\n */\nimport { programs } from './gm-soundfont-manifest.json';\nimport { getSharedAudio } from './audio-engine';\nimport { loadPackInfo, resolveAssetBase, type SoundPackName } from './assets';\nimport { addDrumFallback, loadPlayers, type AudioPlayer } from './sound-players';\nimport { fallbackSf2Url, planSound, type SoundPlan, type SoundRequest, type SoundSource } from './sounds';\nimport { metronomeHits, metronomeNotes, type MetronomeVoice } from './metronome';\n\nexport type InstrumentOptions = {\n /** Root of a pepperscore-sounds-<pack> layout (relative to the page); default: the jsDelivr copy of pepperscore-sounds-<soundPack>. */\n assetBaseUrl?: string;\n /** Picks the default assetBaseUrl. With your own assetBaseUrl, its pack.json decides which FluidR3 sounds exist. */\n soundPack?: SoundPackName;\n /** Your own sounds, claimed per GM program or for the drum kit (the PepperScore `soundSources` prop). */\n sources?: readonly SoundSource[];\n /** Default: the page's shared AudioContext (getSharedAudio). */\n context?: AudioContext;\n /** Where the instrument's output goes. Default: the shared master compressor (or `context.destination` for your own context). */\n destination?: AudioNode;\n /** Notes to load before the promise resolves. Default: 21-108 for an instrument, none for the drum kit. */\n notes?: number[];\n};\n\n/** The public view of an instrument's sound plan. */\nexport type InstrumentPlan = { readonly kind: SoundPlan['kind']; readonly sourceId: string };\n\n/** A loaded sound: an AudioPlayer plus its output gain (volume) and the plan it came from. */\nexport type Instrument = AudioPlayer & {\n readonly context: AudioContext;\n /** The instrument's volume; connected to `destination`. */\n readonly output: GainNode;\n /** Which kind of source plays it and its id (for example `'builtin:fluidr3'`). Read-only; the plan's URLs and presets are internal. */\n readonly plan: InstrumentPlan;\n /** Load (decode) these notes; a note starts silently until it is loaded. Drums load TimGM6mb's kit for notes the kit lacks. */\n loadNotes(notes: number[]): Promise<void>;\n /** Whether a loaded player can sound this note. */\n covers(note: number): boolean;\n};\n\n/** A GM program (1-128), a FluidR3 sound name (`'acoustic_grand_piano'`), or `'drums'` for the GM drum kit (`'drum-kit'`, the score part id, is accepted as an alias). */\nexport type InstrumentName = number | string;\n\nconst PIANO_RANGE = Array.from({ length: 88 }, (_, i) => 21 + i);\nconst pageBase = (): string => (typeof document !== 'undefined' && document.baseURI) || 'http://localhost/';\n\n/** The sound request for a program number, a FluidR3 name or 'drums'/'drum-kit'. */\nexport function instrumentRequest(sound: InstrumentName): SoundRequest {\n if (sound === 'drums' || sound === 'drum-kit') return { drums: true };\n const entry = typeof sound === 'number' ? (Number.isInteger(sound) ? programs[sound - 1] : undefined) : programs.find(item => item.soundfont === sound);\n if (!entry) throw new Error(`pepperscore/audio: unknown instrument ${JSON.stringify(sound)} (use a GM program 1-128, a FluidR3 name or 'drums').`);\n return { drums: false, program: entry.program, name: entry.soundfont };\n}\n\nfunction audioTarget(options: { context?: AudioContext; destination?: AudioNode }): { context: AudioContext; destination: AudioNode } {\n if (options.context) return { context: options.context, destination: options.destination ?? options.context.destination };\n const shared = getSharedAudio();\n if (!shared) throw new Error('pepperscore/audio: Web Audio is not available on this device.');\n return { context: shared.context, destination: options.destination ?? shared.master };\n}\n\n/**\n * Load an instrument through pepperscore's sound resolution. `start()` returns a stop function for that one note;\n * `stop()` stops every sounding note and cancels every scheduled one. A note's `destination` is honoured by sample-pack\n * and note-file sounds; SF2 sounds always play through `output`.\n */\nexport async function loadInstrument(sound: InstrumentName, options: InstrumentOptions = {}): Promise<Instrument> {\n const request = instrumentRequest(sound);\n const { context, destination } = audioTarget(options);\n const base = resolveAssetBase(options.assetBaseUrl, options.soundPack ?? 'core');\n const pack = await loadPackInfo(base);\n const plan = planSound(request, { sources: options.sources, fluidr3: pack.fluidr3, base, page: pageBase() });\n const output = context.createGain();\n output.connect(destination);\n let players: AudioPlayer[];\n try { players = await loadPlayers(context, plan, output); } catch (error) { output.disconnect(); throw error; }\n let disposed = false;\n // The drum kit's TimGM6mb fallback loads one at a time (two overlapping loadNotes calls would each fetch the 6 MB SF2),\n // and a player that arrives after dispose() is released at once instead of leaking into the old player list.\n let fallbackQueue: Promise<void> = Promise.resolve();\n const loadNotes = async (notes: number[]) => {\n await Promise.all(players.map(player => player.loadNotes?.(notes)));\n if (plan.kind === 'note-files' && plan.drums) {\n const step = fallbackQueue.then(async () => {\n if (disposed) return;\n const current = players, before = current.length;\n await addDrumFallback(context, current, notes, fallbackSf2Url(base), output);\n if (disposed) current.slice(before).forEach(player => player.dispose());\n });\n fallbackQueue = step.catch(() => {});\n await step;\n }\n };\n const instrument: Instrument = {\n context, output, plan: { kind: plan.kind, sourceId: plan.sourceId }, loadNotes,\n covers: note => players.some(player => player.covers?.(note) ?? true),\n start: options => {\n const stops: Array<() => void> = [];\n for (const player of players) {\n // A sample-pack player throws for a note it has not loaded; that note is silent rather than an error mid-schedule.\n try { stops.push(player.start({ ...options, destination: options.destination ?? output })); } catch { /* not loaded */ }\n }\n return () => stops.forEach(stop => stop());\n },\n stop: () => players.forEach(player => player.stop()),\n dispose: () => { disposed = true; players.forEach(player => player.dispose()); players = []; output.disconnect(); },\n };\n try { await loadNotes(options.notes ?? (request.drums ? [] : PIANO_RANGE)); } catch (error) { instrument.dispose(); throw error; }\n return instrument;\n}\n\n/** The GM drum kit (`loadInstrument('drums', options)`): Perfect Drums note files, TimGM6mb's kit for notes they lack. */\nexport const loadDrumKit = (options: InstrumentOptions = {}): Promise<Instrument> => loadInstrument('drums', options);\n\nexport type MetronomeOptions = Omit<InstrumentOptions, 'notes'> & {\n /** Default 'woodblock'. */\n voice?: MetronomeVoice;\n /** Output volume, 0-1. Default 0.5 (gentle). */\n gain?: number;\n};\n\nexport type Metronome = {\n readonly voice: MetronomeVoice;\n readonly output: GainNode;\n /**\n * Schedule one beat at `time` (AudioContext seconds). `beat` counts from 0 within the bar; beat 0 is accented unless\n * `accent` says otherwise. Returns a stop function for that beat.\n */\n tick(options: { time: number; beat: number; accent?: boolean }): () => void;\n /**\n * Resolves once the drum kit and the notes of the voice given to `createMetronome` have loaded (or failed: then the\n * synthesized sounds keep playing). `createMetronome` itself does not wait for it.\n */\n readonly ready: Promise<void>;\n /** Switch voice; resolves when the drum kit notes the voice needs have loaded. Until then the voice plays its synthesized sound. A failed load is retried by the next call. */\n setVoice(voice: MetronomeVoice): Promise<void>;\n /** Stop every sounding and scheduled beat. */\n stop(): void;\n dispose(): void;\n};\n\n/** After a failed drum load, ticks retry in the background no sooner than this. */\nconst RETRY_AFTER_MS = 10_000;\n\nconst SYNTH = {\n knock: { frequency: [740, 1040], drop: .6, decay: .07, level: [.5, .7], type: 'triangle' },\n tick: { frequency: [1800, 2400], drop: 1, decay: .025, level: [.18, .28], type: 'sine' },\n} as const;\n\n/**\n * A metronome on the shared AudioContext; drum voices come from the same drum kit loadDrumKit plays. Resolves at once:\n * the drum kit (a few MB for the woodblock's TimGM6mb kit) loads in the background, and beats play the synthesized\n * sound until it arrives (`await metronome.ready` to wait).\n */\nexport async function createMetronome(options: MetronomeOptions = {}): Promise<Metronome> {\n const { context, destination } = audioTarget(options);\n const output = context.createGain();\n output.gain.value = Math.max(0, Math.min(1, options.gain ?? .5));\n output.connect(destination);\n let voice: MetronomeVoice = options.voice ?? 'woodblock';\n let kit: Instrument | null = null;\n let kitLoad: Promise<Instrument> | null = null;\n let disposed = false;\n let failedAt = -Infinity;\n /** Voices whose kit notes are loaded; a voice plays its synthesized sound until then. */\n const loaded = new Set<MetronomeVoice>();\n const synths = new Set<OscillatorNode>();\n // The drum kit loads once however many setVoice calls overlap (they share the in-flight promise), a kit that arrives\n // after dispose() is released, and a failed load is not remembered: the next setVoice (or, after a pause, tick) retries.\n const ensureKit = (): Promise<Instrument> => kitLoad ??= loadDrumKit({ ...options, context, destination: output }).then(\n loadedKit => {\n if (disposed) { loadedKit.dispose(); throw new Error('the metronome was disposed'); }\n kit = loadedKit;\n return loadedKit;\n },\n error => { kitLoad = null; throw error; });\n const setVoice = async (next: MetronomeVoice) => {\n voice = next;\n const notes = metronomeNotes(next);\n if (!notes.length || disposed || loaded.has(next)) return;\n try {\n const drums = await ensureKit();\n await drums.loadNotes(notes);\n if (!disposed) loaded.add(next);\n } catch (error) {\n if (disposed) return;\n // No drum kit at the asset base (or the fetch failed): the sample voices play synthesized sounds, and a later retry is allowed.\n failedAt = Date.now();\n console.warn(`pepperscore/audio: the metronome's drum sounds could not load (${error instanceof Error ? error.message : String(error)}); using synthesized sounds.`);\n }\n };\n const ready = setVoice(voice);\n const synth = (kind: 'knock' | 'tick', accent: boolean, time: number) => {\n const spec = SYNTH[kind], i = accent ? 1 : 0;\n const osc = context.createOscillator(), env = context.createGain();\n osc.type = spec.type;\n osc.frequency.setValueAtTime(spec.frequency[i], time);\n osc.frequency.exponentialRampToValueAtTime(spec.frequency[i] * spec.drop, time + spec.decay);\n env.gain.setValueAtTime(0, time);\n env.gain.linearRampToValueAtTime(spec.level[i], time + .002);\n env.gain.exponentialRampToValueAtTime(.0001, time + spec.decay);\n osc.connect(env).connect(output);\n osc.onended = () => { synths.delete(osc); osc.disconnect(); env.disconnect(); };\n synths.add(osc);\n osc.start(time);\n osc.stop(time + spec.decay + .01);\n return () => { if (synths.has(osc)) try { osc.stop(); } catch { /* ended */ } };\n };\n const stop = () => { kit?.stop(); for (const osc of [...synths]) try { osc.stop(); } catch { /* ended */ } };\n return {\n get voice() { return voice; },\n output,\n ready,\n setVoice,\n tick: ({ time, beat, accent }) => {\n const at = Math.max(time, context.currentTime);\n // A drum voice whose kit failed to load tries again, at most once per RETRY_AFTER_MS, while ticks keep sounding synthesized.\n if (!disposed && !kitLoad && !loaded.has(voice) && metronomeNotes(voice).length && Date.now() - failedAt > RETRY_AFTER_MS) void setVoice(voice);\n const drums = kit && loaded.has(voice) ? kit : null;\n const stops = metronomeHits(voice, beat, { accent, covers: drums ? note => drums.covers(note) : undefined }).map(hit =>\n hit.kind === 'note' ? drums!.start({ note: hit.note, time: at, duration: .5, velocity: hit.velocity }) : synth(hit.kind, hit.accent, at));\n return () => stops.forEach(stop => stop());\n },\n stop,\n dispose: () => { disposed = true; stop(); kit?.dispose(); kit = null; kitLoad = null; output.disconnect(); },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { type InstrumentId, type RangeLevel } from '../lib/instrument-model';
2
+ export declare const LEVEL_NAMES: Record<RangeLevel, string>;
3
+ export type InstrumentChooserProps = {
4
+ instruments: readonly InstrumentId[];
5
+ /** The instrument shown; undefined = as written. */
6
+ current: InstrumentId | undefined;
7
+ level: RangeLevel;
8
+ autoRange: boolean;
9
+ onInstrument(id: InstrumentId | undefined): void;
10
+ onLevel(level: RangeLevel): void;
11
+ onAutoRange(on: boolean): void;
12
+ /** Smaller options in a list (the embed switcher). */
13
+ compact?: boolean;
14
+ /** The "As written" option's icon (the part's own instrument); a note glyph when absent. */
15
+ asWrittenIcon?: string;
16
+ };
17
+ export default function InstrumentChooser({ instruments, current, level, autoRange, onInstrument, onLevel, onAutoRange, compact, asWrittenIcon }: InstrumentChooserProps): import("react").JSX.Element;
@@ -0,0 +1,21 @@
1
+ /** What is selected: the number of notes, the staff they are on and how many are outside the range; null for nothing yet. */
2
+ export type OctaveToolSelection = {
3
+ count: number;
4
+ partName: string;
5
+ outOfRange?: number;
6
+ } | null;
7
+ export type OctaveToolProps = {
8
+ selection: OctaveToolSelection;
9
+ /** Whether there are octave moves Reset would clear (the selection's staff, else any). */
10
+ canReset?: boolean;
11
+ onUp: () => void;
12
+ onDown: () => void;
13
+ onPhrase: () => void;
14
+ onReset: () => void;
15
+ onDone: () => void;
16
+ };
17
+ /**
18
+ * A group of labelled buttons; Escape (handled by the reader's root) leaves the tool like Done. Unavailable buttons are
19
+ * aria-disabled, not disabled, so a button that becomes unavailable when pressed (Reset) keeps the focus.
20
+ */
21
+ export default function OctaveTool({ selection, canReset, onUp, onDown, onPhrase, onReset, onDone }: OctaveToolProps): import("react").JSX.Element;
@@ -7,12 +7,75 @@ import type { ExternalClock } from '../lib/clock';
7
7
  export type PepperScoreReadyInfo = {
8
8
  title: string;
9
9
  composer?: string;
10
+ /**
11
+ * One entry per listed staff (a grand staff lists each staff; a TAB staff doubling a part is not listed). `sourcePart`
12
+ * is the 1-based source part number (a grand staff's staves share one), `switchable` whether the instrument switch
13
+ * applies to it. `settings.instruments` takes either `String(sourcePart)` or `id` as a key.
14
+ */
10
15
  parts: Array<{
11
16
  id: string;
12
17
  name: string;
18
+ sourcePart: number;
19
+ switchable: boolean;
13
20
  }>;
14
21
  measures: number;
15
22
  };
23
+ /** What a click on the engraving hit (`onElementClick`). */
24
+ export type PepperScoreClickInfo = {
25
+ /** Viewer note id (data-note-id) when a note or rest was hit. */
26
+ noteId?: string;
27
+ /** Source element id (the MusicXML `id` attribute) of the first pitch of that note, when known. */
28
+ sourceId?: string;
29
+ /** Zero-based measure index, when a measure box was hit. */
30
+ measureIndex?: number;
31
+ /** 0..1 position of the click across the measure's width. */
32
+ fraction?: number;
33
+ /** 1-based index of the nearest visible staff in the system. */
34
+ staff?: number;
35
+ /**
36
+ * When no note was hit: the drawn note or rest in the hit measure, on `staff`, whose notehead is nearest the click
37
+ * across the engraving (its viewer id and MusicXML id). Engraved positions are not proportional to time, so this
38
+ * maps a click in staff space to an event better than `fraction`.
39
+ */
40
+ nearestNoteId?: string;
41
+ nearestSourceId?: string;
42
+ clientX: number;
43
+ clientY: number;
44
+ };
45
+ /** Adds `className` to the drawn notes (`ids`: note or source ids) and measures (`measures`: zero-based indexes); re-applied after every draw. */
46
+ export type PepperScoreHighlight = {
47
+ ids?: string[];
48
+ measures?: number[];
49
+ className: string;
50
+ };
51
+ /** CSS pixels from each edge. */
52
+ export type PepperScoreInsets = {
53
+ top?: number;
54
+ right?: number;
55
+ bottom?: number;
56
+ left?: number;
57
+ };
58
+ /** What `scrollIntoView` reveals: the drawn notes (note or source ids, like `highlights`), else the measure (zero-based). */
59
+ export type PepperScoreScrollTarget = {
60
+ ids?: string[];
61
+ measure?: number;
62
+ };
63
+ export type PepperScoreScrollOptions = {
64
+ /** Keep the target at least this far inside the visible edges (a number for every edge). Default 0. */
65
+ margin?: number | PepperScoreInsets;
66
+ /**
67
+ * When a scroll is needed, go this share (0..1) of the visible extent past the least scroll, in the direction of
68
+ * travel, so what follows is in view too (the target always stays inside the margins). Default 0.
69
+ */
70
+ lead?: number;
71
+ /** Client coordinates the target must also stay inside, e.g. the space between a host's overlays. */
72
+ bounds?: PepperScoreInsets;
73
+ /**
74
+ * A `performance.now()` time: do nothing if the reader has scrolled, wheeled, touched or pressed on the score
75
+ * since then (or a pointer is still down on it), so a reader's own scrolling or click is never overridden.
76
+ */
77
+ interactedSince?: number;
78
+ };
16
79
  export type PepperScoreHandle = {
17
80
  /** Start playback (no-op while playing, when the chrome loads no audio, or with a `clock`). */
18
81
  play(): Promise<void>;
@@ -27,6 +90,17 @@ export type PepperScoreHandle = {
27
90
  seek(seconds: number): void;
28
91
  /** Seconds of the playhead: `clock.now()` with a `clock`, else the self-driven position. */
29
92
  currentTime(): number;
93
+ /** Draw the measure's system if needed and scroll the measure into view. */
94
+ scrollToMeasure(index: number): Promise<void>;
95
+ /** `seek` to the start of a measure (its first performed occurrence). */
96
+ seekToMeasure(index: number): void;
97
+ /**
98
+ * Scroll the least distance (plus `lead`) that brings the target `margin` inside the visible edges; nothing moves
99
+ * when it is already there. Horizontally the notes (else the measure) must show; vertically their whole system
100
+ * (or the notes, when the system is taller than the view). Draws the measure's system if needed. Smooth, unless the
101
+ * user prefers reduced motion. Does nothing while playback follows (it owns the view). Resolves `true` when it scrolled.
102
+ */
103
+ scrollIntoView(target: PepperScoreScrollTarget, options?: PepperScoreScrollOptions): Promise<boolean>;
30
104
  };
31
105
  export type PepperScoreProps = {
32
106
  /** Score sources; the first present wins, in this order. */
@@ -57,6 +131,14 @@ export type PepperScoreProps = {
57
131
  persist?: PersistNamespace;
58
132
  /** Root of a pepperscore-sounds-<pack> layout; default: the jsDelivr copy of pepperscore-sounds-<soundPack>. */
59
133
  assetBaseUrl?: string;
134
+ /**
135
+ * A directory with an interface-compatible Verovio build to engrave with instead of the copy shipped in
136
+ * dist/verovio/, laid out like the verovio npm package's dist/ (`verovio-module.mjs` and `verovio.mjs`), for example
137
+ * `https://cdn.jsdelivr.net/npm/verovio@6.3.0/dist/`. Relative URLs resolve against the page; cross-origin needs CORS.
138
+ * All readers on a page share one Verovio worker: set it before the first score engraves (the latest value wins
139
+ * when the worker next starts).
140
+ */
141
+ verovioBaseUrl?: string;
60
142
  soundPack?: SoundPackName;
61
143
  /** Sounds that replace the built-in ones for the programs (or drum kit) they claim; the first claiming entry wins. */
62
144
  soundSources?: SoundSource[];
@@ -77,8 +159,21 @@ export type PepperScoreProps = {
77
159
  onSeek?(seconds: number): void;
78
160
  /** Self-driven playback time, about 10 times a second while playing. */
79
161
  onTimeUpdate?(seconds: number): void;
162
+ /** Any click on the engraving (every chrome, with or without a clock): the note, measure and staff it hit. */
163
+ onElementClick?(info: PepperScoreClickInfo): void;
164
+ /** Every draw landed (the first paint, a re-layout, an in-place swap), with `highlights` already applied. */
165
+ onRender?(): void;
166
+ /** Classes to add to notes and measures (for a host's selection or cursor; see the `ps-*` classes in styles.css). */
167
+ highlights?: PepperScoreHighlight[];
80
168
  /** Focus the reader on mount so page-turn keys work before any click. */
81
169
  autoFocus?: boolean;
170
+ /**
171
+ * How a new `musicXml` or `abc` replaces a score already on screen. `"reveal"` (default): fade out, show the loading
172
+ * overlay, scroll to the top and fade the new score in. `"none"`: keep the current engraving and scroll position until
173
+ * the new one replaces it in place, with no fade or overlay (for a host that edits the score it shows, like the
174
+ * editor). The first paint, other sources and setting changes (mode, font, transposition) always reveal.
175
+ */
176
+ paintTransition?: 'reveal' | 'none';
82
177
  ref?: React.Ref<PepperScoreHandle>;
83
178
  };
84
- export default function PepperScore({ musicXml, file, scoreUrl, abc, chrome: preset, controls, view, height, className, ariaLabel, settings, persist, assetBaseUrl, soundPack, soundSources, onReady, onPlay, onStop, onError, clock, audio: withAudio, onSeek, onTimeUpdate, autoFocus, ref }: PepperScoreProps): import("react").JSX.Element;
179
+ export default function PepperScore({ musicXml, file, scoreUrl, abc, chrome: preset, controls, view, height, className, ariaLabel, settings, persist, assetBaseUrl, verovioBaseUrl, soundPack, soundSources, onReady, onPlay, onStop, onError, clock, audio: withAudio, onSeek, onTimeUpdate, onElementClick, onRender, highlights, autoFocus, paintTransition, ref }: PepperScoreProps): import("react").JSX.Element;
package/dist/index.d.ts CHANGED
@@ -2,9 +2,10 @@ import PepperScore from './components/PepperScore';
2
2
  import type { PepperScoreProps } from './components/PepperScore';
3
3
  export { PepperScore };
4
4
  export default PepperScore;
5
- export type { PepperScoreProps, PepperScoreHandle, PepperScoreReadyInfo } from './components/PepperScore';
5
+ export type { PepperScoreProps, PepperScoreHandle, PepperScoreReadyInfo, PepperScoreClickInfo, PepperScoreHighlight, PepperScoreInsets, PepperScoreScrollTarget, PepperScoreScrollOptions } from './components/PepperScore';
6
6
  export type { ChromePreset, PepperScoreControls } from './lib/chrome';
7
- export type { PepperScoreSettings } from './lib/prefs';
7
+ export type { PepperScoreSettings, PepperScoreAnnotationSizes, AnnotationSize } from './lib/prefs';
8
+ export type { InstrumentId, RangeLevel, SwitchInstrumentId } from './lib/instrument-model';
8
9
  export type { ExternalClock, ClockEvent } from './lib/clock';
9
10
  export type { SoundSource } from './lib/sounds';
10
11
  export type { SoundPackName } from './lib/assets';