Skip to content

Instantly share code, notes, and snippets.

@sgqy
Created July 13, 2025 20:18
Show Gist options
  • Select an option

  • Save sgqy/a5cb9d7b66f1665ef9032297bf4f0691 to your computer and use it in GitHub Desktop.

Select an option

Save sgqy/a5cb9d7b66f1665ef9032297bf4f0691 to your computer and use it in GitHub Desktop.
<!-- AIGC: Generated by Gemini -->
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>音符计算练习</title>
<!-- A4 双页打印,每页上下布局,行高调整,sci行浅蓝背景;自动生成Helmholtz题目与完整答案 -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<!-- 更新:引入 EB Garamond (正文) 和 Noto Music (音乐符号) 字体 -->
<link href="https://fonts.googleapis.com/css2?family=EB+Garamond:wght@500;700&family=Noto+Music&display=swap" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<style>
@page { size: A4 portrait; margin: 1cm; }
html, body { margin: 0; padding: 0; height: 100%;}
body { font-family: 'EB Garamond', serif; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.page { display: flex; flex-direction: column; height: 100%; page-break-after: always; }
.half { flex: 1; display: flex; align-items: center; justify-content: center; }
table { width: 90%; border-collapse: collapse; table-layout: fixed; }
th, td {
border: 1px solid #000;
text-align: center;
font-size: 10pt;
width: 20%;
height: 11mm;
line-height: 1.2;
padding: 1px;
vertical-align: middle;
word-break: break-all;
}
/* 浅色表头背景 */
thead th:nth-child(1) { background: #f8d7da; }
thead th:nth-child(2) { background: #fff3cd; }
thead th:nth-child(3) { background: #e2e3e5; }
thead th:nth-child(4) { background: #d4edda; }
thead th:nth-child(5) { background: #d1ecf1; }
/* sci 行背景 */
tbody tr[id^="sci-"] td { background: #eaf4ff; }
.q-note {
text-align: left;
font-size: 14pt;
padding-left: 8px;
font-weight: bold;
}
.music-symbol {
font-family: 'Noto Music', serif;
font-size: 1.2em;
vertical-align: middle;
}
/* 更新:添加仅屏幕显示的样式 */
.screen-only {
padding: 10px 20px;
background-color: #f0f8ff;
border-bottom: 1px solid #ddd;
margin-bottom: 10px;
}
.screen-only h2 {
margin: 0 0 10px 0;
}
.screen-only p {
margin: 5px 0;
}
/* 更新:添加打印样式,隐藏屏幕专属区域 */
@media print {
.screen-only {
display: none;
}
.page {
height: 100%; /* 打印时确保页面高度正确 */
}
}
</style>
<script>
$(function() {
// --- 音乐理论核心数据 ---
const perTable = 5;
const NOTE_MIDI_OFFSETS = { 'C': 0, 'D': 2, 'E': 4, 'F': 5, 'G': 7, 'A': 9, 'B': 11 };
const MIDI_NOTE_NAMES = {
0: [{ l: 'C', a: '' }, { l: 'B', a: '#' }, { l: 'D', a: 'bb' }],
1: [{ l: 'C', a: '#' }, { l: 'D', a: 'b' }],
2: [{ l: 'D', a: '' }, { l: 'C', a: 'x' }, { l: 'E', a: 'bb' }],
3: [{ l: 'D', a: '#' }, { l: 'E', a: 'b' }],
4: [{ l: 'E', a: '' }, { l: 'F', a: 'b' }, { l: 'D', a: 'x' }],
5: [{ l: 'F', a: '' }, { l: 'E', a: '#' }],
6: [{ l: 'F', a: '#' }, { l: 'G', a: 'b' }],
7: [{ l: 'G', a: '' }, { l: 'F', a: 'x' }, { l: 'A', a: 'bb' }],
8: [{ l: 'G', a: '#' }, { l: 'A', a: 'b' }],
9: [{ l: 'A', a: '' }, { l: 'G', a: 'x' }, { l: 'B', a: 'bb' }],
10: [{ l: 'A', a: '#' }, { l: 'B', a: 'b' }],
11: [{ l: 'B', a: '' }, { l: 'C', a: 'b' }, { l: 'A', a: 'x' }]
};
const ACCIDENTAL_SYMBOLS = { 'bb': '\u{1D12B}', 'b': '\u266D', '': '', '#': '\u266F', 'x': '\u{1D12A}' };
const ACCIDENTAL_MODIFIERS = { 'bb': -2, 'b': -1, '': 0, '#': 1, 'x': 2 };
const COLUMN_ACCIDENTALS = ['bb', 'b', '', '#', 'x'];
// --- 核心转换与生成函数 ---
function wrapSymbol(symbol) {
if (!symbol) return '';
return `<span class="music-symbol">${symbol}</span>`;
}
function scientificToHelmholtz(letter, octave) {
if (octave >= 3) {
const sup = octave - 3;
return letter.toLowerCase() + (sup > 0 ? `<sup>${sup}</sup>` : '');
} else {
const sub = 2 - octave;
return letter.toUpperCase() + (sub > 0 ? `<sub>${sub}</sub>` : '');
}
}
function midiToAllNotations(midi) {
if (midi < 12 || midi > 108) return { sci: ['N/A'], helm: ['N/A'] };
const octave = Math.floor(midi / 12) - 1;
const noteIndex = midi % 12;
const possibleNotes = MIDI_NOTE_NAMES[noteIndex] || [];
const notations = { sci: [], helm: [] };
possibleNotes.forEach(note => {
const accSymbol = ACCIDENTAL_SYMBOLS[note.a] || '';
notations.sci.push(wrapSymbol(accSymbol) + note.l + octave);
const helmBase = scientificToHelmholtz(note.l, octave);
notations.helm.push(wrapSymbol(accSymbol) + helmBase);
});
return notations;
}
function parseHelmholtz(helmNoteHtml) {
const textOnly = $('<div>').html(helmNoteHtml).text();
let notePart = textOnly;
let initialModifier = 0;
const orderedAccKeys = ['bb', 'x', 'b', '#'];
for (const key of orderedAccKeys) {
const symbol = ACCIDENTAL_SYMBOLS[key];
if (textOnly.startsWith(symbol)) {
initialModifier = ACCIDENTAL_MODIFIERS[key];
notePart = textOnly.substring(symbol.length);
break;
}
}
const letter = notePart.match(/[A-Ga-g]/)[0];
const supMatch = helmNoteHtml.match(/<sup>(\d+)<\/sup>/);
const subMatch = helmNoteHtml.match(/<sub>(\d+)<\/sub>/);
let octave;
if (letter === letter.toLowerCase()) {
octave = 3 + (supMatch ? parseInt(supMatch[1]) : 0);
} else {
octave = 2 - (subMatch ? parseInt(subMatch[1]) : 0);
}
const baseMidi = 12 * (octave + 1) + NOTE_MIDI_OFFSETS[letter.toUpperCase()];
return baseMidi + initialModifier;
}
function genAlteredHelmholtz(generated) {
let note;
const letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
const initialAccidentals = ['bb', 'b', '', '#', 'x'];
do {
const useLower = Math.random() > 0.3;
const letter = letters[Math.floor(Math.random() * letters.length)];
let octave, helmBase;
if (useLower) {
octave = Math.floor(Math.random() * 3) + 3;
} else {
octave = Math.floor(Math.random() * 3);
}
helmBase = scientificToHelmholtz(letter, octave);
const accKey = initialAccidentals[Math.floor(Math.random() * initialAccidentals.length)];
const accSymbol = ACCIDENTAL_SYMBOLS[accKey];
note = wrapSymbol(accSymbol) + helmBase;
} while (generated.has(note));
generated.add(note);
return note;
}
// --- 主执行逻辑 ---
$('th').each(function() {
const text = $(this).text();
if (text) {
$(this).html(wrapSymbol(text));
}
});
const generatedQuestions = new Set();
for (let i = 0; i < perTable * 2; i++) {
const tableId = i < perTable ? 1 : 2;
const rowIndex = (i % perTable) + 1;
const baseHelmholtzQ = genAlteredHelmholtz(generatedQuestions);
const baseMidi = parseHelmholtz(baseHelmholtzQ);
$(`#q-table-${tableId} #hel-${rowIndex} td:nth-child(3)`).addClass('q-note').html(baseHelmholtzQ);
COLUMN_ACCIDENTALS.forEach((colAccKey, colIndex) => {
const columnModifier = ACCIDENTAL_MODIFIERS[colAccKey];
const targetMidi = baseMidi + columnModifier;
const allNotations = midiToAllNotations(targetMidi);
const column = colIndex + 1;
$(`#a-table-${tableId} #hel-${rowIndex} td:nth-child(${column})`).html(allNotations.helm.join(' / '));
$(`#a-table-${tableId} #sci-${rowIndex} td:nth-child(${column})`).html(allNotations.sci.join(' / '));
});
}
});
</script>
</head>
<body>
<!-- 更新:添加仅屏幕显示的说明区域 -->
<div class="screen-only">
<h2>音符计算练习</h2>
<p>在每个格子里填写等音的所有符号。第一行使用大字小字记法,第二行使用科学记法。</p>
<p>使用浏览器的打印功能(Ctrl+P)双面打印在纸上使用,不要截图后打印。</p>
</div>
<!-- 第1页 -->
<div class="page">
<!-- 习题 -->
<div class="half">
<table id="q-table-1">
<thead>
<tr><th>&#x1D12B;</th><th>&#x266D;</th><th>&#x266E;</th><th>&#x266F;</th><th>&#x1D12A;</th></tr>
</thead>
<tbody>
<tr id="hel-1"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="sci-1"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="hel-2"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="sci-2"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="hel-3"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="sci-3"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="hel-4"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="sci-4"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="hel-5"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="sci-5"><td></td><td></td><td></td><td></td><td></td></tr>
</tbody>
</table>
</div>
<!-- 答案 -->
<div class="half">
<table id="a-table-1">
<thead>
<tr><th>&#x1D12B;</th><th>&#x266D;</th><th>&#x266E;</th><th>&#x266F;</th><th>&#x1D12A;</th></tr>
</thead>
<tbody>
<tr id="hel-1"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="sci-1"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="hel-2"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="sci-2"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="hel-3"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="sci-3"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="hel-4"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="sci-4"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="hel-5"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="sci-5"><td></td><td></td><td></td><td></td><td></td></tr>
</tbody>
</table>
</div>
</div>
<!-- 第2页 -->
<div class="page">
<!-- 习题 -->
<div class="half">
<table id="q-table-2">
<thead>
<tr><th>&#x1D12B;</th><th>&#x266D;</th><th>&#x266E;</th><th>&#x266F;</th><th>&#x1D12A;</th></tr>
</thead>
<tbody>
<tr id="hel-1"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="sci-1"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="hel-2"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="sci-2"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="hel-3"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="sci-3"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="hel-4"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="sci-4"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="hel-5"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="sci-5"><td></td><td></td><td></td><td></td><td></td></tr>
</tbody>
</table>
</div>
<!-- 答案 -->
<div class="half">
<table id="a-table-2">
<thead>
<tr><th>&#x1D12B;</th><th>&#x266D;</th><th>&#x266E;</th><th>&#x266F;</th><th>&#x1D12A;</th></tr>
</thead>
<tbody>
<tr id="hel-1"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="sci-1"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="hel-2"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="sci-2"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="hel-3"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="sci-3"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="hel-4"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="sci-4"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="hel-5"><td></td><td></td><td></td><td></td><td></td></tr>
<tr id="sci-5"><td></td><td></td><td></td><td></td><td></td></tr>
</tbody>
</table>
</div>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment