Support for absolute PROJ offsets introduced in Battle for Naboo

This commit is contained in:
Jack Andersen 2016-05-29 08:22:20 -10:00
parent 3056426afc
commit 494a39e76a
14 changed files with 579 additions and 169 deletions

97
AudioUnit/CMakeLists.txt Normal file
View File

@ -0,0 +1,97 @@
if (APPLE AND (NOT CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VERSION_GREATER 10.10))
set(APPLE_DEV_ID "" CACHE STRING "Mac Developer ID string 'Mac Developer: John Smith (XXXXXXXXXX)'")
set(APPLE_TEAM_ID "" CACHE STRING "Team ID string provisioned within Xcode / Apple's portal")
find_library(AVFOUNDATION_LIBRARY AVFoundation)
find_library(AUDIOUNIT_LIBRARY AudioUnit)
find_library(COREAUDIOKIT_LIBRARY CoreAudioKit)
if (NOT (AUDIOUNIT_LIBRARY STREQUAL AUDIOUNIT_LIBRARY-NOTFOUND))
set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_BINARY_DIR}")
# Search for provision profile to make AudioUnit extension on OS X
unset(PROV_PROFILE)
file(GLOB PROV_FILES "$ENV{HOME}/Library/MobileDevice/Provisioning Profiles/*.provisionprofile")
foreach(FILE ${PROV_FILES})
file(STRINGS "${FILE}" NAME REGEX ${APPLE_TEAM_ID})
if(NAME)
set(PROV_PROFILE "${FILE}")
break()
endif()
endforeach()
if(EXISTS "${PROV_PROFILE}")
# Extension App
add_executable(amuse-au MACOSX_BUNDLE AudioUnitBackend.hpp AudioUnitBackend.mm
AudioUnitViewController.hpp AudioUnitViewController.mm
AudioGroupFilePresenter.hpp AudioGroupFilePresenter.mm)
set(APPLE_BUNDLE_ID "io.github.axiodl.Amuse.AudioUnit")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/AmuseExtension.entitlements.in
${CMAKE_CURRENT_BINARY_DIR}/AmuseExtension.entitlements)
target_link_libraries(amuse-au amuse boo soxr ${AUDIOUNIT_LIBRARY} ${COREAUDIOKIT_LIBRARY}
${AVFOUNDATION_LIBRARY} ${BOO_SYS_LIBS} logvisor athena-core)
set_target_properties(amuse-au PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/ExtensionInfo.plist"
BUNDLE_EXTENSION "appex" BUNDLE TRUE
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_BINARY_DIR}/AmuseExtension.entitlements"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${APPLE_DEV_ID}"
LINK_FLAGS "-e _NSExtensionMain -fobjc-arc -fobjc-link-runtime -fapplication-extension")
# Containing App
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/AmuseContainerMainMenu.nib
COMMAND ibtool --errors --warnings --notices --module amuse_au_container --auto-activate-custom-fonts
--target-device mac --minimum-deployment-target 10.11 --output-format human-readable-text --compile
${CMAKE_CURRENT_BINARY_DIR}/AmuseContainerMainMenu.nib
${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainerMainMenu.xib
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainerMainMenu.xib
)
add_executable(amuse-au-container MACOSX_BUNDLE AmuseContainingApp.mm
AudioUnitBackend.hpp AudioUnitBackend.mm
AudioUnitViewController.hpp AudioUnitViewController.mm
AudioGroupFilePresenter.hpp AudioGroupFilePresenter.mm
AmuseContainerMainMenu.nib)
set_source_files_properties(AudioUnitBackend.mm AudioUnitViewController.mm
AmuseContainingApp.mm AudioGroupFilePresenter.mm
PROPERTIES COMPILE_FLAGS -fobjc-arc)
target_link_libraries(amuse-au-container amuse boo soxr ${AUDIOUNIT_LIBRARY} ${COREAUDIOKIT_LIBRARY}
${AVFOUNDATION_LIBRARY} ${BOO_SYS_LIBS} logvisor athena-core)
set(APPLE_BUNDLE_ID "io.github.axiodl.Amuse")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainer.entitlements.in
${CMAKE_CURRENT_BINARY_DIR}/AmuseContainer.entitlements)
set_target_properties(amuse-au-container PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/ContainerInfo.plist"
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_BINARY_DIR}/AmuseContainer.entitlements"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${APPLE_DEV_ID}")
add_custom_command(TARGET amuse-au POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy "${PROV_PROFILE}" "$<TARGET_FILE_DIR:amuse-au>/../embedded.provisionprofile"
COMMAND ${CMAKE_COMMAND} -E remove_directory "$<TARGET_FILE_DIR:amuse-au-container>/../PlugIns/amuse-au.appex"
COMMAND ${CMAKE_COMMAND} -E copy_directory "$<TARGET_FILE_DIR:amuse-au>/../.."
"$<TARGET_FILE_DIR:amuse-au-container>/../PlugIns/amuse-au.appex"
COMMAND codesign --force --sign
${APPLE_DEV_ID} --entitlements "${CMAKE_CURRENT_BINARY_DIR}/AmuseExtension.entitlements"
"$<TARGET_FILE_DIR:amuse-au-container>/../PlugIns/amuse-au.appex"
COMMAND codesign --force --sign ${APPLE_DEV_ID}
"$<TARGET_FILE_DIR:amuse-au-container>/../.."
VERBATIM
)
add_custom_command(TARGET amuse-au-container POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
"${CMAKE_CURRENT_BINARY_DIR}/AmuseContainerMainMenu.nib"
"$<TARGET_FILE_DIR:amuse-au-container>/../Resources/AmuseContainerMainMenu.nib"
COMMAND codesign --force --sign
${APPLE_DEV_ID} "$<TARGET_FILE_DIR:amuse-au-container>/../.."
VERBATIM
)
else()
message(WARNING "Unable to find developer provision profile; skipping Amuse-AU")
endif()
endif()
endif()

