Skip to content

Commit

Permalink
Merge pull request #24 from matejsemancik/feature/galaxy-sketch
Browse files Browse the repository at this point in the history
feature/galaxy-sketch
  • Loading branch information
matejsemancik authored Oct 14, 2019
2 parents e0751cc + 71fd578 commit 783e3a4
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 66 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@
build/
out/
*.iml
local.properties
local.properties
data/midi
data/movies
data/music
2 changes: 1 addition & 1 deletion src/main/kotlin/dev/matsem/astral/Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package dev.matsem.astral
object Config {

object Sketch {
const val DEFAULT_SELECTOR = '1'
const val DEFAULT_SELECTOR = 's'
}

object Color {
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/dev/matsem/astral/di/koin_modules.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import dev.matsem.astral.sketches.gameoflife.GameOfLifeSketch
import dev.matsem.astral.sketches.patterns.PatternsSketch
import dev.matsem.astral.sketches.polygonal.PolygonalSketch
import dev.matsem.astral.sketches.spikes.SpikesSketch
import dev.matsem.astral.sketches.starfield.StarfieldSketch
import dev.matsem.astral.sketches.galaxy.GalaxySketch
import dev.matsem.astral.sketches.starglitch.StarGlitchSketch
import dev.matsem.astral.sketches.terrain.TerrainSketch
import dev.matsem.astral.sketches.video.VideoSketch
Expand Down Expand Up @@ -83,6 +83,6 @@ val appModule = module {
factory { SpikesSketch() }
factory { CubesSketch() }
factory { VideoSketch() }
factory { StarfieldSketch() }
factory { GalaxySketch() }
factory { GameOfLifeSketch() }
}
6 changes: 3 additions & 3 deletions src/main/kotlin/dev/matsem/astral/sketches/SketchLoader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import dev.matsem.astral.sketches.gameoflife.GameOfLifeSketch
import dev.matsem.astral.sketches.patterns.PatternsSketch
import dev.matsem.astral.sketches.polygonal.PolygonalSketch
import dev.matsem.astral.sketches.spikes.SpikesSketch
import dev.matsem.astral.sketches.starfield.StarfieldSketch
import dev.matsem.astral.sketches.galaxy.GalaxySketch
import dev.matsem.astral.sketches.starglitch.StarGlitchSketch
import dev.matsem.astral.sketches.terrain.TerrainSketch
import dev.matsem.astral.sketches.video.VideoSketch
Expand Down Expand Up @@ -88,7 +88,7 @@ class SketchLoader : PApplet(), KoinComponent {
private val spikesSketch: SpikesSketch by inject()
private val cubesSketch: CubesSketch by inject()
private val videoSketch: VideoSketch by inject()
private val starfieldSketch: StarfieldSketch by inject()
private val galaxySketch: GalaxySketch by inject()
private val gameOfLifeSketch: GameOfLifeSketch by inject()

// endregion
Expand Down Expand Up @@ -149,7 +149,7 @@ class SketchLoader : PApplet(), KoinComponent {
put('9', spikesSketch)
put('p', cubesSketch)
put('m', videoSketch)
put('s', starfieldSketch)
put('s', galaxySketch)
put('g', gameOfLifeSketch)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package dev.matsem.astral.sketches.starfield
package dev.matsem.astral.sketches.galaxy

data class GalaxyImage(
val path: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
package dev.matsem.astral.sketches.starfield
package dev.matsem.astral.sketches.galaxy

import dev.matsem.astral.sketches.BaseSketch
import dev.matsem.astral.sketches.SketchLoader
import dev.matsem.astral.tools.audio.AudioProcessor
import dev.matsem.astral.tools.audio.beatcounter.BeatCounter
import dev.matsem.astral.tools.audio.beatcounter.OnKick
import dev.matsem.astral.tools.audio.beatcounter.OnSnare
import dev.matsem.astral.tools.automator.MidiAutomator
import dev.matsem.astral.tools.extensions.*
import dev.matsem.astral.tools.kontrol.KontrolF1
import dev.matsem.astral.tools.kontrol.onTogglePad
import dev.matsem.astral.tools.kontrol.onTriggerPad
import dev.matsem.astral.tools.galaxy.Galaxy
import dev.matsem.astral.tools.logging.SketchLogger
import org.koin.core.KoinComponent
import org.koin.core.inject
import processing.core.PApplet.sin
import processing.core.PConstants
import processing.core.PImage
import processing.core.PVector
import kotlin.math.sin

class StarfieldSketch : BaseSketch(), KoinComponent {

override val sketch: SketchLoader by inject()
class GalaxySketch : BaseSketch(), KoinComponent {

data class Star(
val vec: PVector,
Expand All @@ -37,53 +34,55 @@ class StarfieldSketch : BaseSketch(), KoinComponent {
.withFps()
.build()

override val sketch: SketchLoader by inject()
private val audioProcessor: AudioProcessor by inject()
private val beatCounter: BeatCounter by inject()
private val kontrol: KontrolF1 by inject()
private val galaxy: Galaxy by inject()
private val automator: MidiAutomator by inject()

private val lock = Any()
private val starField = mutableListOf<Star>()
private val galaxy = mutableListOf<Star>()
private val galaxyStars = mutableListOf<Star>()
private val images = arrayOf(
GalaxyImage(path = "images/galaxy1.png", pixelStep = 3, threshold = 60f),
GalaxyImage(path = "images/galaxy2.png", pixelStep = 2, threshold = 50f)
GalaxyImage(path = "images/galaxy2.png", pixelStep = 2, threshold = 50f),
GalaxyImage(path = "images/galaxy1.png", pixelStep = 3, threshold = 50f),
GalaxyImage(path = "images/galaxy2.png", pixelStep = 2, threshold = 40f)
)

private var bassGain: Float = 0f
private var expandingQuantized: Boolean = false
private var expandingOnBeat: Boolean = false
private var expandingValue = 1f
private var randomDiameters: Boolean = false
// region remote control

override fun onBecameActive() {
kontrol.reset()
private val galaxyImageButtons = galaxy.createPushButtonGroup(10, listOf(4, 5, 6, 7)) {
createGalaxy(images[it])
}

kontrol.onTriggerPad(0, 0, 50) {
if (it) {
createGalaxy(images[0])
}
}
private val zoomQuantizeButton = galaxy.createToggleButton(channel = 10, cc = 8, defaultValue = false)
private val zoomOnBeatButton = galaxy.createToggleButton(channel = 10, cc = 9, defaultValue = false)
private val zoomQuantSlider = galaxy.createPot(channel = 10, cc = 10, min = 0.005f, max = 0.5f, initialValue = 0.5f)
private val zoomHzSlider = galaxy.createPot(channel = 10, cc = 11, min = 1 / 60f, max = 1 / 5f, initialValue = 1 / 60f)
private val zoomMinSlider = galaxy.createPot(channel = 10, cc = 12, min = 1f, max = 4f, initialValue = 1f)
private val zoomMaxSlider = galaxy.createPot(channel = 10, cc = 13, min = 1f, max = 4f, initialValue = 2f)
private var zoomValue = 1f

kontrol.onTriggerPad(0, 1, 50) {
if (it) {
createGalaxy(images[1])
}
}
private val randomDiametersButton = galaxy.createToggleButton(channel = 10, cc = 14, defaultValue = false)
private val starDiameterSlider = galaxy.createPot(channel = 10, cc = 15, min = 0.5f, max = 1.5f, initialValue = 1f)

kontrol.onTogglePad(0, 2, 0) {
expandingQuantized = it
}
private val bassGainSlider = galaxy.createPot(channel = 10, cc = 16, min = 0f, max = 1f)

kontrol.onTogglePad(1, 2, 10) {
expandingOnBeat = it
}
// endregion

kontrol.onTogglePad(0, 3, 70) {
randomDiameters = it
}
}
override fun onBecameActive() = Unit

override fun setup() = with(sketch) {
automator.setupWithGalaxy(
channel = 10,
recordButtonCC = 0,
playButtonCC = 1,
loopButtonCC = 2,
clearButtonCC = 3,
channelFilter = null
)

// Create galaxy from image
createGalaxy(images[0])

Expand All @@ -100,21 +99,21 @@ class StarfieldSketch : BaseSketch(), KoinComponent {
}

beatCounter.addListener(OnSnare, 1) {
if (randomDiameters) {
if (randomDiametersButton.isPressed) {
randomizeDiameters()
}
}

beatCounter.addListener(OnKick, 4) {
if (expandingOnBeat) {
expandingValue = random(1f, 1.5f)
if (zoomOnBeatButton.isPressed) {
zoomValue = random(zoomMinSlider.value, zoomMaxSlider.value)
}
}
}

private fun createGalaxy(image: GalaxyImage) = with(sketch) {
synchronized(lock) {
galaxy.clear()
galaxyStars.clear()
val galaxyImage: PImage = loadImage(image.path).apply {
val ratio = pixelWidth / pixelHeight.toFloat()
resize(720, (720 / ratio).toInt())
Expand All @@ -126,7 +125,7 @@ class StarfieldSketch : BaseSketch(), KoinComponent {
for (y in 0 until galaxyImage.height step image.pixelStep) {
pixelBrightness = brightness(galaxyImage[x, y])
if (pixelBrightness > image.threshold) {
galaxy += Star(
galaxyStars += Star(
vec = PVector(
x.toFloat() - galaxyImage.width / 2f,
random(-4f, 4f),
Expand All @@ -144,7 +143,7 @@ class StarfieldSketch : BaseSketch(), KoinComponent {
}

private fun randomizeDiameters() = synchronized(lock) {
galaxy.forEach {
galaxyStars.forEach {
it.diameter = generateDiameter()
}
}
Expand All @@ -154,33 +153,37 @@ class StarfieldSketch : BaseSketch(), KoinComponent {
}

override fun draw() = with(sketch) {
bassGain = kontrol.slider1.midiRange(1f)
automator.update()
val diameterFactor = starDiameterSlider.value

beatCounter.update()
background(30)
background(bgColor)

noFill()
stroke(0f, 0f, 100f)
stroke(fgColor)

if (zoomQuantizeButton.isPressed) {
zoomValue = sin(angularTimeHz(zoomHzSlider.value))
.mapSin(zoomMinSlider.value, zoomMaxSlider.value)
.quantize(zoomQuantSlider.value)
}

// Galaxy
synchronized(lock) {
galaxy.forEach {
galaxyStars.forEach {
pushMatrix()
translateCenter()
scale(zoomValue)

it.rotationExtra += audioProcessor.getRange(1000f..4000f).remap(0f, 100f, 0f, 0.02f) * it.randomFactor
rotateX(-0.34f)
rotateY((millis() - it.birth) * it.ySpeed + it.rotationExtra)
rotateZ((millis() - it.birth) * it.zSpeed)

strokeWeight(it.diameter)
val amp = audioProcessor.getRange(20f..200f) * random(-0.1f, 0.1f) * bassGain

if (expandingQuantized) {
expandingValue = sin(saw(1 / 5f)).mapp(1f, 1.5f).quantize(0.05f)
}
strokeWeight(it.diameter * diameterFactor)
val amp = audioProcessor.getRange(20f..200f) * random(-0.1f, 0.1f) * bassGainSlider.value

val v = it.vec.copy().mult(expandingValue)
val v = it.vec
point(v.x, v.y + amp, v.z)
popMatrix()
}
Expand All @@ -192,25 +195,27 @@ class StarfieldSketch : BaseSketch(), KoinComponent {
.take(audioProcessor
.getRange(20f..60f)
.remap(0f, 400f, starField.size.toFloat(), starField.size.toFloat() / 2f).toInt()
.constrain(high = starField.size - 1)
.constrain(low = 0, high = starField.size - 1)
)
.forEach {
pushMatrix()
translateCenter()
scale(zoomValue)
it.rotationExtra += audioProcessor.getRange(2500f..16000f).remap(0f, 100f, 0f, 0.2f) * it.randomFactor
rotateY(millis() * it.ySpeed + it.rotationExtra)
rotateZ(millis() * it.zSpeed)

strokeWeight(it.diameter)
strokeWeight(it.diameter * diameterFactor)
point(it.vec.x, it.vec.y, it.vec.z)
popMatrix()
}

// Black hole
pushMatrix()
translateCenter()
scale(zoomValue)
noStroke()
fill(0)
fill(bgColor)
ellipseMode(PConstants.CENTER)
beginShape()
sphere(25f)
Expand Down
3 changes: 3 additions & 0 deletions src/main/kotlin/dev/matsem/astral/tools/galaxy/Galaxy.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ class Galaxy : MidiDevice {
fun createButtonGroup(channel: Int, ccs: List<Int>, activeCCs: List<Int>) =
ButtonGroup(midiBus, channel, ccs, activeCCs).also { controls.add(it) }

fun createPushButtonGroup(channel: Int, ccs: List<Int>, listener: (Int) -> Unit) =
PushButtonGroup(midiBus, channel, ccs, listener).also { controls.add(it) }

fun createEncoder(channel: Int, cc: Int, min: Int, max: Int, initialValue: Int = 0) =
Encoder(midiBus, channel, cc, min, max, initialValue).also { controls.add(it) }

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package dev.matsem.astral.tools.galaxy.controls

import themidibus.MidiBus

class PushButtonGroup(
private val midiBus: MidiBus,
val ch: Int,
val ccs: List<Int>,
val listener: (Int) -> Unit
) : GalaxyControl {


override fun controllerChange(channel: Int, control: Int, v: Int) {
if (ch == channel && ccs.contains(control) && v == 127) {
listener(ccs.indexOf(control))
}
}

override fun update() = Unit

override fun updatePhone() = Unit
}
Binary file modified touchosc/Astral.touchosc
Binary file not shown.

0 comments on commit 783e3a4

Please sign in to comment.