6 Commits

Author SHA1 Message Date
310f77fc3a Update Gradle config, dependencies, and Kotlin plugin version
Configured Gradle to use "corretto-21" JVM and bumped the Kotlin Multiplatform plugin to version 2.1.10. Updated the "midi-arrays" dependency to version 0.3.4 across relevant modules. These changes ensure compatibility and leverage the latest library improvements.
2025-03-17 18:16:47 +00:00
60a21bbd79 Update dependencies and refine MIDI handling.
Upgraded various dependencies, including `vst-ui-base` to 1.2.0 and build configurations to include `mavenLocal`. Refined MIDI handling by removing redundant logging to improve performance and clarity. Adjusted knob component value ranges for better user experience.
2024-12-26 14:23:16 +01:00
d58fb9c7b5 Refactor MIDI handling and update dependencies.
Streamlined MIDI message handling by introducing `MidiMessageHandler` and removed redundant code. Added better handler support for specific message types and parameters. Also upgraded Kotlin to version 2.1.0 and adjusted build configurations.
2024-12-21 20:42:19 +01:00
fbba6d1422 Refactor MIDI handling and improve audio processing
Replaced `uInt8ArrayOf` with simplified integer arrays for MIDI messages. Introduced `TimedMidiMessage` and buffer handling for better synchronization in audio processing. Updated Gradle dependencies and added timing-aware MIDI utilities.
2024-12-17 20:51:32 +01:00
4c00356dff Increase polyphony and comment out debug logs
Updated the polyphony level from 10 to 20 to enhance sound capability and commented out several debug logs for cleaner console output. Additionally, commented out a block of code related to sine wave modulation that appears unnecessary at this stage. The console log message for registering the processor was slightly modified for consistency.
2024-12-09 19:51:57 +01:00
29aac228e5 Update VST Worklet Base dependency version
Upgrade the nl.astraeus:vst-worklet-base dependency from version 1.0.0-SNAPSHOT to 1.0.1 in audio-worklet/build.gradle.kts. This change ensures compatibility with the updated library while bringing in any fixes or enhancements included in the new version.
2024-12-08 20:43:00 +01:00
12 changed files with 252 additions and 230 deletions

2
.idea/gradle.xml generated
View File

@@ -5,7 +5,7 @@
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="" />
<option name="gradleJvm" value="corretto-21" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />

View File

