第5课:噪声发生器(LFSR)

阶段1:波形基础

噪声是芯片音乐中不可或缺的元素——鼓点、打击乐、爆炸音效、海浪声,都来自噪声发生器。本课我们用LFSR(线性反馈移位寄存器)实现硬件噪声生成,这是所有经典声音芯片使用的技术。

什么是噪声?

在音频领域,噪声是指随机或不规则的声波信号。与乐音(周期性波形)不同,噪声没有明确的音高,听起来像"嘶嘶"或"沙沙"声。

🔊 噪声的颜色

按频谱分布,噪声被形象地用"颜色"分类:

类型频谱特征听感典型应用
白噪声各频率能量相等嘶嘶声,像收音机无信号军鼓、踩镲
粉红噪声能量按1/f衰减更柔和,像雨声环境音
棕噪声能量按1/f²衰减低沉轰鸣,像海浪爆炸、雷声
蓝噪声能量按f增长尖锐嘶嘶特殊效果

芯片音乐主要使用白噪声及其变种,因为LFSR天然产生白噪声。

LFSR原理详解

线性反馈移位寄存器是芯片噪声生成的核心:

📐 LFSR工作原理

LFSR由一个移位寄存器和异或(XOR)反馈网络组成:

┌───┬───┬───┬───┬───┬───┬───┬───┐
│b15│b14│b13│b12│b11│...│ b1│ b0│
└─┬─┴─┬─┴───┴───┴───┴───┴───┴─┬─┘
  │   │                        │
  └──XOR──┐                     │
          │  feedback           │
          └────────────────────┘
  1. 选择某些位(抽头)进行XOR运算,得到feedback位
  2. 整个寄存器右移一位
  3. feedback位填入最高位
  4. 重复——产生伪随机序列

LFSR是"伪随机"的——序列看起来随机,但实际上是完全确定性的,最终会循环。好的LFSR配置可以产生非常长的周期(2^n - 1),16位LFSR最长周期为65535步。

反馈抽头选择

抽头位置决定了LFSR的周期长度和统计特性:

模式抽头位置周期音色特征
短序列[15,14]嗡嗡声,有调性
NES风格[15,13]32767经典白噪声
长1[15,14,12,10]65535全周期白噪声
金属感[15,11]32767金属质感,像镲片
NES 2A03的噪声通道有两种模式:长模式(周期32767步)和短模式(周期93步)。短模式的声音有明显的调性感,听起来像低质量的"嘟嘟"声,常用于特殊音效。

移位速率与噪声"频率"

噪声没有明确的音高,但移位速率影响噪声的"质感":

通过调节shift_rate参数,我们可以从同一LFSR获得各种质感的噪声。

Verilog实现解析

1. 移位速率分频

rate_counter和shift_rate配合,控制LFSR移位的速率。shift_rate越大,移位越慢,噪声越粗糙。

2. 反馈网络

7种模式对应7组抽头配置,通过noise_mode选择。case语句在综合时变成MUX。

3. 种子值

复位时LFSR初始化为0xACE1(非零)。LFSR绝对不能全零——全零状态永远不会离开(0 XOR 0 = 0)。

4. 输出映射

取LFSR的高位作为输出。多位输出比单bit输出提供更多振幅变化,使噪声听起来更"自然"。

🔬 从LFSR到噪声鼓点

NES的鼓点全部来自噪声通道:

// 军鼓:短时高速噪声 + 三角波
// 踩镲:极短时高速噪声
// 底鼓:不使用噪声!用三角波下降音高模拟

// 速率参考(NES时钟约894886Hz):
// 高速 ≈ 每周期移位一次 → 白噪声(军鼓/踩镲)
// 中速 ≈ 每4周期移位 → 粗噪声(爆炸)
// 低速 ≈ 每16周期移位 → 嗡嗡声(引擎)
  1. 用Verilator编译LFSR噪声模块,验证7种模式的输出
  2. 写testbench:让LFSR运行一个完整周期(65535步),统计1和0的比例(应接近50%)
  3. 实验:对比短模式和长模式的听感差异
  4. 挑战:实现一个"噪声+包络"模块——噪声受ADSR包络控制,模拟军鼓音色

噪声大师 — 掌握LFSR伪随机数生成原理,实现可配置噪声发生器,理解噪声模式与音色的关系!四种基本波形全部完成!

Verilog 实现

