7天从乐理小白到代码大神:Teoria.js音乐理论编程全指南
【免费下载链接】teoria Javascript taught Music Theory 项目地址: https://gitcode.com/gh_mirrors/te/teoria
你还在为音乐理论与代码实现之间的鸿沟而苦恼吗?想让你的Web应用具备专业级音乐计算能力却不知从何下手?本文将带你从零掌握Teoria.js——这款轻量级却功能强大的JavaScript音乐理论库,7天内让你能够轻松实现音符计算、和弦构建、音阶生成等专业音乐功能。
读完本文你将获得:
- 精通Teoria.js核心API的使用方法
- 掌握音乐理论在代码中的实际应用
- 学会构建和弦生成器、音阶分析器等实用音乐工具
- 能够将音乐理论无缝集成到Web应用中
- 获取10+个可直接复用的音乐编程代码模块
项目介绍:Teoria.js是什么?
Teoria.js是一个轻量级、高性能的JavaScript音乐理论库,同时支持爵士乐和古典音乐理论。它提供了直观的编程接口,使开发者能够轻松地在应用中实现复杂的音乐理论功能,如乐谱阅读器、音乐创作工具、MIDI播放器等。
该项目采用MIT许可证开源,代码托管于https://gitcode.com/gh_mirrors/te/teoria,目前已成为Web音乐应用开发的重要工具之一。
核心功能概览
Teoria.js提供了四大核心对象,覆盖了音乐理论的主要方面:
安装与环境配置
Teoria.js支持Node.js和浏览器环境,安装方式简单直观:
NPM安装(推荐)
npm install teoria
浏览器直接引入
<script src="path/to/teoria.js"></script>
第一天:音符(Note)——音乐的基本单位
音符是音乐的基本构建块,Teoria.js的Note对象提供了全面的音符操作功能。让我们从最基础的音符创建开始:
创建音符的四种方式
Teoria.js支持多种音符表示法,满足不同场景需求:
// 1. 科学记谱法 (推荐)
const a4 = teoria.note('a4'); // A4 (标准音高,440Hz)
const eb3 = teoria.note('Eb3'); // 降E3
// 2. 赫尔姆霍茨记谱法
const c5 = teoria.note("c''"); // C5 (两个上标表示高两个八度)
const f2 = teoria.note("F,,"); // F2 (两个下标表示低两个八度)
// 3. 钢琴键编号 (A0为1)
const midi60 = teoria.note.fromKey(49); // 中央C (MIDI编号60)
// 4. 频率创建
const freqNote = teoria.note.fromFrequency(440); // {note: A4, cents: 0}
音符属性与方法
每个Note对象都提供了丰富的属性和方法,用于获取和转换音符信息:
const c4 = teoria.note('C4'); // 中央C
console.log(c4.name()); // "c" - 音符名称
console.log(c4.octave()); // 4 - 八度编号
console.log(c4.accidental()); // "" - 临时记号(升#/降b等)
console.log(c4.accidentalValue()); // 0 - 临时记号数值表示
console.log(c4.key()); // 60 - 钢琴键编号
console.log(c4.midi()); // 60 - MIDI编号
console.log(c4.fq()); // 261.6255653005986 - 频率(Hz)
console.log(c4.chroma()); // 0 - 音高等级(0-11,C为0)
// 记谱法转换
console.log(c4.scientific()); // "C4" - 科学记谱法
console.log(c4.helmholtz()); // "c'" - 赫尔姆霍茨记谱法
音符转换与计算
音符间的转换是音乐计算的基础,Note对象提供了便捷的转换方法:
const a4 = teoria.note('a4');
// 音程转换
const c5 = a4.interval('m3'); // A4上方小三度是C5
console.log(c5.scientific()); // "C5"
// 转位
const enharmonics = a4.enharmonics(); // 获取等音
console.log(enharmonics.map(n => n.scientific())); // ["G##4", "Bbb5"]
// 频率计算
const freq = a4.fq(); // 440Hz
const highA = teoria.note('a5');
console.log(highA.fq()); // 880Hz (正好是A4的两倍)
实战:音符频率计算器
结合上述知识,我们可以快速实现一个音符频率计算器:
<input type="text" id="noteInput" placeholder="输入音符如C4、Bb3">
<button onclick="calculateFrequency()">计算频率</button>
<div id="result"></div>
<script src="path/to/teoria.js"></script>
<script>
function calculateFrequency() {
const noteName = document.getElementById('noteInput').value;
try {
const note = teoria.note(noteName);
const frequency = note.fq().toFixed(2);
const midiNumber = note.midi();
const pianoKey = note.key();
document.getElementById('result').innerHTML = `
<p>音符: ${note.scientific()}</p>
<p>频率: ${frequency} Hz</p>
<p>MIDI编号: ${midiNumber}</p>
<p>钢琴键位: ${pianoKey}</p>
`;
} catch (e) {
document.getElementById('result').textContent = '无效的音符输入';
}
}
</script>
第二天:音程(Interval)——音符间的距离
音程是音乐中两个音符之间的距离,是构建和弦和音阶的基础。Teoria.js的Interval对象提供了全面的音程计算功能。
音程的表示与创建
音程由性质和度数组成,Teoria.js支持多种音程表示方法:
// 从字符串创建音程
const majorThird = teoria.interval('M3'); // 大三度
const perfectFifth = teoria.interval('P5'); // 纯五度
const minorSeventh = teoria.interval('m7'); // 小七度
// 两个音符之间的音程
const fromNote = teoria.note('C4');
const toNote = teoria.note('E4');
const interval = teoria.interval(fromNote, toNote); // 计算C4到E4的音程
console.log(interval.toString()); // "M3" (大三度)
// 从音程创建音符
const c4 = teoria.note('C4');
const e4 = c4.interval('M3'); // C4上方大三度是E4
音程属性与计算
Interval对象提供了丰富的属性和方法,用于音程分析和转换:
const interval = teoria.interval('m3'); // 小三度
console.log(interval.toString()); // "m3" - 音程字符串表示
console.log(interval.number()); // 3 - 音程度数
console.log(interval.quality()); // "minor" - 音程性质
console.log(interval.semitones()); // 3 - 半音数量
console.log(interval.direction()); // "up" - 方向(上行)
// 音程转位
const inverted = interval.invert();
console.log(inverted.toString()); // "M6" (小三度转位为大六度)
// 音程比较
const m3 = teoria.interval('m3');
const M3 = teoria.interval('M3');
console.log(m3.smaller(M3)); // true (小三度比大三度小)
音程的数学计算
音程可以进行加减运算,这在复杂音乐理论计算中非常有用:
const m3 = teoria.interval('m3'); // 小三度(3半音)
const P4 = teoria.interval('P4'); // 纯四度(5半音)
// 音程相加
const sum = m3.add(P4);
console.log(sum.toString()); // "m6" (小三度+纯四度=小六度)
console.log(sum.semitones()); // 8 (3+5=8半音)
// 音程比较
console.log(m3.equal(teoria.interval('m3'))); // true
console.log(m3.greater(P4)); // false
实战:音程计算器
下面实现一个功能完整的音程计算器,支持音程识别和构建:
<div>
<label>音符1: </label>
<input type="text" id="note1" value="C4">
<label>音符2: </label>
<input type="text" id="note2" value="E4">
<button onclick="calculateInterval()">计算音程</button>
</div>
<div>
<label>根音: </label>
<input type="text" id="rootNote" value="C4">
<label>音程: </label>
<select id="intervalSelect">
<option value="M3">大三度(M3)</option>
<option value="m3">小三度(m3)</option>
<option value="P5">纯五度(P5)</option>
<option value="M7">大七度(M7)</option>
</select>
<button onclick="buildNoteFromInterval()">构建音符</button>
</div>
<div id="result"></div>
<script src="path/to/teoria.js"></script>
<script>
function calculateInterval() {
try {
const note1 = teoria.note(document.getElementById('note1').value);
const note2 = teoria.note(document.getElementById('note2').value);
const interval = teoria.interval(note1, note2);
document.getElementById('result').innerHTML += `
<p>音程: ${interval.toString()} (${interval.quality()} ${interval.number()})</p>
<p>半音数: ${interval.semitones()}</p>
<p>转位音程: ${interval.invert().toString()}</p>
`;
} catch (e) {
alert('无效的音符输入');
}
}
function buildNoteFromInterval() {
try {
const root = teoria.note(document.getElementById('rootNote').value);
const interval = document.getElementById('intervalSelect').value;
const targetNote = root.interval(interval);
document.getElementById('result').innerHTML += `
<p>${root.scientific()} + ${interval} = ${targetNote.scientific()}</p>
`;
} catch (e) {
alert('无效的输入');
}
}
</script>
第三天:和弦(Chord)——和谐的音符组合
和弦是音乐的和声基础,Teoria.js的Chord对象提供了强大的和弦构建与分析能力,支持从简单三和弦到复杂爵士和弦的全面功能。
和弦的创建方法
Teoria.js支持多种和弦创建方式,满足不同使用场景:
// 1. 从音符和和弦类型创建
const cMajor = teoria.note('C4').chord(); // C大三和弦(默认)
const cMinor = teoria.note('C4').chord('m'); // C小三和弦
const c7 = teoria.note('C4').chord('7'); // C属七和弦
const cmaj7 = teoria.note('C4').chord('maj7'); // C大七和弦
// 2. 从和弦名称直接创建
const gMinor7 = teoria.chord('Gm7'); // Gm7和弦
const abDominant9 = teoria.chord('Ab9'); // Ab9和弦
const fSharp11 = teoria.chord('F#11'); // F#11和弦
// 3. 复杂爵士和弦
const advancedChord = teoria.chord('C#m9b5'); // C#m9b5和弦
const jazzChord = teoria.chord('Bb#11b9'); // 高级爵士和弦
和弦属性与方法
Chord对象提供了全面的和弦分析功能:
const cmaj7 = teoria.chord('Cmaj7'); // C大七和弦
// 获取和弦音符
const notes = cmaj7.notes();
console.log(notes.map(n => n.scientific())); // ["C4", "E4", "G4", "B4"]
// 简化表示
console.log(cmaj7.simple()); // ["c", "e", "g", "b"]
// 和弦属性
console.log(cmaj7.name); // "Cmaj7" - 和弦名称
console.log(cmaj7.root.name()); // "c" - 根音
console.log(cmaj7.quality()); // "major" - 和弦性质
console.log(cmaj7.chordType()); // "tetrad" - 和弦类型(四音和弦)
// 和弦转位
const firstInversion = cmaj7.voicing(['M3', 'P5', 'M7', 'P1']);
console.log(firstInversion.notes().map(n => n.scientific()));
// ["E4", "G4", "B4", "C5"] (第一转位,E为低音)
和弦进行与和声分析
Teoria.js可以轻松实现和弦进行和和声分析,是音乐理论教学和实践的强大工具:
// 创建和弦进行
const progression = [
teoria.chord('C'), // C大三和弦
teoria.chord('Am'), // A小三和弦
teoria.chord('F'), // F大三和弦
teoria.chord('G7') // G属七和弦
];
// 分析和弦进行
progression.forEach((chord, i) => {
console.log(`和弦 ${i+1}: ${chord.name}`);
console.log(` 性质: ${chord.quality()}`);
console.log(` 类型: ${chord.chordType()}`);
console.log(` 音符: ${chord.simple().join(', ')}`);
});
// 和弦关系
const cMajor = teoria.chord('C');
console.log(cMajor.dominant().name); // "G" (C的属和弦是G)
console.log(cMajor.subdominant().name); // "F" (C的下属和弦是F)
console.log(cMajor.parallel().name); // "Cm" (C的平行小调是Cm)
实战:和弦可视化工具
下面实现一个和弦可视化工具,可以显示和弦组成音及钢琴键盘位置:
<div>
<input type="text" id="chordInput" value="Cmaj7">
<button onclick="visualizeChord()">可视化和弦</button>
</div>
<div id="chordNotes"></div>
<div id="pianoKeyboard" style="display: flex; margin-top: 20px;"></div>
<script src="path/to/teoria.js"></script>
<script>
function visualizeChord() {
try {
const chordName = document.getElementById('chordInput').value;
const chord = teoria.chord(chordName);
const notes = chord.notes();
// 显示和弦音符
document.getElementById('chordNotes').innerHTML = `
<h3>${chordName} 组成音</h3>
<p>${notes.map(n => `${n.scientific()} (${n.fq().toFixed(1)}Hz)`).join(', ')}</p>
<p>和弦性质: ${chord.quality()}, 类型: ${chord.chordType()}</p>
`;
// 生成钢琴键盘
generatePianoKeyboard(notes);
} catch (e) {
alert('无效的和弦输入');
}
}
function generatePianoKeyboard(highlightNotes) {
const keyboard = document.getElementById('pianoKeyboard');
keyboard.innerHTML = '';
// 生成从C4到B5的钢琴键盘
const startNote = teoria.note('C4');
const highlightKeys = new Set(highlightNotes.map(n => n.key()));
for (let i = 0; i < 24; i++) {
const note = startNote.interval(teoria.interval(i + 'm2'));
const key = note.key();
const isBlack = ['c#', 'd#', 'f#', 'g#', 'a#'].includes(note.toString(true));
const keyDiv = document.createElement('div');
keyDiv.style.width = isBlack ? '30px' : '50px';
keyDiv.style.height = isBlack ? '100px' : '200px';
keyDiv.style.backgroundColor = highlightKeys.has(key) ?
(isBlack ? '#666' : '#ffaaaa') : (isBlack ? '#000' : '#fff');
keyDiv.style.border = '1px solid #333';
keyDiv.style.position = isBlack ? 'absolute' : 'relative';
keyDiv.style.marginLeft = isBlack ? '-15px' : '0';
keyDiv.title = note.scientific();
keyboard.appendChild(keyDiv);
}
}
</script>
第四天:音阶(Scale)——音乐的调色板
音阶是音乐的基础框架,Teoria.js的Scale对象提供了全面的音阶生成和分析功能,支持从简单的大调音阶到复杂的爵士音阶。
音阶的创建与表示
Teoria.js内置了多种常见音阶,同时支持自定义音阶:
// 1. 从根音和音阶名称创建
const cMajor = teoria.note('C4').scale('major'); // C大调音阶
const aMinor = teoria.note('A4').scale('minor'); // A小调音阶
const cMajorPentatonic = teoria.note('C4').scale('majorpentatonic'); // C大调五声音阶
// 2. 获取所有已知音阶
console.log(teoria.Scale.KNOWN_SCALES);
// 输出所有支持的音阶名称
// 3. 七声音阶(调式)
const modes = [
'ionian', 'dorian', 'phrygian', 'lydian',
'mixolydian', 'aeolian', 'locrian'
];
modes.forEach(mode => {
const scale = teoria.note('C4').scale(mode);
console.log(`${mode}: ${scale.simple().join(', ')}`);
});
// 4. 自定义音阶
const customScale = new teoria.Scale(teoria.note('C4'), ['P1', 'M2', 'm3', 'A4', 'P5']);
音阶属性与方法
Scale对象提供了丰富的属性和方法,用于音阶分析和转换:
const cMajor = teoria.note('C4').scale('major');
// 音阶基本信息
console.log(cMajor.name); // "ionian" - 音阶名称(大调即伊奥尼亚调式)
console.log(cMajor.tonic.scientific()); // "C4" - 主音
console.log(cMajor.type()); // "heptatonic" - 音阶类型(七声音阶)
// 获取音阶音符
const notes = cMajor.notes();
console.log(notes.map(n => n.scientific()));
// ["C4", "D4", "E4", "F4", "G4", "A4", "B4"]
// 简化表示
console.log(cMajor.simple()); // ["c", "d", "e", "f", "g", "a", "b"]
// 获取特定度数的音
console.log(cMajor.get(1).scientific()); // "C4" - 第一音(主音)
console.log(cMajor.get('third').scientific()); // "E4" - 第三音(三音)
console.log(cMajor.get('seventh').scientific()); // "B4" - 第七音(七音)
音阶转调与模态转换
音阶可以轻松转调和转换为不同调式,这在音乐创作和分析中非常有用:
// 原始音阶
const cMajor = teoria.note('C4').scale('major');
console.log(cMajor.simple()); // ["c", "d", "e", "f", "g", "a", "b"]
// 转调 - 移高大二度
const dMajor = cMajor.interval('M2');
console.log(dMajor.simple()); // ["d", "e", "f#", "g", "a", "b", "c#"]
// 调式转换 - 同主音不同调式
const cDorian = teoria.note('C4').scale('dorian');
console.log(cDorian.simple()); // ["c", "d", "eb", "f", "g", "a", "bb"]
// 关系大小调
const aMinor = cMajor.interval('m3'); // C大调的关系小调是A小调
console.log(aMinor.simple()); // ["a", "b", "c", "d", "e", "f", "g"]
实战:音阶训练工具
下面实现一个音阶训练工具,帮助音乐学习者熟悉各种音阶:
<div>
<select id="rootNote">
<option value="C">C</option>
<option value="D">D</option>
<option value="E">E</option>
<!-- 其他音符选项 -->
</select>
<select id="scaleType">
<option value="major">大调</option>
<option value="minor">小调</option>
<option value="majorpentatonic">大调五声音阶</option>
<option value="minorpentatonic">小调五声音阶</option>
<option value="dorian">多里安调式</option>
<!-- 其他音阶选项 -->
</select>
<button onclick="generateScale()">生成音阶</button>
</div>
<div id="scaleDisplay"></div>
<div id="earTraining"></div>
<script src="path/to/teoria.js"></script>
<script>
function generateScale() {
const root = document.getElementById('rootNote').value;
const scaleType = document.getElementById('scaleType').value;
try {
const scale = teoria.note(root + '4').scale(scaleType);
const notes = scale.notes();
// 显示音阶
let scaleHtml = `<h3>${root} ${getScaleName(scaleType)}音阶</h3>`;
scaleHtml += '<div style="display: flex; gap: 10px; margin: 20px 0;">';
notes.forEach((note, index) => {
scaleHtml += `
<div style="text-align: center;">
<div style="width: 50px; height: 50px; border: 1px solid #333;
display: flex; align-items: center; justify-content: center;
background: ${index === 0 ? '#ffd700' : '#fff'}">
${note.scientific()}
</div>
<div>${index + 1}度</div>
</div>
`;
});
scaleHtml += '</div>';
scaleHtml += `<p>音程结构: ${scale.scale.join(', ')}</p>`;
scaleHtml += `<p>音阶类型: ${scale.type()}</p>`;
document.getElementById('scaleDisplay').innerHTML = scaleHtml;
// 生成听力训练
generateEarTraining(scale);
} catch (e) {
alert('无法生成音阶: ' + e.message);
}
}
function getScaleName(scaleType) {
const names = {
'major': '大调',
'minor': '小调',
'majorpentatonic': '大调五声音阶',
'minorpentatonic': '小调五声音阶',
'dorian': '多里安调式',
// 其他音阶名称映射
};
return names[scaleType] || scaleType;
}
function generateEarTraining(scale) {
// 简单的听力训练生成逻辑
const degrees = ['第一', '第二', '第三', '第四', '第五', '第六', '第七'];
const randomDegree = Math.floor(Math.random() * scale.notes().length);
document.getElementById('earTraining').innerHTML = `
<h4>听力训练</h4>
<p>问题: 音阶中的${degrees[randomDegree]}音是什么?</p>
<button onclick="showAnswer(${randomDegree}, '${scale.tonic.scientific()}', '${scale.name}')">
显示答案
</button>
<div id="answer"></div>
`;
}
function showAnswer(degree, tonic, scaleName) {
const scale = teoria.note(tonic).scale(scaleName);
const note = scale.get(degree + 1);
document.getElementById('answer').textContent =
`答案: ${note.scientific()} (${note.name().toUpperCase()}${note.accidental()})`;
}
</script>
第五天:高级应用——Teoria.js实战技巧
掌握了Teoria.js的基本功能后,让我们探索一些高级应用技巧,将音乐理论与编程更紧密地结合起来。
音乐理论与数学的结合
音乐本质上是数学的一种表现形式,Teoria.js可以帮助我们揭示音乐中的数学规律:
// 计算十二平均律的频率比
function calculateTemperamentRatios() {
const ratios = [];
for (let i = 0; i < 12; i++) {
// 十二平均律: 频率比 = 2^(i/12)
const ratio = Math.pow(2, i / 12);
ratios.push({
semitone: i,
ratio: ratio.toFixed(4),
interval: teoria.interval(teoria.note('C4'), teoria.note('C4').interval(`${i}m2`)).toString()
});
}
return ratios;
}
// 显示频率比表格
console.table(calculateTemperamentRatios());
// 计算和弦的和谐度(基于泛音列相似度)
function chordConsonance(chord) {
const notes = chord.notes();
const rootFreq = notes[0].fq();
let consonance = 0;
// 基于泛音列计算和谐度
notes.forEach(note => {
const ratio = note.fq() / rootFreq;
// 简化的和谐度计算: 接近简单整数比的音程更和谐
const simplified = simplifyRatio(ratio);
consonance += 1 / (simplified.numerator + simplified.denominator);
});
return consonance / notes.length; // 平均和谐度
}
// 简化频率比为最简分数
function simplifyRatio(ratio) {
// 实现简化分数的逻辑
// ...
}
即兴演奏辅助系统
Teoria.js可以构建强大的即兴演奏辅助系统,帮助音乐家在演奏时做出更好的和声选择:
// 构建即兴演奏辅助系统
class ImprovisationAssistant {
constructor(key, style = 'jazz') {
this.key = key; // 调式中心
this.style = style; // 音乐风格
this.chordProgressions = this.loadProgressions();
}
// 加载常见和弦进行
loadProgressions() {
return {
jazz: [
'ii-V-I', 'I-vi-ii-V', 'blues', 'rhythm changes'
],
pop: [
'I-V-vi-IV', 'I-IV-V', 'vi-IV-I-V', 'I-vi-iv-V'
]
// 其他风格...
};
}
// 生成和弦进行
generateProgression(type, length = 4) {
if (type === 'ii-V-I') {
const ii = this.key.interval('m2').scale('dorian').chord('m7');
const V = this.key.interval('P5').scale('mixolydian').chord('7');
const I = this.key.scale('major').chord('maj7');
return [ii, V, I];
}
// 实现其他和弦进行...
}
// 获取和弦的可用音阶
getChordScales(chord) {
const quality = chord.quality();
const root = chord.root;
switch(quality) {
case 'major':
return [root.scale('ionian'), root.scale('lydian')];
case 'minor':
return [root.scale('aeolian'), root.scale('dorian'), root.scale('phrygian')];
case 'dominant':
return [root.scale('mixolydian'), root.scale('altered')];
// 其他和弦类型...
}
}
// 推荐即兴音符
suggestNotes(chord, position = 'upbeat') {
const scales = this.getChordScales(chord);
const chordTones = chord.notes().map(n => n.chroma());
const availableNotes = [];
// 收集可用音符
scales.forEach(scale => {
scale.notes().forEach(note => {
if (!availableNotes.some(n => n.chroma() === note.chroma())) {
availableNotes.push({
note: note,
isChordTone: chordTones.includes(note.chroma()),
scale: scale.name
});
}
});
});
// 根据位置推荐不同音符(强拍推荐和弦音,弱拍推荐经过音)
return availableNotes.filter(n => position === 'downbeat' ? n.isChordTone : true);
}
}
// 使用示例
const assistant = new ImprovisationAssistant(teoria.note('C4'), 'jazz');
const progression = assistant.generateProgression('ii-V-I');
console.log('推荐和弦进行:', progression.map(c => c.name));
// 为每个和弦推荐即兴音符
progression.forEach(chord => {
console.log(`\n${chord.name} 推荐音符:`);
const notes = assistant.suggestNotes(chord);
notes.forEach(n => {
console.log(`${n.note.scientific()} (${n.scale}${n.isChordTone ? ', 和弦音' : ''})`);
});
});
MIDI与Web Audio集成
Teoria.js可以与Web MIDI API和Web Audio API无缝集成,创建完整的音乐应用:
// Web Audio API与Teoria.js集成
class WebAudioSynth {
constructor() {
this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
this.gainNode = this.audioContext.createGain();
this.gainNode.connect(this.audioContext.destination);
this.oscillators = {};
}
// 播放音符
playNote(note, duration = 1, velocity = 0.7) {
const now = this.audioContext.currentTime;
const oscillator = this.audioContext.createOscillator();
const gain = this.audioContext.createGain();
// 设置振荡器
oscillator.type = 'sine';
oscillator.frequency.value = note.fq(); // 使用Teoria.js获取频率
// 设置音量包络
gain.gain.setValueAtTime(0, now);
gain.gain.linearRampToValueAtTime(velocity, now + 0.01);
gain.gain.linearRampToValueAtTime(velocity * 0.8, now + duration * 0.5);
gain.gain.linearRampToValueAtTime(0, now + duration);
// 连接并开始播放
oscillator.connect(gain);
gain.connect(this.gainNode);
oscillator.start(now);
// 存储振荡器引用以便停止
const id = note.scientific();
this.oscillators[id] = oscillator;
// 自动停止
setTimeout(() => {
oscillator.stop(now + 0.05);
delete this.oscillators[id];
}, duration * 1000);
return oscillator;
}
// 停止所有音符
stopAllNotes() {
Object.values(this.oscillators).forEach(osc => {
osc.stop(this.audioContext.currentTime + 0.01);
});
this.oscillators = {};
}
// 播放和弦
playChord(chord, duration = 1, velocity = 0.7) {
chord.notes().forEach(note => {
this.playNote(note, duration, velocity);
});
}
// 播放音阶
playScale(scale, duration = 0.5, velocity = 0.7, direction = 'up') {
let notes = scale.notes();
if (direction === 'down') notes = notes.reverse();
notes.forEach((note, index) => {
setTimeout(() => {
this.playNote(note, duration, velocity);
}, index * duration * 1000);
});
}
}
// 使用示例
const synth = new WebAudioSynth();
// 播放C大调音阶
document.getElementById('playScale').addEventListener('click', () => {
const scale = teoria.note('C4').scale('major');
synth.playScale(scale, 0.3);
});
// 播放Cmaj7和弦
document.getElementById('playChord').addEventListener('click', () => {
const chord = teoria.chord('Cmaj7');
synth.playChord(chord, 2);
});
// 钢琴键盘交互
document.querySelectorAll('.piano-key').forEach(key => {
key.addEventListener('mousedown', () => {
const noteName = key.dataset.note;
const note = teoria.note(noteName);
synth.playNote(note, 0.5);
});
});
第六天:项目实战——构建音乐理论工具包
现在我们将综合运用Teoria.js的各项功能,构建几个实用的音乐理论工具。
工具1:和弦进行生成器
这个工具可以生成常见风格的和弦进行,并提供详细的和声分析:
<div class="chord-progression-generator">
<h3>和弦进行生成器</h3>
<div class="controls">
<div>
<label>调式中心: </label>
<select id="keySelector">
<!-- 生成所有12个调式选项 -->
</select>
</div>
<div>
<label>音乐风格: </label>
<select id="styleSelector">
<option value="pop">流行</option>
<option value="rock">摇滚</option>
<option value="jazz">爵士</option>
<option value="blues">布鲁斯</option>
<option value="classical">古典</option>
</select>
</div>
<div>
<label>长度: </label>
<select id="lengthSelector">
<option value="4">4小节</option>
<option value="8">8小节</option>
<option value="12">12小节</option>
<option value="16">16小节</option>
</select>
</div>
<button id="generateBtn">生成和弦进行</button>
</div>
<div id="progressionDisplay"></div>
<div id="analysisDisplay"></div>
<button id="playProgressionBtn">播放和弦进行</button>
</div>
<script src="path/to/teoria.js"></script>
<script>
// 生成调式选择器选项
const keySelector = document.getElementById('keySelector');
['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'].forEach(key => {
const option = document.createElement('option');
option.value = key;
option.textContent = key;
keySelector.appendChild(option);
});
// 和弦进行生成器类
class ChordProgressionGenerator {
constructor() {
this.synth = new WebAudioSynth(); // 使用前面定义的WebAudioSynth
this.progression = [];
// 初始化事件监听
document.getElementById('generateBtn').addEventListener('click', () => this.generate());
document.getElementById('playProgressionBtn').addEventListener('click', () => this.play());
}
// 生成和弦进行
generate() {
const key = document.getElementById('keySelector').value;
const style = document.getElementById('styleSelector').value;
const length = parseInt(document.getElementById('lengthSelector').value);
// 根据风格和长度生成不同的和弦进行
this.progression = this.createProgression(key, style, length);
// 显示和弦进行
this.displayProgression();
// 分析和弦进行
this.analyzeProgression();
}
// 创建和弦进行
createProgression(key, style, length) {
const rootNote = teoria.note(key + '4');
const progression = [];
switch(style) {
case 'pop':
// 流行音乐常见和弦进行
const popPatterns = [
['I', 'V', 'vi', 'IV'], // 最流行的和弦进行
['I', 'IV', 'V', 'V'],
['vi', 'IV', 'I', 'V'],
['I', 'vi', 'iv', 'V']
];
const pattern = popPatterns[Math.floor(Math.random() * popPatterns.length)];
while (progression.length < length) {
pattern.forEach(roman => {
if (progression.length < length) {
progression.push(this.getChordFromRoman(rootNote, roman));
}
});
}
break;
case 'blues':
// 12小节布鲁斯进行
progression.push(
this.getChordFromRoman(rootNote, 'I'),
this.getChordFromRoman(rootNote, 'I'),
this.getChordFromRoman(rootNote, 'I'),
this.getChordFromRoman(rootNote, 'I'),
this.getChordFromRoman(rootNote, 'IV'),
this.getChordFromRoman(rootNote, 'IV'),
this.getChordFromRoman(rootNote, 'I'),
this.getChordFromRoman(rootNote, 'I'),
this.getChordFromRoman(rootNote, 'V'),
this.getChordFromRoman(rootNote, 'IV'),
this.getChordFromRoman(rootNote, 'I'),
this.getChordFromRoman(rootNote, 'V')
);
break;
// 其他风格的和弦进行生成逻辑...
}
return progression;
}
// 根据罗马数字标记获取和弦
getChordFromRoman(rootNote, roman) {
const key = rootNote.scale('major');
let chord;
switch(roman) {
case 'I': chord = key.get(1).chord('maj7'); break;
case 'ii': chord = key.get(2).chord('m7'); break;
case 'iii': chord = key.get(3).chord('m7'); break;
case 'IV': chord = key.get(4).chord('maj7'); break;
case 'V': chord = key.get(5).chord('7'); break;
case 'vi': chord = key.get(6).chord('m7'); break;
case 'vii': chord = key.get(7).chord('dim7'); break;
// 更多和弦类型...
}
return chord;
}
// 显示和弦进行
displayProgression() {
const display = document.getElementById('progressionDisplay');
display.innerHTML = '<h4>和弦进行</h4><div class="chord-grid">';
this.progression.forEach((chord, index) => {
const chordDiv = document.createElement('div');
chordDiv.className = 'chord-box';
chordDiv.innerHTML = `
<div class="chord-name">${chord.name}</div>
<div class="chord-notes">${chord.simple().join(', ')}</div>
<div class="chord-degrees">${index + 1}</div>
`;
chordDiv.addEventListener('click', () => this.synth.playChord(chord, 1));
display.appendChild(chordDiv);
});
display.innerHTML += '</div>';
}
// 分析和弦进行
analyzeProgression() {
const analysis = document.getElementById('analysisDisplay');
analysis.innerHTML = '<h4>和声分析</h4>';
// 调式分析
const key = this.progression[0].root.scale('major');
analysis.innerHTML += `<p>调式: ${key.tonic.scientific()}大调</p>`;
// 和弦功能分析
analysis.innerHTML += '<h5>和弦功能分析</h5><ul>';
this.progression.forEach((chord, index) => {
const functionName = this.determineChordFunction(chord, key);
analysis.innerHTML += `<li>第${index + 1}小节: ${chord.name} (${functionName})</li>`;
});
analysis.innerHTML += '</ul>';
// 和声节奏分析
analysis.innerHTML += '<h5>和声节奏</h5>';
analysis.innerHTML += `<p>平均和弦时长: ${4 / this.progression.length}小节</p>`;
}
// 确定和弦功能
determineChordFunction(chord, key) {
const root = chord.root;
const interval = teoria.interval(key.tonic, root).toString();
const functions = {
'P1': '主和弦(I)',
'M2': '上主和弦(ii)',
'M3': '中音和弦(iii)',
'P4': '下属和弦(IV)',
'P5': '属和弦(V)',
'M6': '下中音和弦(vi)',
'm7': '导音和弦(vii°)'
// 更多和弦功能...
};
return functions[interval] || '未确定功能';
}
// 播放和弦进行
playProgression() {
this.progression.forEach((chord, index) => {
setTimeout(() => {
this.synth.playChord(chord, 0.8);
}, index * 1000);
});
}
}
// 初始化生成器
const generator = new ChordProgressionGenerator();
</script>
工具2:音乐理论考试系统
这个工具可以帮助音乐学习者测试和巩固音乐理论知识:
<div class="music-theory-quiz">
<h3>音乐理论考试系统</h3>
<div class="quiz-controls">
<select id="questionType">
<option value="interval">音程识别</option>
<option value="chord">和弦识别</option>
<option value="scale">音阶识别</option>
<option value="note">音符识别</option>
</select>
<select id="difficulty">
<option value="easy">简单</option>
<option value="medium">中等</option>
<option value="hard">困难</option>
</select>
<button id="startQuizBtn">开始考试</button>
</div>
<div id="quizContainer"></div>
<div id="scoreContainer"></div>
</div>
<script src="path/to/teoria.js"></script>
<script>
// 音乐理论考试系统
class MusicTheoryQuiz {
constructor() {
this.score = 0;
this.questions = [];
this.currentQuestion = 0;
document.getElementById('startQuizBtn').addEventListener('click', () => this.startQuiz());
}
// 开始考试
startQuiz() {
this.score = 0;
this.currentQuestion = 0;
const questionType = document.getElementById('questionType').value;
const difficulty = document.getElementById('difficulty').value;
// 生成题目
this.generateQuestions(questionType, difficulty, 10);
// 显示第一题
this.displayQuestion();
// 重置分数显示
document.getElementById('scoreContainer').innerHTML =
`<p>得分: ${this.score}/${this.questions.length}</p>`;
}
// 生成题目
generateQuestions(type, difficulty, count) {
this.questions = [];
for (let i = 0; i < count; i++) {
switch(type) {
case 'interval':
this.questions.push(this.generateIntervalQuestion(difficulty));
break;
case 'chord':
this.questions.push(this.generateChordQuestion(difficulty));
break;
case 'scale':
this.questions.push(this.generateScaleQuestion(difficulty));
break;
case 'note':
this.questions.push(this.generateNoteQuestion(difficulty));
break;
}
}
}
// 生成音程题目
generateIntervalQuestion(difficulty) {
// 根据难度选择不同范围的音程
const intervals = difficulty === 'easy' ?
['M2', 'm2', 'M3', 'm3', 'P4', 'P5', 'M6', 'm6', 'M7', 'm7', 'P8'] :
difficulty === 'medium' ?
['M2', 'm2', 'M3', 'm3', 'P4', 'A4', 'd5', 'P5', 'M6', 'm6', 'M7', 'm7', 'P8'] :
['M2', 'm2', 'A2', 'd2', 'M3', 'm3', 'A3', 'd3', 'P4', 'A4', 'd5', 'P5', 'A5', 'd5', 'M6', 'm6', 'A6', 'd6', 'M7', 'm7', 'A7', 'd7', 'P8'];
// 随机选择音程和根音
const intervalName = intervals[Math.floor(Math.random() * intervals.length)];
const interval = teoria.interval(intervalName);
const rootNote = teoria.note.fromKey(36 + Math.floor(Math.random() * 48)); // 随机根音
const targetNote = rootNote.interval(interval);
// 创建选项
const options = [intervalName];
// 添加干扰项
while (options.length < 4) {
const distractor = intervals[Math.floor(Math.random() * intervals.length)];
if (!options.includes(distractor)) options.push(distractor);
}
// 打乱选项顺序
this.shuffleArray(options);
return {
type: 'interval',
question: `识别${rootNote.scientific()}到${targetNote.scientific()}的音程`,
correctAnswer: intervalName,
options: options,
audio: () => {
// 播放音程的函数
setTimeout(() => this.synth.playNote(rootNote, 0.5), 100);
setTimeout(() => this.synth.playNote(targetNote, 0.5), 600);
}
};
}
// 生成和弦题目
generateChordQuestion(difficulty) {
// 实现和弦题目的生成逻辑
// ...
}
// 生成音阶题目
generateScaleQuestion(difficulty) {
// 实现音阶题目的生成逻辑
// ...
}
// 生成音符题目
generateNoteQuestion(difficulty) {
// 实现音符题目的生成逻辑
// ...
}
// 显示当前题目
displayQuestion() {
const container = document.getElementById('quizContainer');
const question = this.questions[this.currentQuestion];
container.innerHTML = `
<div class="question-header">
<h4>问题 ${this.currentQuestion + 1}/${this.questions.length}</h4>
<p>${question.question}</p>
</div>
<div class="question-options">
${question.options.map(option => `
<div class="quiz-option" data-correct="${option === question.correctAnswer}">
${option}
</div>
`).join('')}
</div>
`;
// 如果有音频播放函数,添加播放按钮
if (question.audio) {
const audioBtn = document.createElement('button');
audioBtn.className = 'play-audio-btn';
audioBtn.textContent = '播放音频';
audioBtn.addEventListener('click', question.audio);
container.appendChild(audioBtn);
}
// 添加选项点击事件
document.querySelectorAll('.quiz-option').forEach(option => {
option.addEventListener('click', () => {
this.checkAnswer(option.dataset.correct === 'true');
});
});
}
// 检查答案
checkAnswer(isCorrect) {
if (isCorrect) {
this.score++;
document.getElementById('scoreContainer').innerHTML =
`<p>得分: ${this.score}/${this.questions.length}</p>`;
alert('正确!');
} else {
alert(`错误,正确答案是: ${this.questions[this.currentQuestion].correctAnswer}`);
}
// 下一题或结束
this.currentQuestion++;
if (this.currentQuestion < this.questions.length) {
this.displayQuestion();
} else {
this.endQuiz();
}
}
// 结束考试
endQuiz() {
const container = document.getElementById('quizContainer');
const scorePercentage = (this.score / this.questions.length) * 100;
container.innerHTML = `
<div class="quiz-results">
<h3>考试结束!</h3>
<p>你的得分: ${this.score}/${this.questions.length} (${scorePercentage.toFixed(1)}%)</p>
<p>${this.getFeedback(scorePercentage)}</p>
<button id="restartQuizBtn">再试一次</button>
</div>
`;
document.getElementById('restartQuizBtn').addEventListener('click', () => this.startQuiz());
}
// 获取反馈
getFeedback(score) {
if (score >= 90) return '优秀!你的音乐理论知识非常扎实。';
if (score >= 75) return '良好!继续努力。';
if (score >= 60) return '及格。还有提升空间。';
return '需要加强练习。建议复习相关音乐理论知识。';
}
// 打乱数组顺序
shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
}
// 初始化考试系统
const quizSystem = new MusicTheoryQuiz();
</script>
第七天:项目部署与优化
经过六天的学习,我们已经掌握了Teoria.js的核心功能和高级应用。最后一天,我们将学习如何将音乐应用部署到生产环境并进行优化。
项目构建与打包
使用Webpack打包Teoria.js应用:
// webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
devtool: 'source-map',
devServer: {
contentBase: './dist',
port: 8080
}
};
性能优化策略
优化Teoria.js应用性能的关键技巧:
// 1. 缓存常用计算结果
class CachedMusicCalculator {
constructor() {
this.chordCache = new Map();
this.scaleCache = new Map();
this.intervalCache = new Map();
}
// 缓存和弦计算
getChord(root, type) {
const key = `${root.scientific()}-${type}`;
if (this.chordCache.has(key)) {
return this.chordCache.get(key);
}
const chord = root.chord(type);
this.chordCache.set(key, chord);
// 限制缓存大小,防止内存泄漏
if (this.chordCache.size > 1000) {
const oldestKey = this.chordCache.keys().next().value;
this.chordCache.delete(oldestKey);
}
return chord;
}
// 缓存音阶计算
getScale(root, type) {
const key = `${root.scientific()}-${type}`;
if (this.scaleCache.has(key)) {
return this.scaleCache.get(key);
}
const scale = root.scale(type);
this.scaleCache.set(key, scale);
if (this.scaleCache.size > 1000) {
const oldestKey = this.scaleCache.keys().next().value;
this.scaleCache.delete(oldestKey);
}
return scale;
}
// 缓存音程计算
getInterval(fromNote, toNote) {
const key = `${fromNote.scientific()}-${toNote.scientific()}`;
if (this.intervalCache.has(key)) {
return this.intervalCache.get(key);
}
const interval = teoria.interval(fromNote, toNote);
this.intervalCache.set(key, interval);
if (this.intervalCache.size > 10000) {
const oldestKey = this.intervalCache.keys().next().value;
this.intervalCache.delete(oldestKey);
}
return interval;
}
}
// 使用缓存计算器
const musicCalc = new CachedMusicCalculator();
// 第一次计算会缓存结果
const cMajor = musicCalc.getScale(teoria.note('C4'), 'major');
// 第二次计算会直接返回缓存结果
const cMajorAgain = musicCalc.getScale(teoria.note('C4'), 'major');
移动端优化与响应式设计
为确保音乐应用在移动设备上有良好体验,需要进行响应式设计优化:
/* 响应式和弦网格 */
.chord-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
gap: 10px;
margin-top: 20px;
}
.chord-box {
background: #f5f5f5;
border: 1px solid #ddd;
border-radius: 8px;
padding: 10px;
text-align: center;
cursor: pointer;
transition: all 0.2s;
}
.chord-box:hover {
background: #e0e0e0;
transform: translateY(-2px);
}
/* 响应式测验布局 */
.quiz-option {
background: #f5f5f5;
border: 1px solid #ddd;
border-radius: 8px;
padding: 15px;
margin: 5px 0;
cursor: pointer;
}
@media (max-width: 768px) {
.controls {
flex-direction: column;
gap: 10px;
}
.chord-grid {
grid-template-columns: repeat(2, 1fr);
}
.quiz-option {
padding: 12px;
font-size: 0.9em;
}
}
@media (max-width: 480px) {
.chord-grid {
grid-template-columns: 1fr;
}
h3 {
font-size: 1.2em;
}
.question-header {
font-size: 0.9em;
}
}
总结与后续学习
通过这7天的学习,你已经掌握了Teoria.js的核心功能和实际应用技巧。从基本的音符创建到复杂的和弦进行生成,从音乐理论分析到Web Audio集成,你现在拥有了构建专业音乐应用的能力。
知识回顾
- 第1天:学习了
Note对象的创建和基本操作,能够表示和转换各种音符 - 第2天:掌握了
Interval对象,理解音程的性质和计算方法 - 第3天:深入学习
Chord对象,能够创建和分析各种和弦 - 第4天:探索
Scale对象,生成和转换各种音阶和调式 - 第5-6天:综合运用Teoria.js构建实际项目,包括和弦生成器和音乐理论考试系统
- 第7天:学习项目优化和部署技巧,确保应用性能和兼容性
后续学习路径
- 深入音乐理论:进一步学习和声学、对位法等高级音乐理论
- MIDI应用开发:探索Web MIDI API,实现与外部MIDI设备的交互
- 音频可视化:结合Canvas或WebGL实现音乐可视化效果
- AI音乐创作:将Teoria.js与机器学习结合,开发音乐创作AI
- 音乐教育应用:构建互动式音乐理论学习工具
实用资源推荐
- Teoria.js官方文档:深入了解每个API的详细用法
- 音乐理论基础:《音乐理论教程》(Tonal Harmony)
- Web Audio API文档:MDN Web Audio API指南
- 音乐编程社区:Web Audio API论坛和Stack Overflow音乐编程板块
现在,是时候将你的音乐创意和编程技能结合起来,开发出令人惊叹的音乐应用了!无论你是想构建音乐教育工具、创作辅助软件还是交互式音乐体验,Teoria.js都将是你不可或缺的强大工具。
祝你在音乐编程的道路上越走越远!
如果你觉得本教程对你有帮助,请点赞、收藏并关注作者,获取更多音乐编程相关内容。下期预告:《使用TensorFlow.js和Teoria.js构建AI作曲助手》
【免费下载链接】teoria Javascript taught Music Theory 项目地址: https://gitcode.com/gh_mirrors/te/teoria
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



