@blibliki/engine 0.3.2 → 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.d.cts CHANGED
@@ -3,6 +3,8 @@ import { Optional, EmptyObject } from '@blibliki/utils';
3
3
 
4
4
  type BarsBeatsSixteenths = `${number}:${number}:${number}`;
5
5
  type TTime = number | BarsBeatsSixteenths | Time;
6
+ declare const t: (value?: TTime) => Time;
7
+ declare const nt: (value?: TTime) => number;
6
8
  declare class Time {
7
9
  private value;
8
10
  private _notation?;
@@ -741,7 +743,7 @@ declare class Engine {
741
743
  start(props?: {
742
744
  offset?: TTime;
743
745
  actionAt?: TTime;
744
- }): void;
746
+ }): Promise<void>;
745
747
  stop(props?: {
746
748
  actionAt?: TTime;
747
749
  }): void;
@@ -750,6 +752,9 @@ declare class Engine {
750
752
  }): void;
751
753
  get bpm(): number;
752
754
  set bpm(value: number);
755
+ get timeSignature(): [number, number];
756
+ set timeSignature(value: [number, number]);
757
+ get playhead(): Time;
753
758
  resume(): Promise<void>;
754
759
  dispose(): void;
755
760
  findModule(id: string): ModuleTypeToModuleMapping[keyof ModuleTypeToModuleMapping];
@@ -762,4 +767,4 @@ declare class Engine {
762
767
  private onStop;
763
768
  }
764
769
 
765
- export { type ArrayProp, type BooleanProp, Engine, type EnumProp, type ICreateModule, type ICreateRoute, type IGain, type IIOSerialize, type IMaster, type IMidiDevice, type IModule, type IModuleSerialize, type INote, type IOscillator, type IPolyModuleSerialize, type IRoute, type ISequence, type IStepSequencer, type IStepSequencerProps, type IUpdateModule, MidiDevice, MidiPortState, type ModuleParams, ModuleType, type ModuleTypeToPropsMapping, Note, type NumberProp, OscillatorWave, type PropDefinition, type PropSchema, type StringProp, TransportState, moduleSchemas };
770
+ export { type ArrayProp, type BooleanProp, Engine, type EnumProp, type ICreateModule, type ICreateRoute, type IGain, type IIOSerialize, type IMaster, type IMidiDevice, type IModule, type IModuleSerialize, type INote, type IOscillator, type IPolyModuleSerialize, type IRoute, type ISequence, type IStepSequencer, type IStepSequencerProps, type IUpdateModule, MidiDevice, MidiPortState, type ModuleParams, ModuleType, type ModuleTypeToPropsMapping, Note, type NumberProp, OscillatorWave, type PropDefinition, type PropSchema, type StringProp, TransportState, moduleSchemas, nt, t };
package/dist/index.d.ts CHANGED
@@ -3,6 +3,8 @@ import { Optional, EmptyObject } from '@blibliki/utils';
3
3
 
4
4
  type BarsBeatsSixteenths = `${number}:${number}:${number}`;
5
5
  type TTime = number | BarsBeatsSixteenths | Time;
6
+ declare const t: (value?: TTime) => Time;
7
+ declare const nt: (value?: TTime) => number;
6
8
  declare class Time {
7
9
  private value;
8
10
  private _notation?;
@@ -741,7 +743,7 @@ declare class Engine {
741
743
  start(props?: {
742
744
  offset?: TTime;
743
745
  actionAt?: TTime;
744
- }): void;
746
+ }): Promise<void>;
745
747
  stop(props?: {
746
748
  actionAt?: TTime;
747
749
  }): void;
@@ -750,6 +752,9 @@ declare class Engine {
750
752
  }): void;
751
753
  get bpm(): number;
752
754
  set bpm(value: number);
755
+ get timeSignature(): [number, number];
756
+ set timeSignature(value: [number, number]);
757
+ get playhead(): Time;
753
758
  resume(): Promise<void>;
754
759
  dispose(): void;
755
760
  findModule(id: string): ModuleTypeToModuleMapping[keyof ModuleTypeToModuleMapping];
@@ -762,4 +767,4 @@ declare class Engine {
762
767
  private onStop;
763
768
  }
764
769
 
765
- export { type ArrayProp, type BooleanProp, Engine, type EnumProp, type ICreateModule, type ICreateRoute, type IGain, type IIOSerialize, type IMaster, type IMidiDevice, type IModule, type IModuleSerialize, type INote, type IOscillator, type IPolyModuleSerialize, type IRoute, type ISequence, type IStepSequencer, type IStepSequencerProps, type IUpdateModule, MidiDevice, MidiPortState, type ModuleParams, ModuleType, type ModuleTypeToPropsMapping, Note, type NumberProp, OscillatorWave, type PropDefinition, type PropSchema, type StringProp, TransportState, moduleSchemas };
770
+ export { type ArrayProp, type BooleanProp, Engine, type EnumProp, type ICreateModule, type ICreateRoute, type IGain, type IIOSerialize, type IMaster, type IMidiDevice, type IModule, type IModuleSerialize, type INote, type IOscillator, type IPolyModuleSerialize, type IRoute, type ISequence, type IStepSequencer, type IStepSequencerProps, type IUpdateModule, MidiDevice, MidiPortState, type ModuleParams, ModuleType, type ModuleTypeToPropsMapping, Note, type NumberProp, OscillatorWave, type PropDefinition, type PropSchema, type StringProp, TransportState, moduleSchemas, nt, t };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{assertDefined as ot,pick as bt,uuidv4 as Nt}from"@blibliki/utils";import{upperFirst as be,uuidv4 as at}from"@blibliki/utils";import{assertNever as nt}from"@blibliki/utils";import{deterministicId as it,uuidv4 as rt}from"@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??rt(),this.engineId=e,this.name=i,this.moduleType=s,this.voices=n||1,this._props={},this.props=h,this.inputs=new x(this),this.outputs=new S(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=it(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 T.getById(this.engineId)}get context(){return this.engine.context}};import{deterministicId as st}from"@blibliki/utils";var ce=class{id;ioType;name;module;connections;constructor(e,t){this.module=e,this.name=t.name,this.ioType=t.ioType,this.id=st(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}}},M=class extends ce{plug(e,t){super.plug(e,t)}unPlug(e,t){super.unPlug(e,t)}};var g=class extends M{plug(e,t=!0){super.plug(e,t),!(!t&&e instanceof b)&&ie(this,e,!0)}unPlug(e,t=!0){super.unPlug(e,t),!(!t&&e instanceof b)&&ie(this,e,!1)}findIOByVoice(e){return this.module.findVoice(e).inputs.findByName(this.name)}},b=class extends M{plug(e,t=!0){super.plug(e,t),!(!t&&e instanceof g)&&ie(this,e,!0)}unPlug(e,t=!0){super.unPlug(e,t),!(!t&&e instanceof g)&&ie(this,e,!1)}findIOByVoice(e){return this.module.findVoice(e).outputs.findByName(this.name)}};function ie(r,e,t){if(e instanceof g||e instanceof b){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 G=class extends M{getAudioNode;constructor(e,t){super(e,t),this.getAudioNode=t.getAudioNode}},V=class extends M{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 F=class extends M{onMidiEvent;constructor(e,t){super(e,t),this.onMidiEvent=t.onMidiEvent}},z=class extends M{onMidiEvent=e=>{this.midiConnections.forEach(t=>{t.onMidiEvent(e)})};get midiConnections(){return this.connections.filter(e=>e instanceof F)}};var R=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 G(this.module,e);break;case"audioOutput":if(this.module instanceof l)throw Error("Not compatible");t=new V(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 b(this.module,e);break;case"midiInput":t=new F(this.module,e);break;case"midiOutput":t=new z(this.module,e);break;default:nt(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`)}},x=class extends R{constructor(e){super("Input",e)}},S=class extends R{constructor(e){super("Output",e)}};import{Message as Se}from"webmidi";var ut=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]]),me=ut;var he=["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"],pt=2,p=class r{static _notes;name;octave;velocity=1;duration;static fromFrequency(e){let t;for(let[o,i]of me)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=he[e.data[1]%12],o=Math.floor(e.data[1]/12)-2;return new r(`${t}${o}`)}static notes(e=3){return he.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 me.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+pt)*12+this.noteIndex}get noteIndex(){return he.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)}};import{isNumber as xe}from"@blibliki/utils";import{Scheduler as dt}from"@ircam/sc-scheduling";var _=class{transport;internalScheduler;constructor(e){this.transport=e,this.internalScheduler=new dt(y,{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 re=(o=>(o.playing="playing",o.stopped="stopped",o.paused="paused",o))(re||{}),N=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=y()}){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=y()}){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=y()}){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(y()).subtrack(this.startTime)}validateFutureTime(e){if(c(e).isBefore(y()))throw Error("Past time not allowed")}};function y(){return T.current.context.currentTime}function Oe(r){let e=performance.now()/1e3-y();return r/1e3-e}var c=r=>(r??=y(),r instanceof C?r:new C(r)),a=r=>(r??=y(),typeof r=="number"?r:c(r).toNumber()),C=class r{value;_notation;_number;constructor(e){this.value=e instanceof r?e.value:e,xe(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(xe(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 T.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 Se(i.midiData(t)),o)}static fromCC(e,t,o){return new r(new Se(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??at(),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 x(this),this.outputs=new S(this),this.superInitialized=!0}get props(){return this._props}set props(e){Object.keys(e).forEach(t=>{let o=`onSet${be(t)}`;this[o]?.(e[t])}),this._props={...this._props,...e},Object.keys(e).forEach(t=>{let o=`onAfterSet${be(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 T.getById(this.engineId)}get context(){return this.engine.context}};import{uuidv4 as lt}from"@blibliki/utils";var L=class{engine;routes;constructor(e){this.engine=e,this.routes=new Map}addRoute(e){let t=e.id??lt(),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}}};import{Output as Ne,WebMidi as ne}from"webmidi";var se=(t=>(t.connected="connected",t.disconnected="disconnected",t))(se||{}),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,Oe(e.timestamp));switch(t.type){case"noteon":case"noteoff":this.eventListerCallbacks.forEach(o=>{o(t)})}}};var ct={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")},mt=()=>({id:"computer_keyboard",name:"Computer Keyboard",state:"connected"}),k=class{id;name;state;eventListerCallbacks=[];constructor(){let{id:e,name:t,state:o}=mt();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 ct[e.key]}};var D=class{devices=new Map;initialized=!1;listeners=[];constructor(){let e=new k;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 ne.enable(),ne.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(){ne.addListener("connected",e=>{let t=e.port;if(t instanceof Ne||this.devices.has(t.id))return;let o=new O(t);this.devices.set(o.id,o),this.listeners.forEach(i=>{i(o)})}),ne.addListener("disconnected",e=>{let t=e.port;if(t instanceof Ne)return;let o=this.devices.get(t.id);o&&(o instanceof k||(o.disconnect(),this.devices.delete(o.id),this.listeners.forEach(i=>{i(o)})))})}};import{assertNever as xt}from"@blibliki/utils";var Ce={},Ee={},Me=class extends u{activeNote=null;triggeredAt=c(0);constructor(e,t){let o={...Ee,...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")}}},U=class extends l{midiOutput;constructor(e,t){let o={...Ee,...t.props},i=(s,n)=>new Me(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 we={gain:{kind:"number",min:0,max:1/0,step:.01,label:"Gain"}},Fe={gain:1},E=class extends u{constructor(e,t){let o={...Fe,...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})}},$=class extends l{constructor(e,t){let o={...Fe,...t.props},i=(s,n)=>new E(s,n);super(e,{...t,props:o,monoModuleConstructor:i}),this.registerAdditionalInputs(),this.registerDefaultIOs()}registerAdditionalInputs(){this.registerAudioInput({name:"gain"})}};var ke=20,Te=2e4,De={cutoff:Te,envelopeAmount:0,type:"lowpass",Q:1},qe={cutoff:{kind:"number",min:ke,max:Te,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"}},ye=class extends u{scale;amount;constructor(e,t){let o={...De,...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 E(e,{name:"amount",moduleType:"Gain",props:{gain:o.envelopeAmount}}),this.scale=q(e,{name:"scale",moduleType:"Scale",props:{min:ke,max:Te,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})}},W=class extends l{constructor(e,t){let o={...De,...t.props},i=(s,n)=>new ye(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 Be={value:{kind:"number",min:-1/0,max:1/0,step:.01,label:"Value"}},ht={value:1},j=class extends u{isStated=!1;constructor(e,t){let o={...ht,...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=()=>{}};import{createScaleNormalized as Ve}from"@blibliki/utils";var ze={attack:.1,decay:.2,sustain:0,release:.3},Re={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"}},Ge=Ve({min:.001,max:10}),ft=Ve({min:.001,max:5}),Ie=class extends u{constructor(e,t){let o={...ze,...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 Ge(this.props.attack)}scaledDecay(){return ft(this.props.decay)}scaledRelease(){return Ge(this.props.release)}},K=class extends l{constructor(e,t){let o={...ze,...t.props},i=(s,n)=>new Ie(s,n);super(e,{...t,props:o,monoModuleConstructor:i}),this.registerDefaultIOs()}};import{assertNever as Mt}from"@blibliki/utils";var _e=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],w=n[I];for(let A=0;A<P.length;A++){let d=P[A],B=m.length>1?m[A]:m[0],de=Math.max(20,Math.min(2e4,B)),ae=Math.log(de/20)/Math.log(2e4/20),v=Math.pow(.5,(1-ae)/.125),ve=1-Math.pow(.5,((h.length>1?h[A]:h[0])+.125)/.125)*v;this.s0=ve*this.s0-v*this.s1+v*d,this.s1=ve*this.s1+v*this.s0,w[A]=this.s1}}return!0}}registerProcessor("filter-processor",r)}).toString(),")()"],{type:"application/javascript"}));var Le=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 w=(i.current.length>1,i.current[0]);P.fill(w)}return!0}for(let P=0;P<s.length;P++){let w=s[P],A=n[P];for(let d=0;d<w.length;d++){let B=w[d],de=m.length>1?m[d]:m[0],ae=h.length>1?h[d]:h[0],v=I.length>1?I[d]:I[0];B<0?A[d]=v*Math.pow(de/v,-B):A[d]=v*Math.pow(ae/v,B)}}return!0}}registerProcessor("scale-processor",r)}).toString(),")()"],{type:"application/javascript"}));async function Ue(r){await r.audioWorklet.addModule(Le),await r.audioWorklet.addModule(_e)}function ue(r,e){switch(e){case"ScaleProcessor":return new AudioWorkletNode(r,"scale-processor");case"FilterProcessor":return new AudioWorkletNode(r,"filter-processor");default:Mt(e)}}var $e=20,Pe=22050,We={cutoff:Pe,envelopeAmount:0,resonance:0},Qe={cutoff:{kind:"number",min:$e,max:Pe,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"}},ge=class extends u{scale;amount;constructor(e,t){let o={...We,...t.props},i=s=>ue(s,"FilterProcessor");super(e,{...t,props:o,audioNodeConstructor:i}),this.amount=new E(e,{name:"amount",moduleType:"Gain",props:{gain:o.envelopeAmount}}),this.scale=q(e,{name:"scale",moduleType:"Scale",props:{min:$e,max:Pe,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})}},H=class extends l{constructor(e,t){let o={...We,...t.props},i=(s,n)=>new ge(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 je={fftSize:{kind:"enum",options:[32,64,128,256,512,1024,2048,4096,8192,16384,32768],label:"FFT size"}},Tt={fftSize:512},X=class extends u{_buffer;constructor(e,t){let o={...Tt,...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 It={},Ke={},Y=class extends u{constructor(e,t){let o={...It,...t.props},i=s=>s.destination;super(e,{...t,audioNodeConstructor:i,props:o}),this.registerDefaultIOs("in")}};var He={selectedId:{kind:"string",label:"Midi device ID"}},gt={selectedId:void 0},J=class extends u{midiOutput;_forwardMidiEvent;constructor(e,t){let o={...gt,...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"})}};import{dbToGain as Pt}from"@blibliki/utils";var Xe=-18,pe=(i=>(i.sine="sine",i.triangle="triangle",i.square="square",i.sawtooth="sawtooth",i))(pe||{}),Ye={wave:{kind:"enum",options:Object.values(pe),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 ${Xe}db Gain`}},Je={wave:"sine",frequency:440,fine:0,coarse:0,octave:0,lowGain:!1},Ae=class extends u{isStated=!1;lowOutputGain;detuneGain;constructor(e,t){let o={...Je,...t.props},i=s=>new OscillatorNode(s);super(e,{...t,props:o,audioNodeConstructor:i}),this.lowOutputGain=new GainNode(this.context,{gain:Pt(Xe)}),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})}},Z=class extends l{constructor(e,t){let o={...Je,...t.props},i=(s,n)=>new Ae(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 Ze={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"}},At={min:0,max:1,current:.5},ee=class extends u{constructor(e,t){let o={...At,...t.props},i=s=>ue(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 et={steps:{kind:"number",min:1,max:16,step:1,label:"Steps"},bars:{kind:"number",min:1,max:16,step:1,label:"Steps"}},vt={sequences:[],steps:16,bars:1},te=class extends u{midiOutput;constructor(e,t){let o={...vt,...t.props};super(e,{...t,props:o})}};var tt={activeNotes:{kind:"array",label:"Active notes"}},Ot={activeNotes:[]},oe=class extends u{midiOutput;constructor(e,t){let o={...Ot,...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 Q=(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))(Q||{}),St={Oscillator:Ye,Gain:we,Master:Ke,MidiSelector:He,Envelope:Re,Filter:Qe,BiquadFilter:qe,Scale:Ze,Inspector:je,Constant:Be,VirtualMidi:tt,StepSequencer:et,VoiceScheduler:Ce};function q(r,e){switch(e.moduleType){case"Oscillator":return new Z(r,e);case"Gain":return new $(r,e);case"Master":return new Y(r,e);case"MidiSelector":return new J(r,e);case"Envelope":return new K(r,e);case"Filter":return new H(r,e);case"BiquadFilter":return new W(r,e);case"Scale":return new ee(r,e);case"Inspector":return new X(r,e);case"Constant":return new j(r,e);case"VirtualMidi":return new oe(r,e);case"StepSequencer":return new te(r,e);case"VoiceScheduler":return new U(r,e);default:xt(e)}}var T=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 ot(t),t}static get current(){return ot(this._currentId),this.getById(this._currentId)}constructor(e){this.id=Nt(),this.context=e,this.transport=new N({onStart:this.onStart,onStop:this.onStop}),this.routes=new L(this),this.modules=new Map,this.midiDeviceManager=new D,r._engines.set(this.id,this),r._currentId=this.id}get state(){return this.transport.state}async initialize(){this.isInitialized||(await Ue(this.context),await this.midiDeviceManager.initialize(),this.isInitialized=!0)}addModule(e){let t=q(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=bt(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)})}};export{T as Engine,O as MidiDevice,se as MidiPortState,Q as ModuleType,p as Note,pe as OscillatorWave,re as TransportState,St as moduleSchemas};
1
+ import{assertDefined as ot,pick as bt,uuidv4 as Nt}from"@blibliki/utils";import{upperFirst as be,uuidv4 as at}from"@blibliki/utils";import{assertNever as nt}from"@blibliki/utils";import{deterministicId as it,uuidv4 as rt}from"@blibliki/utils";var c=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??rt(),this.engineId=e,this.name=i,this.moduleType=s,this.voices=n||1,this._props={},this.props=h,this.inputs=new x(this),this.outputs=new S(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=it(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 T.getById(this.engineId)}get context(){return this.engine.context}};import{deterministicId as st}from"@blibliki/utils";var ce=class{id;ioType;name;module;connections;constructor(e,t){this.module=e,this.name=t.name,this.ioType=t.ioType,this.id=st(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}}},M=class extends ce{plug(e,t){super.plug(e,t)}unPlug(e,t){super.unPlug(e,t)}};var g=class extends M{plug(e,t=!0){super.plug(e,t),!(!t&&e instanceof b)&&ie(this,e,!0)}unPlug(e,t=!0){super.unPlug(e,t),!(!t&&e instanceof b)&&ie(this,e,!1)}findIOByVoice(e){return this.module.findVoice(e).inputs.findByName(this.name)}},b=class extends M{plug(e,t=!0){super.plug(e,t),!(!t&&e instanceof g)&&ie(this,e,!0)}unPlug(e,t=!0){super.unPlug(e,t),!(!t&&e instanceof g)&&ie(this,e,!1)}findIOByVoice(e){return this.module.findVoice(e).outputs.findByName(this.name)}};function ie(r,e,t){if(e instanceof g||e instanceof b){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 G=class extends M{getAudioNode;constructor(e,t){super(e,t),this.getAudioNode=t.getAudioNode}},V=class extends M{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 F=class extends M{onMidiEvent;constructor(e,t){super(e,t),this.onMidiEvent=t.onMidiEvent}},z=class extends M{onMidiEvent=e=>{this.midiConnections.forEach(t=>{t.onMidiEvent(e)})};get midiConnections(){return this.connections.filter(e=>e instanceof F)}};var R=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 G(this.module,e);break;case"audioOutput":if(this.module instanceof c)throw Error("Not compatible");t=new V(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 b(this.module,e);break;case"midiInput":t=new F(this.module,e);break;case"midiOutput":t=new z(this.module,e);break;default:nt(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`)}},x=class extends R{constructor(e){super("Input",e)}},S=class extends R{constructor(e){super("Output",e)}};import{Message as Se}from"webmidi";var ut=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]]),me=ut;var he=["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"],pt=2,p=class r{static _notes;name;octave;velocity=1;duration;static fromFrequency(e){let t;for(let[o,i]of me)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=he[e.data[1]%12],o=Math.floor(e.data[1]/12)-2;return new r(`${t}${o}`)}static notes(e=3){return he.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 me.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+pt)*12+this.noteIndex}get noteIndex(){return he.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)}};import{isNumber as xe}from"@blibliki/utils";import{Scheduler as dt}from"@ircam/sc-scheduling";var _=class{transport;internalScheduler;constructor(e){this.transport=e,this.internalScheduler=new dt(y,{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 re=(o=>(o.playing="playing",o.stopped="stopped",o.paused="paused",o))(re||{}),N=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=y()}){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=y()}){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=y()}){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(y()).subtrack(this.startTime)}validateFutureTime(e){if(l(e).isBefore(y()))throw Error("Past time not allowed")}};function y(){return T.current.context.currentTime}function Oe(r){let e=performance.now()/1e3-y();return r/1e3-e}var l=r=>(r??=y(),r instanceof C?r:new C(r)),a=r=>(r??=y(),typeof r=="number"?r:l(r).toNumber()),C=class r{value;_notation;_number;constructor(e){this.value=e instanceof r?e.value:e,xe(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,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(xe(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 T.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 Se(i.midiData(t)),o)}static fromCC(e,t,o){return new r(new Se(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 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??at(),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 x(this),this.outputs=new S(this),this.superInitialized=!0}get props(){return this._props}set props(e){Object.keys(e).forEach(t=>{let o=`onSet${be(t)}`;this[o]?.(e[t])}),this._props={...this._props,...e},Object.keys(e).forEach(t=>{let o=`onAfterSet${be(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 T.getById(this.engineId)}get context(){return this.engine.context}};import{uuidv4 as lt}from"@blibliki/utils";var L=class{engine;routes;constructor(e){this.engine=e,this.routes=new Map}addRoute(e){let t=e.id??lt(),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}}};import{Output as Ne,WebMidi as ne}from"webmidi";var se=(t=>(t.connected="connected",t.disconnected="disconnected",t))(se||{}),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,Oe(e.timestamp));switch(t.type){case"noteon":case"noteoff":this.eventListerCallbacks.forEach(o=>{o(t)})}}};var ct={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")},mt=()=>({id:"computer_keyboard",name:"Computer Keyboard",state:"connected"}),k=class{id;name;state;eventListerCallbacks=[];constructor(){let{id:e,name:t,state:o}=mt();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 ct[e.key]}};var D=class{devices=new Map;initialized=!1;listeners=[];constructor(){let e=new k;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 ne.enable(),ne.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(){ne.addListener("connected",e=>{let t=e.port;if(t instanceof Ne||this.devices.has(t.id))return;let o=new O(t);this.devices.set(o.id,o),this.listeners.forEach(i=>{i(o)})}),ne.addListener("disconnected",e=>{let t=e.port;if(t instanceof Ne)return;let o=this.devices.get(t.id);o&&(o instanceof k||(o.disconnect(),this.devices.delete(o.id),this.listeners.forEach(i=>{i(o)})))})}};import{assertNever as xt}from"@blibliki/utils";var Ce={},Ee={},Me=class extends u{activeNote=null;triggeredAt=l(0);constructor(e,t){let o={...Ee,...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")}}},U=class extends c{midiOutput;constructor(e,t){let o={...Ee,...t.props},i=(s,n)=>new Me(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 we={gain:{kind:"number",min:0,max:1/0,step:.01,label:"Gain"}},Fe={gain:1},E=class extends u{constructor(e,t){let o={...Fe,...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})}},$=class extends c{constructor(e,t){let o={...Fe,...t.props},i=(s,n)=>new E(s,n);super(e,{...t,props:o,monoModuleConstructor:i}),this.registerAdditionalInputs(),this.registerDefaultIOs()}registerAdditionalInputs(){this.registerAudioInput({name:"gain"})}};var ke=20,Te=2e4,De={cutoff:Te,envelopeAmount:0,type:"lowpass",Q:1},qe={cutoff:{kind:"number",min:ke,max:Te,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"}},ye=class extends u{scale;amount;constructor(e,t){let o={...De,...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 E(e,{name:"amount",moduleType:"Gain",props:{gain:o.envelopeAmount}}),this.scale=q(e,{name:"scale",moduleType:"Scale",props:{min:ke,max:Te,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})}},W=class extends c{constructor(e,t){let o={...De,...t.props},i=(s,n)=>new ye(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 Be={value:{kind:"number",min:-1/0,max:1/0,step:.01,label:"Value"}},ht={value:1},j=class extends u{isStated=!1;constructor(e,t){let o={...ht,...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=()=>{}};import{createScaleNormalized as Ve}from"@blibliki/utils";var ze={attack:.1,decay:.2,sustain:0,release:.3},Re={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"}},Ge=Ve({min:.001,max:10}),ft=Ve({min:.001,max:5}),Ie=class extends u{constructor(e,t){let o={...ze,...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 Ge(this.props.attack)}scaledDecay(){return ft(this.props.decay)}scaledRelease(){return Ge(this.props.release)}},K=class extends c{constructor(e,t){let o={...ze,...t.props},i=(s,n)=>new Ie(s,n);super(e,{...t,props:o,monoModuleConstructor:i}),this.registerDefaultIOs()}};import{assertNever as Mt}from"@blibliki/utils";var _e=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],w=n[I];for(let A=0;A<P.length;A++){let d=P[A],B=m.length>1?m[A]:m[0],de=Math.max(20,Math.min(2e4,B)),ae=Math.log(de/20)/Math.log(2e4/20),v=Math.pow(.5,(1-ae)/.125),ve=1-Math.pow(.5,((h.length>1?h[A]:h[0])+.125)/.125)*v;this.s0=ve*this.s0-v*this.s1+v*d,this.s1=ve*this.s1+v*this.s0,w[A]=this.s1}}return!0}}registerProcessor("filter-processor",r)}).toString(),")()"],{type:"application/javascript"}));var Le=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 w=(i.current.length>1,i.current[0]);P.fill(w)}return!0}for(let P=0;P<s.length;P++){let w=s[P],A=n[P];for(let d=0;d<w.length;d++){let B=w[d],de=m.length>1?m[d]:m[0],ae=h.length>1?h[d]:h[0],v=I.length>1?I[d]:I[0];B<0?A[d]=v*Math.pow(de/v,-B):A[d]=v*Math.pow(ae/v,B)}}return!0}}registerProcessor("scale-processor",r)}).toString(),")()"],{type:"application/javascript"}));async function Ue(r){await r.audioWorklet.addModule(Le),await r.audioWorklet.addModule(_e)}function ue(r,e){switch(e){case"ScaleProcessor":return new AudioWorkletNode(r,"scale-processor");case"FilterProcessor":return new AudioWorkletNode(r,"filter-processor");default:Mt(e)}}var $e=20,Pe=22050,We={cutoff:Pe,envelopeAmount:0,resonance:0},Qe={cutoff:{kind:"number",min:$e,max:Pe,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"}},ge=class extends u{scale;amount;constructor(e,t){let o={...We,...t.props},i=s=>ue(s,"FilterProcessor");super(e,{...t,props:o,audioNodeConstructor:i}),this.amount=new E(e,{name:"amount",moduleType:"Gain",props:{gain:o.envelopeAmount}}),this.scale=q(e,{name:"scale",moduleType:"Scale",props:{min:$e,max:Pe,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})}},H=class extends c{constructor(e,t){let o={...We,...t.props},i=(s,n)=>new ge(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 je={fftSize:{kind:"enum",options:[32,64,128,256,512,1024,2048,4096,8192,16384,32768],label:"FFT size"}},Tt={fftSize:512},X=class extends u{_buffer;constructor(e,t){let o={...Tt,...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 It={},Ke={},Y=class extends u{constructor(e,t){let o={...It,...t.props},i=s=>s.destination;super(e,{...t,audioNodeConstructor:i,props:o}),this.registerDefaultIOs("in")}};var He={selectedId:{kind:"string",label:"Midi device ID"}},gt={selectedId:void 0},J=class extends u{midiOutput;_forwardMidiEvent;constructor(e,t){let o={...gt,...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"})}};import{dbToGain as Pt}from"@blibliki/utils";var Xe=-18,pe=(i=>(i.sine="sine",i.triangle="triangle",i.square="square",i.sawtooth="sawtooth",i))(pe||{}),Ye={wave:{kind:"enum",options:Object.values(pe),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 ${Xe}db Gain`}},Je={wave:"sine",frequency:440,fine:0,coarse:0,octave:0,lowGain:!1},Ae=class extends u{isStated=!1;lowOutputGain;detuneGain;constructor(e,t){let o={...Je,...t.props},i=s=>new OscillatorNode(s);super(e,{...t,props:o,audioNodeConstructor:i}),this.lowOutputGain=new GainNode(this.context,{gain:Pt(Xe)}),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})}},Z=class extends c{constructor(e,t){let o={...Je,...t.props},i=(s,n)=>new Ae(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 Ze={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"}},At={min:0,max:1,current:.5},ee=class extends u{constructor(e,t){let o={...At,...t.props},i=s=>ue(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 et={steps:{kind:"number",min:1,max:16,step:1,label:"Steps"},bars:{kind:"number",min:1,max:16,step:1,label:"Steps"}},vt={sequences:[],steps:16,bars:1},te=class extends u{midiOutput;constructor(e,t){let o={...vt,...t.props};super(e,{...t,props:o})}};var tt={activeNotes:{kind:"array",label:"Active notes"}},Ot={activeNotes:[]},oe=class extends u{midiOutput;constructor(e,t){let o={...Ot,...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 Q=(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))(Q||{}),St={Oscillator:Ye,Gain:we,Master:Ke,MidiSelector:He,Envelope:Re,Filter:Qe,BiquadFilter:qe,Scale:Ze,Inspector:je,Constant:Be,VirtualMidi:tt,StepSequencer:et,VoiceScheduler:Ce};function q(r,e){switch(e.moduleType){case"Oscillator":return new Z(r,e);case"Gain":return new $(r,e);case"Master":return new Y(r,e);case"MidiSelector":return new J(r,e);case"Envelope":return new K(r,e);case"Filter":return new H(r,e);case"BiquadFilter":return new W(r,e);case"Scale":return new ee(r,e);case"Inspector":return new X(r,e);case"Constant":return new j(r,e);case"VirtualMidi":return new oe(r,e);case"StepSequencer":return new te(r,e);case"VoiceScheduler":return new U(r,e);default:xt(e)}}var T=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 ot(t),t}static get current(){return ot(this._currentId),this.getById(this._currentId)}constructor(e){this.id=Nt(),this.context=e,this.transport=new N({onStart:this.onStart,onStop:this.onStop}),this.routes=new L(this),this.modules=new Map,this.midiDeviceManager=new D,r._engines.set(this.id,this),r._currentId=this.id}get state(){return this.transport.state}async initialize(){this.isInitialized||(await Ue(this.context),await this.midiDeviceManager.initialize(),this.isInitialized=!0)}addModule(e){let t=q(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=bt(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,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()}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(),r._engines.delete(this.id),r._currentId=r._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 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)})}};export{T as Engine,O as MidiDevice,se as MidiPortState,Q as ModuleType,p as Note,pe as OscillatorWave,re as TransportState,St as moduleSchemas};
2
2
  //# sourceMappingURL=index.js.map