[orx-delegate-magic, orx-envelopes] Add orx-delegate-magic, orx-envelopes
This commit is contained in:
7
orx-envelopes/README.md
Normal file
7
orx-envelopes/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# orx-envelopes
|
||||
|
||||
ADSR envelopes and tools
|
||||
|
||||
## ADSR
|
||||
|
||||
Attack, decay, sustain, release
|
||||
25
orx-envelopes/build.gradle.kts
Normal file
25
orx-envelopes/build.gradle.kts
Normal file
@@ -0,0 +1,25 @@
|
||||
plugins {
|
||||
org.openrndr.extra.convention.`kotlin-multiplatform`
|
||||
}
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
val commonMain by getting {
|
||||
dependencies {
|
||||
implementation(project(":orx-parameters"))
|
||||
implementation(libs.openrndr.application)
|
||||
implementation(libs.openrndr.draw)
|
||||
implementation(libs.openrndr.filter)
|
||||
implementation(libs.kotlin.reflect)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
val jvmDemo by getting {
|
||||
dependencies {
|
||||
implementation(project(":orx-shapes"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
37
orx-envelopes/src/commonMain/kotlin/ADSR.kt
Normal file
37
orx-envelopes/src/commonMain/kotlin/ADSR.kt
Normal file
@@ -0,0 +1,37 @@
|
||||
package org.openrndr.extra.envelopes
|
||||
|
||||
import org.openrndr.math.mix
|
||||
import kotlin.math.min
|
||||
|
||||
data class ADSR(
|
||||
val attackDuration: Double,
|
||||
val decayDuration: Double,
|
||||
val sustainValue: Double,
|
||||
val releaseDuration: Double
|
||||
) : Envelope{
|
||||
override fun value(t: Double, tOff: Double): Double {
|
||||
return adsr(attackDuration, decayDuration, sustainValue, releaseDuration, t, tOff)
|
||||
}
|
||||
|
||||
override fun isActive(t: Double, tOff: Double): Boolean {
|
||||
return !(t - tOff > releaseDuration)
|
||||
}
|
||||
}
|
||||
|
||||
fun adsr(
|
||||
attackDuration: Double,
|
||||
decayDuration: Double,
|
||||
sustainValue: Double,
|
||||
releaseDuration: Double,
|
||||
t: Double,
|
||||
tOff: Double = 1E10
|
||||
): Double {
|
||||
|
||||
val da = t / attackDuration
|
||||
val dc = (t - attackDuration) / decayDuration
|
||||
|
||||
val vOn = mix(min(1.0, da), sustainValue, dc.coerceIn(0.0..1.0))
|
||||
|
||||
return mix(vOn, 0.0, ((t - tOff) / releaseDuration).coerceIn(0.0..1.0))
|
||||
|
||||
}
|
||||
7
orx-envelopes/src/commonMain/kotlin/Envelope.kt
Normal file
7
orx-envelopes/src/commonMain/kotlin/Envelope.kt
Normal file
@@ -0,0 +1,7 @@
|
||||
package org.openrndr.extra.envelopes
|
||||
|
||||
interface Envelope {
|
||||
fun value(t: Double, tOff: Double): Double
|
||||
|
||||
fun isActive(t: Double, tOff:Double): Boolean
|
||||
}
|
||||
69
orx-envelopes/src/commonMain/kotlin/Tracker.kt
Normal file
69
orx-envelopes/src/commonMain/kotlin/Tracker.kt
Normal file
@@ -0,0 +1,69 @@
|
||||
@file:Suppress("RUNTIME_ANNOTATION_NOT_SUPPORTED")
|
||||
|
||||
package org.openrndr.extra.envelopes
|
||||
|
||||
import org.openrndr.Program
|
||||
import org.openrndr.animatable.Clock
|
||||
import org.openrndr.extra.parameters.DoubleParameter
|
||||
|
||||
class Trigger(val on: Double, var off: Double, val envelope: Envelope)
|
||||
|
||||
class TrackerValue(val time: Double, val value: Double)
|
||||
abstract class Tracker<T : Envelope>(val program: Program) {
|
||||
|
||||
val triggers = mutableListOf<Trigger>()
|
||||
|
||||
|
||||
protected abstract fun createEnvelope(): T
|
||||
|
||||
fun triggerOn() {
|
||||
val t = program.seconds
|
||||
triggers.removeAll { !it.envelope.isActive(t - it.on, it.off - it.on) }
|
||||
triggers.add(Trigger(program.seconds, 1E30, createEnvelope()))
|
||||
}
|
||||
|
||||
fun triggerOff() {
|
||||
val t = program.seconds
|
||||
triggers.removeAll { !it.envelope.isActive(t - it.on, it.off - it.on) }
|
||||
triggers.lastOrNull()?.let {
|
||||
it.off = program.seconds
|
||||
}
|
||||
}
|
||||
|
||||
fun values(): List<TrackerValue> {
|
||||
val t = program.seconds
|
||||
return triggers.mapNotNull {
|
||||
val tOn = t - it.on
|
||||
val tOff = it.off - it.on
|
||||
|
||||
if (it.envelope.isActive(tOn, tOff)) {
|
||||
val v = it.envelope.value(tOn, tOff)
|
||||
|
||||
TrackerValue(t, v)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun value(): Double {
|
||||
return values().sumOf { it.value }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ADSRTracker(program: Program): Tracker<ADSR>(program) {
|
||||
|
||||
@DoubleParameter("attack", 0.0, 20.0, order = 1)
|
||||
var attack: Double = 0.1
|
||||
@DoubleParameter("decay", 0.0, 20.0, order = 2)
|
||||
var decay: Double = 0.1
|
||||
@DoubleParameter("sustain", 0.0, 1.0, order = 3)
|
||||
var sustain: Double = 0.9
|
||||
@DoubleParameter("release", 0.0, 20.0, order = 4)
|
||||
var release: Double = 0.9
|
||||
|
||||
override fun createEnvelope(): ADSR {
|
||||
return ADSR(attack, decay, sustain, release)
|
||||
}
|
||||
}
|
||||
35
orx-envelopes/src/jvmDemo/kotlin/DemoADSRTracker01.kt
Normal file
35
orx-envelopes/src/jvmDemo/kotlin/DemoADSRTracker01.kt
Normal file
@@ -0,0 +1,35 @@
|
||||
import org.openrndr.application
|
||||
import org.openrndr.draw.loadFont
|
||||
import org.openrndr.extra.envelopes.ADSRTracker
|
||||
|
||||
fun main() {
|
||||
application {
|
||||
program {
|
||||
val tracker = ADSRTracker(this)
|
||||
tracker.attack = 1.0
|
||||
tracker.decay = 0.2
|
||||
tracker.sustain = 0.8
|
||||
tracker.release = 2.0
|
||||
|
||||
keyboard.keyDown.listen {
|
||||
if (it.name == "t")
|
||||
tracker.triggerOn()
|
||||
}
|
||||
keyboard.keyUp.listen {
|
||||
if (it.name == "t")
|
||||
tracker.triggerOff()
|
||||
}
|
||||
extend {
|
||||
tracker.values().forEach {
|
||||
drawer.circle(40.0, 40.0, 20.0 * it.value)
|
||||
drawer.translate(40.0, 0.0)
|
||||
}
|
||||
drawer.defaults()
|
||||
drawer.circle(drawer.bounds.center, 100.0 * tracker.value())
|
||||
|
||||
drawer.fontMap = loadFont("demo-data/fonts/IBMPlexMono-Regular.ttf", 16.0)
|
||||
drawer.text("press and hold 't'", 20.0, height - 20.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user