Also search on name when setting midi port

This commit is contained in:
2024-07-13 16:44:33 +02:00
parent f2269c8865
commit 8df6a4fff6
45 changed files with 2387 additions and 934 deletions

View File

@@ -1,34 +0,0 @@
package nl.astraeus.vst.chip
import kotlin.js.JsName
data class PatchDTO(
@JsName("waveform")
val waveform: Int = 0,
@JsName("midiId")
val midiId: String = "",
@JsName("midiName")
val midiName: String = "",
@JsName("midiChannel")
var midiChannel: Int = 0,
@JsName("volume")
var volume: Double = 0.75,
@JsName("dutyCycle")
var dutyCycle: Double = 0.5,
@JsName("fmModFreq")
var fmModFreq: Double = 0.0,
@JsName("fmModAmp")
var fmModAmp: Double = 0.0,
@JsName("amModFreq")
var amModFreq: Double = 0.0,
@JsName("amModAmp")
var amModAmp: Double = 0.0,
@JsName("attack")
var attack: Double = 0.1,
@JsName("decay")
var decay: Double = 0.2,
@JsName("sustain")
var sustain: Double = 0.5,
@JsName("release")
var release: Double = 0.2,
)

View File

@@ -0,0 +1,24 @@
package nl.astraeus.vst.string
import kotlin.js.ExperimentalJsExport
import kotlin.js.JsExport
import kotlin.js.JsName
@ExperimentalJsExport
@JsExport
data class PatchDTO(
@JsName("midiId")
val midiId: String = "",
@JsName("midiName")
val midiName: String = "",
@JsName("midiChannel")
var midiChannel: Int = 0,
@JsName("volume")
var volume: Double = 0.75,
@JsName("damping")
var damping: Double = 0.5,
@JsName("delay")
var delay: Double = 0.0,
@JsName("delayDepth")
var delayDepth: Double = 0.0,
)

View File

@@ -1,4 +1,4 @@
package nl.astraeus.vst.chip.logger
package nl.astraeus.vst.string.logger
val log = Logger

View File

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

View File

@@ -1,203 +0,0 @@
package nl.astraeus.vst.chip.audio
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",
"vst-chip-processor"
) {
var waveform: Int = 0
set(value) {
field = value
postMessage("waveform\n$value")
}
var midiChannel = 0
set(value) {
check(value in 0..15) {
"Midi channel must be between 0 and 15."
}
field = value
postMessage("set_channel\n${midiChannel}")
}
var volume = 0.75
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 7, (value * 127).toInt())
)
}
var dutyCycle = 0.5
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 0x47, (value * 127).toInt())
)
}
var fmModFreq = 0.0
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 0x4a, (value * 127).toInt())
)
}
var fmModAmp = 0.0
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 0x4b, (value * 127).toInt())
)
}
var amModFreq = 0.0
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 0x4c, (value * 127).toInt())
)
}
var amModAmp = 0.0
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 0x4d, (value * 127).toInt())
)
}
var attack = 0.1
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 0x49, (value * 127).toInt())
)
}
var decay = 0.2
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 0x4b, (value * 127).toInt())
)
}
var sustain = 0.5
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 0x46, (value * 127).toInt())
)
}
var release = 0.2
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 0x48, (value * 127).toInt())
)
}
var recording: Float32Array? = null
override fun onMessage(message: MessageEvent) {
//console.log("Message from worklet: ", message)
val data = message.data
if (data is Float32Array) {
this.recording = data
WaveformView.requestUpdate()
}
}
fun postDirectlyToWorklet(msg: Any) {
super.postMessage(msg)
}
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]
handleIncomingMidi(knob, value)
} else {
super.postMessage(msg)
}
} else {
super.postMessage(msg)
}
}
private fun handleIncomingMidi(knob: Byte, value: Byte) {
when (knob) {
0x46.toByte() -> {
volume = value / 127.0
MainView.requestUpdate()
}
0x4a.toByte() -> {
dutyCycle = value / 127.0
MainView.requestUpdate()
}
0x4b.toByte() -> {
fmModFreq = value / 127.0
MainView.requestUpdate()
}
0x4c.toByte() -> {
fmModAmp = value / 127.0
MainView.requestUpdate()
}
0x47.toByte() -> {
amModFreq = value / 127.0
MainView.requestUpdate()
}
0x48.toByte() -> {
amModAmp = value / 127.0
MainView.requestUpdate()
}
}
}
fun load(patch: PatchDTO) {
waveform = patch.waveform
midiChannel = patch.midiChannel
volume = patch.volume
dutyCycle = patch.dutyCycle
fmModFreq = patch.fmModFreq
fmModAmp = patch.fmModAmp
amModFreq = patch.amModFreq
amModAmp = patch.amModAmp
attack = patch.attack
decay = patch.decay
sustain = patch.sustain
release = patch.release
}
fun save(): PatchDTO {
return PatchDTO(
waveform = waveform,
midiChannel = midiChannel,
volume = volume,
dutyCycle = dutyCycle,
fmModFreq = fmModFreq,
fmModAmp = fmModAmp,
amModFreq = amModFreq,
amModAmp = amModAmp,
attack = attack,
decay = decay,
sustain = sustain,
release = release
)
}
}

