playlist-data-engine 1.6.0 → 1.7.1

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 (33) hide show
  1. package/dist/analysis.js +1 -1
  2. package/dist/analysis.mjs +2 -2
  3. package/dist/arweaveGatewayManager-C9SIMDTd.cjs +1 -0
  4. package/dist/{arweaveGatewayManager-BKUZ1Klm.js → arweaveGatewayManager-DDSO5sLJ.js} +381 -338
  5. package/dist/core/parser/MetadataExtractor.d.ts +57 -3
  6. package/dist/core/parser/MetadataExtractor.d.ts.map +1 -1
  7. package/dist/core/parser/PlaylistParser.d.ts.map +1 -1
  8. package/dist/core/parser/TrackExtras.d.ts +23 -0
  9. package/dist/core/parser/TrackExtras.d.ts.map +1 -1
  10. package/dist/core/types/Playlist.d.ts +4 -1
  11. package/dist/core/types/Playlist.d.ts.map +1 -1
  12. package/dist/gateway-DYTdioNs.js +677 -0
  13. package/dist/gateway-UffqbE1i.cjs +1 -0
  14. package/dist/gateway.d.ts +2 -0
  15. package/dist/gateway.d.ts.map +1 -1
  16. package/dist/gateway.js +1 -1
  17. package/dist/gateway.mjs +18 -315
  18. package/dist/index.d.ts +1 -1
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/playlist-data-engine.js +40 -40
  21. package/dist/playlist-data-engine.mjs +1742 -1973
  22. package/dist/{unifyBeatMap-sIbIw5OX.cjs → unifyBeatMap-DIsNlck4.cjs} +1 -1
  23. package/dist/{unifyBeatMap-BA5EG991.js → unifyBeatMap-k6vw_JPQ.js} +1 -1
  24. package/dist/utils/arweaveGatewayManager.d.ts +18 -3
  25. package/dist/utils/arweaveGatewayManager.d.ts.map +1 -1
  26. package/dist/utils/arweaveUtils.d.ts +29 -0
  27. package/dist/utils/arweaveUtils.d.ts.map +1 -1
  28. package/dist/utils/ipfsUtils.d.ts +7 -0
  29. package/dist/utils/ipfsUtils.d.ts.map +1 -1
  30. package/dist/utils/playlistUtils.d.ts +2 -0
  31. package/dist/utils/playlistUtils.d.ts.map +1 -1
  32. package/package.json +34 -31
  33. package/dist/arweaveGatewayManager-CeW9SP2P.cjs +0 -1
@@ -1,4 +1,4 @@
1
- "use strict";const mt=require("./arweaveGatewayManager-CeW9SP2P.cjs"),Dt={beatsPerMeasure:4},Z={segments:[{startBeat:0,downbeatBeatIndex:0,timeSignature:Dt}]},st=2,at=12;function ft(h){if(!h.segments||h.segments.length===0)throw new Error("DownbeatConfig must have at least one segment");for(const t of h.segments){if(t.startBeat<0)throw new Error(`startBeat must be non-negative, got ${t.startBeat}`);if(t.downbeatBeatIndex<0)throw new Error(`downbeatBeatIndex must be non-negative, got ${t.downbeatBeatIndex}`);const{beatsPerMeasure:e}=t.timeSignature;if(e<st||e>at)throw new Error(`beatsPerMeasure must be between ${st} and ${at}, got ${e}`)}for(let t=1;t<h.segments.length;t++)if(h.segments[t].startBeat<=h.segments[t-1].startBeat)throw new Error("Segments must be ordered by startBeat in ascending order")}function gt(h,t){for(const e of h.segments)if(e.downbeatBeatIndex>=t)throw new Error(`downbeatBeatIndex ${e.downbeatBeatIndex} exceeds total beats ${t}`)}function Ce(h,t){ft(t),gt(t,h.beats.length);const e=Re(t.segments,h.beats.length),n=h.beats.map((i,s)=>{const a=De(t.segments,s),o=t.segments[a],{downbeatBeatIndex:r,timeSignature:c}=o,{beatsPerMeasure:l}=c,d=s-r,u=(d%l+l)%l,m=u===0,g=Math.max(0,Math.floor(d/l))+e[a];return{...i,beatInMeasure:u,isDownbeat:m,measureNumber:g}});return{...h,beats:n,downbeatConfig:t}}function Re(h,t){const e=[];for(let n=0;n<h.length;n++)if(n===0)e.push(0);else{const i=h[n-1],{downbeatBeatIndex:s,timeSignature:a}=i,o=a.beatsPerMeasure,c=h[n].startBeat-1-s,l=Math.max(0,Math.floor(c/o));e.push(l+1)}return e}function De(h,t){let e=0;for(let n=0;n<h.length&&h[n].startBeat<=t;n++)e=n;return e}const Et={perfect:.03,great:.05,good:.1,ok:.2},zt={perfect:.02,great:.035,good:.075,ok:.125},pt={perfect:.01,great:.025,good:.05,ok:.1},rt={efficient:10,standard:4,hq:2},Ft={standard:40,detailed:64,maximum:80},Nt={minimal:10,standard:20,smooth:40};function yt(h={mode:"standard"}){if(h.mode==="custom"){const t=h.customValue??rt.standard;return Math.max(1,Math.min(50,t))}return rt[h.mode]}function bt(h={mode:"standard"}){return Ft[h.mode]}function Mt(h={mode:"standard"}){return Nt[h.mode]}const V={minBpm:90,maxBpm:180,sensitivity:1,filter:0,noiseFloorThreshold:0,hopSizeMs:4,fftSize:2048,rollingBpmWindowSize:8,dpAlpha:680,melBands:40,highPassCutoff:.4,gaussianSmoothMs:20,tempoCenter:.5,tempoWidth:1.4,useOctaveResolution:!1,useTripleMeter:!1,hopSizeMode:{mode:"standard"},melBandsMode:{mode:"standard"},gaussianSmoothMode:{mode:"standard"}},Ot={anticipationTime:2,userOffsetMs:0,compensateOutputLatency:!0,timingTolerance:.01,difficultyPreset:"medium",customThresholds:{},useInterpolatedBeats:!1,ignoreKeyRequirements:!1},Ee=pt;function ot(h){switch(h){case"easy":return Et;case"medium":return zt;default:return pt}}const kt={minAnchorConfidence:.3,gridSnapTolerance:.05,tempoAdaptationRate:.3,extrapolateStart:!0,extrapolateEnd:!0,anomalyThreshold:.4,denseSectionMinBeats:3,gridAlignmentWeight:.5,anchorConfidenceWeight:.3,paceConfidenceWeight:.2,tempoSectionThreshold:.1,minClusterBeats:4,enableMultiTempo:!1};function ze(h){const t=[],e=["perfect","great","good","ok"];for(const i of e)if(i in h){const s=h[i];s==null?t.push(`${i} is undefined or null`):typeof s!="number"||isNaN(s)?t.push(`${i} must be a number, got ${typeof s}`):s<0&&t.push(`${i} must be positive, got ${s}`)}if(t.length>0)return{valid:!1,errors:t};const n=e.filter(i=>i in h&&h[i]!==void 0);for(let i=0;i<n.length-1;i++){const s=n[i],a=n[i+1],o=h[s],r=h[a];o>=r&&t.push(`${a} (${r}) must be greater than ${s} (${o})`)}return{valid:t.length===0,errors:t}}const Fe={beatSubdivisions:new Map,defaultSubdivision:"quarter"},ct=4,K=["quarter","half","eighth","sixteenth","triplet8","triplet4","dotted4","dotted8","swing","offbeat8","rest"];function lt(h){return typeof h=="string"&&K.includes(h)}function Gt(h){switch(h){case"rest":return 0;case"half":return .5;case"dotted4":return 2/3;case"quarter":case"offbeat8":return 1;case"triplet4":return 1.5;case"triplet8":return 3;case"eighth":case"dotted8":case"swing":return 2;case"sixteenth":return 4;default:const t=h;throw new Error(`Unknown subdivision type: ${t}`)}}function qt(h){if(!(h.beatSubdivisions instanceof Map))throw new Error("SubdivisionConfig.beatSubdivisions must be a Map");for(const[t,e]of h.beatSubdivisions){if(t<0)throw new Error(`Beat index must be non-negative, got ${t}`);if(!lt(e))throw new Error(`Beat ${t}: Invalid subdivision type "${e}". Valid types: ${K.join(", ")}`)}if(!lt(h.defaultSubdivision))throw new Error(`Invalid defaultSubdivision "${h.defaultSubdivision}". Valid types: ${K.join(", ")}`)}function Ne(h,t){if(qt(h),t===0&&h.beatSubdivisions.size>0)throw new Error("Cannot apply subdivision config with beat assignments to empty beat map");for(const[e]of h.beatSubdivisions);}function Oe(h){const t=Gt(h);if(t>ct)throw new Error(`Subdivision "${h}" has density ${t}x which exceeds maximum supported density of ${ct}x (sixteenth notes)`)}const ke={initialSubdivision:"quarter",transitionMode:"immediate",onSubdivisionChange:void 0,anticipationTime:2,timingTolerance:.01,userOffsetMs:0,compensateOutputLatency:!0},Vt="1.0.0",$t="ellis-dp-v1",z=[{tier:"D",minHotness:0,maxHotness:33,windowMs:31},{tier:"C",minHotness:33,maxHotness:66,windowMs:25},{tier:"B",minHotness:66,maxHotness:100,windowMs:20},{tier:"A",minHotness:100,maxHotness:150,windowMs:15},{tier:"S",minHotness:150,maxHotness:200,windowMs:10},{tier:"SS",minHotness:200,maxHotness:350,windowMs:7},{tier:"Platinum",minHotness:350,maxHotness:1/0,windowMs:5}];function Ge(h){for(const t of z)if(h>=t.minHotness&&h<t.maxHotness)return t.tier;return"Platinum"}function qe(h){const t=z.findIndex(r=>h>=r.minHotness&&h<r.maxHotness);if(t===-1)return z[6].windowMs;const e=z[t],n=z[t+1];if(!n)return e.windowMs;const i=e.maxHotness-e.minHotness,a=(h-e.minHotness)/i,o=e.windowMs-n.windowMs;return e.windowMs-o*a}function Ve(h){return z.find(e=>e.tier===h)?.minHotness??0}const $e={minHitsForPocket:3,basePocketWindowFraction:.03125,minPocketWindowSeconds:.015,hotnessGainPerHit:8,hotnessLossOnBreak:80,hotnessLossOnMiss:80,averagingWindowSize:4,neutralDeadZone:.01},Lt={hotnessLossOnMiss:50,hotnessLossOnBreak:50},Y={hotnessLossOnMiss:80,hotnessLossOnBreak:80},Ut={hotnessLossOnMiss:120,hotnessLossOnBreak:120},Wt={easy:Lt,medium:Y,hard:Ut,natural:Y};function Le(h,t){return h==="custom"?{...Y,...t}:Wt[h]}const dt={difficulty:"medium",controllerMode:"ddr",pitchInfluenceWeight:1,emphasizeDownbeats:!0,emphasizeSyncopation:!1,consecutiveSameKeyLimit:8,patternMemory:4,useRhythmBand:!0},H={easy:12,medium:8,hard:6,natural:6};function Ht(h){return h==="custom"?H.medium:h==="natural"?H.hard:H[h]}function Ue(h){const t=[];return h.pitchInfluenceWeight!==void 0&&(h.pitchInfluenceWeight<0||h.pitchInfluenceWeight>1)&&t.push(`pitchInfluenceWeight must be between 0 and 1, got ${h.pitchInfluenceWeight}`),h.consecutiveSameKeyLimit!==void 0&&h.consecutiveSameKeyLimit<1&&t.push(`consecutiveSameKeyLimit must be at least 1, got ${h.consecutiveSameKeyLimit}`),h.patternMemory!==void 0&&h.patternMemory<0&&t.push(`patternMemory must be non-negative, got ${h.patternMemory}`),h.controllerMode!==void 0&&h.controllerMode!=="ddr"&&h.controllerMode!=="guitar_hero"&&h.controllerMode!=="tap"&&t.push(`controllerMode must be 'ddr', 'guitar_hero', or 'tap', got '${h.controllerMode}'`),{valid:t.length===0,errors:t}}function We(h){if(!h)return{...dt};const t={...dt,...h};return!h.consecutiveSameKeyLimit&&h.difficulty&&(t.consecutiveSameKeyLimit=Ht(h.difficulty)),t}function He(h){return{straight_16th:"sixteenth",triplet_8th:"triplet8",straight_8th:"eighth",quarter_triplet:"triplet8",straight_4th:"quarter",quarter:"quarter"}[h]??"sixteenth"}function Ke(h,t,e){let n;switch(e){case"straight_16th":n=t*.25;break;case"triplet_8th":case"quarter_triplet":n=t*(1/3);break;case"straight_8th":n=t*.5;break;default:n=0;break}return h+n}function Ye(h){const t={version:h.chartMetadata.seed??"1.0.0",algorithm:"procedural-generation",minBpm:h.bpm,maxBpm:h.bpm,sensitivity:1,filter:0,noiseFloorThreshold:0,hopSizeMs:4,fftSize:2048,dpAlpha:680,melBands:40,highPassCutoff:.4,gaussianSmoothMs:20,tempoCenter:.5,tempoWidth:1.4,useOctaveResolution:!1,useTripleMeter:!1,generatedAt:h.chartMetadata.generatedAt};return{audioId:h.audioId,duration:h.duration,beats:h.beats,bpm:h.bpm,metadata:t,downbeatConfig:h.downbeatConfig}}function Qe(h,t){const e=[],n=h.trackId===t.id,i=h.title.trim().toLowerCase()===t.title.trim().toLowerCase(),s=h.artist.trim().toLowerCase()===t.artist.trim().toLowerCase();return n||i&&s?{matches:!0,mismatchDetails:[]}:(n||e.push(`Track ID: expected "${h.trackId}", got "${t.id}"`),i||e.push(`Title: expected "${h.title}", got "${t.title}"`),s||e.push(`Artist: expected "${h.artist}", got "${t.artist}"`),{matches:!1,mismatchDetails:e,requiredTrack:{title:h.title,artist:h.artist,playlistName:h.playlistName,trackIndex:h.trackIndex}})}function Je(h){if(typeof h!="object"||h===null)return!1;const t=h;return t.version===1&&t.format==="full-beatmap"&&typeof t.audioId=="string"&&typeof t.exportedAt=="number"&&typeof t.duration=="number"&&typeof t.quarterNoteBpm=="number"&&typeof t.quarterNoteConfidence=="number"&&Array.isArray(t.detectedBeats)&&Array.isArray(t.mergedBeats)&&typeof t.interpolatedMetadata=="object"}function je(h){if(typeof h!="object"||h===null)return!1;const t=h;return t.version===1&&t.format==="level-pack"&&typeof t.exportedAt=="number"&&t.difficulties!==null&&typeof t.difficulties=="object"&&Object.keys(t.difficulties).some(e=>{const n=t.difficulties[e];return n!=null})}var Ze=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function Kt(h){return h&&h.__esModule&&Object.prototype.hasOwnProperty.call(h,"default")?h.default:h}var nt,xt;function Xe(){if(xt)return nt;xt=1,nt=h;function h(t,e){var n,i,s,a,o,r,c,l;for(n=t.length&3,i=t.length-n,s=e,o=3432918353,r=461845907,l=0;l<i;)c=t.charCodeAt(l)&255|(t.charCodeAt(++l)&255)<<8|(t.charCodeAt(++l)&255)<<16|(t.charCodeAt(++l)&255)<<24,++l,c=(c&65535)*o+(((c>>>16)*o&65535)<<16)&4294967295,c=c<<15|c>>>17,c=(c&65535)*r+(((c>>>16)*r&65535)<<16)&4294967295,s^=c,s=s<<13|s>>>19,a=(s&65535)*5+(((s>>>16)*5&65535)<<16)&4294967295,s=(a&65535)+27492+(((a>>>16)+58964&65535)<<16);switch(c=0,n){case 3:c^=(t.charCodeAt(l+2)&255)<<16;case 2:c^=(t.charCodeAt(l+1)&255)<<8;case 1:c^=t.charCodeAt(l)&255,c=(c&65535)*o+(((c>>>16)*o&65535)<<16)&4294967295,c=c<<15|c>>>17,c=(c&65535)*r+(((c>>>16)*r&65535)<<16)&4294967295,s^=c}return s^=t.length,s^=s>>>16,s=(s&65535)*2246822507+(((s>>>16)*2246822507&65535)<<16)&4294967295,s^=s>>>13,s=(s&65535)*3266489909+(((s>>>16)*3266489909&65535)<<16)&4294967295,s^=s>>>16,s>>>0}return nt}var tn=Xe();const en=Kt(tn);function nn(h,t,e){return`${h}-${t}-${e}`}function N(h){return en(h,0)/4294967295}function sn(h,t,e){const n=N(h);return Math.floor(n*(e-t))+t}function $(h,t){return`${h}:${t}`}function ht(h){return 2595*Math.log10(1+h/700)}function Yt(h){return 700*(Math.pow(10,h/2595)-1)}function X(h,t){const e=h.sampleRate,n=e/t,i=h.length,s=Math.ceil(i/n),a=new Float32Array(i);for(let r=0;r<h.numberOfChannels;r++){const c=h.getChannelData(r);for(let l=0;l<i;l++)a[l]+=c[l]/h.numberOfChannels}const o=new Float32Array(s);for(let r=0;r<s;r++){const c=r*n,l=Math.floor(c),d=Math.min(l+1,i-1),u=c-l;o[r]=a[l]*(1-u)+a[d]*u}return{data:o,originalSampleRate:e,targetSampleRate:t}}function Qt(h,t,e,n=0,i=e/2){const s=t/2+1,a=[],o=ht(n),r=ht(i),c=[];for(let d=0;d<h+2;d++)c.push(o+d*(r-o)/(h+1));const l=c.map(d=>{const u=Yt(d);return Math.floor((t+1)*u/e)});for(let d=0;d<h;d++){const u=new Float32Array(s),m=l[d],f=l[d+1],g=l[d+2];for(let p=m;p<f;p++)f!==m&&(u[p]=(p-m)/(f-m));for(let p=f;p<g;p++)g!==f&&(u[p]=(g-p)/(g-f));a.push(u)}return a}function Jt(h,t,e){if(h.length===0)return new Float32Array(0);const n=1/(2*Math.PI*t),i=1/e,s=n/(n+i),a=new Float32Array(h.length);a[0]=h[0];for(let o=1;o<h.length;o++)a[o]=s*(a[o-1]+h[o]-h[o-1]);return a}function Bt(h,t,e){if(h.length===0)return new Float32Array(0);const n=Math.round(t/1e3*e);if(n<=1)return new Float32Array(h);const i=n/6,s=n,a=new Float32Array(s),o=Math.floor(s/2);let r=0;for(let l=0;l<s;l++){const d=l-o;a[l]=Math.exp(-(d*d)/(2*i*i)),r+=a[l]}for(let l=0;l<s;l++)a[l]/=r;const c=new Float32Array(h.length);for(let l=0;l<h.length;l++){let d=0;for(let u=0;u<s;u++){const m=l+u-o,f=m<0?-m:m>=h.length?2*h.length-m-2:m,g=Math.max(0,Math.min(h.length-1,f));d+=h[g]*a[u]}c[l]=d}return c}function jt(h){if(h.length===0)return 0;let t=0;for(let s=0;s<h.length;s++)t+=h[s];const e=t/h.length;let n=0;for(let s=0;s<h.length;s++){const a=h[s]-e;n+=a*a}const i=n/h.length;return Math.sqrt(i)}function Zt(h){const t=h.length,e=Math.pow(2,Math.ceil(Math.log2(t))),n=new Float32Array(e),i=new Float32Array(e);for(let r=0;r<t;r++){const c=.5-.5*Math.cos(2*Math.PI*r/(t-1));n[r]=h[r]*c}let s=0;for(let r=0;r<e-1;r++){r<s&&([n[r],n[s]]=[n[s],n[r]],[i[r],i[s]]=[i[s],i[r]]);let c=e/2;for(;s>=c;)s-=c,c/=2;s+=c}let a=2;for(;a<=e;){const r=-2*Math.PI/a,c=Math.cos(r),l=Math.sin(r);for(let d=0;d<e;d+=a){let u=1,m=0;for(let f=0;f<a/2;f++){const g=d+f,p=d+f+a/2,b=n[p]*u-i[p]*m,y=n[p]*m+i[p]*u;n[p]=n[g]-b,i[p]=i[g]-y,n[g]+=b,i[g]+=y;const B=u*c-m*l;m=u*l+m*c,u=B}}a*=2}const o=new Float32Array(e/2+1);for(let r=0;r<o.length;r++){const c=n[r],l=i[r];o[r]=Math.sqrt(c*c+l*l)}return o}function Tt(h,t,e,n){const i=[];let s=0;for(;s+t<=h.length;){const a=h.slice(s,s+t),o=Zt(a);i.push(o),s+=e}return{frames:i,numFrames:i.length,fftSize:t,hopSize:e,sampleRate:n}}const Xt=[{name:"low",lowHz:20,highHz:500,description:"Low frequencies (bass, kick, sub)"},{name:"mid",lowHz:500,highHz:2e3,description:"Mid frequencies (vocals, snare body, lead instruments)"},{name:"high",lowHz:2e3,highHz:2e4,description:"High frequencies (hi-hats, cymbals, harmonics, air)"}];function te(h,t){const e=Math.PI*(2*h-1)/(2*t);return 1/(2*Math.sin(e))}function an(h,t,e,n){const i=2*Math.PI*h/t,s=Math.cos(i),a=Math.sin(i),o=te(e,n),r=a/(2*o),c=1+r,l=(1-s)/2/c,d=(1-s)/c,u=(1-s)/2/c,m=-2*s/c,f=(1-r)/c;return{b0:l,b1:d,b2:u,a1:m,a2:f}}function rn(h,t,e,n){const i=2*Math.PI*h/t,s=Math.cos(i),a=Math.sin(i),o=te(e,n),r=a/(2*o),c=1+r,l=(1+s)/2/c,d=-(1+s)/c,u=(1+s)/2/c,m=-2*s/c,f=(1-r)/c;return{b0:l,b1:d,b2:u,a1:m,a2:f}}function At(h,t){const{b0:e,b1:n,b2:i,a1:s,a2:a}=t,o=new Float32Array(h.length);o[0]=e*h[0],h.length>1&&(o[1]=e*h[1]+n*h[0]-s*o[0]);for(let r=2;r<h.length;r++)o[r]=e*h[r]+n*h[r-1]+i*h[r-2]-s*o[r-1]-a*o[r-2];return o}function on(h,t,e,n,i){if(h.length===0)return new Float32Array(0);const s=8;if(t>=e)throw new Error(`Low frequency (${t} Hz) must be less than high frequency (${e} Hz)`);if(e>=n/2)throw new Error(`High frequency (${e} Hz) must be less than Nyquist frequency (${n/2} Hz)`);const a=s/2;let o=new Float32Array(h);for(let r=1;r<=a;r++){const c=rn(t,n,r,s);o=At(o,c)}for(let r=1;r<=a;r++){const c=an(e,n,r,s);o=At(o,c)}return o}function cn(h,t,e,n){const i=Xt.find(s=>s.name===t);if(!i)throw new Error(`Unknown frequency band: ${t}. Valid bands are: low, mid, high`);return on(h,i.lowHz,i.highHz,e)}const ln={targetSampleRate:44100,fftWindowSizeMs:23,hopSizeMs:10,smoothWindowMs:10,peakThreshold:.3,bands:Xt};class ee{constructor(t={}){if(this.config={...ln,...t},this.config.peakThreshold<0||this.config.peakThreshold>1)throw new Error(`peakThreshold must be between 0 and 1, got: ${this.config.peakThreshold}`);if(this.config.bands.length===0)throw new Error("At least one frequency band must be specified")}getConfig(){return{...this.config}}analyze(t){const e=t.duration,n=this.config.targetSampleRate,i=X(t,n),s=Math.pow(2,Math.ceil(Math.log2(this.config.fftWindowSizeMs/1e3*n))),a=Math.round(this.config.hopSizeMs/1e3*n),o=this.config.hopSizeMs/1e3,r=1/o,c=new Map,l=[];for(const f of this.config.bands){const g=this.analyzeBand(i.data,f,n,s,a,o,r);c.set(f.name,g),l.push(g.energyOverTime)}const d=l[0]?.length??0,u=this.combineEnergyProfiles(l,d),m=this.calculateDominantBands(c);return{bands:c,dominantBands:m,energyProfile:u,metadata:{numFrames:d,duration:e,hopSizeSeconds:o,effectiveSampleRate:n,bandsAnalyzed:this.config.bands.map(f=>f.name)}}}analyzeBand(t,e,n,i,s,a,o){const r=cn(t,e.name,n),c=Tt(r,i,s,n),l=c.numFrames,d=new Float32Array(l);for(let M=0;M<l;M++){const T=c.frames[M];let S=0;for(let v=0;v<T.length;v++)S+=T[v]*T[v];d[M]=Math.sqrt(S/T.length)}const u=Math.max(...d);if(u>0)for(let M=0;M<d.length;M++)d[M]/=u;const m=u,f=this.calculateOnsetEnvelope(c.frames),g=Bt(f,this.config.smoothWindowMs,o),p=Math.max(...g),b=new Float32Array(g.length);if(p>0)for(let M=0;M<g.length;M++)b[M]=g[M]/p;const y=this.findPeaks(b,this.config.peakThreshold),B=y.map(M=>M*a);return{name:e.name,frequencyRange:{lowHz:e.lowHz,highHz:e.highHz},envelope:b,peaks:y,peakTimes:B,energy:m,energyOverTime:d}}calculateOnsetEnvelope(t){const e=t.length,n=new Float32Array(e);n[0]=0;for(let i=1;i<e;i++){const s=t[i],a=t[i-1];let o=0;for(let r=0;r<s.length;r++){const c=s[r]-a[r];c>0&&(o+=c)}n[i]=o}return n}findPeaks(t,e){const n=[];for(let i=1;i<t.length-1;i++)t[i]>t[i-1]&&t[i]>t[i+1]&&t[i]>=e&&n.push(i);return n}combineEnergyProfiles(t,e){const n=new Float32Array(e);for(let i=0;i<e;i++){let s=0;for(const a of t)i<a.length&&a[i]>s&&(s=a[i]);n[i]=s}return n}calculateDominantBands(t){const e=[];for(const[n,i]of t)e.push({name:n,energy:i.energy});return e.sort((n,i)=>i.energy-n.energy),e.map(n=>n.name)}}const it={low:{threshold:.5,minInterval:.1,adaptiveThresholding:!1},mid:{threshold:.3,minInterval:.08,adaptiveThresholding:!1},high:{threshold:.25,minInterval:.06,adaptiveThresholding:!1}},dn={baseThreshold:.3,adaptiveThresholding:!1,adaptiveWindowSize:50,minTransientInterval:.02};class ne{constructor(t={}){const{bands:e,bandConfig:n,...i}=t,s={low:{...it.low,...n?.low},mid:{...it.mid,...n?.mid},high:{...it.high,...n?.high}};if(this.config={...dn,...i,bandConfig:s},e!==void 0&&(this.config.bands=e),this.config.baseThreshold<0||this.config.baseThreshold>1)throw new Error(`baseThreshold must be between 0 and 1, got: ${this.config.baseThreshold}`);if(this.config.adaptiveWindowSize<1)throw new Error(`adaptiveWindowSize must be at least 1, got: ${this.config.adaptiveWindowSize}`);if(this.config.minTransientInterval<0)throw new Error(`minTransientInterval must be non-negative, got: ${this.config.minTransientInterval}`);for(const a of["low","mid","high"]){const o=this.config.bandConfig[a];if(o.threshold<0||o.threshold>1)throw new Error(`${a} band threshold must be between 0 and 1, got: ${o.threshold}`);if(o.minInterval<0)throw new Error(`${a} band minInterval must be non-negative, got: ${o.minInterval}`)}}getConfig(){const{bandConfig:t,...e}=this.config;return{...e,bandConfig:{low:{...t.low},mid:{...t.mid},high:{...t.high}}}}getBandConfig(){return{low:{...this.config.bandConfig.low},mid:{...this.config.bandConfig.mid},high:{...this.config.bandConfig.high}}}detect(t){const e=new Map,n=[],i=new Set;for(const[o,r]of t.bands){const c=this.detectBandTransients(o,r,t.metadata.hopSizeSeconds);e.set(o,c),n.push(...c),c.forEach(l=>i.add(l.detectionMethod))}n.sort((o,r)=>o.timestamp-r.timestamp);const s=new Map;for(const[o,r]of e)s.set(o,r.length);const a=n.length>0?n.reduce((o,r)=>o+r.intensity,0)/n.length:0;return{transients:n,bandTransients:e,metadata:{totalTransients:n.length,transientsPerBand:s,duration:t.metadata.duration,averageIntensity:a,detectionMethodsUsed:Array.from(i)}}}detectBandTransients(t,e,n){const i=this.config.bandConfig[t],s=this.getDetectionMethod(t),a=s==="energy"?e.energyOverTime:e.envelope;if(!a||a.length===0)return[];const o=i.adaptiveThresholding?this.calculateAdaptiveThreshold(a,i.threshold):i.threshold,c=this.findPeaks(a,o).map(d=>({timestamp:d*n,intensity:a[d],band:t,detectionMethod:s}));return this.applyNonMaximumSuppression(c,i.minInterval)}applyNonMaximumSuppression(t,e){if(t.length===0)return[];const n=[...t].sort((s,a)=>a.intensity-s.intensity),i=[];for(const s of n){let a=!1;for(const o of i)if(Math.abs(s.timestamp-o.timestamp)<e){a=!0;break}a||i.push(s)}return i.sort((s,a)=>s.timestamp-a.timestamp),i}getDetectionMethod(t){switch(t){case"low":return"energy";case"mid":return"spectral_flux";case"high":return"hfc";default:return"spectral_flux"}}calculateAdaptiveThreshold(t,e){const n=e??this.config.baseThreshold;if(t.length===0)return n;let i=0,s=0;for(let u=0;u<t.length;u++)i+=t[u],t[u]>s&&(s=t[u]);const a=i/t.length;let o=0;for(let u=0;u<t.length;u++){const m=t[u]-a;o+=m*m}const r=Math.sqrt(o/t.length),l=1+(a>0?r/a:0)*.5,d=n*l;return Math.max(.1,Math.min(.9,d))}findPeaks(t,e){const n=[];for(let i=1;i<t.length-1;i++)t[i]>t[i-1]&&t[i]>t[i+1]&&t[i]>=e&&n.push(i);return n}}const q={densityValidation:{maxRetries:0,baseSensitivityReduction:.1,maxCumulativeReduction:.5},minimumTransientIntensity:0,bands:[]};class St{constructor(t={}){this.config={densityValidation:{maxRetries:t.densityValidation?.maxRetries??q.densityValidation.maxRetries,baseSensitivityReduction:t.densityValidation?.baseSensitivityReduction??q.densityValidation.baseSensitivityReduction,maxCumulativeReduction:t.densityValidation?.maxCumulativeReduction??q.densityValidation.maxCumulativeReduction},minimumTransientIntensity:t.minimumTransientIntensity??q.minimumTransientIntensity,bands:t.bands??q.bands}}getConfig(){return{...this.config}}quantize(t,e,n){const i=this.splitTransientsByBand(t.transients),s=e.quarterNoteInterval/6,a=this.processBand(i.low,"low",s),o=this.processBand(i.mid,"mid",s),r=this.processBand(i.high,"high",s),c={low:this.quantizeBand(a.filteredTransients,e,"low",n),mid:this.quantizeBand(o.filteredTransients,e,"mid",n),high:this.quantizeBand(r.filteredTransients,e,"high",n)},l=a.filteredCount+o.filteredCount+r.filteredCount,d=this.aggregateDensityResults([a.densityResult,o.densityResult,r.densityResult],s);return{streams:c,metadata:{densityValidation:d,transientsFilteredByIntensity:l,transientsFilteredByBand:{low:a.filteredCount,mid:o.filteredCount,high:r.filteredCount}}}}splitTransientsByBand(t){return{low:t.filter(e=>e.band==="low"),mid:t.filter(e=>e.band==="mid"),high:t.filter(e=>e.band==="high")}}processBand(t,e,n){const i=this.config.densityValidation.maxRetries,s=this.config.densityValidation.baseSensitivityReduction,a=this.config.densityValidation.maxCumulativeReduction;let o=0,r=t;if(this.config.minimumTransientIntensity>0){const m=r.length;r=r.filter(f=>f.intensity>=this.config.minimumTransientIntensity),o=m-r.length}let c=this.config.minimumTransientIntensity,l=0,d=0;for(;d<=i;){const m=this.validateBandDensity(r,e,n,d,l);if(m.isValid)return{filteredTransients:r,filteredCount:o,densityResult:m};if(d>=i)return console.warn(`[${e}] Density validation: Max retries (${i}) reached. Proceeding with ${r.length} transients. Min interval: ${(m.minIntervalDetected*1e3).toFixed(1)}ms (required: ${(n*1e3).toFixed(1)}ms)`),{filteredTransients:r,filteredCount:o,densityResult:m};d++;const f=Math.min(s,a-l);l+=f,c=Math.min(this.config.minimumTransientIntensity+l,1);const g=r.length;r=r.filter(b=>b.intensity>=c);const p=g-r.length;o+=p,console.warn(`[${e}] Density validation retry ${d}: Threshold increased to ${(c*100).toFixed(1)}%, Filtered ${p} transients, ${r.length} remaining`)}const u=this.validateBandDensity(r,e,n,d,l);return{filteredTransients:r,filteredCount:o,densityResult:u}}validateBandDensity(t,e,n,i,s,a=this.config.minimumTransientIntensity){const o=t.length,r=Math.min(this.config.minimumTransientIntensity+s,1);if(t.length===0)return{band:e,isValid:!0,minIntervalDetected:1/0,requiredMinInterval:n,retryCount:i,sensitivityReduction:s,finalIntensityThreshold:r,transientsRemaining:o};const c=[...t].sort((u,m)=>u.timestamp-m.timestamp);let l=1/0;for(let u=1;u<c.length;u++){const m=c[u].timestamp-c[u-1].timestamp;m<l&&(l=m)}const d=l>=n;return{band:e,isValid:d,minIntervalDetected:l,requiredMinInterval:n,retryCount:i,sensitivityReduction:s,finalIntensityThreshold:r,transientsRemaining:o}}aggregateDensityResults(t,e){let n=0,i=0,s=1/0,a=!0;for(const o of t)o.retryCount>n&&(n=o.retryCount),o.sensitivityReduction>i&&(i=o.sensitivityReduction),o.minIntervalDetected<s&&(s=o.minIntervalDetected),o.isValid||(a=!1);return{isValid:a,bands:{low:t.find(o=>o.band==="low"),mid:t.find(o=>o.band==="mid"),high:t.find(o=>o.band==="high")},maxRetryCount:n,maxSensitivityReduction:i}}decideGrids(t,e,n){const i=[],s=e.quarterNoteInterval,a=this.getBandGridType(n),o=[...t].sort((r,c)=>r.timestamp-c.timestamp);for(let r=0;r<e.beats.length;r++){const c=e.beats[r],l=c.timestamp,d=r<e.beats.length-1?e.beats[r+1].timestamp:c.timestamp+s,u=o.filter(m=>m.timestamp>=l&&m.timestamp<d);u.length!==0&&(a?i.push({beatIndex:r,selectedGrid:a,transientCount:u.length,confidence:1}):i.push(this.detectGrid(u,c,r,s)))}return i}quantizeToGrids(t,e,n,i){const s=[],a=e.quarterNoteInterval,o=[...t].sort((c,l)=>c.timestamp-l.timestamp),r=new Map;for(const c of i)r.set(c.beatIndex,c);for(let c=0;c<e.beats.length;c++){const l=e.beats[c],d=r.get(c);if(!d)continue;const u=l.timestamp,m=c<e.beats.length-1?e.beats[c+1].timestamp:l.timestamp+a,f=o.filter(g=>g.timestamp>=u&&g.timestamp<m);for(const g of f){const p=this.quantizeTransient(g,l,c,d.selectedGrid,a);p&&s.push(p)}}return s}quantizeBand(t,e,n,i){const s=i?i(t,e,n):this.decideGrids(t,e,n),a=this.quantizeToGrids(t,e,n,s),o=this.deduplicateBeats(a);return{audioId:e.audioId,duration:e.duration,beats:o,gridDecisions:s,quarterNoteInterval:e.quarterNoteInterval}}deduplicateBeats(t){const e=new Map;for(const n of t){const i=`${n.beatIndex}:${n.gridPosition}:${n.gridType}`,s=e.get(i);(!s||n.intensity>s.intensity)&&e.set(i,n)}return Array.from(e.values()).sort((n,i)=>n.timestamp-i.timestamp)}getBandGridType(t){switch(t){case"low":return"straight_8th";case"mid":case"high":return null}}detectGrid(t,e,n,i){const s=this.calculateStraightGrid(e.timestamp,i),a=this.calculateTripletGrid(e.timestamp,i);let o=0,r=0,c=0;for(const f of t){const g=this.calculateOffsetFromGrid(f,s),p=this.calculateOffsetFromGrid(f,a);o+=g,r+=p,c++}const l=c>0?o/c:0,d=c>0?r/c:0,u=l<=d?"straight_16th":"triplet_8th",m=Math.abs(l-d);return{beatIndex:n,selectedGrid:u,straightAvgOffset:l,tripletAvgOffset:d,transientCount:c,confidence:m}}calculateStraightGrid(t,e){const n=[],i=e/4;for(let s=0;s<4;s++)n.push(t+s*i);return n}calculateTripletGrid(t,e){const n=[],i=e/3;for(let s=0;s<3;s++)n.push(t+s*i);return n}calculate8thGrid(t,e){const n=[],i=e/2;for(let s=0;s<2;s++)n.push(t+s*i);return n}calculateOffsetFromGrid(t,e){let n=1/0;for(const i of e){const s=Math.abs(t.timestamp-i);s<n&&(n=s)}return n*1e3}quantizeTransient(t,e,n,i,s){let a,o;switch(i){case"straight_8th":a=1,o=s/2;break;case"straight_16th":a=3,o=s/4;break;case"triplet_8th":a=2,o=s/3;break}const r=Math.round((t.timestamp-e.timestamp)/o);if(r<0||r>a)return null;const c=e.timestamp+r*o,l=Math.abs(t.timestamp-c)*1e3;return{timestamp:c,detectedTimestamp:t.timestamp,beatIndex:n,gridPosition:r,gridType:i,intensity:t.intensity,band:t.band,quantizationError:l}}}class ie{constructor(t={}){this.id="high-bpm-grid-restriction",this.description="Restricts 16th notes and triplets to 8th notes at high BPMs for playability",this.restrict16thBpm=t.restrict16thBpm??160,this.restrictTripletBpm=t.restrictTripletBpm??200}applies(t,e){return e.band==="low"?!1:t>=this.restrict16thBpm}apply(t,e){const{bpm:n}=e,i=n>=this.restrictTripletBpm;return t.map(s=>{const{selectedGrid:a}=s;return a==="straight_8th"?s:a==="straight_16th"&&n>=this.restrict16thBpm?{...s,selectedGrid:"straight_8th",confidence:1,straightAvgOffset:void 0,tripletAvgOffset:void 0}:a==="triplet_8th"&&i?{...s,selectedGrid:"straight_8th",confidence:1,straightAvgOffset:void 0,tripletAvgOffset:void 0}:s})}}const vt={rules:[new ie],enabled:!0};class se{constructor(t=vt,e){this.config=t,this.rhythmQuantizer=e??new St}getConfig(){return{...this.config}}decideGrids(t,e,n){const i=this.rhythmQuantizer.decideGrids(t,e,n),s={bpm:e.quarterNoteBpm,quarterNoteInterval:e.quarterNoteInterval,band:n,transients:t};return this.applyRules(i,s)}applyRules(t,e){if(this.config.enabled===!1)return t;let n=t;for(const i of this.config.rules)i.applies(e.bpm,e)&&(n=i.apply(n,e));return n}}const hn={phraseSizes:[1,2,4,8],minOccurrences:3,topSignificantCount:10,includePhrasesWithoutVariation:!1,minNotesPerPhrase:h=>1+h};class ae{constructor(t={}){this.config={...hn,...t}}analyze(t){const e={low:this.analyzeBand(t.low,"low"),mid:this.analyzeBand(t.mid,"mid"),high:this.analyzeBand(t.high,"high")},n=[...e.low.phrases,...e.mid.phrases,...e.high.phrases],i=new Map;i.set("low",e.low.phrases),i.set("mid",e.mid.phrases),i.set("high",e.high.phrases);const s=new Map;for(const c of this.config.phraseSizes){const l=n.filter(d=>d.sizeInBeats===c);l.length>0&&s.set(c,l)}const o=[...n].sort((c,l)=>l.significance-c.significance).slice(0,this.config.topSignificantCount),r=n.filter(c=>c.hasVariation&&c.availableForReuse);return{phrases:n,phrasesByBand:i,mostSignificantPhrases:o,phrasesBySize:s,patternLibrary:r,bandAnalysis:e}}getMinNotes(t){return typeof this.config.minNotesPerPhrase=="function"?this.config.minNotesPerPhrase(t):typeof this.config.minNotesPerPhrase=="number"?this.config.minNotesPerPhrase:1+t}analyzeBand(t,e){const n=Math.max(...t.beats.map(r=>r.beatIndex),0),i=new Map;for(const r of this.config.phraseSizes)for(let c=0;c<=n-r+1;c++){const l=this.extractPhraseCandidate(t,c,r,e);if(l){const d=i.get(l.hash);d?d.push(l):i.set(l.hash,[l])}}const s=[];for(const[r,c]of i){if(c.length<this.config.minOccurrences)continue;const l=c[0];if(l.pattern.length<this.getMinNotes(l.sizeInBeats))continue;const d=this.hasPatternVariation(l.pattern,l.sizeInBeats);if(!d&&!this.config.includePhrasesWithoutVariation)continue;const u=c.map(g=>({beatIndex:g.startBeatIndex,startTimestamp:g.startTimestamp,endTimestamp:g.endTimestamp})),m=this.calculateSignificance(l.sizeInBeats,c.length),f=d&&c.length>=this.config.minOccurrences;s.push({id:r,pattern:l.pattern,sizeInBeats:l.sizeInBeats,sourceBand:e,occurrences:u,significance:m,hasVariation:d,availableForReuse:f})}s.sort((r,c)=>c.significance-r.significance);const a=new Map;for(const r of this.config.phraseSizes){const c=s.filter(l=>l.sizeInBeats===r);c.length>0&&a.set(r,c)}const o=s.filter(r=>r.hasVariation);return{band:e,phrases:s,phrasesBySize:a,phrasesWithVariation:o}}extractPhraseCandidate(t,e,n,i){const s=e+n-1,a=t.beats.filter(d=>d.beatIndex>=e&&d.beatIndex<=s);if(a.length===0)return null;const o=a.map(d=>({...d,beatIndex:d.beatIndex-e})),r=this.hashPattern(o,n),c=Math.min(...a.map(d=>d.timestamp)),l=Math.max(...a.map(d=>d.timestamp));return{hash:r,pattern:o,sizeInBeats:n,startBeatIndex:e,startTimestamp:c,endTimestamp:l}}hashPattern(t,e){const i=[...t].sort((s,a)=>s.beatIndex!==a.beatIndex?s.beatIndex-a.beatIndex:s.gridPosition-a.gridPosition).map(s=>`${s.beatIndex}:${s.gridPosition}:${s.gridType}`);return`phrase_${e}_${i.join("|")}`}hasPatternVariation(t,e){if(t.length===0)return!1;if(t.some(o=>o.gridType==="triplet_8th")||t.some(o=>o.gridPosition===1||o.gridPosition===3))return!0;const n=t.map(o=>o.intensity),i=Math.max(...n),s=Math.min(...n);if(i-s>.1)return!0;if(t.length===e&&t.every(r=>r.gridPosition===0))return!1;const a=new Set(t.map(o=>o.gridPosition));return!(a.size===2&&a.has(0)&&a.has(2)&&this.countBeatsWithNoteCount(t,2)===e)}countBeatsWithNoteCount(t,e){const n=new Map;for(const s of t){const a=n.get(s.beatIndex)??0;n.set(s.beatIndex,a+1)}let i=0;for(const s of n.values())s===e&&i++;return i}calculateSignificance(t,e){const n=t,i=Math.log2(e+1);return n*i}}const un={beatsPerSection:8,sparseThreshold:1,denseThreshold:1.5};class re{constructor(t={}){this.config={...un,...t}}analyze(t,e,n){const i=e/60,s={low:this.analyzeBand(t.streams.low,"low",i,n),mid:this.analyzeBand(t.streams.mid,"mid",i,n),high:this.analyzeBand(t.streams.high,"high",i,n)};[...t.streams.low.beats,...t.streams.mid.beats,...t.streams.high.beats];const a=this.calculateCombinedPerBeatDensity(t.streams.low,t.streams.mid,t.streams.high),o=this.calculateCombinedMetrics(a,i,n),r=this.calculateSectionMetrics(a,i,n);return{bandMetrics:s,combinedMetrics:o,sections:r,perBeatDensity:a}}analyzeBand(t,e,n,i){const s=t.beats,o=(s.length>0?Math.max(...s.map(y=>y.beatIndex)):0)+1,r=new Map;for(const y of s){const B=r.get(y.beatIndex);B?(B.count++,B.intensities.push(y.intensity)):r.set(y.beatIndex,{count:1,intensities:[y.intensity]})}const c=[];let l=0;for(let y=0;y<o;y++){const B=r.get(y),M=B?.count??0,T=B?B.intensities.reduce((S,v)=>S+v,0)/B.intensities.length:0;c.push({beatIndex:y,transientCount:M,bands:M>0?[e]:[],averageIntensity:T}),l+=M}const d=c.map(y=>y.transientCount);let u;i&&i>0?u=l/i:u=o>0?l/o*n:0;const m=d.length>0?Math.min(...d)*n:0,f=d.length>0?Math.max(...d)*n:0,g=this.calculateVariance(d,u/n)*n*n,p=this.categorizeDensity(u),b=this.determineNaturalDifficulty(p);return{band:e,totalBeats:o,totalTransients:l,notesPerSecond:u,minNotesPerSecond:m,maxNotesPerSecond:f,variance:g,densityCategory:p,naturalDifficulty:b,perBeatDensity:c}}calculateCombinedPerBeatDensity(t,e,n){const i=[...t.beats,...e.beats,...n.beats],a=(i.length>0?Math.max(...i.map(c=>c.beatIndex)):0)+1,o=new Map;for(const c of t.beats)this.addToBeatData(o,c,"low");for(const c of e.beats)this.addToBeatData(o,c,"mid");for(const c of n.beats)this.addToBeatData(o,c,"high");const r=[];for(let c=0;c<a;c++){const l=o.get(c);if(l){const d=l.intensities.length>0?l.intensities.reduce((u,m)=>u+m,0)/l.intensities.length:0;r.push({beatIndex:c,transientCount:l.count,bands:Array.from(l.bands),averageIntensity:d})}else r.push({beatIndex:c,transientCount:0,bands:[],averageIntensity:0})}return r}addToBeatData(t,e,n){const i=t.get(e.beatIndex);if(i)i.count++,i.bands.add(n),i.intensities.push(e.intensity);else{const s=new Set;s.add(n),t.set(e.beatIndex,{count:1,bands:s,intensities:[e.intensity]})}}calculateCombinedMetrics(t,e,n){const i=t.reduce((r,c)=>r+c.transientCount,0);let s;if(n&&n>0)s=i/n;else{const r=t.length;s=r>0?i/r*e:0}const a=this.categorizeDensity(s),o=this.determineNaturalDifficulty(a);return{totalTransients:i,notesPerSecond:s,densityCategory:a,naturalDifficulty:o}}calculateSectionMetrics(t,e,n){const i=[],s=this.config.beatsPerSection,a=t.length;for(let o=0;o<a;o+=s){const r=Math.min(o+s-1,a-1),c=t.slice(o,r+1),l=c.reduce((y,B)=>y+B.transientCount,0),d=c.length,u=d>0?l/d*e:0,m=c.map(y=>y.transientCount),f=m.length>0?Math.min(...m)*e:0,g=m.length>0?Math.max(...m)*e:0,p=this.categorizeDensity(u),b=this.determineNaturalDifficulty(p);i.push({startBeat:o,endBeat:r,beatCount:d,totalTransients:l,notesPerSecond:u,minNotesPerSecond:f,maxNotesPerSecond:g,densityCategory:p,naturalDifficulty:b})}return i}categorizeDensity(t){return t<this.config.sparseThreshold?"sparse":t>this.config.denseThreshold?"dense":"moderate"}determineNaturalDifficulty(t){switch(t){case"sparse":return"easy";case"moderate":return"medium";case"dense":return"hard"}}calculateVariance(t,e){return t.length===0?0:t.map(i=>Math.pow(i-e,2)).reduce((i,s)=>i+s,0)/t.length}getConfig(){return{...this.config}}}const oe={beatsPerSection:8,ioiVarianceWeight:.3,syncopationWeight:.3,phraseSignificanceWeight:.25,densityWeight:.15,offbeatGridPositions:{straight_16th:[1,3],triplet_8th:[1,2],straight_8th:[1]},bandBiasWeights:{low:.8,mid:.95,high:1}},mn={low:.8,mid:.95,high:1},fn={ddr:{ioiVarianceWeight:.2,syncopationWeight:.15,phraseSignificanceWeight:.35,densityWeight:.3},guitar_hero:{ioiVarianceWeight:.3,syncopationWeight:.3,phraseSignificanceWeight:.25,densityWeight:.15},tap:{ioiVarianceWeight:.3,syncopationWeight:.2,phraseSignificanceWeight:.3,densityWeight:.2}};function gn(h){const t=fn[h];return{...oe,...t,bandBiasWeights:{...mn}}}class ce{constructor(t={}){this.config={...oe,...t}}score(t,e,n){const i=[],s={low:[],mid:[],high:[]},a=[...t.streams.low.beats,...t.streams.mid.beats,...t.streams.high.beats],o=a.length>0?Math.max(...a.map(m=>m.beatIndex)):0,r=o+1,c=["low","mid","high"];for(let m=0;m<r;m+=this.config.beatsPerSection){const f=Math.min(m+this.config.beatsPerSection-1,o),g={start:m,end:f};for(const p of c){const b=this.scoreSection(t.streams[p],p,g,e,n);i.push(b),s[p].push(b.score)}}const l={low:s.low.reduce((m,f)=>m+f,0),mid:s.mid.reduce((m,f)=>m+f,0),high:s.high.reduce((m,f)=>m+f,0)},d={low:s.low.length>0?l.low/s.low.length:0,mid:s.mid.length>0?l.mid/s.mid.length:0,high:s.high.length>0?l.high/s.high.length:0},u=this.determineSectionWinners(i);return{sectionScores:i,bandTotals:l,bandAverages:d,sectionWinners:u,config:{...this.config}}}scoreSection(t,e,n,i,s){const a=t.beats.filter(u=>u.beatIndex>=n.start&&u.beatIndex<=n.end),o=this.calculateIOIVariance(a),r=this.calculateSyncopationLevel(a),c=this.calculatePhraseSignificance(i,e,n),l=this.calculateDensityFactor(s,e,n);let d=o*this.config.ioiVarianceWeight+r*this.config.syncopationWeight+c*this.config.phraseSignificanceWeight+l*this.config.densityWeight;if(this.config.bandBiasWeights){const u=this.config.bandBiasWeights[e]??1;d*=u}return{beatRange:n,band:e,score:d,factors:{ioiVariance:o,syncopationLevel:r,phraseSignificance:c,densityFactor:l}}}calculateIOIVariance(t){if(t.length<2)return 0;const e=[...t].sort((r,c)=>r.timestamp-c.timestamp),n=[];for(let r=1;r<e.length;r++)n.push(e[r].timestamp-e[r-1].timestamp);if(n.length===0)return 0;const i=n.reduce((r,c)=>r+c,0)/n.length,s=n.reduce((r,c)=>r+Math.pow(c-i,2),0)/n.length,a=Math.sqrt(s),o=i>0?a/i:0;return Math.min(o,1)}calculateSyncopationLevel(t){if(t.length===0)return 0;let e=0,n=0;for(const i of t){const a=this.config.offbeatGridPositions[i.gridType].includes(i.gridPosition),o=i.intensity;a&&(e+=o),n+=o}return n===0?0:e/n}calculatePhraseSignificance(t,e,n){const i=t.phrasesByBand.get(e)??[];if(i.length===0)return 0;let s=0,a=0;for(const r of i){a=Math.max(a,r.significance);for(const c of r.occurrences){const l=c.beatIndex+r.sizeInBeats-1;if(c.beatIndex<=n.end&&l>=n.start){const d=Math.max(c.beatIndex,n.start),f=(Math.min(l,n.end)-d+1)/r.sizeInBeats;s+=r.significance*f;break}}}if(a===0)return 0;const o=s/a;return Math.min(o,1)}calculateDensityFactor(t,e,n){const a=t.bandMetrics[e].perBeatDensity.filter(m=>m.beatIndex>=n.start&&m.beatIndex<=n.end);if(a.length===0)return 0;const o=a.reduce((m,f)=>m+f.transientCount,0)/a.length,r=this.config.bpm!=null?this.config.bpm/60:1,c=o*r;return Math.exp(-Math.pow(c-1,2)/(2*Math.pow(.75,2)))}determineSectionWinners(t){const e=new Map;for(const i of t){const s=`${i.beatRange.start}-${i.beatRange.end}`,a=e.get(s);a?a.push(i):e.set(s,[i])}const n=[];for(const[,i]of e){if(i.length===0)continue;const s=[...i].sort((c,l)=>l.score-c.score),a=s[0],o=s[1],r=o?a.score-o.score:a.score;n.push({beatRange:a.beatRange,winner:a.band,score:a.score,margin:r})}return n.sort((i,s)=>i.beatRange.start-s.beatRange.start),n}getConfig(){return{...this.config}}updateConfig(t){this.config={...this.config,...t}}}const pn={transitionOverlapBeats:0,preserveGridDecisions:!0},yn=1,bn=1.5;class le{constructor(t={}){this.config={...pn,...t}}generate(t,e,n,i){const s=e.sectionWinners,a={low:0,mid:0,high:0},o={low:0,mid:0,high:0},c=s.filter(b=>{const y=["low","mid","high"];let B=!1;for(const M of y)if(t.streams[M].beats.filter(v=>v.beatIndex>=b.beatRange.start&&v.beatIndex<=b.beatRange.end).length>0){B=!0;break}return B}).map(b=>({beatRange:b.beatRange,sourceBand:b.winner,score:b.score,margin:b.margin}));for(const b of c)o[b.sourceBand]++;const l=[];for(const b of c){const y=t.streams[b.sourceBand],B=this.extractSectionBeats(y,b.beatRange,b.sourceBand);l.push(...B),a[b.sourceBand]+=B.length}l.sort((b,y)=>b.timestamp-y.timestamp);const d=this.deduplicateBeats(l),u=t.streams.low.quarterNoteInterval,m=60/u,f=this.determineNaturalDifficulty(d,n,m,i),g=c.length,p={totalBeats:d.length,sectionCount:g,beatsPerBand:a,sectionsPerBand:{low:g>0?o.low/g:0,mid:g>0?o.mid/g:0,high:g>0?o.high/g:0}};return{beats:d,sections:c,naturalDifficulty:f,quarterNoteInterval:u,metadata:p}}extractSectionBeats(t,e,n){return t.beats.filter(i=>i.beatIndex>=e.start&&i.beatIndex<=e.end).map(i=>({...i,sourceBand:n}))}deduplicateBeats(t){const e=new Map;for(const n of t){const i=Math.round(n.timestamp*1e3),s=e.get(i);(!s||n.intensity>s.intensity)&&e.set(i,n)}return Array.from(e.values()).sort((n,i)=>n.timestamp-i.timestamp)}determineNaturalDifficulty(t,e,n,i){if(t.length===0)return"easy";let s;if(i&&i>0)s=t.length/i;else{const o=Math.max(...t.map(r=>r.beatIndex))+1;s=t.length/o*(n/60)}return s<yn?"easy":s>bn?"hard":"medium"}getConfig(){return{...this.config}}}const tt={strongBeatEmphasis:"natural",downbeatProximityRange:2,fillEmptyMeasures:!0,addedBeatIntensity:.45,marginSeconds:.5},Mn={ddr:{strongBeatEmphasis:"natural",downbeatProximityRange:1,fillEmptyMeasures:!0,addedBeatIntensity:.45,marginSeconds:.5},guitar_hero:{strongBeatEmphasis:"natural",downbeatProximityRange:2,fillEmptyMeasures:!0,addedBeatIntensity:.45,marginSeconds:.5},tap:{strongBeatEmphasis:"natural",downbeatProximityRange:1.5,fillEmptyMeasures:!0,addedBeatIntensity:.45,marginSeconds:.5}};function Bn(h){return{...Mn[h]}}function de(h){return h%3===0?3:2}function he(h,t){return h%t===0}function ue(h,t){return h%t!==0}function me(h,t){let e=h[0];for(const n of h)if(n.startBeat<=t)e=n;else break;return e}function fe(h,t,e){if(e==="neutral")return!1;const n=de(t);return e==="natural"?he(h,n):ue(h,n)}class ge{constructor(t={}){this.config={...tt,...t}}getConfig(){return{...this.config}}balance(t,e){const n={shiftedToDownbeat:0,emptyMeasuresFilled:0,proximityShifts:0,beatsAdded:0,beatsShifted:0,marginRemovals:0};let i=[...t.beats];return i=this.shiftLoneSubdivisionNotes(i,e,n),i=this.fillEmptyMeasures(i,e,n),i=this.enforceDownbeatProximity(i,e,n),i=this.removeMarginNotes(i,e.duration,n),i.sort((s,a)=>s.timestamp-a.timestamp),{composite:{...t,beats:i,metadata:{...t.metadata,totalBeats:i.length}},stats:n}}shiftLoneSubdivisionNotes(t,e,n){if(!e.downbeatConfig?.segments)return t;const i=new Map;for(const a of t){const o=e.beats[a.beatIndex];if(o){const r=o.measureNumber;i.has(r)||i.set(r,[]),i.get(r).push(a)}}const s=[];for(const a of t){const o=e.beats[a.beatIndex];if(!o){s.push(a);continue}const r=o.measureNumber;if((i.get(r)||[]).length===1&&a.gridPosition!==0){const l={...a,gridPosition:0,timestamp:e.beats[a.beatIndex].timestamp,balancerAction:"shifted_to_downbeat"};s.push(l),n.shiftedToDownbeat++,n.beatsShifted++}else s.push(a)}return s}fillEmptyMeasures(t,e,n){if(!this.config.fillEmptyMeasures||!e.downbeatConfig?.segments)return t;let i=1/0,s=-1/0;for(const c of e.beats)i=Math.min(i,c.measureNumber),s=Math.max(s,c.measureNumber);if(i===1/0)return t;const a=new Map;for(const c of t){const l=e.beats[c.beatIndex];if(l){const d=l.measureNumber;a.has(d)||a.set(d,[]),a.get(d).push(c)}}const o=new Map;for(const c of t)o.set(c.beatIndex,c.gridType);const r=[];for(let c=i;c<=s;c++)if((a.get(c)||[]).length===0){const d=e.beats.findIndex(u=>u.measureNumber===c&&u.isDownbeat);if(d>=0){let u="straight_8th";for(let g=1;g<=8;g++){const p=d-g,b=d+g;if(o.has(p)){u=o.get(p);break}if(o.has(b)){u=o.get(b);break}}const f={timestamp:e.beats[d].timestamp,beatIndex:d,gridPosition:0,gridType:u,intensity:this.config.addedBeatIntensity,band:"mid",sourceBand:"mid",balancerAction:"empty_measure_fill"};r.push(f),n.emptyMeasuresFilled++,n.beatsAdded++}}return[...t,...r]}enforceDownbeatProximity(t,e,n){const i=this.config.downbeatProximityRange;if(i<0)return t;const s=new Set;for(const o of t)o.gridPosition===0&&s.add(o.beatIndex);const a=[];for(const o of t){if(o.gridPosition===0){a.push(o);continue}let r=!1;const c=Math.ceil(i);for(let l=0;l<=c&&!(l>i);l++)if(l===0){if(s.has(o.beatIndex)){r=!0;break}}else if(s.has(o.beatIndex-l)||s.has(o.beatIndex+l)){r=!0;break}if(r)a.push(o);else{const l={...o,gridPosition:0,timestamp:e.beats[o.beatIndex]?.timestamp??o.timestamp,balancerAction:"proximity_shift"};a.push(l),s.add(o.beatIndex),n.proximityShifts++,n.beatsShifted++}}return a}removeMarginNotes(t,e,n){const i=this.config.marginSeconds;if(i<=0||e<=0)return t;const s=e-i;return t.filter(a=>a.timestamp<i||a.timestamp>s?(n.marginRemovals++,!1):!0)}}const Tn=["straight_16th","triplet_8th","straight_8th","quarter_triplet","straight_4th"],ut={straight_16th:4,straight_8th:2,triplet_8th:3,straight_4th:1,quarter_triplet:1},C={easy:{maxSubdivision:"eighth",allowedGridTypes:["straight_4th","quarter_triplet"],description:"Quarter notes and quarter note triplets only",targetDensityRange:{min:0,max:1}},medium:{maxSubdivision:"eighth",allowedGridTypes:["straight_8th","quarter_triplet"],description:"8th notes and quarter note triplets only, with density reduction for moderate difficulty",targetDensityRange:{min:1,max:1.5}},hard:{maxSubdivision:"sixteenth",allowedGridTypes:["straight_16th","triplet_8th","straight_8th","quarter_triplet"],description:"All subdivision types including 16th notes",targetDensityRange:{min:1.5,max:1/0}},natural:{maxSubdivision:"sixteenth",allowedGridTypes:["straight_16th","triplet_8th","straight_8th","quarter_triplet"],description:"Unedited composite stream - no subdivision restrictions",targetDensityRange:{min:0,max:1/0}},custom:{maxSubdivision:"sixteenth",allowedGridTypes:["straight_16th","triplet_8th","straight_8th","quarter_triplet"],description:"Custom density-based variant — parameters provided at generation time",targetDensityRange:{min:0,max:1/0}}},pe=70,ye=70,be=120;function R(h,t){if(h==="natural")return[...C.natural.allowedGridTypes];if(h==="easy")return["straight_4th","quarter_triplet"];if(h==="medium")return["straight_8th","quarter_triplet"];if(h==="hard")return t>=ye?["straight_8th","quarter_triplet"]:[...C.hard.allowedGridTypes];if(h==="custom")return[...C.custom.allowedGridTypes];const e=h;throw new Error(`Unhandled difficulty: ${e}`)}const Sn={straight_4th:["straight_4th"],straight_8th:["straight_8th","quarter_triplet"],quarter_triplet:["quarter_triplet","straight_8th"],triplet_8th:["triplet_8th","straight_8th","quarter_triplet"],straight_16th:["straight_16th","triplet_8th","straight_8th","quarter_triplet"]};function Me(h,t){const e=Sn[h.maxGridType]??[h.maxGridType];if(!h.bpmBasedQuantization)return[...e];const n=h.restrictBpm??pe,i=h.quarterNoteBpm??be;let s=[...e];return t>=n&&(s=s.filter(a=>a!=="straight_16th"&&a!=="triplet_8th")),t>i&&(s=s.filter(a=>a!=="straight_8th")),s}function Be(h,t){if(h.length===0||t<=0)return 0;const e=60/t;return Math.max(...h.map(i=>ut[i]))/e}const vn={logConversions:!1,preservePhraseBoundaries:!0,simplificationIntensityThreshold:.3,heavySimplificationIntensityThreshold:.5,moderateSimplificationIntensityThreshold:.4,densityReductionMinIntensity:.25,interpolatedBeatIntensity:.5,preferPatternInsertion:!0,maxPatternInsertionSize:4,densityTargetStrategy:"midpoint",maxReductionPasses:3,seed:void 0,rhythmicBalanceConfig:void 0};function In(h,t,e){return e!==void 0?R(t,e).includes(h):C[t].allowedGridTypes.includes(h)}function _n(h,t){return t!==void 0?R(h,t):[...C[h].allowedGridTypes]}function Q(h,t,e,n){const i=n??(e!==void 0?R(t,e):C[t].allowedGridTypes);if(i.includes(h))return h;switch(h){case"straight_16th":return i.includes("straight_4th")&&!i.includes("straight_8th")?"straight_4th":"straight_8th";case"triplet_8th":return"quarter_triplet";case"straight_8th":return"straight_4th";default:return h}}function wn(h){return h}function Te(h,t,e){const n=[],i=e!==void 0?R(t,e):C[t].allowedGridTypes;for(const s of h)i.includes(s.gridType)||n.push({beat:s,gridType:s.gridType,suggestedConversion:Q(s.gridType,t,e)});return{isValid:n.length===0,violations:n,totalBeats:h.length,violationCount:n.length}}class Se{constructor(t={}){this.currentUnifiedBeatMap=null,this.config={...vn,...t}}lockGridPerBeatIndex(t,e,n,i,s){const a=this.enforceSingleGridPerBeat(t),o=new Map;if(a.length===0)return{beats:[],gridLock:o};const r=Math.max(...a.map(d=>d.beatIndex)),c=new Map;for(const d of a){const u=c.get(d.beatIndex)??[];u.push(d),c.set(d.beatIndex,u)}for(const[d,u]of c)o.set(d,u[0].gridType);const l=s??R(e,n);for(let d=0;d<=r;d++){if(o.has(d))continue;if(i?.has(d)){const f=i.get(d);o.set(d,f.selectedGrid);continue}let u=!1;for(const f of[1,-1,2,-2,3,-3]){const g=d+f;if(o.has(g)){o.set(d,o.get(g)),u=!0;break}}if(u)continue;const m=l[0]??"straight_8th";o.set(d,m)}return{beats:a,gridLock:o}}generate(t,e,n,i){this.currentUnifiedBeatMap=e;const s=t.naturalDifficulty,a=this.generateVariant(t,"easy",s,e,n,i),o=this.generateVariant(t,"medium",s,e,n,i),r=this.generateVariant(t,"hard",s,e,n,i);this.validateGridLockResult(a.beats,"easy"),this.validateGridLockResult(o.beats,"medium"),this.validateGridLockResult(r.beats,"hard");const c={difficulty:"natural",beats:this.enforceSingleGridPerBeat([...t.beats]),isUnedited:!0,editType:"none",editAmount:0};this.validateVariant(a,"easy"),this.validateVariant(o,"medium"),this.validateVariant(r,"hard");const l=e?.duration??120;if(a.densityValidation=this.validateDensityInRange(a,l),o.densityValidation=this.validateDensityInRange(o,l),r.densityValidation=this.validateDensityInRange(r,l),this.config.logConversions){const d=u=>{const m=u.densityValidation,f=m.targetRange.max===1/0?"∞":m.targetRange.max.toFixed(1),g=m.inRange?"✓":"✗";return`${u.difficulty}: ${m.density.toFixed(2)} nps (target [${m.targetRange.min}, ${f}]) ${g}`};console.log(`[DifficultyVariantGenerator] Density validation summary:
1
+ "use strict";const mt=require("./arweaveGatewayManager-C9SIMDTd.cjs"),Dt={beatsPerMeasure:4},Z={segments:[{startBeat:0,downbeatBeatIndex:0,timeSignature:Dt}]},st=2,at=12;function ft(h){if(!h.segments||h.segments.length===0)throw new Error("DownbeatConfig must have at least one segment");for(const t of h.segments){if(t.startBeat<0)throw new Error(`startBeat must be non-negative, got ${t.startBeat}`);if(t.downbeatBeatIndex<0)throw new Error(`downbeatBeatIndex must be non-negative, got ${t.downbeatBeatIndex}`);const{beatsPerMeasure:e}=t.timeSignature;if(e<st||e>at)throw new Error(`beatsPerMeasure must be between ${st} and ${at}, got ${e}`)}for(let t=1;t<h.segments.length;t++)if(h.segments[t].startBeat<=h.segments[t-1].startBeat)throw new Error("Segments must be ordered by startBeat in ascending order")}function gt(h,t){for(const e of h.segments)if(e.downbeatBeatIndex>=t)throw new Error(`downbeatBeatIndex ${e.downbeatBeatIndex} exceeds total beats ${t}`)}function Ce(h,t){ft(t),gt(t,h.beats.length);const e=Re(t.segments,h.beats.length),n=h.beats.map((i,s)=>{const a=De(t.segments,s),o=t.segments[a],{downbeatBeatIndex:r,timeSignature:c}=o,{beatsPerMeasure:l}=c,d=s-r,u=(d%l+l)%l,m=u===0,g=Math.max(0,Math.floor(d/l))+e[a];return{...i,beatInMeasure:u,isDownbeat:m,measureNumber:g}});return{...h,beats:n,downbeatConfig:t}}function Re(h,t){const e=[];for(let n=0;n<h.length;n++)if(n===0)e.push(0);else{const i=h[n-1],{downbeatBeatIndex:s,timeSignature:a}=i,o=a.beatsPerMeasure,c=h[n].startBeat-1-s,l=Math.max(0,Math.floor(c/o));e.push(l+1)}return e}function De(h,t){let e=0;for(let n=0;n<h.length&&h[n].startBeat<=t;n++)e=n;return e}const Et={perfect:.03,great:.05,good:.1,ok:.2},zt={perfect:.02,great:.035,good:.075,ok:.125},pt={perfect:.01,great:.025,good:.05,ok:.1},rt={efficient:10,standard:4,hq:2},Ft={standard:40,detailed:64,maximum:80},Nt={minimal:10,standard:20,smooth:40};function yt(h={mode:"standard"}){if(h.mode==="custom"){const t=h.customValue??rt.standard;return Math.max(1,Math.min(50,t))}return rt[h.mode]}function bt(h={mode:"standard"}){return Ft[h.mode]}function Mt(h={mode:"standard"}){return Nt[h.mode]}const V={minBpm:90,maxBpm:180,sensitivity:1,filter:0,noiseFloorThreshold:0,hopSizeMs:4,fftSize:2048,rollingBpmWindowSize:8,dpAlpha:680,melBands:40,highPassCutoff:.4,gaussianSmoothMs:20,tempoCenter:.5,tempoWidth:1.4,useOctaveResolution:!1,useTripleMeter:!1,hopSizeMode:{mode:"standard"},melBandsMode:{mode:"standard"},gaussianSmoothMode:{mode:"standard"}},Ot={anticipationTime:2,userOffsetMs:0,compensateOutputLatency:!0,timingTolerance:.01,difficultyPreset:"medium",customThresholds:{},useInterpolatedBeats:!1,ignoreKeyRequirements:!1},Ee=pt;function ot(h){switch(h){case"easy":return Et;case"medium":return zt;default:return pt}}const kt={minAnchorConfidence:.3,gridSnapTolerance:.05,tempoAdaptationRate:.3,extrapolateStart:!0,extrapolateEnd:!0,anomalyThreshold:.4,denseSectionMinBeats:3,gridAlignmentWeight:.5,anchorConfidenceWeight:.3,paceConfidenceWeight:.2,tempoSectionThreshold:.1,minClusterBeats:4,enableMultiTempo:!1};function ze(h){const t=[],e=["perfect","great","good","ok"];for(const i of e)if(i in h){const s=h[i];s==null?t.push(`${i} is undefined or null`):typeof s!="number"||isNaN(s)?t.push(`${i} must be a number, got ${typeof s}`):s<0&&t.push(`${i} must be positive, got ${s}`)}if(t.length>0)return{valid:!1,errors:t};const n=e.filter(i=>i in h&&h[i]!==void 0);for(let i=0;i<n.length-1;i++){const s=n[i],a=n[i+1],o=h[s],r=h[a];o>=r&&t.push(`${a} (${r}) must be greater than ${s} (${o})`)}return{valid:t.length===0,errors:t}}const Fe={beatSubdivisions:new Map,defaultSubdivision:"quarter"},ct=4,K=["quarter","half","eighth","sixteenth","triplet8","triplet4","dotted4","dotted8","swing","offbeat8","rest"];function lt(h){return typeof h=="string"&&K.includes(h)}function Gt(h){switch(h){case"rest":return 0;case"half":return .5;case"dotted4":return 2/3;case"quarter":case"offbeat8":return 1;case"triplet4":return 1.5;case"triplet8":return 3;case"eighth":case"dotted8":case"swing":return 2;case"sixteenth":return 4;default:const t=h;throw new Error(`Unknown subdivision type: ${t}`)}}function qt(h){if(!(h.beatSubdivisions instanceof Map))throw new Error("SubdivisionConfig.beatSubdivisions must be a Map");for(const[t,e]of h.beatSubdivisions){if(t<0)throw new Error(`Beat index must be non-negative, got ${t}`);if(!lt(e))throw new Error(`Beat ${t}: Invalid subdivision type "${e}". Valid types: ${K.join(", ")}`)}if(!lt(h.defaultSubdivision))throw new Error(`Invalid defaultSubdivision "${h.defaultSubdivision}". Valid types: ${K.join(", ")}`)}function Ne(h,t){if(qt(h),t===0&&h.beatSubdivisions.size>0)throw new Error("Cannot apply subdivision config with beat assignments to empty beat map");for(const[e]of h.beatSubdivisions);}function Oe(h){const t=Gt(h);if(t>ct)throw new Error(`Subdivision "${h}" has density ${t}x which exceeds maximum supported density of ${ct}x (sixteenth notes)`)}const ke={initialSubdivision:"quarter",transitionMode:"immediate",onSubdivisionChange:void 0,anticipationTime:2,timingTolerance:.01,userOffsetMs:0,compensateOutputLatency:!0},Vt="1.0.0",$t="ellis-dp-v1",z=[{tier:"D",minHotness:0,maxHotness:33,windowMs:31},{tier:"C",minHotness:33,maxHotness:66,windowMs:25},{tier:"B",minHotness:66,maxHotness:100,windowMs:20},{tier:"A",minHotness:100,maxHotness:150,windowMs:15},{tier:"S",minHotness:150,maxHotness:200,windowMs:10},{tier:"SS",minHotness:200,maxHotness:350,windowMs:7},{tier:"Platinum",minHotness:350,maxHotness:1/0,windowMs:5}];function Ge(h){for(const t of z)if(h>=t.minHotness&&h<t.maxHotness)return t.tier;return"Platinum"}function qe(h){const t=z.findIndex(r=>h>=r.minHotness&&h<r.maxHotness);if(t===-1)return z[6].windowMs;const e=z[t],n=z[t+1];if(!n)return e.windowMs;const i=e.maxHotness-e.minHotness,a=(h-e.minHotness)/i,o=e.windowMs-n.windowMs;return e.windowMs-o*a}function Ve(h){return z.find(e=>e.tier===h)?.minHotness??0}const $e={minHitsForPocket:3,basePocketWindowFraction:.03125,minPocketWindowSeconds:.015,hotnessGainPerHit:8,hotnessLossOnBreak:80,hotnessLossOnMiss:80,averagingWindowSize:4,neutralDeadZone:.01},Lt={hotnessLossOnMiss:50,hotnessLossOnBreak:50},Y={hotnessLossOnMiss:80,hotnessLossOnBreak:80},Ut={hotnessLossOnMiss:120,hotnessLossOnBreak:120},Wt={easy:Lt,medium:Y,hard:Ut,natural:Y};function Le(h,t){return h==="custom"?{...Y,...t}:Wt[h]}const dt={difficulty:"medium",controllerMode:"ddr",pitchInfluenceWeight:1,emphasizeDownbeats:!0,emphasizeSyncopation:!1,consecutiveSameKeyLimit:8,patternMemory:4,useRhythmBand:!0},H={easy:12,medium:8,hard:6,natural:6};function Ht(h){return h==="custom"?H.medium:h==="natural"?H.hard:H[h]}function Ue(h){const t=[];return h.pitchInfluenceWeight!==void 0&&(h.pitchInfluenceWeight<0||h.pitchInfluenceWeight>1)&&t.push(`pitchInfluenceWeight must be between 0 and 1, got ${h.pitchInfluenceWeight}`),h.consecutiveSameKeyLimit!==void 0&&h.consecutiveSameKeyLimit<1&&t.push(`consecutiveSameKeyLimit must be at least 1, got ${h.consecutiveSameKeyLimit}`),h.patternMemory!==void 0&&h.patternMemory<0&&t.push(`patternMemory must be non-negative, got ${h.patternMemory}`),h.controllerMode!==void 0&&h.controllerMode!=="ddr"&&h.controllerMode!=="guitar_hero"&&h.controllerMode!=="tap"&&t.push(`controllerMode must be 'ddr', 'guitar_hero', or 'tap', got '${h.controllerMode}'`),{valid:t.length===0,errors:t}}function We(h){if(!h)return{...dt};const t={...dt,...h};return!h.consecutiveSameKeyLimit&&h.difficulty&&(t.consecutiveSameKeyLimit=Ht(h.difficulty)),t}function He(h){return{straight_16th:"sixteenth",triplet_8th:"triplet8",straight_8th:"eighth",quarter_triplet:"triplet8",straight_4th:"quarter",quarter:"quarter"}[h]??"sixteenth"}function Ke(h,t,e){let n;switch(e){case"straight_16th":n=t*.25;break;case"triplet_8th":case"quarter_triplet":n=t*(1/3);break;case"straight_8th":n=t*.5;break;default:n=0;break}return h+n}function Ye(h){const t={version:h.chartMetadata.seed??"1.0.0",algorithm:"procedural-generation",minBpm:h.bpm,maxBpm:h.bpm,sensitivity:1,filter:0,noiseFloorThreshold:0,hopSizeMs:4,fftSize:2048,dpAlpha:680,melBands:40,highPassCutoff:.4,gaussianSmoothMs:20,tempoCenter:.5,tempoWidth:1.4,useOctaveResolution:!1,useTripleMeter:!1,generatedAt:h.chartMetadata.generatedAt};return{audioId:h.audioId,duration:h.duration,beats:h.beats,bpm:h.bpm,metadata:t,downbeatConfig:h.downbeatConfig}}function Qe(h,t){const e=[],n=h.trackId===t.id,i=h.title.trim().toLowerCase()===t.title.trim().toLowerCase(),s=h.artist.trim().toLowerCase()===t.artist.trim().toLowerCase();return n||i&&s?{matches:!0,mismatchDetails:[]}:(n||e.push(`Track ID: expected "${h.trackId}", got "${t.id}"`),i||e.push(`Title: expected "${h.title}", got "${t.title}"`),s||e.push(`Artist: expected "${h.artist}", got "${t.artist}"`),{matches:!1,mismatchDetails:e,requiredTrack:{title:h.title,artist:h.artist,playlistName:h.playlistName,trackIndex:h.trackIndex}})}function Je(h){if(typeof h!="object"||h===null)return!1;const t=h;return t.version===1&&t.format==="full-beatmap"&&typeof t.audioId=="string"&&typeof t.exportedAt=="number"&&typeof t.duration=="number"&&typeof t.quarterNoteBpm=="number"&&typeof t.quarterNoteConfidence=="number"&&Array.isArray(t.detectedBeats)&&Array.isArray(t.mergedBeats)&&typeof t.interpolatedMetadata=="object"}function je(h){if(typeof h!="object"||h===null)return!1;const t=h;return t.version===1&&t.format==="level-pack"&&typeof t.exportedAt=="number"&&t.difficulties!==null&&typeof t.difficulties=="object"&&Object.keys(t.difficulties).some(e=>{const n=t.difficulties[e];return n!=null})}var Ze=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function Kt(h){return h&&h.__esModule&&Object.prototype.hasOwnProperty.call(h,"default")?h.default:h}var nt,xt;function Xe(){if(xt)return nt;xt=1,nt=h;function h(t,e){var n,i,s,a,o,r,c,l;for(n=t.length&3,i=t.length-n,s=e,o=3432918353,r=461845907,l=0;l<i;)c=t.charCodeAt(l)&255|(t.charCodeAt(++l)&255)<<8|(t.charCodeAt(++l)&255)<<16|(t.charCodeAt(++l)&255)<<24,++l,c=(c&65535)*o+(((c>>>16)*o&65535)<<16)&4294967295,c=c<<15|c>>>17,c=(c&65535)*r+(((c>>>16)*r&65535)<<16)&4294967295,s^=c,s=s<<13|s>>>19,a=(s&65535)*5+(((s>>>16)*5&65535)<<16)&4294967295,s=(a&65535)+27492+(((a>>>16)+58964&65535)<<16);switch(c=0,n){case 3:c^=(t.charCodeAt(l+2)&255)<<16;case 2:c^=(t.charCodeAt(l+1)&255)<<8;case 1:c^=t.charCodeAt(l)&255,c=(c&65535)*o+(((c>>>16)*o&65535)<<16)&4294967295,c=c<<15|c>>>17,c=(c&65535)*r+(((c>>>16)*r&65535)<<16)&4294967295,s^=c}return s^=t.length,s^=s>>>16,s=(s&65535)*2246822507+(((s>>>16)*2246822507&65535)<<16)&4294967295,s^=s>>>13,s=(s&65535)*3266489909+(((s>>>16)*3266489909&65535)<<16)&4294967295,s^=s>>>16,s>>>0}return nt}var tn=Xe();const en=Kt(tn);function nn(h,t,e){return`${h}-${t}-${e}`}function N(h){return en(h,0)/4294967295}function sn(h,t,e){const n=N(h);return Math.floor(n*(e-t))+t}function $(h,t){return`${h}:${t}`}function ht(h){return 2595*Math.log10(1+h/700)}function Yt(h){return 700*(Math.pow(10,h/2595)-1)}function X(h,t){const e=h.sampleRate,n=e/t,i=h.length,s=Math.ceil(i/n),a=new Float32Array(i);for(let r=0;r<h.numberOfChannels;r++){const c=h.getChannelData(r);for(let l=0;l<i;l++)a[l]+=c[l]/h.numberOfChannels}const o=new Float32Array(s);for(let r=0;r<s;r++){const c=r*n,l=Math.floor(c),d=Math.min(l+1,i-1),u=c-l;o[r]=a[l]*(1-u)+a[d]*u}return{data:o,originalSampleRate:e,targetSampleRate:t}}function Qt(h,t,e,n=0,i=e/2){const s=t/2+1,a=[],o=ht(n),r=ht(i),c=[];for(let d=0;d<h+2;d++)c.push(o+d*(r-o)/(h+1));const l=c.map(d=>{const u=Yt(d);return Math.floor((t+1)*u/e)});for(let d=0;d<h;d++){const u=new Float32Array(s),m=l[d],f=l[d+1],g=l[d+2];for(let p=m;p<f;p++)f!==m&&(u[p]=(p-m)/(f-m));for(let p=f;p<g;p++)g!==f&&(u[p]=(g-p)/(g-f));a.push(u)}return a}function Jt(h,t,e){if(h.length===0)return new Float32Array(0);const n=1/(2*Math.PI*t),i=1/e,s=n/(n+i),a=new Float32Array(h.length);a[0]=h[0];for(let o=1;o<h.length;o++)a[o]=s*(a[o-1]+h[o]-h[o-1]);return a}function Bt(h,t,e){if(h.length===0)return new Float32Array(0);const n=Math.round(t/1e3*e);if(n<=1)return new Float32Array(h);const i=n/6,s=n,a=new Float32Array(s),o=Math.floor(s/2);let r=0;for(let l=0;l<s;l++){const d=l-o;a[l]=Math.exp(-(d*d)/(2*i*i)),r+=a[l]}for(let l=0;l<s;l++)a[l]/=r;const c=new Float32Array(h.length);for(let l=0;l<h.length;l++){let d=0;for(let u=0;u<s;u++){const m=l+u-o,f=m<0?-m:m>=h.length?2*h.length-m-2:m,g=Math.max(0,Math.min(h.length-1,f));d+=h[g]*a[u]}c[l]=d}return c}function jt(h){if(h.length===0)return 0;let t=0;for(let s=0;s<h.length;s++)t+=h[s];const e=t/h.length;let n=0;for(let s=0;s<h.length;s++){const a=h[s]-e;n+=a*a}const i=n/h.length;return Math.sqrt(i)}function Zt(h){const t=h.length,e=Math.pow(2,Math.ceil(Math.log2(t))),n=new Float32Array(e),i=new Float32Array(e);for(let r=0;r<t;r++){const c=.5-.5*Math.cos(2*Math.PI*r/(t-1));n[r]=h[r]*c}let s=0;for(let r=0;r<e-1;r++){r<s&&([n[r],n[s]]=[n[s],n[r]],[i[r],i[s]]=[i[s],i[r]]);let c=e/2;for(;s>=c;)s-=c,c/=2;s+=c}let a=2;for(;a<=e;){const r=-2*Math.PI/a,c=Math.cos(r),l=Math.sin(r);for(let d=0;d<e;d+=a){let u=1,m=0;for(let f=0;f<a/2;f++){const g=d+f,p=d+f+a/2,b=n[p]*u-i[p]*m,y=n[p]*m+i[p]*u;n[p]=n[g]-b,i[p]=i[g]-y,n[g]+=b,i[g]+=y;const B=u*c-m*l;m=u*l+m*c,u=B}}a*=2}const o=new Float32Array(e/2+1);for(let r=0;r<o.length;r++){const c=n[r],l=i[r];o[r]=Math.sqrt(c*c+l*l)}return o}function Tt(h,t,e,n){const i=[];let s=0;for(;s+t<=h.length;){const a=h.slice(s,s+t),o=Zt(a);i.push(o),s+=e}return{frames:i,numFrames:i.length,fftSize:t,hopSize:e,sampleRate:n}}const Xt=[{name:"low",lowHz:20,highHz:500,description:"Low frequencies (bass, kick, sub)"},{name:"mid",lowHz:500,highHz:2e3,description:"Mid frequencies (vocals, snare body, lead instruments)"},{name:"high",lowHz:2e3,highHz:2e4,description:"High frequencies (hi-hats, cymbals, harmonics, air)"}];function te(h,t){const e=Math.PI*(2*h-1)/(2*t);return 1/(2*Math.sin(e))}function an(h,t,e,n){const i=2*Math.PI*h/t,s=Math.cos(i),a=Math.sin(i),o=te(e,n),r=a/(2*o),c=1+r,l=(1-s)/2/c,d=(1-s)/c,u=(1-s)/2/c,m=-2*s/c,f=(1-r)/c;return{b0:l,b1:d,b2:u,a1:m,a2:f}}function rn(h,t,e,n){const i=2*Math.PI*h/t,s=Math.cos(i),a=Math.sin(i),o=te(e,n),r=a/(2*o),c=1+r,l=(1+s)/2/c,d=-(1+s)/c,u=(1+s)/2/c,m=-2*s/c,f=(1-r)/c;return{b0:l,b1:d,b2:u,a1:m,a2:f}}function At(h,t){const{b0:e,b1:n,b2:i,a1:s,a2:a}=t,o=new Float32Array(h.length);o[0]=e*h[0],h.length>1&&(o[1]=e*h[1]+n*h[0]-s*o[0]);for(let r=2;r<h.length;r++)o[r]=e*h[r]+n*h[r-1]+i*h[r-2]-s*o[r-1]-a*o[r-2];return o}function on(h,t,e,n,i){if(h.length===0)return new Float32Array(0);const s=8;if(t>=e)throw new Error(`Low frequency (${t} Hz) must be less than high frequency (${e} Hz)`);if(e>=n/2)throw new Error(`High frequency (${e} Hz) must be less than Nyquist frequency (${n/2} Hz)`);const a=s/2;let o=new Float32Array(h);for(let r=1;r<=a;r++){const c=rn(t,n,r,s);o=At(o,c)}for(let r=1;r<=a;r++){const c=an(e,n,r,s);o=At(o,c)}return o}function cn(h,t,e,n){const i=Xt.find(s=>s.name===t);if(!i)throw new Error(`Unknown frequency band: ${t}. Valid bands are: low, mid, high`);return on(h,i.lowHz,i.highHz,e)}const ln={targetSampleRate:44100,fftWindowSizeMs:23,hopSizeMs:10,smoothWindowMs:10,peakThreshold:.3,bands:Xt};class ee{constructor(t={}){if(this.config={...ln,...t},this.config.peakThreshold<0||this.config.peakThreshold>1)throw new Error(`peakThreshold must be between 0 and 1, got: ${this.config.peakThreshold}`);if(this.config.bands.length===0)throw new Error("At least one frequency band must be specified")}getConfig(){return{...this.config}}analyze(t){const e=t.duration,n=this.config.targetSampleRate,i=X(t,n),s=Math.pow(2,Math.ceil(Math.log2(this.config.fftWindowSizeMs/1e3*n))),a=Math.round(this.config.hopSizeMs/1e3*n),o=this.config.hopSizeMs/1e3,r=1/o,c=new Map,l=[];for(const f of this.config.bands){const g=this.analyzeBand(i.data,f,n,s,a,o,r);c.set(f.name,g),l.push(g.energyOverTime)}const d=l[0]?.length??0,u=this.combineEnergyProfiles(l,d),m=this.calculateDominantBands(c);return{bands:c,dominantBands:m,energyProfile:u,metadata:{numFrames:d,duration:e,hopSizeSeconds:o,effectiveSampleRate:n,bandsAnalyzed:this.config.bands.map(f=>f.name)}}}analyzeBand(t,e,n,i,s,a,o){const r=cn(t,e.name,n),c=Tt(r,i,s,n),l=c.numFrames,d=new Float32Array(l);for(let M=0;M<l;M++){const T=c.frames[M];let S=0;for(let v=0;v<T.length;v++)S+=T[v]*T[v];d[M]=Math.sqrt(S/T.length)}const u=Math.max(...d);if(u>0)for(let M=0;M<d.length;M++)d[M]/=u;const m=u,f=this.calculateOnsetEnvelope(c.frames),g=Bt(f,this.config.smoothWindowMs,o),p=Math.max(...g),b=new Float32Array(g.length);if(p>0)for(let M=0;M<g.length;M++)b[M]=g[M]/p;const y=this.findPeaks(b,this.config.peakThreshold),B=y.map(M=>M*a);return{name:e.name,frequencyRange:{lowHz:e.lowHz,highHz:e.highHz},envelope:b,peaks:y,peakTimes:B,energy:m,energyOverTime:d}}calculateOnsetEnvelope(t){const e=t.length,n=new Float32Array(e);n[0]=0;for(let i=1;i<e;i++){const s=t[i],a=t[i-1];let o=0;for(let r=0;r<s.length;r++){const c=s[r]-a[r];c>0&&(o+=c)}n[i]=o}return n}findPeaks(t,e){const n=[];for(let i=1;i<t.length-1;i++)t[i]>t[i-1]&&t[i]>t[i+1]&&t[i]>=e&&n.push(i);return n}combineEnergyProfiles(t,e){const n=new Float32Array(e);for(let i=0;i<e;i++){let s=0;for(const a of t)i<a.length&&a[i]>s&&(s=a[i]);n[i]=s}return n}calculateDominantBands(t){const e=[];for(const[n,i]of t)e.push({name:n,energy:i.energy});return e.sort((n,i)=>i.energy-n.energy),e.map(n=>n.name)}}const it={low:{threshold:.5,minInterval:.1,adaptiveThresholding:!1},mid:{threshold:.3,minInterval:.08,adaptiveThresholding:!1},high:{threshold:.25,minInterval:.06,adaptiveThresholding:!1}},dn={baseThreshold:.3,adaptiveThresholding:!1,adaptiveWindowSize:50,minTransientInterval:.02};class ne{constructor(t={}){const{bands:e,bandConfig:n,...i}=t,s={low:{...it.low,...n?.low},mid:{...it.mid,...n?.mid},high:{...it.high,...n?.high}};if(this.config={...dn,...i,bandConfig:s},e!==void 0&&(this.config.bands=e),this.config.baseThreshold<0||this.config.baseThreshold>1)throw new Error(`baseThreshold must be between 0 and 1, got: ${this.config.baseThreshold}`);if(this.config.adaptiveWindowSize<1)throw new Error(`adaptiveWindowSize must be at least 1, got: ${this.config.adaptiveWindowSize}`);if(this.config.minTransientInterval<0)throw new Error(`minTransientInterval must be non-negative, got: ${this.config.minTransientInterval}`);for(const a of["low","mid","high"]){const o=this.config.bandConfig[a];if(o.threshold<0||o.threshold>1)throw new Error(`${a} band threshold must be between 0 and 1, got: ${o.threshold}`);if(o.minInterval<0)throw new Error(`${a} band minInterval must be non-negative, got: ${o.minInterval}`)}}getConfig(){const{bandConfig:t,...e}=this.config;return{...e,bandConfig:{low:{...t.low},mid:{...t.mid},high:{...t.high}}}}getBandConfig(){return{low:{...this.config.bandConfig.low},mid:{...this.config.bandConfig.mid},high:{...this.config.bandConfig.high}}}detect(t){const e=new Map,n=[],i=new Set;for(const[o,r]of t.bands){const c=this.detectBandTransients(o,r,t.metadata.hopSizeSeconds);e.set(o,c),n.push(...c),c.forEach(l=>i.add(l.detectionMethod))}n.sort((o,r)=>o.timestamp-r.timestamp);const s=new Map;for(const[o,r]of e)s.set(o,r.length);const a=n.length>0?n.reduce((o,r)=>o+r.intensity,0)/n.length:0;return{transients:n,bandTransients:e,metadata:{totalTransients:n.length,transientsPerBand:s,duration:t.metadata.duration,averageIntensity:a,detectionMethodsUsed:Array.from(i)}}}detectBandTransients(t,e,n){const i=this.config.bandConfig[t],s=this.getDetectionMethod(t),a=s==="energy"?e.energyOverTime:e.envelope;if(!a||a.length===0)return[];const o=i.adaptiveThresholding?this.calculateAdaptiveThreshold(a,i.threshold):i.threshold,c=this.findPeaks(a,o).map(d=>({timestamp:d*n,intensity:a[d],band:t,detectionMethod:s}));return this.applyNonMaximumSuppression(c,i.minInterval)}applyNonMaximumSuppression(t,e){if(t.length===0)return[];const n=[...t].sort((s,a)=>a.intensity-s.intensity),i=[];for(const s of n){let a=!1;for(const o of i)if(Math.abs(s.timestamp-o.timestamp)<e){a=!0;break}a||i.push(s)}return i.sort((s,a)=>s.timestamp-a.timestamp),i}getDetectionMethod(t){switch(t){case"low":return"energy";case"mid":return"spectral_flux";case"high":return"hfc";default:return"spectral_flux"}}calculateAdaptiveThreshold(t,e){const n=e??this.config.baseThreshold;if(t.length===0)return n;let i=0,s=0;for(let u=0;u<t.length;u++)i+=t[u],t[u]>s&&(s=t[u]);const a=i/t.length;let o=0;for(let u=0;u<t.length;u++){const m=t[u]-a;o+=m*m}const r=Math.sqrt(o/t.length),l=1+(a>0?r/a:0)*.5,d=n*l;return Math.max(.1,Math.min(.9,d))}findPeaks(t,e){const n=[];for(let i=1;i<t.length-1;i++)t[i]>t[i-1]&&t[i]>t[i+1]&&t[i]>=e&&n.push(i);return n}}const q={densityValidation:{maxRetries:0,baseSensitivityReduction:.1,maxCumulativeReduction:.5},minimumTransientIntensity:0,bands:[]};class St{constructor(t={}){this.config={densityValidation:{maxRetries:t.densityValidation?.maxRetries??q.densityValidation.maxRetries,baseSensitivityReduction:t.densityValidation?.baseSensitivityReduction??q.densityValidation.baseSensitivityReduction,maxCumulativeReduction:t.densityValidation?.maxCumulativeReduction??q.densityValidation.maxCumulativeReduction},minimumTransientIntensity:t.minimumTransientIntensity??q.minimumTransientIntensity,bands:t.bands??q.bands}}getConfig(){return{...this.config}}quantize(t,e,n){const i=this.splitTransientsByBand(t.transients),s=e.quarterNoteInterval/6,a=this.processBand(i.low,"low",s),o=this.processBand(i.mid,"mid",s),r=this.processBand(i.high,"high",s),c={low:this.quantizeBand(a.filteredTransients,e,"low",n),mid:this.quantizeBand(o.filteredTransients,e,"mid",n),high:this.quantizeBand(r.filteredTransients,e,"high",n)},l=a.filteredCount+o.filteredCount+r.filteredCount,d=this.aggregateDensityResults([a.densityResult,o.densityResult,r.densityResult],s);return{streams:c,metadata:{densityValidation:d,transientsFilteredByIntensity:l,transientsFilteredByBand:{low:a.filteredCount,mid:o.filteredCount,high:r.filteredCount}}}}splitTransientsByBand(t){return{low:t.filter(e=>e.band==="low"),mid:t.filter(e=>e.band==="mid"),high:t.filter(e=>e.band==="high")}}processBand(t,e,n){const i=this.config.densityValidation.maxRetries,s=this.config.densityValidation.baseSensitivityReduction,a=this.config.densityValidation.maxCumulativeReduction;let o=0,r=t;if(this.config.minimumTransientIntensity>0){const m=r.length;r=r.filter(f=>f.intensity>=this.config.minimumTransientIntensity),o=m-r.length}let c=this.config.minimumTransientIntensity,l=0,d=0;for(;d<=i;){const m=this.validateBandDensity(r,e,n,d,l);if(m.isValid)return{filteredTransients:r,filteredCount:o,densityResult:m};if(d>=i)return console.warn(`[${e}] Density validation: Max retries (${i}) reached. Proceeding with ${r.length} transients. Min interval: ${(m.minIntervalDetected*1e3).toFixed(1)}ms (required: ${(n*1e3).toFixed(1)}ms)`),{filteredTransients:r,filteredCount:o,densityResult:m};d++;const f=Math.min(s,a-l);l+=f,c=Math.min(this.config.minimumTransientIntensity+l,1);const g=r.length;r=r.filter(b=>b.intensity>=c);const p=g-r.length;o+=p,console.warn(`[${e}] Density validation retry ${d}: Threshold increased to ${(c*100).toFixed(1)}%, Filtered ${p} transients, ${r.length} remaining`)}const u=this.validateBandDensity(r,e,n,d,l);return{filteredTransients:r,filteredCount:o,densityResult:u}}validateBandDensity(t,e,n,i,s,a=this.config.minimumTransientIntensity){const o=t.length,r=Math.min(this.config.minimumTransientIntensity+s,1);if(t.length===0)return{band:e,isValid:!0,minIntervalDetected:1/0,requiredMinInterval:n,retryCount:i,sensitivityReduction:s,finalIntensityThreshold:r,transientsRemaining:o};const c=[...t].sort((u,m)=>u.timestamp-m.timestamp);let l=1/0;for(let u=1;u<c.length;u++){const m=c[u].timestamp-c[u-1].timestamp;m<l&&(l=m)}const d=l>=n;return{band:e,isValid:d,minIntervalDetected:l,requiredMinInterval:n,retryCount:i,sensitivityReduction:s,finalIntensityThreshold:r,transientsRemaining:o}}aggregateDensityResults(t,e){let n=0,i=0,s=1/0,a=!0;for(const o of t)o.retryCount>n&&(n=o.retryCount),o.sensitivityReduction>i&&(i=o.sensitivityReduction),o.minIntervalDetected<s&&(s=o.minIntervalDetected),o.isValid||(a=!1);return{isValid:a,bands:{low:t.find(o=>o.band==="low"),mid:t.find(o=>o.band==="mid"),high:t.find(o=>o.band==="high")},maxRetryCount:n,maxSensitivityReduction:i}}decideGrids(t,e,n){const i=[],s=e.quarterNoteInterval,a=this.getBandGridType(n),o=[...t].sort((r,c)=>r.timestamp-c.timestamp);for(let r=0;r<e.beats.length;r++){const c=e.beats[r],l=c.timestamp,d=r<e.beats.length-1?e.beats[r+1].timestamp:c.timestamp+s,u=o.filter(m=>m.timestamp>=l&&m.timestamp<d);u.length!==0&&(a?i.push({beatIndex:r,selectedGrid:a,transientCount:u.length,confidence:1}):i.push(this.detectGrid(u,c,r,s)))}return i}quantizeToGrids(t,e,n,i){const s=[],a=e.quarterNoteInterval,o=[...t].sort((c,l)=>c.timestamp-l.timestamp),r=new Map;for(const c of i)r.set(c.beatIndex,c);for(let c=0;c<e.beats.length;c++){const l=e.beats[c],d=r.get(c);if(!d)continue;const u=l.timestamp,m=c<e.beats.length-1?e.beats[c+1].timestamp:l.timestamp+a,f=o.filter(g=>g.timestamp>=u&&g.timestamp<m);for(const g of f){const p=this.quantizeTransient(g,l,c,d.selectedGrid,a);p&&s.push(p)}}return s}quantizeBand(t,e,n,i){const s=i?i(t,e,n):this.decideGrids(t,e,n),a=this.quantizeToGrids(t,e,n,s),o=this.deduplicateBeats(a);return{audioId:e.audioId,duration:e.duration,beats:o,gridDecisions:s,quarterNoteInterval:e.quarterNoteInterval}}deduplicateBeats(t){const e=new Map;for(const n of t){const i=`${n.beatIndex}:${n.gridPosition}:${n.gridType}`,s=e.get(i);(!s||n.intensity>s.intensity)&&e.set(i,n)}return Array.from(e.values()).sort((n,i)=>n.timestamp-i.timestamp)}getBandGridType(t){switch(t){case"low":return"straight_8th";case"mid":case"high":return null}}detectGrid(t,e,n,i){const s=this.calculateStraightGrid(e.timestamp,i),a=this.calculateTripletGrid(e.timestamp,i);let o=0,r=0,c=0;for(const f of t){const g=this.calculateOffsetFromGrid(f,s),p=this.calculateOffsetFromGrid(f,a);o+=g,r+=p,c++}const l=c>0?o/c:0,d=c>0?r/c:0,u=l<=d?"straight_16th":"triplet_8th",m=Math.abs(l-d);return{beatIndex:n,selectedGrid:u,straightAvgOffset:l,tripletAvgOffset:d,transientCount:c,confidence:m}}calculateStraightGrid(t,e){const n=[],i=e/4;for(let s=0;s<4;s++)n.push(t+s*i);return n}calculateTripletGrid(t,e){const n=[],i=e/3;for(let s=0;s<3;s++)n.push(t+s*i);return n}calculate8thGrid(t,e){const n=[],i=e/2;for(let s=0;s<2;s++)n.push(t+s*i);return n}calculateOffsetFromGrid(t,e){let n=1/0;for(const i of e){const s=Math.abs(t.timestamp-i);s<n&&(n=s)}return n*1e3}quantizeTransient(t,e,n,i,s){let a,o;switch(i){case"straight_8th":a=1,o=s/2;break;case"straight_16th":a=3,o=s/4;break;case"triplet_8th":a=2,o=s/3;break}const r=Math.round((t.timestamp-e.timestamp)/o);if(r<0||r>a)return null;const c=e.timestamp+r*o,l=Math.abs(t.timestamp-c)*1e3;return{timestamp:c,detectedTimestamp:t.timestamp,beatIndex:n,gridPosition:r,gridType:i,intensity:t.intensity,band:t.band,quantizationError:l}}}class ie{constructor(t={}){this.id="high-bpm-grid-restriction",this.description="Restricts 16th notes and triplets to 8th notes at high BPMs for playability",this.restrict16thBpm=t.restrict16thBpm??160,this.restrictTripletBpm=t.restrictTripletBpm??200}applies(t,e){return e.band==="low"?!1:t>=this.restrict16thBpm}apply(t,e){const{bpm:n}=e,i=n>=this.restrictTripletBpm;return t.map(s=>{const{selectedGrid:a}=s;return a==="straight_8th"?s:a==="straight_16th"&&n>=this.restrict16thBpm?{...s,selectedGrid:"straight_8th",confidence:1,straightAvgOffset:void 0,tripletAvgOffset:void 0}:a==="triplet_8th"&&i?{...s,selectedGrid:"straight_8th",confidence:1,straightAvgOffset:void 0,tripletAvgOffset:void 0}:s})}}const vt={rules:[new ie],enabled:!0};class se{constructor(t=vt,e){this.config=t,this.rhythmQuantizer=e??new St}getConfig(){return{...this.config}}decideGrids(t,e,n){const i=this.rhythmQuantizer.decideGrids(t,e,n),s={bpm:e.quarterNoteBpm,quarterNoteInterval:e.quarterNoteInterval,band:n,transients:t};return this.applyRules(i,s)}applyRules(t,e){if(this.config.enabled===!1)return t;let n=t;for(const i of this.config.rules)i.applies(e.bpm,e)&&(n=i.apply(n,e));return n}}const hn={phraseSizes:[1,2,4,8],minOccurrences:3,topSignificantCount:10,includePhrasesWithoutVariation:!1,minNotesPerPhrase:h=>1+h};class ae{constructor(t={}){this.config={...hn,...t}}analyze(t){const e={low:this.analyzeBand(t.low,"low"),mid:this.analyzeBand(t.mid,"mid"),high:this.analyzeBand(t.high,"high")},n=[...e.low.phrases,...e.mid.phrases,...e.high.phrases],i=new Map;i.set("low",e.low.phrases),i.set("mid",e.mid.phrases),i.set("high",e.high.phrases);const s=new Map;for(const c of this.config.phraseSizes){const l=n.filter(d=>d.sizeInBeats===c);l.length>0&&s.set(c,l)}const o=[...n].sort((c,l)=>l.significance-c.significance).slice(0,this.config.topSignificantCount),r=n.filter(c=>c.hasVariation&&c.availableForReuse);return{phrases:n,phrasesByBand:i,mostSignificantPhrases:o,phrasesBySize:s,patternLibrary:r,bandAnalysis:e}}getMinNotes(t){return typeof this.config.minNotesPerPhrase=="function"?this.config.minNotesPerPhrase(t):typeof this.config.minNotesPerPhrase=="number"?this.config.minNotesPerPhrase:1+t}analyzeBand(t,e){const n=Math.max(...t.beats.map(r=>r.beatIndex),0),i=new Map;for(const r of this.config.phraseSizes)for(let c=0;c<=n-r+1;c++){const l=this.extractPhraseCandidate(t,c,r,e);if(l){const d=i.get(l.hash);d?d.push(l):i.set(l.hash,[l])}}const s=[];for(const[r,c]of i){if(c.length<this.config.minOccurrences)continue;const l=c[0];if(l.pattern.length<this.getMinNotes(l.sizeInBeats))continue;const d=this.hasPatternVariation(l.pattern,l.sizeInBeats);if(!d&&!this.config.includePhrasesWithoutVariation)continue;const u=c.map(g=>({beatIndex:g.startBeatIndex,startTimestamp:g.startTimestamp,endTimestamp:g.endTimestamp})),m=this.calculateSignificance(l.sizeInBeats,c.length),f=d&&c.length>=this.config.minOccurrences;s.push({id:r,pattern:l.pattern,sizeInBeats:l.sizeInBeats,sourceBand:e,occurrences:u,significance:m,hasVariation:d,availableForReuse:f})}s.sort((r,c)=>c.significance-r.significance);const a=new Map;for(const r of this.config.phraseSizes){const c=s.filter(l=>l.sizeInBeats===r);c.length>0&&a.set(r,c)}const o=s.filter(r=>r.hasVariation);return{band:e,phrases:s,phrasesBySize:a,phrasesWithVariation:o}}extractPhraseCandidate(t,e,n,i){const s=e+n-1,a=t.beats.filter(d=>d.beatIndex>=e&&d.beatIndex<=s);if(a.length===0)return null;const o=a.map(d=>({...d,beatIndex:d.beatIndex-e})),r=this.hashPattern(o,n),c=Math.min(...a.map(d=>d.timestamp)),l=Math.max(...a.map(d=>d.timestamp));return{hash:r,pattern:o,sizeInBeats:n,startBeatIndex:e,startTimestamp:c,endTimestamp:l}}hashPattern(t,e){const i=[...t].sort((s,a)=>s.beatIndex!==a.beatIndex?s.beatIndex-a.beatIndex:s.gridPosition-a.gridPosition).map(s=>`${s.beatIndex}:${s.gridPosition}:${s.gridType}`);return`phrase_${e}_${i.join("|")}`}hasPatternVariation(t,e){if(t.length===0)return!1;if(t.some(o=>o.gridType==="triplet_8th")||t.some(o=>o.gridPosition===1||o.gridPosition===3))return!0;const n=t.map(o=>o.intensity),i=Math.max(...n),s=Math.min(...n);if(i-s>.1)return!0;if(t.length===e&&t.every(r=>r.gridPosition===0))return!1;const a=new Set(t.map(o=>o.gridPosition));return!(a.size===2&&a.has(0)&&a.has(2)&&this.countBeatsWithNoteCount(t,2)===e)}countBeatsWithNoteCount(t,e){const n=new Map;for(const s of t){const a=n.get(s.beatIndex)??0;n.set(s.beatIndex,a+1)}let i=0;for(const s of n.values())s===e&&i++;return i}calculateSignificance(t,e){const n=t,i=Math.log2(e+1);return n*i}}const un={beatsPerSection:8,sparseThreshold:1,denseThreshold:1.5};class re{constructor(t={}){this.config={...un,...t}}analyze(t,e,n){const i=e/60,s={low:this.analyzeBand(t.streams.low,"low",i,n),mid:this.analyzeBand(t.streams.mid,"mid",i,n),high:this.analyzeBand(t.streams.high,"high",i,n)};[...t.streams.low.beats,...t.streams.mid.beats,...t.streams.high.beats];const a=this.calculateCombinedPerBeatDensity(t.streams.low,t.streams.mid,t.streams.high),o=this.calculateCombinedMetrics(a,i,n),r=this.calculateSectionMetrics(a,i,n);return{bandMetrics:s,combinedMetrics:o,sections:r,perBeatDensity:a}}analyzeBand(t,e,n,i){const s=t.beats,o=(s.length>0?Math.max(...s.map(y=>y.beatIndex)):0)+1,r=new Map;for(const y of s){const B=r.get(y.beatIndex);B?(B.count++,B.intensities.push(y.intensity)):r.set(y.beatIndex,{count:1,intensities:[y.intensity]})}const c=[];let l=0;for(let y=0;y<o;y++){const B=r.get(y),M=B?.count??0,T=B?B.intensities.reduce((S,v)=>S+v,0)/B.intensities.length:0;c.push({beatIndex:y,transientCount:M,bands:M>0?[e]:[],averageIntensity:T}),l+=M}const d=c.map(y=>y.transientCount);let u;i&&i>0?u=l/i:u=o>0?l/o*n:0;const m=d.length>0?Math.min(...d)*n:0,f=d.length>0?Math.max(...d)*n:0,g=this.calculateVariance(d,u/n)*n*n,p=this.categorizeDensity(u),b=this.determineNaturalDifficulty(p);return{band:e,totalBeats:o,totalTransients:l,notesPerSecond:u,minNotesPerSecond:m,maxNotesPerSecond:f,variance:g,densityCategory:p,naturalDifficulty:b,perBeatDensity:c}}calculateCombinedPerBeatDensity(t,e,n){const i=[...t.beats,...e.beats,...n.beats],a=(i.length>0?Math.max(...i.map(c=>c.beatIndex)):0)+1,o=new Map;for(const c of t.beats)this.addToBeatData(o,c,"low");for(const c of e.beats)this.addToBeatData(o,c,"mid");for(const c of n.beats)this.addToBeatData(o,c,"high");const r=[];for(let c=0;c<a;c++){const l=o.get(c);if(l){const d=l.intensities.length>0?l.intensities.reduce((u,m)=>u+m,0)/l.intensities.length:0;r.push({beatIndex:c,transientCount:l.count,bands:Array.from(l.bands),averageIntensity:d})}else r.push({beatIndex:c,transientCount:0,bands:[],averageIntensity:0})}return r}addToBeatData(t,e,n){const i=t.get(e.beatIndex);if(i)i.count++,i.bands.add(n),i.intensities.push(e.intensity);else{const s=new Set;s.add(n),t.set(e.beatIndex,{count:1,bands:s,intensities:[e.intensity]})}}calculateCombinedMetrics(t,e,n){const i=t.reduce((r,c)=>r+c.transientCount,0);let s;if(n&&n>0)s=i/n;else{const r=t.length;s=r>0?i/r*e:0}const a=this.categorizeDensity(s),o=this.determineNaturalDifficulty(a);return{totalTransients:i,notesPerSecond:s,densityCategory:a,naturalDifficulty:o}}calculateSectionMetrics(t,e,n){const i=[],s=this.config.beatsPerSection,a=t.length;for(let o=0;o<a;o+=s){const r=Math.min(o+s-1,a-1),c=t.slice(o,r+1),l=c.reduce((y,B)=>y+B.transientCount,0),d=c.length,u=d>0?l/d*e:0,m=c.map(y=>y.transientCount),f=m.length>0?Math.min(...m)*e:0,g=m.length>0?Math.max(...m)*e:0,p=this.categorizeDensity(u),b=this.determineNaturalDifficulty(p);i.push({startBeat:o,endBeat:r,beatCount:d,totalTransients:l,notesPerSecond:u,minNotesPerSecond:f,maxNotesPerSecond:g,densityCategory:p,naturalDifficulty:b})}return i}categorizeDensity(t){return t<this.config.sparseThreshold?"sparse":t>this.config.denseThreshold?"dense":"moderate"}determineNaturalDifficulty(t){switch(t){case"sparse":return"easy";case"moderate":return"medium";case"dense":return"hard"}}calculateVariance(t,e){return t.length===0?0:t.map(i=>Math.pow(i-e,2)).reduce((i,s)=>i+s,0)/t.length}getConfig(){return{...this.config}}}const oe={beatsPerSection:8,ioiVarianceWeight:.3,syncopationWeight:.3,phraseSignificanceWeight:.25,densityWeight:.15,offbeatGridPositions:{straight_16th:[1,3],triplet_8th:[1,2],straight_8th:[1]},bandBiasWeights:{low:.8,mid:.95,high:1}},mn={low:.8,mid:.95,high:1},fn={ddr:{ioiVarianceWeight:.2,syncopationWeight:.15,phraseSignificanceWeight:.35,densityWeight:.3},guitar_hero:{ioiVarianceWeight:.3,syncopationWeight:.3,phraseSignificanceWeight:.25,densityWeight:.15},tap:{ioiVarianceWeight:.3,syncopationWeight:.2,phraseSignificanceWeight:.3,densityWeight:.2}};function gn(h){const t=fn[h];return{...oe,...t,bandBiasWeights:{...mn}}}class ce{constructor(t={}){this.config={...oe,...t}}score(t,e,n){const i=[],s={low:[],mid:[],high:[]},a=[...t.streams.low.beats,...t.streams.mid.beats,...t.streams.high.beats],o=a.length>0?Math.max(...a.map(m=>m.beatIndex)):0,r=o+1,c=["low","mid","high"];for(let m=0;m<r;m+=this.config.beatsPerSection){const f=Math.min(m+this.config.beatsPerSection-1,o),g={start:m,end:f};for(const p of c){const b=this.scoreSection(t.streams[p],p,g,e,n);i.push(b),s[p].push(b.score)}}const l={low:s.low.reduce((m,f)=>m+f,0),mid:s.mid.reduce((m,f)=>m+f,0),high:s.high.reduce((m,f)=>m+f,0)},d={low:s.low.length>0?l.low/s.low.length:0,mid:s.mid.length>0?l.mid/s.mid.length:0,high:s.high.length>0?l.high/s.high.length:0},u=this.determineSectionWinners(i);return{sectionScores:i,bandTotals:l,bandAverages:d,sectionWinners:u,config:{...this.config}}}scoreSection(t,e,n,i,s){const a=t.beats.filter(u=>u.beatIndex>=n.start&&u.beatIndex<=n.end),o=this.calculateIOIVariance(a),r=this.calculateSyncopationLevel(a),c=this.calculatePhraseSignificance(i,e,n),l=this.calculateDensityFactor(s,e,n);let d=o*this.config.ioiVarianceWeight+r*this.config.syncopationWeight+c*this.config.phraseSignificanceWeight+l*this.config.densityWeight;if(this.config.bandBiasWeights){const u=this.config.bandBiasWeights[e]??1;d*=u}return{beatRange:n,band:e,score:d,factors:{ioiVariance:o,syncopationLevel:r,phraseSignificance:c,densityFactor:l}}}calculateIOIVariance(t){if(t.length<2)return 0;const e=[...t].sort((r,c)=>r.timestamp-c.timestamp),n=[];for(let r=1;r<e.length;r++)n.push(e[r].timestamp-e[r-1].timestamp);if(n.length===0)return 0;const i=n.reduce((r,c)=>r+c,0)/n.length,s=n.reduce((r,c)=>r+Math.pow(c-i,2),0)/n.length,a=Math.sqrt(s),o=i>0?a/i:0;return Math.min(o,1)}calculateSyncopationLevel(t){if(t.length===0)return 0;let e=0,n=0;for(const i of t){const a=this.config.offbeatGridPositions[i.gridType].includes(i.gridPosition),o=i.intensity;a&&(e+=o),n+=o}return n===0?0:e/n}calculatePhraseSignificance(t,e,n){const i=t.phrasesByBand.get(e)??[];if(i.length===0)return 0;let s=0,a=0;for(const r of i){a=Math.max(a,r.significance);for(const c of r.occurrences){const l=c.beatIndex+r.sizeInBeats-1;if(c.beatIndex<=n.end&&l>=n.start){const d=Math.max(c.beatIndex,n.start),f=(Math.min(l,n.end)-d+1)/r.sizeInBeats;s+=r.significance*f;break}}}if(a===0)return 0;const o=s/a;return Math.min(o,1)}calculateDensityFactor(t,e,n){const a=t.bandMetrics[e].perBeatDensity.filter(m=>m.beatIndex>=n.start&&m.beatIndex<=n.end);if(a.length===0)return 0;const o=a.reduce((m,f)=>m+f.transientCount,0)/a.length,r=this.config.bpm!=null?this.config.bpm/60:1,c=o*r;return Math.exp(-Math.pow(c-1,2)/(2*Math.pow(.75,2)))}determineSectionWinners(t){const e=new Map;for(const i of t){const s=`${i.beatRange.start}-${i.beatRange.end}`,a=e.get(s);a?a.push(i):e.set(s,[i])}const n=[];for(const[,i]of e){if(i.length===0)continue;const s=[...i].sort((c,l)=>l.score-c.score),a=s[0],o=s[1],r=o?a.score-o.score:a.score;n.push({beatRange:a.beatRange,winner:a.band,score:a.score,margin:r})}return n.sort((i,s)=>i.beatRange.start-s.beatRange.start),n}getConfig(){return{...this.config}}updateConfig(t){this.config={...this.config,...t}}}const pn={transitionOverlapBeats:0,preserveGridDecisions:!0},yn=1,bn=1.5;class le{constructor(t={}){this.config={...pn,...t}}generate(t,e,n,i){const s=e.sectionWinners,a={low:0,mid:0,high:0},o={low:0,mid:0,high:0},c=s.filter(b=>{const y=["low","mid","high"];let B=!1;for(const M of y)if(t.streams[M].beats.filter(v=>v.beatIndex>=b.beatRange.start&&v.beatIndex<=b.beatRange.end).length>0){B=!0;break}return B}).map(b=>({beatRange:b.beatRange,sourceBand:b.winner,score:b.score,margin:b.margin}));for(const b of c)o[b.sourceBand]++;const l=[];for(const b of c){const y=t.streams[b.sourceBand],B=this.extractSectionBeats(y,b.beatRange,b.sourceBand);l.push(...B),a[b.sourceBand]+=B.length}l.sort((b,y)=>b.timestamp-y.timestamp);const d=this.deduplicateBeats(l),u=t.streams.low.quarterNoteInterval,m=60/u,f=this.determineNaturalDifficulty(d,n,m,i),g=c.length,p={totalBeats:d.length,sectionCount:g,beatsPerBand:a,sectionsPerBand:{low:g>0?o.low/g:0,mid:g>0?o.mid/g:0,high:g>0?o.high/g:0}};return{beats:d,sections:c,naturalDifficulty:f,quarterNoteInterval:u,metadata:p}}extractSectionBeats(t,e,n){return t.beats.filter(i=>i.beatIndex>=e.start&&i.beatIndex<=e.end).map(i=>({...i,sourceBand:n}))}deduplicateBeats(t){const e=new Map;for(const n of t){const i=Math.round(n.timestamp*1e3),s=e.get(i);(!s||n.intensity>s.intensity)&&e.set(i,n)}return Array.from(e.values()).sort((n,i)=>n.timestamp-i.timestamp)}determineNaturalDifficulty(t,e,n,i){if(t.length===0)return"easy";let s;if(i&&i>0)s=t.length/i;else{const o=Math.max(...t.map(r=>r.beatIndex))+1;s=t.length/o*(n/60)}return s<yn?"easy":s>bn?"hard":"medium"}getConfig(){return{...this.config}}}const tt={strongBeatEmphasis:"natural",downbeatProximityRange:2,fillEmptyMeasures:!0,addedBeatIntensity:.45,marginSeconds:.5},Mn={ddr:{strongBeatEmphasis:"natural",downbeatProximityRange:1,fillEmptyMeasures:!0,addedBeatIntensity:.45,marginSeconds:.5},guitar_hero:{strongBeatEmphasis:"natural",downbeatProximityRange:2,fillEmptyMeasures:!0,addedBeatIntensity:.45,marginSeconds:.5},tap:{strongBeatEmphasis:"natural",downbeatProximityRange:1.5,fillEmptyMeasures:!0,addedBeatIntensity:.45,marginSeconds:.5}};function Bn(h){return{...Mn[h]}}function de(h){return h%3===0?3:2}function he(h,t){return h%t===0}function ue(h,t){return h%t!==0}function me(h,t){let e=h[0];for(const n of h)if(n.startBeat<=t)e=n;else break;return e}function fe(h,t,e){if(e==="neutral")return!1;const n=de(t);return e==="natural"?he(h,n):ue(h,n)}class ge{constructor(t={}){this.config={...tt,...t}}getConfig(){return{...this.config}}balance(t,e){const n={shiftedToDownbeat:0,emptyMeasuresFilled:0,proximityShifts:0,beatsAdded:0,beatsShifted:0,marginRemovals:0};let i=[...t.beats];return i=this.shiftLoneSubdivisionNotes(i,e,n),i=this.fillEmptyMeasures(i,e,n),i=this.enforceDownbeatProximity(i,e,n),i=this.removeMarginNotes(i,e.duration,n),i.sort((s,a)=>s.timestamp-a.timestamp),{composite:{...t,beats:i,metadata:{...t.metadata,totalBeats:i.length}},stats:n}}shiftLoneSubdivisionNotes(t,e,n){if(!e.downbeatConfig?.segments)return t;const i=new Map;for(const a of t){const o=e.beats[a.beatIndex];if(o){const r=o.measureNumber;i.has(r)||i.set(r,[]),i.get(r).push(a)}}const s=[];for(const a of t){const o=e.beats[a.beatIndex];if(!o){s.push(a);continue}const r=o.measureNumber;if((i.get(r)||[]).length===1&&a.gridPosition!==0){const l={...a,gridPosition:0,timestamp:e.beats[a.beatIndex].timestamp,balancerAction:"shifted_to_downbeat"};s.push(l),n.shiftedToDownbeat++,n.beatsShifted++}else s.push(a)}return s}fillEmptyMeasures(t,e,n){if(!this.config.fillEmptyMeasures||!e.downbeatConfig?.segments)return t;let i=1/0,s=-1/0;for(const c of e.beats)i=Math.min(i,c.measureNumber),s=Math.max(s,c.measureNumber);if(i===1/0)return t;const a=new Map;for(const c of t){const l=e.beats[c.beatIndex];if(l){const d=l.measureNumber;a.has(d)||a.set(d,[]),a.get(d).push(c)}}const o=new Map;for(const c of t)o.set(c.beatIndex,c.gridType);const r=[];for(let c=i;c<=s;c++)if((a.get(c)||[]).length===0){const d=e.beats.findIndex(u=>u.measureNumber===c&&u.isDownbeat);if(d>=0){let u="straight_8th";for(let g=1;g<=8;g++){const p=d-g,b=d+g;if(o.has(p)){u=o.get(p);break}if(o.has(b)){u=o.get(b);break}}const f={timestamp:e.beats[d].timestamp,beatIndex:d,gridPosition:0,gridType:u,intensity:this.config.addedBeatIntensity,band:"mid",sourceBand:"mid",balancerAction:"empty_measure_fill"};r.push(f),n.emptyMeasuresFilled++,n.beatsAdded++}}return[...t,...r]}enforceDownbeatProximity(t,e,n){const i=this.config.downbeatProximityRange;if(i<0)return t;const s=new Set;for(const o of t)o.gridPosition===0&&s.add(o.beatIndex);const a=[];for(const o of t){if(o.gridPosition===0){a.push(o);continue}let r=!1;const c=Math.ceil(i);for(let l=0;l<=c&&!(l>i);l++)if(l===0){if(s.has(o.beatIndex)){r=!0;break}}else if(s.has(o.beatIndex-l)||s.has(o.beatIndex+l)){r=!0;break}if(r)a.push(o);else{const l={...o,gridPosition:0,timestamp:e.beats[o.beatIndex]?.timestamp??o.timestamp,balancerAction:"proximity_shift"};a.push(l),s.add(o.beatIndex),n.proximityShifts++,n.beatsShifted++}}return a}removeMarginNotes(t,e,n){const i=this.config.marginSeconds;if(i<=0||e<=0)return t;const s=e-i;return t.filter(a=>a.timestamp<i||a.timestamp>s?(n.marginRemovals++,!1):!0)}}const Tn=["straight_16th","triplet_8th","straight_8th","quarter_triplet","straight_4th"],ut={straight_16th:4,straight_8th:2,triplet_8th:3,straight_4th:1,quarter_triplet:1},C={easy:{maxSubdivision:"eighth",allowedGridTypes:["straight_4th","quarter_triplet"],description:"Quarter notes and quarter note triplets only",targetDensityRange:{min:0,max:1}},medium:{maxSubdivision:"eighth",allowedGridTypes:["straight_8th","quarter_triplet"],description:"8th notes and quarter note triplets only, with density reduction for moderate difficulty",targetDensityRange:{min:1,max:1.5}},hard:{maxSubdivision:"sixteenth",allowedGridTypes:["straight_16th","triplet_8th","straight_8th","quarter_triplet"],description:"All subdivision types including 16th notes",targetDensityRange:{min:1.5,max:1/0}},natural:{maxSubdivision:"sixteenth",allowedGridTypes:["straight_16th","triplet_8th","straight_8th","quarter_triplet"],description:"Unedited composite stream - no subdivision restrictions",targetDensityRange:{min:0,max:1/0}},custom:{maxSubdivision:"sixteenth",allowedGridTypes:["straight_16th","triplet_8th","straight_8th","quarter_triplet"],description:"Custom density-based variant — parameters provided at generation time",targetDensityRange:{min:0,max:1/0}}},pe=70,ye=70,be=120;function R(h,t){if(h==="natural")return[...C.natural.allowedGridTypes];if(h==="easy")return["straight_4th","quarter_triplet"];if(h==="medium")return["straight_8th","quarter_triplet"];if(h==="hard")return t>=ye?["straight_8th","quarter_triplet"]:[...C.hard.allowedGridTypes];if(h==="custom")return[...C.custom.allowedGridTypes];const e=h;throw new Error(`Unhandled difficulty: ${e}`)}const Sn={straight_4th:["straight_4th"],straight_8th:["straight_8th","quarter_triplet"],quarter_triplet:["quarter_triplet","straight_8th"],triplet_8th:["triplet_8th","straight_8th","quarter_triplet"],straight_16th:["straight_16th","triplet_8th","straight_8th","quarter_triplet"]};function Me(h,t){const e=Sn[h.maxGridType]??[h.maxGridType];if(!h.bpmBasedQuantization)return[...e];const n=h.restrictBpm??pe,i=h.quarterNoteBpm??be;let s=[...e];return t>=n&&(s=s.filter(a=>a!=="straight_16th"&&a!=="triplet_8th")),t>i&&(s=s.filter(a=>a!=="straight_8th")),s}function Be(h,t){if(h.length===0||t<=0)return 0;const e=60/t;return Math.max(...h.map(i=>ut[i]))/e}const vn={logConversions:!1,preservePhraseBoundaries:!0,simplificationIntensityThreshold:.3,heavySimplificationIntensityThreshold:.5,moderateSimplificationIntensityThreshold:.4,densityReductionMinIntensity:.25,interpolatedBeatIntensity:.5,preferPatternInsertion:!0,maxPatternInsertionSize:4,densityTargetStrategy:"midpoint",maxReductionPasses:3,seed:void 0,rhythmicBalanceConfig:void 0};function In(h,t,e){return e!==void 0?R(t,e).includes(h):C[t].allowedGridTypes.includes(h)}function _n(h,t){return t!==void 0?R(h,t):[...C[h].allowedGridTypes]}function Q(h,t,e,n){const i=n??(e!==void 0?R(t,e):C[t].allowedGridTypes);if(i.includes(h))return h;switch(h){case"straight_16th":return i.includes("straight_4th")&&!i.includes("straight_8th")?"straight_4th":"straight_8th";case"triplet_8th":return"quarter_triplet";case"straight_8th":return"straight_4th";default:return h}}function wn(h){return h}function Te(h,t,e){const n=[],i=e!==void 0?R(t,e):C[t].allowedGridTypes;for(const s of h)i.includes(s.gridType)||n.push({beat:s,gridType:s.gridType,suggestedConversion:Q(s.gridType,t,e)});return{isValid:n.length===0,violations:n,totalBeats:h.length,violationCount:n.length}}class Se{constructor(t={}){this.currentUnifiedBeatMap=null,this.config={...vn,...t}}lockGridPerBeatIndex(t,e,n,i,s){const a=this.enforceSingleGridPerBeat(t),o=new Map;if(a.length===0)return{beats:[],gridLock:o};const r=Math.max(...a.map(d=>d.beatIndex)),c=new Map;for(const d of a){const u=c.get(d.beatIndex)??[];u.push(d),c.set(d.beatIndex,u)}for(const[d,u]of c)o.set(d,u[0].gridType);const l=s??R(e,n);for(let d=0;d<=r;d++){if(o.has(d))continue;if(i?.has(d)){const f=i.get(d);o.set(d,f.selectedGrid);continue}let u=!1;for(const f of[1,-1,2,-2,3,-3]){const g=d+f;if(o.has(g)){o.set(d,o.get(g)),u=!0;break}}if(u)continue;const m=l[0]??"straight_8th";o.set(d,m)}return{beats:a,gridLock:o}}generate(t,e,n,i){this.currentUnifiedBeatMap=e;const s=t.naturalDifficulty,a=this.generateVariant(t,"easy",s,e,n,i),o=this.generateVariant(t,"medium",s,e,n,i),r=this.generateVariant(t,"hard",s,e,n,i);this.validateGridLockResult(a.beats,"easy"),this.validateGridLockResult(o.beats,"medium"),this.validateGridLockResult(r.beats,"hard");const c={difficulty:"natural",beats:this.enforceSingleGridPerBeat([...t.beats]),isUnedited:!0,editType:"none",editAmount:0};this.validateVariant(a,"easy"),this.validateVariant(o,"medium"),this.validateVariant(r,"hard");const l=e?.duration??120;if(a.densityValidation=this.validateDensityInRange(a,l),o.densityValidation=this.validateDensityInRange(o,l),r.densityValidation=this.validateDensityInRange(r,l),this.config.logConversions){const d=u=>{const m=u.densityValidation,f=m.targetRange.max===1/0?"∞":m.targetRange.max.toFixed(1),g=m.inRange?"✓":"✗";return`${u.difficulty}: ${m.density.toFixed(2)} nps (target [${m.targetRange.min}, ${f}]) ${g}`};console.log(`[DifficultyVariantGenerator] Density validation summary:
2
2
  ${d(a)}
3
3
  ${d(o)}
4
4
  ${d(r)}`)}return{easy:a,medium:o,hard:r,natural:c}}generateAtDensity(t,e,n,i,s){this.currentUnifiedBeatMap=n;const a=n?.quarterNoteBpm??120,o=n?.duration??120;this.calculateDensity(t.beats,o);const r=Me(e,a),c=Be(r,a);let l=e.targetDensity,d=!1;e.targetDensity>c&&(l=c,d=!0,console.warn(`[DifficultyVariantGenerator] Target density ${e.targetDensity.toFixed(2)} nps exceeds max achievable ${c.toFixed(2)} nps for grid types [${r.join(", ")}] at ${a} BPM. Clamping to ${l.toFixed(2)} nps.`));const{beats:u,gridLock:m}=this.lockGridPerBeatIndex(t.beats,"custom",a,s,r),f=this.calculateDensity(u,o),g=1e-10,p=Math.max(l,1e-10),b=u.some(y=>!r.includes(y.gridType));if(this.config.logConversions&&console.log(`[DifficultyVariantGenerator] generateAtDensity: current=${f.toFixed(2)} nps, target=${p.toFixed(2)} nps, maxGridType=${e.maxGridType}, allowedTypes=[${r.join(", ")}], clamped=${d}`),f>p*(1+g)){const y=this.simplifyBeats(u,"custom",t.quarterNoteInterval,!1,i,a,m,o,r,l);return{difficulty:"custom",beats:this.enforceSingleGridPerBeat(y.beats),isUnedited:!1,editType:"simplified",editAmount:y.metadata.totalBeatsBefore>0?(y.metadata.totalBeatsBefore-y.metadata.totalBeatsAfter)/y.metadata.totalBeatsBefore:0,conversionMetadata:y.metadata,densityClamped:d}}else if(f<l*(1-g)){const y=this.enhanceBeats(u,"custom",a,n,i,s,t.quarterNoteInterval,m,r,l),B=this.enforceSingleGridPerBeat(y.beats),M=y.metadata.patternsInserted>0?"pattern_inserted":"interpolated";return{difficulty:"custom",beats:B,isUnedited:!1,editType:M,editAmount:y.metadata.totalBeatsBefore>0?(y.metadata.totalBeatsAfter-y.metadata.totalBeatsBefore)/y.metadata.totalBeatsBefore:0,patternsInserted:y.metadata.insertedPatternIds.length>0?y.metadata.insertedPatternIds:void 0,enhancementMetadata:y.metadata}}else{if(b){this.config.logConversions&&console.log(`[DifficultyVariantGenerator] Density approximately equal (${f.toFixed(2)} ≈ ${l.toFixed(2)}), but grid restrictions needed`);const B=this.simplifyBeats(u,"custom",t.quarterNoteInterval,!1,i,a,m,o,r,l);return{difficulty:"custom",beats:this.enforceSingleGridPerBeat(B.beats),isUnedited:B.metadata.beatsRemoved===0&&!d,editType:B.metadata.beatsRemoved>0?"simplified":"none",editAmount:B.metadata.totalBeatsBefore>0?(B.metadata.totalBeatsBefore-B.metadata.totalBeatsAfter)/B.metadata.totalBeatsBefore:0,conversionMetadata:B.metadata,densityClamped:d}}return{difficulty:"custom",beats:this.enforceSingleGridPerBeat(u),isUnedited:!d,editType:"none",editAmount:0}}}generateAtDensities(t,e,n,i,s){const a=new Map;for(const{label:o,config:r}of e){const c={...t,beats:t.beats.map(d=>({...d}))},l=this.generateAtDensity(c,r,n,i,s);a.set(o,l)}return a}validateVariant(t,e){const n=Te(t.beats,e);if(n.isValid)this.config.logConversions&&console.log(`[DifficultyVariantGenerator] ${e} variant validated: ${n.totalBeats} beats, no subdivision violations`);else if(console.warn(`[DifficultyVariantGenerator] ${e} variant has ${n.violationCount} subdivision violations out of ${n.totalBeats} beats. This indicates a bug in the variant generation logic.`),this.config.logConversions){for(const i of n.violations.slice(0,5))console.warn(` - Beat at index ${i.beat.beatIndex}, position ${i.beat.gridPosition}, grid: ${i.gridType} (suggested: ${i.suggestedConversion})`);n.violations.length>5&&console.warn(` ... and ${n.violations.length-5} more violations`)}}validateGridLockResult(t,e){const n=this.validateSingleGridPerBeat(t);if(!n.isValid&&(console.warn(`[DifficultyVariantGenerator] ${e} variant has ${n.violations.length} grid lock violations (mixed grid types at same beat index). This indicates a bug in the grid lock implementation.`),this.config.logConversions)){for(const i of n.violations.slice(0,5))console.warn(` - Beat index ${i.beatIndex} has mixed grids: ${i.gridTypes.join(", ")}`);n.violations.length>5&&console.warn(` ... and ${n.violations.length-5} more violations`)}}validateDensityInRange(t,e){const n=this.calculateDensity(t.beats,e),i=C[t.difficulty].targetDensityRange,s=n>=i.min&&(i.max===1/0||n<=i.max);if(s){if(this.config.logConversions){const a=i.max===1/0?"∞":i.max.toFixed(2);console.log(`[DifficultyVariantGenerator] ${t.difficulty} variant density ${n.toFixed(2)} nps is within target range [${i.min.toFixed(2)}, ${a}] ✓`)}}else{const a=i.max===1/0?"∞":i.max.toFixed(2);console.warn(`[DifficultyVariantGenerator] ${t.difficulty} variant density ${n.toFixed(2)} nps is OUTSIDE target range [${i.min.toFixed(2)}, ${a}]. This may occur for edge cases (short songs, extreme tempos).`)}return{inRange:s,density:n,targetRange:i,difficulty:t.difficulty}}generateVariant(t,e,n,i,s,a){const o=e===n,r=i?.quarterNoteBpm??120,c=i?.duration??120,l=R(e,r),{beats:d,gridLock:u}=this.lockGridPerBeatIndex(t.beats,e,r,a);if(o){if(d.every(b=>l.includes(b.gridType))){const{targetCount:b}=this.calculateBeatCountTarget(d.length,c,e);if(d.length<b){const y=this.enhanceBeats(d,e,r,i,s,a,t.quarterNoteInterval,u),B=y.metadata.patternsInserted>0?"pattern_inserted":"interpolated";return{difficulty:e,beats:y.beats,isUnedited:!1,editType:B,editAmount:y.metadata.totalBeatsBefore>0?(y.metadata.totalBeatsAfter-y.metadata.totalBeatsBefore)/y.metadata.totalBeatsBefore:0,enhancementMetadata:y.metadata}}return{difficulty:e,beats:[...d],isUnedited:!0,editType:"none",editAmount:0}}const p=this.simplifyBeats(d,e,t.quarterNoteInterval,!1,s,r,u,c);return{difficulty:e,beats:p.beats,isUnedited:!1,editType:"simplified",editAmount:p.metadata.totalBeatsBefore>0?(p.metadata.totalBeatsBefore-p.metadata.totalBeatsAfter)/p.metadata.totalBeatsBefore:0,conversionMetadata:p.metadata}}const m=this.needsSimplification(e,n),f=this.needsEnhancement(e,n);if(m){const g=this.isHeavySimplification(e,n),p=this.simplifyBeats(d,e,t.quarterNoteInterval,g,s,r,u,c),{targetCount:b}=this.calculateBeatCountTarget(p.beats.length,c,e);if(p.beats.length<b-1){const y=this.enhanceBeats(p.beats,e,r,i,s,a,t.quarterNoteInterval,u),B=y.metadata.patternsInserted>0?"pattern_inserted":"interpolated";return{difficulty:e,beats:y.beats,isUnedited:!1,editType:B,editAmount:1,conversionMetadata:p.metadata,enhancementMetadata:y.metadata}}return{difficulty:e,beats:p.beats,isUnedited:!1,editType:"simplified",editAmount:p.metadata.totalBeatsBefore>0?(p.metadata.totalBeatsBefore-p.metadata.totalBeatsAfter)/p.metadata.totalBeatsBefore:0,conversionMetadata:p.metadata}}if(f){const g=this.enhanceBeats(d,e,r,i,s,a,t.quarterNoteInterval,u);let p=g.beats;if(p.some(B=>!l.includes(B.gridType))){const B=[];for(const M of p)if(l.includes(M.gridType))B.push(M);else{const T=this.convertBeatGridType(M,e,t.quarterNoteInterval,r);T&&B.push(T)}p=this.deduplicateConvertedBeats(B)}const y=g.metadata.patternsInserted>0?"pattern_inserted":"interpolated";return{difficulty:e,beats:p,isUnedited:!1,editType:y,editAmount:g.metadata.totalBeatsBefore>0?(g.metadata.totalBeatsAfter-g.metadata.totalBeatsBefore)/g.metadata.totalBeatsBefore:0,patternsInserted:g.metadata.insertedPatternIds.length>0?g.metadata.insertedPatternIds:void 0,enhancementMetadata:g.metadata}}return{difficulty:e,beats:[...d],isUnedited:!0,editType:"none",editAmount:0}}simplifyBeats(t,e,n,i=!1,s,a=120,o,r=120,c,l){const d={sixteenthToEighth:0,tripletToQuarterTriplet:0,eighthToQuarter:0,beatsRemoved:0,totalBeatsBefore:t.length,totalBeatsAfter:0},u=this.buildPhraseMembershipMap(s),m=o?t:this.enforceSingleGridPerBeat(t);d.totalBeatsBefore=m.length;const f=c??R(e,a);if(m.every(_=>f.includes(_.gridType))&&!i){const _=l!==void 0?Math.round(l*r):this.calculateBeatCountTarget(m.length,r,e).targetCount,x=this.reduceDensityToTarget(m,e,d,u,a,_,r);return d.totalBeatsAfter=x.length,{beats:x,metadata:d}}let p=m;i&&(p=this.filterBeatsForHeavySimplification(m,d,u));const b=[];for(const _ of p){if(f.includes(_.gridType)){b.push(_);continue}const x=o?.get(_.beatIndex),I=this.convertBeatGridType(_,e,n,a,x,f);if(I)if(b.push(I),_.gridType==="straight_16th"){if(d.sixteenthToEighth++,this.config.logConversions){const w=I.gridType==="straight_4th"?"quarter":"8th";console.log(`[DifficultyVariantGenerator] Converted 16th note at beat ${_.beatIndex} position ${_.gridPosition} to ${w} note`)}}else _.gridType==="triplet_8th"?(d.tripletToQuarterTriplet++,this.config.logConversions&&console.log(`[DifficultyVariantGenerator] Converted 8th triplet at beat ${_.beatIndex} position ${_.gridPosition} to quarter triplet`)):_.gridType==="straight_8th"&&(d.eighthToQuarter++,this.config.logConversions&&console.log(`[DifficultyVariantGenerator] Converted 8th note at beat ${_.beatIndex} position ${_.gridPosition} to quarter note`));else d.beatsRemoved++,this.config.logConversions&&console.log(`[DifficultyVariantGenerator] Removed beat at beat ${_.beatIndex} position ${_.gridPosition} (grid: ${_.gridType})`)}const y=this.deduplicateConvertedBeats(b);d.beatsRemoved+=b.length-y.length;const B=b.length-y.length,M=this.calculateDensity(y,r),T=l!==void 0?Math.round(l*r):this.calculateBeatCountTarget(y.length,r,e).targetCount,S=l??this.calculateBeatCountTarget(y.length,r,e).targetDensity;if(y.length<=T)return this.config.logConversions&&console.log(`[DifficultyVariantGenerator] Grid conversion achieved target density: ${M.toFixed(2)} notes/sec (target midpoint ${S.toFixed(2)} nps, ${T} beats) for ${e}`+(B>0?` (${B} beats collapsed)`:"")),d.totalBeatsAfter=y.length,{beats:y,metadata:d};const v=this.reduceDensityToTarget(y,e,d,u,a,T,r);return d.totalBeatsAfter=v.length,{beats:v,metadata:d}}filterBeatsForHeavySimplification(t,e,n=new Map){const i=this.config.heavySimplificationIntensityThreshold,s=[];for(const a of t){const o=this.isStrongBeat(a.beatIndex),r=a.gridPosition===0,c=a.gridPosition===1||a.gridPosition===3,l=this.shouldPreserveForPhrase(a,n,i);o||l||r&&a.intensity>=i*.7||c&&a.intensity>=i||a.gridPosition===2&&a.intensity>=i*.8?s.push(a):(e.beatsRemoved++,this.config.logConversions&&console.log(`[DifficultyVariantGenerator] Heavy simplification: removed beat at beat ${a.beatIndex} position ${a.gridPosition} (intensity: ${a.intensity.toFixed(2)}, strongBeat: ${o})`))}return s}isStrongBeat(t){const e=this.config.rhythmicBalanceConfig?.strongBeatEmphasis??"natural";if(e==="neutral")return!1;const n=this.currentUnifiedBeatMap;if(!n){const r=t%4;return r===0||r===2}const i=n.beats[t];if(!i){const r=t%4;return r===0||r===2}const s=n.downbeatConfig?.segments;if(!s||s.length===0){const r=t%4;return r===0||r===2}const o=me(s,t).timeSignature.beatsPerMeasure;return fe(i.beatInMeasure,o,e)}calculateDensity(t,e){return t.length===0||e<=0?0:t.length/e}calculateBeatCountTarget(t,e,n){const i=C[n].targetDensityRange;if(n==="natural"||n==="custom"){const u=e>0?t/e:0;return{targetCount:t,maxCount:t,minCount:t,targetDensity:u}}const a={easy:.9,medium:1.25,hard:1.75}[n];let o;switch(this.config.densityTargetStrategy){case"lower":o=a*.75+i.min*.25;break;case"upper":{const u=i.max===1/0?a*1.5:i.max;o=a*.75+u*.25;break}default:o=a;break}const r=i.max===1/0?o:i.max;o=Math.max(i.min,Math.min(r,o));const c=Math.round(i.min*e),l=i.max===1/0?1/0:Math.round(i.max*e);return{targetCount:Math.round(o*e),maxCount:l,minCount:c,targetDensity:o}}calculateBeatsToAdd(t,e,n,i){const s=this.calculateBeatCountTarget(t,e,i),a=Math.max(0,s.targetCount-t),o=R(i,n),r=this.getMaxBeatsPerIndexFromGridTypes(o);return{beatsToAdd:a,targetCount:s.targetCount,maxBeatsPerIndex:r}}getMaxBeatsPerIndexFromGridTypes(t){let e=1;for(const n of t){const i=ut[n];i>e&&(e=i)}return e}getMaxBeatsForGridType(t){return ut[t]??1}distributeBeatsAcrossIndices(t,e,n,i,s,a){const o=new Map;let r=t;for(let m=0;m<=i;m++){const f=e.get(m)??[];o.set(m,f.length)}if(r<=0)return o;const c=m=>{const f=n.get(m);return f?a&&!a.includes(f)?this.getMaxBeatsPerIndexFromGridTypes(a):this.getMaxBeatsForGridType(f):a?this.getMaxBeatsPerIndexFromGridTypes(a):4},l=[],d=[];for(let m=0;m<=i;m++){const f=o.get(m)??0,g=c(m);f===0?l.push(m):f<g&&d.push(m)}const u=this.groupConsecutiveEmptyIndices(l);u.sort((m,f)=>{const g=m.length-f.length;if(g!==0)return g;const p=N($(s,`gap:${m[0]}`)),b=N($(s,`gap:${f[0]}`));return p-b});for(const m of u){if(r<=0)break;const f=m.length<=2;for(const g of m){if(r<=0)break;const p=c(g);let b;f?b=Math.min(p,r,2):b=Math.min(p,r,1),b>0&&(o.set(g,b),r-=b)}}d.sort((m,f)=>{const g=o.get(m)??0,p=o.get(f)??0,b=c(m),y=c(f),B=b-g,T=y-p-B;if(T!==0)return T;const S=N($(s,`partial:${m}`)),v=N($(s,`partial:${f}`));return S-v});for(const m of d){if(r<=0)break;const f=o.get(m)??0,p=c(m)-f;if(p>0){const b=Math.min(p,r);o.set(m,f+b),r-=b}}if(r>0)for(const m of l){if(r<=0)break;const f=o.get(m)??0,p=c(m)-f;if(p>0){const b=Math.min(p,r);o.set(m,f+b),r-=b}}return o}groupConsecutiveEmptyIndices(t){if(t.length===0)return[];const e=[];let n=[t[0]];for(let i=1;i<t.length;i++){const s=t[i-1],a=t[i];a===s+1?n.push(a):(e.push(n),n=[a])}return e.push(n),e}reduceDensityToTarget(t,e,n,i=new Map,s=120,a,o=120){const r=C[e].targetDensityRange,c=this.calculateDensity(t,o);if(a!==void 0&&t.length<=a)return this.config.logConversions&&console.log(`[DifficultyVariantGenerator] Density ${c.toFixed(2)} notes/sec already at or below target midpoint (${a} beats) for ${e}`),t;if(c<=r.max&&a===void 0)return this.config.logConversions&&console.log(`[DifficultyVariantGenerator] Density ${c.toFixed(2)} notes/sec already within target range [${r.min}, ${r.max}] for ${e}`),t;this.config.logConversions&&console.log(`[DifficultyVariantGenerator] Reducing density from ${c.toFixed(2)} notes/sec to target max ${r.max} notes/sec for ${e}`);const l=this.buildDownbeatCountMap(t),d=t.map(M=>({beat:M,priority:this.calculateRemovalPriority(M,i,l)}));d.sort((M,T)=>M.priority-T.priority);const u=new Set;let m=t.length;const f=this.config.maxReductionPasses;let g=0;for(let M=1;M<=f;M++){g=M;let T=0;const S=M===f;let v,_,x=!1;M===1?(v=1-this.config.densityReductionMinIntensity,_=this.config.moderateSimplificationIntensityThreshold):M===2?(v=1-this.config.densityReductionMinIntensity-.15,_=this.config.moderateSimplificationIntensityThreshold-.1):(x=!0,v=0,_=0);for(const{beat:I,priority:w}of d)if(!u.has(I)){if(a!==void 0){if(m-1<=a)break}else if((m-1)/o<=r.max)break;if(x){if(this.isStrongBeat(I.beatIndex))continue}else if(w>=v||I.intensity>=_)continue;u.add(I),m--,T++,this.config.logConversions&&console.log(`[DifficultyVariantGenerator] Pass ${M}: Removed beat at index ${I.beatIndex} position ${I.gridPosition} (priority: ${w.toFixed(2)}, intensity: ${I.intensity.toFixed(2)})`)}if(this.config.logConversions&&console.log(`[DifficultyVariantGenerator] Pass ${M}${S?" (final)":""}: Removed ${T} beats, density now: ${(m/o).toFixed(2)} notes/sec`),a!==void 0){if(m<=a)break}else if(m/o<=r.max)break}const p=m/o;if((a!==void 0?m>a:p>r.max)&&this.config.logConversions){const M=a!==void 0?`${a} beats (midpoint ${(a/o).toFixed(2)} nps)`:`${r.max} notes/sec`;console.warn(`[DifficultyVariantGenerator] Could not reach target density ${M} for ${e} after ${f} passes. Final density: ${p.toFixed(2)} notes/sec (${m} beats remaining)`)}const y=t.filter(M=>!u.has(M));n.reductionPasses=g,n.beatsRemoved+=u.size;const B=Math.ceil(r.min*o);if(y.length<B&&t.length>0){const M=d.filter(({beat:T})=>u.has(T)).sort((T,S)=>S.priority-T.priority);for(const{beat:T}of M){if(y.length>=B)break;y.push(T),n.beatsRemoved--}}return y}buildDownbeatCountMap(t){const e=new Map,n=this.currentUnifiedBeatMap;for(const i of t){if(i.gridPosition!==0)continue;let s;n?.beats[i.beatIndex]?s=n.beats[i.beatIndex].measureNumber:s=Math.floor(i.beatIndex/4),e.set(s,(e.get(s)??0)+1)}return e}calculateRemovalPriority(t,e,n=new Map){const i=this.config.rhythmicBalanceConfig?.strongBeatEmphasis??"natural";let s=.5;if(i!=="neutral"&&this.isStrongBeat(t.beatIndex)&&(s+=.3),t.gridPosition===0){s+=.2;const o=this.currentUnifiedBeatMap;let r;o?.beats[t.beatIndex]?r=o.beats[t.beatIndex].measureNumber:r=Math.floor(t.beatIndex/4),(n.get(r)??0)===1&&(s+=.2)}s+=t.intensity*.3;const a=e.get(t.beatIndex);if(a&&a.length>0){const o=Math.max(...a.map(r=>r.significance));s+=Math.min(.15,o*.05)}return(t.gridPosition===1||t.gridPosition===3)&&(s-=.1),Math.max(0,Math.min(1,s))}convertBeatGridType(t,e,n,i=120,s,a){const o=s??t.gridType,r=Q(o,e,i,a);if(r===o)return{...t,gridType:r};let c,l,d;switch(o){case"straight_16th":{const u=n/4;if(d=t.timestamp-t.gridPosition*u,r==="straight_4th")c=0,l=d;else{t.gridPosition===1||t.gridPosition===3?c=t.gridPosition===1?0:2:c=t.gridPosition;const m=n/2;l=d+(c===0?0:m)}break}case"triplet_8th":{const u=n/3;d=t.timestamp-t.gridPosition*u,c=0,l=d;break}case"straight_8th":{const u=n/2;d=t.timestamp-t.gridPosition*u,c=0,l=d;break}default:return{...t,gridType:t.gridType}}return{...t,gridType:r,gridPosition:c,timestamp:l}}deduplicateConvertedBeats(t){const e=new Map;for(const n of t){const i=`${n.beatIndex}:${n.gridPosition}:${n.gridType}`,s=e.get(i);(!s||n.intensity>s.intensity)&&e.set(i,n)}return Array.from(e.values()).sort((n,i)=>n.timestamp-i.timestamp)}needsSimplification(t,e){const n=["easy","medium","hard"],i=n.indexOf(t),s=n.indexOf(e);return i<s}needsEnhancement(t,e){const n=["easy","medium","hard"],i=n.indexOf(t),s=n.indexOf(e);return i>s}isHeavySimplification(t,e){return e==="hard"&&t==="easy"}enhanceBeats(t,e,n,i,s,a,o=.5,r,c,l){const d=i?.duration??120,u={totalBeatsBefore:t.length,totalBeatsAfter:0,patternsInserted:0,interpolatedBeats:0,insertedPatternIds:[]},m=I=>{if(c){if(c.includes(I))return I;const w=["straight_16th","triplet_8th","straight_8th","quarter_triplet","straight_4th"],F=w.indexOf(I);for(let P=F+1;P<w.length;P++)if(c.includes(w[P]))return w[P];return c[c.length-1]??I}return Q(I,e,n)};if(t.length===0)return u.totalBeatsAfter=0,{beats:[],metadata:u};let f=r?t:this.enforceSingleGridPerBeat(t);if(c&&f.some(w=>!c.includes(w.gridType))){const w=[];for(const P of f)if(c.includes(P.gridType))w.push(P);else{const L=this.convertBeatGridType(P,e,o,n,void 0,c);L&&w.push(L)}f=this.deduplicateConvertedBeats(w)}u.totalBeatsBefore=f.length;const g=this.groupBeatsByIndex(f),p=Math.max(...Array.from(g.keys()));let b;if(l!==void 0){const I=Math.round(l*d);b=Math.max(0,I-f.length);const w=Math.max(0,3*f.length);b=Math.min(b,w)}else b=this.calculateBeatsToAdd(f.length,d,n,e).beatsToAdd;const y=this.config.seed??`enhance:${p}:${f.length}`,B=this.distributeBeatsAcrossIndices(b,g,r??new Map,p,y,c),M=[],T=new Map,S=(I,w)=>`${I}:${w}`;for(const I of f){const w=S(I.beatIndex,I.gridPosition);T.has(w)||T.set(w,I.gridType)}for(let I=0;I<=p;I++){const w=g.get(I)??[],F=B.get(I)??0;if(w.length>=F){M.push(...w);continue}const P=F-w.length;if(w.length===0){const D=r?.get(I),E=D?m(D):void 0,k=this.createBeatsForEmptyIndex(I,P,i,a,o,g,T,E),Pe=E??this.getGridForBeatIndex(I,k,a);for(const G of k){const wt=S(G.beatIndex,G.gridPosition);!T.has(wt)&&G.gridType===Pe&&(T.set(wt,G.gridType),M.push(G),u.interpolatedBeats++)}continue}const L=r?.get(I)??w[0].gridType,_t=m(L);let et=0;if(this.config.preferPatternInsertion&&s){const D=this.tryInsertPattern(w,I,P,s,T,_t);et=D.beatsAdded,D.patternId&&(u.patternsInserted++,u.insertedPatternIds.push(D.patternId))}if(et<P){const D=this.interpolateBeats(w,I,P-et,o,T,_t,i);for(const E of D){const k=S(E.beatIndex,E.gridPosition);T.has(k)||(T.set(k,E.gridType),M.push(E),u.interpolatedBeats++)}}M.push(...w)}const v=M.sort((I,w)=>I.beatIndex!==w.beatIndex?I.beatIndex-w.beatIndex:I.gridPosition-w.gridPosition);let _;r?(this.validateSingleGridPerBeat(v).isValid,_=v):_=this.enforceSingleGridPerBeat(v);const x=this.deduplicateEnhancedBeats(_);return u.totalBeatsAfter=x.length,this.config.logConversions&&console.log(`[DifficultyVariantGenerator] Enhanced beats for ${e}: ${u.totalBeatsBefore} → ${u.totalBeatsAfter} beats (patterns: ${u.patternsInserted}, interpolated: ${u.interpolatedBeats})`),{beats:x,metadata:u}}groupBeatsByIndex(t){const e=new Map;for(const n of t){const i=e.get(n.beatIndex);i?i.push(n):e.set(n.beatIndex,[n])}return e}calculateTargetBeatsPerBeat(t,e,n){const i=new Map;for(let s=0;s<=n;s++){const a=t.get(s);if(a){const o=Math.min(Math.ceil(a.length*e),4);i.set(s,o)}else{const o=Math.min(Math.ceil(e*.7),4);o>=2&&i.set(s,o)}}return i}tryInsertPattern(t,e,n,i,s,a){const r=i.patternLibrary.filter(y=>y.sizeInBeats<=this.config.maxPatternInsertionSize&&y.availableForReuse);if(r.length===0)return{beatsAdded:0};const c=r.filter(y=>y.pattern.some(B=>B.gridType===a));if(c.length===0)return{beatsAdded:0};c.sort((y,B)=>B.significance-y.significance);const l=c[0],d=l.pattern.filter(y=>y.beatIndex===0),u=new Set(t.map(y=>y.gridPosition)),m=(y,B)=>`${y}:${B}`,f=d.filter(y=>!(y.gridType!==a||u.has(y.gridPosition)||s.has(m(e,y.gridPosition))));if(f.length===0)return{beatsAdded:0};const g=f.slice(0,n),p=l.sourceBand,b=g.map(y=>({...y,beatIndex:e,band:p,sourceBand:p,intensity:y.intensity*.8}));for(const y of b)s.set(m(y.beatIndex,y.gridPosition),y.gridType);return{beatsAdded:b.length,patternId:l.id}}createBeatsForEmptyIndex(t,e,n,i,s=.5,a,o,r){let c=r??"straight_16th",l="mid",d="mid";if(!r&&i){const M=i.get(t);M&&(c=M.selectedGrid)}if(!r&&!i?.has(t)&&a)for(const M of[1,-1,2,-2,3,-3]){const T=a.get(t+M);if(T&&T.length>0){c=T[0].gridType,l=T[0].band,d=T[0].sourceBand;break}}const u=new Set;if(o){const M=(T,S)=>`${T}:${S}`;for(let T=0;T<4;T++)o.has(M(t,T))&&u.add(T)}const f={straight_16th:4,straight_8th:2,triplet_8th:3,straight_4th:1,quarter_triplet:1}[c],g=[];for(let M=0;M<f;M++)u.has(M)||g.push(M);g.sort((M,T)=>{const S=v=>v===0?0:v===f-1?2:1;return S(M)-S(T)});const p=g.slice(0,e),b=n?.beats[t]?.timestamp??t*s,B={straight_16th:s/4,straight_8th:s/2,triplet_8th:s/3,straight_4th:s,quarter_triplet:s}[c];return p.map(M=>({timestamp:b+M*B,beatIndex:t,gridPosition:M,gridType:c,intensity:this.config.interpolatedBeatIntensity*.8,band:l,sourceBand:d,quantizationError:0}))}interpolateBeats(t,e,n,i=.5,s,a,o){if(n<=0||t.length===0)return[];const r=a??t[0].gridType,l=(M=>M==="straight_16th"?4:M==="straight_8th"?2:M==="straight_4th"||M==="quarter_triplet"?1:3)(r),d=(M,T)=>`${M}:${T}`,u=new Set(t.map(M=>M.gridPosition));if(s)for(let M=0;M<l;M++)s.has(d(e,M))&&u.add(M);const m=[];for(let M=0;M<l;M++)u.has(M)||m.push(M);m.sort((M,T)=>(M===0||M===3?2:1)-(T===0||T===3?2:1));const f=m.slice(0,n),g=t[0],p=o?.beats[e]?.timestamp??e*i,y={straight_16th:i/4,straight_8th:i/2,triplet_8th:i/3,straight_4th:i,quarter_triplet:i}[r];return f.map(M=>({timestamp:p+M*y,beatIndex:e,gridPosition:M,gridType:r,intensity:this.config.interpolatedBeatIntensity,band:g.band,sourceBand:g.sourceBand,quantizationError:0}))}getGridForBeatIndex(t,e,n,i){if(e.length>0)return e[0].gridType;if(n?.has(t))return n.get(t).selectedGrid;if(i)for(const s of[1,-1,2,-2,3,-3]){const a=i.get(t+s);if(a&&a.length>0)return a[0].gridType}return"straight_16th"}deduplicateEnhancedBeats(t){const e=new Map;for(const s of t){const a=e.get(s.beatIndex)??new Map;a.set(s.gridType,(a.get(s.gridType)??0)+1),e.set(s.beatIndex,a)}const n=new Map;for(const[s,a]of e){let o="straight_16th",r=0;for(const[c,l]of a)l>r&&(r=l,o=c);n.set(s,o)}const i=new Map;for(const s of t){const a=`${s.beatIndex}:${s.gridPosition}`,o=i.get(a),r=n.get(s.beatIndex);o?s.gridType===r&&o.gridType!==r&&i.set(a,s):i.set(a,s)}return Array.from(i.values())}enforceSingleGridPerBeat(t){const e=new Map;for(const i of t){const s=e.get(i.beatIndex)??[];s.push(i),e.set(i.beatIndex,s)}const n=[];for(const[,i]of e){if(i.length<=1){n.push(...i);continue}const s=new Set(i.map(c=>c.gridType));if(s.size<=1){n.push(...i);continue}let a="straight_16th",o=0;for(const c of s){const l=i.filter(d=>d.gridType===c).reduce((d,u)=>d+u.intensity,0);l>o&&(o=l,a=c)}const r=i.filter(c=>c.gridType===a);if(this.config.logConversions&&r.length<i.length){const c=i.filter(l=>l.gridType!==a);console.log(`[DifficultyVariantGenerator] Enforced single grid at beat ${i[0].beatIndex}: kept ${a} (${r.length} beats), removed ${c.map(l=>l.gridType).join(", ")} (${c.length} beats)`)}n.push(...r)}return n.sort((i,s)=>i.timestamp-s.timestamp)}validateSingleGridPerBeat(t){const e=new Map;for(const i of t){const s=e.get(i.beatIndex)??[];s.push(i),e.set(i.beatIndex,s)}const n=[];for(const[i,s]of e){if(s.length<=1)continue;const a=new Set(s.map(o=>o.gridType));a.size>1&&n.push({beatIndex:i,gridTypes:Array.from(a)})}if(n.length>0&&this.config.logConversions){console.warn(`[DifficultyVariantGenerator] Grid validation found ${n.length} violations. This indicates a bug in grid lock implementation.`);for(const i of n.slice(0,5))console.warn(` - Beat index ${i.beatIndex} has mixed grids: ${i.gridTypes.join(", ")}`)}return{isValid:n.length===0,violations:n}}getConfig(){return{...this.config}}buildPhraseMembershipMap(t){const e=new Map;if(!t||!this.config.preservePhraseBoundaries)return e;const n=t.phrases.filter(i=>i.hasVariation);for(const i of n)for(const s of i.occurrences)for(let a=0;a<i.sizeInBeats;a++){const o=s.beatIndex+a,r=e.get(o)??[];r.push(i),e.set(o,r)}return e}shouldPreserveForPhrase(t,e,n){if(!this.config.preservePhraseBoundaries)return!1;const i=e.get(t.beatIndex);if(!i||i.length===0)return!1;const s=i.reduce((l,d)=>d.significance>l.significance?d:l),o=t.intensity-n>=-.15,c=s.significance>=1.5;return o&&c?(this.config.logConversions&&console.log(`[DifficultyVariantGenerator] Preserving beat at index ${t.beatIndex} position ${t.gridPosition} (intensity: ${t.intensity.toFixed(2)}) due to phrase membership (phrase significance: ${s.significance.toFixed(2)})`),!0):!1}}const It={casual:{difficulty:"easy",outputMode:"composite",description:"Easy difficulty for relaxed gameplay"},standard:{difficulty:"medium",outputMode:"composite",description:"Balanced experience for most players"},challenge:{difficulty:"hard",outputMode:"composite",description:"Hard difficulty for skilled players"},bass:{difficulty:"medium",outputMode:"low",description:"Focus on bass/low-frequency rhythms"}};function xn(h){return It[h]}function An(){return Object.keys(It)}const Pn={difficulty:"medium",outputMode:"composite",measureStartOffset:0,minimumTransientIntensity:0,transientConfig:void 0,scoringConfig:void 0,phraseAnalyzerConfig:void 0,rhythmicBalanceConfig:tt,seed:void 0,verbose:!1,enableCache:!0,cacheMaxAge:1800*1e3,skipDifficultyVariants:!1};class O{constructor(t={}){this.cache=new Map,this.cacheHits=0,this.cacheMisses=0;const e={...tt,...t.rhythmicBalanceConfig};this.options={...Pn,...t,rhythmicBalanceConfig:e},this.multiBandAnalyzer=new ee,this.transientDetector=new ne({bandConfig:this.options.transientConfig}),this.rhythmQuantizer=new St({minimumTransientIntensity:this.options.minimumTransientIntensity,densityValidation:this.options.densityValidation}),this.phraseAnalyzer=new ae(this.options.phraseAnalyzerConfig),this.densityAnalyzer=new re,this.streamScorer=new ce(this.options.scoringConfig),this.compositeGenerator=new le,this.variantGenerator=new Se({seed:this.options.seed,rhythmicBalanceConfig:e}),this.rhythmicBalancer=new ge(this.options.rhythmicBalanceConfig),this.tempoAwareQuantizer=new se(this.options.tempoQuantizationConfig??vt,this.rhythmQuantizer)}generateCacheKey(t,e,n){return`${t}:${e}:${n}`}createConfigFingerprint(){const t={minimumTransientIntensity:this.options.minimumTransientIntensity,measureStartOffset:this.options.measureStartOffset,tempoQuantizationConfig:this.options.tempoQuantizationConfig};return JSON.stringify(t)}getFromCache(t){if(!this.options.enableCache)return null;const e=this.cache.get(t);return e?Date.now()-e.timestamp>this.options.cacheMaxAge?(this.cache.delete(t),this.cacheMisses++,null):(this.cacheHits++,this.options.verbose&&console.log(`[RhythmGenerator] Cache HIT for key: ${t}`),e.result):(this.cacheMisses++,null)}setCache(t,e){this.options.enableCache&&(this.cache.set(t,{result:e,timestamp:Date.now(),key:t}),this.options.verbose&&console.log(`[RhythmGenerator] Cache SET for key: ${t}`))}clearCache(){this.cache.clear(),this.cacheHits=0,this.cacheMisses=0}pruneExpiredCache(){const t=Date.now();for(const[e,n]of this.cache.entries())t-n.timestamp>this.options.cacheMaxAge&&this.cache.delete(e)}getCacheStats(){let t=0;const e=[];let n=null;for(const[i,s]of this.cache.entries()){const a=i.split(":")[1];e.includes(a)||e.push(a);try{t+=JSON.stringify(s.result).length*2}catch{t+=1e3}(n===null||s.timestamp<n)&&(n=s.timestamp)}return{entryCount:this.cache.size,estimatedSize:t,cachedPhases:e,oldestEntry:n,hits:this.cacheHits,misses:this.cacheMisses}}isCached(t,e){const n=this.createConfigFingerprint(),i=this.generateCacheKey(t,e,n);return this.cache.has(i)}getOptions(){return{...this.options}}async generate(t,e,n,i){const s=(T,S,v)=>{this.options.verbose&&console.log(`[RhythmGenerator] [${T}] ${Math.round(S*100)}%: ${v}`),i?.(T,S,v)};n?.throwIfAborted();const a=this.generateCacheKey(e.audioId,"variants",this.createConfigFingerprint()),o=this.getFromCache(a);if(o)return s("Cache",1,"Retrieved complete result from cache"),o;s("Phase 1",0,"Starting multi-band analysis"),n?.throwIfAborted();const r=this.analyzeMultiBand(t);s("Phase 1",.2,`Analyzed ${r.bands.size} frequency bands`),n?.throwIfAborted();const c=this.detectTransients(r);s("Phase 1",.4,`Detected ${c.transients.length} transients`),n?.throwIfAborted();const l=this.quantizeTransients(c,e);s("Phase 1",.8,`Quantized to ${l.streams.low.beats.length+l.streams.mid.beats.length+l.streams.high.beats.length} beats across all bands`),s("Phase 1",1,"Phase 1 complete"),n?.throwIfAborted(),s("Phase 2",0,"Starting phrase and density analysis"),n?.throwIfAborted();const d=this.analyzePhrases(l.streams);s("Phase 2",.3,`Detected ${d.phrases.length} rhythmic phrases`),n?.throwIfAborted();const u=this.analyzeDensity(l,e.quarterNoteBpm,e.duration);s("Phase 2",.7,`Density category: ${u.combinedMetrics.densityCategory}`),s("Phase 2",1,"Phase 2 complete"),n?.throwIfAborted(),s("Phase 3",0,"Starting scoring and composite generation"),n?.throwIfAborted();const m=this.scoreStreams(l,d,u,e.quarterNoteBpm);s("Phase 3",.2,`Scored ${m.sectionWinners.length} sections`),n?.throwIfAborted();const f=this.generateComposite(l,m,u,e.duration);s("Phase 3",.4,`Generated composite with ${f.beats.length} beats, natural difficulty: ${f.naturalDifficulty}`),n?.throwIfAborted();const g=this.rhythmicBalancer.balance(f,e),p=g.composite,b=g.stats;s("Phase 3",.6,`Balanced composite: ${p.beats.length} beats (${b.beatsAdded} added, ${b.beatsShifted} shifted for rhythmic structure)`);const y=this.options.skipDifficultyVariants?null:this.generateDifficultyVariants(p,d,l,e);s("Phase 3",.8,this.options.skipDifficultyVariants?"Skipped preset difficulty variants (density-based mode)":"Generated easy/medium/hard difficulty variants"),s("Phase 3",1,"Phase 3 complete"),n?.throwIfAborted();const B={difficulty:this.options.difficulty,bandsAnalyzed:["low","mid","high"],transientsDetected:c.metadata.totalTransients,transientsFilteredByIntensity:l.metadata.transientsFilteredByIntensity,densityValidationRetries:l.metadata.densityValidation.maxRetryCount,phrasesDetected:d.phrases.length,averageDensity:u.combinedMetrics.notesPerSecond,naturalDifficulty:p.naturalDifficulty,generationConfig:this.options,duration:t.duration,totalBeats:e.beats.length,balanceStats:b},M={difficultyVariants:y,bandStreams:l.streams,composite:p,analysis:{transientAnalysis:c,quantizationResult:l,phraseAnalysis:d,densityAnalysis:u,scoringResult:m},metadata:B};return this.setCache(a,M),M}analyzeMultiBand(t){return this.multiBandAnalyzer.analyze(t)}detectTransients(t){return this.transientDetector.detect(t)}quantizeTransients(t,e){return this.rhythmQuantizer.quantize(t,e,(n,i,s)=>this.tempoAwareQuantizer.decideGrids(n,i,s))}analyzePhrases(t){return this.phraseAnalyzer.analyze(t)}analyzeDensity(t,e,n){return this.densityAnalyzer.analyze(t,e,n)}scoreStreams(t,e,n,i){return this.streamScorer.updateConfig({bpm:i}),this.streamScorer.score(t,e,n)}generateComposite(t,e,n,i){return this.compositeGenerator.generate(t,e,n,i)}generateDifficultyVariants(t,e,n,i){const s=this.collectGridDecisions(n);return this.variantGenerator.generate(t,i,e,s)}collectGridDecisions(t){const e=new Map,n=[...t.streams.low.gridDecisions,...t.streams.mid.gridDecisions,...t.streams.high.gridDecisions];for(const i of n){const s=e.get(i.beatIndex);(!s||i.confidence>s.confidence)&&e.set(i.beatIndex,i)}return e}static async quickGenerate(t,e){return new O().generate(t,e)}static async generateForDifficulty(t,e,n){return(await new O().generate(t,e)).difficultyVariants[n]}static toJSON(t){const e={difficultyVariants:t.difficultyVariants?{easy:this.serializeDifficultyVariant(t.difficultyVariants.easy),medium:this.serializeDifficultyVariant(t.difficultyVariants.medium),hard:this.serializeDifficultyVariant(t.difficultyVariants.hard),natural:this.serializeDifficultyVariant(t.difficultyVariants.natural)}:null,bandStreams:{low:this.serializeGeneratedRhythmMap(t.bandStreams.low),mid:this.serializeGeneratedRhythmMap(t.bandStreams.mid),high:this.serializeGeneratedRhythmMap(t.bandStreams.high)},composite:this.serializeCompositeStream(t.composite),analysis:{transientAnalysis:this.serializeTransientAnalysis(t.analysis.transientAnalysis),quantizationResult:this.serializeQuantizedBandStreams(t.analysis.quantizationResult),phraseAnalysis:this.serializePhraseAnalysisResult(t.analysis.phraseAnalysis),densityAnalysis:this.serializeDensityAnalysisResult(t.analysis.densityAnalysis),scoringResult:this.serializeStreamScoringResult(t.analysis.scoringResult)},metadata:t.metadata};return JSON.stringify(e,null,2)}static fromJSON(t){const e=JSON.parse(t);return{difficultyVariants:e.difficultyVariants?{easy:this.deserializeDifficultyVariant(e.difficultyVariants.easy),medium:this.deserializeDifficultyVariant(e.difficultyVariants.medium),hard:this.deserializeDifficultyVariant(e.difficultyVariants.hard),natural:this.deserializeDifficultyVariant(e.difficultyVariants.natural)}:null,bandStreams:{low:this.deserializeGeneratedRhythmMap(e.bandStreams.low),mid:this.deserializeGeneratedRhythmMap(e.bandStreams.mid),high:this.deserializeGeneratedRhythmMap(e.bandStreams.high)},composite:this.deserializeCompositeStream(e.composite),analysis:{transientAnalysis:this.deserializeTransientAnalysis(e.analysis.transientAnalysis),quantizationResult:this.deserializeQuantizedBandStreams(e.analysis.quantizationResult),phraseAnalysis:this.deserializePhraseAnalysisResult(e.analysis.phraseAnalysis),densityAnalysis:this.deserializeDensityAnalysisResult(e.analysis.densityAnalysis),scoringResult:this.deserializeStreamScoringResult(e.analysis.scoringResult)},metadata:e.metadata}}static async saveToFile(t,e){if(typeof process>"u"||!process.versions?.node)throw new Error("saveToFile is only available in Node.js environment");const{writeFile:n}=await Promise.resolve().then(()=>require("./__vite-browser-external-BcPniuRQ.cjs")),i=O.toJSON(t);await n(e,i,"utf-8")}static async loadFromFile(t){if(typeof process>"u"||!process.versions?.node)throw new Error("loadFromFile is only available in Node.js environment");const{readFile:e}=await Promise.resolve().then(()=>require("./__vite-browser-external-BcPniuRQ.cjs")),n=await e(t,"utf-8");return O.fromJSON(n)}static serializeDifficultyVariant(t){return{difficulty:t.difficulty,beats:t.beats.map(e=>this.serializeVariantBeat(e)),isUnedited:t.isUnedited,editType:t.editType,editAmount:t.editAmount,patternsInserted:t.patternsInserted,conversionMetadata:t.conversionMetadata,enhancementMetadata:t.enhancementMetadata}}static deserializeDifficultyVariant(t){return{difficulty:t.difficulty,beats:t.beats.map(e=>this.deserializeVariantBeat(e)),isUnedited:t.isUnedited,editType:t.editType,editAmount:t.editAmount,patternsInserted:t.patternsInserted,conversionMetadata:t.conversionMetadata,enhancementMetadata:t.enhancementMetadata}}static serializeVariantBeat(t){return{timestamp:t.timestamp,beatIndex:t.beatIndex,gridPosition:t.gridPosition,gridType:t.gridType,intensity:t.intensity,band:t.band,quantizationError:t.quantizationError,sourceBand:t.sourceBand}}static deserializeVariantBeat(t){return{timestamp:t.timestamp,beatIndex:t.beatIndex,gridPosition:t.gridPosition,gridType:t.gridType,intensity:t.intensity,band:t.band,quantizationError:t.quantizationError,sourceBand:t.sourceBand}}static serializeGeneratedRhythmMap(t){return{audioId:t.audioId,duration:t.duration,beats:t.beats.map(e=>this.serializeGeneratedBeat(e)),gridDecisions:t.gridDecisions,quarterNoteInterval:t.quarterNoteInterval}}static deserializeGeneratedRhythmMap(t){return{audioId:t.audioId,duration:t.duration,beats:t.beats.map(e=>this.deserializeGeneratedBeat(e)),gridDecisions:t.gridDecisions,quarterNoteInterval:t.quarterNoteInterval}}static serializeGeneratedBeat(t){return{timestamp:t.timestamp,beatIndex:t.beatIndex,gridPosition:t.gridPosition,gridType:t.gridType,intensity:t.intensity,band:t.band,quantizationError:t.quantizationError}}static deserializeGeneratedBeat(t){return{timestamp:t.timestamp,beatIndex:t.beatIndex,gridPosition:t.gridPosition,gridType:t.gridType,intensity:t.intensity,band:t.band,quantizationError:t.quantizationError}}static serializeCompositeStream(t){return{beats:t.beats.map(e=>this.serializeCompositeBeat(e)),sections:t.sections,naturalDifficulty:t.naturalDifficulty,quarterNoteInterval:t.quarterNoteInterval,metadata:t.metadata}}static deserializeCompositeStream(t){return{beats:t.beats.map(e=>this.deserializeCompositeBeat(e)),sections:t.sections,naturalDifficulty:t.naturalDifficulty,quarterNoteInterval:t.quarterNoteInterval,metadata:t.metadata}}static serializeCompositeBeat(t){return{timestamp:t.timestamp,beatIndex:t.beatIndex,gridPosition:t.gridPosition,gridType:t.gridType,intensity:t.intensity,band:t.band,quantizationError:t.quantizationError,sourceBand:t.sourceBand,balancerAction:t.balancerAction}}static deserializeCompositeBeat(t){return{timestamp:t.timestamp,beatIndex:t.beatIndex,gridPosition:t.gridPosition,gridType:t.gridType,intensity:t.intensity,band:t.band,quantizationError:t.quantizationError,sourceBand:t.sourceBand,balancerAction:t.balancerAction}}static serializeTransientAnalysis(t){return{transients:t.transients.map(e=>this.serializeTransientResult(e)),bandTransients:Array.from(t.bandTransients.entries()).map(([e,n])=>({band:e,transients:n.map(i=>this.serializeTransientResult(i))})),metadata:{totalTransients:t.metadata.totalTransients,transientsPerBand:Array.from(t.metadata.transientsPerBand.entries()).map(([e,n])=>({band:e,count:n})),duration:t.metadata.duration,averageIntensity:t.metadata.averageIntensity,detectionMethodsUsed:t.metadata.detectionMethodsUsed}}}static deserializeTransientAnalysis(t){const e=new Map;for(const i of t.bandTransients)e.set(i.band,i.transients.map(s=>this.deserializeTransientResult(s)));const n=new Map;for(const i of t.metadata.transientsPerBand)n.set(i.band,i.count);return{transients:t.transients.map(i=>this.deserializeTransientResult(i)),bandTransients:e,metadata:{totalTransients:t.metadata.totalTransients,transientsPerBand:n,duration:t.metadata.duration,averageIntensity:t.metadata.averageIntensity,detectionMethodsUsed:t.metadata.detectionMethodsUsed}}}static serializeTransientResult(t){return{timestamp:t.timestamp,intensity:t.intensity,band:t.band,detectionMethod:t.detectionMethod,nearestBeat:t.nearestBeat}}static deserializeTransientResult(t){return{timestamp:t.timestamp,intensity:t.intensity,band:t.band,detectionMethod:t.detectionMethod,nearestBeat:t.nearestBeat}}static serializeQuantizedBandStreams(t){return{streams:{low:this.serializeGeneratedRhythmMap(t.streams.low),mid:this.serializeGeneratedRhythmMap(t.streams.mid),high:this.serializeGeneratedRhythmMap(t.streams.high)},metadata:{densityValidation:this.serializeDensityValidationResult(t.metadata.densityValidation),transientsFilteredByIntensity:t.metadata.transientsFilteredByIntensity,transientsFilteredByBand:t.metadata.transientsFilteredByBand}}}static serializeDensityValidationResult(t){return{isValid:t.isValid,bands:{low:this.serializeBandDensityValidationResult(t.bands.low),mid:this.serializeBandDensityValidationResult(t.bands.mid),high:this.serializeBandDensityValidationResult(t.bands.high)},maxRetryCount:t.maxRetryCount,maxSensitivityReduction:t.maxSensitivityReduction}}static serializeBandDensityValidationResult(t){return{band:t.band,isValid:t.isValid,minIntervalDetected:t.minIntervalDetected,requiredMinInterval:t.requiredMinInterval,retryCount:t.retryCount,sensitivityReduction:t.sensitivityReduction,finalIntensityThreshold:t.finalIntensityThreshold,transientsRemaining:t.transientsRemaining}}static deserializeQuantizedBandStreams(t){return{streams:{low:this.deserializeGeneratedRhythmMap(t.streams.low),mid:this.deserializeGeneratedRhythmMap(t.streams.mid),high:this.deserializeGeneratedRhythmMap(t.streams.high)},metadata:{densityValidation:this.deserializeDensityValidationResult(t.metadata.densityValidation),transientsFilteredByIntensity:t.metadata.transientsFilteredByIntensity,transientsFilteredByBand:t.metadata.transientsFilteredByBand}}}static deserializeDensityValidationResult(t){return{isValid:t.isValid,bands:{low:this.deserializeBandDensityValidationResult(t.bands.low),mid:this.deserializeBandDensityValidationResult(t.bands.mid),high:this.deserializeBandDensityValidationResult(t.bands.high)},maxRetryCount:t.maxRetryCount,maxSensitivityReduction:t.maxSensitivityReduction}}static deserializeBandDensityValidationResult(t){return{band:t.band,isValid:t.isValid,minIntervalDetected:t.minIntervalDetected,requiredMinInterval:t.requiredMinInterval,retryCount:t.retryCount,sensitivityReduction:t.sensitivityReduction,finalIntensityThreshold:t.finalIntensityThreshold,transientsRemaining:t.transientsRemaining}}static serializePhraseAnalysisResult(t){return{phrases:t.phrases.map(e=>this.serializeRhythmicPhrase(e)),phrasesByBand:Array.from(t.phrasesByBand.entries()).map(([e,n])=>({band:e,phrases:n.map(i=>this.serializeRhythmicPhrase(i))})),mostSignificantPhrases:t.mostSignificantPhrases.map(e=>this.serializeRhythmicPhrase(e)),phrasesBySize:Array.from(t.phrasesBySize.entries()).map(([e,n])=>({size:e,phrases:n.map(i=>this.serializeRhythmicPhrase(i))})),patternLibrary:t.patternLibrary.map(e=>this.serializeRhythmicPhrase(e)),bandAnalysis:{low:this.serializeBandPhraseAnalysis(t.bandAnalysis.low),mid:this.serializeBandPhraseAnalysis(t.bandAnalysis.mid),high:this.serializeBandPhraseAnalysis(t.bandAnalysis.high)}}}static deserializePhraseAnalysisResult(t){const e=new Map;for(const i of t.phrasesByBand)e.set(i.band,i.phrases.map(s=>this.deserializeRhythmicPhrase(s)));const n=new Map;for(const i of t.phrasesBySize)n.set(i.size,i.phrases.map(s=>this.deserializeRhythmicPhrase(s)));return{phrases:t.phrases.map(i=>this.deserializeRhythmicPhrase(i)),phrasesByBand:e,mostSignificantPhrases:t.mostSignificantPhrases.map(i=>this.deserializeRhythmicPhrase(i)),phrasesBySize:n,patternLibrary:t.patternLibrary.map(i=>this.deserializeRhythmicPhrase(i)),bandAnalysis:{low:this.deserializeBandPhraseAnalysis(t.bandAnalysis.low),mid:this.deserializeBandPhraseAnalysis(t.bandAnalysis.mid),high:this.deserializeBandPhraseAnalysis(t.bandAnalysis.high)}}}static serializeRhythmicPhrase(t){return{id:t.id,pattern:t.pattern.map(e=>this.serializeGeneratedBeat(e)),sizeInBeats:t.sizeInBeats,sourceBand:t.sourceBand,occurrences:t.occurrences,significance:t.significance,hasVariation:t.hasVariation,availableForReuse:t.availableForReuse}}static deserializeRhythmicPhrase(t){return{id:t.id,pattern:t.pattern.map(e=>this.deserializeGeneratedBeat(e)),sizeInBeats:t.sizeInBeats,sourceBand:t.sourceBand,occurrences:t.occurrences,significance:t.significance,hasVariation:t.hasVariation,availableForReuse:t.availableForReuse}}static serializeBandPhraseAnalysis(t){return{band:t.band,phrases:t.phrases.map(e=>this.serializeRhythmicPhrase(e)),phrasesBySize:Array.from(t.phrasesBySize.entries()).map(([e,n])=>({size:e,phrases:n.map(i=>this.serializeRhythmicPhrase(i))})),phrasesWithVariation:t.phrasesWithVariation.map(e=>this.serializeRhythmicPhrase(e))}}static deserializeBandPhraseAnalysis(t){const e=new Map;for(const n of t.phrasesBySize)e.set(n.size,n.phrases.map(i=>this.deserializeRhythmicPhrase(i)));return{band:t.band,phrases:t.phrases.map(n=>this.deserializeRhythmicPhrase(n)),phrasesBySize:e,phrasesWithVariation:t.phrasesWithVariation.map(n=>this.deserializeRhythmicPhrase(n))}}static serializeDensityAnalysisResult(t){return{bandMetrics:{low:this.serializeBandDensityMetrics(t.bandMetrics.low),mid:this.serializeBandDensityMetrics(t.bandMetrics.mid),high:this.serializeBandDensityMetrics(t.bandMetrics.high)},combinedMetrics:t.combinedMetrics,sections:t.sections,perBeatDensity:t.perBeatDensity}}static deserializeDensityAnalysisResult(t){return{bandMetrics:{low:this.deserializeBandDensityMetrics(t.bandMetrics.low),mid:this.deserializeBandDensityMetrics(t.bandMetrics.mid),high:this.deserializeBandDensityMetrics(t.bandMetrics.high)},combinedMetrics:t.combinedMetrics,sections:t.sections,perBeatDensity:t.perBeatDensity}}static serializeBandDensityMetrics(t){return{band:t.band,totalBeats:t.totalBeats,totalTransients:t.totalTransients,notesPerSecond:t.notesPerSecond,minNotesPerSecond:t.minNotesPerSecond,maxNotesPerSecond:t.maxNotesPerSecond,variance:t.variance,densityCategory:t.densityCategory,naturalDifficulty:t.naturalDifficulty,perBeatDensity:t.perBeatDensity}}static deserializeBandDensityMetrics(t){return{band:t.band,totalBeats:t.totalBeats,totalTransients:t.totalTransients,notesPerSecond:t.notesPerSecond,minNotesPerSecond:t.minNotesPerSecond,maxNotesPerSecond:t.maxNotesPerSecond,variance:t.variance,densityCategory:t.densityCategory,naturalDifficulty:t.naturalDifficulty,perBeatDensity:t.perBeatDensity}}static serializeStreamScoringResult(t){return{sectionScores:t.sectionScores,bandTotals:t.bandTotals,bandAverages:t.bandAverages,sectionWinners:t.sectionWinners,config:t.config}}static deserializeStreamScoringResult(t){return{sectionScores:t.sectionScores,bandTotals:t.bandTotals,bandAverages:t.bandAverages,sectionWinners:t.sectionWinners,config:t.config}}}const Cn={minFrequency:80,maxFrequency:1e3,frameSize:2048,hopSize:512,voicingThreshold:.2,transitionPenalty:.5,selfTransitionProbability:.99,yinThreshold:.4,targetSampleRate:44100},Pt=69,Ct=440,Rn=["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"];class Dn{constructor(t={}){if(this.states=[],this.transitionMatrix=[],this.config={...Cn,...t},this.config.minFrequency<=0)throw new Error(`minFrequency must be positive, got: ${this.config.minFrequency}`);if(this.config.maxFrequency<=this.config.minFrequency)throw new Error("maxFrequency must be greater than minFrequency");if(this.config.frameSize<=0||(this.config.frameSize&this.config.frameSize-1)!==0)throw new Error("frameSize must be a positive power of 2");if(this.config.hopSize<=0)throw new Error("hopSize must be positive");if(this.config.voicingThreshold<0||this.config.voicingThreshold>1)throw new Error("voicingThreshold must be between 0 and 1");this.initializeHMM()}getConfig(){return{...this.config}}initializeHMM(){const{minFrequency:t,maxFrequency:e}=this.config,n=this.frequencyToMidi(t),i=this.frequencyToMidi(e);this.states=[];for(let s=n;s<=i;s+=.5)this.states.push({frequency:this.midiToFrequency(s),midiNote:Math.round(s),index:this.states.length});this.states.push({frequency:0,midiNote:-1,index:this.states.length}),this.transitionMatrix=this.computeTransitionMatrix()}computeTransitionMatrix(){const t=this.states.length,e=[];for(let n=0;n<t;n++){e[n]=[];for(let i=0;i<t;i++)e[n][i]=this.transitionProbability(n,i)}return e}transitionProbability(t,e){const{selfTransitionProbability:n,transitionPenalty:i}=this.config,a=this.states.length-1;if(t===e)return Math.log(n);if(t===a||e===a)return Math.log((1-n)*.1);const o=this.states[t].midiNote,r=this.states[e].midiNote,c=Math.abs(r-o),l=(1-n)*Math.exp(-i*c);return Math.log(l)}frequencyToMidi(t){return Pt+12*Math.log2(t/Ct)}midiToFrequency(t){return Ct*Math.pow(2,(t-Pt)/12)}midiToNoteName(t){const e=Math.floor(t/12)-1,n=Math.round(t)%12;return`${Rn[n]}${e}`}detect(t){const n=X(t,this.config.targetSampleRate).data,i=this.config.targetSampleRate,{frameSize:s,hopSize:a}=this.config,o=Math.floor((n.length-s)/a)+1,r=a/i,c=[],l=[];for(let m=0;m<o;m++){const f=m*a,g=n.slice(f,f+s),{filtered:p,all:b}=this.analyzeFrame(g,i);c.push(p),l.push(b)}const d=this.viterbiDecode(c),u=[];for(let m=0;m<o;m++){const f=d[m],g=this.states[f],p=c[m],b=l[m],y={timestamp:m*r,frequency:g.frequency,probability:this.getFrameProbability(f,p),isVoiced:g.frequency>0,midiNote:g.frequency>0?g.midiNote:null,noteName:g.frequency>0?this.midiToNoteName(g.midiNote):null};b.length>1&&(y.alternativeHypotheses=b.slice(0,5).map(B=>({frequency:B.frequency,probability:B.probability}))),u.push(y)}return u}detectSignal(t,e){const{frameSize:n,hopSize:i}=this.config,s=Math.floor((t.length-n)/i)+1,a=i/e,o=[],r=[];for(let d=0;d<s;d++){const u=d*i,m=t.slice(u,u+n),{filtered:f,all:g}=this.analyzeFrame(m,e);o.push(f),r.push(g)}const c=this.viterbiDecode(o),l=[];for(let d=0;d<s;d++){const u=c[d],m=this.states[u],f=o[d],g=r[d],p={timestamp:d*a,frequency:m.frequency,probability:this.getFrameProbability(u,f),isVoiced:m.frequency>0,midiNote:m.frequency>0?m.midiNote:null,noteName:m.frequency>0?this.midiToNoteName(m.midiNote):null};g.length>1&&(p.alternativeHypotheses=g.slice(0,5).map(b=>({frequency:b.frequency,probability:b.probability}))),l.push(p)}return l}detectSignalRaw(t,e){const{frameSize:n,hopSize:i,voicingThreshold:s}=this.config,a=Math.floor((t.length-n)/i)+1,o=i/e,r=[];let c=0,l=0;const d={below01:0,b01_02:0,b02_03:0,b03_04:0,b04_05:0,above05:0};for(let u=0;u<a;u++){const m=u*i,f=t.slice(m,m+n),{filtered:g,all:p}=this.analyzeFrame(f,e),b=u*o;if(g.length>0){c++;const y=g[0].probability;if(y<.1?d.below01++:y<.2?d.b01_02++:y<.3?d.b02_03++:y<.4?d.b03_04++:y<.5?d.b04_05++:d.above05++,y>=s){const B=g[0],M=Math.round(this.frequencyToMidi(B.frequency)),T={timestamp:b,frequency:B.frequency,probability:B.probability,isVoiced:!0,midiNote:M,noteName:this.midiToNoteName(M)};p.length>1&&(T.alternativeHypotheses=p.slice(0,5).map(S=>({frequency:S.frequency,probability:S.probability}))),r.push(T)}else r.push({timestamp:b,frequency:0,probability:0,isVoiced:!1,midiNote:null,noteName:null})}else l++,r.push({timestamp:b,frequency:0,probability:0,isVoiced:!1,midiNote:null,noteName:null})}return console.log("[PitchDetector.detectSignalRaw] Candidate quality:",{numFrames:a,framesWithCandidates:c,framesWithNoCandidates:l,candidateRate:(c/a*100).toFixed(1)+"%",voicingThreshold:s,probBuckets:d}),r}detectAt(t,e,n){const{frameSize:i,hopSize:s}=this.config,a=Math.round(n*e),o=Math.max(0,a-Math.floor(i/2)),r=Math.min(t.length,o+i);if(r-o<i)return{timestamp:n,frequency:0,probability:0,isVoiced:!1,midiNote:null,noteName:null};const c=t.slice(o,r),{filtered:l,all:d}=this.analyzeFrame(c,e);if(l.length===0)return{timestamp:n,frequency:0,probability:0,isVoiced:!1,midiNote:null,noteName:null};const u=l[0],m=Math.round(this.frequencyToMidi(u.frequency)),f={timestamp:n,frequency:u.frequency,probability:u.probability,isVoiced:u.probability>=this.config.voicingThreshold,midiNote:m,noteName:this.midiToNoteName(m)};return d.length>1&&(f.alternativeHypotheses=d.slice(0,5).map(g=>({frequency:g.frequency,probability:g.probability}))),f}analyzeFrame(t,e){const{minFrequency:n,maxFrequency:i,yinThreshold:s}=this.config,a=Math.ceil(e/n),o=Math.max(2,Math.floor(e/i)),r=Math.min(a,Math.floor(t.length/2)),c=this.computeDifferenceFunction(t,r),l=this.computeCMNDF(c,o,r),d=[];for(let f=o+1;f<r-1;f++)if(l[f]<l[f-1]&&l[f]<l[f+1]&&l[f]<s){const g=this.parabolicInterpolation(l,f),p=e/g,b=1-l[f];p>=n&&p<=i&&d.push({lag:g,frequency:p,probability:b})}if(d.sort((f,g)=>g.probability-f.probability),d.length===0)return{filtered:[],all:[]};const u=[],m=d[0].probability;for(const f of d){let g=!1;for(const p of d){if(p.frequency<=f.frequency||p.probability<m*.9)continue;const b=p.frequency/f.frequency,y=Math.round(b),B=Math.abs(b-y);if(y>=2&&y<=5&&B<.1){g=!0;break}}g||u.push(f)}return u.length===0&&d.length>0&&u.push(d[0]),{filtered:u,all:d}}computeDifferenceFunction(t,e){const n=t.length,i=new Float32Array(e+1);i[0]=0;for(let s=1;s<=e;s++){let a=0;for(let o=0;o<n-s;o++){const r=t[o]-t[o+s];a+=r*r}i[s]=a}return i}computeCMNDF(t,e,n){const i=new Float32Array(t.length);i[0]=1;let s=0;for(let a=1;a<=n;a++)s+=t[a],i[a]=t[a]*a/s;return i}parabolicInterpolation(t,e){if(e<=0||e>=t.length-1)return e;const n=t[e-1],i=t[e],s=t[e+1],a=(s-n)/(2*(2*i-n-s));return Math.max(e-1,Math.min(e+1,e+a))}getFrameProbability(t,e){const i=this.states.length-1;if(t===i)return e.length===0?1:1-e[0].probability;const s=this.states[t].frequency;let a=0;for(const o of e)Math.abs(o.frequency-s)/s<.05&&(a=Math.max(a,o.probability));return a}viterbiDecode(t){const e=t.length,n=this.states.length;if(e===0)return[];const i=[];i[0]=[];for(let r=0;r<n;r++){const c=this.priorLogProbability(r,t[0]);i[0][r]={logProbability:c,previousState:-1}}for(let r=1;r<e;r++){i[r]=[];for(let c=0;c<n;c++){const l=this.observationLogProbability(c,t[r]);let d=0,u=-1/0;for(let m=0;m<n;m++){const f=this.transitionMatrix[m][c],g=i[r-1][m].logProbability+f;g>u&&(u=g,d=m)}i[r][c]={logProbability:u+l,previousState:d}}}const s=new Array(e);let a=0,o=i[e-1][0].logProbability;for(let r=1;r<n;r++)i[e-1][r].logProbability>o&&(o=i[e-1][r].logProbability,a=r);s[e-1]=a;for(let r=e-2;r>=0;r--)s[r]=i[r+1][s[r+1]].previousState;return s}priorLogProbability(t,e){const n=this.states.length,i=n-1,s=Math.log(.7/(n-1)),a=Math.log(.3);return t===i?a+this.observationLogProbability(t,e):s+this.observationLogProbability(t,e)}observationLogProbability(t,e){const i=this.states.length-1;if(t===i){if(e.length===0)return Math.log(.9);const o=e[0].probability;return Math.log(1-o*.8)}const s=this.states[t].frequency;let a=0;for(const o of e){const r=o.frequency/s,c=Math.abs(r-1);if(c<.05){const l=1-c/.05*.2,d=o.probability*l;d>a&&(a=d)}if(a===0){const l=Math.abs(r-.5),d=Math.abs(r-2);if(l<.05||d<.05){const u=o.probability*.4;u>a&&(a=u)}}}return Math.log(a===0?.01:a)}}const En=[{id:"ddr_basic_single_up",name:"Single Up",controllerMode:"ddr",keys:["up"],measures:1,tags:["basic","single","beginner"],category:"basic",difficulty:1},{id:"ddr_basic_single_down",name:"Single Down",controllerMode:"ddr",keys:["down"],measures:1,tags:["basic","single","beginner"],category:"basic",difficulty:1},{id:"ddr_basic_single_left",name:"Single Left",controllerMode:"ddr",keys:["left"],measures:1,tags:["basic","single","beginner"],category:"basic",difficulty:1},{id:"ddr_basic_single_right",name:"Single Right",controllerMode:"ddr",keys:["right"],measures:1,tags:["basic","single","beginner"],category:"basic",difficulty:1},{id:"ddr_basic_alternating_up_down",name:"Alternating Up-Down",controllerMode:"ddr",keys:["up","down","up","down"],measures:1,tags:["basic","alternating","vertical"],category:"basic",difficulty:2},{id:"ddr_basic_alternating_left_right",name:"Alternating Left-Right",controllerMode:"ddr",keys:["left","right","left","right"],measures:1,tags:["basic","alternating","horizontal"],category:"basic",difficulty:2},{id:"ddr_basic_alternating_up_left",name:"Alternating Up-Left",controllerMode:"ddr",keys:["up","left","up","left"],measures:1,tags:["basic","alternating"],category:"basic",difficulty:2},{id:"ddr_basic_alternating_down_right",name:"Alternating Down-Right",controllerMode:"ddr",keys:["down","right","down","right"],measures:1,tags:["basic","alternating"],category:"basic",difficulty:2},{id:"ddr_basic_double_up",name:"Double Up",controllerMode:"ddr",keys:["up","up","down","down"],measures:1,tags:["basic","double","repeat"],category:"basic",difficulty:2},{id:"ddr_basic_double_left",name:"Double Left",controllerMode:"ddr",keys:["left","left","right","right"],measures:1,tags:["basic","double","repeat"],category:"basic",difficulty:2},{id:"ddr_basic_walk_forward",name:"Walk Forward",controllerMode:"ddr",keys:["left","right","left","right"],measures:1,tags:["basic","walk","horizontal"],category:"basic",difficulty:2},{id:"ddr_basic_walk_vertical",name:"Walk Vertical",controllerMode:"ddr",keys:["up","down","up","down"],measures:1,tags:["basic","walk","vertical"],category:"basic",difficulty:2}],zn=[{id:"ddr_roll_clockwise_full",name:"Clockwise Full Roll",controllerMode:"ddr",keys:["up","right","down","left"],measures:1,tags:["roll","clockwise","full"],category:"roll",difficulty:3},{id:"ddr_roll_clockwise_extended",name:"Clockwise Extended Roll",controllerMode:"ddr",keys:["up","right","down","left","up","right","down","left"],measures:2,tags:["roll","clockwise","extended"],category:"roll",difficulty:4},{id:"ddr_roll_counterclockwise_full",name:"Counter-Clockwise Full Roll",controllerMode:"ddr",keys:["up","left","down","right"],measures:1,tags:["roll","counterclockwise","full"],category:"roll",difficulty:3},{id:"ddr_roll_counterclockwise_extended",name:"Counter-Clockwise Extended Roll",controllerMode:"ddr",keys:["up","left","down","right","up","left","down","right"],measures:2,tags:["roll","counterclockwise","extended"],category:"roll",difficulty:4},{id:"ddr_roll_half_right",name:"Half Roll Right",controllerMode:"ddr",keys:["up","right","down"],measures:1,tags:["roll","half","right"],category:"roll",difficulty:3},{id:"ddr_roll_half_left",name:"Half Roll Left",controllerMode:"ddr",keys:["up","left","down"],measures:1,tags:["roll","half","left"],category:"roll",difficulty:3},{id:"ddr_roll_bottom_half_right",name:"Bottom Half Roll Right",controllerMode:"ddr",keys:["down","right","up"],measures:1,tags:["roll","half","bottom","right"],category:"roll",difficulty:3},{id:"ddr_roll_bottom_half_left",name:"Bottom Half Roll Left",controllerMode:"ddr",keys:["down","left","up"],measures:1,tags:["roll","half","bottom","left"],category:"roll",difficulty:3},{id:"ddr_roll_triangle_up",name:"Triangle Roll Up",controllerMode:"ddr",keys:["left","up","right"],measures:1,tags:["roll","triangle","top"],category:"roll",difficulty:3},{id:"ddr_roll_triangle_down",name:"Triangle Roll Down",controllerMode:"ddr",keys:["left","down","right"],measures:1,tags:["roll","triangle","bottom"],category:"roll",difficulty:3}],Fn=[{id:"ddr_stream_vertical_8",name:"Vertical Stream 8",controllerMode:"ddr",keys:["up","down","up","down","up","down","up","down"],measures:2,tags:["stream","vertical","fast"],category:"stream",difficulty:5},{id:"ddr_stream_vertical_16",name:"Vertical Stream 16",controllerMode:"ddr",keys:["up","down","up","down","up","down","up","down","up","down","up","down","up","down","up","down"],measures:4,tags:["stream","vertical","extended"],category:"stream",difficulty:7},{id:"ddr_stream_horizontal_8",name:"Horizontal Stream 8",controllerMode:"ddr",keys:["left","right","left","right","left","right","left","right"],measures:2,tags:["stream","horizontal","fast"],category:"stream",difficulty:5},{id:"ddr_stream_diagonal_1",name:"Diagonal Stream 1",controllerMode:"ddr",keys:["up","right","up","right","up","right","up","right"],measures:2,tags:["stream","diagonal"],category:"stream",difficulty:5},{id:"ddr_stream_diagonal_2",name:"Diagonal Stream 2",controllerMode:"ddr",keys:["up","left","up","left","up","left","up","left"],measures:2,tags:["stream","diagonal"],category:"stream",difficulty:5},{id:"ddr_stream_diagonal_3",name:"Diagonal Stream 3",controllerMode:"ddr",keys:["down","right","down","right","down","right","down","right"],measures:2,tags:["stream","diagonal"],category:"stream",difficulty:5},{id:"ddr_stream_diagonal_4",name:"Diagonal Stream 4",controllerMode:"ddr",keys:["down","left","down","left","down","left","down","left"],measures:2,tags:["stream","diagonal"],category:"stream",difficulty:5},{id:"ddr_stream_mixed_box",name:"Box Stream",controllerMode:"ddr",keys:["up","right","down","left","up","right","down","left"],measures:2,tags:["stream","box","circular"],category:"stream",difficulty:6},{id:"ddr_stream_mixed_zigzag",name:"Zigzag Stream",controllerMode:"ddr",keys:["up","left","down","right","up","left","down","right"],measures:2,tags:["stream","zigzag"],category:"stream",difficulty:6}],Nn=[{id:"ddr_jump_opposite_vertical",name:"Opposite Jump Vertical",controllerMode:"ddr",keys:["up","down","up","down"],measures:1,tags:["jump","opposite","vertical"],category:"jump",difficulty:4},{id:"ddr_jump_opposite_horizontal",name:"Opposite Jump Horizontal",controllerMode:"ddr",keys:["left","right","left","right"],measures:1,tags:["jump","opposite","horizontal"],category:"jump",difficulty:4},{id:"ddr_jump_diagonal_1",name:"Diagonal Jump 1",controllerMode:"ddr",keys:["up","left","up","left"],measures:1,tags:["jump","diagonal"],category:"jump",difficulty:4},{id:"ddr_jump_diagonal_2",name:"Diagonal Jump 2",controllerMode:"ddr",keys:["up","right","up","right"],measures:1,tags:["jump","diagonal"],category:"jump",difficulty:4},{id:"ddr_jump_diagonal_3",name:"Diagonal Jump 3",controllerMode:"ddr",keys:["down","left","down","left"],measures:1,tags:["jump","diagonal"],category:"jump",difficulty:4},{id:"ddr_jump_diagonal_4",name:"Diagonal Jump 4",controllerMode:"ddr",keys:["down","right","down","right"],measures:1,tags:["jump","diagonal"],category:"jump",difficulty:4},{id:"ddr_jump_cross_pattern",name:"Cross Pattern",controllerMode:"ddr",keys:["up","left","down","right"],measures:1,tags:["jump","cross"],category:"jump",difficulty:5},{id:"ddr_jump_x_pattern",name:"X Pattern",controllerMode:"ddr",keys:["up","right","down","left"],measures:1,tags:["jump","x"],category:"jump",difficulty:5},{id:"ddr_jump_leap_sequence",name:"Leap Sequence",controllerMode:"ddr",keys:["up","down","left","right","up","down"],measures:2,tags:["jump","leap","sequence"],category:"jump",difficulty:6},{id:"ddr_jump_corner_to_corner",name:"Corner to Corner",controllerMode:"ddr",keys:["up","right","down","left","up","right"],measures:2,tags:["jump","corner"],category:"jump",difficulty:6}],On=[{id:"ddr_transition_build_up",name:"Build Up",controllerMode:"ddr",keys:["left","left","up","up","right","right"],measures:2,tags:["transition","build-up","intensity"],category:"transition",difficulty:4},{id:"ddr_transition_wind_down",name:"Wind Down",controllerMode:"ddr",keys:["right","right","up","up","left","left"],measures:2,tags:["transition","wind-down"],category:"transition",difficulty:4},{id:"ddr_transition_fill_4",name:"Fill 4 Count",controllerMode:"ddr",keys:["up","right","down","left"],measures:1,tags:["transition","fill"],category:"transition",difficulty:3},{id:"ddr_transition_fill_8",name:"Fill 8 Count",controllerMode:"ddr",keys:["up","up","right","right","down","down","left","left"],measures:2,tags:["transition","fill","extended"],category:"transition",difficulty:4}],kn=[{id:"gh_basic_single_1",name:"Single Fret 1",controllerMode:"guitar_hero",keys:[1],measures:1,tags:["basic","single","beginner"],category:"basic",difficulty:1},{id:"gh_basic_single_2",name:"Single Fret 2",controllerMode:"guitar_hero",keys:[2],measures:1,tags:["basic","single","beginner"],category:"basic",difficulty:1},{id:"gh_basic_single_3",name:"Single Fret 3",controllerMode:"guitar_hero",keys:[3],measures:1,tags:["basic","single","beginner"],category:"basic",difficulty:1},{id:"gh_basic_single_4",name:"Single Fret 4",controllerMode:"guitar_hero",keys:[4],measures:1,tags:["basic","single","beginner"],category:"basic",difficulty:1},{id:"gh_basic_single_5",name:"Single Fret 5",controllerMode:"guitar_hero",keys:[5],measures:1,tags:["basic","single","beginner"],category:"basic",difficulty:1},{id:"gh_basic_ascending_full",name:"Ascending Full Run",controllerMode:"guitar_hero",keys:[1,2,3,4,5],measures:1,tags:["basic","ascending","full"],category:"basic",difficulty:3},{id:"gh_basic_ascending_quad",name:"Ascending Quad",controllerMode:"guitar_hero",keys:[1,2,3,4],measures:1,tags:["basic","ascending"],category:"basic",difficulty:2},{id:"gh_basic_ascending_tri_low",name:"Ascending Tri Low",controllerMode:"guitar_hero",keys:[1,2,3],measures:1,tags:["basic","ascending","tri"],category:"basic",difficulty:2},{id:"gh_basic_ascending_tri_mid",name:"Ascending Tri Mid",controllerMode:"guitar_hero",keys:[2,3,4],measures:1,tags:["basic","ascending","tri"],category:"basic",difficulty:2},{id:"gh_basic_ascending_tri_high",name:"Ascending Tri High",controllerMode:"guitar_hero",keys:[3,4,5],measures:1,tags:["basic","ascending","tri"],category:"basic",difficulty:2},{id:"gh_basic_descending_full",name:"Descending Full Run",controllerMode:"guitar_hero",keys:[5,4,3,2,1],measures:1,tags:["basic","descending","full"],category:"basic",difficulty:3},{id:"gh_basic_descending_quad",name:"Descending Quad",controllerMode:"guitar_hero",keys:[5,4,3,2],measures:1,tags:["basic","descending"],category:"basic",difficulty:2},{id:"gh_basic_descending_tri_high",name:"Descending Tri High",controllerMode:"guitar_hero",keys:[5,4,3],measures:1,tags:["basic","descending","tri"],category:"basic",difficulty:2},{id:"gh_basic_descending_tri_mid",name:"Descending Tri Mid",controllerMode:"guitar_hero",keys:[4,3,2],measures:1,tags:["basic","descending","tri"],category:"basic",difficulty:2},{id:"gh_basic_descending_tri_low",name:"Descending Tri Low",controllerMode:"guitar_hero",keys:[3,2,1],measures:1,tags:["basic","descending","tri"],category:"basic",difficulty:2},{id:"gh_basic_step_up",name:"Step Up",controllerMode:"guitar_hero",keys:[1,2,3,4],measures:1,tags:["basic","step","up"],category:"basic",difficulty:2},{id:"gh_basic_step_down",name:"Step Down",controllerMode:"guitar_hero",keys:[5,4,3,2],measures:1,tags:["basic","step","down"],category:"basic",difficulty:2}],Gn=[{id:"gh_alternating_1_3",name:"Alternating 1-3",controllerMode:"guitar_hero",keys:[1,3,1,3],measures:1,tags:["alternating","skip"],category:"basic",difficulty:3},{id:"gh_alternating_2_4",name:"Alternating 2-4",controllerMode:"guitar_hero",keys:[2,4,2,4],measures:1,tags:["alternating","skip"],category:"basic",difficulty:3},{id:"gh_alternating_3_5",name:"Alternating 3-5",controllerMode:"guitar_hero",keys:[3,5,3,5],measures:1,tags:["alternating","skip"],category:"basic",difficulty:3},{id:"gh_alternating_1_2",name:"Alternating 1-2",controllerMode:"guitar_hero",keys:[1,2,1,2],measures:1,tags:["alternating","adjacent"],category:"basic",difficulty:2},{id:"gh_alternating_2_3",name:"Alternating 2-3",controllerMode:"guitar_hero",keys:[2,3,2,3],measures:1,tags:["alternating","adjacent"],category:"basic",difficulty:2},{id:"gh_alternating_3_4",name:"Alternating 3-4",controllerMode:"guitar_hero",keys:[3,4,3,4],measures:1,tags:["alternating","adjacent"],category:"basic",difficulty:2},{id:"gh_alternating_4_5",name:"Alternating 4-5",controllerMode:"guitar_hero",keys:[4,5,4,5],measures:1,tags:["alternating","adjacent"],category:"basic",difficulty:2},{id:"gh_alternating_tri_1_3_5",name:"Alternating 1-3-5",controllerMode:"guitar_hero",keys:[1,3,5,3],measures:1,tags:["alternating","tri","wide"],category:"basic",difficulty:4},{id:"gh_alternating_tri_1_2_3",name:"Alternating 1-2-3",controllerMode:"guitar_hero",keys:[1,2,3,2],measures:1,tags:["alternating","tri","tight"],category:"basic",difficulty:3},{id:"gh_alternating_tri_3_4_5",name:"Alternating 3-4-5",controllerMode:"guitar_hero",keys:[3,4,5,4],measures:1,tags:["alternating","tri","tight"],category:"basic",difficulty:3},{id:"gh_alternating_extended_1_3",name:"Extended Alternating 1-3",controllerMode:"guitar_hero",keys:[1,3,1,3,1,3,1,3],measures:2,tags:["alternating","extended"],category:"basic",difficulty:4},{id:"gh_alternating_extended_2_4",name:"Extended Alternating 2-4",controllerMode:"guitar_hero",keys:[2,4,2,4,2,4,2,4],measures:2,tags:["alternating","extended"],category:"basic",difficulty:4}],qn=[{id:"gh_chord_power_full",name:"Power Chord Full",controllerMode:"guitar_hero",keys:[1,3,5],measures:1,tags:["chord","power","full"],category:"chord",difficulty:4},{id:"gh_chord_power_low",name:"Power Chord Low",controllerMode:"guitar_hero",keys:[1,3],measures:1,tags:["chord","power","low"],category:"chord",difficulty:3},{id:"gh_chord_power_mid",name:"Power Chord Mid",controllerMode:"guitar_hero",keys:[2,4],measures:1,tags:["chord","power","mid"],category:"chord",difficulty:3},{id:"gh_chord_power_high",name:"Power Chord High",controllerMode:"guitar_hero",keys:[3,5],measures:1,tags:["chord","power","high"],category:"chord",difficulty:3},{id:"gh_chord_triad_low",name:"Triad Low",controllerMode:"guitar_hero",keys:[1,2,3],measures:1,tags:["chord","triad","low"],category:"chord",difficulty:4},{id:"gh_chord_triad_mid",name:"Triad Mid",controllerMode:"guitar_hero",keys:[2,3,4],measures:1,tags:["chord","triad","mid"],category:"chord",difficulty:4},{id:"gh_chord_triad_high",name:"Triad High",controllerMode:"guitar_hero",keys:[3,4,5],measures:1,tags:["chord","triad","high"],category:"chord",difficulty:4},{id:"gh_chord_progression_1",name:"Chord Progression 1",controllerMode:"guitar_hero",keys:[1,3,2,4,3,5],measures:2,tags:["chord","progression"],category:"chord",difficulty:5},{id:"gh_chord_progression_2",name:"Chord Progression 2",controllerMode:"guitar_hero",keys:[1,2,3,4,5,4,3,2],measures:2,tags:["chord","progression","wave"],category:"chord",difficulty:5}],Vn=[{id:"gh_jump_wide_1_4",name:"Wide Jump 1-4",controllerMode:"guitar_hero",keys:[1,4,1,4],measures:1,tags:["jump","wide"],category:"jump",difficulty:4},{id:"gh_jump_wide_2_5",name:"Wide Jump 2-5",controllerMode:"guitar_hero",keys:[2,5,2,5],measures:1,tags:["jump","wide"],category:"jump",difficulty:4},{id:"gh_jump_wide_1_5",name:"Wide Jump 1-5",controllerMode:"guitar_hero",keys:[1,5,1,5],measures:1,tags:["jump","widest"],category:"jump",difficulty:5},{id:"gh_jump_shift_up",name:"Position Shift Up",controllerMode:"guitar_hero",keys:[1,2,4,5],measures:1,tags:["jump","shift","up"],category:"jump",difficulty:4},{id:"gh_jump_shift_down",name:"Position Shift Down",controllerMode:"guitar_hero",keys:[5,4,2,1],measures:1,tags:["jump","shift","down"],category:"jump",difficulty:4},{id:"gh_jump_leap_sequence",name:"Leap Sequence",controllerMode:"guitar_hero",keys:[1,3,5,3,1,3,5],measures:2,tags:["jump","leap","sequence"],category:"jump",difficulty:5},{id:"gh_jump_bounce",name:"Bounce Pattern",controllerMode:"guitar_hero",keys:[1,5,2,4,3],measures:1,tags:["jump","bounce"],category:"jump",difficulty:5},{id:"gh_jump_stretch_1_4_5",name:"Stretch 1-4-5",controllerMode:"guitar_hero",keys:[1,4,5,4],measures:1,tags:["jump","stretch"],category:"jump",difficulty:5},{id:"gh_jump_stretch_1_2_5",name:"Stretch 1-2-5",controllerMode:"guitar_hero",keys:[1,2,5,2],measures:1,tags:["jump","stretch"],category:"jump",difficulty:5}],$n=[{id:"gh_transition_build_up",name:"Build Up",controllerMode:"guitar_hero",keys:[1,1,2,2,3,3,4,4,5],measures:2,tags:["transition","build-up"],category:"transition",difficulty:4},{id:"gh_transition_wind_down",name:"Wind Down",controllerMode:"guitar_hero",keys:[5,5,4,4,3,3,2,2,1],measures:2,tags:["transition","wind-down"],category:"transition",difficulty:4},{id:"gh_transition_fill_ascending",name:"Fill Ascending",controllerMode:"guitar_hero",keys:[1,2,3,4,5],measures:1,tags:["transition","fill","ascending"],category:"transition",difficulty:3},{id:"gh_transition_fill_descending",name:"Fill Descending",controllerMode:"guitar_hero",keys:[5,4,3,2,1],measures:1,tags:["transition","fill","descending"],category:"transition",difficulty:3},{id:"gh_transition_fill_wave",name:"Fill Wave",controllerMode:"guitar_hero",keys:[1,3,5,3,1],measures:1,tags:["transition","fill","wave"],category:"transition",difficulty:4},{id:"gh_transition_end_resolve",name:"End Resolve",controllerMode:"guitar_hero",keys:[5,4,3,2,1,1],measures:2,tags:["transition","resolve","end"],category:"transition",difficulty:3}],Ln=[...En,...zn,...Fn,...Nn,...On],Un=[...kn,...Gn,...qn,...Vn,...$n];function ve(h,t){const e=new Map,n=["basic","roll","stream","jump","chord","transition"];for(const s of n){const a=t.filter(o=>o.category===s);a.length>0&&e.set(s,a)}const i=new Map;for(let s=1;s<=10;s++){const a=t.filter(o=>o.difficulty===s);a.length>0&&i.set(s,a)}return{controllerMode:h,patterns:t,byCategory:e,byDifficulty:i}}const Ie=ve("ddr",Ln),_e=ve("guitar_hero",Un);function Wn(h){return h==="ddr"?Ie:_e}function Hn(h,t){return h.byCategory.get(t)??[]}function Kn(h,t=1,e=10){const n=[];for(let i=t;i<=e;i++){const s=h.byDifficulty.get(i);s&&n.push(...s)}return n}function Yn(h,t){return h.patterns.filter(e=>t.every(n=>e.tags.includes(n)))}function Qn(h,t){return h.patterns.filter(e=>e.keys.length===t)}function Jn(h,t){const e=t?h.patterns.filter(t):h.patterns;if(e.length===0)return;const n=Math.floor(Math.random()*e.length);return e[n]}function jn(h,t){return h.patterns.find(e=>e.id===t)}function Zn(h){const t={basic:0,roll:0,stream:0,jump:0,chord:0,transition:0},e={};for(let a=1;a<=10;a++)e[a]=0;let n=0,i=1/0,s=0;for(const a of h.patterns)t[a.category]++,e[a.difficulty]++,n+=a.keys.length,i=Math.min(i,a.keys.length),s=Math.max(s,a.keys.length);return{totalPatterns:h.patterns.length,byCategory:t,byDifficulty:e,averageKeyCount:h.patterns.length>0?n/h.patterns.length:0,minKeys:i===1/0?0:i,maxKeys:s}}class Xn{static separateFrequencyBands(t,e){const n=t.length,i=e/2/n,s=[],a=[],o=[];for(let r=0;r<n;r++){const c=r*i,l=t[r]/255;c>=20&&c<400?s.push(l):c>=400&&c<4e3?a.push(l):c>=4e3&&c<=14e3&&o.push(l)}return{bass:s,mid:a,treble:o}}static calculateDominance(t,e){if(t.length===0)return 0;const i=t.reduce((s,a)=>s+a,0)/t.length;return e===void 0?i:i/(e/1e3)}}const U={targetSampleRate:8e3,fftWindowSize:32,hopSizeMs:4,hopSizeMode:{mode:"standard"},melBands:40,melBandsMode:{mode:"standard"},highPassCutoff:.4,gaussianSmoothMs:20,gaussianSmoothMode:{mode:"standard"}};class we{constructor(t={}){const e=t.hopSizeMode?yt(t.hopSizeMode):t.hopSizeMs??U.hopSizeMs,n=t.melBandsMode?bt(t.melBandsMode):t.melBands??U.melBands,i=t.gaussianSmoothMode?Mt(t.gaussianSmoothMode):t.gaussianSmoothMs??U.gaussianSmoothMs;this.config={...U,...t,hopSizeMs:e,melBands:n,gaussianSmoothMs:i}}calculate(t){const e=X(t,this.config.targetSampleRate),n=e.targetSampleRate,i=t.duration,s=Math.round(this.config.fftWindowSize/1e3*n),a=Math.pow(2,Math.ceil(Math.log2(s))),o=Math.round(this.config.hopSizeMs/1e3*n),r=this.config.hopSizeMs/1e3,c=Tt(e.data,a,o,n),l=Qt(this.config.melBands,a,n),d=c.numFrames,u=[];for(let B=0;B<d;B++){const M=c.frames[B],T=new Float32Array(this.config.melBands);for(let S=0;S<this.config.melBands;S++){const v=l[S];let _=0;for(let x=0;x<v.length&&x<M.length;x++)_+=M[x]*v[x];T[S]=20*Math.log10(_+1e-10)}u.push(T)}const m=new Float32Array(d);m[0]=0;for(let B=1;B<d;B++){let M=0;for(let T=0;T<this.config.melBands;T++){const S=u[B][T]-u[B-1][T];S>0&&(M+=S)}m[B]=M}const f=1/r,g=Jt(m,this.config.highPassCutoff,f),p=Bt(g,this.config.gaussianSmoothMs,f),b=jt(p),y=new Float32Array(p.length);if(b>1e-10)for(let B=0;B<p.length;B++)y[B]=p[B]/b;else for(let B=0;B<p.length;B++)y[B]=p[B];return{envelope:y,numFrames:d,hopSizeSeconds:r,effectiveSampleRate:n,duration:i}}getConfig(){return{...this.config}}findPeaks(t,e=.5){const n=[];for(let i=1;i<t.length-1;i++)t[i]>t[i-1]&&t[i]>t[i+1]&&t[i]>=e&&n.push(i);return n}frameToTime(t,e){return t*e}timeToFrame(t,e){return Math.round(t/e)}}const ti={tempoCenter:.5,tempoWidth:1.4,minBpm:90,maxBpm:180,useOctaveResolution:!1,useTripleMeter:!1};class xe{constructor(t={}){this.config={...ti,...t}}estimateTempo(t,e){if(t.length<10)return this.getDefaultEstimate();const n=Math.round(60/this.config.minBpm/e),i=Math.round(60/this.config.maxBpm/e),s=Math.max(i,2),a=Math.min(n,Math.floor(t.length/2));if(a<=s)return this.getDefaultEstimate();const o=this.computeAutocorrelation(t,s,a),r=this.applyPerceptualWeighting(o.values,o.minLag,e);let c=this.findPeak(r,0,r.length);if(this.config.useOctaveResolution){const M=this.calculateTPS2(o.values,c),T=Math.floor(c/2);T>=1&&T<r.length&&this.calculateTPS2(o.values,T)>M&&(c=T)}if(this.config.useTripleMeter){const M=this.calculateTPS3(o.values,c),T=Math.floor(c/3);T>=1&&T<r.length&&this.calculateTPS3(o.values,T)>M&&(c=T)}const l=this.lagToBpm(c+o.minLag,e),d=l/2,u=r[c]||0,m=Math.min(c*2,r.length-1),f=r[m]||0,g=Math.max(Math.floor(c/2),0),p=r[g]||0,b=1,y=Math.min(Math.max(Math.max(f,p)/(u+.001),0),1),B=60/l;return{primaryBpm:l,secondaryBpm:d,primaryWeight:b,secondaryWeight:y,targetIntervalSeconds:B}}getConfig(){return{...this.config}}computeAutocorrelation(t,e,n){const i=n-e+1,s=new Float32Array(i);let a=0;for(let o=0;o<t.length;o++)a+=t[o];a/=t.length;for(let o=e;o<=n;o++){let r=0,c=0;for(let l=o;l<t.length;l++)r+=(t[l]-a)*(t[l-o]-a),c++;s[o-e]=c>0?r/c:0}return{values:s,minLag:e,maxLag:n}}applyPerceptualWeighting(t,e,n){const i=new Float32Array(t.length),s=this.config.tempoCenter/n,a=this.config.tempoWidth;for(let o=0;o<t.length;o++){const r=e+o;if(r<=0||s<=0){i[o]=0;continue}const c=Math.log2(r/s),l=Math.exp(-.5*Math.pow(c/a,2));i[o]=t[o]*l}return i}findPeak(t,e,n){let i=e,s=t[e];for(let a=e+1;a<n&&a<t.length;a++)t[a]>s&&(s=t[a],i=a);return i}lagToBpm(t,e){return t<=0||e<=0?120:60/(t*e)}calculateTPS2(t,e){const n=t[e]||0,i=e*2,s=i-1,a=i+1,o=t[i]||0,r=s>=0&&t[s]||0,c=a<t.length&&t[a]||0;return n+.5*o+.25*r+.25*c}calculateTPS3(t,e){const n=t[e]||0,i=e*3,s=i-1,a=i+1,o=t[i]||0,r=s>=0&&t[s]||0,c=a<t.length&&t[a]||0;return n+.33*o+.33*r+.33*c}getDefaultEstimate(){return{primaryBpm:120,secondaryBpm:60,primaryWeight:1,secondaryWeight:.5,targetIntervalSeconds:.5}}getTempoCandidates(t,e,n=5){if(t.length<10)return[{bpm:120,strength:1}];const i=Math.round(60/this.config.minBpm/e),s=Math.round(60/this.config.maxBpm/e),a=Math.max(s,2),o=Math.min(i,Math.floor(t.length/2));if(o<=a)return[{bpm:120,strength:1}];const r=this.computeAutocorrelation(t,a,o),c=this.applyPerceptualWeighting(r.values,r.minLag,e),l=[];for(let d=1;d<c.length-1;d++)if(c[d]>c[d-1]&&c[d]>c[d+1]){const u=this.lagToBpm(d+r.minLag,e);l.push({bpm:u,strength:c[d]})}return l.sort((d,u)=>u.strength-d.strength),l.slice(0,n)}}const W=mt.Logger.for("BeatTracker"),ei={dpAlpha:680,sensitivity:1,minPredecessorRatio:.5,maxPredecessorRatio:2};class Ae{constructor(t={}){this.config={...ei,...t}}getConfig(){return{...this.config}}trackBeats(t,e,n){const i=t.length;if(i<10)return{beats:[],beatFrames:[],cumulativeScores:new Float32Array(i)};const s=Math.round(e.targetIntervalSeconds/n);if(W.debug("BeatTracker: Beat tracking parameters",{targetIntervalSeconds:e.targetIntervalSeconds,hopSizeSeconds:n,periodFrames:s,envelopeLength:i}),s<2||i<s*2)return{beats:[],beatFrames:[],cumulativeScores:new Float32Array(i)};const a=this.config.sensitivity,o=Math.round(this.config.dpAlpha/a),r=Math.max(10,Math.min(1e4,o));W.debug("Beat tracking parameters",{sensitivity:a,dpAlpha:this.config.dpAlpha,effectiveDpAlpha:r});const c=Math.max(1,Math.round(s*this.config.minPredecessorRatio)),l=Math.round(s*this.config.maxPredecessorRatio),d=new Float32Array(l-c+1);for(let B=0;B<d.length;B++){const M=c+B,T=Math.log(M/s);d[B]=-r*T*T}const u=new Int32Array(i);u.fill(-1);const m=new Float32Array(t);for(let B=l+1;B<i;B++){let M=-1/0,T=-1;for(let S=0;S<d.length;S++){const v=B-(c+S);if(v>=0&&v<i){const _=d[S]+m[v];_>M&&(M=_,T=v)}}m[B]=M+t[B],u[B]=T}W.debug("BeatTracker: Starting backward pass",{maxCumulativeScore:Math.max(...m),envelopeLength:i});let f=0,g=m[0];for(let B=1;B<i;B++)m[B]>g&&(g=m[B],f=B);const p=[];let b=f;for(;b>=0&&u[b]>=0;)p.unshift(b),b=u[b];return b>=0&&t[b]>0&&p.unshift(b),W.debug("BeatTracker: Backward pass complete",{beatsFound:p.length,bestEndFrame:f,firstBeatFrame:p[0],lastBeatFrame:p[p.length-1]}),{beats:this.convertToBeats(p,t,m,n,s),beatFrames:p,cumulativeScores:m}}convertToBeats(t,e,n,i,s){if(t.length===0)return[];const a=[];let o=0;for(let l=0;l<e.length;l++)e[l]>o&&(o=e[l]);o<=0&&(o=1);let r=0;for(let l=0;l<t.length;l++)r+=e[t[l]];const c=r/t.length;for(let l=0;l<t.length;l++){const d=t[l],u=d*i,m=Math.max(0,Math.min(1,e[d]/o)),f=e[d],g=c>0?f/c:.5,p=Math.max(0,Math.min(1,.5+.3*(g-1)));a.push({timestamp:u,beatInMeasure:0,isDownbeat:!1,measureNumber:0,intensity:m,confidence:p})}return a}trackBeatsWithOptions(t,e,n,i={}){const s=this.trackBeats(t,e,n);if(i.applyTrimming&&s.beatFrames.length>0&&this.applyDiscountedScoreTrimming(s,t.length,Math.round(e.targetIntervalSeconds/n)),i.minScoreThreshold!==void 0){const a=s.beats.filter((o,r)=>{const c=s.beatFrames[r];return s.cumulativeScores[c]>=i.minScoreThreshold});s.beats=a,s.beatFrames=s.beatFrames.filter((o,r)=>{const c=s.beatFrames[r];return s.cumulativeScores[c]>=i.minScoreThreshold})}return s}applyDiscountedScoreTrimming(t,e,n){if(t.beatFrames.length<3)return;const i=t.cumulativeScores,s=i[e-1],a=new Float32Array(e);for(let u=0;u<e;u++)a[u]=i[u]-u/e*s;let o=0,r=e-1;for(let u=0;u<e;u++)if(a[u]>0){o=u;break}for(let u=e-1;u>=0;u--)if(a[u]>0){r=u;break}const c=Math.floor(n/2),l=[],d=[];for(let u=0;u<t.beatFrames.length;u++){const m=t.beatFrames[u];m>=o-c&&m<=r+c&&(l.push(t.beats[u]),d.push(m))}t.beats=l,t.beatFrames=d}getTrackingStats(t,e){const{beats:n,beatFrames:i}=t;if(n.length===0)return{numBeats:0,avgInterval:0,stdInterval:0,avgIntensity:0,avgConfidence:0,estimatedBpm:0};const s=[];for(let d=1;d<i.length;d++)s.push((i[d]-i[d-1])*e);const a=s.length>0?s.reduce((d,u)=>d+u,0)/s.length:0,o=s.length>0?Math.sqrt(s.reduce((d,u)=>d+Math.pow(u-a,2),0)/s.length):0,r=n.reduce((d,u)=>d+u.intensity,0)/n.length,c=n.reduce((d,u)=>d+u.confidence,0)/n.length,l=a>0?60/a:0;return{numBeats:n.length,avgInterval:a,stdInterval:o,avgIntensity:r,avgConfidence:c,estimatedBpm:l}}}const Rt=mt.Logger.for("BeatMapGenerator");class J{constructor(t={}){this.state=null;const e={...V,...t},n=t.hopSizeMode,i=t.melBandsMode,s=t.gaussianSmoothMode,a=n?yt(n):t.hopSizeMs??V.hopSizeMs,o=i?bt(i):t.melBands??V.melBands,r=s?Mt(s):t.gaussianSmoothMs??V.gaussianSmoothMs;this.options={...e,hopSizeMs:a,melBands:o,gaussianSmoothMs:r,...n?{hopSizeMode:n}:{},...i?{melBandsMode:i}:{},...s?{gaussianSmoothMode:s}:{}}}getConfig(){return{...this.options}}async generateBeatMap(t,e,n,i){this.state={cancelled:!1,progress:{phase:"loading",progress:0,message:"Loading audio..."}};try{this.updateProgress("loading",0,"Loading audio...");const s=await this.fetchAndDecode(t);if(this.state.cancelled)throw new Error("Generation cancelled");return await this.generateBeatMapFromBuffer(s,e,n,i)}finally{this.state=null}}async generateBeatMapFromBuffer(t,e,n,i){this.state||(this.state={cancelled:!1,progress:{phase:"preprocessing",progress:0,message:"Starting..."}}),n&&ft(n);try{const s=t.duration;if(this.updateProgress("preprocessing",5,"Preparing audio..."),this.state.cancelled)throw new Error("Generation cancelled");if(this.updateProgress("ose_calculation",10,"Calculating onset strength envelope..."),this.state.cancelled)throw new Error("Generation cancelled");const o=new we({targetSampleRate:8e3,fftWindowSize:32,hopSizeMs:this.options.hopSizeMs,melBands:this.options.melBands,highPassCutoff:this.options.highPassCutoff,gaussianSmoothMs:this.options.gaussianSmoothMs}).calculate(t);if(this.updateProgress("ose_calculation",35,"Onset strength envelope calculated."),this.state.cancelled)throw new Error("Generation cancelled");if(this.updateProgress("tempo_estimation",40,"Estimating tempo..."),this.state.cancelled)throw new Error("Generation cancelled");const c=new xe({tempoCenter:this.options.tempoCenter,tempoWidth:this.options.tempoWidth,minBpm:this.options.minBpm,maxBpm:this.options.maxBpm,useOctaveResolution:this.options.useOctaveResolution}).estimateTempo(o.envelope,o.hopSizeSeconds);if(this.updateProgress("tempo_estimation",55,`Tempo estimated: ${Math.round(c.primaryBpm)} BPM`),this.state.cancelled)throw new Error("Generation cancelled");if(this.updateProgress("beat_tracking",60,"Tracking beats..."),this.state.cancelled)throw new Error("Generation cancelled");const d=new Ae({dpAlpha:this.options.dpAlpha,sensitivity:this.options.sensitivity}).trackBeats(o.envelope,c,o.hopSizeSeconds);if(this.updateProgress("beat_tracking",85,`${d.beats.length} beats detected.`),this.state.cancelled)throw new Error("Generation cancelled");if(this.updateProgress("measure_labeling",87,"Applying measure labels..."),this.state.cancelled)throw new Error("Generation cancelled");const u=n??Z;n&&gt(n,d.beats.length);const m=this.applyMeasureLabels(d.beats,u);if(this.updateProgress("measure_labeling",97,"Measure labels applied."),this.state.cancelled)throw new Error("Generation cancelled");this.updateProgress("finalizing",98,"Finalizing beat map...");let f=m;const g=this.options.filter;g>0&&(f=this.filterBeatsByGridAlignment(f,c,g));const p=f.length;f=this.applyIntensityThreshold(f),Rt.debug("BeatMapGenerator: Intensity filter applied",{beatsBefore:p,beatsAfter:f.length,beatsFiltered:p-f.length,noiseFloorThreshold:this.options.noiseFloorThreshold});const b={version:Vt,algorithm:$t,minBpm:this.options.minBpm,maxBpm:this.options.maxBpm,sensitivity:this.options.sensitivity,filter:this.options.filter,noiseFloorThreshold:this.options.noiseFloorThreshold,hopSizeMs:this.options.hopSizeMs,fftSize:this.options.fftSize,dpAlpha:this.options.dpAlpha,melBands:this.options.melBands,highPassCutoff:this.options.highPassCutoff,gaussianSmoothMs:this.options.gaussianSmoothMs,tempoCenter:this.options.tempoCenter,tempoWidth:this.options.tempoWidth,useOctaveResolution:this.options.useOctaveResolution??!1,useTripleMeter:this.options.useTripleMeter??!1,generatedAt:new Date().toISOString()},y={audioId:e,duration:s,beats:f,bpm:c.primaryBpm,metadata:b,...n?{downbeatConfig:n}:{}};return this.updateProgress("complete",100,"Beat map generation complete."),i?.(this.state.progress),y}finally{this.state=null}}getProgress(){return this.state?.progress??null}cancel(){this.state&&(this.state.cancelled=!0,this.state.progress={phase:"error",progress:this.state.progress.progress,message:"Generation cancelled",error:"Cancelled by user"})}applyIntensityThreshold(t){const e=this.options.noiseFloorThreshold;return t.filter(n=>n.intensity>=e)}applyMeasureLabels(t,e){const n=this.computeMeasureOffsets(e.segments,t.length);return t.map((i,s)=>{const a=this.findActiveSegmentIndex(e.segments,s),o=e.segments[a],{downbeatBeatIndex:r,timeSignature:c}=o,{beatsPerMeasure:l}=c,d=s-r,u=(d%l+l)%l,m=u===0,g=Math.max(0,Math.floor(d/l))+n[a];return{...i,beatInMeasure:u,isDownbeat:m,measureNumber:g}})}computeMeasureOffsets(t,e){const n=[];for(let i=0;i<t.length;i++)if(i===0)n.push(0);else{const s=t[i-1],{downbeatBeatIndex:a,timeSignature:o}=s,r=o.beatsPerMeasure,l=t[i].startBeat-1-a,d=Math.max(0,Math.floor(l/r));n.push(d+1)}return n}findActiveSegmentIndex(t,e){let n=0;for(let i=0;i<t.length&&t[i].startBeat<=e;i++)n=i;return n}filterBeatsByGridAlignment(t,e,n){if(n<=0)return t;const i=60/e.primaryBpm,s=(1-n)*(i/2),a=t.filter(o=>{const c=Math.round(o.timestamp/i)*i;return Math.abs(o.timestamp-c)<=s});return Rt.debug("Filtered beats by grid alignment",{originalCount:t.length,filteredCount:a.length,threshold:n,maxDeviationMs:s*1e3}),a}updateProgress(t,e,n){this.state&&(this.state.progress={phase:t,progress:e,message:n})}async fetchAndDecode(t){const e=await fetch(t);if(!e.ok)throw new Error(`Failed to fetch audio: ${e.statusText}`);const n=await e.arrayBuffer(),i=globalThis.AudioContext||window?.AudioContext;if(!i)throw new Error("AudioContext not available in this environment");const s=new i;return await new Promise((a,o)=>{s.decodeAudioData(n,a,o)})}static toJSON(t){const e={audioId:t.audioId,duration:t.duration,beats:t.beats.map(n=>({timestamp:n.timestamp,beatInMeasure:n.beatInMeasure,isDownbeat:n.isDownbeat,measureNumber:n.measureNumber,intensity:n.intensity,confidence:n.confidence,...n.requiredKey!==void 0&&{requiredKey:n.requiredKey}})),bpm:t.bpm,metadata:t.metadata};return JSON.stringify(e,null,2)}static fromJSON(t){const e=JSON.parse(t);return{audioId:e.audioId,duration:e.duration,beats:e.beats.map(n=>({timestamp:n.timestamp,beatInMeasure:n.beatInMeasure,isDownbeat:n.isDownbeat,measureNumber:n.measureNumber,intensity:n.intensity,confidence:n.confidence,...n.requiredKey!==void 0&&{requiredKey:n.requiredKey}})),bpm:e.bpm,metadata:e.metadata}}static async saveToFile(t,e){if(typeof process>"u"||!process.versions?.node)throw new Error("saveToFile is only available in Node.js environment");const{writeFile:n}=await Promise.resolve().then(()=>require("./__vite-browser-external-BcPniuRQ.cjs")),i=J.toJSON(t);await n(e,i,"utf-8")}static async loadFromFile(t){if(typeof process>"u"||!process.versions?.node)throw new Error("loadFromFile is only available in Node.js environment");const{readFile:e}=await Promise.resolve().then(()=>require("./__vite-browser-external-BcPniuRQ.cjs")),n=await e(t,"utf-8");return J.fromJSON(n)}}function ni(h){return"mergedBeats"in h&&"detectedBeats"in h}function ii(h){return"subdivisionConfig"in h&&"subdivisionMetadata"in h}class si{constructor(t,e,n={},i=8){this.beatMap=t,this.audioContext=e,this.options={...Ot,...n},this.rollingBpmWindowSize=i,this.normalizedBeatMap=this.createNormalizedBeatMap(t),this.state={isRunning:!1,currentTime:0,startTime:0,isPaused:!1,pauseTime:0,rafId:null,lastButtonPress:null,thresholds:this.resolveThresholds()},this.subscribers=new Set,this.scheduledBeats=this.initializeScheduledBeats()}createNormalizedBeatMap(t){if(ii(t)){let e=120;if(t.beats.length>=2){const i=t.beats[1].timestamp-t.beats[0].timestamp;i>0&&(e=60/i)}const n={version:"1.0.0",algorithm:"subdivision",minBpm:e,maxBpm:e,sensitivity:1,filter:0,noiseFloorThreshold:0,hopSizeMs:4,fftSize:2048,dpAlpha:680,melBands:40,highPassCutoff:.4,gaussianSmoothMs:20,tempoCenter:.5,tempoWidth:1.4,useOctaveResolution:!1,useTripleMeter:!1,generatedAt:new Date().toISOString()};return{audioId:t.audioId,duration:t.duration,beats:t.beats,bpm:e,metadata:n,downbeatConfig:t.downbeatConfig}}else return ni(t)?this.options.useInterpolatedBeats?{audioId:t.audioId,duration:t.duration,beats:t.mergedBeats,bpm:t.quarterNoteBpm,metadata:t.originalMetadata}:{audioId:t.audioId,duration:t.duration,beats:t.detectedBeats,bpm:t.quarterNoteBpm,metadata:t.originalMetadata}:t}initializeScheduledBeats(){return this.normalizedBeatMap.beats.map((t,e)=>({beat:t,index:e,upcomingEmitted:!1,exactEmitted:!1,passedEmitted:!1}))}getOptions(){return{...this.options}}getAccuracyThresholds(){return{...this.state.thresholds}}setDifficulty(t){t.preset!==void 0&&(this.options.difficultyPreset=t.preset),t.customThresholds!==void 0&&(this.options.customThresholds=t.customThresholds),this.state.thresholds=this.resolveThresholds()}subscribe(t){return this.subscribers.add(t),()=>{this.subscribers.delete(t)}}start(){this.state.isRunning||(this.state.isRunning=!0,this.state.startTime=this.audioContext.currentTime-this.state.pauseTime,this.state.isPaused=!1,this.scheduleUpdate())}stop(){this.state.rafId!==null&&(cancelAnimationFrame(this.state.rafId),this.state.rafId=null),this.state.isRunning=!1,this.state.isPaused=!1,this.state.pauseTime=0,this.scheduledBeats=this.initializeScheduledBeats()}pause(){!this.state.isRunning||this.state.isPaused||(this.state.isPaused=!0,this.state.pauseTime=this.getCurrentAudioTime(),this.state.rafId!==null&&(cancelAnimationFrame(this.state.rafId),this.state.rafId=null))}resume(){this.state.isPaused&&(this.state.isPaused=!1,this.state.startTime=this.audioContext.currentTime-this.state.pauseTime,this.scheduleUpdate())}seek(t){const e=Math.max(0,Math.min(t,this.normalizedBeatMap.duration));this.state.pauseTime=e,this.state.isRunning&&!this.state.isPaused&&(this.state.startTime=this.audioContext.currentTime-e),this.scheduledBeats=this.initializeScheduledBeats()}getCurrentAudioTime(){return this.state.isRunning?this.state.isPaused?this.state.pauseTime:this.audioContext.currentTime-this.state.startTime+this.getTotalLatencyCompensation():this.state.pauseTime}getTotalLatencyCompensation(){let t=0;if(this.options.compensateOutputLatency){const e=this.audioContext.outputLatency??0,n=this.audioContext.baseLatency??0;t+=e+n}return t+=this.options.userOffsetMs/1e3,t}getSyncState(){const t=this.audioContext.currentTime,e=this.getCurrentAudioTime(),n=this.audioContext.outputLatency??0,i=this.audioContext.baseLatency??0,s=t-this.state.startTime,a=e-s-this.getTotalLatencyCompensation();return{audioContextTime:t,audioElementTime:e,drift:a,isSynchronized:Math.abs(a)<=this.options.timingTolerance,outputLatency:n,baseLatency:i,userOffsetMs:this.options.userOffsetMs,totalCompensation:this.getTotalLatencyCompensation()}}scheduleUpdate(){!this.state.isRunning||this.state.isPaused||(this.state.rafId=requestAnimationFrame(()=>{this.update(),this.scheduleUpdate()}))}update(){if(!this.state.isRunning||this.state.isPaused)return;const t=this.getCurrentAudioTime(),e=this.getCurrentBpm();for(const n of this.scheduledBeats){const s=n.beat.timestamp-t;!n.upcomingEmitted&&s<=this.options.anticipationTime&&s>0&&(this.emitEvent(n,"upcoming",t,e,s),n.upcomingEmitted=!0),!n.exactEmitted&&Math.abs(s)<=this.options.timingTolerance&&(this.emitEvent(n,"exact",t,e,s),n.exactEmitted=!0),!n.passedEmitted&&s<-this.options.timingTolerance&&(this.emitEvent(n,"passed",t,e,s),n.passedEmitted=!0)}}emitEvent(t,e,n,i,s){const a={beat:t.beat,currentBpm:i,audioTime:n,timeUntilBeat:s,type:e};for(const o of this.subscribers)try{o(a)}catch(r){console.error("BeatStream callback error:",r)}}getUpcomingBeats(t){const e=this.getCurrentAudioTime(),n=[];for(const i of this.normalizedBeatMap.beats){const s=i.timestamp-e;if(s>=0&&s<=this.options.anticipationTime&&(n.push(i),n.length>=t))break}return n}getBeatAtTime(t){const e=this.options.timingTolerance;for(const n of this.normalizedBeatMap.beats)if(Math.abs(n.timestamp-t)<=e)return n;return null}getCurrentBeat(){const t=this.getCurrentAudioTime();let e=null;for(const n of this.normalizedBeatMap.beats)if(n.timestamp<=t)e=n;else break;return e}getNextBeat(){const t=this.getCurrentAudioTime();for(const e of this.normalizedBeatMap.beats)if(e.timestamp>t)return e;return null}getCurrentBpm(){const t=this.getCurrentAudioTime(),e=[];for(const r of this.normalizedBeatMap.beats)r.timestamp<=t+.1&&e.push(r);if(e.length<2)return this.normalizedBeatMap.bpm;const n=Math.min(this.rollingBpmWindowSize,e.length),i=e.slice(-n);let s=0;for(let r=1;r<i.length;r++)s+=i[r].timestamp-i[r-1].timestamp;const o=60/(s/(i.length-1));return Math.max(30,Math.min(300,o))}resolveThresholds(){return this.options.customThresholds&&Object.keys(this.options.customThresholds).length>0?{...ot(this.options.difficultyPreset||"medium"),...this.options.customThresholds}:ot(this.options.difficultyPreset||"medium")}checkButtonPress(t,e){let n=null,i=1/0;for(const m of this.normalizedBeatMap.beats){const f=t-m.timestamp,g=Math.abs(f);g<i&&(i=g,n=m)}if(!n){const m={accuracy:"miss",offset:t,matchedBeat:null,absoluteOffset:t,keyMatch:!0,pressedKey:e,requiredKey:void 0};return this.state.lastButtonPress=m,m}const s=t-n.timestamp,a=Math.abs(s);let o;const r=this.state.thresholds;a<=r.perfect?o="perfect":a<=r.great?o="great":a<=r.good?o="good":a<=r.ok?o="ok":o="miss";const c=this.options.ignoreKeyRequirements??!1,l=n.requiredKey!==void 0;let d=!0;!c&&l&&(e===void 0?(o="miss",d=!1):e!==n.requiredKey&&(o="wrongKey",d=!1));const u={accuracy:o,offset:s,matchedBeat:n,absoluteOffset:a,keyMatch:d,pressedKey:e,requiredKey:n.requiredKey};return this.state.lastButtonPress=u,u}getLastBeatAccuracy(){return this.state.lastButtonPress}isRunning(){return this.state.isRunning&&!this.state.isPaused}isPaused(){return this.state.isPaused}getCurrentTime(){return this.getCurrentAudioTime()}getDuration(){return this.normalizedBeatMap.duration}getBeatMap(){return this.beatMap}getNormalizedBeatMap(){return this.normalizedBeatMap}setBeatMap(t){this.beatMap=t,this.normalizedBeatMap=this.createNormalizedBeatMap(t),this.scheduledBeats=this.initializeScheduledBeats()}dispose(){this.stop(),this.subscribers.clear()}}const A=mt.Logger.for("BeatInterpolator");class j{constructor(t={}){this.options={...kt,...t}}getConfig(){return{...this.options}}interpolate(t){const{beats:e,audioId:n,duration:i,metadata:s,bpm:a,downbeatConfig:o}=t;if(A.debug("Starting beat interpolation",{audioId:n,detectedBeats:e.length,duration:i,originalBpm:a}),e.length===0)return A.warn("No beats to interpolate"),this.createEmptyInterpolatedBeatMap(t);if(e.length===1)return A.warn("Only one beat, cannot determine quarter note"),this.createSingleBeatInterpolatedBeatMap(t);const r=this.detectQuarterNote(e);A.debug("Quarter note detected",{intervalSeconds:r.intervalSeconds,bpm:r.bpm,confidence:r.confidence,method:r.method,denseSectionCount:r.denseSectionCount});const c=this.analyzeGaps(e,r.intervalSeconds);A.debug("Gap analysis complete",{totalGaps:c.totalGaps,halfNoteGaps:c.halfNoteGaps,anomalies:c.anomalies.length,gridAlignmentScore:c.gridAlignmentScore});const l=this.generateGrid(t,r,c);let d=this.mergeBeats(e,l,o);const u=d.filter(S=>S.source==="interpolated").length,m=u>0?d.filter(S=>S.source==="interpolated").reduce((S,v)=>S+v.confidence,0)/u:0,f=this.calculateTempoDriftRatio(d),g=this.identifyTempoClusters(e),p=g.map(S=>Math.round(S.bpm)),b=this.filterOctaveMultiples(p),y=b.length>1;let B,M;if(this.options.enableMultiTempo&&y){const S=this.runMultiTempoAnalysis(e,g,i);S&&(B=S.tempoSections,M=!0,B.length>1&&(d=this.reinterpolateBoundaryRegions(d,B,e,o)),A.debug("Multi-tempo analysis complete",{sectionCount:B.length,tempos:B.map(v=>v.bpm)}))}const T={quarterNoteDetection:r,gapAnalysis:c,detectedBeatCount:e.length,interpolatedBeatCount:u,totalBeatCount:d.length,interpolationRatio:d.length>0?u/d.length:0,avgInterpolatedConfidence:m,tempoDriftRatio:f,detectedClusterTempos:b.length>0?b:void 0,hasMultipleTempos:y,tempoSections:B,hasMultiTempoApplied:M};return A.debug("Interpolation complete",{detectedBeats:e.length,interpolatedBeats:u,totalBeats:d.length,interpolationRatio:T.interpolationRatio.toFixed(2),hasMultipleTempos:y,hasMultiTempoApplied:M}),{audioId:n,duration:i,detectedBeats:[...e],mergedBeats:d,quarterNoteInterval:r.intervalSeconds,quarterNoteBpm:r.bpm,quarterNoteConfidence:r.confidence,originalMetadata:s,interpolationMetadata:T,downbeatConfig:o}}detectQuarterNote(t){const e=this.identifyDenseSections(t);A.debug("Identified dense sections",{count:e.length,totalBeats:e.reduce((u,m)=>u+m.beatCount,0)});const n=this.calculateWeightedIntervals(t,e),i=this.buildIntervalHistogram(n),s=this.findHistogramPeaks(i);if(s.length===0){const u=this.calculateAverageInterval(t);return{intervalSeconds:u,bpm:60/u,confidence:.3,histogramPeak:0,secondaryPeaks:[],method:"tempo-detector-fallback",denseSectionCount:e.length,denseSectionBeats:e.reduce((m,f)=>m+f.beatCount,0)}}const a=s[0],o=s.slice(1,4).map(u=>u.interval),r=n.reduce((u,m)=>u+m.weight,0),c=r>0?a.weight/r:0,l=e.reduce((u,m)=>u+m.beatCount,0)/t.length,d=Math.min(1,c*.6+l*.4);return{intervalSeconds:a.interval,bpm:60/a.interval,confidence:d,histogramPeak:a.weight,secondaryPeaks:o,method:"histogram",denseSectionCount:e.length,denseSectionBeats:e.reduce((u,m)=>u+m.beatCount,0)}}identifyDenseSections(t){const e=this.options.denseSectionMinBeats,n=[];if(t.length<e)return n;const i=[];for(let o=1;o<t.length;o++)i.push(t[o].timestamp-t[o-1].timestamp);let s=0;for(let o=1;o<i.length;o++){const r=i.slice(s,o+1),c=r.reduce((u,m)=>u+m,0)/r.length,l=r.reduce((u,m)=>u+Math.pow(m-c,2),0)/r.length,d=Math.pow(c*.2,2);if(l>d){const u=o-s+1;if(u>=e){const m=i.slice(s,o),f=m.reduce((p,b)=>p+b,0)/m.length,g=m.reduce((p,b)=>p+Math.pow(b-f,2),0)/m.length;n.push({startIndex:s,endIndex:o-1,beatCount:u,avgInterval:f,intervalVariance:g})}s=o}}const a=i.length-s+1;if(a>=e){const o=i.slice(s),r=o.reduce((l,d)=>l+d,0)/o.length,c=o.reduce((l,d)=>l+Math.pow(d-r,2),0)/o.length;n.push({startIndex:s,endIndex:i.length-1,beatCount:a,avgInterval:r,intervalVariance:c})}return n}identifyTempoClusters(t){const e=this.identifyDenseSections(t);if(e.length===0)return[];const n=this.options.tempoSectionThreshold,i=this.options.minClusterBeats,s=e.map(o=>({...o,bpm:60/o.avgInterval,isVerified:o.beatCount>=i}));if(s.length===1)return s[0].isVerified?s:[];s.sort((o,r)=>o.startIndex-r.startIndex);const a=[s[0]];for(let o=1;o<s.length;o++){const r=s[o],c=a[a.length-1],l=c.endIndex+1>=r.startIndex,u=1-Math.min(c.avgInterval,r.avgInterval)/Math.max(c.avgInterval,r.avgInterval)<=n;if(l&&u){const m=[];for(let p=c.startIndex;p<=r.endIndex&&p<t.length-1;p++)m.push(t[p+1].timestamp-t[p].timestamp);const f=m.reduce((p,b)=>p+b,0)/m.length,g=m.reduce((p,b)=>p+Math.pow(b-f,2),0)/m.length;a[a.length-1]={startIndex:c.startIndex,endIndex:r.endIndex,beatCount:c.beatCount+r.beatCount,avgInterval:f,intervalVariance:g,bpm:60/f,isVerified:c.beatCount+r.beatCount>=i}}else a.push(r)}return a.filter(o=>o.isVerified)}findConflictingClusters(t){if(t.length<2)return null;const e=this.options.tempoSectionThreshold,n=[];for(let i=0;i<t.length;i++)for(let s=i+1;s<t.length;s++){const a=t[i],o=t[s];if(this.isOctaveMultiple(a.bpm,o.bpm))continue;1-Math.min(a.bpm,o.bpm)/Math.max(a.bpm,o.bpm)>e&&n.push({cluster1:a,cluster2:o})}return n.length>0?n:null}isOctaveMultiple(t,e,n=.1){const i=[.5,2],s=t/e;return i.some(a=>Math.abs(s-a)<=n)}filterOctaveMultiples(t){if(t.length<=1)return t;const e=[...t].sort((i,s)=>i-s),n=[];for(const i of e)n.some(a=>this.isOctaveMultiple(i,a))||n.push(i);return n}findCrossingPoint(t,e,n){const i=this.options.tempoSectionThreshold,s=this.options.tempoAdaptationRate,a=n.slice(t.startIndex,t.endIndex+1),o=n.slice(e.startIndex,e.endIndex+1),r=n.slice(t.endIndex+1,e.startIndex),c=a[a.length-1],l=o[0];if(r.length===0){const f=(c.timestamp+l.timestamp)/2;return A.debug("No connecting beats between clusters → automatic boundary",{cluster1Bpm:t.bpm,cluster2Bpm:e.bpm,boundaryTimestamp:f}),{hasBoundary:!0,boundaryTimestamp:f,gapRatio:1,beatsInSection1:a,beatsInSection2:o}}const d=this.interpolateForwardsWithDrift(c.timestamp,t.avgInterval,r,s,l.timestamp),u=this.interpolateBackwardsWithDrift(l.timestamp,e.avgInterval,r,s,c.timestamp),m=this.measureGapAtCrossing(d,u,t.avgInterval,e.avgInterval);if(A.debug("Crossing point analysis",{cluster1Bpm:t.bpm,cluster2Bpm:e.bpm,connectingBeats:r.length,gapRatio:m.gapRatio.toFixed(3),threshold:i,hasBoundary:m.gapRatio>i}),m.gapRatio>i){const f=m.crossingTimestamp,{beatsInSection1:g,beatsInSection2:p}=this.assignBeatsToSections(r,t,e,f);return{hasBoundary:!0,boundaryTimestamp:f,gapRatio:m.gapRatio,beatsInSection1:[...a,...g],beatsInSection2:[...p,...o]}}else return{hasBoundary:!1,gapRatio:m.gapRatio,beatsInSection1:[...a,...r,...o],beatsInSection2:[]}}measureGapAtCrossing(t,e,n,i){const s=t.endTimestamp,a=e.endTimestamp,o=(s+a)/2,r=t.beatPositions,c=e.beatPositions;let l=s,d=1/0;for(const b of r){const y=Math.abs(b-o);y<d&&(d=y,l=b)}let u=a,m=1/0;for(const b of c){const y=Math.abs(b-o);y<m&&(m=y,u=b)}r.length===0&&(l=s),c.length===0&&(u=a);const f=Math.abs(l-u),g=(n+i)/2;return{gapRatio:g>0?f/g:0,crossingTimestamp:o,forwardsInterval:t.finalInterval,backwardsInterval:e.finalInterval}}assignBeatsToSections(t,e,n,i){const s=[],a=[];t.length>0&&t[0].timestamp>i,t[0],t[t.length-1];for(const o of t)o.timestamp<i?s.push(o):a.push(o);return A.debug("Assigned connecting beats to sections",{totalConnectingBeats:t.length,toSection1:s.length,toSection2:a.length,boundaryTimestamp:i}),{beatsInSection1:s,beatsInSection2:a}}calculatePhaseAlignment(t,e,n,i=.1){const s=t-e,a=Math.round(s/n),o=e+a*n,r=Math.abs(t-o),c=n*i;return r<=c?1:0}runMultiTempoAnalysis(t,e,n){if(e.length<2)return null;const i=this.findConflictingClusters(e);if(!i||i.length===0)return A.debug("No conflicting tempo clusters found"),null;A.debug("Found conflicting tempo clusters",{conflictCount:i.length,conflicts:i.map(l=>({c1:Math.round(l.cluster1.bpm),c2:Math.round(l.cluster2.bpm)}))});const s=[...e].sort((l,d)=>l.startIndex-d.startIndex),a=[];let o=0,r=0;for(let l=0;l<s.length-1;l++){const d=s[l],u=s[l+1];if(!i.some(g=>g.cluster1===d&&g.cluster2===u||g.cluster1===u&&g.cluster2===d))continue;const f=this.findCrossingPoint(d,u,t);if(f.hasBoundary){const g=f.boundaryTimestamp;t[d.endIndex],a.push({start:o,end:g,bpm:Math.round(d.bpm*10)/10,intervalSeconds:d.avgInterval,beatCount:d.beatCount,startBeatIndex:r,endBeatIndex:d.endIndex}),o=g,r=u.startIndex}}const c=s[s.length-1];return a.push({start:o,end:n,bpm:Math.round(c.bpm*10)/10,intervalSeconds:c.avgInterval,beatCount:c.beatCount,startBeatIndex:r,endBeatIndex:c.endIndex}),a.length===1?(A.debug("Multi-tempo analysis found no section boundaries"),null):{tempoSections:a}}reinterpolateBoundaryRegions(t,e,n,i){return A.debug("Boundary regions identified",{sectionCount:e.length,sections:e.map(s=>({bpm:s.bpm,start:s.start.toFixed(2),end:s.end.toFixed(2)}))}),t}canApplyMultiTempo(t){const{interpolationMetadata:e}=t,n=e.hasMultipleTempos,i=e.hasMultiTempoApplied===!0;return n&&!i}calculateWeightedIntervals(t,e){const n=[];for(let i=1;i<t.length;i++){const s=t[i].timestamp-t[i-1].timestamp,a=e.some(d=>i>d.startIndex&&i<=d.endIndex),o=(t[i-1].confidence+t[i].confidence)/2,r=a?2:1;let c=1;if(i>1){const d=t[i-1].timestamp-t[i-2].timestamp;c=.5+Math.min(s,d)/Math.max(s,d)*.5}if(i<t.length-1){const d=t[i+1].timestamp-t[i].timestamp,u=Math.min(s,d)/Math.max(s,d);c=Math.max(c,.5+u*.5)}const l=o*r*c;n.push({intervalSeconds:s,weight:l,beatIndex:i,isFromDenseSection:a,confidence:o})}return n}buildIntervalHistogram(t){const e=new Map,n=.005;for(const i of t){const s=Math.round(i.intervalSeconds/n)*n,a=e.get(s)||0;e.set(s,a+i.weight)}return e}findHistogramPeaks(t){const e=[],n=Array.from(t.entries()).sort((a,o)=>a[0]-o[0]);for(let a=0;a<n.length;a++){const[o,r]=n[a],c=a>0?n[a-1][1]:0,l=a<n.length-1?n[a+1][1]:0;r>=c&&r>=l&&r>0&&e.push({interval:o,weight:r})}e.sort((a,o)=>o.weight-a.weight);const i=.05,s=[];for(const a of e)s.some(r=>Math.abs(r.interval-a.interval)<i)||s.push(a);return s}calculateAverageInterval(t){if(t.length<2)return .5;let e=0;for(let n=1;n<t.length;n++)e+=t[n].timestamp-t[n-1].timestamp;return e/(t.length-1)}analyzeGaps(t,e){const n=this.options.anomalyThreshold;let i=0;const s=[],a=[];let o=0;for(let d=1;d<t.length;d++){const m=(t[d].timestamp-t[d-1].timestamp)/e,f=Math.round(m);f>1&&a.push(f),Math.abs(m-2)<.2&&i++,(m<1-n||m>1+n&&Math.abs(m-2)>.3&&Math.abs(m-3)>.3&&Math.abs(m-4)>.3)&&s.push(d);const p=Math.round(t[d].timestamp/e)*e,b=Math.abs(t[d].timestamp-p)/e;o+=b}const r=t.length>1?o/(t.length-1):0,c=Math.max(0,1-r*2),l=a.length>0?a.reduce((d,u)=>d+u,0)/a.length:1;return{totalGaps:a.length,halfNoteGaps:i,anomalies:s,avgGapSize:l,gridAlignmentScore:c}}generateGrid(t,e,n){return this.interpolateAdaptivePhaseLocked(t,e)}interpolateForwardsWithDrift(t,e,n,i,s){const a=[];let o=e,r=t;const c=n.filter(f=>!(f.timestamp<=t||s!==void 0&&f.timestamp>s));let l=t;for(let f=0;f<c.length;f++){const g=c[f],p=g.timestamp-l,b=Math.round(p/o);if(b>0){const y=r+b*o,M=(g.timestamp-y)/b*i;o=o+M;for(let T=1;T<b;T++){const S=l+T*o;if(s!==void 0&&S>s)break;a.push(S)}}r=g.timestamp,l=g.timestamp}const d=a.length,u=t+d*e,m=a.length>0?a[a.length-1]-u:0;return{finalInterval:o,beatPositions:a,phaseError:m,endTimestamp:l}}interpolateBackwardsWithDrift(t,e,n,i,s){const a=[];let o=e,r=t;const c=n.filter(f=>!(f.timestamp>=t||s!==void 0&&f.timestamp<s)).reverse();let l=t;for(let f=0;f<c.length;f++){const g=c[f],p=l-g.timestamp,b=Math.round(p/o);if(b>0){const y=r-b*o,M=(g.timestamp-y)/b*i;o=o+M;for(let T=1;T<b;T++){const S=l-T*o;if(s!==void 0&&S<s)break;a.unshift(S)}}r=g.timestamp,l=g.timestamp}const d=a.length,u=t-d*e,m=a.length>0?a[0]-u:0;return{finalInterval:o,beatPositions:a,phaseError:m,endTimestamp:l}}interpolateAdaptivePhaseLocked(t,e){const{beats:n,duration:i}=t,s=e.intervalSeconds,a=this.options.gridSnapTolerance,o=this.options.tempoAdaptationRate,r=[],c=this.options.gridAlignmentWeight,l=this.options.anchorConfidenceWeight,d=this.options.paceConfidenceWeight;if(this.options.extrapolateStart){let f=n[0].timestamp-s;for(;f>=0;){const g=this.calculateConfidence(c,l*.5,d*e.confidence);r.unshift(this.createInterpolatedBeat(f,g,n[0].timestamp)),f-=s}}let u=n[0].timestamp,m=s;for(let f=0;f<n.length;f++){const g=n[f];if(r.push(this.createDetectedBeat(g)),f<n.length-1){const p=n[f+1],b=p.timestamp-g.timestamp,y=Math.round(b/m),B=u+y*m,M=p.timestamp-B;if(y>0){const T=M/y*o;m=m+T}for(let T=1;T<y;T++){const S=g.timestamp+T*m;if(S>=p.timestamp-a)break;const v=this.calculateConfidence(c,l*((g.confidence+p.confidence)/2),d*e.confidence);r.push(this.createInterpolatedBeat(S,v,g.timestamp))}u=p.timestamp}}if(this.options.extrapolateEnd){let f=n[n.length-1].timestamp+m;for(;f<=i;){const g=this.calculateConfidence(c,l*.5,d*e.confidence);r.push(this.createInterpolatedBeat(f,g,n[n.length-1].timestamp)),f+=m}}return r.sort((f,g)=>f.timestamp-g.timestamp),r}mergeBeats(t,e,n){const i=this.options.gridSnapTolerance,s=[],a=[...e].sort((l,d)=>l.timestamp-d.timestamp),o=[...t].sort((l,d)=>l.timestamp-d.timestamp),r=new Map;for(const l of o)r.set(l.timestamp,l);const c=new Set;for(const l of a){const d=this.findBeatNear(r,l.timestamp,i);d&&!c.has(d.timestamp)?(s.push(this.createDetectedBeat(d)),c.add(d.timestamp)):l.source==="interpolated"&&s.push(l)}for(const l of o)c.has(l.timestamp)||s.push(this.createDetectedBeat(l));return s.sort((l,d)=>l.timestamp-d.timestamp),this.reassignBeatPositions(s,n),s}reassignBeatPositions(t,e){const n=e??Z,i=this.computeMeasureOffsets(n.segments,t.length);for(let s=0;s<t.length;s++){const a=t[s],o=this.findActiveSegmentIndex(n.segments,s),r=n.segments[o],{downbeatBeatIndex:c,timeSignature:l}=r,{beatsPerMeasure:d}=l,u=s-c,m=(u%d+d)%d,f=m===0,p=Math.max(0,Math.floor(u/d))+i[o];a.beatInMeasure=m,a.isDownbeat=f,a.measureNumber=p}}computeMeasureOffsets(t,e){const n=[];for(let i=0;i<t.length;i++)if(i===0)n.push(0);else{const s=t[i-1],{downbeatBeatIndex:a,timeSignature:o}=s,r=o.beatsPerMeasure,l=t[i].startBeat-1-a,d=Math.max(0,Math.floor(l/r));n.push(d+1)}return n}findActiveSegmentIndex(t,e){let n=0;for(let i=0;i<t.length&&t[i].startBeat<=e;i++)n=i;return n}calculateConfidence(t,e,n){return Math.max(0,Math.min(1,t+e+n))}createInterpolatedBeat(t,e,n){return{timestamp:t,beatInMeasure:0,isDownbeat:!1,measureNumber:0,intensity:.5,confidence:e,source:"interpolated",distanceToAnchor:Math.abs(t-n),nearestAnchorTimestamp:n}}createDetectedBeat(t){return{...t,source:"detected",distanceToAnchor:0,nearestAnchorTimestamp:t.timestamp}}findBeatNear(t,e,n){const i=t.get(e);if(i)return i;for(const[s,a]of t)if(Math.abs(s-e)<=n)return a;return null}findNearestAnchor(t,e,n){const i=n>=0&&n<t.length?t[n]:t[0],s=n+1<t.length?t[n+1]:t[t.length-1],a=Math.abs(e-i.timestamp),o=Math.abs(e-s.timestamp);return a<=o?{timestamp:i.timestamp,confidence:i.confidence}:{timestamp:s.timestamp,confidence:s.confidence}}calculateTempoDriftRatio(t){if(t.length<3)return 1;const e=[];for(let s=1;s<t.length;s++){const a=t[s].timestamp-t[s-1].timestamp;a>0&&e.push(60/a)}if(e.length===0)return 1;const n=Math.min(...e),i=Math.max(...e);return n>0?i/n:1}createEmptyInterpolatedBeatMap(t){return{audioId:t.audioId,duration:t.duration,detectedBeats:[],mergedBeats:[],quarterNoteInterval:.5,quarterNoteBpm:120,quarterNoteConfidence:0,originalMetadata:t.metadata,interpolationMetadata:{quarterNoteDetection:{intervalSeconds:.5,bpm:120,confidence:0,histogramPeak:0,secondaryPeaks:[],method:"tempo-detector-fallback",denseSectionCount:0,denseSectionBeats:0},gapAnalysis:{totalGaps:0,halfNoteGaps:0,anomalies:[],avgGapSize:1,gridAlignmentScore:0},detectedBeatCount:0,interpolatedBeatCount:0,totalBeatCount:0,interpolationRatio:0,avgInterpolatedConfidence:0,tempoDriftRatio:1,detectedClusterTempos:void 0,hasMultipleTempos:!1,tempoSections:void 0,hasMultiTempoApplied:void 0},downbeatConfig:t.downbeatConfig}}createSingleBeatInterpolatedBeatMap(t){const e=t.beats[0],n={...e,source:"detected",distanceToAnchor:0,nearestAnchorTimestamp:e.timestamp};return{audioId:t.audioId,duration:t.duration,detectedBeats:[e],mergedBeats:[n],quarterNoteInterval:.5,quarterNoteBpm:120,quarterNoteConfidence:.1,originalMetadata:t.metadata,interpolationMetadata:{quarterNoteDetection:{intervalSeconds:.5,bpm:120,confidence:.1,histogramPeak:0,secondaryPeaks:[],method:"tempo-detector-fallback",denseSectionCount:0,denseSectionBeats:0},gapAnalysis:{totalGaps:0,halfNoteGaps:0,anomalies:[],avgGapSize:1,gridAlignmentScore:0},detectedBeatCount:1,interpolatedBeatCount:0,totalBeatCount:1,interpolationRatio:0,avgInterpolatedConfidence:0,tempoDriftRatio:1,detectedClusterTempos:void 0,hasMultipleTempos:!1,tempoSections:void 0,hasMultiTempoApplied:void 0},downbeatConfig:t.downbeatConfig}}static toJSON(t){const e={audioId:t.audioId,duration:t.duration,detectedBeats:t.detectedBeats.map(n=>({timestamp:n.timestamp,beatInMeasure:n.beatInMeasure,isDownbeat:n.isDownbeat,measureNumber:n.measureNumber,intensity:n.intensity,confidence:n.confidence,...n.requiredKey!==void 0&&{requiredKey:n.requiredKey}})),mergedBeats:t.mergedBeats.map(n=>({timestamp:n.timestamp,beatInMeasure:n.beatInMeasure,isDownbeat:n.isDownbeat,measureNumber:n.measureNumber,intensity:n.intensity,confidence:n.confidence,...n.requiredKey!==void 0&&{requiredKey:n.requiredKey},source:n.source,distanceToAnchor:n.distanceToAnchor,nearestAnchorTimestamp:n.nearestAnchorTimestamp})),quarterNoteInterval:t.quarterNoteInterval,quarterNoteBpm:t.quarterNoteBpm,quarterNoteConfidence:t.quarterNoteConfidence,originalMetadata:t.originalMetadata,interpolationMetadata:{quarterNoteDetection:{intervalSeconds:t.interpolationMetadata.quarterNoteDetection.intervalSeconds,bpm:t.interpolationMetadata.quarterNoteDetection.bpm,confidence:t.interpolationMetadata.quarterNoteDetection.confidence,histogramPeak:t.interpolationMetadata.quarterNoteDetection.histogramPeak,secondaryPeaks:t.interpolationMetadata.quarterNoteDetection.secondaryPeaks,method:t.interpolationMetadata.quarterNoteDetection.method,denseSectionCount:t.interpolationMetadata.quarterNoteDetection.denseSectionCount,denseSectionBeats:t.interpolationMetadata.quarterNoteDetection.denseSectionBeats},gapAnalysis:{totalGaps:t.interpolationMetadata.gapAnalysis.totalGaps,halfNoteGaps:t.interpolationMetadata.gapAnalysis.halfNoteGaps,anomalies:t.interpolationMetadata.gapAnalysis.anomalies,avgGapSize:t.interpolationMetadata.gapAnalysis.avgGapSize,gridAlignmentScore:t.interpolationMetadata.gapAnalysis.gridAlignmentScore},detectedBeatCount:t.interpolationMetadata.detectedBeatCount,interpolatedBeatCount:t.interpolationMetadata.interpolatedBeatCount,totalBeatCount:t.interpolationMetadata.totalBeatCount,interpolationRatio:t.interpolationMetadata.interpolationRatio,avgInterpolatedConfidence:t.interpolationMetadata.avgInterpolatedConfidence,tempoDriftRatio:t.interpolationMetadata.tempoDriftRatio,detectedClusterTempos:t.interpolationMetadata.detectedClusterTempos,hasMultipleTempos:t.interpolationMetadata.hasMultipleTempos,tempoSections:t.interpolationMetadata.tempoSections?.map(n=>({start:n.start,end:n.end,bpm:n.bpm,intervalSeconds:n.intervalSeconds,beatCount:n.beatCount,startBeatIndex:n.startBeatIndex,endBeatIndex:n.endBeatIndex})),hasMultiTempoApplied:t.interpolationMetadata.hasMultiTempoApplied},downbeatConfig:t.downbeatConfig};return JSON.stringify(e,null,2)}static fromJSON(t){const e=JSON.parse(t);return{audioId:e.audioId,duration:e.duration,detectedBeats:e.detectedBeats.map(n=>({timestamp:n.timestamp,beatInMeasure:n.beatInMeasure,isDownbeat:n.isDownbeat,measureNumber:n.measureNumber,intensity:n.intensity,confidence:n.confidence,...n.requiredKey!==void 0&&{requiredKey:n.requiredKey}})),mergedBeats:e.mergedBeats.map(n=>({timestamp:n.timestamp,beatInMeasure:n.beatInMeasure,isDownbeat:n.isDownbeat,measureNumber:n.measureNumber,intensity:n.intensity,confidence:n.confidence,...n.requiredKey!==void 0&&{requiredKey:n.requiredKey},source:n.source,distanceToAnchor:n.distanceToAnchor,nearestAnchorTimestamp:n.nearestAnchorTimestamp})),quarterNoteInterval:e.quarterNoteInterval,quarterNoteBpm:e.quarterNoteBpm,quarterNoteConfidence:e.quarterNoteConfidence,originalMetadata:e.originalMetadata,interpolationMetadata:{quarterNoteDetection:{intervalSeconds:e.interpolationMetadata.quarterNoteDetection.intervalSeconds,bpm:e.interpolationMetadata.quarterNoteDetection.bpm,confidence:e.interpolationMetadata.quarterNoteDetection.confidence,histogramPeak:e.interpolationMetadata.quarterNoteDetection.histogramPeak,secondaryPeaks:e.interpolationMetadata.quarterNoteDetection.secondaryPeaks,method:e.interpolationMetadata.quarterNoteDetection.method,denseSectionCount:e.interpolationMetadata.quarterNoteDetection.denseSectionCount,denseSectionBeats:e.interpolationMetadata.quarterNoteDetection.denseSectionBeats},gapAnalysis:{totalGaps:e.interpolationMetadata.gapAnalysis.totalGaps,halfNoteGaps:e.interpolationMetadata.gapAnalysis.halfNoteGaps,anomalies:e.interpolationMetadata.gapAnalysis.anomalies,avgGapSize:e.interpolationMetadata.gapAnalysis.avgGapSize,gridAlignmentScore:e.interpolationMetadata.gapAnalysis.gridAlignmentScore},detectedBeatCount:e.interpolationMetadata.detectedBeatCount,interpolatedBeatCount:e.interpolationMetadata.interpolatedBeatCount,totalBeatCount:e.interpolationMetadata.totalBeatCount,interpolationRatio:e.interpolationMetadata.interpolationRatio,avgInterpolatedConfidence:e.interpolationMetadata.avgInterpolatedConfidence,tempoDriftRatio:e.interpolationMetadata.tempoDriftRatio,detectedClusterTempos:e.interpolationMetadata.detectedClusterTempos,hasMultipleTempos:e.interpolationMetadata.hasMultipleTempos??!1,tempoSections:e.interpolationMetadata.tempoSections?.map(n=>({start:n.start,end:n.end,bpm:n.bpm,intervalSeconds:n.intervalSeconds,beatCount:n.beatCount,startBeatIndex:n.startBeatIndex,endBeatIndex:n.endBeatIndex})),hasMultiTempoApplied:e.interpolationMetadata.hasMultiTempoApplied},downbeatConfig:e.downbeatConfig}}static async saveToFile(t,e){if(typeof process>"u"||!process.versions?.node)throw new Error("saveToFile is only available in Node.js environment");const{writeFile:n}=await Promise.resolve().then(()=>require("./__vite-browser-external-BcPniuRQ.cjs")),i=j.toJSON(t);await n(e,i,"utf-8")}static async loadFromFile(t){if(typeof process>"u"||!process.versions?.node)throw new Error("loadFromFile is only available in Node.js environment");const{readFile:e}=await Promise.resolve().then(()=>require("./__vite-browser-external-BcPniuRQ.cjs")),n=await e(t,"utf-8");return j.fromJSON(n)}}function ai(h){const{mergedBeats:t,interpolationMetadata:e,downbeatConfig:n}=h,i=[],s=[];for(let o=0;o<t.length;o++){const r=t[o],c={timestamp:r.timestamp,beatInMeasure:r.beatInMeasure,isDownbeat:r.isDownbeat,measureNumber:r.measureNumber,intensity:r.intensity,confidence:r.confidence};i.push(c),r.source==="detected"&&s.push(o)}return{audioId:h.audioId,duration:h.duration,beats:i,detectedBeatIndices:s,quarterNoteInterval:h.quarterNoteInterval,quarterNoteBpm:h.quarterNoteBpm,downbeatConfig:n??Z,tempoSections:e.tempoSections,originalMetadata:h.originalMetadata}}exports.ALL_GRID_TYPES=Tn;exports.BEAT_ACCURACY_THRESHOLDS=Ee;exports.BEAT_DETECTION_ALGORITHM=$t;exports.BEAT_DETECTION_VERSION=Vt;exports.BeatInterpolator=j;exports.BeatMapGenerator=J;exports.BeatStream=si;exports.BeatTracker=Ae;exports.CONSECUTIVE_KEY_LIMITS=H;exports.CompositeStreamGenerator=le;exports.DDR_PATTERN_LIBRARY=Ie;exports.DEFAULT_BEATMAP_GENERATOR_OPTIONS=V;exports.DEFAULT_BEATSTREAM_OPTIONS=Ot;exports.DEFAULT_BEAT_INTERPOLATION_OPTIONS=kt;exports.DEFAULT_BUTTON_MAPPING_CONFIG=dt;exports.DEFAULT_DOWNBEAT_CONFIG=Z;exports.DEFAULT_GROOVE_OPTIONS=$e;exports.DEFAULT_RHYTHMIC_BALANCE_CONFIG=tt;exports.DEFAULT_SUBDIVISION_CONFIG=Fe;exports.DEFAULT_SUBDIVISION_PLAYBACK_OPTIONS=ke;exports.DEFAULT_TEMPO_AWARE_CONFIG=vt;exports.DEFAULT_TIME_SIGNATURE=Dt;exports.DensityAnalyzer=re;exports.DifficultyVariantGenerator=Se;exports.EASY_ACCURACY_THRESHOLDS=Et;exports.EASY_GROOVE_PENALTIES=Lt;exports.EASY_QUARTER_NOTE_BPM=be;exports.GAUSSIAN_SMOOTH_PRESETS=Nt;exports.GROOVE_PENALTY_PRESETS=Wt;exports.GROOVE_TIERS=z;exports.GUITAR_HERO_PATTERN_LIBRARY=_e;exports.HARD_ACCURACY_THRESHOLDS=pt;exports.HARD_GROOVE_PENALTIES=Ut;exports.HARD_RESTRICT_BPM=ye;exports.HOP_SIZE_PRESETS=rt;exports.HighBpmGridRestrictionRule=ie;exports.MAX_BEATS_PER_MEASURE=at;exports.MAX_SUBDIVISION_DENSITY=ct;exports.MEDIUM_ACCURACY_THRESHOLDS=zt;exports.MEDIUM_GROOVE_PENALTIES=Y;exports.MEDIUM_RESTRICT_BPM=pe;exports.MEL_BANDS_PRESETS=Ft;exports.MIN_BEATS_PER_MEASURE=st;exports.MultiBandAnalyzer=ee;exports.OnsetStrengthEnvelope=we;exports.PhraseAnalyzer=ae;exports.PitchDetector=Dn;exports.RHYTHM_PRESETS=It;exports.RhythmGenerator=O;exports.RhythmQuantizer=St;exports.RhythmicBalancer=ge;exports.SUBDIVISION_LIMITS=C;exports.SpectrumScanner=Xn;exports.StreamScorer=ce;exports.TempoAwareQuantizer=se;exports.TempoDetector=xe;exports.TransientDetector=ne;exports.VALID_SUBDIVISION_TYPES=K;exports.calculateBeatInMeasure=Ke;exports.calculateMaxAchievableDensity=Be;exports.calculateStdDev=jt;exports.chartedBeatMapToBeatMap=Ye;exports.commonjsGlobal=Ze;exports.convertToAllowedGridType=Q;exports.createMelFilterbank=Qt;exports.deriveAllowedGridTypes=Me;exports.deriveSeed=$;exports.findActiveSegment=me;exports.gaussianSmooth=Bt;exports.generateSeed=nn;exports.getAccuracyThresholdsForPreset=ot;exports.getAllowedGridTypes=_n;exports.getConsecutiveKeyLimit=Ht;exports.getControllerModeBalanceDefaults=Bn;exports.getControllerModeScoringDefaults=gn;exports.getDefaultExportFromCjs=Kt;exports.getGaussianSmoothMs=Mt;exports.getGroovePenaltiesForPreset=Le;exports.getGrooveTier=Ge;exports.getGrooveWindowMs=qe;exports.getHopSizeMs=yt;exports.getMelBands=bt;exports.getMetricGroupSize=de;exports.getMinHotnessForTier=Ve;exports.getPatternById=jn;exports.getPatternLibrary=Wn;exports.getPatternLibraryStats=Zn;exports.getPatternsByCategory=Hn;exports.getPatternsByDifficulty=Kn;exports.getPatternsByKeyCount=Qn;exports.getPatternsByTags=Yn;exports.getRandomPattern=Jn;exports.getRhythmPreset=xn;exports.getRhythmPresetNames=An;exports.getSubdivisionDensity=Gt;exports.getTempoAwareAllowedGridTypes=R;exports.hashSeedToFloat=N;exports.hashSeedToInt=sn;exports.highPassFilter=Jt;exports.hzToMel=ht;exports.isFullBeatMapExportData=Je;exports.isGridTypeAllowed=In;exports.isLevelPackExport=je;exports.isMetricStrongBeat=he;exports.isMetricWeakBeat=ue;exports.isStrongBeatForEmphasis=fe;exports.isValidSubdivisionType=lt;exports.mapGridToSubdivision=He;exports.melToHz=Yt;exports.mergeButtonMappingConfig=We;exports.naturalDifficultyToLevel=wn;exports.performFFT=Zt;exports.performSTFT=Tt;exports.reapplyDownbeatConfig=Ce;exports.resampleAudio=X;exports.unifyBeatMap=ai;exports.validateButtonMappingConfig=Ue;exports.validateDownbeatConfig=ft;exports.validateDownbeatConfigAgainstBeats=gt;exports.validateSubdivisionConfig=qt;exports.validateSubdivisionConfigAgainstBeats=Ne;exports.validateSubdivisionDensity=Oe;exports.validateSubdivisionLimits=Te;exports.validateThresholds=ze;exports.validateTrackMatch=Qe;
@@ -1,4 +1,4 @@
1
- import { L as nt } from "./arweaveGatewayManager-BKUZ1Klm.js";
1
+ import { L as nt } from "./arweaveGatewayManager-DDSO5sLJ.js";
2
2
  const kt = {
3
3
  beatsPerMeasure: 4
4
4
  }, it = {