diff --git a/tsvm_core/src/net/torvald/tsvm/VMSetupBroker.kt b/tsvm_core/src/net/torvald/tsvm/VMSetupBroker.kt index 2765c0a..5e0bbd2 100644 --- a/tsvm_core/src/net/torvald/tsvm/VMSetupBroker.kt +++ b/tsvm_core/src/net/torvald/tsvm/VMSetupBroker.kt @@ -58,7 +58,10 @@ object VMSetupBroker { vm.park() for (i in 1 until vm.peripheralTable.size) { - vm.peripheralTable[i].peripheral?.dispose() + try { + vm.peripheralTable[i].peripheral?.dispose() + } + catch (_: Throwable) {} } vm.getPrintStream = { TODO() } diff --git a/tsvm_core/src/net/torvald/tsvm/peripheral/AudioAdapter.kt b/tsvm_core/src/net/torvald/tsvm/peripheral/AudioAdapter.kt index 1bd38ef..85901e6 100644 --- a/tsvm_core/src/net/torvald/tsvm/peripheral/AudioAdapter.kt +++ b/tsvm_core/src/net/torvald/tsvm/peripheral/AudioAdapter.kt @@ -4,13 +4,80 @@ import com.badlogic.gdx.Gdx import com.badlogic.gdx.backends.lwjgl3.audio.OpenALLwjgl3Audio import com.badlogic.gdx.utils.Queue import net.torvald.UnsafeHelper +import net.torvald.UnsafePtr import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.toUint import net.torvald.tsvm.ThreeFiveMiniUfloat import net.torvald.tsvm.VM -import kotlin.system.exitProcess private fun Boolean.toInt() = if (this) 1 else 0 +private class RenderRunnable(val playhead: AudioAdapter.Playhead) : Runnable { + @Volatile private var exit = false + override fun run() { + while (!Thread.interrupted()) { + if (playhead.isPcmMode) { + + val writeQueue = playhead.pcmQueue + + if (playhead.isPlaying && writeQueue.notEmpty()) { + +// printdbg("Taking samples from queue (queue size: ${writeQueue.size})") + + val samples = writeQueue.removeFirst() + playhead.position = writeQueue.size + +// printdbg("P${playhead.index+1} Vol ${playhead.masterVolume}; LpP ${playhead.pcmUploadLength}; start playback...") +// printdbg(""+(0..42).joinToString { String.format("%.2f", samples[it]) }) + + playhead.audioDevice.writeSamplesUI8(samples, 0, samples.size) + +// printdbg("P${playhead.index+1} go back to spinning") + + } + else if (playhead.isPlaying) { +// printdbg("Queue exhausted, stopping...") +// it.isPlaying = false + } + } + + + Thread.sleep(1) + } + Thread.currentThread().interrupt() + } + fun stop() { + exit = true + } +} + +private class WriteQueueingRunnable(val playhead: AudioAdapter.Playhead, val pcmBin: UnsafePtr) : Runnable { + @Volatile private var exit = false + override fun run() { + while (!Thread.interrupted()) { + + playhead.let { + if (it.pcmQueue.size < 4 && it.pcmUpload && it.pcmUploadLength > 0) { +// printdbg("Downloading samples ${it.pcmUploadLength}") + + val samples = ByteArray(it.pcmUploadLength) + UnsafeHelper.memcpyRaw(null, pcmBin.ptr, samples, UnsafeHelper.getArrayOffset(samples), it.pcmUploadLength.toLong()) + it.pcmQueue.addLast(samples) + + it.pcmUploadLength = 0 + it.position += 1 + } + } + + + Thread.sleep(4) + } + Thread.currentThread().interrupt() + } + fun stop() { + exit = true + } +} + /** * Created by minjaesong on 2022-12-30. */ @@ -32,38 +99,15 @@ class AudioAdapter(val vm: VM) : PeriBase { internal val cueSheet = Array(2048) { PlayCue() } internal val pcmBin = UnsafeHelper.allocate(65536L) -// private var audioDevices: Array - private val renderThreads = Array(4) { Thread(getRenderFun(it)) } - private val writeQueueingThreads = Array(4) { Thread(getQueueingFun(it)) } + private val renderRunnables: Array + private val renderThreads: Array + private val writeQueueingRunnables: Array + private val writeQueueingThreads: Array private val threadExceptionHandler = Thread.UncaughtExceptionHandler { thread, throwable -> throwable.printStackTrace() - exitProcess(1) } - private fun getRenderFun(pheadNum: Int): () -> Unit = { while (true) { - render(playheads[pheadNum]) - Thread.sleep(1) - } } - - private fun getQueueingFun(pheadNum: Int): () -> Unit = { while (true) { - - playheads[pheadNum].let { - if (it.pcmQueue.size < 4 && it.pcmUpload && it.pcmUploadLength > 0) { - printdbg("Downloading samples ${it.pcmUploadLength}") - - val samples = ByteArray(it.pcmUploadLength) - UnsafeHelper.memcpyRaw(null, pcmBin.ptr, samples, UnsafeHelper.getArrayOffset(samples), it.pcmUploadLength.toLong()) - it.pcmQueue.addLast(samples) - - it.pcmUploadLength = 0 - it.position += 1 - } - } - - - Thread.sleep(4) - } } init { @@ -93,7 +137,10 @@ class AudioAdapter(val vm: VM) : PeriBase { Playhead(index = it, audioDevice = adev) } - + renderRunnables = Array(4) { RenderRunnable(playheads[it]) } + renderThreads = Array(4) { Thread(renderRunnables[it], "AudioRenderHead${it+1}") } + writeQueueingRunnables = Array(4) { WriteQueueingRunnable(playheads[it], pcmBin) } + writeQueueingThreads = Array(4) { Thread(writeQueueingRunnables[it], "AudioQueueingHead${it+1}") } // printdbg("AudioAdapter latency: ${audioDevice.latency}") renderThreads.forEach { it.uncaughtExceptionHandler = threadExceptionHandler; it.start() } @@ -181,8 +228,8 @@ class AudioAdapter(val vm: VM) : PeriBase { } override fun dispose() { - renderThreads.forEach { it.interrupt() } - writeQueueingThreads.forEach { it.interrupt() } + renderRunnables.forEach { it.stop() } + writeQueueingRunnables.forEach { it.stop() } playheads.forEach { it.dispose() } sampleBin.destroy() pcmBin.destroy() diff --git a/tsvm_executable/src/net/torvald/tsvm/TsvmEmulator.java b/tsvm_executable/src/net/torvald/tsvm/TsvmEmulator.java index 2a972b7..132602b 100644 --- a/tsvm_executable/src/net/torvald/tsvm/TsvmEmulator.java +++ b/tsvm_executable/src/net/torvald/tsvm/TsvmEmulator.java @@ -83,8 +83,8 @@ public class TsvmEmulator { HEIGHT = VIEWPORT_H * PANELS_Y; appConfig = new Lwjgl3ApplicationConfiguration(); - appConfig.setIdleFPS(9999); - appConfig.setForegroundFPS(9999); + appConfig.setIdleFPS(60); + appConfig.setForegroundFPS(60); appConfig.useVsync(false); appConfig.setResizable(false); appConfig.setTitle(appTitle); diff --git a/tsvm_executable/src/net/torvald/tsvm/VMEmuExecutable.kt b/tsvm_executable/src/net/torvald/tsvm/VMEmuExecutable.kt index 06c83a7..15d17da 100644 --- a/tsvm_executable/src/net/torvald/tsvm/VMEmuExecutable.kt +++ b/tsvm_executable/src/net/torvald/tsvm/VMEmuExecutable.kt @@ -16,6 +16,7 @@ import net.torvald.terrarum.utils.JsonFetcher import net.torvald.tsvm.VMEmuExecutableWrapper.Companion.FONT import net.torvald.tsvm.VMEmuExecutableWrapper.Companion.SQTEX import net.torvald.tsvm.peripheral.* +import kotlin.system.exitProcess class VMEmuExecutableWrapper(val windowWidth: Int, val windowHeight: Int, var panelsX: Int, var panelsY: Int, val diskPathRoot: String) : ApplicationAdapter() { @@ -50,8 +51,10 @@ class VMEmuExecutableWrapper(val windowWidth: Int, val windowHeight: Int, var pa } override fun dispose() { +// println("App Dispose") executable.dispose() SQTEX.dispose() + exitProcess(1) } }