View File

@ -75,105 +75,13 @@ add_library(amuse
${EXTRAS})
if(TARGET boo)
# AudioUnit Target
if (APPLE AND (NOT CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VERSION_GREATER 10.10))
set(APPLE_DEV_ID "" CACHE STRING "Mac Developer ID string 'Mac Developer: John Smith (XXXXXXXXXX)'")
set(APPLE_TEAM_ID "" CACHE STRING "Team ID string provisioned within Xcode / Apple's portal")
find_library(AVFOUNDATION_LIBRARY AVFoundation)
find_library(AUDIOUNIT_LIBRARY AudioUnit)
find_library(COREAUDIOKIT_LIBRARY CoreAudioKit)
if (NOT (AUDIOUNIT_LIBRARY STREQUAL AUDIOUNIT_LIBRARY-NOTFOUND))
set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_BINARY_DIR}")
# AudioUnit Target (OS X only)
add_subdirectory(AudioUnit)
# Search for provision profile to make AudioUnit extension on OS X
unset(PROV_PROFILE)
file(GLOB PROV_FILES "$ENV{HOME}/Library/MobileDevice/Provisioning Profiles/*.provisionprofile")
foreach(FILE ${PROV_FILES})
file(STRINGS "${FILE}" NAME REGEX ${APPLE_TEAM_ID})
if(NAME)
set(PROV_PROFILE "${FILE}")
break()
endif()
endforeach()
if(EXISTS "${PROV_PROFILE}")
# Extension App
add_executable(amuse-au MACOSX_BUNDLE AudioUnit/AudioUnitBackend.hpp AudioUnit/AudioUnitBackend.mm
AudioUnit/AudioUnitViewController.hpp AudioUnit/AudioUnitViewController.mm
AudioUnit/AudioGroupFilePresenter.hpp AudioUnit/AudioGroupFilePresenter.mm)
set(APPLE_BUNDLE_ID "io.github.axiodl.Amuse.AudioUnit")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/AudioUnit/AmuseExtension.entitlements.in
${CMAKE_CURRENT_BINARY_DIR}/AmuseExtension.entitlements)
target_link_libraries(amuse-au amuse boo soxr ${AUDIOUNIT_LIBRARY} ${COREAUDIOKIT_LIBRARY}
${AVFOUNDATION_LIBRARY} ${BOO_SYS_LIBS} logvisor athena-core)
set_target_properties(amuse-au PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/AudioUnit/ExtensionInfo.plist"
BUNDLE_EXTENSION "appex" BUNDLE TRUE
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_BINARY_DIR}/AmuseExtension.entitlements"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${APPLE_DEV_ID}"
LINK_FLAGS "-e _NSExtensionMain -fobjc-arc -fobjc-link-runtime -fapplication-extension")
# Containing App
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/AmuseContainerMainMenu.nib
COMMAND ibtool --errors --warnings --notices --module amuse_au_container --auto-activate-custom-fonts
--target-device mac --minimum-deployment-target 10.11 --output-format human-readable-text --compile
${CMAKE_CURRENT_BINARY_DIR}/AmuseContainerMainMenu.nib
${CMAKE_CURRENT_SOURCE_DIR}/AudioUnit/AmuseContainerMainMenu.xib
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/AudioUnit/AmuseContainerMainMenu.xib
)
add_executable(amuse-au-container MACOSX_BUNDLE AudioUnit/AmuseContainingApp.mm
AudioUnit/AudioUnitBackend.hpp AudioUnit/AudioUnitBackend.mm
AudioUnit/AudioUnitViewController.hpp AudioUnit/AudioUnitViewController.mm
AudioUnit/AudioGroupFilePresenter.hpp AudioUnit/AudioGroupFilePresenter.mm
AmuseContainerMainMenu.nib)
set_source_files_properties(AudioUnit/AudioUnitBackend.mm AudioUnit/AudioUnitViewController.mm
AudioUnit/AmuseContainingApp.mm AudioUnit/AudioGroupFilePresenter.mm
PROPERTIES COMPILE_FLAGS -fobjc-arc)
target_link_libraries(amuse-au-container amuse boo soxr ${AUDIOUNIT_LIBRARY} ${COREAUDIOKIT_LIBRARY}
${AVFOUNDATION_LIBRARY} ${BOO_SYS_LIBS} logvisor athena-core)
set(APPLE_BUNDLE_ID "io.github.axiodl.Amuse")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/AudioUnit/AmuseContainer.entitlements.in
${CMAKE_CURRENT_BINARY_DIR}/AmuseContainer.entitlements)
set_target_properties(amuse-au-container PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/AudioUnit/ContainerInfo.plist"
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_BINARY_DIR}/AmuseContainer.entitlements"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${APPLE_DEV_ID}")
add_custom_command(TARGET amuse-au POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy "${PROV_PROFILE}" "$<TARGET_FILE_DIR:amuse-au>/../embedded.provisionprofile"
COMMAND ${CMAKE_COMMAND} -E remove_directory "$<TARGET_FILE_DIR:amuse-au-container>/../PlugIns/amuse-au.appex"
COMMAND ${CMAKE_COMMAND} -E copy_directory "$<TARGET_FILE_DIR:amuse-au>/../.."
"$<TARGET_FILE_DIR:amuse-au-container>/../PlugIns/amuse-au.appex"
COMMAND codesign --force --sign
${APPLE_DEV_ID} --entitlements "${CMAKE_CURRENT_BINARY_DIR}/AmuseExtension.entitlements"
"$<TARGET_FILE_DIR:amuse-au-container>/../PlugIns/amuse-au.appex"
COMMAND codesign --force --sign ${APPLE_DEV_ID}
"$<TARGET_FILE_DIR:amuse-au-container>/../.."
VERBATIM
)
add_custom_command(TARGET amuse-au-container POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
"${CMAKE_CURRENT_BINARY_DIR}/AmuseContainerMainMenu.nib"
"$<TARGET_FILE_DIR:amuse-au-container>/../Resources/AmuseContainerMainMenu.nib"
COMMAND codesign --force --sign
${APPLE_DEV_ID} "$<TARGET_FILE_DIR:amuse-au-container>/../.."
VERBATIM
)
else()
message(WARNING "Unable to find developer provision profile; skipping Amuse-AU")
endif()
endif()
endif()
# VST Target
add_subdirectory(VST)
# Multi-platform CLI tool
add_executable(amuseplay WIN32 driver/main.cpp)
target_link_libraries(amuseplay amuse boo ${BOO_SYS_LIBS} logvisor athena-core ${ZLIB_LIBRARIES})
endif()

0
VST/CMakeLists.txt Normal file
View File

View File

@ -24,8 +24,8 @@ class AudioGroup
public:
operator bool() const {return m_valid;}
AudioGroup(const AudioGroupData& data, GCNDataTag);
AudioGroup(const AudioGroupData& data, N64DataTag);
AudioGroup(const AudioGroupData& data, PCDataTag);
AudioGroup(const AudioGroupData& data, bool absOffs, N64DataTag);
AudioGroup(const AudioGroupData& data, bool absOffs, PCDataTag);
const Sample* getSample(int sfxId) const;
const unsigned char* getSampleData(uint32_t offset) const;

View File

@ -16,20 +16,26 @@ protected:
unsigned char* m_sdir;
unsigned char* m_samp;
DataFormat m_fmt;
bool m_absOffs;
AudioGroupData(unsigned char* proj, unsigned char* pool,
unsigned char* sdir, unsigned char* samp, DataFormat fmt)
: m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp), m_fmt(fmt) {}
unsigned char* sdir, unsigned char* samp,
DataFormat fmt, bool absOffs)
: m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp),
m_fmt(fmt), m_absOffs(absOffs) {}
public:
AudioGroupData(unsigned char* proj, unsigned char* pool,
unsigned char* sdir, unsigned char* samp, GCNDataTag)
: m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp), m_fmt(DataFormat::GCN) {}
: m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp),
m_fmt(DataFormat::GCN), m_absOffs(true) {}
AudioGroupData(unsigned char* proj, unsigned char* pool,
unsigned char* sdir, unsigned char* samp, N64DataTag)
: m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp), m_fmt(DataFormat::N64) {}
unsigned char* sdir, unsigned char* samp, bool absOffs, N64DataTag)
: m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp),
m_fmt(DataFormat::N64), m_absOffs(absOffs) {}
AudioGroupData(unsigned char* proj, unsigned char* pool,
unsigned char* sdir, unsigned char* samp, PCDataTag)
: m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp), m_fmt(DataFormat::PC) {}
unsigned char* sdir, unsigned char* samp, bool absOffs, PCDataTag)
: m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp),
m_fmt(DataFormat::PC), m_absOffs(absOffs) {}
const unsigned char* getProj() const {return m_proj;}
const unsigned char* getPool() const {return m_pool;}
@ -42,6 +48,7 @@ public:
}
DataFormat getDataFormat() const {return m_fmt;}
bool getAbsoluteProjOffsets() const {return m_absOffs;}
};
/** A buffer-owning version of AudioGroupData */

View File

@ -76,13 +76,13 @@ class AudioGroupProject
std::unique_ptr<SongGroupIndex::PageEntry[]> m_convNormalPages;
std::unique_ptr<SongGroupIndex::PageEntry[]> m_convDrumPages;
std::unique_ptr<std::array<SongGroupIndex::MIDISetup, 16>[]> m_convMidiSetups;
void _allocateConvBuffers(const unsigned char* data, N64DataTag);
void _allocateConvBuffers(const unsigned char* data, PCDataTag);
void _allocateConvBuffers(const unsigned char* data, bool absOffs, N64DataTag);
void _allocateConvBuffers(const unsigned char* data, bool absOffs, PCDataTag);
public:
AudioGroupProject(const unsigned char* data, GCNDataTag);
AudioGroupProject(const unsigned char* data, N64DataTag);
AudioGroupProject(const unsigned char* data, PCDataTag);
AudioGroupProject(const unsigned char* data, bool absOffs, N64DataTag);
AudioGroupProject(const unsigned char* data, bool absOffs, PCDataTag);
static AudioGroupProject CreateAudioGroupProject(const AudioGroupData& data);
const SongGroupIndex* getSongGroupIndex(int groupId) const;

View File

@ -48,8 +48,9 @@ private:
std::unordered_map<uint16_t, std::pair<Entry, ADPCMParms>> m_entries;
public:
AudioGroupSampleDirectory(const unsigned char* data, GCNDataTag);
AudioGroupSampleDirectory(const unsigned char* data, const unsigned char* sampData, N64DataTag);
AudioGroupSampleDirectory(const unsigned char* data, PCDataTag);
AudioGroupSampleDirectory(const unsigned char* data, const unsigned char* sampData,
bool absOffs, N64DataTag);
AudioGroupSampleDirectory(const unsigned char* data, bool absOffs, PCDataTag);
};
}

View File

@ -19,6 +19,8 @@ public:
MetroidPrime2,
RogueSquadronPC,
RogueSquadronN64,
BattleForNabooPC,
BattleForNabooN64,
RogueSquadron2,
RogueSquadron3
};

View File

@ -12,18 +12,18 @@ AudioGroup::AudioGroup(const AudioGroupData& data, GCNDataTag)
m_fmt(DataFormat::GCN)
{}
AudioGroup::AudioGroup(const AudioGroupData& data, N64DataTag)
: m_proj(data.getProj(), N64DataTag{}),
AudioGroup::AudioGroup(const AudioGroupData& data, bool absOffs, N64DataTag)
: m_proj(data.getProj(), absOffs, N64DataTag{}),
m_pool(data.getPool()),
m_sdir(data.getSdir(), data.getSamp(), N64DataTag{}),
m_sdir(data.getSdir(), data.getSamp(), absOffs, N64DataTag{}),
m_samp(data.getSamp()),
m_fmt(DataFormat::N64)
{}
AudioGroup::AudioGroup(const AudioGroupData& data, PCDataTag)
: m_proj(data.getProj(), PCDataTag{}),
AudioGroup::AudioGroup(const AudioGroupData& data, bool absOffs, PCDataTag)
: m_proj(data.getProj(), absOffs, PCDataTag{}),
m_pool(data.getPool(), PCDataTag{}),
m_sdir(data.getSdir(), PCDataTag{}),
m_sdir(data.getSdir(), absOffs, PCDataTag{}),
m_samp(data.getSamp()),
m_fmt(DataFormat::PC)
{}

View File

@ -15,7 +15,7 @@ IntrusiveAudioGroupData::~IntrusiveAudioGroupData()
}
IntrusiveAudioGroupData::IntrusiveAudioGroupData(IntrusiveAudioGroupData&& other)
: AudioGroupData(other.m_proj, other.m_pool, other.m_sdir, other.m_samp, other.m_fmt)
: AudioGroupData(other.m_proj, other.m_pool, other.m_sdir, other.m_samp, other.m_fmt, other.m_absOffs)
{
m_owns = other.m_owns;
other.m_owns = false;
@ -39,6 +39,7 @@ IntrusiveAudioGroupData& IntrusiveAudioGroupData::operator=(IntrusiveAudioGroupD
m_sdir = other.m_sdir;
m_samp = other.m_samp;
m_fmt = other.m_fmt;
m_absOffs = other.m_absOffs;
return *this;
}

View File

@ -152,7 +152,7 @@ struct MusyX1MIDISetup
}
};
void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, N64DataTag)
void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, bool absOffs, N64DataTag)
{
size_t normPageCount = 0;
size_t drumPageCount = 0;
@ -161,7 +161,7 @@ void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, N64DataT
const GroupHeader* group = reinterpret_cast<const GroupHeader*>(data);
while (group->groupEndOff != 0xffffffff)
{
const unsigned char* subData = data + 8;
const unsigned char* subData = absOffs ? data : data + 8;
GroupHeader header = *group;
header.swapBig();
@ -194,8 +194,13 @@ void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, N64DataT
}
}
data += header.groupEndOff;
group = reinterpret_cast<const GroupHeader*>(data);
if (absOffs)
group = reinterpret_cast<const GroupHeader*>(data + header.groupEndOff);
else
{
data += header.groupEndOff;
group = reinterpret_cast<const GroupHeader*>(data);
}
}
if (normPageCount)
@ -206,9 +211,9 @@ void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, N64DataT
m_convMidiSetups.reset(new std::array<SongGroupIndex::MIDISetup, 16>[midiSetupCount]);
}
AudioGroupProject::AudioGroupProject(const unsigned char* data, N64DataTag)
AudioGroupProject::AudioGroupProject(const unsigned char* data, bool absOffs, N64DataTag)
{
_allocateConvBuffers(data, N64DataTag{});
_allocateConvBuffers(data, absOffs, N64DataTag{});
SongGroupIndex::PageEntry* normPagesBuf = m_convNormalPages.get();
SongGroupIndex::PageEntry* drumPagesBuf = m_convDrumPages.get();
std::array<SongGroupIndex::MIDISetup, 16>* midiSetupsBuf = m_convMidiSetups.get();
@ -216,7 +221,7 @@ AudioGroupProject::AudioGroupProject(const unsigned char* data, N64DataTag)
const GroupHeader* group = reinterpret_cast<const GroupHeader*>(data);
while (group->groupEndOff != 0xffffffff)
{
const unsigned char* subData = data + 8;
const unsigned char* subData = absOffs ? data : data + 8;
GroupHeader header = *group;
header.swapBig();
@ -289,12 +294,17 @@ AudioGroupProject::AudioGroupProject(const unsigned char* data, N64DataTag)
bIdx->m_layersIndex = reinterpret_cast<const uint16_t*>(subData + header.layerIdsOff);
}
data += header.groupEndOff;
group = reinterpret_cast<const GroupHeader*>(data);
if (absOffs)
group = reinterpret_cast<const GroupHeader*>(data + header.groupEndOff);
else
{
data += header.groupEndOff;
group = reinterpret_cast<const GroupHeader*>(data);
}
}
}
void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, PCDataTag)
void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, bool absOffs, PCDataTag)
{
size_t normPageCount = 0;
size_t drumPageCount = 0;
@ -303,7 +313,7 @@ void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, PCDataTa
const GroupHeader* group = reinterpret_cast<const GroupHeader*>(data);
while (group->groupEndOff != 0xffffffff)
{
const unsigned char* subData = data + 8;
const unsigned char* subData = absOffs ? data : data + 8;
if (group->type == GroupType::Song)
{
@ -334,8 +344,13 @@ void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, PCDataTa
}
}
data += group->groupEndOff;
group = reinterpret_cast<const GroupHeader*>(data);
if (absOffs)
group = reinterpret_cast<const GroupHeader*>(data + group->groupEndOff);
else
{
data += group->groupEndOff;
group = reinterpret_cast<const GroupHeader*>(data);
}
}
if (normPageCount)
@ -346,9 +361,9 @@ void AudioGroupProject::_allocateConvBuffers(const unsigned char* data, PCDataTa
m_convMidiSetups.reset(new std::array<SongGroupIndex::MIDISetup, 16>[midiSetupCount]);
}
AudioGroupProject::AudioGroupProject(const unsigned char* data, PCDataTag)
AudioGroupProject::AudioGroupProject(const unsigned char* data, bool absOffs, PCDataTag)
{
_allocateConvBuffers(data, PCDataTag{});
_allocateConvBuffers(data, absOffs, PCDataTag{});
SongGroupIndex::PageEntry* normPagesBuf = m_convNormalPages.get();
SongGroupIndex::PageEntry* drumPagesBuf = m_convDrumPages.get();
std::array<SongGroupIndex::MIDISetup, 16>* midiSetupsBuf = m_convMidiSetups.get();
@ -356,7 +371,7 @@ AudioGroupProject::AudioGroupProject(const unsigned char* data, PCDataTag)
const GroupHeader* group = reinterpret_cast<const GroupHeader*>(data);
while (group->groupEndOff != 0xffffffff)
{
const unsigned char* subData = data + 8;
const unsigned char* subData = absOffs ? data : data + 8;
AudioGroupIndex* bIdx = nullptr;
@ -427,8 +442,13 @@ AudioGroupProject::AudioGroupProject(const unsigned char* data, PCDataTag)
bIdx->m_layersIndex = reinterpret_cast<const uint16_t*>(subData + group->layerIdsOff);
}
data += group->groupEndOff;
group = reinterpret_cast<const GroupHeader*>(data);
if (absOffs)
group = reinterpret_cast<const GroupHeader*>(data + group->groupEndOff);
else
{
data += group->groupEndOff;
group = reinterpret_cast<const GroupHeader*>(data);
}
}
}
@ -439,9 +459,9 @@ AudioGroupProject AudioGroupProject::CreateAudioGroupProject(const AudioGroupDat
case DataFormat::GCN:
return AudioGroupProject(data.getProj(), GCNDataTag{});
case DataFormat::N64:
return AudioGroupProject(data.getProj(), N64DataTag{});
return AudioGroupProject(data.getProj(), data.getAbsoluteProjOffsets(), N64DataTag{});
case DataFormat::PC:
return AudioGroupProject(data.getProj(), PCDataTag{});
return AudioGroupProject(data.getProj(), data.getAbsoluteProjOffsets(), PCDataTag{});
}
}

