Playing with settings
This commit is contained in:
@@ -21,17 +21,20 @@ import kotlin.math.sin
|
||||
val POLYPHONICS = 10
|
||||
val PI2 = PI * 2
|
||||
|
||||
@ExperimentalJsExport
|
||||
@JsExport
|
||||
class PlayingNote(
|
||||
val note: Int,
|
||||
var velocity: Int = 0
|
||||
) {
|
||||
val noteObj = Note.fromMidi(note)
|
||||
|
||||
fun retrigger(velocity: Int) {
|
||||
this.velocity = velocity
|
||||
sample = 0
|
||||
noteStart = currentTime
|
||||
noteRelease = null
|
||||
for (i in 0 until combDelayBuffer.length) {
|
||||
combDelayBuffer[i] = 0f
|
||||
}
|
||||
}
|
||||
|
||||
var noteStart = currentTime
|
||||
@@ -39,6 +42,7 @@ class PlayingNote(
|
||||
var cycleOffset = 0.0
|
||||
var sample = 0
|
||||
var actualVolume = 0f
|
||||
val combDelayBuffer = Float32Array((sampleRate / noteObj.freq).toInt())
|
||||
}
|
||||
|
||||
enum class Waveform {
|
||||
@@ -82,6 +86,14 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
||||
var recordingSample = 0
|
||||
var recordingStart = 0
|
||||
|
||||
val rightDelayBuffer = Float32Array(sampleRate)
|
||||
val leftDelayBuffer = Float32Array(sampleRate)
|
||||
var delayIndex = 0
|
||||
var delay = 0.0
|
||||
var delayDepth = 0.0
|
||||
|
||||
var feedback = 0.0
|
||||
|
||||
init {
|
||||
this.port.onmessage = ::handleMessage
|
||||
Note.updateSampleRate(sampleRate)
|
||||
@@ -95,7 +107,7 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
||||
try {
|
||||
when (data) {
|
||||
is String -> {
|
||||
when(data) {
|
||||
when (data) {
|
||||
"start_recording" -> {
|
||||
port.postMessage(recordingBuffer)
|
||||
if (recordingState == RecordingState.STOPPED) {
|
||||
@@ -103,6 +115,7 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
||||
recordingSample = 0
|
||||
}
|
||||
}
|
||||
|
||||
else ->
|
||||
if (data.startsWith("set_channel")) {
|
||||
val parts = data.split('\n')
|
||||
@@ -113,7 +126,7 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
||||
} else if (data.startsWith("waveform")) {
|
||||
val parts = data.split('\n')
|
||||
if (parts.size == 2) {
|
||||
waveform =parts[1].toInt()
|
||||
waveform = parts[1].toInt()
|
||||
println("Setting waveform: $waveform")
|
||||
}
|
||||
}
|
||||
@@ -135,7 +148,7 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
||||
else ->
|
||||
console.error("Don't kow how to handle message", message)
|
||||
}
|
||||
} catch(e: Exception) {
|
||||
} catch (e: Exception) {
|
||||
console.log(e.message, e)
|
||||
}
|
||||
}
|
||||
@@ -155,7 +168,7 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
||||
cmdByte = cmdByte and 0xf0
|
||||
|
||||
//console.log("Received", bytes)
|
||||
when(cmdByte) {
|
||||
when (cmdByte) {
|
||||
0x90 -> {
|
||||
if (bytes.length == 3) {
|
||||
val note = bytes[1]
|
||||
@@ -201,18 +214,19 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
||||
dutyCycle = value / 127.0
|
||||
}
|
||||
|
||||
0x4a -> {
|
||||
0x40 -> {
|
||||
fmFreq = value / 127.0
|
||||
}
|
||||
|
||||
0x4b -> {
|
||||
0x41 -> {
|
||||
fmAmp = value / 127.0
|
||||
}
|
||||
|
||||
0x4c -> {
|
||||
0x42 -> {
|
||||
amFreq = value / 127.0
|
||||
}
|
||||
0x4d -> {
|
||||
|
||||
0x43 -> {
|
||||
amAmp = value / 127.0
|
||||
}
|
||||
|
||||
@@ -232,6 +246,21 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
||||
release = value / 127.0
|
||||
}
|
||||
|
||||
0x4e -> {
|
||||
delay = value / 127.0
|
||||
println("Setting delay $delay")
|
||||
}
|
||||
|
||||
0x4f -> {
|
||||
delayDepth = value / 127.0
|
||||
println("Setting delayDepth $delayDepth")
|
||||
}
|
||||
|
||||
0x50 -> {
|
||||
feedback = value / 127.0
|
||||
println("Setting feedback $delayDepth")
|
||||
}
|
||||
|
||||
123 -> {
|
||||
for (note in notes) {
|
||||
note?.noteRelease = currentTime
|
||||
@@ -280,11 +309,11 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun process (
|
||||
inputs: Array<Array<Float32Array>>,
|
||||
outputs: Array<Array<Float32Array>>,
|
||||
parameters: dynamic
|
||||
) : Boolean {
|
||||
override fun process(
|
||||
inputs: Array<Array<Float32Array>>,
|
||||
outputs: Array<Array<Float32Array>>,
|
||||
parameters: dynamic
|
||||
): Boolean {
|
||||
val samples = outputs[0][0].length
|
||||
|
||||
val left = outputs[0][0]
|
||||
@@ -304,10 +333,11 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
||||
|
||||
for ((index, note) in notes.withIndex()) {
|
||||
if (note != null) {
|
||||
val sampleDelta = Note.fromMidi(note.note).sampleDelta
|
||||
val midiNote = Note.fromMidi(note.note)
|
||||
val sampleDelta = midiNote.sampleDelta
|
||||
|
||||
for (i in 0 until samples) {
|
||||
var targetVolume = note.velocity / 127f
|
||||
var targetVolume = note.velocity / 127f * 10f
|
||||
targetVolume *= ADSR.calculate(
|
||||
attack,
|
||||
decay,
|
||||
@@ -324,38 +354,64 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
||||
}
|
||||
|
||||
var cycleOffset = note.cycleOffset
|
||||
val fmModulation = sampleDelta * sin( fmFreq * 20f * PI2 * (note.sample / sampleRate.toDouble())).toFloat() * fmAmp
|
||||
val amModulation = 1f + (sin(sampleLength * amFreq * 10f * PI2 * note.sample) * amAmp).toFloat()
|
||||
val fmModulation =
|
||||
sampleDelta + (sin(fmFreq * 1000f * PI2 * (note.sample / sampleRate.toDouble())).toFloat() * (100f * fmAmp * sampleDelta))
|
||||
val amModulation =
|
||||
1f + (sin(sampleLength * amFreq * 1000f * PI2 * note.sample) * amAmp).toFloat()
|
||||
|
||||
cycleOffset = if (cycleOffset < dutyCycle) {
|
||||
cycleOffset / dutyCycle / 2.0
|
||||
} else {
|
||||
0.5 + ((cycleOffset -dutyCycle) / (1.0 - dutyCycle) / 2.0)
|
||||
0.5 + ((cycleOffset - dutyCycle) / (1.0 - dutyCycle) / 2.0)
|
||||
}
|
||||
|
||||
val waveValue: Float = when (waveform) {
|
||||
0 -> {
|
||||
sin(cycleOffset * PI2).toFloat()
|
||||
}
|
||||
|
||||
1 -> {
|
||||
if (cycleOffset < 0.5) { 1f } else { -1f }
|
||||
if (cycleOffset < 0.5) {
|
||||
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 }
|
||||
if (cycleOffset < 0.5) {
|
||||
1f
|
||||
} else {
|
||||
-1f
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
left[i] = left[i] + waveValue * note.actualVolume * volume * amModulation
|
||||
right[i] = right[i] + waveValue * note.actualVolume * volume * amModulation
|
||||
|
||||
|
||||
// comb filter delay
|
||||
val delaySampleIndex =
|
||||
(note.sample + note.combDelayBuffer.length) % note.combDelayBuffer.length
|
||||
|
||||
left[i] = left[i] + (note.combDelayBuffer[delaySampleIndex] * feedback.toFloat())
|
||||
right[i] = right[i] + (note.combDelayBuffer[delaySampleIndex] * feedback.toFloat())
|
||||
|
||||
note.combDelayBuffer[delaySampleIndex] = (left[i] + right[i]) / 2f
|
||||
// end - comb filter delay
|
||||
|
||||
|
||||
note.cycleOffset += sampleDelta + fmModulation
|
||||
if (note.cycleOffset > 1f) {
|
||||
note.cycleOffset -= 1f
|
||||
@@ -370,6 +426,26 @@ class VstChipProcessor : AudioWorkletProcessor() {
|
||||
}
|
||||
}
|
||||
|
||||
// if sin enable
|
||||
for (i in 0 until samples) {
|
||||
left[i] = sin(left[i] * PI2).toFloat()
|
||||
right[i] = sin(right[i] * PI2).toFloat()
|
||||
}
|
||||
|
||||
val delaySamples = (delay * leftDelayBuffer.length).toInt()
|
||||
for (i in 0 until samples) {
|
||||
if (delaySamples > 0) {
|
||||
val delaySampleIndex = (delayIndex + sampleRate - delaySamples) % sampleRate
|
||||
|
||||
left[i] = left[i] + (leftDelayBuffer[delaySampleIndex] * delayDepth.toFloat())
|
||||
right[i] = right[i] + (rightDelayBuffer[delaySampleIndex] * delayDepth.toFloat())
|
||||
}
|
||||
|
||||
leftDelayBuffer[delayIndex] = left[i]
|
||||
rightDelayBuffer[delayIndex++] = right[i]
|
||||
delayIndex %= sampleRate
|
||||
}
|
||||
|
||||
if (recordingState == RecordingState.RECORDING) {
|
||||
for (i in recordingStart until samples) {
|
||||
recordingBuffer[recordingSample] = (left[i] + right[i]) / 2f
|
||||
|
||||
Reference in New Issue
Block a user