Convert wav files to .vag
This commit is contained in:
parent
746590eef3
commit
0dc1f522c5
|
@ -12,7 +12,7 @@ CLUT_4_COLOR_TRANS_FLAGS = simple-tim clut4 --color-trans
|
||||||
## Music tracks
|
## Music tracks
|
||||||
INPUT += $(OUTPUT_DIR)/Evacuation_cdda.xa
|
INPUT += $(OUTPUT_DIR)/Evacuation_cdda.xa
|
||||||
INPUT += $(OUTPUT_DIR)/fox.xa
|
INPUT += $(OUTPUT_DIR)/fox.xa
|
||||||
INPUT += $(OUTPUT_DIR)/apple.adpcm
|
INPUT += $(OUTPUT_DIR)/apple.vag
|
||||||
|
|
||||||
## Images
|
## Images
|
||||||
INPUT += $(OUTPUT_DIR)/TexturePage.img
|
INPUT += $(OUTPUT_DIR)/TexturePage.img
|
||||||
|
@ -37,9 +37,9 @@ $(OUTPUT_DIR)/fox.xa: audio/temp/fox.wav
|
||||||
@mkdir -p $(OUTPUT_DIR)
|
@mkdir -p $(OUTPUT_DIR)
|
||||||
jaby_engine_fconv $< -o $@ xa
|
jaby_engine_fconv $< -o $@ xa
|
||||||
|
|
||||||
$(OUTPUT_DIR)/%.adpcm: audio/temp/%.wav
|
$(OUTPUT_DIR)/%.vag: audio/temp/%.wav
|
||||||
@mkdir -p $(OUTPUT_DIR)
|
@mkdir -p $(OUTPUT_DIR)
|
||||||
jaby_engine_fconv $< -o $@ adpcm
|
jaby_engine_fconv $< -o $@ vag
|
||||||
|
|
||||||
$(OUTPUT_DIR)/%.xa: audio/%.wav
|
$(OUTPUT_DIR)/%.xa: audio/%.wav
|
||||||
@mkdir -p $(OUTPUT_DIR)
|
@mkdir -p $(OUTPUT_DIR)
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
</InterleavedFile>
|
</InterleavedFile>
|
||||||
</Directory>
|
</Directory>
|
||||||
<Directory name = "SFX" hidden = "true">
|
<Directory name = "SFX" hidden = "true">
|
||||||
<File name = "APPLE.ADP" lz4 = "none">../assets/bin/apple.adpcm</File>
|
<File name = "APPLE.VAG" lz4 = "none">../assets/bin/apple.vag</File>
|
||||||
</Directory>
|
</Directory>
|
||||||
</Filesystem>
|
</Filesystem>
|
||||||
<AudioTrack align = "true">../assets/audio/temp/breaking.wav</AudioTrack>
|
<AudioTrack align = "true">../assets/audio/temp/breaking.wav</AudioTrack>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "jaby_engine_fconv"
|
name = "jaby_engine_fconv"
|
||||||
version = "0.1.6"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
@ -8,7 +8,6 @@ panic = "abort"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = {version = "4.4.11", features = ["derive"]}
|
clap = {version = "4.4.11", features = ["derive"]}
|
||||||
hound = "3.5.1"
|
|
||||||
image = "0.24.7"
|
image = "0.24.7"
|
||||||
paste = "1.0.14"
|
paste = "1.0.14"
|
||||||
png = "0.17.10"
|
png = "0.17.10"
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
use clap::{Args, ValueEnum};
|
|
||||||
use hound::Sample;
|
|
||||||
use image::{DynamicImage, io::Reader as ImageReader};
|
|
||||||
use std::io::{Cursor, Write};
|
|
||||||
use tool_helper::{print_warning, Error, Input};
|
|
||||||
|
|
||||||
#[derive(Args)]
|
|
||||||
pub struct Arguments {
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn convert(input: Input, output: &mut dyn Write) -> Result<(), Error> {
|
|
||||||
let mut audio_io = hound::WavReader::new(input)?;
|
|
||||||
let header = audio_io.spec();
|
|
||||||
|
|
||||||
if header.sample_format != hound::SampleFormat::Int ||header.bits_per_sample != 16 {
|
|
||||||
return Err(Error::from_str("Only 16bit integer samples are supported"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if header.channels > 1 {
|
|
||||||
print_warning("Found more than one audio channel. First channel will be encoded.".to_owned());
|
|
||||||
}
|
|
||||||
|
|
||||||
let active_channel = 1;
|
|
||||||
let mut sample_count = 0;
|
|
||||||
for sample in audio_io.samples::<i16>() {
|
|
||||||
match sample {
|
|
||||||
Ok(sample) => {
|
|
||||||
sample_count += 1;
|
|
||||||
|
|
||||||
if sample_count%active_channel == 0 {
|
|
||||||
output.write(&sample.to_le_bytes())?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(error) => {
|
|
||||||
return Err(Error::from_text(format!("Failed iterating over samples: {}", error)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -1,2 +1,43 @@
|
||||||
pub mod adpcm;
|
pub mod xa;
|
||||||
pub mod xa;
|
pub mod vag;
|
||||||
|
|
||||||
|
use std::{env, path::PathBuf, process::Command};
|
||||||
|
use tool_helper::Error;
|
||||||
|
|
||||||
|
fn run_psxavenc<I, S>(input: PathBuf, output: PathBuf, args: I) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = S>,
|
||||||
|
S: AsRef<std::ffi::OsStr>, {
|
||||||
|
let psxavenc = get_psxavenc_path()?;
|
||||||
|
let result = Command::new(psxavenc).args(args).arg(input.to_string_lossy().as_ref()).arg(output.to_string_lossy().as_ref()).output()?;
|
||||||
|
|
||||||
|
let stderr = tool_helper::vec_helper::to_string(result.stderr)?;
|
||||||
|
let stdout = tool_helper::vec_helper::to_string(result.stdout)?;
|
||||||
|
|
||||||
|
if !result.status.success() {
|
||||||
|
return Err(Error::from_text(format!("psxavenc returned: {}. {}", result.status, stderr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !stdout.is_empty() {
|
||||||
|
println!("{}", stdout);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_psxavenc_path() -> Result<PathBuf, Error> {
|
||||||
|
let tool_path = {
|
||||||
|
let mut my_path = env::current_exe()?;
|
||||||
|
|
||||||
|
my_path.pop();
|
||||||
|
my_path.push("extern");
|
||||||
|
my_path.push("psxavenc");
|
||||||
|
|
||||||
|
my_path
|
||||||
|
};
|
||||||
|
|
||||||
|
if !tool_path.exists() {
|
||||||
|
return Err(Error::from_str("Could not locate psxavenc. Make sure it is installed under \"<Jaby Engine>/bin/extern\""));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(tool_path)
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
use clap::Args;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use tool_helper::Error;
|
||||||
|
|
||||||
|
#[derive(Args)]
|
||||||
|
pub struct Arguments {
|
||||||
|
frequency: Option<u32>
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn convert(args: Arguments, input: PathBuf, output: PathBuf) -> Result<(), Error> {
|
||||||
|
let mut cmd_args = vec!["-t", "vag"];
|
||||||
|
let frequency_str;
|
||||||
|
|
||||||
|
if let Some(frequency) = args.frequency {
|
||||||
|
frequency_str = frequency.to_string().to_owned();
|
||||||
|
|
||||||
|
cmd_args.push("-f");
|
||||||
|
cmd_args.push(frequency_str.as_ref());
|
||||||
|
}
|
||||||
|
|
||||||
|
super::run_psxavenc(input, output, cmd_args)
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
use clap::{Args, ValueEnum};
|
use clap::{Args, ValueEnum};
|
||||||
use std::{env, path::PathBuf, process::Command, str};
|
use std::{path::PathBuf, str};
|
||||||
use tool_helper::Error;
|
use tool_helper::Error;
|
||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
|
@ -43,39 +43,13 @@ impl Sample {
|
||||||
pub fn convert(args: Arguments, input: PathBuf, output: PathBuf) -> Result<(), Error> {
|
pub fn convert(args: Arguments, input: PathBuf, output: PathBuf) -> Result<(), Error> {
|
||||||
let quality = args.quality;
|
let quality = args.quality;
|
||||||
let sample = args.sample;
|
let sample = args.sample;
|
||||||
let tool_path = {
|
|
||||||
let mut my_path = env::current_exe()?;
|
super::run_psxavenc(input, output, [
|
||||||
|
|
||||||
my_path.pop();
|
|
||||||
my_path.push("extern");
|
|
||||||
my_path.push("psxavenc");
|
|
||||||
|
|
||||||
my_path
|
|
||||||
};
|
|
||||||
|
|
||||||
if !tool_path.exists() {
|
|
||||||
return Err(Error::from_str("Could not locate psxavenc. Make sure it is installed under \"<Jaby Engine>/bin/extern\""));
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = Command::new(tool_path).args([
|
|
||||||
"-t", "xacd",
|
"-t", "xacd",
|
||||||
"-f", quality.get_frequency().to_string().as_ref(),
|
"-f", quality.get_frequency().to_string().as_ref(),
|
||||||
"-b", "4",
|
"-b", "4",
|
||||||
"-c", sample.get_channel().to_string().as_ref(),
|
"-c", sample.get_channel().to_string().as_ref(),
|
||||||
"-F", "0",
|
"-F", "0",
|
||||||
"-C", "0",
|
"-C", "0",
|
||||||
input.to_string_lossy().as_ref(), output.to_string_lossy().as_ref()
|
])
|
||||||
]) .output()?;
|
|
||||||
|
|
||||||
let stderr = tool_helper::vec_helper::to_string(result.stderr)?;
|
|
||||||
let stdout = tool_helper::vec_helper::to_string(result.stdout)?;
|
|
||||||
|
|
||||||
if !result.status.success() {
|
|
||||||
return Err(Error::from_text(format!("psxavenc returned: {}. {}", result.status, stderr)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if !stdout.is_empty() {
|
|
||||||
println!("{}", stdout);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
|
@ -24,10 +24,22 @@ enum SubCommands {
|
||||||
// === Internal Commands ===
|
// === Internal Commands ===
|
||||||
Nothing,
|
Nothing,
|
||||||
SimpleTIM(reduced_tim::Arguments),
|
SimpleTIM(reduced_tim::Arguments),
|
||||||
ADPCM,
|
|
||||||
|
|
||||||
// === External Commands ===
|
// === External Commands ===
|
||||||
XA(xa::Arguments)
|
VAG(vag::Arguments),
|
||||||
|
XA(xa::Arguments),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubCommands {
|
||||||
|
pub fn is_external_command(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
SubCommands::Nothing => false,
|
||||||
|
SubCommands::SimpleTIM(_) => false,
|
||||||
|
|
||||||
|
SubCommands::VAG(_) => true,
|
||||||
|
SubCommands::XA(_) => true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_internal_conversion(cmd: CommandLine) -> Result<(), Error> {
|
fn run_internal_conversion(cmd: CommandLine) -> Result<(), Error> {
|
||||||
|
@ -48,8 +60,7 @@ fn run_internal_conversion(cmd: CommandLine) -> Result<(), Error> {
|
||||||
match cmd.sub_command {
|
match cmd.sub_command {
|
||||||
SubCommands::Nothing => nothing::copy(&mut input, dst_buffer),
|
SubCommands::Nothing => nothing::copy(&mut input, dst_buffer),
|
||||||
SubCommands::SimpleTIM(args) => reduced_tim::convert(args, input, dst_buffer),
|
SubCommands::SimpleTIM(args) => reduced_tim::convert(args, input, dst_buffer),
|
||||||
SubCommands::ADPCM => adpcm::convert(input, dst_buffer),
|
_ => Err(Error::from_str("External functions can not be called for internal conversion"))
|
||||||
_ => Err(Error::not_implemented("External functions can not be called for internal conversion"))
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -79,13 +90,14 @@ fn run_external_conversion(cmd: CommandLine) -> Result<(), Error> {
|
||||||
let output_file = cmd.output_file.ok_or(Error::from_str("Output has to be a file"))?;
|
let output_file = cmd.output_file.ok_or(Error::from_str("Output has to be a file"))?;
|
||||||
|
|
||||||
match cmd.sub_command {
|
match cmd.sub_command {
|
||||||
SubCommands::XA(args) => xa::convert(args, input_file, output_file),
|
SubCommands::VAG(args) => vag::convert(args, input_file, output_file),
|
||||||
_ => Err(Error::not_implemented("Internal functions can not be called for external conversion"))
|
SubCommands::XA(args) => xa::convert(args, input_file, output_file),
|
||||||
|
_ => Err(Error::from_str("Internal functions can not be called for external conversion"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_main(cmd: CommandLine) -> Result<(), Error> {
|
fn run_main(cmd: CommandLine) -> Result<(), Error> {
|
||||||
if matches!(cmd.sub_command, SubCommands::XA(_)) {
|
if cmd.sub_command.is_external_command() {
|
||||||
run_external_conversion(cmd)
|
run_external_conversion(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue