Harmonics
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
}, "")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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") {}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user