summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKiritoDv <kiritodev01@gmail.com>2025-02-06 21:33:39 -0600
committerKiritoDv <kiritodev01@gmail.com>2025-02-06 21:33:39 -0600
commit784db6dcaed6e597fbe74e826e73cf94b874c9af (patch)
treea9d76839fd7fb25102db31200e45abada7f50b9b
parent6a52c9a2ae9290247062744bb9e69f6b6c3b49c9 (diff)
WIP Sequence importerseq-importer
-rw-r--r--src/audio/audio_load.c8
-rw-r--r--src/port/resource/importers/audio/SequenceFactory.cpp311
-rw-r--r--src/port/resource/importers/audio/SequenceFactory.h4
-rw-r--r--src/port/resource/loaders/AudioLoader.cpp5
4 files changed, 327 insertions, 1 deletions
diff --git a/src/audio/audio_load.c b/src/audio/audio_load.c
index c5804b62..3b4fbff2 100644
--- a/src/audio/audio_load.c
+++ b/src/audio/audio_load.c
@@ -402,6 +402,7 @@ void AudioLoad_SyncInitSeqPlayerInternal(s32 playerIdx, s32 seqId, s32 arg2) {
AudioLoad_SyncLoadFont(fontId);
}
+ printf("seqId: %d\n", seqId);
seqData = AudioLoad_SyncLoadSeq(seqId);
AudioSeq_ResetSequencePlayer(playerIdx);
@@ -416,8 +417,15 @@ void AudioLoad_SyncInitSeqPlayerInternal(s32 playerIdx, s32 seqId, s32 arg2) {
gSeqPlayers[playerIdx].finished = false;
}
+char* WriteDummySequence();
+
void* AudioLoad_SyncLoadSeq(s32 seqId) {
+ // if(seqId == 9 || seqId == 21){
+ // return WriteDummySequence();
+ // }
AudioTable* table = AudioLoad_GetLoadTable(SEQUENCE_TABLE);
+ char* seqPath = ResourceGetNameByCrc((uint64_t) table->entries[seqId].romAddr);
+ printf("seqPath: %s\n", seqPath);
return ResourceGetDataByCrc((uint64_t) table->entries[seqId].romAddr);
}
diff --git a/src/port/resource/importers/audio/SequenceFactory.cpp b/src/port/resource/importers/audio/SequenceFactory.cpp
new file mode 100644
index 00000000..bc7728e3
--- /dev/null
+++ b/src/port/resource/importers/audio/SequenceFactory.cpp
@@ -0,0 +1,311 @@
+#include "SequenceFactory.h"
+#include "BinaryWriter.h"
+#include <type_traits>
+
+template <typename T> static void WriteInsnOneArg(Ship::BinaryWriter* writer, uint8_t opcode, T arg) {
+ static_assert(std::is_fundamental<T>::value);
+ writer->Write(opcode);
+ writer->Write(arg);
+}
+
+template <typename T1, typename T2>
+static void WriteInsnTwoArg(Ship::BinaryWriter* writer, uint8_t opcode, T1 arg1, T2 arg2) {
+ static_assert(std::is_fundamental<T1>::value && std::is_fundamental<T2>::value);
+ writer->Write(opcode);
+ writer->Write(arg1);
+ writer->Write(arg2);
+}
+
+template <typename T1, typename T2, typename T3>
+static void WriteInsnThreeArg(Ship::BinaryWriter* writer, uint8_t opcode, T1 arg1, T2 arg2, T3 arg3) {
+ static_assert(std::is_fundamental<T1>::value && std::is_fundamental<T2>::value);
+ writer->Write(opcode);
+ writer->Write(arg1);
+ writer->Write(arg2);
+ writer->Write(arg3);
+}
+
+static void WriteInsnNoArg(Ship::BinaryWriter* writer, uint8_t opcode) {
+ writer->Write(opcode);
+}
+
+static void WriteLegato(Ship::BinaryWriter* writer) {
+ WriteInsnNoArg(writer, 0xC4);
+}
+
+static void WriteNoLegato(Ship::BinaryWriter* writer) {
+ WriteInsnNoArg(writer, 0xC5);
+}
+
+static void WriteMuteBhv(Ship::BinaryWriter* writer, uint8_t arg) {
+ WriteInsnOneArg(writer, 0xD3, arg);
+}
+
+static void WriteMuteScale(Ship::BinaryWriter* writer, uint8_t arg) {
+ WriteInsnOneArg(writer, 0xD5, arg);
+}
+
+static void WriteInitchan(Ship::BinaryWriter* writer, uint16_t channels) {
+ WriteInsnOneArg(writer, 0xD7, channels);
+}
+
+static void WriteLdchan(Ship::BinaryWriter* writer, uint8_t channel, uint16_t offset) {
+ WriteInsnOneArg(writer, 0x90 | channel, offset);
+}
+
+static void WriteVolSHeader(Ship::BinaryWriter* writer, uint8_t vol) {
+ WriteInsnOneArg(writer, 0xDB, vol);
+}
+
+static void WriteVolCHeader(Ship::BinaryWriter* writer, uint8_t vol) {
+ WriteInsnOneArg(writer, 0xDF, vol);
+}
+
+static void WriteTempo(Ship::BinaryWriter* writer, uint8_t tempo) {
+ WriteInsnOneArg(writer, 0xDD, tempo);
+}
+
+static void WriteJump(Ship::BinaryWriter* writer, uint16_t offset) {
+ WriteInsnOneArg(writer, 0xFB, offset);
+}
+
+static void WriteDisablecan(Ship::BinaryWriter* writer, uint16_t channels) {
+ WriteInsnOneArg(writer, 0xD6, channels);
+}
+
+static void WriteNoshort(Ship::BinaryWriter* writer) {
+ WriteInsnNoArg(writer, 0xC4);
+}
+
+// TODO: This is different on sf64
+static void WriteLdlayer(Ship::BinaryWriter* writer, uint8_t layer, uint16_t offset) {
+ WriteInsnOneArg(writer, 0x90 | layer, offset);
+}
+
+static void WritePan(Ship::BinaryWriter* writer, uint8_t pan) {
+ WriteInsnOneArg(writer, 0xDD, pan);
+}
+
+static void WriteBend(Ship::BinaryWriter* writer, uint8_t bend) {
+ WriteInsnOneArg(writer, 0xD3, bend);
+}
+
+static void WriteInstrument(Ship::BinaryWriter* writer, uint8_t instrument) {
+ WriteInsnOneArg(writer, 0xC1, instrument);
+}
+
+static void WriteTranspose(Ship::BinaryWriter* writer, int8_t transpose) {
+ WriteInsnOneArg(writer, 0xC2, transpose);
+}
+
+static void WriteDelay(Ship::BinaryWriter* writer, uint16_t delay) {
+ if (delay > 0x7F) {
+ WriteInsnOneArg(writer, 0xFD, static_cast<uint16_t>(delay | 0x8000));
+ } else {
+ WriteInsnOneArg(writer, 0xFD, static_cast<uint8_t>(delay));
+ }
+}
+
+template <typename T> static void WriteLDelay(Ship::BinaryWriter* writer, T delay) {
+ WriteInsnOneArg(writer, 0xC0, delay);
+}
+
+template <typename T> static void WriteNotedv(Ship::BinaryWriter* writer, uint8_t note, T delay, uint8_t velocity) {
+ WriteInsnTwoArg(writer, note, delay, velocity);
+}
+
+static void WriteNotedvg(Ship::BinaryWriter* writer, uint8_t note, uint16_t delay, uint8_t velocity, uint8_t gateTime) {
+ if (delay > 0x7F) {
+ WriteInsnThreeArg(writer, note, static_cast<uint16_t>(delay | 0x8000), velocity, gateTime);
+ } else {
+ WriteInsnThreeArg(writer, note, static_cast<uint8_t>(delay), velocity, gateTime);
+ }
+}
+
+static void WriteMonoSingleSeq(Ship::BinaryWriter* writer, uint16_t delay, uint8_t tempo, bool looped) {
+ uint16_t channelStart;
+ uint16_t channelPlaceholderOff;
+ uint16_t loopPoint;
+ uint16_t layerPlaceholderOff;
+ uint16_t layerStart;
+ if (looped) {
+ delay = 0x7FFF;
+ }
+ // Write seq header
+
+ // These two values are always the same in OOT and MM
+ WriteMuteBhv(writer, 0x20);
+ WriteMuteScale(writer, 0x32);
+
+ // We only have one channel
+ WriteInitchan(writer, 0b11);
+ // Store the current position so we can write the address of the channel when we are ready.
+ channelPlaceholderOff = writer->GetBaseAddress();
+ // Store the current position so we can loop here after the song ends.
+ loopPoint = writer->GetBaseAddress();
+ WriteLdchan(writer, 0, 0); // Fill in the actual address later
+
+ WriteVolSHeader(writer, 127); // Max volume
+ WriteTempo(writer, tempo);
+
+ WriteDelay(writer, delay);
+ if (looped) {
+ WriteJump(writer, loopPoint);
+ }
+ WriteDisablecan(writer, 0b11);
+ writer->Write(static_cast<uint8_t>(0xFF));
+
+ // Fill in the ldchan from before
+ channelStart = writer->GetBaseAddress();
+ writer->Seek(channelPlaceholderOff, Ship::SeekOffsetType::Start);
+ WriteLdchan(writer, 0, channelStart);
+ writer->Seek(channelStart, Ship::SeekOffsetType::Start);
+
+ // Channel header
+ layerPlaceholderOff = writer->GetBaseAddress();
+ WriteNoshort(writer);
+ WriteLdlayer(writer, 0, 0);
+ WritePan(writer, 70);
+ WriteVolCHeader(writer, 127); // Max volume
+ WriteBend(writer, 0);
+ WriteInstrument(writer, 0);
+ WriteDelay(writer, delay);
+ writer->Write(static_cast<uint8_t>(0xFF));
+
+ layerStart = writer->GetBaseAddress();
+ writer->Seek(layerPlaceholderOff, Ship::SeekOffsetType::Start);
+ WriteLdlayer(writer, 0, layerStart);
+ writer->Seek(layerStart, Ship::SeekOffsetType::Start);
+
+ // Note layer
+ WriteLegato(writer);
+ WriteNotedvg(writer, 39, 0x7FFF - 1, static_cast<uint8_t>(0x7F), static_cast<uint8_t>(1));
+ writer->Write(static_cast<uint8_t>(0xFF));
+}
+
+static void WriteStereoSingleSeq(Ship::BinaryWriter* writer, uint16_t delay, uint8_t tempo, bool looped) {
+ uint16_t lChannelStart;
+ uint16_t rChannelStart;
+ uint16_t channelPlaceholderOff;
+ uint16_t loopPoint;
+ uint16_t lLayerPlaceholderOff;
+ uint16_t rLayerPlaceholderOff;
+ uint16_t lLayerOffset;
+ uint16_t rLayerOffset;
+
+ uint16_t layerStart;
+ // Write seq header
+ if (looped) {
+ delay = 0x7FFF;
+ }
+ // These two values are always the same in OOT and MM
+ WriteMuteBhv(writer, 0x20);
+ WriteMuteScale(writer, 0x32);
+
+ // We only have one channel
+ WriteInitchan(writer, 0b11);
+ // Store the current position so we can write the address of the channel when we are ready.
+ channelPlaceholderOff = writer->GetBaseAddress();
+ // Store the current position so we can loop here after the song ends.
+ loopPoint = writer->GetBaseAddress();
+ // Left note channel
+ WriteLdchan(writer, 0, 0); // Fill in the actual address later
+ // Right note channel
+ WriteLdchan(writer, 1, 0); // Fill in the actual address later
+
+ WriteVolSHeader(writer, 127); // Max volume
+ WriteTempo(writer, tempo);
+
+ WriteDelay(writer, delay);
+ if (looped) {
+ WriteJump(writer, loopPoint);
+ }
+ WriteDisablecan(writer, 0b11);
+ writer->Write(static_cast<uint8_t>(0xFF));
+
+ lChannelStart = writer->GetBaseAddress();
+ // Left Channel header
+ WriteNoshort(writer);
+ lLayerPlaceholderOff = writer->GetBaseAddress();
+ WriteLdlayer(writer, 0, 0);
+ WritePan(writer, 0);
+ WriteVolCHeader(writer, 127); // Max volume
+ WriteBend(writer, 0);
+ WriteInstrument(writer, 0);
+ WriteDelay(writer, delay);
+ writer->Write(static_cast<uint8_t>(0xFF));
+
+ rChannelStart = writer->GetBaseAddress();
+ // Right Channel header
+ WriteNoshort(writer);
+ rLayerPlaceholderOff = writer->GetBaseAddress();
+ WriteLdlayer(writer, 1, 0);
+ WritePan(writer, 127);
+ WriteVolCHeader(writer, 127); // Max volume
+ WriteBend(writer, 0);
+ WriteInstrument(writer, 1);
+ WriteDelay(writer, delay);
+ writer->Write(static_cast<uint8_t>(0xFF));
+ uint16_t placeHolder = writer->GetBaseAddress();
+ writer->Seek(channelPlaceholderOff, Ship::SeekOffsetType::Start);
+ WriteLdchan(writer, 0, lChannelStart);
+ WriteLdchan(writer, 1, rChannelStart);
+ writer->Seek(placeHolder, Ship::SeekOffsetType::Start);
+
+ // Left Note layer
+ lLayerOffset = writer->GetBaseAddress();
+ WriteLegato(writer);
+ WriteNotedvg(writer, 39, 0x7FFF - 1, static_cast<uint8_t>(0x7F), static_cast<uint8_t>(1));
+ writer->Write(static_cast<uint8_t>(0xFF));
+
+ // Right Note layer
+ rLayerOffset = writer->GetBaseAddress();
+ WriteLegato(writer);
+ WriteNotedvg(writer, 39, 0x7FFF - 1, static_cast<uint8_t>(0x7F), static_cast<uint8_t>(1));
+ writer->Write(static_cast<uint8_t>(0xFF));
+
+ writer->Seek(lLayerPlaceholderOff, Ship::SeekOffsetType::Start);
+ WriteLdlayer(writer, 0, lLayerOffset);
+ writer->Seek(rLayerPlaceholderOff, Ship::SeekOffsetType::Start);
+ WriteLdlayer(writer, 1, rLayerOffset);
+}
+
+extern "C" char* WriteDummySequence() {
+ Ship::BinaryWriter writer = Ship::BinaryWriter();
+ writer.SetEndianness(Ship::Endianness::Big);
+
+ bool stereo = true;
+ bool looped = true;
+ uint32_t length = 60;
+ // Placeholder off is the offset of the instruction to be replaced. The second variable is the target adress
+ // of what we need to load of jump to
+ uint16_t loopPoint;
+ uint16_t channelPlaceholderOff, channelStart;
+ uint16_t layerPlaceholderOff, layerStart;
+
+ // 1 second worth of ticks can be found by using `ticks = 60 / (bpm * 48)`
+ // Get the number of ticks per second and then divide the length by this number to get the number of ticks
+ // for the song.
+ constexpr uint8_t TEMPO = 1;
+ constexpr float TEMPO_F = TEMPO;
+ // Use floats for this first calculation so we can round up
+ float delayF = length / (60.0f / (TEMPO_F * 48.0f));
+ // Convert to u16. This way this value is encoded changes depending on the value.
+ // It can be at most 0xFFFF so store it in a u16 for now.
+ uint16_t delay;
+ if (delayF >= 65535.0f) {
+ delay = 0x7FFF;
+ } else {
+ delay = delayF;
+ }
+ if (stereo) {
+ WriteStereoSingleSeq(&writer, delay, TEMPO, looped);
+ } else {
+ WriteMonoSingleSeq(&writer, delay, TEMPO, looped);
+ }
+
+ auto result = writer.ToVector();
+ char* output = new char[result.size()];
+ memcpy(output, result.data(), result.size());
+ return output;
+} \ No newline at end of file
diff --git a/src/port/resource/importers/audio/SequenceFactory.h b/src/port/resource/importers/audio/SequenceFactory.h
new file mode 100644
index 00000000..d537fdb4
--- /dev/null
+++ b/src/port/resource/importers/audio/SequenceFactory.h
@@ -0,0 +1,4 @@
+#pragma once
+
+
+class ResourceFactoryXMLSequenceV0 {}; \ No newline at end of file
diff --git a/src/port/resource/loaders/AudioLoader.cpp b/src/port/resource/loaders/AudioLoader.cpp
index 156d067b..515d5f59 100644
--- a/src/port/resource/loaders/AudioLoader.cpp
+++ b/src/port/resource/loaders/AudioLoader.cpp
@@ -9,7 +9,10 @@
#ifdef OTR_AUDIO
extern "C" SoundFont* Audio_LoadFont(AudioTableEntry entry, uint32_t fontId) {
- return (SoundFont*) ResourceGetDataByCrc((uint64_t) gSoundFontTable->entries[fontId].romAddr);
+ auto crc = (uint64_t) gSoundFontTable->entries[fontId].romAddr;
+ auto path = ResourceGetNameByCrc(crc);
+ printf("Font: %s\n", path);
+ return (SoundFont*) ResourceGetDataByCrc(crc);
}
#else
namespace fs = std::filesystem;