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.
This commit is contained in:
@@ -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()")
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -5,12 +5,8 @@ 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",
|
||||
@@ -33,63 +29,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 +93,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()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -138,20 +134,16 @@ object VstChipWorklet : AudioNode(
|
||||
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]
|
||||
override fun postMessage(vararg msg: Int) {
|
||||
if (
|
||||
msg.size == 3
|
||||
&& (msg[0] and 0xf == midiChannel)
|
||||
&& (msg[0] and 0xf0 == 0xb0)
|
||||
) {
|
||||
val knob = msg[1]
|
||||
val value = msg[2]
|
||||
|
||||
handleIncomingMidi(knob, value)
|
||||
} else {
|
||||
super.postMessage(msg)
|
||||
}
|
||||
handleIncomingMidi(knob.toByte(), value.toByte())
|
||||
} else {
|
||||
super.postMessage(msg)
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user