Merge branch 'ToolBox_TODOs_SupportSFX' into ToolBox_TODOs

This commit is contained in:
2024-09-28 13:02:26 +02:00
38 changed files with 977 additions and 299 deletions

View File

@@ -65,21 +65,21 @@ namespace JabyEngine {
GPU_IO::GP1.write(GPU_IO::Command::ResetCMDBufer());
}
namespace DMA {
struct DMA {
#ifdef __SUPPORT_PS3__
// The PS3 doesn't autoincrement the GPU MADR register so we have to do it
extern uintptr_t MADR;
static uintptr_t MADR;
#endif // __SUPPORT_PS3__
static void wait() {
::JabyEngine::DMA_IO::GPU.wait();
DMA_IO::GPU.wait();
}
static void end() {
reset_cmd_buffer();
}
namespace Receive {
struct Receive {
static void prepare() {
GPU_IO::GP1.write(GPU_IO::Command::DMADirection(GPU_IO::DMADirection::CPU2GPU));
reset_cmd_buffer();
@@ -87,7 +87,7 @@ namespace JabyEngine {
static void set_src(uintptr_t adr) {
#ifdef __SUPPORT_PS3__
MADR = adr;
DMA::MADR = adr;
#else
DMA_IO::GPU.set_adr(adr);
#endif // __SUPPORT_PS3__
@@ -101,17 +101,17 @@ namespace JabyEngine {
}
static void start(uint16_t blockCount, uint16_t wordsPerBlock = 0x10) {
typedef DMA_IO::BCR::SyncMode1 SyncMode1;
using SyncMode1 = DMA_IO::BCR::SyncMode1;
#ifdef __SUPPORT_PS3__
DMA_IO::GPU.set_adr(MADR);
MADR += (blockCount * wordsPerBlock) << 2;
DMA::MADR += (blockCount * wordsPerBlock) << 2;
#endif // __SUPPORT_PS3__
DMA_IO::GPU.block_ctrl.write(DMA_IO::BCR::from(SyncMode1::BlockSize.with(wordsPerBlock), SyncMode1::BlockAmount.with(blockCount)));
DMA_IO::GPU.channel_ctrl.write(DMA_IO::CHCHR::StartGPUReceive());
}
}
}
};
};
}
}
}

View File

