Upgrade Kotlin to 2.3.0, refine MainView, and update dependencies
Updated Kotlin Multiplatform to 2.3.0 for enhanced compatibility and improvements. Streamlined `MainView` with cleaner structure, added responsive scaling, and introduced a `HiddenCss` class. Upgraded various dependencies, including `vst-ui-base` to 2.2.3 and `midi-arrays` to 0.3.6, ensuring better functionality and consistency. Added changes to build task configurations for improved build pipelines.
This commit is contained in:
9
.run/JS.run.xml
Normal file
9
.run/JS.run.xml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="JS" type="JavascriptDebugType" engineId="98ca6316-2f89-46d9-a9e5-fa9e2b0625b3"
|
||||||
|
uri="http://localhost:9005">
|
||||||
|
<method v="2">
|
||||||
|
<option name="Gradle.BeforeRunTask" enabled="false" tasks="buildJS" externalProjectPath="$PROJECT_DIR$" vmOptions=""
|
||||||
|
scriptParameters=""/>
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
@@ -17,11 +17,11 @@
|
|||||||
</ExternalSystemSettings>
|
</ExternalSystemSettings>
|
||||||
<ExternalSystemDebugServerProcess>false</ExternalSystemDebugServerProcess>
|
<ExternalSystemDebugServerProcess>false</ExternalSystemDebugServerProcess>
|
||||||
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||||
|
<ExternalSystemDebugDisabled>false</ExternalSystemDebugDisabled>
|
||||||
<DebugAllEnabled>false</DebugAllEnabled>
|
<DebugAllEnabled>false</DebugAllEnabled>
|
||||||
<RunAsTest>false</RunAsTest>
|
<RunAsTest>false</RunAsTest>
|
||||||
<method v="2">
|
<GradleProfilingDisabled>false</GradleProfilingDisabled>
|
||||||
<option name="Gradle.BeforeRunTask" enabled="true" tasks="clean build" externalProjectPath="$PROJECT_DIR$"
|
<GradleCoverageDisabled>false</GradleCoverageDisabled>
|
||||||
vmOptions="" scriptParameters=""/>
|
<method v="2"/>
|
||||||
</method>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
||||||
@@ -40,7 +40,7 @@ kotlin {
|
|||||||
val commonMain by getting {
|
val commonMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("nl.astraeus:vst-worklet-base:1.0.1")
|
implementation("nl.astraeus:vst-worklet-base:1.0.1")
|
||||||
implementation("nl.astraeus:midi-arrays:0.3.4")
|
implementation("nl.astraeus:midi-arrays:0.3.6")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val jsMain by getting
|
val jsMain by getting
|
||||||
|
|||||||
@@ -5,12 +5,8 @@ package nl.astraeus.vst.chip
|
|||||||
import nl.astraeus.midi.message.SortedTimedMidiMessageList
|
import nl.astraeus.midi.message.SortedTimedMidiMessageList
|
||||||
import nl.astraeus.midi.message.TimedMidiMessage
|
import nl.astraeus.midi.message.TimedMidiMessage
|
||||||
import nl.astraeus.tba.SlicedByteArray
|
import nl.astraeus.tba.SlicedByteArray
|
||||||
import nl.astraeus.vst.ADSR
|
import nl.astraeus.vst.*
|
||||||
import nl.astraeus.vst.AudioWorkletProcessor
|
|
||||||
import nl.astraeus.vst.currentTime
|
|
||||||
import nl.astraeus.vst.midi.MidiMessageHandler
|
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.Float32Array
|
||||||
import org.khronos.webgl.get
|
import org.khronos.webgl.get
|
||||||
import org.khronos.webgl.set
|
import org.khronos.webgl.set
|
||||||
@@ -392,8 +388,8 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
|||||||
val delaySampleIndex =
|
val delaySampleIndex =
|
||||||
(note.sample + note.combDelayBuffer.length) % note.combDelayBuffer.length
|
(note.sample + note.combDelayBuffer.length) % note.combDelayBuffer.length
|
||||||
|
|
||||||
left[i] = left[i] + (note.combDelayBuffer[delaySampleIndex] * feedback.toFloat())
|
//left[i] = left[i] + (note.combDelayBuffer[delaySampleIndex] * feedback.toFloat())
|
||||||
right[i] = right[i] + (note.combDelayBuffer[delaySampleIndex] * feedback.toFloat())
|
//right[i] = right[i] + (note.combDelayBuffer[delaySampleIndex] * feedback.toFloat())
|
||||||
|
|
||||||
note.combDelayBuffer[delaySampleIndex] = (left[i] + right[i]) / 2f
|
note.combDelayBuffer[delaySampleIndex] = (left[i] + right[i]) / 2f
|
||||||
// end - comb filter delay
|
// end - comb filter delay
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ kotlin {
|
|||||||
sourceSets {
|
sourceSets {
|
||||||
val commonMain by getting {
|
val commonMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
api("nl.astraeus:vst-ui-base:2.0.0")
|
api("nl.astraeus:vst-ui-base:2.2.3")
|
||||||
implementation("nl.astraeus:midi-arrays:0.3.4")
|
implementation("nl.astraeus:midi-arrays:0.3.6")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val jsMain by getting
|
val jsMain by getting
|
||||||
@@ -85,6 +85,17 @@ tasks.register<Copy>("buildJS") {
|
|||||||
from(layout.projectDirectory.dir("web2"))
|
from(layout.projectDirectory.dir("web2"))
|
||||||
into(layout.projectDirectory.dir("web"))
|
into(layout.projectDirectory.dir("web"))
|
||||||
}
|
}
|
||||||
|
tasks.register<Copy>("buildJSProd") {
|
||||||
|
duplicatesStrategy = DuplicatesStrategy.INCLUDE
|
||||||
|
dependsOn("audio-worklet:jsBrowserDistribution")
|
||||||
|
dependsOn("jsBrowserDistribution")
|
||||||
|
|
||||||
|
from(layout.projectDirectory.dir("web1"))
|
||||||
|
into(layout.projectDirectory.dir("web"))
|
||||||
|
|
||||||
|
from(layout.projectDirectory.dir("web2"))
|
||||||
|
into(layout.projectDirectory.dir("web"))
|
||||||
|
}
|
||||||
|
|
||||||
/* Hardcoded deploy configuration */
|
/* Hardcoded deploy configuration */
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
group = "nl.astraeus"
|
group = "nl.astraeus"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
pluginManagement {
|
pluginManagement {
|
||||||
plugins {
|
plugins {
|
||||||
kotlin("multiplatform") version "2.1.20"
|
kotlin("multiplatform") version "2.3.0"
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
|
|||||||
@@ -2,34 +2,13 @@
|
|||||||
|
|
||||||
package nl.astraeus.vst.chip.view
|
package nl.astraeus.vst.chip.view
|
||||||
|
|
||||||
|
import kotlinx.browser.document
|
||||||
import kotlinx.browser.window
|
import kotlinx.browser.window
|
||||||
import kotlinx.html.InputType
|
import kotlinx.html.*
|
||||||
import kotlinx.html.canvas
|
|
||||||
import kotlinx.html.classes
|
|
||||||
import kotlinx.html.div
|
|
||||||
import kotlinx.html.h1
|
|
||||||
import kotlinx.html.input
|
|
||||||
import kotlinx.html.js.onChangeFunction
|
import kotlinx.html.js.onChangeFunction
|
||||||
import kotlinx.html.js.onClickFunction
|
import kotlinx.html.js.onClickFunction
|
||||||
import kotlinx.html.js.onInputFunction
|
import kotlinx.html.js.onInputFunction
|
||||||
import kotlinx.html.option
|
import nl.astraeus.css.properties.*
|
||||||
import kotlinx.html.select
|
|
||||||
import kotlinx.html.span
|
|
||||||
import nl.astraeus.css.properties.AlignItems
|
|
||||||
import nl.astraeus.css.properties.BoxSizing
|
|
||||||
import nl.astraeus.css.properties.Display
|
|
||||||
import nl.astraeus.css.properties.FlexDirection
|
|
||||||
import nl.astraeus.css.properties.FontWeight
|
|
||||||
import nl.astraeus.css.properties.JustifyContent
|
|
||||||
import nl.astraeus.css.properties.Position
|
|
||||||
import nl.astraeus.css.properties.Transform
|
|
||||||
import nl.astraeus.css.properties.em
|
|
||||||
import nl.astraeus.css.properties.hsla
|
|
||||||
import nl.astraeus.css.properties.prc
|
|
||||||
import nl.astraeus.css.properties.px
|
|
||||||
import nl.astraeus.css.properties.rem
|
|
||||||
import nl.astraeus.css.properties.vh
|
|
||||||
import nl.astraeus.css.properties.vw
|
|
||||||
import nl.astraeus.css.style.Style
|
import nl.astraeus.css.style.Style
|
||||||
import nl.astraeus.css.style.cls
|
import nl.astraeus.css.style.cls
|
||||||
import nl.astraeus.komp.HtmlBuilder
|
import nl.astraeus.komp.HtmlBuilder
|
||||||
@@ -50,12 +29,9 @@ import nl.astraeus.vst.ui.css.Css.noTextSelect
|
|||||||
import nl.astraeus.vst.ui.css.CssName
|
import nl.astraeus.vst.ui.css.CssName
|
||||||
import nl.astraeus.vst.ui.css.hover
|
import nl.astraeus.vst.ui.css.hover
|
||||||
import org.khronos.webgl.get
|
import org.khronos.webgl.get
|
||||||
import org.w3c.dom.CanvasRenderingContext2D
|
import org.w3c.dom.*
|
||||||
import org.w3c.dom.HTMLCanvasElement
|
|
||||||
import org.w3c.dom.HTMLInputElement
|
|
||||||
import org.w3c.dom.HTMLSelectElement
|
|
||||||
|
|
||||||
object WaveformView: Komponent() {
|
object WaveformView : Komponent() {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
window.requestAnimationFrame(::onAnimationFrame)
|
window.requestAnimationFrame(::onAnimationFrame)
|
||||||
@@ -102,9 +78,11 @@ object WaveformView: Komponent() {
|
|||||||
class MainView : Komponent() {
|
class MainView : Komponent() {
|
||||||
private var messages: MutableList<String> = ArrayList()
|
private var messages: MutableList<String> = ArrayList()
|
||||||
var started = false
|
var started = false
|
||||||
|
var firstRender = true
|
||||||
|
|
||||||
init {
|
init {
|
||||||
css()
|
css()
|
||||||
|
window.addEventListener("resize", { requestUpdate() }, Any())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addMessage(message: String) {
|
fun addMessage(message: String) {
|
||||||
@@ -122,307 +100,333 @@ class MainView : Komponent() {
|
|||||||
|
|
||||||
override fun HtmlBuilder.render() {
|
override fun HtmlBuilder.render() {
|
||||||
div(MainDivCss.name) {
|
div(MainDivCss.name) {
|
||||||
if (!started) {
|
id = "fixed-container"
|
||||||
div(StartSplashCss.name) {
|
style = scaleContainer(currentElement(), 1920, 1080)
|
||||||
div(StartBoxCss.name) {
|
|
||||||
div(StartButtonCss.name) {
|
div(InnerDivCss.name) {
|
||||||
+"START"
|
if (!started) {
|
||||||
|
div(StartSplashCss.name) {
|
||||||
|
div(StartBoxCss.name) {
|
||||||
|
div(StartButtonCss.name) {
|
||||||
|
id = "start-button"
|
||||||
|
+"START"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
onClickFunction = {
|
||||||
onClickFunction = {
|
document.getElementById("start-button")?.classList?.add(HiddenCss.name)
|
||||||
VstChipWorklet.create {
|
VstChipWorklet.create {
|
||||||
started = true
|
started = true
|
||||||
requestUpdate()
|
requestUpdate()
|
||||||
WebsocketClient.send("LOAD\n")
|
WebsocketClient.send("LOAD\n")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
h1 {
|
||||||
h1 {
|
+"VST Chip"
|
||||||
+"VST Chip"
|
}
|
||||||
}
|
div {
|
||||||
div {
|
span {
|
||||||
span {
|
+"Midi input: "
|
||||||
+"Midi input: "
|
select {
|
||||||
select {
|
|
||||||
option {
|
|
||||||
+"None"
|
|
||||||
value = "none"
|
|
||||||
}
|
|
||||||
for (mi in Midi.inputs) {
|
|
||||||
option {
|
option {
|
||||||
+mi.name
|
+"None"
|
||||||
value = mi.id
|
value = "none"
|
||||||
selected = mi.id == Midi.currentInput?.id
|
}
|
||||||
|
for (mi in Midi.inputs) {
|
||||||
|
option {
|
||||||
|
+mi.name
|
||||||
|
value = mi.id
|
||||||
|
selected = mi.id == Midi.currentInput?.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeFunction = { event ->
|
||||||
|
val target = event.target as HTMLSelectElement
|
||||||
|
if (target.value == "none") {
|
||||||
|
Midi.setInput(null)
|
||||||
|
} else {
|
||||||
|
Midi.setInput(target.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
onChangeFunction = { event ->
|
span {
|
||||||
val target = event.target as HTMLSelectElement
|
+"channel:"
|
||||||
if (target.value == "none") {
|
input {
|
||||||
Midi.setInput(null)
|
type = InputType.number
|
||||||
} else {
|
value = VstChipWorklet.midiChannel.toString()
|
||||||
Midi.setInput(target.value)
|
onInputFunction = { event ->
|
||||||
|
val target = event.target as HTMLInputElement
|
||||||
|
println("onInput channel: $target")
|
||||||
|
VstChipWorklet.midiChannel = target.value.toInt()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span {
|
div {
|
||||||
+"channel:"
|
span(ButtonBarCss.name) {
|
||||||
input {
|
+"SAVE"
|
||||||
type = InputType.number
|
onClickFunction = {
|
||||||
value = VstChipWorklet.midiChannel.toString()
|
val patch = VstChipWorklet.save().copy(
|
||||||
onInputFunction = { event ->
|
midiId = Midi.currentInput?.id ?: "",
|
||||||
val target = event.target as HTMLInputElement
|
midiName = Midi.currentInput?.name ?: ""
|
||||||
println("onInput channel: $target")
|
)
|
||||||
VstChipWorklet.midiChannel = target.value.toInt()
|
|
||||||
|
WebsocketClient.send("SAVE\n${JSON.stringify(patch)}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span(ButtonBarCss.name) {
|
||||||
|
+"STOP"
|
||||||
|
onClickFunction = {
|
||||||
|
VstChipWorklet.postDirectlyToWorklet(
|
||||||
|
TimedMidiMessage(getCurrentTime(), (0xb0 + midiChannel).toByte(), 123, 0)
|
||||||
|
.data.buffer.data
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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(
|
||||||
|
ExpKnobComponent(
|
||||||
|
value = VstChipWorklet.volume,
|
||||||
|
label = "Volume",
|
||||||
|
minValue = 0.0,
|
||||||
|
maxValue = 1.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(
|
||||||
|
ExpKnobComponent(
|
||||||
|
value = VstChipWorklet.fmModFreq,
|
||||||
|
label = "FM Freq",
|
||||||
|
minValue = 0.0,
|
||||||
|
maxValue = 2.0,
|
||||||
|
step = 5.0 / 127.0,
|
||||||
|
width = 100,
|
||||||
|
height = 120,
|
||||||
|
) { value ->
|
||||||
|
VstChipWorklet.fmModFreq = value
|
||||||
|
}
|
||||||
|
)
|
||||||
|
include(
|
||||||
|
ExpKnobComponent(
|
||||||
|
value = VstChipWorklet.fmModAmp,
|
||||||
|
label = "FM Ampl",
|
||||||
|
minValue = 0.0,
|
||||||
|
maxValue = 1.0,
|
||||||
|
step = 5.0 / 127.0,
|
||||||
|
width = 100,
|
||||||
|
height = 120,
|
||||||
|
) { value ->
|
||||||
|
VstChipWorklet.fmModAmp = value
|
||||||
|
}
|
||||||
|
)
|
||||||
|
include(
|
||||||
|
ExpKnobComponent(
|
||||||
|
value = VstChipWorklet.amModFreq,
|
||||||
|
label = "AM Freq",
|
||||||
|
minValue = 0.0,
|
||||||
|
maxValue = 1.0,
|
||||||
|
step = 5.0 / 127.0,
|
||||||
|
width = 100,
|
||||||
|
height = 120,
|
||||||
|
) { value ->
|
||||||
|
VstChipWorklet.amModFreq = value
|
||||||
|
}
|
||||||
|
)
|
||||||
|
include(
|
||||||
|
ExpKnobComponent(
|
||||||
|
value = VstChipWorklet.amModAmp,
|
||||||
|
label = "AM Ampl",
|
||||||
|
minValue = 0.0,
|
||||||
|
maxValue = 1.0,
|
||||||
|
step = 5.0 / 127.0,
|
||||||
|
width = 100,
|
||||||
|
height = 120,
|
||||||
|
) { value ->
|
||||||
|
VstChipWorklet.amModAmp = value
|
||||||
|
}
|
||||||
|
)
|
||||||
|
include(
|
||||||
|
ExpKnobComponent(
|
||||||
|
value = VstChipWorklet.feedback,
|
||||||
|
label = "Feedback",
|
||||||
|
minValue = 0.0,
|
||||||
|
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.0,
|
||||||
|
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.0,
|
||||||
|
maxValue = 1.0,
|
||||||
|
step = 5.0 / 127.0,
|
||||||
|
width = 100,
|
||||||
|
height = 120,
|
||||||
|
) { value ->
|
||||||
|
VstChipWorklet.delayDepth = value
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
div(ControlsCss.name) {
|
||||||
|
include(
|
||||||
|
ExpKnobComponent(
|
||||||
|
value = VstChipWorklet.attack,
|
||||||
|
label = "Attack",
|
||||||
|
minValue = 0.0,
|
||||||
|
maxValue = 5.0,
|
||||||
|
step = 25.0 / 127.0,
|
||||||
|
width = 100,
|
||||||
|
height = 120,
|
||||||
|
) { value ->
|
||||||
|
VstChipWorklet.attack = value / 5.0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
include(
|
||||||
|
ExpKnobComponent(
|
||||||
|
value = VstChipWorklet.decay,
|
||||||
|
label = "Decay",
|
||||||
|
minValue = 0.0,
|
||||||
|
maxValue = 5.0,
|
||||||
|
step = 25.0 / 127.0,
|
||||||
|
width = 100,
|
||||||
|
height = 120,
|
||||||
|
) { value ->
|
||||||
|
VstChipWorklet.decay = value / 5.0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
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(
|
||||||
|
ExpKnobComponent(
|
||||||
|
value = VstChipWorklet.release,
|
||||||
|
label = "Release",
|
||||||
|
minValue = 0.0,
|
||||||
|
maxValue = 5.0,
|
||||||
|
step = 25.0 / 127.0,
|
||||||
|
width = 100,
|
||||||
|
height = 120,
|
||||||
|
) { value ->
|
||||||
|
VstChipWorklet.release = value / 5.0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
include(WaveformView)
|
||||||
}
|
}
|
||||||
div {
|
|
||||||
span(ButtonBarCss.name) {
|
|
||||||
+"SAVE"
|
|
||||||
onClickFunction = {
|
|
||||||
val patch = VstChipWorklet.save().copy(
|
|
||||||
midiId = Midi.currentInput?.id ?: "",
|
|
||||||
midiName = Midi.currentInput?.name ?: ""
|
|
||||||
)
|
|
||||||
|
|
||||||
WebsocketClient.send("SAVE\n${JSON.stringify(patch)}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
span(ButtonBarCss.name) {
|
|
||||||
+"STOP"
|
|
||||||
onClickFunction = {
|
|
||||||
VstChipWorklet.postDirectlyToWorklet(
|
|
||||||
TimedMidiMessage(getCurrentTime(), (0xb0 + midiChannel).toByte(), 123, 0)
|
|
||||||
.data.buffer.data
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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(
|
|
||||||
ExpKnobComponent(
|
|
||||||
value = VstChipWorklet.volume,
|
|
||||||
label = "Volume",
|
|
||||||
minValue = 0.0,
|
|
||||||
maxValue = 1.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(
|
|
||||||
ExpKnobComponent(
|
|
||||||
value = VstChipWorklet.fmModFreq,
|
|
||||||
label = "FM Freq",
|
|
||||||
minValue = 0.0,
|
|
||||||
maxValue = 2.0,
|
|
||||||
step = 5.0 / 127.0,
|
|
||||||
width = 100,
|
|
||||||
height = 120,
|
|
||||||
) { value ->
|
|
||||||
VstChipWorklet.fmModFreq = value
|
|
||||||
}
|
|
||||||
)
|
|
||||||
include(
|
|
||||||
ExpKnobComponent(
|
|
||||||
value = VstChipWorklet.fmModAmp,
|
|
||||||
label = "FM Ampl",
|
|
||||||
minValue = 0.0,
|
|
||||||
maxValue = 1.0,
|
|
||||||
step = 5.0 / 127.0,
|
|
||||||
width = 100,
|
|
||||||
height = 120,
|
|
||||||
) { value ->
|
|
||||||
VstChipWorklet.fmModAmp = value
|
|
||||||
}
|
|
||||||
)
|
|
||||||
include(
|
|
||||||
ExpKnobComponent(
|
|
||||||
value = VstChipWorklet.amModFreq,
|
|
||||||
label = "AM Freq",
|
|
||||||
minValue = 0.0,
|
|
||||||
maxValue = 1.0,
|
|
||||||
step = 5.0 / 127.0,
|
|
||||||
width = 100,
|
|
||||||
height = 120,
|
|
||||||
) { value ->
|
|
||||||
VstChipWorklet.amModFreq = value
|
|
||||||
}
|
|
||||||
)
|
|
||||||
include(
|
|
||||||
ExpKnobComponent(
|
|
||||||
value = VstChipWorklet.amModAmp,
|
|
||||||
label = "AM Ampl",
|
|
||||||
minValue = 0.0,
|
|
||||||
maxValue = 1.0,
|
|
||||||
step = 5.0 / 127.0,
|
|
||||||
width = 100,
|
|
||||||
height = 120,
|
|
||||||
) { value ->
|
|
||||||
VstChipWorklet.amModAmp = value
|
|
||||||
}
|
|
||||||
)
|
|
||||||
include(
|
|
||||||
ExpKnobComponent(
|
|
||||||
value = VstChipWorklet.feedback,
|
|
||||||
label = "Feedback",
|
|
||||||
minValue = 0.0,
|
|
||||||
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.0,
|
|
||||||
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.0,
|
|
||||||
maxValue = 1.0,
|
|
||||||
step = 5.0 / 127.0,
|
|
||||||
width = 100,
|
|
||||||
height = 120,
|
|
||||||
) { value ->
|
|
||||||
VstChipWorklet.delayDepth = value
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
div(ControlsCss.name) {
|
|
||||||
include(
|
|
||||||
ExpKnobComponent(
|
|
||||||
value = VstChipWorklet.attack,
|
|
||||||
label = "Attack",
|
|
||||||
minValue = 0.0,
|
|
||||||
maxValue = 5.0,
|
|
||||||
step = 25.0 / 127.0,
|
|
||||||
width = 100,
|
|
||||||
height = 120,
|
|
||||||
) { value ->
|
|
||||||
VstChipWorklet.attack = value / 5.0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
include(
|
|
||||||
ExpKnobComponent(
|
|
||||||
value = VstChipWorklet.decay,
|
|
||||||
label = "Decay",
|
|
||||||
minValue = 0.0,
|
|
||||||
maxValue = 5.0,
|
|
||||||
step = 25.0 / 127.0,
|
|
||||||
width = 100,
|
|
||||||
height = 120,
|
|
||||||
) { value ->
|
|
||||||
VstChipWorklet.decay = value / 5.0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
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(
|
|
||||||
ExpKnobComponent(
|
|
||||||
value = VstChipWorklet.release,
|
|
||||||
label = "Release",
|
|
||||||
minValue = 0.0,
|
|
||||||
maxValue = 5.0,
|
|
||||||
step = 25.0 / 127.0,
|
|
||||||
width = 100,
|
|
||||||
height = 120,
|
|
||||||
) { value ->
|
|
||||||
VstChipWorklet.release = value / 5.0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
include(WaveformView)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun scaleContainer(
|
||||||
|
container: Element,
|
||||||
|
containerWidth: Int,
|
||||||
|
containerHeight: Int,
|
||||||
|
): String {
|
||||||
|
val vpWidth = window.innerWidth
|
||||||
|
val vpHeight = window.innerHeight
|
||||||
|
|
||||||
|
val scaleX: Double = vpWidth / containerWidth.toDouble()
|
||||||
|
val scaleY: Double = vpHeight / containerHeight.toDouble()
|
||||||
|
|
||||||
|
val scale = if (scaleX < scaleY) scaleX else scaleY
|
||||||
|
val left = (vpWidth - containerWidth * scale) / 2
|
||||||
|
val top = (vpHeight - containerHeight * scale) / 2
|
||||||
|
|
||||||
|
return "transform: translate(${left}px, ${top}px) scale($scale);"
|
||||||
|
}
|
||||||
|
|
||||||
companion object MainViewCss : CssName() {
|
companion object MainViewCss : CssName() {
|
||||||
object MainDivCss : CssName()
|
object MainDivCss : CssName()
|
||||||
|
object InnerDivCss : CssName()
|
||||||
object ActiveCss : CssName()
|
object ActiveCss : CssName()
|
||||||
object ButtonCss : CssName()
|
object ButtonCss : CssName()
|
||||||
object ButtonBarCss : CssName()
|
object ButtonBarCss : CssName()
|
||||||
@@ -431,6 +435,7 @@ class MainView : Komponent() {
|
|||||||
object StartSplashCss : CssName()
|
object StartSplashCss : CssName()
|
||||||
object StartBoxCss : CssName()
|
object StartBoxCss : CssName()
|
||||||
object StartButtonCss : CssName()
|
object StartButtonCss : CssName()
|
||||||
|
object HiddenCss : CssName()
|
||||||
object ControlsCss : CssName()
|
object ControlsCss : CssName()
|
||||||
|
|
||||||
private fun css() {
|
private fun css() {
|
||||||
@@ -445,10 +450,12 @@ class MainView : Komponent() {
|
|||||||
select("html", "body") {
|
select("html", "body") {
|
||||||
margin(0.px)
|
margin(0.px)
|
||||||
padding(0.px)
|
padding(0.px)
|
||||||
|
width(100.prc)
|
||||||
height(100.prc)
|
height(100.prc)
|
||||||
|
overflow(Overflow.hidden)
|
||||||
}
|
}
|
||||||
select("html", "body") {
|
select("html", "body") {
|
||||||
backgroundColor(Css.currentStyle.mainBackgroundColor)
|
backgroundColor(Css.currentStyle.mainBackgroundColor.darken(10))
|
||||||
color(Css.currentStyle.mainFontColor)
|
color(Css.currentStyle.mainFontColor)
|
||||||
|
|
||||||
fontFamily("JetbrainsMono, monospace")
|
fontFamily("JetbrainsMono, monospace")
|
||||||
@@ -478,7 +485,17 @@ class MainView : Komponent() {
|
|||||||
minHeight(4.rem)
|
minHeight(4.rem)
|
||||||
}
|
}
|
||||||
select(cls(MainDivCss)) {
|
select(cls(MainDivCss)) {
|
||||||
margin(1.rem)
|
backgroundColor(Css.currentStyle.mainBackgroundColor)
|
||||||
|
width(1920.px)
|
||||||
|
height(1080.px)
|
||||||
|
position(Position.absolute)
|
||||||
|
top(0.px)
|
||||||
|
left(0.px)
|
||||||
|
transformOrigin("0 0")
|
||||||
|
|
||||||
|
select(cls(InnerDivCss)) {
|
||||||
|
padding(1.rem)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
select("select") {
|
select("select") {
|
||||||
plain("appearance", "none")
|
plain("appearance", "none")
|
||||||
@@ -496,17 +513,17 @@ class MainView : Komponent() {
|
|||||||
position(Position.fixed)
|
position(Position.fixed)
|
||||||
left(0.px)
|
left(0.px)
|
||||||
top(0.px)
|
top(0.px)
|
||||||
width(100.vw)
|
width(1920.px)
|
||||||
height(100.vh)
|
height(1080.px)
|
||||||
zIndex(100)
|
zIndex(100)
|
||||||
backgroundColor(hsla(32, 0, 5, 0.65))
|
backgroundColor(hsla(32, 0, 5, 0.65))
|
||||||
|
|
||||||
select(cls(StartBoxCss)) {
|
select(cls(StartBoxCss)) {
|
||||||
position(Position.relative)
|
position(Position.relative)
|
||||||
left(25.vw)
|
left(100.px)
|
||||||
top(25.vh)
|
top(100.px)
|
||||||
width(50.vw)
|
width(1720.px)
|
||||||
height(50.vh)
|
height(880.px)
|
||||||
backgroundColor(hsla(239, 50, 10, 1.0))
|
backgroundColor(hsla(239, 50, 10, 1.0))
|
||||||
borderColor(Css.currentStyle.mainFontColor)
|
borderColor(Css.currentStyle.mainFontColor)
|
||||||
borderWidth(2.px)
|
borderWidth(2.px)
|
||||||
@@ -531,6 +548,9 @@ class MainView : Komponent() {
|
|||||||
padding(1.rem)
|
padding(1.rem)
|
||||||
backgroundColor(Css.currentStyle.mainBackgroundColor)
|
backgroundColor(Css.currentStyle.mainBackgroundColor)
|
||||||
}
|
}
|
||||||
|
select(HiddenCss.cls()) {
|
||||||
|
display(Display.none)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user