| 45 | import type {SoundFont2} from "soundfont2" |
| 46 | |
| 47 | export class EngineWorklet extends AudioWorkletNode implements Engine { |
| 48 | static ID: int = 0 | 0 |
| 49 | |
| 50 | readonly id = EngineWorklet.ID++ |
| 51 | |
| 52 | readonly #terminator: Terminator = new Terminator() |
| 53 | |
| 54 | readonly #project: Project |
| 55 | readonly #playbackTimestamp: DefaultObservableValue<ppqn> = new DefaultObservableValue(0.0) |
| 56 | readonly #position: DefaultObservableValue<ppqn> = new DefaultObservableValue(0.0) |
| 57 | readonly #bpm: DefaultObservableValue<bpm> = new DefaultObservableValue(120.0) |
| 58 | readonly #isPlaying: DefaultObservableValue<boolean> = new DefaultObservableValue(false) |
| 59 | readonly #isRecording: DefaultObservableValue<boolean> = new DefaultObservableValue(false) |
| 60 | readonly #isCountingIn: DefaultObservableValue<boolean> = new DefaultObservableValue(false) |
| 61 | readonly #countInBeatsRemaining: DefaultObservableValue<int> = new DefaultObservableValue(0) |
| 62 | readonly #preferences: PreferencesHost<EngineSettings> |
| 63 | readonly #markerState: DefaultObservableValue<Nullable<[UUID.Bytes, int]>> = |
| 64 | new DefaultObservableValue<Nullable<[UUID.Bytes, int]>>(null) |
| 65 | readonly #cpuLoad: DefaultObservableValue<number> = new DefaultObservableValue(0) |
| 66 | readonly #controlFlags: Int32Array<SharedArrayBuffer> |
| 67 | readonly #notifyClipNotification: Notifier<ClipNotification> |
| 68 | readonly #notifyNoteSignals: Notifier<NoteSignal> |
| 69 | readonly #playingClips: Array<UUID.Bytes> |
| 70 | readonly #deviceMessageListeners: SetMultimap<string, Procedure<string>> = new SetMultimap() |
| 71 | readonly #commands: EngineCommands |
| 72 | readonly #isReady: Promise<void> |
| 73 | |
| 74 | #perfBuffer: Float32Array = new Float32Array(0) |
| 75 | #perfIndex: int = 0 |
| 76 | #lastPerfReadIndex: int = 0 |
| 77 | #consecutiveOverloadCount: int = 0 |
| 78 | #lastCpuLoadUpdate: number = 0 |
| 79 | #maxMsSinceLastUpdate: number = 0 |
| 80 | #monitoringRouter: Nullable<MonitoringRouter> = null |
| 81 | |
| 82 | constructor(context: BaseAudioContext, |
| 83 | project: Project, |
| 84 | exportConfiguration?: ExportStemsConfiguration, |
| 85 | options?: ProcessorOptions) { |
| 86 | const numberOfChannels = ExportStemsConfiguration.countStems(Option.wrap(exportConfiguration)) * 2 |
| 87 | const budgetMs = (RenderQuantum / context.sampleRate) * 1000 |
| 88 | const reader = SyncStream.reader<EngineState>(EngineStateSchema(), state => { |
| 89 | this.#isPlaying.setValue(state.isPlaying) |
| 90 | this.#isRecording.setValue(state.isRecording) |
| 91 | this.#isCountingIn.setValue(state.isCountingIn) |
| 92 | this.#countInBeatsRemaining.setValue(state.countInBeatsRemaining) |
| 93 | this.#playbackTimestamp.setValue(state.playbackTimestamp) |
| 94 | this.#bpm.setValue(state.bpm) |
| 95 | this.#perfBuffer = state.perfBuffer |
| 96 | this.#perfIndex = state.perfIndex |
| 97 | this.#updateCpuLoad(budgetMs, project) |
| 98 | this.#position.setValue(state.position) // This must be the last to handle the state values before |
| 99 | }) |
| 100 | |
| 101 | const controlFlagsSAB = new SharedArrayBuffer(4) // 4 bytes minimum |
| 102 | |
| 103 | super(context, "engine-processor", { |
| 104 | numberOfInputs: 1, |
nothing calls this directly
no outgoing calls
no test coverage detected