Simple interaction with audioworkler
This commit is contained in:
@@ -4,7 +4,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinJsCompilerType.IR
|
|||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
kotlin("multiplatform") version "1.7.20"
|
kotlin("multiplatform") version "1.8.10"
|
||||||
application
|
application
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,11 +62,11 @@ kotlin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
application {
|
application {
|
||||||
mainClass.set("nl.astraeus.application.ServerKt")
|
mainClass.set("ServerKt")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.named<Copy>("jvmProcessResources") {
|
tasks.named<Copy>("jvmProcessResources") {
|
||||||
val jsBrowserDistribution = tasks.named("jsBrowserDistribution")
|
val jsBrowserDistribution = tasks.named("jsBrowserDevelopmentWebpack")
|
||||||
from(jsBrowserDistribution)
|
from(jsBrowserDistribution)
|
||||||
from(tasks.named("jsAudioWorkletBrowserDistribution"))
|
from(tasks.named("jsAudioWorkletBrowserDistribution"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ import org.w3c.dom.MessagePort
|
|||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
|
|
||||||
|
const val PI2 = PI * 2
|
||||||
|
const val NOTE_LENGTH = 2500
|
||||||
|
|
||||||
@ExperimentalJsExport
|
@ExperimentalJsExport
|
||||||
@JsExport
|
@JsExport
|
||||||
object WorkletProcessor {
|
object WorkletProcessor {
|
||||||
@@ -16,6 +19,8 @@ object WorkletProcessor {
|
|||||||
var note = Note.C2
|
var note = Note.C2
|
||||||
var offset = 0.0
|
var offset = 0.0
|
||||||
|
|
||||||
|
var note_length = 2500
|
||||||
|
|
||||||
@JsName("setPort")
|
@JsName("setPort")
|
||||||
fun setPort(port: MessagePort) {
|
fun setPort(port: MessagePort) {
|
||||||
WorkletProcessor.port = port
|
WorkletProcessor.port = port
|
||||||
@@ -26,7 +31,10 @@ object WorkletProcessor {
|
|||||||
fun onMessage(message: MessageEvent) {
|
fun onMessage(message: MessageEvent) {
|
||||||
console.log("WorkletProcessor: Received message", message)
|
console.log("WorkletProcessor: Received message", message)
|
||||||
|
|
||||||
when (message.data) {
|
val data = message.data
|
||||||
|
if (data is String) {
|
||||||
|
val parts = data.split("\n")
|
||||||
|
when (parts[0]) {
|
||||||
"start" -> {
|
"start" -> {
|
||||||
println("Start worklet!")
|
println("Start worklet!")
|
||||||
}
|
}
|
||||||
@@ -35,10 +43,15 @@ object WorkletProcessor {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"set_note_length" -> {
|
||||||
|
note_length = parts[1].toInt()
|
||||||
|
}
|
||||||
|
|
||||||
else ->
|
else ->
|
||||||
console.error("Don't kow how to handle message", message)
|
console.error("Don't kow how to handle message", message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@JsName("process")
|
@JsName("process")
|
||||||
fun process(samples: Int, left: Float64Array, right: Float64Array) {
|
fun process(samples: Int, left: Float64Array, right: Float64Array) {
|
||||||
@@ -46,10 +59,14 @@ object WorkletProcessor {
|
|||||||
var delta = note.sampleDelta
|
var delta = note.sampleDelta
|
||||||
|
|
||||||
for (sample in 0 until samples) {
|
for (sample in 0 until samples) {
|
||||||
var value = sin(offset * 2 * PI)
|
var value = sin(offset * PI2) +
|
||||||
|
sin(offset * 2 * PI2) * 0.5 +
|
||||||
|
sin(offset * 3 * PI2) * 0.25 +
|
||||||
|
sin(offset * 4 * PI2) * 0.15
|
||||||
offset += delta
|
offset += delta
|
||||||
|
|
||||||
val noteProgress = tmpCounter % 5000
|
// new note every NOTE_LENGTH samples
|
||||||
|
val noteProgress = tmpCounter % note_length
|
||||||
if (noteProgress == 0) {
|
if (noteProgress == 0) {
|
||||||
note = note.transpose(1)
|
note = note.transpose(1)
|
||||||
if (note == Note.C7) {
|
if (note == Note.C7) {
|
||||||
@@ -57,7 +74,8 @@ object WorkletProcessor {
|
|||||||
}
|
}
|
||||||
delta = note.sampleDelta
|
delta = note.sampleDelta
|
||||||
}
|
}
|
||||||
value *= (1.0 - noteProgress / 5000.0)
|
// simple envelop from max to 0 every note
|
||||||
|
value *= (1.0 - noteProgress / note_length.toDouble())
|
||||||
|
|
||||||
left[sample] = value
|
left[sample] = value
|
||||||
right[sample] = value
|
right[sample] = value
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
import kotlinx.browser.document
|
|
||||||
import handler.AudioWorkletHandler
|
|
||||||
|
|
||||||
fun main() {
|
|
||||||
AudioWorkletHandler.loadCode()
|
|
||||||
|
|
||||||
println("Ok")
|
|
||||||
|
|
||||||
document.getElementById("clicker")?.also {
|
|
||||||
it.addEventListener("click", {
|
|
||||||
AudioWorkletHandler.createContext {
|
|
||||||
println("Created context")
|
|
||||||
|
|
||||||
AudioWorkletHandler.start()
|
|
||||||
}
|
|
||||||
}, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,7 @@ package nl.astraeus
|
|||||||
|
|
||||||
import kotlinx.browser.document
|
import kotlinx.browser.document
|
||||||
import nl.astraeus.handler.AudioWorkletHandler
|
import nl.astraeus.handler.AudioWorkletHandler
|
||||||
|
import org.w3c.dom.HTMLInputElement
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
AudioWorkletHandler.loadCode()
|
AudioWorkletHandler.loadCode()
|
||||||
@@ -18,4 +19,17 @@ fun main() {
|
|||||||
}, "")
|
}, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print("get noteLength")
|
||||||
|
document.getElementById("noteLength")?.also {
|
||||||
|
println("Set noteLength event")
|
||||||
|
it.addEventListener("change", {
|
||||||
|
println("Set noteLength 1")
|
||||||
|
val target = it.target
|
||||||
|
if (target is HTMLInputElement) {
|
||||||
|
println("Set noteLength 2")
|
||||||
|
AudioWorkletHandler.setNoteLength(target.value.toInt())
|
||||||
|
}
|
||||||
|
}, "")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -159,4 +159,7 @@ object AudioWorkletHandler : AudioWorklet(
|
|||||||
audioWorkletMessagePort?.postMessage("start")
|
audioWorkletMessagePort?.postMessage("start")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setNoteLength(length: Int) {
|
||||||
|
audioWorkletMessagePort?.postMessage("set_note_length\n$length")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,14 @@
|
|||||||
|
.button_div {
|
||||||
|
margin: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
padding: 3px 5px;
|
padding: 3px 5px;
|
||||||
background-color: red;
|
background-color: #2c008f;
|
||||||
|
color: white;
|
||||||
|
font-size: large;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
margin: 1em;
|
||||||
}
|
}
|
||||||
@@ -14,15 +14,31 @@ fun HTML.index() {
|
|||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
div {
|
div {
|
||||||
+"Hello from Ktor"
|
+"We need a button to start because we can only start audio from a user event"
|
||||||
}
|
|
||||||
div {
|
|
||||||
id = "root"
|
|
||||||
}
|
}
|
||||||
|
div("button_div") {
|
||||||
span("button") {
|
span("button") {
|
||||||
id = "clicker"
|
id = "clicker"
|
||||||
|
|
||||||
+ "Start"
|
+"Start"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
+ "An example of how to interact with the audioworklet:"
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
label {
|
||||||
|
htmlFor = "noteLength"
|
||||||
|
+"Note length (in samples):"
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
id = "noteLength"
|
||||||
|
type = InputType.number
|
||||||
|
value = "2500"
|
||||||
|
min = "1"
|
||||||
|
max = "100000"
|
||||||
|
step = "100"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
script(src = "/static/kotlin-audioworklet.js") {}
|
script(src = "/static/kotlin-audioworklet.js") {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
package nl.astraeus.application
|
|
||||||
|
|
||||||
import io.ktor.http.HttpStatusCode
|
|
||||||
import io.ktor.server.application.*
|
|
||||||
import io.ktor.server.engine.embeddedServer
|
|
||||||
import io.ktor.server.html.*
|
|
||||||
import io.ktor.server.http.content.*
|
|
||||||
import io.ktor.server.netty.Netty
|
|
||||||
import io.ktor.server.routing.*
|
|
||||||
import kotlinx.html.*
|
|
||||||
|
|
||||||
fun HTML.index() {
|
|
||||||
head {
|
|
||||||
title("Hello from Ktor!")
|
|
||||||
link("static/worklet.css", "stylesheet" ,"text/css")
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
div {
|
|
||||||
+"Hello from Ktor"
|
|
||||||
}
|
|
||||||
div {
|
|
||||||
id = "root"
|
|
||||||
}
|
|
||||||
span("button") {
|
|
||||||
id = "clicker"
|
|
||||||
|
|
||||||
+ "Start"
|
|
||||||
}
|
|
||||||
script(src = "/static/kotlin-audioworklet.js") {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun main() {
|
|
||||||
embeddedServer(Netty, port = 8080, host = "127.0.0.1") {
|
|
||||||
routing {
|
|
||||||
get("/") {
|
|
||||||
call.respondHtml(HttpStatusCode.OK, HTML::index)
|
|
||||||
}
|
|
||||||
static("/static") {
|
|
||||||
resources()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.start(wait = true)
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user