鼓机是芯片音乐节奏的核心。本课实现一个完整的4音色鼓机——底鼓、军鼓、踩镲、开镲,每种音色用不同的合成方法生成,配合16步序列器自动演奏节奏模式。
与真实鼓不同,芯片音乐的鼓完全是合成的。每种鼓有独特的合成策略:
| 鼓 | 合成方法 | 关键参数 | 时长 |
|---|---|---|---|
| 底鼓(Kick) | 正弦波+频率扫描 | 起始~150Hz→结束~50Hz | 200-400ms |
| 军鼓(Snare) | 噪声+三角波 | 噪声带宽+音高 | 100-200ms |
| 踩镲(Hi-hat) | 带通滤波噪声 | 截止频率高 | 30-80ms |
| 开镲(Open Hat) | 同踩镲但衰减慢 | 截止频率高 | 200-500ms |
底鼓最关键的特性是音高下降——从高音快速下降到低音,产生"嘭"的感觉:
// 频率扫描实现
初始频率 ≈ 150Hz
每个时钟:freq = freq - (freq >> 4) // 指数下降
最终频率 ≈ 50Hz
同时:envelope 快速衰减
这种"频率扫描+包络"是所有808/909风格底鼓的核心。TR-808的底鼓是正弦波+频率扫描的经典案例。
基本4/4拍 (120BPM):
Kick: X...X...X...X...
Snare: ....X.......X...
HiHat: X.X.X.X.X.X.X.X.
Disco:
Kick: X...X...X...X...
Snare: ....X.......X...
HiHat: X.X.XXX.X.X.XXX
Breakbeat:
Kick: X.....X.X.......
Snare: ....X.......X.X.
HiHat: X.X.X.X.X.X.X.X.
Bossa Nova:
Kick: X..X....X..X....
Snare: ....X.......X.X.
HiHat: X.X.X.X.X.X.X.X.
NES没有专门的鼓通道!鼓声来自:
节奏大师 — 实现4音色鼓机,掌握芯片鼓音色的合成方法,理解频率扫描和噪声衰减的原理!
// drum_machine.v - 鼓机模块
// 4种鼓音色 + 步进序列器
module drum_machine #(
parameter CLK_FREQ = 50000000,
parameter BIT_DEPTH = 8,
parameter PHASE_BITS = 32,
parameter STEPS = 16
)(
input wire clk,
input wire rst_n,
input wire beat_pulse,
input wire play,
// 鼓模式:4个鼓×16步
input wire [STEPS-1:0] kick_pattern,
input wire [STEPS-1:0] snare_pattern,
input wire [STEPS-1:0] hihat_pattern,
input wire [STEPS-1:0] openhat_pattern,
// 输出
output wire [BIT_DEPTH-1:0] audio_out,
output wire [3:0] step_indicator
);
// ─── 步进计数器 ───
reg [3:0] step;
reg playing;
reg [3:0] trigger; // 4个鼓的触发信号
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
step <= 4'd0;
playing <= 1'b0;
trigger <= 4'd0;
end else begin
trigger <= 4'd0;
if (play && !playing) begin
playing <= 1'b1;
step <= 4'd0;
end
if (playing && beat_pulse) begin
// 检查当前步哪些鼓被触发
trigger[0] <= kick_pattern[step];
trigger[1] <= snare_pattern[step];
trigger[2] <= hihat_pattern[step];
trigger[3] <= openhat_pattern[step];
step <= step + 4'd1;
end
end
end
assign step_indicator = step;
// ─── 底鼓(Kick) ───
// 短时正弦波 + 快速频率下降(从~150Hz到~50Hz)
reg [PHASE_BITS-1:0] kick_phase;
reg [PHASE_BITS-1:0] kick_freq;
reg [7:0] kick_env;
reg kick_active;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
kick_phase <= {PHASE_BITS{1'b0}};
kick_freq <= {PHASE_BITS{1'b0}};
kick_env <= 8'd0;
kick_active <= 1'b0;
end else begin
if (trigger[0]) begin
kick_active <= 1'b1;
kick_freq <= 32'd1288490; // ~150Hz
kick_env <= 8'd255;
end else if (kick_active) begin
kick_phase <= kick_phase + kick_freq;
// 频率下降
if (kick_freq > 32'd429497)
kick_freq <= kick_freq - (kick_freq >> 4);
// 包络衰减
if (kick_env > 8'd4)
kick_env <= kick_env - (kick_env >> 3);
else begin
kick_active <= 1'b0;
kick_env <= 8'd0;
end
end
end
end
wire [7:0] kick_out = kick_active ?
((kick_phase[31:24] < 128) ? kick_env : 8'd0) : 8'd0;
// ─── 军鼓(Snare) ───
// 噪声 + 短三角波 + 快速衰减
reg [15:0] snare_lfsr;
reg [7:0] snare_env;
reg snare_active;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
snare_lfsr <= 16'hBEEF;
snare_env <= 8'd0;
snare_active <= 1'b0;
end else begin
if (trigger[1]) begin
snare_active <= 1'b1;
snare_env <= 8'd255;
end else if (snare_active) begin
snare_lfsr <= {snare_lfsr[14:0], snare_lfsr[15] ^ snare_lfsr[13]};
if (snare_env > 8'd3)
snare_env <= snare_env - (snare_env >> 2);
else begin
snare_active <= 1'b0;
snare_env <= 8'd0;
end
end
end
end
wire [7:0] snare_out = snare_active ?
((snare_lfsr[15:8] & 8'h7F) * snare_env) >> 8 : 8'd0;
// ─── 踩镲(Hi-hat) ───
// 高速噪声 + 极快衰减
reg [15:0] hh_lfsr;
reg [7:0] hh_env;
reg hh_active;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
hh_lfsr <= 16'hCAFE;
hh_env <= 8'd0;
hh_active <= 1'b0;
end else begin
if (trigger[2]) begin
hh_active <= 1'b1;
hh_env <= 8'd200;
end else if (hh_active) begin
hh_lfsr <= {hh_lfsr[14:0], hh_lfsr[15] ^ hh_lfsr[12]};
if (hh_env > 8'd2)
hh_env <= hh_env - (hh_env >> 1);
else begin
hh_active <= 1'b0;
hh_env <= 8'd0;
end
end
end
end
wire [7:0] hihat_out = hh_active ?
((hh_lfsr[15:8] & 8'h3F) * hh_env) >> 8 : 8'd0;
// ─── 开镲(Open Hat) ───
// 与踩镲相同但衰减更慢
reg [15:0] oh_lfsr;
reg [7:0] oh_env;
reg oh_active;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
oh_lfsr <= 16'hDEAD;
oh_env <= 8'd0;
oh_active <= 1'b0;
end else begin
if (trigger[3]) begin
oh_active <= 1'b1;
oh_env <= 8'd180;
end else if (oh_active) begin
oh_lfsr <= {oh_lfsr[14:0], oh_lfsr[15] ^ oh_lfsr[11]};
if (oh_env > 8'd2)
oh_env <= oh_env - (oh_env >> 3);
else begin
oh_active <= 1'b0;
oh_env <= 8'd0;
end
end
end
end
wire [7:0] openhat_out = oh_active ?
((oh_lfsr[15:8] & 8'h3F) * oh_env) >> 8 : 8'd0;
// ─── 混音 ───
assign audio_out = kick_out + snare_out + hihat_out + openhat_out;
endmodule
✅ Verilator验证通过
以下是芯片音乐中常用的16步鼓模式,可直接用于你的音序器:
═══ 基本4/4 ═══
Kick: X...X...X...X...
Snare: ....X.......X...
HiHat: X.X.X.X.X.X.X.X.
═══ Rock ═══
Kick: X.......X...X...
Snare: ....X.......X...
HiHat: X.X.X.X.X.X.XXX
═══ Funk ═══
Kick: X.....X.X....X..
Snare: ....X.......X...
HiHat: X.XXX.X.XXX.X.X.
═══ Hip-Hop ═══
Kick: X...........X...
Snare: ....X.......X...
HiHat: X.X.X.X.X.X.X.X.
═══ D&B (170BPM) ═══
Kick: X.....X.........X.
Snare: ....X.......X.X...
HiHat: X.X.X.X.X.X.X.X.X
═══ Breakbeat ═══
Kick: X.....X.X.......
Snare: ....X.......X.X.
HiHat: X.X.X.X.X.X.X.X.
═══ Bossa Nova ═══
Kick: X..X....X..X....
Snare: ....X.......X.X.
HiHat: X.X.X.X.X.X.X.X.
═══ Reggae ═══
Kick: X.......X.......
Snare: ....X.......X...
HiHat: X.X.X.X.X.X.X.X.
OpenH: ..............X.
| 特性 | TR-808 | TR-909 |
|---|---|---|
| 底鼓 | 正弦波+长衰减,深沉 | 正弦波+噪声点击,紧致 |
| 军鼓 | 噪声+低Q滤波,柔软 | 噪声+短正弦,尖锐 |
| 踩镲 | 6个方波叠加 | 噪声+带通滤波 |
| 风格 | Hip-hop, R&B, Electro | House, Techno, Trance |
| 芯片模拟难度 | 中等(正弦波+包络) | 较难(需要滤波器) |
通过不同的力度值,同一个鼓模式可以产生不同的律动感:
理解真实鼓的声学特性有助于设计更好的合成鼓:
| 特征 | 真实底鼓 | 合成底鼓 | 差异 |
|---|---|---|---|
| 频率 | 50-100Hz + 泛音 | 50-150Hz扫描 | 扫描更戏剧化 |
| 衰减 | 指数~500ms | 指数~300ms | 合成更短 |
| 攻击 | 1-5ms 点击 | 瞬间 | 合成更锐利 |
| 泛音 | 丰富非线性 | 简单FM边带 | 真实更复杂 |
合成鼓不需要完美复制真实鼓——它有自己的美学。808底鼓之所以成为传奇,恰恰是因为它"不像"真实底鼓。
通过力度控制鼓的参数,让鼓组更有表现力:
// 力度敏感的底鼓
轻击(vel=64): 起始频率=80Hz, 衰减慢, 音量低
重击(vel=255): 起始频率=150Hz, 衰减快, 音量高
wire [31:0] kick_start_freq = 32'd858993 + (vel << 16);
wire [7:0] kick_start_env = vel;
wire [7:0] kick_decay_rate = 3 + (vel >> 5);