From 945f4bb01600cdaa017939d9907e10da40ccf86e Mon Sep 17 00:00:00 2001 From: rnentjes Date: Tue, 18 Jun 2024 17:41:22 +0200 Subject: [PATCH] Waveform/dutyCycle --- .../nl/astraeus/vst/chip/ChipProcessor.kt | 61 +++++++++++++++++-- .../commonMain/kotlin/nl/astraeus/vst/Note.kt | 23 +++---- .../kotlin/nl/astraeus/vst/chip/midi/Midi.kt | 10 ++- 3 files changed, 76 insertions(+), 18 deletions(-) diff --git a/audio-worklet/src/jsMain/kotlin/nl/astraeus/vst/chip/ChipProcessor.kt b/audio-worklet/src/jsMain/kotlin/nl/astraeus/vst/chip/ChipProcessor.kt index 3721444..18daa7a 100644 --- a/audio-worklet/src/jsMain/kotlin/nl/astraeus/vst/chip/ChipProcessor.kt +++ b/audio-worklet/src/jsMain/kotlin/nl/astraeus/vst/chip/ChipProcessor.kt @@ -49,6 +49,13 @@ class PlayingNote( var actualVolume = 0f } +enum class Waveform { + SINE, + SQUARE, + TRIANGLE, + SAWTOOTH +} + @ExperimentalJsExport @JsExport class VstChipProcessor : AudioWorkletProcessor() { @@ -57,6 +64,8 @@ class VstChipProcessor : AudioWorkletProcessor() { 0 ) } + var waveform = Waveform.SINE.ordinal + var dutyCycle = 0.5 init { this.port.onmessage = ::handleMessage @@ -117,6 +126,27 @@ class VstChipProcessor : AudioWorkletProcessor() { 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) { + 0x4a -> { + dutyCycle = value / 127.0 + } + } + } + } } } } @@ -175,20 +205,39 @@ class VstChipProcessor : AudioWorkletProcessor() { note.releaseSamples-- targetVolume *= (note.releaseSamples / 10000f) } - note.actualVolume += (targetVolume - note.actualVolume) * 0.005f + note.actualVolume += (targetVolume - note.actualVolume) * 0.001f if (note.state == NoteState.RELEASED && note.actualVolume <= 0) { note.state = NoteState.OFF } - left[i] = left[i] + sin(note.cycleOffset * PI2).toFloat() * note.actualVolume * 0.3f - right[i] = right[i] + sin(note.cycleOffset * PI2).toFloat() * note.actualVolume * 0.3f + val cycleOffset = note.cycleOffset - //left[i] = left[i] + if (note.cycleOffset < 0.5) { 0.3f } else { -0.3f } * note.actualVolume //sin(note.cycleOffset * PI2).toFloat() * note.actualVolume * 0.3f - //right[i] = right[i] + if (note.cycleOffset < 0.5) { 0.3f } else { -0.3f } * note.actualVolume //sin(note.cycleOffset * PI2).toFloat() * note.actualVolume * 0.3f + val waveValue: Float = when (waveform) { + 0 -> { + sin(cycleOffset * PI2).toFloat() + } + 1 -> { + if (cycleOffset < dutyCycle) { 1f } else { -1f } + } + 2 -> when { + cycleOffset < 0.25 -> 4 * cycleOffset + cycleOffset < 0.75 -> 2 - 4 * cycleOffset + else -> 4 * cycleOffset - 4 + }.toFloat() + 3 -> { + ((cycleOffset * 2f) - 1f).toFloat() + } + else -> { + if (cycleOffset < 0.5) { 1f } else { -1f } + } + } + + left[i] = left[i] + waveValue * note.actualVolume * 0.3f + right[i] = right[i] + waveValue * note.actualVolume * 0.3f note.cycleOffset += sampleDelta - if (note.cycleOffset > 1f) { + if (cycleOffset > 1f) { note.cycleOffset -= 1f } } diff --git a/common/src/commonMain/kotlin/nl/astraeus/vst/Note.kt b/common/src/commonMain/kotlin/nl/astraeus/vst/Note.kt index c4507ab..6b5f639 100644 --- a/common/src/commonMain/kotlin/nl/astraeus/vst/Note.kt +++ b/common/src/commonMain/kotlin/nl/astraeus/vst/Note.kt @@ -15,16 +15,16 @@ enum class Note( val sharp: String, val flat: String ) { - NONE("---", "---"), - No02("C--","C--"), - NO03("C#-","Db-"), - NO04("D--","D--"), - NO05("D#-","Eb-"), - NO06("E--","E--"), - NO07("F--","F--"), - NO08("F#-","Gb-"), - NO09("G--","G--"), - NO10("G#-","Ab-"), + NO01("C--","C--"), + NO02("C#-","Db-"), + NO03("D--","D--"), + NO04("D#-","Eb-"), + NO05("E--","E--"), + NO06("F--","F--"), + NO07("F#-","Gb-"), + NO08("G--","G--"), + NO09("G#-","Ab-"), + NO10("A--","A--"), NO11("A#-","Bb-"), NO12("B--","B--"), C0("C-0","C-0"), @@ -148,12 +148,13 @@ enum class Note( //A9("A-9","A-9"), //A9s("A#9","Bb9"), //B9("B-9","B-9"), + NONE("---", "---"), UP("^^^","^^^"), END("XXX","XXX"), ; // 69 = A4.ordinal - val freq: Double = round(440.0 * 2.0.pow((ordinal - 69)/12.0) * 100.0) / 100.0 + val freq: Double = round(440.0 * 2.0.pow((ordinal - 69)/12.0) * 10000.0) / 10000.0 val cycleLength: Double = 1.0 / freq var sampleDelta: Double = 0.0 diff --git a/src/jsMain/kotlin/nl/astraeus/vst/chip/midi/Midi.kt b/src/jsMain/kotlin/nl/astraeus/vst/chip/midi/Midi.kt index 4211319..02ce022 100644 --- a/src/jsMain/kotlin/nl/astraeus/vst/chip/midi/Midi.kt +++ b/src/jsMain/kotlin/nl/astraeus/vst/chip/midi/Midi.kt @@ -3,6 +3,8 @@ package nl.astraeus.vst.chip.midi import kotlinx.browser.window import nl.astraeus.vst.chip.audio.VstChipWorklet import nl.astraeus.vst.chip.view.MainView +import org.khronos.webgl.Uint8Array +import org.khronos.webgl.get external class MIDIInput { val connection: String @@ -77,7 +79,13 @@ object Midi { } currentInput?.onmidimessage = { message -> - console.log("Midi message:", message) + val data = message.data as Uint8Array + val hex = StringBuilder() + for (index in 0 until data.length) { + hex.append(data[index].toString(16)) + hex.append(" ") + } + console.log("Midi message:", hex) VstChipWorklet.postMessage( message.data )