forked from Keelrleek/SoulStream
dj sets + lyrics: a mix that names its own tracks, and words pulled off the separated voice
This commit is contained in:
1 parent
4efe85b6bf
commit
1dd8573808
41 files changed
+9288
-647
No files matched your search
@@ -76,6 +76,8 @@ pub struct Settings {
|
||||
pub stream_source_prefs: config::SourcePrefs,
|
||||
pub download_source_prefs: config::SourcePrefs,
|
||||
pub volume_normalization: bool,
|
||||
/// Word-by-word lyric fill — experimental, default off.
|
||||
pub word_timing: bool,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -114,6 +116,7 @@ pub async fn get_settings(
|
||||
stream_source_prefs: cfg.stream_source_prefs,
|
||||
download_source_prefs: cfg.download_source_prefs,
|
||||
volume_normalization: config::volume_normalization(&cfg),
|
||||
word_timing: config::word_timing(&cfg),
|
||||
username: cfg.username,
|
||||
})
|
||||
}
|
||||
@@ -141,6 +144,7 @@ pub async fn set_settings(
|
||||
stream_source_prefs: Option<config::SourcePrefs>,
|
||||
download_source_prefs: Option<config::SourcePrefs>,
|
||||
volume_normalization: Option<bool>,
|
||||
word_timing: Option<bool>,
|
||||
) -> Result<(), String> {
|
||||
let mut cfg = config::load(&app);
|
||||
let library_folder_moved = download_dir
|
||||
@@ -209,6 +213,9 @@ pub async fn set_settings(
|
||||
// takes effect from the next track.
|
||||
crate::loudness::set_enabled(&app, enabled);
|
||||
}
|
||||
if word_timing.is_some() {
|
||||
cfg.word_timing = word_timing;
|
||||
}
|
||||
config::save(&app, &cfg);
|
||||
|
||||
// A new library folder is a new library. Re-base immediately rather than
|
||||
@@ -1550,6 +1557,15 @@ pub async fn catalog_search(
|
||||
Ok(state.metadata.catalog_search(&query).await)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn catalog_track_by_isrc(
|
||||
state: State<'_, LibraryState>,
|
||||
isrc: String,
|
||||
) -> Result<Option<metadata::CatalogTrack>, String> {
|
||||
state.touch_catalog_activity();
|
||||
Ok(state.metadata.catalog_track_by_isrc(&isrc).await)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn catalog_artist(
|
||||
app: tauri::AppHandle,
|
||||
@@ -4051,6 +4067,7 @@ pub fn play_local(
|
||||
app: tauri::AppHandle,
|
||||
path: String,
|
||||
duration: Option<f64>,
|
||||
start_secs: Option<f64>,
|
||||
) -> Result<(), String> {
|
||||
if std::fs::metadata(&path).is_err() {
|
||||
return Err("file not found".into());
|
||||
@@ -4064,7 +4081,11 @@ pub fn play_local(
|
||||
0,
|
||||
None,
|
||||
Box::new(move || {
|
||||
app2.state::<PlayerState>().player.play_local(&path2, duration);
|
||||
// `start_secs` = play a SLICE of the file from there (the
|
||||
// setlist segment rows); plain tracks pass None.
|
||||
app2.state::<PlayerState>()
|
||||
.player
|
||||
.play_local_from(&path2, duration, start_secs);
|
||||
}),
|
||||
);
|
||||
Ok(())
|
||||
@@ -4407,6 +4428,8 @@ pub async fn waveform(
|
||||
players: State<'_, PlayerState>,
|
||||
path: String,
|
||||
buckets: usize,
|
||||
start_secs: Option<f64>,
|
||||
end_secs: Option<f64>,
|
||||
) -> Result<Vec<f32>, String> {
|
||||
const MAX_WAVEFORM_BUCKETS: usize = 4096;
|
||||
if buckets > MAX_WAVEFORM_BUCKETS {
|
||||
@@ -4417,7 +4440,20 @@ pub async fn waveform(
|
||||
if buckets == 0 {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
let key = format!("{path}#{buckets}");
|
||||
// A range = a setlist SLICE's lane; each slice of one file caches
|
||||
// separately under its own key.
|
||||
let ranged = start_secs.is_some() || end_secs.is_some();
|
||||
let key = if ranged {
|
||||
format!(
|
||||
"{path}#{buckets}@{:.3}-{}",
|
||||
start_secs.unwrap_or(0.0),
|
||||
end_secs
|
||||
.map(|e| format!("{e:.3}"))
|
||||
.unwrap_or_else(|| "end".into()),
|
||||
)
|
||||
} else {
|
||||
format!("{path}#{buckets}")
|
||||
};
|
||||
let job = players.waveform_job(&key);
|
||||
let result = async {
|
||||
let job_guard = job.clone().lock_owned().await;
|
||||
@@ -4426,7 +4462,11 @@ pub async fn waveform(
|
||||
}
|
||||
let p = std::path::PathBuf::from(&path);
|
||||
let (job_guard, peaks) = tauri::async_runtime::spawn_blocking(move || {
|
||||
let peaks = player::compute_waveform(&p, buckets);
|
||||
let peaks = if ranged {
|
||||
player::compute_waveform_range(&p, buckets, start_secs.unwrap_or(0.0), end_secs)
|
||||
} else {
|
||||
player::compute_waveform(&p, buckets)
|
||||
};
|
||||
(job_guard, peaks)
|
||||
})
|
||||
.await
|
||||
|
||||
Reference in new issue
Block a user