midi2taud: loop point detection and forced-loop

This commit is contained in:
minjaesong
2026-06-16 23:04:51 +09:00
parent 930e867b3e
commit c3702fb597
5 changed files with 315 additions and 29 deletions

View File

@@ -3852,6 +3852,7 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
ts.cuePos = when (instr) {
is PlayInstGoBack -> (ts.cuePos - instr.arg).coerceAtLeast(0)
is PlayInstSkip -> (ts.cuePos + instr.arg).coerceAtMost(1023)
is PlayInstJump -> instr.arg.coerceIn(0, 1023)
else -> (ts.cuePos + 1).coerceAtMost(1023)
}
playhead.position = ts.cuePos
@@ -4113,7 +4114,7 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
// 00000000 (NOP) default 64-row cue
// 1000xxxx yyyyyyyy (BAK) go back 12-bit arg
// 1001xxxx yyyyyyyy (FWD) skip forward 12-bit arg
// 1111xxxx yyyyyyyy (JMP) go to absolute pattern (currently unused)
// 1111xxxx yyyyyyyy (JMP) go to absolute cue (loop back to cue arg)
private fun recomputeInstruction() {
val b30 = instByte30
val b31 = instByte31
@@ -4130,7 +4131,8 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
(b30 and 0xF0) == 0x80 -> PlayInstGoBack(((b30 and 0xF) shl 8) or (b31 and 0xFF))
// FWD: 1001xxxx yyyyyyyy — 12-bit arg.
(b30 and 0xF0) == 0x90 -> PlayInstSkip(((b30 and 0xF) shl 8) or (b31 and 0xFF))
// JMP: 1111xxxx yyyyyyyy — reserved (decoder TBD).
// JMP: 1111xxxx yyyyyyyy — go to absolute cue 0bxxxxyyyyyyyy.
(b30 and 0xF0) == 0xF0 -> PlayInstJump(((b30 and 0xF) shl 8) or (b31 and 0xFF))
else -> PlayInstNop
}
}
@@ -4176,6 +4178,9 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
internal open class PlayInstruction(val arg: Int)
internal class PlayInstGoBack(arg: Int) : PlayInstruction(arg)
internal class PlayInstSkip(arg: Int) : PlayInstruction(arg)
/** "JMP": go to absolute cue [arg]. Used by looping converters to jump back
* to the loop-start cue (e.g. midi2taud's whole-song / loop-marker loop). */
internal class PlayInstJump(arg: Int) : PlayInstruction(arg)
internal class PlayInstPatLen(val rows: Int) : PlayInstruction(rows)
/** "Halt at x": play [rows] rows of the pattern (1..64) then stop. */
internal class PlayInstHaltAt(val rows: Int) : PlayInstruction(rows)

View File

@@ -19,13 +19,11 @@ import net.torvald.terrarum.DefaultGL32Shaders
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.toUint
import net.torvald.tsvm.*
import net.torvald.tsvm.peripheral.GraphicsAdapter.Companion.DRAW_SHADER_FRAG
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import java.util.*
import kotlin.experimental.and
import kotlin.math.floor
import kotlin.math.min
data class AdapterConfig(
val theme: String,
@@ -114,7 +112,7 @@ open class GraphicsAdapter(private val assetsRoot: String, val vm: VM, val confi
override var blinkCursor = true
override var ttyRawMode = false
private var graphicsUseSprites = false
private var graphicsDisableTexts = false
private var lastUsedColour = (-1).toByte()
private var currentChrRom = 0
private var chrWidth = 7f
@@ -346,7 +344,7 @@ open class GraphicsAdapter(private val assetsRoot: String, val vm: VM, val confi
ttyRawMode.toInt(1) or
blinkCursor.toInt()).toByte()
private fun getGraphicsAttributes(): Byte = graphicsUseSprites.toInt().toByte()
private fun getGraphicsAttributes(): Byte = graphicsDisableTexts.toInt().toByte()
private fun setTextmodeAttributes(rawbyte: Byte) {
currentChrRom = rawbyte.toInt().and(0b11110000).ushr(4)
@@ -355,7 +353,7 @@ open class GraphicsAdapter(private val assetsRoot: String, val vm: VM, val confi
}
private fun setGraphicsAttributes(rawbyte: Byte) {
graphicsUseSprites = rawbyte.and(1) == 1.toByte()
graphicsDisableTexts = rawbyte.and(1) == 1.toByte()
}
override fun mmio_read(addr: Long): Byte? {
@@ -1248,7 +1246,7 @@ open class GraphicsAdapter(private val assetsRoot: String, val vm: VM, val confi
outFBObatch.color = Color.WHITE
if (!graphicsUseSprites) {
if (!graphicsDisableTexts) {
// draw texts
val (cx, cy) = getCursorPos()