Improve SPU code and support state of voice

This commit is contained in:
Jaby 2024-09-24 22:21:58 +02:00
parent 6c94bca700
commit 332476cd4e
7 changed files with 59 additions and 67 deletions

View File

@ -11,7 +11,7 @@ namespace JabyEngine {
// TODO: Rename to sample...?
struct Voice {
size_t get_id() {
size_t get_id() const {
return reinterpret_cast<size_t>(this);
}
@ -33,11 +33,22 @@ namespace JabyEngine {
SPU_IO::Key::On.write(SPU_IO::KeyOn::for_specific(Voice::get_id()));
}
void play_if_end() {
if(Voice::is_end()) {
Voice::play();
}
}
void stop() {
SPU_IO::Key::Off.write(SPU_IO::KeyOff::for_specific(Voice::get_id()));
}
bool is_end() const {
// TODO: Make work in XEBRA
return SPU_IO::Key::Status.read().is_set(Voice::get_id());
}
};
extern Voice voice[SPU_IO::VoiceCount];
static auto& voice = __new_declare_io_port_array(Voice, SPU_IO::VoiceCount, 0x0);
}
}

View File

@ -4,23 +4,6 @@
namespace JabyEngine {
namespace SPU_IO_Values {
namespace internal {
template<typename T>
struct AliasUbus32IOPort : public IOPort<ubus32_t> {
T read() const {
return T{IOPort<ubus32_t>::read()};
}
void write(T value) {
IOPort<ubus32_t>::write(value.raw);
}
};
#define alias_ioport_ubus32(type) \
template<> \
struct IOPort<type> : public SPU_IO_Values::internal::AliasUbus32IOPort<type> {}
}
namespace MemoryMap {
static constexpr uintptr_t ADPCM = 0x01000;
}
@ -64,7 +47,7 @@ namespace JabyEngine {
}
};
__declare_io_value(Echo, ubus32_t) {
__declare_io_value(Echo, uint32_t) {
static constexpr auto EchoBits = BitRange::from_to(0, 23);
static constexpr Echo AllOff() {
@ -72,27 +55,27 @@ namespace JabyEngine {
}
};
__declare_io_value(KeyOff, ubus32_t) {
__declare_io_value(KeyOff, uint32_t) {
static constexpr KeyOff for_specific(uint32_t id) {
return KeyOff{ubus32_t::from(1 << id)};
return KeyOff{1u << id};
}
static constexpr KeyOff all() {
return KeyOff{ubus32_t::from(UI32_MAX)};
return KeyOff{UI32_MAX};
}
};
__declare_io_value(KeyOn, ubus32_t) {
__declare_io_value(KeyOn, uint32_t) {
static constexpr KeyOn for_specific(uint32_t id) {
return KeyOn{ubus32_t::from(1 << id)};
return KeyOn{1u << id};
}
static constexpr KeyOn all() {
return KeyOn{ubus32_t::from(UI32_MAX)};
return KeyOn{UI32_MAX};
}
};
__declare_io_value(KeyStatus, ubus32_t) {
__declare_io_value(KeyStatus, uint32_t) {
};
__declare_io_value(Noise, uint16_t) {
@ -103,7 +86,7 @@ namespace JabyEngine {
}
};
__declare_io_value(PitchModulation, ubus32_t) {
__declare_io_value(PitchModulation, uint32_t) {
static constexpr auto EnableBits = BitRange::from_to(1, 23);
static constexpr PitchModulation AllOff() {
@ -228,10 +211,4 @@ namespace JabyEngine {
}
};
}
alias_ioport_ubus32(SPU_IO_Values::Echo);
alias_ioport_ubus32(SPU_IO_Values::Noise);
alias_ioport_ubus32(SPU_IO_Values::KeyOff);
alias_ioport_ubus32(SPU_IO_Values::KeyOn);
alias_ioport_ubus32(SPU_IO_Values::KeyStatus);
alias_ioport_ubus32(SPU_IO_Values::PitchModulation);
}

View File

@ -65,15 +65,6 @@ namespace JabyEngine {
};
}
struct ubus32_t {
uint16_t low;
uint16_t high;
static constexpr ubus32_t from(uint32_t value) {
return {.low = static_cast<uint16_t>(value & 0xFFFF), .high = static_cast<uint16_t>(value >> 16)};
}
};
template<typename T>
struct IOPort {
using Value = T;
@ -89,25 +80,34 @@ namespace JabyEngine {
};
template<>
struct IOPort<ubus32_t> {
using Value = ubus32_t;
ubus32_t value;
struct IOPort<uint32_t>;
ubus32_t read() const {
auto*const cv_this = const_cast<const volatile IOPort<ubus32_t>*>(this);
template<typename T>
struct IOPort32 {
union ValueHelper {
struct {
uint16_t low;
uint16_t high;
};
T value;
};
using Value = T;
T value;
return {.low = cv_this->value.low, .high = cv_this->value.high};
T read() const {
const auto* cast_this = reinterpret_cast<const IOPort32<ValueHelper>*>(this);
const volatile auto* cv_this = const_cast<volatile decltype(cast_this)>(cast_this);
return ValueHelper{.low = cv_this->value.low, .high = cv_this->value.high}.value;
}
void write(ubus32_t value) {
auto*const cv_this = const_cast<volatile IOPort<ubus32_t>*>(this);
void write(T value) {
const auto new_value = ValueHelper{.value = value};
auto* cast_this = reinterpret_cast<IOPort32<ValueHelper>*>(this);
volatile auto* v_this = const_cast<volatile decltype(cast_this)>(cast_this);
cv_this->value.low = value.low;
cv_this->value.high = value.high;
}
void write(uint32_t value) {
IOPort<ubus32_t>::write(ubus32_t::from(value));
v_this->value.low = new_value.low;
v_this->value.high = new_value.high;
}
};

View File

@ -20,12 +20,12 @@ namespace JabyEngine {
using ADIO = IOPort<SPU_IO_Values::AD>;
using DataTransferControlIO = IOPort<SPU_IO_Values::DataTransferControl>;
using EchoIO = IOPort<SPU_IO_Values::Echo>;
using KeyOffIO = IOPort<SPU_IO_Values::KeyOff>;
using KeyOnIO = IOPort<SPU_IO_Values::KeyOn>;
using KeyStatusIO = IOPort<SPU_IO_Values::KeyStatus>;
using EchoIO = IOPort32<SPU_IO_Values::Echo>;
using KeyOffIO = IOPort32<SPU_IO_Values::KeyOff>;
using KeyOnIO = IOPort32<SPU_IO_Values::KeyOn>;
using KeyStatusIO = IOPort32<SPU_IO_Values::KeyStatus>;
using NoiseIO = IOPort<SPU_IO_Values::Noise>;
using PitchModulationIO = IOPort<SPU_IO_Values::PitchModulation>;
using PitchModulationIO = IOPort32<SPU_IO_Values::PitchModulation>;
using SampleRateIO = IOPort<SPU_IO_Values::SampleRate>;
using SimpleVolumeIO = IOPort<SPU_IO_Values::SimpleVolume>;
using StatusRegisterIO = IOPort<SPU_IO_Values::StatusRegister>;

View File

@ -3,6 +3,7 @@
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

@ -52,11 +52,14 @@ namespace JabyEngine {
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 bytes = header.get_sample_size();
const auto words = bytes_to_words(header.get_sample_size());
const auto bytes = words_to_bytes(words);
state.words_left = bytes_to_words(bytes);
state.words_left = words;
auto sram_adr = SPU::voice[state.voice_id].allocate(SPU_IO::SampleRate::from_HZ(header.get_sample_frequency()), words_to_bytes(state.words_left));
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));