This commit is contained in:
2024-06-20 18:57:20 +02:00
parent 945f4bb016
commit f4a5d0a75b
9 changed files with 350 additions and 139 deletions

View File

@@ -37,6 +37,8 @@ kotlin {
val commonMain by getting {
dependencies {
implementation(project(":common"))
implementation("nl.astraeus:vst-worklet-base:1.0.0-SNAPSHOT")
}
}
val jsMain by getting {

View File

@@ -1,43 +0,0 @@
package nl.astraeus.vst
import org.khronos.webgl.Float32Array
import org.w3c.dom.MessagePort
enum class AutomationRate(
val rate: String
) {
A_RATE("a-rate"),
K_RATE("k-rate")
}
interface AudioParam {
var value: Double
var automationRate: AutomationRate
val defaultValue: Double
val minValue: Double
val maxValue: Double
}
interface AudioParamMap {
operator fun get(name: String): AudioParam
}
abstract external class AudioWorkletProcessor {
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/AudioWorkletNode/parameters) */
//val parameters: AudioParamMap;
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/AudioWorkletNode/port) */
@JsName("port")
val port: MessagePort
@JsName("process")
open fun process (
inputs: Array<Array<Float32Array>>,
outputs: Array<Array<Float32Array>>,
parameters: dynamic
) : Boolean { definedExternally }
}
external fun registerProcessor(name: String, processorCtor: JsClass<*>)
external val sampleRate: Int
external val currentTime: Double

View File

@@ -66,6 +66,11 @@ class VstChipProcessor : AudioWorkletProcessor() {
}
var waveform = Waveform.SINE.ordinal
var dutyCycle = 0.5
var fmFreq = 0.0
var fmAmp = 0.0
var amFreq = 0.0
var amAmp = 0.0
val sampleLength = 1 / sampleRate.toDouble()
init {
this.port.onmessage = ::handleMessage
@@ -106,6 +111,7 @@ class VstChipProcessor : AudioWorkletProcessor() {
private fun playMidi(bytes: Int32Array) {
if (bytes.length > 0) {
//console.log("Received", bytes)
when(bytes[0]) {
0x90 -> {
if (bytes.length == 3) {
@@ -119,6 +125,7 @@ class VstChipProcessor : AudioWorkletProcessor() {
}
}
}
0x80 -> {
if (bytes.length >= 2) {
val note = bytes[1]
@@ -126,6 +133,7 @@ class VstChipProcessor : AudioWorkletProcessor() {
noteOff(note)
}
}
0xc9 -> {
if (bytes.length >= 1) {
val waveform = bytes[1]
@@ -135,18 +143,44 @@ class VstChipProcessor : AudioWorkletProcessor() {
}
}
}
0xb0 -> {
if (bytes.length == 3) {
val knob = bytes[1]
val value = bytes[2]
when(knob) {
when (knob) {
0x4a -> {
dutyCycle = value / 127.0
}
0x4b -> {
fmFreq = value / 127.0
}
0x4c -> {
fmAmp = value / 127.0
}
0x47 -> {
amFreq = value / 127.0
}
0x48 -> {
amAmp = value / 127.0
}
}
}
}
0xe0 -> {
if (bytes.length == 3) {
val lsb = bytes[1]
val msb = bytes[2]
amFreq = (((msb - 0x40) + (lsb / 127.0)) / 0x40) * 10.0
}
}
}
}
}
@@ -167,7 +201,7 @@ class VstChipProcessor : AudioWorkletProcessor() {
notes[i].state = NoteState.ON
val n = Note.fromMidi(note)
console.log("Playing note: ${n.sharp} (${n.freq})")
//console.log("Playing note: ${n.sharp} (${n.freq})")
break
}
}
@@ -205,13 +239,16 @@ class VstChipProcessor : AudioWorkletProcessor() {
note.releaseSamples--
targetVolume *= (note.releaseSamples / 10000f)
}
note.actualVolume += (targetVolume - note.actualVolume) * 0.001f
note.actualVolume += (targetVolume - note.actualVolume) * 0.0001f
if (note.state == NoteState.RELEASED && note.actualVolume <= 0) {
note.state = NoteState.OFF
}
val cycleOffset = note.cycleOffset
var cycleOffset = note.cycleOffset
val fmModulation = sin(sampleLength * fmFreq * 10f * PI2 * note.sample).toFloat() * fmAmp * 5f
val amModulation = 1f + (sin(sampleLength * amFreq * 10f * PI2 * note.sample) * amAmp).toFloat()
cycleOffset += fmModulation
val waveValue: Float = when (waveform) {
0 -> {
@@ -233,13 +270,14 @@ class VstChipProcessor : AudioWorkletProcessor() {
}
}
left[i] = left[i] + waveValue * note.actualVolume * 0.3f
right[i] = right[i] + waveValue * note.actualVolume * 0.3f
left[i] = left[i] + waveValue * note.actualVolume * 0.3f * amModulation
right[i] = right[i] + waveValue * note.actualVolume * 0.3f * amModulation
note.cycleOffset += sampleDelta
if (cycleOffset > 1f) {
note.cycleOffset -= 1f
}
note.sample++
}
}
}