format revision and tracker GUI

This commit is contained in:
minjaesong
2026-04-23 20:48:40 +09:00
parent 44f11120d8
commit 25309cf5b6
2 changed files with 63 additions and 35 deletions

View File

@@ -679,9 +679,9 @@ on sample byte read during loop playback:
Each cell carries a 6-bit value field plus a 2-bit selector field for the volume column. The four selectors are: Each cell carries a 6-bit value field plus a 2-bit selector field for the volume column. The four selectors are:
- **`0.$xx` — Set volume** to `$xx` (6-bit, $00..$3F). Equivalent to a note's default volume. - **`0.$xx` — Set volume** to `$xx` (6-bit, $00..$3F). Equivalent to a note's default volume.
- **`1.$xx` — Volume slide up** by `$xx` per non-first tick (6-bit). Volume clamps at $3F. - **`1.$xx` — Volume slide up** by `$xx` per non-first tick (4-bit). Volume clamps at $3F.
- **`2.$xx` — Volume slide down** by `$xx` per non-first tick (6-bit). Volume clamps at $00. - **`2.$xx` — Volume slide down** by `$xx` per non-first tick (4-bit). Volume clamps at $00.
- **`3.$Sx` — Fine volume slide** on tick 0 only. The high bit `$S` of the value selects direction (0 = down, 1 = up); the low 5 bits `$x` ($00..$1F) are the magnitude. Equivalent in scale to `D $xF00` / `D $Fy00` but with a 5-bit cap. Fires once per row regardless of speed. - **`3.$Sx` — Fine volume slide** on tick 0 only. The high bit `$S` of the value selects direction (0 = down, 1 = up); the low 4 bits `$x` ($0..$F) are the magnitude. Equivalent in scale to `D $xF00` / `D $Fy00` but with a 5-bit cap. Fires once per row regardless of speed.
Volume-column effects do not consume the main effect slot; a cell can carry both (for instance, a tone portamento in the effect slot and a volume slide in the volume column). Volume-column effects do not consume the main effect slot; a cell can carry both (for instance, a tone portamento in the effect slot and a volume slide in the volume column).
@@ -696,8 +696,8 @@ NOTE: **`3.00` — is No-op**
The panning column uses the same 6-bit value + 2-bit selector layout: The panning column uses the same 6-bit value + 2-bit selector layout:
- **`0.$xx` — Set pan** (6-bit, $00..$3F mapped onto the channel's 8-bit pan space; $01 = full left, $1F = centre-left, $20 = centre-right, $3F = full right). For 8-bit precision use `S $80xx` instead. - **`0.$xx` — Set pan** (6-bit, $00..$3F mapped onto the channel's 8-bit pan space; $01 = full left, $1F = centre-left, $20 = centre-right, $3F = full right). For 8-bit precision use `S $80xx` instead.
- **`1.$xx` — Pan slide right** by `$xx` per non-first tick. - **`1.$xx` — Pan slide right** by `$xx` per non-first tick (4-bit).
- **`2.$xx` — Pan slide left** by `$xx` per non-first tick. - **`2.$xx` — Pan slide left** by `$xx` per non-first tick (4-bit).
- **`3.$Sx` — Fine pan slide** on tick 0 only, same direction-bit encoding as the volume column's selector 3. - **`3.$Sx` — Fine pan slide** on tick 0 only, same direction-bit encoding as the volume column's selector 3.
NOTE: **`3.00` — is No-op** NOTE: **`3.00` — is No-op**

View File

