1
+ package dev.matsem.astral.playground.sketches
2
+
3
+ import ch.bildspur.postfx.builder.PostFX
4
+ import dev.matsem.astral.core.tools.animations.AnimationHandler
5
+ import dev.matsem.astral.core.tools.animations.radianSeconds
6
+ import dev.matsem.astral.core.tools.animations.saw
7
+ import dev.matsem.astral.core.tools.audio.beatcounter.BeatCounter
8
+ import dev.matsem.astral.core.tools.audio.beatcounter.OnKick
9
+ import dev.matsem.astral.core.tools.audio.beatcounter.OnSnare
10
+ import dev.matsem.astral.core.tools.extensions.centerX
11
+ import dev.matsem.astral.core.tools.extensions.colorModeHsb
12
+ import dev.matsem.astral.core.tools.extensions.mapSin
13
+ import dev.matsem.astral.core.tools.extensions.mapp
14
+ import dev.matsem.astral.core.tools.extensions.pushPop
15
+ import dev.matsem.astral.core.tools.extensions.quantize
16
+ import dev.matsem.astral.core.tools.extensions.shorterDimension
17
+ import dev.matsem.astral.core.tools.extensions.translateCenter
18
+ import dev.matsem.astral.core.tools.videoexport.VideoExporter
19
+ import org.koin.core.KoinComponent
20
+ import org.koin.core.inject
21
+ import processing.core.PApplet
22
+
23
+ /* *
24
+ * VJ loop for SEM008 release https://soundcloud.com/semfree/sem008-offish-evasion-straight-shootingcalculated-risk-out-300922
25
+ */
26
+ class Sem008 : PApplet (), KoinComponent, AnimationHandler {
27
+
28
+ sealed class ExportConfig (
29
+ val width : Int ,
30
+ val height : Int ,
31
+ val outputFile : String ,
32
+ val travelLength : Int
33
+ ) {
34
+ object Square : ExportConfig(1080 , 1080 , " sem008_loop_sqr.mp4" , 200_000 )
35
+ object Story : ExportConfig(1080 , 1920 , " sem008_loop_story.mp4" , 300_000 )
36
+ }
37
+
38
+ private val exportConfig = ExportConfig .Square
39
+
40
+ private lateinit var fx: PostFX
41
+
42
+ private val beatCounter: BeatCounter by inject()
43
+ private val videoExporter: VideoExporter by inject()
44
+
45
+ override fun provideMillis (): Int = videoExporter.videoMillis()
46
+
47
+ private var ures: Float = 3f
48
+ private var uresTarget: Float = 3f
49
+ private var vres: Float = 3f
50
+ private var vresTarget: Float = 3f
51
+ private var zoom: Float = 1f
52
+ private var invert: Boolean = false
53
+
54
+ override fun settings () {
55
+ size(exportConfig.width, exportConfig.height, P3D )
56
+ }
57
+
58
+ override fun setup () {
59
+ colorModeHsb()
60
+ surface.setAlwaysOnTop(true )
61
+ fx = PostFX (this )
62
+
63
+ beatCounter.addListener(OnKick , 2 ) {
64
+ uresTarget = random(1f , 5f )
65
+ vresTarget = random(1f , 5f )
66
+ }
67
+
68
+ beatCounter.addListener(OnKick , 4 ) {
69
+ invert = true
70
+ }
71
+
72
+ beatCounter.addListener(OnSnare , 2 ) {
73
+ zoom = random(0.7f , 1f )
74
+ }
75
+
76
+ videoExporter.prepare(
77
+ audioFilePath = " music/sem0081minclip.mp3" ,
78
+ movieFps = 30f ,
79
+ dryRun = true ,
80
+ audioGain = 2f ,
81
+ outputVideoFileName = exportConfig.outputFile
82
+ ) { drawSketch() }
83
+ }
84
+
85
+ override fun draw () = drawSketch()
86
+
87
+ private fun PApplet.drawSketch () {
88
+ ures = lerp(ures, uresTarget, 0.2f )
89
+ vres = lerp(vres, vresTarget, 0.2f )
90
+
91
+ clear()
92
+ background(0f , 0f , 10f )
93
+
94
+ sphereDetail(ures.toInt(), vres.toInt())
95
+
96
+ pushPop {
97
+ translateCenter()
98
+ scale(zoom)
99
+
100
+ for (travel in 0 until exportConfig.travelLength step 1000 ) {
101
+ strokeWeight(4f )
102
+ if (travel < saw(1 / 5f ).mapp(0f , exportConfig.travelLength.toFloat())) {
103
+ fill(0f , 0f , 10f )
104
+ stroke(0f , 0f , 90f )
105
+ } else {
106
+ fill(0f , 0f , 60f )
107
+ stroke(0f , 0f , 0f )
108
+ }
109
+
110
+ pushPop {
111
+ rotateZ(radianSeconds(20f ) + travel)
112
+ translate(0f , 0f , millis().toFloat())
113
+
114
+ pushPop {
115
+ translate(- centerX() * 1.2f , 0f )
116
+ translate(0f , 0f , - travel.toFloat())
117
+ rotateY(radianSeconds(10f ).quantize(0.05f ))
118
+ rotateZ(- radianSeconds(30f ))
119
+ sphere(shorterDimension() * 0.50f )
120
+ }
121
+
122
+ pushPop {
123
+ translate(centerX() * 1.2f , 0f )
124
+ translate(0f , 0f , - travel.toFloat())
125
+ rotateY(- radianSeconds(10f ).quantize(0.05f ))
126
+ rotateZ(radianSeconds(30f ))
127
+ sphere(shorterDimension() * 0.50f )
128
+ }
129
+ }
130
+ }
131
+ }
132
+
133
+ fx.render().apply {
134
+ noise(0.3f , 0.5f )
135
+ rgbSplit(50f )
136
+ bloom(0.5f , 20 , 5f )
137
+ pixelate(sin(radianSeconds(5f )).mapSin(width * 1f , width * 0.4f ))
138
+ if (invert) {
139
+ invert()
140
+ invert = false
141
+ }
142
+ }.compose()
143
+ }
144
+ }
0 commit comments