diff options
| author | salmonik <raisersoft@proton.me> | 2026-06-07 21:19:46 +0300 |
|---|---|---|
| committer | salmonik <raisersoft@proton.me> | 2026-06-07 21:19:46 +0300 |
| commit | 45a1728ea4a3812120728562084fd416b35b074c (patch) | |
| tree | ae2f74cd08e97102ff1dda4c3c5006bde15d7bea /src/audio.rs | |
| parent | Merge pull request 'autocompletion' (#1) from autocompletion into main (diff) | |
| download | rsplayer-45a1728ea4a3812120728562084fd416b35b074c.tar.gz rsplayer-45a1728ea4a3812120728562084fd416b35b074c.zip | |
Add lyrics support
Diffstat (limited to '')
| -rw-r--r-- | src/audio.rs | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/src/audio.rs b/src/audio.rs index 6da47c3..f8eba04 100644 --- a/src/audio.rs +++ b/src/audio.rs | |||
| @@ -122,6 +122,7 @@ pub struct AudioEngine { | |||
| 122 | pub current_track: Arc<Mutex<Option<std::path::PathBuf>>>, | 122 | pub current_track: Arc<Mutex<Option<std::path::PathBuf>>>, |
| 123 | track_ended: Arc<AtomicBool>, | 123 | track_ended: Arc<AtomicBool>, |
| 124 | volume: Arc<Mutex<f32>>, | 124 | volume: Arc<Mutex<f32>>, |
| 125 | position: Arc<Mutex<f64>>, | ||
| 125 | } | 126 | } |
| 126 | 127 | ||
| 127 | #[allow(clippy::new_without_default)] | 128 | #[allow(clippy::new_without_default)] |
| @@ -138,6 +139,9 @@ impl AudioEngine { | |||
| 138 | let volume = Arc::new(Mutex::new(1.0f32)); | 139 | let volume = Arc::new(Mutex::new(1.0f32)); |
| 139 | let volume_clone = Arc::clone(&volume); | 140 | let volume_clone = Arc::clone(&volume); |
| 140 | 141 | ||
| 142 | let position = Arc::new(Mutex::new(0.0)); | ||
| 143 | let position_clone = Arc::clone(&position); | ||
| 144 | |||
| 141 | thread::spawn(move || { | 145 | thread::spawn(move || { |
| 142 | audio_thread( | 146 | audio_thread( |
| 143 | rx, | 147 | rx, |
| @@ -145,6 +149,7 @@ impl AudioEngine { | |||
| 145 | current_track_clone, | 149 | current_track_clone, |
| 146 | volume_clone, | 150 | volume_clone, |
| 147 | track_ended_clone, | 151 | track_ended_clone, |
| 152 | position_clone, | ||
| 148 | ); | 153 | ); |
| 149 | }); | 154 | }); |
| 150 | 155 | ||
| @@ -154,6 +159,7 @@ impl AudioEngine { | |||
| 154 | current_track, | 159 | current_track, |
| 155 | track_ended, | 160 | track_ended, |
| 156 | volume, | 161 | volume, |
| 162 | position, | ||
| 157 | } | 163 | } |
| 158 | } | 164 | } |
| 159 | 165 | ||
| @@ -199,6 +205,10 @@ impl AudioEngine { | |||
| 199 | pub fn poll_track_ended(&self) -> bool { | 205 | pub fn poll_track_ended(&self) -> bool { |
| 200 | self.track_ended.swap(false, Ordering::SeqCst) | 206 | self.track_ended.swap(false, Ordering::SeqCst) |
| 201 | } | 207 | } |
| 208 | |||
| 209 | pub fn position(&self) -> f64 { | ||
| 210 | self.position.lock().map(|p| *p).unwrap_or(0.0) | ||
| 211 | } | ||
| 202 | } | 212 | } |
| 203 | 213 | ||
| 204 | struct AudioData { | 214 | struct AudioData { |
| @@ -245,6 +255,7 @@ fn audio_thread( | |||
| 245 | current_track: Arc<Mutex<Option<std::path::PathBuf>>>, | 255 | current_track: Arc<Mutex<Option<std::path::PathBuf>>>, |
| 246 | volume: Arc<Mutex<f32>>, | 256 | volume: Arc<Mutex<f32>>, |
| 247 | track_ended: Arc<AtomicBool>, | 257 | track_ended: Arc<AtomicBool>, |
| 258 | position: Arc<Mutex<f64>>, | ||
| 248 | ) { | 259 | ) { |
| 249 | use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; | 260 | use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; |
| 250 | 261 | ||
| @@ -282,6 +293,9 @@ fn audio_thread( | |||
| 282 | if let Ok(mut track) = current_track.lock() { | 293 | if let Ok(mut track) = current_track.lock() { |
| 283 | *track = Some(path.clone()); | 294 | *track = Some(path.clone()); |
| 284 | } | 295 | } |
| 296 | if let Ok(mut pos) = position.lock() { | ||
| 297 | *pos = 0.0; | ||
| 298 | } | ||
| 285 | 299 | ||
| 286 | // Drop the current stream before creating a new one | 300 | // Drop the current stream before creating a new one |
| 287 | current_stream = None; | 301 | current_stream = None; |
| @@ -334,6 +348,7 @@ fn audio_thread( | |||
| 334 | let vol = Arc::clone(&volume); | 348 | let vol = Arc::clone(&volume); |
| 335 | let ended = Arc::clone(&track_ended); | 349 | let ended = Arc::clone(&track_ended); |
| 336 | let is_playing_clone = Arc::clone(&is_playing); | 350 | let is_playing_clone = Arc::clone(&is_playing); |
| 351 | let position_clone = Arc::clone(&position); | ||
| 337 | 352 | ||
| 338 | if let Ok(mut d) = audio_data.lock() { | 353 | if let Ok(mut d) = audio_data.lock() { |
| 339 | *d = Some(data); | 354 | *d = Some(data); |
| @@ -434,6 +449,14 @@ fn audio_thread( | |||
| 434 | *sample = 0.0; | 449 | *sample = 0.0; |
| 435 | } | 450 | } |
| 436 | 451 | ||
| 452 | // Track playback position | ||
| 453 | if offset > 0 | ||
| 454 | && let Ok(mut pos) = position_clone.lock() | ||
| 455 | { | ||
| 456 | *pos += offset as f64 | ||
| 457 | / (device_sample_rate as f64 * channels as f64); | ||
| 458 | } | ||
| 459 | |||
| 437 | // If no more data and offset is 0, track ended | 460 | // If no more data and offset is 0, track ended |
| 438 | if offset == 0 && state.sample_buffer.is_empty() { | 461 | if offset == 0 && state.sample_buffer.is_empty() { |
| 439 | ended.store(true, Ordering::SeqCst); | 462 | ended.store(true, Ordering::SeqCst); |
