mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-11 07:14:04 +09:00
playtaud tweaks
This commit is contained in:
@@ -390,11 +390,11 @@ const NAME_RULES = [
|
|||||||
'kick','snare','hat','drum','perc','clap','cymb','tom','ride',
|
'kick','snare','hat','drum','perc','clap','cymb','tom','ride',
|
||||||
'crash','rim','clave','cowbell','shaker','tamb','conga','bongo',
|
'crash','rim','clave','cowbell','shaker','tamb','conga','bongo',
|
||||||
'snr','kik','bdrum','sdrum','kit','break','909','707','606',
|
'snr','kik','bdrum','sdrum','kit','break','909','707','606',
|
||||||
' bd',' sd',' hh',' bd1',' bd2',' sd1',' sd2'
|
' bd',' sd',' hh',' bd1',' bd2',' sd1',' sd2',' sn',' tst',' tsk'
|
||||||
]},
|
]},
|
||||||
{ arch: ARCH_METAL, words: [
|
{ arch: ARCH_METAL, words: [
|
||||||
'metal','ring mod','ringmod','noise','glass','chime','clang',
|
'metal','ring mod','ringmod','noise','glass','chime','clang',
|
||||||
'sweep','riser','blip','zap','laser','bitcrush','crush','fm '
|
'sweep','riser','blip','zap','laser','bitcrush','crush','fm ','xwav'
|
||||||
]},
|
]},
|
||||||
{ arch: ARCH_BASS, words: [
|
{ arch: ARCH_BASS, words: [
|
||||||
'bass','sub','808','b-line','bassline','b.s.'
|
'bass','sub','808','b-line','bassline','b.s.'
|
||||||
@@ -457,16 +457,7 @@ function classifyInstrument(slot) {
|
|||||||
const c4Rate = readInstU16(slot, 6)
|
const c4Rate = readInstU16(slot, 6)
|
||||||
if (sampleLen === 0) return null // empty slot
|
if (sampleLen === 0) return null // empty slot
|
||||||
|
|
||||||
// Acoustic override: an unambiguously percussive sample (short one-shot,
|
// Name-based prior first — a kick called "Kick" is a kick even if its
|
||||||
// no loop) is treated as DRUM even when the name says otherwise. Modules
|
|
||||||
// sometimes label kicks "Bass" or label individual percussion hits with
|
|
||||||
// genre tags — the acoustic shape is the more reliable signal there.
|
|
||||||
const flags = readInstByte(slot, 14)
|
|
||||||
const loopMode = flags & 0x03
|
|
||||||
const looped = (loopMode === 1 || loopMode === 2)
|
|
||||||
if (sampleLen < 4096 && !looped) return ARCH_DRUM
|
|
||||||
|
|
||||||
// Name-based prior next — a kick called "Kick" is a kick even if its
|
|
||||||
// envelope/spectrum could read as something else. Falls back to the
|
// envelope/spectrum could read as something else. Falls back to the
|
||||||
// acoustic heuristic when name has no keyword hits.
|
// acoustic heuristic when name has no keyword hits.
|
||||||
const nameHit = classifyByName(song.instNames[slot] + ' ' + song.sampleNames[slot])
|
const nameHit = classifyByName(song.instNames[slot] + ' ' + song.sampleNames[slot])
|
||||||
@@ -934,17 +925,21 @@ function drawStereo() {
|
|||||||
const bins = new Float32Array(W)
|
const bins = new Float32Array(W)
|
||||||
for (let v = 0; v < song.numVoices; v++) {
|
for (let v = 0; v < song.numVoices; v++) {
|
||||||
if (!audio.getVoiceActive(0, v)) continue
|
if (!audio.getVoiceActive(0, v)) continue
|
||||||
const vol = audio.getVoiceEffectiveVolume(0, v) || 0
|
const vol = Math.pow(audio.getVoiceEffectiveVolume(0, v) || 0, 0.125)
|
||||||
if (vol <= 0) continue
|
if (vol <= 0) continue
|
||||||
const pan = audio.getVoiceEffectivePan(0, v)
|
const pan = audio.getVoiceEffectivePan(0, v)
|
||||||
let col = Math.round((pan / 255) * (W - 1))
|
let col = Math.round((pan / 255) * (W - 1))
|
||||||
if (col < 0) col = 0
|
if (col < 0) col = 0
|
||||||
if (col >= W) col = W - 1
|
if (col >= W) col = W - 1
|
||||||
// Gaussian-ish 3-cell spread so individual voices don't read as single
|
// Gaussian-ish 7-cell spread so individual voices don't read as single
|
||||||
// spikes — the eye reads bars best with some neighbouring mass.
|
// spikes — the eye reads bars best with some neighbouring mass.
|
||||||
bins[col] += vol
|
bins[col] += vol
|
||||||
if (col > 0) bins[col - 1] += vol * 0.5
|
if (col >= 3) bins[col - 3] += vol * 0.05
|
||||||
if (col < W - 1) bins[col + 1] += vol * 0.5
|
if (col >= 2) bins[col - 2] += vol * 0.3
|
||||||
|
if (col >= 1) bins[col - 1] += vol * 0.75
|
||||||
|
if (col < W - 1) bins[col + 1] += vol * 0.75
|
||||||
|
if (col < W - 2) bins[col + 2] += vol * 0.3
|
||||||
|
if (col < W - 3) bins[col + 3] += vol * 0.05
|
||||||
}
|
}
|
||||||
const stairs = [0x20, 0xB0, 0xB1, 0xB2, 0xDB] // space ░ ▒ ▓ █
|
const stairs = [0x20, 0xB0, 0xB1, 0xB2, 0xDB] // space ░ ▒ ▓ █
|
||||||
for (let i = 0; i < W; i++) {
|
for (let i = 0; i < W; i++) {
|
||||||
@@ -1007,9 +1002,7 @@ let errorlevel = 0
|
|||||||
// clock.
|
// clock.
|
||||||
|
|
||||||
let ticksPerRow = Math.max(1, song.tickRate)
|
let ticksPerRow = Math.max(1, song.tickRate)
|
||||||
const frameIntervalMs = 33
|
let synthTick = 0 // tick within current row, 0..ticksPerRow-1
|
||||||
let synthTick = 0 // tick within current row, 0..ticksPerRow-1
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (audio.isPlaying(0) && !stopReq) {
|
while (audio.isPlaying(0) && !stopReq) {
|
||||||
// Backspace polling (mirrors playtad).
|
// Backspace polling (mirrors playtad).
|
||||||
@@ -1046,7 +1039,7 @@ try {
|
|||||||
drawStereo()
|
drawStereo()
|
||||||
drawTickLights(synthTick, ticksPerRow)
|
drawTickLights(synthTick, ticksPerRow)
|
||||||
|
|
||||||
sys.sleep(frameIntervalMs)
|
sys.sleep((2500 / audio.getBPM(0))|0) // one visual frame = one tick
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
|
|||||||
Reference in New Issue
Block a user