@@ -47,13 +47,13 @@ keyoff:"\u00A0\u00CD\u00CD\u00A1",
notecut:"\u00A4\u00A4\u00A4\u00A4", notecut:"\u00A4\u00A4\u00A4\u00A4",
/* special effects */ /* special effects */
volset:MIDDOT, volset:'',//MIDDOT,
volup:"\u008430u", volup:"\u008430u",
voldn:"\u008431u", voldn:"\u008431u",
volfineup:"+", volfineup:"+",
volfinedn:"-", volfinedn:"-",
panset:MIDDOT, panset:'',//MIDDOT,
panle:"\u008417u", panle:"\u008417u",
panri:"\u008416u", panri:"\u008416u",
panfinele:"\u008427u", panfinele:"\u008427u",
@@ -133,6 +133,9 @@ Number.prototype.hex04 = function() {
Number.prototype.hexD2 = function() { Number.prototype.hexD2 = function() {
return this.toString(16).toUpperCase().padStart(2, sym.middot) return this.toString(16).toUpperCase().padStart(2, sym.middot)
} }
Number.prototype.hex1 = function() {
return this.toString(16).toUpperCase()
}
Number.prototype.dec02 = function() { Number.prototype.dec02 = function() {
return this.toString(10).toUpperCase().padStart(2,'0') return this.toString(10).toUpperCase().padStart(2,'0')
} }
@@ -165,44 +168,44 @@ function buildRowCell(ptnDat, row) {
if (inst == 0) sInst = sym.middot.repeat(2) if (inst == 0) sInst = sym.middot.repeat(2)
let sVolEff = volEffSym[voleff >>> 6] let sVolEff = volEffSym[voleff >>> 6]
let sVolArg = voleffarg.decD2() let sVolArg = voleffarg.hexD2()
if (voleff === 0) { if (voleff === 0) {
sVolEff = sym.middot sVolEff = ''
sVolArg = sym.middot.repeat(2) sVolArg = sym.middot.repeat(2)
} }
else if (voleff >>> 6 == 3) { else if (voleff >>> 6 == 3) {
if (voleffarg == 0) { if (voleffarg == 0) {
sVolEff = sym.middot sVolEff = sym.middot
sVolArg = sym.middot.repeat(2) sVolArg = sym.middot.repeat(1)
} }
else if (voleffarg >= 32) { else if (voleffarg >= 32) {
sVolEff = volEffSym[3] sVolEff = volEffSym[3]
sVolArg = (voleffarg & 31).dec02() sVolArg = (voleffarg & 15).hex1()
} }
else { else {
sVolEff = volEffSym[4] sVolEff = volEffSym[4]
sVolArg = (voleffarg & 31).dec02() sVolArg = (voleffarg & 15).hex1()
} }
} }
let sPanEff = panEffSym[paneff >>> 6] let sPanEff = panEffSym[paneff >>> 6]
let sPanArg = paneffarg.decD2() let sPanArg = paneffarg.hexD2()
if (paneff === 0) { if (paneff === 0) {
sPanEff = sym.middot sPanEff = ''
sPanArg = sym.middot.repeat(2) sPanArg = sym.middot.repeat(2)
} }
else if (paneff >>> 6 == 3) { else if (paneff >>> 6 == 3) {
if (paneffarg == 0) { if (paneffarg == 0) {
sPanEff = sym.middot sPanEff = sym.middot
sPanArg = sym.middot.repeat(2) sPanArg = sym.middot.repeat(1)
} }
else if (paneffarg >= 32) { else if (paneffarg >= 32) {
sPanEff = panEffSym[4] sPanEff = panEffSym[4]
sPanArg = (paneffarg & 31).dec02() sPanArg = (paneffarg & 15).hex1()
} }
else { else {
sPanEff = panEffSym[3] sPanEff = panEffSym[3]
sPanArg = (paneffarg & 31).dec02() sPanArg = (paneffarg & 15).hex1()
} }
} }
@@ -219,9 +222,9 @@ function buildRowCell(ptnDat, row) {
const EMPTY_CELL = { const EMPTY_CELL = {
sNote: sym.middot.repeat(4), sNote: sym.middot.repeat(4),
sInst: sym.middot.repeat(3), sInst: sym.middot.repeat(3),
sVolEff: sym.middot, sVolEff: '',
sVolArg: sym.middot.repeat(2), sVolArg: sym.middot.repeat(2),
sPanEff: sym.middot, sPanEff: '',
sPanArg: sym.middot.repeat(2), sPanArg: sym.middot.repeat(2),
sEffOp: sym.middot, sEffOp: sym.middot,
sEffArg: sym.middot.repeat(4) sEffArg: sym.middot.repeat(4)
@@ -339,11 +342,11 @@ function loadTaud(filePath, songIndex) {
///////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////
const [SCRH, SCRW] = con.getmaxyx() const [SCRH, SCRW] = con.getmaxyx()
const PTNVIEW_OFFSET_X = 5 const PTNVIEW_OFFSET_X = 3
const PTNVIEW_OFFSET_Y = 9 const PTNVIEW_OFFSET_Y = 9
const PTNVIEW_HEIGHT = SCRH - PTNVIEW_OFFSET_Y const PTNVIEW_HEIGHT = SCRH - PTNVIEW_OFFSET_Y
const COLSIZE = 18 const COLSIZE = 15
const VOCSIZE = 4 const VOCSIZE = 5
const VIEW_TIMELINE = 0 const VIEW_TIMELINE = 0
const VIEW_ORDERS = 1 const VIEW_ORDERS = 1
@@ -358,6 +361,8 @@ const colStatus = 253
const colVoiceHdr = 230 const colVoiceHdr = 230
const colSep = 252 const colSep = 252
let separatorStyle = 0
function fillLine(y, c, back) { function fillLine(y, c, back) {
con.color_pair(c, back) con.color_pair(c, back)
for (let x = 1; x <= SCRW; x++) { for (let x = 1; x <= SCRW; x++) {
@@ -369,17 +374,36 @@ function drawStatusBar() {
fillLine(1, colStatus, 255) fillLine(1, colStatus, 255)
const maxCue = song.lastActiveCue < 0 ? 0 : song.lastActiveCue const maxCue = song.lastActiveCue < 0 ? 0 : song.lastActiveCue
const vHi = Math.min(voiceOff + VOCSIZE, song.numVoices) const vHi = Math.min(voiceOff + VOCSIZE, song.numVoices)
const txt = ` ${song.filePath} Cue ${cueIdx.hex03()}/${maxCue.hex03()} Row ${cursorRow.dec02()} V${(voiceOff+1).dec02()}-${vHi.dec02()}/${song.numVoices.dec02()} BPM ${song.bpm} Spd ${song.tickRate} ` const txt = `${song.filePath} Cue ${cueIdx.hex03()}/${maxCue.hex03()} Row ${cursorRow.dec02()} V${(voiceOff+1).dec02()}-${vHi.dec02()}/${song.numVoices.dec02()} BPM ${song.bpm} Spd ${song.tickRate} `
con.move(1, 1) con.move(1, 1)
con.color_pair(colStatus, 255) con.color_pair(colStatus, 255)
print(txt) print(txt)
} }
function drawSeparators(posY, col_size) { /**
con.color_pair(colSep, 255) * @param style 0: condensed timeline, 1: vertical bars between voices
for (let c = 0; c < VOCSIZE - 1; c++) { */
con.move(posY, PTNVIEW_OFFSET_X + col_size * (c+1) - 1) function drawSeparators(style) {
con.prnch(0xB3) if (style == 1) {
con.color_pair(colSep, 255)
for (let c = 0; c < VOCSIZE - 1; c++) {
for (let y = PTNVIEW_OFFSET_Y - 1; y < PTNVIEW_HEIGHT; y++) {
con.move(y, PTNVIEW_OFFSET_X + COLSIZE * (c+1) - 1)
con.prnch(0xB3)
}
}
}
else {
// paint the first column of pattern view with colour
for (let x = PTNVIEW_OFFSET_X; x < SCRW - 3; x += COLSIZE) {
for (let y = 0; y < PTNVIEW_HEIGHT+1; y++) {
let memOffset = (y+PTNVIEW_OFFSET_Y-2) * SCRW + (x-1)
let bgColOffset = GPU_MEM - TEXT_BACK_OFF - memOffset
sys.poke(bgColOffset, colHighlight)
}
}
con.color_pair(colSep, 255)
} }
} }
@@ -400,12 +424,12 @@ function drawVoiceHeaders() {
const ptnIdx = cue.ptns[voice] const ptnIdx = cue.ptns[voice]
const vlabel = `V${(voice+1).dec02()}` const vlabel = `V${(voice+1).dec02()}`
const plabel = (ptnIdx === CUE_EMPTY) ? '---' : ptnIdx.hex03() const plabel = (ptnIdx === CUE_EMPTY) ? '---' : ptnIdx.hex03()
const label = ` ${vlabel} ptn ${plabel} ` const label = ` ${vlabel} ptn ${plabel} `
print((label + ' ').substring(0, COLSIZE - 1)) print((label + ' ').substring(0, COLSIZE - 1))
} }
} }
drawSeparators(PTNVIEW_OFFSET_Y - 1, COLSIZE) drawSeparators(separatorStyle)
} }
function drawPatternRowAt(viewRow) { function drawPatternRowAt(viewRow) {
@@ -440,7 +464,7 @@ function drawPatternRowAt(viewRow) {
drawCellAt(y, x, cell, back) drawCellAt(y, x, cell, back)
} }
drawSeparators(y, COLSIZE) drawSeparators(separatorStyle)
} }
function drawPatternView() { function drawPatternView() {
@@ -529,10 +553,10 @@ function drawVoiceDetail() {
const effarg = ptnDat[6] | (ptnDat[7] << 8) const effarg = ptnDat[6] | (ptnDat[7] << 8)
con.move(6,1) con.move(6,1)
print(`Pattern $${ptnIdx.hex02()}\tRow ${cursorRow.dec02()}\tVoice ${cursorVox}`) print(`Pattern $${ptnIdx.hex02()}\tRow ${cursorRow.dec02()}\tVoice ${cursorVox+1}`)
con.move(7,1) con.move(7,1)
print(`Pitch $${note.hex04()}\tInst $${inst.hex02()}\tVolEff ${voleffop}.${voleffarg.dec02()}\t`+ print(`Pitch $${note.hex04()}\tInst $${inst.hex02()}\tVolEff ${voleffop}.$${voleffarg.hex02()}\t`+
`PanEff ${paneffop}.${paneffarg.dec02()}\tFx ${effop.toString(36).toUpperCase()}.${effarg.hex04()}`) `PanEff ${paneffop}.$${paneffarg.hex02()}\tFx ${effop.toString(36).toUpperCase()}.${effarg.hex04()}`)
} }
function drawAll() { function drawAll() {
@@ -541,6 +565,7 @@ function drawAll() {
drawVoiceHeaders() drawVoiceHeaders()
drawPatternView() drawPatternView()
drawVoiceDetail() drawVoiceDetail()
drawSeparators(separatorStyle)
drawControlHint() drawControlHint()
con.move(1, 1) con.move(1, 1)
} }
@@ -639,7 +664,6 @@ function drawVoiceColumnAt(slot) {
cell = buildRowCell(song.patterns[ptnIdx], actualRow) cell = buildRowCell(song.patterns[ptnIdx], actualRow)
} }
drawCellAt(y, x, cell, back) drawCellAt(y, x, cell, back)
drawSeparators(y, COLSIZE)
} }
} }
@@ -789,6 +813,7 @@ function updatePlayback() {
drawPatternRowAt(cursorRow - scrollRow) drawPatternRowAt(cursorRow - scrollRow)
} }
drawStatusBar() drawStatusBar()
drawSeparators(separatorStyle)
drawVoiceDetail() drawVoiceDetail()
} }
} }
@@ -854,6 +879,7 @@ while (!exitFlag) {
drawVoiceColumnAt(dVoice > 0 ? VOCSIZE - 1 : 0) drawVoiceColumnAt(dVoice > 0 ? VOCSIZE - 1 : 0)
} }
drawVoiceHeaders() drawVoiceHeaders()
drawSeparators(separatorStyle)
drawStatusBar() drawStatusBar()
} }
else if (keysym === "m" || keysym === "M") { toggleMute(cursorVox) } else if (keysym === "m" || keysym === "M") { toggleMute(cursorVox) }
@@ -881,6 +907,7 @@ while (!exitFlag) {
drawVoiceColumnAt(dVoice > 0 ? VOCSIZE - 1 : 0) drawVoiceColumnAt(dVoice > 0 ? VOCSIZE - 1 : 0)
} }
drawVoiceHeaders() drawVoiceHeaders()
drawSeparators(separatorStyle)
drawStatusBar() drawStatusBar()
drawVoiceDetail() drawVoiceDetail()
return return
@@ -933,6 +960,7 @@ while (!exitFlag) {
drawPatternRowAt(cursorRow - scrollRow) drawPatternRowAt(cursorRow - scrollRow)
} }
drawSeparators(separatorStyle)
drawStatusBar() drawStatusBar()
drawVoiceDetail() drawVoiceDetail()
}) })