@@ -35,12 +35,12 @@ kotlin {
}
}
}
jvm()
sourceSets {
val commonMain by getting {
dependencies {
implementation("nl.astraeus:vst-worklet-base:1.0.0-SNAPSHOT")
implementation("nl.astraeus:vst-worklet-base:1.0.1")
implementation("nl.astraeus:midi-arrays:0.3.4")
}
}
val jsMain by getting

View File

@@ -2,14 +2,16 @@
package nl.astraeus.vst.chip
import nl.astraeus.midi.message.SortedTimedMidiMessageList
import nl.astraeus.midi.message.TimedMidiMessage
import nl.astraeus.tba.SlicedByteArray
import nl.astraeus.vst.ADSR
import nl.astraeus.vst.AudioWorkletProcessor
import nl.astraeus.vst.currentTime
import nl.astraeus.vst.midi.MidiMessageHandler
import nl.astraeus.vst.registerProcessor
import nl.astraeus.vst.sampleRate
import org.khronos.webgl.Float32Array
import org.khronos.webgl.Int32Array
import org.khronos.webgl.Uint8Array
import org.khronos.webgl.get
import org.khronos.webgl.set
import org.w3c.dom.MessageEvent
@@ -17,7 +19,7 @@ import kotlin.math.PI
import kotlin.math.min
import kotlin.math.sin
val POLYPHONICS = 10
val POLYPHONICS = 20
val PI2 = PI * 2
@ExperimentalJsExport
@@ -64,7 +66,8 @@ enum class RecordingState {
@ExperimentalJsExport
@JsExport
class VstChipProcessor : AudioWorkletProcessor() {
var midiChannel = 0
val midiMessageBuffer = SortedTimedMidiMessageList()
val midiMessageHandler = MidiMessageHandler()
val notes = Array<PlayingNote?>(POLYPHONICS) { null }
var waveform = Waveform.SINE.ordinal
@@ -98,18 +101,94 @@ class VstChipProcessor : AudioWorkletProcessor() {
init {
this.port.onmessage = ::handleMessage
Note.updateSampleRate(sampleRate)
with(midiMessageHandler) {
addHandler(0x90) { b1, b2, b3 ->
val note = b2.toInt() and 0xff
val velocity = b3.toInt() and 0xff
if (velocity > 0) {
console.log("Note on", note, velocity)
noteOn(note, velocity)
} else {
console.log("Note off", note)
noteOff(note)
}
}
addHandler(0x80) { b1, b2, b3 ->
val note = b2.toInt() and 0xff
console.log("Note off", note)
noteOff(note)
}
addHandler(0xc9) { b1, b2, b3 ->
waveform = b2.toInt() and 0xff
}
addHandler(0xb0, 7) { b1, b2, b3 ->
volume = b3 / 127f
}
addHandler(0xb0, 0x47) { b1, b2, b3 ->
dutyCycle = b3 / 127.0
}
addHandler(0xb0, 0x40) { b1, b2, b3 ->
fmFreq = b3 / 127.0
}
addHandler(0xb0, 0x41) { b1, b2, b3 ->
fmAmp = b3 / 127.0
}
addHandler(0xb0, 0x42) { b1, b2, b3 ->
amFreq = b3 / 127.0
}
addHandler(0xb0, 0x43) { b1, b2, b3 ->
amAmp = b3 / 127.0
}
addHandler(0xb0, 0x49) { b1, b2, b3 ->
attack = b3 / 127.0
}
addHandler(0xb0, 0x4b) { b1, b2, b3 ->
decay = b3 / 127.0
}
addHandler(0xb0, 0x46) { b1, b2, b3 ->
sustain = b3 / 127.0
}
addHandler(0xb0, 0x48) { b1, b2, b3 ->
release = b3 / 127.0
}
addHandler(0xb0, 0x4e) { b1, b2, b3 ->
delay = b3 / 127.0
}
addHandler(0xb0, 0x4f) { b1, b2, b3 ->
delayDepth = b3 / 127.0
}
addHandler(0xb0, 0x50) { b1, b2, b3 ->
feedback = b3 / 127.0
}
addHandler(0xb0, 123) { b1, b2, b3 ->
for (note in notes) {
note?.noteRelease = currentTime
}
}
addHandler(0xe0) { b1, b2, b3 ->
if (b2.toInt() and 0xff > 0) {
val lsb = b2.toInt() and 0xff
val msb = b3.toInt() and 0xff
amFreq = (((msb - 0x40) + (lsb / 127.0)) / 0x40) * 10.0
}
}
}
}
private fun handleMessage(message: MessageEvent) {
//console.log("VstChipProcessor: Received message:", message.data)
//console.log("VstChipProcessor: Received message:", currentTime)
val data = message.data
try {
when (data) {
is String -> {
when (data) {
"start_recording" -> {
when {
data == "start_recording" -> {
port.postMessage(recordingBuffer)
if (recordingState == RecordingState.STOPPED) {
recordingState = RecordingState.WAITING_TO_START
@@ -117,34 +196,43 @@ class VstChipProcessor : AudioWorkletProcessor() {
}
}
else ->
if (data.startsWith("set_channel")) {
val parts = data.split('\n')
if (parts.size == 2) {
midiChannel = parts[1].toInt()
println("Setting channel: $midiChannel")
}
} else if (data.startsWith("waveform")) {
val parts = data.split('\n')
if (parts.size == 2) {
waveform = parts[1].toInt()
println("Setting waveform: $waveform")
}
data.startsWith("set_channel") -> {
val parts = data.split('\n')
if (parts.size == 2) {
midiMessageHandler.channel = parts[1].toByte()
println("Setting channel: ${midiMessageHandler.channel}")
}
}
data.startsWith("waveform") -> {
val parts = data.split('\n')
if (parts.size == 2) {
waveform = parts[1].toInt()
println("Setting waveform: $waveform")
}
}
}
}
is Uint8Array -> {
val data32 = Int32Array(data.length)
for (i in 0 until data.length) {
data32[i] = (data[i].toInt() and 0xff)
}
playMidi(data32)
is ByteArray -> {
val message1 = TimedMidiMessage(data)
midiMessageBuffer.add(message1)
playBuffer()
}
/*
is Uint8Array -> {
val data32 = Int32Array(data.length)
for (i in 0 until data.length) {
data32[i] = (data[i].toInt() and 0xff)
}
playMidi(data32)
}
is Int32Array -> {
playMidi(data)
}
is Int32Array -> {
playMidi(data)
}
*/
else ->
console.error("Don't kow how to handle message", message)
@@ -154,135 +242,30 @@ class VstChipProcessor : AudioWorkletProcessor() {
}
}
private fun playMidi(bytes: Int32Array) {
console.log("playMidi", bytes)
if (bytes.length > 0) {
var cmdByte = bytes[0]
val channelCmd = ((cmdByte shr 4) and 0xf) != 0xf0
val channel = cmdByte and 0xf
println("Channel cmd: $channelCmd")
if (channelCmd && channel != midiChannel) {
console.log("Wrong channel", midiChannel, bytes)
return
}
cmdByte = cmdByte and 0xf0
//console.log("Received", bytes)
when (cmdByte) {
0x90 -> {
if (bytes.length == 3) {
val note = bytes[1]
val velocity = bytes[2]
if (velocity > 0) {
noteOn(note, velocity)
} else {
noteOff(note)
}
}
}
0x80 -> {
if (bytes.length >= 2) {
val note = bytes[1]
noteOff(note)
}
}
0xc9 -> {
if (bytes.length >= 1) {
val waveform = bytes[1]
if (waveform < 4) {
this.waveform = waveform
}
}
}
0xb0 -> {
if (bytes.length == 3) {
val knob = bytes[1]
val value = bytes[2]
when (knob) {
7 -> {
volume = value / 127f
}
0x47 -> {
dutyCycle = value / 127.0
}
0x40 -> {
fmFreq = value / 127.0
}
0x41 -> {
fmAmp = value / 127.0
}
0x42 -> {
amFreq = value / 127.0
}
0x43 -> {
amAmp = value / 127.0
}
0x49 -> {
attack = value / 127.0
}
0x4b -> {
decay = value / 127.0
}
0x46 -> {
sustain = value / 127.0
}
0x48 -> {
release = value / 127.0
}
0x4e -> {
delay = value / 127.0
println("Setting delay $delay")
}
0x4f -> {
delayDepth = value / 127.0
println("Setting delayDepth $delayDepth")
}
0x50 -> {
feedback = value / 127.0
println("Setting feedback $delayDepth")
}
123 -> {
for (note in notes) {
note?.noteRelease = currentTime
}
}
}
}
}
0xe0 -> {
if (bytes.length == 3) {
val lsb = bytes[1]
val msb = bytes[2]
amFreq = (((msb - 0x40) + (lsb / 127.0)) / 0x40) * 10.0
}
}
}
private fun playBuffer() {
while (
midiMessageBuffer.isNotEmpty() &&
(midiMessageBuffer.nextTimestamp() ?: 0.0) < currentTime
) {
val midi = midiMessageBuffer.read()
playMidi(midi.midi)
}
}
private fun playMidi(bytes: SlicedByteArray) {
var index = 0
while (index < bytes.size && bytes[index].toUByte() > 0u) {
val buffer = bytes.getBlob(index, 3)
playMidiFromBuffer(buffer)
index += 3
}
}
private fun playMidiFromBuffer(bytes: SlicedByteArray) {
midiMessageHandler.handle(bytes[0], bytes[1], bytes[2])
}
private fun noteOn(note: Int, velocity: Int) {
for (i in 0 until POLYPHONICS) {
if (notes[i]?.note == note) {
@@ -332,13 +315,15 @@ class VstChipProcessor : AudioWorkletProcessor() {
recordingStart = 0
}
playBuffer()
for ((index, note) in notes.withIndex()) {
if (note != null) {
val midiNote = Note.fromMidi(note.note)
val sampleDelta = midiNote.sampleDelta
for (i in 0 until samples) {
var targetVolume = note.velocity / 127f * 10f
var targetVolume = note.velocity / 127f * 1f
targetVolume *= ADSR.calculate(
attack,
decay,
@@ -401,7 +386,6 @@ class VstChipProcessor : AudioWorkletProcessor() {
left[i] = left[i] + waveValue * note.actualVolume * volume * amModulation
right[i] = right[i] + waveValue * note.actualVolume * volume * amModulation
// comb filter delay
val delaySampleIndex =
(note.sample + note.combDelayBuffer.length) % note.combDelayBuffer.length
@@ -428,10 +412,13 @@ class VstChipProcessor : AudioWorkletProcessor() {
}
// if sin enable
/*
for (i in 0 until samples) {
left[i] = sin(left[i] * PI2).toFloat()
right[i] = sin(right[i] * PI2).toFloat()
}
*/
val delaySamples = (delay * leftDelayBuffer.length).toInt()
for (i in 0 until samples) {
@@ -466,5 +453,5 @@ class VstChipProcessor : AudioWorkletProcessor() {
fun main() {
registerProcessor("vst-chip-processor", VstChipProcessor::class.js)
println("VstChipProcessor registered!")
console.log("'vst-chip-processor' registered!", currentTime)
}

View File

@@ -12,8 +12,6 @@ import kotlin.math.round
* Time: 11:50
*/
@ExperimentalJsExport
@JsExport
enum class Note(
val sharp: String,
val flat: String

View File

@@ -57,8 +57,8 @@ kotlin {
dependencies {
//base
implementation("nl.astraeus:kotlin-css-generator:1.0.10")
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.0")
implementation("nl.astraeus:vst-ui-base:1.1.2")
implementation("nl.astraeus:vst-ui-base:1.2.0")
implementation("nl.astraeus:midi-arrays:0.3.4")
}
}
val jsMain by getting {
@@ -80,6 +80,7 @@ kotlin {
val jvmMain by getting {
dependencies {
//base
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.0")
implementation("io.undertow:undertow-core:2.3.14.Final")
implementation("io.undertow:undertow-websockets-jsr:2.3.14.Final")

View File

@@ -3,10 +3,13 @@ version = "0.1.0"
allprojects {
repositories {
mavenLocal()
mavenCentral()
maven {
url = uri("https://gitea.astraeus.nl/api/packages/rnentjes/maven")
}
maven {
url = uri("https://gitea.astraeus.nl:8443/api/packages/rnentjes/maven")
}
mavenCentral()
mavenLocal()
}
}

View File

@@ -1,6 +1,6 @@
pluginManagement {
plugins {
kotlin("multiplatform") version "2.0.21"
kotlin("multiplatform") version "2.1.10"
}
repositories {
gradlePluginPortal()

View File

@@ -1,10 +1,5 @@
package nl.astraeus.vst.chip.audio
import nl.astraeus.vst.chip.AudioContext
object AudioContextHandler {
val audioContext: dynamic = AudioContext()
}
val audioContext: dynamic = js("new AudioContext()")
}

View File

@@ -1,5 +1,6 @@
package nl.astraeus.vst.chip.audio
import nl.astraeus.midi.message.TimedMidiMessage
import nl.astraeus.vst.chip.AudioWorkletNode
import nl.astraeus.vst.chip.AudioWorkletNodeParameters
import nl.astraeus.vst.chip.audio.AudioContextHandler.audioContext
@@ -53,11 +54,27 @@ abstract class AudioNode(
abstract fun onMessage(message: MessageEvent)
open fun postMessage(vararg data: Int) {
if (port == null) {
console.log("postMessage port is NULL!")
}
val array = ByteArray(data.size) { data[it].toByte() }
port?.postMessage(
TimedMidiMessage(
audioContext.currentTime,
*array
).data.buffer.toByteArray()
)
}
open fun postMessage(msg: Any) {
if (port == null) {
console.log("postMessage port is NULL!")
}
port?.postMessage(msg)
//console.log("Posted message", audioContext.currentTime)
}
// call from user gesture
@@ -83,6 +100,7 @@ abstract class AudioNode(
port = node.port as? MessagePort
created = true
console.log("Created node: ${audioContext.currentTime}")
done(node)
}

View File

@@ -2,15 +2,12 @@
package nl.astraeus.vst.chip.audio
import nl.astraeus.midi.message.TimedMidiMessage
import nl.astraeus.vst.chip.PatchDTO
import nl.astraeus.vst.chip.view.MainView
import nl.astraeus.vst.chip.view.WaveformView
import nl.astraeus.vst.ui.util.uInt8ArrayOf
import org.khronos.webgl.Float32Array
import org.khronos.webgl.Uint8Array
import org.khronos.webgl.get
import org.w3c.dom.MessageEvent
import kotlin.experimental.and
object VstChipWorklet : AudioNode(
"/vst-chip-worklet.js",
@@ -33,63 +30,63 @@ object VstChipWorklet : AudioNode(
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 7, (value * 127).toInt())
0xb0 + midiChannel, 7, (value * 127).toInt()
)
}
var dutyCycle = 0.5
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 0x47, (value * 127).toInt())
0xb0 + midiChannel, 0x47, (value * 127).toInt()
)
}
var fmModFreq = 0.0
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 0x40, (value * 127).toInt())
0xb0 + midiChannel, 0x40, (value * 127).toInt()
)
}
var fmModAmp = 0.0
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 0x41, (value * 127).toInt())
0xb0 + midiChannel, 0x41, (value * 127).toInt()
)
}
var amModFreq = 0.0
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 0x42, (value * 127).toInt())
0xb0 + midiChannel, 0x42, (value * 127).toInt()
)
}
var amModAmp = 0.0
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 0x43, (value * 127).toInt())
0xb0 + midiChannel, 0x43, (value * 127).toInt()
)
}
var feedback = 0.0
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 0x50, (value * 127).toInt())
0xb0 + midiChannel, 0x50, (value * 127).toInt()
)
}
var delay = 0.0
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 0x4e, (value * 127).toInt())
0xb0 + midiChannel, 0x4e, (value * 127).toInt()
)
}
var delayDepth = 0.0
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 0x4f, (value * 127).toInt())
0xb0 + midiChannel, 0x4f, (value * 127).toInt()
)
}
@@ -97,28 +94,28 @@ object VstChipWorklet : AudioNode(
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 0x49, (value * 127).toInt())
0xb0 + midiChannel, 0x49, (value * 127).toInt()
)
}
var decay = 0.2
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 0x4b, (value * 127).toInt())
0xb0 + midiChannel, 0x4b, (value * 127).toInt()
)
}
var sustain = 0.5
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 0x46, (value * 127).toInt())
0xb0 + midiChannel, 0x46, (value * 127).toInt()
)
}
var release = 0.2
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 0x48, (value * 127).toInt())
0xb0 + midiChannel, 0x48, (value * 127).toInt()
)
}
@@ -139,25 +136,35 @@ object VstChipWorklet : AudioNode(
}
override fun postMessage(msg: Any) {
if (msg is Uint8Array) {
if (
msg.length == 3
&& (msg[0] and 0xf == midiChannel.toByte())
&& (msg[0] and 0xf0.toByte() == 0xb0.toByte())
) {
val knob = msg[1]
val value = msg[2]
if (msg is ByteArray) {
val tmm = TimedMidiMessage(msg)
val byte1 = tmm.midi[0]
handleIncomingMidi(knob, value)
} else {
super.postMessage(msg)
if (byte1.toInt() and 0xf0 == 0xb0) {
handleIncomingMidi(tmm.midi[1], tmm.midi[2])
}
} else {
super.postMessage(msg)
}
super.postMessage(msg)
}
override fun postMessage(vararg msg: Int) {
println("postMessage ${msg.size} bytes")
if (
msg.size == 3
&& (msg[0] and 0xf == midiChannel)
&& (msg[0] and 0xf0 == 0xb0)
) {
val knob = msg[1]
val value = msg[2]
handleIncomingMidi(knob.toByte(), value.toByte())
}
super.postMessage(msg)
}
private fun handleIncomingMidi(knob: Byte, value: Byte) {
println("Incoming knob: $knob, value: $value")
when (knob) {
0x46.toByte() -> {
volume = value / 127.0

View File

@@ -1,6 +1,8 @@
package nl.astraeus.vst.chip.midi
import kotlinx.browser.window
import nl.astraeus.midi.message.TimedMidiMessage
import nl.astraeus.vst.chip.audio.AudioContextHandler
import nl.astraeus.vst.chip.audio.VstChipWorklet
import nl.astraeus.vst.chip.view.MainView
import org.khronos.webgl.Uint8Array
@@ -124,9 +126,14 @@ object Midi {
hex.append(data[index].toString(16))
hex.append(" ")
}
console.log("Midi message:", hex)
console.log("Midi message:", hex, message)
val midiData = ByteArray(message.data.length) { data[it].toByte() }
val timeMessage = TimedMidiMessage(
AudioContextHandler.audioContext.currentTime,
*midiData
)
VstChipWorklet.postMessage(
message.data
timeMessage.data.buffer.toByteArray()
)
}

View File

@@ -35,6 +35,8 @@ import nl.astraeus.css.style.cls
import nl.astraeus.komp.HtmlBuilder
import nl.astraeus.komp.Komponent
import nl.astraeus.komp.currentElement
import nl.astraeus.midi.message.TimedMidiMessage
import nl.astraeus.midi.message.getCurrentTime
import nl.astraeus.vst.chip.audio.VstChipWorklet
import nl.astraeus.vst.chip.audio.VstChipWorklet.midiChannel
import nl.astraeus.vst.chip.midi.Midi
@@ -46,7 +48,6 @@ import nl.astraeus.vst.ui.css.Css.defineCss
import nl.astraeus.vst.ui.css.Css.noTextSelect
import nl.astraeus.vst.ui.css.CssName
import nl.astraeus.vst.ui.css.hover
import nl.astraeus.vst.ui.util.uInt8ArrayOf
import org.khronos.webgl.get
import org.w3c.dom.CanvasRenderingContext2D
import org.w3c.dom.HTMLCanvasElement
@@ -95,7 +96,6 @@ object WaveformView: Komponent() {
}
}
}
}
object MainView : Komponent(), CssName {
@@ -114,6 +114,11 @@ object MainView : Komponent(), CssName {
requestUpdate()
}
override fun renderUpdate() {
println("Rendering MainView")
super.renderUpdate()
}
override fun HtmlBuilder.render() {
div(MainDivCss.name) {
if (!started) {
@@ -190,7 +195,8 @@ object MainView : Komponent(), CssName {
+"STOP"
onClickFunction = {
VstChipWorklet.postDirectlyToWorklet(
uInt8ArrayOf(0xb0 + midiChannel, 123, 0)
TimedMidiMessage(getCurrentTime(), (0xb0 + midiChannel).toByte(), 123, 0)
.data.buffer.data
)
}
}
@@ -242,7 +248,7 @@ object MainView : Komponent(), CssName {
ExpKnobComponent(
value = VstChipWorklet.volume,
label = "Volume",
minValue = 0.005,
minValue = 0.0,
maxValue = 1.0,
step = 5.0 / 127.0,
width = 100,
@@ -268,7 +274,7 @@ object MainView : Komponent(), CssName {
ExpKnobComponent(
value = VstChipWorklet.fmModFreq,
label = "FM Freq",
minValue = 0.005,
minValue = 0.0,
maxValue = 1.0,
step = 5.0 / 127.0,
width = 100,
@@ -281,7 +287,7 @@ object MainView : Komponent(), CssName {
ExpKnobComponent(
value = VstChipWorklet.fmModAmp,
label = "FM Ampl",
minValue = 0.005,
minValue = 0.0,
maxValue = 1.0,
step = 5.0 / 127.0,
width = 100,
@@ -294,7 +300,7 @@ object MainView : Komponent(), CssName {
ExpKnobComponent(
value = VstChipWorklet.amModFreq,
label = "AM Freq",
minValue = 0.005,
minValue = 0.0,
maxValue = 1.0,
step = 5.0 / 127.0,
width = 100,
@@ -307,7 +313,7 @@ object MainView : Komponent(), CssName {
ExpKnobComponent(
value = VstChipWorklet.amModAmp,
label = "AM Ampl",
minValue = 0.005,
minValue = 0.0,
maxValue = 1.0,
step = 5.0 / 127.0,
width = 100,
@@ -320,7 +326,7 @@ object MainView : Komponent(), CssName {
ExpKnobComponent(
value = VstChipWorklet.feedback,
label = "Feedback",
minValue = 0.005,
minValue = 0.0,
maxValue = 1.0,
step = 5.0 / 127.0,
width = 100,
@@ -333,7 +339,7 @@ object MainView : Komponent(), CssName {
ExpKnobComponent(
value = VstChipWorklet.delay,
label = "Delay",
minValue = 0.005,
minValue = 0.0,
maxValue = 1.0,
step = 5.0 / 127.0,
width = 100,
@@ -346,7 +352,7 @@ object MainView : Komponent(), CssName {
ExpKnobComponent(
value = VstChipWorklet.delayDepth,
label = "Delay depth",
minValue = 0.005,
minValue = 0.0,
maxValue = 1.0,
step = 5.0 / 127.0,
width = 100,
@@ -361,26 +367,26 @@ object MainView : Komponent(), CssName {
ExpKnobComponent(
value = VstChipWorklet.attack,
label = "Attack",
minValue = 0.005,
maxValue = 1.0,
step = 5.0 / 127.0,
minValue = 0.0,
maxValue = 5.0,
step = 25.0 / 127.0,
width = 100,
height = 120,
) { value ->
VstChipWorklet.attack = value
VstChipWorklet.attack = value / 5.0
}
)
include(
ExpKnobComponent(
value = VstChipWorklet.decay,
label = "Decay",
minValue = 0.005,
maxValue = 1.0,
step = 5.0 / 127.0,
minValue = 0.0,
maxValue = 5.0,
step = 25.0 / 127.0,
width = 100,
height = 120,
) { value ->
VstChipWorklet.decay = value
VstChipWorklet.decay = value / 5.0
}
)
include(
@@ -400,13 +406,13 @@ object MainView : Komponent(), CssName {
ExpKnobComponent(
value = VstChipWorklet.release,
label = "Release",
minValue = 0.005,
maxValue = 1.0,
step = 5.0 / 127.0,
minValue = 0.0,
maxValue = 5.0,
step = 25.0 / 127.0,
width = 100,
height = 120,
) { value ->
VstChipWorklet.release = value
VstChipWorklet.release = value / 5.0
}
)
}