View File

@@ -1,4 +1,4 @@
package nl.astraeus.vst.chip
package nl.astraeus.vst.string
external class AudioContext {
var sampleRate: Int

View File

@@ -1,12 +1,12 @@
package nl.astraeus.vst.chip
package nl.astraeus.vst.string
import kotlinx.browser.document
import nl.astraeus.komp.Komponent
import nl.astraeus.komp.UnsafeMode
import nl.astraeus.vst.chip.logger.log
import nl.astraeus.vst.chip.midi.Midi
import nl.astraeus.vst.chip.view.MainView
import nl.astraeus.vst.chip.ws.WebsocketClient
import nl.astraeus.vst.string.logger.log
import nl.astraeus.vst.string.midi.Midi
import nl.astraeus.vst.string.view.MainView
import nl.astraeus.vst.string.ws.WebsocketClient
import nl.astraeus.vst.ui.css.CssSettings
fun main() {

View File

@@ -0,0 +1,10 @@
package nl.astraeus.vst.string.audio
import nl.astraeus.vst.string.AudioContext
object AudioContextHandler {
val audioContext: dynamic = AudioContext()
}

View File

@@ -1,8 +1,8 @@
package nl.astraeus.vst.chip.audio
package nl.astraeus.vst.string.audio
import nl.astraeus.vst.chip.AudioWorkletNode
import nl.astraeus.vst.chip.AudioWorkletNodeParameters
import nl.astraeus.vst.chip.audio.AudioContextHandler.audioContext
import nl.astraeus.vst.string.AudioWorkletNode
import nl.astraeus.vst.string.AudioWorkletNodeParameters
import nl.astraeus.vst.string.audio.AudioContextHandler.audioContext
import org.w3c.dom.MessageEvent
import org.w3c.dom.MessagePort

View File

@@ -0,0 +1,123 @@
@file:OptIn(ExperimentalJsExport::class)
package nl.astraeus.vst.string.audio
import nl.astraeus.vst.string.PatchDTO
import nl.astraeus.vst.string.view.MainView
import nl.astraeus.vst.string.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 VstStringWorklet : AudioNode(
"/vst-string-worklet.js",
"vst-string-processor"
) {
var midiChannel = 0
set(value) {
check(value in 0..15) {
"Midi channel must be between 0 and 15."
}
field = value
postMessage("set_channel\n${midiChannel}")
}
var volume = 0.75
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 7, (value * 127).toInt())
)
}
var damping = 0.996
set(value) {
field = value
super.postMessage(
uInt8ArrayOf(0xb0 + midiChannel, 0x47, ((value - 0.8) * 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())
)
}
var recording: Float32Array? = null
override fun onMessage(message: MessageEvent) {
//console.log("Message from worklet: ", message)
val data = message.data
if (data is Float32Array) {
this.recording = data
WaveformView.requestUpdate()
}
}
fun postDirectlyToWorklet(msg: Any) {
super.postMessage(msg)
}
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]
handleIncomingMidi(knob, value)
} else {
super.postMessage(msg)
}
} else {
super.postMessage(msg)
}
}
private fun handleIncomingMidi(knob: Byte, value: Byte) {
when (knob) {
0x46.toByte() -> {
volume = value / 127.0
MainView.requestUpdate()
}
0x4a.toByte() -> {
damping = value / 127.0
MainView.requestUpdate()
}
}
}
fun load(patch: PatchDTO) {
midiChannel = patch.midiChannel
volume = patch.volume
damping = patch.damping
delay = patch.delay
delayDepth = patch.delayDepth
}
fun save(): PatchDTO {
return PatchDTO(
midiChannel = midiChannel,
volume = volume,
damping = damping,
delay = delay,
delayDepth = delayDepth,
)
}
}

