diff --git a/MusicPlayer/src/net/torvald/terrarum/musicplayer/gui/MusicPlayer.kt b/MusicPlayer/src/net/torvald/terrarum/musicplayer/gui/MusicPlayer.kt index 750c82908..33f8ef357 100644 --- a/MusicPlayer/src/net/torvald/terrarum/musicplayer/gui/MusicPlayer.kt +++ b/MusicPlayer/src/net/torvald/terrarum/musicplayer/gui/MusicPlayer.kt @@ -29,7 +29,8 @@ class MusicPlayer(private val ingame: TerrarumIngame) : UICanvas() { private val maskOffWidth = 8 - private val nameFBO = FrameBuffer(Pixmap.Format.RGBA8888, 400, capsuleHeight, false) + private val nameStrMaxLen = 180 + private val nameFBO = FrameBuffer(Pixmap.Format.RGBA8888, nameStrMaxLen + 2*maskOffWidth, capsuleHeight, false) private val baloonTexture = ModMgr.getGdxFile("musicplayer", "gui/blob.tga").let { TextureRegionPack(it, capsuleMosaicSize, capsuleMosaicSize) @@ -59,17 +60,41 @@ class MusicPlayer(private val ingame: TerrarumIngame) : UICanvas() { init { setAsAlwaysVisible() + + ingame.musicGovernor.addMusicStartHook { music -> + setMusicName(music.name) + } + ingame.musicGovernor.addMusicStopHook { music -> + setIntermission() + } + } + + private var renderFBOreq: String? = "" + private var nameOverflown = false + + private fun setIntermission() { + renderFBOreq = "" + nameOverflown = false + } + + private fun setMusicName(str: String) { + renderFBOreq = str } override fun renderUI(batch: SpriteBatch, camera: OrthographicCamera) { - batch.end() - - - renderNameToFBO(batch, camera, AudioMixer.musicTrack.currentTrack?.name ?: "", 0f..(width - 2*STRIP_W - capsuleHeight + maskOffWidth)) - - - - batch.begin() + if (renderFBOreq != null) { + batch.end() + width = if (renderFBOreq!!.isEmpty()) + 2*STRIP_W.toInt() + else { + val slen = App.fontGameFBO.getWidth(renderFBOreq!!) + if (slen > nameStrMaxLen) { nameOverflown = true } + slen.coerceAtMost(nameStrMaxLen) + 2 * STRIP_W.toInt() + maskOffWidth + } + renderNameToFBO(batch, camera, renderFBOreq!!, 0f..width.toFloat() - 2*STRIP_W.toInt() - maskOffWidth) + batch.begin() + renderFBOreq = null + } val posX = ((Toolkit.drawWidth - width) / 2).toFloat() val posY = (App.scr.height - App.scr.tvSafeGraphicsHeight - height).toFloat() @@ -143,7 +168,7 @@ class MusicPlayer(private val ingame: TerrarumIngame) : UICanvas() { private val chsum = ComplexArray(FloatArray(FFTSIZE * 2)) private val fftOut = ComplexArray(FloatArray(FFTSIZE * 2)) private val binHeights = FloatArray(FFTSIZE / 2) - private val FFT_SMOOTHING_FACTOR = BasicDebugInfoWindow.getSmoothingFactor(1600) + private val FFT_SMOOTHING_FACTOR = BasicDebugInfoWindow.getSmoothingFactor(2048) private val lowlim = -36.0f private val STRIP_W = 9f diff --git a/assets/mods/musicplayer/MusicPlayer.jar b/assets/mods/musicplayer/MusicPlayer.jar index 96ec2e2bc..744e74570 100644 --- a/assets/mods/musicplayer/MusicPlayer.jar +++ b/assets/mods/musicplayer/MusicPlayer.jar @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:50da851a5d5c61fdfd1ad719ea4162be71d529f0706e4d4b7e97088f92ab9c02 -size 2072631 +oid sha256:f1a4ae227d3a05dcda2085bd5be4c81e8ff3fa32aaac2d57557270f4ae133c36 +size 2075377 diff --git a/src/net/torvald/terrarum/audio/AudioMixer.kt b/src/net/torvald/terrarum/audio/AudioMixer.kt index 34eec6d10..9135931a0 100644 --- a/src/net/torvald/terrarum/audio/AudioMixer.kt +++ b/src/net/torvald/terrarum/audio/AudioMixer.kt @@ -176,7 +176,8 @@ object AudioMixer: Disposable { masterTrack.filters[0] = SoftClp masterTrack.filters[1] = Buffer - masterTrack.filters[2] = Scope() + masterTrack.filters[2] = Spectro() + masterTrack.filters[3] = Vecto() listOf(sumBus, convolveBusOpen, convolveBusCave).forEach { it.addSidechainInput(musicTrack, 1.0) diff --git a/src/net/torvald/terrarum/audio/dsp/Scope.kt b/src/net/torvald/terrarum/audio/dsp/Spectro.kt similarity index 89% rename from src/net/torvald/terrarum/audio/dsp/Scope.kt rename to src/net/torvald/terrarum/audio/dsp/Spectro.kt index f8f9a4283..bf3ac8fe3 100644 --- a/src/net/torvald/terrarum/audio/dsp/Scope.kt +++ b/src/net/torvald/terrarum/audio/dsp/Spectro.kt @@ -11,14 +11,7 @@ import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.STRIP_W import net.torvald.terrarum.ui.Toolkit import kotlin.math.* -class Scope : TerrarumAudioFilter() { - val backbufL = Array((6144f / AUDIO_BUFFER_SIZE).roundToInt().coerceAtLeast(1)) { - FloatArray(AUDIO_BUFFER_SIZE) - } - val backbufR = Array((6144f / AUDIO_BUFFER_SIZE).roundToInt().coerceAtLeast(1)) { - FloatArray(AUDIO_BUFFER_SIZE) - } - +class Spectro : TerrarumAudioFilter() { private val FFTSIZE = 1024 private val inBuf = Array(2) { FloatArray(FFTSIZE) } @@ -53,6 +46,63 @@ class Scope : TerrarumAudioFilter() { } } + override fun thru(inbuf: List, outbuf: List) { + // create (L+R)/2 array + push(inbuf[0], inBuf[0]) + push(inbuf[1], inBuf[1]) + for (i in 0 until FFTSIZE) { + chsum.reim[2*i] = ((inBuf[0][i] + inBuf[1][i]) / 2f) * fftWin[i] + } + + // do fft + FFT.fftInto(chsum, fftOut) + + // copy samples over + outbuf.forEachIndexed { index, outTrack -> + System.arraycopy(inbuf[index], 0, outTrack, 0, outTrack.size) + } + } + + private val spectroPlotCol = Color(0xdf6fa0_aa.toInt()) + + private val lowlim = -60.0 + + override fun drawDebugView(batch: SpriteBatch, x: Int, y: Int) { + // spectrometer + batch.color = spectroPlotCol + for (bin in 0 until FFTSIZE / 2) { + val freqL = (SAMPLING_RATED / FFTSIZE) * bin + val freqR = (SAMPLING_RATED / FFTSIZE) * (bin + 1) + val magn0 = fftOut.reim[2 * bin].absoluteValue / FFTSIZE * (freqR / 10.0) // apply slope + val magn = FastMath.interpolateLinear(BasicDebugInfoWindow.FFT_SMOOTHING_FACTOR, magn0, oldFFTmagn[bin]) + val magnLog = fullscaleToDecibels(magn) + + if (magnLog >= lowlim) { + val xL = linToLogPerc(freqL, 24.0, 24000.0).coerceIn(0.0, 1.0) * STRIP_W + val xR = linToLogPerc(freqR, 24.0, 24000.0).coerceIn(0.0, 1.0) * STRIP_W + val w = (xR - xL) + val h = (magnLog - lowlim) / lowlim * STRIP_W + Toolkit.fillArea(batch, x + xL.toFloat(), y + STRIP_W.toFloat(), w.toFloat(), h.toFloat()) + } + + oldFFTmagn[bin] = magn + } + } + + override val debugViewHeight = STRIP_W +} + + +class Vecto : TerrarumAudioFilter() { + val backbufL = Array((6144f / AUDIO_BUFFER_SIZE).roundToInt().coerceAtLeast(1)) { + FloatArray(AUDIO_BUFFER_SIZE) + } + val backbufR = Array((6144f / AUDIO_BUFFER_SIZE).roundToInt().coerceAtLeast(1)) { + FloatArray(AUDIO_BUFFER_SIZE) + } + + private val sqrt2p = 0.7071067811865475 + override fun thru(inbuf: List, outbuf: List) { // shift buffer for (i in backbufL.lastIndex downTo 1) { @@ -74,16 +124,6 @@ class Scope : TerrarumAudioFilter() { backbufR[0][i] = y.toFloat() } - // create (L+R)/2 array - push(inbuf[0], inBuf[0]) - push(inbuf[1], inBuf[1]) - for (i in 0 until FFTSIZE) { - chsum.reim[2*i] = ((inBuf[0][i] + inBuf[1][i]) / 2f) * fftWin[i] - } - - // do fft - FFT.fftInto(chsum, fftOut) - // copy samples over outbuf.forEachIndexed { index, outTrack -> System.arraycopy(inbuf[index], 0, outTrack, 0, outTrack.size) @@ -93,47 +133,23 @@ class Scope : TerrarumAudioFilter() { private val halfStripW = STRIP_W / 2 private val scopePlotCol = Color(0x61b3df_33) - private val spectroPlotCol = Color(0xdf6fa0_aa.toInt()) - - private val lowlim = -60.0 override fun drawDebugView(batch: SpriteBatch, x: Int, y: Int) { - batch.color = spectroPlotCol - for (bin in 0 until FFTSIZE / 2) { - val freqL = (SAMPLING_RATED / FFTSIZE) * bin - val freqR = (SAMPLING_RATED / FFTSIZE) * (bin + 1) - val magn0 = fftOut.reim[2 * bin].absoluteValue / FFTSIZE * (freqR / 10.0) // apply slope - val magn = FastMath.interpolateLinear(BasicDebugInfoWindow.FFT_SMOOTHING_FACTOR, magn0, oldFFTmagn[bin]) - val magnLog = fullscaleToDecibels(magn) - - if (magnLog >= lowlim) { - val xL = linToLogPerc(freqL, 24.0, 24000.0).coerceIn(0.0, 1.0) * STRIP_W - val xR = linToLogPerc(freqR, 24.0, 24000.0).coerceIn(0.0, 1.0) * STRIP_W - val w = (xR - xL) - val h = (magnLog - lowlim) / lowlim * STRIP_W - Toolkit.fillArea(batch, x + xL.toFloat(), y + STRIP_W.toFloat(), w.toFloat(), h.toFloat()) - } - - oldFFTmagn[bin] = magn - } - - - - + // vectorscope batch.color = scopePlotCol val xxs = backbufR val yys = backbufL for (t in xxs.lastIndex downTo 0) { val xs = xxs[t] val ys = yys[t] - for (i in xs.indices.reversed()) { val px = xs[i] * halfStripW + halfStripW val py = ys[i] * halfStripW + halfStripW Toolkit.fillArea(batch, x + px, y + py, 1f, 1f) } - } + + // TODO correlation meter } override val debugViewHeight = STRIP_W diff --git a/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt b/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt index 73df624cc..3c661e456 100644 --- a/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt +++ b/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt @@ -418,7 +418,7 @@ class BasicDebugInfoWindow : UICanvas() { fun getSmoothingFactor(sampleCount: Int) = (1.0 - (256.0 / sampleCount)) val PEAK_SMOOTHING_FACTOR = getSmoothingFactor(640) - val FFT_SMOOTHING_FACTOR = getSmoothingFactor(1200) + val FFT_SMOOTHING_FACTOR = getSmoothingFactor(2048) val LAMP_SMOOTHING_FACTOR = getSmoothingFactor(3200) val RMS_SMOOTHING_FACTOR = getSmoothingFactor(12000) } @@ -427,7 +427,7 @@ class BasicDebugInfoWindow : UICanvas() { private val stripGap = 1 private val stripFilterHeight = 16 private val stripFaderHeight = meterHeight + 20 - private val numberOfFilters = 10 + private val numberOfFilters = 14 private val stripH = stripFaderHeight + stripFilterHeight * numberOfFilters + 16 private val trackBack = listOf(COL_WELL, COL_WELL2)