mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-23 12:44:04 +09:00
taut: note jamming on inst views
This commit is contained in:
@@ -4010,6 +4010,22 @@ HUB.markUnsaved = () => { hasUnsavedChanges = true }
|
|||||||
HUB.tickPlayback = () => { if (playbackMode !== PLAYMODE_NONE) updatePlayback() }
|
HUB.tickPlayback = () => { if (playbackMode !== PLAYMODE_NONE) updatePlayback() }
|
||||||
HUB.stopPlayback = stopPlayback
|
HUB.stopPlayback = stopPlayback
|
||||||
|
|
||||||
|
// Shared piano-jam audition for the Instruments view + Advanced Edit: if `event` is a jam
|
||||||
|
// key (a..k / w..u, no shift) and playback is stopped, audition `instSlot` at editOctave and
|
||||||
|
// return true (so the caller swallows the key). Scancode-based like the pattern-view jam.
|
||||||
|
HUB.tryJamFromEvent = function(event, instSlot) {
|
||||||
|
if (!event || event[0] !== 'key_down' || event[2] !== 1) return false
|
||||||
|
if (playbackMode !== PLAYMODE_NONE) return false
|
||||||
|
if (event.includes(59) || event.includes(60)) return false // shifted = other commands
|
||||||
|
let sc = event[3]; if (sc == 59) sc = event[4]; if (sc == 60) sc = event[5]
|
||||||
|
const semi = jamScancodeToSemitone(sc)
|
||||||
|
if (semi === null) return false
|
||||||
|
const n = semitoneToNote(semi, editOctave)
|
||||||
|
if (n !== null && (instSlot | 0) >= 1 && typeof audio.jamNote === 'function')
|
||||||
|
audio.jamNote(PLAYHEAD, 0, n, instSlot | 0)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
HUB.views = requireTaut("taut_views").init(HUB)
|
HUB.views = requireTaut("taut_views").init(HUB)
|
||||||
const {
|
const {
|
||||||
drawSamplesContents, samplesInput, drawInstrumentsContents, instrumentsInput,
|
drawSamplesContents, samplesInput, drawInstrumentsContents, instrumentsInput,
|
||||||
|
|||||||
@@ -1916,7 +1916,7 @@ function instrumentsInput(wo, event) {
|
|||||||
|
|
||||||
const n = instrumentsCache ? instrumentsCache.length : 0
|
const n = instrumentsCache ? instrumentsCache.length : 0
|
||||||
if (n === 0) {
|
if (n === 0) {
|
||||||
if (keysym === 'e' || keysym === 'E') {
|
if (keysym === '\n' || keysym === 'E') { // Enter / Shift+E opens a new instrument
|
||||||
openAdvancedInstEdit(-1)
|
openAdvancedInstEdit(-1)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@@ -1937,9 +1937,12 @@ function instrumentsInput(wo, event) {
|
|||||||
if (keysym === '4') { instSubTab = INST_TAB_PAN; drawInstrumentsContents(); return }
|
if (keysym === '4') { instSubTab = INST_TAB_PAN; drawInstrumentsContents(); return }
|
||||||
if (keysym === '5') { instSubTab = INST_TAB_PIT; drawInstrumentsContents(); return }
|
if (keysym === '5') { instSubTab = INST_TAB_PIT; drawInstrumentsContents(); return }
|
||||||
if (keysym === '6') { instSubTab = INST_TAB_FILT; drawInstrumentsContents(); return }
|
if (keysym === '6') { instSubTab = INST_TAB_FILT; drawInstrumentsContents(); return }
|
||||||
if (keysym === 'e' || keysym === 'E') {
|
// Note jamming: audition the selected instrument with the piano keys (a..k / w..u).
|
||||||
const e = instrumentsCache[instListCursor]
|
const sel = instrumentsCache[instListCursor]
|
||||||
if (e) openAdvancedInstEdit(e.slot)
|
if (HUB.tryJamFromEvent && HUB.tryJamFromEvent(event, sel ? sel.slot : 0)) return
|
||||||
|
// Open Advanced Edit: Enter or Shift+E (lowercase 'e' is the D# jam key).
|
||||||
|
if (keysym === '\n' || keysym === 'E') {
|
||||||
|
if (sel) openAdvancedInstEdit(sel.slot)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2531,7 +2534,7 @@ function editorModalLoop(onKey, onTick) {
|
|||||||
if (ev[0] !== 'key_down') return
|
if (ev[0] !== 'key_down') return
|
||||||
const ks = ev[1]
|
const ks = ev[1]
|
||||||
if (ks === '<ESC>' || ks === '<ESCAPE>' || ks === '<TAB>') { if (1 === ev[2]) finish(); return }
|
if (ks === '<ESC>' || ks === '<ESCAPE>' || ks === '<TAB>') { if (1 === ev[2]) finish(); return }
|
||||||
onKey(ks, finish, (1 === ev[2]))
|
onKey(ks, finish, (1 === ev[2]), ev)
|
||||||
})
|
})
|
||||||
if (!done && onTick) onTick() // don't overpaint the new panel after a switch
|
if (!done && onTick) onTick() // don't overpaint the new panel after a switch
|
||||||
}
|
}
|
||||||
@@ -2702,6 +2705,7 @@ function ovr(val, isDefault) { return isDefault ? '--' : ('$' + (val & 0xFF).toS
|
|||||||
// (bottom-right). Mouse-aware (patches + transport). See plan Step 2.
|
// (bottom-right). Mouse-aware (patches + transport). See plan Step 2.
|
||||||
function openAdvancedInstEdit(slot) {
|
function openAdvancedInstEdit(slot) {
|
||||||
const SLOT = (slot !== undefined && slot >= 0) ? (slot | 0) : -1
|
const SLOT = (slot !== undefined && slot >= 0) ? (slot | 0) : -1
|
||||||
|
if (typeof audio.jamStop === 'function') audio.jamStop(PLAYHEAD) // clean slate: drop any list-view jam
|
||||||
const Y = PTNVIEW_OFFSET_Y - 1 // start one row above the normal panel top (row 4), 1 row taller
|
const Y = PTNVIEW_OFFSET_Y - 1 // start one row above the normal panel top (row 4), 1 row taller
|
||||||
const cHdr = colVoiceHdr, cStatus = colStatus, cDim = colSep, cBack = 255
|
const cHdr = colVoiceHdr, cStatus = colStatus, cDim = colSep, cBack = 255
|
||||||
|
|
||||||
@@ -3108,7 +3112,10 @@ function openAdvancedInstEdit(slot) {
|
|||||||
const litVol = new Array(zones.length).fill(0) // max CURRENT eff vol per zone (brightness)
|
const litVol = new Array(zones.length).fill(0) // max CURRENT eff vol per zone (brightness)
|
||||||
const litCnt = new Array(zones.length).fill(0) // sounding-voice count per zone (heat)
|
const litCnt = new Array(zones.length).fill(0) // sounding-voice count per zone (heat)
|
||||||
for (let v = 0; v < nv; v++) {
|
for (let v = 0; v < nv; v++) {
|
||||||
if (!playing || !audio.getVoiceActive(PLAYHEAD, v) || audio.getVoiceInstrument(PLAYHEAD, v) !== SLOT) { voicePeak[v] = null; continue }
|
// During playback show only THIS instrument's voices; during a (stopped) jam
|
||||||
|
// audition show the active jam voice(s) — a meta plays its foreground layer under
|
||||||
|
// a layer instrument, not SLOT, so don't filter on SLOT while stopped.
|
||||||
|
if (!audio.getVoiceActive(PLAYHEAD, v) || (playing && audio.getVoiceInstrument(PLAYHEAD, v) !== SLOT)) { voicePeak[v] = null; continue }
|
||||||
const note = audio.getVoiceNote(PLAYHEAD, v)
|
const note = audio.getVoiceNote(PLAYHEAD, v)
|
||||||
const eff = audio.getVoiceEffectiveVolume(PLAYHEAD, v) || 0
|
const eff = audio.getVoiceEffectiveVolume(PLAYHEAD, v) || 0
|
||||||
let pk = voicePeak[v]
|
let pk = voicePeak[v]
|
||||||
@@ -3192,7 +3199,9 @@ function openAdvancedInstEdit(slot) {
|
|||||||
drawDetail(); drawEnvGraph(); drawHint()
|
drawDetail(); drawEnvGraph(); drawHint()
|
||||||
registerMouse()
|
registerMouse()
|
||||||
|
|
||||||
editorModalLoop((ks, finish, first) => {
|
editorModalLoop((ks, finish, first, ev) => {
|
||||||
|
// Note jamming: audition the instrument being edited with the piano keys (a..k / w..u).
|
||||||
|
if (SLOT >= 1 && HUB.tryJamFromEvent && HUB.tryJamFromEvent(ev, SLOT)) return
|
||||||
if (zones.length === 0) return
|
if (zones.length === 0) return
|
||||||
if (ks === '<UP>') { if (selIdx > 0) { selIdx--; redrawSel() } return }
|
if (ks === '<UP>') { if (selIdx > 0) { selIdx--; redrawSel() } return }
|
||||||
if (ks === '<DOWN>') { if (selIdx < zones.length - 1) { selIdx++; redrawSel() } return }
|
if (ks === '<DOWN>') { if (selIdx < zones.length - 1) { selIdx++; redrawSel() } return }
|
||||||
@@ -3205,6 +3214,7 @@ function openAdvancedInstEdit(slot) {
|
|||||||
if (ks === '<RIGHT>') { envKind = (envKind + 1) % ENV_TABS.length; drawEnvGraph(); liveSig = '~'; return }
|
if (ks === '<RIGHT>') { envKind = (envKind + 1) % ENV_TABS.length; drawEnvGraph(); liveSig = '~'; return }
|
||||||
}, refreshLiveVoices)
|
}, refreshLiveVoices)
|
||||||
|
|
||||||
|
if (typeof audio.jamStop === 'function') audio.jamStop(PLAYHEAD) // silence any lingering jam audition
|
||||||
clearEnvGraphics() // don't leave the graph over the restored viewer
|
clearEnvGraphics() // don't leave the graph over the restored viewer
|
||||||
refreshInstrumentsCache()
|
refreshInstrumentsCache()
|
||||||
clampInstrumentsCursor()
|
clampInstrumentsCursor()
|
||||||
|
|||||||
@@ -523,7 +523,7 @@ private class Beeper {
|
|||||||
// Arpeggio note-effects step at 60 Hz: 48000 / 60 = 800 samples per step.
|
// Arpeggio note-effects step at 60 Hz: 48000 / 60 = 800 samples per step.
|
||||||
private const val SAMPLES_PER_ARP_TICK = SAMPLE_RATE / ARPRATE
|
private const val SAMPLES_PER_ARP_TICK = SAMPLE_RATE / ARPRATE
|
||||||
private const val CHUNK = SAMPLES_PER_ARP_TICK
|
private const val CHUNK = SAMPLES_PER_ARP_TICK
|
||||||
private const val AMPLITUDE = 8192 // ~ -12 dBFS; square waves are loud
|
private const val AMPLITUDE = 16384 // ~ -6 dBFS; square waves are loud
|
||||||
}
|
}
|
||||||
|
|
||||||
// MMIO 94..99 write-staging registers:
|
// MMIO 94..99 write-staging registers:
|
||||||
|
|||||||
Reference in New Issue
Block a user