taut: minor bugfixes

This commit is contained in:
minjaesong
2026-04-27 18:19:58 +09:00
parent 6bc49e3f0b
commit 2053526dfa
6 changed files with 324 additions and 25 deletions

View File

@@ -552,6 +552,10 @@ const VOCSIZE_ORDERS = Math.floor((SCRW - 8) / 4)
const VIEW_TIMELINE = 0
const VIEW_CUES = 1
const VIEW_PATTERN_DETAILS = 2
const VIEW_SAMPLES = 3
const VIEW_INSTRMNT = 4
const VIEW_PROJECT = 5
const VIEW_FILE = 6
const colPlayback = 86
const colHighlight = 41
@@ -840,7 +844,8 @@ function drawControlHint() {
// ['q','Quit'],
]
let hintElems = [hintElemTimeline, hintElemOrders, hintElemPatterns]
const hintElemExternal = [['Tab','Panel']]
let hintElems = [hintElemTimeline, hintElemOrders, hintElemPatterns, hintElemExternal, hintElemExternal, hintElemExternal, hintElemExternal]
// erase current line
con.move(SCRH, 1)
@@ -1156,6 +1161,22 @@ function resetAudioDevice() {
audio.stop(PLAYHEAD)
}
function applyMuteTransition(toPanel) {
if (toPanel === VIEW_PATTERN_DETAILS) {
timelineMuteSnapshot = voiceMutes.slice()
if (voiceMutes[0]) {
voiceMutes[0] = false
audio.setVoiceMute(PLAYHEAD, 0, false)
}
} else if (toPanel === VIEW_TIMELINE && timelineMuteSnapshot !== null) {
for (let i = 0; i < song.numVoices; i++) {
voiceMutes[i] = timelineMuteSnapshot[i]
audio.setVoiceMute(PLAYHEAD, i, voiceMutes[i])
}
timelineMuteSnapshot = null
}
}
function redrawFull() { drawAll() }
function redrawPanel() {
@@ -1273,7 +1294,7 @@ function timelineInput(wo, event) {
const oldVoiceOff = voiceOff
const prevVox = cursorVox
let triedCross = false
if (shiftDown) {
if (shiftDown || timelineRowStyle > 0) {
cursorVox += dir * moveDelta
timelineColCursor = dir > 0 ? 0 : 5
} else {
@@ -1750,8 +1771,33 @@ function patternsInput(wo, event) {
const panelTimeline = new win.WindowObject(1, PTNVIEW_OFFSET_Y, SCRW, PTNVIEW_HEIGHT, timelineInput, drawTimelineContents, undefined, ()=>{})
const panelOrders = new win.WindowObject(1, PTNVIEW_OFFSET_Y, SCRW, PTNVIEW_HEIGHT, ordersInput, drawOrdersContents, undefined, ()=>{})
const panelPatterns = new win.WindowObject(1, PTNVIEW_OFFSET_Y, SCRW, PTNVIEW_HEIGHT, patternsInput, drawPatternsContents, undefined, ()=>{})
const panels = [panelTimeline, panelOrders, panelPatterns]
const panelPatterns = new win.WindowObject(1, PTNVIEW_OFFSET_Y, SCRW, PTNVIEW_HEIGHT, patternsInput, drawPatternsContents, undefined, ()=>{})
// External sub-program panels: drawContents launches the sub-program synchronously.
// The sub-program draws rows 4+ and does NOT touch rows 1-3 (drawn by taut.js before launch).
// On exit, the sub-program sets _G.taut_nextPanel to request a tab switch.
function makeExternalPanelDraw(progName) {
return function(wo) {
_G.taut_nextPanel = undefined
_G.shell.execute(`${progName} ${fullPathObj.full} ${currentPanel}`)
}
}
function drawProjectContents(wo) {
fillLine(PTNVIEW_OFFSET_Y - 1, colVoiceHdr, 255)
for (let y = PTNVIEW_OFFSET_Y; y < SCRH; y++) fillLine(y, colBackPtn, 255)
con.move(PTNVIEW_OFFSET_Y + 2, 3)
con.color_pair(colStatus, 255)
print('[Project settings — not yet implemented]')
}
function externalPanelInput(wo, event) {}
const panelSamples = new win.WindowObject(1, PTNVIEW_OFFSET_Y, SCRW, PTNVIEW_HEIGHT, externalPanelInput, makeExternalPanelDraw('taut_sampleedit'), undefined, ()=>{})
const panelInstrmnt = new win.WindowObject(1, PTNVIEW_OFFSET_Y, SCRW, PTNVIEW_HEIGHT, externalPanelInput, makeExternalPanelDraw('taut_instredit'), undefined, ()=>{})
const panelProject = new win.WindowObject(1, PTNVIEW_OFFSET_Y, SCRW, PTNVIEW_HEIGHT, externalPanelInput, drawProjectContents, undefined, ()=>{})
const panelFile = new win.WindowObject(1, PTNVIEW_OFFSET_Y, SCRW, PTNVIEW_HEIGHT, externalPanelInput, makeExternalPanelDraw('taut_fileop'), undefined, ()=>{})
const panels = [panelTimeline, panelOrders, panelPatterns, panelSamples, panelInstrmnt, panelProject, panelFile]
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// PLAYBACK STATE
@@ -1925,6 +1971,11 @@ function updatePlayback() {
clampCursor()
if (currentPanel === VIEW_TIMELINE) redrawPanel()
else if (currentPanel === VIEW_PATTERN_DETAILS && song.numPats > 0) { simStateKey = ''; redrawPanel() }
else if (currentPanel === VIEW_CUES) {
if (cueIdx < ordersScroll) ordersScroll = cueIdx
if (cueIdx >= ordersScroll + PTNVIEW_HEIGHT) ordersScroll = Math.max(0, cueIdx - PTNVIEW_HEIGHT + 1)
drawOrdersContents()
}
} else if (previewActive || nowCue === cueIdx) {
const oldCursor = cursorRow
const oldScroll = scrollRow
@@ -2152,7 +2203,17 @@ taud.uploadTaudFile(fullPathObj.full, 0, PLAYHEAD)
audio.setMasterVolume(PLAYHEAD, 255)
audio.setMasterPan(PLAYHEAD, 128)
function isExternalPanel(p) {
return p === VIEW_SAMPLES || p === VIEW_INSTRMNT || p === VIEW_FILE
}
// Launching a sub-program from inside an input.withEvent callback causes the triggering
// Tab event to leak into the sub-program's own withEvent call (the event hasn't been
// consumed yet when the callback is still executing). We avoid this by deferring the
// actual shell.execute until after withEvent returns.
let exitFlag = false
let pendingExternalDraw = false
while (!exitFlag) {
input.withEvent(event => {
if (event[0] !== "key_down") return
@@ -2166,28 +2227,18 @@ while (!exitFlag) {
}
if (keyJustHit && keysym === "<TAB>") {
const prevPanel = currentPanel
currentPanel = (currentPanel + (shiftDown ? -1 : 1))
if (currentPanel < 0) currentPanel += panels.length
currentPanel = currentPanel % panels.length
if (currentPanel === VIEW_PATTERN_DETAILS) {
// Entering Patterns: save mute state and ensure voice 0 (preview voice) is audible
timelineMuteSnapshot = voiceMutes.slice()
if (voiceMutes[0]) {
voiceMutes[0] = false
audio.setVoiceMute(PLAYHEAD, 0, false)
}
} else if (currentPanel === VIEW_TIMELINE && timelineMuteSnapshot !== null) {
// Returning to Timeline: restore saved mute state
for (let i = 0; i < song.numVoices; i++) {
voiceMutes[i] = timelineMuteSnapshot[i]
audio.setVoiceMute(PLAYHEAD, i, voiceMutes[i])
}
timelineMuteSnapshot = null
applyMuteTransition(currentPanel)
if (isExternalPanel(currentPanel)) {
// Redraw header now so the tab highlight is visible immediately,
// but defer the actual sub-program launch to after withEvent returns.
con.clear(); drawAlwaysOnElems(); drawControlHint()
pendingExternalDraw = true
} else {
drawAll()
}
drawAll()
return
}
@@ -2199,6 +2250,24 @@ while (!exitFlag) {
panels[currentPanel].processInput(event)
})
// Launch external sub-program OUTSIDE the withEvent callback so the triggering
// Tab event is fully consumed before the sub-program's event loop begins.
if (pendingExternalDraw) {
pendingExternalDraw = false
redrawPanel()
while (_G.taut_nextPanel !== undefined && _G.taut_nextPanel !== null) {
currentPanel = _G.taut_nextPanel
_G.taut_nextPanel = undefined
applyMuteTransition(currentPanel)
if (isExternalPanel(currentPanel)) {
con.clear(); drawAlwaysOnElems(); drawControlHint()
redrawPanel()
} else {
drawAll()
}
}
}
if (playbackMode !== PLAYMODE_NONE) updatePlayback()
}

View File

@@ -1 +1,77 @@
// filesystem navigator for Taut
/**
* TAUT File Operations
* Sub-program launched by taut.js when the File tab is active.
* Rows 1-3 are owned by the parent; this program draws rows 4+.
*
* exec_args[1] = path to .taud file
* Sets _G.taut_nextPanel before returning to request a panel switch.
*
* Created by minjaesong on 2026-04-27
*/
const win = require("wintex")
const PANEL_COUNT = 7
const MY_PANEL = 6 // VIEW_FILE
const [SCRH, SCRW] = con.getmaxyx()
const PANEL_Y = 4
const PANEL_H = SCRH - PANEL_Y
const colStatus = 253
const colContent = 240
const colHdr = 239
function drawFileOpContents(wo) {
for (let y = PANEL_Y; y < SCRH; y++) {
con.move(y, 1)
con.color_pair(colContent, 255)
print(' '.repeat(SCRW))
}
con.move(PANEL_Y + 1, 3)
con.color_pair(colHdr, 255)
print('[ File ]')
con.move(PANEL_Y + 3, 3)
con.color_pair(colStatus, 255)
print('placeholder — not yet implemented')
}
function drawHints() {
con.move(SCRH, 1)
con.color_pair(colStatus, 255)
print(' '.repeat(SCRW - 1))
con.move(SCRH, 1)
con.color_pair(colHdr, 255); print('Tab ')
con.color_pair(colStatus, 255); print('Panel')
}
function fileOpInput(wo, event) {
// placeholder — no interaction yet
}
const panel = new win.WindowObject(1, PANEL_Y, SCRW, PANEL_H, fileOpInput, drawFileOpContents, undefined, ()=>{})
panel.drawContents()
drawHints()
let done = false
while (!done) {
input.withEvent(event => {
if (event[0] !== 'key_down') return
const keysym = event[1]
const keyJustHit = (1 == event[2])
const shiftDown = (event.includes(59) || event.includes(60))
if (!keyJustHit) return
if (keysym === '<TAB>') {
_G.taut_nextPanel = (MY_PANEL + (shiftDown ? -1 : 1) + PANEL_COUNT) % PANEL_COUNT
done = true
return
}
panel.processInput(event)
})
}
return 0

View File

@@ -0,0 +1,77 @@
/**
* TAUT Instrument Editor
* Sub-program launched by taut.js when the Instrmnt tab is active.
* Rows 1-3 are owned by the parent; this program draws rows 4+.
*
* exec_args[1] = path to .taud file
* Sets _G.taut_nextPanel before returning to request a panel switch.
*
* Created by minjaesong on 2026-04-27
*/
const win = require("wintex")
const PANEL_COUNT = 7
const MY_PANEL = 4 // VIEW_INSTRMNT
const [SCRH, SCRW] = con.getmaxyx()
const PANEL_Y = 4
const PANEL_H = SCRH - PANEL_Y
const colStatus = 253
const colContent = 240
const colHdr = 239
function drawInstEditContents(wo) {
for (let y = PANEL_Y; y < SCRH; y++) {
con.move(y, 1)
con.color_pair(colContent, 255)
print(' '.repeat(SCRW))
}
con.move(PANEL_Y + 1, 3)
con.color_pair(colHdr, 255)
print('[ Instrument Editor ]')
con.move(PANEL_Y + 3, 3)
con.color_pair(colStatus, 255)
print('placeholder — not yet implemented')
}
function drawHints() {
con.move(SCRH, 1)
con.color_pair(colStatus, 255)
print(' '.repeat(SCRW - 1))
con.move(SCRH, 1)
con.color_pair(colHdr, 255); print('Tab ')
con.color_pair(colStatus, 255); print('Panel')
}
function instEditInput(wo, event) {
// placeholder — no interaction yet
}
const panel = new win.WindowObject(1, PANEL_Y, SCRW, PANEL_H, instEditInput, drawInstEditContents, undefined, ()=>{})
panel.drawContents()
drawHints()
let done = false
while (!done) {
input.withEvent(event => {
if (event[0] !== 'key_down') return
const keysym = event[1]
const keyJustHit = (1 == event[2])
const shiftDown = (event.includes(59) || event.includes(60))
if (!keyJustHit) return
if (keysym === '<TAB>') {
_G.taut_nextPanel = (MY_PANEL + (shiftDown ? -1 : 1) + PANEL_COUNT) % PANEL_COUNT
done = true
return
}
panel.processInput(event)
})
}
return 0

View File

@@ -0,0 +1,77 @@
/**
* TAUT Sample Editor
* Sub-program launched by taut.js when the Samples tab is active.
* Rows 1-3 are owned by the parent; this program draws rows 4+.
*
* exec_args[1] = path to .taud file
* Sets _G.taut_nextPanel before returning to request a panel switch.
*
* Created by minjaesong on 2026-04-27
*/
const win = require("wintex")
const PANEL_COUNT = 7
const MY_PANEL = 3 // VIEW_SAMPLES
const [SCRH, SCRW] = con.getmaxyx()
const PANEL_Y = 4
const PANEL_H = SCRH - PANEL_Y
const colStatus = 253
const colContent = 240
const colHdr = 239
function drawSampleEditContents(wo) {
for (let y = PANEL_Y; y < SCRH; y++) {
con.move(y, 1)
con.color_pair(colContent, 255)
print(' '.repeat(SCRW))
}
con.move(PANEL_Y + 1, 3)
con.color_pair(colHdr, 255)
print('[ Sample Editor ]')
con.move(PANEL_Y + 3, 3)
con.color_pair(colStatus, 255)
print('placeholder — not yet implemented')
}
function drawHints() {
con.move(SCRH, 1)
con.color_pair(colStatus, 255)
print(' '.repeat(SCRW - 1))
con.move(SCRH, 1)
con.color_pair(colHdr, 255); print('Tab ')
con.color_pair(colStatus, 255); print('Panel')
}
function sampleEditInput(wo, event) {
// placeholder — no interaction yet
}
const panel = new win.WindowObject(1, PANEL_Y, SCRW, PANEL_H, sampleEditInput, drawSampleEditContents, undefined, ()=>{})
panel.drawContents()
drawHints()
let done = false
while (!done) {
input.withEvent(event => {
if (event[0] !== 'key_down') return
const keysym = event[1]
const keyJustHit = (1 == event[2])
const shiftDown = (event.includes(59) || event.includes(60))
if (!keyJustHit) return
if (keysym === '<TAB>') {
_G.taut_nextPanel = (MY_PANEL + (shiftDown ? -1 : 1) + PANEL_COUNT) % PANEL_COUNT
done = true
return
}
panel.processInput(event)
})
}
return 0