dataset.step = i;
单元格.onclick = () => this.切换节奏单元格(单元格);
编排器.appendChild(单元格);
// 初始化节奏数据
if (!this.节奏数据[鼓名]) {
this.节奏数据[鼓名] = [];
}
}
});
}
初始化控件() {
// 节奏控制
document.getElementById('tempoControl').addEventListener('input', (e) => {
this.当前节奏 = parseInt(e.target.value);
document.getElementById('tempoValue').textContent = this.当前节奏 + ' BPM';
});
// 音量控制
document.getElementById('volumeControl').addEventListener('input', (e) => {
this.当前音量 = e.target.value / 100;
document.getElementById('volumeValue').textContent = e.target.value + '%';
});
}
切换节奏单元格(单元格) {
单元格.classList.toggle('active');
const 鼓名 = 单元格.dataset.drum;
const 步进 = parseInt(单元格.dataset.step);
if (单元格.classList.contains('active')) {
if (!this.节奏数据[鼓名]) {
this.节奏数据[鼓名] = [];
}
this.节奏数据[鼓名].push(步进);
} else {
this.节奏数据[鼓名] = this.节奏数据[鼓名].filter(s => s !== 步进);
}
this.输出日志(`${鼓名} - 步进 ${步进} ${单元格.classList.contains('active') ? '激活' : '取消'}`);
}
播放鼓声(鼓名) {
const 配置 = this.鼓组配置[鼓名];
if (!配置) return;
const 振荡器 = this.音频上下文.createOscillator();
const 增益节点 = this.音频上下文.createGain();
振荡器.connect(增益节点);
增益节点.connect(this.音频上下文.destination);
switch(配置.type) {
case 'sine':
振荡器.frequency.setValueAtTime(配置.freq, this.音频上下文.currentTime);
振荡器.frequency.exponentialRampToValueAtTime(0.01, this.音频上下文.currentTime + 配置.duration);
break;
case 'noise':
// 噪声生成
const 缓冲 = this.音频上下文.createBuffer(1, 22050, 22050);
const 数据 = 缓冲.getChannelData(0);
for (let i = 0; i < 22050; i++) {
数据[i] = Math.random() * 2 - 1;
}
const 源 = this.音频上下文.createBufferSource();
源.buffer = 缓冲;
源.connect(增益节点);
源.start();
break;
case 'highpass':
// 高频滤波
const 滤波器 = this.音频上下文.createBiquadFilter();
滤波器.type = 'highpass';
滤波器.frequency.value = 配置.freq;
振荡器.connect(滤波器);
滤波器.connect(增益节点);
break;
}
振荡器.type = 配置.type === 'sine' ? 'sine' : 'square';
增益节点.gain.setValueAtTime(this.当前音量, this.音频上下文.currentTime);
增益节点.gain.exponentialRampToValueAtTime(0.01, this.音频上下文.currentTime + 配置.duration);
if (配置.type !== 'noise') {
振荡器.start(this.音频上下文.currentTime);
振荡器.stop(this.音频上下文.currentTime + 配置.duration);
}
// 视觉反馈
const 鼓按钮 = Array.from(document.querySelectorAll('.drum-pad'))
.find(btn => btn.textContent === 鼓名);
if (鼓按钮) {
鼓按钮.classList.add('playing');
setTimeout(() => 鼓按钮.classList.remove('playing'), 200);
}
}
播放节奏() {
if (this.播放状态 === 'playing') {
this.停止播放();
return;
}
this.播放状态 = 'playing';
this.当前播放步进 = 0;
this.输出日志('开始播放节奏...');
const 步进间隔 = (60 / this.当前节奏) * 1000 / 4; // 16分音符间隔
this.播放定时器 = setInterval(() => {
if (this.播放状态 !== 'playing') return;
this.当前播放步进++;
if (this.当前播放步进 > 16) {
this.当前播放步进 = 1;
}
// 更新视觉反馈
document.querySelectorAll('.step-cell').forEach(单元格 => {
单元格.classList.remove('playing');
if (parseInt(单元格.dataset.step) === this.当前播放步进) {
单元格.classList.add('playing');
}
});
// 播放当前步进的鼓声
Object.keys(this.节奏数据).forEach(鼓名 => {
if (this.节奏数据[鼓名].includes(this.当前播放步进)) {
this.播放鼓声(鼓名);
}
});
}, 步进间隔);
}
停止播放() {
this.播放状态 = 'stopped';
if (this.播放定时器) {
clearInterval(this.播放定时器);
this.播放定时器 = null;
}
document.querySelectorAll('.step-cell').forEach(单元格 => {
单元格.classList.remove('playing');
});
this.输出日志('节奏播放停止');
}
录制节奏() {
this.输出日志('开始录制节奏...');
}
清空节奏() {
this.节奏数据 = {};
document.querySelectorAll('.step-cell').forEach(单元格 => {
Back to home |
File page
Subscribe |
Register |
Login
| N