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
|
||||
|
||||
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 signal;
|
||||
return dBToSignal(db + outputGain);
|
||||
}
|
||||
}
|
@ -1,53 +1,40 @@
|
||||
package music.filter
|
||||
|
||||
import music.Signal
|
||||
|
||||
interface Filter {
|
||||
fun stream(signal: Signal): Signal
|
||||
}
|
||||
|
||||
|
||||
import music.SoundSamples
|
||||
import kotlin.math.log10
|
||||
import kotlin.math.pow
|
||||
|
||||
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 {
|
||||
IN {
|
||||
override fun stream (signal: Signal): Signal {
|
||||
val len = kotlin.math.min(duration, signal.size)
|
||||
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();
|
||||
object DefaultEases {
|
||||
val IN = EaseFilter(32, 0)
|
||||
val OUT = EaseFilter(0, 32)
|
||||
val INOUT = EaseFilter(32, 32)
|
||||
}
|
||||
},
|
||||
|
||||
OUT {
|
||||
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)
|
||||
class EaseFilter(val inDuration: Int, val outDuration: Int): Filter() {
|
||||
|
||||
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 {
|
||||
override fun stream(signal: Signal): Signal {
|
||||
val len = kotlin.math.min(duration, signal.size / 2)
|
||||
val sep = signal.size - len - 1;
|
||||
val start = signal.slice(0 until len)
|
||||
val mid = signal.slice(len until sep)
|
||||
val end = signal.slice(sep until signal.size)
|
||||
val sep = soundSamples.size - outlen - 1;
|
||||
val start = soundSamples.slice(0 until inlen)
|
||||
val mid = soundSamples.slice(inlen until sep)
|
||||
val end = soundSamples.slice(sep until soundSamples.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
|
||||
+ 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();
|
||||
}
|
||||
};
|
||||
|
||||
override fun stream(signal: Signal): Signal = signal
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
package music.filter
|
||||
|
||||
import music.Signal
|
||||
import music.SoundSamples
|
||||
|
||||
class FilterQueue(private vararg val filters: Filter): Filter {
|
||||
override fun stream(signal: Signal): Signal =
|
||||
filters.fold(signal, {acc, filter -> filter.stream(acc)})
|
||||
override fun stream(soundSamples: SoundSamples): SoundSamples =
|
||||
filters.fold(soundSamples, { acc, filter -> filter.stream(acc)})
|
||||
}
|
@ -1,11 +1,10 @@
|
||||
package music.generators
|
||||
|
||||
import music.Samples
|
||||
import music.Signal
|
||||
import music.WaveformTransformation
|
||||
import music.TimeSamples
|
||||
import music.SoundSamples
|
||||
|
||||
interface Generator {
|
||||
fun get(samples: Samples): Signal
|
||||
fun get(timeSamples: TimeSamples): SoundSamples
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue