#audio-streaming #disk #io #stream

creek

实时安全的磁盘音频文件流读写

12 个版本 (6 个稳定版本)

1.2.2 2024年1月7日
1.2.0 2023年12月30日
1.1.1 2023年9月13日
1.1.0 2023年7月12日
0.1.1 2021年10月18日

#35 in 音频

Download history 145/week @ 2024-05-02 64/week @ 2024-05-09 103/week @ 2024-05-16 225/week @ 2024-05-23 411/week @ 2024-05-30 1518/week @ 2024-06-06 1176/week @ 2024-06-13 990/week @ 2024-06-20 464/week @ 2024-06-27 397/week @ 2024-07-04 330/week @ 2024-07-11 242/week @ 2024-07-18 215/week @ 2024-07-25 465/week @ 2024-08-01 490/week @ 2024-08-08 371/week @ 2024-08-15

每月 1,591 次下载
4 个 crate 中使用 (通过 web-audio-api)

MIT/Apache 许可

125KB
2K SLoC

🏞️ creek 🏞️

Documentation Crates.io License

磁盘上的音频文件实时安全流读写。

内置的解码器使用 Symphonia。有关支持的编解码器,请参阅 Symphonia 的文档。Symphonia 的 Cargo 功能以 decode- 为前缀暴露,除了 creek 目前无法处理的 aacisomp4。例如,要在 creek 中启用 MP3 解码,启用 decode-mp3 功能。

内置的编码器仅支持 WAV 格式。

读取流的原理

how it works

流内部有两种类型的缓冲区:一个 cache 缓冲区和 look-ahead 缓冲区。

一个 cache 缓冲区是预先加载的文件中用户定义的样本范围。

流可以有任意多的 cache 缓冲区。这个用例的常见用途是缓存文件的开头或循环区域,以实现无缝循环。当在文件中搜索帧时,creek 会检查是否存在包含该帧的缓存。如果存在,则播放可以立即恢复,无需缓冲。

使用 look-ahead 缓冲区自动提前加载播放头之前的帧,确保即使在最坏的情况下 I/O 延迟场景下,数据也始终可用。

如果没有找到合适的缓存(或缓存尚未加载),则需要先填充 look-ahead 缓冲区,然后才能读取更多数据。在这种情况下,您可以选择继续播放(这将输出静音)或暂时暂停播放,直到数据可用。

Creek 会自动启动一个“IO 服务器”线程来处理非实时操作。当流被丢弃时,该服务器会自动关闭。

写入流的原理

写入流的工作方式符合您的预期。一旦一个块被数据填满,它就会被发送到IO服务器线程进行写入。一旦服务器线程处理完那个块,它就会将其发送回写入流以便重用。

示例

简单使用示例

use creek::{
    SymphoniaDecoder, SeekMode, ReadDiskStream,
    WriteDiskStream, WavEncoder, wav_bit_depth
};

// Open a read stream.


let mut read_disk_stream = ReadDiskStream::<SymphoniaDecoder>::new(
    "./test_files/wav_f32_stereo.wav",  // Path to file.
    0,  // The frame in the file to start reading from.
    Default::default(),  // Use default read stream options.
).unwrap();

// Cache the start of the file into cache with index `0`.
let _ = read_disk_stream.cache(0, 0);

// Tell the stream to seek to the beginning of file. This will also alert the stream to the existence
// of the cache with index `0`.
read_disk_stream.seek(0, Default::default()).unwrap();

// Wait until the buffer is filled before sending it to the process thread.
//
// NOTE: Do ***not*** use this method in a real-time thread.
read_disk_stream.block_until_ready().unwrap();

// (Send `read_stream` to the audio processing thread)


// Open a write stream.


WriteDiskStream::<WavEncoder<wav_bit_depth::Float32>>::new(
    "./test_files/wav_f32_stereo_out.wav",  // Path to file.
    2,  // The number of channels in the file
    44100,  // The sample rate of the file
    Default::default(),  // Use default write stream options.
).unwrap();

// (Send `write_stream` to the audio processing thread)


// -------------------------------------------------------------


// In the realtime audio processing thread:


// Update read client and check if it is ready.
//
// NOTE: You should avoid using `unwrap()` in realtime code.
if !read_disk_stream.is_ready().unwrap() {
    // If the look-ahead buffer is still buffering, We can choose to either continue
    // reading (which will return silence), or pause playback until the buffer is filled.
}

let read_data = read_disk_stream.read(num_frames_in_output_buffer).unwrap();

println!("{}", read_data.num_frames());
println!("{}", read_data.num_channels());

// Seek to a new position in the file.
read_disk_stream.seek(50000, SeekMode::Auto};

assert_eq!(read_dist_stream.playhead(), 50000);


// Send stereo data to be written to disk.

write_disk_stream.write(
    &[read_data.read_channel(0), read_data.read_channel(1)]
).unwrap();

演示

贡献

我们使用各种pre-commit钩子来确保代码风格和格式的一致性。

请遵循安装说明,了解如何在您的开发系统中设置pre-commit。这允许您在提交代码之前在本地运行检查,并等待CI结果。

pre-commit run --all-files

Git

与Git合作的约定

  • 提交应遵循七条规则
  • 版本使用前缀v后跟crate的版本号进行标记,以匹配在crates.io页面上显示的版本。

依赖项

~0–0.8MB
~23K SLoC