Harmonics

This commit is contained in:
2023-02-24 17:35:54 +01:00
parent 96455dd7f2
commit 444682e7ae
6 changed files with 98 additions and 83 deletions

View File

@@ -12,13 +12,15 @@ const val PI2 = PI * 2
@ExperimentalJsExport @ExperimentalJsExport
@JsExport @JsExport
object WorkletProcessor { object WorkletProcessor {
var port: MessagePort? = null private var port: MessagePort? = null
var counter: Int = 0 private var counter: Int = 0
var note = Note.C2 private var note = Note.C2
var offset = 0.0 private var offset = 0.0
var note_length = 2500 private var started = false
private var note_length = 2500
private var harmonics = 3
@JsName("setPort") @JsName("setPort")
fun setPort(port: MessagePort) { fun setPort(port: MessagePort) {
@@ -36,16 +38,20 @@ object WorkletProcessor {
when (parts[0]) { when (parts[0]) {
"start" -> { "start" -> {
println("Start worklet!") println("Start worklet!")
}
started = true
}
"stop" -> { "stop" -> {
println("Stop worklet!")
started = false
} }
"set_note_length" -> { "set_note_length" -> {
note_length = parts[1].toInt() note_length = parts[1].toInt()
} }
"harmonics" -> {
harmonics = 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)
} }
@@ -54,34 +60,37 @@ object WorkletProcessor {
@JsName("process") @JsName("process")
fun process(samples: Int, left: Float64Array, right: Float64Array) { fun process(samples: Int, left: Float64Array, right: Float64Array) {
var tmpCounter = counter if (started) {
var delta = note.sampleDelta var tmpCounter = counter
var delta = note.sampleDelta
for (sample in 0 until samples) { for (sample in 0 until samples) {
var value = sin(offset * PI2) + 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
// new note every NOTE_LENGTH samples for(index in 0 until harmonics) {
val noteProgress = tmpCounter % note_length value += sin(offset * (index + 2) * PI2) * (1.0 / (index+2))
if (noteProgress == 0) {
note = note.transpose(1)
if (note == Note.C7) {
note = Note.C2
} }
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 counter += samples
right[sample] = value
tmpCounter++
} }
counter += samples
} }
} }

View File

@@ -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)
// }
}
}

View File

@@ -9,16 +9,26 @@ fun main() {
println("Ok") println("Ok")
document.getElementById("clicker")?.also { document.getElementById("startButton")?.also {
it.addEventListener("click", { it.addEventListener("click", {
AudioWorkletHandler.createContext { if (AudioWorkletHandler.audioContext == null) {
println("Created context") AudioWorkletHandler.createContext {
println("Created context")
AudioWorkletHandler.start()
}
} else {
AudioWorkletHandler.start() AudioWorkletHandler.start()
} }
}, "") }, "")
} }
document.getElementById("stopButton")?.also {
it.addEventListener("click", {
AudioWorkletHandler.stop()
}, "")
}
document.getElementById("noteLength")?.also { document.getElementById("noteLength")?.also {
it.addEventListener("change", { it.addEventListener("change", {
val target = it.target 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())
}
}, "")
}
} }

View File

@@ -159,7 +159,15 @@ object AudioWorkletHandler : AudioWorklet(
audioWorkletMessagePort?.postMessage("start") audioWorkletMessagePort?.postMessage("start")
} }
fun stop() {
audioWorkletMessagePort?.postMessage("stop")
}
fun setNoteLength(length: Int) { fun setNoteLength(length: Int) {
audioWorkletMessagePort?.postMessage("set_note_length\n$length") audioWorkletMessagePort?.postMessage("set_note_length\n$length")
} }
fun setHarmonics(length: Int) {
audioWorkletMessagePort?.postMessage("harmonics\n$length")
}
} }

View File

@@ -1,14 +1,21 @@
body {
font-size: x-large;
margin: 2em;
}
.button_div { .button_div {
margin: 1em; margin: 0.5em;
} }
.button { .button {
padding: 3px 5px; padding: 3px 5px;
background-color: #2c008f; background-color: #2c008f;
color: white; color: white;
font-size: large; font-size: xx-large;
margin: 0.5em;
} }
input { input {
margin: 1em; margin: 1em;
font-size: x-large;
} }

View File

@@ -14,14 +14,20 @@ fun HTML.index() {
} }
body { body {
div { 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") { div("button_div") {
span("button") { span("button") {
id = "clicker" id = "startButton"
+"Start" +"Start"
} }
span("button") {
id = "stopButton"
+"Stop"
}
} }
div { div {
+ "An example of how to interact with the audioworklet:" + "An example of how to interact with the audioworklet:"
@@ -40,6 +46,19 @@ fun HTML.index() {
step = "100" 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") {} script(src = "/static/kotlin-audioworklet.js") {}
} }
} }