@@ -0,0 +1,44 @@
#pragma once
#include <PSX/System/IOPorts/dma_io.hpp>
#include <PSX/SPU/spu.hpp>
namespace JabyEngine {
namespace SPU {
namespace internal {
struct DMA {
static void wait() {
DMA_IO::SPU.wait();
while(SPU_IO::StatusRegister.read().is_set(SPU_IO_Values::StatusRegister::TransferBusy));
}
static void end() {
SPU_IO::ControlRegister.set_transfer_mode(SPU_IO::ControlRegister::Stop);
}
struct Receive {
static void prepare() {
end();
SPU_IO::DataTransferControl.write(SPU_IO::DataTransferControl::NormalTransferMode());
SPU_IO::ControlRegister.set_transfer_mode(SPU_IO::ControlRegister::Stop);
}
static void set_src(uintptr_t adr) {
DMA_IO::SPU.set_adr(adr);
}
static void set_dst(SPU::SRAMAdr adr) {
SPU_IO::SRAMTransferAdr.write(adr);
SPU_IO::ControlRegister.set_transfer_mode(SPU_IO::ControlRegister::DMAWrite);
}
static void start(uint16_t blockCount, uint16_t wordsPerBlock = 0x10) {
using SyncMode1 = DMA_IO::BCR::SyncMode1;
DMA_IO::SPU.block_ctrl.write(DMA_IO::BCR::from(SyncMode1::BlockSize.with(wordsPerBlock), SyncMode1::BlockAmount.with(blockCount)));
DMA_IO::SPU.channel_ctrl.write(DMA_IO::CHCHR::StartSPUReceive());
}
};
};
}
}
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include <PSX/jabyengine.hpp>
namespace JabyEngine {
namespace SPU_MMU {
// TODO: Make this work with words? Word align?
const uint8_t* allocate(uint8_t voice, size_t size);
void deallocate(uint8_t voice);
}
}

View File

@@ -8,7 +8,7 @@ namespace JabyEngine {
using namespace SPU_IO;
static void clear_main_volume() {
static constexpr auto StartVol = SweepVolume::from(SweepVolume::VolumeEnable, SweepVolume::Volume.with(static_cast<int16_t>(I16_MAX >> 2)));
static constexpr auto StartVol = SweepVolume::from(SweepVolume::VolumeMode::Enable, SweepVolume::VolumeMode::Volume.with(SweepVolume::VolumeMode::MaxVolume >> 1));
MainVolume::Left.write(StartVol);
MainVolume::Right.write(StartVol);
@@ -18,37 +18,37 @@ namespace JabyEngine {
CDVolume::Left.write(0.75_vol);
CDVolume::Right.write(0.75_vol);
ExternalAudioInputVolume::Left.write({0});
ExternalAudioInputVolume::Right.write({0});
ExternalAudioInputVolume::Left.write(SimpleVolume::mute());
ExternalAudioInputVolume::Right.write(SimpleVolume::mute());
}
static void clear_voice() {
for(auto& voice : SPU_IO::Voice) {
voice.volumeLeft.write({0});
voice.volumeRight.write({0});
voice.sampleRate.write({0});
voice.ad.write({0});
voice.sr.write({0});
voice.currentVolume.write({0});
voice.volumeLeft.write(SweepVolume::mute());
voice.volumeRight.write(SweepVolume::mute());
voice.sampleRate.write(SampleRate::stop());
voice.ad.write(AD::none());
voice.sr.write(SR::none());
voice.adsr_volume.write(SimpleVolume::mute());
voice.adr.write(Voice::start_adr());
voice.repeatAdr.write(Voice::start_adr());
voice.adr.write(SRAMAdr::adpcm_start());
voice.repeatAdr.write(SRAMAdr::adpcm_start());
}
}
static void clear_pmon() {
SPU_IO::PMON.write({0});
SPU_IO::PMON.write(PitchModulation::AllOff());
}
static void clear_noise_and_echo() {
SPU_IO::NON.write({0});
SPU_IO::EON.write({0});
SPU_IO::NON.write(Noise::AllOff());
SPU_IO::EON.write(Echo::AllOff());
}
static void clear_reverb() {
Reverb::Volume::Left.write({0});
Reverb::Volume::Right.write({0});
Reverb::WorkAreaAdr.write({0});
Reverb::Volume::Left.write(SimpleVolume::mute());
Reverb::Volume::Right.write(SimpleVolume::mute());
Reverb::WorkAreaAdr.write(SRAMAdr::null());
}
static void setup_control_register() {
@@ -57,25 +57,19 @@ namespace JabyEngine {
SPU_IO::ControlRegister.write(SetupValue);
}
static void setup_data_transfer_control() {
static constexpr struct DataTransferControl RequiredValue{(2 << 1)};
DataTransferControl.write(RequiredValue);
}
static void wait_voices() {
static constexpr SimpleVolume Treshhold{static_cast<int16_t>(I16_MAX*0.03)};
static constexpr auto Treshhold = SimpleVolume::mute();
try_again:
for(const auto& voice : SPU_IO::Voice) {
if(voice.currentVolume.read() > Treshhold) {
if(voice.adsr_volume.read() > Treshhold) {
goto try_again;
}
}
}
void stop_voices() {
SPU_IO::Key::Off.write({UI32_MAX});
SPU_IO::Key::Off.write(KeyOff::all());
}
void setup() {
@@ -88,7 +82,6 @@ namespace JabyEngine {
clear_noise_and_echo();
clear_reverb();
setup_data_transfer_control();
setup_control_register();
}
}

View File

@@ -2,7 +2,10 @@
#include "../../internal-include/GPU/gpu_internal.hpp"
#include <stdio.hpp>
#include "../../internal-include/SPU/spu_mmu.hpp"
#include <PSX/GTE/gte.hpp>
#include <PSX/SPU/spu.hpp>
#include <PSX/System/IOPorts/spu_io.hpp>
#include <PSX/System/syscalls.hpp>
extern "C" uint32_t __heap_start;
@@ -39,6 +42,26 @@ namespace JabyEngine {
}
}
static void test_spu_alloc() {
static const auto calculate_spu_adr = [](size_t size) -> const uint8_t* {
return reinterpret_cast<const uint8_t*>(SPU_IO::MemoryMap::ADPCM + size);
};
static const auto simple_assert = [](uint32_t test_id, const uint8_t* adr, const uint8_t* expected) {
static const char* ok_text = "Test %i: 0x%p == 0x%p; OK\n";
static const char* failed_text = "Test %i: 0x%p != 0x%p; Failed\n";
printf(adr == expected ? ok_text : failed_text, test_id, adr, expected);
};
printf("=== SPU test ===\n");
simple_assert(0, SPU_MMU::allocate(0, 0x600), calculate_spu_adr(0x0));
simple_assert(1, SPU_MMU::allocate(1, 0x800), calculate_spu_adr(0x600));
simple_assert(2, SPU_MMU::allocate(0, 0x300), calculate_spu_adr(0x0));
simple_assert(3, SPU_MMU::allocate(2, 0x300), calculate_spu_adr(0x300));
// TODO: More tests
}
namespace boot {
namespace Start {
// Thanks to Nicolas Noble!
@@ -77,6 +100,7 @@ namespace JabyEngine {
GTE::setup();
test_bios_font();
test_gte_scale();
test_spu_alloc();
SPU::setup();
}

View File

@@ -37,11 +37,17 @@ namespace JabyEngine {
}(file, buf_cfg, is_lz4);
switch(file.type) {
case CDFileType::SimpleTIM:
return FileProcessor::create(data_adr, file.payload.simple_tim);
case CDFileType::CopyTo:
return FileProcessor::create(data_adr, Nothing());
case CDFileType::SimpleTIM:
return FileProcessor::create(data_adr, file.payload.simple_tim);
#ifdef __SUPPORT_VAG__
case CDFileType::SonyVAG:
return FileProcessor::create(data_adr, file.payload.vag);
#endif //__SUPPORT_VAG__
default:
return FileProcessor::create_custom(data_adr, static_cast<CDFileType_t>(file.type) - static_cast<CDFileType_t>(CDFileType::Custom), file.payload);
}

View File

@@ -10,7 +10,7 @@ namespace JabyEngine {
}
State create(const uint32_t* data_adr, const Nothing& nothing) {
return State::from(NothingState(), reinterpret_cast<const uint8_t*>(data_adr), parse_nothing);
return State::from(NothingState(), data_adr, parse_nothing);
}
}
}

View File

@@ -1,7 +1,6 @@
#include "../../../internal-include/GPU/gpu_internal.hpp"
#include <PSX/File/file_processor_helper.hpp>
#include <PSX/GPU/gpu_types.hpp>
#include <limits.hpp>
#include <stdio.hpp>
namespace JabyEngine {
@@ -63,44 +62,12 @@ namespace JabyEngine {
}
static Progress parse_data(State::Configuration& config, SimpleTIMState& state) {
const auto config_data_words = (config.data_bytes/sizeof(uint32_t));
const auto words_to_use = (config_data_words > state.words_left) ? state.words_left : config_data_words;
bool is_last = (words_to_use == state.words_left);
auto block_count = (words_to_use >> 4);
const auto [words_to_use, is_last] = Helper::DMA::WordsReady::calculate(config, state.words_left);
const auto words_used = Helper::DMA::send_words<GPU::internal::DMA>(words_to_use, is_last);
while(block_count > 0) {
const auto block_send = (block_count > UI16_MAX) ? UI16_MAX : block_count;
// Send data!
GPU::internal::DMA::wait();
GPU::internal::DMA::Receive::start(block_send);
block_count -= block_send;
}
if(is_last) {
// Send words
const auto last_words = (words_to_use & 0b1111);
if(last_words > 0) {
GPU::internal::DMA::wait();
GPU::internal::DMA::Receive::start(1, last_words);
}
GPU::internal::DMA::wait();
GPU::internal::DMA::end();
state.words_left = 0;
config.processed(words_to_use*sizeof(uint32_t));
return Progress::Done;
}
else {
const auto words_used = (words_to_use & ~0b1111);
state.words_left -= words_used;
config.processed(words_used*sizeof(uint32_t));
return Progress::InProgress;
}
state.words_left -= words_used;
config.processed(words_used*sizeof(uint32_t));
return is_last ? Progress::Done : Progress::InProgress;
}
static Progress switch_state_parse_data(State::Configuration& config, SimpleTIMState& state) {
@@ -139,7 +106,7 @@ namespace JabyEngine {
}
State create(const uint32_t* data_adr, const SimpleTIM& file) {
return State::from(SimpleTIMState(file), reinterpret_cast<const uint8_t*>(data_adr), parse_header);
return State::from(SimpleTIMState(file), data_adr, parse_header);
}
}
}

View File

@@ -0,0 +1,81 @@
#include "../../../internal-include/SPU/spu_internal.hpp"
#include <PSX/Auxiliary/big_endian.hpp>
#include <PSX/Auxiliary/word_helper.hpp>
#include <PSX/File/file_processor_helper.hpp>
#include <PSX/SPU/spu.hpp>
#include <stdio.hpp>
#ifdef __SUPPORT_VAG__
namespace JabyEngine {
namespace FileProcessor {
struct VAGHeader {
char id[4];
uint32_t version;
uint32_t reserved;
uint32_t sample_size;
uint32_t sample_frequency;
uint8_t reserved_2[12];
char name[16];
constexpr uint32_t get_version() const {
return read_be(this->version);
}
constexpr uint32_t get_sample_size() const {
return read_be(this->sample_size);
}
constexpr uint32_t get_sample_frequency() const {
return read_be(this->sample_frequency);
}
};
struct VAGState {
uint32_t voice_id;
size_t words_left;
SPU::SimpleVolume inital_vol;
static constexpr VAGState create(uint32_t voice_id, SPU::SimpleVolume inital_vol) {
return VAGState{.voice_id = voice_id, .words_left = 0, .inital_vol = inital_vol};
}
};
static Progress parse_sample(State::Configuration& config, VAGState& state) {
const auto [words_to_use, is_last] = Helper::DMA::WordsReady::calculate(config, state.words_left);
const auto words_used = Helper::DMA::send_words<SPU::internal::DMA>(words_to_use, is_last);
state.words_left -= words_used;
config.processed(words_used*sizeof(uint32_t));
return is_last ? Progress::Done : Progress::InProgress;
}
static Progress parse_header(State::Configuration& config, VAGState& state) {
if(config.data_bytes >= sizeof(VAGHeader)) {
const auto& header = *reinterpret_cast<const VAGHeader*>(config.data_adr);
const auto words = bytes_to_words(header.get_sample_size());
const auto bytes = words_to_bytes(words);
state.words_left = words;
auto sram_adr = SPU::voice[state.voice_id].allocate(SPU_IO::SampleRate::from_HZ(header.get_sample_frequency()), bytes);
// TODO: Keep this as optional?
printf("SPU: Allocated %i @0x%p to 0x%p (%i bytes)\n", state.voice_id, sram_adr.raw, (sram_adr.raw + bytes), bytes);
SPU::voice[state.voice_id].set_volume(state.inital_vol, state.inital_vol);
config.processed(sizeof(VAGHeader));
SPU::internal::DMA::Receive::prepare();
SPU::internal::DMA::Receive::set_dst(sram_adr);
SPU::internal::DMA::Receive::set_src(reinterpret_cast<uintptr_t>(config.data_adr));
return Helper::exchange_and_execute_process_function(parse_sample, config, state);
}
return Progress::InProgress;
}
State create(const uint32_t* data_adr, const VAG& file) {
return State::from(VAGState::create(file.voice_number, file.inital_stereo_vol), data_adr, parse_header);
}
}
}
#endif // __SUPPORT_VAG__

View File

@@ -8,11 +8,9 @@ namespace JabyEngine {
uint8_t Display :: current_id = 1; //< Setup will call exchange and set it to 0
namespace internal {
namespace DMA {
#ifdef __SUPPORT_PS3__
uintptr_t MADR = 0;
#endif // __SUPPORT_PS3__
}
#ifdef __SUPPORT_PS3__
uintptr_t DMA :: MADR = 0;
#endif // __SUPPORT_PS3__
static SysCall::InterruptVerifierResult interrupt_verifier();
static void interrupt_handler(uint32_t);

View File

@@ -0,0 +1,31 @@
#include "../../internal-include/SPU/spu_internal.hpp"
#include "../../internal-include/SPU/spu_mmu.hpp"
#include <PSX/System/IOPorts/spu_io.hpp>
#include <PSX/SPU/spu.hpp>
#include <stddef.hpp>
#include <stdio.hpp>
namespace JabyEngine {
namespace SPU {
SRAMAdr Voice :: allocate(size_t size) {
Voice::stop();
const auto voice_id = Voice::get_id();
const auto adr = SRAMAdr{static_cast<SRAMAdr::UnderlyingType>(reinterpret_cast<uintptr_t>(SPU_MMU::allocate(voice_id, size)))};
SPU_IO::Voice[voice_id].adr.write(adr);
return adr;
}
SRAMAdr Voice :: allocate(SPU_IO::SampleRate frequency, size_t size) {
const auto result = Voice::allocate(size);
Voice::set_sample_rate(frequency);
return result;
}
void Voice :: deallocate() {
Voice::stop();
SPU_MMU::deallocate(Voice::get_id());
}
}
}

View File

@@ -0,0 +1,125 @@
#include "../../internal-include/SPU/spu_mmu.hpp"
#include <PSX/System/IOPorts/spu_io.hpp>
#include <PSX/Auxiliary/math_helper.hpp>
#include <PSX/SPU/spu.hpp>
#include <stddef.hpp>
namespace JabyEngine {
namespace SPU_MMU {
namespace SPU_MemoryMap = SPU_IO::MemoryMap;
struct SPUMemory {
// TODO: v change to uint16_t??
const uint8_t* adr;
size_t size;
static SPUMemory create(size_t size) {
return SPUMemory{.adr = reinterpret_cast<const uint8_t*>(SPU_MemoryMap::ADPCM), .size = size};
}
constexpr void clear() {
this->adr = nullptr;
this->size = 0;
}
constexpr const uint8_t* get_end_adr() const {
return (this->adr + this->size);
}
constexpr bool is_free() const {
return this->adr == nullptr;
}
constexpr bool intersects(const SPUMemory& other) const {
const auto* min = max_of(this->adr, other.adr);
const auto* max = min_of(this->get_end_adr(), other.get_end_adr());
return min < max;
}
};
struct AllocatedVoice {
SPUMemory memory;
AllocatedVoice* next_entry;
};
struct VoiceManager {
struct Iterator {
AllocatedVoice* *prev_voice;
AllocatedVoice* current_voice;
void next() {
this->prev_voice = &this->current_voice->next_entry;
this->current_voice = this->current_voice->next_entry;
}
bool has_next() const {
return this->current_voice;
}
operator bool() const {
return Iterator::has_next();
}
};
AllocatedVoice allocated_voice_buffer[SPU_IO::VoiceCount + SPU_IO::ReverbCount] = {0};
AllocatedVoice* first_allocated_voice = nullptr;
Iterator iterator() {
return Iterator{.prev_voice = &this->first_allocated_voice, .current_voice = this->first_allocated_voice};
}
AllocatedVoice& get_voice(uint8_t id) {
return this->allocated_voice_buffer[id];
}
};
static VoiceManager voice_mgr;
using MemoryFoundCallback = const uint8_t* (AllocatedVoice& new_entry, AllocatedVoice* &prev_entry, AllocatedVoice* next_entry);
static const uint8_t* verify_and_add(AllocatedVoice& new_entry, AllocatedVoice* &prev_entry, AllocatedVoice* next_entry) {
// TODO: Verify that we are not crashing into reverb or that we are higher then SPU
prev_entry = &new_entry;
new_entry.next_entry = next_entry;
return new_entry.memory.adr;
}
static const uint8_t* find_first_fit(AllocatedVoice &new_entry, MemoryFoundCallback memory_found) {
auto iterator = voice_mgr.iterator();
while(iterator) {
if(!iterator.current_voice->memory.intersects(new_entry.memory)) {
break;
}
new_entry.memory.adr = iterator.current_voice->memory.get_end_adr();
iterator.next();
}
return memory_found(new_entry, *iterator.prev_voice, iterator.current_voice);
}
const uint8_t* allocate(uint8_t voice, size_t size) {
auto& voice_entry = voice_mgr.get_voice(voice);
if(!voice_entry.memory.is_free()) {
deallocate(voice);
}
voice_entry.memory = SPUMemory::create(size);
return find_first_fit(voice_entry, verify_and_add);
}
void deallocate(uint8_t voice) {
auto* voice_adr = &voice_mgr.get_voice(voice);
auto iterator = voice_mgr.iterator();
voice_adr->memory.clear();
while(iterator) {
if(iterator.current_voice == voice_adr) {
*iterator.prev_voice = voice_adr->next_entry;
break;
}
iterator.next();
}
}
}
}

View File

@@ -1,6 +1,6 @@
[package]
name = "jaby_engine_fconv"
version = "0.1.6"
version = "0.2.0"
edition = "2021"
[profile.release]

View File

@@ -1 +1,43 @@
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)
}

View File

@@ -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)
}

View File

@@ -1,5 +1,5 @@
use clap::{Args, ValueEnum};
use std::{env, path::PathBuf, process::Command, str};
use std::{path::PathBuf, str};
use tool_helper::Error;
#[derive(Args)]
@@ -43,39 +43,13 @@ impl Sample {
pub fn convert(args: Arguments, input: PathBuf, output: PathBuf) -> Result<(), Error> {
let quality = args.quality;
let sample = args.sample;
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\""));
}
let result = Command::new(tool_path).args([
super::run_psxavenc(input, output, [
"-t", "xacd",
"-f", quality.get_frequency().to_string().as_ref(),
"-b", "4",
"-c", sample.get_channel().to_string().as_ref(),
"-F", "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(())
])
}

View File

@@ -21,9 +21,25 @@ struct CommandLine {
#[derive(Subcommand)]
enum SubCommands {
// === Internal Commands ===
Nothing,
SimpleTIM(reduced_tim::Arguments),
XA(xa::Arguments)
// === External Commands ===
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> {
@@ -44,7 +60,7 @@ fn run_internal_conversion(cmd: CommandLine) -> Result<(), Error> {
match cmd.sub_command {
SubCommands::Nothing => nothing::copy(&mut input, dst_buffer),
SubCommands::SimpleTIM(args) => reduced_tim::convert(args, input, dst_buffer),
_ => Err(Error::not_implemented("External functions can not be called for internal conversion"))
_ => Err(Error::from_str("External functions can not be called for internal conversion"))
}
};
@@ -74,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"))?;
match cmd.sub_command {
SubCommands::XA(args) => xa::convert(args, input_file, output_file),
_ => Err(Error::not_implemented("Internal functions can not be called for external conversion"))
SubCommands::VAG(args) => vag::convert(args, input_file, output_file),
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> {
if matches!(cmd.sub_command, SubCommands::XA(_)) {
if cmd.sub_command.is_external_command() {
run_external_conversion(cmd)
}