@blibliki/engine 0.3.1 → 0.3.3
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.
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -2
- package/dist/index.d.ts +7 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +5 -3
- package/src/Engine.ts +17 -2
- package/src/core/Timing/index.ts +1 -1
- package/src/core/index.ts +1 -1
- package/src/index.ts +2 -0
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var he=Object.defineProperty;var ct=Object.getOwnPropertyDescriptor;var mt=Object.getOwnPropertyNames;var ht=Object.prototype.hasOwnProperty;var ft=(r,e)=>{for(var t in e)he(r,t,{get:e[t],enumerable:!0})},Mt=(r,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of mt(e))!ht.call(r,i)&&i!==t&&he(r,i,{get:()=>e[i],enumerable:!(o=ct(e,i))||o.enumerable});return r};var yt=r=>Mt(he({},"__esModule",{value:!0}),r);var wt={};ft(wt,{Engine:()=>M,MidiDevice:()=>O,MidiPortState:()=>K,ModuleType:()=>G,Note:()=>p,OscillatorWave:()=>se,TransportState:()=>W,moduleSchemas:()=>lt});module.exports=yt(wt);var F=require("@blibliki/utils");var Q=require("@blibliki/utils");var Fe=require("@blibliki/utils");var de=require("@blibliki/utils");var l=class{id;engineId;moduleType;audioModules;inputs;outputs;monoModuleConstructor;_props;superInitialized=!1;_voices;_name;constructor(e,t){let{id:o,name:i,moduleType:s,voices:n,monoModuleConstructor:m,props:h}=t;this.audioModules=[],this.monoModuleConstructor=m,this.id=o??(0,de.uuidv4)(),this.engineId=e,this.name=i,this.moduleType=s,this.voices=n||1,this._props={},this.props=h,this.inputs=new S(this),this.outputs=new b(this),this.superInitialized=!0}get name(){return this._name}set name(e){this._name=e,this.audioModules.forEach(t=>t.name=e)}get props(){return this._props}set props(e){this._props={...this._props,...e},this.audioModules.forEach(t=>t.props=e)}get voices(){return this._voices}set voices(e){this._voices=e,this.adjustNumberOfModules(),this.rePlugAll()}start(e){this.audioModules.forEach(t=>{t.start(e)})}stop(e){this.audioModules.forEach(t=>{t.stop(e)})}serialize(){return{id:this.id,name:this.name,moduleType:this.moduleType,voices:this.voices,props:this.props,inputs:this.inputs.serialize(),outputs:this.outputs.serialize()}}plug({audioModule:e,from:t,to:o}){let i=this.outputs.findByName(t),s=e.inputs.findByName(o);i.plug(s)}rePlugAll(e){this.superInitialized&&(this.inputs.rePlugAll(e),this.outputs.rePlugAll(e))}unPlugAll(){this.inputs.unPlugAll(),this.outputs.unPlugAll()}dispose(){this.inputs.unPlugAll(),this.outputs.unPlugAll(),this.audioModules.forEach(e=>{e.dispose()})}onMidiEvent=e=>{let t=e.voiceNo??0;this.findVoice(t).onMidiEvent(e)};findVoice(e){let t=this.audioModules.find(o=>o.voiceNo===e);if(!t)throw Error(`Voice ${e} on module ${this.name} not found`);return t}registerDefaultIOs(e="both"){this.registerMidiInput({name:"midi in",onMidiEvent:this.onMidiEvent}),(e==="in"||e==="both")&&this.registerAudioInput({name:"in"}),(e==="out"||e==="both")&&this.registerAudioOutput({name:"out"})}registerAudioInput(e){return this.inputs.add({...e,ioType:"polyAudioInput"})}registerAudioOutput(e){return this.outputs.add({...e,ioType:"polyAudioOutput"})}registerMidiInput(e){return this.inputs.add({...e,ioType:"midiInput"})}registerMidiOutput(e){return this.outputs.add({...e,ioType:"midiOutput"})}adjustNumberOfModules(){if(this.audioModules.length!==this.voices){if(this.audioModules.length>this.voices)this.audioModules.pop()?.dispose();else{let e=this.audioModules.length,t=(0,de.deterministicId)(this.id,e.toString()),o=this.monoModuleConstructor(this.engineId,{id:t,name:this.name,moduleType:this.moduleType,voiceNo:e,props:{...this.props}});this.audioModules.push(o)}this.adjustNumberOfModules()}}get engine(){return M.getById(this.engineId)}get context(){return this.engine.context}};var we=require("@blibliki/utils");var Me=class{id;ioType;name;module;connections;constructor(e,t){this.module=e,this.name=t.name,this.ioType=t.ioType,this.id=(0,we.deterministicId)(this.module.id,this.name),this.connections=[]}plug(e,t=!0){this.connections.push(e),t&&e.plug(this,!1)}unPlug(e,t=!0){this.connections=this.connections.filter(o=>o.id!==e.id),t&&e.unPlug(this,!1)}rePlugAll(e){let t=this.connections;this.unPlugAll(),e&&e(),t.forEach(o=>{this.plug(o)})}unPlugAll(){this.connections.forEach(e=>{this.unPlug(e)})}isAudio(){return this.ioType==="audioInput"||this.ioType==="audioOutput"||this.ioType==="polyAudioInput"||this.ioType==="polyAudioOutput"}isMidi(){return this.ioType==="midiInput"||this.ioType==="midiOutput"}serialize(){return{id:this.id,name:this.name,ioType:this.ioType,moduleId:this.module.id}}},y=class extends Me{plug(e,t){super.plug(e,t)}unPlug(e,t){super.unPlug(e,t)}};var g=class extends y{plug(e,t=!0){super.plug(e,t),!(!t&&e instanceof N)&&ae(this,e,!0)}unPlug(e,t=!0){super.unPlug(e,t),!(!t&&e instanceof N)&&ae(this,e,!1)}findIOByVoice(e){return this.module.findVoice(e).inputs.findByName(this.name)}},N=class extends y{plug(e,t=!0){super.plug(e,t),!(!t&&e instanceof g)&&ae(this,e,!0)}unPlug(e,t=!0){super.unPlug(e,t),!(!t&&e instanceof g)&&ae(this,e,!1)}findIOByVoice(e){return this.module.findVoice(e).outputs.findByName(this.name)}};function ae(r,e,t){if(e instanceof g||e instanceof N){let o=Math.max(r.module.voices,e.module.voices);for(let i=0;i<o;i++){let s=r.findIOByVoice(i%r.module.voices),n=e.findIOByVoice(i%e.module.voices);t?s.plug(n):s.unPlug(n)}}else for(let o=0;o<r.module.voices;o++){let i=r.findIOByVoice(o);t?i.plug(e):i.unPlug(e)}}var R=class extends y{getAudioNode;constructor(e,t){super(e,t),this.getAudioNode=t.getAudioNode}},_=class extends y{getAudioNode;constructor(e,t){super(e,t),this.getAudioNode=t.getAudioNode}plug(e,t=!0){if(super.plug(e,t),e instanceof g)return;let o=e.getAudioNode();o instanceof AudioParam?this.getAudioNode().connect(o):this.getAudioNode().connect(o)}unPlug(e,t=!0){if(super.unPlug(e,t),e instanceof g)return;let o=e.getAudioNode();try{o instanceof AudioParam?this.getAudioNode().disconnect(o):this.getAudioNode().disconnect(o)}catch{}}};var D=class extends y{onMidiEvent;constructor(e,t){super(e,t),this.onMidiEvent=t.onMidiEvent}},L=class extends y{onMidiEvent=e=>{this.midiConnections.forEach(t=>{t.onMidiEvent(e)})};get midiConnections(){return this.connections.filter(e=>e instanceof D)}};var U=class{module;collection=[];collectionType;constructor(e,t){this.collectionType=e,this.module=t}add(e){let t;switch(this.validateUniqName(e.name),e.ioType){case"audioInput":if(this.module instanceof l)throw Error("Not compatible");t=new R(this.module,e);break;case"audioOutput":if(this.module instanceof l)throw Error("Not compatible");t=new _(this.module,e);break;case"polyAudioInput":if(this.module instanceof u)throw Error("Not compatible");t=new g(this.module,e);break;case"polyAudioOutput":if(this.module instanceof u)throw Error("Not compatible");t=new N(this.module,e);break;case"midiInput":t=new D(this.module,e);break;case"midiOutput":t=new L(this.module,e);break;default:(0,Fe.assertNever)(e)}return this.collection.push(t),t}unPlugAll(){this.collection.forEach(e=>{e.unPlugAll()})}rePlugAll(e){this.collection.forEach(t=>{t.rePlugAll(e)})}find(e){let t=this.collection.find(o=>o.id===e);if(!t)throw Error(`The io with id ${e} is not exists`);return t}findByName(e){let t=this.collection.find(o=>o.name===e);if(!t)throw Error(`The io with name ${e} is not exists`);return t}serialize(){return this.collection.map(e=>e.serialize())}validateUniqName(e){if(this.collection.some(t=>t.name===e))throw Error(`An io with name ${e} is already exists`)}},S=class extends U{constructor(e){super("Input",e)}},b=class extends U{constructor(e){super("Output",e)}};var ge=require("webmidi");var Tt=new Map([["C0",16.35],["C#0",17.32],["Db0",17.32],["D0",18.35],["D#0",19.45],["Eb0",19.45],["E0",20.6],["F0",21.83],["F#0",23.12],["Gb0",23.12],["G0",24.5],["G#0",25.96],["Ab0",25.96],["A0",27.5],["A#0",29.14],["Bb0",29.14],["B0",30.87],["C1",32.7],["C#1",34.65],["Db1",34.65],["D1",36.71],["D#1",38.89],["Eb1",38.89],["E1",41.2],["F1",43.65],["F#1",46.25],["Gb1",46.25],["G1",49],["G#1",51.91],["Ab1",51.91],["A1",55],["A#1",58.27],["Bb1",58.27],["B1",61.74],["C2",65.41],["C#2",69.3],["Db2",69.3],["D2",73.42],["D#2",77.78],["Eb2",77.78],["E2",82.41],["F2",87.31],["F#2",92.5],["Gb2",92.5],["G2",98],["G#2",103.83],["Ab2",103.83],["A2",110],["A#2",116.54],["Bb2",116.54],["B2",123.47],["C3",130.81],["C#3",138.59],["Db3",138.59],["D3",146.83],["D#3",155.56],["Eb3",155.56],["E3",164.81],["F3",174.61],["F#3",185],["Gb3",185],["G3",196],["G#3",207.65],["Ab3",207.65],["A3",220],["A#3",233.08],["Bb3",233.08],["B3",246.94],["C4",261.63],["C#4",277.18],["Db4",277.18],["D4",293.66],["D#4",311.13],["Eb4",311.13],["E4",329.63],["F4",349.23],["F#4",369.99],["Gb4",369.99],["G4",392],["G#4",415.3],["Ab4",415.3],["A4",440],["A#4",466.16],["Bb4",466.16],["B4",493.88],["C5",523.25],["C#5",554.37],["Db5",554.37],["D5",587.33],["D#5",622.25],["Eb5",622.25],["E5",659.26],["F5",698.46],["F#5",739.99],["Gb5",739.99],["G5",783.99],["G#5",830.61],["Ab5",830.61],["A5",880],["A#5",932.33],["Bb5",932.33],["B5",987.77],["C6",1046.5],["C#6",1108.73],["Db6",1108.73],["D6",1174.66],["D#6",1244.51],["Eb6",1244.51],["E6",1318.51],["F6",1396.91],["F#6",1479.98],["Gb6",1479.98],["G6",1567.98],["G#6",1661.22],["Ab6",1661.22],["A6",1760],["A#6",1864.66],["Bb6",1864.66],["B6",1975.53],["C7",2093],["C#7",2217.46],["Db7",2217.46],["D7",2349.32],["D#7",2489.02],["Eb7",2489.02],["E7",2637.02],["F7",2793.83],["F#7",2959.96],["Gb7",2959.96],["G7",3135.96],["G#7",3322.44],["Ab7",3322.44],["A7",3520],["A#7",3729.31],["Bb7",3729.31],["B7",3951.07],["C8",4186.01],["C#8",4434.92],["Db8",4434.92],["D8",4698.64],["D#8",4978.03],["Eb8",4978.03]]),ye=Tt;var Te=["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"],It=2,p=class r{static _notes;name;octave;velocity=1;duration;static fromFrequency(e){let t;for(let[o,i]of ye)if(i===e){t=o;break}if(!t)throw Error("Not matching frequency with a note");return new r(t)}static fromEvent(e){let t=Te[e.data[1]%12],o=Math.floor(e.data[1]/12)-2;return new r(`${t}${o}`)}static notes(e=3){return Te.map(t=>new r(`${t}${e}`))}constructor(e){typeof e=="string"?this.fromString(e):this.fromProps(e)}get isSemi(){return this.name.endsWith("#")}get fullName(){return`${this.name}${this.octave}`}get frequency(){return ye.get(`${this.name}${this.octave}`)}midiData(e=!0){let t=e?144:128;return new Uint8Array([t,this.midiNumber,this.velocity*100])}get midiNumber(){return(this.octave+It)*12+this.noteIndex}get noteIndex(){return Te.indexOf(this.name)}valueOf(){return this.fullName}serialize(){return{name:this.name,octave:this.octave,frequency:this.frequency,velocity:this.velocity,duration:this.duration}}fromString(e){let t=/(\w#?)(\d)?/.exec(e)??[];this.name=t[1],this.octave=t[2]?parseInt(t[2]):1}fromProps(e){Object.assign(this,e)}};var Ie=require("@blibliki/utils");var ke=require("@ircam/sc-scheduling");var $=class{transport;internalScheduler;constructor(e){this.transport=e,this.internalScheduler=new ke.Scheduler(T,{currentTimeToProcessorTimeFunction:()=>this.transport.playhead})}start(e,t){this.internalScheduler.add(this.processor,a(e)),this.defer(t,e)}stop(e,t){this.defer(()=>{this.internalScheduler.remove(this.processor),t()},e)}defer(e,t){this.internalScheduler.defer(e,a(t))}processor=(e,t)=>(console.log(`playhead: ${c(t).toNotation()}`),e+.5)};var W=(o=>(o.playing="playing",o.stopped="stopped",o.paused="paused",o))(W||{}),C=class{bpm=120;timeSignature=[4,4];loopStart;loopEnd;state="stopped";offset=0;startTime=0;onStart;onStop;scheduler;constructor(e){this.onStart=e.onStart,this.onStop=e.onStop,this.loopStart=c("0:0:0"),this.scheduler=new $(this)}start({offset:e=this.offset,actionAt:t=T()}){if(this.state!=="playing")return this.validateFutureTime(t),this.scheduler.start(t,()=>{this.state="playing",this.offset=e,this.startTime=c(t).subtrack(this.offset)}),this.onStart?.(t),t}stop({actionAt:e=T()}){if(this.state!=="stopped")return this.validateFutureTime(e),this.scheduler.stop(e,()=>{this.state="stopped",this.offset=0}),this.onStop?.(e),e}pause({actionAt:e=T()}){if(this.state!=="paused")return this.validateFutureTime(e),this.scheduler.stop(e,()=>{this.state="paused",this.offset=c(e).subtrack(this.startTime)}),this.onStop?.(e),e}get playhead(){return this.state==="stopped"?c(0):this.state==="paused"?c(this.offset):c(T()).subtrack(this.startTime)}validateFutureTime(e){if(c(e).isBefore(T()))throw Error("Past time not allowed")}};function T(){return M.current.context.currentTime}function De(r){let e=performance.now()/1e3-T();return r/1e3-e}var c=r=>(r??=T(),r instanceof E?r:new E(r)),a=r=>(r??=T(),typeof r=="number"?r:c(r).toNumber()),E=class r{value;_notation;_number;constructor(e){this.value=e instanceof r?e.value:e,(0,Ie.isNumber)(this.value)?this._number=this.value:this._notation=this.value}add(e){return c(this.toNumber()+c(e).toNumber())}subtrack(e){return c(this.toNumber()-a(e))}isBefore(e){return this.toNumber()<a(e)}isAfter(e){return this.toNumber()>a(e)}isEqual(e){return this.toNumber()>a(e)}toNotation(){if(this._notation)return this._notation;let[e,t]=this.transport.timeSignature,o=16/t,i=e*o,s=60/this.transport.bpm,n=Math.floor(this.value/s*o),m=Math.floor(n/i),h=Math.floor(n%i/o),I=n%o;return this._notation=`${m}:${h}:${I}`,this._notation}toNumber(){if((0,Ie.isNumber)(this._number))return this._number;let[e,t]=this.transport.timeSignature,o=60/this.transport.bpm,[i,s,n]=this.value.split(":").map(Number),m=i*e+s+n/(t/4);return this._number=m*o,this._number}get transport(){return M.current.transport}};var f=class r{note;voiceNo;triggeredAt;message;static fromNote(e,t=!0,o){let i=e instanceof p?e:new p(e);return new r(new ge.Message(i.midiData(t)),o)}static fromCC(e,t,o){return new r(new ge.Message(new Uint8Array([176,e,t])),o)}constructor(e,t){this.message=e,this.triggeredAt=t??c(),this.defineNotes()}get type(){return this.message.type}get isNote(){return this.type==="noteon"||this.type==="noteoff"}defineNotes(){this.isNote&&(this.note||(this.note=p.fromEvent(this.message)))}get rawMessage(){return this.message}clone(e){let t=new r(this.message,this.triggeredAt);return t.voiceNo=e,t}};var u=class{id;engineId;name;moduleType;voiceNo;audioNode;inputs;outputs;_props;superInitialized=!1;activeNotes;constructor(e,t){let{id:o,name:i,moduleType:s,voiceNo:n,audioNodeConstructor:m,props:h}=t;this.id=o??(0,Q.uuidv4)(),this.engineId=e,this.name=i,this.moduleType=s,this.voiceNo=n??0,this.activeNotes=[],this.audioNode=m?.(this.context),this._props={},this.props=h,this.inputs=new S(this),this.outputs=new b(this),this.superInitialized=!0}get props(){return this._props}set props(e){Object.keys(e).forEach(t=>{let o=`onSet${(0,Q.upperFirst)(t)}`;this[o]?.(e[t])}),this._props={...this._props,...e},Object.keys(e).forEach(t=>{let o=`onAfterSet${(0,Q.upperFirst)(t)}`;this[o]?.(e[t])})}serialize(){return{id:this.id,name:this.name,moduleType:this.moduleType,voiceNo:this.voiceNo,props:this.props,inputs:this.inputs.serialize(),outputs:this.outputs.serialize()}}plug({audioModule:e,from:t,to:o}){let i=this.outputs.findByName(t),s=e.inputs.findByName(o);i.plug(s)}rePlugAll(e){this.inputs.rePlugAll(e),this.outputs.rePlugAll(e)}unPlugAll(){this.inputs.unPlugAll(),this.outputs.unPlugAll()}start(e){}stop(e){}triggerAttack(e,t){this.activeNotes.some(o=>o.fullName===e.fullName)||this.activeNotes.push(e)}triggerRelease(e,t){this.activeNotes=this.activeNotes.filter(o=>o.fullName!==e.fullName)}onMidiEvent=e=>{let{note:t,triggeredAt:o}=e;switch(e.type){case"noteon":{this.triggerAttack(t,o);break}case"noteoff":this.triggerRelease(t,o);break;default:throw Error("This type is not a note")}};triggerPropsUpdate(){this.engine._triggerPropsUpdate({id:this.id,moduleType:this.moduleType,voiceNo:this.voiceNo,name:this.name,props:this.props})}dispose(){this.inputs.unPlugAll(),this.outputs.unPlugAll()}registerDefaultIOs(e="both"){this.registerMidiInput({name:"midi in",onMidiEvent:this.onMidiEvent}),this.audioNode&&((e==="in"||e==="both")&&this.registerAudioInput({name:"in",getAudioNode:()=>this.audioNode}),(e==="out"||e==="both")&&this.registerAudioOutput({name:"out",getAudioNode:()=>this.audioNode}))}registerAudioInput(e){return this.inputs.add({...e,ioType:"audioInput"})}registerAudioOutput(e){return this.outputs.add({...e,ioType:"audioOutput"})}registerMidiInput(e){return this.inputs.add({...e,ioType:"midiInput"})}registerMidiOutput(e){return this.outputs.add({...e,ioType:"midiOutput"})}get engine(){return M.getById(this.engineId)}get context(){return this.engine.context}};var qe=require("@blibliki/utils"),j=class{engine;routes;constructor(e){this.engine=e,this.routes=new Map}addRoute(e){let t=e.id??(0,qe.uuidv4)(),o={...e,id:t};return this.routes.set(t,o),this.plug(t),o}removeRoute(e){this.unPlug(e),this.routes.delete(e)}clear(){for(let e in this.routes)this.removeRoute(e)}plug(e){let{sourceIO:t,destinationIO:o}=this.getIOs(e);t.plug(o)}unPlug(e){let{sourceIO:t,destinationIO:o}=this.getIOs(e);t.unPlug(o)}find(e){let t=this.routes.get(e);if(!t)throw Error(`Route with id ${e} not found`);return t}getIOs(e){let t=this.find(e),{source:o,destination:i}=t,s=this.engine.findIO(o.moduleId,o.ioName,"output"),n=this.engine.findIO(i.moduleId,i.ioName,"input");return{sourceIO:s,destinationIO:n}}};var x=require("webmidi");var K=(t=>(t.connected="connected",t.disconnected="disconnected",t))(K||{}),O=class{id;name;eventListerCallbacks=[];input;constructor(e){this.id=e.id,this.name=e.name||`Device ${e.id}`,this.input=e,this.connect()}get state(){return this.input.state}connect(){this.input.addListener("midimessage",e=>{this.processEvent(e)})}disconnect(){this.input.removeListener()}serialize(){let{id:e,name:t,state:o}=this;return{id:e,name:t,state:o}}addEventListener(e){this.eventListerCallbacks.push(e)}removeEventListener(e){this.eventListerCallbacks=this.eventListerCallbacks.filter(t=>t!==e)}processEvent(e){let t=new f(e.message,De(e.timestamp));switch(t.type){case"noteon":case"noteoff":this.eventListerCallbacks.forEach(o=>{o(t)})}}};var gt={a:new p("C3"),s:new p("D3"),d:new p("E3"),f:new p("F3"),g:new p("G3"),h:new p("A3"),j:new p("B3"),k:new p("C4"),l:new p("D4"),w:new p("C#3"),e:new p("D#3"),t:new p("F#3"),y:new p("G#3"),u:new p("A#3"),o:new p("C#4"),p:new p("D#4")},Pt=()=>({id:"computer_keyboard",name:"Computer Keyboard",state:"connected"}),q=class{id;name;state;eventListerCallbacks=[];constructor(){let{id:e,name:t,state:o}=Pt();this.id=e,this.name=t,this.state=o,document.addEventListener("keydown",this.onKeyTrigger(!0)),document.addEventListener("keyup",this.onKeyTrigger(!1))}addEventListener(e){this.eventListerCallbacks.push(e)}removeEventListener(e){this.eventListerCallbacks=this.eventListerCallbacks.filter(t=>t!==e)}serialize(){let{id:e,name:t,state:o}=this;return{id:e,name:t,state:o}}onKeyTrigger=e=>t=>{let o=this.extractNote(t);if(!o)return;let i=f.fromNote(o,e);this.eventListerCallbacks.forEach(s=>{s(i)})};extractNote(e){if(!e.repeat)return gt[e.key]}};var B=class{devices=new Map;initialized=!1;listeners=[];constructor(){let e=new q;this.devices.set(e.id,e)}async initialize(){await this.initializeDevices(),this.listenChanges(),this.initialized=!0}find(e){return this.devices.get(e)}addListener(e){this.listeners.push(e)}async initializeDevices(){if(!this.initialized)try{await x.WebMidi.enable(),x.WebMidi.inputs.forEach(e=>{this.devices.has(e.id)||this.devices.set(e.id,new O(e))})}catch(e){console.error("Error enabling WebMidi:",e)}}listenChanges(){x.WebMidi.addListener("connected",e=>{let t=e.port;if(t instanceof x.Output||this.devices.has(t.id))return;let o=new O(t);this.devices.set(o.id,o),this.listeners.forEach(i=>{i(o)})}),x.WebMidi.addListener("disconnected",e=>{let t=e.port;if(t instanceof x.Output)return;let o=this.devices.get(t.id);o&&(o instanceof q||(o.disconnect(),this.devices.delete(o.id),this.listeners.forEach(i=>{i(o)})))})}};var at=require("@blibliki/utils");var Be={},Ge={},Ae=class extends u{activeNote=null;triggeredAt=c(0);constructor(e,t){let o={...Ge,...t.props};super(e,{...t,props:o})}midiTriggered=e=>{let{triggeredAt:t,note:o,type:i}=e;if(!o)return;let s=o.fullName;switch(i){case"noteon":this.activeNote=s,this.triggeredAt=t;break;case"noteoff":this.activeNote=null;break;default:throw Error("This type is not a note")}}},H=class extends l{midiOutput;constructor(e,t){let o={...Ge,...t.props},i=(s,n)=>new Ae(s,n);super(e,{...t,props:o,monoModuleConstructor:i}),this.registerInputs(),this.registerOutputs()}onMidiEvent=e=>{let t;switch(e.type){case"noteon":t=this.findFreeVoice();break;case"noteoff":t=this.audioModules.find(o=>o.activeNote===e.note.fullName);break;default:throw Error("This type is not a note")}t&&(t.midiTriggered(e),e.voiceNo=t.voiceNo,this.midiOutput.onMidiEvent(e))};findFreeVoice(){let e=this.audioModules.find(t=>!t.activeNote);return e??=this.audioModules.sort((t,o)=>a(t.triggeredAt)-a(o.triggeredAt))[0],e}registerInputs(){this.registerMidiInput({name:"midi in",onMidiEvent:this.onMidiEvent})}registerOutputs(){this.midiOutput=this.registerMidiOutput({name:"midi out"})}};var Ve={gain:{kind:"number",min:0,max:1/0,step:.01,label:"Gain"}},ze={gain:1},w=class extends u{constructor(e,t){let o={...ze,...t.props},i=s=>new GainNode(s);super(e,{...t,audioNodeConstructor:i,props:o}),this.registerDefaultIOs(),this.registerAdditionalInputs()}onSetGain(e){this.audioNode.gain.value=e}registerAdditionalInputs(){this.registerAudioInput({name:"gain",getAudioNode:()=>this.audioNode.gain})}},X=class extends l{constructor(e,t){let o={...ze,...t.props},i=(s,n)=>new w(s,n);super(e,{...t,props:o,monoModuleConstructor:i}),this.registerAdditionalInputs(),this.registerDefaultIOs()}registerAdditionalInputs(){this.registerAudioInput({name:"gain"})}};var Re=20,Oe=2e4,_e={cutoff:Oe,envelopeAmount:0,type:"lowpass",Q:1},Le={cutoff:{kind:"number",min:Re,max:Oe,step:1,label:"Cutoff"},envelopeAmount:{kind:"number",min:-1,max:1,step:.01,label:"Envelope Amount"},type:{kind:"enum",options:["lowpass","highpass","bandpass"],label:"Type"},Q:{kind:"number",min:-100,max:100,step:.1,label:"Q"}},ve=class extends u{scale;amount;constructor(e,t){let o={..._e,...t.props},i=s=>new BiquadFilterNode(s,{type:o.type,frequency:o.cutoff,Q:o.Q});super(e,{...t,props:o,audioNodeConstructor:i}),this.amount=new w(e,{name:"amount",moduleType:"Gain",props:{gain:o.envelopeAmount}}),this.scale=V(e,{name:"scale",moduleType:"Scale",props:{min:Re,max:Oe,current:this.props.cutoff}}),this.amount.plug({audioModule:this.scale,from:"out",to:"in"}),this.scale.audioNode.connect(this.audioNode.frequency),this.registerDefaultIOs(),this.registerInputs()}onSetType(e){this.audioNode.type=e}onSetCutoff(e){this.superInitialized&&(this.scale.props={current:e})}onSetQ(e){this.audioNode.Q.value=e}onSetEnvelopeAmount(e){this.superInitialized&&(this.amount.props={gain:e})}registerInputs(){this.registerAudioInput({name:"cutoff",getAudioNode:()=>this.audioNode.frequency}),this.registerAudioInput({name:"cutoffMod",getAudioNode:()=>this.amount.audioNode}),this.registerAudioInput({name:"Q",getAudioNode:()=>this.audioNode.Q})}},Y=class extends l{constructor(e,t){let o={..._e,...t.props},i=(s,n)=>new ve(s,n);super(e,{...t,props:o,monoModuleConstructor:i}),this.registerInputs(),this.registerDefaultIOs()}registerInputs(){this.registerAudioInput({name:"cutoff"}),this.registerAudioInput({name:"cutoffMod"}),this.registerAudioInput({name:"Q"})}};var Ue={value:{kind:"number",min:-1/0,max:1/0,step:.01,label:"Value"}},At={value:1},J=class extends u{isStated=!1;constructor(e,t){let o={...At,...t.props},i=s=>new ConstantSourceNode(s);super(e,{...t,props:o,audioNodeConstructor:i}),this.registerDefaultIOs("out")}onSetValue(e){this.audioNode.offset.value=e}start(e){this.isStated||(this.isStated=!0,this.audioNode.start(a(e)))}stop(e){this.audioNode.stop(a(e)),this.rePlugAll(()=>{this.audioNode=new ConstantSourceNode(this.context,{offset:this.props.value})}),this.isStated=!1}triggerAttack=(e,t)=>{this.audioNode.offset.setValueAtTime(e.frequency,a(t)),this.start(t)};triggerRelease=()=>{}};var Se=require("@blibliki/utils");var We={attack:.1,decay:.2,sustain:0,release:.3},Qe={attack:{kind:"number",min:1e-4,max:1,step:.01,label:"Attack"},decay:{kind:"number",min:0,max:1,step:.01,label:"Decay"},sustain:{kind:"number",min:0,max:1,step:.01,label:"Sustain"},release:{kind:"number",min:0,max:1,step:.01,label:"Release"}},$e=(0,Se.createScaleNormalized)({min:.001,max:10}),vt=(0,Se.createScaleNormalized)({min:.001,max:5}),xe=class extends u{constructor(e,t){let o={...We,...t.props},i=s=>{let n=new GainNode(s);return n.gain.value=0,n};super(e,{...t,props:o,audioNodeConstructor:i}),this.registerDefaultIOs()}triggerAttack(e,t){super.triggerAttack(e,t);let o=this.scaledAttack(),i=this.scaledDecay(),s=this.props.sustain,n=a(t);this.audioNode.gain.cancelAndHoldAtTime(n),this.audioNode.gain.value===0&&this.audioNode.gain.setValueAtTime(.001,n),this.audioNode.gain.exponentialRampToValueAtTime(1,n+o),s>0?this.audioNode.gain.exponentialRampToValueAtTime(s,n+o+i):this.audioNode.gain.exponentialRampToValueAtTime(.001,n+o+i)}triggerRelease(e,t){if(super.triggerRelease(e,t),this.activeNotes.length>0)return;let o=this.scaledRelease(),i=a(t);this.audioNode.gain.cancelAndHoldAtTime(i);let s=this.audioNode.gain.value;s>=1e-4&&(this.audioNode.gain.setValueAtTime(s,i),this.audioNode.gain.exponentialRampToValueAtTime(1e-4,i+o-1e-4)),this.audioNode.gain.setValueAtTime(0,i+o)}scaledAttack(){return $e(this.props.attack)}scaledDecay(){return vt(this.props.decay)}scaledRelease(){return $e(this.props.release)}},Z=class extends l{constructor(e,t){let o={...We,...t.props},i=(s,n)=>new xe(s,n);super(e,{...t,props:o,monoModuleConstructor:i}),this.registerDefaultIOs()}};var He=require("@blibliki/utils");var je=URL.createObjectURL(new Blob(["(",(()=>{class r extends AudioWorkletProcessor{s0;s1;constructor(){super(),this.s0=0,this.s1=0}static get parameterDescriptors(){return[{name:"cutoff",defaultValue:1e3,minValue:20,maxValue:2e4},{name:"resonance",defaultValue:0,minValue:0,maxValue:4}]}process(t,o,i){let s=t[0],n=o[0],m=i.cutoff,h=i.resonance;for(let I=0;I<s.length;I++){let P=s[I],k=n[I];for(let A=0;A<P.length;A++){let d=P[A],z=m.length>1?m[A]:m[0],ce=Math.max(20,Math.min(2e4,z)),me=Math.log(ce/20)/Math.log(2e4/20),v=Math.pow(.5,(1-me)/.125),Ee=1-Math.pow(.5,((h.length>1?h[A]:h[0])+.125)/.125)*v;this.s0=Ee*this.s0-v*this.s1+v*d,this.s1=Ee*this.s1+v*this.s0,k[A]=this.s1}}return!0}}registerProcessor("filter-processor",r)}).toString(),")()"],{type:"application/javascript"}));var Ke=URL.createObjectURL(new Blob(["(",(()=>{class r extends AudioWorkletProcessor{static get parameterDescriptors(){return[{name:"min",defaultValue:1e-10},{name:"max",defaultValue:1},{name:"current",defaultValue:.5}]}process(t,o,i){let s=t[0],n=o[0],m=i.min,h=i.max,I=i.current;if(!s.length||s[0].length===0){for(let P of n){let k=(i.current.length>1,i.current[0]);P.fill(k)}return!0}for(let P=0;P<s.length;P++){let k=s[P],A=n[P];for(let d=0;d<k.length;d++){let z=k[d],ce=m.length>1?m[d]:m[0],me=h.length>1?h[d]:h[0],v=I.length>1?I[d]:I[0];z<0?A[d]=v*Math.pow(ce/v,-z):A[d]=v*Math.pow(me/v,z)}}return!0}}registerProcessor("scale-processor",r)}).toString(),")()"],{type:"application/javascript"}));async function Xe(r){await r.audioWorklet.addModule(Ke),await r.audioWorklet.addModule(je)}function le(r,e){switch(e){case"ScaleProcessor":return new AudioWorkletNode(r,"scale-processor");case"FilterProcessor":return new AudioWorkletNode(r,"filter-processor");default:(0,He.assertNever)(e)}}var Ye=20,Ne=22050,Je={cutoff:Ne,envelopeAmount:0,resonance:0},Ze={cutoff:{kind:"number",min:Ye,max:Ne,step:1e-4,label:"Cutoff"},envelopeAmount:{kind:"number",min:-1,max:1,step:.01,label:"Envelope Amount"},resonance:{kind:"number",min:0,max:4,step:.01,label:"resonance"}},be=class extends u{scale;amount;constructor(e,t){let o={...Je,...t.props},i=s=>le(s,"FilterProcessor");super(e,{...t,props:o,audioNodeConstructor:i}),this.amount=new w(e,{name:"amount",moduleType:"Gain",props:{gain:o.envelopeAmount}}),this.scale=V(e,{name:"scale",moduleType:"Scale",props:{min:Ye,max:Ne,current:this.props.cutoff}}),this.amount.plug({audioModule:this.scale,from:"out",to:"in"}),this.scale.audioNode.connect(this.cutoff),this.registerDefaultIOs(),this.registerInputs()}get cutoff(){return this.audioNode.parameters.get("cutoff")}get resonance(){return this.audioNode.parameters.get("resonance")}onSetCutoff(e){this.superInitialized&&(this.scale.props={current:e})}onSetResonance(e){this.resonance.value=e}onSetEnvelopeAmount(e){this.superInitialized&&(this.amount.props={gain:e})}registerInputs(){this.registerAudioInput({name:"cutoff",getAudioNode:()=>this.scale.audioNode}),this.registerAudioInput({name:"cutoffMod",getAudioNode:()=>this.amount.audioNode}),this.registerAudioInput({name:"Q",getAudioNode:()=>this.resonance})}},ee=class extends l{constructor(e,t){let o={...Je,...t.props},i=(s,n)=>new be(s,n);super(e,{...t,props:o,monoModuleConstructor:i}),this.registerInputs(),this.registerDefaultIOs()}registerInputs(){this.registerAudioInput({name:"cutoff"}),this.registerAudioInput({name:"cutoffMod"}),this.registerAudioInput({name:"Q"})}};var et={fftSize:{kind:"enum",options:[32,64,128,256,512,1024,2048,4096,8192,16384,32768],label:"FFT size"}},xt={fftSize:512},te=class extends u{_buffer;constructor(e,t){let o={...xt,...t.props},i=s=>new AnalyserNode(s);super(e,{...t,props:o,audioNodeConstructor:i}),this.registerDefaultIOs("in")}onSetFftSize(e){this._buffer=new Float32Array(e)}get buffer(){return this._buffer?this._buffer:(this._buffer=new Float32Array(this.props.fftSize),this._buffer)}getValue(){return this.getValues()[0]}getValues(){return this.audioNode.getFloatTimeDomainData(this.buffer),this.buffer}};var St={},tt={},oe=class extends u{constructor(e,t){let o={...St,...t.props},i=s=>s.destination;super(e,{...t,audioNodeConstructor:i,props:o}),this.registerDefaultIOs("in")}};var ot={selectedId:{kind:"string",label:"Midi device ID"}},bt={selectedId:void 0},ie=class extends u{midiOutput;_forwardMidiEvent;constructor(e,t){let o={...bt,...t.props};super(e,{...t,props:o}),this.addEventListener(this.props.selectedId),this.registerOutputs()}onSetSelectedId(e){this.superInitialized&&(this.removeEventListener(),this.addEventListener(e))}get forwardMidiEvent(){return this._forwardMidiEvent?this._forwardMidiEvent:(this._forwardMidiEvent=e=>{this.midiOutput.onMidiEvent(e)},this._forwardMidiEvent)}addEventListener(e){if(!e)return;this.engine.findMidiDevice(e)?.addEventListener(this.forwardMidiEvent)}removeEventListener(){if(!this.props.selectedId)return;this.engine.findMidiDevice(this.props.selectedId)?.removeEventListener(this.forwardMidiEvent)}registerOutputs(){this.midiOutput=this.registerMidiOutput({name:"midi out"})}};var it=require("@blibliki/utils");var rt=-18,se=(i=>(i.sine="sine",i.triangle="triangle",i.square="square",i.sawtooth="sawtooth",i))(se||{}),st={wave:{kind:"enum",options:Object.values(se),label:"Waveform"},frequency:{kind:"number",min:0,max:25e3,step:1,label:"Frequency"},fine:{kind:"number",min:-1,max:1,step:.01,label:"Fine"},coarse:{kind:"number",min:-12,max:12,step:1,label:"Coarse"},octave:{kind:"number",min:-4,max:4,step:1,label:"Octave"},lowGain:{kind:"boolean",label:`Use ${rt}db Gain`}},nt={wave:"sine",frequency:440,fine:0,coarse:0,octave:0,lowGain:!1},Ce=class extends u{isStated=!1;lowOutputGain;detuneGain;constructor(e,t){let o={...nt,...t.props},i=s=>new OscillatorNode(s);super(e,{...t,props:o,audioNodeConstructor:i}),this.lowOutputGain=new GainNode(this.context,{gain:(0,it.dbToGain)(rt)}),this.applyOutputGain(),this.initializeGainDetune(),this.registerInputs(),this.registerOutputs()}onAfterSetWave(e){this.audioNode.type=e}onAfterSetFrequency(){this.updateFrequency()}onAfterSetFine(){this.updateFrequency()}onAfterSetCoarse(){this.updateFrequency()}onAfterSetOctave(){this.updateFrequency()}onAfterSetLowGain(){this.superInitialized&&this.rePlugAll()}start(e){this.isStated||(this.isStated=!0,this.audioNode.start(a(e)))}stop(e){this.audioNode.stop(a(e)),this.rePlugAll(()=>{this.audioNode=new OscillatorNode(this.context,{type:this.props.wave,frequency:this.finalFrequency}),this.applyOutputGain(),this.detuneGain.connect(this.audioNode.detune)}),this.isStated=!1}triggerAttack=(e,t)=>{super.triggerAttack(e,t),this.props={frequency:e.frequency},this.updateFrequency(t),this.start(t)};triggerRelease(e,t){super.triggerRelease(e,t);let o=this.activeNotes.length?this.activeNotes[this.activeNotes.length-1]:null;o&&(this.props={frequency:o.frequency},this.updateFrequency(t))}get finalFrequency(){let{frequency:e,coarse:t,octave:o,fine:i}=this.props;return this.superInitialized?e*Math.pow(2,t/12+o+i/12):void 0}updateFrequency(e){this.finalFrequency!==void 0&&(e?this.audioNode.frequency.setValueAtTime(this.finalFrequency,a(e)):this.audioNode.frequency.value=this.finalFrequency)}applyOutputGain(){this.audioNode.connect(this.lowOutputGain)}initializeGainDetune(){this.detuneGain=new GainNode(this.context,{gain:100}),this.detuneGain.connect(this.audioNode.detune)}registerInputs(){this.registerAudioInput({name:"detune",getAudioNode:()=>this.detuneGain})}registerOutputs(){this.registerAudioOutput({name:"out",getAudioNode:()=>this.props.lowGain?this.lowOutputGain:this.audioNode})}},re=class extends l{constructor(e,t){let o={...nt,...t.props},i=(s,n)=>new Ce(s,n);super(e,{...t,props:o,monoModuleConstructor:i}),this.registerInputs(),this.registerDefaultIOs("out")}start(e){this.audioModules.forEach(t=>{t.start(e)})}stop(e){this.audioModules.forEach(t=>{t.stop(e)})}registerInputs(){this.registerAudioInput({name:"detune"})}};var ut={min:{kind:"number",min:-1/0,max:1/0,step:.01,label:"Min"},max:{kind:"number",min:-1/0,max:1/0,step:.01,label:"Max"},current:{kind:"number",min:-1/0,max:1/0,step:.01,label:"Current"}},Nt={min:0,max:1,current:.5},ne=class extends u{constructor(e,t){let o={...Nt,...t.props},i=s=>le(s,"ScaleProcessor");super(e,{...t,props:o,audioNodeConstructor:i}),this.registerDefaultIOs()}get current(){return this.audioNode.parameters.get("current")}get min(){return this.audioNode.parameters.get("min")}get max(){return this.audioNode.parameters.get("max")}onSetMin(e){this.min.value=e}onSetMax(e){this.max.value=e}onSetCurrent(e){this.current.value=e}};var pt={steps:{kind:"number",min:1,max:16,step:1,label:"Steps"},bars:{kind:"number",min:1,max:16,step:1,label:"Steps"}},Ct={sequences:[],steps:16,bars:1},ue=class extends u{midiOutput;constructor(e,t){let o={...Ct,...t.props};super(e,{...t,props:o})}};var dt={activeNotes:{kind:"array",label:"Active notes"}},Et={activeNotes:[]},pe=class extends u{midiOutput;constructor(e,t){let o={...Et,...t.props};super(e,{...t,props:o}),this.registerInputs(),this.registerOutputs()}sendMidi(e){this.midiOutput.onMidiEvent(e)}triggerAttack=(e,t)=>{this.props={activeNotes:[...this.props.activeNotes,e.fullName]},this.triggerPropsUpdate(),this.sendMidi(f.fromNote(e,!0,t))};triggerRelease=(e,t)=>{this.props={activeNotes:this.props.activeNotes.filter(o=>o!==e.fullName)},this.triggerPropsUpdate(),this.sendMidi(f.fromNote(e,!1,t))};registerInputs(){this.registerMidiInput({name:"midi in",onMidiEvent:this.onMidiEvent})}registerOutputs(){this.midiOutput=this.registerMidiOutput({name:"midi out"})}};var G=(d=>(d.Master="Master",d.Oscillator="Oscillator",d.Gain="Gain",d.MidiSelector="MidiSelector",d.Envelope="Envelope",d.Filter="Filter",d.BiquadFilter="BiquadFilter",d.Scale="Scale",d.Inspector="Inspector",d.Constant="Constant",d.VirtualMidi="VirtualMidi",d.StepSequencer="StepSequencer",d.VoiceScheduler="VoiceScheduler",d))(G||{}),lt={Oscillator:st,Gain:Ve,Master:tt,MidiSelector:ot,Envelope:Qe,Filter:Ze,BiquadFilter:Le,Scale:ut,Inspector:et,Constant:Ue,VirtualMidi:dt,StepSequencer:pt,VoiceScheduler:Be};function V(r,e){switch(e.moduleType){case"Oscillator":return new re(r,e);case"Gain":return new X(r,e);case"Master":return new oe(r,e);case"MidiSelector":return new ie(r,e);case"Envelope":return new Z(r,e);case"Filter":return new ee(r,e);case"BiquadFilter":return new Y(r,e);case"Scale":return new ne(r,e);case"Inspector":return new te(r,e);case"Constant":return new J(r,e);case"VirtualMidi":return new pe(r,e);case"StepSequencer":return new ue(r,e);case"VoiceScheduler":return new H(r,e);default:(0,at.assertNever)(e)}}var M=class r{static _engines=new Map;static _currentId;propsUpdateCallbacks=[];id;context;isInitialized=!1;routes;transport;modules;midiDeviceManager;static getById(e){let t=r._engines.get(e);return(0,F.assertDefined)(t),t}static get current(){return(0,F.assertDefined)(this._currentId),this.getById(this._currentId)}constructor(e){this.id=(0,F.uuidv4)(),this.context=e,this.transport=new C({onStart:this.onStart,onStop:this.onStop}),this.routes=new j(this),this.modules=new Map,this.midiDeviceManager=new B,r._engines.set(this.id,this),r._currentId=this.id}get state(){return this.transport.state}async initialize(){this.isInitialized||(await Xe(this.context),await this.midiDeviceManager.initialize(),this.isInitialized=!0)}addModule(e){let t=V(this.id,e);return this.modules.set(t.id,t),t.serialize()}updateModule(e){let t=this.findModule(e.id);if(t.moduleType!==e.moduleType)throw Error(`The module id ${e.id} isn't moduleType ${e.moduleType}`);let o=(0,F.pick)(e.changes,["name","props"]);return Object.assign(t,o),t instanceof l&&e.changes.voices!==void 0&&(t.voices=e.changes.voices),t.serialize()}removeModule(e){this.modules.delete(e)}addRoute(e){return this.routes.addRoute(e)}removeRoute(e){this.routes.removeRoute(e)}validRoute(e){let{source:t,destination:o}=e,i=this.findIO(t.moduleId,t.ioName,"output"),s=this.findIO(o.moduleId,o.ioName,"input");return i.isMidi()&&s.isMidi()||i.isAudio()&&s.isAudio()}start(e={}){this.transport.start(e)}stop(e={}){this.transport.stop(e)}pause(e={}){this.transport.pause(e)}get bpm(){return this.transport.bpm}set bpm(e){this.transport.bpm=e}async resume(){await this.context.resume()}dispose(){this.stop(),this.routes.clear(),this.modules.forEach(e=>{e.dispose()}),this.modules.clear()}findModule(e){let t=this.modules.get(e);if(!t)throw Error(`The module with id ${e} is not exists`);return t}findIO(e,t,o){return this.findModule(e)[`${o}s`].findByName(t)}findMidiDevice(e){return this.midiDeviceManager.find(e)}onPropsUpdate(e){this.propsUpdateCallbacks.push(e)}_triggerPropsUpdate(e){this.propsUpdateCallbacks.forEach(t=>{t(e)})}triggerVirtualMidi(e,t,o){let i=this.findModule(e);if(i.moduleType!=="VirtualMidi")throw Error("This is not a virtual mid");i.sendMidi(f.fromNote(t,o==="noteOn"))}onStart=e=>{this.modules.forEach(t=>{t.start(e)})};onStop=e=>{this.modules.forEach(t=>{t.stop(e)})}};
|
|
1
|
+
"use strict";var he=Object.defineProperty;var ct=Object.getOwnPropertyDescriptor;var mt=Object.getOwnPropertyNames;var ht=Object.prototype.hasOwnProperty;var ft=(i,e)=>{for(var t in e)he(i,t,{get:e[t],enumerable:!0})},Mt=(i,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of mt(e))!ht.call(i,r)&&r!==t&&he(i,r,{get:()=>e[r],enumerable:!(o=ct(e,r))||o.enumerable});return i};var yt=i=>Mt(he({},"__esModule",{value:!0}),i);var wt={};ft(wt,{Engine:()=>M,MidiDevice:()=>O,MidiPortState:()=>K,ModuleType:()=>G,Note:()=>p,OscillatorWave:()=>se,TransportState:()=>W,moduleSchemas:()=>lt});module.exports=yt(wt);var F=require("@blibliki/utils");var Q=require("@blibliki/utils");var Fe=require("@blibliki/utils");var de=require("@blibliki/utils");var c=class{id;engineId;moduleType;audioModules;inputs;outputs;monoModuleConstructor;_props;superInitialized=!1;_voices;_name;constructor(e,t){let{id:o,name:r,moduleType:s,voices:n,monoModuleConstructor:m,props:h}=t;this.audioModules=[],this.monoModuleConstructor=m,this.id=o??(0,de.uuidv4)(),this.engineId=e,this.name=r,this.moduleType=s,this.voices=n||1,this._props={},this.props=h,this.inputs=new S(this),this.outputs=new b(this),this.superInitialized=!0}get name(){return this._name}set name(e){this._name=e,this.audioModules.forEach(t=>t.name=e)}get props(){return this._props}set props(e){this._props={...this._props,...e},this.audioModules.forEach(t=>t.props=e)}get voices(){return this._voices}set voices(e){this._voices=e,this.adjustNumberOfModules(),this.rePlugAll()}start(e){this.audioModules.forEach(t=>{t.start(e)})}stop(e){this.audioModules.forEach(t=>{t.stop(e)})}serialize(){return{id:this.id,name:this.name,moduleType:this.moduleType,voices:this.voices,props:this.props,inputs:this.inputs.serialize(),outputs:this.outputs.serialize()}}plug({audioModule:e,from:t,to:o}){let r=this.outputs.findByName(t),s=e.inputs.findByName(o);r.plug(s)}rePlugAll(e){this.superInitialized&&(this.inputs.rePlugAll(e),this.outputs.rePlugAll(e))}unPlugAll(){this.inputs.unPlugAll(),this.outputs.unPlugAll()}dispose(){this.inputs.unPlugAll(),this.outputs.unPlugAll(),this.audioModules.forEach(e=>{e.dispose()})}onMidiEvent=e=>{let t=e.voiceNo??0;this.findVoice(t).onMidiEvent(e)};findVoice(e){let t=this.audioModules.find(o=>o.voiceNo===e);if(!t)throw Error(`Voice ${e} on module ${this.name} not found`);return t}registerDefaultIOs(e="both"){this.registerMidiInput({name:"midi in",onMidiEvent:this.onMidiEvent}),(e==="in"||e==="both")&&this.registerAudioInput({name:"in"}),(e==="out"||e==="both")&&this.registerAudioOutput({name:"out"})}registerAudioInput(e){return this.inputs.add({...e,ioType:"polyAudioInput"})}registerAudioOutput(e){return this.outputs.add({...e,ioType:"polyAudioOutput"})}registerMidiInput(e){return this.inputs.add({...e,ioType:"midiInput"})}registerMidiOutput(e){return this.outputs.add({...e,ioType:"midiOutput"})}adjustNumberOfModules(){if(this.audioModules.length!==this.voices){if(this.audioModules.length>this.voices)this.audioModules.pop()?.dispose();else{let e=this.audioModules.length,t=(0,de.deterministicId)(this.id,e.toString()),o=this.monoModuleConstructor(this.engineId,{id:t,name:this.name,moduleType:this.moduleType,voiceNo:e,props:{...this.props}});this.audioModules.push(o)}this.adjustNumberOfModules()}}get engine(){return M.getById(this.engineId)}get context(){return this.engine.context}};var we=require("@blibliki/utils");var Me=class{id;ioType;name;module;connections;constructor(e,t){this.module=e,this.name=t.name,this.ioType=t.ioType,this.id=(0,we.deterministicId)(this.module.id,this.name),this.connections=[]}plug(e,t=!0){this.connections.push(e),t&&e.plug(this,!1)}unPlug(e,t=!0){this.connections=this.connections.filter(o=>o.id!==e.id),t&&e.unPlug(this,!1)}rePlugAll(e){let t=this.connections;this.unPlugAll(),e&&e(),t.forEach(o=>{this.plug(o)})}unPlugAll(){this.connections.forEach(e=>{this.unPlug(e)})}isAudio(){return this.ioType==="audioInput"||this.ioType==="audioOutput"||this.ioType==="polyAudioInput"||this.ioType==="polyAudioOutput"}isMidi(){return this.ioType==="midiInput"||this.ioType==="midiOutput"}serialize(){return{id:this.id,name:this.name,ioType:this.ioType,moduleId:this.module.id}}},y=class extends Me{plug(e,t){super.plug(e,t)}unPlug(e,t){super.unPlug(e,t)}};var g=class extends y{plug(e,t=!0){super.plug(e,t),!(!t&&e instanceof N)&&ae(this,e,!0)}unPlug(e,t=!0){super.unPlug(e,t),!(!t&&e instanceof N)&&ae(this,e,!1)}findIOByVoice(e){return this.module.findVoice(e).inputs.findByName(this.name)}},N=class extends y{plug(e,t=!0){super.plug(e,t),!(!t&&e instanceof g)&&ae(this,e,!0)}unPlug(e,t=!0){super.unPlug(e,t),!(!t&&e instanceof g)&&ae(this,e,!1)}findIOByVoice(e){return this.module.findVoice(e).outputs.findByName(this.name)}};function ae(i,e,t){if(e instanceof g||e instanceof N){let o=Math.max(i.module.voices,e.module.voices);for(let r=0;r<o;r++){let s=i.findIOByVoice(r%i.module.voices),n=e.findIOByVoice(r%e.module.voices);t?s.plug(n):s.unPlug(n)}}else for(let o=0;o<i.module.voices;o++){let r=i.findIOByVoice(o);t?r.plug(e):r.unPlug(e)}}var R=class extends y{getAudioNode;constructor(e,t){super(e,t),this.getAudioNode=t.getAudioNode}},_=class extends y{getAudioNode;constructor(e,t){super(e,t),this.getAudioNode=t.getAudioNode}plug(e,t=!0){if(super.plug(e,t),e instanceof g)return;let o=e.getAudioNode();o instanceof AudioParam?this.getAudioNode().connect(o):this.getAudioNode().connect(o)}unPlug(e,t=!0){if(super.unPlug(e,t),e instanceof g)return;let o=e.getAudioNode();try{o instanceof AudioParam?this.getAudioNode().disconnect(o):this.getAudioNode().disconnect(o)}catch{}}};var D=class extends y{onMidiEvent;constructor(e,t){super(e,t),this.onMidiEvent=t.onMidiEvent}},L=class extends y{onMidiEvent=e=>{this.midiConnections.forEach(t=>{t.onMidiEvent(e)})};get midiConnections(){return this.connections.filter(e=>e instanceof D)}};var U=class{module;collection=[];collectionType;constructor(e,t){this.collectionType=e,this.module=t}add(e){let t;switch(this.validateUniqName(e.name),e.ioType){case"audioInput":if(this.module instanceof c)throw Error("Not compatible");t=new R(this.module,e);break;case"audioOutput":if(this.module instanceof c)throw Error("Not compatible");t=new _(this.module,e);break;case"polyAudioInput":if(this.module instanceof u)throw Error("Not compatible");t=new g(this.module,e);break;case"polyAudioOutput":if(this.module instanceof u)throw Error("Not compatible");t=new N(this.module,e);break;case"midiInput":t=new D(this.module,e);break;case"midiOutput":t=new L(this.module,e);break;default:(0,Fe.assertNever)(e)}return this.collection.push(t),t}unPlugAll(){this.collection.forEach(e=>{e.unPlugAll()})}rePlugAll(e){this.collection.forEach(t=>{t.rePlugAll(e)})}find(e){let t=this.collection.find(o=>o.id===e);if(!t)throw Error(`The io with id ${e} is not exists`);return t}findByName(e){let t=this.collection.find(o=>o.name===e);if(!t)throw Error(`The io with name ${e} is not exists`);return t}serialize(){return this.collection.map(e=>e.serialize())}validateUniqName(e){if(this.collection.some(t=>t.name===e))throw Error(`An io with name ${e} is already exists`)}},S=class extends U{constructor(e){super("Input",e)}},b=class extends U{constructor(e){super("Output",e)}};var ge=require("webmidi");var Tt=new Map([["C0",16.35],["C#0",17.32],["Db0",17.32],["D0",18.35],["D#0",19.45],["Eb0",19.45],["E0",20.6],["F0",21.83],["F#0",23.12],["Gb0",23.12],["G0",24.5],["G#0",25.96],["Ab0",25.96],["A0",27.5],["A#0",29.14],["Bb0",29.14],["B0",30.87],["C1",32.7],["C#1",34.65],["Db1",34.65],["D1",36.71],["D#1",38.89],["Eb1",38.89],["E1",41.2],["F1",43.65],["F#1",46.25],["Gb1",46.25],["G1",49],["G#1",51.91],["Ab1",51.91],["A1",55],["A#1",58.27],["Bb1",58.27],["B1",61.74],["C2",65.41],["C#2",69.3],["Db2",69.3],["D2",73.42],["D#2",77.78],["Eb2",77.78],["E2",82.41],["F2",87.31],["F#2",92.5],["Gb2",92.5],["G2",98],["G#2",103.83],["Ab2",103.83],["A2",110],["A#2",116.54],["Bb2",116.54],["B2",123.47],["C3",130.81],["C#3",138.59],["Db3",138.59],["D3",146.83],["D#3",155.56],["Eb3",155.56],["E3",164.81],["F3",174.61],["F#3",185],["Gb3",185],["G3",196],["G#3",207.65],["Ab3",207.65],["A3",220],["A#3",233.08],["Bb3",233.08],["B3",246.94],["C4",261.63],["C#4",277.18],["Db4",277.18],["D4",293.66],["D#4",311.13],["Eb4",311.13],["E4",329.63],["F4",349.23],["F#4",369.99],["Gb4",369.99],["G4",392],["G#4",415.3],["Ab4",415.3],["A4",440],["A#4",466.16],["Bb4",466.16],["B4",493.88],["C5",523.25],["C#5",554.37],["Db5",554.37],["D5",587.33],["D#5",622.25],["Eb5",622.25],["E5",659.26],["F5",698.46],["F#5",739.99],["Gb5",739.99],["G5",783.99],["G#5",830.61],["Ab5",830.61],["A5",880],["A#5",932.33],["Bb5",932.33],["B5",987.77],["C6",1046.5],["C#6",1108.73],["Db6",1108.73],["D6",1174.66],["D#6",1244.51],["Eb6",1244.51],["E6",1318.51],["F6",1396.91],["F#6",1479.98],["Gb6",1479.98],["G6",1567.98],["G#6",1661.22],["Ab6",1661.22],["A6",1760],["A#6",1864.66],["Bb6",1864.66],["B6",1975.53],["C7",2093],["C#7",2217.46],["Db7",2217.46],["D7",2349.32],["D#7",2489.02],["Eb7",2489.02],["E7",2637.02],["F7",2793.83],["F#7",2959.96],["Gb7",2959.96],["G7",3135.96],["G#7",3322.44],["Ab7",3322.44],["A7",3520],["A#7",3729.31],["Bb7",3729.31],["B7",3951.07],["C8",4186.01],["C#8",4434.92],["Db8",4434.92],["D8",4698.64],["D#8",4978.03],["Eb8",4978.03]]),ye=Tt;var Te=["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"],It=2,p=class i{static _notes;name;octave;velocity=1;duration;static fromFrequency(e){let t;for(let[o,r]of ye)if(r===e){t=o;break}if(!t)throw Error("Not matching frequency with a note");return new i(t)}static fromEvent(e){let t=Te[e.data[1]%12],o=Math.floor(e.data[1]/12)-2;return new i(`${t}${o}`)}static notes(e=3){return Te.map(t=>new i(`${t}${e}`))}constructor(e){typeof e=="string"?this.fromString(e):this.fromProps(e)}get isSemi(){return this.name.endsWith("#")}get fullName(){return`${this.name}${this.octave}`}get frequency(){return ye.get(`${this.name}${this.octave}`)}midiData(e=!0){let t=e?144:128;return new Uint8Array([t,this.midiNumber,this.velocity*100])}get midiNumber(){return(this.octave+It)*12+this.noteIndex}get noteIndex(){return Te.indexOf(this.name)}valueOf(){return this.fullName}serialize(){return{name:this.name,octave:this.octave,frequency:this.frequency,velocity:this.velocity,duration:this.duration}}fromString(e){let t=/(\w#?)(\d)?/.exec(e)??[];this.name=t[1],this.octave=t[2]?parseInt(t[2]):1}fromProps(e){Object.assign(this,e)}};var Ie=require("@blibliki/utils");var ke=require("@ircam/sc-scheduling");var $=class{transport;internalScheduler;constructor(e){this.transport=e,this.internalScheduler=new ke.Scheduler(T,{currentTimeToProcessorTimeFunction:()=>this.transport.playhead})}start(e,t){this.internalScheduler.add(this.processor,a(e)),this.defer(t,e)}stop(e,t){this.defer(()=>{this.internalScheduler.remove(this.processor),t()},e)}defer(e,t){this.internalScheduler.defer(e,a(t))}processor=(e,t)=>(console.log(`playhead: ${l(t).toNotation()}`),e+.5)};var W=(o=>(o.playing="playing",o.stopped="stopped",o.paused="paused",o))(W||{}),C=class{bpm=120;timeSignature=[4,4];loopStart;loopEnd;state="stopped";offset=0;startTime=0;onStart;onStop;scheduler;constructor(e){this.onStart=e.onStart,this.onStop=e.onStop,this.loopStart=l("0:0:0"),this.scheduler=new $(this)}start({offset:e=this.offset,actionAt:t=T()}){if(this.state!=="playing")return this.validateFutureTime(t),this.scheduler.start(t,()=>{this.state="playing",this.offset=e,this.startTime=l(t).subtrack(this.offset)}),this.onStart?.(t),t}stop({actionAt:e=T()}){if(this.state!=="stopped")return this.validateFutureTime(e),this.scheduler.stop(e,()=>{this.state="stopped",this.offset=0}),this.onStop?.(e),e}pause({actionAt:e=T()}){if(this.state!=="paused")return this.validateFutureTime(e),this.scheduler.stop(e,()=>{this.state="paused",this.offset=l(e).subtrack(this.startTime)}),this.onStop?.(e),e}get playhead(){return this.state==="stopped"?l(0):this.state==="paused"?l(this.offset):l(T()).subtrack(this.startTime)}validateFutureTime(e){if(l(e).isBefore(T()))throw Error("Past time not allowed")}};function T(){return M.current.context.currentTime}function De(i){let e=performance.now()/1e3-T();return i/1e3-e}var l=i=>(i??=T(),i instanceof E?i:new E(i)),a=i=>(i??=T(),typeof i=="number"?i:l(i).toNumber()),E=class i{value;_notation;_number;constructor(e){this.value=e instanceof i?e.value:e,(0,Ie.isNumber)(this.value)?this._number=this.value:this._notation=this.value}add(e){return l(this.toNumber()+l(e).toNumber())}subtrack(e){return l(this.toNumber()-a(e))}isBefore(e){return this.toNumber()<a(e)}isAfter(e){return this.toNumber()>a(e)}isEqual(e){return this.toNumber()>a(e)}toNotation(){if(this._notation)return this._notation;let[e,t]=this.transport.timeSignature,o=16/t,r=e*o,s=60/this.transport.bpm,n=Math.floor(this.value/s*o),m=Math.floor(n/r),h=Math.floor(n%r/o),I=n%o;return this._notation=`${m}:${h}:${I}`,this._notation}toNumber(){if((0,Ie.isNumber)(this._number))return this._number;let[e,t]=this.transport.timeSignature,o=60/this.transport.bpm,[r,s,n]=this.value.split(":").map(Number),m=r*e+s+n/(t/4);return this._number=m*o,this._number}get transport(){return M.current.transport}};var f=class i{note;voiceNo;triggeredAt;message;static fromNote(e,t=!0,o){let r=e instanceof p?e:new p(e);return new i(new ge.Message(r.midiData(t)),o)}static fromCC(e,t,o){return new i(new ge.Message(new Uint8Array([176,e,t])),o)}constructor(e,t){this.message=e,this.triggeredAt=t??l(),this.defineNotes()}get type(){return this.message.type}get isNote(){return this.type==="noteon"||this.type==="noteoff"}defineNotes(){this.isNote&&(this.note||(this.note=p.fromEvent(this.message)))}get rawMessage(){return this.message}clone(e){let t=new i(this.message,this.triggeredAt);return t.voiceNo=e,t}};var u=class{id;engineId;name;moduleType;voiceNo;audioNode;inputs;outputs;_props;superInitialized=!1;activeNotes;constructor(e,t){let{id:o,name:r,moduleType:s,voiceNo:n,audioNodeConstructor:m,props:h}=t;this.id=o??(0,Q.uuidv4)(),this.engineId=e,this.name=r,this.moduleType=s,this.voiceNo=n??0,this.activeNotes=[],this.audioNode=m?.(this.context),this._props={},this.props=h,this.inputs=new S(this),this.outputs=new b(this),this.superInitialized=!0}get props(){return this._props}set props(e){Object.keys(e).forEach(t=>{let o=`onSet${(0,Q.upperFirst)(t)}`;this[o]?.(e[t])}),this._props={...this._props,...e},Object.keys(e).forEach(t=>{let o=`onAfterSet${(0,Q.upperFirst)(t)}`;this[o]?.(e[t])})}serialize(){return{id:this.id,name:this.name,moduleType:this.moduleType,voiceNo:this.voiceNo,props:this.props,inputs:this.inputs.serialize(),outputs:this.outputs.serialize()}}plug({audioModule:e,from:t,to:o}){let r=this.outputs.findByName(t),s=e.inputs.findByName(o);r.plug(s)}rePlugAll(e){this.inputs.rePlugAll(e),this.outputs.rePlugAll(e)}unPlugAll(){this.inputs.unPlugAll(),this.outputs.unPlugAll()}start(e){}stop(e){}triggerAttack(e,t){this.activeNotes.some(o=>o.fullName===e.fullName)||this.activeNotes.push(e)}triggerRelease(e,t){this.activeNotes=this.activeNotes.filter(o=>o.fullName!==e.fullName)}onMidiEvent=e=>{let{note:t,triggeredAt:o}=e;switch(e.type){case"noteon":{this.triggerAttack(t,o);break}case"noteoff":this.triggerRelease(t,o);break;default:throw Error("This type is not a note")}};triggerPropsUpdate(){this.engine._triggerPropsUpdate({id:this.id,moduleType:this.moduleType,voiceNo:this.voiceNo,name:this.name,props:this.props})}dispose(){this.inputs.unPlugAll(),this.outputs.unPlugAll()}registerDefaultIOs(e="both"){this.registerMidiInput({name:"midi in",onMidiEvent:this.onMidiEvent}),this.audioNode&&((e==="in"||e==="both")&&this.registerAudioInput({name:"in",getAudioNode:()=>this.audioNode}),(e==="out"||e==="both")&&this.registerAudioOutput({name:"out",getAudioNode:()=>this.audioNode}))}registerAudioInput(e){return this.inputs.add({...e,ioType:"audioInput"})}registerAudioOutput(e){return this.outputs.add({...e,ioType:"audioOutput"})}registerMidiInput(e){return this.inputs.add({...e,ioType:"midiInput"})}registerMidiOutput(e){return this.outputs.add({...e,ioType:"midiOutput"})}get engine(){return M.getById(this.engineId)}get context(){return this.engine.context}};var qe=require("@blibliki/utils"),j=class{engine;routes;constructor(e){this.engine=e,this.routes=new Map}addRoute(e){let t=e.id??(0,qe.uuidv4)(),o={...e,id:t};return this.routes.set(t,o),this.plug(t),o}removeRoute(e){this.unPlug(e),this.routes.delete(e)}clear(){for(let e in this.routes)this.removeRoute(e)}plug(e){let{sourceIO:t,destinationIO:o}=this.getIOs(e);t.plug(o)}unPlug(e){let{sourceIO:t,destinationIO:o}=this.getIOs(e);t.unPlug(o)}find(e){let t=this.routes.get(e);if(!t)throw Error(`Route with id ${e} not found`);return t}getIOs(e){let t=this.find(e),{source:o,destination:r}=t,s=this.engine.findIO(o.moduleId,o.ioName,"output"),n=this.engine.findIO(r.moduleId,r.ioName,"input");return{sourceIO:s,destinationIO:n}}};var x=require("webmidi");var K=(t=>(t.connected="connected",t.disconnected="disconnected",t))(K||{}),O=class{id;name;eventListerCallbacks=[];input;constructor(e){this.id=e.id,this.name=e.name||`Device ${e.id}`,this.input=e,this.connect()}get state(){return this.input.state}connect(){this.input.addListener("midimessage",e=>{this.processEvent(e)})}disconnect(){this.input.removeListener()}serialize(){let{id:e,name:t,state:o}=this;return{id:e,name:t,state:o}}addEventListener(e){this.eventListerCallbacks.push(e)}removeEventListener(e){this.eventListerCallbacks=this.eventListerCallbacks.filter(t=>t!==e)}processEvent(e){let t=new f(e.message,De(e.timestamp));switch(t.type){case"noteon":case"noteoff":this.eventListerCallbacks.forEach(o=>{o(t)})}}};var gt={a:new p("C3"),s:new p("D3"),d:new p("E3"),f:new p("F3"),g:new p("G3"),h:new p("A3"),j:new p("B3"),k:new p("C4"),l:new p("D4"),w:new p("C#3"),e:new p("D#3"),t:new p("F#3"),y:new p("G#3"),u:new p("A#3"),o:new p("C#4"),p:new p("D#4")},Pt=()=>({id:"computer_keyboard",name:"Computer Keyboard",state:"connected"}),q=class{id;name;state;eventListerCallbacks=[];constructor(){let{id:e,name:t,state:o}=Pt();this.id=e,this.name=t,this.state=o,document.addEventListener("keydown",this.onKeyTrigger(!0)),document.addEventListener("keyup",this.onKeyTrigger(!1))}addEventListener(e){this.eventListerCallbacks.push(e)}removeEventListener(e){this.eventListerCallbacks=this.eventListerCallbacks.filter(t=>t!==e)}serialize(){let{id:e,name:t,state:o}=this;return{id:e,name:t,state:o}}onKeyTrigger=e=>t=>{let o=this.extractNote(t);if(!o)return;let r=f.fromNote(o,e);this.eventListerCallbacks.forEach(s=>{s(r)})};extractNote(e){if(!e.repeat)return gt[e.key]}};var B=class{devices=new Map;initialized=!1;listeners=[];constructor(){let e=new q;this.devices.set(e.id,e)}async initialize(){await this.initializeDevices(),this.listenChanges(),this.initialized=!0}find(e){return this.devices.get(e)}addListener(e){this.listeners.push(e)}async initializeDevices(){if(!this.initialized)try{await x.WebMidi.enable(),x.WebMidi.inputs.forEach(e=>{this.devices.has(e.id)||this.devices.set(e.id,new O(e))})}catch(e){console.error("Error enabling WebMidi:",e)}}listenChanges(){x.WebMidi.addListener("connected",e=>{let t=e.port;if(t instanceof x.Output||this.devices.has(t.id))return;let o=new O(t);this.devices.set(o.id,o),this.listeners.forEach(r=>{r(o)})}),x.WebMidi.addListener("disconnected",e=>{let t=e.port;if(t instanceof x.Output)return;let o=this.devices.get(t.id);o&&(o instanceof q||(o.disconnect(),this.devices.delete(o.id),this.listeners.forEach(r=>{r(o)})))})}};var at=require("@blibliki/utils");var Be={},Ge={},Ae=class extends u{activeNote=null;triggeredAt=l(0);constructor(e,t){let o={...Ge,...t.props};super(e,{...t,props:o})}midiTriggered=e=>{let{triggeredAt:t,note:o,type:r}=e;if(!o)return;let s=o.fullName;switch(r){case"noteon":this.activeNote=s,this.triggeredAt=t;break;case"noteoff":this.activeNote=null;break;default:throw Error("This type is not a note")}}},H=class extends c{midiOutput;constructor(e,t){let o={...Ge,...t.props},r=(s,n)=>new Ae(s,n);super(e,{...t,props:o,monoModuleConstructor:r}),this.registerInputs(),this.registerOutputs()}onMidiEvent=e=>{let t;switch(e.type){case"noteon":t=this.findFreeVoice();break;case"noteoff":t=this.audioModules.find(o=>o.activeNote===e.note.fullName);break;default:throw Error("This type is not a note")}t&&(t.midiTriggered(e),e.voiceNo=t.voiceNo,this.midiOutput.onMidiEvent(e))};findFreeVoice(){let e=this.audioModules.find(t=>!t.activeNote);return e??=this.audioModules.sort((t,o)=>a(t.triggeredAt)-a(o.triggeredAt))[0],e}registerInputs(){this.registerMidiInput({name:"midi in",onMidiEvent:this.onMidiEvent})}registerOutputs(){this.midiOutput=this.registerMidiOutput({name:"midi out"})}};var Ve={gain:{kind:"number",min:0,max:1/0,step:.01,label:"Gain"}},ze={gain:1},w=class extends u{constructor(e,t){let o={...ze,...t.props},r=s=>new GainNode(s);super(e,{...t,audioNodeConstructor:r,props:o}),this.registerDefaultIOs(),this.registerAdditionalInputs()}onSetGain(e){this.audioNode.gain.value=e}registerAdditionalInputs(){this.registerAudioInput({name:"gain",getAudioNode:()=>this.audioNode.gain})}},X=class extends c{constructor(e,t){let o={...ze,...t.props},r=(s,n)=>new w(s,n);super(e,{...t,props:o,monoModuleConstructor:r}),this.registerAdditionalInputs(),this.registerDefaultIOs()}registerAdditionalInputs(){this.registerAudioInput({name:"gain"})}};var Re=20,Oe=2e4,_e={cutoff:Oe,envelopeAmount:0,type:"lowpass",Q:1},Le={cutoff:{kind:"number",min:Re,max:Oe,step:1,label:"Cutoff"},envelopeAmount:{kind:"number",min:-1,max:1,step:.01,label:"Envelope Amount"},type:{kind:"enum",options:["lowpass","highpass","bandpass"],label:"Type"},Q:{kind:"number",min:-100,max:100,step:.1,label:"Q"}},ve=class extends u{scale;amount;constructor(e,t){let o={..._e,...t.props},r=s=>new BiquadFilterNode(s,{type:o.type,frequency:o.cutoff,Q:o.Q});super(e,{...t,props:o,audioNodeConstructor:r}),this.amount=new w(e,{name:"amount",moduleType:"Gain",props:{gain:o.envelopeAmount}}),this.scale=V(e,{name:"scale",moduleType:"Scale",props:{min:Re,max:Oe,current:this.props.cutoff}}),this.amount.plug({audioModule:this.scale,from:"out",to:"in"}),this.scale.audioNode.connect(this.audioNode.frequency),this.registerDefaultIOs(),this.registerInputs()}onSetType(e){this.audioNode.type=e}onSetCutoff(e){this.superInitialized&&(this.scale.props={current:e})}onSetQ(e){this.audioNode.Q.value=e}onSetEnvelopeAmount(e){this.superInitialized&&(this.amount.props={gain:e})}registerInputs(){this.registerAudioInput({name:"cutoff",getAudioNode:()=>this.audioNode.frequency}),this.registerAudioInput({name:"cutoffMod",getAudioNode:()=>this.amount.audioNode}),this.registerAudioInput({name:"Q",getAudioNode:()=>this.audioNode.Q})}},Y=class extends c{constructor(e,t){let o={..._e,...t.props},r=(s,n)=>new ve(s,n);super(e,{...t,props:o,monoModuleConstructor:r}),this.registerInputs(),this.registerDefaultIOs()}registerInputs(){this.registerAudioInput({name:"cutoff"}),this.registerAudioInput({name:"cutoffMod"}),this.registerAudioInput({name:"Q"})}};var Ue={value:{kind:"number",min:-1/0,max:1/0,step:.01,label:"Value"}},At={value:1},J=class extends u{isStated=!1;constructor(e,t){let o={...At,...t.props},r=s=>new ConstantSourceNode(s);super(e,{...t,props:o,audioNodeConstructor:r}),this.registerDefaultIOs("out")}onSetValue(e){this.audioNode.offset.value=e}start(e){this.isStated||(this.isStated=!0,this.audioNode.start(a(e)))}stop(e){this.audioNode.stop(a(e)),this.rePlugAll(()=>{this.audioNode=new ConstantSourceNode(this.context,{offset:this.props.value})}),this.isStated=!1}triggerAttack=(e,t)=>{this.audioNode.offset.setValueAtTime(e.frequency,a(t)),this.start(t)};triggerRelease=()=>{}};var Se=require("@blibliki/utils");var We={attack:.1,decay:.2,sustain:0,release:.3},Qe={attack:{kind:"number",min:1e-4,max:1,step:.01,label:"Attack"},decay:{kind:"number",min:0,max:1,step:.01,label:"Decay"},sustain:{kind:"number",min:0,max:1,step:.01,label:"Sustain"},release:{kind:"number",min:0,max:1,step:.01,label:"Release"}},$e=(0,Se.createScaleNormalized)({min:.001,max:10}),vt=(0,Se.createScaleNormalized)({min:.001,max:5}),xe=class extends u{constructor(e,t){let o={...We,...t.props},r=s=>{let n=new GainNode(s);return n.gain.value=0,n};super(e,{...t,props:o,audioNodeConstructor:r}),this.registerDefaultIOs()}triggerAttack(e,t){super.triggerAttack(e,t);let o=this.scaledAttack(),r=this.scaledDecay(),s=this.props.sustain,n=a(t);this.audioNode.gain.cancelAndHoldAtTime(n),this.audioNode.gain.value===0&&this.audioNode.gain.setValueAtTime(.001,n),this.audioNode.gain.exponentialRampToValueAtTime(1,n+o),s>0?this.audioNode.gain.exponentialRampToValueAtTime(s,n+o+r):this.audioNode.gain.exponentialRampToValueAtTime(.001,n+o+r)}triggerRelease(e,t){if(super.triggerRelease(e,t),this.activeNotes.length>0)return;let o=this.scaledRelease(),r=a(t);this.audioNode.gain.cancelAndHoldAtTime(r);let s=this.audioNode.gain.value;s>=1e-4&&(this.audioNode.gain.setValueAtTime(s,r),this.audioNode.gain.exponentialRampToValueAtTime(1e-4,r+o-1e-4)),this.audioNode.gain.setValueAtTime(0,r+o)}scaledAttack(){return $e(this.props.attack)}scaledDecay(){return vt(this.props.decay)}scaledRelease(){return $e(this.props.release)}},Z=class extends c{constructor(e,t){let o={...We,...t.props},r=(s,n)=>new xe(s,n);super(e,{...t,props:o,monoModuleConstructor:r}),this.registerDefaultIOs()}};var He=require("@blibliki/utils");var je=URL.createObjectURL(new Blob(["(",(()=>{class i extends AudioWorkletProcessor{s0;s1;constructor(){super(),this.s0=0,this.s1=0}static get parameterDescriptors(){return[{name:"cutoff",defaultValue:1e3,minValue:20,maxValue:2e4},{name:"resonance",defaultValue:0,minValue:0,maxValue:4}]}process(t,o,r){let s=t[0],n=o[0],m=r.cutoff,h=r.resonance;for(let I=0;I<s.length;I++){let P=s[I],k=n[I];for(let A=0;A<P.length;A++){let d=P[A],z=m.length>1?m[A]:m[0],ce=Math.max(20,Math.min(2e4,z)),me=Math.log(ce/20)/Math.log(2e4/20),v=Math.pow(.5,(1-me)/.125),Ee=1-Math.pow(.5,((h.length>1?h[A]:h[0])+.125)/.125)*v;this.s0=Ee*this.s0-v*this.s1+v*d,this.s1=Ee*this.s1+v*this.s0,k[A]=this.s1}}return!0}}registerProcessor("filter-processor",i)}).toString(),")()"],{type:"application/javascript"}));var Ke=URL.createObjectURL(new Blob(["(",(()=>{class i extends AudioWorkletProcessor{static get parameterDescriptors(){return[{name:"min",defaultValue:1e-10},{name:"max",defaultValue:1},{name:"current",defaultValue:.5}]}process(t,o,r){let s=t[0],n=o[0],m=r.min,h=r.max,I=r.current;if(!s.length||s[0].length===0){for(let P of n){let k=(r.current.length>1,r.current[0]);P.fill(k)}return!0}for(let P=0;P<s.length;P++){let k=s[P],A=n[P];for(let d=0;d<k.length;d++){let z=k[d],ce=m.length>1?m[d]:m[0],me=h.length>1?h[d]:h[0],v=I.length>1?I[d]:I[0];z<0?A[d]=v*Math.pow(ce/v,-z):A[d]=v*Math.pow(me/v,z)}}return!0}}registerProcessor("scale-processor",i)}).toString(),")()"],{type:"application/javascript"}));async function Xe(i){await i.audioWorklet.addModule(Ke),await i.audioWorklet.addModule(je)}function le(i,e){switch(e){case"ScaleProcessor":return new AudioWorkletNode(i,"scale-processor");case"FilterProcessor":return new AudioWorkletNode(i,"filter-processor");default:(0,He.assertNever)(e)}}var Ye=20,Ne=22050,Je={cutoff:Ne,envelopeAmount:0,resonance:0},Ze={cutoff:{kind:"number",min:Ye,max:Ne,step:1e-4,label:"Cutoff"},envelopeAmount:{kind:"number",min:-1,max:1,step:.01,label:"Envelope Amount"},resonance:{kind:"number",min:0,max:4,step:.01,label:"resonance"}},be=class extends u{scale;amount;constructor(e,t){let o={...Je,...t.props},r=s=>le(s,"FilterProcessor");super(e,{...t,props:o,audioNodeConstructor:r}),this.amount=new w(e,{name:"amount",moduleType:"Gain",props:{gain:o.envelopeAmount}}),this.scale=V(e,{name:"scale",moduleType:"Scale",props:{min:Ye,max:Ne,current:this.props.cutoff}}),this.amount.plug({audioModule:this.scale,from:"out",to:"in"}),this.scale.audioNode.connect(this.cutoff),this.registerDefaultIOs(),this.registerInputs()}get cutoff(){return this.audioNode.parameters.get("cutoff")}get resonance(){return this.audioNode.parameters.get("resonance")}onSetCutoff(e){this.superInitialized&&(this.scale.props={current:e})}onSetResonance(e){this.resonance.value=e}onSetEnvelopeAmount(e){this.superInitialized&&(this.amount.props={gain:e})}registerInputs(){this.registerAudioInput({name:"cutoff",getAudioNode:()=>this.scale.audioNode}),this.registerAudioInput({name:"cutoffMod",getAudioNode:()=>this.amount.audioNode}),this.registerAudioInput({name:"Q",getAudioNode:()=>this.resonance})}},ee=class extends c{constructor(e,t){let o={...Je,...t.props},r=(s,n)=>new be(s,n);super(e,{...t,props:o,monoModuleConstructor:r}),this.registerInputs(),this.registerDefaultIOs()}registerInputs(){this.registerAudioInput({name:"cutoff"}),this.registerAudioInput({name:"cutoffMod"}),this.registerAudioInput({name:"Q"})}};var et={fftSize:{kind:"enum",options:[32,64,128,256,512,1024,2048,4096,8192,16384,32768],label:"FFT size"}},xt={fftSize:512},te=class extends u{_buffer;constructor(e,t){let o={...xt,...t.props},r=s=>new AnalyserNode(s);super(e,{...t,props:o,audioNodeConstructor:r}),this.registerDefaultIOs("in")}onSetFftSize(e){this._buffer=new Float32Array(e)}get buffer(){return this._buffer?this._buffer:(this._buffer=new Float32Array(this.props.fftSize),this._buffer)}getValue(){return this.getValues()[0]}getValues(){return this.audioNode.getFloatTimeDomainData(this.buffer),this.buffer}};var St={},tt={},oe=class extends u{constructor(e,t){let o={...St,...t.props},r=s=>s.destination;super(e,{...t,audioNodeConstructor:r,props:o}),this.registerDefaultIOs("in")}};var ot={selectedId:{kind:"string",label:"Midi device ID"}},bt={selectedId:void 0},ie=class extends u{midiOutput;_forwardMidiEvent;constructor(e,t){let o={...bt,...t.props};super(e,{...t,props:o}),this.addEventListener(this.props.selectedId),this.registerOutputs()}onSetSelectedId(e){this.superInitialized&&(this.removeEventListener(),this.addEventListener(e))}get forwardMidiEvent(){return this._forwardMidiEvent?this._forwardMidiEvent:(this._forwardMidiEvent=e=>{this.midiOutput.onMidiEvent(e)},this._forwardMidiEvent)}addEventListener(e){if(!e)return;this.engine.findMidiDevice(e)?.addEventListener(this.forwardMidiEvent)}removeEventListener(){if(!this.props.selectedId)return;this.engine.findMidiDevice(this.props.selectedId)?.removeEventListener(this.forwardMidiEvent)}registerOutputs(){this.midiOutput=this.registerMidiOutput({name:"midi out"})}};var it=require("@blibliki/utils");var rt=-18,se=(r=>(r.sine="sine",r.triangle="triangle",r.square="square",r.sawtooth="sawtooth",r))(se||{}),st={wave:{kind:"enum",options:Object.values(se),label:"Waveform"},frequency:{kind:"number",min:0,max:25e3,step:1,label:"Frequency"},fine:{kind:"number",min:-1,max:1,step:.01,label:"Fine"},coarse:{kind:"number",min:-12,max:12,step:1,label:"Coarse"},octave:{kind:"number",min:-4,max:4,step:1,label:"Octave"},lowGain:{kind:"boolean",label:`Use ${rt}db Gain`}},nt={wave:"sine",frequency:440,fine:0,coarse:0,octave:0,lowGain:!1},Ce=class extends u{isStated=!1;lowOutputGain;detuneGain;constructor(e,t){let o={...nt,...t.props},r=s=>new OscillatorNode(s);super(e,{...t,props:o,audioNodeConstructor:r}),this.lowOutputGain=new GainNode(this.context,{gain:(0,it.dbToGain)(rt)}),this.applyOutputGain(),this.initializeGainDetune(),this.registerInputs(),this.registerOutputs()}onAfterSetWave(e){this.audioNode.type=e}onAfterSetFrequency(){this.updateFrequency()}onAfterSetFine(){this.updateFrequency()}onAfterSetCoarse(){this.updateFrequency()}onAfterSetOctave(){this.updateFrequency()}onAfterSetLowGain(){this.superInitialized&&this.rePlugAll()}start(e){this.isStated||(this.isStated=!0,this.audioNode.start(a(e)))}stop(e){this.audioNode.stop(a(e)),this.rePlugAll(()=>{this.audioNode=new OscillatorNode(this.context,{type:this.props.wave,frequency:this.finalFrequency}),this.applyOutputGain(),this.detuneGain.connect(this.audioNode.detune)}),this.isStated=!1}triggerAttack=(e,t)=>{super.triggerAttack(e,t),this.props={frequency:e.frequency},this.updateFrequency(t),this.start(t)};triggerRelease(e,t){super.triggerRelease(e,t);let o=this.activeNotes.length?this.activeNotes[this.activeNotes.length-1]:null;o&&(this.props={frequency:o.frequency},this.updateFrequency(t))}get finalFrequency(){let{frequency:e,coarse:t,octave:o,fine:r}=this.props;return this.superInitialized?e*Math.pow(2,t/12+o+r/12):void 0}updateFrequency(e){this.finalFrequency!==void 0&&(e?this.audioNode.frequency.setValueAtTime(this.finalFrequency,a(e)):this.audioNode.frequency.value=this.finalFrequency)}applyOutputGain(){this.audioNode.connect(this.lowOutputGain)}initializeGainDetune(){this.detuneGain=new GainNode(this.context,{gain:100}),this.detuneGain.connect(this.audioNode.detune)}registerInputs(){this.registerAudioInput({name:"detune",getAudioNode:()=>this.detuneGain})}registerOutputs(){this.registerAudioOutput({name:"out",getAudioNode:()=>this.props.lowGain?this.lowOutputGain:this.audioNode})}},re=class extends c{constructor(e,t){let o={...nt,...t.props},r=(s,n)=>new Ce(s,n);super(e,{...t,props:o,monoModuleConstructor:r}),this.registerInputs(),this.registerDefaultIOs("out")}start(e){this.audioModules.forEach(t=>{t.start(e)})}stop(e){this.audioModules.forEach(t=>{t.stop(e)})}registerInputs(){this.registerAudioInput({name:"detune"})}};var ut={min:{kind:"number",min:-1/0,max:1/0,step:.01,label:"Min"},max:{kind:"number",min:-1/0,max:1/0,step:.01,label:"Max"},current:{kind:"number",min:-1/0,max:1/0,step:.01,label:"Current"}},Nt={min:0,max:1,current:.5},ne=class extends u{constructor(e,t){let o={...Nt,...t.props},r=s=>le(s,"ScaleProcessor");super(e,{...t,props:o,audioNodeConstructor:r}),this.registerDefaultIOs()}get current(){return this.audioNode.parameters.get("current")}get min(){return this.audioNode.parameters.get("min")}get max(){return this.audioNode.parameters.get("max")}onSetMin(e){this.min.value=e}onSetMax(e){this.max.value=e}onSetCurrent(e){this.current.value=e}};var pt={steps:{kind:"number",min:1,max:16,step:1,label:"Steps"},bars:{kind:"number",min:1,max:16,step:1,label:"Steps"}},Ct={sequences:[],steps:16,bars:1},ue=class extends u{midiOutput;constructor(e,t){let o={...Ct,...t.props};super(e,{...t,props:o})}};var dt={activeNotes:{kind:"array",label:"Active notes"}},Et={activeNotes:[]},pe=class extends u{midiOutput;constructor(e,t){let o={...Et,...t.props};super(e,{...t,props:o}),this.registerInputs(),this.registerOutputs()}sendMidi(e){this.midiOutput.onMidiEvent(e)}triggerAttack=(e,t)=>{this.props={activeNotes:[...this.props.activeNotes,e.fullName]},this.triggerPropsUpdate(),this.sendMidi(f.fromNote(e,!0,t))};triggerRelease=(e,t)=>{this.props={activeNotes:this.props.activeNotes.filter(o=>o!==e.fullName)},this.triggerPropsUpdate(),this.sendMidi(f.fromNote(e,!1,t))};registerInputs(){this.registerMidiInput({name:"midi in",onMidiEvent:this.onMidiEvent})}registerOutputs(){this.midiOutput=this.registerMidiOutput({name:"midi out"})}};var G=(d=>(d.Master="Master",d.Oscillator="Oscillator",d.Gain="Gain",d.MidiSelector="MidiSelector",d.Envelope="Envelope",d.Filter="Filter",d.BiquadFilter="BiquadFilter",d.Scale="Scale",d.Inspector="Inspector",d.Constant="Constant",d.VirtualMidi="VirtualMidi",d.StepSequencer="StepSequencer",d.VoiceScheduler="VoiceScheduler",d))(G||{}),lt={Oscillator:st,Gain:Ve,Master:tt,MidiSelector:ot,Envelope:Qe,Filter:Ze,BiquadFilter:Le,Scale:ut,Inspector:et,Constant:Ue,VirtualMidi:dt,StepSequencer:pt,VoiceScheduler:Be};function V(i,e){switch(e.moduleType){case"Oscillator":return new re(i,e);case"Gain":return new X(i,e);case"Master":return new oe(i,e);case"MidiSelector":return new ie(i,e);case"Envelope":return new Z(i,e);case"Filter":return new ee(i,e);case"BiquadFilter":return new Y(i,e);case"Scale":return new ne(i,e);case"Inspector":return new te(i,e);case"Constant":return new J(i,e);case"VirtualMidi":return new pe(i,e);case"StepSequencer":return new ue(i,e);case"VoiceScheduler":return new H(i,e);default:(0,at.assertNever)(e)}}var M=class i{static _engines=new Map;static _currentId;propsUpdateCallbacks=[];id;context;isInitialized=!1;routes;transport;modules;midiDeviceManager;static getById(e){let t=i._engines.get(e);return(0,F.assertDefined)(t),t}static get current(){return(0,F.assertDefined)(this._currentId),this.getById(this._currentId)}constructor(e){this.id=(0,F.uuidv4)(),this.context=e,this.transport=new C({onStart:this.onStart,onStop:this.onStop}),this.routes=new j(this),this.modules=new Map,this.midiDeviceManager=new B,i._engines.set(this.id,this),i._currentId=this.id}get state(){return this.transport.state}async initialize(){this.isInitialized||(await Xe(this.context),await this.midiDeviceManager.initialize(),this.isInitialized=!0)}addModule(e){let t=V(this.id,e);return this.modules.set(t.id,t),t.serialize()}updateModule(e){let t=this.findModule(e.id);if(t.moduleType!==e.moduleType)throw Error(`The module id ${e.id} isn't moduleType ${e.moduleType}`);let o=(0,F.pick)(e.changes,["name","props"]);return Object.assign(t,o),t instanceof c&&e.changes.voices!==void 0&&(t.voices=e.changes.voices),t.serialize()}removeModule(e){this.modules.delete(e)}addRoute(e){return this.routes.addRoute(e)}removeRoute(e){this.routes.removeRoute(e)}validRoute(e){let{source:t,destination:o}=e,r=this.findIO(t.moduleId,t.ioName,"output"),s=this.findIO(o.moduleId,o.ioName,"input");return r.isMidi()&&s.isMidi()||r.isAudio()&&s.isAudio()}async start(e={}){await this.resume(),this.transport.start(e)}stop(e={}){this.transport.stop(e)}pause(e={}){this.transport.pause(e)}get bpm(){return this.transport.bpm}set bpm(e){this.transport.bpm=e}get timeSignature(){return this.transport.timeSignature}set timeSignature(e){this.transport.timeSignature=e}get playhead(){return this.transport.playhead}async resume(){await this.context.resume()}dispose(){this.stop(),this.routes.clear(),this.modules.forEach(e=>{e.dispose()}),this.modules.clear(),i._engines.delete(this.id),i._currentId=i._engines.keys().next().value}findModule(e){let t=this.modules.get(e);if(!t)throw Error(`The module with id ${e} is not exists`);return t}findIO(e,t,o){return this.findModule(e)[`${o}s`].findByName(t)}findMidiDevice(e){return this.midiDeviceManager.find(e)}onPropsUpdate(e){this.propsUpdateCallbacks.push(e)}_triggerPropsUpdate(e){this.propsUpdateCallbacks.forEach(t=>{t(e)})}triggerVirtualMidi(e,t,o){let r=this.findModule(e);if(r.moduleType!=="VirtualMidi")throw Error("This is not a virtual mid");r.sendMidi(f.fromNote(t,o==="noteOn"))}onStart=e=>{this.modules.forEach(t=>{t.start(e)})};onStop=e=>{this.modules.forEach(t=>{t.stop(e)})}};
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|