diff --git a/src/net/torvald/terrarum/audio/MixerTrackProcessor.kt b/src/net/torvald/terrarum/audio/MixerTrackProcessor.kt index f62aafa7c..da3528c5a 100644 --- a/src/net/torvald/terrarum/audio/MixerTrackProcessor.kt +++ b/src/net/torvald/terrarum/audio/MixerTrackProcessor.kt @@ -144,7 +144,8 @@ class MixerTrackProcessor(bufferSize: Int, val rate: Int, val track: TerrarumAud ) val isApproaching = if (distFromActorNext <= distFromActor) 1.0 else -1.0 val relativeSpeed = (sourceVec - listenerVec).magnitude * GAME_TO_SI_VELO * isApproaching - val dopplerFactor = (SPEED_OF_SOUND_AIR + relativeSpeed) / SPEED_OF_SOUND_AIR // >1: speedup, <1: speeddown + val soundSpeed = SPEED_OF_SOUND_AIR * 4f // using an arbitrary value for "gamification" + val dopplerFactor = (soundSpeed + relativeSpeed) / soundSpeed // >1: speedup, <1: speeddown track.processor.streamBuf?.playbackSpeed = dopplerFactor.toFloat() diff --git a/src/net/torvald/terrarum/audio/dsp/BinoPan.kt b/src/net/torvald/terrarum/audio/dsp/BinoPan.kt index 9167c08d0..2a0971db9 100644 --- a/src/net/torvald/terrarum/audio/dsp/BinoPan.kt +++ b/src/net/torvald/terrarum/audio/dsp/BinoPan.kt @@ -22,6 +22,8 @@ import kotlin.math.tanh * @param pan -1 for far-left, 0 for centre, 1 for far-right * @param soundSpeed speed of the sound in meters per seconds * @param earDist distance between ears in meters. Maximum: 16.0 + * + * Created by minjaesong on 2023-11-23. */ class BinoPan(var pan: Float, var earDist: Float = EARDIST_DEFAULT): TerrarumAudioFilter() { diff --git a/src/net/torvald/terrarum/audio/dsp/Bitcrush.kt b/src/net/torvald/terrarum/audio/dsp/Bitcrush.kt index 76be14a0e..a7d1a9f92 100644 --- a/src/net/torvald/terrarum/audio/dsp/Bitcrush.kt +++ b/src/net/torvald/terrarum/audio/dsp/Bitcrush.kt @@ -9,6 +9,9 @@ import net.torvald.terrarum.ui.BasicDebugInfoWindow import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.toIntAndFrac import net.torvald.terrarum.ui.Toolkit +/** + * Created by minjaesong on 2023-11-23. + */ class Bitcrush(var steps: Int, var inputGain: Float = 1f): TerrarumAudioFilter() { override fun thru(inbuf: List, outbuf: List) { for (ch in outbuf.indices) { diff --git a/src/net/torvald/terrarum/audio/dsp/Buffer.kt b/src/net/torvald/terrarum/audio/dsp/Buffer.kt index 2cc7c804b..8f5912b6b 100644 --- a/src/net/torvald/terrarum/audio/dsp/Buffer.kt +++ b/src/net/torvald/terrarum/audio/dsp/Buffer.kt @@ -4,6 +4,9 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch import net.torvald.terrarum.App import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.FILTER_NAME_ACTIVE +/** + * Created by minjaesong on 2023-11-18. + */ object Buffer : TerrarumAudioFilter() { init { bypass = true diff --git a/src/net/torvald/terrarum/audio/dsp/Convolv.kt b/src/net/torvald/terrarum/audio/dsp/Convolv.kt index 53cdeccab..cc46dee2b 100644 --- a/src/net/torvald/terrarum/audio/dsp/Convolv.kt +++ b/src/net/torvald/terrarum/audio/dsp/Convolv.kt @@ -21,6 +21,8 @@ import kotlin.math.roundToInt * @param ir Binary file containing MONO IR (containing only two channels) * @param crossfeed The amount of channel crossfeeding to simulate the true stereo IR. Fullscale (0.0 - 1.0) * @param gain output gain. Fullscale (0.0 - 1.0) + * + * Created by minjaesong on 2023-11-25. */ class Convolv(ir: File, val crossfeed: Float, gain: Float = 1f / 256f): TerrarumAudioFilter() { diff --git a/src/net/torvald/terrarum/audio/dsp/Gain.kt b/src/net/torvald/terrarum/audio/dsp/Gain.kt index 8d8e2d31a..1dc659506 100644 --- a/src/net/torvald/terrarum/audio/dsp/Gain.kt +++ b/src/net/torvald/terrarum/audio/dsp/Gain.kt @@ -6,6 +6,9 @@ import net.torvald.terrarum.audio.fullscaleToDecibels import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.FILTER_NAME_ACTIVE import kotlin.math.roundToInt +/** + * Created by minjaesong on 2023-11-25. + */ class Gain(var gain: Float): TerrarumAudioFilter() { override fun thru(inbuf: List, outbuf: List) { for (i in 0 until App.audioBufferSize) { diff --git a/src/net/torvald/terrarum/audio/dsp/Highpass.kt b/src/net/torvald/terrarum/audio/dsp/Highpass.kt index cf42e7ceb..83132c3f3 100644 --- a/src/net/torvald/terrarum/audio/dsp/Highpass.kt +++ b/src/net/torvald/terrarum/audio/dsp/Highpass.kt @@ -10,7 +10,9 @@ import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.COL_METER_GRAD2 import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.FILTER_NAME_ACTIVE import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.STRIP_W import net.torvald.terrarum.ui.Toolkit - +/** + * Created by minjaesong on 2023-11-19. + */ class Highpass(cutoff0: Float): TerrarumAudioFilter() { var cutoff = cutoff0.toDouble(); private set diff --git a/src/net/torvald/terrarum/audio/dsp/LoFi.kt b/src/net/torvald/terrarum/audio/dsp/LoFi.kt new file mode 100644 index 000000000..e63425db8 --- /dev/null +++ b/src/net/torvald/terrarum/audio/dsp/LoFi.kt @@ -0,0 +1,53 @@ +package net.torvald.terrarum.audio.dsp + +import com.badlogic.gdx.graphics.g2d.SpriteBatch +import net.torvald.terrarum.App +import java.io.File +import kotlin.math.absoluteValue +import kotlin.math.tanh + +/** + * Convolver with tanh saturator + * + * @param ir Binary file containing MONO IR (containing only two channels) + * @param crossfeed The amount of channel crossfeeding to simulate the true stereo IR. Fullscale (0.0 - 1.0) + * @param gain output gain. Fullscale (0.0 - 1.0) + * + * Created by minjaesong on 2024-01-21. + */ +class LoFi(ir: File, val crossfeed: Float, gain: Float = 1f / 256f): TerrarumAudioFilter(), DspCompressor { + override val downForce = arrayOf(1.0f, 1.0f) + + internal val convolver = Convolv(ir, crossfeed, gain) + + private val imm = listOf(FloatArray(App.audioBufferSize), FloatArray(App.audioBufferSize)) + + override fun thru(inbuf: List, outbuf: List) { + convolver.thru(inbuf, imm) + + for (ch in imm.indices) { + val inn = imm[ch] + val out = outbuf[ch] + + for (i in inn.indices) { + val u = inn[i] + val v = tanh(u) + val diff = (v.absoluteValue / u.absoluteValue) + out[i] = v + + if (!diff.isNaN()) { + downForce[ch] = minOf(downForce[ch], diff) + } + } + } + } + + override fun drawDebugView(batch: SpriteBatch, x: Int, y: Int) { + } + + override val debugViewHeight = 0 + + override fun copyParamsFrom(other: TerrarumAudioFilter) { + this.convolver.copyParamsFrom((other as LoFi).convolver) + } +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/audio/dsp/Lowpass.kt b/src/net/torvald/terrarum/audio/dsp/Lowpass.kt index 473fb4601..990448390 100644 --- a/src/net/torvald/terrarum/audio/dsp/Lowpass.kt +++ b/src/net/torvald/terrarum/audio/dsp/Lowpass.kt @@ -11,6 +11,9 @@ import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.COL_METER_GRAD2 import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.FILTER_NAME_ACTIVE import net.torvald.terrarum.ui.Toolkit +/** + * Created by minjaesong on 2023-11-17. + */ class Lowpass(cutoff0: Float): TerrarumAudioFilter() { var cutoff = cutoff0.toDouble(); private set diff --git a/src/net/torvald/terrarum/audio/dsp/NullFilter.kt b/src/net/torvald/terrarum/audio/dsp/NullFilter.kt index 4c38b52ef..6a2027f4c 100644 --- a/src/net/torvald/terrarum/audio/dsp/NullFilter.kt +++ b/src/net/torvald/terrarum/audio/dsp/NullFilter.kt @@ -2,6 +2,9 @@ package net.torvald.terrarum.audio.dsp import com.badlogic.gdx.graphics.g2d.SpriteBatch +/** + * Created by minjaesong on 2023-11-17. + */ object NullFilter : TerrarumAudioFilter() { override fun thru(inbuf: List, outbuf: List) { outbuf.forEachIndexed { index, outTrack -> diff --git a/src/net/torvald/terrarum/audio/dsp/Reverb.kt b/src/net/torvald/terrarum/audio/dsp/Reverb.kt index 4a8d483d9..a44a2672f 100644 --- a/src/net/torvald/terrarum/audio/dsp/Reverb.kt +++ b/src/net/torvald/terrarum/audio/dsp/Reverb.kt @@ -6,6 +6,9 @@ import net.torvald.terrarum.App import net.torvald.terrarum.audio.TerrarumAudioMixerTrack import kotlin.math.roundToInt +/** + * Created by minjaesong on 2023-11-23. + */ class Reverb(val delayMS: Float = 36f, var feedback: Float = 0.92f, var lowpass: Float = 1200f): TerrarumAudioFilter() { private val highpass = 80f diff --git a/src/net/torvald/terrarum/audio/dsp/SoftClp.kt b/src/net/torvald/terrarum/audio/dsp/SoftClp.kt index bf567944e..2676d5ac6 100644 --- a/src/net/torvald/terrarum/audio/dsp/SoftClp.kt +++ b/src/net/torvald/terrarum/audio/dsp/SoftClp.kt @@ -5,8 +5,11 @@ import kotlin.math.absoluteValue import kotlin.math.pow import kotlin.math.sqrt -object SoftClp : TerrarumAudioFilter() { - val downForce = arrayOf(1.0f, 1.0f) +/** + * Created by minjaesong on 2023-11-20. + */ +object SoftClp : TerrarumAudioFilter(), DspCompressor { + override val downForce = arrayOf(1.0f, 1.0f) override fun thru(inbuf: List, outbuf: List) { downForce.fill(1.0f) diff --git a/src/net/torvald/terrarum/audio/dsp/Spectro.kt b/src/net/torvald/terrarum/audio/dsp/Spectro.kt index 1c54497b1..794e6c20b 100644 --- a/src/net/torvald/terrarum/audio/dsp/Spectro.kt +++ b/src/net/torvald/terrarum/audio/dsp/Spectro.kt @@ -11,6 +11,9 @@ import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.STRIP_W import net.torvald.terrarum.ui.Toolkit import kotlin.math.* +/** + * Created by minjaesong on 2023-12-21. + */ class Spectro(var gain: Float = 1f) : TerrarumAudioFilter() { private val FFTSIZE = 1024 private val inBuf = Array(2) { FloatArray(FFTSIZE) } @@ -99,7 +102,9 @@ class Spectro(var gain: Float = 1f) : TerrarumAudioFilter() { } } - +/** + * Created by minjaesong on 2023-11-20. + */ class Vecto(var gain: Float = 1f) : TerrarumAudioFilter() { var backbufL = Array((6144f / App.audioBufferSize).roundToInt().coerceAtLeast(1)) { FloatArray(App.audioBufferSize) diff --git a/src/net/torvald/terrarum/audio/dsp/TerrarumAudioFilter.kt b/src/net/torvald/terrarum/audio/dsp/TerrarumAudioFilter.kt index 878a35087..0c0eb215a 100644 --- a/src/net/torvald/terrarum/audio/dsp/TerrarumAudioFilter.kt +++ b/src/net/torvald/terrarum/audio/dsp/TerrarumAudioFilter.kt @@ -2,9 +2,12 @@ package net.torvald.terrarum.audio.dsp import com.badlogic.gdx.graphics.g2d.SpriteBatch +/** + * Created by minjaesong on 2023-11-17. + */ abstract class TerrarumAudioFilter { var bypass = false - protected abstract fun thru(inbuf: List, outbuf: List) + abstract fun thru(inbuf: List, outbuf: List) operator fun invoke(inbuf: List, outbuf: List) { if (bypass) { outbuf.forEachIndexed { index, outTrack -> @@ -18,6 +21,13 @@ abstract class TerrarumAudioFilter { abstract fun copyParamsFrom(other: TerrarumAudioFilter) } +/** + * Created by minjaesong on 2024-01-21. + */ +interface DspCompressor { + val downForce: Array +} + fun FloatArray.applyGain(gain: Float = 1f) = this.map { it * gain }.toFloatArray() fun push(samples: FloatArray, buf: FloatArray) { if (samples.size >= buf.size) { diff --git a/src/net/torvald/terrarum/audio/dsp/XYtoMS.kt b/src/net/torvald/terrarum/audio/dsp/XYtoMS.kt index 466780ba8..32a1eb5b9 100644 --- a/src/net/torvald/terrarum/audio/dsp/XYtoMS.kt +++ b/src/net/torvald/terrarum/audio/dsp/XYtoMS.kt @@ -3,6 +3,9 @@ package net.torvald.terrarum.audio.dsp import com.badlogic.gdx.graphics.g2d.SpriteBatch import net.torvald.terrarum.App +/** + * Created by minjaesong on 2023-11-24. + */ object XYtoMS: TerrarumAudioFilter() { override fun thru(inbuf: List, outbuf: List) { for (i in 0 until App.audioBufferSize) { @@ -24,6 +27,9 @@ object XYtoMS: TerrarumAudioFilter() { } } +/** + * Created by minjaesong on 2023-11-24. + */ object MStoXY: TerrarumAudioFilter() { override fun thru(inbuf: List, outbuf: List) { for (i in 0 until App.audioBufferSize) { diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureJukebox.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureJukebox.kt index 5d59ac7c9..f9459897d 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureJukebox.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureJukebox.kt @@ -11,6 +11,7 @@ import net.torvald.terrarum.App.printdbg import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE import net.torvald.terrarum.audio.AudioMixer.Companion.DEFAULT_FADEOUT_LEN import net.torvald.terrarum.audio.dsp.Convolv +import net.torvald.terrarum.audio.dsp.LoFi import net.torvald.terrarum.audio.dsp.NullFilter import net.torvald.terrarum.gameactors.AVKey import net.torvald.terrarum.gameitems.ItemID @@ -40,6 +41,8 @@ class FixtureJukebox : Electric { @Transient private val backLamp: SheetSpriteAnimation + @Transient private val filterIndex = 2 + internal val discInventory = ArrayList() val musicIsPlaying: Boolean @@ -114,7 +117,7 @@ class FixtureJukebox : Electric { App.audioMixer.requestFadeOut(App.audioMixer.musicTrack, DEFAULT_FADEOUT_LEN / 2f) { startAudio(musicNowPlaying!!) { - it.filters[2] = Convolv( + it.filters[filterIndex] = LoFi( ModMgr.getFile( "basegame", "audio/convolution/Soundwoofer - large_speaker_Marshall JVM 205C SM57 A 0 0 1.bin" @@ -162,7 +165,7 @@ class FixtureJukebox : Electric { private fun unloadConvolver(music: MusicContainer?) { if (music != null) { musicTracks[music]?.let { - it.filters[2] = NullFilter + it.filters[filterIndex] = NullFilter } } } diff --git a/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt b/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt index 9177f58b5..6106a6c6b 100644 --- a/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt +++ b/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt @@ -721,7 +721,7 @@ class BasicDebugInfoWindow : UICanvas() { } // comp marker - track.filters.filterIsInstance().firstOrNull()?.let { + track.filters.filterIsInstance().firstOrNull()?.let { for (ch in 0..1) { val downForceNow = it.downForce[ch] * 1.0 if (downForceNow != 0.0) {