parallelised audio processing

This commit is contained in:
minjaesong
2023-11-26 19:00:29 +09:00
parent 1d727397b4
commit 29c4d92542
4 changed files with 57 additions and 4 deletions

View File

@@ -9,10 +9,12 @@ import net.torvald.terrarum.App
import net.torvald.terrarum.ModMgr
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RATE
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RATED
import net.torvald.terrarum.concurrent.ThreadExecutor
import net.torvald.terrarum.modulebasegame.MusicContainer
import net.torvald.terrarum.tryDispose
import java.lang.Thread.MAX_PRIORITY
import java.util.*
import java.util.concurrent.Callable
import kotlin.math.*
/**
@@ -86,8 +88,9 @@ object AudioMixer: Disposable {
var processing = true
private val processingExecutor = ThreadExecutor()
val processingThread = Thread {
while (processing) {
/*while (processing) {
// process
tracks.forEach {
if (!it.processor.paused) {
@@ -100,12 +103,32 @@ object AudioMixer: Disposable {
Thread.sleep(1)
}*/
while (!masterTrack.pcmQueue.isEmpty) {
masterTrack.adev!!.writeSamples(masterTrack.pcmQueue.removeFirst()) // it blocks until the queue is consumed
}
}*/
while (processing) {
parallelProcessingSchedule.forEach { tracks ->
val callables = tracks.map { Callable {
if (!it.processor.paused) {
it.processor.run()
}
} }
processingExecutor.renew()
processingExecutor.submitAll(callables)
processingExecutor.join()
}
while (!masterTrack.pcmQueue.isEmpty) {
masterTrack.adev!!.writeSamples(masterTrack.pcmQueue.removeFirst()) // it blocks until the queue is consumed
}
}
}
val parallelProcessingSchedule: Array<Array<TerrarumAudioMixerTrack>>
// val feeder = FeedSamplesToAdev(BUFFER_SIZE, SAMPLING_RATE, masterTrack)
// val feedingThread = Thread(feeder)
@@ -149,6 +172,14 @@ object AudioMixer: Disposable {
masterTrack.addSidechainInput(guiTrack, 1.0)
parallelProcessingSchedule = arrayOf(
arrayOf(musicTrack, ambientTrack, sfxMixTrack, guiTrack),
arrayOf(sumBus, convolveBusOpen, convolveBusCave),
arrayOf(fadeBus),
arrayOf(masterTrack)
)
processingThread.priority = MAX_PRIORITY // higher = more predictable; audio delay is very noticeable so it gets high priority
processingThread.start()
// feedingThread.priority = MAX_PRIORITY

View File

@@ -312,7 +312,7 @@ class Reverb(val delayMS: Float = 36f, var feedback: Float = 0.92f, var lowpass:
class Convolv(ir: File, val gain: Float = 1f / 256f): TerrarumAudioFilter() {
private val fftLen: Int
val fftLen: Int
private val convFFT: Array<ComplexArray>
// private val convFFTpartd: Array<Array<ComplexArray>> // index: Channel, partition, frequencies
private val inbuf: Array<FloatArray>

View File

@@ -20,7 +20,7 @@ class TerrarumAudioMixerTrack(val name: String, val isMaster: Boolean = false, v
const val SAMPLING_RATE = 48000
const val SAMPLING_RATEF = 48000f
const val SAMPLING_RATED = 48000.0
const val BUFFER_SIZE = 512*4 // n ms -> 384 * n
const val BUFFER_SIZE = 256*4 // n ms -> 384 * n
}
val hash = getHashStr()

View File

@@ -398,6 +398,10 @@ class BasicDebugInfoWindow : UICanvas() {
private val COL_METER_GRAD2 = Color(0x25a0f2_aa)
private val COL_SENDS_GRAD = Color(0x50751c_aa)
private val COL_SENDS_GRAD2 = Color(0xa0f225_aa.toInt())
private val COL_METER_GRAD_YELLOW = Color(0x62471c_aa)
private val COL_METER_GRAD2_YELLOW = Color(0xc68f24_aa.toInt())
private val COL_METER_GRAD_RED = Color(0x921c34_aa.toInt())
private val COL_METER_GRAD2_RED = Color(0xfa687d_aa.toInt())
private val COL_METER_BAR = Color(0x4caee5_aa)
private val COL_METER_BAR_OVER = Color(0xef8297_aa.toInt())
private val COL_METER_COMP_BAR = Color(0xf3d458_aa.toInt())
@@ -603,7 +607,7 @@ class BasicDebugInfoWindow : UICanvas() {
"Highpass" to 16,
"Buffer" to 16,
"BinoPan" to 32,
"Convolv" to 16,
"Convolv" to 32,
"Gain" to 16,
"Scope" to stripW,
)
@@ -653,8 +657,26 @@ class BasicDebugInfoWindow : UICanvas() {
App.fontSmallNumbers.draw(batch, "Bs:${BUFFER_SIZE/4}", x+3f, y+1f)
}
is Convolv -> {
// processing speed bar
val w = filter.processingSpeed
val perc = w.coerceAtMost(2f) / 2f
batch.color = if (w > 1.5f) COL_METER_GRAD2 else if (w > 1f) COL_METER_GRAD2_YELLOW else COL_METER_GRAD2_RED
Toolkit.fillArea(batch, x.toFloat(), y.toFloat(), stripW * perc, 14f)
batch.color = if (w > 1.5f) COL_METER_GRAD else if (w > 1f) COL_METER_GRAD_YELLOW else COL_METER_GRAD_RED
Toolkit.fillArea(batch, x.toFloat(), y+14f, stripW * perc, 2f)
// filter length bar
val g = FastMath.intLog2(BUFFER_SIZE / 4)
val perc2 = (FastMath.intLog2(filter.fftLen).minus(g).toFloat() / (16f - g)).coerceIn(0f, 1f)
batch.color = COL_METER_GRAD2
Toolkit.fillArea(batch, x.toFloat(), y + 16f, stripW * perc2, 14f)
batch.color = COL_METER_GRAD
Toolkit.fillArea(batch, x.toFloat(), y + 16f+14f, stripW * perc2, 2f)
// texts
batch.color = FILTER_NAME_ACTIVE
App.fontSmallNumbers.draw(batch, "P:${filter.processingSpeed.times(100).roundToInt().div(100f)}x", x+3f, y+1f)
App.fontSmallNumbers.draw(batch, "L:${filter.fftLen}", x+3f, y+17f)
}
is Gain -> {
batch.color = FILTER_NAME_ACTIVE