mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-14 04:24:05 +09:00
sound engine is no longer a singleton
This commit is contained in:
@@ -7,20 +7,15 @@ import com.badlogic.gdx.utils.Disposable
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.spriteanimation.AssembledSpriteAnimation
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.App.THREAD_COUNT
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RATE
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RATED
|
||||
import net.torvald.terrarum.audio.dsp.*
|
||||
import net.torvald.terrarum.concurrent.ThreadExecutor
|
||||
import net.torvald.terrarum.concurrent.sliceEvenly
|
||||
import net.torvald.terrarum.gameactors.ActorWithBody
|
||||
import net.torvald.terrarum.modulebasegame.BuildingMaker
|
||||
import net.torvald.terrarum.modulebasegame.MusicContainer
|
||||
import java.lang.Thread.MAX_PRIORITY
|
||||
import java.util.*
|
||||
import java.util.concurrent.Callable
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import kotlin.math.*
|
||||
|
||||
/**
|
||||
@@ -28,13 +23,16 @@ import kotlin.math.*
|
||||
*
|
||||
* Created by minjaesong on 2023-11-07.
|
||||
*/
|
||||
object AudioMixer: Disposable {
|
||||
var SPEED_OF_SOUND = 340f
|
||||
class AudioMixer(val bufferSize: Int): Disposable {
|
||||
|
||||
const val SPEED_OF_SOUND_AIR = 340f
|
||||
const val SPEED_OF_SOUND_WATER = 1480f
|
||||
companion object {
|
||||
const val SPEED_OF_SOUND_AIR = 340f
|
||||
const val SPEED_OF_SOUND_WATER = 1480f
|
||||
const val SPEED_OF_SOUND = 340f
|
||||
|
||||
const val DEFAULT_FADEOUT_LEN = 1.8
|
||||
}
|
||||
|
||||
const val DEFAULT_FADEOUT_LEN = 1.8
|
||||
|
||||
val masterVolume: Double
|
||||
get() = App.getConfigDouble("mastervolume")
|
||||
@@ -99,7 +97,7 @@ object AudioMixer: Disposable {
|
||||
val fadeBus: TerrarumAudioMixerTrack
|
||||
get() = tracks[7]
|
||||
|
||||
var processing = true
|
||||
var processing = false
|
||||
|
||||
var actorNowPlaying = Terrarum.ingame?.actorNowPlaying; private set
|
||||
|
||||
@@ -128,8 +126,7 @@ object AudioMixer: Disposable {
|
||||
return (headSize0 ?: 0f).times(scale).coerceAtLeast(BinoPan.EARDIST_DEFAULT)
|
||||
}
|
||||
|
||||
private val processingExecutor = ThreadExecutor()
|
||||
val processingThread = Thread {
|
||||
fun createProcessingThread(): Thread = Thread {
|
||||
// serial precessing
|
||||
while (processing) {
|
||||
actorNowPlaying = Terrarum.ingame?.actorNowPlaying
|
||||
@@ -184,8 +181,13 @@ object AudioMixer: Disposable {
|
||||
masterTrack.adev!!.writeSamples(masterTrack.pcmQueue.removeFirst()) // it blocks until the queue is consumed
|
||||
}
|
||||
}*/
|
||||
}.also {
|
||||
it.priority = MAX_PRIORITY // higher = more predictable; audio delay is very noticeable so it gets high priority
|
||||
}
|
||||
|
||||
private val processingExecutor = ThreadExecutor()
|
||||
lateinit var processingThread: Thread
|
||||
|
||||
// val parallelProcessingSchedule: Array<Array<TerrarumAudioMixerTrack>>
|
||||
|
||||
|
||||
@@ -246,8 +248,8 @@ object AudioMixer: Disposable {
|
||||
arrayOf(fadeBus) +
|
||||
arrayOf(masterTrack)*/
|
||||
|
||||
|
||||
processingThread.priority = MAX_PRIORITY // higher = more predictable; audio delay is very noticeable so it gets high priority
|
||||
processingThread = createProcessingThread()
|
||||
processing = true
|
||||
processingThread.start()
|
||||
// feedingThread.priority = MAX_PRIORITY
|
||||
// feedingThread.start()
|
||||
@@ -306,7 +308,7 @@ object AudioMixer: Disposable {
|
||||
if (Gdx.input.isKeyPressed(Input.Keys.NUM_3))
|
||||
testAudioMixRatio = 1.0
|
||||
if (!muteLatched && Gdx.input.isKeyPressed(Input.Keys.NUM_4)) {
|
||||
AudioMixer.sumBus.volume = 1.0 - AudioMixer.sumBus.volume
|
||||
sumBus.volume = 1.0 - sumBus.volume
|
||||
muteLatched = true
|
||||
}
|
||||
else if (!Gdx.input.isKeyPressed(Input.Keys.NUM_4))
|
||||
@@ -316,13 +318,13 @@ object AudioMixer: Disposable {
|
||||
|
||||
if (testAudioMixRatio >= 0.0) {
|
||||
val ratio1 = testAudioMixRatio.coerceIn(0.0, 1.0)
|
||||
AudioMixer.convolveBusCave.volume = ratio1
|
||||
AudioMixer.convolveBusOpen.volume = 1.0 - ratio1
|
||||
convolveBusCave.volume = ratio1
|
||||
convolveBusOpen.volume = 1.0 - ratio1
|
||||
}
|
||||
else {
|
||||
val ratio1 = (testAudioMixRatio / MaterialCodex["AIIR"].sondrefl).absoluteValue.coerceIn(0.0, 1.0)
|
||||
AudioMixer.convolveBusOpen.volume = (1.0 - ratio1).pow(0.75)
|
||||
AudioMixer.convolveBusCave.volume = 0.0
|
||||
convolveBusOpen.volume = (1.0 - ratio1).pow(0.75)
|
||||
convolveBusCave.volume = 0.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -496,6 +498,35 @@ object AudioMixer: Disposable {
|
||||
}, 500L)
|
||||
}
|
||||
|
||||
fun updateBufferSizeChange() {
|
||||
processing = false
|
||||
processingThread.interrupt()
|
||||
|
||||
|
||||
|
||||
dynamicTracks.forEach { it.stop() }
|
||||
tracks.filter { it.trackType == TrackType.STATIC_SOURCE }.forEach { it.stop() }
|
||||
masterTrack.volume = 0.0
|
||||
|
||||
dynamicTracks.forEach { it.updateBufferSizeChange() }
|
||||
tracks.forEach { it.updateBufferSizeChange() }
|
||||
masterTrack.updateBufferSizeChange()
|
||||
|
||||
|
||||
|
||||
processingThread = createProcessingThread()
|
||||
processing = true
|
||||
processingThread.start()
|
||||
|
||||
|
||||
// give some time for the cave bus to decay before ramping the volume up
|
||||
Timer().schedule(object : TimerTask() {
|
||||
override fun run() {
|
||||
masterTrack.volume = 1.0
|
||||
}
|
||||
}, 500L)
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
processingExecutor.killAll()
|
||||
// processingSubthreads.forEach { it.interrupt() }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package net.torvald.terrarum.audio
|
||||
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.AUDIO_BUFFER_SIZE
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RATE
|
||||
import net.torvald.terrarum.ceilToInt
|
||||
import net.torvald.terrarum.floorToInt
|
||||
@@ -54,7 +54,6 @@ class AudioProcessBuf(val inputSamplingRate: Int, val audioReadFun: (ByteArray)
|
||||
}
|
||||
}
|
||||
|
||||
private val BS = AUDIO_BUFFER_SIZE
|
||||
private val MP3_CHUNK_SIZE = 1152 // 1152 for 32k-48k, 576 for 16k-24k, 384 for 8k-12k
|
||||
|
||||
|
||||
@@ -76,13 +75,13 @@ class AudioProcessBuf(val inputSamplingRate: Int, val audioReadFun: (ByteArray)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getOptimalBufferSize(rate: Int) = bufLut[BS to rate]!!
|
||||
private fun getOptimalBufferSize(rate: Int) = bufLut[App.audioBufferSize to rate]!!
|
||||
}
|
||||
|
||||
private val q
|
||||
get() = internalSamplingRate.toDouble() / SAMPLING_RATE // <= 1.0
|
||||
|
||||
private val fetchSize = (BS.toFloat() / MP3_CHUNK_SIZE).ceilToInt() * MP3_CHUNK_SIZE // fetchSize is always multiple of MP3_CHUNK_SIZE, even if the audio is NOT MP3
|
||||
private val fetchSize = (App.audioBufferSize.toFloat() / MP3_CHUNK_SIZE).ceilToInt() * MP3_CHUNK_SIZE // fetchSize is always multiple of MP3_CHUNK_SIZE, even if the audio is NOT MP3
|
||||
private val internalBufferSize = getOptimalBufferSize(inputSamplingRate)// fetchSize * 3
|
||||
|
||||
private val PADSIZE = TAPS + 1
|
||||
@@ -120,13 +119,17 @@ class AudioProcessBuf(val inputSamplingRate: Int, val audioReadFun: (ByteArray)
|
||||
private val foutR = FloatArray(internalBufferSize) // 640 for (44100, 48000), 512 for (48000, 48000) with BUFFER_SIZE = 512 * 4
|
||||
private val readBuf = ByteArray(fetchSize * 4)
|
||||
|
||||
init {
|
||||
printdbg(this, "App.audioMixerBufferSize=${App.audioBufferSize}")
|
||||
}
|
||||
|
||||
private fun shift(array: FloatArray, size: Int) {
|
||||
System.arraycopy(array, size, array, 0, array.size - size)
|
||||
for (i in array.size - size until array.size) { array[i] = 0f }
|
||||
}
|
||||
|
||||
fun fetchBytes() {
|
||||
val readCount = if (validSamplesInBuf < BS) fetchSize else 0
|
||||
val readCount = if (validSamplesInBuf < App.audioBufferSize) fetchSize else 0
|
||||
val writeCount = (readCount / q).roundToInt()
|
||||
|
||||
fun getFromReadBuf(i: Int, bytesRead: Int) = if (i < bytesRead) readBuf[i].toUint() else 0
|
||||
@@ -187,17 +190,17 @@ class AudioProcessBuf(val inputSamplingRate: Int, val audioReadFun: (ByteArray)
|
||||
|
||||
fun getLR(volume: Double): Pair<FloatArray, FloatArray> {
|
||||
// copy into the out
|
||||
val outL = FloatArray(BS) { (foutL[it] * volume).toFloat() }
|
||||
val outR = FloatArray(BS) { (foutR[it] * volume).toFloat() }
|
||||
val outL = FloatArray(App.audioBufferSize) { (foutL[it] * volume).toFloat() }
|
||||
val outR = FloatArray(App.audioBufferSize) { (foutR[it] * volume).toFloat() }
|
||||
// shift bytes in the fout
|
||||
System.arraycopy(foutL, BS, foutL, 0, validSamplesInBuf - BS)
|
||||
System.arraycopy(foutR, BS, foutR, 0, validSamplesInBuf - BS)
|
||||
for (i in validSamplesInBuf until BS) {
|
||||
System.arraycopy(foutL, App.audioBufferSize, foutL, 0, validSamplesInBuf - App.audioBufferSize)
|
||||
System.arraycopy(foutR, App.audioBufferSize, foutR, 0, validSamplesInBuf - App.audioBufferSize)
|
||||
for (i in validSamplesInBuf until App.audioBufferSize) {
|
||||
foutL[i] = 0f
|
||||
foutR[i] = 0f
|
||||
}
|
||||
// decrement necessary variables
|
||||
validSamplesInBuf -= BS
|
||||
validSamplesInBuf -= App.audioBufferSize
|
||||
|
||||
return outL to outR
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package net.torvald.terrarum.audio
|
||||
|
||||
import com.badlogic.gdx.utils.Queue
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.reflection.forceInvoke
|
||||
import net.torvald.spriteanimation.AssembledSpriteAnimation
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RATE
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RATED
|
||||
@@ -19,7 +17,18 @@ import kotlin.math.*
|
||||
/**
|
||||
* Created by minjaesong on 2023-11-17.
|
||||
*/
|
||||
class MixerTrackProcessor(val buffertaille: Int, val rate: Int, val track: TerrarumAudioMixerTrack): Runnable {
|
||||
class MixerTrackProcessor(bufferSize: Int, val rate: Int, val track: TerrarumAudioMixerTrack): Runnable {
|
||||
|
||||
private var buffertaille = bufferSize
|
||||
|
||||
fun reset(newBufferSize: Int) {
|
||||
buffertaille = newBufferSize
|
||||
// printdbg("new buffertaille = $buffertaille")
|
||||
emptyBuf = FloatArray(buffertaille)
|
||||
fout1 = listOf(emptyBuf, emptyBuf)
|
||||
purgeStreamBuf()
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
}
|
||||
@@ -29,7 +38,7 @@ class MixerTrackProcessor(val buffertaille: Int, val rate: Int, val track: Terra
|
||||
private val pauseLock = java.lang.Object()
|
||||
|
||||
|
||||
private val emptyBuf = FloatArray(buffertaille)
|
||||
private var emptyBuf = FloatArray(buffertaille)
|
||||
|
||||
|
||||
internal var streamBuf: AudioProcessBuf? = null
|
||||
@@ -117,18 +126,18 @@ class MixerTrackProcessor(val buffertaille: Int, val rate: Int, val track: Terra
|
||||
|
||||
// update panning and shits
|
||||
if (track.trackType == TrackType.DYNAMIC_SOURCE && track.isPlaying) {
|
||||
(track.filters[0] as BinoPan).earDist = AudioMixer.listenerHeadSize
|
||||
(track.filters[0] as BinoPan).earDist = App.audioMixer.listenerHeadSize
|
||||
|
||||
if (AudioMixer.actorNowPlaying != null) {
|
||||
if (track.trackingTarget == null || track.trackingTarget == AudioMixer.actorNowPlaying) {
|
||||
if (App.audioMixer.actorNowPlaying != null) {
|
||||
if (track.trackingTarget == null || track.trackingTarget == App.audioMixer.actorNowPlaying) {
|
||||
// "reset" the track
|
||||
track.volume = track.maxVolume
|
||||
(track.filters[0] as BinoPan).pan = 0f
|
||||
(track.filters[1] as Lowpass).setCutoff(SAMPLING_RATE / 2f)
|
||||
}
|
||||
else if (track.trackingTarget is ActorWithBody) {
|
||||
val relativeXpos = relativeXposition(AudioMixer.actorNowPlaying!!, track.trackingTarget as ActorWithBody)
|
||||
val distFromActor = distBetweenActors(AudioMixer.actorNowPlaying!!, track.trackingTarget as ActorWithBody)
|
||||
val relativeXpos = relativeXposition(App.audioMixer.actorNowPlaying!!, track.trackingTarget as ActorWithBody)
|
||||
val distFromActor = distBetweenActors(App.audioMixer.actorNowPlaying!!, track.trackingTarget as ActorWithBody)
|
||||
val vol = track.maxVolume * getVolFun(distFromActor / distFalloff).coerceAtLeast(0.0)
|
||||
track.volume = vol
|
||||
(track.filters[0] as BinoPan).pan = (1.3f * relativeXpos / distFalloff).toFloat()
|
||||
@@ -169,7 +178,13 @@ class MixerTrackProcessor(val buffertaille: Int, val rate: Int, val track: Terra
|
||||
// add all up
|
||||
sidechains.forEach { (side, mix) ->
|
||||
for (i in samplesL1.indices) {
|
||||
samplesL1[i] += side.processor.fout1[0][i] * (mix * track.volume).toFloat()
|
||||
// try {
|
||||
samplesL1[i] += side.processor.fout1[0][i] * (mix * track.volume).toFloat()
|
||||
// }
|
||||
// catch (e: ArrayIndexOutOfBoundsException) {
|
||||
// printdbg("buffertaille = $buffertaille, samplesL1 size = ${samplesL1.size}, side.processor.fout1[0] size = ${side.processor.fout1[0].size}")
|
||||
// throw e
|
||||
// }
|
||||
samplesR1[i] += side.processor.fout1[1][i] * (mix * track.volume).toFloat()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package net.torvald.terrarum.audio
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.audio.Sound
|
||||
import com.badlogic.gdx.backends.lwjgl3.audio.OpenALLwjgl3Audio
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import com.badlogic.gdx.utils.Queue
|
||||
import net.torvald.reflection.forceInvoke
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.audio.dsp.NullFilter
|
||||
import net.torvald.terrarum.audio.dsp.TerrarumAudioFilter
|
||||
@@ -35,7 +33,6 @@ class TerrarumAudioMixerTrack(
|
||||
const val SAMPLING_RATE = 48000
|
||||
const val SAMPLING_RATEF = 48000f
|
||||
const val SAMPLING_RATED = 48000.0
|
||||
val AUDIO_BUFFER_SIZE = App.getConfigInt("audio_buffer_size") // n ms -> 384 * n
|
||||
}
|
||||
|
||||
val hash = getHashStr()
|
||||
@@ -168,7 +165,7 @@ class TerrarumAudioMixerTrack(
|
||||
|
||||
// 1st ring of the hell: the THREADING HELL //
|
||||
|
||||
internal var processor = MixerTrackProcessor(AUDIO_BUFFER_SIZE, SAMPLING_RATE, this)
|
||||
internal var processor = MixerTrackProcessor(App.audioBufferSize, SAMPLING_RATE, this)
|
||||
/*private val processorThread = Thread(processor).also { // uncomment to multithread
|
||||
it.priority = MAX_PRIORITY // higher = more predictable; audio delay is very noticeable so it gets high priority
|
||||
it.start()
|
||||
@@ -178,8 +175,8 @@ class TerrarumAudioMixerTrack(
|
||||
private lateinit var queueDispatcherThread: Thread
|
||||
|
||||
init {
|
||||
pcmQueue.addLast(listOf(FloatArray(AUDIO_BUFFER_SIZE), FloatArray(AUDIO_BUFFER_SIZE)))
|
||||
pcmQueue.addLast(listOf(FloatArray(AUDIO_BUFFER_SIZE), FloatArray(AUDIO_BUFFER_SIZE)))
|
||||
pcmQueue.addLast(listOf(FloatArray(App.audioBufferSize), FloatArray(App.audioBufferSize)))
|
||||
pcmQueue.addLast(listOf(FloatArray(App.audioBufferSize), FloatArray(App.audioBufferSize)))
|
||||
|
||||
/*if (isMaster) { // uncomment to multithread
|
||||
queueDispatcher = FeedSamplesToAdev(BUFFER_SIZE, SAMPLING_RATE, this)
|
||||
@@ -190,6 +187,16 @@ class TerrarumAudioMixerTrack(
|
||||
}*/
|
||||
}
|
||||
|
||||
fun updateBufferSizeChange() {
|
||||
// printdbg(this, "new buffer size: $App.audioMixerBufferSize")
|
||||
pcmQueue.clear()
|
||||
pcmQueue.addLast(listOf(FloatArray(App.audioBufferSize), FloatArray(App.audioBufferSize)))
|
||||
pcmQueue.addLast(listOf(FloatArray(App.audioBufferSize), FloatArray(App.audioBufferSize)))
|
||||
processor.reset(App.audioBufferSize)
|
||||
filters.forEach { it.reset() }
|
||||
}
|
||||
|
||||
|
||||
override fun hashCode() = hashCode0
|
||||
}
|
||||
|
||||
|
||||
@@ -3,10 +3,7 @@ package net.torvald.terrarum.audio.dsp
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.audio.AudioMixer
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.AUDIO_BUFFER_SIZE
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RATEF
|
||||
import net.torvald.terrarum.audio.decibelsToFullscale
|
||||
import net.torvald.terrarum.ceilToInt
|
||||
@@ -43,8 +40,8 @@ class BinoPan(var pan: Float, var earDist: Float = EARDIST_DEFAULT): TerrarumAud
|
||||
private val delays = arrayOf(0f, 0f)
|
||||
private val mults = arrayOf(1f, 1f)
|
||||
|
||||
private val outLs = Array(2) { FloatArray(AUDIO_BUFFER_SIZE) }
|
||||
private val outRs = Array(2) { FloatArray(AUDIO_BUFFER_SIZE) }
|
||||
private var outLs = Array(2) { FloatArray(App.audioBufferSize) }
|
||||
private var outRs = Array(2) { FloatArray(App.audioBufferSize) }
|
||||
|
||||
|
||||
companion object {
|
||||
@@ -58,6 +55,13 @@ class BinoPan(var pan: Float, var earDist: Float = EARDIST_DEFAULT): TerrarumAud
|
||||
private val HALF_PI = (Math.PI / 2.0).toFloat()
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
outLs = Array(2) { FloatArray(App.audioBufferSize) }
|
||||
outRs = Array(2) { FloatArray(App.audioBufferSize) }
|
||||
delayLineL.fill(0f)
|
||||
delayLineR.fill(0f)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param intensity -inf to +inf
|
||||
*/
|
||||
@@ -104,7 +108,7 @@ class BinoPan(var pan: Float, var earDist: Float = EARDIST_DEFAULT): TerrarumAud
|
||||
mults[R] = volMultFsOther
|
||||
}
|
||||
|
||||
for (i in 0 until AUDIO_BUFFER_SIZE) {
|
||||
for (i in 0 until App.audioBufferSize) {
|
||||
sumbuf[L][i] = mults[L] * getFrom(i - delays[L], delayLine, inbuf)
|
||||
sumbuf[R][i] = mults[R] * getFrom(i - delays[R], delayLine, inbuf)
|
||||
}
|
||||
@@ -115,7 +119,7 @@ class BinoPan(var pan: Float, var earDist: Float = EARDIST_DEFAULT): TerrarumAud
|
||||
thru("L", -50f, inbuf[L], outLs, delayLineL) // 50 will become 59.036 on panningFieldMap
|
||||
thru("R", +50f, inbuf[R], outRs, delayLineR)
|
||||
|
||||
for (i in 0 until AUDIO_BUFFER_SIZE) {
|
||||
for (i in 0 until App.audioBufferSize) {
|
||||
val outL = (outLs[L][i] + outRs[L][i]) / 2f
|
||||
val outR = (outLs[R][i] + outRs[R][i]) / 2f
|
||||
outbuf[L][i] = outL
|
||||
|
||||
@@ -3,7 +3,6 @@ package net.torvald.terrarum.audio.dsp
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
|
||||
import net.torvald.terrarum.audio.linToLogPerc
|
||||
import net.torvald.terrarum.roundToFloat
|
||||
import net.torvald.terrarum.ui.BasicDebugInfoWindow
|
||||
@@ -13,7 +12,7 @@ import net.torvald.terrarum.ui.Toolkit
|
||||
class Bitcrush(var steps: Int, var inputGain: Float = 1f): TerrarumAudioFilter() {
|
||||
override fun thru(inbuf: List<FloatArray>, outbuf: List<FloatArray>) {
|
||||
for (ch in outbuf.indices) {
|
||||
for (i in 0 until TerrarumAudioMixerTrack.AUDIO_BUFFER_SIZE) {
|
||||
for (i in 0 until App.audioBufferSize) {
|
||||
val inn = ((inbuf[ch][i] * inputGain).coerceIn(-1f, 1f) + 1f) / 2f // 0f..1f
|
||||
val stepped = (inn * (steps - 1)).roundToFloat() / (steps - 1)
|
||||
val out = (stepped * 2f) - 1f // -1f..1f
|
||||
@@ -35,5 +34,8 @@ class Bitcrush(var steps: Int, var inputGain: Float = 1f): TerrarumAudioFilter()
|
||||
App.fontSmallNumbers.draw(batch, "B:$bits", x+3f, y+1f)
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
}
|
||||
|
||||
override val debugViewHeight = 16
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package net.torvald.terrarum.audio.dsp
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.AUDIO_BUFFER_SIZE
|
||||
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.FILTER_NAME_ACTIVE
|
||||
|
||||
object Buffer : TerrarumAudioFilter() {
|
||||
@@ -16,7 +15,10 @@ object Buffer : TerrarumAudioFilter() {
|
||||
|
||||
override fun drawDebugView(batch: SpriteBatch, x: Int, y: Int) {
|
||||
batch.color = FILTER_NAME_ACTIVE
|
||||
App.fontSmallNumbers.draw(batch, "Bs:${AUDIO_BUFFER_SIZE}", x+3f, y+1f)
|
||||
App.fontSmallNumbers.draw(batch, "Bs:${App.audioBufferSize}", x+3f, y+1f)
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
}
|
||||
|
||||
override val debugViewHeight = 16
|
||||
|
||||
@@ -5,8 +5,6 @@ import com.jme3.math.FastMath
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.App.setDebugTime
|
||||
import net.torvald.terrarum.audio.*
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.AUDIO_BUFFER_SIZE
|
||||
import net.torvald.terrarum.ui.BasicDebugInfoWindow
|
||||
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.COL_METER_GRAD
|
||||
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.COL_METER_GRAD2
|
||||
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.COL_METER_GRAD2_RED
|
||||
@@ -25,14 +23,13 @@ import kotlin.math.roundToInt
|
||||
* @param gain output gain. Fullscale (0.0 - 1.0)
|
||||
*/
|
||||
class Convolv(ir: File, val crossfeed: Float, gain: Float = 1f / 256f): TerrarumAudioFilter() {
|
||||
|
||||
private val gain: Float = gain / (1f + crossfeed)
|
||||
|
||||
val fftLen: Int
|
||||
private val convFFT: Array<ComplexArray>
|
||||
private val sumbuf: Array<ComplexArray>
|
||||
|
||||
private val BLOCKSIZE = TerrarumAudioMixerTrack.AUDIO_BUFFER_SIZE
|
||||
|
||||
var processingSpeed = 1f; private set
|
||||
|
||||
init {
|
||||
@@ -71,12 +68,18 @@ class Convolv(ir: File, val crossfeed: Float, gain: Float = 1f / 256f): Terrarum
|
||||
}
|
||||
}
|
||||
|
||||
private val realtime = (BLOCKSIZE / TerrarumAudioMixerTrack.SAMPLING_RATEF * 1000000000L)
|
||||
private var realtime = (App.audioBufferSize / TerrarumAudioMixerTrack.SAMPLING_RATEF * 1000000000L)
|
||||
private val fftIn = ComplexArray(FloatArray(fftLen * 2))
|
||||
private val fftMult = ComplexArray(FloatArray(fftLen * 2))
|
||||
private val fftOutL = FloatArray(fftLen)
|
||||
private val fftOutR = FloatArray(fftLen)
|
||||
|
||||
override fun reset() {
|
||||
realtime = (App.audioBufferSize / TerrarumAudioMixerTrack.SAMPLING_RATEF * 1000000000L)
|
||||
processingSpeed = 1f
|
||||
sumbuf.forEach { it.reim.fill(0f) }
|
||||
}
|
||||
|
||||
private fun convolve(x: ComplexArray, h: ComplexArray, output: FloatArray) {
|
||||
FFT.fftInto(x, fftIn)
|
||||
fftIn.mult(h, fftMult)
|
||||
@@ -96,9 +99,9 @@ class Convolv(ir: File, val crossfeed: Float, gain: Float = 1f / 256f): Terrarum
|
||||
convolve(sumbuf[0], convFFT[0], fftOutL)
|
||||
convolve(sumbuf[1], convFFT[1], fftOutR)
|
||||
|
||||
for (i in 0 until BLOCKSIZE) {
|
||||
outbuf[0][i] = fftOutL[fftLen - BLOCKSIZE + i]
|
||||
outbuf[1][i] = fftOutR[fftLen - BLOCKSIZE + i]
|
||||
for (i in 0 until App.audioBufferSize) {
|
||||
outbuf[0][i] = fftOutL[fftLen - App.audioBufferSize + i]
|
||||
outbuf[1][i] = fftOutR[fftLen - App.audioBufferSize + i]
|
||||
}
|
||||
|
||||
|
||||
@@ -144,7 +147,7 @@ class Convolv(ir: File, val crossfeed: Float, gain: Float = 1f / 256f): Terrarum
|
||||
Toolkit.fillArea(batch, x.toFloat(), y+14f, STRIP_W * perc, 2f)
|
||||
|
||||
// filter length bar
|
||||
val g = FastMath.intLog2(AUDIO_BUFFER_SIZE)
|
||||
val g = FastMath.intLog2(App.audioBufferSize)
|
||||
val perc2 = (FastMath.intLog2(fftLen).minus(g).toFloat() / (16f - g)).coerceIn(0f, 1f)
|
||||
batch.color = COL_METER_GRAD2
|
||||
Toolkit.fillArea(batch, x.toFloat(), y + 16f, STRIP_W * perc2, 14f)
|
||||
|
||||
@@ -2,14 +2,13 @@ package net.torvald.terrarum.audio.dsp
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
|
||||
import net.torvald.terrarum.audio.fullscaleToDecibels
|
||||
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.FILTER_NAME_ACTIVE
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class Gain(var gain: Float): TerrarumAudioFilter() {
|
||||
override fun thru(inbuf: List<FloatArray>, outbuf: List<FloatArray>) {
|
||||
for (i in 0 until TerrarumAudioMixerTrack.AUDIO_BUFFER_SIZE) {
|
||||
for (i in 0 until App.audioBufferSize) {
|
||||
outbuf[0][i] = inbuf[0][i] * gain
|
||||
outbuf[1][i] = inbuf[1][i] * gain
|
||||
}
|
||||
@@ -20,5 +19,9 @@ class Gain(var gain: Float): TerrarumAudioFilter() {
|
||||
App.fontSmallNumbers.draw(batch, "G:${fullscaleToDecibels(gain.toDouble()).times(100).roundToInt().div(100f)}", x+3f, y+1f)
|
||||
}
|
||||
|
||||
|
||||
override fun reset() {
|
||||
}
|
||||
|
||||
override val debugViewHeight = 16
|
||||
}
|
||||
@@ -68,4 +68,8 @@ class Highpass(cutoff0: Float): TerrarumAudioFilter() {
|
||||
|
||||
override val debugViewHeight = 16
|
||||
|
||||
override fun reset() {
|
||||
in0.fill(0f)
|
||||
out0.fill(0f)
|
||||
}
|
||||
}
|
||||
@@ -67,4 +67,9 @@ class Lowpass(cutoff0: Float): TerrarumAudioFilter() {
|
||||
}
|
||||
|
||||
override val debugViewHeight = 16
|
||||
|
||||
override fun reset() {
|
||||
in0.fill(0f)
|
||||
out0.fill(0f)
|
||||
}
|
||||
}
|
||||
@@ -13,4 +13,7 @@ object NullFilter : TerrarumAudioFilter() {
|
||||
}
|
||||
|
||||
override val debugViewHeight = 0
|
||||
|
||||
override fun reset() {
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package net.torvald.terrarum.audio.dsp
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@@ -31,7 +32,7 @@ class Reverb(val delayMS: Float = 36f, var feedback: Float = 0.92f, var lowpass:
|
||||
val alphaHi = RCHi / (RCHi + dt)
|
||||
|
||||
for (ch in outbuf.indices) {
|
||||
for (i in 0 until TerrarumAudioMixerTrack.AUDIO_BUFFER_SIZE) {
|
||||
for (i in 0 until App.audioBufferSize) {
|
||||
val inn = inbuf[ch][i]
|
||||
|
||||
// reverb
|
||||
@@ -52,4 +53,8 @@ class Reverb(val delayMS: Float = 36f, var feedback: Float = 0.92f, var lowpass:
|
||||
}
|
||||
|
||||
override val debugViewHeight = 0
|
||||
|
||||
override fun reset() {
|
||||
buf.forEach { it.fill(0f) }
|
||||
}
|
||||
}
|
||||
@@ -56,4 +56,7 @@ object SoftClp : TerrarumAudioFilter() {
|
||||
}
|
||||
|
||||
override val debugViewHeight = 0
|
||||
|
||||
override fun reset() {
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,8 @@ package net.torvald.terrarum.audio.dsp
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.audio.*
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.AUDIO_BUFFER_SIZE
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RATED
|
||||
import net.torvald.terrarum.ui.BasicDebugInfoWindow
|
||||
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.STRIP_W
|
||||
@@ -91,15 +91,18 @@ class Spectro(val gain: Float = 1f) : TerrarumAudioFilter() {
|
||||
}
|
||||
|
||||
override val debugViewHeight = STRIP_W
|
||||
|
||||
override fun reset() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Vecto(val gain: Float = 1f) : TerrarumAudioFilter() {
|
||||
val backbufL = Array((6144f / AUDIO_BUFFER_SIZE).roundToInt().coerceAtLeast(1)) {
|
||||
FloatArray(AUDIO_BUFFER_SIZE)
|
||||
var backbufL = Array((6144f / App.audioBufferSize).roundToInt().coerceAtLeast(1)) {
|
||||
FloatArray(App.audioBufferSize)
|
||||
}
|
||||
val backbufR = Array((6144f / AUDIO_BUFFER_SIZE).roundToInt().coerceAtLeast(1)) {
|
||||
FloatArray(AUDIO_BUFFER_SIZE)
|
||||
var backbufR = Array((6144f / App.audioBufferSize).roundToInt().coerceAtLeast(1)) {
|
||||
FloatArray(App.audioBufferSize)
|
||||
}
|
||||
|
||||
private val sqrt2p = 0.7071067811865475
|
||||
@@ -110,11 +113,11 @@ class Vecto(val gain: Float = 1f) : TerrarumAudioFilter() {
|
||||
backbufL[i] = backbufL[i - 1]
|
||||
backbufR[i] = backbufR[i - 1]
|
||||
}
|
||||
backbufL[0] = FloatArray(TerrarumAudioMixerTrack.AUDIO_BUFFER_SIZE)
|
||||
backbufR[0] = FloatArray(TerrarumAudioMixerTrack.AUDIO_BUFFER_SIZE)
|
||||
backbufL[0] = FloatArray(App.audioBufferSize)
|
||||
backbufR[0] = FloatArray(App.audioBufferSize)
|
||||
|
||||
// plot dots
|
||||
for (i in 0 until TerrarumAudioMixerTrack.AUDIO_BUFFER_SIZE) {
|
||||
for (i in 0 until App.audioBufferSize) {
|
||||
val y0 = +inbuf[0][i] * gain
|
||||
val x0 = -inbuf[1][i] * gain// rotate the domain by -90 deg
|
||||
|
||||
@@ -154,4 +157,13 @@ class Vecto(val gain: Float = 1f) : TerrarumAudioFilter() {
|
||||
}
|
||||
|
||||
override val debugViewHeight = STRIP_W
|
||||
|
||||
override fun reset() {
|
||||
backbufL = Array((6144f / App.audioBufferSize).roundToInt().coerceAtLeast(1)) {
|
||||
FloatArray(App.audioBufferSize)
|
||||
}
|
||||
backbufR = Array((6144f / App.audioBufferSize).roundToInt().coerceAtLeast(1)) {
|
||||
FloatArray(App.audioBufferSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ abstract class TerrarumAudioFilter {
|
||||
}
|
||||
else thru(inbuf, outbuf)
|
||||
}
|
||||
abstract fun reset()
|
||||
abstract fun drawDebugView(batch: SpriteBatch, x: Int, y: Int)
|
||||
abstract val debugViewHeight: Int
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package net.torvald.terrarum.audio.dsp
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
|
||||
import net.torvald.terrarum.App
|
||||
|
||||
object XYtoMS: TerrarumAudioFilter() {
|
||||
override fun thru(inbuf: List<FloatArray>, outbuf: List<FloatArray>) {
|
||||
for (i in 0 until TerrarumAudioMixerTrack.AUDIO_BUFFER_SIZE) {
|
||||
for (i in 0 until App.audioBufferSize) {
|
||||
val X = inbuf[0][i]
|
||||
val Y = inbuf[1][i]
|
||||
val M = (X + Y) / 2f
|
||||
@@ -19,11 +19,14 @@ object XYtoMS: TerrarumAudioFilter() {
|
||||
}
|
||||
|
||||
override val debugViewHeight = 0
|
||||
|
||||
override fun reset() {
|
||||
}
|
||||
}
|
||||
|
||||
object MStoXY: TerrarumAudioFilter() {
|
||||
override fun thru(inbuf: List<FloatArray>, outbuf: List<FloatArray>) {
|
||||
for (i in 0 until TerrarumAudioMixerTrack.AUDIO_BUFFER_SIZE) {
|
||||
for (i in 0 until App.audioBufferSize) {
|
||||
val M = inbuf[0][i]
|
||||
val S = inbuf[1][i]
|
||||
val X = M + S
|
||||
@@ -37,4 +40,7 @@ object MStoXY: TerrarumAudioFilter() {
|
||||
}
|
||||
|
||||
override val debugViewHeight = 0
|
||||
|
||||
override fun reset() {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user