【问题标题】:Rust: How to create sounds programmatically using alto crateRust:如何使用 alto crate 以编程方式创建声音
【发布时间】:2020-06-15 04:39:31
【问题描述】:

我是 Rust 的新手,我根据秘密酱算法生成的序列拼接了一个播放声音的程序。

但是,我没有听到使用整数序列作为测试数据播放的声音。

我不知道数字序列中哪些值是有效的,哪些值是可听见的,哪些值是可怕的,因为播放它们会失去我的听力。

我也在为 Rust 的结果包装器概念而苦苦挣扎;在我的代码中,我使用了三种不同的方法来解开其中一些可能不合适的方法。

这是我的代码:

fn main() {
    use std::process::exit;

    if let Err(e) = run() {
        println!("Failed to run basic example: {}", e);
        exit(1);
    }
}

extern crate alto;

use alto::{Alto, AltoResult, Mono, Source}; 

fn run() -> AltoResult<()> {
    use std::sync::Arc;

    let alto = Alto::load_default()?;

    for s in alto.enumerate_outputs() {
        println!("Found device: {}", s.to_str().unwrap());
    }

    let device = alto.open(None)?; // Opens the default audio device
    let context = device.new_context(None)?; // Creates a default context

    // Configure listener
    context.set_position([1.0, 4.0, 5.0])?;
    context.set_velocity([2.5, 0.0, 0.0])?;
    context.set_orientation(([0.0, 0.0, 1.0], [0.0, 1.0, 0.0]))?;

    let mut _source = context.new_static_source()?;

    // Now you can load your samples and store them in a buffer with
    // `context.new_buffer(samples, frequency)`;

    let data: Vec<_> = (10..200u32).map(|i| i as i16).collect();
    let buffer = context.new_buffer::<Mono<i16>, _>(data, 44_100);
    let buf = Arc::new(buffer.unwrap());

    let good_result = _source.set_buffer(buf);
    assert!(good_result.is_ok() && !good_result.is_err());

    _source.play();

    Ok(())
}

期望的结果:从整数序列(而不是音频文件)播放一些声音。 我也想知道如何附加到 Vec(vector)。

【问题讨论】:

    标签: audio rust alto


    【解决方案1】:

    看起来这很接近工作,只是几个问题:

    • 似乎对_source.play() 的调用是非阻塞的,这意味着进程在启动音频后几乎立即退出。你可以通过调用thread::sleep来防止这种情况发生。

    • 样本数据 (10..200) 仅 190 个样本长,在 44100 Hz 下只能持续 190 / 44100 秒,或大约 0.004 秒。此外,此处的波形可能听不见,因为其中没有振荡,扬声器的位置/压力只有一个线性斜坡。您可以通过创建正弦曲线或其他一些重复波形来获得声音。

    这是对您的示例的修改,它对我有用,生成 220 Hz 正弦波持续 2 秒:

    use alto::{Alto, AltoResult, Mono, Source};
    use std::{thread, time};
    
    fn main() {
        use std::process::exit;
    
        if let Err(e) = run() {
            println!("Failed to run basic example: {}", e);
            exit(1);
        }
    }
    
    fn run() -> AltoResult<()> {
        use std::sync::Arc;
    
        let alto = Alto::load_default()?;
    
        for s in alto.enumerate_outputs() {
            println!("Found device: {}", s.to_str().unwrap());
        }
    
        let device = alto.open(None)?; // Opens the default audio device
        let context = device.new_context(None)?; // Creates a default context
    
        // Configure listener
        context.set_position([1.0, 4.0, 5.0])?;
        context.set_velocity([2.5, 0.0, 0.0])?;
        context.set_orientation(([0.0, 0.0, 1.0], [0.0, 1.0, 0.0]))?;
    
        let mut _source = context.new_static_source()?;
    
        // Now you can load your samples and store them in a buffer with
        // `context.new_buffer(samples, frequency)`;
    
        let pi = std::f32::consts::PI;
        let data: Vec<_> = (0..88200u32)
            .map(|i| ((i16::MAX as f32) * f32::sin(2.0 * pi * (i as f32) * 220.0 / 44100.0)) as i16)
            .collect();
        let buffer = context.new_buffer::<Mono<i16>, _>(data, 44_100);
        let buf = Arc::new(buffer.unwrap());
    
        let good_result = _source.set_buffer(buf);
        assert!(good_result.is_ok() && !good_result.is_err());
    
        _source.play();
    
        thread::sleep(time::Duration::from_millis(2000));
        Ok(())
    }
    

    要回答有关序列中有效值范围的问题,任何i16 值都是有效的,因此您需要提供介于i16::MINi16::MAX 之间的值,即介于-32768 和+32767 之间的值.为了获得最高质量,您可能希望将音频标准化,以便在其最响亮的部分达到(或接近达到)最大值 32767,并且您可以调整系统音量级别以防止这引起不适/听力损失.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-14
      • 1970-01-01
      • 2014-02-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多