Try linking GUI to sound

random-generator
Emilien Bauer 2 years ago
commit a0515ae626

@ -1,9 +1,15 @@
import Params.PI import Params.PI
import Params.SAMPLES
import Params.TWO_PI import Params.TWO_PI
import Params.as_samples import Params.as_samples
import filter.Compressor import filter.Compressor
import filter.EchoFilter
import filter.Limiter import filter.Limiter
import java.lang.StrictMath.pow import java.lang.StrictMath.pow
import gui.SimpleEx
import random.RandomDisplacementFractal
import java.awt.event.WindowAdapter
import javax.swing.JSlider
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.pow import kotlin.math.pow
import kotlin.math.sin import kotlin.math.sin
@ -39,9 +45,10 @@ class SineWaveGenerator(var tone: Float) : StepGenerator() {
class RandomGenerator(var tone: Float) :StepGenerator() { class RandomGenerator(var tone: Float) :StepGenerator() {
val N = 200 val N = 200
val loudness = fun(i:Int): Double { val loudness = fun(i:Int): Double {
return i.toDouble().pow(-0) return i.toDouble().pow(power)
} }
var loudnessSum = 0.0 var loudnessSum = 0.0
var power:Double = -1.0
init { init {
for (i in 1 .. N) for (i in 1 .. N)
loudnessSum+=loudness(i) loudnessSum+=loudness(i)
@ -54,26 +61,58 @@ class RandomGenerator(var tone: Float) :StepGenerator() {
return (p/loudnessSum).toFloat() return (p/loudnessSum).toFloat()
} }
} }
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>) { fun main(args: Array<String>) {
val sink = AudioSink() val sink = AudioSink()
val machine = SoundMachine()
SoundMachine.State.bpm = 1024F
machine.globalEffects.add(Compressor(as_samples(.4f).toInt())::apply)
machine.globalEffects.add(Limiter(.9f)::apply)
val gen = RandomGenerator(0f)
machine.generators.add(Chain(gen::generate, ArrayList()))
val gen = SoundMachine() sink.enqueueChunk(machine.nextChunk())
gen.globalEffects.add(Compressor(as_samples(.4f).toInt())::apply) sink.start()
gen.globalEffects.add(Limiter(.9f)::apply)
gen.generators.add(Chain(RandomGenerator(0f)::generate, ArrayList())) val close = false
sink.enqueueChunk(gen.nextChunk()) Thread {
while (!close) {
sink.enqueueChunk(machine.nextChunk())
while (sink.queueSize > 1) {
Thread.sleep(1)
}
}
}.start()
sink.start() val frame = SimpleEx("Play!")
for (i in 1..100) { frame.add_slider("Property 1", 0, 10000, 50).addChangeListener { e ->
sink.enqueueChunk(gen.nextChunk()) val value = (e.source as JSlider).value
gen.power = -value.toDouble()/100.0
println("Switching power to " + gen.power.toString())
} }
sink.terminate() frame.isVisible = true
} }

@ -2,6 +2,9 @@ package filter
import java.lang.Float.max import java.lang.Float.max
import java.lang.Float.min import java.lang.Float.min
import java.util.* 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{ fun clamp(min_val: Float, value: Float, max_val: Float) : Float{
return max(min(value, max_val), min_val) 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 }) private val cache: Queue<Float> = LinkedList(List(size) { 0f })
override fun step(value: Float): Float { override fun step(value: Float): Float {
val effect = value + cache.remove() * volume val effect = value + cache.remove()
cache.add(effect)
cache.add(effect.absoluteValue.pow(volume) * effect.sign)
return effect return effect
} }
} }

@ -0,0 +1,40 @@
package gui
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;
}
}

@ -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…
Cancel
Save