mirror of
https://github.com/G2-Games/lbee-utils.git
synced 2025-04-18 23:02:56 -05:00
Added rather unfortunate audio playback to pak explorer
This commit is contained in:
parent
1ffc88d379
commit
982f55fde6
4 changed files with 106 additions and 18 deletions
|
@ -67,6 +67,17 @@ impl Entry {
|
||||||
&self.data
|
&self.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the byte data of an entry, but fixed to be compatible with normal things
|
||||||
|
pub fn cloned_bytes_fixed(&self) -> Vec<u8> {
|
||||||
|
match self.file_type() {
|
||||||
|
EntryType::OGGPAK => {
|
||||||
|
dbg!(self.data[15]);
|
||||||
|
self.data[15..].to_vec()
|
||||||
|
},
|
||||||
|
_ => self.data.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn display_name(&self) -> String {
|
pub fn display_name(&self) -> String {
|
||||||
let mut name = self.name().clone().unwrap_or(self.id().to_string());
|
let mut name = self.name().clone().unwrap_or(self.id().to_string());
|
||||||
let entry_type = self.file_type();
|
let entry_type = self.file_type();
|
||||||
|
@ -88,6 +99,12 @@ impl Entry {
|
||||||
}
|
}
|
||||||
} else if self.data[0..3] == [b'M', b'V', b'T'] {
|
} else if self.data[0..3] == [b'M', b'V', b'T'] {
|
||||||
EntryType::MVT
|
EntryType::MVT
|
||||||
|
} else if self.data[0..4] == [b'R', b'I', b'F', b'F'] {
|
||||||
|
EntryType::WAV
|
||||||
|
} else if self.data[0..4] == [b'O', b'g', b'g', b'S'] {
|
||||||
|
EntryType::OGG
|
||||||
|
} else if self.data[0..6] == [b'O', b'G', b'G', b'P', b'A', b'K'] {
|
||||||
|
EntryType::OGGPAK
|
||||||
} else {
|
} else {
|
||||||
EntryType::Unknown
|
EntryType::Unknown
|
||||||
}
|
}
|
||||||
|
@ -96,6 +113,7 @@ impl Entry {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum EntryType {
|
pub enum EntryType {
|
||||||
|
// CZ image files
|
||||||
CZ0,
|
CZ0,
|
||||||
CZ1,
|
CZ1,
|
||||||
CZ2,
|
CZ2,
|
||||||
|
@ -106,6 +124,14 @@ pub enum EntryType {
|
||||||
/// An MVT video file
|
/// An MVT video file
|
||||||
MVT,
|
MVT,
|
||||||
|
|
||||||
|
/// OGG Audio file
|
||||||
|
OGG,
|
||||||
|
/// OGGPAK Audio file
|
||||||
|
OGGPAK,
|
||||||
|
|
||||||
|
/// Wav Audio file
|
||||||
|
WAV,
|
||||||
|
|
||||||
/// Who knows!
|
/// Who knows!
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
@ -121,6 +147,9 @@ impl EntryType {
|
||||||
Self::CZ4 => ".cz4",
|
Self::CZ4 => ".cz4",
|
||||||
Self::CZ5 => ".cz5",
|
Self::CZ5 => ".cz5",
|
||||||
Self::MVT => ".mvt",
|
Self::MVT => ".mvt",
|
||||||
|
Self::OGG => ".ogg",
|
||||||
|
Self::OGGPAK => ".oggpak",
|
||||||
|
Self::WAV => ".wav",
|
||||||
Self::Unknown => "",
|
Self::Unknown => "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ pub struct PakLimits {
|
||||||
impl Default for PakLimits {
|
impl Default for PakLimits {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
entry_limit: 10_000, // 10,000 entries
|
entry_limit: 100_000, // 100,000 entries
|
||||||
size_limit: u32::MAX as usize, // 10 gb
|
size_limit: u32::MAX as usize, // 10 gb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,14 +10,16 @@ authors.workspace = true
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
colog = "1.3.0"
|
colog = "1.3"
|
||||||
cz = { path = "../cz/" }
|
cz = { path = "../cz/" }
|
||||||
eframe = { version = "0.29", default-features = false, features = ["wayland", "x11", "accesskit", "default_fonts", "wgpu"] }
|
eframe = { version = "0.29", default-features = false, features = ["wayland", "x11", "accesskit", "default_fonts", "wgpu"] }
|
||||||
egui_extras = "0.29"
|
egui_extras = "0.29"
|
||||||
image = { version = "0.25", default-features = false, features = ["png"] }
|
image = { version = "0.25", default-features = false, features = ["png"] }
|
||||||
log = "0.4.22"
|
kira = "0.10"
|
||||||
|
log = "0.4"
|
||||||
luca_pak = { path = "../luca_pak/" }
|
luca_pak = { path = "../luca_pak/" }
|
||||||
rfd = "0.15"
|
rfd = "0.15"
|
||||||
|
symphonia = "0.5.4"
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
|
@ -2,11 +2,12 @@
|
||||||
|
|
||||||
use colog;
|
use colog;
|
||||||
use eframe::egui::{
|
use eframe::egui::{
|
||||||
self, ColorImage, Image, TextureFilter, TextureHandle, TextureOptions, ThemePreference,
|
self, ColorImage, Image, ProgressBar, TextureFilter, TextureHandle, TextureOptions, ThemePreference
|
||||||
};
|
};
|
||||||
|
use kira::{backend::Backend, sound::static_sound::{StaticSoundData, StaticSoundHandle}, AudioManager, AudioManagerSettings, DefaultBackend, Tween};
|
||||||
use log::error;
|
use log::error;
|
||||||
use luca_pak::{entry::EntryType, Pak};
|
use luca_pak::{entry::EntryType, Pak};
|
||||||
use std::fs;
|
use std::{fs, io::Cursor, time::Duration};
|
||||||
|
|
||||||
fn main() -> eframe::Result {
|
fn main() -> eframe::Result {
|
||||||
colog::default_builder()
|
colog::default_builder()
|
||||||
|
@ -18,13 +19,23 @@ fn main() -> eframe::Result {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let manager = AudioManager::<DefaultBackend>::new(AudioManagerSettings::default()).unwrap();
|
||||||
|
|
||||||
eframe::run_native(
|
eframe::run_native(
|
||||||
"LUCA PAK Explorer",
|
"LUCA PAK Explorer",
|
||||||
options,
|
options,
|
||||||
Box::new(|ctx| {
|
Box::new(|ctx| {
|
||||||
let ppp = ctx.egui_ctx.pixels_per_point() * 1.5;
|
let ppp = ctx.egui_ctx.pixels_per_point() * 1.5;
|
||||||
ctx.egui_ctx.set_pixels_per_point(ppp);
|
ctx.egui_ctx.set_pixels_per_point(ppp);
|
||||||
Ok(Box::<PakExplorer>::default())
|
Ok(Box::new(PakExplorer {
|
||||||
|
open_file: None,
|
||||||
|
selected_entry: None,
|
||||||
|
image_texture: None,
|
||||||
|
hex_string: None,
|
||||||
|
audio_player: manager,
|
||||||
|
audio_handle: None,
|
||||||
|
audio_duration: None,
|
||||||
|
}))
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -34,17 +45,9 @@ struct PakExplorer {
|
||||||
selected_entry: Option<luca_pak::entry::Entry>,
|
selected_entry: Option<luca_pak::entry::Entry>,
|
||||||
image_texture: Option<egui::TextureHandle>,
|
image_texture: Option<egui::TextureHandle>,
|
||||||
hex_string: Option<Vec<String>>,
|
hex_string: Option<Vec<String>>,
|
||||||
}
|
audio_player: AudioManager,
|
||||||
|
audio_handle: Option<StaticSoundHandle>,
|
||||||
impl Default for PakExplorer {
|
audio_duration: Option<Duration>,
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
open_file: None,
|
|
||||||
selected_entry: None,
|
|
||||||
image_texture: None,
|
|
||||||
hex_string: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl eframe::App for PakExplorer {
|
impl eframe::App for PakExplorer {
|
||||||
|
@ -67,6 +70,13 @@ impl eframe::App for PakExplorer {
|
||||||
self.selected_entry = None;
|
self.selected_entry = None;
|
||||||
self.image_texture = None;
|
self.image_texture = None;
|
||||||
self.hex_string = None;
|
self.hex_string = None;
|
||||||
|
|
||||||
|
if let Some(a) = self.audio_handle.as_mut() {
|
||||||
|
a.stop(Tween::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.audio_handle = None;
|
||||||
|
self.audio_duration = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(pak) = &self.open_file {
|
if let Some(pak) = &self.open_file {
|
||||||
|
@ -97,7 +107,7 @@ impl eframe::App for PakExplorer {
|
||||||
};
|
};
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
egui::ComboBox::from_id_source("my-combobox")
|
egui::ComboBox::from_id_salt("my-combobox")
|
||||||
.selected_text(selection.clone())
|
.selected_text(selection.clone())
|
||||||
.truncate()
|
.truncate()
|
||||||
.show_ui(ui, |ui| {
|
.show_ui(ui, |ui| {
|
||||||
|
@ -112,6 +122,13 @@ impl eframe::App for PakExplorer {
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
self.image_texture = None;
|
self.image_texture = None;
|
||||||
|
|
||||||
|
if let Some(a) = self.audio_handle.as_mut() {
|
||||||
|
a.stop(Tween::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.audio_handle = None;
|
||||||
|
self.audio_duration = None;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -203,6 +220,46 @@ impl eframe::App for PakExplorer {
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
EntryType::OGG
|
||||||
|
| EntryType::OGGPAK
|
||||||
|
| EntryType::WAV => {
|
||||||
|
ui.separator();
|
||||||
|
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
if ui.button("▶").clicked() && self.audio_handle.is_none() {
|
||||||
|
let sound_data = StaticSoundData::from_cursor(
|
||||||
|
Cursor::new(entry.cloned_bytes_fixed())
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.volume(-8.0);
|
||||||
|
|
||||||
|
self.audio_duration = Some(sound_data.duration());
|
||||||
|
self.audio_handle = Some(self.audio_player.play(sound_data.clone()).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ui.button("⏹").clicked() && self.audio_handle.is_some() {
|
||||||
|
self.audio_handle.as_mut().unwrap().stop(Tween::default());
|
||||||
|
self.audio_handle = None;
|
||||||
|
self.audio_duration = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(a) = &self.audio_handle {
|
||||||
|
let pos = a.position() as f32;
|
||||||
|
|
||||||
|
ui.add(ProgressBar::new(
|
||||||
|
pos / self.audio_duration.as_ref().unwrap().as_secs_f32()
|
||||||
|
).rounding(1.0).text(format!("{:02.0}:{:02.0}", pos / 60.0, pos % 60.0)));
|
||||||
|
|
||||||
|
if pos / self.audio_duration.as_ref().unwrap().as_secs_f32() > 0.99 {
|
||||||
|
self.audio_handle.as_mut().unwrap().stop(Tween::default());
|
||||||
|
self.audio_handle = None;
|
||||||
|
self.audio_duration = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.request_repaint_after(Duration::from_millis(50));
|
||||||
|
});
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
ui.centered_and_justified(|ui| ui.label("No Preview Available"));
|
ui.centered_and_justified(|ui| ui.label("No Preview Available"));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue