diff --git a/assets/disk0/home/soundtest.js b/assets/disk0/home/soundtest.js index 1b4c4c1..44bf7d0 100644 --- a/assets/disk0/home/soundtest.js +++ b/assets/disk0/home/soundtest.js @@ -96,43 +96,9 @@ function readBytes(length) { return ptr } -/*let sampleSize = FILE_SIZE -const FETCH_INTERVAL = 631578947 -let updateAkku = FETCH_INTERVAL -let oldNanoTime = sys.nanoTime() - -const BLOCK_SIZE = 37894 - -audio.setPcmMode(0) -audio.setMasterVolume(0, 255) - -while (sampleSize > 0) { - let newNanoTime = sys.nanoTime() - updateAkku += newNanoTime - oldNanoTime - oldNanoTime = newNanoTime - - if (updateAkku >= FETCH_INTERVAL) { - println((FILE_SIZE - sampleSize) / FILE_SIZE * 100 + "%") - updateAkku -= FETCH_INTERVAL - - let readLength = (sampleSize < BLOCK_SIZE) ? sampleSize : BLOCK_SIZE - let samples = readBytes(readLength) - - audio.setUploadLength(0, readLength) - audio.putPcmDataByPtr(samples, readLength, 0) - audio.play(0) - - sampleSize -= readLength - sys.free(samples) - } - - sys.spin() -}*/ - - let sampleSize = FILE_SIZE const BLOCK_SIZE = 4096 -const QUEUEING_SIZE = 4 +const QUEUE_MAX = 4 // according to the spec audio.resetParams(0) audio.purgeQueue(0) @@ -145,20 +111,23 @@ audio.setMasterVolume(0, 255) while (sampleSize > 0) { let queueSize = audio.getPosition(0) - serial.println(`[js] Trying to upload samples, queueSize = ${queueSize}`) +// serial.println(`[js] Trying to upload samples, queueSize = ${queueSize}`) print(".") - if (queueSize == 0) { + if (queueSize <= 1) { + serial.println(`[js] Queue size: ${queueSize}; uploading ${QUEUE_MAX - queueSize} samples`) + println() println((FILE_SIZE - sampleSize) / FILE_SIZE * 100 + " %") // upload four samples for lag-safely - for (let repeat = QUEUEING_SIZE; repeat > 0; repeat--) { + for (let repeat = QUEUE_MAX - queueSize; repeat > 0; repeat--) { let readLength = (sampleSize < BLOCK_SIZE) ? sampleSize : BLOCK_SIZE let samples = readBytes(readLength) audio.putPcmDataByPtr(samples, readLength, 0) - audio.uploadSamples(0, readLength) + audio.setSampleUploadLength(0, readLength) + audio.startSampleUpload(0) sampleSize -= readLength sys.free(samples) @@ -169,6 +138,9 @@ while (sampleSize > 0) { audio.play(0) } +// audio.setMasterVolume(0, (Math.random()*255)|0) + + sys.sleep(10) } diff --git a/assets/disk0/tvdos/bin/command.js b/assets/disk0/tvdos/bin/command.js index e790025..47b3ca3 100644 --- a/assets/disk0/tvdos/bin/command.js +++ b/assets/disk0/tvdos/bin/command.js @@ -502,6 +502,27 @@ shell.coreutils = { } else return 1 }, + mv: function(args) { + if (args[2] === undefined || args[1] === undefined) { + printerrln(`Usage: ${args[0].toUpperCase()} source_file destination_file`) + return + } + let path = shell.resolvePathInput(args[1]) + let pathd = shell.resolvePathInput(args[2]) + let sourceFile = files.open(path.full) + let destFile = files.open(pathd.full) + + debugprintln(`[cp] source path: ${path.full}`) + debugprintln(`[cp] dest path: ${pathd.full}`) + + if (sourceFile.isDirectory || !sourceFile.exists) { printerrln(`${args[0].toUpperCase()} failed for '${sourceFile.fullPath}'`); return 1 } // if file is directory or failed to open, IO error code will be returned + if (destFile.isDirectory) { printerrln(`${args[0].toUpperCase()} failed for '${destFile.fullPath}'`); return 1 } // if file is directory or failed to open, IO error code will be returned + + destFile.bwrite(sourceFile.bread()) + + destFile.flush(); destFile.close() + sourceFile.remove() + }, rem: function(args) { return 0 }, @@ -555,6 +576,7 @@ shell.coreutils.rm = shell.coreutils.del shell.coreutils.ls = shell.coreutils.dir shell.coreutils.time = shell.coreutils.date shell.coreutils.md = shell.coreutils.mkdir +shell.coreutils.move = shell.coreutils.mv // end of command aliases Object.freeze(shell.coreutils) shell.stdio = { diff --git a/terranmon.txt b/terranmon.txt index e950a22..9f146d4 100644 --- a/terranmon.txt +++ b/terranmon.txt @@ -573,7 +573,7 @@ Play Head Flags NOTE: changing from PCM mode to Tracker mode or vice versa will also reset the parameters as described above Byte 2 - - PCM Mode: Sampling rate multiplier in 3.5 Unsigned Minifloat (0.03125x to 126x) + - PCM Mode: Write non-zero value to start uploading; always 0 when read Byte 3 (Tracker Mode) - BPM (24 to 280. Play Data will change this register) @@ -583,6 +583,8 @@ Play Head Flags Byte 3-4 (PCM Mode) - Signed Int16 Sampling rate difference from 30000 Hz + Uploaded PCM data will be stored onto the queue and the queue is only 4-entries long; any more uploads will be silently discarded. + 32768..65535 RW: Cue Sheet (2048 cues) Byte 1..15: pattern number for voice 1..15 diff --git a/tsvm_core/src/net/torvald/tsvm/AudioJSR223Delegate.kt b/tsvm_core/src/net/torvald/tsvm/AudioJSR223Delegate.kt index 1a77e92..6094381 100644 --- a/tsvm_core/src/net/torvald/tsvm/AudioJSR223Delegate.kt +++ b/tsvm_core/src/net/torvald/tsvm/AudioJSR223Delegate.kt @@ -16,7 +16,10 @@ class AudioJSR223Delegate(private val vm: VM) { fun setTrackerMode(playhead: Int) { getPlayhead(playhead)?.isPcmMode = false } fun isTrackerMode(playhead: Int) = getPlayhead(playhead)?.isPcmMode == false - fun setMasterVolume(playhead: Int, volume: Int) { getPlayhead(playhead)?.masterVolume = volume and 255 } + fun setMasterVolume(playhead: Int, volume: Int) { getPlayhead(playhead)?.apply { + masterVolume = volume and 255 + audioDevice.setVolume(masterVolume / 255f) + } } fun getMasterVolume(playhead: Int) = getPlayhead(playhead)?.masterVolume fun setMasterPan(playhead: Int, pan: Int) { getPlayhead(playhead)?.masterPan = pan and 255 } @@ -29,13 +32,12 @@ class AudioJSR223Delegate(private val vm: VM) { // fun setPosition(playhead: Int, pos: Int) { getPlayhead(playhead)?.position = pos and 65535 } fun getPosition(playhead: Int) = getPlayhead(playhead)?.position - fun uploadSamples(playhead: Int, length: Int) { getPlayhead(playhead)?.pcmUploadLength = length and 65535 } + fun setSampleUploadLength(playhead: Int, length: Int) { getPlayhead(playhead)?.pcmUploadLength = length and 65535 } fun setSamplingRate(playhead: Int, rate: Int) { getPlayhead(playhead)?.setSamplingRate(rate) } fun getSamplingRate(playhead: Int) = getPlayhead(playhead)?.getSamplingRate() - fun setSamplingRateMult(playhead: Int, mult: Float) { getPlayhead(playhead)?.samplingRateMult = ThreeFiveMiniUfloat(mult) } - fun getSamplingRateMult(playhead: Int) = getPlayhead(playhead)?.samplingRateMult?.toFloat() + fun startSampleUpload(playhead: Int) { getPlayhead(playhead)?.pcmUpload = true } fun setBPM(playhead: Int, bpm: Int) { getPlayhead(playhead)?.bpm = (bpm - 24).and(255) + 24 } fun getBPM(playhead: Int) = getPlayhead(playhead)?.bpm diff --git a/tsvm_core/src/net/torvald/tsvm/UnsafePtr.kt b/tsvm_core/src/net/torvald/tsvm/UnsafePtr.kt index fd826a5..c03178e 100644 --- a/tsvm_core/src/net/torvald/tsvm/UnsafePtr.kt +++ b/tsvm_core/src/net/torvald/tsvm/UnsafePtr.kt @@ -3,13 +3,15 @@ package net.torvald import sun.misc.Unsafe import java.io.PrintStream +class DanglingPointerException(msg: String) : NullPointerException(msg) +class AddressOverflowException(msg: String) : IndexOutOfBoundsException(msg) + /** * Further read: * - http://www.docjar.com/docs/api/sun/misc/Unsafe.html * * Created by minjaesong on 2019-06-21. */ - internal object UnsafeHelper { val unsafe: Unsafe @@ -87,8 +89,8 @@ internal class UnsafePtr(pointer: Long, allocSize: Long) { //// You may break the glass and use this tool when some fucking incomprehensible bugs ("vittujen vitun bugit") //// appear (e.g. getting garbage values when it fucking shouldn't) - assert(!destroyed) { throw NullPointerException("The pointer is already destroyed ($this)") } - if (index !in 0 until size) throw IndexOutOfBoundsException("Index: $index; alloc size: $size; pointer: ${this}\n${Thread.currentThread().stackTrace.joinToString("\n", limit=10) { " $it" }}") + if (destroyed) { throw DanglingPointerException("The pointer is already destroyed ($this)") } + if (index !in 0 until size) throw AddressOverflowException("Index: $index; alloc size: $size; pointer: ${this}\n${Thread.currentThread().stackTrace.joinToString("\n", limit=10) { " $it" }}") } operator fun get(index: Long): Byte { diff --git a/tsvm_core/src/net/torvald/tsvm/peripheral/AudioAdapter.kt b/tsvm_core/src/net/torvald/tsvm/peripheral/AudioAdapter.kt index b791e25..1550c01 100644 --- a/tsvm_core/src/net/torvald/tsvm/peripheral/AudioAdapter.kt +++ b/tsvm_core/src/net/torvald/tsvm/peripheral/AudioAdapter.kt @@ -28,69 +28,27 @@ class AudioAdapter(val vm: VM) : PeriBase { internal val sampleBin = UnsafeHelper.allocate(114687L) internal val instruments = Array(256) { TaudInst() } internal val playdata = Array(256) { Array(64) { TaudPlayData(0,0,0,0,0,0,0,0) } } - internal val playheads = Array(4) { Playhead() } + internal val playheads: Array internal val cueSheet = Array(2048) { PlayCue() } internal val pcmBin = UnsafeHelper.allocate(65536L) - private lateinit var audioDevices: Array +// private var audioDevices: Array private val renderThreads = Array(4) { Thread(getRenderFun(it)) } private val writeQueueingThreads = Array(4) { Thread(getQueueingFun(it)) } -// private val writeQueues = Array(4) { Queue() } - - /*private val alSources = Array(4) { - val audioField = OpenALAudioDevice::class.java.getDeclaredField("audio") - audioField.isAccessible = true - val audio = audioField.get(audioDevices[it]) as OpenALLwjgl3Audio - - val obtainSourceMethod = OpenALLwjgl3Audio::class.java.getDeclaredMethod("obtainSource", java.lang.Boolean.TYPE) - obtainSourceMethod.isAccessible = true - val alSource = obtainSourceMethod.invoke(audio, true) as Int - - alSource - } - - private val alBuffers = Array(4) { - val buffers = IntArray(3) - AL11.alGenBuffers(buffers) - buffers - } - - private fun freeAlSources() { - audioDevices.forEachIndexed { index, adev -> - val audioField = OpenALAudioDevice::class.java.getDeclaredField("audio") - audioField.isAccessible = true - val audio = audioField.get(adev) as OpenALLwjgl3Audio - - val freeSourceMethod = OpenALLwjgl3Audio::class.java.getDeclaredMethod("freeSource", java.lang.Integer.TYPE) - freeSourceMethod.isAccessible = true - freeSourceMethod.invoke(audio, alSources[index]) - } - } - - private fun enqueuePacket(alSource: Int, alBuffer: Int, data: ByteBuffer) { - AL11.alBufferData(alBuffer, AL11.AL_FORMAT_STEREO8, data, SAMPLING_RATE) - AL11.alSourceQueueBuffers(alSource, alBuffer) - - }*/ - - private val pcmCurrentPosInSamples = ShortArray(4) - - private var pcmPlaybackWatchdogs = Array(4) { Thread { - - } } private fun getRenderFun(pheadNum: Int): () -> Unit = { while (true) { - render(playheads[pheadNum], pheadNum) + render(playheads[pheadNum]) Thread.sleep(1) } } private fun getQueueingFun(pheadNum: Int): () -> Unit = { while (true) { playheads[pheadNum].let { - if (it.pcmUploadLength > 0) { + if (it.pcmQueue.size < 4 && it.pcmUpload && it.pcmUploadLength > 0) { printdbg("Downloading samples ${it.pcmUploadLength}") - val samples = FloatArray(it.pcmUploadLength) { pcmBin[it.toLong()].toUint().div(255f) * 2f - 1f } + val samples = ByteArray(it.pcmUploadLength) + UnsafeHelper.memcpyRaw(null, pcmBin.ptr, samples, UnsafeHelper.getArrayOffset(samples), it.pcmUploadLength.toLong()) it.pcmQueue.addLast(samples) it.pcmUploadLength = 0 @@ -115,14 +73,21 @@ class AudioAdapter(val vm: VM) : PeriBase { printdbg("buffer size: $deviceBufferSize x $deviceBufferCount") - audioDevices = Array(4) { OpenALBufferedAudioDevice( - Gdx.audio as OpenALLwjgl3Audio, - SAMPLING_RATE, - false, - deviceBufferSize, - deviceBufferCount) { + playheads = Array(4) { + val adev = OpenALBufferedAudioDevice( + Gdx.audio as OpenALLwjgl3Audio, + SAMPLING_RATE, + false, + deviceBufferSize, + deviceBufferCount + ) { + + } + + + Playhead(index = it, audioDevice = adev) + } - } } // printdbg("AudioAdapter latency: ${audioDevice.latency}") @@ -134,7 +99,7 @@ class AudioAdapter(val vm: VM) : PeriBase { /** * Put this function into a separate thread and keep track of the delta time by yourself */ - private fun render(playhead: Playhead, pheadNum: Int) { + private fun render(playhead: Playhead) { if (playhead.isPcmMode) { val writeQueue = playhead.pcmQueue @@ -146,14 +111,12 @@ class AudioAdapter(val vm: VM) : PeriBase { val samples = writeQueue.removeFirst() playhead.position = writeQueue.size - printdbg("P${pheadNum+1} Vol ${playhead.masterVolume}; LpP ${playhead.pcmUploadLength}; start playback...") +// printdbg("P${playhead.index+1} Vol ${playhead.masterVolume}; LpP ${playhead.pcmUploadLength}; start playback...") // printdbg(""+(0..42).joinToString { String.format("%.2f", samples[it]) }) - if (playhead.masterVolume == 0) printdbg("P${pheadNum+1} volume is zero!") - audioDevices[pheadNum].setVolume(playhead.masterVolume / 255f) - audioDevices[pheadNum].writeSamples(samples, 0, samples.size) + playhead.audioDevice.writeSamplesUI8(samples, 0, samples.size) - printdbg("P${pheadNum+1} go back to spinning") +// printdbg("P${playhead.index+1} go back to spinning") } else if (playhead.isPlaying) { @@ -215,8 +178,7 @@ class AudioAdapter(val vm: VM) : PeriBase { override fun dispose() { renderThreads.forEach { it.interrupt() } writeQueueingThreads.forEach { it.interrupt() } - audioDevices.forEach { it.dispose() } -// freeAlSources() + playheads.forEach { it.dispose() } sampleBin.destroy() pcmBin.destroy() } @@ -270,6 +232,8 @@ class AudioAdapter(val vm: VM) : PeriBase { internal object PlayInstNop : PlayInstruction(0) internal data class Playhead( + val index: Int, + var position: Int = 0, var pcmUploadLength: Int = 0, var masterVolume: Int = 0, @@ -277,11 +241,13 @@ class AudioAdapter(val vm: VM) : PeriBase { // flags var isPcmMode: Boolean = false, var isPlaying: Boolean = false, - var samplingRateMult: ThreeFiveMiniUfloat = ThreeFiveMiniUfloat(32), +// var samplingRateMult: ThreeFiveMiniUfloat = ThreeFiveMiniUfloat(32), var bpm: Int = 120, // "stored" as 96 var tickRate: Int = 6, + var pcmUpload: Boolean = false, - var pcmQueue: Queue = Queue() + var pcmQueue: Queue = Queue(), + val audioDevice: OpenALBufferedAudioDevice ) { fun read(index: Int): Byte = when (index) { 0 -> position.toByte() @@ -291,31 +257,37 @@ class AudioAdapter(val vm: VM) : PeriBase { 4 -> masterVolume.toByte() 5 -> masterPan.toByte() 6 -> (isPcmMode.toInt().shl(7) or isPlaying.toInt().shl(4)).toByte() - 7 -> samplingRateMult.index.toByte() + 7 -> 0 8 -> (bpm - 24).toByte() 9 -> tickRate.toByte() else -> throw InternalError("Bad offset $index") } - fun write(index: Int, byte: Int) = when (index) { - 0 -> if (!isPcmMode) { position = position.and(0xff00) or position } else {} - 1 -> if (!isPcmMode) { position = position.and(0x00ff) or position.shl(8) } else {} - 2 -> { pcmUploadLength = pcmUploadLength.and(0xff00) or pcmUploadLength } - 3 -> { pcmUploadLength = pcmUploadLength.and(0x00ff) or pcmUploadLength.shl(8) } - 4 -> { masterVolume = byte } - 5 -> { masterPan = byte } - 6 -> { byte.let { - val oldPcmMode = isPcmMode - isPcmMode = (it and 0b10000000) != 0 - isPlaying = (it and 0b00010000) != 0 + fun write(index: Int, byte: Int) { + val byte = byte and 255 + when (index) { + 0 -> if (!isPcmMode) { position = position.and(0xff00) or position } else {} + 1 -> if (!isPcmMode) { position = position.and(0x00ff) or position.shl(8) } else {} + 2 -> { pcmUploadLength = pcmUploadLength.and(0xff00) or pcmUploadLength } + 3 -> { pcmUploadLength = pcmUploadLength.and(0x00ff) or pcmUploadLength.shl(8) } + 4 -> { + masterVolume = byte + audioDevice.setVolume(masterVolume / 255f) + } + 5 -> { masterPan = byte } + 6 -> { byte.let { + val oldPcmMode = isPcmMode + isPcmMode = (it and 0b10000000) != 0 + isPlaying = (it and 0b00010000) != 0 - if (it and 0b01000000 != 0 || oldPcmMode != isPcmMode) resetParams() - if (it and 0b00100000 != 0) purgeQueue() - } } - 7 -> { samplingRateMult = ThreeFiveMiniUfloat(byte) } - 8 -> { bpm = byte + 24 } - 9 -> { tickRate = byte } - else -> throw InternalError("Bad offset $index") + if (it and 0b01000000 != 0 || oldPcmMode != isPcmMode) resetParams() + if (it and 0b00100000 != 0) purgeQueue() + } } + 7 -> if (isPcmMode) { pcmUpload = true } else {} + 8 -> { bpm = byte + 24 } + 9 -> { tickRate = byte } + else -> throw InternalError("Bad offset $index") + } } fun getSamplingRate() = 30000 - ((bpm - 24).and(255) or tickRate.and(255).shl(8)).toShort().toInt() @@ -338,6 +310,10 @@ class AudioAdapter(val vm: VM) : PeriBase { pcmUploadLength = 0 } } + + fun dispose() { + audioDevice.dispose() + } } internal data class TaudPlayData( diff --git a/tsvm_core/src/net/torvald/tsvm/peripheral/IOSpace.kt b/tsvm_core/src/net/torvald/tsvm/peripheral/IOSpace.kt index 8cb7657..52450db 100644 --- a/tsvm_core/src/net/torvald/tsvm/peripheral/IOSpace.kt +++ b/tsvm_core/src/net/torvald/tsvm/peripheral/IOSpace.kt @@ -3,6 +3,8 @@ package net.torvald.tsvm.peripheral import com.badlogic.gdx.Gdx import com.badlogic.gdx.Input import com.badlogic.gdx.InputProcessor +import net.torvald.AddressOverflowException +import net.torvald.DanglingPointerException import net.torvald.UnsafeHelper import net.torvald.tsvm.CircularArray import net.torvald.tsvm.VM @@ -159,77 +161,96 @@ class IOSpace(val vm: VM) : PeriBase, InputProcessor { override fun mmio_write(addr: Long, byte: Byte) { val adi = addr.toInt() val bi = byte.toInt().and(255) - when (addr) { - 37L -> keyboardBuffer.appendHead(byte) - 38L -> { - keyboardInputRequested = (byte.isNonZero()) - if (keyboardInputRequested) keyboardBuffer.clear() + try { + when (addr) { + 37L -> keyboardBuffer.appendHead(byte) + 38L -> { + keyboardInputRequested = (byte.isNonZero()) + if (keyboardInputRequested) keyboardBuffer.clear() + } + + 39L -> rawInputFunctionLatched = (byte.isNonZero()) + in 40..47 -> keyEventBuffers[adi - 40] = byte + 68L -> { + uptimeCounterLatched = byte.and(0b01).isNonZero() + RTClatched = byte.and(0b10).isNonZero() + } + + 88L -> vm.romMapping = bi + 89L -> { + acpiShutoff = byte.and(-128).isNonZero() + } + + in 1024..2047 -> peripheralFast[addr - 1024] = byte + + 4076L -> blockTransferPorts[0].statusCode.set(bi) + 4077L -> blockTransferPorts[1].statusCode.set(bi) + 4078L -> blockTransferPorts[2].statusCode.set(bi) + 4079L -> blockTransferPorts[3].statusCode.set(bi) + + 4084L -> + blockTransferPorts[0].blockSize.getAcquire().let { + blockTransferPorts[0].blockSize.setRelease(it.and(0xFF00) or byte.toInt().and(255)) + } + + 4085L -> { + blockTransferPorts[0].hasNext.set(byte < 0) + blockTransferPorts[0].blockSize.getAcquire().let { + blockTransferPorts[0].blockSize.setRelease(it.and(0x00FF) or byte.toInt().and(15)) + } + } + + 4086L -> blockTransferPorts[1].blockSize.getAcquire().let { + blockTransferPorts[1].blockSize.setRelease(it.and(0xFF00) or byte.toInt().and(255)) + } + + 4087L -> { + blockTransferPorts[1].hasNext.set(byte < 0) + blockTransferPorts[1].blockSize.getAcquire().let { + blockTransferPorts[1].blockSize.setRelease(it.and(0x00FF) or byte.toInt().and(15)) + } + } + + 4088L -> blockTransferPorts[2].blockSize.getAcquire().let { + blockTransferPorts[2].blockSize.setRelease(it.and(0xFF00) or byte.toInt().and(255)) + } + + 4089L -> { + blockTransferPorts[2].hasNext.set(byte < 0) + blockTransferPorts[2].blockSize.getAcquire().let { + blockTransferPorts[2].blockSize.setRelease(it.and(0x00FF) or byte.toInt().and(15)) + } + } + + 4090L -> blockTransferPorts[3].blockSize.getAcquire().let { + blockTransferPorts[3].blockSize.setRelease(it.and(0xFF00) or byte.toInt().and(255)) + } + + 4091L -> { + blockTransferPorts[3].hasNext.set(byte < 0) + blockTransferPorts[3].blockSize.getAcquire().let { + blockTransferPorts[3].blockSize.setRelease(it.and(0x00FF) or byte.toInt().and(15)) + } + } + + in 4092..4095 -> setBlockTransferPortStatus(adi - 4092, byte) + + in 4096..8191 -> blockTransferTx[0][addr - 4096] = byte + in 8192..12287 -> blockTransferTx[1][addr - 8192] = byte + in 12288..16383 -> blockTransferTx[2][addr - 12288] = byte + in 16384..20479 -> blockTransferTx[3][addr - 16384] = byte + + in 131072..262143 -> vm.peripheralTable[1].peripheral?.mmio_write(addr - 131072, byte) + in 262144..393215 -> vm.peripheralTable[2].peripheral?.mmio_write(addr - 262144, byte) + in 393216..524287 -> vm.peripheralTable[3].peripheral?.mmio_write(addr - 393216, byte) + in 524288..655359 -> vm.peripheralTable[4].peripheral?.mmio_write(addr - 524288, byte) + in 655360..786431 -> vm.peripheralTable[5].peripheral?.mmio_write(addr - 655360, byte) + in 786432..917503 -> vm.peripheralTable[6].peripheral?.mmio_write(addr - 786432, byte) + in 917504..1048575 -> vm.peripheralTable[7].peripheral?.mmio_write(addr - 917504, byte) } - 39L -> rawInputFunctionLatched = (byte.isNonZero()) - in 40..47 -> keyEventBuffers[adi - 40] = byte - 68L -> { - uptimeCounterLatched = byte.and(0b01).isNonZero() - RTClatched = byte.and(0b10).isNonZero() - } - - 88L -> vm.romMapping = bi - 89L -> { acpiShutoff = byte.and(-128).isNonZero() } - - in 1024..2047 -> peripheralFast[addr - 1024] = byte - - 4076L -> blockTransferPorts[0].statusCode.set(bi) - 4077L -> blockTransferPorts[1].statusCode.set(bi) - 4078L -> blockTransferPorts[2].statusCode.set(bi) - 4079L -> blockTransferPorts[3].statusCode.set(bi) - - 4084L -> - blockTransferPorts[0].blockSize.getAcquire().let { - blockTransferPorts[0].blockSize.setRelease(it.and(0xFF00) or byte.toInt().and(255)) } - 4085L -> { - blockTransferPorts[0].hasNext.set(byte < 0) - blockTransferPorts[0].blockSize.getAcquire().let { - blockTransferPorts[0].blockSize.setRelease(it.and(0x00FF) or byte.toInt().and(15)) } - } - - 4086L -> blockTransferPorts[1].blockSize.getAcquire().let { - blockTransferPorts[1].blockSize.setRelease(it.and(0xFF00) or byte.toInt().and(255)) } - 4087L -> { - blockTransferPorts[1].hasNext.set(byte < 0) - blockTransferPorts[1].blockSize.getAcquire().let { - blockTransferPorts[1].blockSize.setRelease(it.and(0x00FF) or byte.toInt().and(15)) } - } - - 4088L -> blockTransferPorts[2].blockSize.getAcquire().let { - blockTransferPorts[2].blockSize.setRelease(it.and(0xFF00) or byte.toInt().and(255)) } - 4089L -> { - blockTransferPorts[2].hasNext.set(byte < 0) - blockTransferPorts[2].blockSize.getAcquire().let { - blockTransferPorts[2].blockSize.setRelease(it.and(0x00FF) or byte.toInt().and(15)) } - } - - 4090L -> blockTransferPorts[3].blockSize.getAcquire().let { - blockTransferPorts[3].blockSize.setRelease(it.and(0xFF00) or byte.toInt().and(255)) } - 4091L -> { - blockTransferPorts[3].hasNext.set(byte < 0) - blockTransferPorts[3].blockSize.getAcquire().let { - blockTransferPorts[3].blockSize.setRelease(it.and(0x00FF) or byte.toInt().and(15)) } - } - - in 4092..4095 -> setBlockTransferPortStatus(adi - 4092, byte) - - in 4096..8191 -> blockTransferTx[0][addr - 4096] = byte - in 8192..12287 -> blockTransferTx[1][addr - 8192] = byte - in 12288..16383 -> blockTransferTx[2][addr - 12288] = byte - in 16384..20479 -> blockTransferTx[3][addr - 16384] = byte - - in 131072..262143 -> vm.peripheralTable[1].peripheral?.mmio_write(addr - 131072, byte) - in 262144..393215 -> vm.peripheralTable[2].peripheral?.mmio_write(addr - 262144, byte) - in 393216..524287 -> vm.peripheralTable[3].peripheral?.mmio_write(addr - 393216, byte) - in 524288..655359 -> vm.peripheralTable[4].peripheral?.mmio_write(addr - 524288, byte) - in 655360..786431 -> vm.peripheralTable[5].peripheral?.mmio_write(addr - 655360, byte) - in 786432..917503 -> vm.peripheralTable[6].peripheral?.mmio_write(addr - 786432, byte) - in 917504..1048575 -> vm.peripheralTable[7].peripheral?.mmio_write(addr - 917504, byte) } + catch (_: DanglingPointerException) {} + catch (_: AddressOverflowException) {} } override fun dispose() { diff --git a/tsvm_core/src/net/torvald/tsvm/peripheral/OpenALBufferedAudioDevice.kt b/tsvm_core/src/net/torvald/tsvm/peripheral/OpenALBufferedAudioDevice.kt index 47ce186..63fa110 100644 --- a/tsvm_core/src/net/torvald/tsvm/peripheral/OpenALBufferedAudioDevice.kt +++ b/tsvm_core/src/net/torvald/tsvm/peripheral/OpenALBufferedAudioDevice.kt @@ -5,6 +5,7 @@ import com.badlogic.gdx.backends.lwjgl3.audio.OpenALAudioDevice import com.badlogic.gdx.backends.lwjgl3.audio.OpenALLwjgl3Audio import com.badlogic.gdx.math.MathUtils import com.badlogic.gdx.utils.GdxRuntimeException +import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.toUint import org.lwjgl.BufferUtils import org.lwjgl.openal.AL10 import org.lwjgl.openal.AL11 @@ -64,6 +65,20 @@ class OpenALBufferedAudioDevice( tempBuffer = BufferUtils.createByteBuffer(bufferSize) } + fun writeSamplesUI8(samples: ByteArray, offset: Int, numSamples: Int) { + if (bytes == null || bytes!!.size < numSamples * 2) bytes = ByteArray(numSamples * 2) + val end = Math.min(offset + numSamples, samples.size) + var i = offset + var ii = 0 + while (i < end) { + val sample = ui8toI16Hi[samples[i].toUint()] + bytes!![ii++] = sample + bytes!![ii++] = sample + i++ + } + writeSamples(bytes!!, 0, numSamples * 2) + } + override fun writeSamples(samples: ShortArray, offset: Int, numSamples: Int) { if (bytes == null || bytes!!.size < numSamples * 2) bytes = ByteArray(numSamples * 2) val end = Math.min(offset + numSamples, samples.size) @@ -228,5 +243,7 @@ class OpenALBufferedAudioDevice( companion object { private const val bytesPerSample = 2 + private val ui8toI16Hi = ByteArray(256) { (128 + it).toByte() } + } } \ No newline at end of file