View File

@@ -1,6 +1,6 @@
@file:OptIn(ExperimentalJsExport::class)
package nl.astraeus.vst.chip.midi
package nl.astraeus.vst.string.midi
import kotlinx.browser.window
import org.khronos.webgl.Uint8Array

View File

@@ -1,8 +1,8 @@
package nl.astraeus.vst.chip.midi
package nl.astraeus.vst.string.midi
import kotlinx.browser.window
import nl.astraeus.vst.chip.audio.VstChipWorklet
import nl.astraeus.vst.chip.view.MainView
import nl.astraeus.vst.string.audio.VstStringWorklet
import nl.astraeus.vst.string.view.MainView
import org.khronos.webgl.Uint8Array
import org.khronos.webgl.get
@@ -125,7 +125,7 @@ object Midi {
hex.append(" ")
}
console.log("Midi message:", hex)
VstChipWorklet.postMessage(
VstStringWorklet.postMessage(
message.data
)
}

View File

@@ -1,9 +1,8 @@
package nl.astraeus.vst.chip.view
@file:OptIn(ExperimentalJsExport::class)
package nl.astraeus.vst.string.view
import kotlinx.browser.window
import kotlinx.html.InputType
import kotlinx.html.canvas
import kotlinx.html.classes
import kotlinx.html.div
import kotlinx.html.h1
import kotlinx.html.input
@@ -32,72 +31,30 @@ import nl.astraeus.css.style.Style
import nl.astraeus.css.style.cls
import nl.astraeus.komp.HtmlBuilder
import nl.astraeus.komp.Komponent
import nl.astraeus.komp.currentElement
import nl.astraeus.vst.chip.audio.VstChipWorklet
import nl.astraeus.vst.chip.audio.VstChipWorklet.midiChannel
import nl.astraeus.vst.chip.midi.Midi
import nl.astraeus.vst.chip.ws.WebsocketClient
import nl.astraeus.vst.ui.components.KnobComponent
import nl.astraeus.vst.string.PhysicalString
import nl.astraeus.vst.string.audio.VstStringWorklet
import nl.astraeus.vst.string.audio.VstStringWorklet.midiChannel
import nl.astraeus.vst.string.midi.Midi
import nl.astraeus.vst.string.ws.WebsocketClient
import nl.astraeus.vst.ui.components.ExpKnobComponent
import nl.astraeus.vst.ui.css.Css
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
import org.w3c.dom.HTMLInputElement
import org.w3c.dom.HTMLSelectElement
object WaveformView: Komponent() {
init {
window.requestAnimationFrame(::onAnimationFrame)
}
fun onAnimationFrame(time: Double) {
if (MainView.started) {
VstChipWorklet.postMessage("start_recording")
}
window.requestAnimationFrame(::onAnimationFrame)
}
override fun HtmlBuilder.render() {
div {
if (VstChipWorklet.recording != null) {
canvas {
width = "1000"
height = "400"
val ctx = (currentElement() as? HTMLCanvasElement)?.getContext("2d") as? CanvasRenderingContext2D
val data = VstChipWorklet.recording
if (ctx != null && data != null) {
val width = ctx.canvas.width.toDouble()
val height = ctx.canvas.height.toDouble()
val halfHeight = height / 2.0
ctx.lineWidth = 2.0
ctx.clearRect(0.0, 0.0, width, height)
val step = 1000.0 / data.length
ctx.beginPath()
ctx.strokeStyle = "rgba(0, 255, 255, 0.5)"
ctx.moveTo(0.0, halfHeight)
for (i in 0 until data.length) {
ctx.lineTo(i * step, halfHeight - data[i] * halfHeight)
}
ctx.stroke()
}
}
}
}
}
}
object MainView : Komponent(), CssName {
private var messages: MutableList<String> = ArrayList()
var started = false
val playString = PhysicalStringView(
PhysicalString(
sampleRate = 48000,
damping = 0.996,
)
)
init {
css()
@@ -119,7 +76,7 @@ object MainView : Komponent(), CssName {
div(StartButtonCss.name) {
+"START"
onClickFunction = {
VstChipWorklet.create {
VstStringWorklet.create {
started = true
requestUpdate()
WebsocketClient.send("LOAD\n")
@@ -130,7 +87,7 @@ object MainView : Komponent(), CssName {
}
}
h1 {
+"VST Chip"
+"VST Guitar"
}
div {
span {
@@ -162,11 +119,11 @@ object MainView : Komponent(), CssName {
+"channel:"
input {
type = InputType.number
value = VstChipWorklet.midiChannel.toString()
value = midiChannel.toString()
onInputFunction = { event ->
val target = event.target as HTMLInputElement
println("onInput channel: $target")
VstChipWorklet.midiChannel = target.value.toInt()
VstStringWorklet.midiChannel = target.value.toInt()
}
}
}
@@ -175,7 +132,7 @@ object MainView : Komponent(), CssName {
span(ButtonBarCss.name) {
+"SAVE"
onClickFunction = {
val patch = VstChipWorklet.save().copy(
val patch = VstStringWorklet.save().copy(
midiId = Midi.currentInput?.id ?: "",
midiName = Midi.currentInput?.name ?: ""
)
@@ -186,189 +143,29 @@ object MainView : Komponent(), CssName {
span(ButtonBarCss.name) {
+"STOP"
onClickFunction = {
VstChipWorklet.postDirectlyToWorklet(
VstStringWorklet.postDirectlyToWorklet(
uInt8ArrayOf(0xb0 + midiChannel, 123, 0)
)
}
}
}
div {
span(ButtonBarCss.name) {
+"Sine"
if (VstChipWorklet.waveform == 0) {
classes += SelectedCss.name
}
onClickFunction = {
VstChipWorklet.waveform = 0
requestUpdate()
}
}
span(ButtonBarCss.name) {
+"Square"
if (VstChipWorklet.waveform == 1) {
classes += SelectedCss.name
}
onClickFunction = {
VstChipWorklet.waveform = 1
requestUpdate()
}
}
span(ButtonBarCss.name) {
+"Triangle"
if (VstChipWorklet.waveform == 2) {
classes += SelectedCss.name
}
onClickFunction = {
VstChipWorklet.waveform = 2
requestUpdate()
}
}
span(ButtonBarCss.name) {
+"Sawtooth"
if (VstChipWorklet.waveform == 3) {
classes += SelectedCss.name
}
onClickFunction = {
VstChipWorklet.waveform = 3
requestUpdate()
}
}
}
div(ControlsCss.name) {
include(
KnobComponent(
value = VstChipWorklet.volume,
ExpKnobComponent(
value = VstStringWorklet.volume,
label = "Volume",
minValue = 0.0,
minValue = 0.005,
maxValue = 1.0,
step = 2.0 / 127.0,
step = 5.0 / 127.0,
width = 100,
height = 120,
) { value ->
VstChipWorklet.volume = value
}
)
include(
KnobComponent(
value = VstChipWorklet.dutyCycle,
label = "Duty cycle",
minValue = 0.0,
maxValue = 1.0,
step = 2.0 / 127.0,
width = 100,
height = 120,
) { value ->
VstChipWorklet.dutyCycle = value
}
)
include(
KnobComponent(
value = VstChipWorklet.fmModFreq,
label = "FM Freq",
minValue = 0.0,
maxValue = 1.0,
step = 2.0 / 127.0,
width = 100,
height = 120,
) { value ->
VstChipWorklet.fmModFreq = value
}
)
include(
KnobComponent(
value = VstChipWorklet.fmModAmp,
label = "FM Ampl",
minValue = 0.0,
maxValue = 1.0,
step = 2.0 / 127.0,
width = 100,
height = 120,
) { value ->
VstChipWorklet.fmModAmp = value
}
)
include(
KnobComponent(
value = VstChipWorklet.amModFreq,
label = "AM Freq",
minValue = 0.0,
maxValue = 1.0,
step = 2.0 / 127.0,
width = 100,
height = 120,
) { value ->
VstChipWorklet.amModFreq = value
}
)
include(
KnobComponent(
value = VstChipWorklet.amModAmp,
label = "AM Ampl",
minValue = 0.0,
maxValue = 1.0,
step = 2.0 / 127.0,
width = 100,
height = 120,
) { value ->
VstChipWorklet.amModAmp = value
}
)
}
div(ControlsCss.name) {
include(
KnobComponent(
value = VstChipWorklet.attack,
label = "Attack",
minValue = 0.0,
maxValue = 1.0,
step = 2.0 / 127.0,
width = 100,
height = 120,
) { value ->
VstChipWorklet.attack = value
}
)
include(
KnobComponent(
value = VstChipWorklet.decay,
label = "Decay",
minValue = 0.0,
maxValue = 1.0,
step = 2.0 / 127.0,
width = 100,
height = 120,
) { value ->
VstChipWorklet.decay = value
}
)
include(
KnobComponent(
value = VstChipWorklet.sustain,
label = "Sustain",
minValue = 0.0,
maxValue = 1.0,
step = 2.0 / 127.0,
width = 100,
height = 120,
) { value ->
VstChipWorklet.sustain = value
}
)
include(
KnobComponent(
value = VstChipWorklet.release,
label = "Release",
minValue = 0.0,
maxValue = 1.0,
step = 2.0 / 127.0,
width = 100,
height = 120,
) { value ->
VstChipWorklet.release = value
VstStringWorklet.volume = value
}
)
}
include(WaveformView)
include(playString)
}
}

View File

@@ -0,0 +1,109 @@
package nl.astraeus.vst.string.view
import kotlinx.browser.window
import kotlinx.html.canvas
import kotlinx.html.div
import kotlinx.html.js.onClickFunction
import kotlinx.html.span
import nl.astraeus.komp.HtmlBuilder
import nl.astraeus.komp.Komponent
import nl.astraeus.komp.currentElement
import nl.astraeus.vst.Note
import nl.astraeus.vst.string.PhysicalString
import nl.astraeus.vst.string.audio.VstStringWorklet
import nl.astraeus.vst.string.view.MainView.ControlsCss
import nl.astraeus.vst.ui.components.KnobComponent
import nl.astraeus.vst.util.formatDouble
import org.w3c.dom.CanvasRenderingContext2D
import org.w3c.dom.HTMLCanvasElement
class PhysicalStringView(
val string: PhysicalString
) : Komponent() {
var context: CanvasRenderingContext2D? = null
var interval: Int = -1
var lastUpdateTime: Double = window.performance.now()
init {
window.requestAnimationFrame(::onAnimationFrame)
interval = window.setInterval({
if (context?.canvas?.isConnected == true) {
val now: Double = window.performance.now()
val time = now - lastUpdateTime
lastUpdateTime = now
string.update(time)
} else {
window.clearInterval(interval)
}
}, 1)
}
private fun onAnimationFrame(time: Double) {
if (MainView.started) {
draw()
}
window.requestAnimationFrame(::onAnimationFrame)
}
override fun HtmlBuilder.render() {
div {
div(ControlsCss.name) {
include(
KnobComponent(
value = VstStringWorklet.damping,
label = "Damping",
minValue = 0.8,
maxValue = 1.0,
step = 0.2 / 127.0,
width = 100,
height = 120,
renderer = { formatDouble(it, 3) }
) { value ->
VstStringWorklet.damping = value
}
)
}
div {
span {
+"Play C3"
onClickFunction = {
string.pluck(Note.C3, 1.0)
}
}
span {
+"Play C4"
onClickFunction = {
string.pluck(Note.C4, 1.0)
}
}
}
canvas {
width = "1000"
height = "400"
context = (currentElement() as? HTMLCanvasElement)?.getContext("2d") as? CanvasRenderingContext2D
}
}
}
private fun draw() {
val ctx = context
if (ctx != null) {
val width = ctx.canvas.width.toDouble()
val height = ctx.canvas.height.toDouble()
val halfHeight = height / 2.0
ctx.lineWidth = 2.0
ctx.clearRect(0.0, 0.0, width, height)
val step = width / string.length
ctx.beginPath()
ctx.strokeStyle = "rgba(0, 255, 255, 0.5)"
for (i in 0 until string.length) {
ctx.moveTo(i * step, halfHeight)
ctx.lineTo(i * step, halfHeight + string.buffer[i] * halfHeight)
}
ctx.stroke()
}
}
}

View File

@@ -0,0 +1,56 @@
package nl.astraeus.vst.string.view
import kotlinx.browser.window
import kotlinx.html.canvas
import kotlinx.html.div
import nl.astraeus.komp.HtmlBuilder
import nl.astraeus.komp.Komponent
import nl.astraeus.komp.currentElement
import nl.astraeus.vst.string.audio.VstStringWorklet
import org.khronos.webgl.get
import org.w3c.dom.CanvasRenderingContext2D
import org.w3c.dom.HTMLCanvasElement
object WaveformView : Komponent() {
init {
window.requestAnimationFrame(::onAnimationFrame)
}
fun onAnimationFrame(time: Double) {
if (MainView.started) {
VstStringWorklet.postMessage("start_recording")
}
window.requestAnimationFrame(::onAnimationFrame)
}
override fun HtmlBuilder.render() {
div {
if (VstStringWorklet.recording != null) {
canvas {
width = "1000"
height = "400"
val ctx = (currentElement() as? HTMLCanvasElement)?.getContext("2d") as? CanvasRenderingContext2D
val data = VstStringWorklet.recording
if (ctx != null && data != null) {
val width = ctx.canvas.width.toDouble()
val height = ctx.canvas.height.toDouble()
val halfHeight = height / 2.0
ctx.lineWidth = 2.0
ctx.clearRect(0.0, 0.0, width, height)
val step = 1000.0 / data.length
ctx.beginPath()
ctx.strokeStyle = "rgba(0, 255, 255, 0.5)"
ctx.moveTo(0.0, halfHeight)
for (i in 0 until data.length) {
ctx.lineTo(i * step, halfHeight - data[i] * halfHeight)
}
ctx.stroke()
}
}
}
}
}
}

View File

@@ -1,10 +1,10 @@
package nl.astraeus.vst.chip.ws
package nl.astraeus.vst.string.ws
import kotlinx.browser.window
import nl.astraeus.vst.chip.PatchDTO
import nl.astraeus.vst.chip.audio.VstChipWorklet
import nl.astraeus.vst.chip.midi.Midi
import nl.astraeus.vst.chip.view.MainView
import nl.astraeus.vst.string.PatchDTO
import nl.astraeus.vst.string.audio.VstStringWorklet
import nl.astraeus.vst.string.midi.Midi
import nl.astraeus.vst.string.view.MainView
import org.w3c.dom.MessageEvent
import org.w3c.dom.WebSocket
import org.w3c.dom.events.Event
@@ -17,7 +17,7 @@ object WebsocketClient {
close()
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 {
WebSocket("wss://${window.location.hostname}/ws")
}
@@ -87,7 +87,7 @@ object WebsocketClient {
val patch = JSON.parse<PatchDTO>(patchJson)
Midi.setInput(patch.midiId, patch.midiName)
VstChipWorklet.load(patch)
VstStringWorklet.load(patch)
MainView.requestUpdate()
}
}

View File

@@ -1,6 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<body>
<script type="application/javascript" src="vst-chip-worklet-ui.js"></script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
package nl.astraeus.vst.chip
package nl.astraeus.vst.string
import java.security.SecureRandom

View File

@@ -1,4 +1,4 @@
package nl.astraeus.vst.chip
package nl.astraeus.vst.string
import com.zaxxer.hikari.HikariConfig
import io.undertow.Undertow
@@ -6,10 +6,10 @@ import io.undertow.UndertowOptions
import io.undertow.server.session.InMemorySessionManager
import io.undertow.server.session.SessionAttachmentHandler
import io.undertow.server.session.SessionCookieConfig
import nl.astraeus.vst.chip.db.Database
import nl.astraeus.vst.chip.logger.LogLevel
import nl.astraeus.vst.chip.logger.Logger
import nl.astraeus.vst.chip.web.RequestHandler
import nl.astraeus.vst.string.db.Database
import nl.astraeus.vst.string.logger.LogLevel
import nl.astraeus.vst.string.logger.Logger
import nl.astraeus.vst.string.web.RequestHandler
fun main() {
Logger.level = LogLevel.DEBUG

View File

@@ -1,4 +1,4 @@
package nl.astraeus.vst.chip
package nl.astraeus.vst.string
import java.io.File
import java.io.FileInputStream
@@ -6,7 +6,7 @@ import java.util.*
object Settings {
var runningAsRoot: Boolean = false
var port = 9000
var port = 9004
var sslPort = 8443
var connectionTimeout = 30000

View File

@@ -1,7 +1,7 @@
package nl.astraeus.vst.chip.db
package nl.astraeus.vst.string.db
import kotlinx.datetime.Instant
import nl.astraeus.vst.chip.logger.log
import nl.astraeus.vst.string.logger.log
import java.sql.PreparedStatement
import java.sql.ResultSet
import java.sql.Timestamp

View File

@@ -1,4 +1,4 @@
package nl.astraeus.vst.chip.db
package nl.astraeus.vst.string.db
import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource

View File

@@ -1,4 +1,4 @@
package nl.astraeus.vst.chip.db
package nl.astraeus.vst.string.db
interface Entity {
fun getPK(): Array<Any>

View File

@@ -1,6 +1,6 @@
package nl.astraeus.vst.chip.db
package nl.astraeus.vst.string.db
import nl.astraeus.vst.chip.logger.log
import nl.astraeus.vst.string.logger.log
import java.sql.Connection
import java.sql.SQLException
import java.sql.Timestamp

View File

@@ -1,4 +1,4 @@
package nl.astraeus.vst.chip.db
package nl.astraeus.vst.string.db
object PatchDao : BaseDao<PatchEntity>() {

View File

@@ -1,4 +1,4 @@
package nl.astraeus.vst.chip.db
package nl.astraeus.vst.string.db
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant

View File

@@ -1,4 +1,4 @@
package nl.astraeus.vst.chip.db
package nl.astraeus.vst.string.db
import java.sql.ResultSet
import java.sql.Types

View File

@@ -1,4 +1,4 @@
package nl.astraeus.vst.chip.web
package nl.astraeus.vst.string.web
import kotlinx.html.body
import kotlinx.html.head
@@ -14,12 +14,12 @@ fun generateIndex(patch: String?): String {
if (patch == null) {
result.appendHTML(true).html {
head {
title { +"VST Chip" }
title { +"VST String" }
}
body {
script {
type = "application/javascript"
src = "/vst-chip-worklet-ui.js"
src = "/vst-string-worklet-ui.js"
}
}
}

View File

@@ -1,4 +1,4 @@
package nl.astraeus.vst.chip.web
package nl.astraeus.vst.string.web
import io.undertow.Handlers.websocket
import io.undertow.server.HttpHandler
@@ -16,10 +16,10 @@ import io.undertow.websockets.core.BufferedTextMessage
import io.undertow.websockets.core.WebSocketChannel
import io.undertow.websockets.core.WebSockets
import io.undertow.websockets.spi.WebSocketHttpExchange
import nl.astraeus.vst.chip.db.PatchDao
import nl.astraeus.vst.chip.db.PatchEntity
import nl.astraeus.vst.chip.db.transaction
import nl.astraeus.vst.chip.generateId
import nl.astraeus.vst.string.db.PatchDao
import nl.astraeus.vst.string.db.PatchEntity
import nl.astraeus.vst.string.db.transaction
import nl.astraeus.vst.string.generateId
import java.nio.file.Paths
class WebsocketHandler(

View File

@@ -1,4 +1,4 @@
package nl.astraeus.vst.chip.web
package nl.astraeus.vst.string.web
class VstSession(
val patchId: String