redguard-preservation 0.10.0

A CLI tool to preserve Redguard files
Documentation
use super::write_wav;
use color_eyre::Result;
use log::info;
use rayon::prelude::*;
use rgpre::import::sfx;
use serde_json::json;
use std::path::Path;

pub(crate) fn handle_sfx_convert(file: &Path, output_path: &Path) -> Result<()> {
    let file_content = std::fs::read(file)?;
    let sfx_file =
        sfx::parse_sfx_file(&file_content).map_err(|e| color_eyre::eyre::eyre!("{e}"))?;

    std::fs::create_dir_all(output_path)?;

    let effect_metadata: Vec<serde_json::Value> = sfx_file
        .effects
        .par_iter()
        .enumerate()
        .map(|(i, effect)| -> Result<serde_json::Value> {
            let wav_filename = format!("{i:03}.wav");
            let wav_path = output_path.join(&wav_filename);

            write_wav(
                &wav_path,
                effect.audio_type,
                effect.sample_rate,
                &effect.pcm_data,
            )?;

            info!(
                "  [{i:03}] {:?} {}Hz {:.3}s -> {}",
                effect.audio_type,
                effect.sample_rate,
                effect.duration_secs(),
                wav_path.display(),
            );

            Ok(json!({
                "index": i,
                "wav_file": wav_filename,
                "audio_type": format!("{:?}", effect.audio_type),
                "sample_rate": effect.sample_rate,
                "duration_secs": effect.duration_secs(),
                "loop": effect.loop_flag != 0,
                "loop_offset": effect.loop_offset,
                "loop_end": effect.loop_end,
                "pcm_bytes": effect.pcm_data.len(),
            }))
        })
        .collect::<Result<Vec<_>>>()?;

    let source_name = file
        .file_name()
        .map(|n| n.to_string_lossy().to_string())
        .unwrap_or_default();

    let index = json!({
        "source": source_name,
        "description": sfx_file.description,
        "effect_count": effect_metadata.len(),
        "effects": effect_metadata,
    });

    let index_path = output_path.join("index.json");
    std::fs::write(&index_path, serde_json::to_string_pretty(&index)?)?;
    info!("Metadata index written to: {}", index_path.display());

    info!(
        "Extracted {} effects to {}",
        sfx_file.effects.len(),
        output_path.display()
    );

    Ok(())
}