diff --git a/src/jsAudioWorkletMain/kotlin/WorkletProcessor.kt b/src/jsAudioWorkletMain/kotlin/WorkletProcessor.kt index 838fcf5..cfbeb0a 100644 --- a/src/jsAudioWorkletMain/kotlin/WorkletProcessor.kt +++ b/src/jsAudioWorkletMain/kotlin/WorkletProcessor.kt @@ -12,13 +12,15 @@ const val PI2 = PI * 2 @ExperimentalJsExport @JsExport object WorkletProcessor { - var port: MessagePort? = null + private var port: MessagePort? = null - var counter: Int = 0 - var note = Note.C2 - var offset = 0.0 + private var counter: Int = 0 + private var note = Note.C2 + private var offset = 0.0 - var note_length = 2500 + private var started = false + private var note_length = 2500 + private var harmonics = 3 @JsName("setPort") fun setPort(port: MessagePort) { @@ -36,16 +38,20 @@ object WorkletProcessor { when (parts[0]) { "start" -> { println("Start worklet!") - } + started = true + } "stop" -> { + println("Stop worklet!") + started = false } - "set_note_length" -> { note_length = parts[1].toInt() } - + "harmonics" -> { + harmonics = parts[1].toInt() + } else -> console.error("Don't kow how to handle message", message) } @@ -54,34 +60,37 @@ object WorkletProcessor { @JsName("process") fun process(samples: Int, left: Float64Array, right: Float64Array) { - var tmpCounter = counter - var delta = note.sampleDelta + if (started) { + var tmpCounter = counter + var delta = note.sampleDelta - for (sample in 0 until samples) { - var value = sin(offset * PI2) + - sin(offset * 2 * PI2) * 0.6 + - sin(offset * 3 * PI2) * 0.4 + - sin(offset * 4 * PI2) * 0.3 - offset += delta + for (sample in 0 until samples) { + var value = sin(offset * PI2); - // new note every NOTE_LENGTH samples - val noteProgress = tmpCounter % note_length - if (noteProgress == 0) { - note = note.transpose(1) - if (note == Note.C7) { - note = Note.C2 + for(index in 0 until harmonics) { + value += sin(offset * (index + 2) * PI2) * (1.0 / (index+2)) } - delta = note.sampleDelta + offset += delta + + // new note every NOTE_LENGTH samples + val noteProgress = tmpCounter % note_length + if (noteProgress == 0) { + note = note.transpose(1) + if (note == Note.C7) { + note = Note.C2 + } + delta = note.sampleDelta + } + // simple envelop from max to 0 every note + value *= (1.0 - noteProgress / note_length.toDouble()) + + left[sample] = value + right[sample] = value + tmpCounter++ } - // simple envelop from max to 0 every note - value *= (1.0 - noteProgress / note_length.toDouble()) - left[sample] = value - right[sample] = value - tmpCounter++ + counter += samples } - - counter += samples } } diff --git a/src/jsAudioWorkletMain/kotlin/nl/astraeus/processor/WorkletProcessor.kt b/src/jsAudioWorkletMain/kotlin/nl/astraeus/processor/WorkletProcessor.kt deleted file mode 100644 index 85a3c7d..0000000 --- a/src/jsAudioWorkletMain/kotlin/nl/astraeus/processor/WorkletProcessor.kt +++ /dev/null @@ -1,46 +0,0 @@ -@file:OptIn(ExperimentalJsExport::class) - -package nl.astraeus.processor - -import org.khronos.webgl.Float64Array -import org.w3c.dom.MessageEvent -import org.w3c.dom.MessagePort - -@ExperimentalJsExport -@JsExport -object WorkletProcessor { - var port: MessagePort? = null - - @JsName("setPort") - fun setPort(port: MessagePort) { - this.port = port - this.port?.onmessage = ::onMessage - } - - @JsName("onMessage") - fun onMessage(message: MessageEvent) { - console.log("WorkletProcessor: Received message", message) - - when (message.data) { - "start" -> { - println("Start worklet!") - } - "stop" -> { - - } - else -> - console.error("Don't kow how to handle message", message) - } - } - - @JsName("process") - fun process(samples: Int, left: Float64Array, right: Float64Array) { - //console.log("WorkletProcessor.process", samples) -// val buffer = Float64SampleBuffer(samples, left, right) -// -// audioGenerator?.also { generator -> -// generator.fillBuffer(buffer, 0, samples, false) -// } - } - -} diff --git a/src/jsMain/kotlin/nl/astraeus/Main.kt b/src/jsMain/kotlin/nl/astraeus/Main.kt index 886bec3..9165460 100644 --- a/src/jsMain/kotlin/nl/astraeus/Main.kt +++ b/src/jsMain/kotlin/nl/astraeus/Main.kt @@ -9,16 +9,26 @@ fun main() { println("Ok") - document.getElementById("clicker")?.also { + document.getElementById("startButton")?.also { it.addEventListener("click", { - AudioWorkletHandler.createContext { - println("Created context") + if (AudioWorkletHandler.audioContext == null) { + AudioWorkletHandler.createContext { + println("Created context") + AudioWorkletHandler.start() + } + } else { AudioWorkletHandler.start() } }, "") } + document.getElementById("stopButton")?.also { + it.addEventListener("click", { + AudioWorkletHandler.stop() + }, "") + } + document.getElementById("noteLength")?.also { it.addEventListener("change", { val target = it.target @@ -27,5 +37,13 @@ fun main() { } }, "") } + document.getElementById("harmonics")?.also { + it.addEventListener("change", { + val target = it.target + if (target is HTMLInputElement) { + AudioWorkletHandler.setHarmonics(target.value.toInt()) + } + }, "") + } } diff --git a/src/jsMain/kotlin/nl/astraeus/handler/AudioWorkletHandler.kt b/src/jsMain/kotlin/nl/astraeus/handler/AudioWorkletHandler.kt index 4d211a8..d8d4515 100644 --- a/src/jsMain/kotlin/nl/astraeus/handler/AudioWorkletHandler.kt +++ b/src/jsMain/kotlin/nl/astraeus/handler/AudioWorkletHandler.kt @@ -159,7 +159,15 @@ object AudioWorkletHandler : AudioWorklet( audioWorkletMessagePort?.postMessage("start") } + fun stop() { + audioWorkletMessagePort?.postMessage("stop") + } + fun setNoteLength(length: Int) { audioWorkletMessagePort?.postMessage("set_note_length\n$length") } + + fun setHarmonics(length: Int) { + audioWorkletMessagePort?.postMessage("harmonics\n$length") + } } diff --git a/src/jsMain/resources/worklet.css b/src/jsMain/resources/worklet.css index 08e3dec..535f382 100644 --- a/src/jsMain/resources/worklet.css +++ b/src/jsMain/resources/worklet.css @@ -1,14 +1,21 @@ +body { + font-size: x-large; + margin: 2em; +} + .button_div { - margin: 1em; + margin: 0.5em; } .button { padding: 3px 5px; background-color: #2c008f; color: white; - font-size: large; + font-size: xx-large; + margin: 0.5em; } input { margin: 1em; + font-size: x-large; } diff --git a/src/jvmMain/kotlin/Server.kt b/src/jvmMain/kotlin/Server.kt index 90ab5b9..32d5665 100644 --- a/src/jvmMain/kotlin/Server.kt +++ b/src/jvmMain/kotlin/Server.kt @@ -14,14 +14,20 @@ fun HTML.index() { } body { div { - +"We need a button to start because we can only start audio from a user event" + +"We need a button to start because we can only start audio from a user event:" } div("button_div") { span("button") { - id = "clicker" + id = "startButton" +"Start" } + + span("button") { + id = "stopButton" + + +"Stop" + } } div { + "An example of how to interact with the audioworklet:" @@ -40,6 +46,19 @@ fun HTML.index() { step = "100" } } + div { + label { + htmlFor = "harmonics" + +"Number of harmonics:" + } + input { + id = "harmonics" + type = InputType.number + value = "3" + min = "1" + max = "10" + } + } script(src = "/static/kotlin-audioworklet.js") {} } }