Save patch

This commit is contained in:
2024-06-30 20:32:43 +02:00
parent 194857d687
commit 976328ed69
24 changed files with 1155 additions and 162 deletions

View File

@@ -2,8 +2,10 @@
package nl.astraeus.vst.chip
import nl.astraeus.vst.ADSR
import nl.astraeus.vst.AudioWorkletProcessor
import nl.astraeus.vst.Note
import nl.astraeus.vst.currentTime
import nl.astraeus.vst.registerProcessor
import nl.astraeus.vst.sampleRate
import org.khronos.webgl.Float32Array
@@ -19,14 +21,6 @@ import kotlin.math.sin
val POLYPHONICS = 10
val PI2 = PI * 2
@ExperimentalJsExport
@JsExport
enum class NoteState {
ON,
RELEASED,
OFF
}
@ExperimentalJsExport
@JsExport
class PlayingNote(
@@ -35,17 +29,15 @@ class PlayingNote(
) {
fun retrigger(velocity: Int) {
this.velocity = velocity
state = NoteState.ON
sample = 0
attackSamples = 2500
releaseSamples = 10000
noteStart = currentTime
noteRelease = null
}
var state = NoteState.OFF
var noteStart = currentTime
var noteRelease: Double? = null
var cycleOffset = 0.0
var sample = 0
var attackSamples = 2500
var releaseSamples = 10000
var actualVolume = 0f
}
@@ -68,11 +60,8 @@ enum class RecordingState {
@JsExport
class VstChipProcessor : AudioWorkletProcessor() {
var midiChannel = 0
val notes = Array(POLYPHONICS) {
PlayingNote(
0
)
}
val notes = Array<PlayingNote?>(POLYPHONICS) { null }
var waveform = Waveform.SINE.ordinal
var volume = 0.75f
var dutyCycle = 0.5
@@ -80,6 +69,12 @@ class VstChipProcessor : AudioWorkletProcessor() {
var fmAmp = 0.0
var amFreq = 0.0
var amAmp = 0.0
var attack = 0.1
var decay = 0.2
var sustain = 0.5
var release = 0.2
val sampleLength = 1 / sampleRate.toDouble()
val recordingBuffer = Float32Array(sampleRate / 60)
@@ -198,27 +193,49 @@ class VstChipProcessor : AudioWorkletProcessor() {
val value = bytes[2]
when (knob) {
0x46 -> {
7 -> {
volume = value / 127f
}
0x4a -> {
dutyCycle = value / 127.0
}
0x4b -> {
fmFreq = value / 127.0
}
0x4c -> {
fmAmp = value / 127.0
}
0x47 -> {
dutyCycle = value / 127.0
}
0x4a -> {
fmFreq = value / 127.0
}
0x4b -> {
fmAmp = value / 127.0
}
0x4c -> {
amFreq = value / 127.0
}
0x4d -> {
amAmp = value / 127.0
}
0x49 -> {
attack = value / 127.0
}
0x4b -> {
decay = value / 127.0
}
0x46 -> {
sustain = value / 127.0
}
0x48 -> {
amAmp = value / 127.0
release = value / 127.0
}
123 -> {
for (note in notes) {
note?.noteRelease = currentTime
}
}
}
}
@@ -238,21 +255,17 @@ class VstChipProcessor : AudioWorkletProcessor() {
private fun noteOn(note: Int, velocity: Int) {
for (i in 0 until POLYPHONICS) {
if (notes[i].note == note) {
notes[i].retrigger(velocity)
if (notes[i]?.note == note) {
notes[i]?.retrigger(velocity)
return
}
}
for (i in 0 until POLYPHONICS) {
if (notes[i].state == NoteState.OFF) {
if (notes[i] == null) {
notes[i] = PlayingNote(
note,
velocity
)
notes[i].state = NoteState.ON
val n = Note.fromMidi(note)
//console.log("Playing note: ${n.sharp} (${n.freq})")
break
}
}
@@ -260,8 +273,8 @@ class VstChipProcessor : AudioWorkletProcessor() {
private fun noteOff(note: Int) {
for (i in 0 until POLYPHONICS) {
if (notes[i].note == note && notes[i].state == NoteState.ON) {
notes[i].state = NoteState.RELEASED
if (notes[i]?.note == note) {
notes[i]?.noteRelease = currentTime
break
}
}
@@ -279,7 +292,7 @@ class VstChipProcessor : AudioWorkletProcessor() {
var lowestNote = 200
for (note in notes) {
if (note.state != NoteState.OFF) {
if (note != null) {
lowestNote = min(lowestNote, note.note)
}
}
@@ -289,23 +302,25 @@ class VstChipProcessor : AudioWorkletProcessor() {
recordingStart = 0
}
for (note in notes) {
if (note.state != NoteState.OFF) {
for ((index, note) in notes.withIndex()) {
if (note != null) {
val sampleDelta = Note.fromMidi(note.note).sampleDelta
for (i in 0 until samples) {
var targetVolume = note.velocity / 127f
if (note.state == NoteState.ON && note.sample < note.attackSamples) {
note.attackSamples--
targetVolume *= ( 1f - (note.attackSamples / 2500f))
} else if (note.state == NoteState.RELEASED) {
note.releaseSamples--
targetVolume *= (note.releaseSamples / 10000f)
}
targetVolume *= ADSR.calculate(
attack,
decay,
sustain,
release,
note.noteStart,
currentTime,
note.noteRelease
).toFloat()
note.actualVolume += (targetVolume - note.actualVolume) * 0.0001f
if (note.state == NoteState.RELEASED && note.actualVolume <= 0) {
note.state = NoteState.OFF
if (note.noteRelease != null && note.actualVolume <= 0.01) {
notes[index] = null
}
var cycleOffset = note.cycleOffset