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

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")
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())
}
}, "")
}
}

View File

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

View File

@@ -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;
}

View File

@@ -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") {}
}
}