You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust Rodio库中意外Frequency Modulation行为问题求助

Rust Rodio库中意外Frequency Modulation行为问题求助

大家好,我在使用Rodio 0.20.1和0.21.0版本时遇到了一个奇怪的调频(FM)行为问题,想请社区的朋友们帮忙排查一下问题所在。

具体情况是这样的:我写了一个自定义的Source实现来生成调频音频,当我把常量DEMONSTRATING_DEFECT设为false时,播放的声音是符合预期的——类似警报器的效果,在两个固定频率之间交替变化;但当把它设为true,使用随时间正弦变化的频率函数时,原本期望的是频率在440Hz±50Hz之间平滑交替,结果实际播放出来的却是高频越来越高,低频越来越低,完全偏离了预期效果。

以下是我的main.rs代码:

use std::{f32::consts::PI, io::stdin};
use rodio::{OutputStream, OutputStreamBuilder, Source};

const SAMPLE_RATE: u32 = 44_100;

struct FrequencyModulation {
    sample_num: u32,
    frequency: Box<dyn Fn(f32) -> f32 + Send + 'static>,
}

fn amplitude(time_in_secs: f32, hz: f32) -> f32 /* (-1.0, 1.0) */ {
    (2.0 * PI * hz * time_in_secs).sin()
}

fn time(sample_num: u32) -> f32 {
    sample_num as f32 / SAMPLE_RATE as f32
}

impl FrequencyModulation {
    pub fn new(frequency: Box<dyn Fn(f32) -> f32 + Send + 'static>) -> FrequencyModulation {
        FrequencyModulation {
            sample_num: 0,
            frequency,
        }
    }
}

impl Source for FrequencyModulation {
    fn current_span_len(&self) -> Option<usize> {
        None
    }

    fn channels(&self) -> u16 {
        1
    }

    fn sample_rate(&self) -> u32 {
        SAMPLE_RATE
    }

    fn total_duration(&self) -> Option<std::time::Duration> {
        None
    }
}

impl Iterator for FrequencyModulation {
    type Item = f32;

    fn next(&mut self) -> Option<Self::Item> {
        let time_in_secs = time(self.sample_num);
        let instantaneous_frequency = (self.frequency)(time_in_secs);
        let sample = amplitude(time_in_secs, instantaneous_frequency);
        self.sample_num = self.sample_num + 1;
        Some(sample)
    }
}

const DEMONSTRATING_DEFECT: bool = true;

fn main() {
    let (_stream, stream_handle) = OutputStreamBuilder::open_default_stream().unwrap();
    let freq = if DEMONSTRATING_DEFECT {
        // 行为异常:高频持续升高,低频持续降低
        |t: f32| 440.0 + 50.0 * (t * 2.0 * PI).sin()
    } else {
        // 行为符合预期:类似警报器的交替音调
        |t: f32| 440.0 + if (t * 2.0 * PI).sin() > 0.0 { 50.0 } else { -50.0 }
    };

    let source = FrequencyModulation::new(Box::new(freq));
    let _ = stream_handle.mixer().add(source);

    stdin().read_line(&mut String::new()).unwrap();
}

我怀疑是不是自己对调频的实现逻辑有误解?毕竟直接用瞬时频率计算振幅的方式,是不是忽略了调频需要累积相位而不是直接用当前时间乘以频率?希望有经验的朋友能帮我指出问题所在,或者给出正确的实现思路,谢谢大家!

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 07:24:31