Playing with settings
This commit is contained in:
@@ -21,17 +21,20 @@ import kotlin.math.sin
|
|||||||
val POLYPHONICS = 10
|
val POLYPHONICS = 10
|
||||||
val PI2 = PI * 2
|
val PI2 = PI * 2
|
||||||
|
|
||||||
@ExperimentalJsExport
|
|
||||||
@JsExport
|
|
||||||
class PlayingNote(
|
class PlayingNote(
|
||||||
val note: Int,
|
val note: Int,
|
||||||
var velocity: Int = 0
|
var velocity: Int = 0
|
||||||
) {
|
) {
|
||||||
|
val noteObj = Note.fromMidi(note)
|
||||||
|
|
||||||
fun retrigger(velocity: Int) {
|
fun retrigger(velocity: Int) {
|
||||||
this.velocity = velocity
|
this.velocity = velocity
|
||||||
sample = 0
|
sample = 0
|
||||||
noteStart = currentTime
|
noteStart = currentTime
|
||||||
noteRelease = null
|
noteRelease = null
|
||||||
|
for (i in 0 until combDelayBuffer.length) {
|
||||||
|
combDelayBuffer[i] = 0f
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var noteStart = currentTime
|
var noteStart = currentTime
|
||||||
@@ -39,6 +42,7 @@ class PlayingNote(
|
|||||||
var cycleOffset = 0.0
|
var cycleOffset = 0.0
|
||||||
var sample = 0
|
var sample = 0
|
||||||
var actualVolume = 0f
|
var actualVolume = 0f
|
||||||
|
val combDelayBuffer = Float32Array((sampleRate / noteObj.freq).toInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Waveform {
|
enum class Waveform {
|
||||||
@@ -82,6 +86,14 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
|||||||
var recordingSample = 0
|
var recordingSample = 0
|
||||||
var recordingStart = 0
|
var recordingStart = 0
|
||||||
|
|
||||||
|
val rightDelayBuffer = Float32Array(sampleRate)
|
||||||
|
val leftDelayBuffer = Float32Array(sampleRate)
|
||||||
|
var delayIndex = 0
|
||||||
|
var delay = 0.0
|
||||||
|
var delayDepth = 0.0
|
||||||
|
|
||||||
|
var feedback = 0.0
|
||||||
|
|
||||||
init {
|
init {
|
||||||
this.port.onmessage = ::handleMessage
|
this.port.onmessage = ::handleMessage
|
||||||
Note.updateSampleRate(sampleRate)
|
Note.updateSampleRate(sampleRate)
|
||||||
@@ -95,7 +107,7 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
|||||||
try {
|
try {
|
||||||
when (data) {
|
when (data) {
|
||||||
is String -> {
|
is String -> {
|
||||||
when(data) {
|
when (data) {
|
||||||
"start_recording" -> {
|
"start_recording" -> {
|
||||||
port.postMessage(recordingBuffer)
|
port.postMessage(recordingBuffer)
|
||||||
if (recordingState == RecordingState.STOPPED) {
|
if (recordingState == RecordingState.STOPPED) {
|
||||||
@@ -103,6 +115,7 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
|||||||
recordingSample = 0
|
recordingSample = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else ->
|
else ->
|
||||||
if (data.startsWith("set_channel")) {
|
if (data.startsWith("set_channel")) {
|
||||||
val parts = data.split('\n')
|
val parts = data.split('\n')
|
||||||
@@ -113,7 +126,7 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
|||||||
} else if (data.startsWith("waveform")) {
|
} else if (data.startsWith("waveform")) {
|
||||||
val parts = data.split('\n')
|
val parts = data.split('\n')
|
||||||
if (parts.size == 2) {
|
if (parts.size == 2) {
|
||||||
waveform =parts[1].toInt()
|
waveform = parts[1].toInt()
|
||||||
println("Setting waveform: $waveform")
|
println("Setting waveform: $waveform")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -135,7 +148,7 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
|||||||
else ->
|
else ->
|
||||||
console.error("Don't kow how to handle message", message)
|
console.error("Don't kow how to handle message", message)
|
||||||
}
|
}
|
||||||
} catch(e: Exception) {
|
} catch (e: Exception) {
|
||||||
console.log(e.message, e)
|
console.log(e.message, e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -155,7 +168,7 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
|||||||
cmdByte = cmdByte and 0xf0
|
cmdByte = cmdByte and 0xf0
|
||||||
|
|
||||||
//console.log("Received", bytes)
|
//console.log("Received", bytes)
|
||||||
when(cmdByte) {
|
when (cmdByte) {
|
||||||
0x90 -> {
|
0x90 -> {
|
||||||
if (bytes.length == 3) {
|
if (bytes.length == 3) {
|
||||||
val note = bytes[1]
|
val note = bytes[1]
|
||||||
@@ -201,18 +214,19 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
|||||||
dutyCycle = value / 127.0
|
dutyCycle = value / 127.0
|
||||||
}
|
}
|
||||||
|
|
||||||
0x4a -> {
|
0x40 -> {
|
||||||
fmFreq = value / 127.0
|
fmFreq = value / 127.0
|
||||||
}
|
}
|
||||||
|
|
||||||
0x4b -> {
|
0x41 -> {
|
||||||
fmAmp = value / 127.0
|
fmAmp = value / 127.0
|
||||||
}
|
}
|
||||||
|
|
||||||
0x4c -> {
|
0x42 -> {
|
||||||
amFreq = value / 127.0
|
amFreq = value / 127.0
|
||||||
}
|
}
|
||||||
0x4d -> {
|
|
||||||
|
0x43 -> {
|
||||||
amAmp = value / 127.0
|
amAmp = value / 127.0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,6 +246,21 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
|||||||
release = value / 127.0
|
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 -> {
|
123 -> {
|
||||||
for (note in notes) {
|
for (note in notes) {
|
||||||
note?.noteRelease = currentTime
|
note?.noteRelease = currentTime
|
||||||
@@ -280,11 +309,11 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun process (
|
override fun process(
|
||||||
inputs: Array<Array<Float32Array>>,
|
inputs: Array<Array<Float32Array>>,
|
||||||
outputs: Array<Array<Float32Array>>,
|
outputs: Array<Array<Float32Array>>,
|
||||||
parameters: dynamic
|
parameters: dynamic
|
||||||
) : Boolean {
|
): Boolean {
|
||||||
val samples = outputs[0][0].length
|
val samples = outputs[0][0].length
|
||||||
|
|
||||||
val left = outputs[0][0]
|
val left = outputs[0][0]
|
||||||
@@ -304,10 +333,11 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
|||||||
|
|
||||||
for ((index, note) in notes.withIndex()) {
|
for ((index, note) in notes.withIndex()) {
|
||||||
if (note != null) {
|
if (note != null) {
|
||||||
val sampleDelta = Note.fromMidi(note.note).sampleDelta
|
val midiNote = Note.fromMidi(note.note)
|
||||||
|
val sampleDelta = midiNote.sampleDelta
|
||||||
|
|
||||||
for (i in 0 until samples) {
|
for (i in 0 until samples) {
|
||||||
var targetVolume = note.velocity / 127f
|
var targetVolume = note.velocity / 127f * 10f
|
||||||
targetVolume *= ADSR.calculate(
|
targetVolume *= ADSR.calculate(
|
||||||
attack,
|
attack,
|
||||||
decay,
|
decay,
|
||||||
@@ -324,38 +354,64 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var cycleOffset = note.cycleOffset
|
var cycleOffset = note.cycleOffset
|
||||||
val fmModulation = sampleDelta * sin( fmFreq * 20f * PI2 * (note.sample / sampleRate.toDouble())).toFloat() * fmAmp
|
val fmModulation =
|
||||||
val amModulation = 1f + (sin(sampleLength * amFreq * 10f * PI2 * note.sample) * amAmp).toFloat()
|
sampleDelta + (sin(fmFreq * 1000f * PI2 * (note.sample / sampleRate.toDouble())).toFloat() * (100f * fmAmp * sampleDelta))
|
||||||
|
val amModulation =
|
||||||
|
1f + (sin(sampleLength * amFreq * 1000f * PI2 * note.sample) * amAmp).toFloat()
|
||||||
|
|
||||||
cycleOffset = if (cycleOffset < dutyCycle) {
|
cycleOffset = if (cycleOffset < dutyCycle) {
|
||||||
cycleOffset / dutyCycle / 2.0
|
cycleOffset / dutyCycle / 2.0
|
||||||
} else {
|
} else {
|
||||||
0.5 + ((cycleOffset -dutyCycle) / (1.0 - dutyCycle) / 2.0)
|
0.5 + ((cycleOffset - dutyCycle) / (1.0 - dutyCycle) / 2.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
val waveValue: Float = when (waveform) {
|
val waveValue: Float = when (waveform) {
|
||||||
0 -> {
|
0 -> {
|
||||||
sin(cycleOffset * PI2).toFloat()
|
sin(cycleOffset * PI2).toFloat()
|
||||||
}
|
}
|
||||||
|
|
||||||
1 -> {
|
1 -> {
|
||||||
if (cycleOffset < 0.5) { 1f } else { -1f }
|
if (cycleOffset < 0.5) {
|
||||||
|
1f
|
||||||
|
} else {
|
||||||
|
-1f
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
2 -> when {
|
2 -> when {
|
||||||
cycleOffset < 0.25 -> 4 * cycleOffset
|
cycleOffset < 0.25 -> 4 * cycleOffset
|
||||||
cycleOffset < 0.75 -> 2 - 4 * cycleOffset
|
cycleOffset < 0.75 -> 2 - 4 * cycleOffset
|
||||||
else -> 4 * cycleOffset - 4
|
else -> 4 * cycleOffset - 4
|
||||||
}.toFloat()
|
}.toFloat()
|
||||||
|
|
||||||
3 -> {
|
3 -> {
|
||||||
((cycleOffset * 2f) - 1f).toFloat()
|
((cycleOffset * 2f) - 1f).toFloat()
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
if (cycleOffset < 0.5) { 1f } else { -1f }
|
if (cycleOffset < 0.5) {
|
||||||
|
1f
|
||||||
|
} else {
|
||||||
|
-1f
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
left[i] = left[i] + waveValue * note.actualVolume * volume * amModulation
|
left[i] = left[i] + waveValue * note.actualVolume * volume * amModulation
|
||||||
right[i] = right[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
|
||||||
|
|
||||||
|
left[i] = left[i] + (note.combDelayBuffer[delaySampleIndex] * feedback.toFloat())
|
||||||
|
right[i] = right[i] + (note.combDelayBuffer[delaySampleIndex] * feedback.toFloat())
|
||||||
|
|
||||||
|
note.combDelayBuffer[delaySampleIndex] = (left[i] + right[i]) / 2f
|
||||||
|
// end - comb filter delay
|
||||||
|
|
||||||
|
|
||||||
note.cycleOffset += sampleDelta + fmModulation
|
note.cycleOffset += sampleDelta + fmModulation
|
||||||
if (note.cycleOffset > 1f) {
|
if (note.cycleOffset > 1f) {
|
||||||
note.cycleOffset -= 1f
|
note.cycleOffset -= 1f
|
||||||
@@ -370,6 +426,26 @@ 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) {
|
||||||
|
if (delaySamples > 0) {
|
||||||
|
val delaySampleIndex = (delayIndex + sampleRate - delaySamples) % sampleRate
|
||||||
|
|
||||||
|
left[i] = left[i] + (leftDelayBuffer[delaySampleIndex] * delayDepth.toFloat())
|
||||||
|
right[i] = right[i] + (rightDelayBuffer[delaySampleIndex] * delayDepth.toFloat())
|
||||||
|
}
|
||||||
|
|
||||||
|
leftDelayBuffer[delayIndex] = left[i]
|
||||||
|
rightDelayBuffer[delayIndex++] = right[i]
|
||||||
|
delayIndex %= sampleRate
|
||||||
|
}
|
||||||
|
|
||||||
if (recordingState == RecordingState.RECORDING) {
|
if (recordingState == RecordingState.RECORDING) {
|
||||||
for (i in recordingStart until samples) {
|
for (i in recordingStart until samples) {
|
||||||
recordingBuffer[recordingSample] = (left[i] + right[i]) / 2f
|
recordingBuffer[recordingSample] = (left[i] + right[i]) / 2f
|
||||||
|
|||||||
@@ -28,6 +28,22 @@ kotlin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
@OptIn(ExperimentalWasmDsl::class)
|
||||||
|
wasmJs {
|
||||||
|
binaries.executable()
|
||||||
|
browser{
|
||||||
|
distribution {
|
||||||
|
outputDirectory.set(File("$projectDir/web/"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mavenPublication {
|
||||||
|
groupId = group as String
|
||||||
|
pom { name = "${project.name}-wasm-js" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
jvm{
|
jvm{
|
||||||
withJava()
|
withJava()
|
||||||
}
|
}
|
||||||
@@ -37,15 +53,14 @@ kotlin {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":common"))
|
implementation(project(":common"))
|
||||||
//base
|
//base
|
||||||
api("nl.astraeus:kotlin-css-generator:1.0.7")
|
api("nl.astraeus:kotlin-css-generator:1.0.9-SNAPSHOT")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0")
|
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.0")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val jsMain by getting {
|
val jsMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
//base
|
implementation("nl.astraeus:kotlin-komponent:1.2.4-SNAPSHOT")
|
||||||
implementation("nl.astraeus:kotlin-komponent-js:1.2.2")
|
implementation("nl.astraeus:vst-ui-base:1.0.1-SNAPSHOT")
|
||||||
implementation("nl.astraeus:vst-ui-base:1.0.0-SNAPSHOT")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val jsTest by getting {
|
val jsTest by getting {
|
||||||
@@ -53,6 +68,12 @@ kotlin {
|
|||||||
implementation(kotlin("test-js"))
|
implementation(kotlin("test-js"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* val wasmJsMain by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation("nl.astraeus:kotlin-komponent:1.2.4-SNAPSHOT")
|
||||||
|
implementation("nl.astraeus:vst-ui-base:1.0.1-SNAPSHOT")
|
||||||
|
}
|
||||||
|
}*/
|
||||||
val jvmMain by getting {
|
val jvmMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
//base
|
//base
|
||||||
|
|||||||
@@ -5,9 +5,5 @@ allprojects {
|
|||||||
repositories {
|
repositories {
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven("https://reposilite.astraeus.nl/releases")
|
|
||||||
maven {
|
|
||||||
url = uri("https://nexus.astraeus.nl/nexus/content/groups/public")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@file:OptIn(ExperimentalKotlinGradlePluginApi::class)
|
@file:OptIn(ExperimentalKotlinGradlePluginApi::class)
|
||||||
|
|
||||||
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
|
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
|
||||||
|
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
apply(from = "../common.gradle.kts")
|
apply(from = "../common.gradle.kts")
|
||||||
@@ -17,16 +18,19 @@ kotlin {
|
|||||||
}
|
}
|
||||||
browser()
|
browser()
|
||||||
}
|
}
|
||||||
|
@OptIn(ExperimentalWasmDsl::class)
|
||||||
|
wasmJs {
|
||||||
|
browser()
|
||||||
|
mavenPublication {
|
||||||
|
groupId = group as String
|
||||||
|
pom { name = "${project.name}-wasm-js" }
|
||||||
|
}
|
||||||
|
}
|
||||||
jvm()
|
jvm()
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
val commonMain by getting {
|
val commonMain by getting
|
||||||
dependencies {
|
val jsMain by getting
|
||||||
}
|
val wasmJsMain by getting
|
||||||
}
|
|
||||||
val jsMain by getting {
|
|
||||||
dependencies {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
pluginManagement {
|
pluginManagement {
|
||||||
plugins {
|
plugins {
|
||||||
kotlin("multiplatform") version "2.0.20-Beta1"
|
kotlin("multiplatform") version "2.0.20-RC"
|
||||||
id("org.gradle.toolchains.foojay-resolver-convention") version "0.5.0"
|
id("org.gradle.toolchains.foojay-resolver-convention") version "0.5.0"
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
package nl.astraeus.vst.chip
|
package nl.astraeus.vst.chip
|
||||||
|
|
||||||
|
import kotlin.js.ExperimentalJsExport
|
||||||
|
import kotlin.js.JsExport
|
||||||
import kotlin.js.JsName
|
import kotlin.js.JsName
|
||||||
|
|
||||||
|
@ExperimentalJsExport
|
||||||
|
@JsExport
|
||||||
data class PatchDTO(
|
data class PatchDTO(
|
||||||
@JsName("waveform")
|
@JsName("waveform")
|
||||||
val waveform: Int = 0,
|
val waveform: Int = 0,
|
||||||
@@ -31,4 +35,10 @@ data class PatchDTO(
|
|||||||
var sustain: Double = 0.5,
|
var sustain: Double = 0.5,
|
||||||
@JsName("release")
|
@JsName("release")
|
||||||
var release: Double = 0.2,
|
var release: Double = 0.2,
|
||||||
|
@JsName("delay")
|
||||||
|
var delay: Double = 0.0,
|
||||||
|
@JsName("delayDepth")
|
||||||
|
var delayDepth: Double = 0.0,
|
||||||
|
@JsName("feedback")
|
||||||
|
var feedback: Double = 0.0,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -45,28 +45,49 @@ object VstChipWorklet : AudioNode(
|
|||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
super.postMessage(
|
super.postMessage(
|
||||||
uInt8ArrayOf(0xb0 + midiChannel, 0x4a, (value * 127).toInt())
|
uInt8ArrayOf(0xb0 + midiChannel, 0x40, (value * 127).toInt())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
var fmModAmp = 0.0
|
var fmModAmp = 0.0
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
super.postMessage(
|
super.postMessage(
|
||||||
uInt8ArrayOf(0xb0 + midiChannel, 0x4b, (value * 127).toInt())
|
uInt8ArrayOf(0xb0 + midiChannel, 0x41, (value * 127).toInt())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
var amModFreq = 0.0
|
var amModFreq = 0.0
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
super.postMessage(
|
super.postMessage(
|
||||||
uInt8ArrayOf(0xb0 + midiChannel, 0x4c, (value * 127).toInt())
|
uInt8ArrayOf(0xb0 + midiChannel, 0x42, (value * 127).toInt())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
var amModAmp = 0.0
|
var amModAmp = 0.0
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
super.postMessage(
|
super.postMessage(
|
||||||
uInt8ArrayOf(0xb0 + midiChannel, 0x4d, (value * 127).toInt())
|
uInt8ArrayOf(0xb0 + midiChannel, 0x43, (value * 127).toInt())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
var feedback = 0.0
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
super.postMessage(
|
||||||
|
uInt8ArrayOf(0xb0 + midiChannel, 0x50, (value * 127).toInt())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
var delay = 0.0
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
super.postMessage(
|
||||||
|
uInt8ArrayOf(0xb0 + midiChannel, 0x4e, (value * 127).toInt())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
var delayDepth = 0.0
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
super.postMessage(
|
||||||
|
uInt8ArrayOf(0xb0 + midiChannel, 0x4f, (value * 127).toInt())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,22 +167,22 @@ object VstChipWorklet : AudioNode(
|
|||||||
MainView.requestUpdate()
|
MainView.requestUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
0x4b.toByte() -> {
|
0x40.toByte() -> {
|
||||||
fmModFreq = value / 127.0
|
fmModFreq = value / 127.0
|
||||||
MainView.requestUpdate()
|
MainView.requestUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
0x4c.toByte() -> {
|
0x41.toByte() -> {
|
||||||
fmModAmp = value / 127.0
|
fmModAmp = value / 127.0
|
||||||
MainView.requestUpdate()
|
MainView.requestUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
0x47.toByte() -> {
|
0x42.toByte() -> {
|
||||||
amModFreq = value / 127.0
|
amModFreq = value / 127.0
|
||||||
MainView.requestUpdate()
|
MainView.requestUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
0x48.toByte() -> {
|
0x43.toByte() -> {
|
||||||
amModAmp = value / 127.0
|
amModAmp = value / 127.0
|
||||||
MainView.requestUpdate()
|
MainView.requestUpdate()
|
||||||
}
|
}
|
||||||
@@ -181,6 +202,9 @@ object VstChipWorklet : AudioNode(
|
|||||||
decay = patch.decay
|
decay = patch.decay
|
||||||
sustain = patch.sustain
|
sustain = patch.sustain
|
||||||
release = patch.release
|
release = patch.release
|
||||||
|
delay = patch.delay
|
||||||
|
delayDepth = patch.delayDepth
|
||||||
|
feedback = patch.feedback
|
||||||
}
|
}
|
||||||
|
|
||||||
fun save(): PatchDTO {
|
fun save(): PatchDTO {
|
||||||
@@ -196,7 +220,10 @@ object VstChipWorklet : AudioNode(
|
|||||||
attack = attack,
|
attack = attack,
|
||||||
decay = decay,
|
decay = decay,
|
||||||
sustain = sustain,
|
sustain = sustain,
|
||||||
release = release
|
release = release,
|
||||||
|
delay = delay,
|
||||||
|
delayDepth = delayDepth,
|
||||||
|
feedback = feedback
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import nl.astraeus.vst.chip.audio.VstChipWorklet
|
|||||||
import nl.astraeus.vst.chip.audio.VstChipWorklet.midiChannel
|
import nl.astraeus.vst.chip.audio.VstChipWorklet.midiChannel
|
||||||
import nl.astraeus.vst.chip.midi.Midi
|
import nl.astraeus.vst.chip.midi.Midi
|
||||||
import nl.astraeus.vst.chip.ws.WebsocketClient
|
import nl.astraeus.vst.chip.ws.WebsocketClient
|
||||||
|
import nl.astraeus.vst.ui.components.ExpKnobComponent
|
||||||
import nl.astraeus.vst.ui.components.KnobComponent
|
import nl.astraeus.vst.ui.components.KnobComponent
|
||||||
import nl.astraeus.vst.ui.css.Css
|
import nl.astraeus.vst.ui.css.Css
|
||||||
import nl.astraeus.vst.ui.css.Css.defineCss
|
import nl.astraeus.vst.ui.css.Css.defineCss
|
||||||
@@ -236,12 +237,12 @@ object MainView : Komponent(), CssName {
|
|||||||
}
|
}
|
||||||
div(ControlsCss.name) {
|
div(ControlsCss.name) {
|
||||||
include(
|
include(
|
||||||
KnobComponent(
|
ExpKnobComponent(
|
||||||
value = VstChipWorklet.volume,
|
value = VstChipWorklet.volume,
|
||||||
label = "Volume",
|
label = "Volume",
|
||||||
minValue = 0.0,
|
minValue = 0.005,
|
||||||
maxValue = 1.0,
|
maxValue = 1.0,
|
||||||
step = 2.0 / 127.0,
|
step = 5.0 / 127.0,
|
||||||
width = 100,
|
width = 100,
|
||||||
height = 120,
|
height = 120,
|
||||||
) { value ->
|
) { value ->
|
||||||
@@ -262,12 +263,12 @@ object MainView : Komponent(), CssName {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
include(
|
include(
|
||||||
KnobComponent(
|
ExpKnobComponent(
|
||||||
value = VstChipWorklet.fmModFreq,
|
value = VstChipWorklet.fmModFreq,
|
||||||
label = "FM Freq",
|
label = "FM Freq",
|
||||||
minValue = 0.0,
|
minValue = 0.005,
|
||||||
maxValue = 1.0,
|
maxValue = 1.0,
|
||||||
step = 2.0 / 127.0,
|
step = 5.0 / 127.0,
|
||||||
width = 100,
|
width = 100,
|
||||||
height = 120,
|
height = 120,
|
||||||
) { value ->
|
) { value ->
|
||||||
@@ -275,12 +276,12 @@ object MainView : Komponent(), CssName {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
include(
|
include(
|
||||||
KnobComponent(
|
ExpKnobComponent(
|
||||||
value = VstChipWorklet.fmModAmp,
|
value = VstChipWorklet.fmModAmp,
|
||||||
label = "FM Ampl",
|
label = "FM Ampl",
|
||||||
minValue = 0.0,
|
minValue = 0.005,
|
||||||
maxValue = 1.0,
|
maxValue = 1.0,
|
||||||
step = 2.0 / 127.0,
|
step = 5.0 / 127.0,
|
||||||
width = 100,
|
width = 100,
|
||||||
height = 120,
|
height = 120,
|
||||||
) { value ->
|
) { value ->
|
||||||
@@ -288,12 +289,12 @@ object MainView : Komponent(), CssName {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
include(
|
include(
|
||||||
KnobComponent(
|
ExpKnobComponent(
|
||||||
value = VstChipWorklet.amModFreq,
|
value = VstChipWorklet.amModFreq,
|
||||||
label = "AM Freq",
|
label = "AM Freq",
|
||||||
minValue = 0.0,
|
minValue = 0.005,
|
||||||
maxValue = 1.0,
|
maxValue = 1.0,
|
||||||
step = 2.0 / 127.0,
|
step = 5.0 / 127.0,
|
||||||
width = 100,
|
width = 100,
|
||||||
height = 120,
|
height = 120,
|
||||||
) { value ->
|
) { value ->
|
||||||
@@ -301,27 +302,66 @@ object MainView : Komponent(), CssName {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
include(
|
include(
|
||||||
KnobComponent(
|
ExpKnobComponent(
|
||||||
value = VstChipWorklet.amModAmp,
|
value = VstChipWorklet.amModAmp,
|
||||||
label = "AM Ampl",
|
label = "AM Ampl",
|
||||||
minValue = 0.0,
|
minValue = 0.005,
|
||||||
maxValue = 1.0,
|
maxValue = 1.0,
|
||||||
step = 2.0 / 127.0,
|
step = 5.0 / 127.0,
|
||||||
width = 100,
|
width = 100,
|
||||||
height = 120,
|
height = 120,
|
||||||
) { value ->
|
) { value ->
|
||||||
VstChipWorklet.amModAmp = value
|
VstChipWorklet.amModAmp = value
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
include(
|
||||||
|
ExpKnobComponent(
|
||||||
|
value = VstChipWorklet.feedback,
|
||||||
|
label = "Feedback",
|
||||||
|
minValue = 0.005,
|
||||||
|
maxValue = 1.0,
|
||||||
|
step = 5.0 / 127.0,
|
||||||
|
width = 100,
|
||||||
|
height = 120,
|
||||||
|
) { value ->
|
||||||
|
VstChipWorklet.feedback = value
|
||||||
|
}
|
||||||
|
)
|
||||||
|
include(
|
||||||
|
ExpKnobComponent(
|
||||||
|
value = VstChipWorklet.delay,
|
||||||
|
label = "Delay",
|
||||||
|
minValue = 0.005,
|
||||||
|
maxValue = 1.0,
|
||||||
|
step = 5.0 / 127.0,
|
||||||
|
width = 100,
|
||||||
|
height = 120,
|
||||||
|
) { value ->
|
||||||
|
VstChipWorklet.delay = value
|
||||||
|
}
|
||||||
|
)
|
||||||
|
include(
|
||||||
|
ExpKnobComponent(
|
||||||
|
value = VstChipWorklet.delayDepth,
|
||||||
|
label = "Delay depth",
|
||||||
|
minValue = 0.005,
|
||||||
|
maxValue = 1.0,
|
||||||
|
step = 5.0 / 127.0,
|
||||||
|
width = 100,
|
||||||
|
height = 120,
|
||||||
|
) { value ->
|
||||||
|
VstChipWorklet.delayDepth = value
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
div(ControlsCss.name) {
|
div(ControlsCss.name) {
|
||||||
include(
|
include(
|
||||||
KnobComponent(
|
ExpKnobComponent(
|
||||||
value = VstChipWorklet.attack,
|
value = VstChipWorklet.attack,
|
||||||
label = "Attack",
|
label = "Attack",
|
||||||
minValue = 0.0,
|
minValue = 0.005,
|
||||||
maxValue = 1.0,
|
maxValue = 1.0,
|
||||||
step = 2.0 / 127.0,
|
step = 5.0 / 127.0,
|
||||||
width = 100,
|
width = 100,
|
||||||
height = 120,
|
height = 120,
|
||||||
) { value ->
|
) { value ->
|
||||||
@@ -329,12 +369,12 @@ object MainView : Komponent(), CssName {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
include(
|
include(
|
||||||
KnobComponent(
|
ExpKnobComponent(
|
||||||
value = VstChipWorklet.decay,
|
value = VstChipWorklet.decay,
|
||||||
label = "Decay",
|
label = "Decay",
|
||||||
minValue = 0.0,
|
minValue = 0.005,
|
||||||
maxValue = 1.0,
|
maxValue = 1.0,
|
||||||
step = 2.0 / 127.0,
|
step = 5.0 / 127.0,
|
||||||
width = 100,
|
width = 100,
|
||||||
height = 120,
|
height = 120,
|
||||||
) { value ->
|
) { value ->
|
||||||
@@ -355,12 +395,12 @@ object MainView : Komponent(), CssName {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
include(
|
include(
|
||||||
KnobComponent(
|
ExpKnobComponent(
|
||||||
value = VstChipWorklet.release,
|
value = VstChipWorklet.release,
|
||||||
label = "Release",
|
label = "Release",
|
||||||
minValue = 0.0,
|
minValue = 0.005,
|
||||||
maxValue = 1.0,
|
maxValue = 1.0,
|
||||||
step = 2.0 / 127.0,
|
step = 5.0 / 127.0,
|
||||||
width = 100,
|
width = 100,
|
||||||
height = 120,
|
height = 120,
|
||||||
) { value ->
|
) { value ->
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ object WebsocketClient {
|
|||||||
close()
|
close()
|
||||||
|
|
||||||
websocket = if (window.location.hostname.contains("localhost") || window.location.hostname.contains("192.168")) {
|
websocket = if (window.location.hostname.contains("localhost") || window.location.hostname.contains("192.168")) {
|
||||||
WebSocket("ws://${window.location.hostname}:9000/ws")
|
WebSocket("ws://${window.location.hostname}:${window.location.port}/ws")
|
||||||
} else {
|
} else {
|
||||||
WebSocket("wss://${window.location.hostname}/ws")
|
WebSocket("wss://${window.location.hostname}/ws")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user