Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions screen.js
Original file line number Diff line number Diff line change
Expand Up @@ -13628,8 +13628,19 @@ function createNoteDetector(options = {}) {
const info = (hw && hw.getSongInfo) ? hw.getSongInfo() : null;
if (!info) return;
if (info.arrangement) currentArrangement = _ndArrangementKindFromName(info.arrangement);
if (Array.isArray(info.tuning)) tuningOffsets = info.tuning;
if (Number.isFinite(info.capo)) capo = info.capo;
// Tuning and capo of the chart as the highway shows it. A chart-
// transform provider (core #952) can re-fret the notes and change the
// tuning to match, e.g. a drop tuning shown as standard shapes;
// getSongInfo() keeps the ORIGINAL metadata, so scoring the transformed
// frets against it would expect the wrong pitch on re-fretted strings.
// Older hosts without the effective getters fall back to songInfo.
let effTuning = null, effCapo = null;
try { effTuning = (hw && typeof hw.getTuning === 'function') ? hw.getTuning() : null; } catch (_) {}
try { effCapo = (hw && typeof hw.getCapo === 'function') ? hw.getCapo() : null; } catch (_) {}
const tuning = Array.isArray(effTuning) && effTuning.length ? effTuning : info.tuning;
if (Array.isArray(tuning)) tuningOffsets = tuning;
if (Number.isFinite(effCapo)) capo = effCapo;
else if (Number.isFinite(info.capo)) capo = info.capo;

// String-count resolution, in precedence order:
// 1. hw.getStringCount() — host's authoritative count. Asked
Expand All @@ -13654,7 +13665,7 @@ function createNoteDetector(options = {}) {
if (Number.isFinite(hostStringCount)) {
currentStringCount = hostStringCount;
} else if (info.arrangement) {
const tuneLen = Array.isArray(info.tuning) ? info.tuning.length : null;
const tuneLen = Array.isArray(tuning) ? tuning.length : null;
const consistent = currentArrangement === 'bass'
? (tuneLen === 4 || tuneLen === 5)
: (tuneLen === 6 || tuneLen === 7 || tuneLen === 8);
Expand All @@ -13663,8 +13674,8 @@ function createNoteDetector(options = {}) {
} else {
currentStringCount = currentArrangement === 'bass' ? 4 : 6;
}
} else if (Array.isArray(info.tuning)) {
currentStringCount = info.tuning.length;
} else if (Array.isArray(tuning)) {
currentStringCount = tuning.length;
}
}

Expand Down
51 changes: 51 additions & 0 deletions test/chart_state_sync.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,54 @@ test('older host without getStringCount: bass with arrangement XML-padded 6-entr
'bass + tuning.length=6 (arrangement XML pad) must fall back to bass-4');
det.destroy();
});

test('a chart transform\'s effective tuning and capo win over the original song info', () => {
// A provider re-fretted a Drop D chart into D-standard shapes: the
// highway's getTuning() reports the uniform tuning the frets now match,
// while getSongInfo() keeps the original Drop D metadata.
const core = loadDetectionCore();
const det = mountDetectorWithSong(core, {
arrangement: 'Lead', tuning: [-2, 0, 0, 0, 0, 0], capo: 0, stringCount: 6,
});
core.highway.getTuning = () => [-2, -2, -2, -2, -2, -2];
core.highway.getCapo = () => 0;
det._syncChartStateFromHw();
let state = det._getChartState();
assert.deepEqual([...state.tuningOffsets], [-2, -2, -2, -2, -2, -2]);
assert.equal(state.capo, 0);

// A transform that moves the capo is honoured too.
core.highway.getCapo = () => 3;
det._syncChartStateFromHw();
state = det._getChartState();
assert.equal(state.capo, 3);
det.destroy();
});

test('older hosts without getTuning/getCapo keep using the song info', () => {
const core = loadDetectionCore();
const det = mountDetectorWithSong(core, {
arrangement: 'Lead', tuning: [-2, 0, 0, 0, 0, 0], capo: 2, stringCount: 6,
});
delete core.highway.getTuning;
delete core.highway.getCapo;
det._syncChartStateFromHw();
const state = det._getChartState();
assert.deepEqual([...state.tuningOffsets], [-2, 0, 0, 0, 0, 0]);
assert.equal(state.capo, 2);
det.destroy();
});

test('an empty or throwing effective tuning falls back to the song info', () => {
const core = loadDetectionCore();
const det = mountDetectorWithSong(core, {
arrangement: 'Bass', tuning: [-1, -1, -1, -1], capo: 0, stringCount: 4,
});
core.highway.getTuning = () => [];
core.highway.getCapo = () => { throw new Error('boom'); };
det._syncChartStateFromHw();
const state = det._getChartState();
assert.deepEqual([...state.tuningOffsets], [-1, -1, -1, -1]);
assert.equal(state.capo, 0);
det.destroy();
});