From 6c8c0369199c072471a2439efe33ccf1fbe13acf Mon Sep 17 00:00:00 2001 From: minjaesong Date: Sun, 19 Nov 2023 21:43:29 +0900 Subject: [PATCH] mixer: clipping detector --- .../terrarum/audio/MixerTrackProcessor.kt | 14 +++++++++++ .../terrarum/ui/BasicDebugInfoWindow.kt | 23 ++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/net/torvald/terrarum/audio/MixerTrackProcessor.kt b/src/net/torvald/terrarum/audio/MixerTrackProcessor.kt index 5b8bf20bd..52eb1762d 100644 --- a/src/net/torvald/terrarum/audio/MixerTrackProcessor.kt +++ b/src/net/torvald/terrarum/audio/MixerTrackProcessor.kt @@ -31,6 +31,7 @@ class MixerTrackProcessor(val bufferSize: Int, val rate: Int, val track: Terraru private var fout1 = listOf(emptyBuf, emptyBuf) var maxSigLevel = arrayOf(0.0, 0.0); private set + var hasClipping = arrayOf(false, false); private set private var breakBomb = false @@ -163,9 +164,22 @@ class MixerTrackProcessor(val bufferSize: Int, val rate: Int, val track: Terraru fout1.map { it.maxOf { it.absoluteValue } }.forEachIndexed { index, fl -> maxSigLevel[index] = fl.toDouble() } + hasClipping.fill(false) + fout1.forEachIndexed { index, floats -> + var lastSample = floats[0] + for (i in 1 until floats.size) { + val currentSample = floats[i] + if (lastSample * currentSample > 0.0 && lastSample.absoluteValue >= 1.0 && currentSample.absoluteValue >= 1.0) { + hasClipping[index] = true + break + } + lastSample = currentSample + } + } } else { maxSigLevel.fill(0.0) + hasClipping.fill(false) } diff --git a/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt b/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt index ddb96d8be..2759879d7 100644 --- a/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt +++ b/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt @@ -396,6 +396,10 @@ class BasicDebugInfoWindow : UICanvas() { private val trackBack = listOf(COL_WELL, COL_WELL2) private val meterTroughHeight = 16 * 11 + 5 private val meterHeight = meterTroughHeight - 4 + + private val mixerLastTimeHadClipping = (AudioMixer.tracks + AudioMixer.masterTrack).map { arrayOf(0L, 0L) } + private val clippingHoldTime = 60000L * 3 // 3 mins + private fun drawAudioMixer(batch: SpriteBatch) { val x = App.scr.width - 186 - (AudioMixer.tracks.size + 1) * (stripW + stripGap) @@ -406,7 +410,15 @@ class BasicDebugInfoWindow : UICanvas() { // batch.color = COL_MIXER_BACK // Toolkit.fillArea(batch, x - stripGap, y - stripGap, strips.size * (stripW + stripGap) + stripGap, stripH + 2*stripGap) - strips.forEachIndexed { index, track -> drawStrip(batch, x + index * (stripW + stripGap), y, track, index) } + strips.forEachIndexed { index, track -> + // get clipping status + track.processor.hasClipping.forEachIndexed { channel, b -> + if (b) mixerLastTimeHadClipping[index][channel] = System.currentTimeMillis() + } + + // draw + drawStrip(batch, x + index * (stripW + stripGap), y, track, index) + } } private val dbLow = 48.0 @@ -493,6 +505,15 @@ class BasicDebugInfoWindow : UICanvas() { batch.color = ICON_GREEN App.fontSmallNumbers.draw(batch, "\u00C0", x + 17f, faderY + 1f) } + + // clipping marker + val timeNow = System.currentTimeMillis() + batch.color = ICON_RED + mixerLastTimeHadClipping[index].forEachIndexed { channel, time -> + if (timeNow - time < clippingHoldTime) { + Toolkit.fillArea(batch, x + 19 + channel*7, faderY + 16, 6, 2) + } + } } private fun drawFilterParam(batch: SpriteBatch, x: Int, y: Int, filter: TerrarumAudioFilter, track: TerrarumAudioMixerTrack) {