add sine example
This commit is contained in:
commit
f5c4ff8c35
3 changed files with 133 additions and 0 deletions
2
01-play-sine/.gitignore
vendored
Normal file
2
01-play-sine/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
Cargo.lock
|
7
01-play-sine/Cargo.toml
Normal file
7
01-play-sine/Cargo.toml
Normal 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
124
01-play-sine/src/main.rs
Normal 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(¶m_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(())
|
||||||
|
}
|
Loading…
Reference in a new issue