lfsr_noise.v
// lfsr_noise.v - LFSR噪声发生器
// 支持7种噪声模式(不同反馈抽头配置)
module lfsr_noise #(
    parameter BIT_DEPTH = 8,
    parameter LFSR_BITS = 16       // LFSR位宽
)(
    input  wire clk,
    input  wire rst_n,
    input  wire enable,
    input  wire [2:0] noise_mode,   // 噪声模式选择
    input  wire [15:0] shift_rate,  // 移位速率控制
    output wire [BIT_DEPTH-1:0] noise_out
);
    reg [LFSR_BITS-1:0] lfsr;
    reg [15:0] rate_counter;
    
    // 移位速率分频器
    wire shift_en;
    assign shift_en = enable && (rate_counter >= shift_rate);
    
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            rate_counter <= 16'd0;
        end else if (enable) begin
            if (rate_counter >= shift_rate)
                rate_counter <= 16'd0;
            else
                rate_counter <= rate_counter + 16'd1;
        end
    end
    
    // LFSR反馈位(异或抽头)
    reg feedback;
    always @(*) begin
        case (noise_mode)
            3'd0: feedback = lfsr[15] ^ lfsr[14];             // 短序列
            3'd1: feedback = lfsr[15] ^ lfsr[13];             // NES风格
            3'd2: feedback = lfsr[15] ^ lfsr[14] ^ lfsr[12] ^ lfsr[10]; // 长1
            3'd3: feedback = lfsr[15] ^ lfsr[12];             // 长2
            3'd4: feedback = lfsr[15] ^ lfsr[11];             // 金属感
            3'd5: feedback = lfsr[15] ^ lfsr[14] ^ lfsr[7];  // 风格化
            3'd6: feedback = lfsr[15] ^ lfsr[13] ^ lfsr[11]; // 软噪声
            default: feedback = lfsr[15] ^ lfsr[14];
        endcase
    end
    
    // LFSR移位寄存器
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            lfsr <= 16'hACE1;  // 种子值(非零)
        end else if (shift_en) begin
            lfsr <= {lfsr[LFSR_BITS-2:0], feedback};
        end
    end
    
    // 输出:将LFSR高位扩展为BIT_DEPTH位
    // 使用LFSR的多个位产生多级噪声
    assign noise_out = {lfsr[15:15-BIT_DEPTH+1]} & {BIT_DEPTH{enable}};
endmodule

✅ Verilator验证通过

LFSR的数学原理

LFSR的理论基础是有限域(Galois Field)理论本原多项式(Primitive Polynomial)

📐 本原多项式与最大周期

一个n位LFSR要达到最大周期2^n-1,其反馈多项式必须是本原多项式。对于16位LFSR,本原多项式包括:

x^16 + x^15 + x^13 + x^4 + 1  → 抽头 [15, 13]
x^16 + x^14 + x^13 + x^11 + 1  → 抽头 [15, 14, 13, 11]
x^16 + x^15 + x^12 + x^10 + 1  → 抽头 [15, 14, 12, 10]  ← 我们使用的

选择不同的本原多项式产生不同但等价的伪随机序列——周期都是65535,但具体序列不同。

NES噪声通道的两种模式

NES 2A04噪声通道有两种模式,由寄存器位$400C bit 7控制:

🔊 长/短模式对比

模式周期频谱听感用途
长模式32767步接近白噪声嘶嘶声,自然军鼓、踩镲、风声
短模式93步有调性周期嗡嗡声,金属激光音效、引擎

短模式的93步周期产生约1.6kHz的基频(取决于移位速率),有明显的音高感。这个"缺陷"被巧妙地用作特殊音效。

噪声的音色塑造

单纯的LFSR噪声听起来很"干",需要处理才能变成有趣的鼓声:

1. 包络塑造

最关键的处理——控制噪声的持续时间和衰减速率:

2. 频率筛选

虽然我们没有实现完整的数字滤波器,但可以通过简单方法模拟:

3. 混合合成

最有效的鼓音色是噪声+音调的混合:

// 军鼓 = 噪声(高频) + 三角波(中频)
snare_out = (noise * noise_level + triangle * tone_level) * envelope;

// 底鼓 = 正弦波(频率扫描) + 轻微噪声
kick_out = (sine(freq_sweep) + noise * 0.1) * envelope;

LFSR的安全应用

除了音频,LFSR在密码学和通信中也有重要应用:

🔐 LFSR的密码学应用

多级噪声的混合

在芯片音乐中,经常混合不同特征的噪声产生更丰富的打击乐:

// 白噪声(高速LFSR) + 低频噪声(低速LFSR) = 有"轰鸣感"的军鼓
wire [7:0] white_noise = lfsr_high_speed[15:8];
wire [7:0] low_noise = lfsr_low_speed[15:8];
wire [7:0] mixed_noise = (white_noise + low_noise) >> 1;

// 噪声 + 低频正弦 = "有调性"的打击乐
wire [7:0] tonal_hit = (noise_out + sine_low_freq) >> 1;

// 多层噪声 = 更"自然"的打击乐
wire [7:0] natural = (lfsr1_out + lfsr2_out + lfsr3_out) / 3;

LFSR的Verilog实现模板

通用LFSR模块,可配置抽头和位宽:

🔧 参数化LFSR模块

module lfsr_generic #(
    parameter WIDTH = 16,
    parameter [WIDTH-1:0] TAPS = 16'b1100000000000000, // 抽头位置
    parameter [WIDTH-1:0] SEED = 16'hACE1  // 初始种子(非零!)
)(
    input  wire clk,
    input  wire rst_n,
    input  wire enable,
    output wire [WIDTH-1:0] data_out
);

reg [WIDTH-1:0] lfsr;

// 计算反馈位:所有抽头位异或
wire feedback;
assign feedback = ^(lfsr & TAPS);  // 缩位异或

always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        lfsr <= SEED;  // 重要:种子不能为0!
    else if (enable)
        lfsr <= {lfsr[WIDTH-2:0], feedback};
end

assign data_out = lfsr;

endmodule

这个参数化模块通过修改TAP参数就能支持任意LFSR配置。缩位异或运算符^是Verilog的利器——它将所有位异或在一起,一行代码替代多行case。