From 3bc8c6403b729f8ffe9ad2f65557327412f97a95 Mon Sep 17 00:00:00 2001 From: Devin Jean Date: Thu, 31 Oct 2024 11:59:47 -0500 Subject: [PATCH] ties --- extensions/BeatBlox/index.js | 13 ++++- extensions/BeatBlox/webAudioAPI.js | 93 ++++++++++++++++-------------- 2 files changed, 61 insertions(+), 45 deletions(-) diff --git a/extensions/BeatBlox/index.js b/extensions/BeatBlox/index.js index b991f80..57e6d18 100644 --- a/extensions/BeatBlox/index.js +++ b/extensions/BeatBlox/index.js @@ -242,6 +242,7 @@ new Extension.Palette.Block('playDrums'), new Extension.Palette.Block('rest'), new Extension.Palette.Block('noteMod'), + new Extension.Palette.Block('tieDuration'), new Extension.Palette.Block('noteNumber'), '-', new Extension.Palette.Block('playClip'), @@ -299,14 +300,21 @@ if (duration.contents !== undefined) duration = duration.contents; if (!Array.isArray(duration)) duration = notes.map(() => duration); - if (duration.some(x => DURATIONS[x] === undefined)) throw Error('unknown note duration'); if (duration.length !== notes.length) throw Error('number of durations and notes must match'); + if (duration.some(x => typeof(x) !== 'string')) throw Error('unknown note duration'); + duration = duration.map(x => x.split('+').filter(y => y.length !== 0)); + if (duration.some(x => x.some(y => DURATIONS[y] === undefined))) throw Error('unknown note duration'); const mods = this.musicInfo.mods.map(x => audio.getModification(MODIFIERS[x])); let t = Infinity; for (let i = 0; i < notes.length; ++i) { - t = Math.min(t, await audio.playNote(this.receiver.id, notes[i], this.musicInfo.t, DURATIONS[duration[i]], mods)); + let tt = 0; + for (let j = 0; j < duration[i].length; ++j) { + const m = j === 0 ? mods : mods.concat([ audio.getModification(MODIFIERS['Tie']) ]); + tt += await audio.playNote(this.receiver.id, notes[i], this.musicInfo.t + tt, DURATIONS[duration[i][j]], m); + } + t = Math.min(t, tt); } this.musicInfo.t += t; await waitUntil(this.musicInfo.t - SCHEDULING_WINDOW); @@ -358,6 +366,7 @@ } } }), + new Extension.Block('tieDuration', 'reporter', 'music', 'tie %mult%noteDuration', [['Quarter']], durations => durations.contents.map(x => x.toString()).filter(x => x.length !== 0).join('+')), new Extension.Block('noteNumber', 'reporter', 'music', 'note# %s', ['C4'], parseNote), new Extension.Block('playClip', 'command', 'music', 'play sound %snd', [], function (rawSound) { return this.runAsyncFn(async () => { diff --git a/extensions/BeatBlox/webAudioAPI.js b/extensions/BeatBlox/webAudioAPI.js index 2a06662..d89c3f8 100644 --- a/extensions/BeatBlox/webAudioAPI.js +++ b/extensions/BeatBlox/webAudioAPI.js @@ -149,16 +149,20 @@ const ModificationIncompatibilities = { ModificationType.Pianissimo, ModificationType.Fortissimo, ModificationType.Pianississimo, ModificationType.Fortissimo], [ModificationType.Fortississimo]: [ModificationType.Velocity, ModificationType.Piano, ModificationType.Forte, ModificationType.MezzoPiano, ModificationType.MezzoForte, ModificationType.Pianissimo, ModificationType.Fortissimo, ModificationType.Pianississimo, ModificationType.Fortissimo], + [ModificationType.Slur]: [ModificationType.Slur, ModificationType.Tie], [ModificationType.Crescendo]: [ModificationType.Crescendo, ModificationType.Decrescendo, ModificationType.Diminuendo], [ModificationType.Decrescendo]: [ModificationType.Crescendo, ModificationType.Decrescendo, ModificationType.Diminuendo], [ModificationType.Diminuendo]: [ModificationType.Crescendo, ModificationType.Decrescendo, ModificationType.Diminuendo], - [ModificationType.Accent]: [ModificationType.Accent, ModificationType.Marcato], - [ModificationType.Marcato]: [ModificationType.Accent, ModificationType.Marcato], + [ModificationType.Accent]: [ModificationType.Accent, ModificationType.Marcato, ModificationType.Sforzando], + [ModificationType.Marcato]: [ModificationType.Accent, ModificationType.Marcato, ModificationType.Sforzando], [ModificationType.Staccato]: [ModificationType.Staccato, ModificationType.Staccatissimo, ModificationType.Tenuto], [ModificationType.Staccatissimo]: [ModificationType.Staccato, ModificationType.Staccatissimo, ModificationType.Tenuto], [ModificationType.Tenuto]: [ModificationType.Staccato, ModificationType.Staccatissimo, ModificationType.Tenuto], + [ModificationType.Sforzando]: [ModificationType.Accent, ModificationType.Marcato, ModificationType.Sforzando], + [ModificationType.Tie]: [ModificationType.Tie, ModificationType.Slur], [ModificationType.OctaveShiftUp]: [ModificationType.OctaveShiftUp, ModificationType.OctaveShiftDown], [ModificationType.OctaveShiftDown]: [ModificationType.OctaveShiftUp, ModificationType.OctaveShiftDown], + [ModificationType.Natural]: [ModificationType.Natural], [ModificationType.GraceAcciaccatura]: [ModificationType.GraceAcciaccatura, ModificationType.GraceAppoggiatura], [ModificationType.GraceAppoggiatura]: [ModificationType.GraceAcciaccatura, ModificationType.GraceAppoggiatura], [ModificationType.Tuplet]: [ModificationType.Tuplet, ModificationType.Triplet, ModificationType.Quintuplet, ModificationType.Sextuplet, ModificationType.Septuplet], @@ -166,6 +170,7 @@ const ModificationIncompatibilities = { [ModificationType.Quintuplet]: [ModificationType.Tuplet, ModificationType.Triplet, ModificationType.Quintuplet, ModificationType.Sextuplet, ModificationType.Septuplet], [ModificationType.Sextuplet]: [ModificationType.Tuplet, ModificationType.Triplet, ModificationType.Quintuplet, ModificationType.Sextuplet, ModificationType.Septuplet], [ModificationType.Septuplet]: [ModificationType.Tuplet, ModificationType.Triplet, ModificationType.Quintuplet, ModificationType.Sextuplet, ModificationType.Septuplet], + [ModificationType.Fermata]: [ModificationType.Fermata], [ModificationType.TrillUpper]: [ModificationType.TrillUpper, ModificationType.TrillLower, ModificationType.MordentUpper, ModificationType.MordentLower, ModificationType.TurnUpper, ModificationType.TurnLower, ModificationType.Glissando, ModificationType.Portamento], [ModificationType.TrillLower]: [ModificationType.TrillUpper, ModificationType.TrillLower, ModificationType.MordentUpper, ModificationType.MordentLower, @@ -4948,7 +4953,7 @@ class WavFileEncoder extends EncoderBase { } } -var di=Object.defineProperty;var Pe=Object.getOwnPropertySymbols;var li=Object.prototype.hasOwnProperty,ui=Object.prototype.propertyIsEnumerable;var p=Math.pow,ve=(l,e,i)=>e in l?di(l,e,{enumerable:!0,configurable:!0,writable:!0,value:i}):l[e]=i,Me=(l,e)=>{for(var i in e||={})li.call(e,i)&&ve(l,i,e[i]);if(Pe)for(var i of Pe(e))ui.call(e,i)&&ve(l,i,e[i]);return l};var ge=(l,e,i)=>{if(!e.has(l))throw TypeError("Cannot "+i)};var t=(l,e,i)=>(ge(l,e,"read from private field"),i?i.call(l):e.get(l)),a=(l,e,i)=>{if(e.has(l))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(l):e.set(l,i);},u=(l,e,i,s)=>(ge(l,e,"write to private field"),s?s.call(l,i):e.set(l,i),i);var h=(l,e,i)=>(ge(l,e,"access private method"),i);var J=class{constructor(e){this.value=e;}},O=class{constructor(e){this.value=e;}};var we=l=>l<1<<8?1:l<1<<16?2:l<1<<24?3:l{if(l<(1<<7)-1)return 1;if(l<(1<<14)-1)return 2;if(l<(1<<21)-1)return 3;if(l<(1<<28)-1)return 4;if(l{let s=0;for(let r=e;r>c;s<<=1,s|=b;}return s},Fe=(l,e,i,s)=>{for(let r=e;r>i-r-1<>8),t(this,m).setUint8(s++,e);break;case 3:t(this,m).setUint8(s++,1<<5|e>>16),t(this,m).setUint8(s++,e>>8),t(this,m).setUint8(s++,e);break;case 4:t(this,m).setUint8(s++,1<<4|e>>24),t(this,m).setUint8(s++,e>>16),t(this,m).setUint8(s++,e>>8),t(this,m).setUint8(s++,e);break;case 5:t(this,m).setUint8(s++,1<<3|e/p(2,32)&7),t(this,m).setUint8(s++,e>>24),t(this,m).setUint8(s++,e>>16),t(this,m).setUint8(s++,e>>8),t(this,m).setUint8(s++,e);break;case 6:t(this,m).setUint8(s++,1<<2|e/p(2,40)&3),t(this,m).setUint8(s++,e/p(2,32)|0),t(this,m).setUint8(s++,e>>24),t(this,m).setUint8(s++,e>>16),t(this,m).setUint8(s++,e>>8),t(this,m).setUint8(s++,e);break;default:throw new Error("Bad EBML VINT size "+i)}this.write(t(this,A).subarray(0,s));}writeEBML(e){var i,s;if(e!==null)if(e instanceof Uint8Array)this.write(e);else if(Array.isArray(e))for(let r of e)this.writeEBML(r);else if(this.offsets.set(e,this.pos),h(this,yt,ye).call(this,e.id),Array.isArray(e.data)){let r=this.pos,n=e.size===-1?1:(i=e.size)!=null?i:4;e.size===-1?h(this,Lt,_e).call(this,255):this.seek(this.pos+n);let o=this.pos;if(this.dataOffsets.set(e,o),this.writeEBML(e.data),e.size!==-1){let c=this.pos-o,b=this.pos;this.seek(r),this.writeEBMLVarInt(c,n),this.seek(b);}}else if(typeof e.data=="number"){let r=(s=e.size)!=null?s:we(e.data);this.writeEBMLVarInt(r),h(this,yt,ye).call(this,e.data,r);}else typeof e.data=="string"?(this.writeEBMLVarInt(e.data.length),h(this,qt,We).call(this,e.data)):e.data instanceof Uint8Array?(this.writeEBMLVarInt(e.data.byteLength,e.size),this.write(e.data)):e.data instanceof J?(this.writeEBMLVarInt(4),h(this,Yt,Ne).call(this,e.data.value)):e.data instanceof O&&(this.writeEBMLVarInt(8),h(this,Zt,Oe).call(this,e.data.value));}};A=new WeakMap,m=new WeakMap,Lt=new WeakSet,_e=function(e){t(this,m).setUint8(0,e),this.write(t(this,A).subarray(0,1));},Yt=new WeakSet,Ne=function(e){t(this,m).setFloat32(0,e,!1),this.write(t(this,A).subarray(0,4));},Zt=new WeakSet,Oe=function(e){t(this,m).setFloat64(0,e,!1),this.write(t(this,A));},yt=new WeakSet,ye=function(e,i=we(e)){let s=0;switch(i){case 6:t(this,m).setUint8(s++,e/p(2,40)|0);case 5:t(this,m).setUint8(s++,e/p(2,32)|0);case 4:t(this,m).setUint8(s++,e>>24);case 3:t(this,m).setUint8(s++,e>>16);case 2:t(this,m).setUint8(s++,e>>8);case 1:t(this,m).setUint8(s++,e);break;default:throw new Error("Bad UINT size "+i)}this.write(t(this,A).subarray(0,s));},qt=new WeakSet,We=function(e){this.write(new Uint8Array(e.split("").map(i=>i.charCodeAt(0))));};var kt,P,tt,Ct,ke,Kt=class extends $t{constructor(i){super();a(this,Ct);a(this,kt,void 0);a(this,P,new ArrayBuffer(p(2,16)));a(this,tt,new Uint8Array(t(this,P)));u(this,kt,i);}write(i){h(this,Ct,ke).call(this,this.pos+i.byteLength),t(this,tt).set(i,this.pos),this.pos+=i.byteLength;}finalize(){h(this,Ct,ke).call(this,this.pos),t(this,kt).buffer=t(this,P).slice(0,this.pos);}};kt=new WeakMap,P=new WeakMap,tt=new WeakMap,Ct=new WeakSet,ke=function(i){let s=t(this,P).byteLength;for(;so.start-c.start);i.push({start:s[0].start,size:s[0].data.byteLength});for(let o=1;og.start<=s&&sci){for(let g=0;g=i.written[o+1].start;)i.written[o].end=Math.max(i.written[o].end,i.written[o+1].end),i.written.splice(o+1,1);},Xt=new WeakSet,Be=function(i){let r={start:Math.floor(i/t(this,y))*t(this,y),data:new Uint8Array(t(this,y)),written:[],shouldFlush:!1};return t(this,w).push(r),t(this,w).sort((n,o)=>n.start-o.start),t(this,w).indexOf(r)},et=new WeakSet,Bt=function(i=!1){var s,r;for(let n=0;ne.stream.write({type:"write",data:r,position:n}),chunked:!0,chunkSize:(s=e.options)==null?void 0:s.chunkSize}),i);}};var it=1,Et=2,jt=3,mi=1,bi=2,pi=17,Te=p(2,15),zt=p(2,12),$e="https://github.com/Vanilagy/webm-muxer",Ke=6,Ge=5,gi=["strict","offset","permissive"],f,d,at,nt,x,B,$,R,K,z,G,L,S,Y,Z,V,D,F,ot,ht,q,Q,Dt,dt,lt,ie,Le,se,Ye,re,Ze,ae,qe,ne,Qe,oe,Xe,he,je,Pt,Se,vt,Ae,de,Je,_,st,N,rt,le,Ie,ue,ti,ut,Jt,ft,It,fe,ei,T,E,X,Vt,ct,te,ce,ii,Mt,Ue,mt,ee,xe=class{constructor(e){a(this,ie);a(this,se);a(this,re);a(this,ae);a(this,ne);a(this,oe);a(this,he);a(this,Pt);a(this,vt);a(this,de);a(this,_);a(this,N);a(this,le);a(this,ue);a(this,ut);a(this,ft);a(this,fe);a(this,T);a(this,X);a(this,ct);a(this,ce);a(this,Mt);a(this,mt);a(this,f,void 0);a(this,d,void 0);a(this,at,void 0);a(this,nt,void 0);a(this,x,void 0);a(this,B,void 0);a(this,$,void 0);a(this,R,void 0);a(this,K,void 0);a(this,z,void 0);a(this,G,void 0);a(this,L,void 0);a(this,S,void 0);a(this,Y,void 0);a(this,Z,0);a(this,V,[]);a(this,D,[]);a(this,F,[]);a(this,ot,void 0);a(this,ht,void 0);a(this,q,-1);a(this,Q,-1);a(this,Dt,-1);a(this,dt,void 0);a(this,lt,!1);var s;h(this,ie,Le).call(this,e),u(this,f,Me({type:"webm",firstTimestampBehavior:"strict"},e)),this.target=e.target;let i=!!t(this,f).streaming;if(e.target instanceof Wt)u(this,d,new Kt(e.target));else if(e.target instanceof I)u(this,d,(s=e.target.options)!=null&&s.chunked?new wt(e.target,i):new gt(e.target,i));else if(e.target instanceof Ht)u(this,d,new Gt(e.target,i));else throw new Error(`Invalid target: ${e.target}`);h(this,se,Ye).call(this);}addVideoChunk(e,i,s){let r=new Uint8Array(e.byteLength);e.copyTo(r),this.addVideoChunkRaw(r,e.type,s!=null?s:e.timestamp,i);}addVideoChunkRaw(e,i,s,r){if(h(this,mt,ee).call(this),!t(this,f).video)throw new Error("No video track declared.");t(this,ot)===void 0&&u(this,ot,s),r&&h(this,le,Ie).call(this,r);let n=h(this,ft,It).call(this,e,i,s,it);for(t(this,f).video.codec==="V_VP9"&&h(this,ue,ti).call(this,n),u(this,q,n.timestamp);t(this,D).length>0&&t(this,D)[0].timestamp<=n.timestamp;){let o=t(this,D).shift();h(this,T,E).call(this,o,!1);}!t(this,f).audio||n.timestamp<=t(this,Q)?h(this,T,E).call(this,n,!0):t(this,V).push(n),h(this,ut,Jt).call(this),h(this,_,st).call(this);}addAudioChunk(e,i,s){let r=new Uint8Array(e.byteLength);e.copyTo(r),this.addAudioChunkRaw(r,e.type,s!=null?s:e.timestamp,i);}addAudioChunkRaw(e,i,s,r){if(h(this,mt,ee).call(this),!t(this,f).audio)throw new Error("No audio track declared.");t(this,ht)===void 0&&u(this,ht,s),r!=null&&r.decoderConfig&&(t(this,f).streaming?u(this,z,h(this,X,Vt).call(this,r.decoderConfig.description)):h(this,ct,te).call(this,t(this,z),r.decoderConfig.description));let n=h(this,ft,It).call(this,e,i,s,Et);for(u(this,Q,n.timestamp);t(this,V).length>0&&t(this,V)[0].timestamp<=n.timestamp;){let o=t(this,V).shift();h(this,T,E).call(this,o,!0);}!t(this,f).video||n.timestamp<=t(this,q)?h(this,T,E).call(this,n,!t(this,f).video):t(this,D).push(n),h(this,ut,Jt).call(this),h(this,_,st).call(this);}addSubtitleChunk(e,i,s){if(h(this,mt,ee).call(this),!t(this,f).subtitles)throw new Error("No subtitle track declared.");i!=null&&i.decoderConfig&&(t(this,f).streaming?u(this,G,h(this,X,Vt).call(this,i.decoderConfig.description)):h(this,ct,te).call(this,t(this,G),i.decoderConfig.description));let r=h(this,ft,It).call(this,e.body,"key",s!=null?s:e.timestamp,jt,e.duration,e.additions);u(this,Dt,r.timestamp),t(this,F).push(r),h(this,ut,Jt).call(this),h(this,_,st).call(this);}finalize(){if(t(this,lt))throw new Error("Cannot finalize a muxer more than once.");for(;t(this,V).length>0;)h(this,T,E).call(this,t(this,V).shift(),!0);for(;t(this,D).length>0;)h(this,T,E).call(this,t(this,D).shift(),!0);for(;t(this,F).length>0&&t(this,F)[0].timestamp<=t(this,Z);)h(this,T,E).call(this,t(this,F).shift(),!1);if(t(this,f).streaming||h(this,Mt,Ue).call(this),t(this,d).writeEBML(t(this,L)),!t(this,f).streaming){let e=t(this,d).pos,i=t(this,d).pos-t(this,N,rt);t(this,d).seek(t(this,d).offsets.get(t(this,at))+4),t(this,d).writeEBMLVarInt(i,Ke),t(this,$).data=new O(t(this,Z)),t(this,d).seek(t(this,d).offsets.get(t(this,$))),t(this,d).writeEBML(t(this,$)),t(this,x).data[0].data[1].data=t(this,d).offsets.get(t(this,L))-t(this,N,rt),t(this,x).data[1].data[1].data=t(this,d).offsets.get(t(this,nt))-t(this,N,rt),t(this,x).data[2].data[1].data=t(this,d).offsets.get(t(this,B))-t(this,N,rt),t(this,d).seek(t(this,d).offsets.get(t(this,x))),t(this,d).writeEBML(t(this,x)),t(this,d).seek(e);}h(this,_,st).call(this),t(this,d).finalize(),u(this,lt,!0);}};f=new WeakMap,d=new WeakMap,at=new WeakMap,nt=new WeakMap,x=new WeakMap,B=new WeakMap,$=new WeakMap,R=new WeakMap,K=new WeakMap,z=new WeakMap,G=new WeakMap,L=new WeakMap,S=new WeakMap,Y=new WeakMap,Z=new WeakMap,V=new WeakMap,D=new WeakMap,F=new WeakMap,ot=new WeakMap,ht=new WeakMap,q=new WeakMap,Q=new WeakMap,Dt=new WeakMap,dt=new WeakMap,lt=new WeakMap,ie=new WeakSet,Le=function(e){if(e.type&&e.type!=="webm"&&e.type!=="matroska")throw new Error(`Invalid type: ${e.type}`);if(e.firstTimestampBehavior&&!gi.includes(e.firstTimestampBehavior))throw new Error(`Invalid first timestamp behavior: ${e.firstTimestampBehavior}`)},se=new WeakSet,Ye=function(){t(this,d)instanceof U&&t(this,d).target.options.onHeader&&t(this,d).startTrackingWrites(),h(this,re,Ze).call(this),t(this,f).streaming||h(this,oe,Xe).call(this),h(this,he,je).call(this),h(this,ae,qe).call(this),h(this,ne,Qe).call(this),t(this,f).streaming||(h(this,Pt,Se).call(this),h(this,vt,Ae).call(this)),h(this,de,Je).call(this),h(this,_,st).call(this);},re=new WeakSet,Ze=function(){var i;let e={id:440786851,data:[{id:17030,data:1},{id:17143,data:1},{id:17138,data:4},{id:17139,data:8},{id:17026,data:(i=t(this,f).type)!=null?i:"webm"},{id:17031,data:2},{id:17029,data:2}]};t(this,d).writeEBML(e);},ae=new WeakSet,qe=function(){u(this,K,{id:236,size:4,data:new Uint8Array(zt)}),u(this,z,{id:236,size:4,data:new Uint8Array(zt)}),u(this,G,{id:236,size:4,data:new Uint8Array(zt)});},ne=new WeakSet,Qe=function(){u(this,R,{id:21936,data:[{id:21937,data:2},{id:21946,data:2},{id:21947,data:2},{id:21945,data:0}]});},oe=new WeakSet,Xe=function(){let e=new Uint8Array([28,83,187,107]),i=new Uint8Array([21,73,169,102]),s=new Uint8Array([22,84,174,107]),r={id:290298740,data:[{id:19899,data:[{id:21419,data:e},{id:21420,size:5,data:0}]},{id:19899,data:[{id:21419,data:i},{id:21420,size:5,data:0}]},{id:19899,data:[{id:21419,data:s},{id:21420,size:5,data:0}]}]};u(this,x,r);},he=new WeakSet,je=function(){let e={id:17545,data:new O(0)};u(this,$,e);let i={id:357149030,data:[{id:2807729,data:1e6},{id:19840,data:$e},{id:22337,data:$e},t(this,f).streaming?null:e]};u(this,nt,i);},Pt=new WeakSet,Se=function(){let e={id:374648427,data:[]};u(this,B,e),t(this,f).video&&e.data.push({id:174,data:[{id:215,data:it},{id:29637,data:it},{id:131,data:mi},{id:134,data:t(this,f).video.codec},t(this,K),t(this,f).video.frameRate?{id:2352003,data:1e9/t(this,f).video.frameRate}:null,{id:224,data:[{id:176,data:t(this,f).video.width},{id:186,data:t(this,f).video.height},t(this,f).video.alpha?{id:21440,data:1}:null,t(this,R)]}]}),t(this,f).audio&&(u(this,z,t(this,f).streaming?t(this,z)||null:{id:236,size:4,data:new Uint8Array(zt)}),e.data.push({id:174,data:[{id:215,data:Et},{id:29637,data:Et},{id:131,data:bi},{id:134,data:t(this,f).audio.codec},t(this,z),{id:225,data:[{id:181,data:new J(t(this,f).audio.sampleRate)},{id:159,data:t(this,f).audio.numberOfChannels},t(this,f).audio.bitDepth?{id:25188,data:t(this,f).audio.bitDepth}:null]}]})),t(this,f).subtitles&&e.data.push({id:174,data:[{id:215,data:jt},{id:29637,data:jt},{id:131,data:pi},{id:134,data:t(this,f).subtitles.codec},t(this,G)]});},vt=new WeakSet,Ae=function(){let e={id:408125543,size:t(this,f).streaming?-1:Ke,data:[t(this,f).streaming?null:t(this,x),t(this,nt),t(this,B)]};if(u(this,at,e),t(this,d).writeEBML(e),t(this,d)instanceof U&&t(this,d).target.options.onHeader){let{data:i,start:s}=t(this,d).getTrackedWrites();t(this,d).target.options.onHeader(i,s);}},de=new WeakSet,Je=function(){u(this,L,{id:475249515,data:[]});},_=new WeakSet,st=function(){t(this,d)instanceof gt&&t(this,d).flush();},N=new WeakSet,rt=function(){return t(this,d).dataOffsets.get(t(this,at))},le=new WeakSet,Ie=function(e){if(!!e.decoderConfig){if(e.decoderConfig.colorSpace){let i=e.decoderConfig.colorSpace;if(u(this,dt,i),t(this,R).data=[{id:21937,data:{rgb:1,bt709:1,bt470bg:5,smpte170m:6}[i.matrix]},{id:21946,data:{bt709:1,smpte170m:6,"iec61966-2-1":13}[i.transfer]},{id:21947,data:{bt709:1,bt470bg:5,smpte170m:6}[i.primaries]},{id:21945,data:[1,2][Number(i.fullRange)]}],!t(this,f).streaming){let s=t(this,d).pos;t(this,d).seek(t(this,d).offsets.get(t(this,R))),t(this,d).writeEBML(t(this,R)),t(this,d).seek(s);}}e.decoderConfig.description&&(t(this,f).streaming?u(this,K,h(this,X,Vt).call(this,e.decoderConfig.description)):h(this,ct,te).call(this,t(this,K),e.decoderConfig.description));}},ue=new WeakSet,ti=function(e){if(e.type!=="key"||!t(this,dt))return;let i=0;if(W(e.data,0,2)!==2)return;i+=2;let s=(W(e.data,i+1,i+2)<<1)+W(e.data,i+0,i+1);i+=2,s===3&&i++;let r=W(e.data,i+0,i+1);if(i++,r)return;let n=W(e.data,i+0,i+1);if(i++,n!==0)return;i+=2;let o=W(e.data,i+0,i+24);if(i+=24,o!==4817730)return;s>=2&&i++;let c={rgb:7,bt709:2,bt470bg:1,smpte170m:3}[t(this,dt).matrix];Fe(e.data,i+0,i+3,c);},ut=new WeakSet,Jt=function(){let e=Math.min(t(this,f).video?t(this,q):1/0,t(this,f).audio?t(this,Q):1/0),i=t(this,F);for(;i.length>0&&i[0].timestamp<=e;)h(this,T,E).call(this,i.shift(),!t(this,f).video&&!t(this,f).audio);},ft=new WeakSet,It=function(e,i,s,r,n,o){let c=h(this,fe,ei).call(this,s,r);return {data:e,additions:o,type:i,timestamp:c,duration:n,trackNumber:r}},fe=new WeakSet,ei=function(e,i){let s=i===it?t(this,q):i===Et?t(this,Q):t(this,Dt);if(i!==jt){let r=i===it?t(this,ot):t(this,ht);if(t(this,f).firstTimestampBehavior==="strict"&&s===-1&&e!==0)throw new Error(`The first chunk for your media track must have a timestamp of 0 (received ${e}). Non-zero first timestamps are often caused by directly piping frames or audio data from a MediaStreamTrack into the encoder. Their timestamps are typically relative to the age of the document, which is probably what you want. +var di=Object.defineProperty;var Pe=Object.getOwnPropertySymbols;var li=Object.prototype.hasOwnProperty,ui=Object.prototype.propertyIsEnumerable;var p=Math.pow,ve=(l,e,i)=>e in l?di(l,e,{enumerable:!0,configurable:!0,writable:!0,value:i}):l[e]=i,Me=(l,e)=>{for(var i in e||={})li.call(e,i)&&ve(l,i,e[i]);if(Pe)for(var i of Pe(e))ui.call(e,i)&&ve(l,i,e[i]);return l};var ge=(l,e,i)=>{if(!e.has(l))throw TypeError("Cannot "+i)};var t=(l,e,i)=>(ge(l,e,"read from private field"),i?i.call(l):e.get(l)),a=(l,e,i)=>{if(e.has(l))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(l):e.set(l,i);},u=(l,e,i,s)=>(ge(l,e,"write to private field"),e.set(l,i),i);var h=(l,e,i)=>(ge(l,e,"access private method"),i);var J=class{constructor(e){this.value=e;}},O=class{constructor(e){this.value=e;}};var we=l=>l<1<<8?1:l<1<<16?2:l<1<<24?3:l{if(l<(1<<7)-1)return 1;if(l<(1<<14)-1)return 2;if(l<(1<<21)-1)return 3;if(l<(1<<28)-1)return 4;if(l{let s=0;for(let r=e;r>c;s<<=1,s|=b;}return s},Fe=(l,e,i,s)=>{for(let r=e;r>i-r-1<>8),t(this,m).setUint8(s++,e);break;case 3:t(this,m).setUint8(s++,1<<5|e>>16),t(this,m).setUint8(s++,e>>8),t(this,m).setUint8(s++,e);break;case 4:t(this,m).setUint8(s++,1<<4|e>>24),t(this,m).setUint8(s++,e>>16),t(this,m).setUint8(s++,e>>8),t(this,m).setUint8(s++,e);break;case 5:t(this,m).setUint8(s++,1<<3|e/p(2,32)&7),t(this,m).setUint8(s++,e>>24),t(this,m).setUint8(s++,e>>16),t(this,m).setUint8(s++,e>>8),t(this,m).setUint8(s++,e);break;case 6:t(this,m).setUint8(s++,1<<2|e/p(2,40)&3),t(this,m).setUint8(s++,e/p(2,32)|0),t(this,m).setUint8(s++,e>>24),t(this,m).setUint8(s++,e>>16),t(this,m).setUint8(s++,e>>8),t(this,m).setUint8(s++,e);break;default:throw new Error("Bad EBML VINT size "+i)}this.write(t(this,A).subarray(0,s));}writeEBML(e){var i,s;if(e!==null)if(e instanceof Uint8Array)this.write(e);else if(Array.isArray(e))for(let r of e)this.writeEBML(r);else if(this.offsets.set(e,this.pos),h(this,yt,ye).call(this,e.id),Array.isArray(e.data)){let r=this.pos,n=e.size===-1?1:(i=e.size)!=null?i:4;e.size===-1?h(this,Lt,_e).call(this,255):this.seek(this.pos+n);let o=this.pos;if(this.dataOffsets.set(e,o),this.writeEBML(e.data),e.size!==-1){let c=this.pos-o,b=this.pos;this.seek(r),this.writeEBMLVarInt(c,n),this.seek(b);}}else if(typeof e.data=="number"){let r=(s=e.size)!=null?s:we(e.data);this.writeEBMLVarInt(r),h(this,yt,ye).call(this,e.data,r);}else typeof e.data=="string"?(this.writeEBMLVarInt(e.data.length),h(this,qt,We).call(this,e.data)):e.data instanceof Uint8Array?(this.writeEBMLVarInt(e.data.byteLength,e.size),this.write(e.data)):e.data instanceof J?(this.writeEBMLVarInt(4),h(this,Yt,Ne).call(this,e.data.value)):e.data instanceof O&&(this.writeEBMLVarInt(8),h(this,Zt,Oe).call(this,e.data.value));}};A=new WeakMap,m=new WeakMap,Lt=new WeakSet,_e=function(e){t(this,m).setUint8(0,e),this.write(t(this,A).subarray(0,1));},Yt=new WeakSet,Ne=function(e){t(this,m).setFloat32(0,e,!1),this.write(t(this,A).subarray(0,4));},Zt=new WeakSet,Oe=function(e){t(this,m).setFloat64(0,e,!1),this.write(t(this,A));},yt=new WeakSet,ye=function(e,i=we(e)){let s=0;switch(i){case 6:t(this,m).setUint8(s++,e/p(2,40)|0);case 5:t(this,m).setUint8(s++,e/p(2,32)|0);case 4:t(this,m).setUint8(s++,e>>24);case 3:t(this,m).setUint8(s++,e>>16);case 2:t(this,m).setUint8(s++,e>>8);case 1:t(this,m).setUint8(s++,e);break;default:throw new Error("Bad UINT size "+i)}this.write(t(this,A).subarray(0,s));},qt=new WeakSet,We=function(e){this.write(new Uint8Array(e.split("").map(i=>i.charCodeAt(0))));};var kt,P,tt,Ct,ke,Kt=class extends $t{constructor(i){super();a(this,Ct);a(this,kt,void 0);a(this,P,new ArrayBuffer(p(2,16)));a(this,tt,new Uint8Array(t(this,P)));u(this,kt,i);}write(i){h(this,Ct,ke).call(this,this.pos+i.byteLength),t(this,tt).set(i,this.pos),this.pos+=i.byteLength;}finalize(){h(this,Ct,ke).call(this,this.pos),t(this,kt).buffer=t(this,P).slice(0,this.pos);}};kt=new WeakMap,P=new WeakMap,tt=new WeakMap,Ct=new WeakSet,ke=function(i){let s=t(this,P).byteLength;for(;so.start-c.start);i.push({start:s[0].start,size:s[0].data.byteLength});for(let o=1;og.start<=s&&sci){for(let g=0;g=i.written[o+1].start;)i.written[o].end=Math.max(i.written[o].end,i.written[o+1].end),i.written.splice(o+1,1);},Xt=new WeakSet,Be=function(i){let r={start:Math.floor(i/t(this,y))*t(this,y),data:new Uint8Array(t(this,y)),written:[],shouldFlush:!1};return t(this,w).push(r),t(this,w).sort((n,o)=>n.start-o.start),t(this,w).indexOf(r)},et=new WeakSet,Bt=function(i=!1){var s,r;for(let n=0;ne.stream.write({type:"write",data:r,position:n}),chunked:!0,chunkSize:(s=e.options)==null?void 0:s.chunkSize}),i);}};var it=1,Et=2,jt=3,mi=1,bi=2,pi=17,Te=p(2,15),zt=p(2,12),$e="https://github.com/Vanilagy/webm-muxer",Ke=6,Ge=5,gi=["strict","offset","permissive"],f,d,at,nt,x,B,$,R,K,z,G,L,S,Y,Z,V,D,F,ot,ht,q,Q,Dt,dt,lt,ie,Le,se,Ye,re,Ze,ae,qe,ne,Qe,oe,Xe,he,je,Pt,Se,vt,Ae,de,Je,_,st,N,rt,le,Ie,ue,ti,ut,Jt,ft,It,fe,ei,T,E,X,Vt,ct,te,ce,ii,Mt,Ue,mt,ee,xe=class{constructor(e){a(this,ie);a(this,se);a(this,re);a(this,ae);a(this,ne);a(this,oe);a(this,he);a(this,Pt);a(this,vt);a(this,de);a(this,_);a(this,N);a(this,le);a(this,ue);a(this,ut);a(this,ft);a(this,fe);a(this,T);a(this,X);a(this,ct);a(this,ce);a(this,Mt);a(this,mt);a(this,f,void 0);a(this,d,void 0);a(this,at,void 0);a(this,nt,void 0);a(this,x,void 0);a(this,B,void 0);a(this,$,void 0);a(this,R,void 0);a(this,K,void 0);a(this,z,void 0);a(this,G,void 0);a(this,L,void 0);a(this,S,void 0);a(this,Y,void 0);a(this,Z,0);a(this,V,[]);a(this,D,[]);a(this,F,[]);a(this,ot,void 0);a(this,ht,void 0);a(this,q,-1);a(this,Q,-1);a(this,Dt,-1);a(this,dt,void 0);a(this,lt,!1);var s;h(this,ie,Le).call(this,e),u(this,f,Me({type:"webm",firstTimestampBehavior:"strict"},e)),this.target=e.target;let i=!!t(this,f).streaming;if(e.target instanceof Wt)u(this,d,new Kt(e.target));else if(e.target instanceof I)u(this,d,(s=e.target.options)!=null&&s.chunked?new wt(e.target,i):new gt(e.target,i));else if(e.target instanceof Ht)u(this,d,new Gt(e.target,i));else throw new Error(`Invalid target: ${e.target}`);h(this,se,Ye).call(this);}addVideoChunk(e,i,s){let r=new Uint8Array(e.byteLength);e.copyTo(r),this.addVideoChunkRaw(r,e.type,s!=null?s:e.timestamp,i);}addVideoChunkRaw(e,i,s,r){if(h(this,mt,ee).call(this),!t(this,f).video)throw new Error("No video track declared.");t(this,ot)===void 0&&u(this,ot,s),r&&h(this,le,Ie).call(this,r);let n=h(this,ft,It).call(this,e,i,s,it);for(t(this,f).video.codec==="V_VP9"&&h(this,ue,ti).call(this,n),u(this,q,n.timestamp);t(this,D).length>0&&t(this,D)[0].timestamp<=n.timestamp;){let o=t(this,D).shift();h(this,T,E).call(this,o,!1);}!t(this,f).audio||n.timestamp<=t(this,Q)?h(this,T,E).call(this,n,!0):t(this,V).push(n),h(this,ut,Jt).call(this),h(this,_,st).call(this);}addAudioChunk(e,i,s){let r=new Uint8Array(e.byteLength);e.copyTo(r),this.addAudioChunkRaw(r,e.type,s!=null?s:e.timestamp,i);}addAudioChunkRaw(e,i,s,r){if(h(this,mt,ee).call(this),!t(this,f).audio)throw new Error("No audio track declared.");t(this,ht)===void 0&&u(this,ht,s),r!=null&&r.decoderConfig&&(t(this,f).streaming?u(this,z,h(this,X,Vt).call(this,r.decoderConfig.description)):h(this,ct,te).call(this,t(this,z),r.decoderConfig.description));let n=h(this,ft,It).call(this,e,i,s,Et);for(u(this,Q,n.timestamp);t(this,V).length>0&&t(this,V)[0].timestamp<=n.timestamp;){let o=t(this,V).shift();h(this,T,E).call(this,o,!0);}!t(this,f).video||n.timestamp<=t(this,q)?h(this,T,E).call(this,n,!t(this,f).video):t(this,D).push(n),h(this,ut,Jt).call(this),h(this,_,st).call(this);}addSubtitleChunk(e,i,s){if(h(this,mt,ee).call(this),!t(this,f).subtitles)throw new Error("No subtitle track declared.");i!=null&&i.decoderConfig&&(t(this,f).streaming?u(this,G,h(this,X,Vt).call(this,i.decoderConfig.description)):h(this,ct,te).call(this,t(this,G),i.decoderConfig.description));let r=h(this,ft,It).call(this,e.body,"key",s!=null?s:e.timestamp,jt,e.duration,e.additions);u(this,Dt,r.timestamp),t(this,F).push(r),h(this,ut,Jt).call(this),h(this,_,st).call(this);}finalize(){if(t(this,lt))throw new Error("Cannot finalize a muxer more than once.");for(;t(this,V).length>0;)h(this,T,E).call(this,t(this,V).shift(),!0);for(;t(this,D).length>0;)h(this,T,E).call(this,t(this,D).shift(),!0);for(;t(this,F).length>0&&t(this,F)[0].timestamp<=t(this,Z);)h(this,T,E).call(this,t(this,F).shift(),!1);if(t(this,f).streaming||h(this,Mt,Ue).call(this),t(this,d).writeEBML(t(this,L)),!t(this,f).streaming){let e=t(this,d).pos,i=t(this,d).pos-t(this,N,rt);t(this,d).seek(t(this,d).offsets.get(t(this,at))+4),t(this,d).writeEBMLVarInt(i,Ke),t(this,$).data=new O(t(this,Z)),t(this,d).seek(t(this,d).offsets.get(t(this,$))),t(this,d).writeEBML(t(this,$)),t(this,x).data[0].data[1].data=t(this,d).offsets.get(t(this,L))-t(this,N,rt),t(this,x).data[1].data[1].data=t(this,d).offsets.get(t(this,nt))-t(this,N,rt),t(this,x).data[2].data[1].data=t(this,d).offsets.get(t(this,B))-t(this,N,rt),t(this,d).seek(t(this,d).offsets.get(t(this,x))),t(this,d).writeEBML(t(this,x)),t(this,d).seek(e);}h(this,_,st).call(this),t(this,d).finalize(),u(this,lt,!0);}};f=new WeakMap,d=new WeakMap,at=new WeakMap,nt=new WeakMap,x=new WeakMap,B=new WeakMap,$=new WeakMap,R=new WeakMap,K=new WeakMap,z=new WeakMap,G=new WeakMap,L=new WeakMap,S=new WeakMap,Y=new WeakMap,Z=new WeakMap,V=new WeakMap,D=new WeakMap,F=new WeakMap,ot=new WeakMap,ht=new WeakMap,q=new WeakMap,Q=new WeakMap,Dt=new WeakMap,dt=new WeakMap,lt=new WeakMap,ie=new WeakSet,Le=function(e){if(e.type&&e.type!=="webm"&&e.type!=="matroska")throw new Error(`Invalid type: ${e.type}`);if(e.firstTimestampBehavior&&!gi.includes(e.firstTimestampBehavior))throw new Error(`Invalid first timestamp behavior: ${e.firstTimestampBehavior}`)},se=new WeakSet,Ye=function(){t(this,d)instanceof U&&t(this,d).target.options.onHeader&&t(this,d).startTrackingWrites(),h(this,re,Ze).call(this),t(this,f).streaming||h(this,oe,Xe).call(this),h(this,he,je).call(this),h(this,ae,qe).call(this),h(this,ne,Qe).call(this),t(this,f).streaming||(h(this,Pt,Se).call(this),h(this,vt,Ae).call(this)),h(this,de,Je).call(this),h(this,_,st).call(this);},re=new WeakSet,Ze=function(){var i;let e={id:440786851,data:[{id:17030,data:1},{id:17143,data:1},{id:17138,data:4},{id:17139,data:8},{id:17026,data:(i=t(this,f).type)!=null?i:"webm"},{id:17031,data:2},{id:17029,data:2}]};t(this,d).writeEBML(e);},ae=new WeakSet,qe=function(){u(this,K,{id:236,size:4,data:new Uint8Array(zt)}),u(this,z,{id:236,size:4,data:new Uint8Array(zt)}),u(this,G,{id:236,size:4,data:new Uint8Array(zt)});},ne=new WeakSet,Qe=function(){u(this,R,{id:21936,data:[{id:21937,data:2},{id:21946,data:2},{id:21947,data:2},{id:21945,data:0}]});},oe=new WeakSet,Xe=function(){let e=new Uint8Array([28,83,187,107]),i=new Uint8Array([21,73,169,102]),s=new Uint8Array([22,84,174,107]),r={id:290298740,data:[{id:19899,data:[{id:21419,data:e},{id:21420,size:5,data:0}]},{id:19899,data:[{id:21419,data:i},{id:21420,size:5,data:0}]},{id:19899,data:[{id:21419,data:s},{id:21420,size:5,data:0}]}]};u(this,x,r);},he=new WeakSet,je=function(){let e={id:17545,data:new O(0)};u(this,$,e);let i={id:357149030,data:[{id:2807729,data:1e6},{id:19840,data:$e},{id:22337,data:$e},t(this,f).streaming?null:e]};u(this,nt,i);},Pt=new WeakSet,Se=function(){let e={id:374648427,data:[]};u(this,B,e),t(this,f).video&&e.data.push({id:174,data:[{id:215,data:it},{id:29637,data:it},{id:131,data:mi},{id:134,data:t(this,f).video.codec},t(this,K),t(this,f).video.frameRate?{id:2352003,data:1e9/t(this,f).video.frameRate}:null,{id:224,data:[{id:176,data:t(this,f).video.width},{id:186,data:t(this,f).video.height},t(this,f).video.alpha?{id:21440,data:1}:null,t(this,R)]}]}),t(this,f).audio&&(u(this,z,t(this,f).streaming?t(this,z)||null:{id:236,size:4,data:new Uint8Array(zt)}),e.data.push({id:174,data:[{id:215,data:Et},{id:29637,data:Et},{id:131,data:bi},{id:134,data:t(this,f).audio.codec},t(this,z),{id:225,data:[{id:181,data:new J(t(this,f).audio.sampleRate)},{id:159,data:t(this,f).audio.numberOfChannels},t(this,f).audio.bitDepth?{id:25188,data:t(this,f).audio.bitDepth}:null]}]})),t(this,f).subtitles&&e.data.push({id:174,data:[{id:215,data:jt},{id:29637,data:jt},{id:131,data:pi},{id:134,data:t(this,f).subtitles.codec},t(this,G)]});},vt=new WeakSet,Ae=function(){let e={id:408125543,size:t(this,f).streaming?-1:Ke,data:[t(this,f).streaming?null:t(this,x),t(this,nt),t(this,B)]};if(u(this,at,e),t(this,d).writeEBML(e),t(this,d)instanceof U&&t(this,d).target.options.onHeader){let{data:i,start:s}=t(this,d).getTrackedWrites();t(this,d).target.options.onHeader(i,s);}},de=new WeakSet,Je=function(){u(this,L,{id:475249515,data:[]});},_=new WeakSet,st=function(){t(this,d)instanceof gt&&t(this,d).flush();},N=new WeakSet,rt=function(){return t(this,d).dataOffsets.get(t(this,at))},le=new WeakSet,Ie=function(e){if(!!e.decoderConfig){if(e.decoderConfig.colorSpace){let i=e.decoderConfig.colorSpace;if(u(this,dt,i),t(this,R).data=[{id:21937,data:{rgb:1,bt709:1,bt470bg:5,smpte170m:6}[i.matrix]},{id:21946,data:{bt709:1,smpte170m:6,"iec61966-2-1":13}[i.transfer]},{id:21947,data:{bt709:1,bt470bg:5,smpte170m:6}[i.primaries]},{id:21945,data:[1,2][Number(i.fullRange)]}],!t(this,f).streaming){let s=t(this,d).pos;t(this,d).seek(t(this,d).offsets.get(t(this,R))),t(this,d).writeEBML(t(this,R)),t(this,d).seek(s);}}e.decoderConfig.description&&(t(this,f).streaming?u(this,K,h(this,X,Vt).call(this,e.decoderConfig.description)):h(this,ct,te).call(this,t(this,K),e.decoderConfig.description));}},ue=new WeakSet,ti=function(e){if(e.type!=="key"||!t(this,dt))return;let i=0;if(W(e.data,0,2)!==2)return;i+=2;let s=(W(e.data,i+1,i+2)<<1)+W(e.data,i+0,i+1);i+=2,s===3&&i++;let r=W(e.data,i+0,i+1);if(i++,r)return;let n=W(e.data,i+0,i+1);if(i++,n!==0)return;i+=2;let o=W(e.data,i+0,i+24);if(i+=24,o!==4817730)return;s>=2&&i++;let c={rgb:7,bt709:2,bt470bg:1,smpte170m:3}[t(this,dt).matrix];Fe(e.data,i+0,i+3,c);},ut=new WeakSet,Jt=function(){let e=Math.min(t(this,f).video?t(this,q):1/0,t(this,f).audio?t(this,Q):1/0),i=t(this,F);for(;i.length>0&&i[0].timestamp<=e;)h(this,T,E).call(this,i.shift(),!t(this,f).video&&!t(this,f).audio);},ft=new WeakSet,It=function(e,i,s,r,n,o){let c=h(this,fe,ei).call(this,s,r);return {data:e,additions:o,type:i,timestamp:c,duration:n,trackNumber:r}},fe=new WeakSet,ei=function(e,i){let s=i===it?t(this,q):i===Et?t(this,Q):t(this,Dt);if(i!==jt){let r=i===it?t(this,ot):t(this,ht);if(t(this,f).firstTimestampBehavior==="strict"&&s===-1&&e!==0)throw new Error(`The first chunk for your media track must have a timestamp of 0 (received ${e}). Non-zero first timestamps are often caused by directly piping frames or audio data from a MediaStreamTrack into the encoder. Their timestamps are typically relative to the age of the document, which is probably what you want. If you want to offset all timestamps of a track such that the first one is zero, set firstTimestampBehavior: 'offset' in the options. If you want to allow non-zero first timestamps, set firstTimestampBehavior: 'permissive'. @@ -5045,7 +5050,7 @@ function createTrack(name, audioContext, tempo, keySignature, trackAudioSink) { // Track-local variable definitions let instrument = null, midiDevice = null, audioDeviceInput = null; let currentVelocity = 0.5, chordIndex = 0, chordDynamicUpdated = false; - const audioSources = [], asyncAudioSources = [], effects = [], notesInWaiting = {}, waitingTies = []; + const audioSources = [], asyncAudioSources = [], effects = [], notesInWaiting = {}; const audioSink = new AnalyserNode(audioContext, { fftSize: 1024, maxDecibels: -10.0, smoothingTimeConstant: 0.5 }); const analysisBuffer = new Uint8Array(audioSink.frequencyBinCount); audioSink.connect(trackAudioSink); @@ -5284,26 +5289,29 @@ function createTrack(name, audioContext, tempo, keySignature, trackAudioSink) { throw new WebAudioTrackError(`The current track (${name}) cannot play a note without first setting up an instrument`); // Infer missing modification details for any notes in waiting - const waitingNoteDetails = [], newTies = []; - for (const noteInWaitingPitch in notesInWaiting) { - const noteInWaiting = notesInWaiting[noteInWaitingPitch]; - if (!fromChord || (noteInWaiting.chordIndex != chordIndex)) { - let noteDetails = [new NoteDetails(noteInWaiting.note, currentVelocity, noteInWaiting.duration)]; - const sequence = [[noteInWaiting.note, noteInWaiting.duration], [note, duration]]; - for (const modification of noteInWaiting.pendingModifications) - modification.value = inferModificationParametersFromSequence(modification.type, sequence, 1, modification.value); - for (const modification of noteInWaiting.modifications) { - const modClass = loadModification(modification.type, tempo, keySignature, noteDetails[0]); - noteDetails = modClass.getModifiedNoteDetails(modification.value); - if (modification.type == ModificationType.Tie) - newTies.push(noteDetails[0].note); - for (const noteDetail of noteDetails) { - noteDetail.startTimeOffset -= (startTime - noteInWaiting.startTime); - noteDetail.wasWaitingNote = true; + let wasTied = false; + const waitingNoteDetails = []; + if (!modifications.some(el => el.type === ModificationType.Tie)) { + for (const noteInWaitingPitch in notesInWaiting) { + const noteInWaiting = notesInWaiting[noteInWaitingPitch]; + if ((!fromChord || (noteInWaiting.chordIndex != chordIndex)) && (!noteInWaiting.modifications.some(el => el.type === ModificationType.Tie) || noteInWaiting.note === note)) { + let noteDetails = [new NoteDetails(noteInWaiting.note, currentVelocity, noteInWaiting.duration)]; + const sequence = noteInWaiting.sequence.concat([[note, duration]]); + for (const modification of noteInWaiting.modifications) + modification.value = inferModificationParametersFromSequence(modification.type, sequence, 1, modification.value); + for (const modification of noteInWaiting.modifications) { + const modClass = loadModification(modification.type, tempo, keySignature, noteDetails[0]); + noteDetails = modClass.getModifiedNoteDetails(modification.value); + if (modification.type == ModificationType.Tie) + wasTied = true; + for (const noteDetail of noteDetails) { + noteDetail.startTimeOffset -= (startTime - noteInWaiting.startTime); + noteDetail.wasWaitingNote = true; + } } + delete notesInWaiting[noteInWaitingPitch]; + waitingNoteDetails.push(...noteDetails); } - delete notesInWaiting[noteInWaitingPitch]; - waitingNoteDetails.push(...noteDetails); } } @@ -5321,6 +5329,8 @@ function createTrack(name, audioContext, tempo, keySignature, trackAudioSink) { // Get concrete note details based on any applied modifications let requiresWaiting = false, totalDurationSeconds = 0.0; let noteDetails = [new NoteDetails(note, currentVelocity, duration)]; + for (const noteInWaitingPitch in notesInWaiting) + notesInWaiting[noteInWaitingPitch].addedToSeq = false; for (const modification of modifications) { // Determine if the modification requires that we wait for the next note to infer missing details @@ -5330,8 +5340,13 @@ function createTrack(name, audioContext, tempo, keySignature, trackAudioSink) { for (const neededParam of neededParams) if (!('value' in modification) || !(neededParam in modification.value) && ((neededParams.length > 1) || !('implicit' in modification.value))) { if (!(note in notesInWaiting)) - notesInWaiting[note] = { note: note, duration: duration, startTime: startTime, chordIndex: chordIndex, modifications: modifications, pendingModifications: [] }; - notesInWaiting[note].pendingModifications.push(modification); + notesInWaiting[note] = { note: note, duration: duration, startTime: startTime, chordIndex: chordIndex, modifications: [], addedToSeq: false, sequence: [] }; + if (!notesInWaiting[note].addedToSeq) { + notesInWaiting[note].addedToSeq = true; + notesInWaiting[note].sequence.push([note, duration]); + } + if (!notesInWaiting[note].modifications.some(el => el.type == modification.type)) + notesInWaiting[note].modifications.push(modification); requiresWaiting = modRequiresWaiting = true; } } @@ -5346,32 +5361,24 @@ function createTrack(name, audioContext, tempo, keySignature, trackAudioSink) { currentVelocity = noteDetails[0].velocity; chordDynamicUpdated = fromChord; } - else if (modification.type == ModificationType.Tie) - newTies.push(noteDetails[0].note); } else totalDurationSeconds = (noteDetails[0].usedDuration < 0) ? -noteDetails[0].usedDuration : (60.0 / ((noteDetails[0].usedDuration / tempo.beatBase) * tempo.beatsPerMinute)); } // Schedule all notes for playback - noteDetails = (requiresWaiting ? waitingNoteDetails : waitingNoteDetails.concat(noteDetails)); + noteDetails = (requiresWaiting || wasTied ? waitingNoteDetails : waitingNoteDetails.concat(noteDetails)); for (const note of noteDetails) { const durationSeconds = (note.duration < 0) ? -note.duration : (60.0 / ((note.duration / tempo.beatBase) * tempo.beatsPerMinute)); - if (waitingTies.includes(note.note)) - waitingTies.splice(waitingTies.indexOf(note.note), 1); - else { - const noteSource = instrument.getNote(note.note); - const noteVolume = new GainNode(audioContext, { gain: note.velocity }); - noteSource.connect(noteVolume).connect(audioSink); - if (!isDrumNote) - noteVolume.gain.setTargetAtTime(0.0, startTime + note.startTimeOffset + durationSeconds, 0.03); - noteSource.onended = sourceEnded.bind(this, noteSource, noteVolume); - audioSources.push(noteSource); - noteSource.start(startTime + note.startTimeOffset, 0, isDrumNote ? undefined : (durationSeconds + 0.200)); - } - if (newTies.includes(note.note)) - waitingTies.push(newTies.splice(newTies.indexOf(note.note), 1)[0]); - if (!note.wasWaitingNote) + const noteSource = instrument.getNote(note.note); + const noteVolume = new GainNode(audioContext, { gain: note.velocity }); + noteSource.connect(noteVolume).connect(audioSink); + if (!isDrumNote) + noteVolume.gain.setTargetAtTime(0.0, startTime + note.startTimeOffset + durationSeconds, 0.03); + noteSource.onended = sourceEnded.bind(this, noteSource, noteVolume); + audioSources.push(noteSource); + noteSource.start(startTime + note.startTimeOffset, 0, isDrumNote ? undefined : (durationSeconds + 0.200)); + if (!note.wasWaitingNote || wasTied) totalDurationSeconds += (note.usedDuration <= 0) ? -note.usedDuration : (60.0 / ((note.usedDuration / tempo.beatBase) * tempo.beatsPerMinute)); } return totalDurationSeconds; @@ -7614,7 +7621,7 @@ class WebAudioAPI { async stopNote(trackName, note) { if (!(trackName in this.#tracks)) throw new WebAudioTargetError(`The target track name (${trackName}) does not exist`); - this.#tracks[trackName].stopNoteAsync(Number(note) < 0 ? -Number(note) : Number(note)); + this.#tracks[trackName].stopNoteAsync(note); } /**