首页 > 解决方案 > Rust:如何使用 alto crate 以编程方式创建声音

问题描述

我是 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)。

标签: audiorustalto

解决方案


看起来这非常接近工作,只有几个问题:

  • 看起来调用_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::MIN和之间的值i16::MAX,即介于 -32768 和 +32767 之间的值。为了获得最高质量,您可能希望对音频进行标准化,以便在其最响亮的部分达到(或接近达到)最大值 32767,并且您可以调整系统音量以防止这引起不适/听力损失.


推荐阅读