mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-12 19:44:05 +09:00
parallelised audio processing
This commit is contained in:
@@ -9,10 +9,12 @@ import net.torvald.terrarum.App
|
|||||||
import net.torvald.terrarum.ModMgr
|
import net.torvald.terrarum.ModMgr
|
||||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RATE
|
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RATE
|
||||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RATED
|
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.modulebasegame.MusicContainer
|
||||||
import net.torvald.terrarum.tryDispose
|
import net.torvald.terrarum.tryDispose
|
||||||
import java.lang.Thread.MAX_PRIORITY
|
import java.lang.Thread.MAX_PRIORITY
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.concurrent.Callable
|
||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -86,8 +88,9 @@ object AudioMixer: Disposable {
|
|||||||
|
|
||||||
var processing = true
|
var processing = true
|
||||||
|
|
||||||
|
private val processingExecutor = ThreadExecutor()
|
||||||
val processingThread = Thread {
|
val processingThread = Thread {
|
||||||
while (processing) {
|
/*while (processing) {
|
||||||
// process
|
// process
|
||||||
tracks.forEach {
|
tracks.forEach {
|
||||||
if (!it.processor.paused) {
|
if (!it.processor.paused) {
|
||||||
@@ -100,12 +103,32 @@ object AudioMixer: Disposable {
|
|||||||
Thread.sleep(1)
|
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) {
|
while (!masterTrack.pcmQueue.isEmpty) {
|
||||||
masterTrack.adev!!.writeSamples(masterTrack.pcmQueue.removeFirst()) // it blocks until the queue is consumed
|
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 feeder = FeedSamplesToAdev(BUFFER_SIZE, SAMPLING_RATE, masterTrack)
|
||||||
// val feedingThread = Thread(feeder)
|
// val feedingThread = Thread(feeder)
|
||||||
|
|
||||||
@@ -149,6 +172,14 @@ object AudioMixer: Disposable {
|
|||||||
masterTrack.addSidechainInput(guiTrack, 1.0)
|
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.priority = MAX_PRIORITY // higher = more predictable; audio delay is very noticeable so it gets high priority
|
||||||
processingThread.start()
|
processingThread.start()
|
||||||
// feedingThread.priority = MAX_PRIORITY
|
// feedingThread.priority = MAX_PRIORITY
|
||||||
|
|||||||
@@ -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() {
|
class Convolv(ir: File, val gain: Float = 1f / 256f): TerrarumAudioFilter() {
|
||||||
|
|
||||||
private val fftLen: Int
|
val fftLen: Int
|
||||||
private val convFFT: Array<ComplexArray>
|
private val convFFT: Array<ComplexArray>
|
||||||
// private val convFFTpartd: Array<Array<ComplexArray>> // index: Channel, partition, frequencies
|
// private val convFFTpartd: Array<Array<ComplexArray>> // index: Channel, partition, frequencies
|
||||||
private val inbuf: Array<FloatArray>
|
private val inbuf: Array<FloatArray>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class TerrarumAudioMixerTrack(val name: String, val isMaster: Boolean = false, v
|
|||||||
const val SAMPLING_RATE = 48000
|
const val SAMPLING_RATE = 48000
|
||||||
const val SAMPLING_RATEF = 48000f
|
const val SAMPLING_RATEF = 48000f
|
||||||
const val SAMPLING_RATED = 48000.0
|
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()
|
val hash = getHashStr()
|
||||||
|
|||||||
@@ -398,6 +398,10 @@ class BasicDebugInfoWindow : UICanvas() {
|
|||||||
private val COL_METER_GRAD2 = Color(0x25a0f2_aa)
|
private val COL_METER_GRAD2 = Color(0x25a0f2_aa)
|
||||||
private val COL_SENDS_GRAD = Color(0x50751c_aa)
|
private val COL_SENDS_GRAD = Color(0x50751c_aa)
|
||||||
private val COL_SENDS_GRAD2 = Color(0xa0f225_aa.toInt())
|
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 = Color(0x4caee5_aa)
|
||||||
private val COL_METER_BAR_OVER = Color(0xef8297_aa.toInt())
|
private val COL_METER_BAR_OVER = Color(0xef8297_aa.toInt())
|
||||||
private val COL_METER_COMP_BAR = Color(0xf3d458_aa.toInt())
|
private val COL_METER_COMP_BAR = Color(0xf3d458_aa.toInt())
|
||||||
@@ -603,7 +607,7 @@ class BasicDebugInfoWindow : UICanvas() {
|
|||||||
"Highpass" to 16,
|
"Highpass" to 16,
|
||||||
"Buffer" to 16,
|
"Buffer" to 16,
|
||||||
"BinoPan" to 32,
|
"BinoPan" to 32,
|
||||||
"Convolv" to 16,
|
"Convolv" to 32,
|
||||||
"Gain" to 16,
|
"Gain" to 16,
|
||||||
"Scope" to stripW,
|
"Scope" to stripW,
|
||||||
)
|
)
|
||||||
@@ -653,8 +657,26 @@ class BasicDebugInfoWindow : UICanvas() {
|
|||||||
App.fontSmallNumbers.draw(batch, "Bs:${BUFFER_SIZE/4}", x+3f, y+1f)
|
App.fontSmallNumbers.draw(batch, "Bs:${BUFFER_SIZE/4}", x+3f, y+1f)
|
||||||
}
|
}
|
||||||
is Convolv -> {
|
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
|
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, "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 -> {
|
is Gain -> {
|
||||||
batch.color = FILTER_NAME_ACTIVE
|
batch.color = FILTER_NAME_ACTIVE
|
||||||
|
|||||||
Reference in New Issue
Block a user