Tenho 7 botões, CDEFGAB, uma textarea e uma Original Key.
Se eu copiar a letra de "Fly me to the moon" para a área de texto com seus acordes e pressionar o botão E uma vez, ele subirá um tom normalmente. No entanto, se eu pressionar o mesmo botão novamente, ele subirá outro tom. O que há de errado com o valor? Alguém pode me explicar? Agradeço antecipadamente.
const { transpose, Interval } = Tonal;
// Function to transpose chords in the text
function transposeChords(text, interval) {
return text.replace(/\b([A-G][#b]?)(m|min|maj|dim|dim7|aug|sus|add)?([0-9]*)\b/g, (match, root, type, number) => {
let chordType = type;
// Handle extended chords
if (number) {
chordType = chordType || '';
if (number.match(/\d+/)) {
chordType += number;
}
}
try {
const transposedRoot = transpose(root, interval);
const transposedChord = transposedRoot + (chordType || '');
return transposedChord || match;
} catch (e) {
console.error('Error transposing chord', match, e);
return match;
}
});
}
// Function to handle transpose button click
window.transpose = function(padd) {
let interval = Interval.distance(window.originalKey, padd);
let lyrics = document.getElementById("textarea").value;
document.getElementById('textarea').value = transposeChords(lyrics, interval);
colorPads(padd);
};
// Highlighted 17 Pads
function colorPads(padd) {
const buttons = document.querySelectorAll('.pads');
buttons.forEach(button => {
if (button.dataset.padd === padd) {
button.classList.add('blue');
} else {
button.classList.remove('blue');
}
});
}
// Save original key when selected from dropdown
function originalKey_function() {
const select_OrigKey = document.getElementById('originalKey_id');
window.originalKey = select_OrigKey.value;
colorPads(window.originalKey);
}
// Event listener for pads (17 buttons)
document.querySelectorAll('.pads').forEach(button => {
button.addEventListener('click', () => {
const padd = button.dataset.padd;
window.transpose(padd);
});
});
// Event listener for original key dropdown
document.getElementById('originalKey_id').addEventListener('change', originalKey_function);
// Initial setup
window.originalKey = 'C'; // Default original key
colorPads(window.originalKey);
body {
font-family: Arial, sans-serif;
background-color: #333;
color: #ccc;
text-align: center;
}
.pads_container {
position:relative;
top:2vmin;
display:flex;
width:95%;
left:1vmin;
right:1vmin;
}
button.pads {
padding: 1em;
font-size: 3vmin;
border: 1px solid #ccc;
background: green;
color: #fff;
cursor: pointer;
}
button.pads.blue {
background-color: #007bff;
color: #fff;
}
button.pads:hover {
background-color: #00a3d9;
}
#textarea {
top:3em;
position:relative;
width:100%;
background: #222;
color: #ddd;
}
<script src="https://cdn.jsdelivr.net/npm/tonal/browser/tonal.min.js"></script>
<!-- Original Key -->
<div>
<label for="originalKey_id">Original Key:</label>
<select id="originalKey_id">
<option value="C">C</option>
<option value="D">D</option>
<option value="E">E</option>
<option value="F">F</option>
<option value="G">G</option>
<option value="A">A</option>
<option value="B">B</option>
</select>
</div>
<!-- 17 buttons -->
<div class="pads_container">
<button class="pads" data-padd="C">C</button>
<button class="pads" data-padd="D">D</button>
<button class="pads" data-padd="E">E</button>
<button class="pads" data-padd="F">F</button>
<button class="pads" data-padd="G">G</button>
<button class="pads" data-padd="A">A</button>
<button class="pads" data-padd="B">B</button>
</div>
<textarea value="" id="textarea" rows="5" cols="25">
D G A D
Fly me to the moon, let me play among the stars
</textarea>
O problema é que sua lógica de transposição calcula o intervalo em relação à tonalidade original e, portanto, não leva em conta a transposição que já foi aplicada anteriormente, mas considera o texto da textarea para usar a notação na tonalidade original.
Para garantir que a notação do texto seja interpretada conforme pretendido pela transposição aplicada mais recentemente, você deve manter um registro da última transposição aplicada, por exemplo, mantendo uma variável global
currentKey
. Assim, você pode calcular o intervalo correto com referência a ela em vez deoriginalKey
:Há também outro problema não relacionado: a expressão regular exige uma quebra de palavra no final (
\b
), mas isso significa que você nunca encontrará um acorde que termine em sustenido . Por exemplo, no texto,"F# B"
as correspondências incluiriam"F"
, não"F#"
. Isso ocorre porque um símbolo de cerquilha não é um caractere de palavra e, portanto, não é seguido por uma quebra de palavra neste exemplo.Para resolver esse problema, você pode exigir que a correspondência não seja seguida por caracteres de palavras, ou seja, colocada
(?!\w)
no final da sua regex em vez de\b
.Talvez também permita múltiplos sustenidos ou bemóis, como em
"F##"
.Aqui está o código adaptado (deixei de fora algum CSS que não era relevante):