mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-17 05:54:05 +09:00
audio engine: resize buffer without restarting the game
This commit is contained in:
@@ -13,6 +13,7 @@ import com.badlogic.gdx.utils.Disposable;
|
|||||||
import com.badlogic.gdx.utils.GdxRuntimeException;
|
import com.badlogic.gdx.utils.GdxRuntimeException;
|
||||||
import com.badlogic.gdx.utils.JsonValue;
|
import com.badlogic.gdx.utils.JsonValue;
|
||||||
import com.github.strikerx3.jxinput.XInputDevice;
|
import com.github.strikerx3.jxinput.XInputDevice;
|
||||||
|
import kotlin.jvm.functions.Function0;
|
||||||
import kotlin.text.Charsets;
|
import kotlin.text.Charsets;
|
||||||
import net.torvald.getcpuname.GetCpuName;
|
import net.torvald.getcpuname.GetCpuName;
|
||||||
import net.torvald.terrarum.audio.AudioMixer;
|
import net.torvald.terrarum.audio.AudioMixer;
|
||||||
@@ -1055,6 +1056,12 @@ public class App implements ApplicationListener {
|
|||||||
public static AudioMixer audioMixer;
|
public static AudioMixer audioMixer;
|
||||||
public static int audioBufferSize;
|
public static int audioBufferSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure to call App.audioMixerRenewHooks.remove(Object) whenever the class gets disposed of
|
||||||
|
* Key: the class that calls the hook, value: the actual operation (function)
|
||||||
|
*/
|
||||||
|
public static HashMap<Object, Function0> audioMixerRenewHooks = new HashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init stuffs which needs GL context
|
* Init stuffs which needs GL context
|
||||||
*/
|
*/
|
||||||
@@ -1243,6 +1250,16 @@ public class App implements ApplicationListener {
|
|||||||
audioManagerThread = new Thread(new AudioManagerRunnable(audioMixer), "TerrarumAudioManager");
|
audioManagerThread = new Thread(new AudioManagerRunnable(audioMixer), "TerrarumAudioManager");
|
||||||
audioManagerThread.setPriority(MAX_PRIORITY); // higher = more predictable; audio delay is very noticeable so it gets high priority
|
audioManagerThread.setPriority(MAX_PRIORITY); // higher = more predictable; audio delay is very noticeable so it gets high priority
|
||||||
audioManagerThread.start();
|
audioManagerThread.start();
|
||||||
|
|
||||||
|
|
||||||
|
for (var it : audioMixerRenewHooks.values()) {
|
||||||
|
try {
|
||||||
|
it.invoke();
|
||||||
|
}
|
||||||
|
catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -498,35 +498,6 @@ class AudioMixer(val bufferSize: Int): Disposable {
|
|||||||
}, 500L)
|
}, 500L)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateBufferSizeChange() {
|
|
||||||
processing = false
|
|
||||||
processingThread.interrupt()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dynamicTracks.forEach { it.stop() }
|
|
||||||
tracks.filter { it.trackType == TrackType.STATIC_SOURCE }.forEach { it.stop() }
|
|
||||||
masterTrack.volume = 0.0
|
|
||||||
|
|
||||||
dynamicTracks.forEach { it.updateBufferSizeChange() }
|
|
||||||
tracks.forEach { it.updateBufferSizeChange() }
|
|
||||||
masterTrack.updateBufferSizeChange()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
processingThread = createProcessingThread()
|
|
||||||
processing = true
|
|
||||||
processingThread.start()
|
|
||||||
|
|
||||||
|
|
||||||
// give some time for the cave bus to decay before ramping the volume up
|
|
||||||
Timer().schedule(object : TimerTask() {
|
|
||||||
override fun run() {
|
|
||||||
masterTrack.volume = 1.0
|
|
||||||
}
|
|
||||||
}, 500L)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
processingExecutor.killAll()
|
processingExecutor.killAll()
|
||||||
// processingSubthreads.forEach { it.interrupt() }
|
// processingSubthreads.forEach { it.interrupt() }
|
||||||
|
|||||||
@@ -21,15 +21,6 @@ class MixerTrackProcessor(bufferSize: Int, val rate: Int, val track: TerrarumAud
|
|||||||
|
|
||||||
private var buffertaille = bufferSize
|
private var buffertaille = bufferSize
|
||||||
|
|
||||||
fun reset(newBufferSize: Int) {
|
|
||||||
buffertaille = newBufferSize
|
|
||||||
// printdbg("new buffertaille = $buffertaille")
|
|
||||||
emptyBuf = FloatArray(buffertaille)
|
|
||||||
fout1 = listOf(emptyBuf, emptyBuf)
|
|
||||||
purgeStreamBuf()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,13 +169,7 @@ class MixerTrackProcessor(bufferSize: Int, val rate: Int, val track: TerrarumAud
|
|||||||
// add all up
|
// add all up
|
||||||
sidechains.forEach { (side, mix) ->
|
sidechains.forEach { (side, mix) ->
|
||||||
for (i in samplesL1.indices) {
|
for (i in samplesL1.indices) {
|
||||||
// try {
|
samplesL1[i] += side.processor.fout1[0][i] * (mix * track.volume).toFloat()
|
||||||
samplesL1[i] += side.processor.fout1[0][i] * (mix * track.volume).toFloat()
|
|
||||||
// }
|
|
||||||
// catch (e: ArrayIndexOutOfBoundsException) {
|
|
||||||
// printdbg("buffertaille = $buffertaille, samplesL1 size = ${samplesL1.size}, side.processor.fout1[0] size = ${side.processor.fout1[0].size}")
|
|
||||||
// throw e
|
|
||||||
// }
|
|
||||||
samplesR1[i] += side.processor.fout1[1][i] * (mix * track.volume).toFloat()
|
samplesR1[i] += side.processor.fout1[1][i] * (mix * track.volume).toFloat()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -187,16 +187,6 @@ class TerrarumAudioMixerTrack(
|
|||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateBufferSizeChange() {
|
|
||||||
// printdbg(this, "new buffer size: $App.audioMixerBufferSize")
|
|
||||||
pcmQueue.clear()
|
|
||||||
pcmQueue.addLast(listOf(FloatArray(App.audioBufferSize), FloatArray(App.audioBufferSize)))
|
|
||||||
pcmQueue.addLast(listOf(FloatArray(App.audioBufferSize), FloatArray(App.audioBufferSize)))
|
|
||||||
processor.reset(App.audioBufferSize)
|
|
||||||
filters.forEach { it.reset() }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun hashCode() = hashCode0
|
override fun hashCode() = hashCode0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,13 +55,6 @@ class BinoPan(var pan: Float, var earDist: Float = EARDIST_DEFAULT): TerrarumAud
|
|||||||
private val HALF_PI = (Math.PI / 2.0).toFloat()
|
private val HALF_PI = (Math.PI / 2.0).toFloat()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun reset() {
|
|
||||||
outLs = Array(2) { FloatArray(App.audioBufferSize) }
|
|
||||||
outRs = Array(2) { FloatArray(App.audioBufferSize) }
|
|
||||||
delayLineL.fill(0f)
|
|
||||||
delayLineR.fill(0f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param intensity -inf to +inf
|
* @param intensity -inf to +inf
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -34,8 +34,5 @@ class Bitcrush(var steps: Int, var inputGain: Float = 1f): TerrarumAudioFilter()
|
|||||||
App.fontSmallNumbers.draw(batch, "B:$bits", x+3f, y+1f)
|
App.fontSmallNumbers.draw(batch, "B:$bits", x+3f, y+1f)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun reset() {
|
|
||||||
}
|
|
||||||
|
|
||||||
override val debugViewHeight = 16
|
override val debugViewHeight = 16
|
||||||
}
|
}
|
||||||
@@ -18,8 +18,5 @@ object Buffer : TerrarumAudioFilter() {
|
|||||||
App.fontSmallNumbers.draw(batch, "Bs:${App.audioBufferSize}", x+3f, y+1f)
|
App.fontSmallNumbers.draw(batch, "Bs:${App.audioBufferSize}", x+3f, y+1f)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun reset() {
|
|
||||||
}
|
|
||||||
|
|
||||||
override val debugViewHeight = 16
|
override val debugViewHeight = 16
|
||||||
}
|
}
|
||||||
@@ -74,12 +74,6 @@ class Convolv(ir: File, val crossfeed: Float, gain: Float = 1f / 256f): Terrarum
|
|||||||
private val fftOutL = FloatArray(fftLen)
|
private val fftOutL = FloatArray(fftLen)
|
||||||
private val fftOutR = FloatArray(fftLen)
|
private val fftOutR = FloatArray(fftLen)
|
||||||
|
|
||||||
override fun reset() {
|
|
||||||
realtime = (App.audioBufferSize / TerrarumAudioMixerTrack.SAMPLING_RATEF * 1000000000L)
|
|
||||||
processingSpeed = 1f
|
|
||||||
sumbuf.forEach { it.reim.fill(0f) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun convolve(x: ComplexArray, h: ComplexArray, output: FloatArray) {
|
private fun convolve(x: ComplexArray, h: ComplexArray, output: FloatArray) {
|
||||||
FFT.fftInto(x, fftIn)
|
FFT.fftInto(x, fftIn)
|
||||||
fftIn.mult(h, fftMult)
|
fftIn.mult(h, fftMult)
|
||||||
|
|||||||
@@ -19,9 +19,5 @@ class Gain(var gain: Float): TerrarumAudioFilter() {
|
|||||||
App.fontSmallNumbers.draw(batch, "G:${fullscaleToDecibels(gain.toDouble()).times(100).roundToInt().div(100f)}", x+3f, y+1f)
|
App.fontSmallNumbers.draw(batch, "G:${fullscaleToDecibels(gain.toDouble()).times(100).roundToInt().div(100f)}", x+3f, y+1f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun reset() {
|
|
||||||
}
|
|
||||||
|
|
||||||
override val debugViewHeight = 16
|
override val debugViewHeight = 16
|
||||||
}
|
}
|
||||||
@@ -67,9 +67,4 @@ class Highpass(cutoff0: Float): TerrarumAudioFilter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val debugViewHeight = 16
|
override val debugViewHeight = 16
|
||||||
|
|
||||||
override fun reset() {
|
|
||||||
in0.fill(0f)
|
|
||||||
out0.fill(0f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -67,9 +67,4 @@ class Lowpass(cutoff0: Float): TerrarumAudioFilter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val debugViewHeight = 16
|
override val debugViewHeight = 16
|
||||||
|
|
||||||
override fun reset() {
|
|
||||||
in0.fill(0f)
|
|
||||||
out0.fill(0f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,4 @@ object NullFilter : TerrarumAudioFilter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val debugViewHeight = 0
|
override val debugViewHeight = 0
|
||||||
|
|
||||||
override fun reset() {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -53,8 +53,4 @@ class Reverb(val delayMS: Float = 36f, var feedback: Float = 0.92f, var lowpass:
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val debugViewHeight = 0
|
override val debugViewHeight = 0
|
||||||
|
|
||||||
override fun reset() {
|
|
||||||
buf.forEach { it.fill(0f) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -56,7 +56,4 @@ object SoftClp : TerrarumAudioFilter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val debugViewHeight = 0
|
override val debugViewHeight = 0
|
||||||
|
|
||||||
override fun reset() {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -91,9 +91,6 @@ class Spectro(val gain: Float = 1f) : TerrarumAudioFilter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val debugViewHeight = STRIP_W
|
override val debugViewHeight = STRIP_W
|
||||||
|
|
||||||
override fun reset() {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -157,13 +154,4 @@ class Vecto(val gain: Float = 1f) : TerrarumAudioFilter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val debugViewHeight = STRIP_W
|
override val debugViewHeight = STRIP_W
|
||||||
|
|
||||||
override fun reset() {
|
|
||||||
backbufL = Array((6144f / App.audioBufferSize).roundToInt().coerceAtLeast(1)) {
|
|
||||||
FloatArray(App.audioBufferSize)
|
|
||||||
}
|
|
||||||
backbufR = Array((6144f / App.audioBufferSize).roundToInt().coerceAtLeast(1)) {
|
|
||||||
FloatArray(App.audioBufferSize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,6 @@ abstract class TerrarumAudioFilter {
|
|||||||
}
|
}
|
||||||
else thru(inbuf, outbuf)
|
else thru(inbuf, outbuf)
|
||||||
}
|
}
|
||||||
abstract fun reset()
|
|
||||||
abstract fun drawDebugView(batch: SpriteBatch, x: Int, y: Int)
|
abstract fun drawDebugView(batch: SpriteBatch, x: Int, y: Int)
|
||||||
abstract val debugViewHeight: Int
|
abstract val debugViewHeight: Int
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,9 +19,6 @@ object XYtoMS: TerrarumAudioFilter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val debugViewHeight = 0
|
override val debugViewHeight = 0
|
||||||
|
|
||||||
override fun reset() {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object MStoXY: TerrarumAudioFilter() {
|
object MStoXY: TerrarumAudioFilter() {
|
||||||
@@ -40,7 +37,4 @@ object MStoXY: TerrarumAudioFilter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val debugViewHeight = 0
|
override val debugViewHeight = 0
|
||||||
|
|
||||||
override fun reset() {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -67,6 +67,9 @@ class FixtureJukebox : Electric {
|
|||||||
it.setSpriteImage(TextureRegionPack(backLampTex, TILE_SIZE * 2, TILE_SIZE * 3))
|
it.setSpriteImage(TextureRegionPack(backLampTex, TILE_SIZE * 2, TILE_SIZE * 3))
|
||||||
it.setRowsAndFrames(1, 1)
|
it.setRowsAndFrames(1, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
App.audioMixerRenewHooks[this] = { stopGracefully() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override val canBeDespawned: Boolean
|
override val canBeDespawned: Boolean
|
||||||
@@ -174,6 +177,7 @@ class FixtureJukebox : Electric {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
|
App.audioMixerRenewHooks.remove(this)
|
||||||
super.dispose()
|
super.dispose()
|
||||||
// testMusic.gdxMusic.dispose()
|
// testMusic.gdxMusic.dispose()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ class UIInventoryEscMenu(val full: UIInventoryFull) : UICanvas() {
|
|||||||
"MENU_IO_SAVE_GAME",
|
"MENU_IO_SAVE_GAME",
|
||||||
"MENU_OPTIONS_CONTROLS",
|
"MENU_OPTIONS_CONTROLS",
|
||||||
"MENU_LABEL_IME",
|
"MENU_LABEL_IME",
|
||||||
|
"MENU_LABEL_SOUND",
|
||||||
"MENU_LABEL_LANGUAGE",
|
"MENU_LABEL_LANGUAGE",
|
||||||
"MENU_LABEL_SHARE",
|
"MENU_LABEL_SHARE",
|
||||||
"MENU_LABEL_QUIT",
|
"MENU_LABEL_QUIT",
|
||||||
@@ -86,6 +87,7 @@ class UIInventoryEscMenu(val full: UIInventoryFull) : UICanvas() {
|
|||||||
private val languageUI = UITitleLanguage(null)
|
private val languageUI = UITitleLanguage(null)
|
||||||
private val keyboardSetupUI = UIIMEConfig(null)
|
private val keyboardSetupUI = UIIMEConfig(null)
|
||||||
private val shareUI = UIShare()
|
private val shareUI = UIShare()
|
||||||
|
private val audioUI = UISoundControlPanel(null)
|
||||||
|
|
||||||
private var oldScreen = 0
|
private var oldScreen = 0
|
||||||
private var screen = 0
|
private var screen = 0
|
||||||
@@ -156,12 +158,15 @@ class UIInventoryEscMenu(val full: UIInventoryFull) : UICanvas() {
|
|||||||
screen = 1; gameMenuButtons.deselect()
|
screen = 1; gameMenuButtons.deselect()
|
||||||
}
|
}
|
||||||
3 -> {
|
3 -> {
|
||||||
screen = 5; gameMenuButtons.deselect()
|
screen = 7; gameMenuButtons.deselect()
|
||||||
}
|
}
|
||||||
4 -> {
|
4 -> {
|
||||||
screen = 6; gameMenuButtons.deselect()
|
screen = 5; gameMenuButtons.deselect()
|
||||||
}
|
}
|
||||||
5 -> {
|
5 -> {
|
||||||
|
screen = 6; gameMenuButtons.deselect()
|
||||||
|
}
|
||||||
|
6 -> {
|
||||||
screen = 2; gameMenuButtons.deselect()
|
screen = 2; gameMenuButtons.deselect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -183,7 +188,7 @@ class UIInventoryEscMenu(val full: UIInventoryFull) : UICanvas() {
|
|||||||
|
|
||||||
// Completely unrelated to the gameMenuButtons order
|
// Completely unrelated to the gameMenuButtons order
|
||||||
private val screens = arrayOf(
|
private val screens = arrayOf(
|
||||||
gameMenuButtons, keyboardSetupUI, areYouSureMainMenuButtons, savingUI, keyConfigUI, languageUI, shareUI
|
gameMenuButtons, keyboardSetupUI, areYouSureMainMenuButtons, savingUI, keyConfigUI, languageUI, shareUI, audioUI
|
||||||
)
|
)
|
||||||
|
|
||||||
// `screens` order
|
// `screens` order
|
||||||
@@ -222,6 +227,11 @@ class UIInventoryEscMenu(val full: UIInventoryFull) : UICanvas() {
|
|||||||
App.fontGame.draw(batch, full.gameMenuControlHelp, controlHintX, full.yEnd - 20)
|
App.fontGame.draw(batch, full.gameMenuControlHelp, controlHintX, full.yEnd - 20)
|
||||||
shareUI.render(frameDelta, batch, camera)
|
shareUI.render(frameDelta, batch, camera)
|
||||||
},
|
},
|
||||||
|
{ frameDelta: Float, batch: SpriteBatch, camera: OrthographicCamera ->
|
||||||
|
// control hints
|
||||||
|
App.fontGame.draw(batch, full.gameMenuControlHelp, controlHintX, full.yEnd - 20)
|
||||||
|
audioUI.render(frameDelta, batch, camera)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
// `screens` order
|
// `screens` order
|
||||||
@@ -237,6 +247,7 @@ class UIInventoryEscMenu(val full: UIInventoryFull) : UICanvas() {
|
|||||||
},
|
},
|
||||||
{ screenX: Int, screenY: Int, pointer: Int, button: Int -> },
|
{ screenX: Int, screenY: Int, pointer: Int, button: Int -> },
|
||||||
{ screenX: Int, screenY: Int, pointer: Int, button: Int -> },
|
{ screenX: Int, screenY: Int, pointer: Int, button: Int -> },
|
||||||
|
{ screenX: Int, screenY: Int, pointer: Int, button: Int -> },
|
||||||
)
|
)
|
||||||
|
|
||||||
// `screens` order
|
// `screens` order
|
||||||
@@ -252,6 +263,7 @@ class UIInventoryEscMenu(val full: UIInventoryFull) : UICanvas() {
|
|||||||
},
|
},
|
||||||
{ screenX: Int, screenY: Int, pointer: Int, button: Int -> },
|
{ screenX: Int, screenY: Int, pointer: Int, button: Int -> },
|
||||||
{ screenX: Int, screenY: Int, pointer: Int, button: Int -> },
|
{ screenX: Int, screenY: Int, pointer: Int, button: Int -> },
|
||||||
|
{ screenX: Int, screenY: Int, pointer: Int, button: Int -> },
|
||||||
)
|
)
|
||||||
|
|
||||||
// `screens` order
|
// `screens` order
|
||||||
@@ -265,6 +277,7 @@ class UIInventoryEscMenu(val full: UIInventoryFull) : UICanvas() {
|
|||||||
{ amountX: Float, amountY: Float -> },
|
{ amountX: Float, amountY: Float -> },
|
||||||
{ amountX: Float, amountY: Float -> },
|
{ amountX: Float, amountY: Float -> },
|
||||||
{ amountX: Float, amountY: Float -> },
|
{ amountX: Float, amountY: Float -> },
|
||||||
|
{ amountX: Float, amountY: Float -> },
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun show() {
|
override fun show() {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class UISoundControlPanel(remoCon: UIRemoCon?) : UICanvas() {
|
|||||||
arrayOf("", { "" }, "pp"),
|
arrayOf("", { "" }, "pp"),
|
||||||
arrayOf("", { Lang["MENU_LABEL_AUDIO_ENGINE"] }, "h1"),
|
arrayOf("", { Lang["MENU_LABEL_AUDIO_ENGINE"] }, "h1"),
|
||||||
arrayOf("audio_speaker_setup", { Lang["MENU_OPTIONS_SPEAKER_SETUP"] }, "textsel,headphone=MENU_OPTIONS_SPEAKER_HEADPHONE,stereo=MENU_OPTIONS_SPEAKER_STEREO"),
|
arrayOf("audio_speaker_setup", { Lang["MENU_OPTIONS_SPEAKER_SETUP"] }, "textsel,headphone=MENU_OPTIONS_SPEAKER_HEADPHONE,stereo=MENU_OPTIONS_SPEAKER_STEREO"),
|
||||||
arrayOf("audio_buffer_size", { Lang["MENU_OPTIONS_App.audioMixerBufferSize"] }, "spinnersel,128,256,512,1024,2048"),
|
arrayOf("audio_buffer_size", { Lang["MENU_OPTIONS_AUDIO_BUFFER_SIZE"] }, "spinnersel,128,256,512,1024,2048"),
|
||||||
// arrayOf("", { "(${Lang["MENU_LABEL_RESTART_REQUIRED"]})" }, "p"),
|
// arrayOf("", { "(${Lang["MENU_LABEL_RESTART_REQUIRED"]})" }, "p"),
|
||||||
arrayOf("", { "${Lang["MENU_LABEL_AUDIO_BUFFER_INSTRUCTION"]}" }, "p"),
|
arrayOf("", { "${Lang["MENU_LABEL_AUDIO_BUFFER_INSTRUCTION"]}" }, "p"),
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user