add sine example

This commit is contained in:
Michael Sippel 2024-12-03 15:41:08 +01:00
commit f5c4ff8c35
Signed by: senvas
GPG key ID: F96CF119C34B64A6
3 changed files with 133 additions and 0 deletions

2
01-play-sine/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/target
Cargo.lock

7
01-play-sine/Cargo.toml Normal file
View file

@ -0,0 +1,7 @@
[package]
name = "play-sine"
version = "0.1.0"
edition = "2021"
[dependencies]
pipewire = "0.8.0"

124
01-play-sine/src/main.rs Normal file
View file

@ -0,0 +1,124 @@
use std::io::Cursor;
use pipewire::{
context::Context,
main_loop::MainLoop,
properties::properties,
spa::{
param::audio::{AudioFormat, AudioInfoRaw},
pod::{serialize::PodSerializer, Object, Pod, Value},
sys::{SPA_PARAM_EnumFormat, SPA_TYPE_OBJECT_Format},
utils::Direction,
},
stream::{Stream, StreamFlags},
};
struct MyData {
time: u64,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mainloop = MainLoop::new(None)?;
let context = Context::new(&mainloop)?;
let core = context.connect(None)?;
let registry = core.get_registry()?;
let _global_listener = registry
.add_listener_local()
.global(|global| println!("New global: {:?}", global))
.register();
let sample_rate = 48000;
let channel_count = 2;
let mut audio_info = AudioInfoRaw::new();
audio_info.set_format(AudioFormat::F32LE);
audio_info.set_rate(sample_rate);
audio_info.set_channels(channel_count);
let param_bytes = PodSerializer::serialize(
Cursor::new(vec![]),
&Value::Object(Object {
type_: SPA_TYPE_OBJECT_Format,
id: SPA_PARAM_EnumFormat,
properties: audio_info.into(),
}),
)
.expect("failed to serialize param")
.0
.into_inner();
let mut params = vec![Pod::from_bytes(&param_bytes).expect("failed to create pod")];
let out_stream = Stream::new(
&core,
"out1",
properties! {
*pipewire::keys::MEDIA_TYPE => "Audio",
*pipewire::keys::MEDIA_CATEGORY => "Playback",
*pipewire::keys::MEDIA_ROLE => "Music"
},
)
.expect("failed to create stream");
out_stream
.connect(
Direction::Output,
None,
StreamFlags::AUTOCONNECT | StreamFlags::MAP_BUFFERS | StreamFlags::RT_PROCESS,
params.as_mut_slice(),
)
.expect("failed to connect stream");
let my_data = MyData { time: 0 };
let _out_stream_listener = out_stream
.add_local_listener_with_user_data(my_data)
.process(move |stream, my_data: &mut MyData| {
let mut buffer = match stream.dequeue_buffer() {
Some(buf) => buf,
None => {
eprintln!("stream is out of buffers");
return;
}
};
let stride = std::mem::size_of::<f32>() * (channel_count as usize);
let datas = buffer.datas_mut();
let data = &mut datas[0];
let mut samples_written = 0;
if let Some(slice) = data.data() {
let slice = unsafe { &mut *(slice as *mut _ as *mut [f32]) };
for i in 0..(slice.len() / stride) {
let time_samples = {
let t = my_data.time;
my_data.time += 1;
t
};
let time_secs = (time_samples as f32) / 48000.0 as f32;
let sine_freq = 440.0;
let pi2 = 2.0 * 3.141;
let phi = pi2 * time_secs * sine_freq;
let value = 0.5 + 0.5 * f32::sin(phi);
slice[2 * i] = value;
slice[2 * i + 1] = value;
samples_written += 2;
}
}
let chunk = data.chunk_mut();
*chunk.offset_mut() = 0;
*chunk.stride_mut() = stride as _;
*chunk.size_mut() = (stride * samples_written) as _;
})
.register()
.expect("failed to add listener");
mainloop.run();
Ok(())
}