added gui and stuff like that
This commit is contained in:
parent
fca2ca7dc1
commit
f3c678f589
@ -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)
|
||||
|
||||
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<String>) {
|
||||
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()
|
||||
}
|
||||
|
||||
|
@ -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<Float> = 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
|
||||
}
|
||||
}
|
||||
|
42
src/main/kotlin/gui/gui.kt
Normal file
42
src/main/kotlin/gui/gui.kt
Normal file
@ -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() {
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
105
src/main/kotlin/random/RandomDisplacementFractal.kt
Normal file
105
src/main/kotlin/random/RandomDisplacementFractal.kt
Normal file
@ -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<FloatArray> = 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<BooleanArray>? {
|
||||
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
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user