diff --git a/src/main/kotlin/de/moritzruth/dracula_musical/act/Act1.kt b/src/main/kotlin/de/moritzruth/dracula_musical/act/Act1.kt index 0c93e37..a395daa 100644 --- a/src/main/kotlin/de/moritzruth/dracula_musical/act/Act1.kt +++ b/src/main/kotlin/de/moritzruth/dracula_musical/act/Act1.kt @@ -62,19 +62,19 @@ fun ShowBuilderContext.act1() = act("Erster Akt") { } } - scene("Mrs. Hawkins’ Feierabend") { + scene("Hawkins’ Feierabend") { step(StepCue.Text("Lucy", "Heute gehört Mister Harker uns.", "Ende")) { actors { -"Mina" -"Lucy" -"Jonathan" - +"Mrs. Hawkins" + +"Hawkins" // TODO: Expand +"Sekretärinnen" } props { - it[PropPosition.CENTER] = "Mrs. Hawkins’ Stuhl" + it[PropPosition.CENTER] = "Hawkins’ Stuhl" } } @@ -94,7 +94,7 @@ fun ShowBuilderContext.act1() = act("Erster Akt") { step(StepCue.MusicStart("Umbau (Adel ist geil)", 10.seconds)) { actors { - -"Mrs. Hawkins" + -"Hawkins" -"Sekretärinnen" } @@ -114,7 +114,7 @@ fun ShowBuilderContext.act1() = act("Erster Akt") { scene("Die Irrenanstalt") { step(StepCue.MusicEnd) { actors { - +"Mrs. Ascot" + +"Ascot" +"Mina" } @@ -129,7 +129,7 @@ fun ShowBuilderContext.act1() = act("Erster Akt") { } } - step(StepCue.Text("Mrs. Ascot", "Da kommt der Rest der Familie!")) { + step(StepCue.Text("Ascot", "Da kommt der Rest der Familie!")) { actors { +"Oberschwester" // TODO: Expand @@ -142,6 +142,7 @@ fun ShowBuilderContext.act1() = act("Erster Akt") { step(StepCue.Text("Oberschwester", "Sonst kriegst du sie als Zäpfchen!")) { actors { -"Oberschwester" + -"Pflegeteam" -"Die Irren" +"Renfield" +"Vermieterin" @@ -157,7 +158,7 @@ fun ShowBuilderContext.act1() = act("Erster Akt") { -"Wärter 1" -"Wärter 2" -"Dr. Sewart" - -"Mrs. Ascot" + -"Ascot" } } @@ -186,7 +187,7 @@ fun ShowBuilderContext.act1() = act("Erster Akt") { step(StepCue.Text("Mr. Nickelby", "…als du die Vorhänge aufgemacht hast.")) { actors { - +"Mrs. Ascot" + +"Ascot" } onRun { @@ -194,7 +195,7 @@ fun ShowBuilderContext.act1() = act("Erster Akt") { } } - step(StepCue.Text("Mrs. Ascot", "Sie Flötenguru!")) { + step(StepCue.Text("Ascot", "Sie Flötenguru!")) { actors { +"Dr. Sewart" } @@ -215,7 +216,7 @@ fun ShowBuilderContext.act1() = act("Erster Akt") { step(StepCue.Text("Dr. Sewart", "Und dass mir ja die Gardine aufbleibt!")) { actors { -"Dr. Sewart" - -"Mrs. Ascot" + -"Ascot" -"Lucy" -"Mr. Nickelby" -"Mrs. Nickelby" @@ -242,13 +243,13 @@ fun ShowBuilderContext.act1() = act("Erster Akt") { step(StepCue.Text("Mina", "Sehr merkwürdig.")) { actors { - +"Mrs. Ascot" + +"Ascot" } } - step(StepCue.Text("Mrs. Ascot", "Miss Murray!", "beim dritten Mal")) { + step(StepCue.Text("Ascot", "Miss Murray!", "beim dritten Mal")) { actors { - -"Mrs. Ascot" + -"Ascot" } } @@ -256,7 +257,7 @@ fun ShowBuilderContext.act1() = act("Erster Akt") { step(StepCue.Text("Mina", "So markiere ich, was mir gehört.")) { actors { - +"Mrs. Ascot" + +"Ascot" } } @@ -264,14 +265,196 @@ fun ShowBuilderContext.act1() = act("Erster Akt") { actors { -"Mina" -"Jonathan" - -"Mrs. Ascot" + -"Ascot" } leftSpotTarget = null + curtainState = CurtainState.CLOSED onRun { FrontLights.all { it.brightness.off(5.seconds) } } } + + step(StepCue.MusicStart("Umbau (Duett)", 10.seconds)) {} + } + + scene("Kaffeeklatsch") { + step(StepCue.MusicEnd) { + actors { + +"Dr. Sewart" + } + + curtainState = CurtainState.OPEN + rightSpotTarget = "Dr. Sewart" + + onRun { + sidelight.colors.forEach { it.static(Color(hue = 180.degrees, saturation = 10.percent)) } + sidelight.brightness.fade(10.percent, 6.seconds) + } + } + + step(StepCue.Custom("Dr. Sewart ist versteckt")) { + actors { + +"Oberschwester" + } + + onRun { + FrontLights.all { it.brightness.fade(50.percent, 3.5.seconds) } + sidelight.brightness.fade(75.percent, 4.seconds) + Spots.right.brightness.static(100.percent) + } + } + + step(StepCue.Text("Dr. Sewart", "Da sind sie!")) { + actors { + +"Ascot" + // TODO: Expand + +"Kaffeetanten" + // TODO: Expand + +"Nichten" + } + + onRun { + FrontLights.all { it.brightness.fade(100.percent, 3.seconds) } + sidelight.brightness.off(10.seconds) + } + } + + step(StepCue.Text("Dr. Sewart", "Ich mache Diät!")) { + actors { + -"Dr. Sewart" + -"Oberschwester" + } + } + + songKaffeeklatsch() + } + + scene("Ankunft Van Helsings") { + step(StepCue.Text("Ascot", "Jetzt ist Lucy wieder ganz gesund.")) { + actors { + +"Dr. Sewart" + } + + onRun { + Washs.both { + it.pointAtCeiling() + it.colorWheelMode.static(CoemarProWash.ColorWheelMode.White) + it.magenta.reset() + } + } + } + + step(StepCue.Text("Dr. Sewart", "Was mach ich nur!")) { + actors { + +"Van Helsing" + } + + rightSpotTarget = "Van Helsing" + + onRun { + Spots.right.brightness.static(100.percent) + FrontLights.all { it.brightness.pulseOnce( + rampUpDuration = 1.seconds, + rampDownDuration = 10.seconds, + peak = 0.percent, + start = 100.percent, + end = 100.percent + ) } + + BlinderBars.all { + it.preset.static(null) + it.color.static(Color.WHITE) + it.white.static(40.percent) + it.brightness.pulseOnce(0.3.seconds, 2.seconds, 100.percent) + } + + Washs.both { + it.pointAtAudience() + it.beamAngle.fade(0.percent, 2.seconds) + it.brightness.fade(start = 100.percent, end = 0.percent, duration = 2.seconds) + } + } + } + + step(StepCue.Text("Van Helsing", "Oder will jemand von den Damen?")) { + actors { + -"Kaffeetanten" + -"Nichten" + } + } + + step(StepCue.Text("Van Helsing", "Helfen Sie mir jetzt!")) { + actors { + -"Dr. Sewart" + -"Van Helsing" + -"Ascot" + } + + curtainState = CurtainState.CLOSED + + onRun { + FrontLights.all { it.brightness.off(3.seconds) } + + BlinderBars.all { + it.color.reset() + it.white.reset() + } + } + } + } + + scene("Verträge") { + step(StepCue.Custom("Vorhang ist geschlossen")) { + actors { + +"Hawkins / durchs Publikum" + +"Renfield / durchs Publikum" + } + + rightSpotTarget = "Hawkins & Renfield (im Publikum)" + + onRun { + Spots.right.brightness.fade(100.percent, 3.seconds) + } + } + + step(StepCue.Text("Hawkins", "…zum Grafen Dracula!")) { + actors { + -"Hawkins / durch den Vorhang" + -"Renfield / durch den Vorhang" + } + + rightSpotTarget = "mittig verbleiben" + + onRun { + Spots.right.brightness.off(10.seconds) + } + } + } + + scene("Einbruch") { + step(StepCue.Custom("Umbau abgeschlossen")) { + actors { + +"Backe / von links" + +"Timmy / von links" + +"Eloïse / im Sarg" + +"Françoise / im Sarg" + +"Bernadette / im Sarg" + } + + curtainState = CurtainState.OPEN + + onRun { + sidelight.color1.fadeRandomAround(230.degrees, 10.degrees, 10.seconds) + sidelight.color2.static(Color(hue = 230.degrees, saturation = 60.percent)) + sidelight.color3.static(Color(hue = 230.degrees, saturation = 10.percent)) + sidelight.color4.static(Color(hue = 230.degrees, saturation = 10.percent)) + sidelight.brightness.fade(40.percent, 8.seconds) + } + } + + songEsIstAngerichtet() + songDraculasZorn() } } \ No newline at end of file diff --git a/src/main/kotlin/de/moritzruth/dracula_musical/song/DraculasZorn.kt b/src/main/kotlin/de/moritzruth/dracula_musical/song/DraculasZorn.kt new file mode 100644 index 0000000..bc2164a --- /dev/null +++ b/src/main/kotlin/de/moritzruth/dracula_musical/song/DraculasZorn.kt @@ -0,0 +1,32 @@ +package de.moritzruth.dracula_musical.song + +import de.moritzruth.theaterdsl.show.SceneBuilderContext +import de.moritzruth.theaterdsl.show.StepCue +import kotlin.time.Duration.Companion.minutes +import kotlin.time.Duration.Companion.seconds + +fun SceneBuilderContext.songDraculasZorn() { + step(StepCue.MusicStart("Draculas Zorn", 3.minutes + 50.seconds)) { + // Aggressiver Einstieg durchs Publikum + } + + // Ruhiger, langsamer Sprechpart + // Spannung steigt + // Weiter gehts aggressiv für wenige Takte + // Langsamer Sprechpart, Spannung steigt + // "Er ist schuld, er hat uns provoziert" + // Ritardando + // Balladenartige Beschwichtigung im Pulk + // Stimmungswechsel zu düsterer, nicht mehr im Pulk + // 1 Takt Bridge, besonderer Rhythmus + // Rückkehr zum Ursprungsrhythmus + // DRAAAACUUUUUUULAAAAA + // Fill-in, pick-up + // DEEEEEEINEEEEEER MAAAAACHT + // DRAAAAAAAAACUUUUUULAAAAAAAAAAAA + // DRAAACUUUULAAAAAAAAAA + // Ruhiger: "Du bist unser …" + // MEIS-TER + // GRAAAAF DRAAAACUUUUULAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + // Endpose +} \ No newline at end of file diff --git a/src/main/kotlin/de/moritzruth/dracula_musical/song/EsIstAngerichtet.kt b/src/main/kotlin/de/moritzruth/dracula_musical/song/EsIstAngerichtet.kt new file mode 100644 index 0000000..1df7fc8 --- /dev/null +++ b/src/main/kotlin/de/moritzruth/dracula_musical/song/EsIstAngerichtet.kt @@ -0,0 +1,180 @@ +package de.moritzruth.dracula_musical.song + +import de.moritzruth.dracula_musical.device.* +import de.moritzruth.theaterdsl.show.SceneBuilderContext +import de.moritzruth.theaterdsl.show.StepCue +import de.moritzruth.theaterdsl.value.Color +import de.moritzruth.theaterdsl.value.degrees +import de.moritzruth.theaterdsl.value.percent +import kotlin.time.Duration.Companion.minutes +import kotlin.time.Duration.Companion.seconds + +fun SceneBuilderContext.songEsIstAngerichtet() { + step(StepCue.MusicStart("Es ist angerichtet", 2.minutes + 30.seconds)) { + actors { + // TODO: Expand + +"Vampire" + } + + onRun { + backlightBar.color.static(Color(hue = 0.degrees, saturation = 80.percent)) + backlightBar.brightness.pulse(2.seconds, 0.1.seconds, 0.2.seconds, startDelay = 0.seconds, peak = 30.percent) + + Washs.both { + it.pointAtStageCenter() + it.colorWheelMode.static(CoemarProWash.ColorWheelMode.Red) + it.brightness.pulse(2.seconds, 0.1.seconds, 0.3.seconds, startDelay = 0.4.seconds, peak = 30.percent) + } + } + } + + lightStep(StepCue.Custom("Musik: Drums setzen ein")) { + backlightBar.brightness.pulse(1.6.seconds, 0.1.seconds, 0.2.seconds, startDelay = 0.seconds, peak = 60.percent) + + Washs.both { + it.pointAtStageCenter() + it.colorWheelMode.static(CoemarProWash.ColorWheelMode.Red) + it.brightness.pulse(1.6.seconds, 0.1.seconds, 0.3.seconds, startDelay = 0.4.seconds, peak = 100.percent) + } + + BlinderBars.all { + it.preset.static(StairvilleSplb.Preset.STUB) // red, chase, back-and-forth + it.presetSpeed.static(50.percent) + it.brightness.fade(10.percent, 10.seconds) + } + } + + + lightStep(StepCue.Text("Vampire", "Wir wollen bloß spielen!", "Anfang")) { + Washs.both { + it.brightness.off(0.3.seconds) + it.pointAtAudience() + } + } + + repeat(2) { + lightStep(StepCue.Text("Vampire", "Aaah")) { + sidelight.brightness.fade(80.percent, 3.seconds) + backlightBar.brightness.rampDown(0.6.seconds) + } + + lightStep(StepCue.Text("Vampire", "…angerichtet!", "erste Silbe")) { + backlightBar.brightness.pulseOnce(0.1.seconds, 3.seconds, end = 20.percent) + } + + lightStep(StepCue.Text("Vampire", "…angerichtet!", "zweite Silbe")) { + sidelight.brightness.pulseOnce(0.1.seconds, 1.seconds, end = 40.percent) + Washs.both { it.brightness.pulseOnce(0.1.seconds, 0.4.seconds) } + } + + lightStep(StepCue.Text("Vampire", "…angerichtet!", "dritte Silbe")) { + BlinderBars.outer { it.brightness.pulseOnce(0.1.seconds, 0.4.seconds, peak = 50.percent, end = 10.percent) } + } + + lightStep(StepCue.Text("Vampire", "…angerichtet!", "vierte Silbe")) { + BlinderBars.inner { it.brightness.pulseOnce(0.1.seconds, 0.4.seconds, peak = 50.percent, end = 10.percent) } + } + } + + lightStep(StepCue.Text("Vampire", "Aaah")) { + sidelight.brightness.fade(80.percent, 3.seconds) + backlightBar.brightness.rampDown(0.6.seconds) + } + + repeat(2) { + lightStep(StepCue.Text("Vampire", "Aaah")) { + sidelight.brightness.fade(80.percent, 3.seconds) + backlightBar.brightness.rampDown(0.6.seconds) + } + + lightStep(StepCue.Text("Vampire", "…angerichtet!", "erste Silbe")) { + backlightBar.brightness.pulseOnce(0.1.seconds, 3.seconds, end = 20.percent) + } + + lightStep(StepCue.Text("Vampire", "…angerichtet!", "zweite Silbe")) { + sidelight.brightness.pulseOnce(0.1.seconds, 1.seconds, end = 40.percent) + Washs.both { it.brightness.pulseOnce(0.1.seconds, 0.4.seconds) } + } + + lightStep(StepCue.Text("Vampire", "…angerichtet!", "dritte Silbe")) { + BlinderBars.outer { it.brightness.pulseOnce(0.1.seconds, 0.4.seconds, peak = 50.percent, end = 10.percent) } + } + + lightStep(StepCue.Text("Vampire", "…angerichtet!", "vierte Silbe")) { + BlinderBars.inner { it.brightness.pulseOnce(0.1.seconds, 0.4.seconds, peak = 50.percent, end = 10.percent) } + } + } + + lightStep(StepCue.Text("Vampire", "Aaah")) { + sidelight.brightness.pulseOnce(2.seconds, 1.seconds, peak = 80.percent, end = 40.percent) + backlightBar.brightness.rampDown(0.6.seconds) + + Washs.both { + it.pointAtAudience() + it.colorWheelMode.static(CoemarProWash.ColorWheelMode.WarmWhite) + it.beamAngle.static(100.percent) + } + } + + lightStep(StepCue.Text("Vampire", "Aaah")) { + sidelight.brightness.pulseOnce(2.seconds, 1.seconds, peak = 80.percent, end = 40.percent) + + BlinderBars.all { it.brightness.pulseOnce(2.seconds, 1.seconds, peak = 50.percent, end = 30.percent) } + Washs.both { + it.pointAtCeiling(3.seconds) + it.brightness.pulseOnce(0.5.seconds, 3.seconds) + } + } + + lightStep(StepCue.Text("Vampire", "Aaah")) { + sidelight.brightness.off(7.seconds) + backlightBar.strobeSpeed.fade(start = 60.percent, end = 85.percent, duration = 7.seconds) + backlightBar.brightness.fade(start = 10.percent, end = 100.percent, duration = 7.seconds) + + BlinderBars.all { it.brightness.off(5.seconds) } + } + + lightStep(StepCue.Text("Vampire", "Jetzt…")) { + backlightBar.brightness.static(100.percent) + backlightBar.strobeSpeed.static(0.percent) + } + + lightStep(StepCue.Text("Vampire", "…ist…")) { + sidelight.brightness.static(100.percent) + } + + lightStep(StepCue.Text("Vampire", "…Essenszeit!", "erste Silbe")) { + Washs.both { it.brightness.static(100.percent) } + } + + lightStep(StepCue.Text("Vampire", "…Essenszeit!", "zweite Silbe")) { + BlinderBars.outer { + it.preset.static(null) + it.color.static(Color(hue = 0.degrees)) + it.brightness.static(100.percent) + } + } + + lightStep(StepCue.Text("Vampire", "…Essenszeit!", "dritte Silbe")) { + BlinderBars.inner { + it.preset.static(null) + it.color.static(Color(hue = 0.degrees)) + it.brightness.static(100.percent) + } + } + + lightStep(StepCue.Custom("Nächster Beat")) { + backlightBar.color.fade(Color(hue = 0.degrees, saturation = 10.percent), 0.5.seconds) + backlightBar.brightness.fade(30.percent, 0.5.seconds) + + sidelight.brightness.off(0.5.seconds) + Washs.both { it.brightness.off(0.5.seconds) } + BlinderBars.all { it.brightness.off(0.5.seconds) } + } + + lightStep(StepCue.MusicEnd) { + sidelight.brightness.fade(40.percent, 10.seconds) + + BlinderBars.all { it.color.reset() } + } +} \ No newline at end of file diff --git a/src/main/kotlin/de/moritzruth/dracula_musical/song/Kaffeeklatsch.kt b/src/main/kotlin/de/moritzruth/dracula_musical/song/Kaffeeklatsch.kt new file mode 100644 index 0000000..31d4f8f --- /dev/null +++ b/src/main/kotlin/de/moritzruth/dracula_musical/song/Kaffeeklatsch.kt @@ -0,0 +1,25 @@ +package de.moritzruth.dracula_musical.song + +import de.moritzruth.dracula_musical.device.BlinderBars +import de.moritzruth.dracula_musical.device.StairvilleSplb +import de.moritzruth.theaterdsl.show.SceneBuilderContext +import de.moritzruth.theaterdsl.show.StepCue +import de.moritzruth.theaterdsl.value.percent +import kotlin.time.Duration.Companion.minutes +import kotlin.time.Duration.Companion.seconds + +fun SceneBuilderContext.songKaffeeklatsch() { + step(StepCue.MusicStart("Kaffeeklatsch", 3.minutes)) { + BlinderBars.all { + it.preset.static(StairvilleSplb.Preset.STUB) // idk + it.presetSpeed.static(50.percent) + it.brightness.fade(25.percent, 4.seconds) + } + } + + step(StepCue.MusicEnd) { + BlinderBars.all { + it.brightness.off(1.seconds) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/de/moritzruth/theaterdsl/device/DynamicValue.kt b/src/main/kotlin/de/moritzruth/theaterdsl/device/DynamicValue.kt index 8f9b505..efc271b 100644 --- a/src/main/kotlin/de/moritzruth/theaterdsl/device/DynamicValue.kt +++ b/src/main/kotlin/de/moritzruth/theaterdsl/device/DynamicValue.kt @@ -10,6 +10,7 @@ import kotlin.math.min import kotlin.math.sin import kotlin.random.Random import kotlin.time.Duration +import kotlin.time.Duration.Companion.milliseconds import kotlin.time.ExperimentalTime import kotlin.time.TimeSource @@ -39,8 +40,17 @@ abstract class DoubleDV(private val initialStaticValue: Double) : DynamicValu } } + data class Pulse( + val interval: Duration, + val rampUpDuration: Duration, + val rampDownDuration: Duration, + val startDelay: Duration, + val peakValue: Double, + val start: Double, + val end: Double + ) : State + data class Ramp(val period: Duration, val start: Double, val end: Double) : State - data class TriangleWave(val period: Duration, val start: Double, val end: Double) : State data class Step(val steps: ImmutableList, val interval: Duration, val startIndex: Int) : State data class PulseOnce(val rampUpDuration: Duration, val rampDownDuration: Duration, val peakValue: Double, val start: Double, val end: Double) : State } @@ -79,24 +89,38 @@ abstract class DoubleDV(private val initialStaticValue: Double) : DynamicValu clampedProcess * (s.end - s.start) + s.start } - is State.TriangleWave -> { - val progress = elapsedTime.inWholeMilliseconds.toDouble() / s.period.inWholeMilliseconds - val clampedProcess = progress.mod(1.0) - 1.0 - } - is State.Step -> { val index = (elapsedTime / s.interval).toInt() + s.startIndex s.steps[index.mod(s.steps.size)] } + is State.Pulse -> { + var time = elapsedTime - s.startDelay + if (time < Duration.ZERO) 0.0 + else { + time = (time.inWholeMilliseconds.toDouble() / s.interval.inWholeMilliseconds).mod(1.0).milliseconds + + if (time <= s.rampUpDuration) { + val progress = time / s.rampUpDuration + val delta = s.peakValue - s.start + (progress * delta + s.start) + } else { + time = time - s.rampUpDuration + + val progress = min(time / s.rampDownDuration, 1.0) + val delta = s.peakValue - s.end + (s.peakValue - progress * delta) + } + } + } + is State.PulseOnce -> { if (elapsedTime <= s.rampUpDuration) { val progress = elapsedTime / s.rampUpDuration val delta = s.peakValue - s.start (progress * delta + s.start) } else { - val progress = min(elapsedTime / s.rampDownDuration, 1.0) + val progress = min((elapsedTime - s.rampUpDuration) / s.rampDownDuration, 1.0) val delta = s.peakValue - s.end (s.peakValue - progress * delta) } @@ -150,6 +174,18 @@ abstract class DoubleDV(private val initialStaticValue: Double) : DynamicValu steps(persistentListOf(a, b), interval, startIndex) } + fun pulse( + interval: Duration, + rampUpDuration: Duration, + rampDownDuration: Duration, + startDelay: Duration = Duration.ZERO, + peak: T = maximumValue, + end: T = minimumValue, + start: T = getCurrentValue() + ) { + state = State.Pulse(interval, rampUpDuration, rampDownDuration, startDelay, fromDomain(peak), fromDomain(start), fromDomain(end)) + } + fun pulseOnce(rampUpDuration: Duration, rampDownDuration: Duration, peak: T = maximumValue, end: T = minimumValue, start: T = getCurrentValue()) { state = State.PulseOnce(rampUpDuration, rampDownDuration, fromDomain(peak), fromDomain(start), fromDomain(end)) }