[orx-delegate-magic, orx-envelopes] Add orx-delegate-magic, orx-envelopes
This commit is contained in:
38
orx-delegate-magic/README.md
Normal file
38
orx-delegate-magic/README.md
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# orx-delegate magic
|
||||||
|
|
||||||
|
Collection of magical property delegators
|
||||||
|
|
||||||
|
## Delegated properties
|
||||||
|
|
||||||
|
[Kotlin documentation](https://kotlinlang.org/docs/delegated-properties.html)
|
||||||
|
|
||||||
|
## Property smoothing
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
val state = object {
|
||||||
|
var radius = 10.0
|
||||||
|
}
|
||||||
|
|
||||||
|
val smoothRadius by smoothing(state::radius)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Property dynamics
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
val state = object {
|
||||||
|
var radius = 10.0
|
||||||
|
}
|
||||||
|
|
||||||
|
val dynamicRadius by springForcing(state::radius)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Property tracking
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
val state = object {
|
||||||
|
var radius = 10.0
|
||||||
|
}
|
||||||
|
|
||||||
|
val radiusHistory by tracking(state::radius)
|
||||||
|
```
|
||||||
25
orx-delegate-magic/build.gradle.kts
Normal file
25
orx-delegate-magic/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"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
@file:Suppress("PackageDirectoryMismatch")
|
||||||
|
|
||||||
|
package org.openrndr.extra.delegatemagic.dynamics
|
||||||
|
|
||||||
|
import org.openrndr.Program
|
||||||
|
import org.openrndr.math.LinearType
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
import kotlin.reflect.KProperty0
|
||||||
|
|
||||||
|
class DoublePropertySpringForcer(
|
||||||
|
private val program: Program,
|
||||||
|
private val property: KProperty0<Double>,
|
||||||
|
private val k: Double,
|
||||||
|
private val kProperty: KProperty0<Double>?,
|
||||||
|
private val decay: Double,
|
||||||
|
private val decayProperty: KProperty0<Double>?
|
||||||
|
|
||||||
|
) {
|
||||||
|
private var output: Double? = null
|
||||||
|
private var lastTime: Double? = null
|
||||||
|
private var velocity = 0.0
|
||||||
|
operator fun getValue(any: Any?, property: KProperty<*>): Double {
|
||||||
|
val k = kProperty?.get() ?: k
|
||||||
|
val decay = decayProperty?.get() ?: decay
|
||||||
|
|
||||||
|
val anchor = this.property.get()
|
||||||
|
if (lastTime != null) {
|
||||||
|
val dt = program.seconds - lastTime!!
|
||||||
|
if (dt > 0.0) {
|
||||||
|
val sfY = -k * (output!! - anchor)
|
||||||
|
velocity = velocity * decay + sfY * dt * 10.0
|
||||||
|
output = output!! + velocity * dt * 10.0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
output = this.property.get()
|
||||||
|
}
|
||||||
|
lastTime = program.seconds
|
||||||
|
return output ?: error("no value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LinearTypePropertySpringForcer<T : LinearType<T>>(
|
||||||
|
private val program: Program,
|
||||||
|
private val property: KProperty0<T>,
|
||||||
|
private val k: Double,
|
||||||
|
private val kProperty: KProperty0<Double>?,
|
||||||
|
private val decay: Double,
|
||||||
|
private val decayProperty: KProperty0<Double>?
|
||||||
|
) {
|
||||||
|
private var output: T? = null
|
||||||
|
private var lastTime: Double? = null
|
||||||
|
private var velocity: T? = null
|
||||||
|
operator fun getValue(any: Any?, property: KProperty<*>): T {
|
||||||
|
val k = kProperty?.get() ?: k
|
||||||
|
val decay = decayProperty?.get() ?: decay
|
||||||
|
|
||||||
|
val anchor = this.property.get()
|
||||||
|
if (lastTime != null) {
|
||||||
|
val dt = program.seconds - lastTime!!
|
||||||
|
if (dt > 0.0) {
|
||||||
|
val sfY = (output!! - anchor) * -k
|
||||||
|
|
||||||
|
velocity = if (velocity != null) {
|
||||||
|
velocity!! * decay + sfY * dt * 10.0
|
||||||
|
} else {
|
||||||
|
sfY * dt * 10.0
|
||||||
|
}
|
||||||
|
output = output!! + velocity!! * dt * 10.0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
output = this.property.get()
|
||||||
|
}
|
||||||
|
lastTime = program.seconds
|
||||||
|
return output ?: error("no value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a property spring force delegate
|
||||||
|
* @param property the property that is used as the spring anchor
|
||||||
|
* @param k the spring stiffness
|
||||||
|
* @param kProperty the spring stiffness property, overrides [k]
|
||||||
|
* @param decay velocity decay, best to set to < 1
|
||||||
|
* @param decayProperty velocity decay property, overrides [decay]
|
||||||
|
* @since 0.4.3
|
||||||
|
*/
|
||||||
|
fun Program.springForcing(
|
||||||
|
property: KProperty0<Double>,
|
||||||
|
k: Double = 1.0,
|
||||||
|
kProperty: KProperty0<Double>? = null,
|
||||||
|
decay: Double = 0.9,
|
||||||
|
decayProperty: KProperty0<Double>? = null
|
||||||
|
): DoublePropertySpringForcer {
|
||||||
|
return DoublePropertySpringForcer(
|
||||||
|
program = this,
|
||||||
|
property = property,
|
||||||
|
k = k,
|
||||||
|
kProperty = kProperty,
|
||||||
|
decay = decay,
|
||||||
|
decayProperty = decayProperty
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a property spring force delegate
|
||||||
|
* @param property the property that is used as the spring anchor
|
||||||
|
* @param k the spring stiffness
|
||||||
|
* @param kProperty the spring stiffness property, overrides [k]
|
||||||
|
* @param decay velocity decay, best to set to < 1
|
||||||
|
* @param decayProperty velocity decay property, overrides [decay]
|
||||||
|
* @since 0.4.3
|
||||||
|
*/
|
||||||
|
fun <T : LinearType<T>> Program.springForcing(
|
||||||
|
property: KProperty0<T>,
|
||||||
|
k: Double = 1.0,
|
||||||
|
kProperty: KProperty0<Double>? = null,
|
||||||
|
decay: Double = 0.9,
|
||||||
|
decayProperty: KProperty0<Double>? = null
|
||||||
|
): LinearTypePropertySpringForcer<T> {
|
||||||
|
return LinearTypePropertySpringForcer(
|
||||||
|
program = this,
|
||||||
|
property = property,
|
||||||
|
k = k,
|
||||||
|
kProperty = kProperty,
|
||||||
|
decay = decay,
|
||||||
|
decayProperty = decayProperty
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
@file:Suppress("PackageDirectoryMismatch")
|
||||||
|
|
||||||
|
package org.openrndr.extra.delegatemagic.smoothing
|
||||||
|
|
||||||
|
import org.openrndr.Program
|
||||||
|
import org.openrndr.math.LinearType
|
||||||
|
import kotlin.math.pow
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
import kotlin.reflect.KProperty0
|
||||||
|
|
||||||
|
class DoublePropertySmoother(
|
||||||
|
private val program: Program,
|
||||||
|
private val property: KProperty0<Double>,
|
||||||
|
private val factor: Double = 0.99,
|
||||||
|
private val factorProperty: KProperty0<Double>?
|
||||||
|
) {
|
||||||
|
private var output: Double? = null
|
||||||
|
private var lastTime: Double? = null
|
||||||
|
operator fun getValue(any: Any?, property: KProperty<*>): Double {
|
||||||
|
if (lastTime != null) {
|
||||||
|
val dt = program.seconds - lastTime!!
|
||||||
|
if (dt > 1E-10) {
|
||||||
|
val steps = dt * 60.0
|
||||||
|
val ef = (factorProperty?.get() ?: factor).pow(steps)
|
||||||
|
output = output!! * ef + this.property.get() * (1.0 - ef)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
output = this.property.get()
|
||||||
|
}
|
||||||
|
lastTime = program.seconds
|
||||||
|
return output ?: error("no value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PropertySmoother<T : LinearType<T>>(
|
||||||
|
private val program: Program,
|
||||||
|
private val property: KProperty0<T>,
|
||||||
|
private val factor: Double = 0.99,
|
||||||
|
private val factorProperty: KProperty0<Double>?
|
||||||
|
) {
|
||||||
|
private var output: T? = null
|
||||||
|
private var lastTime: Double? = null
|
||||||
|
operator fun getValue(any: Any?, property: KProperty<*>): T {
|
||||||
|
if (lastTime != null) {
|
||||||
|
val dt = program.seconds - lastTime!!
|
||||||
|
if (dt > 1E-10) {
|
||||||
|
val steps = dt * 60.0
|
||||||
|
val ef = (factorProperty?.get() ?: factor).pow(steps)
|
||||||
|
|
||||||
|
val target = this.property.get()
|
||||||
|
output = output!! * ef + target * (1.0 - ef)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
output = this.property.get()
|
||||||
|
}
|
||||||
|
lastTime = program.seconds
|
||||||
|
return output ?: error("no value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a property smoother delegate
|
||||||
|
* @param property the property to smooth
|
||||||
|
* @param factor the smoothing factor
|
||||||
|
* @since 0.4.3
|
||||||
|
*/
|
||||||
|
fun Program.smoothing(property: KProperty0<Double>, factor: Double = 0.99): DoublePropertySmoother {
|
||||||
|
return DoublePropertySmoother(this, property, factor, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a property smoother delegate
|
||||||
|
* @param property the property to smooth
|
||||||
|
* @param factor the smoothing factor property
|
||||||
|
* @since 0.4.3
|
||||||
|
*/
|
||||||
|
fun Program.smoothing(
|
||||||
|
property: KProperty0<Double>,
|
||||||
|
factor: KProperty0<Double>
|
||||||
|
): DoublePropertySmoother {
|
||||||
|
return DoublePropertySmoother(this, property, 1E10, factor)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a property smoother delegate
|
||||||
|
* @param property the property to smooth
|
||||||
|
* @param factor the smoothing factor
|
||||||
|
* @since 0.4.3
|
||||||
|
*/
|
||||||
|
fun <T : LinearType<T>> Program.smoothing(property: KProperty0<T>, factor: Double = 0.99): PropertySmoother<T> {
|
||||||
|
return PropertySmoother(this, property, factor, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a property smoother delegate
|
||||||
|
* @param property the property to smooth
|
||||||
|
* @param factor the smoothing factor property
|
||||||
|
* @since 0.4.3
|
||||||
|
*/
|
||||||
|
fun <T : LinearType<T>> Program.smoothing(property: KProperty0<T>, factor: KProperty0<Double>): PropertySmoother<T> {
|
||||||
|
return PropertySmoother(this, property, 1E10, factor)
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
@file:Suppress("PackageDirectoryMismatch")
|
||||||
|
|
||||||
|
package org.openrndr.extra.delegatemagic.tracking
|
||||||
|
|
||||||
|
import org.openrndr.Program
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
import kotlin.reflect.KProperty0
|
||||||
|
|
||||||
|
class PropertyTracker<T>(private val program: Program, private val property: KProperty0<T>, val length: Int = 30) {
|
||||||
|
private val track = mutableListOf<T>()
|
||||||
|
private var lastTime: Double? = null
|
||||||
|
|
||||||
|
operator fun getValue(any: Any?, property: KProperty<*>): List<T> {
|
||||||
|
if (lastTime != null) {
|
||||||
|
val dt = program.seconds - lastTime!!
|
||||||
|
if (dt > 1E-10) {
|
||||||
|
track.add(this.property.get())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
track.add(this.property.get())
|
||||||
|
}
|
||||||
|
if (track.size > length) {
|
||||||
|
track.removeAt(0)
|
||||||
|
}
|
||||||
|
lastTime = program.seconds
|
||||||
|
return track
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a property tracker
|
||||||
|
* @param property the property to track
|
||||||
|
* @param length the maximum length of the tracked history
|
||||||
|
* @return a property tracker
|
||||||
|
* @since 0.4.3
|
||||||
|
*/
|
||||||
|
fun <T> Program.tracking(property: KProperty0<T>, length: Int = 30): PropertyTracker<T> {
|
||||||
|
return PropertyTracker(this, property, length)
|
||||||
|
}
|
||||||
29
orx-delegate-magic/src/jvmDemo/kotlin/DemoSmoothing01.kt
Normal file
29
orx-delegate-magic/src/jvmDemo/kotlin/DemoSmoothing01.kt
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import org.openrndr.application
|
||||||
|
import org.openrndr.extra.delegatemagic.smoothing.smoothing
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
fun main() = application {
|
||||||
|
program {
|
||||||
|
val state = object {
|
||||||
|
var x = width / 2.0
|
||||||
|
var y = height / 2.0
|
||||||
|
var radius = 5.0
|
||||||
|
}
|
||||||
|
|
||||||
|
val sx by smoothing(state::x)
|
||||||
|
val sy by smoothing(state::y)
|
||||||
|
val sradius by smoothing(state::radius)
|
||||||
|
extend {
|
||||||
|
if (Random.nextDouble() < 0.01) {
|
||||||
|
state.radius = Random.nextDouble(10.0, 200.0)
|
||||||
|
}
|
||||||
|
if (Random.nextDouble() < 0.01) {
|
||||||
|
state.x = Random.nextDouble(0.0, width.toDouble())
|
||||||
|
}
|
||||||
|
if (Random.nextDouble() < 0.01) {
|
||||||
|
state.y = Random.nextDouble(10.0, height.toDouble())
|
||||||
|
}
|
||||||
|
drawer.circle(sx, sy, sradius)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
33
orx-delegate-magic/src/jvmDemo/kotlin/DemoSpring01.kt
Normal file
33
orx-delegate-magic/src/jvmDemo/kotlin/DemoSpring01.kt
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import org.openrndr.application
|
||||||
|
import org.openrndr.extra.delegatemagic.dynamics.springForcing
|
||||||
|
import org.openrndr.extra.delegatemagic.smoothing.smoothing
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
fun main() = application {
|
||||||
|
program {
|
||||||
|
val state = object {
|
||||||
|
var x = width / 2.0
|
||||||
|
var y = height / 2.0
|
||||||
|
var radius = 5.0
|
||||||
|
}
|
||||||
|
|
||||||
|
val sx by springForcing(state::x, k = 10.0)
|
||||||
|
val sy by springForcing(state::y)
|
||||||
|
val sradius by springForcing(state::radius)
|
||||||
|
extend {
|
||||||
|
if (Random.nextDouble() < 0.01) {
|
||||||
|
state.radius = Random.nextDouble(10.0, 200.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Random.nextDouble() < 0.01) {
|
||||||
|
state.x = Random.nextDouble(0.0, width.toDouble())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Random.nextDouble() < 0.01) {
|
||||||
|
state.y = Random.nextDouble(10.0, height.toDouble())
|
||||||
|
}
|
||||||
|
|
||||||
|
drawer.circle(sx, sy, sradius)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,8 +23,10 @@ include(
|
|||||||
"orx-compositor",
|
"orx-compositor",
|
||||||
"orx-compute-graph",
|
"orx-compute-graph",
|
||||||
"orx-compute-graph-nodes",
|
"orx-compute-graph-nodes",
|
||||||
|
"orx-delegate-magic",
|
||||||
"orx-jvm:orx-dnk3",
|
"orx-jvm:orx-dnk3",
|
||||||
"orx-easing",
|
"orx-easing",
|
||||||
|
"orx-envelopes",
|
||||||
"orx-jvm:orx-expression-evaluator",
|
"orx-jvm:orx-expression-evaluator",
|
||||||
"orx-jvm:orx-file-watcher",
|
"orx-jvm:orx-file-watcher",
|
||||||
"orx-parameters",
|
"orx-parameters",
|
||||||
|
|||||||
Reference in New Issue
Block a user