View File

@ -94,36 +94,109 @@ struct MusyX1SdirEntry
}
};
struct MusyX1AbsSdirEntry
{
uint16_t m_sfxId;
uint32_t m_sampleOff;
uint32_t m_unk;
uint32_t m_pitchSampleRate;
uint32_t m_numSamples;
uint32_t m_loopStartSample;
uint32_t m_loopLengthSamples;
void swapBig()
{
m_sfxId = SBig(m_sfxId);
m_sampleOff = SBig(m_sampleOff);
m_unk = SBig(m_unk);
m_pitchSampleRate = SBig(m_pitchSampleRate);
m_numSamples = SBig(m_numSamples);
m_loopStartSample = SBig(m_loopStartSample);
m_loopLengthSamples = SBig(m_loopLengthSamples);
}
void setIntoMusyX2(AudioGroupSampleDirectory::Entry& ent) const
{
ent.m_sfxId = m_sfxId;
ent.m_sampleOff = m_sampleOff;
ent.m_unk = m_unk;
ent.m_pitch = m_pitchSampleRate >> 24;
ent.m_sampleRate = m_pitchSampleRate & 0xffff;
ent.m_numSamples = m_numSamples;
ent.m_loopStartSample = m_loopStartSample;
ent.m_loopLengthSamples = m_loopLengthSamples;
ent.m_adpcmParmOffset = 0;
}
};
AudioGroupSampleDirectory::AudioGroupSampleDirectory(const unsigned char* data,
const unsigned char* sampData, N64DataTag)
const unsigned char* sampData,
bool absOffs, N64DataTag)
{
const unsigned char* cur = data;
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
if (absOffs)
{
MusyX1SdirEntry ent = *reinterpret_cast<const MusyX1SdirEntry*>(cur);
ent.swapBig();
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
{
MusyX1AbsSdirEntry ent = *reinterpret_cast<const MusyX1AbsSdirEntry*>(cur);
ent.swapBig();
std::pair<Entry, ADPCMParms>& store = m_entries[ent.m_sfxId];
ent.setIntoMusyX2(store.first);
std::pair<Entry, ADPCMParms>& store = m_entries[ent.m_sfxId];
ent.setIntoMusyX2(store.first);
memcpy(&store.second.vadpcm.m_coefs, sampData + ent.m_sampleOff, 256);
store.second.swapBigVADPCM();
memcpy(&store.second.vadpcm.m_coefs, sampData + ent.m_sampleOff, 256);
store.second.swapBigVADPCM();
cur += 24;
cur += 28;
}
}
else
{
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
{
MusyX1SdirEntry ent = *reinterpret_cast<const MusyX1SdirEntry*>(cur);
ent.swapBig();
std::pair<Entry, ADPCMParms>& store = m_entries[ent.m_sfxId];
ent.setIntoMusyX2(store.first);
memcpy(&store.second.vadpcm.m_coefs, sampData + ent.m_sampleOff, 256);
store.second.swapBigVADPCM();
cur += 24;
}
}
}
AudioGroupSampleDirectory::AudioGroupSampleDirectory(const unsigned char* data, PCDataTag)
AudioGroupSampleDirectory::AudioGroupSampleDirectory(const unsigned char* data,
bool absOffs, PCDataTag)
{
const unsigned char* cur = data;
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
if (absOffs)
{
const MusyX1SdirEntry* ent = reinterpret_cast<const MusyX1SdirEntry*>(cur);
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
{
const MusyX1AbsSdirEntry* ent = reinterpret_cast<const MusyX1AbsSdirEntry*>(cur);
std::pair<Entry, ADPCMParms>& store = m_entries[ent->m_sfxId];
ent->setIntoMusyX2(store.first);
std::pair<Entry, ADPCMParms>& store = m_entries[ent->m_sfxId];
ent->setIntoMusyX2(store.first);
cur += 24;
cur += 28;
}
}
else
{
while (*reinterpret_cast<const uint32_t*>(cur) != 0xffffffff)
{
const MusyX1SdirEntry* ent = reinterpret_cast<const MusyX1SdirEntry*>(cur);
std::pair<Entry, ADPCMParms>& store = m_entries[ent->m_sfxId];
ent->setIntoMusyX2(store.first);
cur += 24;
}
}
}

View File

@ -51,6 +51,10 @@ const char* ContainerRegistry::TypeToName(Type tp)
return "Star Wars: Rogue Squadron (PC)";
case Type::RogueSquadronN64:
return "Star Wars: Rogue Squadron (N64)";
case Type::BattleForNabooPC:
return "Star Wars Episode I: Battle for Naboo (PC)";
case Type::BattleForNabooN64:
return "Star Wars Episode I: Battle for Naboo (N64)";
case Type::RogueSquadron2:
return "Star Wars: Rogue Squadron 2 (GCN)";
case Type::RogueSquadron3:
@ -371,13 +375,13 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadMP2(FILE
fread(pool.get(), 1, poolSz, fp);
std::unique_ptr<uint8_t[]> proj(new uint8_t[projSz]);
fread(pool.get(), 1, projSz, fp);
fread(proj.get(), 1, projSz, fp);
std::unique_ptr<uint8_t[]> sdir(new uint8_t[sdirSz]);
fread(pool.get(), 1, sdirSz, fp);
fread(sdir.get(), 1, sdirSz, fp);
std::unique_ptr<uint8_t[]> samp(new uint8_t[sampSz]);
fread(pool.get(), 1, sampSz, fp);
fread(samp.get(), 1, sampSz, fp);
ret.emplace_back(std::move(name), IntrusiveAudioGroupData{proj.release(), pool.release(),
sdir.release(), samp.release(), GCNDataTag{}});
@ -410,7 +414,14 @@ struct RS1FSTEntry
}
};
static void SwapN64Rom(void* data, size_t size)
static void SwapN64Rom16(void* data, size_t size)
{
uint16_t* words = reinterpret_cast<uint16_t*>(data);
for (size_t i=0 ; i<size/2 ; ++i)
words[i] = SBig(words[i]);
}
static void SwapN64Rom32(void* data, size_t size)
{
uint32_t* words = reinterpret_cast<uint32_t*>(data);
for (size_t i=0 ; i<size/4 ; ++i)
@ -505,7 +516,8 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadRS1PC(FI
}
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(),
sdir.release(), samp.release(), PCDataTag{}});
sdir.release(), samp.release(),
false, PCDataTag{}});
}
}
@ -522,11 +534,15 @@ static bool ValidateRS1N64(FILE* fp)
fread(data.get(), 1, endPos, fp);
if ((data[0] & 0x80) != 0x80 && (data[3] & 0x80) == 0x80)
SwapN64Rom(data.get(), endPos);
SwapN64Rom32(data.get(), endPos);
else if ((data[0] & 0x80) != 0x80 && (data[1] & 0x80) == 0x80)
SwapN64Rom16(data.get(), endPos);
#if 0
const uint32_t* gameId = reinterpret_cast<const uint32_t*>(&data[59]);
if (*gameId != 0x4e525345 && *gameId != 0x4553524e)
return false; /* GameId not 'NRSE' */
if (*gameId != 0x4553524e && *gameId != 0x4a53524e && *gameId != 0x5053524e)
return false; /* GameId not 'NRSE', 'NRSJ', or 'NRSP' */
#endif
const uint8_t* dataSeg = reinterpret_cast<const uint8_t*>(memmem(data.get(), endPos,
"dbg_data\0\0\0\0\0\0\0\0", 16));
@ -571,7 +587,9 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadRS1N64(F
fread(data.get(), 1, endPos, fp);
if ((data[0] & 0x80) != 0x80 && (data[3] & 0x80) == 0x80)
SwapN64Rom(data.get(), endPos);
SwapN64Rom32(data.get(), endPos);
else if ((data[0] & 0x80) != 0x80 && (data[1] & 0x80) == 0x80)
SwapN64Rom16(data.get(), endPos);
const uint8_t* dataSeg = reinterpret_cast<const uint8_t*>(memmem(data.get(), endPos,
"dbg_data\0\0\0\0\0\0\0\0", 16));
@ -656,7 +674,261 @@ static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadRS1N64(F
}
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(),
sdir.release(), samp.release(), N64DataTag{}});
sdir.release(), samp.release(),
false, N64DataTag{}});
}
return ret;
}
static bool ValidateBFNPC(FILE* fp)
{
size_t endPos = FileLength(fp);
uint32_t fstOff;
uint32_t fstSz;
if (fread(&fstOff, 1, 4, fp) == 4 && fread(&fstSz, 1, 4, fp) == 4)
{
if (fstOff + fstSz <= endPos)
{
FSeek(fp, fstOff, SEEK_SET);
uint32_t elemCount = fstSz / 32;
std::unique_ptr<RS1FSTEntry[]> entries(new RS1FSTEntry[elemCount]);
fread(entries.get(), fstSz, 1, fp);
uint8_t foundComps = 0;
for (uint32_t i=0 ; i<elemCount ; ++i)
{
RS1FSTEntry& entry = entries[i];
if (!strncmp("proj", entry.name, 16))
foundComps |= 1;
else if (!strncmp("pool", entry.name, 16))
foundComps |= 2;
else if (!strncmp("sdir", entry.name, 16))
foundComps |= 4;
else if (!strncmp("samp", entry.name, 16))
foundComps |= 8;
}
if (foundComps == 0xf)
return true;
}
}
return false;
}
static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadBFNPC(FILE* fp)
{
std::vector<std::pair<std::string, IntrusiveAudioGroupData>> ret;
size_t endPos = FileLength(fp);
uint32_t fstOff;
uint32_t fstSz;
if (fread(&fstOff, 1, 4, fp) == 4 && fread(&fstSz, 1, 4, fp) == 4)
{
if (fstOff + fstSz <= endPos)
{
FSeek(fp, fstOff, SEEK_SET);
uint32_t elemCount = fstSz / 32;
std::unique_ptr<RS1FSTEntry[]> entries(new RS1FSTEntry[elemCount]);
fread(entries.get(), fstSz, 1, fp);
std::unique_ptr<uint8_t[]> proj;
std::unique_ptr<uint8_t[]> pool;
std::unique_ptr<uint8_t[]> sdir;
std::unique_ptr<uint8_t[]> samp;
for (uint32_t i=0 ; i<elemCount ; ++i)
{
RS1FSTEntry& entry = entries[i];
if (!strncmp("proj", entry.name, 16))
{
proj.reset(new uint8_t[entry.decompSz]);
FSeek(fp, entry.offset, SEEK_SET);
fread(proj.get(), 1, entry.decompSz, fp);
}
else if (!strncmp("pool", entry.name, 16))
{
pool.reset(new uint8_t[entry.decompSz]);
FSeek(fp, entry.offset, SEEK_SET);
fread(pool.get(), 1, entry.decompSz, fp);
}
else if (!strncmp("sdir", entry.name, 16))
{
sdir.reset(new uint8_t[entry.decompSz]);
FSeek(fp, entry.offset, SEEK_SET);
fread(sdir.get(), 1, entry.decompSz, fp);
}
else if (!strncmp("samp", entry.name, 16))
{
samp.reset(new uint8_t[entry.decompSz]);
FSeek(fp, entry.offset, SEEK_SET);
fread(samp.get(), 1, entry.decompSz, fp);
}
}
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(),
sdir.release(), samp.release(),
true, PCDataTag{}});
}
}
return ret;
}
static bool ValidateBFNN64(FILE* fp)
{
size_t endPos = FileLength(fp);
if (endPos > 32 * 1024 * 1024)
return false; /* N64 ROM definitely won't exceed 32MB */
std::unique_ptr<uint8_t[]> data(new uint8_t[endPos]);
fread(data.get(), 1, endPos, fp);
if ((data[0] & 0x80) != 0x80 && (data[3] & 0x80) == 0x80)
SwapN64Rom32(data.get(), endPos);
else if ((data[0] & 0x80) != 0x80 && (data[1] & 0x80) == 0x80)
SwapN64Rom16(data.get(), endPos);
#if 0
const uint32_t* gameId = reinterpret_cast<const uint32_t*>(&data[59]);
if (*gameId != 0x4553524e && *gameId != 0x4a53524e && *gameId != 0x5053524e)
return false; /* GameId not 'NRSE', 'NRSJ', or 'NRSP' */
#endif
const uint8_t* dataSeg = reinterpret_cast<const uint8_t*>(memmem(data.get(), endPos,
"dbg_data\0\0\0\0\0\0\0\0", 16));
if (dataSeg)
{
dataSeg += 28;
size_t fstEnd = SBig(*reinterpret_cast<const uint32_t*>(dataSeg));
dataSeg += 4;
size_t fstOff = SBig(*reinterpret_cast<const uint32_t*>(dataSeg));
if (endPos <= size_t(dataSeg - data.get()) + fstOff || endPos <= size_t(dataSeg - data.get()) + fstEnd)
return false;
const RS1FSTEntry* entry = reinterpret_cast<const RS1FSTEntry*>(dataSeg + fstOff);
const RS1FSTEntry* lastEnt = reinterpret_cast<const RS1FSTEntry*>(dataSeg + fstEnd);
uint8_t foundComps = 0;
for (; entry != lastEnt ; ++entry)
{
if (!strncmp("proj", entry->name, 16))
foundComps |= 1;
else if (!strncmp("pool", entry->name, 16))
foundComps |= 2;
else if (!strncmp("sdir", entry->name, 16))
foundComps |= 4;
else if (!strncmp("samp", entry->name, 16))
foundComps |= 8;
}
if (foundComps == 0xf)
return true;
}
return false;
}
static std::vector<std::pair<std::string, IntrusiveAudioGroupData>> LoadBFNN64(FILE* fp)
{
std::vector<std::pair<std::string, IntrusiveAudioGroupData>> ret;
size_t endPos = FileLength(fp);
std::unique_ptr<uint8_t[]> data(new uint8_t[endPos]);
fread(data.get(), 1, endPos, fp);
if ((data[0] & 0x80) != 0x80 && (data[3] & 0x80) == 0x80)
SwapN64Rom32(data.get(), endPos);
else if ((data[0] & 0x80) != 0x80 && (data[1] & 0x80) == 0x80)
SwapN64Rom16(data.get(), endPos);
const uint8_t* dataSeg = reinterpret_cast<const uint8_t*>(memmem(data.get(), endPos,
"dbg_data\0\0\0\0\0\0\0\0", 16));
if (dataSeg)
{
dataSeg += 28;
size_t fstEnd = SBig(*reinterpret_cast<const uint32_t*>(dataSeg));
dataSeg += 4;
size_t fstOff = SBig(*reinterpret_cast<const uint32_t*>(dataSeg));
if (endPos <= size_t(dataSeg - data.get()) + fstOff || endPos <= size_t(dataSeg - data.get()) + fstEnd)
return ret;
const RS1FSTEntry* entry = reinterpret_cast<const RS1FSTEntry*>(dataSeg + fstOff);
const RS1FSTEntry* lastEnt = reinterpret_cast<const RS1FSTEntry*>(dataSeg + fstEnd);
std::unique_ptr<uint8_t[]> proj;
std::unique_ptr<uint8_t[]> pool;
std::unique_ptr<uint8_t[]> sdir;
std::unique_ptr<uint8_t[]> samp;
for (; entry != lastEnt ; ++entry)
{
RS1FSTEntry ent = *entry;
ent.swapBig();
if (!strncmp("proj", ent.name, 16))
{
if (ent.compSz == 0xffffffff)
{
proj.reset(new uint8_t[ent.decompSz]);
memcpy(proj.get(), dataSeg + ent.offset, ent.decompSz);
}
else
{
proj.reset(new uint8_t[ent.decompSz]);
uLongf outSz = ent.decompSz;
uncompress(proj.get(), &outSz, dataSeg + ent.offset, ent.compSz);
}
}
else if (!strncmp("pool", ent.name, 16))
{
if (ent.compSz == 0xffffffff)
{
pool.reset(new uint8_t[ent.decompSz]);
memcpy(pool.get(), dataSeg + ent.offset, ent.decompSz);
}
else
{
pool.reset(new uint8_t[ent.decompSz]);
uLongf outSz = ent.decompSz;
uncompress(pool.get(), &outSz, dataSeg + ent.offset, ent.compSz);
}
}
else if (!strncmp("sdir", ent.name, 16))
{
if (ent.compSz == 0xffffffff)
{
sdir.reset(new uint8_t[ent.decompSz]);
memcpy(sdir.get(), dataSeg + ent.offset, ent.decompSz);
}
else
{
sdir.reset(new uint8_t[ent.decompSz]);
uLongf outSz = ent.decompSz;
uncompress(sdir.get(), &outSz, dataSeg + ent.offset, ent.compSz);
}
}
else if (!strncmp("samp", ent.name, 16))
{
if (ent.compSz == 0xffffffff)
{
samp.reset(new uint8_t[ent.decompSz]);
memcpy(samp.get(), dataSeg + ent.offset, ent.decompSz);
}
else
{
samp.reset(new uint8_t[ent.decompSz]);
uLongf outSz = ent.decompSz;
uncompress(samp.get(), &outSz, dataSeg + ent.offset, ent.compSz);
}
}
}
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(),
sdir.release(), samp.release(),
true, N64DataTag{}});
}
return ret;
@ -989,6 +1261,18 @@ ContainerRegistry::Type ContainerRegistry::DetectContainerType(const char* path)
return Type::RogueSquadronN64;
}
if (ValidateBFNPC(fp))
{
fclose(fp);
return Type::BattleForNabooPC;
}
if (ValidateBFNN64(fp))
{
fclose(fp);
return Type::BattleForNabooN64;
}
if (ValidateRS2(fp))
{
fclose(fp);
@ -1103,13 +1387,16 @@ ContainerRegistry::LoadContainer(const char* path)
/* SDIR-based format detection */
if (*reinterpret_cast<uint32_t*>(sdir.get() + 8) == 0x0)
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(),
sdir.release(), samp.release(), GCNDataTag{}});
sdir.release(), samp.release(),
GCNDataTag{}});
else if (sdir[9] == 0x0)
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(),
sdir.release(), samp.release(), N64DataTag{}});
sdir.release(), samp.release(),
false, N64DataTag{}});
else
ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(),
sdir.release(), samp.release(), PCDataTag{}});
sdir.release(), samp.release(),
false, PCDataTag{}});
return ret;
}
@ -1146,6 +1433,20 @@ ContainerRegistry::LoadContainer(const char* path)
return ret;
}
if (ValidateBFNPC(fp))
{
auto ret = LoadBFNPC(fp);
fclose(fp);
return ret;
}
if (ValidateBFNN64(fp))
{
auto ret = LoadBFNN64(fp);
fclose(fp);
return ret;
}
if (ValidateRS2(fp))
{
auto ret = LoadRS2(fp);

View File

@ -205,10 +205,10 @@ const AudioGroup* Engine::addAudioGroup(const AudioGroupData& data)
grp = std::make_unique<AudioGroup>(data, GCNDataTag{});
break;
case DataFormat::N64:
grp = std::make_unique<AudioGroup>(data, N64DataTag{});
grp = std::make_unique<AudioGroup>(data, data.m_absOffs, N64DataTag{});
break;
case DataFormat::PC:
grp = std::make_unique<AudioGroup>(data, PCDataTag{});
grp = std::make_unique<AudioGroup>(data, data.m_absOffs, PCDataTag{});
break;
}
if (!grp)