From f3c678f5891831b186538f55375d6b0a36ff2a0a Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Sat, 21 Jan 2023 14:04:27 +0000 Subject: [PATCH] added gui and stuff like that --- src/main/kotlin/Main.kt | 51 ++++++++- src/main/kotlin/filter/EchoFilter.kt | 8 +- src/main/kotlin/gui/gui.kt | 42 +++++++ .../random/RandomDisplacementFractal.java | 107 ------------------ .../random/RandomDisplacementFractal.kt | 105 +++++++++++++++++ 5 files changed, 198 insertions(+), 115 deletions(-) create mode 100644 src/main/kotlin/gui/gui.kt delete mode 100644 src/main/kotlin/random/RandomDisplacementFractal.java create mode 100644 src/main/kotlin/random/RandomDisplacementFractal.kt diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 047ec45..5dd93b5 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -1,8 +1,13 @@ import Params.PI +import Params.SAMPLES import Params.TWO_PI import Params.as_samples import filter.Compressor +import filter.EchoFilter import filter.Limiter +import gui.SimpleEx +import random.RandomDisplacementFractal +import javax.swing.JSlider import kotlin.math.cos import kotlin.math.pow import kotlin.math.sin @@ -35,27 +40,61 @@ class SineWaveGenerator(var tone: Float) : StepGenerator() { } } +class RandomDisplacementFractalNoiseGenerator(private val period: Float, val repetitions: Int): StepGenerator() { + val width = (period * SAMPLES).toInt() + val rng = RandomDisplacementFractal( 4f, width, repetitions) -fun main(args: Array) { - val sink = AudioSink() + var pos: Int = 0 + + override fun generateSingle(time: Float): Float { + val x = pos % width + val y = (pos / width) % repetitions + pos ++ + + return rng.get(x, y) + } + +} + +fun main(args: Array) { + val sink = AudioSink() val gen = SoundMachine() gen.globalEffects.add(Compressor(as_samples(.4f).toInt())::apply) gen.globalEffects.add(Limiter(.9f)::apply) - gen.generators.add(Chain(SineWaveGenerator(0f)::generate, ArrayList())) + gen.generators.add(Chain( + RandomDisplacementFractalNoiseGenerator(.2f, 100)::generate, + listOf( + EchoFilter((SAMPLES * 2).toInt(), 0.2f)::apply, + ) + ) + ) sink.enqueueChunk(gen.nextChunk()) sink.start() - for (i in 1..100) { - sink.enqueueChunk(gen.nextChunk()) + val close = false + + Thread { + while (!close) { + sink.enqueueChunk(gen.nextChunk()) + while (sink.queueSize > 2) { + Thread.sleep(1) + } + } + }.start() + + val frame = SimpleEx("Play!") + + frame.add_slider("Property 1", 0, 100, 50).addChangeListener { e -> + val value = (e.source as JSlider).value + } - sink.terminate() } diff --git a/src/main/kotlin/filter/EchoFilter.kt b/src/main/kotlin/filter/EchoFilter.kt index a35bc9b..d181890 100644 --- a/src/main/kotlin/filter/EchoFilter.kt +++ b/src/main/kotlin/filter/EchoFilter.kt @@ -2,6 +2,9 @@ package filter import java.lang.Float.max import java.lang.Float.min import java.util.* +import kotlin.math.absoluteValue +import kotlin.math.pow +import kotlin.math.sign fun clamp(min_val: Float, value: Float, max_val: Float) : Float{ return max(min(value, max_val), min_val) @@ -12,8 +15,9 @@ class EchoFilter(size: Int, private val volume: Float = 0.5f) : StepFilter() { private val cache: Queue = LinkedList(List(size) { 0f }) override fun step(value: Float): Float { - val effect = value + cache.remove() * volume - cache.add(effect) + val effect = value + cache.remove() + + cache.add(effect.absoluteValue.pow(volume) * effect.sign) return effect } } diff --git a/src/main/kotlin/gui/gui.kt b/src/main/kotlin/gui/gui.kt new file mode 100644 index 0000000..6c833f0 --- /dev/null +++ b/src/main/kotlin/gui/gui.kt @@ -0,0 +1,42 @@ +package gui + +import javafx.scene.layout.StackPane +import java.awt.EventQueue +import java.awt.GridLayout +import java.awt.Label +import javax.swing.JFrame +import javax.swing.JSlider + +class SimpleEx(title: String) : JFrame() { + + init { + createUI(title) + } + + private fun createUI(title: String) { + + setTitle(title) + + defaultCloseOperation = EXIT_ON_CLOSE + setSize(400, 300) + setLocationRelativeTo(null) + + layout = GridLayout(20, 2) + } + + fun add_slider(name: String, min: Int, max: Int, value: Int): JSlider { + add(Label(name)) + val slider = JSlider(min, max, value) + + slider.minorTickSpacing = 10; + slider.paintTicks = true; + + add(slider) + + return slider + } +} + + +fun main() { +} \ No newline at end of file diff --git a/src/main/kotlin/random/RandomDisplacementFractal.java b/src/main/kotlin/random/RandomDisplacementFractal.java deleted file mode 100644 index 978f87f..0000000 --- a/src/main/kotlin/random/RandomDisplacementFractal.java +++ /dev/null @@ -1,107 +0,0 @@ -package random; -import java.util.Random; - -public class RandomDisplacementFractal { - - - /** Source of entropy */ - private Random rand_; - - /** Amount of roughness */ - float roughness_; - - /** Plasma fractal grid */ - private float[][] grid_; - - /** Generate a noise source based upon the midpoint displacement fractal. - * - * @param rand The random number generator - * @param roughness a roughness parameter - * @param width the width of the grid - * @param height the height of the grid - */ - public RandomDisplacementFractal(Random rand, float roughness, int width, int height) { - roughness_ = roughness / width; - grid_ = new float[width][height]; - rand_ = (rand == null) ? new Random() : rand; - } - - public void initialise() { - int xh = grid_.length - 1; - int yh = grid_[0].length - 1; - - // set the corner points - grid_[0][0] = rand_.nextFloat() - 0.5f; - grid_[0][yh] = rand_.nextFloat() - 0.5f; - grid_[xh][0] = rand_.nextFloat() - 0.5f; - grid_[xh][yh] = rand_.nextFloat() - 0.5f; - - // generate the fractal - generate(0, 0, xh, yh); - } - - - // Add a suitable amount of random displacement to a point - private float roughen(float v, int l, int h) { - return v + roughness_ * (float) (rand_.nextGaussian() * (h - l)); - } - - - // generate the fractal - private void generate(int xl, int yl, int xh, int yh) { - int xm = (xl + xh) / 2; - int ym = (yl + yh) / 2; - if ((xl == xm) && (yl == ym)) return; - - grid_[xm][yl] = 0.5f * (grid_[xl][yl] + grid_[xh][yl]); - grid_[xm][yh] = 0.5f * (grid_[xl][yh] + grid_[xh][yh]); - grid_[xl][ym] = 0.5f * (grid_[xl][yl] + grid_[xl][yh]); - grid_[xh][ym] = 0.5f * (grid_[xh][yl] + grid_[xh][yh]); - - float v = roughen(0.5f * (grid_[xm][yl] + grid_[xm][yh]), xl + yl, yh - + xh); - grid_[xm][ym] = v; - grid_[xm][yl] = roughen(grid_[xm][yl], xl, xh); - grid_[xm][yh] = roughen(grid_[xm][yh], xl, xh); - grid_[xl][ym] = roughen(grid_[xl][ym], yl, yh); - grid_[xh][ym] = roughen(grid_[xh][ym], yl, yh); - - generate(xl, yl, xm, ym); - generate(xm, yl, xh, ym); - generate(xl, ym, xm, yh); - generate(xm, ym, xh, yh); - } - - - /** - * Dump out as a CSV - */ - public void printAsCSV() { - for(int i = 0;i < grid_.length;i++) { - for(int j = 0;j < grid_[0].length;j++) { - System.out.print(grid_[i][j]); - System.out.print(","); - } - System.out.println(); - } - } - - - /** - * Convert to a Boolean array - * @return the boolean array - */ - public boolean[][] toBooleans() { - int w = grid_.length; - int h = grid_[0].length; - boolean[][] ret = new boolean[w][h]; - for(int i = 0;i < w;i++) { - for(int j = 0;j < h;j++) { - ret[i][j] = grid_[i][j] < 0; - } - } - return ret; - } - - -} diff --git a/src/main/kotlin/random/RandomDisplacementFractal.kt b/src/main/kotlin/random/RandomDisplacementFractal.kt new file mode 100644 index 0000000..2d5c3f5 --- /dev/null +++ b/src/main/kotlin/random/RandomDisplacementFractal.kt @@ -0,0 +1,105 @@ +package random + +import java.util.* + +class RandomDisplacementFractal(val roughness: Float,val width: Int,val height: Int) { + /** Source of entropy */ + private var rand_: Random = Random() + + /** Amount of roughness */ + val roughness_ = roughness / width + + /** Plasma fractal grid */ + private val grid_: Array = Array(width) { FloatArray(height) } + + init { + println("Creating fractal...") + initialise() + println("fractal created") + } + + fun initialise() { + val xh = grid_.size - 1 + val yh = grid_[0].size - 1 + + // set the corner points + grid_[0][0] = rand_.nextFloat() - 0.5f + grid_[0][yh] = rand_.nextFloat() - 0.5f + grid_[xh][0] = rand_.nextFloat() - 0.5f + grid_[xh][yh] = rand_.nextFloat() - 0.5f + + // generate the fractal + generate(0, 0, xh, yh) + } + + + // Add a suitable amount of random displacement to a point + private fun roughen(v: Float, l: Int, h: Int): Float { + return v + roughness_ * (rand_.nextGaussian() * (h - l)).toFloat() + } + + + operator fun get(i: Int, j: Int): Float { + if (i >= 0 && i < grid_.size) { + if (j >= 0 && j < grid_[0].size) { + return grid_[i][j] + } + } + throw IndexOutOfBoundsException("Out of bounds access detected!") + } + + // generate the fractal + private fun generate(xl: Int, yl: Int, xh: Int, yh: Int) { + val xm = (xl + xh) / 2 + val ym = (yl + yh) / 2 + if (xl == xm && yl == ym) return + grid_[xm][yl] = 0.5f * (grid_[xl][yl] + grid_[xh][yl]) + grid_[xm][yh] = 0.5f * (grid_[xl][yh] + grid_[xh][yh]) + grid_[xl][ym] = 0.5f * (grid_[xl][yl] + grid_[xl][yh]) + grid_[xh][ym] = 0.5f * (grid_[xh][yl] + grid_[xh][yh]) + val v = roughen( + 0.5f * (grid_[xm][yl] + grid_[xm][yh]), xl + yl, yh + + xh + ) + grid_[xm][ym] = v + grid_[xm][yl] = roughen(grid_[xm][yl], xl, xh) + grid_[xm][yh] = roughen(grid_[xm][yh], xl, xh) + grid_[xl][ym] = roughen(grid_[xl][ym], yl, yh) + grid_[xh][ym] = roughen(grid_[xh][ym], yl, yh) + generate(xl, yl, xm, ym) + generate(xm, yl, xh, ym) + generate(xl, ym, xm, yh) + generate(xm, ym, xh, yh) + } + + + /** + * Dump out as a CSV + */ + fun printAsCSV() { + for (floats in grid_) { + for (j in grid_[0].indices) { + print(floats[j]) + print(",") + } + println() + } + } + + + /** + * Convert to a Boolean array + * @return the boolean array + */ + fun toBooleans(): Array? { + val w = grid_.size + val h = grid_[0].size + val ret = Array(w) { BooleanArray(h) } + for (i in 0 until w) { + for (j in 0 until h) { + ret[i][j] = grid_[i][j] < 0 + } + } + return ret + } +} \ No newline at end of file