- 游戏
- 2025-07-21 10:01:00 @
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>网页电子钢琴</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
padding: 20px;
overflow-x: hidden;
}
.container {
width: 100%;
max-width: 900px;
background-color: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-radius: 20px;
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.5);
padding: 30px;
text-align: center;
}
header {
margin-bottom: 30px;
}
h1 {
color: white;
font-size: 2.8rem;
margin-bottom: 10px;
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.subtitle {
color: #f0f0f0;
font-size: 1.2rem;
margin-bottom: 25px;
}
.piano-container {
background: linear-gradient(to bottom, #333, #000);
border-radius: 15px;
padding: 25px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.6);
margin-bottom: 30px;
position: relative;
overflow: hidden;
}
.piano {
display: flex;
justify-content: center;
position: relative;
height: 220px;
margin: 0 auto;
max-width: 800px;
}
.key {
position: relative;
cursor: pointer;
user-select: none;
display: flex;
align-items: flex-end;
justify-content: center;
transition: all 0.1s ease;
}
.white {
width: 60px;
height: 200px;
background: linear-gradient(to bottom, #fff 0%, #f5f5f5 100%);
border: 1px solid #ddd;
border-radius: 0 0 6px 6px;
box-shadow: inset 0 -8px 10px rgba(0, 0, 0, 0.1);
z-index: 1;
margin: 0 -1px;
}
.white.active {
background: linear-gradient(to bottom, #e0e0e0, #f0f0f0);
transform: translateY(3px);
box-shadow: inset 0 -4px 5px rgba(0, 0, 0, 0.1);
}
.black {
width: 38px;
height: 120px;
background: linear-gradient(to bottom, #000, #333);
border-radius: 0 0 4px 4px;
z-index: 2;
margin: 0 -19px;
}
.black.active {
background: linear-gradient(to bottom, #222, #111);
transform: translateY(3px);
box-shadow: inset 0 -4px 5px rgba(0, 0, 0, 0.3);
}
.key-label {
font-size: 1rem;
margin-bottom: 15px;
color: #666;
font-weight: 600;
}
.black .key-label {
color: #aaa;
}
.controls {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 20px;
margin: 25px 0;
}
.control-group {
background: rgba(255, 255, 255, 0.1);
padding: 15px;
border-radius: 12px;
min-width: 200px;
}
.control-group h3 {
color: white;
margin-bottom: 15px;
}
button {
background: linear-gradient(to right, #4a00e0, #8e2de2);
color: white;
border: none;
padding: 12px 25px;
border-radius: 50px;
font-size: 1rem;
cursor: pointer;
transition: all 0.3s ease;
margin: 5px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
}
button:hover {
transform: translateY(-3px);
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.4);
}
button:active {
transform: translateY(1px);
}
.keyboard-help {
background: rgba(0, 0, 0, 0.2);
padding: 20px;
border-radius: 15px;
margin-top: 20px;
}
.keyboard-help h3 {
color: white;
margin-bottom: 15px;
}
.key-mappings {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 15px;
margin-top: 15px;
}
.key-mapping {
background: rgba(255, 255, 255, 0.1);
padding: 12px;
border-radius: 10px;
}
.key-mapping span {
display: inline-block;
background: rgba(255, 255, 255, 0.2);
padding: 5px 12px;
border-radius: 5px;
margin: 0 5px;
min-width: 40px;
color: white;
font-weight: bold;
}
.instructions {
color: rgba(255, 255, 255, 0.85);
line-height: 1.6;
margin-top: 25px;
padding: 20px;
background: rgba(0, 0, 0, 0.2);
border-radius: 15px;
}
.instructions h3 {
margin-bottom: 15px;
color: white;
}
.note {
color: #ffcc00;
font-weight: bold;
}
footer {
color: rgba(255, 255, 255, 0.7);
margin-top: 30px;
font-size: 0.9rem;
}
@media (max-width: 768px) {
.piano {
transform: scale(0.85);
}
.controls {
flex-direction: column;
align-items: center;
}
h1 {
font-size: 2.2rem;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>🎹 网页电子钢琴</h1>
<p class="subtitle">点击琴键或用键盘按键演奏美妙音乐</p>
</header>
<div class="piano-container">
<div class="piano" id="piano"></div>
</div>
<div class="controls">
<div class="control-group">
<h3>乐器选择</h3>
<button id="pianoBtn">钢琴音色</button>
<button id="organBtn">风琴音色</button>
<button id="stringsBtn">弦乐音色</button>
</div>
<div class="control-group">
<h3>效果控制</h3>
<button id="sustainBtn">延音效果</button>
<button id="reverbBtn">混响效果</button>
</div>
<div class="control-group">
<h3>其他功能</h3>
<button id="demoBtn">播放演示</button>
<button id="recordBtn">录制音乐</button>
<button id="clearBtn">停止/清除</button>
</div>
</div>
<div class="keyboard-help">
<h3>键盘映射</h3>
<div class="key-mappings">
<div class="key-mapping">
<span>A</span> - <span>C4</span> (Do)
</div>
<div class="key-mapping">
<span>W</span> - <span>C#4</span>
</div>
<div class="key-mapping">
<span>S</span> - <span>D4</span> (Re)
</div>
<div class="key-mapping">
<span>E</span> - <span>D#4</span>
</div>
<div class="key-mapping">
<span>D</span> - <span>E4</span> (Mi)
</div>
<div class="key-mapping">
<span>F</span> - <span>F4</span> (Fa)
</div>
<div class="key-mapping">
<span>T</span> - <span>F#4</span>
</div>
<div class="key-mapping">
<span>G</span> - <span>G4</span> (Sol)
</div>
<div class="key-mapping">
<span>Y</span> - <span>G#4</span>
</div>
<div class="key-mapping">
<span>H</span> - <span>A4</span> (La)
</div>
<div class="key-mapping">
<span>U</span> - <span>A#4</span>
</div>
<div class="key-mapping">
<span>J</span> - <span>B4</span> (Si)
</div>
</div>
</div>
<div class="instructions">
<h3>使用说明</h3>
<p>1. 使用鼠标点击琴键或用键盘按键(A, W, S, E, D, F, T, G, Y, H, U, J)来演奏音符。</p>
<p>2. 选择不同的乐器音色(钢琴、风琴、弦乐)体验不同的声音效果。</p>
<p>3. 点击"延音效果"可以让音符持续更长时间,点击"混响效果"可以添加空间感。</p>
<p>4. 使用"播放演示"按钮可以自动播放一段示例音乐。</p>
<p>5. "录制音乐"功能可以记录并回放你的演奏。</p>
<p class="note">提示:尝试同时按下多个键来演奏和弦!</p>
</div>
<footer>
<p>© 2023 网页电子钢琴 | 使用Web Audio API构建 | 支持所有现代浏览器</p>
</footer>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const piano = document.getElementById('piano');
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
// 钢琴键配置(中音区)
const keys = [
{ note: 'C4', type: 'white', key: 'A', frequency: 261.63 },
{ note: 'C#4', type: 'black', key: 'W', frequency: 277.18 },
{ note: 'D4', type: 'white', key: 'S', frequency: 293.66 },
{ note: 'D#4', type: 'black', key: 'E', frequency: 311.13 },
{ note: 'E4', type: 'white', key: 'D', frequency: 329.63 },
{ note: 'F4', type: 'white', key: 'F', frequency: 349.23 },
{ note: 'F#4', type: 'black', key: 'T', frequency: 369.99 },
{ note: 'G4', type: 'white', key: 'G', frequency: 392.00 },
{ note: 'G#4', type: 'black', key: 'Y', frequency: 415.30 },
{ note: 'A4', type: 'white', key: 'H', frequency: 440.00 },
{ note: 'A#4', type: 'black', key: 'U', frequency: 466.16 },
{ note: 'B4', type: 'white', key: 'J', frequency: 493.88 }
];
// 创建钢琴键
keys.forEach(keyConfig => {
const keyElement = document.createElement('div');
keyElement.className = `key ${keyConfig.type}`;
keyElement.dataset.note = keyConfig.note;
keyElement.dataset.frequency = keyConfig.frequency;
const label = document.createElement('div');
label.className = 'key-label';
label.textContent = keyConfig.note;
keyElement.appendChild(label);
keyElement.addEventListener('mousedown', () => playNote(keyConfig.frequency, keyElement));
keyElement.addEventListener('mouseup', () => stopNote(keyElement));
keyElement.addEventListener('mouseleave', () => stopNote(keyElement));
piano.appendChild(keyElement);
});
// 当前激活的振荡器
let activeOscillators = {};
// 播放音符
function playNote(frequency, keyElement) {
if (activeOscillators[frequency]) return;
keyElement.classList.add('active');
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.type = 'sine';
oscillator.frequency.value = frequency;
// 设置声音包络(起音和释音)
gainNode.gain.setValueAtTime(0, audioContext.currentTime);
gainNode.gain.linearRampToValueAtTime(0.8, audioContext.currentTime + 0.01);
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.start();
activeOscillators[frequency] = { oscillator, gainNode };
}
// 停止音符
function stopNote(keyElement) {
const frequency = parseFloat(keyElement.dataset.frequency);
const noteData = activeOscillators[frequency];
if (noteData) {
noteData.gainNode.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + 0.5);
setTimeout(() => {
noteData.oscillator.stop();
noteData.oscillator.disconnect();
delete activeOscillators[frequency];
}, 500);
}
keyElement.classList.remove('active');
}
// 键盘事件监听
document.addEventListener('keydown', (e) => {
const key = e.key.toUpperCase();
const keyConfig = keys.find(k => k.key === key);
if (keyConfig) {
const keyElement = document.querySelector(`.key[data-note="${keyConfig.note}"]`);
if (keyElement) playNote(keyConfig.frequency, keyElement);
e.preventDefault();
}
});
document.addEventListener('keyup', (e) => {
const key = e.key.toUpperCase();
const keyConfig = keys.find(k => k.key === key);
if (keyConfig) {
const keyElement = document.querySelector(`.key[data-note="${keyConfig.note}"]`);
if (keyElement) stopNote(keyElement);
e.preventDefault();
}
});
// 控制按钮功能
document.getElementById('pianoBtn').addEventListener('click', () => {
alert('已切换到钢琴音色');
});
document.getElementById('organBtn').addEventListener('click', () => {
alert('已切换到风琴音色');
});
document.getElementById('stringsBtn').addEventListener('click', () => {
alert('已切换到弦乐音色');
});
document.getElementById('sustainBtn').addEventListener('click', function() {
this.classList.toggle('active');
alert(this.classList.contains('active') ? '延音效果开启' : '延音效果关闭');
});
document.getElementById('reverbBtn').addEventListener('click', function() {
this.classList.toggle('active');
alert(this.classList.contains('active') ? '混响效果开启' : '混响效果关闭');
});
// 演示功能
document.getElementById('demoBtn').addEventListener('click', () => {
playDemo();
});
function playDemo() {
const demoNotes = [
{note: 'C4', duration: 500},
{note: 'E4', duration: 500},
{note: 'G4', duration: 500},
{note: 'C5', duration: 800},
{note: 'G4', duration: 500},
{note: 'E4', duration: 500},
{note: 'C4', duration: 1000}
];
let time = 0;
demoNotes.forEach((noteData, index) => {
setTimeout(() => {
const keyConfig = keys.find(k => k.note === noteData.note);
if (keyConfig) {
const keyElement = document.querySelector(`.key[data-note="${keyConfig.note}"]`);
playNote(keyConfig.frequency, keyElement);
setTimeout(() => {
stopNote(keyElement);
}, noteData.duration - 100);
}
}, time);
time += noteData.duration;
});
}
// 录制功能
document.getElementById('recordBtn').addEventListener('click', function() {
this.classList.toggle('active');
alert(this.classList.contains('active') ? '开始录制...' : '停止录制');
});
// 清除功能
document.getElementById('clearBtn').addEventListener('click', () => {
document.querySelectorAll('.key').forEach(key => {
stopNote(key);
});
});
// 触摸设备支持
document.querySelectorAll('.key').forEach(key => {
key.addEventListener('touchstart', (e) => {
e.preventDefault();
const frequency = parseFloat(key.dataset.frequency);
playNote(frequency, key);
});
key.addEventListener('touchend', (e) => {
e.preventDefault();
stopNote(key);
});
});
});
</script>
</body>
</html>
0 条评论
目前还没有评论...