some reworks
parent
e127450404
commit
a38f0b35d6
@ -0,0 +1,8 @@
|
|||||||
|
package music
|
||||||
|
|
||||||
|
class Frac(val upper: Int, val lower: Int) {
|
||||||
|
val numerator = upper;
|
||||||
|
val denominator = lower;
|
||||||
|
|
||||||
|
fun value(): Double = upper / lower.toDouble();
|
||||||
|
}
|
@ -1,10 +1,29 @@
|
|||||||
package music.filter
|
package music.filter
|
||||||
|
|
||||||
import music.Signal
|
import music.Frac
|
||||||
|
import music.SoundSamples
|
||||||
|
import music.map
|
||||||
|
import kotlin.math.log10
|
||||||
|
|
||||||
class Compressor(val threshold: Int, val ratio: Float, val outputGain: Float):Filter {
|
/**
|
||||||
|
* @param threshold the threshold when the compressor starts in decibel
|
||||||
|
* @param ratio how much to compress when crossing the threshold. A ration of 6/1 means 1 decibel output for each 6 decibel over the threshold
|
||||||
|
* @param outputGain how much the signal should be amplified after compression
|
||||||
|
*/
|
||||||
|
class Compressor(private val threshold: Int, val ratio: Frac, val outputGain: Float):Filter() {
|
||||||
|
override fun stream(soundSamples: SoundSamples): SoundSamples {
|
||||||
|
return soundSamples.map(this::apply)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun apply(sample: Int): Int {
|
||||||
|
val db = signalToDB(sample)
|
||||||
|
|
||||||
|
if (db > threshold) {
|
||||||
|
val surplus = db - threshold;
|
||||||
|
val reduction = surplus - (surplus / ratio.value())
|
||||||
|
return dBToSignal(db - reduction + outputGain)
|
||||||
|
}
|
||||||
|
|
||||||
override fun stream(signal: Signal): Signal {
|
return dBToSignal(db + outputGain);
|
||||||
return signal;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,53 +1,40 @@
|
|||||||
package music.filter
|
package music.filter
|
||||||
|
|
||||||
import music.Signal
|
import music.SoundSamples
|
||||||
|
import kotlin.math.log10
|
||||||
interface Filter {
|
import kotlin.math.pow
|
||||||
fun stream(signal: Signal): Signal
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
abstract class Filter {
|
||||||
|
abstract fun stream(soundSamples: SoundSamples): SoundSamples
|
||||||
|
|
||||||
|
protected fun signalToDB(signal: Int): Double =
|
||||||
|
20 * log10(signal.toDouble())
|
||||||
|
|
||||||
|
protected fun dBToSignal(db: Double): Int =
|
||||||
|
10.0.pow(db / 20).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
enum class EaseFilter(val duration: Int = 32): Filter {
|
object DefaultEases {
|
||||||
IN {
|
val IN = EaseFilter(32, 0)
|
||||||
override fun stream (signal: Signal): Signal {
|
val OUT = EaseFilter(0, 32)
|
||||||
val len = kotlin.math.min(duration, signal.size)
|
val INOUT = EaseFilter(32, 32)
|
||||||
val start = signal.slice(0 until len)
|
|
||||||
val end = signal.slice(len until signal.size)
|
|
||||||
|
|
||||||
return (start.withIndex().map { i -> (i.value * (i.index / len.toFloat())).toInt() } + end).toTypedArray();
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
OUT {
|
class EaseFilter(val inDuration: Int, val outDuration: Int): Filter() {
|
||||||
override fun stream(signal: Signal): Signal {
|
|
||||||
val len = kotlin.math.min(duration, signal.size)
|
|
||||||
val sep = signal.size - len - 1;
|
|
||||||
val start = signal.slice(0 until sep)
|
|
||||||
val end = signal.slice(sep until signal.size)
|
|
||||||
|
|
||||||
return (start + end.withIndex().map { i -> (i.value * ((len - i.index) / len.toFloat())).toInt() }).toTypedArray();
|
override fun stream(soundSamples: SoundSamples): SoundSamples {
|
||||||
}
|
val inlen = kotlin.math.min(inDuration, soundSamples.size - outDuration)
|
||||||
},
|
val outlen = kotlin.math.min(outDuration, soundSamples.size - inlen)
|
||||||
|
|
||||||
INOUT {
|
val sep = soundSamples.size - outlen - 1;
|
||||||
override fun stream(signal: Signal): Signal {
|
val start = soundSamples.slice(0 until inlen)
|
||||||
val len = kotlin.math.min(duration, signal.size / 2)
|
val mid = soundSamples.slice(inlen until sep)
|
||||||
val sep = signal.size - len - 1;
|
val end = soundSamples.slice(sep until soundSamples.size)
|
||||||
val start = signal.slice(0 until len)
|
|
||||||
val mid = signal.slice(len until sep)
|
|
||||||
val end = signal.slice(sep until signal.size)
|
|
||||||
|
|
||||||
return (start.withIndex().map { i -> (i.value * (i.index / len.toFloat())).toInt() }
|
return (start.withIndex().map { i -> (i.value * (i.index / inlen.toFloat())).toInt() }
|
||||||
+ mid
|
+ mid
|
||||||
+ end.withIndex().map { i -> (i.value * ((len - i.index) / len.toFloat())).toInt() }
|
+ end.withIndex().map { i -> (i.value * ((outlen - i.index) / outlen.toFloat())).toInt() }
|
||||||
).toTypedArray();
|
).toTypedArray();
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
override fun stream(signal: Signal): Signal = signal
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package music.filter
|
package music.filter
|
||||||
|
|
||||||
import music.Signal
|
import music.SoundSamples
|
||||||
|
|
||||||
class FilterQueue(private vararg val filters: Filter): Filter {
|
class FilterQueue(private vararg val filters: Filter): Filter {
|
||||||
override fun stream(signal: Signal): Signal =
|
override fun stream(soundSamples: SoundSamples): SoundSamples =
|
||||||
filters.fold(signal, {acc, filter -> filter.stream(acc)})
|
filters.fold(soundSamples, { acc, filter -> filter.stream(acc)})
|
||||||
}
|
}
|
@ -1,11 +1,10 @@
|
|||||||
package music.generators
|
package music.generators
|
||||||
|
|
||||||
import music.Samples
|
import music.TimeSamples
|
||||||
import music.Signal
|
import music.SoundSamples
|
||||||
import music.WaveformTransformation
|
|
||||||
|
|
||||||
interface Generator {
|
interface Generator {
|
||||||
fun get(samples: Samples): Signal
|
fun get(timeSamples: TimeSamples): SoundSamples
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue